diff --git a/port/ehci/usb_glue_aic.c b/port/ehci/usb_glue_aic.c index d9ed53ff..500bc02a 100644 --- a/port/ehci/usb_glue_aic.c +++ b/port/ehci/usb_glue_aic.c @@ -9,11 +9,16 @@ #include #include "usbh_core.h" #include "usb_hc_ehci.h" +#include "usb_hc_ohci.h" #if !defined(CONFIG_USB_EHCI_CONFIGFLAG) #error "aic ehci must define CONFIG_USB_EHCI_CONFIGFLAG" #endif +#if !defined(CONFIG_USB_EHCI_WITH_OHCI) +#error "aic must define CONFIG_USB_EHCI_WITH_OHCI for ls/fs device" +#endif + #if CONFIG_USB_OHCI_HCOR_OFFSET != 0x400 #error "aic CONFIG_USB_OHCI_HCOR_OFFSET must be 0x400" #endif @@ -130,17 +135,7 @@ void usb_hc_low_level_init(struct usbh_bus *bus) uint8_t usbh_get_port_speed(struct usbh_bus *bus, const uint8_t port) { - /* Defined by individual manufacturers */ - uint32_t regval; - - regval = EHCI_HCOR->portsc[port-1]; - if ((regval & EHCI_PORTSC_LSTATUS_MASK) == EHCI_PORTSC_LSTATUS_KSTATE) - return USB_SPEED_LOW; - - if (regval & EHCI_PORTSC_PE) - return USB_SPEED_HIGH; - else - return USB_SPEED_FULL; + return USB_SPEED_HIGH; } void usb_ehci_dcache_clean(uintptr_t addr, uint32_t len) diff --git a/port/ehci/usb_hc_ehci.c b/port/ehci/usb_hc_ehci.c index 8b9caba4..a4be60dd 100644 --- a/port/ehci/usb_hc_ehci.c +++ b/port/ehci/usb_hc_ehci.c @@ -1063,7 +1063,6 @@ int usbh_roothub_control(struct usbh_bus *bus, struct usb_setup_packet *setup, u while (!(EHCI_HCOR->portsc[port - 1] & EHCI_PORTSC_OWNER)) { } - return ohci_roothub_control(bus, setup, buf); } #endif break; diff --git a/port/ohci/README.md b/port/ohci/README.md index 34e753c3..928eb0c3 100644 --- a/port/ohci/README.md +++ b/port/ohci/README.md @@ -1,18 +1,23 @@ # Note -This OHCI is a companion controller of EHCI. +This OHCI is a companion controller of EHCI. But you can use OHCI only without CONFIG_USB_EHCI_WITH_OHCI definition. + +**And you need to pay for using OHCI driver**. ## Support Chip List ### AllwinnerTech -- F133 +- F133(EHCI + OHCI) ### Nuvoton -- Nuvoton all series +- Nuvoton all series(EHCI + OHCI, OHCI only) ### Artinchip -- d13x, d21x +- d13x, d21x(EHCI + OHCI) + +### NXP +- LPC4X/LPC5X(OHCI only) \ No newline at end of file diff --git a/port/ohci/usb_glue_lpc.c b/port/ohci/usb_glue_lpc.c new file mode 100644 index 00000000..79547180 --- /dev/null +++ b/port/ohci/usb_glue_lpc.c @@ -0,0 +1,40 @@ +#include "fsl_device_registers.h" +#include "fsl_power.h" +#include "usbh_core.h" + +#if defined(CONFIG_USB_EHCI_WITH_OHCI) +#error "lpc does not have ehci" +#endif + +void usb_hc_low_level_init(struct usbh_bus *bus) +{ +#if ((defined FSL_FEATURE_SOC_SYSMPU_COUNT) && (FSL_FEATURE_SOC_SYSMPU_COUNT)) + SYSMPU_Enable(SYSMPU, 0); +#endif /* FSL_FEATURE_SOC_SYSMPU_COUNT */ + + NVIC_ClearPendingIRQ(USB0_IRQn); + NVIC_ClearPendingIRQ(USB0_NEEDCLK_IRQn); + + POWER_DisablePD(kPDRUNCFG_PD_USB0_PHY); /*< Turn on USB0 Phy */ + + RESET_PeripheralReset(kUSB0D_RST_SHIFT_RSTn); + RESET_PeripheralReset(kUSB0HSL_RST_SHIFT_RSTn); + RESET_PeripheralReset(kUSB0HMR_RST_SHIFT_RSTn); + + CLOCK_EnableUsbfs0HostClock(kCLOCK_UsbfsSrcPll1, 48000000U); + + NVIC_SetPriority(USB0_IRQn, 3); + EnableIRQ(USB0_IRQn); +} + + +void usb_hc_low_level_deinit(struct usbh_bus *bus) +{ + DisableIRQ(USB0_IRQn); +} + +void USB0_IRQHandler(void) +{ + extern void USBH_IRQHandler(uint8_t busid); + USBH_IRQHandler(0); +} \ No newline at end of file diff --git a/port/ohci/usb_hc_ohci.c b/port/ohci/usb_hc_ohci.c index fda18090..2bec2a03 100644 --- a/port/ohci/usb_hc_ohci.c +++ b/port/ohci/usb_hc_ohci.c @@ -4,18 +4,58 @@ * SPDX-License-Identifier: Apache-2.0 */ #include "usb_hc_ohci.h" -#include "usb_hc_ehci.h" + +/* Frame Interval / Periodic Start. + * + * At 12Mbps, there are 12000 bit time in each 1Msec frame. + */ + +#define OHCI_FMINTERVAL_FI (12000 - 1) +#define OHCI_FMINTERVAL_FSMPS ((6 * (OHCI_FMINTERVAL_FI - 210)) / 7) +#define DEFAULT_FMINTERVAL ((OHCI_FMINTERVAL_FSMPS << OHCI_FMINT_FSMPS_SHIFT) | OHCI_FMINTERVAL_FI) +#define DEFAULT_PERSTART ((OHCI_FMINTERVAL_FI * 9) / 10) + +struct ohci_hcd g_ohci_hcd[CONFIG_USBHOST_MAX_BUS]; + +USB_NOCACHE_RAM_SECTION struct ohci_ed_hw g_ohci_ed_pool[CONFIG_USBHOST_MAX_BUS][CONFIG_USB_OHCI_ED_NUM]; +USB_NOCACHE_RAM_SECTION struct ohci_hcca ohci_hcca[CONFIG_USBHOST_MAX_BUS]; int ohci_init(struct usbh_bus *bus) { volatile uint32_t timeout = 0; uint32_t regval; + struct ohci_ed_hw *ed; + + memset(&g_ohci_hcd[bus->hcd.hcd_id], 0, sizeof(struct ohci_hcd)); + memset(g_ohci_ed_pool[bus->hcd.hcd_id], 0, sizeof(struct ohci_ed_hw) * CONFIG_USB_OHCI_ED_NUM); + + for (uint32_t i = 0; i < 32; i++) { + ohci_hcca[bus->hcd.hcd_id].inttbl[i] = 0; + } + + for (uint8_t index = 0; index < CONFIG_USB_OHCI_ED_NUM; index++) { + ed = &g_ohci_ed_pool[bus->hcd.hcd_id][index]; + if ((uint32_t)&ed->hw % 32) { + USB_LOG_ERR("struct ohci_ed_hw is not align 32\r\n"); + return -USB_ERR_INVAL; + } + for (uint8_t i = 0; i < CONFIG_USB_OHCI_TD_NUM; i++) { + if ((uint32_t)&ed->td_pool[i] % 32) { + USB_LOG_ERR("struct ohci_td_hw is not align 32\r\n"); + return -USB_ERR_INVAL; + } + } + } + + for (uint8_t index = 0; index < CONFIG_USB_OHCI_ED_NUM; index++) { + ed = &g_ohci_ed_pool[bus->hcd.hcd_id][index]; + ed->waitsem = usb_osal_sem_create(0); + } USB_LOG_INFO("OHCI hcrevision:0x%02x\r\n", (unsigned int)OHCI_HCOR->hcrevision); + OHCI_HCOR->hcintdis = OHCI_INT_MIE; 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) { @@ -26,45 +66,39 @@ int ohci_init(struct usbh_bus *bus) } } - /* 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; + OHCI_HCOR->hclsthreshold = 0x628; + + OHCI_HCOR->hccontrolheaded = 0; + OHCI_HCOR->hcbulkheaded = 0; + OHCI_HCOR->hchcca = (uintptr_t)&ohci_hcca[bus->hcd.hcd_id]; + + /* Clear pending interrupts */ + regval = OHCI_HCOR->hcintsts; + OHCI_HCOR->hcintsts = regval; /* Put HC in operational state */ regval = OHCI_HCOR->hccontrol; + regval &= ~OHCI_CTRL_CBSR; regval &= ~OHCI_CTRL_HCFS_MASK; regval |= OHCI_CTRL_HCFS_OPER; + regval |= OHCI_CTRL_CBSR; + regval |= OHCI_CTRL_CLE; OHCI_HCOR->hccontrol = regval; - /* Set global power in HcRhStatus */ - OHCI_HCOR->hcrhsts = OHCI_RHSTATUS_SGP; + g_ohci_hcd[bus->hcd.hcd_id].n_ports = OHCI_HCOR->hcrhdescriptora & OHCI_RHDESCA_NDP_MASK; + USB_LOG_INFO("OHCI n_ports:%d\r\n", g_ohci_hcd[bus->hcd.hcd_id].n_ports); - /* Set HCCA base address */ - OHCI_HCOR->hchcca = 0; + OHCI_HCOR->hcrhdescriptora &= ~OHCI_RHDESCA_PSM; + OHCI_HCOR->hcrhdescriptora &= ~OHCI_RHDESCA_NPS; - /* 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; - } + /* Set global power in HcRhStatus */ + OHCI_HCOR->hcrhsts = OHCI_RHSTATUS_SGP; + usb_osal_msleep(20); /* 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; + OHCI_HCOR->hcinten = OHCI_INT_WDH | OHCI_INT_RHSC | OHCI_INT_MIE; return 0; } @@ -72,15 +106,25 @@ int ohci_init(struct usbh_bus *bus) int ohci_deinit(struct usbh_bus *bus) { uint32_t regval; + struct ohci_ed_hw *ed; /* 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; + OHCI_HCOR->hcintdis = OHCI_INT_WDH | OHCI_INT_RHSC | OHCI_INT_MIE; + + /* Clear pending interrupts */ + regval = OHCI_HCOR->hcintsts; + OHCI_HCOR->hcintsts = regval; + + OHCI_HCOR->hcrhsts &= ~OHCI_RHSTATUS_SGP; + + regval = OHCI_HCOR->hccontrol; + regval &= ~OHCI_CTRL_HCFS_MASK; + regval |= OHCI_CTRL_HCFS_SUSPEND; + OHCI_HCOR->hccontrol = 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; + for (uint8_t index = 0; index < CONFIG_USB_OHCI_ED_NUM; index++) { + ed = &g_ohci_ed_pool[bus->hcd.hcd_id][index]; + usb_osal_sem_delete(ed->waitsem); } return 0; @@ -97,7 +141,7 @@ int ohci_roothub_control(struct usbh_bus *bus, struct usb_setup_packet *setup, u uint8_t port; uint32_t temp; - nports = g_ehci_hcd[bus->hcd.hcd_id].n_pcc; + nports = g_ohci_hcd[bus->hcd.hcd_id].n_ports; port = setup->wIndex; if (setup->bmRequestType & USB_REQUEST_RECIPIENT_DEVICE) { @@ -139,28 +183,46 @@ int ohci_roothub_control(struct usbh_bus *bus, struct usb_setup_packet *setup, u switch (setup->wValue) { case HUB_PORT_FEATURE_ENABLE: + temp = OHCI_RHPORTST_CCS; break; case HUB_PORT_FEATURE_SUSPEND: + temp = OHCI_HCOR->hccontrol; + temp &= ~OHCI_CTRL_HCFS_MASK; + temp |= OHCI_CTRL_HCFS_RESUME; + OHCI_HCOR->hccontrol = temp; + + usb_osal_msleep(20); + temp = OHCI_HCOR->hccontrol; + temp &= ~OHCI_CTRL_HCFS_MASK; + temp |= OHCI_CTRL_HCFS_OPER; + OHCI_HCOR->hccontrol = temp; + + temp = OHCI_RHPORTST_POCI; + break; case HUB_PORT_FEATURE_C_SUSPEND: + temp = OHCI_RHPORTST_PSSC; break; case HUB_PORT_FEATURE_POWER: + OHCI_HCOR->hcrhsts = OHCI_RHSTATUS_CGP; + temp = OHCI_RHPORTST_LSDA; break; case HUB_PORT_FEATURE_C_CONNECTION: - OHCI_HCOR->hcrhportsts[port - 1] |= OHCI_RHPORTST_CSC; + temp = OHCI_RHPORTST_CSC; break; case HUB_PORT_FEATURE_C_ENABLE: - OHCI_HCOR->hcrhportsts[port - 1] |= OHCI_RHPORTST_PESC; + temp = OHCI_RHPORTST_PESC; break; case HUB_PORT_FEATURE_C_OVER_CURREN: - OHCI_HCOR->hcrhportsts[port - 1] |= OHCI_RHPORTST_OCIC; + temp = OHCI_RHPORTST_OCIC; break; case HUB_PORT_FEATURE_C_RESET: - OHCI_HCOR->hcrhportsts[port - 1] |= OHCI_RHPORTST_PRSC; + temp = OHCI_RHPORTST_PRSC; break; default: return -USB_ERR_NOTSUPP; } + OHCI_HCOR->hcrhportsts[port - 1] = temp; break; case HUB_REQUEST_SET_FEATURE: if (!port || port > nports) { @@ -169,11 +231,17 @@ int ohci_roothub_control(struct usbh_bus *bus, struct usb_setup_packet *setup, u switch (setup->wValue) { case HUB_PORT_FEATURE_SUSPEND: + temp = OHCI_HCOR->hccontrol; + temp &= ~OHCI_CTRL_HCFS_MASK; + temp |= OHCI_CTRL_HCFS_SUSPEND; + OHCI_HCOR->hccontrol = temp; + break; case HUB_PORT_FEATURE_POWER: + OHCI_HCOR->hcrhsts = OHCI_RHSTATUS_SGP; break; case HUB_PORT_FEATURE_RESET: - OHCI_HCOR->hcrhportsts[port - 1] |= OHCI_RHPORTST_PRS; + OHCI_HCOR->hcrhportsts[port - 1] = OHCI_RHPORTST_PRS; while (OHCI_HCOR->hcrhportsts[port - 1] & OHCI_RHPORTST_PRS) { } @@ -188,7 +256,6 @@ int ohci_roothub_control(struct usbh_bus *bus, struct usb_setup_packet *setup, u return -USB_ERR_INVAL; } temp = OHCI_HCOR->hcrhportsts[port - 1]; - memcpy(buf, &temp, 4); break; default: @@ -216,9 +283,9 @@ void OHCI_IRQHandler(uint8_t busid) bus = &g_usbhost_bus[busid]; usbsts = OHCI_HCOR->hcintsts & OHCI_HCOR->hcinten; - OHCI_HCOR->hcintsts = usbsts; if (usbsts & OHCI_INT_RHSC) { + OHCI_HCOR->hcintsts = OHCI_INT_RHSC; for (int port = 0; port < CONFIG_USBHOST_MAX_RHPORTS; port++) { uint32_t portsc = OHCI_HCOR->hcrhportsts[port]; @@ -236,5 +303,51 @@ void OHCI_IRQHandler(uint8_t busid) } } if (usbsts & OHCI_INT_WDH) { + OHCI_HCOR->hcintsts = OHCI_INT_WDH; } -} \ No newline at end of file +} + +#ifndef CONFIG_USB_EHCI_WITH_OHCI +__WEAK void usb_hc_low_level_init(struct usbh_bus *bus) +{ + (void)bus; +} + +__WEAK void usb_hc_low_level_deinit(struct usbh_bus *bus) +{ + (void)bus; +} + +int usb_hc_init(struct usbh_bus *bus) +{ + usb_hc_low_level_init(bus); + return ohci_init(bus); +} + +int usb_hc_deinit(struct usbh_bus *bus) +{ + ohci_deinit(bus); + usb_hc_low_level_deinit(bus); + return 0; +} + +int usbh_roothub_control(struct usbh_bus *bus, struct usb_setup_packet *setup, uint8_t *buf) +{ + return ohci_roothub_control(bus, setup, buf); +} + +int usbh_submit_urb(struct usbh_urb *urb) +{ + return ohci_submit_urb(urb); +} + +int usbh_kill_urb(struct usbh_urb *urb) +{ + return ohci_kill_urb(urb); +} + +void USBH_IRQHandler(uint8_t busid) +{ + OHCI_IRQHandler(busid); +} +#endif \ No newline at end of file diff --git a/port/ohci/usb_hc_ohci.h b/port/ohci/usb_hc_ohci.h index 68815d9d..19d51909 100644 --- a/port/ohci/usb_hc_ohci.h +++ b/port/ohci/usb_hc_ohci.h @@ -12,6 +12,38 @@ #define OHCI_HCOR ((struct ohci_hcor *)(uintptr_t)(bus->hcd.reg_base + CONFIG_USB_OHCI_HCOR_OFFSET)) +#define OHCI_PTR2ADDR(x) ((uint32_t)(uintptr_t)(x) & ~0x0F) +#define OHCI_ADDR2ED(x) ((struct ohci_ed_hw *)(uintptr_t)((uint32_t)(x) & ~0x0F)) +#define OHCI_ADDR2TD(x) ((struct ohci_td_hw *)(uintptr_t)((uint32_t)(x) & ~0x0F)) + +#ifndef CONFIG_USB_OHCI_ED_NUM +#define CONFIG_USB_OHCI_ED_NUM CONFIG_USBHOST_PIPE_NUM +#endif +#ifndef CONFIG_USB_OHCI_TD_NUM +#define CONFIG_USB_OHCI_TD_NUM 3 +#endif + +struct ohci_ed_hw; +struct ohci_td_hw { + struct ohci_gtd hw; + struct usbh_urb *urb; + uint32_t buf_start; + uint32_t length; +} __attribute__((aligned(32))); /* min is 16bytes, we use 32 for cacheline */ + +struct ohci_ed_hw { + struct ohci_ed hw; + struct ohci_td_hw td_pool[CONFIG_USB_OHCI_TD_NUM]; + uint32_t td_count; + uint8_t ed_type; + usb_osal_sem_t waitsem; +} __attribute__((aligned(32))); /* min is 16bytes, we use 32 for cacheline */ + +struct ohci_hcd { + bool ohci_ed_used[CONFIG_USB_OHCI_ED_NUM]; + uint8_t n_ports; +}; + int ohci_init(struct usbh_bus *bus); int ohci_deinit(struct usbh_bus *bus); uint16_t ohci_get_frame_number(struct usbh_bus *bus); diff --git a/port/ohci/usb_ohci_reg.h b/port/ohci/usb_ohci_reg.h index 030350e5..61f7f4bf 100644 --- a/port/ohci/usb_ohci_reg.h +++ b/port/ohci/usb_ohci_reg.h @@ -95,10 +95,10 @@ /* 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_PLE (1 << 2) /* Bit 2: Periodic list enable */ +#define OHCI_CTRL_IE (1 << 3) /* Bit 3: Isochronous enable */ +#define OHCI_CTRL_CLE (1 << 4) /* Bit 4: Control list enable */ +#define OHCI_CTRL_BLE (1 << 5) /* Bit 5: 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) @@ -261,9 +261,9 @@ # 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_SPPED_LOW (1 << 13) /* Bit 13: Speed (low) */ +#define ED_CONTROL_SKIP (1 << 14) /* Bit 14: Skip */ +#define ED_CONTROL_FORMAT_ISO (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) @@ -406,7 +406,7 @@ struct ohci_hcor /* Endpoint Descriptor Offsets (4.2.1) */ -struct ohci_ed_s +struct ohci_ed { volatile uint32_t ctrl; /* ED status/control bits */ volatile uint32_t tailp; /* TD Queue Tail Pointer (TailP) */ @@ -416,7 +416,7 @@ struct ohci_ed_s /* General Transfer Descriptor (4.3.1) */ -struct ohci_gtd_s +struct ohci_gtd { volatile uint32_t ctrl; /* TD status/control bits */ volatile uint32_t cbp; /* Current Buffer Pointer (CBP) */ @@ -426,7 +426,7 @@ struct ohci_gtd_s /* Isochronous Transfer Descriptor Offsets (4.3.2) */ -struct ohci_itd_s +struct ohci_itd { volatile uint32_t ctrl; /* TD status/control bits */ volatile uint32_t bp0; /* Buffer page 0 (BP0 */ @@ -437,7 +437,7 @@ struct ohci_itd_s /* Host Controller Communications Area Format (4.4.1) */ -struct ohci_hcca_s +struct ohci_hcca { /* HccaInterruptTable: 32x32-bit pointers to interrupt EDs */