Skip to content

Commit

Permalink
drm/imagination: Implement power management
Browse files Browse the repository at this point in the history
Add power management to the driver, using runtime pm. The power off
sequence depends on firmware commands which are not implemented in this
patch.

Changes since v8:
- Corrected license identifiers

Changes since v5:
- Use RUNTIME_PM_OPS() to declare PM callbacks
- Add Kconfig dependency on CONFIG_PM

Changes since v4:
- Suspend runtime PM before unplugging device on rmmod

Changes since v3:
- Don't power device when calling pvr_device_gpu_fini()
- Documentation for pvr_dev->lost has been improved
- pvr_power_init() renamed to pvr_watchdog_init()
- Use drm_dev_{enter,exit}

Changes since v2:
- Use runtime PM
- Implement watchdog

Signed-off-by: Sarah Walker <sarah.walker@imgtec.com>
Signed-off-by: Donald Robson <donald.robson@imgtec.com>
Reviewed-by: Maxime Ripard <mripard@kernel.org>
Link: https://lore.kernel.org/r/e09af4ef1ff514e1d6d7f97c7c5032c643c56f9c.1700668843.git.donald.robson@imgtec.com
Signed-off-by: Maxime Ripard <mripard@kernel.org>
  • Loading branch information
Sarah Walker authored and Maxime Ripard committed Nov 23, 2023
1 parent ff5f643 commit 727538a
Show file tree
Hide file tree
Showing 7 changed files with 374 additions and 3 deletions.
1 change: 1 addition & 0 deletions drivers/gpu/drm/imagination/Kconfig
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ config DRM_POWERVR
tristate "Imagination Technologies PowerVR (Series 6 and later) & IMG Graphics"
depends on ARM64
depends on DRM
depends on PM
select DRM_GEM_SHMEM_HELPER
select DRM_SCHED
select DRM_GPUVM
Expand Down
1 change: 1 addition & 0 deletions drivers/gpu/drm/imagination/Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ powervr-y := \
pvr_fw.o \
pvr_gem.o \
pvr_mmu.o \
pvr_power.o \
pvr_vm.o

obj-$(CONFIG_DRM_POWERVR) += powervr.o
23 changes: 21 additions & 2 deletions drivers/gpu/drm/imagination/pvr_device.c
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
#include "pvr_device_info.h"

#include "pvr_fw.h"
#include "pvr_power.h"
#include "pvr_rogue_cr_defs.h"
#include "pvr_vm.h"

Expand Down Expand Up @@ -361,20 +362,38 @@ pvr_device_gpu_fini(struct pvr_device *pvr_dev)
int
pvr_device_init(struct pvr_device *pvr_dev)
{
struct drm_device *drm_dev = from_pvr_device(pvr_dev);
struct device *dev = drm_dev->dev;
int err;

/* Enable and initialize clocks required for the device to operate. */
err = pvr_device_clk_init(pvr_dev);
if (err)
return err;

/* Explicitly power the GPU so we can access control registers before the FW is booted. */
err = pm_runtime_resume_and_get(dev);
if (err)
return err;

/* Map the control registers into memory. */
err = pvr_device_reg_init(pvr_dev);
if (err)
return err;
goto err_pm_runtime_put;

/* Perform GPU-specific initialization steps. */
return pvr_device_gpu_init(pvr_dev);
err = pvr_device_gpu_init(pvr_dev);
if (err)
goto err_pm_runtime_put;

pm_runtime_put(dev);

return 0;

err_pm_runtime_put:
pm_runtime_put_sync_suspend(dev);

return err;
}

/**
Expand Down
22 changes: 22 additions & 0 deletions drivers/gpu/drm/imagination/pvr_device.h
Original file line number Diff line number Diff line change
Expand Up @@ -141,6 +141,28 @@ struct pvr_device {
* before submitting the next job.
*/
atomic_t mmu_flush_cache_flags;

struct {
/** @work: Work item for watchdog callback. */
struct delayed_work work;

/** @old_kccb_cmds_executed: KCCB command execution count at last watchdog poll. */
u32 old_kccb_cmds_executed;

/** @kccb_stall_count: Number of watchdog polls KCCB has been stalled for. */
u32 kccb_stall_count;
} watchdog;

/**
* @lost: %true if the device has been lost.
*
* This variable is set if the device has become irretrievably unavailable, e.g. if the
* firmware processor has stopped responding and can not be revived via a hard reset.
*/
bool lost;

/** @sched_wq: Workqueue for schedulers. */
struct workqueue_struct *sched_wq;
};

/**
Expand Down
20 changes: 19 additions & 1 deletion drivers/gpu/drm/imagination/pvr_drv.c
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
#include "pvr_drv.h"
#include "pvr_gem.h"
#include "pvr_mmu.h"
#include "pvr_power.h"
#include "pvr_rogue_defs.h"
#include "pvr_rogue_fwif_client.h"
#include "pvr_rogue_fwif_shared.h"
Expand Down Expand Up @@ -1265,9 +1266,16 @@ pvr_probe(struct platform_device *plat_dev)

platform_set_drvdata(plat_dev, drm_dev);

devm_pm_runtime_enable(&plat_dev->dev);
pm_runtime_mark_last_busy(&plat_dev->dev);

pm_runtime_set_autosuspend_delay(&plat_dev->dev, 50);
pm_runtime_use_autosuspend(&plat_dev->dev);
pvr_watchdog_init(pvr_dev);

err = pvr_device_init(pvr_dev);
if (err)
return err;
goto err_watchdog_fini;

err = drm_dev_register(drm_dev, 0);
if (err)
Expand All @@ -1278,6 +1286,9 @@ pvr_probe(struct platform_device *plat_dev)
err_device_fini:
pvr_device_fini(pvr_dev);

err_watchdog_fini:
pvr_watchdog_fini(pvr_dev);

return err;
}

Expand All @@ -1287,8 +1298,10 @@ pvr_remove(struct platform_device *plat_dev)
struct drm_device *drm_dev = platform_get_drvdata(plat_dev);
struct pvr_device *pvr_dev = to_pvr_device(drm_dev);

pm_runtime_suspend(drm_dev->dev);
pvr_device_fini(pvr_dev);
drm_dev_unplug(drm_dev);
pvr_watchdog_fini(pvr_dev);

return 0;
}
Expand All @@ -1299,11 +1312,16 @@ static const struct of_device_id dt_match[] = {
};
MODULE_DEVICE_TABLE(of, dt_match);

static const struct dev_pm_ops pvr_pm_ops = {
RUNTIME_PM_OPS(pvr_power_device_suspend, pvr_power_device_resume, pvr_power_device_idle)
};

static struct platform_driver pvr_driver = {
.probe = pvr_probe,
.remove = pvr_remove,
.driver = {
.name = PVR_DRIVER_NAME,
.pm = &pvr_pm_ops,
.of_match_table = dt_match,
},
};
Expand Down
Loading

0 comments on commit 727538a

Please sign in to comment.