NvError NvRmPrivPmuInit(NvRmDeviceHandle hRmDevice)
{
    NvError e;
    ExecPlatform env;
    NvOdmPmuProperty PmuProperty;

    NV_ASSERT(hRmDevice);
    env = NvRmPrivGetExecPlatform(hRmDevice);

    NvOsMemset(&s_Pmu, 0, sizeof(NvRmPmu));
    s_PmuSupportedEnv = NV_FALSE;

    if (env == ExecPlatform_Soc)
    {
        // Set supported environment flag
        s_PmuSupportedEnv = NV_TRUE;

        // Create the PMU mutex, semaphore, interrupt handler thread,
        // register PMU interrupt, and get ODM PMU handle
        NV_CHECK_ERROR_CLEANUP(NvOsMutexCreate(&s_Pmu.hMutex));
        NV_CHECK_ERROR_CLEANUP(NvOsSemaphoreCreate(&s_Pmu.hSemaphore, 0));

        if (NvOdmQueryGetPmuProperty(&PmuProperty) && PmuProperty.IrqConnected)
        {
            if (hRmDevice->ChipId.Id >= 0x20)
                NvRmPrivAp20SetPmuIrqPolarity(
                    hRmDevice, PmuProperty.IrqPolarity);
            else
                NV_ASSERT(PmuProperty.IrqPolarity ==
                          NvOdmInterruptPolarity_Low);
            {
                NvOsInterruptHandler hPmuIsr = PmuIsr;
                NvU32 PmuExtIrq = NvRmGetIrqForLogicalInterrupt(
                    hRmDevice, NVRM_MODULE_ID(NvRmPrivModuleID_PmuExt, 0), 0);
                NV_CHECK_ERROR_CLEANUP(NvRmInterruptRegister(hRmDevice, 1,
                    &PmuExtIrq, &hPmuIsr, &s_Pmu, &s_Pmu.hInterrupt, NV_FALSE));
            }
        }

        if(!NvOdmPmuDeviceOpen(&s_Pmu.hOdmPmu))
        {
            e = NvError_NotInitialized;
            goto fail;
        }
        NV_CHECK_ERROR_CLEANUP(NvOsThreadCreate(PmuThread, &s_Pmu, &s_Pmu.hThread));
        NvRmPrivIoPowerControlInit(hRmDevice);
        NvRmPrivCoreVoltageInit(hRmDevice);
    }
    return NvSuccess;

fail:
    NvRmPrivPmuDeinit(hRmDevice);
    return e;
}
NvError NvEcPowerSuspend(
    NvEcPowerState PowerState)
{
    NvError e = NvSuccess;
    NvEcPrivState   *ec = &g_ec;

    NvOsMutexLock(ec->mutex);
    
    // Call transport's power off only if it's in ON state
    if (ec->powerState == NV_TRUE)
    {
        // Perform pre-suspend EC operations
        NV_CHECK_ERROR_CLEANUP( NvEcPrivPowerSuspendHook(ec->hEc, PowerState) );
        // Enter low power state
        ec->EnterLowPowerState = NV_TRUE;
        // Signal priv thread to get ready for power suspend.
        NvOsSemaphoreSignal(ec->sema);
        // Wait till priv thread is ready for power suspend.
        NvOsSemaphoreWait(ec->LowPowerEntrySema);
        e = NvEcTransportPowerSuspend(ec->transport);
        ec->powerState = NV_FALSE;
    }

fail:
    NvOsMutexUnlock(ec->mutex);
    return e;
}
NvError NvEcPowerResume(void)
{
    NvError e = NvSuccess;
    NvEcPrivState   *ec = &g_ec;
    
    NvOsMutexLock(ec->mutex);

    // Call transport's power on if it's OFF state
    if (ec->powerState == NV_FALSE)
    {
NvOsDebugPrintf("ec_rs NvEcPowerResume 1\n");
        NV_CHECK_ERROR_CLEANUP( NvEcTransportPowerResume(ec->transport) );

        ec->powerState = NV_TRUE;
        ec->EnterLowPowerState = NV_FALSE;
        // Signal priv thread to get out of power suspend.
        NvOsSemaphoreSignal(ec->LowPowerExitSema);
        // Perform post-resume EC operations
        NvEcPrivPowerResumeHook(ec->hEc);
NvOsDebugPrintf("ec_rs NvEcPowerResume 2\n");
    }

fail:
    NvOsMutexUnlock(ec->mutex);
    return e;
}
示例#4
0
NvError NvRmPrivPowerInit(NvRmDeviceHandle hRmDeviceHandle)
{
    NvU32 i;
    NvError e;

    NV_ASSERT(hRmDeviceHandle);

    // Initialize registry
    s_PowerRegistry.pPowerClients = NULL;
    s_PowerRegistry.AvailableEntries = 0;
    s_PowerRegistry.UsedIndexRange = 0;

    // Clear busy head pointers as well as starvation and power plane
    // reference counts. Aalthough power plane references are cleared
    // here, the combined power state is not updated - it will kept as
    // set by the boot code, until the 1st client requests power.
    NvOsMemset(s_BusyReqHeads, 0, sizeof(s_BusyReqHeads));
    NvOsMemset(s_StarveOnRefCounts, 0, sizeof(s_StarveOnRefCounts));
    NvOsMemset(s_PowerOnRefCounts, 0, sizeof(s_PowerOnRefCounts));

    // Initialize busy requests pool
    NvOsMemset(s_BusyReqPool, 0, sizeof(s_BusyReqPool));
    for (i = 0; i < NVRM_BUSYREQ_POOL_SIZE; i++)
        s_pFreeBusyReqPool[i] = &s_BusyReqPool[i];
    s_FreeBusyReqPoolSize = NVRM_BUSYREQ_POOL_SIZE;

    // Create the RM registry mutex and initialize RM/OAL interface
    s_hPowerClientMutex = NULL;
    NV_CHECK_ERROR_CLEANUP(NvOsMutexCreate(&s_hPowerClientMutex));
    NV_CHECK_ERROR_CLEANUP(NvRmPrivOalIntfInit(hRmDeviceHandle));

    // Initialize power group control, and power gate SoC partitions
    NvRmPrivPowerGroupControlInit(hRmDeviceHandle);
    return NvSuccess;

fail:
    NvRmPrivOalIntfDeinit(hRmDeviceHandle);
    NvOsMutexDestroy(s_hPowerClientMutex);
    s_hPowerClientMutex = NULL;
    return e;
}
NvError
NvEcOpen(NvEcHandle *phEc,
         NvU32 InstanceId)
{
    NvEc            *hEc = NULL;
    NvU32           i;
    NvEcPrivState   *ec = &g_ec;
    NvOsMutexHandle mutex = NULL;
    NvError         e = NvSuccess;

    NV_ASSERT( phEc );

    if ( NULL == ec->mutex )
    {
        e = NvOsMutexCreate(&mutex);
        if (NvSuccess != e)
            return e;
        if (0 != NvOsAtomicCompareExchange32((NvS32*)&ec->mutex, 0,
                                                        (NvS32)mutex) )
            NvOsMutexDestroy( mutex );
    }

    NvOsMutexLock(ec->mutex);

    if ( !s_refcount )
    {
        mutex = ec->mutex;
        NvOsMemset( ec, 0, sizeof(NvEcPrivState) );
        ec->mutex = mutex;
        
        NV_CHECK_ERROR_CLEANUP( NvOsMutexCreate( &ec->requestMutex ));
        NV_CHECK_ERROR_CLEANUP( NvOsMutexCreate( &ec->responseMutex ));
        NV_CHECK_ERROR_CLEANUP( NvOsMutexCreate( &ec->eventMutex ));
        
        NV_CHECK_ERROR_CLEANUP( NvOsSemaphoreCreate( &ec->sema, 0));
        NV_CHECK_ERROR_CLEANUP( NvOsSemaphoreCreate( &ec->LowPowerEntrySema, 0));
        NV_CHECK_ERROR_CLEANUP( NvOsSemaphoreCreate( &ec->LowPowerExitSema, 0));
        
        NV_CHECK_ERROR_CLEANUP( NvEcTransportOpen( &ec->transport, InstanceId,
            ec->sema, 0 ) );
    }

    // Set this flag as TRUE to indicate power is enabled
    ec->powerState = NV_TRUE;

    // create private handle for internal communications between NvEc driver
    // and EC
    if ( !s_refcount )
    {
        ec->hEc = NvOsAlloc( sizeof(NvEc) );
        if ( NULL == ec->hEc )
            goto clean;
        
        // reserve the zero tag for internal use by the nvec driver; this ensures
        // that the driver always has a requestor tag available and can therefore
        // always talk to the EC
        ec->tagAllocated[0] = NV_TRUE;
        ec->hEc->ec = ec;
        ec->hEc->tag = 0;

        NV_CHECK_ERROR_CLEANUP(NvOsSemaphoreCreate(&ec->hPingSema, 0));

        // perform startup operations before mutex is unlocked
        NV_CHECK_ERROR_CLEANUP( NvEcPrivInitHook(ec->hEc) );

        // start thread to send "pings" - no-op commands to keep EC "alive"
        NV_CHECK_ERROR_CLEANUP(NvOsThreadCreate(
            (NvOsThreadFunction)NvEcPrivPingThread, ec, &ec->hPingThread));
    }

    hEc = NvOsAlloc( sizeof(NvEc) );
    if ( NULL == hEc )
        goto clean;

    NvOsMemset(hEc, 0x00, sizeof(NvEc));

    hEc->ec = ec;

    hEc->tag = NVEC_REQUESTOR_TAG_INVALID;
    for ( i = 0; i < NVEC_MAX_REQUESTOR_TAG; i++ )
    {
        if ( !ec->tagAllocated[i] )
        {
            ec->tagAllocated[i] = NV_TRUE;
            hEc->tag = i;
            break;
        }
    }
    if ( NVEC_REQUESTOR_TAG_INVALID == hEc->tag )
        goto clean;      // run out of tag, clean it up!

    *phEc = hEc;
    s_refcount++;

    NvOsMutexUnlock( ec->mutex );

    ec->IsEcActive = NV_FALSE;

    return NvSuccess;

clean:
    NvOsFree( hEc );
    NvOsMutexUnlock( ec->mutex );

    return NvError_InsufficientMemory;

fail:
    if (!s_refcount)
    {
        ec->exitPingThread = NV_TRUE;
        if (ec->hPingSema)
            NvOsSemaphoreSignal( ec->hPingSema );
        NvOsThreadJoin( ec->hPingThread );
        NvOsSemaphoreDestroy(ec->hPingSema);
        ec->exitThread = NV_TRUE;
        if (ec->sema)
            NvOsSemaphoreSignal( ec->sema );
        NvOsThreadJoin( ec->thread );
        NvOsFree( ec->hEc );
        if ( ec->transport )
            NvEcTransportClose( ec->transport );
        NvOsMutexDestroy( ec->requestMutex );
        NvOsMutexDestroy( ec->responseMutex );
        NvOsMutexDestroy( ec->eventMutex );
        NvOsSemaphoreDestroy( ec->sema );
        NvOsSemaphoreDestroy( ec->LowPowerEntrySema );
        NvOsSemaphoreDestroy( ec->LowPowerExitSema );
        if ( ec->mutex )
        {
            NvOsMutexUnlock( ec->mutex );
            // Destroying of this mutex here is not safe, if another thread is
            // waiting on this mutex, it can cause issues.  We shold have
            // serialized Init/DeInit calls for creating and destroying this mutex.
            NvOsMutexDestroy( ec->mutex );
            NvOsMemset( ec, 0, sizeof(NvEcPrivState) );
            ec->mutex = NULL;
        }
    }
    return NvError_NotInitialized;
}
NvError
NvEcSendRequest(
    NvEcHandle hEc,
    NvEcRequest *pRequest,
    NvEcResponse *pResponse,
    NvU32 RequestSize,
    NvU32 ResponseSize)
{
    NvEcPrivState       *ec;
    NvError             e = NvSuccess;
    NvEcRequestNode     *requestNode = NULL;
    NvEcResponseNode    *responseNode = NULL;
    NvOsSemaphoreHandle requestSema = NULL;
    NvOsSemaphoreHandle responseSema = NULL;
    
    NV_ASSERT( pRequest );
    NV_ASSERT( hEc );
    if ( (RequestSize > sizeof(NvEcRequest)) || 
         (ResponseSize > sizeof(NvEcResponse)) )
        return NvError_InvalidSize;
    
    ec = hEc->ec;
    requestNode = NvOsAlloc(sizeof(NvEcRequestNode));
    if ( NULL == requestNode )
    {
        e = NvError_InsufficientMemory;
        goto fail;
    }
    NV_CHECK_ERROR_CLEANUP( NvOsSemaphoreCreate( &requestSema, 0 ) );
    
    if ( pResponse )
    {
        responseNode = NvOsAlloc(sizeof(NvEcResponseNode));
        if ( NULL == responseNode )
        {
            e = NvError_InsufficientMemory;
            goto fail;
        }
        NV_CHECK_ERROR_CLEANUP( NvOsSemaphoreCreate( &responseSema, 0 ) );
    }

    ec->IsEcActive = NV_TRUE;

    // request end-queue.  Timeout set to infinite until request sent.
    NvOsMemset( requestNode, 0, sizeof(NvEcRequestNode) );
    pRequest->RequestorTag = hEc->tag;      // assigned tag here
    DISP_MESSAGE(("NvEcSendRequest:pRequest->RequestorTag=0x%x\n", pRequest->RequestorTag));
    NvOsMemcpy(&requestNode->request, pRequest, RequestSize);
    requestNode->tag = hEc->tag;
    DISP_MESSAGE(("NvEcSendRequest:requestNode->tag=0x%x\n", requestNode->tag));
    requestNode->sema = requestSema;
    requestNode->timeout = NV_WAIT_INFINITE;
    requestNode->completed = NV_FALSE;
    requestNode->size = RequestSize;
    
    NvOsMutexLock( ec->requestMutex );
    NVEC_ENQ( ec->request, requestNode );
    DISP_MESSAGE(("\r\nSendReq ec->requestBegin=0x%x", ec->requestBegin));
    NvOsMutexUnlock( ec->requestMutex );
    
    // response en-queue.  Timeout set to infinite until request completes.
    if ( pResponse )
    {
        NvOsMemset( responseNode, 0, sizeof(NvEcResponseNode) );
        requestNode->responseNode = responseNode;   // association between
        responseNode->requestNode = requestNode;    //   request & response
        responseNode->sema = responseSema;
        responseNode->timeout = NV_WAIT_INFINITE;
        responseNode->tag = hEc->tag;
        DISP_MESSAGE(("NvEcSendRequest:responseNode->tag=0x%x\n", responseNode->tag));
        responseNode->size = ResponseSize;
        NvOsMutexLock( ec->responseMutex );
        NVEC_ENQ( ec->response, responseNode );
        DISP_MESSAGE(("\r\nSendReq ec->responseBegin=0x%x", ec->responseBegin));
        NvOsMutexUnlock( ec->responseMutex );
    }

    NvOsMutexLock( ec->mutex );
    if ( !ec->thread )
        NvEcPrivThreadCreate( ec );
    NvOsMutexUnlock( ec->mutex );

    // Trigger EcPrivThread
    NvOsSemaphoreSignal( ec->sema );
    DISP_MESSAGE(("\r\nSendReq requestNode=0x%x, requestNode->responseNode=0x%x",
        requestNode, requestNode->responseNode));
    // Wait on Request returns
    NvOsSemaphoreWait( requestSema );
    DISP_MESSAGE(("\r\nSendReq Out of req sema"));

    e = requestNode->status;
    if ( NvSuccess != e )
    {
        NvEcResponseNode    *t = NULL, *p = NULL;

        // de-queue responseNode too !!!!
        NvOsMutexLock( ec->responseMutex );
        NVEC_REMOVE_FROM_Q( ec->response, responseNode, t, p );
        DISP_MESSAGE(("\r\nSendReq responseBegin=0x%x", ec->responseBegin));
        NvOsMutexUnlock( ec->responseMutex );
        goto fail;
    }

    if ( pResponse )
    {
        // Wait on Response returns
        NvOsSemaphoreWait( responseSema );
        DISP_MESSAGE(("\r\nSendReq Out of resp sema"));
        NV_CHECK_ERROR_CLEANUP( responseNode->status );
        NvOsMemcpy(pResponse, &responseNode->response, ResponseSize);
    }
    // if successful, nodes should be de-queue already but not freed yet

fail:
    NvOsSemaphoreDestroy( requestSema );
    NvOsSemaphoreDestroy( responseSema );
    DISP_MESSAGE(("\r\nSendReq Freeing requestNode=0x%x, responseNode=0x%x", 
        requestNode, responseNode));
    NvOsFree( requestNode );
    NvOsFree( responseNode );
    return e;
}
示例#7
0
/* platform driver interface */
static int __devinit tegra_otg_probe(struct platform_device *pdev)
{
	int err = 0;
	struct resource *res;
	int instance = pdev->id;
	NvError e;
	struct tegra_otg_platform_data *pdata;

	sg_tegra_otg = kzalloc(sizeof(struct tegra_otg_data), GFP_KERNEL);
	if (!sg_tegra_otg)
		return -ENOMEM;

	spin_lock_init(&sg_tegra_otg->lock);
	platform_set_drvdata(pdev, sg_tegra_otg);

	NV_CHECK_ERROR_CLEANUP(
		NvDdkUsbPhyOpen(s_hRmGlobal, instance, &sg_tegra_otg->usb_phy)
	);
	NV_CHECK_ERROR_CLEANUP(
		NvDdkUsbPhyPowerUp(sg_tegra_otg->usb_phy, NV_FALSE, 0)
	);
	sg_tegra_otg->instance = pdev->id;
	sg_tegra_otg->dev = &pdev->dev;
	sg_tegra_otg->otg.label = driver_name;
	sg_tegra_otg->otg.state = OTG_STATE_UNDEFINED;
	sg_tegra_otg->otg.set_peripheral = tegra_otg_set_peripheral;
	sg_tegra_otg->otg.set_host = tegra_otg_set_host;
	sg_tegra_otg->otg.set_power = tegra_otg_set_power;
	sg_tegra_otg->otg.set_suspend = tegra_otg_set_suspend;
	pdata = sg_tegra_otg->dev->platform_data;
	if(pdata->usb_property->IdPinDetectionType == NvOdmUsbIdPinType_CableId)
		sg_tegra_otg->id_connected = 1;
	if(pdata->usb_property->UseInternalPhyWakeup)
		sg_tegra_otg->vbus_connected = 1;

	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
	if (!res) {
		err = -ENXIO;
		goto err_irq;
	}

	sg_tegra_otg->regs = ioremap(res->start, resource_size(res));
	if (!sg_tegra_otg->regs) {
		err = -ENOMEM;
		goto err_irq;
	}

	sg_tegra_otg->irq = platform_get_irq(pdev, 0);
	if (!sg_tegra_otg->irq) {
		err = -ENODEV;
		goto err_irq;
	}

	err = request_irq(sg_tegra_otg->irq, tegra_otg_irq, IRQF_SHARED,
			driver_name, pdev);
	if (err) {
		printk("cannot request irq %d err %d\n",
				sg_tegra_otg->irq, err);
		goto err_mem_map;
	}

	/* only active when a gadget is registered */
	err = otg_set_transceiver(&sg_tegra_otg->otg);
	if (err) {
		dev_err(&pdev->dev, "can't register transceiver, err: %d\n",
			err);
		goto err_otg;
	}

	NvDdkUsbPhyPowerDown(sg_tegra_otg->usb_phy, NV_FALSE, 0);

	return 0;

err_otg:
	free_irq(sg_tegra_otg->irq, &pdev->dev);
err_mem_map:
	iounmap(sg_tegra_otg->regs);
err_irq:
	NvDdkUsbPhyClose(sg_tegra_otg->usb_phy);
fail:
	platform_set_drvdata(pdev, NULL);
	kfree(sg_tegra_otg);
	return err;
}
NvError
NvDdkUsbPhyPowerDown(
    NvDdkUsbPhyHandle hUsbPhy,
    NvBool IsHostMode,
    NvBool IsDpd)
{
    NvError e = NvSuccess;
    NvDdkUsbPhyIoctl_VBusStatusOutputArgs VBusStatus;
    NvU32 TimeOut = USB_PHY_HW_TIMEOUT_US;

    NV_ASSERT(hUsbPhy);

    NvOsMutexLock(hUsbPhy->ThreadSafetyMutex);
    if (!hUsbPhy->IsPhyPoweredUp)
    {
        NvOsMutexUnlock(hUsbPhy->ThreadSafetyMutex);
        return e;
    }

    /* Allow saving register context for the USB host if it is a ULPI
       interface or if the lowest power state is LP1 */
    if (hUsbPhy->pProperty->UsbMode == NvOdmUsbModeType_Host)
    {
        hUsbPhy->SaveContext(hUsbPhy);
    }

    /* Turn on/off the vbus for host mode */
    hUsbPhy->IsHostMode = IsHostMode;
    if (IsHostMode)
    {
        UsbPrivEnableVbus(hUsbPhy, NV_FALSE);
        /* Wait till Vbus is turned off */
        do
        {
            NvOsWaitUS(1000);
            TimeOut -= 1000;
            e = hUsbPhy->Ioctl(hUsbPhy,
                    NvDdkUsbPhyIoctlType_VBusStatus,
                    NULL,
                    &VBusStatus);
        } while (VBusStatus.VBusDetected && TimeOut);
    }
    // Power down the USB Phy
    NV_CHECK_ERROR_CLEANUP(hUsbPhy->PowerDown(hUsbPhy));

    // On AP20 H-CLK should not be turned off
    // This is required to detect the sensor interrupts.
    // However, phy can be programmed to put in the low power mode
    if (!hUsbPhy->Caps.PhyRegInController)
    {
        // Disable the clock
        NV_CHECK_ERROR_CLEANUP(
            NvRmPowerModuleClockControl(hUsbPhy->hRmDevice,
              NVRM_MODULE_ID(NvRmModuleID_Usb2Otg, hUsbPhy->Instance),
              hUsbPhy->RmPowerClientId, NV_FALSE));
    }

    // Disable power
    NV_CHECK_ERROR_CLEANUP(
        NvRmPowerVoltageControl(hUsbPhy->hRmDevice,
          NVRM_MODULE_ID(NvRmModuleID_Usb2Otg, hUsbPhy->Instance),
          hUsbPhy->RmPowerClientId, NvRmVoltsOff, NvRmVoltsOff,
          NULL, 0, NULL));

    /* Turn off the USB busy hints */
    UsbPhyDfsBusyHint(hUsbPhy, NV_FALSE, NV_WAIT_INFINITE);

    if (hUsbPhy->TurnOffPowerRail)
    {
         NvOdmEnableUsbPhyPowerRail(NV_FALSE);
         NvOdmEnableOtgCircuitry(NV_FALSE);
    }

    hUsbPhy->IsPhyPoweredUp = NV_FALSE;

fail:

    NvOsMutexUnlock(hUsbPhy->ThreadSafetyMutex);
    return e;
}
NvError
NvDdkUsbPhyPowerUp(
    NvDdkUsbPhyHandle hUsbPhy,
    NvBool IsHostMode,
    NvBool IsDpd)
{
    NvError e = NvSuccess;

    NV_ASSERT(hUsbPhy);

    NvOsMutexLock(hUsbPhy->ThreadSafetyMutex);
    if (hUsbPhy->IsPhyPoweredUp)
    {
        NvOsMutexUnlock(hUsbPhy->ThreadSafetyMutex);
        return e;
    }

    if (hUsbPhy->TurnOffPowerRail)
    {
        NvOdmEnableUsbPhyPowerRail(NV_TRUE);
    }

    // Enable power for USB module
    NV_CHECK_ERROR_CLEANUP(
        NvRmPowerVoltageControl(hUsbPhy->hRmDevice,
          NVRM_MODULE_ID(NvRmModuleID_Usb2Otg, hUsbPhy->Instance),
          hUsbPhy->RmPowerClientId, NvRmVoltsUnspecified,
          NvRmVoltsUnspecified, NULL, 0, NULL));

    // On Ap20 We will not turn off the H-Clk so not required to turn on
    if (!hUsbPhy->Caps.PhyRegInController)
    {
        NV_CHECK_ERROR_CLEANUP(
            NvRmPowerModuleClockControl(hUsbPhy->hRmDevice,
              NVRM_MODULE_ID(NvRmModuleID_Usb2Otg, hUsbPhy->Instance),
              hUsbPhy->RmPowerClientId, NV_TRUE));
    }

    // Power up the Phy
    NV_CHECK_ERROR_CLEANUP(hUsbPhy->PowerUp(hUsbPhy));

    /* Allow restoring register context for the USB host if it is a ULPI
       interface or if the lowest power state is LP1 */
    if (hUsbPhy->pProperty->UsbMode == NvOdmUsbModeType_Host)
    {
        hUsbPhy->RestoreContext(hUsbPhy);
    }

    hUsbPhy->IsHostMode = IsHostMode;
    if (IsHostMode)
    {
        UsbPrivEnableVbus(hUsbPhy, NV_TRUE);
    }
    else
    {
        /* Turn on the USB busy hints */
        UsbPhyDfsBusyHint(hUsbPhy, NV_TRUE, NV_WAIT_INFINITE);
    }
    hUsbPhy->IsPhyPoweredUp = NV_TRUE;


fail:

    NvOsMutexUnlock(hUsbPhy->ThreadSafetyMutex);
    return e;
}
NvError
NvDdkUsbPhyOpen(
    NvRmDeviceHandle hRm,
    NvU32 Instance,
    NvDdkUsbPhyHandle *hUsbPhy)
{
    NvError e;
    NvU32 MaxInstances = 0;
    NvDdkUsbPhy *pUsbPhy = NULL;
    NvOsMutexHandle UsbPhyMutex = NULL;
    NvRmModuleInfo info[MAX_USB_INSTANCES];
    NvU32 j;

    NV_ASSERT(hRm);
    NV_ASSERT(hUsbPhy);
    NV_ASSERT(Instance < MAX_USB_INSTANCES);

    NV_CHECK_ERROR(NvRmModuleGetModuleInfo( hRm, NvRmModuleID_Usb2Otg, &MaxInstances, NULL ));
    if (MaxInstances > MAX_USB_INSTANCES)
    {
       // Ceil "instances" to MAX_USB_INSTANCES
       MaxInstances = MAX_USB_INSTANCES;
    }
    NV_CHECK_ERROR(NvRmModuleGetModuleInfo( hRm, NvRmModuleID_Usb2Otg, &MaxInstances, info ));
    for (j = 0; j < MaxInstances; j++)
    {
    // Check whether the requested instance is present
        if(info[j].Instance == Instance)
            break;
    }
    // No match found return
    if (j == MaxInstances)
    {
        return NvError_ModuleNotPresent;
    }

    if (!s_UsbPhyMutex)
    {
        e = NvOsMutexCreate(&UsbPhyMutex);
        if (e!=NvSuccess)
            return e;

        if (NvOsAtomicCompareExchange32(
                (NvS32*)&s_UsbPhyMutex, 0, (NvS32)UsbPhyMutex)!=0)
        {
            NvOsMutexDestroy(UsbPhyMutex);
        }
    }

    NvOsMutexLock(s_UsbPhyMutex);
    if (!s_pUsbPhy)
    {
        s_pUsbPhy = NvOsAlloc(MaxInstances * sizeof(NvDdkUsbPhy));
        if (s_pUsbPhy)
            NvOsMemset(s_pUsbPhy, 0, MaxInstances * sizeof(NvDdkUsbPhy));
    }
    NvOsMutexUnlock(s_UsbPhyMutex);

    if (!s_pUsbPhy)
        return NvError_InsufficientMemory;

    NvOsMutexLock(s_UsbPhyMutex);
    if (!s_pUtmiPadConfig)
    {
        s_pUtmiPadConfig = NvOsAlloc(sizeof(NvDdkUsbPhyUtmiPadConfig));
        if (s_pUtmiPadConfig)
        {
            NvRmPhysAddr PhyAddr;

            NvOsMemset(s_pUtmiPadConfig, 0, sizeof(NvDdkUsbPhyUtmiPadConfig));
            NvRmModuleGetBaseAddress(
                hRm, 
                NVRM_MODULE_ID(NvRmModuleID_Usb2Otg, 0),
                &PhyAddr, &s_pUtmiPadConfig->BankSize);

            NV_CHECK_ERROR_CLEANUP(
                NvRmPhysicalMemMap(
                    PhyAddr, s_pUtmiPadConfig->BankSize, NVOS_MEM_READ_WRITE,
                    NvOsMemAttribute_Uncached, (void **)&s_pUtmiPadConfig->pVirAdr));
        }
    }
    NvOsMutexUnlock(s_UsbPhyMutex);

    if (!s_pUtmiPadConfig)
        return NvError_InsufficientMemory;

    pUsbPhy = &s_pUsbPhy[Instance];

    NvOsMutexLock(s_UsbPhyMutex);
    if (!pUsbPhy->RefCount)
    {
        NvRmPhysAddr PhysAddr;
        NvOsMutexHandle ThreadSafetyMutex = NULL;

        NvOsMemset(pUsbPhy, 0, sizeof(NvDdkUsbPhy));
        pUsbPhy->Instance = Instance;
        pUsbPhy->hRmDevice = hRm;
        pUsbPhy->RefCount = 1;
        pUsbPhy->IsPhyPoweredUp = NV_FALSE;
        pUsbPhy->pUtmiPadConfig = s_pUtmiPadConfig;
        pUsbPhy->pProperty = NvOdmQueryGetUsbProperty(
                                    NvOdmIoModule_Usb, pUsbPhy->Instance);
        pUsbPhy->TurnOffPowerRail = UsbPhyTurnOffPowerRail(MaxInstances);

        NV_CHECK_ERROR_CLEANUP(NvOsMutexCreate(&ThreadSafetyMutex));
        if (NvOsAtomicCompareExchange32(
                (NvS32*)&pUsbPhy->ThreadSafetyMutex, 0,
                (NvS32)ThreadSafetyMutex)!=0)
        {
            NvOsMutexDestroy(ThreadSafetyMutex);
        }

        NvRmModuleGetBaseAddress(
            pUsbPhy->hRmDevice,
            NVRM_MODULE_ID(NvRmModuleID_Usb2Otg, pUsbPhy->Instance),
            &PhysAddr, &pUsbPhy->UsbBankSize);

        NV_CHECK_ERROR_CLEANUP(
            NvRmPhysicalMemMap(
                PhysAddr, pUsbPhy->UsbBankSize, NVOS_MEM_READ_WRITE,
                NvOsMemAttribute_Uncached, (void **)&pUsbPhy->UsbVirAdr));

        NvRmModuleGetBaseAddress(
            pUsbPhy->hRmDevice,
            NVRM_MODULE_ID(NvRmModuleID_Misc, 0),
            &PhysAddr, &pUsbPhy->MiscBankSize);

        NV_CHECK_ERROR_CLEANUP(
            NvRmPhysicalMemMap(
                PhysAddr, pUsbPhy->MiscBankSize, NVOS_MEM_READ_WRITE,
                NvOsMemAttribute_Uncached, (void **)&pUsbPhy->MiscVirAdr));

        if ( ( pUsbPhy->pProperty->UsbInterfaceType ==
               NvOdmUsbInterfaceType_UlpiNullPhy) ||
             ( pUsbPhy->pProperty->UsbInterfaceType ==
               NvOdmUsbInterfaceType_UlpiExternalPhy))
        {
            if (NvRmSetModuleTristate(
                    pUsbPhy->hRmDevice,
                    NVRM_MODULE_ID(NvRmModuleID_Usb2Otg, pUsbPhy->Instance),
                    NV_FALSE) != NvSuccess )
               return NvError_NotSupported;
        }

        // Register with Power Manager
        NV_CHECK_ERROR_CLEANUP(
            NvOsSemaphoreCreate(&pUsbPhy->hPwrEventSem, 0));

        pUsbPhy->RmPowerClientId = NVRM_POWER_CLIENT_TAG('U','S','B','p');
        NV_CHECK_ERROR_CLEANUP(
            NvRmPowerRegister(pUsbPhy->hRmDevice,
            pUsbPhy->hPwrEventSem, &pUsbPhy->RmPowerClientId));

        // Open the H/W interface
        UsbPhyOpenHwInterface(pUsbPhy);

        // Initialize the USB Phy
        NV_CHECK_ERROR_CLEANUP(UsbPhyInitialize(pUsbPhy));
    }
    else
    {
        pUsbPhy->RefCount++;
    }

    *hUsbPhy = pUsbPhy;
    NvOsMutexUnlock(s_UsbPhyMutex);

    return NvSuccess;

fail:

    NvDdkUsbPhyClose(pUsbPhy);
    NvOsMutexUnlock(s_UsbPhyMutex);
    return e;
}
static NvError
UsbPhyInitialize(
    NvDdkUsbPhyHandle hUsbPhy)
{
    NvError e = NvSuccess;
    NvRmFreqKHz CurrentFreq = 0;
    NvRmFreqKHz PrefFreqList[3] = {12000, 60000, NvRmFreqUnspecified};

    // NvOsDebugPrintf("UsbPhyInitialize::VOLTAGE ON, instance %d\n",
    //                hUsbPhy->Instance);
    // request power
    NV_CHECK_ERROR_CLEANUP(
        NvRmPowerVoltageControl(hUsbPhy->hRmDevice,
            NVRM_MODULE_ID(NvRmModuleID_Usb2Otg, hUsbPhy->Instance),
            hUsbPhy->RmPowerClientId, NvRmVoltsUnspecified,
            NvRmVoltsUnspecified, NULL, 0, NULL));

    // Enable clock to the USB controller and Phy
    NV_CHECK_ERROR_CLEANUP(
        NvRmPowerModuleClockControl(hUsbPhy->hRmDevice,
            NVRM_MODULE_ID(NvRmModuleID_Usb2Otg, hUsbPhy->Instance),
                hUsbPhy->RmPowerClientId, NV_TRUE));

    if (!hUsbPhy->Caps.PhyRegInController)
    {
        if (hUsbPhy->pProperty->UsbInterfaceType == NvOdmUsbInterfaceType_UlpiNullPhy)
        {
            /* Request for 60MHz clk */
            NV_CHECK_ERROR_CLEANUP(
                NvRmPowerModuleClockConfig(hUsbPhy->hRmDevice,
                    NVRM_MODULE_ID(NvRmModuleID_Usb2Otg, hUsbPhy->Instance),
                    hUsbPhy->RmPowerClientId, PrefFreqList[1],
                    PrefFreqList[1], &PrefFreqList[1], 1, &CurrentFreq, 0));
        }
        else
        {
            /* Request for 12 MHz clk */
            NV_CHECK_ERROR_CLEANUP(
                NvRmPowerModuleClockConfig(hUsbPhy->hRmDevice,
                    NVRM_MODULE_ID(NvRmModuleID_Usb2Otg, hUsbPhy->Instance),
                    hUsbPhy->RmPowerClientId, PrefFreqList[0],
                    PrefFreqList[0], &PrefFreqList[0], 1, &CurrentFreq, 0));
        }
    }
    // else
    {
        /* No need for actual clock configuration - all USB PLL frequencies
         are available concurrently in this case. */
    }

    // Reset controller
    NvRmModuleReset(hUsbPhy->hRmDevice,
        NVRM_MODULE_ID(NvRmModuleID_Usb2Otg, hUsbPhy->Instance));


    // On AP20 H-CLK should not be turned off
    // This is required to detect the sensor interrupts.
    // However, phy can be programmed to put in the low power mode
    if (!hUsbPhy->Caps.PhyRegInController)
    {
        // Disable the clock
        NV_CHECK_ERROR_CLEANUP(
            NvRmPowerModuleClockControl(hUsbPhy->hRmDevice,
              NVRM_MODULE_ID(NvRmModuleID_Usb2Otg, hUsbPhy->Instance),
              hUsbPhy->RmPowerClientId, NV_FALSE));
    }

    // Disable power
    NV_CHECK_ERROR_CLEANUP(
        NvRmPowerVoltageControl(hUsbPhy->hRmDevice,
          NVRM_MODULE_ID(NvRmModuleID_Usb2Otg, hUsbPhy->Instance),
          hUsbPhy->RmPowerClientId, NvRmVoltsOff, NvRmVoltsOff,
          NULL, 0, NULL));

    // if we are not turning off the power rail during power up and down
    // then turn on only once during the initalization.
    if (!hUsbPhy->TurnOffPowerRail)
    {
        NvOdmEnableUsbPhyPowerRail(NV_TRUE);
    }

fail:

    return e;
}
static NvError
UsbPhyDfsBusyHint(
    NvDdkUsbPhyHandle hUsbPhy,
    NvBool DfsOn,
    NvU32 BoostDurationMs)
{
    NvRmDfsBusyHint pUsbHintOn[] =
    {
        { NvRmDfsClockId_Emc, NV_WAIT_INFINITE, USB_HW_MIN_SYSTEM_FREQ_KH, NV_TRUE },
        { NvRmDfsClockId_Ahb, NV_WAIT_INFINITE, USB_HW_MIN_SYSTEM_FREQ_KH, NV_TRUE },
        { NvRmDfsClockId_Cpu, NV_WAIT_INFINITE, USB_HW_MIN_CPU_FREQ_KH, NV_TRUE }
    };
    NvRmDfsBusyHint pUsbHintOff[] =
    {
        { NvRmDfsClockId_Emc, 0, 0, NV_TRUE },
        { NvRmDfsClockId_Ahb, 0, 0, NV_TRUE },
        { NvRmDfsClockId_Cpu, 0, 0, NV_TRUE }
    };
    NvError e = NvSuccess;
    NvU32 NumHints;

    if (hUsbPhy->IsHostMode)
    {
        // Do not enable busy hints for cpu clock in host mode
        NumHints = NV_ARRAY_SIZE(pUsbHintOn) - 1;
    }
    else
    {
        NumHints = NV_ARRAY_SIZE(pUsbHintOn);
    }

    pUsbHintOn[0].BoostDurationMs = BoostDurationMs;
    pUsbHintOn[1].BoostDurationMs = BoostDurationMs;
    pUsbHintOn[2].BoostDurationMs = BoostDurationMs;

    if (DfsOn)
    {
        if (hUsbPhy->Caps.PhyRegInController)
        {
            // Indicate USB controller is active
            NvRmFreqKHz PrefFreq = NvRmPowerModuleGetMaxFrequency(
                hUsbPhy->hRmDevice,
                NVRM_MODULE_ID(NvRmModuleID_Usb2Otg, hUsbPhy->Instance));

            NV_CHECK_ERROR_CLEANUP(
                NvRmPowerModuleClockConfig(hUsbPhy->hRmDevice,
                    NVRM_MODULE_ID(NvRmModuleID_Usb2Otg, hUsbPhy->Instance),
                    hUsbPhy->RmPowerClientId, PrefFreq, PrefFreq, &PrefFreq,
                    1, NULL, 0));
        }
        return NvRmPowerBusyHintMulti(hUsbPhy->hRmDevice,
                                      hUsbPhy->RmPowerClientId,
                                      pUsbHintOn,
                                      NumHints,
                                      NvRmDfsBusyHintSyncMode_Async);
    }
    else
    {
        if (hUsbPhy->Caps.PhyRegInController)
        {
            // Indicate USB controller is idle
            NvRmFreqKHz PrefFreq = USBC_IDLE_KHZ;

            NV_CHECK_ERROR_CLEANUP(
                NvRmPowerModuleClockConfig(hUsbPhy->hRmDevice,
                    NVRM_MODULE_ID(NvRmModuleID_Usb2Otg, hUsbPhy->Instance),
                    hUsbPhy->RmPowerClientId, PrefFreq, PrefFreq, &PrefFreq,
                    1, NULL, 0));
        }
        return NvRmPowerBusyHintMulti(hUsbPhy->hRmDevice,
                                      hUsbPhy->RmPowerClientId,
                                      pUsbHintOff,
                                      NumHints,
                                      NvRmDfsBusyHintSyncMode_Async);
    }

fail:
    return e;
}