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