示例#1
0
void NvRmPrivPowerDeinit(NvRmDeviceHandle hRmDeviceHandle)
{
    NvU32 i;
    NvRmPowerRegistry* pRegistry = &s_PowerRegistry;

    NV_ASSERT(hRmDeviceHandle);

    // TODO: expand after clock API is completed

    // Free busy hint lists for DFS clock domains
    for (i = 0; i < NvRmDfsClockId_Num; i++)
    {
        while (s_BusyReqHeads[i].pNext != NULL)
        {
            BusyHintReq* pBusyHintReq = s_BusyReqHeads[i].pNext;
            s_BusyReqHeads[i].pNext = pBusyHintReq->pNext;
            BusyReqFree(pBusyHintReq);
        }
    }
    // Free RM power registry memory
    for (i = 0; i < pRegistry->UsedIndexRange; i++)
    {
        FreePowerClient(pRegistry->pPowerClients[i]);
    }
    NvOsFree(pRegistry->pPowerClients);
    pRegistry->pPowerClients = NULL;
    pRegistry->AvailableEntries = 0;
    pRegistry->UsedIndexRange = 0;

    // Destroy RM registry mutex and free RM/OAL interface resources
    NvRmPrivOalIntfDeinit(hRmDeviceHandle);
    NvOsMutexDestroy(s_hPowerClientMutex);
    s_hPowerClientMutex = NULL;
}
示例#2
0
void NvRmPrivDeInitKeyList(NvRmDeviceHandle hRm)
{
    NvOsMutexLock(s_Mutex);
    FreeKeyList();
    s_pKeyList = NULL;
    NvOsMutexUnlock(s_Mutex);
    NvOsMutexDestroy(s_Mutex);
}
void NvRmPrivPmuDeinit(NvRmDeviceHandle hRmDevice)
{
    if (s_PmuSupportedEnv == NV_FALSE)
        return;

    PmuThreadTerminate(&s_Pmu);
    NvOdmPmuDeviceClose(s_Pmu.hOdmPmu);
    NvRmInterruptUnregister(hRmDevice, s_Pmu.hInterrupt);
    NvOsSemaphoreDestroy(s_Pmu.hSemaphore);
    NvOsMutexDestroy(s_Pmu.hMutex);

    NvOsMemset(&s_Pmu, 0, sizeof(NvRmPmu));
    s_PmuSupportedEnv = NV_FALSE;
}
示例#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;
}
示例#5
0
static void nvec_battery_remove(struct nvec_device *pdev)
{
	unsigned int i = 0;

	if (batt_dev) {
		batt_dev->exitThread = NV_TRUE;
		if (batt_dev->hOdmSemaphore) {
			NvOsSemaphoreSignal(batt_dev->hOdmSemaphore);
			NvOsSemaphoreDestroy(batt_dev->hOdmSemaphore);
			batt_dev->hOdmSemaphore = NULL;
		}

		if (batt_dev->hBattEventThread) {
			NvOsThreadJoin(batt_dev->hBattEventThread);
		}

	    if (batt_dev->hBattEventMutex) {    
		    NvOsMutexDestroy(batt_dev->hBattEventMutex);
		    batt_dev->hBattEventMutex = NULL;
	    }

		if (batt_dev->hOdmBattDev) {
			device_remove_file(&pdev->dev, &tegra_battery_attr);

			NvOdmBatteryDeviceClose(batt_dev->hOdmBattDev);
			batt_dev->hOdmBattDev = NULL;

			for (i = 0; i < ARRAY_SIZE(tegra_power_supplies); i++) {
				power_supply_unregister(&tegra_power_supplies[i]);
			}
		}

		kfree(batt_dev);
		batt_dev = NULL;

	}
}
void
NvEcClose(NvEcHandle hEc)
{
    NvEcPrivState   *ec;
    NvBool          destroy = NV_FALSE;

    if ( NULL == hEc )
        return;

    NV_ASSERT( s_refcount );

    ec = hEc->ec;
    NvOsMutexLock( ec->mutex );

    // FIXME: handle client still with outstanding event types
    if ( !--s_refcount )
    {
        NvEcPrivDeinitHook(ec->hEc);

        NV_ASSERT( NULL == ec->eventReg[hEc->tag].regBegin &&
                    NULL == ec->eventReg[hEc->tag].regEnd );
        NV_ASSERT( NULL == ec->requestBegin && NULL == ec->requestEnd );
        NV_ASSERT( NULL == ec->responseBegin && NULL == ec->responseEnd );

        ec->exitPingThread = NV_TRUE;
        NvOsSemaphoreSignal( ec->hPingSema );
        NvOsThreadJoin( ec->hPingThread );
        ec->exitThread = NV_TRUE;
        NvOsSemaphoreSignal( ec->sema );
        NvOsThreadJoin( ec->thread );

        NvEcTransportClose( ec->transport );
        NvOsMutexDestroy( ec->requestMutex );
        NvOsMutexDestroy( ec->responseMutex );
        NvOsMutexDestroy( ec->eventMutex );
        NvOsSemaphoreDestroy( ec->sema );
        NvOsSemaphoreDestroy( ec->hPingSema );
        NvOsSemaphoreDestroy( ec->LowPowerEntrySema );
        NvOsSemaphoreDestroy( ec->LowPowerExitSema );
        destroy = NV_TRUE;

        NvOsFree( ec->eventNodes );
        NvOsFree( ec->hEc );
    }

    // Set this flag as FALSE to indicate power is disabled
    ec->powerState = NV_FALSE;

    NV_ASSERT( hEc->tag < NVEC_MAX_REQUESTOR_TAG );
    ec->tagAllocated[hEc->tag] = NV_FALSE;      // to be recycled

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

    if ( destroy )
    {
        NvOsMutexDestroy( ec->mutex );
        NvOsMemset( ec, 0, sizeof(NvEcPrivState) );
        ec->mutex = NULL;
    }
}
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;
}
示例#8
0
static int nvec_battery_probe(struct nvec_device *pdev)
{
	int i, rc;
	NvError ErrorStatus = NvSuccess;
	NvBool result = NV_FALSE;

	batt_dev = kzalloc(sizeof(struct tegra_battery_dev), GFP_KERNEL);
	if (!batt_dev) {
		pr_err("nvec_battery_probe:NOMEM\n");
		return -ENOMEM;
	}

	ErrorStatus = NvOsMutexCreate(&batt_dev->hBattEventMutex);
	if (NvSuccess != ErrorStatus) {
		pr_err("NvOsMutexCreate Failed!\n");
		goto Cleanup;
	}

	ErrorStatus = NvOsSemaphoreCreate(&batt_dev->hOdmSemaphore, 0);
	if (NvSuccess != ErrorStatus) {
		pr_err("NvOsSemaphoreCreate Failed!\n");
		goto Cleanup;
	}
/*Henry++ adjust thread to be createn at last
	batt_dev->exitThread = NV_FALSE;
	batt_dev->inSuspend  = NV_FALSE;
	ErrorStatus = NvOsThreadCreate(NvBatteryEventHandlerThread,
					batt_dev,
					&(batt_dev->hBattEventThread));
	if (NvSuccess != ErrorStatus) {
		pr_err("NvOsThreadCreate FAILED\n");
		goto Cleanup;
	}
*/

//Henry add retry when fail ****
for(i=0;i<BATTERY_RETRY_TIMES;i++){
	result = NvOdmBatteryDeviceOpen(&(batt_dev->hOdmBattDev),
		(NvOdmOsSemaphoreHandle *)&batt_dev->hOdmSemaphore);
	if (!result || !batt_dev->hOdmBattDev) {
		pr_err("NvOdmBatteryDeviceOpen FAILED,retry i=%i\n",i);
		NvOsWaitUS(10000);
		continue;
	}
	else{
		break;
	}
}
if(i==BATTERY_RETRY_TIMES){
	pr_err("NvOdmBatteryDeviceOpen FAILED\n");	
	goto Cleanup;
}
//******************************
    
	for (i = 0; i < ARRAY_SIZE(tegra_power_supplies); i++) {
		if (power_supply_register(&pdev->dev, &tegra_power_supplies[i]))
			pr_err("Failed to register power supply\n");
	}

	batt_dev->batt_status_poll_period = NVBATTERY_POLLING_INTERVAL;

	rc = device_create_file(&pdev->dev, &tegra_battery_attr);
	if (rc) {
		for (i = 0; i < ARRAY_SIZE(tegra_power_supplies); i++) {
			power_supply_unregister(&tegra_power_supplies[i]);
		}

		pr_err("nvec_battery_probe:device_create_file FAILED");
		goto Cleanup;
	}

//Henry++ adjust thread to be createn at last
	batt_dev->exitThread = NV_FALSE;
	batt_dev->inSuspend  = NV_FALSE;
	ErrorStatus = NvOsThreadCreate(NvBatteryEventHandlerThread,
					batt_dev,
					&(batt_dev->hBattEventThread));
	if (NvSuccess != ErrorStatus) {
		pr_err("NvOsThreadCreate FAILED\n");
		goto Cleanup;
	}

	return 0;

Cleanup:
	batt_dev->exitThread = NV_TRUE;
	if (batt_dev->hOdmSemaphore) {
		NvOsSemaphoreSignal(batt_dev->hOdmSemaphore);
		NvOsSemaphoreDestroy(batt_dev->hOdmSemaphore);
		batt_dev->hOdmSemaphore = NULL;
	}

	if (batt_dev->hBattEventThread) {
		NvOsThreadJoin(batt_dev->hBattEventThread);
	}
    
	if (batt_dev->hBattEventMutex) {    
		NvOsMutexDestroy(batt_dev->hBattEventMutex);
		batt_dev->hBattEventMutex = NULL;
	}

	if (batt_dev->hOdmBattDev) {
		NvOdmBatteryDeviceClose(batt_dev->hOdmBattDev);
		batt_dev->hOdmBattDev = NULL;
	}

	kfree(batt_dev);
	batt_dev = NULL;
	//return -1;
   return 0;  //henry++ workaround system can't enter suspend
}
void
NvEcClose(NvEcHandle hEc)
{
    NvEcPrivState   *ec;
    NvBool          destroy = NV_FALSE;

    if ( NULL == hEc )
        return;

    NV_ASSERT( s_refcount );

    ec = hEc->ec;
    NvOsMutexLock( ec->mutex );

    // FIXME: handle client still with outstanding event types
    if ( !--s_refcount )
    {
        NvEcPrivDeinitHook(ec->hEc);

        NV_ASSERT( NULL == ec->eventReg[hEc->tag].regBegin &&
                    NULL == ec->eventReg[hEc->tag].regEnd );
        NV_ASSERT( NULL == ec->requestBegin && NULL == ec->requestEnd );
        NV_ASSERT( NULL == ec->responseBegin && NULL == ec->responseEnd );
#ifndef CONFIG_TEGRA_ODM_BETELGEUSE
        ec->exitPingThread = NV_TRUE;
        NvOsSemaphoreSignal( ec->hPingSema );
        NvOsThreadJoin( ec->hPingThread );
#endif
        ec->exitThread = NV_TRUE;
        NvOsSemaphoreSignal( ec->sema );
        NvOsThreadJoin( ec->thread );

        NvEcTransportClose( ec->transport );
        NvOsMutexDestroy( ec->requestMutex );
        NvOsMutexDestroy( ec->responseMutex );
        NvOsMutexDestroy( ec->eventMutex );
        NvOsSemaphoreDestroy( ec->sema );
#ifndef CONFIG_TEGRA_ODM_BETELGEUSE
        NvOsSemaphoreDestroy( ec->hPingSema );
#endif
        NvOsSemaphoreDestroy( ec->LowPowerEntrySema );
        NvOsSemaphoreDestroy( ec->LowPowerExitSema );
        destroy = NV_TRUE;

        NvOsFree( ec->eventNodes );
        NvOsFree( ec->hEc );
    }

    // Set this flag as FALSE to indicate power is disabled
    //Daniel 20100723, if we change power state to NV_FALSE, we won't be able to suspend/poweroff it.
    //Is there any side effect ????? 
    //ec->powerState = NV_FALSE;

    NV_ASSERT( hEc->tag < NVEC_MAX_REQUESTOR_TAG );
    ec->tagAllocated[hEc->tag] = NV_FALSE;      // to be recycled

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

    if ( destroy )
    {
        NvOsMutexDestroy( ec->mutex );
        NvOsMemset( ec, 0, sizeof(NvEcPrivState) );
        ec->mutex = NULL;
    }
}
示例#10
0
void NvRmPrivPwmDeInit(NvRmDeviceHandle hRm)
{
    NvOsMutexDestroy(s_hPwmMutex);
}
示例#11
0
void NvOdmOsMutexDestroy(NvOdmOsMutexHandle mutex)
{
    NvOsMutexDestroy((NvOsMutexHandle)mutex);
}
void
NvDdkUsbPhyClose(
    NvDdkUsbPhyHandle hUsbPhy)
{
    if (!hUsbPhy)
        return;

    NvOsMutexLock(s_UsbPhyMutex);

    if (!hUsbPhy->RefCount)
    {
        NvOsMutexUnlock(s_UsbPhyMutex);
        return;
    }

    --hUsbPhy->RefCount;

    if (hUsbPhy->RefCount)
    {
        NvOsMutexUnlock(s_UsbPhyMutex);
        return;
    }

    NvRmSetModuleTristate(
        hUsbPhy->hRmDevice,
        NVRM_MODULE_ID(NvRmModuleID_Usb2Otg, hUsbPhy->Instance),
        NV_TRUE);

    NvOsMutexLock(hUsbPhy->ThreadSafetyMutex);
    if (hUsbPhy->RmPowerClientId)
    {
        if (hUsbPhy->IsPhyPoweredUp)
        {
            NV_ASSERT_SUCCESS(
                NvRmPowerModuleClockControl(hUsbPhy->hRmDevice,
                  NVRM_MODULE_ID(NvRmModuleID_Usb2Otg, hUsbPhy->Instance),
                  hUsbPhy->RmPowerClientId,
                  NV_FALSE));

            //NvOsDebugPrintf("NvDdkUsbPhyClose::VOLTAGE OFF\n");
            NV_ASSERT_SUCCESS(
                NvRmPowerVoltageControl(hUsbPhy->hRmDevice,
                  NVRM_MODULE_ID(NvRmModuleID_Usb2Otg, hUsbPhy->Instance),
                  hUsbPhy->RmPowerClientId,
                  NvRmVoltsOff, NvRmVoltsOff,
                  NULL, 0, NULL));
            hUsbPhy->IsPhyPoweredUp = NV_FALSE;
        }
        // Unregister driver from Power Manager
        NvRmPowerUnRegister(hUsbPhy->hRmDevice, hUsbPhy->RmPowerClientId);
        NvOsSemaphoreDestroy(hUsbPhy->hPwrEventSem);
    }
    NvOsMutexUnlock(hUsbPhy->ThreadSafetyMutex);

    NvOsMutexDestroy(hUsbPhy->ThreadSafetyMutex);

    if (hUsbPhy->CloseHwInterface)
    {
        hUsbPhy->CloseHwInterface(hUsbPhy);
    }

    if ((hUsbPhy->pProperty->UsbMode == NvOdmUsbModeType_Host) ||
        (hUsbPhy->pProperty->UsbMode == NvOdmUsbModeType_OTG))
    {
        UsbPrivEnableVbus(hUsbPhy, NV_FALSE);
    }

    NvOdmEnableUsbPhyPowerRail(NV_FALSE);

    NvRmPhysicalMemUnmap(
        (void*)hUsbPhy->UsbVirAdr, hUsbPhy->UsbBankSize);

    NvRmPhysicalMemUnmap(
        (void*)hUsbPhy->MiscVirAdr, hUsbPhy->MiscBankSize);

    NvOsMemset(hUsbPhy, 0, sizeof(NvDdkUsbPhy));
    NvOsMutexUnlock(s_UsbPhyMutex);
}
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;
}