18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0 28c2ecf20Sopenharmony_ci/* 38c2ecf20Sopenharmony_ci * Driver for the NXP ISP1760 chip 48c2ecf20Sopenharmony_ci * 58c2ecf20Sopenharmony_ci * However, the code might contain some bugs. What doesn't work for sure is: 68c2ecf20Sopenharmony_ci * - ISO 78c2ecf20Sopenharmony_ci * - OTG 88c2ecf20Sopenharmony_ci e The interrupt line is configured as active low, level. 98c2ecf20Sopenharmony_ci * 108c2ecf20Sopenharmony_ci * (c) 2007 Sebastian Siewior <bigeasy@linutronix.de> 118c2ecf20Sopenharmony_ci * 128c2ecf20Sopenharmony_ci * (c) 2011 Arvid Brodin <arvid.brodin@enea.com> 138c2ecf20Sopenharmony_ci * 148c2ecf20Sopenharmony_ci */ 158c2ecf20Sopenharmony_ci#include <linux/gpio/consumer.h> 168c2ecf20Sopenharmony_ci#include <linux/module.h> 178c2ecf20Sopenharmony_ci#include <linux/kernel.h> 188c2ecf20Sopenharmony_ci#include <linux/slab.h> 198c2ecf20Sopenharmony_ci#include <linux/list.h> 208c2ecf20Sopenharmony_ci#include <linux/usb.h> 218c2ecf20Sopenharmony_ci#include <linux/usb/hcd.h> 228c2ecf20Sopenharmony_ci#include <linux/debugfs.h> 238c2ecf20Sopenharmony_ci#include <linux/uaccess.h> 248c2ecf20Sopenharmony_ci#include <linux/io.h> 258c2ecf20Sopenharmony_ci#include <linux/iopoll.h> 268c2ecf20Sopenharmony_ci#include <linux/mm.h> 278c2ecf20Sopenharmony_ci#include <linux/timer.h> 288c2ecf20Sopenharmony_ci#include <asm/unaligned.h> 298c2ecf20Sopenharmony_ci#include <asm/cacheflush.h> 308c2ecf20Sopenharmony_ci 318c2ecf20Sopenharmony_ci#include "isp1760-core.h" 328c2ecf20Sopenharmony_ci#include "isp1760-hcd.h" 338c2ecf20Sopenharmony_ci#include "isp1760-regs.h" 348c2ecf20Sopenharmony_ci 358c2ecf20Sopenharmony_cistatic struct kmem_cache *qtd_cachep; 368c2ecf20Sopenharmony_cistatic struct kmem_cache *qh_cachep; 378c2ecf20Sopenharmony_cistatic struct kmem_cache *urb_listitem_cachep; 388c2ecf20Sopenharmony_ci 398c2ecf20Sopenharmony_citypedef void (packet_enqueue)(struct usb_hcd *hcd, struct isp1760_qh *qh, 408c2ecf20Sopenharmony_ci struct isp1760_qtd *qtd); 418c2ecf20Sopenharmony_ci 428c2ecf20Sopenharmony_cistatic inline struct isp1760_hcd *hcd_to_priv(struct usb_hcd *hcd) 438c2ecf20Sopenharmony_ci{ 448c2ecf20Sopenharmony_ci return *(struct isp1760_hcd **)hcd->hcd_priv; 458c2ecf20Sopenharmony_ci} 468c2ecf20Sopenharmony_ci 478c2ecf20Sopenharmony_ci/* urb state*/ 488c2ecf20Sopenharmony_ci#define DELETE_URB (0x0008) 498c2ecf20Sopenharmony_ci#define NO_TRANSFER_ACTIVE (0xffffffff) 508c2ecf20Sopenharmony_ci 518c2ecf20Sopenharmony_ci/* Philips Proprietary Transfer Descriptor (PTD) */ 528c2ecf20Sopenharmony_citypedef __u32 __bitwise __dw; 538c2ecf20Sopenharmony_cistruct ptd { 548c2ecf20Sopenharmony_ci __dw dw0; 558c2ecf20Sopenharmony_ci __dw dw1; 568c2ecf20Sopenharmony_ci __dw dw2; 578c2ecf20Sopenharmony_ci __dw dw3; 588c2ecf20Sopenharmony_ci __dw dw4; 598c2ecf20Sopenharmony_ci __dw dw5; 608c2ecf20Sopenharmony_ci __dw dw6; 618c2ecf20Sopenharmony_ci __dw dw7; 628c2ecf20Sopenharmony_ci}; 638c2ecf20Sopenharmony_ci#define PTD_OFFSET 0x0400 648c2ecf20Sopenharmony_ci#define ISO_PTD_OFFSET 0x0400 658c2ecf20Sopenharmony_ci#define INT_PTD_OFFSET 0x0800 668c2ecf20Sopenharmony_ci#define ATL_PTD_OFFSET 0x0c00 678c2ecf20Sopenharmony_ci#define PAYLOAD_OFFSET 0x1000 688c2ecf20Sopenharmony_ci 698c2ecf20Sopenharmony_ci 708c2ecf20Sopenharmony_ci/* ATL */ 718c2ecf20Sopenharmony_ci/* DW0 */ 728c2ecf20Sopenharmony_ci#define DW0_VALID_BIT 1 738c2ecf20Sopenharmony_ci#define FROM_DW0_VALID(x) ((x) & 0x01) 748c2ecf20Sopenharmony_ci#define TO_DW0_LENGTH(x) (((u32) x) << 3) 758c2ecf20Sopenharmony_ci#define TO_DW0_MAXPACKET(x) (((u32) x) << 18) 768c2ecf20Sopenharmony_ci#define TO_DW0_MULTI(x) (((u32) x) << 29) 778c2ecf20Sopenharmony_ci#define TO_DW0_ENDPOINT(x) (((u32) x) << 31) 788c2ecf20Sopenharmony_ci/* DW1 */ 798c2ecf20Sopenharmony_ci#define TO_DW1_DEVICE_ADDR(x) (((u32) x) << 3) 808c2ecf20Sopenharmony_ci#define TO_DW1_PID_TOKEN(x) (((u32) x) << 10) 818c2ecf20Sopenharmony_ci#define DW1_TRANS_BULK ((u32) 2 << 12) 828c2ecf20Sopenharmony_ci#define DW1_TRANS_INT ((u32) 3 << 12) 838c2ecf20Sopenharmony_ci#define DW1_TRANS_SPLIT ((u32) 1 << 14) 848c2ecf20Sopenharmony_ci#define DW1_SE_USB_LOSPEED ((u32) 2 << 16) 858c2ecf20Sopenharmony_ci#define TO_DW1_PORT_NUM(x) (((u32) x) << 18) 868c2ecf20Sopenharmony_ci#define TO_DW1_HUB_NUM(x) (((u32) x) << 25) 878c2ecf20Sopenharmony_ci/* DW2 */ 888c2ecf20Sopenharmony_ci#define TO_DW2_DATA_START_ADDR(x) (((u32) x) << 8) 898c2ecf20Sopenharmony_ci#define TO_DW2_RL(x) ((x) << 25) 908c2ecf20Sopenharmony_ci#define FROM_DW2_RL(x) (((x) >> 25) & 0xf) 918c2ecf20Sopenharmony_ci/* DW3 */ 928c2ecf20Sopenharmony_ci#define FROM_DW3_NRBYTESTRANSFERRED(x) ((x) & 0x7fff) 938c2ecf20Sopenharmony_ci#define FROM_DW3_SCS_NRBYTESTRANSFERRED(x) ((x) & 0x07ff) 948c2ecf20Sopenharmony_ci#define TO_DW3_NAKCOUNT(x) ((x) << 19) 958c2ecf20Sopenharmony_ci#define FROM_DW3_NAKCOUNT(x) (((x) >> 19) & 0xf) 968c2ecf20Sopenharmony_ci#define TO_DW3_CERR(x) ((x) << 23) 978c2ecf20Sopenharmony_ci#define FROM_DW3_CERR(x) (((x) >> 23) & 0x3) 988c2ecf20Sopenharmony_ci#define TO_DW3_DATA_TOGGLE(x) ((x) << 25) 998c2ecf20Sopenharmony_ci#define FROM_DW3_DATA_TOGGLE(x) (((x) >> 25) & 0x1) 1008c2ecf20Sopenharmony_ci#define TO_DW3_PING(x) ((x) << 26) 1018c2ecf20Sopenharmony_ci#define FROM_DW3_PING(x) (((x) >> 26) & 0x1) 1028c2ecf20Sopenharmony_ci#define DW3_ERROR_BIT (1 << 28) 1038c2ecf20Sopenharmony_ci#define DW3_BABBLE_BIT (1 << 29) 1048c2ecf20Sopenharmony_ci#define DW3_HALT_BIT (1 << 30) 1058c2ecf20Sopenharmony_ci#define DW3_ACTIVE_BIT (1 << 31) 1068c2ecf20Sopenharmony_ci#define FROM_DW3_ACTIVE(x) (((x) >> 31) & 0x01) 1078c2ecf20Sopenharmony_ci 1088c2ecf20Sopenharmony_ci#define INT_UNDERRUN (1 << 2) 1098c2ecf20Sopenharmony_ci#define INT_BABBLE (1 << 1) 1108c2ecf20Sopenharmony_ci#define INT_EXACT (1 << 0) 1118c2ecf20Sopenharmony_ci 1128c2ecf20Sopenharmony_ci#define SETUP_PID (2) 1138c2ecf20Sopenharmony_ci#define IN_PID (1) 1148c2ecf20Sopenharmony_ci#define OUT_PID (0) 1158c2ecf20Sopenharmony_ci 1168c2ecf20Sopenharmony_ci/* Errata 1 */ 1178c2ecf20Sopenharmony_ci#define RL_COUNTER (0) 1188c2ecf20Sopenharmony_ci#define NAK_COUNTER (0) 1198c2ecf20Sopenharmony_ci#define ERR_COUNTER (2) 1208c2ecf20Sopenharmony_ci 1218c2ecf20Sopenharmony_cistruct isp1760_qtd { 1228c2ecf20Sopenharmony_ci u8 packet_type; 1238c2ecf20Sopenharmony_ci void *data_buffer; 1248c2ecf20Sopenharmony_ci u32 payload_addr; 1258c2ecf20Sopenharmony_ci 1268c2ecf20Sopenharmony_ci /* the rest is HCD-private */ 1278c2ecf20Sopenharmony_ci struct list_head qtd_list; 1288c2ecf20Sopenharmony_ci struct urb *urb; 1298c2ecf20Sopenharmony_ci size_t length; 1308c2ecf20Sopenharmony_ci size_t actual_length; 1318c2ecf20Sopenharmony_ci 1328c2ecf20Sopenharmony_ci /* QTD_ENQUEUED: waiting for transfer (inactive) */ 1338c2ecf20Sopenharmony_ci /* QTD_PAYLOAD_ALLOC: chip mem has been allocated for payload */ 1348c2ecf20Sopenharmony_ci /* QTD_XFER_STARTED: valid ptd has been written to isp176x - only 1358c2ecf20Sopenharmony_ci interrupt handler may touch this qtd! */ 1368c2ecf20Sopenharmony_ci /* QTD_XFER_COMPLETE: payload has been transferred successfully */ 1378c2ecf20Sopenharmony_ci /* QTD_RETIRE: transfer error/abort qtd */ 1388c2ecf20Sopenharmony_ci#define QTD_ENQUEUED 0 1398c2ecf20Sopenharmony_ci#define QTD_PAYLOAD_ALLOC 1 1408c2ecf20Sopenharmony_ci#define QTD_XFER_STARTED 2 1418c2ecf20Sopenharmony_ci#define QTD_XFER_COMPLETE 3 1428c2ecf20Sopenharmony_ci#define QTD_RETIRE 4 1438c2ecf20Sopenharmony_ci u32 status; 1448c2ecf20Sopenharmony_ci}; 1458c2ecf20Sopenharmony_ci 1468c2ecf20Sopenharmony_ci/* Queue head, one for each active endpoint */ 1478c2ecf20Sopenharmony_cistruct isp1760_qh { 1488c2ecf20Sopenharmony_ci struct list_head qh_list; 1498c2ecf20Sopenharmony_ci struct list_head qtd_list; 1508c2ecf20Sopenharmony_ci u32 toggle; 1518c2ecf20Sopenharmony_ci u32 ping; 1528c2ecf20Sopenharmony_ci int slot; 1538c2ecf20Sopenharmony_ci int tt_buffer_dirty; /* See USB2.0 spec section 11.17.5 */ 1548c2ecf20Sopenharmony_ci}; 1558c2ecf20Sopenharmony_ci 1568c2ecf20Sopenharmony_cistruct urb_listitem { 1578c2ecf20Sopenharmony_ci struct list_head urb_list; 1588c2ecf20Sopenharmony_ci struct urb *urb; 1598c2ecf20Sopenharmony_ci}; 1608c2ecf20Sopenharmony_ci 1618c2ecf20Sopenharmony_ci/* 1628c2ecf20Sopenharmony_ci * Access functions for isp176x registers (addresses 0..0x03FF). 1638c2ecf20Sopenharmony_ci */ 1648c2ecf20Sopenharmony_cistatic u32 reg_read32(void __iomem *base, u32 reg) 1658c2ecf20Sopenharmony_ci{ 1668c2ecf20Sopenharmony_ci return isp1760_read32(base, reg); 1678c2ecf20Sopenharmony_ci} 1688c2ecf20Sopenharmony_ci 1698c2ecf20Sopenharmony_cistatic void reg_write32(void __iomem *base, u32 reg, u32 val) 1708c2ecf20Sopenharmony_ci{ 1718c2ecf20Sopenharmony_ci isp1760_write32(base, reg, val); 1728c2ecf20Sopenharmony_ci} 1738c2ecf20Sopenharmony_ci 1748c2ecf20Sopenharmony_ci/* 1758c2ecf20Sopenharmony_ci * Access functions for isp176x memory (offset >= 0x0400). 1768c2ecf20Sopenharmony_ci * 1778c2ecf20Sopenharmony_ci * bank_reads8() reads memory locations prefetched by an earlier write to 1788c2ecf20Sopenharmony_ci * HC_MEMORY_REG (see isp176x datasheet). Unless you want to do fancy multi- 1798c2ecf20Sopenharmony_ci * bank optimizations, you should use the more generic mem_reads8() below. 1808c2ecf20Sopenharmony_ci * 1818c2ecf20Sopenharmony_ci * For access to ptd memory, use the specialized ptd_read() and ptd_write() 1828c2ecf20Sopenharmony_ci * below. 1838c2ecf20Sopenharmony_ci * 1848c2ecf20Sopenharmony_ci * These functions copy via MMIO data to/from the device. memcpy_{to|from}io() 1858c2ecf20Sopenharmony_ci * doesn't quite work because some people have to enforce 32-bit access 1868c2ecf20Sopenharmony_ci */ 1878c2ecf20Sopenharmony_cistatic void bank_reads8(void __iomem *src_base, u32 src_offset, u32 bank_addr, 1888c2ecf20Sopenharmony_ci __u32 *dst, u32 bytes) 1898c2ecf20Sopenharmony_ci{ 1908c2ecf20Sopenharmony_ci __u32 __iomem *src; 1918c2ecf20Sopenharmony_ci u32 val; 1928c2ecf20Sopenharmony_ci __u8 *src_byteptr; 1938c2ecf20Sopenharmony_ci __u8 *dst_byteptr; 1948c2ecf20Sopenharmony_ci 1958c2ecf20Sopenharmony_ci src = src_base + (bank_addr | src_offset); 1968c2ecf20Sopenharmony_ci 1978c2ecf20Sopenharmony_ci if (src_offset < PAYLOAD_OFFSET) { 1988c2ecf20Sopenharmony_ci while (bytes >= 4) { 1998c2ecf20Sopenharmony_ci *dst = le32_to_cpu(__raw_readl(src)); 2008c2ecf20Sopenharmony_ci bytes -= 4; 2018c2ecf20Sopenharmony_ci src++; 2028c2ecf20Sopenharmony_ci dst++; 2038c2ecf20Sopenharmony_ci } 2048c2ecf20Sopenharmony_ci } else { 2058c2ecf20Sopenharmony_ci while (bytes >= 4) { 2068c2ecf20Sopenharmony_ci *dst = __raw_readl(src); 2078c2ecf20Sopenharmony_ci bytes -= 4; 2088c2ecf20Sopenharmony_ci src++; 2098c2ecf20Sopenharmony_ci dst++; 2108c2ecf20Sopenharmony_ci } 2118c2ecf20Sopenharmony_ci } 2128c2ecf20Sopenharmony_ci 2138c2ecf20Sopenharmony_ci if (!bytes) 2148c2ecf20Sopenharmony_ci return; 2158c2ecf20Sopenharmony_ci 2168c2ecf20Sopenharmony_ci /* in case we have 3, 2 or 1 by left. The dst buffer may not be fully 2178c2ecf20Sopenharmony_ci * allocated. 2188c2ecf20Sopenharmony_ci */ 2198c2ecf20Sopenharmony_ci if (src_offset < PAYLOAD_OFFSET) 2208c2ecf20Sopenharmony_ci val = le32_to_cpu(__raw_readl(src)); 2218c2ecf20Sopenharmony_ci else 2228c2ecf20Sopenharmony_ci val = __raw_readl(src); 2238c2ecf20Sopenharmony_ci 2248c2ecf20Sopenharmony_ci dst_byteptr = (void *) dst; 2258c2ecf20Sopenharmony_ci src_byteptr = (void *) &val; 2268c2ecf20Sopenharmony_ci while (bytes > 0) { 2278c2ecf20Sopenharmony_ci *dst_byteptr = *src_byteptr; 2288c2ecf20Sopenharmony_ci dst_byteptr++; 2298c2ecf20Sopenharmony_ci src_byteptr++; 2308c2ecf20Sopenharmony_ci bytes--; 2318c2ecf20Sopenharmony_ci } 2328c2ecf20Sopenharmony_ci} 2338c2ecf20Sopenharmony_ci 2348c2ecf20Sopenharmony_cistatic void mem_reads8(void __iomem *src_base, u32 src_offset, void *dst, 2358c2ecf20Sopenharmony_ci u32 bytes) 2368c2ecf20Sopenharmony_ci{ 2378c2ecf20Sopenharmony_ci reg_write32(src_base, HC_MEMORY_REG, src_offset + ISP_BANK(0)); 2388c2ecf20Sopenharmony_ci ndelay(90); 2398c2ecf20Sopenharmony_ci bank_reads8(src_base, src_offset, ISP_BANK(0), dst, bytes); 2408c2ecf20Sopenharmony_ci} 2418c2ecf20Sopenharmony_ci 2428c2ecf20Sopenharmony_cistatic void mem_writes8(void __iomem *dst_base, u32 dst_offset, 2438c2ecf20Sopenharmony_ci __u32 const *src, u32 bytes) 2448c2ecf20Sopenharmony_ci{ 2458c2ecf20Sopenharmony_ci __u32 __iomem *dst; 2468c2ecf20Sopenharmony_ci 2478c2ecf20Sopenharmony_ci dst = dst_base + dst_offset; 2488c2ecf20Sopenharmony_ci 2498c2ecf20Sopenharmony_ci if (dst_offset < PAYLOAD_OFFSET) { 2508c2ecf20Sopenharmony_ci while (bytes >= 4) { 2518c2ecf20Sopenharmony_ci __raw_writel(cpu_to_le32(*src), dst); 2528c2ecf20Sopenharmony_ci bytes -= 4; 2538c2ecf20Sopenharmony_ci src++; 2548c2ecf20Sopenharmony_ci dst++; 2558c2ecf20Sopenharmony_ci } 2568c2ecf20Sopenharmony_ci } else { 2578c2ecf20Sopenharmony_ci while (bytes >= 4) { 2588c2ecf20Sopenharmony_ci __raw_writel(*src, dst); 2598c2ecf20Sopenharmony_ci bytes -= 4; 2608c2ecf20Sopenharmony_ci src++; 2618c2ecf20Sopenharmony_ci dst++; 2628c2ecf20Sopenharmony_ci } 2638c2ecf20Sopenharmony_ci } 2648c2ecf20Sopenharmony_ci 2658c2ecf20Sopenharmony_ci if (!bytes) 2668c2ecf20Sopenharmony_ci return; 2678c2ecf20Sopenharmony_ci /* in case we have 3, 2 or 1 bytes left. The buffer is allocated and the 2688c2ecf20Sopenharmony_ci * extra bytes should not be read by the HW. 2698c2ecf20Sopenharmony_ci */ 2708c2ecf20Sopenharmony_ci 2718c2ecf20Sopenharmony_ci if (dst_offset < PAYLOAD_OFFSET) 2728c2ecf20Sopenharmony_ci __raw_writel(cpu_to_le32(*src), dst); 2738c2ecf20Sopenharmony_ci else 2748c2ecf20Sopenharmony_ci __raw_writel(*src, dst); 2758c2ecf20Sopenharmony_ci} 2768c2ecf20Sopenharmony_ci 2778c2ecf20Sopenharmony_ci/* 2788c2ecf20Sopenharmony_ci * Read and write ptds. 'ptd_offset' should be one of ISO_PTD_OFFSET, 2798c2ecf20Sopenharmony_ci * INT_PTD_OFFSET, and ATL_PTD_OFFSET. 'slot' should be less than 32. 2808c2ecf20Sopenharmony_ci */ 2818c2ecf20Sopenharmony_cistatic void ptd_read(void __iomem *base, u32 ptd_offset, u32 slot, 2828c2ecf20Sopenharmony_ci struct ptd *ptd) 2838c2ecf20Sopenharmony_ci{ 2848c2ecf20Sopenharmony_ci reg_write32(base, HC_MEMORY_REG, 2858c2ecf20Sopenharmony_ci ISP_BANK(0) + ptd_offset + slot*sizeof(*ptd)); 2868c2ecf20Sopenharmony_ci ndelay(90); 2878c2ecf20Sopenharmony_ci bank_reads8(base, ptd_offset + slot*sizeof(*ptd), ISP_BANK(0), 2888c2ecf20Sopenharmony_ci (void *) ptd, sizeof(*ptd)); 2898c2ecf20Sopenharmony_ci} 2908c2ecf20Sopenharmony_ci 2918c2ecf20Sopenharmony_cistatic void ptd_write(void __iomem *base, u32 ptd_offset, u32 slot, 2928c2ecf20Sopenharmony_ci struct ptd *ptd) 2938c2ecf20Sopenharmony_ci{ 2948c2ecf20Sopenharmony_ci mem_writes8(base, ptd_offset + slot*sizeof(*ptd) + sizeof(ptd->dw0), 2958c2ecf20Sopenharmony_ci &ptd->dw1, 7*sizeof(ptd->dw1)); 2968c2ecf20Sopenharmony_ci /* Make sure dw0 gets written last (after other dw's and after payload) 2978c2ecf20Sopenharmony_ci since it contains the enable bit */ 2988c2ecf20Sopenharmony_ci wmb(); 2998c2ecf20Sopenharmony_ci mem_writes8(base, ptd_offset + slot*sizeof(*ptd), &ptd->dw0, 3008c2ecf20Sopenharmony_ci sizeof(ptd->dw0)); 3018c2ecf20Sopenharmony_ci} 3028c2ecf20Sopenharmony_ci 3038c2ecf20Sopenharmony_ci 3048c2ecf20Sopenharmony_ci/* memory management of the 60kb on the chip from 0x1000 to 0xffff */ 3058c2ecf20Sopenharmony_cistatic void init_memory(struct isp1760_hcd *priv) 3068c2ecf20Sopenharmony_ci{ 3078c2ecf20Sopenharmony_ci int i, curr; 3088c2ecf20Sopenharmony_ci u32 payload_addr; 3098c2ecf20Sopenharmony_ci 3108c2ecf20Sopenharmony_ci payload_addr = PAYLOAD_OFFSET; 3118c2ecf20Sopenharmony_ci for (i = 0; i < BLOCK_1_NUM; i++) { 3128c2ecf20Sopenharmony_ci priv->memory_pool[i].start = payload_addr; 3138c2ecf20Sopenharmony_ci priv->memory_pool[i].size = BLOCK_1_SIZE; 3148c2ecf20Sopenharmony_ci priv->memory_pool[i].free = 1; 3158c2ecf20Sopenharmony_ci payload_addr += priv->memory_pool[i].size; 3168c2ecf20Sopenharmony_ci } 3178c2ecf20Sopenharmony_ci 3188c2ecf20Sopenharmony_ci curr = i; 3198c2ecf20Sopenharmony_ci for (i = 0; i < BLOCK_2_NUM; i++) { 3208c2ecf20Sopenharmony_ci priv->memory_pool[curr + i].start = payload_addr; 3218c2ecf20Sopenharmony_ci priv->memory_pool[curr + i].size = BLOCK_2_SIZE; 3228c2ecf20Sopenharmony_ci priv->memory_pool[curr + i].free = 1; 3238c2ecf20Sopenharmony_ci payload_addr += priv->memory_pool[curr + i].size; 3248c2ecf20Sopenharmony_ci } 3258c2ecf20Sopenharmony_ci 3268c2ecf20Sopenharmony_ci curr = i; 3278c2ecf20Sopenharmony_ci for (i = 0; i < BLOCK_3_NUM; i++) { 3288c2ecf20Sopenharmony_ci priv->memory_pool[curr + i].start = payload_addr; 3298c2ecf20Sopenharmony_ci priv->memory_pool[curr + i].size = BLOCK_3_SIZE; 3308c2ecf20Sopenharmony_ci priv->memory_pool[curr + i].free = 1; 3318c2ecf20Sopenharmony_ci payload_addr += priv->memory_pool[curr + i].size; 3328c2ecf20Sopenharmony_ci } 3338c2ecf20Sopenharmony_ci 3348c2ecf20Sopenharmony_ci WARN_ON(payload_addr - priv->memory_pool[0].start > PAYLOAD_AREA_SIZE); 3358c2ecf20Sopenharmony_ci} 3368c2ecf20Sopenharmony_ci 3378c2ecf20Sopenharmony_cistatic void alloc_mem(struct usb_hcd *hcd, struct isp1760_qtd *qtd) 3388c2ecf20Sopenharmony_ci{ 3398c2ecf20Sopenharmony_ci struct isp1760_hcd *priv = hcd_to_priv(hcd); 3408c2ecf20Sopenharmony_ci int i; 3418c2ecf20Sopenharmony_ci 3428c2ecf20Sopenharmony_ci WARN_ON(qtd->payload_addr); 3438c2ecf20Sopenharmony_ci 3448c2ecf20Sopenharmony_ci if (!qtd->length) 3458c2ecf20Sopenharmony_ci return; 3468c2ecf20Sopenharmony_ci 3478c2ecf20Sopenharmony_ci for (i = 0; i < BLOCKS; i++) { 3488c2ecf20Sopenharmony_ci if (priv->memory_pool[i].size >= qtd->length && 3498c2ecf20Sopenharmony_ci priv->memory_pool[i].free) { 3508c2ecf20Sopenharmony_ci priv->memory_pool[i].free = 0; 3518c2ecf20Sopenharmony_ci qtd->payload_addr = priv->memory_pool[i].start; 3528c2ecf20Sopenharmony_ci return; 3538c2ecf20Sopenharmony_ci } 3548c2ecf20Sopenharmony_ci } 3558c2ecf20Sopenharmony_ci} 3568c2ecf20Sopenharmony_ci 3578c2ecf20Sopenharmony_cistatic void free_mem(struct usb_hcd *hcd, struct isp1760_qtd *qtd) 3588c2ecf20Sopenharmony_ci{ 3598c2ecf20Sopenharmony_ci struct isp1760_hcd *priv = hcd_to_priv(hcd); 3608c2ecf20Sopenharmony_ci int i; 3618c2ecf20Sopenharmony_ci 3628c2ecf20Sopenharmony_ci if (!qtd->payload_addr) 3638c2ecf20Sopenharmony_ci return; 3648c2ecf20Sopenharmony_ci 3658c2ecf20Sopenharmony_ci for (i = 0; i < BLOCKS; i++) { 3668c2ecf20Sopenharmony_ci if (priv->memory_pool[i].start == qtd->payload_addr) { 3678c2ecf20Sopenharmony_ci WARN_ON(priv->memory_pool[i].free); 3688c2ecf20Sopenharmony_ci priv->memory_pool[i].free = 1; 3698c2ecf20Sopenharmony_ci qtd->payload_addr = 0; 3708c2ecf20Sopenharmony_ci return; 3718c2ecf20Sopenharmony_ci } 3728c2ecf20Sopenharmony_ci } 3738c2ecf20Sopenharmony_ci 3748c2ecf20Sopenharmony_ci dev_err(hcd->self.controller, "%s: Invalid pointer: %08x\n", 3758c2ecf20Sopenharmony_ci __func__, qtd->payload_addr); 3768c2ecf20Sopenharmony_ci WARN_ON(1); 3778c2ecf20Sopenharmony_ci qtd->payload_addr = 0; 3788c2ecf20Sopenharmony_ci} 3798c2ecf20Sopenharmony_ci 3808c2ecf20Sopenharmony_cistatic int handshake(struct usb_hcd *hcd, u32 reg, 3818c2ecf20Sopenharmony_ci u32 mask, u32 done, int usec) 3828c2ecf20Sopenharmony_ci{ 3838c2ecf20Sopenharmony_ci u32 result; 3848c2ecf20Sopenharmony_ci int ret; 3858c2ecf20Sopenharmony_ci 3868c2ecf20Sopenharmony_ci ret = readl_poll_timeout_atomic(hcd->regs + reg, result, 3878c2ecf20Sopenharmony_ci ((result & mask) == done || 3888c2ecf20Sopenharmony_ci result == U32_MAX), 1, usec); 3898c2ecf20Sopenharmony_ci if (result == U32_MAX) 3908c2ecf20Sopenharmony_ci return -ENODEV; 3918c2ecf20Sopenharmony_ci 3928c2ecf20Sopenharmony_ci return ret; 3938c2ecf20Sopenharmony_ci} 3948c2ecf20Sopenharmony_ci 3958c2ecf20Sopenharmony_ci/* reset a non-running (STS_HALT == 1) controller */ 3968c2ecf20Sopenharmony_cistatic int ehci_reset(struct usb_hcd *hcd) 3978c2ecf20Sopenharmony_ci{ 3988c2ecf20Sopenharmony_ci struct isp1760_hcd *priv = hcd_to_priv(hcd); 3998c2ecf20Sopenharmony_ci 4008c2ecf20Sopenharmony_ci u32 command = reg_read32(hcd->regs, HC_USBCMD); 4018c2ecf20Sopenharmony_ci 4028c2ecf20Sopenharmony_ci command |= CMD_RESET; 4038c2ecf20Sopenharmony_ci reg_write32(hcd->regs, HC_USBCMD, command); 4048c2ecf20Sopenharmony_ci hcd->state = HC_STATE_HALT; 4058c2ecf20Sopenharmony_ci priv->next_statechange = jiffies; 4068c2ecf20Sopenharmony_ci 4078c2ecf20Sopenharmony_ci return handshake(hcd, HC_USBCMD, CMD_RESET, 0, 250 * 1000); 4088c2ecf20Sopenharmony_ci} 4098c2ecf20Sopenharmony_ci 4108c2ecf20Sopenharmony_cistatic struct isp1760_qh *qh_alloc(gfp_t flags) 4118c2ecf20Sopenharmony_ci{ 4128c2ecf20Sopenharmony_ci struct isp1760_qh *qh; 4138c2ecf20Sopenharmony_ci 4148c2ecf20Sopenharmony_ci qh = kmem_cache_zalloc(qh_cachep, flags); 4158c2ecf20Sopenharmony_ci if (!qh) 4168c2ecf20Sopenharmony_ci return NULL; 4178c2ecf20Sopenharmony_ci 4188c2ecf20Sopenharmony_ci INIT_LIST_HEAD(&qh->qh_list); 4198c2ecf20Sopenharmony_ci INIT_LIST_HEAD(&qh->qtd_list); 4208c2ecf20Sopenharmony_ci qh->slot = -1; 4218c2ecf20Sopenharmony_ci 4228c2ecf20Sopenharmony_ci return qh; 4238c2ecf20Sopenharmony_ci} 4248c2ecf20Sopenharmony_ci 4258c2ecf20Sopenharmony_cistatic void qh_free(struct isp1760_qh *qh) 4268c2ecf20Sopenharmony_ci{ 4278c2ecf20Sopenharmony_ci WARN_ON(!list_empty(&qh->qtd_list)); 4288c2ecf20Sopenharmony_ci WARN_ON(qh->slot > -1); 4298c2ecf20Sopenharmony_ci kmem_cache_free(qh_cachep, qh); 4308c2ecf20Sopenharmony_ci} 4318c2ecf20Sopenharmony_ci 4328c2ecf20Sopenharmony_ci/* one-time init, only for memory state */ 4338c2ecf20Sopenharmony_cistatic int priv_init(struct usb_hcd *hcd) 4348c2ecf20Sopenharmony_ci{ 4358c2ecf20Sopenharmony_ci struct isp1760_hcd *priv = hcd_to_priv(hcd); 4368c2ecf20Sopenharmony_ci u32 hcc_params; 4378c2ecf20Sopenharmony_ci int i; 4388c2ecf20Sopenharmony_ci 4398c2ecf20Sopenharmony_ci spin_lock_init(&priv->lock); 4408c2ecf20Sopenharmony_ci 4418c2ecf20Sopenharmony_ci for (i = 0; i < QH_END; i++) 4428c2ecf20Sopenharmony_ci INIT_LIST_HEAD(&priv->qh_list[i]); 4438c2ecf20Sopenharmony_ci 4448c2ecf20Sopenharmony_ci /* 4458c2ecf20Sopenharmony_ci * hw default: 1K periodic list heads, one per frame. 4468c2ecf20Sopenharmony_ci * periodic_size can shrink by USBCMD update if hcc_params allows. 4478c2ecf20Sopenharmony_ci */ 4488c2ecf20Sopenharmony_ci priv->periodic_size = DEFAULT_I_TDPS; 4498c2ecf20Sopenharmony_ci 4508c2ecf20Sopenharmony_ci /* controllers may cache some of the periodic schedule ... */ 4518c2ecf20Sopenharmony_ci hcc_params = reg_read32(hcd->regs, HC_HCCPARAMS); 4528c2ecf20Sopenharmony_ci /* full frame cache */ 4538c2ecf20Sopenharmony_ci if (HCC_ISOC_CACHE(hcc_params)) 4548c2ecf20Sopenharmony_ci priv->i_thresh = 8; 4558c2ecf20Sopenharmony_ci else /* N microframes cached */ 4568c2ecf20Sopenharmony_ci priv->i_thresh = 2 + HCC_ISOC_THRES(hcc_params); 4578c2ecf20Sopenharmony_ci 4588c2ecf20Sopenharmony_ci return 0; 4598c2ecf20Sopenharmony_ci} 4608c2ecf20Sopenharmony_ci 4618c2ecf20Sopenharmony_cistatic int isp1760_hc_setup(struct usb_hcd *hcd) 4628c2ecf20Sopenharmony_ci{ 4638c2ecf20Sopenharmony_ci struct isp1760_hcd *priv = hcd_to_priv(hcd); 4648c2ecf20Sopenharmony_ci int result; 4658c2ecf20Sopenharmony_ci u32 scratch, hwmode; 4668c2ecf20Sopenharmony_ci 4678c2ecf20Sopenharmony_ci reg_write32(hcd->regs, HC_SCRATCH_REG, 0xdeadbabe); 4688c2ecf20Sopenharmony_ci /* Change bus pattern */ 4698c2ecf20Sopenharmony_ci scratch = reg_read32(hcd->regs, HC_CHIP_ID_REG); 4708c2ecf20Sopenharmony_ci scratch = reg_read32(hcd->regs, HC_SCRATCH_REG); 4718c2ecf20Sopenharmony_ci if (scratch != 0xdeadbabe) { 4728c2ecf20Sopenharmony_ci dev_err(hcd->self.controller, "Scratch test failed.\n"); 4738c2ecf20Sopenharmony_ci return -ENODEV; 4748c2ecf20Sopenharmony_ci } 4758c2ecf20Sopenharmony_ci 4768c2ecf20Sopenharmony_ci /* 4778c2ecf20Sopenharmony_ci * The RESET_HC bit in the SW_RESET register is supposed to reset the 4788c2ecf20Sopenharmony_ci * host controller without touching the CPU interface registers, but at 4798c2ecf20Sopenharmony_ci * least on the ISP1761 it seems to behave as the RESET_ALL bit and 4808c2ecf20Sopenharmony_ci * reset the whole device. We thus can't use it here, so let's reset 4818c2ecf20Sopenharmony_ci * the host controller through the EHCI USB Command register. The device 4828c2ecf20Sopenharmony_ci * has been reset in core code anyway, so this shouldn't matter. 4838c2ecf20Sopenharmony_ci */ 4848c2ecf20Sopenharmony_ci reg_write32(hcd->regs, HC_BUFFER_STATUS_REG, 0); 4858c2ecf20Sopenharmony_ci reg_write32(hcd->regs, HC_ATL_PTD_SKIPMAP_REG, NO_TRANSFER_ACTIVE); 4868c2ecf20Sopenharmony_ci reg_write32(hcd->regs, HC_INT_PTD_SKIPMAP_REG, NO_TRANSFER_ACTIVE); 4878c2ecf20Sopenharmony_ci reg_write32(hcd->regs, HC_ISO_PTD_SKIPMAP_REG, NO_TRANSFER_ACTIVE); 4888c2ecf20Sopenharmony_ci 4898c2ecf20Sopenharmony_ci result = ehci_reset(hcd); 4908c2ecf20Sopenharmony_ci if (result) 4918c2ecf20Sopenharmony_ci return result; 4928c2ecf20Sopenharmony_ci 4938c2ecf20Sopenharmony_ci /* Step 11 passed */ 4948c2ecf20Sopenharmony_ci 4958c2ecf20Sopenharmony_ci /* ATL reset */ 4968c2ecf20Sopenharmony_ci hwmode = reg_read32(hcd->regs, HC_HW_MODE_CTRL) & ~ALL_ATX_RESET; 4978c2ecf20Sopenharmony_ci reg_write32(hcd->regs, HC_HW_MODE_CTRL, hwmode | ALL_ATX_RESET); 4988c2ecf20Sopenharmony_ci mdelay(10); 4998c2ecf20Sopenharmony_ci reg_write32(hcd->regs, HC_HW_MODE_CTRL, hwmode); 5008c2ecf20Sopenharmony_ci 5018c2ecf20Sopenharmony_ci reg_write32(hcd->regs, HC_INTERRUPT_ENABLE, INTERRUPT_ENABLE_MASK); 5028c2ecf20Sopenharmony_ci 5038c2ecf20Sopenharmony_ci priv->hcs_params = reg_read32(hcd->regs, HC_HCSPARAMS); 5048c2ecf20Sopenharmony_ci 5058c2ecf20Sopenharmony_ci return priv_init(hcd); 5068c2ecf20Sopenharmony_ci} 5078c2ecf20Sopenharmony_ci 5088c2ecf20Sopenharmony_cistatic u32 base_to_chip(u32 base) 5098c2ecf20Sopenharmony_ci{ 5108c2ecf20Sopenharmony_ci return ((base - 0x400) >> 3); 5118c2ecf20Sopenharmony_ci} 5128c2ecf20Sopenharmony_ci 5138c2ecf20Sopenharmony_cistatic int last_qtd_of_urb(struct isp1760_qtd *qtd, struct isp1760_qh *qh) 5148c2ecf20Sopenharmony_ci{ 5158c2ecf20Sopenharmony_ci struct urb *urb; 5168c2ecf20Sopenharmony_ci 5178c2ecf20Sopenharmony_ci if (list_is_last(&qtd->qtd_list, &qh->qtd_list)) 5188c2ecf20Sopenharmony_ci return 1; 5198c2ecf20Sopenharmony_ci 5208c2ecf20Sopenharmony_ci urb = qtd->urb; 5218c2ecf20Sopenharmony_ci qtd = list_entry(qtd->qtd_list.next, typeof(*qtd), qtd_list); 5228c2ecf20Sopenharmony_ci return (qtd->urb != urb); 5238c2ecf20Sopenharmony_ci} 5248c2ecf20Sopenharmony_ci 5258c2ecf20Sopenharmony_ci/* magic numbers that can affect system performance */ 5268c2ecf20Sopenharmony_ci#define EHCI_TUNE_CERR 3 /* 0-3 qtd retries; 0 == don't stop */ 5278c2ecf20Sopenharmony_ci#define EHCI_TUNE_RL_HS 4 /* nak throttle; see 4.9 */ 5288c2ecf20Sopenharmony_ci#define EHCI_TUNE_RL_TT 0 5298c2ecf20Sopenharmony_ci#define EHCI_TUNE_MULT_HS 1 /* 1-3 transactions/uframe; 4.10.3 */ 5308c2ecf20Sopenharmony_ci#define EHCI_TUNE_MULT_TT 1 5318c2ecf20Sopenharmony_ci#define EHCI_TUNE_FLS 2 /* (small) 256 frame schedule */ 5328c2ecf20Sopenharmony_ci 5338c2ecf20Sopenharmony_cistatic void create_ptd_atl(struct isp1760_qh *qh, 5348c2ecf20Sopenharmony_ci struct isp1760_qtd *qtd, struct ptd *ptd) 5358c2ecf20Sopenharmony_ci{ 5368c2ecf20Sopenharmony_ci u32 maxpacket; 5378c2ecf20Sopenharmony_ci u32 multi; 5388c2ecf20Sopenharmony_ci u32 rl = RL_COUNTER; 5398c2ecf20Sopenharmony_ci u32 nak = NAK_COUNTER; 5408c2ecf20Sopenharmony_ci 5418c2ecf20Sopenharmony_ci memset(ptd, 0, sizeof(*ptd)); 5428c2ecf20Sopenharmony_ci 5438c2ecf20Sopenharmony_ci /* according to 3.6.2, max packet len can not be > 0x400 */ 5448c2ecf20Sopenharmony_ci maxpacket = usb_maxpacket(qtd->urb->dev, qtd->urb->pipe, 5458c2ecf20Sopenharmony_ci usb_pipeout(qtd->urb->pipe)); 5468c2ecf20Sopenharmony_ci multi = 1 + ((maxpacket >> 11) & 0x3); 5478c2ecf20Sopenharmony_ci maxpacket &= 0x7ff; 5488c2ecf20Sopenharmony_ci 5498c2ecf20Sopenharmony_ci /* DW0 */ 5508c2ecf20Sopenharmony_ci ptd->dw0 = DW0_VALID_BIT; 5518c2ecf20Sopenharmony_ci ptd->dw0 |= TO_DW0_LENGTH(qtd->length); 5528c2ecf20Sopenharmony_ci ptd->dw0 |= TO_DW0_MAXPACKET(maxpacket); 5538c2ecf20Sopenharmony_ci ptd->dw0 |= TO_DW0_ENDPOINT(usb_pipeendpoint(qtd->urb->pipe)); 5548c2ecf20Sopenharmony_ci 5558c2ecf20Sopenharmony_ci /* DW1 */ 5568c2ecf20Sopenharmony_ci ptd->dw1 = usb_pipeendpoint(qtd->urb->pipe) >> 1; 5578c2ecf20Sopenharmony_ci ptd->dw1 |= TO_DW1_DEVICE_ADDR(usb_pipedevice(qtd->urb->pipe)); 5588c2ecf20Sopenharmony_ci ptd->dw1 |= TO_DW1_PID_TOKEN(qtd->packet_type); 5598c2ecf20Sopenharmony_ci 5608c2ecf20Sopenharmony_ci if (usb_pipebulk(qtd->urb->pipe)) 5618c2ecf20Sopenharmony_ci ptd->dw1 |= DW1_TRANS_BULK; 5628c2ecf20Sopenharmony_ci else if (usb_pipeint(qtd->urb->pipe)) 5638c2ecf20Sopenharmony_ci ptd->dw1 |= DW1_TRANS_INT; 5648c2ecf20Sopenharmony_ci 5658c2ecf20Sopenharmony_ci if (qtd->urb->dev->speed != USB_SPEED_HIGH) { 5668c2ecf20Sopenharmony_ci /* split transaction */ 5678c2ecf20Sopenharmony_ci 5688c2ecf20Sopenharmony_ci ptd->dw1 |= DW1_TRANS_SPLIT; 5698c2ecf20Sopenharmony_ci if (qtd->urb->dev->speed == USB_SPEED_LOW) 5708c2ecf20Sopenharmony_ci ptd->dw1 |= DW1_SE_USB_LOSPEED; 5718c2ecf20Sopenharmony_ci 5728c2ecf20Sopenharmony_ci ptd->dw1 |= TO_DW1_PORT_NUM(qtd->urb->dev->ttport); 5738c2ecf20Sopenharmony_ci ptd->dw1 |= TO_DW1_HUB_NUM(qtd->urb->dev->tt->hub->devnum); 5748c2ecf20Sopenharmony_ci 5758c2ecf20Sopenharmony_ci /* SE bit for Split INT transfers */ 5768c2ecf20Sopenharmony_ci if (usb_pipeint(qtd->urb->pipe) && 5778c2ecf20Sopenharmony_ci (qtd->urb->dev->speed == USB_SPEED_LOW)) 5788c2ecf20Sopenharmony_ci ptd->dw1 |= 2 << 16; 5798c2ecf20Sopenharmony_ci 5808c2ecf20Sopenharmony_ci rl = 0; 5818c2ecf20Sopenharmony_ci nak = 0; 5828c2ecf20Sopenharmony_ci } else { 5838c2ecf20Sopenharmony_ci ptd->dw0 |= TO_DW0_MULTI(multi); 5848c2ecf20Sopenharmony_ci if (usb_pipecontrol(qtd->urb->pipe) || 5858c2ecf20Sopenharmony_ci usb_pipebulk(qtd->urb->pipe)) 5868c2ecf20Sopenharmony_ci ptd->dw3 |= TO_DW3_PING(qh->ping); 5878c2ecf20Sopenharmony_ci } 5888c2ecf20Sopenharmony_ci /* DW2 */ 5898c2ecf20Sopenharmony_ci ptd->dw2 = 0; 5908c2ecf20Sopenharmony_ci ptd->dw2 |= TO_DW2_DATA_START_ADDR(base_to_chip(qtd->payload_addr)); 5918c2ecf20Sopenharmony_ci ptd->dw2 |= TO_DW2_RL(rl); 5928c2ecf20Sopenharmony_ci 5938c2ecf20Sopenharmony_ci /* DW3 */ 5948c2ecf20Sopenharmony_ci ptd->dw3 |= TO_DW3_NAKCOUNT(nak); 5958c2ecf20Sopenharmony_ci ptd->dw3 |= TO_DW3_DATA_TOGGLE(qh->toggle); 5968c2ecf20Sopenharmony_ci if (usb_pipecontrol(qtd->urb->pipe)) { 5978c2ecf20Sopenharmony_ci if (qtd->data_buffer == qtd->urb->setup_packet) 5988c2ecf20Sopenharmony_ci ptd->dw3 &= ~TO_DW3_DATA_TOGGLE(1); 5998c2ecf20Sopenharmony_ci else if (last_qtd_of_urb(qtd, qh)) 6008c2ecf20Sopenharmony_ci ptd->dw3 |= TO_DW3_DATA_TOGGLE(1); 6018c2ecf20Sopenharmony_ci } 6028c2ecf20Sopenharmony_ci 6038c2ecf20Sopenharmony_ci ptd->dw3 |= DW3_ACTIVE_BIT; 6048c2ecf20Sopenharmony_ci /* Cerr */ 6058c2ecf20Sopenharmony_ci ptd->dw3 |= TO_DW3_CERR(ERR_COUNTER); 6068c2ecf20Sopenharmony_ci} 6078c2ecf20Sopenharmony_ci 6088c2ecf20Sopenharmony_cistatic void transform_add_int(struct isp1760_qh *qh, 6098c2ecf20Sopenharmony_ci struct isp1760_qtd *qtd, struct ptd *ptd) 6108c2ecf20Sopenharmony_ci{ 6118c2ecf20Sopenharmony_ci u32 usof; 6128c2ecf20Sopenharmony_ci u32 period; 6138c2ecf20Sopenharmony_ci 6148c2ecf20Sopenharmony_ci /* 6158c2ecf20Sopenharmony_ci * Most of this is guessing. ISP1761 datasheet is quite unclear, and 6168c2ecf20Sopenharmony_ci * the algorithm from the original Philips driver code, which was 6178c2ecf20Sopenharmony_ci * pretty much used in this driver before as well, is quite horrendous 6188c2ecf20Sopenharmony_ci * and, i believe, incorrect. The code below follows the datasheet and 6198c2ecf20Sopenharmony_ci * USB2.0 spec as far as I can tell, and plug/unplug seems to be much 6208c2ecf20Sopenharmony_ci * more reliable this way (fingers crossed...). 6218c2ecf20Sopenharmony_ci */ 6228c2ecf20Sopenharmony_ci 6238c2ecf20Sopenharmony_ci if (qtd->urb->dev->speed == USB_SPEED_HIGH) { 6248c2ecf20Sopenharmony_ci /* urb->interval is in units of microframes (1/8 ms) */ 6258c2ecf20Sopenharmony_ci period = qtd->urb->interval >> 3; 6268c2ecf20Sopenharmony_ci 6278c2ecf20Sopenharmony_ci if (qtd->urb->interval > 4) 6288c2ecf20Sopenharmony_ci usof = 0x01; /* One bit set => 6298c2ecf20Sopenharmony_ci interval 1 ms * uFrame-match */ 6308c2ecf20Sopenharmony_ci else if (qtd->urb->interval > 2) 6318c2ecf20Sopenharmony_ci usof = 0x22; /* Two bits set => interval 1/2 ms */ 6328c2ecf20Sopenharmony_ci else if (qtd->urb->interval > 1) 6338c2ecf20Sopenharmony_ci usof = 0x55; /* Four bits set => interval 1/4 ms */ 6348c2ecf20Sopenharmony_ci else 6358c2ecf20Sopenharmony_ci usof = 0xff; /* All bits set => interval 1/8 ms */ 6368c2ecf20Sopenharmony_ci } else { 6378c2ecf20Sopenharmony_ci /* urb->interval is in units of frames (1 ms) */ 6388c2ecf20Sopenharmony_ci period = qtd->urb->interval; 6398c2ecf20Sopenharmony_ci usof = 0x0f; /* Execute Start Split on any of the 6408c2ecf20Sopenharmony_ci four first uFrames */ 6418c2ecf20Sopenharmony_ci 6428c2ecf20Sopenharmony_ci /* 6438c2ecf20Sopenharmony_ci * First 8 bits in dw5 is uSCS and "specifies which uSOF the 6448c2ecf20Sopenharmony_ci * complete split needs to be sent. Valid only for IN." Also, 6458c2ecf20Sopenharmony_ci * "All bits can be set to one for every transfer." (p 82, 6468c2ecf20Sopenharmony_ci * ISP1761 data sheet.) 0x1c is from Philips driver. Where did 6478c2ecf20Sopenharmony_ci * that number come from? 0xff seems to work fine... 6488c2ecf20Sopenharmony_ci */ 6498c2ecf20Sopenharmony_ci /* ptd->dw5 = 0x1c; */ 6508c2ecf20Sopenharmony_ci ptd->dw5 = 0xff; /* Execute Complete Split on any uFrame */ 6518c2ecf20Sopenharmony_ci } 6528c2ecf20Sopenharmony_ci 6538c2ecf20Sopenharmony_ci period = period >> 1;/* Ensure equal or shorter period than requested */ 6548c2ecf20Sopenharmony_ci period &= 0xf8; /* Mask off too large values and lowest unused 3 bits */ 6558c2ecf20Sopenharmony_ci 6568c2ecf20Sopenharmony_ci ptd->dw2 |= period; 6578c2ecf20Sopenharmony_ci ptd->dw4 = usof; 6588c2ecf20Sopenharmony_ci} 6598c2ecf20Sopenharmony_ci 6608c2ecf20Sopenharmony_cistatic void create_ptd_int(struct isp1760_qh *qh, 6618c2ecf20Sopenharmony_ci struct isp1760_qtd *qtd, struct ptd *ptd) 6628c2ecf20Sopenharmony_ci{ 6638c2ecf20Sopenharmony_ci create_ptd_atl(qh, qtd, ptd); 6648c2ecf20Sopenharmony_ci transform_add_int(qh, qtd, ptd); 6658c2ecf20Sopenharmony_ci} 6668c2ecf20Sopenharmony_ci 6678c2ecf20Sopenharmony_cistatic void isp1760_urb_done(struct usb_hcd *hcd, struct urb *urb) 6688c2ecf20Sopenharmony_ci__releases(priv->lock) 6698c2ecf20Sopenharmony_ci__acquires(priv->lock) 6708c2ecf20Sopenharmony_ci{ 6718c2ecf20Sopenharmony_ci struct isp1760_hcd *priv = hcd_to_priv(hcd); 6728c2ecf20Sopenharmony_ci 6738c2ecf20Sopenharmony_ci if (!urb->unlinked) { 6748c2ecf20Sopenharmony_ci if (urb->status == -EINPROGRESS) 6758c2ecf20Sopenharmony_ci urb->status = 0; 6768c2ecf20Sopenharmony_ci } 6778c2ecf20Sopenharmony_ci 6788c2ecf20Sopenharmony_ci if (usb_pipein(urb->pipe) && usb_pipetype(urb->pipe) != PIPE_CONTROL) { 6798c2ecf20Sopenharmony_ci void *ptr; 6808c2ecf20Sopenharmony_ci for (ptr = urb->transfer_buffer; 6818c2ecf20Sopenharmony_ci ptr < urb->transfer_buffer + urb->transfer_buffer_length; 6828c2ecf20Sopenharmony_ci ptr += PAGE_SIZE) 6838c2ecf20Sopenharmony_ci flush_dcache_page(virt_to_page(ptr)); 6848c2ecf20Sopenharmony_ci } 6858c2ecf20Sopenharmony_ci 6868c2ecf20Sopenharmony_ci /* complete() can reenter this HCD */ 6878c2ecf20Sopenharmony_ci usb_hcd_unlink_urb_from_ep(hcd, urb); 6888c2ecf20Sopenharmony_ci spin_unlock(&priv->lock); 6898c2ecf20Sopenharmony_ci usb_hcd_giveback_urb(hcd, urb, urb->status); 6908c2ecf20Sopenharmony_ci spin_lock(&priv->lock); 6918c2ecf20Sopenharmony_ci} 6928c2ecf20Sopenharmony_ci 6938c2ecf20Sopenharmony_cistatic struct isp1760_qtd *qtd_alloc(gfp_t flags, struct urb *urb, 6948c2ecf20Sopenharmony_ci u8 packet_type) 6958c2ecf20Sopenharmony_ci{ 6968c2ecf20Sopenharmony_ci struct isp1760_qtd *qtd; 6978c2ecf20Sopenharmony_ci 6988c2ecf20Sopenharmony_ci qtd = kmem_cache_zalloc(qtd_cachep, flags); 6998c2ecf20Sopenharmony_ci if (!qtd) 7008c2ecf20Sopenharmony_ci return NULL; 7018c2ecf20Sopenharmony_ci 7028c2ecf20Sopenharmony_ci INIT_LIST_HEAD(&qtd->qtd_list); 7038c2ecf20Sopenharmony_ci qtd->urb = urb; 7048c2ecf20Sopenharmony_ci qtd->packet_type = packet_type; 7058c2ecf20Sopenharmony_ci qtd->status = QTD_ENQUEUED; 7068c2ecf20Sopenharmony_ci qtd->actual_length = 0; 7078c2ecf20Sopenharmony_ci 7088c2ecf20Sopenharmony_ci return qtd; 7098c2ecf20Sopenharmony_ci} 7108c2ecf20Sopenharmony_ci 7118c2ecf20Sopenharmony_cistatic void qtd_free(struct isp1760_qtd *qtd) 7128c2ecf20Sopenharmony_ci{ 7138c2ecf20Sopenharmony_ci WARN_ON(qtd->payload_addr); 7148c2ecf20Sopenharmony_ci kmem_cache_free(qtd_cachep, qtd); 7158c2ecf20Sopenharmony_ci} 7168c2ecf20Sopenharmony_ci 7178c2ecf20Sopenharmony_cistatic void start_bus_transfer(struct usb_hcd *hcd, u32 ptd_offset, int slot, 7188c2ecf20Sopenharmony_ci struct isp1760_slotinfo *slots, 7198c2ecf20Sopenharmony_ci struct isp1760_qtd *qtd, struct isp1760_qh *qh, 7208c2ecf20Sopenharmony_ci struct ptd *ptd) 7218c2ecf20Sopenharmony_ci{ 7228c2ecf20Sopenharmony_ci struct isp1760_hcd *priv = hcd_to_priv(hcd); 7238c2ecf20Sopenharmony_ci int skip_map; 7248c2ecf20Sopenharmony_ci 7258c2ecf20Sopenharmony_ci WARN_ON((slot < 0) || (slot > 31)); 7268c2ecf20Sopenharmony_ci WARN_ON(qtd->length && !qtd->payload_addr); 7278c2ecf20Sopenharmony_ci WARN_ON(slots[slot].qtd); 7288c2ecf20Sopenharmony_ci WARN_ON(slots[slot].qh); 7298c2ecf20Sopenharmony_ci WARN_ON(qtd->status != QTD_PAYLOAD_ALLOC); 7308c2ecf20Sopenharmony_ci 7318c2ecf20Sopenharmony_ci /* Make sure done map has not triggered from some unlinked transfer */ 7328c2ecf20Sopenharmony_ci if (ptd_offset == ATL_PTD_OFFSET) { 7338c2ecf20Sopenharmony_ci priv->atl_done_map |= reg_read32(hcd->regs, 7348c2ecf20Sopenharmony_ci HC_ATL_PTD_DONEMAP_REG); 7358c2ecf20Sopenharmony_ci priv->atl_done_map &= ~(1 << slot); 7368c2ecf20Sopenharmony_ci } else { 7378c2ecf20Sopenharmony_ci priv->int_done_map |= reg_read32(hcd->regs, 7388c2ecf20Sopenharmony_ci HC_INT_PTD_DONEMAP_REG); 7398c2ecf20Sopenharmony_ci priv->int_done_map &= ~(1 << slot); 7408c2ecf20Sopenharmony_ci } 7418c2ecf20Sopenharmony_ci 7428c2ecf20Sopenharmony_ci qh->slot = slot; 7438c2ecf20Sopenharmony_ci qtd->status = QTD_XFER_STARTED; 7448c2ecf20Sopenharmony_ci slots[slot].timestamp = jiffies; 7458c2ecf20Sopenharmony_ci slots[slot].qtd = qtd; 7468c2ecf20Sopenharmony_ci slots[slot].qh = qh; 7478c2ecf20Sopenharmony_ci ptd_write(hcd->regs, ptd_offset, slot, ptd); 7488c2ecf20Sopenharmony_ci 7498c2ecf20Sopenharmony_ci if (ptd_offset == ATL_PTD_OFFSET) { 7508c2ecf20Sopenharmony_ci skip_map = reg_read32(hcd->regs, HC_ATL_PTD_SKIPMAP_REG); 7518c2ecf20Sopenharmony_ci skip_map &= ~(1 << qh->slot); 7528c2ecf20Sopenharmony_ci reg_write32(hcd->regs, HC_ATL_PTD_SKIPMAP_REG, skip_map); 7538c2ecf20Sopenharmony_ci } else { 7548c2ecf20Sopenharmony_ci skip_map = reg_read32(hcd->regs, HC_INT_PTD_SKIPMAP_REG); 7558c2ecf20Sopenharmony_ci skip_map &= ~(1 << qh->slot); 7568c2ecf20Sopenharmony_ci reg_write32(hcd->regs, HC_INT_PTD_SKIPMAP_REG, skip_map); 7578c2ecf20Sopenharmony_ci } 7588c2ecf20Sopenharmony_ci} 7598c2ecf20Sopenharmony_ci 7608c2ecf20Sopenharmony_cistatic int is_short_bulk(struct isp1760_qtd *qtd) 7618c2ecf20Sopenharmony_ci{ 7628c2ecf20Sopenharmony_ci return (usb_pipebulk(qtd->urb->pipe) && 7638c2ecf20Sopenharmony_ci (qtd->actual_length < qtd->length)); 7648c2ecf20Sopenharmony_ci} 7658c2ecf20Sopenharmony_ci 7668c2ecf20Sopenharmony_cistatic void collect_qtds(struct usb_hcd *hcd, struct isp1760_qh *qh, 7678c2ecf20Sopenharmony_ci struct list_head *urb_list) 7688c2ecf20Sopenharmony_ci{ 7698c2ecf20Sopenharmony_ci int last_qtd; 7708c2ecf20Sopenharmony_ci struct isp1760_qtd *qtd, *qtd_next; 7718c2ecf20Sopenharmony_ci struct urb_listitem *urb_listitem; 7728c2ecf20Sopenharmony_ci 7738c2ecf20Sopenharmony_ci list_for_each_entry_safe(qtd, qtd_next, &qh->qtd_list, qtd_list) { 7748c2ecf20Sopenharmony_ci if (qtd->status < QTD_XFER_COMPLETE) 7758c2ecf20Sopenharmony_ci break; 7768c2ecf20Sopenharmony_ci 7778c2ecf20Sopenharmony_ci last_qtd = last_qtd_of_urb(qtd, qh); 7788c2ecf20Sopenharmony_ci 7798c2ecf20Sopenharmony_ci if ((!last_qtd) && (qtd->status == QTD_RETIRE)) 7808c2ecf20Sopenharmony_ci qtd_next->status = QTD_RETIRE; 7818c2ecf20Sopenharmony_ci 7828c2ecf20Sopenharmony_ci if (qtd->status == QTD_XFER_COMPLETE) { 7838c2ecf20Sopenharmony_ci if (qtd->actual_length) { 7848c2ecf20Sopenharmony_ci switch (qtd->packet_type) { 7858c2ecf20Sopenharmony_ci case IN_PID: 7868c2ecf20Sopenharmony_ci mem_reads8(hcd->regs, qtd->payload_addr, 7878c2ecf20Sopenharmony_ci qtd->data_buffer, 7888c2ecf20Sopenharmony_ci qtd->actual_length); 7898c2ecf20Sopenharmony_ci fallthrough; 7908c2ecf20Sopenharmony_ci case OUT_PID: 7918c2ecf20Sopenharmony_ci qtd->urb->actual_length += 7928c2ecf20Sopenharmony_ci qtd->actual_length; 7938c2ecf20Sopenharmony_ci fallthrough; 7948c2ecf20Sopenharmony_ci case SETUP_PID: 7958c2ecf20Sopenharmony_ci break; 7968c2ecf20Sopenharmony_ci } 7978c2ecf20Sopenharmony_ci } 7988c2ecf20Sopenharmony_ci 7998c2ecf20Sopenharmony_ci if (is_short_bulk(qtd)) { 8008c2ecf20Sopenharmony_ci if (qtd->urb->transfer_flags & URB_SHORT_NOT_OK) 8018c2ecf20Sopenharmony_ci qtd->urb->status = -EREMOTEIO; 8028c2ecf20Sopenharmony_ci if (!last_qtd) 8038c2ecf20Sopenharmony_ci qtd_next->status = QTD_RETIRE; 8048c2ecf20Sopenharmony_ci } 8058c2ecf20Sopenharmony_ci } 8068c2ecf20Sopenharmony_ci 8078c2ecf20Sopenharmony_ci if (qtd->payload_addr) 8088c2ecf20Sopenharmony_ci free_mem(hcd, qtd); 8098c2ecf20Sopenharmony_ci 8108c2ecf20Sopenharmony_ci if (last_qtd) { 8118c2ecf20Sopenharmony_ci if ((qtd->status == QTD_RETIRE) && 8128c2ecf20Sopenharmony_ci (qtd->urb->status == -EINPROGRESS)) 8138c2ecf20Sopenharmony_ci qtd->urb->status = -EPIPE; 8148c2ecf20Sopenharmony_ci /* Defer calling of urb_done() since it releases lock */ 8158c2ecf20Sopenharmony_ci urb_listitem = kmem_cache_zalloc(urb_listitem_cachep, 8168c2ecf20Sopenharmony_ci GFP_ATOMIC); 8178c2ecf20Sopenharmony_ci if (unlikely(!urb_listitem)) 8188c2ecf20Sopenharmony_ci break; /* Try again on next call */ 8198c2ecf20Sopenharmony_ci urb_listitem->urb = qtd->urb; 8208c2ecf20Sopenharmony_ci list_add_tail(&urb_listitem->urb_list, urb_list); 8218c2ecf20Sopenharmony_ci } 8228c2ecf20Sopenharmony_ci 8238c2ecf20Sopenharmony_ci list_del(&qtd->qtd_list); 8248c2ecf20Sopenharmony_ci qtd_free(qtd); 8258c2ecf20Sopenharmony_ci } 8268c2ecf20Sopenharmony_ci} 8278c2ecf20Sopenharmony_ci 8288c2ecf20Sopenharmony_ci#define ENQUEUE_DEPTH 2 8298c2ecf20Sopenharmony_cistatic void enqueue_qtds(struct usb_hcd *hcd, struct isp1760_qh *qh) 8308c2ecf20Sopenharmony_ci{ 8318c2ecf20Sopenharmony_ci struct isp1760_hcd *priv = hcd_to_priv(hcd); 8328c2ecf20Sopenharmony_ci int ptd_offset; 8338c2ecf20Sopenharmony_ci struct isp1760_slotinfo *slots; 8348c2ecf20Sopenharmony_ci int curr_slot, free_slot; 8358c2ecf20Sopenharmony_ci int n; 8368c2ecf20Sopenharmony_ci struct ptd ptd; 8378c2ecf20Sopenharmony_ci struct isp1760_qtd *qtd; 8388c2ecf20Sopenharmony_ci 8398c2ecf20Sopenharmony_ci if (unlikely(list_empty(&qh->qtd_list))) { 8408c2ecf20Sopenharmony_ci WARN_ON(1); 8418c2ecf20Sopenharmony_ci return; 8428c2ecf20Sopenharmony_ci } 8438c2ecf20Sopenharmony_ci 8448c2ecf20Sopenharmony_ci /* Make sure this endpoint's TT buffer is clean before queueing ptds */ 8458c2ecf20Sopenharmony_ci if (qh->tt_buffer_dirty) 8468c2ecf20Sopenharmony_ci return; 8478c2ecf20Sopenharmony_ci 8488c2ecf20Sopenharmony_ci if (usb_pipeint(list_entry(qh->qtd_list.next, struct isp1760_qtd, 8498c2ecf20Sopenharmony_ci qtd_list)->urb->pipe)) { 8508c2ecf20Sopenharmony_ci ptd_offset = INT_PTD_OFFSET; 8518c2ecf20Sopenharmony_ci slots = priv->int_slots; 8528c2ecf20Sopenharmony_ci } else { 8538c2ecf20Sopenharmony_ci ptd_offset = ATL_PTD_OFFSET; 8548c2ecf20Sopenharmony_ci slots = priv->atl_slots; 8558c2ecf20Sopenharmony_ci } 8568c2ecf20Sopenharmony_ci 8578c2ecf20Sopenharmony_ci free_slot = -1; 8588c2ecf20Sopenharmony_ci for (curr_slot = 0; curr_slot < 32; curr_slot++) { 8598c2ecf20Sopenharmony_ci if ((free_slot == -1) && (slots[curr_slot].qtd == NULL)) 8608c2ecf20Sopenharmony_ci free_slot = curr_slot; 8618c2ecf20Sopenharmony_ci if (slots[curr_slot].qh == qh) 8628c2ecf20Sopenharmony_ci break; 8638c2ecf20Sopenharmony_ci } 8648c2ecf20Sopenharmony_ci 8658c2ecf20Sopenharmony_ci n = 0; 8668c2ecf20Sopenharmony_ci list_for_each_entry(qtd, &qh->qtd_list, qtd_list) { 8678c2ecf20Sopenharmony_ci if (qtd->status == QTD_ENQUEUED) { 8688c2ecf20Sopenharmony_ci WARN_ON(qtd->payload_addr); 8698c2ecf20Sopenharmony_ci alloc_mem(hcd, qtd); 8708c2ecf20Sopenharmony_ci if ((qtd->length) && (!qtd->payload_addr)) 8718c2ecf20Sopenharmony_ci break; 8728c2ecf20Sopenharmony_ci 8738c2ecf20Sopenharmony_ci if ((qtd->length) && 8748c2ecf20Sopenharmony_ci ((qtd->packet_type == SETUP_PID) || 8758c2ecf20Sopenharmony_ci (qtd->packet_type == OUT_PID))) { 8768c2ecf20Sopenharmony_ci mem_writes8(hcd->regs, qtd->payload_addr, 8778c2ecf20Sopenharmony_ci qtd->data_buffer, qtd->length); 8788c2ecf20Sopenharmony_ci } 8798c2ecf20Sopenharmony_ci 8808c2ecf20Sopenharmony_ci qtd->status = QTD_PAYLOAD_ALLOC; 8818c2ecf20Sopenharmony_ci } 8828c2ecf20Sopenharmony_ci 8838c2ecf20Sopenharmony_ci if (qtd->status == QTD_PAYLOAD_ALLOC) { 8848c2ecf20Sopenharmony_ci/* 8858c2ecf20Sopenharmony_ci if ((curr_slot > 31) && (free_slot == -1)) 8868c2ecf20Sopenharmony_ci dev_dbg(hcd->self.controller, "%s: No slot " 8878c2ecf20Sopenharmony_ci "available for transfer\n", __func__); 8888c2ecf20Sopenharmony_ci*/ 8898c2ecf20Sopenharmony_ci /* Start xfer for this endpoint if not already done */ 8908c2ecf20Sopenharmony_ci if ((curr_slot > 31) && (free_slot > -1)) { 8918c2ecf20Sopenharmony_ci if (usb_pipeint(qtd->urb->pipe)) 8928c2ecf20Sopenharmony_ci create_ptd_int(qh, qtd, &ptd); 8938c2ecf20Sopenharmony_ci else 8948c2ecf20Sopenharmony_ci create_ptd_atl(qh, qtd, &ptd); 8958c2ecf20Sopenharmony_ci 8968c2ecf20Sopenharmony_ci start_bus_transfer(hcd, ptd_offset, free_slot, 8978c2ecf20Sopenharmony_ci slots, qtd, qh, &ptd); 8988c2ecf20Sopenharmony_ci curr_slot = free_slot; 8998c2ecf20Sopenharmony_ci } 9008c2ecf20Sopenharmony_ci 9018c2ecf20Sopenharmony_ci n++; 9028c2ecf20Sopenharmony_ci if (n >= ENQUEUE_DEPTH) 9038c2ecf20Sopenharmony_ci break; 9048c2ecf20Sopenharmony_ci } 9058c2ecf20Sopenharmony_ci } 9068c2ecf20Sopenharmony_ci} 9078c2ecf20Sopenharmony_ci 9088c2ecf20Sopenharmony_cistatic void schedule_ptds(struct usb_hcd *hcd) 9098c2ecf20Sopenharmony_ci{ 9108c2ecf20Sopenharmony_ci struct isp1760_hcd *priv; 9118c2ecf20Sopenharmony_ci struct isp1760_qh *qh, *qh_next; 9128c2ecf20Sopenharmony_ci struct list_head *ep_queue; 9138c2ecf20Sopenharmony_ci LIST_HEAD(urb_list); 9148c2ecf20Sopenharmony_ci struct urb_listitem *urb_listitem, *urb_listitem_next; 9158c2ecf20Sopenharmony_ci int i; 9168c2ecf20Sopenharmony_ci 9178c2ecf20Sopenharmony_ci if (!hcd) { 9188c2ecf20Sopenharmony_ci WARN_ON(1); 9198c2ecf20Sopenharmony_ci return; 9208c2ecf20Sopenharmony_ci } 9218c2ecf20Sopenharmony_ci 9228c2ecf20Sopenharmony_ci priv = hcd_to_priv(hcd); 9238c2ecf20Sopenharmony_ci 9248c2ecf20Sopenharmony_ci /* 9258c2ecf20Sopenharmony_ci * check finished/retired xfers, transfer payloads, call urb_done() 9268c2ecf20Sopenharmony_ci */ 9278c2ecf20Sopenharmony_ci for (i = 0; i < QH_END; i++) { 9288c2ecf20Sopenharmony_ci ep_queue = &priv->qh_list[i]; 9298c2ecf20Sopenharmony_ci list_for_each_entry_safe(qh, qh_next, ep_queue, qh_list) { 9308c2ecf20Sopenharmony_ci collect_qtds(hcd, qh, &urb_list); 9318c2ecf20Sopenharmony_ci if (list_empty(&qh->qtd_list)) 9328c2ecf20Sopenharmony_ci list_del(&qh->qh_list); 9338c2ecf20Sopenharmony_ci } 9348c2ecf20Sopenharmony_ci } 9358c2ecf20Sopenharmony_ci 9368c2ecf20Sopenharmony_ci list_for_each_entry_safe(urb_listitem, urb_listitem_next, &urb_list, 9378c2ecf20Sopenharmony_ci urb_list) { 9388c2ecf20Sopenharmony_ci isp1760_urb_done(hcd, urb_listitem->urb); 9398c2ecf20Sopenharmony_ci kmem_cache_free(urb_listitem_cachep, urb_listitem); 9408c2ecf20Sopenharmony_ci } 9418c2ecf20Sopenharmony_ci 9428c2ecf20Sopenharmony_ci /* 9438c2ecf20Sopenharmony_ci * Schedule packets for transfer. 9448c2ecf20Sopenharmony_ci * 9458c2ecf20Sopenharmony_ci * According to USB2.0 specification: 9468c2ecf20Sopenharmony_ci * 9478c2ecf20Sopenharmony_ci * 1st prio: interrupt xfers, up to 80 % of bandwidth 9488c2ecf20Sopenharmony_ci * 2nd prio: control xfers 9498c2ecf20Sopenharmony_ci * 3rd prio: bulk xfers 9508c2ecf20Sopenharmony_ci * 9518c2ecf20Sopenharmony_ci * ... but let's use a simpler scheme here (mostly because ISP1761 doc 9528c2ecf20Sopenharmony_ci * is very unclear on how to prioritize traffic): 9538c2ecf20Sopenharmony_ci * 9548c2ecf20Sopenharmony_ci * 1) Enqueue any queued control transfers, as long as payload chip mem 9558c2ecf20Sopenharmony_ci * and PTD ATL slots are available. 9568c2ecf20Sopenharmony_ci * 2) Enqueue any queued INT transfers, as long as payload chip mem 9578c2ecf20Sopenharmony_ci * and PTD INT slots are available. 9588c2ecf20Sopenharmony_ci * 3) Enqueue any queued bulk transfers, as long as payload chip mem 9598c2ecf20Sopenharmony_ci * and PTD ATL slots are available. 9608c2ecf20Sopenharmony_ci * 9618c2ecf20Sopenharmony_ci * Use double buffering (ENQUEUE_DEPTH==2) as a compromise between 9628c2ecf20Sopenharmony_ci * conservation of chip mem and performance. 9638c2ecf20Sopenharmony_ci * 9648c2ecf20Sopenharmony_ci * I'm sure this scheme could be improved upon! 9658c2ecf20Sopenharmony_ci */ 9668c2ecf20Sopenharmony_ci for (i = 0; i < QH_END; i++) { 9678c2ecf20Sopenharmony_ci ep_queue = &priv->qh_list[i]; 9688c2ecf20Sopenharmony_ci list_for_each_entry_safe(qh, qh_next, ep_queue, qh_list) 9698c2ecf20Sopenharmony_ci enqueue_qtds(hcd, qh); 9708c2ecf20Sopenharmony_ci } 9718c2ecf20Sopenharmony_ci} 9728c2ecf20Sopenharmony_ci 9738c2ecf20Sopenharmony_ci#define PTD_STATE_QTD_DONE 1 9748c2ecf20Sopenharmony_ci#define PTD_STATE_QTD_RELOAD 2 9758c2ecf20Sopenharmony_ci#define PTD_STATE_URB_RETIRE 3 9768c2ecf20Sopenharmony_ci 9778c2ecf20Sopenharmony_cistatic int check_int_transfer(struct usb_hcd *hcd, struct ptd *ptd, 9788c2ecf20Sopenharmony_ci struct urb *urb) 9798c2ecf20Sopenharmony_ci{ 9808c2ecf20Sopenharmony_ci __dw dw4; 9818c2ecf20Sopenharmony_ci int i; 9828c2ecf20Sopenharmony_ci 9838c2ecf20Sopenharmony_ci dw4 = ptd->dw4; 9848c2ecf20Sopenharmony_ci dw4 >>= 8; 9858c2ecf20Sopenharmony_ci 9868c2ecf20Sopenharmony_ci /* FIXME: ISP1761 datasheet does not say what to do with these. Do we 9878c2ecf20Sopenharmony_ci need to handle these errors? Is it done in hardware? */ 9888c2ecf20Sopenharmony_ci 9898c2ecf20Sopenharmony_ci if (ptd->dw3 & DW3_HALT_BIT) { 9908c2ecf20Sopenharmony_ci 9918c2ecf20Sopenharmony_ci urb->status = -EPROTO; /* Default unknown error */ 9928c2ecf20Sopenharmony_ci 9938c2ecf20Sopenharmony_ci for (i = 0; i < 8; i++) { 9948c2ecf20Sopenharmony_ci switch (dw4 & 0x7) { 9958c2ecf20Sopenharmony_ci case INT_UNDERRUN: 9968c2ecf20Sopenharmony_ci dev_dbg(hcd->self.controller, "%s: underrun " 9978c2ecf20Sopenharmony_ci "during uFrame %d\n", 9988c2ecf20Sopenharmony_ci __func__, i); 9998c2ecf20Sopenharmony_ci urb->status = -ECOMM; /* Could not write data */ 10008c2ecf20Sopenharmony_ci break; 10018c2ecf20Sopenharmony_ci case INT_EXACT: 10028c2ecf20Sopenharmony_ci dev_dbg(hcd->self.controller, "%s: transaction " 10038c2ecf20Sopenharmony_ci "error during uFrame %d\n", 10048c2ecf20Sopenharmony_ci __func__, i); 10058c2ecf20Sopenharmony_ci urb->status = -EPROTO; /* timeout, bad CRC, PID 10068c2ecf20Sopenharmony_ci error etc. */ 10078c2ecf20Sopenharmony_ci break; 10088c2ecf20Sopenharmony_ci case INT_BABBLE: 10098c2ecf20Sopenharmony_ci dev_dbg(hcd->self.controller, "%s: babble " 10108c2ecf20Sopenharmony_ci "error during uFrame %d\n", 10118c2ecf20Sopenharmony_ci __func__, i); 10128c2ecf20Sopenharmony_ci urb->status = -EOVERFLOW; 10138c2ecf20Sopenharmony_ci break; 10148c2ecf20Sopenharmony_ci } 10158c2ecf20Sopenharmony_ci dw4 >>= 3; 10168c2ecf20Sopenharmony_ci } 10178c2ecf20Sopenharmony_ci 10188c2ecf20Sopenharmony_ci return PTD_STATE_URB_RETIRE; 10198c2ecf20Sopenharmony_ci } 10208c2ecf20Sopenharmony_ci 10218c2ecf20Sopenharmony_ci return PTD_STATE_QTD_DONE; 10228c2ecf20Sopenharmony_ci} 10238c2ecf20Sopenharmony_ci 10248c2ecf20Sopenharmony_cistatic int check_atl_transfer(struct usb_hcd *hcd, struct ptd *ptd, 10258c2ecf20Sopenharmony_ci struct urb *urb) 10268c2ecf20Sopenharmony_ci{ 10278c2ecf20Sopenharmony_ci WARN_ON(!ptd); 10288c2ecf20Sopenharmony_ci if (ptd->dw3 & DW3_HALT_BIT) { 10298c2ecf20Sopenharmony_ci if (ptd->dw3 & DW3_BABBLE_BIT) 10308c2ecf20Sopenharmony_ci urb->status = -EOVERFLOW; 10318c2ecf20Sopenharmony_ci else if (FROM_DW3_CERR(ptd->dw3)) 10328c2ecf20Sopenharmony_ci urb->status = -EPIPE; /* Stall */ 10338c2ecf20Sopenharmony_ci else 10348c2ecf20Sopenharmony_ci urb->status = -EPROTO; /* Unknown */ 10358c2ecf20Sopenharmony_ci/* 10368c2ecf20Sopenharmony_ci dev_dbg(hcd->self.controller, "%s: ptd error:\n" 10378c2ecf20Sopenharmony_ci " dw0: %08x dw1: %08x dw2: %08x dw3: %08x\n" 10388c2ecf20Sopenharmony_ci " dw4: %08x dw5: %08x dw6: %08x dw7: %08x\n", 10398c2ecf20Sopenharmony_ci __func__, 10408c2ecf20Sopenharmony_ci ptd->dw0, ptd->dw1, ptd->dw2, ptd->dw3, 10418c2ecf20Sopenharmony_ci ptd->dw4, ptd->dw5, ptd->dw6, ptd->dw7); 10428c2ecf20Sopenharmony_ci*/ 10438c2ecf20Sopenharmony_ci return PTD_STATE_URB_RETIRE; 10448c2ecf20Sopenharmony_ci } 10458c2ecf20Sopenharmony_ci 10468c2ecf20Sopenharmony_ci if ((ptd->dw3 & DW3_ERROR_BIT) && (ptd->dw3 & DW3_ACTIVE_BIT)) { 10478c2ecf20Sopenharmony_ci /* Transfer Error, *but* active and no HALT -> reload */ 10488c2ecf20Sopenharmony_ci dev_dbg(hcd->self.controller, "PID error; reloading ptd\n"); 10498c2ecf20Sopenharmony_ci return PTD_STATE_QTD_RELOAD; 10508c2ecf20Sopenharmony_ci } 10518c2ecf20Sopenharmony_ci 10528c2ecf20Sopenharmony_ci if (!FROM_DW3_NAKCOUNT(ptd->dw3) && (ptd->dw3 & DW3_ACTIVE_BIT)) { 10538c2ecf20Sopenharmony_ci /* 10548c2ecf20Sopenharmony_ci * NAKs are handled in HW by the chip. Usually if the 10558c2ecf20Sopenharmony_ci * device is not able to send data fast enough. 10568c2ecf20Sopenharmony_ci * This happens mostly on slower hardware. 10578c2ecf20Sopenharmony_ci */ 10588c2ecf20Sopenharmony_ci return PTD_STATE_QTD_RELOAD; 10598c2ecf20Sopenharmony_ci } 10608c2ecf20Sopenharmony_ci 10618c2ecf20Sopenharmony_ci return PTD_STATE_QTD_DONE; 10628c2ecf20Sopenharmony_ci} 10638c2ecf20Sopenharmony_ci 10648c2ecf20Sopenharmony_cistatic void handle_done_ptds(struct usb_hcd *hcd) 10658c2ecf20Sopenharmony_ci{ 10668c2ecf20Sopenharmony_ci struct isp1760_hcd *priv = hcd_to_priv(hcd); 10678c2ecf20Sopenharmony_ci struct ptd ptd; 10688c2ecf20Sopenharmony_ci struct isp1760_qh *qh; 10698c2ecf20Sopenharmony_ci int slot; 10708c2ecf20Sopenharmony_ci int state; 10718c2ecf20Sopenharmony_ci struct isp1760_slotinfo *slots; 10728c2ecf20Sopenharmony_ci u32 ptd_offset; 10738c2ecf20Sopenharmony_ci struct isp1760_qtd *qtd; 10748c2ecf20Sopenharmony_ci int modified; 10758c2ecf20Sopenharmony_ci int skip_map; 10768c2ecf20Sopenharmony_ci 10778c2ecf20Sopenharmony_ci skip_map = reg_read32(hcd->regs, HC_INT_PTD_SKIPMAP_REG); 10788c2ecf20Sopenharmony_ci priv->int_done_map &= ~skip_map; 10798c2ecf20Sopenharmony_ci skip_map = reg_read32(hcd->regs, HC_ATL_PTD_SKIPMAP_REG); 10808c2ecf20Sopenharmony_ci priv->atl_done_map &= ~skip_map; 10818c2ecf20Sopenharmony_ci 10828c2ecf20Sopenharmony_ci modified = priv->int_done_map || priv->atl_done_map; 10838c2ecf20Sopenharmony_ci 10848c2ecf20Sopenharmony_ci while (priv->int_done_map || priv->atl_done_map) { 10858c2ecf20Sopenharmony_ci if (priv->int_done_map) { 10868c2ecf20Sopenharmony_ci /* INT ptd */ 10878c2ecf20Sopenharmony_ci slot = __ffs(priv->int_done_map); 10888c2ecf20Sopenharmony_ci priv->int_done_map &= ~(1 << slot); 10898c2ecf20Sopenharmony_ci slots = priv->int_slots; 10908c2ecf20Sopenharmony_ci /* This should not trigger, and could be removed if 10918c2ecf20Sopenharmony_ci noone have any problems with it triggering: */ 10928c2ecf20Sopenharmony_ci if (!slots[slot].qh) { 10938c2ecf20Sopenharmony_ci WARN_ON(1); 10948c2ecf20Sopenharmony_ci continue; 10958c2ecf20Sopenharmony_ci } 10968c2ecf20Sopenharmony_ci ptd_offset = INT_PTD_OFFSET; 10978c2ecf20Sopenharmony_ci ptd_read(hcd->regs, INT_PTD_OFFSET, slot, &ptd); 10988c2ecf20Sopenharmony_ci state = check_int_transfer(hcd, &ptd, 10998c2ecf20Sopenharmony_ci slots[slot].qtd->urb); 11008c2ecf20Sopenharmony_ci } else { 11018c2ecf20Sopenharmony_ci /* ATL ptd */ 11028c2ecf20Sopenharmony_ci slot = __ffs(priv->atl_done_map); 11038c2ecf20Sopenharmony_ci priv->atl_done_map &= ~(1 << slot); 11048c2ecf20Sopenharmony_ci slots = priv->atl_slots; 11058c2ecf20Sopenharmony_ci /* This should not trigger, and could be removed if 11068c2ecf20Sopenharmony_ci noone have any problems with it triggering: */ 11078c2ecf20Sopenharmony_ci if (!slots[slot].qh) { 11088c2ecf20Sopenharmony_ci WARN_ON(1); 11098c2ecf20Sopenharmony_ci continue; 11108c2ecf20Sopenharmony_ci } 11118c2ecf20Sopenharmony_ci ptd_offset = ATL_PTD_OFFSET; 11128c2ecf20Sopenharmony_ci ptd_read(hcd->regs, ATL_PTD_OFFSET, slot, &ptd); 11138c2ecf20Sopenharmony_ci state = check_atl_transfer(hcd, &ptd, 11148c2ecf20Sopenharmony_ci slots[slot].qtd->urb); 11158c2ecf20Sopenharmony_ci } 11168c2ecf20Sopenharmony_ci 11178c2ecf20Sopenharmony_ci qtd = slots[slot].qtd; 11188c2ecf20Sopenharmony_ci slots[slot].qtd = NULL; 11198c2ecf20Sopenharmony_ci qh = slots[slot].qh; 11208c2ecf20Sopenharmony_ci slots[slot].qh = NULL; 11218c2ecf20Sopenharmony_ci qh->slot = -1; 11228c2ecf20Sopenharmony_ci 11238c2ecf20Sopenharmony_ci WARN_ON(qtd->status != QTD_XFER_STARTED); 11248c2ecf20Sopenharmony_ci 11258c2ecf20Sopenharmony_ci switch (state) { 11268c2ecf20Sopenharmony_ci case PTD_STATE_QTD_DONE: 11278c2ecf20Sopenharmony_ci if ((usb_pipeint(qtd->urb->pipe)) && 11288c2ecf20Sopenharmony_ci (qtd->urb->dev->speed != USB_SPEED_HIGH)) 11298c2ecf20Sopenharmony_ci qtd->actual_length = 11308c2ecf20Sopenharmony_ci FROM_DW3_SCS_NRBYTESTRANSFERRED(ptd.dw3); 11318c2ecf20Sopenharmony_ci else 11328c2ecf20Sopenharmony_ci qtd->actual_length = 11338c2ecf20Sopenharmony_ci FROM_DW3_NRBYTESTRANSFERRED(ptd.dw3); 11348c2ecf20Sopenharmony_ci 11358c2ecf20Sopenharmony_ci qtd->status = QTD_XFER_COMPLETE; 11368c2ecf20Sopenharmony_ci if (list_is_last(&qtd->qtd_list, &qh->qtd_list) || 11378c2ecf20Sopenharmony_ci is_short_bulk(qtd)) 11388c2ecf20Sopenharmony_ci qtd = NULL; 11398c2ecf20Sopenharmony_ci else 11408c2ecf20Sopenharmony_ci qtd = list_entry(qtd->qtd_list.next, 11418c2ecf20Sopenharmony_ci typeof(*qtd), qtd_list); 11428c2ecf20Sopenharmony_ci 11438c2ecf20Sopenharmony_ci qh->toggle = FROM_DW3_DATA_TOGGLE(ptd.dw3); 11448c2ecf20Sopenharmony_ci qh->ping = FROM_DW3_PING(ptd.dw3); 11458c2ecf20Sopenharmony_ci break; 11468c2ecf20Sopenharmony_ci 11478c2ecf20Sopenharmony_ci case PTD_STATE_QTD_RELOAD: /* QTD_RETRY, for atls only */ 11488c2ecf20Sopenharmony_ci qtd->status = QTD_PAYLOAD_ALLOC; 11498c2ecf20Sopenharmony_ci ptd.dw0 |= DW0_VALID_BIT; 11508c2ecf20Sopenharmony_ci /* RL counter = ERR counter */ 11518c2ecf20Sopenharmony_ci ptd.dw3 &= ~TO_DW3_NAKCOUNT(0xf); 11528c2ecf20Sopenharmony_ci ptd.dw3 |= TO_DW3_NAKCOUNT(FROM_DW2_RL(ptd.dw2)); 11538c2ecf20Sopenharmony_ci ptd.dw3 &= ~TO_DW3_CERR(3); 11548c2ecf20Sopenharmony_ci ptd.dw3 |= TO_DW3_CERR(ERR_COUNTER); 11558c2ecf20Sopenharmony_ci qh->toggle = FROM_DW3_DATA_TOGGLE(ptd.dw3); 11568c2ecf20Sopenharmony_ci qh->ping = FROM_DW3_PING(ptd.dw3); 11578c2ecf20Sopenharmony_ci break; 11588c2ecf20Sopenharmony_ci 11598c2ecf20Sopenharmony_ci case PTD_STATE_URB_RETIRE: 11608c2ecf20Sopenharmony_ci qtd->status = QTD_RETIRE; 11618c2ecf20Sopenharmony_ci if ((qtd->urb->dev->speed != USB_SPEED_HIGH) && 11628c2ecf20Sopenharmony_ci (qtd->urb->status != -EPIPE) && 11638c2ecf20Sopenharmony_ci (qtd->urb->status != -EREMOTEIO)) { 11648c2ecf20Sopenharmony_ci qh->tt_buffer_dirty = 1; 11658c2ecf20Sopenharmony_ci if (usb_hub_clear_tt_buffer(qtd->urb)) 11668c2ecf20Sopenharmony_ci /* Clear failed; let's hope things work 11678c2ecf20Sopenharmony_ci anyway */ 11688c2ecf20Sopenharmony_ci qh->tt_buffer_dirty = 0; 11698c2ecf20Sopenharmony_ci } 11708c2ecf20Sopenharmony_ci qtd = NULL; 11718c2ecf20Sopenharmony_ci qh->toggle = 0; 11728c2ecf20Sopenharmony_ci qh->ping = 0; 11738c2ecf20Sopenharmony_ci break; 11748c2ecf20Sopenharmony_ci 11758c2ecf20Sopenharmony_ci default: 11768c2ecf20Sopenharmony_ci WARN_ON(1); 11778c2ecf20Sopenharmony_ci continue; 11788c2ecf20Sopenharmony_ci } 11798c2ecf20Sopenharmony_ci 11808c2ecf20Sopenharmony_ci if (qtd && (qtd->status == QTD_PAYLOAD_ALLOC)) { 11818c2ecf20Sopenharmony_ci if (slots == priv->int_slots) { 11828c2ecf20Sopenharmony_ci if (state == PTD_STATE_QTD_RELOAD) 11838c2ecf20Sopenharmony_ci dev_err(hcd->self.controller, 11848c2ecf20Sopenharmony_ci "%s: PTD_STATE_QTD_RELOAD on " 11858c2ecf20Sopenharmony_ci "interrupt packet\n", __func__); 11868c2ecf20Sopenharmony_ci if (state != PTD_STATE_QTD_RELOAD) 11878c2ecf20Sopenharmony_ci create_ptd_int(qh, qtd, &ptd); 11888c2ecf20Sopenharmony_ci } else { 11898c2ecf20Sopenharmony_ci if (state != PTD_STATE_QTD_RELOAD) 11908c2ecf20Sopenharmony_ci create_ptd_atl(qh, qtd, &ptd); 11918c2ecf20Sopenharmony_ci } 11928c2ecf20Sopenharmony_ci 11938c2ecf20Sopenharmony_ci start_bus_transfer(hcd, ptd_offset, slot, slots, qtd, 11948c2ecf20Sopenharmony_ci qh, &ptd); 11958c2ecf20Sopenharmony_ci } 11968c2ecf20Sopenharmony_ci } 11978c2ecf20Sopenharmony_ci 11988c2ecf20Sopenharmony_ci if (modified) 11998c2ecf20Sopenharmony_ci schedule_ptds(hcd); 12008c2ecf20Sopenharmony_ci} 12018c2ecf20Sopenharmony_ci 12028c2ecf20Sopenharmony_cistatic irqreturn_t isp1760_irq(struct usb_hcd *hcd) 12038c2ecf20Sopenharmony_ci{ 12048c2ecf20Sopenharmony_ci struct isp1760_hcd *priv = hcd_to_priv(hcd); 12058c2ecf20Sopenharmony_ci u32 imask; 12068c2ecf20Sopenharmony_ci irqreturn_t irqret = IRQ_NONE; 12078c2ecf20Sopenharmony_ci 12088c2ecf20Sopenharmony_ci spin_lock(&priv->lock); 12098c2ecf20Sopenharmony_ci 12108c2ecf20Sopenharmony_ci if (!(hcd->state & HC_STATE_RUNNING)) 12118c2ecf20Sopenharmony_ci goto leave; 12128c2ecf20Sopenharmony_ci 12138c2ecf20Sopenharmony_ci imask = reg_read32(hcd->regs, HC_INTERRUPT_REG); 12148c2ecf20Sopenharmony_ci if (unlikely(!imask)) 12158c2ecf20Sopenharmony_ci goto leave; 12168c2ecf20Sopenharmony_ci reg_write32(hcd->regs, HC_INTERRUPT_REG, imask); /* Clear */ 12178c2ecf20Sopenharmony_ci 12188c2ecf20Sopenharmony_ci priv->int_done_map |= reg_read32(hcd->regs, HC_INT_PTD_DONEMAP_REG); 12198c2ecf20Sopenharmony_ci priv->atl_done_map |= reg_read32(hcd->regs, HC_ATL_PTD_DONEMAP_REG); 12208c2ecf20Sopenharmony_ci 12218c2ecf20Sopenharmony_ci handle_done_ptds(hcd); 12228c2ecf20Sopenharmony_ci 12238c2ecf20Sopenharmony_ci irqret = IRQ_HANDLED; 12248c2ecf20Sopenharmony_cileave: 12258c2ecf20Sopenharmony_ci spin_unlock(&priv->lock); 12268c2ecf20Sopenharmony_ci 12278c2ecf20Sopenharmony_ci return irqret; 12288c2ecf20Sopenharmony_ci} 12298c2ecf20Sopenharmony_ci 12308c2ecf20Sopenharmony_ci/* 12318c2ecf20Sopenharmony_ci * Workaround for problem described in chip errata 2: 12328c2ecf20Sopenharmony_ci * 12338c2ecf20Sopenharmony_ci * Sometimes interrupts are not generated when ATL (not INT?) completion occurs. 12348c2ecf20Sopenharmony_ci * One solution suggested in the errata is to use SOF interrupts _instead_of_ 12358c2ecf20Sopenharmony_ci * ATL done interrupts (the "instead of" might be important since it seems 12368c2ecf20Sopenharmony_ci * enabling ATL interrupts also causes the chip to sometimes - rarely - "forget" 12378c2ecf20Sopenharmony_ci * to set the PTD's done bit in addition to not generating an interrupt!). 12388c2ecf20Sopenharmony_ci * 12398c2ecf20Sopenharmony_ci * So if we use SOF + ATL interrupts, we sometimes get stale PTDs since their 12408c2ecf20Sopenharmony_ci * done bit is not being set. This is bad - it blocks the endpoint until reboot. 12418c2ecf20Sopenharmony_ci * 12428c2ecf20Sopenharmony_ci * If we use SOF interrupts only, we get latency between ptd completion and the 12438c2ecf20Sopenharmony_ci * actual handling. This is very noticeable in testusb runs which takes several 12448c2ecf20Sopenharmony_ci * minutes longer without ATL interrupts. 12458c2ecf20Sopenharmony_ci * 12468c2ecf20Sopenharmony_ci * A better solution is to run the code below every SLOT_CHECK_PERIOD ms. If it 12478c2ecf20Sopenharmony_ci * finds active ATL slots which are older than SLOT_TIMEOUT ms, it checks the 12488c2ecf20Sopenharmony_ci * slot's ACTIVE and VALID bits. If these are not set, the ptd is considered 12498c2ecf20Sopenharmony_ci * completed and its done map bit is set. 12508c2ecf20Sopenharmony_ci * 12518c2ecf20Sopenharmony_ci * The values of SLOT_TIMEOUT and SLOT_CHECK_PERIOD have been arbitrarily chosen 12528c2ecf20Sopenharmony_ci * not to cause too much lag when this HW bug occurs, while still hopefully 12538c2ecf20Sopenharmony_ci * ensuring that the check does not falsely trigger. 12548c2ecf20Sopenharmony_ci */ 12558c2ecf20Sopenharmony_ci#define SLOT_TIMEOUT 300 12568c2ecf20Sopenharmony_ci#define SLOT_CHECK_PERIOD 200 12578c2ecf20Sopenharmony_cistatic struct timer_list errata2_timer; 12588c2ecf20Sopenharmony_cistatic struct usb_hcd *errata2_timer_hcd; 12598c2ecf20Sopenharmony_ci 12608c2ecf20Sopenharmony_cistatic void errata2_function(struct timer_list *unused) 12618c2ecf20Sopenharmony_ci{ 12628c2ecf20Sopenharmony_ci struct usb_hcd *hcd = errata2_timer_hcd; 12638c2ecf20Sopenharmony_ci struct isp1760_hcd *priv = hcd_to_priv(hcd); 12648c2ecf20Sopenharmony_ci int slot; 12658c2ecf20Sopenharmony_ci struct ptd ptd; 12668c2ecf20Sopenharmony_ci unsigned long spinflags; 12678c2ecf20Sopenharmony_ci 12688c2ecf20Sopenharmony_ci spin_lock_irqsave(&priv->lock, spinflags); 12698c2ecf20Sopenharmony_ci 12708c2ecf20Sopenharmony_ci for (slot = 0; slot < 32; slot++) 12718c2ecf20Sopenharmony_ci if (priv->atl_slots[slot].qh && time_after(jiffies, 12728c2ecf20Sopenharmony_ci priv->atl_slots[slot].timestamp + 12738c2ecf20Sopenharmony_ci msecs_to_jiffies(SLOT_TIMEOUT))) { 12748c2ecf20Sopenharmony_ci ptd_read(hcd->regs, ATL_PTD_OFFSET, slot, &ptd); 12758c2ecf20Sopenharmony_ci if (!FROM_DW0_VALID(ptd.dw0) && 12768c2ecf20Sopenharmony_ci !FROM_DW3_ACTIVE(ptd.dw3)) 12778c2ecf20Sopenharmony_ci priv->atl_done_map |= 1 << slot; 12788c2ecf20Sopenharmony_ci } 12798c2ecf20Sopenharmony_ci 12808c2ecf20Sopenharmony_ci if (priv->atl_done_map) 12818c2ecf20Sopenharmony_ci handle_done_ptds(hcd); 12828c2ecf20Sopenharmony_ci 12838c2ecf20Sopenharmony_ci spin_unlock_irqrestore(&priv->lock, spinflags); 12848c2ecf20Sopenharmony_ci 12858c2ecf20Sopenharmony_ci errata2_timer.expires = jiffies + msecs_to_jiffies(SLOT_CHECK_PERIOD); 12868c2ecf20Sopenharmony_ci add_timer(&errata2_timer); 12878c2ecf20Sopenharmony_ci} 12888c2ecf20Sopenharmony_ci 12898c2ecf20Sopenharmony_cistatic int isp1760_run(struct usb_hcd *hcd) 12908c2ecf20Sopenharmony_ci{ 12918c2ecf20Sopenharmony_ci int retval; 12928c2ecf20Sopenharmony_ci u32 temp; 12938c2ecf20Sopenharmony_ci u32 command; 12948c2ecf20Sopenharmony_ci u32 chipid; 12958c2ecf20Sopenharmony_ci 12968c2ecf20Sopenharmony_ci hcd->uses_new_polling = 1; 12978c2ecf20Sopenharmony_ci 12988c2ecf20Sopenharmony_ci hcd->state = HC_STATE_RUNNING; 12998c2ecf20Sopenharmony_ci 13008c2ecf20Sopenharmony_ci /* Set PTD interrupt AND & OR maps */ 13018c2ecf20Sopenharmony_ci reg_write32(hcd->regs, HC_ATL_IRQ_MASK_AND_REG, 0); 13028c2ecf20Sopenharmony_ci reg_write32(hcd->regs, HC_ATL_IRQ_MASK_OR_REG, 0xffffffff); 13038c2ecf20Sopenharmony_ci reg_write32(hcd->regs, HC_INT_IRQ_MASK_AND_REG, 0); 13048c2ecf20Sopenharmony_ci reg_write32(hcd->regs, HC_INT_IRQ_MASK_OR_REG, 0xffffffff); 13058c2ecf20Sopenharmony_ci reg_write32(hcd->regs, HC_ISO_IRQ_MASK_AND_REG, 0); 13068c2ecf20Sopenharmony_ci reg_write32(hcd->regs, HC_ISO_IRQ_MASK_OR_REG, 0xffffffff); 13078c2ecf20Sopenharmony_ci /* step 23 passed */ 13088c2ecf20Sopenharmony_ci 13098c2ecf20Sopenharmony_ci temp = reg_read32(hcd->regs, HC_HW_MODE_CTRL); 13108c2ecf20Sopenharmony_ci reg_write32(hcd->regs, HC_HW_MODE_CTRL, temp | HW_GLOBAL_INTR_EN); 13118c2ecf20Sopenharmony_ci 13128c2ecf20Sopenharmony_ci command = reg_read32(hcd->regs, HC_USBCMD); 13138c2ecf20Sopenharmony_ci command &= ~(CMD_LRESET|CMD_RESET); 13148c2ecf20Sopenharmony_ci command |= CMD_RUN; 13158c2ecf20Sopenharmony_ci reg_write32(hcd->regs, HC_USBCMD, command); 13168c2ecf20Sopenharmony_ci 13178c2ecf20Sopenharmony_ci retval = handshake(hcd, HC_USBCMD, CMD_RUN, CMD_RUN, 250 * 1000); 13188c2ecf20Sopenharmony_ci if (retval) 13198c2ecf20Sopenharmony_ci return retval; 13208c2ecf20Sopenharmony_ci 13218c2ecf20Sopenharmony_ci /* 13228c2ecf20Sopenharmony_ci * XXX 13238c2ecf20Sopenharmony_ci * Spec says to write FLAG_CF as last config action, priv code grabs 13248c2ecf20Sopenharmony_ci * the semaphore while doing so. 13258c2ecf20Sopenharmony_ci */ 13268c2ecf20Sopenharmony_ci down_write(&ehci_cf_port_reset_rwsem); 13278c2ecf20Sopenharmony_ci reg_write32(hcd->regs, HC_CONFIGFLAG, FLAG_CF); 13288c2ecf20Sopenharmony_ci 13298c2ecf20Sopenharmony_ci retval = handshake(hcd, HC_CONFIGFLAG, FLAG_CF, FLAG_CF, 250 * 1000); 13308c2ecf20Sopenharmony_ci up_write(&ehci_cf_port_reset_rwsem); 13318c2ecf20Sopenharmony_ci if (retval) 13328c2ecf20Sopenharmony_ci return retval; 13338c2ecf20Sopenharmony_ci 13348c2ecf20Sopenharmony_ci errata2_timer_hcd = hcd; 13358c2ecf20Sopenharmony_ci timer_setup(&errata2_timer, errata2_function, 0); 13368c2ecf20Sopenharmony_ci errata2_timer.expires = jiffies + msecs_to_jiffies(SLOT_CHECK_PERIOD); 13378c2ecf20Sopenharmony_ci add_timer(&errata2_timer); 13388c2ecf20Sopenharmony_ci 13398c2ecf20Sopenharmony_ci chipid = reg_read32(hcd->regs, HC_CHIP_ID_REG); 13408c2ecf20Sopenharmony_ci dev_info(hcd->self.controller, "USB ISP %04x HW rev. %d started\n", 13418c2ecf20Sopenharmony_ci chipid & 0xffff, chipid >> 16); 13428c2ecf20Sopenharmony_ci 13438c2ecf20Sopenharmony_ci /* PTD Register Init Part 2, Step 28 */ 13448c2ecf20Sopenharmony_ci 13458c2ecf20Sopenharmony_ci /* Setup registers controlling PTD checking */ 13468c2ecf20Sopenharmony_ci reg_write32(hcd->regs, HC_ATL_PTD_LASTPTD_REG, 0x80000000); 13478c2ecf20Sopenharmony_ci reg_write32(hcd->regs, HC_INT_PTD_LASTPTD_REG, 0x80000000); 13488c2ecf20Sopenharmony_ci reg_write32(hcd->regs, HC_ISO_PTD_LASTPTD_REG, 0x00000001); 13498c2ecf20Sopenharmony_ci reg_write32(hcd->regs, HC_ATL_PTD_SKIPMAP_REG, 0xffffffff); 13508c2ecf20Sopenharmony_ci reg_write32(hcd->regs, HC_INT_PTD_SKIPMAP_REG, 0xffffffff); 13518c2ecf20Sopenharmony_ci reg_write32(hcd->regs, HC_ISO_PTD_SKIPMAP_REG, 0xffffffff); 13528c2ecf20Sopenharmony_ci reg_write32(hcd->regs, HC_BUFFER_STATUS_REG, 13538c2ecf20Sopenharmony_ci ATL_BUF_FILL | INT_BUF_FILL); 13548c2ecf20Sopenharmony_ci 13558c2ecf20Sopenharmony_ci /* GRR this is run-once init(), being done every time the HC starts. 13568c2ecf20Sopenharmony_ci * So long as they're part of class devices, we can't do it init() 13578c2ecf20Sopenharmony_ci * since the class device isn't created that early. 13588c2ecf20Sopenharmony_ci */ 13598c2ecf20Sopenharmony_ci return 0; 13608c2ecf20Sopenharmony_ci} 13618c2ecf20Sopenharmony_ci 13628c2ecf20Sopenharmony_cistatic int qtd_fill(struct isp1760_qtd *qtd, void *databuffer, size_t len) 13638c2ecf20Sopenharmony_ci{ 13648c2ecf20Sopenharmony_ci qtd->data_buffer = databuffer; 13658c2ecf20Sopenharmony_ci 13668c2ecf20Sopenharmony_ci if (len > MAX_PAYLOAD_SIZE) 13678c2ecf20Sopenharmony_ci len = MAX_PAYLOAD_SIZE; 13688c2ecf20Sopenharmony_ci qtd->length = len; 13698c2ecf20Sopenharmony_ci 13708c2ecf20Sopenharmony_ci return qtd->length; 13718c2ecf20Sopenharmony_ci} 13728c2ecf20Sopenharmony_ci 13738c2ecf20Sopenharmony_cistatic void qtd_list_free(struct list_head *qtd_list) 13748c2ecf20Sopenharmony_ci{ 13758c2ecf20Sopenharmony_ci struct isp1760_qtd *qtd, *qtd_next; 13768c2ecf20Sopenharmony_ci 13778c2ecf20Sopenharmony_ci list_for_each_entry_safe(qtd, qtd_next, qtd_list, qtd_list) { 13788c2ecf20Sopenharmony_ci list_del(&qtd->qtd_list); 13798c2ecf20Sopenharmony_ci qtd_free(qtd); 13808c2ecf20Sopenharmony_ci } 13818c2ecf20Sopenharmony_ci} 13828c2ecf20Sopenharmony_ci 13838c2ecf20Sopenharmony_ci/* 13848c2ecf20Sopenharmony_ci * Packetize urb->transfer_buffer into list of packets of size wMaxPacketSize. 13858c2ecf20Sopenharmony_ci * Also calculate the PID type (SETUP/IN/OUT) for each packet. 13868c2ecf20Sopenharmony_ci */ 13878c2ecf20Sopenharmony_ci#define max_packet(wMaxPacketSize) ((wMaxPacketSize) & 0x07ff) 13888c2ecf20Sopenharmony_cistatic void packetize_urb(struct usb_hcd *hcd, 13898c2ecf20Sopenharmony_ci struct urb *urb, struct list_head *head, gfp_t flags) 13908c2ecf20Sopenharmony_ci{ 13918c2ecf20Sopenharmony_ci struct isp1760_qtd *qtd; 13928c2ecf20Sopenharmony_ci void *buf; 13938c2ecf20Sopenharmony_ci int len, maxpacketsize; 13948c2ecf20Sopenharmony_ci u8 packet_type; 13958c2ecf20Sopenharmony_ci 13968c2ecf20Sopenharmony_ci /* 13978c2ecf20Sopenharmony_ci * URBs map to sequences of QTDs: one logical transaction 13988c2ecf20Sopenharmony_ci */ 13998c2ecf20Sopenharmony_ci 14008c2ecf20Sopenharmony_ci if (!urb->transfer_buffer && urb->transfer_buffer_length) { 14018c2ecf20Sopenharmony_ci /* XXX This looks like usb storage / SCSI bug */ 14028c2ecf20Sopenharmony_ci dev_err(hcd->self.controller, 14038c2ecf20Sopenharmony_ci "buf is null, dma is %08lx len is %d\n", 14048c2ecf20Sopenharmony_ci (long unsigned)urb->transfer_dma, 14058c2ecf20Sopenharmony_ci urb->transfer_buffer_length); 14068c2ecf20Sopenharmony_ci WARN_ON(1); 14078c2ecf20Sopenharmony_ci } 14088c2ecf20Sopenharmony_ci 14098c2ecf20Sopenharmony_ci if (usb_pipein(urb->pipe)) 14108c2ecf20Sopenharmony_ci packet_type = IN_PID; 14118c2ecf20Sopenharmony_ci else 14128c2ecf20Sopenharmony_ci packet_type = OUT_PID; 14138c2ecf20Sopenharmony_ci 14148c2ecf20Sopenharmony_ci if (usb_pipecontrol(urb->pipe)) { 14158c2ecf20Sopenharmony_ci qtd = qtd_alloc(flags, urb, SETUP_PID); 14168c2ecf20Sopenharmony_ci if (!qtd) 14178c2ecf20Sopenharmony_ci goto cleanup; 14188c2ecf20Sopenharmony_ci qtd_fill(qtd, urb->setup_packet, sizeof(struct usb_ctrlrequest)); 14198c2ecf20Sopenharmony_ci list_add_tail(&qtd->qtd_list, head); 14208c2ecf20Sopenharmony_ci 14218c2ecf20Sopenharmony_ci /* for zero length DATA stages, STATUS is always IN */ 14228c2ecf20Sopenharmony_ci if (urb->transfer_buffer_length == 0) 14238c2ecf20Sopenharmony_ci packet_type = IN_PID; 14248c2ecf20Sopenharmony_ci } 14258c2ecf20Sopenharmony_ci 14268c2ecf20Sopenharmony_ci maxpacketsize = max_packet(usb_maxpacket(urb->dev, urb->pipe, 14278c2ecf20Sopenharmony_ci usb_pipeout(urb->pipe))); 14288c2ecf20Sopenharmony_ci 14298c2ecf20Sopenharmony_ci /* 14308c2ecf20Sopenharmony_ci * buffer gets wrapped in one or more qtds; 14318c2ecf20Sopenharmony_ci * last one may be "short" (including zero len) 14328c2ecf20Sopenharmony_ci * and may serve as a control status ack 14338c2ecf20Sopenharmony_ci */ 14348c2ecf20Sopenharmony_ci buf = urb->transfer_buffer; 14358c2ecf20Sopenharmony_ci len = urb->transfer_buffer_length; 14368c2ecf20Sopenharmony_ci 14378c2ecf20Sopenharmony_ci for (;;) { 14388c2ecf20Sopenharmony_ci int this_qtd_len; 14398c2ecf20Sopenharmony_ci 14408c2ecf20Sopenharmony_ci qtd = qtd_alloc(flags, urb, packet_type); 14418c2ecf20Sopenharmony_ci if (!qtd) 14428c2ecf20Sopenharmony_ci goto cleanup; 14438c2ecf20Sopenharmony_ci this_qtd_len = qtd_fill(qtd, buf, len); 14448c2ecf20Sopenharmony_ci list_add_tail(&qtd->qtd_list, head); 14458c2ecf20Sopenharmony_ci 14468c2ecf20Sopenharmony_ci len -= this_qtd_len; 14478c2ecf20Sopenharmony_ci buf += this_qtd_len; 14488c2ecf20Sopenharmony_ci 14498c2ecf20Sopenharmony_ci if (len <= 0) 14508c2ecf20Sopenharmony_ci break; 14518c2ecf20Sopenharmony_ci } 14528c2ecf20Sopenharmony_ci 14538c2ecf20Sopenharmony_ci /* 14548c2ecf20Sopenharmony_ci * control requests may need a terminating data "status" ack; 14558c2ecf20Sopenharmony_ci * bulk ones may need a terminating short packet (zero length). 14568c2ecf20Sopenharmony_ci */ 14578c2ecf20Sopenharmony_ci if (urb->transfer_buffer_length != 0) { 14588c2ecf20Sopenharmony_ci int one_more = 0; 14598c2ecf20Sopenharmony_ci 14608c2ecf20Sopenharmony_ci if (usb_pipecontrol(urb->pipe)) { 14618c2ecf20Sopenharmony_ci one_more = 1; 14628c2ecf20Sopenharmony_ci if (packet_type == IN_PID) 14638c2ecf20Sopenharmony_ci packet_type = OUT_PID; 14648c2ecf20Sopenharmony_ci else 14658c2ecf20Sopenharmony_ci packet_type = IN_PID; 14668c2ecf20Sopenharmony_ci } else if (usb_pipebulk(urb->pipe) 14678c2ecf20Sopenharmony_ci && (urb->transfer_flags & URB_ZERO_PACKET) 14688c2ecf20Sopenharmony_ci && !(urb->transfer_buffer_length % 14698c2ecf20Sopenharmony_ci maxpacketsize)) { 14708c2ecf20Sopenharmony_ci one_more = 1; 14718c2ecf20Sopenharmony_ci } 14728c2ecf20Sopenharmony_ci if (one_more) { 14738c2ecf20Sopenharmony_ci qtd = qtd_alloc(flags, urb, packet_type); 14748c2ecf20Sopenharmony_ci if (!qtd) 14758c2ecf20Sopenharmony_ci goto cleanup; 14768c2ecf20Sopenharmony_ci 14778c2ecf20Sopenharmony_ci /* never any data in such packets */ 14788c2ecf20Sopenharmony_ci qtd_fill(qtd, NULL, 0); 14798c2ecf20Sopenharmony_ci list_add_tail(&qtd->qtd_list, head); 14808c2ecf20Sopenharmony_ci } 14818c2ecf20Sopenharmony_ci } 14828c2ecf20Sopenharmony_ci 14838c2ecf20Sopenharmony_ci return; 14848c2ecf20Sopenharmony_ci 14858c2ecf20Sopenharmony_cicleanup: 14868c2ecf20Sopenharmony_ci qtd_list_free(head); 14878c2ecf20Sopenharmony_ci} 14888c2ecf20Sopenharmony_ci 14898c2ecf20Sopenharmony_cistatic int isp1760_urb_enqueue(struct usb_hcd *hcd, struct urb *urb, 14908c2ecf20Sopenharmony_ci gfp_t mem_flags) 14918c2ecf20Sopenharmony_ci{ 14928c2ecf20Sopenharmony_ci struct isp1760_hcd *priv = hcd_to_priv(hcd); 14938c2ecf20Sopenharmony_ci struct list_head *ep_queue; 14948c2ecf20Sopenharmony_ci struct isp1760_qh *qh, *qhit; 14958c2ecf20Sopenharmony_ci unsigned long spinflags; 14968c2ecf20Sopenharmony_ci LIST_HEAD(new_qtds); 14978c2ecf20Sopenharmony_ci int retval; 14988c2ecf20Sopenharmony_ci int qh_in_queue; 14998c2ecf20Sopenharmony_ci 15008c2ecf20Sopenharmony_ci switch (usb_pipetype(urb->pipe)) { 15018c2ecf20Sopenharmony_ci case PIPE_CONTROL: 15028c2ecf20Sopenharmony_ci ep_queue = &priv->qh_list[QH_CONTROL]; 15038c2ecf20Sopenharmony_ci break; 15048c2ecf20Sopenharmony_ci case PIPE_BULK: 15058c2ecf20Sopenharmony_ci ep_queue = &priv->qh_list[QH_BULK]; 15068c2ecf20Sopenharmony_ci break; 15078c2ecf20Sopenharmony_ci case PIPE_INTERRUPT: 15088c2ecf20Sopenharmony_ci if (urb->interval < 0) 15098c2ecf20Sopenharmony_ci return -EINVAL; 15108c2ecf20Sopenharmony_ci /* FIXME: Check bandwidth */ 15118c2ecf20Sopenharmony_ci ep_queue = &priv->qh_list[QH_INTERRUPT]; 15128c2ecf20Sopenharmony_ci break; 15138c2ecf20Sopenharmony_ci case PIPE_ISOCHRONOUS: 15148c2ecf20Sopenharmony_ci dev_err(hcd->self.controller, "%s: isochronous USB packets " 15158c2ecf20Sopenharmony_ci "not yet supported\n", 15168c2ecf20Sopenharmony_ci __func__); 15178c2ecf20Sopenharmony_ci return -EPIPE; 15188c2ecf20Sopenharmony_ci default: 15198c2ecf20Sopenharmony_ci dev_err(hcd->self.controller, "%s: unknown pipe type\n", 15208c2ecf20Sopenharmony_ci __func__); 15218c2ecf20Sopenharmony_ci return -EPIPE; 15228c2ecf20Sopenharmony_ci } 15238c2ecf20Sopenharmony_ci 15248c2ecf20Sopenharmony_ci if (usb_pipein(urb->pipe)) 15258c2ecf20Sopenharmony_ci urb->actual_length = 0; 15268c2ecf20Sopenharmony_ci 15278c2ecf20Sopenharmony_ci packetize_urb(hcd, urb, &new_qtds, mem_flags); 15288c2ecf20Sopenharmony_ci if (list_empty(&new_qtds)) 15298c2ecf20Sopenharmony_ci return -ENOMEM; 15308c2ecf20Sopenharmony_ci 15318c2ecf20Sopenharmony_ci retval = 0; 15328c2ecf20Sopenharmony_ci spin_lock_irqsave(&priv->lock, spinflags); 15338c2ecf20Sopenharmony_ci 15348c2ecf20Sopenharmony_ci if (!test_bit(HCD_FLAG_HW_ACCESSIBLE, &hcd->flags)) { 15358c2ecf20Sopenharmony_ci retval = -ESHUTDOWN; 15368c2ecf20Sopenharmony_ci qtd_list_free(&new_qtds); 15378c2ecf20Sopenharmony_ci goto out; 15388c2ecf20Sopenharmony_ci } 15398c2ecf20Sopenharmony_ci retval = usb_hcd_link_urb_to_ep(hcd, urb); 15408c2ecf20Sopenharmony_ci if (retval) { 15418c2ecf20Sopenharmony_ci qtd_list_free(&new_qtds); 15428c2ecf20Sopenharmony_ci goto out; 15438c2ecf20Sopenharmony_ci } 15448c2ecf20Sopenharmony_ci 15458c2ecf20Sopenharmony_ci qh = urb->ep->hcpriv; 15468c2ecf20Sopenharmony_ci if (qh) { 15478c2ecf20Sopenharmony_ci qh_in_queue = 0; 15488c2ecf20Sopenharmony_ci list_for_each_entry(qhit, ep_queue, qh_list) { 15498c2ecf20Sopenharmony_ci if (qhit == qh) { 15508c2ecf20Sopenharmony_ci qh_in_queue = 1; 15518c2ecf20Sopenharmony_ci break; 15528c2ecf20Sopenharmony_ci } 15538c2ecf20Sopenharmony_ci } 15548c2ecf20Sopenharmony_ci if (!qh_in_queue) 15558c2ecf20Sopenharmony_ci list_add_tail(&qh->qh_list, ep_queue); 15568c2ecf20Sopenharmony_ci } else { 15578c2ecf20Sopenharmony_ci qh = qh_alloc(GFP_ATOMIC); 15588c2ecf20Sopenharmony_ci if (!qh) { 15598c2ecf20Sopenharmony_ci retval = -ENOMEM; 15608c2ecf20Sopenharmony_ci usb_hcd_unlink_urb_from_ep(hcd, urb); 15618c2ecf20Sopenharmony_ci qtd_list_free(&new_qtds); 15628c2ecf20Sopenharmony_ci goto out; 15638c2ecf20Sopenharmony_ci } 15648c2ecf20Sopenharmony_ci list_add_tail(&qh->qh_list, ep_queue); 15658c2ecf20Sopenharmony_ci urb->ep->hcpriv = qh; 15668c2ecf20Sopenharmony_ci } 15678c2ecf20Sopenharmony_ci 15688c2ecf20Sopenharmony_ci list_splice_tail(&new_qtds, &qh->qtd_list); 15698c2ecf20Sopenharmony_ci schedule_ptds(hcd); 15708c2ecf20Sopenharmony_ci 15718c2ecf20Sopenharmony_ciout: 15728c2ecf20Sopenharmony_ci spin_unlock_irqrestore(&priv->lock, spinflags); 15738c2ecf20Sopenharmony_ci return retval; 15748c2ecf20Sopenharmony_ci} 15758c2ecf20Sopenharmony_ci 15768c2ecf20Sopenharmony_cistatic void kill_transfer(struct usb_hcd *hcd, struct urb *urb, 15778c2ecf20Sopenharmony_ci struct isp1760_qh *qh) 15788c2ecf20Sopenharmony_ci{ 15798c2ecf20Sopenharmony_ci struct isp1760_hcd *priv = hcd_to_priv(hcd); 15808c2ecf20Sopenharmony_ci int skip_map; 15818c2ecf20Sopenharmony_ci 15828c2ecf20Sopenharmony_ci WARN_ON(qh->slot == -1); 15838c2ecf20Sopenharmony_ci 15848c2ecf20Sopenharmony_ci /* We need to forcefully reclaim the slot since some transfers never 15858c2ecf20Sopenharmony_ci return, e.g. interrupt transfers and NAKed bulk transfers. */ 15868c2ecf20Sopenharmony_ci if (usb_pipecontrol(urb->pipe) || usb_pipebulk(urb->pipe)) { 15878c2ecf20Sopenharmony_ci skip_map = reg_read32(hcd->regs, HC_ATL_PTD_SKIPMAP_REG); 15888c2ecf20Sopenharmony_ci skip_map |= (1 << qh->slot); 15898c2ecf20Sopenharmony_ci reg_write32(hcd->regs, HC_ATL_PTD_SKIPMAP_REG, skip_map); 15908c2ecf20Sopenharmony_ci priv->atl_slots[qh->slot].qh = NULL; 15918c2ecf20Sopenharmony_ci priv->atl_slots[qh->slot].qtd = NULL; 15928c2ecf20Sopenharmony_ci } else { 15938c2ecf20Sopenharmony_ci skip_map = reg_read32(hcd->regs, HC_INT_PTD_SKIPMAP_REG); 15948c2ecf20Sopenharmony_ci skip_map |= (1 << qh->slot); 15958c2ecf20Sopenharmony_ci reg_write32(hcd->regs, HC_INT_PTD_SKIPMAP_REG, skip_map); 15968c2ecf20Sopenharmony_ci priv->int_slots[qh->slot].qh = NULL; 15978c2ecf20Sopenharmony_ci priv->int_slots[qh->slot].qtd = NULL; 15988c2ecf20Sopenharmony_ci } 15998c2ecf20Sopenharmony_ci 16008c2ecf20Sopenharmony_ci qh->slot = -1; 16018c2ecf20Sopenharmony_ci} 16028c2ecf20Sopenharmony_ci 16038c2ecf20Sopenharmony_ci/* 16048c2ecf20Sopenharmony_ci * Retire the qtds beginning at 'qtd' and belonging all to the same urb, killing 16058c2ecf20Sopenharmony_ci * any active transfer belonging to the urb in the process. 16068c2ecf20Sopenharmony_ci */ 16078c2ecf20Sopenharmony_cistatic void dequeue_urb_from_qtd(struct usb_hcd *hcd, struct isp1760_qh *qh, 16088c2ecf20Sopenharmony_ci struct isp1760_qtd *qtd) 16098c2ecf20Sopenharmony_ci{ 16108c2ecf20Sopenharmony_ci struct urb *urb; 16118c2ecf20Sopenharmony_ci int urb_was_running; 16128c2ecf20Sopenharmony_ci 16138c2ecf20Sopenharmony_ci urb = qtd->urb; 16148c2ecf20Sopenharmony_ci urb_was_running = 0; 16158c2ecf20Sopenharmony_ci list_for_each_entry_from(qtd, &qh->qtd_list, qtd_list) { 16168c2ecf20Sopenharmony_ci if (qtd->urb != urb) 16178c2ecf20Sopenharmony_ci break; 16188c2ecf20Sopenharmony_ci 16198c2ecf20Sopenharmony_ci if (qtd->status >= QTD_XFER_STARTED) 16208c2ecf20Sopenharmony_ci urb_was_running = 1; 16218c2ecf20Sopenharmony_ci if (last_qtd_of_urb(qtd, qh) && 16228c2ecf20Sopenharmony_ci (qtd->status >= QTD_XFER_COMPLETE)) 16238c2ecf20Sopenharmony_ci urb_was_running = 0; 16248c2ecf20Sopenharmony_ci 16258c2ecf20Sopenharmony_ci if (qtd->status == QTD_XFER_STARTED) 16268c2ecf20Sopenharmony_ci kill_transfer(hcd, urb, qh); 16278c2ecf20Sopenharmony_ci qtd->status = QTD_RETIRE; 16288c2ecf20Sopenharmony_ci } 16298c2ecf20Sopenharmony_ci 16308c2ecf20Sopenharmony_ci if ((urb->dev->speed != USB_SPEED_HIGH) && urb_was_running) { 16318c2ecf20Sopenharmony_ci qh->tt_buffer_dirty = 1; 16328c2ecf20Sopenharmony_ci if (usb_hub_clear_tt_buffer(urb)) 16338c2ecf20Sopenharmony_ci /* Clear failed; let's hope things work anyway */ 16348c2ecf20Sopenharmony_ci qh->tt_buffer_dirty = 0; 16358c2ecf20Sopenharmony_ci } 16368c2ecf20Sopenharmony_ci} 16378c2ecf20Sopenharmony_ci 16388c2ecf20Sopenharmony_cistatic int isp1760_urb_dequeue(struct usb_hcd *hcd, struct urb *urb, 16398c2ecf20Sopenharmony_ci int status) 16408c2ecf20Sopenharmony_ci{ 16418c2ecf20Sopenharmony_ci struct isp1760_hcd *priv = hcd_to_priv(hcd); 16428c2ecf20Sopenharmony_ci unsigned long spinflags; 16438c2ecf20Sopenharmony_ci struct isp1760_qh *qh; 16448c2ecf20Sopenharmony_ci struct isp1760_qtd *qtd; 16458c2ecf20Sopenharmony_ci int retval = 0; 16468c2ecf20Sopenharmony_ci 16478c2ecf20Sopenharmony_ci spin_lock_irqsave(&priv->lock, spinflags); 16488c2ecf20Sopenharmony_ci retval = usb_hcd_check_unlink_urb(hcd, urb, status); 16498c2ecf20Sopenharmony_ci if (retval) 16508c2ecf20Sopenharmony_ci goto out; 16518c2ecf20Sopenharmony_ci 16528c2ecf20Sopenharmony_ci qh = urb->ep->hcpriv; 16538c2ecf20Sopenharmony_ci if (!qh) { 16548c2ecf20Sopenharmony_ci retval = -EINVAL; 16558c2ecf20Sopenharmony_ci goto out; 16568c2ecf20Sopenharmony_ci } 16578c2ecf20Sopenharmony_ci 16588c2ecf20Sopenharmony_ci list_for_each_entry(qtd, &qh->qtd_list, qtd_list) 16598c2ecf20Sopenharmony_ci if (qtd->urb == urb) { 16608c2ecf20Sopenharmony_ci dequeue_urb_from_qtd(hcd, qh, qtd); 16618c2ecf20Sopenharmony_ci list_move(&qtd->qtd_list, &qh->qtd_list); 16628c2ecf20Sopenharmony_ci break; 16638c2ecf20Sopenharmony_ci } 16648c2ecf20Sopenharmony_ci 16658c2ecf20Sopenharmony_ci urb->status = status; 16668c2ecf20Sopenharmony_ci schedule_ptds(hcd); 16678c2ecf20Sopenharmony_ci 16688c2ecf20Sopenharmony_ciout: 16698c2ecf20Sopenharmony_ci spin_unlock_irqrestore(&priv->lock, spinflags); 16708c2ecf20Sopenharmony_ci return retval; 16718c2ecf20Sopenharmony_ci} 16728c2ecf20Sopenharmony_ci 16738c2ecf20Sopenharmony_cistatic void isp1760_endpoint_disable(struct usb_hcd *hcd, 16748c2ecf20Sopenharmony_ci struct usb_host_endpoint *ep) 16758c2ecf20Sopenharmony_ci{ 16768c2ecf20Sopenharmony_ci struct isp1760_hcd *priv = hcd_to_priv(hcd); 16778c2ecf20Sopenharmony_ci unsigned long spinflags; 16788c2ecf20Sopenharmony_ci struct isp1760_qh *qh, *qh_iter; 16798c2ecf20Sopenharmony_ci int i; 16808c2ecf20Sopenharmony_ci 16818c2ecf20Sopenharmony_ci spin_lock_irqsave(&priv->lock, spinflags); 16828c2ecf20Sopenharmony_ci 16838c2ecf20Sopenharmony_ci qh = ep->hcpriv; 16848c2ecf20Sopenharmony_ci if (!qh) 16858c2ecf20Sopenharmony_ci goto out; 16868c2ecf20Sopenharmony_ci 16878c2ecf20Sopenharmony_ci WARN_ON(!list_empty(&qh->qtd_list)); 16888c2ecf20Sopenharmony_ci 16898c2ecf20Sopenharmony_ci for (i = 0; i < QH_END; i++) 16908c2ecf20Sopenharmony_ci list_for_each_entry(qh_iter, &priv->qh_list[i], qh_list) 16918c2ecf20Sopenharmony_ci if (qh_iter == qh) { 16928c2ecf20Sopenharmony_ci list_del(&qh_iter->qh_list); 16938c2ecf20Sopenharmony_ci i = QH_END; 16948c2ecf20Sopenharmony_ci break; 16958c2ecf20Sopenharmony_ci } 16968c2ecf20Sopenharmony_ci qh_free(qh); 16978c2ecf20Sopenharmony_ci ep->hcpriv = NULL; 16988c2ecf20Sopenharmony_ci 16998c2ecf20Sopenharmony_ci schedule_ptds(hcd); 17008c2ecf20Sopenharmony_ci 17018c2ecf20Sopenharmony_ciout: 17028c2ecf20Sopenharmony_ci spin_unlock_irqrestore(&priv->lock, spinflags); 17038c2ecf20Sopenharmony_ci} 17048c2ecf20Sopenharmony_ci 17058c2ecf20Sopenharmony_cistatic int isp1760_hub_status_data(struct usb_hcd *hcd, char *buf) 17068c2ecf20Sopenharmony_ci{ 17078c2ecf20Sopenharmony_ci struct isp1760_hcd *priv = hcd_to_priv(hcd); 17088c2ecf20Sopenharmony_ci u32 temp, status = 0; 17098c2ecf20Sopenharmony_ci u32 mask; 17108c2ecf20Sopenharmony_ci int retval = 1; 17118c2ecf20Sopenharmony_ci unsigned long flags; 17128c2ecf20Sopenharmony_ci 17138c2ecf20Sopenharmony_ci /* if !PM, root hub timers won't get shut down ... */ 17148c2ecf20Sopenharmony_ci if (!HC_IS_RUNNING(hcd->state)) 17158c2ecf20Sopenharmony_ci return 0; 17168c2ecf20Sopenharmony_ci 17178c2ecf20Sopenharmony_ci /* init status to no-changes */ 17188c2ecf20Sopenharmony_ci buf[0] = 0; 17198c2ecf20Sopenharmony_ci mask = PORT_CSC; 17208c2ecf20Sopenharmony_ci 17218c2ecf20Sopenharmony_ci spin_lock_irqsave(&priv->lock, flags); 17228c2ecf20Sopenharmony_ci temp = reg_read32(hcd->regs, HC_PORTSC1); 17238c2ecf20Sopenharmony_ci 17248c2ecf20Sopenharmony_ci if (temp & PORT_OWNER) { 17258c2ecf20Sopenharmony_ci if (temp & PORT_CSC) { 17268c2ecf20Sopenharmony_ci temp &= ~PORT_CSC; 17278c2ecf20Sopenharmony_ci reg_write32(hcd->regs, HC_PORTSC1, temp); 17288c2ecf20Sopenharmony_ci goto done; 17298c2ecf20Sopenharmony_ci } 17308c2ecf20Sopenharmony_ci } 17318c2ecf20Sopenharmony_ci 17328c2ecf20Sopenharmony_ci /* 17338c2ecf20Sopenharmony_ci * Return status information even for ports with OWNER set. 17348c2ecf20Sopenharmony_ci * Otherwise hub_wq wouldn't see the disconnect event when a 17358c2ecf20Sopenharmony_ci * high-speed device is switched over to the companion 17368c2ecf20Sopenharmony_ci * controller by the user. 17378c2ecf20Sopenharmony_ci */ 17388c2ecf20Sopenharmony_ci 17398c2ecf20Sopenharmony_ci if ((temp & mask) != 0 17408c2ecf20Sopenharmony_ci || ((temp & PORT_RESUME) != 0 17418c2ecf20Sopenharmony_ci && time_after_eq(jiffies, 17428c2ecf20Sopenharmony_ci priv->reset_done))) { 17438c2ecf20Sopenharmony_ci buf [0] |= 1 << (0 + 1); 17448c2ecf20Sopenharmony_ci status = STS_PCD; 17458c2ecf20Sopenharmony_ci } 17468c2ecf20Sopenharmony_ci /* FIXME autosuspend idle root hubs */ 17478c2ecf20Sopenharmony_cidone: 17488c2ecf20Sopenharmony_ci spin_unlock_irqrestore(&priv->lock, flags); 17498c2ecf20Sopenharmony_ci return status ? retval : 0; 17508c2ecf20Sopenharmony_ci} 17518c2ecf20Sopenharmony_ci 17528c2ecf20Sopenharmony_cistatic void isp1760_hub_descriptor(struct isp1760_hcd *priv, 17538c2ecf20Sopenharmony_ci struct usb_hub_descriptor *desc) 17548c2ecf20Sopenharmony_ci{ 17558c2ecf20Sopenharmony_ci int ports = HCS_N_PORTS(priv->hcs_params); 17568c2ecf20Sopenharmony_ci u16 temp; 17578c2ecf20Sopenharmony_ci 17588c2ecf20Sopenharmony_ci desc->bDescriptorType = USB_DT_HUB; 17598c2ecf20Sopenharmony_ci /* priv 1.0, 2.3.9 says 20ms max */ 17608c2ecf20Sopenharmony_ci desc->bPwrOn2PwrGood = 10; 17618c2ecf20Sopenharmony_ci desc->bHubContrCurrent = 0; 17628c2ecf20Sopenharmony_ci 17638c2ecf20Sopenharmony_ci desc->bNbrPorts = ports; 17648c2ecf20Sopenharmony_ci temp = 1 + (ports / 8); 17658c2ecf20Sopenharmony_ci desc->bDescLength = 7 + 2 * temp; 17668c2ecf20Sopenharmony_ci 17678c2ecf20Sopenharmony_ci /* ports removable, and usb 1.0 legacy PortPwrCtrlMask */ 17688c2ecf20Sopenharmony_ci memset(&desc->u.hs.DeviceRemovable[0], 0, temp); 17698c2ecf20Sopenharmony_ci memset(&desc->u.hs.DeviceRemovable[temp], 0xff, temp); 17708c2ecf20Sopenharmony_ci 17718c2ecf20Sopenharmony_ci /* per-port overcurrent reporting */ 17728c2ecf20Sopenharmony_ci temp = HUB_CHAR_INDV_PORT_OCPM; 17738c2ecf20Sopenharmony_ci if (HCS_PPC(priv->hcs_params)) 17748c2ecf20Sopenharmony_ci /* per-port power control */ 17758c2ecf20Sopenharmony_ci temp |= HUB_CHAR_INDV_PORT_LPSM; 17768c2ecf20Sopenharmony_ci else 17778c2ecf20Sopenharmony_ci /* no power switching */ 17788c2ecf20Sopenharmony_ci temp |= HUB_CHAR_NO_LPSM; 17798c2ecf20Sopenharmony_ci desc->wHubCharacteristics = cpu_to_le16(temp); 17808c2ecf20Sopenharmony_ci} 17818c2ecf20Sopenharmony_ci 17828c2ecf20Sopenharmony_ci#define PORT_WAKE_BITS (PORT_WKOC_E|PORT_WKDISC_E|PORT_WKCONN_E) 17838c2ecf20Sopenharmony_ci 17848c2ecf20Sopenharmony_cistatic int check_reset_complete(struct usb_hcd *hcd, int index, 17858c2ecf20Sopenharmony_ci int port_status) 17868c2ecf20Sopenharmony_ci{ 17878c2ecf20Sopenharmony_ci if (!(port_status & PORT_CONNECT)) 17888c2ecf20Sopenharmony_ci return port_status; 17898c2ecf20Sopenharmony_ci 17908c2ecf20Sopenharmony_ci /* if reset finished and it's still not enabled -- handoff */ 17918c2ecf20Sopenharmony_ci if (!(port_status & PORT_PE)) { 17928c2ecf20Sopenharmony_ci 17938c2ecf20Sopenharmony_ci dev_info(hcd->self.controller, 17948c2ecf20Sopenharmony_ci "port %d full speed --> companion\n", 17958c2ecf20Sopenharmony_ci index + 1); 17968c2ecf20Sopenharmony_ci 17978c2ecf20Sopenharmony_ci port_status |= PORT_OWNER; 17988c2ecf20Sopenharmony_ci port_status &= ~PORT_RWC_BITS; 17998c2ecf20Sopenharmony_ci reg_write32(hcd->regs, HC_PORTSC1, port_status); 18008c2ecf20Sopenharmony_ci 18018c2ecf20Sopenharmony_ci } else 18028c2ecf20Sopenharmony_ci dev_info(hcd->self.controller, "port %d high speed\n", 18038c2ecf20Sopenharmony_ci index + 1); 18048c2ecf20Sopenharmony_ci 18058c2ecf20Sopenharmony_ci return port_status; 18068c2ecf20Sopenharmony_ci} 18078c2ecf20Sopenharmony_ci 18088c2ecf20Sopenharmony_cistatic int isp1760_hub_control(struct usb_hcd *hcd, u16 typeReq, 18098c2ecf20Sopenharmony_ci u16 wValue, u16 wIndex, char *buf, u16 wLength) 18108c2ecf20Sopenharmony_ci{ 18118c2ecf20Sopenharmony_ci struct isp1760_hcd *priv = hcd_to_priv(hcd); 18128c2ecf20Sopenharmony_ci int ports = HCS_N_PORTS(priv->hcs_params); 18138c2ecf20Sopenharmony_ci u32 temp, status; 18148c2ecf20Sopenharmony_ci unsigned long flags; 18158c2ecf20Sopenharmony_ci int retval = 0; 18168c2ecf20Sopenharmony_ci 18178c2ecf20Sopenharmony_ci /* 18188c2ecf20Sopenharmony_ci * FIXME: support SetPortFeatures USB_PORT_FEAT_INDICATOR. 18198c2ecf20Sopenharmony_ci * HCS_INDICATOR may say we can change LEDs to off/amber/green. 18208c2ecf20Sopenharmony_ci * (track current state ourselves) ... blink for diagnostics, 18218c2ecf20Sopenharmony_ci * power, "this is the one", etc. EHCI spec supports this. 18228c2ecf20Sopenharmony_ci */ 18238c2ecf20Sopenharmony_ci 18248c2ecf20Sopenharmony_ci spin_lock_irqsave(&priv->lock, flags); 18258c2ecf20Sopenharmony_ci switch (typeReq) { 18268c2ecf20Sopenharmony_ci case ClearHubFeature: 18278c2ecf20Sopenharmony_ci switch (wValue) { 18288c2ecf20Sopenharmony_ci case C_HUB_LOCAL_POWER: 18298c2ecf20Sopenharmony_ci case C_HUB_OVER_CURRENT: 18308c2ecf20Sopenharmony_ci /* no hub-wide feature/status flags */ 18318c2ecf20Sopenharmony_ci break; 18328c2ecf20Sopenharmony_ci default: 18338c2ecf20Sopenharmony_ci goto error; 18348c2ecf20Sopenharmony_ci } 18358c2ecf20Sopenharmony_ci break; 18368c2ecf20Sopenharmony_ci case ClearPortFeature: 18378c2ecf20Sopenharmony_ci if (!wIndex || wIndex > ports) 18388c2ecf20Sopenharmony_ci goto error; 18398c2ecf20Sopenharmony_ci wIndex--; 18408c2ecf20Sopenharmony_ci temp = reg_read32(hcd->regs, HC_PORTSC1); 18418c2ecf20Sopenharmony_ci 18428c2ecf20Sopenharmony_ci /* 18438c2ecf20Sopenharmony_ci * Even if OWNER is set, so the port is owned by the 18448c2ecf20Sopenharmony_ci * companion controller, hub_wq needs to be able to clear 18458c2ecf20Sopenharmony_ci * the port-change status bits (especially 18468c2ecf20Sopenharmony_ci * USB_PORT_STAT_C_CONNECTION). 18478c2ecf20Sopenharmony_ci */ 18488c2ecf20Sopenharmony_ci 18498c2ecf20Sopenharmony_ci switch (wValue) { 18508c2ecf20Sopenharmony_ci case USB_PORT_FEAT_ENABLE: 18518c2ecf20Sopenharmony_ci reg_write32(hcd->regs, HC_PORTSC1, temp & ~PORT_PE); 18528c2ecf20Sopenharmony_ci break; 18538c2ecf20Sopenharmony_ci case USB_PORT_FEAT_C_ENABLE: 18548c2ecf20Sopenharmony_ci /* XXX error? */ 18558c2ecf20Sopenharmony_ci break; 18568c2ecf20Sopenharmony_ci case USB_PORT_FEAT_SUSPEND: 18578c2ecf20Sopenharmony_ci if (temp & PORT_RESET) 18588c2ecf20Sopenharmony_ci goto error; 18598c2ecf20Sopenharmony_ci 18608c2ecf20Sopenharmony_ci if (temp & PORT_SUSPEND) { 18618c2ecf20Sopenharmony_ci if ((temp & PORT_PE) == 0) 18628c2ecf20Sopenharmony_ci goto error; 18638c2ecf20Sopenharmony_ci /* resume signaling for 20 msec */ 18648c2ecf20Sopenharmony_ci temp &= ~(PORT_RWC_BITS); 18658c2ecf20Sopenharmony_ci reg_write32(hcd->regs, HC_PORTSC1, 18668c2ecf20Sopenharmony_ci temp | PORT_RESUME); 18678c2ecf20Sopenharmony_ci priv->reset_done = jiffies + 18688c2ecf20Sopenharmony_ci msecs_to_jiffies(USB_RESUME_TIMEOUT); 18698c2ecf20Sopenharmony_ci } 18708c2ecf20Sopenharmony_ci break; 18718c2ecf20Sopenharmony_ci case USB_PORT_FEAT_C_SUSPEND: 18728c2ecf20Sopenharmony_ci /* we auto-clear this feature */ 18738c2ecf20Sopenharmony_ci break; 18748c2ecf20Sopenharmony_ci case USB_PORT_FEAT_POWER: 18758c2ecf20Sopenharmony_ci if (HCS_PPC(priv->hcs_params)) 18768c2ecf20Sopenharmony_ci reg_write32(hcd->regs, HC_PORTSC1, 18778c2ecf20Sopenharmony_ci temp & ~PORT_POWER); 18788c2ecf20Sopenharmony_ci break; 18798c2ecf20Sopenharmony_ci case USB_PORT_FEAT_C_CONNECTION: 18808c2ecf20Sopenharmony_ci reg_write32(hcd->regs, HC_PORTSC1, temp | PORT_CSC); 18818c2ecf20Sopenharmony_ci break; 18828c2ecf20Sopenharmony_ci case USB_PORT_FEAT_C_OVER_CURRENT: 18838c2ecf20Sopenharmony_ci /* XXX error ?*/ 18848c2ecf20Sopenharmony_ci break; 18858c2ecf20Sopenharmony_ci case USB_PORT_FEAT_C_RESET: 18868c2ecf20Sopenharmony_ci /* GetPortStatus clears reset */ 18878c2ecf20Sopenharmony_ci break; 18888c2ecf20Sopenharmony_ci default: 18898c2ecf20Sopenharmony_ci goto error; 18908c2ecf20Sopenharmony_ci } 18918c2ecf20Sopenharmony_ci reg_read32(hcd->regs, HC_USBCMD); 18928c2ecf20Sopenharmony_ci break; 18938c2ecf20Sopenharmony_ci case GetHubDescriptor: 18948c2ecf20Sopenharmony_ci isp1760_hub_descriptor(priv, (struct usb_hub_descriptor *) 18958c2ecf20Sopenharmony_ci buf); 18968c2ecf20Sopenharmony_ci break; 18978c2ecf20Sopenharmony_ci case GetHubStatus: 18988c2ecf20Sopenharmony_ci /* no hub-wide feature/status flags */ 18998c2ecf20Sopenharmony_ci memset(buf, 0, 4); 19008c2ecf20Sopenharmony_ci break; 19018c2ecf20Sopenharmony_ci case GetPortStatus: 19028c2ecf20Sopenharmony_ci if (!wIndex || wIndex > ports) 19038c2ecf20Sopenharmony_ci goto error; 19048c2ecf20Sopenharmony_ci wIndex--; 19058c2ecf20Sopenharmony_ci status = 0; 19068c2ecf20Sopenharmony_ci temp = reg_read32(hcd->regs, HC_PORTSC1); 19078c2ecf20Sopenharmony_ci 19088c2ecf20Sopenharmony_ci /* wPortChange bits */ 19098c2ecf20Sopenharmony_ci if (temp & PORT_CSC) 19108c2ecf20Sopenharmony_ci status |= USB_PORT_STAT_C_CONNECTION << 16; 19118c2ecf20Sopenharmony_ci 19128c2ecf20Sopenharmony_ci 19138c2ecf20Sopenharmony_ci /* whoever resumes must GetPortStatus to complete it!! */ 19148c2ecf20Sopenharmony_ci if (temp & PORT_RESUME) { 19158c2ecf20Sopenharmony_ci dev_err(hcd->self.controller, "Port resume should be skipped.\n"); 19168c2ecf20Sopenharmony_ci 19178c2ecf20Sopenharmony_ci /* Remote Wakeup received? */ 19188c2ecf20Sopenharmony_ci if (!priv->reset_done) { 19198c2ecf20Sopenharmony_ci /* resume signaling for 20 msec */ 19208c2ecf20Sopenharmony_ci priv->reset_done = jiffies 19218c2ecf20Sopenharmony_ci + msecs_to_jiffies(20); 19228c2ecf20Sopenharmony_ci /* check the port again */ 19238c2ecf20Sopenharmony_ci mod_timer(&hcd->rh_timer, priv->reset_done); 19248c2ecf20Sopenharmony_ci } 19258c2ecf20Sopenharmony_ci 19268c2ecf20Sopenharmony_ci /* resume completed? */ 19278c2ecf20Sopenharmony_ci else if (time_after_eq(jiffies, 19288c2ecf20Sopenharmony_ci priv->reset_done)) { 19298c2ecf20Sopenharmony_ci status |= USB_PORT_STAT_C_SUSPEND << 16; 19308c2ecf20Sopenharmony_ci priv->reset_done = 0; 19318c2ecf20Sopenharmony_ci 19328c2ecf20Sopenharmony_ci /* stop resume signaling */ 19338c2ecf20Sopenharmony_ci temp = reg_read32(hcd->regs, HC_PORTSC1); 19348c2ecf20Sopenharmony_ci reg_write32(hcd->regs, HC_PORTSC1, 19358c2ecf20Sopenharmony_ci temp & ~(PORT_RWC_BITS | PORT_RESUME)); 19368c2ecf20Sopenharmony_ci retval = handshake(hcd, HC_PORTSC1, 19378c2ecf20Sopenharmony_ci PORT_RESUME, 0, 2000 /* 2msec */); 19388c2ecf20Sopenharmony_ci if (retval != 0) { 19398c2ecf20Sopenharmony_ci dev_err(hcd->self.controller, 19408c2ecf20Sopenharmony_ci "port %d resume error %d\n", 19418c2ecf20Sopenharmony_ci wIndex + 1, retval); 19428c2ecf20Sopenharmony_ci goto error; 19438c2ecf20Sopenharmony_ci } 19448c2ecf20Sopenharmony_ci temp &= ~(PORT_SUSPEND|PORT_RESUME|(3<<10)); 19458c2ecf20Sopenharmony_ci } 19468c2ecf20Sopenharmony_ci } 19478c2ecf20Sopenharmony_ci 19488c2ecf20Sopenharmony_ci /* whoever resets must GetPortStatus to complete it!! */ 19498c2ecf20Sopenharmony_ci if ((temp & PORT_RESET) 19508c2ecf20Sopenharmony_ci && time_after_eq(jiffies, 19518c2ecf20Sopenharmony_ci priv->reset_done)) { 19528c2ecf20Sopenharmony_ci status |= USB_PORT_STAT_C_RESET << 16; 19538c2ecf20Sopenharmony_ci priv->reset_done = 0; 19548c2ecf20Sopenharmony_ci 19558c2ecf20Sopenharmony_ci /* force reset to complete */ 19568c2ecf20Sopenharmony_ci reg_write32(hcd->regs, HC_PORTSC1, temp & ~PORT_RESET); 19578c2ecf20Sopenharmony_ci /* REVISIT: some hardware needs 550+ usec to clear 19588c2ecf20Sopenharmony_ci * this bit; seems too long to spin routinely... 19598c2ecf20Sopenharmony_ci */ 19608c2ecf20Sopenharmony_ci retval = handshake(hcd, HC_PORTSC1, 19618c2ecf20Sopenharmony_ci PORT_RESET, 0, 750); 19628c2ecf20Sopenharmony_ci if (retval != 0) { 19638c2ecf20Sopenharmony_ci dev_err(hcd->self.controller, "port %d reset error %d\n", 19648c2ecf20Sopenharmony_ci wIndex + 1, retval); 19658c2ecf20Sopenharmony_ci goto error; 19668c2ecf20Sopenharmony_ci } 19678c2ecf20Sopenharmony_ci 19688c2ecf20Sopenharmony_ci /* see what we found out */ 19698c2ecf20Sopenharmony_ci temp = check_reset_complete(hcd, wIndex, 19708c2ecf20Sopenharmony_ci reg_read32(hcd->regs, HC_PORTSC1)); 19718c2ecf20Sopenharmony_ci } 19728c2ecf20Sopenharmony_ci /* 19738c2ecf20Sopenharmony_ci * Even if OWNER is set, there's no harm letting hub_wq 19748c2ecf20Sopenharmony_ci * see the wPortStatus values (they should all be 0 except 19758c2ecf20Sopenharmony_ci * for PORT_POWER anyway). 19768c2ecf20Sopenharmony_ci */ 19778c2ecf20Sopenharmony_ci 19788c2ecf20Sopenharmony_ci if (temp & PORT_OWNER) 19798c2ecf20Sopenharmony_ci dev_err(hcd->self.controller, "PORT_OWNER is set\n"); 19808c2ecf20Sopenharmony_ci 19818c2ecf20Sopenharmony_ci if (temp & PORT_CONNECT) { 19828c2ecf20Sopenharmony_ci status |= USB_PORT_STAT_CONNECTION; 19838c2ecf20Sopenharmony_ci /* status may be from integrated TT */ 19848c2ecf20Sopenharmony_ci status |= USB_PORT_STAT_HIGH_SPEED; 19858c2ecf20Sopenharmony_ci } 19868c2ecf20Sopenharmony_ci if (temp & PORT_PE) 19878c2ecf20Sopenharmony_ci status |= USB_PORT_STAT_ENABLE; 19888c2ecf20Sopenharmony_ci if (temp & (PORT_SUSPEND|PORT_RESUME)) 19898c2ecf20Sopenharmony_ci status |= USB_PORT_STAT_SUSPEND; 19908c2ecf20Sopenharmony_ci if (temp & PORT_RESET) 19918c2ecf20Sopenharmony_ci status |= USB_PORT_STAT_RESET; 19928c2ecf20Sopenharmony_ci if (temp & PORT_POWER) 19938c2ecf20Sopenharmony_ci status |= USB_PORT_STAT_POWER; 19948c2ecf20Sopenharmony_ci 19958c2ecf20Sopenharmony_ci put_unaligned(cpu_to_le32(status), (__le32 *) buf); 19968c2ecf20Sopenharmony_ci break; 19978c2ecf20Sopenharmony_ci case SetHubFeature: 19988c2ecf20Sopenharmony_ci switch (wValue) { 19998c2ecf20Sopenharmony_ci case C_HUB_LOCAL_POWER: 20008c2ecf20Sopenharmony_ci case C_HUB_OVER_CURRENT: 20018c2ecf20Sopenharmony_ci /* no hub-wide feature/status flags */ 20028c2ecf20Sopenharmony_ci break; 20038c2ecf20Sopenharmony_ci default: 20048c2ecf20Sopenharmony_ci goto error; 20058c2ecf20Sopenharmony_ci } 20068c2ecf20Sopenharmony_ci break; 20078c2ecf20Sopenharmony_ci case SetPortFeature: 20088c2ecf20Sopenharmony_ci wIndex &= 0xff; 20098c2ecf20Sopenharmony_ci if (!wIndex || wIndex > ports) 20108c2ecf20Sopenharmony_ci goto error; 20118c2ecf20Sopenharmony_ci wIndex--; 20128c2ecf20Sopenharmony_ci temp = reg_read32(hcd->regs, HC_PORTSC1); 20138c2ecf20Sopenharmony_ci if (temp & PORT_OWNER) 20148c2ecf20Sopenharmony_ci break; 20158c2ecf20Sopenharmony_ci 20168c2ecf20Sopenharmony_ci/* temp &= ~PORT_RWC_BITS; */ 20178c2ecf20Sopenharmony_ci switch (wValue) { 20188c2ecf20Sopenharmony_ci case USB_PORT_FEAT_ENABLE: 20198c2ecf20Sopenharmony_ci reg_write32(hcd->regs, HC_PORTSC1, temp | PORT_PE); 20208c2ecf20Sopenharmony_ci break; 20218c2ecf20Sopenharmony_ci 20228c2ecf20Sopenharmony_ci case USB_PORT_FEAT_SUSPEND: 20238c2ecf20Sopenharmony_ci if ((temp & PORT_PE) == 0 20248c2ecf20Sopenharmony_ci || (temp & PORT_RESET) != 0) 20258c2ecf20Sopenharmony_ci goto error; 20268c2ecf20Sopenharmony_ci 20278c2ecf20Sopenharmony_ci reg_write32(hcd->regs, HC_PORTSC1, temp | PORT_SUSPEND); 20288c2ecf20Sopenharmony_ci break; 20298c2ecf20Sopenharmony_ci case USB_PORT_FEAT_POWER: 20308c2ecf20Sopenharmony_ci if (HCS_PPC(priv->hcs_params)) 20318c2ecf20Sopenharmony_ci reg_write32(hcd->regs, HC_PORTSC1, 20328c2ecf20Sopenharmony_ci temp | PORT_POWER); 20338c2ecf20Sopenharmony_ci break; 20348c2ecf20Sopenharmony_ci case USB_PORT_FEAT_RESET: 20358c2ecf20Sopenharmony_ci if (temp & PORT_RESUME) 20368c2ecf20Sopenharmony_ci goto error; 20378c2ecf20Sopenharmony_ci /* line status bits may report this as low speed, 20388c2ecf20Sopenharmony_ci * which can be fine if this root hub has a 20398c2ecf20Sopenharmony_ci * transaction translator built in. 20408c2ecf20Sopenharmony_ci */ 20418c2ecf20Sopenharmony_ci if ((temp & (PORT_PE|PORT_CONNECT)) == PORT_CONNECT 20428c2ecf20Sopenharmony_ci && PORT_USB11(temp)) { 20438c2ecf20Sopenharmony_ci temp |= PORT_OWNER; 20448c2ecf20Sopenharmony_ci } else { 20458c2ecf20Sopenharmony_ci temp |= PORT_RESET; 20468c2ecf20Sopenharmony_ci temp &= ~PORT_PE; 20478c2ecf20Sopenharmony_ci 20488c2ecf20Sopenharmony_ci /* 20498c2ecf20Sopenharmony_ci * caller must wait, then call GetPortStatus 20508c2ecf20Sopenharmony_ci * usb 2.0 spec says 50 ms resets on root 20518c2ecf20Sopenharmony_ci */ 20528c2ecf20Sopenharmony_ci priv->reset_done = jiffies + 20538c2ecf20Sopenharmony_ci msecs_to_jiffies(50); 20548c2ecf20Sopenharmony_ci } 20558c2ecf20Sopenharmony_ci reg_write32(hcd->regs, HC_PORTSC1, temp); 20568c2ecf20Sopenharmony_ci break; 20578c2ecf20Sopenharmony_ci default: 20588c2ecf20Sopenharmony_ci goto error; 20598c2ecf20Sopenharmony_ci } 20608c2ecf20Sopenharmony_ci reg_read32(hcd->regs, HC_USBCMD); 20618c2ecf20Sopenharmony_ci break; 20628c2ecf20Sopenharmony_ci 20638c2ecf20Sopenharmony_ci default: 20648c2ecf20Sopenharmony_cierror: 20658c2ecf20Sopenharmony_ci /* "stall" on error */ 20668c2ecf20Sopenharmony_ci retval = -EPIPE; 20678c2ecf20Sopenharmony_ci } 20688c2ecf20Sopenharmony_ci spin_unlock_irqrestore(&priv->lock, flags); 20698c2ecf20Sopenharmony_ci return retval; 20708c2ecf20Sopenharmony_ci} 20718c2ecf20Sopenharmony_ci 20728c2ecf20Sopenharmony_cistatic int isp1760_get_frame(struct usb_hcd *hcd) 20738c2ecf20Sopenharmony_ci{ 20748c2ecf20Sopenharmony_ci struct isp1760_hcd *priv = hcd_to_priv(hcd); 20758c2ecf20Sopenharmony_ci u32 fr; 20768c2ecf20Sopenharmony_ci 20778c2ecf20Sopenharmony_ci fr = reg_read32(hcd->regs, HC_FRINDEX); 20788c2ecf20Sopenharmony_ci return (fr >> 3) % priv->periodic_size; 20798c2ecf20Sopenharmony_ci} 20808c2ecf20Sopenharmony_ci 20818c2ecf20Sopenharmony_cistatic void isp1760_stop(struct usb_hcd *hcd) 20828c2ecf20Sopenharmony_ci{ 20838c2ecf20Sopenharmony_ci struct isp1760_hcd *priv = hcd_to_priv(hcd); 20848c2ecf20Sopenharmony_ci u32 temp; 20858c2ecf20Sopenharmony_ci 20868c2ecf20Sopenharmony_ci del_timer(&errata2_timer); 20878c2ecf20Sopenharmony_ci 20888c2ecf20Sopenharmony_ci isp1760_hub_control(hcd, ClearPortFeature, USB_PORT_FEAT_POWER, 1, 20898c2ecf20Sopenharmony_ci NULL, 0); 20908c2ecf20Sopenharmony_ci msleep(20); 20918c2ecf20Sopenharmony_ci 20928c2ecf20Sopenharmony_ci spin_lock_irq(&priv->lock); 20938c2ecf20Sopenharmony_ci ehci_reset(hcd); 20948c2ecf20Sopenharmony_ci /* Disable IRQ */ 20958c2ecf20Sopenharmony_ci temp = reg_read32(hcd->regs, HC_HW_MODE_CTRL); 20968c2ecf20Sopenharmony_ci reg_write32(hcd->regs, HC_HW_MODE_CTRL, temp &= ~HW_GLOBAL_INTR_EN); 20978c2ecf20Sopenharmony_ci spin_unlock_irq(&priv->lock); 20988c2ecf20Sopenharmony_ci 20998c2ecf20Sopenharmony_ci reg_write32(hcd->regs, HC_CONFIGFLAG, 0); 21008c2ecf20Sopenharmony_ci} 21018c2ecf20Sopenharmony_ci 21028c2ecf20Sopenharmony_cistatic void isp1760_shutdown(struct usb_hcd *hcd) 21038c2ecf20Sopenharmony_ci{ 21048c2ecf20Sopenharmony_ci u32 command, temp; 21058c2ecf20Sopenharmony_ci 21068c2ecf20Sopenharmony_ci isp1760_stop(hcd); 21078c2ecf20Sopenharmony_ci temp = reg_read32(hcd->regs, HC_HW_MODE_CTRL); 21088c2ecf20Sopenharmony_ci reg_write32(hcd->regs, HC_HW_MODE_CTRL, temp &= ~HW_GLOBAL_INTR_EN); 21098c2ecf20Sopenharmony_ci 21108c2ecf20Sopenharmony_ci command = reg_read32(hcd->regs, HC_USBCMD); 21118c2ecf20Sopenharmony_ci command &= ~CMD_RUN; 21128c2ecf20Sopenharmony_ci reg_write32(hcd->regs, HC_USBCMD, command); 21138c2ecf20Sopenharmony_ci} 21148c2ecf20Sopenharmony_ci 21158c2ecf20Sopenharmony_cistatic void isp1760_clear_tt_buffer_complete(struct usb_hcd *hcd, 21168c2ecf20Sopenharmony_ci struct usb_host_endpoint *ep) 21178c2ecf20Sopenharmony_ci{ 21188c2ecf20Sopenharmony_ci struct isp1760_hcd *priv = hcd_to_priv(hcd); 21198c2ecf20Sopenharmony_ci struct isp1760_qh *qh = ep->hcpriv; 21208c2ecf20Sopenharmony_ci unsigned long spinflags; 21218c2ecf20Sopenharmony_ci 21228c2ecf20Sopenharmony_ci if (!qh) 21238c2ecf20Sopenharmony_ci return; 21248c2ecf20Sopenharmony_ci 21258c2ecf20Sopenharmony_ci spin_lock_irqsave(&priv->lock, spinflags); 21268c2ecf20Sopenharmony_ci qh->tt_buffer_dirty = 0; 21278c2ecf20Sopenharmony_ci schedule_ptds(hcd); 21288c2ecf20Sopenharmony_ci spin_unlock_irqrestore(&priv->lock, spinflags); 21298c2ecf20Sopenharmony_ci} 21308c2ecf20Sopenharmony_ci 21318c2ecf20Sopenharmony_ci 21328c2ecf20Sopenharmony_cistatic const struct hc_driver isp1760_hc_driver = { 21338c2ecf20Sopenharmony_ci .description = "isp1760-hcd", 21348c2ecf20Sopenharmony_ci .product_desc = "NXP ISP1760 USB Host Controller", 21358c2ecf20Sopenharmony_ci .hcd_priv_size = sizeof(struct isp1760_hcd *), 21368c2ecf20Sopenharmony_ci .irq = isp1760_irq, 21378c2ecf20Sopenharmony_ci .flags = HCD_MEMORY | HCD_USB2, 21388c2ecf20Sopenharmony_ci .reset = isp1760_hc_setup, 21398c2ecf20Sopenharmony_ci .start = isp1760_run, 21408c2ecf20Sopenharmony_ci .stop = isp1760_stop, 21418c2ecf20Sopenharmony_ci .shutdown = isp1760_shutdown, 21428c2ecf20Sopenharmony_ci .urb_enqueue = isp1760_urb_enqueue, 21438c2ecf20Sopenharmony_ci .urb_dequeue = isp1760_urb_dequeue, 21448c2ecf20Sopenharmony_ci .endpoint_disable = isp1760_endpoint_disable, 21458c2ecf20Sopenharmony_ci .get_frame_number = isp1760_get_frame, 21468c2ecf20Sopenharmony_ci .hub_status_data = isp1760_hub_status_data, 21478c2ecf20Sopenharmony_ci .hub_control = isp1760_hub_control, 21488c2ecf20Sopenharmony_ci .clear_tt_buffer_complete = isp1760_clear_tt_buffer_complete, 21498c2ecf20Sopenharmony_ci}; 21508c2ecf20Sopenharmony_ci 21518c2ecf20Sopenharmony_ciint __init isp1760_init_kmem_once(void) 21528c2ecf20Sopenharmony_ci{ 21538c2ecf20Sopenharmony_ci urb_listitem_cachep = kmem_cache_create("isp1760_urb_listitem", 21548c2ecf20Sopenharmony_ci sizeof(struct urb_listitem), 0, SLAB_TEMPORARY | 21558c2ecf20Sopenharmony_ci SLAB_MEM_SPREAD, NULL); 21568c2ecf20Sopenharmony_ci 21578c2ecf20Sopenharmony_ci if (!urb_listitem_cachep) 21588c2ecf20Sopenharmony_ci return -ENOMEM; 21598c2ecf20Sopenharmony_ci 21608c2ecf20Sopenharmony_ci qtd_cachep = kmem_cache_create("isp1760_qtd", 21618c2ecf20Sopenharmony_ci sizeof(struct isp1760_qtd), 0, SLAB_TEMPORARY | 21628c2ecf20Sopenharmony_ci SLAB_MEM_SPREAD, NULL); 21638c2ecf20Sopenharmony_ci 21648c2ecf20Sopenharmony_ci if (!qtd_cachep) 21658c2ecf20Sopenharmony_ci return -ENOMEM; 21668c2ecf20Sopenharmony_ci 21678c2ecf20Sopenharmony_ci qh_cachep = kmem_cache_create("isp1760_qh", sizeof(struct isp1760_qh), 21688c2ecf20Sopenharmony_ci 0, SLAB_TEMPORARY | SLAB_MEM_SPREAD, NULL); 21698c2ecf20Sopenharmony_ci 21708c2ecf20Sopenharmony_ci if (!qh_cachep) { 21718c2ecf20Sopenharmony_ci kmem_cache_destroy(qtd_cachep); 21728c2ecf20Sopenharmony_ci return -ENOMEM; 21738c2ecf20Sopenharmony_ci } 21748c2ecf20Sopenharmony_ci 21758c2ecf20Sopenharmony_ci return 0; 21768c2ecf20Sopenharmony_ci} 21778c2ecf20Sopenharmony_ci 21788c2ecf20Sopenharmony_civoid isp1760_deinit_kmem_cache(void) 21798c2ecf20Sopenharmony_ci{ 21808c2ecf20Sopenharmony_ci kmem_cache_destroy(qtd_cachep); 21818c2ecf20Sopenharmony_ci kmem_cache_destroy(qh_cachep); 21828c2ecf20Sopenharmony_ci kmem_cache_destroy(urb_listitem_cachep); 21838c2ecf20Sopenharmony_ci} 21848c2ecf20Sopenharmony_ci 21858c2ecf20Sopenharmony_ciint isp1760_hcd_register(struct isp1760_hcd *priv, void __iomem *regs, 21868c2ecf20Sopenharmony_ci struct resource *mem, int irq, unsigned long irqflags, 21878c2ecf20Sopenharmony_ci struct device *dev) 21888c2ecf20Sopenharmony_ci{ 21898c2ecf20Sopenharmony_ci struct usb_hcd *hcd; 21908c2ecf20Sopenharmony_ci int ret; 21918c2ecf20Sopenharmony_ci 21928c2ecf20Sopenharmony_ci hcd = usb_create_hcd(&isp1760_hc_driver, dev, dev_name(dev)); 21938c2ecf20Sopenharmony_ci if (!hcd) 21948c2ecf20Sopenharmony_ci return -ENOMEM; 21958c2ecf20Sopenharmony_ci 21968c2ecf20Sopenharmony_ci *(struct isp1760_hcd **)hcd->hcd_priv = priv; 21978c2ecf20Sopenharmony_ci 21988c2ecf20Sopenharmony_ci priv->hcd = hcd; 21998c2ecf20Sopenharmony_ci 22008c2ecf20Sopenharmony_ci init_memory(priv); 22018c2ecf20Sopenharmony_ci 22028c2ecf20Sopenharmony_ci hcd->irq = irq; 22038c2ecf20Sopenharmony_ci hcd->regs = regs; 22048c2ecf20Sopenharmony_ci hcd->rsrc_start = mem->start; 22058c2ecf20Sopenharmony_ci hcd->rsrc_len = resource_size(mem); 22068c2ecf20Sopenharmony_ci 22078c2ecf20Sopenharmony_ci /* This driver doesn't support wakeup requests */ 22088c2ecf20Sopenharmony_ci hcd->cant_recv_wakeups = 1; 22098c2ecf20Sopenharmony_ci 22108c2ecf20Sopenharmony_ci ret = usb_add_hcd(hcd, irq, irqflags); 22118c2ecf20Sopenharmony_ci if (ret) 22128c2ecf20Sopenharmony_ci goto error; 22138c2ecf20Sopenharmony_ci 22148c2ecf20Sopenharmony_ci device_wakeup_enable(hcd->self.controller); 22158c2ecf20Sopenharmony_ci 22168c2ecf20Sopenharmony_ci return 0; 22178c2ecf20Sopenharmony_ci 22188c2ecf20Sopenharmony_cierror: 22198c2ecf20Sopenharmony_ci usb_put_hcd(hcd); 22208c2ecf20Sopenharmony_ci return ret; 22218c2ecf20Sopenharmony_ci} 22228c2ecf20Sopenharmony_ci 22238c2ecf20Sopenharmony_civoid isp1760_hcd_unregister(struct isp1760_hcd *priv) 22248c2ecf20Sopenharmony_ci{ 22258c2ecf20Sopenharmony_ci if (!priv->hcd) 22268c2ecf20Sopenharmony_ci return; 22278c2ecf20Sopenharmony_ci 22288c2ecf20Sopenharmony_ci usb_remove_hcd(priv->hcd); 22298c2ecf20Sopenharmony_ci usb_put_hcd(priv->hcd); 22308c2ecf20Sopenharmony_ci} 2231