1 // Copyright 2017 The Fuchsia Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4
5 #include <assert.h>
6 #include <stdint.h>
7 #include <stdio.h>
8 #include <stdlib.h>
9 #include <string.h>
10 #include <threads.h>
11 #include <unistd.h>
12
13 #include <ddk/binding.h>
14 #include <ddk/debug.h>
15 #include <ddk/device.h>
16 #include <ddk/driver.h>
17 #include <ddk/platform-defs.h>
18 #include <ddk/protocol/platform/bus.h>
19
20 #include <zircon/process.h>
21 #include <zircon/syscalls.h>
22 #include <zircon/assert.h>
23
24 #include "qemu-virt.h"
25
26 typedef struct {
27 pbus_protocol_t pbus;
28 } qemu_bus_t;
29
qemu_pci_init(void)30 static zx_status_t qemu_pci_init(void) {
31 zx_status_t status;
32
33 zx_pci_init_arg_t* arg;
34 size_t arg_size = sizeof(*arg) + sizeof(arg->addr_windows[0]); // room for one addr window
35 arg = calloc(1, arg_size);
36 if (!arg) return ZX_ERR_NO_MEMORY;
37
38 status = zx_pci_add_subtract_io_range(get_root_resource(), true /* mmio */,
39 PCIE_MMIO_BASE_PHYS, PCIE_MMIO_SIZE, true /* add */);
40 if (status != ZX_OK) {
41 goto fail;
42 }
43 status = zx_pci_add_subtract_io_range(get_root_resource(), false /* pio */,
44 PCIE_PIO_BASE_PHYS, PCIE_PIO_SIZE, true /* add */);
45 if (status != ZX_OK) {
46 goto fail;
47 }
48
49 // initialize our swizzle table
50 zx_pci_irq_swizzle_lut_t* lut = &arg->dev_pin_to_global_irq;
51 for (unsigned dev_id = 0; dev_id < ZX_PCI_MAX_DEVICES_PER_BUS; dev_id++) {
52 for (unsigned func_id = 0; func_id < ZX_PCI_MAX_FUNCTIONS_PER_DEVICE; func_id++) {
53 for (unsigned pin = 0; pin < ZX_PCI_MAX_LEGACY_IRQ_PINS; pin++) {
54 (*lut)[dev_id][func_id][pin] = PCIE_INT_BASE +
55 (pin + dev_id) % ZX_PCI_MAX_LEGACY_IRQ_PINS;
56 }
57 }
58 }
59 arg->num_irqs = 0;
60 arg->addr_window_count = 1;
61 arg->addr_windows[0].cfg_space_type = PCI_CFG_SPACE_TYPE_MMIO;
62 arg->addr_windows[0].has_ecam = true;
63 arg->addr_windows[0].base = PCIE_ECAM_BASE_PHYS;
64 arg->addr_windows[0].size = PCIE_ECAM_SIZE;
65 arg->addr_windows[0].bus_start = 0;
66 arg->addr_windows[0].bus_end = (PCIE_ECAM_SIZE / ZX_PCI_ECAM_BYTE_PER_BUS) - 1;
67
68 status = zx_pci_init(get_root_resource(), arg, arg_size);
69 if (status != ZX_OK) {
70 zxlogf(ERROR, "%s: error %d in zx_pci_init\n", __FUNCTION__, status);
71 goto fail;
72 }
73
74 fail:
75 free(arg);
76 return status;
77 }
78
qemu_bus_release(void * ctx)79 static void qemu_bus_release(void* ctx) {
80 qemu_bus_t* bus = ctx;
81 free(bus);
82 }
83
84 static zx_protocol_device_t qemu_bus_device_protocol = {
85 .version = DEVICE_OPS_VERSION,
86 .release = qemu_bus_release,
87 };
88
89 static const pbus_mmio_t pl031_mmios[] = {
90 {
91 .base = RTC_BASE_PHYS,
92 .length = RTC_SIZE,
93 },
94 };
95
96 static const pbus_dev_t pl031_dev = {
97 .name = "pl031",
98 .vid = PDEV_VID_GENERIC,
99 .pid = PDEV_PID_GENERIC,
100 .did = PDEV_DID_RTC_PL031,
101 .mmio_list = pl031_mmios,
102 .mmio_count = countof(pl031_mmios),
103 };
104
qemu_bus_bind(void * ctx,zx_device_t * parent)105 static zx_status_t qemu_bus_bind(void* ctx, zx_device_t* parent) {
106 // we don't really need a context struct yet, but lets create one for future expansion.
107 qemu_bus_t* bus = calloc(1, sizeof(qemu_bus_t));
108 if (!bus) {
109 return ZX_ERR_NO_MEMORY;
110 }
111
112 if (device_get_protocol(parent, ZX_PROTOCOL_PBUS, &bus->pbus) != ZX_OK) {
113 free(bus);
114 return ZX_ERR_NOT_SUPPORTED;
115 }
116
117 zx_status_t status = qemu_pci_init();
118 if (status != ZX_OK) {
119 goto fail;
120 }
121
122 device_add_args_t args = {
123 .version = DEVICE_ADD_ARGS_VERSION,
124 .name = "qemu-bus",
125 .ops = &qemu_bus_device_protocol,
126 .flags = DEVICE_ADD_NON_BINDABLE,
127 };
128
129 status = device_add(parent, &args, NULL);
130 if (status != ZX_OK) {
131 goto fail;
132 }
133
134 pbus_bti_t pci_btis[] = {
135 {
136 .iommu_index = 0,
137 .bti_id = 0,
138 },
139 };
140
141 pbus_dev_t pci_dev = {
142 .name = "pci",
143 .vid = PDEV_VID_GENERIC,
144 .pid = PDEV_PID_GENERIC,
145 .did = PDEV_DID_KPCI,
146 .bti_list = pci_btis,
147 .bti_count = countof(pci_btis),
148 };
149
150 status = pbus_device_add(&bus->pbus, &pci_dev);
151 if (status != ZX_OK) {
152 zxlogf(ERROR, "qemu_bus_bind could not add pci_dev: %d\n", status);
153 }
154
155 status = pbus_device_add(&bus->pbus, &pl031_dev);
156 if (status != ZX_OK) {
157 zxlogf(ERROR, "qemu_bus_bind could not add pl031: %d\n", status);
158 }
159
160 return ZX_OK;
161
162 fail:
163 printf("qemu_bus_bind failed %d\n", status);
164 qemu_bus_release(bus);
165 return status;
166 }
167
168 static zx_driver_ops_t qemu_bus_driver_ops = {
169 .version = DRIVER_OPS_VERSION,
170 .bind = qemu_bus_bind,
171 };
172
173 ZIRCON_DRIVER_BEGIN(qemu_bus, qemu_bus_driver_ops, "zircon", "0.1", 3)
174 BI_ABORT_IF(NE, BIND_PROTOCOL, ZX_PROTOCOL_PBUS),
175 BI_ABORT_IF(NE, BIND_PLATFORM_DEV_VID, PDEV_VID_QEMU),
176 BI_MATCH_IF(EQ, BIND_PLATFORM_DEV_PID, PDEV_PID_QEMU),
177 ZIRCON_DRIVER_END(qemu_bus)
178