diff options
Diffstat (limited to 'firmware/target/arm/as3525/usb-drv-as3525v2.c')
-rw-r--r-- | firmware/target/arm/as3525/usb-drv-as3525v2.c | 185 |
1 files changed, 175 insertions, 10 deletions
diff --git a/firmware/target/arm/as3525/usb-drv-as3525v2.c b/firmware/target/arm/as3525/usb-drv-as3525v2.c index 83a5701a11..369a838c65 100644 --- a/firmware/target/arm/as3525/usb-drv-as3525v2.c +++ b/firmware/target/arm/as3525/usb-drv-as3525v2.c | |||
@@ -48,6 +48,9 @@ struct usb_endpoint | |||
48 | static struct usb_endpoint endpoints[USB_NUM_ENDPOINTS*2]; | 48 | static struct usb_endpoint endpoints[USB_NUM_ENDPOINTS*2]; |
49 | #endif | 49 | #endif |
50 | 50 | ||
51 | static unsigned int usb_num_in_ep = 0; | ||
52 | static unsigned int usb_num_out_ep = 0; | ||
53 | |||
51 | void usb_attach(void) | 54 | void usb_attach(void) |
52 | { | 55 | { |
53 | usb_enable(true); | 56 | usb_enable(true); |
@@ -102,6 +105,51 @@ static void as3525v2_connect(void) | |||
102 | usb_delay(); | 105 | usb_delay(); |
103 | } | 106 | } |
104 | 107 | ||
108 | static void usb_enable_common_interrupts(void) | ||
109 | { | ||
110 | /* Clear any pending otg interrupt */ | ||
111 | USB_GOTGINT = 0xffffffff; | ||
112 | /* Clear any pending interrupt */ | ||
113 | USB_GINTSTS = 0Xffffffff; | ||
114 | /* Enable interrupts */ | ||
115 | USB_GINTMSK |= USB_GINTMSK_modemismatch | | ||
116 | USB_GINTMSK_otgintr | | ||
117 | USB_GINTMSK_rxstsqlvl | /* for dma */ | ||
118 | USB_GINTMSK_conidstschng | | ||
119 | USB_GINTMSK_wkupintr | | ||
120 | USB_GINTMSK_disconnect | | ||
121 | USB_GINTMSK_usbsuspend | | ||
122 | USB_GINTMSK_sessreqintr; | ||
123 | } | ||
124 | |||
125 | static void usb_flush_tx_fifos(int nums) | ||
126 | { | ||
127 | unsigned int i = 0; | ||
128 | |||
129 | USB_GRSTCTL = (USB_GRSTCTL & (~USB_GRSTCTL_txfnum_bits)) | ||
130 | | (nums << USB_GRSTCTL_txfnum_bit_pos) | ||
131 | | USB_GRSTCTL_txfflsh_flush; | ||
132 | while(USB_GRSTCTL & USB_GRSTCTL_txfflsh_flush && i < 0x300) | ||
133 | i++; | ||
134 | if(USB_GRSTCTL & USB_GRSTCTL_txfflsh_flush) | ||
135 | panicf("usb: hang of flush tx fifos (%x)", nums); | ||
136 | /* wait 3 phy clocks */ | ||
137 | sleep(1); | ||
138 | } | ||
139 | |||
140 | static void usb_flush_rx_fifo(void) | ||
141 | { | ||
142 | unsigned int i = 0; | ||
143 | |||
144 | USB_GRSTCTL |= USB_GRSTCTL_rxfflsh_flush; | ||
145 | while(USB_GRSTCTL & USB_GRSTCTL_rxfflsh_flush && i < 0x300) | ||
146 | i++; | ||
147 | if(USB_GRSTCTL & USB_GRSTCTL_rxfflsh_flush) | ||
148 | panicf("usb: hang of flush rx fifo"); | ||
149 | /* wait 3 phy clocks */ | ||
150 | sleep(1); | ||
151 | } | ||
152 | |||
105 | static void core_reset(void) | 153 | static void core_reset(void) |
106 | { | 154 | { |
107 | unsigned int i = 0; | 155 | unsigned int i = 0; |
@@ -118,26 +166,137 @@ static void core_reset(void) | |||
118 | i++; | 166 | i++; |
119 | 167 | ||
120 | if(USB_GRSTCTL & USB_GRSTCTL_csftrst) | 168 | if(USB_GRSTCTL & USB_GRSTCTL_csftrst) |
121 | { | 169 | panicf("oops, usb core soft reset hang :("); |
122 | logf("oops, usb core soft reset hang :("); | ||
123 | } | ||
124 | 170 | ||
125 | /* Wait for 3 PHY Clocks */ | 171 | /* Wait for 3 PHY Clocks */ |
126 | /*mdelay(100);*/ | 172 | /*mdelay(100);*/ |
127 | sleep(1); | 173 | sleep(1); |
128 | 174 | ||
129 | logf("%ld endpoints", USB_GHWCFG2_NUM_EP); | 175 | /* Check hardware capabilityies */ |
130 | for(i = 0; i < USB_GHWCFG2_NUM_EP; i++) | 176 | if(USB_GHWCFG2_ARCH != USB_INT_DMA_ARCH) |
131 | logf(" EP%d: IN=%ld OUT=%ld", i, USB_GHWCFG1_IN_EP(i), USB_GHWCFG1_OUT_EP(i)); | 177 | panicf("usb: wrong architecture (%ld)", USB_GHWCFG2_ARCH); |
178 | if(USB_GHWCFG2_HS_PHY_TYPE != USB_PHY_TYPE_UTMI) | ||
179 | panicf("usb: wrong HS phy type (%ld)", USB_GHWCFG2_HS_PHY_TYPE); | ||
180 | if(USB_GHWCFG2_FS_PHY_TYPE != USB_PHY_TYPE_UNSUPPORTED) | ||
181 | panicf("usb: wrong FS phy type (%ld)", USB_GHWCFG2_FS_PHY_TYPE); | ||
182 | if(USB_GHWCFG2_DYN_FIFO != 1) | ||
183 | panicf("usb: no dynamic fifo"); | ||
184 | if(USB_GHWCFG4_UTMI_PHY_DATA_WIDTH != 0x2) | ||
185 | panicf("usb: wrong utmi data width (%ld)", USB_GHWCFG4_UTMI_PHY_DATA_WIDTH); | ||
186 | if(USB_GHWCFG4_DED_FIFO_EN != 1) /* it seems to be multiple tx fifo support */ | ||
187 | panicf("usb: no multiple tx fifo"); | ||
188 | |||
132 | logf("hwcfg1: %08lx", USB_GHWCFG1); | 189 | logf("hwcfg1: %08lx", USB_GHWCFG1); |
133 | logf("hwcfg2: %08lx", USB_GHWCFG2); | 190 | logf("hwcfg2: %08lx", USB_GHWCFG2); |
134 | logf("hwcfg3: %08lx", USB_GHWCFG3); | 191 | logf("hwcfg3: %08lx", USB_GHWCFG3); |
135 | logf("hwcfg4: %08lx", USB_GHWCFG4); | 192 | logf("hwcfg4: %08lx", USB_GHWCFG4); |
136 | 193 | ||
137 | logf("%ld in ep", USB_GHWCFG4_NUM_IN_EP); | 194 | logf("%ld endpoints", USB_GHWCFG2_NUM_EP); |
138 | logf("tot fifo sz: %ld", USB_GHWCFG3_DFIFO_LEN); | 195 | usb_num_in_ep = 0; |
139 | logf("rx fifo sz: %ld", USB_GRXFSIZ); | 196 | usb_num_out_ep = 0; |
140 | logf("tx fifo sz: %ld", USB_GNPTXFSIZ >> 16); /* there is no perio ep so print only non-perio */ | 197 | for(i = 0; i < USB_GHWCFG2_NUM_EP; i++) |
198 | { | ||
199 | if(USB_GHWCFG1_IN_EP(i)) | ||
200 | usb_num_in_ep++; | ||
201 | if(USB_GHWCFG1_OUT_EP(i)) | ||
202 | usb_num_out_ep++; | ||
203 | logf(" EP%d: IN=%ld OUT=%ld", i, USB_GHWCFG1_IN_EP(i), USB_GHWCFG1_OUT_EP(i)); | ||
204 | } | ||
205 | |||
206 | if(usb_num_in_ep != USB_GHWCFG4_NUM_IN_EP) | ||
207 | panicf("usb: num in ep mismatch(%d,%lu)", usb_num_in_ep, USB_GHWCFG4_NUM_IN_EP); | ||
208 | |||
209 | logf("%d in ep, %d out ep", usb_num_in_ep, usb_num_out_ep); | ||
210 | logf("initial:"); | ||
211 | logf(" tot fifo sz: %ld", USB_GHWCFG3_DFIFO_LEN); | ||
212 | logf(" rx fifo sz: %ld", USB_GRXFSIZ); | ||
213 | logf(" tx fifo sz: %ld", USB_GET_FIFOSIZE_DEPTH(USB_GNPTXFSIZ)); /* there is no perio ep so print only non-perio */ | ||
214 | for(i = 1; i <= USB_GHWCFG4_NUM_IN_EP; i++) | ||
215 | { | ||
216 | logf(" dieptx fifo sd (%2u): %ld", i, USB_GET_FIFOSIZE_DEPTH(USB_DIEPTXFSIZ(i))); | ||
217 | } | ||
218 | |||
219 | /* Setup FIFOs */ | ||
220 | /* Organize FIFO as follow (unsure): | ||
221 | * 0 -> rxfsize : RX fifo | ||
222 | * rxfsize -> rxfsize + nptxfsize : TX fifo for first IN ep | ||
223 | * rxfsize + nptxfsize -> rxfsize + 2 * nptxfsize : TX fifo for second IN ep | ||
224 | * rxfsize + 2 * nptxfsize -> rxfsize + 3 * nptxfsize : TX fifo for third IN ep | ||
225 | * ... | ||
226 | */ | ||
227 | |||
228 | unsigned short adr = USB_GRXFSIZ; | ||
229 | unsigned short depth = USB_GET_FIFOSIZE_DEPTH(USB_GNPTXFSIZ); | ||
230 | USB_GNPTXFSIZ = USB_MAKE_FIFOSIZE_DATA(adr, depth); | ||
231 | adr += depth; | ||
232 | |||
233 | for(i = 1; i <= USB_GHWCFG4_NUM_IN_EP; i++) | ||
234 | { | ||
235 | depth = USB_GET_FIFOSIZE_DEPTH(USB_DIEPTXFSIZ(i)); | ||
236 | USB_DIEPTXFSIZ(i) = USB_MAKE_FIFOSIZE_DATA(adr, depth); | ||
237 | adr += depth; | ||
238 | } | ||
239 | |||
240 | logf("used:"); | ||
241 | logf(" rx fifo: [%04x,+%4lx]", 0, USB_GRXFSIZ); | ||
242 | logf(" nptx fifo: [%04lx,+%4lx]", USB_GET_FIFOSIZE_START_ADR(USB_GNPTXFSIZ), | ||
243 | USB_GET_FIFOSIZE_DEPTH(USB_GNPTXFSIZ)); | ||
244 | for(i = 1; i <= USB_GHWCFG4_NUM_IN_EP; i++) | ||
245 | { | ||
246 | logf(" dieptx fifo(%2u): [%04lx,+%4lx]", i, | ||
247 | USB_GET_FIFOSIZE_START_ADR(USB_DIEPTXFSIZ(i)), | ||
248 | USB_GET_FIFOSIZE_DEPTH(USB_DIEPTXFSIZ(i))); | ||
249 | } | ||
250 | |||
251 | /* flush the fifos */ | ||
252 | usb_flush_tx_fifos(0x10); /* flush all */ | ||
253 | usb_flush_rx_fifo(); | ||
254 | |||
255 | /* flush learning queue */ | ||
256 | USB_GRSTCTL |= USB_GRSTCTL_intknqflsh; | ||
257 | |||
258 | /* Clear all pending device interrupts */ | ||
259 | USB_DIEPMSK = 0; | ||
260 | USB_DOEPMSK = 0; | ||
261 | USB_DAINT = 0xffffffff; | ||
262 | USB_DAINTMSK = 0; | ||
263 | |||
264 | for(i = 0; i <= usb_num_in_ep; i++) | ||
265 | { | ||
266 | /* disable endpoint if enabled */ | ||
267 | if(USB_DIEPCTL(i) & USB_DEPCTL_epena) | ||
268 | USB_DIEPCTL(i) = USB_DEPCTL_epdis | USB_DEPCTL_snak; | ||
269 | else | ||
270 | USB_DIEPCTL(i) = 0; | ||
271 | |||
272 | USB_DIEPTSIZ(i) = 0; | ||
273 | USB_DIEPDMA(i) = 0; | ||
274 | USB_DIEPINT(i) = 0xff; | ||
275 | } | ||
276 | |||
277 | for(i = 0; i <= usb_num_out_ep; i++) | ||
278 | { | ||
279 | /* disable endpoint if enabled */ | ||
280 | if(USB_DOEPCTL(i) & USB_DEPCTL_epena) | ||
281 | USB_DOEPCTL(i) = USB_DEPCTL_epdis | USB_DEPCTL_snak; | ||
282 | else | ||
283 | USB_DOEPCTL(i) = 0; | ||
284 | |||
285 | USB_DOEPTSIZ(i) = 0; | ||
286 | USB_DOEPDMA(i) = 0; | ||
287 | USB_DOEPINT(i) = 0xff; | ||
288 | } | ||
289 | } | ||
290 | |||
291 | static void core_dev_init(void) | ||
292 | { | ||
293 | /* Restart the phy clock */ | ||
294 | USB_PCGCCTL = 0; | ||
295 | /* Set phy speed : high speed */ | ||
296 | USB_DCFG = (USB_DCFG & (~USB_DCFG_devspd_bits)) | USB_DCFG_devspd_hs_phy_hs; | ||
297 | /* Set periodic frame interval */ | ||
298 | USB_DCFG = (USB_DCFG & (~USB_DCFG_perfrint_bits)) | (USB_DCFG_FRAME_INTERVAL_80 << USB_DCFG_perfrint_bit_pos); | ||
299 | /* Configure data fifo size */ | ||
141 | } | 300 | } |
142 | 301 | ||
143 | static void core_init(void) | 302 | static void core_init(void) |
@@ -169,6 +328,12 @@ static void core_init(void) | |||
169 | USB_GAHBCFG |= USB_GAHBCFG_dma_enable; | 328 | USB_GAHBCFG |= USB_GAHBCFG_dma_enable; |
170 | /* Disable HNP and SRP, not sure it's useful because we already forced dev mode */ | 329 | /* Disable HNP and SRP, not sure it's useful because we already forced dev mode */ |
171 | USB_GUSBCFG &= ~(USB_GUSBCFG_SRP_cap | USB_GUSBCFG_HNP_cap); | 330 | USB_GUSBCFG &= ~(USB_GUSBCFG_SRP_cap | USB_GUSBCFG_HNP_cap); |
331 | |||
332 | /* enable basic interrupts */ | ||
333 | usb_enable_common_interrupts(); | ||
334 | |||
335 | /* perform device model specific init */ | ||
336 | core_dev_init(); | ||
172 | } | 337 | } |
173 | 338 | ||
174 | void usb_drv_init(void) | 339 | void usb_drv_init(void) |