2 * Copyright (c) 2013 Qualcomm Atheros, Inc.
3 * Copyright (c) 2016 Oleksij Rempel <linux@rempel-privat.de>
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:
11 * * Redistributions of source code must retain the above copyright
12 * notice, this list of conditions and the following disclaimer.
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
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.
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.
38 /* shared patches for k2 and magpie */
49 #include "athos_api.h"
50 #include "usbfifo_api.h"
52 #include "adf_os_io.h"
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
59 extern USB_FIFO_CONFIG usbFifoConf;
60 extern Action eUsbCxFinishAction;
61 extern void _fw_usb_suspend_reboot();
63 typedef void (* USBFIFO_recv_command)(VBUF *cmd);
64 USBFIFO_recv_command m_origUsbfifoRecvCmd = NULL;
66 void _fw_usbfifo_recv_command(VBUF *buf)
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();
77 m_origUsbfifoRecvCmd(buf);
80 void _fw_usbfifo_init(USB_FIFO_CONFIG *pConfig)
82 m_origUsbfifoRecvCmd = pConfig->recv_command;
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;
90 void cold_reboot(void)
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) */
102 * support more than 64 bytes command on ep3
104 void usb_status_in_patch(void)
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;
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;
121 mUSB_STATUS_IN_INT_DISABLE();
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;
133 * controller supposed will take care of zero-length? */
135 reg_buf_len = buf_len;
140 for (count = 0; count < (reg_buf_len / 4); count++)
142 iowrite32_usb(ZM_EP3_DATA_OFFSET, *regaddr);
146 remainder = reg_buf_len % 4;
151 iowrite32_usb(ZM_CBUS_FIFO_SIZE_OFFSET, 0x7);
154 iowrite32_usb(ZM_CBUS_FIFO_SIZE_OFFSET, 0x3);
157 iowrite32_usb(ZM_CBUS_FIFO_SIZE_OFFSET, 0x1);
161 iowrite32_usb(ZM_EP3_DATA_OFFSET, *regaddr);
163 /* Restore CBus FIFO size to word size */
164 iowrite32_usb(ZM_CBUS_FIFO_SIZE_OFFSET, 0xF);
167 mUSB_EP3_XFER_DONE();
169 if (evntbuf != NULL && cmd_end) {
170 usbFifoConf.send_event_done(evntbuf);
176 * support more than 64 bytes command on ep4
178 void usb_reg_out_patch(void)
183 static volatile uint32_t *regaddr;
184 static uint16_t cmd_len;
186 BOOLEAN cmd_is_last = FALSE;
187 static BOOLEAN cmd_is_new = TRUE;
189 /* get the size of this transcation */
190 usbfifolen = ioread8_usb(ZM_EP4_BYTE_COUNT_LOW_OFFSET);
192 if (usbfifolen > USB_EP4_MAX_PKT_SIZE) {
193 A_PRINTF("EP4 FIFO Bug? Buffer is too big: %x\n", usbfifolen);
197 /* check is command is new */
200 buf = usbFifoConf.get_command_buf();
204 A_PRINTF("%s: Filed to get new buffer.\n", __func__);
208 /* copy free, assignment buffer of the address */
209 regaddr = (uint32_t *)buf->desc_list->buf_addr;
214 /* just in case, suppose should not happen */
218 /* if size is smaller, this is the last command!
219 * zero-length supposed should be set through 0x27/bit7->0x19/bit4, not here
221 if(usbfifolen < USB_EP4_MAX_PKT_SIZE)
224 /* accumulate the size */
225 cmd_len += usbfifolen;
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__);
233 /* round it to alignment */
235 usbfifolen = (usbfifolen >> 2) + 1;
237 usbfifolen = usbfifolen >> 2;
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);
247 /* if this is the last command, callback to HTC */
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;
256 usbFifoConf.recv_command(buf);
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);
270 /* mUSB_STATUS_IN_INT_ENABLE(); */
277 * - theoretically ep6 configured same way as ep1
278 * so, if there are some problems we should have it
280 * - do we really need support usb1.1?
282 extern uint16_t u8UsbConfigValue;
283 extern uint16_t u8UsbInterfaceValue;
284 extern uint16_t u8UsbInterfaceAlternateSetting;
285 extern SetupPacket ControlCmd;
286 extern void vUsbClrEPx(void);
288 #undef FS_C1_I0_A0_EP_NUMBER
289 #define FS_C1_I0_A0_EP_NUMBER 6
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
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)))
312 void vUSBFIFO_EP6Cfg_FS_patch(void)
314 #if (FS_C1_I0_A0_EP_NUMBER >= 6)
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);
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 ++)
325 mUsbFIFOConfig(i, (FS_C1_I0_A0_EP6_FIFO_CONFIG & (~BIT7)) );
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);
337 void vUsbFIFO_EPxCfg_FS_patch(void)
339 switch (u8UsbConfigValue)
341 #if (FS_CONFIGURATION_NUMBER >= 1)
342 /* Configuration 0X01 */
344 switch (u8UsbInterfaceValue)
346 #if (FS_C1_INTERFACE_NUMBER >= 1)
349 switch (u8UsbInterfaceAlternateSetting)
352 #if (FS_C1_I0_ALT_NUMBER >= 1)
353 /* AlternateSetting 0 */
358 /* patch up this ep6_fs config */
359 vUSBFIFO_EP6Cfg_FS_patch();
377 /* mCHECK_STACK(); */
380 BOOLEAN bSet_configuration_patch(void)
382 /* do some defaul configuration */
383 bSet_configuration();
385 /* overwrite defaul FIFO configuration for FullSpeed USB */
386 if ((mLOW_BYTE(mDEV_REQ_VALUE()) != 0) && !mUsbHighSpeedST())
387 vUsbFIFO_EPxCfg_FS_patch();
389 eUsbCxFinishAction = ACT_DONE;
393 extern BOOLEAN bStandardCommand(void);
395 BOOLEAN bStandardCommand_patch(void)
397 if (mDEV_REQ_REQ() == USB_SET_CONFIGURATION) {
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;
407 #if SYSTEM_MODULE_HP_EP5
408 MAGPIE_REG_USB_RX1_SWAP_DATA = 0x1;
411 #if SYSTEM_MODULE_HP_EP6
412 MAGPIE_REG_USB_RX2_SWAP_DATA = 0x1;
415 #endif /* ENABLE_SWAP_DATA_MODE */
418 return bStandardCommand();
422 * usb descriptor patch
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);
432 uint16_t ConfigDescriptorPatch[30];
433 uint16_t UsbDeviceDescriptorPatch[9];
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
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
445 BOOLEAN bGet_descriptor_patch(void)
447 if (mDEV_REQ_VALUE_HIGH() == 1)
449 uint8_t *p = (uint8_t *)u8UsbDeviceDescriptor;
451 /* Copy Usb Device Descriptor */
452 ath_hal_memcpy(UsbDeviceDescriptorPatch, p,
453 sizeof(UsbDeviceDescriptorPatch));
455 /* Change bcdDevice. we need it to detect if FW
457 UsbDeviceDescriptorPatch[BCD_DEVICE_OFFSET] =
458 BCD_DEVICE_FW_SIGNATURE;
460 pu8DescriptorEX = UsbDeviceDescriptorPatch;
461 u16TxRxCounter = mTABLE_LEN(u8UsbDeviceDescriptor[0]);
463 if (u16TxRxCounter > mDEV_REQ_LENGTH())
464 u16TxRxCounter = mDEV_REQ_LENGTH();
469 } else if (mDEV_REQ_VALUE_HIGH() == 2) {
470 uint8_t *p = (uint8_t *)u8ConfigDescriptorEX;
472 /* Copy ConfigDescriptor */
473 ath_hal_memcpy(ConfigDescriptorPatch, p,
474 sizeof(ConfigDescriptorPatch));
476 /* place holder for EPx patches */
478 if (mDEV_REQ_VALUE_LOW() == 0) {
479 /* configuration no: 0 */
480 pu8DescriptorEX = ConfigDescriptorPatch;
481 u16TxRxCounter = ConfigDescriptorPatch[1];
485 if (u16TxRxCounter > mDEV_REQ_LENGTH())
486 u16TxRxCounter = mDEV_REQ_LENGTH();
491 return bGet_descriptor();