Commit 8d9ee35f authored by Robert Sprowson's avatar Robert Sprowson Committed by ROOL

Add support for XHCI that exists on a PCI bus

Ask PCI manager if there are any XHCI controllers to attach to, then continue to HAL described ones once they're all done. Similarly ask around for the PCI root hub name.
xhci.c: Root hub name now in a RAM variable. Workaround for DMA controller problem with VL805 if the array of structure pointers is only 8 byte aligned.
xhcimodule.c/h: Do 2 pass discovery, PCI first, then HAL descriptors. Speed up interrupt despatch a bit by calling the HAL's enable/disable directly rather than via _swix(OS_Hardware). Explicitly clear the interrupt too for the case where it's latched in the PCI peripheral.

Version 0.30. Tagged as 'XHCIDriver-0_30'
parent 841353e9
/* (0.29)
/* (0.30)
*
* This file is automatically maintained by srccommit, do not edit manually.
*
*/
#define Module_MajorVersion_CMHG 0.29
#define Module_MajorVersion_CMHG 0.30
#define Module_MinorVersion_CMHG
#define Module_Date_CMHG 04 Jul 2020
#define Module_Date_CMHG 12 Sep 2020
#define Module_MajorVersion "0.29"
#define Module_Version 29
#define Module_MajorVersion "0.30"
#define Module_Version 30
#define Module_MinorVersion ""
#define Module_Date "04 Jul 2020"
#define Module_Date "12 Sep 2020"
#define Module_ApplicationDate "04-Jul-20"
#define Module_ApplicationDate "12-Sep-20"
#define Module_ComponentName "XHCIDriver"
#define Module_FullVersion "0.29"
#define Module_HelpVersion "0.29 (04 Jul 2020)"
#define Module_LibraryVersionInfo "0:29"
#define Module_FullVersion "0.30"
#define Module_HelpVersion "0.30 (12 Sep 2020)"
#define Module_LibraryVersionInfo "0:30"
......@@ -852,9 +852,15 @@ xhci_init(struct xhci_softc *sc)
sc->sc_maxspbuf = XHCI_HCS2_MAXSPBUF(hcs2);
aprint_debug_dev(sc->sc_dev, "sc_maxspbuf %d\n", sc->sc_maxspbuf);
if (sc->sc_maxspbuf != 0) {
#ifdef RISCOS
err = usb_allocmem(&sc->sc_bus,
sizeof(uint64_t) * sc->sc_maxspbuf, 64, /* Overalign for VL805 */
&sc->sc_spbufarray_dma);
#else
err = usb_allocmem(&sc->sc_bus,
sizeof(uint64_t) * sc->sc_maxspbuf, sizeof(uint64_t),
&sc->sc_spbufarray_dma);
#endif
if (err)
return err;
......@@ -881,6 +887,15 @@ xhci_init(struct xhci_softc *sc)
config |= sc->sc_maxslots & 0xFF;
xhci_op_write_4(sc, XHCI_CONFIG, config);
#ifdef RISCOS
/* Disable any SuperSpeed ports since no USB3 yet */
for (i = 0; i < sc->sc_ss_port_count; i++) {
int port = XHCI_PORTSC(sc->sc_ss_port_start + i);
/* Disable port then force RxDetect state to redo link as UBS2 or USB1 */
xhci_op_write_4(sc, port, XHCI_PS_PLS_SET(5) | XHCI_PS_PED);
}
#endif
err = xhci_ring_init(sc, &sc->sc_cr, XHCI_COMMAND_RING_TRBS,
XHCI_COMMAND_RING_SEGMENTS_ALIGN);
if (err) {
......@@ -2922,7 +2937,7 @@ xhci_root_ctrl_start(usbd_xfer_handle xfer)
break;
case 1: /* Vendor */
#ifdef RISCOS
totlen = usb_makestrdesc(sd, len, intl_lookup("RHV"));
totlen = usb_makestrdesc(sd, len, g_vendor);
#else
totlen = usb_makestrdesc(sd, len, "NetBSD");
#endif
......
......@@ -23,8 +23,8 @@
#include "Global/OSMisc.h"
#include "Global/HALEntries.h"
#include "Global/ModHand.h"
#undef Module_Title /* Avoid CMHG clash */
#include "Interface/USBDriver.h"
#include "Interface/PCI.h"
#include "callx/callx.h"
......@@ -51,7 +51,9 @@ void *g_pw;
uint32_t g_msgblock[4];
uint32_t g_instance;
uint32_t g_controller = 0;
usbloc_t g_location = LOC_PCI;
usbinfo_t g_device;
char g_vendor[32];
barrier_func barriers[3]; /* Write + Read + ReadWrite */
/* Locals */
......@@ -60,6 +62,7 @@ static struct xhci_softc xhcisoftc;
static struct device *usbstate = NULL;
static bool_t driver_up = FALSE;
static bool_t driver_registering = FALSE;
static void *hal_irqwksp, *hal_irqclear, *hal_irqenable, *hal_irqdisable;
/*
* International support functions
......@@ -123,13 +126,13 @@ static _kernel_oserror *xhcidriver_registerbus(void *mystate, struct device **yo
static _kernel_oserror *xhcidriver_spawn(_kernel_swi_regs *r, void *pw, void *arg)
{
_kernel_oserror *err;
char name[sizeof(Module_Title) + 1 + 10 + 1 + 10];
char name[sizeof(Module_Title) + 1 + 10 + 1 + 1 + 10];
/* Try to register this controller */
xhcidriver_registerbus(&xhcisoftc, &usbstate);
/* Try for another instance for another controller */
sprintf(name, Module_Title "%%%u %u", g_instance + 1, g_controller + 1);
sprintf(name, Module_Title "%%%u %c%u", g_instance + 1, g_location, g_controller + 1);
err = _swix(OS_Module, _INR(0,1), ModHandReason_NewIncarnation, name);
dprintf(("" , "Try instance %u for controller %u -> %s\n",
g_instance + 1, g_controller + 1, (err == NULL) ? "OK" : err->errmess));
......@@ -230,6 +233,62 @@ void veneer_install(int *vn, int *st, size_t sz)
entry_table + 2 * (sz / sizeof(void *)) - 1);
}
/*
* Discovery
*/
static bool_t find_pci_controllers(void)
{
_kernel_oserror *err;
size_t size;
uint32_t info[2];
err = _swix(PCI_FindByClass, _INR(0,1) | _IN(3) | _OUT(3),
0x0C0330 /* XHCI */, 0xFFFFFF, g_controller, &g_controller);
if ((err != NULL) || (g_controller == 0)) return false;
err = _swix(PCI_ReadInfo, _INR(0,3) | _OUT(2),
PCI_ReadInfo_Vendor | PCI_ReadInfo_IntDeviceVector, info, sizeof(info), g_controller,
&size);
if ((err != NULL) || (size != sizeof(info))) return false;
err = _swix(PCI_HardwareAddress, _INR(0,1) | _IN(3) | _OUT(4),
0, 0, g_controller, &g_device.hw);
if (err != NULL) return false;
/* Now construct a HAL look-a-like */
g_device.type = HALUSBControllerType_XHCI;
g_device.flags = HALUSBControllerFlag_XHCI_No_Offset;
g_device.devno = info[0];
strcpy(g_vendor, (const char *)info[1]);
return true;
}
static bool_t find_hal_controllers(void)
{
_kernel_oserror *err;
size_t size;
while (1)
{
err = _swix(OS_Hardware, _INR(0,2) | _INR(8,9) | _OUT(0),
g_controller, &g_device, sizeof(g_device),
OSHW_CallHAL, EntryNo_HAL_USBControllerInfo,
&size);
if (err != NULL) return false;
if (size == 0) return false;
if ((size == sizeof(g_device)) && (g_device.type == HALUSBControllerType_XHCI))
{
/* Found another */
break;
}
g_controller++;
}
strcpy(g_vendor, intl_lookup("RHV"));
return true;
}
/*
* Module functions
*/
......@@ -267,38 +326,41 @@ _kernel_oserror *xhcidriver_init(const char *cmd_tail, int podule_base, void *pw
MMUCReason_GetARMop + (ARMop_DMB_ReadWrite << 8), &barriers[BARRIER_READ + BARRIER_WRITE - 1]);
if (err != NULL) goto initclose;
/* Get the direct HAL IRQ routines */
err = _swix(OS_Hardware, _INR(8,9) | _OUTR(0,1),
OSHW_LookupRoutine, EntryNo_HAL_IRQEnable, &hal_irqenable, &hal_irqwksp);
if (err != NULL) goto initclose;
err = _swix(OS_Hardware, _INR(8,9) | _OUT(0),
OSHW_LookupRoutine, EntryNo_HAL_IRQDisable, &hal_irqdisable);
if (err != NULL) goto initclose;
err = _swix(OS_Hardware, _INR(8,9) | _OUT(0),
OSHW_LookupRoutine, EntryNo_HAL_IRQClear, &hal_irqclear);
if (err != NULL) goto initclose;
/* For the first instance, start at 0, otherwise continue from the
* controller number passed in the command_tail string.
*/
if (g_instance != 0)
{
if (sscanf(cmd_tail, "%u", &g_controller) == 0)
if (sscanf(cmd_tail, "%c%u", &g_location, &g_controller) != 2)
{
/* Tail missing or not a number */
err = intl_error(ERR00_SINGLE_INSTANCE);
goto initclose;
}
}
while (1)
switch (g_location)
{
size_t size;
err = _swix(OS_Hardware, _INR(0,2) | _INR(8,9) | _OUT(0),
g_controller, &g_device, sizeof(g_device),
OSHW_CallHAL, EntryNo_HAL_USBControllerInfo,
&size);
if (err != NULL) goto initclose;
if (size == 0)
{
case LOC_PCI:
if (find_pci_controllers()) break;
g_controller = 0;
g_location = LOC_HAL;
/* Fall through */
case LOC_HAL:
if (find_hal_controllers()) break;
err = intl_error(ERR01_NO_MORE_XHCI);
goto initclose;
}
if ((size == sizeof(g_device)) && (g_device.type == HALUSBControllerType_XHCI))
{
/* Found another */
break;
}
g_controller++;
}
/* Initialise this one */
......@@ -400,11 +462,10 @@ int xhcidriver_irq_handler(_kernel_swi_regs *r, void *pw)
int handled;
/* Prevent recursion by masking the device while we handle the interrupt */
_swix(OS_Hardware, _IN(0) | _INR(8,9), g_device.devno,
OSHW_CallHAL, EntryNo_HAL_IRQDisable);
hal_irqcall(g_device.devno, hal_irqdisable, hal_irqwksp);
handled = xhci_intr(&xhcisoftc);
_swix(OS_Hardware, _IN(0) | _INR(8,9), g_device.devno,
OSHW_CallHAL, EntryNo_HAL_IRQEnable);
if (handled) hal_irqcall(g_device.devno, hal_irqclear, hal_irqwksp);
hal_irqcall(g_device.devno, hal_irqenable, hal_irqwksp);
UNUSED(r);
UNUSED(pw);
......
......@@ -47,6 +47,12 @@ typedef uint8_t bool_t;
#define FALSE 0
#define TRUE (!FALSE)
typedef enum
{
LOC_PCI = 'P',
LOC_HAL = 'H'
} usbloc_t;
typedef struct
{
uint32_t type;
......@@ -61,6 +67,7 @@ typedef struct
extern void *Resources(void); /* Generated by 'resgen' */
void veneer_install(int *, int *, size_t); /* In 'veneer' */
int *veneer_init(void); /* In 'veneer' */
int hal_irqcall(int, void *, void *); /* In 'veneer' */
const char *intl_lookup(const char *);
/* Exported variables */
......@@ -69,5 +76,7 @@ extern uint32_t g_msgblock[4];
extern uint32_t g_instance;
extern uint32_t g_controller;
extern usbinfo_t g_device;
extern char g_vendor[];
extern usbloc_t g_location;
#endif
......@@ -20,6 +20,7 @@
GET Hdr:Proc
AREA |C$$code|, CODE, READONLY
EXPORT hal_irqcall
EXPORT veneer_init
EXPORT glue_rt_entry
IMPORT glue_rt_handler
......@@ -109,4 +110,14 @@ common Entry "v1,v2,fp"
EXIT
magic_end
; int hal_irqcall(int devno, void *func, void *wksp);
;
; Call one of the HAL interrupt controller routines directly, putting
; the workspace pointer into sb as required.
hal_irqcall ROUT
Entry "r9"
MOV r9, a3
BLX a2
EXIT
END
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment