embeddedsw/XilinxProcessorIPLib/drivers/usb/src/xusb.c
Jagannadha Sutradharudu Teki 2c8f92039d embeddesw: Add initial code support
Added initial support Xilinx Embedded Software.

Signed-off-by: Jagannadha Sutradharudu Teki <jaganna@xilinx.com>
2014-06-24 16:45:01 +05:30

641 lines
No EOL
20 KiB
C
Executable file

/******************************************************************************
*
* Copyright (C) 2006 Vreelin Engineering, Inc. All Rights Reserved.
* (c) Copyright 2007-2013 Xilinx, Inc. All rights reserved.
*
* This file contains confidential and proprietary information of Xilinx, Inc.
* and is protected under U.S. and international copyright and other
* intellectual property laws.
*
* DISCLAIMER
* This disclaimer is not a license and does not grant any rights to the
* materials distributed herewith. Except as otherwise provided in a valid
* license issued to you by Xilinx, and to the maximum extent permitted by
* applicable law: (1) THESE MATERIALS ARE MADE AVAILABLE "AS IS" AND WITH ALL
* FAULTS, AND XILINX HEREBY DISCLAIMS ALL WARRANTIES AND CONDITIONS, EXPRESS,
* IMPLIED, OR STATUTORY, INCLUDING BUT NOT LIMITED TO WARRANTIES OF
* MERCHANTABILITY, NON-INFRINGEMENT, OR FITNESS FOR ANY PARTICULAR PURPOSE;
* and (2) Xilinx shall not be liable (whether in contract or tort, including
* negligence, or under any other theory of liability) for any loss or damage
* of any kind or nature related to, arising under or in connection with these
* materials, including for any direct, or any indirect, special, incidental,
* or consequential loss or damage (including loss of data, profits, goodwill,
* or any type of loss or damage suffered as a result of any action brought by
* a third party) even if such damage or loss was reasonably foreseeable or
* Xilinx had been advised of the possibility of the same.
*
* CRITICAL APPLICATIONS
* Xilinx products are not designed or intended to be fail-safe, or for use in
* any application requiring fail-safe performance, such as life-support or
* safety devices or systems, Class III medical devices, nuclear facilities,
* applications related to the deployment of airbags, or any other applications
* that could lead to death, personal injury, or severe property or
* environmental damage (individually and collectively, "Critical
* Applications"). Customer assumes the sole risk and liability of any use of
* Xilinx products in Critical Applications, subject only to applicable laws
* and regulations governing limitations on product liability.
*
* THIS COPYRIGHT NOTICE AND DISCLAIMER MUST BE RETAINED AS PART OF THIS FILE
* AT ALL TIMES.
*
******************************************************************************/
/*****************************************************************************/
/**
* @file xusb.c
*
* The XUsb driver. Functions in this file are the minimum required functions
* for this driver. See xusb.h for a detailed description of the driver.
*
* @note None.
*
* <pre>
* MODIFICATION HISTORY:
*
* Ver Who Date Changes
* ----- ---- -----------------------------------------------------------------
* 1.00a hvm 2/22/07 First release
* 2.00a hvm 10/22/08 Added DMA APIs.
* 3.00a hvm 12/3/09 Added XUsb_ReadErrorCounters API to return USB error
* counters data. Updated to use HAL processor APIs.
* XUsb_mReadReg is renamed to XUsb_ReadReg and
* XUsb_mWriteReg is renamed to XUsb_WriteReg.
* 3.02a hvm 7/15/10 Added Device ID initialization in XUsb_CfgInitialize
* function (CR555996).
* 4.00a hvm 10/21/10 Added ULPI PHY Read/Write APIs.
* Added DMA handler initialization in XUsb_CfgInitialize
* function
* 4.03a bss 06/20/10 Added SIE Reset API (XUsb_SieReset) to reset the SIE
* state machine (CR 660602)
* </pre>
*****************************************************************************/
/***************************** Include Files *********************************/
#include "xusb.h"
/************************** Constant Definitions *****************************/
/**************************** Type Definitions *******************************/
/***************** Macros (Inline Functions) Definitions *********************/
/************************** Variable Definitions *****************************/
/************************** Function Prototypes ******************************/
static void StubHandler(void);
/*****************************************************************************/
/**
*
* This function initializes a XUsb instance/driver.
*
* The initialization entails:
* - Initialize all members of the XUsb structure.
*
* @param InstancePtr is a pointer to the XUsb instance of the USB device.
* @param ConfigPtr is a pointer to a XUsb_Config configuration structure.
* This structure will contain the requested configuration for the
* device. Typically, this is a local structure and the content of
* which will be copied into the configuration structure within
* XUsb.
* @param EffectiveAddr is the device base address in the virtual memory
* address space. If the address translation is not used then the
* physical address is passed.
* Unexpected errors may occur if the address mapping is changed
* after this function is invoked.
*
* @return
* - XST_SUCCESS no errors occurred.
* - XST_FAILURE an error occurred during initialization.
*
* @note After calling XUsb_CfgInitialize() the USB device IS NOT READY
* for use. Before the USB device can be used its parameters must
* be configured. See xusb.h for details.
*
******************************************************************************/
int XUsb_CfgInitialize(XUsb *InstancePtr, XUsb_Config *ConfigPtr,
u32 EffectiveAddr)
{
u8 Index;
Xil_AssertNonvoid(InstancePtr != NULL);
Xil_AssertNonvoid(ConfigPtr != NULL);
/*
* Initialize the XUsb structure to default values.
*/
InstancePtr->Config.DeviceId = ConfigPtr->DeviceId;
InstancePtr->Config.BaseAddress = EffectiveAddr;
InstancePtr->Config.DmaEnabled = ConfigPtr->DmaEnabled;
InstancePtr->DeviceConfig.NumEndpoints = XUSB_MAX_ENDPOINTS;
for (Index = 0; Index < XUSB_MAX_ENDPOINTS; Index++) {
InstancePtr->EndPointOffset[Index] = XUSB_EP0_CONFIG_OFFSET +
(Index * 0x10);
}
InstancePtr->HandlerFunc = (XUsb_IntrHandlerFunc) StubHandler;
InstancePtr->ErrHandlerFunc = (XUsb_IntrHandlerFunc) StubHandler;
InstancePtr->DmaHandlerFunc = (XUsb_IntrHandlerFunc) StubHandler;
InstancePtr->UlpiHandlerFunc = (XUsb_IntrHandlerFunc) StubHandler;
InstancePtr->DeviceConfig.CurrentSpeed = XUSB_EP_FULL_SPEED;
InstancePtr->IsReady = XIL_COMPONENT_IS_READY;
return XST_SUCCESS;
}
/*****************************************************************************/
/**
*
* This function initializes USB End points.
*
* @param InstancePtr is a pointer to the XUsb instance.
* @param CfgPtr is pointer to a XUsb_Config configuration structure.
* This structure will contain the requested configuration for the
* device. Typically, this is a local structure and the content of
* which will be copied into the configuration structure within
* XUsb.
*
* @return
* - XST_SUCCESS no errors occurred.
* - XST_FAILURE an error occurred during initialization.
*
* @note None.
*
******************************************************************************/
int XUsb_ConfigureDevice(XUsb *InstancePtr, XUsb_DeviceConfig *CfgPtr)
{
int Index;
/*
* Initialize the End points.
*/
for (Index = 0; Index < CfgPtr->NumEndpoints; Index++) {
InstancePtr->DeviceConfig.Ep[Index].RamBase =
CfgPtr->Ep[Index].RamBase;
InstancePtr->DeviceConfig.Ep[Index].Size =
CfgPtr->Ep[Index].Size;
InstancePtr->DeviceConfig.Ep[Index].EpType =
CfgPtr->Ep[Index].EpType;
if (Index == 0) {
InstancePtr->DeviceConfig.Ep[Index].Buffer0Ready = 1;
}
else {
InstancePtr->DeviceConfig.Ep[Index].Buffer0Ready = 0;
}
InstancePtr->DeviceConfig.Ep[Index].Buffer0Count = 0;
InstancePtr->DeviceConfig.Ep[Index].Buffer1Ready = 0;
InstancePtr->DeviceConfig.Ep[Index].Buffer1Count = 0;
InstancePtr->DeviceConfig.Ep[Index].OutIn =
CfgPtr->Ep[Index].OutIn;
InstancePtr->DeviceConfig.Ep[Index].CurBufNum = 0;
XUsb_EpConfigure(InstancePtr, Index,
&InstancePtr->DeviceConfig.Ep[Index]);
}
return XST_SUCCESS;
}
/*****************************************************************************/
/**
* This function starts the USB Device.
*
* @param InstancePtr is a pointer to the XUsb instance.
*
* @return None.
*
* @note None.
*
******************************************************************************/
void XUsb_Start(XUsb *InstancePtr)
{
Xil_AssertVoid(InstancePtr != NULL);
Xil_AssertVoid(InstancePtr->IsReady == XIL_COMPONENT_IS_READY);
/*
* Start the USB Serial Interface Engine.
*/
XUsb_WriteReg(InstancePtr->Config.BaseAddress,
XUSB_CONTROL_OFFSET, XUSB_CONTROL_USB_READY_MASK);
}
/*****************************************************************************/
/**
* This function stops the USB device.
*
* @param InstancePtr is a pointer to the XUsb instance.
*
* @return None.
*
* @note None.
*
******************************************************************************/
void XUsb_Stop(XUsb *InstancePtr)
{
u32 CrRegValue;
Xil_AssertVoid(InstancePtr != NULL);
Xil_AssertVoid(InstancePtr->IsReady == XIL_COMPONENT_IS_READY);
CrRegValue = XUsb_ReadReg(InstancePtr->Config.BaseAddress,
XUSB_CONTROL_OFFSET);
CrRegValue &= ~XUSB_CONTROL_USB_READY_MASK;
/*
* Stop the USB Serial Interface Engine.
*/
XUsb_WriteReg(InstancePtr->Config.BaseAddress,
XUSB_CONTROL_OFFSET, CrRegValue);
}
/*****************************************************************************/
/**
* This function returns the current frame number.
*
* @param InstancePtr is a pointer to the XUsb instance.
*
* @return The current frame number..
*
* @note None.
*
******************************************************************************/
u32 XUsb_GetFrameNum(const XUsb *InstancePtr)
{
u32 FrameNumPtr = 0;
Xil_AssertNonvoid(InstancePtr != NULL);
Xil_AssertNonvoid(InstancePtr->IsReady == XIL_COMPONENT_IS_READY);
FrameNumPtr = XUsb_ReadReg(InstancePtr->Config.BaseAddress,
XUSB_FRAMENUM_OFFSET);
return (FrameNumPtr);
}
/*****************************************************************************/
/**
* This function sets the USB device address.
*
* @param InstancePtr is a pointer to the XUsb instance.
* @param Address is the device address to be set.
*
* @return
* - XST_SUCCESS: Address set successfully.
* - XST_INVALID_PARAM: Invalid parameter passed.
*
* @note None.
*
******************************************************************************/
int XUsb_SetDeviceAddress(XUsb *InstancePtr, u8 Address)
{
Xil_AssertNonvoid(InstancePtr != NULL);
Xil_AssertNonvoid(InstancePtr->IsReady == XIL_COMPONENT_IS_READY);
/*
* Check address range validity.
*/
if (Address > XUSB_DEVICEADDR_MAX) {
return XST_INVALID_PARAM;
}
XUsb_WriteReg(InstancePtr->Config.BaseAddress,
XUSB_ADDRESS_OFFSET, Address);
return XST_SUCCESS;
}
/*****************************************************************************/
/**
* This function sets the USB device into a given test mode.
*
* @param InstancePtr is a pointer to the XUsb instance.
* @param TestMode is the type of test to be performed.
* @param BufPtr is a pointer to the buffer containing the test packet.
*
* @return None.
*
* @note If the test mode is Test packet(TEST_PKT), then user needs
* to pass the address of the buffer containing the test packet. In
* other cases, the BufPtr parameter is not used and the user can
* send a NULL or any value. BufPtr parameter should be 32 bit
* aligned.
*
******************************************************************************/
void XUsb_SetTestMode(XUsb *InstancePtr, u8 TestMode, u8 *BufPtr)
{
volatile u32 *Src, *Dst;
u32 Count;
Xil_AssertVoid(InstancePtr != NULL);
Xil_AssertVoid(InstancePtr->IsReady == XIL_COMPONENT_IS_READY);
Xil_AssertVoid((TestMode == TEST_J) ||
(TestMode == TEST_K) ||
(TestMode == TEST_SE0_NAK) || (TestMode == TEST_PKT));
/*
* Stop the SIE.
*/
XUsb_Stop(InstancePtr);
if (TestMode == TEST_PKT) {
if (BufPtr == NULL) {
/*
* Null pointer is passed.
*/
while (1) {
/*
* Do a hardware reset to re-start the device.
*/
}
}
Src = (u32 *) BufPtr;
Dst = (u32 *) (InstancePtr->Config.BaseAddress);
Count = 14;
/*
* Copy Leurker PKT to DP RAM at 0.
*/
while (Count--) {
*Dst++ = *Src++;
}
}
/*
* Set the test mode.
*/
XUsb_WriteReg(InstancePtr->Config.BaseAddress, XUSB_TESTMODE_OFFSET,
TestMode);
/*
* Re-start the SIE.
*/
XUsb_Start(InstancePtr);
while (1) {
; /*
* Only way out is through hardware reset!
*/
}
}
/******************************************************************************/
/**
* This function resets the DMA module of the USB device
*
* @param InstancePtr is a pointer to the XUsb instance.
*
* @return None.
*
* @note After the DMA reset, only the DMA related logic part of the
* USB device will be reset and all the DMA related registers will
* be reset to the default values. Upon DMA Reset, any DMA
* transfer in progress will be stopped.
*
******************************************************************************/
void XUsb_DmaReset(XUsb *InstancePtr)
{
Xil_AssertVoid(InstancePtr != NULL);
XUsb_WriteReg(InstancePtr->Config.BaseAddress, XUSB_DMA_RESET_OFFSET,
XUSB_DMA_RESET_VALUE);
}
/******************************************************************************/
/**
* This function sets the DMA registers with the given values to initiate a DMA
* data transfer. This function is called by the XUsb_EpDataSend and
* XUsb_EpDataRecv functions.
*
* @param InstancePtr is a pointer to the XUsb instance.
* @param SrcAddr is the source address from where the data is to be
* read.
* @param DstAddr is the destination address to where the data is to be
* written.
* @param Length is the amount of data that can be transferred. The
* maximum data transfer can be 1024.
*
* @return None.
*
* @note This function doesn't guarantee that the transfer is done
* successfully. This function only initiates the DMA transfer.
*
******************************************************************************/
void XUsb_DmaTransfer(XUsb *InstancePtr, u32 *SrcAddr, u32 *DstAddr,
u16 Length)
{
Xil_AssertVoid(InstancePtr != NULL);
Xil_AssertVoid(SrcAddr != NULL);
Xil_AssertVoid(DstAddr != NULL);
Xil_AssertVoid(Length <= 1024);
/*
* Set the addresses in the DMA source and destination
* registers and then set the length into the DMA length register.
*/
XUsb_WriteReg(InstancePtr->Config.BaseAddress,
XUSB_DMA_DSAR_ADDR_OFFSET,
(u32)SrcAddr);
XUsb_WriteReg(InstancePtr->Config.BaseAddress,
XUSB_DMA_DDAR_ADDR_OFFSET,
(u32)DstAddr);
XUsb_WriteReg(InstancePtr->Config.BaseAddress,
XUSB_DMA_LENGTH_OFFSET,
Length);
}
/******************************************************************************/
/**
* This function reads the USB error counter regsiter and returns the error
* counters information.
*
* @param InstancePtr is a pointer to the XUsb instance.
* @param BitStuffErrors is a pointer to the 8 bit bitstuff error
* counter.
* @param PidErrors is a pointer to the 8 bit pid error counter.
* @param CrcErrors is a pointer to the 8 bit crc error counter.
*
* @return None.
*
* @note None.
*
******************************************************************************/
void XUsb_ReadErrorCounters(XUsb *InstancePtr, u8 *BitStuffErrors,
u8 *PidErrors, u8 *CrcErrors)
{
u32 ErrCounterReg;
Xil_AssertVoid(InstancePtr != NULL);
Xil_AssertVoid(BitStuffErrors != NULL);
Xil_AssertVoid(PidErrors != NULL);
Xil_AssertVoid(CrcErrors != NULL);
ErrCounterReg = XUsb_ReadReg(InstancePtr->Config.BaseAddress,
XUSB_ECR_OFFSET);
*BitStuffErrors = (ErrCounterReg & XUSB_ECR_BITSTUFF_ERRCNT_MASK) >>
XUSB_ECR_BITSTUFF_ERRCNT_SHIFT;
*PidErrors = (ErrCounterReg & XUSB_ECR_PID_ERRCNT_MASK) >>
XUSB_ECR_PID_ERRCNT_SHIFT;
*CrcErrors = (ErrCounterReg & XUSB_ECR_CRC_ERRCNT_MASK) >>
XUSB_ECR_CRC_ERRCNT_SHIFT;
}
/******************************************************************************/
/**
* This function initiates the USB ULPI PHY regsiter read transaction. This
* function returns the busy status if the earlier transaction is still in
* progress and returns the PHY register data upon successful read transaction.
*
* @param InstancePtr is a pointer to the XUsb instance.
* @param RegAddr is the address of the PHY register.
*
* @return
* - Register data
* - XST_DEVICE_BUSY: The previous PHY transaction is still in
* progress.
*
* @note This function waits till the BUSY bit is cleared in the ULPI
* PHY resgiter and then reads the register. The user of this API
* should note that the PHY interrupt should be ignored during read
* operation.
*
******************************************************************************/
u8 XUsb_UlpiPhyReadRegister(XUsb *InstancePtr, u8 RegAddr)
{
Xil_AssertNonvoid(InstancePtr != NULL);
/*
* Check whether the earlier transaction is complete.
*/
if (XUsb_ReadReg(InstancePtr->Config.BaseAddress,
XUSB_UPAR_OFFSET) & XUSB_UPAR_BUSY_MASK) {
return XST_DEVICE_BUSY;
}
/*
* Initiate the read transaction for the given PHY register.
*/
XUsb_WriteReg(InstancePtr->Config.BaseAddress, XUSB_UPAR_OFFSET,
RegAddr);
while (XUsb_ReadReg(InstancePtr->Config.BaseAddress,
XUSB_UPAR_OFFSET) & XUSB_UPAR_BUSY_MASK);
return(((XUsb_ReadReg(InstancePtr->Config.BaseAddress,
XUSB_UPAR_OFFSET) & XUSB_UPAR_REG_DATA_MASK) >>
XUSB_UPAR_REG_DATA_SHIFT));
}
/******************************************************************************/
/**
* This function initiates the USB ULPI PHY regsiter write transaction. This
* function returns the busy status if the earlier transaction is still in
* progress and returns a success upon successful write transaction initiation.
*
* @param InstancePtr is a pointer to the XUsb instance.
* @param RegAddr is the address of the PHY register.
* counter.
* @param UlpiPhyRegData is the data to be written to PHY register.
*
* @return
* - XST_SUCCESS: Read transaction initiated successfully.
* - XST_DEVICE_BUSY: The previous PHY transaction is still in
* progress.
*
* @note None.
*
******************************************************************************/
int XUsb_UlpiPhyWriteRegister(XUsb *InstancePtr, u8 RegAddr,
u8 UlpiPhyRegData)
{
Xil_AssertNonvoid(InstancePtr != NULL);
/*
* Check whether the earlier transaction is complete.
*/
if (XUsb_ReadReg(InstancePtr->Config.BaseAddress,
XUSB_UPAR_OFFSET) & XUSB_UPAR_BUSY_MASK) {
return XST_DEVICE_BUSY;
}
/*
* Initiate the write transaction for the given PHY register.
*/
XUsb_WriteReg(InstancePtr->Config.BaseAddress, XUSB_UPAR_OFFSET,
(RegAddr |
(XUSB_UPAR_READ_WRITE_MASK) | (UlpiPhyRegData <<
XUSB_UPAR_REG_DATA_SHIFT)));
return XST_SUCCESS;
}
/******************************************************************************/
/**
* This routine is a stub for the asynchronous callbacks. The stub is here in
* case the upper layer forgot to set the handler. On initialization, all
* handlers are set to this callback. It is considered an error for this handler
* to be invoked.
*
* @param None.
*
* @return None.
*
* @note None.
*
******************************************************************************/
static void StubHandler(void)
{
Xil_AssertVoidAlways();
}
/******************************************************************************/
/**
* This function resets the Serial Interface Engine
*
* @param InstancePtr is a pointer to the XUsb instance.
*
* @return None.
*
* @note After the SIE reset, only the SIE state machine logic part of
* the USB device will be reset and starts from Init state.
*
******************************************************************************/
void XUsb_SieReset(XUsb *InstancePtr)
{
u32 RegData;
Xil_AssertVoid(InstancePtr != NULL);
RegData = XUsb_ReadReg(InstancePtr->Config.BaseAddress,
XUSB_CONTROL_OFFSET);
/* Reset by writing 1 */
XUsb_WriteReg(InstancePtr->Config.BaseAddress, XUSB_CONTROL_OFFSET,
RegData | XUSB_CONTROL_SIE_RESET_MASK);
/* Release from reset by writing 0 */
XUsb_WriteReg(InstancePtr->Config.BaseAddress, XUSB_CONTROL_OFFSET,
RegData & (~(XUSB_CONTROL_SIE_RESET_MASK)));
}