Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 8 additions & 0 deletions drivers/gpu/drm/v3d/v3d_gem.c
Original file line number Diff line number Diff line change
Expand Up @@ -206,6 +206,14 @@ v3d_clean_caches(struct v3d_dev *v3d)

trace_v3d_cache_clean_begin(dev);

/* GFXH-1897: Ensure pending flushes complete before writing L2TCACTL */
if (v3d->ver < V3D_GEN_71) {
if (wait_for(!(V3D_CORE_READ(core, V3D_CTL_L2TCACTL) &
V3D_L2TCACTL_L2TFLS), 100)) {
DRM_ERROR("Timeout waiting for L2T clean\n");
}
}

V3D_CORE_WRITE(core, V3D_CTL_L2TCACTL, V3D_L2TCACTL_TMUWCF);
if (wait_for(!(V3D_CORE_READ(core, V3D_CTL_L2TCACTL) &
V3D_L2TCACTL_TMUWCF), 100)) {
Expand Down
31 changes: 22 additions & 9 deletions drivers/gpu/drm/v3d/v3d_mmu.c
Original file line number Diff line number Diff line change
Expand Up @@ -35,13 +35,14 @@ static bool v3d_mmu_is_aligned(u32 page, u32 page_address, size_t alignment)
IS_ALIGNED(page_address, alignment >> V3D_MMU_PAGE_SHIFT);
}

int v3d_mmu_flush_all(struct v3d_dev *v3d)
/*
* Issue the MMUC flush and TLB clear unconditionally. The caller must
* already know that V3D is reachable. In particular, this is used from
* the runtime resume callback.
*/
static int v3d_mmu_flush_all_locked(struct v3d_dev *v3d)
{
int ret = 0;

/* Flush the PTs only if we're already awake */
if (!pm_runtime_get_if_active(v3d->drm.dev))
return 0;
int ret;

V3D_WRITE(V3D_MMUC_CONTROL, V3D_MMUC_CONTROL_FLUSH |
V3D_MMUC_CONTROL_ENABLE);
Expand All @@ -50,7 +51,7 @@ int v3d_mmu_flush_all(struct v3d_dev *v3d)
V3D_MMUC_CONTROL_FLUSHING), 100);
if (ret) {
dev_err(v3d->drm.dev, "MMUC flush wait idle failed\n");
goto pm_put;
return ret;
}

V3D_WRITE(V3D_MMU_CTL, V3D_READ(V3D_MMU_CTL) |
Expand All @@ -61,7 +62,19 @@ int v3d_mmu_flush_all(struct v3d_dev *v3d)
if (ret)
dev_err(v3d->drm.dev, "MMU TLB clear wait idle failed\n");

pm_put:
return ret;
}

int v3d_mmu_flush_all(struct v3d_dev *v3d)
{
int ret;

/* Flush the PTs only if we're already awake */
if (!pm_runtime_get_if_active(v3d->drm.dev))
return 0;

ret = v3d_mmu_flush_all_locked(v3d);

v3d_pm_runtime_put(v3d);
return ret;
}
Expand All @@ -83,7 +96,7 @@ int v3d_mmu_set_page_table(struct v3d_dev *v3d)
V3D_MMU_ILLEGAL_ADDR_ENABLE);
V3D_WRITE(V3D_MMUC_CONTROL, V3D_MMUC_CONTROL_ENABLE);

return v3d_mmu_flush_all(v3d);
return v3d_mmu_flush_all_locked(v3d);
}

void v3d_mmu_insert_ptes(struct v3d_bo *bo)
Expand Down
41 changes: 24 additions & 17 deletions drivers/gpu/drm/v3d/v3d_power.c
Original file line number Diff line number Diff line change
Expand Up @@ -2,53 +2,64 @@
/* Copyright (C) 2026 Raspberry Pi */

#include <linux/clk.h>
#include <linux/reset.h>

#include <drm/drm_print.h>

#include "v3d_drv.h"
#include "v3d_regs.h"

static void
static int
v3d_resume_sms(struct v3d_dev *v3d)
{
if (v3d->ver < V3D_GEN_71)
return;
return 0;

V3D_SMS_WRITE(V3D_SMS_TEE_CS, V3D_SMS_CLEAR_POWER_OFF);

if (wait_for((V3D_GET_FIELD(V3D_SMS_READ(V3D_SMS_TEE_CS),
V3D_SMS_STATE) == V3D_SMS_IDLE), 100)) {
drm_err(&v3d->drm, "Failed to power up SMS\n");
return -ETIMEDOUT;
}

v3d_reset_sms(v3d);

return 0;
}

static void
static int
v3d_suspend_sms(struct v3d_dev *v3d)
{
if (v3d->ver < V3D_GEN_71)
return;
return 0;

V3D_SMS_WRITE(V3D_SMS_TEE_CS, V3D_SMS_POWER_OFF);

if (wait_for((V3D_GET_FIELD(V3D_SMS_READ(V3D_SMS_TEE_CS),
V3D_SMS_STATE) == V3D_SMS_POWER_OFF_STATE), 100)) {
drm_err(&v3d->drm, "Failed to power off SMS\n");
return -ETIMEDOUT;
}

return 0;
}

int v3d_power_suspend(struct device *dev)
{
struct drm_device *drm = dev_get_drvdata(dev);
struct v3d_dev *v3d = to_v3d_dev(drm);
int ret;

v3d_irq_disable(v3d);
v3d_suspend_sms(v3d);

if (v3d->reset)
reset_control_assert(v3d->reset);
/* Always clean V3D caches on shutdown. */
v3d_clean_caches(v3d);

ret = v3d_suspend_sms(v3d);
if (ret) {
v3d_irq_enable(v3d);
return ret;
}

clk_disable_unprepare(v3d->clk);

Expand All @@ -65,19 +76,15 @@ int v3d_power_resume(struct device *dev)
if (ret)
return ret;

if (v3d->reset) {
ret = reset_control_deassert(v3d->reset);
if (ret)
goto clk_disable;
ret = v3d_resume_sms(v3d);
if (ret) {
clk_disable_unprepare(v3d->clk);
return ret;
}

v3d_resume_sms(v3d);
v3d_init_hw_state(v3d);
v3d_mmu_set_page_table(v3d);
v3d_irq_enable(v3d);

return 0;

clk_disable:
clk_disable_unprepare(v3d->clk);
return ret;
}
2 changes: 1 addition & 1 deletion drivers/pmdomain/bcm/bcm2835-power.c
Original file line number Diff line number Diff line change
Expand Up @@ -175,7 +175,7 @@ static int bcm2835_asb_control(struct bcm2835_power *power, u32 reg, bool enable
writel(PM_PASSWORD | val, base + reg);

if (readl_poll_timeout_atomic(base + reg, val,
!!(val & ASB_ACK) != enable, 0, 5))
!!(val & ASB_ACK) != enable, 0, 100))
return -ETIMEDOUT;

return 0;
Expand Down
Loading