diff --git a/SConscript b/SConscript index a4a07943..3990cc0e 100644 --- a/SConscript +++ b/SConscript @@ -130,8 +130,11 @@ if GetDepend(['PKG_CHERRYUSB_HOST']): src += Glob('port/ehci/usb_hc_ehci.c') src += Glob('port/ehci/usb_glue_hpm.c') if GetDepend(['PKG_CHERRYUSB_HOST_EHCI_AIC']): + path += [cwd + '/port/ehci'] + path += [cwd + '/port/ohci'] src += Glob('port/ehci/usb_hc_ehci.c') src += Glob('port/ehci/usb_glue_aic.c') + src += Glob('port/ohci/usb_hc_ohci.c') if GetDepend(['PKG_CHERRYUSB_HOST_EHCI_NUVOTON_NUC980']): src += Glob('port/ehci/usb_hc_ehci.c') src += Glob('port/ehci/usb_glue_nuc980.c') @@ -198,7 +201,7 @@ if GetDepend(['PKG_CHERRYUSB_HOST']): src += Glob('demo/usb_host.c') if GetDepend('RT_USING_DFS'): - src += Glob('third_party/rt-thread-5.0/dfs_usbh_msc.c') + src += Glob('third_party/rt-thread-5.0/dfs_usbh_msc.c') group = DefineGroup('CherryUSB', src, depend = ['PKG_USING_CHERRYUSB'], CPPPATH = path, CPPDEFINES = CPPDEFINES) diff --git a/cherryusb_config_template.h b/cherryusb_config_template.h index 713db692..a0e7be64 100644 --- a/cherryusb_config_template.h +++ b/cherryusb_config_template.h @@ -160,10 +160,9 @@ #define CONFIG_USB_EHCI_HCCR_OFFSET (0x0) #define CONFIG_USB_EHCI_HCOR_OFFSET (0x10) +#define CONFIG_USB_OHCI_HCOR_OFFSET (0x400) #define CONFIG_USB_EHCI_FRAME_LIST_SIZE 1024 // #define CONFIG_USB_EHCI_HCOR_RESERVED_DISABLE // #define CONFIG_USB_EHCI_CONFIGFLAG -// #define CONFIG_USB_EHCI_PORT_POWER -// #define CONFIG_USB_EHCI_PRINT_HW_PARAM #endif diff --git a/port/ehci/usb_ehci_priv.h b/port/ehci/usb_ehci_priv.h index f6e4ff00..a134c668 100644 --- a/port/ehci/usb_ehci_priv.h +++ b/port/ehci/usb_ehci_priv.h @@ -1,3 +1,8 @@ +/* + * Copyright (c) 2022, sakumisu + * + * SPDX-License-Identifier: Apache-2.0 + */ #ifndef _USB_EHCI_PRIV_H #define _USB_EHCI_PRIV_H @@ -47,6 +52,12 @@ struct ehci_itd_hw { struct ehci_hcd { bool ehci_qh_used[CONFIG_USB_EHCI_QH_NUM]; bool ehci_itd_used[CONFIG_USB_EHCI_ITD_NUM]; + bool ppc; /* Port Power Control */ + bool has_tt; /* if use tt instead of Companion Controller */ + uint8_t n_cc; /* Number of Companion Controller */ + uint8_t n_pcc; /* Number of ports supported per companion host controller */ + uint8_t n_ports; + uint8_t hccr_offset; }; extern struct ehci_hcd g_ehci_hcd[CONFIG_USBHOST_MAX_BUS]; diff --git a/port/ehci/usb_glue_aic.c b/port/ehci/usb_glue_aic.c index 0d0db4d6..5445b535 100644 --- a/port/ehci/usb_glue_aic.c +++ b/port/ehci/usb_glue_aic.c @@ -19,6 +19,13 @@ static void aic_ehci_isr(int vector, void *arg) USBH_IRQHandler(bus->hcd.hcd_id); } +static void aic_ohci_isr(int vector, void *arg) +{ + struct usbh_bus *bus = (struct usbh_bus *)arg; + extern void OHCI_IRQHandler(uint8_t busid); + OHCI_IRQHandler(bus->hcd.hcd_id); +} + typedef struct aic_ehci_config { uint32_t base_addr; uint32_t clk_id; @@ -107,6 +114,8 @@ void usb_hc_low_level_init(struct usbh_bus *bus) /* register interrupt callback */ aicos_request_irq(config[i].irq_num, (irq_handler_t)aic_ehci_isr, 0, "usb_host_ehci", bus); + aicos_request_irq(config[i].irq_num + 1, (irq_handler_t)aic_ohci_isr, + 0, "usb_host_ohci", bus); aicos_irq_enable(config[i].irq_num); } @@ -155,7 +164,6 @@ int usbh_init(void) usbh_initialize(bus_id, USB_HOST1_BASE); bus_id++; #endif - return 0; } diff --git a/port/ehci/usb_hc_ehci.c b/port/ehci/usb_hc_ehci.c index 8d39dc6e..413f5112 100644 --- a/port/ehci/usb_hc_ehci.c +++ b/port/ehci/usb_hc_ehci.c @@ -4,6 +4,9 @@ * SPDX-License-Identifier: Apache-2.0 */ #include "usb_ehci_priv.h" +#ifdef CONFIG_USB_EHCI_WITH_OHCI +#include "usb_ohci_priv.h" +#endif #define EHCI_TUNE_CERR 3 /* 0-3 qtd retries; 0 == don't stop */ #define EHCI_TUNE_RL_HS 4 /* nak throttle; see 4.9 */ @@ -770,11 +773,24 @@ int usb_hc_init(struct usbh_bus *bus) EHCI_HCOR->usbintr = 0; EHCI_HCOR->usbsts = EHCI_HCOR->usbsts; -#ifdef CONFIG_USB_EHCI_PRINT_HW_PARAM - USB_LOG_INFO("EHCI HCIVERSION:%04x\r\n", (int)EHCI_HCCR->hciversion); - USB_LOG_INFO("EHCI HCSPARAMS:%06x\r\n", (int)EHCI_HCCR->hcsparams); - USB_LOG_INFO("EHCI HCCPARAMS:%04x\r\n", (int)EHCI_HCCR->hccparams); -#endif + + USB_LOG_INFO("EHCI HCIVERSION:0x%04x\r\n", (unsigned int)EHCI_HCCR->hciversion); + USB_LOG_INFO("EHCI HCSPARAMS:0x%06x\r\n", (unsigned int)EHCI_HCCR->hcsparams); + USB_LOG_INFO("EHCI HCCPARAMS:0x%04x\r\n", (unsigned int)EHCI_HCCR->hccparams); + + g_ehci_hcd[bus->hcd.hcd_id].ppc = (EHCI_HCCR->hcsparams & EHCI_HCSPARAMS_PPC) ? true : false; + g_ehci_hcd[bus->hcd.hcd_id].n_ports = (EHCI_HCCR->hcsparams & EHCI_HCSPARAMS_NPORTS_MASK) >> EHCI_HCSPARAMS_NPORTS_SHIFT; + g_ehci_hcd[bus->hcd.hcd_id].n_cc = (EHCI_HCCR->hcsparams & EHCI_HCSPARAMS_NCC_MASK) >> EHCI_HCSPARAMS_NCC_SHIFT; + g_ehci_hcd[bus->hcd.hcd_id].n_pcc = (EHCI_HCCR->hcsparams & EHCI_HCSPARAMS_NPCC_MASK) >> EHCI_HCSPARAMS_NPCC_SHIFT; + g_ehci_hcd[bus->hcd.hcd_id].has_tt = g_ehci_hcd[bus->hcd.hcd_id].n_cc ? false : true; + g_ehci_hcd[bus->hcd.hcd_id].hccr_offset = EHCI_HCCR->caplength; + + USB_LOG_INFO("EHCI ppc:%u, n_ports:%u, n_cc:%u, n_pcc:%u\r\n", + g_ehci_hcd[bus->hcd.hcd_id].ppc, + g_ehci_hcd[bus->hcd.hcd_id].n_ports, + g_ehci_hcd[bus->hcd.hcd_id].n_cc, + g_ehci_hcd[bus->hcd.hcd_id].n_pcc); + /* Set the Current Asynchronous List Address. */ EHCI_HCOR->asynclistaddr = EHCI_PTR2ADDR(&g_async_qh_head[bus->hcd.hcd_id]); /* Set the Periodic Frame List Base Address. */ @@ -809,13 +825,32 @@ int usb_hc_init(struct usbh_bus *bus) return -USB_ERR_TIMEOUT; } } -#ifdef CONFIG_USB_EHCI_PORT_POWER - for (uint8_t port = 0; port < CONFIG_USBHOST_MAX_RHPORTS; port++) { - regval = EHCI_HCOR->portsc[port]; - regval |= EHCI_PORTSC_PP; - EHCI_HCOR->portsc[port] = regval; + + if (g_ehci_hcd[bus->hcd.hcd_id].ppc) { + for (uint8_t port = 0; port < g_ehci_hcd[bus->hcd.hcd_id].n_ports; port++) { + regval = EHCI_HCOR->portsc[port]; + regval |= EHCI_PORTSC_PP; + EHCI_HCOR->portsc[port] = regval; + } } + + if (g_ehci_hcd[bus->hcd.hcd_id].has_tt) { +#ifdef CONFIG_USB_EHCI_WITH_OHCI + USB_LOG_INFO("EHCI uses tt for ls/fs device, so cannot enable this macro\r\n"); + return -USB_ERR_INVAL; #endif + } + + if (g_ehci_hcd[bus->hcd.hcd_id].has_tt) { + USB_LOG_INFO("EHCI uses tt for ls/fs device\r\n"); + } else { +#ifdef CONFIG_USB_EHCI_WITH_OHCI + USB_LOG_INFO("EHCI uses companion controller for ls/fs device\r\n"); + ohci_init(bus); +#else + USB_LOG_WRN("Do not enable companion controller, you should use a hub to support ls/fs device\r\n"); +#endif + } /* Enable EHCI interrupts. */ EHCI_HCOR->usbintr = EHCI_USBIE_INT | EHCI_USBIE_ERR | EHCI_USBIE_PCD | EHCI_USBIE_FATAL | EHCI_USBIE_IAA; @@ -845,13 +880,13 @@ int usb_hc_deinit(struct usbh_bus *bus) } } -#ifdef CONFIG_USB_EHCI_PORT_POWER - for (uint8_t port = 0; port < CONFIG_USBHOST_MAX_RHPORTS; port++) { - regval = EHCI_HCOR->portsc[port]; - regval &= ~EHCI_PORTSC_PP; - EHCI_HCOR->portsc[port] = regval; + if (g_ehci_hcd[bus->hcd.hcd_id].ppc) { + for (uint8_t port = 0; port < g_ehci_hcd[bus->hcd.hcd_id].n_ports; port++) { + regval = EHCI_HCOR->portsc[port]; + regval &= ~EHCI_PORTSC_PP; + EHCI_HCOR->portsc[port] = regval; + } } -#endif #ifdef CONFIG_USB_EHCI_CONFIGFLAG EHCI_HCOR->configflag = 0; @@ -864,12 +899,22 @@ int usb_hc_deinit(struct usbh_bus *bus) usb_osal_sem_delete(qh->waitsem); } +#ifdef CONFIG_USB_EHCI_WITH_OHCI + ohci_deinit(bus); +#endif + usb_hc_low_level_deinit(bus); return 0; } uint16_t usbh_get_frame_number(struct usbh_bus *bus) { +#ifdef CONFIG_USB_EHCI_WITH_OHCI + if (EHCI_HCOR->portsc[0] & EHCI_PORTSC_OWNER) { + return ohci_get_frame_number(bus); + } +#endif + return (((EHCI_HCOR->frindex & EHCI_FRINDEX_MASK) >> 3) & 0x3ff); } @@ -879,9 +924,25 @@ int usbh_roothub_control(struct usbh_bus *bus, struct usb_setup_packet *setup, u uint8_t port; uint32_t temp, status; - nports = CONFIG_USBHOST_MAX_RHPORTS; + nports = g_ehci_hcd[bus->hcd.hcd_id].n_ports; port = setup->wIndex; + + temp = EHCI_HCOR->portsc[port - 1]; + +#ifdef CONFIG_USB_EHCI_WITH_OHCI + if (temp & EHCI_PORTSC_OWNER) { + return ohci_roothub_control(bus, setup, buf); + } + + if ((temp & EHCI_PORTSC_LSTATUS_MASK) == EHCI_PORTSC_LSTATUS_KSTATE) { + EHCI_HCOR->portsc[port - 1] |= EHCI_PORTSC_OWNER; + + while (!(EHCI_HCOR->portsc[port - 1] & EHCI_PORTSC_OWNER)) { + } + return ohci_roothub_control(bus, setup, buf); + } +#endif if (setup->bmRequestType & USB_REQUEST_RECIPIENT_DEVICE) { switch (setup->bRequest) { case HUB_REQUEST_CLEAR_FEATURE: @@ -942,9 +1003,7 @@ int usbh_roothub_control(struct usbh_bus *bus, struct usb_setup_packet *setup, u case HUB_PORT_FEATURE_C_SUSPEND: break; case HUB_PORT_FEATURE_POWER: -#ifdef CONFIG_USB_EHCI_PORT_POWER EHCI_HCOR->portsc[port - 1] &= ~EHCI_PORTSC_PP; -#endif break; case HUB_PORT_FEATURE_C_CONNECTION: EHCI_HCOR->portsc[port - 1] |= EHCI_PORTSC_CSC; @@ -982,12 +1041,19 @@ int usbh_roothub_control(struct usbh_bus *bus, struct usb_setup_packet *setup, u } break; case HUB_PORT_FEATURE_POWER: -#ifdef CONFIG_USB_EHCI_PORT_POWER EHCI_HCOR->portsc[port - 1] |= EHCI_PORTSC_PP; -#endif break; case HUB_PORT_FEATURE_RESET: usbh_reset_port(bus, port); +#ifdef CONFIG_USB_EHCI_WITH_OHCI + if (!(EHCI_HCOR->portsc[port - 1] & EHCI_PORTSC_PE)) { + EHCI_HCOR->portsc[port - 1] |= EHCI_PORTSC_OWNER; + + while (!(EHCI_HCOR->portsc[port - 1] & EHCI_PORTSC_OWNER)) { + } + return ohci_roothub_control(bus, setup, buf); + } +#endif break; default: @@ -1067,6 +1133,12 @@ int usbh_submit_urb(struct usbh_urb *urb) hub = hub->parent->parent; } +#ifdef CONFIG_USB_EHCI_WITH_OHCI + if (EHCI_HCOR->portsc[hport->port - 1] & EHCI_PORTSC_OWNER) { + return ohci_submit_urb(urb); + } +#endif + if (!urb->hport->connected || !(EHCI_HCOR->portsc[hport->port - 1] & EHCI_PORTSC_CCS)) { return -USB_ERR_NOTCONN; } @@ -1138,12 +1210,18 @@ int usbh_kill_urb(struct usbh_urb *urb) struct usbh_bus *bus; size_t flags; - if (!urb || !urb->hcpriv || !urb->hport->bus) { + if (!urb || !urb->hport || !urb->hcpriv || !urb->hport->bus) { return -USB_ERR_INVAL; } bus = urb->hport->bus; +#ifdef CONFIG_USB_EHCI_WITH_OHCI + if (EHCI_HCOR->portsc[urb->hport->port - 1] & EHCI_PORTSC_OWNER) { + return ohci_kill_urb(urb); + } +#endif + flags = usb_osal_enter_critical_section(); EHCI_HCOR->usbcmd &= ~(EHCI_USBCMD_PSEN | EHCI_USBCMD_ASEN); @@ -1245,7 +1323,7 @@ void USBH_IRQHandler(uint8_t busid) } if (usbsts & EHCI_USBSTS_PCD) { - for (int port = 0; port < CONFIG_USBHOST_MAX_RHPORTS; port++) { + for (int port = 0; port < g_ehci_hcd[bus->hcd.hcd_id].n_ports; port++) { uint32_t portsc = EHCI_HCOR->portsc[port]; if (portsc & EHCI_PORTSC_CSC) { diff --git a/port/ehci/usb_hc_ehci.h b/port/ehci/usb_hc_ehci.h index 15cada31..7f3febc2 100644 --- a/port/ehci/usb_hc_ehci.h +++ b/port/ehci/usb_hc_ehci.h @@ -281,12 +281,12 @@ */ struct ehci_hccr { - uint8_t caplength; /* 0x00: Capability Register Length */ - uint8_t reserved; /* 0x01: reserved */ - uint16_t hciversion; /* 0x02: Interface Version Number */ - uint32_t hcsparams; /* 0x04: Structural Parameters */ - uint32_t hccparams; /* 0x08: Capability Parameters */ - uint8_t hcspportroute[8]; /* 0x0c: Companion Port Route Description */ + volatile uint8_t caplength; /* 0x00: Capability Register Length */ + volatile uint8_t reserved; /* 0x01: reserved */ + volatile uint16_t hciversion; /* 0x02: Interface Version Number */ + volatile uint32_t hcsparams; /* 0x04: Structural Parameters */ + volatile uint32_t hccparams; /* 0x08: Capability Parameters */ + volatile uint8_t hcspportroute[8]; /* 0x0c: Companion Port Route Description */ }; /* Host Controller Operational Registers. @@ -295,18 +295,18 @@ struct ehci_hccr { */ struct ehci_hcor { - uint32_t usbcmd; /* 0x00: USB Command */ - uint32_t usbsts; /* 0x04: USB Status */ - uint32_t usbintr; /* 0x08: USB Interrupt Enable */ - uint32_t frindex; /* 0x0c: USB Frame Index */ - uint32_t ctrldssegment; /* 0x10: 4G Segment Selector */ - uint32_t periodiclistbase; /* 0x14: Frame List Base Address */ - uint32_t asynclistaddr; /* 0x18: Next Asynchronous List Address */ + volatile uint32_t usbcmd; /* 0x00: USB Command */ + volatile uint32_t usbsts; /* 0x04: USB Status */ + volatile uint32_t usbintr; /* 0x08: USB Interrupt Enable */ + volatile uint32_t frindex; /* 0x0c: USB Frame Index */ + volatile uint32_t ctrldssegment; /* 0x10: 4G Segment Selector */ + volatile uint32_t periodiclistbase; /* 0x14: Frame List Base Address */ + volatile uint32_t asynclistaddr; /* 0x18: Next Asynchronous List Address */ #ifndef CONFIG_USB_EHCI_HCOR_RESERVED_DISABLE uint32_t reserved[9]; #endif - uint32_t configflag; /* 0x40: Configured Flag Register */ - uint32_t portsc[15]; /* 0x44: Port Status/Control */ + volatile uint32_t configflag; /* 0x40: Configured Flag Register */ + volatile uint32_t portsc[15]; /* 0x44: Port Status/Control */ }; /* USB2 Debug Port Register Interface. @@ -357,7 +357,7 @@ struct ehci_itd { uint32_t bpl[7]; /* 0x24-0x3c: Buffer Page Pointer List */ }; -#define SIZEOF_EHCI_ITD_S (64) /* 16*sizeof(uint32_t) */ +#define SIZEOF_EHCI_ITD (64) /* 16*sizeof(uint32_t) */ /* Split Transaction Isochronous Transfer Descriptor (siTD). Paragraph 3.4 */ @@ -370,6 +370,6 @@ struct ehci_sitd { uint32_t blp; /* 0x18-0x1b: Back link pointer */ }; -#define SIZEOF_EHCI_SITD_S (28) /* 7*sizeof(uint32_t) */ +#define SIZEOF_EHCI_SITD (28) /* 7*sizeof(uint32_t) */ #endif /* USB_HC_EHCI_H */ diff --git a/port/ohci/README.md b/port/ohci/README.md new file mode 100644 index 00000000..34e753c3 --- /dev/null +++ b/port/ohci/README.md @@ -0,0 +1,18 @@ +# Note + +This OHCI is a companion controller of EHCI. + +## Support Chip List + +### AllwinnerTech + +- F133 + +### Nuvoton + +- Nuvoton all series + +### Artinchip + +- d13x, d21x + diff --git a/port/ohci/usb_hc_ohci.c b/port/ohci/usb_hc_ohci.c new file mode 100644 index 00000000..b3d65829 --- /dev/null +++ b/port/ohci/usb_hc_ohci.c @@ -0,0 +1,240 @@ +/* + * Copyright (c) 2024, sakumisu + * + * SPDX-License-Identifier: Apache-2.0 + */ +#include "usb_ohci_priv.h" +#include "usb_ehci_priv.h" + +int ohci_init(struct usbh_bus *bus) +{ + volatile uint32_t timeout = 0; + uint32_t regval; + + USB_LOG_INFO("OHCI hcrevision:0x%02x\r\n", (unsigned int)OHCI_HCOR->hcrevision); + + OHCI_HCOR->hccontrol = 0; + OHCI_HCOR->hccontrolheaded = 0; + OHCI_HCOR->hcbulkheaded = 0; + + OHCI_HCOR->hccmdsts = OHCI_CMDST_HCR; + while (OHCI_HCOR->hccmdsts & OHCI_CMDST_HCR) { + usb_osal_msleep(1); + timeout++; + if (timeout > 100) { + return -USB_ERR_TIMEOUT; + } + } + + /* Frame Interval / Periodic Start. + * + * At 12Mbps, there are 12000 bit time in each 1Msec frame. + */ + +#define BITS_PER_FRAME 12000 +#define FI (BITS_PER_FRAME - 1) +#define FSMPS ((6 * (FI - 210)) / 7) +#define DEFAULT_FMINTERVAL ((FSMPS << OHCI_FMINT_FSMPS_SHIFT) | FI) +#define DEFAULT_PERSTART (((9 * BITS_PER_FRAME) / 10) - 1) + + OHCI_HCOR->hcfminterval = DEFAULT_FMINTERVAL; + OHCI_HCOR->hcperiodicstart = DEFAULT_PERSTART; + + /* Put HC in operational state */ + regval = OHCI_HCOR->hccontrol; + regval &= ~OHCI_CTRL_HCFS_MASK; + regval |= OHCI_CTRL_HCFS_OPER; + OHCI_HCOR->hccontrol = regval; + + /* Set global power in HcRhStatus */ + OHCI_HCOR->hcrhsts = OHCI_RHSTATUS_SGP; + + /* Set HCCA base address */ + OHCI_HCOR->hchcca = 0; + + /* Clear pending interrupts */ + regval = OHCI_HCOR->hcintsts; + OHCI_HCOR->hcintsts = regval; + + for (uint8_t port = 0; port < g_ehci_hcd[bus->hcd.hcd_id].n_pcc; port++) { + regval = OHCI_HCOR->hcrhportsts[port]; + regval |= OHCI_RHPORTST_PPS; + OHCI_HCOR->hcrhportsts[port] = regval; + } + + /* Enable OHCI interrupts */ + OHCI_HCOR->hcinten = OHCI_INT_SO | OHCI_INT_RD | OHCI_INT_UE | OHCI_INT_OC | + OHCI_INT_WDH | OHCI_INT_RHSC | OHCI_INT_MIE; + + return 0; +} + +int ohci_deinit(struct usbh_bus *bus) +{ + uint32_t regval; + + /* Disable OHCI interrupts */ + OHCI_HCOR->hcintdis = OHCI_INT_SO | OHCI_INT_RD | OHCI_INT_UE | OHCI_INT_OC | + OHCI_INT_WDH | OHCI_INT_RHSC | OHCI_INT_MIE; + + for (uint8_t port = 0; port < g_ehci_hcd[bus->hcd.hcd_id].n_pcc; port++) { + regval = OHCI_HCOR->hcrhportsts[port]; + regval &= ~OHCI_RHPORTST_PPS; + OHCI_HCOR->hcrhportsts[port] = regval; + } + + return 0; +} + +uint16_t ohci_get_frame_number(struct usbh_bus *bus) +{ + return OHCI_HCOR->hcfmnumber; +} + +int ohci_roothub_control(struct usbh_bus *bus, struct usb_setup_packet *setup, uint8_t *buf) +{ + uint8_t nports; + uint8_t port; + uint32_t temp; + + nports = g_ehci_hcd[bus->hcd.hcd_id].n_pcc; + + port = setup->wIndex; + if (setup->bmRequestType & USB_REQUEST_RECIPIENT_DEVICE) { + switch (setup->bRequest) { + case HUB_REQUEST_CLEAR_FEATURE: + switch (setup->wValue) { + case HUB_FEATURE_HUB_C_LOCALPOWER: + break; + case HUB_FEATURE_HUB_C_OVERCURRENT: + break; + default: + return -USB_ERR_NOTSUPP; + } + break; + case HUB_REQUEST_SET_FEATURE: + switch (setup->wValue) { + case HUB_FEATURE_HUB_C_LOCALPOWER: + break; + case HUB_FEATURE_HUB_C_OVERCURRENT: + break; + default: + return -USB_ERR_NOTSUPP; + } + break; + case HUB_REQUEST_GET_DESCRIPTOR: + break; + case HUB_REQUEST_GET_STATUS: + memset(buf, 0, 4); + break; + default: + break; + } + } else if (setup->bmRequestType & USB_REQUEST_RECIPIENT_OTHER) { + switch (setup->bRequest) { + case HUB_REQUEST_CLEAR_FEATURE: + if (!port || port > nports) { + return -USB_ERR_INVAL; + } + + switch (setup->wValue) { + case HUB_PORT_FEATURE_ENABLE: + break; + case HUB_PORT_FEATURE_SUSPEND: + + case HUB_PORT_FEATURE_C_SUSPEND: + break; + case HUB_PORT_FEATURE_POWER: + break; + case HUB_PORT_FEATURE_C_CONNECTION: + OHCI_HCOR->hcrhportsts[port - 1] |= OHCI_RHPORTST_CSC; + break; + case HUB_PORT_FEATURE_C_ENABLE: + OHCI_HCOR->hcrhportsts[port - 1] |= OHCI_RHPORTST_PESC; + break; + case HUB_PORT_FEATURE_C_OVER_CURREN: + OHCI_HCOR->hcrhportsts[port - 1] |= OHCI_RHPORTST_OCIC; + break; + case HUB_PORT_FEATURE_C_RESET: + OHCI_HCOR->hcrhportsts[port - 1] |= OHCI_RHPORTST_PRSC; + break; + default: + return -USB_ERR_NOTSUPP; + } + break; + case HUB_REQUEST_SET_FEATURE: + if (!port || port > nports) { + return -USB_ERR_INVAL; + } + + switch (setup->wValue) { + case HUB_PORT_FEATURE_SUSPEND: + break; + case HUB_PORT_FEATURE_POWER: + break; + case HUB_PORT_FEATURE_RESET: + OHCI_HCOR->hcrhportsts[port - 1] |= OHCI_RHPORTST_PRS; + + while (OHCI_HCOR->hcrhportsts[port - 1] & OHCI_RHPORTST_PRS) { + } + break; + + default: + return -USB_ERR_NOTSUPP; + } + break; + case HUB_REQUEST_GET_STATUS: + if (!port || port > nports) { + return -USB_ERR_INVAL; + } + temp = OHCI_HCOR->hcrhportsts[port - 1]; + + memcpy(buf, &temp, 4); + break; + default: + break; + } + } + return 0; +} + +int ohci_submit_urb(struct usbh_urb *urb) +{ + return -USB_ERR_NOTSUPP; +} + +int ohci_kill_urb(struct usbh_urb *urb) +{ + return -USB_ERR_NOTSUPP; +} + +void OHCI_IRQHandler(uint8_t busid) +{ + uint32_t usbsts; + struct usbh_bus *bus; + + bus = &g_usbhost_bus[busid]; + + usbsts = OHCI_HCOR->hcintsts & OHCI_HCOR->hcinten; + OHCI_HCOR->hcintsts = usbsts; + + if (usbsts & OHCI_INT_RHSC) { + for (int port = 0; port < CONFIG_USBHOST_MAX_RHPORTS; port++) { + uint32_t portsc = OHCI_HCOR->hcrhportsts[port]; + + if (portsc & OHCI_RHPORTST_CSC) { + if (OHCI_HCOR->hcrhsts & OHCI_RHSTATUS_DRWE) { + /* If DRWE is set, Connect Status Change indicates a remote wake-up event */ + } else { + if (portsc & OHCI_RHPORTST_CCS) { + } else { + } + bus->hcd.roothub.int_buffer[0] |= (1 << (port + 1)); + usbh_hub_thread_wakeup(&bus->hcd.roothub); + } + } + } + } + if (usbsts & OHCI_INT_WDH) { + } +} \ No newline at end of file diff --git a/port/ohci/usb_hc_ohci.h b/port/ohci/usb_hc_ohci.h new file mode 100644 index 00000000..030350e5 --- /dev/null +++ b/port/ohci/usb_hc_ohci.h @@ -0,0 +1,484 @@ +/**************************************************************************** + * include/nuttx/usb/ohci.h + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. The + * ASF licenses this file to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance with the + * License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the + * License for the specific language governing permissions and limitations + * under the License. + * + ****************************************************************************/ + +#ifndef __INCLUDE_NUTTX_USB_OHCI_H +#define __INCLUDE_NUTTX_USB_OHCI_H + +/**************************************************************************** + * Included Files + ****************************************************************************/ + +#include + +/**************************************************************************** + * Pre-processor Definitions + ****************************************************************************/ + +/* Register offsets *********************************************************/ + +/* Control and status registers (section 7.1) */ + +#define OHCI_HCIREV_OFFSET 0x0000 /* HcRevision: Version of HCI specification */ +#define OHCI_CTRL_OFFSET 0x0004 /* HcControl: HC control */ +#define OHCI_CMDST_OFFSET 0x0008 /* HcCommandStatus: HC command status */ +#define OHCI_INTST_OFFSET 0x000c /* HcInterruptStatus: HC interrupt status */ +#define OHCI_INTEN_OFFSET 0x0010 /* HcInterruptEnable: HC interrupt enable */ +#define OHCI_INTDIS_OFFSET 0x0014 /* HcInterruptDisable: HC interrupt disable */ + +/* Memory pointer registers (section 7.2) */ + +#define OHCI_HCCA_OFFSET 0x0018 /* HcHCCA: HC communication area */ +#define OHCI_PERED_OFFSET 0x001c /* HcPeriodCurrentED: Current isoc or int endpoint desc */ +#define OHCI_CTRLHEADED_OFFSET 0x0020 /* HcControlHeadED: First EP desc in the control list */ +#define OHCI_CTRLED_OFFSET 0x0024 /* HcControlCurrentED: Current EP desc in the control list */ +#define OHCI_BULKHEADED_OFFSET 0x0028 /* HcBulkHeadED: First EP desc in the bulk list */ +#define OHCI_BULKED_OFFSET 0x002c /* HcBulkCurrentED: Current EP desc in the bulk list */ +#define OHCI_DONEHEAD_OFFSET 0x0030 /* HcDoneHead: Last transfer desc added to DONE queue */ + +/* Frame counter registers (section 7.3) */ + +#define OHCI_FMINT_OFFSET 0x0034 /* HcFmInterval: Bit time interval that would not cause overrun */ +#define OHCI_FMREM_OFFSET 0x0038 /* HcFmRemaining: Bit time remaining in current frame */ +#define OHCI_FMNO_OFFSET 0x003c /* HcFmNumber: Frame number counter */ +#define OHCI_PERSTART_OFFSET 0x0040 /* HcPeriodicStart: Time to start processing periodic list */ + +/* Root hub registers (section 7.4) */ + +#define OHCI_LSTHRES_OFFSET 0x0044 /* HcLSThreshold: Commit to transfer threshold */ +#define OHCI_RHDESCA_OFFSET 0x0048 /* HcRhDescriptorA: Describes root hub (part A) */ +#define OHCI_RHDESCB_OFFSET 0x004c /* HcRhDescriptorB: Describes root hub (part B) */ +#define OHCI_RHSTATUS_OFFSET 0x0050 /* HcRhStatus: Root hub status */ + +#define OHCI_MAX_RHPORT 15 /* Maximum number of OHCI root hub ports */ + +#define OHCI_RHPORTST_OFFSET(n) (0x0054 + (((n) - 1) << 2)) +#define OHCI_RHPORTST1_OFFSET 0x0054 /* HcRhPort1Status: Root hub port status 1 */ +#define OHCI_RHPORTST2_OFFSET 0x0058 /* HcRhPort2Status: Root hub port status 2 */ +#define OHCI_RHPORTST3_OFFSET 0x005c /* HcRhPort3Status: Root hub port status 3 */ +#define OHCI_RHPORTST4_OFFSET 0x0060 /* HcRhPort4Status: Root hub port status 4 */ +#define OHCI_RHPORTST5_OFFSET 0x0064 /* HcRhPort5Status: Root hub port status 5 */ +#define OHCI_RHPORTST6_OFFSET 0x0068 /* HcRhPort6Status: Root hub port status 6 */ +#define OHCI_RHPORTST7_OFFSET 0x006c /* HcRhPort7Status: Root hub port status 7 */ +#define OHCI_RHPORTST8_OFFSET 0x0070 /* HcRhPort8Status: Root hub port status 8 */ +#define OHCI_RHPORTST9_OFFSET 0x0074 /* HcRhPort9Status: Root hub port status 9 */ +#define OHCI_RHPORTST10_OFFSET 0x0078 /* HcRhPort10Status: Root hub port status 10 */ +#define OHCI_RHPORTST11_OFFSET 0x007c /* HcRhPort11Status: Root hub port status 11 */ +#define OHCI_RHPORTST12_OFFSET 0x0080 /* HcRhPort12Status: Root hub port status 12 */ +#define OHCI_RHPORTST13_OFFSET 0x0084 /* HcRhPort13Status: Root hub port status 13 */ +#define OHCI_RHPORTST14_OFFSET 0x0088 /* HcRhPort14Status: Root hub port status 14 */ +#define OHCI_RHPORTST15_OFFSET 0x008c /* HcRhPort15Status: Root hub port status 15 */ + +/* Register bit definitions *************************************************/ + +/* HcRevision: Version of HCI specification (7.1.1) */ + +#define OHCI_HCIREV_SHIFT (0) /* Bits 0-7: HCI spec version (BCD) */ +#define OHCI_HCIREV_MASK (0xff << OHCI_HCIREV_SHIFT) + +/* HcControl: HC control (7.1.2) */ + +#define OHCI_CTRL_CBSR (3 << 0) /* Bit 0: Control/bulk service ratio */ +#define OHCI_CTRL_PLE (1 << 2) /* Bit 1: Periodic list enable */ +#define OHCI_CTRL_IE (1 << 3) /* Bit 2: Isochronous enable */ +#define OHCI_CTRL_CLE (1 << 4) /* Bit 3: Control list enable */ +#define OHCI_CTRL_BLE (1 << 5) /* Bit 4: Bulk list enable */ +#define OHCI_CTRL_HCFS_SHIFT (6) /* Bits 6-7: Host controller functional state */ +#define OHCI_CTRL_HCFS_MASK (3 << OHCI_CTRL_HCFS_SHIFT) +# define OHCI_CTRL_HCFS_RESET (0 << OHCI_CTRL_HCFS_SHIFT) +# define OHCI_CTRL_HCFS_RESUME (1 << OHCI_CTRL_HCFS_SHIFT) +# define OHCI_CTRL_HCFS_OPER (2 << OHCI_CTRL_HCFS_SHIFT) +# define OHCI_CTRL_HCFS_SUSPEND (3 << OHCI_CTRL_HCFS_SHIFT) +#define OHCI_CTRL_IR (1 << 8) /* Bit 8: Interrupt routing */ +#define OHCI_CTRL_RWC (1 << 9) /* Bit 9: Remote wakeup connected */ +#define OHCI_CTRL_RWE (1 << 10) /* Bit 10: Remote wakeup enable */ + /* Bits 11-31: Reserved */ + +/* HcCommandStatus: HC command status (7.1.3) */ + +#define OHCI_CMDST_HCR (1 << 0) /* Bit 0: Host controller reset */ +#define OHCI_CMDST_CLF (1 << 1) /* Bit 1: Control list filled */ +#define OHCI_CMDST_BLF (1 << 2) /* Bit 2: Bulk list filled */ +#define OHCI_CMDST_OCR (1 << 3) /* Bit 3: Ownership change request */ + /* Bits 4-15: Reserved */ +#define OHCI_CMDST_SOC (3 << 16) /* Bit 16: Scheduling overrun count */ + /* Bits 17-31: Reserved */ + +/* HcInterruptStatus: HC interrupt status (7.1.4), + * HcInterruptEnable: HC interrupt enable (7.1.5), and + * HcInterruptDisable: HC interrupt disable (7.1.6) + */ + +#define OHCI_INT_SO (1 << 0) /* Bit 0: Scheduling overrun */ +#define OHCI_INT_WDH (1 << 1) /* Bit 1: Writeback done head */ +#define OHCI_INT_SF (1 << 2) /* Bit 2: Start of frame */ +#define OHCI_INT_RD (1 << 3) /* Bit 3: Resume detected */ +#define OHCI_INT_UE (1 << 4) /* Bit 4: Unrecoverable error */ +#define OHCI_INT_FNO (1 << 5) /* Bit 5: Frame number overflow */ +#define OHCI_INT_RHSC (1 << 6) /* Bit 6: Root hub status change */ + /* Bits 7-29: Reserved */ +#define OHCI_INT_OC (1 << 30) /* Bit 30: Ownership change */ +#define OHCI_INT_MIE (1 << 31) /* Bit 31: Master interrupt enable + * (Enable/disable only) */ + +/* HcHCCA: HC communication area (7.2.1): + * + * 32-bits aligned to 256 byte boundary. + */ + +/* HcPeriodCurrentED: Current isoc or int endpoint desc (7.2.2), + * HcControlHeadED: First EP desc in the control list (7.2.3), + * HcControlCurrentED: Current EP desc in the control list (7.2.4), + * HcBulkHeadED: First EP desc in the bulk list (7.2.5), + * HcBulkCurrentED: Current EP desc in the bulk list (7.2.6), and + * HcDoneHead: Last transfer desc added to DONE queue (7.2.7): + * + * All 32-bits aligned to an 8-byte boundary + */ + +/* HcFmInterval: Bit time interval that would not cause overrun (7.3.1) */ + +#define OHCI_FMINT_FI_SHIFT (0) /* Bits 0-13: Frame interval */ +#define OHCI_FMINT_FI_MASK (0x3fff << OHCI_FMINT_FI_SHIFT) + /* Bits 14-15: Reserved */ +#define OHCI_FMINT_FSMPS_SHIFT (16) /* Bits 16-30: FS largest packet data */ +#define OHCI_FMINT_FSMPS_MASK (0x7fff << OHCI_FMINT_FSMPS_SHIFT) +#define OHCI_FMINT_FIT (1 << 31) /* Bit 31: Frame interval toggle */ + +/* HcFmRemaining: Bit time remaining in current frame (7.3.2) */ + +#define OHCI_FMREM_FR_SHIFT (0) /* Bits 0-13: Frame remaining */ +#define OHCI_FMREM_FR_MASK (0x3fff << OHCI_FMREM_FR_SHIFT) + /* Bits 16-30: Reserved */ +#define OHCI_FMINT_FRT (1 << 31) /* Bit 31: Frame remaining toggle */ + +/* HcFmNumber: Frame number counter (7.3.3) */ + +#define OHCI_FMNO_FI_SHIFT (0) /* Bits 0-15: Frame number */ +#define OHCI_FMNO_FI_MASK (0xffff << OHCI_FMINT_FI_SHIFT) + /* Bits 16-31: Reserved */ + +/* HcPeriodicStart: Time to start processing periodic list (7.3.4) */ + +#define OHCI_PERSTART_SHIFT (0) /* Bits 0-13: Periodic start */ +#define OHCI_PERSTART_MASK (0x3fff << OHCI_PERSTART_SHIFT) + /* Bits 14-31: Reserved */ + +/* HcLSThreshold: Commit to transfer threshold (7.3.5) */ + +#define OHCI_LSTHRES_SHIFT (0) /* Bits 0-11: LS threshold */ +#define OHCI_LSTHRES_MASK (0x0fff << OHCI_PERSTART_SHIFT) + /* Bits 12-31: Reserved */ + +/* HcRhDescriptorN: Describes root hub (part A) (7.4.1) */ + +#define OHCI_RHDESCA_NDP_SHIFT (0) /* Bits 0-7: Number downstream ports */ +#define OHCI_RHDESCA_NDP_MASK (0xff << OHCI_RHDESCA_NDP_SHIFT) +#define OHCI_RHDESCA_PSM (1 << 8) /* Bit 8: Power switching mode */ +#define OHCI_RHDESCA_NPS (1 << 9) /* Bit 9: No power switching */ +#define OHCI_RHDESCA_DT (1 << 10) /* Bit 10: Device type */ +#define OHCI_RHDESCA_OCPM (1 << 11) /* Bit 11: Over current protection mode */ +#define OHCI_RHDESCA_NOCP (1 << 12) /* Bit 12: No over current protection */ + /* Bits 13-23: Reserved */ +#define OHCI_RHDESCA_POTPGT_SHIFT (24) /* Bits 24-31: Power on to power good time */ +#define OHCI_RHDESCA_POTPGT_MASK (0xff << OHCI_RHDESCA_POTPGT_SHIFT) + +/* HcRhDescriptorB: Describes root hub (part B) (7.4.2) */ + +#define OHCI_RHDESCB_DR_SHIFT (0) /* Bits 0-15: Device removable */ +#define OHCI_RHDESCB_DR_MASK (0xffff << OHCI_RHDESCB_DR_SHIFT) +# define OHCI_RHDESCB_ATTACHED(n) (1 << (OHCI_RHDESCB_DR_SHIFT+(n))) +#define OHCI_RHDESCB_PPCM_SHIFT (16) /* Bits 16-31: Port power control mask */ +#define OHCI_RHDESCB_PPCM_MASK (0xffff << OHCI_RHDESCB_PPCM_SHIFT) +# define OHCI_RHDESCB_POWERED(n) (1 << (OHCI_RHDESCB_DR_SHIFT+(n))) + +/* HcRhStatus: Root hub status (7.4.3) */ + +#define OHCI_RHSTATUS_LPS (1 << 0) /* Bit 0: Local power status (read)*/ +#define OHCI_RHSTATUS_CGP (1 << 0) /* Bit 0: Clear global power (write)*/ +#define OHCI_RHSTATUS_OCI (1 << 1) /* Bit 1: Over current indicator */ + /* Bits 2-14: Reserved */ +#define OHCI_RHSTATUS_DRWE (1 << 15) /* Bit 15: Device remote wakeup enable */ +#define OHCI_RHSTATUS_LPSC (1 << 16) /* Bit 16: Local power status change (read) */ +#define OHCI_RHSTATUS_SGP (1 << 16) /* Bit 16: Set global power (write) */ +#define OHCI_RHSTATUS_OCIC (1 << 17) /* Bit 17: Overcurrent indicator change */ + /* Bits 18-30: Reserved */ +#define OHCI_RHSTATUS_CRWE (1 << 31) /* Bit 31: Clear remote wakeup enable */ + +/* HcRhPortStatus: Root hub port status (7.4.4) */ + +#define OHCI_RHPORTST_CCS (1 << 0) /* Bit 0: Current connect status */ +#define OHCI_RHPORTST_PES (1 << 1) /* Bit 1: Port enable status */ +#define OHCI_RHPORTST_PSS (1 << 2) /* Bit 2: Port suspend status */ +#define OHCI_RHPORTST_POCI (1 << 3) /* Bit 3: Port over current indicator */ +#define OHCI_RHPORTST_PRS (1 << 4) /* Bit 4: Port reset status */ + /* Bits 5-7: Reserved */ +#define OHCI_RHPORTST_PPS (1 << 8) /* Bit 8: Port power status */ +#define OHCI_RHPORTST_LSDA (1 << 9) /* Bit 9: Low speed device attached */ + /* Bits 10-15: Reserved */ +#define OHCI_RHPORTST_CSC (1 << 16) /* Bit 16: Connect status change */ +#define OHCI_RHPORTST_PESC (1 << 17) /* Bit 17: Port enable status change */ +#define OHCI_RHPORTST_PSSC (1 << 18) /* Bit 18: Port suspend status change */ +#define OHCI_RHPORTST_OCIC (1 << 19) /* Bit 19: Port over current indicator change */ +#define OHCI_RHPORTST_PRSC (1 << 20) /* Bit 20: Port reset status change */ + /* Bits 21-31: Reserved */ + +/* Transfer Descriptors *****************************************************/ + +/* Endpoint Descriptor Offsets (4.2.1) */ + +#define ED_CONTROL_OFFSET (0x00) /* ED status/control bits */ +#define ED_TAILP_OFFSET (0x04) /* TD Queue Tail Pointer (TailP) */ +#define ED_HEADP_OFFSET (0x08) /* TD Queue Head Pointer (HeadP) */ +#define ED_NEXTED_OFFSET (0x0c) /* Next Endpoint Descriptor (NextED) */ + +/* Endpoint Descriptor Bit Definitions (4.2.2) */ + +#define ED_CONTROL_FA_SHIFT (0) /* Bits 0-6: Function Address */ +#define ED_CONTROL_FA_MASK (0x7f << ED_CONTROL_FA_SHIFT) +#define ED_CONTROL_EN_SHIFT (7) /* Bits 7-10: Endpoint number */ +#define ED_CONTROL_EN_MASK (15 << ED_CONTROL_EN_SHIFT) +#define ED_CONTROL_D_SHIFT (11) /* Bits 11-12: Direction */ +#define ED_CONTROL_D_MASK (3 << ED_CONTROL_D_SHIFT) +# define ED_CONTROL_D_TD1 (0 << ED_CONTROL_D_SHIFT) /* Get direction from TD */ +# define ED_CONTROL_D_OUT (1 << ED_CONTROL_D_SHIFT) /* OUT */ +# define ED_CONTROL_D_IN (2 << ED_CONTROL_D_SHIFT) /* IN */ +# define ED_CONTROL_D_TD2 (3 << ED_CONTROL_D_SHIFT) /* Get direction from TD */ + +#define ED_CONTROL_S (1 << 13) /* Bit 13: Speed (low) */ +#define ED_CONTROL_K (1 << 14) /* Bit 14: Skip */ +#define ED_CONTROL_F (1 << 15) /* Bit 15: Format (isochronous) */ +#define ED_CONTROL_MPS_SHIFT (16) /* Bits 16-26: Maximum packet size */ +#define ED_CONTROL_MPS_MASK (0x7ff << ED_CONTROL_MPS_SHIFT) + +#define ED_HEADP_ADDR_SHIFT (0) +#define ED_HEADP_ADDR_MASK 0xfffffff0 +#define ED_HEADP_H (1 << 0) /* Bit 0: Halted */ +#define ED_HEADP_C (1 << 1) /* Bit 1: Toggle carry */ + +/* General Transfer Descriptor Offsets (4.3.1) */ + +#define GTD_STATUS_OFFSET (0x00) /* TD status bits */ +#define GTD_CBP_OFFSET (0x04) /* Current Buffer Pointer (CBP) */ +#define GTD_NEXTTD_OFFSET (0x08) /* Next TD (NextTD) */ +#define GTD_BE_OFFSET (0x0c) /* Buffer End (BE) */ + +/* General Transfer Descriptor Bit Definitions */ + + /* Bits 0-17: Reserved */ + +#define GTD_STATUS_R (1 << 18) /* Bit 18: Buffer rounding */ +#define GTD_STATUS_DP_SHIFT (19) /* Bits 19-20: Direction/PID */ +#define GTD_STATUS_DP_MASK (3 << GTD_STATUS_DP_SHIFT) +# define GTD_STATUS_DP_SETUP (0 << GTD_STATUS_DP_SHIFT) /* To endpoint */ +# define GTD_STATUS_DP_OUT (1 << GTD_STATUS_DP_SHIFT) /* To endpoint */ +# define GTD_STATUS_DP_IN (2 << GTD_STATUS_DP_SHIFT) /* From endpoint */ + +#define GTD_STATUS_DI_SHIFT (21) /* Bits 21-23: Delay input */ +#define GTD_STATUS_DI_MASK (7 << GTD_STATUS_DI_SHIFT) +#define GTD_STATUS_T_SHIFT (24) /* Bits 24-25: Data Toggle */ +#define GTD_STATUS_T_MASK (3 << GTD_STATUS_T_SHIFT) +# define GTD_STATUS_T_TOGGLE (0 << GTD_STATUS_T_SHIFT) +# define GTD_STATUS_T_DATA0 (2 << GTD_STATUS_T_SHIFT) +# define GTD_STATUS_T_DATA1 (3 << GTD_STATUS_T_SHIFT) +#define GTD_STATUS_EC_SHIFT (26) /* Bits 26-27: Error count */ +#define GTD_STATUS_EC_MASK (3 << GTD_STATUS_EC_SHIFT) +#define GTD_STATUS_CC_SHIFT (28) /* Bits 28-31: Condition code */ +#define GTD_STATUS_CC_MASK (15 << GTD_STATUS_CC_SHIFT) + +/* Isochronous Transfer Descriptor Offsets (4.3.2) */ + +#define ITD_STATUS_OFFSET (0x00) /* TD status bits */ +#define ITD_BP0_OFFSET (0x04) /* Buffer page 0 (BP0) */ +#define ITD_NEXTTD_OFFSET (0x08) /* Next TD (NextTD) */ +#define ITD_BE_OFFSET (0x0c) /* Buffer End (BE) */ + +#define ITD_NPSW (8) +#define ITD_PSW0_OFFSET (0x10) /* Offset0/PSW0 */ +#define ITD_PSW1_OFFSET (0x12) /* Offset1/PSW1 */ +#define ITD_PSW2_OFFSET (0x14) /* Offset2/PSW2 */ +#define ITD_PSW3_OFFSET (0x16) /* Offset3/PSW3 */ +#define ITD_PSW4_OFFSET (0x18) /* Offset4/PSW4 */ +#define ITD_PSW5_OFFSET (0x1a) /* Offset5/PSW5 */ +#define ITD_PSW6_OFFSET (0x1c) /* Offset6/PSW6 */ +#define ITD_PSW7_OFFSET (0x1e) /* Offset7/PSW7 */ + +/* Condition codes (Table 4-7) */ + +#define TD_CC_NOERROR 0x00 +#define TD_CC_CRC 0x01 +#define TD_CC_BITSTUFFING 0x02 +#define TD_CC_DATATOGGLEMISMATCH 0x03 +#define TD_CC_STALL 0x04 +#define TD_CC_DEVNOTRESPONDING 0x05 +#define TD_CC_PIDCHECKFAILURE 0x06 +#define TD_CC_UNEXPECTEDPID 0x07 +#define TD_CC_DATAOVERRUN 0x08 +#define TD_CC_DATAUNDERRUN 0x09 +#define TD_CC_BUFFEROVERRUN 0x0c +#define TD_CC_BUFFERUNDERRUN 0x0d +#define TD_CC_NOTACCESSED 0x0f + +#define TD_CC_USER 0x10 /* For use by OHCI drivers */ + +/* Host Controller Communications Area Format (4.4.1) ***********************/ + +/* HccaInterruptTable: 32x32-bit pointers to interrupt EDs */ + +#define HCCA_INTTBL_OFFSET (0x00) +#define HCCA_INTTBL_WSIZE (32) +#define HCCA_INTTBL_BSIZE (HCCA_INTTBL_WSIZE * 4) + +/* HccaFrameNumber: Current frame number */ + +#define HCCA_FMNO_OFFSET (0x80) +#define HCCA_FMNO_BSIZE (2) + +/* HccaPad1: Zero when frame no. updated */ + +#define HCCA_PAD1_OFFSET (0x82) +#define HCCA_PAD1_BSIZE (2) + +/* HccaDoneHead: When the HC reaches the end of a frame and its deferred + * interrupt register is 0, it writes the current value of its HcDoneHead to + * this location and generates an interrupt. + * + * The LSB of HCCADoneHead may be set to 1 to indicate that an unmasked + * HcInterruptStatus was set when HccaDoneHead was written. + */ + +#define HCCA_DONEHEAD_OFFSET (0x84) +#define HCCA_DONEHEAD_BSIZE (4) + +#define HCCA_DONEHEAD_MASK 0xfffffffe +#define HCCA_DONEHEAD_INTSTA (1 << 0) + +/* 0x88: 116 bytes reserved */ + +#define HCCA_RESERVED_OFFSET (0x88) +#define HCCA_RESERVED_BSIZE (116) + +/**************************************************************************** + * Public Types + ****************************************************************************/ + +struct ohci_hcor +{ + volatile uint32_t hcrevision; /* 0x00 */ + volatile uint32_t hccontrol; /* 0x04 */ + volatile uint32_t hccmdsts; /* 0x08 */ + volatile uint32_t hcintsts; /* 0x0c */ + volatile uint32_t hcinten; /* 0x10 */ + volatile uint32_t hcintdis; /* 0x14 */ + volatile uint32_t hchcca; /* 0x18 */ + volatile uint32_t hcperiodcurrented; /* 0x1c */ + volatile uint32_t hccontrolheaded; /* 0x20 */ + volatile uint32_t hccontrolcurrented; /* 0x24 */ + volatile uint32_t hcbulkheaded; /* 0x28 */ + volatile uint32_t hcbulkcurrented; /* 0x2c */ + volatile uint32_t hcdonehead; /* 0x30 */ + volatile uint32_t hcfminterval; /* 0x34 */ + volatile uint32_t hcfmremaining; /* 0x38 */ + volatile uint32_t hcfmnumber; /* 0x3c */ + volatile uint32_t hcperiodicstart; /* 0x40 */ + volatile uint32_t hclsthreshold; /* 0x44 */ + volatile uint32_t hcrhdescriptora; /* 0x48 */ + volatile uint32_t hcrhdescriptorb; /* 0x4c */ + volatile uint32_t hcrhsts; /* 0x50 */ + volatile uint32_t hcrhportsts[15]; /* 0x54 */ +}; + +/* Endpoint Descriptor Offsets (4.2.1) */ + +struct ohci_ed_s +{ + volatile uint32_t ctrl; /* ED status/control bits */ + volatile uint32_t tailp; /* TD Queue Tail Pointer (TailP) */ + volatile uint32_t headp; /* TD Queue Head Pointer (HeadP) */ + volatile uint32_t nexted; /* Next Endpoint Descriptor (NextED) */ +}; + +/* General Transfer Descriptor (4.3.1) */ + +struct ohci_gtd_s +{ + volatile uint32_t ctrl; /* TD status/control bits */ + volatile uint32_t cbp; /* Current Buffer Pointer (CBP) */ + volatile uint32_t nexttd; /* Next TD (NextTD) */ + volatile uint32_t be; /* Buffer End (BE) */ +}; + +/* Isochronous Transfer Descriptor Offsets (4.3.2) */ + +struct ohci_itd_s +{ + volatile uint32_t ctrl; /* TD status/control bits */ + volatile uint32_t bp0; /* Buffer page 0 (BP0 */ + volatile uint32_t nexttd; /* Next TD (NextTD) */ + volatile uint32_t be; /* Buffer End (BE) */ + volatile uint16_t psw[ITD_NPSW]; /* Offset/PSW */ +}; + +/* Host Controller Communications Area Format (4.4.1) */ + +struct ohci_hcca_s +{ + /* HccaInterruptTable: 32x32-bit pointers to interrupt EDs */ + + volatile uint32_t inttbl[HCCA_INTTBL_WSIZE]; + + /* HccaFrameNumber: Current frame number and + * HccaPad1: Zero when frame no. updated + */ + + volatile uint16_t fmno; + volatile uint16_t pad1; + + /* HccaDoneHead: When the HC reaches the end of a frame and its deferred + * interrupt register is 0, it writes the current value of its HcDoneHead + * to this location and generates an interrupt. + */ + + volatile uint32_t donehead; + volatile uint8_t reserved[HCCA_RESERVED_BSIZE]; + volatile uint32_t extra; +} __attribute__((aligned(256))); + +/**************************************************************************** + * Public Data + ****************************************************************************/ + +#ifdef __cplusplus +#define EXTERN extern "C" +extern "C" +{ +#else +#define EXTERN extern +#endif + +/**************************************************************************** + * Public Function Prototypes + ****************************************************************************/ + +#undef EXTERN +#ifdef __cplusplus +} +#endif + +#endif /* __INCLUDE_NUTTX_USB_OHCI_H */ diff --git a/port/ohci/usb_ohci_priv.h b/port/ohci/usb_ohci_priv.h new file mode 100644 index 00000000..4404dc25 --- /dev/null +++ b/port/ohci/usb_ohci_priv.h @@ -0,0 +1,24 @@ +/* + * Copyright (c) 2024, sakumisu + * + * SPDX-License-Identifier: Apache-2.0 + */ +#ifndef _USB_OHCI_PRIV_H +#define _USB_OHCI_PRIV_H + +#include "usbh_core.h" +#include "usbh_hub.h" +#include "usb_hc_ohci.h" + +#define OHCI_HCOR ((struct ohci_hcor *)(uintptr_t)(bus->hcd.reg_base + CONFIG_USB_OHCI_HCOR_OFFSET)) + +int ohci_init(struct usbh_bus *bus); +int ohci_deinit(struct usbh_bus *bus); +uint16_t ohci_get_frame_number(struct usbh_bus *bus); +int ohci_roothub_control(struct usbh_bus *bus, struct usb_setup_packet *setup, uint8_t *buf); +int ohci_submit_urb(struct usbh_urb *urb); +int ohci_kill_urb(struct usbh_urb *urb); + +void OHCI_IRQHandler(uint8_t busid); + +#endif \ No newline at end of file