104 lines
2.9 KiB
C
104 lines
2.9 KiB
C
#include <amd64/apic.h>
|
|
#include <amd64/intr_defs.h>
|
|
#include <device/def_device_op.h>
|
|
#include <device/device.h>
|
|
#include <device/pci.h>
|
|
#include <device/pci_info.h>
|
|
#include <device/pci_xhci.h>
|
|
#include <device/xhci.h>
|
|
#include <libk/align.h>
|
|
#include <libk/lengthof.h>
|
|
#include <libk/printf.h>
|
|
#include <libk/std.h>
|
|
#include <limine/requests.h>
|
|
#include <proc/proc.h>
|
|
#include <proc/reschedule.h>
|
|
#include <sys/debug.h>
|
|
#include <sys/mm.h>
|
|
|
|
static int xhci_counter = 0;
|
|
|
|
bool pci_xhci_init (struct proc* proc, struct reschedule_ctx* rctx, struct pci_info pci_info) {
|
|
struct limine_hhdm_response* hhdm = limine_hhdm_request.response;
|
|
|
|
if (xhci_counter == 3) {
|
|
DEBUG ("Cannot initialize more XHCI controllers\n");
|
|
return false;
|
|
}
|
|
|
|
uint8_t progif = pci_read8 (pci_info.bus, pci_info.slot, pci_info.func, PCI_PROG_IF);
|
|
|
|
/* not an XHCI controller */
|
|
if (progif != 0x30) {
|
|
return true;
|
|
}
|
|
|
|
uint16_t pci_cmd = pci_read16 (pci_info.bus, pci_info.slot, pci_info.func, PCI_COMMAND);
|
|
|
|
uint16_t new_cmd = (pci_cmd | (1 << 1) | (1 << 2)) & ~(1 << 10);
|
|
|
|
if (pci_cmd != new_cmd) {
|
|
pci_write16 (pci_info.bus, pci_info.slot, pci_info.func, PCI_COMMAND, new_cmd);
|
|
}
|
|
|
|
uintptr_t xhci_phys = 0;
|
|
|
|
uint32_t bar0 = pci_read32 (pci_info.bus, pci_info.slot, pci_info.func, PCI_BAR0);
|
|
|
|
if ((bar0 & PCI_BAR_MEM64)) {
|
|
uint32_t bar1 = pci_read32 (pci_info.bus, pci_info.slot, pci_info.func, PCI_BAR1);
|
|
xhci_phys = ((uint64_t)bar1 << 32) | (bar0 & ~0xF);
|
|
DEBUG ("XHCI phys base addr=%p (64 bit)\n", xhci_phys);
|
|
} else {
|
|
xhci_phys = (bar0 & ~0xF);
|
|
DEBUG ("XHCI phys base addr=%p (32 bit)\n", xhci_phys);
|
|
}
|
|
|
|
if (xhci_phys == 0) {
|
|
DEBUG ("WARNING xhci_phys is NULL!\n");
|
|
return false;
|
|
}
|
|
|
|
uintptr_t xhci_base = xhci_phys + (uintptr_t)hhdm->offset;
|
|
|
|
/* 2 pages should cover the mmio space */
|
|
for (size_t page = 0; page < 8; page++) {
|
|
mm_map_kernel_page (xhci_phys + page * PAGE_SIZE, xhci_base + page * PAGE_SIZE,
|
|
MM_PG_RW | MM_PG_PRESENT);
|
|
}
|
|
|
|
bool irqs_support = false;
|
|
|
|
uint32_t irq = INTR_XHCI0 + xhci_counter;
|
|
|
|
if (!pci_msi_init (pci_info.bus, pci_info.slot, pci_info.func, irq, thiscpu->lapic_id)) {
|
|
uint8_t intr_line = pci_read8 (pci_info.bus, pci_info.slot, pci_info.func, PCI_INTERRUPT_LINE);
|
|
uint8_t intr_pin = pci_read8 (pci_info.bus, pci_info.slot, pci_info.func, PCI_INTERRUPT_PIN);
|
|
|
|
if (intr_pin != 0) {
|
|
irqs_support = true;
|
|
ioapic_route_irq (irq, intr_line, 0, thiscpu->lapic_id);
|
|
}
|
|
} else {
|
|
irqs_support = true;
|
|
}
|
|
|
|
DEBUG ("IRQ support=%d\n", irqs_support);
|
|
|
|
char key[32];
|
|
snprintf (key, sizeof (key), "xhci%d", xhci_counter++);
|
|
|
|
struct xhci_init init = {
|
|
.xhci_mmio_base = xhci_base,
|
|
.irqs_support = irqs_support,
|
|
.irq = irq,
|
|
};
|
|
|
|
device_op_func_t ops[] = {0};
|
|
|
|
struct device* xhci =
|
|
device_create (key, ops, lengthof (ops), &xhci_init, &xhci_fini, &init, proc, rctx);
|
|
|
|
return true;
|
|
}
|