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