/* * 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 "ap20/arusb.h" #include "ap20/arapb_misc.h" #include "nvrm_hardware_access.h" #include "nvddk_usbphy_priv.h" #include "nvodm_query.h" /* Defines for USB register read and writes */ #define USB_REG_RD(reg)\ NV_READ32(pUsbPhy->UsbVirAdr + ((USB2_CONTROLLER_2_USB2D_##reg##_0)/4)) #define USB_REG_WR(reg, data)\ NV_WRITE32(pUsbPhy->UsbVirAdr + ((USB2_CONTROLLER_2_USB2D_##reg##_0)/4), (data)) // Read perticular field value from reg mentioned #define USB_DRF_VAL(reg, field, value) \ NV_DRF_VAL(USB2_CONTROLLER_2_USB2D, reg, field, value) #define USB_FLD_SET_DRF_DEF(reg, field, define, value) \ NV_FLD_SET_DRF_DEF(USB2_CONTROLLER_2_USB2D, reg, field, define, value) #define USB_REG_SET_DRF_DEF(reg, field, define) \ NV_FLD_SET_DRF_DEF(USB2_CONTROLLER_2_USB2D, reg, field, define, USB_REG_RD(reg)) #define USB_REG_UPDATE_DEF(reg, field, define) \ USB_REG_WR(reg, USB_REG_SET_DRF_DEF(reg, field, define)) #define USB_DRF_DEF(reg, field, define) \ NV_DRF_DEF(USB2_CONTROLLER_2_USB2D, reg, field, define) #define USB_DRF_VAL(reg, field, value) \ NV_DRF_VAL(USB2_CONTROLLER_2_USB2D, reg, field, value) #define USB_REG_READ_VAL(reg, field) \ USB_DRF_VAL(reg, field, USB_REG_RD(reg)) #define USB_REG_SET_DRF_NUM(reg, field, num, value) \ NV_FLD_SET_DRF_NUM(USB2_CONTROLLER_2_USB2D, reg, field, num, value); /* Defines for USB IF register read and writes */ #define USB1_IF_FLD_SET_DRF_DEF(reg, field, define, value) \ NV_FLD_SET_DRF_DEF(USB1_IF, reg, field, define, value) #define USB1_IF_REG_RD(reg)\ NV_READ32(pUsbPhy->UsbVirAdr + ((USB1_IF_##reg##_0)/4)) #define USB1_IF_REG_WR(reg, data)\ NV_WRITE32(pUsbPhy->UsbVirAdr + ((USB1_IF_##reg##_0)/4), (data)) #define USB1_IF_REG_SET_DRF_DEF(reg, field, define) \ NV_FLD_SET_DRF_DEF(USB1_IF, reg, field, define, USB1_IF_REG_RD(reg)) #define USB1_IF_REG_UPDATE_DEF(reg, field, define) \ USB1_IF_REG_WR(reg, USB1_IF_REG_SET_DRF_DEF(reg, field, define)) #define USB1_IF_DRF_VAL(reg, field, value) \ NV_DRF_VAL(USB1_IF, reg, field, value) #define USB1_IF_REG_READ_VAL(reg, field) \ USB1_IF_DRF_VAL(reg, field, USB1_IF_REG_RD(reg)) #define USB3_IF_FLD_SET_DRF_DEF(reg, field, define, value) \ NV_FLD_SET_DRF_DEF(USB3_IF_USB, reg, field, define, value) #define USB_IF_DRF_DEF(reg, field, define) \ NV_DRF_DEF(USB2_IF_USB, reg, field, define) #define USB_IF_DRF_NUM(reg, field, value) \ NV_DRF_NUM(USB2_IF_USB, reg, field, value) #define USB_IF_DRF_VAL(reg, field, value) \ NV_DRF_VAL(USB2_IF_USB, reg, field, value) #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)) #define USB_IF_REG_READ_VAL(reg, field) \ USB_IF_DRF_VAL(reg, field, USB_IF_REG_RD(reg)) #define USB_IF_REG_SET_DRF_NUM(reg, field, define) \ NV_FLD_SET_DRF_NUM(USB2_IF_USB, reg, field, define, USB_IF_REG_RD(reg)) #define USB_IF_REG_SET_DRF_DEF(reg, field, define) \ NV_FLD_SET_DRF_DEF(USB2_IF_USB, reg, field, define, USB_IF_REG_RD(reg)) #define USB_IF_REG_UPDATE_DEF(reg, field, define) \ USB_IF_REG_WR(reg, USB_IF_REG_SET_DRF_DEF(reg, field, define)) #define USB_IF_REG_UPDATE_NUM(reg, field, define) \ USB_IF_REG_WR(reg, USB_IF_REG_SET_DRF_NUM(reg, field, define)) // defines for ULPI register access #define ULPI_IF_REG_RD(reg)\ NV_READ32(pUsbPhy->UsbVirAdr + ((USB2_IF_ULPI_##reg##_0)/4)) #define ULPI_IF_REG_WR(reg, data)\ NV_WRITE32(pUsbPhy->UsbVirAdr + ((USB2_IF_ULPI_##reg##_0)/4), (data)) #define ULPI_IF_DRF_DEF(reg, field, define) \ NV_DRF_DEF(USB2_IF_ULPI, reg, field, define) #define ULPI_IF_DRF_NUM(reg, field, define) \ NV_DRF_NUM(USB2_IF_ULPI, reg, field, define) /* Defines for USB IF register read and writes */ #define USB_UTMIP_FLD_SET_DRF_DEF(reg, field, define, value) \ NV_FLD_SET_DRF_NUM(USB1_UTMIP, reg, field, define, value) #define USB_UTMIP_REG_RD(reg)\ NV_READ32(pUsbPhy->UsbVirAdr + ((USB1_UTMIP_##reg##_0)/4)) #define USB_UTMIP_REG_WR(reg, data)\ NV_WRITE32(pUsbPhy->UsbVirAdr + ((USB1_UTMIP_##reg##_0)/4), (data)) #define USB_UTMIP_REG_SET_DRF_NUM(reg, field, num) \ NV_FLD_SET_DRF_NUM(USB1_UTMIP, reg, field, num, USB_UTMIP_REG_RD(reg)) #define USB_UTMIP_REG_UPDATE_NUM(reg, field, num) \ USB_UTMIP_REG_WR(reg, USB_UTMIP_REG_SET_DRF_NUM(reg, field, num)) /* 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; static NvError Ap20UsbPhyUtmiConfigure( 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; } // Hold UTMIP in reset RegVal =USB_IF_REG_RD(SUSP_CTRL); RegVal = USB3_IF_FLD_SET_DRF_DEF(SUSP_CTRL, UTMIP_RESET, ENABLE, RegVal); USB_IF_REG_WR(SUSP_CTRL, RegVal); // Change the USB1 to non-legacy mode if (pUsbPhy->Instance == 0) { RegVal =USB1_IF_REG_RD(USB1_LEGACY_CTRL); RegVal = USB1_IF_FLD_SET_DRF_DEF( USB1_LEGACY_CTRL, USB1_NO_LEGACY_MODE, NEW, RegVal); USB1_IF_REG_WR(USB1_LEGACY_CTRL, RegVal); } USB_UTMIP_REG_UPDATE_NUM(TX_CFG0, UTMIP_FS_PREAMBLE_J, 0x1); // 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_UTMIP_REG_RD(HSRX_CFG0); RegVal = USB_UTMIP_FLD_SET_DRF_DEF(HSRX_CFG0, UTMIP_IDLE_WAIT,s_UtmipIdleWaitDelay, RegVal); RegVal = USB_UTMIP_FLD_SET_DRF_DEF(HSRX_CFG0, UTMIP_ELASTIC_LIMIT,s_UtmipElasticLimit, RegVal); USB_UTMIP_REG_WR(HSRX_CFG0, RegVal); // Configure the UTMIP_HS_SYNC_START_DLY USB_UTMIP_REG_UPDATE_NUM( HSRX_CFG1, UTMIP_HS_SYNC_START_DLY, s_UtmipHsSyncStartDelay); // Program 1ms Debounce time for VBUS to become valid. USB_UTMIP_REG_UPDATE_NUM( DEBOUNCE_CFG0, UTMIP_BIAS_DEBOUNCE_A, s_UsbBiasDebounceATime[FreqIndex]); // PLL Delay CONFIGURATION settings // The following parameters control the bring up of the plls: USB_UTMIP_REG_UPDATE_NUM(MISC_CFG0, UTMIP_SUSPEND_EXIT_ON_EDGE, 0); RegVal = USB_UTMIP_REG_RD(MISC_CFG1); RegVal = USB_UTMIP_FLD_SET_DRF_DEF(MISC_CFG1, UTMIP_PLLU_STABLE_COUNT, s_UsbPllDelayParams[FreqIndex].StableCount, RegVal); RegVal = USB_UTMIP_FLD_SET_DRF_DEF(MISC_CFG1, UTMIP_PLL_ACTIVE_DLY_COUNT, s_UsbPllDelayParams[FreqIndex].ActiveDelayCount, RegVal); USB_UTMIP_REG_WR(MISC_CFG1, RegVal); // Set PLL enable delay count and Crystal frequency count RegVal = USB_UTMIP_REG_RD(PLL_CFG1); RegVal = USB_UTMIP_FLD_SET_DRF_DEF(PLL_CFG1, UTMIP_PLLU_ENABLE_DLY_COUNT, s_UsbPllDelayParams[FreqIndex].EnableDelayCount, RegVal); RegVal = USB_UTMIP_FLD_SET_DRF_DEF(PLL_CFG1, UTMIP_XTAL_FREQ_COUNT, s_UsbPllDelayParams[FreqIndex].XtalFreqCount, RegVal); USB_UTMIP_REG_WR(PLL_CFG1, RegVal); return NvSuccess; } static void Ap20UsbPhyUtmiPowerControl( NvDdkUsbPhy *pUsbPhy, NvBool Enable) { NvU32 RegVal = 0; NvU32 XcvrSetupValue = 0x8; if (Enable) { // Disable the automatic phy enable on wakeup event USB1_IF_REG_UPDATE_DEF(USB_SUSP_CTRL, USB_WAKE_ON_DISCON_EN_DEV, DISABLE); USB1_IF_REG_UPDATE_DEF(USB_SUSP_CTRL, USB_WAKE_ON_CNNT_EN_DEV, DISABLE); // USB Power Up sequence if (!pUsbPhy->pUtmiPadConfig->PadOnRefCount) { /* UTMI PAD control logic is common to all UTMIP phys and they are controlled from USB1 controller */ // Power Up OTG and Bias config pad circuitry RegVal = NV_READ32(pUsbPhy->pUtmiPadConfig->pVirAdr + ((USB1_UTMIP_BIAS_CFG0_0)/4)); RegVal = USB_UTMIP_FLD_SET_DRF_DEF(BIAS_CFG0, UTMIP_OTGPD, 0, RegVal); RegVal = USB_UTMIP_FLD_SET_DRF_DEF(BIAS_CFG0, UTMIP_BIASPD, 0, RegVal); NV_WRITE32(pUsbPhy->pUtmiPadConfig->pVirAdr + ((USB1_UTMIP_BIAS_CFG0_0)/4), RegVal); } /* Increment the reference count to turn off the UTMIP pads */ pUsbPhy->pUtmiPadConfig->PadOnRefCount++; // Turn on power in the tranciver RegVal = USB_UTMIP_REG_RD(XCVR_CFG0); RegVal = USB_UTMIP_FLD_SET_DRF_DEF( XCVR_CFG0, UTMIP_FORCE_PDZI_POWERDOWN, 0, RegVal); RegVal = USB_UTMIP_FLD_SET_DRF_DEF( XCVR_CFG0, UTMIP_FORCE_PD2_POWERDOWN, 0, RegVal); RegVal = USB_UTMIP_FLD_SET_DRF_DEF( XCVR_CFG0, UTMIP_FORCE_PD_POWERDOWN, 0, RegVal); RegVal = USB_UTMIP_FLD_SET_DRF_DEF( XCVR_CFG0, UTMIP_XCVR_SETUP, XcvrSetupValue, RegVal); if (pUsbPhy->pProperty->UsbMode == NvOdmUsbModeType_Host) { // To slow rise/ fall times in low-speed eye diagrams in host mode RegVal = USB_UTMIP_FLD_SET_DRF_DEF( XCVR_CFG0, UTMIP_XCVR_LSFSLEW, 2, RegVal); RegVal = USB_UTMIP_FLD_SET_DRF_DEF( XCVR_CFG0, UTMIP_XCVR_LSRSLEW, 2, RegVal); } USB_UTMIP_REG_WR(XCVR_CFG0, RegVal); // Enables the PHY calibration values to read from the fuses. RegVal = USB_UTMIP_REG_RD(SPARE_CFG0); RegVal |= (1 << 3); USB_UTMIP_REG_WR(SPARE_CFG0, RegVal); RegVal = USB_UTMIP_REG_RD(XCVR_CFG1); RegVal = USB_UTMIP_FLD_SET_DRF_DEF( XCVR_CFG1, UTMIP_FORCE_PDDISC_POWERDOWN, 0, RegVal); RegVal = USB_UTMIP_FLD_SET_DRF_DEF( XCVR_CFG1, UTMIP_FORCE_PDCHRP_POWERDOWN, 0, RegVal); RegVal = USB_UTMIP_FLD_SET_DRF_DEF( XCVR_CFG1, UTMIP_FORCE_PDDR_POWERDOWN, 0, RegVal); USB_UTMIP_REG_WR(XCVR_CFG1, RegVal); // Enable Batery charge enabling bit, set to '0' for enable USB_UTMIP_REG_UPDATE_NUM(BAT_CHRG_CFG0, UTMIP_PD_CHRG, 0); if (pUsbPhy->Instance == 2) { // Enable UTMIP PHY for USB3 controller RegVal = USB_IF_REG_RD(SUSP_CTRL); RegVal = USB3_IF_FLD_SET_DRF_DEF( SUSP_CTRL, UTMIP_PHY_ENB, ENABLE, RegVal); USB_IF_REG_WR(SUSP_CTRL, RegVal); } // Release reset to UTMIP RegVal =USB_IF_REG_RD(SUSP_CTRL); RegVal = USB3_IF_FLD_SET_DRF_DEF(SUSP_CTRL, UTMIP_RESET, DISABLE, RegVal); USB_IF_REG_WR(SUSP_CTRL, RegVal); if (pUsbPhy->Instance == 0) { RegVal = USB1_IF_REG_RD(USB1_LEGACY_CTRL); RegVal = USB1_IF_FLD_SET_DRF_DEF( USB1_LEGACY_CTRL, USB1_VBUS_SENSE_CTL, A_SESS_VLD, RegVal); USB1_IF_REG_WR(USB1_LEGACY_CTRL, RegVal); } if (pUsbPhy->Instance == 0) { USB1_IF_REG_UPDATE_DEF(USB_SUSP_CTRL, USB_SUSP_SET, UNSET); } USB_IF_REG_UPDATE_DEF(SUSP_CTRL, USB_SUSP_CLR, SET); NvOsWaitUS(10); USB_IF_REG_UPDATE_DEF(SUSP_CTRL, USB_SUSP_CLR, UNSET); } else { // Put the Phy in the suspend mode if (pUsbPhy->Instance == 0) { USB1_IF_REG_UPDATE_DEF(USB_SUSP_CTRL, USB_SUSP_SET, SET); NvOsWaitUS(10); USB1_IF_REG_UPDATE_DEF(USB_SUSP_CTRL, USB_SUSP_SET, UNSET); //NvOsDebugPrintf("Waiting for Phy Clock to stop \n"); // check for phy in suspend.. do { NvOsWaitUS(1); } while (USB_IF_REG_READ_VAL(SUSP_CTRL, USB_PHY_CLK_VALID)); //NvOsDebugPrintf("Phy Clock stopped successfully \n"); } // Put the Phy in the suspend mode if (pUsbPhy->Instance == 2) { RegVal = USB_REG_RD(PORTSC1); RegVal = USB_FLD_SET_DRF_DEF(PORTSC1, PHCD, ENABLE, RegVal); USB_REG_WR(PORTSC1, RegVal); } // Setup debounce time for wakeup event 5 HCLK cycles USB_IF_REG_UPDATE_NUM(SUSP_CTRL, USB_WAKEUP_DEBOUNCE_COUNT, 5); // ENABLE the automatic phy enable on wakeup event USB1_IF_REG_UPDATE_DEF(USB_SUSP_CTRL, USB_WAKE_ON_CNNT_EN_DEV, ENABLE); USB1_IF_REG_UPDATE_DEF(USB_SUSP_CTRL, USB_WAKE_ON_DISCON_EN_DEV, ENABLE); // USB Power down sequence /* decrement the pad control refernce count */ pUsbPhy->pUtmiPadConfig->PadOnRefCount--; if (!pUsbPhy->pUtmiPadConfig->PadOnRefCount) { /* since there is no reference to the pads turn off */ RegVal = NV_READ32(pUsbPhy->pUtmiPadConfig->pVirAdr + ((USB1_UTMIP_BIAS_CFG0_0)/4)); // Power down OTG and Bias circuitry RegVal = USB_UTMIP_FLD_SET_DRF_DEF(BIAS_CFG0, UTMIP_OTGPD, 1, RegVal); RegVal = USB_UTMIP_FLD_SET_DRF_DEF(BIAS_CFG0, UTMIP_BIASPD, 1, RegVal); NV_WRITE32(pUsbPhy->pUtmiPadConfig->pVirAdr + ((USB1_UTMIP_BIAS_CFG0_0)/4), RegVal); } // Disable Batery charge enabling bit set to '1' for disable USB_UTMIP_REG_UPDATE_NUM(BAT_CHRG_CFG0, UTMIP_PD_CHRG, 1); // Turn off power in the tranciver RegVal = USB_UTMIP_REG_RD(XCVR_CFG0); RegVal = USB_UTMIP_FLD_SET_DRF_DEF( XCVR_CFG0, UTMIP_FORCE_PDZI_POWERDOWN, 1, RegVal); RegVal = USB_UTMIP_FLD_SET_DRF_DEF( XCVR_CFG0, UTMIP_FORCE_PD2_POWERDOWN, 1, RegVal); RegVal = USB_UTMIP_FLD_SET_DRF_DEF( XCVR_CFG0, UTMIP_FORCE_PD_POWERDOWN, 1, RegVal); USB_UTMIP_REG_WR(XCVR_CFG0, RegVal); RegVal = USB_UTMIP_REG_RD(XCVR_CFG1); RegVal = USB_UTMIP_FLD_SET_DRF_DEF( XCVR_CFG1, UTMIP_FORCE_PDDISC_POWERDOWN, 1, RegVal); RegVal = USB_UTMIP_FLD_SET_DRF_DEF( XCVR_CFG1, UTMIP_FORCE_PDCHRP_POWERDOWN, 1, RegVal); RegVal = USB_UTMIP_FLD_SET_DRF_DEF( XCVR_CFG1, UTMIP_FORCE_PDDR_POWERDOWN, 1, RegVal); USB_UTMIP_REG_WR(XCVR_CFG1, RegVal); // Hold UTMIP in reset RegVal =USB_IF_REG_RD(SUSP_CTRL); RegVal = USB3_IF_FLD_SET_DRF_DEF(SUSP_CTRL, UTMIP_RESET, ENABLE, RegVal); USB_IF_REG_WR(SUSP_CTRL, RegVal); } } static void Ap20UsbPhySelectUsbMode( NvDdkUsbPhy *pUsbPhy) { NvU32 RegVal = 0; if ((pUsbPhy->pProperty->UsbInterfaceType == NvOdmUsbInterfaceType_Utmi) && (pUsbPhy->Instance == 2)) { // Disable ICUSB interface USB_REG_UPDATE_DEF(ICUSB_CTRL, IC_ENB1, DISABLE); // set UTMIP PHY and parallel UTMI interface RegVal = USB_REG_RD(PORTSC1); RegVal = USB_FLD_SET_DRF_DEF(PORTSC1, PTS, UTMI, RegVal); RegVal = USB_FLD_SET_DRF_DEF(PORTSC1, STS, PARALLEL_IF, RegVal); USB_REG_WR(PORTSC1, RegVal); } } static void Ap20UsbPhyUlpiNullModeConfigure( NvDdkUsbPhy *pUsbPhy) { // default trimmer values for ap20 NvOdmUsbTrimmerCtrl trimmerCtrl = {0, 0, 4, 4}; if (pUsbPhy->pProperty->TrimmerCtrl.UlpiShadowClkDelay || pUsbPhy->pProperty->TrimmerCtrl.UlpiClockOutDelay || pUsbPhy->pProperty->TrimmerCtrl.UlpiDataTrimmerSel || pUsbPhy->pProperty->TrimmerCtrl.UlpiStpDirNxtTrimmerSel) { // update the trimmer values if they are specified in nvodm_query NvOsMemcpy(&trimmerCtrl, &pUsbPhy->pProperty->TrimmerCtrl, sizeof(NvOdmUsbTrimmerCtrl)); } // Put the UHSIC in the reset USB_IF_REG_UPDATE_DEF(SUSP_CTRL, UHSIC_RESET, ENABLE); // Bypass the Pin Mux on the ULPI outputs and ULPI clock output enable ULPI_IF_REG_WR(TIMING_CTRL_0, ULPI_IF_REG_RD(TIMING_CTRL_0) | ULPI_IF_DRF_DEF(TIMING_CTRL_0, ULPI_OUTPUT_PINMUX_BYP, ENABLE) | ULPI_IF_DRF_DEF(TIMING_CTRL_0, ULPI_CLKOUT_PINMUX_BYP, ENABLE)); // Enable ULPI clock from clk_gen USB_IF_REG_UPDATE_DEF(SUSP_CTRL, ULPI_PHY_ENB, ENABLE); // Set the timming perameters ULPI_IF_REG_WR(TIMING_CTRL_0, ULPI_IF_REG_RD(TIMING_CTRL_0) | ULPI_IF_DRF_DEF(TIMING_CTRL_0, ULPI_SHADOW_CLK_LOOPBACK_EN, ENABLE) | ULPI_IF_DRF_DEF(TIMING_CTRL_0, ULPI_SHADOW_CLK_SEL, POST_PAD) | ULPI_IF_DRF_DEF(TIMING_CTRL_0, ULPI_OUTPUT_PINMUX_BYP, ENABLE) | ULPI_IF_DRF_DEF(TIMING_CTRL_0, ULPI_CLKOUT_PINMUX_BYP, ENABLE) | ULPI_IF_DRF_DEF(TIMING_CTRL_0, ULPI_LBK_PAD_EN, OUTPUT) | ULPI_IF_DRF_NUM(TIMING_CTRL_0, ULPI_SHADOW_CLK_DELAY, trimmerCtrl.UlpiShadowClkDelay) | ULPI_IF_DRF_NUM(TIMING_CTRL_0, ULPI_CLOCK_OUT_DELAY, trimmerCtrl.UlpiClockOutDelay) | ULPI_IF_DRF_NUM(TIMING_CTRL_0, ULPI_LBK_PAD_E_INPUT_OR, 0)); // Set all the trimmers to 0 at the start ULPI_IF_REG_WR(TIMING_CTRL_1, 0); // wait for 10 micro seconds NvOsWaitUS(10); // Set USB2 controller to null ulpi mode (ULPIS2S_ENA = 1) // Enable PLLU (ULPIS2S_PLLU_MASTER_BLASTER60 = 1) // ULPIS2S_SPARE[0] = VBUS active USB_IF_REG_WR(ULPIS2S_CTRL, USB_IF_DRF_DEF(ULPIS2S_CTRL, ULPIS2S_ENA, ENABLE) | USB_IF_DRF_DEF(ULPIS2S_CTRL, ULPIS2S_PLLU_MASTER_BLASTER60, ENABLE) | USB_IF_DRF_NUM(ULPIS2S_CTRL, ULPIS2S_SPARE, (pUsbPhy->pProperty->UsbMode == NvOdmUsbModeType_Host)?3:1)); // Select ULPI_CORE_CLK_SEL to SHADOW_CLK ULPI_IF_REG_WR(TIMING_CTRL_0, ULPI_IF_REG_RD(TIMING_CTRL_0) | ULPI_IF_DRF_DEF(TIMING_CTRL_0, ULPI_CORE_CLK_SEL, SHADOW_CLK)); // wait for 10 micro seconds NvOsWaitUS(10); // Set ULPI_CLK_OUT_ENA to 1 to enable ULPI null clocks // Can't set the trimmers before this ULPI_IF_REG_WR(TIMING_CTRL_0, ULPI_IF_REG_RD(TIMING_CTRL_0) | ULPI_IF_DRF_NUM(TIMING_CTRL_0, ULPI_CLK_OUT_ENA, 1)); // wait for 10 micro seconds NvOsWaitUS(10); // Set the trimmer values ULPI_IF_REG_WR(TIMING_CTRL_1, ULPI_IF_DRF_NUM(TIMING_CTRL_1, ULPI_DATA_TRIMMER_LOAD, 0) | ULPI_IF_DRF_NUM(TIMING_CTRL_1, ULPI_DATA_TRIMMER_SEL, trimmerCtrl.UlpiDataTrimmerSel) | ULPI_IF_DRF_NUM(TIMING_CTRL_1, ULPI_STPDIRNXT_TRIMMER_LOAD, 0) | ULPI_IF_DRF_NUM(TIMING_CTRL_1, ULPI_STPDIRNXT_TRIMMER_SEL, trimmerCtrl.UlpiStpDirNxtTrimmerSel) | ULPI_IF_DRF_NUM(TIMING_CTRL_1, ULPI_DIR_TRIMMER_LOAD, 0) | ULPI_IF_DRF_NUM(TIMING_CTRL_1, ULPI_DIR_TRIMMER_SEL, 4)); // wait for 10 micro seconds NvOsWaitUS(10); //Load the trimmers by toggling the load bits ULPI_IF_REG_WR(TIMING_CTRL_1, ULPI_IF_DRF_NUM(TIMING_CTRL_1, ULPI_DATA_TRIMMER_LOAD, 1) | ULPI_IF_DRF_NUM(TIMING_CTRL_1, ULPI_DATA_TRIMMER_SEL, trimmerCtrl.UlpiDataTrimmerSel) | ULPI_IF_DRF_NUM(TIMING_CTRL_1, ULPI_STPDIRNXT_TRIMMER_LOAD, 1) | ULPI_IF_DRF_NUM(TIMING_CTRL_1, ULPI_STPDIRNXT_TRIMMER_SEL, trimmerCtrl.UlpiStpDirNxtTrimmerSel) | ULPI_IF_DRF_NUM(TIMING_CTRL_1, ULPI_DIR_TRIMMER_LOAD, 1) | ULPI_IF_DRF_NUM(TIMING_CTRL_1, ULPI_DIR_TRIMMER_SEL, 4)); // wait for 10 micro seconds NvOsWaitUS(10); // Set ULPI_CLK_PADOUT_ENA to 1 to enable ULPI null clock going out to // ulpi clk pad (ulpi_clk) ULPI_IF_REG_WR(TIMING_CTRL_0, ULPI_IF_REG_RD(TIMING_CTRL_0) | ULPI_IF_DRF_NUM(TIMING_CTRL_0, ULPI_CLK_PADOUT_ENA, 1)); } static void Ap20UsbPhyUlpiLinkModeConfigure( NvDdkUsbPhy *pUsbPhy, NvBool Enable) { NvU32 RegVal; if (Enable) { // Put the UHSIC in the reset USB_IF_REG_UPDATE_DEF(SUSP_CTRL, UHSIC_RESET, ENABLE); // Bypass the Pin Mux on the ULPI outputs and ULPI clock output enable ULPI_IF_REG_WR(TIMING_CTRL_0, ULPI_IF_REG_RD(TIMING_CTRL_0) | ULPI_IF_DRF_DEF(TIMING_CTRL_0, ULPI_OUTPUT_PINMUX_BYP, ENABLE) | ULPI_IF_DRF_DEF(TIMING_CTRL_0, ULPI_CLKOUT_PINMUX_BYP, ENABLE)); // Enable ULPI clock from clk_gen USB_IF_REG_UPDATE_DEF(SUSP_CTRL, ULPI_PHY_ENB, ENABLE); // Set all the trimmers to 0 at the start ULPI_IF_REG_WR(TIMING_CTRL_1, 0); // Set the trimmer values ULPI_IF_REG_WR(TIMING_CTRL_1, ULPI_IF_DRF_NUM(TIMING_CTRL_1, ULPI_DATA_TRIMMER_LOAD, 0) | ULPI_IF_DRF_NUM(TIMING_CTRL_1, ULPI_DATA_TRIMMER_SEL, 4) | ULPI_IF_DRF_NUM(TIMING_CTRL_1, ULPI_STPDIRNXT_TRIMMER_LOAD, 0) | ULPI_IF_DRF_NUM(TIMING_CTRL_1, ULPI_STPDIRNXT_TRIMMER_SEL, 4) | ULPI_IF_DRF_NUM(TIMING_CTRL_1, ULPI_DIR_TRIMMER_LOAD, 0) | ULPI_IF_DRF_NUM(TIMING_CTRL_1, ULPI_DIR_TRIMMER_SEL, 4)); // wait for 10 micro seconds NvOsWaitUS(10); //Load the trimmers by toggling the load bits ULPI_IF_REG_WR(TIMING_CTRL_1, ULPI_IF_DRF_NUM(TIMING_CTRL_1, ULPI_DATA_TRIMMER_LOAD, 1) | ULPI_IF_DRF_NUM(TIMING_CTRL_1, ULPI_DATA_TRIMMER_SEL, 4) | ULPI_IF_DRF_NUM(TIMING_CTRL_1, ULPI_STPDIRNXT_TRIMMER_LOAD, 1) | ULPI_IF_DRF_NUM(TIMING_CTRL_1, ULPI_STPDIRNXT_TRIMMER_SEL, 4) | ULPI_IF_DRF_NUM(TIMING_CTRL_1, ULPI_DIR_TRIMMER_LOAD, 1) | ULPI_IF_DRF_NUM(TIMING_CTRL_1, ULPI_DIR_TRIMMER_SEL, 4)); // fix VbusValid for Harmony due to floating VBUS RegVal = USB_REG_RD(ULPI_VIEWPORT); RegVal = USB_FLD_SET_DRF_DEF(ULPI_VIEWPORT, ULPI_WAKEUP, CLEAR, RegVal); RegVal = USB_FLD_SET_DRF_DEF(ULPI_VIEWPORT, ULPI_RUN, SET, RegVal); RegVal = USB_FLD_SET_DRF_DEF(ULPI_VIEWPORT, ULPI_RD_WR, WRITE, RegVal); RegVal = USB_FLD_SET_DRF_DEF(ULPI_VIEWPORT, ULPI_PORT, SW_DEFAULT, RegVal); RegVal = USB_REG_SET_DRF_NUM(ULPI_VIEWPORT, ULPI_REG_ADDR, 0x8, RegVal); RegVal = USB_REG_SET_DRF_NUM(ULPI_VIEWPORT, ULPI_DATA_WR, 0x40, RegVal); USB_REG_WR(ULPI_VIEWPORT, RegVal); // wait for run bit to be cleared do { RegVal = USB_REG_RD(ULPI_VIEWPORT); } while (USB_DRF_VAL(ULPI_VIEWPORT, ULPI_RUN, RegVal)); // set UseExternalVbusIndicator to 1 RegVal = USB_REG_RD(ULPI_VIEWPORT); RegVal = USB_FLD_SET_DRF_DEF(ULPI_VIEWPORT, ULPI_WAKEUP, CLEAR, RegVal); RegVal = USB_FLD_SET_DRF_DEF(ULPI_VIEWPORT, ULPI_RUN, SET, RegVal); RegVal = USB_FLD_SET_DRF_DEF(ULPI_VIEWPORT, ULPI_RD_WR, WRITE, RegVal); RegVal = USB_FLD_SET_DRF_DEF(ULPI_VIEWPORT, ULPI_PORT, SW_DEFAULT, RegVal); RegVal = USB_REG_SET_DRF_NUM(ULPI_VIEWPORT, ULPI_REG_ADDR, 0xB, RegVal); RegVal = USB_REG_SET_DRF_NUM(ULPI_VIEWPORT, ULPI_DATA_WR, 0x80, RegVal); USB_REG_WR(ULPI_VIEWPORT, RegVal); // wait for run bit to be cleared do { RegVal = USB_REG_RD(ULPI_VIEWPORT); } while (USB_DRF_VAL(ULPI_VIEWPORT, ULPI_RUN, RegVal)); // enabling WKCN/WKDS/WKOC bit RegVal = USB_REG_RD(PORTSC1); RegVal = USB_FLD_SET_DRF_DEF(PORTSC1, WKCN, ENABLE, RegVal); RegVal = USB_FLD_SET_DRF_DEF(PORTSC1, WKDS, ENABLE, RegVal); RegVal = USB_FLD_SET_DRF_DEF(PORTSC1, WKOC, ENABLE, RegVal); USB_REG_WR(PORTSC1, RegVal); } else { // Resetting the ULPI register IndicatorPassThru RegVal = USB_REG_RD(ULPI_VIEWPORT); RegVal = USB_FLD_SET_DRF_DEF(ULPI_VIEWPORT, ULPI_WAKEUP, CLEAR, RegVal); RegVal = USB_FLD_SET_DRF_DEF(ULPI_VIEWPORT, ULPI_RUN, SET, RegVal); RegVal = USB_FLD_SET_DRF_DEF(ULPI_VIEWPORT, ULPI_RD_WR, WRITE, RegVal); RegVal = USB_FLD_SET_DRF_DEF(ULPI_VIEWPORT, ULPI_PORT, SW_DEFAULT, RegVal); RegVal = USB_REG_SET_DRF_NUM(ULPI_VIEWPORT, ULPI_REG_ADDR, 0x9, RegVal); RegVal = USB_REG_SET_DRF_NUM(ULPI_VIEWPORT, ULPI_DATA_WR, 0x40, RegVal); USB_REG_WR(ULPI_VIEWPORT, RegVal); // wait for run bit to be cleared do { RegVal = USB_REG_RD(ULPI_VIEWPORT); } while (USB_DRF_VAL(ULPI_VIEWPORT, ULPI_RUN, RegVal)); // Resetting ULPI register UseExternalVbusIndicator RegVal = USB_REG_RD(ULPI_VIEWPORT); RegVal = USB_FLD_SET_DRF_DEF(ULPI_VIEWPORT, ULPI_WAKEUP, CLEAR, RegVal); RegVal = USB_FLD_SET_DRF_DEF(ULPI_VIEWPORT, ULPI_RUN, SET, RegVal); RegVal = USB_FLD_SET_DRF_DEF(ULPI_VIEWPORT, ULPI_RD_WR, WRITE, RegVal); RegVal = USB_FLD_SET_DRF_DEF(ULPI_VIEWPORT, ULPI_PORT, SW_DEFAULT, RegVal); RegVal = USB_REG_SET_DRF_NUM(ULPI_VIEWPORT, ULPI_REG_ADDR, 0xC, RegVal); RegVal = USB_REG_SET_DRF_NUM(ULPI_VIEWPORT, ULPI_DATA_WR, 0x80, RegVal); USB_REG_WR(ULPI_VIEWPORT, RegVal); // wait for run bit to be cleared do { RegVal = USB_REG_RD(ULPI_VIEWPORT); } while (USB_DRF_VAL(ULPI_VIEWPORT, ULPI_RUN, RegVal)); // USB Interrupt Rising - making sure vbus comparator and id are off RegVal = USB_REG_RD(ULPI_VIEWPORT); RegVal = USB_FLD_SET_DRF_DEF(ULPI_VIEWPORT, ULPI_WAKEUP, CLEAR, RegVal); RegVal = USB_FLD_SET_DRF_DEF(ULPI_VIEWPORT, ULPI_RUN, SET, RegVal); RegVal = USB_FLD_SET_DRF_DEF(ULPI_VIEWPORT, ULPI_RD_WR, WRITE, RegVal); RegVal = USB_FLD_SET_DRF_DEF(ULPI_VIEWPORT, ULPI_PORT, SW_DEFAULT, RegVal); RegVal = USB_REG_SET_DRF_NUM(ULPI_VIEWPORT, ULPI_REG_ADDR, 0x0d, RegVal); RegVal = USB_REG_SET_DRF_NUM(ULPI_VIEWPORT, ULPI_DATA_WR, 0x00, RegVal); USB_REG_WR(ULPI_VIEWPORT, RegVal); // wait for run bit to be cleared do { RegVal = USB_REG_RD(ULPI_VIEWPORT); } while (USB_DRF_VAL(ULPI_VIEWPORT, ULPI_RUN, RegVal)); // USB Interrupt Falling RegVal = USB_REG_RD(ULPI_VIEWPORT); RegVal = USB_FLD_SET_DRF_DEF(ULPI_VIEWPORT, ULPI_WAKEUP, CLEAR, RegVal); RegVal = USB_FLD_SET_DRF_DEF(ULPI_VIEWPORT, ULPI_RUN, SET, RegVal); RegVal = USB_FLD_SET_DRF_DEF(ULPI_VIEWPORT, ULPI_RD_WR, WRITE, RegVal); RegVal = USB_FLD_SET_DRF_DEF(ULPI_VIEWPORT, ULPI_PORT, SW_DEFAULT, RegVal); RegVal = USB_REG_SET_DRF_NUM(ULPI_VIEWPORT, ULPI_REG_ADDR, 0x10, RegVal); RegVal = USB_REG_SET_DRF_NUM(ULPI_VIEWPORT, ULPI_DATA_WR, 0x00, RegVal); USB_REG_WR(ULPI_VIEWPORT, RegVal); // wait for run bit to be cleared do { RegVal = USB_REG_RD(ULPI_VIEWPORT); } while (USB_DRF_VAL(ULPI_VIEWPORT, ULPI_RUN, RegVal)); //Carkit Control RegVal = USB_REG_RD(ULPI_VIEWPORT); RegVal = USB_FLD_SET_DRF_DEF(ULPI_VIEWPORT, ULPI_WAKEUP, CLEAR, RegVal); RegVal = USB_FLD_SET_DRF_DEF(ULPI_VIEWPORT, ULPI_RUN, SET, RegVal); RegVal = USB_FLD_SET_DRF_DEF(ULPI_VIEWPORT, ULPI_RD_WR, WRITE, RegVal); RegVal = USB_FLD_SET_DRF_DEF(ULPI_VIEWPORT, ULPI_PORT, SW_DEFAULT, RegVal); RegVal = USB_REG_SET_DRF_NUM(ULPI_VIEWPORT, ULPI_REG_ADDR, 0x19, RegVal); RegVal = USB_REG_SET_DRF_NUM(ULPI_VIEWPORT, ULPI_DATA_WR, 0x00, RegVal); USB_REG_WR(ULPI_VIEWPORT, RegVal); // wait for run bit to be cleared do { RegVal = USB_REG_RD(ULPI_VIEWPORT); } while (USB_DRF_VAL(ULPI_VIEWPORT, ULPI_RUN, RegVal)); // Disabling ID float Rise/Fall (Carkit Enable) RegVal = USB_REG_RD(ULPI_VIEWPORT); RegVal = USB_FLD_SET_DRF_DEF(ULPI_VIEWPORT, ULPI_WAKEUP, CLEAR, RegVal); RegVal = USB_FLD_SET_DRF_DEF(ULPI_VIEWPORT, ULPI_RUN, SET, RegVal); RegVal = USB_FLD_SET_DRF_DEF(ULPI_VIEWPORT, ULPI_RD_WR, WRITE, RegVal); RegVal = USB_FLD_SET_DRF_DEF(ULPI_VIEWPORT, ULPI_PORT, SW_DEFAULT, RegVal); RegVal = USB_REG_SET_DRF_NUM(ULPI_VIEWPORT, ULPI_REG_ADDR, 0x1D, RegVal); RegVal = USB_REG_SET_DRF_NUM(ULPI_VIEWPORT, ULPI_DATA_WR, 0x00, RegVal); USB_REG_WR(ULPI_VIEWPORT, RegVal); // wait for run bit to be cleared do { RegVal = USB_REG_RD(ULPI_VIEWPORT); } while (USB_DRF_VAL(ULPI_VIEWPORT, ULPI_RUN, RegVal)); // USB I/O and power RegVal = USB_REG_RD(ULPI_VIEWPORT); RegVal = USB_FLD_SET_DRF_DEF(ULPI_VIEWPORT, ULPI_WAKEUP, CLEAR, RegVal); RegVal = USB_FLD_SET_DRF_DEF(ULPI_VIEWPORT, ULPI_RUN, SET, RegVal); RegVal = USB_FLD_SET_DRF_DEF(ULPI_VIEWPORT, ULPI_RD_WR, WRITE, RegVal); RegVal = USB_FLD_SET_DRF_DEF(ULPI_VIEWPORT, ULPI_PORT, SW_DEFAULT, RegVal); RegVal = USB_REG_SET_DRF_NUM(ULPI_VIEWPORT, ULPI_REG_ADDR, 0x39, RegVal); RegVal = USB_REG_SET_DRF_NUM(ULPI_VIEWPORT, ULPI_DATA_WR, 0x00, RegVal); USB_REG_WR(ULPI_VIEWPORT, RegVal); // wait for run bit to be cleared do { RegVal = USB_REG_RD(ULPI_VIEWPORT); } while (USB_DRF_VAL(ULPI_VIEWPORT, ULPI_RUN, RegVal)); // clear WKCN/WKDS/WKOC wake-on events that can cause the USB // Controller to immediately bring the ULPI PHY out of low power mode RegVal = USB_REG_RD(PORTSC1); RegVal = USB_FLD_SET_DRF_DEF(PORTSC1, WKCN, DISBLE, RegVal); RegVal = USB_FLD_SET_DRF_DEF(PORTSC1, WKDS, DISBLE, RegVal); RegVal = USB_FLD_SET_DRF_DEF(PORTSC1, WKOC, DISBLE, RegVal); USB_REG_WR(PORTSC1, RegVal); } } static void Ap20UsbPhyUlpiPowerControl( NvDdkUsbPhy *pUsbPhy, NvBool Enable) { NvU32 RegVal = 0; if (pUsbPhy->pProperty->UsbMode == NvOdmUsbModeType_Host) { if (Enable) { // Bring the Phy out of suspend mode USB_IF_REG_UPDATE_DEF(SUSP_CTRL, USB_SUSP_CLR, SET); NvOsWaitUS(100); USB_IF_REG_UPDATE_DEF(SUSP_CTRL, USB_SUSP_CLR, UNSET); } else { // Put the Phy in the suspend mode RegVal = USB_REG_RD(PORTSC1); RegVal = USB_FLD_SET_DRF_DEF(PORTSC1, PHCD, ENABLE, RegVal); USB_REG_WR(PORTSC1, RegVal); } } } static NvError Ap20UsbPhyIoctlVbusInterrupt( 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 = USB1_IF_REG_RD(USB_PHY_VBUS_WAKEUP_ID); if (pVbusIntr->EnableVBusInterrupt) { RegVal = NV_FLD_SET_DRF_DEF(USB1_IF, USB_PHY_VBUS_WAKEUP_ID, VBUS_WAKEUP_WAKEUP_EN, ENABLE, RegVal); RegVal = NV_FLD_SET_DRF_DEF(USB1_IF, USB_PHY_VBUS_WAKEUP_ID, VBUS_WAKEUP_INT_EN, ENABLE, RegVal); } else { RegVal = NV_FLD_SET_DRF_DEF(USB1_IF, USB_PHY_VBUS_WAKEUP_ID, VBUS_WAKEUP_WAKEUP_EN, DISABLE, RegVal); RegVal = NV_FLD_SET_DRF_DEF(USB1_IF, USB_PHY_VBUS_WAKEUP_ID, VBUS_WAKEUP_INT_EN, DISABLE, RegVal); RegVal = NV_FLD_SET_DRF_DEF(USB1_IF, USB_PHY_VBUS_WAKEUP_ID, VBUS_WAKEUP_CHG_DET, SET, RegVal); } USB1_IF_REG_WR(USB_PHY_VBUS_WAKEUP_ID, RegVal); } else if (pUsbPhy->pProperty->UsbInterfaceType == NvOdmUsbInterfaceType_UlpiExternalPhy) { if (pVbusIntr->EnableVBusInterrupt) { USB_REG_WR(USBINTR, USB_DRF_DEF(USBINTR, UE, ENABLE)); RegVal = USB_REG_SET_DRF_DEF(OTGSC, BSVIE, ENABLE); USB_REG_WR(OTGSC, RegVal); } else { USB_REG_WR(USBSTS, USB_REG_RD(USBSTS)); RegVal = USB_REG_SET_DRF_DEF(OTGSC, BSVIE, DISABLE); USB_REG_WR(OTGSC, RegVal); } } else { // In NULL phy mode this is not required as VBUS is always present } return NvSuccess; } static NvError Ap20UsbPhyIoctlVBusStatus( NvDdkUsbPhy *pUsbPhy, void *pOutputArgs) { NvDdkUsbPhyIoctl_VBusStatusOutputArgs *pVBusStatus = NULL; NvU32 RegVal = 0; if (!pOutputArgs) return NvError_BadParameter; pVBusStatus = (NvDdkUsbPhyIoctl_VBusStatusOutputArgs *)pOutputArgs; pVBusStatus = (NvDdkUsbPhyIoctl_VBusStatusOutputArgs *)pOutputArgs; if (pUsbPhy->pProperty->UsbInterfaceType == NvOdmUsbInterfaceType_Utmi) { RegVal = USB1_IF_REG_RD(USB_PHY_VBUS_WAKEUP_ID); if (NV_DRF_VAL(USB1_IF, USB_PHY_VBUS_WAKEUP_ID, VBUS_WAKEUP_STS, RegVal)) { pVBusStatus->VBusDetected = NV_TRUE; } else { pVBusStatus->VBusDetected = NV_FALSE; } } else if (pUsbPhy->pProperty->UsbInterfaceType == NvOdmUsbInterfaceType_UlpiExternalPhy) { if (USB_REG_READ_VAL(OTGSC, BSV)) { pVBusStatus->VBusDetected = NV_TRUE; } else { pVBusStatus->VBusDetected = NV_FALSE; } } else { // In NULL phy mode VBUS is always present pVBusStatus->VBusDetected = NV_TRUE; } return NvSuccess; } static NvError Ap20UsbPhyIoctlIdPinInterrupt( 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 = USB1_IF_REG_RD(USB_PHY_VBUS_WAKEUP_ID); if (pIdPinIntr->EnableIdPinInterrupt) { RegVal = NV_FLD_SET_DRF_DEF(USB1_IF, USB_PHY_VBUS_WAKEUP_ID, ID_PU, ENABLE, RegVal); RegVal = NV_FLD_SET_DRF_DEF(USB1_IF, USB_PHY_VBUS_WAKEUP_ID, ID_INT_EN, ENABLE, RegVal); } else { RegVal = NV_FLD_SET_DRF_DEF(USB1_IF, USB_PHY_VBUS_WAKEUP_ID, ID_PU, DISABLE, RegVal); RegVal = NV_FLD_SET_DRF_DEF(USB1_IF, USB_PHY_VBUS_WAKEUP_ID, ID_INT_EN, DISABLE, RegVal); RegVal = NV_FLD_SET_DRF_DEF(USB1_IF, USB_PHY_VBUS_WAKEUP_ID, ID_CHG_DET, SET, RegVal); } USB1_IF_REG_WR(USB_PHY_VBUS_WAKEUP_ID, RegVal); } else { //TODO:ENable the ID pin interrupt for the ULPI } return NvSuccess; } static NvError Ap20UsbPhyIoctlIdPinStatus( NvDdkUsbPhy *pUsbPhy, void *pOutputArgs) { NvDdkUsbPhyIoctl_IdPinStatusOutputArgs *pIdPinStatus = NULL; NvU32 RegVal = 0; if (!pOutputArgs) return NvError_BadParameter; pIdPinStatus = (NvDdkUsbPhyIoctl_IdPinStatusOutputArgs *)pOutputArgs; pIdPinStatus = (NvDdkUsbPhyIoctl_IdPinStatusOutputArgs *)pOutputArgs; RegVal = USB1_IF_REG_RD(USB_PHY_VBUS_WAKEUP_ID); if (!NV_DRF_VAL(USB1_IF, USB_PHY_VBUS_WAKEUP_ID, ID_STS, RegVal)) { pIdPinStatus->IdPinSetToLow = NV_TRUE; } else { pIdPinStatus->IdPinSetToLow = NV_FALSE; } return NvSuccess; } static NvError Ap20UsbPhyIoctlDedicatedChargerDetection( 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_UTMIP_REG_RD(BAT_CHRG_CFG0); RegVal = NV_FLD_SET_DRF_NUM(USB1_UTMIP, BAT_CHRG_CFG0, UTMIP_OP_SRC_EN, 1, RegVal); RegVal = NV_FLD_SET_DRF_NUM(USB1_UTMIP, BAT_CHRG_CFG0, UTMIP_ON_SINK_EN, 1, RegVal); USB_UTMIP_REG_WR(BAT_CHRG_CFG0, RegVal); // Source should be on for 100 ms as per USB charging spec NvOsSleepMS(TDP_SRC_ON_MS); RegVal = USB1_IF_REG_RD(USB_PHY_VBUS_WAKEUP_ID); if (pChargerDetection->EnableChargerInterrupt) { RegVal = NV_FLD_SET_DRF_DEF(USB1_IF, 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(USB1_IF, USB_PHY_VBUS_WAKEUP_ID, VDAT_DET_INT_EN, DISABLE, RegVal); RegVal = NV_FLD_SET_DRF_DEF(USB1_IF, USB_PHY_VBUS_WAKEUP_ID, VDAT_DET_CHG_DET, SET, RegVal); } USB1_IF_REG_WR(USB_PHY_VBUS_WAKEUP_ID, RegVal); } else { // disable the interrupt RegVal = USB1_IF_REG_RD(USB_PHY_VBUS_WAKEUP_ID); RegVal = NV_FLD_SET_DRF_DEF(USB1_IF, USB_PHY_VBUS_WAKEUP_ID, VDAT_DET_INT_EN, DISABLE, RegVal); RegVal = NV_FLD_SET_DRF_DEF(USB1_IF, USB_PHY_VBUS_WAKEUP_ID, VDAT_DET_CHG_DET, SET, RegVal); USB1_IF_REG_WR(USB_PHY_VBUS_WAKEUP_ID, RegVal); // Disable charger detection logic RegVal = USB_UTMIP_REG_RD(BAT_CHRG_CFG0); RegVal = NV_FLD_SET_DRF_NUM(USB1_UTMIP, BAT_CHRG_CFG0, UTMIP_OP_SRC_EN, 0, RegVal); RegVal = NV_FLD_SET_DRF_NUM(USB1_UTMIP, BAT_CHRG_CFG0, UTMIP_ON_SINK_EN, 0, RegVal); USB_UTMIP_REG_WR(BAT_CHRG_CFG0, RegVal); // Delay of 40 ms before we pull the D+ as per battery charger spec. NvOsSleepMS(TDPSRC_CON_MS); } return NvSuccess; } static NvError Ap20UsbPhyIoctlDedicatedChargerStatus( 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 = USB1_IF_REG_RD(USB_PHY_VBUS_WAKEUP_ID); if (NV_DRF_VAL(USB1_IF, USB_PHY_VBUS_WAKEUP_ID, VDAT_DET_STS, RegVal)) { pChargerStatus->ChargerDetected = NV_TRUE; } else { pChargerStatus->ChargerDetected = NV_FALSE; } return NvSuccess; } static NvError Ap20UsbPhyIoctl( NvDdkUsbPhy *pUsbPhy, NvDdkUsbPhyIoctlType IoctlType, const void *pInputArgs, void *pOutputArgs) { NvError ErrStatus = NvSuccess; switch (IoctlType) { case NvDdkUsbPhyIoctlType_VBusStatus: ErrStatus = Ap20UsbPhyIoctlVBusStatus(pUsbPhy, pOutputArgs); break; case NvDdkUsbPhyIoctlType_VBusInterrupt: ErrStatus = Ap20UsbPhyIoctlVbusInterrupt(pUsbPhy, pInputArgs); break; case NvDdkUsbPhyIoctlType_IdPinStatus: ErrStatus = Ap20UsbPhyIoctlIdPinStatus(pUsbPhy, pOutputArgs); break; case NvDdkUsbPhyIoctlType_IdPinInterrupt: ErrStatus = Ap20UsbPhyIoctlIdPinInterrupt(pUsbPhy, pInputArgs); break; case NvDdkUsbPhyIoctlType_DedicatedChargerStatus: ErrStatus = Ap20UsbPhyIoctlDedicatedChargerStatus(pUsbPhy, pOutputArgs); break; case NvDdkUsbPhyIoctlType_DedicatedChargerDetection: ErrStatus = Ap20UsbPhyIoctlDedicatedChargerDetection(pUsbPhy, pInputArgs); break; default: return NvError_NotSupported; } return ErrStatus; } static NvError Ap20UsbPhyWaitForStableClock( NvDdkUsbPhy *pUsbPhy) { NvU32 TimeOut = USB_PHY_HW_TIMEOUT_US; NvU32 PhyClkValid = 0; // Wait for the phy clock to become valid or hardware timeout do { PhyClkValid = USB_IF_REG_READ_VAL(SUSP_CTRL, USB_PHY_CLK_VALID); if (!TimeOut) { return NvError_Timeout; } NvOsWaitUS(1); TimeOut--; } while (PhyClkValid != USB3_IF_USB_SUSP_CTRL_0_USB_PHY_CLK_VALID_SET); return NvSuccess; } static NvError Ap20UsbPhyPowerUp( NvDdkUsbPhy *pUsbPhy) { NvError ErrVal = NvSuccess; switch (pUsbPhy->pProperty->UsbInterfaceType) { case NvOdmUsbInterfaceType_UlpiNullPhy: Ap20UsbPhyUlpiNullModeConfigure(pUsbPhy); Ap20UsbPhyUlpiPowerControl(pUsbPhy, NV_TRUE); break; case NvOdmUsbInterfaceType_UlpiExternalPhy: pUsbPhy->hOdmUlpi = NvOdmUsbUlpiOpen(pUsbPhy->Instance); Ap20UsbPhyUlpiLinkModeConfigure(pUsbPhy, NV_TRUE); Ap20UsbPhyUlpiPowerControl(pUsbPhy, NV_TRUE); break; case NvOdmUsbInterfaceType_Utmi: ErrVal = Ap20UsbPhyUtmiConfigure(pUsbPhy); if (ErrVal != NvSuccess) return ErrVal; Ap20UsbPhyUtmiPowerControl(pUsbPhy, NV_TRUE); default: break; } ErrVal = Ap20UsbPhyWaitForStableClock(pUsbPhy); if (ErrVal == NvSuccess) { Ap20UsbPhySelectUsbMode(pUsbPhy); if (pUsbPhy->pProperty->UsbInterfaceType == NvOdmUsbInterfaceType_UlpiNullPhy) pUsbPhy->hOdmUlpi = NvOdmUsbUlpiOpen(pUsbPhy->Instance); } return ErrVal; } static NvError Ap20UsbPhyPowerDown( NvDdkUsbPhy *pUsbPhy) { switch (pUsbPhy->pProperty->UsbInterfaceType) { case NvOdmUsbInterfaceType_UlpiNullPhy: break; case NvOdmUsbInterfaceType_UlpiExternalPhy: Ap20UsbPhyUlpiLinkModeConfigure(pUsbPhy, NV_FALSE); Ap20UsbPhyUlpiPowerControl(pUsbPhy, NV_FALSE); if (pUsbPhy->hOdmUlpi) { NvOdmUsbUlpiClose(pUsbPhy->hOdmUlpi); pUsbPhy->hOdmUlpi = NULL; } break; case NvOdmUsbInterfaceType_Utmi: Ap20UsbPhyUtmiPowerControl(pUsbPhy, NV_FALSE); default: break; } return NvSuccess; } static void Ap20UsbPhyClose( NvDdkUsbPhy *pUsbPhy) { // Power down the USB controller NV_ASSERT_SUCCESS(Ap20UsbPhyPowerDown(pUsbPhy)); } /* static void PrintRegs( NvDdkUsbPhy *pUsbPhy) { NvOsDebugPrintf("********** USB REG DUMP - Start\n"); NvOsDebugPrintf("USBMODE: 0x%x\n",USB_REG_RD(USBMODE)); NvOsDebugPrintf("OTGSC: 0x%x\n",USB_REG_RD(OTGSC)); NvOsDebugPrintf("TXFILLTUNING: 0x%x\n",USB_REG_RD(TXFILLTUNING)); NvOsDebugPrintf("ASYNCLISTADDR: 0x%x\n",USB_REG_RD(ASYNCLISTADDR)); NvOsDebugPrintf("PERIODICLISTBASE: 0x%x\n",USB_REG_RD(PERIODICLISTBASE)); NvOsDebugPrintf("USBCMD: 0x%x\n",USB_REG_RD(USBCMD)); NvOsDebugPrintf("USBINTR: 0x%x\n",USB_REG_RD(USBINTR)); NvOsDebugPrintf("USBSTS: 0x%x\n",USB_REG_RD(USBSTS)); NvOsDebugPrintf("PORTSC1: 0x%x\n",USB_REG_RD(PORTSC1)); NvOsDebugPrintf("********** USB REG DUMP - End\n"); } */ static void Ap20PhyRemoveTristate( NvDdkUsbPhy *pUsbPhy) { NvU32 RegVal = 0; // Remove ULPI pads from tristate. This step will bring the PHY out of suspend, since // the controller will start driving the ULPI pads. RegVal = USB_MISC_REGR(pUsbPhy, APB_MISC_PP_TRISTATE_REG_B_0); RegVal = NV_FLD_SET_DRF_DEF(APB_MISC_PP, TRISTATE_REG_B, Z_UAA, NORMAL, RegVal); RegVal = NV_FLD_SET_DRF_DEF(APB_MISC_PP, TRISTATE_REG_B, Z_UAB, NORMAL, RegVal); RegVal = NV_FLD_SET_DRF_DEF(APB_MISC_PP, TRISTATE_REG_B, Z_UAC, NORMAL, RegVal); USB_MISC_REGW(pUsbPhy, APB_MISC_PP_TRISTATE_REG_B_0, RegVal); do { RegVal = USB_IF_REG_RD(SUSP_CTRL); RegVal = NV_DRF_VAL(USB2_IF_USB,SUSP_CTRL, USB_PHY_CLK_VALID, RegVal); } while (RegVal != USB2_IF_USB_SUSP_CTRL_0_USB_PHY_CLK_VALID_SET); } static void Ap20PhyRestoreRegs( NvDdkUsbPhy *pUsbPhy) { NvU16 RegCount = 0; RegCount = pUsbPhy->Context.UsbRegCount; RegCount--; USB_REG_WR(USBMODE, pUsbPhy->Context.UsbRegs[RegCount--]); USB_REG_WR(OTGSC, pUsbPhy->Context.UsbRegs[RegCount--]); USB_REG_WR(TXFILLTUNING, pUsbPhy->Context.UsbRegs[RegCount--]); USB_REG_WR(ASYNCLISTADDR, pUsbPhy->Context.UsbRegs[RegCount--]); USB_REG_WR(PERIODICLISTBASE, pUsbPhy->Context.UsbRegs[RegCount--]); // Restore interrupt context later RegCount--; USB_REG_WR(USBCMD, pUsbPhy->Context.UsbRegs[RegCount--]); } static void Ap20PhySaveContext( NvDdkUsbPhy *pUsbPhy) { NvU16 RegCount = 0; pUsbPhy->Context.UsbPortSpeed = (NvDdkUsbPhyPortSpeedType)USB_REG_READ_VAL(PORTSC1, PSPD); // If no device connection or invalid speeds just return if( pUsbPhy->Context.UsbPortSpeed > NvDdkUsbPhyPortSpeedType_High) { pUsbPhy->Context.IsValid = NV_FALSE; return; } // PrintRegs(pUsbPhy); pUsbPhy->Context.UsbRegs[RegCount++] = USB_REG_RD(USBCMD); pUsbPhy->Context.UsbRegs[RegCount++] = USB_REG_RD(USBINTR); pUsbPhy->Context.UsbRegs[RegCount++] = USB_REG_RD(PERIODICLISTBASE); pUsbPhy->Context.UsbRegs[RegCount++] = USB_REG_RD(ASYNCLISTADDR); pUsbPhy->Context.UsbRegs[RegCount++] = USB_REG_RD(TXFILLTUNING); pUsbPhy->Context.UsbRegs[RegCount++] = USB_REG_RD(OTGSC); pUsbPhy->Context.UsbRegs[RegCount++] = USB_REG_RD(USBMODE); pUsbPhy->Context.UsbRegCount = RegCount; pUsbPhy->Context.IsValid = NV_TRUE; } static void Ap20PhyRestoreContext( NvDdkUsbPhy *pUsbPhy) { NvU32 RegVal = 0; /* If any saved context is present, restore it */ // In case of no valid context just return if (!pUsbPhy->Context.IsValid) return; // Restore register context Ap20PhyRestoreRegs(pUsbPhy); // Enable Port Power USB_REG_UPDATE_DEF(PORTSC1, PP, POWERED); NvOsWaitUS(10); // Program the field PTC in PORTSC based on the saved speed mode RegVal = USB_REG_RD(PORTSC1); if (pUsbPhy->Context.UsbPortSpeed == NvDdkUsbPhyPortSpeedType_High) { RegVal = USB_REG_SET_DRF_NUM(PORTSC1, PTC, 0x05, RegVal); } else if (pUsbPhy->Context.UsbPortSpeed == NvDdkUsbPhyPortSpeedType_Full) { RegVal = USB_REG_SET_DRF_NUM(PORTSC1, PTC, 0x06, RegVal); } else if (pUsbPhy->Context.UsbPortSpeed == NvDdkUsbPhyPortSpeedType_Low) { RegVal = USB_REG_SET_DRF_NUM(PORTSC1, PTC, 0x07, RegVal); } else { NV_ASSERT(!"\n speed is not configureed properly"); } USB_REG_WR(PORTSC1, RegVal); NvOsWaitUS(10); // Disable test mode by setting PTC field to NORMAL_OP USB_REG_UPDATE_DEF(PORTSC1, PTC, NORMAL_OP); // Poll until CCS is enabled do { RegVal = USB_REG_RD(PORTSC1); } while (!USB_DRF_VAL(PORTSC1, CCS, RegVal)); // Poll until PE is enabled do { RegVal = USB_REG_RD(PORTSC1); } while (!USB_DRF_VAL(PORTSC1, PE, RegVal)); // Clear the PCI status, to avoid an interrupt taken upon resume USB_REG_UPDATE_DEF(USBSTS, PCI, PORT_CHANGE); do { RegVal = USB_REG_RD(USBSTS); } while (USB_DRF_VAL(USBSTS, PCI, RegVal)); // Put controller in suspend mode by writing 1 to SUSP bit of PORTSC USB_REG_UPDATE_DEF(PORTSC1, SUSP, SUSPEND); // Wait until port suspend completes while (!USB_REG_READ_VAL(PORTSC1, SUSP)) { NvOsWaitUS(1); }; if (pUsbPhy->pProperty->UsbInterfaceType == NvOdmUsbInterfaceType_UlpiExternalPhy) { Ap20PhyRemoveTristate(pUsbPhy); } // Restore interrupt register USB_REG_WR(USBINTR, pUsbPhy->Context.UsbRegs[1]); NvOsWaitUS(10); // PrintRegs(pUsbPhy); } void Ap20UsbPhyOpenHwInterface( NvDdkUsbPhy *pUsbPhy) { pUsbPhy->PowerUp = Ap20UsbPhyPowerUp; pUsbPhy->PowerDown = Ap20UsbPhyPowerDown; pUsbPhy->Ioctl = Ap20UsbPhyIoctl; pUsbPhy->WaitForStableClock = Ap20UsbPhyWaitForStableClock; pUsbPhy->CloseHwInterface = Ap20UsbPhyClose; pUsbPhy->SaveContext = Ap20PhySaveContext; pUsbPhy->RestoreContext = Ap20PhyRestoreContext; }