Files

2601 lines
72 KiB
C

/*
* drvhostlib.c- Sigmastar
*
* Copyright (C) 2018 Sigmastar Technology Corp.
*
* Author: jiang.ann <jiang.ann@sigmastar.com.tw>
*
* This software is licensed under the terms of the GNU General Public
* License version 2, as published by the Free Software Foundation, and
* may be copied, distributed, and modified under those terms.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
*/
#include "hal/platform.h"
#include "inc/common.h"
#include "inc/drvhostlib.h"
#ifdef USB_LIB_DEBUG
#define USB_LIB_PRINTF MS_MSG
#else
#define USB_LIB_PRINTF(fmt, ...)
#endif
#ifdef USB_LIB_BULK_DEBUG
#define USB_LIB_BULK_PRINTF MS_MSG
#else
#define USB_LIB_BULK_PRINTF(fmt, ...)
#endif
#define Scsi_Max_Transfer_Len 16*1024
#define wTimeWaitForConnect_ms 9500
#ifdef USB_EMBEDDED_STANDARD_COMMAND
MS_UINT8 OTGH_GETDESCRIPTOR_DEVICE_8[] = {0x80,0x06,0x00,0x01,0x00,0x00,0x08,0x00};
MS_UINT8 OTGH_GETDESCRIPTOR_DEVICE[] = {0x80,0x06,0x00,0x01,0x00,0x00,0x12,0x00};
MS_UINT8 OTGH_GETDESCRIPTOR_CONFIG[] = {0x80,0x06,0x00,0x02,0x00,0x00,0x08,0x00};
MS_UINT8 OTGH_SETADDRESS[] = {0x00,0x05,0x03,0x00,0x00,0x00,0x00,0x00};
MS_UINT8 OTGH_SETCONFIGURATION[] = {0x00,0x09,0x01,0x00,0x00,0x00,0x00,0x00};
MS_UINT8 OTGH_SET_FEATURE_OTG[] = {0x00,0x03,0x03,0x00,0x00,0x00,0x00,0x00};
/* Set Device Descriptor */
MS_UINT8 OTGH_SETDESCRIPTOR_DEVICE[] = {0x00,0x07,0x00,0x01,0x00,0x00,0x12,0x00};
#endif
MS_UINT8 QtdBuf[ Host20_qTD_SIZE * Host20_qTD_MAX + 0x20*4] __attribute__ ((aligned (128)));
qHD_Structure Host20_qHD_List_Control0 __attribute__ ((aligned (128)));
qHD_Structure Host20_qHD_List_Control1 __attribute__ ((aligned (128)));
qHD_Structure Host20_qHD_List_Bulk0 __attribute__ ((aligned (128)));
qHD_Structure Host20_qHD_List_Bulk1 __attribute__ ((aligned (128)));
qHD_Structure Host20_qHD_List_Intr __attribute__ ((aligned (128)));
Periodic_Frame_List_Structure Host20_FramList __attribute__ ((aligned (4096)));
static MS_UINT16 waIntervalMap[11]={1,2,4,8,16,32,64,128,256,512,1024};
MS_UINT8 Host20_qTD_Manage[Host20_qTD_MAX]; // 1=>Free 2=>used
MS_UINT8 UsbCtrlBuf[0x100] __attribute__ ((aligned (128)));
MS_UINT8 UsbDataBuf[0x100] __attribute__ ((aligned (128)));
/* debug functions for dump QTD & QH data */
void Dump_QTD(MS_UINT32 addr);
void Dump_Data(MS_UINT32 addr, MS_UINT16 sz);
// TODO: FIXME or REMOVE IT
#if defined(USB_BUF_ALIGNED_PATCH)
#define ALIGNED_BUF_SIZE 24 * 1024
__declspec( align(4096) ) MS_UINT8 usb_temp_buf[ALIGNED_BUF_SIZE];
#endif
#if defined(CONFIG_USB_BOUNCE_BUF_PATCH)
#define BOUNCE_BUF_SIZE 24 * 1024
MS_UINT8 usb_bounce_buf[BOUNCE_BUF_SIZE] __attribute__ ((aligned (4096)));
#endif
static struct ehci_hcd ms_ehci;
MS_U32 MsOS_USB_PA2KSEG1(MS_U32 addr)
{
//return ((MS_U32)(((MS_U32)addr) | 0x80000000));
return addr;
}
MS_U32 MsOS_USB_PA2KSEG0(MS_U32 addr)
{
//return ((MS_U32)(((MS_U32)addr) | 0x40000000));
return addr;
}
MS_U32 MsOS_USB_VA2PA(MS_U32 addr)
{
//return ((MS_U32)(((MS_U32)addr) & 0x1fffffff));
return addr;
}
/* ====================================================================
* Function Name: flib_Host20_Bulk_Init
* Description:
* Input: none
* OutPut: none
* ==================================================================== */
void flib_Host20_Bulk_Init(struct usb_device *dev, struct usb_hcd *hcd)
{
struct usb_endpoint_descriptor *ep,*ep2;
struct ehci_hcd *ehci = hcd->ehci;
MS_UINT8 ii;
ep = &dev->config.if_desc[0].ep_desc[0];
ep2 = &dev->config.if_desc[0].ep_desc[1];
USB_LIB_PRINTF("[USB] no_of_ep: %d\n", dev->config.if_desc[0].no_of_ep);
for (ii=0; ii<dev->config.if_desc[0].no_of_ep; ii++)
{
if (dev->config.if_desc[0].ep_desc[ii].bmAttributes == OTGH_ED_BULK)
{
USB_LIB_PRINTF("[USB] find bulk ep: %d\n", ii);
ep=&dev->config.if_desc[0].ep_desc[ii];
ii++;
break;
}
}
for (;ii<dev->config.if_desc[0].no_of_ep; ii++)
{
if (dev->config.if_desc[0].ep_desc[ii].bmAttributes == OTGH_ED_BULK)
{
USB_LIB_PRINTF("[USB] find bulk ep2: %d\n", ii);
ep2=&dev->config.if_desc[0].ep_desc[ii];
break;
}
}
USB_LIB_PRINTF("\n[USB] bulk max packet size: ep(%s) 0x%x, ep2(%s) 0x%x\n",
(ep->bEndpointAddress & 0x80) ? "in" : "out", ep->wMaxPacketSize,
(ep2->bEndpointAddress & 0x80) ? "in" : "out", ep2->wMaxPacketSize);
/* <5>.Hook the qHD */
if ((ep->bmAttributes)==OTGH_ED_BULK)
{
/* <5.1>.stop Asynchronous Schedule */
flib_Host20_Asynchronous_Setting(hcd, HOST20_Disable);
/* <5.2>.Hook the qHD for ED0~ED3 */
/* Circle the QH: CtrQH -> Bulk0QH -> Bulk1QH -> CtrQH */
ehci->qh_control1->bNextQHDPointer = (VA2PA((MS_UINT32)ehci->qh_bulk0) >> 5);
ehci->qh_bulk0->bNextQHDPointer = (VA2PA((MS_UINT32)ehci->qh_bulk1) >> 5);
ehci->qh_bulk1->bNextQHDPointer = (VA2PA((MS_UINT32)ehci->qh_control0) >> 5);
#if (_USB_FLUSH_BUFFER == 1)
/* make sure QH chain modification has flushed to mem */
Chip_Flush_Memory();
#endif
/* <5.2>.Enable Asynchronous Schedule */
flib_Host20_Asynchronous_Setting(hcd, HOST20_Enable);
}
#if 0 // moved to ubootglue.c
FirstBulkIn = 1;
FirstBulkOut = 1;
#endif
ehci->spBulkInqTD = NULL;
/* Setting Max Packet Size */
ehci->qh_bulk0->bMaxPacketSize = ep->wMaxPacketSize; //wMaxPacketSize;
ehci->qh_bulk1->bMaxPacketSize = ep2->wMaxPacketSize; //wMaxPacketSize;
/* set device address */
ehci->qh_bulk0->bDeviceAddress = dev->devnum;
ehci->qh_bulk1->bDeviceAddress = dev->devnum;
/* set endpoint# address */
ehci->qh_bulk0->bEdNumber = (ep->bEndpointAddress) & 0x0f;
ehci->qh_bulk1->bEdNumber = (ep2->bEndpointAddress) & 0x0f; //set endpoint address
ehci->ep_bulk0_dir = (((ep->bEndpointAddress) & 0x80) > 0) ? OTGH_Dir_IN : OTGH_Dir_Out;
USB_LIB_PRINTF("[USB] bulk0 is %s\n", ehci->ep_bulk0_dir ? "in" : "out");
}
/* ====================================================================
* Function Name: flib_Host20_Interrupt_Init
* Description:
* //Reserve=> <1>.If Periodic Enable => Disable Periodic
* <2>.Disable all the Frame List (Terminal=1)
* <3>.Hang the Interrupt-qHD-1 to Frame List
*
* Input: wInterval=1~16 => Full Speed => 1ms ~ 32 sec
* High Speed => 125us ~ 40.96 sec
* OutPut:
* ==================================================================== */
void flib_Host20_Interrupt_Init(struct usb_device *dev, struct usb_hcd *hcd)
{
MS_UINT32 i,j;
MS_UINT32 wSize;
MS_UINT8 x;
MS_UINT8 *pData;
MS_UINT16 wForceInterval = 0;
struct usb_interface *iface;
struct ehci_hcd *ehci = hcd->ehci;
MS_UINT32 ehci_base = hcd->ehc_base;
iface = &dev->config.if_desc[0];
/* <1>.Disable the Periodic */
flib_Host20_Periodic_Setting(hcd, HOST20_Disable);
/* <2>.Init qHD for Interrupt(7~9) Scan the ED */
x = mwHost20Port(ehci_base,0x10);
x = (x&0xF3)|((MS_UINT8)HOST20_USBCMD_FrameListSize_256<<2);
mwHost20Port_wr(ehci_base,0x10, x);
for (i=0; i < (iface->desc.bNumEndpoints); i++)
{
/* that is an interrupt endpoint */
if (iface->ep_desc[i].bmAttributes==OTGH_ED_INT)
{
wSize = iface->ep_desc[i].wMaxPacketSize;
wForceInterval = iface->ep_desc[i].bInterval;
ehci->qh_intr =(qHD_Structure*)KSEG02KSEG1(&Host20_qHD_List_Intr);
flush_cache((ulong)&Host20_qHD_List_Intr, sizeof(qHD_Structure));
pData=(MS_UINT8*)ehci->qh_intr;
for (j = 0; (j < sizeof(qHD_Structure)) && (j<Host20_qHD_SIZE); j++)
*(pData + j) = 0;
/* Address=0,Head=1,EndPt=0,Size */
flib_Host20_Allocate_QHD(hcd, ehci->qh_intr, HOST20_HD_Type_QH, dev->devnum, 0, (i+1), wSize);
ehci->qh_intr->bHighBandwidth = 1;
ehci->qh_intr->bInterruptScheduleMask = 1;
ehci->qh_intr->bEdSpeed = hcd->bSpeed;
ehci->qh_intr->bDataToggleControl = 0;
/* interrupt schedule */
ehci->qh_intr->bInterruptScheduleMask = 1;
/* 1~3, MULTI =1 */
ehci->qh_intr->bHighBandwidth = 1;
/* support only one interrupt pipe */
break;
}
}
/* point to itself */
ehci->qh_intr->bNextQHDPointer = (VA2PA((MS_UINT32)ehci->qh_intr) >> 5);
/* terminated */
ehci->qh_intr->bTerminate = 1;
ehci->spIntInqTD = NULL;
ehci->framelist = (Periodic_Frame_List_Structure*) KSEG02KSEG1(&Host20_FramList);
flush_cache((ulong)&Host20_FramList, sizeof(Periodic_Frame_List_Structure));
pData=(MS_UINT8 *)ehci->framelist;
for (j=0;j<sizeof(Periodic_Frame_List_Structure);j++)
*(pData+j)=0;
/* <3>.Link qHD to the FameListCell by wInterval */
for (i = 0; i < Host20_Preiodic_Frame_List_MAX; i++)
ehci->framelist->sCell[i].bTerminal = 1;
/* Find the Interval-X */
x = 0;
while(waIntervalMap[x]<wForceInterval)
{
x++;
if(x > 10)
{
MS_MSG("[USB] Interval Input Error...\n");
return;
}
};
for (i = 0; i < Host20_Preiodic_Frame_List_MAX; i = i + waIntervalMap[x])
{
ehci->framelist->sCell[i].bLinkPointer = (VA2PA((MS_UINT32)(ehci->qh_intr))>>5);
ehci->framelist->sCell[i].bTerminal = 0;
ehci->framelist->sCell[i].bType = HOST20_HD_Type_QH;
}
/* <4>.Set Periodic Base Address */
mwHost20_PeriodicBaseAddr_Set(hcd->ehc_base, VA2PA((MS_UINT32)ehci->framelist));
/* <5>.Enable the periodic */
flib_Host20_Periodic_Setting(hcd, HOST20_Enable);
}
/* ====================================================================
* Function Name: flib_Host20_Periodic_Setting
* Description:
* Input:
* OutPut:
* ==================================================================== */
void flib_Host20_Periodic_Setting(struct usb_hcd *hcd, MS_UINT8 bOption)
{
MS_UINT32 ehci_base = hcd->ehc_base;
MS_UINT32 polling_count = 0;
if (bOption == HOST20_Enable)
{
/* <1>.If Already enable => return */
if (mwHost20_USBSTS_PeriodicStatus_Rd(ehci_base) > 0)
return ;
/* <2>.Disable Periodic */
mbHost20_USBCMD_PeriodicEnable_Set(ehci_base);
/* <3>.Polling Status */
while (polling_count++ < 16 * 125) {
if (mwHost20_USBSTS_PeriodicStatus_Rd(ehci_base) > 0) {
return; /* succeed */
}
udelay(1); /* delay 1us */
}
/* timeout: 16 microframes */
MS_MSG("[USB] timeout when starting periodic schedule\n");
}
else if (bOption == HOST20_Disable)
{
/* <1>.If Already Disable => return */
if (mwHost20_USBSTS_PeriodicStatus_Rd(ehci_base) == 0)
return ;
/* <2>.Enable Periodic */
mbHost20_USBCMD_PeriodicEnable_Clr(ehci_base);
/* <3>.Polling Status */
while (polling_count++ < 16 * 125) {
if (mwHost20_USBSTS_PeriodicStatus_Rd(ehci_base) == 0) {
return; /* succeed */
}
udelay(1); /* delay 1us */
}
/* timeout: 16 microframes */
MS_MSG("[USB] timeout when stopping periodic schedule\n");
}
else
{
MS_MSG("[USB] ??? Input Error 'flib_Host20_Periodic_Setting'...\n");
}
}
/* ====================================================================
* Function Name: flib_Host20_Issue_Interrupt
* Description:
* Input:
* OutPut:
* ==================================================================== */
MS_UINT8 flib_Host20_Issue_Interrupt(struct usb_hcd *hcd, MS_UINT32 pwBuffer, MS_UINT16 hwSize)
{
qTD_Structure *spTempqTD;
struct ehci_hcd *ehci = hcd->ehci;
MS_UINT32 workbuf = 0;
MS_UINT8 bResult;
if ( pwBuffer != (MS_UINT32) KSEG02KSEG1(pwBuffer) )
{
flush_cache((ulong)pwBuffer,hwSize); //flush buffer to uncached buffer
#if (_USB_FLUSH_BUFFER == 1)
Chip_Flush_Memory();
#endif
pwBuffer=(MS_UINT32)KSEG02KSEG1(pwBuffer);
}
/* <1>.Fill TD */
/* The qTD will be release in the function "Send" */
spTempqTD = flib_Host20_GetStructure(hcd, Host20_MEM_TYPE_qTD);
if(spTempqTD == NULL)
return HOST20_FATAL;
workbuf = pwBuffer;
spTempqTD->bTotalBytes=hwSize;
/* cache issue, if cache enable */
spTempqTD->ArrayBufferPointer_Word[0] = VA2PA(workbuf);
spTempqTD->ArrayBufferPointer_Word[1] = 0;
spTempqTD->ArrayBufferPointer_Word[2] = 0;
spTempqTD->ArrayBufferPointer_Word[3] = 0;
spTempqTD->ArrayBufferPointer_Word[4] = 0;
/* <2>.Analysis the Direction */
spTempqTD->bPID=HOST20_qTD_PID_IN;
/* <3>.Send TD */
bResult=flib_Host20_Send_qTD2(hcd, spTempqTD, ehci->qh_intr, 10);
return bResult;
}
/* ====================================================================
* Function Name: flib_Host20_Issue_Interrupt_NonBlock
* Description:
* Input:
* OutPut:
* ==================================================================== */
MS_UINT8 flib_Host20_Issue_Interrupt_NonBlock(struct usb_hcd *hcd, MS_UINT32 pwBuffer, MS_UINT16 hwSize, MS_U32 *actual_len)
{
qTD_Structure *spTempqTD;
struct ehci_hcd *ehci = hcd->ehci;
MS_UINT32 workbuf = 0;
MS_UINT8 bResult=HOST20_OK;
if (mwHost20_PORTSC_ConnectStatus_Rd(hcd->ehc_base) == 0)
{
MS_MSG("[USB] Port%d device disconn\n", hcd->port_index);
bResult = HOST20_FATAL;
hcd->urb_status |= USB_ST_DISCONNECT;
flib_Host20_Periodic_Setting(hcd, HOST20_Disable);
ehci->qh_intr->bOverlay_Status=0; //clear halt status
flib_Host20_ReleaseStructure(hcd, Host20_MEM_TYPE_qTD, (MS_UINT32)ehci->spIntInqTD);
return bResult;
}
if (hcd->FirstIntIn == 1)
{
// If periodic still running then return, else release first qtd point
if (ehci->spIntInqTD->bStatus_Active==1)
hcd->IntrIn_Complete = 0;
else
{
hcd->IntrIn_Complete = 1;
hcd->FirstIntIn = 0;
*actual_len = (MS_UINT32)(hwSize - (MS_UINT16)ehci->spIntInqTD->bTotalBytes);
flib_Host20_ReleaseStructure(hcd, Host20_MEM_TYPE_qTD, (MS_UINT32)ehci->spIntInqTD);
}
return bResult;
}
hcd->IntrIn_Complete = 0;
hcd->FirstIntIn = 1;
ehci->spIntInqTD = (qTD_Structure*)PA2VA((( MS_UINT32)(ehci->qh_intr->bOverlay_NextqTD))<<5);
if ( pwBuffer != (MS_UINT32) KSEG02KSEG1(pwBuffer) )
{
flush_cache((ulong)pwBuffer,hwSize); //flush buffer to uncached buffer
#if (_USB_FLUSH_BUFFER == 1)
Chip_Flush_Memory();
#endif
pwBuffer=(MS_UINT32)KSEG02KSEG1(pwBuffer);
}
workbuf = pwBuffer;
/* <1>.Fill TD */
/* The qTD will be release in the function "Send" */
spTempqTD = flib_Host20_GetStructure(hcd, Host20_MEM_TYPE_qTD);
spTempqTD->bTotalBytes=hwSize;
/* cache issue, if cache enable */
spTempqTD->ArrayBufferPointer_Word[0] = VA2PA(workbuf);
spTempqTD->ArrayBufferPointer_Word[1] = 0;
spTempqTD->ArrayBufferPointer_Word[2] = 0;
spTempqTD->ArrayBufferPointer_Word[3] = 0;
spTempqTD->ArrayBufferPointer_Word[4] = 0;
/* <2>.Analysis the Direction */
spTempqTD->bPID=HOST20_qTD_PID_IN;
/* <3>.Send TD */
bResult=flib_Host20_Send_qTD_Intr(hcd, spTempqTD, ehci->qh_intr);
return bResult;
}
/* *********************************************************************************
* *********************************************************************************
* *** Group-1:Main Function ***
* *********************************************************************************
* ********************************************************************************* */
unsigned char mwHost20Port(int addr, int bOffset)
{
if (bOffset & 1)
return(*((MS_UINT8 volatile *) ( addr + bOffset*2 - 1)));
else /* even */
return(*((MS_UINT8 volatile *) ( addr + bOffset*2)));
}
void mwHost20Port_wr(int addr, int bOffset, int value)
{
if (bOffset & 1)
(*((MS_UINT8 volatile *) ( addr + bOffset*2 -1))) = value;
else /* even */
(*((MS_UINT8 volatile *) ( addr + bOffset*2))) = value;
}
/* bOffset should be 32 bits alignment */
void mwHost20Portw(int addr, int bOffset, int value)
{
*((MS_UINT32 volatile *)(addr + bOffset*2)) = value & 0xffff;
*((MS_UINT32 volatile *)(addr + bOffset*2 + 4)) = (value >> 16) & 0xffff;
}
int mwHost20Bit_Rd(int addr, int bByte, int wBitNum)
{
return (mwHost20Port(addr, bByte) & wBitNum);
}
void mwHost20Bit_Set(int addr, int bByte, int wBitNum)
{
MS_UINT8 temp;
temp = mwHost20Port(addr, bByte);
temp |= wBitNum;
mwHost20Port_wr(addr, bByte, temp);
}
void mwHost20Bit_Clr(int addr, int bByte, int wBitNum)
{
MS_UINT8 temp;
temp = mwHost20Port(addr, bByte);
temp &= ~wBitNum;
mwHost20Port_wr(addr, bByte,temp);
}
/* ====================================================================
* Function Name: flib_Host20_Init
* Description: Init the Host HW and prepare the ED/TD
* <1>.Init All the Data Structure
* <1.1>.Build control list
* <1.2>.Build Bulk list
* <1.3>.Build Interrupt list
* <1.4>.Build ISO list (Reserved)
* <2>.Reset the chip
* <3>.Set HW register
* <3.1>.Enable FIFO-Enable(0x100->Bit5) & FPGA-Mode-Half-Speed (0x100->Bit1)
* <3.2>.Enable interrupts
* <3.3>.Periodic List Base Address register
* <3.4>.USBCMD (Interrupt/Threshod/Frame List/Run-Stop)
*
* Input: wTimeWaitForConnect_ms:The time of waitting for connecting
* OutPut: 0:Device do not connect
* 1:Host init ok
* 2:Bus Rest Fail
* ==================================================================== */
MS_UINT8 flib_Host20_Init(struct usb_hcd *hcd, MS_UINT8 wForDevice_B, MS_UINT16 wDelay)
{
MS_UINT8 wValue = 0;
MS_UINT16 wTimer_ms = 0;
MS_UINT32 ehci_base = hcd->ehc_base;
MS_UINT32 utmi_base = hcd->utmi_base;
USB_DELAY(wDelay);
if (mwHost20_PORTSC_ConnectStatus_Rd(ehci_base) == 0)
{
MS_MSG("[USB] No USB is connecting\n");
return (0);
}
/* <1>.Waiting for the Device connect */
if (wForDevice_B == 0) {
/* host controller reset */
flib_Host20_Reset_HC(hcd);
}
wValue = 0;
wTimer_ms = 0;
do {
wValue = mwHost20_PORTSC_ConnectStatus_Rd(ehci_base);
if (wValue==0) {
/* 10, wait 1 ms */
USB_DELAY(1);
wTimer_ms++;
}
/* Case1:Waiting for 10 sec=10000 */
/* Case2:Waiting for 100 ms =100 */
if (wTimer_ms > wTimeWaitForConnect_ms)
{
MS_MSG("[USB] ??? Waiting for Peripheral Connecting Fail...\n");
return (0);
}
}while(wValue == 0);
mwHost20_Misc_EOF1Time_Set(ehci_base,Host20_EOF1Time);
/* <2>.Init All the Data Structure & write Base Address register */
flib_Host20_InitStructure(hcd);
/* Write Base Address to Register */
USB_LIB_PRINTF("[USB] Async base addr: 0x%x \n", hcd->ehci->async);
mwHost20_CurrentAsynchronousAddr_Set(ehci_base, hcd->ehci->async);
USB_LIB_PRINTF("[USB] Reg 0x28: 0x%lx 0x%lx\n", *((MS_UINT32 volatile *)(ehci_base + 0x28*2)),
*((MS_UINT32 volatile *)(ehci_base + 0x28*2 + 4)));
if (wForDevice_B == 0) {
if (flib_Host20_PortBusReset(hcd) > 0)
return(2);
}
if (hcd->bSpeed == 0) /* full speed */
{
mwHost20Bit_Clr(utmi_base, 0x9, MS_BIT7);
mwHost20_Misc_EOF1Time_Set(ehci_base, 2);
}
else if (hcd->bSpeed == 2) /* high speed */
{
/* HS rx robust enable */
mwHost20Bit_Set(utmi_base, 0x9, MS_BIT7);
mwHost20_Misc_EOF1Time_Set(ehci_base, 3);
}
flib_Host20_QHD_Control_Init(hcd);
return (1);
}
/* ====================================================================
* Function Name: flib_Host20_Close
* Description:
* <1>.Suspend Host
* <2>.Disable the interrupt
* <3>.Clear Interrupt Status
* <4>.Issue HW Reset
* <5>.Free the Allocated Memory
* Input:
* OutPut:
* ==================================================================== */
MS_UINT8 flib_Host20_Close(struct usb_hcd *hcd, MS_UINT8 bForDeviceB)
{
MS_UINT32 wTemp;
MS_UINT32 ehci_base = hcd->ehc_base;
if (mwHost20_USBINTR_Rd(ehci_base) > 0) {
/* <1>.Suspend Host */
if (bForDeviceB == 0)
{
flib_Host20_Suspend(hcd);
}
else
flib_Host20_StopRun_Setting(hcd, HOST20_Disable);
/* <2>.Disable the interrupt */
mwHost20_USBINTR_Set(ehci_base, 0);
/* <3>.Clear Interrupt Status */
wTemp = mwHost20_USBSTS_Rd(ehci_base);
wTemp = wTemp & 0x0000003F;
mwHost20_USBSTS_Set(ehci_base, wTemp);
}
return (1);
}
inline void flib_Host20_Fix_DataLength_ByteAlign(struct usb_hcd *hcd)
{
mwHost20Bit_Set(hcd->ehc_base, 0x81, MS_BIT6);
}
/* ====================================================================
* Function Name: flib_Host20_StopRun_Setting
* Description:
* Input:
* OutPut:
* ==================================================================== */
void flib_Host20_StopRun_Setting(struct usb_hcd *hcd, MS_UINT8 bOption)
{
MS_UINT32 ehci_base = hcd->ehc_base;
MS_UINT32 polling_count = 0;
if (bOption == HOST20_Enable) {
if (mbHost20_USBCMD_RunStop_Rd(ehci_base) > 0)
return;
mbHost20_USBCMD_RunStop_Set(ehci_base);
while (polling_count++ < 16 * 125) {
if (mwHost20_USBSTS_HCHalted_Rd(ehci_base) == 0) {
return; /* succeed */
}
udelay(1); /* delay 1us */
}
/* timeout: 16 microframes */
MS_MSG("[USB] timeout when starting HC\n");
}
else if (bOption == HOST20_Disable) {
if (mbHost20_USBCMD_RunStop_Rd(ehci_base) == 0)
return;
mbHost20_USBCMD_RunStop_Clr(ehci_base);
while (polling_count++ < 16 * 125) {
if (mwHost20_USBSTS_HCHalted_Rd(ehci_base) > 0) {
return; /* succeed */
}
udelay(1); /* delay 1us */
}
/* timeout: 16 microframes */
MS_MSG("[USB] timeout when stopping HC\n");
}
else {
MS_MSG("[USB] ??? Input Error 'flib_Host20_StopRun_Setting'...\n");
MS_MSG("[USB] USBCMD's Run/Stop bit remains unchanged\n");
}
}
/* ====================================================================
* Function Name: flib_Host20_Reset_HC
* Description:
* Input:
* OutPut:
* ==================================================================== */
void flib_Host20_Reset_HC(struct usb_hcd *hcd)
{
MS_UINT32 ehci_base = hcd->ehc_base;
MS_UINT32 tmp;
/* host controller reset */
mbHost20_USBCMD_HCReset_Set(ehci_base);
tmp = 0;
while(mbHost20_USBCMD_HCReset_Rd(ehci_base)>0)
{
tmp++;
USB_DELAY(1);
/* 100ms timeout*/
if(tmp > 100)
{
MS_MSG("[USB] can not reset UHC\n");
break;
}
}
}
/* ====================================================================
* Function Name: flib_Host20_Asynchronous_Setting
* Description:
* Input:
* OutPut:
* ==================================================================== */
void flib_Host20_Asynchronous_Setting(struct usb_hcd *hcd, MS_UINT8 bOption)
{
MS_UINT32 ehci_base = hcd->ehc_base;
MS_UINT32 polling_count = 0;
if (bOption == HOST20_Enable) {
if (mwHost20_USBSTS_AsynchronousStatus_Rd(ehci_base) > 0)
return;
mbHost20_USBCMD_AsynchronousEnable_Set(ehci_base);
while (polling_count++ < 16 * 125) {
if (mwHost20_USBSTS_AsynchronousStatus_Rd(ehci_base) > 0) {
return; /* succeed */
}
udelay(1); /* delay 1us */
}
/* timeout: 16 microframes */
MS_MSG("[USB] timeout when starting asynchronous schedule\n");
}
else if (bOption==HOST20_Disable) {
if (mwHost20_USBSTS_AsynchronousStatus_Rd(ehci_base) == 0)
return;
mbHost20_USBCMD_AsynchronousEnable_Clr(ehci_base);
while (polling_count++ < 16 * 125) {
if (mwHost20_USBSTS_AsynchronousStatus_Rd(ehci_base) == 0) {
return; /* succeed */
}
udelay(1); /* delay 1us */
}
/* timeout: 16 microframes */
MS_MSG("[USB] timeout when stopping asynchronous schedule\n");
}
else {
MS_MSG("[USB] ??? Input Error 'flib_Host20_Asynchronous_Setting'...\n");
// while(1);
}
}
#if defined( USB_BAD_DEVICE_RETRY_PATCH )
extern MS_BOOL force_FS;
void flib_Host20_ForceSpeed(struct usb_hcd *hcd, MS_U32 port)
{
MS_UINT32 ehci_base = hcd->ehc_base;
MS_MSG("[USB] flib_Host20_ForceSpeed ++\n");
writeb(readb(ehci_base+0x40*2) | 0x80, ehci_base+0x40*2); /* force full speed */
writeb(readb(ehci_base+0x34*2) | 0x40, ehci_base+0x34*2);
MS_MSG("[USB] Force HS Reg: %x\n", readb(ehci_base+0x40*2));
}
#endif
/* ====================================================================
* Function Name: flib_Host20_PortBusReset
* Description:
* <1>.Waiting for HCHalted=0
* <2>.Write PortEnable=0(Reserved for Faraday-IP)
* <3>.Write PortReset=0
* <4>.Wait time
* <5>.Write PortReset=0
* <6>.Waiting for IRS->PortChangeDetect
* Input:
* OutPut:
* ==================================================================== */
MS_UINT8 flib_Host20_PortBusReset(struct usb_hcd *hcd)
{
MS_UINT32 wTmp;
MS_UINT32 ehci_base = hcd->ehc_base;
MS_UINT32 utmi_base = hcd->utmi_base;
#if defined( USB_BAD_DEVICE_RETRY_PATCH )
if(force_FS == TRUE)
flib_Host20_ForceSpeed(hcd, hcd->port_index);
#endif
/* <1>.Disable RunStop */
USB_LIB_PRINTF("[USB] disable run\n");
if (mbHost20_USBCMD_RunStop_Rd(ehci_base) > 0)
flib_Host20_StopRun_Setting(hcd, HOST20_Disable);
/* <2>.Write PortReset=0 */
mwHost20Portw(utmi_base, 0x2C, 0x00000010);
mwHost20Port_wr(utmi_base, 0x2A, 0x80);
mwHost20_PORTSC_PortReset_Set(ehci_base);
/* <3>.Total Wait time=>70ms */
USB_DELAY(50);
mwHost20Port_wr(utmi_base, 0x2A, UTMI_DISCON_LEVEL_2A);
USB_DELAY(20);
// flib_Debug_LED_Off_All();; /* GPIO-High */
/* <4>.Write PortReset=0 */
mwHost20_PORTSC_PortReset_Clr(ehci_base);
mwHost20Portw(utmi_base, 0x2C, UTMI_ALL_EYE_SETTING);
/* <5>.Waiting for IRS->PortChangeDetect */
wTmp = 0;
while (1)
{
if (mwHost20_PORTSC_PortReset_Rd(ehci_base) == 0)
break;
wTmp++;
if (wTmp > 20000)
{
MS_MSG("[USB] ??? Error waiting for Bus Reset Fail...==> Reset HW Control\n");
flib_Host20_Reset_HC(hcd);
return (1);
}
}
#if 0
if (mwHost20_PORTSC_ForceSuspend_Rd())
{
USB_LIB_PRINTF("[USB] port suspend\n");
mwHost20_PORTSC_ForceResume_Set(); /* force resume */
USBDELAY(14);
mwHost20_PORTSC_ForceResume_Clr();
}
#endif
/* UTMI TX/RX Reset */
mwHost20Bit_Set(utmi_base, 0x6, MS_BIT0 | MS_BIT1);
mwHost20Bit_Clr(utmi_base, 0x6, MS_BIT0 | MS_BIT1);
/* <6>.Enable RunStop Bit */
flib_Host20_StopRun_Setting(hcd, HOST20_Enable);
/* wait some slow device to be ready */
USB_DELAY(5);
/* <7>.Detect Speed */
hcd->bSpeed= mwOTG20_Control_HOST_SPD_TYP_Rd(ehci_base);
MS_MSG ("[USB] Host Speed:%x \n", hcd->bSpeed);
/* <8>.Delay 20 ms ?? */
return (0);
}
/* ====================================================================
* Function Name: flib_Host20_Suspend
* Description:
* <1>.Make sure PortEnable=1
* <2>.Write PORTSC->Suspend=1
* <3>.Waiting for the ISR->PORTSC->Suspend=1
* Input:
* OutPut: 0:OK
* 1:Fail
* ==================================================================== */
MS_UINT8 flib_Host20_Suspend(struct usb_hcd *hcd)
{
MS_UINT32 ehci_base = hcd->ehc_base;
if (mbHost20_USBCMD_RunStop_Rd(ehci_base) == 0)
return(1);
/* <1>.Make sure PortEnable=1 */
if (mwHost20_PORTSC_EnableDisable_Rd(ehci_base) == 0)
return(1);
/* <2>.Write PORTSC->Suspend=1 */
/* For Faraday HW request */
flib_Host20_StopRun_Setting(hcd, HOST20_Disable);
/* <3>.Write PORTSC->Suspend=1 */
mwHost20_PORTSC_ForceSuspend_Set(ehci_base);
/* <4>.Waiting for the ISR->PORTSC->Suspend=1 */
#if 0
flib_Host20_TimerEnable_UnLock(1); /* 1sec */
bExitFlag = 0;
do {
if (mwHost20_PORTSC_ForceSuspend_Rd() > 0)
bExitFlag = 1;
if (gwOTG_Timer_Counter>5) {
bExitFlag = 1;
MS_MSG("[USB] >>> Fail => Time Out for Waiting ForceSuspend...\n");
}
}
while(bExitFlag==0);
#else
while(mwHost20_PORTSC_ForceSuspend_Rd(ehci_base)==0);
#endif
return (0);
}
/* ====================================================================
* Function Name: flib_Host20_Issue_Control
* Description:
* <1>.Analysis the Controller Command => 3 type
* <2>.Case-1:"Setup/In/Out' Format..."
* (get status/get descriptor/get configuration/get interface)
* <3>.Case-2:'Setup/In' Format... => Faraday Driver will not need
* (clear feature/set feature/set address/set Configuration/set interface )
* <4>.Case-3:'Setup/Out/In'
* (set descriptor)
* Input:
* OutPut: 0: OK
* X: >0 => Fail
* ==================================================================== */
MS_UINT8 flib_Host20_Issue_Control (struct usb_hcd *hcd, MS_UINT8 bEdNum, MS_UINT8* pbCmd, MS_UINT16 hwDataSize, MS_UINT8* pbData)
{
qTD_Structure *spTempqTD;
MS_UINT8 bReturnValue, bOneMore=1, bIsInput;
qHD_Structure *qh_ptr;
struct ehci_hcd *ehci = hcd->ehci;
if (bEdNum == 0)
qh_ptr = ehci->qh_control0;
else
{
ehci->qh_control1->bDeviceAddress = bEdNum;
qh_ptr = ehci->qh_control1;
}
/* <0>.Allocate qTD & Data Buffer */
/* 0=>qTD */
spTempqTD = flib_Host20_GetStructure(hcd, Host20_MEM_TYPE_qTD);
if(spTempqTD == NULL){
return HOST20_FATAL;
}
/* <2.1>.Setup packet */
/* <A>.Fill qTD */
spTempqTD->bPID = HOST20_qTD_PID_SETUP; /* Bit8~9 */
spTempqTD->bTotalBytes = 8; /* Bit16~30 */
spTempqTD->bDataToggle = 0; /* Bit31 */
memcpy(ehci->ep0_buffer, pbCmd, 8);
spTempqTD->ArrayBufferPointer_Word[0] = VA2PA((MS_UINT32)ehci->ep0_buffer);
/* debug dump QTD data */
// Dump_QTD(spTempqTD);
// Dump_Data(XXX, XXX);
/* <B>.Send qTD */
bReturnValue= flib_Host20_Send_qTD(hcd, spTempqTD, qh_ptr, Host20_Ctrl_Timeout);
if (bReturnValue > 0)
goto exit_issue_control;
/* <1>.Analysis the Controller Command */
#if 1
bIsInput = usb_pipein(*pbCmd);
if (hwDataSize > 0)
/* Data Stage */
{
/* <A>.Fill qTD */
/* 0=>qTD */
spTempqTD = flib_Host20_GetStructure(hcd, Host20_MEM_TYPE_qTD);
if(spTempqTD == NULL){
return HOST20_FATAL;
}
if (bIsInput)
spTempqTD->bPID = HOST20_qTD_PID_IN; /* Bit8~9 */
else
{
spTempqTD->bPID = HOST20_qTD_PID_OUT; /* Bit8~9 */
memcpy(ehci->ep0_buffer, pbData, hwDataSize);
}
spTempqTD->bTotalBytes = hwDataSize; /* Bit16~30 */
spTempqTD->bDataToggle = 1; /* Bit31 */
spTempqTD->ArrayBufferPointer_Word[0] = VA2PA((MS_UINT32)ehci->ep0_buffer);
/* <B>.Send qTD */
bReturnValue = flib_Host20_Send_qTD(hcd, spTempqTD, qh_ptr,Host20_Ctrl_Timeout);
if (bReturnValue>0)
goto exit_issue_control;
/* <C>.Waiting for result */
if (bIsInput)
memcpy((MS_UINT8 *)pbData, ehci->ep0_buffer, hwDataSize);
// Dump_Data((MS_UINT16)pbData, hwDataSize);
}
// Send short packet
if (bOneMore)
{
spTempqTD=flib_Host20_GetStructure(hcd, Host20_MEM_TYPE_qTD);
if(spTempqTD == NULL){
return HOST20_FATAL;
}
if (bIsInput)
spTempqTD->bPID = HOST20_qTD_PID_OUT; /* Bit8~9 */
else
spTempqTD->bPID = HOST20_qTD_PID_IN; /* Bit8~9 */
spTempqTD->bTotalBytes = 0; /* Bit16~30 */
spTempqTD->bDataToggle = 1; /* Bit31 */
bReturnValue = flib_Host20_Send_qTD(hcd, spTempqTD, qh_ptr, Host20_Ctrl_Timeout);
if (bReturnValue > 0)
goto exit_issue_control;
}
#else
USB_LIB_PRINTF("usb_pipein:%d\n",usb_pipein(*pbCmd));
USB_LIB_PRINTF("hwDataSize:%d\n",hwDataSize);
/* by Standard Request codes */
switch (*(pbCmd + 1)) {
/* <2>.Case-1:"Setup/In/Out' Format..." */
case 0: /* get status */
case 6: /* get descriptor */
case 8: /* get configuration */
case 10: /* get interface */
case 0xfe: /* get Max Lun */
/* <2.2>.In packet */
SetupRead:
/* <A>.Fill qTD */
/* 0=>qTD */
spTempqTD = flib_Host20_GetStructure(hcd, Host20_MEM_TYPE_qTD);
if(spTempqTD == NULL){
return HOST20_FATAL;
}
spTempqTD->bPID = HOST20_qTD_PID_IN; /* Bit8~9 */
spTempqTD->bTotalBytes = hwDataSize; /* Bit16~30 */
spTempqTD->bDataToggle = 1; /* Bit31 */
spTempqTD->ArrayBufferPointer_Word[0] = VA2PA((MS_UINT32)ehci->ep0_buffer);
/* <B>.Send qTD */
bReturnValue = flib_Host20_Send_qTD(hcd, spTempqTD, qh_ptr,Host20_Ctrl_Timeout);
if (bReturnValue>0)
goto exit_issue_control;
/* <C>.Waiting for result */
memcpy((MS_UINT8 *)pbData, ehci->ep0_buffer, hwDataSize);
// Dump_Data((MS_UINT16)pbData, hwDataSize);
/* <2.3>.Out packet */
/* <A>.Fill qTD */
/* 0=>qTD */
spTempqTD=flib_Host20_GetStructure(hcd, Host20_MEM_TYPE_qTD);
if(spTempqTD == NULL){
return HOST20_FATAL;
}
spTempqTD->bPID = HOST20_qTD_PID_OUT; /* Bit8~9 */
spTempqTD->bTotalBytes = 0; /* Bit16~30 */
spTempqTD->bDataToggle = 1; /* Bit31 */
/* <B>.Send qTD */
bReturnValue = flib_Host20_Send_qTD(hcd, spTempqTD, qh_ptr, Host20_Ctrl_Timeout);
if (bReturnValue > 0)
goto exit_issue_control;
break;
/* <3>.Case-2:'Setup/In' Format... => Faraday Driver will not need */
case 0xf0: /* read */
case 0xf1: /* write */
if (*(pbCmd) == 0xc0)
goto SetupRead;
else if (*(pbCmd) == 0x40)
goto SetupWrite;
break;
case 1: /* clear feature */
case 3: /* set feature */
case 5: /* set address */
case 9: /* set Configuration */
case 11: /* set interface */
case 0xff: /* device reset */
/* <3.2>.In packet */
/* <A>.Fill qTD */
/* 0=>qTD */
spTempqTD = flib_Host20_GetStructure(hcd, Host20_MEM_TYPE_qTD);
if(spTempqTD == NULL){
return HOST20_FATAL;
}
spTempqTD->bPID = HOST20_qTD_PID_IN; /* Bit8~9 */
spTempqTD->bTotalBytes = hwDataSize; /* Bit16~30 */
spTempqTD->bDataToggle = 1; /* Bit31 */
spTempqTD->ArrayBufferPointer_Word[0] = VA2PA((MS_UINT32)ehci->ep0_buffer);
/* <B>.Send qTD */
bReturnValue = flib_Host20_Send_qTD(hcd, spTempqTD, qh_ptr, Host20_Ctrl_Timeout);
if (bReturnValue > 0)
goto exit_issue_control;
/* <C>.Copy Result */
// memcpy(pbData,pUsbCtrlBuf, hwDataSize);
break;
/* <4>.Case-3:'Setup/Out/In' */
case 7: /* set descriptor */
/* <4.2>.Out packet */
/* <A>.Fill qTD */
SetupWrite:
/* 0=>qTD */
spTempqTD = flib_Host20_GetStructure(hcd, Host20_MEM_TYPE_qTD);
if(spTempqTD == NULL){
return HOST20_FATAL;
}
spTempqTD->bPID = HOST20_qTD_PID_OUT; /* Bit8~9 */
spTempqTD->bTotalBytes = hwDataSize; /* Bit16~30 */
spTempqTD->bDataToggle = 1; /* Bit31 */
spTempqTD->ArrayBufferPointer_Word[0] = VA2PA((MS_UINT32)ehci->ep0_buffer);
memcpy(ehci->ep0_buffer, pbData, hwDataSize);
/* <B>.Send qTD */
bReturnValue = flib_Host20_Send_qTD(hcd, spTempqTD, qh_ptr, Host20_Ctrl_Timeout);
if (bReturnValue > 0)
goto exit_issue_control;
/* <4.3>.In packet */
/* <A>.Fill qTD */
/* 0=>qTD */
spTempqTD=flib_Host20_GetStructure(hcd, Host20_MEM_TYPE_qTD);
if(spTempqTD == NULL){
return HOST20_FATAL;
}
spTempqTD->bPID = HOST20_qTD_PID_IN; /* Bit8~9 */
spTempqTD->bTotalBytes = 0; /* Bit16~30 */
spTempqTD->bDataToggle = 1; /* Bit31 */
/* <B>.Send qTD */
bReturnValue = flib_Host20_Send_qTD(hcd, spTempqTD, qh_ptr, Host20_Ctrl_Timeout);
if (bReturnValue > 0)
goto exit_issue_control;
break;
default:
if (*(pbCmd) & 0x80)
goto SetupRead;
else if (!(*(pbCmd) & 0x80))
goto SetupWrite;
break;
}
#endif
return (0);
exit_issue_control:
return (bReturnValue);
}
void Dump_QTD(MS_UINT32 addr)
{
MS_UINT8 i;
USB_LIB_PRINTF("[USB] QH/QTD:%lx -> \n", addr);
for (i = 0; i < 0x20 ; i = i+4)
{
USB_LIB_PRINTF("%x ", *(unsigned char volatile *)(addr + i+ 3));
USB_LIB_PRINTF("%x ", *(unsigned char volatile *)(addr + i+ 2));
USB_LIB_PRINTF("%x ", *(unsigned char volatile *)(addr + i+ 1));
USB_LIB_PRINTF("%x ", *(unsigned char volatile *)(addr + i));
USB_LIB_PRINTF("\n");
}
}
void Dump_Data(MS_UINT32 addr, MS_UINT16 sz)
{
MS_UINT16 i, xxx=0;
USB_LIB_PRINTF("[USB] addr:%lx -> \n", addr);
while (sz >= 0x10)
{
USB_LIB_PRINTF("\nADDR %x -> ", xxx);
for (i = 0; i < 0x10; i++)
USB_LIB_PRINTF("%x ", *(unsigned char volatile *)(addr + i));
sz -= 0x10;
addr += 0x10;
xxx += 0x10;
}
USB_LIB_PRINTF("\nADDR %x -> ", xxx);
for (i = 0; i < sz ; i++)
USB_LIB_PRINTF("%02x ", *(unsigned char volatile *)(addr + i));
}
MS_UINT8 flib_Host20_Send_Receive_Bulk_Data(struct usb_hcd *hcd, void *buffer, int len, int dir_out)
{
MS_UINT32 wTotalLengthRemain = 0;
MS_UINT32 buf = 0;
MS_UINT8 result = 0;
MS_UINT32 TransferLen = 0;
MS_UINT32 TransBuf;
/* <1>.To fill the data buffer */
wTotalLengthRemain = len;
buf = (MS_UINT32)buffer;
/* <2>.Issue Transfer */
while (wTotalLengthRemain)
{
if(wTotalLengthRemain > Scsi_Max_Transfer_Len)
TransferLen = Scsi_Max_Transfer_Len;
else
TransferLen = wTotalLengthRemain;
if (dir_out)
{
#if defined(CONFIG_USB_BOUNCE_BUF_PATCH)
TransBuf = (MS_UINT32) usb_bounce_buf;
memcpy((void*)TransBuf, (void*)buf, TransferLen);
#else
TransBuf = buf;
#endif
result = flib_Host20_Issue_Bulk (hcd, TransferLen
, TransBuf, OTGH_Dir_Out);
if (result != HOST20_OK)
return result;
}
else
{
#if defined(CONFIG_USB_BOUNCE_BUF_PATCH)
TransBuf = (MS_UINT32) usb_bounce_buf;
#else
TransBuf = buf;
#endif
result = flib_Host20_Issue_Bulk (hcd, TransferLen
, TransBuf, OTGH_Dir_IN);
if (result != HOST20_OK)
return result;
#if defined(CONFIG_USB_BOUNCE_BUF_PATCH)
memcpy((void*)buf, (void*)TransBuf, TransferLen);
#endif
}
buf += TransferLen;
wTotalLengthRemain -= TransferLen;
}
return(result);
}
/* ====================================================================
* Function Name: flib_Host20_Issue_Bulk
* Description: Input data must be 4K-Alignment
* <1>.MaxSize=20 K
* <2>.Support Only 1-TD
* Input:
* OutPut:
* ==================================================================== */
MS_UINT8 flib_Host20_Issue_Bulk (struct usb_hcd *hcd, MS_UINT32 hwSize, MS_UINT32 pwBuffer, MS_UINT8 bDirection)
{
MS_UINT8 bTemp = 0, i = 0;
MS_UINT32 count = 0;
MS_UINT32 addr = 0, workbuf = 0;
#if defined(USB_BUF_ALIGNED_PATCH)
MS_UINT32 mybuf = 0;
#endif
#if 0
int TranSize = 0;
#endif
qTD_Structure *spTempqTD = NULL;
qHD_Structure *spTempqH = NULL;
struct ehci_hcd *ehci = hcd->ehci;
if (pwBuffer !=(MS_UINT32) KSEG02KSEG1(pwBuffer) )
{
#if defined(USB_BUF_ALIGNED_PATCH)
/* ?? any buf issue template */
/* flush should be 8 bytes aligned */
if (pwBuffer & 0x7)
{
USB_LIB_PRINTF("[USB] Use 8byte aligned buf\n");
mybuf = (MS_UINT32) KSEG02KSEG1(usb_temp_buf);
if (mybuf)
{
MS_MSG("[USB] usb memory get uncache buf failed!\n");
return HOST20_FATAL;
}
}
else
#endif
{
USB_LIB_BULK_PRINTF("[USB] Flush Data & MIU PIPE\n");
/* flush/invalidate data to DRAM */
flush_cache((ulong)pwBuffer,hwSize);
#if (_USB_FLUSH_BUFFER == 1)
Chip_Flush_Memory();
#endif
/* uncached buffer */
pwBuffer=(MS_UINT32)KSEG02KSEG1(pwBuffer);
}
}
#if defined(USB_BUF_ALIGNED_PATCH)
/* ?? any buf issue template */
else
{
/* flush should be 8 bytes aligned */
if (pwBuffer & 0x7)
{
USB_LIB_PRINTF("[USB] Use 8byte aligned buf\n");
mybuf = (MS_UINT32) KSEG02KSEG1(usb_temp_buf);
if(mybuf)
{
MS_MSG("[USB] usb memory get uncache buf failed!\n");
return HOST20_FATAL;
}
}
}
#endif
/* The qTD will be release in the function "Send" */
spTempqTD = flib_Host20_GetStructure(hcd, Host20_MEM_TYPE_qTD);
if(spTempqTD == NULL) {
return HOST20_FATAL;
}
spTempqTD->bTotalBytes = hwSize ;
/* not allow buffer over 16K for my usage */
#if defined(USB_BUF_ALIGNED_PATCH)
/* ?? any buf issue template */
/* use original buf */
if (!mybuf)
workbuf = mybuf;
else
#endif
workbuf = pwBuffer;
spTempqTD->ArrayBufferPointer_Word[0] = VA2PA(workbuf);
/* rest of that page */
count = 0x1000 - (workbuf & 0x0fff);
/* ... iff needed */
if ( hwSize < count)
count = hwSize;
else
{
workbuf += 0x1000;
workbuf &= ~0x0fff;
/* per-qtd limit: from 16K to 20K (best alignment) */
for (i = 1; (count < hwSize) && (i < 5); i++)
{
addr = workbuf;
spTempqTD->ArrayBufferPointer_Word[i] = VA2PA(addr);
workbuf += 0x1000;
if ((count + 0x1000) < hwSize)
count += 0x1000;
else
count = hwSize;
}
}
spTempqH = (bDirection == ehci->ep_bulk0_dir) ? ehci->qh_bulk0 : ehci->qh_bulk1;
USB_LIB_BULK_PRINTF("[USB] direction: %s, using qh_bulk%d\n",
bDirection ? "in" : "out",
(bDirection == ehci->ep_bulk0_dir) ? 0 : 1);
/* <2>.Analysis the Direction */
if (bDirection==OTGH_Dir_IN)
{
spTempqTD->bPID = HOST20_qTD_PID_IN;
if (hcd->FirstBulkIn)
{
spTempqTD->bDataToggle = 0;
spTempqH->bDataToggleControl = 1;
}
}
else
{
spTempqTD->bPID=HOST20_qTD_PID_OUT;
if (hcd->FirstBulkOut)
{
spTempqTD->bDataToggle = 0;
spTempqH->bDataToggleControl = 1;
}
#if defined(USB_BUF_ALIGNED_PATCH)
/* ?? any buf issue template */
if (mybuf)
memcpy((void*)mybuf, (void*)pwBuffer, hwSize); /* copy to 8byte aligned buffer */
#endif
}
/* <3>.Send TD */
bTemp = flib_Host20_Send_qTD(hcd, spTempqTD ,spTempqH,Host20_Timeout);
if ((hcd->FirstBulkIn) && (bDirection==OTGH_Dir_IN))
{
spTempqH->bDataToggleControl = 0;
hcd->FirstBulkIn = 0;
}
if ((hcd->FirstBulkOut) && (bDirection==OTGH_Dir_Out))
{
spTempqH->bDataToggleControl = 0;
hcd->FirstBulkOut = 0;
}
if (bDirection == OTGH_Dir_IN)
{
#if defined(USB_BUF_ALIGNED_PATCH)
/* ?? any buf issue template */
if (mybuf)
memcpy((void*)pwBuffer, (void*)mybuf, hwSize); /* copy from 8byte aligned buffer */
#endif
#if 0
TranSize = hwSize - hcd->total_bytes;
if ((TranSize % 8) == 7)
{
USB_LIB_PRINTF("[USB] patch wallace bug\n");
*((MS_UINT8*)workbuf+TranSize-1)=*((MS_UINT8*)workbuf+TranSize+3); //fix hardware bug
}
else if ((TranSize % 8)==3)
{
USB_LIB_PRINTF("[USB] patch wallace bug\n");
*((MS_UINT8*)workbuf+TranSize-1)=*((MS_UINT8*)workbuf+TranSize+7); //fix hardware bug
}
#endif
}
return (bTemp);
}
/* **********************************************************************************
* **********************************************************************************
*** Group-4:Structure Function ***
* **********************************************************************************
* ********************************************************************************** */
/* ====================================================================
* Function Name: flib_Host20_InitStructure
* Description:
* 1.Init qHD for Control
* qHD_C-->qHD_C-->qHD_C
* 2.Init qHD for Bulk
* |-------------------------|
* qHD_C-->qHD_C-->qHD_B-->qHD_B
*
* 3.Init qHD for Interrupt
* 4.Init iTD for ISO (Reserved for feature)
* Input:Type =0 =>iTD
* =1 =>qTD
* =2
* OutPut: 0:Fail
* 1:ok
*==================================================================== */
void flib_Host20_InitStructure(struct usb_hcd *hcd)
{
MS_UINT16 i;
MS_UINT8 *pData;
struct ehci_hcd *ehci;
hcd->ehci = &ms_ehci;
ehci = hcd->ehci;
ehci->ep0_buffer = (MS_UINT8 *)KSEG02KSEG1(UsbCtrlBuf);
ehci->qtd_pool = (MS_UINT8 *)KSEG02KSEG1(QtdBuf);
flush_cache((ulong)UsbDataBuf, sizeof(UsbDataBuf));
hcd->ehci->pUsbDataBuf = (MS_UINT8 *)KSEG02KSEG1(UsbDataBuf);
/* <1>.Clear memory */
pData = ehci->qtd_pool;
for (i=0 ; i < (Host20_qTD_SIZE*Host20_qTD_MAX+0x20) ; i++)
pData[i]=0;
//if ((MS_UINT32)Host20_STRUCTURE_qTD_BASE_ADDRESS & 0x10)
// Host20_STRUCTURE_qTD_BASE_ADDRESS += 0x10; /* make it aligned with 32 */
ehci->qh_control0 = (qHD_Structure*)KSEG02KSEG1(&Host20_qHD_List_Control0);
ehci->qh_control1 = (qHD_Structure*)KSEG02KSEG1(&Host20_qHD_List_Control1);
ehci->qh_bulk0 = (qHD_Structure*)KSEG02KSEG1(&Host20_qHD_List_Bulk0);
ehci->qh_bulk1 = (qHD_Structure*)KSEG02KSEG1(&Host20_qHD_List_Bulk1);
pData = (MS_UINT8*)ehci->qh_control0;
for (i = 0 ; i < sizeof(qHD_Structure); i++)
pData[i]=0;
pData = (MS_UINT8*)ehci->qh_control1;
for (i = 0 ; i < sizeof(qHD_Structure); i++)
pData[i]=0;
pData = (MS_UINT8*)ehci->qh_bulk0;
for (i = 0 ; i < sizeof(qHD_Structure); i++)
pData[i]=0;
pData = (MS_UINT8*)ehci->qh_bulk1;
for ( i=0 ; i < sizeof(qHD_Structure); i++)
pData[i]=0;
ehci->async = VA2PA((MS_UINT32)ehci->qh_control0);
/* <2>.For qTD & iTD & 4K-Buffer Manage init */
ehci->qtd_manage = &Host20_qTD_Manage[0];
for (i = 0;i < Host20_qTD_MAX; i++)
ehci->qtd_manage[i] = Host20_MEM_FREE;
// psHost20_qHD_List_Control[0]->bType = HOST20_HD_Type_QH;
/* Address=0,Head=1,EndPt=0,Size */
flib_Host20_Allocate_QHD(hcd, ehci->qh_control0, HOST20_HD_Type_QH, 0, 1, 0, 64);
/* Address=1,Head=0,EndPt=0,Size */
flib_Host20_Allocate_QHD(hcd, ehci->qh_control1, HOST20_HD_Type_QH, 1, 0, 0, 64);
/* Address=1,Head=0,EndPt=1,Size */
flib_Host20_Allocate_QHD(hcd, ehci->qh_bulk0, HOST20_HD_Type_QH, 1, 0, 1, 64);
/* Address=1,Head=0,EndPt=2,Size */
flib_Host20_Allocate_QHD(hcd, ehci->qh_bulk1, HOST20_HD_Type_QH, 1, 0, 2, 64);
/* <3.3>.Link the qHD (contol) */
ehci->qh_control0->bNextQHDPointer = (VA2PA((MS_UINT32)ehci->qh_control1) >>5);
ehci->qh_control1->bNextQHDPointer = (VA2PA((MS_UINT32)ehci->qh_control0) >>5);
/* for QHs address checking*/
#if 0
MS_MSG("ctrl0 %x size %x\n", &Host20_qHD_List_Control0, sizeof(qHD_Structure));
MS_MSG("ctrl1 %x size %x\n", &Host20_qHD_List_Control1, sizeof(qHD_Structure));
MS_MSG("bulk0 %x size %x\n", &Host20_qHD_List_Bulk0, sizeof(qHD_Structure));
MS_MSG("bulk1 %x size %x\n", &Host20_qHD_List_Bulk1, sizeof(qHD_Structure));
#endif
}
/* ====================================================================
* Function Name: flib_Host20_GetStructure
* Description:
*
* Input:Type =0 =>qTD
* =1 =>iTD
* =2 =>4K Buffer
* OutPut: 0:Fail
* ~0:Addrress
* ==================================================================== */
qTD_Structure *flib_Host20_GetStructure(struct usb_hcd *hcd, MS_UINT8 Type)
{
MS_UINT32 i;
MS_UINT8 bFound = 0;
qTD_Structure *spTempqTD;
struct ehci_hcd *ehci = hcd->ehci;
switch(Type)
{
// For qTD
case Host20_MEM_TYPE_qTD:
for (i = 0;i < Host20_qTD_MAX; i++)
if (ehci->qtd_manage[i] == Host20_MEM_FREE)
{
bFound = 1;
ehci->qtd_manage[i] = Host20_MEM_USED;
break;
}
if (bFound == 1)
{
spTempqTD = (qTD_Structure *)((MS_UINT32)ehci->qtd_pool + i*Host20_qTD_SIZE);
memset((unsigned char *)spTempqTD, 0, Host20_qTD_SIZE);
spTempqTD->bTerminate = 1; /* Bit0 */
spTempqTD->bStatus_Active = 0; /* Bit7 */
spTempqTD->bInterruptOnComplete = 1; /* Bit15 */
spTempqTD->bAlternateTerminate = 1;
spTempqTD->bErrorCounter = 3;
// USB_LIB_PRINTF("[USB] get QTD:%x\n", (MS_U32) spTempqTD);
return (spTempqTD);
}
else
MS_MSG("[USB] QTD underrun!\n");
break;
default:
return 0;
break;
}
/* Not Found... */
return (0);
}
/* ====================================================================
* Function Name: flib_Host20_ReleaseStructure
* Description:
*
* Input:Type =0 =>qTD
* =1 =>iTD
* =2
* OutPut: 0:Fail
* ~0:Addrress
*==================================================================== */
void flib_Host20_ReleaseStructure(struct usb_hcd *hcd, MS_UINT8 Type, MS_UINT32 pwAddress)
{
MS_UINT8 i;
MS_UINT32 wReleaseNum;
MS_UINT8 *pData;
struct ehci_hcd *ehci = hcd->ehci;
// USB_LIB_PRINTF("[USB] release QTD:%x\n",pwAddress);
pData = (MS_UINT8*)pwAddress;
switch(Type)
{
case Host20_MEM_TYPE_qTD:
if (pwAddress<(MS_UINT32)ehci->qtd_pool)
{
MS_MSG("[USB] ??? Memory release area fail...\n");
return;
}
if ((pwAddress-(MS_UINT32)ehci->qtd_pool) == 0)
wReleaseNum = 0;
else
wReleaseNum=(pwAddress-(MS_UINT32)ehci->qtd_pool)/Host20_qTD_SIZE;
/* ERROR FIX Prevent Tool 070522 */
if (wReleaseNum >= Host20_qTD_MAX)
{
MS_MSG("[USB] ??? Memory release area fail...\n");
return;
}
ehci->qtd_manage[wReleaseNum]=Host20_MEM_FREE;
/* qTD size=32 bytes */
for (i = 0;i < Host20_qTD_SIZE; i++)
*(pData+i) = 0;
break;
}
}
/* ====================================================================
* Function Name: flib_Host20_QHD_Control_Init
* Description:
*
* Input:Type =0 =>qTD
* =1 =>iTD
* =2
* OutPut: 0:Fail
* ~0:Addrress
* ==================================================================== */
void flib_Host20_QHD_Control_Init(struct usb_hcd *hcd)
{
struct ehci_hcd *ehci = hcd->ehci;
/* <1>.Init Control-0/1 */
ehci->qh_control0->bEdSpeed = hcd->bSpeed;
ehci->qh_control0->bInactiveOnNextTransaction = 0;
ehci->qh_control0->bDataToggleControl = 1;
ehci->qh_control1->bEdSpeed = hcd->bSpeed;
ehci->qh_control1->bInactiveOnNextTransaction = 0;
ehci->qh_control1->bDataToggleControl = 1;
/* <2>.Init Bulk-0/1 */
ehci->qh_bulk0->bEdSpeed = hcd->bSpeed;
ehci->qh_bulk0->bInactiveOnNextTransaction = 0;
ehci->qh_bulk0->bDataToggleControl = 0;
ehci->qh_bulk1->bEdSpeed = hcd->bSpeed;
ehci->qh_bulk1->bInactiveOnNextTransaction = 0;
ehci->qh_bulk1->bDataToggleControl = 0;
/* <12>.Enable Asynchronous */
USB_LIB_PRINTF("[USB] enable aynch \n");
mbHost20_USBCMD_AsynchronousEnable_Set(hcd->ehc_base); /* Temp;;Bruce */
}
void flib_Host20_SetControl1MaxPacket(struct usb_hcd *hcd, MS_UINT8 max)
{
struct ehci_hcd *ehci = hcd->ehci;
ehci->qh_control1->bMaxPacketSize = max;
USB_LIB_PRINTF("[USB] control1 max:%x\n", ehci->qh_control1->bMaxPacketSize);
}
/* ====================================================================
* Function Name: flib_Host20_Allocate_QHD
* Description:
*
* Input:Type =0 =>qTD
* =1 =>iTD
* =2
* OutPut: 0:Fail
* ~0:Addrress
* ==================================================================== */
void flib_Host20_Allocate_QHD(struct usb_hcd *hcd, qHD_Structure *psQHTemp, MS_UINT8 bNextType, MS_UINT8 bAddress, MS_UINT8 bHead, MS_UINT8 bEndPt, MS_UINT32 wMaxPacketSize)
{
qTD_Structure *spTempqTD;
psQHTemp->bTerminate = 0; /* Bit0 */
psQHTemp->bType = bNextType; /* Bit2~1 */
psQHTemp->bDeviceAddress = bAddress; /* Bit0~6 */
psQHTemp->bEdNumber = bEndPt; /* Bit11~8 */
psQHTemp->bHeadOfReclamationListFlag = bHead; /* Bit15 */
psQHTemp->bMaxPacketSize = wMaxPacketSize; /* Bit16~26 */
psQHTemp->bNakCounter = Host20_QHD_Nat_Counter;
psQHTemp->bOverlay_NextTerminate = 1;
psQHTemp->bOverlay_AlternateNextTerminate = 1;
/* <2>.allocate dumy qTD */
/* <2.1>.Allocate qTD */
spTempqTD = flib_Host20_GetStructure(hcd, Host20_MEM_TYPE_qTD); /* 0=>qTD */
psQHTemp->bOverlay_NextqTD = (VA2PA((MS_UINT32)spTempqTD) >> 5);
/* <2.3>.Active the qTD */
psQHTemp->bOverlay_NextTerminate = 0;
}
/* ====================================================================
* Function Name: flib_Host20_CheckingForResult_QHD
* Description:
* Input:Type
* OutPut:
* ==================================================================== */
MS_UINT8 flib_Host20_CheckingForResult_QHD(struct usb_hcd *hcd, qHD_Structure *spTempqHD)
{
MS_UINT32 bQHStatus;
MS_UINT16 wIntStatus;
struct ehci_hcd *ehci = hcd->ehci;
wIntStatus = mwHost20_USBSTS_Rd(hcd->ehc_base);
hcd->urb_status = 0;
/* <2>.Checking for the Error type interrupt => Halt the system */
if (wIntStatus & HOST20_USBINTR_SystemError)
{
MS_MSG("[USB] USBSTS System Error... Halt the system...\n");
ehci->bSendStatusError = 1;
}
if (wIntStatus & HOST20_USBINTR_USBError) {
MS_MSG("[USB] USBSTS USB Error...\n");
mwHost20_USBSTS_USBError_Set(hcd->ehc_base);
ehci->bSendStatusError = 1;
}
if (ehci->bSendStatusError == 0)
return HOST20_OK;
USB_LIB_PRINTF("[USB] Send Error USBSTS Status:%x\n",wIntStatus);
/* <1>.Analysis the qHD Status */
ehci->bSendStatusError = 0;
MS_MSG("[USB] USB Error Interrupt Event...\n");
bQHStatus = spTempqHD->bOverlay_Status;
USB_LIB_PRINTF("[USB] bQHStatus:%lx\n",bQHStatus);
/* stop to check ehci status */
// while (1) {};
if (bQHStatus & HOST20_qTD_STATUS_Halted)
{
/* clear halt status */
spTempqHD->bOverlay_Status = 0;
spTempqHD->bOverlay_TotalBytes = 0;
spTempqHD->bOverlay_Direction = 0;
/* no other error status */
if (bQHStatus == HOST20_qTD_STATUS_Halted)
{
MS_MSG("[USB] qHD Status STALL\n");
hcd->urb_status |= USB_ST_STALLED;
return HOST20_DEVICE_STALL;
}
else
MS_MSG("[USB] qHD Status => Halted (Stall/Babble/Error Counter=0)...0x%lx\n", bQHStatus);
}
if (bQHStatus & HOST20_qTD_STATUS_BufferError)
{
hcd->urb_status |= USB_ST_BUF_ERR;
MS_MSG("[USB] qHD Status => HOST20_qTD_STATUS_BufferError...\n");
}
if (bQHStatus & HOST20_qTD_STATUS_Babble)
{
MS_MSG("[USB] qHD Status => HOST20_qTD_STATUS_Babble !!! \n");
/* don't fix babble error for Bert */
spTempqHD->bOverlay_Status = 0;
hcd->urb_status |= USB_ST_BABBLE_DET;
return HOST20_OK;
}
if (bQHStatus & HOST20_qTD_STATUS_TransactionError)
{
MS_MSG("[USB] qHD Status => HOST20_qTD_STATUS_TransactionError...\n");
hcd->urb_status |= USB_ST_CRC_ERR;
}
if (bQHStatus & HOST20_qTD_STATUS_MissMicroFrame)
{
MS_MSG("[USB] qHD Status => HOST20_qTD_STATUS_MissMicroFrame...\n");
hcd->urb_status |= USB_ST_BIT_ERR;
}
/* <2>.Clear the status */
spTempqHD->bOverlay_Status = 0;
return HOST20_FAIL;
}
MS_UINT8 flib_Host20_Send_qTD_Intr(struct usb_hcd *hcd, qTD_Structure *spHeadqTD ,qHD_Structure *spTempqHD)
{
MS_UINT8 bReturnValue;
qTD_Structure *spNewDumyqTD;
qTD_Structure *spOldDumyqTD;
qTD_Structure *spLastqTD;
MS_UINT32 ehci_base = hcd->ehc_base;
spOldDumyqTD=(qTD_Structure*)PA2VA((( MS_UINT32)(spTempqHD->bOverlay_NextqTD))<<5);
memcpy(spOldDumyqTD,spHeadqTD,Host20_qTD_SIZE);
//<2>.Prepare new dumy qTD
spNewDumyqTD=spHeadqTD;
memset((void *)spNewDumyqTD ,0, Host20_qTD_SIZE);
spNewDumyqTD->bTerminate=1;
//<3>.Find spLastqTD & link spLastqTD to NewDumyqTD & Set NewDumyqTD->T=1
spLastqTD=spOldDumyqTD;
while(spLastqTD->bTerminate==0) {
spLastqTD=(qTD_Structure*)PA2VA((( MS_UINT32)(spLastqTD->bNextQTDPointer))<<5);
};
spLastqTD->bNextQTDPointer=VA2PA((MS_UINT32)spNewDumyqTD)>>5;
spLastqTD->bTerminate=0;
//Link Alternate qTD pointer
spLastqTD->bAlternateQTDPointer=(VA2PA(( MS_UINT32)spNewDumyqTD)>>5);
spLastqTD->bAlternateTerminate=0;
//<4>.Set OldDumyqTD->Active=1
//Dump_QTD(spOldDumyqTD);
//Dump_QTD(spNewDumyqTD);
while (mwHost20_USBSTS_Rd(ehci_base) & 0x3b)
{
mwHost20_USBSTS_Set(ehci_base,0x3b); //clear interrupt, don't clear port change int
}
spOldDumyqTD->bStatus_Active=1;
flush_cache((ulong)spOldDumyqTD,0x10); //wried, seems like cache has bug,
//CPU always keep its own copy,
//even we use non-cache memory
bReturnValue=HOST20_OK;
return (bReturnValue);
}
MS_UINT8 flib_Host20_Send_qTD2(struct usb_hcd *hcd, qTD_Structure *spHeadqTD ,qHD_Structure *spTempqHD, MS_UINT32 wTimeOutSec)
{
MS_UINT8 bReturnValue;
qTD_Structure *spNewDumyqTD;
qTD_Structure *spOldDumyqTD;
qTD_Structure *spReleaseqTD;
qTD_Structure *spReleaseqTDNext;
qTD_Structure *spLastqTD;
MS_UINT32 ehci_base = hcd->ehc_base;
unsigned long wTimes;
//if (wTimeOutSec==0)
//{
// DEBUG_USB(printf("error, timeout sec is zero\n"));
//}
spOldDumyqTD=(qTD_Structure*)PA2VA((( MS_UINT32)(spTempqHD->bOverlay_NextqTD))<<5);
//spTempqHD->bOverlay_Status|=HOST20_qTD_STATUS_Halted;
while (mbHost20_USBCMD_PeriodicEnable_Rd(ehci_base))
{
mbHost20_USBCMD_PeriodicEnable_Clr(ehci_base);
}
//spHeadqTD->bTerminate=1; //set to terminate
memcpy(spOldDumyqTD,spHeadqTD,Host20_qTD_SIZE);
//spOldDumyqTD->bStatus_Halted=1;
//spOldDumyqTD->bStatus_Active=0;
//<2>.Prepare new dumy qTD
spNewDumyqTD=spHeadqTD;
memset((void *)spNewDumyqTD ,0, Host20_qTD_SIZE);
spNewDumyqTD->bTerminate=1;
//spNewDumyqTD->bAlternateTerminate=1;
//spNewDumyqTD->bStatus_Halted=1;
//<3>.Find spLastqTD & link spLastqTD to NewDumyqTD & Set NewDumyqTD->T=1
spLastqTD=spOldDumyqTD;
while(spLastqTD->bTerminate==0) {
spLastqTD=(qTD_Structure*)PA2VA((( MS_UINT32)(spLastqTD->bNextQTDPointer))<<5);
};
spLastqTD->bNextQTDPointer=VA2PA((MS_UINT32)spNewDumyqTD)>>5;
spLastqTD->bTerminate=0;
//Link Alternate qTD pointer
spLastqTD->bAlternateQTDPointer=(VA2PA(( MS_UINT32)spNewDumyqTD)>>5);
spLastqTD->bAlternateTerminate=0;
//<4>.Set OldDumyqTD->Active=1
//gwLastqTDSendOK=0;
//sAttachDevice.psSendLastqTD=spLastqTD;
//sAttachDevice.bSendStatusError=0;
//Dump_QTD(spOldDumyqTD);
//Dump_QTD(spNewDumyqTD);
while (mwHost20_USBSTS_Rd(ehci_base) & 0x3b)
{
mwHost20_USBSTS_Set(ehci_base,0x3b); //clear interrupt, don't clear port change int
}
//bExitLoop=0;
//spOldDumyqTD->bStatus_Halted=0;
//spOldDumyqTD->bStatus_Halted=0;
#if 0
printf("spOldDumyqTD: %X\n", spOldDumyqTD);
printf("bTerminate: %X\n", spOldDumyqTD->bTerminate);
printf("bNextQTDPointer: %X\n", spOldDumyqTD->bNextQTDPointer);
printf("bAlternateTerminate: %X\n", spOldDumyqTD->bAlternateTerminate);
printf("bAlternateQTDPointer: %X\n", spOldDumyqTD->bAlternateQTDPointer);
printf("bStatus_PingState: %X\n", spOldDumyqTD->bStatus_PingState);
printf("bStatus_SplitState: %X\n", spOldDumyqTD->bStatus_SplitState);
printf("bStatus_MissMicroFrame: %X\n", spOldDumyqTD->bStatus_MissMicroFrame);
printf("bStatus_Transaction_Err: %X\n", spOldDumyqTD->bStatus_Transaction_Err);
printf("bStatus_Babble: %X\n", spOldDumyqTD->bStatus_Babble);
printf("bStatus_Buffer_Err: %X\n", spOldDumyqTD->bStatus_Buffer_Err);
printf("bStatus_Halted: %X\n", spOldDumyqTD->bStatus_Halted);
printf("bStatus_Active: %X\n", spOldDumyqTD->bStatus_Active);
printf("bPID: %X\n", spOldDumyqTD->bPID);
printf("bErrorCounter: %X\n", spOldDumyqTD->bErrorCounter);
printf("CurrentPage: %X\n", spOldDumyqTD->CurrentPage);
printf("bInterruptOnComplete: %X\n", spOldDumyqTD->bInterruptOnComplete);
printf("bTotalBytes: %X\n", spOldDumyqTD->bTotalBytes);
printf("bDataToggle: %X\n", spOldDumyqTD->bDataToggle);
printf("ArrayBufferPointer_Word: %X\n", spOldDumyqTD->ArrayBufferPointer_Word[0]);
#endif
//flib_Host20_StopRun_Setting(HOST20_Enable);
//printf("RunStop: %X\n", mbHost20_USBCMD_RunStop_Rd());
spOldDumyqTD->bStatus_Active=1;
while (mbHost20_USBCMD_PeriodicEnable_Rd(ehci_base)==0)
{
mbHost20_USBCMD_PeriodicEnable_Set(ehci_base);
}
//spTempqHD->bOverlay_Status&=~HOST20_qTD_STATUS_Halted;
//wait until asynchronous scheduler is idle
//mbHost20_USBCMD_RunStop_Set();
//spTempqHD->bOverlay_Status&=~0x40; //clr HALT bit, start this queue head
wTimes=0;
//<5>.Waiting for result
//EAL=0;
while (1)
{
flush_cache((ulong)spOldDumyqTD,0x10); //wried, seems like cache has bug,
//CPU always keep its own copy,
//even we use non-cache memory
wTimes++;
if ((spOldDumyqTD->bStatus_Active==0) &&
( mwHost20_USBSTS_Rd(ehci_base)& HOST20_USBINTR_CompletionOfTransaction)) //wait until Status_Active become 0
{
bReturnValue=HOST20_OK;
break;
//bExitLoop=1;
//printf("bReturn:%02bx\n", bReturnValue);
}
//if (bExitLoop) break;
#if 1
if (mwHost20_USBSTS_Rd(ehci_base)&(HOST20_USBINTR_SystemError+HOST20_USBINTR_USBError))
{
bReturnValue=HOST20_OK;
//if (spOldDumyqTD->bStatus_Active==1)
//{
// printf("something wrong..USBINTR:%02bx\n",mwHost20_USBSTS_Rd());
// printf("QH status:%02bx\n",spTempqHD->bOverlay_Status);
//}
break; //USB interrupt happened
}
#endif
wTimes++;
if (mwHost20_PORTSC_ConnectStatus_Rd(ehci_base) == 0)
{
MS_MSG("[USB] Port%d device disconn\n", hcd->port_index);
bReturnValue = HOST20_FATAL;
hcd->urb_status |= USB_ST_DISCONNECT;
break;
}
udelay(1);
/* Timeout: Xs*/
if (wTimes > wTimeOutSec * 1000 * 1000)
{
bReturnValue = HOST20_FATAL;
hcd->urb_status |= USB_ST_TIMEOUT;
/* host controller reset */
// mbHost20_USBCMD_HCReset_Set();
// while(mbHost20_USBCMD_HCReset_Rd() > 0);
MS_MSG("[USB] >>> Fail => Time Out for Send qTD...\n");
USB_LIB_PRINTF("[USB] Reg 0x28: 0x%lx 0x%lx\n", *((MS_UINT32 volatile *)(ehci_base+0x28*2)),
*((MS_UINT32 volatile *)(ehci_base+0x28*2+4)));
USB_LIB_PRINTF("[USB] QH: \n");
Dump_QTD((MS_UINT32)spTempqHD);
USB_LIB_PRINTF("[USB] TD: \n");
Dump_QTD((MS_UINT32)spOldDumyqTD);
// while(1);
break;
}
}
while (mbHost20_USBCMD_PeriodicEnable_Rd(ehci_base))
{
mbHost20_USBCMD_PeriodicEnable_Clr(ehci_base);
}
//<6>.Checking the Result
if (bReturnValue!=HOST20_FATAL)
bReturnValue=flib_Host20_CheckingForResult_QHD(hcd, spTempqHD);
if (bReturnValue==HOST20_TRANSACTION_ERROR)
{
//printf("Transaction Error\n");
spTempqHD->bOverlay_Status=0; //clear halt status
spTempqHD->bOverlay_CurrentqTD=VA2PA((MS_UINT32)spNewDumyqTD)>>5;
}
//<5>.Release the all the qTD (Not include spNewDumyqTD)
#if 1
spReleaseqTD=spOldDumyqTD;
do {
//spReleaseqTDNext=((UINT32)(spReleaseqTD->bNextQTDPointerL))<<5 + ((UINT32)(spReleaseqTD->bNextQTDPointerH))<<16 ;
spReleaseqTDNext=(qTD_Structure*)PA2VA(((MS_UINT32)(spReleaseqTD->bNextQTDPointer))<<5);
flib_Host20_ReleaseStructure(hcd, Host20_MEM_TYPE_qTD,(MS_UINT32)spReleaseqTD);
spReleaseqTD=spReleaseqTDNext;
} while(((MS_UINT32)spReleaseqTD)!=((MS_UINT32)spNewDumyqTD));
#endif
return (bReturnValue);
}
/* ====================================================================
* Function Name: flib_Host20_Send_qTD
* Description:
* Case-1:1qTD
* Case-2:2qTD
* Case-3:3qTD above
* Input:Type
* OutPut: 0 => OK
* 1 => TimeOut
* ==================================================================== */
MS_UINT8 flib_Host20_Send_qTD(struct usb_hcd *hcd, qTD_Structure *spHeadqTD, qHD_Structure *spTempqHD, MS_UINT32 wTimeOutSec)
{
MS_UINT8 bReturnValue;
MS_UINT32 wTimes;
MS_UINT32 ehci_base = hcd->ehc_base;
struct ehci_hcd *ehci = hcd->ehci;
qTD_Structure *spNewDumyqTD;
qTD_Structure *spOldDumyqTD;
qTD_Structure *spReleaseqTD;
qTD_Structure *spReleaseqTDNext;
qTD_Structure *spLastqTD;
if (wTimeOutSec==0)
MS_MSG("[USB] error, timeout sec is zero\n");
spOldDumyqTD=(qTD_Structure*)PA2VA(((MS_UINT32)(spTempqHD->bOverlay_NextqTD)) << 5);
// spTempqHD->bOverlay_Status |= HOST20_qTD_STATUS_Halted;
#if 0
while (mbHost20_USBCMD_AsynchronousEnable_Rd())
{
/* pause asynchronous scheduler */
mbHost20_USBCMD_AsynchronousEnable_Clr();
}
#endif
/* set to terminate */
memcpy(spOldDumyqTD, spHeadqTD, Host20_qTD_SIZE);
/* <2>.Prepare new dumy qTD */
spNewDumyqTD = spHeadqTD;
memset((unsigned char *)spNewDumyqTD, 0, Host20_qTD_SIZE);
spNewDumyqTD->bTerminate = 1;
// spNewDumyqTD->bAlternateTerminate = 1;
// spNewDumyqTD->bStatus_Halted = 1;
/* <3>.Find spLastqTD & link spLastqTD to NewDumyqTD & Set NewDumyqTD->T=1 */
spLastqTD = spOldDumyqTD;
while(spLastqTD->bTerminate == 0) {
spLastqTD = (qTD_Structure*)PA2VA((((MS_UINT32)(spLastqTD->bNextQTDPointer)) << 5));
};
spLastqTD->bNextQTDPointer = VA2PA((MS_UINT32)spNewDumyqTD) >> 5;
spLastqTD->bTerminate = 0;
/* Link Alternate qTD pointer */
spLastqTD->bAlternateQTDPointer = VA2PA((MS_UINT32)spNewDumyqTD) >> 5;
spLastqTD->bAlternateTerminate = 0;
ehci->bSendStatusError = 0;
#if 0
USB_LIB_PRINTF("[USB] Before ... \n");
USB_LIB_PRINTF("[USB] QH: \n");
Dump_QTD((MS_UINT32)spTempqHD);
USB_LIB_PRINTF("[USB] TD: \n");
Dump_QTD((MS_UINT32)spOldDumyqTD);
USB_LIB_PRINTF("[USB] After ... \n");
#endif
// while (mwHost20_USBSTS_Rd() & 0x3f)
// {
mwHost20_USBSTS_Set(ehci_base, 0x3f); /* clear interrupt */
// }
// spOldDumyqTD->bStatus_Halted = 0;
// spOldDumyqTD->bStatus_Halted = 0;
spOldDumyqTD->bStatus_Active = 1;
#if (_USB_FLUSH_BUFFER == 1)
Chip_Flush_Memory();
#endif
// while (1){};
#if 0
while (mbHost20_USBCMD_AsynchronousEnable_Rd() == 0)
{
/* re start asynchronous scheduler */
mbHost20_USBCMD_AsynchronousEnable_Set();
}
#endif
// spTempqHD->bOverlay_Status &= ~HOST20_qTD_STATUS_Halted;
/* wait until asynchronous scheduler is idle */
// mbHost20_USBCMD_RunStop_Set();
/* clr HALT bit, start this queue head */
// spTempqHD->bOverlay_Status &= ~0x40;
wTimes=0;
while (1)
{
/* ******************************** *
* wried, seems like cache has bug, *
* CPU always keep its own copy, *
* even we use non-cache memory *
*********************************** */
flush_cache((ulong)spOldDumyqTD,0x10);
// mb();
if ( mwHost20_USBSTS_Rd(ehci_base) & HOST20_USBINTR_CompletionOfTransaction )
{
#if (_USB_FLUSH_BUFFER == 1)
Chip_Read_Memory();
#endif
if (spOldDumyqTD->bStatus_Active == 0)
{
bReturnValue = HOST20_OK;
break;
}
}
if (mwHost20_USBSTS_Rd(ehci_base) & (HOST20_USBINTR_SystemError+HOST20_USBINTR_USBError))
{
bReturnValue = HOST20_OK;
break; /* USB interrupt happened */
}
// if (gwOTG_Timer_Counter>wTimeOutSec)
wTimes++;
if (mwHost20_PORTSC_ConnectStatus_Rd(ehci_base) == 0)
{
MS_MSG("[USB] Port%d device disconn\n", hcd->port_index);
bReturnValue = HOST20_FATAL;
hcd->urb_status |= USB_ST_DISCONNECT;
break;
}
udelay(1);
/* Timeout: Xs*/
if (wTimes > wTimeOutSec * 1000 * 1000)
{
bReturnValue = HOST20_FATAL;
hcd->urb_status |= USB_ST_TIMEOUT;
/* host controller reset */
// mbHost20_USBCMD_HCReset_Set();
// while(mbHost20_USBCMD_HCReset_Rd() > 0);
MS_MSG("[USB] >>> Fail => Time Out for Send qTD...\n");
USB_LIB_PRINTF("[USB] Reg 0x28: 0x%lx 0x%lx\n", *((MS_UINT32 volatile *)(ehci_base+0x28*2)),
*((MS_UINT32 volatile *)(ehci_base+0x28*2+4)));
USB_LIB_PRINTF("[USB] QH: \n");
Dump_QTD((MS_UINT32)spTempqHD);
USB_LIB_PRINTF("[USB] TD: \n");
Dump_QTD((MS_UINT32)spOldDumyqTD);
// while(1);
break;
}
}
hcd->total_bytes = spOldDumyqTD->bTotalBytes;
/* <6>.Checking the Result */
if (bReturnValue != HOST20_FATAL)
bReturnValue = flib_Host20_CheckingForResult_QHD(hcd, spTempqHD);
/* <5>.Release the all the qTD (Not include spNewDumyqTD) */
spReleaseqTD=spOldDumyqTD;
do {
spReleaseqTDNext=(qTD_Structure*)PA2VA(((MS_UINT32)(spReleaseqTD->bNextQTDPointer)) << 5);
flib_Host20_ReleaseStructure(hcd, Host20_MEM_TYPE_qTD,(MS_UINT32)spReleaseqTD);
spReleaseqTD = spReleaseqTDNext;
} while(((MS_UINT32)spReleaseqTD) != ((MS_UINT32)spNewDumyqTD));
//<6>.Double Check the QH overlay status. Adjust it if need.
if( spTempqHD->bOverlay_NextqTD != (VA2PA(( MS_UINT32)spNewDumyqTD)>>5)
|| spTempqHD->bOverlay_Status & MS_BIT7 )
{
// Bug of WD 3.0 disk. Disconnection happens while data face of SETUP transaction.
// If chain qTDs after disconnection/timeout, QH overlay will not be advanced by HW.
// It muss up qTD chain layout. QH doesn't stop at old dumy and stare at new dumy.
// SW advance QH overlay manually no matter HW advancing or not.
// Run bit is cleared by HQ when disconnection, so it is safe to modify the QH.
MS_MSG("[Warning] Adjust bad qTD chain..\r\n");
spTempqHD->bOverlay_Status = spTempqHD->bOverlay_Status & ~MS_BIT7;
spTempqHD->bOverlay_CurrentqTD = VA2PA(( MS_UINT32)spOldDumyqTD) >> 5;
spTempqHD->bOverlay_NextqTD = VA2PA(( MS_UINT32)spNewDumyqTD) >> 5;
spTempqHD->bOverlay_AlternateqTD = VA2PA(( MS_UINT32)spNewDumyqTD) >> 5;
}
return (bReturnValue);
}
MS_UINT8 flib_Host20_Start_BulkIn(struct usb_hcd *hcd, MS_UINT16 hwSize, MS_UINT32 pwBuffer)
{
qTD_Structure *spTempqTD = NULL;
MS_UINT32 workbuf=0;
qHD_Structure *spTempqH = NULL;
qTD_Structure *spNewDumyqTD;
qTD_Structure *spOldDumyqTD;
qTD_Structure *spLastqTD;
if ( pwBuffer != (MS_UINT32) KSEG02KSEG1(pwBuffer) )
{
flush_cache((ulong)pwBuffer,hwSize); //flush buffer to uncached buffer
#if (_USB_FLUSH_BUFFER == 1)
Chip_Flush_Memory();
#endif
pwBuffer=(MS_UINT32)KSEG02KSEG1(pwBuffer);
}
spTempqTD = flib_Host20_GetStructure(hcd, Host20_MEM_TYPE_qTD); //The qTD will be release in the function "Send"
if(spTempqTD == NULL)
return HOST20_FATAL;
spTempqTD->bTotalBytes = hwSize ;
workbuf = pwBuffer;
spTempqTD->ArrayBufferPointer_Word[0] = VA2PA(workbuf);
spTempqH = (hcd->ehci->ep_bulk0_dir == OTGH_Dir_IN) ? hcd->ehci->qh_bulk0 : hcd->ehci->qh_bulk1;
spTempqTD->bPID=HOST20_qTD_PID_IN;
if (hcd->FirstBulkIn)
{
spTempqTD->bDataToggle=0;
spTempqH->bDataToggleControl=1;
}
//<3>.Send TD
spOldDumyqTD=(qTD_Structure*)PA2VA(((MS_UINT32)(spTempqH->bOverlay_NextqTD))<<5);
hcd->ehci->spBulkInqTD = spOldDumyqTD;
USB_LIB_BULK_PRINTF("[USB] spBulkInqTD: %x\n", (MS_U32)hcd->ehci->spBulkInqTD);
memcpy(spOldDumyqTD, spTempqTD, Host20_qTD_SIZE);
//<2>.Prepare new dumy qTD
spNewDumyqTD = spTempqTD;
memset((unsigned char *)spNewDumyqTD , 0, Host20_qTD_SIZE);
spNewDumyqTD->bTerminate = 1;
spLastqTD = spOldDumyqTD;
while(spLastqTD->bTerminate==0) {
spLastqTD=(qTD_Structure*)PA2VA((((MS_UINT32)(spLastqTD->bNextQTDPointer))<<5));
};
spLastqTD->bNextQTDPointer = VA2PA((MS_UINT32)spNewDumyqTD)>>5;
spLastqTD->bTerminate = 0;
spLastqTD->bAlternateQTDPointer = VA2PA((MS_UINT32)spNewDumyqTD)>>5;
spLastqTD->bAlternateTerminate = 0;
hcd->ehci->bSendStatusError = 0;
mwHost20_USBSTS_Set(hcd->ehc_base, 0x3f); /* clear interrupt */
spOldDumyqTD->bStatus_Active = 1;
#if (_USB_FLUSH_BUFFER == 1)
Chip_Flush_Memory();
#endif
if (hcd->FirstBulkIn)
{
spTempqH->bDataToggleControl=0;
hcd->FirstBulkIn=0;
}
return HOST20_OK;
}
MS_UINT8 flib_Host20_Get_BulkIn_Data(struct usb_hcd *hcd, struct usb_device *dev, unsigned int pipe,
MS_U32 buf, MS_U32 length, MS_U32 *actual_len, int timeout)
{
MS_U32 uTotalSize = 0, uRemainSize;
MS_U16 wMaxPacketSize;
MS_UINT8 bReturnValue = HOST20_OK;
qHD_Structure *spTempqHD;
USB_LIB_BULK_PRINTF("[USB] flib_Host20_Get_BulkIn_Data enter...\n");
timeout *= 1000; /* convert from ms to us */
dev->status = hcd->urb_status = 0;
wMaxPacketSize = dev->epmaxpacketin[((pipe>>15) & 0xf)];
spTempqHD = (hcd->ehci->ep_bulk0_dir == OTGH_Dir_IN) ? hcd->ehci->qh_bulk0 : hcd->ehci->qh_bulk1;
if (hcd->ehci->spBulkInqTD== NULL)
{
//Start a BulkIn with length MaxPktSize
flib_Host20_Start_BulkIn(hcd, wMaxPacketSize, (MS_U32)hcd->ehci->pUsbDataBuf);
}
do
{
if ( mwHost20_USBSTS_Rd(hcd->ehc_base) & HOST20_USBINTR_CompletionOfTransaction )
{
#if (_USB_FLUSH_BUFFER == 1)
Chip_Read_Memory();
#endif
if (hcd->ehci->spBulkInqTD->bStatus_Active == 0)
{
bReturnValue = HOST20_OK;
// Add total return size
uRemainSize = (MS_U16)hcd->ehci->spBulkInqTD->bTotalBytes;
uTotalSize += wMaxPacketSize - uRemainSize;
if (uRemainSize > 0)
{
//printf("short data\n");
goto Trans_Done;
}
if (uTotalSize >= length)
goto Trans_Done;;
//Start a BulkIn with length MaxPktSize
flib_Host20_Start_BulkIn(hcd, wMaxPacketSize, (MS_U32)(hcd->ehci->pUsbDataBuf+uTotalSize));
}
}
if (mwHost20_USBSTS_Rd(hcd->ehc_base) & (HOST20_USBINTR_SystemError+HOST20_USBINTR_USBError))
{
bReturnValue=HOST20_OK;
goto Trans_Done; //USB interrupt happened
}
if (mwHost20_PORTSC_ConnectStatus_Rd(hcd->ehc_base) == 0)
{
MS_MSG("[USB] Port%d device disconn\n", hcd->port_index);
bReturnValue = HOST20_FATAL;
hcd->urb_status |= USB_ST_DISCONNECT;
goto Trans_Done;
}
udelay(1);
} while(timeout-->0);
*actual_len = 0;
return (bReturnValue); //Timeout return
Trans_Done:
USB_LIB_BULK_PRINTF("[USB] Trans %d bytes\n", uTotalSize);
memcpy((void*)buf, hcd->ehci->pUsbDataBuf, uTotalSize);
*actual_len = uTotalSize;
//<6>.Checking the Result
if (bReturnValue!=HOST20_FATAL)
bReturnValue=flib_Host20_CheckingForResult_QHD(hcd, spTempqHD);
//<5>.Release the all the qTD (Not include spNewDumyqTD)
flib_Host20_ReleaseStructure(hcd, Host20_MEM_TYPE_qTD, (MS_UINT32)(hcd->ehci->spBulkInqTD));
hcd->ehci->spBulkInqTD = NULL;
dev->status = hcd->urb_status;
return (bReturnValue);
}
//------- xHCI --------
void U3phy_MS28_init(struct xhc_comp *xhci)
{
#ifdef XHCI_SINGLE_PORT_ENABLE_MAC
writeb(readb((void*)(xhci->u3phy_D_base+0x84*2))|0x40, (void*)(xhci->u3phy_D_base+0x84*2)); // open XHCI MAC clock
#endif
//-- 28 hpm mstar only---
writew(0x0104, (void*) (xhci->u3phy_A_base+0x6*2)); // for Enable 1G clock pass to UTMI //[2] reg_pd_usb3_purt [7:6] reg_gcr_hpd_vsel
//U3phy initial sequence
writew(0x0, (void*) (xhci->u3phy_A_base)); // power on rx atop
writew(0x0, (void*) (xhci->u3phy_A_base+0x2*2)); // power on tx atop
//writew(0x0910, (void*) (U3PHY_D_base+0x4*2)); // the same as default
writew(0x0, (void*) (xhci->u3phy_A_base+0x3A*2)); // overwrite power on rx/tx atop
writew(0x0160, (void*) (xhci->u3phy_D_base+0x18*2));
writew(0x0, (void*) (xhci->u3phy_D_base+0x20*2)); // power on u3_phy clockgen
writew(0x0, (void*) (xhci->u3phy_D_base+0x22*2)); // power on u3_phy clockgen
#ifdef XHCI_ENABLE_PD_OVERRIDE
writew(0x308, (void*) (xhci->u3phy_A_base+0x3A*2)); // [9,8,3] PD_TXCLK_USB3TXPLL, PD_USB3_IBIAS, PD_USB3TXPLL override enable
writeb(readb((void*)(xhci->u3phy_A_base+0x3*2-1)) & 0xbb, (void*)(xhci->u3phy_A_base+0x3*2-1)); // override value 0
#endif
writeb(0xF4, (void*) (xhci->u3phy_D_base+0x12*2)); //TX lock threshold
if(xhci->xhci_base != 0) {
//disable compliance mode
writeb(readb((void*)(xhci->xhci_base+0x6817)) | MS_BIT7, (void*)(xhci->xhci_base+0x6817));
}
}
void xhci_enable_clock(void)
{
static int clock_enable = 0;
#ifdef XHCI_PORT0_ADDR
struct xhc_comp xc = XHC_COMP_PORT0;
#endif
#ifdef XHCI_PORT1_ADDR
struct xhc_comp xc1 = XHC_COMP_PORT1;
#endif
if (clock_enable)
return;
#ifdef XHCI_PORT0_ADDR
printf("xhci_enable_clock\n");
U3phy_MS28_init(&xc);
clock_enable = 1;
#endif
#ifdef XHCI_PORT1_ADDR
U3phy_MS28_init(&xc1);
#endif
}
MS_UINT32 xhci_port_state_to_neutral(MS_UINT32 state)
{
/* Save read-only status and port state */
return (state & XHCI_PORT_RO) | (state & XHCI_PORT_RWS);
}
void xhci_ssport_set_state(struct xhc_comp *xhci, int bOn)
{
MS_UINT32 temp;
temp = readl((void*)(xhci->xhci_port_addr));
printf("port status 0x%x: 0x%lx\n", xhci->xhci_port_addr, temp);
if (bOn) {
if ((temp & PORT_PLS_MASK) == USB_SS_PORT_LS_SS_DISABLED) {
temp = xhci_port_state_to_neutral(temp);
temp &= ~PORT_PLS_MASK;
temp |= PORT_LINK_STROBE | USB_SS_PORT_LS_RX_DETECT;
writel(temp, (void*)(xhci->xhci_port_addr));
wait_ms(10);
temp = readl((void*)(xhci->xhci_port_addr));
printf("port status: 0x%lx\n", temp);
}
} else {
if ((temp & PORT_PLS_MASK) != USB_SS_PORT_LS_SS_DISABLED) {
temp = xhci_port_state_to_neutral(temp);
writel(temp | PORT_PE, (void*)(xhci->xhci_port_addr));
wait_ms(10);
temp = readl((void*)(xhci->xhci_port_addr));
printf("port status: 0x%lx\n", temp);
}
}
}
//--------------------