XHCI baby steps!
This commit is contained in:
@@ -7,7 +7,6 @@
|
||||
#include <proc/proc.h>
|
||||
#include <proc/reschedule.h>
|
||||
#include <proc/suspension_q.h>
|
||||
#include <sync/spin_lock.h>
|
||||
|
||||
#define IDE_PROBE_AVAIL (1 << 0)
|
||||
#define IDE_PROBE_LBA48 (1 << 1)
|
||||
|
||||
@@ -2,6 +2,7 @@
|
||||
#include <device/pci.h>
|
||||
#include <device/pci_ide.h>
|
||||
#include <device/pci_info.h>
|
||||
#include <device/pci_xhci.h>
|
||||
#include <libk/lengthof.h>
|
||||
#include <libk/std.h>
|
||||
#include <libk/string.h>
|
||||
@@ -12,6 +13,7 @@
|
||||
|
||||
static const struct pci_driver_info pci_driver_infos[] = {
|
||||
{.class = 0x01, .subclass = 0x01, .init = &pci_ide_init},
|
||||
{.class = 0x0C, .subclass = 0x03, .init = &pci_xhci_init},
|
||||
};
|
||||
|
||||
static spin_lock_t pci_lock = SPIN_LOCK_INIT;
|
||||
@@ -279,7 +281,9 @@ static void pci_discovery_cb (struct proc* proc, struct reschedule_ctx* rctx,
|
||||
for (size_t driver = 0; driver < lengthof (pci_driver_infos); driver++) {
|
||||
if (pci_driver_infos[driver].class == pci_info.class &&
|
||||
pci_driver_infos[driver].subclass == pci_info.subclass) {
|
||||
pci_driver_infos[driver].init (proc, rctx, pci_info);
|
||||
if (!pci_driver_infos[driver].init (proc, rctx, pci_info)) {
|
||||
DEBUG ("Init failed. Skipping this device!\n");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
72
kernel/device/pci_xhci.c
Normal file
72
kernel/device/pci_xhci.c
Normal file
@@ -0,0 +1,72 @@
|
||||
#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;
|
||||
|
||||
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));
|
||||
|
||||
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 */
|
||||
mm_map_kernel_page (xhci_phys, xhci_base, MM_PG_RW | MM_PG_PRESENT);
|
||||
mm_map_kernel_page (xhci_phys + PAGE_SIZE, xhci_base + PAGE_SIZE, MM_PG_RW | MM_PG_PRESENT);
|
||||
|
||||
char key[32];
|
||||
snprintf (key, sizeof (key), "xhci%d", xhci_counter++);
|
||||
|
||||
struct xhci_init init = {.xhci_mmio_base = xhci_base};
|
||||
|
||||
device_op_func_t ops[] = {0};
|
||||
|
||||
struct device* xhci =
|
||||
device_create (key, ops, lengthof (ops), &xhci_init, &xhci_fini, &init, proc, rctx);
|
||||
|
||||
return true;
|
||||
}
|
||||
11
kernel/device/pci_xhci.h
Normal file
11
kernel/device/pci_xhci.h
Normal file
@@ -0,0 +1,11 @@
|
||||
#ifndef _KERNEL_DEVICE_PCI_XHCI_H
|
||||
#define _KERNEL_DEVICE_PCI_XHCI_H
|
||||
|
||||
#include <device/pci_info.h>
|
||||
#include <libk/std.h>
|
||||
#include <proc/proc.h>
|
||||
#include <proc/reschedule.h>
|
||||
|
||||
bool pci_xhci_init (struct proc* proc, struct reschedule_ctx* rctx, struct pci_info pci_info);
|
||||
|
||||
#endif // _KERNEL_DEVICE_PCI_XHCI_H
|
||||
@@ -17,11 +17,15 @@ ifeq ($(platform),amd64)
|
||||
device/idedrv.c \
|
||||
device/pci.c \
|
||||
device/pci_defs.c \
|
||||
device/pci_ide.c
|
||||
device/pci_ide.c \
|
||||
device/pci_xhci.c \
|
||||
device/xhci.c
|
||||
|
||||
o += device/ps2_kb.o \
|
||||
device/idedrv.o \
|
||||
device/pci.o \
|
||||
device/pci_defs.o \
|
||||
device/pci_ide.o
|
||||
device/pci_ide.o \
|
||||
device/pci_xhci.o \
|
||||
device/xhci.o
|
||||
endif
|
||||
|
||||
107
kernel/device/xhci.c
Normal file
107
kernel/device/xhci.c
Normal file
@@ -0,0 +1,107 @@
|
||||
#include <device/def_device_op.h>
|
||||
#include <device/device.h>
|
||||
#include <device/xhci.h>
|
||||
#include <libk/list.h>
|
||||
#include <libk/std.h>
|
||||
#include <libk/string.h>
|
||||
#include <mm/malloc.h>
|
||||
#include <proc/proc.h>
|
||||
#include <proc/reschedule.h>
|
||||
#include <proc/suspension_q.h>
|
||||
#include <sys/debug.h>
|
||||
|
||||
/* clang-format off */
|
||||
|
||||
/* capability registers */
|
||||
#define XHCI_CAPLENGTH 0x00
|
||||
#define XHCI_RSVD 0x01
|
||||
#define XHCI_HCIVERSION 0x02
|
||||
#define XHCI_HCSPARAMS1 0x04
|
||||
#define XHCI_HCSPARAMS2 0x08
|
||||
#define XHCI_HCSPARAMS3 0x0C
|
||||
#define XHCI_HCCPARAMS1 0x10
|
||||
#define XHCI_DBOFF 0x14
|
||||
#define XHCI_RTSOFF 0x18
|
||||
#define XHCI_HCCPARAMS2 0x1C
|
||||
|
||||
/* operational registers */
|
||||
#define XHCI_USBCMD 0x00
|
||||
#define XHCI_USBSTS 0x04
|
||||
#define XHCI_PAGESIZE 0x08
|
||||
#define XHCI_DNCTRL 0x14
|
||||
#define XHCI_CRCR 0x18
|
||||
#define XHCI_DCBAAP 0x30
|
||||
#define XHCI_CONFIG 0x38
|
||||
|
||||
/* port registers */
|
||||
#define XHCI_PORTSC 0x00
|
||||
#define XHCI_PORTPMSC 0x04
|
||||
#define XHCI_PORTLI 0x08
|
||||
|
||||
/* runtime registers */
|
||||
#define XHCI_MFINDEX 0x00
|
||||
/* + IRQ sets (0x20) */
|
||||
#define XHCI_IMAN 0x00
|
||||
#define XHCI_IMOD 0x04
|
||||
#define XHCI_ERSTSZ 0x08
|
||||
#define XHCI_ERSTBA 0x10
|
||||
#define XHCI_ERDP 0x18
|
||||
|
||||
/* clang-format on */
|
||||
|
||||
static void xhci_write8 (uintptr_t base, uint32_t reg, uint8_t value) {
|
||||
*(volatile uint8_t*)(base + reg) = value;
|
||||
}
|
||||
|
||||
static void xhci_write16 (uintptr_t base, uint32_t reg, uint16_t value) {
|
||||
*(volatile uint16_t*)(base + reg) = value;
|
||||
}
|
||||
|
||||
static void xhci_write32 (uintptr_t base, uint32_t reg, uint32_t value) {
|
||||
*(volatile uint32_t*)(base + reg) = value;
|
||||
}
|
||||
|
||||
static uint8_t xhci_read8 (uintptr_t base, uint32_t reg) {
|
||||
return *(volatile uint8_t*)(base + reg);
|
||||
}
|
||||
|
||||
static uint16_t xhci_read16 (uintptr_t base, uint32_t reg) {
|
||||
return *(volatile uint16_t*)(base + reg);
|
||||
}
|
||||
|
||||
static uint32_t xhci_read32 (uintptr_t base, uint32_t reg) {
|
||||
return *(volatile uint32_t*)(base + reg);
|
||||
}
|
||||
|
||||
DEFINE_DEVICE_INIT (xhci_init) {
|
||||
struct xhci* xhci = malloc (sizeof (*xhci));
|
||||
|
||||
if (xhci == NULL)
|
||||
return false;
|
||||
|
||||
struct xhci_init* init = arg;
|
||||
|
||||
memset (xhci, 0, sizeof (*xhci));
|
||||
xhci->device = device;
|
||||
xhci->xhci_mmio_base = init->xhci_mmio_base;
|
||||
|
||||
device->udata = xhci;
|
||||
|
||||
uint8_t cap_length = xhci_read8 (xhci->xhci_mmio_base, XHCI_CAPLENGTH);
|
||||
|
||||
xhci->xhci_oper_base = xhci->xhci_mmio_base + cap_length;
|
||||
|
||||
uint32_t rtsoff = xhci_read32 (xhci->xhci_mmio_base, XHCI_RTSOFF);
|
||||
xhci->xhci_runtime_base = xhci->xhci_mmio_base + rtsoff;
|
||||
|
||||
uint32_t dboff = xhci_read32 (xhci->xhci_mmio_base, XHCI_DBOFF);
|
||||
xhci->xhci_doorbell_base = xhci->xhci_mmio_base + dboff;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
DEFINE_DEVICE_FINI (xhci_fini) {
|
||||
struct xhci* xhci = device->udata;
|
||||
|
||||
free (xhci);
|
||||
}
|
||||
27
kernel/device/xhci.h
Normal file
27
kernel/device/xhci.h
Normal file
@@ -0,0 +1,27 @@
|
||||
#ifndef _KERNEL_DEVICE_XHCI_H
|
||||
#define _KERNEL_DEVICE_XHCI_H
|
||||
|
||||
#include <device/def_device_op.h>
|
||||
#include <libk/list.h>
|
||||
#include <libk/std.h>
|
||||
#include <proc/proc.h>
|
||||
#include <proc/reschedule.h>
|
||||
#include <proc/suspension_q.h>
|
||||
|
||||
struct xhci_init {
|
||||
uintptr_t xhci_mmio_base;
|
||||
};
|
||||
|
||||
struct xhci {
|
||||
struct device* device;
|
||||
uintptr_t xhci_mmio_base;
|
||||
uintptr_t xhci_oper_base;
|
||||
uintptr_t xhci_runtime_base;
|
||||
uintptr_t xhci_doorbell_base;
|
||||
};
|
||||
|
||||
DEFINE_DEVICE_INIT (xhci_init);
|
||||
|
||||
DEFINE_DEVICE_FINI (xhci_fini);
|
||||
|
||||
#endif // _KERNEL_DEVICE_XHCI_H
|
||||
Reference in New Issue
Block a user