amd-gpu: refine power control by moving it out of the hal

While we're at it, since we now directly call kgsl_pwrctrl (which is
formerly kgsl_hal_setpowerstate), there's nothing stopping us from
removing device_setproperty ioctl and all related code.
This commit is contained in:
Matt Sealey
2012-12-03 19:20:44 -06:00
parent 3be1cc03b7
commit d7191e15c2
9 changed files with 109 additions and 264 deletions

View File

@@ -461,22 +461,6 @@ done:
return result;
}
static int kgsl_ioctl_device_setproperty(struct file *fd, void __user *arg)
{
int result;
struct kgsl_device_setproperty param;
if (copy_from_user(&param, arg, sizeof(param))) {
result = GSL_FAILURE; // -EFAULT
goto done;
}
result = kgsl_device_setproperty(param.device_id, param.type, param.value, param.sizebytes);
done:
return result;
}
static int kgsl_ioctl_device_regread(struct file *fd, void __user *arg)
{
int status = GSL_SUCCESS;
@@ -936,9 +920,6 @@ static int kgsl_ioctl(struct inode *inode, struct file *fd, unsigned int cmd, un
case IOCTL_KGSL_DEVICE_GETPROPERTY:
result = kgsl_ioctl_device_getproperty(fd, (void __user *)arg);
break;
case IOCTL_KGSL_DEVICE_SETPROPERTY:
result = kgsl_ioctl_device_setproperty(fd, (void __user *)arg);
break;
case IOCTL_KGSL_SHAREDMEM_ALLOC:
/* qcom: runpending on each device first */
result = kgsl_ioctl_sharedmem_alloc(fd, (void __user *)arg);
@@ -1305,16 +1286,10 @@ static int gpu_remove(struct platform_device *pdev)
static int gpu_suspend(struct platform_device *pdev, pm_message_t state)
{
int i;
struct kgsl_powerprop power;
/* this is hideous! */
power.flags = GSL_PWRFLAGS_POWER_OFF;
for (i = 0; i < KGSL_DEVICE_MAX; i++) {
kgsl_device_setproperty(
(unsigned int) (i+1),
KGSL_PROP_DEVICE_POWER,
&power,
sizeof(struct kgsl_powerprop));
kgsl_pwrctrl(i, GSL_PWRFLAGS_POWER_OFF, 0);
}
return 0;
@@ -1323,16 +1298,12 @@ static int gpu_suspend(struct platform_device *pdev, pm_message_t state)
static int gpu_resume(struct platform_device *pdev)
{
int i;
struct kgsl_powerprop power;
power.flags = GSL_PWRFLAGS_POWER_ON;
/* this is hideous! */
for (i = 0; i < KGSL_DEVICE_MAX; i++) {
kgsl_device_setproperty(
(unsigned int) (i+1),
KGSL_PROP_DEVICE_POWER,
&power,
sizeof(struct kgsl_powerprop));
kgsl_pwrctrl(i, GSL_PWRFLAGS_POWER_ON, 100);
}
return 0;
}
#else

View File

@@ -276,28 +276,6 @@ int kgsl_device_getproperty(unsigned int device_id, enum kgsl_property_type type
return status;
}
int kgsl_device_setproperty(unsigned int device_id, enum kgsl_property_type type, void *value, unsigned int sizebytes)
{
int status = GSL_SUCCESS;
struct kgsl_device *device;
KGSL_DRV_VDBG("device_id=%d, type=%d, value=0x%08x, sizebytes=%u\n", device_id, type, (unsigned int) value, sizebytes);
DEBUG_ASSERT(value);
mutex_lock(&gsl_driver.lock);
device = &gsl_driver.device[device_id-1]; // device_id is 1 based
if (device->flags & KGSL_FLAGS_INITIALIZED) {
if (device->ftbl.setproperty) {
status = device->ftbl.setproperty(device, type, value, sizebytes);
}
}
mutex_unlock(&gsl_driver.lock);
return (status);
}
//----------------------------------------------------------------------------
int
kgsl_device_start(unsigned int device_id, unsigned int flags)
{

View File

@@ -57,7 +57,6 @@ struct kgsl_functable {
int (*start) (struct kgsl_device *device, unsigned int flags);
int (*stop) (struct kgsl_device *device);
int (*getproperty) (struct kgsl_device *device, enum kgsl_property_type type, void *value, unsigned int sizebytes);
int (*setproperty) (struct kgsl_device *device, enum kgsl_property_type type, void *value, unsigned int sizebytes);
int (*idle) (struct kgsl_device *device, unsigned int timeout);
int (*regread) (struct kgsl_device *device, unsigned int offsetwords, unsigned int *value);
int (*regwrite) (struct kgsl_device *device, unsigned int offsetwords, unsigned int value);
@@ -132,13 +131,10 @@ int kgsl_device_stop(unsigned int device_id);
int kgsl_device_idle(unsigned int device_id, unsigned int timeout);
int kgsl_device_isidle(unsigned int device_id);
int kgsl_device_getproperty(unsigned int device_id, enum kgsl_property_type type, void *value, unsigned int sizebytes);
int kgsl_device_setproperty(unsigned int device_id, enum kgsl_property_type type, void *value, unsigned int sizebytes);
int kgsl_device_regread(unsigned int device_id, unsigned int offsetwords, unsigned int *value);
int kgsl_clock(unsigned int dev, int enable);
int kgsl_pwrctrl(unsigned int device_id, int state, unsigned int value);
int kgsl_device_active(struct kgsl_device *dev);
int kgsl_device_clock(unsigned int id, int enable);
int kgsl_device_autogate_init(struct kgsl_device *dev);
void kgsl_device_autogate_exit(struct kgsl_device *dev);
#endif // __GSL_DEVICE_H

View File

@@ -201,7 +201,7 @@ kgsl_g12_init(struct kgsl_device *device)
device->flags |= KGSL_FLAGS_INITIALIZED;
kgsl_hal_setpowerstate(device->id, GSL_PWRFLAGS_POWER_ON, 100);
kgsl_pwrctrl(device->id, GSL_PWRFLAGS_POWER_ON, 100);
// setup MH arbiter - MH offsets are considered to be dword based, therefore no down shift
kgsl_g12_regwrite(device, ADDR_MH_ARBITER_CONFIG, KGSL_G12_CFG_G12_MHARB);
@@ -283,7 +283,7 @@ kgsl_g12_close(struct kgsl_device *device)
// shutdown interrupt
kgsl_intr_close(device);
kgsl_hal_setpowerstate(device->id, GSL_PWRFLAGS_POWER_OFF, 0);
kgsl_pwrctrl(device->id, GSL_PWRFLAGS_POWER_OFF, 0);
device->flags &= ~KGSL_FLAGS_INITIALIZED;
@@ -330,7 +330,7 @@ int kgsl_g12_start(struct kgsl_device *device, unsigned int flags)
int status = GSL_SUCCESS;
(void) flags;
kgsl_hal_setpowerstate(device->id, GSL_PWRFLAGS_CLK_ON, 100);
kgsl_pwrctrl(device->id, GSL_PWRFLAGS_CLK_ON, 100);
/* qcom: bitch if not initialized */
@@ -364,7 +364,7 @@ int kgsl_g12_stop(struct kgsl_device *device)
/* qcom: destroy irq work */
status = kgsl_hal_setpowerstate(device->id, GSL_PWRFLAGS_CLK_OFF, 0);
status = kgsl_pwrctrl(device->id, GSL_PWRFLAGS_CLK_OFF, 0);
device->flags &= ~KGSL_FLAGS_STARTED;
return status;
@@ -396,26 +396,7 @@ int kgsl_g12_getproperty(struct kgsl_device *device, enum kgsl_property_type typ
return status;
}
int kgsl_g12_setproperty(struct kgsl_device *device, enum kgsl_property_type type, void *value, unsigned int sizebytes)
{
int status = GSL_FAILURE;
if (type == KGSL_PROP_DEVICE_POWER) {
struct kgsl_powerprop *power = (struct kgsl_powerprop *) value;
DEBUG_ASSERT(sizebytes == sizeof(struct kgsl_powerprop));
if (!(device->flags & KGSL_FLAGS_SAFEMODE)) {
kgsl_hal_setpowerstate(device->id, power->flags, power->value);
}
status = GSL_SUCCESS;
}
return status;
}
int
kgsl_g12_idle(struct kgsl_device *device, unsigned int timeout)
int kgsl_g12_idle(struct kgsl_device *device, unsigned int timeout)
{
if ( device->flags & KGSL_FLAGS_STARTED )
{
@@ -514,7 +495,6 @@ kgsl_g12_getfunctable(struct kgsl_functable *ftbl)
ftbl->start = kgsl_g12_start;
ftbl->stop = kgsl_g12_stop;
ftbl->getproperty = kgsl_g12_getproperty;
ftbl->setproperty = kgsl_g12_setproperty;
ftbl->idle = kgsl_g12_idle;
ftbl->regread = kgsl_g12_regread;
ftbl->regwrite = kgsl_g12_regwrite;

View File

@@ -24,7 +24,6 @@
/* compile string for debug */
#include <linux/compile.h>
#include <linux/clk.h>
#include <linux/kernel.h>
#include <linux/pci.h>
#include <linux/vmalloc.h>
@@ -401,114 +400,3 @@ kgsl_hal_getchipid(unsigned int device_id)
return chipid;
}
/* --------------------------------------------------------------------------- */
KGSLHAL_API int
kgsl_hal_setpowerstate(unsigned int device_id, int state, unsigned int value)
{
struct kgsl_device *device = &gsl_driver.device[device_id-1];
struct clk *gpu_clk = NULL;
struct clk *garb_clk = NULL;
struct clk *emi_garb_clk = NULL;
/* unreferenced formal parameters */
(void) value;
switch (device_id) {
case KGSL_DEVICE_G12:
gpu_clk = clk_get(0, "gpu2d_clk");
break;
case KGSL_DEVICE_YAMATO:
gpu_clk = clk_get(0, "gpu3d_clk");
garb_clk = clk_get(0, "garb_clk");
emi_garb_clk = clk_get(0, "emi_garb_clk");
break;
default:
return GSL_FAILURE_DEVICEERROR;
}
if (!gpu_clk) {
return GSL_FAILURE_DEVICEERROR;
}
switch (state) {
case GSL_PWRFLAGS_CLK_ON:
break;
case GSL_PWRFLAGS_POWER_ON:
clk_enable(gpu_clk);
if (garb_clk) {
clk_enable(garb_clk);
}
if (emi_garb_clk) {
clk_enable(emi_garb_clk);
}
kgsl_device_autogate_init(&gsl_driver.device[device_id-1]);
break;
case GSL_PWRFLAGS_CLK_OFF:
break;
case GSL_PWRFLAGS_POWER_OFF:
if (device->ftbl.idle(device, GSL_TIMEOUT_DEFAULT) != GSL_SUCCESS) {
return GSL_FAILURE_DEVICEERROR;
}
kgsl_device_autogate_exit(&gsl_driver.device[device_id-1]);
clk_disable(gpu_clk);
if (garb_clk) {
clk_disable(garb_clk);
}
if (emi_garb_clk) {
clk_disable(emi_garb_clk);
}
break;
default:
break;
}
return GSL_SUCCESS;
}
KGSLHAL_API int kgsl_clock(unsigned int dev, int enable)
{
struct clk *gpu_clk = NULL;
struct clk *garb_clk = NULL;
struct clk *emi_garb_clk = NULL;
switch (dev) {
case KGSL_DEVICE_G12:
gpu_clk = clk_get(0, "gpu2d_clk");
break;
case KGSL_DEVICE_YAMATO:
gpu_clk = clk_get(0, "gpu3d_clk");
garb_clk = clk_get(0, "garb_clk");
emi_garb_clk = clk_get(0, "emi_garb_clk");
break;
default:
printk(KERN_ERR "GPU device %d is invalid!\n", dev);
return GSL_FAILURE_DEVICEERROR;
}
if (IS_ERR(gpu_clk)) {
printk(KERN_ERR "%s: GPU clock get failed!\n", DRVNAME);
return GSL_FAILURE_DEVICEERROR;
}
if (enable) {
clk_enable(gpu_clk);
if (garb_clk) {
clk_enable(garb_clk);
}
if (emi_garb_clk) {
clk_enable(emi_garb_clk);
}
} else {
clk_disable(gpu_clk);
if (garb_clk) {
clk_disable(garb_clk);
}
if (emi_garb_clk) {
clk_disable(emi_garb_clk);
}
}
return GSL_SUCCESS;
}

View File

@@ -92,7 +92,6 @@ typedef struct _gsl_hal_t {
KGSLHAL_API int kgsl_hal_init(void);
KGSLHAL_API int kgsl_hal_close(void);
KGSLHAL_API int kgsl_hal_getdevconfig(unsigned int device_id, struct kgsl_devconfig *config);
KGSLHAL_API int kgsl_hal_setpowerstate(unsigned int device_id, int state, unsigned int value);
KGSLHAL_API unsigned int kgsl_hal_getchipid(unsigned int device_id);
#ifdef __cplusplus

View File

@@ -18,6 +18,8 @@
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
*/
#include <linux/err.h>
#include <linux/clk.h>
#include <linux/timer.h>
#include <linux/spinlock.h>
#include <linux/slab.h>
@@ -45,6 +47,54 @@ static DECLARE_MUTEX(sem_dev);
#define KGSL_DEVICE_IDLE_TIMEOUT 5000 /* unit ms */
int kgsl_clock(unsigned int dev, int enable)
{
struct clk *gpu_clk = NULL;
struct clk *garb_clk = NULL;
struct clk *emi_garb_clk = NULL;
switch (dev) {
case KGSL_DEVICE_G12:
gpu_clk = clk_get(0, "gpu2d_clk");
break;
case KGSL_DEVICE_YAMATO:
gpu_clk = clk_get(0, "gpu3d_clk");
garb_clk = clk_get(0, "garb_clk");
emi_garb_clk = clk_get(0, "emi_garb_clk");
break;
default:
pr_err("GPU device %d is invalid!\n", dev);
return GSL_FAILURE_DEVICEERROR;
}
if (IS_ERR(gpu_clk)) {
pr_err("GPU clock get failed!\n");
return GSL_FAILURE_DEVICEERROR;
}
if (enable) {
clk_enable(gpu_clk);
if (garb_clk) {
clk_enable(garb_clk);
}
if (emi_garb_clk) {
clk_enable(emi_garb_clk);
}
} else {
clk_disable(gpu_clk);
if (garb_clk) {
clk_disable(garb_clk);
}
if (emi_garb_clk) {
clk_disable(emi_garb_clk);
}
}
return GSL_SUCCESS;
}
static void clk_disable_task(struct work_struct *work)
{
gsl_autogate_t *autogate;
@@ -61,10 +111,10 @@ static int _kgsl_device_active(struct kgsl_device *dev, int all)
int to_active = 0;
gsl_autogate_t *autogate = dev->autogate;
if (!autogate) {
printk(KERN_ERR "%s: autogate has exited!\n", __func__);
pr_err("%s: autogate has exited!\n", __func__);
return 0;
}
// printk(KERN_ERR "%s:%d id %d active %d\n", __func__, __LINE__, dev->id, autogate->active);
// pr_err("%s:%d id %d active %d\n", __func__, __LINE__, dev->id, autogate->active);
spin_lock_irqsave(&autogate->lock, flags);
if (in_interrupt()) {
@@ -99,7 +149,7 @@ static void kgsl_device_inactive(unsigned long data)
gsl_autogate_t *autogate = (gsl_autogate_t *)data;
unsigned long flags;
// printk(KERN_ERR "%s:%d id %d active %d\n", __func__, __LINE__, autogate->dev->id, autogate->active);
// pr_err("%s:%d id %d active %d\n", __func__, __LINE__, autogate->dev->id, autogate->active);
del_timer(&autogate->timer);
spin_lock_irqsave(&autogate->lock, flags);
WARN(!autogate->active, "GPU Device %d is already inactive\n", autogate->dev->id);
@@ -111,33 +161,14 @@ static void kgsl_device_inactive(unsigned long data)
spin_unlock_irqrestore(&autogate->lock, flags);
}
int kgsl_device_clock(unsigned int id, int enable)
{
int ret = GSL_SUCCESS;
struct kgsl_device *device;
device = &gsl_driver.device[id-1]; // device_id is 1 based
if (device->flags & KGSL_FLAGS_INITIALIZED) {
if (enable)
kgsl_device_active(device);
else
kgsl_device_inactive((unsigned long)device);
} else {
printk(KERN_ERR "%s: Dev %d clock is already off!\n", __func__, id);
ret = GSL_FAILURE;
}
return ret;
}
int kgsl_device_autogate_init(struct kgsl_device *dev)
{
gsl_autogate_t *autogate;
// printk(KERN_ERR "%s:%d id %d\n", __func__, __LINE__, dev->id);
// pr_err("%s:%d id %d\n", __func__, __LINE__, dev->id);
autogate = kzalloc(sizeof(gsl_autogate_t), GFP_KERNEL);
if (!autogate) {
printk(KERN_ERR "%s: out of memory!\n", __func__);
pr_err("%s: out of memory!\n", __func__);
return -ENOMEM;
}
down(&sem_dev);
@@ -161,7 +192,7 @@ void kgsl_device_autogate_exit(struct kgsl_device *dev)
{
gsl_autogate_t *autogate = dev->autogate;
// printk(KERN_ERR "%s:%d id %d active %d\n", __func__, __LINE__, dev->id, autogate->active);
// pr_err("%s:%d id %d active %d\n", __func__, __LINE__, dev->id, autogate->active);
down(&sem_dev);
del_timer_sync(&autogate->timer);
if (!autogate->active)
@@ -172,3 +203,41 @@ void kgsl_device_autogate_exit(struct kgsl_device *dev)
kfree(autogate);
dev->autogate = NULL;
}
int kgsl_pwrctrl(unsigned int device_id, int state, unsigned int value)
{
struct kgsl_device *device = &gsl_driver.device[device_id-1];
/* unreferenced formal parameters */
(void) value;
switch (device_id) {
case KGSL_DEVICE_G12:
case KGSL_DEVICE_YAMATO:
break;
default:
return GSL_FAILURE_DEVICEERROR;
}
switch (state) {
case GSL_PWRFLAGS_CLK_ON:
break;
case GSL_PWRFLAGS_POWER_ON:
kgsl_clock(device_id, 1);
kgsl_device_autogate_init(device);
break;
case GSL_PWRFLAGS_CLK_OFF:
break;
case GSL_PWRFLAGS_POWER_OFF:
if (device->ftbl.idle(device, GSL_TIMEOUT_DEFAULT) != GSL_SUCCESS) {
return GSL_FAILURE_DEVICEERROR;
}
kgsl_device_autogate_exit(device);
kgsl_clock(device_id, 0);
break;
default:
break;
}
return GSL_SUCCESS;
}

View File

@@ -350,7 +350,7 @@ kgsl_yamato_init(struct kgsl_device *device)
device->flags |= KGSL_FLAGS_INITIALIZED;
kgsl_hal_setpowerstate(device->id, GSL_PWRFLAGS_POWER_ON, 100);
kgsl_pwrctrl(device->id, GSL_PWRFLAGS_POWER_ON, 100);
//We need to make sure all blocks are powered up and clocked before
//issuing a soft reset. The overrides will be turned off (set to 0)
@@ -408,7 +408,7 @@ kgsl_yamato_close(struct kgsl_device *device)
// shutdown interrupt
kgsl_intr_close(device);
kgsl_hal_setpowerstate(device->id, GSL_PWRFLAGS_POWER_OFF, 0);
kgsl_pwrctrl(device->id, GSL_PWRFLAGS_POWER_OFF, 0);
device->flags &= ~KGSL_FLAGS_INITIALIZED;
}
@@ -460,7 +460,7 @@ kgsl_yamato_start(struct kgsl_device *device, unsigned int flags)
(void) flags; // unreferenced formal parameter
kgsl_hal_setpowerstate(device->id, GSL_PWRFLAGS_CLK_ON, 100);
kgsl_pwrctrl(device->id, GSL_PWRFLAGS_CLK_ON, 100);
// default power management override when running in safe mode
pm1 = (device->flags & KGSL_FLAGS_SAFEMODE) ? 0xFFFFFFFE : 0x00000000;
@@ -547,7 +547,7 @@ kgsl_yamato_stop(struct kgsl_device *device)
if(device->refcnt == 0)
{
kgsl_hal_setpowerstate(device->id, GSL_PWRFLAGS_CLK_OFF, 0);
kgsl_pwrctrl(device->id, GSL_PWRFLAGS_CLK_OFF, 0);
}
device->flags &= ~KGSL_FLAGS_STARTED;
@@ -610,35 +610,6 @@ int kgsl_yamato_getproperty(struct kgsl_device *device, enum kgsl_property_type
return status;
}
int kgsl_yamato_setproperty(struct kgsl_device *device, enum kgsl_property_type type, void *value, unsigned int sizebytes)
{
int status = GSL_FAILURE;
(void) sizebytes;
if (type == KGSL_PROP_DEVICE_POWER) {
struct kgsl_powerprop *power = (struct kgsl_powerprop *) value;
DEBUG_ASSERT(sizebytes == sizeof(struct kgsl_powerprop));
if (!(device->flags & KGSL_FLAGS_SAFEMODE)) {
if (power->flags & GSL_PWRFLAGS_OVERRIDE_ON) {
kgsl_yamato_regwrite(device, REG_RBBM_PM_OVERRIDE1, 0xfffffffe);
kgsl_yamato_regwrite(device, REG_RBBM_PM_OVERRIDE2, 0xffffffff);
} else if (power->flags & GSL_PWRFLAGS_OVERRIDE_OFF) {
kgsl_yamato_regwrite(device, REG_RBBM_PM_OVERRIDE1, 0x00000000);
kgsl_yamato_regwrite(device, REG_RBBM_PM_OVERRIDE2, 0x00000000);
} else {
kgsl_hal_setpowerstate(device->id, power->flags, power->value);
}
}
status = GSL_SUCCESS;
} else {
status = GSL_FAILURE;
}
return status;
}
int kgsl_yamato_idle(struct kgsl_device *device, unsigned int timeout)
{
int status = GSL_FAILURE;
@@ -736,7 +707,6 @@ kgsl_yamato_getfunctable(struct kgsl_functable *ftbl)
ftbl->start = kgsl_yamato_start;
ftbl->stop = kgsl_yamato_stop;
ftbl->getproperty = kgsl_yamato_getproperty;
ftbl->setproperty = kgsl_yamato_setproperty;
ftbl->idle = kgsl_yamato_idle;
ftbl->waittimestamp = kgsl_yamato_waittimestamp;
ftbl->regread = kgsl_yamato_regread;

View File

@@ -124,12 +124,6 @@ struct kgsl_shadowprop {
unsigned int flags; /* contains KGSL_FLAGS_ values */
};
/* NQ - used internally by FSL kernel driver, userspace has no clue */
struct kgsl_powerprop {
unsigned int value;
unsigned int flags;
};
/*
* please check of NQ items are even called from FSL userspace
*/