diff --git a/port/ehci/README.md b/port/ehci/README.md index 8160c65d..ede4cab8 100644 --- a/port/ehci/README.md +++ b/port/ehci/README.md @@ -12,7 +12,7 @@ ### AllwinnerTech -- F133 +- F133/T113 ### Nuvoton diff --git a/port/ehci/usb_glue_t113.c b/port/ehci/usb_glue_t113.c new file mode 100644 index 00000000..99927acb --- /dev/null +++ b/port/ehci/usb_glue_t113.c @@ -0,0 +1,219 @@ +/* + * Copyright (c) 2025, YC113 + * + * SPDX-License-Identifier: Apache-2.0 + */ +#include "usbh_core.h" +#include "usb_hc_ehci.h" +#include "usb_hc_ohci.h" + +#include "interrupt.h" +#include "drv_reg_base.h" +#include "drv_clock.h" + +#if !defined(CONFIG_USB_EHCI_WITH_OHCI) +#error "t113 must define CONFIG_USB_EHCI_WITH_OHCI for ls/fs device" +#endif + +#if CONFIG_USBHOST_MAX_BUS != 2 +#error "t113 has 2 usb host controller" +#endif + +#if CONFIG_USB_OHCI_HCOR_OFFSET != 0x400 +#error "t113 CONFIG_USB_OHCI_HCOR_OFFSET must be 0x400" +#endif + +#if defined(CONFIG_USB_EHCI_HCOR_RESERVED_DISABLE) +#error "t113 usb ehci register need reserved" +#endif + +#if !defined(CONFIG_USB_EHCI_CONFIGFLAG) +#error "t113 usb ehci has configflag register" +#endif + +#if defined(CONFIG_USB_EHCI_ISO) +#error "t113 usb ehci no iso register" +#endif + +void usb_select_phyTohci(void) +{ + *(volatile rt_uint32_t *)(USB0_OTG_BASE_ADDR + 0x420) &= ~(1 << 0); +} + +void usb_gate_open(rt_uint8_t busid) +{ + rt_uint32_t addr; + + /* otg bus reset and gate open */ + if (busid == 0) + usb_select_phyTohci(); + + /* reset phy */ + addr = (rt_uint32_t)&CCU->usb0_clk + busid * 4; + *(volatile rt_uint32_t *)addr &= ~(1 << 30); + sdelay(10); + *(volatile rt_uint32_t *)addr |= 1 << 30; + sdelay(10); + + /* ehci bus reset */ + CCU->usb_bgr &= ~((1 << 20) << busid); + sdelay(10); + CCU->usb_bgr |= (1 << 20) << busid; + sdelay(10); + + /* ehci gate open */ + CCU->usb_bgr |= (1 << 4) << busid; + + /* ohci bus reset */ + CCU->usb_bgr &= ~((1 << 16) << busid); + sdelay(10); + CCU->usb_bgr |= (1 << 16) << busid; + sdelay(10); + + /* ohci gate open */ + CCU->usb_bgr |= 1 << busid; + + sdelay(10); + + /* clock enable */ + *(volatile rt_uint32_t *)addr &= ~(3 << 24); + *(volatile rt_uint32_t *)addr |= (1 << 31) | (1 << 24); + + USB_LOG_DBG("usb%d gate : %X, clock : %X\n", busid, CCU->usb_bgr, *(volatile rt_uint32_t *)addr); +} + +void usb_clean_siddp(struct usbh_bus *bus) +{ + *(volatile rt_uint32_t *)(bus->hcd.reg_base + 0x810) &= ~(1 << 3); +} + +static void usb_new_phyx_tp_write(struct usbh_bus *bus, int addr, int data, int len) +{ + rt_uint32_t base = bus->hcd.reg_base; + + for (int i = 0; i < len; i++) { + *(volatile rt_uint8_t *)(base + 0x810) |= 1 << 1; + + *(volatile rt_uint8_t *)(base + 0x810 + 1) = addr + i; + + *(volatile rt_uint8_t *)(base + 0x810) &= ~(1 << 0); + + *(volatile rt_uint8_t *)(base + 0x810) &= ~(1 << 7); + *(volatile rt_uint8_t *)(base + 0x810) |= (data & 0x1) << 7; + + *(volatile rt_uint8_t *)(base + 0x810) |= 1 << 0; + + *(volatile rt_uint8_t *)(base + 0x810) &= ~(1 << 0); + + *(volatile rt_uint8_t *)(base + 0x810) &= ~(1 << 1); + + data >>= 1; + } +} + +void usb_new_phy_init(struct usbh_bus *bus) +{ + rt_int32_t value = 0; + rt_uint32_t efuse_val = 0x1E5080F; + + usb_new_phyx_tp_write(bus, 0x1C, 0x0, 0x03); + + /* vref mode */ + usb_new_phyx_tp_write(bus, 0x60, 0x0, 0x01); + + value = (efuse_val & 0x3C0000) >> 18; + usb_new_phyx_tp_write(bus, 0x44, value, 0x04); + + value = (efuse_val & 0x1C00000) >> 22; + usb_new_phyx_tp_write(bus, 0x36, value, 0x03); +} + +void usb_hci_set_passby(struct usbh_bus *bus) +{ + /* AHB Master interface INCR16 enable */ + /* AHB Master interface INCR8 enable */ + /* AHB Master interface burst type INCR4 enable */ + /* AHB Master interface INCRX align enable */ + /* ULPI bypass enable */ + *(volatile rt_uint32_t *)(bus->hcd.reg_base + 0x800) |= (1 << 11) | (1 << 10) | (1 << 9) | (1 << 8) | (1 << 0); +} + +void t113_ehci_isr(int vector, void *arg) +{ + struct usbh_bus *bus = (struct usbh_bus *)arg; + + USB_LOG_DBG("t113_ehci_isr"); + + extern void USBH_IRQHandler(uint8_t busid); + USBH_IRQHandler(bus->hcd.hcd_id); +} + +void t113_ohci_isr(int vector, void *arg) +{ + struct usbh_bus *bus = (struct usbh_bus *)arg; + + USB_LOG_DBG("t113_ohci_isr"); + + extern void OHCI_IRQHandler(uint8_t busid); + OHCI_IRQHandler(bus->hcd.hcd_id); +} + +void usb_hc_low_level_init(struct usbh_bus *bus) +{ + int vector; + RT_ASSERT(bus->busid <= 1); + + usb_gate_open(bus->busid); + usb_clean_siddp(bus); + usb_hci_set_passby(bus); + + /* register EHCI interrupt callback */ + vector = T113_IRQ_USB0_EHCI + (bus->busid > 0 ? 3 : 0); + rt_hw_interrupt_install(vector, t113_ehci_isr, bus, RT_NULL); + rt_hw_interrupt_umask(vector); + + /* register OHCI interrupt callback */ + rt_hw_interrupt_install(vector + 1, t113_ohci_isr, bus, RT_NULL); + rt_hw_interrupt_umask(vector + 1); + + USB_LOG_DBG("usb%d vector : %d, phy : %X\n", bus->busid, vector, *(volatile rt_uint32_t *)(bus->hcd.reg_base + 0x810)); + USB_LOG_DBG("usb%d hc low level init success\n", bus->busid); +} + +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; +} + +int __usbh_init(void) +{ +#ifdef T113_USING_USB0_HOST + /* USB0 MSC test OK */ + usbh_initialize(0, USB0_BASE_ADDR); +#endif + +#ifdef T113_USING_USB1_HOST + /* USB1 MSC test OK */ + usbh_initialize(1, USB1_BASE_ADDR); +#endif + return 0; +} + +#ifdef PKG_CHERRYUSB_HOST + +#include +#include + +INIT_ENV_EXPORT(__usbh_init); + +#endif