1 /*
2  * Copyright (c) 2024, sakumisu
3  *
4  * SPDX-License-Identifier: Apache-2.0
5  */
6 #include "bflb_core.h"
7 #include "bflb_l1c.h"
8 #include "usbh_core.h"
9 #include "hardware/usb_v2_reg.h"
10 
11 #ifndef CONFIG_USB_EHCI_HCOR_RESERVED_DISABLE
12 #error "usb host must enable CONFIG_USB_EHCI_HCOR_RESERVED_DISABLE"
13 #endif
14 
15 #define BLFB_USB_BASE ((uint32_t)0x20072000)
16 #define BFLB_PDS_BASE ((uint32_t)0x2000e000)
17 
18 #define PDS_USB_CTL_OFFSET      (0x500) /* usb_ctl */
19 #define PDS_USB_PHY_CTRL_OFFSET (0x504) /* usb_phy_ctrl */
20 
21 /* 0x500 : usb_ctl */
22 #define PDS_REG_USB_SW_RST_N   (1 << 0U)
23 #define PDS_REG_USB_EXT_SUSP_N (1 << 1U)
24 #define PDS_REG_USB_WAKEUP     (1 << 2U)
25 #define PDS_REG_USB_L1_WAKEUP  (1 << 3U)
26 #define PDS_REG_USB_DRVBUS_POL (1 << 4U)
27 #define PDS_REG_USB_IDDIG      (1 << 5U)
28 
29 /* 0x504 : usb_phy_ctrl */
30 #define PDS_REG_USB_PHY_PONRST       (1 << 0U)
31 #define PDS_REG_USB_PHY_OSCOUTEN     (1 << 1U)
32 #define PDS_REG_USB_PHY_XTLSEL_SHIFT (2U)
33 #define PDS_REG_USB_PHY_XTLSEL_MASK  (0x3 << PDS_REG_USB_PHY_XTLSEL_SHIFT)
34 #define PDS_REG_USB_PHY_OUTCLKSEL    (1 << 4U)
35 #define PDS_REG_USB_PHY_PLLALIV      (1 << 5U)
36 #define PDS_REG_PU_USB20_PSW         (1 << 6U)
37 
38 #define USB_SOF_TIMER_MASK_AFTER_RESET_HS (0x44C)
39 #define USB_SOF_TIMER_MASK_AFTER_RESET_FS (0x2710)
40 
41 extern void USBH_IRQHandler(uint8_t busid);
42 
USBH_IRQ(int irq,void * arg)43 void USBH_IRQ(int irq, void *arg) {
44     USBH_IRQHandler(0);
45 }
46 
bflb_usb_phy_init(void)47 static void bflb_usb_phy_init(void)
48 {
49     uint32_t regval;
50 
51     /* USB_PHY_CTRL[3:2] reg_usb_phy_xtlsel=0                             */
52     /* 2000e504 = 0x40; #100; USB_PHY_CTRL[6] reg_pu_usb20_psw=1 (VCC33A) */
53     /* 2000e504 = 0x41; #500; USB_PHY_CTRL[0] reg_usb_phy_ponrst=1        */
54     /* 2000e500 = 0x20; #100; USB_CTL[0] reg_usb_sw_rst_n=0               */
55     /* 2000e500 = 0x22; #500; USB_CTL[1] reg_usb_ext_susp_n=1             */
56     /* 2000e500 = 0x23; #100; USB_CTL[0] reg_usb_sw_rst_n=1               */
57     /* #1.2ms; wait UCLK                                                  */
58     /* wait(soc616_b0.usb_uclk);                                          */
59 
60     regval = getreg32(BFLB_PDS_BASE + PDS_USB_PHY_CTRL_OFFSET);
61     regval &= ~PDS_REG_USB_PHY_XTLSEL_MASK;
62     putreg32(regval, BFLB_PDS_BASE + PDS_USB_PHY_CTRL_OFFSET);
63 
64     regval = getreg32(BFLB_PDS_BASE + PDS_USB_PHY_CTRL_OFFSET);
65     regval |= PDS_REG_PU_USB20_PSW;
66     putreg32(regval, BFLB_PDS_BASE + PDS_USB_PHY_CTRL_OFFSET);
67 
68     regval = getreg32(BFLB_PDS_BASE + PDS_USB_PHY_CTRL_OFFSET);
69     regval |= PDS_REG_USB_PHY_PONRST;
70     putreg32(regval, BFLB_PDS_BASE + PDS_USB_PHY_CTRL_OFFSET);
71 
72     /* greater than 5T */
73     bflb_mtimer_delay_us(1);
74 
75     regval = getreg32(BFLB_PDS_BASE + PDS_USB_CTL_OFFSET);
76     regval &= ~PDS_REG_USB_SW_RST_N;
77     putreg32(regval, BFLB_PDS_BASE + PDS_USB_CTL_OFFSET);
78 
79     /* greater than 5T */
80     bflb_mtimer_delay_us(1);
81 
82     regval = getreg32(BFLB_PDS_BASE + PDS_USB_CTL_OFFSET);
83     regval |= PDS_REG_USB_EXT_SUSP_N;
84     putreg32(regval, BFLB_PDS_BASE + PDS_USB_CTL_OFFSET);
85 
86     /* wait UCLK 1.2ms */
87     bflb_mtimer_delay_ms(3);
88 
89     regval = getreg32(BFLB_PDS_BASE + PDS_USB_CTL_OFFSET);
90     regval |= PDS_REG_USB_SW_RST_N;
91     putreg32(regval, BFLB_PDS_BASE + PDS_USB_CTL_OFFSET);
92 
93     bflb_mtimer_delay_ms(2);
94 }
95 
usb_hc_low_level_init(struct usbh_bus * bus)96 void usb_hc_low_level_init(struct usbh_bus *bus)
97 {
98     uint32_t regval;
99 
100     bflb_usb_phy_init();
101 
102     bflb_irq_attach(37, USBH_IRQ, NULL);
103     bflb_irq_enable(37);
104 
105     /* enable device-A for host */
106     regval = getreg32(BFLB_PDS_BASE + PDS_USB_CTL_OFFSET);
107     regval &= ~PDS_REG_USB_IDDIG;
108     putreg32(regval, BFLB_PDS_BASE + PDS_USB_CTL_OFFSET);
109 
110     regval = getreg32(BLFB_USB_BASE + USB_OTG_CSR_OFFSET);
111     regval |= USB_A_BUS_DROP_HOV;
112     regval &= ~USB_A_BUS_REQ_HOV;
113     putreg32(regval, BLFB_USB_BASE + USB_OTG_CSR_OFFSET);
114 
115     bflb_mtimer_delay_ms(10);
116 
117     /* enable vbus and bus control */
118     regval = getreg32(BLFB_USB_BASE + USB_OTG_CSR_OFFSET);
119     regval &= ~USB_A_BUS_DROP_HOV;
120     regval |= USB_A_BUS_REQ_HOV;
121     putreg32(regval, BLFB_USB_BASE + USB_OTG_CSR_OFFSET);
122 
123     regval = getreg32(BLFB_USB_BASE + USB_GLB_INT_OFFSET);
124     regval |= USB_MDEV_INT;
125     regval |= USB_MOTG_INT;
126     regval &= ~USB_MHC_INT;
127     putreg32(regval, BLFB_USB_BASE + USB_GLB_INT_OFFSET);
128 }
129 
usbh_get_port_speed(struct usbh_bus * bus,const uint8_t port)130 uint8_t usbh_get_port_speed(struct usbh_bus *bus, const uint8_t port)
131 {
132     uint8_t speed = 3;
133 
134     speed = (getreg32(BLFB_USB_BASE + USB_OTG_CSR_OFFSET) & USB_SPD_TYP_HOV_POV_MASK) >> USB_SPD_TYP_HOV_POV_SHIFT;
135 
136     if (speed == 0) {
137         return USB_SPEED_FULL;
138     } else if (speed == 1) {
139         return USB_SPEED_LOW;
140     } else if (speed == 2) {
141         return USB_SPEED_HIGH;
142     }
143     return USB_SPEED_HIGH;
144 }
145 
146 #ifdef CONFIG_USB_DCACHE_ENABLE
usb_dcache_clean(uintptr_t addr,size_t size)147 void usb_dcache_clean(uintptr_t addr, size_t size)
148 {
149     bflb_l1c_dcache_clean_range((void *)addr, size);
150 }
151 
usb_dcache_invalidate(uintptr_t addr,size_t size)152 void usb_dcache_invalidate(uintptr_t addr, size_t size)
153 {
154     bflb_l1c_dcache_invalidate_range((void *)addr, size);
155 }
156 
usb_dcache_flush(uintptr_t addr,size_t size)157 void usb_dcache_flush(uintptr_t addr, size_t size)
158 {
159     bflb_l1c_dcache_clean_invalidate_range((void *)addr, size);
160 }
161 #endif