thor: fix invalid larger device descriptor than requested
[profile/mobile/platform/kernel/u-boot-tm1.git] / property / usb / drv_cdc.c
1 /******************************************************************************
2  ** File Name:      DRV_usb.c                                                 *
3  ** Author:         JiaYong.Yang                                              *
4  ** DATE:           09/01/2010                                                *
5  ** Copyright:      2010 Spreatrum, Incoporated. All Rights Reserved.         *
6  ** Description:                                                              *
7  ******************************************************************************/
8 /**---------------------------------------------------------------------------*
9  **                         Dependencies                                      *
10  **---------------------------------------------------------------------------*/
11 #include <config.h>
12 #include <common.h>
13
14 #include <asm/arch/common.h>
15 #include <asm/arch/usb200_fdl.h>
16 #include <asm/arch/drv_usb20.h>
17 #include <asm/arch/virtual_com.h>
18 #include <asm/arch/packet.h>
19 #include <asm/arch/usb20_reg_v3.h>
20 #include <linux/usb/ch9.h>
21
22 #define USB_DEBUG
23
24 #ifdef USB_DEBUG
25 #define usb_debug(fmt, arg...)          printf(fmt, ## arg)
26 #else
27 #define usb_debug(fmt, arg...)
28 #endif
29
30 typedef enum
31 {
32         USB_HIGH, USB_FULL, USB_LOW
33 } USB_SPEED;
34
35 #define USB_DEVICE_QUALIFIER_TYPE                 0x06
36 #define USB_OTHER_SPEED_CONFIGURATION_DESCRIPTOR_TYPE                 0x07
37
38
39 #define PUBLIC
40 #define LOCAL static
41 int rdx=0;
42 int x=0;
43 int error=0;
44 int length;
45 int check_usb_reconnected = 0;
46
47 extern void usb_power_on(void);
48 extern void usb_power_off(void);
49 extern unsigned char *thor_get_device_desc(unsigned int speed);
50 extern unsigned char *thor_get_config_desc(unsigned int speed);
51 extern unsigned char *thor_get_string_desc(unsigned char index);
52 extern unsigned char *thor_get_qualifer_desc(void);
53 extern unsigned char *thor_get_other_speed_config_desc(void);
54
55 extern void Dcache_InvalRegion(unsigned int addr, unsigned int length);
56 extern void Dcache_CleanRegion(unsigned int addr, unsigned int length);
57 extern int panic_display(void);
58
59 static __inline void usb_handler (void);
60
61 //static int booting_mode = BOOT_MODE_NORMAL;
62
63 /**---------------------------------------------------------------------------*
64  **                         Compiler Flag                                     *
65  **---------------------------------------------------------------------------*/
66 #define BULK_MPS                USB_PACKET_512
67 #define EP_OUT                  USB_EP2
68 #define EP_IN                   USB_EP1
69 #define EP_INTERRUPT            USB_EP3
70 #define MAX_RECV_LENGTH         (BULK_MPS) 
71 #define MAX_PACKET_SIZE                 (BULK_MPS)
72 #define USB_TIMEOUT             (1000)
73
74 #define USB_SUSPEND_AFTER_USB_MODE_START    0 // step 2. if (usb suspend occurred) after usb mode started
75 #define USB_STARTED                         1 // step 1. after usb mode start this value will set
76 #define USB_DETACHED_AFTER_USB_MODE_START   2 // step 3. if (usb suspend occurred) and (musb cable detached) -> goto usb restart
77 #define USB_BEFORE_USB_MODE                 4 // step 0. default value before usb mode start
78
79 /**---------------------------------------------------------------------------*
80  **                         Data Structures                                   *
81  **---------------------------------------------------------------------------*/
82 __align(32) uint8 line_coding_config[7] = {0x00,0xc2,0x01,0x00,0x00,0x00,0x08};
83 __align (32) LOCAL uint32    s_setup_packet[8] = {0};
84 __align (32) LOCAL unsigned char usb_out_endpoint_buf[2] [MAX_RECV_LENGTH];
85 /*lint -e551 for "enum_speed" */
86 uint32    enum_speed = 0;
87 LOCAL uint32    recv_length = 0;
88 static unsigned int g_cdc_status = 0;
89 LOCAL uint32    s_comm_feature = 0;
90 /*++for ch9 test*/
91 uint32  g_cdc_state = 0;
92 LOCAL uint32 g_cdc_configuration = 1;
93 LOCAL uint32 g_cdc_interface = 1;
94 /*--for ch9 test*/
95 LOCAL uint32 g_usb_status = USB_BEFORE_USB_MODE;
96 /*****************************************************************************/
97 //  Description:   configure out endpoint0 to receive setup message.
98 //  Global resource dependence:
99 //  Author:        jiayong.yang
100 //  Note:
101 /*****************************************************************************/
102 LOCAL int EPO0_config (BOOLEAN is_dma, uint32 *buffer)
103 {
104         // Programs DOEPTSIZ0 register with Packet Count and Transfer Size
105         * (volatile uint32 *) USB_DOEP0TSIZ |= (unsigned int) (BIT_29|BIT_30); //setup packet count , 3 packet
106         * (volatile uint32 *) USB_DOEP0TSIZ |= (unsigned int) (BIT_3|BIT_4); //set Transfer Size ,24 bytes
107
108         if (is_dma)
109         {
110                 * (volatile uint32 *) USB_DOEPDMA (0) = (uint32) buffer;//lint !e718
111         }
112
113         * (volatile uint32 *) USB_DOEP0CTL |= (unsigned int) BIT_26;    // set clear NAK
114         * (volatile uint32 *) USB_DOEP0CTL |= (unsigned int) BIT_31;    // set endpoint enable
115         return 0;
116 }
117 /*****************************************************************************/
118 //  Description:   configure in endpoint0 to send message.
119 //  Global resource dependence:
120 //  Author:        jiayong.yang
121 //  Note:
122 /*****************************************************************************/
123 LOCAL void EPI0_config (uint32 transfer_size, uint32 packet_count, BOOLEAN is_dma, uint32 *buffer)
124 {
125         volatile USB_DIEP0TSIZ_U *diep0tsiz_ptr = (USB_DIEP0TSIZ_U *) USB_DIEP0TSIZ;
126
127         diep0tsiz_ptr->mBits.transfer_size = transfer_size;
128         diep0tsiz_ptr->mBits.packet_count = packet_count;
129
130         if (is_dma)
131         {
132                 Dcache_CleanRegion((unsigned int)(buffer), transfer_size);
133                 * (volatile uint32 *) USB_DIEPDMA (0) = (uint32) buffer;//lint !e718
134         }
135
136         * (volatile uint32 *) USB_DIEP0CTL &= (unsigned int) (~ (BIT_22|BIT_23|BIT_24|BIT_25)); // set EP0 in tx fifo nummber
137
138         * (volatile uint32 *) USB_DIEP0CTL |= (unsigned int) BIT_26;                    // clear NAK
139
140         * (volatile uint32 *) USB_DIEP0CTL |= (unsigned int) BIT_31;                    // set endpoint enable
141
142         while(1)
143         {
144                 diep0tsiz_ptr = (USB_DIEP0TSIZ_U *) USB_DIEP0TSIZ;
145                 if(diep0tsiz_ptr->dwValue==0)
146                 {
147                         break;
148                 }
149         }
150         diep0tsiz_ptr->dwValue=0;
151 }
152 /*****************************************************************************/
153 //  Description:   usb reset interrupt handler.
154 //  Global resource dependence:
155 //  Author:        jiayong.yang
156 //  Note:
157 /*****************************************************************************/
158 LOCAL void usb_EPActive (USB_EP_NUM_E ep_num, BOOLEAN dir)
159 {
160         if (dir)        // out endpoint
161         {
162                 *(volatile uint32 *) USB_DOEPCTL (ep_num) |= (unsigned int) BIT_15;     //lint !e718// endpoint active
163                 * (volatile uint32 *) USB_DOEPMSK = (unsigned int) (BIT_13|BIT_12|BIT_3|BIT_0);
164         }
165         else
166         {
167                 *(volatile uint32 *) USB_DIEPCTL (ep_num) |= (unsigned int) BIT_15;     //lint !e718// endpoint active
168                 *(volatile uint32 *) USB_DIEPMSK = 0xffffffff;
169         }
170 }
171 /*****************************************************************************/
172 //  Description:   configure specified endpoint to send/receive message.
173 //  Global resource dependence:
174 //  Author:        jiayong.yang
175 //  Note:
176 /*****************************************************************************/
177 LOCAL void EPn_config (USB_EP_NUM_E ep_num, USB_EP_TYPE_E ep_type, BOOLEAN dir, uint32 mps)
178 {
179         // out endpoint
180         if (dir)
181         {
182                 volatile USB_DOEPCTL_U *doepctl_ptr = (USB_DOEPCTL_U *) USB_DOEPCTL (ep_num);
183
184                 doepctl_ptr->mBits.ep_type = ep_type;
185                 doepctl_ptr->mBits.mps =mps;
186                 doepctl_ptr->mBits.set_nak = 0x1;
187         }
188         else
189         {
190                 volatile USB_DIEPCTL_U *diepctl_ptr = (USB_DIEPCTL_U *) USB_DIEPCTL (ep_num);
191
192                 diepctl_ptr->mBits.ep_type = ep_type;
193                 diepctl_ptr->mBits.mps = mps;
194                 diepctl_ptr->mBits.set_nak = 0x1;
195         }
196 }
197
198 /*****************************************************************************/
199 //  Description:   start endpoint transfer.
200 //  Global resource dependence:
201 //  Author:        jiayong.yang
202 //  Note:
203 /*****************************************************************************/
204 LOCAL void usb_start_transfer (USB_EP_NUM_E ep_num, BOOLEAN dir, uint32 transfer_size, BOOLEAN is_dma, uint32 *buffer)
205 {
206         uint16 packet_count = 0;
207
208         if (dir)
209         {
210                 volatile USB_DOEPTSIZ_U *doeptsiz_ptr = (USB_DOEPTSIZ_U *) USB_DOEPTSIZ (ep_num);
211
212                 if (is_dma)
213                 {
214                         * (volatile uint32 *) USB_DOEPDMA (ep_num) = (uint32) buffer;
215                 }
216
217                 doeptsiz_ptr->mBits.transfer_size = MAX_RECV_LENGTH;    // transfer size
218                 doeptsiz_ptr->mBits.packet_count = MAX_RECV_LENGTH/BULK_MPS;
219                 * (volatile uint32 *) USB_DOEPCTL (ep_num) |= (unsigned int) (BIT_26|BIT_31); // clear nak
220         }
221         else
222         {
223                 volatile USB_DIEPTSIZ_U *dieptsiz_ptr = (USB_DIEPTSIZ_U *) USB_DIEPTSIZ (ep_num);
224                 volatile USB_DIEPCTL_U   *diepctl_ptr = (USB_DIEPCTL_U *) USB_DIEPCTL (ep_num);
225
226                 if (is_dma)
227                 {
228                         Dcache_CleanRegion((unsigned int)buffer,  transfer_size);//0511
229                         * (volatile uint32 *) USB_DIEPDMA (ep_num) = (uint32) buffer;
230                 }
231
232                 dieptsiz_ptr->mBits.transfer_size = transfer_size;                  // transfer size
233                 packet_count = (transfer_size+diepctl_ptr->mBits.mps-1) /diepctl_ptr->mBits.mps;/*lint !e564*/
234                 dieptsiz_ptr->mBits.packet_count = packet_count;                    // packet count
235         diepctl_ptr->mBits.tx_fifo_number = ep_num;                         // tx fifo number
236
237                 * (volatile uint32 *) USB_DIEPCTL (ep_num) |= (unsigned int) BIT_26;            // clear nak
238                 * (volatile uint32 *) USB_DIEPCTL (ep_num) |= (unsigned int) BIT_31;            // endpoint enable
239         }
240
241 }
242
243 /*****************************************************************************/
244 //  Description:   process desecriptor request.
245 //  Global resource dependence:
246 //  Author:        jiayong.yang
247 //  Note:
248 /*****************************************************************************/
249 LOCAL void usb_get_descriptor (USB_REQUEST_1_U *request1, USB_REQUEST_2_U *request2)
250 {
251         uint32 length = 0;
252         uint8 *send_data=NULL;
253         uint8 pkt_cnt=0;
254         uint32 config_des_size=0;
255
256         length = (uint32) (request2->mBits.length_m<<8 |request2->mBits.length_l);
257
258         switch (request1->mBits.value_m)
259         {
260                 case USB_DEVICE_DESCRIPTOR_TYPE:
261                         send_data = (uint8 *) thor_get_device_desc(enum_speed);
262
263                         /*
264                          * only send less or equal than requested length.
265                          * no need to care about larger reqeust than possible
266                          * descriptor length because of zero-length packet
267                          * generated by usb controller
268                          */
269                         EPI0_config (min(USB_DT_DEVICE_SIZE, length), 0x1, TRUE, (uint32 *) send_data);
270                         break;
271
272                 case USB_CONFIGURATION_DESCRIPTOR_TYPE:
273                         send_data = (uint8 *) thor_get_config_desc(enum_speed);
274                         config_des_size = send_data[3]<<8 |send_data[2];
275
276                         if (length > config_des_size)
277                         {
278                                 pkt_cnt =  (config_des_size % 64) ? config_des_size/64 + 1 : config_des_size/64;
279                                 EPI0_config (config_des_size, pkt_cnt, TRUE, (uint32 *) send_data);
280                         }
281                         else
282                         {
283                                 pkt_cnt =  (length % 64) ? length/64 + 1 : length/64;
284                                 EPI0_config (length, pkt_cnt, TRUE, (uint32 *) send_data);
285                         }
286                         break;
287
288                 case USB_STRING_DESCRIPTOR_TYPE:
289                 {
290                         uint8 str_index = request1->mBits.value_l;
291                         send_data = thor_get_string_desc(str_index);
292
293                         if(length > send_data[0])
294                         {
295                                 EPI0_config (send_data[0], 0x1, TRUE, (uint32 *) send_data);
296                         }
297                         else
298                         {
299                                 EPI0_config (length, 0x1, TRUE, (uint32 *) send_data);
300                         }
301                 }
302                         break;
303
304                 case USB_DEVICE_QUALIFIER_TYPE:
305                         send_data = (uint8 *) thor_get_qualifer_desc();
306                         if(length > send_data[0])
307                         {
308                                 EPI0_config (send_data[0], 0x1, TRUE, (uint32 *) send_data);
309                         }
310                         else
311                         {
312                                 EPI0_config (length, 0x1, TRUE, (uint32 *) send_data);
313                         }
314                         break;
315
316                 case USB_OTHER_SPEED_CONFIGURATION_DESCRIPTOR_TYPE:
317
318                         send_data = (uint8 *) thor_get_other_speed_config_desc();
319                         config_des_size = send_data[3]<<8 |send_data[2];
320                         if (length > config_des_size)
321                         {
322                                 pkt_cnt =  (config_des_size % 64) ? config_des_size/64 + 1 : config_des_size/64;
323                                 EPI0_config (config_des_size, pkt_cnt, TRUE, (uint32 *) send_data);
324                         }
325                         else
326                         {
327                                 pkt_cnt =  (length % 64) ? length/64 + 1 : length/64;
328                                 EPI0_config (length, pkt_cnt, TRUE, (uint32 *) send_data);
329                         }
330                         break;
331
332                 default:
333                         break;
334         }
335 }
336 /*****************************************************************************/
337 //  Description:   process setup transaction.
338 //  Global resource dependence:
339 //  Author:        jiayong.yang
340 //  Note:
341 /*****************************************************************************/
342 LOCAL int USB_EP0RecvEmptyPacket (void)
343 {
344         uint32 packet_count;
345         volatile USB_DOEPINT_U *doepint_ptr = (USB_DOEPINT_U *) USB_DOEPINT (0);
346
347         if(doepint_ptr->mBits.transfer_com == 1)
348                 doepint_ptr->mBits.transfer_com=1;
349         packet_count = 1;
350         * (volatile uint32 *) USB_DOEP0TSIZ = (packet_count<<19) ; //setup packet count , 3 packet
351
352         * (volatile uint32 *) USB_DOEP0CTL |= BIT_26;       // set clear NAK
353         * (volatile uint32 *) USB_DOEP0CTL |= BIT_31;       // set endpoint enable
354         while(doepint_ptr->mBits.transfer_com==0)
355         {
356                 doepint_ptr = (USB_DOEPINT_U *) USB_DOEPINT (0);
357         }
358         return 0;
359 }
360 LOCAL int USB_EP0RecvData (uint32 *pBuf,int transfer_size)
361 {
362         uint32 packet_count;
363
364         if (transfer_size == 0)
365         {
366                 return 0;
367         }
368
369         packet_count = (transfer_size+63) /64;
370         * (volatile uint32 *) USB_DOEP0TSIZ = (packet_count<<19) | (transfer_size&0x7f); //setup packet count , 3 packet
371         * (volatile uint32 *) USB_DOEPDMA (0) = (uint32) pBuf;
372         * (volatile uint32 *) USB_DOEP0CTL |= BIT_26;       // set clear NAK
373         * (volatile uint32 *) USB_DOEP0CTL |= BIT_31;       // set endpoint enable
374         return 0;
375 }
376 LOCAL void usb_reset_pipe(uint8 epno)
377 {
378         uint8 ep_num = epno & 0x7F;
379         if(ep_num == 0)
380         {
381                 return;
382         }
383         if((epno & 0x80) == 0)
384         {
385                 *(volatile uint32 *)USB_DOEPCTL(ep_num) |= BIT_28;
386         }
387         else
388         {
389                 *(volatile uint32 *)USB_DIEPCTL(ep_num) |= BIT_28;
390         }
391 }
392 /*****************************************************************************/
393 //  Description:   process setup transaction.
394 //  Global resource dependence:
395 //  Author:        jiayong.yang
396 //  Note:
397 /*****************************************************************************/
398 PUBLIC void usb_set_feature (void)
399 {
400         volatile USB_DCTL_U *dctl_ptr = (volatile USB_DCTL_U *) USB_DCTL;
401         USB_REQUEST_2_U   *request2;
402         USB_REQUEST_2_U   request2_u;
403         request2_u.dwValue = s_setup_packet[1];
404         request2= &request2_u;
405
406         EPI0_config (0x0, 0x1, FALSE, NULL);
407
408         while (* (volatile uint32 *) USB_DIEP0TSIZ) {}; // wait packet count is zero
409
410         * (volatile uint32 *) USB_DOEP0CTL |= BIT_26; // clear ep out nak
411
412         switch (request2->mBits.index_m)
413         {
414                 case    1://Test_J
415                         dctl_ptr->mBits.tstctl = request2->mBits.index_m;
416                         break;
417                 case    2://Test_K
418                         dctl_ptr->mBits.tstctl = request2->mBits.index_m;
419                         break;
420                 case    3://Test_SE0_NAK
421                         dctl_ptr->mBits.tstctl = request2->mBits.index_m;
422                         break;
423                 case    4://Test_Packet
424                         dctl_ptr->mBits.tstctl = request2->mBits.index_m;
425                         break;
426                 case    5://Test_Force_Enable
427                         dctl_ptr->mBits.tstctl = request2->mBits.index_m;
428                         break;
429                 default:
430                         break;
431         }
432
433         dctl_ptr->mBits.tstctl = request2->mBits.index_m;
434 }
435
436 LOCAL void usb_setup_handle (void)
437 {
438         usb_debug("%s : enter \n", __func__);
439         uint32  vendor_ack = 0;
440         USB_REQUEST_1_U   *request1;
441         USB_REQUEST_2_U   *request2;
442         USB_REQUEST_1_U   request1_u;
443         USB_REQUEST_2_U   request2_u;
444         request1_u.dwValue = s_setup_packet[0];
445         request2_u.dwValue = s_setup_packet[1];
446         request1= &request1_u;
447         request2= &request2_u;
448
449         switch (request1->mBits.type)
450         {
451                 case USB_REQ_STANDARD://standard
452
453                         switch (request1->mBits.recipient)                                              //Recipient
454                         {
455                                 case USB_REC_DEVICE:
456
457                                         switch (request1->mBits.brequest)
458                                         {
459                                                 case USB_REQUEST_SET_FEATURE:
460                                                         usb_set_feature ();
461                                                         break;
462                                                 case USB_REQUEST_SET_ADDRESS:
463                                                 {
464                                                         volatile USB_DCFG_U *dcfg_ptr = (USB_DCFG_U *) USB_DCFG;
465
466                                                         dcfg_ptr->mBits.devaddr = request1->mBits.value_l;
467                                                         EPI0_config (0, 1, FALSE, NULL);
468                                                 }
469                                                         break;
470                                                 case USB_REQUEST_GET_DESCRIPTOR:
471                                                         usb_get_descriptor (request1, request2);
472                                                         break;
473                                                 case USB_REQUEST_SET_CONFIGURATION: //0x00 0x09
474                                                         g_cdc_configuration = request1->mBits.value_l;
475                                                         EPI0_config (0, 1, FALSE, NULL);
476
477                                                         if(g_cdc_status ==0)
478                                                         {
479                                                                 usb_EPActive (EP_IN, USB_EP_DIR_IN);
480                                                                 usb_EPActive (EP_OUT, USB_EP_DIR_OUT);
481                                                                 g_cdc_status = 1;
482                                                         }
483                                                         break;
484                                                 case USB_REQUEST_GET_CONFIGURATION:
485                                                         EPI0_config (request2->mBits.length_l, 1, TRUE, &g_cdc_configuration);
486                                                         break;
487                                                 case USB_REQUEST_SET_INTERFACE:
488                                                         EPI0_config (0, 1, FALSE, NULL);
489                                                         break;
490                                                 case USB_REQUEST_CLEAR_FEATURE:
491                                                         if(request1->mBits.recipient == 2)
492                                                         {
493                                                                 usb_reset_pipe(request2->mBits.index_l);
494                                                         }
495                                                         EPI0_config (0, 1, FALSE, NULL);
496                                                         break;
497                                                 default:
498                                                         EPI0_config (0, 1, TRUE, &vendor_ack);
499                                                         break;
500                                         }
501                                         break;
502
503                                 case USB_REC_INTERFACE:
504
505                                         switch(request1->mBits.brequest)
506                                         {
507                                                 case USB_REQUEST_SET_INTERFACE://0x01 0x0b
508                                                         g_cdc_interface = request1->mBits.value_l;
509                                                         EPI0_config (0, 1, FALSE, NULL);
510                                                         break;
511                                                 case USB_REQUEST_GET_INTERFACE://0x81 0x0a
512                                                         EPI0_config (request2->mBits.length_l, 1, TRUE, &g_cdc_interface);
513                                                         break;
514                                         }
515                                         break;
516
517                                 case USB_REC_ENDPOINT:
518
519                                         switch(request1->mBits.brequest)
520                                         {
521                                                 case USB_REQUEST_GET_STATUS://0x82 0x00
522                                                         EPI0_config (request2->mBits.length_l, 1, TRUE, &g_cdc_state);
523                                                         break;
524                                                 case USB_REQUEST_SET_FEATURE://0x02 0x03
525                                                         g_cdc_state = 1;
526                                                         usb_set_feature ();
527                                                         break;
528                                                 case USB_REQUEST_CLEAR_FEATURE://0x02 0x01
529                                                         if(request1->mBits.recipient == 2)
530                                                         {
531                                                                 usb_reset_pipe(request2->mBits.index_l);
532                                                         }
533                                                         EPI0_config (0, 1, FALSE, NULL);
534                                                         g_cdc_state = 0;
535                                                         break;
536                                                 default:
537                                                         break;
538                                         }
539                                         break;
540                         }
541                         break;
542
543                 case USB_REQ_CLASS://class
544                         switch (request1->mBits.recipient)
545                         {
546                                 case USB_REC_INTERFACE:
547                                         switch (request1->mBits.brequest)
548                                         {
549                                                 case 0x22:
550                                                         if (request1->mBits.value_l)
551                                                         {
552                                                                 if (g_cdc_status == 0)
553                                                                 {
554                                                                         usb_EPActive (EP_IN, USB_EP_DIR_IN);
555                                                                         usb_EPActive (EP_OUT, USB_EP_DIR_OUT);
556                                                                         g_cdc_status = 1;
557                                                                         usb_debug("g_cdc_status = 1 \n");
558                                                                 }
559                                                         }
560                                                         EPI0_config (0, 1, FALSE, NULL);
561                                                         break;
562                                                 case 0x20:
563                                                         if (request2->mBits.length_l)
564                                                         {
565                                                                 USB_EP0RecvData((uint32 *)line_coding_config,request2->mBits.length_l);
566                                                         }
567                                                                 EPI0_config (0, 1, FALSE, NULL);
568                                                         break;
569                                                 case 0x21:
570                                                         EPI0_config(7, 1, TRUE,(uint32 *)line_coding_config);
571                                                         USB_EP0RecvEmptyPacket();
572                                                         break;
573                                                 case USB_CLEAR_COMM_FEATURE :
574                                                         s_comm_feature = 0;
575                                                         EPI0_config (0, 1, FALSE, NULL);
576                                                         break;
577                                                 case USB_GET_COMM_FEATURE :
578                                                         if (request2->mBits.length_l)
579                                                         {
580                                                                 EPI0_config (2, 1, TRUE, &s_comm_feature);
581                                                         }
582                                                         break;
583                                                 case USB_SET_COMM_FEATURE :
584                                                         if (request2->mBits.length_l)
585                                                         {
586                                                                 USB_EP0RecvData((uint32 *)&s_comm_feature,2);
587                                                         }
588                                                         EPI0_config (0, 1, FALSE, NULL);
589                                                         break;
590                                         }
591                                         break;
592                                 default:
593                                         EPI0_config (0, 1, TRUE, NULL);
594                                         break;
595                         }
596                         break;
597                 case USB_REQ_VENDOR:
598                         EPI0_config (4, 1, TRUE, &vendor_ack);
599                         break;
600                 default:
601                         EPI0_config (0, 1, TRUE, NULL);
602                         break;
603         }
604 }
605 /*****************************************************************************/
606 //  Description:   usb reset interrupt handler.
607 //  Global resource dependence:
608 //  Author:        jiayong.yang
609 //  Note:
610 /*****************************************************************************/
611
612 LOCAL void usb_reset_handler (void)
613 {
614         uint32  timeout = 0;
615         volatile USB_DCFG_U *dcfg_ptr = (USB_DCFG_U *) USB_DCFG;
616
617     dcfg_ptr->mBits.devaddr = 0;
618     *(volatile uint32 *) USB_GAHBCFG |= BIT_5;
619     *(volatile uint32 *) USB_GINTMSK &= (unsigned int) (~BIT_12);                          // disable reset interrupt
620
621     *(volatile uint32 *) USB_DOEP0CTL |= (unsigned int) BIT_27;                            // set NAK for all OUT endpoint
622
623     *(volatile uint32 *) USB_DOEPCTL (6) |= (unsigned int) BIT_27;
624
625     *(volatile uint32 *) USB_DAINTMSK |= (unsigned int) (BIT_0|BIT_16);
626     *(volatile uint32 *) USB_DOEPMSK |= (unsigned int) (BIT_0|BIT_3|BIT_2|BIT_1);
627     *(volatile uint32 *) USB_DIEPMSK |= (unsigned int) (BIT_0|BIT_3|BIT_1|BIT_2|BIT_5);//lint !e718
628
629         *(volatile uint32 *) USB_GRXFSIZ = (unsigned int) (BIT_2 | BIT_4 | BIT_8);
630         *(volatile uint32 *) USB_GNPTXFSIZ = (unsigned int) ((BIT_2 | BIT_4 | BIT_8) | BIT_20);
631         *(volatile uint32 *) USB_DIEPTXF (1) = (unsigned int) ((BIT_2 | BIT_5 | BIT_8) | BIT_24);
632         *(volatile uint32 *) USB_DIEPTXF (2) = (unsigned int) ((BIT_2 | BIT_5 | BIT_9) | BIT_18);
633         *(volatile uint32 *) USB_DIEPTXF (3) = (unsigned int) ((BIT_3 | BIT_5 | BIT_9) | BIT_24);
634         *(volatile uint32 *) USB_DIEPTXF (4) = (unsigned int) ((BIT_3 | BIT_5 | BIT_8 | BIT_9) | BIT_18);
635         *(volatile uint32 *) USB_DIEPTXF (5) = (unsigned int) ((BIT_2 | BIT_3 | BIT_5 | BIT_8 | BIT_9) | BIT_24);
636         *(volatile uint32 *) USB_DIEPTXF (6) = (unsigned int) ((BIT_2 | BIT_3 | BIT_5 | BIT_10) | BIT_18);
637
638     *(volatile uint32 *) USB_GRSTCTL |= (unsigned int) BIT_5;                          //reflush tx fifo
639
640         while ( (* (volatile uint32 *) USB_GRSTCTL) & ( (unsigned int) BIT_5))
641         {
642                 timeout++;
643
644                 if (timeout >= USB_TIMEOUT)
645                 {
646                         break;
647                 }
648         }
649
650         timeout = 0;
651
652         * (volatile uint32 *) USB_GRSTCTL |= (unsigned int) BIT_4;                          //reflush rx fifo
653
654         while ( (* (volatile uint32 *) USB_GRSTCTL) & ( (unsigned int) BIT_4))
655         {
656                 timeout++;
657
658                 if (timeout >= USB_TIMEOUT)
659                 {
660                         break;
661                 }
662         }
663
664         Dcache_InvalRegion((unsigned int)s_setup_packet, sizeof(s_setup_packet));//////////for test
665         EPO0_config (TRUE, s_setup_packet);
666
667         *(volatile uint32 *) USB_GINTMSK |= (unsigned int) BIT_12;                             // enable reset interrupt
668         *(volatile uint32 *) USB_GINTSTS |= (unsigned int) BIT_12;                             //clear reset interrupt
669 }
670
671 /*****************************************************************************/
672 //  Description:   usb enumeration done handler.
673 //  Global resource dependence:
674 //  Author:        jiayong.yang
675 //  Note:
676 /*****************************************************************************/
677
678 LOCAL void usb_enumeration_done (void)
679 {
680         volatile USB_DSTS_U *dsts_ptr = (USB_DSTS_U *) USB_DSTS;
681
682         enum_speed = dsts_ptr->mBits.enumspd;                                   //read enumration speed
683         * (volatile uint32 *) USB_DIEP0CTL &= (unsigned int) (~ (BIT_0|BIT_1));
684
685         if ( enum_speed == USB_HIGH )
686         {
687                 EPn_config (EP_IN, USB_EP_TYPE_BULK, USB_EP_DIR_IN, BULK_MPS);
688                 EPn_config (EP_OUT, USB_EP_TYPE_BULK, USB_EP_DIR_OUT, BULK_MPS);
689                 EPn_config (EP_INTERRUPT, USB_EP_TYPE_INTERRUPT, USB_EP_DIR_IN, USB_PACKET_16);
690         }
691         else
692         {
693                 EPn_config (EP_IN, USB_EP_TYPE_BULK, USB_EP_DIR_IN, USB_PACKET_64);
694                 EPn_config (EP_OUT, USB_EP_TYPE_BULK, USB_EP_DIR_OUT, USB_PACKET_64);
695                 EPn_config (EP_INTERRUPT, USB_EP_TYPE_INTERRUPT, USB_EP_DIR_IN, USB_PACKET_16);
696         }
697         usb_EPActive (EP_INTERRUPT, USB_EP_DIR_IN);
698         Dcache_InvalRegion((unsigned int)s_setup_packet, sizeof(s_setup_packet));
699         EPO0_config (TRUE, s_setup_packet);
700
701         *(volatile uint32 *) USB_DCTL |= (unsigned int) BIT_8;
702         *(volatile uint32 *) USB_GINTSTS |= (unsigned int) BIT_13;
703 }
704
705 /*****************************************************************************/
706 //  Description:   out endpoint0 handler.
707 //  Global resource dependence:
708 //  Author:        jiayong.yang
709 //  Note:
710 /*****************************************************************************/
711
712 LOCAL void usb_EP0_out_handle (void)
713 {
714         volatile USB_DOEPINT_U *doepint_ptr = (USB_DOEPINT_U *) USB_DOEPINT (0);
715         USB_DOEPINT_U doepint;
716
717         doepint.dwValue = doepint_ptr->dwValue;
718         doepint_ptr->dwValue = doepint.dwValue;
719
720         if (doepint.mBits.timeout_condi)
721         {
722                 usb_setup_handle ();
723         }
724
725         if (doepint.mBits.transfer_com)
726         {
727                 uint8 size = 0;
728                 uint32 i;
729                 *(volatile uint32 *) USB_DOEP0CTL |= (unsigned int) BIT_27;
730
731                 for(i=0;i<50;i++);
732
733                 size = (*(volatile uint32 *)USB_DOEP0TSIZ) & 0x18;
734                 if(size != 0x18)
735                 {
736                         usb_setup_handle();
737                 }
738         }
739
740         Dcache_InvalRegion ((unsigned int) s_setup_packet, sizeof (s_setup_packet));    //0511
741         EPO0_config (TRUE, s_setup_packet);     //renable ep0 nd set packet count
742 }
743
744
745 /*****************************************************************************/
746 //  Description:   out endpoint handler.
747 //  Global resource dependence:
748 //  Author:        jiayong.yang
749 //  Note:
750 /*****************************************************************************/
751 LOCAL void usb_EP_out_handle (void)
752 {
753         volatile USB_DAINT_U *daint_ptr = (USB_DAINT_U *) USB_DAINT;
754         USB_DAINT_U daint;
755
756         daint.dwValue = daint_ptr->dwValue;         // disable EP out interrupt
757
758         if (daint.mBits.outepint_0)
759         {
760                 usb_EP0_out_handle();
761         }
762
763         //* (volatile uint32 *) USB_GINTMSK |= (unsigned int) BIT_19; // enable reset interrupt
764 }
765 /*****************************************************************************/
766 //  Description:   in endpoint handler.
767 //  Global resource dependence:
768 //  Author:        jiayong.yang
769 //  Note:
770 /*****************************************************************************/
771 LOCAL void usb_EP_in_handle (void)
772 {
773         volatile USB_DAINT_U *daint_ptr = (USB_DAINT_U *) USB_DAINT;
774         USB_DAINT_U daint;
775
776         daint.dwValue = daint_ptr->dwValue;
777
778         if (daint.mBits.inepint_0)
779         {
780                 volatile USB_DIEPINT_U *diepint_ptr = (USB_DIEPINT_U *) USB_DIEPINT (0);
781                 USB_DIEPINT_U diepint;
782                 diepint.dwValue = diepint_ptr->dwValue;
783                 diepint_ptr->dwValue = diepint.dwValue;
784         }
785 }
786
787 /*****************************************************************************/
788 //  Description:   usb interrupt handler.
789 //  Global resource dependence:
790 //  Author:        jiayong.yang
791 //  Note:
792 /*****************************************************************************/
793 static  void usb_handler (void)
794 {
795         volatile USB_INTSTS_U *usb_int_ptr = (USB_INTSTS_U *) USB_GINTSTS;
796         volatile USB_INTSTS_U  usb_int;
797         usb_int.dwValue = usb_int_ptr->dwValue;
798
799         // in endpoint interrupt
800         if (usb_int.mBits.iepint)
801                 usb_EP_in_handle();
802
803         // out endpoint interrupt
804         if (usb_int.mBits.oepint)
805                 usb_EP_out_handle();
806
807         // enumeration done interrupt
808         if (usb_int.mBits.enumdone)
809                 usb_enumeration_done();
810
811         // reset interrupt
812         if (usb_int.mBits.usbrst)
813         {
814                 if (g_cdc_status)
815                 {
816                         check_usb_reconnected = 1;
817                         g_cdc_status = 0;
818                 }
819                 usb_reset_handler();
820         }
821
822         if (usb_int.mBits.usbsusp)
823         {
824                 if(g_usb_status == USB_STARTED)
825                 {
826                         g_usb_status = USB_SUSPEND_AFTER_USB_MODE_START;
827                 }
828         }
829 }
830
831 /*****************************************************************************/
832 //  Description:   configure in endpoint ep_id to send message.
833 //  Global resource dependence:
834 //  Author:        jiayong.yang
835 //  Note:
836 /*****************************************************************************/
837 //extern int microusb_charger_connected(void);
838 extern u32 is_usb_cable(void);
839 static int32 USB_ReadEx_Internal(uint8 *pBuf,uint32 len)
840 {
841     volatile USB_DOEPINT_U *doepint_ptr = (USB_DOEPINT_U *) USB_DOEPINT (EP_OUT);
842     volatile USB_DOEPTSIZ_U *doeptsiz_ptr = (USB_DOEPTSIZ_U *) USB_DOEPTSIZ (EP_OUT);
843
844     if(recv_length == 0)
845     {
846         if(doepint_ptr->mBits.transfer_com == 1)
847         {
848             doepint_ptr->mBits.transfer_com = 1;
849         }
850
851         Dcache_CleanRegion((unsigned int)(&pBuf[0]),  MAX_RECV_LENGTH); 
852         usb_start_transfer (EP_OUT, USB_EP_DIR_OUT, 1, TRUE, (uint32 *) pBuf);
853         while(doepint_ptr->mBits.transfer_com==0)
854         {
855                 doepint_ptr = (USB_DOEPINT_U *) USB_DOEPINT (EP_OUT);
856                 usb_handler();
857                 if(check_usb_reconnected == 1 && g_cdc_status == 1)
858                 {
859                         usb_start_transfer (EP_OUT, USB_EP_DIR_OUT, 1, TRUE, (uint32 *) pBuf);
860                         check_usb_reconnected = 0;
861                 }
862         }
863         doepint_ptr->mBits.transfer_com = 1;
864         Dcache_InvalRegion((unsigned int)(&pBuf[0]),  MAX_RECV_LENGTH);//0511
865         recv_length = MAX_RECV_LENGTH - doeptsiz_ptr->mBits.transfer_size;
866     }
867
868     if(recv_length > len)
869     {
870         recv_length -= len;
871     }
872     else
873     {
874         len = recv_length;
875         recv_length = 0;
876     }
877
878     return len;
879 }
880
881 int USB_ReadEx(unsigned char *pBuf, int len)
882 {
883     int32 ret = len;
884     int32 read_len = 0;
885     if (len == 0)
886                 return 0;
887     do {
888         read_len = USB_ReadEx_Internal(pBuf,len);
889         if( read_len == 6 )
890         {
891             /* RDX exception handling when PC(intenet explorer) control RDX tool */
892             return 6;
893         }
894
895         if( g_usb_status == USB_DETACHED_AFTER_USB_MODE_START )
896         {
897             return 0;
898         }
899         pBuf += read_len;
900         len -= read_len;
901     } while (len > 0);
902
903     return ret;
904 }
905 /*****************************************************************************/
906 //  Description:   configure in endpoint ep_id to send message.
907 //  Global resource dependence:
908 //  Author:        jiayong.yang
909 //  Note:
910 /*****************************************************************************/
911 PUBLIC int32 USB_WriteEx(uint8 *pBuf,uint32 len)
912 {
913         volatile USB_DIEPINT_U *diepint_ptr = (USB_DIEPINT_U *) USB_DIEPINT (EP_IN);
914         int i;
915
916         int transfer_size = 0;
917         int transfered_size = 0;
918
919
920         do{
921                 if(len > MAX_RECV_LENGTH)
922                 {
923                         transfer_size = MAX_RECV_LENGTH;
924                 }
925                 else if((len % MAX_PACKET_SIZE)==0)
926                 {
927                         transfer_size = len - 32;
928                 }
929                 else
930                 {
931                         transfer_size = len;
932                 }
933
934                 len = len - transfer_size;
935
936                 for(i=0;i<transfer_size;i++)
937                 {
938                         usb_out_endpoint_buf[1][i] = pBuf[i+transfered_size];
939                 }
940
941                 if(diepint_ptr->mBits.transfer_com == 1)
942                 {
943                         diepint_ptr->mBits.transfer_com = 1;
944                 }
945                 usb_handler();
946                 usb_start_transfer ( (USB_EP_NUM_E) EP_IN, USB_EP_DIR_IN, transfer_size, TRUE, (uint32 *) usb_out_endpoint_buf[1]);
947
948                 do{
949                         diepint_ptr = (USB_DIEPINT_U *) USB_DIEPINT (EP_IN);
950                         usb_handler();
951                 }while(diepint_ptr->mBits.transfer_com==0);
952                 diepint_ptr->mBits.transfer_com = 1;
953                 transfered_size += transfer_size;
954         }while(len >0);
955         return transfered_size;
956 }
957
958 /*****************************************************************************/
959 //  Description:   initialize the usb core.
960 //  Global resource dependence:
961 //  Author:        jiayong.yang
962 //  Note:
963 /*****************************************************************************/
964 LOCAL void usb_core_init (void)
965 {
966         usb_debug("%s : enter \n", __func__);
967         uint32 time_out=0;
968
969         //Core soft reset, include hclk and phy clock
970         * (volatile uint32 *) USB_GRSTCTL |= BIT_0;
971         usb_debug("Inside usb_core_init \n");
972         do {
973                 uint32 reg_val = 0;
974                 time_out++;
975                 reg_val = * (volatile uint32 *) USB_GRSTCTL;
976
977                 if (reg_val & BIT_31)
978                 {
979                         break;
980                 }
981         } while (time_out<10);
982
983         * (volatile uint32 *) USB_DCTL &= ~ (BIT_1);  //soft disconnect
984         * (volatile uint32 *) USB_GOTGCTL |= BIT_6|BIT_7;//Bvalid en
985
986         // program global ahb configuration
987
988         * (volatile uint32 *) USB_GAHBCFG |= BIT_1|BIT_2|BIT_3;     // burst length  INCR16
989         * (volatile uint32 *) USB_GAHBCFG |= BIT_0;                 // global interrupt mask  , 0:mask 1:unmask
990
991         // program global usb configuration
992         * (volatile uint32 *) USB_GUSBCFG &= ~ (BIT_6);             // External FS PAY or Interal FS  Serial PHY Selection, UTMI+ or ULPI PHY
993         * (volatile uint32 *) USB_GUSBCFG &= ~ (BIT_17);            // External FS PAY or Interal FS  Serial PHY Selection, UTMI+ or ULPI PHY
994         * (volatile uint32 *) USB_GUSBCFG &= ~ (BIT_4);             // ULPI or UTMI+ selection bit,  UTMI+ interface
995         * (volatile uint32 *) USB_GUSBCFG |= BIT_3;                 // PHY Interface bit, 16 bit
996         * (volatile uint32 *) USB_GUSBCFG &= ~ (BIT_0|BIT_1|BIT_2); // HS/FS time out calibration,
997         * (volatile uint32 *) USB_GUSBCFG |= BIT_10|BIT_12;         // USB turnaround time, 16bit UTMI+
998         * (volatile uint32 *) USB_GUSBCFG |= BIT_30;         // force device mode
999
1000         * (volatile uint32 *) USB_GINTSTS = 0xffffffff;
1001
1002         * (volatile uint32 *) USB_GINTMSK =  0;                     // mask all first
1003
1004         // device init
1005         * (volatile uint32 *) USB_DCFG &= ~BIT_2;                   // out handshake
1006         * (volatile uint32 *) USB_DCFG &= ~ (BIT_11 | BIT_12);
1007
1008         * (volatile uint32 *) USB_GINTMSK |= BIT_12;                // usb reset int mask, 0:mask 1:unmask
1009         * (volatile uint32 *) USB_GINTMSK |= BIT_13;                // enumeration done int mask, 0:mask 1:unmask
1010         * (volatile uint32 *) USB_GINTMSK |= BIT_18;
1011         * (volatile uint32 *) USB_GINTMSK |= BIT_19;
1012
1013         * (volatile uint32 *) USB_GINTMSK &= ~BIT_4;                // DMA mode, must mask rx fifo level interrupt
1014
1015         * (volatile uint32 *) USB_DCFG &= ~BIT_0;  //configure HS mode.
1016         usb_debug("After USBC_CORE_INIT \n");
1017 }
1018 /*****************************************************************************/
1019 //  Description:   configure in endpoint ep_id to send message.
1020 //  Global resource dependence:
1021 //  Author:        jiayong.yang
1022 //  Note:
1023 /*****************************************************************************/
1024
1025 __align(64) unsigned char sprd_thor_setup_buf[512] = {0,};
1026
1027 static int s_usb_connected = 0;
1028
1029 extern int thor_handle(void);
1030
1031 void sprd_usb_thor_start(void)
1032 {
1033     g_usb_status = USB_STARTED;
1034
1035         do {
1036                 if (s_usb_connected == 0) {
1037                         USB_ReadEx_Internal(sprd_thor_setup_buf, sizeof(sprd_thor_setup_buf));
1038
1039                         if (g_usb_status == USB_DETACHED_AFTER_USB_MODE_START)
1040                                 return;
1041
1042                         if (!strncmp((char *)sprd_thor_setup_buf, "THOR", strlen("THOR")))
1043                         {
1044                                 usb_debug("- thor is connected!\n");
1045                                 USB_WriteEx((uint8 *)"ROHT", strlen("ROHT"));
1046                                 usb_debug("thor Setup Complete\n");
1047                                 s_usb_connected = 1;
1048                                 break;
1049                         } else{
1050                                 usb_debug("thor_seup error - Not receiving THOR\n");
1051                                 s_usb_connected = 0;
1052                         }
1053                 }
1054         } while(1);
1055
1056         thor_handle();
1057
1058         usb_debug("%s : exit \n", __func__);
1059         return;
1060 }
1061
1062 /* Enter point */
1063 void thor_USB_Init(void)
1064 {
1065         usb_debug("%s : enter\n", __func__);
1066
1067         usb_power_on();
1068         usb_core_init();
1069         usb_debug("usb_Core_init() is called\n");
1070
1071 USB_RESTART:
1072         while (!g_cdc_status)
1073                 usb_handler();
1074
1075         sprd_usb_thor_start();
1076
1077         if (g_usb_status == USB_DETACHED_AFTER_USB_MODE_START) {
1078                 g_usb_status = USB_BEFORE_USB_MODE;
1079                 g_cdc_status = 0;
1080                 goto USB_RESTART;
1081         }
1082 }
1083
1084 void USB_DeInit (void)
1085 {
1086         usb_power_off();
1087 }
1088
1089 /************************************************
1090  *
1091  * Register call back function for v3_protocol.
1092  *
1093  ************************************************/
1094 /* FIXME */
1095 //extern int usb_cb_register(u32 (*up)(void *, u32), u32 (*down)(void *, u32));
1096 #if 0
1097 void sprd_usb_cb_register(void)
1098 {
1099         usb_debug("%s : start \n", __func__);
1100         usb_cb_register(USB_WriteEx, USB_ReadEx);
1101 }
1102 #endif
1103
1104 void disconnect_usb(void)
1105 {
1106         s_usb_connected = 0;
1107 }
1108
1109 int thor_usb_is_connected(void)
1110 {
1111         return s_usb_connected;
1112 }