1
0
uboot-1.1.4-kirkwood/board/mv_feroceon/mv_hal/usb/device/mvUsbHsDevMain.c

1869 lines
74 KiB
C
Raw Normal View History

2024-01-09 13:41:15 +01:00
/*******************************************************************************
This software file (the "File") is distributed by Marvell International Ltd.
or its affiliate(s) under the terms of the GNU General Public License Version 2,
June 1991 (the "License"). You may use, redistribute and/or modify this File
in accordance with the terms and conditions of the License, a copy of which
is available along with the File in the license.txt file or by writing to the
Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
or on the worldwide web at http://www.gnu.org/licenses/gpl.txt.
THE FILE IS DISTRIBUTED AS-IS, WITHOUT WARRANTY OF ANY KIND, AND THE IMPLIED
WARRANTIES OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE ARE EXPRESSLY
DISCLAIMED. The GPL License provides additional details about this warranty
disclaimer.
(C) Copyright 2004 - 2007 Marvell Semiconductor Israel Ltd. All Rights Reserved.
(C) Copyright 1999 - 2004 Chipidea Microelectronica, S.A. All Rights Reserved.
*******************************************************************************/
#include "usb/api/mvUsbDevApi.h"
#include "usb/device/mvUsbDevPrv.h"
/*FUNCTION*-------------------------------------------------------------
*
* Function Name : _usb_dci_vusb20_init
* Returned Value : USB_OK or error code
* Comments :
* Initializes the USB device controller.
*
*END*-----------------------------------------------------------------*/
uint_8 _usb_dci_vusb20_init
(
/* [IN] the USB device controller to initialize */
uint_8 devnum,
/* [OUT] the USB_dev_initialize state structure */
_usb_device_handle handle
)
{ /* Body */
USB_DEV_STATE_STRUCT_PTR usb_dev_ptr;
uint_32 temp;
uint_8* pBuf;
unsigned long phyAddr;
usb_dev_ptr = (USB_DEV_STATE_STRUCT_PTR)handle;
usb_dev_ptr->CAP_REGS_PTR =
(VUSB20_REG_STRUCT_PTR)USB_get_cap_reg_addr(devnum);
/* Get the base address of the VUSB_HS registers */
usb_dev_ptr->DEV_PTR =
(VUSB20_REG_STRUCT_PTR)(((uint_32)usb_dev_ptr->CAP_REGS_PTR) +
(USB_32BIT_LE(usb_dev_ptr->CAP_REGS_PTR->REGISTERS.CAPABILITY_REGISTERS.CAPLENGTH_HCIVER) &
EHCI_CAP_LEN_MASK));
/* Get the maximum number of endpoints supported by this USB controller */
usb_dev_ptr->MAX_ENDPOINTS =
(USB_32BIT_LE(usb_dev_ptr->CAP_REGS_PTR->REGISTERS.CAPABILITY_REGISTERS.DCC_PARAMS) &
VUSB20_DCC_MAX_ENDPTS_SUPPORTED);
USB_printf("USB init: CAP_REGS=0x%x, DEV_REGS=0x%x, MAX_EP=%d\n",
(unsigned)usb_dev_ptr->CAP_REGS_PTR, (unsigned)usb_dev_ptr->DEV_PTR,
usb_dev_ptr->MAX_ENDPOINTS);
temp = (usb_dev_ptr->MAX_ENDPOINTS * 2);
pBuf = (uint_8*)USB_uncached_memalloc(temp*sizeof(VUSB20_EP_QUEUE_HEAD_STRUCT),
2048, &phyAddr);
if (pBuf == NULL)
{
USB_printf("_usb_dci_vusb20_init, malloc of %d bytes in Uncached area failed\n",
temp*sizeof(VUSB20_EP_QUEUE_HEAD_STRUCT));
return USBERR_ALLOC;
}
/****************************************************************
Assign QH base
****************************************************************/
usb_dev_ptr->EP_QUEUE_HEAD_BASE = pBuf;
usb_dev_ptr->EP_QUEUE_HEAD_PHYS = (uint_32)phyAddr;
/* Align the endpoint queue head to 2K boundary */
usb_dev_ptr->EP_QUEUE_HEAD_PTR = (VUSB20_EP_QUEUE_HEAD_STRUCT_PTR)
USB_MEM2048_ALIGN((uint_32)usb_dev_ptr->EP_QUEUE_HEAD_BASE);
usb_dev_ptr->EP_QUEUE_HEAD_SIZE = temp*sizeof(VUSB20_EP_QUEUE_HEAD_STRUCT) +
((uint_32)usb_dev_ptr->EP_QUEUE_HEAD_PTR -
(uint_32)usb_dev_ptr->EP_QUEUE_HEAD_BASE);
/****************************************************************
Zero out the memory allocated
****************************************************************/
USB_memzero( (void*)usb_dev_ptr->EP_QUEUE_HEAD_PTR,
temp*sizeof(VUSB20_EP_QUEUE_HEAD_STRUCT));
USB_printf("USB EP_QH: Base=%p (0x%x), Aligned(%d)=%p, Size=%d\n",
usb_dev_ptr->EP_QUEUE_HEAD_BASE, usb_dev_ptr->EP_QUEUE_HEAD_PHYS,
2048, usb_dev_ptr->EP_QUEUE_HEAD_PTR, usb_dev_ptr->EP_QUEUE_HEAD_SIZE);
/****************************************************************
Assign DTD base
****************************************************************/
pBuf = (uint_8*)USB_uncached_memalloc(MAX_EP_TR_DESCRS*sizeof(VUSB20_EP_TR_STRUCT),
32, &phyAddr);
if (pBuf == NULL)
{
USB_printf("_usb_dci_vusb20_init, malloc of %d bytes in Uncached area failed\n",
MAX_EP_TR_DESCRS*sizeof(VUSB20_EP_TR_STRUCT));
return USBERR_ALLOC;
}
usb_dev_ptr->DTD_BASE_PTR = pBuf;
usb_dev_ptr->DTD_BASE_PHYS = (uint_32)phyAddr;
/* Align the dTD base to 32 byte boundary */
usb_dev_ptr->DTD_ALIGNED_BASE_PTR = (VUSB20_EP_TR_STRUCT_PTR)
USB_MEM32_ALIGN((uint_32)usb_dev_ptr->DTD_BASE_PTR);
usb_dev_ptr->DTD_SIZE = MAX_EP_TR_DESCRS*sizeof(VUSB20_EP_TR_STRUCT) +
((uint_32)usb_dev_ptr->EP_QUEUE_HEAD_PTR -
(uint_32)usb_dev_ptr->EP_QUEUE_HEAD_BASE);
/****************************************************************
Zero out the memory allocated
****************************************************************/
USB_memzero((void*)usb_dev_ptr->DTD_ALIGNED_BASE_PTR,
MAX_EP_TR_DESCRS*sizeof(VUSB20_EP_TR_STRUCT));
/****************************************************************
Assign SCRATCH Structure base
****************************************************************/
/* Allocate memory for internal scratch structure */
pBuf = USB_memalloc(MAX_EP_TR_DESCRS*sizeof(SCRATCH_STRUCT));
if (pBuf == NULL)
{
USB_printf("_usb_dci_vusb20_init, malloc of %d bytes failed\n",
MAX_EP_TR_DESCRS*sizeof(SCRATCH_STRUCT));
return USBERR_ALLOC;
}
usb_dev_ptr->SCRATCH_STRUCT_BASE = (SCRATCH_STRUCT_PTR)pBuf;
USB_memzero(usb_dev_ptr->SCRATCH_STRUCT_BASE,
MAX_EP_TR_DESCRS*sizeof(SCRATCH_STRUCT));
USB_printf("USB dTD(%d): Base=%p (0x%x), Aligned(%d)=%p, Size=%d, Scratch=%p\n",
MAX_EP_TR_DESCRS, usb_dev_ptr->DTD_BASE_PTR, usb_dev_ptr->DTD_BASE_PHYS,
32, usb_dev_ptr->DTD_ALIGNED_BASE_PTR, usb_dev_ptr->DTD_SIZE,
usb_dev_ptr->SCRATCH_STRUCT_BASE);
#ifdef USB_UNDERRUN_WA
usbSramBase = (uint_8*)USB_get_sram_addr(&usbSramSize);
if (usbSramBase == NULL)
{
USB_printf("_usb_dci_vusb20_init, SRAM is not available\n");
return USBERR_ALLOC;
}
USB_memzero(usbSramBase, usbSramSize);
USB_printf("USB WA_Queue: base=%p, size=%d, parts=%d\n",
usbSramBase, usbSramSize, global_wa_sram_parts);
#endif /* USB_UNDERRUN_WA */
usb_dev_ptr->USB_STATE = ARC_USB_STATE_UNKNOWN;
/* Initialize the VUSB_HS controller */
_usb_dci_vusb20_chip_initialize((pointer)usb_dev_ptr);
return USB_OK;
} /* EndBody */
/*FUNCTION*-------------------------------------------------------------
*
* Function Name : _usb_dci_vusb20_chip_initialize
* Returned Value : USB_OK or error code
* Comments :
* Initializes the USB device controller.
*
*END*-----------------------------------------------------------------*/
void _usb_dci_vusb20_chip_initialize
(
/* [IN] the USB_dev_initialize state structure */
_usb_device_handle handle
)
{ /* Body */
USB_DEV_STATE_STRUCT_PTR usb_dev_ptr;
VUSB20_REG_STRUCT_PTR dev_ptr;
VUSB20_EP_QUEUE_HEAD_STRUCT_PTR ep_queue_head_ptr;
VUSB20_EP_TR_STRUCT_PTR dTD_ptr;
uint_32 i, port_control;
SCRATCH_STRUCT_PTR temp_scratch_ptr;
volatile unsigned long delay;
ARC_DEBUG_TRACE(ARC_DEBUG_FLAG_INIT, "chip_initialize\n");
usb_dev_ptr = (USB_DEV_STATE_STRUCT_PTR)handle;
dev_ptr = (VUSB20_REG_STRUCT_PTR)usb_dev_ptr->DEV_PTR;
/* Stop the controller */
dev_ptr->REGISTERS.OPERATIONAL_DEVICE_REGISTERS.USB_CMD &= ~(USB_32BIT_LE(EHCI_CMD_RUN_STOP));
/* Reset the controller to get default values */
dev_ptr->REGISTERS.OPERATIONAL_DEVICE_REGISTERS.USB_CMD = USB_32BIT_LE(EHCI_CMD_CTRL_RESET);
USB_printf("USB Init: Wait for RESET completed\n");
delay = 0x100000;
while (dev_ptr->REGISTERS.OPERATIONAL_DEVICE_REGISTERS.USB_CMD &
(USB_32BIT_LE(EHCI_CMD_CTRL_RESET)))
{
/* Wait for the controller reset to complete */
delay--;
if(delay == 0)
break;
} /* EndWhile */
if(delay == 0)
{
USB_printf("USB Init: Wait for RESET completed TIMEOUT\n");
}
else
{
USB_printf("USB Init: RESET completed\n");
}
/* Call BSP callback to complete reset process */
USB_reset_complete(usb_dev_ptr->DEV_NUM);
/* Initialize the internal dTD head and tail to NULL */
usb_dev_ptr->DTD_HEAD = NULL;
usb_dev_ptr->DTD_TAIL = NULL;
usb_dev_ptr->DTD_ENTRIES = 0;
usb_dev_ptr->ERROR_STATE = 0;
/* Make sure the 16 MSBs of this register are 0s */
dev_ptr->REGISTERS.OPERATIONAL_DEVICE_REGISTERS.ENDPT_SETUP_STAT = USB_32BIT_LE(0);
ep_queue_head_ptr = usb_dev_ptr->EP_QUEUE_HEAD_PTR;
/* Initialize all device queue heads */
for (i=0; i<(usb_dev_ptr->MAX_ENDPOINTS*2); i++)
{
/* Interrupt on Setup packet */
(ep_queue_head_ptr + i)->MAX_PKT_LENGTH = (USB_32BIT_LE(
((uint_32)USB_MAX_CTRL_PAYLOAD << VUSB_EP_QUEUE_HEAD_MAX_PKT_LEN_POS) |
VUSB_EP_QUEUE_HEAD_IOS));
(ep_queue_head_ptr + i)->NEXT_DTD_PTR = (USB_32BIT_LE(VUSB_EP_QUEUE_HEAD_NEXT_TERMINATE));
} /* Endfor */
/* Configure the Endpoint List Address */
dev_ptr->REGISTERS.OPERATIONAL_DEVICE_REGISTERS.EP_LIST_ADDR =
USB_32BIT_LE(USB_EP_QH_VIRT_TO_PHYS(usb_dev_ptr, ep_queue_head_ptr));
port_control = USB_32BIT_LE(dev_ptr->REGISTERS.OPERATIONAL_DEVICE_REGISTERS.PORTSCX[0]);
if (usb_dev_ptr->CAP_REGS_PTR->REGISTERS.CAPABILITY_REGISTERS.HCS_PARAMS &
USB_32BIT_LE(VUSB20_HCS_PARAMS_PORT_POWER_CONTROL_FLAG))
{
port_control &= (~EHCI_PORTSCX_W1C_BITS | ~EHCI_PORTSCX_PORT_POWER);
} /* Endif */
if(usb_dev_ptr->FORCE_FS == TRUE)
{
port_control |= EHCI_PORTSCX_FORCE_FULL_SPEED_CONNECT;
}
else
{
port_control &= (~EHCI_PORTSCX_FORCE_FULL_SPEED_CONNECT);
}
dev_ptr->REGISTERS.OPERATIONAL_DEVICE_REGISTERS.PORTSCX[0] = USB_32BIT_LE(port_control);
dTD_ptr = usb_dev_ptr->DTD_ALIGNED_BASE_PTR;
temp_scratch_ptr = usb_dev_ptr->SCRATCH_STRUCT_BASE;
/* Enqueue all the dTDs */
for (i=0; i<MAX_EP_TR_DESCRS; i++)
{
dTD_ptr->SCRATCH_PTR = temp_scratch_ptr;
dTD_ptr->SCRATCH_PTR->FREE = _usb_dci_vusb20_free_dTD;
/* Set the dTD to be invalid */
dTD_ptr->NEXT_TR_ELEM_PTR = USB_32BIT_LE(VUSBHS_TD_NEXT_TERMINATE);
/* Set the Reserved fields to 0 */
dTD_ptr->SIZE_IOC_STS &= ~(USB_32BIT_LE(VUSBHS_TD_RESERVED_FIELDS));
dTD_ptr->SCRATCH_PTR->PRIVATE = (pointer)usb_dev_ptr;
_usb_dci_vusb20_free_dTD((pointer)dTD_ptr);
dTD_ptr++;
temp_scratch_ptr++;
} /* Endfor */
} /* EndBody */
/*FUNCTION*-------------------------------------------------------------
*
* Function Name : _usb_dci_vusb20_free_dTD
* Returned Value : void
* Comments :
* Enqueues a dTD onto the free DTD ring.
*
*END*-----------------------------------------------------------------*/
void _usb_dci_vusb20_free_dTD
(
/* [IN] the dTD to enqueue */
pointer dTD_ptr
)
{ /* Body */
USB_DEV_STATE_STRUCT_PTR usb_dev_ptr;
int lockKey;
usb_dev_ptr = (USB_DEV_STATE_STRUCT_PTR)(((VUSB20_EP_TR_STRUCT_PTR)dTD_ptr)->SCRATCH_PTR->PRIVATE);
ARC_DEBUG_TRACE(ARC_DEBUG_FLAG_TRACE, "free_dTD: dTD_ptr=0x%x\n", (unsigned)dTD_ptr);
ARC_DEBUG_CODE(ARC_DEBUG_FLAG_STATS, (usb_dev_ptr->STATS.free_dTD_count++));
/*
** This function can be called from any context, and it needs mutual
** exclusion with itself.
*/
lockKey = USB_lock();
/*
** Add the dTD to the free dTD queue (linked via PRIVATE) and
** increment the tail to the next descriptor
*/
EHCI_DTD_QADD(usb_dev_ptr->DTD_HEAD, usb_dev_ptr->DTD_TAIL, (VUSB20_EP_TR_STRUCT_PTR)dTD_ptr);
usb_dev_ptr->DTD_ENTRIES++;
USB_unlock(lockKey);
} /* Endbody */
/*FUNCTION*-------------------------------------------------------------
*
* Function Name : _usb_dci_vusb20_add_dTD
* Returned Value : USB_OK or error code
* Comments :
* Adds a device transfer desriptor(s) to the queue.
*
*END*-----------------------------------------------------------------*/
uint_8 _usb_dci_vusb20_add_dTD
(
/* [IN] the USB_dev_initialize state structure */
_usb_device_handle handle,
/* [IN] The transfer descriptor address */
XD_STRUCT_PTR xd_ptr
)
{ /* Body */
USB_DEV_STATE_STRUCT_PTR usb_dev_ptr;
VUSB20_REG_STRUCT_PTR dev_ptr;
VUSB20_EP_TR_STRUCT_PTR dTD_ptr, temp_dTD_ptr, first_dTD_ptr = NULL;
VUSB20_EP_QUEUE_HEAD_STRUCT_PTR ep_queue_head_ptr;
uint_32 curr_pkt_len, remaining_len;
uint_32 curr_offset, temp, bit_pos;
volatile unsigned long timeout;
/*********************************************************************
For a optimal implementation, we need to detect the fact that
we are adding DTD to an empty list. If list is empty, we can
actually skip several programming steps esp. those for ensuring
that there is no race condition.The following boolean will be useful
in skipping some code here.
*********************************************************************/
boolean list_empty = FALSE;
usb_dev_ptr = (USB_DEV_STATE_STRUCT_PTR)handle;
dev_ptr = (VUSB20_REG_STRUCT_PTR)usb_dev_ptr->DEV_PTR;
remaining_len = xd_ptr->WTOTALLENGTH;
curr_offset = 0;
temp = (2*xd_ptr->EP_NUM + xd_ptr->BDIRECTION);
bit_pos = (1 << (16 * xd_ptr->BDIRECTION + xd_ptr->EP_NUM));
ep_queue_head_ptr = (VUSB20_EP_QUEUE_HEAD_STRUCT_PTR)usb_dev_ptr->EP_QUEUE_HEAD_PTR + temp;
/*********************************************************************
This loops iterates through the length of the transfer and divides
the data in to DTDs each handling the a max of 0x4000 bytes of data.
The first DTD in the list is stored in a pointer called first_dTD_ptr.
This pointer is later linked in to QH for processing by the hardware.
*********************************************************************/
do
{
/* Check if we need to split the transfer into multiple dTDs */
if (remaining_len > VUSB_EP_MAX_LENGTH_TRANSFER)
{
curr_pkt_len = VUSB_EP_MAX_LENGTH_TRANSFER;
}
else
{
curr_pkt_len = remaining_len;
} /* Endif */
/* Get a dTD from the queue */
EHCI_DTD_QGET(usb_dev_ptr->DTD_HEAD, usb_dev_ptr->DTD_TAIL, dTD_ptr);
if (!dTD_ptr)
{
USB_printf("Error: Can't get dTD\n");
return USBERR_TR_FAILED;
} /* Endif */
ARC_DEBUG_CODE(ARC_DEBUG_FLAG_STATS, (usb_dev_ptr->STATS.usb_add_count++));
remaining_len -= curr_pkt_len;
usb_dev_ptr->DTD_ENTRIES--;
if (curr_offset == 0)
{
first_dTD_ptr = dTD_ptr;
} /* Endif */
/* Zero the dTD. Leave the last 4 bytes as that is the scratch pointer */
USB_memzero((void *) dTD_ptr,(sizeof(VUSB20_EP_TR_STRUCT) - 4));
/* Initialize the dTD */
dTD_ptr->SCRATCH_PTR->PRIVATE = handle;
/* Set the Terminate bit */
dTD_ptr->NEXT_TR_ELEM_PTR = USB_32BIT_LE(VUSB_EP_QUEUE_HEAD_NEXT_TERMINATE);
/*************************************************************
FIX ME: For hig-speed and high-bandwidth ISO IN endpoints,
we must initialize the multiplied field so that Host can issues
multiple IN transactions on the endpoint. See the DTD data
structure for MultiIO field.
S Garg 11/06/2003
*************************************************************/
/* Fill in the transfer size */
if (!remaining_len)
{
dTD_ptr->SIZE_IOC_STS = USB_32BIT_LE((curr_pkt_len <<
VUSBHS_TD_LENGTH_BIT_POS) | (VUSBHS_TD_IOC) | (VUSBHS_TD_STATUS_ACTIVE));
}
else
{
dTD_ptr->SIZE_IOC_STS = USB_32BIT_LE((curr_pkt_len << VUSBHS_TD_LENGTH_BIT_POS)
| VUSBHS_TD_STATUS_ACTIVE);
} /* Endif */
/* Set the reserved field to 0 */
dTD_ptr->SIZE_IOC_STS &= ~USB_32BIT_LE(VUSBHS_TD_RESERVED_FIELDS);
/* 4K apart buffer page pointers */
if(xd_ptr->WSTARTADDRESS != NULL)
{
uint_32 physAddr = USB_virt_to_phys((uint_8*)xd_ptr->WSTARTADDRESS + curr_offset);
dTD_ptr->BUFF_PTR0 = USB_32BIT_LE(physAddr);
physAddr += 4096;
dTD_ptr->BUFF_PTR1 = USB_32BIT_LE(physAddr);
physAddr += 4096;
dTD_ptr->BUFF_PTR2 = USB_32BIT_LE(physAddr);
physAddr += 4096;
dTD_ptr->BUFF_PTR3 = USB_32BIT_LE(physAddr);
physAddr += 4096;
dTD_ptr->BUFF_PTR4 = USB_32BIT_LE(physAddr);
}
else
{
dTD_ptr->BUFF_PTR0 = dTD_ptr->BUFF_PTR1 = dTD_ptr->BUFF_PTR2 = 0;
dTD_ptr->BUFF_PTR3 = dTD_ptr->BUFF_PTR4 = 0;
}
curr_offset += curr_pkt_len;
/* Maintain the first and last device transfer descriptor per
** endpoint and direction
*/
if (!usb_dev_ptr->EP_DTD_HEADS[temp])
{
usb_dev_ptr->EP_DTD_HEADS[temp] = dTD_ptr;
/***********************************************
If list does not have a head, it means that list
is empty. An empty condition is detected.
***********************************************/
list_empty = TRUE;
} /* Endif */
/* Check if the transfer is to be queued at the end or beginning */
temp_dTD_ptr = usb_dev_ptr->EP_DTD_TAILS[temp];
/* Remember which XD to use for this dTD */
dTD_ptr->SCRATCH_PTR->XD_FOR_THIS_DTD = (pointer)xd_ptr;
/* New tail */
usb_dev_ptr->EP_DTD_TAILS[temp] = dTD_ptr;
if (temp_dTD_ptr)
{
/* Should not do |=. The Terminate bit should be zero */
temp_dTD_ptr->NEXT_TR_ELEM_PTR = USB_32BIT_LE(USB_DTD_VIRT_TO_PHYS(usb_dev_ptr, dTD_ptr));
} /* Endif */
} while (remaining_len); /* EndWhile */
/**************************************************************
In the loop above DTD has already been added to the list
However endpoint has not been primed yet. If list is not empty
we need safter ways to add DTD to the existing list.
Else we just skip to adding DTD to QH safely.
**************************************************************/
if(list_empty == FALSE)
{
volatile boolean read_safe = FALSE;
uint_32 prime, temp_ep_stat=0;
/*********************************************************
Hardware v3.2+ require the use of semaphore to ensure that
QH is safely updated.
*********************************************************/
ARC_DEBUG_CODE(ARC_DEBUG_FLAG_STATS, (usb_dev_ptr->STATS.usb_add_not_empty_count++));
/*********************************************************
Check the prime bit. If set goto done
*********************************************************/
prime = USB_32BIT_LE(dev_ptr->REGISTERS.OPERATIONAL_DEVICE_REGISTERS.ENDPTPRIME);
/*
USB_printf("%03d: Add not empty: bit_pos=%x, prime=0x%x, status=0x%x\n",
usb_dev_ptr->STATS.usb_add_not_empty_count, prime, bit_pos,
USB_32BIT_LE(dev_ptr->REGISTERS.OPERATIONAL_DEVICE_REGISTERS.ENDPTSTATUS),
USB_32BIT_LE(ep_queue_head_ptr->SIZE_IOC_INT_STS) );
*/
if(prime & bit_pos)
{
timeout = 0x1000;
while( dev_ptr->REGISTERS.OPERATIONAL_DEVICE_REGISTERS.ENDPTPRIME
& USB_32BIT_LE(bit_pos) )
{
/* Wait for the ENDPTPRIME to go to zero */
timeout--;
if(timeout <= 0)
{
USB_printf(
"timeout: CTRL=%x, PRIME=%x, STAT=%x, INTR=%x, ADDR=%x, PORTSC=%x, dTD=%p, temp_dTD=%p\n",
USB_32BIT_LE(dev_ptr->REGISTERS.OPERATIONAL_DEVICE_REGISTERS.ENDPTCTRLX[0]),
USB_32BIT_LE(dev_ptr->REGISTERS.OPERATIONAL_DEVICE_REGISTERS.ENDPTPRIME),
USB_32BIT_LE(dev_ptr->REGISTERS.OPERATIONAL_DEVICE_REGISTERS.ENDPTSTATUS),
USB_32BIT_LE(dev_ptr->REGISTERS.OPERATIONAL_DEVICE_REGISTERS.USB_STS),
USB_32BIT_LE(dev_ptr->REGISTERS.OPERATIONAL_DEVICE_REGISTERS.DEVICE_ADDR),
USB_32BIT_LE(dev_ptr->REGISTERS.OPERATIONAL_DEVICE_REGISTERS.PORTSCX[0]),
first_dTD_ptr, temp_dTD_ptr);
_usb_ep_status(handle, xd_ptr->EP_NUM, xd_ptr->BDIRECTION);
return USBERR_TR_FAILED;
}
} /* EndWhile */
/*ARC_DEBUG_TRACE(ARC_DEBUG_FLAG_TRANSFER,*/
if(dev_ptr->REGISTERS.OPERATIONAL_DEVICE_REGISTERS.ENDPTSTATUS & USB_32BIT_LE(bit_pos))
{
goto done;
}
}
read_safe = FALSE;
timeout = 1000000;
while(read_safe == FALSE)
{
timeout--;
if(timeout <= 0)
{
USB_printf("%s: Timeout for ATDTW_TRIPWIRE reg = 0x%x\n", __FUNCTION__,
(unsigned)USB_32BIT_LE(dev_ptr->REGISTERS.OPERATIONAL_DEVICE_REGISTERS.USB_CMD));
return USBERR_TR_FAILED;
}
/*********************************************************
start with setting the semaphores
*********************************************************/
dev_ptr->REGISTERS.OPERATIONAL_DEVICE_REGISTERS.USB_CMD |=
USB_32BIT_LE(EHCI_CMD_ATDTW_TRIPWIRE_SET);
/*********************************************************
Read the endpoint status
*********************************************************/
temp_ep_stat = USB_32BIT_LE(dev_ptr->REGISTERS.OPERATIONAL_DEVICE_REGISTERS.ENDPTSTATUS)
& bit_pos;
/*********************************************************
Reread the ATDTW semaphore bit to check if it is cleared.
When hardware see a hazard, it will clear the bit or
else we remain set to 1 and we can proceed with priming
of endpoint if not already primed.
*********************************************************/
if( dev_ptr->REGISTERS.OPERATIONAL_DEVICE_REGISTERS.USB_CMD &
USB_32BIT_LE(EHCI_CMD_ATDTW_TRIPWIRE_SET))
{
read_safe = TRUE;
}
}/*end while loop */
/*********************************************************
Clear the semaphore
*********************************************************/
dev_ptr->REGISTERS.OPERATIONAL_DEVICE_REGISTERS.USB_CMD &=
USB_32BIT_LE(EHCI_CMD_ATDTW_TRIPWIRE_CLEAR);
/*********************************************************
* If endpoint is not active, we activate it now.
*********************************************************/
if(!temp_ep_stat)
{
/* No other transfers on the queue */
ep_queue_head_ptr->NEXT_DTD_PTR = USB_32BIT_LE(
USB_DTD_VIRT_TO_PHYS(usb_dev_ptr, first_dTD_ptr));
ep_queue_head_ptr->SIZE_IOC_INT_STS = 0;
/* Prime the Endpoint */
dev_ptr->REGISTERS.OPERATIONAL_DEVICE_REGISTERS.ENDPTPRIME = USB_32BIT_LE(bit_pos);
}
}
else
{
/* No other transfers on the queue */
ep_queue_head_ptr->NEXT_DTD_PTR = USB_32BIT_LE(
USB_DTD_VIRT_TO_PHYS(usb_dev_ptr, first_dTD_ptr));
ep_queue_head_ptr->SIZE_IOC_INT_STS = 0;
/* Prime the Endpoint */
dev_ptr->REGISTERS.OPERATIONAL_DEVICE_REGISTERS.ENDPTPRIME = USB_32BIT_LE(bit_pos);
/* delay */
timeout = 0x100;
while(timeout > 0)
timeout--;
dev_ptr->REGISTERS.OPERATIONAL_DEVICE_REGISTERS.ENDPTPRIME = USB_32BIT_LE(bit_pos);
}
done:
if(first_dTD_ptr == NULL)
USB_printf("ERROR !!!! first_dTD_ptr=NULL\n");
ARC_DEBUG_TRACE(ARC_DEBUG_FLAG_TRANSFER,
" add_%d: fri=0x%x, ep=%d%s, buf=%p, size=%d, xd=%p, dTD=%p %p, empty=%d\n",
usb_dev_ptr->STATS.usb_add_count & 0xFFFF,
USB_32BIT_LE(dev_ptr->REGISTERS.OPERATIONAL_DEVICE_REGISTERS.USB_FRINDEX),
xd_ptr->EP_NUM, xd_ptr->BDIRECTION ? "in" : "out",
xd_ptr->WSTARTADDRESS, (int)xd_ptr->WTOTALLENGTH,
xd_ptr, (unsigned)first_dTD_ptr,
usb_dev_ptr->EP_DTD_HEADS[temp], list_empty);
return USB_OK;
/* End CR 1015 */
} /* EndBody */
/*FUNCTION*-------------------------------------------------------------
*
* Function Name : _usb_dci_vusb20_process_tr_complete
* Returned Value : None
* Comments :
* Services transaction complete interrupt
*
*END*-----------------------------------------------------------------*/
void _usb_dci_vusb20_process_tr_complete
(
/* [IN] the USB_dev_initialize state structure */
_usb_device_handle handle
)
{ /* Body */
USB_DEV_STATE_STRUCT_PTR usb_dev_ptr;
volatile VUSB20_REG_STRUCT_PTR dev_ptr;
volatile VUSB20_EP_TR_STRUCT_PTR dTD_ptr;
VUSB20_EP_TR_STRUCT_PTR temp_dTD_ptr;
VUSB20_EP_QUEUE_HEAD_STRUCT_PTR ep_queue_head_ptr;
uint_32 temp, i, ep_num = 0, direction = 0, bit_pos;
uint_32 remaining_length = 0;
uint_32 actual_transfer_length = 0;
uint_32 counter, errors = 0;
XD_STRUCT_PTR xd_ptr;
XD_STRUCT_PTR temp_xd_ptr = NULL;
uint_8_ptr buff_start_address = NULL;
boolean endpoint_detected = FALSE;
usb_dev_ptr = (USB_DEV_STATE_STRUCT_PTR)handle;
dev_ptr = (VUSB20_REG_STRUCT_PTR)usb_dev_ptr->DEV_PTR;
ARC_DEBUG_CODE(ARC_DEBUG_FLAG_STATS, (usb_dev_ptr->STATS.usb_complete_isr_count++));
/* We use separate loops for ENDPTSETUPSTAT and ENDPTCOMPLETE because the
** setup packets are to be read ASAP
*/
/* Process all Setup packet received interrupts */
bit_pos = USB_32BIT_LE(dev_ptr->REGISTERS.OPERATIONAL_DEVICE_REGISTERS.ENDPT_SETUP_STAT);
if (bit_pos)
{
ARC_DEBUG_TRACE(ARC_DEBUG_FLAG_SETUP, "setup_isr: bit_pos=0x%x\n", (unsigned)bit_pos);
for(i=0; i<USB_MAX_CONTROL_ENDPOINTS; i++)
{
if (bit_pos & (1 << i))
{
ARC_DEBUG_CODE(ARC_DEBUG_FLAG_STATS, (usb_dev_ptr->STATS.usb_setup_count++));
_usb_device_call_service(handle, i, TRUE, 0, 0, 8, 0);
} /* Endif */
} /* Endfor */
} /* Endif */
/* Don't clear the endpoint setup status register here. It is cleared as a
** setup packet is read out of the buffer
*/
/* Process non-setup transaction complete interrupts */
bit_pos = USB_32BIT_LE(dev_ptr->REGISTERS.OPERATIONAL_DEVICE_REGISTERS.ENDPTCOMPLETE);
/* Clear the bits in the register */
dev_ptr->REGISTERS.OPERATIONAL_DEVICE_REGISTERS.ENDPTCOMPLETE = USB_32BIT_LE(bit_pos);
if (bit_pos)
{
ARC_DEBUG_CODE(ARC_DEBUG_FLAG_STATS, (usb_dev_ptr->STATS.usb_complete_count++));
/* Get the endpoint number and the direction of transfer */
counter = 0;
for (i=0; i<(ARC_USB_MAX_ENDPOINTS*2); i++)
{
endpoint_detected = FALSE;
if ((i < ARC_USB_MAX_ENDPOINTS) && (bit_pos & (1 << i)))
{
ep_num = i;
direction = ARC_USB_RECV;
endpoint_detected = TRUE;
}
else
{
if( (i >= ARC_USB_MAX_ENDPOINTS) &&
(bit_pos & (1 << (i+16-ARC_USB_MAX_ENDPOINTS))))
{
ep_num = (i - ARC_USB_MAX_ENDPOINTS);
direction = ARC_USB_SEND;
endpoint_detected = TRUE;
}
}
if(endpoint_detected)
{
temp = (2*ep_num + direction);
/* Get the first dTD */
dTD_ptr = usb_dev_ptr->EP_DTD_HEADS[temp];
ep_queue_head_ptr = (VUSB20_EP_QUEUE_HEAD_STRUCT_PTR)usb_dev_ptr->EP_QUEUE_HEAD_PTR + temp;
/* Process all the dTDs for respective transfers */
while (dTD_ptr)
{
if (USB_32BIT_LE(dTD_ptr->SIZE_IOC_STS) & VUSBHS_TD_STATUS_ACTIVE)
{
/* No more dTDs to process. Next one is owned by VUSB */
if(counter == 0)
{
ARC_DEBUG_TRACE(ARC_DEBUG_FLAG_ISR, "tr_complete - break: ep=%d %s, bit_pos=0x%x\n",
(unsigned)ep_num, direction ? "SEND" : "RECV", (unsigned)bit_pos);
ARC_DEBUG_CODE(ARC_DEBUG_FLAG_STATS, (usb_dev_ptr->STATS.usb_empty_complete_count++));
}
break;
} /* Endif */
/* Get the correct internal transfer descriptor */
xd_ptr = (XD_STRUCT_PTR)dTD_ptr->SCRATCH_PTR->XD_FOR_THIS_DTD;
if (xd_ptr)
{
buff_start_address = xd_ptr->WSTARTADDRESS;
actual_transfer_length = xd_ptr->WTOTALLENGTH;
temp_xd_ptr = xd_ptr;
} /* Endif */
/* Get the address of the next dTD */
temp_dTD_ptr = (VUSB20_EP_TR_STRUCT_PTR)USB_DTD_PHYS_TO_VIRT(usb_dev_ptr,
(uint_32)(USB_32BIT_LE(dTD_ptr->NEXT_TR_ELEM_PTR) & VUSBHS_TD_ADDR_MASK) );
/* Read the errors */
errors = (USB_32BIT_LE(dTD_ptr->SIZE_IOC_STS) & VUSBHS_TD_ERROR_MASK);
if (!errors)
{
/* No errors */
/* Get the length of transfer from the current dTD */
remaining_length += ((USB_32BIT_LE(dTD_ptr->SIZE_IOC_STS) & VUSB_EP_TR_PACKET_SIZE) >> 16);
actual_transfer_length -= remaining_length;
}
else
{
if (errors & VUSBHS_TD_STATUS_HALTED)
{
/* Clear the errors and Halt condition */
ep_queue_head_ptr->SIZE_IOC_INT_STS &= USB_32BIT_LE(~errors);
} /* Endif */
ARC_DEBUG_TRACE(ARC_DEBUG_FLAG_ERROR,
"complete_tr ERROR: ep=%d %s: STS=0x%x, dTD=%p, dTD_next=%p, xd=%p, qh->sts=0x%x\n",
(unsigned)ep_num, direction ? "SEND" : "RECV",
(unsigned)dTD_ptr->SIZE_IOC_STS, dTD_ptr, temp_dTD_ptr,
xd_ptr, ep_queue_head_ptr->SIZE_IOC_INT_STS);
} /* Endif */
/* Retire the processed dTD */
counter++;
_usb_dci_vusb20_cancel_transfer(handle, ep_num, direction);
if( (temp_dTD_ptr == NULL) ||
(temp_dTD_ptr->SCRATCH_PTR->XD_FOR_THIS_DTD != temp_xd_ptr) )
{
/* Transfer complete. Call the register service function for the endpoint */
ARC_DEBUG_CODE(ARC_DEBUG_FLAG_STATS, (usb_dev_ptr->STATS.usb_complete_ep_count[temp]++));
#if defined(USB_UNDERRUN_WA)
if( (direction == ARC_USB_SEND) &&
(((ep_queue_head_ptr->MAX_PKT_LENGTH >> 16) & 0x7FF) > global_wa_threshold) )
usbSendComplete(handle, ep_num, FALSE, direction,
buff_start_address, actual_transfer_length, errors);
else
#endif /* USB_UNDERRUN_WA */
_usb_device_call_service(handle, ep_num, FALSE, direction,
buff_start_address, actual_transfer_length, errors);
remaining_length = 0;
ARC_DEBUG_TRACE(ARC_DEBUG_FLAG_TRANSFER,
"comp_%d: fri=0x%x, ep=%d%s, buf=%p, size=%d, xd=%p, dTD=%p %p %p, COMP=0x%x\n",
usb_dev_ptr->STATS.usb_complete_count & 0xFFFF,
USB_32BIT_LE(dev_ptr->REGISTERS.OPERATIONAL_DEVICE_REGISTERS.USB_FRINDEX),
(unsigned)ep_num, direction ? "in" : "out",
buff_start_address, actual_transfer_length,
temp_xd_ptr, dTD_ptr, temp_dTD_ptr, usb_dev_ptr->EP_DTD_HEADS[temp], (unsigned)bit_pos);
} /* Endif */
else
{
ARC_DEBUG_TRACE(ARC_DEBUG_FLAG_TRANSFER, "tr_complete not completed: ep=%d %s\n",
(unsigned)ep_num, direction ? "SEND" : "RECV");
}
if( (temp_dTD_ptr == NULL) && (usb_dev_ptr->EP_DTD_HEADS[temp] != NULL) )
{
/*
USB_printf("tr_complete: ep=%d, temp_dTD=%p, dTD_ptr=%p (%p), DTD_HEADS=%p, remain=%d\n",
temp, temp_dTD_ptr, dTD_ptr,
USB_DTD_PHYS_TO_VIRT(usb_dev_ptr, (uint_32)(USB_32BIT_LE(dTD_ptr->NEXT_TR_ELEM_PTR) & VUSBHS_TD_ADDR_MASK) ),
usb_dev_ptr->EP_DTD_HEADS[temp], remaining_length);
*/
dTD_ptr = usb_dev_ptr->EP_DTD_HEADS[temp];
}
else
{
dTD_ptr = temp_dTD_ptr;
}
errors = 0;
} /* Endwhile */
} /* Endif */
} /* Endfor */
ARC_DEBUG_CODE(ARC_DEBUG_FLAG_STATS,
( {if(usb_dev_ptr->STATS.usb_complete_max_count < counter)
usb_dev_ptr->STATS.usb_complete_max_count = counter;}));
} /* Endif */
} /* EndBody */
/*FUNCTION*-------------------------------------------------------------
*
* Function Name : _usb_dci_vusb20_isr
* Returned Value : None
* Comments :
* Services all the VUSB_HS interrupt sources
*
*END*-----------------------------------------------------------------*/
void _usb_dci_vusb20_isr
(
_usb_device_handle handle
)
{ /* Body */
USB_DEV_STATE_STRUCT_PTR usb_dev_ptr;
VUSB20_REG_STRUCT_PTR dev_ptr;
uint_32 status;
usb_dev_ptr = (USB_DEV_STATE_STRUCT_PTR)handle;
ARC_DEBUG_CODE(ARC_DEBUG_FLAG_STATS, (usb_dev_ptr->STATS.usb_isr_count++));
dev_ptr = (VUSB20_REG_STRUCT_PTR)usb_dev_ptr->DEV_PTR;
status = USB_32BIT_LE(dev_ptr->REGISTERS.OPERATIONAL_DEVICE_REGISTERS.USB_STS);
status &= USB_32BIT_LE(dev_ptr->REGISTERS.OPERATIONAL_DEVICE_REGISTERS.USB_INTR);
if(status == 0)
{
ARC_DEBUG_CODE(ARC_DEBUG_FLAG_STATS, (usb_dev_ptr->STATS.usb_empty_isr_count++));
return;
} /* Endif */
/*
USB_printf("USB_ISR: FRINDEX=0x%x, status=0x%x, PORTSC=0x%x, EP_SETUP=0x%x, EP_COMPLETE=0x%x\n",
USB_32BIT_LE(dev_ptr->REGISTERS.OPERATIONAL_DEVICE_REGISTERS.USB_FRINDEX),
status,
USB_32BIT_LE(dev_ptr->REGISTERS.OPERATIONAL_DEVICE_REGISTERS.PORTSCX[0]),
USB_32BIT_LE(dev_ptr->REGISTERS.OPERATIONAL_DEVICE_REGISTERS.ENDPT_SETUP_STAT),
USB_32BIT_LE(dev_ptr->REGISTERS.OPERATIONAL_DEVICE_REGISTERS.ENDPTCOMPLETE) );
*/
/* Clear all the interrupts occured */
dev_ptr->REGISTERS.OPERATIONAL_DEVICE_REGISTERS.USB_STS = USB_32BIT_LE(status);
if (status & EHCI_STS_ERR)
{
usb_dev_ptr->ERROR_STATE = (status & 0xFFFF);
_usb_dci_vusb20_process_error((pointer)usb_dev_ptr);
/* do tr_complete if no STS_INT set */
if( (status & EHCI_STS_INT) == 0)
_usb_dci_vusb20_process_tr_complete((pointer)usb_dev_ptr);
/*USB_printf("USB process error: status=0x%x\n", status);*/
} /* Endif */
if (status & EHCI_STS_RESET)
{
_usb_dci_vusb20_process_reset((pointer)usb_dev_ptr);
} /* Endif */
if (status & EHCI_STS_PORT_CHANGE)
{
_usb_dci_vusb20_process_port_change((pointer)usb_dev_ptr);
} /* Endif */
if (status & EHCI_STS_SOF)
{
_usb_dci_vusb20_process_SOF((pointer)usb_dev_ptr);
} /* Endif */
if (status & EHCI_STS_INT)
{
_usb_dci_vusb20_process_tr_complete((pointer)usb_dev_ptr);
} /* Endif */
if (status & EHCI_STS_SUSPEND)
{
_usb_dci_vusb20_process_suspend((pointer)usb_dev_ptr);
} /* Endif */
} /* EndBody */
/*FUNCTION*-------------------------------------------------------------
*
* Function Name : _usb_dci_vusb20_process_reset
* Returned Value : None
* Comments :
* Services reset interrupt
*
*END*-----------------------------------------------------------------*/
void _usb_dci_vusb20_process_reset
(
/* [IN] the USB_dev_initialize state structure */
_usb_device_handle handle
)
{ /* Body */
USB_DEV_STATE_STRUCT_PTR usb_dev_ptr;
VUSB20_REG_STRUCT_PTR dev_ptr;
uint_32 temp;
volatile unsigned long timeout;
usb_dev_ptr = (USB_DEV_STATE_STRUCT_PTR)handle;
ARC_DEBUG_TRACE(ARC_DEBUG_FLAG_ISR, "process_reset\n");
ARC_DEBUG_CODE(ARC_DEBUG_FLAG_STATS, (usb_dev_ptr->STATS.usb_reset_count++));
dev_ptr = (VUSB20_REG_STRUCT_PTR)usb_dev_ptr->DEV_PTR;
/* Inform the application so that it can cancel all previously queued transfers */
_usb_device_call_service(usb_dev_ptr, ARC_USB_SERVICE_BUS_RESET, 0, 0, 0, 0, 0);
#if defined(USB_UNDERRUN_WA)
_usb_reset_send_queue();
#endif /* USB_UNDERRUN_WA */
/* The address bits are past bit 25-31. Set the address */
dev_ptr->REGISTERS.OPERATIONAL_DEVICE_REGISTERS.DEVICE_ADDR &= ~USB_32BIT_LE(0xFE000000);
/* Clear all the setup token semaphores */
temp = USB_32BIT_LE(dev_ptr->REGISTERS.OPERATIONAL_DEVICE_REGISTERS.ENDPT_SETUP_STAT);
dev_ptr->REGISTERS.OPERATIONAL_DEVICE_REGISTERS.ENDPT_SETUP_STAT = USB_32BIT_LE(temp);
/* Clear all the endpoint complete status bits */
temp = USB_32BIT_LE(dev_ptr->REGISTERS.OPERATIONAL_DEVICE_REGISTERS.ENDPTCOMPLETE);
dev_ptr->REGISTERS.OPERATIONAL_DEVICE_REGISTERS.ENDPTCOMPLETE = USB_32BIT_LE(temp);
timeout = 0x10000;
while (USB_32BIT_LE(dev_ptr->REGISTERS.OPERATIONAL_DEVICE_REGISTERS.ENDPTPRIME) & 0xFFFFFFFF)
{
timeout--;
if(timeout <= 0)
{
USB_printf("%s: Timeout for ENDPTPRIME = 0x%x\n", __FUNCTION__,
(unsigned)USB_32BIT_LE(dev_ptr->REGISTERS.OPERATIONAL_DEVICE_REGISTERS.ENDPTPRIME));
break;
}
/* Wait until all ENDPTPRIME bits cleared */
} /* Endif */
/* Write 1s to the Flush register */
dev_ptr->REGISTERS.OPERATIONAL_DEVICE_REGISTERS.ENDPTFLUSH = USB_32BIT_LE(0xFFFFFFFF);
if( (usb_dev_ptr->ERROR_STATE == 0x0) &&
(USB_32BIT_LE(dev_ptr->REGISTERS.OPERATIONAL_DEVICE_REGISTERS.PORTSCX[0]) &
EHCI_PORTSCX_PORT_RESET) )
{
ARC_DEBUG_TRACE(ARC_DEBUG_FLAG_RESET,
"USB Bus Reset: fri=0x%x, dev_ptr=%p, STATE=%d, PORTSC=0x%x, CMD=0x%x, ENDPT[0]=0x%x\n",
USB_32BIT_LE(dev_ptr->REGISTERS.OPERATIONAL_DEVICE_REGISTERS.USB_FRINDEX),
usb_dev_ptr, usb_dev_ptr->USB_STATE,
USB_32BIT_LE(dev_ptr->REGISTERS.OPERATIONAL_DEVICE_REGISTERS.PORTSCX[0]),
USB_32BIT_LE(dev_ptr->REGISTERS.OPERATIONAL_DEVICE_REGISTERS.USB_CMD),
USB_32BIT_LE(dev_ptr->REGISTERS.OPERATIONAL_DEVICE_REGISTERS.ENDPTCTRLX[0]));
usb_dev_ptr->BUS_RESETTING = TRUE;
usb_dev_ptr->USB_STATE = ARC_USB_STATE_POWERED;
}
else
{
USB_printf("USB Chip reinit: PORTSC=0x%x\n",
USB_32BIT_LE(dev_ptr->REGISTERS.OPERATIONAL_DEVICE_REGISTERS.PORTSCX[0]));
/* re-initialize */
_usb_dci_vusb20_chip_initialize((pointer)usb_dev_ptr);
ARC_DEBUG_TRACE(ARC_DEBUG_FLAG_INIT, "process_reset, Chip reinit hw\n");
} /* Endif */
_usb_device_call_service(usb_dev_ptr, ARC_USB_SERVICE_BUS_RESET, 1, 0, 0, 0, 0);
} /* EndBody */
/*FUNCTION*-------------------------------------------------------------
*
* Function Name : _usb_dci_vusb20_process_suspend
* Returned Value : None
* Comments :
* Services suspend interrupt
*
*END*-----------------------------------------------------------------*/
void _usb_dci_vusb20_process_suspend
(
/* [IN] the USB_dev_initialize state structure */
_usb_device_handle handle
)
{ /* Body */
USB_DEV_STATE_STRUCT_PTR usb_dev_ptr;
VUSB20_REG_STRUCT_PTR dev_ptr;
usb_dev_ptr = (USB_DEV_STATE_STRUCT_PTR)handle;
dev_ptr = (VUSB20_REG_STRUCT_PTR)usb_dev_ptr->DEV_PTR;
ARC_DEBUG_TRACE(ARC_DEBUG_FLAG_ISR, "process_suspend\n");
ARC_DEBUG_CODE(ARC_DEBUG_FLAG_STATS, (usb_dev_ptr->STATS.usb_suspend_count++));
usb_dev_ptr->USB_DEV_STATE_B4_SUSPEND = usb_dev_ptr->USB_STATE;
usb_dev_ptr->USB_STATE = ARC_USB_STATE_SUSPEND;
/* Inform the upper layers */
_usb_device_call_service(usb_dev_ptr, ARC_USB_SERVICE_SLEEP, 0, 0, 0, 0, 0);
} /* EndBody */
/*FUNCTION*-------------------------------------------------------------
*
* Function Name : _usb_dci_vusb20_process_SOF
* Returned Value : None
* Comments :
* Services SOF interrupt
*
*END*-----------------------------------------------------------------*/
void _usb_dci_vusb20_process_SOF
(
/* [IN] the USB_dev_initialize state structure */
_usb_device_handle handle
)
{ /* Body */
USB_DEV_STATE_STRUCT_PTR usb_dev_ptr;
VUSB20_REG_STRUCT_PTR dev_ptr;
ARC_DEBUG_TRACE(ARC_DEBUG_FLAG_ISR, "process_SOF\n");
usb_dev_ptr = (USB_DEV_STATE_STRUCT_PTR)handle;
dev_ptr = (VUSB20_REG_STRUCT_PTR)usb_dev_ptr->DEV_PTR;
/* Inform the upper layer */
_usb_device_call_service(usb_dev_ptr, ARC_USB_SERVICE_SOF, 0, 0, 0,
USB_32BIT_LE(dev_ptr->REGISTERS.OPERATIONAL_DEVICE_REGISTERS.USB_FRINDEX), 0);
} /* EndBody */
/*FUNCTION*-------------------------------------------------------------
*
* Function Name : _usb_dci_vusb20_process_port_change
* Returned Value : None
* Comments :
* Services port change detect interrupt
*
*END*-----------------------------------------------------------------*/
void _usb_dci_vusb20_process_port_change
(
/* [IN] the USB_dev_initialize state structure */
_usb_device_handle handle
)
{ /* Body */
USB_DEV_STATE_STRUCT_PTR usb_dev_ptr;
VUSB20_REG_STRUCT_PTR dev_ptr;
usb_dev_ptr = (USB_DEV_STATE_STRUCT_PTR)handle;
ARC_DEBUG_TRACE(ARC_DEBUG_FLAG_ISR, "process_port_change\n");
ARC_DEBUG_CODE(ARC_DEBUG_FLAG_STATS, (usb_dev_ptr->STATS.usb_port_change_count++));
dev_ptr = (VUSB20_REG_STRUCT_PTR)usb_dev_ptr->DEV_PTR;
/*
USB_printf("port_change: PORTSC=0x%x, DTD_ENTRIES=%d, XD_ENTRIES=%d\n",
USB_32BIT_LE(dev_ptr->REGISTERS.OPERATIONAL_DEVICE_REGISTERS.PORTSCX[0]),
usb_dev_ptr->DTD_ENTRIES, usb_dev_ptr->XD_ENTRIES);
*/
if (usb_dev_ptr->BUS_RESETTING)
{
/* Bus reset operation complete */
usb_dev_ptr->BUS_RESETTING = FALSE;
} /* Endif */
if (!(USB_32BIT_LE(dev_ptr->REGISTERS.OPERATIONAL_DEVICE_REGISTERS.PORTSCX[0]) &
EHCI_PORTSCX_PORT_RESET))
{
/* Get the speed */
if (USB_32BIT_LE(dev_ptr->REGISTERS.OPERATIONAL_DEVICE_REGISTERS.PORTSCX[0]) &
EHCI_PORTSCX_PORT_HIGH_SPEED)
{
usb_dev_ptr->SPEED = ARC_USB_SPEED_HIGH;
}
else
{
usb_dev_ptr->SPEED = ARC_USB_SPEED_FULL;
} /* Endif */
/*
USB_printf("USB %s speed device detected\n",
(usb_dev_ptr->SPEED == ARC_USB_SPEED_HIGH) ? "High" : "Full");
*/
/* Inform the upper layers of the speed of operation */
_usb_device_call_service(usb_dev_ptr, ARC_USB_SERVICE_SPEED_DETECTION, 0, 0,
0, usb_dev_ptr->SPEED, 0);
} /* Endif */
if (USB_32BIT_LE(dev_ptr->REGISTERS.OPERATIONAL_DEVICE_REGISTERS.PORTSCX[0]) &
EHCI_PORTSCX_PORT_SUSPEND)
{
usb_dev_ptr->USB_DEV_STATE_B4_SUSPEND = usb_dev_ptr->USB_STATE;
usb_dev_ptr->USB_STATE = ARC_USB_STATE_SUSPEND;
/* Inform the upper layers */
USB_printf("USB suspend\n");
_usb_device_call_service(usb_dev_ptr, ARC_USB_SERVICE_SUSPEND, 0, 0, 0, 0, 0);
} /* Endif */
if (!(USB_32BIT_LE(dev_ptr->REGISTERS.OPERATIONAL_DEVICE_REGISTERS.PORTSCX[0]) & EHCI_PORTSCX_PORT_SUSPEND)
&& (usb_dev_ptr->USB_STATE == ARC_USB_STATE_SUSPEND))
{
USB_printf("USB resume\n");
usb_dev_ptr->USB_STATE = usb_dev_ptr->USB_DEV_STATE_B4_SUSPEND;
/* Inform the upper layers */
_usb_device_call_service(usb_dev_ptr, ARC_USB_SERVICE_RESUME, 0, 0, 0, 0, 0);
ARC_DEBUG_TRACE(ARC_DEBUG_FLAG_SUSPEND, "process_port_change, SUCCESSFUL, resumed\n");
return;
} /* Endif */
usb_dev_ptr->USB_STATE = ARC_USB_STATE_DEFAULT;
} /* EndBody */
/*FUNCTION*-------------------------------------------------------------
*
* Function Name : _usb_dci_vusb20_process_error
* Returned Value : None
* Comments :
* Services error interrupt
*
*END*-----------------------------------------------------------------*/
void _usb_dci_vusb20_process_error
(
/* [IN] the USB_dev_initialize state structure */
_usb_device_handle handle
)
{ /* Body */
USB_DEV_STATE_STRUCT_PTR usb_dev_ptr;
usb_dev_ptr = (USB_DEV_STATE_STRUCT_PTR)handle;
/* Increment the error count */
usb_dev_ptr->ERRORS++;
ARC_DEBUG_TRACE(ARC_DEBUG_FLAG_ERROR,
"process_error_%d: state=0x%x\n",
usb_dev_ptr->ERRORS, usb_dev_ptr->ERROR_STATE);
} /* EndBody */
/*FUNCTION*-------------------------------------------------------------
*
* Function Name : _usb_dci_vusb20_set_speed_full
* Returned Value : None
* Comments :
* Force the controller port in full speed mode.
*
*END*-----------------------------------------------------------------*/
void _usb_dci_vusb20_set_speed_full
(
/* [IN] the USB_dev_initialize state structure */
_usb_device_handle handle,
/* The port number on the device */
uint_8 port_number
)
{ /* Body */
USB_DEV_STATE_STRUCT_PTR usb_dev_ptr;
VUSB20_REG_STRUCT_PTR dev_ptr;
uint_32 port_control;
ARC_DEBUG_TRACE(ARC_DEBUG_FLAG_ANY, "FORCE set_speed_full\n");
usb_dev_ptr = (USB_DEV_STATE_STRUCT_PTR)handle;
dev_ptr = (VUSB20_REG_STRUCT_PTR)usb_dev_ptr->DEV_PTR;
port_control = USB_32BIT_LE(dev_ptr->REGISTERS.OPERATIONAL_DEVICE_REGISTERS.PORTSCX[port_number]);
port_control |= EHCI_PORTSCX_FORCE_FULL_SPEED_CONNECT;
dev_ptr->REGISTERS.OPERATIONAL_DEVICE_REGISTERS.PORTSCX[port_number] = USB_32BIT_LE(port_control);
} /* EndBody */
/*FUNCTION*-------------------------------------------------------------
*
* Function Name : _usb_dci_vusb20_suspend_phy
* Returned Value : None
* Comments :
* Suspends the PHY in low power mode
*
*END*-----------------------------------------------------------------*/
void _usb_dci_vusb20_suspend_phy
(
/* [IN] the USB_dev_initialize state structure */
_usb_device_handle handle,
/* The port number on the device */
uint_8 port_number
)
{ /* Body */
USB_DEV_STATE_STRUCT_PTR usb_dev_ptr;
VUSB20_REG_STRUCT_PTR dev_ptr;
uint_32 port_control;
ARC_DEBUG_TRACE(ARC_DEBUG_FLAG_SUSPEND, "set_suspend_phy\n");
usb_dev_ptr = (USB_DEV_STATE_STRUCT_PTR)handle;
dev_ptr = (VUSB20_REG_STRUCT_PTR)usb_dev_ptr->DEV_PTR;
port_control = USB_32BIT_LE(dev_ptr->REGISTERS.OPERATIONAL_DEVICE_REGISTERS.PORTSCX[port_number]);
port_control |= EHCI_PORTSCX_PHY_CLOCK_DISABLE;
dev_ptr->REGISTERS.OPERATIONAL_DEVICE_REGISTERS.PORTSCX[port_number] = USB_32BIT_LE(port_control);
} /* EndBody */
/*FUNCTION*-------------------------------------------------------------
*
* Function Name : _usb_dci_vusb20_set_address
* Returned Value : None
* Comments :
* Sets the newly assigned device address
*
*END*-----------------------------------------------------------------*/
void _usb_dci_vusb20_set_address
(
/* [IN] the USB_dev_initialize state structure */
_usb_device_handle handle,
/* Address of the device assigned by the host */
uint_8 address
)
{ /* Body */
USB_DEV_STATE_STRUCT_PTR usb_dev_ptr;
VUSB20_REG_STRUCT_PTR dev_ptr;
ARC_DEBUG_TRACE(ARC_DEBUG_FLAG_ADDR, "set_address: address=%d\n",address);
usb_dev_ptr = (USB_DEV_STATE_STRUCT_PTR)handle;
dev_ptr = (VUSB20_REG_STRUCT_PTR)usb_dev_ptr->DEV_PTR;
#ifdef SET_ADDRESS_HARDWARE_ASSISTANCE
/***********************************************************
Hardware Rev 4.0 onwards have special assistance built in
for handling the set_address command. As per the USB specs
a device should be able to receive the response on a new
address, within 2 msecs after status phase of set_address is
completed. Since 2 mili second may be a very small time window
(on high interrupt latency systems) before software could
come to the code below and write the device register,
this routine will be called in advance when status phase of
set_address is still not finished. The following line in the
code will set the bit 24 to '1' and hardware will take
the address and queue it in an internal buffer. From which
it will use it to decode the next USB token. Please look
at hardware rev details for the implementation of this
assistance.
Also note that writing bit 24 to 0x01 will not break
any old hardware revs because it was an unused bit.
***********************************************************/
/* The address bits are past bit 25-31. Set the address
also set the bit 24 to 0x01 to start hardware assitance*/
dev_ptr->REGISTERS.OPERATIONAL_DEVICE_REGISTERS.DEVICE_ADDR =
USB_32BIT_LE((uint_32)address << VUSBHS_ADDRESS_BIT_SHIFT) |
(0x01 << (VUSBHS_ADDRESS_BIT_SHIFT -1));
#else
dev_ptr->REGISTERS.OPERATIONAL_DEVICE_REGISTERS.DEVICE_ADDR =
USB_32BIT_LE((uint_32)address << VUSBHS_ADDRESS_BIT_SHIFT);
#endif /* SET_ADDRESS_HARDWARE_ASSISTANCE */
usb_dev_ptr->USB_STATE = ARC_USB_STATE_ADDRESS;
} /* EndBody */
/*FUNCTION*-------------------------------------------------------------
*
* Function Name : _usb_dci_vusb20_get_setup_data
* Returned Value : None
* Comments :
* Reads the Setup data from the 8-byte setup buffer
*
*END*-----------------------------------------------------------------*/
void _usb_dci_vusb20_get_setup_data
(
/* [IN] the USB_dev_initialize state structure */
_usb_device_handle handle,
/* [IN] the Endpoint number */
uint_8 ep_num,
/* [OUT] address of the buffer to read the setup data into */
uint_8_ptr buffer_ptr
)
{ /* Body */
USB_DEV_STATE_STRUCT_PTR usb_dev_ptr;
volatile VUSB20_REG_STRUCT_PTR dev_ptr;
volatile VUSB20_EP_QUEUE_HEAD_STRUCT_PTR ep_queue_head_ptr;
volatile boolean read_safe = FALSE;
volatile unsigned long timeout;
usb_dev_ptr = (USB_DEV_STATE_STRUCT_PTR)handle;
dev_ptr = (VUSB20_REG_STRUCT_PTR)usb_dev_ptr->DEV_PTR;
/* Get the endpoint queue head */
ep_queue_head_ptr = (VUSB20_EP_QUEUE_HEAD_STRUCT_PTR)usb_dev_ptr->EP_QUEUE_HEAD_PTR +
2*ep_num + ARC_USB_RECV;
/********************************************************************
CR 1219. Hardware versions 2.3+ have a implementation of tripwire
semaphore mechanism that requires that we read the contents of
QH safely by using the semaphore. Read the USBHS document to under
stand how the code uses the semaphore mechanism. The following are
the steps in brief
1. USBCMD Write <EFBFBD>1<EFBFBD> to Setup Tripwire in register.
2. Duplicate contents of dQH.StatusBuffer into local software byte
array.
3 Read Setup TripWire in register. (if set - continue; if
cleared goto 1.)
4. Write '0' to clear Setup Tripwire in register.
5. Process setup packet using local software byte array copy and
execute status/handshake phases.
********************************************************************/
timeout = 0x100000;
while(!read_safe)
{
/*********************************************************
start with setting the semaphores
*********************************************************/
dev_ptr->REGISTERS.OPERATIONAL_DEVICE_REGISTERS.USB_CMD |=
USB_32BIT_LE(EHCI_CMD_SETUP_TRIPWIRE_SET);
/* Copy the setup packet to private buffer */
USB_memcopy((uint_8_ptr)ep_queue_head_ptr->SETUP_BUFFER, buffer_ptr, 8);
/*********************************************************
If setup tripwire semaphore is cleared by hardware it means
that we have a danger and we need to restart.
else we can exit out of loop safely.
*********************************************************/
if(USB_32BIT_LE(dev_ptr->REGISTERS.OPERATIONAL_DEVICE_REGISTERS.USB_CMD) &
EHCI_CMD_SETUP_TRIPWIRE_SET)
{
read_safe = TRUE; /* we can proceed exiting out of loop*/
}
if(timeout <= 0)
{
USB_printf("%s: Timeout for SETUP_TRIPWIRE = 0x%x\n", __FUNCTION__,
(unsigned)USB_32BIT_LE(dev_ptr->REGISTERS.OPERATIONAL_DEVICE_REGISTERS.USB_CMD));
break;
}
}
ARC_DEBUG_CODE(ARC_DEBUG_FLAG_STATS, (usb_dev_ptr->STATS.usb_read_setup_count++));
/*********************************************************
Clear the semaphore bit now
*********************************************************/
dev_ptr->REGISTERS.OPERATIONAL_DEVICE_REGISTERS.USB_CMD &=
USB_32BIT_LE(EHCI_CMD_SETUP_TRIPWIRE_CLEAR);
/* Clear the bit in the ENDPTSETUPSTAT */
dev_ptr->REGISTERS.OPERATIONAL_DEVICE_REGISTERS.ENDPT_SETUP_STAT = USB_32BIT_LE(1 << ep_num);
} /* EndBody */
/*FUNCTION*-------------------------------------------------------------
*
* Function Name : _usb_dci_vusb20_init_endpoint
* Returned Value : None
* Comments :
* Initializes the specified endpoint and the endpoint queue head
*
*END*-----------------------------------------------------------------*/
uint_8 _usb_dci_vusb20_init_endpoint
(
/* [IN] the USB_dev_initialize state structure */
_usb_device_handle handle,
/* [IN] the transaction descriptor address */
XD_STRUCT_PTR xd_ptr
)
{ /* Body */
USB_DEV_STATE_STRUCT_PTR usb_dev_ptr;
VUSB20_REG_STRUCT_PTR dev_ptr;
VUSB20_EP_QUEUE_HEAD_STRUCT _PTR_ ep_queue_head_ptr;
uint_32 val, bit_pos;
usb_dev_ptr = (USB_DEV_STATE_STRUCT_PTR)handle;
dev_ptr = (VUSB20_REG_STRUCT_PTR)usb_dev_ptr->DEV_PTR;
/* Get the endpoint queue head address */
ep_queue_head_ptr = (VUSB20_EP_QUEUE_HEAD_STRUCT_PTR)usb_dev_ptr->EP_QUEUE_HEAD_PTR +
2*xd_ptr->EP_NUM + xd_ptr->BDIRECTION;
bit_pos = (1 << (16 * xd_ptr->BDIRECTION + xd_ptr->EP_NUM));
/* Check if the Endpoint is Primed */
if ((!(USB_32BIT_LE(dev_ptr->REGISTERS.OPERATIONAL_DEVICE_REGISTERS.ENDPTPRIME) & bit_pos)) &&
(!(USB_32BIT_LE(dev_ptr->REGISTERS.OPERATIONAL_DEVICE_REGISTERS.ENDPTSTATUS) & bit_pos)))
{
/* Set the max packet length, interrupt on Setup and Mult fields */
if (xd_ptr->EP_TYPE == ARC_USB_ISOCHRONOUS_ENDPOINT)
{
/* Mult bit should be set for isochronous endpoints */
ep_queue_head_ptr->MAX_PKT_LENGTH = USB_32BIT_LE((xd_ptr->WMAXPACKETSIZE << 16) |
((xd_ptr->MAX_PKTS_PER_UFRAME ? xd_ptr->MAX_PKTS_PER_UFRAME : 1) <<
VUSB_EP_QUEUE_HEAD_MULT_POS));
}
else
{
if (xd_ptr->EP_TYPE != ARC_USB_CONTROL_ENDPOINT)
{
/* BULK or INTERRUPT */
ep_queue_head_ptr->MAX_PKT_LENGTH = USB_32BIT_LE((xd_ptr->WMAXPACKETSIZE << 16) |
(xd_ptr->DONT_ZERO_TERMINATE ? VUSB_EP_QUEUE_HEAD_ZERO_LEN_TER_SEL : 0));
}
else
{
/* CONTROL */
ep_queue_head_ptr->MAX_PKT_LENGTH = USB_32BIT_LE((xd_ptr->WMAXPACKETSIZE << 16) |
VUSB_EP_QUEUE_HEAD_IOS);
} /* Endif */
} /* Endif */
/* Enable the endpoint for Rx or Tx and set the endpoint type */
val = dev_ptr->REGISTERS.OPERATIONAL_DEVICE_REGISTERS.ENDPTCTRLX[xd_ptr->EP_NUM];
if(xd_ptr->BDIRECTION == ARC_USB_SEND)
{
val &= ~(USB_32BIT_LE(EHCI_EPCTRL_TX_ALL_MASK));
val |= USB_32BIT_LE((EHCI_EPCTRL_TX_ENABLE | EHCI_EPCTRL_TX_DATA_TOGGLE_RST) |
(xd_ptr->EP_TYPE << EHCI_EPCTRL_TX_EP_TYPE_SHIFT));
}
else
{
val &= ~(USB_32BIT_LE(EHCI_EPCTRL_RX_ALL_MASK));
val |= USB_32BIT_LE((EHCI_EPCTRL_RX_ENABLE | EHCI_EPCTRL_RX_DATA_TOGGLE_RST) |
(xd_ptr->EP_TYPE << EHCI_EPCTRL_RX_EP_TYPE_SHIFT));
}
dev_ptr->REGISTERS.OPERATIONAL_DEVICE_REGISTERS.ENDPTCTRLX[xd_ptr->EP_NUM] = val;
/* Implement Guideline (GL# USB-7) The unused endpoint type must */
/* be programmed to bulk. */
if( (dev_ptr->REGISTERS.OPERATIONAL_DEVICE_REGISTERS.ENDPTCTRLX[xd_ptr->EP_NUM] &
USB_32BIT_LE(EHCI_EPCTRL_RX_ENABLE)) == 0)
{
dev_ptr->REGISTERS.OPERATIONAL_DEVICE_REGISTERS.ENDPTCTRLX[xd_ptr->EP_NUM] |=
USB_32BIT_LE(ARC_USB_BULK_ENDPOINT << EHCI_EPCTRL_RX_EP_TYPE_SHIFT);
}
if( (dev_ptr->REGISTERS.OPERATIONAL_DEVICE_REGISTERS.ENDPTCTRLX[xd_ptr->EP_NUM] &
USB_32BIT_LE(EHCI_EPCTRL_TX_ENABLE)) == 0)
{
dev_ptr->REGISTERS.OPERATIONAL_DEVICE_REGISTERS.ENDPTCTRLX[xd_ptr->EP_NUM] |=
USB_32BIT_LE(ARC_USB_BULK_ENDPOINT << EHCI_EPCTRL_TX_EP_TYPE_SHIFT);
}
ARC_DEBUG_TRACE(ARC_DEBUG_FLAG_INIT,
"init ep #%d %s: type=0x%x, EPCTRLX=0x%x, SETUP=0x%x, PRIME=0x%x, STATUS=0x%x, COMPL=0x%x\n",
xd_ptr->EP_NUM, xd_ptr->BDIRECTION ? "SEND" : "RECV", xd_ptr->EP_TYPE,
(unsigned)USB_32BIT_LE(dev_ptr->REGISTERS.OPERATIONAL_DEVICE_REGISTERS.ENDPTCTRLX[xd_ptr->EP_NUM]),
(unsigned)USB_32BIT_LE(dev_ptr->REGISTERS.OPERATIONAL_DEVICE_REGISTERS.ENDPT_SETUP_STAT),
(unsigned)USB_32BIT_LE(dev_ptr->REGISTERS.OPERATIONAL_DEVICE_REGISTERS.ENDPTPRIME),
(unsigned)USB_32BIT_LE(dev_ptr->REGISTERS.OPERATIONAL_DEVICE_REGISTERS.ENDPTSTATUS),
(unsigned)USB_32BIT_LE(dev_ptr->REGISTERS.OPERATIONAL_DEVICE_REGISTERS.ENDPTCOMPLETE) );
}
else
{
USB_printf("ep=%d %s: Init ERROR: ENDPTPRIME=0x%x, ENDPTSTATUS=0x%x, bit_pos=0x%x\n",
(unsigned)xd_ptr->EP_NUM, xd_ptr->BDIRECTION ? "SEND" : "RECV",
(unsigned)USB_32BIT_LE(dev_ptr->REGISTERS.OPERATIONAL_DEVICE_REGISTERS.ENDPTPRIME),
(unsigned)USB_32BIT_LE(dev_ptr->REGISTERS.OPERATIONAL_DEVICE_REGISTERS.ENDPTSTATUS),
(unsigned)bit_pos);
return USBERR_EP_INIT_FAILED;
} /* Endif */
return USB_OK;
} /* EndBody */
/*FUNCTION*-------------------------------------------------------------
*
* Function Name : _usb_dci_vusb20_get_transfer_status
* Returned Value : USB_OK or error code
* Comments :
* Gets the status of a transfer
*
*END*-----------------------------------------------------------------*/
uint_8 _usb_dci_vusb20_get_transfer_status
(
/* [IN] the USB_dev_initialize state structure */
_usb_device_handle handle,
/* [IN] the Endpoint number */
uint_8 ep_num,
/* [IN] direction */
uint_8 direction
)
{ /* Body */
USB_DEV_STATE_STRUCT_PTR usb_dev_ptr;
VUSB20_EP_TR_STRUCT_PTR dTD_ptr;
XD_STRUCT_PTR xd_ptr;
uint_8 status;
usb_dev_ptr = (USB_DEV_STATE_STRUCT_PTR)handle;
/* Unlink the dTD */
dTD_ptr = usb_dev_ptr->EP_DTD_HEADS[2*ep_num + direction];
if (dTD_ptr)
{
/* Get the transfer descriptor for the dTD */
xd_ptr = (XD_STRUCT_PTR)dTD_ptr->SCRATCH_PTR->XD_FOR_THIS_DTD;
status = xd_ptr->BSTATUS;
}
else
{
status = ARC_USB_STATUS_IDLE;
} /* Endif */
return (status);
} /* EndBody */
/*FUNCTION*-------------------------------------------------------------
*
* Function Name : _usb_dci_vusb20_get_transfer_details
* Returned Value : pointer to structure that has details for transfer
* Gets the status of a transfer
*
*END*-----------------------------------------------------------------*/
XD_STRUCT_PTR _usb_dci_vusb20_get_transfer_details
(
/* [IN] the USB_dev_initialize state structure */
_usb_device_handle handle,
/* [IN] the Endpoint number */
uint_8 ep_num,
/* [IN] direction */
uint_8 direction
)
{ /* Body */
USB_DEV_STATE_STRUCT_PTR usb_dev_ptr;
VUSB20_REG_STRUCT_PTR dev_ptr;
VUSB20_EP_TR_STRUCT_PTR dTD_ptr, temp_dTD_ptr;
XD_STRUCT_PTR xd_ptr;
uint_32 temp, remaining_bytes;
VUSB20_EP_QUEUE_HEAD_STRUCT_PTR ep_queue_head_ptr;
usb_dev_ptr = (USB_DEV_STATE_STRUCT_PTR)handle;
dev_ptr = (VUSB20_REG_STRUCT_PTR)usb_dev_ptr->DEV_PTR;
temp = (2*ep_num + direction);
/* get a pointer to QH for this endpoint */
ep_queue_head_ptr = (VUSB20_EP_QUEUE_HEAD_STRUCT_PTR)usb_dev_ptr->EP_QUEUE_HEAD_PTR + temp;
ARC_DEBUG_TRACE(ARC_DEBUG_FLAG_TRACE, "get_transfer_details\n");
/* Unlink the dTD */
dTD_ptr = usb_dev_ptr->EP_DTD_HEADS[2*ep_num + direction];
if (dTD_ptr)
{
/* Get the transfer descriptor for the dTD */
xd_ptr = (XD_STRUCT_PTR)dTD_ptr->SCRATCH_PTR->XD_FOR_THIS_DTD;
if(!xd_ptr) return NULL;
/* Initialize the transfer length field */
xd_ptr->WSOFAR =0;
remaining_bytes =0;
/*if length of this transfer is greater than 20K
we have multiple DTDs to count */
if(xd_ptr->WTOTALLENGTH > VUSB_EP_MAX_LENGTH_TRANSFER)
{
/* it is a valid DTD. We should parse all DTDs for this XD
and find the total bytes used so far */
temp_dTD_ptr = dTD_ptr;
/*loop through the list of DTDS until an active DTD is found
or list has finished */
while(!(USB_32BIT_LE(dTD_ptr->NEXT_TR_ELEM_PTR) & VUSBHS_TD_NEXT_TERMINATE))
{
/**********************************************************
If this DTD has been overlayed, we take the actual length
from QH.
**********************************************************/
if ((uint_32)(USB_32BIT_LE(ep_queue_head_ptr->CURR_DTD_PTR) & VUSBHS_TD_ADDR_MASK) ==
USB_DTD_VIRT_TO_PHYS(usb_dev_ptr, temp_dTD_ptr) )
{
remaining_bytes +=
((USB_32BIT_LE(ep_queue_head_ptr->SIZE_IOC_INT_STS) & VUSB_EP_TR_PACKET_SIZE) >> 16);
}
else
{
/* take the length from DTD itself */
remaining_bytes +=
((USB_32BIT_LE(temp_dTD_ptr->SIZE_IOC_STS) & VUSB_EP_TR_PACKET_SIZE) >> 16);
}
dTD_ptr = temp_dTD_ptr;
/* Get the address of the next dTD */
temp_dTD_ptr = (VUSB20_EP_TR_STRUCT_PTR)USB_DTD_PHYS_TO_VIRT(usb_dev_ptr,
(uint_32)(USB_32BIT_LE(temp_dTD_ptr->NEXT_TR_ELEM_PTR) & VUSBHS_TD_ADDR_MASK) );
}
xd_ptr->WSOFAR = xd_ptr->WTOTALLENGTH - remaining_bytes;
}
else
{
/*look at actual length from QH*/
xd_ptr->WSOFAR = xd_ptr->WTOTALLENGTH -
((USB_32BIT_LE(ep_queue_head_ptr->SIZE_IOC_INT_STS) & VUSB_EP_TR_PACKET_SIZE) >> 16);
}
}
else
{
xd_ptr = NULL;
} /* Endif */
return (xd_ptr);
} /* EndBody */
/*FUNCTION*-------------------------------------------------------------
*
* Function Name : _usb_dci_vusb20_deinit_endpoint
* Returned Value : None
* Comments :
* Disables the specified endpoint and the endpoint queue head
*
*END*-----------------------------------------------------------------*/
uint_8 _usb_dci_vusb20_deinit_endpoint
(
/* [IN] the USB_dev_initialize state structure */
_usb_device_handle handle,
/* [IN] the Endpoint number */
uint_8 ep_num,
/* [IN] direction */
uint_8 direction
)
{ /* Body */
USB_DEV_STATE_STRUCT_PTR usb_dev_ptr;
VUSB20_REG_STRUCT_PTR dev_ptr;
VUSB20_EP_QUEUE_HEAD_STRUCT* ep_queue_head_ptr;
uint_32 bit_pos;
uint_8 status = USB_OK;
usb_dev_ptr = (USB_DEV_STATE_STRUCT_PTR)handle;
dev_ptr = (VUSB20_REG_STRUCT_PTR)usb_dev_ptr->DEV_PTR;
/* Get the endpoint queue head address */
ep_queue_head_ptr = (VUSB20_EP_QUEUE_HEAD_STRUCT_PTR)usb_dev_ptr->EP_QUEUE_HEAD_PTR +
(2*ep_num + direction);
bit_pos = (1 << (16 * direction + ep_num));
ARC_DEBUG_TRACE(ARC_DEBUG_FLAG_INIT,
"deinit ep #%d-%s: bit_pos=0x%x, EPCTRLX=0x%x, SETUP=0x%x, PRIME=0x%x, STATUS=0x%x, COMPL=0x%x\n",
ep_num, direction ? "SEND" : "RECV", bit_pos,
(unsigned)USB_32BIT_LE(dev_ptr->REGISTERS.OPERATIONAL_DEVICE_REGISTERS.ENDPTCTRLX[ep_num]),
(unsigned)USB_32BIT_LE(dev_ptr->REGISTERS.OPERATIONAL_DEVICE_REGISTERS.ENDPT_SETUP_STAT),
(unsigned)USB_32BIT_LE(dev_ptr->REGISTERS.OPERATIONAL_DEVICE_REGISTERS.ENDPTPRIME),
(unsigned)USB_32BIT_LE(dev_ptr->REGISTERS.OPERATIONAL_DEVICE_REGISTERS.ENDPTSTATUS),
(unsigned)USB_32BIT_LE(dev_ptr->REGISTERS.OPERATIONAL_DEVICE_REGISTERS.ENDPTCOMPLETE) );
/* Check if the Endpoint is Primed */
if( ((USB_32BIT_LE(dev_ptr->REGISTERS.OPERATIONAL_DEVICE_REGISTERS.ENDPTPRIME) & bit_pos)) ||
((USB_32BIT_LE(dev_ptr->REGISTERS.OPERATIONAL_DEVICE_REGISTERS.ENDPTSTATUS) & bit_pos)) )
{
USB_printf("ep=%d %s: Deinit ERROR: ENDPTPRIME=0x%x, ENDPTSTATUS=0x%x, bit_pos=0x%x\n",
(unsigned)ep_num, direction ? "SEND" : "RECV",
(unsigned)USB_32BIT_LE(dev_ptr->REGISTERS.OPERATIONAL_DEVICE_REGISTERS.ENDPTPRIME),
(unsigned)USB_32BIT_LE(dev_ptr->REGISTERS.OPERATIONAL_DEVICE_REGISTERS.ENDPTSTATUS),
(unsigned)bit_pos);
status = USBERR_EP_DEINIT_FAILED;
}
/* Reset the max packet length and the interrupt on Setup */
ep_queue_head_ptr->MAX_PKT_LENGTH = 0;
/* Disable the endpoint for Rx or Tx and reset the endpoint type */
dev_ptr->REGISTERS.OPERATIONAL_DEVICE_REGISTERS.ENDPTCTRLX[ep_num] &=
USB_32BIT_LE( ~((direction ? EHCI_EPCTRL_TX_ENABLE : EHCI_EPCTRL_RX_ENABLE) |
(direction ? EHCI_EPCTRL_TX_TYPE : EHCI_EPCTRL_RX_TYPE)));
return status;
}
/*FUNCTION*-------------------------------------------------------------
*
* Function Name : _usb_dci_vusb20_shutdown
* Returned Value : None
* Comments :
* Shuts down the VUSB_HS Device
*
*END*-----------------------------------------------------------------*/
void _usb_dci_vusb20_shutdown
(
/* [IN] the USB_dev_initialize state structure */
_usb_device_handle handle
)
{ /* Body */
USB_DEV_STATE_STRUCT_PTR usb_dev_ptr;
VUSB20_REG_STRUCT_PTR dev_ptr;
usb_dev_ptr = (USB_DEV_STATE_STRUCT_PTR)handle;
dev_ptr = (VUSB20_REG_STRUCT_PTR)usb_dev_ptr->DEV_PTR;
/* Disable interrupts */
dev_ptr->REGISTERS.OPERATIONAL_DEVICE_REGISTERS.USB_INTR &=
~(USB_32BIT_LE(EHCI_INTR_INT_EN | EHCI_INTR_ERR_INT_EN |
EHCI_INTR_PORT_CHANGE_DETECT_EN | EHCI_INTR_RESET_EN));
USB_uncached_memfree(usb_dev_ptr->EP_QUEUE_HEAD_BASE,
usb_dev_ptr->EP_QUEUE_HEAD_SIZE,
usb_dev_ptr->EP_QUEUE_HEAD_PHYS);
USB_uncached_memfree(usb_dev_ptr->DTD_BASE_PTR,
usb_dev_ptr->DTD_SIZE,
usb_dev_ptr->DTD_BASE_PHYS);
USB_memfree(usb_dev_ptr->SCRATCH_STRUCT_BASE);
USB_printf("USB shutdown: usb_dev_ptr=%p\n", usb_dev_ptr);
/* Reset the Run the bit in the command register to stop VUSB */
dev_ptr->REGISTERS.OPERATIONAL_DEVICE_REGISTERS.USB_CMD &= ~USB_32BIT_LE(EHCI_CMD_RUN_STOP);
/* Reset the controller to get default values */
dev_ptr->REGISTERS.OPERATIONAL_DEVICE_REGISTERS.USB_CMD = USB_32BIT_LE(EHCI_CMD_CTRL_RESET);
} /* EndBody */
/*FUNCTION*-------------------------------------------------------------
*
* Function Name : _usb_dci_vusb20_stop
* Returned Value : None
* Comments :
* Stop USB device controller
*
*END*-----------------------------------------------------------------*/
void _usb_dci_vusb20_stop(_usb_device_handle handle)
{
USB_DEV_STATE_STRUCT_PTR usb_dev_ptr;
VUSB20_REG_STRUCT_PTR dev_ptr;
usb_dev_ptr = (USB_DEV_STATE_STRUCT_PTR)handle;
dev_ptr = (VUSB20_REG_STRUCT_PTR)usb_dev_ptr->DEV_PTR;
/* Disable interrupts */
dev_ptr->REGISTERS.OPERATIONAL_DEVICE_REGISTERS.USB_INTR &=
~(USB_32BIT_LE(EHCI_INTR_INT_EN | EHCI_INTR_ERR_INT_EN |
EHCI_INTR_PORT_CHANGE_DETECT_EN | EHCI_INTR_RESET_EN));
/* Reset the Run the bit in the command register to stop VUSB */
dev_ptr->REGISTERS.OPERATIONAL_DEVICE_REGISTERS.USB_CMD &= ~USB_32BIT_LE(EHCI_CMD_RUN_STOP);
}
/*FUNCTION*-------------------------------------------------------------
*
* Function Name : _usb_dci_vusb20_start
* Returned Value : None
* Comments :
* Start USB device controller
*
*END*-----------------------------------------------------------------*/
void _usb_dci_vusb20_start(_usb_device_handle handle)
{
USB_DEV_STATE_STRUCT_PTR usb_dev_ptr;
VUSB20_REG_STRUCT_PTR dev_ptr;
usb_dev_ptr = (USB_DEV_STATE_STRUCT_PTR)handle;
dev_ptr = (VUSB20_REG_STRUCT_PTR)usb_dev_ptr->DEV_PTR;
/* Enable interrupts */
dev_ptr->REGISTERS.OPERATIONAL_DEVICE_REGISTERS.USB_INTR = USB_32BIT_LE(
EHCI_INTR_INT_EN
| EHCI_INTR_ERR_INT_EN
| EHCI_INTR_PORT_CHANGE_DETECT_EN
| EHCI_INTR_RESET_EN
| EHCI_INTR_DEVICE_SUSPEND
/*
| EHCI_INTR_SOF_UFRAME_EN
*/
);
usb_dev_ptr->USB_STATE = ARC_USB_STATE_UNKNOWN;
/* Set the Run bit in the command register */
dev_ptr->REGISTERS.OPERATIONAL_DEVICE_REGISTERS.USB_CMD = USB_32BIT_LE(EHCI_CMD_RUN_STOP);
}
/* EOF */