drm/panfrost: Really power off GPU cores in panfrost_gpu_power_off()
The layout of the registers {TILER,SHADER,L2}_PWROFF_LO, used to request
powering off cores, is the same as the {TILER,SHADER,L2}_PWRON_LO ones:
this means that in order to request poweroff of cores, we are supposed
to write a bitmask of cores that should be powered off!
This means that the panfrost_gpu_power_off() function has always been
doing nothing.
Fix powering off the GPU by writing a bitmask of the cores to poweroff
to the relevant PWROFF_LO registers and then check that the transition
(from ON to OFF) has finished by polling the relevant PWRTRANS_LO
registers.
While at it, in order to avoid code duplication, move the core mask
logic from panfrost_gpu_power_on() to a new panfrost_get_core_mask()
function, used in both poweron and poweroff.
Fixes: f3ba91228e
("drm/panfrost: Add initial panfrost driver")
Signed-off-by: AngeloGioacchino Del Regno <angelogioacchino.delregno@collabora.com>
Reviewed-by: Steven Price <steven.price@arm.com>
Signed-off-by: Steven Price <steven.price@arm.com>
Link: https://patchwork.freedesktop.org/patch/msgid/20231102141507.73481-1-angelogioacchino.delregno@collabora.com
This commit is contained in:
parent
a78422e9df
commit
22aa1a2090
1 changed files with 46 additions and 18 deletions
|
@ -362,28 +362,38 @@ unsigned long long panfrost_cycle_counter_read(struct panfrost_device *pfdev)
|
||||||
return ((u64)hi << 32) | lo;
|
return ((u64)hi << 32) | lo;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static u64 panfrost_get_core_mask(struct panfrost_device *pfdev)
|
||||||
|
{
|
||||||
|
u64 core_mask;
|
||||||
|
|
||||||
|
if (pfdev->features.l2_present == 1)
|
||||||
|
return U64_MAX;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Only support one core group now.
|
||||||
|
* ~(l2_present - 1) unsets all bits in l2_present except
|
||||||
|
* the bottom bit. (l2_present - 2) has all the bits in
|
||||||
|
* the first core group set. AND them together to generate
|
||||||
|
* a mask of cores in the first core group.
|
||||||
|
*/
|
||||||
|
core_mask = ~(pfdev->features.l2_present - 1) &
|
||||||
|
(pfdev->features.l2_present - 2);
|
||||||
|
dev_info_once(pfdev->dev, "using only 1st core group (%lu cores from %lu)\n",
|
||||||
|
hweight64(core_mask),
|
||||||
|
hweight64(pfdev->features.shader_present));
|
||||||
|
|
||||||
|
return core_mask;
|
||||||
|
}
|
||||||
|
|
||||||
void panfrost_gpu_power_on(struct panfrost_device *pfdev)
|
void panfrost_gpu_power_on(struct panfrost_device *pfdev)
|
||||||
{
|
{
|
||||||
int ret;
|
int ret;
|
||||||
u32 val;
|
u32 val;
|
||||||
u64 core_mask = U64_MAX;
|
u64 core_mask;
|
||||||
|
|
||||||
panfrost_gpu_init_quirks(pfdev);
|
panfrost_gpu_init_quirks(pfdev);
|
||||||
|
core_mask = panfrost_get_core_mask(pfdev);
|
||||||
|
|
||||||
if (pfdev->features.l2_present != 1) {
|
|
||||||
/*
|
|
||||||
* Only support one core group now.
|
|
||||||
* ~(l2_present - 1) unsets all bits in l2_present except
|
|
||||||
* the bottom bit. (l2_present - 2) has all the bits in
|
|
||||||
* the first core group set. AND them together to generate
|
|
||||||
* a mask of cores in the first core group.
|
|
||||||
*/
|
|
||||||
core_mask = ~(pfdev->features.l2_present - 1) &
|
|
||||||
(pfdev->features.l2_present - 2);
|
|
||||||
dev_info_once(pfdev->dev, "using only 1st core group (%lu cores from %lu)\n",
|
|
||||||
hweight64(core_mask),
|
|
||||||
hweight64(pfdev->features.shader_present));
|
|
||||||
}
|
|
||||||
gpu_write(pfdev, L2_PWRON_LO, pfdev->features.l2_present & core_mask);
|
gpu_write(pfdev, L2_PWRON_LO, pfdev->features.l2_present & core_mask);
|
||||||
ret = readl_relaxed_poll_timeout(pfdev->iomem + L2_READY_LO,
|
ret = readl_relaxed_poll_timeout(pfdev->iomem + L2_READY_LO,
|
||||||
val, val == (pfdev->features.l2_present & core_mask),
|
val, val == (pfdev->features.l2_present & core_mask),
|
||||||
|
@ -408,9 +418,27 @@ void panfrost_gpu_power_on(struct panfrost_device *pfdev)
|
||||||
|
|
||||||
void panfrost_gpu_power_off(struct panfrost_device *pfdev)
|
void panfrost_gpu_power_off(struct panfrost_device *pfdev)
|
||||||
{
|
{
|
||||||
gpu_write(pfdev, TILER_PWROFF_LO, 0);
|
u64 core_mask = panfrost_get_core_mask(pfdev);
|
||||||
gpu_write(pfdev, SHADER_PWROFF_LO, 0);
|
int ret;
|
||||||
gpu_write(pfdev, L2_PWROFF_LO, 0);
|
u32 val;
|
||||||
|
|
||||||
|
gpu_write(pfdev, SHADER_PWROFF_LO, pfdev->features.shader_present & core_mask);
|
||||||
|
ret = readl_relaxed_poll_timeout(pfdev->iomem + SHADER_PWRTRANS_LO,
|
||||||
|
val, !val, 1, 1000);
|
||||||
|
if (ret)
|
||||||
|
dev_err(pfdev->dev, "shader power transition timeout");
|
||||||
|
|
||||||
|
gpu_write(pfdev, TILER_PWROFF_LO, pfdev->features.tiler_present);
|
||||||
|
ret = readl_relaxed_poll_timeout(pfdev->iomem + TILER_PWRTRANS_LO,
|
||||||
|
val, !val, 1, 1000);
|
||||||
|
if (ret)
|
||||||
|
dev_err(pfdev->dev, "tiler power transition timeout");
|
||||||
|
|
||||||
|
gpu_write(pfdev, L2_PWROFF_LO, pfdev->features.l2_present & core_mask);
|
||||||
|
ret = readl_poll_timeout(pfdev->iomem + L2_PWRTRANS_LO,
|
||||||
|
val, !val, 0, 1000);
|
||||||
|
if (ret)
|
||||||
|
dev_err(pfdev->dev, "l2 power transition timeout");
|
||||||
}
|
}
|
||||||
|
|
||||||
int panfrost_gpu_init(struct panfrost_device *pfdev)
|
int panfrost_gpu_init(struct panfrost_device *pfdev)
|
||||||
|
|
Loading…
Add table
Reference in a new issue