gcmkONERROR(_SetupExternalSRAMVidMem(device));
#endif
+ /* Create the suspend semaphore. */
+ gcmkONERROR(gckOS_CreateSemaphore(device->os, &device->suspendSemaphore));
+
/* Initialize the kernel thread semaphores. */
for (i = 0; i < gcdMAX_GPU_COUNT; i++)
{
}
}
+ /* Destroy the suspend semaphore. */
+ if (Device->suspendSemaphore)
+ {
+ gcmkVERIFY_OK(gckOS_DestroySemaphore(Device->os, Device->suspendSemaphore));
+ }
if (Device->taos)
{
return status;
}
+/*******************************************************************************
+**
+** gckGALDEVICE_Suspend
+**
+** Suspend the gal device to specific state.
+**
+** INPUT:
+**
+** gckGALDEVICE Device
+** Pointer to an gckGALDEVICE object.
+**
+** gceCHIPPOWERSTATE State
+** State to suspend.
+**
+** OUTPUT:
+**
+** Nothing.
+**
+** RETURNS:
+**
+** gcvSTATUS_OK
+** Suspend successfully.
+*/
+gceSTATUS
+gckGALDEVICE_Suspend(
+ IN gckGALDEVICE Device,
+ IN gceCHIPPOWERSTATE State
+ )
+{
+ gctUINT i;
+ gceSTATUS status;
+ gckHARDWARE hardware;
+ gceCHIPPOWERSTATE currentState = gcvPOWER_INVALID;
+
+ gcmkHEADER_ARG("Device=%p", Device);
+
+ for (i = 0; i < gcdMAX_GPU_COUNT; i++)
+ {
+ if (Device->kernels[i] == gcvNULL)
+ {
+ continue;
+ }
+ Device->statesStored[i] = gcvPOWER_INVALID;
+ }
+
+ for (i = 0; i < gcdMAX_GPU_COUNT; i++)
+ {
+ if (Device->kernels[i] == gcvNULL)
+ {
+ continue;
+ }
+
+#if gcdENABLE_VG
+ if (i == gcvCORE_VG)
+ {
+ hardware = Device->kernels[i]->vg->hardware;
+ }
+ else
+#endif
+ {
+ hardware = Device->kernels[i]->hardware;
+ }
+
+ /* Query state. */
+#if gcdENABLE_VG
+ if (i == gcvCORE_VG)
+ {
+ gcmkONERROR(gckVGHARDWARE_QueryPowerManagementState(hardware,
+ ¤tState));
+ }
+ else
+#endif
+ {
+ gcmkONERROR(gckHARDWARE_QueryPowerState(hardware, ¤tState));
+ }
+
+ /* Store state. */
+ Device->statesStored[i] = currentState;
+
+ /* Pull up power to flush GPU command buffer before suspending. */
+#if gcdENABLE_VG
+ if (i == gcvCORE_VG)
+ {
+ gcmkONERROR(gckVGHARDWARE_SetPowerState(hardware, gcvPOWER_ON));
+ }
+ else
+#endif
+ {
+ gcmkONERROR(gckHARDWARE_SetPowerState(hardware, gcvPOWER_ON));
+ }
+
+#if gcdENABLE_VG
+ if (i == gcvCORE_VG)
+ {
+ gcmkONERROR(gckVGHARDWARE_SetPowerState(hardware, State));
+ }
+ else
+#endif
+ {
+ gcmkONERROR(gckHARDWARE_SetPowerState(hardware, State));
+ }
+ }
+
+ gcmkFOOTER_NO();
+ return gcvSTATUS_OK;
+
+OnError:
+ /* Roll back the state for touched cores. */
+ for (i = 0; i < gcdMAX_GPU_COUNT; i++)
+ {
+ if (Device->kernels[i] == gcvNULL)
+ {
+ continue;
+ }
+
+ if (Device->statesStored[i] == gcvPOWER_INVALID)
+ {
+ continue;
+ }
+
+ /* Reset stored state. */
+ Device->statesStored[i] = gcvPOWER_INVALID;
+ }
+
+ gcmkFOOTER();
+ return status;
+}
+
+/*******************************************************************************
+**
+** gckGALDEVICE_Resume
+**
+** Resume the gal device.
+**
+** INPUT:
+**
+** gckGALDEVICE Device
+** Pointer to an gckGALDEVICE object.
+**
+** OUTPUT:
+**
+** Nothing.
+**
+** RETURNS:
+**
+** gcvSTATUS_OK
+** Resume successfully.
+*/
+gceSTATUS
+gckGALDEVICE_Resume(
+ IN gckGALDEVICE Device
+ )
+{
+ gctUINT i;
+ gceSTATUS status;
+ gckHARDWARE hardware;
+ gceCHIPPOWERSTATE state;
+
+ gcmkHEADER_ARG("Device=%p", Device);
+
+ for (i = 0; i < gcdMAX_GPU_COUNT; i++)
+ {
+ if (Device->kernels[i] == gcvNULL)
+ {
+ continue;
+ }
+
+ if (Device->statesStored[i] == gcvPOWER_INVALID)
+ {
+ continue;
+ }
+
+#if gcdENABLE_VG
+ if (i == gcvCORE_VG)
+ {
+ hardware = Device->kernels[i]->vg->hardware;
+ }
+ else
+#endif
+ {
+ hardware = Device->kernels[i]->hardware;
+ }
+
+#if gcdENABLE_VG
+ if (i == gcvCORE_VG)
+ {
+ gcmkERR_RETURN(gckVGHARDWARE_SetPowerState(hardware, gcvPOWER_ON));
+ }
+ else
+#endif
+ {
+ gcmkERR_RETURN(gckHARDWARE_SetPowerState(hardware, gcvPOWER_ON));
+ }
+
+ /* Convert global state to corresponding internal state. */
+ switch (Device->statesStored[i])
+ {
+ case gcvPOWER_ON:
+ state = gcvPOWER_ON_AUTO;
+ break;
+ case gcvPOWER_IDLE:
+ state = gcvPOWER_IDLE_BROADCAST;
+ break;
+ case gcvPOWER_SUSPEND:
+ state = gcvPOWER_SUSPEND_BROADCAST;
+ break;
+ case gcvPOWER_OFF:
+ state = gcvPOWER_OFF_BROADCAST;
+ break;
+ default:
+ state = Device->statesStored[i];
+ break;
+ }
+
+ /* Restore state. */
+#if gcdENABLE_VG
+ if (i == gcvCORE_VG)
+ {
+ gcmkERR_RETURN(gckVGHARDWARE_SetPowerState(hardware, state));
+ }
+ else
+#endif
+ {
+ gctINT j = 0;
+
+ for (; j < 100; j++)
+ {
+ status = gckHARDWARE_SetPowerState(hardware, state);
+
+ if ((state != gcvPOWER_OFF_BROADCAST &&
+ state != gcvPOWER_SUSPEND_BROADCAST) ||
+ status != gcvSTATUS_CHIP_NOT_READY)
+ {
+ break;
+ }
+
+ gcmkVERIFY_OK(gckOS_Delay(hardware->os, 10));
+ }
+
+ gcmkERR_RETURN(status);
+ }
+
+ /* Reset stored state. */
+ Device->statesStored[i] = gcvPOWER_INVALID;
+ }
+
+ gcmkFOOTER();
+ return status;
+}
/* States before suspend. */
gceCHIPPOWERSTATE statesStored[gcdMAX_GPU_COUNT];
+ gctPOINTER suspendSemaphore;
gcsDEBUGFS_DIR debugfsDir;
}
gcsHAL_PRIVATE_DATA, * gcsHAL_PRIVATE_DATA_PTR;
+gceSTATUS
+gckGALDEVICE_Suspend(
+ IN gckGALDEVICE Device,
+ IN gceCHIPPOWERSTATE State
+ );
+
+gceSTATUS
+gckGALDEVICE_Resume(
+ IN gckGALDEVICE Device
+ );
+
gceSTATUS
gckGALDEVICE_Start(
IN gckGALDEVICE Device
static int gpu_suspend(struct platform_device *dev, pm_message_t state)
{
gceSTATUS status;
- gckGALDEVICE device;
- gctINT i;
-
- device = platform_get_drvdata(dev);
+ gctBOOL sem_acquired = gcvFALSE;
+ gckGALDEVICE device = platform_get_drvdata(dev);
if (!device)
{
return -1;
}
- for (i = 0; i < gcdMAX_GPU_COUNT; i++)
- {
- if (device->kernels[i] != gcvNULL)
- {
- /* Store states. */
-#if gcdENABLE_VG
- if (i == gcvCORE_VG)
- {
- status = gckVGHARDWARE_QueryPowerManagementState(device->kernels[i]->vg->hardware, &device->statesStored[i]);
- }
- else
-#endif
- {
- status = gckHARDWARE_QueryPowerState(device->kernels[i]->hardware, &device->statesStored[i]);
- }
-
- if (gcmIS_ERROR(status))
- {
- return -1;
- }
-
- /* need pull up power to flush gpu command buffer before suspend */
-#if gcdENABLE_VG
- if (i == gcvCORE_VG)
- {
- status = gckVGHARDWARE_SetPowerState(device->kernels[i]->vg->hardware, gcvPOWER_ON);
- }
- else
-#endif
- {
- status = gckHARDWARE_SetPowerState(device->kernels[i]->hardware, gcvPOWER_ON);
- }
+ /* Acquire the suspend management semaphore. */
+ gcmkONERROR(gckOS_AcquireSemaphore(device->os,
+ device->suspendSemaphore));
- if (gcmIS_ERROR(status))
- {
- return -1;
- }
+ sem_acquired = gcvTRUE;
-#if gcdENABLE_VG
- if (i == gcvCORE_VG)
- {
- status = gckVGHARDWARE_SetPowerState(device->kernels[i]->vg->hardware, gcvPOWER_OFF);
- }
- else
-#endif
- {
- status = gckHARDWARE_SetPowerState(device->kernels[i]->hardware, gcvPOWER_OFF);
- }
+ /* Suspend the GPU to off state. */
+ gcmkONERROR(gckGALDEVICE_Suspend(device, gcvPOWER_OFF));
- if (gcmIS_ERROR(status))
- {
- return -1;
- }
+ return 0;
- }
+OnError:
+ /* Release the suspend semaphore. */
+ if (sem_acquired)
+ {
+ gcmkVERIFY_OK(gckOS_ReleaseSemaphore(device->os,
+ device->suspendSemaphore));
}
- return 0;
+ return -1;
}
static int gpu_resume(struct platform_device *dev)
{
gceSTATUS status;
- gckGALDEVICE device;
- gctINT i;
- gceCHIPPOWERSTATE statesStored;
-
- device = platform_get_drvdata(dev);
+ gckGALDEVICE device = platform_get_drvdata(dev);
if (!device)
{
return -1;
}
- for (i = 0; i < gcdMAX_GPU_COUNT; i++)
- {
- if (device->kernels[i] != gcvNULL)
- {
-#if gcdENABLE_VG
- if (i == gcvCORE_VG)
- {
- status = gckVGHARDWARE_SetPowerState(device->kernels[i]->vg->hardware, gcvPOWER_ON);
- }
- else
-#endif
- {
- status = gckHARDWARE_SetPowerState(device->kernels[i]->hardware, gcvPOWER_ON);
- }
-
- if (gcmIS_ERROR(status))
- {
- return -1;
- }
-
- /* Convert global state to crossponding internal state. */
- switch(device->statesStored[i])
- {
- case gcvPOWER_ON:
- statesStored = gcvPOWER_ON_AUTO;
- break;
- case gcvPOWER_IDLE:
- statesStored = gcvPOWER_IDLE_BROADCAST;
- break;
- case gcvPOWER_SUSPEND:
- statesStored = gcvPOWER_SUSPEND_BROADCAST;
- break;
- case gcvPOWER_OFF:
- statesStored = gcvPOWER_OFF_BROADCAST;
- break;
- default:
- statesStored = device->statesStored[i];
- break;
- }
-
- /* Restore states. */
-#if gcdENABLE_VG
- if (i == gcvCORE_VG)
- {
- status = gckVGHARDWARE_SetPowerState(device->kernels[i]->vg->hardware, statesStored);
- }
- else
-#endif
- {
- gctINT j = 0;
-
- for (; j < 100; j++)
- {
- status = gckHARDWARE_SetPowerState(device->kernels[i]->hardware, statesStored);
-
- if (( statesStored != gcvPOWER_OFF_BROADCAST
- && statesStored != gcvPOWER_SUSPEND_BROADCAST)
- || status != gcvSTATUS_CHIP_NOT_READY)
- {
- break;
- }
+ /* Resume GPU to previous state. */
+ status = gckGALDEVICE_Resume(device);
- gcmkVERIFY_OK(gckOS_Delay(device->kernels[i]->os, 10));
- };
- }
+ /* Release the suspend semaphore. */
+ gcmkVERIFY_OK(gckOS_ReleaseSemaphore(device->os, device->suspendSemaphore));
- if (gcmIS_ERROR(status))
- {
- return -1;
- }
- }
- }
+ if (gcmIS_ERROR(status))
+ return -1;
return 0;
}
struct imx_priv *priv = &imxPriv;
int core = gcvCORE_MAJOR;
int i;
+ gckGALDEVICE device = platform_get_drvdata(pdevice);
+ gctBOOL sem_acquired = gcvFALSE;
+ gceSTATUS status;
+
+ if (!device)
+ {
+ return count;
+ }
for (i = 0; i < GOVERN_COUNT; i++)
{
return count;
}
+ /* Acquire the suspend semaphore. */
+ gcmkONERROR(gckOS_AcquireSemaphore(device->os, device->suspendSemaphore));
+
+ sem_acquired = gcvTRUE;
+
+ /* Suspend the GPU to idle state. */
+ gcmkONERROR(gckGALDEVICE_Suspend(device, gcvPOWER_IDLE));
+
core_freq = priv->imx_gpu_govern.core_clk_freq[i];
shader_freq = priv->imx_gpu_govern.shader_clk_freq[i];
priv->imx_gpu_govern.current_mode = i;
}
}
+ /* Resume GPU to previous state. */
+ gcmVERIFY_OK(gckGALDEVICE_Resume(device));
+
+OnError:
+ /* Release the suspend semaphore. */
+ if (sem_acquired)
+ {
+ gcmkVERIFY_OK(gckOS_ReleaseSemaphore(device->os,
+ device->suspendSemaphore));
+ }
+
return count;
}