1 #include <lunaix/device.h>
2 #include <asm-generic/isrm.h>
3 #include <lunaix/syslog.h>
4 #include <lunaix/mm/mmio.h>
10 #define PCI_DEVICE_16x50_UART 0x070000
12 LOG_MODULE("16x50-pci")
14 static DEFINE_LLIST(pci_ports);
17 uart_msi_irq_handler(const struct hart_state* hstate)
20 struct uart16550* uart;
22 vector = hart_vector_stamp(hstate);
23 uart = (struct uart16550*)isrm_get_payload(hstate);
26 uart_handle_irq(vector, uart);
30 uart_intx_irq_handler(const struct hart_state* hstate)
32 int vector = hart_vector_stamp(hstate);
33 uart_handle_irq_overlap(vector, &pci_ports);
37 pci16550_init(struct device_def* def)
39 return pci_bind_definition_all(pcidev_def(def));
43 pci16650_check_compat(struct pci_device_def* def,
44 struct pci_device* pcidev)
47 classid = pci_device_class(pcidev);
49 return (classid & 0xffff00) == PCI_DEVICE_16x50_UART;
53 pci16650_binder(struct device_def* def, struct device* dev)
56 struct pci_base_addr* bar;
57 struct pci_device* pcidev;
58 struct uart16550* uart;
59 struct serial_dev* sdev;
61 pcidev = PCI_DEVICE(dev);
65 for (int i = 0; i < PCI_BAR_COUNT; i++)
68 pci_cmd_set_msi(&cmd);
70 bar = pci_device_bar(pcidev, i);
75 if (!pci_bar_mmio_space(bar)) {
76 pci_cmd_set_pmio(&cmd);
77 pci_apply_command(pcidev, cmd);
79 uart = uart16x50_pmio_create(bar->start);
82 pci_cmd_set_mmio(&cmd);
83 pci_apply_command(pcidev, cmd);
85 uart = uart16x50_mmio_create(bar->start, bar->size);
89 WARN("not accessible (BAR #%d)", i);
93 if (pci_capability_msi(pcidev)) {
94 irq = isrm_ivexalloc(uart_msi_irq_handler);
95 isrm_set_payload(irq, __ptr(uart));
96 pci_setup_msi(pcidev, irq);
99 irq = pci_intr_irq(pcidev);
100 irq = isrm_bindirq(irq, uart_intx_irq_handler);
103 INFO("base: 0x%x (%s), irq=%d (%s)",
105 pci_bar_mmio_space(bar) ? "mmio" : "pmio",
107 pci_capability_msi(pcidev) ? "msi" : "intx, re-routed");
111 sdev = uart_create_serial(uart, &def->class, &pci_ports, "PCI");
112 pci_bind_instance(pcidev, sdev);
118 static struct pci_device_def uart_pci_def = {
119 .devdef = { .class = DEVCLASS(DEVIF_PCI, DEVFN_CHAR, DEV_UART16550),
120 .name = "16550 UART (PCI/MMIO)",
121 .init = pci16550_init,
122 .bind = pci16650_binder },
123 .test_compatibility = pci16650_check_compat
125 EXPORT_PCI_DEVICE(uart16550_pci, &uart_pci_def, load_onboot);