/*
* Copyright (c) 2009 NVIDIA Corporation.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
*
* Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
*
* Neither the name of the NVIDIA Corporation nor the names of its contributors
* may be used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*
*/
/**
* @file
* @brief NVIDIA Driver Development Kit:
* NvDDK USB PHY functions
*
* @b Description: Defines USB PHY private functions
*
*/
#include "nvrm_module.h"
#include "nvrm_drf.h"
#include "ap15/arclk_rst.h"
#include "ap15/arfuse.h"
#include "ap16/arapb_misc.h"
#include "ap20/arusb.h"
#include "nvrm_hardware_access.h"
#include "nvddk_usbphy_priv.h"
#define USB_IF_REG_RD(reg)\
NV_READ32(pUsbPhy->UsbVirAdr + ((USB2_IF_USB_##reg##_0)/4))
#define USB_IF_REG_WR(reg, data)\
NV_WRITE32(pUsbPhy->UsbVirAdr + ((USB2_IF_USB_##reg##_0)/4), (data))
/* Defines for MISC register access */
#define USB_MISC_REGR(pUsbPhy, offset) \
NV_READ32(pUsbPhy->MiscVirAdr + offset/4)
#define USB_MISC_REGW(pUsbPhy, offset, value) \
NV_WRITE32(pUsbPhy->MiscVirAdr + offset/4, value)
/**
* Structure defining the fields for USB UTMI clocks delay Parameters.
*/
typedef struct UsbPllDelayParamsRec
{
// Pll-U Enable Delay Count
NvU8 EnableDelayCount;
//PLL-U Stable count
NvU8 StableCount;
//Pll-U Active delay count
NvU8 ActiveDelayCount;
//PLL-U Xtal frequency count
NvU8 XtalFreqCount;
} UsbPllDelayParams;
/*
* Set of oscillator frequencies supported
*/
typedef enum
{
NvRmClocksOscFreq_13_MHz = 0x0,
NvRmClocksOscFreq_19_2_MHz,
NvRmClocksOscFreq_12_MHz,
NvRmClocksOscFreq_26_MHz,
NvRmClocksOscFreq_Num, // dummy to get number of frequencies
NvRmClocksOscFreq_Force32 = 0x7fffffff
} NvRmClocksOscFreq;
// Possible Oscillator Frequecies in KHz for mapping the index
static NvRmFreqKHz s_RmOscFrequecy [NvRmClocksOscFreq_Num] =
{
13000, // 13 Mega Hertz
19200,// 19.2 Mega Hertz
12000,// 12 Mega Hertz
26000 // 26 Mega Hertz
};
///////////////////////////////////////////////////////////////////////////////
// USB PLL CONFIGURATION & PARAMETERS: refer to the arapb_misc_utmip.spec file.
///////////////////////////////////////////////////////////////////////////////
// PLL CONFIGURATION & PARAMETERS for different clock generators:
//-----------------------------------------------------------------------------
// Reference frequency 13.0MHz 19.2MHz 12.0MHz 26.0MHz
// ----------------------------------------------------------------------------
// PLLU_ENABLE_DLY_COUNT 02 (02h) 03 (03h) 02 (02h) 04 (04h)
// PLLU_STABLE_COUNT 51 (33h) 75 (4Bh) 47 (2Fh) 102 (66h)
// PLL_ACTIVE_DLY_COUNT 05 (05h) 06 (06h) 04 (04h) 09 (09h)
// XTAL_FREQ_COUNT 127 (7Fh) 187 (BBh) 118 (76h) 254 (FEh)
///////////////////////////////////////////////////////////////////////////////
static const UsbPllDelayParams s_UsbPllDelayParams[NvRmClocksOscFreq_Num] =
{
//ENABLE_DLY, STABLE_CNT, ACTIVE_DLY, XTAL_FREQ_CNT
{0x02, 0x33, 0x05, 0x7F}, // For NvRmClocksOscFreq_13_MHz,
{0x03, 0x4B, 0x06, 0xBB}, // For NvRmClocksOscFreq_19_2_MHz
{0x02, 0x2F, 0x04, 0x76}, // For NvRmClocksOscFreq_12_MHz
{0x04, 0x66, 0x09, 0xFE} // For NvRmClocksOscFreq_26_MHz
};
///////////////////////////////////////////////////////////////////////////////
// USB Debounce values IdDig, Avalid, Bvalid, VbusValid, VbusWakeUp, and SessEnd.
// Each of these signals have their own debouncer and for each of those one out
// of 2 debouncing times can be chosen (BIAS_DEBOUNCE_A or BIAS_DEBOUNCE_B.)
//
// The values of DEBOUNCE_A and DEBOUNCE_B are calculated as follows:
// 0xffff -> No debouncing at all
// ms = *1000 / (1/19.2MHz) / 4
// So to program a 1 ms debounce for BIAS_DEBOUNCE_A, we have:
// BIAS_DEBOUNCE_A[15:0] = 1000 * 19.2 / 4 = 4800 = 0x12c0
// We need to use only DebounceA, We dont need the DebounceB
// values, so we can keep those to default.
///////////////////////////////////////////////////////////////////////////////
static const NvU32 s_UsbBiasDebounceATime[NvRmClocksOscFreq_Num] =
{
/* Ten milli second delay for BIAS_DEBOUNCE_A */
0x7EF4, // For NvRmClocksOscFreq_13_MHz,
0xBB80, // For NvRmClocksOscFreq_19_2_MHz
0x7530, // For NvRmClocksOscFreq_12_MHz
0xFDE8 // For NvRmClocksOscFreq_26_MHz
};
///////////////////////////////////////////////////////////////////////////////
// The following arapb_misc_utmip.spec fields need to be programmed to ensure
// correct operation of the UTMIP block:
// Production settings :
// 'HS_SYNC_START_DLY' : 9,
// 'IDLE_WAIT' : 17,
// 'ELASTIC_LIMIT' : 16,
// All other fields can use the default reset values.
// Setting the fields above, together with default values of the other fields,
// results in programming the registers below as follows:
// UTMIP_HSRX_CFG0 = 0x9168c000
// UTMIP_HSRX_CFG1 = 0x13
///////////////////////////////////////////////////////////////////////////////
//UTMIP Idle Wait Delay
static const NvU8 s_UtmipIdleWaitDelay = 17;
//UTMIP Elastic limit
static const NvU8 s_UtmipElasticLimit = 16;
//UTMIP High Speed Sync Start Delay
static const NvU8 s_UtmipHsSyncStartDelay = 9;
//UTMIP Tranciver setup Value, this value must be read from the fuses
static NvU32 s_XcvrSetupValue = 0;
static NvError
Ap16UsbPhyUtmiConfigure(
NvDdkUsbPhy *pUsbPhy)
{
NvU32 RegVal = 0;
NvRmFreqKHz OscFreqKz = 0;
NvU32 FreqIndex;
// Get the Oscillator Frequency
OscFreqKz = NvRmPowerGetPrimaryFrequency(pUsbPhy->hRmDevice);
// Get the Oscillator Frequency Index
for (FreqIndex = 0; FreqIndex < NvRmClocksOscFreq_Num; FreqIndex++)
{
if (OscFreqKz == s_RmOscFrequecy[FreqIndex])
{
// Bail Out if frequecy matches with the supported frequency
break;
}
}
// If Index is equal to the maximum supported frequency count
// There is a mismatch of the frequecy, so returning since the
// frequency is not supported.
if (FreqIndex >= NvRmClocksOscFreq_Num)
{
return NvError_NotSupported;
}
RegVal = USB_MISC_REGR(pUsbPhy, APB_MISC_UTMIP_TX_CFG0_0);
RegVal = NV_FLD_SET_DRF_NUM(
APB_MISC, UTMIP_TX_CFG0, UTMIP_FS_PREAMBLE_J, 0x1, RegVal);
USB_MISC_REGW(pUsbPhy, APB_MISC_UTMIP_TX_CFG0_0, RegVal);
// Configure the UTMIP_IDLE_WAIT and UTMIP_ELASTIC_LIMIT
// Setting these fields, together with default values of the other
// fields, results in programming the registers below as follows:
// UTMIP_HSRX_CFG0 = 0x9168c000
// UTMIP_HSRX_CFG1 = 0x13
RegVal = USB_MISC_REGR(pUsbPhy, APB_MISC_UTMIP_HSRX_CFG0_0);
RegVal = NV_FLD_SET_DRF_NUM(APB_MISC, UTMIP_HSRX_CFG0,
UTMIP_IDLE_WAIT, s_UtmipIdleWaitDelay, RegVal);
RegVal = NV_FLD_SET_DRF_NUM(APB_MISC, UTMIP_HSRX_CFG0,
UTMIP_ELASTIC_LIMIT, s_UtmipElasticLimit, RegVal);
USB_MISC_REGW(pUsbPhy, APB_MISC_UTMIP_HSRX_CFG0_0, RegVal);
// Configure the UTMIP_HS_SYNC_START_DLY
RegVal = USB_MISC_REGR(pUsbPhy, APB_MISC_UTMIP_HSRX_CFG1_0);
RegVal = NV_FLD_SET_DRF_NUM(APB_MISC, UTMIP_HSRX_CFG1,
UTMIP_HS_SYNC_START_DLY, s_UtmipHsSyncStartDelay, RegVal);
USB_MISC_REGW(pUsbPhy, APB_MISC_UTMIP_HSRX_CFG1_0, RegVal);
// Program 1ms Debounce time for VBUS to become valid.
RegVal = USB_MISC_REGR(pUsbPhy, APB_MISC_UTMIP_DEBOUNCE_CFG0_0);
RegVal = NV_FLD_SET_DRF_NUM(APB_MISC, UTMIP_DEBOUNCE_CFG0,
UTMIP_BIAS_DEBOUNCE_A, s_UsbBiasDebounceATime[FreqIndex], RegVal);
USB_MISC_REGW(pUsbPhy, APB_MISC_UTMIP_DEBOUNCE_CFG0_0, RegVal);
// PLL Delay CONFIGURATION settings
// The following parameters control the bring up of the plls:
RegVal = USB_MISC_REGR(pUsbPhy, APB_MISC_UTMIP_MISC_CFG0_0);
RegVal = NV_FLD_SET_DRF_NUM(APB_MISC, UTMIP_MISC_CFG0,
UTMIP_SUSPEND_EXIT_ON_EDGE, 0, RegVal);
USB_MISC_REGW(pUsbPhy, APB_MISC_UTMIP_MISC_CFG0_0, RegVal);
RegVal = USB_MISC_REGR(pUsbPhy, APB_MISC_UTMIP_MISC_CFG1_0);
RegVal = NV_FLD_SET_DRF_NUM(APB_MISC, UTMIP_MISC_CFG1, UTMIP_PLLU_STABLE_COUNT,
s_UsbPllDelayParams[FreqIndex].StableCount, RegVal);
RegVal = NV_FLD_SET_DRF_NUM(APB_MISC, UTMIP_MISC_CFG1, UTMIP_PLL_ACTIVE_DLY_COUNT,
s_UsbPllDelayParams[FreqIndex].ActiveDelayCount, RegVal);
USB_MISC_REGW(pUsbPhy, APB_MISC_UTMIP_MISC_CFG1_0, RegVal);
// Set PLL enable delay count and Crystal frequency count
RegVal = USB_MISC_REGR(pUsbPhy, APB_MISC_UTMIP_PLL_CFG1_0);
RegVal = NV_FLD_SET_DRF_NUM(APB_MISC, UTMIP_PLL_CFG1, UTMIP_PLLU_ENABLE_DLY_COUNT,
s_UsbPllDelayParams[FreqIndex].EnableDelayCount, RegVal);
RegVal = NV_FLD_SET_DRF_NUM(APB_MISC, UTMIP_PLL_CFG1, UTMIP_XTAL_FREQ_COUNT,
s_UsbPllDelayParams[FreqIndex].XtalFreqCount, RegVal);
USB_MISC_REGW(pUsbPhy, APB_MISC_UTMIP_PLL_CFG1_0, RegVal);
return NvSuccess;
}
static void
Ap16UsbPhyUtmiPowerControl(
NvDdkUsbPhy *pUsbPhy,
NvBool Enable)
{
NvU32 RegVal = 0;
if (Enable)
{
// USB Power Up sequence
// Power Up OTG and Bias circuitry
RegVal = USB_MISC_REGR(pUsbPhy, APB_MISC_UTMIP_BIAS_CFG0_0);
RegVal = NV_FLD_SET_DRF_NUM(
APB_MISC, UTMIP_BIAS_CFG0, UTMIP_OTGPD, 0, RegVal);
RegVal = NV_FLD_SET_DRF_NUM(
APB_MISC, UTMIP_BIAS_CFG0, UTMIP_BIASPD, 0, RegVal);
USB_MISC_REGW(pUsbPhy, APB_MISC_UTMIP_BIAS_CFG0_0, RegVal);
// Turn on power in the tranciver
RegVal = USB_MISC_REGR(pUsbPhy, APB_MISC_UTMIP_XCVR_CFG0_0);
RegVal = NV_FLD_SET_DRF_NUM(APB_MISC,
UTMIP_XCVR_CFG0, UTMIP_FORCE_PDZI_POWERDOWN, 0, RegVal);
RegVal = NV_FLD_SET_DRF_NUM(APB_MISC,
UTMIP_XCVR_CFG0, UTMIP_FORCE_PD2_POWERDOWN, 0, RegVal);
RegVal = NV_FLD_SET_DRF_NUM(APB_MISC,
UTMIP_XCVR_CFG0, UTMIP_FORCE_PD_POWERDOWN, 0, RegVal);
RegVal = NV_FLD_SET_DRF_NUM(APB_MISC,
UTMIP_XCVR_CFG0, UTMIP_XCVR_SETUP, s_XcvrSetupValue, RegVal);
USB_MISC_REGW(pUsbPhy, APB_MISC_UTMIP_XCVR_CFG0_0, RegVal);
// Enable Batery charge enabling bit, set to '0' for enable
RegVal = USB_MISC_REGR(pUsbPhy, APB_MISC_UTMIP_BAT_CHRG_CFG0_0);
RegVal = NV_FLD_SET_DRF_NUM(
APB_MISC, UTMIP_BAT_CHRG_CFG0, UTMIP_PD_CHRG, 0, RegVal);
USB_MISC_REGW(pUsbPhy, APB_MISC_UTMIP_BAT_CHRG_CFG0_0, RegVal);
}
else
{
// USB Power down sequence
// Power down OTG and Bias circuitry
RegVal = USB_MISC_REGR(pUsbPhy, APB_MISC_UTMIP_BIAS_CFG0_0);
// Check if Internal Phy is going to wake up the usb
// controller upon cable insertion.
if (!pUsbPhy->pProperty->UseInternalPhyWakeup)
{
/// If not internal Phy then Use PMU interrupt for VBUS detection.
/// Disable the OTG bias circuitry.
RegVal = NV_FLD_SET_DRF_NUM(
APB_MISC, UTMIP_BIAS_CFG0, UTMIP_OTGPD, 1, RegVal);
}
RegVal = NV_FLD_SET_DRF_NUM(
APB_MISC, UTMIP_BIAS_CFG0, UTMIP_BIASPD, 1, RegVal);
USB_MISC_REGW(pUsbPhy, APB_MISC_UTMIP_BIAS_CFG0_0, RegVal);
// Disable Batery charge enabling bit set to '1' for disable
RegVal = USB_MISC_REGR(pUsbPhy, APB_MISC_UTMIP_BAT_CHRG_CFG0_0);
RegVal = NV_FLD_SET_DRF_NUM(
APB_MISC, UTMIP_BAT_CHRG_CFG0, UTMIP_PD_CHRG, 1, RegVal);
USB_MISC_REGW(pUsbPhy, APB_MISC_UTMIP_BAT_CHRG_CFG0_0, RegVal);
// Turn off power in the tranciver
RegVal = USB_MISC_REGR(pUsbPhy, APB_MISC_UTMIP_XCVR_CFG0_0);
RegVal = NV_FLD_SET_DRF_NUM(APB_MISC,
UTMIP_XCVR_CFG0, UTMIP_FORCE_PDZI_POWERDOWN, 1, RegVal);
RegVal = NV_FLD_SET_DRF_NUM(APB_MISC,
UTMIP_XCVR_CFG0, UTMIP_FORCE_PD2_POWERDOWN, 1, RegVal);
RegVal = NV_FLD_SET_DRF_NUM(APB_MISC,
UTMIP_XCVR_CFG0, UTMIP_FORCE_PD_POWERDOWN, 1, RegVal);
USB_MISC_REGW(pUsbPhy, APB_MISC_UTMIP_XCVR_CFG0_0, RegVal);
}
}
static void
Ap16UsbPhyUlpiLinkModeConfigure(
NvDdkUsbPhy *pUsbPhy)
{
NvU32 RegVal = 0;
// Enable clock to the USB2 and Bring out of Reset
// Then Setup the Link Mode Trimmers.
// Bypass the Pin Mux on the ULPI outputs and set trimmer values for inputs
RegVal = USB_MISC_REGR(pUsbPhy, APB_MISC_UTMIP_SPARE_CFG0_0);
RegVal = RegVal & ( ~( (0x1 << 13) | (0xf << 4) | (0xf << 28) ) );
//bit 13 : data output pinmux bypass enable: set to 1
//bit 4 : data input trimmer load enable (toggle)
//bit [7:5] : data input trimmer value: set to 3
//bit 28 : data input trimmer2 load enable (toggle)
//bit [31:29] : data input trimmer2 value: set to 3
RegVal = RegVal | ( (0x1 << 13) | (0x0 << 5) | (0x0 << 4) |
(0x0 << 29) | (0x0 << 28) );
USB_MISC_REGW(pUsbPhy, APB_MISC_UTMIP_SPARE_CFG0_0, RegVal);
// wait 10 us
NvOsWaitUS(10);
// toggle bits 4 and 28 to latch the trimmer values
RegVal = RegVal | ( (0x1 << 4) | (0x1 << 28) );
USB_MISC_REGW(pUsbPhy, APB_MISC_UTMIP_SPARE_CFG0_0, RegVal);
// wait 10 us
NvOsWaitUS(10);
}
static void
Ap16UsbPhyUlpiNullModeConfigure(
NvDdkUsbPhy *pUsbPhy)
{
NvU32 RegVal = 0;
// Enable clock to the USB2 and Bring out of Reset then
// Clear the trimmers and Setup the ULPI NULL mode PINMUX
RegVal = USB_MISC_REGR(pUsbPhy, APB_MISC_UTMIP_SPARE_CFG0_0);
RegVal = RegVal & (0xf);
RegVal = RegVal | ( (0x0 << 29) | (0x0 << 28) | (0x0 << 27) | (0 << 22) |
(0x0 << 21) | (0x0 << 16) | (0x0 << 15) | (0x1 << 14) |
(0x1 << 13) | (0x0 << 12) | (0x1 << 11) | (0x1 << 10) |
(0x1 << 9) | (0x0 << 5) | (0x0 << 4) );
USB_MISC_REGW(pUsbPhy, APB_MISC_UTMIP_SPARE_CFG0_0, RegVal);
// wait 10 us
NvOsWaitUS(10);
// Enable null phy (bit 0)
// ULPIS2S_SPARE[3] = ULPIS2S_INT_CLOCK
// ULPIS2S_SPARE[0] = VBUS active
RegVal = USB_IF_REG_RD(ULPIS2S_CTRL);
RegVal = NV_FLD_SET_DRF_DEF(
USB2_IF_USB, ULPIS2S_CTRL, ULPIS2S_ENA, ENABLE, RegVal);
RegVal = NV_FLD_SET_DRF_NUM(
USB2_IF_USB, ULPIS2S_CTRL, ULPIS2S_SPARE, 0x9, RegVal);
USB_IF_REG_WR(ULPIS2S_CTRL, RegVal);
// wait 10 us
NvOsWaitUS(10);
// Set ULPI_CLK_ENA (ULPIS2S_SPARE[2]) to 1 to enable ULPI null clocks
// ULPIS2S_SPARE[3] = ULPIS2S_INT_CLOCK
// ULPIS2S_SPARE[2] = 1
// ULPIS2S_SPARE[0] = VBUS active
RegVal = USB_IF_REG_RD(ULPIS2S_CTRL);
RegVal = NV_FLD_SET_DRF_NUM(
USB2_IF_USB, ULPIS2S_CTRL, ULPIS2S_SPARE, 0xD, RegVal);
USB_IF_REG_WR(ULPIS2S_CTRL, RegVal);
// wait 10 us
NvOsWaitUS(10);
// Set trimmers required for the NULL ULPI
// Configure 60M clock for USB2 - ULPI controller
// Set up to use PLLU at 60 MHz and keep USB PHY PLL in reset
// bit 27 : bypass 60 MHz Div5 for PLLU - set to 1
// bit 9 : nullphy_pll_source - use USB_PHY_PLL output (set to 0) :
// Workaround: set to 1 to use PLLU Output at 12 MHz
RegVal = USB_MISC_REGR(pUsbPhy, APB_MISC_UTMIP_SPARE_CFG0_0);
RegVal &= (~( 0x1 << 27) );
RegVal |= ((0x1 << 9));
USB_MISC_REGW(pUsbPhy, APB_MISC_UTMIP_SPARE_CFG0_0,
RegVal);
// Set the trimmers
// bit 4 : data input trimmer load enable (toggle)
// bit [7:5] : data input trimmer value - set to 3
// bit 28 : data input trimmer2 load enable - (toggle)
// bit [31:29] : data input trimmer2 value - set to 3
RegVal = USB_MISC_REGR(pUsbPhy, APB_MISC_UTMIP_SPARE_CFG0_0);
RegVal = RegVal | ( (0x7 << 29) | (0x0 << 28) | (0x7 << 5) | (0x0 << 4) );
USB_MISC_REGW(pUsbPhy, APB_MISC_UTMIP_SPARE_CFG0_0, RegVal);
// wait 10 us
NvOsWaitUS(10);
// toggle bits 4 and 28 to latch the trimmer values
RegVal = RegVal | ( (0x1 << 4) | (0x1 << 28) );
USB_MISC_REGW(pUsbPhy, APB_MISC_UTMIP_SPARE_CFG0_0, RegVal);
// wait 10 us
NvOsWaitUS(10);
// Set ULPI_CLK_PADOUT_ENA (ULPIS2S_SPARE[1]) to 1 to enable ULPI
// null clock going out to ulpi clk pad (gp3_pv[0])
RegVal = USB_IF_REG_RD(ULPIS2S_CTRL);
RegVal = NV_FLD_SET_DRF_NUM(
USB2_IF_USB, ULPIS2S_CTRL, ULPIS2S_SPARE, 0xF, RegVal);
USB_IF_REG_WR(ULPIS2S_CTRL, RegVal);
}
static void
Ap16UsbPhyReadXcvrSetupValueFromFuses(
NvDdkUsbPhy *pUsbPhy)
{
NvU32 RegVal = 0;
#if NV_USE_FUSE_CLOCK_ENABLE
// Enable fuse clock
NvRmPowerModuleClockControl(pUsbPhy->hRmDevice, NvRmModuleID_Fuse, 0, NV_TRUE);
#endif
// Enable fuse values to be visible before reading the fuses.
RegVal = NV_REGR(pUsbPhy->hRmDevice, NvRmPrivModuleID_ClockAndReset, 0,
CLK_RST_CONTROLLER_MISC_CLK_ENB_0);
RegVal = NV_FLD_SET_DRF_NUM( CLK_RST_CONTROLLER, MISC_CLK_ENB,
CFG_ALL_VISIBLE, 1, RegVal );
NV_REGW( pUsbPhy->hRmDevice, NvRmPrivModuleID_ClockAndReset, 0,
CLK_RST_CONTROLLER_MISC_CLK_ENB_0, RegVal );
// Read the spare register fuses and redundancy fuses for setting up USB
// UTMIP_XCVR_SETUP value for proper EYE diagram.
RegVal = NV_REGR( pUsbPhy->hRmDevice, NvRmModuleID_Fuse, 0, FUSE_FUSEDATA21_0);
s_XcvrSetupValue = (NV_DRF_VAL(FUSE, FUSEDATA21,
FUSEDATA_SPARE_BIT_10__PRI_ALIAS_0, RegVal) |
NV_DRF_VAL(FUSE, FUSEDATA21,
FUSEDATA_SPARE_BIT_13__PRI_ALIAS_0, RegVal)) << 0;
s_XcvrSetupValue |= (NV_DRF_VAL(FUSE, FUSEDATA21,
FUSEDATA_SPARE_BIT_11__PRI_ALIAS_0, RegVal) |
NV_DRF_VAL(FUSE, FUSEDATA21,
FUSEDATA_SPARE_BIT_14__PRI_ALIAS_0, RegVal)) << 1;
s_XcvrSetupValue |= (NV_DRF_VAL(FUSE, FUSEDATA21,
FUSEDATA_SPARE_BIT_12__PRI_ALIAS_0, RegVal) |
NV_DRF_VAL(FUSE, FUSEDATA21,
FUSEDATA_SPARE_BIT_15__PRI_ALIAS_0, RegVal)) << 2;
// Only UTMIP_XCVR_SETUP[3-1] need to be programmed with the fuse vlaue
// UTMIP_XCVR_SETUP[0] must be equal to 0
s_XcvrSetupValue = s_XcvrSetupValue << 1;
// Disable fuse values visibility, we already read the data
RegVal = NV_REGR( pUsbPhy->hRmDevice, NvRmPrivModuleID_ClockAndReset, 0,
CLK_RST_CONTROLLER_MISC_CLK_ENB_0 );
RegVal = NV_FLD_SET_DRF_NUM( CLK_RST_CONTROLLER, MISC_CLK_ENB,
CFG_ALL_VISIBLE, 0, RegVal );
NV_REGW( pUsbPhy->hRmDevice, NvRmPrivModuleID_ClockAndReset, 0,
CLK_RST_CONTROLLER_MISC_CLK_ENB_0, RegVal );
#if NV_USE_FUSE_CLOCK_ENABLE
// Disable fuse clock
NvRmPowerModuleClockControl(pUsbPhy->hRmDevice, NvRmModuleID_Fuse, 0, NV_FALSE);
#endif
}
static void
Ap16UsbPhyControlClockAndReset(
NvDdkUsbPhy *pUsbPhy,
NvBool EnableClock)
{
NvBool HoldReset = EnableClock ? NV_FALSE : NV_TRUE;
NvU32 RegVal = 0;
NvU32 TimeOut = 1000;
NvU32 PhyClkValid = 0;
if(!EnableClock && ( pUsbPhy->pProperty->UsbInterfaceType == NvOdmUsbInterfaceType_UlpiExternalPhy))
{
// before disabling clock.. put the phy to low power mode..
// enter low power suspend mode
RegVal = NV_REGR(pUsbPhy->hRmDevice, NvRmModuleID_Usb2Otg, 1,
USB2_CONTROLLER_1_USB2D_PORTSC1_0);
RegVal = NV_FLD_SET_DRF_DEF(USB2_CONTROLLER_1, USB2D_PORTSC1, PHCD,
ENABLE, RegVal);
NV_REGW(pUsbPhy->hRmDevice, NvRmModuleID_Usb2Otg, 1,
USB2_CONTROLLER_1_USB2D_PORTSC1_0, RegVal);
// check for the phy in suspend..
do
{
//Wait for the phy clock to stop or invalid
RegVal = NV_REGR(pUsbPhy->hRmDevice, NvRmModuleID_Usb2Otg, 1 ,
USB2_IF_USB_SUSP_CTRL_0);
PhyClkValid = NV_DRF_VAL(USB2_IF, USB_SUSP_CTRL, USB_PHY_CLK_VALID,
RegVal);
if (!TimeOut)
{
break;
}
NvOsWaitUS(1);
TimeOut--;
} while (PhyClkValid);
}
// Enable/Disable Clock to the controller
if (pUsbPhy->Caps.CommonClockAndReset)
{
RegVal = USB_MISC_REGR(pUsbPhy, APB_MISC_PP_MISC_USB_CLK_RST_CTL_0);
if (pUsbPhy->Instance == 1)
{
RegVal = NV_FLD_SET_DRF_DEF(APB_MISC_PP, MISC_USB_CLK_RST_CTL,
MISC_USB2_RST, ENABLE, RegVal);
RegVal = NV_FLD_SET_DRF_NUM(APB_MISC_PP, MISC_USB_CLK_RST_CTL,
MISC_USB2_CE, EnableClock, RegVal);
}
else
{
RegVal = NV_FLD_SET_DRF_DEF(APB_MISC_PP, MISC_USB_CLK_RST_CTL,
MISC_USB_RST, ENABLE, RegVal);
RegVal = NV_FLD_SET_DRF_NUM(APB_MISC_PP, MISC_USB_CLK_RST_CTL,
MISC_USB_CE, EnableClock, RegVal);
}
USB_MISC_REGW(pUsbPhy, APB_MISC_PP_MISC_USB_CLK_RST_CTL_0, RegVal);
}
// Hold/ Release the RESET to the controller
if (pUsbPhy->Caps.CommonClockAndReset)
{
RegVal = USB_MISC_REGR(pUsbPhy, APB_MISC_PP_MISC_USB_CLK_RST_CTL_0);
if (pUsbPhy->Instance == 1)
{
RegVal = NV_FLD_SET_DRF_NUM(APB_MISC_PP, MISC_USB_CLK_RST_CTL,
MISC_USB2_RST, HoldReset, RegVal);
}
else
{
RegVal = NV_FLD_SET_DRF_NUM(APB_MISC_PP, MISC_USB_CLK_RST_CTL,
MISC_USB_RST, HoldReset, RegVal);
}
USB_MISC_REGW(pUsbPhy, APB_MISC_PP_MISC_USB_CLK_RST_CTL_0, RegVal);
}
else
{
NvRmModuleResetWithHold(pUsbPhy->hRmDevice,
NVRM_MODULE_ID(NvRmModuleID_Usb2Otg, pUsbPhy->Instance), HoldReset);
}
if(EnableClock &&( pUsbPhy->pProperty->UsbInterfaceType ==
NvOdmUsbInterfaceType_UlpiExternalPhy))
{
// Wake-up ULPI PHY generate a postive pulse
//set
RegVal = NV_REGR(pUsbPhy->hRmDevice, NvRmModuleID_Usb2Otg, 1,
USB2_IF_USB_SUSP_CTRL_0);
RegVal = NV_FLD_SET_DRF_DEF(USB2_IF, USB_SUSP_CTRL, USB_SUSP_CLR, SET,
RegVal);
NV_REGW(pUsbPhy->hRmDevice, NvRmModuleID_Usb2Otg, 1,
USB2_IF_USB_SUSP_CTRL_0, RegVal);
// wait 10 us
NvOsWaitUS(100);
// clear
RegVal = NV_REGR(pUsbPhy->hRmDevice, NvRmModuleID_Usb2Otg, 1,
USB2_IF_USB_SUSP_CTRL_0);
RegVal = NV_FLD_SET_DRF_DEF(USB2_IF, USB_SUSP_CTRL,
USB_SUSP_CLR, UNSET, RegVal);
NV_REGW(pUsbPhy->hRmDevice, NvRmModuleID_Usb2Otg, 1,
USB2_IF_USB_SUSP_CTRL_0, RegVal);
}
}
static NvError
Ap16UsbPhyIoctlVbusInterrupt(
NvDdkUsbPhy *pUsbPhy,
const void *pInputArgs)
{
NvDdkUsbPhyIoctl_VBusInterruptInputArgs *pVbusIntr = NULL;
NvU32 RegVal = 0;
if (!pInputArgs)
return NvError_BadParameter;
pVbusIntr = (NvDdkUsbPhyIoctl_VBusInterruptInputArgs *)pInputArgs;
if (pUsbPhy->pProperty->UsbInterfaceType == NvOdmUsbInterfaceType_Utmi)
{
RegVal = USB_MISC_REGR(pUsbPhy, APB_MISC_PP_USB_PHY_VBUS_SENSORS_0);
if (pVbusIntr->EnableVBusInterrupt)
{
RegVal = NV_FLD_SET_DRF_DEF(APB_MISC_PP, USB_PHY_VBUS_SENSORS,
A_SESS_VLD_INT_EN, ENABLE, RegVal);
}
else
{
RegVal = NV_FLD_SET_DRF_DEF(APB_MISC_PP, USB_PHY_VBUS_SENSORS,
A_SESS_VLD_INT_EN, DISABLE, RegVal);
RegVal = NV_FLD_SET_DRF_DEF(APB_MISC_PP, USB_PHY_VBUS_SENSORS,
A_SESS_VLD_CHG_DET, SET, RegVal);
}
USB_MISC_REGW(pUsbPhy, APB_MISC_PP_USB_PHY_VBUS_SENSORS_0, RegVal);
}
else
{
//TODO:ENable the VBUS interrupt for the ULPI
}
return NvSuccess;
}
static NvError
Ap16UsbPhyIoctlVBusStatus(
NvDdkUsbPhy *pUsbPhy,
void *pOutputArgs)
{
NvDdkUsbPhyIoctl_VBusStatusOutputArgs *pVBusStatus = NULL;
NvU32 RegVal = 0;
if (!pOutputArgs)
return NvError_BadParameter;
pVBusStatus = (NvDdkUsbPhyIoctl_VBusStatusOutputArgs *)pOutputArgs;
if (pUsbPhy->pProperty->UsbInterfaceType == NvOdmUsbInterfaceType_Utmi)
{
RegVal = USB_MISC_REGR(pUsbPhy, APB_MISC_PP_USB_PHY_VBUS_SENSORS_0);
if (NV_DRF_VAL(APB_MISC, PP_USB_PHY_VBUS_SENSORS, A_SESS_VLD_STS, RegVal))
{
pVBusStatus->VBusDetected = NV_TRUE;
}
else
{
pVBusStatus->VBusDetected = NV_FALSE;
}
}
else
{
pVBusStatus->VBusDetected = NV_TRUE;
}
return NvSuccess;
}
static NvError
Ap16UsbPhyIoctlIdPinInterrupt(
NvDdkUsbPhy *pUsbPhy,
const void *pInputArgs)
{
NvDdkUsbPhyIoctl_IdPinInterruptInputArgs *pIdPinIntr = NULL;
NvU32 RegVal = 0;
if (!pInputArgs)
return NvError_BadParameter;
pIdPinIntr = (NvDdkUsbPhyIoctl_IdPinInterruptInputArgs *)pInputArgs;
if (pUsbPhy->pProperty->UsbInterfaceType == NvOdmUsbInterfaceType_Utmi)
{
RegVal = USB_MISC_REGR(pUsbPhy, APB_MISC_PP_USB_PHY_VBUS_WAKEUP_ID_0);
if (pIdPinIntr->EnableIdPinInterrupt)
{
RegVal = NV_FLD_SET_DRF_DEF(APB_MISC_PP, USB_PHY_VBUS_WAKEUP_ID,
ID_INT_EN, ENABLE, RegVal);
}
else
{
RegVal = NV_FLD_SET_DRF_DEF(APB_MISC_PP, USB_PHY_VBUS_WAKEUP_ID,
ID_INT_EN, DISABLE, RegVal);
RegVal = NV_FLD_SET_DRF_DEF(APB_MISC_PP, USB_PHY_VBUS_WAKEUP_ID,
ID_CHG_DET, SET, RegVal);
}
USB_MISC_REGW(pUsbPhy, APB_MISC_PP_USB_PHY_VBUS_WAKEUP_ID_0, RegVal);
}
else
{
//TODO:ENable the ID pin interrupt for the ULPI
}
return NvSuccess;
}
static NvError
Ap16UsbPhyIoctlIdPinStatus(
NvDdkUsbPhy *pUsbPhy,
void *pOutputArgs)
{
NvDdkUsbPhyIoctl_IdPinStatusOutputArgs *pIdPinStatus = NULL;
NvU32 RegVal = 0;
if (!pOutputArgs)
return NvError_BadParameter;
pIdPinStatus = (NvDdkUsbPhyIoctl_IdPinStatusOutputArgs *)pOutputArgs;
RegVal = USB_MISC_REGR(pUsbPhy, APB_MISC_PP_USB_PHY_VBUS_WAKEUP_ID_0);
if (!NV_DRF_VAL(APB_MISC_PP, USB_PHY_VBUS_WAKEUP_ID, ID_STS, RegVal))
{
pIdPinStatus->IdPinSetToLow = NV_TRUE;
}
else
{
pIdPinStatus->IdPinSetToLow = NV_FALSE;
}
return NvSuccess;
}
static NvError
Ap16UsbPhyIoctlDedicatedChargerDetection(
NvDdkUsbPhy *pUsbPhy,
const void *pInputArgs)
{
// These values (in milli second) are taken from the battery charging spec.
#define TDP_SRC_ON_MS 100
#define TDPSRC_CON_MS 40
NvDdkUsbPhyIoctl_DedicatedChargerDetectionInputArgs *pChargerDetection = NULL;
NvU32 RegVal = 0;
if (!pInputArgs)
return NvError_BadParameter;
pChargerDetection = (NvDdkUsbPhyIoctl_DedicatedChargerDetectionInputArgs *)pInputArgs;
if (pUsbPhy->pProperty->UsbInterfaceType != NvOdmUsbInterfaceType_Utmi)
{
// Charger detection is not there for ULPI
return NvSuccess;
}
if (pChargerDetection->EnableChargerDetection)
{
// Enable charger detection logic
RegVal = USB_MISC_REGR(pUsbPhy, APB_MISC_UTMIP_BAT_CHRG_CFG0_0);
RegVal = NV_FLD_SET_DRF_NUM(APB_MISC, UTMIP_BAT_CHRG_CFG0,
UTMIP_OP_SRC_EN, 1, RegVal);
RegVal = NV_FLD_SET_DRF_NUM(APB_MISC, UTMIP_BAT_CHRG_CFG0,
UTMIP_ON_SINK_EN, 1, RegVal);
USB_MISC_REGW(pUsbPhy, APB_MISC_UTMIP_BAT_CHRG_CFG0_0, RegVal);
// Source should be on for 100 ms as per USB charging spec
NvOsSleepMS(TDP_SRC_ON_MS);
RegVal = USB_MISC_REGR(pUsbPhy, APB_MISC_PP_USB_PHY_VBUS_WAKEUP_ID_0);
if (pChargerDetection->EnableChargerInterrupt)
{
RegVal = NV_FLD_SET_DRF_DEF(APB_MISC, PP_USB_PHY_VBUS_WAKEUP_ID,
VDAT_DET_INT_EN, ENABLE, RegVal);
}
else
{
// If charger is not connected disable the interrupt
RegVal = NV_FLD_SET_DRF_DEF(APB_MISC, PP_USB_PHY_VBUS_WAKEUP_ID,
VDAT_DET_INT_EN, DISABLE, RegVal);
RegVal = NV_FLD_SET_DRF_DEF(APB_MISC, PP_USB_PHY_VBUS_WAKEUP_ID,
VDAT_DET_CHG_DET, SET, RegVal);
}
USB_MISC_REGW(pUsbPhy, APB_MISC_PP_USB_PHY_VBUS_WAKEUP_ID_0, RegVal);
}
else
{
// disable the interrupt
RegVal = USB_MISC_REGR(pUsbPhy, APB_MISC_PP_USB_PHY_VBUS_WAKEUP_ID_0);
RegVal = NV_FLD_SET_DRF_DEF(APB_MISC, PP_USB_PHY_VBUS_WAKEUP_ID,
VDAT_DET_INT_EN, DISABLE, RegVal);
RegVal = NV_FLD_SET_DRF_DEF(APB_MISC, PP_USB_PHY_VBUS_WAKEUP_ID,
VDAT_DET_CHG_DET, SET, RegVal);
USB_MISC_REGW(pUsbPhy, APB_MISC_PP_USB_PHY_VBUS_WAKEUP_ID_0, RegVal);
// Disable charger detection logic
RegVal = USB_MISC_REGR(pUsbPhy, APB_MISC_UTMIP_BAT_CHRG_CFG0_0);
RegVal = NV_FLD_SET_DRF_NUM(APB_MISC, UTMIP_BAT_CHRG_CFG0,
UTMIP_OP_SRC_EN, 0, RegVal);
RegVal = NV_FLD_SET_DRF_NUM(APB_MISC, UTMIP_BAT_CHRG_CFG0,
UTMIP_ON_SINK_EN, 0, RegVal);
USB_MISC_REGW(pUsbPhy, APB_MISC_UTMIP_BAT_CHRG_CFG0_0, RegVal);
// Delay of 40 ms before we pull the D+ as per battery charger spec.
NvOsSleepMS(TDPSRC_CON_MS);
}
return NvSuccess;
}
static NvError
Ap16UsbPhyIoctlDedicatedChargerStatus(
NvDdkUsbPhy *pUsbPhy,
void *pOutputArgs)
{
NvDdkUsbPhyIoctl_DedicatedChargerStatusOutputArgs *pChargerStatus = NULL;
NvU32 RegVal = 0;
if (!pOutputArgs)
return NvError_BadParameter;
pChargerStatus = (NvDdkUsbPhyIoctl_DedicatedChargerStatusOutputArgs *)pOutputArgs;
if (pUsbPhy->pProperty->UsbInterfaceType != NvOdmUsbInterfaceType_Utmi)
{
// Charger detection is not there for ULPI
// return Charger not available
pChargerStatus->ChargerDetected = NV_FALSE;
return NvSuccess;
}
RegVal = USB_MISC_REGR(pUsbPhy, APB_MISC_PP_USB_PHY_VBUS_WAKEUP_ID_0);
if (NV_DRF_VAL(APB_MISC, PP_USB_PHY_VBUS_WAKEUP_ID, VDAT_DET_STS, RegVal))
{
pChargerStatus->ChargerDetected = NV_TRUE;
}
else
{
pChargerStatus->ChargerDetected = NV_FALSE;
}
return NvSuccess;
}
static NvError
Ap16UsbPhyIoctl(
NvDdkUsbPhy *pUsbPhy,
NvDdkUsbPhyIoctlType IoctlType,
const void *pInputArgs,
void *pOutputArgs)
{
NvError ErrStatus = NvSuccess;
switch (IoctlType)
{
case NvDdkUsbPhyIoctlType_VBusStatus:
ErrStatus = Ap16UsbPhyIoctlVBusStatus(pUsbPhy, pOutputArgs);
break;
case NvDdkUsbPhyIoctlType_VBusInterrupt:
ErrStatus = Ap16UsbPhyIoctlVbusInterrupt(pUsbPhy, pInputArgs);
break;
case NvDdkUsbPhyIoctlType_IdPinStatus:
ErrStatus = Ap16UsbPhyIoctlIdPinStatus(pUsbPhy, pOutputArgs);
break;
case NvDdkUsbPhyIoctlType_IdPinInterrupt:
ErrStatus = Ap16UsbPhyIoctlIdPinInterrupt(pUsbPhy, pInputArgs);
break;
case NvDdkUsbPhyIoctlType_DedicatedChargerStatus:
ErrStatus = Ap16UsbPhyIoctlDedicatedChargerStatus(pUsbPhy, pOutputArgs);
break;
case NvDdkUsbPhyIoctlType_DedicatedChargerDetection:
ErrStatus = Ap16UsbPhyIoctlDedicatedChargerDetection(pUsbPhy, pInputArgs);
break;
default:
return NvError_NotSupported;
}
return ErrStatus;
}
static NvError
Ap16UsbPhyWaitForStableClock(
NvDdkUsbPhy *pUsbPhy)
{
NvU32 TimeOut = USB_PHY_HW_TIMEOUT_US;
NvU32 PhyClkValid = 0;
if (pUsbPhy->pProperty->UsbInterfaceType == NvOdmUsbInterfaceType_Utmi)
{
// Wait for the phy clock to become valid or hardware timeout
do {
PhyClkValid = USB_MISC_REGR(pUsbPhy, APB_MISC_PP_MISC_USB_OTG_0);
PhyClkValid = NV_DRF_VAL(APB_MISC_PP,
MISC_USB_OTG, PCLKVLD, PhyClkValid);
if (!TimeOut)
{
return NvError_Timeout;
}
NvOsWaitUS(1);
TimeOut--;
} while (PhyClkValid != APB_MISC_PP_MISC_USB_OTG_0_PCLKVLD_SET);
}
else
{
// Wait for the phy clock to become valid or hardware timeout
do {
PhyClkValid = USB_IF_REG_RD(SUSP_CTRL);
PhyClkValid = NV_DRF_VAL(USB2_IF_USB,
SUSP_CTRL, USB_PHY_CLK_VALID, PhyClkValid);
if (!TimeOut)
{
return NvError_Timeout;
}
NvOsWaitUS(1);
TimeOut--;
} while (PhyClkValid != USB2_IF_USB_SUSP_CTRL_0_USB_PHY_CLK_VALID_SET);
}
return NvSuccess;
}
static NvError
Ap16UsbPhyPowerUp(
NvDdkUsbPhy *pUsbPhy)
{
NvError ErrVal = NvSuccess;
switch (pUsbPhy->pProperty->UsbInterfaceType)
{
case NvOdmUsbInterfaceType_UlpiNullPhy:
Ap16UsbPhyControlClockAndReset(pUsbPhy, NV_TRUE);
Ap16UsbPhyUlpiNullModeConfigure(pUsbPhy);
break;
case NvOdmUsbInterfaceType_UlpiExternalPhy:
pUsbPhy->hOdmUlpi = NvOdmUsbUlpiOpen(pUsbPhy->Instance);
Ap16UsbPhyControlClockAndReset(pUsbPhy, NV_TRUE);
Ap16UsbPhyUlpiLinkModeConfigure(pUsbPhy);
break;
case NvOdmUsbInterfaceType_Utmi:
default:
ErrVal = Ap16UsbPhyUtmiConfigure(pUsbPhy);
if (ErrVal != NvSuccess)
return ErrVal;
Ap16UsbPhyUtmiPowerControl(pUsbPhy, NV_TRUE);
Ap16UsbPhyControlClockAndReset(pUsbPhy, NV_TRUE);
break;
}
ErrVal = Ap16UsbPhyWaitForStableClock(pUsbPhy);
return ErrVal;
}
static NvError
Ap16UsbPhyPowerDown(
NvDdkUsbPhy *pUsbPhy)
{
switch (pUsbPhy->pProperty->UsbInterfaceType)
{
case NvOdmUsbInterfaceType_UlpiExternalPhy:
if (pUsbPhy->hOdmUlpi)
{
NvOdmUsbUlpiClose(pUsbPhy->hOdmUlpi);
pUsbPhy->hOdmUlpi = NULL;
}
Ap16UsbPhyControlClockAndReset(pUsbPhy, NV_FALSE);
break;
case NvOdmUsbInterfaceType_UlpiNullPhy:
Ap16UsbPhyControlClockAndReset(pUsbPhy, NV_FALSE);
break;
case NvOdmUsbInterfaceType_Utmi:
default:
Ap16UsbPhyUtmiPowerControl(pUsbPhy, NV_FALSE);
Ap16UsbPhyControlClockAndReset(pUsbPhy, NV_FALSE);
break;
}
return NvSuccess;
}
static void
Ap16UsbPhyClose(
NvDdkUsbPhy *pUsbPhy)
{
// Power down the USB controller
NV_ASSERT_SUCCESS(Ap16UsbPhyPowerDown(pUsbPhy));
}
static void
Ap16PhySaveContext(
NvDdkUsbPhy *pUsbPhy)
{
// return
}
static void
Ap16PhyRestoreContext(
NvDdkUsbPhy *pUsbPhy)
{
// return
}
void
Ap16UsbPhyOpenHwInterface(
NvDdkUsbPhy *pUsbPhy)
{
pUsbPhy->PowerUp = Ap16UsbPhyPowerUp;
pUsbPhy->PowerDown = Ap16UsbPhyPowerDown;
pUsbPhy->Ioctl = Ap16UsbPhyIoctl;
pUsbPhy->WaitForStableClock = Ap16UsbPhyWaitForStableClock;
pUsbPhy->CloseHwInterface = Ap16UsbPhyClose;
pUsbPhy->SaveContext = Ap16PhySaveContext;
pUsbPhy->RestoreContext = Ap16PhyRestoreContext;
Ap16UsbPhyReadXcvrSetupValueFromFuses(pUsbPhy);
}