carl9170: Update to latest upstream
[linux-libre-firmware.git] / ath9k_htc / target_firmware / magpie_fw_dev / target / hif / usb_api_main_patch.c
1 /*
2  * Copyright (c) 2013 Qualcomm Atheros, Inc.
3  * Copyright (c) 2016 Oleksij Rempel <linux@rempel-privat.de>
4  *
5  * All rights reserved.
6  *
7  * Redistribution and use in source and binary forms, with or without
8  * modification, are permitted (subject to the limitations in the
9  * disclaimer below) provided that the following conditions are met:
10  *
11  *  * Redistributions of source code must retain the above copyright
12  *    notice, this list of conditions and the following disclaimer.
13  *
14  *  * Redistributions in binary form must reproduce the above copyright
15  *    notice, this list of conditions and the following disclaimer in the
16  *    documentation and/or other materials provided with the
17  *    distribution.
18  *
19  *  * Neither the name of Qualcomm Atheros nor the names of its
20  *    contributors may be used to endorse or promote products derived
21  *    from this software without specific prior written permission.
22  *
23  * NO EXPRESS OR IMPLIED LICENSES TO ANY PARTY'S PATENT RIGHTS ARE
24  * GRANTED BY THIS LICENSE.  THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT
25  * HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED
26  * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
27  * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
28  * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
29  * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
30  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
31  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
32  * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
33  * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
34  * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
35  * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
36  */
37
38 /* shared patches for k2 and magpie */
39
40 #include <ah_osdep.h>
41 #include <rom.h>
42
43 #include "usb_defs.h"
44 #include "usb_type.h"
45 #include "usb_pre.h"
46 #include "usb_extr.h"
47 #include "usb_std.h"
48 #include "reg_defs.h"
49 #include "athos_api.h"
50 #include "usbfifo_api.h"
51
52 #include "adf_os_io.h"
53
54 #include "sys_cfg.h"
55
56 #define USB_EP4_MAX_PKT_SIZE bUSB_EP_MAX_PKT_SIZE_64
57 #define USB_EP3_MAX_PKT_SIZE bUSB_EP_MAX_PKT_SIZE_64
58
59 extern USB_FIFO_CONFIG usbFifoConf;
60 extern Action eUsbCxFinishAction;
61 extern void _fw_usb_suspend_reboot();
62
63 typedef void (* USBFIFO_recv_command)(VBUF *cmd);
64 USBFIFO_recv_command m_origUsbfifoRecvCmd = NULL;
65
66 void _fw_usbfifo_recv_command(VBUF *buf)
67 {
68         uint8_t *cmd_data;
69         uint32_t tmp;
70
71         cmd_data = (uint8_t *)(buf->desc_list->buf_addr +
72                                 buf->desc_list->data_offset);
73         tmp = *((uint32_t *)cmd_data);
74         if (tmp == 0xFFFFFFFF)
75                 _fw_usb_suspend_reboot();
76         else
77                 m_origUsbfifoRecvCmd(buf);
78 }
79
80 void _fw_usbfifo_init(USB_FIFO_CONFIG *pConfig)
81 {
82         m_origUsbfifoRecvCmd = pConfig->recv_command;
83
84         usbFifoConf.get_command_buf = pConfig->get_command_buf;
85         usbFifoConf.recv_command    = _fw_usbfifo_recv_command;
86         usbFifoConf.get_event_buf   = pConfig->get_event_buf;
87         usbFifoConf.send_event_done = pConfig->send_event_done;
88 }
89
90 void cold_reboot(void)
91 {
92         A_PRINTF("Cold reboot initiated.");
93 #if defined(PROJECT_MAGPIE)
94         iowrite32(WATCH_DOG_MAGIC_PATTERN_ADDR, 0);
95 #elif defined(PROJECT_K2)
96         iowrite32(MAGPIE_REG_RST_STATUS_ADDR, 0);
97 #endif /* #if defined(PROJECT_MAGPIE) */
98         A_USB_JUMP_BOOT();
99 }
100
101 /*
102  * support more than 64 bytes command on ep3
103  */
104 void usb_status_in_patch(void)
105 {
106         uint16_t count;
107         uint16_t remainder;
108         uint16_t reg_buf_len;
109         static uint16_t buf_len;
110         static VBUF *evntbuf = NULL;
111         static volatile uint32_t *regaddr;
112         static BOOLEAN cmd_is_new = TRUE;
113         BOOLEAN cmd_end = FALSE;
114
115         if (cmd_is_new) {
116                 evntbuf = usbFifoConf.get_event_buf();
117                 if (evntbuf != NULL) {
118                         regaddr = (uint32_t *)VBUF_GET_DATA_ADDR(evntbuf);
119                         buf_len = evntbuf->buf_length;
120                 } else {
121                         mUSB_STATUS_IN_INT_DISABLE();
122                         return;
123                 }
124
125                 cmd_is_new = FALSE;
126         }
127
128         if (buf_len > USB_EP3_MAX_PKT_SIZE) {
129                 reg_buf_len = USB_EP3_MAX_PKT_SIZE;
130                 buf_len -= USB_EP3_MAX_PKT_SIZE;
131         }
132         /* TODO: 64 bytes...
133          * controller supposed will take care of zero-length? */
134         else {
135                 reg_buf_len = buf_len;
136                 cmd_end = TRUE;
137         }
138
139         /* INT use EP3 */
140         for (count = 0; count < (reg_buf_len / 4); count++)
141         {
142                 iowrite32_usb(ZM_EP3_DATA_OFFSET, *regaddr);
143                 regaddr++;
144         }
145
146         remainder = reg_buf_len % 4;
147
148         if (remainder) {
149                 switch(remainder) {
150                 case 3:
151                         iowrite32_usb(ZM_CBUS_FIFO_SIZE_OFFSET, 0x7);
152                         break;
153                 case 2:
154                         iowrite32_usb(ZM_CBUS_FIFO_SIZE_OFFSET, 0x3);
155                         break;
156                 case 1:
157                         iowrite32_usb(ZM_CBUS_FIFO_SIZE_OFFSET, 0x1);
158                         break;
159                 }
160
161                 iowrite32_usb(ZM_EP3_DATA_OFFSET, *regaddr);
162
163                 /* Restore CBus FIFO size to word size */
164                 iowrite32_usb(ZM_CBUS_FIFO_SIZE_OFFSET, 0xF);
165         }
166
167         mUSB_EP3_XFER_DONE();
168
169         if (evntbuf != NULL && cmd_end) {
170                 usbFifoConf.send_event_done(evntbuf);
171                 cmd_is_new = TRUE;
172         }
173 }
174
175 /*
176  * support more than 64 bytes command on ep4
177  */
178 void usb_reg_out_patch(void)
179 {
180         uint16_t usbfifolen;
181         uint16_t ii;
182         uint32_t ep4_data;
183         static volatile uint32_t *regaddr;
184         static uint16_t cmd_len;
185         static VBUF *buf;
186         BOOLEAN cmd_is_last = FALSE;
187         static BOOLEAN cmd_is_new = TRUE;
188
189         /* get the size of this transcation */
190         usbfifolen = ioread8_usb(ZM_EP4_BYTE_COUNT_LOW_OFFSET);
191
192         if (usbfifolen > USB_EP4_MAX_PKT_SIZE) {
193                 A_PRINTF("EP4 FIFO Bug? Buffer is too big: %x\n", usbfifolen);
194                 cold_reboot();
195         }
196
197         /* check is command is new */
198         if(cmd_is_new) {
199
200                 buf = usbFifoConf.get_command_buf();
201                 cmd_len = 0;
202
203                 if(!buf) {
204                         A_PRINTF("%s: Filed to get new buffer.\n", __func__);
205                         goto err;
206                 }
207
208                 /* copy free, assignment buffer of the address */
209                 regaddr = (uint32_t *)buf->desc_list->buf_addr;
210
211                 cmd_is_new = FALSE;
212         }
213
214         /* just in case, suppose should not happen */
215         if(!buf)
216                 goto err;
217
218         /* if size is smaller, this is the last command!
219          * zero-length supposed should be set through 0x27/bit7->0x19/bit4, not here
220          */
221         if(usbfifolen < USB_EP4_MAX_PKT_SIZE)
222                 cmd_is_last = TRUE;
223
224         /* accumulate the size */
225         cmd_len += usbfifolen;
226
227         if (cmd_len > buf->desc_list->buf_size) {
228                 A_PRINTF("%s: Data length on EP4 FIFO is bigger as "
229                          "allocated buffer data! Drop it!\n", __func__);
230                 goto err;
231         }
232
233         /* round it to alignment */
234         if(usbfifolen % 4)
235                 usbfifolen = (usbfifolen >> 2) + 1;
236         else
237                 usbfifolen = usbfifolen >> 2;
238
239         /* retrieve the data from fifo */
240         for(ii = 0; ii < usbfifolen; ii++) {
241                 /* read fifo data out */
242                 ep4_data = ioread32_usb(ZM_EP4_DATA_OFFSET);
243                 *regaddr = ep4_data;
244                 regaddr++;
245         }
246
247         /* if this is the last command, callback to HTC */
248         if (cmd_is_last) {
249                 buf->desc_list->next_desc = NULL;
250                 buf->desc_list->data_offset = 0;
251                 buf->desc_list->data_size = cmd_len;
252                 buf->desc_list->control = 0;
253                 buf->next_buf = NULL;
254                 buf->buf_length = cmd_len;
255
256                 usbFifoConf.recv_command(buf);
257
258                 cmd_is_new = TRUE;
259         }
260
261         goto done;
262 err:
263         /* we might get no command buffer here?
264          * but if we return here, the ep4 fifo will be lock out,
265          * so that we still read them out but just drop it? */
266         for(ii = 0; ii < usbfifolen; ii++)
267                 ep4_data = ioread32_usb(ZM_EP4_DATA_OFFSET);
268
269 done:
270         /* mUSB_STATUS_IN_INT_ENABLE(); */
271         ;
272 }
273
274 /*
275  * usb1.1 ep6 fix
276  * TODO:
277  * - theoretically ep6 configured same way as ep1
278  * so, if there are some problems we should have it
279  * there too.
280  * - do we really need support usb1.1?
281  */
282 extern uint16_t         u8UsbConfigValue;
283 extern uint16_t         u8UsbInterfaceValue;
284 extern uint16_t         u8UsbInterfaceAlternateSetting;
285 extern SetupPacket      ControlCmd;
286 extern void             vUsbClrEPx(void);
287
288 #undef FS_C1_I0_A0_EP_NUMBER
289 #define FS_C1_I0_A0_EP_NUMBER 6
290
291 #define FS_C1_I0_A0_EP6_BLKSIZE    BLK512BYTE
292 #define FS_C1_I0_A0_EP6_BLKNO      DOUBLE_BLK
293 #define FS_C1_I0_A0_EP6_DIRECTION  DIRECTION_OUT
294 #define FS_C1_I0_A0_EP6_TYPE       TF_TYPE_BULK
295 #define FS_C1_I0_A0_EP6_MAX_PACKET 0x0040
296 #define FS_C1_I0_A0_EP6_bInterval  0
297
298 /* EP6 */
299 #define FS_C1_I0_A0_EP6_FIFO_START      \
300          (FS_C1_I0_A0_EP5_FIFO_START + FS_C1_I0_A0_EP5_FIFO_NO)
301 #define FS_C1_I0_A0_EP6_FIFO_NO         \
302          (FS_C1_I0_A0_EP6_BLKNO * FS_C1_I0_A0_EP6_BLKSIZE)
303 #define FS_C1_I0_A0_EP6_FIFO_CONFIG     \
304          (0x80 | ((FS_C1_I0_A0_EP6_BLKSIZE - 1) << 4) | \
305           ((FS_C1_I0_A0_EP6_BLKNO - 1) << 2) | FS_C1_I0_A0_EP6_TYPE)
306 #define FS_C1_I0_A0_EP6_FIFO_MAP        \
307          (((1 - FS_C1_I0_A0_EP6_DIRECTION) << 4) | EP6)
308 #define FS_C1_I0_A0_EP6_MAP             \
309          (FS_C1_I0_A0_EP6_FIFO_START | (FS_C1_I0_A0_EP6_FIFO_START << 4) | \
310           (MASK_F0 >> (4*FS_C1_I0_A0_EP6_DIRECTION)))
311
312 void vUSBFIFO_EP6Cfg_FS_patch(void)
313 {
314 #if (FS_C1_I0_A0_EP_NUMBER >= 6)
315         int i;
316
317         /* EP0X06 */
318         mUsbEPMap(EP6, FS_C1_I0_A0_EP6_MAP);
319         mUsbFIFOMap(FS_C1_I0_A0_EP6_FIFO_START, FS_C1_I0_A0_EP6_FIFO_MAP);
320         mUsbFIFOConfig(FS_C1_I0_A0_EP6_FIFO_START, FS_C1_I0_A0_EP6_FIFO_CONFIG);
321
322         for(i = FS_C1_I0_A0_EP6_FIFO_START + 1 ;
323             i < FS_C1_I0_A0_EP6_FIFO_START + FS_C1_I0_A0_EP6_FIFO_NO ; i ++)
324         {
325                 mUsbFIFOConfig(i, (FS_C1_I0_A0_EP6_FIFO_CONFIG & (~BIT7)) );
326         }
327
328         mUsbEPMxPtSzHigh(EP6, FS_C1_I0_A0_EP6_DIRECTION,
329                          (FS_C1_I0_A0_EP6_MAX_PACKET & 0x7ff));
330         mUsbEPMxPtSzLow(EP6, FS_C1_I0_A0_EP6_DIRECTION,
331                         (FS_C1_I0_A0_EP6_MAX_PACKET & 0x7ff));
332         mUsbEPinHighBandSet(EP6, FS_C1_I0_A0_EP6_DIRECTION,
333                             FS_C1_I0_A0_EP6_MAX_PACKET);
334 #endif
335 }
336
337 void vUsbFIFO_EPxCfg_FS_patch(void)
338 {
339         switch (u8UsbConfigValue)
340         {
341 #if (FS_CONFIGURATION_NUMBER >= 1)
342                 /* Configuration 0X01 */
343         case 0X01:
344                 switch (u8UsbInterfaceValue)
345                 {
346 #if (FS_C1_INTERFACE_NUMBER >= 1)
347                         /* Interface 0 */
348                 case 0:
349                         switch (u8UsbInterfaceAlternateSetting)
350                         {
351
352 #if (FS_C1_I0_ALT_NUMBER >= 1)
353                                 /* AlternateSetting 0 */
354                         case 0:
355
356                                 /* snapped.... */
357
358                                 /* patch up this ep6_fs config */
359                                 vUSBFIFO_EP6Cfg_FS_patch();
360
361                                 break;
362
363 #endif
364                         default:
365                                 break;
366                         }
367                         break;
368 #endif
369                 default:
370                         break;
371                 }
372                 break;
373 #endif
374         default:
375                 break;
376         }
377         /* mCHECK_STACK(); */
378 }
379
380 BOOLEAN bSet_configuration_patch(void)
381 {
382         /* do some defaul configuration */
383         bSet_configuration();
384
385         /* overwrite defaul FIFO configuration for FullSpeed USB */
386         if ((mLOW_BYTE(mDEV_REQ_VALUE()) != 0) && !mUsbHighSpeedST())
387                         vUsbFIFO_EPxCfg_FS_patch();
388
389         eUsbCxFinishAction = ACT_DONE;
390         return TRUE;
391 }
392
393 extern BOOLEAN bStandardCommand(void);
394
395 BOOLEAN bStandardCommand_patch(void)
396 {
397         if (mDEV_REQ_REQ() == USB_SET_CONFIGURATION) {
398                 A_USB_SET_CONFIG();
399
400 #if ENABLE_SWAP_DATA_MODE
401                 /* SWAP FUNCTION should be enabled while DMA engine
402                  * is not working, the best place to enable it
403                  * is before we trigger the DMA */
404                 MAGPIE_REG_USB_RX0_SWAP_DATA = 0x1;
405                 MAGPIE_REG_USB_TX0_SWAP_DATA = 0x1;
406
407 #if SYSTEM_MODULE_HP_EP5
408                 MAGPIE_REG_USB_RX1_SWAP_DATA = 0x1;
409 #endif
410
411 #if SYSTEM_MODULE_HP_EP6
412                 MAGPIE_REG_USB_RX2_SWAP_DATA = 0x1;
413 #endif
414
415 #endif /* ENABLE_SWAP_DATA_MODE */
416                 return TRUE;
417         } else
418                 return bStandardCommand();
419 }
420
421 /*
422  * usb descriptor patch
423  */
424
425 extern uint16_t         *u8ConfigDescriptorEX;
426 extern uint16_t         *pu8DescriptorEX;
427 extern uint16_t         u16TxRxCounter;
428 extern SetupPacket      ControlCmd;
429 extern uint16_t         *u8UsbDeviceDescriptor;
430 extern BOOLEAN          bGet_descriptor(void);
431
432 uint16_t ConfigDescriptorPatch[30];
433 uint16_t UsbDeviceDescriptorPatch[9];
434
435 #define BCD_DEVICE_OFFSET               6
436 #define BCD_DEVICE_FW_SIGNATURE         0xffff
437 #define VENDOR_ID_OFFSET                4
438 #define PRODUCT_ID_OFFSET               5
439
440 #define EP3_TRANSFER_TYPE_OFFSET        17
441 #define EP3_INT_INTERVAL                19
442 #define EP4_TRANSFER_TYPE_OFFSET        21
443 #define EP4_INT_INTERVAL                22
444
445 BOOLEAN bGet_descriptor_patch(void)
446 {
447         if (mDEV_REQ_VALUE_HIGH() == 1)
448         {
449                 uint8_t *p = (uint8_t *)u8UsbDeviceDescriptor;
450
451                 /* Copy Usb Device Descriptor */
452                 ath_hal_memcpy(UsbDeviceDescriptorPatch, p,
453                                 sizeof(UsbDeviceDescriptorPatch));
454
455                 /* Change bcdDevice. we need it to detect if FW
456                  * was uploaded. */
457                 UsbDeviceDescriptorPatch[BCD_DEVICE_OFFSET] =
458                         BCD_DEVICE_FW_SIGNATURE;
459
460                 pu8DescriptorEX = UsbDeviceDescriptorPatch;
461                 u16TxRxCounter = mTABLE_LEN(u8UsbDeviceDescriptor[0]);
462
463                 if (u16TxRxCounter > mDEV_REQ_LENGTH())
464                         u16TxRxCounter = mDEV_REQ_LENGTH();
465
466                 A_USB_EP0_TX_DATA();
467
468                 return TRUE;
469         } else if (mDEV_REQ_VALUE_HIGH() == 2) {
470                 uint8_t *p = (uint8_t *)u8ConfigDescriptorEX;
471
472                 /* Copy ConfigDescriptor */
473                 ath_hal_memcpy(ConfigDescriptorPatch, p,
474                                 sizeof(ConfigDescriptorPatch));
475
476                  /* place holder for EPx patches */
477
478                 if (mDEV_REQ_VALUE_LOW() == 0) {
479                         /* configuration no: 0 */
480                         pu8DescriptorEX = ConfigDescriptorPatch;
481                         u16TxRxCounter = ConfigDescriptorPatch[1];
482                 } else
483                         return FALSE;
484
485                 if (u16TxRxCounter > mDEV_REQ_LENGTH())
486                         u16TxRxCounter = mDEV_REQ_LENGTH();
487
488                 A_USB_EP0_TX_DATA();
489                 return TRUE;
490         } else
491                 return bGet_descriptor();
492 }
493