1 /*
2 * Copyright (c) 2022, Artinchip Technology Co., Ltd
3 *
4 * SPDX-License-Identifier: Apache-2.0
5 */
6
7 #include <aic_core.h>
8 #include <aic_hal.h>
9 #include <hal_syscfg.h>
10 #include "usbh_core.h"
11 #include "usb_hc_ehci.h"
12 #include "usb_hc_ohci.h"
13
14 #if !defined(CONFIG_USB_EHCI_CONFIGFLAG)
15 #error "aic ehci must define CONFIG_USB_EHCI_CONFIGFLAG"
16 #endif
17
18 #if !defined(CONFIG_USB_EHCI_WITH_OHCI)
19 #error "aic must define CONFIG_USB_EHCI_WITH_OHCI for ls/fs device"
20 #endif
21
22 #if CONFIG_USB_OHCI_HCOR_OFFSET != 0x400
23 #error "aic CONFIG_USB_OHCI_HCOR_OFFSET must be 0x400"
24 #endif
25
26 extern void USBH_IRQHandler(uint8_t busid);
27
aic_ehci_isr(int vector,void * arg)28 static void aic_ehci_isr(int vector, void *arg)
29 {
30 struct usbh_bus *bus = (struct usbh_bus *)arg;
31 extern void USBH_IRQHandler(uint8_t busid);
32 USBH_IRQHandler(bus->hcd.hcd_id);
33 }
34
aic_ohci_isr(int vector,void * arg)35 static void aic_ohci_isr(int vector, void *arg)
36 {
37 struct usbh_bus *bus = (struct usbh_bus *)arg;
38 extern void OHCI_IRQHandler(uint8_t busid);
39 OHCI_IRQHandler(bus->hcd.hcd_id);
40 }
41
42 typedef struct aic_ehci_config {
43 uint32_t base_addr;
44 uint32_t clk_id;
45 uint32_t rst_id;
46 uint32_t phy_clk_id;
47 uint32_t phy_rst_id;
48 uint32_t irq_num;
49 }aic_ehci_config_t;
50
51 aic_ehci_config_t config[] = {
52 #ifdef AIC_USING_USB0_HOST
53 {
54 USB_HOST0_BASE,
55 CLK_USBH0,
56 RESET_USBH0,
57 CLK_USB_PHY0,
58 RESET_USBPHY0,
59 USB_HOST0_EHCI_IRQn
60 },
61 #else
62 {
63 0xFFFFFFFF,
64 0xFFFFFFFF,
65 0xFFFFFFFF,
66 0xFFFFFFFF,
67 0xFFFFFFFF,
68 0xFFFFFFFF
69 },
70 #endif
71 #ifdef AIC_USING_USB1_HOST
72 {
73 USB_HOST1_BASE,
74 CLK_USBH1,
75 RESET_USBH1,
76 CLK_USB_PHY1,
77 RESET_USBPHY1,
78 USB_HOST1_EHCI_IRQn
79 }
80 #endif
81 };
82
usb_hc_low_level_init(struct usbh_bus * bus)83 void usb_hc_low_level_init(struct usbh_bus *bus)
84 {
85 uint32_t val;
86 int i = 0;
87
88 for (i=0; i<sizeof(config)/sizeof(aic_ehci_config_t); i++) {
89 if (bus->hcd.reg_base == config[i].base_addr)
90 break;
91 }
92
93 if (i == sizeof(config)/sizeof(aic_ehci_config_t))
94 return;
95
96 /* set usb0 phy switch: Host/Device */
97 if (i == 0)
98 syscfg_usb_phy0_sw_host(1);
99
100 /* enable clock */
101 hal_clk_enable(config[i].phy_clk_id);
102 hal_clk_enable(config[i].clk_id);
103 aicos_udelay(300);
104 hal_reset_assert(config[i].phy_rst_id);
105 hal_reset_assert(config[i].rst_id);
106 aicos_udelay(300);
107 hal_reset_deassert(config[i].phy_rst_id);
108 hal_reset_deassert(config[i].rst_id);
109 aicos_udelay(300);
110
111 /* set phy type: UTMI/ULPI */
112 val = readl((volatile void *)(unsigned long)(config[i].base_addr+0x800));
113 #ifdef FPGA_BOARD_ARTINCHIP
114 /* fpga phy type = ULPI */
115 writel((val & ~0x1U), (volatile void *)(unsigned long)(config[i].base_addr+0x800));
116 #else
117 /* board phy type = UTMI */
118 writel((val | 0x1), (volatile void *)(unsigned long)(config[i].base_addr+0x800));
119 #endif
120
121 /* Set AHB2STBUS_INSREG01
122 Set EHCI packet buffer IN/OUT threshold (in DWORDs)
123 Must increase the OUT threshold to avoid underrun. (FIFO size - 4)
124 */
125 writel((32 | (127 << 16)), (volatile void *)(unsigned long)(config[i].base_addr+0x94));
126
127 /* register interrupt callback */
128 aicos_request_irq(config[i].irq_num, (irq_handler_t)aic_ehci_isr,
129 0, "usb_host_ehci", bus);
130 aicos_request_irq(config[i].irq_num + 1, (irq_handler_t)aic_ohci_isr,
131 0, "usb_host_ohci", bus);
132 aicos_irq_enable(config[i].irq_num);
133 aicos_irq_enable(config[i].irq_num + 1);
134 }
135
usbh_get_port_speed(struct usbh_bus * bus,const uint8_t port)136 uint8_t usbh_get_port_speed(struct usbh_bus *bus, const uint8_t port)
137 {
138 return USB_SPEED_HIGH;
139 }
140
usb_ehci_dcache_clean(uintptr_t addr,uint32_t len)141 void usb_ehci_dcache_clean(uintptr_t addr, uint32_t len)
142 {
143 aicos_dcache_clean_range((size_t *)addr, len);
144 }
145
usb_ehci_dcache_invalidate(uintptr_t addr,uint32_t len)146 void usb_ehci_dcache_invalidate(uintptr_t addr, uint32_t len)
147 {
148 aicos_dcache_invalid_range((size_t *)addr, len);
149 }
150
usb_ehci_dcache_clean_invalidate(uintptr_t addr,uint32_t len)151 void usb_ehci_dcache_clean_invalidate(uintptr_t addr, uint32_t len)
152 {
153 aicos_dcache_clean_invalid_range((size_t *)addr, len);
154 }
155
__usbh_init(void)156 int __usbh_init(void)
157 {
158 #if defined(AIC_USING_USB0_HOST) || defined(AIC_USING_USB1_HOST)
159 int bus_id = 0;
160 #endif
161
162 #ifdef AIC_USING_USB0_HOST
163 usbh_initialize(bus_id, USB_HOST0_BASE);
164 bus_id++;
165 #endif
166
167 #ifdef AIC_USING_USB1_HOST
168 usbh_initialize(bus_id, USB_HOST1_BASE);
169 bus_id++;
170 #endif
171 return 0;
172 }
173
174 #if defined(KERNEL_RTTHREAD)
175 #include <rtthread.h>
176 #include <rtdevice.h>
177
178 INIT_ENV_EXPORT(__usbh_init);
179 #endif