1*53ee8cc1Swenshuai.xi //<MStar Software>
2*53ee8cc1Swenshuai.xi //******************************************************************************
3*53ee8cc1Swenshuai.xi // MStar Software
4*53ee8cc1Swenshuai.xi // Copyright (c) 2010 - 2012 MStar Semiconductor, Inc. All rights reserved.
5*53ee8cc1Swenshuai.xi // All software, firmware and related documentation herein ("MStar Software") are
6*53ee8cc1Swenshuai.xi // intellectual property of MStar Semiconductor, Inc. ("MStar") and protected by
7*53ee8cc1Swenshuai.xi // law, including, but not limited to, copyright law and international treaties.
8*53ee8cc1Swenshuai.xi // Any use, modification, reproduction, retransmission, or republication of all
9*53ee8cc1Swenshuai.xi // or part of MStar Software is expressly prohibited, unless prior written
10*53ee8cc1Swenshuai.xi // permission has been granted by MStar.
11*53ee8cc1Swenshuai.xi //
12*53ee8cc1Swenshuai.xi // By accessing, browsing and/or using MStar Software, you acknowledge that you
13*53ee8cc1Swenshuai.xi // have read, understood, and agree, to be bound by below terms ("Terms") and to
14*53ee8cc1Swenshuai.xi // comply with all applicable laws and regulations:
15*53ee8cc1Swenshuai.xi //
16*53ee8cc1Swenshuai.xi // 1. MStar shall retain any and all right, ownership and interest to MStar
17*53ee8cc1Swenshuai.xi // Software and any modification/derivatives thereof.
18*53ee8cc1Swenshuai.xi // No right, ownership, or interest to MStar Software and any
19*53ee8cc1Swenshuai.xi // modification/derivatives thereof is transferred to you under Terms.
20*53ee8cc1Swenshuai.xi //
21*53ee8cc1Swenshuai.xi // 2. You understand that MStar Software might include, incorporate or be
22*53ee8cc1Swenshuai.xi // supplied together with third party`s software and the use of MStar
23*53ee8cc1Swenshuai.xi // Software may require additional licenses from third parties.
24*53ee8cc1Swenshuai.xi // Therefore, you hereby agree it is your sole responsibility to separately
25*53ee8cc1Swenshuai.xi // obtain any and all third party right and license necessary for your use of
26*53ee8cc1Swenshuai.xi // such third party`s software.
27*53ee8cc1Swenshuai.xi //
28*53ee8cc1Swenshuai.xi // 3. MStar Software and any modification/derivatives thereof shall be deemed as
29*53ee8cc1Swenshuai.xi // MStar`s confidential information and you agree to keep MStar`s
30*53ee8cc1Swenshuai.xi // confidential information in strictest confidence and not disclose to any
31*53ee8cc1Swenshuai.xi // third party.
32*53ee8cc1Swenshuai.xi //
33*53ee8cc1Swenshuai.xi // 4. MStar Software is provided on an "AS IS" basis without warranties of any
34*53ee8cc1Swenshuai.xi // kind. Any warranties are hereby expressly disclaimed by MStar, including
35*53ee8cc1Swenshuai.xi // without limitation, any warranties of merchantability, non-infringement of
36*53ee8cc1Swenshuai.xi // intellectual property rights, fitness for a particular purpose, error free
37*53ee8cc1Swenshuai.xi // and in conformity with any international standard. You agree to waive any
38*53ee8cc1Swenshuai.xi // claim against MStar for any loss, damage, cost or expense that you may
39*53ee8cc1Swenshuai.xi // incur related to your use of MStar Software.
40*53ee8cc1Swenshuai.xi // In no event shall MStar be liable for any direct, indirect, incidental or
41*53ee8cc1Swenshuai.xi // consequential damages, including without limitation, lost of profit or
42*53ee8cc1Swenshuai.xi // revenues, lost or damage of data, and unauthorized system use.
43*53ee8cc1Swenshuai.xi // You agree that this Section 4 shall still apply without being affected
44*53ee8cc1Swenshuai.xi // even if MStar Software has been modified by MStar in accordance with your
45*53ee8cc1Swenshuai.xi // request or instruction for your use, except otherwise agreed by both
46*53ee8cc1Swenshuai.xi // parties in writing.
47*53ee8cc1Swenshuai.xi //
48*53ee8cc1Swenshuai.xi // 5. If requested, MStar may from time to time provide technical supports or
49*53ee8cc1Swenshuai.xi // services in relation with MStar Software to you for your use of
50*53ee8cc1Swenshuai.xi // MStar Software in conjunction with your or your customer`s product
51*53ee8cc1Swenshuai.xi // ("Services").
52*53ee8cc1Swenshuai.xi // You understand and agree that, except otherwise agreed by both parties in
53*53ee8cc1Swenshuai.xi // writing, Services are provided on an "AS IS" basis and the warranty
54*53ee8cc1Swenshuai.xi // disclaimer set forth in Section 4 above shall apply.
55*53ee8cc1Swenshuai.xi //
56*53ee8cc1Swenshuai.xi // 6. Nothing contained herein shall be construed as by implication, estoppels
57*53ee8cc1Swenshuai.xi // or otherwise:
58*53ee8cc1Swenshuai.xi // (a) conferring any license or right to use MStar name, trademark, service
59*53ee8cc1Swenshuai.xi // mark, symbol or any other identification;
60*53ee8cc1Swenshuai.xi // (b) obligating MStar or any of its affiliates to furnish any person,
61*53ee8cc1Swenshuai.xi // including without limitation, you and your customers, any assistance
62*53ee8cc1Swenshuai.xi // of any kind whatsoever, or any information; or
63*53ee8cc1Swenshuai.xi // (c) conferring any license or right under any intellectual property right.
64*53ee8cc1Swenshuai.xi //
65*53ee8cc1Swenshuai.xi // 7. These terms shall be governed by and construed in accordance with the laws
66*53ee8cc1Swenshuai.xi // of Taiwan, R.O.C., excluding its conflict of law rules.
67*53ee8cc1Swenshuai.xi // Any and all dispute arising out hereof or related hereto shall be finally
68*53ee8cc1Swenshuai.xi // settled by arbitration referred to the Chinese Arbitration Association,
69*53ee8cc1Swenshuai.xi // Taipei in accordance with the ROC Arbitration Law and the Arbitration
70*53ee8cc1Swenshuai.xi // Rules of the Association by three (3) arbitrators appointed in accordance
71*53ee8cc1Swenshuai.xi // with the said Rules.
72*53ee8cc1Swenshuai.xi // The place of arbitration shall be in Taipei, Taiwan and the language shall
73*53ee8cc1Swenshuai.xi // be English.
74*53ee8cc1Swenshuai.xi // The arbitration award shall be final and binding to both parties.
75*53ee8cc1Swenshuai.xi //
76*53ee8cc1Swenshuai.xi //******************************************************************************
77*53ee8cc1Swenshuai.xi //<MStar Software>
78*53ee8cc1Swenshuai.xi
79*53ee8cc1Swenshuai.xi #include "include/drvConfig.h"
80*53ee8cc1Swenshuai.xi
81*53ee8cc1Swenshuai.xi #ifdef CONFIG_USB_DEBUG
82*53ee8cc1Swenshuai.xi #define DEBUG
83*53ee8cc1Swenshuai.xi #else
84*53ee8cc1Swenshuai.xi #undef DEBUG
85*53ee8cc1Swenshuai.xi #endif
86*53ee8cc1Swenshuai.xi
87*53ee8cc1Swenshuai.xi //#include <MsCommon.h> // NUSED
88*53ee8cc1Swenshuai.xi //#include "include/drvCompiler.h" // NUSED
89*53ee8cc1Swenshuai.xi //#include "include/drvPorts.h" // NUSED
90*53ee8cc1Swenshuai.xi #include "include/drvErrno.h"
91*53ee8cc1Swenshuai.xi //#include "include/drvPCIMEM.h" // NUSED
92*53ee8cc1Swenshuai.xi //#include "include/drvList.h" // NUSED
93*53ee8cc1Swenshuai.xi //#include "include/drvTimer.h" // NUSED
94*53ee8cc1Swenshuai.xi //#include "include/drvKernel.h" // NUSED
95*53ee8cc1Swenshuai.xi // USB related implemented header files
96*53ee8cc1Swenshuai.xi #include "include/drvUSBHost.h"
97*53ee8cc1Swenshuai.xi #include "drvUsbd.h"
98*53ee8cc1Swenshuai.xi //#include "include/drvCPE_EHCI.h" // NUSED
99*53ee8cc1Swenshuai.xi #include "drvEHCI.h"
100*53ee8cc1Swenshuai.xi #include "drvUSBHwCtl.h"
101*53ee8cc1Swenshuai.xi //#include "include/drvCPE_AMBA.h" // NUSED
102*53ee8cc1Swenshuai.xi //#include "drvUSB.h" // NUSED
103*53ee8cc1Swenshuai.xi /* should applying drvUsbHostConfig.h (inside drvUSBHwctl.h) */
104*53ee8cc1Swenshuai.xi
105*53ee8cc1Swenshuai.xi /*-------------------------------------------------------------------------*/
106*53ee8cc1Swenshuai.xi
107*53ee8cc1Swenshuai.xi
108*53ee8cc1Swenshuai.xi #define DRIVER_VERSION "eCos Newhost"
109*53ee8cc1Swenshuai.xi #define DRIVER_AUTHOR "Mstar USB Team"
110*53ee8cc1Swenshuai.xi #define DRIVER_DESC "USB 2.0 'Enhanced' Host Controller (EHCI) Driver"
111*53ee8cc1Swenshuai.xi
112*53ee8cc1Swenshuai.xi // #define EHCI_VERBOSE_DEBUG
113*53ee8cc1Swenshuai.xi //#define EHCI_TD_DEBUG
114*53ee8cc1Swenshuai.xi #define ENABLE_QH_REFRESH
115*53ee8cc1Swenshuai.xi
116*53ee8cc1Swenshuai.xi #ifdef DEBUG
117*53ee8cc1Swenshuai.xi #define EHCI_STATS
118*53ee8cc1Swenshuai.xi #endif
119*53ee8cc1Swenshuai.xi
120*53ee8cc1Swenshuai.xi #define EHCI_RL_NAKCNT 4 /* enable nak throttle mode, spec 4.9 */
121*53ee8cc1Swenshuai.xi #define EHCI_RL_NAKCNT_TT 0 /* disable nak throttle mode when TT */
122*53ee8cc1Swenshuai.xi #define EHCI_HI_BW_MULT_HS 1 /* high bandwidth file, transactions number/uframe, spec 4.10.3 */
123*53ee8cc1Swenshuai.xi #define EHCI_HI_BW_MULT_TT 1
124*53ee8cc1Swenshuai.xi
125*53ee8cc1Swenshuai.xi #ifdef CONFIG_HC_TEST
126*53ee8cc1Swenshuai.xi #define EHCI_PERIODIC_FLS 0 /* (max) 1024 frame for schedule */
127*53ee8cc1Swenshuai.xi #else
128*53ee8cc1Swenshuai.xi #define EHCI_PERIODIC_FLS 2 /* (minl) 256 frame schedule */
129*53ee8cc1Swenshuai.xi #endif
130*53ee8cc1Swenshuai.xi /* Initial IRQ latency: lower than default */
131*53ee8cc1Swenshuai.xi static int log2_irq_thresh = 0; // 0 to 6
132*53ee8cc1Swenshuai.xi #define INTR_MASK (USBSTS_IAA | USBSTS_FATAL | USBSTS_PCD | USBSTS_ERR | USBSTS_INT)
133*53ee8cc1Swenshuai.xi
134*53ee8cc1Swenshuai.xi #if defined(ENABLE_16US_EOF1)
135*53ee8cc1Swenshuai.xi static U32 park_eco = 3;
136*53ee8cc1Swenshuai.xi #else
137*53ee8cc1Swenshuai.xi static U32 park_eco = 0;
138*53ee8cc1Swenshuai.xi #endif
139*53ee8cc1Swenshuai.xi
140*53ee8cc1Swenshuai.xi /* Debug print definition */
141*53ee8cc1Swenshuai.xi #define DBG_MSG
142*53ee8cc1Swenshuai.xi #define DBG_WARN
143*53ee8cc1Swenshuai.xi //#define DBG_FUNC
144*53ee8cc1Swenshuai.xi #undef ms_debug_msg
145*53ee8cc1Swenshuai.xi #undef ms_debug_warn
146*53ee8cc1Swenshuai.xi #undef ms_debug_func
147*53ee8cc1Swenshuai.xi
148*53ee8cc1Swenshuai.xi #ifdef DBG_MSG
149*53ee8cc1Swenshuai.xi #define ms_debug_msg(fmt, arg...) \
150*53ee8cc1Swenshuai.xi do {diag_printf(fmt, ##arg);} while(0)
151*53ee8cc1Swenshuai.xi #else
152*53ee8cc1Swenshuai.xi #define ms_debug_msg(fmt, arg...) do {} while (0)
153*53ee8cc1Swenshuai.xi #endif
154*53ee8cc1Swenshuai.xi
155*53ee8cc1Swenshuai.xi #ifdef DBG_WARN
156*53ee8cc1Swenshuai.xi #define ms_debug_warn(fmt, arg...) \
157*53ee8cc1Swenshuai.xi do {diag_printf(fmt, ##arg);} while(0)
158*53ee8cc1Swenshuai.xi #else
159*53ee8cc1Swenshuai.xi #define ms_debug_warn(fmt, arg...) do {} while (0)
160*53ee8cc1Swenshuai.xi #endif
161*53ee8cc1Swenshuai.xi
162*53ee8cc1Swenshuai.xi #ifdef DBG_FUNC
163*53ee8cc1Swenshuai.xi #define ms_debug_func(fmt, arg...) \
164*53ee8cc1Swenshuai.xi do {diag_printf(fmt, ##arg);} while(0)
165*53ee8cc1Swenshuai.xi #else
166*53ee8cc1Swenshuai.xi #define ms_debug_func(fmt, arg...) do {} while (0)
167*53ee8cc1Swenshuai.xi #endif
168*53ee8cc1Swenshuai.xi
169*53ee8cc1Swenshuai.xi static void ms_unlink_async(struct ehci_hcd *, struct ehci_qh *);
170*53ee8cc1Swenshuai.xi static void ms_intr_deschedule(struct ehci_hcd *, struct ehci_qh *);
171*53ee8cc1Swenshuai.xi static int ms_qh_schedule(struct ehci_hcd *, struct ehci_qh *);
172*53ee8cc1Swenshuai.xi
173*53ee8cc1Swenshuai.xi void ms_ehci_stoprun_setting(MS_U8 bOption, struct ehci_hcd *ehci);
174*53ee8cc1Swenshuai.xi extern void Chip_Flush_Memory(void);
175*53ee8cc1Swenshuai.xi extern void Chip_Read_Memory(void);
176*53ee8cc1Swenshuai.xi
177*53ee8cc1Swenshuai.xi #ifdef EHCI_TD_DEBUG
Dump_TD(unsigned int addr,int is_qh)178*53ee8cc1Swenshuai.xi void Dump_TD(unsigned int addr, int is_qh)
179*53ee8cc1Swenshuai.xi {
180*53ee8cc1Swenshuai.xi int i;
181*53ee8cc1Swenshuai.xi
182*53ee8cc1Swenshuai.xi diag_printf("[USB] %s:%x -> \n", is_qh?"QH":"QTD", addr);
183*53ee8cc1Swenshuai.xi for (i = 0; i < 0x20 ; i = i+4)
184*53ee8cc1Swenshuai.xi {
185*53ee8cc1Swenshuai.xi diag_printf("%02x ", *(unsigned char volatile *)(addr + i+ 3));
186*53ee8cc1Swenshuai.xi diag_printf("%02x ", *(unsigned char volatile *)(addr + i+ 2));
187*53ee8cc1Swenshuai.xi diag_printf("%02x ", *(unsigned char volatile *)(addr + i+ 1));
188*53ee8cc1Swenshuai.xi diag_printf("%02x ", *(unsigned char volatile *)(addr + i));
189*53ee8cc1Swenshuai.xi diag_printf("\n");
190*53ee8cc1Swenshuai.xi }
191*53ee8cc1Swenshuai.xi }
192*53ee8cc1Swenshuai.xi #endif
193*53ee8cc1Swenshuai.xi
ms_check_status(U32 * pPtr,U32 u32Mask,U32 u32Done,int us)194*53ee8cc1Swenshuai.xi static int ms_check_status (U32 *pPtr, U32 u32Mask, U32 u32Done, int us)
195*53ee8cc1Swenshuai.xi {
196*53ee8cc1Swenshuai.xi U32 u32regv;
197*53ee8cc1Swenshuai.xi
198*53ee8cc1Swenshuai.xi ms_debug_func("++[%s] line:[%d]\n", __FUNCTION__, __LINE__);
199*53ee8cc1Swenshuai.xi do {
200*53ee8cc1Swenshuai.xi u32regv = hcd_reg_readl ((U32)pPtr);
201*53ee8cc1Swenshuai.xi if (u32regv == ~(U32)0) /* card removed */
202*53ee8cc1Swenshuai.xi {
203*53ee8cc1Swenshuai.xi ms_debug_func("--[%s] line:[%d]\n", __FUNCTION__, __LINE__);
204*53ee8cc1Swenshuai.xi return -ENODEV;
205*53ee8cc1Swenshuai.xi }
206*53ee8cc1Swenshuai.xi
207*53ee8cc1Swenshuai.xi u32regv &= u32Mask;
208*53ee8cc1Swenshuai.xi if (u32regv == u32Done)
209*53ee8cc1Swenshuai.xi return 0;
210*53ee8cc1Swenshuai.xi
211*53ee8cc1Swenshuai.xi udelay (1);
212*53ee8cc1Swenshuai.xi us--;
213*53ee8cc1Swenshuai.xi } while (us > 0);
214*53ee8cc1Swenshuai.xi
215*53ee8cc1Swenshuai.xi ms_debug_func("--[%s] line:[%d]\n", __FUNCTION__, __LINE__);
216*53ee8cc1Swenshuai.xi return -ETIMEDOUT;
217*53ee8cc1Swenshuai.xi }
218*53ee8cc1Swenshuai.xi
ms_ehci_halt(struct ehci_hcd * pEhci)219*53ee8cc1Swenshuai.xi static int ms_ehci_halt (struct ehci_hcd *pEhci)
220*53ee8cc1Swenshuai.xi {
221*53ee8cc1Swenshuai.xi U32 u32regv = hcd_reg_readl ((U32)&pEhci->op_regs->usbsts);
222*53ee8cc1Swenshuai.xi
223*53ee8cc1Swenshuai.xi ms_debug_func("++[%s] line:[%d]\n", __FUNCTION__, __LINE__);
224*53ee8cc1Swenshuai.xi if ((u32regv & USBSTS_HALT) != 0)
225*53ee8cc1Swenshuai.xi {
226*53ee8cc1Swenshuai.xi ms_debug_func("--[%s] line:[%d]\n", __FUNCTION__, __LINE__);
227*53ee8cc1Swenshuai.xi return 0;
228*53ee8cc1Swenshuai.xi }
229*53ee8cc1Swenshuai.xi
230*53ee8cc1Swenshuai.xi u32regv = hcd_reg_readl ((U32)&pEhci->op_regs->usbcmd);
231*53ee8cc1Swenshuai.xi u32regv &= ~USBCMD_RUN;
232*53ee8cc1Swenshuai.xi hcd_reg_writel (u32regv, (U32)&pEhci->op_regs->usbcmd);
233*53ee8cc1Swenshuai.xi
234*53ee8cc1Swenshuai.xi ms_debug_func("--[%s] line:[%d]\n", __FUNCTION__, __LINE__);
235*53ee8cc1Swenshuai.xi return ms_check_status (&pEhci->op_regs->usbsts, USBSTS_HALT, USBSTS_HALT, 16 * 125);
236*53ee8cc1Swenshuai.xi }
237*53ee8cc1Swenshuai.xi
ms_ehci_reset(struct ehci_hcd * pEhci)238*53ee8cc1Swenshuai.xi static int ms_ehci_reset (struct ehci_hcd *pEhci)
239*53ee8cc1Swenshuai.xi {
240*53ee8cc1Swenshuai.xi int retv;
241*53ee8cc1Swenshuai.xi U32 u32regv = hcd_reg_readl ((U32)&pEhci->op_regs->usbcmd);
242*53ee8cc1Swenshuai.xi
243*53ee8cc1Swenshuai.xi ms_debug_func("++[%s] line:[%d]\n", __FUNCTION__, __LINE__);
244*53ee8cc1Swenshuai.xi u32regv |= USBCMD_RESET;
245*53ee8cc1Swenshuai.xi hcd_reg_writel (u32regv, (U32)&pEhci->op_regs->usbcmd);
246*53ee8cc1Swenshuai.xi pEhci->hcd.state = HCD_STATE_HALT;
247*53ee8cc1Swenshuai.xi //Wait for HC reset complete
248*53ee8cc1Swenshuai.xi retv = ms_check_status (&pEhci->op_regs->usbcmd, USBCMD_RESET, 0, 250 * 1000);
249*53ee8cc1Swenshuai.xi
250*53ee8cc1Swenshuai.xi #if defined(ENABLE_UHC_RUN_BIT_ALWAYS_ON_ECO)
251*53ee8cc1Swenshuai.xi /* Don't close RUN bit when device disconnect */
252*53ee8cc1Swenshuai.xi {
253*53ee8cc1Swenshuai.xi U32 u32hcmisc = hcd_reg_readl ((U32)&pEhci->op_regs->hcmisc);
254*53ee8cc1Swenshuai.xi hcd_reg_writel(u32hcmisc | BIT7, (U32)&pEhci->op_regs->hcmisc);
255*53ee8cc1Swenshuai.xi }
256*53ee8cc1Swenshuai.xi #endif
257*53ee8cc1Swenshuai.xi
258*53ee8cc1Swenshuai.xi ms_debug_func("--[%s] line:[%d]\n", __FUNCTION__, __LINE__);
259*53ee8cc1Swenshuai.xi return retv;
260*53ee8cc1Swenshuai.xi }
261*53ee8cc1Swenshuai.xi
ms_ehci_quiesce(struct ehci_hcd * pEhci)262*53ee8cc1Swenshuai.xi static void ms_ehci_quiesce (struct ehci_hcd *pEhci)
263*53ee8cc1Swenshuai.xi {
264*53ee8cc1Swenshuai.xi U32 u32regv;
265*53ee8cc1Swenshuai.xi
266*53ee8cc1Swenshuai.xi ms_debug_func("++[%s] line:[%d]\n", __FUNCTION__, __LINE__);
267*53ee8cc1Swenshuai.xi
268*53ee8cc1Swenshuai.xi /* check if there is any schedule bit set (patch from Linux 2.6.28 */
269*53ee8cc1Swenshuai.xi u32regv = hcd_reg_readl ((U32)&pEhci->op_regs->usbcmd) << 10;
270*53ee8cc1Swenshuai.xi u32regv &= USBSTS_ASS | USBSTS_PSS;
271*53ee8cc1Swenshuai.xi if (ms_check_status (&pEhci->op_regs->usbsts, USBSTS_ASS | USBSTS_PSS,
272*53ee8cc1Swenshuai.xi 0, 16 * 125) != 0)
273*53ee8cc1Swenshuai.xi {
274*53ee8cc1Swenshuai.xi ms_debug_err("Cannot stop scheduler, force halt - 1\n");
275*53ee8cc1Swenshuai.xi ms_ehci_halt(pEhci);
276*53ee8cc1Swenshuai.xi pEhci->hcd.state = HCD_STATE_HALT;
277*53ee8cc1Swenshuai.xi return;
278*53ee8cc1Swenshuai.xi }
279*53ee8cc1Swenshuai.xi
280*53ee8cc1Swenshuai.xi u32regv = hcd_reg_readl ((U32)&pEhci->op_regs->usbcmd);
281*53ee8cc1Swenshuai.xi u32regv &= ~(USBCMD_ASE | USBCMD_IAAD | USBCMD_PSE);
282*53ee8cc1Swenshuai.xi hcd_reg_writel (u32regv, (U32)&pEhci->op_regs->usbcmd);
283*53ee8cc1Swenshuai.xi
284*53ee8cc1Swenshuai.xi /* wait 16 microframes */
285*53ee8cc1Swenshuai.xi if (ms_check_status (&pEhci->op_regs->usbsts, USBSTS_ASS | USBSTS_PSS,
286*53ee8cc1Swenshuai.xi 0, 16 * 125) != 0)
287*53ee8cc1Swenshuai.xi {
288*53ee8cc1Swenshuai.xi ms_debug_err("Cannot stop scheduler, force halt - 2\n");
289*53ee8cc1Swenshuai.xi /* patch from Linux 2.6.28 */
290*53ee8cc1Swenshuai.xi ms_ehci_halt(pEhci);
291*53ee8cc1Swenshuai.xi pEhci->hcd.state = HCD_STATE_HALT;
292*53ee8cc1Swenshuai.xi return;
293*53ee8cc1Swenshuai.xi }
294*53ee8cc1Swenshuai.xi ms_debug_func("--[%s] line:[%d]\n", __FUNCTION__, __LINE__);
295*53ee8cc1Swenshuai.xi }
296*53ee8cc1Swenshuai.xi
297*53ee8cc1Swenshuai.xi /*
298*53ee8cc1Swenshuai.xi * @brief clear reset timer
299*53ee8cc1Swenshuai.xi *
300*53ee8cc1Swenshuai.xi * @param struct ehci_hcd *pEhci
301*53ee8cc1Swenshuai.xi * @param int iIndex
302*53ee8cc1Swenshuai.xi * @param int port_status
303*53ee8cc1Swenshuai.xi *
304*53ee8cc1Swenshuai.xi * @return port_status
305*53ee8cc1Swenshuai.xi */
306*53ee8cc1Swenshuai.xi
ms_reset_complete(struct ehci_hcd * pEhci,int iIndex,int port_status)307*53ee8cc1Swenshuai.xi static int ms_reset_complete (
308*53ee8cc1Swenshuai.xi struct ehci_hcd *pEhci,
309*53ee8cc1Swenshuai.xi int iIndex,
310*53ee8cc1Swenshuai.xi int port_status)
311*53ee8cc1Swenshuai.xi {
312*53ee8cc1Swenshuai.xi ms_debug_func("++[%s] line:[%d]\n", __FUNCTION__, __LINE__);
313*53ee8cc1Swenshuai.xi
314*53ee8cc1Swenshuai.xi if (!(port_status & PORTSC_CONNECT))
315*53ee8cc1Swenshuai.xi {
316*53ee8cc1Swenshuai.xi //pEhci->u32ResetEnd [iIndex] = 0; // un-patch from Linux 2.6.28
317*53ee8cc1Swenshuai.xi return port_status;
318*53ee8cc1Swenshuai.xi }
319*53ee8cc1Swenshuai.xi
320*53ee8cc1Swenshuai.xi /* Mstar EHCI is integrated TT */
321*53ee8cc1Swenshuai.xi if (!(port_status & PORTSC_PE))
322*53ee8cc1Swenshuai.xi {
323*53ee8cc1Swenshuai.xi ms_debug_err("TT roothub not enable port\n");
324*53ee8cc1Swenshuai.xi }
325*53ee8cc1Swenshuai.xi
326*53ee8cc1Swenshuai.xi ms_debug_func("--[%s] line:[%d]\n", __FUNCTION__, __LINE__);
327*53ee8cc1Swenshuai.xi return port_status;
328*53ee8cc1Swenshuai.xi }
329*53ee8cc1Swenshuai.xi
330*53ee8cc1Swenshuai.xi /*-------------------------------------------------------------------------*/
331*53ee8cc1Swenshuai.xi /*
332*53ee8cc1Swenshuai.xi * @brief check hub ports status change
333*53ee8cc1Swenshuai.xi * our echi ip (root hub) supports only one port
334*53ee8cc1Swenshuai.xi *
335*53ee8cc1Swenshuai.xi * @param struct usb_hcd *pHcd
336*53ee8cc1Swenshuai.xi * @param char *pBuf
337*53ee8cc1Swenshuai.xi *
338*53ee8cc1Swenshuai.xi * @return success/false
339*53ee8cc1Swenshuai.xi */
ms_hub_status_data(struct usb_hcd * pHcd,char * pBuf)340*53ee8cc1Swenshuai.xi int ms_hub_status_data (struct usb_hcd *pHcd, char *pBuf)
341*53ee8cc1Swenshuai.xi {
342*53ee8cc1Swenshuai.xi struct ehci_hcd *pEhci = hcd_to_ehci (pHcd);
343*53ee8cc1Swenshuai.xi U32 u32Temp, u32Status = 0;
344*53ee8cc1Swenshuai.xi U32 u32Flags;
345*53ee8cc1Swenshuai.xi
346*53ee8cc1Swenshuai.xi ms_debug_func("++[%s] line:[%d]\n", __FUNCTION__, __LINE__);
347*53ee8cc1Swenshuai.xi
348*53ee8cc1Swenshuai.xi if (!HCD_IS_RUNNING(pHcd->state)) // patch from 2.6.28
349*53ee8cc1Swenshuai.xi return 0;
350*53ee8cc1Swenshuai.xi
351*53ee8cc1Swenshuai.xi /* init u32Status to no-changes */
352*53ee8cc1Swenshuai.xi pBuf [0] = 0;
353*53ee8cc1Swenshuai.xi
354*53ee8cc1Swenshuai.xi /* port 1 changes ? */
355*53ee8cc1Swenshuai.xi osapi_spin_lock_irqsave (&pEhci->tHcdLock, u32Flags);
356*53ee8cc1Swenshuai.xi
357*53ee8cc1Swenshuai.xi u32Temp = hcd_reg_readl ((U32)&pEhci->op_regs->portsc[0]);
358*53ee8cc1Swenshuai.xi
359*53ee8cc1Swenshuai.xi /* PCD interrupt mode, not utilize such scheme */
360*53ee8cc1Swenshuai.xi //if ( ((u32Temp & PORTSC_CONNECT) == 0) && ((pHcd->pre_sts & PORTSC_CONNECT) != 0) )
361*53ee8cc1Swenshuai.xi //{
362*53ee8cc1Swenshuai.xi // ms_debug_msg("<ms_hub_status_data> Add CSC @ root hub %d, DISCONNECT! (psc = 0x%x)\n", (int)pHcd->host_id, (unsigned int)u32Temp);
363*53ee8cc1Swenshuai.xi // u32Temp |= PORTSC_CSC;
364*53ee8cc1Swenshuai.xi //}
365*53ee8cc1Swenshuai.xi //pHcd->pre_sts = u32Temp;
366*53ee8cc1Swenshuai.xi
367*53ee8cc1Swenshuai.xi //if (!(u32Temp & PORTSC_CONNECT)) // un-patch from Linux 2.6.28
368*53ee8cc1Swenshuai.xi // pEhci->u32ResetEnd [0] = 0;
369*53ee8cc1Swenshuai.xi
370*53ee8cc1Swenshuai.xi /* no need to consider over current for this IP */
371*53ee8cc1Swenshuai.xi if ((u32Temp & (PORTSC_CSC) || PORTSC_PEC) != 0 ||
372*53ee8cc1Swenshuai.xi (pEhci->u32ResetEnd[0] && ms_time_after_eq(
373*53ee8cc1Swenshuai.xi jiffies, pEhci->u32ResetEnd[0])))
374*53ee8cc1Swenshuai.xi {
375*53ee8cc1Swenshuai.xi /* bit 0 is for hub up port u32Status change */
376*53ee8cc1Swenshuai.xi pBuf [0] |= 1 << 1;
377*53ee8cc1Swenshuai.xi u32Status = USBSTS_PCD;
378*53ee8cc1Swenshuai.xi }
379*53ee8cc1Swenshuai.xi
380*53ee8cc1Swenshuai.xi osapi_spin_unlock_irqrestore (&pEhci->tHcdLock, u32Flags);
381*53ee8cc1Swenshuai.xi ms_debug_func("--[%s] line:[%d]\n", __FUNCTION__, __LINE__);
382*53ee8cc1Swenshuai.xi return u32Status ? 1 : 0;
383*53ee8cc1Swenshuai.xi }
384*53ee8cc1Swenshuai.xi
385*53ee8cc1Swenshuai.xi /*-------------------------------------------------------------------------*/
386*53ee8cc1Swenshuai.xi /*
387*53ee8cc1Swenshuai.xi * @brief fill hub descriptor
388*53ee8cc1Swenshuai.xi *
389*53ee8cc1Swenshuai.xi * @param struct ehci_hcd *pEhci
390*53ee8cc1Swenshuai.xi * @param struct usb_hub_descriptor *pDesc
391*53ee8cc1Swenshuai.xi *
392*53ee8cc1Swenshuai.xi * @return none
393*53ee8cc1Swenshuai.xi */
394*53ee8cc1Swenshuai.xi
ms_get_roothub_desc(struct ehci_hcd * pEhci,struct usb_hub_descriptor * pDesc)395*53ee8cc1Swenshuai.xi static void ms_get_roothub_desc (
396*53ee8cc1Swenshuai.xi struct ehci_hcd *pEhci,
397*53ee8cc1Swenshuai.xi struct usb_hub_descriptor *pDesc
398*53ee8cc1Swenshuai.xi )
399*53ee8cc1Swenshuai.xi {
400*53ee8cc1Swenshuai.xi int iPorts = HCS_N_PORTS (pEhci->hcs_params);
401*53ee8cc1Swenshuai.xi U16 u16Temp;
402*53ee8cc1Swenshuai.xi
403*53ee8cc1Swenshuai.xi ms_debug_func("++[%s] line:[%d]\n", __FUNCTION__, __LINE__);
404*53ee8cc1Swenshuai.xi pDesc->bDescriptorType = 0x29;
405*53ee8cc1Swenshuai.xi pDesc->bPwrOn2PwrGood = 0;
406*53ee8cc1Swenshuai.xi pDesc->bHubContrCurrent = 0;
407*53ee8cc1Swenshuai.xi pDesc->bNbrPorts = iPorts;
408*53ee8cc1Swenshuai.xi u16Temp = 1 + (iPorts / 8);
409*53ee8cc1Swenshuai.xi pDesc->bDescLength = 7 + 2 * u16Temp;
410*53ee8cc1Swenshuai.xi
411*53ee8cc1Swenshuai.xi /* two bitmaps: iPorts removable, and usb 1.0 legacy PortPwrCtrlMask */
412*53ee8cc1Swenshuai.xi memset (&pDesc->DeviceRemovable [0], 0, u16Temp);
413*53ee8cc1Swenshuai.xi memset (&pDesc->DeviceRemovable [u16Temp], 0xff, u16Temp);
414*53ee8cc1Swenshuai.xi
415*53ee8cc1Swenshuai.xi u16Temp = 0x0008; /* Individual Port Over-current Protection */
416*53ee8cc1Swenshuai.xi if (HCS_PPC (pEhci->hcs_params))
417*53ee8cc1Swenshuai.xi u16Temp |= 0x0001; /* Ganged power switching (all iPorts' power at once) */
418*53ee8cc1Swenshuai.xi if (HCS_P_INDICATOR (pEhci->hcs_params))
419*53ee8cc1Swenshuai.xi u16Temp |= 0x0080; /* Individual port indicators (LEDs) */
420*53ee8cc1Swenshuai.xi pDesc->wHubCharacteristics = u16Temp;
421*53ee8cc1Swenshuai.xi ms_debug_func("--[%s] line:[%d]\n", __FUNCTION__, __LINE__);
422*53ee8cc1Swenshuai.xi }
423*53ee8cc1Swenshuai.xi
424*53ee8cc1Swenshuai.xi /*-------------------------------------------------------------------------*/
ms_ehci_softrst(struct ehci_hcd * pEhci)425*53ee8cc1Swenshuai.xi void ms_ehci_softrst(struct ehci_hcd *pEhci)
426*53ee8cc1Swenshuai.xi {
427*53ee8cc1Swenshuai.xi U32 regTmp[2];
428*53ee8cc1Swenshuai.xi
429*53ee8cc1Swenshuai.xi ms_debug_func("++[%s] line:[%d]\n", __FUNCTION__, __LINE__);
430*53ee8cc1Swenshuai.xi
431*53ee8cc1Swenshuai.xi /* ensure HC already stopped before HC Reset
432*53ee8cc1Swenshuai.xi * otherwise, there will be a fatal error (DMA Error)
433*53ee8cc1Swenshuai.xi */
434*53ee8cc1Swenshuai.xi ms_ehci_halt(pEhci);
435*53ee8cc1Swenshuai.xi /* make sure USB device going to suspend */
436*53ee8cc1Swenshuai.xi //mdelay(10); // TBD
437*53ee8cc1Swenshuai.xi
438*53ee8cc1Swenshuai.xi /* iff asynchronous QH head is not pointed to itself, restore it too */
439*53ee8cc1Swenshuai.xi if ((pEhci->hcd.rh_disconn == 1) &&
440*53ee8cc1Swenshuai.xi (pEhci->stAsync->hw_next_qh != QH_NEXT(pEhci->stAsync->qh_dma_addr)))
441*53ee8cc1Swenshuai.xi {
442*53ee8cc1Swenshuai.xi ms_debug_err("[EHCI] Head QH not point to itself (%x)!\n\n\n",
443*53ee8cc1Swenshuai.xi pEhci->stAsync->hw_next_qh);
444*53ee8cc1Swenshuai.xi pEhci->stAsync->hw_next_qh = QH_NEXT(pEhci->stAsync->qh_dma_addr);
445*53ee8cc1Swenshuai.xi }
446*53ee8cc1Swenshuai.xi if (!hcd_reg_readl((U32)&pEhci->op_regs->asynclistaddr))
447*53ee8cc1Swenshuai.xi ms_debug_err("[EHCI] async reg 0!!!\n");
448*53ee8cc1Swenshuai.xi
449*53ee8cc1Swenshuai.xi /* sometimes, replug device quickly crashs aync_base, just restore it */
450*53ee8cc1Swenshuai.xi hcd_reg_writel ((U32)pEhci->stAsync->qh_dma_addr, (U32)&pEhci->op_regs->asynclistaddr);
451*53ee8cc1Swenshuai.xi
452*53ee8cc1Swenshuai.xi regTmp[0] = hcd_reg_readl((U32)&pEhci->op_regs->usbcmd);
453*53ee8cc1Swenshuai.xi regTmp[1] = hcd_reg_readl((U32)&pEhci->op_regs->usbintr);
454*53ee8cc1Swenshuai.xi // HC soft reset
455*53ee8cc1Swenshuai.xi ms_ehci_reset(pEhci);
456*53ee8cc1Swenshuai.xi // restore regisger setting
457*53ee8cc1Swenshuai.xi hcd_reg_writel(regTmp[1],(U32)&pEhci->op_regs->usbintr);
458*53ee8cc1Swenshuai.xi hcd_reg_writel(regTmp[0],(U32)&pEhci->op_regs->usbcmd);
459*53ee8cc1Swenshuai.xi pEhci->hcd.state = HCD_STATE_RUNNING;
460*53ee8cc1Swenshuai.xi ms_debug_func("--[%s] line:[%d]\n", __FUNCTION__, __LINE__);
461*53ee8cc1Swenshuai.xi }
462*53ee8cc1Swenshuai.xi
463*53ee8cc1Swenshuai.xi static const char *const speed_name_list[] = {
464*53ee8cc1Swenshuai.xi "full-speed",
465*53ee8cc1Swenshuai.xi "low-speed",
466*53ee8cc1Swenshuai.xi "high-speed",
467*53ee8cc1Swenshuai.xi "UNKNOWN",
468*53ee8cc1Swenshuai.xi };
469*53ee8cc1Swenshuai.xi /*-------------------------------------------------------------------------*/
470*53ee8cc1Swenshuai.xi /*
471*53ee8cc1Swenshuai.xi * @brief process hub request
472*53ee8cc1Swenshuai.xi *
473*53ee8cc1Swenshuai.xi * @param struct usb_hcd *pHcd
474*53ee8cc1Swenshuai.xi * @param U16 typeReq
475*53ee8cc1Swenshuai.xi * @param U16 u16Value
476*53ee8cc1Swenshuai.xi * @param U16 u16Index
477*53ee8cc1Swenshuai.xi * @param char *pBuf
478*53ee8cc1Swenshuai.xi *
479*53ee8cc1Swenshuai.xi * @return error code
480*53ee8cc1Swenshuai.xi *
481*53ee8cc1Swenshuai.xi */
ms_hub_control(struct usb_hcd * pHcd,U16 typeReq,U16 u16Value,U16 u16Index,char * pBuf)482*53ee8cc1Swenshuai.xi int ms_hub_control (
483*53ee8cc1Swenshuai.xi struct usb_hcd *pHcd,
484*53ee8cc1Swenshuai.xi U16 typeReq,
485*53ee8cc1Swenshuai.xi U16 u16Value,
486*53ee8cc1Swenshuai.xi U16 u16Index,
487*53ee8cc1Swenshuai.xi char *pBuf
488*53ee8cc1Swenshuai.xi )
489*53ee8cc1Swenshuai.xi {
490*53ee8cc1Swenshuai.xi struct ehci_hcd *pEhci = hcd_to_ehci (pHcd);
491*53ee8cc1Swenshuai.xi int iPorts = HCS_N_PORTS (pEhci->hcs_params);
492*53ee8cc1Swenshuai.xi U32 u32Temp, u32Status, u32Bus_monitor;
493*53ee8cc1Swenshuai.xi U32 u32Flags;
494*53ee8cc1Swenshuai.xi int iRetval = 0;
495*53ee8cc1Swenshuai.xi int time_out;
496*53ee8cc1Swenshuai.xi struct cpe_dev *dev;
497*53ee8cc1Swenshuai.xi const struct device_s *__mptr = pHcd->controller;
498*53ee8cc1Swenshuai.xi dev = (struct cpe_dev *)( (char *)__mptr - offsetof(struct cpe_dev,dev) );
499*53ee8cc1Swenshuai.xi U32 u32RegUTMI = dev->utmibase;
500*53ee8cc1Swenshuai.xi U32 u32Temp2, u32Speed;
501*53ee8cc1Swenshuai.xi
502*53ee8cc1Swenshuai.xi ms_debug_func("++[%s] line:[%d]\n", __FUNCTION__, __LINE__);
503*53ee8cc1Swenshuai.xi osapi_spin_lock_irqsave (&pEhci->tHcdLock, u32Flags);
504*53ee8cc1Swenshuai.xi switch (typeReq)
505*53ee8cc1Swenshuai.xi {
506*53ee8cc1Swenshuai.xi case Req_ClearHubFeature:
507*53ee8cc1Swenshuai.xi if ((u16Value != C_HUB_LOCAL_POWER)&&(u16Value != C_HUB_OVER_CURRENT))
508*53ee8cc1Swenshuai.xi goto error;
509*53ee8cc1Swenshuai.xi break;
510*53ee8cc1Swenshuai.xi case Req_ClearPortFeature:
511*53ee8cc1Swenshuai.xi if (!u16Index || u16Index > iPorts)
512*53ee8cc1Swenshuai.xi goto error;
513*53ee8cc1Swenshuai.xi u16Index--;
514*53ee8cc1Swenshuai.xi u32Temp = hcd_reg_readl ((U32)&pEhci->op_regs->portsc [u16Index]);
515*53ee8cc1Swenshuai.xi u32Temp &= ~PORTSC_RWC_BITS;
516*53ee8cc1Swenshuai.xi
517*53ee8cc1Swenshuai.xi if (u32Temp & PORTSC_OWNER)
518*53ee8cc1Swenshuai.xi break;
519*53ee8cc1Swenshuai.xi
520*53ee8cc1Swenshuai.xi switch (u16Value)
521*53ee8cc1Swenshuai.xi {
522*53ee8cc1Swenshuai.xi case USB_PORT_FEAT_ENABLE:
523*53ee8cc1Swenshuai.xi ms_debug_debug("Disable port\n");
524*53ee8cc1Swenshuai.xi hcd_reg_writel (u32Temp & ~PORTSC_PE, (U32)&pEhci->op_regs->portsc [u16Index]);
525*53ee8cc1Swenshuai.xi #if 0
526*53ee8cc1Swenshuai.xi // not in linux
527*53ee8cc1Swenshuai.xi //�˸m�Q�������ɭ� ����scheduler
528*53ee8cc1Swenshuai.xi hcd_reg_writel(hcd_reg_readl((U32)&pEhci->op_regs->usbcmd)&(~(USBCMD_ASE|USBCMD_PSE|USBCMD_IAAD)),(U32)&pEhci->op_regs->usbcmd);
529*53ee8cc1Swenshuai.xi #endif
530*53ee8cc1Swenshuai.xi
531*53ee8cc1Swenshuai.xi #if 0 // not to reset EHCI at this time
532*53ee8cc1Swenshuai.xi //Halt HCD
533*53ee8cc1Swenshuai.xi ms_host_halt(pEhci);
534*53ee8cc1Swenshuai.xi ms_ehci_softrst(pEhci);
535*53ee8cc1Swenshuai.xi #endif
536*53ee8cc1Swenshuai.xi break;
537*53ee8cc1Swenshuai.xi case USB_PORT_FEAT_C_ENABLE:
538*53ee8cc1Swenshuai.xi hcd_reg_writel ((u32Temp /*& ~PORTSC_RWC_BITS*/) | PORTSC_PEC,
539*53ee8cc1Swenshuai.xi (U32)&pEhci->op_regs->portsc [u16Index]);
540*53ee8cc1Swenshuai.xi break;
541*53ee8cc1Swenshuai.xi case USB_PORT_FEAT_SUSPEND:
542*53ee8cc1Swenshuai.xi case USB_PORT_FEAT_C_SUSPEND:
543*53ee8cc1Swenshuai.xi break;
544*53ee8cc1Swenshuai.xi case USB_PORT_FEAT_POWER:
545*53ee8cc1Swenshuai.xi if (HCS_PPC (pEhci->hcs_params))
546*53ee8cc1Swenshuai.xi hcd_reg_writel (u32Temp & ~PORTSC_POWER,
547*53ee8cc1Swenshuai.xi (U32)&pEhci->op_regs->portsc [u16Index]);
548*53ee8cc1Swenshuai.xi break;
549*53ee8cc1Swenshuai.xi case USB_PORT_FEAT_C_CONNECTION:
550*53ee8cc1Swenshuai.xi /* for force HC Reset */
551*53ee8cc1Swenshuai.xi if(pEhci->u32MoreCSC)
552*53ee8cc1Swenshuai.xi {
553*53ee8cc1Swenshuai.xi diag_printf("[EHCI] clear more CSC\n");
554*53ee8cc1Swenshuai.xi pEhci->u32MoreCSC = false;
555*53ee8cc1Swenshuai.xi }
556*53ee8cc1Swenshuai.xi hcd_reg_writel ((u32Temp /*& ~PORTSC_RWC_BITS*/) | PORTSC_CSC,
557*53ee8cc1Swenshuai.xi (U32)&pEhci->op_regs->portsc [u16Index]);
558*53ee8cc1Swenshuai.xi break;
559*53ee8cc1Swenshuai.xi case USB_PORT_FEAT_C_OVER_CURRENT:
560*53ee8cc1Swenshuai.xi hcd_reg_writel ((u32Temp /*& ~PORTSC_RWC_BITS*/) | PORTSC_OCC,
561*53ee8cc1Swenshuai.xi (U32)&pEhci->op_regs->portsc [u16Index]);
562*53ee8cc1Swenshuai.xi break;
563*53ee8cc1Swenshuai.xi case USB_PORT_FEAT_C_RESET:
564*53ee8cc1Swenshuai.xi /* GetPortStatus clears reset */
565*53ee8cc1Swenshuai.xi break;
566*53ee8cc1Swenshuai.xi default:
567*53ee8cc1Swenshuai.xi goto error;
568*53ee8cc1Swenshuai.xi }
569*53ee8cc1Swenshuai.xi u32Temp = hcd_reg_readl ((U32)&pEhci->op_regs->usbcmd); /* unblock posted write */
570*53ee8cc1Swenshuai.xi break;
571*53ee8cc1Swenshuai.xi case Req_GetHubDescriptor:
572*53ee8cc1Swenshuai.xi ms_get_roothub_desc(pEhci, (struct usb_hub_descriptor *)
573*53ee8cc1Swenshuai.xi pBuf);
574*53ee8cc1Swenshuai.xi break;
575*53ee8cc1Swenshuai.xi case Req_GetHubStatus:
576*53ee8cc1Swenshuai.xi /* no hub-wide feature/u32Status u32Flags */
577*53ee8cc1Swenshuai.xi memset (pBuf, 0, 4);
578*53ee8cc1Swenshuai.xi //cpu_to_le32s ((U32 *) pBuf);
579*53ee8cc1Swenshuai.xi break;
580*53ee8cc1Swenshuai.xi case Req_GetPortStatus:
581*53ee8cc1Swenshuai.xi if (!u16Index || u16Index > iPorts)
582*53ee8cc1Swenshuai.xi goto error;
583*53ee8cc1Swenshuai.xi u16Index--;
584*53ee8cc1Swenshuai.xi u32Status = 0;
585*53ee8cc1Swenshuai.xi u32Temp = hcd_reg_readl ((U32)&pEhci->op_regs->portsc [u16Index]);
586*53ee8cc1Swenshuai.xi // old flow to patch hub polling
587*53ee8cc1Swenshuai.xi //if ( ((u32Temp & PORTSC_CONNECT) == 0) && ((u32Temp & PORTSC_CSC) == 0) )
588*53ee8cc1Swenshuai.xi //{
589*53ee8cc1Swenshuai.xi // if ((pHcd->pre_temp & PORTSC_CONNECT) != 0)
590*53ee8cc1Swenshuai.xi // {
591*53ee8cc1Swenshuai.xi // ms_debug_msg("<ms_hub_control> Req_GetPortStatus:Add CSC here, pStatus = %x\n", (unsigned int)u32Temp);
592*53ee8cc1Swenshuai.xi // u32Temp |= PORTSC_CSC;
593*53ee8cc1Swenshuai.xi // }
594*53ee8cc1Swenshuai.xi //}
595*53ee8cc1Swenshuai.xi //pHcd->pre_temp = u32Temp;
596*53ee8cc1Swenshuai.xi
597*53ee8cc1Swenshuai.xi /* deal with wPortChange bits */
598*53ee8cc1Swenshuai.xi if (u32Temp & PORTSC_CSC)
599*53ee8cc1Swenshuai.xi {
600*53ee8cc1Swenshuai.xi u32Status |= 1 << USB_PORT_FEAT_C_CONNECTION;
601*53ee8cc1Swenshuai.xi }
602*53ee8cc1Swenshuai.xi else if(pEhci->u32MoreCSC)
603*53ee8cc1Swenshuai.xi {
604*53ee8cc1Swenshuai.xi diag_printf("[EHCI] retrun more CSC\n");
605*53ee8cc1Swenshuai.xi u32Status |= 1 << USB_PORT_FEAT_C_CONNECTION;
606*53ee8cc1Swenshuai.xi }
607*53ee8cc1Swenshuai.xi if (u32Temp & PORTSC_PEC)
608*53ee8cc1Swenshuai.xi u32Status |= 1 << USB_PORT_FEAT_C_ENABLE;
609*53ee8cc1Swenshuai.xi // USB_PORT_FEAT_C_SUSPEND
610*53ee8cc1Swenshuai.xi if (u32Temp & PORTSC_OCC)
611*53ee8cc1Swenshuai.xi u32Status |= 1 << USB_PORT_FEAT_C_OVER_CURRENT;
612*53ee8cc1Swenshuai.xi
613*53ee8cc1Swenshuai.xi if ((u32Temp & PORTSC_RESET)
614*53ee8cc1Swenshuai.xi && ms_time_after (jiffies,
615*53ee8cc1Swenshuai.xi pEhci->u32ResetEnd [u16Index]))
616*53ee8cc1Swenshuai.xi {
617*53ee8cc1Swenshuai.xi u32Status |= 1 << USB_PORT_FEAT_C_RESET;
618*53ee8cc1Swenshuai.xi pEhci->u32ResetEnd [u16Index] = 0; // patch from Linux 2.6.28
619*53ee8cc1Swenshuai.xi time_out=0;
620*53ee8cc1Swenshuai.xi
621*53ee8cc1Swenshuai.xi writeb(UTMI_DISCON_LEVEL_2A ,(void*)(u32RegUTMI+0x2A*2)); // disconnect level
622*53ee8cc1Swenshuai.xi mdelay(20); // chirp patch
623*53ee8cc1Swenshuai.xi
624*53ee8cc1Swenshuai.xi /* Do port reset until finish */
625*53ee8cc1Swenshuai.xi //hcd_reg_writel (u32Temp & ~PORTSC_RESET,
626*53ee8cc1Swenshuai.xi hcd_reg_writel (u32Temp & ~(PORTSC_RWC_BITS | PORTSC_RESET),
627*53ee8cc1Swenshuai.xi (U32)&pEhci->op_regs->portsc [u16Index]);
628*53ee8cc1Swenshuai.xi do {
629*53ee8cc1Swenshuai.xi u32Temp = hcd_reg_readl ((U32)&pEhci->op_regs->portsc [u16Index]);
630*53ee8cc1Swenshuai.xi udelay (10);
631*53ee8cc1Swenshuai.xi } while ((u32Temp&(PORTSC_RESET|PORTSC_CONNECT)) == (PORTSC_RESET|PORTSC_CONNECT)&&(time_out++<10000));
632*53ee8cc1Swenshuai.xi
633*53ee8cc1Swenshuai.xi writeb( UTMI_EYE_SETTING_2C, (void*) (u32RegUTMI+0x2c*2)); // chirp patch
634*53ee8cc1Swenshuai.xi writeb( UTMI_EYE_SETTING_2D, (void*) (u32RegUTMI+0x2d*2-1)); // chirp patch
635*53ee8cc1Swenshuai.xi writeb( UTMI_EYE_SETTING_2E, (void*) (u32RegUTMI+0x2e*2)); // chirp patch
636*53ee8cc1Swenshuai.xi writeb( UTMI_EYE_SETTING_2F, (void*) (u32RegUTMI+0x2f*2-1)); // chirp patch
637*53ee8cc1Swenshuai.xi #ifdef ENABLE_TX_RX_RESET_CLK_GATING_ECO
638*53ee8cc1Swenshuai.xi // DO UTMI TX/RX RESET
639*53ee8cc1Swenshuai.xi writeb( readb((void*)(u32RegUTMI+0x06*2)) | 0x03, (void*) (u32RegUTMI+0x06*2));
640*53ee8cc1Swenshuai.xi writeb( readb((void*)(u32RegUTMI+0x06*2)) & ~0x03, (void*) (u32RegUTMI+0x06*2));
641*53ee8cc1Swenshuai.xi #endif
642*53ee8cc1Swenshuai.xi
643*53ee8cc1Swenshuai.xi //Add time-out mechanism to cover HW BUG
644*53ee8cc1Swenshuai.xi //HW ISSUE?
645*53ee8cc1Swenshuai.xi if( time_out >= 10000 )
646*53ee8cc1Swenshuai.xi {
647*53ee8cc1Swenshuai.xi //Maybe HW bug ==> check it out
648*53ee8cc1Swenshuai.xi ms_debug_err("ERR: Port reset cannot force complete!!\n");//HW ISSUE?
649*53ee8cc1Swenshuai.xi ms_ehci_softrst(pEhci);
650*53ee8cc1Swenshuai.xi }
651*53ee8cc1Swenshuai.xi u32Speed = (hcd_reg_readl((U32)&pEhci->op_regs->bus_control) >> 9) & 0x3;
652*53ee8cc1Swenshuai.xi //ms_debug_msg("SPEED: %x\n", (unsigned int)u32Speed);
653*53ee8cc1Swenshuai.xi ms_debug_msg("RootHub SPEED: %s\n", speed_name_list[u32Speed]);
654*53ee8cc1Swenshuai.xi
655*53ee8cc1Swenshuai.xi u32Temp2 = hcd_reg_readl((U32)&pEhci->op_regs->hcmisc) & 0xfffffff3;
656*53ee8cc1Swenshuai.xi
657*53ee8cc1Swenshuai.xi /* unset UTMI force full speed hub driving timing */
658*53ee8cc1Swenshuai.xi ms_UTMI_ANDXBYTE_EX(0x03, (~BIT2), u32RegUTMI);
659*53ee8cc1Swenshuai.xi
660*53ee8cc1Swenshuai.xi if (u32Speed == 2) // high u32Speed
661*53ee8cc1Swenshuai.xi {
662*53ee8cc1Swenshuai.xi ms_UTMI_ORXBYTE_EX(0x09, 0x80, u32RegUTMI); //HS rx robust enable
663*53ee8cc1Swenshuai.xi #if defined(ENABLE_16US_EOF1)
664*53ee8cc1Swenshuai.xi /* set EOF1 to 16us for babble prevention under hub case */
665*53ee8cc1Swenshuai.xi //diag_printf("[EHCI] set 16us EOF1\n ");
666*53ee8cc1Swenshuai.xi u32Temp2 |= (1 << 2);
667*53ee8cc1Swenshuai.xi #else
668*53ee8cc1Swenshuai.xi u32Temp2 |= (3 << 2);
669*53ee8cc1Swenshuai.xi #endif
670*53ee8cc1Swenshuai.xi }
671*53ee8cc1Swenshuai.xi else if (u32Speed == 0 ) //full u32Speed
672*53ee8cc1Swenshuai.xi {
673*53ee8cc1Swenshuai.xi /* set UTMI force full speed hub driving timing */
674*53ee8cc1Swenshuai.xi ms_UTMI_ORXBYTE_EX(0x03, BIT2, u32RegUTMI);
675*53ee8cc1Swenshuai.xi ms_UTMI_ANDXBYTE_EX(0x09, 0x7F, u32RegUTMI);
676*53ee8cc1Swenshuai.xi u32Temp2 |= (2 << 2);
677*53ee8cc1Swenshuai.xi }
678*53ee8cc1Swenshuai.xi else if (u32Speed == 1 ) //low u32Speed
679*53ee8cc1Swenshuai.xi {
680*53ee8cc1Swenshuai.xi ms_UTMI_ANDXBYTE_EX(0x09, 0x7F, u32RegUTMI);
681*53ee8cc1Swenshuai.xi u32Temp2 |= (2 << 2);
682*53ee8cc1Swenshuai.xi }
683*53ee8cc1Swenshuai.xi hcd_reg_writel (u32Temp2, (U32)&pEhci->op_regs->hcmisc); // misc, EOF1
684*53ee8cc1Swenshuai.xi
685*53ee8cc1Swenshuai.xi /* patch from Linux 2.6.28 */
686*53ee8cc1Swenshuai.xi //u32Temp = ms_reset_complete (pEhci, u16Index, u32Temp);
687*53ee8cc1Swenshuai.xi u32Temp = ms_reset_complete (pEhci, u16Index,
688*53ee8cc1Swenshuai.xi hcd_reg_readl ((U32)&pEhci->op_regs->portsc [u16Index]));
689*53ee8cc1Swenshuai.xi pHcd->isRootHubPortReset = FALSE;
690*53ee8cc1Swenshuai.xi }
691*53ee8cc1Swenshuai.xi
692*53ee8cc1Swenshuai.xi if (!(u32Temp & (PORTSC_RESUME|PORTSC_RESET))) // patch from Linux 2.6.28
693*53ee8cc1Swenshuai.xi pEhci->u32ResetEnd[u16Index] = 0;
694*53ee8cc1Swenshuai.xi
695*53ee8cc1Swenshuai.xi // don't show wPortStatus if it's owned by a companion hc
696*53ee8cc1Swenshuai.xi /* patch from Linux 2.6.28, TT root hub */
697*53ee8cc1Swenshuai.xi //if (!(u32Temp & PORTSC_OWNER))
698*53ee8cc1Swenshuai.xi {
699*53ee8cc1Swenshuai.xi if (u32Temp & PORTSC_CONNECT)
700*53ee8cc1Swenshuai.xi {
701*53ee8cc1Swenshuai.xi u32Status |= USB_PORT_STAT_CONNECTION;
702*53ee8cc1Swenshuai.xi u32Bus_monitor=hcd_reg_readl ((U32)&pEhci->op_regs->bus_control);
703*53ee8cc1Swenshuai.xi u32Bus_monitor>>=9;
704*53ee8cc1Swenshuai.xi if (u32Bus_monitor==2)
705*53ee8cc1Swenshuai.xi u32Status |= USB_PORT_STAT_HIGH_SPEED;
706*53ee8cc1Swenshuai.xi else if (u32Bus_monitor==1)
707*53ee8cc1Swenshuai.xi u32Status |= USB_PORT_STAT_LOW_SPEED;
708*53ee8cc1Swenshuai.xi //else ==> full u32Speed don't set any bits
709*53ee8cc1Swenshuai.xi
710*53ee8cc1Swenshuai.xi }
711*53ee8cc1Swenshuai.xi if (u32Temp & PORTSC_PE)
712*53ee8cc1Swenshuai.xi u32Status |= USB_PORT_STAT_ENABLE;
713*53ee8cc1Swenshuai.xi if (u32Temp & (PORTSC_SUSPEND | PORTSC_RESUME))
714*53ee8cc1Swenshuai.xi u32Status |= USB_PORT_STAT_SUSPEND;
715*53ee8cc1Swenshuai.xi if (u32Temp & PORTSC_OC)
716*53ee8cc1Swenshuai.xi u32Status |= USB_PORT_STAT_OVERCURRENT;
717*53ee8cc1Swenshuai.xi if (u32Temp & PORTSC_RESET)
718*53ee8cc1Swenshuai.xi u32Status |= USB_PORT_STAT_RESET;
719*53ee8cc1Swenshuai.xi if (u32Temp & PORTSC_POWER)
720*53ee8cc1Swenshuai.xi u32Status |= USB_PORT_STAT_POWER;
721*53ee8cc1Swenshuai.xi }
722*53ee8cc1Swenshuai.xi
723*53ee8cc1Swenshuai.xi *pBuf = u32Status;
724*53ee8cc1Swenshuai.xi *(pBuf+1) = u32Status >> 8;
725*53ee8cc1Swenshuai.xi *(pBuf+2) = u32Status >> 16;
726*53ee8cc1Swenshuai.xi *(pBuf+3) = u32Status >> 24;
727*53ee8cc1Swenshuai.xi break;
728*53ee8cc1Swenshuai.xi case Req_SetHubFeature:
729*53ee8cc1Swenshuai.xi if ((u16Value != C_HUB_LOCAL_POWER)&&(u16Value != C_HUB_OVER_CURRENT))
730*53ee8cc1Swenshuai.xi goto error;
731*53ee8cc1Swenshuai.xi break;
732*53ee8cc1Swenshuai.xi case Req_SetPortFeature:
733*53ee8cc1Swenshuai.xi if (!u16Index || u16Index > iPorts)
734*53ee8cc1Swenshuai.xi goto error;
735*53ee8cc1Swenshuai.xi u16Index--;
736*53ee8cc1Swenshuai.xi u32Temp = hcd_reg_readl ((U32)&pEhci->op_regs->portsc [u16Index]);
737*53ee8cc1Swenshuai.xi #if 0 // MStar patch for Faraday IP
738*53ee8cc1Swenshuai.xi if (u32Temp & PORTSC_OWNER)
739*53ee8cc1Swenshuai.xi break;
740*53ee8cc1Swenshuai.xi #endif
741*53ee8cc1Swenshuai.xi // patch from Linux
742*53ee8cc1Swenshuai.xi u32Temp &= ~PORTSC_RWC_BITS;
743*53ee8cc1Swenshuai.xi
744*53ee8cc1Swenshuai.xi switch (u16Value)
745*53ee8cc1Swenshuai.xi {
746*53ee8cc1Swenshuai.xi case USB_PORT_FEAT_SUSPEND:
747*53ee8cc1Swenshuai.xi ms_debug_msg("SetPortFeature suspend\n");
748*53ee8cc1Swenshuai.xi hcd_reg_writel (u32Temp | PORTSC_SUSPEND,
749*53ee8cc1Swenshuai.xi (U32)&pEhci->op_regs->portsc [u16Index]);
750*53ee8cc1Swenshuai.xi break;
751*53ee8cc1Swenshuai.xi case USB_PORT_FEAT_POWER:
752*53ee8cc1Swenshuai.xi if (HCS_PPC (pEhci->hcs_params))
753*53ee8cc1Swenshuai.xi hcd_reg_writel (u32Temp | PORTSC_POWER,
754*53ee8cc1Swenshuai.xi (U32)&pEhci->op_regs->portsc [u16Index]);
755*53ee8cc1Swenshuai.xi break;
756*53ee8cc1Swenshuai.xi case USB_PORT_FEAT_RESET:
757*53ee8cc1Swenshuai.xi //Do port reset only if device attaches to this port
758*53ee8cc1Swenshuai.xi if( u32Temp&PORTSC_CONNECT )
759*53ee8cc1Swenshuai.xi {
760*53ee8cc1Swenshuai.xi pHcd->isRootHubPortReset = TRUE;
761*53ee8cc1Swenshuai.xi ms_ehci_stoprun_setting(HOST20_Enable, pEhci);
762*53ee8cc1Swenshuai.xi
763*53ee8cc1Swenshuai.xi writeb(0x10, (void*)(u32RegUTMI+0x2C*2)); // chirp patch
764*53ee8cc1Swenshuai.xi writeb(0x00, (void*)(u32RegUTMI+0x2D*2-1)); // chirp patch
765*53ee8cc1Swenshuai.xi writeb(0x00, (void*)(u32RegUTMI+0x2E*2)); // chirp patch
766*53ee8cc1Swenshuai.xi writeb(0x00, (void*)(u32RegUTMI+0x2F*2-1)); // chirp patch
767*53ee8cc1Swenshuai.xi // Chirp K detection level: 0x80 => 400mv, 0x20 => 575mv
768*53ee8cc1Swenshuai.xi writeb(0x80 ,(void*)(u32RegUTMI+0x2A*2)); // chirp patch
769*53ee8cc1Swenshuai.xi
770*53ee8cc1Swenshuai.xi u32Temp |= PORTSC_RESET;
771*53ee8cc1Swenshuai.xi u32Temp &= ~PORTSC_PE;
772*53ee8cc1Swenshuai.xi /*
773*53ee8cc1Swenshuai.xi * 50 ms resets on root for usb spec.
774*53ee8cc1Swenshuai.xi */
775*53ee8cc1Swenshuai.xi pEhci->u32ResetEnd [u16Index] = jiffies
776*53ee8cc1Swenshuai.xi + ((50 /* msec */ * HZ) / 1000);
777*53ee8cc1Swenshuai.xi hcd_reg_writel (u32Temp, (U32)&pEhci->op_regs->portsc [u16Index]); // port reset
778*53ee8cc1Swenshuai.xi }
779*53ee8cc1Swenshuai.xi else
780*53ee8cc1Swenshuai.xi {
781*53ee8cc1Swenshuai.xi /* fail reset process, if device has gone */
782*53ee8cc1Swenshuai.xi diag_printf("[USB] device has gone before bus reset\n");
783*53ee8cc1Swenshuai.xi iRetval = -ENODEV;
784*53ee8cc1Swenshuai.xi }
785*53ee8cc1Swenshuai.xi break;
786*53ee8cc1Swenshuai.xi default:
787*53ee8cc1Swenshuai.xi goto error;
788*53ee8cc1Swenshuai.xi }
789*53ee8cc1Swenshuai.xi u32Temp = hcd_reg_readl ((U32)&pEhci->op_regs->usbcmd); /* unblock posted writes */
790*53ee8cc1Swenshuai.xi break;
791*53ee8cc1Swenshuai.xi
792*53ee8cc1Swenshuai.xi default:
793*53ee8cc1Swenshuai.xi error:
794*53ee8cc1Swenshuai.xi /* issue stall */
795*53ee8cc1Swenshuai.xi iRetval = -EPIPE;
796*53ee8cc1Swenshuai.xi }
797*53ee8cc1Swenshuai.xi osapi_spin_unlock_irqrestore (&pEhci->tHcdLock, u32Flags);
798*53ee8cc1Swenshuai.xi ms_debug_func("--[%s] line:[%d]\n", __FUNCTION__, __LINE__);
799*53ee8cc1Swenshuai.xi return iRetval;
800*53ee8cc1Swenshuai.xi }
801*53ee8cc1Swenshuai.xi
802*53ee8cc1Swenshuai.xi /*------------------------------------------------------------------------------*/
803*53ee8cc1Swenshuai.xi #include "drvEHCI_MEM.cxx"
804*53ee8cc1Swenshuai.xi
805*53ee8cc1Swenshuai.xi /*
806*53ee8cc1Swenshuai.xi * @brief fill qtd buffer from urb
807*53ee8cc1Swenshuai.xi *
808*53ee8cc1Swenshuai.xi * @param struct ehci_qtd *pQtd
809*53ee8cc1Swenshuai.xi * @param dma_addr_t tBufAddr
810*53ee8cc1Swenshuai.xi * @param size_t total
811*53ee8cc1Swenshuai.xi * @param int iToken
812*53ee8cc1Swenshuai.xi * @param int iMaxpkt
813*53ee8cc1Swenshuai.xi *
814*53ee8cc1Swenshuai.xi * @return u32Cnt
815*53ee8cc1Swenshuai.xi */
816*53ee8cc1Swenshuai.xi static int
ms_qtd_pack(struct ehci_qtd * pQtd,dma_addr_t tBufAddr,size_t total,int iToken,int iMaxpkt)817*53ee8cc1Swenshuai.xi ms_qtd_pack (struct ehci_qtd *pQtd, dma_addr_t tBufAddr, size_t total,
818*53ee8cc1Swenshuai.xi int iToken, int iMaxpkt)
819*53ee8cc1Swenshuai.xi {
820*53ee8cc1Swenshuai.xi U32 u32Cnt;
821*53ee8cc1Swenshuai.xi int i/*, lastnums = 0*/;
822*53ee8cc1Swenshuai.xi //unsigned char u8PageShift;
823*53ee8cc1Swenshuai.xi
824*53ee8cc1Swenshuai.xi /* buffer must continuous, first page address may not on 4K boundary */
825*53ee8cc1Swenshuai.xi
826*53ee8cc1Swenshuai.xi ms_debug_func("++[%s] line:[%d]\n", __FUNCTION__, __LINE__);
827*53ee8cc1Swenshuai.xi pQtd->hw_buffer [0] = tBufAddr;
828*53ee8cc1Swenshuai.xi u32Cnt = 0x1000 - (tBufAddr & 0x0fff); /* rest of that page */
829*53ee8cc1Swenshuai.xi if (total < u32Cnt) /* ... iff needed */
830*53ee8cc1Swenshuai.xi u32Cnt = total;
831*53ee8cc1Swenshuai.xi else
832*53ee8cc1Swenshuai.xi {
833*53ee8cc1Swenshuai.xi tBufAddr += 0x1000;
834*53ee8cc1Swenshuai.xi tBufAddr &= ~0x0fff;
835*53ee8cc1Swenshuai.xi
836*53ee8cc1Swenshuai.xi /* pQtd buffer range : min 16K, max 20K */
837*53ee8cc1Swenshuai.xi for (i = 1; u32Cnt < total && i < 5; i++)
838*53ee8cc1Swenshuai.xi {
839*53ee8cc1Swenshuai.xi pQtd->hw_buffer [i] = tBufAddr;
840*53ee8cc1Swenshuai.xi //lastnums++;
841*53ee8cc1Swenshuai.xi tBufAddr += 0x1000;
842*53ee8cc1Swenshuai.xi u32Cnt = ((u32Cnt+0x1000) < total) ? (u32Cnt+0x1000) : total;
843*53ee8cc1Swenshuai.xi }
844*53ee8cc1Swenshuai.xi
845*53ee8cc1Swenshuai.xi /* short packets on transfer end */
846*53ee8cc1Swenshuai.xi if (u32Cnt != total)
847*53ee8cc1Swenshuai.xi u32Cnt -= (u32Cnt % iMaxpkt);
848*53ee8cc1Swenshuai.xi }
849*53ee8cc1Swenshuai.xi pQtd->hw_token = (u32Cnt << 16) | iToken;
850*53ee8cc1Swenshuai.xi pQtd->length = u32Cnt;
851*53ee8cc1Swenshuai.xi /* un-patched base on linux code */
852*53ee8cc1Swenshuai.xi //if ((u32Cnt > 0) && (lastnums < 4))
853*53ee8cc1Swenshuai.xi //{
854*53ee8cc1Swenshuai.xi // for (u8PageShift = lastnums + 1;u8PageShift < 5; u8PageShift++)
855*53ee8cc1Swenshuai.xi // {
856*53ee8cc1Swenshuai.xi // pQtd->hw_buffer[u8PageShift] = pQtd->hw_buffer [lastnums];
857*53ee8cc1Swenshuai.xi // }
858*53ee8cc1Swenshuai.xi //}
859*53ee8cc1Swenshuai.xi ms_debug_func("--[%s] line:[%d]\n", __FUNCTION__, __LINE__);
860*53ee8cc1Swenshuai.xi return u32Cnt;
861*53ee8cc1Swenshuai.xi }
862*53ee8cc1Swenshuai.xi
863*53ee8cc1Swenshuai.xi /*-------------------------------------------------------------------------*/
864*53ee8cc1Swenshuai.xi /*
865*53ee8cc1Swenshuai.xi * @brief refresh QH overlay, based on Linux 3.10.x
866*53ee8cc1Swenshuai.xi * merge qh_refresh and qh_update
867*53ee8cc1Swenshuai.xi *
868*53ee8cc1Swenshuai.xi * @param struct ehci_hcd *pEhci
869*53ee8cc1Swenshuai.xi * @param struct ehci_qh *pQh
870*53ee8cc1Swenshuai.xi *
871*53ee8cc1Swenshuai.xi * @return none
872*53ee8cc1Swenshuai.xi */
873*53ee8cc1Swenshuai.xi
874*53ee8cc1Swenshuai.xi static void
ms_qh_refresh(struct ehci_hcd * pEhci,struct ehci_qh * pQh)875*53ee8cc1Swenshuai.xi ms_qh_refresh (struct ehci_hcd *pEhci, struct ehci_qh *pQh)
876*53ee8cc1Swenshuai.xi {
877*53ee8cc1Swenshuai.xi struct ehci_qtd *pQtd;
878*53ee8cc1Swenshuai.xi
879*53ee8cc1Swenshuai.xi ms_debug_func("++[%s] line:[%d]\n", __FUNCTION__, __LINE__);
880*53ee8cc1Swenshuai.xi pQtd = entry_to_container(pQh->qtd_list.next, struct ehci_qtd, qtd_list);
881*53ee8cc1Swenshuai.xi
882*53ee8cc1Swenshuai.xi if (pQh->hw_token & QTD_STS_ACT)
883*53ee8cc1Swenshuai.xi {
884*53ee8cc1Swenshuai.xi ms_debug_debug("[USB] QTD_STS_ACT, (%x,%x)\n", pQh->hw_next_qtd, pQtd->hw_next_qtd);
885*53ee8cc1Swenshuai.xi pQh->hw_next_qtd = pQtd->hw_next_qtd;
886*53ee8cc1Swenshuai.xi }
887*53ee8cc1Swenshuai.xi else {
888*53ee8cc1Swenshuai.xi if (pQh->qh_status != QH_STS_IDLE)
889*53ee8cc1Swenshuai.xi ms_debug_err("[USB] Not in IDLE state!\n");
890*53ee8cc1Swenshuai.xi pQh->hw_next_qtd = (U32)(pQtd->qtd_dma_addr);
891*53ee8cc1Swenshuai.xi pQh->hw_alt_next_qtd = EHCI_LIST_END;
892*53ee8cc1Swenshuai.xi
893*53ee8cc1Swenshuai.xi if (!(pQh->hw_ep_state1 & QH_DTC_BIT)) {
894*53ee8cc1Swenshuai.xi unsigned is_out, epnum;
895*53ee8cc1Swenshuai.xi
896*53ee8cc1Swenshuai.xi is_out = usb_pipeout(pQtd->urb->u32Pipe);
897*53ee8cc1Swenshuai.xi epnum = (pQh->hw_ep_state1 >> 8) & 0x0f;
898*53ee8cc1Swenshuai.xi if (!usb_gettoggle (pQh->dev, epnum, is_out)) {
899*53ee8cc1Swenshuai.xi pQh->hw_token &= ~QTD_TOGGLE;
900*53ee8cc1Swenshuai.xi usb_settoggle (pQh->dev, epnum, is_out, 1);
901*53ee8cc1Swenshuai.xi }
902*53ee8cc1Swenshuai.xi }
903*53ee8cc1Swenshuai.xi
904*53ee8cc1Swenshuai.xi pQh->hw_token &= (QTD_TOGGLE | QTD_STS_PERR);
905*53ee8cc1Swenshuai.xi }
906*53ee8cc1Swenshuai.xi
907*53ee8cc1Swenshuai.xi ms_debug_func("--[%s] line:[%d]\n", __FUNCTION__, __LINE__);
908*53ee8cc1Swenshuai.xi }
909*53ee8cc1Swenshuai.xi
910*53ee8cc1Swenshuai.xi #ifndef ENABLE_QH_REFRESH // replaced by ms_qh_refresh()
911*53ee8cc1Swenshuai.xi /*-------------------------------------------------------------------------*/
912*53ee8cc1Swenshuai.xi /*
913*53ee8cc1Swenshuai.xi * @brief link qtd list to qh
914*53ee8cc1Swenshuai.xi *
915*53ee8cc1Swenshuai.xi * @param struct ehci_qh *pQh
916*53ee8cc1Swenshuai.xi * @param struct ehci_qtd *pQtd
917*53ee8cc1Swenshuai.xi *
918*53ee8cc1Swenshuai.xi * @return none
919*53ee8cc1Swenshuai.xi */
920*53ee8cc1Swenshuai.xi
921*53ee8cc1Swenshuai.xi static __inline__ void
ms_qh_update_link(struct ehci_qh * pQh,struct ehci_qtd * pQtd)922*53ee8cc1Swenshuai.xi ms_qh_update_link (struct ehci_qh *pQh, struct ehci_qtd *pQtd)
923*53ee8cc1Swenshuai.xi {
924*53ee8cc1Swenshuai.xi ms_debug_func("++[%s] line:[%d]\n", __FUNCTION__, __LINE__);
925*53ee8cc1Swenshuai.xi pQh->hw_next_qtd = (U32)(pQtd->qtd_dma_addr);
926*53ee8cc1Swenshuai.xi pQh->hw_alt_next_qtd = EHCI_LIST_END;
927*53ee8cc1Swenshuai.xi
928*53ee8cc1Swenshuai.xi /* HC must see latest pQtd and pQh data before we clear ACTIVE+HALT */
929*53ee8cc1Swenshuai.xi wmb ();
930*53ee8cc1Swenshuai.xi pQh->hw_token &= (QTD_TOGGLE | QTD_STS_PERR);
931*53ee8cc1Swenshuai.xi ms_debug_func("--[%s] line:[%d]\n", __FUNCTION__, __LINE__);
932*53ee8cc1Swenshuai.xi }
933*53ee8cc1Swenshuai.xi #endif
934*53ee8cc1Swenshuai.xi
935*53ee8cc1Swenshuai.xi /*-------------------------------------------------------------------------*/
936*53ee8cc1Swenshuai.xi /*
937*53ee8cc1Swenshuai.xi * @brief check qtd status register
938*53ee8cc1Swenshuai.xi *
939*53ee8cc1Swenshuai.xi * @param struct urb *pUrb
940*53ee8cc1Swenshuai.xi * @param size_t length
941*53ee8cc1Swenshuai.xi * @param U32 u32Token
942*53ee8cc1Swenshuai.xi *
943*53ee8cc1Swenshuai.xi * @return none
944*53ee8cc1Swenshuai.xi */
945*53ee8cc1Swenshuai.xi
ms_qtd_copy_status(struct urb * pUrb,size_t length,U32 u32Token)946*53ee8cc1Swenshuai.xi static void ms_qtd_copy_status (
947*53ee8cc1Swenshuai.xi struct urb *pUrb,
948*53ee8cc1Swenshuai.xi size_t length,
949*53ee8cc1Swenshuai.xi U32 u32Token
950*53ee8cc1Swenshuai.xi )
951*53ee8cc1Swenshuai.xi {
952*53ee8cc1Swenshuai.xi #ifdef USB_EHCI_TT
953*53ee8cc1Swenshuai.xi struct usb_hcd *hcd = pUrb->dev->bus->hcpriv;
954*53ee8cc1Swenshuai.xi #endif
955*53ee8cc1Swenshuai.xi
956*53ee8cc1Swenshuai.xi ms_debug_func("++[%s] line:[%d]\n", __FUNCTION__, __LINE__);
957*53ee8cc1Swenshuai.xi
958*53ee8cc1Swenshuai.xi if (QTD_PID (u32Token) != 2)
959*53ee8cc1Swenshuai.xi pUrb->u32ActualLength += length - QTD_BYTES (u32Token);
960*53ee8cc1Swenshuai.xi
961*53ee8cc1Swenshuai.xi /* error codes ���n�h�復 */
962*53ee8cc1Swenshuai.xi if (pUrb->s32Status != -EINPROGRESS)
963*53ee8cc1Swenshuai.xi return;
964*53ee8cc1Swenshuai.xi
965*53ee8cc1Swenshuai.xi /* force cleanup , may not a wrong */
966*53ee8cc1Swenshuai.xi if (IS_SHORT_READ (u32Token))
967*53ee8cc1Swenshuai.xi pUrb->s32Status = -MS_ERR_REMOTEIO;
968*53ee8cc1Swenshuai.xi
969*53ee8cc1Swenshuai.xi if (u32Token & QTD_STS_HALT)
970*53ee8cc1Swenshuai.xi {
971*53ee8cc1Swenshuai.xi if (u32Token & QTD_STS_BABBLE)
972*53ee8cc1Swenshuai.xi {
973*53ee8cc1Swenshuai.xi diag_printf(" [ !!!! USB QTD_STS_BABBLE !!!!] \n "); // SHOULD BE PRINT
974*53ee8cc1Swenshuai.xi pUrb->s32Status = -MS_ERR_OVERFLOW;
975*53ee8cc1Swenshuai.xi }
976*53ee8cc1Swenshuai.xi else if (u32Token & QTD_STS_MISSMF)
977*53ee8cc1Swenshuai.xi {
978*53ee8cc1Swenshuai.xi diag_printf(" [ !!!! USB QTD_STS_MISSMF !!!!] \n "); // SHOULD BE PRINT
979*53ee8cc1Swenshuai.xi /* FS/LS transfer lost complete-split */
980*53ee8cc1Swenshuai.xi pUrb->s32Status = -MS_ERR_PROTOCAL;
981*53ee8cc1Swenshuai.xi }
982*53ee8cc1Swenshuai.xi else if (u32Token & QTD_STS_DATERR)
983*53ee8cc1Swenshuai.xi {
984*53ee8cc1Swenshuai.xi diag_printf(" [ !!!! USB QTD_STS_DATERR !!!!] \n "); // SHOULD BE PRINT
985*53ee8cc1Swenshuai.xi pUrb->s32Status = (QTD_PID (u32Token) == 1) /* Is IN token? */
986*53ee8cc1Swenshuai.xi ? -MS_ERR_RECEIVE /* HCD can't read data */
987*53ee8cc1Swenshuai.xi : -MS_ERR_SEND; /* HCD can't write data */
988*53ee8cc1Swenshuai.xi }
989*53ee8cc1Swenshuai.xi else if (u32Token & QTD_STS_XACTERR)
990*53ee8cc1Swenshuai.xi {
991*53ee8cc1Swenshuai.xi ms_debug_msg(" [ USB QTD_STS_XACTERR ] \n ");
992*53ee8cc1Swenshuai.xi
993*53ee8cc1Swenshuai.xi if (QTD_CERR (u32Token)) /* ���~���Atimeout, bad crc, wrong PID */
994*53ee8cc1Swenshuai.xi pUrb->s32Status = -EPIPE;
995*53ee8cc1Swenshuai.xi else
996*53ee8cc1Swenshuai.xi {
997*53ee8cc1Swenshuai.xi ms_debug_warn ("devpath %s ep%d%s 3strikes\n",
998*53ee8cc1Swenshuai.xi pUrb->dev->devpath,
999*53ee8cc1Swenshuai.xi (int)usb_pipeendpoint (pUrb->u32Pipe),
1000*53ee8cc1Swenshuai.xi usb_pipein (pUrb->u32Pipe) ? "in" : "out");
1001*53ee8cc1Swenshuai.xi pUrb->s32Status = -MS_ERR_PROTOCAL;
1002*53ee8cc1Swenshuai.xi }
1003*53ee8cc1Swenshuai.xi /* �S��error bit ���O��halt, will stall */
1004*53ee8cc1Swenshuai.xi }
1005*53ee8cc1Swenshuai.xi else if (QTD_CERR (u32Token))
1006*53ee8cc1Swenshuai.xi pUrb->s32Status = -EPIPE;
1007*53ee8cc1Swenshuai.xi else /* ���������~ */
1008*53ee8cc1Swenshuai.xi pUrb->s32Status = -MS_ERR_PROTOCAL;
1009*53ee8cc1Swenshuai.xi
1010*53ee8cc1Swenshuai.xi if( pUrb->s32Status < 0 )
1011*53ee8cc1Swenshuai.xi {
1012*53ee8cc1Swenshuai.xi ms_debug_warn("dev%d ep%d%s qtd token %08x --> status %d, len=%d\n",
1013*53ee8cc1Swenshuai.xi (int)usb_pipedevice (pUrb->u32Pipe),
1014*53ee8cc1Swenshuai.xi (int)usb_pipeendpoint (pUrb->u32Pipe),
1015*53ee8cc1Swenshuai.xi usb_pipein (pUrb->u32Pipe) ? "in" : "out",
1016*53ee8cc1Swenshuai.xi (unsigned int)u32Token, (int)pUrb->s32Status, (int)pUrb->u32TransferBufferLength);
1017*53ee8cc1Swenshuai.xi }
1018*53ee8cc1Swenshuai.xi
1019*53ee8cc1Swenshuai.xi
1020*53ee8cc1Swenshuai.xi /* Stall ��ܻݭn��error recovery */
1021*53ee8cc1Swenshuai.xi if (pUrb->s32Status == -EPIPE)
1022*53ee8cc1Swenshuai.xi {
1023*53ee8cc1Swenshuai.xi /* halt bit obsolete */
1024*53ee8cc1Swenshuai.xi //int pipe = pUrb->u32Pipe;
1025*53ee8cc1Swenshuai.xi
1026*53ee8cc1Swenshuai.xi //if (!usb_pipecontrol (pipe))
1027*53ee8cc1Swenshuai.xi // usb_endpoint_halt (pUrb->dev, usb_pipeendpoint (pipe), usb_pipeout (pipe));
1028*53ee8cc1Swenshuai.xi
1029*53ee8cc1Swenshuai.xi }
1030*53ee8cc1Swenshuai.xi /* if async CSPLIT failed, try cleaning out the TT buffer */
1031*53ee8cc1Swenshuai.xi /* patch from linux 2.6.28 */
1032*53ee8cc1Swenshuai.xi #ifdef USB_EHCI_TT
1033*53ee8cc1Swenshuai.xi else if (pUrb->dev->tt && !usb_pipeint (pUrb->u32Pipe)
1034*53ee8cc1Swenshuai.xi && ((u32Token & QTD_STS_MISSMF) != 0 || QTD_CERR(u32Token) == 0)
1035*53ee8cc1Swenshuai.xi && (pUrb->dev->tt->hub != hcd->self.root_hub))
1036*53ee8cc1Swenshuai.xi {
1037*53ee8cc1Swenshuai.xi //#ifdef DEBUG
1038*53ee8cc1Swenshuai.xi ms_debug_msg ("clear tt buffer port %d, a%d ep%d t%08x\n",
1039*53ee8cc1Swenshuai.xi pUrb->dev->u32TTPort, pUrb->dev->u32DevNum,
1040*53ee8cc1Swenshuai.xi usb_pipeendpoint (pUrb->u32Pipe), u32Token);
1041*53ee8cc1Swenshuai.xi //#endif
1042*53ee8cc1Swenshuai.xi ms_usb_hub_tt_clear_buffer (pUrb->dev, pUrb->u32Pipe);
1043*53ee8cc1Swenshuai.xi }
1044*53ee8cc1Swenshuai.xi #endif
1045*53ee8cc1Swenshuai.xi }
1046*53ee8cc1Swenshuai.xi ms_debug_func("--[%s] line:[%d]\n", __FUNCTION__, __LINE__);
1047*53ee8cc1Swenshuai.xi }
1048*53ee8cc1Swenshuai.xi
1049*53ee8cc1Swenshuai.xi
1050*53ee8cc1Swenshuai.xi static void
ms_urb_done(struct ehci_hcd * pEhci,struct urb * pUrb,struct stPtRegs * pRegs)1051*53ee8cc1Swenshuai.xi ms_urb_done (struct ehci_hcd *pEhci, struct urb *pUrb, struct stPtRegs *pRegs)
1052*53ee8cc1Swenshuai.xi {
1053*53ee8cc1Swenshuai.xi ms_debug_func("++[%s] line:[%d]\n", __FUNCTION__, __LINE__);
1054*53ee8cc1Swenshuai.xi if (pUrb->hcpriv != 0)
1055*53ee8cc1Swenshuai.xi {
1056*53ee8cc1Swenshuai.xi struct ehci_qh *qh = (struct ehci_qh *) pUrb->hcpriv;
1057*53ee8cc1Swenshuai.xi ms_qh_put (pEhci, qh);
1058*53ee8cc1Swenshuai.xi }
1059*53ee8cc1Swenshuai.xi
1060*53ee8cc1Swenshuai.xi osapi_spin_lock (&pUrb->lock);
1061*53ee8cc1Swenshuai.xi pUrb->hcpriv = 0;
1062*53ee8cc1Swenshuai.xi switch (pUrb->s32Status)
1063*53ee8cc1Swenshuai.xi {
1064*53ee8cc1Swenshuai.xi case -EINPROGRESS: /* success */
1065*53ee8cc1Swenshuai.xi pUrb->s32Status = 0;
1066*53ee8cc1Swenshuai.xi default: /* fault */
1067*53ee8cc1Swenshuai.xi INCREASE (pEhci->stats.u32Complete);
1068*53ee8cc1Swenshuai.xi break;
1069*53ee8cc1Swenshuai.xi case -MS_ERR_REMOTEIO: /* fault or normal */
1070*53ee8cc1Swenshuai.xi if (!(pUrb->u32TransferFlags & MS_FLAG_URB_SHORT_NOT_OK))
1071*53ee8cc1Swenshuai.xi pUrb->s32Status = 0;
1072*53ee8cc1Swenshuai.xi INCREASE (pEhci->stats.u32Complete);
1073*53ee8cc1Swenshuai.xi break;
1074*53ee8cc1Swenshuai.xi case -ECONNRESET: /* canceled */
1075*53ee8cc1Swenshuai.xi case -ENOENT:
1076*53ee8cc1Swenshuai.xi INCREASE(pEhci->stats.u32Unlink);
1077*53ee8cc1Swenshuai.xi break;
1078*53ee8cc1Swenshuai.xi }
1079*53ee8cc1Swenshuai.xi osapi_spin_unlock (&pUrb->lock);
1080*53ee8cc1Swenshuai.xi
1081*53ee8cc1Swenshuai.xi /* HCD run complete() funciton */
1082*53ee8cc1Swenshuai.xi osapi_spin_unlock (&pEhci->tHcdLock);
1083*53ee8cc1Swenshuai.xi ms_usb_hcd_giveback_urb (pUrb, pRegs);
1084*53ee8cc1Swenshuai.xi osapi_spin_lock (&pEhci->tHcdLock);
1085*53ee8cc1Swenshuai.xi ms_debug_func("--[%s] line:[%d]\n", __FUNCTION__, __LINE__);
1086*53ee8cc1Swenshuai.xi }
1087*53ee8cc1Swenshuai.xi
1088*53ee8cc1Swenshuai.xi /*
1089*53ee8cc1Swenshuai.xi * @brief free qtd list and run urb's complet function
1090*53ee8cc1Swenshuai.xi *
1091*53ee8cc1Swenshuai.xi * @param struct ehci_hcd *pEhci
1092*53ee8cc1Swenshuai.xi * @param struct ehci_qh *pQh
1093*53ee8cc1Swenshuai.xi * @param struct stPtRegs *pRegs
1094*53ee8cc1Swenshuai.xi *
1095*53ee8cc1Swenshuai.xi * @return u8Count
1096*53ee8cc1Swenshuai.xi */
1097*53ee8cc1Swenshuai.xi
1098*53ee8cc1Swenshuai.xi #define HALT_BIT QTD_STS_HALT
1099*53ee8cc1Swenshuai.xi static unsigned
ms_qh_completions(struct ehci_hcd * pEhci,struct ehci_qh * pQh,struct stPtRegs * pRegs)1100*53ee8cc1Swenshuai.xi ms_qh_completions (struct ehci_hcd *pEhci, struct ehci_qh *pQh, struct stPtRegs *pRegs)
1101*53ee8cc1Swenshuai.xi {
1102*53ee8cc1Swenshuai.xi struct ehci_qtd *pLast = 0, *pEnd = pQh->pDummyQtd;
1103*53ee8cc1Swenshuai.xi struct list_head *entry, *tmp;
1104*53ee8cc1Swenshuai.xi int iStopped;
1105*53ee8cc1Swenshuai.xi unsigned u8Count = 0;
1106*53ee8cc1Swenshuai.xi int iDoStatus = 0;
1107*53ee8cc1Swenshuai.xi unsigned char u8State;
1108*53ee8cc1Swenshuai.xi //BOOL bIsPageOver = FALSE; // obsolete
1109*53ee8cc1Swenshuai.xi
1110*53ee8cc1Swenshuai.xi ms_debug_func("++[%s] line:[%d]\n", __FUNCTION__, __LINE__);
1111*53ee8cc1Swenshuai.xi if (ms_is_empty_list (&pQh->qtd_list))
1112*53ee8cc1Swenshuai.xi {
1113*53ee8cc1Swenshuai.xi ms_debug_func("--[%s] line:[%d]\n", __FUNCTION__, __LINE__);
1114*53ee8cc1Swenshuai.xi return u8Count;
1115*53ee8cc1Swenshuai.xi }
1116*53ee8cc1Swenshuai.xi
1117*53ee8cc1Swenshuai.xi u8State = pQh->qh_status;
1118*53ee8cc1Swenshuai.xi pQh->qh_status = QH_STS_COMPLETING;
1119*53ee8cc1Swenshuai.xi iStopped = (u8State == QH_STS_IDLE);
1120*53ee8cc1Swenshuai.xi
1121*53ee8cc1Swenshuai.xi list_for_loop_ex (entry, tmp, &pQh->qtd_list)
1122*53ee8cc1Swenshuai.xi {
1123*53ee8cc1Swenshuai.xi struct ehci_qtd *pQtd;
1124*53ee8cc1Swenshuai.xi struct urb *pUrb;
1125*53ee8cc1Swenshuai.xi U32 u32Token = 0;
1126*53ee8cc1Swenshuai.xi
1127*53ee8cc1Swenshuai.xi pQtd = entry_to_container (entry, struct ehci_qtd, qtd_list);
1128*53ee8cc1Swenshuai.xi //list_entry (entry, struct ehci_qtd,qtd_list, struct list_head,qtd);
1129*53ee8cc1Swenshuai.xi pUrb = pQtd->urb;
1130*53ee8cc1Swenshuai.xi
1131*53ee8cc1Swenshuai.xi /* obsolete, no such hardware bug */
1132*53ee8cc1Swenshuai.xi //if ( ((pQtd->hw_token >> 12) & 0x7) > 5) //For patching H/W bug
1133*53ee8cc1Swenshuai.xi //{
1134*53ee8cc1Swenshuai.xi // bIsPageOver = TRUE;
1135*53ee8cc1Swenshuai.xi //}
1136*53ee8cc1Swenshuai.xi
1137*53ee8cc1Swenshuai.xi /* free previous QTD ...*/
1138*53ee8cc1Swenshuai.xi if (pLast)
1139*53ee8cc1Swenshuai.xi {
1140*53ee8cc1Swenshuai.xi if (pLast->urb != pUrb)
1141*53ee8cc1Swenshuai.xi {
1142*53ee8cc1Swenshuai.xi ms_urb_done (pEhci, pLast->urb, pRegs);
1143*53ee8cc1Swenshuai.xi u8Count++;
1144*53ee8cc1Swenshuai.xi }
1145*53ee8cc1Swenshuai.xi ms_ehci_qtd_free (pEhci, pLast);
1146*53ee8cc1Swenshuai.xi pLast = 0;
1147*53ee8cc1Swenshuai.xi }
1148*53ee8cc1Swenshuai.xi
1149*53ee8cc1Swenshuai.xi if (pQtd == pEnd)
1150*53ee8cc1Swenshuai.xi break;
1151*53ee8cc1Swenshuai.xi
1152*53ee8cc1Swenshuai.xi /* HW implement qtds content copy */
1153*53ee8cc1Swenshuai.xi rmb ();
1154*53ee8cc1Swenshuai.xi
1155*53ee8cc1Swenshuai.xi u32Token = pQtd->hw_token;
1156*53ee8cc1Swenshuai.xi
1157*53ee8cc1Swenshuai.xi xacterr_retry:
1158*53ee8cc1Swenshuai.xi if ((u32Token & QTD_STS_ACT) == 0)
1159*53ee8cc1Swenshuai.xi {
1160*53ee8cc1Swenshuai.xi if ((u32Token & QTD_STS_HALT) != 0)
1161*53ee8cc1Swenshuai.xi {
1162*53ee8cc1Swenshuai.xi if ((u32Token & QTD_STS_XACTERR) &&
1163*53ee8cc1Swenshuai.xi QTD_CERR(u32Token) == 0 &&
1164*53ee8cc1Swenshuai.xi --pQh->xacterrs > 0 /*&& !urb->unlinked*/) {
1165*53ee8cc1Swenshuai.xi u32Token &= ~QTD_STS_HALT;
1166*53ee8cc1Swenshuai.xi u32Token |= QTD_STS_ACT | (MAX_CERR_CNT << 10);
1167*53ee8cc1Swenshuai.xi pQtd->hw_token = u32Token;
1168*53ee8cc1Swenshuai.xi wmb();
1169*53ee8cc1Swenshuai.xi pQh->hw_token = u32Token;
1170*53ee8cc1Swenshuai.xi goto xacterr_retry;
1171*53ee8cc1Swenshuai.xi }
1172*53ee8cc1Swenshuai.xi iStopped = 1;
1173*53ee8cc1Swenshuai.xi }
1174*53ee8cc1Swenshuai.xi else if (IS_SHORT_READ (u32Token)
1175*53ee8cc1Swenshuai.xi /* patch from linux */
1176*53ee8cc1Swenshuai.xi && !(pQtd->hw_alt_next_qtd & EHCI_LIST_END))
1177*53ee8cc1Swenshuai.xi // && (pQh->hw_alt_next_qtd & QTD_MASK)
1178*53ee8cc1Swenshuai.xi // == pEhci->stAsync->hw_alt_next_qtd)
1179*53ee8cc1Swenshuai.xi {
1180*53ee8cc1Swenshuai.xi iStopped = 1;
1181*53ee8cc1Swenshuai.xi goto halt;
1182*53ee8cc1Swenshuai.xi }
1183*53ee8cc1Swenshuai.xi }
1184*53ee8cc1Swenshuai.xi else if(!iStopped && HCD_IS_RUNNING (pEhci->hcd.state))
1185*53ee8cc1Swenshuai.xi {
1186*53ee8cc1Swenshuai.xi break;
1187*53ee8cc1Swenshuai.xi }
1188*53ee8cc1Swenshuai.xi else
1189*53ee8cc1Swenshuai.xi {
1190*53ee8cc1Swenshuai.xi iStopped = 1;
1191*53ee8cc1Swenshuai.xi
1192*53ee8cc1Swenshuai.xi if (pUrb->s32Status == -EINPROGRESS)
1193*53ee8cc1Swenshuai.xi continue;
1194*53ee8cc1Swenshuai.xi
1195*53ee8cc1Swenshuai.xi /* issue status for control transfer */
1196*53ee8cc1Swenshuai.xi if ((iDoStatus != 0)
1197*53ee8cc1Swenshuai.xi && QTD_PID (u32Token) == 0) //Check is OUT token?
1198*53ee8cc1Swenshuai.xi {
1199*53ee8cc1Swenshuai.xi iDoStatus = 0;
1200*53ee8cc1Swenshuai.xi continue;
1201*53ee8cc1Swenshuai.xi }
1202*53ee8cc1Swenshuai.xi
1203*53ee8cc1Swenshuai.xi if (u8State == QH_STS_IDLE
1204*53ee8cc1Swenshuai.xi && pQtd->qtd_dma_addr
1205*53ee8cc1Swenshuai.xi == pQh->hw_current_qtd)
1206*53ee8cc1Swenshuai.xi u32Token = pQh->hw_token;
1207*53ee8cc1Swenshuai.xi
1208*53ee8cc1Swenshuai.xi if ((HALT_BIT & pQh->hw_token) == 0)
1209*53ee8cc1Swenshuai.xi {
1210*53ee8cc1Swenshuai.xi halt:
1211*53ee8cc1Swenshuai.xi pQh->hw_token |= HALT_BIT;
1212*53ee8cc1Swenshuai.xi wmb ();
1213*53ee8cc1Swenshuai.xi }
1214*53ee8cc1Swenshuai.xi }
1215*53ee8cc1Swenshuai.xi
1216*53ee8cc1Swenshuai.xi
1217*53ee8cc1Swenshuai.xi /* remove it from the queue */
1218*53ee8cc1Swenshuai.xi osapi_spin_lock (&pUrb->lock);
1219*53ee8cc1Swenshuai.xi ms_qtd_copy_status (pUrb, pQtd->length, u32Token);
1220*53ee8cc1Swenshuai.xi /* obsolete, no such hardware bug */
1221*53ee8cc1Swenshuai.xi //if (bIsPageOver)
1222*53ee8cc1Swenshuai.xi //{
1223*53ee8cc1Swenshuai.xi // ms_debug_warn("urb error because C_Page > 5\n");
1224*53ee8cc1Swenshuai.xi // pUrb->s32Status = (QTD_PID (u32Token) == 1) /* Is IN token? */
1225*53ee8cc1Swenshuai.xi // ? -MS_ERR_RECEIVE /* HCD can't read data */
1226*53ee8cc1Swenshuai.xi // : -MS_ERR_SEND; /* HCD can't write data */
1227*53ee8cc1Swenshuai.xi //}
1228*53ee8cc1Swenshuai.xi iDoStatus = (pUrb->s32Status == -MS_ERR_REMOTEIO)
1229*53ee8cc1Swenshuai.xi && usb_pipecontrol (pUrb->u32Pipe);
1230*53ee8cc1Swenshuai.xi osapi_spin_unlock (&pUrb->lock);
1231*53ee8cc1Swenshuai.xi
1232*53ee8cc1Swenshuai.xi if (iStopped && pQtd->qtd_list.prev != &pQh->qtd_list) {
1233*53ee8cc1Swenshuai.xi pLast = entry_to_container (pQtd->qtd_list.prev, struct ehci_qtd, qtd_list);
1234*53ee8cc1Swenshuai.xi //list_entry (qtd->qtd_list.prev,struct ehci_qtd,qtd_list, struct list_head,last);
1235*53ee8cc1Swenshuai.xi pLast->hw_next_qtd = pQtd->hw_next_qtd;
1236*53ee8cc1Swenshuai.xi
1237*53ee8cc1Swenshuai.xi }
1238*53ee8cc1Swenshuai.xi ms_list_remove (&pQtd->qtd_list);
1239*53ee8cc1Swenshuai.xi pLast = pQtd;
1240*53ee8cc1Swenshuai.xi
1241*53ee8cc1Swenshuai.xi pQh->xacterrs = QH_MAX_XACTRTT_RETRY;
1242*53ee8cc1Swenshuai.xi }
1243*53ee8cc1Swenshuai.xi
1244*53ee8cc1Swenshuai.xi if (pLast != 0)
1245*53ee8cc1Swenshuai.xi {
1246*53ee8cc1Swenshuai.xi ms_urb_done (pEhci, pLast->urb, pRegs);
1247*53ee8cc1Swenshuai.xi u8Count++;
1248*53ee8cc1Swenshuai.xi ms_ehci_qtd_free (pEhci, pLast);
1249*53ee8cc1Swenshuai.xi pLast = 0;
1250*53ee8cc1Swenshuai.xi }
1251*53ee8cc1Swenshuai.xi
1252*53ee8cc1Swenshuai.xi pQh->qh_status = u8State;
1253*53ee8cc1Swenshuai.xi
1254*53ee8cc1Swenshuai.xi if ((iStopped != 0)
1255*53ee8cc1Swenshuai.xi /* avoid some old EHCI vendor will overlay dummy qtds */
1256*53ee8cc1Swenshuai.xi || pQh->hw_next_qtd == EHCI_LIST_END)
1257*53ee8cc1Swenshuai.xi {
1258*53ee8cc1Swenshuai.xi #ifdef ENABLE_QH_REFRESH
1259*53ee8cc1Swenshuai.xi /* patch from linux 2.6.x ~ 3.8.x */
1260*53ee8cc1Swenshuai.xi if (u8State == QH_STS_IDLE)
1261*53ee8cc1Swenshuai.xi ms_qh_refresh(pEhci, pQh);
1262*53ee8cc1Swenshuai.xi else if (u8State == QH_STS_LINKED) {
1263*53ee8cc1Swenshuai.xi /* patch base on linux 2.6.x */
1264*53ee8cc1Swenshuai.xi if ((pQh->hw_ep_state2 & QH_SMASK) != 0) {
1265*53ee8cc1Swenshuai.xi ms_intr_deschedule(pEhci, pQh);
1266*53ee8cc1Swenshuai.xi ms_qh_schedule(pEhci, pQh);
1267*53ee8cc1Swenshuai.xi }
1268*53ee8cc1Swenshuai.xi else
1269*53ee8cc1Swenshuai.xi ms_unlink_async(pEhci, pQh);
1270*53ee8cc1Swenshuai.xi }
1271*53ee8cc1Swenshuai.xi #else // replaced by linux code
1272*53ee8cc1Swenshuai.xi if (ms_is_empty_list (&pQh->qtd_list))
1273*53ee8cc1Swenshuai.xi pEnd = pQh->pDummyQtd;
1274*53ee8cc1Swenshuai.xi else
1275*53ee8cc1Swenshuai.xi {
1276*53ee8cc1Swenshuai.xi pEnd = entry_to_container (pQh->qtd_list.next,struct ehci_qtd, qtd_list);
1277*53ee8cc1Swenshuai.xi if (pEnd->qtd_dma_addr == pQh->hw_current_qtd)
1278*53ee8cc1Swenshuai.xi pEnd = 0;
1279*53ee8cc1Swenshuai.xi }
1280*53ee8cc1Swenshuai.xi if (pEnd)
1281*53ee8cc1Swenshuai.xi ms_qh_update_link (pQh, pEnd);
1282*53ee8cc1Swenshuai.xi #endif
1283*53ee8cc1Swenshuai.xi }
1284*53ee8cc1Swenshuai.xi
1285*53ee8cc1Swenshuai.xi ms_debug_func("--[%s] line:[%d]\n", __FUNCTION__, __LINE__);
1286*53ee8cc1Swenshuai.xi return u8Count;
1287*53ee8cc1Swenshuai.xi }
1288*53ee8cc1Swenshuai.xi
1289*53ee8cc1Swenshuai.xi /*-------------------------------------------------------------------------*/
1290*53ee8cc1Swenshuai.xi // high bandwidth multiplier, as encoded in highspeed endpoint descriptors
1291*53ee8cc1Swenshuai.xi #define hb_mult(wMaxPacketSize) (1 + (((wMaxPacketSize) >> 11) & 0x03))
1292*53ee8cc1Swenshuai.xi // ... and packet size, for any kind of endpoint descriptor
1293*53ee8cc1Swenshuai.xi #define max_packet(wMaxPacketSize) ((wMaxPacketSize) & 0x07ff)
1294*53ee8cc1Swenshuai.xi
ms_qtd_register_free(struct ehci_hcd * pEhci,struct list_head * qtd_list)1295*53ee8cc1Swenshuai.xi static void ms_qtd_register_free (
1296*53ee8cc1Swenshuai.xi struct ehci_hcd *pEhci,
1297*53ee8cc1Swenshuai.xi struct list_head *qtd_list
1298*53ee8cc1Swenshuai.xi )
1299*53ee8cc1Swenshuai.xi {
1300*53ee8cc1Swenshuai.xi struct list_head *pEntry, *pTemp;
1301*53ee8cc1Swenshuai.xi
1302*53ee8cc1Swenshuai.xi ms_debug_func("++[%s] line:[%d]\n", __FUNCTION__, __LINE__);
1303*53ee8cc1Swenshuai.xi list_for_loop_ex (pEntry, pTemp, qtd_list)
1304*53ee8cc1Swenshuai.xi {
1305*53ee8cc1Swenshuai.xi struct ehci_qtd *pQtd;
1306*53ee8cc1Swenshuai.xi
1307*53ee8cc1Swenshuai.xi pQtd = entry_to_container (pEntry, struct ehci_qtd, qtd_list);
1308*53ee8cc1Swenshuai.xi ms_list_remove (&pQtd->qtd_list);
1309*53ee8cc1Swenshuai.xi ms_ehci_qtd_free (pEhci, pQtd);
1310*53ee8cc1Swenshuai.xi }
1311*53ee8cc1Swenshuai.xi ms_debug_func("--[%s] line:[%d]\n", __FUNCTION__, __LINE__);
1312*53ee8cc1Swenshuai.xi }
1313*53ee8cc1Swenshuai.xi
1314*53ee8cc1Swenshuai.xi /*
1315*53ee8cc1Swenshuai.xi * @brief prepare and allocate qtd_list
1316*53ee8cc1Swenshuai.xi * fill buffer to qtd from urb
1317*53ee8cc1Swenshuai.xi *
1318*53ee8cc1Swenshuai.xi * @param struct ehci_hcd *pEhci
1319*53ee8cc1Swenshuai.xi * @param struct urb *pUrb
1320*53ee8cc1Swenshuai.xi * @param struct list_head *pHead
1321*53ee8cc1Swenshuai.xi * @param int iFlags
1322*53ee8cc1Swenshuai.xi *
1323*53ee8cc1Swenshuai.xi * @return struct list_head *
1324*53ee8cc1Swenshuai.xi */
1325*53ee8cc1Swenshuai.xi
1326*53ee8cc1Swenshuai.xi static struct list_head *
ms_qh_urb_process(struct ehci_hcd * pEhci,struct urb * pUrb,struct list_head * pHead,int iFlags)1327*53ee8cc1Swenshuai.xi ms_qh_urb_process (
1328*53ee8cc1Swenshuai.xi struct ehci_hcd *pEhci,
1329*53ee8cc1Swenshuai.xi struct urb *pUrb,
1330*53ee8cc1Swenshuai.xi struct list_head *pHead,
1331*53ee8cc1Swenshuai.xi int iFlags
1332*53ee8cc1Swenshuai.xi )
1333*53ee8cc1Swenshuai.xi {
1334*53ee8cc1Swenshuai.xi struct ehci_qtd *pQtd, *pQtdPrev;
1335*53ee8cc1Swenshuai.xi dma_addr_t tBuf;
1336*53ee8cc1Swenshuai.xi int iLen, iMaxpkt;
1337*53ee8cc1Swenshuai.xi int iIsInput;
1338*53ee8cc1Swenshuai.xi U32 u32Token;
1339*53ee8cc1Swenshuai.xi
1340*53ee8cc1Swenshuai.xi ms_debug_func("++[%s] line:[%d]\n", __FUNCTION__, __LINE__);
1341*53ee8cc1Swenshuai.xi pQtd = ms_ehci_qtd_alloc (pEhci, iFlags);
1342*53ee8cc1Swenshuai.xi if (!pQtd)
1343*53ee8cc1Swenshuai.xi {
1344*53ee8cc1Swenshuai.xi ms_debug_func("--[%s] line:[%d]\n", __FUNCTION__, __LINE__);
1345*53ee8cc1Swenshuai.xi return 0;
1346*53ee8cc1Swenshuai.xi }
1347*53ee8cc1Swenshuai.xi ms_insert_list_before (&pQtd->qtd_list, pHead);
1348*53ee8cc1Swenshuai.xi pQtd->urb = pUrb;
1349*53ee8cc1Swenshuai.xi
1350*53ee8cc1Swenshuai.xi u32Token = QTD_STS_ACT;
1351*53ee8cc1Swenshuai.xi u32Token |= (MAX_CERR_CNT << 10);
1352*53ee8cc1Swenshuai.xi /* for split transactions, SplitXState initialized to zero */
1353*53ee8cc1Swenshuai.xi
1354*53ee8cc1Swenshuai.xi iLen = pUrb->u32TransferBufferLength;
1355*53ee8cc1Swenshuai.xi iIsInput = usb_pipein (pUrb->u32Pipe);
1356*53ee8cc1Swenshuai.xi if (usb_pipecontrol (pUrb->u32Pipe))
1357*53ee8cc1Swenshuai.xi {
1358*53ee8cc1Swenshuai.xi ms_qtd_pack (pQtd, pUrb->tSetupDma, sizeof (struct usb_ctrlrequest),
1359*53ee8cc1Swenshuai.xi u32Token | PID_SETUP, 8);
1360*53ee8cc1Swenshuai.xi
1361*53ee8cc1Swenshuai.xi /* ... and always at least one more pid */
1362*53ee8cc1Swenshuai.xi u32Token ^= QTD_TOGGLE;
1363*53ee8cc1Swenshuai.xi pQtdPrev = pQtd;
1364*53ee8cc1Swenshuai.xi pQtd = ms_ehci_qtd_alloc (pEhci, iFlags);
1365*53ee8cc1Swenshuai.xi if (!pQtd)
1366*53ee8cc1Swenshuai.xi goto cleanup;
1367*53ee8cc1Swenshuai.xi pQtd->urb = pUrb;
1368*53ee8cc1Swenshuai.xi pQtdPrev->hw_next_qtd = (U32)(pQtd->qtd_dma_addr);
1369*53ee8cc1Swenshuai.xi ms_insert_list_before (&pQtd->qtd_list, pHead);
1370*53ee8cc1Swenshuai.xi }
1371*53ee8cc1Swenshuai.xi
1372*53ee8cc1Swenshuai.xi /*
1373*53ee8cc1Swenshuai.xi * data stage : prepare buffer
1374*53ee8cc1Swenshuai.xi */
1375*53ee8cc1Swenshuai.xi
1376*53ee8cc1Swenshuai.xi if (iLen > 0)
1377*53ee8cc1Swenshuai.xi tBuf = pUrb->tTransferDma;
1378*53ee8cc1Swenshuai.xi else
1379*53ee8cc1Swenshuai.xi tBuf = 0;
1380*53ee8cc1Swenshuai.xi
1381*53ee8cc1Swenshuai.xi if (!tBuf || iIsInput)
1382*53ee8cc1Swenshuai.xi u32Token |= PID_IN;
1383*53ee8cc1Swenshuai.xi
1384*53ee8cc1Swenshuai.xi /* patch code from linux */
1385*53ee8cc1Swenshuai.xi iMaxpkt = max_packet(usb_maxpacket(pUrb->dev, pUrb->u32Pipe, !iIsInput));
1386*53ee8cc1Swenshuai.xi //if (usb_pipebulk(pUrb->u32Pipe))
1387*53ee8cc1Swenshuai.xi //{
1388*53ee8cc1Swenshuai.xi // switch (pUrb->dev->eSpeed)
1389*53ee8cc1Swenshuai.xi // {
1390*53ee8cc1Swenshuai.xi // case USB_FULL_SPEED:
1391*53ee8cc1Swenshuai.xi // iMaxpkt = max_packet(usb_maxpacket(pUrb->dev, pUrb->u32Pipe, !iIsInput));
1392*53ee8cc1Swenshuai.xi // break;
1393*53ee8cc1Swenshuai.xi // case USB_HIGH_SPEED:
1394*53ee8cc1Swenshuai.xi // default:
1395*53ee8cc1Swenshuai.xi // iMaxpkt = 512;
1396*53ee8cc1Swenshuai.xi // break;
1397*53ee8cc1Swenshuai.xi // }
1398*53ee8cc1Swenshuai.xi //}
1399*53ee8cc1Swenshuai.xi //else
1400*53ee8cc1Swenshuai.xi //{
1401*53ee8cc1Swenshuai.xi // iMaxpkt = max_packet(usb_maxpacket(pUrb->dev, pUrb->u32Pipe, !iIsInput));
1402*53ee8cc1Swenshuai.xi //}
1403*53ee8cc1Swenshuai.xi
1404*53ee8cc1Swenshuai.xi for (;;)
1405*53ee8cc1Swenshuai.xi {
1406*53ee8cc1Swenshuai.xi int this_qtd_len;
1407*53ee8cc1Swenshuai.xi
1408*53ee8cc1Swenshuai.xi this_qtd_len = ms_qtd_pack (pQtd, tBuf, iLen, u32Token, iMaxpkt);
1409*53ee8cc1Swenshuai.xi iLen -= this_qtd_len;
1410*53ee8cc1Swenshuai.xi tBuf += this_qtd_len;
1411*53ee8cc1Swenshuai.xi if (iIsInput)
1412*53ee8cc1Swenshuai.xi pQtd->hw_alt_next_qtd = pEhci->stAsync->hw_alt_next_qtd;
1413*53ee8cc1Swenshuai.xi
1414*53ee8cc1Swenshuai.xi /* for control transaction, maybe needs switch it */
1415*53ee8cc1Swenshuai.xi if ((iMaxpkt & (this_qtd_len + (iMaxpkt - 1))) == 0)
1416*53ee8cc1Swenshuai.xi u32Token ^= QTD_TOGGLE;
1417*53ee8cc1Swenshuai.xi
1418*53ee8cc1Swenshuai.xi if (iLen <= 0)
1419*53ee8cc1Swenshuai.xi break;
1420*53ee8cc1Swenshuai.xi
1421*53ee8cc1Swenshuai.xi pQtdPrev = pQtd;
1422*53ee8cc1Swenshuai.xi pQtd = ms_ehci_qtd_alloc (pEhci, iFlags);
1423*53ee8cc1Swenshuai.xi if (!pQtd)
1424*53ee8cc1Swenshuai.xi goto cleanup;
1425*53ee8cc1Swenshuai.xi pQtd->urb = pUrb;
1426*53ee8cc1Swenshuai.xi pQtdPrev->hw_next_qtd = (U32)(pQtd->qtd_dma_addr);
1427*53ee8cc1Swenshuai.xi ms_insert_list_before (&pQtd->qtd_list, pHead);
1428*53ee8cc1Swenshuai.xi }
1429*53ee8cc1Swenshuai.xi
1430*53ee8cc1Swenshuai.xi if ((pUrb->u32TransferFlags & MS_FLAG_URB_SHORT_NOT_OK) == 0
1431*53ee8cc1Swenshuai.xi || usb_pipecontrol (pUrb->u32Pipe))
1432*53ee8cc1Swenshuai.xi pQtd->hw_alt_next_qtd = EHCI_LIST_END;
1433*53ee8cc1Swenshuai.xi
1434*53ee8cc1Swenshuai.xi //if (tBuf != 0)
1435*53ee8cc1Swenshuai.xi if (pUrb->u32TransferBufferLength != 0)
1436*53ee8cc1Swenshuai.xi {
1437*53ee8cc1Swenshuai.xi int one_more = 0;
1438*53ee8cc1Swenshuai.xi
1439*53ee8cc1Swenshuai.xi if (usb_pipecontrol (pUrb->u32Pipe))
1440*53ee8cc1Swenshuai.xi {
1441*53ee8cc1Swenshuai.xi one_more = 1;
1442*53ee8cc1Swenshuai.xi u32Token ^= 0x0100; /* PID IN/OUT toggled */
1443*53ee8cc1Swenshuai.xi u32Token |= QTD_TOGGLE; /* set DATA1 */
1444*53ee8cc1Swenshuai.xi }
1445*53ee8cc1Swenshuai.xi //else if (usb_pipebulk (pUrb->u32Pipe)
1446*53ee8cc1Swenshuai.xi else if (usb_pipeout (pUrb->u32Pipe)
1447*53ee8cc1Swenshuai.xi && (pUrb->u32TransferFlags & MS_FLAG_URB_ZERO_PACKET)
1448*53ee8cc1Swenshuai.xi && !(pUrb->u32TransferBufferLength % iMaxpkt))
1449*53ee8cc1Swenshuai.xi {
1450*53ee8cc1Swenshuai.xi one_more = 1;
1451*53ee8cc1Swenshuai.xi }
1452*53ee8cc1Swenshuai.xi
1453*53ee8cc1Swenshuai.xi if (one_more)
1454*53ee8cc1Swenshuai.xi {
1455*53ee8cc1Swenshuai.xi pQtdPrev = pQtd;
1456*53ee8cc1Swenshuai.xi pQtd = ms_ehci_qtd_alloc (pEhci, iFlags);
1457*53ee8cc1Swenshuai.xi if (!pQtd)
1458*53ee8cc1Swenshuai.xi goto cleanup;
1459*53ee8cc1Swenshuai.xi pQtd->urb = pUrb;
1460*53ee8cc1Swenshuai.xi pQtdPrev->hw_next_qtd = (U32)(pQtd->qtd_dma_addr);
1461*53ee8cc1Swenshuai.xi ms_insert_list_before (&pQtd->qtd_list, pHead);
1462*53ee8cc1Swenshuai.xi
1463*53ee8cc1Swenshuai.xi /* make NULL packet */
1464*53ee8cc1Swenshuai.xi ms_qtd_pack (pQtd, 0, 0, u32Token, 0);
1465*53ee8cc1Swenshuai.xi }
1466*53ee8cc1Swenshuai.xi }
1467*53ee8cc1Swenshuai.xi
1468*53ee8cc1Swenshuai.xi /* set interrupt enable when qtd completed */
1469*53ee8cc1Swenshuai.xi if (!(pUrb->u32TransferFlags & MS_FLAG_URB_NO_INTERRUPT))
1470*53ee8cc1Swenshuai.xi pQtd->hw_token |= QTD_IOC;
1471*53ee8cc1Swenshuai.xi
1472*53ee8cc1Swenshuai.xi ms_debug_func("--[%s] line:[%d]\n", __FUNCTION__, __LINE__);
1473*53ee8cc1Swenshuai.xi return pHead;
1474*53ee8cc1Swenshuai.xi
1475*53ee8cc1Swenshuai.xi cleanup:
1476*53ee8cc1Swenshuai.xi
1477*53ee8cc1Swenshuai.xi ms_qtd_register_free (pEhci, pHead);
1478*53ee8cc1Swenshuai.xi ms_debug_func("--[%s] line:[%d]\n", __FUNCTION__, __LINE__);
1479*53ee8cc1Swenshuai.xi return 0;
1480*53ee8cc1Swenshuai.xi }
1481*53ee8cc1Swenshuai.xi
1482*53ee8cc1Swenshuai.xi /*-------------------------------------------------------------------------*/
1483*53ee8cc1Swenshuai.xi /* Obsolete code */
1484*53ee8cc1Swenshuai.xi //static __inline__ void
1485*53ee8cc1Swenshuai.xi //ms_clear_toggle (struct usb_device *pUdev, int iEp, int is_out, struct ehci_qh *pQh)
1486*53ee8cc1Swenshuai.xi //{
1487*53ee8cc1Swenshuai.xi // ms_debug_func("++[%s] line:[%d]\n", __FUNCTION__, __LINE__);
1488*53ee8cc1Swenshuai.xi // ms_debug_msg ("clear toggle dev%d iEp 0x%x-%s\n",
1489*53ee8cc1Swenshuai.xi // (int)pUdev->u32DevNum, iEp, is_out ? "out" : "in");
1490*53ee8cc1Swenshuai.xi // pQh->hw_token &= ~(QTD_TOGGLE);
1491*53ee8cc1Swenshuai.xi //
1492*53ee8cc1Swenshuai.xi // usb_settoggle (pUdev, iEp, is_out, 1);
1493*53ee8cc1Swenshuai.xi // ms_debug_func("--[%s] line:[%d]\n", __FUNCTION__, __LINE__);
1494*53ee8cc1Swenshuai.xi //}
1495*53ee8cc1Swenshuai.xi /*
1496*53ee8cc1Swenshuai.xi * @brief allocate and make qh
1497*53ee8cc1Swenshuai.xi *
1498*53ee8cc1Swenshuai.xi * @param struct ehci_hcd *pEhci
1499*53ee8cc1Swenshuai.xi * @param struct urb *pUrb
1500*53ee8cc1Swenshuai.xi * @param int iFlags
1501*53ee8cc1Swenshuai.xi *
1502*53ee8cc1Swenshuai.xi * @return struct ehci_qh *
1503*53ee8cc1Swenshuai.xi */
1504*53ee8cc1Swenshuai.xi
1505*53ee8cc1Swenshuai.xi static struct ehci_qh *
ms_qh_make(struct ehci_hcd * pEhci,struct urb * pUrb,int iFlags)1506*53ee8cc1Swenshuai.xi ms_qh_make (
1507*53ee8cc1Swenshuai.xi struct ehci_hcd *pEhci,
1508*53ee8cc1Swenshuai.xi struct urb *pUrb,
1509*53ee8cc1Swenshuai.xi int iFlags
1510*53ee8cc1Swenshuai.xi )
1511*53ee8cc1Swenshuai.xi {
1512*53ee8cc1Swenshuai.xi struct ehci_qh *pQh = ms_ehci_qh_alloc (pEhci, iFlags);
1513*53ee8cc1Swenshuai.xi U32 u32Info1 = 0, u32Info2 = 0;
1514*53ee8cc1Swenshuai.xi int iIsInput, iType;
1515*53ee8cc1Swenshuai.xi int iMaxpkt = 0;
1516*53ee8cc1Swenshuai.xi
1517*53ee8cc1Swenshuai.xi ms_debug_func("++[%s] line:[%d]\n", __FUNCTION__, __LINE__);
1518*53ee8cc1Swenshuai.xi if (!pQh)
1519*53ee8cc1Swenshuai.xi {
1520*53ee8cc1Swenshuai.xi ms_debug_func("--[%s] line:[%d]\n", __FUNCTION__, __LINE__);
1521*53ee8cc1Swenshuai.xi return pQh;
1522*53ee8cc1Swenshuai.xi }
1523*53ee8cc1Swenshuai.xi
1524*53ee8cc1Swenshuai.xi u32Info1 |= usb_pipeendpoint (pUrb->u32Pipe) << 8;
1525*53ee8cc1Swenshuai.xi u32Info1 |= usb_pipedevice (pUrb->u32Pipe) << 0;
1526*53ee8cc1Swenshuai.xi
1527*53ee8cc1Swenshuai.xi iIsInput = usb_pipein (pUrb->u32Pipe);
1528*53ee8cc1Swenshuai.xi iType = usb_pipetype (pUrb->u32Pipe);
1529*53ee8cc1Swenshuai.xi iMaxpkt = usb_maxpacket (pUrb->dev, pUrb->u32Pipe, !iIsInput);
1530*53ee8cc1Swenshuai.xi
1531*53ee8cc1Swenshuai.xi /* check if maximum packet size > 1024 bytes */
1532*53ee8cc1Swenshuai.xi if (max_packet(iMaxpkt) > 1024) {
1533*53ee8cc1Swenshuai.xi ms_debug_err("error maxp %d\n", max_packet(iMaxpkt));
1534*53ee8cc1Swenshuai.xi goto done;
1535*53ee8cc1Swenshuai.xi }
1536*53ee8cc1Swenshuai.xi
1537*53ee8cc1Swenshuai.xi if (iType == EP_INTERRUPT)
1538*53ee8cc1Swenshuai.xi {
1539*53ee8cc1Swenshuai.xi pQh->u8Usecs = NS_2_US(ms_usb_calc_bus_time (USB_HIGH_SPEED, iIsInput,
1540*53ee8cc1Swenshuai.xi hb_mult (iMaxpkt) * max_packet (iMaxpkt)));
1541*53ee8cc1Swenshuai.xi
1542*53ee8cc1Swenshuai.xi pQh->u16Start = NO_FRAME;
1543*53ee8cc1Swenshuai.xi
1544*53ee8cc1Swenshuai.xi if (pUrb->dev->eSpeed == USB_HIGH_SPEED)
1545*53ee8cc1Swenshuai.xi {
1546*53ee8cc1Swenshuai.xi pQh->c_usecs = 0;
1547*53ee8cc1Swenshuai.xi pQh->u8Gap_uf = 0;
1548*53ee8cc1Swenshuai.xi
1549*53ee8cc1Swenshuai.xi /* Warning, highspeed periods < 1 frame. */
1550*53ee8cc1Swenshuai.xi pQh->u16Period = pUrb->u32Interval >> 3;
1551*53ee8cc1Swenshuai.xi /* patch from linux, 2.6.28 and 3.10.86 different */
1552*53ee8cc1Swenshuai.xi //if (pQh->u16Period < 1)
1553*53ee8cc1Swenshuai.xi if (pQh->u16Period == 1 && pUrb->u32Interval != 1)
1554*53ee8cc1Swenshuai.xi {
1555*53ee8cc1Swenshuai.xi ms_debug_warn ("intr period %d uframes, NYET!", (int)pUrb->u32Interval);
1556*53ee8cc1Swenshuai.xi goto done;
1557*53ee8cc1Swenshuai.xi }
1558*53ee8cc1Swenshuai.xi }
1559*53ee8cc1Swenshuai.xi else
1560*53ee8cc1Swenshuai.xi {
1561*53ee8cc1Swenshuai.xi
1562*53ee8cc1Swenshuai.xi /* FS/LS transfer times */
1563*53ee8cc1Swenshuai.xi pQh->u8Gap_uf = 1 + ms_usb_calc_bus_time (pUrb->dev->eSpeed,
1564*53ee8cc1Swenshuai.xi iIsInput, iMaxpkt) / (125 * 1000);
1565*53ee8cc1Swenshuai.xi
1566*53ee8cc1Swenshuai.xi /* Warning, let SPLIT/CSPLIT times to close */
1567*53ee8cc1Swenshuai.xi if (iIsInput)
1568*53ee8cc1Swenshuai.xi { // SPLIT, gap, CSPLIT+DATA
1569*53ee8cc1Swenshuai.xi pQh->c_usecs = pQh->u8Usecs + HIGHSPEED_US (0);
1570*53ee8cc1Swenshuai.xi pQh->u8Usecs = (U8)HIGHSPEED_US (1);
1571*53ee8cc1Swenshuai.xi }
1572*53ee8cc1Swenshuai.xi else
1573*53ee8cc1Swenshuai.xi { // SPLIT+DATA, gap, CSPLIT
1574*53ee8cc1Swenshuai.xi pQh->u8Usecs += HIGHSPEED_US (1);
1575*53ee8cc1Swenshuai.xi pQh->c_usecs = (U8)HIGHSPEED_US (0);
1576*53ee8cc1Swenshuai.xi }
1577*53ee8cc1Swenshuai.xi pQh->u16Period = pUrb->u32Interval;
1578*53ee8cc1Swenshuai.xi
1579*53ee8cc1Swenshuai.xi }
1580*53ee8cc1Swenshuai.xi }
1581*53ee8cc1Swenshuai.xi
1582*53ee8cc1Swenshuai.xi /* patch from linux */
1583*53ee8cc1Swenshuai.xi pQh->dev = pUrb->dev;
1584*53ee8cc1Swenshuai.xi
1585*53ee8cc1Swenshuai.xi /* merge code into the following switch case description */
1586*53ee8cc1Swenshuai.xi #if 0
1587*53ee8cc1Swenshuai.xi if (pUrb->dev->eSpeed == USB_HIGH_SPEED)
1588*53ee8cc1Swenshuai.xi {
1589*53ee8cc1Swenshuai.xi u32Info1 |= (2 << 12);
1590*53ee8cc1Swenshuai.xi }
1591*53ee8cc1Swenshuai.xi else if (pUrb->dev->eSpeed == USB_LOW_SPEED)
1592*53ee8cc1Swenshuai.xi {
1593*53ee8cc1Swenshuai.xi u32Info1 |= (1 << 12);
1594*53ee8cc1Swenshuai.xi }
1595*53ee8cc1Swenshuai.xi else
1596*53ee8cc1Swenshuai.xi {
1597*53ee8cc1Swenshuai.xi if (pUrb->dev->eSpeed != USB_FULL_SPEED)
1598*53ee8cc1Swenshuai.xi ms_debug_warn ("unknow speed %d", pUrb->dev->eSpeed);
1599*53ee8cc1Swenshuai.xi }
1600*53ee8cc1Swenshuai.xi #endif
1601*53ee8cc1Swenshuai.xi
1602*53ee8cc1Swenshuai.xi /* Is TT? */
1603*53ee8cc1Swenshuai.xi switch (pUrb->dev->eSpeed)
1604*53ee8cc1Swenshuai.xi {
1605*53ee8cc1Swenshuai.xi
1606*53ee8cc1Swenshuai.xi case USB_LOW_SPEED:
1607*53ee8cc1Swenshuai.xi //if (iType == EP_CONTROL)
1608*53ee8cc1Swenshuai.xi //{
1609*53ee8cc1Swenshuai.xi // u32Info1 |= 8 << 16; /* hard code maxpacket item */
1610*53ee8cc1Swenshuai.xi //}
1611*53ee8cc1Swenshuai.xi u32Info1 |= (1 << 12); /* EPS is 1.5 Mb/s */
1612*53ee8cc1Swenshuai.xi
1613*53ee8cc1Swenshuai.xi case USB_FULL_SPEED:
1614*53ee8cc1Swenshuai.xi /* patch from linux, maxp applied */
1615*53ee8cc1Swenshuai.xi //if (iType == EP_CONTROL && (pUrb->dev->eSpeed == USB_FULL_SPEED) )
1616*53ee8cc1Swenshuai.xi //{
1617*53ee8cc1Swenshuai.xi // //info1 |= 64 << 16; // fixed maxpacket
1618*53ee8cc1Swenshuai.xi // u32Info1 |= max_packet (iMaxpkt) << 16; // PIPE_INTERRUPT,PIPE_BULK,PIPE_ISOCHRONOUS
1619*53ee8cc1Swenshuai.xi //}
1620*53ee8cc1Swenshuai.xi //if (iType != EP_CONTROL)
1621*53ee8cc1Swenshuai.xi //{
1622*53ee8cc1Swenshuai.xi // u32Info1 |= max_packet (iMaxpkt) << 16; // PIPE_INTERRUPT,PIPE_BULK,PIPE_ISOCHRONOUS
1623*53ee8cc1Swenshuai.xi //}
1624*53ee8cc1Swenshuai.xi u32Info1 |= iMaxpkt << 16;
1625*53ee8cc1Swenshuai.xi /* EPS 0 means "full" */
1626*53ee8cc1Swenshuai.xi // info1 |= (3 << 12); /* EPS "reserve" */
1627*53ee8cc1Swenshuai.xi if (iType != EP_INTERRUPT)
1628*53ee8cc1Swenshuai.xi u32Info1 |= (EHCI_RL_NAKCNT_TT << 28);
1629*53ee8cc1Swenshuai.xi if (iType == EP_CONTROL)
1630*53ee8cc1Swenshuai.xi {
1631*53ee8cc1Swenshuai.xi u32Info1 |= QH_C_BIT; /* for TT */
1632*53ee8cc1Swenshuai.xi u32Info1 |= QH_DTC_BIT; /* toggle from qtd */
1633*53ee8cc1Swenshuai.xi }
1634*53ee8cc1Swenshuai.xi u32Info2 |= (EHCI_HI_BW_MULT_TT << 30);
1635*53ee8cc1Swenshuai.xi
1636*53ee8cc1Swenshuai.xi /* linux code always sets ttport, but not to set hubaddr iff roothub */
1637*53ee8cc1Swenshuai.xi u32Info2 |= pUrb->dev->u32TTPort << 23; /* Port Number */
1638*53ee8cc1Swenshuai.xi if (pUrb->dev->tt && pUrb->dev->tt->hub->u32DevNum != 1) // Skip the Root Hub devnum == 1
1639*53ee8cc1Swenshuai.xi {
1640*53ee8cc1Swenshuai.xi u32Info2 |= pUrb->dev->tt->hub->u32DevNum << 16; /* Hub Addr */
1641*53ee8cc1Swenshuai.xi ms_debug_debug("[USB] set TT and not root hub, (ttport, hubaddr) = (%d,%d)\n", pUrb->dev->u32TTPort, pUrb->dev->tt->hub->u32DevNum);
1642*53ee8cc1Swenshuai.xi }
1643*53ee8cc1Swenshuai.xi //if (pUrb->dev->tt->hub->u32DevNum != 1) // Skip the Root Hub devnum == 1
1644*53ee8cc1Swenshuai.xi //{
1645*53ee8cc1Swenshuai.xi // u32Info2 |= pUrb->dev->u32TTPort << 23; /* Port Number */
1646*53ee8cc1Swenshuai.xi // u32Info2 |= pUrb->dev->tt->hub->u32DevNum << 16; /* Hub Addr */
1647*53ee8cc1Swenshuai.xi //}
1648*53ee8cc1Swenshuai.xi /* NOTE: if (EP_INTERRUPT) { scheduler sets c-mask } */
1649*53ee8cc1Swenshuai.xi break;
1650*53ee8cc1Swenshuai.xi case USB_HIGH_SPEED: /* �P TT �L�� */
1651*53ee8cc1Swenshuai.xi u32Info1 |= (2 << 12); /* EPS is 480Mb/s */
1652*53ee8cc1Swenshuai.xi
1653*53ee8cc1Swenshuai.xi if (iType == EP_CONTROL)
1654*53ee8cc1Swenshuai.xi {
1655*53ee8cc1Swenshuai.xi u32Info1 |= (EHCI_RL_NAKCNT << 28);
1656*53ee8cc1Swenshuai.xi u32Info1 |= 64 << 16; /* Endpoint (wMaxPacketSize) */
1657*53ee8cc1Swenshuai.xi u32Info1 |= QH_DTC_BIT; /* Data toggle control */
1658*53ee8cc1Swenshuai.xi u32Info2 |= (EHCI_HI_BW_MULT_HS << 30);
1659*53ee8cc1Swenshuai.xi }
1660*53ee8cc1Swenshuai.xi else if (iType == EP_BULK)
1661*53ee8cc1Swenshuai.xi {
1662*53ee8cc1Swenshuai.xi u32Info1 |= (EHCI_RL_NAKCNT << 28);
1663*53ee8cc1Swenshuai.xi u32Info1 |= max_packet (iMaxpkt) << 16; // Philips mp3 player endpoint descriptor bug
1664*53ee8cc1Swenshuai.xi u32Info2 |= (EHCI_HI_BW_MULT_HS << 30);
1665*53ee8cc1Swenshuai.xi }
1666*53ee8cc1Swenshuai.xi else
1667*53ee8cc1Swenshuai.xi { /* Other transation type */
1668*53ee8cc1Swenshuai.xi u32Info1 |= max_packet (iMaxpkt) << 16;
1669*53ee8cc1Swenshuai.xi u32Info2 |= hb_mult (iMaxpkt) << 30;
1670*53ee8cc1Swenshuai.xi }
1671*53ee8cc1Swenshuai.xi break;
1672*53ee8cc1Swenshuai.xi default:
1673*53ee8cc1Swenshuai.xi ms_debug_msg ("usb dev %p speed %d", pUrb->dev, pUrb->dev->eSpeed);
1674*53ee8cc1Swenshuai.xi done:
1675*53ee8cc1Swenshuai.xi ms_qh_put (pEhci, pQh);
1676*53ee8cc1Swenshuai.xi ms_debug_func("--[%s] line:[%d]\n", __FUNCTION__, __LINE__);
1677*53ee8cc1Swenshuai.xi return 0;
1678*53ee8cc1Swenshuai.xi }
1679*53ee8cc1Swenshuai.xi
1680*53ee8cc1Swenshuai.xi pQh->qh_status = QH_STS_IDLE;
1681*53ee8cc1Swenshuai.xi pQh->hw_ep_state1 = u32Info1;
1682*53ee8cc1Swenshuai.xi pQh->hw_ep_state2 = u32Info2;
1683*53ee8cc1Swenshuai.xi usb_settoggle (pUrb->dev, usb_pipeendpoint (pUrb->u32Pipe), !iIsInput, 1);
1684*53ee8cc1Swenshuai.xi #ifdef ENABLE_QH_REFRESH
1685*53ee8cc1Swenshuai.xi /* patch from linux 2.6.x ~ 3.8.x */
1686*53ee8cc1Swenshuai.xi ms_qh_refresh(pEhci, pQh);
1687*53ee8cc1Swenshuai.xi #else
1688*53ee8cc1Swenshuai.xi ms_qh_update_link (pQh, pQh->pDummyQtd); // replaced by ms_qh_refresh()
1689*53ee8cc1Swenshuai.xi #endif
1690*53ee8cc1Swenshuai.xi ms_debug_func("--[%s] line:[%d]\n", __FUNCTION__, __LINE__);
1691*53ee8cc1Swenshuai.xi return pQh;
1692*53ee8cc1Swenshuai.xi }
1693*53ee8cc1Swenshuai.xi
1694*53ee8cc1Swenshuai.xi /*-------------------------------------------------------------------------*/
1695*53ee8cc1Swenshuai.xi /*
1696*53ee8cc1Swenshuai.xi * @brief start async schedule
1697*53ee8cc1Swenshuai.xi *
1698*53ee8cc1Swenshuai.xi * @param struct ehci_hcd *pEhci
1699*53ee8cc1Swenshuai.xi * @param struct ehci_qh *pQh
1700*53ee8cc1Swenshuai.xi *
1701*53ee8cc1Swenshuai.xi * @return none
1702*53ee8cc1Swenshuai.xi */
1703*53ee8cc1Swenshuai.xi
ms_qh_link_async(struct ehci_hcd * pEhci,struct ehci_qh * pQh)1704*53ee8cc1Swenshuai.xi static void ms_qh_link_async (struct ehci_hcd *pEhci, struct ehci_qh *pQh)
1705*53ee8cc1Swenshuai.xi {
1706*53ee8cc1Swenshuai.xi U32 u32DmaAddr = QH_NEXT (pQh->qh_dma_addr);
1707*53ee8cc1Swenshuai.xi struct ehci_qh *pHead;
1708*53ee8cc1Swenshuai.xi
1709*53ee8cc1Swenshuai.xi ms_debug_func("++[%s] line:[%d]\n", __FUNCTION__, __LINE__);
1710*53ee8cc1Swenshuai.xi pHead = pEhci->stAsync;
1711*53ee8cc1Swenshuai.xi ms_timer_action_done (pEhci, TIMER_ASYNC_OFF);
1712*53ee8cc1Swenshuai.xi
1713*53ee8cc1Swenshuai.xi if (!pHead->qh_next.qh)
1714*53ee8cc1Swenshuai.xi {
1715*53ee8cc1Swenshuai.xi U32 cmd = hcd_reg_readl ((U32)&pEhci->op_regs->usbcmd);
1716*53ee8cc1Swenshuai.xi //If disable => restart it
1717*53ee8cc1Swenshuai.xi if (!(cmd & USBCMD_ASE))
1718*53ee8cc1Swenshuai.xi {
1719*53ee8cc1Swenshuai.xi (void) ms_check_status (&pEhci->op_regs->usbsts, USBSTS_ASS, 0, 150);
1720*53ee8cc1Swenshuai.xi cmd |= USBCMD_ASE | USBCMD_RUN; //asynchronous scheduler enable
1721*53ee8cc1Swenshuai.xi hcd_reg_writel (cmd, (U32)&pEhci->op_regs->usbcmd);
1722*53ee8cc1Swenshuai.xi pEhci->hcd.state = HCD_STATE_RUNNING;
1723*53ee8cc1Swenshuai.xi }
1724*53ee8cc1Swenshuai.xi }
1725*53ee8cc1Swenshuai.xi
1726*53ee8cc1Swenshuai.xi /* patch from linux code */
1727*53ee8cc1Swenshuai.xi #ifdef ENABLE_QH_REFRESH
1728*53ee8cc1Swenshuai.xi /* clear toggle */
1729*53ee8cc1Swenshuai.xi if (pQh->qh_status == QH_STS_IDLE)
1730*53ee8cc1Swenshuai.xi ms_qh_refresh(pEhci, pQh);
1731*53ee8cc1Swenshuai.xi #else
1732*53ee8cc1Swenshuai.xi /* Don't write QH memory if not necessary */
1733*53ee8cc1Swenshuai.xi if(pQh->hw_token & HALT_BIT)
1734*53ee8cc1Swenshuai.xi pQh->hw_token &= ~HALT_BIT;
1735*53ee8cc1Swenshuai.xi #endif
1736*53ee8cc1Swenshuai.xi
1737*53ee8cc1Swenshuai.xi pQh->qh_next = pHead->qh_next;
1738*53ee8cc1Swenshuai.xi pQh->hw_next_qh = pHead->hw_next_qh;
1739*53ee8cc1Swenshuai.xi wmb ();
1740*53ee8cc1Swenshuai.xi
1741*53ee8cc1Swenshuai.xi pHead->qh_next.qh = pQh;
1742*53ee8cc1Swenshuai.xi pHead->hw_next_qh = u32DmaAddr;
1743*53ee8cc1Swenshuai.xi
1744*53ee8cc1Swenshuai.xi /* note: qh descriptor needs to flush into the memory */
1745*53ee8cc1Swenshuai.xi
1746*53ee8cc1Swenshuai.xi pQh->xacterrs = QH_MAX_XACTRTT_RETRY; // maximum xacterr retry count
1747*53ee8cc1Swenshuai.xi pQh->qh_status = QH_STS_LINKED;
1748*53ee8cc1Swenshuai.xi /* IRQ will report qtd completions event */
1749*53ee8cc1Swenshuai.xi ms_debug_func("--[%s] line:[%d]\n", __FUNCTION__, __LINE__);
1750*53ee8cc1Swenshuai.xi }
1751*53ee8cc1Swenshuai.xi
1752*53ee8cc1Swenshuai.xi /*-------------------------------------------------------------------------*/
1753*53ee8cc1Swenshuai.xi
1754*53ee8cc1Swenshuai.xi #define QH_ADDR_MASK 0x7f
1755*53ee8cc1Swenshuai.xi
ms_qh_append_tds(struct ehci_hcd * pEhci,struct urb * pUrb,struct list_head * qtd_list,int iEpNum,void ** ptr)1756*53ee8cc1Swenshuai.xi static struct ehci_qh *ms_qh_append_tds (
1757*53ee8cc1Swenshuai.xi struct ehci_hcd *pEhci,
1758*53ee8cc1Swenshuai.xi struct urb *pUrb,
1759*53ee8cc1Swenshuai.xi struct list_head *qtd_list,
1760*53ee8cc1Swenshuai.xi int iEpNum,
1761*53ee8cc1Swenshuai.xi void **ptr
1762*53ee8cc1Swenshuai.xi )
1763*53ee8cc1Swenshuai.xi {
1764*53ee8cc1Swenshuai.xi struct ehci_qh *pQh = 0;
1765*53ee8cc1Swenshuai.xi //int maxp;
1766*53ee8cc1Swenshuai.xi
1767*53ee8cc1Swenshuai.xi ms_debug_func("++[%s] line:[%d]\n", __FUNCTION__, __LINE__);
1768*53ee8cc1Swenshuai.xi pQh = (struct ehci_qh *) *ptr;
1769*53ee8cc1Swenshuai.xi if (pQh == 0)
1770*53ee8cc1Swenshuai.xi {
1771*53ee8cc1Swenshuai.xi pQh = ms_qh_make (pEhci, pUrb, GFP_ATOMIC);
1772*53ee8cc1Swenshuai.xi *ptr = pQh;
1773*53ee8cc1Swenshuai.xi }
1774*53ee8cc1Swenshuai.xi
1775*53ee8cc1Swenshuai.xi if (pQh != 0)
1776*53ee8cc1Swenshuai.xi {
1777*53ee8cc1Swenshuai.xi struct ehci_qtd *pQtd;
1778*53ee8cc1Swenshuai.xi
1779*53ee8cc1Swenshuai.xi if (ms_is_empty_list (qtd_list))
1780*53ee8cc1Swenshuai.xi pQtd = 0;
1781*53ee8cc1Swenshuai.xi else
1782*53ee8cc1Swenshuai.xi {
1783*53ee8cc1Swenshuai.xi pQtd = entry_to_container (qtd_list->next, struct ehci_qtd, qtd_list);
1784*53ee8cc1Swenshuai.xi //list_entry (qtd_list->next, struct ehci_qtd, qtd_list, struct list_head, qtd);
1785*53ee8cc1Swenshuai.xi }
1786*53ee8cc1Swenshuai.xi
1787*53ee8cc1Swenshuai.xi /* control qh may need patching after enumeration */
1788*53ee8cc1Swenshuai.xi if (iEpNum == 0)
1789*53ee8cc1Swenshuai.xi {
1790*53ee8cc1Swenshuai.xi /* ep0 maxpacket will be updated here after HCD issue get_descriptor. */
1791*53ee8cc1Swenshuai.xi /* the purpose like usb_ep0_reinit */
1792*53ee8cc1Swenshuai.xi if (!(pQh->hw_ep_state1 & (0x3 << 12)))
1793*53ee8cc1Swenshuai.xi {
1794*53ee8cc1Swenshuai.xi int maxp, hw_maxp;
1795*53ee8cc1Swenshuai.xi
1796*53ee8cc1Swenshuai.xi maxp = usb_maxpacket (pUrb->dev, pUrb->u32Pipe, !(usb_pipein (pUrb->u32Pipe)));
1797*53ee8cc1Swenshuai.xi hw_maxp = max_packet(pQh->hw_ep_state1 >> 16);
1798*53ee8cc1Swenshuai.xi if (maxp != hw_maxp)
1799*53ee8cc1Swenshuai.xi ms_debug_debug("[USB] hw_map(%x) <-> maxp(%x)\n", hw_maxp, maxp);
1800*53ee8cc1Swenshuai.xi
1801*53ee8cc1Swenshuai.xi if (maxp > hw_maxp)
1802*53ee8cc1Swenshuai.xi {
1803*53ee8cc1Swenshuai.xi U32 u32Info = pQh->hw_ep_state1;
1804*53ee8cc1Swenshuai.xi
1805*53ee8cc1Swenshuai.xi u32Info &= ~(0x07ff << 16);
1806*53ee8cc1Swenshuai.xi u32Info |= maxp << 16;
1807*53ee8cc1Swenshuai.xi pQh->hw_ep_state1 = u32Info;
1808*53ee8cc1Swenshuai.xi }
1809*53ee8cc1Swenshuai.xi }
1810*53ee8cc1Swenshuai.xi
1811*53ee8cc1Swenshuai.xi /* usb_reset_device() back the device address to 0 */
1812*53ee8cc1Swenshuai.xi if (usb_pipedevice (pUrb->u32Pipe) == 0)
1813*53ee8cc1Swenshuai.xi pQh->hw_ep_state1 &= ~QH_ADDR_MASK;
1814*53ee8cc1Swenshuai.xi /* modify device address, the purpose like usb_ep0_reinit */
1815*53ee8cc1Swenshuai.xi else if ((pQh->hw_ep_state1 & QH_ADDR_MASK) == 0) {
1816*53ee8cc1Swenshuai.xi ms_debug_debug("[USB] qh device addr 0, append urb device addr %d\n", usb_pipedevice (pUrb->u32Pipe));
1817*53ee8cc1Swenshuai.xi pQh->hw_ep_state1 |= usb_pipedevice (pUrb->u32Pipe);
1818*53ee8cc1Swenshuai.xi }
1819*53ee8cc1Swenshuai.xi }
1820*53ee8cc1Swenshuai.xi
1821*53ee8cc1Swenshuai.xi /* Obsolete code */
1822*53ee8cc1Swenshuai.xi //if ((!usb_gettoggle (pUrb->dev,
1823*53ee8cc1Swenshuai.xi // (iEpNum & 0x0f), !(iEpNum & 0x10)))
1824*53ee8cc1Swenshuai.xi // && !usb_pipecontrol (pUrb->u32Pipe))
1825*53ee8cc1Swenshuai.xi //{
1826*53ee8cc1Swenshuai.xi // /* "never happens": drivers do stall cleanup right */
1827*53ee8cc1Swenshuai.xi // if (pQh->qh_status != QH_STS_IDLE
1828*53ee8cc1Swenshuai.xi // && !ms_is_empty_list (&pQh->qtd_list)
1829*53ee8cc1Swenshuai.xi // && pQh->qh_status != QH_STS_COMPLETING)
1830*53ee8cc1Swenshuai.xi // ms_debug_msg ("clear toggle dev%d ep%d%s: not idle\n", (int)usb_pipedevice (pUrb->u32Pipe), iEpNum & 0x0f, usb_pipein (pUrb->u32Pipe) ? "in" : "out");
1831*53ee8cc1Swenshuai.xi // ms_clear_toggle (pUrb->dev, iEpNum & 0x0f, !(iEpNum & 0x10), pQh);
1832*53ee8cc1Swenshuai.xi // diag_printf("[USB] clear toggle called!!!\n");
1833*53ee8cc1Swenshuai.xi //}
1834*53ee8cc1Swenshuai.xi
1835*53ee8cc1Swenshuai.xi if (pQtd != 0)
1836*53ee8cc1Swenshuai.xi {
1837*53ee8cc1Swenshuai.xi struct ehci_qtd *dummy;
1838*53ee8cc1Swenshuai.xi dma_addr_t tDmaAddr;
1839*53ee8cc1Swenshuai.xi U32 pToken;
1840*53ee8cc1Swenshuai.xi
1841*53ee8cc1Swenshuai.xi pToken = pQtd->hw_token;
1842*53ee8cc1Swenshuai.xi pQtd->hw_token = HALT_BIT;
1843*53ee8cc1Swenshuai.xi wmb ();
1844*53ee8cc1Swenshuai.xi dummy = pQh->pDummyQtd;
1845*53ee8cc1Swenshuai.xi /* Copy qtd's data to dummy except dummy->qtd_dma */
1846*53ee8cc1Swenshuai.xi tDmaAddr = dummy->qtd_dma_addr;
1847*53ee8cc1Swenshuai.xi *dummy = *pQtd;
1848*53ee8cc1Swenshuai.xi dummy->qtd_dma_addr = tDmaAddr;
1849*53ee8cc1Swenshuai.xi
1850*53ee8cc1Swenshuai.xi ms_list_remove (&pQtd->qtd_list);
1851*53ee8cc1Swenshuai.xi ms_insert_list_after (&dummy->qtd_list, qtd_list);
1852*53ee8cc1Swenshuai.xi ms_list_join (qtd_list, pQh->qtd_list.prev);
1853*53ee8cc1Swenshuai.xi
1854*53ee8cc1Swenshuai.xi ms_ehci_qtd_init (pQtd, pQtd->qtd_dma_addr);
1855*53ee8cc1Swenshuai.xi pQh->pDummyQtd = pQtd;
1856*53ee8cc1Swenshuai.xi
1857*53ee8cc1Swenshuai.xi /* hc must see the new dummy at list end */
1858*53ee8cc1Swenshuai.xi tDmaAddr = pQtd->qtd_dma_addr;
1859*53ee8cc1Swenshuai.xi pQtd = entry_to_container (pQh->qtd_list.prev, struct ehci_qtd, qtd_list);
1860*53ee8cc1Swenshuai.xi //list_entry (qh->qtd_list.prev, struct ehci_qtd, qtd_list,struct list_head, qtd);
1861*53ee8cc1Swenshuai.xi //the last qtd of qh before spliceing qtd_list
1862*53ee8cc1Swenshuai.xi pQtd->hw_next_qtd = (U32)(tDmaAddr);
1863*53ee8cc1Swenshuai.xi
1864*53ee8cc1Swenshuai.xi /* let the hc process these next qtds */
1865*53ee8cc1Swenshuai.xi wmb ();
1866*53ee8cc1Swenshuai.xi dummy->hw_token = pToken;
1867*53ee8cc1Swenshuai.xi
1868*53ee8cc1Swenshuai.xi pUrb->hcpriv = ms_qh_get (pQh);
1869*53ee8cc1Swenshuai.xi }
1870*53ee8cc1Swenshuai.xi }
1871*53ee8cc1Swenshuai.xi ms_debug_func("--[%s] line:[%d]\n", __FUNCTION__, __LINE__);
1872*53ee8cc1Swenshuai.xi return pQh;
1873*53ee8cc1Swenshuai.xi }
1874*53ee8cc1Swenshuai.xi
1875*53ee8cc1Swenshuai.xi /*-------------------------------------------------------------------------*/
1876*53ee8cc1Swenshuai.xi static int
ms_submit_async(struct ehci_hcd * pEhci,struct urb * pUrb,struct list_head * qtd_list)1877*53ee8cc1Swenshuai.xi ms_submit_async (
1878*53ee8cc1Swenshuai.xi struct ehci_hcd *pEhci,
1879*53ee8cc1Swenshuai.xi struct urb *pUrb,
1880*53ee8cc1Swenshuai.xi struct list_head *qtd_list
1881*53ee8cc1Swenshuai.xi )
1882*53ee8cc1Swenshuai.xi {
1883*53ee8cc1Swenshuai.xi //struct ehci_qtd *pQtd;
1884*53ee8cc1Swenshuai.xi struct s_hcd_dev *pDev;
1885*53ee8cc1Swenshuai.xi int iEpNum;
1886*53ee8cc1Swenshuai.xi U32 u32Flags;
1887*53ee8cc1Swenshuai.xi struct ehci_qh *pQh = 0;
1888*53ee8cc1Swenshuai.xi
1889*53ee8cc1Swenshuai.xi ms_debug_func("++[%s] line:[%d]\n", __FUNCTION__, __LINE__);
1890*53ee8cc1Swenshuai.xi /* only urb trace code needs qtd information */
1891*53ee8cc1Swenshuai.xi //pQtd = entry_to_container (qtd_list->next, struct ehci_qtd, qtd_list);
1892*53ee8cc1Swenshuai.xi //list_entry (qtd_list->next, struct ehci_qtd, qtd_list, struct list_head, qtd);
1893*53ee8cc1Swenshuai.xi pDev = (struct s_hcd_dev *)pUrb->dev->hcpriv;
1894*53ee8cc1Swenshuai.xi iEpNum = usb_pipeendpoint (pUrb->u32Pipe);
1895*53ee8cc1Swenshuai.xi if (usb_pipein (pUrb->u32Pipe) && !usb_pipecontrol (pUrb->u32Pipe))
1896*53ee8cc1Swenshuai.xi iEpNum |= 0x10;
1897*53ee8cc1Swenshuai.xi
1898*53ee8cc1Swenshuai.xi osapi_spin_lock_irqsave (&pEhci->tHcdLock, u32Flags);
1899*53ee8cc1Swenshuai.xi pQh = ms_qh_append_tds (pEhci, pUrb, qtd_list, iEpNum, &pDev->ep [iEpNum]);
1900*53ee8cc1Swenshuai.xi /* EP Control/bulk �g�L TT ���ݭn scheduling */
1901*53ee8cc1Swenshuai.xi if (pQh != 0)
1902*53ee8cc1Swenshuai.xi {
1903*53ee8cc1Swenshuai.xi if (pQh->qh_status == QH_STS_IDLE)
1904*53ee8cc1Swenshuai.xi ms_qh_link_async (pEhci, ms_qh_get (pQh));
1905*53ee8cc1Swenshuai.xi }
1906*53ee8cc1Swenshuai.xi
1907*53ee8cc1Swenshuai.xi Chip_Flush_Memory();
1908*53ee8cc1Swenshuai.xi
1909*53ee8cc1Swenshuai.xi osapi_spin_unlock_irqrestore (&pEhci->tHcdLock, u32Flags);
1910*53ee8cc1Swenshuai.xi if (pQh == 0)
1911*53ee8cc1Swenshuai.xi {
1912*53ee8cc1Swenshuai.xi ms_qtd_register_free (pEhci, qtd_list);
1913*53ee8cc1Swenshuai.xi return -ENOMEM;
1914*53ee8cc1Swenshuai.xi }
1915*53ee8cc1Swenshuai.xi ms_debug_func("--[%s] line:[%d]\n", __FUNCTION__, __LINE__);
1916*53ee8cc1Swenshuai.xi return 0;
1917*53ee8cc1Swenshuai.xi }
1918*53ee8cc1Swenshuai.xi
1919*53ee8cc1Swenshuai.xi /*-------------------------------------------------------------------------*/
1920*53ee8cc1Swenshuai.xi
1921*53ee8cc1Swenshuai.xi static void ms_start_unlink_async (struct ehci_hcd *pEhci, struct ehci_qh *pQh);
ms_end_unlink_async(struct ehci_hcd * pEhci,struct stPtRegs * pRegs)1922*53ee8cc1Swenshuai.xi static void ms_end_unlink_async (struct ehci_hcd *pEhci, struct stPtRegs *pRegs)
1923*53ee8cc1Swenshuai.xi {
1924*53ee8cc1Swenshuai.xi struct ehci_qh *pQh = pEhci->stReclaim;
1925*53ee8cc1Swenshuai.xi struct ehci_qh *pNext;
1926*53ee8cc1Swenshuai.xi
1927*53ee8cc1Swenshuai.xi ms_debug_func("++[%s] line:[%d]\n", __FUNCTION__, __LINE__);
1928*53ee8cc1Swenshuai.xi if(pQh == NULL)
1929*53ee8cc1Swenshuai.xi {
1930*53ee8cc1Swenshuai.xi ms_debug_err("--[%s] reclaim NULL\n", __FUNCTION__);
1931*53ee8cc1Swenshuai.xi return;
1932*53ee8cc1Swenshuai.xi }
1933*53ee8cc1Swenshuai.xi
1934*53ee8cc1Swenshuai.xi //ms_timer_action_done (pEhci, TIMER_IAA_WATCHDOG);
1935*53ee8cc1Swenshuai.xi ms_iaa_watchdog_done(pEhci);
1936*53ee8cc1Swenshuai.xi
1937*53ee8cc1Swenshuai.xi Chip_Read_Memory(); // 20121218, 20121225
1938*53ee8cc1Swenshuai.xi
1939*53ee8cc1Swenshuai.xi pQh->qh_status = QH_STS_IDLE;
1940*53ee8cc1Swenshuai.xi pQh->qh_next.qh = 0;
1941*53ee8cc1Swenshuai.xi ms_qh_put (pEhci, pQh); // pQh is directed to reclaim
1942*53ee8cc1Swenshuai.xi
1943*53ee8cc1Swenshuai.xi pNext = pQh->pReclaimQh;
1944*53ee8cc1Swenshuai.xi pEhci->stReclaim = pNext;
1945*53ee8cc1Swenshuai.xi //pEhci->iReclaimReady = 0;
1946*53ee8cc1Swenshuai.xi pQh->pReclaimQh = 0;
1947*53ee8cc1Swenshuai.xi
1948*53ee8cc1Swenshuai.xi ms_qh_completions (pEhci, pQh, pRegs);
1949*53ee8cc1Swenshuai.xi
1950*53ee8cc1Swenshuai.xi if (!ms_is_empty_list (&pQh->qtd_list)
1951*53ee8cc1Swenshuai.xi && HCD_IS_RUNNING (pEhci->hcd.state))
1952*53ee8cc1Swenshuai.xi ms_qh_link_async (pEhci, pQh);
1953*53ee8cc1Swenshuai.xi else
1954*53ee8cc1Swenshuai.xi {
1955*53ee8cc1Swenshuai.xi ms_qh_put (pEhci, pQh); // pQh is directed from async list
1956*53ee8cc1Swenshuai.xi
1957*53ee8cc1Swenshuai.xi if (HCD_IS_RUNNING (pEhci->hcd.state)
1958*53ee8cc1Swenshuai.xi && pEhci->stAsync->qh_next.qh == 0)
1959*53ee8cc1Swenshuai.xi ms_timer_action (pEhci, TIMER_ASYNC_OFF);
1960*53ee8cc1Swenshuai.xi }
1961*53ee8cc1Swenshuai.xi
1962*53ee8cc1Swenshuai.xi if (pNext)
1963*53ee8cc1Swenshuai.xi {
1964*53ee8cc1Swenshuai.xi pEhci->stReclaim = 0;
1965*53ee8cc1Swenshuai.xi ms_start_unlink_async (pEhci, pNext);
1966*53ee8cc1Swenshuai.xi }
1967*53ee8cc1Swenshuai.xi ms_debug_func("--[%s] line:[%d]\n", __FUNCTION__, __LINE__);
1968*53ee8cc1Swenshuai.xi }
1969*53ee8cc1Swenshuai.xi
ms_start_unlink_async(struct ehci_hcd * pEhci,struct ehci_qh * pQh)1970*53ee8cc1Swenshuai.xi static void ms_start_unlink_async (struct ehci_hcd *pEhci, struct ehci_qh *pQh)
1971*53ee8cc1Swenshuai.xi {
1972*53ee8cc1Swenshuai.xi int iUsbCmd = hcd_reg_readl ((U32)&pEhci->op_regs->usbcmd);
1973*53ee8cc1Swenshuai.xi struct ehci_qh *pPrev;
1974*53ee8cc1Swenshuai.xi
1975*53ee8cc1Swenshuai.xi ms_debug_func("++[%s] line:[%d]\n", __FUNCTION__, __LINE__);
1976*53ee8cc1Swenshuai.xi #ifdef DEBUG
1977*53ee8cc1Swenshuai.xi if (pEhci->stReclaim
1978*53ee8cc1Swenshuai.xi || (pQh->qh_status != QH_STS_LINKED
1979*53ee8cc1Swenshuai.xi && pQh->qh_status != QH_STS_UNLINK_WAIT)
1980*53ee8cc1Swenshuai.xi // If support SMP, needs to check locked
1981*53ee8cc1Swenshuai.xi // || !spin_is_locked (&pEhci->tHcdLock)
1982*53ee8cc1Swenshuai.xi )
1983*53ee8cc1Swenshuai.xi USB_ASSERT(0, "BUG()!\n");
1984*53ee8cc1Swenshuai.xi #endif
1985*53ee8cc1Swenshuai.xi
1986*53ee8cc1Swenshuai.xi if (pQh == pEhci->stAsync)
1987*53ee8cc1Swenshuai.xi {
1988*53ee8cc1Swenshuai.xi if (pEhci->hcd.state != HCD_STATE_HALT && !pEhci->stReclaim)
1989*53ee8cc1Swenshuai.xi {
1990*53ee8cc1Swenshuai.xi /* stop async schedule */
1991*53ee8cc1Swenshuai.xi hcd_reg_writel (iUsbCmd & ~USBCMD_ASE, (U32)&pEhci->op_regs->usbcmd);
1992*53ee8cc1Swenshuai.xi wmb ();
1993*53ee8cc1Swenshuai.xi // handshake later, if we need to
1994*53ee8cc1Swenshuai.xi ms_timer_action_done (pEhci, TIMER_ASYNC_OFF);
1995*53ee8cc1Swenshuai.xi }
1996*53ee8cc1Swenshuai.xi return;
1997*53ee8cc1Swenshuai.xi }
1998*53ee8cc1Swenshuai.xi
1999*53ee8cc1Swenshuai.xi pQh->qh_status = QH_STS_UNLINK;
2000*53ee8cc1Swenshuai.xi pEhci->stReclaim = pQh = ms_qh_get (pQh);
2001*53ee8cc1Swenshuai.xi
2002*53ee8cc1Swenshuai.xi pPrev = pEhci->stAsync;
2003*53ee8cc1Swenshuai.xi while (pPrev->qh_next.qh != pQh)
2004*53ee8cc1Swenshuai.xi pPrev = pPrev->qh_next.qh;
2005*53ee8cc1Swenshuai.xi
2006*53ee8cc1Swenshuai.xi #ifdef _USB_ENABLE_BDMA_PATCH // BDMA SW patch
2007*53ee8cc1Swenshuai.xi if (get_64bit_OBF_cipher()) {
2008*53ee8cc1Swenshuai.xi m_BDMA_write(pQh->qh_dma_addr, pPrev->qh_dma_addr);
2009*53ee8cc1Swenshuai.xi USB_ASSERT(pPrev->hw_next_qh == pQh->hw_next_qh,
2010*53ee8cc1Swenshuai.xi "[BDMA] hw_next not matched!\n");
2011*53ee8cc1Swenshuai.xi }
2012*53ee8cc1Swenshuai.xi else
2013*53ee8cc1Swenshuai.xi pPrev->hw_next_qh = pQh->hw_next_qh;
2014*53ee8cc1Swenshuai.xi #else
2015*53ee8cc1Swenshuai.xi pPrev->hw_next_qh = pQh->hw_next_qh;
2016*53ee8cc1Swenshuai.xi #endif
2017*53ee8cc1Swenshuai.xi pPrev->qh_next = pQh->qh_next;
2018*53ee8cc1Swenshuai.xi wmb ();
2019*53ee8cc1Swenshuai.xi
2020*53ee8cc1Swenshuai.xi Chip_Flush_Memory(); // (20140827 to push the pipe)
2021*53ee8cc1Swenshuai.xi
2022*53ee8cc1Swenshuai.xi //if (pEhci->hcd.state == HCD_STATE_HALT)
2023*53ee8cc1Swenshuai.xi if (!HCD_IS_RUNNING(pEhci->hcd.state))
2024*53ee8cc1Swenshuai.xi {
2025*53ee8cc1Swenshuai.xi ms_end_unlink_async (pEhci, NULL);
2026*53ee8cc1Swenshuai.xi ms_debug_err("HCD not running, end unlink directly\n");
2027*53ee8cc1Swenshuai.xi return;
2028*53ee8cc1Swenshuai.xi }
2029*53ee8cc1Swenshuai.xi //inform HC thar something has been removed from asyn. schedule
2030*53ee8cc1Swenshuai.xi //pEhci->iReclaimReady = 0;
2031*53ee8cc1Swenshuai.xi #if 1 // For bug 125MHz copy error (HALT)
2032*53ee8cc1Swenshuai.xi //if (!pEhci->uDontSendIAA) // 20130110 no need flag control
2033*53ee8cc1Swenshuai.xi {
2034*53ee8cc1Swenshuai.xi iUsbCmd |= USBCMD_IAAD;
2035*53ee8cc1Swenshuai.xi hcd_reg_writel (iUsbCmd, (U32)&pEhci->op_regs->usbcmd);
2036*53ee8cc1Swenshuai.xi }
2037*53ee8cc1Swenshuai.xi #endif
2038*53ee8cc1Swenshuai.xi //ms_timer_action (pEhci, TIMER_IAA_WATCHDOG);
2039*53ee8cc1Swenshuai.xi ms_iaa_watchdog_begin(pEhci);
2040*53ee8cc1Swenshuai.xi ms_debug_func("--[%s] line:[%d]\n", __FUNCTION__, __LINE__);
2041*53ee8cc1Swenshuai.xi }
2042*53ee8cc1Swenshuai.xi
ms_unlink_async(struct ehci_hcd * pEhci,struct ehci_qh * pQh)2043*53ee8cc1Swenshuai.xi static void ms_unlink_async (struct ehci_hcd *pEhci, struct ehci_qh *pQh)
2044*53ee8cc1Swenshuai.xi {
2045*53ee8cc1Swenshuai.xi if (!HCD_IS_RUNNING (pEhci->hcd.state) && pEhci->stReclaim)
2046*53ee8cc1Swenshuai.xi ms_end_unlink_async (pEhci, NULL);
2047*53ee8cc1Swenshuai.xi
2048*53ee8cc1Swenshuai.xi if (pQh->qh_status != QH_STS_LINKED)
2049*53ee8cc1Swenshuai.xi ;
2050*53ee8cc1Swenshuai.xi else if (pEhci->stReclaim)
2051*53ee8cc1Swenshuai.xi {
2052*53ee8cc1Swenshuai.xi struct ehci_qh *pLast;
2053*53ee8cc1Swenshuai.xi
2054*53ee8cc1Swenshuai.xi for (pLast = pEhci->stReclaim;
2055*53ee8cc1Swenshuai.xi pLast->pReclaimQh;
2056*53ee8cc1Swenshuai.xi pLast = pLast->pReclaimQh)
2057*53ee8cc1Swenshuai.xi continue;
2058*53ee8cc1Swenshuai.xi pQh->qh_status = QH_STS_UNLINK_WAIT;
2059*53ee8cc1Swenshuai.xi pLast->pReclaimQh = pQh;
2060*53ee8cc1Swenshuai.xi /* bypass IAA if the hc can't care */
2061*53ee8cc1Swenshuai.xi diag_printf("[EHCI] set QH_STS_UNLINK_WAIT\n");
2062*53ee8cc1Swenshuai.xi }
2063*53ee8cc1Swenshuai.xi else
2064*53ee8cc1Swenshuai.xi ms_start_unlink_async (pEhci, pQh);
2065*53ee8cc1Swenshuai.xi }
2066*53ee8cc1Swenshuai.xi
2067*53ee8cc1Swenshuai.xi /*-------------------------------------------------------------------------*/
2068*53ee8cc1Swenshuai.xi /*
2069*53ee8cc1Swenshuai.xi * @brief free qtd list but kept qh for plug test shall cause some problems
2070*53ee8cc1Swenshuai.xi *
2071*53ee8cc1Swenshuai.xi * @param struct ehci_hcd *pEhci
2072*53ee8cc1Swenshuai.xi * @param struct stPtRegs *pRegs
2073*53ee8cc1Swenshuai.xi *
2074*53ee8cc1Swenshuai.xi * @return none
2075*53ee8cc1Swenshuai.xi */
2076*53ee8cc1Swenshuai.xi
2077*53ee8cc1Swenshuai.xi static void
ms_scan_async(struct ehci_hcd * pEhci,struct stPtRegs * pRegs)2078*53ee8cc1Swenshuai.xi ms_scan_async (struct ehci_hcd *pEhci, struct stPtRegs *pRegs)
2079*53ee8cc1Swenshuai.xi {
2080*53ee8cc1Swenshuai.xi struct ehci_qh *pQh;
2081*53ee8cc1Swenshuai.xi enum ehci_timer_event eAction = TIMER_IO_WATCHDOG;
2082*53ee8cc1Swenshuai.xi
2083*53ee8cc1Swenshuai.xi ms_debug_func("++[%s] line:[%d]\n", __FUNCTION__, __LINE__);
2084*53ee8cc1Swenshuai.xi if (!++(pEhci->u32Stamp))
2085*53ee8cc1Swenshuai.xi pEhci->u32Stamp++;
2086*53ee8cc1Swenshuai.xi ms_timer_action_done (pEhci, TIMER_ASYNC_SHRINK);
2087*53ee8cc1Swenshuai.xi rescan:
2088*53ee8cc1Swenshuai.xi pQh = pEhci->stAsync->qh_next.qh;
2089*53ee8cc1Swenshuai.xi if (pQh != 0)
2090*53ee8cc1Swenshuai.xi {
2091*53ee8cc1Swenshuai.xi do
2092*53ee8cc1Swenshuai.xi {
2093*53ee8cc1Swenshuai.xi /* free qtd for this qh */
2094*53ee8cc1Swenshuai.xi if (!ms_is_empty_list (&pQh->qtd_list)
2095*53ee8cc1Swenshuai.xi && pQh->u32Stamp != pEhci->u32Stamp)
2096*53ee8cc1Swenshuai.xi {
2097*53ee8cc1Swenshuai.xi int temp;
2098*53ee8cc1Swenshuai.xi
2099*53ee8cc1Swenshuai.xi pQh = ms_qh_get (pQh);
2100*53ee8cc1Swenshuai.xi pQh->u32Stamp = pEhci->u32Stamp;
2101*53ee8cc1Swenshuai.xi temp = ms_qh_completions (pEhci, pQh, pRegs);
2102*53ee8cc1Swenshuai.xi ms_qh_put (pEhci, pQh);
2103*53ee8cc1Swenshuai.xi if (temp != 0)
2104*53ee8cc1Swenshuai.xi {
2105*53ee8cc1Swenshuai.xi goto rescan;
2106*53ee8cc1Swenshuai.xi }
2107*53ee8cc1Swenshuai.xi }
2108*53ee8cc1Swenshuai.xi
2109*53ee8cc1Swenshuai.xi //FIXME: #if 1 is correct procedure but it will cause some problems when do plug testing
2110*53ee8cc1Swenshuai.xi //Watchdog timer will be unlink for unknow reason ==> Therefore, qHD can not be
2111*53ee8cc1Swenshuai.xi //unlinked from async list. (qh->state == USB_STATE_LINKED but HCD_STATE_HALT)
2112*53ee8cc1Swenshuai.xi //So when disconnect attached device ep1in (Bulk in) cannot be released.
2113*53ee8cc1Swenshuai.xi #if 1
2114*53ee8cc1Swenshuai.xi #if 0
2115*53ee8cc1Swenshuai.xi if (ms_is_empty_list (&pQh->qtd_list))
2116*53ee8cc1Swenshuai.xi {
2117*53ee8cc1Swenshuai.xi if (pQh->u32Stamp == pEhci->u32Stamp)
2118*53ee8cc1Swenshuai.xi eAction = TIMER_ASYNC_SHRINK;
2119*53ee8cc1Swenshuai.xi else if (!pEhci->stReclaim
2120*53ee8cc1Swenshuai.xi && pQh->qh_status == QH_STS_LINKED)
2121*53ee8cc1Swenshuai.xi ms_start_unlink_async (pEhci, pQh);
2122*53ee8cc1Swenshuai.xi }
2123*53ee8cc1Swenshuai.xi #else
2124*53ee8cc1Swenshuai.xi #define MS_QH_SHRINK_FRAMES 5
2125*53ee8cc1Swenshuai.xi if (ms_is_empty_list (&pQh->qtd_list) && (pQh->qh_status == QH_STS_LINKED))
2126*53ee8cc1Swenshuai.xi {
2127*53ee8cc1Swenshuai.xi if (!pEhci->stReclaim
2128*53ee8cc1Swenshuai.xi && ((pEhci->u32Stamp - pQh->u32Stamp) & 0x1fff) >= MS_QH_SHRINK_FRAMES * 8)
2129*53ee8cc1Swenshuai.xi {
2130*53ee8cc1Swenshuai.xi //diag_printf("[USB][%d] %s start_unlink sts1:%x\n",
2131*53ee8cc1Swenshuai.xi // jiffies, __func__, pQh->hw_ep_state1);
2132*53ee8cc1Swenshuai.xi ms_start_unlink_async (pEhci, pQh);
2133*53ee8cc1Swenshuai.xi }
2134*53ee8cc1Swenshuai.xi else
2135*53ee8cc1Swenshuai.xi {
2136*53ee8cc1Swenshuai.xi //diag_printf("[USB] TIMER_ASYNC_SHRINK qh_sts:0x%x\n", pQh->hw_ep_state1);
2137*53ee8cc1Swenshuai.xi eAction = TIMER_ASYNC_SHRINK;
2138*53ee8cc1Swenshuai.xi }
2139*53ee8cc1Swenshuai.xi }
2140*53ee8cc1Swenshuai.xi #endif
2141*53ee8cc1Swenshuai.xi #else
2142*53ee8cc1Swenshuai.xi if (ms_is_empty_list (&pQh->qtd_list))
2143*53ee8cc1Swenshuai.xi {
2144*53ee8cc1Swenshuai.xi if (!pEhci->stReclaim && pQh->qh_status == QH_STS_LINKED)
2145*53ee8cc1Swenshuai.xi ms_start_unlink_async (pEhci, pQh);
2146*53ee8cc1Swenshuai.xi }
2147*53ee8cc1Swenshuai.xi #endif
2148*53ee8cc1Swenshuai.xi pQh = pQh->qh_next.qh;
2149*53ee8cc1Swenshuai.xi } while (pQh);
2150*53ee8cc1Swenshuai.xi }
2151*53ee8cc1Swenshuai.xi if (eAction == TIMER_ASYNC_SHRINK)
2152*53ee8cc1Swenshuai.xi ms_timer_action (pEhci, TIMER_ASYNC_SHRINK);
2153*53ee8cc1Swenshuai.xi ms_debug_func("--[%s] line:[%d]\n", __FUNCTION__, __LINE__);
2154*53ee8cc1Swenshuai.xi }
2155*53ee8cc1Swenshuai.xi
2156*53ee8cc1Swenshuai.xi #ifdef EHCI_TD_DEBUG
dbg_timeout_async(struct usb_hcd * hcd)2157*53ee8cc1Swenshuai.xi void dbg_timeout_async(struct usb_hcd *hcd)
2158*53ee8cc1Swenshuai.xi {
2159*53ee8cc1Swenshuai.xi #if defined(CPU_TYPE_MIPS)
2160*53ee8cc1Swenshuai.xi #define PA2VA(a) (0xA0000000+(a))
2161*53ee8cc1Swenshuai.xi #elif defined(CPU_TYPE_ARM)
2162*53ee8cc1Swenshuai.xi #define PA2VA(a) (0x20000000+(a))
2163*53ee8cc1Swenshuai.xi #endif
2164*53ee8cc1Swenshuai.xi #define HW_NEXT(a) ((a) & 0xffffffe0)
2165*53ee8cc1Swenshuai.xi struct ehci_hcd *ehci = hcd_to_ehci(hcd);
2166*53ee8cc1Swenshuai.xi struct ehci_qh *qh;
2167*53ee8cc1Swenshuai.xi unsigned int *hw_p;
2168*53ee8cc1Swenshuai.xi unsigned int hw_next;
2169*53ee8cc1Swenshuai.xi
2170*53ee8cc1Swenshuai.xi /* print out async register */
2171*53ee8cc1Swenshuai.xi hw_next = hcd_reg_readl ((U32)&ehci->op_regs->asynclistaddr);
2172*53ee8cc1Swenshuai.xi diag_printf("[EHCI] async register %x\n", hw_next);
2173*53ee8cc1Swenshuai.xi /* print out hardware asynchronous qh link */
2174*53ee8cc1Swenshuai.xi hw_next = (U32)ehci->stAsync;
2175*53ee8cc1Swenshuai.xi diag_printf("--> %8x", hw_next);
2176*53ee8cc1Swenshuai.xi diag_printf("--> %8x", hw_next+0x80);
2177*53ee8cc1Swenshuai.xi diag_printf("--> %8x", hw_next+0x100);
2178*53ee8cc1Swenshuai.xi diag_printf("--> %8x\n", hw_next+0x180);
2179*53ee8cc1Swenshuai.xi
2180*53ee8cc1Swenshuai.xi hw_p = (unsigned int *)hw_next;
2181*53ee8cc1Swenshuai.xi diag_printf("--> %8x", *hw_p);
2182*53ee8cc1Swenshuai.xi hw_next += 0x80;
2183*53ee8cc1Swenshuai.xi hw_p = (unsigned int *)hw_next;
2184*53ee8cc1Swenshuai.xi diag_printf("--> %8x", *hw_p);
2185*53ee8cc1Swenshuai.xi hw_next += 0x80;
2186*53ee8cc1Swenshuai.xi hw_p = (unsigned int *)hw_next;
2187*53ee8cc1Swenshuai.xi diag_printf("--> %8x", *hw_p);
2188*53ee8cc1Swenshuai.xi hw_next += 0x80;
2189*53ee8cc1Swenshuai.xi hw_p = (unsigned int *)hw_next;
2190*53ee8cc1Swenshuai.xi diag_printf("--> %8x", *hw_p);
2191*53ee8cc1Swenshuai.xi diag_printf("\n");
2192*53ee8cc1Swenshuai.xi
2193*53ee8cc1Swenshuai.xi /* print out asynchronous qh list */
2194*53ee8cc1Swenshuai.xi qh = ehci->stAsync->qh_next.qh;
2195*53ee8cc1Swenshuai.xi if (qh == 0) {
2196*53ee8cc1Swenshuai.xi diag_printf("[EHCI] no QH list\n");
2197*53ee8cc1Swenshuai.xi return;
2198*53ee8cc1Swenshuai.xi }
2199*53ee8cc1Swenshuai.xi do {
2200*53ee8cc1Swenshuai.xi unsigned int c_qtd;
2201*53ee8cc1Swenshuai.xi int cqtd_n_list = 1;
2202*53ee8cc1Swenshuai.xi
2203*53ee8cc1Swenshuai.xi diag_printf("qh status %d, dummy_qtd %x\n",
2204*53ee8cc1Swenshuai.xi qh->qh_status, (unsigned int)qh->pDummyQtd);
2205*53ee8cc1Swenshuai.xi Dump_TD((unsigned int)qh, 1);
2206*53ee8cc1Swenshuai.xi c_qtd = (unsigned int)PA2VA(qh->hw_current_qtd);
2207*53ee8cc1Swenshuai.xi if (!ms_is_empty_list (&qh->qtd_list)) {
2208*53ee8cc1Swenshuai.xi struct list_head *entry, *tmp;
2209*53ee8cc1Swenshuai.xi
2210*53ee8cc1Swenshuai.xi list_for_loop_ex (entry, tmp, &qh->qtd_list) {
2211*53ee8cc1Swenshuai.xi struct ehci_qtd *qtd;
2212*53ee8cc1Swenshuai.xi
2213*53ee8cc1Swenshuai.xi qtd = entry_to_container (entry, struct ehci_qtd, qtd_list);
2214*53ee8cc1Swenshuai.xi Dump_TD((unsigned int)qtd, 0);
2215*53ee8cc1Swenshuai.xi if (c_qtd == (unsigned int)qtd)
2216*53ee8cc1Swenshuai.xi cqtd_n_list = 0;
2217*53ee8cc1Swenshuai.xi }
2218*53ee8cc1Swenshuai.xi }
2219*53ee8cc1Swenshuai.xi if (cqtd_n_list) {
2220*53ee8cc1Swenshuai.xi diag_printf(" CURRENT QTD\n");
2221*53ee8cc1Swenshuai.xi Dump_TD((unsigned int)PA2VA(qh->hw_current_qtd), 0);
2222*53ee8cc1Swenshuai.xi }
2223*53ee8cc1Swenshuai.xi qh = qh->qh_next.qh;
2224*53ee8cc1Swenshuai.xi } while (qh);
2225*53ee8cc1Swenshuai.xi }
2226*53ee8cc1Swenshuai.xi #endif
2227*53ee8cc1Swenshuai.xi
2228*53ee8cc1Swenshuai.xi #include "drvEHCI_SCHD.cxx"
2229*53ee8cc1Swenshuai.xi
2230*53ee8cc1Swenshuai.xi /*-------------------------------------------------------------------------*/
2231*53ee8cc1Swenshuai.xi
2232*53ee8cc1Swenshuai.xi static void ms_ehci_work(struct ehci_hcd *ehci, struct stPtRegs *regs);
ms_ehci_iaa_watchdog(U32 u32Param)2233*53ee8cc1Swenshuai.xi static void ms_ehci_iaa_watchdog(U32 u32Param)
2234*53ee8cc1Swenshuai.xi {
2235*53ee8cc1Swenshuai.xi struct ehci_hcd *pEhci = (struct ehci_hcd *) u32Param;
2236*53ee8cc1Swenshuai.xi unsigned long u32Flags;
2237*53ee8cc1Swenshuai.xi
2238*53ee8cc1Swenshuai.xi ms_debug_func("++[%s] line:[%d]\n", __FUNCTION__, __LINE__);
2239*53ee8cc1Swenshuai.xi osapi_spin_lock_irqsave (&pEhci->tHcdLock, u32Flags);
2240*53ee8cc1Swenshuai.xi
2241*53ee8cc1Swenshuai.xi /* see Linux 2.6.28.9 ehci_iaa_watchdog description
2242*53ee8cc1Swenshuai.xi */
2243*53ee8cc1Swenshuai.xi if (pEhci->stReclaim
2244*53ee8cc1Swenshuai.xi && !ms_timer_pending(&pEhci->stiaa_Watchdog)
2245*53ee8cc1Swenshuai.xi && HCD_IS_RUNNING(pEhci->hcd.state)) {
2246*53ee8cc1Swenshuai.xi U32 u32Cmd, u32Status;
2247*53ee8cc1Swenshuai.xi
2248*53ee8cc1Swenshuai.xi u32Cmd = hcd_reg_readl((U32)&pEhci->op_regs->usbcmd);
2249*53ee8cc1Swenshuai.xi if (u32Cmd & USBCMD_IAAD)
2250*53ee8cc1Swenshuai.xi hcd_reg_writel(u32Cmd & ~USBCMD_IAAD,
2251*53ee8cc1Swenshuai.xi (U32)&pEhci->op_regs->usbcmd);
2252*53ee8cc1Swenshuai.xi
2253*53ee8cc1Swenshuai.xi u32Status = hcd_reg_readl((U32)&pEhci->op_regs->usbsts);
2254*53ee8cc1Swenshuai.xi if ((u32Status & USBSTS_IAA) || !(u32Cmd & USBCMD_IAAD)) {
2255*53ee8cc1Swenshuai.xi INCREASE (pEhci->stats.u32LostIAA);
2256*53ee8cc1Swenshuai.xi ms_debug_err("IAA watchdog (lost IAA): status %x cmd %x\n",
2257*53ee8cc1Swenshuai.xi u32Status, u32Cmd);
2258*53ee8cc1Swenshuai.xi hcd_reg_writel(USBSTS_IAA, (U32)&pEhci->op_regs->usbsts);
2259*53ee8cc1Swenshuai.xi }
2260*53ee8cc1Swenshuai.xi
2261*53ee8cc1Swenshuai.xi ms_debug_func("IAA watchdog: status %x cmd %x\n",
2262*53ee8cc1Swenshuai.xi u32Status, u32Cmd);
2263*53ee8cc1Swenshuai.xi ms_end_unlink_async(pEhci, NULL);
2264*53ee8cc1Swenshuai.xi }
2265*53ee8cc1Swenshuai.xi
2266*53ee8cc1Swenshuai.xi osapi_spin_unlock_irqrestore(&pEhci->tHcdLock, u32Flags);
2267*53ee8cc1Swenshuai.xi ms_debug_func("--[%s] line:[%d]\n", __FUNCTION__, __LINE__);
2268*53ee8cc1Swenshuai.xi }
2269*53ee8cc1Swenshuai.xi
ms_ehci_watchdog(U32 u32Param)2270*53ee8cc1Swenshuai.xi static void ms_ehci_watchdog (U32 u32Param)
2271*53ee8cc1Swenshuai.xi {
2272*53ee8cc1Swenshuai.xi struct ehci_hcd *pEhci = (struct ehci_hcd *) u32Param;
2273*53ee8cc1Swenshuai.xi U32 u32Flags;
2274*53ee8cc1Swenshuai.xi
2275*53ee8cc1Swenshuai.xi ms_debug_func("++[%s] line:[%d]\n", __FUNCTION__, __LINE__);
2276*53ee8cc1Swenshuai.xi ms_debug_func("[%s] action: 0x%08X\n", __FUNCTION__, (U32)pEhci->u32Actions);
2277*53ee8cc1Swenshuai.xi osapi_spin_lock_irqsave (&pEhci->tHcdLock, u32Flags);
2278*53ee8cc1Swenshuai.xi
2279*53ee8cc1Swenshuai.xi #if 0 // old reclaim flow
2280*53ee8cc1Swenshuai.xi /* avoid vt8235 lost IAA irqs */
2281*53ee8cc1Swenshuai.xi if (pEhci->stReclaim)
2282*53ee8cc1Swenshuai.xi {
2283*53ee8cc1Swenshuai.xi U32 status = hcd_reg_readl ((U32)&pEhci->op_regs->usbsts);
2284*53ee8cc1Swenshuai.xi
2285*53ee8cc1Swenshuai.xi if (status & USBSTS_IAA)
2286*53ee8cc1Swenshuai.xi {
2287*53ee8cc1Swenshuai.xi INCREASE(pEhci->stats.u32LostIAA);
2288*53ee8cc1Swenshuai.xi hcd_reg_writel (USBSTS_IAA, (U32)&pEhci->op_regs->usbsts);
2289*53ee8cc1Swenshuai.xi pEhci->iReclaimReady = 1;
2290*53ee8cc1Swenshuai.xi }
2291*53ee8cc1Swenshuai.xi else if ( (hcd_reg_readl((U32)&pEhci->op_regs->usbcmd)&USBCMD_IAAD) && !(status & USBSTS_IAA))
2292*53ee8cc1Swenshuai.xi {
2293*53ee8cc1Swenshuai.xi ms_debug_warn ("Something wrong ==>lost IAA\n");//HW ISSUE?
2294*53ee8cc1Swenshuai.xi pEhci->iReclaimReady = 1;
2295*53ee8cc1Swenshuai.xi }
2296*53ee8cc1Swenshuai.xi }
2297*53ee8cc1Swenshuai.xi #endif
2298*53ee8cc1Swenshuai.xi
2299*53ee8cc1Swenshuai.xi /* stop async processing after it's idled a bit */
2300*53ee8cc1Swenshuai.xi //Periodic schedule issue was fixed, so reopen it
2301*53ee8cc1Swenshuai.xi if (ms_test_bit (TIMER_ASYNC_OFF, &pEhci->u32Actions))
2302*53ee8cc1Swenshuai.xi ms_start_unlink_async (pEhci, pEhci->stAsync);
2303*53ee8cc1Swenshuai.xi
2304*53ee8cc1Swenshuai.xi /* pEhci could run by timer, without IRQs ... */
2305*53ee8cc1Swenshuai.xi //if (ms_test_bit (TIMER_IO_WATCHDOG, &pEhci->u32Actions))
2306*53ee8cc1Swenshuai.xi ms_ehci_work(pEhci, NULL);
2307*53ee8cc1Swenshuai.xi
2308*53ee8cc1Swenshuai.xi osapi_spin_unlock_irqrestore (&pEhci->tHcdLock, u32Flags);
2309*53ee8cc1Swenshuai.xi ms_debug_func("--[%s] line:[%d]\n", __FUNCTION__, __LINE__);
2310*53ee8cc1Swenshuai.xi
2311*53ee8cc1Swenshuai.xi }
2312*53ee8cc1Swenshuai.xi
ms_ehci_init(struct usb_hcd * pHcd)2313*53ee8cc1Swenshuai.xi int ms_ehci_init (struct usb_hcd *pHcd)
2314*53ee8cc1Swenshuai.xi {
2315*53ee8cc1Swenshuai.xi struct ehci_hcd *ehci = hcd_to_ehci (pHcd);
2316*53ee8cc1Swenshuai.xi
2317*53ee8cc1Swenshuai.xi ms_debug_func("++[%s] line:[%d]\n", __FUNCTION__, __LINE__);
2318*53ee8cc1Swenshuai.xi osapi_spin_lock_init (&ehci->tHcdLock);
2319*53ee8cc1Swenshuai.xi
2320*53ee8cc1Swenshuai.xi ehci->u32MoreCSC = false;
2321*53ee8cc1Swenshuai.xi ehci->ehci_port_not_change_cnt = 0;
2322*53ee8cc1Swenshuai.xi
2323*53ee8cc1Swenshuai.xi ehci->cap_regs = (struct ehci_cap_regs *) pHcd->uhc_regs;
2324*53ee8cc1Swenshuai.xi ehci->op_regs = (struct ehci_op_regs *) ( (U32)pHcd->uhc_regs +
2325*53ee8cc1Swenshuai.xi (U32)hcd_reg_readb ((U32)&ehci->cap_regs->caplength));
2326*53ee8cc1Swenshuai.xi
2327*53ee8cc1Swenshuai.xi ehci->hcs_params = hcd_reg_readl ((U32)&ehci->cap_regs->hcsparams);
2328*53ee8cc1Swenshuai.xi ms_debug_func("--[%s] line:[%d]\n", __FUNCTION__, __LINE__);
2329*53ee8cc1Swenshuai.xi return ms_ehci_halt (ehci);
2330*53ee8cc1Swenshuai.xi }
2331*53ee8cc1Swenshuai.xi
2332*53ee8cc1Swenshuai.xi /*
2333*53ee8cc1Swenshuai.xi * @brief start ehci controller
2334*53ee8cc1Swenshuai.xi *
2335*53ee8cc1Swenshuai.xi * @param struct usb_hcd *hcd
2336*53ee8cc1Swenshuai.xi *
2337*53ee8cc1Swenshuai.xi * @return error code
2338*53ee8cc1Swenshuai.xi */
2339*53ee8cc1Swenshuai.xi
2340*53ee8cc1Swenshuai.xi extern void ms_hcd_poll_rh_status(struct usb_hcd *pHcd);
2341*53ee8cc1Swenshuai.xi extern MS_U8 MDrv_SYS_GetChipRev(void);
ms_ehci_begin(struct usb_hcd * hcd)2342*53ee8cc1Swenshuai.xi int ms_ehci_begin (struct usb_hcd *hcd)
2343*53ee8cc1Swenshuai.xi {
2344*53ee8cc1Swenshuai.xi struct ehci_hcd *ehci = hcd_to_ehci (hcd);
2345*53ee8cc1Swenshuai.xi U32 u32Temp;
2346*53ee8cc1Swenshuai.xi struct usb_device *pUdev;
2347*53ee8cc1Swenshuai.xi struct usb_bus *pBus;
2348*53ee8cc1Swenshuai.xi int iRetval;
2349*53ee8cc1Swenshuai.xi U32 u32HccParams;
2350*53ee8cc1Swenshuai.xi
2351*53ee8cc1Swenshuai.xi ms_debug_func("++[%s] line:[%d]\n", __FUNCTION__, __LINE__);
2352*53ee8cc1Swenshuai.xi
2353*53ee8cc1Swenshuai.xi ehci->u32PeriodicSize = DEFAULT_I_TDPS;
2354*53ee8cc1Swenshuai.xi if ((iRetval = ms_ehci_mem_init (ehci, SLAB_KERNEL)) < 0)
2355*53ee8cc1Swenshuai.xi return iRetval;
2356*53ee8cc1Swenshuai.xi
2357*53ee8cc1Swenshuai.xi u32HccParams = hcd_reg_readl ((U32)&ehci->cap_regs->hcc_params);
2358*53ee8cc1Swenshuai.xi if (HCC_ISO_CACHE (u32HccParams)) // full frame cache
2359*53ee8cc1Swenshuai.xi ehci->u32IThresh = 8;
2360*53ee8cc1Swenshuai.xi else // N microframes cached
2361*53ee8cc1Swenshuai.xi ehci->u32IThresh = 2 + HCC_ISO_THRES (u32HccParams);
2362*53ee8cc1Swenshuai.xi
2363*53ee8cc1Swenshuai.xi ehci->stReclaim = 0;
2364*53ee8cc1Swenshuai.xi ehci->iNextUframe = -1;
2365*53ee8cc1Swenshuai.xi
2366*53ee8cc1Swenshuai.xi if ((iRetval = ms_ehci_reset (ehci)) != 0)
2367*53ee8cc1Swenshuai.xi {
2368*53ee8cc1Swenshuai.xi ms_ehci_mem_cleanup (ehci);
2369*53ee8cc1Swenshuai.xi return iRetval;
2370*53ee8cc1Swenshuai.xi }
2371*53ee8cc1Swenshuai.xi
2372*53ee8cc1Swenshuai.xi hcd_reg_writel (INTR_MASK, (U32)&ehci->op_regs->usbintr);
2373*53ee8cc1Swenshuai.xi u32Temp=hcd_reg_readl((U32)&ehci->op_regs->bus_control);
2374*53ee8cc1Swenshuai.xi // temp|=INT_POLAR+HALF_SPEED;
2375*53ee8cc1Swenshuai.xi u32Temp|=INT_POLAR;
2376*53ee8cc1Swenshuai.xi u32Temp&=~VBUS_OFF;
2377*53ee8cc1Swenshuai.xi hcd_reg_writel(u32Temp,(U32)&ehci->op_regs->bus_control); //set intr high active
2378*53ee8cc1Swenshuai.xi hcd_reg_writel (ehci->tPeriodicDma, (U32)&ehci->op_regs->periodiclistbase);
2379*53ee8cc1Swenshuai.xi
2380*53ee8cc1Swenshuai.xi ehci->stAsync->qh_next.qh = 0;
2381*53ee8cc1Swenshuai.xi ehci->stAsync->hw_next_qh = QH_NEXT (ehci->stAsync->qh_dma_addr);
2382*53ee8cc1Swenshuai.xi ehci->stAsync->hw_ep_state1 = QH_H_BIT;
2383*53ee8cc1Swenshuai.xi ehci->stAsync->hw_token = QTD_STS_HALT;
2384*53ee8cc1Swenshuai.xi ehci->stAsync->hw_next_qtd = EHCI_LIST_END;
2385*53ee8cc1Swenshuai.xi ehci->stAsync->qh_status = QH_STS_LINKED;
2386*53ee8cc1Swenshuai.xi ehci->stAsync->hw_alt_next_qtd = (U32)(ehci->stAsync->pDummyQtd->qtd_dma_addr);
2387*53ee8cc1Swenshuai.xi ms_debug_msg("qh dma addr: %p\n", (void *)ehci->stAsync->qh_dma_addr);
2388*53ee8cc1Swenshuai.xi hcd_reg_writel ((U32)ehci->stAsync->qh_dma_addr, (U32)&ehci->op_regs->asynclistaddr);
2389*53ee8cc1Swenshuai.xi
2390*53ee8cc1Swenshuai.xi if (HCC_64BIT_ADDR_CAP (u32HccParams))
2391*53ee8cc1Swenshuai.xi {
2392*53ee8cc1Swenshuai.xi hcd_reg_writel (0, (U32)&ehci->op_regs->ctrldssegment);
2393*53ee8cc1Swenshuai.xi }
2394*53ee8cc1Swenshuai.xi
2395*53ee8cc1Swenshuai.xi u32Temp = hcd_reg_readl ((U32)&ehci->op_regs->usbcmd) & 0x0fff;
2396*53ee8cc1Swenshuai.xi if (log2_irq_thresh < 0 || log2_irq_thresh > 6)
2397*53ee8cc1Swenshuai.xi log2_irq_thresh = 0;
2398*53ee8cc1Swenshuai.xi u32Temp |= 1 << (16 + log2_irq_thresh);
2399*53ee8cc1Swenshuai.xi
2400*53ee8cc1Swenshuai.xi #if defined(CHIP_K2)
2401*53ee8cc1Swenshuai.xi // K2 U02 & Newer IC
2402*53ee8cc1Swenshuai.xi if (MDrv_SYS_GetChipRev() >= 0x01)
2403*53ee8cc1Swenshuai.xi {
2404*53ee8cc1Swenshuai.xi park_eco = 3;
2405*53ee8cc1Swenshuai.xi }
2406*53ee8cc1Swenshuai.xi #endif
2407*53ee8cc1Swenshuai.xi
2408*53ee8cc1Swenshuai.xi if (park_eco && HCC_ASPC(u32HccParams))
2409*53ee8cc1Swenshuai.xi {
2410*53ee8cc1Swenshuai.xi ms_debug_msg("[EHCI] Enable Park Mode: %d\n", (int)park_eco);
2411*53ee8cc1Swenshuai.xi u32Temp |= USBCMD_PARK;
2412*53ee8cc1Swenshuai.xi u32Temp |= park_eco << 8;
2413*53ee8cc1Swenshuai.xi }
2414*53ee8cc1Swenshuai.xi
2415*53ee8cc1Swenshuai.xi if (HCC_PFLF (u32HccParams))
2416*53ee8cc1Swenshuai.xi {
2417*53ee8cc1Swenshuai.xi u32Temp &= ~(3 << 2);
2418*53ee8cc1Swenshuai.xi u32Temp |= (EHCI_PERIODIC_FLS << 2);
2419*53ee8cc1Swenshuai.xi switch (EHCI_PERIODIC_FLS)
2420*53ee8cc1Swenshuai.xi {
2421*53ee8cc1Swenshuai.xi case 0: ehci->u32PeriodicSize = 1024; break;
2422*53ee8cc1Swenshuai.xi case 1: ehci->u32PeriodicSize = 512; break;
2423*53ee8cc1Swenshuai.xi case 2: ehci->u32PeriodicSize = 256; break;
2424*53ee8cc1Swenshuai.xi default: USB_ASSERT(0, "Not alllowed periodic frame list size\n");
2425*53ee8cc1Swenshuai.xi }
2426*53ee8cc1Swenshuai.xi }
2427*53ee8cc1Swenshuai.xi u32Temp &= ~(USBCMD_IAAD | USBCMD_ASE | USBCMD_PSE),
2428*53ee8cc1Swenshuai.xi
2429*53ee8cc1Swenshuai.xi // Only make HC run when device connects to bus
2430*53ee8cc1Swenshuai.xi u32Temp |= USBCMD_RUN;
2431*53ee8cc1Swenshuai.xi hcd_reg_writel (u32Temp, (U32)&ehci->op_regs->usbcmd);
2432*53ee8cc1Swenshuai.xi
2433*53ee8cc1Swenshuai.xi /* initialize watchdog timer function */
2434*53ee8cc1Swenshuai.xi
2435*53ee8cc1Swenshuai.xi ms_init_timer (&ehci->stWatchdog);
2436*53ee8cc1Swenshuai.xi ehci->stWatchdog.function = ms_ehci_watchdog;
2437*53ee8cc1Swenshuai.xi ehci->stWatchdog.data = (U32) ehci;
2438*53ee8cc1Swenshuai.xi
2439*53ee8cc1Swenshuai.xi ms_init_timer (&ehci->stiaa_Watchdog);
2440*53ee8cc1Swenshuai.xi ehci->stiaa_Watchdog.function = ms_ehci_iaa_watchdog;
2441*53ee8cc1Swenshuai.xi ehci->stiaa_Watchdog.data = (U32) ehci;
2442*53ee8cc1Swenshuai.xi
2443*53ee8cc1Swenshuai.xi pBus = (struct usb_bus *)(&hcd->self);
2444*53ee8cc1Swenshuai.xi pBus->root_hub = pUdev = ms_usb_alloc_dev (NULL, pBus);
2445*53ee8cc1Swenshuai.xi if (!pUdev)
2446*53ee8cc1Swenshuai.xi {
2447*53ee8cc1Swenshuai.xi done2:
2448*53ee8cc1Swenshuai.xi ms_ehci_mem_cleanup (ehci);
2449*53ee8cc1Swenshuai.xi ms_debug_func("--[%s] line:[%d]\n", __FUNCTION__, __LINE__);
2450*53ee8cc1Swenshuai.xi return -ENOMEM;
2451*53ee8cc1Swenshuai.xi }
2452*53ee8cc1Swenshuai.xi
2453*53ee8cc1Swenshuai.xi ehci->hcd.state = HCD_STATE_RUNNING;
2454*53ee8cc1Swenshuai.xi u32Temp = hcd_reg_readl ((U32)&ehci->op_regs->usbcmd); /* unblock posted write */
2455*53ee8cc1Swenshuai.xi
2456*53ee8cc1Swenshuai.xi u32Temp = hcd_reg_readw ((U32)&ehci->cap_regs->hciversion);
2457*53ee8cc1Swenshuai.xi ms_debug_msg ("EHCI %x.%02x, driver %s\n",
2458*53ee8cc1Swenshuai.xi (unsigned int)u32Temp >> 8, (unsigned int)u32Temp & 0xff, DRIVER_VERSION);
2459*53ee8cc1Swenshuai.xi
2460*53ee8cc1Swenshuai.xi pUdev->eSpeed = USB_HIGH_SPEED;
2461*53ee8cc1Swenshuai.xi if (ms_register_root_hub(hcd) != 0)
2462*53ee8cc1Swenshuai.xi {
2463*53ee8cc1Swenshuai.xi if (hcd->state == HCD_STATE_RUNNING)
2464*53ee8cc1Swenshuai.xi ms_ehci_quiesce(ehci);
2465*53ee8cc1Swenshuai.xi ms_ehci_reset (ehci);
2466*53ee8cc1Swenshuai.xi pBus->root_hub = 0;
2467*53ee8cc1Swenshuai.xi ms_usb_put_dev (pUdev);
2468*53ee8cc1Swenshuai.xi iRetval = -ENODEV;
2469*53ee8cc1Swenshuai.xi goto done2;
2470*53ee8cc1Swenshuai.xi }
2471*53ee8cc1Swenshuai.xi
2472*53ee8cc1Swenshuai.xi ms_debug_func("--[%s] line:[%d]\n", __FUNCTION__, __LINE__);
2473*53ee8cc1Swenshuai.xi return 0;
2474*53ee8cc1Swenshuai.xi }
2475*53ee8cc1Swenshuai.xi
2476*53ee8cc1Swenshuai.xi /*
2477*53ee8cc1Swenshuai.xi * @brief stop ehci controller
2478*53ee8cc1Swenshuai.xi *
2479*53ee8cc1Swenshuai.xi * @param struct usb_hcd *hcd
2480*53ee8cc1Swenshuai.xi *
2481*53ee8cc1Swenshuai.xi * @return none
2482*53ee8cc1Swenshuai.xi */
2483*53ee8cc1Swenshuai.xi
ms_ehci_end(struct usb_hcd * hcd)2484*53ee8cc1Swenshuai.xi void ms_ehci_end (struct usb_hcd *hcd)
2485*53ee8cc1Swenshuai.xi {
2486*53ee8cc1Swenshuai.xi struct ehci_hcd *ehci = hcd_to_ehci (hcd);
2487*53ee8cc1Swenshuai.xi
2488*53ee8cc1Swenshuai.xi ms_debug_func("[%s] line:[%d]\n", __FUNCTION__, __LINE__);
2489*53ee8cc1Swenshuai.xi
2490*53ee8cc1Swenshuai.xi ms_del_timer_sync (&ehci->stWatchdog);
2491*53ee8cc1Swenshuai.xi ms_del_timer_sync (&ehci->stiaa_Watchdog);
2492*53ee8cc1Swenshuai.xi
2493*53ee8cc1Swenshuai.xi osapi_spin_lock_irq (&ehci->tHcdLock);
2494*53ee8cc1Swenshuai.xi if (hcd->state == HCD_STATE_RUNNING)
2495*53ee8cc1Swenshuai.xi ms_ehci_quiesce(ehci);
2496*53ee8cc1Swenshuai.xi // need to turn off all ports?
2497*53ee8cc1Swenshuai.xi ms_ehci_reset (ehci);
2498*53ee8cc1Swenshuai.xi //osapi_spin_unlock_irq (&ehci->tHcdLock);
2499*53ee8cc1Swenshuai.xi
2500*53ee8cc1Swenshuai.xi //osapi_spin_lock_irq (&ehci->tHcdLock);
2501*53ee8cc1Swenshuai.xi if (ehci->stAsync) // patch from Linux 3.1.10
2502*53ee8cc1Swenshuai.xi ms_ehci_work(ehci, NULL);
2503*53ee8cc1Swenshuai.xi osapi_spin_unlock_irq (&ehci->tHcdLock);
2504*53ee8cc1Swenshuai.xi ms_ehci_mem_cleanup (ehci);
2505*53ee8cc1Swenshuai.xi
2506*53ee8cc1Swenshuai.xi #ifdef EHCI_STATS
2507*53ee8cc1Swenshuai.xi ms_debug_msg ("[EHCI DEBUG] irq normal %ld err %ld reclaim %ld (lost %ld) ",
2508*53ee8cc1Swenshuai.xi ehci->stats.u32Normal, ehci->stats.u32Error, ehci->stats.u32Reclaim,
2509*53ee8cc1Swenshuai.xi ehci->stats.u32LostIAA);
2510*53ee8cc1Swenshuai.xi ms_debug_msg ("complete %ld unlink %ld\n",
2511*53ee8cc1Swenshuai.xi ehci->stats.u32Complete, ehci->stats.u32Unlink);
2512*53ee8cc1Swenshuai.xi #endif
2513*53ee8cc1Swenshuai.xi
2514*53ee8cc1Swenshuai.xi }
2515*53ee8cc1Swenshuai.xi
ms_ehci_get_frame_idx(struct usb_hcd * hcd)2516*53ee8cc1Swenshuai.xi int ms_ehci_get_frame_idx (struct usb_hcd *hcd)
2517*53ee8cc1Swenshuai.xi {
2518*53ee8cc1Swenshuai.xi struct ehci_hcd *ehci = hcd_to_ehci (hcd);
2519*53ee8cc1Swenshuai.xi ms_debug_func("[%s] line:[%d]\n", __FUNCTION__, __LINE__);
2520*53ee8cc1Swenshuai.xi return (hcd_reg_readl ((U32)&ehci->op_regs->frindex) >> 3) % ehci->u32PeriodicSize;
2521*53ee8cc1Swenshuai.xi }
2522*53ee8cc1Swenshuai.xi
2523*53ee8cc1Swenshuai.xi /*-------------------------------------------------------------------------*/
2524*53ee8cc1Swenshuai.xi
ms_ehci_suspend(struct usb_hcd * hcd,U32 state)2525*53ee8cc1Swenshuai.xi int ms_ehci_suspend (struct usb_hcd *hcd, U32 state)
2526*53ee8cc1Swenshuai.xi {
2527*53ee8cc1Swenshuai.xi struct ehci_hcd *ehci = hcd_to_ehci (hcd);
2528*53ee8cc1Swenshuai.xi int iPorts;
2529*53ee8cc1Swenshuai.xi int i;
2530*53ee8cc1Swenshuai.xi
2531*53ee8cc1Swenshuai.xi ms_debug_func("++[%s] line:[%d]\n", __FUNCTION__, __LINE__);
2532*53ee8cc1Swenshuai.xi
2533*53ee8cc1Swenshuai.xi iPorts = HCS_N_PORTS (ehci->hcs_params);
2534*53ee8cc1Swenshuai.xi
2535*53ee8cc1Swenshuai.xi if (hcd->state == HCD_STATE_RUNNING)
2536*53ee8cc1Swenshuai.xi ms_ehci_quiesce(ehci);
2537*53ee8cc1Swenshuai.xi ms_debug_msg("ms_ehci_suspend\n");
2538*53ee8cc1Swenshuai.xi hcd_reg_writel(hcd_reg_readl ((U32)&ehci->op_regs->usbcmd) & ~USBCMD_RUN, (U32)&ehci->op_regs->usbcmd);
2539*53ee8cc1Swenshuai.xi while((hcd_reg_readl((U32)&ehci->op_regs->usbsts)&USBSTS_HALT) == 0);
2540*53ee8cc1Swenshuai.xi
2541*53ee8cc1Swenshuai.xi /* suspend each port, then stop the hc */
2542*53ee8cc1Swenshuai.xi for (i = 0; i < iPorts; i++) {
2543*53ee8cc1Swenshuai.xi int temp = hcd_reg_readl ((U32)&ehci->op_regs->portsc [i]);
2544*53ee8cc1Swenshuai.xi if ((temp & PORTSC_PE) == 0
2545*53ee8cc1Swenshuai.xi /* || (temp & PORTSC_OWNER) != 0 */)
2546*53ee8cc1Swenshuai.xi continue;
2547*53ee8cc1Swenshuai.xi ms_debug_msg ("suspend port %d", i);
2548*53ee8cc1Swenshuai.xi temp |= PORTSC_SUSPEND;
2549*53ee8cc1Swenshuai.xi hcd_reg_writel (temp, (U32)&ehci->op_regs->portsc [i]);
2550*53ee8cc1Swenshuai.xi }
2551*53ee8cc1Swenshuai.xi ms_debug_func("--[%s] line:[%d]\n", __FUNCTION__, __LINE__);
2552*53ee8cc1Swenshuai.xi return 0;
2553*53ee8cc1Swenshuai.xi }
2554*53ee8cc1Swenshuai.xi
ms_ehci_resume(struct usb_hcd * hcd)2555*53ee8cc1Swenshuai.xi int ms_ehci_resume (struct usb_hcd *hcd)
2556*53ee8cc1Swenshuai.xi {
2557*53ee8cc1Swenshuai.xi struct ehci_hcd *ehci = hcd_to_ehci (hcd);
2558*53ee8cc1Swenshuai.xi int iPorts;
2559*53ee8cc1Swenshuai.xi int i;
2560*53ee8cc1Swenshuai.xi //U32 U32Tmp;
2561*53ee8cc1Swenshuai.xi
2562*53ee8cc1Swenshuai.xi ms_debug_func("++[%s] line:[%d]\n", __FUNCTION__, __LINE__);
2563*53ee8cc1Swenshuai.xi
2564*53ee8cc1Swenshuai.xi iPorts = HCS_N_PORTS (ehci->hcs_params);
2565*53ee8cc1Swenshuai.xi hcd->state = HCD_STATE_RUNNING;
2566*53ee8cc1Swenshuai.xi for (i = 0; i < iPorts; i++)
2567*53ee8cc1Swenshuai.xi {
2568*53ee8cc1Swenshuai.xi int temp = hcd_reg_readl ((U32)&ehci->op_regs->portsc [i]);
2569*53ee8cc1Swenshuai.xi if ((temp & PORTSC_PE) == 0
2570*53ee8cc1Swenshuai.xi || (temp & PORTSC_SUSPEND) != 0)
2571*53ee8cc1Swenshuai.xi continue;
2572*53ee8cc1Swenshuai.xi ms_debug_msg ("resume port %d", i);
2573*53ee8cc1Swenshuai.xi temp |= PORTSC_SUSPEND;
2574*53ee8cc1Swenshuai.xi hcd_reg_writel (temp, (U32)&ehci->op_regs->portsc [i]);
2575*53ee8cc1Swenshuai.xi /*U32Tmp = */hcd_reg_readl ((U32)&ehci->op_regs->usbcmd); /* unblock posted writes */
2576*53ee8cc1Swenshuai.xi wait_ms (20);
2577*53ee8cc1Swenshuai.xi temp &= ~PORTSC_SUSPEND;
2578*53ee8cc1Swenshuai.xi hcd_reg_writel (temp, (U32)&ehci->op_regs->portsc [i]);
2579*53ee8cc1Swenshuai.xi }
2580*53ee8cc1Swenshuai.xi /*U32Tmp = */hcd_reg_readl ((U32)&ehci->op_regs->usbcmd); /* unblock posted writes */
2581*53ee8cc1Swenshuai.xi ms_debug_func("--[%s] line:[%d]\n", __FUNCTION__, __LINE__);
2582*53ee8cc1Swenshuai.xi return 0;
2583*53ee8cc1Swenshuai.xi }
2584*53ee8cc1Swenshuai.xi
2585*53ee8cc1Swenshuai.xi /*-------------------------------------------------------------------------*/
2586*53ee8cc1Swenshuai.xi /*
2587*53ee8cc1Swenshuai.xi * @brief scan asynchronous qh chain and periodic frame list
2588*53ee8cc1Swenshuai.xi *
2589*53ee8cc1Swenshuai.xi * @param struct ehci_hcd *pEhci
2590*53ee8cc1Swenshuai.xi * @param struct stPtRegs *regs
2591*53ee8cc1Swenshuai.xi *
2592*53ee8cc1Swenshuai.xi * @return none
2593*53ee8cc1Swenshuai.xi */
ms_ehci_work(struct ehci_hcd * pEhci,struct stPtRegs * regs)2594*53ee8cc1Swenshuai.xi static void ms_ehci_work(struct ehci_hcd *pEhci, struct stPtRegs *regs)
2595*53ee8cc1Swenshuai.xi {
2596*53ee8cc1Swenshuai.xi ms_debug_func("++[%s] line:[%d]\n", __FUNCTION__, __LINE__);
2597*53ee8cc1Swenshuai.xi ms_timer_action_done (pEhci, TIMER_IO_WATCHDOG);
2598*53ee8cc1Swenshuai.xi Chip_Read_Memory(); // 20121218, 20121225
2599*53ee8cc1Swenshuai.xi
2600*53ee8cc1Swenshuai.xi #if 0 // old reclaim flow
2601*53ee8cc1Swenshuai.xi // This sequence will release Host task befor USB DSR complete.
2602*53ee8cc1Swenshuai.xi if (pEhci->iReclaimReady)
2603*53ee8cc1Swenshuai.xi {
2604*53ee8cc1Swenshuai.xi ms_end_unlink_async (pEhci, regs);
2605*53ee8cc1Swenshuai.xi ms_scan_async (pEhci, regs);
2606*53ee8cc1Swenshuai.xi //ms_end_unlink_async (pEhci, regs); // move 2 lines ahead for IAA issue. 20140408
2607*53ee8cc1Swenshuai.xi }
2608*53ee8cc1Swenshuai.xi #endif
2609*53ee8cc1Swenshuai.xi
2610*53ee8cc1Swenshuai.xi if (pEhci->iScanning)
2611*53ee8cc1Swenshuai.xi return;
2612*53ee8cc1Swenshuai.xi pEhci->iScanning = 1;
2613*53ee8cc1Swenshuai.xi ms_scan_async (pEhci, regs);
2614*53ee8cc1Swenshuai.xi if (pEhci->iNextUframe != -1)
2615*53ee8cc1Swenshuai.xi ms_scan_periodic (pEhci, regs);
2616*53ee8cc1Swenshuai.xi pEhci->iScanning = 0;
2617*53ee8cc1Swenshuai.xi
2618*53ee8cc1Swenshuai.xi if (HCD_IS_RUNNING(pEhci->hcd.state) &&
2619*53ee8cc1Swenshuai.xi ((pEhci->stAsync->qh_next.ptr != 0) || (pEhci->u32PeriodicSched != 0)))
2620*53ee8cc1Swenshuai.xi ms_timer_action (pEhci, TIMER_IO_WATCHDOG);
2621*53ee8cc1Swenshuai.xi ms_debug_func("--[%s] line:[%d]\n", __FUNCTION__, __LINE__);
2622*53ee8cc1Swenshuai.xi }
2623*53ee8cc1Swenshuai.xi
2624*53ee8cc1Swenshuai.xi /*-------------------------------------------------------------------------*/
2625*53ee8cc1Swenshuai.xi /*
2626*53ee8cc1Swenshuai.xi * @brief process ehci controller interrupt events
2627*53ee8cc1Swenshuai.xi *
2628*53ee8cc1Swenshuai.xi * @param struct usb_hcd *pHcd
2629*53ee8cc1Swenshuai.xi * @param struct stPtRegs *pRegs
2630*53ee8cc1Swenshuai.xi *
2631*53ee8cc1Swenshuai.xi * @return none
2632*53ee8cc1Swenshuai.xi */
ms_ehci_irq(struct usb_hcd * pHcd,struct stPtRegs * pRegs)2633*53ee8cc1Swenshuai.xi void ms_ehci_irq (struct usb_hcd *pHcd, struct stPtRegs *pRegs)
2634*53ee8cc1Swenshuai.xi {
2635*53ee8cc1Swenshuai.xi struct ehci_hcd *pEhci= hcd_to_ehci (pHcd);
2636*53ee8cc1Swenshuai.xi U32 u32Status, int_status;
2637*53ee8cc1Swenshuai.xi int bh;
2638*53ee8cc1Swenshuai.xi U32 u32Cmd;
2639*53ee8cc1Swenshuai.xi
2640*53ee8cc1Swenshuai.xi osapi_spin_lock (&pEhci->tHcdLock);
2641*53ee8cc1Swenshuai.xi
2642*53ee8cc1Swenshuai.xi int_status = u32Status = hcd_reg_readl ((U32)&pEhci->op_regs->usbsts);
2643*53ee8cc1Swenshuai.xi
2644*53ee8cc1Swenshuai.xi if (u32Status == ~(U32) 0)
2645*53ee8cc1Swenshuai.xi {
2646*53ee8cc1Swenshuai.xi ms_debug_msg ("reg usbsts is 0xffff, device removed\n");
2647*53ee8cc1Swenshuai.xi goto dead;
2648*53ee8cc1Swenshuai.xi }
2649*53ee8cc1Swenshuai.xi
2650*53ee8cc1Swenshuai.xi u32Status &= INTR_MASK;
2651*53ee8cc1Swenshuai.xi if (!u32Status) /* No any our interrupt event */
2652*53ee8cc1Swenshuai.xi {
2653*53ee8cc1Swenshuai.xi diag_printf("ms_ehci_irq status: %x, intr_enable: %x\n", (unsigned int)int_status, hcd_reg_readw((U32)&pEhci->op_regs->usbintr));
2654*53ee8cc1Swenshuai.xi goto done;
2655*53ee8cc1Swenshuai.xi }
2656*53ee8cc1Swenshuai.xi
2657*53ee8cc1Swenshuai.xi hcd_reg_writel (u32Status, (U32)&pEhci->op_regs->usbsts);
2658*53ee8cc1Swenshuai.xi u32Cmd = hcd_reg_readl ((U32)&pEhci->op_regs->usbcmd);
2659*53ee8cc1Swenshuai.xi bh = 0;
2660*53ee8cc1Swenshuai.xi //pEhci->uDontSendIAA = 0;
2661*53ee8cc1Swenshuai.xi
2662*53ee8cc1Swenshuai.xi /* Notify controller for advance async schedule */
2663*53ee8cc1Swenshuai.xi /* USBSTS_INT for normal completion, see 4.15.1.2
2664*53ee8cc1Swenshuai.xi USBSTS_ERR for error completion, see 4.15.1.1 */
2665*53ee8cc1Swenshuai.xi if ((u32Status & (USBSTS_INT|USBSTS_ERR)) != 0)
2666*53ee8cc1Swenshuai.xi {
2667*53ee8cc1Swenshuai.xi #if 0 // old reclaim flow
2668*53ee8cc1Swenshuai.xi // Enable the interrupt for Async Advance Enable
2669*53ee8cc1Swenshuai.xi pEhci->iReclaimReady = 0;
2670*53ee8cc1Swenshuai.xi int cmd = hcd_reg_readl ((U32)&pEhci->op_regs->usbcmd);
2671*53ee8cc1Swenshuai.xi cmd |= USBCMD_IAAD;
2672*53ee8cc1Swenshuai.xi hcd_reg_writel (cmd, (U32)&pEhci->op_regs->usbcmd);
2673*53ee8cc1Swenshuai.xi (void) hcd_reg_readl ((U32)&pEhci->op_regs->usbcmd);
2674*53ee8cc1Swenshuai.xi //pEhci->uDontSendIAA = 1;
2675*53ee8cc1Swenshuai.xi #endif
2676*53ee8cc1Swenshuai.xi if ((u32Status & USBSTS_ERR) == 0)
2677*53ee8cc1Swenshuai.xi {
2678*53ee8cc1Swenshuai.xi INCREASE(pEhci->stats.u32Normal);
2679*53ee8cc1Swenshuai.xi }
2680*53ee8cc1Swenshuai.xi else
2681*53ee8cc1Swenshuai.xi {
2682*53ee8cc1Swenshuai.xi INCREASE(pEhci->stats.u32Error);
2683*53ee8cc1Swenshuai.xi //bh = 1; //Note, remove for command stall
2684*53ee8cc1Swenshuai.xi }
2685*53ee8cc1Swenshuai.xi bh = 1;
2686*53ee8cc1Swenshuai.xi }
2687*53ee8cc1Swenshuai.xi
2688*53ee8cc1Swenshuai.xi /* IAA is used for complete the unlinking of qh */
2689*53ee8cc1Swenshuai.xi if (u32Status & USBSTS_IAA)
2690*53ee8cc1Swenshuai.xi {
2691*53ee8cc1Swenshuai.xi #if 0 // old reclaim flow
2692*53ee8cc1Swenshuai.xi INCREASE(pEhci->stats.u32Reclaim);
2693*53ee8cc1Swenshuai.xi pEhci->iReclaimReady = 1;
2694*53ee8cc1Swenshuai.xi //pEhci->uDontSendIAA = 1;
2695*53ee8cc1Swenshuai.xi bh = 1;
2696*53ee8cc1Swenshuai.xi #endif
2697*53ee8cc1Swenshuai.xi if (u32Cmd & USBCMD_IAAD)
2698*53ee8cc1Swenshuai.xi {
2699*53ee8cc1Swenshuai.xi hcd_reg_writel (u32Cmd & ~USBCMD_IAAD, (U32)&pEhci->op_regs->usbcmd);
2700*53ee8cc1Swenshuai.xi ms_debug_err("[EHCI] IAAD not clear?\n");
2701*53ee8cc1Swenshuai.xi }
2702*53ee8cc1Swenshuai.xi if (pEhci->stReclaim)
2703*53ee8cc1Swenshuai.xi {
2704*53ee8cc1Swenshuai.xi INCREASE(pEhci->stats.u32Reclaim);
2705*53ee8cc1Swenshuai.xi ms_end_unlink_async(pEhci, pRegs);
2706*53ee8cc1Swenshuai.xi }
2707*53ee8cc1Swenshuai.xi else
2708*53ee8cc1Swenshuai.xi ms_debug_err("reclaim but with nothing there!\n");
2709*53ee8cc1Swenshuai.xi }
2710*53ee8cc1Swenshuai.xi
2711*53ee8cc1Swenshuai.xi /* See [4.3.1] */
2712*53ee8cc1Swenshuai.xi if (u32Status & USBSTS_PCD)
2713*53ee8cc1Swenshuai.xi {
2714*53ee8cc1Swenshuai.xi // Only support one port
2715*53ee8cc1Swenshuai.xi int iPsc/*, masked_psc*/;
2716*53ee8cc1Swenshuai.xi int isHalt = 0;
2717*53ee8cc1Swenshuai.xi
2718*53ee8cc1Swenshuai.xi iPsc = hcd_reg_readl((U32)&pEhci->op_regs->portsc [0]);
2719*53ee8cc1Swenshuai.xi
2720*53ee8cc1Swenshuai.xi /* new patch, root hub not run */
2721*53ee8cc1Swenshuai.xi if (iPsc == pHcd->saved_ehci_state.iPsc &&
2722*53ee8cc1Swenshuai.xi pEhci->u32ResetEnd[0] == pHcd->saved_ehci_state.reset_done &&
2723*53ee8cc1Swenshuai.xi u32Cmd == pHcd->saved_ehci_state.usbcmd &&
2724*53ee8cc1Swenshuai.xi (u32Cmd & USBCMD_RUN) == 0)
2725*53ee8cc1Swenshuai.xi {
2726*53ee8cc1Swenshuai.xi ++pEhci->ehci_port_not_change_cnt;
2727*53ee8cc1Swenshuai.xi if (pEhci->ehci_port_not_change_cnt > 7)
2728*53ee8cc1Swenshuai.xi isHalt = 1;
2729*53ee8cc1Swenshuai.xi }
2730*53ee8cc1Swenshuai.xi else
2731*53ee8cc1Swenshuai.xi pEhci->ehci_port_not_change_cnt = 0;
2732*53ee8cc1Swenshuai.xi pHcd->saved_ehci_state.iPsc = iPsc;
2733*53ee8cc1Swenshuai.xi pHcd->saved_ehci_state.reset_done = pEhci->u32ResetEnd[0];
2734*53ee8cc1Swenshuai.xi pHcd->saved_ehci_state.usbcmd = u32Cmd;
2735*53ee8cc1Swenshuai.xi if (isHalt)
2736*53ee8cc1Swenshuai.xi {
2737*53ee8cc1Swenshuai.xi diag_printf("[EHCI] PCD not clear, reset UHC to get new CURRENT usbsts\n");
2738*53ee8cc1Swenshuai.xi if(iPsc & PORTSC_CSC)
2739*53ee8cc1Swenshuai.xi {
2740*53ee8cc1Swenshuai.xi diag_printf("[EHCI] set more CSC\n");
2741*53ee8cc1Swenshuai.xi pEhci->u32MoreCSC = true;
2742*53ee8cc1Swenshuai.xi }
2743*53ee8cc1Swenshuai.xi ms_ehci_softrst(pEhci);
2744*53ee8cc1Swenshuai.xi goto done;
2745*53ee8cc1Swenshuai.xi }
2746*53ee8cc1Swenshuai.xi
2747*53ee8cc1Swenshuai.xi // root hub not run
2748*53ee8cc1Swenshuai.xi #if 0 // NUSED
2749*53ee8cc1Swenshuai.xi if ((u32Cmd & USBCMD_RUN) == 0)
2750*53ee8cc1Swenshuai.xi {
2751*53ee8cc1Swenshuai.xi //u32Cmd |= USBCMD_RUN;
2752*53ee8cc1Swenshuai.xi //hcd_reg_writel(u32Cmd, (U32)&pEhci->op_regs->usbcmd);
2753*53ee8cc1Swenshuai.xi //while(hcd_reg_readw ((U32)&pEhci->op_regs->usbsts) & USBSTS_HALT);
2754*53ee8cc1Swenshuai.xi isHalt = 1;
2755*53ee8cc1Swenshuai.xi //hcd_reg_writel (u32Status, (U32)&pEhci->op_regs->usbsts);
2756*53ee8cc1Swenshuai.xi //diag_printf("clear USBSTS_PCD (0x%x) again\n", hcd_reg_readw ((U32)&pEhci->op_regs->usbsts));
2757*53ee8cc1Swenshuai.xi }
2758*53ee8cc1Swenshuai.xi
2759*53ee8cc1Swenshuai.xi masked_psc = iPsc & 0xf;
2760*53ee8cc1Swenshuai.xi //if ((masked_psc == 0xa /*|| masked_psc == 0xf */) && pEhci->u32ResetEnd[0] == 0)
2761*53ee8cc1Swenshuai.xi if ((masked_psc == 0xb))
2762*53ee8cc1Swenshuai.xi {
2763*53ee8cc1Swenshuai.xi if (isHalt)
2764*53ee8cc1Swenshuai.xi {
2765*53ee8cc1Swenshuai.xi //ms_ehci_softrst(pEhci);
2766*53ee8cc1Swenshuai.xi //diag_printf("PCD not clear, reset UHC to get new CURRENT usbsts = 0x%x\n", hcd_reg_readl ((U32)&pEhci->op_regs->usbsts));
2767*53ee8cc1Swenshuai.xi }
2768*53ee8cc1Swenshuai.xi }
2769*53ee8cc1Swenshuai.xi #endif
2770*53ee8cc1Swenshuai.xi
2771*53ee8cc1Swenshuai.xi /* Clear port enable bit when root device disconnect */
2772*53ee8cc1Swenshuai.xi /* Patch for hub+device hot plug frequency then lost disconnect event */
2773*53ee8cc1Swenshuai.xi if ((iPsc & PORTSC_CSC) && (iPsc & PORTSC_CONNECT)==0)
2774*53ee8cc1Swenshuai.xi {
2775*53ee8cc1Swenshuai.xi iPsc &= ~(PORTSC_PEC | PORTSC_PE | PORTSC_CSC);
2776*53ee8cc1Swenshuai.xi hcd_reg_writel(iPsc, (U32)&pEhci->op_regs->portsc[0]);
2777*53ee8cc1Swenshuai.xi //diag_printf("<irq> clear PORTSC_PE\n");
2778*53ee8cc1Swenshuai.xi }
2779*53ee8cc1Swenshuai.xi #if 0 // un-patch since not to support suspend
2780*53ee8cc1Swenshuai.xi if ((((iPsc & PORTSC_RESUME) ||
2781*53ee8cc1Swenshuai.xi !(iPsc & PORTSC_SUSPEND)) &&
2782*53ee8cc1Swenshuai.xi (iPsc & PORTSC_PE) &&
2783*53ee8cc1Swenshuai.xi pEhci->u32ResetEnd[0] == 0))
2784*53ee8cc1Swenshuai.xi {
2785*53ee8cc1Swenshuai.xi /* The root hub port active 20 msec resume signal,
2786*53ee8cc1Swenshuai.xi * PORTSC_SUSPEND to stop resume signal.
2787*53ee8cc1Swenshuai.xi */
2788*53ee8cc1Swenshuai.xi pEhci->u32ResetEnd [0] = jiffies + ((20 /* msec */ * HZ) / 1000);
2789*53ee8cc1Swenshuai.xi ms_debug_msg ("port 1 remote wakeup\n");
2790*53ee8cc1Swenshuai.xi ms_update_timer(&pHcd->roothub_timer, pEhci->u32ResetEnd[0], 0);
2791*53ee8cc1Swenshuai.xi }
2792*53ee8cc1Swenshuai.xi #endif
2793*53ee8cc1Swenshuai.xi }
2794*53ee8cc1Swenshuai.xi
2795*53ee8cc1Swenshuai.xi
2796*53ee8cc1Swenshuai.xi /* See [4.15.2.4] */
2797*53ee8cc1Swenshuai.xi
2798*53ee8cc1Swenshuai.xi if ((u32Status & USBSTS_FATAL) != 0)
2799*53ee8cc1Swenshuai.xi {
2800*53ee8cc1Swenshuai.xi ms_debug_err ("[EHCI] fatal error\n");
2801*53ee8cc1Swenshuai.xi dead:
2802*53ee8cc1Swenshuai.xi //ms_ehci_reset (pEhci);
2803*53ee8cc1Swenshuai.xi ms_ehci_softrst(pEhci);
2804*53ee8cc1Swenshuai.xi /* uses ms_ehci_end to clean up the rest */
2805*53ee8cc1Swenshuai.xi bh = 1;
2806*53ee8cc1Swenshuai.xi }
2807*53ee8cc1Swenshuai.xi
2808*53ee8cc1Swenshuai.xi if (bh ||
2809*53ee8cc1Swenshuai.xi (pEhci->u32PeriodicSched != 0) //If we has periodic transactions in Schedule, we must scan periodic when USBSTS_INT
2810*53ee8cc1Swenshuai.xi )
2811*53ee8cc1Swenshuai.xi ms_ehci_work(pEhci, pRegs);
2812*53ee8cc1Swenshuai.xi done:
2813*53ee8cc1Swenshuai.xi osapi_spin_unlock (&pEhci->tHcdLock);
2814*53ee8cc1Swenshuai.xi if (u32Status & USBSTS_PCD)
2815*53ee8cc1Swenshuai.xi ms_hcd_poll_rh_status(pHcd);
2816*53ee8cc1Swenshuai.xi
2817*53ee8cc1Swenshuai.xi }
2818*53ee8cc1Swenshuai.xi
2819*53ee8cc1Swenshuai.xi /*-------------------------------------------------------------------------*/
2820*53ee8cc1Swenshuai.xi /*
2821*53ee8cc1Swenshuai.xi * @brief transforms urb into qh+qtd list and submit to HCD hardware
2822*53ee8cc1Swenshuai.xi *
2823*53ee8cc1Swenshuai.xi * @param struct usb_hcd *pHcd
2824*53ee8cc1Swenshuai.xi * @param struct urb *pUrb
2825*53ee8cc1Swenshuai.xi * @param int iMem_flags
2826*53ee8cc1Swenshuai.xi *
2827*53ee8cc1Swenshuai.xi * @return error code
2828*53ee8cc1Swenshuai.xi */
ms_urb_enqueue(struct usb_hcd * pHcd,struct urb * pUrb,int iMem_flags)2829*53ee8cc1Swenshuai.xi int ms_urb_enqueue (
2830*53ee8cc1Swenshuai.xi struct usb_hcd *pHcd,
2831*53ee8cc1Swenshuai.xi struct urb *pUrb,
2832*53ee8cc1Swenshuai.xi int iMem_flags
2833*53ee8cc1Swenshuai.xi )
2834*53ee8cc1Swenshuai.xi {
2835*53ee8cc1Swenshuai.xi struct ehci_hcd *pEhci = hcd_to_ehci (pHcd);
2836*53ee8cc1Swenshuai.xi struct list_head qtd_list;
2837*53ee8cc1Swenshuai.xi int iRetVal;
2838*53ee8cc1Swenshuai.xi
2839*53ee8cc1Swenshuai.xi ms_debug_func("++[%s] line:[%d]\n", __FUNCTION__, __LINE__);
2840*53ee8cc1Swenshuai.xi #ifdef ENABLE_DISCONNECT_FAST_RESPONSE
2841*53ee8cc1Swenshuai.xi if( (hcd_reg_readl ((U32)&pEhci->op_regs->portsc[0])&PORTSC_CONNECT) == 0 )
2842*53ee8cc1Swenshuai.xi {
2843*53ee8cc1Swenshuai.xi iRetVal = -ENODEV;
2844*53ee8cc1Swenshuai.xi goto urb_enqueue_fail;
2845*53ee8cc1Swenshuai.xi }
2846*53ee8cc1Swenshuai.xi #endif
2847*53ee8cc1Swenshuai.xi ms_list_init (&qtd_list);
2848*53ee8cc1Swenshuai.xi
2849*53ee8cc1Swenshuai.xi switch (usb_pipetype (pUrb->u32Pipe))
2850*53ee8cc1Swenshuai.xi {
2851*53ee8cc1Swenshuai.xi case EP_CONTROL:
2852*53ee8cc1Swenshuai.xi case EP_BULK:
2853*53ee8cc1Swenshuai.xi if (!ms_qh_urb_process (pEhci, pUrb, &qtd_list, iMem_flags))
2854*53ee8cc1Swenshuai.xi {
2855*53ee8cc1Swenshuai.xi iRetVal = -ENOMEM;
2856*53ee8cc1Swenshuai.xi goto urb_enqueue_fail;
2857*53ee8cc1Swenshuai.xi }
2858*53ee8cc1Swenshuai.xi iRetVal = ms_submit_async (pEhci, pUrb, &qtd_list);
2859*53ee8cc1Swenshuai.xi break;
2860*53ee8cc1Swenshuai.xi
2861*53ee8cc1Swenshuai.xi case EP_INTERRUPT:
2862*53ee8cc1Swenshuai.xi if (!ms_qh_urb_process (pEhci, pUrb, &qtd_list, iMem_flags))
2863*53ee8cc1Swenshuai.xi {
2864*53ee8cc1Swenshuai.xi iRetVal = -ENOMEM;
2865*53ee8cc1Swenshuai.xi goto urb_enqueue_fail;
2866*53ee8cc1Swenshuai.xi }
2867*53ee8cc1Swenshuai.xi iRetVal = ms_intr_submit (pEhci, pUrb, &qtd_list);
2868*53ee8cc1Swenshuai.xi break;
2869*53ee8cc1Swenshuai.xi
2870*53ee8cc1Swenshuai.xi default:
2871*53ee8cc1Swenshuai.xi ms_debug_msg ("no support the transaction type!!\n");
2872*53ee8cc1Swenshuai.xi iRetVal = -ENOSYS;
2873*53ee8cc1Swenshuai.xi }
2874*53ee8cc1Swenshuai.xi
2875*53ee8cc1Swenshuai.xi urb_enqueue_fail:
2876*53ee8cc1Swenshuai.xi ms_debug_func("--[%s] line:[%d]\n", __FUNCTION__, __LINE__);
2877*53ee8cc1Swenshuai.xi return iRetVal;
2878*53ee8cc1Swenshuai.xi }
2879*53ee8cc1Swenshuai.xi
2880*53ee8cc1Swenshuai.xi /*
2881*53ee8cc1Swenshuai.xi * @brief remove qh from HW content
2882*53ee8cc1Swenshuai.xi * will happen a completion event
2883*53ee8cc1Swenshuai.xi *
2884*53ee8cc1Swenshuai.xi * @param struct usb_hcd *pHcd
2885*53ee8cc1Swenshuai.xi * @param struct urb *pUrb
2886*53ee8cc1Swenshuai.xi *
2887*53ee8cc1Swenshuai.xi * @return error code
2888*53ee8cc1Swenshuai.xi */
ms_urb_dequeue(struct usb_hcd * pHcd,struct urb * pUrb)2889*53ee8cc1Swenshuai.xi int ms_urb_dequeue (struct usb_hcd *pHcd, struct urb *pUrb)
2890*53ee8cc1Swenshuai.xi {
2891*53ee8cc1Swenshuai.xi struct ehci_hcd *pEhci = hcd_to_ehci (pHcd);
2892*53ee8cc1Swenshuai.xi struct ehci_qh *pQh = (struct ehci_qh *) pUrb->hcpriv;
2893*53ee8cc1Swenshuai.xi U32 u32Flags;
2894*53ee8cc1Swenshuai.xi int iStatus = 0;
2895*53ee8cc1Swenshuai.xi
2896*53ee8cc1Swenshuai.xi if (!pQh)
2897*53ee8cc1Swenshuai.xi return 0;
2898*53ee8cc1Swenshuai.xi
2899*53ee8cc1Swenshuai.xi ms_debug_func("++[%s] line:[%d]\n", __FUNCTION__, __LINE__);
2900*53ee8cc1Swenshuai.xi osapi_spin_lock_irqsave (&pEhci->tHcdLock, u32Flags);
2901*53ee8cc1Swenshuai.xi switch (usb_pipetype (pUrb->u32Pipe))
2902*53ee8cc1Swenshuai.xi {
2903*53ee8cc1Swenshuai.xi /*
2904*53ee8cc1Swenshuai.xi // case EP_CONTROL:
2905*53ee8cc1Swenshuai.xi // case EP_BULK:
2906*53ee8cc1Swenshuai.xi */
2907*53ee8cc1Swenshuai.xi default:
2908*53ee8cc1Swenshuai.xi /* patch the old flow */
2909*53ee8cc1Swenshuai.xi switch (pQh->qh_status) {
2910*53ee8cc1Swenshuai.xi case QH_STS_LINKED:
2911*53ee8cc1Swenshuai.xi case QH_STS_COMPLETING:
2912*53ee8cc1Swenshuai.xi #ifdef ENABLE_DISCONNECT_FAST_RESPONSE
2913*53ee8cc1Swenshuai.xi /* remove (20150422) */
2914*53ee8cc1Swenshuai.xi /* do fast unlink if HCD halt */
2915*53ee8cc1Swenshuai.xi //if ( (hcd_reg_readw ((U32)&pEhci->op_regs->usbcmd)&USBCMD_RUN) == 0 )
2916*53ee8cc1Swenshuai.xi // pEhci->hcd.state = HCD_STATE_HALT;
2917*53ee8cc1Swenshuai.xi #endif
2918*53ee8cc1Swenshuai.xi /* base on linux 2.6.28, 3.1.10 */
2919*53ee8cc1Swenshuai.xi /*** unlink_async ***/
2920*53ee8cc1Swenshuai.xi ms_unlink_async(pEhci, pQh);
2921*53ee8cc1Swenshuai.xi break;
2922*53ee8cc1Swenshuai.xi case QH_STS_UNLINK:
2923*53ee8cc1Swenshuai.xi case QH_STS_UNLINK_WAIT:
2924*53ee8cc1Swenshuai.xi /* had started */
2925*53ee8cc1Swenshuai.xi break;
2926*53ee8cc1Swenshuai.xi case QH_STS_IDLE:
2927*53ee8cc1Swenshuai.xi diag_printf("[USB] dequeue idle qh\n");
2928*53ee8cc1Swenshuai.xi break;
2929*53ee8cc1Swenshuai.xi }
2930*53ee8cc1Swenshuai.xi #if 0 // renewed old flow
2931*53ee8cc1Swenshuai.xi /* if we need to use IAA and it's busy, defer */
2932*53ee8cc1Swenshuai.xi if (pQh->qh_status == QH_STS_LINKED
2933*53ee8cc1Swenshuai.xi && pEhci->stReclaim
2934*53ee8cc1Swenshuai.xi && HCD_IS_RUNNING (pEhci->hcd.state)
2935*53ee8cc1Swenshuai.xi )
2936*53ee8cc1Swenshuai.xi {
2937*53ee8cc1Swenshuai.xi struct ehci_qh *pLast;
2938*53ee8cc1Swenshuai.xi
2939*53ee8cc1Swenshuai.xi for (pLast = pEhci->stReclaim;
2940*53ee8cc1Swenshuai.xi pLast->pReclaimQh;
2941*53ee8cc1Swenshuai.xi pLast = pLast->pReclaimQh)
2942*53ee8cc1Swenshuai.xi continue;
2943*53ee8cc1Swenshuai.xi pQh->qh_status = QH_STS_UNLINK_WAIT;
2944*53ee8cc1Swenshuai.xi pLast->pReclaimQh = pQh;
2945*53ee8cc1Swenshuai.xi /* bypass IAA if the hc can't care */
2946*53ee8cc1Swenshuai.xi }
2947*53ee8cc1Swenshuai.xi else if (!HCD_IS_RUNNING (pEhci->hcd.state) && pEhci->stReclaim)
2948*53ee8cc1Swenshuai.xi ms_end_unlink_async (pEhci, NULL);
2949*53ee8cc1Swenshuai.xi
2950*53ee8cc1Swenshuai.xi /* something else might have unlinked the qh by now */
2951*53ee8cc1Swenshuai.xi if (pQh->qh_status == QH_STS_LINKED)
2952*53ee8cc1Swenshuai.xi ms_start_unlink_async (pEhci, pQh);
2953*53ee8cc1Swenshuai.xi #endif
2954*53ee8cc1Swenshuai.xi //FIXME: cover FOTG200 bug
2955*53ee8cc1Swenshuai.xi // NUSED, not proper hardware patch
2956*53ee8cc1Swenshuai.xi //if( (hcd_reg_readw ((U32)&pEhci->op_regs->portsc[0])&PORTSC_CONNECT) == 0 )
2957*53ee8cc1Swenshuai.xi //{
2958*53ee8cc1Swenshuai.xi // diag_printf("[urb_dequeue] connect bit = 0 \n");
2959*53ee8cc1Swenshuai.xi // //Finish ullinking procedure
2960*53ee8cc1Swenshuai.xi // ms_end_unlink_async (pEhci, NULL);
2961*53ee8cc1Swenshuai.xi // //Reset HC to ensure FOTG200 work correctly at the next time
2962*53ee8cc1Swenshuai.xi // ms_hub_port_disable(pEhci->hcd.self.root_hub,0);
2963*53ee8cc1Swenshuai.xi //}
2964*53ee8cc1Swenshuai.xi //else if ( (hcd_reg_readw ((U32)&pEhci->op_regs->usbcmd)&USBCMD_RUN) == 0 )
2965*53ee8cc1Swenshuai.xi //{
2966*53ee8cc1Swenshuai.xi // diag_printf("Something wrong (script auto running?) ==> Check it out\n");
2967*53ee8cc1Swenshuai.xi // //Finish ullinking procedure
2968*53ee8cc1Swenshuai.xi // ms_end_unlink_async (pEhci, NULL);
2969*53ee8cc1Swenshuai.xi // //Reset HC to ensure FOTG200 work correctly at the next time
2970*53ee8cc1Swenshuai.xi // ms_hub_port_disable(pEhci->hcd.self.root_hub,0);
2971*53ee8cc1Swenshuai.xi //}
2972*53ee8cc1Swenshuai.xi break;
2973*53ee8cc1Swenshuai.xi case EP_INTERRUPT:
2974*53ee8cc1Swenshuai.xi /* patch from Linux 2.6.28 */
2975*53ee8cc1Swenshuai.xi switch (pQh->qh_status)
2976*53ee8cc1Swenshuai.xi {
2977*53ee8cc1Swenshuai.xi case QH_STS_LINKED:
2978*53ee8cc1Swenshuai.xi //case QH_STS_COMPLETING:
2979*53ee8cc1Swenshuai.xi ms_intr_deschedule (pEhci, pQh);
2980*53ee8cc1Swenshuai.xi /* revise to fall through */
2981*53ee8cc1Swenshuai.xi //break;
2982*53ee8cc1Swenshuai.xi case QH_STS_IDLE:
2983*53ee8cc1Swenshuai.xi ms_qh_completions (pEhci, pQh, NULL);
2984*53ee8cc1Swenshuai.xi break;
2985*53ee8cc1Swenshuai.xi default:
2986*53ee8cc1Swenshuai.xi ms_debug_err("bogus qh %p state %d\n",
2987*53ee8cc1Swenshuai.xi pQh, pQh->qh_status);
2988*53ee8cc1Swenshuai.xi goto done;
2989*53ee8cc1Swenshuai.xi }
2990*53ee8cc1Swenshuai.xi break;
2991*53ee8cc1Swenshuai.xi #if 0 // renewed old one
2992*53ee8cc1Swenshuai.xi if (pQh->qh_status == QH_STS_LINKED)
2993*53ee8cc1Swenshuai.xi {
2994*53ee8cc1Swenshuai.xi /* messy, can spin or block a microframe ... */
2995*53ee8cc1Swenshuai.xi ms_intr_deschedule (pEhci, pQh, 1);
2996*53ee8cc1Swenshuai.xi /* qh_state == IDLE */
2997*53ee8cc1Swenshuai.xi }
2998*53ee8cc1Swenshuai.xi ms_qh_completions (pEhci, pQh, NULL);
2999*53ee8cc1Swenshuai.xi #endif
3000*53ee8cc1Swenshuai.xi
3001*53ee8cc1Swenshuai.xi /* reschedule QH iff another request is queued */
3002*53ee8cc1Swenshuai.xi if (!ms_is_empty_list (&pQh->qtd_list)
3003*53ee8cc1Swenshuai.xi && HCD_IS_RUNNING (pEhci->hcd.state))
3004*53ee8cc1Swenshuai.xi {
3005*53ee8cc1Swenshuai.xi //int iStatus;
3006*53ee8cc1Swenshuai.xi
3007*53ee8cc1Swenshuai.xi iStatus = ms_qh_schedule (pEhci, pQh);
3008*53ee8cc1Swenshuai.xi //osapi_spin_unlock_irqrestore (&pEhci->tHcdLock, u32Flags);
3009*53ee8cc1Swenshuai.xi if (iStatus != 0)
3010*53ee8cc1Swenshuai.xi {
3011*53ee8cc1Swenshuai.xi // Warning happened
3012*53ee8cc1Swenshuai.xi ms_debug_err ("can't reschedule pQh %p, err %d", pQh, iStatus);
3013*53ee8cc1Swenshuai.xi }
3014*53ee8cc1Swenshuai.xi //ms_debug_func("--[%s] line:[%d]\n", __FUNCTION__, __LINE__);
3015*53ee8cc1Swenshuai.xi //return iStatus;
3016*53ee8cc1Swenshuai.xi }
3017*53ee8cc1Swenshuai.xi break;
3018*53ee8cc1Swenshuai.xi }
3019*53ee8cc1Swenshuai.xi done:
3020*53ee8cc1Swenshuai.xi osapi_spin_unlock_irqrestore (&pEhci->tHcdLock, u32Flags);
3021*53ee8cc1Swenshuai.xi ms_debug_func("--[%s] line:[%d]\n", __FUNCTION__, __LINE__);
3022*53ee8cc1Swenshuai.xi return iStatus;
3023*53ee8cc1Swenshuai.xi }
3024*53ee8cc1Swenshuai.xi
3025*53ee8cc1Swenshuai.xi /*-------------------------------------------------------------------------*/
3026*53ee8cc1Swenshuai.xi
3027*53ee8cc1Swenshuai.xi /*
3028*53ee8cc1Swenshuai.xi * @brief wait qh unlink complete then free qtd list.
3029*53ee8cc1Swenshuai.xi *
3030*53ee8cc1Swenshuai.xi * @param struct usb_hcd *pHcd
3031*53ee8cc1Swenshuai.xi * @param struct s_hcd_dev *pDev
3032*53ee8cc1Swenshuai.xi * @param int iEp
3033*53ee8cc1Swenshuai.xi *
3034*53ee8cc1Swenshuai.xi * @return none
3035*53ee8cc1Swenshuai.xi */
3036*53ee8cc1Swenshuai.xi
3037*53ee8cc1Swenshuai.xi void
ms_ehci_disable_ep(struct usb_hcd * pHcd,struct s_hcd_dev * pDev,int iEp)3038*53ee8cc1Swenshuai.xi ms_ehci_disable_ep (struct usb_hcd *pHcd, struct s_hcd_dev *pDev, int iEp)
3039*53ee8cc1Swenshuai.xi {
3040*53ee8cc1Swenshuai.xi struct ehci_hcd *pEhci = hcd_to_ehci (pHcd);
3041*53ee8cc1Swenshuai.xi int iEpnum;
3042*53ee8cc1Swenshuai.xi U32 u32Flags;
3043*53ee8cc1Swenshuai.xi struct ehci_qh *pQh, *tmp;
3044*53ee8cc1Swenshuai.xi int numRescan = 100;
3045*53ee8cc1Swenshuai.xi
3046*53ee8cc1Swenshuai.xi ms_debug_func("++[%s] line:[%d]\n", __FUNCTION__, __LINE__);
3047*53ee8cc1Swenshuai.xi iEpnum = iEp & USB_ENDPOINT_NUMBER_MASK;
3048*53ee8cc1Swenshuai.xi if (iEpnum != 0 && (iEp & USB_DIR_IN))
3049*53ee8cc1Swenshuai.xi iEpnum |= 0x10;
3050*53ee8cc1Swenshuai.xi
3051*53ee8cc1Swenshuai.xi rescan:
3052*53ee8cc1Swenshuai.xi osapi_spin_lock_irqsave (&pEhci->tHcdLock, u32Flags);
3053*53ee8cc1Swenshuai.xi pQh = (struct ehci_qh *) pDev->ep[iEpnum];
3054*53ee8cc1Swenshuai.xi if (!pQh)
3055*53ee8cc1Swenshuai.xi goto done;
3056*53ee8cc1Swenshuai.xi
3057*53ee8cc1Swenshuai.xi if (!HCD_IS_RUNNING (pEhci->hcd.state))
3058*53ee8cc1Swenshuai.xi pQh->qh_status = QH_STS_IDLE;
3059*53ee8cc1Swenshuai.xi switch (pQh->qh_status)
3060*53ee8cc1Swenshuai.xi {
3061*53ee8cc1Swenshuai.xi case QH_STS_LINKED:
3062*53ee8cc1Swenshuai.xi for (tmp = pEhci->stAsync->qh_next.qh;
3063*53ee8cc1Swenshuai.xi tmp && tmp != pQh; tmp = tmp->qh_next.qh)
3064*53ee8cc1Swenshuai.xi continue;
3065*53ee8cc1Swenshuai.xi if (!tmp)
3066*53ee8cc1Swenshuai.xi goto bad;
3067*53ee8cc1Swenshuai.xi /* base on linux 2.6.28, 3.1.10 */
3068*53ee8cc1Swenshuai.xi /*** unlink_async ***/
3069*53ee8cc1Swenshuai.xi ms_unlink_async(pEhci, pQh);
3070*53ee8cc1Swenshuai.xi //break;
3071*53ee8cc1Swenshuai.xi /* to disable endpoint, unlink continued */
3072*53ee8cc1Swenshuai.xi case QH_STS_UNLINK:
3073*53ee8cc1Swenshuai.xi case QH_STS_UNLINK_WAIT:
3074*53ee8cc1Swenshuai.xi osapi_spin_unlock_irqrestore (&pEhci->tHcdLock, u32Flags);
3075*53ee8cc1Swenshuai.xi osapi_schedule_timeout (1);
3076*53ee8cc1Swenshuai.xi if (--numRescan)
3077*53ee8cc1Swenshuai.xi goto rescan;
3078*53ee8cc1Swenshuai.xi diag_printf("[UM-DEP] rescan 100 times, qh state %d, HCD state %x\n", pQh->qh_status, pEhci->hcd.state);
3079*53ee8cc1Swenshuai.xi osapi_spin_lock_irqsave (&pEhci->tHcdLock, u32Flags);
3080*53ee8cc1Swenshuai.xi case QH_STS_IDLE:
3081*53ee8cc1Swenshuai.xi if (ms_is_empty_list (&pQh->qtd_list))
3082*53ee8cc1Swenshuai.xi {
3083*53ee8cc1Swenshuai.xi ms_qh_put (pEhci, pQh);
3084*53ee8cc1Swenshuai.xi break;
3085*53ee8cc1Swenshuai.xi }
3086*53ee8cc1Swenshuai.xi default:
3087*53ee8cc1Swenshuai.xi bad:
3088*53ee8cc1Swenshuai.xi //if ( !ms_is_empty_list (&pQh->qtd_list))
3089*53ee8cc1Swenshuai.xi {
3090*53ee8cc1Swenshuai.xi ms_debug_err ("<%s> pQh %p (ep#%d) state %d%s\n",
3091*53ee8cc1Swenshuai.xi __FUNCTION__, pQh, iEpnum, pQh->qh_status,
3092*53ee8cc1Swenshuai.xi ms_is_empty_list (&pQh->qtd_list) ? "" : "(has tds)");
3093*53ee8cc1Swenshuai.xi }
3094*53ee8cc1Swenshuai.xi break;
3095*53ee8cc1Swenshuai.xi }
3096*53ee8cc1Swenshuai.xi if (numRescan)
3097*53ee8cc1Swenshuai.xi pDev->ep[iEpnum] = 0;
3098*53ee8cc1Swenshuai.xi done:
3099*53ee8cc1Swenshuai.xi osapi_spin_unlock_irqrestore (&pEhci->tHcdLock, u32Flags);
3100*53ee8cc1Swenshuai.xi ms_debug_func("--[%s] line:[%d]\n", __FUNCTION__, __LINE__);
3101*53ee8cc1Swenshuai.xi return;
3102*53ee8cc1Swenshuai.xi }
3103*53ee8cc1Swenshuai.xi
3104*53ee8cc1Swenshuai.xi /*-------------------------------------------------------------------------*/
3105*53ee8cc1Swenshuai.xi
ms_ehci_stoprun_setting(MS_U8 bOption,struct ehci_hcd * ehci)3106*53ee8cc1Swenshuai.xi void ms_ehci_stoprun_setting(MS_U8 bOption, struct ehci_hcd *ehci)
3107*53ee8cc1Swenshuai.xi {
3108*53ee8cc1Swenshuai.xi U32 temp;
3109*53ee8cc1Swenshuai.xi
3110*53ee8cc1Swenshuai.xi ms_debug_func("++[%s] line:[%d]\n", __FUNCTION__, __LINE__);
3111*53ee8cc1Swenshuai.xi if (bOption==HOST20_Enable)
3112*53ee8cc1Swenshuai.xi {
3113*53ee8cc1Swenshuai.xi temp = hcd_reg_readl((U32)&ehci->op_regs->usbcmd);
3114*53ee8cc1Swenshuai.xi if (temp & USBCMD_RUN)
3115*53ee8cc1Swenshuai.xi {
3116*53ee8cc1Swenshuai.xi ms_debug_func("--[%s] line:[%d]\n", __FUNCTION__, __LINE__);
3117*53ee8cc1Swenshuai.xi return;
3118*53ee8cc1Swenshuai.xi }
3119*53ee8cc1Swenshuai.xi temp |= USBCMD_RUN;
3120*53ee8cc1Swenshuai.xi hcd_reg_writel(temp, (U32)&ehci->op_regs->usbcmd);
3121*53ee8cc1Swenshuai.xi do
3122*53ee8cc1Swenshuai.xi {
3123*53ee8cc1Swenshuai.xi temp = hcd_reg_readl((U32)&ehci->op_regs->usbcmd);
3124*53ee8cc1Swenshuai.xi } while ((temp & USBCMD_RUN) == 0);
3125*53ee8cc1Swenshuai.xi ehci->hcd.state = HCD_STATE_RUNNING;
3126*53ee8cc1Swenshuai.xi }
3127*53ee8cc1Swenshuai.xi else if (bOption==HOST20_Disable)
3128*53ee8cc1Swenshuai.xi {
3129*53ee8cc1Swenshuai.xi temp = hcd_reg_readl((U32)&ehci->op_regs->usbcmd);
3130*53ee8cc1Swenshuai.xi if ((temp & USBCMD_RUN) == 0)
3131*53ee8cc1Swenshuai.xi return;
3132*53ee8cc1Swenshuai.xi
3133*53ee8cc1Swenshuai.xi temp &= ~USBCMD_RUN;
3134*53ee8cc1Swenshuai.xi hcd_reg_writel(temp, (U32)&ehci->op_regs->usbcmd);
3135*53ee8cc1Swenshuai.xi do {
3136*53ee8cc1Swenshuai.xi temp = hcd_reg_readl((U32)&ehci->op_regs->usbcmd);
3137*53ee8cc1Swenshuai.xi } while ((temp & USBCMD_RUN) > 0);
3138*53ee8cc1Swenshuai.xi ehci->hcd.state = HCD_STATE_HALT;
3139*53ee8cc1Swenshuai.xi }
3140*53ee8cc1Swenshuai.xi else
3141*53ee8cc1Swenshuai.xi USB_ASSERT(0, "??? Input Error 'ms_ehci_stoprun_setting'...");
3142*53ee8cc1Swenshuai.xi
3143*53ee8cc1Swenshuai.xi ms_debug_func("--[%s] line:[%d]\n", __FUNCTION__, __LINE__);
3144*53ee8cc1Swenshuai.xi }
3145*53ee8cc1Swenshuai.xi
ms_qh_ehci_reinit(struct usb_hcd * pHcd,int not_fix)3146*53ee8cc1Swenshuai.xi void ms_qh_ehci_reinit(struct usb_hcd *pHcd, int not_fix)
3147*53ee8cc1Swenshuai.xi {
3148*53ee8cc1Swenshuai.xi struct ehci_hcd *pEhci = hcd_to_ehci (pHcd);
3149*53ee8cc1Swenshuai.xi U32 u32Temp;
3150*53ee8cc1Swenshuai.xi int is_empty_qtd = 0;
3151*53ee8cc1Swenshuai.xi
3152*53ee8cc1Swenshuai.xi if( pEhci->stAsync->qh_next.qh != 0 )
3153*53ee8cc1Swenshuai.xi {
3154*53ee8cc1Swenshuai.xi ms_debug_err("[reinit] MAY Not only cantain one qHD in asyn. scheduler (%p)\n", pEhci->stAsync);
3155*53ee8cc1Swenshuai.xi ms_debug_err("[reinit] async hw_next_qh %x\n", pEhci->stAsync->hw_next_qh);
3156*53ee8cc1Swenshuai.xi #if 0
3157*53ee8cc1Swenshuai.xi struct ehci_qh *pQh = pEhci->stAsync->qh_next.qh;
3158*53ee8cc1Swenshuai.xi while(pQh) {
3159*53ee8cc1Swenshuai.xi ms_debug_err("qh %p\n=============\n", pQh);
3160*53ee8cc1Swenshuai.xi ms_debug_err("[UM] status %d\n", pQh->qh_status);
3161*53ee8cc1Swenshuai.xi ms_debug_err("[UM] hw ep %d\n", (pQh->hw_ep_state1 >> 8) & 0xf);
3162*53ee8cc1Swenshuai.xi ms_debug_err("[UM] qtd_list %s\n", !ms_is_empty_list (&pQh->qtd_list) ? "there": "none");
3163*53ee8cc1Swenshuai.xi ms_debug_err("[UM] refcnt %d\n", pQh->tRefCnt);
3164*53ee8cc1Swenshuai.xi if (ms_is_empty_list (&pQh->qtd_list))
3165*53ee8cc1Swenshuai.xi is_empty_qtd = 1;
3166*53ee8cc1Swenshuai.xi pQh = pQh->qh_next.qh;
3167*53ee8cc1Swenshuai.xi }
3168*53ee8cc1Swenshuai.xi ms_debug_err("=============\n");
3169*53ee8cc1Swenshuai.xi #endif
3170*53ee8cc1Swenshuai.xi }
3171*53ee8cc1Swenshuai.xi
3172*53ee8cc1Swenshuai.xi if (not_fix || is_empty_qtd)
3173*53ee8cc1Swenshuai.xi return;
3174*53ee8cc1Swenshuai.xi
3175*53ee8cc1Swenshuai.xi u32Temp = hcd_reg_readl ((U32)&pEhci->op_regs->portsc [0]);
3176*53ee8cc1Swenshuai.xi u32Temp = u32Temp & ~PORTSC_RWC_BITS;
3177*53ee8cc1Swenshuai.xi hcd_reg_writel (u32Temp & ~PORTSC_PE, (U32)&pEhci->op_regs->portsc [0]);
3178*53ee8cc1Swenshuai.xi //�˸m�Q�������ɭ� ����scheduler
3179*53ee8cc1Swenshuai.xi hcd_reg_writel(hcd_reg_readl((U32)&pEhci->op_regs->usbcmd)&(~(USBCMD_ASE|USBCMD_PSE|USBCMD_IAAD)),(U32)&pEhci->op_regs->usbcmd);
3180*53ee8cc1Swenshuai.xi /* recover periodic size setting at STR off/on */
3181*53ee8cc1Swenshuai.xi u32Temp = hcd_reg_readl((U32)&pEhci->op_regs->usbcmd);
3182*53ee8cc1Swenshuai.xi u32Temp &= ~(3 << 2);
3183*53ee8cc1Swenshuai.xi u32Temp |= (EHCI_PERIODIC_FLS << 2);
3184*53ee8cc1Swenshuai.xi hcd_reg_writel(u32Temp,(U32)&pEhci->op_regs->usbcmd);
3185*53ee8cc1Swenshuai.xi
3186*53ee8cc1Swenshuai.xi if( pEhci->stAsync->qh_next.qh != 0 )
3187*53ee8cc1Swenshuai.xi {
3188*53ee8cc1Swenshuai.xi struct ehci_qh *pQh = pEhci->stAsync->qh_next.qh;
3189*53ee8cc1Swenshuai.xi
3190*53ee8cc1Swenshuai.xi do {
3191*53ee8cc1Swenshuai.xi struct ehci_qh *qh_rm;
3192*53ee8cc1Swenshuai.xi
3193*53ee8cc1Swenshuai.xi qh_rm = pQh;
3194*53ee8cc1Swenshuai.xi pQh = pQh->qh_next.qh;
3195*53ee8cc1Swenshuai.xi qh_rm->qh_next.qh = NULL;
3196*53ee8cc1Swenshuai.xi qh_rm->tRefCnt = 1; // forced to be 1
3197*53ee8cc1Swenshuai.xi ms_qh_put(pEhci, qh_rm);
3198*53ee8cc1Swenshuai.xi } while(pQh);
3199*53ee8cc1Swenshuai.xi
3200*53ee8cc1Swenshuai.xi /* re-init head QH */
3201*53ee8cc1Swenshuai.xi pEhci->stAsync->qh_next.qh = NULL;
3202*53ee8cc1Swenshuai.xi pEhci->stAsync->hw_next_qh = QH_NEXT (pEhci->stAsync->qh_dma_addr);
3203*53ee8cc1Swenshuai.xi pEhci->stAsync->hw_ep_state1 = QH_H_BIT;
3204*53ee8cc1Swenshuai.xi pEhci->stAsync->hw_token = QTD_STS_HALT;
3205*53ee8cc1Swenshuai.xi pEhci->stAsync->hw_next_qtd = EHCI_LIST_END;
3206*53ee8cc1Swenshuai.xi pEhci->stAsync->qh_status = QH_STS_LINKED;
3207*53ee8cc1Swenshuai.xi pEhci->stAsync->hw_alt_next_qtd = (U32)(pEhci->stAsync->pDummyQtd->qtd_dma_addr);
3208*53ee8cc1Swenshuai.xi }
3209*53ee8cc1Swenshuai.xi }
3210*53ee8cc1Swenshuai.xi
3211*53ee8cc1Swenshuai.xi #ifdef USB_SYSTEM_STR_SUPPORT
ms_ehci_periodic_size_init(struct usb_hcd * hcd)3212*53ee8cc1Swenshuai.xi void ms_ehci_periodic_size_init (struct usb_hcd *hcd)
3213*53ee8cc1Swenshuai.xi {
3214*53ee8cc1Swenshuai.xi struct ehci_hcd *pEhci = hcd_to_ehci (hcd);
3215*53ee8cc1Swenshuai.xi U32 u32Temp;
3216*53ee8cc1Swenshuai.xi
3217*53ee8cc1Swenshuai.xi /* recover periodic size setting at STR off/on */
3218*53ee8cc1Swenshuai.xi u32Temp = hcd_reg_readl((U32)&pEhci->op_regs->usbcmd);
3219*53ee8cc1Swenshuai.xi u32Temp &= ~(3 << 2);
3220*53ee8cc1Swenshuai.xi u32Temp |= (EHCI_PERIODIC_FLS << 2);
3221*53ee8cc1Swenshuai.xi hcd_reg_writel(u32Temp,(U32)&pEhci->op_regs->usbcmd);
3222*53ee8cc1Swenshuai.xi }
3223*53ee8cc1Swenshuai.xi #endif
3224*53ee8cc1Swenshuai.xi
3225*53ee8cc1Swenshuai.xi #if USB_IF_EHSET_SUPPORT // Embedded host electrical test procedure
3226*53ee8cc1Swenshuai.xi struct list_head *
ms_qh_urb_transaction_EHSET(struct ehci_hcd * ehci,struct urb * urb,struct list_head * head,int iFlags,int iStage)3227*53ee8cc1Swenshuai.xi ms_qh_urb_transaction_EHSET (
3228*53ee8cc1Swenshuai.xi struct ehci_hcd *ehci,
3229*53ee8cc1Swenshuai.xi struct urb *urb,
3230*53ee8cc1Swenshuai.xi struct list_head *head,
3231*53ee8cc1Swenshuai.xi int iFlags,
3232*53ee8cc1Swenshuai.xi int iStage
3233*53ee8cc1Swenshuai.xi )
3234*53ee8cc1Swenshuai.xi {
3235*53ee8cc1Swenshuai.xi struct ehci_qtd *pQtd, *pQtdPrev;
3236*53ee8cc1Swenshuai.xi dma_addr_t tBufAddr;
3237*53ee8cc1Swenshuai.xi int iLen, iMaxpkt;
3238*53ee8cc1Swenshuai.xi int iIsInput;
3239*53ee8cc1Swenshuai.xi U32 u32Token;
3240*53ee8cc1Swenshuai.xi
3241*53ee8cc1Swenshuai.xi ms_debug_func("++[%s] line:[%d]\n", __FUNCTION__, __LINE__);
3242*53ee8cc1Swenshuai.xi pQtd = ms_ehci_qtd_alloc (ehci, iFlags);
3243*53ee8cc1Swenshuai.xi if (!pQtd)
3244*53ee8cc1Swenshuai.xi {
3245*53ee8cc1Swenshuai.xi ms_debug_func("--[%s] line:[%d]\n", __FUNCTION__, __LINE__);
3246*53ee8cc1Swenshuai.xi return 0;
3247*53ee8cc1Swenshuai.xi }
3248*53ee8cc1Swenshuai.xi ms_insert_list_before (&pQtd->qtd_list, head);
3249*53ee8cc1Swenshuai.xi pQtd->urb = urb;
3250*53ee8cc1Swenshuai.xi
3251*53ee8cc1Swenshuai.xi u32Token = QTD_STS_ACT;
3252*53ee8cc1Swenshuai.xi u32Token |= (MAX_CERR_CNT << 10);
3253*53ee8cc1Swenshuai.xi
3254*53ee8cc1Swenshuai.xi iLen = urb->u32TransferBufferLength;
3255*53ee8cc1Swenshuai.xi iIsInput = usb_pipein (urb->u32Pipe);
3256*53ee8cc1Swenshuai.xi if (!iStage)
3257*53ee8cc1Swenshuai.xi {
3258*53ee8cc1Swenshuai.xi if (usb_pipecontrol (urb->u32Pipe))
3259*53ee8cc1Swenshuai.xi {
3260*53ee8cc1Swenshuai.xi ms_qtd_pack (pQtd, urb->tSetupDma, sizeof (struct usb_ctrlrequest),
3261*53ee8cc1Swenshuai.xi u32Token | (2 /* "setup" */ << 8), 8);
3262*53ee8cc1Swenshuai.xi pQtd->hw_alt_next_qtd = EHCI_LIST_END; // EHSET
3263*53ee8cc1Swenshuai.xi u32Token ^= QTD_TOGGLE;
3264*53ee8cc1Swenshuai.xi }
3265*53ee8cc1Swenshuai.xi
3266*53ee8cc1Swenshuai.xi if (!(urb->u32TransferFlags & MS_FLAG_URB_NO_INTERRUPT))
3267*53ee8cc1Swenshuai.xi pQtd->hw_token |= QTD_IOC; // EHSET
3268*53ee8cc1Swenshuai.xi return head;
3269*53ee8cc1Swenshuai.xi }
3270*53ee8cc1Swenshuai.xi else
3271*53ee8cc1Swenshuai.xi u32Token ^= QTD_TOGGLE;
3272*53ee8cc1Swenshuai.xi
3273*53ee8cc1Swenshuai.xi tBufAddr = (iLen > 0) ? urb->tTransferDma : 0;
3274*53ee8cc1Swenshuai.xi
3275*53ee8cc1Swenshuai.xi if (!tBufAddr || iIsInput)
3276*53ee8cc1Swenshuai.xi u32Token |= (1 /* "in" */ << 8);
3277*53ee8cc1Swenshuai.xi if (usb_pipebulk(urb->u32Pipe))
3278*53ee8cc1Swenshuai.xi {
3279*53ee8cc1Swenshuai.xi switch (urb->dev->eSpeed)
3280*53ee8cc1Swenshuai.xi {
3281*53ee8cc1Swenshuai.xi case USB_FULL_SPEED:
3282*53ee8cc1Swenshuai.xi iMaxpkt = max_packet(usb_maxpacket(urb->dev, urb->u32Pipe, !iIsInput));
3283*53ee8cc1Swenshuai.xi break;
3284*53ee8cc1Swenshuai.xi case USB_HIGH_SPEED:
3285*53ee8cc1Swenshuai.xi default:
3286*53ee8cc1Swenshuai.xi iMaxpkt = 512;
3287*53ee8cc1Swenshuai.xi break;
3288*53ee8cc1Swenshuai.xi }
3289*53ee8cc1Swenshuai.xi }
3290*53ee8cc1Swenshuai.xi else
3291*53ee8cc1Swenshuai.xi {
3292*53ee8cc1Swenshuai.xi iMaxpkt = max_packet(usb_maxpacket(urb->dev, urb->u32Pipe, !iIsInput));
3293*53ee8cc1Swenshuai.xi }
3294*53ee8cc1Swenshuai.xi
3295*53ee8cc1Swenshuai.xi for (;;)
3296*53ee8cc1Swenshuai.xi {
3297*53ee8cc1Swenshuai.xi int iThisQtdLen;
3298*53ee8cc1Swenshuai.xi
3299*53ee8cc1Swenshuai.xi iThisQtdLen = ms_qtd_pack (pQtd, tBufAddr, iLen, u32Token, iMaxpkt);
3300*53ee8cc1Swenshuai.xi iLen -= iThisQtdLen;
3301*53ee8cc1Swenshuai.xi tBufAddr += iThisQtdLen;
3302*53ee8cc1Swenshuai.xi if (iIsInput)
3303*53ee8cc1Swenshuai.xi pQtd->hw_alt_next_qtd = ehci->stAsync->hw_alt_next_qtd;
3304*53ee8cc1Swenshuai.xi
3305*53ee8cc1Swenshuai.xi if ((iMaxpkt & (iThisQtdLen + (iMaxpkt - 1))) == 0)
3306*53ee8cc1Swenshuai.xi u32Token ^= QTD_TOGGLE;
3307*53ee8cc1Swenshuai.xi
3308*53ee8cc1Swenshuai.xi if (iLen <= 0)
3309*53ee8cc1Swenshuai.xi break;
3310*53ee8cc1Swenshuai.xi
3311*53ee8cc1Swenshuai.xi pQtdPrev = pQtd;
3312*53ee8cc1Swenshuai.xi pQtd = ms_ehci_qtd_alloc (ehci, iFlags);
3313*53ee8cc1Swenshuai.xi if (!pQtd)
3314*53ee8cc1Swenshuai.xi goto cleanup;
3315*53ee8cc1Swenshuai.xi pQtd->urb = urb;
3316*53ee8cc1Swenshuai.xi pQtdPrev->hw_next_qtd = (U32)(pQtd->qtd_dma_addr);
3317*53ee8cc1Swenshuai.xi ms_insert_list_before (&pQtd->qtd_list, head);
3318*53ee8cc1Swenshuai.xi }
3319*53ee8cc1Swenshuai.xi
3320*53ee8cc1Swenshuai.xi if ((urb->u32TransferFlags & MS_FLAG_URB_SHORT_NOT_OK) == 0
3321*53ee8cc1Swenshuai.xi || usb_pipecontrol (urb->u32Pipe))
3322*53ee8cc1Swenshuai.xi pQtd->hw_alt_next_qtd = EHCI_LIST_END;
3323*53ee8cc1Swenshuai.xi
3324*53ee8cc1Swenshuai.xi if (tBufAddr != 0)
3325*53ee8cc1Swenshuai.xi {
3326*53ee8cc1Swenshuai.xi int iOneMore = 0;
3327*53ee8cc1Swenshuai.xi
3328*53ee8cc1Swenshuai.xi if (usb_pipecontrol (urb->u32Pipe))
3329*53ee8cc1Swenshuai.xi {
3330*53ee8cc1Swenshuai.xi iOneMore = 1;
3331*53ee8cc1Swenshuai.xi u32Token ^= 0x0100; /* "in" <--> "out" */
3332*53ee8cc1Swenshuai.xi u32Token |= QTD_TOGGLE; /* force DATA1 */
3333*53ee8cc1Swenshuai.xi }
3334*53ee8cc1Swenshuai.xi else if (usb_pipebulk (urb->u32Pipe)
3335*53ee8cc1Swenshuai.xi && (urb->u32TransferFlags & MS_FLAG_URB_ZERO_PACKET)
3336*53ee8cc1Swenshuai.xi && !(urb->u32TransferBufferLength % iMaxpkt)) {
3337*53ee8cc1Swenshuai.xi iOneMore = 1;
3338*53ee8cc1Swenshuai.xi }
3339*53ee8cc1Swenshuai.xi if (iOneMore)
3340*53ee8cc1Swenshuai.xi {
3341*53ee8cc1Swenshuai.xi pQtdPrev = pQtd;
3342*53ee8cc1Swenshuai.xi pQtd = ms_ehci_qtd_alloc (ehci, iFlags);
3343*53ee8cc1Swenshuai.xi if (!pQtd)
3344*53ee8cc1Swenshuai.xi goto cleanup;
3345*53ee8cc1Swenshuai.xi pQtd->urb = urb;
3346*53ee8cc1Swenshuai.xi pQtdPrev->hw_next_qtd = (U32)(pQtd->qtd_dma_addr);
3347*53ee8cc1Swenshuai.xi ms_insert_list_before (&pQtd->qtd_list, head);
3348*53ee8cc1Swenshuai.xi
3349*53ee8cc1Swenshuai.xi ms_qtd_pack (pQtd, 0, 0, u32Token, 0);
3350*53ee8cc1Swenshuai.xi }
3351*53ee8cc1Swenshuai.xi }
3352*53ee8cc1Swenshuai.xi
3353*53ee8cc1Swenshuai.xi if (!(urb->u32TransferFlags & MS_FLAG_URB_NO_INTERRUPT))
3354*53ee8cc1Swenshuai.xi pQtd->hw_token |= QTD_IOC;
3355*53ee8cc1Swenshuai.xi
3356*53ee8cc1Swenshuai.xi ms_debug_func("--[%s] line:[%d]\n", __FUNCTION__, __LINE__);
3357*53ee8cc1Swenshuai.xi return head;
3358*53ee8cc1Swenshuai.xi
3359*53ee8cc1Swenshuai.xi cleanup:
3360*53ee8cc1Swenshuai.xi
3361*53ee8cc1Swenshuai.xi ms_qtd_register_free (ehci, head);
3362*53ee8cc1Swenshuai.xi ms_debug_func("--[%s] line:[%d]\n", __FUNCTION__, __LINE__);
3363*53ee8cc1Swenshuai.xi return 0;
3364*53ee8cc1Swenshuai.xi }
3365*53ee8cc1Swenshuai.xi
ms_submit_async_EHSET(struct ehci_hcd * ehci,struct urb * urb,struct list_head * qtd_list,int mem_flags)3366*53ee8cc1Swenshuai.xi inline int ms_submit_async_EHSET (
3367*53ee8cc1Swenshuai.xi struct ehci_hcd *ehci,
3368*53ee8cc1Swenshuai.xi struct urb *urb,
3369*53ee8cc1Swenshuai.xi struct list_head *qtd_list,
3370*53ee8cc1Swenshuai.xi int mem_flags
3371*53ee8cc1Swenshuai.xi ) {
3372*53ee8cc1Swenshuai.xi ms_debug_func("++[%s] line:[%d]\n", __FUNCTION__, __LINE__);
3373*53ee8cc1Swenshuai.xi return ms_submit_async(ehci, urb, qtd_list);
3374*53ee8cc1Swenshuai.xi }
3375*53ee8cc1Swenshuai.xi #endif
3376