From 3a9f1d470619a7b0c0bdee564d312bb1424dfe01 Mon Sep 17 00:00:00 2001 From: Jonathan Cavitt Date: Fri, 17 Apr 2026 05:00:47 +0800 Subject: [PATCH 001/145] drm/auth: Only drm_drop_master if it exists It is possible that both dev->master and file_priv->master are NULL when passed to drm_master_release, which would result in dev being passed to drm_drop_master (as NULL == NULL here). This would result in a NULL pointer dereference when passing dev->master to drm_master_put in drm_drop_master. Only call drm_drop_master if dev->master exists. Also, make sure the original calling requirement is maintained (dev->master == file_priv->master). This fixes a static analysis issue. Signed-off-by: Jonathan Cavitt Cc: Maarten Lankhorst Cc: Maxime Ripard Cc: Thomas Zimmermann Cc: David Airlie Cc: Simona Vetter Acked-by: Luben Tuikov Reviewed-by: Maciej Patelczyk Link: https://patch.msgid.link/20260416210047.3904106-1-jonathan.cavitt@intel.com --- drivers/gpu/drm/drm_auth.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/gpu/drm/drm_auth.c b/drivers/gpu/drm/drm_auth.c index e17bb0f1f9e0..e5013b870ba0 100644 --- a/drivers/gpu/drm/drm_auth.c +++ b/drivers/gpu/drm/drm_auth.c @@ -347,7 +347,7 @@ void drm_master_release(struct drm_file *file_priv) if (!drm_is_current_master_locked(file_priv)) goto out; - if (dev->master == file_priv->master) + if (dev->master && dev->master == file_priv->master) drm_drop_master(dev, file_priv); out: if (drm_core_check_feature(dev, DRIVER_MODESET) && file_priv->is_master) { From 8711eb2dde2ed44c98714b875dcf7329950c71ba Mon Sep 17 00:00:00 2001 From: Max Zhen Date: Tue, 21 Apr 2026 11:15:02 -0700 Subject: [PATCH 002/145] accel/amdxdna: Improve tracing for job lifecycle and mailbox RX worker Add more trace coverage to amdxdna job handling and mailbox receive processing to make driver execution easier to debug. Extend the xdna_job trace event to record the command opcode in addition to the job sequence number. Use the enhanced tracepoint in the job run, sent-to-device, signaled-fence, and job-free paths so that trace output can be correlated with the command being executed. Also add debug-point tracing when a command is received through the submit ioctl path, and add a trace event when the mailbox RX worker runs. These changes improve visibility into job lifetime transitions and mailbox activity, which helps debug command flow and scheduler issues. Signed-off-by: Max Zhen Reviewed-by: Mario Limonciello (AMD) Signed-off-by: Lizhi Hou Link: https://patch.msgid.link/20260421181502.1970263-1-lizhi.hou@amd.com --- drivers/accel/amdxdna/aie2_ctx.c | 14 ++++++--- drivers/accel/amdxdna/amdxdna_ctx.c | 3 +- drivers/accel/amdxdna/amdxdna_ctx.h | 1 + drivers/accel/amdxdna/amdxdna_mailbox.c | 1 + include/trace/events/amdxdna.h | 42 ++++++++++++++++--------- 5 files changed, 42 insertions(+), 19 deletions(-) diff --git a/drivers/accel/amdxdna/aie2_ctx.c b/drivers/accel/amdxdna/aie2_ctx.c index d37123d925b6..3b0feba448c4 100644 --- a/drivers/accel/amdxdna/aie2_ctx.c +++ b/drivers/accel/amdxdna/aie2_ctx.c @@ -64,6 +64,7 @@ static void aie2_job_release(struct kref *ref) struct amdxdna_sched_job *job; job = container_of(ref, struct amdxdna_sched_job, refcnt); + amdxdna_sched_job_cleanup(job); atomic64_inc(&job->hwctx->job_free_cnt); wake_up(&job->hwctx->priv->job_free_wq); @@ -195,7 +196,8 @@ aie2_sched_notify(struct amdxdna_sched_job *job) { struct dma_fence *fence = job->fence; - trace_xdna_job(&job->base, job->hwctx->name, "signaled fence", job->seq); + trace_xdna_job(&job->base, job->hwctx->name, "signaling fence", + job->seq, job->drv_cmd ? job->drv_cmd->opcode : DEFAULT_IO); aie2_tdr_signal(job->hwctx->client->xdna); job->hwctx->priv->completed++; @@ -366,6 +368,9 @@ aie2_sched_job_run(struct drm_sched_job *sched_job) struct dma_fence *fence; int ret; + trace_xdna_job(sched_job, hwctx->name, "job run", + job->seq, job->drv_cmd ? job->drv_cmd->opcode : DEFAULT_IO); + if (!hwctx->priv->mbox_chann) return NULL; @@ -409,7 +414,8 @@ aie2_sched_job_run(struct drm_sched_job *sched_job) } else { aie2_tdr_signal(hwctx->client->xdna); } - trace_xdna_job(sched_job, hwctx->name, "sent to device", job->seq); + trace_xdna_job(sched_job, hwctx->name, "sent to device", + job->seq, job->drv_cmd ? job->drv_cmd->opcode : DEFAULT_IO); return fence; } @@ -419,7 +425,8 @@ static void aie2_sched_job_free(struct drm_sched_job *sched_job) struct amdxdna_sched_job *job = drm_job_to_xdna_job(sched_job); struct amdxdna_hwctx *hwctx = job->hwctx; - trace_xdna_job(sched_job, hwctx->name, "job free", job->seq); + trace_xdna_job(sched_job, hwctx->name, "job free", + job->seq, job->drv_cmd ? job->drv_cmd->opcode : DEFAULT_IO); if (!job->job_done) up(&hwctx->priv->job_sem); @@ -437,7 +444,6 @@ aie2_sched_job_timedout(struct drm_sched_job *sched_job) int ret; xdna = hwctx->client->xdna; - trace_xdna_job(sched_job, hwctx->name, "job timedout", job->seq); guard(mutex)(&xdna->dev_lock); diff --git a/drivers/accel/amdxdna/amdxdna_ctx.c b/drivers/accel/amdxdna/amdxdna_ctx.c index ff6c3e8e5a15..2c2c21992c87 100644 --- a/drivers/accel/amdxdna/amdxdna_ctx.c +++ b/drivers/accel/amdxdna/amdxdna_ctx.c @@ -514,7 +514,6 @@ int amdxdna_cmd_submit(struct amdxdna_client *client, goto unlock_srcu; } - job->hwctx = hwctx; job->mm = current->mm; @@ -612,6 +611,8 @@ int amdxdna_drm_submit_cmd_ioctl(struct drm_device *dev, void *data, struct drm_ if (args->ext || args->ext_flags) return -EINVAL; + trace_amdxdna_debug_point(current->comm, args->type, "job received"); + switch (args->type) { case AMDXDNA_CMD_SUBMIT_EXEC_BUF: return amdxdna_drm_submit_execbuf(client, args); diff --git a/drivers/accel/amdxdna/amdxdna_ctx.h b/drivers/accel/amdxdna/amdxdna_ctx.h index a8557d7e8923..355798687376 100644 --- a/drivers/accel/amdxdna/amdxdna_ctx.h +++ b/drivers/accel/amdxdna/amdxdna_ctx.h @@ -119,6 +119,7 @@ struct amdxdna_hwctx { container_of(j, struct amdxdna_sched_job, base) enum amdxdna_job_opcode { + DEFAULT_IO, SYNC_DEBUG_BO, ATTACH_DEBUG_BO, DETACH_DEBUG_BO, diff --git a/drivers/accel/amdxdna/amdxdna_mailbox.c b/drivers/accel/amdxdna/amdxdna_mailbox.c index 37771bdb24a1..cc8865f4e79c 100644 --- a/drivers/accel/amdxdna/amdxdna_mailbox.c +++ b/drivers/accel/amdxdna/amdxdna_mailbox.c @@ -361,6 +361,7 @@ static void mailbox_rx_worker(struct work_struct *rx_work) int ret; mb_chann = container_of(rx_work, struct mailbox_channel, rx_work); + trace_mbox_rx_worker(MAILBOX_NAME, mb_chann->msix_irq); if (READ_ONCE(mb_chann->bad_state)) { MB_ERR(mb_chann, "Channel in bad state, work aborted"); diff --git a/include/trace/events/amdxdna.h b/include/trace/events/amdxdna.h index c6cb2da7b706..71da24267e52 100644 --- a/include/trace/events/amdxdna.h +++ b/include/trace/events/amdxdna.h @@ -30,26 +30,30 @@ TRACE_EVENT(amdxdna_debug_point, ); TRACE_EVENT(xdna_job, - TP_PROTO(struct drm_sched_job *sched_job, const char *name, const char *str, u64 seq), + TP_PROTO(struct drm_sched_job *sched_job, const char *name, + const char *str, u64 seq, u32 op), - TP_ARGS(sched_job, name, str, seq), + TP_ARGS(sched_job, name, str, seq, op), TP_STRUCT__entry(__string(name, name) __string(str, str) __field(u64, fence_context) __field(u64, fence_seqno) - __field(u64, seq)), + __field(u64, seq) + __field(u32, op)), TP_fast_assign(__assign_str(name); __assign_str(str); __entry->fence_context = sched_job->s_fence->finished.context; __entry->fence_seqno = sched_job->s_fence->finished.seqno; - __entry->seq = seq;), + __entry->seq = seq; + __entry->op = op;), - TP_printk("fence=(context:%llu, seqno:%lld), %s seq#:%lld %s", + TP_printk("fence=(context:%llu, seqno:%llu), %s seq#:%llu %s, op=%u", __entry->fence_context, __entry->fence_seqno, __get_str(name), __entry->seq, - __get_str(str)) + __get_str(str), + __entry->op) ); DECLARE_EVENT_CLASS(xdna_mbox_msg, @@ -81,18 +85,28 @@ DEFINE_EVENT(xdna_mbox_msg, mbox_set_head, TP_ARGS(name, chann_id, opcode, id) ); -TRACE_EVENT(mbox_irq_handle, - TP_PROTO(char *name, int irq), +DECLARE_EVENT_CLASS(xdna_mbox_name_id, + TP_PROTO(char *name, int irq), - TP_ARGS(name, irq), + TP_ARGS(name, irq), - TP_STRUCT__entry(__string(name, name) - __field(int, irq)), + TP_STRUCT__entry(__string(name, name) + __field(int, irq)), - TP_fast_assign(__assign_str(name); - __entry->irq = irq;), + TP_fast_assign(__assign_str(name); + __entry->irq = irq;), - TP_printk("%s.%d", __get_str(name), __entry->irq) + TP_printk("%s.%d", __get_str(name), __entry->irq) +); + +DEFINE_EVENT(xdna_mbox_name_id, mbox_irq_handle, + TP_PROTO(char *name, int irq), + TP_ARGS(name, irq) +); + +DEFINE_EVENT(xdna_mbox_name_id, mbox_rx_worker, + TP_PROTO(char *name, int irq), + TP_ARGS(name, irq) ); #endif /* !defined(_TRACE_AMDXDNA_H) || defined(TRACE_HEADER_MULTI_READ) */ From f7e677a23701a95e71569be88759bf195fd9a42d Mon Sep 17 00:00:00 2001 From: David Heidelberg Date: Fri, 17 Apr 2026 09:49:51 +0300 Subject: [PATCH 003/145] dt-bindigs: display: extend the LVDS codec with Triple 10-BIT LVDS Transmitter LVDS transmitter used in the Microsoft Surface RT. Signed-off-by: David Heidelberg Signed-off-by: Svyatoslav Ryhel Reviewed-by: Robert Foss Acked-by: Rob Herring (Arm) Link: https://patch.msgid.link/20260417064953.20511-2-clamor95@gmail.com Signed-off-by: Dmitry Baryshkov --- Documentation/devicetree/bindings/display/bridge/lvds-codec.yaml | 1 + 1 file changed, 1 insertion(+) diff --git a/Documentation/devicetree/bindings/display/bridge/lvds-codec.yaml b/Documentation/devicetree/bindings/display/bridge/lvds-codec.yaml index 7586d681bcc6..0363201f0e61 100644 --- a/Documentation/devicetree/bindings/display/bridge/lvds-codec.yaml +++ b/Documentation/devicetree/bindings/display/bridge/lvds-codec.yaml @@ -34,6 +34,7 @@ properties: - items: - enum: - doestek,dtc34lm85am # For the Doestek DTC34LM85AM Flat Panel Display (FPD) Transmitter + - idt,v103 # For the Triple 10-BIT LVDS Transmitter - onnn,fin3385 # OnSemi FIN3385 - ti,ds90c185 # For the TI DS90C185 FPD-Link Serializer - ti,ds90c187 # For the TI DS90C187 FPD-Link Serializer From 147782489b48e7bda472151cee48985d6704a919 Mon Sep 17 00:00:00 2001 From: Svyatoslav Ryhel Date: Fri, 17 Apr 2026 09:49:52 +0300 Subject: [PATCH 004/145] dt-bindigs: display: extend the simple bridge with MStar TSUMU88ADT3-LF-1 bridge A simple bridge used in ASUS Transformer AiO P1801-T. Signed-off-by: Svyatoslav Ryhel Reviewed-by: Robert Foss Acked-by: Conor Dooley Link: https://patch.msgid.link/20260417064953.20511-3-clamor95@gmail.com Signed-off-by: Dmitry Baryshkov --- .../devicetree/bindings/display/bridge/simple-bridge.yaml | 1 + 1 file changed, 1 insertion(+) diff --git a/Documentation/devicetree/bindings/display/bridge/simple-bridge.yaml b/Documentation/devicetree/bindings/display/bridge/simple-bridge.yaml index e6808419f625..7636c24906ba 100644 --- a/Documentation/devicetree/bindings/display/bridge/simple-bridge.yaml +++ b/Documentation/devicetree/bindings/display/bridge/simple-bridge.yaml @@ -30,6 +30,7 @@ properties: - algoltek,ag6311 - asl-tek,cs5263 - dumb-vga-dac + - mstar,tsumu88adt3-lf-1 - parade,ps185hdm - radxa,ra620 - realtek,rtd2171 From 7dbca56a79fedf40106baffbc8b0e15f1e54098b Mon Sep 17 00:00:00 2001 From: Maxim Schwalm Date: Fri, 17 Apr 2026 09:49:53 +0300 Subject: [PATCH 005/145] drm/bridge: simple-bridge: Add support for MStar TSUMU88ADT3-LF-1 A simple HDMI bridge used in ASUS Transformer AiO P1801-T. Signed-off-by: Maxim Schwalm Signed-off-by: Svyatoslav Ryhel Reviewed-by: Robert Foss Link: https://patch.msgid.link/20260417064953.20511-4-clamor95@gmail.com Signed-off-by: Dmitry Baryshkov --- drivers/gpu/drm/bridge/simple-bridge.c | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/drivers/gpu/drm/bridge/simple-bridge.c b/drivers/gpu/drm/bridge/simple-bridge.c index 8aa31ca3c72d..cc13c98f9be6 100644 --- a/drivers/gpu/drm/bridge/simple-bridge.c +++ b/drivers/gpu/drm/bridge/simple-bridge.c @@ -270,6 +270,11 @@ static const struct of_device_id simple_bridge_match[] = { .data = &(const struct simple_bridge_info) { .connector_type = DRM_MODE_CONNECTOR_HDMIA, }, + }, { + .compatible = "mstar,tsumu88adt3-lf-1", + .data = &(const struct simple_bridge_info) { + .connector_type = DRM_MODE_CONNECTOR_HDMIA, + }, }, { .compatible = "parade,ps185hdm", .data = &(const struct simple_bridge_info) { From 7ae674a399b6d83ab9b463adb61cc0b64e298eaf Mon Sep 17 00:00:00 2001 From: Dmitry Baryshkov Date: Sat, 18 Apr 2026 02:16:20 +0300 Subject: [PATCH 006/145] dt-bindings: display/panel: ilitek,ili9881c: describe Waveshare panel Describe Waveshare 7" DSI panel which uses ILI9881 as a panel controller. This panel requires two voltags supplies, so add separate iovcc supply. Acked-by: Krzysztof Kozlowski Link: https://patch.msgid.link/20260418-waveshare-dsi-touch-v4-1-b249f3e702bd@oss.qualcomm.com Signed-off-by: Dmitry Baryshkov --- .../devicetree/bindings/display/panel/ilitek,ili9881c.yaml | 2 ++ 1 file changed, 2 insertions(+) diff --git a/Documentation/devicetree/bindings/display/panel/ilitek,ili9881c.yaml b/Documentation/devicetree/bindings/display/panel/ilitek,ili9881c.yaml index d979701a00a8..42e35986fbf6 100644 --- a/Documentation/devicetree/bindings/display/panel/ilitek,ili9881c.yaml +++ b/Documentation/devicetree/bindings/display/panel/ilitek,ili9881c.yaml @@ -24,6 +24,7 @@ properties: - raspberrypi,dsi-7inch - startek,kd050hdfia020 - tdo,tl050hdv35 + - waveshare,7.0-dsi-touch-a - wanchanglong,w552946aaa - wanchanglong,w552946aba - const: ilitek,ili9881c @@ -34,6 +35,7 @@ properties: backlight: true port: true power-supply: true + iovcc-supply: true reset-gpios: true rotation: true From 4c95b2b7d49edc5846730970cef322a6d8d967ba Mon Sep 17 00:00:00 2001 From: Dmitry Baryshkov Date: Sat, 18 Apr 2026 02:16:21 +0300 Subject: [PATCH 007/145] drm/panel: ilitek-ili9881c: support Waveshare 7.0" DSI panel Enable support for Waveshare 7.0" DSI TOUCH-A panel. It requires additional voltage regulator, iovcc. Reviewed-by: Linus Walleij Link: https://patch.msgid.link/20260418-waveshare-dsi-touch-v4-2-b249f3e702bd@oss.qualcomm.com Signed-off-by: Dmitry Baryshkov --- drivers/gpu/drm/panel/panel-ilitek-ili9881c.c | 251 +++++++++++++++++- 1 file changed, 249 insertions(+), 2 deletions(-) diff --git a/drivers/gpu/drm/panel/panel-ilitek-ili9881c.c b/drivers/gpu/drm/panel/panel-ilitek-ili9881c.c index 947b47841b01..0652cdb57d11 100644 --- a/drivers/gpu/drm/panel/panel-ilitek-ili9881c.c +++ b/drivers/gpu/drm/panel/panel-ilitek-ili9881c.c @@ -52,6 +52,7 @@ struct ili9881c { const struct ili9881c_desc *desc; struct regulator *power; + struct regulator *iovcc; struct gpio_desc *reset; enum drm_panel_orientation orientation; @@ -1997,6 +1998,205 @@ static const struct ili9881c_instr bsd1218_a101kl68_init[] = { ILI9881C_COMMAND_INSTR(0xd3, 0x3f), }; +static const struct ili9881c_instr waveshare_7inch_a_init[] = { + ILI9881C_SWITCH_PAGE_INSTR(3), + ILI9881C_COMMAND_INSTR(0x01, 0x00), + ILI9881C_COMMAND_INSTR(0x02, 0x00), + ILI9881C_COMMAND_INSTR(0x03, 0x73), + ILI9881C_COMMAND_INSTR(0x04, 0x00), + ILI9881C_COMMAND_INSTR(0x05, 0x00), + ILI9881C_COMMAND_INSTR(0x06, 0x0a), + ILI9881C_COMMAND_INSTR(0x07, 0x00), + ILI9881C_COMMAND_INSTR(0x08, 0x00), + ILI9881C_COMMAND_INSTR(0x09, 0x61), + ILI9881C_COMMAND_INSTR(0x0a, 0x00), + ILI9881C_COMMAND_INSTR(0x0b, 0x00), + ILI9881C_COMMAND_INSTR(0x0c, 0x01), + ILI9881C_COMMAND_INSTR(0x0d, 0x00), + ILI9881C_COMMAND_INSTR(0x0e, 0x00), + ILI9881C_COMMAND_INSTR(0x0f, 0x61), + ILI9881C_COMMAND_INSTR(0x10, 0x61), + ILI9881C_COMMAND_INSTR(0x11, 0x00), + ILI9881C_COMMAND_INSTR(0x12, 0x00), + ILI9881C_COMMAND_INSTR(0x13, 0x00), + ILI9881C_COMMAND_INSTR(0x14, 0x00), + ILI9881C_COMMAND_INSTR(0x15, 0x00), + ILI9881C_COMMAND_INSTR(0x16, 0x00), + ILI9881C_COMMAND_INSTR(0x17, 0x00), + ILI9881C_COMMAND_INSTR(0x18, 0x00), + ILI9881C_COMMAND_INSTR(0x19, 0x00), + ILI9881C_COMMAND_INSTR(0x1a, 0x00), + ILI9881C_COMMAND_INSTR(0x1b, 0x00), + ILI9881C_COMMAND_INSTR(0x1c, 0x00), + ILI9881C_COMMAND_INSTR(0x1d, 0x00), + ILI9881C_COMMAND_INSTR(0x1e, 0x40), + ILI9881C_COMMAND_INSTR(0x1f, 0x80), + ILI9881C_COMMAND_INSTR(0x20, 0x06), + ILI9881C_COMMAND_INSTR(0x21, 0x01), + ILI9881C_COMMAND_INSTR(0x22, 0x00), + ILI9881C_COMMAND_INSTR(0x23, 0x00), + ILI9881C_COMMAND_INSTR(0x24, 0x00), + ILI9881C_COMMAND_INSTR(0x25, 0x00), + ILI9881C_COMMAND_INSTR(0x26, 0x00), + ILI9881C_COMMAND_INSTR(0x27, 0x00), + ILI9881C_COMMAND_INSTR(0x28, 0x33), + ILI9881C_COMMAND_INSTR(0x29, 0x03), + ILI9881C_COMMAND_INSTR(0x2a, 0x00), + ILI9881C_COMMAND_INSTR(0x2b, 0x00), + ILI9881C_COMMAND_INSTR(0x2c, 0x00), + ILI9881C_COMMAND_INSTR(0x2d, 0x00), + ILI9881C_COMMAND_INSTR(0x2e, 0x00), + ILI9881C_COMMAND_INSTR(0x2f, 0x00), + ILI9881C_COMMAND_INSTR(0x30, 0x00), + ILI9881C_COMMAND_INSTR(0x31, 0x00), + ILI9881C_COMMAND_INSTR(0x32, 0x00), + ILI9881C_COMMAND_INSTR(0x33, 0x00), + ILI9881C_COMMAND_INSTR(0x34, 0x04), + ILI9881C_COMMAND_INSTR(0x35, 0x00), + ILI9881C_COMMAND_INSTR(0x36, 0x00), + ILI9881C_COMMAND_INSTR(0x37, 0x00), + ILI9881C_COMMAND_INSTR(0x38, 0x3c), + ILI9881C_COMMAND_INSTR(0x39, 0x00), + ILI9881C_COMMAND_INSTR(0x3a, 0x00), + ILI9881C_COMMAND_INSTR(0x3b, 0x00), + ILI9881C_COMMAND_INSTR(0x3c, 0x00), + ILI9881C_COMMAND_INSTR(0x3d, 0x00), + ILI9881C_COMMAND_INSTR(0x3e, 0x00), + ILI9881C_COMMAND_INSTR(0x3f, 0x00), + ILI9881C_COMMAND_INSTR(0x40, 0x00), + ILI9881C_COMMAND_INSTR(0x41, 0x00), + ILI9881C_COMMAND_INSTR(0x42, 0x00), + ILI9881C_COMMAND_INSTR(0x43, 0x00), + ILI9881C_COMMAND_INSTR(0x44, 0x00), + ILI9881C_COMMAND_INSTR(0x50, 0x10), + ILI9881C_COMMAND_INSTR(0x51, 0x32), + ILI9881C_COMMAND_INSTR(0x52, 0x54), + ILI9881C_COMMAND_INSTR(0x53, 0x76), + ILI9881C_COMMAND_INSTR(0x54, 0x98), + ILI9881C_COMMAND_INSTR(0x55, 0xba), + ILI9881C_COMMAND_INSTR(0x56, 0x10), + ILI9881C_COMMAND_INSTR(0x57, 0x32), + ILI9881C_COMMAND_INSTR(0x58, 0x54), + ILI9881C_COMMAND_INSTR(0x59, 0x76), + ILI9881C_COMMAND_INSTR(0x5a, 0x98), + ILI9881C_COMMAND_INSTR(0x5b, 0xba), + ILI9881C_COMMAND_INSTR(0x5c, 0xdc), + ILI9881C_COMMAND_INSTR(0x5d, 0xfe), + ILI9881C_COMMAND_INSTR(0x5e, 0x00), + ILI9881C_COMMAND_INSTR(0x5f, 0x0e), + ILI9881C_COMMAND_INSTR(0x60, 0x0f), + ILI9881C_COMMAND_INSTR(0x61, 0x0c), + ILI9881C_COMMAND_INSTR(0x62, 0x0d), + ILI9881C_COMMAND_INSTR(0x63, 0x06), + ILI9881C_COMMAND_INSTR(0x64, 0x07), + ILI9881C_COMMAND_INSTR(0x65, 0x02), + ILI9881C_COMMAND_INSTR(0x66, 0x02), + ILI9881C_COMMAND_INSTR(0x67, 0x02), + ILI9881C_COMMAND_INSTR(0x68, 0x02), + ILI9881C_COMMAND_INSTR(0x69, 0x01), + ILI9881C_COMMAND_INSTR(0x6a, 0x00), + ILI9881C_COMMAND_INSTR(0x6b, 0x02), + ILI9881C_COMMAND_INSTR(0x6c, 0x15), + ILI9881C_COMMAND_INSTR(0x6d, 0x14), + ILI9881C_COMMAND_INSTR(0x6e, 0x02), + ILI9881C_COMMAND_INSTR(0x6f, 0x02), + ILI9881C_COMMAND_INSTR(0x70, 0x02), + ILI9881C_COMMAND_INSTR(0x71, 0x02), + ILI9881C_COMMAND_INSTR(0x72, 0x02), + ILI9881C_COMMAND_INSTR(0x73, 0x02), + ILI9881C_COMMAND_INSTR(0x74, 0x02), + ILI9881C_COMMAND_INSTR(0x75, 0x0e), + ILI9881C_COMMAND_INSTR(0x76, 0x0f), + ILI9881C_COMMAND_INSTR(0x77, 0x0c), + ILI9881C_COMMAND_INSTR(0x78, 0x0d), + ILI9881C_COMMAND_INSTR(0x79, 0x06), + ILI9881C_COMMAND_INSTR(0x7a, 0x07), + ILI9881C_COMMAND_INSTR(0x7b, 0x02), + ILI9881C_COMMAND_INSTR(0x7c, 0x02), + ILI9881C_COMMAND_INSTR(0x7d, 0x02), + ILI9881C_COMMAND_INSTR(0x7e, 0x02), + ILI9881C_COMMAND_INSTR(0x7f, 0x01), + ILI9881C_COMMAND_INSTR(0x80, 0x00), + ILI9881C_COMMAND_INSTR(0x81, 0x02), + ILI9881C_COMMAND_INSTR(0x82, 0x14), + ILI9881C_COMMAND_INSTR(0x83, 0x15), + ILI9881C_COMMAND_INSTR(0x84, 0x02), + ILI9881C_COMMAND_INSTR(0x85, 0x02), + ILI9881C_COMMAND_INSTR(0x86, 0x02), + ILI9881C_COMMAND_INSTR(0x87, 0x02), + ILI9881C_COMMAND_INSTR(0x88, 0x02), + ILI9881C_COMMAND_INSTR(0x89, 0x02), + ILI9881C_COMMAND_INSTR(0x8a, 0x02), + + ILI9881C_SWITCH_PAGE_INSTR(4), + ILI9881C_COMMAND_INSTR(0x38, 0x01), + ILI9881C_COMMAND_INSTR(0x39, 0x00), + ILI9881C_COMMAND_INSTR(0x6c, 0x15), + ILI9881C_COMMAND_INSTR(0x6e, 0x2a), + ILI9881C_COMMAND_INSTR(0x6f, 0x33), + ILI9881C_COMMAND_INSTR(0x3a, 0x94), + ILI9881C_COMMAND_INSTR(0x8d, 0x14), + ILI9881C_COMMAND_INSTR(0x87, 0xba), + ILI9881C_COMMAND_INSTR(0x26, 0x76), + ILI9881C_COMMAND_INSTR(0xb2, 0xd1), + ILI9881C_COMMAND_INSTR(0xb5, 0x06), + ILI9881C_COMMAND_INSTR(0x3b, 0x98), + + ILI9881C_SWITCH_PAGE_INSTR(1), + ILI9881C_COMMAND_INSTR(0x22, 0x0a), + ILI9881C_COMMAND_INSTR(0x31, 0x00), + ILI9881C_COMMAND_INSTR(0x53, 0x71), + ILI9881C_COMMAND_INSTR(0x55, 0x8f), + ILI9881C_COMMAND_INSTR(0x40, 0x33), + ILI9881C_COMMAND_INSTR(0x50, 0x96), + ILI9881C_COMMAND_INSTR(0x51, 0x96), + ILI9881C_COMMAND_INSTR(0x60, 0x23), + ILI9881C_COMMAND_INSTR(0xa0, 0x08), + ILI9881C_COMMAND_INSTR(0xa1, 0x1d), + ILI9881C_COMMAND_INSTR(0xa2, 0x2a), + ILI9881C_COMMAND_INSTR(0xa3, 0x10), + ILI9881C_COMMAND_INSTR(0xa4, 0x15), + ILI9881C_COMMAND_INSTR(0xa5, 0x28), + ILI9881C_COMMAND_INSTR(0xa6, 0x1c), + ILI9881C_COMMAND_INSTR(0xa7, 0x1d), + ILI9881C_COMMAND_INSTR(0xa8, 0x7e), + ILI9881C_COMMAND_INSTR(0xa9, 0x1d), + ILI9881C_COMMAND_INSTR(0xaa, 0x29), + ILI9881C_COMMAND_INSTR(0xab, 0x6b), + ILI9881C_COMMAND_INSTR(0xac, 0x1a), + ILI9881C_COMMAND_INSTR(0xad, 0x18), + ILI9881C_COMMAND_INSTR(0xae, 0x4b), + ILI9881C_COMMAND_INSTR(0xaf, 0x20), + ILI9881C_COMMAND_INSTR(0xb0, 0x27), + ILI9881C_COMMAND_INSTR(0xb1, 0x50), + ILI9881C_COMMAND_INSTR(0xb2, 0x64), + ILI9881C_COMMAND_INSTR(0xb3, 0x39), + ILI9881C_COMMAND_INSTR(0xc0, 0x08), + ILI9881C_COMMAND_INSTR(0xc1, 0x1d), + ILI9881C_COMMAND_INSTR(0xc2, 0x2a), + ILI9881C_COMMAND_INSTR(0xc3, 0x10), + ILI9881C_COMMAND_INSTR(0xc4, 0x15), + ILI9881C_COMMAND_INSTR(0xc5, 0x28), + ILI9881C_COMMAND_INSTR(0xc6, 0x1c), + ILI9881C_COMMAND_INSTR(0xc7, 0x1d), + ILI9881C_COMMAND_INSTR(0xc8, 0x7e), + ILI9881C_COMMAND_INSTR(0xc9, 0x1d), + ILI9881C_COMMAND_INSTR(0xca, 0x29), + ILI9881C_COMMAND_INSTR(0xcb, 0x6b), + ILI9881C_COMMAND_INSTR(0xcc, 0x1a), + ILI9881C_COMMAND_INSTR(0xcd, 0x18), + ILI9881C_COMMAND_INSTR(0xce, 0x4b), + ILI9881C_COMMAND_INSTR(0xcf, 0x20), + ILI9881C_COMMAND_INSTR(0xd0, 0x27), + ILI9881C_COMMAND_INSTR(0xd1, 0x50), + ILI9881C_COMMAND_INSTR(0xd2, 0x64), + ILI9881C_COMMAND_INSTR(0xd3, 0x39), + + ILI9881C_SWITCH_PAGE_INSTR(0), + ILI9881C_COMMAND_INSTR(0x3a, 0x77), + ILI9881C_COMMAND_INSTR(0x36, 0x00), +}; + static inline struct ili9881c *panel_to_ili9881c(struct drm_panel *panel) { return container_of(panel, struct ili9881c, panel); @@ -2035,9 +2235,19 @@ static int ili9881c_prepare(struct drm_panel *panel) int ret; /* Power the panel */ + if (ctx->iovcc) { + ret = regulator_enable(ctx->iovcc); + if (ret) + return ret; + } + + msleep(5); ret = regulator_enable(ctx->power); - if (ret) - return ret; + if (ret) { + mctx.accum_err = ret; + goto disable_iovcc; + } + msleep(5); /* And reset it */ @@ -2074,6 +2284,9 @@ static int ili9881c_prepare(struct drm_panel *panel) disable_power: regulator_disable(ctx->power); +disable_iovcc: + if (ctx->iovcc) + regulator_disable(ctx->iovcc); return mctx.accum_err; } @@ -2085,6 +2298,8 @@ static int ili9881c_unprepare(struct drm_panel *panel) mipi_dsi_dcs_set_display_off_multi(&mctx); mipi_dsi_dcs_enter_sleep_mode_multi(&mctx); regulator_disable(ctx->power); + if (ctx->iovcc) + regulator_disable(ctx->iovcc); gpiod_set_value_cansleep(ctx->reset, 1); return 0; @@ -2260,6 +2475,23 @@ static const struct drm_display_mode bsd1218_a101kl68_default_mode = { .height_mm = 170, }; +static const struct drm_display_mode waveshare_7inch_a_mode = { + .clock = 83333, + + .hdisplay = 720, + .hsync_start = 720 + 120, + .hsync_end = 720 + 120 + 100, + .htotal = 720 + 120 + 100 + 100, + + .vdisplay = 1280, + .vsync_start = 1280 + 10, + .vsync_end = 1280 + 10 + 10, + .vtotal = 1280 + 10 + 10 + 10, + + .width_mm = 85, + .height_mm = 154, +}; + static int ili9881c_get_modes(struct drm_panel *panel, struct drm_connector *connector) { @@ -2329,6 +2561,11 @@ static int ili9881c_dsi_probe(struct mipi_dsi_device *dsi) return dev_err_probe(&dsi->dev, PTR_ERR(ctx->power), "Couldn't get our power regulator\n"); + ctx->iovcc = devm_regulator_get_optional(&dsi->dev, "iovcc"); + if (IS_ERR(ctx->iovcc)) + return dev_err_probe(&dsi->dev, PTR_ERR(ctx->iovcc), + "Couldn't get our iovcc regulator\n"); + ctx->reset = devm_gpiod_get_optional(&dsi->dev, "reset", GPIOD_OUT_LOW); if (IS_ERR(ctx->reset)) return dev_err_probe(&dsi->dev, PTR_ERR(ctx->reset), @@ -2454,6 +2691,15 @@ static const struct ili9881c_desc bsd1218_a101kl68_desc = { .lanes = 4, }; +static const struct ili9881c_desc waveshare_7inch_a_desc = { + .init = waveshare_7inch_a_init, + .init_length = ARRAY_SIZE(waveshare_7inch_a_init), + .mode = &waveshare_7inch_a_mode, + .mode_flags = MIPI_DSI_MODE_VIDEO | MIPI_DSI_MODE_VIDEO_HSE | + MIPI_DSI_MODE_LPM | MIPI_DSI_CLOCK_NON_CONTINUOUS, + .lanes = 2, +}; + static const struct of_device_id ili9881c_of_match[] = { { .compatible = "bananapi,lhr050h41", .data = &lhr050h41_desc }, { .compatible = "bestar,bsd1218-a101kl68", .data = &bsd1218_a101kl68_desc }, @@ -2462,6 +2708,7 @@ static const struct of_device_id ili9881c_of_match[] = { { .compatible = "tdo,tl050hdv35", .data = &tl050hdv35_desc }, { .compatible = "wanchanglong,w552946aaa", .data = &w552946aaa_desc }, { .compatible = "wanchanglong,w552946aba", .data = &w552946aba_desc }, + { .compatible = "waveshare,7.0-dsi-touch-a", .data = &waveshare_7inch_a_desc }, { .compatible = "ampire,am8001280g", .data = &am8001280g_desc }, { .compatible = "raspberrypi,dsi-5inch", &rpi_5inch_desc }, { .compatible = "raspberrypi,dsi-7inch", &rpi_7inch_desc }, From 6920d18ef7971c405253407842d0aae0654bd406 Mon Sep 17 00:00:00 2001 From: Karol Wachowski Date: Tue, 21 Apr 2026 11:39:07 +0200 Subject: [PATCH 008/145] accel/ivpu: Fix swapped register names in pwr_island_drive functions pwr_island_drive_37xx and pwr_island_drive_40xx functions had incorrectly swapped registers definitions. Bug is purely cosmetic as those registers have exactly same offsets and layout in both 37XX and 40XX. Reviewed-by: Andrzej Kacprowski Signed-off-by: Karol Wachowski Link: https://patch.msgid.link/20260421093907.37304-1-karol.wachowski@linux.intel.com --- drivers/accel/ivpu/ivpu_hw_ip.c | 24 ++++++++++++------------ 1 file changed, 12 insertions(+), 12 deletions(-) diff --git a/drivers/accel/ivpu/ivpu_hw_ip.c b/drivers/accel/ivpu/ivpu_hw_ip.c index 37f95a0551ed..81f0b1f8f5a6 100644 --- a/drivers/accel/ivpu/ivpu_hw_ip.c +++ b/drivers/accel/ivpu/ivpu_hw_ip.c @@ -307,18 +307,6 @@ static void pwr_island_trickle_drive_40xx(struct ivpu_device *vdev, bool enable) } static void pwr_island_drive_37xx(struct ivpu_device *vdev, bool enable) -{ - u32 val = REGV_RD32(VPU_40XX_HOST_SS_AON_PWR_ISLAND_EN0); - - if (enable) - val = REG_SET_FLD(VPU_40XX_HOST_SS_AON_PWR_ISLAND_EN0, CSS_CPU, val); - else - val = REG_CLR_FLD(VPU_40XX_HOST_SS_AON_PWR_ISLAND_EN0, CSS_CPU, val); - - REGV_WR32(VPU_40XX_HOST_SS_AON_PWR_ISLAND_EN0, val); -} - -static void pwr_island_drive_40xx(struct ivpu_device *vdev, bool enable) { u32 val = REGV_RD32(VPU_37XX_HOST_SS_AON_PWR_ISLAND_EN0); @@ -330,6 +318,18 @@ static void pwr_island_drive_40xx(struct ivpu_device *vdev, bool enable) REGV_WR32(VPU_37XX_HOST_SS_AON_PWR_ISLAND_EN0, val); } +static void pwr_island_drive_40xx(struct ivpu_device *vdev, bool enable) +{ + u32 val = REGV_RD32(VPU_40XX_HOST_SS_AON_PWR_ISLAND_EN0); + + if (enable) + val = REG_SET_FLD(VPU_40XX_HOST_SS_AON_PWR_ISLAND_EN0, CSS_CPU, val); + else + val = REG_CLR_FLD(VPU_40XX_HOST_SS_AON_PWR_ISLAND_EN0, CSS_CPU, val); + + REGV_WR32(VPU_40XX_HOST_SS_AON_PWR_ISLAND_EN0, val); +} + static void pwr_island_enable(struct ivpu_device *vdev) { if (ivpu_hw_ip_gen(vdev) == IVPU_HW_IP_37XX) { From ac7e1a9819d6ada9a9800d6d26256e5258711b99 Mon Sep 17 00:00:00 2001 From: Avinal Kumar Date: Fri, 17 Apr 2026 11:48:41 +0530 Subject: [PATCH 009/145] drm/mipi-dsi: add mipi_dsi_shutdown_peripheral_multi Add mipi_dsi_shutdown_peripheral_multi function and mark mipi_dsi_shutdown_peripheral function as deprecated. Signed-off-by: Avinal Kumar Reviewed-by: Neil Armstrong Reviewed-by: Douglas Anderson Signed-off-by: Douglas Anderson Link: https://patch.msgid.link/20260417061842.66631-2-avinal.xlvii@gmail.com --- drivers/gpu/drm/drm_mipi_dsi.c | 28 ++++++++++++++++++++++++++++ include/drm/drm_mipi_dsi.h | 1 + 2 files changed, 29 insertions(+) diff --git a/drivers/gpu/drm/drm_mipi_dsi.c b/drivers/gpu/drm/drm_mipi_dsi.c index 0390e14d3157..3ac1dd5ad640 100644 --- a/drivers/gpu/drm/drm_mipi_dsi.c +++ b/drivers/gpu/drm/drm_mipi_dsi.c @@ -587,6 +587,9 @@ EXPORT_SYMBOL(mipi_dsi_create_packet); * mipi_dsi_shutdown_peripheral() - sends a Shutdown Peripheral command * @dsi: DSI peripheral device * + * This function is deprecated. Use mipi_dsi_shutdown_peripheral_multi() + * instead. + * * Return: 0 on success or a negative error code on failure. */ int mipi_dsi_shutdown_peripheral(struct mipi_dsi_device *dsi) @@ -1980,6 +1983,31 @@ void mipi_dsi_dcs_set_tear_scanline_multi(struct mipi_dsi_multi_context *ctx, } EXPORT_SYMBOL(mipi_dsi_dcs_set_tear_scanline_multi); +/** + * mipi_dsi_shutdown_peripheral_multi() - sends a Shutdown Peripheral command + * @ctx: Context for multiple DSI transactions + * + * Like mipi_dsi_shutdown_peripheral() but deals with errors in a way that + * makes it convenient to make several calls in a row. + */ +void mipi_dsi_shutdown_peripheral_multi(struct mipi_dsi_multi_context *ctx) +{ + struct mipi_dsi_device *dsi = ctx->dsi; + struct device *dev = &dsi->dev; + int ret; + + if (ctx->accum_err) + return; + + ret = mipi_dsi_shutdown_peripheral(dsi); + if (ret < 0) { + ctx->accum_err = ret; + dev_err(dev, "Failed to shutdown peripheral: %d\n", + ctx->accum_err); + } +} +EXPORT_SYMBOL(mipi_dsi_shutdown_peripheral_multi); + static int mipi_dsi_drv_probe(struct device *dev) { struct mipi_dsi_driver *drv = to_mipi_dsi_driver(dev->driver); diff --git a/include/drm/drm_mipi_dsi.h b/include/drm/drm_mipi_dsi.h index 2ab651a36115..b429acde4f71 100644 --- a/include/drm/drm_mipi_dsi.h +++ b/include/drm/drm_mipi_dsi.h @@ -393,6 +393,7 @@ void mipi_dsi_dcs_set_page_address_multi(struct mipi_dsi_multi_context *ctx, void mipi_dsi_dcs_set_tear_scanline_multi(struct mipi_dsi_multi_context *ctx, u16 scanline); void mipi_dsi_dcs_set_tear_off_multi(struct mipi_dsi_multi_context *ctx); +void mipi_dsi_shutdown_peripheral_multi(struct mipi_dsi_multi_context *ctx); /** * mipi_dsi_generic_write_seq_multi - transmit data using a generic write packet From 03af6c3afc4893988ceed54531f5dde4bebd6024 Mon Sep 17 00:00:00 2001 From: Avinal Kumar Date: Fri, 17 Apr 2026 11:48:42 +0530 Subject: [PATCH 010/145] drm/panel: panasonic-vvx10f034n00: transition to mipi_dsi wrapped functions Change the panasonic-vvx10f034n00 panel to multi style functions for improved error handling and remove redundant error printout. Signed-off-by: Avinal Kumar Reviewed-by: Dmitry Baryshkov Reviewed-by: Douglas Anderson Signed-off-by: Douglas Anderson Link: https://patch.msgid.link/20260417061842.66631-3-avinal.xlvii@gmail.com --- .../drm/panel/panel-panasonic-vvx10f034n00.c | 24 ++++++++++--------- 1 file changed, 13 insertions(+), 11 deletions(-) diff --git a/drivers/gpu/drm/panel/panel-panasonic-vvx10f034n00.c b/drivers/gpu/drm/panel/panel-panasonic-vvx10f034n00.c index 3c3308fc55df..d21d93a0700e 100644 --- a/drivers/gpu/drm/panel/panel-panasonic-vvx10f034n00.c +++ b/drivers/gpu/drm/panel/panel-panasonic-vvx10f034n00.c @@ -44,14 +44,23 @@ static inline struct wuxga_nt_panel *to_wuxga_nt_panel(struct drm_panel *panel) static int wuxga_nt_panel_on(struct wuxga_nt_panel *wuxga_nt) { - return mipi_dsi_turn_on_peripheral(wuxga_nt->dsi); + struct mipi_dsi_multi_context dsi_ctx = { + .dsi = wuxga_nt->dsi + }; + + mipi_dsi_turn_on_peripheral_multi(&dsi_ctx); + return dsi_ctx.accum_err; } static int wuxga_nt_panel_disable(struct drm_panel *panel) { struct wuxga_nt_panel *wuxga_nt = to_wuxga_nt_panel(panel); + struct mipi_dsi_multi_context dsi_ctx = { + .dsi = wuxga_nt->dsi + }; - return mipi_dsi_shutdown_peripheral(wuxga_nt->dsi); + mipi_dsi_shutdown_peripheral_multi(&dsi_ctx); + return dsi_ctx.accum_err; } static int wuxga_nt_panel_unprepare(struct drm_panel *panel) @@ -94,15 +103,8 @@ static int wuxga_nt_panel_prepare(struct drm_panel *panel) msleep(250); ret = wuxga_nt_panel_on(wuxga_nt); - if (ret < 0) { - dev_err(panel->dev, "failed to set panel on: %d\n", ret); - goto poweroff; - } - - return 0; - -poweroff: - regulator_disable(wuxga_nt->supply); + if (ret < 0) + regulator_disable(wuxga_nt->supply); return ret; } From e3953ff665742c15c002af9e176bd24d5cd9ec61 Mon Sep 17 00:00:00 2001 From: Hamza Mahfooz Date: Wed, 25 Feb 2026 12:57:08 -0500 Subject: [PATCH 011/145] drm/edid: add CTA Video Format Data Block support Video Format Data Blocks (VFDBs) contain the necessary information that needs to be fed to the Optimized Video Timings (OVT) Algorithm. Also, we require OVT support to cover modes that aren't supported by earlier standards (e.g. CVT). So, parse all of the relevant VFDB data and feed it to the OVT Algorithm, to extract all of the missing OVT modes. Suggested-by: Karol Herbst Signed-off-by: Hamza Mahfooz Link: https://patch.msgid.link/20260225175709.408010-1-someguy@effective-light.com --- drivers/gpu/drm/drm_edid.c | 465 +++++++++++++++++++++++++++++++++++++ include/drm/drm_edid.h | 3 + 2 files changed, 468 insertions(+) diff --git a/drivers/gpu/drm/drm_edid.c b/drivers/gpu/drm/drm_edid.c index 4385d13bd382..0325b8592ac9 100644 --- a/drivers/gpu/drm/drm_edid.c +++ b/drivers/gpu/drm/drm_edid.c @@ -31,6 +31,7 @@ #include #include #include +#include #include #include #include @@ -778,6 +779,87 @@ static const struct minimode extra_modes[] = { { 2048, 1536, 60, 0 }, }; +struct cta_rid { + u16 hactive; + u16 vactive; + u8 hratio; + u8 vratio; +}; + +/* CTA-861-I Table 11 - Resolution Identification (RID) */ +static const struct cta_rid rids[] = { + [0] = { 0, 0, 0, 0 }, + [1] = { 1280, 720, 16, 9 }, + [2] = { 1280, 720, 64, 27 }, + [3] = { 1680, 720, 64, 27 }, + [4] = { 1920, 1080, 16, 9 }, + [5] = { 1920, 1080, 64, 27 }, + [6] = { 2560, 1080, 64, 27 }, + [7] = { 3840, 1080, 32, 9 }, + [8] = { 2560, 1440, 16, 9 }, + [9] = { 3440, 1440, 64, 27 }, + [10] = { 5120, 1440, 32, 9 }, + [11] = { 3840, 2160, 16, 9 }, + [12] = { 3840, 2160, 64, 27 }, + [13] = { 5120, 2160, 64, 27 }, + [14] = { 7680, 2160, 32, 9 }, + [15] = { 5120, 2880, 16, 9 }, + [16] = { 5120, 2880, 64, 27 }, + [17] = { 6880, 2880, 64, 27 }, + [18] = { 10240, 2880, 32, 9 }, + [19] = { 7680, 4320, 16, 9 }, + [20] = { 7680, 4320, 64, 27 }, + [21] = { 10240, 4320, 64, 27 }, + [22] = { 15360, 4320, 32, 9 }, + [23] = { 11520, 6480, 16, 9 }, + [24] = { 11520, 6480, 64, 27 }, + [25] = { 15360, 6480, 64, 27 }, + [26] = { 15360, 8640, 16, 9 }, + [27] = { 15360, 8640, 64, 27 }, + [28] = { 20480, 8640, 64, 27 }, +}; + +/* CTA-861-I Table 12 - AVI InfoFrame Video Format Frame Rate */ +static const u16 video_format_frame_rates[] = { + /* Frame Rate 0-7 */ + 0, 24, 25, 30, 48, 50, 60, 100, + /* Frame Rate 8-15 */ + 120, 144, 200, 240, 300, 360, 400, 480, +}; + +/* CTA-861-I Table 13 - RID To VIC Mapping */ +static const u8 rid_to_vic[][8] = { + [0] = {}, + [1] = { 60, 61, 62, 108, 19, 4, 41, 47 }, + [2] = { 65, 66, 67, 109, 68, 69, 70, 71 }, + [3] = { 79, 80, 81, 110, 82, 83, 84, 85 }, + [4] = { 32, 33, 34, 111, 31, 16, 64, 63 }, + [5] = { 72, 73, 74, 112, 75, 76, 77, 78 }, + [6] = { 86, 87, 88, 113, 89, 90, 91, 92 }, + [7] = {}, + [8] = {}, + [9] = {}, + [10] = {}, + [11] = { 93, 94, 95, 114, 96, 97, 117, 118 }, + [12] = { 103, 104, 105, 116, 106, 107, 119, 120 }, + [13] = { 121, 122, 123, 124, 125, 126, 127, 193 }, + [14] = {}, + [15] = {}, + [16] = {}, + [17] = {}, + [18] = {}, + [19] = { 194, 195, 196, 197, 198, 199, 200, 201 }, + [20] = { 202, 203, 204, 205, 206, 207, 208, 209 }, + [21] = { 210, 211, 212, 213, 214, 215, 216, 217 }, + [22] = {}, + [23] = {}, + [24] = {}, + [25] = {}, + [26] = {}, + [27] = {}, + [28] = {}, +}; + /* * From CEA/CTA-861 spec. * @@ -4178,6 +4260,7 @@ static int add_detailed_modes(struct drm_connector *connector, #define CTA_DB_VIDEO 2 #define CTA_DB_VENDOR 3 #define CTA_DB_SPEAKER 4 +#define CTA_DB_VIDEO_FORMAT 6 #define CTA_DB_EXTENDED_TAG 7 /* CTA-861-H Table 62 - CTA Extended Tag Codes */ @@ -5019,6 +5102,16 @@ struct cea_db { u8 data[]; } __packed; +struct cta_vfd { + u8 rid; + u8 fr_fact; + bool bfr50; + bool fr24; + bool bfr60; + bool fr144; + bool fr48; +}; + static int cea_db_tag(const struct cea_db *db) { return db->tag_length >> 5; @@ -5304,6 +5397,376 @@ static int edid_hfeeodb_extension_block_count(const struct edid *edid) return cta[4 + 2]; } +/* CTA-861 Video Format Descriptor (CTA VFD) */ +static void parse_cta_vfd(struct cta_vfd *vfd, const u8 *data, int vfd_len) +{ + vfd->rid = data[0] & 0x3f; + vfd->bfr50 = data[0] & 0x80; + vfd->fr24 = data[0] & 0x40; + vfd->bfr60 = vfd_len > 1 ? (data[1] & 0x80) : true; + vfd->fr144 = vfd_len > 1 ? (data[1] & 0x40) : false; + vfd->fr_fact = vfd_len > 1 ? (data[1] & 0x3f) : 0x3; + vfd->fr48 = vfd_len > 2 ? (data[2] & 0x1) : false; +} + +static bool vfd_has_fr(const struct cta_vfd *vfd, int rate) +{ + static const u8 factors[] = { + 1, 2, 4, 8, 12, 16 + }; + int factor = 0; + int i; + + switch (rate) { + case 24: + return vfd->fr24; + case 48: + return vfd->fr48; + case 144: + return vfd->fr144; + } + + if (!(rate % 25)) { + if (!vfd->bfr50) + return false; + + factor = rate / 25; + } else if (!(rate % 30)) { + if (!vfd->bfr60) + return false; + + factor = rate / 30; + } + + for (i = 0; i < ARRAY_SIZE(factors); i++) + if (factor == factors[i] && (vfd->fr_fact & (1 << i))) + return true; + + return false; +} + +#define OVT_PIXEL_CLOCK_GRANULARITY 1000 /* Hz */ +#define OVT_MIN_HTOTAL_GRANULARITY 8 /* pixels */ +#define OVT_MIN_VBLANK_DURATION 460000000 /* ps */ +#define OVT_MIN_VBLANK_LINES 20 +#define OVT_MIN_VSYNC_LEADING_EDGE 400 /* us */ +#define OVT_MIN_VSYNC_LE_LINES 14 +#define OVT_MIN_CLOCK_RATE_420 590000000 /* Hz */ +#define OVT_PIXEL_FACTOR_420 2 +#define OVT_MIN_HBLANK_444 80 /* pixels */ +#define OVT_MIN_HBLANK_420 128 /* pixels */ +#define OVT_MAX_CHUNK_RATE 650000000 /* Hz */ +#define OVT_AUDIO_PACKET_RATE 195000 /* Hz */ +#define OVT_AUDIO_PACKET_SIZE 32 +#define OVT_LINE_OVERHEAD 32 +#define OVT_HSYNC_WIDTH 32 +#define OVT_VSYNC_WIDTH 8 + +static u32 calculate_ovt_min_vtotal(const struct cta_rid *rid, u64 max_vrate, + u32 vtotal_granularity) +{ + u64 max_active_time; + u32 min_line_time; + u32 min_vblank; + u32 min_vtotal; + + /* step 2 */ + max_active_time = div64_u64(1000000000000, max_vrate) - + (u64)OVT_MIN_VBLANK_DURATION; + + min_line_time = div_u64(max_active_time, rid->vactive); + + min_vblank = max_t(u64, (u64)OVT_MIN_VBLANK_LINES, + DIV64_U64_ROUND_UP(OVT_MIN_VBLANK_DURATION, + min_line_time)); + + min_vtotal = rid->vactive + min_vblank; + + if (min_vtotal % vtotal_granularity) + min_vtotal += vtotal_granularity - (min_vtotal % + vtotal_granularity); + + return min_vtotal; +} + +static u32 calculate_ovt_min_htotal(const struct cta_rid *rid, + const u32 max_vrate, + const u32 min_vtotal, + u32 *min_hblank, + u32 *htotal_granularity) +{ + u32 max_audio_packets_per_line; + u32 htotal_granularity_chunk; + u64 min_pixel_clock_rate; + u32 min_line_rate; + u32 min_htotal; + + /* step 3 */ + min_line_rate = max_vrate * min_vtotal; + + max_audio_packets_per_line = DIV_ROUND_UP(OVT_AUDIO_PACKET_RATE, + min_line_rate); + + /* step 4 */ + *min_hblank = OVT_LINE_OVERHEAD + OVT_AUDIO_PACKET_SIZE * + max_audio_packets_per_line; + + min_htotal = rid->hactive + max(OVT_MIN_HBLANK_444, *min_hblank); + + min_pixel_clock_rate = max_vrate * min_htotal * min_vtotal; + + htotal_granularity_chunk = + roundup_pow_of_two(DIV64_U64_ROUND_UP(min_pixel_clock_rate, + OVT_MAX_CHUNK_RATE)); + + *htotal_granularity = max(OVT_MIN_HTOTAL_GRANULARITY, + htotal_granularity_chunk); + + if (min_htotal % *htotal_granularity) + min_htotal += *htotal_granularity - (min_htotal % + *htotal_granularity); + + return min_htotal; +} + +static u64 calculate_ovt_pixel_clock_rate(const struct cta_rid *rid, + const u32 max_vrate, + const u32 min_hblank, + u32 min_htotal, + u32 min_vtotal, + const u32 htotal_granularity, + const u32 vtotal_granularity, + u32 *htotal, u32 *vtotal) +{ + u32 resolution_granularity; + u64 pixel_clock_rate; + u64 min_resolution; + u64 rem; + u32 h; + u64 r; + u32 v; + + resolution_granularity = OVT_PIXEL_CLOCK_GRANULARITY / + gcd(OVT_PIXEL_CLOCK_GRANULARITY, max_vrate); + + do { + /* step 5 */ + min_resolution = 0; + v = min_vtotal; + + goto loop_end; + + while (!min_resolution || r <= min_resolution) { + goto inner_loop_end; + + while (rem || div64_u64(max_vrate * r, (h & ~(h - 1))) > + OVT_MAX_CHUNK_RATE) { + h += htotal_granularity; + r = (u64)h * (u64)v; +inner_loop_end: + div64_u64_rem(r, resolution_granularity, &rem); + } + + if (!min_resolution || r < min_resolution) { + *htotal = h; + *vtotal = v; + min_resolution = r; + } + + v += vtotal_granularity; + +loop_end: + h = min_htotal; + r = (u64)h * (u64)v; + } + + pixel_clock_rate = max_vrate * min_resolution; + + /* step 6 */ + min_htotal = rid->hactive + max(OVT_MIN_HBLANK_420, + OVT_PIXEL_FACTOR_420 * + min_hblank); + + } while (pixel_clock_rate >= OVT_MIN_CLOCK_RATE_420 && + *htotal < min_htotal); + + return pixel_clock_rate; +} + +static const struct cta_rid *find_rid(u8 rid) +{ + if (!rid || rid >= ARRAY_SIZE(rids)) + return NULL; + + return &rids[rid]; +} + +/* OVT Algorthim as specified in CTA-861-I */ +struct drm_display_mode *drm_ovt_mode(struct drm_device *dev, int r_id, + int vrefresh) +{ + const struct cta_rid *rid = find_rid(r_id); + struct drm_display_mode *mode; + u32 vtotal_granularity = 1; + u32 htotal_granularity; + u32 max_vrate = vrefresh; + u64 pixel_clock_rate; + u32 vsync_position; + u32 min_hblank; + u32 min_htotal; + u32 min_vtotal; + u32 htotal; + u32 vtotal; + + if (!rid) + return NULL; + + /* step 1 */ + switch (vrefresh) { + case 24: + case 25: + max_vrate = 30; + fallthrough; + case 30: + vtotal_granularity = 20; + break; + case 48: + case 50: + max_vrate = 60; + fallthrough; + case 60: + vtotal_granularity = 20; + break; + case 100: + max_vrate = 120; + fallthrough; + case 120: + vtotal_granularity = 5; + break; + case 200: + max_vrate = 240; + fallthrough; + case 240: + vtotal_granularity = 5; + break; + case 300: + max_vrate = 360; + fallthrough; + case 360: + vtotal_granularity = 5; + break; + case 400: + max_vrate = 480; + fallthrough; + case 480: + vtotal_granularity = 5; + break; + } + + min_vtotal = calculate_ovt_min_vtotal(rid, max_vrate, + vtotal_granularity); + + min_htotal = calculate_ovt_min_htotal(rid, max_vrate, min_vtotal, + &min_hblank, &htotal_granularity); + + pixel_clock_rate = calculate_ovt_pixel_clock_rate(rid, max_vrate, + min_hblank, + min_htotal, + min_vtotal, + htotal_granularity, + vtotal_granularity, + &htotal, &vtotal); + + /* step 7 */ + vtotal = vtotal * max_vrate / (u32)vrefresh; + + /* step 8 */ + vsync_position = max(OVT_MIN_VSYNC_LE_LINES, + DIV64_U64_ROUND_UP((u64)OVT_MIN_VSYNC_LE_LINES * + pixel_clock_rate, + (u64)htotal * (u64)1000000)); + + mode = drm_mode_create(dev); + + if (!mode) + return NULL; + + /* step 10 */ + mode->clock = div_u64(pixel_clock_rate, 1000); + mode->hdisplay = rid->hactive; + mode->hsync_start = htotal - OVT_HSYNC_WIDTH * 2; + mode->hsync_end = mode->hsync_start + OVT_HSYNC_WIDTH; + mode->htotal = htotal; + + mode->vdisplay = rid->vactive; + mode->vsync_start = vtotal - vsync_position; + mode->vsync_end = mode->vsync_start + OVT_VSYNC_WIDTH; + mode->vtotal = vtotal; + + return mode; +} + +static u8 find_vic(u8 rid, int rate_idx) +{ + if (video_format_frame_rates[rate_idx] > 120 || !find_rid(rid)) + return 0; + + return rid_to_vic[rid][rate_idx - 1]; +} + +/* CTA-861 Video Format Data Block (CTA VFDB) */ +static int add_modes_from_vfdb(struct drm_connector *connector, + const struct cea_db *db) +{ + const struct drm_display_info *info = &connector->display_info; + int vfdb_len = cea_db_payload_len(db); + struct drm_display_mode *mode; + struct cta_vfd vfd; + int num_modes = 0; + int rate_idx; + int vfd_len; + int rate; + int i; + + if (!vfdb_len) + return 0; + + vfd_len = (db->data[0] & 0x3); + + if (!vfd_len) + return 0; + + vfd_len++; + vfdb_len--; + vfdb_len -= (vfdb_len % vfd_len); + + for (i = 0; i < vfdb_len; i += vfd_len) { + parse_cta_vfd(&vfd, &db->data[i + 1], vfd_len); + + for (rate_idx = 1; rate_idx < + ARRAY_SIZE(video_format_frame_rates); rate_idx++) { + rate = video_format_frame_rates[rate_idx]; + + if (!vfd_has_fr(&vfd, rate) || find_vic(vfd.rid, + rate_idx)) + continue; + + mode = drm_ovt_mode(connector->dev, vfd.rid, rate); + + if (!mode) + continue; + + mode->height_mm = info->height_mm; + mode->width_mm = info->width_mm; + + drm_mode_probed_add(connector, mode); + num_modes++; + } + } + + return num_modes; +} + /* * CTA-861 YCbCr 4:2:0 Capability Map Data Block (CTA Y420CMDB) * @@ -5372,6 +5835,8 @@ static int add_cea_modes(struct drm_connector *connector, /* Add 4:2:0(only) modes present in EDID */ modes += do_y420vdb_modes(connector, vdb420, cea_db_payload_len(db) - 1); + } else if (cea_db_tag(db) == CTA_DB_VIDEO_FORMAT) { + modes += add_modes_from_vfdb(connector, db); } } cea_db_iter_end(&iter); diff --git a/include/drm/drm_edid.h b/include/drm/drm_edid.h index 04f7a7f1f108..272506331634 100644 --- a/include/drm/drm_edid.h +++ b/include/drm/drm_edid.h @@ -463,6 +463,9 @@ struct drm_display_mode * drm_display_mode_from_cea_vic(struct drm_device *dev, u8 video_code); +struct drm_display_mode *drm_ovt_mode(struct drm_device *dev, int rid, + int vrefresh); + /* Interface based on struct drm_edid */ const struct drm_edid *drm_edid_alloc(const void *edid, size_t size); const struct drm_edid *drm_edid_dup(const struct drm_edid *drm_edid); From 241061119a51423b84dca11e79ee2e178b6163e4 Mon Sep 17 00:00:00 2001 From: Hamza Mahfooz Date: Sat, 25 Apr 2026 11:17:19 -0700 Subject: [PATCH 012/145] drm/hyperv: use VMBUS_RING_SIZE() VMBUS ring buffers must be page aligned. So, use VMBUS_RING_SIZE() to ensure they are always aligned and large enough to hold all of the relevant data. Cc: stable@kernel.vger.org Fixes: 76c56a5affeb ("drm/hyperv: Add DRM driver for hyperv synthetic video device") Signed-off-by: Hamza Mahfooz Reviewed-by: Saurabh Sengar Link: https://patch.msgid.link/20260425181719.1538483-2-hamzamahfooz@linux.microsoft.com --- drivers/gpu/drm/hyperv/hyperv_drm_proto.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/gpu/drm/hyperv/hyperv_drm_proto.c b/drivers/gpu/drm/hyperv/hyperv_drm_proto.c index 051ecc526832..753d97bff76f 100644 --- a/drivers/gpu/drm/hyperv/hyperv_drm_proto.c +++ b/drivers/gpu/drm/hyperv/hyperv_drm_proto.c @@ -10,7 +10,7 @@ #include "hyperv_drm.h" -#define VMBUS_RING_BUFSIZE (256 * 1024) +#define VMBUS_RING_BUFSIZE VMBUS_RING_SIZE(256 * 1024) #define VMBUS_VSP_TIMEOUT (10 * HZ) #define SYNTHVID_VERSION(major, minor) ((minor) << 16 | (major)) From 96f865ed44b0d4f7ecadee3855861ef38f25a3cf Mon Sep 17 00:00:00 2001 From: Brajesh Gupta Date: Mon, 27 Apr 2026 11:01:38 +0530 Subject: [PATCH 013/145] drm/imagination: Restrict init_fw_trace_mask module param to read only Param used for setting FW trace mask at module load time. Other debugfs entry exist to allow update at run time. Signed-off-by: Brajesh Gupta Reviewed-by: Alessio Belle Link: https://patch.msgid.link/20260427-ftrace_fix-v3-2-e081530759a8@imgtec.com Signed-off-by: Matt Coster --- drivers/gpu/drm/imagination/pvr_fw_trace.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/gpu/drm/imagination/pvr_fw_trace.c b/drivers/gpu/drm/imagination/pvr_fw_trace.c index e154cb35f604..458d9ab8193e 100644 --- a/drivers/gpu/drm/imagination/pvr_fw_trace.c +++ b/drivers/gpu/drm/imagination/pvr_fw_trace.c @@ -77,7 +77,7 @@ const struct kernel_param_ops pvr_fw_trace_init_mask_ops = { }; param_check_hexint(init_fw_trace_mask, &pvr_fw_trace_init_mask); -module_param_cb(init_fw_trace_mask, &pvr_fw_trace_init_mask_ops, &pvr_fw_trace_init_mask, 0600); +module_param_cb(init_fw_trace_mask, &pvr_fw_trace_init_mask_ops, &pvr_fw_trace_init_mask, 0400); __MODULE_PARM_TYPE(init_fw_trace_mask, "hexint"); MODULE_PARM_DESC(init_fw_trace_mask, "Enable FW trace for the specified groups at device init time"); From 974d6764b76fef6f2b0f3933596fefd5d05e687c Mon Sep 17 00:00:00 2001 From: Lizhi Hou Date: Thu, 23 Apr 2026 21:08:22 -0700 Subject: [PATCH 014/145] accel/amdxdna: Set default DPM level based on QoS for temporal-only mode The QoS request provided when creating a hardware context is currently ignored when operating in temporal-only mode. Change this to use resource allocation through xrs_allocate_resource(), which sets the default DPM level according to the QoS request. When multiple hardware contexts are active, track their required DPM levels and set the default DPM level to the highest among them. Reviewed-by: Mario Limonciello (AMD) Signed-off-by: Lizhi Hou Link: https://patch.msgid.link/20260424040824.2253607-1-lizhi.hou@amd.com --- drivers/accel/amdxdna/aie2_ctx.c | 34 +++++++++++++---------------- drivers/accel/amdxdna/aie2_pci.c | 1 + drivers/accel/amdxdna/aie2_pci.h | 1 + drivers/accel/amdxdna/aie2_pm.c | 2 +- drivers/accel/amdxdna/aie2_solver.c | 10 ++++++++- drivers/accel/amdxdna/npu1_regs.c | 1 + drivers/accel/amdxdna/npu4_regs.c | 1 + drivers/accel/amdxdna/npu5_regs.c | 1 + drivers/accel/amdxdna/npu6_regs.c | 1 + 9 files changed, 31 insertions(+), 21 deletions(-) diff --git a/drivers/accel/amdxdna/aie2_ctx.c b/drivers/accel/amdxdna/aie2_ctx.c index 3b0feba448c4..139825ac8515 100644 --- a/drivers/accel/amdxdna/aie2_ctx.c +++ b/drivers/accel/amdxdna/aie2_ctx.c @@ -546,22 +546,24 @@ static int aie2_alloc_resource(struct amdxdna_hwctx *hwctx) { struct amdxdna_dev *xdna = hwctx->client->xdna; struct alloc_requests *xrs_req; + u32 temporal_only_col = 0; int ret; - if (AIE_FEATURE_ON(&xdna->dev_handle->aie, AIE2_TEMPORAL_ONLY)) { - hwctx->num_unused_col = xdna->dev_handle->total_col - hwctx->num_col; - hwctx->num_col = xdna->dev_handle->total_col; - return aie2_create_context(xdna->dev_handle, hwctx); - } - xrs_req = kzalloc_obj(*xrs_req); if (!xrs_req) return -ENOMEM; - xrs_req->cdo.start_cols = hwctx->col_list; - xrs_req->cdo.cols_len = hwctx->col_list_len; - xrs_req->cdo.ncols = hwctx->num_col; - xrs_req->cdo.qos_cap.opc = hwctx->max_opc; + if (AIE_FEATURE_ON(&xdna->dev_handle->aie, AIE2_TEMPORAL_ONLY)) { + xrs_req->cdo.start_cols = &temporal_only_col; + xrs_req->cdo.cols_len = 1; + xrs_req->cdo.ncols = xdna->dev_handle->total_col; + } else { + xrs_req->cdo.start_cols = hwctx->col_list; + xrs_req->cdo.cols_len = hwctx->col_list_len; + xrs_req->cdo.ncols = hwctx->num_col; + } + /* Use platform opc */ + xrs_req->cdo.qos_cap.opc = xdna->dev_handle->priv->col_opc * hwctx->num_col; xrs_req->rqos.gops = hwctx->qos.gops; xrs_req->rqos.fps = hwctx->qos.fps; @@ -585,15 +587,9 @@ static void aie2_release_resource(struct amdxdna_hwctx *hwctx) struct amdxdna_dev *xdna = hwctx->client->xdna; int ret; - if (AIE_FEATURE_ON(&xdna->dev_handle->aie, AIE2_TEMPORAL_ONLY)) { - ret = aie2_destroy_context(xdna->dev_handle, hwctx); - if (ret && ret != -ENODEV) - XDNA_ERR(xdna, "Destroy temporal only context failed, ret %d", ret); - } else { - ret = xrs_release_resource(xdna->xrs_hdl, (uintptr_t)hwctx); - if (ret) - XDNA_ERR(xdna, "Release AIE resource failed, ret %d", ret); - } + ret = xrs_release_resource(xdna->xrs_hdl, (uintptr_t)hwctx); + if (ret) + XDNA_ERR(xdna, "Release AIE resource failed, ret %d", ret); } static int aie2_ctx_syncobj_create(struct amdxdna_hwctx *hwctx) diff --git a/drivers/accel/amdxdna/aie2_pci.c b/drivers/accel/amdxdna/aie2_pci.c index 1d1fb012294a..a07e453a1721 100644 --- a/drivers/accel/amdxdna/aie2_pci.c +++ b/drivers/accel/amdxdna/aie2_pci.c @@ -246,6 +246,7 @@ static int aie2_xrs_load(void *cb_arg, struct xrs_action_load *action) xdna = hwctx->client->xdna; hwctx->start_col = action->part.start_col; + hwctx->num_unused_col = action->part.ncols - hwctx->num_col; hwctx->num_col = action->part.ncols; ret = aie2_create_context(xdna->dev_handle, hwctx); if (ret) diff --git a/drivers/accel/amdxdna/aie2_pci.h b/drivers/accel/amdxdna/aie2_pci.h index c44616065058..f12073175676 100644 --- a/drivers/accel/amdxdna/aie2_pci.h +++ b/drivers/accel/amdxdna/aie2_pci.h @@ -237,6 +237,7 @@ struct amdxdna_dev_priv { #define COL_ALIGN_NONE 0 #define COL_ALIGN_NATURE 1 u32 col_align; + u32 col_opc; u32 mbox_dev_addr; /* If mbox_size is 0, use BAR size. See MBOX_SIZE macro */ u32 mbox_size; diff --git a/drivers/accel/amdxdna/aie2_pm.c b/drivers/accel/amdxdna/aie2_pm.c index 786d688bd82c..d9ccd7fc8a6d 100644 --- a/drivers/accel/amdxdna/aie2_pm.c +++ b/drivers/accel/amdxdna/aie2_pm.c @@ -74,7 +74,7 @@ int aie2_pm_init(struct amdxdna_dev_hdl *ndev) return ret; ndev->pw_mode = POWER_MODE_DEFAULT; - ndev->dft_dpm_level = ndev->max_dpm_level; + ndev->dft_dpm_level = 0; return 0; } diff --git a/drivers/accel/amdxdna/aie2_solver.c b/drivers/accel/amdxdna/aie2_solver.c index 3611e3268d79..6f3ee77d5264 100644 --- a/drivers/accel/amdxdna/aie2_solver.c +++ b/drivers/accel/amdxdna/aie2_solver.c @@ -52,7 +52,7 @@ static u32 calculate_gops(struct aie_qos *rqos) u32 service_rate = 0; if (rqos->latency) - service_rate = (1000 / rqos->latency); + service_rate = max_t(u32, 1000 / rqos->latency, 1); if (rqos->fps > service_rate) return rqos->fps * rqos->gops; @@ -348,6 +348,7 @@ int xrs_release_resource(void *hdl, u64 rid) { struct solver_state *xrs = hdl; struct solver_node *node; + u32 level = 0; node = rg_search_node(&xrs->rgp, rid); if (!node) { @@ -358,6 +359,13 @@ int xrs_release_resource(void *hdl, u64 rid) xrs->cfg.actions->unload(node->cb_arg); remove_solver_node(&xrs->rgp, node); + /* set the dpm level which fits all the sessions */ + list_for_each_entry(node, &xrs->rgp.node_list, list) { + if (node->dpm_level > level) + level = node->dpm_level; + } + xrs->cfg.actions->set_dft_dpm_level(xrs->cfg.ddev, level); + return 0; } diff --git a/drivers/accel/amdxdna/npu1_regs.c b/drivers/accel/amdxdna/npu1_regs.c index d7e50c6b06ef..4e48c030a69f 100644 --- a/drivers/accel/amdxdna/npu1_regs.c +++ b/drivers/accel/amdxdna/npu1_regs.c @@ -97,6 +97,7 @@ static const struct amdxdna_dev_priv npu1_dev_priv = { .rt_config = npu1_default_rt_cfg, .dpm_clk_tbl = npu1_dpm_clk_table, .col_align = COL_ALIGN_NONE, + .col_opc = 2048, .mbox_dev_addr = NPU1_MBOX_BAR_BASE, .mbox_size = 0, /* Use BAR size */ .sram_dev_addr = NPU1_SRAM_BAR_BASE, diff --git a/drivers/accel/amdxdna/npu4_regs.c b/drivers/accel/amdxdna/npu4_regs.c index 935999ced70f..eddc31803a50 100644 --- a/drivers/accel/amdxdna/npu4_regs.c +++ b/drivers/accel/amdxdna/npu4_regs.c @@ -160,6 +160,7 @@ static const struct amdxdna_dev_priv npu4_dev_priv = { .rt_config = npu4_default_rt_cfg, .dpm_clk_tbl = npu4_dpm_clk_table, .col_align = COL_ALIGN_NATURE, + .col_opc = 4096, .mbox_dev_addr = NPU4_MBOX_BAR_BASE, .mbox_size = 0, /* Use BAR size */ .sram_dev_addr = NPU4_SRAM_BAR_BASE, diff --git a/drivers/accel/amdxdna/npu5_regs.c b/drivers/accel/amdxdna/npu5_regs.c index 795bd1996845..a9102978e4a8 100644 --- a/drivers/accel/amdxdna/npu5_regs.c +++ b/drivers/accel/amdxdna/npu5_regs.c @@ -67,6 +67,7 @@ static const struct amdxdna_dev_priv npu5_dev_priv = { .rt_config = npu4_default_rt_cfg, .dpm_clk_tbl = npu4_dpm_clk_table, .col_align = COL_ALIGN_NATURE, + .col_opc = 4096, .mbox_dev_addr = NPU5_MBOX_BAR_BASE, .mbox_size = 0, /* Use BAR size */ .sram_dev_addr = NPU5_SRAM_BAR_BASE, diff --git a/drivers/accel/amdxdna/npu6_regs.c b/drivers/accel/amdxdna/npu6_regs.c index 3125d1ce45ab..e0db3a09740b 100644 --- a/drivers/accel/amdxdna/npu6_regs.c +++ b/drivers/accel/amdxdna/npu6_regs.c @@ -67,6 +67,7 @@ static const struct amdxdna_dev_priv npu6_dev_priv = { .rt_config = npu4_default_rt_cfg, .dpm_clk_tbl = npu4_dpm_clk_table, .col_align = COL_ALIGN_NATURE, + .col_opc = 4096, .mbox_dev_addr = NPU6_MBOX_BAR_BASE, .mbox_size = 0, /* Use BAR size */ .sram_dev_addr = NPU6_SRAM_BAR_BASE, From 4ee91aadeee48f57b0988ecb63eb526064bbb180 Mon Sep 17 00:00:00 2001 From: Nishad Saraf Date: Thu, 23 Apr 2026 21:08:24 -0700 Subject: [PATCH 015/145] accel/amdxdna: Set the system efficiency factor to 2 The system efficiency factor is used for QoS calculation. Change it to 2 to account for the efficiency overhead. Signed-off-by: Nishad Saraf Reviewed-by: Mario Limonciello (AMD) Signed-off-by: Lizhi Hou Link: https://patch.msgid.link/20260424040824.2253607-3-lizhi.hou@amd.com --- drivers/accel/amdxdna/aie2_pci.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/accel/amdxdna/aie2_pci.c b/drivers/accel/amdxdna/aie2_pci.c index a07e453a1721..f0ddb843eb21 100644 --- a/drivers/accel/amdxdna/aie2_pci.c +++ b/drivers/accel/amdxdna/aie2_pci.c @@ -595,7 +595,7 @@ static int aie2_init(struct amdxdna_dev *xdna) xrs_cfg.clk_list.num_levels = ndev->max_dpm_level + 1; for (i = 0; i < xrs_cfg.clk_list.num_levels; i++) xrs_cfg.clk_list.cu_clk_list[i] = ndev->priv->dpm_clk_tbl[i].hclk; - xrs_cfg.sys_eff_factor = 1; + xrs_cfg.sys_eff_factor = 2; xrs_cfg.ddev = &xdna->ddev; xrs_cfg.actions = &aie2_xrs_actions; xrs_cfg.total_col = ndev->total_col; From e22bb770b01dc65c29553013e6278a84fc3c3d73 Mon Sep 17 00:00:00 2001 From: Nishad Saraf Date: Thu, 23 Apr 2026 21:08:23 -0700 Subject: [PATCH 016/145] accel/amdxdna: Add configuring low and medium power mode Add support for POWER_MODE_LOW and POWER_MODE_MEDIUM. Signed-off-by: Nishad Saraf Reviewed-by: Mario Limonciello (AMD) Signed-off-by: Lizhi Hou Link: https://patch.msgid.link/20260424040824.2253607-2-lizhi.hou@amd.com --- drivers/accel/amdxdna/aie2_pm.c | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/drivers/accel/amdxdna/aie2_pm.c b/drivers/accel/amdxdna/aie2_pm.c index d9ccd7fc8a6d..4fe6030d2c41 100644 --- a/drivers/accel/amdxdna/aie2_pm.c +++ b/drivers/accel/amdxdna/aie2_pm.c @@ -108,6 +108,14 @@ int aie2_pm_set_mode(struct amdxdna_dev_hdl *ndev, enum amdxdna_power_mode_type clk_gating = AIE2_CLK_GATING_ENABLE; dpm_level = ndev->dft_dpm_level; break; + case POWER_MODE_LOW: + clk_gating = AIE2_CLK_GATING_ENABLE; + dpm_level = 0; + break; + case POWER_MODE_MEDIUM: + clk_gating = AIE2_CLK_GATING_ENABLE; + dpm_level = ndev->max_dpm_level / 2; + break; default: return -EOPNOTSUPP; } From ef1b53284175f6d57d81c8b4d99e33a6080cd9f6 Mon Sep 17 00:00:00 2001 From: Marco Crivellari Date: Fri, 31 Oct 2025 11:20:19 +0100 Subject: [PATCH 017/145] drm/nouveau: replace use of system_unbound_wq with system_dfl_wq Currently if a user enqueue a work item using schedule_delayed_work() the used wq is "system_wq" (per-cpu wq) while queue_delayed_work() use WORK_CPU_UNBOUND (used when a cpu is not specified). The same applies to schedule_work() that is using system_wq and queue_work(), that makes use again of WORK_CPU_UNBOUND. This lack of consistency cannot be addressed without refactoring the API. system_unbound_wq should be the default workqueue so as not to enforce locality constraints for random work whenever it's not required. Adding system_dfl_wq to encourage its use when unbound work should be used. The old system_unbound_wq will be kept for a few release cycles. Suggested-by: Tejun Heo Signed-off-by: Marco Crivellari Acked-by: Thomas Zimmermann Link: https://patch.msgid.link/20251031102020.95349-2-marco.crivellari@suse.com Signed-off-by: Danilo Krummrich --- drivers/gpu/drm/nouveau/dispnv50/disp.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/gpu/drm/nouveau/dispnv50/disp.c b/drivers/gpu/drm/nouveau/dispnv50/disp.c index 6c3a8712d38a..04b6fa3ee2ae 100644 --- a/drivers/gpu/drm/nouveau/dispnv50/disp.c +++ b/drivers/gpu/drm/nouveau/dispnv50/disp.c @@ -2474,7 +2474,7 @@ nv50_disp_atomic_commit(struct drm_device *dev, pm_runtime_get_noresume(dev->dev); if (nonblock) - queue_work(system_unbound_wq, &state->commit_work); + queue_work(system_dfl_wq, &state->commit_work); else nv50_disp_atomic_commit_tail(state); From c82a16b0caac5799333bd3dc63c12ab4c6ee13b4 Mon Sep 17 00:00:00 2001 From: Marco Crivellari Date: Fri, 31 Oct 2025 11:20:20 +0100 Subject: [PATCH 018/145] drm/nouveau: WQ_PERCPU added to alloc_workqueue users MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Currently if a user enqueue a work item using schedule_delayed_work() the used wq is "system_wq" (per-cpu wq) while queue_delayed_work() use WORK_CPU_UNBOUND (used when a cpu is not specified). The same applies to schedule_work() that is using system_wq and queue_work(), that makes use again of WORK_CPU_UNBOUND. This lack of consistentcy cannot be addressed without refactoring the API. alloc_workqueue() treats all queues as per-CPU by default, while unbound workqueues must opt-in via WQ_UNBOUND. This default is suboptimal: most workloads benefit from unbound queues, allowing the scheduler to place worker threads where they’re needed and reducing noise when CPUs are isolated. This change adds a new WQ_PERCPU flag to explicitly request alloc_workqueue() to be per-cpu when WQ_UNBOUND has not been specified. With the introduction of the WQ_PERCPU flag (equivalent to !WQ_UNBOUND), any alloc_workqueue() caller that doesn’t explicitly specify WQ_UNBOUND must now use WQ_PERCPU. Once migration is complete, WQ_UNBOUND can be removed and unbound will become the implicit default. Suggested-by: Tejun Heo Signed-off-by: Marco Crivellari Link: https://patch.msgid.link/20251031102020.95349-3-marco.crivellari@suse.com Signed-off-by: Danilo Krummrich --- drivers/gpu/drm/nouveau/nouveau_drm.c | 2 +- drivers/gpu/drm/nouveau/nouveau_sched.c | 3 ++- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/drivers/gpu/drm/nouveau/nouveau_drm.c b/drivers/gpu/drm/nouveau/nouveau_drm.c index 517ff2c31dce..e16f59b00f6f 100644 --- a/drivers/gpu/drm/nouveau/nouveau_drm.c +++ b/drivers/gpu/drm/nouveau/nouveau_drm.c @@ -632,7 +632,7 @@ nouveau_drm_device_init(struct nouveau_drm *drm) struct drm_device *dev = drm->dev; int ret; - drm->sched_wq = alloc_workqueue("nouveau_sched_wq_shared", 0, + drm->sched_wq = alloc_workqueue("nouveau_sched_wq_shared", WQ_PERCPU, WQ_MAX_ACTIVE); if (!drm->sched_wq) return -ENOMEM; diff --git a/drivers/gpu/drm/nouveau/nouveau_sched.c b/drivers/gpu/drm/nouveau/nouveau_sched.c index 179edf90a531..2cbae003d6de 100644 --- a/drivers/gpu/drm/nouveau/nouveau_sched.c +++ b/drivers/gpu/drm/nouveau/nouveau_sched.c @@ -413,7 +413,8 @@ nouveau_sched_init(struct nouveau_sched *sched, struct nouveau_drm *drm, int ret; if (!wq) { - wq = alloc_workqueue("nouveau_sched_wq_%d", 0, WQ_MAX_ACTIVE, + wq = alloc_workqueue("nouveau_sched_wq_%d", WQ_PERCPU, + WQ_MAX_ACTIVE, current->pid); if (!wq) return -ENOMEM; From 7455a0583a906533041a80e48c6a2e3230cce96e Mon Sep 17 00:00:00 2001 From: Andrzej Kacprowski Date: Wed, 8 Apr 2026 17:01:52 +0200 Subject: [PATCH 019/145] accel/ivpu: Add support for limiting NPU frequency Add configurable frequency limits to allow users to constrain the NPU operating frequency range for power and thermal management. This support requires firmware API version 3.34.0 or newer. New sysfs interface: The freq/ subdirectory contains the following attributes: - hw_min_freq: Minimum frequency supported by hardware (read-only) - hw_max_freq: Maximum frequency supported by hardware (read-only) - hw_efficient_freq: Hardware's optimal operating frequency (read-only) - current_freq: Current NPU frequency in MHz (read-only) - set_min_freq: Configure minimum operating frequency (50XX+ devices) - set_max_freq: Configure maximum operating frequency (50XX+ devices) Legacy attributes npu_max_frequency_mhz and npu_current_frequency_mhz are maintained for backward compatibility. Implementation details: - Frequency configuration is communicated to firmware via JSM messages - User-specified frequency values are clamped to hardware limits - Power-efficient frequency (pn_ratio) is adjusted dynamically to stay within the configured range - Frequency configuration is initialized during device boot - The JSM API header is updated to version 3.34.0 to support the new VPU_JSM_MSG_FREQ_CONFIG firmware message Added description for the sysfs attributes in the Documentation/ABI. Signed-off-by: Andrzej Kacprowski Reviewed-by: Karol Wachowski Signed-off-by: Karol Wachowski Link: https://patch.msgid.link/20260408150152.2093638-1-andrzej.kacprowski@linux.intel.com --- Documentation/ABI/obsolete/sysfs-driver-ivpu | 30 +++ Documentation/ABI/testing/sysfs-driver-ivpu | 65 +++++++ MAINTAINERS | 2 + drivers/accel/ivpu/ivpu_drv.c | 8 +- drivers/accel/ivpu/ivpu_hw.h | 16 +- drivers/accel/ivpu/ivpu_hw_btrs.c | 112 ++++++++--- drivers/accel/ivpu/ivpu_hw_btrs.h | 10 +- drivers/accel/ivpu/ivpu_jsm_msg.c | 18 +- drivers/accel/ivpu/ivpu_jsm_msg.h | 3 +- drivers/accel/ivpu/ivpu_sysfs.c | 190 ++++++++++++++++--- drivers/accel/ivpu/vpu_jsm_api.h | 34 +++- 11 files changed, 421 insertions(+), 67 deletions(-) create mode 100644 Documentation/ABI/obsolete/sysfs-driver-ivpu create mode 100644 Documentation/ABI/testing/sysfs-driver-ivpu diff --git a/Documentation/ABI/obsolete/sysfs-driver-ivpu b/Documentation/ABI/obsolete/sysfs-driver-ivpu new file mode 100644 index 000000000000..b906e7149729 --- /dev/null +++ b/Documentation/ABI/obsolete/sysfs-driver-ivpu @@ -0,0 +1,30 @@ +What: /sys/bus/pci/drivers/intel_vpu/.../sched_mode +Date: October 2024 +KernelVersion: 6.12 +Contact: dri-devel@lists.freedesktop.org +Description: Current NPU scheduling mode. Returns one of the following strings: + - "HW" - Hardware Scheduler mode + - "OS" - Operating System Scheduler mode + Read-only. + Deprecated since the "OS" scheduling mode is not usable + and will be removed from future versions of the driver. + Will be removed in 2027 + +What: /sys/bus/pci/drivers/intel_vpu/.../npu_max_frequency_mhz +Date: April 2025 +KernelVersion: 6.15 +Contact: dri-devel@lists.freedesktop.org +Description: Legacy alias for /sys/bus/pci/drivers/intel_vpu/.../freq/hw_max_freq. + Shows maximum frequency in MHz of the NPU's data processing unit. + Read-only. + Will be removed in 2027 + +What: /sys/bus/pci/drivers/intel_vpu/.../npu_current_frequency_mhz +Date: April 2025 +KernelVersion: 6.15 +Contact: dri-devel@lists.freedesktop.org +Description: Legacy alias for /sys/bus/pci/drivers/intel_vpu/.../freq/current_freq. + Shows current frequency in MHz of the NPU's data processing unit. + The value is read only when the device is active; otherwise it returns 0. + Read-only. + Will be removed in 2027 diff --git a/Documentation/ABI/testing/sysfs-driver-ivpu b/Documentation/ABI/testing/sysfs-driver-ivpu new file mode 100644 index 000000000000..91685774edfc --- /dev/null +++ b/Documentation/ABI/testing/sysfs-driver-ivpu @@ -0,0 +1,65 @@ +What: /sys/bus/pci/drivers/intel_vpu/.../npu_busy_time_us +Date: May 2024 +KernelVersion: 6.11 +Contact: dri-devel@lists.freedesktop.org +Description: Time in microseconds that the device spent executing jobs. The time is + counted when and only when there are jobs submitted to firmware. This time + can be used to measure the utilization of NPU, either by calculating the + difference between two timepoints or monitoring utilization percentage by + reading periodically. Recommended read period is 1 second to avoid impact + on job submission performance. Read-only. + +What: /sys/bus/pci/drivers/intel_vpu/.../npu_memory_utilization +Date: Jan 2025 +KernelVersion: 6.15 +Contact: dri-devel@lists.freedesktop.org +Description: Current NPU memory utilization in bytes. Reports the total size of all + resident buffer objects allocated for NPU use. Read-only. + +What: /sys/bus/pci/drivers/intel_vpu/.../freq/hw_min_freq +Date: April 2026 +KernelVersion: 7.2 +Contact: dri-devel@lists.freedesktop.org +Description: Minimum frequency in MHz supported by the NPU hardware. This is a + hardware capability and cannot be changed. Read-only. + +What: /sys/bus/pci/drivers/intel_vpu/.../freq/hw_efficient_freq +Date: April 2026 +KernelVersion: 7.2 +Contact: dri-devel@lists.freedesktop.org +Description: Most efficient operating frequency in MHz for the NPU. This represents + the frequency at which the NPU operates most efficiently in terms of power + and performance. Read-only. + +What: /sys/bus/pci/drivers/intel_vpu/.../freq/hw_max_freq +Date: April 2026 +KernelVersion: 7.2 +Contact: dri-devel@lists.freedesktop.org +Description: Maximum frequency in MHz supported by the NPU hardware. This is a + hardware capability and cannot be changed. Read-only. + +What: /sys/bus/pci/drivers/intel_vpu/.../freq/current_freq +Date: April 2026 +KernelVersion: 7.2 +Contact: dri-devel@lists.freedesktop.org +Description: Current operating frequency in MHz of the NPU. The value is valid only + when the device is active; returns 0 when idle. The actual frequency may + be lower than the requested range due to power or thermal constraints. + Read-only. + +What: /sys/bus/pci/drivers/intel_vpu/.../freq/set_min_freq +Date: April 2026 +KernelVersion: 7.2 +Contact: dri-devel@lists.freedesktop.org +Description: Configured minimum operating frequency in MHz (50XX devices and newer). + Values written are clamped to hardware limits (hw_min_freq to hw_max_freq). + If set_min_freq exceeds set_max_freq, the driver clamps set_min_freq to + set_max_freq when selecting the operating frequency. Read-write. + +What: /sys/bus/pci/drivers/intel_vpu/.../freq/set_max_freq +Date: April 2026 +KernelVersion: 7.2 +Contact: dri-devel@lists.freedesktop.org +Description: Configured maximum operating frequency in MHz (50XX devices and newer). + Values written are clamped to hardware limits (hw_min_freq to hw_max_freq). + Read-write. diff --git a/MAINTAINERS b/MAINTAINERS index 2fb1c75afd16..74d114884b34 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -7840,6 +7840,8 @@ M: Karol Wachowski L: dri-devel@lists.freedesktop.org S: Supported T: git https://gitlab.freedesktop.org/drm/misc/kernel.git +F: Documentation/ABI/obsolete/sysfs-driver-ivpu +F: Documentation/ABI/testing/sysfs-driver-ivpu F: drivers/accel/ivpu/ F: include/uapi/drm/ivpu_accel.h diff --git a/drivers/accel/ivpu/ivpu_drv.c b/drivers/accel/ivpu/ivpu_drv.c index 2801378e3e19..e6d631108145 100644 --- a/drivers/accel/ivpu/ivpu_drv.c +++ b/drivers/accel/ivpu/ivpu_drv.c @@ -1,6 +1,6 @@ // SPDX-License-Identifier: GPL-2.0-only /* - * Copyright (C) 2020-2025 Intel Corporation + * Copyright (C) 2020-2026 Intel Corporation */ #include @@ -234,7 +234,7 @@ static int ivpu_get_param_ioctl(struct drm_device *dev, void *data, struct drm_f args->value = vdev->platform; break; case DRM_IVPU_PARAM_CORE_CLOCK_RATE: - args->value = ivpu_hw_dpu_max_freq_get(vdev); + args->value = ivpu_hw_btrs_pll_ratio_to_hz(vdev, vdev->hw->pll.max_ratio); break; case DRM_IVPU_PARAM_NUM_CONTEXTS: args->value = file_priv->user_limits->max_ctx_count; @@ -487,6 +487,10 @@ int ivpu_boot(struct ivpu_device *vdev) ret = ivpu_hw_sched_init(vdev); if (ret) goto err_disable_ipc; + + ret = ivpu_hw_btrs_cfg_freq_init(vdev); + if (ret) + goto err_disable_ipc; } return 0; diff --git a/drivers/accel/ivpu/ivpu_hw.h b/drivers/accel/ivpu/ivpu_hw.h index b6d0f0d0dccc..487a918e2fa9 100644 --- a/drivers/accel/ivpu/ivpu_hw.h +++ b/drivers/accel/ivpu/ivpu_hw.h @@ -1,6 +1,6 @@ /* SPDX-License-Identifier: GPL-2.0-only */ /* - * Copyright (C) 2020-2025 Intel Corporation + * Copyright (C) 2020-2026 Intel Corporation */ #ifndef __IVPU_HW_H__ @@ -28,6 +28,7 @@ struct ivpu_hw_info { struct ivpu_addr_range dma; } ranges; struct { + /* Hardware min and max pll ratio */ u8 min_ratio; u8 max_ratio; /* @@ -35,6 +36,9 @@ struct ivpu_hw_info { * performance to power ratio at this frequency. */ u8 pn_ratio; + /* Pll ratios configured via sysfs interface */ + u8 cfg_min_ratio; + u8 cfg_max_ratio; u32 profiling_freq; } pll; struct { @@ -80,16 +84,6 @@ static inline u64 ivpu_hw_range_size(const struct ivpu_addr_range *range) return range->end - range->start; } -static inline u32 ivpu_hw_dpu_max_freq_get(struct ivpu_device *vdev) -{ - return ivpu_hw_btrs_dpu_max_freq_get(vdev); -} - -static inline u32 ivpu_hw_dpu_freq_get(struct ivpu_device *vdev) -{ - return ivpu_hw_btrs_dpu_freq_get(vdev); -} - static inline void ivpu_hw_irq_clear(struct ivpu_device *vdev) { ivpu_hw_ip_irq_clear(vdev); diff --git a/drivers/accel/ivpu/ivpu_hw_btrs.c b/drivers/accel/ivpu/ivpu_hw_btrs.c index 06e65c592618..dac935164e11 100644 --- a/drivers/accel/ivpu/ivpu_hw_btrs.c +++ b/drivers/accel/ivpu/ivpu_hw_btrs.c @@ -1,6 +1,6 @@ // SPDX-License-Identifier: GPL-2.0-only /* - * Copyright (C) 2020-2025 Intel Corporation + * Copyright (C) 2020-2026 Intel Corporation */ #include @@ -11,6 +11,7 @@ #include "ivpu_hw_btrs_lnl_reg.h" #include "ivpu_hw_btrs_mtl_reg.h" #include "ivpu_hw_reg_io.h" +#include "ivpu_jsm_msg.h" #include "ivpu_pm.h" #define BTRS_MTL_IRQ_MASK ((REG_FLD(VPU_HW_BTRS_MTL_INTERRUPT_STAT, ATS_ERR)) | \ @@ -33,8 +34,7 @@ #define PLL_CDYN_DEFAULT 0x80 #define PLL_EPP_DEFAULT 0x80 -#define PLL_REF_CLK_FREQ 50000000ull -#define PLL_RATIO_TO_FREQ(x) ((x) * PLL_REF_CLK_FREQ) +#define PLL_REF_CLK_FREQ_MHZ 50 #define PLL_TIMEOUT_US (1500 * USEC_PER_MSEC) #define IDLE_TIMEOUT_US (5 * USEC_PER_MSEC) @@ -59,8 +59,6 @@ #define DCT_ENABLE 0x1 #define DCT_DISABLE 0x0 -static u32 pll_ratio_to_dpu_freq(struct ivpu_device *vdev, u32 ratio); - int ivpu_hw_btrs_irqs_clear_with_0_mtl(struct ivpu_device *vdev) { REGB_WR32(VPU_HW_BTRS_MTL_INTERRUPT_STAT, BTRS_MTL_ALL_IRQ_MASK); @@ -111,6 +109,8 @@ void ivpu_hw_btrs_freq_ratios_init(struct ivpu_device *vdev) hw->pll.min_ratio = clamp_t(u8, ivpu_pll_min_ratio, hw->pll.min_ratio, hw->pll.max_ratio); hw->pll.max_ratio = clamp_t(u8, ivpu_pll_max_ratio, hw->pll.min_ratio, hw->pll.max_ratio); hw->pll.pn_ratio = clamp_t(u8, hw->pll.pn_ratio, hw->pll.min_ratio, hw->pll.max_ratio); + hw->pll.cfg_max_ratio = hw->pll.max_ratio; + hw->pll.cfg_min_ratio = hw->pll.min_ratio; } static bool tile_disable_check(u32 config) @@ -341,8 +341,8 @@ int ivpu_hw_btrs_wp_drive(struct ivpu_device *vdev, bool enable) prepare_wp_request(vdev, &wp, enable); - ivpu_dbg(vdev, PM, "PLL workpoint request: %lu MHz, config: 0x%x, epp: 0x%x, cdyn: 0x%x\n", - pll_ratio_to_dpu_freq(vdev, wp.target) / HZ_PER_MHZ, wp.cfg, wp.epp, wp.cdyn); + ivpu_dbg(vdev, PM, "PLL workpoint request: %u MHz, config: 0x%x, epp: 0x%x, cdyn: 0x%x\n", + ivpu_hw_btrs_pll_ratio_to_mhz(vdev, wp.target), wp.cfg, wp.epp, wp.cdyn); ret = wp_request_send(vdev, &wp); if (ret) { @@ -598,35 +598,101 @@ static u32 pll_config_get_lnl(struct ivpu_device *vdev) return REGB_RD32(VPU_HW_BTRS_LNL_PLL_FREQ); } -static u32 pll_ratio_to_dpu_freq_mtl(u16 ratio) +static u32 pll_ratio_to_mhz_mtl(u8 pll_ratio) { - return (PLL_RATIO_TO_FREQ(ratio) * 2) / 3; + return (pll_ratio * PLL_REF_CLK_FREQ_MHZ * 2) / 3; } -static u32 pll_ratio_to_dpu_freq_lnl(u16 ratio) +static u32 pll_ratio_to_mhz_lnl(u8 pll_ratio) { - return PLL_RATIO_TO_FREQ(ratio) / 2; + return (pll_ratio * PLL_REF_CLK_FREQ_MHZ) / 2; } -static u32 pll_ratio_to_dpu_freq(struct ivpu_device *vdev, u32 ratio) +u32 ivpu_hw_btrs_pll_ratio_to_mhz(struct ivpu_device *vdev, u8 pll_ratio) { if (ivpu_hw_btrs_gen(vdev) == IVPU_HW_BTRS_MTL) - return pll_ratio_to_dpu_freq_mtl(ratio); + return pll_ratio_to_mhz_mtl(pll_ratio); else - return pll_ratio_to_dpu_freq_lnl(ratio); + return pll_ratio_to_mhz_lnl(pll_ratio); } -u32 ivpu_hw_btrs_dpu_max_freq_get(struct ivpu_device *vdev) +u32 ivpu_hw_btrs_pll_ratio_to_hz(struct ivpu_device *vdev, u8 pll_ratio) { - return pll_ratio_to_dpu_freq(vdev, vdev->hw->pll.max_ratio); + return ivpu_hw_btrs_pll_ratio_to_mhz(vdev, pll_ratio) * HZ_PER_MHZ; } -u32 ivpu_hw_btrs_dpu_freq_get(struct ivpu_device *vdev) +u32 ivpu_hw_btrs_current_freq_get(struct ivpu_device *vdev) { if (ivpu_hw_btrs_gen(vdev) == IVPU_HW_BTRS_MTL) - return pll_ratio_to_dpu_freq_mtl(pll_config_get_mtl(vdev)); + return pll_ratio_to_mhz_mtl(pll_config_get_mtl(vdev)); else - return pll_ratio_to_dpu_freq_lnl(pll_config_get_lnl(vdev)); + return pll_ratio_to_mhz_lnl(pll_config_get_lnl(vdev)); +} + +static int ivpu_hw_btrs_cfg_freq_set(struct ivpu_device *vdev, u8 cfg_min_ratio, u8 cfg_max_ratio) +{ + u8 min_ratio = clamp_t(u8, cfg_min_ratio, vdev->hw->pll.min_ratio, cfg_max_ratio); + u8 pn_ratio = clamp_t(u8, vdev->hw->pll.pn_ratio, min_ratio, cfg_max_ratio); + int ret; + + ivpu_dbg(vdev, PM, "Set frequency range to min: %u, pn: %u, max: %u MHz\n", + ivpu_hw_btrs_pll_ratio_to_mhz(vdev, min_ratio), + ivpu_hw_btrs_pll_ratio_to_mhz(vdev, pn_ratio), + ivpu_hw_btrs_pll_ratio_to_mhz(vdev, cfg_max_ratio)); + + ret = ivpu_rpm_get(vdev); + if (ret < 0) + return ret; + + ret = ivpu_jsm_msg_freq_config(vdev, min_ratio, pn_ratio, cfg_max_ratio); + ivpu_rpm_put(vdev); + + if (ret) { + ivpu_warn(vdev, + "Failed to set frequency to min: %u, pn: %u, max: %u MHz, ret %d\n", + ivpu_hw_btrs_pll_ratio_to_mhz(vdev, min_ratio), + ivpu_hw_btrs_pll_ratio_to_mhz(vdev, pn_ratio), + ivpu_hw_btrs_pll_ratio_to_mhz(vdev, cfg_max_ratio), + ret); + return ret; + } + + vdev->hw->pll.cfg_min_ratio = cfg_min_ratio; + vdev->hw->pll.cfg_max_ratio = cfg_max_ratio; + + return 0; +} + +static u8 dpu_mhz_to_pll_ratio_lnl(u32 freq_mhz) +{ + return clamp_t(u32, freq_mhz / (PLL_REF_CLK_FREQ_MHZ / 2), 0, U8_MAX); +} + +int ivpu_hw_btrs_cfg_max_freq_set(struct ivpu_device *vdev, u32 max_freq_mhz) +{ + u8 ratio = dpu_mhz_to_pll_ratio_lnl(max_freq_mhz); + u8 cfg_max_ratio = clamp_t(u8, ratio, vdev->hw->pll.min_ratio, vdev->hw->pll.max_ratio); + + return ivpu_hw_btrs_cfg_freq_set(vdev, vdev->hw->pll.cfg_min_ratio, cfg_max_ratio); +} + +int ivpu_hw_btrs_cfg_min_freq_set(struct ivpu_device *vdev, u32 min_freq_mhz) +{ + u8 ratio = dpu_mhz_to_pll_ratio_lnl(min_freq_mhz); + u8 cfg_min_ratio = clamp_t(u8, ratio, vdev->hw->pll.min_ratio, vdev->hw->pll.max_ratio); + + return ivpu_hw_btrs_cfg_freq_set(vdev, cfg_min_ratio, vdev->hw->pll.cfg_max_ratio); +} + +int ivpu_hw_btrs_cfg_freq_init(struct ivpu_device *vdev) +{ + if (vdev->hw->pll.min_ratio == vdev->hw->pll.cfg_min_ratio && + vdev->hw->pll.max_ratio == vdev->hw->pll.cfg_max_ratio) + return 0; + + return ivpu_hw_btrs_cfg_freq_set(vdev, + vdev->hw->pll.cfg_min_ratio, + vdev->hw->pll.cfg_max_ratio); } /* Handler for IRQs from Buttress core (irqB) */ @@ -641,8 +707,8 @@ bool ivpu_hw_btrs_irq_handler_mtl(struct ivpu_device *vdev, int irq) if (REG_TEST_FLD(VPU_HW_BTRS_MTL_INTERRUPT_STAT, FREQ_CHANGE, status)) { u32 pll = pll_config_get_mtl(vdev); - ivpu_dbg(vdev, IRQ, "FREQ_CHANGE irq, wp %08x, %lu MHz", - pll, pll_ratio_to_dpu_freq_mtl(pll) / HZ_PER_MHZ); + ivpu_dbg(vdev, IRQ, "FREQ_CHANGE irq, wp %08x, %u MHz", + pll, pll_ratio_to_mhz_mtl(pll)); } if (REG_TEST_FLD(VPU_HW_BTRS_MTL_INTERRUPT_STAT, ATS_ERR, status)) { @@ -695,8 +761,8 @@ bool ivpu_hw_btrs_irq_handler_lnl(struct ivpu_device *vdev, int irq) if (REG_TEST_FLD(VPU_HW_BTRS_LNL_INTERRUPT_STAT, FREQ_CHANGE, status)) { u32 pll = pll_config_get_lnl(vdev); - ivpu_dbg(vdev, IRQ, "FREQ_CHANGE irq, wp %08x, %lu MHz", - pll, pll_ratio_to_dpu_freq_lnl(pll) / HZ_PER_MHZ); + ivpu_dbg(vdev, IRQ, "FREQ_CHANGE irq, wp %08x, %u MHz", + pll, pll_ratio_to_mhz_lnl(pll)); } if (REG_TEST_FLD(VPU_HW_BTRS_LNL_INTERRUPT_STAT, ATS_ERR, status)) { diff --git a/drivers/accel/ivpu/ivpu_hw_btrs.h b/drivers/accel/ivpu/ivpu_hw_btrs.h index c4c10e22f30f..d6343d734570 100644 --- a/drivers/accel/ivpu/ivpu_hw_btrs.h +++ b/drivers/accel/ivpu/ivpu_hw_btrs.h @@ -1,6 +1,6 @@ /* SPDX-License-Identifier: GPL-2.0-only */ /* - * Copyright (C) 2020-2025 Intel Corporation + * Copyright (C) 2020-2026 Intel Corporation */ #ifndef __IVPU_HW_BTRS_H__ @@ -31,8 +31,12 @@ int ivpu_hw_btrs_ip_reset(struct ivpu_device *vdev); void ivpu_hw_btrs_profiling_freq_reg_set_lnl(struct ivpu_device *vdev); void ivpu_hw_btrs_ats_print_lnl(struct ivpu_device *vdev); void ivpu_hw_btrs_clock_relinquish_disable_lnl(struct ivpu_device *vdev); -u32 ivpu_hw_btrs_dpu_max_freq_get(struct ivpu_device *vdev); -u32 ivpu_hw_btrs_dpu_freq_get(struct ivpu_device *vdev); +u32 ivpu_hw_btrs_pll_ratio_to_mhz(struct ivpu_device *vdev, u8 pll_ratio); +u32 ivpu_hw_btrs_pll_ratio_to_hz(struct ivpu_device *vdev, u8 pll_ratio); +u32 ivpu_hw_btrs_current_freq_get(struct ivpu_device *vdev); +int ivpu_hw_btrs_cfg_min_freq_set(struct ivpu_device *vdev, u32 freq_mhz); +int ivpu_hw_btrs_cfg_max_freq_set(struct ivpu_device *vdev, u32 freq_mhz); +int ivpu_hw_btrs_cfg_freq_init(struct ivpu_device *vdev); bool ivpu_hw_btrs_irq_handler_mtl(struct ivpu_device *vdev, int irq); bool ivpu_hw_btrs_irq_handler_lnl(struct ivpu_device *vdev, int irq); int ivpu_hw_btrs_dct_get_request(struct ivpu_device *vdev, bool *enable); diff --git a/drivers/accel/ivpu/ivpu_jsm_msg.c b/drivers/accel/ivpu/ivpu_jsm_msg.c index 07b1d6f615a9..17b42a76aef9 100644 --- a/drivers/accel/ivpu/ivpu_jsm_msg.c +++ b/drivers/accel/ivpu/ivpu_jsm_msg.c @@ -1,6 +1,6 @@ // SPDX-License-Identifier: GPL-2.0-only /* - * Copyright (C) 2020-2024 Intel Corporation + * Copyright (C) 2020-2026 Intel Corporation */ #include "ivpu_drv.h" @@ -86,6 +86,9 @@ const char *ivpu_jsm_msg_type_to_str(enum vpu_ipc_msg_type type) IVPU_CASE_TO_STR(VPU_JSM_MSG_DCT_ENABLE_DONE); IVPU_CASE_TO_STR(VPU_JSM_MSG_DCT_DISABLE); IVPU_CASE_TO_STR(VPU_JSM_MSG_DCT_DISABLE_DONE); + IVPU_CASE_TO_STR(VPU_JSM_MSG_FREQ_CONFIG); + IVPU_CASE_TO_STR(VPU_JSM_MSG_FREQ_CONFIG_RSP); + IVPU_CASE_TO_STR(VPU_JSM_MSG_RESERVED_111E); } #undef IVPU_CASE_TO_STR @@ -571,3 +574,16 @@ int ivpu_jsm_state_dump_no_reply(struct ivpu_device *vdev) return ivpu_ipc_send_and_wait(vdev, &req, VPU_IPC_CHAN_ASYNC_CMD, vdev->timeout.state_dump_msg); } + +int ivpu_jsm_msg_freq_config(struct ivpu_device *vdev, u16 min_ratio, u16 pn_ratio, u16 max_ratio) +{ + struct vpu_jsm_msg req = { .type = VPU_JSM_MSG_FREQ_CONFIG}; + struct vpu_jsm_msg resp; + + req.payload.freq_config.min_freq_pll_ratio = min_ratio; + req.payload.freq_config.pn_freq_pll_ratio = pn_ratio; + req.payload.freq_config.max_freq_pll_ratio = max_ratio; + + return ivpu_ipc_send_receive_internal(vdev, &req, VPU_JSM_MSG_FREQ_CONFIG_RSP, &resp, + VPU_IPC_CHAN_ASYNC_CMD, vdev->timeout.jsm); +} diff --git a/drivers/accel/ivpu/ivpu_jsm_msg.h b/drivers/accel/ivpu/ivpu_jsm_msg.h index a74f5a0b0d93..28ffe07422b0 100644 --- a/drivers/accel/ivpu/ivpu_jsm_msg.h +++ b/drivers/accel/ivpu/ivpu_jsm_msg.h @@ -1,6 +1,6 @@ /* SPDX-License-Identifier: GPL-2.0-only */ /* - * Copyright (C) 2020-2024 Intel Corporation + * Copyright (C) 2020-2026 Intel Corporation */ #ifndef __IVPU_JSM_MSG_H__ @@ -45,5 +45,6 @@ int ivpu_jsm_dct_enable(struct ivpu_device *vdev, u32 active_us, u32 inactive_us int ivpu_jsm_dct_disable(struct ivpu_device *vdev); int ivpu_jsm_state_dump(struct ivpu_device *vdev); int ivpu_jsm_state_dump_no_reply(struct ivpu_device *vdev); +int ivpu_jsm_msg_freq_config(struct ivpu_device *vdev, u16 min_ratio, u16 pn_ratio, u16 max_ratio); #endif diff --git a/drivers/accel/ivpu/ivpu_sysfs.c b/drivers/accel/ivpu/ivpu_sysfs.c index d250a10caca9..95d201b3b8aa 100644 --- a/drivers/accel/ivpu/ivpu_sysfs.c +++ b/drivers/accel/ivpu/ivpu_sysfs.c @@ -1,6 +1,6 @@ // SPDX-License-Identifier: GPL-2.0-only /* - * Copyright (C) 2024-2025 Intel Corporation + * Copyright (C) 2024-2026 Intel Corporation */ #include @@ -82,8 +82,7 @@ static DEVICE_ATTR_RO(npu_memory_utilization); * - "OS" - Operating System Scheduler mode * */ -static ssize_t -sched_mode_show(struct device *dev, struct device_attribute *attr, char *buf) +static ssize_t sched_mode_show(struct device *dev, struct device_attribute *attr, char *buf) { struct drm_device *drm = dev_get_drvdata(dev); struct ivpu_device *vdev = to_ivpu_device(drm); @@ -94,47 +93,162 @@ sched_mode_show(struct device *dev, struct device_attribute *attr, char *buf) static DEVICE_ATTR_RO(sched_mode); /** - * DOC: npu_max_frequency + * DOC: NPU frequency control and information * - * The npu_max_frequency shows maximum frequency in MHz of the NPU's data - * processing unit + * Hardware frequency capabilities: + * freq/hw_min_freq - Minimum frequency supported by the NPU hardware. + * freq/hw_max_freq - Maximum frequency supported by the NPU hardware. + * freq/hw_efficient_freq - Most efficient operating frequency for the NPU. + * + * Configurable frequency limits (50XX devices and newer): + * freq/set_min_freq - Configured minimum operating frequency. + * freq/set_max_freq - Configured maximum operating frequency. + * + * Clamping behavior: Values written to set_min_freq and set_max_freq are + * clamped to hardware limits. If set_min_freq exceeds set_max_freq, the driver + * clamps set_min_freq to set_max_freq when selecting the operating frequency. + * + * Current operating frequency: + * freq/current_freq - Current frequency in MHz. Valid only when the device is + * active; returns 0 when idle. May be lower than the requested range due to + * power or thermal constraints. + * + * Legacy attributes (backward compatibility): + * npu_max_frequency_mhz - Alias for freq/hw_max_freq. + * npu_current_frequency_mhz - Alias for freq/current_freq. */ -static ssize_t -npu_max_frequency_mhz_show(struct device *dev, struct device_attribute *attr, char *buf) + +static ssize_t hw_min_freq_show(struct device *dev, struct device_attribute *attr, char *buf) { struct drm_device *drm = dev_get_drvdata(dev); struct ivpu_device *vdev = to_ivpu_device(drm); - u32 freq = ivpu_hw_dpu_max_freq_get(vdev); + u32 freq_mhz = ivpu_hw_btrs_pll_ratio_to_mhz(vdev, vdev->hw->pll.min_ratio); - return sysfs_emit(buf, "%lu\n", freq / HZ_PER_MHZ); + return sysfs_emit(buf, "%u\n", freq_mhz); } -static DEVICE_ATTR_RO(npu_max_frequency_mhz); +static DEVICE_ATTR_RO(hw_min_freq); -/** - * DOC: npu_current_frequency_mhz - * - * The npu_current_frequency_mhz shows current frequency in MHz of the NPU's - * data processing unit - */ -static ssize_t -npu_current_frequency_mhz_show(struct device *dev, struct device_attribute *attr, char *buf) +static ssize_t hw_efficient_freq_show(struct device *dev, struct device_attribute *attr, char *buf) { struct drm_device *drm = dev_get_drvdata(dev); struct ivpu_device *vdev = to_ivpu_device(drm); - u32 freq = 0; + u32 freq_mhz = ivpu_hw_btrs_pll_ratio_to_mhz(vdev, vdev->hw->pll.pn_ratio); + + return sysfs_emit(buf, "%u\n", freq_mhz); +} + +static DEVICE_ATTR_RO(hw_efficient_freq); + +static ssize_t hw_max_freq_show(struct device *dev, struct device_attribute *attr, char *buf) +{ + struct drm_device *drm = dev_get_drvdata(dev); + struct ivpu_device *vdev = to_ivpu_device(drm); + u32 freq_mhz = ivpu_hw_btrs_pll_ratio_to_mhz(vdev, vdev->hw->pll.max_ratio); + + return sysfs_emit(buf, "%u\n", freq_mhz); +} + +static DEVICE_ATTR_RO(hw_max_freq); + +static ssize_t set_min_freq_show(struct device *dev, struct device_attribute *attr, char *buf) +{ + struct drm_device *drm = dev_get_drvdata(dev); + struct ivpu_device *vdev = to_ivpu_device(drm); + u32 freq_mhz = ivpu_hw_btrs_pll_ratio_to_mhz(vdev, vdev->hw->pll.cfg_min_ratio); + + return sysfs_emit(buf, "%u\n", freq_mhz); +} + +static ssize_t +set_min_freq_store(struct device *dev, struct device_attribute *attr, const char *buf, size_t count) +{ + struct drm_device *drm = dev_get_drvdata(dev); + struct ivpu_device *vdev = to_ivpu_device(drm); + u32 freq_mhz; + int ret; + + ret = kstrtou32(buf, 10, &freq_mhz); + if (ret) + return ret; + + ret = ivpu_hw_btrs_cfg_min_freq_set(vdev, freq_mhz); + if (ret) + return ret; + + return count; +} + +static DEVICE_ATTR_RW(set_min_freq); + +static ssize_t set_max_freq_show(struct device *dev, struct device_attribute *attr, char *buf) +{ + struct drm_device *drm = dev_get_drvdata(dev); + struct ivpu_device *vdev = to_ivpu_device(drm); + u32 freq_mhz = ivpu_hw_btrs_pll_ratio_to_mhz(vdev, vdev->hw->pll.cfg_max_ratio); + + return sysfs_emit(buf, "%u\n", freq_mhz); +} + +static ssize_t +set_max_freq_store(struct device *dev, struct device_attribute *attr, const char *buf, size_t count) +{ + struct drm_device *drm = dev_get_drvdata(dev); + struct ivpu_device *vdev = to_ivpu_device(drm); + u32 freq_mhz; + int ret; + + ret = kstrtou32(buf, 10, &freq_mhz); + if (ret) + return ret; + + /* Convert MHz to Hz and set max frequency */ + ret = ivpu_hw_btrs_cfg_max_freq_set(vdev, freq_mhz); + if (ret) + return ret; + + return count; +} + +static DEVICE_ATTR_RW(set_max_freq); + +static ssize_t current_freq_show(struct device *dev, struct device_attribute *attr, char *buf) +{ + struct drm_device *drm = dev_get_drvdata(dev); + struct ivpu_device *vdev = to_ivpu_device(drm); + u32 freq_mhz = 0; /* Read frequency only if device is active, otherwise frequency is 0 */ if (pm_runtime_get_if_active(vdev->drm.dev) > 0) { - freq = ivpu_hw_dpu_freq_get(vdev); + freq_mhz = ivpu_hw_btrs_current_freq_get(vdev); pm_runtime_put_autosuspend(vdev->drm.dev); } - return sysfs_emit(buf, "%lu\n", freq / HZ_PER_MHZ); + return sysfs_emit(buf, "%u\n", freq_mhz); } -static DEVICE_ATTR_RO(npu_current_frequency_mhz); +static DEVICE_ATTR_RO(current_freq); + +/* Alias to current_freq for legacy compat */ +static struct device_attribute dev_attr_npu_max_frequency_mhz = + __ATTR(npu_max_frequency_mhz, 0444, hw_max_freq_show, NULL); + +static struct device_attribute dev_attr_npu_current_frequency_mhz = + __ATTR(npu_current_frequency_mhz, 0444, current_freq_show, NULL); + +static struct attribute *ivpu_freq_attrs[] = { + &dev_attr_hw_min_freq.attr, + &dev_attr_hw_efficient_freq.attr, + &dev_attr_hw_max_freq.attr, + &dev_attr_current_freq.attr, + NULL, +}; + +static struct attribute_group ivpu_freq_attr_group = { + .name = "freq", + .attrs = ivpu_freq_attrs, +}; static struct attribute *ivpu_dev_attrs[] = { &dev_attr_npu_busy_time_us.attr, @@ -154,6 +268,32 @@ void ivpu_sysfs_init(struct ivpu_device *vdev) int ret; ret = devm_device_add_group(vdev->drm.dev, &ivpu_dev_attr_group); - if (ret) - ivpu_warn(vdev, "Failed to add group to device, ret %d", ret); + if (ret) { + ivpu_warn(vdev, "Failed to add sysfs group to device, ret %d", ret); + return; + } + + ret = devm_device_add_group(vdev->drm.dev, &ivpu_freq_attr_group); + if (ret) { + ivpu_warn(vdev, "Failed to add sysfs freq group, ret %d", ret); + return; + } + + if (ivpu_hw_ip_gen(vdev) >= IVPU_HW_IP_50XX) { + ret = sysfs_add_file_to_group(&vdev->drm.dev->kobj, + &dev_attr_set_min_freq.attr, + "freq"); + if (ret) { + ivpu_warn(vdev, "Failed to add sysfs set_min_freq to device, ret %d", ret); + return; + } + + ret = sysfs_add_file_to_group(&vdev->drm.dev->kobj, + &dev_attr_set_max_freq.attr, + "freq"); + if (ret) { + ivpu_warn(vdev, "Failed to add sysfs set_max_freq to device, ret %d", ret); + return; + } + } } diff --git a/drivers/accel/ivpu/vpu_jsm_api.h b/drivers/accel/ivpu/vpu_jsm_api.h index bca6a44dc041..6d58d04cc0c4 100644 --- a/drivers/accel/ivpu/vpu_jsm_api.h +++ b/drivers/accel/ivpu/vpu_jsm_api.h @@ -23,7 +23,7 @@ /* * Minor version changes when API backward compatibility is preserved. */ -#define VPU_JSM_API_VER_MINOR 33 +#define VPU_JSM_API_VER_MINOR 34 /* * API header changed (field names, documentation, formatting) but API itself has not been changed @@ -604,6 +604,16 @@ enum vpu_ipc_msg_type { * This command has no payload */ VPU_JSM_MSG_DCT_DISABLE = 0x111d, + /** + * Reserved command ID to ensure that the following command requests / + * responses have the same lower byte value. + */ + VPU_JSM_MSG_RESERVED_111E = 0x111e, + /** + * Control command: Configure VPU frequency scaling parameters. + * @see vpu_ipc_msg_payload_freq_config + */ + VPU_JSM_MSG_FREQ_CONFIG = 0x111f, /** * Dump VPU state. To be used for debug purposes only. * This command has no payload. @@ -766,6 +776,11 @@ enum vpu_ipc_msg_type { * This command has no payload */ VPU_JSM_MSG_DCT_DISABLE_DONE = 0x221e, + /** + * Response to control command: Configure VPU frequency scaling parameters. + * @see vpu_ipc_msg_payload_freq_config + */ + VPU_JSM_MSG_FREQ_CONFIG_RSP = 0x221f, /** * Response to state dump control command. * This command has no payload. @@ -1650,6 +1665,22 @@ struct vpu_ipc_msg_payload_pwr_dct_control { u32 dct_inactive_us; }; +/** + * Payload for @ref VPU_JSM_MSG_FREQ_CONFIG message. + * + * This payload allows the host to configure the VPU frequency scaling parameters. + */ +struct vpu_ipc_msg_payload_freq_config { + /** Minimum frequency PLL ratio */ + u32 min_freq_pll_ratio; + /** Efficiency frequency PLL ratio */ + u32 pn_freq_pll_ratio; + /** Maximum frequency PLL ratio */ + u32 max_freq_pll_ratio; + /** Reserved for 64-bit alignment */ + u32 reserved_0; +}; + /* * Payloads union, used to define complete message format. */ @@ -1692,6 +1723,7 @@ union vpu_ipc_msg_payload { struct vpu_ipc_msg_payload_hws_resume_engine hws_resume_engine; struct vpu_ipc_msg_payload_pwr_d0i3_enter pwr_d0i3_enter; struct vpu_ipc_msg_payload_pwr_dct_control pwr_dct_control; + struct vpu_ipc_msg_payload_freq_config freq_config; }; /** From 0c44d8dc6df9885a93d902867348a1ca5489a5b6 Mon Sep 17 00:00:00 2001 From: Jani Nikula Date: Wed, 8 Apr 2026 11:22:10 +0300 Subject: [PATCH 020/145] drm/atomic: prefer drm_printf_indent() over inline \t We have a helper drm_printf_indent() for tab indenting the prints. It makes the actual strings more readable, and highlights the indented parts better in source. Reviewed-by: Chaitanya Kumar Borah Link: https://patch.msgid.link/20260408082211.3040194-1-jani.nikula@intel.com Signed-off-by: Jani Nikula --- drivers/gpu/drm/drm_atomic.c | 110 +++++++++++++++++------------------ 1 file changed, 55 insertions(+), 55 deletions(-) diff --git a/drivers/gpu/drm/drm_atomic.c b/drivers/gpu/drm/drm_atomic.c index 41c57063f3b4..54bab7e9f935 100644 --- a/drivers/gpu/drm/drm_atomic.c +++ b/drivers/gpu/drm/drm_atomic.c @@ -463,19 +463,19 @@ static void drm_atomic_crtc_print_state(struct drm_printer *p, struct drm_crtc *crtc = state->crtc; drm_printf(p, "crtc[%u]: %s\n", crtc->base.id, crtc->name); - drm_printf(p, "\tenable=%d\n", state->enable); - drm_printf(p, "\tactive=%d\n", state->active); - drm_printf(p, "\tself_refresh_active=%d\n", state->self_refresh_active); - drm_printf(p, "\tplanes_changed=%d\n", state->planes_changed); - drm_printf(p, "\tmode_changed=%d\n", state->mode_changed); - drm_printf(p, "\tactive_changed=%d\n", state->active_changed); - drm_printf(p, "\tconnectors_changed=%d\n", state->connectors_changed); - drm_printf(p, "\tcolor_mgmt_changed=%d\n", state->color_mgmt_changed); - drm_printf(p, "\tplane_mask=%x\n", state->plane_mask); - drm_printf(p, "\tconnector_mask=%x\n", state->connector_mask); - drm_printf(p, "\tencoder_mask=%x\n", state->encoder_mask); - drm_printf(p, "\tmode: " DRM_MODE_FMT "\n", DRM_MODE_ARG(&state->mode)); - drm_printf(p, "\tbackground_color=%llx\n", state->background_color); + drm_printf_indent(p, 1, "enable=%d\n", state->enable); + drm_printf_indent(p, 1, "active=%d\n", state->active); + drm_printf_indent(p, 1, "self_refresh_active=%d\n", state->self_refresh_active); + drm_printf_indent(p, 1, "planes_changed=%d\n", state->planes_changed); + drm_printf_indent(p, 1, "mode_changed=%d\n", state->mode_changed); + drm_printf_indent(p, 1, "active_changed=%d\n", state->active_changed); + drm_printf_indent(p, 1, "connectors_changed=%d\n", state->connectors_changed); + drm_printf_indent(p, 1, "color_mgmt_changed=%d\n", state->color_mgmt_changed); + drm_printf_indent(p, 1, "plane_mask=%x\n", state->plane_mask); + drm_printf_indent(p, 1, "connector_mask=%x\n", state->connector_mask); + drm_printf_indent(p, 1, "encoder_mask=%x\n", state->encoder_mask); + drm_printf_indent(p, 1, "mode: " DRM_MODE_FMT "\n", DRM_MODE_ARG(&state->mode)); + drm_printf_indent(p, 1, "background_color=%llx\n", state->background_color); if (crtc->funcs->atomic_print_state) crtc->funcs->atomic_print_state(p, state); @@ -818,38 +818,38 @@ static void drm_atomic_colorop_print_state(struct drm_printer *p, struct drm_colorop *colorop = state->colorop; drm_printf(p, "colorop[%u]:\n", colorop->base.id); - drm_printf(p, "\ttype=%s\n", drm_get_colorop_type_name(colorop->type)); + drm_printf_indent(p, 1, "type=%s\n", drm_get_colorop_type_name(colorop->type)); if (colorop->bypass_property) - drm_printf(p, "\tbypass=%u\n", state->bypass); + drm_printf_indent(p, 1, "bypass=%u\n", state->bypass); switch (colorop->type) { case DRM_COLOROP_1D_CURVE: - drm_printf(p, "\tcurve_1d_type=%s\n", - drm_get_colorop_curve_1d_type_name(state->curve_1d_type)); + drm_printf_indent(p, 1, "curve_1d_type=%s\n", + drm_get_colorop_curve_1d_type_name(state->curve_1d_type)); break; case DRM_COLOROP_1D_LUT: - drm_printf(p, "\tsize=%d\n", colorop->size); - drm_printf(p, "\tinterpolation=%s\n", - drm_get_colorop_lut1d_interpolation_name(colorop->lut1d_interpolation)); - drm_printf(p, "\tdata blob id=%d\n", state->data ? state->data->base.id : 0); + drm_printf_indent(p, 1, "size=%d\n", colorop->size); + drm_printf_indent(p, 1, "interpolation=%s\n", + drm_get_colorop_lut1d_interpolation_name(colorop->lut1d_interpolation)); + drm_printf_indent(p, 1, "data blob id=%d\n", state->data ? state->data->base.id : 0); break; case DRM_COLOROP_CTM_3X4: - drm_printf(p, "\tdata blob id=%d\n", state->data ? state->data->base.id : 0); + drm_printf_indent(p, 1, "data blob id=%d\n", state->data ? state->data->base.id : 0); break; case DRM_COLOROP_MULTIPLIER: - drm_printf(p, "\tmultiplier=%llu\n", state->multiplier); + drm_printf_indent(p, 1, "multiplier=%llu\n", state->multiplier); break; case DRM_COLOROP_3D_LUT: - drm_printf(p, "\tsize=%d\n", colorop->size); - drm_printf(p, "\tinterpolation=%s\n", - drm_get_colorop_lut3d_interpolation_name(colorop->lut3d_interpolation)); - drm_printf(p, "\tdata blob id=%d\n", state->data ? state->data->base.id : 0); + drm_printf_indent(p, 1, "size=%d\n", colorop->size); + drm_printf_indent(p, 1, "interpolation=%s\n", + drm_get_colorop_lut3d_interpolation_name(colorop->lut3d_interpolation)); + drm_printf_indent(p, 1, "data blob id=%d\n", state->data ? state->data->base.id : 0); break; default: break; } - drm_printf(p, "\tnext=%d\n", colorop->next ? colorop->next->base.id : 0); + drm_printf_indent(p, 1, "next=%d\n", colorop->next ? colorop->next->base.id : 0); } static void drm_atomic_plane_print_state(struct drm_printer *p, @@ -860,21 +860,21 @@ static void drm_atomic_plane_print_state(struct drm_printer *p, struct drm_rect dest = drm_plane_state_dest(state); drm_printf(p, "plane[%u]: %s\n", plane->base.id, plane->name); - drm_printf(p, "\tcrtc=%s\n", state->crtc ? state->crtc->name : "(null)"); - drm_printf(p, "\tfb=%u\n", state->fb ? state->fb->base.id : 0); + drm_printf_indent(p, 1, "crtc=%s\n", state->crtc ? state->crtc->name : "(null)"); + drm_printf_indent(p, 1, "fb=%u\n", state->fb ? state->fb->base.id : 0); if (state->fb) drm_framebuffer_print_info(p, 2, state->fb); - drm_printf(p, "\tcrtc-pos=" DRM_RECT_FMT "\n", DRM_RECT_ARG(&dest)); - drm_printf(p, "\tsrc-pos=" DRM_RECT_FP_FMT "\n", DRM_RECT_FP_ARG(&src)); - drm_printf(p, "\trotation=%x\n", state->rotation); - drm_printf(p, "\tnormalized-zpos=%x\n", state->normalized_zpos); - drm_printf(p, "\tcolor-encoding=%s\n", - drm_get_color_encoding_name(state->color_encoding)); - drm_printf(p, "\tcolor-range=%s\n", - drm_get_color_range_name(state->color_range)); - drm_printf(p, "\tcolor_mgmt_changed=%d\n", state->color_mgmt_changed); - drm_printf(p, "\tcolor-pipeline=%d\n", - state->color_pipeline ? state->color_pipeline->base.id : 0); + drm_printf_indent(p, 1, "crtc-pos=" DRM_RECT_FMT "\n", DRM_RECT_ARG(&dest)); + drm_printf_indent(p, 1, "src-pos=" DRM_RECT_FP_FMT "\n", DRM_RECT_FP_ARG(&src)); + drm_printf_indent(p, 1, "rotation=%x\n", state->rotation); + drm_printf_indent(p, 1, "normalized-zpos=%x\n", state->normalized_zpos); + drm_printf_indent(p, 1, "color-encoding=%s\n", + drm_get_color_encoding_name(state->color_encoding)); + drm_printf_indent(p, 1, "color-range=%s\n", + drm_get_color_range_name(state->color_range)); + drm_printf_indent(p, 1, "color_mgmt_changed=%d\n", state->color_mgmt_changed); + drm_printf_indent(p, 1, "color-pipeline=%d\n", + state->color_pipeline ? state->color_pipeline->base.id : 0); if (plane->funcs->atomic_print_state) plane->funcs->atomic_print_state(p, state); } @@ -1347,27 +1347,27 @@ static void drm_atomic_connector_print_state(struct drm_printer *p, struct drm_connector *connector = state->connector; drm_printf(p, "connector[%u]: %s\n", connector->base.id, connector->name); - drm_printf(p, "\tcrtc=%s\n", state->crtc ? state->crtc->name : "(null)"); - drm_printf(p, "\tself_refresh_aware=%d\n", state->self_refresh_aware); - drm_printf(p, "\tinterlace_allowed=%d\n", connector->interlace_allowed); - drm_printf(p, "\tycbcr_420_allowed=%d\n", connector->ycbcr_420_allowed); - drm_printf(p, "\tmax_requested_bpc=%d\n", state->max_requested_bpc); - drm_printf(p, "\tcolorspace=%s\n", drm_get_colorspace_name(state->colorspace)); + drm_printf_indent(p, 1, "crtc=%s\n", state->crtc ? state->crtc->name : "(null)"); + drm_printf_indent(p, 1, "self_refresh_aware=%d\n", state->self_refresh_aware); + drm_printf_indent(p, 1, "interlace_allowed=%d\n", connector->interlace_allowed); + drm_printf_indent(p, 1, "ycbcr_420_allowed=%d\n", connector->ycbcr_420_allowed); + drm_printf_indent(p, 1, "max_requested_bpc=%d\n", state->max_requested_bpc); + drm_printf_indent(p, 1, "colorspace=%s\n", drm_get_colorspace_name(state->colorspace)); if (connector->connector_type == DRM_MODE_CONNECTOR_HDMIA || connector->connector_type == DRM_MODE_CONNECTOR_HDMIB) { - drm_printf(p, "\tbroadcast_rgb=%s\n", - drm_hdmi_connector_get_broadcast_rgb_name(state->hdmi.broadcast_rgb)); - drm_printf(p, "\tis_limited_range=%c\n", state->hdmi.is_limited_range ? 'y' : 'n'); - drm_printf(p, "\toutput_bpc=%u\n", state->hdmi.output_bpc); - drm_printf(p, "\toutput_format=%s\n", - drm_hdmi_connector_get_output_format_name(state->hdmi.output_format)); - drm_printf(p, "\ttmds_char_rate=%llu\n", state->hdmi.tmds_char_rate); + drm_printf_indent(p, 1, "broadcast_rgb=%s\n", + drm_hdmi_connector_get_broadcast_rgb_name(state->hdmi.broadcast_rgb)); + drm_printf_indent(p, 1, "is_limited_range=%c\n", state->hdmi.is_limited_range ? 'y' : 'n'); + drm_printf_indent(p, 1, "output_bpc=%u\n", state->hdmi.output_bpc); + drm_printf_indent(p, 1, "output_format=%s\n", + drm_hdmi_connector_get_output_format_name(state->hdmi.output_format)); + drm_printf_indent(p, 1, "tmds_char_rate=%llu\n", state->hdmi.tmds_char_rate); } if (connector->connector_type == DRM_MODE_CONNECTOR_WRITEBACK) if (state->writeback_job && state->writeback_job->fb) - drm_printf(p, "\tfb=%d\n", state->writeback_job->fb->base.id); + drm_printf_indent(p, 1, "fb=%d\n", state->writeback_job->fb->base.id); if (connector->funcs->atomic_print_state) connector->funcs->atomic_print_state(p, state); From 9a096b8879801a597c06c1a69d41c827458cea60 Mon Sep 17 00:00:00 2001 From: Jani Nikula Date: Wed, 8 Apr 2026 11:22:11 +0300 Subject: [PATCH 021/145] drm/bridge: prefer drm_printf_indent() over inline \t We have a helper drm_printf_indent() for tab indenting the prints. It makes the actual strings more readable, and highlights the indented parts better in source. Reviewed-by: Chaitanya Kumar Borah Link: https://patch.msgid.link/20260408082211.3040194-2-jani.nikula@intel.com Signed-off-by: Jani Nikula --- drivers/gpu/drm/drm_bridge.c | 13 ++++++------- 1 file changed, 6 insertions(+), 7 deletions(-) diff --git a/drivers/gpu/drm/drm_bridge.c b/drivers/gpu/drm/drm_bridge.c index 986e4c79a4e0..d4b3478258ec 100644 --- a/drivers/gpu/drm/drm_bridge.c +++ b/drivers/gpu/drm/drm_bridge.c @@ -1614,18 +1614,17 @@ static void drm_bridge_debugfs_show_bridge(struct drm_printer *p, drm_printf(p, "bridge[%u]: %ps\n", idx, bridge->funcs); - drm_printf(p, "\trefcount: %u%s\n", refcount, - lingering ? " [lingering]" : ""); + drm_printf_indent(p, 1, "refcount: %u%s\n", refcount, + lingering ? " [lingering]" : ""); - drm_printf(p, "\ttype: [%d] %s\n", - bridge->type, - drm_get_connector_type_name(bridge->type)); + drm_printf_indent(p, 1, "type: [%d] %s\n", bridge->type, + drm_get_connector_type_name(bridge->type)); /* The OF node could be freed after drm_bridge_remove() */ if (bridge->of_node && !lingering) - drm_printf(p, "\tOF: %pOFfc\n", bridge->of_node); + drm_printf_indent(p, 1, "OF: %pOFfc\n", bridge->of_node); - drm_printf(p, "\tops: [0x%x]", bridge->ops); + drm_printf_indent(p, 1, "ops: [0x%x]", bridge->ops); if (bridge->ops & DRM_BRIDGE_OP_DETECT) drm_puts(p, " detect"); if (bridge->ops & DRM_BRIDGE_OP_EDID) From a5640267d6d35b89ebe6418da90a952a247215a5 Mon Sep 17 00:00:00 2001 From: Timur Tabi Date: Tue, 28 Apr 2026 15:28:25 -0500 Subject: [PATCH 022/145] drm/nouveau: expose VBIOS via debugfs on GSP-RM systems When Nouveau boots with GSP-RM, it bypasses several traditional code paths to allow GSP-RM to handle those features. In particular, some VBIOS parsing is skipped, and a side effect is that the VBIOS is not exposed in the DRM debugfs entries. Fix this by updating the drm BIOS struct (nvbios) with the VBIOS data from the nvkm BIOS struct (nvkm_bios). This happens normally in NVInitVBIOS(), but that function is skipped when booting with GSP-RM. Signed-off-by: Timur Tabi Link: https://patch.msgid.link/20260428202825.1123719-1-ttabi@nvidia.com Signed-off-by: Danilo Krummrich --- drivers/gpu/drm/nouveau/nouveau_bios.c | 21 +++++++++++++++++++-- 1 file changed, 19 insertions(+), 2 deletions(-) diff --git a/drivers/gpu/drm/nouveau/nouveau_bios.c b/drivers/gpu/drm/nouveau/nouveau_bios.c index c8335f5b49db..38032bb95826 100644 --- a/drivers/gpu/drm/nouveau/nouveau_bios.c +++ b/drivers/gpu/drm/nouveau/nouveau_bios.c @@ -2085,10 +2085,27 @@ nouveau_bios_init(struct drm_device *dev) int ret; /* only relevant for PCI devices */ - if (!dev_is_pci(dev->dev) || - nvkm_gsp_rm(nvxx_device(drm)->gsp)) + if (!dev_is_pci(dev->dev)) return 0; + if (nvkm_gsp_rm(nvxx_device(drm)->gsp)) { + struct nvkm_bios *nvkm_bios = nvxx_bios(drm); + + /* + * If this GPU has an nvkm_device_chip.bios entry, then the VBIOS + * data was already read by the nvkm layer during nvkm_bios_new(). + * Point the legacy DRM-level VBIOS structure at the same buffer + * so that any remaining legacy code can access it. This exposes + * the VBIOS via the DRM debugfs entries. + */ + if (nvkm_bios) { + bios->data = nvkm_bios->data; + bios->length = nvkm_bios->size; + } + + return 0; + } + if (!NVInitVBIOS(dev)) return -ENODEV; From dcad6dd16e87a6dcc78ab05f64c704cec2809db9 Mon Sep 17 00:00:00 2001 From: Luca Ceresoli Date: Thu, 23 Apr 2026 11:16:55 +0200 Subject: [PATCH 023/145] drm/display: bridge-connector: attach the encoder to the created connector Currently all users of the bridge-connector must call drm_connector_attach_encoder() immediately after a successful drm_bridge_connector_init(). This is an unnecessary burden for users. Move the call to the end of drm_bridge_connector_init() so all callers can be simplified. Update documentation accordingly, rewording a bit the whole paragraph which would otherwise become poorly readable due to the growing list of actions. Reviewed-by: Dmitry Baryshkov Link: https://patch.msgid.link/20260423-drm-bridge-connector-attach_encoder-v2-1-2ae6ca69b390@bootlin.com Signed-off-by: Luca Ceresoli --- drivers/gpu/drm/display/drm_bridge_connector.c | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) diff --git a/drivers/gpu/drm/display/drm_bridge_connector.c b/drivers/gpu/drm/display/drm_bridge_connector.c index 39cc18f78eda..d85ceb80c137 100644 --- a/drivers/gpu/drm/display/drm_bridge_connector.c +++ b/drivers/gpu/drm/display/drm_bridge_connector.c @@ -773,8 +773,11 @@ static void drm_bridge_connector_put_bridges(struct drm_device *dev, void *data) * @drm: the DRM device * @encoder: the encoder where the bridge chain starts * - * Allocate, initialise and register a &drm_bridge_connector with the @drm - * device. The connector is associated with a chain of bridges that starts at + * Create a new &drm_bridge_connector for the @drm device. The connector is + * allocated, initialised, registered with the @drm device and attached to + * @encoder. + * + * The connector is associated with a chain of bridges that starts at * the @encoder. All bridges in the chain shall report bridge operation flags * (&drm_bridge->ops) and bridge output type (&drm_bridge->type), and none of * them may create a DRM connector directly. @@ -1055,6 +1058,10 @@ struct drm_connector *drm_bridge_connector_init(struct drm_device *drm, IS_ENABLED(CONFIG_DRM_DISPLAY_HDCP_HELPER)) drm_connector_attach_content_protection_property(connector, true); + ret = drm_connector_attach_encoder(connector, encoder); + if (ret) + return ERR_PTR(ret); + return connector; } EXPORT_SYMBOL_GPL(drm_bridge_connector_init); From f96e621e90dfeb35676604b223f42f721e7c364f Mon Sep 17 00:00:00 2001 From: Luca Ceresoli Date: Thu, 23 Apr 2026 11:16:56 +0200 Subject: [PATCH 024/145] drm: adp: remove now-redundant call to drm_connector_attach_encoder() drm_connector_attach_encoder() is now called by drm_bridge_connector_init(). Reviewed-by: Dmitry Baryshkov Link: https://patch.msgid.link/20260423-drm-bridge-connector-attach_encoder-v2-2-2ae6ca69b390@bootlin.com Signed-off-by: Luca Ceresoli --- drivers/gpu/drm/adp/adp_drv.c | 2 -- 1 file changed, 2 deletions(-) diff --git a/drivers/gpu/drm/adp/adp_drv.c b/drivers/gpu/drm/adp/adp_drv.c index 4554cf75565e..0a11820d5b8a 100644 --- a/drivers/gpu/drm/adp/adp_drv.c +++ b/drivers/gpu/drm/adp/adp_drv.c @@ -444,8 +444,6 @@ static int adp_setup_mode_config(struct adp_drv_private *adp) if (IS_ERR(adp->connector)) return PTR_ERR(adp->connector); - drm_connector_attach_encoder(adp->connector, adp->encoder); - ret = drm_vblank_init(drm, drm->mode_config.num_crtc); if (ret < 0) { drm_err(drm, "failed to initialize vblank"); From 4f88126e09160fa5c226e786982d433aba0345c4 Mon Sep 17 00:00:00 2001 From: Luca Ceresoli Date: Thu, 23 Apr 2026 11:16:57 +0200 Subject: [PATCH 025/145] drm/bridge: adv7511: remove now-redundant call to drm_connector_attach_encoder() drm_connector_attach_encoder() is now called by drm_bridge_connector_init(). Reviewed-by: Dmitry Baryshkov Link: https://patch.msgid.link/20260423-drm-bridge-connector-attach_encoder-v2-3-2ae6ca69b390@bootlin.com Signed-off-by: Luca Ceresoli --- drivers/gpu/drm/bridge/adv7511/adv7511_drv.c | 2 -- 1 file changed, 2 deletions(-) diff --git a/drivers/gpu/drm/bridge/adv7511/adv7511_drv.c b/drivers/gpu/drm/bridge/adv7511/adv7511_drv.c index 6bd76c1fb007..f318080f1139 100644 --- a/drivers/gpu/drm/bridge/adv7511/adv7511_drv.c +++ b/drivers/gpu/drm/bridge/adv7511/adv7511_drv.c @@ -768,8 +768,6 @@ static int adv7511_connector_init(struct adv7511 *adv) return PTR_ERR(connector); } - drm_connector_attach_encoder(connector, bridge->encoder); - return 0; } From 7ecf62396ed7883eda3bb949df7f95e5a1048b17 Mon Sep 17 00:00:00 2001 From: Luca Ceresoli Date: Thu, 23 Apr 2026 11:16:58 +0200 Subject: [PATCH 026/145] drm/bridge: ite-it6263: remove now-redundant call to drm_connector_attach_encoder() drm_connector_attach_encoder() is now called by drm_bridge_connector_init(). Reviewed-by: Liu Ying Reviewed-by: Dmitry Baryshkov Link: https://patch.msgid.link/20260423-drm-bridge-connector-attach_encoder-v2-4-2ae6ca69b390@bootlin.com Signed-off-by: Luca Ceresoli --- drivers/gpu/drm/bridge/ite-it6263.c | 2 -- 1 file changed, 2 deletions(-) diff --git a/drivers/gpu/drm/bridge/ite-it6263.c b/drivers/gpu/drm/bridge/ite-it6263.c index 4f3ebb7af4d4..2ea49245e700 100644 --- a/drivers/gpu/drm/bridge/ite-it6263.c +++ b/drivers/gpu/drm/bridge/ite-it6263.c @@ -697,8 +697,6 @@ static int it6263_bridge_attach(struct drm_bridge *bridge, return ret; } - drm_connector_attach_encoder(connector, encoder); - return 0; } From 1977688f60eab4c92dca15c8b7e6b19635902ee0 Mon Sep 17 00:00:00 2001 From: Luca Ceresoli Date: Thu, 23 Apr 2026 11:16:59 +0200 Subject: [PATCH 027/145] drm/bridge: ti-sn65dsi86: remove now-redundant call to drm_connector_attach_encoder() drm_connector_attach_encoder() is now called by drm_bridge_connector_init(). Reviewed-by: Dmitry Baryshkov Link: https://patch.msgid.link/20260423-drm-bridge-connector-attach_encoder-v2-5-2ae6ca69b390@bootlin.com Signed-off-by: Luca Ceresoli --- drivers/gpu/drm/bridge/ti-sn65dsi86.c | 2 -- 1 file changed, 2 deletions(-) diff --git a/drivers/gpu/drm/bridge/ti-sn65dsi86.c b/drivers/gpu/drm/bridge/ti-sn65dsi86.c index 98d64ad791d0..1336ffab103f 100644 --- a/drivers/gpu/drm/bridge/ti-sn65dsi86.c +++ b/drivers/gpu/drm/bridge/ti-sn65dsi86.c @@ -776,8 +776,6 @@ static int ti_sn_bridge_attach(struct drm_bridge *bridge, goto err_initted_aux; } - drm_connector_attach_encoder(pdata->connector, pdata->bridge.encoder); - return 0; err_initted_aux: From 4b29d25b55fc28ab6065500a60693b093ad05366 Mon Sep 17 00:00:00 2001 From: Luca Ceresoli Date: Thu, 23 Apr 2026 11:17:00 +0200 Subject: [PATCH 028/145] drm/imx/dcss: remove now-redundant call to drm_connector_attach_encoder() drm_connector_attach_encoder() is now called by drm_bridge_connector_init(). Reviewed-by: Laurentiu Palcu Reviewed-by: Dmitry Baryshkov Link: https://patch.msgid.link/20260423-drm-bridge-connector-attach_encoder-v2-6-2ae6ca69b390@bootlin.com Signed-off-by: Luca Ceresoli --- drivers/gpu/drm/imx/dcss/dcss-kms.c | 2 -- 1 file changed, 2 deletions(-) diff --git a/drivers/gpu/drm/imx/dcss/dcss-kms.c b/drivers/gpu/drm/imx/dcss/dcss-kms.c index 3633e8f3aff6..50bd7f36d36d 100644 --- a/drivers/gpu/drm/imx/dcss/dcss-kms.c +++ b/drivers/gpu/drm/imx/dcss/dcss-kms.c @@ -103,8 +103,6 @@ static int dcss_kms_bridge_connector_init(struct dcss_kms_dev *kms) return PTR_ERR(kms->connector); } - drm_connector_attach_encoder(kms->connector, encoder); - return 0; } From dd7784328061fba1fba919d8879ed65ea30feeae Mon Sep 17 00:00:00 2001 From: Luca Ceresoli Date: Thu, 23 Apr 2026 11:17:01 +0200 Subject: [PATCH 029/145] drm/imx: ldb: remove now-redundant call to drm_connector_attach_encoder() drm_connector_attach_encoder() is now called by drm_bridge_connector_init(). Reviewed-by: Dmitry Baryshkov Link: https://patch.msgid.link/20260423-drm-bridge-connector-attach_encoder-v2-7-2ae6ca69b390@bootlin.com Signed-off-by: Luca Ceresoli --- drivers/gpu/drm/imx/ipuv3/imx-ldb.c | 2 -- 1 file changed, 2 deletions(-) diff --git a/drivers/gpu/drm/imx/ipuv3/imx-ldb.c b/drivers/gpu/drm/imx/ipuv3/imx-ldb.c index 730caf883e83..63d6a1e7c1bd 100644 --- a/drivers/gpu/drm/imx/ipuv3/imx-ldb.c +++ b/drivers/gpu/drm/imx/ipuv3/imx-ldb.c @@ -407,8 +407,6 @@ static int imx_ldb_register(struct drm_device *drm, if (IS_ERR(connector)) return PTR_ERR(connector); - drm_connector_attach_encoder(connector, encoder); - return 0; } From 5c18883f8050b1f6fdb35050cf9dad64779f6ee9 Mon Sep 17 00:00:00 2001 From: Luca Ceresoli Date: Thu, 23 Apr 2026 11:17:02 +0200 Subject: [PATCH 030/145] drm/imx: parallel-display: remove now-redundant call to drm_connector_attach_encoder() drm_connector_attach_encoder() is now called by drm_bridge_connector_init(). Reviewed-by: Dmitry Baryshkov Link: https://patch.msgid.link/20260423-drm-bridge-connector-attach_encoder-v2-8-2ae6ca69b390@bootlin.com Signed-off-by: Luca Ceresoli --- drivers/gpu/drm/imx/ipuv3/parallel-display.c | 2 -- 1 file changed, 2 deletions(-) diff --git a/drivers/gpu/drm/imx/ipuv3/parallel-display.c b/drivers/gpu/drm/imx/ipuv3/parallel-display.c index 6c505becb31d..0f06db95f00f 100644 --- a/drivers/gpu/drm/imx/ipuv3/parallel-display.c +++ b/drivers/gpu/drm/imx/ipuv3/parallel-display.c @@ -216,8 +216,6 @@ static int imx_pd_bind(struct device *dev, struct device *master, void *data) if (IS_ERR(connector)) return PTR_ERR(connector); - drm_connector_attach_encoder(connector, encoder); - return 0; } From b490bc69f1c11d8335dbd628d5e32db8986f848c Mon Sep 17 00:00:00 2001 From: Luca Ceresoli Date: Thu, 23 Apr 2026 11:17:03 +0200 Subject: [PATCH 031/145] drm/imx/lcdc: remove now-redundant call to drm_connector_attach_encoder() drm_connector_attach_encoder() is now called by drm_bridge_connector_init(). Reviewed-by: Dmitry Baryshkov Link: https://patch.msgid.link/20260423-drm-bridge-connector-attach_encoder-v2-9-2ae6ca69b390@bootlin.com Signed-off-by: Luca Ceresoli --- drivers/gpu/drm/imx/lcdc/imx-lcdc.c | 2 -- 1 file changed, 2 deletions(-) diff --git a/drivers/gpu/drm/imx/lcdc/imx-lcdc.c b/drivers/gpu/drm/imx/lcdc/imx-lcdc.c index e200b40f30fe..f52832b43aca 100644 --- a/drivers/gpu/drm/imx/lcdc/imx-lcdc.c +++ b/drivers/gpu/drm/imx/lcdc/imx-lcdc.c @@ -448,8 +448,6 @@ static int imx_lcdc_probe(struct platform_device *pdev) if (IS_ERR(lcdc->connector)) return dev_err_probe(drm->dev, PTR_ERR(lcdc->connector), "Cannot init bridge connector\n"); - drm_connector_attach_encoder(lcdc->connector, &lcdc->pipe.encoder); - /* * The LCDC controller does not have an enable bit. The * controller starts directly when the clocks are enabled. From bc9e6392403e316c9d6e337b7cf28543051cb28e Mon Sep 17 00:00:00 2001 From: Luca Ceresoli Date: Thu, 23 Apr 2026 11:17:04 +0200 Subject: [PATCH 032/145] drm/ingenic: remove now-redundant call to drm_connector_attach_encoder() drm_connector_attach_encoder() is now called by drm_bridge_connector_init(). Acked-by: Paul Cercueil Reviewed-by: Dmitry Baryshkov Link: https://patch.msgid.link/20260423-drm-bridge-connector-attach_encoder-v2-10-2ae6ca69b390@bootlin.com Signed-off-by: Luca Ceresoli --- drivers/gpu/drm/ingenic/ingenic-drm-drv.c | 2 -- 1 file changed, 2 deletions(-) diff --git a/drivers/gpu/drm/ingenic/ingenic-drm-drv.c b/drivers/gpu/drm/ingenic/ingenic-drm-drv.c index 4068114adf8c..70088db34f69 100644 --- a/drivers/gpu/drm/ingenic/ingenic-drm-drv.c +++ b/drivers/gpu/drm/ingenic/ingenic-drm-drv.c @@ -1330,8 +1330,6 @@ static int ingenic_drm_bind(struct device *dev, bool has_components) ret = PTR_ERR(connector); goto err_drvdata; } - - drm_connector_attach_encoder(connector, encoder); } drm_for_each_encoder(encoder, drm) { From d731d87126d43936ab74804785446f67a2d60d0c Mon Sep 17 00:00:00 2001 From: Luca Ceresoli Date: Thu, 23 Apr 2026 11:17:05 +0200 Subject: [PATCH 033/145] drm/kmb/dsi: remove now-redundant call to drm_connector_attach_encoder() drm_connector_attach_encoder() is now called by drm_bridge_connector_init(). Reviewed-by: Dmitry Baryshkov Link: https://patch.msgid.link/20260423-drm-bridge-connector-attach_encoder-v2-11-2ae6ca69b390@bootlin.com Signed-off-by: Luca Ceresoli --- drivers/gpu/drm/kmb/kmb_dsi.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/gpu/drm/kmb/kmb_dsi.c b/drivers/gpu/drm/kmb/kmb_dsi.c index febca939bd01..df84b5a79a6c 100644 --- a/drivers/gpu/drm/kmb/kmb_dsi.c +++ b/drivers/gpu/drm/kmb/kmb_dsi.c @@ -1457,7 +1457,7 @@ int kmb_dsi_encoder_init(struct drm_device *dev, struct kmb_dsi *kmb_dsi) drm_encoder_cleanup(encoder); return PTR_ERR(connector); } - drm_connector_attach_encoder(connector, encoder); + return 0; } From c21f9adc83c5edf0b990cd068283d3c831b43074 Mon Sep 17 00:00:00 2001 From: Luca Ceresoli Date: Thu, 23 Apr 2026 11:17:06 +0200 Subject: [PATCH 034/145] drm/mediatek: mtk_dpi: remove now-redundant call to drm_connector_attach_encoder() drm_connector_attach_encoder() is now called by drm_bridge_connector_init(). Reviewed-by: Dmitry Baryshkov Link: https://patch.msgid.link/20260423-drm-bridge-connector-attach_encoder-v2-12-2ae6ca69b390@bootlin.com Signed-off-by: Luca Ceresoli --- drivers/gpu/drm/mediatek/mtk_dpi.c | 1 - 1 file changed, 1 deletion(-) diff --git a/drivers/gpu/drm/mediatek/mtk_dpi.c b/drivers/gpu/drm/mediatek/mtk_dpi.c index 53360b5d12ba..cc6d74ce8b5e 100644 --- a/drivers/gpu/drm/mediatek/mtk_dpi.c +++ b/drivers/gpu/drm/mediatek/mtk_dpi.c @@ -1049,7 +1049,6 @@ static int mtk_dpi_bind(struct device *dev, struct device *master, void *data) ret = PTR_ERR(dpi->connector); goto err_cleanup; } - drm_connector_attach_encoder(dpi->connector, &dpi->encoder); return 0; From 41bfe06bb3cae68c0b3e21c5181c49f68db67e18 Mon Sep 17 00:00:00 2001 From: Luca Ceresoli Date: Thu, 23 Apr 2026 11:17:07 +0200 Subject: [PATCH 035/145] drm/mediatek: mtk_dsi: remove now-redundant call to drm_connector_attach_encoder() drm_connector_attach_encoder() is now called by drm_bridge_connector_init(). Reviewed-by: Dmitry Baryshkov Link: https://patch.msgid.link/20260423-drm-bridge-connector-attach_encoder-v2-13-2ae6ca69b390@bootlin.com Signed-off-by: Luca Ceresoli --- drivers/gpu/drm/mediatek/mtk_dsi.c | 1 - 1 file changed, 1 deletion(-) diff --git a/drivers/gpu/drm/mediatek/mtk_dsi.c b/drivers/gpu/drm/mediatek/mtk_dsi.c index 5aa71fcdcfab..8be32cde2924 100644 --- a/drivers/gpu/drm/mediatek/mtk_dsi.c +++ b/drivers/gpu/drm/mediatek/mtk_dsi.c @@ -936,7 +936,6 @@ static int mtk_dsi_encoder_init(struct drm_device *drm, struct mtk_dsi *dsi) ret = PTR_ERR(dsi->connector); goto err_cleanup_encoder; } - drm_connector_attach_encoder(dsi->connector, &dsi->encoder); return 0; From 82da98ea371dff7a9ece58083846556b043bec9a Mon Sep 17 00:00:00 2001 From: Luca Ceresoli Date: Thu, 23 Apr 2026 11:17:08 +0200 Subject: [PATCH 036/145] drm/meson: encoder_cvbs: remove now-redundant call to drm_connector_attach_encoder() drm_connector_attach_encoder() is now called by drm_bridge_connector_init(). Reviewed-by: Dmitry Baryshkov Link: https://patch.msgid.link/20260423-drm-bridge-connector-attach_encoder-v2-14-2ae6ca69b390@bootlin.com Signed-off-by: Luca Ceresoli --- drivers/gpu/drm/meson/meson_encoder_cvbs.c | 2 -- 1 file changed, 2 deletions(-) diff --git a/drivers/gpu/drm/meson/meson_encoder_cvbs.c b/drivers/gpu/drm/meson/meson_encoder_cvbs.c index 41071d6e05e5..41ba6d2139ee 100644 --- a/drivers/gpu/drm/meson/meson_encoder_cvbs.c +++ b/drivers/gpu/drm/meson/meson_encoder_cvbs.c @@ -279,8 +279,6 @@ int meson_encoder_cvbs_probe(struct meson_drm *priv) return dev_err_probe(priv->dev, PTR_ERR(connector), "Unable to create CVBS bridge connector\n"); - drm_connector_attach_encoder(connector, &meson_encoder_cvbs->encoder); - priv->encoders[MESON_ENC_CVBS] = meson_encoder_cvbs; return 0; From 013adec1a93dcd052c6eb1769609eee661983ca9 Mon Sep 17 00:00:00 2001 From: Luca Ceresoli Date: Thu, 23 Apr 2026 11:17:09 +0200 Subject: [PATCH 037/145] drm/meson: encoder_hdmi: remove now-redundant call to drm_connector_attach_encoder() drm_connector_attach_encoder() is now called by drm_bridge_connector_init(). Reviewed-by: Dmitry Baryshkov Link: https://patch.msgid.link/20260423-drm-bridge-connector-attach_encoder-v2-15-2ae6ca69b390@bootlin.com Signed-off-by: Luca Ceresoli --- drivers/gpu/drm/meson/meson_encoder_hdmi.c | 2 -- 1 file changed, 2 deletions(-) diff --git a/drivers/gpu/drm/meson/meson_encoder_hdmi.c b/drivers/gpu/drm/meson/meson_encoder_hdmi.c index 1abb0572bb5f..8e00ae6edbb1 100644 --- a/drivers/gpu/drm/meson/meson_encoder_hdmi.c +++ b/drivers/gpu/drm/meson/meson_encoder_hdmi.c @@ -433,8 +433,6 @@ int meson_encoder_hdmi_probe(struct meson_drm *priv) "Unable to create HDMI bridge connector\n"); goto err_put_node; } - drm_connector_attach_encoder(meson_encoder_hdmi->connector, - &meson_encoder_hdmi->encoder); /* * We should have now in place: From 6108b5b7219e3f3f947922f4faa8ccbc570210d2 Mon Sep 17 00:00:00 2001 From: Luca Ceresoli Date: Thu, 23 Apr 2026 11:17:10 +0200 Subject: [PATCH 038/145] drm/msm/dp: remove now-redundant call to drm_connector_attach_encoder() drm_connector_attach_encoder() is now called by drm_bridge_connector_init(). Reviewed-by: Dmitry Baryshkov Acked-by: Dmitry Baryshkov Link: https://patch.msgid.link/20260423-drm-bridge-connector-attach_encoder-v2-16-2ae6ca69b390@bootlin.com Signed-off-by: Luca Ceresoli --- drivers/gpu/drm/msm/dp/dp_drm.c | 2 -- 1 file changed, 2 deletions(-) diff --git a/drivers/gpu/drm/msm/dp/dp_drm.c b/drivers/gpu/drm/msm/dp/dp_drm.c index fd6443d2b6ce..333fce3d44ed 100644 --- a/drivers/gpu/drm/msm/dp/dp_drm.c +++ b/drivers/gpu/drm/msm/dp/dp_drm.c @@ -376,7 +376,5 @@ struct drm_connector *msm_dp_drm_connector_init(struct msm_dp *msm_dp_display, if (!msm_dp_display->is_edp) drm_connector_attach_dp_subconnector_property(connector); - drm_connector_attach_encoder(connector, encoder); - return connector; } From f7ed1d3dde56b98e065b950d1044a0f655b194ba Mon Sep 17 00:00:00 2001 From: Luca Ceresoli Date: Thu, 23 Apr 2026 11:17:11 +0200 Subject: [PATCH 039/145] drm/msm/hdmi: remove now-redundant call to drm_connector_attach_encoder() drm_connector_attach_encoder() is now called by drm_bridge_connector_init(). Reviewed-by: Dmitry Baryshkov Acked-by: Dmitry Baryshkov Link: https://patch.msgid.link/20260423-drm-bridge-connector-attach_encoder-v2-17-2ae6ca69b390@bootlin.com Signed-off-by: Luca Ceresoli --- drivers/gpu/drm/msm/hdmi/hdmi.c | 2 -- 1 file changed, 2 deletions(-) diff --git a/drivers/gpu/drm/msm/hdmi/hdmi.c b/drivers/gpu/drm/msm/hdmi/hdmi.c index 852abb2466f0..d9491aac1a89 100644 --- a/drivers/gpu/drm/msm/hdmi/hdmi.c +++ b/drivers/gpu/drm/msm/hdmi/hdmi.c @@ -190,8 +190,6 @@ int msm_hdmi_modeset_init(struct hdmi *hdmi, goto fail; } - drm_connector_attach_encoder(hdmi->connector, hdmi->encoder); - ret = devm_request_irq(dev->dev, hdmi->irq, msm_hdmi_irq, IRQF_TRIGGER_HIGH, "hdmi_isr", hdmi); From 7b229305be6300c90e6f005784f9f53d4d23d579 Mon Sep 17 00:00:00 2001 From: Luca Ceresoli Date: Thu, 23 Apr 2026 11:17:12 +0200 Subject: [PATCH 040/145] drm/omapdrm: remove now-redundant call to drm_connector_attach_encoder() drm_connector_attach_encoder() is now called by drm_bridge_connector_init(). Reviewed-by: Dmitry Baryshkov Link: https://patch.msgid.link/20260423-drm-bridge-connector-attach_encoder-v2-18-2ae6ca69b390@bootlin.com Signed-off-by: Luca Ceresoli --- drivers/gpu/drm/omapdrm/omap_drv.c | 2 -- 1 file changed, 2 deletions(-) diff --git a/drivers/gpu/drm/omapdrm/omap_drv.c b/drivers/gpu/drm/omapdrm/omap_drv.c index ae678696fbac..31bf2618046b 100644 --- a/drivers/gpu/drm/omapdrm/omap_drv.c +++ b/drivers/gpu/drm/omapdrm/omap_drv.c @@ -507,8 +507,6 @@ static int omap_modeset_init(struct drm_device *dev) return PTR_ERR(pipe->connector); } - drm_connector_attach_encoder(pipe->connector, encoder); - crtc = omap_crtc_init(dev, pipe, priv->planes[i]); if (IS_ERR(crtc)) return PTR_ERR(crtc); From 86909f184b4f045f4d85dd2ca957811c1184aa1c Mon Sep 17 00:00:00 2001 From: Luca Ceresoli Date: Thu, 23 Apr 2026 11:17:13 +0200 Subject: [PATCH 041/145] drm/rockchip: cdn-dp: remove now-redundant call to drm_connector_attach_encoder() drm_connector_attach_encoder() is now called by drm_bridge_connector_init(). Reviewed-by: Dmitry Baryshkov Reviewed-by: Liu Ying [Luca: fixed typo in commit subject line] Link: https://patch.msgid.link/20260423-drm-bridge-connector-attach_encoder-v2-19-2ae6ca69b390@bootlin.com Signed-off-by: Luca Ceresoli --- drivers/gpu/drm/rockchip/cdn-dp-core.c | 2 -- 1 file changed, 2 deletions(-) diff --git a/drivers/gpu/drm/rockchip/cdn-dp-core.c b/drivers/gpu/drm/rockchip/cdn-dp-core.c index 177e30445ee8..f39450e12716 100644 --- a/drivers/gpu/drm/rockchip/cdn-dp-core.c +++ b/drivers/gpu/drm/rockchip/cdn-dp-core.c @@ -1024,8 +1024,6 @@ static int cdn_dp_bind(struct device *dev, struct device *master, void *data) return ret; } - drm_connector_attach_encoder(connector, encoder); - for (i = 0; i < dp->ports; i++) { port = dp->port[i]; From d5304653b60edb79bfb71209ebbd4b57001ab003 Mon Sep 17 00:00:00 2001 From: Luca Ceresoli Date: Thu, 23 Apr 2026 11:17:14 +0200 Subject: [PATCH 042/145] drm/rockchip: rk3066_hdmi: remove now-redundant call to drm_connector_attach_encoder() drm_connector_attach_encoder() is now called by drm_bridge_connector_init(). Reviewed-by: Dmitry Baryshkov Link: https://patch.msgid.link/20260423-drm-bridge-connector-attach_encoder-v2-20-2ae6ca69b390@bootlin.com Signed-off-by: Luca Ceresoli --- drivers/gpu/drm/rockchip/rk3066_hdmi.c | 2 -- 1 file changed, 2 deletions(-) diff --git a/drivers/gpu/drm/rockchip/rk3066_hdmi.c b/drivers/gpu/drm/rockchip/rk3066_hdmi.c index 9066ee2d1dff..b64cbed26312 100644 --- a/drivers/gpu/drm/rockchip/rk3066_hdmi.c +++ b/drivers/gpu/drm/rockchip/rk3066_hdmi.c @@ -731,8 +731,6 @@ rk3066_hdmi_register(struct drm_device *drm, struct rk3066_hdmi *hdmi) return ret; } - drm_connector_attach_encoder(hdmi->connector, encoder); - return 0; } From c0670fc1e75782a9dd0cd94acb7b262077b3f720 Mon Sep 17 00:00:00 2001 From: Luca Ceresoli Date: Thu, 23 Apr 2026 11:17:15 +0200 Subject: [PATCH 043/145] drm/tegra: hdmi: remove now-redundant call to drm_connector_attach_encoder() drm_connector_attach_encoder() is now called by drm_bridge_connector_init(). Reviewed-by: Dmitry Baryshkov Link: https://patch.msgid.link/20260423-drm-bridge-connector-attach_encoder-v2-21-2ae6ca69b390@bootlin.com Signed-off-by: Luca Ceresoli --- drivers/gpu/drm/tegra/hdmi.c | 2 -- 1 file changed, 2 deletions(-) diff --git a/drivers/gpu/drm/tegra/hdmi.c b/drivers/gpu/drm/tegra/hdmi.c index 0adcd4244a42..10f02f35c866 100644 --- a/drivers/gpu/drm/tegra/hdmi.c +++ b/drivers/gpu/drm/tegra/hdmi.c @@ -1576,8 +1576,6 @@ static int tegra_hdmi_init(struct host1x_client *client) connector); return PTR_ERR(connector); } - - drm_connector_attach_encoder(connector, &hdmi->output.encoder); } else { drm_connector_init_with_ddc(drm, &hdmi->output.connector, &tegra_hdmi_connector_funcs, From 04ce2e375f6dde267f53995d81c48ab31dc06b52 Mon Sep 17 00:00:00 2001 From: Luca Ceresoli Date: Thu, 23 Apr 2026 11:17:16 +0200 Subject: [PATCH 044/145] drm/tegra: rgb: remove now-redundant call to drm_connector_attach_encoder() drm_connector_attach_encoder() is now called by drm_bridge_connector_init(). Reviewed-by: Dmitry Baryshkov Link: https://patch.msgid.link/20260423-drm-bridge-connector-attach_encoder-v2-22-2ae6ca69b390@bootlin.com Signed-off-by: Luca Ceresoli --- drivers/gpu/drm/tegra/rgb.c | 2 -- 1 file changed, 2 deletions(-) diff --git a/drivers/gpu/drm/tegra/rgb.c b/drivers/gpu/drm/tegra/rgb.c index ff5a749710db..e67fbb2362e6 100644 --- a/drivers/gpu/drm/tegra/rgb.c +++ b/drivers/gpu/drm/tegra/rgb.c @@ -355,8 +355,6 @@ int tegra_dc_rgb_init(struct drm_device *drm, struct tegra_dc *dc) connector); return PTR_ERR(connector); } - - drm_connector_attach_encoder(connector, &output->encoder); } err = tegra_output_init(drm, output); From 6d303956b41f870240a23d4896ec12e420026637 Mon Sep 17 00:00:00 2001 From: Luca Ceresoli Date: Thu, 23 Apr 2026 11:17:17 +0200 Subject: [PATCH 045/145] drm/tests: bridge: remove now-redundant call to drm_connector_attach_encoder() drm_connector_attach_encoder() is now called by drm_bridge_connector_init(). Reviewed-by: Dmitry Baryshkov Link: https://patch.msgid.link/20260423-drm-bridge-connector-attach_encoder-v2-23-2ae6ca69b390@bootlin.com Signed-off-by: Luca Ceresoli --- drivers/gpu/drm/tests/drm_bridge_test.c | 2 -- 1 file changed, 2 deletions(-) diff --git a/drivers/gpu/drm/tests/drm_bridge_test.c b/drivers/gpu/drm/tests/drm_bridge_test.c index 887020141c7f..dbba06a486f0 100644 --- a/drivers/gpu/drm/tests/drm_bridge_test.c +++ b/drivers/gpu/drm/tests/drm_bridge_test.c @@ -173,8 +173,6 @@ drm_test_bridge_init(struct kunit *test, const struct drm_bridge_funcs *funcs) if (IS_ERR(priv->connector)) return ERR_CAST(priv->connector); - drm_connector_attach_encoder(priv->connector, enc); - drm_mode_config_reset(drm); return priv; From 6d65baa60f0d7c305eb63b738163c1e35d0eef20 Mon Sep 17 00:00:00 2001 From: Luca Ceresoli Date: Thu, 23 Apr 2026 11:17:18 +0200 Subject: [PATCH 046/145] drm: verisilicon: remove now-redundant call to drm_connector_attach_encoder() drm_connector_attach_encoder() is now called by drm_bridge_connector_init(). Acked-by: Icenowy Zheng Reviewed-by: Dmitry Baryshkov Link: https://patch.msgid.link/20260423-drm-bridge-connector-attach_encoder-v2-24-2ae6ca69b390@bootlin.com Signed-off-by: Luca Ceresoli --- drivers/gpu/drm/verisilicon/vs_bridge.c | 1 - 1 file changed, 1 deletion(-) diff --git a/drivers/gpu/drm/verisilicon/vs_bridge.c b/drivers/gpu/drm/verisilicon/vs_bridge.c index 2a0ad00a94d6..83c91d5ce397 100644 --- a/drivers/gpu/drm/verisilicon/vs_bridge.c +++ b/drivers/gpu/drm/verisilicon/vs_bridge.c @@ -365,7 +365,6 @@ struct vs_bridge *vs_bridge_init(struct drm_device *drm_dev, ret = PTR_ERR(bridge->conn); return ERR_PTR(ret); } - drm_connector_attach_encoder(bridge->conn, bridge->enc); return bridge; } From d627f7e6318906da2b95ac60616af7501d5145a5 Mon Sep 17 00:00:00 2001 From: Luca Ceresoli Date: Thu, 23 Apr 2026 11:17:19 +0200 Subject: [PATCH 047/145] drm/exynos: exynos_dp: remove now-redundant call to drm_connector_attach_encoder() drm_connector_attach_encoder() is now called by drm_bridge_connector_init(). Reviewed-by: Dmitry Baryshkov Link: https://patch.msgid.link/20260423-drm-bridge-connector-attach_encoder-v2-25-2ae6ca69b390@bootlin.com Signed-off-by: Luca Ceresoli --- drivers/gpu/drm/exynos/exynos_dp.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/gpu/drm/exynos/exynos_dp.c b/drivers/gpu/drm/exynos/exynos_dp.c index 6884ea6d04eb..b80540328150 100644 --- a/drivers/gpu/drm/exynos/exynos_dp.c +++ b/drivers/gpu/drm/exynos/exynos_dp.c @@ -118,7 +118,7 @@ static int exynos_dp_bind(struct device *dev, struct device *master, void *data) return ret; } - return drm_connector_attach_encoder(connector, dp->plat_data.encoder); + return 0; } static void exynos_dp_unbind(struct device *dev, struct device *master, From fa38bb8dc2e852e2979593b965779b8cca532014 Mon Sep 17 00:00:00 2001 From: Luca Ceresoli Date: Thu, 23 Apr 2026 11:17:20 +0200 Subject: [PATCH 048/145] drm: rcar-du: encoder: remove now-redundant call to drm_connector_attach_encoder() drm_connector_attach_encoder() is now called by drm_bridge_connector_init(). Reviewed-by: Dmitry Baryshkov Link: https://patch.msgid.link/20260423-drm-bridge-connector-attach_encoder-v2-26-2ae6ca69b390@bootlin.com Signed-off-by: Luca Ceresoli --- drivers/gpu/drm/renesas/rcar-du/rcar_du_encoder.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/gpu/drm/renesas/rcar-du/rcar_du_encoder.c b/drivers/gpu/drm/renesas/rcar-du/rcar_du_encoder.c index 32ea09d65d76..db2088529b48 100644 --- a/drivers/gpu/drm/renesas/rcar-du/rcar_du_encoder.c +++ b/drivers/gpu/drm/renesas/rcar-du/rcar_du_encoder.c @@ -142,7 +142,7 @@ int rcar_du_encoder_init(struct rcar_du_device *rcdu, return PTR_ERR(connector); } - return drm_connector_attach_encoder(connector, &renc->base); + return 0; } void rcar_du_encoder_cleanup(struct rcar_du_device *rcdu) From 88bcd924cd85a29658a60418f6e60a0f912f990c Mon Sep 17 00:00:00 2001 From: Luca Ceresoli Date: Thu, 23 Apr 2026 11:17:21 +0200 Subject: [PATCH 049/145] drm: renesas: rz-du: rzg2l_du_encoder: remove now-redundant call to drm_connector_attach_encoder() drm_connector_attach_encoder() is now called by drm_bridge_connector_init(). Tested-by: Biju Das # RZ/G2L SMARC EVK Reviewed-by: Dmitry Baryshkov Link: https://patch.msgid.link/20260423-drm-bridge-connector-attach_encoder-v2-27-2ae6ca69b390@bootlin.com Signed-off-by: Luca Ceresoli --- drivers/gpu/drm/renesas/rz-du/rzg2l_du_encoder.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/gpu/drm/renesas/rz-du/rzg2l_du_encoder.c b/drivers/gpu/drm/renesas/rz-du/rzg2l_du_encoder.c index d53068733c66..0e567b57a408 100644 --- a/drivers/gpu/drm/renesas/rz-du/rzg2l_du_encoder.c +++ b/drivers/gpu/drm/renesas/rz-du/rzg2l_du_encoder.c @@ -129,5 +129,5 @@ int rzg2l_du_encoder_init(struct rzg2l_du_device *rcdu, return PTR_ERR(connector); } - return drm_connector_attach_encoder(connector, &renc->base); + return 0; } From b7e25e250ea405f1c65256494b56e0f6443cc96a Mon Sep 17 00:00:00 2001 From: Luca Ceresoli Date: Thu, 23 Apr 2026 11:17:22 +0200 Subject: [PATCH 050/145] drm/rockchip: analogix_dp: remove now-redundant call to drm_connector_attach_encoder() drm_connector_attach_encoder() is now called by drm_bridge_connector_init(). Reviewed-by: Dmitry Baryshkov Link: https://patch.msgid.link/20260423-drm-bridge-connector-attach_encoder-v2-28-2ae6ca69b390@bootlin.com Signed-off-by: Luca Ceresoli --- drivers/gpu/drm/rockchip/analogix_dp-rockchip.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/gpu/drm/rockchip/analogix_dp-rockchip.c b/drivers/gpu/drm/rockchip/analogix_dp-rockchip.c index eea230f0227a..41ff44eaf44d 100644 --- a/drivers/gpu/drm/rockchip/analogix_dp-rockchip.c +++ b/drivers/gpu/drm/rockchip/analogix_dp-rockchip.c @@ -395,7 +395,7 @@ static int rockchip_dp_bind(struct device *dev, struct device *master, goto err_cleanup_encoder; } - return drm_connector_attach_encoder(connector, dp->plat_data.encoder); + return 0; err_cleanup_encoder: dp->encoder.encoder.funcs->destroy(&dp->encoder.encoder); return ret; From 8015bfccca36672e412dae4240886c71278c5b3c Mon Sep 17 00:00:00 2001 From: Luca Ceresoli Date: Thu, 23 Apr 2026 11:17:23 +0200 Subject: [PATCH 051/145] drm/rockchip: dw_dp: remove now-redundant call to drm_connector_attach_encoder() drm_connector_attach_encoder() is now called by drm_bridge_connector_init(). Reviewed-by: Dmitry Baryshkov Link: https://patch.msgid.link/20260423-drm-bridge-connector-attach_encoder-v2-29-2ae6ca69b390@bootlin.com Signed-off-by: Luca Ceresoli --- drivers/gpu/drm/rockchip/dw_dp-rockchip.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/gpu/drm/rockchip/dw_dp-rockchip.c b/drivers/gpu/drm/rockchip/dw_dp-rockchip.c index 22c0911f1896..a9a8bf43aa1d 100644 --- a/drivers/gpu/drm/rockchip/dw_dp-rockchip.c +++ b/drivers/gpu/drm/rockchip/dw_dp-rockchip.c @@ -111,7 +111,7 @@ static int dw_dp_rockchip_bind(struct device *dev, struct device *master, void * return dev_err_probe(dev, PTR_ERR(connector), "Failed to init bridge connector"); - return drm_connector_attach_encoder(connector, encoder); + return 0; } static const struct component_ops dw_dp_rockchip_component_ops = { From 14a25df41b19aba228e66c0d9578e6e6b3cc58f9 Mon Sep 17 00:00:00 2001 From: Luca Ceresoli Date: Thu, 23 Apr 2026 11:17:24 +0200 Subject: [PATCH 052/145] drm/rockchip: dw_hdmi_qp: remove now-redundant call to drm_connector_attach_encoder() drm_connector_attach_encoder() is now called by drm_bridge_connector_init(). Reviewed-by: Dmitry Baryshkov Link: https://patch.msgid.link/20260423-drm-bridge-connector-attach_encoder-v2-30-2ae6ca69b390@bootlin.com Signed-off-by: Luca Ceresoli --- drivers/gpu/drm/rockchip/dw_hdmi_qp-rockchip.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/gpu/drm/rockchip/dw_hdmi_qp-rockchip.c b/drivers/gpu/drm/rockchip/dw_hdmi_qp-rockchip.c index c78db7f8ab6c..f35484715c2d 100644 --- a/drivers/gpu/drm/rockchip/dw_hdmi_qp-rockchip.c +++ b/drivers/gpu/drm/rockchip/dw_hdmi_qp-rockchip.c @@ -603,7 +603,7 @@ static int dw_hdmi_qp_rockchip_bind(struct device *dev, struct device *master, return dev_err_probe(hdmi->dev, PTR_ERR(connector), "Failed to init bridge connector\n"); - return drm_connector_attach_encoder(connector, encoder); + return 0; } static void dw_hdmi_qp_rockchip_unbind(struct device *dev, From 6db094d4ce87fb4caf90db9863bb6a8b427b15c9 Mon Sep 17 00:00:00 2001 From: Luca Ceresoli Date: Thu, 23 Apr 2026 11:17:25 +0200 Subject: [PATCH 053/145] drm/rockchip: inno-hdmi: remove now-redundant call to drm_connector_attach_encoder() drm_connector_attach_encoder() is now called by drm_bridge_connector_init(). Reviewed-by: Dmitry Baryshkov Link: https://patch.msgid.link/20260423-drm-bridge-connector-attach_encoder-v2-31-2ae6ca69b390@bootlin.com Signed-off-by: Luca Ceresoli --- drivers/gpu/drm/rockchip/inno_hdmi-rockchip.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/gpu/drm/rockchip/inno_hdmi-rockchip.c b/drivers/gpu/drm/rockchip/inno_hdmi-rockchip.c index 28e6fb09aae7..45a6dae4de31 100644 --- a/drivers/gpu/drm/rockchip/inno_hdmi-rockchip.c +++ b/drivers/gpu/drm/rockchip/inno_hdmi-rockchip.c @@ -137,7 +137,7 @@ static int inno_hdmi_rockchip_bind(struct device *dev, struct device *master, vo return ret; } - return drm_connector_attach_encoder(connector, encoder); + return 0; } static const struct component_ops inno_hdmi_rockchip_ops = { From 4e833e078f3d40d4f4a24c162210a1b7855f1539 Mon Sep 17 00:00:00 2001 From: Luca Ceresoli Date: Thu, 23 Apr 2026 11:17:26 +0200 Subject: [PATCH 054/145] drm/msm/mdp4: remove now-redundant call to drm_connector_attach_encoder() drm_connector_attach_encoder() is now called by drm_bridge_connector_init(). Reviewed-by: Dmitry Baryshkov Acked-by: Dmitry Baryshkov Link: https://patch.msgid.link/20260423-drm-bridge-connector-attach_encoder-v2-32-2ae6ca69b390@bootlin.com Signed-off-by: Luca Ceresoli --- drivers/gpu/drm/msm/disp/mdp4/mdp4_kms.c | 7 ------- 1 file changed, 7 deletions(-) diff --git a/drivers/gpu/drm/msm/disp/mdp4/mdp4_kms.c b/drivers/gpu/drm/msm/disp/mdp4/mdp4_kms.c index 809ca191e9de..7726edb0d4ed 100644 --- a/drivers/gpu/drm/msm/disp/mdp4/mdp4_kms.c +++ b/drivers/gpu/drm/msm/disp/mdp4/mdp4_kms.c @@ -232,13 +232,6 @@ static int mdp4_modeset_init_intf(struct mdp4_kms *mdp4_kms, return PTR_ERR(connector); } - ret = drm_connector_attach_encoder(connector, encoder); - if (ret) { - DRM_DEV_ERROR(dev->dev, "failed to attach LVDS connector: %d\n", ret); - - return ret; - } - break; case DRM_MODE_ENCODER_TMDS: encoder = mdp4_dtv_encoder_init(dev); From f9274ba1dff8b0adff22e8d877ec1e85bb14d0c3 Mon Sep 17 00:00:00 2001 From: Luca Ceresoli Date: Thu, 23 Apr 2026 11:17:27 +0200 Subject: [PATCH 055/145] drm/msm/dsi: remove now-redundant call to drm_connector_attach_encoder() drm_connector_attach_encoder() is now called by drm_bridge_connector_init(). Reviewed-by: Dmitry Baryshkov Acked-by: Dmitry Baryshkov Link: https://patch.msgid.link/20260423-drm-bridge-connector-attach_encoder-v2-33-2ae6ca69b390@bootlin.com Signed-off-by: Luca Ceresoli --- drivers/gpu/drm/msm/dsi/dsi_manager.c | 4 ---- 1 file changed, 4 deletions(-) diff --git a/drivers/gpu/drm/msm/dsi/dsi_manager.c b/drivers/gpu/drm/msm/dsi/dsi_manager.c index ca400924d4ee..46faeaae9d94 100644 --- a/drivers/gpu/drm/msm/dsi/dsi_manager.c +++ b/drivers/gpu/drm/msm/dsi/dsi_manager.c @@ -485,10 +485,6 @@ int msm_dsi_manager_connector_init(struct msm_dsi *msm_dsi, return PTR_ERR(connector); } - ret = drm_connector_attach_encoder(connector, encoder); - if (ret < 0) - return ret; - return 0; } From da3918b645a5efe6fad2aa53b84a4d98c3df999c Mon Sep 17 00:00:00 2001 From: Luca Ceresoli Date: Thu, 23 Apr 2026 11:17:28 +0200 Subject: [PATCH 056/145] drm/mxsfb/lcdif: remove now-redundant call to drm_connector_attach_encoder() drm_connector_attach_encoder() is now called by drm_bridge_connector_init(). Reviewed-by: Liu Ying Reviewed-by: Dmitry Baryshkov Link: https://patch.msgid.link/20260423-drm-bridge-connector-attach_encoder-v2-34-2ae6ca69b390@bootlin.com Signed-off-by: Luca Ceresoli --- drivers/gpu/drm/mxsfb/lcdif_drv.c | 6 ------ 1 file changed, 6 deletions(-) diff --git a/drivers/gpu/drm/mxsfb/lcdif_drv.c b/drivers/gpu/drm/mxsfb/lcdif_drv.c index 7f07ae24e0dc..f5bb59cd5028 100644 --- a/drivers/gpu/drm/mxsfb/lcdif_drv.c +++ b/drivers/gpu/drm/mxsfb/lcdif_drv.c @@ -99,12 +99,6 @@ static int lcdif_attach_bridge(struct lcdif_drm_private *lcdif) return dev_err_probe(dev, PTR_ERR(connector), "Failed to init bridge_connector for endpoint%u\n", of_ep.id); - - ret = drm_connector_attach_encoder(connector, encoder); - if (ret) - return dev_err_probe(dev, ret, - "Failed to attach connector for endpoint%u\n", - of_ep.id); } return 0; From 24202edb689ead20411568251792a31103b9bde0 Mon Sep 17 00:00:00 2001 From: Luca Ceresoli Date: Thu, 23 Apr 2026 13:53:28 +0200 Subject: [PATCH 057/145] drm/rockchip: lvds: remove now-redundant call to drm_connector_attach_encoder() drm_connector_attach_encoder() is now called by drm_bridge_connector_init(). Reviewed-by: Dmitry Baryshkov Link: https://patch.msgid.link/20260423115334.444750-1-luca.ceresoli@bootlin.com Signed-off-by: Luca Ceresoli --- drivers/gpu/drm/rockchip/rockchip_lvds.c | 6 ------ 1 file changed, 6 deletions(-) diff --git a/drivers/gpu/drm/rockchip/rockchip_lvds.c b/drivers/gpu/drm/rockchip/rockchip_lvds.c index 75f898a10cbc..7a0c4fa29f2f 100644 --- a/drivers/gpu/drm/rockchip/rockchip_lvds.c +++ b/drivers/gpu/drm/rockchip/rockchip_lvds.c @@ -628,12 +628,6 @@ static int rockchip_lvds_bind(struct device *dev, struct device *master, ret = PTR_ERR(connector); goto err_free_bridge; } - - ret = drm_connector_attach_encoder(connector, encoder); - if (ret < 0) { - drm_err(drm_dev, "failed to attach encoder: %d\n", ret); - goto err_free_bridge; - } } pm_runtime_enable(dev); From 71d12d0d8a4a61f39297d17eef1d0d0ea8239d63 Mon Sep 17 00:00:00 2001 From: Luca Ceresoli Date: Thu, 23 Apr 2026 13:55:45 +0200 Subject: [PATCH 058/145] drm/tidss: remove now-redundant call to drm_connector_attach_encoder() drm_connector_attach_encoder() is now called by drm_bridge_connector_init(). Reviewed-by: Dmitry Baryshkov Link: https://patch.msgid.link/20260423115550.444930-2-luca.ceresoli@bootlin.com Signed-off-by: Luca Ceresoli --- drivers/gpu/drm/tidss/tidss_encoder.c | 6 ------ 1 file changed, 6 deletions(-) diff --git a/drivers/gpu/drm/tidss/tidss_encoder.c b/drivers/gpu/drm/tidss/tidss_encoder.c index db467bbcdb77..34db8d2a3792 100644 --- a/drivers/gpu/drm/tidss/tidss_encoder.c +++ b/drivers/gpu/drm/tidss/tidss_encoder.c @@ -123,12 +123,6 @@ int tidss_encoder_create(struct tidss_device *tidss, return PTR_ERR(connector); } - ret = drm_connector_attach_encoder(connector, enc); - if (ret) { - dev_err(tidss->dev, "attaching encoder to connector failed\n"); - return ret; - } - t_enc->connector = connector; dev_dbg(tidss->dev, "Encoder create done\n"); From 055673da01cdb130732ee556db58f7408392c1b8 Mon Sep 17 00:00:00 2001 From: Luca Ceresoli Date: Thu, 23 Apr 2026 13:55:46 +0200 Subject: [PATCH 059/145] drm/tilcdc: remove now-redundant call to drm_connector_attach_encoder() drm_connector_attach_encoder() is now called by drm_bridge_connector_init(). Reviewed-by: Dmitry Baryshkov Link: https://patch.msgid.link/20260423115550.444930-3-luca.ceresoli@bootlin.com Signed-off-by: Luca Ceresoli --- drivers/gpu/drm/tilcdc/tilcdc_encoder.c | 6 ------ 1 file changed, 6 deletions(-) diff --git a/drivers/gpu/drm/tilcdc/tilcdc_encoder.c b/drivers/gpu/drm/tilcdc/tilcdc_encoder.c index 680a2ac6ab59..ac4b5beb2dd5 100644 --- a/drivers/gpu/drm/tilcdc/tilcdc_encoder.c +++ b/drivers/gpu/drm/tilcdc/tilcdc_encoder.c @@ -35,12 +35,6 @@ int tilcdc_attach_bridge(struct drm_device *ddev, struct drm_bridge *bridge) return PTR_ERR(connector); } - ret = drm_connector_attach_encoder(connector, &priv->encoder->base); - if (ret) { - drm_err(ddev, "attaching encoder to connector failed\n"); - return ret; - } - priv->connector = connector; return 0; } From 42ccccb38ca8bac394faeb30c924ad542f5f1bee Mon Sep 17 00:00:00 2001 From: Luca Ceresoli Date: Thu, 23 Apr 2026 13:55:47 +0200 Subject: [PATCH 060/145] drm: zynqmp_kms: remove now-redundant call to drm_connector_attach_encoder() drm_connector_attach_encoder() is now called by drm_bridge_connector_init(). Reviewed-by: Dmitry Baryshkov Link: https://patch.msgid.link/20260423115550.444930-4-luca.ceresoli@bootlin.com Signed-off-by: Luca Ceresoli --- drivers/gpu/drm/xlnx/zynqmp_kms.c | 6 ------ 1 file changed, 6 deletions(-) diff --git a/drivers/gpu/drm/xlnx/zynqmp_kms.c b/drivers/gpu/drm/xlnx/zynqmp_kms.c index 02f3a7d78cf8..a341ca492253 100644 --- a/drivers/gpu/drm/xlnx/zynqmp_kms.c +++ b/drivers/gpu/drm/xlnx/zynqmp_kms.c @@ -453,12 +453,6 @@ static int zynqmp_dpsub_kms_init(struct zynqmp_dpsub *dpsub) goto err_encoder; } - ret = drm_connector_attach_encoder(connector, encoder); - if (ret < 0) { - dev_err(dpsub->dev, "failed to attach connector to encoder\n"); - goto err_encoder; - } - return 0; err_encoder: From 2b727270b955b72cf6f47c5883bdc6f997f0e06f Mon Sep 17 00:00:00 2001 From: Luca Ceresoli Date: Thu, 23 Apr 2026 13:55:48 +0200 Subject: [PATCH 061/145] drm/imx: dc: remove now-redundant call to drm_connector_attach_encoder() drm_connector_attach_encoder() is now called by drm_bridge_connector_init(). Reviewed-by: Liu Ying Reviewed-by: Dmitry Baryshkov Link: https://patch.msgid.link/20260423115550.444930-5-luca.ceresoli@bootlin.com Signed-off-by: Luca Ceresoli --- drivers/gpu/drm/imx/dc/dc-kms.c | 8 +------- 1 file changed, 1 insertion(+), 7 deletions(-) diff --git a/drivers/gpu/drm/imx/dc/dc-kms.c b/drivers/gpu/drm/imx/dc/dc-kms.c index 2b18aa37a4a8..0f8cfaf4c4d1 100644 --- a/drivers/gpu/drm/imx/dc/dc-kms.c +++ b/drivers/gpu/drm/imx/dc/dc-kms.c @@ -81,13 +81,7 @@ static int dc_kms_init_encoder_per_crtc(struct dc_drm_device *dc_drm, return ret; } - ret = drm_connector_attach_encoder(connector, encoder); - if (ret) - dev_err(dev, - "failed to attach encoder to connector for CRTC%u: %d\n", - crtc->index, ret); - - return ret; + return 0; } int dc_kms_init(struct dc_drm_device *dc_drm) From d5d8e04dc0557437b19039206012305166df2bf7 Mon Sep 17 00:00:00 2001 From: Luca Ceresoli Date: Thu, 23 Apr 2026 13:55:49 +0200 Subject: [PATCH 062/145] drm/rockchip: rgb: remove now-redundant call to drm_connector_attach_encoder() drm_connector_attach_encoder() is now called by drm_bridge_connector_init(). Reviewed-by: Dmitry Baryshkov Link: https://patch.msgid.link/20260423115550.444930-6-luca.ceresoli@bootlin.com Signed-off-by: Luca Ceresoli --- drivers/gpu/drm/rockchip/rockchip_rgb.c | 9 --------- 1 file changed, 9 deletions(-) diff --git a/drivers/gpu/drm/rockchip/rockchip_rgb.c b/drivers/gpu/drm/rockchip/rockchip_rgb.c index 5c0c6e2cc28d..add3123e5ce7 100644 --- a/drivers/gpu/drm/rockchip/rockchip_rgb.c +++ b/drivers/gpu/drm/rockchip/rockchip_rgb.c @@ -162,17 +162,8 @@ struct rockchip_rgb *rockchip_rgb_init(struct device *dev, rgb->encoder.crtc_endpoint_id = endpoint_id; - ret = drm_connector_attach_encoder(connector, encoder); - if (ret < 0) { - DRM_DEV_ERROR(drm_dev->dev, - "failed to attach encoder: %d\n", ret); - goto err_free_connector; - } - return rgb; -err_free_connector: - drm_connector_cleanup(connector); err_free_encoder: drm_encoder_cleanup(encoder); return ERR_PTR(ret); From 6533278b0deb14de860035dd1913e1e55e781e60 Mon Sep 17 00:00:00 2001 From: Luca Ceresoli Date: Thu, 23 Apr 2026 13:55:50 +0200 Subject: [PATCH 063/145] drm: renesas: shmobile: remove now-redundant call to drm_connector_attach_encoder() shmob_drm_connector_create() can init the connector in two ways, based on the 'if (sdev->pdata)': 1. manually in shmob_drm_connector_create(), or 2. delegating to drm_bridge_connector_init() Whichever branch is taken, drm_connector_attach_encoder() is called immediately after to attach the connector to the encoder. Now drm_bridge_connector_init() calls drm_connector_attach_encoder() on the connector so it is not needed anymore in case 2 and should be removed, but it is still needed in case 1. Move drm_connector_attach_encoder() from the common path to inside shmob_drm_connector_create() in order to get back to a single drm_connector_attach_encoder() in both cases. Tested-by: Geert Uytterhoeven Reviewed-by: Dmitry Baryshkov Link: https://patch.msgid.link/20260423115550.444930-7-luca.ceresoli@bootlin.com Signed-off-by: Luca Ceresoli --- .../gpu/drm/renesas/shmobile/shmob_drm_crtc.c | 16 +++++++--------- 1 file changed, 7 insertions(+), 9 deletions(-) diff --git a/drivers/gpu/drm/renesas/shmobile/shmob_drm_crtc.c b/drivers/gpu/drm/renesas/shmobile/shmob_drm_crtc.c index 5f460b38596c..815c770147ed 100644 --- a/drivers/gpu/drm/renesas/shmobile/shmob_drm_crtc.c +++ b/drivers/gpu/drm/renesas/shmobile/shmob_drm_crtc.c @@ -583,6 +583,13 @@ shmob_drm_connector_init(struct shmob_drm_device *sdev, drm_connector_helper_add(connector, &connector_helper_funcs); + ret = drm_connector_attach_encoder(connector, encoder); + if (ret < 0) { + drm_connector_cleanup(connector); + kfree(scon); + return ERR_PTR(ret); + } + return connector; } @@ -594,7 +601,6 @@ int shmob_drm_connector_create(struct shmob_drm_device *sdev, struct drm_encoder *encoder) { struct drm_connector *connector; - int ret; if (sdev->pdata) connector = shmob_drm_connector_init(sdev, encoder); @@ -606,17 +612,9 @@ int shmob_drm_connector_create(struct shmob_drm_device *sdev, return PTR_ERR(connector); } - ret = drm_connector_attach_encoder(connector, encoder); - if (ret < 0) - goto error; - connector->dpms = DRM_MODE_DPMS_OFF; sdev->connector = connector; return 0; - -error: - drm_connector_cleanup(connector); - return ret; } From 3221890f4e14f17ab46224798e89fbe099904edc Mon Sep 17 00:00:00 2001 From: Maciej Falkowski Date: Wed, 29 Apr 2026 10:39:58 +0200 Subject: [PATCH 064/145] MAINTAINERS: accel/ivpu: Remove myself and add Andrzej as maintainer As I will be departing from my current position, I will no longer maintain the driver, and remove myself from ivpu's maintainers entry. Andrzej will support Karol in maintaining the driver. Signed-off-by: Maciej Falkowski Reviewed-by: Karol Wachowski Reviewed-by: Andrzej Kacprowski Signed-off-by: Karol Wachowski Link: https://patch.msgid.link/20260429083958.2148777-1-maciej.falkowski@linux.intel.com --- MAINTAINERS | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/MAINTAINERS b/MAINTAINERS index 74d114884b34..54b941d6e8b2 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -7835,8 +7835,8 @@ F: drivers/soc/ti/smartreflex.c F: include/linux/power/smartreflex.h DRM ACCEL DRIVERS FOR INTEL VPU -M: Maciej Falkowski M: Karol Wachowski +M: Andrzej Kacprowski L: dri-devel@lists.freedesktop.org S: Supported T: git https://gitlab.freedesktop.org/drm/misc/kernel.git From a8f5738779a930b4f318104298ce84bc10d43fbc Mon Sep 17 00:00:00 2001 From: Karunika Choo Date: Mon, 27 Apr 2026 16:59:27 +0100 Subject: [PATCH 065/145] drm/panthor: Pass an iomem pointer to GPU register access helpers Convert the Panthor register access helpers to take an iomem pointer instead of a panthor_device pointer. This makes the helpers usable with block-local registers instead of routing all accesses to go through ptdev->iomem. It is a preparatory change for splitting the register space by components and for moving callers away from cross-component register accesses. No functional change intended. v3: - Pick up R-bs from Liviu and Steve v2: - Pick up Ack from Boris. Reviewed-by: Steven Price Reviewed-by: Liviu Dudau Acked-by: Boris Brezillon Signed-off-by: Karunika Choo Tested-by: Boris Brezillon Signed-off-by: Liviu Dudau Link: https://patch.msgid.link/20260427155934.416502-2-karunika.choo@arm.com --- drivers/gpu/drm/panthor/panthor_device.c | 2 +- drivers/gpu/drm/panthor/panthor_device.h | 78 ++++++++++++------------ drivers/gpu/drm/panthor/panthor_drv.c | 6 +- drivers/gpu/drm/panthor/panthor_fw.c | 22 +++---- drivers/gpu/drm/panthor/panthor_gpu.c | 42 ++++++------- drivers/gpu/drm/panthor/panthor_hw.c | 47 +++++++------- drivers/gpu/drm/panthor/panthor_mmu.c | 29 +++++---- drivers/gpu/drm/panthor/panthor_pwr.c | 61 +++++++++--------- drivers/gpu/drm/panthor/panthor_sched.c | 2 +- 9 files changed, 146 insertions(+), 143 deletions(-) diff --git a/drivers/gpu/drm/panthor/panthor_device.c b/drivers/gpu/drm/panthor/panthor_device.c index bc62a498a8a8..d62017b73409 100644 --- a/drivers/gpu/drm/panthor/panthor_device.c +++ b/drivers/gpu/drm/panthor/panthor_device.c @@ -43,7 +43,7 @@ static int panthor_gpu_coherency_init(struct panthor_device *ptdev) /* Check if the ACE-Lite coherency protocol is actually supported by the GPU. * ACE protocol has never been supported for command stream frontend GPUs. */ - if ((gpu_read(ptdev, GPU_COHERENCY_FEATURES) & + if ((gpu_read(ptdev->iomem, GPU_COHERENCY_FEATURES) & GPU_COHERENCY_PROT_BIT(ACE_LITE))) { ptdev->gpu_info.selected_coherency = GPU_COHERENCY_ACE_LITE; return 0; diff --git a/drivers/gpu/drm/panthor/panthor_device.h b/drivers/gpu/drm/panthor/panthor_device.h index 5cba272f9b4d..285bf7e4439e 100644 --- a/drivers/gpu/drm/panthor/panthor_device.h +++ b/drivers/gpu/drm/panthor/panthor_device.h @@ -505,7 +505,7 @@ static irqreturn_t panthor_ ## __name ## _irq_raw_handler(int irq, void *data) struct panthor_device *ptdev = pirq->ptdev; \ enum panthor_irq_state old_state; \ \ - if (!gpu_read(ptdev, __reg_prefix ## _INT_STAT)) \ + if (!gpu_read(ptdev->iomem, __reg_prefix ## _INT_STAT)) \ return IRQ_NONE; \ \ guard(spinlock_irqsave)(&pirq->mask_lock); \ @@ -515,7 +515,7 @@ static irqreturn_t panthor_ ## __name ## _irq_raw_handler(int irq, void *data) if (old_state != PANTHOR_IRQ_STATE_ACTIVE) \ return IRQ_NONE; \ \ - gpu_write(ptdev, __reg_prefix ## _INT_MASK, 0); \ + gpu_write(ptdev->iomem, __reg_prefix ## _INT_MASK, 0); \ return IRQ_WAKE_THREAD; \ } \ \ @@ -534,7 +534,7 @@ static irqreturn_t panthor_ ## __name ## _irq_threaded_handler(int irq, void *da * right before the HW event kicks in. TLDR; it's all expected races we're \ * covered for. \ */ \ - u32 status = gpu_read(ptdev, __reg_prefix ## _INT_RAWSTAT) & pirq->mask; \ + u32 status = gpu_read(ptdev->iomem, __reg_prefix ## _INT_RAWSTAT) & pirq->mask; \ \ if (!status) \ break; \ @@ -550,7 +550,7 @@ static irqreturn_t panthor_ ## __name ## _irq_threaded_handler(int irq, void *da PANTHOR_IRQ_STATE_PROCESSING, \ PANTHOR_IRQ_STATE_ACTIVE); \ if (old_state == PANTHOR_IRQ_STATE_PROCESSING) \ - gpu_write(ptdev, __reg_prefix ## _INT_MASK, pirq->mask); \ + gpu_write(ptdev->iomem, __reg_prefix ## _INT_MASK, pirq->mask); \ } \ \ return ret; \ @@ -560,7 +560,7 @@ static inline void panthor_ ## __name ## _irq_suspend(struct panthor_irq *pirq) { \ scoped_guard(spinlock_irqsave, &pirq->mask_lock) { \ atomic_set(&pirq->state, PANTHOR_IRQ_STATE_SUSPENDING); \ - gpu_write(pirq->ptdev, __reg_prefix ## _INT_MASK, 0); \ + gpu_write(pirq->ptdev->iomem, __reg_prefix ## _INT_MASK, 0); \ } \ synchronize_irq(pirq->irq); \ atomic_set(&pirq->state, PANTHOR_IRQ_STATE_SUSPENDED); \ @@ -571,8 +571,8 @@ static inline void panthor_ ## __name ## _irq_resume(struct panthor_irq *pirq) guard(spinlock_irqsave)(&pirq->mask_lock); \ \ atomic_set(&pirq->state, PANTHOR_IRQ_STATE_ACTIVE); \ - gpu_write(pirq->ptdev, __reg_prefix ## _INT_CLEAR, pirq->mask); \ - gpu_write(pirq->ptdev, __reg_prefix ## _INT_MASK, pirq->mask); \ + gpu_write(pirq->ptdev->iomem, __reg_prefix ## _INT_CLEAR, pirq->mask); \ + gpu_write(pirq->ptdev->iomem, __reg_prefix ## _INT_MASK, pirq->mask); \ } \ \ static int panthor_request_ ## __name ## _irq(struct panthor_device *ptdev, \ @@ -603,7 +603,7 @@ static inline void panthor_ ## __name ## _irq_enable_events(struct panthor_irq * * If the IRQ is suspended/suspending, the mask is restored at resume time. \ */ \ if (atomic_read(&pirq->state) == PANTHOR_IRQ_STATE_ACTIVE) \ - gpu_write(pirq->ptdev, __reg_prefix ## _INT_MASK, pirq->mask); \ + gpu_write(pirq->ptdev->iomem, __reg_prefix ## _INT_MASK, pirq->mask); \ } \ \ static inline void panthor_ ## __name ## _irq_disable_events(struct panthor_irq *pirq, u32 mask)\ @@ -617,80 +617,80 @@ static inline void panthor_ ## __name ## _irq_disable_events(struct panthor_irq * If the IRQ is suspended/suspending, the mask is restored at resume time. \ */ \ if (atomic_read(&pirq->state) == PANTHOR_IRQ_STATE_ACTIVE) \ - gpu_write(pirq->ptdev, __reg_prefix ## _INT_MASK, pirq->mask); \ + gpu_write(pirq->ptdev->iomem, __reg_prefix ## _INT_MASK, pirq->mask); \ } extern struct workqueue_struct *panthor_cleanup_wq; -static inline void gpu_write(struct panthor_device *ptdev, u32 reg, u32 data) +static inline void gpu_write(void __iomem *iomem, u32 reg, u32 data) { - writel(data, ptdev->iomem + reg); + writel(data, iomem + reg); } -static inline u32 gpu_read(struct panthor_device *ptdev, u32 reg) +static inline u32 gpu_read(void __iomem *iomem, u32 reg) { - return readl(ptdev->iomem + reg); + return readl(iomem + reg); } -static inline u32 gpu_read_relaxed(struct panthor_device *ptdev, u32 reg) +static inline u32 gpu_read_relaxed(void __iomem *iomem, u32 reg) { - return readl_relaxed(ptdev->iomem + reg); + return readl_relaxed(iomem + reg); } -static inline void gpu_write64(struct panthor_device *ptdev, u32 reg, u64 data) +static inline void gpu_write64(void __iomem *iomem, u32 reg, u64 data) { - gpu_write(ptdev, reg, lower_32_bits(data)); - gpu_write(ptdev, reg + 4, upper_32_bits(data)); + gpu_write(iomem, reg, lower_32_bits(data)); + gpu_write(iomem, reg + 4, upper_32_bits(data)); } -static inline u64 gpu_read64(struct panthor_device *ptdev, u32 reg) +static inline u64 gpu_read64(void __iomem *iomem, u32 reg) { - return (gpu_read(ptdev, reg) | ((u64)gpu_read(ptdev, reg + 4) << 32)); + return (gpu_read(iomem, reg) | ((u64)gpu_read(iomem, reg + 4) << 32)); } -static inline u64 gpu_read64_relaxed(struct panthor_device *ptdev, u32 reg) +static inline u64 gpu_read64_relaxed(void __iomem *iomem, u32 reg) { - return (gpu_read_relaxed(ptdev, reg) | - ((u64)gpu_read_relaxed(ptdev, reg + 4) << 32)); + return (gpu_read_relaxed(iomem, reg) | + ((u64)gpu_read_relaxed(iomem, reg + 4) << 32)); } -static inline u64 gpu_read64_counter(struct panthor_device *ptdev, u32 reg) +static inline u64 gpu_read64_counter(void __iomem *iomem, u32 reg) { u32 lo, hi1, hi2; do { - hi1 = gpu_read(ptdev, reg + 4); - lo = gpu_read(ptdev, reg); - hi2 = gpu_read(ptdev, reg + 4); + hi1 = gpu_read(iomem, reg + 4); + lo = gpu_read(iomem, reg); + hi2 = gpu_read(iomem, reg + 4); } while (hi1 != hi2); return lo | ((u64)hi2 << 32); } -#define gpu_read_poll_timeout(dev, reg, val, cond, delay_us, timeout_us) \ +#define gpu_read_poll_timeout(iomem, reg, val, cond, delay_us, timeout_us) \ read_poll_timeout(gpu_read, val, cond, delay_us, timeout_us, false, \ - dev, reg) + iomem, reg) -#define gpu_read_poll_timeout_atomic(dev, reg, val, cond, delay_us, \ +#define gpu_read_poll_timeout_atomic(iomem, reg, val, cond, delay_us, \ timeout_us) \ read_poll_timeout_atomic(gpu_read, val, cond, delay_us, timeout_us, \ - false, dev, reg) + false, iomem, reg) -#define gpu_read64_poll_timeout(dev, reg, val, cond, delay_us, timeout_us) \ +#define gpu_read64_poll_timeout(iomem, reg, val, cond, delay_us, timeout_us) \ read_poll_timeout(gpu_read64, val, cond, delay_us, timeout_us, false, \ - dev, reg) + iomem, reg) -#define gpu_read64_poll_timeout_atomic(dev, reg, val, cond, delay_us, \ +#define gpu_read64_poll_timeout_atomic(iomem, reg, val, cond, delay_us, \ timeout_us) \ read_poll_timeout_atomic(gpu_read64, val, cond, delay_us, timeout_us, \ - false, dev, reg) + false, iomem, reg) -#define gpu_read_relaxed_poll_timeout_atomic(dev, reg, val, cond, delay_us, \ +#define gpu_read_relaxed_poll_timeout_atomic(iomem, reg, val, cond, delay_us, \ timeout_us) \ read_poll_timeout_atomic(gpu_read_relaxed, val, cond, delay_us, \ - timeout_us, false, dev, reg) + timeout_us, false, iomem, reg) -#define gpu_read64_relaxed_poll_timeout(dev, reg, val, cond, delay_us, \ +#define gpu_read64_relaxed_poll_timeout(iomem, reg, val, cond, delay_us, \ timeout_us) \ read_poll_timeout(gpu_read64_relaxed, val, cond, delay_us, timeout_us, \ - false, dev, reg) + false, iomem, reg) #endif diff --git a/drivers/gpu/drm/panthor/panthor_drv.c b/drivers/gpu/drm/panthor/panthor_drv.c index 73fc983dc9b4..4f926c861fba 100644 --- a/drivers/gpu/drm/panthor/panthor_drv.c +++ b/drivers/gpu/drm/panthor/panthor_drv.c @@ -839,7 +839,7 @@ static int panthor_query_timestamp_info(struct panthor_device *ptdev, } if (flags & DRM_PANTHOR_TIMESTAMP_GPU_OFFSET) - arg->timestamp_offset = gpu_read64(ptdev, GPU_TIMESTAMP_OFFSET); + arg->timestamp_offset = gpu_read64(ptdev->iomem, GPU_TIMESTAMP_OFFSET); else arg->timestamp_offset = 0; @@ -854,7 +854,7 @@ static int panthor_query_timestamp_info(struct panthor_device *ptdev, query_start_time = 0; if (flags & DRM_PANTHOR_TIMESTAMP_GPU) - arg->current_timestamp = gpu_read64_counter(ptdev, GPU_TIMESTAMP); + arg->current_timestamp = gpu_read64_counter(ptdev->iomem, GPU_TIMESTAMP); else arg->current_timestamp = 0; @@ -870,7 +870,7 @@ static int panthor_query_timestamp_info(struct panthor_device *ptdev, } if (flags & DRM_PANTHOR_TIMESTAMP_GPU_CYCLE_COUNT) - arg->cycle_count = gpu_read64_counter(ptdev, GPU_CYCLE_COUNT); + arg->cycle_count = gpu_read64_counter(ptdev->iomem, GPU_CYCLE_COUNT); else arg->cycle_count = 0; diff --git a/drivers/gpu/drm/panthor/panthor_fw.c b/drivers/gpu/drm/panthor/panthor_fw.c index be0da5b1f3ab..69a19751a314 100644 --- a/drivers/gpu/drm/panthor/panthor_fw.c +++ b/drivers/gpu/drm/panthor/panthor_fw.c @@ -1054,7 +1054,7 @@ static void panthor_fw_init_global_iface(struct panthor_device *ptdev) GLB_CFG_POWEROFF_TIMER | GLB_CFG_PROGRESS_TIMER); - gpu_write(ptdev, CSF_DOORBELL(CSF_GLB_DOORBELL_ID), 1); + gpu_write(ptdev->iomem, CSF_DOORBELL(CSF_GLB_DOORBELL_ID), 1); /* Kick the watchdog. */ mod_delayed_work(ptdev->reset.wq, &ptdev->fw->watchdog.ping_work, @@ -1069,7 +1069,7 @@ static void panthor_job_irq_handler(struct panthor_device *ptdev, u32 status) if (tracepoint_enabled(gpu_job_irq)) start = ktime_get_ns(); - gpu_write(ptdev, JOB_INT_CLEAR, status); + gpu_write(ptdev->iomem, JOB_INT_CLEAR, status); if (!ptdev->fw->booted && (status & JOB_INT_GLOBAL_IF)) ptdev->fw->booted = true; @@ -1097,13 +1097,13 @@ static int panthor_fw_start(struct panthor_device *ptdev) ptdev->fw->booted = false; panthor_job_irq_enable_events(&ptdev->fw->irq, ~0); panthor_job_irq_resume(&ptdev->fw->irq); - gpu_write(ptdev, MCU_CONTROL, MCU_CONTROL_AUTO); + gpu_write(ptdev->iomem, MCU_CONTROL, MCU_CONTROL_AUTO); if (!wait_event_timeout(ptdev->fw->req_waitqueue, ptdev->fw->booted, msecs_to_jiffies(1000))) { if (!ptdev->fw->booted && - !(gpu_read(ptdev, JOB_INT_STAT) & JOB_INT_GLOBAL_IF)) + !(gpu_read(ptdev->iomem, JOB_INT_STAT) & JOB_INT_GLOBAL_IF)) timedout = true; } @@ -1114,7 +1114,7 @@ static int panthor_fw_start(struct panthor_device *ptdev) [MCU_STATUS_HALT] = "halt", [MCU_STATUS_FATAL] = "fatal", }; - u32 status = gpu_read(ptdev, MCU_STATUS); + u32 status = gpu_read(ptdev->iomem, MCU_STATUS); drm_err(&ptdev->base, "Failed to boot MCU (status=%s)", status < ARRAY_SIZE(status_str) ? status_str[status] : "unknown"); @@ -1128,8 +1128,8 @@ static void panthor_fw_stop(struct panthor_device *ptdev) { u32 status; - gpu_write(ptdev, MCU_CONTROL, MCU_CONTROL_DISABLE); - if (gpu_read_poll_timeout(ptdev, MCU_STATUS, status, + gpu_write(ptdev->iomem, MCU_CONTROL, MCU_CONTROL_DISABLE); + if (gpu_read_poll_timeout(ptdev->iomem, MCU_STATUS, status, status == MCU_STATUS_DISABLED, 10, 100000)) drm_err(&ptdev->base, "Failed to stop MCU"); } @@ -1139,7 +1139,7 @@ static bool panthor_fw_mcu_halted(struct panthor_device *ptdev) struct panthor_fw_global_iface *glb_iface = panthor_fw_get_glb_iface(ptdev); bool halted; - halted = gpu_read(ptdev, MCU_STATUS) == MCU_STATUS_HALT; + halted = gpu_read(ptdev->iomem, MCU_STATUS) == MCU_STATUS_HALT; if (panthor_fw_has_glb_state(ptdev)) halted &= (GLB_STATE_GET(glb_iface->output->ack) == GLB_STATE_HALT); @@ -1156,7 +1156,7 @@ static void panthor_fw_halt_mcu(struct panthor_device *ptdev) else panthor_fw_update_reqs(glb_iface, req, GLB_HALT, GLB_HALT); - gpu_write(ptdev, CSF_DOORBELL(CSF_GLB_DOORBELL_ID), 1); + gpu_write(ptdev->iomem, CSF_DOORBELL(CSF_GLB_DOORBELL_ID), 1); } static bool panthor_fw_wait_mcu_halted(struct panthor_device *ptdev) @@ -1414,7 +1414,7 @@ void panthor_fw_ring_csg_doorbells(struct panthor_device *ptdev, u32 csg_mask) struct panthor_fw_global_iface *glb_iface = panthor_fw_get_glb_iface(ptdev); panthor_fw_toggle_reqs(glb_iface, doorbell_req, doorbell_ack, csg_mask); - gpu_write(ptdev, CSF_DOORBELL(CSF_GLB_DOORBELL_ID), 1); + gpu_write(ptdev->iomem, CSF_DOORBELL(CSF_GLB_DOORBELL_ID), 1); } static void panthor_fw_ping_work(struct work_struct *work) @@ -1429,7 +1429,7 @@ static void panthor_fw_ping_work(struct work_struct *work) return; panthor_fw_toggle_reqs(glb_iface, req, ack, GLB_PING); - gpu_write(ptdev, CSF_DOORBELL(CSF_GLB_DOORBELL_ID), 1); + gpu_write(ptdev->iomem, CSF_DOORBELL(CSF_GLB_DOORBELL_ID), 1); ret = panthor_fw_glb_wait_acks(ptdev, GLB_PING, &acked, 100); if (ret) { diff --git a/drivers/gpu/drm/panthor/panthor_gpu.c b/drivers/gpu/drm/panthor/panthor_gpu.c index 2ab444ee8c71..bdb72cebccb3 100644 --- a/drivers/gpu/drm/panthor/panthor_gpu.c +++ b/drivers/gpu/drm/panthor/panthor_gpu.c @@ -56,7 +56,7 @@ struct panthor_gpu { static void panthor_gpu_coherency_set(struct panthor_device *ptdev) { - gpu_write(ptdev, GPU_COHERENCY_PROTOCOL, + gpu_write(ptdev->iomem, GPU_COHERENCY_PROTOCOL, ptdev->gpu_info.selected_coherency); } @@ -75,26 +75,26 @@ static void panthor_gpu_l2_config_set(struct panthor_device *ptdev) } for (i = 0; i < ARRAY_SIZE(data->asn_hash); i++) - gpu_write(ptdev, GPU_ASN_HASH(i), data->asn_hash[i]); + gpu_write(ptdev->iomem, GPU_ASN_HASH(i), data->asn_hash[i]); - l2_config = gpu_read(ptdev, GPU_L2_CONFIG); + l2_config = gpu_read(ptdev->iomem, GPU_L2_CONFIG); l2_config |= GPU_L2_CONFIG_ASN_HASH_ENABLE; - gpu_write(ptdev, GPU_L2_CONFIG, l2_config); + gpu_write(ptdev->iomem, GPU_L2_CONFIG, l2_config); } static void panthor_gpu_irq_handler(struct panthor_device *ptdev, u32 status) { - gpu_write(ptdev, GPU_INT_CLEAR, status); + gpu_write(ptdev->iomem, GPU_INT_CLEAR, status); if (tracepoint_enabled(gpu_power_status) && (status & GPU_POWER_INTERRUPTS_MASK)) trace_gpu_power_status(ptdev->base.dev, - gpu_read64(ptdev, SHADER_READY), - gpu_read64(ptdev, TILER_READY), - gpu_read64(ptdev, L2_READY)); + gpu_read64(ptdev->iomem, SHADER_READY), + gpu_read64(ptdev->iomem, TILER_READY), + gpu_read64(ptdev->iomem, L2_READY)); if (status & GPU_IRQ_FAULT) { - u32 fault_status = gpu_read(ptdev, GPU_FAULT_STATUS); - u64 address = gpu_read64(ptdev, GPU_FAULT_ADDR); + u32 fault_status = gpu_read(ptdev->iomem, GPU_FAULT_STATUS); + u64 address = gpu_read64(ptdev->iomem, GPU_FAULT_ADDR); drm_warn(&ptdev->base, "GPU Fault 0x%08x (%s) at 0x%016llx\n", fault_status, panthor_exception_name(ptdev, fault_status & 0xFF), @@ -204,7 +204,7 @@ int panthor_gpu_block_power_off(struct panthor_device *ptdev, u32 val; int ret; - ret = gpu_read64_relaxed_poll_timeout(ptdev, pwrtrans_reg, val, + ret = gpu_read64_relaxed_poll_timeout(ptdev->iomem, pwrtrans_reg, val, !(mask & val), 100, timeout_us); if (ret) { drm_err(&ptdev->base, @@ -213,9 +213,9 @@ int panthor_gpu_block_power_off(struct panthor_device *ptdev, return ret; } - gpu_write64(ptdev, pwroff_reg, mask); + gpu_write64(ptdev->iomem, pwroff_reg, mask); - ret = gpu_read64_relaxed_poll_timeout(ptdev, pwrtrans_reg, val, + ret = gpu_read64_relaxed_poll_timeout(ptdev->iomem, pwrtrans_reg, val, !(mask & val), 100, timeout_us); if (ret) { drm_err(&ptdev->base, @@ -247,7 +247,7 @@ int panthor_gpu_block_power_on(struct panthor_device *ptdev, u32 val; int ret; - ret = gpu_read64_relaxed_poll_timeout(ptdev, pwrtrans_reg, val, + ret = gpu_read64_relaxed_poll_timeout(ptdev->iomem, pwrtrans_reg, val, !(mask & val), 100, timeout_us); if (ret) { drm_err(&ptdev->base, @@ -256,9 +256,9 @@ int panthor_gpu_block_power_on(struct panthor_device *ptdev, return ret; } - gpu_write64(ptdev, pwron_reg, mask); + gpu_write64(ptdev->iomem, pwron_reg, mask); - ret = gpu_read64_relaxed_poll_timeout(ptdev, rdy_reg, val, + ret = gpu_read64_relaxed_poll_timeout(ptdev->iomem, rdy_reg, val, (mask & val) == val, 100, timeout_us); if (ret) { @@ -326,7 +326,7 @@ int panthor_gpu_flush_caches(struct panthor_device *ptdev, spin_lock_irqsave(&ptdev->gpu->reqs_lock, flags); if (!(ptdev->gpu->pending_reqs & GPU_IRQ_CLEAN_CACHES_COMPLETED)) { ptdev->gpu->pending_reqs |= GPU_IRQ_CLEAN_CACHES_COMPLETED; - gpu_write(ptdev, GPU_CMD, GPU_FLUSH_CACHES(l2, lsc, other)); + gpu_write(ptdev->iomem, GPU_CMD, GPU_FLUSH_CACHES(l2, lsc, other)); } else { ret = -EIO; } @@ -340,7 +340,7 @@ int panthor_gpu_flush_caches(struct panthor_device *ptdev, msecs_to_jiffies(100))) { spin_lock_irqsave(&ptdev->gpu->reqs_lock, flags); if ((ptdev->gpu->pending_reqs & GPU_IRQ_CLEAN_CACHES_COMPLETED) != 0 && - !(gpu_read(ptdev, GPU_INT_RAWSTAT) & GPU_IRQ_CLEAN_CACHES_COMPLETED)) + !(gpu_read(ptdev->iomem, GPU_INT_RAWSTAT) & GPU_IRQ_CLEAN_CACHES_COMPLETED)) ret = -ETIMEDOUT; else ptdev->gpu->pending_reqs &= ~GPU_IRQ_CLEAN_CACHES_COMPLETED; @@ -370,8 +370,8 @@ int panthor_gpu_soft_reset(struct panthor_device *ptdev) if (!drm_WARN_ON(&ptdev->base, ptdev->gpu->pending_reqs & GPU_IRQ_RESET_COMPLETED)) { ptdev->gpu->pending_reqs |= GPU_IRQ_RESET_COMPLETED; - gpu_write(ptdev, GPU_INT_CLEAR, GPU_IRQ_RESET_COMPLETED); - gpu_write(ptdev, GPU_CMD, GPU_SOFT_RESET); + gpu_write(ptdev->iomem, GPU_INT_CLEAR, GPU_IRQ_RESET_COMPLETED); + gpu_write(ptdev->iomem, GPU_CMD, GPU_SOFT_RESET); } spin_unlock_irqrestore(&ptdev->gpu->reqs_lock, flags); @@ -380,7 +380,7 @@ int panthor_gpu_soft_reset(struct panthor_device *ptdev) msecs_to_jiffies(100))) { spin_lock_irqsave(&ptdev->gpu->reqs_lock, flags); if ((ptdev->gpu->pending_reqs & GPU_IRQ_RESET_COMPLETED) != 0 && - !(gpu_read(ptdev, GPU_INT_RAWSTAT) & GPU_IRQ_RESET_COMPLETED)) + !(gpu_read(ptdev->iomem, GPU_INT_RAWSTAT) & GPU_IRQ_RESET_COMPLETED)) timedout = true; else ptdev->gpu->pending_reqs &= ~GPU_IRQ_RESET_COMPLETED; diff --git a/drivers/gpu/drm/panthor/panthor_hw.c b/drivers/gpu/drm/panthor/panthor_hw.c index d135aa6724fa..9309d0938212 100644 --- a/drivers/gpu/drm/panthor/panthor_hw.c +++ b/drivers/gpu/drm/panthor/panthor_hw.c @@ -194,35 +194,38 @@ static int panthor_gpu_info_init(struct panthor_device *ptdev) { unsigned int i; - ptdev->gpu_info.csf_id = gpu_read(ptdev, GPU_CSF_ID); - ptdev->gpu_info.gpu_rev = gpu_read(ptdev, GPU_REVID); - ptdev->gpu_info.core_features = gpu_read(ptdev, GPU_CORE_FEATURES); - ptdev->gpu_info.l2_features = gpu_read(ptdev, GPU_L2_FEATURES); - ptdev->gpu_info.tiler_features = gpu_read(ptdev, GPU_TILER_FEATURES); - ptdev->gpu_info.mem_features = gpu_read(ptdev, GPU_MEM_FEATURES); - ptdev->gpu_info.mmu_features = gpu_read(ptdev, GPU_MMU_FEATURES); - ptdev->gpu_info.thread_features = gpu_read(ptdev, GPU_THREAD_FEATURES); - ptdev->gpu_info.max_threads = gpu_read(ptdev, GPU_THREAD_MAX_THREADS); - ptdev->gpu_info.thread_max_workgroup_size = gpu_read(ptdev, GPU_THREAD_MAX_WORKGROUP_SIZE); - ptdev->gpu_info.thread_max_barrier_size = gpu_read(ptdev, GPU_THREAD_MAX_BARRIER_SIZE); - ptdev->gpu_info.coherency_features = gpu_read(ptdev, GPU_COHERENCY_FEATURES); + ptdev->gpu_info.csf_id = gpu_read(ptdev->iomem, GPU_CSF_ID); + ptdev->gpu_info.gpu_rev = gpu_read(ptdev->iomem, GPU_REVID); + ptdev->gpu_info.core_features = gpu_read(ptdev->iomem, GPU_CORE_FEATURES); + ptdev->gpu_info.l2_features = gpu_read(ptdev->iomem, GPU_L2_FEATURES); + ptdev->gpu_info.tiler_features = gpu_read(ptdev->iomem, GPU_TILER_FEATURES); + ptdev->gpu_info.mem_features = gpu_read(ptdev->iomem, GPU_MEM_FEATURES); + ptdev->gpu_info.mmu_features = gpu_read(ptdev->iomem, GPU_MMU_FEATURES); + ptdev->gpu_info.thread_features = gpu_read(ptdev->iomem, GPU_THREAD_FEATURES); + ptdev->gpu_info.max_threads = gpu_read(ptdev->iomem, GPU_THREAD_MAX_THREADS); + ptdev->gpu_info.thread_max_workgroup_size = + gpu_read(ptdev->iomem, GPU_THREAD_MAX_WORKGROUP_SIZE); + ptdev->gpu_info.thread_max_barrier_size = + gpu_read(ptdev->iomem, GPU_THREAD_MAX_BARRIER_SIZE); + ptdev->gpu_info.coherency_features = gpu_read(ptdev->iomem, GPU_COHERENCY_FEATURES); for (i = 0; i < 4; i++) - ptdev->gpu_info.texture_features[i] = gpu_read(ptdev, GPU_TEXTURE_FEATURES(i)); + ptdev->gpu_info.texture_features[i] = + gpu_read(ptdev->iomem, GPU_TEXTURE_FEATURES(i)); - ptdev->gpu_info.as_present = gpu_read(ptdev, GPU_AS_PRESENT); + ptdev->gpu_info.as_present = gpu_read(ptdev->iomem, GPU_AS_PRESENT); /* Introduced in arch 11.x */ - ptdev->gpu_info.gpu_features = gpu_read64(ptdev, GPU_FEATURES); + ptdev->gpu_info.gpu_features = gpu_read64(ptdev->iomem, GPU_FEATURES); if (panthor_hw_has_pwr_ctrl(ptdev)) { /* Introduced in arch 14.x */ - ptdev->gpu_info.l2_present = gpu_read64(ptdev, PWR_L2_PRESENT); - ptdev->gpu_info.tiler_present = gpu_read64(ptdev, PWR_TILER_PRESENT); - ptdev->gpu_info.shader_present = gpu_read64(ptdev, PWR_SHADER_PRESENT); + ptdev->gpu_info.l2_present = gpu_read64(ptdev->iomem, PWR_L2_PRESENT); + ptdev->gpu_info.tiler_present = gpu_read64(ptdev->iomem, PWR_TILER_PRESENT); + ptdev->gpu_info.shader_present = gpu_read64(ptdev->iomem, PWR_SHADER_PRESENT); } else { - ptdev->gpu_info.shader_present = gpu_read64(ptdev, GPU_SHADER_PRESENT); - ptdev->gpu_info.tiler_present = gpu_read64(ptdev, GPU_TILER_PRESENT); - ptdev->gpu_info.l2_present = gpu_read64(ptdev, GPU_L2_PRESENT); + ptdev->gpu_info.shader_present = gpu_read64(ptdev->iomem, GPU_SHADER_PRESENT); + ptdev->gpu_info.tiler_present = gpu_read64(ptdev->iomem, GPU_TILER_PRESENT); + ptdev->gpu_info.l2_present = gpu_read64(ptdev->iomem, GPU_L2_PRESENT); } return overload_shader_present(ptdev); @@ -287,7 +290,7 @@ static int panthor_hw_bind_device(struct panthor_device *ptdev) static int panthor_hw_gpu_id_init(struct panthor_device *ptdev) { - ptdev->gpu_info.gpu_id = gpu_read(ptdev, GPU_ID); + ptdev->gpu_info.gpu_id = gpu_read(ptdev->iomem, GPU_ID); if (!ptdev->gpu_info.gpu_id) return -ENXIO; diff --git a/drivers/gpu/drm/panthor/panthor_mmu.c b/drivers/gpu/drm/panthor/panthor_mmu.c index fc930ee158a5..6a8ac2239b9c 100644 --- a/drivers/gpu/drm/panthor/panthor_mmu.c +++ b/drivers/gpu/drm/panthor/panthor_mmu.c @@ -522,9 +522,8 @@ static int wait_ready(struct panthor_device *ptdev, u32 as_nr) /* Wait for the MMU status to indicate there is no active command, in * case one is pending. */ - ret = gpu_read_relaxed_poll_timeout_atomic(ptdev, AS_STATUS(as_nr), val, - !(val & AS_STATUS_AS_ACTIVE), - 10, 100000); + ret = gpu_read_relaxed_poll_timeout_atomic(ptdev->iomem, AS_STATUS(as_nr), val, + !(val & AS_STATUS_AS_ACTIVE), 10, 100000); if (ret) { panthor_device_schedule_reset(ptdev); @@ -541,7 +540,7 @@ static int as_send_cmd_and_wait(struct panthor_device *ptdev, u32 as_nr, u32 cmd /* write AS_COMMAND when MMU is ready to accept another command */ status = wait_ready(ptdev, as_nr); if (!status) { - gpu_write(ptdev, AS_COMMAND(as_nr), cmd); + gpu_write(ptdev->iomem, AS_COMMAND(as_nr), cmd); status = wait_ready(ptdev, as_nr); } @@ -592,9 +591,9 @@ static int panthor_mmu_as_enable(struct panthor_device *ptdev, u32 as_nr, panthor_mmu_irq_enable_events(&ptdev->mmu->irq, panthor_mmu_as_fault_mask(ptdev, as_nr)); - gpu_write64(ptdev, AS_TRANSTAB(as_nr), transtab); - gpu_write64(ptdev, AS_MEMATTR(as_nr), memattr); - gpu_write64(ptdev, AS_TRANSCFG(as_nr), transcfg); + gpu_write64(ptdev->iomem, AS_TRANSTAB(as_nr), transtab); + gpu_write64(ptdev->iomem, AS_MEMATTR(as_nr), memattr); + gpu_write64(ptdev->iomem, AS_TRANSCFG(as_nr), transcfg); return as_send_cmd_and_wait(ptdev, as_nr, AS_COMMAND_UPDATE); } @@ -629,9 +628,9 @@ static int panthor_mmu_as_disable(struct panthor_device *ptdev, u32 as_nr, if (recycle_slot) return 0; - gpu_write64(ptdev, AS_TRANSTAB(as_nr), 0); - gpu_write64(ptdev, AS_MEMATTR(as_nr), 0); - gpu_write64(ptdev, AS_TRANSCFG(as_nr), AS_TRANSCFG_ADRMODE_UNMAPPED); + gpu_write64(ptdev->iomem, AS_TRANSTAB(as_nr), 0); + gpu_write64(ptdev->iomem, AS_MEMATTR(as_nr), 0); + gpu_write64(ptdev->iomem, AS_TRANSCFG(as_nr), AS_TRANSCFG_ADRMODE_UNMAPPED); return as_send_cmd_and_wait(ptdev, as_nr, AS_COMMAND_UPDATE); } @@ -784,7 +783,7 @@ int panthor_vm_active(struct panthor_vm *vm) */ fault_mask = panthor_mmu_as_fault_mask(ptdev, as); if (ptdev->mmu->as.faulty_mask & fault_mask) { - gpu_write(ptdev, MMU_INT_CLEAR, fault_mask); + gpu_write(ptdev->iomem, MMU_INT_CLEAR, fault_mask); ptdev->mmu->as.faulty_mask &= ~fault_mask; } @@ -1731,7 +1730,7 @@ static int panthor_vm_lock_region(struct panthor_vm *vm, u64 start, u64 size) mutex_lock(&ptdev->mmu->as.slots_lock); if (vm->as.id >= 0 && size) { /* Lock the region that needs to be updated */ - gpu_write64(ptdev, AS_LOCKADDR(vm->as.id), + gpu_write64(ptdev->iomem, AS_LOCKADDR(vm->as.id), pack_region_range(ptdev, &start, &size)); /* If the lock succeeded, update the locked_region info. */ @@ -1792,8 +1791,8 @@ static void panthor_mmu_irq_handler(struct panthor_device *ptdev, u32 status) u32 access_type; u32 source_id; - fault_status = gpu_read(ptdev, AS_FAULTSTATUS(as)); - addr = gpu_read64(ptdev, AS_FAULTADDRESS(as)); + fault_status = gpu_read(ptdev->iomem, AS_FAULTSTATUS(as)); + addr = gpu_read64(ptdev->iomem, AS_FAULTADDRESS(as)); /* decode the fault status */ exception_type = fault_status & 0xFF; @@ -1824,7 +1823,7 @@ static void panthor_mmu_irq_handler(struct panthor_device *ptdev, u32 status) * Note that COMPLETED irqs are never cleared, but this is fine * because they are always masked. */ - gpu_write(ptdev, MMU_INT_CLEAR, mask); + gpu_write(ptdev->iomem, MMU_INT_CLEAR, mask); if (ptdev->mmu->as.slots[as].vm) ptdev->mmu->as.slots[as].vm->unhandled_fault = true; diff --git a/drivers/gpu/drm/panthor/panthor_pwr.c b/drivers/gpu/drm/panthor/panthor_pwr.c index ed3b2b4479ca..b77c85ad733a 100644 --- a/drivers/gpu/drm/panthor/panthor_pwr.c +++ b/drivers/gpu/drm/panthor/panthor_pwr.c @@ -55,7 +55,7 @@ struct panthor_pwr { static void panthor_pwr_irq_handler(struct panthor_device *ptdev, u32 status) { spin_lock(&ptdev->pwr->reqs_lock); - gpu_write(ptdev, PWR_INT_CLEAR, status); + gpu_write(ptdev->iomem, PWR_INT_CLEAR, status); if (unlikely(status & PWR_IRQ_COMMAND_NOT_ALLOWED)) drm_err(&ptdev->base, "PWR_IRQ: COMMAND_NOT_ALLOWED"); @@ -74,14 +74,14 @@ PANTHOR_IRQ_HANDLER(pwr, PWR, panthor_pwr_irq_handler); static void panthor_pwr_write_command(struct panthor_device *ptdev, u32 command, u64 args) { if (args) - gpu_write64(ptdev, PWR_CMDARG, args); + gpu_write64(ptdev->iomem, PWR_CMDARG, args); - gpu_write(ptdev, PWR_COMMAND, command); + gpu_write(ptdev->iomem, PWR_COMMAND, command); } static bool reset_irq_raised(struct panthor_device *ptdev) { - return gpu_read(ptdev, PWR_INT_RAWSTAT) & PWR_IRQ_RESET_COMPLETED; + return gpu_read(ptdev->iomem, PWR_INT_RAWSTAT) & PWR_IRQ_RESET_COMPLETED; } static bool reset_pending(struct panthor_device *ptdev) @@ -96,7 +96,7 @@ static int panthor_pwr_reset(struct panthor_device *ptdev, u32 reset_cmd) drm_WARN(&ptdev->base, 1, "Reset already pending"); } else { ptdev->pwr->pending_reqs |= PWR_IRQ_RESET_COMPLETED; - gpu_write(ptdev, PWR_INT_CLEAR, PWR_IRQ_RESET_COMPLETED); + gpu_write(ptdev->iomem, PWR_INT_CLEAR, PWR_IRQ_RESET_COMPLETED); panthor_pwr_write_command(ptdev, reset_cmd, 0); } } @@ -185,7 +185,7 @@ static int panthor_pwr_domain_wait_transition(struct panthor_device *ptdev, u32 u64 val; int ret = 0; - ret = gpu_read64_poll_timeout(ptdev, pwrtrans_reg, val, !(PWR_ALL_CORES_MASK & val), 100, + ret = gpu_read64_poll_timeout(ptdev->iomem, pwrtrans_reg, val, !(PWR_ALL_CORES_MASK & val), 100, timeout_us); if (ret) { drm_err(&ptdev->base, "%s domain power in transition, pwrtrans(0x%llx)", @@ -198,17 +198,17 @@ static int panthor_pwr_domain_wait_transition(struct panthor_device *ptdev, u32 static void panthor_pwr_debug_info_show(struct panthor_device *ptdev) { - drm_info(&ptdev->base, "GPU_FEATURES: 0x%016llx", gpu_read64(ptdev, GPU_FEATURES)); - drm_info(&ptdev->base, "PWR_STATUS: 0x%016llx", gpu_read64(ptdev, PWR_STATUS)); - drm_info(&ptdev->base, "L2_PRESENT: 0x%016llx", gpu_read64(ptdev, PWR_L2_PRESENT)); - drm_info(&ptdev->base, "L2_PWRTRANS: 0x%016llx", gpu_read64(ptdev, PWR_L2_PWRTRANS)); - drm_info(&ptdev->base, "L2_READY: 0x%016llx", gpu_read64(ptdev, PWR_L2_READY)); - drm_info(&ptdev->base, "TILER_PRESENT: 0x%016llx", gpu_read64(ptdev, PWR_TILER_PRESENT)); - drm_info(&ptdev->base, "TILER_PWRTRANS: 0x%016llx", gpu_read64(ptdev, PWR_TILER_PWRTRANS)); - drm_info(&ptdev->base, "TILER_READY: 0x%016llx", gpu_read64(ptdev, PWR_TILER_READY)); - drm_info(&ptdev->base, "SHADER_PRESENT: 0x%016llx", gpu_read64(ptdev, PWR_SHADER_PRESENT)); - drm_info(&ptdev->base, "SHADER_PWRTRANS: 0x%016llx", gpu_read64(ptdev, PWR_SHADER_PWRTRANS)); - drm_info(&ptdev->base, "SHADER_READY: 0x%016llx", gpu_read64(ptdev, PWR_SHADER_READY)); + drm_info(&ptdev->base, "GPU_FEATURES: 0x%016llx", gpu_read64(ptdev->iomem, GPU_FEATURES)); + drm_info(&ptdev->base, "PWR_STATUS: 0x%016llx", gpu_read64(ptdev->iomem, PWR_STATUS)); + drm_info(&ptdev->base, "L2_PRESENT: 0x%016llx", gpu_read64(ptdev->iomem, PWR_L2_PRESENT)); + drm_info(&ptdev->base, "L2_PWRTRANS: 0x%016llx", gpu_read64(ptdev->iomem, PWR_L2_PWRTRANS)); + drm_info(&ptdev->base, "L2_READY: 0x%016llx", gpu_read64(ptdev->iomem, PWR_L2_READY)); + drm_info(&ptdev->base, "TILER_PRESENT: 0x%016llx", gpu_read64(ptdev->iomem, PWR_TILER_PRESENT)); + drm_info(&ptdev->base, "TILER_PWRTRANS: 0x%016llx", gpu_read64(ptdev->iomem, PWR_TILER_PWRTRANS)); + drm_info(&ptdev->base, "TILER_READY: 0x%016llx", gpu_read64(ptdev->iomem, PWR_TILER_READY)); + drm_info(&ptdev->base, "SHADER_PRESENT: 0x%016llx", gpu_read64(ptdev->iomem, PWR_SHADER_PRESENT)); + drm_info(&ptdev->base, "SHADER_PWRTRANS: 0x%016llx", gpu_read64(ptdev->iomem, PWR_SHADER_PWRTRANS)); + drm_info(&ptdev->base, "SHADER_READY: 0x%016llx", gpu_read64(ptdev->iomem, PWR_SHADER_READY)); } static int panthor_pwr_domain_transition(struct panthor_device *ptdev, u32 cmd, u32 domain, @@ -240,13 +240,13 @@ static int panthor_pwr_domain_transition(struct panthor_device *ptdev, u32 cmd, return ret; /* domain already in target state, return early */ - if ((gpu_read64(ptdev, ready_reg) & mask) == expected_val) + if ((gpu_read64(ptdev->iomem, ready_reg) & mask) == expected_val) return 0; panthor_pwr_write_command(ptdev, pwr_cmd, mask); - ret = gpu_read64_poll_timeout(ptdev, ready_reg, val, (mask & val) == expected_val, 100, - timeout_us); + ret = gpu_read64_poll_timeout(ptdev->iomem, ready_reg, val, (mask & val) == expected_val, + 100, timeout_us); if (ret) { drm_err(&ptdev->base, "timeout waiting on %s power domain transition, cmd(0x%x), arg(0x%llx)", @@ -279,7 +279,7 @@ static int panthor_pwr_domain_transition(struct panthor_device *ptdev, u32 cmd, static int retract_domain(struct panthor_device *ptdev, u32 domain) { const u32 pwr_cmd = PWR_COMMAND_DEF(PWR_COMMAND_RETRACT, domain, 0); - const u64 pwr_status = gpu_read64(ptdev, PWR_STATUS); + const u64 pwr_status = gpu_read64(ptdev->iomem, PWR_STATUS); const u64 delegated_mask = PWR_STATUS_DOMAIN_DELEGATED(domain); const u64 allow_mask = PWR_STATUS_DOMAIN_ALLOWED(domain); u64 val; @@ -288,8 +288,9 @@ static int retract_domain(struct panthor_device *ptdev, u32 domain) if (drm_WARN_ON(&ptdev->base, domain == PWR_COMMAND_DOMAIN_L2)) return -EPERM; - ret = gpu_read64_poll_timeout(ptdev, PWR_STATUS, val, !(PWR_STATUS_RETRACT_PENDING & val), - 0, PWR_RETRACT_TIMEOUT_US); + ret = gpu_read64_poll_timeout(ptdev->iomem, PWR_STATUS, val, + !(PWR_STATUS_RETRACT_PENDING & val), 0, + PWR_RETRACT_TIMEOUT_US); if (ret) { drm_err(&ptdev->base, "%s domain retract pending", get_domain_name(domain)); return ret; @@ -306,7 +307,7 @@ static int retract_domain(struct panthor_device *ptdev, u32 domain) * On successful retraction * allow-flag will be set with delegated-flag being cleared. */ - ret = gpu_read64_poll_timeout(ptdev, PWR_STATUS, val, + ret = gpu_read64_poll_timeout(ptdev->iomem, PWR_STATUS, val, ((delegated_mask | allow_mask) & val) == allow_mask, 10, PWR_TRANSITION_TIMEOUT_US); if (ret) { @@ -333,7 +334,7 @@ static int retract_domain(struct panthor_device *ptdev, u32 domain) static int delegate_domain(struct panthor_device *ptdev, u32 domain) { const u32 pwr_cmd = PWR_COMMAND_DEF(PWR_COMMAND_DELEGATE, domain, 0); - const u64 pwr_status = gpu_read64(ptdev, PWR_STATUS); + const u64 pwr_status = gpu_read64(ptdev->iomem, PWR_STATUS); const u64 allow_mask = PWR_STATUS_DOMAIN_ALLOWED(domain); const u64 delegated_mask = PWR_STATUS_DOMAIN_DELEGATED(domain); u64 val; @@ -362,7 +363,7 @@ static int delegate_domain(struct panthor_device *ptdev, u32 domain) * On successful delegation * allow-flag will be cleared with delegated-flag being set. */ - ret = gpu_read64_poll_timeout(ptdev, PWR_STATUS, val, + ret = gpu_read64_poll_timeout(ptdev->iomem, PWR_STATUS, val, ((delegated_mask | allow_mask) & val) == delegated_mask, 10, PWR_TRANSITION_TIMEOUT_US); if (ret) { @@ -410,7 +411,7 @@ static int panthor_pwr_delegate_domains(struct panthor_device *ptdev) */ static int panthor_pwr_domain_force_off(struct panthor_device *ptdev, u32 domain) { - const u64 domain_ready = gpu_read64(ptdev, get_domain_ready_reg(domain)); + const u64 domain_ready = gpu_read64(ptdev->iomem, get_domain_ready_reg(domain)); int ret; /* Domain already powered down, early exit. */ @@ -471,7 +472,7 @@ int panthor_pwr_init(struct panthor_device *ptdev) int panthor_pwr_reset_soft(struct panthor_device *ptdev) { - if (!(gpu_read64(ptdev, PWR_STATUS) & PWR_STATUS_ALLOW_SOFT_RESET)) { + if (!(gpu_read64(ptdev->iomem, PWR_STATUS) & PWR_STATUS_ALLOW_SOFT_RESET)) { drm_err(&ptdev->base, "RESET_SOFT not allowed"); return -EOPNOTSUPP; } @@ -482,7 +483,7 @@ int panthor_pwr_reset_soft(struct panthor_device *ptdev) void panthor_pwr_l2_power_off(struct panthor_device *ptdev) { const u64 l2_allow_mask = PWR_STATUS_DOMAIN_ALLOWED(PWR_COMMAND_DOMAIN_L2); - const u64 pwr_status = gpu_read64(ptdev, PWR_STATUS); + const u64 pwr_status = gpu_read64(ptdev->iomem, PWR_STATUS); /* Abort if L2 power off constraints are not satisfied */ if (!(pwr_status & l2_allow_mask)) { @@ -508,7 +509,7 @@ void panthor_pwr_l2_power_off(struct panthor_device *ptdev) int panthor_pwr_l2_power_on(struct panthor_device *ptdev) { - const u32 pwr_status = gpu_read64(ptdev, PWR_STATUS); + const u32 pwr_status = gpu_read64(ptdev->iomem, PWR_STATUS); const u32 l2_allow_mask = PWR_STATUS_DOMAIN_ALLOWED(PWR_COMMAND_DOMAIN_L2); int ret; diff --git a/drivers/gpu/drm/panthor/panthor_sched.c b/drivers/gpu/drm/panthor/panthor_sched.c index 41d6369fa9c0..55660d9056ed 100644 --- a/drivers/gpu/drm/panthor/panthor_sched.c +++ b/drivers/gpu/drm/panthor/panthor_sched.c @@ -3372,7 +3372,7 @@ queue_run_job(struct drm_sched_job *sched_job) if (resume_tick) sched_resume_tick(ptdev); - gpu_write(ptdev, CSF_DOORBELL(queue->doorbell_id), 1); + gpu_write(ptdev->iomem, CSF_DOORBELL(queue->doorbell_id), 1); if (!sched->pm.has_ref && !(group->blocked_queues & BIT(job->queue_idx))) { pm_runtime_get(ptdev->base.dev); From 1f0a27ba793f3b9b5cf46f16157da41303b4aa88 Mon Sep 17 00:00:00 2001 From: Karunika Choo Date: Mon, 27 Apr 2026 16:59:28 +0100 Subject: [PATCH 066/145] drm/panthor: Split register definitions by components Split the panthor register definitions into per-component headers for the GPU, MMU, firmware, power and generic hardware registers. This makes the register layout easier to follow and prepares the driver for component-local iomem mappings by grouping definitions with the code that owns them. The old monolithic panthor_regs.h header can then be dropped. No functional change intended. v3: - Pick up Ack from Boris and R-bs from Liviu and Steve v2: - Merge GPU_ID definitions into panthor_gpu_regs.h - deleted panthor_hw_regs.h Reviewed-by: Steven Price Reviewed-by: Liviu Dudau Acked-by: Boris Brezillon Signed-off-by: Karunika Choo Tested-by: Boris Brezillon Signed-off-by: Liviu Dudau Link: https://patch.msgid.link/20260427155934.416502-3-karunika.choo@arm.com --- drivers/gpu/drm/panthor/panthor_device.c | 3 +- drivers/gpu/drm/panthor/panthor_drv.c | 2 +- drivers/gpu/drm/panthor/panthor_fw.c | 2 +- drivers/gpu/drm/panthor/panthor_fw_regs.h | 30 +++ drivers/gpu/drm/panthor/panthor_gpu.c | 2 +- drivers/gpu/drm/panthor/panthor_gpu_regs.h | 120 +++++++++ drivers/gpu/drm/panthor/panthor_heap.c | 2 +- drivers/gpu/drm/panthor/panthor_hw.c | 3 +- drivers/gpu/drm/panthor/panthor_hw.h | 2 +- drivers/gpu/drm/panthor/panthor_mmu.c | 3 +- drivers/gpu/drm/panthor/panthor_mmu_regs.h | 70 +++++ drivers/gpu/drm/panthor/panthor_pwr.c | 3 +- drivers/gpu/drm/panthor/panthor_pwr_regs.h | 83 ++++++ drivers/gpu/drm/panthor/panthor_regs.h | 291 --------------------- drivers/gpu/drm/panthor/panthor_sched.c | 3 +- 15 files changed, 318 insertions(+), 301 deletions(-) create mode 100644 drivers/gpu/drm/panthor/panthor_fw_regs.h create mode 100644 drivers/gpu/drm/panthor/panthor_gpu_regs.h create mode 100644 drivers/gpu/drm/panthor/panthor_mmu_regs.h create mode 100644 drivers/gpu/drm/panthor/panthor_pwr_regs.h delete mode 100644 drivers/gpu/drm/panthor/panthor_regs.h diff --git a/drivers/gpu/drm/panthor/panthor_device.c b/drivers/gpu/drm/panthor/panthor_device.c index d62017b73409..f876b13492ae 100644 --- a/drivers/gpu/drm/panthor/panthor_device.c +++ b/drivers/gpu/drm/panthor/panthor_device.c @@ -19,12 +19,13 @@ #include "panthor_devfreq.h" #include "panthor_device.h" #include "panthor_fw.h" +#include "panthor_fw_regs.h" #include "panthor_gem.h" #include "panthor_gpu.h" +#include "panthor_gpu_regs.h" #include "panthor_hw.h" #include "panthor_mmu.h" #include "panthor_pwr.h" -#include "panthor_regs.h" #include "panthor_sched.h" static int panthor_gpu_coherency_init(struct panthor_device *ptdev) diff --git a/drivers/gpu/drm/panthor/panthor_drv.c b/drivers/gpu/drm/panthor/panthor_drv.c index 4f926c861fba..e63210b01e6e 100644 --- a/drivers/gpu/drm/panthor/panthor_drv.c +++ b/drivers/gpu/drm/panthor/panthor_drv.c @@ -34,9 +34,9 @@ #include "panthor_fw.h" #include "panthor_gem.h" #include "panthor_gpu.h" +#include "panthor_gpu_regs.h" #include "panthor_heap.h" #include "panthor_mmu.h" -#include "panthor_regs.h" #include "panthor_sched.h" /** diff --git a/drivers/gpu/drm/panthor/panthor_fw.c b/drivers/gpu/drm/panthor/panthor_fw.c index 69a19751a314..4704275b9c8f 100644 --- a/drivers/gpu/drm/panthor/panthor_fw.c +++ b/drivers/gpu/drm/panthor/panthor_fw.c @@ -20,11 +20,11 @@ #include "panthor_device.h" #include "panthor_fw.h" +#include "panthor_fw_regs.h" #include "panthor_gem.h" #include "panthor_gpu.h" #include "panthor_hw.h" #include "panthor_mmu.h" -#include "panthor_regs.h" #include "panthor_sched.h" #include "panthor_trace.h" diff --git a/drivers/gpu/drm/panthor/panthor_fw_regs.h b/drivers/gpu/drm/panthor/panthor_fw_regs.h new file mode 100644 index 000000000000..d523d41e18dd --- /dev/null +++ b/drivers/gpu/drm/panthor/panthor_fw_regs.h @@ -0,0 +1,30 @@ +/* SPDX-License-Identifier: GPL-2.0 or MIT */ +/* Copyright 2026 ARM Limited. All rights reserved. */ + +#ifndef __PANTHOR_FW_REGS_H__ +#define __PANTHOR_FW_REGS_H__ + +#define MCU_CONTROL 0x700 +#define MCU_CONTROL_ENABLE 1 +#define MCU_CONTROL_AUTO 2 +#define MCU_CONTROL_DISABLE 0 + +#define MCU_STATUS 0x704 +#define MCU_STATUS_DISABLED 0 +#define MCU_STATUS_ENABLED 1 +#define MCU_STATUS_HALT 2 +#define MCU_STATUS_FATAL 3 + +#define JOB_INT_RAWSTAT 0x1000 +#define JOB_INT_CLEAR 0x1004 +#define JOB_INT_MASK 0x1008 +#define JOB_INT_STAT 0x100c +#define JOB_INT_GLOBAL_IF BIT(31) +#define JOB_INT_CSG_IF(x) BIT(x) + +#define CSF_GPU_LATEST_FLUSH_ID 0x10000 + +#define CSF_DOORBELL(i) (0x80000 + ((i) * 0x10000)) +#define CSF_GLB_DOORBELL_ID 0 + +#endif /* __PANTHOR_FW_REGS_H__ */ diff --git a/drivers/gpu/drm/panthor/panthor_gpu.c b/drivers/gpu/drm/panthor/panthor_gpu.c index bdb72cebccb3..fecc30747acf 100644 --- a/drivers/gpu/drm/panthor/panthor_gpu.c +++ b/drivers/gpu/drm/panthor/panthor_gpu.c @@ -19,8 +19,8 @@ #include "panthor_device.h" #include "panthor_gpu.h" +#include "panthor_gpu_regs.h" #include "panthor_hw.h" -#include "panthor_regs.h" #define CREATE_TRACE_POINTS #include "panthor_trace.h" diff --git a/drivers/gpu/drm/panthor/panthor_gpu_regs.h b/drivers/gpu/drm/panthor/panthor_gpu_regs.h new file mode 100644 index 000000000000..75474b7d7341 --- /dev/null +++ b/drivers/gpu/drm/panthor/panthor_gpu_regs.h @@ -0,0 +1,120 @@ +/* SPDX-License-Identifier: GPL-2.0 or MIT */ +/* Copyright 2026 ARM Limited. All rights reserved. */ + +#ifndef __PANTHOR_GPU_REGS_H__ +#define __PANTHOR_GPU_REGS_H__ + +#define GPU_ID 0x0 +#define GPU_ARCH_MAJOR(x) ((x) >> 28) +#define GPU_ARCH_MINOR(x) (((x) & GENMASK(27, 24)) >> 24) +#define GPU_ARCH_REV(x) (((x) & GENMASK(23, 20)) >> 20) +#define GPU_PROD_MAJOR(x) (((x) & GENMASK(19, 16)) >> 16) +#define GPU_VER_MAJOR(x) (((x) & GENMASK(15, 12)) >> 12) +#define GPU_VER_MINOR(x) (((x) & GENMASK(11, 4)) >> 4) +#define GPU_VER_STATUS(x) ((x) & GENMASK(3, 0)) + +#define GPU_L2_FEATURES 0x4 +#define GPU_L2_FEATURES_LINE_SIZE(x) (1 << ((x) & GENMASK(7, 0))) + +#define GPU_CORE_FEATURES 0x8 + +#define GPU_TILER_FEATURES 0xC +#define GPU_MEM_FEATURES 0x10 +#define GROUPS_L2_COHERENT BIT(0) + +#define GPU_MMU_FEATURES 0x14 +#define GPU_MMU_FEATURES_VA_BITS(x) ((x) & GENMASK(7, 0)) +#define GPU_MMU_FEATURES_PA_BITS(x) (((x) >> 8) & GENMASK(7, 0)) +#define GPU_AS_PRESENT 0x18 +#define GPU_CSF_ID 0x1C + +#define GPU_INT_RAWSTAT 0x20 +#define GPU_INT_CLEAR 0x24 +#define GPU_INT_MASK 0x28 +#define GPU_INT_STAT 0x2c +#define GPU_IRQ_FAULT BIT(0) +#define GPU_IRQ_PROTM_FAULT BIT(1) +#define GPU_IRQ_RESET_COMPLETED BIT(8) +#define GPU_IRQ_POWER_CHANGED BIT(9) +#define GPU_IRQ_POWER_CHANGED_ALL BIT(10) +#define GPU_IRQ_CLEAN_CACHES_COMPLETED BIT(17) +#define GPU_IRQ_DOORBELL_MIRROR BIT(18) +#define GPU_IRQ_MCU_STATUS_CHANGED BIT(19) +#define GPU_CMD 0x30 +#define GPU_CMD_DEF(type, payload) ((type) | ((payload) << 8)) +#define GPU_SOFT_RESET GPU_CMD_DEF(1, 1) +#define GPU_HARD_RESET GPU_CMD_DEF(1, 2) +#define CACHE_CLEAN BIT(0) +#define CACHE_INV BIT(1) +#define GPU_FLUSH_CACHES(l2, lsc, oth) \ + GPU_CMD_DEF(4, ((l2) << 0) | ((lsc) << 4) | ((oth) << 8)) + +#define GPU_STATUS 0x34 +#define GPU_STATUS_ACTIVE BIT(0) +#define GPU_STATUS_PWR_ACTIVE BIT(1) +#define GPU_STATUS_PAGE_FAULT BIT(4) +#define GPU_STATUS_PROTM_ACTIVE BIT(7) +#define GPU_STATUS_DBG_ENABLED BIT(8) + +#define GPU_FAULT_STATUS 0x3C +#define GPU_FAULT_ADDR 0x40 +#define GPU_L2_CONFIG 0x48 +#define GPU_L2_CONFIG_ASN_HASH_ENABLE BIT(24) + +#define GPU_PWR_KEY 0x50 +#define GPU_PWR_KEY_UNLOCK 0x2968A819 +#define GPU_PWR_OVERRIDE0 0x54 +#define GPU_PWR_OVERRIDE1 0x58 + +#define GPU_FEATURES 0x60 +#define GPU_FEATURES_RAY_INTERSECTION BIT(2) +#define GPU_FEATURES_RAY_TRAVERSAL BIT(5) + +#define GPU_TIMESTAMP_OFFSET 0x88 +#define GPU_CYCLE_COUNT 0x90 +#define GPU_TIMESTAMP 0x98 + +#define GPU_THREAD_MAX_THREADS 0xA0 +#define GPU_THREAD_MAX_WORKGROUP_SIZE 0xA4 +#define GPU_THREAD_MAX_BARRIER_SIZE 0xA8 +#define GPU_THREAD_FEATURES 0xAC + +#define GPU_TEXTURE_FEATURES(n) (0xB0 + ((n) * 4)) + +#define GPU_SHADER_PRESENT 0x100 +#define GPU_TILER_PRESENT 0x110 +#define GPU_L2_PRESENT 0x120 + +#define SHADER_READY 0x140 +#define TILER_READY 0x150 +#define L2_READY 0x160 + +#define SHADER_PWRON 0x180 +#define TILER_PWRON 0x190 +#define L2_PWRON 0x1A0 + +#define SHADER_PWROFF 0x1C0 +#define TILER_PWROFF 0x1D0 +#define L2_PWROFF 0x1E0 + +#define SHADER_PWRTRANS 0x200 +#define TILER_PWRTRANS 0x210 +#define L2_PWRTRANS 0x220 + +#define SHADER_PWRACTIVE 0x240 +#define TILER_PWRACTIVE 0x250 +#define L2_PWRACTIVE 0x260 + +#define GPU_REVID 0x280 + +#define GPU_ASN_HASH(n) (0x2C0 + ((n) * 4)) + +#define GPU_COHERENCY_FEATURES 0x300 +#define GPU_COHERENCY_PROT_BIT(name) BIT(GPU_COHERENCY_ ## name) + +#define GPU_COHERENCY_PROTOCOL 0x304 +#define GPU_COHERENCY_ACE_LITE 0 +#define GPU_COHERENCY_ACE 1 +#define GPU_COHERENCY_NONE 31 + +#endif /* __PANTHOR_GPU_REGS_H__ */ diff --git a/drivers/gpu/drm/panthor/panthor_heap.c b/drivers/gpu/drm/panthor/panthor_heap.c index 1ee30dc7066f..99311abdf1e9 100644 --- a/drivers/gpu/drm/panthor/panthor_heap.c +++ b/drivers/gpu/drm/panthor/panthor_heap.c @@ -9,9 +9,9 @@ #include "panthor_device.h" #include "panthor_gem.h" +#include "panthor_gpu_regs.h" #include "panthor_heap.h" #include "panthor_mmu.h" -#include "panthor_regs.h" /* * The GPU heap context is an opaque structure used by the GPU to track the diff --git a/drivers/gpu/drm/panthor/panthor_hw.c b/drivers/gpu/drm/panthor/panthor_hw.c index 9309d0938212..9431f16d950f 100644 --- a/drivers/gpu/drm/panthor/panthor_hw.c +++ b/drivers/gpu/drm/panthor/panthor_hw.c @@ -8,9 +8,10 @@ #include "panthor_device.h" #include "panthor_gpu.h" +#include "panthor_gpu_regs.h" #include "panthor_hw.h" #include "panthor_pwr.h" -#include "panthor_regs.h" +#include "panthor_pwr_regs.h" #define GPU_PROD_ID_MAKE(arch_major, prod_major) \ (((arch_major) << 24) | (prod_major)) diff --git a/drivers/gpu/drm/panthor/panthor_hw.h b/drivers/gpu/drm/panthor/panthor_hw.h index 2c28aea82841..f797663893b2 100644 --- a/drivers/gpu/drm/panthor/panthor_hw.h +++ b/drivers/gpu/drm/panthor/panthor_hw.h @@ -5,7 +5,7 @@ #define __PANTHOR_HW_H__ #include "panthor_device.h" -#include "panthor_regs.h" +#include "panthor_gpu_regs.h" /** * struct panthor_hw_ops - HW operations that are specific to a GPU diff --git a/drivers/gpu/drm/panthor/panthor_mmu.c b/drivers/gpu/drm/panthor/panthor_mmu.c index 6a8ac2239b9c..853f5ebfe5c6 100644 --- a/drivers/gpu/drm/panthor/panthor_mmu.c +++ b/drivers/gpu/drm/panthor/panthor_mmu.c @@ -33,9 +33,10 @@ #include "panthor_device.h" #include "panthor_gem.h" #include "panthor_gpu.h" +#include "panthor_gpu_regs.h" #include "panthor_heap.h" #include "panthor_mmu.h" -#include "panthor_regs.h" +#include "panthor_mmu_regs.h" #include "panthor_sched.h" #define MAX_AS_SLOTS 32 diff --git a/drivers/gpu/drm/panthor/panthor_mmu_regs.h b/drivers/gpu/drm/panthor/panthor_mmu_regs.h new file mode 100644 index 000000000000..cc9cf603cec6 --- /dev/null +++ b/drivers/gpu/drm/panthor/panthor_mmu_regs.h @@ -0,0 +1,70 @@ +/* SPDX-License-Identifier: GPL-2.0 or MIT */ +/* Copyright 2026 ARM Limited. All rights reserved. */ + +#ifndef __PANTHOR_MMU_REGS_H__ +#define __PANTHOR_MMU_REGS_H__ + +/* MMU regs */ +#define MMU_INT_RAWSTAT 0x2000 +#define MMU_INT_CLEAR 0x2004 +#define MMU_INT_MASK 0x2008 +#define MMU_INT_STAT 0x200c + +/* AS_COMMAND register commands */ + +#define MMU_BASE 0x2400 +#define MMU_AS_SHIFT 6 +#define MMU_AS(as) (MMU_BASE + ((as) << MMU_AS_SHIFT)) + +#define AS_TRANSTAB(as) (MMU_AS(as) + 0x0) +#define AS_MEMATTR(as) (MMU_AS(as) + 0x8) +#define AS_MEMATTR_AARCH64_INNER_ALLOC_IMPL (2 << 2) +#define AS_MEMATTR_AARCH64_INNER_ALLOC_EXPL(w, r) ((3 << 2) | \ + ((w) ? BIT(0) : 0) | \ + ((r) ? BIT(1) : 0)) +#define AS_MEMATTR_AARCH64_SH_MIDGARD_INNER (0 << 4) +#define AS_MEMATTR_AARCH64_SH_CPU_INNER (1 << 4) +#define AS_MEMATTR_AARCH64_SH_CPU_INNER_SHADER_COH (2 << 4) +#define AS_MEMATTR_AARCH64_SHARED (0 << 6) +#define AS_MEMATTR_AARCH64_INNER_OUTER_NC (1 << 6) +#define AS_MEMATTR_AARCH64_INNER_OUTER_WB (2 << 6) +#define AS_MEMATTR_AARCH64_FAULT (3 << 6) +#define AS_LOCKADDR(as) (MMU_AS(as) + 0x10) +#define AS_COMMAND(as) (MMU_AS(as) + 0x18) +#define AS_COMMAND_NOP 0 +#define AS_COMMAND_UPDATE 1 +#define AS_COMMAND_LOCK 2 +#define AS_COMMAND_UNLOCK 3 +#define AS_COMMAND_FLUSH_PT 4 +#define AS_COMMAND_FLUSH_MEM 5 +#define AS_LOCK_REGION_MIN_SIZE (1ULL << 15) +#define AS_FAULTSTATUS(as) (MMU_AS(as) + 0x1C) +#define AS_FAULTSTATUS_ACCESS_TYPE_MASK (0x3 << 8) +#define AS_FAULTSTATUS_ACCESS_TYPE_ATOMIC (0x0 << 8) +#define AS_FAULTSTATUS_ACCESS_TYPE_EX (0x1 << 8) +#define AS_FAULTSTATUS_ACCESS_TYPE_READ (0x2 << 8) +#define AS_FAULTSTATUS_ACCESS_TYPE_WRITE (0x3 << 8) +#define AS_FAULTADDRESS(as) (MMU_AS(as) + 0x20) +#define AS_STATUS(as) (MMU_AS(as) + 0x28) +#define AS_STATUS_AS_ACTIVE BIT(0) +#define AS_TRANSCFG(as) (MMU_AS(as) + 0x30) +#define AS_TRANSCFG_ADRMODE_UNMAPPED (1 << 0) +#define AS_TRANSCFG_ADRMODE_IDENTITY (2 << 0) +#define AS_TRANSCFG_ADRMODE_AARCH64_4K (6 << 0) +#define AS_TRANSCFG_ADRMODE_AARCH64_64K (8 << 0) +#define AS_TRANSCFG_INA_BITS(x) ((x) << 6) +#define AS_TRANSCFG_OUTA_BITS(x) ((x) << 14) +#define AS_TRANSCFG_SL_CONCAT BIT(22) +#define AS_TRANSCFG_PTW_MEMATTR_NC (1 << 24) +#define AS_TRANSCFG_PTW_MEMATTR_WB (2 << 24) +#define AS_TRANSCFG_PTW_SH_NS (0 << 28) +#define AS_TRANSCFG_PTW_SH_OS (2 << 28) +#define AS_TRANSCFG_PTW_SH_IS (3 << 28) +#define AS_TRANSCFG_PTW_RA BIT(30) +#define AS_TRANSCFG_DISABLE_HIER_AP BIT(33) +#define AS_TRANSCFG_DISABLE_AF_FAULT BIT(34) +#define AS_TRANSCFG_WXN BIT(35) +#define AS_TRANSCFG_XREADABLE BIT(36) +#define AS_FAULTEXTRA(as) (MMU_AS(as) + 0x38) + +#endif /* __PANTHOR_MMU_REGS_H__ */ diff --git a/drivers/gpu/drm/panthor/panthor_pwr.c b/drivers/gpu/drm/panthor/panthor_pwr.c index b77c85ad733a..306592ff2227 100644 --- a/drivers/gpu/drm/panthor/panthor_pwr.c +++ b/drivers/gpu/drm/panthor/panthor_pwr.c @@ -11,9 +11,10 @@ #include #include "panthor_device.h" +#include "panthor_gpu_regs.h" #include "panthor_hw.h" #include "panthor_pwr.h" -#include "panthor_regs.h" +#include "panthor_pwr_regs.h" #define PWR_INTERRUPTS_MASK \ (PWR_IRQ_POWER_CHANGED_SINGLE | \ diff --git a/drivers/gpu/drm/panthor/panthor_pwr_regs.h b/drivers/gpu/drm/panthor/panthor_pwr_regs.h new file mode 100644 index 000000000000..ad3e446971db --- /dev/null +++ b/drivers/gpu/drm/panthor/panthor_pwr_regs.h @@ -0,0 +1,83 @@ +/* SPDX-License-Identifier: GPL-2.0 or MIT */ +/* Copyright 2026 ARM Limited. All rights reserved. */ + +#ifndef __PANTHOR_PWR_REGS_H__ +#define __PANTHOR_PWR_REGS_H__ + +#define PWR_CONTROL_BASE 0x800 +#define PWR_CTRL_REG(x) (PWR_CONTROL_BASE + (x)) + +#define PWR_INT_RAWSTAT PWR_CTRL_REG(0x0) +#define PWR_INT_CLEAR PWR_CTRL_REG(0x4) +#define PWR_INT_MASK PWR_CTRL_REG(0x8) +#define PWR_INT_STAT PWR_CTRL_REG(0xc) +#define PWR_IRQ_POWER_CHANGED_SINGLE BIT(0) +#define PWR_IRQ_POWER_CHANGED_ALL BIT(1) +#define PWR_IRQ_DELEGATION_CHANGED BIT(2) +#define PWR_IRQ_RESET_COMPLETED BIT(3) +#define PWR_IRQ_RETRACT_COMPLETED BIT(4) +#define PWR_IRQ_INSPECT_COMPLETED BIT(5) +#define PWR_IRQ_COMMAND_NOT_ALLOWED BIT(30) +#define PWR_IRQ_COMMAND_INVALID BIT(31) + +#define PWR_STATUS PWR_CTRL_REG(0x20) +#define PWR_STATUS_ALLOW_L2 BIT_U64(0) +#define PWR_STATUS_ALLOW_TILER BIT_U64(1) +#define PWR_STATUS_ALLOW_SHADER BIT_U64(8) +#define PWR_STATUS_ALLOW_BASE BIT_U64(14) +#define PWR_STATUS_ALLOW_STACK BIT_U64(15) +#define PWR_STATUS_DOMAIN_ALLOWED(x) BIT_U64(x) +#define PWR_STATUS_DELEGATED_L2 BIT_U64(16) +#define PWR_STATUS_DELEGATED_TILER BIT_U64(17) +#define PWR_STATUS_DELEGATED_SHADER BIT_U64(24) +#define PWR_STATUS_DELEGATED_BASE BIT_U64(30) +#define PWR_STATUS_DELEGATED_STACK BIT_U64(31) +#define PWR_STATUS_DELEGATED_SHIFT 16 +#define PWR_STATUS_DOMAIN_DELEGATED(x) BIT_U64((x) + PWR_STATUS_DELEGATED_SHIFT) +#define PWR_STATUS_ALLOW_SOFT_RESET BIT_U64(33) +#define PWR_STATUS_ALLOW_FAST_RESET BIT_U64(34) +#define PWR_STATUS_POWER_PENDING BIT_U64(41) +#define PWR_STATUS_RESET_PENDING BIT_U64(42) +#define PWR_STATUS_RETRACT_PENDING BIT_U64(43) +#define PWR_STATUS_INSPECT_PENDING BIT_U64(44) + +#define PWR_COMMAND PWR_CTRL_REG(0x28) +#define PWR_COMMAND_POWER_UP 0x10 +#define PWR_COMMAND_POWER_DOWN 0x11 +#define PWR_COMMAND_DELEGATE 0x20 +#define PWR_COMMAND_RETRACT 0x21 +#define PWR_COMMAND_RESET_SOFT 0x31 +#define PWR_COMMAND_RESET_FAST 0x32 +#define PWR_COMMAND_INSPECT 0xF0 +#define PWR_COMMAND_DOMAIN_L2 0 +#define PWR_COMMAND_DOMAIN_TILER 1 +#define PWR_COMMAND_DOMAIN_SHADER 8 +#define PWR_COMMAND_DOMAIN_BASE 14 +#define PWR_COMMAND_DOMAIN_STACK 15 +#define PWR_COMMAND_SUBDOMAIN_RTU BIT(0) +#define PWR_COMMAND_DEF(cmd, domain, subdomain) \ + (((subdomain) << 16) | ((domain) << 8) | (cmd)) + +#define PWR_CMDARG PWR_CTRL_REG(0x30) + +#define PWR_L2_PRESENT PWR_CTRL_REG(0x100) +#define PWR_L2_READY PWR_CTRL_REG(0x108) +#define PWR_L2_PWRTRANS PWR_CTRL_REG(0x110) +#define PWR_L2_PWRACTIVE PWR_CTRL_REG(0x118) +#define PWR_TILER_PRESENT PWR_CTRL_REG(0x140) +#define PWR_TILER_READY PWR_CTRL_REG(0x148) +#define PWR_TILER_PWRTRANS PWR_CTRL_REG(0x150) +#define PWR_TILER_PWRACTIVE PWR_CTRL_REG(0x158) +#define PWR_SHADER_PRESENT PWR_CTRL_REG(0x200) +#define PWR_SHADER_READY PWR_CTRL_REG(0x208) +#define PWR_SHADER_PWRTRANS PWR_CTRL_REG(0x210) +#define PWR_SHADER_PWRACTIVE PWR_CTRL_REG(0x218) +#define PWR_BASE_PRESENT PWR_CTRL_REG(0x380) +#define PWR_BASE_READY PWR_CTRL_REG(0x388) +#define PWR_BASE_PWRTRANS PWR_CTRL_REG(0x390) +#define PWR_BASE_PWRACTIVE PWR_CTRL_REG(0x398) +#define PWR_STACK_PRESENT PWR_CTRL_REG(0x3c0) +#define PWR_STACK_READY PWR_CTRL_REG(0x3c8) +#define PWR_STACK_PWRTRANS PWR_CTRL_REG(0x3d0) + +#endif /* __PANTHOR_PWR_REGS_H__ */ diff --git a/drivers/gpu/drm/panthor/panthor_regs.h b/drivers/gpu/drm/panthor/panthor_regs.h deleted file mode 100644 index 08bf06c452d6..000000000000 --- a/drivers/gpu/drm/panthor/panthor_regs.h +++ /dev/null @@ -1,291 +0,0 @@ -/* SPDX-License-Identifier: GPL-2.0 or MIT */ -/* Copyright 2018 Marty E. Plummer */ -/* Copyright 2019 Linaro, Ltd, Rob Herring */ -/* Copyright 2023 Collabora ltd. */ -/* - * Register definitions based on mali_kbase_gpu_regmap.h and - * mali_kbase_gpu_regmap_csf.h - * (C) COPYRIGHT 2010-2022 ARM Limited. All rights reserved. - */ -#ifndef __PANTHOR_REGS_H__ -#define __PANTHOR_REGS_H__ - -#define GPU_ID 0x0 -#define GPU_ARCH_MAJOR(x) ((x) >> 28) -#define GPU_ARCH_MINOR(x) (((x) & GENMASK(27, 24)) >> 24) -#define GPU_ARCH_REV(x) (((x) & GENMASK(23, 20)) >> 20) -#define GPU_PROD_MAJOR(x) (((x) & GENMASK(19, 16)) >> 16) -#define GPU_VER_MAJOR(x) (((x) & GENMASK(15, 12)) >> 12) -#define GPU_VER_MINOR(x) (((x) & GENMASK(11, 4)) >> 4) -#define GPU_VER_STATUS(x) ((x) & GENMASK(3, 0)) - -#define GPU_L2_FEATURES 0x4 -#define GPU_L2_FEATURES_LINE_SIZE(x) (1 << ((x) & GENMASK(7, 0))) - -#define GPU_CORE_FEATURES 0x8 - -#define GPU_TILER_FEATURES 0xC -#define GPU_MEM_FEATURES 0x10 -#define GROUPS_L2_COHERENT BIT(0) - -#define GPU_MMU_FEATURES 0x14 -#define GPU_MMU_FEATURES_VA_BITS(x) ((x) & GENMASK(7, 0)) -#define GPU_MMU_FEATURES_PA_BITS(x) (((x) >> 8) & GENMASK(7, 0)) -#define GPU_AS_PRESENT 0x18 -#define GPU_CSF_ID 0x1C - -#define GPU_INT_RAWSTAT 0x20 -#define GPU_INT_CLEAR 0x24 -#define GPU_INT_MASK 0x28 -#define GPU_INT_STAT 0x2c -#define GPU_IRQ_FAULT BIT(0) -#define GPU_IRQ_PROTM_FAULT BIT(1) -#define GPU_IRQ_RESET_COMPLETED BIT(8) -#define GPU_IRQ_POWER_CHANGED BIT(9) -#define GPU_IRQ_POWER_CHANGED_ALL BIT(10) -#define GPU_IRQ_CLEAN_CACHES_COMPLETED BIT(17) -#define GPU_IRQ_DOORBELL_MIRROR BIT(18) -#define GPU_IRQ_MCU_STATUS_CHANGED BIT(19) -#define GPU_CMD 0x30 -#define GPU_CMD_DEF(type, payload) ((type) | ((payload) << 8)) -#define GPU_SOFT_RESET GPU_CMD_DEF(1, 1) -#define GPU_HARD_RESET GPU_CMD_DEF(1, 2) -#define CACHE_CLEAN BIT(0) -#define CACHE_INV BIT(1) -#define GPU_FLUSH_CACHES(l2, lsc, oth) \ - GPU_CMD_DEF(4, ((l2) << 0) | ((lsc) << 4) | ((oth) << 8)) - -#define GPU_STATUS 0x34 -#define GPU_STATUS_ACTIVE BIT(0) -#define GPU_STATUS_PWR_ACTIVE BIT(1) -#define GPU_STATUS_PAGE_FAULT BIT(4) -#define GPU_STATUS_PROTM_ACTIVE BIT(7) -#define GPU_STATUS_DBG_ENABLED BIT(8) - -#define GPU_FAULT_STATUS 0x3C -#define GPU_FAULT_ADDR 0x40 -#define GPU_L2_CONFIG 0x48 -#define GPU_L2_CONFIG_ASN_HASH_ENABLE BIT(24) - -#define GPU_PWR_KEY 0x50 -#define GPU_PWR_KEY_UNLOCK 0x2968A819 -#define GPU_PWR_OVERRIDE0 0x54 -#define GPU_PWR_OVERRIDE1 0x58 - -#define GPU_FEATURES 0x60 -#define GPU_FEATURES_RAY_INTERSECTION BIT(2) -#define GPU_FEATURES_RAY_TRAVERSAL BIT(5) - -#define GPU_TIMESTAMP_OFFSET 0x88 -#define GPU_CYCLE_COUNT 0x90 -#define GPU_TIMESTAMP 0x98 - -#define GPU_THREAD_MAX_THREADS 0xA0 -#define GPU_THREAD_MAX_WORKGROUP_SIZE 0xA4 -#define GPU_THREAD_MAX_BARRIER_SIZE 0xA8 -#define GPU_THREAD_FEATURES 0xAC - -#define GPU_TEXTURE_FEATURES(n) (0xB0 + ((n) * 4)) - -#define GPU_SHADER_PRESENT 0x100 -#define GPU_TILER_PRESENT 0x110 -#define GPU_L2_PRESENT 0x120 - -#define SHADER_READY 0x140 -#define TILER_READY 0x150 -#define L2_READY 0x160 - -#define SHADER_PWRON 0x180 -#define TILER_PWRON 0x190 -#define L2_PWRON 0x1A0 - -#define SHADER_PWROFF 0x1C0 -#define TILER_PWROFF 0x1D0 -#define L2_PWROFF 0x1E0 - -#define SHADER_PWRTRANS 0x200 -#define TILER_PWRTRANS 0x210 -#define L2_PWRTRANS 0x220 - -#define SHADER_PWRACTIVE 0x240 -#define TILER_PWRACTIVE 0x250 -#define L2_PWRACTIVE 0x260 - -#define GPU_REVID 0x280 - -#define GPU_ASN_HASH(n) (0x2C0 + ((n) * 4)) - -#define GPU_COHERENCY_FEATURES 0x300 -#define GPU_COHERENCY_PROT_BIT(name) BIT(GPU_COHERENCY_ ## name) - -#define GPU_COHERENCY_PROTOCOL 0x304 -#define GPU_COHERENCY_ACE_LITE 0 -#define GPU_COHERENCY_ACE 1 -#define GPU_COHERENCY_NONE 31 - -#define MCU_CONTROL 0x700 -#define MCU_CONTROL_ENABLE 1 -#define MCU_CONTROL_AUTO 2 -#define MCU_CONTROL_DISABLE 0 - -#define MCU_STATUS 0x704 -#define MCU_STATUS_DISABLED 0 -#define MCU_STATUS_ENABLED 1 -#define MCU_STATUS_HALT 2 -#define MCU_STATUS_FATAL 3 - -/* Job Control regs */ -#define JOB_INT_RAWSTAT 0x1000 -#define JOB_INT_CLEAR 0x1004 -#define JOB_INT_MASK 0x1008 -#define JOB_INT_STAT 0x100c -#define JOB_INT_GLOBAL_IF BIT(31) -#define JOB_INT_CSG_IF(x) BIT(x) - -/* MMU regs */ -#define MMU_INT_RAWSTAT 0x2000 -#define MMU_INT_CLEAR 0x2004 -#define MMU_INT_MASK 0x2008 -#define MMU_INT_STAT 0x200c - -/* AS_COMMAND register commands */ - -#define MMU_BASE 0x2400 -#define MMU_AS_SHIFT 6 -#define MMU_AS(as) (MMU_BASE + ((as) << MMU_AS_SHIFT)) - -#define AS_TRANSTAB(as) (MMU_AS(as) + 0x0) -#define AS_MEMATTR(as) (MMU_AS(as) + 0x8) -#define AS_MEMATTR_AARCH64_INNER_ALLOC_IMPL (2 << 2) -#define AS_MEMATTR_AARCH64_INNER_ALLOC_EXPL(w, r) ((3 << 2) | \ - ((w) ? BIT(0) : 0) | \ - ((r) ? BIT(1) : 0)) -#define AS_MEMATTR_AARCH64_SH_MIDGARD_INNER (0 << 4) -#define AS_MEMATTR_AARCH64_SH_CPU_INNER (1 << 4) -#define AS_MEMATTR_AARCH64_SH_CPU_INNER_SHADER_COH (2 << 4) -#define AS_MEMATTR_AARCH64_SHARED (0 << 6) -#define AS_MEMATTR_AARCH64_INNER_OUTER_NC (1 << 6) -#define AS_MEMATTR_AARCH64_INNER_OUTER_WB (2 << 6) -#define AS_MEMATTR_AARCH64_FAULT (3 << 6) -#define AS_LOCKADDR(as) (MMU_AS(as) + 0x10) -#define AS_COMMAND(as) (MMU_AS(as) + 0x18) -#define AS_COMMAND_NOP 0 -#define AS_COMMAND_UPDATE 1 -#define AS_COMMAND_LOCK 2 -#define AS_COMMAND_UNLOCK 3 -#define AS_COMMAND_FLUSH_PT 4 -#define AS_COMMAND_FLUSH_MEM 5 -#define AS_LOCK_REGION_MIN_SIZE (1ULL << 15) -#define AS_FAULTSTATUS(as) (MMU_AS(as) + 0x1C) -#define AS_FAULTSTATUS_ACCESS_TYPE_MASK (0x3 << 8) -#define AS_FAULTSTATUS_ACCESS_TYPE_ATOMIC (0x0 << 8) -#define AS_FAULTSTATUS_ACCESS_TYPE_EX (0x1 << 8) -#define AS_FAULTSTATUS_ACCESS_TYPE_READ (0x2 << 8) -#define AS_FAULTSTATUS_ACCESS_TYPE_WRITE (0x3 << 8) -#define AS_FAULTADDRESS(as) (MMU_AS(as) + 0x20) -#define AS_STATUS(as) (MMU_AS(as) + 0x28) -#define AS_STATUS_AS_ACTIVE BIT(0) -#define AS_TRANSCFG(as) (MMU_AS(as) + 0x30) -#define AS_TRANSCFG_ADRMODE_UNMAPPED (1 << 0) -#define AS_TRANSCFG_ADRMODE_IDENTITY (2 << 0) -#define AS_TRANSCFG_ADRMODE_AARCH64_4K (6 << 0) -#define AS_TRANSCFG_ADRMODE_AARCH64_64K (8 << 0) -#define AS_TRANSCFG_INA_BITS(x) ((x) << 6) -#define AS_TRANSCFG_OUTA_BITS(x) ((x) << 14) -#define AS_TRANSCFG_SL_CONCAT BIT(22) -#define AS_TRANSCFG_PTW_MEMATTR_NC (1 << 24) -#define AS_TRANSCFG_PTW_MEMATTR_WB (2 << 24) -#define AS_TRANSCFG_PTW_SH_NS (0 << 28) -#define AS_TRANSCFG_PTW_SH_OS (2 << 28) -#define AS_TRANSCFG_PTW_SH_IS (3 << 28) -#define AS_TRANSCFG_PTW_RA BIT(30) -#define AS_TRANSCFG_DISABLE_HIER_AP BIT(33) -#define AS_TRANSCFG_DISABLE_AF_FAULT BIT(34) -#define AS_TRANSCFG_WXN BIT(35) -#define AS_TRANSCFG_XREADABLE BIT(36) -#define AS_FAULTEXTRA(as) (MMU_AS(as) + 0x38) - -#define CSF_GPU_LATEST_FLUSH_ID 0x10000 - -#define CSF_DOORBELL(i) (0x80000 + ((i) * 0x10000)) -#define CSF_GLB_DOORBELL_ID 0 - -/* PWR Control registers */ - -#define PWR_CONTROL_BASE 0x800 -#define PWR_CTRL_REG(x) (PWR_CONTROL_BASE + (x)) - -#define PWR_INT_RAWSTAT PWR_CTRL_REG(0x0) -#define PWR_INT_CLEAR PWR_CTRL_REG(0x4) -#define PWR_INT_MASK PWR_CTRL_REG(0x8) -#define PWR_INT_STAT PWR_CTRL_REG(0xc) -#define PWR_IRQ_POWER_CHANGED_SINGLE BIT(0) -#define PWR_IRQ_POWER_CHANGED_ALL BIT(1) -#define PWR_IRQ_DELEGATION_CHANGED BIT(2) -#define PWR_IRQ_RESET_COMPLETED BIT(3) -#define PWR_IRQ_RETRACT_COMPLETED BIT(4) -#define PWR_IRQ_INSPECT_COMPLETED BIT(5) -#define PWR_IRQ_COMMAND_NOT_ALLOWED BIT(30) -#define PWR_IRQ_COMMAND_INVALID BIT(31) - -#define PWR_STATUS PWR_CTRL_REG(0x20) -#define PWR_STATUS_ALLOW_L2 BIT_U64(0) -#define PWR_STATUS_ALLOW_TILER BIT_U64(1) -#define PWR_STATUS_ALLOW_SHADER BIT_U64(8) -#define PWR_STATUS_ALLOW_BASE BIT_U64(14) -#define PWR_STATUS_ALLOW_STACK BIT_U64(15) -#define PWR_STATUS_DOMAIN_ALLOWED(x) BIT_U64(x) -#define PWR_STATUS_DELEGATED_L2 BIT_U64(16) -#define PWR_STATUS_DELEGATED_TILER BIT_U64(17) -#define PWR_STATUS_DELEGATED_SHADER BIT_U64(24) -#define PWR_STATUS_DELEGATED_BASE BIT_U64(30) -#define PWR_STATUS_DELEGATED_STACK BIT_U64(31) -#define PWR_STATUS_DELEGATED_SHIFT 16 -#define PWR_STATUS_DOMAIN_DELEGATED(x) BIT_U64((x) + PWR_STATUS_DELEGATED_SHIFT) -#define PWR_STATUS_ALLOW_SOFT_RESET BIT_U64(33) -#define PWR_STATUS_ALLOW_FAST_RESET BIT_U64(34) -#define PWR_STATUS_POWER_PENDING BIT_U64(41) -#define PWR_STATUS_RESET_PENDING BIT_U64(42) -#define PWR_STATUS_RETRACT_PENDING BIT_U64(43) -#define PWR_STATUS_INSPECT_PENDING BIT_U64(44) - -#define PWR_COMMAND PWR_CTRL_REG(0x28) -#define PWR_COMMAND_POWER_UP 0x10 -#define PWR_COMMAND_POWER_DOWN 0x11 -#define PWR_COMMAND_DELEGATE 0x20 -#define PWR_COMMAND_RETRACT 0x21 -#define PWR_COMMAND_RESET_SOFT 0x31 -#define PWR_COMMAND_RESET_FAST 0x32 -#define PWR_COMMAND_INSPECT 0xF0 -#define PWR_COMMAND_DOMAIN_L2 0 -#define PWR_COMMAND_DOMAIN_TILER 1 -#define PWR_COMMAND_DOMAIN_SHADER 8 -#define PWR_COMMAND_DOMAIN_BASE 14 -#define PWR_COMMAND_DOMAIN_STACK 15 -#define PWR_COMMAND_SUBDOMAIN_RTU BIT(0) -#define PWR_COMMAND_DEF(cmd, domain, subdomain) \ - (((subdomain) << 16) | ((domain) << 8) | (cmd)) - -#define PWR_CMDARG PWR_CTRL_REG(0x30) - -#define PWR_L2_PRESENT PWR_CTRL_REG(0x100) -#define PWR_L2_READY PWR_CTRL_REG(0x108) -#define PWR_L2_PWRTRANS PWR_CTRL_REG(0x110) -#define PWR_L2_PWRACTIVE PWR_CTRL_REG(0x118) -#define PWR_TILER_PRESENT PWR_CTRL_REG(0x140) -#define PWR_TILER_READY PWR_CTRL_REG(0x148) -#define PWR_TILER_PWRTRANS PWR_CTRL_REG(0x150) -#define PWR_TILER_PWRACTIVE PWR_CTRL_REG(0x158) -#define PWR_SHADER_PRESENT PWR_CTRL_REG(0x200) -#define PWR_SHADER_READY PWR_CTRL_REG(0x208) -#define PWR_SHADER_PWRTRANS PWR_CTRL_REG(0x210) -#define PWR_SHADER_PWRACTIVE PWR_CTRL_REG(0x218) -#define PWR_BASE_PRESENT PWR_CTRL_REG(0x380) -#define PWR_BASE_READY PWR_CTRL_REG(0x388) -#define PWR_BASE_PWRTRANS PWR_CTRL_REG(0x390) -#define PWR_BASE_PWRACTIVE PWR_CTRL_REG(0x398) -#define PWR_STACK_PRESENT PWR_CTRL_REG(0x3c0) -#define PWR_STACK_READY PWR_CTRL_REG(0x3c8) -#define PWR_STACK_PWRTRANS PWR_CTRL_REG(0x3d0) - -#endif diff --git a/drivers/gpu/drm/panthor/panthor_sched.c b/drivers/gpu/drm/panthor/panthor_sched.c index 55660d9056ed..530e1f0254b1 100644 --- a/drivers/gpu/drm/panthor/panthor_sched.c +++ b/drivers/gpu/drm/panthor/panthor_sched.c @@ -28,11 +28,12 @@ #include "panthor_devfreq.h" #include "panthor_device.h" #include "panthor_fw.h" +#include "panthor_fw_regs.h" #include "panthor_gem.h" #include "panthor_gpu.h" +#include "panthor_gpu_regs.h" #include "panthor_heap.h" #include "panthor_mmu.h" -#include "panthor_regs.h" #include "panthor_sched.h" /** From 10858b2bd89dc992d966b1f4445b3b7b24e5e331 Mon Sep 17 00:00:00 2001 From: Karunika Choo Date: Mon, 27 Apr 2026 16:59:29 +0100 Subject: [PATCH 067/145] drm/panthor: Replace cross-component register accesses with helpers Stop reaching into other components' registers directly and route those operations through the component that owns them. Move the timestamp/coherency helpers into panthor_gpu, add a doorbell helper, and update call sites accordingly. This keeps register knowledge local to each block and avoids spreading cross-component register accesses across the driver. This is a preparatory cleanup for using per-component iomem bases. v3: - Pick up Ack from Boris and R-bs from Liviu and Steve v2: - Fix incorrect spelling of timestamp helpers - Fix unintended trailing backslash Reviewed-by: Steven Price Reviewed-by: Liviu Dudau Acked-by: Boris Brezillon Signed-off-by: Karunika Choo Tested-by: Boris Brezillon Signed-off-by: Liviu Dudau Link: https://patch.msgid.link/20260427155934.416502-4-karunika.choo@arm.com --- drivers/gpu/drm/panthor/panthor_device.c | 27 ---------------- drivers/gpu/drm/panthor/panthor_drv.c | 7 ++--- drivers/gpu/drm/panthor/panthor_fw.c | 13 +++++--- drivers/gpu/drm/panthor/panthor_fw.h | 1 + drivers/gpu/drm/panthor/panthor_gpu.c | 40 ++++++++++++++++++++++++ drivers/gpu/drm/panthor/panthor_gpu.h | 6 ++++ drivers/gpu/drm/panthor/panthor_pwr.c | 2 +- drivers/gpu/drm/panthor/panthor_sched.c | 2 +- 8 files changed, 61 insertions(+), 37 deletions(-) diff --git a/drivers/gpu/drm/panthor/panthor_device.c b/drivers/gpu/drm/panthor/panthor_device.c index f876b13492ae..bd417d6ae8c0 100644 --- a/drivers/gpu/drm/panthor/panthor_device.c +++ b/drivers/gpu/drm/panthor/panthor_device.c @@ -22,38 +22,11 @@ #include "panthor_fw_regs.h" #include "panthor_gem.h" #include "panthor_gpu.h" -#include "panthor_gpu_regs.h" #include "panthor_hw.h" #include "panthor_mmu.h" #include "panthor_pwr.h" #include "panthor_sched.h" -static int panthor_gpu_coherency_init(struct panthor_device *ptdev) -{ - BUILD_BUG_ON(GPU_COHERENCY_NONE != DRM_PANTHOR_GPU_COHERENCY_NONE); - BUILD_BUG_ON(GPU_COHERENCY_ACE_LITE != DRM_PANTHOR_GPU_COHERENCY_ACE_LITE); - BUILD_BUG_ON(GPU_COHERENCY_ACE != DRM_PANTHOR_GPU_COHERENCY_ACE); - - /* Start with no coherency, and update it if the device is flagged coherent. */ - ptdev->gpu_info.selected_coherency = GPU_COHERENCY_NONE; - ptdev->coherent = device_get_dma_attr(ptdev->base.dev) == DEV_DMA_COHERENT; - - if (!ptdev->coherent) - return 0; - - /* Check if the ACE-Lite coherency protocol is actually supported by the GPU. - * ACE protocol has never been supported for command stream frontend GPUs. - */ - if ((gpu_read(ptdev->iomem, GPU_COHERENCY_FEATURES) & - GPU_COHERENCY_PROT_BIT(ACE_LITE))) { - ptdev->gpu_info.selected_coherency = GPU_COHERENCY_ACE_LITE; - return 0; - } - - drm_err(&ptdev->base, "Coherency not supported by the device"); - return -ENOTSUPP; -} - static int panthor_clk_init(struct panthor_device *ptdev) { ptdev->clks.core = devm_clk_get(ptdev->base.dev, NULL); diff --git a/drivers/gpu/drm/panthor/panthor_drv.c b/drivers/gpu/drm/panthor/panthor_drv.c index e63210b01e6e..66996c9147c2 100644 --- a/drivers/gpu/drm/panthor/panthor_drv.c +++ b/drivers/gpu/drm/panthor/panthor_drv.c @@ -34,7 +34,6 @@ #include "panthor_fw.h" #include "panthor_gem.h" #include "panthor_gpu.h" -#include "panthor_gpu_regs.h" #include "panthor_heap.h" #include "panthor_mmu.h" #include "panthor_sched.h" @@ -839,7 +838,7 @@ static int panthor_query_timestamp_info(struct panthor_device *ptdev, } if (flags & DRM_PANTHOR_TIMESTAMP_GPU_OFFSET) - arg->timestamp_offset = gpu_read64(ptdev->iomem, GPU_TIMESTAMP_OFFSET); + arg->timestamp_offset = panthor_gpu_get_timestamp_offset(ptdev); else arg->timestamp_offset = 0; @@ -854,7 +853,7 @@ static int panthor_query_timestamp_info(struct panthor_device *ptdev, query_start_time = 0; if (flags & DRM_PANTHOR_TIMESTAMP_GPU) - arg->current_timestamp = gpu_read64_counter(ptdev->iomem, GPU_TIMESTAMP); + arg->current_timestamp = panthor_gpu_get_timestamp(ptdev); else arg->current_timestamp = 0; @@ -870,7 +869,7 @@ static int panthor_query_timestamp_info(struct panthor_device *ptdev, } if (flags & DRM_PANTHOR_TIMESTAMP_GPU_CYCLE_COUNT) - arg->cycle_count = gpu_read64_counter(ptdev->iomem, GPU_CYCLE_COUNT); + arg->cycle_count = panthor_gpu_get_cycle_count(ptdev); else arg->cycle_count = 0; diff --git a/drivers/gpu/drm/panthor/panthor_fw.c b/drivers/gpu/drm/panthor/panthor_fw.c index 4704275b9c8f..4a0c23e987b6 100644 --- a/drivers/gpu/drm/panthor/panthor_fw.c +++ b/drivers/gpu/drm/panthor/panthor_fw.c @@ -1054,7 +1054,7 @@ static void panthor_fw_init_global_iface(struct panthor_device *ptdev) GLB_CFG_POWEROFF_TIMER | GLB_CFG_PROGRESS_TIMER); - gpu_write(ptdev->iomem, CSF_DOORBELL(CSF_GLB_DOORBELL_ID), 1); + panthor_fw_ring_doorbell(ptdev, CSF_GLB_DOORBELL_ID); /* Kick the watchdog. */ mod_delayed_work(ptdev->reset.wq, &ptdev->fw->watchdog.ping_work, @@ -1156,7 +1156,7 @@ static void panthor_fw_halt_mcu(struct panthor_device *ptdev) else panthor_fw_update_reqs(glb_iface, req, GLB_HALT, GLB_HALT); - gpu_write(ptdev->iomem, CSF_DOORBELL(CSF_GLB_DOORBELL_ID), 1); + panthor_fw_ring_doorbell(ptdev, CSF_GLB_DOORBELL_ID); } static bool panthor_fw_wait_mcu_halted(struct panthor_device *ptdev) @@ -1400,6 +1400,11 @@ int panthor_fw_csg_wait_acks(struct panthor_device *ptdev, u32 csg_slot, return ret; } +void panthor_fw_ring_doorbell(struct panthor_device *ptdev, u32 doorbell_id) +{ + gpu_write(ptdev->iomem, CSF_DOORBELL(doorbell_id), 1); +} + /** * panthor_fw_ring_csg_doorbells() - Ring command stream group doorbells. * @ptdev: Device. @@ -1414,7 +1419,7 @@ void panthor_fw_ring_csg_doorbells(struct panthor_device *ptdev, u32 csg_mask) struct panthor_fw_global_iface *glb_iface = panthor_fw_get_glb_iface(ptdev); panthor_fw_toggle_reqs(glb_iface, doorbell_req, doorbell_ack, csg_mask); - gpu_write(ptdev->iomem, CSF_DOORBELL(CSF_GLB_DOORBELL_ID), 1); + panthor_fw_ring_doorbell(ptdev, CSF_GLB_DOORBELL_ID); } static void panthor_fw_ping_work(struct work_struct *work) @@ -1429,7 +1434,7 @@ static void panthor_fw_ping_work(struct work_struct *work) return; panthor_fw_toggle_reqs(glb_iface, req, ack, GLB_PING); - gpu_write(ptdev->iomem, CSF_DOORBELL(CSF_GLB_DOORBELL_ID), 1); + panthor_fw_ring_doorbell(ptdev, CSF_GLB_DOORBELL_ID); ret = panthor_fw_glb_wait_acks(ptdev, GLB_PING, &acked, 100); if (ret) { diff --git a/drivers/gpu/drm/panthor/panthor_fw.h b/drivers/gpu/drm/panthor/panthor_fw.h index fbdc21469ba3..a99a9b6f4825 100644 --- a/drivers/gpu/drm/panthor/panthor_fw.h +++ b/drivers/gpu/drm/panthor/panthor_fw.h @@ -500,6 +500,7 @@ int panthor_fw_csg_wait_acks(struct panthor_device *ptdev, u32 csg_id, u32 req_m int panthor_fw_glb_wait_acks(struct panthor_device *ptdev, u32 req_mask, u32 *acked, u32 timeout_ms); +void panthor_fw_ring_doorbell(struct panthor_device *ptdev, u32 doorbell_id); void panthor_fw_ring_csg_doorbells(struct panthor_device *ptdev, u32 csg_slot); struct panthor_kernel_bo * diff --git a/drivers/gpu/drm/panthor/panthor_gpu.c b/drivers/gpu/drm/panthor/panthor_gpu.c index fecc30747acf..747ac332be64 100644 --- a/drivers/gpu/drm/panthor/panthor_gpu.c +++ b/drivers/gpu/drm/panthor/panthor_gpu.c @@ -427,3 +427,43 @@ void panthor_gpu_resume(struct panthor_device *ptdev) panthor_hw_l2_power_on(ptdev); } +u64 panthor_gpu_get_timestamp(struct panthor_device *ptdev) +{ + return gpu_read64_counter(ptdev->iomem, GPU_TIMESTAMP); +} + +u64 panthor_gpu_get_timestamp_offset(struct panthor_device *ptdev) +{ + return gpu_read64(ptdev->iomem, GPU_TIMESTAMP_OFFSET); +} + +u64 panthor_gpu_get_cycle_count(struct panthor_device *ptdev) +{ + return gpu_read64_counter(ptdev->iomem, GPU_CYCLE_COUNT); +} + +int panthor_gpu_coherency_init(struct panthor_device *ptdev) +{ + BUILD_BUG_ON(GPU_COHERENCY_NONE != DRM_PANTHOR_GPU_COHERENCY_NONE); + BUILD_BUG_ON(GPU_COHERENCY_ACE_LITE != DRM_PANTHOR_GPU_COHERENCY_ACE_LITE); + BUILD_BUG_ON(GPU_COHERENCY_ACE != DRM_PANTHOR_GPU_COHERENCY_ACE); + + /* Start with no coherency, and update it if the device is flagged coherent. */ + ptdev->gpu_info.selected_coherency = GPU_COHERENCY_NONE; + ptdev->coherent = device_get_dma_attr(ptdev->base.dev) == DEV_DMA_COHERENT; + + if (!ptdev->coherent) + return 0; + + /* Check if the ACE-Lite coherency protocol is actually supported by the GPU. + * ACE protocol has never been supported for command stream frontend GPUs. + */ + if ((gpu_read(ptdev->iomem, GPU_COHERENCY_FEATURES) & + GPU_COHERENCY_PROT_BIT(ACE_LITE))) { + ptdev->gpu_info.selected_coherency = GPU_COHERENCY_ACE_LITE; + return 0; + } + + drm_err(&ptdev->base, "Coherency not supported by the device"); + return -ENOTSUPP; +} diff --git a/drivers/gpu/drm/panthor/panthor_gpu.h b/drivers/gpu/drm/panthor/panthor_gpu.h index 12c263a39928..f615feb05609 100644 --- a/drivers/gpu/drm/panthor/panthor_gpu.h +++ b/drivers/gpu/drm/panthor/panthor_gpu.h @@ -54,4 +54,10 @@ int panthor_gpu_soft_reset(struct panthor_device *ptdev); void panthor_gpu_power_changed_off(struct panthor_device *ptdev); int panthor_gpu_power_changed_on(struct panthor_device *ptdev); +u64 panthor_gpu_get_timestamp(struct panthor_device *ptdev); +u64 panthor_gpu_get_timestamp_offset(struct panthor_device *ptdev); +u64 panthor_gpu_get_cycle_count(struct panthor_device *ptdev); + +int panthor_gpu_coherency_init(struct panthor_device *ptdev); + #endif diff --git a/drivers/gpu/drm/panthor/panthor_pwr.c b/drivers/gpu/drm/panthor/panthor_pwr.c index 306592ff2227..aafb0c5c7d23 100644 --- a/drivers/gpu/drm/panthor/panthor_pwr.c +++ b/drivers/gpu/drm/panthor/panthor_pwr.c @@ -199,7 +199,7 @@ static int panthor_pwr_domain_wait_transition(struct panthor_device *ptdev, u32 static void panthor_pwr_debug_info_show(struct panthor_device *ptdev) { - drm_info(&ptdev->base, "GPU_FEATURES: 0x%016llx", gpu_read64(ptdev->iomem, GPU_FEATURES)); + drm_info(&ptdev->base, "GPU_FEATURES: 0x%016llx", ptdev->gpu_info.gpu_features); drm_info(&ptdev->base, "PWR_STATUS: 0x%016llx", gpu_read64(ptdev->iomem, PWR_STATUS)); drm_info(&ptdev->base, "L2_PRESENT: 0x%016llx", gpu_read64(ptdev->iomem, PWR_L2_PRESENT)); drm_info(&ptdev->base, "L2_PWRTRANS: 0x%016llx", gpu_read64(ptdev->iomem, PWR_L2_PWRTRANS)); diff --git a/drivers/gpu/drm/panthor/panthor_sched.c b/drivers/gpu/drm/panthor/panthor_sched.c index 530e1f0254b1..5b34032deff8 100644 --- a/drivers/gpu/drm/panthor/panthor_sched.c +++ b/drivers/gpu/drm/panthor/panthor_sched.c @@ -3373,7 +3373,7 @@ queue_run_job(struct drm_sched_job *sched_job) if (resume_tick) sched_resume_tick(ptdev); - gpu_write(ptdev->iomem, CSF_DOORBELL(queue->doorbell_id), 1); + panthor_fw_ring_doorbell(ptdev, queue->doorbell_id); if (!sched->pm.has_ref && !(group->blocked_queues & BIT(job->queue_idx))) { pm_runtime_get(ptdev->base.dev); From 77e5cc60fa172047ad3460f74db0699b3a7746f9 Mon Sep 17 00:00:00 2001 From: Karunika Choo Date: Mon, 27 Apr 2026 16:59:30 +0100 Subject: [PATCH 068/145] drm/panthor: Store IRQ register base iomem pointer in panthor_irq Update common IRQ handling code to work from an IRQ-local iomem base instead of referencing block-specific interrupt register offsets. Store the interrupt base address iomem pointer in struct panthor_irq and switch the shared IRQ helpers to use generic INT_* offsets from that local base. This removes the need for each caller to expose absolute IRQ register addresses while keeping the common IRQ flow unchanged. No functional change intended. v3: - Clean up definition of pwr->irq.iomem. v2: - Change IRQ request function to accept an iomem pointer instead of computing it from an offset argument. Signed-off-by: Karunika Choo Reviewed-by: Boris Brezillon Tested-by: Boris Brezillon Reviewed-by: Steven Price Reviewed-by: Liviu Dudau Signed-off-by: Liviu Dudau Link: https://patch.msgid.link/20260427155934.416502-5-karunika.choo@arm.com --- drivers/gpu/drm/panthor/panthor_device.h | 32 ++++++++++++++-------- drivers/gpu/drm/panthor/panthor_fw.c | 5 ++-- drivers/gpu/drm/panthor/panthor_fw_regs.h | 2 ++ drivers/gpu/drm/panthor/panthor_gpu.c | 6 ++-- drivers/gpu/drm/panthor/panthor_gpu_regs.h | 3 ++ drivers/gpu/drm/panthor/panthor_mmu.c | 5 ++-- drivers/gpu/drm/panthor/panthor_mmu_regs.h | 3 ++ drivers/gpu/drm/panthor/panthor_pwr.c | 6 ++-- 8 files changed, 42 insertions(+), 20 deletions(-) diff --git a/drivers/gpu/drm/panthor/panthor_device.h b/drivers/gpu/drm/panthor/panthor_device.h index 285bf7e4439e..4e4607bca7cc 100644 --- a/drivers/gpu/drm/panthor/panthor_device.h +++ b/drivers/gpu/drm/panthor/panthor_device.h @@ -82,6 +82,9 @@ struct panthor_irq { /** @ptdev: Panthor device */ struct panthor_device *ptdev; + /** @iomem: CPU mapping of IRQ base address */ + void __iomem *iomem; + /** @irq: IRQ number. */ int irq; @@ -488,6 +491,11 @@ panthor_exception_is_fault(u32 exception_code) const char *panthor_exception_name(struct panthor_device *ptdev, u32 exception_code); +#define INT_RAWSTAT 0x0 +#define INT_CLEAR 0x4 +#define INT_MASK 0x8 +#define INT_STAT 0xc + /** * PANTHOR_IRQ_HANDLER() - Define interrupt handlers and the interrupt * registration function. @@ -498,14 +506,13 @@ const char *panthor_exception_name(struct panthor_device *ptdev, * * void (*handler)(struct panthor_device *, u32 status); */ -#define PANTHOR_IRQ_HANDLER(__name, __reg_prefix, __handler) \ +#define PANTHOR_IRQ_HANDLER(__name, __handler) \ static irqreturn_t panthor_ ## __name ## _irq_raw_handler(int irq, void *data) \ { \ struct panthor_irq *pirq = data; \ - struct panthor_device *ptdev = pirq->ptdev; \ enum panthor_irq_state old_state; \ \ - if (!gpu_read(ptdev->iomem, __reg_prefix ## _INT_STAT)) \ + if (!gpu_read(pirq->iomem, INT_STAT)) \ return IRQ_NONE; \ \ guard(spinlock_irqsave)(&pirq->mask_lock); \ @@ -515,7 +522,7 @@ static irqreturn_t panthor_ ## __name ## _irq_raw_handler(int irq, void *data) if (old_state != PANTHOR_IRQ_STATE_ACTIVE) \ return IRQ_NONE; \ \ - gpu_write(ptdev->iomem, __reg_prefix ## _INT_MASK, 0); \ + gpu_write(pirq->iomem, INT_MASK, 0); \ return IRQ_WAKE_THREAD; \ } \ \ @@ -534,7 +541,7 @@ static irqreturn_t panthor_ ## __name ## _irq_threaded_handler(int irq, void *da * right before the HW event kicks in. TLDR; it's all expected races we're \ * covered for. \ */ \ - u32 status = gpu_read(ptdev->iomem, __reg_prefix ## _INT_RAWSTAT) & pirq->mask; \ + u32 status = gpu_read(pirq->iomem, INT_RAWSTAT) & pirq->mask; \ \ if (!status) \ break; \ @@ -550,7 +557,7 @@ static irqreturn_t panthor_ ## __name ## _irq_threaded_handler(int irq, void *da PANTHOR_IRQ_STATE_PROCESSING, \ PANTHOR_IRQ_STATE_ACTIVE); \ if (old_state == PANTHOR_IRQ_STATE_PROCESSING) \ - gpu_write(ptdev->iomem, __reg_prefix ## _INT_MASK, pirq->mask); \ + gpu_write(pirq->iomem, INT_MASK, pirq->mask); \ } \ \ return ret; \ @@ -560,7 +567,7 @@ static inline void panthor_ ## __name ## _irq_suspend(struct panthor_irq *pirq) { \ scoped_guard(spinlock_irqsave, &pirq->mask_lock) { \ atomic_set(&pirq->state, PANTHOR_IRQ_STATE_SUSPENDING); \ - gpu_write(pirq->ptdev->iomem, __reg_prefix ## _INT_MASK, 0); \ + gpu_write(pirq->iomem, INT_MASK, 0); \ } \ synchronize_irq(pirq->irq); \ atomic_set(&pirq->state, PANTHOR_IRQ_STATE_SUSPENDED); \ @@ -571,17 +578,18 @@ static inline void panthor_ ## __name ## _irq_resume(struct panthor_irq *pirq) guard(spinlock_irqsave)(&pirq->mask_lock); \ \ atomic_set(&pirq->state, PANTHOR_IRQ_STATE_ACTIVE); \ - gpu_write(pirq->ptdev->iomem, __reg_prefix ## _INT_CLEAR, pirq->mask); \ - gpu_write(pirq->ptdev->iomem, __reg_prefix ## _INT_MASK, pirq->mask); \ + gpu_write(pirq->iomem, INT_CLEAR, pirq->mask); \ + gpu_write(pirq->iomem, INT_MASK, pirq->mask); \ } \ \ static int panthor_request_ ## __name ## _irq(struct panthor_device *ptdev, \ struct panthor_irq *pirq, \ - int irq, u32 mask) \ + int irq, u32 mask, void __iomem *iomem) \ { \ pirq->ptdev = ptdev; \ pirq->irq = irq; \ pirq->mask = mask; \ + pirq->iomem = iomem; \ spin_lock_init(&pirq->mask_lock); \ panthor_ ## __name ## _irq_resume(pirq); \ \ @@ -603,7 +611,7 @@ static inline void panthor_ ## __name ## _irq_enable_events(struct panthor_irq * * If the IRQ is suspended/suspending, the mask is restored at resume time. \ */ \ if (atomic_read(&pirq->state) == PANTHOR_IRQ_STATE_ACTIVE) \ - gpu_write(pirq->ptdev->iomem, __reg_prefix ## _INT_MASK, pirq->mask); \ + gpu_write(pirq->iomem, INT_MASK, pirq->mask); \ } \ \ static inline void panthor_ ## __name ## _irq_disable_events(struct panthor_irq *pirq, u32 mask)\ @@ -617,7 +625,7 @@ static inline void panthor_ ## __name ## _irq_disable_events(struct panthor_irq * If the IRQ is suspended/suspending, the mask is restored at resume time. \ */ \ if (atomic_read(&pirq->state) == PANTHOR_IRQ_STATE_ACTIVE) \ - gpu_write(pirq->ptdev->iomem, __reg_prefix ## _INT_MASK, pirq->mask); \ + gpu_write(pirq->iomem, INT_MASK, pirq->mask); \ } extern struct workqueue_struct *panthor_cleanup_wq; diff --git a/drivers/gpu/drm/panthor/panthor_fw.c b/drivers/gpu/drm/panthor/panthor_fw.c index 4a0c23e987b6..73ef07a37e22 100644 --- a/drivers/gpu/drm/panthor/panthor_fw.c +++ b/drivers/gpu/drm/panthor/panthor_fw.c @@ -1088,7 +1088,7 @@ static void panthor_job_irq_handler(struct panthor_device *ptdev, u32 status) trace_gpu_job_irq(ptdev->base.dev, status, duration); } } -PANTHOR_IRQ_HANDLER(job, JOB, panthor_job_irq_handler); +PANTHOR_IRQ_HANDLER(job, panthor_job_irq_handler); static int panthor_fw_start(struct panthor_device *ptdev) { @@ -1470,7 +1470,8 @@ int panthor_fw_init(struct panthor_device *ptdev) if (irq <= 0) return -ENODEV; - ret = panthor_request_job_irq(ptdev, &fw->irq, irq, 0); + ret = panthor_request_job_irq(ptdev, &fw->irq, irq, 0, + ptdev->iomem + JOB_INT_BASE); if (ret) { drm_err(&ptdev->base, "failed to request job irq"); return ret; diff --git a/drivers/gpu/drm/panthor/panthor_fw_regs.h b/drivers/gpu/drm/panthor/panthor_fw_regs.h index d523d41e18dd..eeb41aff249b 100644 --- a/drivers/gpu/drm/panthor/panthor_fw_regs.h +++ b/drivers/gpu/drm/panthor/panthor_fw_regs.h @@ -15,6 +15,8 @@ #define MCU_STATUS_HALT 2 #define MCU_STATUS_FATAL 3 +#define JOB_INT_BASE 0x1000 + #define JOB_INT_RAWSTAT 0x1000 #define JOB_INT_CLEAR 0x1004 #define JOB_INT_MASK 0x1008 diff --git a/drivers/gpu/drm/panthor/panthor_gpu.c b/drivers/gpu/drm/panthor/panthor_gpu.c index 747ac332be64..f00f3d9be240 100644 --- a/drivers/gpu/drm/panthor/panthor_gpu.c +++ b/drivers/gpu/drm/panthor/panthor_gpu.c @@ -110,7 +110,7 @@ static void panthor_gpu_irq_handler(struct panthor_device *ptdev, u32 status) } spin_unlock(&ptdev->gpu->reqs_lock); } -PANTHOR_IRQ_HANDLER(gpu, GPU, panthor_gpu_irq_handler); +PANTHOR_IRQ_HANDLER(gpu, panthor_gpu_irq_handler); /** * panthor_gpu_unplug() - Called when the GPU is unplugged. @@ -162,7 +162,9 @@ int panthor_gpu_init(struct panthor_device *ptdev) if (irq < 0) return irq; - ret = panthor_request_gpu_irq(ptdev, &ptdev->gpu->irq, irq, GPU_INTERRUPTS_MASK); + ret = panthor_request_gpu_irq(ptdev, &ptdev->gpu->irq, irq, + GPU_INTERRUPTS_MASK, + ptdev->iomem + GPU_INT_BASE); if (ret) return ret; diff --git a/drivers/gpu/drm/panthor/panthor_gpu_regs.h b/drivers/gpu/drm/panthor/panthor_gpu_regs.h index 75474b7d7341..3f60c45985a7 100644 --- a/drivers/gpu/drm/panthor/panthor_gpu_regs.h +++ b/drivers/gpu/drm/panthor/panthor_gpu_regs.h @@ -4,6 +4,8 @@ #ifndef __PANTHOR_GPU_REGS_H__ #define __PANTHOR_GPU_REGS_H__ +#define GPU_CONTROL_BASE 0x0 + #define GPU_ID 0x0 #define GPU_ARCH_MAJOR(x) ((x) >> 28) #define GPU_ARCH_MINOR(x) (((x) & GENMASK(27, 24)) >> 24) @@ -28,6 +30,7 @@ #define GPU_AS_PRESENT 0x18 #define GPU_CSF_ID 0x1C +#define GPU_INT_BASE 0x20 #define GPU_INT_RAWSTAT 0x20 #define GPU_INT_CLEAR 0x24 #define GPU_INT_MASK 0x28 diff --git a/drivers/gpu/drm/panthor/panthor_mmu.c b/drivers/gpu/drm/panthor/panthor_mmu.c index 853f5ebfe5c6..64d53e7cb763 100644 --- a/drivers/gpu/drm/panthor/panthor_mmu.c +++ b/drivers/gpu/drm/panthor/panthor_mmu.c @@ -584,7 +584,7 @@ static u32 panthor_mmu_as_fault_mask(struct panthor_device *ptdev, u32 as) /* Forward declaration to call helpers within as_enable/disable */ static void panthor_mmu_irq_handler(struct panthor_device *ptdev, u32 status); -PANTHOR_IRQ_HANDLER(mmu, MMU, panthor_mmu_irq_handler); +PANTHOR_IRQ_HANDLER(mmu, panthor_mmu_irq_handler); static int panthor_mmu_as_enable(struct panthor_device *ptdev, u32 as_nr, u64 transtab, u64 transcfg, u64 memattr) @@ -3247,7 +3247,8 @@ int panthor_mmu_init(struct panthor_device *ptdev) return -ENODEV; ret = panthor_request_mmu_irq(ptdev, &mmu->irq, irq, - panthor_mmu_fault_mask(ptdev, ~0)); + panthor_mmu_fault_mask(ptdev, ~0), + ptdev->iomem + MMU_INT_BASE); if (ret) return ret; diff --git a/drivers/gpu/drm/panthor/panthor_mmu_regs.h b/drivers/gpu/drm/panthor/panthor_mmu_regs.h index cc9cf603cec6..de460042651d 100644 --- a/drivers/gpu/drm/panthor/panthor_mmu_regs.h +++ b/drivers/gpu/drm/panthor/panthor_mmu_regs.h @@ -5,6 +5,9 @@ #define __PANTHOR_MMU_REGS_H__ /* MMU regs */ + +#define MMU_INT_BASE 0x2000 + #define MMU_INT_RAWSTAT 0x2000 #define MMU_INT_CLEAR 0x2004 #define MMU_INT_MASK 0x2008 diff --git a/drivers/gpu/drm/panthor/panthor_pwr.c b/drivers/gpu/drm/panthor/panthor_pwr.c index aafb0c5c7d23..705d998447b5 100644 --- a/drivers/gpu/drm/panthor/panthor_pwr.c +++ b/drivers/gpu/drm/panthor/panthor_pwr.c @@ -70,7 +70,7 @@ static void panthor_pwr_irq_handler(struct panthor_device *ptdev, u32 status) } spin_unlock(&ptdev->pwr->reqs_lock); } -PANTHOR_IRQ_HANDLER(pwr, PWR, panthor_pwr_irq_handler); +PANTHOR_IRQ_HANDLER(pwr, panthor_pwr_irq_handler); static void panthor_pwr_write_command(struct panthor_device *ptdev, u32 command, u64 args) { @@ -464,7 +464,9 @@ int panthor_pwr_init(struct panthor_device *ptdev) if (irq < 0) return irq; - err = panthor_request_pwr_irq(ptdev, &pwr->irq, irq, PWR_INTERRUPTS_MASK); + err = panthor_request_pwr_irq( + ptdev, &pwr->irq, irq, PWR_INTERRUPTS_MASK, + ptdev->iomem + PWR_CONTROL_BASE); if (err) return err; From 247ae9a8ab4d7ca347c1fa75163351f48231d1f1 Mon Sep 17 00:00:00 2001 From: Karunika Choo Date: Mon, 27 Apr 2026 16:59:31 +0100 Subject: [PATCH 069/145] drm/panthor: Use a local iomem base for GPU registers Add a GPU_CONTROL-local iomem pointer to struct panthor_gpu and use it for GPU register accesses. This limits GPU register accesses to the GPU block instead of using the device-wide MMIO mapping directly. Interrupt register accesses continue to use the IRQ-local base provided by the common IRQ helpers. Update panthor_gpu_info_init() to also use a local iomem offset for GPU features and capability. This is a refactoring only and does not change behaviour. v3: - Pick up R-bs from Liviu and Steve v2: - Update panthor_gpu_info_init() to use block-local iomem pointer. Reviewed-by: Steven Price Reviewed-by: Liviu Dudau Signed-off-by: Karunika Choo Signed-off-by: Liviu Dudau Link: https://patch.msgid.link/20260427155934.416502-6-karunika.choo@arm.com --- drivers/gpu/drm/panthor/panthor_gpu.c | 61 +++++++++++++--------- drivers/gpu/drm/panthor/panthor_gpu_regs.h | 4 -- drivers/gpu/drm/panthor/panthor_hw.c | 38 +++++++------- 3 files changed, 56 insertions(+), 47 deletions(-) diff --git a/drivers/gpu/drm/panthor/panthor_gpu.c b/drivers/gpu/drm/panthor/panthor_gpu.c index f00f3d9be240..e52c5675981f 100644 --- a/drivers/gpu/drm/panthor/panthor_gpu.c +++ b/drivers/gpu/drm/panthor/panthor_gpu.c @@ -29,6 +29,9 @@ * struct panthor_gpu - GPU block management data. */ struct panthor_gpu { + /** @iomem: CPU mapping of GPU_CONTROL iomem region */ + void __iomem *iomem; + /** @irq: GPU irq. */ struct panthor_irq irq; @@ -56,12 +59,13 @@ struct panthor_gpu { static void panthor_gpu_coherency_set(struct panthor_device *ptdev) { - gpu_write(ptdev->iomem, GPU_COHERENCY_PROTOCOL, + gpu_write(ptdev->gpu->iomem, GPU_COHERENCY_PROTOCOL, ptdev->gpu_info.selected_coherency); } static void panthor_gpu_l2_config_set(struct panthor_device *ptdev) { + struct panthor_gpu *gpu = ptdev->gpu; const struct panthor_soc_data *data = ptdev->soc_data; u32 l2_config; u32 i; @@ -75,26 +79,28 @@ static void panthor_gpu_l2_config_set(struct panthor_device *ptdev) } for (i = 0; i < ARRAY_SIZE(data->asn_hash); i++) - gpu_write(ptdev->iomem, GPU_ASN_HASH(i), data->asn_hash[i]); + gpu_write(gpu->iomem, GPU_ASN_HASH(i), data->asn_hash[i]); - l2_config = gpu_read(ptdev->iomem, GPU_L2_CONFIG); + l2_config = gpu_read(gpu->iomem, GPU_L2_CONFIG); l2_config |= GPU_L2_CONFIG_ASN_HASH_ENABLE; - gpu_write(ptdev->iomem, GPU_L2_CONFIG, l2_config); + gpu_write(gpu->iomem, GPU_L2_CONFIG, l2_config); } static void panthor_gpu_irq_handler(struct panthor_device *ptdev, u32 status) { - gpu_write(ptdev->iomem, GPU_INT_CLEAR, status); + struct panthor_gpu *gpu = ptdev->gpu; + + gpu_write(gpu->irq.iomem, INT_CLEAR, status); if (tracepoint_enabled(gpu_power_status) && (status & GPU_POWER_INTERRUPTS_MASK)) trace_gpu_power_status(ptdev->base.dev, - gpu_read64(ptdev->iomem, SHADER_READY), - gpu_read64(ptdev->iomem, TILER_READY), - gpu_read64(ptdev->iomem, L2_READY)); + gpu_read64(gpu->iomem, SHADER_READY), + gpu_read64(gpu->iomem, TILER_READY), + gpu_read64(gpu->iomem, L2_READY)); if (status & GPU_IRQ_FAULT) { - u32 fault_status = gpu_read(ptdev->iomem, GPU_FAULT_STATUS); - u64 address = gpu_read64(ptdev->iomem, GPU_FAULT_ADDR); + u32 fault_status = gpu_read(gpu->iomem, GPU_FAULT_STATUS); + u64 address = gpu_read64(gpu->iomem, GPU_FAULT_ADDR); drm_warn(&ptdev->base, "GPU Fault 0x%08x (%s) at 0x%016llx\n", fault_status, panthor_exception_name(ptdev, fault_status & 0xFF), @@ -147,6 +153,7 @@ int panthor_gpu_init(struct panthor_device *ptdev) if (!gpu) return -ENOMEM; + gpu->iomem = ptdev->iomem + GPU_CONTROL_BASE; spin_lock_init(&gpu->reqs_lock); init_waitqueue_head(&gpu->reqs_acked); mutex_init(&gpu->cache_flush_lock); @@ -203,10 +210,11 @@ int panthor_gpu_block_power_off(struct panthor_device *ptdev, u32 pwroff_reg, u32 pwrtrans_reg, u64 mask, u32 timeout_us) { + struct panthor_gpu *gpu = ptdev->gpu; u32 val; int ret; - ret = gpu_read64_relaxed_poll_timeout(ptdev->iomem, pwrtrans_reg, val, + ret = gpu_read64_relaxed_poll_timeout(gpu->iomem, pwrtrans_reg, val, !(mask & val), 100, timeout_us); if (ret) { drm_err(&ptdev->base, @@ -215,9 +223,9 @@ int panthor_gpu_block_power_off(struct panthor_device *ptdev, return ret; } - gpu_write64(ptdev->iomem, pwroff_reg, mask); + gpu_write64(gpu->iomem, pwroff_reg, mask); - ret = gpu_read64_relaxed_poll_timeout(ptdev->iomem, pwrtrans_reg, val, + ret = gpu_read64_relaxed_poll_timeout(gpu->iomem, pwrtrans_reg, val, !(mask & val), 100, timeout_us); if (ret) { drm_err(&ptdev->base, @@ -246,10 +254,11 @@ int panthor_gpu_block_power_on(struct panthor_device *ptdev, u32 pwron_reg, u32 pwrtrans_reg, u32 rdy_reg, u64 mask, u32 timeout_us) { + struct panthor_gpu *gpu = ptdev->gpu; u32 val; int ret; - ret = gpu_read64_relaxed_poll_timeout(ptdev->iomem, pwrtrans_reg, val, + ret = gpu_read64_relaxed_poll_timeout(gpu->iomem, pwrtrans_reg, val, !(mask & val), 100, timeout_us); if (ret) { drm_err(&ptdev->base, @@ -258,9 +267,9 @@ int panthor_gpu_block_power_on(struct panthor_device *ptdev, return ret; } - gpu_write64(ptdev->iomem, pwron_reg, mask); + gpu_write64(gpu->iomem, pwron_reg, mask); - ret = gpu_read64_relaxed_poll_timeout(ptdev->iomem, rdy_reg, val, + ret = gpu_read64_relaxed_poll_timeout(gpu->iomem, rdy_reg, val, (mask & val) == val, 100, timeout_us); if (ret) { @@ -319,6 +328,7 @@ int panthor_gpu_l2_power_on(struct panthor_device *ptdev) int panthor_gpu_flush_caches(struct panthor_device *ptdev, u32 l2, u32 lsc, u32 other) { + struct panthor_gpu *gpu = ptdev->gpu; unsigned long flags; int ret = 0; @@ -328,7 +338,7 @@ int panthor_gpu_flush_caches(struct panthor_device *ptdev, spin_lock_irqsave(&ptdev->gpu->reqs_lock, flags); if (!(ptdev->gpu->pending_reqs & GPU_IRQ_CLEAN_CACHES_COMPLETED)) { ptdev->gpu->pending_reqs |= GPU_IRQ_CLEAN_CACHES_COMPLETED; - gpu_write(ptdev->iomem, GPU_CMD, GPU_FLUSH_CACHES(l2, lsc, other)); + gpu_write(gpu->iomem, GPU_CMD, GPU_FLUSH_CACHES(l2, lsc, other)); } else { ret = -EIO; } @@ -342,7 +352,7 @@ int panthor_gpu_flush_caches(struct panthor_device *ptdev, msecs_to_jiffies(100))) { spin_lock_irqsave(&ptdev->gpu->reqs_lock, flags); if ((ptdev->gpu->pending_reqs & GPU_IRQ_CLEAN_CACHES_COMPLETED) != 0 && - !(gpu_read(ptdev->iomem, GPU_INT_RAWSTAT) & GPU_IRQ_CLEAN_CACHES_COMPLETED)) + !(gpu_read(gpu->irq.iomem, INT_RAWSTAT) & GPU_IRQ_CLEAN_CACHES_COMPLETED)) ret = -ETIMEDOUT; else ptdev->gpu->pending_reqs &= ~GPU_IRQ_CLEAN_CACHES_COMPLETED; @@ -365,6 +375,7 @@ int panthor_gpu_flush_caches(struct panthor_device *ptdev, */ int panthor_gpu_soft_reset(struct panthor_device *ptdev) { + struct panthor_gpu *gpu = ptdev->gpu; bool timedout = false; unsigned long flags; @@ -372,8 +383,8 @@ int panthor_gpu_soft_reset(struct panthor_device *ptdev) if (!drm_WARN_ON(&ptdev->base, ptdev->gpu->pending_reqs & GPU_IRQ_RESET_COMPLETED)) { ptdev->gpu->pending_reqs |= GPU_IRQ_RESET_COMPLETED; - gpu_write(ptdev->iomem, GPU_INT_CLEAR, GPU_IRQ_RESET_COMPLETED); - gpu_write(ptdev->iomem, GPU_CMD, GPU_SOFT_RESET); + gpu_write(gpu->irq.iomem, INT_CLEAR, GPU_IRQ_RESET_COMPLETED); + gpu_write(gpu->iomem, GPU_CMD, GPU_SOFT_RESET); } spin_unlock_irqrestore(&ptdev->gpu->reqs_lock, flags); @@ -382,7 +393,7 @@ int panthor_gpu_soft_reset(struct panthor_device *ptdev) msecs_to_jiffies(100))) { spin_lock_irqsave(&ptdev->gpu->reqs_lock, flags); if ((ptdev->gpu->pending_reqs & GPU_IRQ_RESET_COMPLETED) != 0 && - !(gpu_read(ptdev->iomem, GPU_INT_RAWSTAT) & GPU_IRQ_RESET_COMPLETED)) + !(gpu_read(gpu->irq.iomem, INT_RAWSTAT) & GPU_IRQ_RESET_COMPLETED)) timedout = true; else ptdev->gpu->pending_reqs &= ~GPU_IRQ_RESET_COMPLETED; @@ -431,17 +442,17 @@ void panthor_gpu_resume(struct panthor_device *ptdev) u64 panthor_gpu_get_timestamp(struct panthor_device *ptdev) { - return gpu_read64_counter(ptdev->iomem, GPU_TIMESTAMP); + return gpu_read64_counter(ptdev->gpu->iomem, GPU_TIMESTAMP); } u64 panthor_gpu_get_timestamp_offset(struct panthor_device *ptdev) { - return gpu_read64(ptdev->iomem, GPU_TIMESTAMP_OFFSET); + return gpu_read64(ptdev->gpu->iomem, GPU_TIMESTAMP_OFFSET); } u64 panthor_gpu_get_cycle_count(struct panthor_device *ptdev) { - return gpu_read64_counter(ptdev->iomem, GPU_CYCLE_COUNT); + return gpu_read64_counter(ptdev->gpu->iomem, GPU_CYCLE_COUNT); } int panthor_gpu_coherency_init(struct panthor_device *ptdev) @@ -460,7 +471,7 @@ int panthor_gpu_coherency_init(struct panthor_device *ptdev) /* Check if the ACE-Lite coherency protocol is actually supported by the GPU. * ACE protocol has never been supported for command stream frontend GPUs. */ - if ((gpu_read(ptdev->iomem, GPU_COHERENCY_FEATURES) & + if ((gpu_read(ptdev->gpu->iomem, GPU_COHERENCY_FEATURES) & GPU_COHERENCY_PROT_BIT(ACE_LITE))) { ptdev->gpu_info.selected_coherency = GPU_COHERENCY_ACE_LITE; return 0; diff --git a/drivers/gpu/drm/panthor/panthor_gpu_regs.h b/drivers/gpu/drm/panthor/panthor_gpu_regs.h index 3f60c45985a7..4c5b953796e4 100644 --- a/drivers/gpu/drm/panthor/panthor_gpu_regs.h +++ b/drivers/gpu/drm/panthor/panthor_gpu_regs.h @@ -31,10 +31,6 @@ #define GPU_CSF_ID 0x1C #define GPU_INT_BASE 0x20 -#define GPU_INT_RAWSTAT 0x20 -#define GPU_INT_CLEAR 0x24 -#define GPU_INT_MASK 0x28 -#define GPU_INT_STAT 0x2c #define GPU_IRQ_FAULT BIT(0) #define GPU_IRQ_PROTM_FAULT BIT(1) #define GPU_IRQ_RESET_COMPLETED BIT(8) diff --git a/drivers/gpu/drm/panthor/panthor_hw.c b/drivers/gpu/drm/panthor/panthor_hw.c index 9431f16d950f..80aa151d5936 100644 --- a/drivers/gpu/drm/panthor/panthor_hw.c +++ b/drivers/gpu/drm/panthor/panthor_hw.c @@ -195,28 +195,30 @@ static int panthor_gpu_info_init(struct panthor_device *ptdev) { unsigned int i; - ptdev->gpu_info.csf_id = gpu_read(ptdev->iomem, GPU_CSF_ID); - ptdev->gpu_info.gpu_rev = gpu_read(ptdev->iomem, GPU_REVID); - ptdev->gpu_info.core_features = gpu_read(ptdev->iomem, GPU_CORE_FEATURES); - ptdev->gpu_info.l2_features = gpu_read(ptdev->iomem, GPU_L2_FEATURES); - ptdev->gpu_info.tiler_features = gpu_read(ptdev->iomem, GPU_TILER_FEATURES); - ptdev->gpu_info.mem_features = gpu_read(ptdev->iomem, GPU_MEM_FEATURES); - ptdev->gpu_info.mmu_features = gpu_read(ptdev->iomem, GPU_MMU_FEATURES); - ptdev->gpu_info.thread_features = gpu_read(ptdev->iomem, GPU_THREAD_FEATURES); - ptdev->gpu_info.max_threads = gpu_read(ptdev->iomem, GPU_THREAD_MAX_THREADS); + void __iomem *gpu_iomem = ptdev->iomem + GPU_CONTROL_BASE; + + ptdev->gpu_info.csf_id = gpu_read(gpu_iomem, GPU_CSF_ID); + ptdev->gpu_info.gpu_rev = gpu_read(gpu_iomem, GPU_REVID); + ptdev->gpu_info.core_features = gpu_read(gpu_iomem, GPU_CORE_FEATURES); + ptdev->gpu_info.l2_features = gpu_read(gpu_iomem, GPU_L2_FEATURES); + ptdev->gpu_info.tiler_features = gpu_read(gpu_iomem, GPU_TILER_FEATURES); + ptdev->gpu_info.mem_features = gpu_read(gpu_iomem, GPU_MEM_FEATURES); + ptdev->gpu_info.mmu_features = gpu_read(gpu_iomem, GPU_MMU_FEATURES); + ptdev->gpu_info.thread_features = gpu_read(gpu_iomem, GPU_THREAD_FEATURES); + ptdev->gpu_info.max_threads = gpu_read(gpu_iomem, GPU_THREAD_MAX_THREADS); ptdev->gpu_info.thread_max_workgroup_size = - gpu_read(ptdev->iomem, GPU_THREAD_MAX_WORKGROUP_SIZE); + gpu_read(gpu_iomem, GPU_THREAD_MAX_WORKGROUP_SIZE); ptdev->gpu_info.thread_max_barrier_size = - gpu_read(ptdev->iomem, GPU_THREAD_MAX_BARRIER_SIZE); - ptdev->gpu_info.coherency_features = gpu_read(ptdev->iomem, GPU_COHERENCY_FEATURES); + gpu_read(gpu_iomem, GPU_THREAD_MAX_BARRIER_SIZE); + ptdev->gpu_info.coherency_features = gpu_read(gpu_iomem, GPU_COHERENCY_FEATURES); for (i = 0; i < 4; i++) ptdev->gpu_info.texture_features[i] = - gpu_read(ptdev->iomem, GPU_TEXTURE_FEATURES(i)); + gpu_read(gpu_iomem, GPU_TEXTURE_FEATURES(i)); - ptdev->gpu_info.as_present = gpu_read(ptdev->iomem, GPU_AS_PRESENT); + ptdev->gpu_info.as_present = gpu_read(gpu_iomem, GPU_AS_PRESENT); /* Introduced in arch 11.x */ - ptdev->gpu_info.gpu_features = gpu_read64(ptdev->iomem, GPU_FEATURES); + ptdev->gpu_info.gpu_features = gpu_read64(gpu_iomem, GPU_FEATURES); if (panthor_hw_has_pwr_ctrl(ptdev)) { /* Introduced in arch 14.x */ @@ -224,9 +226,9 @@ static int panthor_gpu_info_init(struct panthor_device *ptdev) ptdev->gpu_info.tiler_present = gpu_read64(ptdev->iomem, PWR_TILER_PRESENT); ptdev->gpu_info.shader_present = gpu_read64(ptdev->iomem, PWR_SHADER_PRESENT); } else { - ptdev->gpu_info.shader_present = gpu_read64(ptdev->iomem, GPU_SHADER_PRESENT); - ptdev->gpu_info.tiler_present = gpu_read64(ptdev->iomem, GPU_TILER_PRESENT); - ptdev->gpu_info.l2_present = gpu_read64(ptdev->iomem, GPU_L2_PRESENT); + ptdev->gpu_info.shader_present = gpu_read64(gpu_iomem, GPU_SHADER_PRESENT); + ptdev->gpu_info.tiler_present = gpu_read64(gpu_iomem, GPU_TILER_PRESENT); + ptdev->gpu_info.l2_present = gpu_read64(gpu_iomem, GPU_L2_PRESENT); } return overload_shader_present(ptdev); From 062b802da689c75d664b7d0a95cbcb832b97ac0e Mon Sep 17 00:00:00 2001 From: Karunika Choo Date: Mon, 27 Apr 2026 16:59:32 +0100 Subject: [PATCH 070/145] drm/panthor: Use a local iomem base for PWR registers Add a PWR_CONTROL-local iomem pointer to struct panthor_pwr and switch power controller register accesses to that base. Update IRQ-local iomem base to use PWR_CONTROl-local iomem and update the register definitions so the PWR block can be addressed relative to its local base. This removes the remaining dependence on the global device MMIO mapping for PWR register accesses. Update panthor_gpu_info_init() to also use the correct PWR_CONTROL iomem for the *_PRESENT registers. No functional change intended. v3: - Clean up definitions for pwr->iomem and pwr->irq.iomem. - Update PWR_INT_BASE to be relative to pwr->iomem. v2: - Update panthor_gpu_info_init() to use block-local iomem pointer. Signed-off-by: Karunika Choo Acked-by: Boris Brezillon Reviewed-by: Steven Price Reviewed-by: Liviu Dudau Signed-off-by: Liviu Dudau Link: https://patch.msgid.link/20260427155934.416502-7-karunika.choo@arm.com --- drivers/gpu/drm/panthor/panthor_hw.c | 8 ++- drivers/gpu/drm/panthor/panthor_pwr.c | 81 ++++++++++++++-------- drivers/gpu/drm/panthor/panthor_pwr_regs.h | 50 ++++++------- 3 files changed, 80 insertions(+), 59 deletions(-) diff --git a/drivers/gpu/drm/panthor/panthor_hw.c b/drivers/gpu/drm/panthor/panthor_hw.c index 80aa151d5936..7e315708ca7c 100644 --- a/drivers/gpu/drm/panthor/panthor_hw.c +++ b/drivers/gpu/drm/panthor/panthor_hw.c @@ -221,10 +221,12 @@ static int panthor_gpu_info_init(struct panthor_device *ptdev) ptdev->gpu_info.gpu_features = gpu_read64(gpu_iomem, GPU_FEATURES); if (panthor_hw_has_pwr_ctrl(ptdev)) { + void __iomem *pwr_iomem = gpu_iomem + PWR_CONTROL_BASE; + /* Introduced in arch 14.x */ - ptdev->gpu_info.l2_present = gpu_read64(ptdev->iomem, PWR_L2_PRESENT); - ptdev->gpu_info.tiler_present = gpu_read64(ptdev->iomem, PWR_TILER_PRESENT); - ptdev->gpu_info.shader_present = gpu_read64(ptdev->iomem, PWR_SHADER_PRESENT); + ptdev->gpu_info.l2_present = gpu_read64(pwr_iomem, PWR_L2_PRESENT); + ptdev->gpu_info.tiler_present = gpu_read64(pwr_iomem, PWR_TILER_PRESENT); + ptdev->gpu_info.shader_present = gpu_read64(pwr_iomem, PWR_SHADER_PRESENT); } else { ptdev->gpu_info.shader_present = gpu_read64(gpu_iomem, GPU_SHADER_PRESENT); ptdev->gpu_info.tiler_present = gpu_read64(gpu_iomem, GPU_TILER_PRESENT); diff --git a/drivers/gpu/drm/panthor/panthor_pwr.c b/drivers/gpu/drm/panthor/panthor_pwr.c index 705d998447b5..7c7f424a1436 100644 --- a/drivers/gpu/drm/panthor/panthor_pwr.c +++ b/drivers/gpu/drm/panthor/panthor_pwr.c @@ -40,6 +40,9 @@ * struct panthor_pwr - PWR_CONTROL block management data. */ struct panthor_pwr { + /** @iomem: CPU mapping of PWR_CONTROL iomem region */ + void __iomem *iomem; + /** @irq: PWR irq. */ struct panthor_irq irq; @@ -55,8 +58,10 @@ struct panthor_pwr { static void panthor_pwr_irq_handler(struct panthor_device *ptdev, u32 status) { + struct panthor_pwr *pwr = ptdev->pwr; + spin_lock(&ptdev->pwr->reqs_lock); - gpu_write(ptdev->iomem, PWR_INT_CLEAR, status); + gpu_write(pwr->irq.iomem, INT_CLEAR, status); if (unlikely(status & PWR_IRQ_COMMAND_NOT_ALLOWED)) drm_err(&ptdev->base, "PWR_IRQ: COMMAND_NOT_ALLOWED"); @@ -74,15 +79,19 @@ PANTHOR_IRQ_HANDLER(pwr, panthor_pwr_irq_handler); static void panthor_pwr_write_command(struct panthor_device *ptdev, u32 command, u64 args) { - if (args) - gpu_write64(ptdev->iomem, PWR_CMDARG, args); + struct panthor_pwr *pwr = ptdev->pwr; - gpu_write(ptdev->iomem, PWR_COMMAND, command); + if (args) + gpu_write64(pwr->iomem, PWR_CMDARG, args); + + gpu_write(pwr->iomem, PWR_COMMAND, command); } static bool reset_irq_raised(struct panthor_device *ptdev) { - return gpu_read(ptdev->iomem, PWR_INT_RAWSTAT) & PWR_IRQ_RESET_COMPLETED; + struct panthor_pwr *pwr = ptdev->pwr; + + return gpu_read(pwr->irq.iomem, INT_RAWSTAT) & PWR_IRQ_RESET_COMPLETED; } static bool reset_pending(struct panthor_device *ptdev) @@ -92,12 +101,14 @@ static bool reset_pending(struct panthor_device *ptdev) static int panthor_pwr_reset(struct panthor_device *ptdev, u32 reset_cmd) { + struct panthor_pwr *pwr = ptdev->pwr; + scoped_guard(spinlock_irqsave, &ptdev->pwr->reqs_lock) { if (reset_pending(ptdev)) { drm_WARN(&ptdev->base, 1, "Reset already pending"); } else { ptdev->pwr->pending_reqs |= PWR_IRQ_RESET_COMPLETED; - gpu_write(ptdev->iomem, PWR_INT_CLEAR, PWR_IRQ_RESET_COMPLETED); + gpu_write(pwr->irq.iomem, INT_CLEAR, PWR_IRQ_RESET_COMPLETED); panthor_pwr_write_command(ptdev, reset_cmd, 0); } } @@ -182,11 +193,12 @@ static u8 get_domain_subdomain(struct panthor_device *ptdev, u32 domain) static int panthor_pwr_domain_wait_transition(struct panthor_device *ptdev, u32 domain, u32 timeout_us) { + struct panthor_pwr *pwr = ptdev->pwr; u32 pwrtrans_reg = get_domain_pwrtrans_reg(domain); u64 val; int ret = 0; - ret = gpu_read64_poll_timeout(ptdev->iomem, pwrtrans_reg, val, !(PWR_ALL_CORES_MASK & val), 100, + ret = gpu_read64_poll_timeout(pwr->iomem, pwrtrans_reg, val, !(PWR_ALL_CORES_MASK & val), 100, timeout_us); if (ret) { drm_err(&ptdev->base, "%s domain power in transition, pwrtrans(0x%llx)", @@ -199,22 +211,25 @@ static int panthor_pwr_domain_wait_transition(struct panthor_device *ptdev, u32 static void panthor_pwr_debug_info_show(struct panthor_device *ptdev) { + struct panthor_pwr *pwr = ptdev->pwr; + drm_info(&ptdev->base, "GPU_FEATURES: 0x%016llx", ptdev->gpu_info.gpu_features); - drm_info(&ptdev->base, "PWR_STATUS: 0x%016llx", gpu_read64(ptdev->iomem, PWR_STATUS)); - drm_info(&ptdev->base, "L2_PRESENT: 0x%016llx", gpu_read64(ptdev->iomem, PWR_L2_PRESENT)); - drm_info(&ptdev->base, "L2_PWRTRANS: 0x%016llx", gpu_read64(ptdev->iomem, PWR_L2_PWRTRANS)); - drm_info(&ptdev->base, "L2_READY: 0x%016llx", gpu_read64(ptdev->iomem, PWR_L2_READY)); - drm_info(&ptdev->base, "TILER_PRESENT: 0x%016llx", gpu_read64(ptdev->iomem, PWR_TILER_PRESENT)); - drm_info(&ptdev->base, "TILER_PWRTRANS: 0x%016llx", gpu_read64(ptdev->iomem, PWR_TILER_PWRTRANS)); - drm_info(&ptdev->base, "TILER_READY: 0x%016llx", gpu_read64(ptdev->iomem, PWR_TILER_READY)); - drm_info(&ptdev->base, "SHADER_PRESENT: 0x%016llx", gpu_read64(ptdev->iomem, PWR_SHADER_PRESENT)); - drm_info(&ptdev->base, "SHADER_PWRTRANS: 0x%016llx", gpu_read64(ptdev->iomem, PWR_SHADER_PWRTRANS)); - drm_info(&ptdev->base, "SHADER_READY: 0x%016llx", gpu_read64(ptdev->iomem, PWR_SHADER_READY)); + drm_info(&ptdev->base, "PWR_STATUS: 0x%016llx", gpu_read64(pwr->iomem, PWR_STATUS)); + drm_info(&ptdev->base, "L2_PRESENT: 0x%016llx", gpu_read64(pwr->iomem, PWR_L2_PRESENT)); + drm_info(&ptdev->base, "L2_PWRTRANS: 0x%016llx", gpu_read64(pwr->iomem, PWR_L2_PWRTRANS)); + drm_info(&ptdev->base, "L2_READY: 0x%016llx", gpu_read64(pwr->iomem, PWR_L2_READY)); + drm_info(&ptdev->base, "TILER_PRESENT: 0x%016llx", gpu_read64(pwr->iomem, PWR_TILER_PRESENT)); + drm_info(&ptdev->base, "TILER_PWRTRANS: 0x%016llx", gpu_read64(pwr->iomem, PWR_TILER_PWRTRANS)); + drm_info(&ptdev->base, "TILER_READY: 0x%016llx", gpu_read64(pwr->iomem, PWR_TILER_READY)); + drm_info(&ptdev->base, "SHADER_PRESENT: 0x%016llx", gpu_read64(pwr->iomem, PWR_SHADER_PRESENT)); + drm_info(&ptdev->base, "SHADER_PWRTRANS: 0x%016llx", gpu_read64(pwr->iomem, PWR_SHADER_PWRTRANS)); + drm_info(&ptdev->base, "SHADER_READY: 0x%016llx", gpu_read64(pwr->iomem, PWR_SHADER_READY)); } static int panthor_pwr_domain_transition(struct panthor_device *ptdev, u32 cmd, u32 domain, u64 mask, u32 timeout_us) { + struct panthor_pwr *pwr = ptdev->pwr; u32 ready_reg = get_domain_ready_reg(domain); u32 pwr_cmd = PWR_COMMAND_DEF(cmd, domain, get_domain_subdomain(ptdev, domain)); u64 expected_val = 0; @@ -241,12 +256,12 @@ static int panthor_pwr_domain_transition(struct panthor_device *ptdev, u32 cmd, return ret; /* domain already in target state, return early */ - if ((gpu_read64(ptdev->iomem, ready_reg) & mask) == expected_val) + if ((gpu_read64(pwr->iomem, ready_reg) & mask) == expected_val) return 0; panthor_pwr_write_command(ptdev, pwr_cmd, mask); - ret = gpu_read64_poll_timeout(ptdev->iomem, ready_reg, val, (mask & val) == expected_val, + ret = gpu_read64_poll_timeout(pwr->iomem, ready_reg, val, (mask & val) == expected_val, 100, timeout_us); if (ret) { drm_err(&ptdev->base, @@ -279,8 +294,9 @@ static int panthor_pwr_domain_transition(struct panthor_device *ptdev, u32 cmd, */ static int retract_domain(struct panthor_device *ptdev, u32 domain) { + struct panthor_pwr *pwr = ptdev->pwr; const u32 pwr_cmd = PWR_COMMAND_DEF(PWR_COMMAND_RETRACT, domain, 0); - const u64 pwr_status = gpu_read64(ptdev->iomem, PWR_STATUS); + const u64 pwr_status = gpu_read64(pwr->iomem, PWR_STATUS); const u64 delegated_mask = PWR_STATUS_DOMAIN_DELEGATED(domain); const u64 allow_mask = PWR_STATUS_DOMAIN_ALLOWED(domain); u64 val; @@ -289,7 +305,7 @@ static int retract_domain(struct panthor_device *ptdev, u32 domain) if (drm_WARN_ON(&ptdev->base, domain == PWR_COMMAND_DOMAIN_L2)) return -EPERM; - ret = gpu_read64_poll_timeout(ptdev->iomem, PWR_STATUS, val, + ret = gpu_read64_poll_timeout(pwr->iomem, PWR_STATUS, val, !(PWR_STATUS_RETRACT_PENDING & val), 0, PWR_RETRACT_TIMEOUT_US); if (ret) { @@ -308,7 +324,7 @@ static int retract_domain(struct panthor_device *ptdev, u32 domain) * On successful retraction * allow-flag will be set with delegated-flag being cleared. */ - ret = gpu_read64_poll_timeout(ptdev->iomem, PWR_STATUS, val, + ret = gpu_read64_poll_timeout(pwr->iomem, PWR_STATUS, val, ((delegated_mask | allow_mask) & val) == allow_mask, 10, PWR_TRANSITION_TIMEOUT_US); if (ret) { @@ -334,8 +350,9 @@ static int retract_domain(struct panthor_device *ptdev, u32 domain) */ static int delegate_domain(struct panthor_device *ptdev, u32 domain) { + struct panthor_pwr *pwr = ptdev->pwr; const u32 pwr_cmd = PWR_COMMAND_DEF(PWR_COMMAND_DELEGATE, domain, 0); - const u64 pwr_status = gpu_read64(ptdev->iomem, PWR_STATUS); + const u64 pwr_status = gpu_read64(pwr->iomem, PWR_STATUS); const u64 allow_mask = PWR_STATUS_DOMAIN_ALLOWED(domain); const u64 delegated_mask = PWR_STATUS_DOMAIN_DELEGATED(domain); u64 val; @@ -364,7 +381,7 @@ static int delegate_domain(struct panthor_device *ptdev, u32 domain) * On successful delegation * allow-flag will be cleared with delegated-flag being set. */ - ret = gpu_read64_poll_timeout(ptdev->iomem, PWR_STATUS, val, + ret = gpu_read64_poll_timeout(pwr->iomem, PWR_STATUS, val, ((delegated_mask | allow_mask) & val) == delegated_mask, 10, PWR_TRANSITION_TIMEOUT_US); if (ret) { @@ -412,7 +429,8 @@ static int panthor_pwr_delegate_domains(struct panthor_device *ptdev) */ static int panthor_pwr_domain_force_off(struct panthor_device *ptdev, u32 domain) { - const u64 domain_ready = gpu_read64(ptdev->iomem, get_domain_ready_reg(domain)); + struct panthor_pwr *pwr = ptdev->pwr; + const u64 domain_ready = gpu_read64(pwr->iomem, get_domain_ready_reg(domain)); int ret; /* Domain already powered down, early exit. */ @@ -456,6 +474,7 @@ int panthor_pwr_init(struct panthor_device *ptdev) if (!pwr) return -ENOMEM; + pwr->iomem = ptdev->iomem + PWR_CONTROL_BASE; spin_lock_init(&pwr->reqs_lock); init_waitqueue_head(&pwr->reqs_acked); ptdev->pwr = pwr; @@ -466,7 +485,7 @@ int panthor_pwr_init(struct panthor_device *ptdev) err = panthor_request_pwr_irq( ptdev, &pwr->irq, irq, PWR_INTERRUPTS_MASK, - ptdev->iomem + PWR_CONTROL_BASE); + pwr->iomem + PWR_INT_BASE); if (err) return err; @@ -475,7 +494,9 @@ int panthor_pwr_init(struct panthor_device *ptdev) int panthor_pwr_reset_soft(struct panthor_device *ptdev) { - if (!(gpu_read64(ptdev->iomem, PWR_STATUS) & PWR_STATUS_ALLOW_SOFT_RESET)) { + struct panthor_pwr *pwr = ptdev->pwr; + + if (!(gpu_read64(pwr->iomem, PWR_STATUS) & PWR_STATUS_ALLOW_SOFT_RESET)) { drm_err(&ptdev->base, "RESET_SOFT not allowed"); return -EOPNOTSUPP; } @@ -485,8 +506,9 @@ int panthor_pwr_reset_soft(struct panthor_device *ptdev) void panthor_pwr_l2_power_off(struct panthor_device *ptdev) { + struct panthor_pwr *pwr = ptdev->pwr; const u64 l2_allow_mask = PWR_STATUS_DOMAIN_ALLOWED(PWR_COMMAND_DOMAIN_L2); - const u64 pwr_status = gpu_read64(ptdev->iomem, PWR_STATUS); + const u64 pwr_status = gpu_read64(pwr->iomem, PWR_STATUS); /* Abort if L2 power off constraints are not satisfied */ if (!(pwr_status & l2_allow_mask)) { @@ -512,7 +534,8 @@ void panthor_pwr_l2_power_off(struct panthor_device *ptdev) int panthor_pwr_l2_power_on(struct panthor_device *ptdev) { - const u32 pwr_status = gpu_read64(ptdev->iomem, PWR_STATUS); + struct panthor_pwr *pwr = ptdev->pwr; + const u32 pwr_status = gpu_read64(pwr->iomem, PWR_STATUS); const u32 l2_allow_mask = PWR_STATUS_DOMAIN_ALLOWED(PWR_COMMAND_DOMAIN_L2); int ret; diff --git a/drivers/gpu/drm/panthor/panthor_pwr_regs.h b/drivers/gpu/drm/panthor/panthor_pwr_regs.h index ad3e446971db..9cf7a715066f 100644 --- a/drivers/gpu/drm/panthor/panthor_pwr_regs.h +++ b/drivers/gpu/drm/panthor/panthor_pwr_regs.h @@ -5,12 +5,8 @@ #define __PANTHOR_PWR_REGS_H__ #define PWR_CONTROL_BASE 0x800 -#define PWR_CTRL_REG(x) (PWR_CONTROL_BASE + (x)) -#define PWR_INT_RAWSTAT PWR_CTRL_REG(0x0) -#define PWR_INT_CLEAR PWR_CTRL_REG(0x4) -#define PWR_INT_MASK PWR_CTRL_REG(0x8) -#define PWR_INT_STAT PWR_CTRL_REG(0xc) +#define PWR_INT_BASE 0x0 #define PWR_IRQ_POWER_CHANGED_SINGLE BIT(0) #define PWR_IRQ_POWER_CHANGED_ALL BIT(1) #define PWR_IRQ_DELEGATION_CHANGED BIT(2) @@ -20,7 +16,7 @@ #define PWR_IRQ_COMMAND_NOT_ALLOWED BIT(30) #define PWR_IRQ_COMMAND_INVALID BIT(31) -#define PWR_STATUS PWR_CTRL_REG(0x20) +#define PWR_STATUS 0x20 #define PWR_STATUS_ALLOW_L2 BIT_U64(0) #define PWR_STATUS_ALLOW_TILER BIT_U64(1) #define PWR_STATUS_ALLOW_SHADER BIT_U64(8) @@ -41,7 +37,7 @@ #define PWR_STATUS_RETRACT_PENDING BIT_U64(43) #define PWR_STATUS_INSPECT_PENDING BIT_U64(44) -#define PWR_COMMAND PWR_CTRL_REG(0x28) +#define PWR_COMMAND 0x28 #define PWR_COMMAND_POWER_UP 0x10 #define PWR_COMMAND_POWER_DOWN 0x11 #define PWR_COMMAND_DELEGATE 0x20 @@ -58,26 +54,26 @@ #define PWR_COMMAND_DEF(cmd, domain, subdomain) \ (((subdomain) << 16) | ((domain) << 8) | (cmd)) -#define PWR_CMDARG PWR_CTRL_REG(0x30) +#define PWR_CMDARG 0x30 -#define PWR_L2_PRESENT PWR_CTRL_REG(0x100) -#define PWR_L2_READY PWR_CTRL_REG(0x108) -#define PWR_L2_PWRTRANS PWR_CTRL_REG(0x110) -#define PWR_L2_PWRACTIVE PWR_CTRL_REG(0x118) -#define PWR_TILER_PRESENT PWR_CTRL_REG(0x140) -#define PWR_TILER_READY PWR_CTRL_REG(0x148) -#define PWR_TILER_PWRTRANS PWR_CTRL_REG(0x150) -#define PWR_TILER_PWRACTIVE PWR_CTRL_REG(0x158) -#define PWR_SHADER_PRESENT PWR_CTRL_REG(0x200) -#define PWR_SHADER_READY PWR_CTRL_REG(0x208) -#define PWR_SHADER_PWRTRANS PWR_CTRL_REG(0x210) -#define PWR_SHADER_PWRACTIVE PWR_CTRL_REG(0x218) -#define PWR_BASE_PRESENT PWR_CTRL_REG(0x380) -#define PWR_BASE_READY PWR_CTRL_REG(0x388) -#define PWR_BASE_PWRTRANS PWR_CTRL_REG(0x390) -#define PWR_BASE_PWRACTIVE PWR_CTRL_REG(0x398) -#define PWR_STACK_PRESENT PWR_CTRL_REG(0x3c0) -#define PWR_STACK_READY PWR_CTRL_REG(0x3c8) -#define PWR_STACK_PWRTRANS PWR_CTRL_REG(0x3d0) +#define PWR_L2_PRESENT 0x100 +#define PWR_L2_READY 0x108 +#define PWR_L2_PWRTRANS 0x110 +#define PWR_L2_PWRACTIVE 0x118 +#define PWR_TILER_PRESENT 0x140 +#define PWR_TILER_READY 0x148 +#define PWR_TILER_PWRTRANS 0x150 +#define PWR_TILER_PWRACTIVE 0x158 +#define PWR_SHADER_PRESENT 0x200 +#define PWR_SHADER_READY 0x208 +#define PWR_SHADER_PWRTRANS 0x210 +#define PWR_SHADER_PWRACTIVE 0x218 +#define PWR_BASE_PRESENT 0x380 +#define PWR_BASE_READY 0x388 +#define PWR_BASE_PWRTRANS 0x390 +#define PWR_BASE_PWRACTIVE 0x398 +#define PWR_STACK_PRESENT 0x3c0 +#define PWR_STACK_READY 0x3c8 +#define PWR_STACK_PWRTRANS 0x3d0 #endif /* __PANTHOR_PWR_REGS_H__ */ From 0c1ff073e22a898d0900bbda39c9f3782b807484 Mon Sep 17 00:00:00 2001 From: Karunika Choo Date: Mon, 27 Apr 2026 16:59:33 +0100 Subject: [PATCH 071/145] drm/panthor: Use a local iomem base for firmware control registers Add an MCU_CONTROL-local iomem pointer to struct panthor_fw and use it for firmware control and status register accesses. Job interrupt accesses continue to go through the IRQ-local base, while doorbell writes stay on the device-wide mapping because they live outside the MCU control window. This keeps firmware register accesses scoped to the component that owns them. No functional change intended. v3: - Pick up R-bs from Liviu and Steve v2: - Pick up Ack from Boris. Reviewed-by: Steven Price Reviewed-by: Liviu Dudau Acked-by: Boris Brezillon Signed-off-by: Karunika Choo Tested-by: Boris Brezillon Signed-off-by: Liviu Dudau Link: https://patch.msgid.link/20260427155934.416502-8-karunika.choo@arm.com --- drivers/gpu/drm/panthor/panthor_fw.c | 20 +++++++++++++------- drivers/gpu/drm/panthor/panthor_fw_regs.h | 11 ++++------- 2 files changed, 17 insertions(+), 14 deletions(-) diff --git a/drivers/gpu/drm/panthor/panthor_fw.c b/drivers/gpu/drm/panthor/panthor_fw.c index 73ef07a37e22..986151681b24 100644 --- a/drivers/gpu/drm/panthor/panthor_fw.c +++ b/drivers/gpu/drm/panthor/panthor_fw.c @@ -234,6 +234,9 @@ struct panthor_fw_iface { * struct panthor_fw - Firmware management */ struct panthor_fw { + /** @iomem: CPU mapping of MCU_CONTROL iomem region */ + void __iomem *iomem; + /** @vm: MCU VM. */ struct panthor_vm *vm; @@ -1069,7 +1072,7 @@ static void panthor_job_irq_handler(struct panthor_device *ptdev, u32 status) if (tracepoint_enabled(gpu_job_irq)) start = ktime_get_ns(); - gpu_write(ptdev->iomem, JOB_INT_CLEAR, status); + gpu_write(ptdev->fw->irq.iomem, INT_CLEAR, status); if (!ptdev->fw->booted && (status & JOB_INT_GLOBAL_IF)) ptdev->fw->booted = true; @@ -1092,18 +1095,19 @@ PANTHOR_IRQ_HANDLER(job, panthor_job_irq_handler); static int panthor_fw_start(struct panthor_device *ptdev) { + struct panthor_fw *fw = ptdev->fw; bool timedout = false; ptdev->fw->booted = false; panthor_job_irq_enable_events(&ptdev->fw->irq, ~0); panthor_job_irq_resume(&ptdev->fw->irq); - gpu_write(ptdev->iomem, MCU_CONTROL, MCU_CONTROL_AUTO); + gpu_write(fw->iomem, MCU_CONTROL, MCU_CONTROL_AUTO); if (!wait_event_timeout(ptdev->fw->req_waitqueue, ptdev->fw->booted, msecs_to_jiffies(1000))) { if (!ptdev->fw->booted && - !(gpu_read(ptdev->iomem, JOB_INT_STAT) & JOB_INT_GLOBAL_IF)) + !(gpu_read(fw->irq.iomem, INT_STAT) & JOB_INT_GLOBAL_IF)) timedout = true; } @@ -1114,7 +1118,7 @@ static int panthor_fw_start(struct panthor_device *ptdev) [MCU_STATUS_HALT] = "halt", [MCU_STATUS_FATAL] = "fatal", }; - u32 status = gpu_read(ptdev->iomem, MCU_STATUS); + u32 status = gpu_read(fw->iomem, MCU_STATUS); drm_err(&ptdev->base, "Failed to boot MCU (status=%s)", status < ARRAY_SIZE(status_str) ? status_str[status] : "unknown"); @@ -1126,10 +1130,11 @@ static int panthor_fw_start(struct panthor_device *ptdev) static void panthor_fw_stop(struct panthor_device *ptdev) { + struct panthor_fw *fw = ptdev->fw; u32 status; - gpu_write(ptdev->iomem, MCU_CONTROL, MCU_CONTROL_DISABLE); - if (gpu_read_poll_timeout(ptdev->iomem, MCU_STATUS, status, + gpu_write(fw->iomem, MCU_CONTROL, MCU_CONTROL_DISABLE); + if (gpu_read_poll_timeout(fw->iomem, MCU_STATUS, status, status == MCU_STATUS_DISABLED, 10, 100000)) drm_err(&ptdev->base, "Failed to stop MCU"); } @@ -1139,7 +1144,7 @@ static bool panthor_fw_mcu_halted(struct panthor_device *ptdev) struct panthor_fw_global_iface *glb_iface = panthor_fw_get_glb_iface(ptdev); bool halted; - halted = gpu_read(ptdev->iomem, MCU_STATUS) == MCU_STATUS_HALT; + halted = gpu_read(ptdev->fw->iomem, MCU_STATUS) == MCU_STATUS_HALT; if (panthor_fw_has_glb_state(ptdev)) halted &= (GLB_STATE_GET(glb_iface->output->ack) == GLB_STATE_HALT); @@ -1461,6 +1466,7 @@ int panthor_fw_init(struct panthor_device *ptdev) if (!fw) return -ENOMEM; + fw->iomem = ptdev->iomem + MCU_CONTROL_BASE; ptdev->fw = fw; init_waitqueue_head(&fw->req_waitqueue); INIT_LIST_HEAD(&fw->sections); diff --git a/drivers/gpu/drm/panthor/panthor_fw_regs.h b/drivers/gpu/drm/panthor/panthor_fw_regs.h index eeb41aff249b..b2e59cfc22b0 100644 --- a/drivers/gpu/drm/panthor/panthor_fw_regs.h +++ b/drivers/gpu/drm/panthor/panthor_fw_regs.h @@ -4,23 +4,20 @@ #ifndef __PANTHOR_FW_REGS_H__ #define __PANTHOR_FW_REGS_H__ -#define MCU_CONTROL 0x700 +#define MCU_CONTROL_BASE 0x700 + +#define MCU_CONTROL 0x0 #define MCU_CONTROL_ENABLE 1 #define MCU_CONTROL_AUTO 2 #define MCU_CONTROL_DISABLE 0 -#define MCU_STATUS 0x704 +#define MCU_STATUS 0x4 #define MCU_STATUS_DISABLED 0 #define MCU_STATUS_ENABLED 1 #define MCU_STATUS_HALT 2 #define MCU_STATUS_FATAL 3 #define JOB_INT_BASE 0x1000 - -#define JOB_INT_RAWSTAT 0x1000 -#define JOB_INT_CLEAR 0x1004 -#define JOB_INT_MASK 0x1008 -#define JOB_INT_STAT 0x100c #define JOB_INT_GLOBAL_IF BIT(31) #define JOB_INT_CSG_IF(x) BIT(x) From 29d6da40d0b8bf3bbc3dcd1d2198434a0e1f71b0 Mon Sep 17 00:00:00 2001 From: Karunika Choo Date: Mon, 27 Apr 2026 16:59:34 +0100 Subject: [PATCH 072/145] drm/panthor: Use a local iomem base for MMU AS registers Add an MMU_AS_CONTROL local iomem pointer to struct panthor_mmu and switch AS register accesses to that base. Interrupt accesses remain routed through the IRQ-local iomem base, while the MMU register definitions are adjusted so AS registers are expressed relative to the local MMU AS window. This completes the conversion away from using the global device mapping for MMU AS register accesses. No functional change intended. v3: - Pick up R-bs from Liviu and Steve v2: - Pick up Ack from Boris. Reviewed-by: Steven Price Reviewed-by: Liviu Dudau Acked-by: Boris Brezillon Signed-off-by: Karunika Choo Tested-by: Boris Brezillon Signed-off-by: Liviu Dudau Link: https://patch.msgid.link/20260427155934.416502-9-karunika.choo@arm.com --- drivers/gpu/drm/panthor/panthor_mmu.c | 35 ++++++++++++++-------- drivers/gpu/drm/panthor/panthor_mmu_regs.h | 10 ++----- 2 files changed, 25 insertions(+), 20 deletions(-) diff --git a/drivers/gpu/drm/panthor/panthor_mmu.c b/drivers/gpu/drm/panthor/panthor_mmu.c index 64d53e7cb763..a7ee14986849 100644 --- a/drivers/gpu/drm/panthor/panthor_mmu.c +++ b/drivers/gpu/drm/panthor/panthor_mmu.c @@ -55,6 +55,9 @@ struct panthor_as_slot { * struct panthor_mmu - MMU related data */ struct panthor_mmu { + /** @iomem: CPU mapping of MMU_AS_CONTROL iomem region */ + void __iomem *iomem; + /** @irq: The MMU irq. */ struct panthor_irq irq; @@ -517,13 +520,14 @@ static void free_pt(void *cookie, void *data, size_t size) static int wait_ready(struct panthor_device *ptdev, u32 as_nr) { + struct panthor_mmu *mmu = ptdev->mmu; int ret; u32 val; /* Wait for the MMU status to indicate there is no active command, in * case one is pending. */ - ret = gpu_read_relaxed_poll_timeout_atomic(ptdev->iomem, AS_STATUS(as_nr), val, + ret = gpu_read_relaxed_poll_timeout_atomic(mmu->iomem, AS_STATUS(as_nr), val, !(val & AS_STATUS_AS_ACTIVE), 10, 100000); if (ret) { @@ -541,7 +545,7 @@ static int as_send_cmd_and_wait(struct panthor_device *ptdev, u32 as_nr, u32 cmd /* write AS_COMMAND when MMU is ready to accept another command */ status = wait_ready(ptdev, as_nr); if (!status) { - gpu_write(ptdev->iomem, AS_COMMAND(as_nr), cmd); + gpu_write(ptdev->mmu->iomem, AS_COMMAND(as_nr), cmd); status = wait_ready(ptdev, as_nr); } @@ -589,12 +593,14 @@ PANTHOR_IRQ_HANDLER(mmu, panthor_mmu_irq_handler); static int panthor_mmu_as_enable(struct panthor_device *ptdev, u32 as_nr, u64 transtab, u64 transcfg, u64 memattr) { + struct panthor_mmu *mmu = ptdev->mmu; + panthor_mmu_irq_enable_events(&ptdev->mmu->irq, panthor_mmu_as_fault_mask(ptdev, as_nr)); - gpu_write64(ptdev->iomem, AS_TRANSTAB(as_nr), transtab); - gpu_write64(ptdev->iomem, AS_MEMATTR(as_nr), memattr); - gpu_write64(ptdev->iomem, AS_TRANSCFG(as_nr), transcfg); + gpu_write64(mmu->iomem, AS_TRANSTAB(as_nr), transtab); + gpu_write64(mmu->iomem, AS_MEMATTR(as_nr), memattr); + gpu_write64(mmu->iomem, AS_TRANSCFG(as_nr), transcfg); return as_send_cmd_and_wait(ptdev, as_nr, AS_COMMAND_UPDATE); } @@ -602,6 +608,7 @@ static int panthor_mmu_as_enable(struct panthor_device *ptdev, u32 as_nr, static int panthor_mmu_as_disable(struct panthor_device *ptdev, u32 as_nr, bool recycle_slot) { + struct panthor_mmu *mmu = ptdev->mmu; struct panthor_vm *vm = ptdev->mmu->as.slots[as_nr].vm; int ret; @@ -629,9 +636,9 @@ static int panthor_mmu_as_disable(struct panthor_device *ptdev, u32 as_nr, if (recycle_slot) return 0; - gpu_write64(ptdev->iomem, AS_TRANSTAB(as_nr), 0); - gpu_write64(ptdev->iomem, AS_MEMATTR(as_nr), 0); - gpu_write64(ptdev->iomem, AS_TRANSCFG(as_nr), AS_TRANSCFG_ADRMODE_UNMAPPED); + gpu_write64(mmu->iomem, AS_TRANSTAB(as_nr), 0); + gpu_write64(mmu->iomem, AS_MEMATTR(as_nr), 0); + gpu_write64(mmu->iomem, AS_TRANSCFG(as_nr), AS_TRANSCFG_ADRMODE_UNMAPPED); return as_send_cmd_and_wait(ptdev, as_nr, AS_COMMAND_UPDATE); } @@ -784,7 +791,7 @@ int panthor_vm_active(struct panthor_vm *vm) */ fault_mask = panthor_mmu_as_fault_mask(ptdev, as); if (ptdev->mmu->as.faulty_mask & fault_mask) { - gpu_write(ptdev->iomem, MMU_INT_CLEAR, fault_mask); + gpu_write(ptdev->mmu->irq.iomem, INT_CLEAR, fault_mask); ptdev->mmu->as.faulty_mask &= ~fault_mask; } @@ -1731,7 +1738,7 @@ static int panthor_vm_lock_region(struct panthor_vm *vm, u64 start, u64 size) mutex_lock(&ptdev->mmu->as.slots_lock); if (vm->as.id >= 0 && size) { /* Lock the region that needs to be updated */ - gpu_write64(ptdev->iomem, AS_LOCKADDR(vm->as.id), + gpu_write64(ptdev->mmu->iomem, AS_LOCKADDR(vm->as.id), pack_region_range(ptdev, &start, &size)); /* If the lock succeeded, update the locked_region info. */ @@ -1780,6 +1787,7 @@ static void panthor_vm_unlock_region(struct panthor_vm *vm) static void panthor_mmu_irq_handler(struct panthor_device *ptdev, u32 status) { + struct panthor_mmu *mmu = ptdev->mmu; bool has_unhandled_faults = false; status = panthor_mmu_fault_mask(ptdev, status); @@ -1792,8 +1800,8 @@ static void panthor_mmu_irq_handler(struct panthor_device *ptdev, u32 status) u32 access_type; u32 source_id; - fault_status = gpu_read(ptdev->iomem, AS_FAULTSTATUS(as)); - addr = gpu_read64(ptdev->iomem, AS_FAULTADDRESS(as)); + fault_status = gpu_read(mmu->iomem, AS_FAULTSTATUS(as)); + addr = gpu_read64(mmu->iomem, AS_FAULTADDRESS(as)); /* decode the fault status */ exception_type = fault_status & 0xFF; @@ -1824,7 +1832,7 @@ static void panthor_mmu_irq_handler(struct panthor_device *ptdev, u32 status) * Note that COMPLETED irqs are never cleared, but this is fine * because they are always masked. */ - gpu_write(ptdev->iomem, MMU_INT_CLEAR, mask); + gpu_write(mmu->irq.iomem, INT_CLEAR, mask); if (ptdev->mmu->as.slots[as].vm) ptdev->mmu->as.slots[as].vm->unhandled_fault = true; @@ -3240,6 +3248,7 @@ int panthor_mmu_init(struct panthor_device *ptdev) if (ret) return ret; + mmu->iomem = ptdev->iomem + MMU_AS_BASE; ptdev->mmu = mmu; irq = platform_get_irq_byname(to_platform_device(ptdev->base.dev), "mmu"); diff --git a/drivers/gpu/drm/panthor/panthor_mmu_regs.h b/drivers/gpu/drm/panthor/panthor_mmu_regs.h index de460042651d..4e32ab931949 100644 --- a/drivers/gpu/drm/panthor/panthor_mmu_regs.h +++ b/drivers/gpu/drm/panthor/panthor_mmu_regs.h @@ -8,16 +8,12 @@ #define MMU_INT_BASE 0x2000 -#define MMU_INT_RAWSTAT 0x2000 -#define MMU_INT_CLEAR 0x2004 -#define MMU_INT_MASK 0x2008 -#define MMU_INT_STAT 0x200c - /* AS_COMMAND register commands */ -#define MMU_BASE 0x2400 +#define MMU_AS_BASE 0x2400 + #define MMU_AS_SHIFT 6 -#define MMU_AS(as) (MMU_BASE + ((as) << MMU_AS_SHIFT)) +#define MMU_AS(as) ((as) << MMU_AS_SHIFT) #define AS_TRANSTAB(as) (MMU_AS(as) + 0x0) #define AS_MEMATTR(as) (MMU_AS(as) + 0x8) From 002ef4dc52dcc1dd0eb1556cffa8f02e2e7edd51 Mon Sep 17 00:00:00 2001 From: Ethan Tidmore Date: Tue, 28 Apr 2026 22:08:40 -0500 Subject: [PATCH 073/145] drm/bridge: analogix_dp: Extract error pointer from correct variable In devm_drm_panel_bridge_add() error path the pointer error should be extracted from dp->plat_data->next_bridge but instead it is extracted from bridge, which is a valid pointer and not part of this error path. Extract error pointer from correct variable. Detected by Smatch: drivers/gpu/drm/bridge/analogix/analogix_dp_core.c:1489 analogix_dp_bind() warn: passing a valid pointer to 'PTR_ERR' Fixes: 1b86a69b61df4 ("drm/bridge: analogix_dp: Apply panel_bridge helper") Signed-off-by: Ethan Tidmore Reviewed-by: Luca Ceresoli Reviewed-by: Damon Ding Link: https://patch.msgid.link/20260429030840.704252-1-ethantidmore06@gmail.com [Luca: add lkp report lines] Reported-by: kernel test robot Closes: https://lore.kernel.org/oe-kbuild-all/202605032334.MuQfn1mP-lkp@intel.com/ Signed-off-by: Luca Ceresoli --- drivers/gpu/drm/bridge/analogix/analogix_dp_core.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/gpu/drm/bridge/analogix/analogix_dp_core.c b/drivers/gpu/drm/bridge/analogix/analogix_dp_core.c index 460729fdcecd..3e46350170d4 100644 --- a/drivers/gpu/drm/bridge/analogix/analogix_dp_core.c +++ b/drivers/gpu/drm/bridge/analogix/analogix_dp_core.c @@ -1486,7 +1486,7 @@ int analogix_dp_bind(struct analogix_dp_device *dp, struct drm_device *drm_dev) dp->plat_data->next_bridge = devm_drm_panel_bridge_add(dp->dev, dp->plat_data->panel); if (IS_ERR(dp->plat_data->next_bridge)) { - ret = PTR_ERR(bridge); + ret = PTR_ERR(dp->plat_data->next_bridge); goto err_unregister_aux; } } From 528578941a240e0916942bbb5b910c57bbfb3614 Mon Sep 17 00:00:00 2001 From: Arnd Bergmann Date: Wed, 29 Apr 2026 16:00:11 +0200 Subject: [PATCH 074/145] drm/ipv3: add CONFIG_OF dependency for DRM_OF_DISPLAY_MODE_BRIDGE Without this, not all dependencies are met here. Depends on [n]: HAS_IOMEM [=y] && DRM [=y] && DRM_BRIDGE [=y] && OF [=n] Selected by [y]: - DRM_IMX_PARALLEL_DISPLAY [=y] && HAS_IOMEM [=y] && DRM [=y] && DRM_IMX [=y] - DRM_IMX_LDB [=y] && HAS_IOMEM [=y] && DRM [=y] && DRM_IMX [=y] && COMMON_CLK [=y] Fixes: ba2db93cf3d5 ("drm/bridge: Move legacy bridge driver out of imx directory for multi-platform use") Signed-off-by: Arnd Bergmann Reviewed-by: Luca Ceresoli Reviewed-by: Damon Ding Link: https://patch.msgid.link/20260429140024.192432-1-arnd@kernel.org Signed-off-by: Luca Ceresoli --- drivers/gpu/drm/imx/ipuv3/Kconfig | 2 ++ 1 file changed, 2 insertions(+) diff --git a/drivers/gpu/drm/imx/ipuv3/Kconfig b/drivers/gpu/drm/imx/ipuv3/Kconfig index 351dc65913eb..3ca237515e46 100644 --- a/drivers/gpu/drm/imx/ipuv3/Kconfig +++ b/drivers/gpu/drm/imx/ipuv3/Kconfig @@ -13,6 +13,7 @@ config DRM_IMX config DRM_IMX_PARALLEL_DISPLAY tristate "Support for parallel displays" depends on DRM_IMX + depends on OF select DRM_BRIDGE select DRM_BRIDGE_CONNECTOR select DRM_DISPLAY_HELPER @@ -33,6 +34,7 @@ config DRM_IMX_LDB tristate "Support for LVDS displays" depends on DRM_IMX depends on COMMON_CLK + depends on OF select MFD_SYSCON select DRM_BRIDGE select DRM_BRIDGE_CONNECTOR From 55a412e3a78104036bbb1036e2ebe8fa4fb41770 Mon Sep 17 00:00:00 2001 From: Luca Ceresoli Date: Thu, 16 Apr 2026 15:59:55 +0200 Subject: [PATCH 075/145] drm/bridge: ti-sn65dsi83: add test pattern generation support Generation of a test pattern output is a useful tool for panel bringup and debugging, and very simple to support with this chip. The value of REG_VID_CHA_ACTIVE_LINE_LENGTH_LOW needs to be divided by two for the test pattern to work in dual LVDS mode. While not clearly stated in the datasheet, this is needed according to the DSI Tuner [0] output. And some dual-LVDS panels refuse to show any picture without this division by two. [0] https://www.ti.com/tool/DSI-TUNER Reviewed-by: Louis Chauvet Link: https://patch.msgid.link/20260416-ti-sn65dsi83-dual-lvds-fixes-and-test-pattern-v3-1-143886aebc6b@bootlin.com Signed-off-by: Luca Ceresoli --- drivers/gpu/drm/bridge/ti-sn65dsi83.c | 14 ++++++++++++-- 1 file changed, 12 insertions(+), 2 deletions(-) diff --git a/drivers/gpu/drm/bridge/ti-sn65dsi83.c b/drivers/gpu/drm/bridge/ti-sn65dsi83.c index 17a885244e1e..2b6f6a54edb7 100644 --- a/drivers/gpu/drm/bridge/ti-sn65dsi83.c +++ b/drivers/gpu/drm/bridge/ti-sn65dsi83.c @@ -114,6 +114,7 @@ #define REG_VID_CHA_HORIZONTAL_FRONT_PORCH 0x38 #define REG_VID_CHA_VERTICAL_FRONT_PORCH 0x3a #define REG_VID_CHA_TEST_PATTERN 0x3c +#define REG_VID_CHA_TEST_PATTERN_EN BIT(4) /* IRQ registers */ #define REG_IRQ_GLOBAL 0xe0 #define REG_IRQ_GLOBAL_IRQ_EN BIT(0) @@ -134,6 +135,9 @@ #define REG_IRQ_STAT_CHA_SOT_BIT_ERR BIT(2) #define REG_IRQ_STAT_CHA_PLL_UNLOCK BIT(0) +static bool sn65dsi83_test_pattern; +module_param_named(test_pattern, sn65dsi83_test_pattern, bool, 0644); + enum sn65dsi83_channel { CHANNEL_A, CHANNEL_B @@ -523,6 +527,7 @@ static void sn65dsi83_atomic_pre_enable(struct drm_bridge *bridge, const struct drm_display_mode *mode; struct drm_connector *connector; struct drm_crtc *crtc; + bool test_pattern = sn65dsi83_test_pattern; bool lvds_format_24bpp; bool lvds_format_jeida; unsigned int pval; @@ -645,7 +650,11 @@ static void sn65dsi83_atomic_pre_enable(struct drm_bridge *bridge, REG_LVDS_LANE_CHB_LVDS_TERM : 0)); regmap_write(ctx->regmap, REG_LVDS_CM, 0x00); - le16val = cpu_to_le16(mode->hdisplay); + /* + * Active line length needs to be halved for test pattern + * generation in dual LVDS output. + */ + le16val = cpu_to_le16(mode->hdisplay / (test_pattern ? dual_factor : 1)); regmap_bulk_write(ctx->regmap, REG_VID_CHA_ACTIVE_LINE_LENGTH_LOW, &le16val, 2); le16val = cpu_to_le16(mode->vdisplay); @@ -668,7 +677,8 @@ static void sn65dsi83_atomic_pre_enable(struct drm_bridge *bridge, (mode->hsync_start - mode->hdisplay) / dual_factor); regmap_write(ctx->regmap, REG_VID_CHA_VERTICAL_FRONT_PORCH, mode->vsync_start - mode->vdisplay); - regmap_write(ctx->regmap, REG_VID_CHA_TEST_PATTERN, 0x00); + regmap_write(ctx->regmap, REG_VID_CHA_TEST_PATTERN, + test_pattern ? REG_VID_CHA_TEST_PATTERN_EN : 0); /* Enable PLL */ regmap_write(ctx->regmap, REG_RC_PLL_EN, REG_RC_PLL_EN_PLL_EN); From 9a56caf49525e8a0ee349fb69db101d018a95a66 Mon Sep 17 00:00:00 2001 From: Max Krummenacher Date: Mon, 28 Jul 2025 17:00:50 +0200 Subject: [PATCH 076/145] drm/bridge: lontium-lt8912b: Do not generate HFP The datasheet of lontium-lt8912b doesn't require blanking during the HFP period. Thus use LP during HFP. Tested with a samsung-dsim (i.MX8 MM) and a tc358768 DPI to DSI bridge as the DSI host. Signed-off-by: Max Krummenacher Reviewed-by: Luca Ceresoli Link: https://patch.msgid.link/20250728150059.2642055-1-max.oss.09@gmail.com Signed-off-by: Luca Ceresoli --- drivers/gpu/drm/bridge/lontium-lt8912b.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/gpu/drm/bridge/lontium-lt8912b.c b/drivers/gpu/drm/bridge/lontium-lt8912b.c index 8a0b48efca58..729b12b67470 100644 --- a/drivers/gpu/drm/bridge/lontium-lt8912b.c +++ b/drivers/gpu/drm/bridge/lontium-lt8912b.c @@ -493,6 +493,7 @@ static int lt8912_attach_dsi(struct lt8912 *lt) dsi->mode_flags = MIPI_DSI_MODE_VIDEO | MIPI_DSI_MODE_LPM | + MIPI_DSI_MODE_VIDEO_NO_HFP | MIPI_DSI_MODE_NO_EOT_PACKET; ret = devm_mipi_dsi_attach(dev, dsi); From 2c23455d5aaa10eff69aa75200d5177e84640189 Mon Sep 17 00:00:00 2001 From: Icenowy Zheng Date: Tue, 31 Mar 2026 14:01:23 +0800 Subject: [PATCH 077/145] drm: verisilicon: make vs_format conversion function return int This is for further proper invalid drm_format handling before committing the plane state change. The return value is not yet checked yet, and will be checked in atomic_check in the future. Signed-off-by: Icenowy Zheng Reviewed-by: Thomas Zimmermann Signed-off-by: Thomas Zimmermann Link: https://patch.msgid.link/20260331060126.1291966-2-zhengxingda@iscas.ac.cn --- drivers/gpu/drm/verisilicon/vs_plane.c | 6 ++++-- drivers/gpu/drm/verisilicon/vs_plane.h | 2 +- 2 files changed, 5 insertions(+), 3 deletions(-) diff --git a/drivers/gpu/drm/verisilicon/vs_plane.c b/drivers/gpu/drm/verisilicon/vs_plane.c index 2f3953e588a3..fa88ed14e41d 100644 --- a/drivers/gpu/drm/verisilicon/vs_plane.c +++ b/drivers/gpu/drm/verisilicon/vs_plane.c @@ -12,7 +12,7 @@ #include "vs_plane.h" -void drm_format_to_vs_format(u32 drm_format, struct vs_format *vs_format) +int drm_format_to_vs_format(u32 drm_format, struct vs_format *vs_format) { switch (drm_format) { case DRM_FORMAT_XRGB4444: @@ -62,7 +62,7 @@ void drm_format_to_vs_format(u32 drm_format, struct vs_format *vs_format) vs_format->color = VSDC_COLOR_FORMAT_A2R10G10B10; break; default: - pr_warn("Unexpected drm format!\n"); + return -EINVAL; } switch (drm_format) { @@ -101,6 +101,8 @@ void drm_format_to_vs_format(u32 drm_format, struct vs_format *vs_format) /* N/A for non-YUV formats */ vs_format->uv_swizzle = false; + + return 0; } dma_addr_t vs_fb_get_dma_addr(struct drm_framebuffer *fb, diff --git a/drivers/gpu/drm/verisilicon/vs_plane.h b/drivers/gpu/drm/verisilicon/vs_plane.h index 41875ea3d66a..a88cc19f2202 100644 --- a/drivers/gpu/drm/verisilicon/vs_plane.h +++ b/drivers/gpu/drm/verisilicon/vs_plane.h @@ -63,7 +63,7 @@ struct vs_format { bool uv_swizzle; }; -void drm_format_to_vs_format(u32 drm_format, struct vs_format *vs_format); +int drm_format_to_vs_format(u32 drm_format, struct vs_format *vs_format); dma_addr_t vs_fb_get_dma_addr(struct drm_framebuffer *fb, const struct drm_rect *src_rect); From 1a2e37548077640262489c4e96dc8df877452e20 Mon Sep 17 00:00:00 2001 From: Icenowy Zheng Date: Tue, 31 Mar 2026 14:01:24 +0800 Subject: [PATCH 078/145] drm: verisilicon: subclass drm_plane_state Create a subclass of drm_plane_state to store hardware-specific state information (e.g. hardware plane format settings) in the future. Signed-off-by: Icenowy Zheng Reviewed-by: Thomas Zimmermann Signed-off-by: Thomas Zimmermann Link: https://patch.msgid.link/20260331060126.1291966-3-zhengxingda@iscas.ac.cn --- drivers/gpu/drm/verisilicon/vs_plane.c | 43 +++++++++++++++++++ drivers/gpu/drm/verisilicon/vs_plane.h | 14 ++++++ .../gpu/drm/verisilicon/vs_primary_plane.c | 6 +-- 3 files changed, 60 insertions(+), 3 deletions(-) diff --git a/drivers/gpu/drm/verisilicon/vs_plane.c b/drivers/gpu/drm/verisilicon/vs_plane.c index fa88ed14e41d..7c6b905c9e1f 100644 --- a/drivers/gpu/drm/verisilicon/vs_plane.c +++ b/drivers/gpu/drm/verisilicon/vs_plane.c @@ -6,9 +6,11 @@ #include #include +#include #include #include #include +#include #include "vs_plane.h" @@ -124,3 +126,44 @@ dma_addr_t vs_fb_get_dma_addr(struct drm_framebuffer *fb, return dma_addr; } + +struct drm_plane_state *vs_plane_duplicate_state(struct drm_plane *plane) +{ + struct vs_plane_state *vs_state; + + if (drm_WARN_ON(plane->dev, !plane->state)) + return NULL; + + vs_state = kzalloc_obj(*vs_state, GFP_KERNEL); + if (!vs_state) + return NULL; + + __drm_atomic_helper_plane_duplicate_state(plane, &vs_state->base); + + return &vs_state->base; +} + +void vs_plane_destroy_state(struct drm_plane *plane, + struct drm_plane_state *state) +{ + __drm_atomic_helper_plane_destroy_state(state); + kfree(state); +} + +/* Called during init to allocate the plane's atomic state. */ +void vs_plane_reset(struct drm_plane *plane) +{ + struct vs_plane_state *vs_state; + + if (plane->state) { + __drm_atomic_helper_plane_destroy_state(plane->state); + kfree(plane->state); + plane->state = NULL; + } + + vs_state = kzalloc_obj(*vs_state, GFP_KERNEL); + if (!vs_state) + return; + + __drm_atomic_helper_plane_reset(plane, &vs_state->base); +} diff --git a/drivers/gpu/drm/verisilicon/vs_plane.h b/drivers/gpu/drm/verisilicon/vs_plane.h index a88cc19f2202..48ed8fc754d1 100644 --- a/drivers/gpu/drm/verisilicon/vs_plane.h +++ b/drivers/gpu/drm/verisilicon/vs_plane.h @@ -63,10 +63,24 @@ struct vs_format { bool uv_swizzle; }; +struct vs_plane_state { + struct drm_plane_state base; +}; + +static inline struct vs_plane_state *to_vs_plane_state(struct drm_plane_state *state) +{ + return container_of(state, struct vs_plane_state, base); +} + int drm_format_to_vs_format(u32 drm_format, struct vs_format *vs_format); dma_addr_t vs_fb_get_dma_addr(struct drm_framebuffer *fb, const struct drm_rect *src_rect); +struct drm_plane_state *vs_plane_duplicate_state(struct drm_plane *plane); +void vs_plane_destroy_state(struct drm_plane *plane, + struct drm_plane_state *state); +void vs_plane_reset(struct drm_plane *plane); + struct drm_plane *vs_primary_plane_init(struct drm_device *dev, struct vs_dc *dc); #endif /* _VS_PLANE_H_ */ diff --git a/drivers/gpu/drm/verisilicon/vs_primary_plane.c b/drivers/gpu/drm/verisilicon/vs_primary_plane.c index e8fcb5958615..bad0bc5e3242 100644 --- a/drivers/gpu/drm/verisilicon/vs_primary_plane.c +++ b/drivers/gpu/drm/verisilicon/vs_primary_plane.c @@ -145,10 +145,10 @@ static const struct drm_plane_helper_funcs vs_primary_plane_helper_funcs = { }; static const struct drm_plane_funcs vs_primary_plane_funcs = { - .atomic_destroy_state = drm_atomic_helper_plane_destroy_state, - .atomic_duplicate_state = drm_atomic_helper_plane_duplicate_state, + .atomic_destroy_state = vs_plane_destroy_state, + .atomic_duplicate_state = vs_plane_duplicate_state, .disable_plane = drm_atomic_helper_disable_plane, - .reset = drm_atomic_helper_plane_reset, + .reset = vs_plane_reset, .update_plane = drm_atomic_helper_update_plane, }; From eae3903e33797a28d0d37e693d4314d58338918e Mon Sep 17 00:00:00 2001 From: Icenowy Zheng Date: Tue, 31 Mar 2026 14:01:25 +0800 Subject: [PATCH 079/145] drm: verisilicon: call atomic helper's plane state check even if no CRTC The `drm_atomic_helper_check_plane_state()` helper function needs to be called even if the plane is bound to no CRTCs. Remove the early return in the primary plane's atomic_check, and use NULL for crtc_state in this situation. Fixes: dbf21777caa8 ("drm: verisilicon: add a driver for Verisilicon display controllers") Signed-off-by: Icenowy Zheng Reviewed-by: Thomas Zimmermann Signed-off-by: Thomas Zimmermann Link: https://patch.msgid.link/20260331060126.1291966-4-zhengxingda@iscas.ac.cn --- drivers/gpu/drm/verisilicon/vs_primary_plane.c | 10 +++------- 1 file changed, 3 insertions(+), 7 deletions(-) diff --git a/drivers/gpu/drm/verisilicon/vs_primary_plane.c b/drivers/gpu/drm/verisilicon/vs_primary_plane.c index bad0bc5e3242..421d6f9dc547 100644 --- a/drivers/gpu/drm/verisilicon/vs_primary_plane.c +++ b/drivers/gpu/drm/verisilicon/vs_primary_plane.c @@ -26,14 +26,10 @@ static int vs_primary_plane_atomic_check(struct drm_plane *plane, struct drm_plane_state *new_plane_state = drm_atomic_get_new_plane_state(state, plane); struct drm_crtc *crtc = new_plane_state->crtc; - struct drm_crtc_state *crtc_state; + struct drm_crtc_state *crtc_state = NULL; - if (!crtc) - return 0; - - crtc_state = drm_atomic_get_new_crtc_state(state, crtc); - if (WARN_ON(!crtc_state)) - return -EINVAL; + if (crtc) + crtc_state = drm_atomic_get_new_crtc_state(state, crtc); return drm_atomic_helper_check_plane_state(new_plane_state, crtc_state, From c0d650bd0e67048dba04cdc21e8d77aef1ff0d5f Mon Sep 17 00:00:00 2001 From: Icenowy Zheng Date: Tue, 31 Mar 2026 14:01:26 +0800 Subject: [PATCH 080/145] drm: verisilicon: fill plane's vs_format in atomic_check Move the conversion from drm_format to vs_format to atomic_check, which is before the point of no return and can properly bail out. Signed-off-by: Icenowy Zheng Reviewed-by: Thomas Zimmermann Signed-off-by: Thomas Zimmermann Link: https://patch.msgid.link/20260331060126.1291966-5-zhengxingda@iscas.ac.cn --- drivers/gpu/drm/verisilicon/vs_plane.c | 7 +++- drivers/gpu/drm/verisilicon/vs_plane.h | 2 ++ .../gpu/drm/verisilicon/vs_primary_plane.c | 36 +++++++++++++------ 3 files changed, 33 insertions(+), 12 deletions(-) diff --git a/drivers/gpu/drm/verisilicon/vs_plane.c b/drivers/gpu/drm/verisilicon/vs_plane.c index 7c6b905c9e1f..d81f7b8f4c65 100644 --- a/drivers/gpu/drm/verisilicon/vs_plane.c +++ b/drivers/gpu/drm/verisilicon/vs_plane.c @@ -129,17 +129,22 @@ dma_addr_t vs_fb_get_dma_addr(struct drm_framebuffer *fb, struct drm_plane_state *vs_plane_duplicate_state(struct drm_plane *plane) { - struct vs_plane_state *vs_state; + struct vs_plane_state *vs_state, *vs_state_old; if (drm_WARN_ON(plane->dev, !plane->state)) return NULL; + vs_state_old = to_vs_plane_state(plane->state); + vs_state = kzalloc_obj(*vs_state, GFP_KERNEL); if (!vs_state) return NULL; __drm_atomic_helper_plane_duplicate_state(plane, &vs_state->base); + memcpy(&vs_state->format, &vs_state_old->format, + sizeof(struct vs_format)); + return &vs_state->base; } diff --git a/drivers/gpu/drm/verisilicon/vs_plane.h b/drivers/gpu/drm/verisilicon/vs_plane.h index 48ed8fc754d1..f18c36ef4cd9 100644 --- a/drivers/gpu/drm/verisilicon/vs_plane.h +++ b/drivers/gpu/drm/verisilicon/vs_plane.h @@ -65,6 +65,8 @@ struct vs_format { struct vs_plane_state { struct drm_plane_state base; + + struct vs_format format; }; static inline struct vs_plane_state *to_vs_plane_state(struct drm_plane_state *state) diff --git a/drivers/gpu/drm/verisilicon/vs_primary_plane.c b/drivers/gpu/drm/verisilicon/vs_primary_plane.c index 421d6f9dc547..3576dd524f5c 100644 --- a/drivers/gpu/drm/verisilicon/vs_primary_plane.c +++ b/drivers/gpu/drm/verisilicon/vs_primary_plane.c @@ -25,17 +25,32 @@ static int vs_primary_plane_atomic_check(struct drm_plane *plane, { struct drm_plane_state *new_plane_state = drm_atomic_get_new_plane_state(state, plane); + struct vs_plane_state *new_vs_plane_state = to_vs_plane_state(new_plane_state); + struct drm_framebuffer *fb = new_plane_state->fb; struct drm_crtc *crtc = new_plane_state->crtc; struct drm_crtc_state *crtc_state = NULL; + int ret; if (crtc) crtc_state = drm_atomic_get_new_crtc_state(state, crtc); - return drm_atomic_helper_check_plane_state(new_plane_state, - crtc_state, - DRM_PLANE_NO_SCALING, - DRM_PLANE_NO_SCALING, - false, true); + ret = drm_atomic_helper_check_plane_state(new_plane_state, + crtc_state, + DRM_PLANE_NO_SCALING, + DRM_PLANE_NO_SCALING, + false, true); + if (ret) + return ret; + + if (!new_plane_state->visible) + return 0; + + ret = drm_format_to_vs_format(fb->format->format, + &new_vs_plane_state->format); + if (drm_WARN_ON_ONCE(plane->dev, ret)) + return ret; + + return 0; } static void vs_primary_plane_commit(struct vs_dc *dc, unsigned int output) @@ -84,11 +99,11 @@ static void vs_primary_plane_atomic_update(struct drm_plane *plane, { struct drm_plane_state *state = drm_atomic_get_new_plane_state(atomic_state, plane); + struct vs_plane_state *vs_state = to_vs_plane_state(state); struct drm_framebuffer *fb = state->fb; struct drm_crtc *crtc = state->crtc; struct vs_dc *dc; struct vs_crtc *vcrtc; - struct vs_format fmt; unsigned int output; dma_addr_t dma_addr; @@ -101,16 +116,15 @@ static void vs_primary_plane_atomic_update(struct drm_plane *plane, output = vcrtc->id; dc = vcrtc->dc; - drm_format_to_vs_format(state->fb->format->format, &fmt); - regmap_update_bits(dc->regs, VSDC_FB_CONFIG(output), VSDC_FB_CONFIG_FMT_MASK, - VSDC_FB_CONFIG_FMT(fmt.color)); + VSDC_FB_CONFIG_FMT(vs_state->format.color)); regmap_update_bits(dc->regs, VSDC_FB_CONFIG(output), VSDC_FB_CONFIG_SWIZZLE_MASK, - VSDC_FB_CONFIG_SWIZZLE(fmt.swizzle)); + VSDC_FB_CONFIG_SWIZZLE(vs_state->format.swizzle)); regmap_assign_bits(dc->regs, VSDC_FB_CONFIG(output), - VSDC_FB_CONFIG_UV_SWIZZLE_EN, fmt.uv_swizzle); + VSDC_FB_CONFIG_UV_SWIZZLE_EN, + vs_state->format.uv_swizzle); dma_addr = vs_fb_get_dma_addr(fb, &state->src); From 83ae9a231dadbe2b0686786344a692d0b598953a Mon Sep 17 00:00:00 2001 From: Thomas Zimmermann Date: Mon, 27 Apr 2026 17:00:38 +0200 Subject: [PATCH 081/145] drm/vmwgfx: Determine lock-waiting timeout from vblank state Use the calculated duration of a frame as stored in the vblank state for the lock-waiting timeout. Decouples the waiting from the details of the vblank implementation. Both values should be equal. This will be helpful for replacing vmwgfx's vblank timer with DRM's common implementation. Signed-off-by: Thomas Zimmermann Reviewed-by: Zack Rusin Link: https://patch.msgid.link/20260427150250.699768-2-tzimmermann@suse.de --- drivers/gpu/drm/vmwgfx/vmwgfx_vkms.c | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/drivers/gpu/drm/vmwgfx/vmwgfx_vkms.c b/drivers/gpu/drm/vmwgfx/vmwgfx_vkms.c index 5abd7f5ad2db..7862f6972512 100644 --- a/drivers/gpu/drm/vmwgfx/vmwgfx_vkms.c +++ b/drivers/gpu/drm/vmwgfx/vmwgfx_vkms.c @@ -516,9 +516,13 @@ vmw_vkms_set_crc_surface(struct drm_crtc *crtc, static inline u64 vmw_vkms_lock_max_wait_ns(struct vmw_display_unit *du) { - s64 nsecs = ktime_to_ns(du->vkms.period_ns); + struct drm_crtc *crtc = &du->crtc; + struct drm_vblank_crtc *vblank = drm_crtc_vblank_crtc(crtc); - return (nsecs > 0) ? nsecs : 16666666; + if (!vblank || !vblank->framedur_ns) + return NSEC_PER_SEC / 60; /* disabled; assume 60 Hz */ + + return vblank->framedur_ns; } /** From 5c6113e07af73046ef32ac0acc9cdc15fb62c4da Mon Sep 17 00:00:00 2001 From: Thomas Zimmermann Date: Mon, 27 Apr 2026 17:00:39 +0200 Subject: [PATCH 082/145] drm/vmwgfx: Move vblank handling into separate helper Decouple vblank handling from the underlying hrtimer. This will be helpful for replacing vmwgfx's vblank timer with DRM's common implementation. The new helper vmw_vkms_handle_vblank_timeout() can later be used as callback for DRM's handle_vblank call as-is. The helper also keeps the current semantics for restarting the timer. It returns true to restart the next vblank timeout even if it could not acquire vmwgfx's vblank lock. The remaining code in vmw_vkms_vblank_simulate() will be replaced by the DRM implementation in a later patch. v2: - clarify return-value semantics in commit message (Zack) Signed-off-by: Thomas Zimmermann Reviewed-by: Zack Rusin Link: https://patch.msgid.link/20260427150250.699768-3-tzimmermann@suse.de --- drivers/gpu/drm/vmwgfx/vmwgfx_vkms.c | 37 +++++++++++++++++++--------- drivers/gpu/drm/vmwgfx/vmwgfx_vkms.h | 1 + 2 files changed, 26 insertions(+), 12 deletions(-) diff --git a/drivers/gpu/drm/vmwgfx/vmwgfx_vkms.c b/drivers/gpu/drm/vmwgfx/vmwgfx_vkms.c index 7862f6972512..15439ddd4f22 100644 --- a/drivers/gpu/drm/vmwgfx/vmwgfx_vkms.c +++ b/drivers/gpu/drm/vmwgfx/vmwgfx_vkms.c @@ -157,27 +157,19 @@ crc_generate_worker(struct work_struct *work) drm_crtc_add_crc_entry(crtc, true, frame_start++, &crc32); } -static enum hrtimer_restart -vmw_vkms_vblank_simulate(struct hrtimer *timer) +bool +vmw_vkms_handle_vblank_timeout(struct drm_crtc *crtc) { - struct vmw_display_unit *du = container_of(timer, struct vmw_display_unit, vkms.timer); - struct drm_crtc *crtc = &du->crtc; + struct vmw_display_unit *du = vmw_crtc_to_du(crtc); struct vmw_private *vmw = vmw_priv(crtc->dev); bool has_surface = false; - u64 ret_overrun; bool locked, ret; - ret_overrun = hrtimer_forward_now(&du->vkms.timer, - du->vkms.period_ns); - if (ret_overrun != 1) - drm_dbg_driver(crtc->dev, "vblank timer missed %lld frames.\n", - ret_overrun - 1); - locked = vmw_vkms_vblank_trylock(crtc); ret = drm_crtc_handle_vblank(crtc); WARN_ON(!ret); if (!locked) - return HRTIMER_RESTART; + return true; has_surface = du->vkms.surface != NULL; vmw_vkms_unlock(crtc); @@ -200,6 +192,27 @@ vmw_vkms_vblank_simulate(struct hrtimer *timer) drm_dbg_driver(crtc->dev, "Composer worker already queued\n"); } + return true; +} + +static enum hrtimer_restart +vmw_vkms_vblank_simulate(struct hrtimer *timer) +{ + struct vmw_display_unit *du = container_of(timer, struct vmw_display_unit, vkms.timer); + struct drm_crtc *crtc = &du->crtc; + u64 ret_overrun; + bool success; + + ret_overrun = hrtimer_forward_now(&du->vkms.timer, + du->vkms.period_ns); + if (ret_overrun != 1) + drm_dbg_driver(crtc->dev, "vblank timer missed %lld frames.\n", + ret_overrun - 1); + + success = vmw_vkms_handle_vblank_timeout(crtc); + if (!success) + return HRTIMER_NORESTART; + return HRTIMER_RESTART; } diff --git a/drivers/gpu/drm/vmwgfx/vmwgfx_vkms.h b/drivers/gpu/drm/vmwgfx/vmwgfx_vkms.h index 69ddd33a8444..0b6bbf7c4487 100644 --- a/drivers/gpu/drm/vmwgfx/vmwgfx_vkms.h +++ b/drivers/gpu/drm/vmwgfx/vmwgfx_vkms.h @@ -45,6 +45,7 @@ bool vmw_vkms_modeset_lock_relaxed(struct drm_crtc *crtc); bool vmw_vkms_vblank_trylock(struct drm_crtc *crtc); void vmw_vkms_unlock(struct drm_crtc *crtc); +bool vmw_vkms_handle_vblank_timeout(struct drm_crtc *crtc); bool vmw_vkms_get_vblank_timestamp(struct drm_crtc *crtc, int *max_error, ktime_t *vblank_time, From 659e7e0f3db552b41f765c230aed7ac05e9d12a6 Mon Sep 17 00:00:00 2001 From: Thomas Zimmermann Date: Mon, 27 Apr 2026 17:00:40 +0200 Subject: [PATCH 083/145] drm/vmwgfx: Convert to DRM vblank timers Replace vmwgfx's vblank timer with DRM's common implementation. The timer handling is almost identical with a few additional bug fixes in the common code. Replace most of vmwgfx's vmw_vkms_get_vblank_timestamp() with the shared helper drm_crtc_vblank_get_vblank_timeout(). The common helper also works in the presence of delayed vblank timeouts that modify the vblank counter concurrently. Set the timeout handler to vmw_vkms_handle_vblank_timeout(). In addition to handling vblank events, this function also controls CRC generation. Remove all the hrtimer-related code from vmwgfx. DRM vblank timers provides this. v2: - only cancel vblank timer in CRTC cleanup if vkms_enabled (Zack) Signed-off-by: Thomas Zimmermann Reviewed-by: Zack Rusin Link: https://patch.msgid.link/20260427150250.699768-4-tzimmermann@suse.de --- drivers/gpu/drm/vmwgfx/vmwgfx_kms.h | 2 - drivers/gpu/drm/vmwgfx/vmwgfx_ldu.c | 1 + drivers/gpu/drm/vmwgfx/vmwgfx_scrn.c | 1 + drivers/gpu/drm/vmwgfx/vmwgfx_stdu.c | 1 + drivers/gpu/drm/vmwgfx/vmwgfx_vkms.c | 65 ++++------------------------ drivers/gpu/drm/vmwgfx/vmwgfx_vkms.h | 1 - 6 files changed, 12 insertions(+), 59 deletions(-) diff --git a/drivers/gpu/drm/vmwgfx/vmwgfx_kms.h b/drivers/gpu/drm/vmwgfx/vmwgfx_kms.h index 445471fe9be6..b5670ece90a9 100644 --- a/drivers/gpu/drm/vmwgfx/vmwgfx_kms.h +++ b/drivers/gpu/drm/vmwgfx/vmwgfx_kms.h @@ -322,8 +322,6 @@ struct vmw_display_unit { struct { struct work_struct crc_generator_work; - struct hrtimer timer; - ktime_t period_ns; /* protects concurrent access to the vblank handler */ atomic_t atomic_lock; diff --git a/drivers/gpu/drm/vmwgfx/vmwgfx_ldu.c b/drivers/gpu/drm/vmwgfx/vmwgfx_ldu.c index f07669b27fba..6f22d5f5c379 100644 --- a/drivers/gpu/drm/vmwgfx/vmwgfx_ldu.c +++ b/drivers/gpu/drm/vmwgfx/vmwgfx_ldu.c @@ -402,6 +402,7 @@ static const struct drm_crtc_helper_funcs vmw_ldu_crtc_helper_funcs = { .atomic_flush = vmw_vkms_crtc_atomic_flush, .atomic_enable = vmw_vkms_crtc_atomic_enable, .atomic_disable = vmw_vkms_crtc_atomic_disable, + .handle_vblank_timeout = vmw_vkms_handle_vblank_timeout, }; diff --git a/drivers/gpu/drm/vmwgfx/vmwgfx_scrn.c b/drivers/gpu/drm/vmwgfx/vmwgfx_scrn.c index 605d037d18c6..cfb8ad3ebe43 100644 --- a/drivers/gpu/drm/vmwgfx/vmwgfx_scrn.c +++ b/drivers/gpu/drm/vmwgfx/vmwgfx_scrn.c @@ -797,6 +797,7 @@ static const struct drm_crtc_helper_funcs vmw_sou_crtc_helper_funcs = { .atomic_flush = vmw_vkms_crtc_atomic_flush, .atomic_enable = vmw_vkms_crtc_atomic_enable, .atomic_disable = vmw_sou_crtc_atomic_disable, + .handle_vblank_timeout = vmw_vkms_handle_vblank_timeout, }; diff --git a/drivers/gpu/drm/vmwgfx/vmwgfx_stdu.c b/drivers/gpu/drm/vmwgfx/vmwgfx_stdu.c index dcbacee97f61..1f5497e2638a 100644 --- a/drivers/gpu/drm/vmwgfx/vmwgfx_stdu.c +++ b/drivers/gpu/drm/vmwgfx/vmwgfx_stdu.c @@ -1515,6 +1515,7 @@ static const struct drm_crtc_helper_funcs vmw_stdu_crtc_helper_funcs = { .atomic_flush = vmw_stdu_crtc_atomic_flush, .atomic_enable = vmw_vkms_crtc_atomic_enable, .atomic_disable = vmw_stdu_crtc_atomic_disable, + .handle_vblank_timeout = vmw_vkms_handle_vblank_timeout, }; diff --git a/drivers/gpu/drm/vmwgfx/vmwgfx_vkms.c b/drivers/gpu/drm/vmwgfx/vmwgfx_vkms.c index 15439ddd4f22..1f98aa04c9f3 100644 --- a/drivers/gpu/drm/vmwgfx/vmwgfx_vkms.c +++ b/drivers/gpu/drm/vmwgfx/vmwgfx_vkms.c @@ -195,27 +195,6 @@ vmw_vkms_handle_vblank_timeout(struct drm_crtc *crtc) return true; } -static enum hrtimer_restart -vmw_vkms_vblank_simulate(struct hrtimer *timer) -{ - struct vmw_display_unit *du = container_of(timer, struct vmw_display_unit, vkms.timer); - struct drm_crtc *crtc = &du->crtc; - u64 ret_overrun; - bool success; - - ret_overrun = hrtimer_forward_now(&du->vkms.timer, - du->vkms.period_ns); - if (ret_overrun != 1) - drm_dbg_driver(crtc->dev, "vblank timer missed %lld frames.\n", - ret_overrun - 1); - - success = vmw_vkms_handle_vblank_timeout(crtc); - if (!success) - return HRTIMER_NORESTART; - - return HRTIMER_RESTART; -} - void vmw_vkms_init(struct vmw_private *vmw) { @@ -258,32 +237,12 @@ vmw_vkms_get_vblank_timestamp(struct drm_crtc *crtc, ktime_t *vblank_time, bool in_vblank_irq) { - struct drm_device *dev = crtc->dev; - struct vmw_private *vmw = vmw_priv(dev); - struct vmw_display_unit *du = vmw_crtc_to_du(crtc); - struct drm_vblank_crtc *vblank = drm_crtc_vblank_crtc(crtc); + struct vmw_private *vmw = vmw_priv(crtc->dev); if (!vmw->vkms_enabled) return false; - if (!READ_ONCE(vblank->enabled)) { - *vblank_time = ktime_get(); - return true; - } - - *vblank_time = READ_ONCE(du->vkms.timer.node.expires); - - if (WARN_ON(*vblank_time == vblank->time)) - return true; - - /* - * To prevent races we roll the hrtimer forward before we do any - * interrupt processing - this is how real hw works (the interrupt is - * only generated after all the vblank registers are updated) and what - * the vblank core expects. Therefore we need to always correct the - * timestampe by one frame. - */ - *vblank_time -= du->vkms.period_ns; + drm_crtc_vblank_get_vblank_timeout(crtc, vblank_time); return true; } @@ -293,20 +252,11 @@ vmw_vkms_enable_vblank(struct drm_crtc *crtc) { struct drm_device *dev = crtc->dev; struct vmw_private *vmw = vmw_priv(dev); - struct drm_vblank_crtc *vblank = drm_crtc_vblank_crtc(crtc); - struct vmw_display_unit *du = vmw_crtc_to_du(crtc); if (!vmw->vkms_enabled) return -EINVAL; - drm_calc_timestamping_constants(crtc, &crtc->mode); - - hrtimer_setup(&du->vkms.timer, &vmw_vkms_vblank_simulate, CLOCK_MONOTONIC, - HRTIMER_MODE_REL); - du->vkms.period_ns = ktime_set(0, vblank->framedur_ns); - hrtimer_start(&du->vkms.timer, du->vkms.period_ns, HRTIMER_MODE_REL); - - return 0; + return drm_crtc_vblank_start_timer(crtc); } void @@ -318,9 +268,9 @@ vmw_vkms_disable_vblank(struct drm_crtc *crtc) if (!vmw->vkms_enabled) return; - hrtimer_cancel(&du->vkms.timer); + drm_crtc_vblank_cancel_timer(crtc); + du->vkms.surface = NULL; - du->vkms.period_ns = ktime_set(0, 0); } enum vmw_vkms_lock_state { @@ -344,12 +294,15 @@ vmw_vkms_crtc_init(struct drm_crtc *crtc) void vmw_vkms_crtc_cleanup(struct drm_crtc *crtc) { + struct vmw_private *vmw = vmw_priv(crtc->dev); struct vmw_display_unit *du = vmw_crtc_to_du(crtc); + if (vmw->vkms_enabled) + drm_crtc_vblank_cancel_timer(crtc); + if (du->vkms.surface) vmw_surface_unreference(&du->vkms.surface); WARN_ON(work_pending(&du->vkms.crc_generator_work)); - hrtimer_cancel(&du->vkms.timer); } void diff --git a/drivers/gpu/drm/vmwgfx/vmwgfx_vkms.h b/drivers/gpu/drm/vmwgfx/vmwgfx_vkms.h index 0b6bbf7c4487..40c679f59db2 100644 --- a/drivers/gpu/drm/vmwgfx/vmwgfx_vkms.h +++ b/drivers/gpu/drm/vmwgfx/vmwgfx_vkms.h @@ -29,7 +29,6 @@ #ifndef VMWGFX_VKMS_H_ #define VMWGFX_VKMS_H_ -#include #include struct drm_atomic_state; From 5e5b64b6dc702c7bcd8da340263535128a3d5518 Mon Sep 17 00:00:00 2001 From: Eduardo Vasconcelos Date: Fri, 24 Apr 2026 15:36:29 -0300 Subject: [PATCH 084/145] drm/crc: Fix typo in doc for drm_crtc_crc Fix a typo in the documentation for struct drm_crtc_crc ("occured." -> "occurred"). Signed-off-by: Eduardo Vasconcelos Reviewed-by: Thomas Zimmermann Signed-off-by: Thomas Zimmermann Link: https://patch.msgid.link/20260424183630.3764-1-eduardo@eduardovasconcelos.com --- include/drm/drm_debugfs_crc.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/include/drm/drm_debugfs_crc.h b/include/drm/drm_debugfs_crc.h index 1b4c98c2f838..1cb71c03bf44 100644 --- a/include/drm/drm_debugfs_crc.h +++ b/include/drm/drm_debugfs_crc.h @@ -49,7 +49,7 @@ struct drm_crtc_crc_entry { * @lock: protects the fields in this struct * @source: name of the currently configured source of CRCs * @opened: whether userspace has opened the data file for reading - * @overflow: whether an overflow occured. + * @overflow: whether an overflow occurred * @entries: array of entries, with size of %DRM_CRC_ENTRIES_NR * @head: head of circular queue * @tail: tail of circular queue From 54068b05c85d75746034ef75721b240823cc872d Mon Sep 17 00:00:00 2001 From: Thomas Zimmermann Date: Wed, 8 Apr 2026 14:03:14 +0200 Subject: [PATCH 085/145] drm/sysfb: corebootdrm: Support power management Set PM ops for the corebootdrm driver. Suspend and resume the DRM state on systems that support it. Many systems lose the hardware's framebuffer settings on suspend, hence resuming doesn't work there. Yet some systems, most notably emulators, keep the hardware state across suspend/resume cycles. There, DRM's suspend and resume helpers bring back the display on resume. Signed-off-by: Thomas Zimmermann Reviewed-by: Javier Martinez Canillas Link: https://patch.msgid.link/20260408120722.328769-2-tzimmermann@suse.de --- drivers/gpu/drm/sysfb/corebootdrm.c | 21 +++++++++++++++++++++ 1 file changed, 21 insertions(+) diff --git a/drivers/gpu/drm/sysfb/corebootdrm.c b/drivers/gpu/drm/sysfb/corebootdrm.c index 5dc6f3c76f7b..853da9a609df 100644 --- a/drivers/gpu/drm/sysfb/corebootdrm.c +++ b/drivers/gpu/drm/sysfb/corebootdrm.c @@ -4,6 +4,7 @@ #include #include #include +#include #include #include @@ -18,6 +19,7 @@ #include #include #include +#include #include #include #include @@ -286,6 +288,24 @@ static struct drm_driver corebootdrm_drm_driver = { * Coreboot driver */ +static int corebootdrm_pm_suspend(struct device *dev) +{ + struct corebootdrm_device *cdev = dev_get_drvdata(dev); + struct drm_device *drm = &cdev->sysfb.dev; + + return drm_mode_config_helper_suspend(drm); +} + +static int corebootdrm_pm_resume(struct device *dev) +{ + struct corebootdrm_device *cdev = dev_get_drvdata(dev); + struct drm_device *drm = &cdev->sysfb.dev; + + return drm_mode_config_helper_resume(drm); +} + +static DEFINE_SIMPLE_DEV_PM_OPS(corebootdrm_pm_ops, corebootdrm_pm_suspend, corebootdrm_pm_resume); + static int corebootdrm_probe(struct platform_device *pdev) { const struct lb_framebuffer *fb = dev_get_platdata(&pdev->dev); @@ -423,6 +443,7 @@ static void corebootdrm_remove(struct platform_device *pdev) static struct platform_driver corebootdrm_platform_driver = { .driver = { .name = "coreboot-framebuffer", + .pm = pm_sleep_ptr(&corebootdrm_pm_ops), }, .probe = corebootdrm_probe, .remove = corebootdrm_remove, From 38699486318e5b6b423aabd35476c37580f2a0ec Mon Sep 17 00:00:00 2001 From: Thomas Zimmermann Date: Wed, 8 Apr 2026 14:03:15 +0200 Subject: [PATCH 086/145] drm/sysfb: efidrm: Support power management Set PM ops for the efidrm driver. Suspend and resume the DRM state on systems that support it. Many systems lose the hardware's framebuffer settings on suspend, hence resuming doesn't work there. Yet some systems, most notably emulators, keep the hardware state across suspend/resume cycles. There, DRM's suspend and resume helpers bring back the display on resume. Signed-off-by: Thomas Zimmermann Reviewed-by: Javier Martinez Canillas Link: https://patch.msgid.link/20260408120722.328769-3-tzimmermann@suse.de --- drivers/gpu/drm/sysfb/efidrm.c | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+) diff --git a/drivers/gpu/drm/sysfb/efidrm.c b/drivers/gpu/drm/sysfb/efidrm.c index a335c94a7bd7..1a1e36700976 100644 --- a/drivers/gpu/drm/sysfb/efidrm.c +++ b/drivers/gpu/drm/sysfb/efidrm.c @@ -5,6 +5,7 @@ #include #include #include +#include #include #include @@ -20,6 +21,7 @@ #include #include #include +#include #include #include #include @@ -371,6 +373,22 @@ static struct drm_driver efidrm_driver = { * Platform driver */ +static int efidrm_pm_suspend(struct device *dev) +{ + struct drm_device *drm = dev_get_drvdata(dev); + + return drm_mode_config_helper_suspend(drm); +} + +static int efidrm_pm_resume(struct device *dev) +{ + struct drm_device *drm = dev_get_drvdata(dev); + + return drm_mode_config_helper_resume(drm); +} + +static DEFINE_SIMPLE_DEV_PM_OPS(efidrm_pm_ops, efidrm_pm_suspend, efidrm_pm_resume); + static int efidrm_probe(struct platform_device *pdev) { struct efidrm_device *efi; @@ -403,6 +421,7 @@ static void efidrm_remove(struct platform_device *pdev) static struct platform_driver efidrm_platform_driver = { .driver = { .name = "efi-framebuffer", + .pm = pm_sleep_ptr(&efidrm_pm_ops), }, .probe = efidrm_probe, .remove = efidrm_remove, From 41820323cc0f22d6e6b0385c22b4cb85ec0cb722 Mon Sep 17 00:00:00 2001 From: Thomas Zimmermann Date: Wed, 8 Apr 2026 14:03:16 +0200 Subject: [PATCH 087/145] drm/sysfb: ofdrm: Support power management Set PM ops for the ofdrm driver. Suspend and resume the DRM state on systems that support it. Many systems lose the hardware's framebuffer settings on suspend, hence resuming doesn't work there. Yet some systems, most notably emulators, keep the hardware state across suspend/resume cycles. There, DRM's suspend and resume helpers bring back the display on resume. Signed-off-by: Thomas Zimmermann Reviewed-by: Javier Martinez Canillas Link: https://patch.msgid.link/20260408120722.328769-4-tzimmermann@suse.de --- drivers/gpu/drm/sysfb/ofdrm.c | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+) diff --git a/drivers/gpu/drm/sysfb/ofdrm.c b/drivers/gpu/drm/sysfb/ofdrm.c index d38ba70f4e0d..8822ebcbc081 100644 --- a/drivers/gpu/drm/sysfb/ofdrm.c +++ b/drivers/gpu/drm/sysfb/ofdrm.c @@ -4,6 +4,7 @@ #include #include #include +#include #include #include @@ -20,6 +21,7 @@ #include #include #include +#include #include #include #include @@ -1095,6 +1097,22 @@ static struct drm_driver ofdrm_driver = { * Platform driver */ +static int ofdrm_pm_suspend(struct device *dev) +{ + struct drm_device *drm = dev_get_drvdata(dev); + + return drm_mode_config_helper_suspend(drm); +} + +static int ofdrm_pm_resume(struct device *dev) +{ + struct drm_device *drm = dev_get_drvdata(dev); + + return drm_mode_config_helper_resume(drm); +} + +static DEFINE_SIMPLE_DEV_PM_OPS(ofdrm_pm_ops, ofdrm_pm_suspend, ofdrm_pm_resume); + static int ofdrm_probe(struct platform_device *pdev) { struct ofdrm_device *odev; @@ -1134,6 +1152,7 @@ static struct platform_driver ofdrm_platform_driver = { .driver = { .name = "of-display", .of_match_table = ofdrm_of_match_display, + .pm = pm_sleep_ptr(&ofdrm_pm_ops), }, .probe = ofdrm_probe, .remove = ofdrm_remove, From 03069f19eefb44c9a75ae84ddadc8970111b3bfd Mon Sep 17 00:00:00 2001 From: Thomas Zimmermann Date: Wed, 8 Apr 2026 14:03:17 +0200 Subject: [PATCH 088/145] drm/sysfb: simpledrm: Support power management Set PM ops for the simpledrm driver. Suspend and resume the DRM state on systems that support it. Many systems lose the hardware's framebuffer settings on suspend, hence resuming doesn't work there. Yet some systems, most notably emulators, keep the hardware state across suspend/resume cycles. There, DRM's suspend and resume helpers bring back the display on resume. Signed-off-by: Thomas Zimmermann Reviewed-by: Javier Martinez Canillas Link: https://patch.msgid.link/20260408120722.328769-5-tzimmermann@suse.de --- drivers/gpu/drm/sysfb/simpledrm.c | 21 +++++++++++++++++++++ 1 file changed, 21 insertions(+) diff --git a/drivers/gpu/drm/sysfb/simpledrm.c b/drivers/gpu/drm/sysfb/simpledrm.c index 7a95d2dacd9d..fc168920f2c6 100644 --- a/drivers/gpu/drm/sysfb/simpledrm.c +++ b/drivers/gpu/drm/sysfb/simpledrm.c @@ -8,6 +8,7 @@ #include #include #include +#include #include #include @@ -24,6 +25,7 @@ #include #include #include +#include #include #include #include @@ -834,6 +836,24 @@ static struct drm_driver simpledrm_driver = { * Platform driver */ +static int simpledrm_pm_suspend(struct device *dev) +{ + struct simpledrm_device *sdev = dev_get_drvdata(dev); + struct drm_device *drm = &sdev->sysfb.dev; + + return drm_mode_config_helper_suspend(drm); +} + +static int simpledrm_pm_resume(struct device *dev) +{ + struct simpledrm_device *sdev = dev_get_drvdata(dev); + struct drm_device *drm = &sdev->sysfb.dev; + + return drm_mode_config_helper_resume(drm); +} + +static DEFINE_SIMPLE_DEV_PM_OPS(simpledrm_pm_ops, simpledrm_pm_suspend, simpledrm_pm_resume); + static int simpledrm_probe(struct platform_device *pdev) { struct simpledrm_device *sdev; @@ -874,6 +894,7 @@ static struct platform_driver simpledrm_platform_driver = { .driver = { .name = "simple-framebuffer", /* connect to sysfb */ .of_match_table = simpledrm_of_match_table, + .pm = pm_sleep_ptr(&simpledrm_pm_ops), }, .probe = simpledrm_probe, .remove = simpledrm_remove, From c813bdae379f95145c77be0ef075e28efd082af7 Mon Sep 17 00:00:00 2001 From: Thomas Zimmermann Date: Wed, 8 Apr 2026 14:03:18 +0200 Subject: [PATCH 089/145] drm/sysfb: vesadrm: Support power management Set PM ops for the vesadrm driver. Suspend and resume the DRM state on systems that support it. Many systems lose the hardware's framebuffer settings on suspend, hence resuming doesn't work there. Yet some systems, most notably emulators, keep the hardware state across suspend/resume cycles. There, DRM's suspend and resume helpers bring back the display on resume. Signed-off-by: Thomas Zimmermann Reviewed-by: Javier Martinez Canillas Link: https://patch.msgid.link/20260408120722.328769-6-tzimmermann@suse.de --- drivers/gpu/drm/sysfb/vesadrm.c | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+) diff --git a/drivers/gpu/drm/sysfb/vesadrm.c b/drivers/gpu/drm/sysfb/vesadrm.c index 4e00113e5c77..255b90a200b0 100644 --- a/drivers/gpu/drm/sysfb/vesadrm.c +++ b/drivers/gpu/drm/sysfb/vesadrm.c @@ -5,6 +5,7 @@ #include #include #include +#include #include #include @@ -21,6 +22,7 @@ #include #include #include +#include #include #include #include @@ -617,6 +619,22 @@ static struct drm_driver vesadrm_driver = { * Platform driver */ +static int vesadrm_pm_suspend(struct device *dev) +{ + struct drm_device *drm = dev_get_drvdata(dev); + + return drm_mode_config_helper_suspend(drm); +} + +static int vesadrm_pm_resume(struct device *dev) +{ + struct drm_device *drm = dev_get_drvdata(dev); + + return drm_mode_config_helper_resume(drm); +} + +static DEFINE_SIMPLE_DEV_PM_OPS(vesadrm_pm_ops, vesadrm_pm_suspend, vesadrm_pm_resume); + static int vesadrm_probe(struct platform_device *pdev) { struct vesadrm_device *vesa; @@ -649,6 +667,7 @@ static void vesadrm_remove(struct platform_device *pdev) static struct platform_driver vesadrm_platform_driver = { .driver = { .name = "vesa-framebuffer", + .pm = pm_sleep_ptr(&vesadrm_pm_ops), }, .probe = vesadrm_probe, .remove = vesadrm_remove, From cd4fe814f3b2e98fc5fc5c74e17b2605a57abb4c Mon Sep 17 00:00:00 2001 From: Marco Crivellari Date: Tue, 4 Nov 2025 12:13:39 +0100 Subject: [PATCH 090/145] drm/bridge: replace use of system_wq with system_percpu_wq Currently if a user enqueue a work item using schedule_delayed_work() the used wq is "system_wq" (per-cpu wq) while queue_delayed_work() use WORK_CPU_UNBOUND (used when a cpu is not specified). The same applies to schedule_work() that is using system_wq and queue_work(), that makes use again of WORK_CPU_UNBOUND. This lack of consistentcy cannot be addressed without refactoring the API. This patch continues the effort to refactor worqueue APIs, which has begun with the change introducing new workqueues and a new alloc_workqueue flag: commit 128ea9f6ccfb ("workqueue: Add system_percpu_wq and system_dfl_wq") commit 930c2ea566af ("workqueue: Add new WQ_PERCPU flag") system_wq should be the per-cpu workqueue, yet in this name nothing makes that clear, so replace system_wq with system_percpu_wq. The old wq (system_wq) will be kept for a few release cycles. Suggested-by: Tejun Heo Signed-off-by: Marco Crivellari Reviewed-by: Thomas Zimmermann Signed-off-by: Thomas Zimmermann Link: https://patch.msgid.link/20251104111339.128685-1-marco.crivellari@suse.com --- drivers/gpu/drm/bridge/ite-it6505.c | 2 +- drivers/gpu/drm/bridge/ti-tfp410.c | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/gpu/drm/bridge/ite-it6505.c b/drivers/gpu/drm/bridge/ite-it6505.c index a094803ba7aa..37bb8123cf9b 100644 --- a/drivers/gpu/drm/bridge/ite-it6505.c +++ b/drivers/gpu/drm/bridge/ite-it6505.c @@ -2048,7 +2048,7 @@ static void it6505_start_hdcp(struct it6505 *it6505) DRM_DEV_DEBUG_DRIVER(dev, "start"); it6505_reset_hdcp(it6505); - queue_delayed_work(system_wq, &it6505->hdcp_work, + queue_delayed_work(system_percpu_wq, &it6505->hdcp_work, msecs_to_jiffies(2400)); } diff --git a/drivers/gpu/drm/bridge/ti-tfp410.c b/drivers/gpu/drm/bridge/ti-tfp410.c index 3b6b0e92cf89..bf4ab4eaf269 100644 --- a/drivers/gpu/drm/bridge/ti-tfp410.c +++ b/drivers/gpu/drm/bridge/ti-tfp410.c @@ -114,7 +114,7 @@ static void tfp410_hpd_callback(void *arg, enum drm_connector_status status) { struct tfp410 *dvi = arg; - mod_delayed_work(system_wq, &dvi->hpd_work, + mod_delayed_work(system_percpu_wq, &dvi->hpd_work, msecs_to_jiffies(HOTPLUG_DEBOUNCE_MS)); } From a1b6cf8e5e7e9102f114f58e599ef1758c732efb Mon Sep 17 00:00:00 2001 From: Laurent Pinchart Date: Tue, 7 Apr 2026 13:49:51 +0300 Subject: [PATCH 091/145] drm: uapi: Use SPDX in DRM core uAPI headers The DRM core uAPI headers are licensed under the MIT license, and carry copies of the license with slight variations. Replace them with SPDX headers. Following a discussion with Simona Vetter on this topic, add a clarification in the drm-uapi.rst file that independent closed-source userspace implementations of software using the DRM uAPI are accepted, as allowed by the MIT license. Signed-off-by: Laurent Pinchart Reviewed-by: Greg Kroah-Hartman Reviewed-by: Thomas Gleixner Reviewed-by: Simona Vetter Reviewed-by: Dave Airlie Link: https://patch.msgid.link/20260407104951.1781047-1-laurent.pinchart+renesas@ideasonboard.com Signed-off-by: Tomi Valkeinen --- Documentation/gpu/drm-uapi.rst | 4 ++++ include/uapi/drm/drm.h | 20 +------------------- include/uapi/drm/drm_fourcc.h | 20 +------------------- include/uapi/drm/drm_mode.h | 19 +------------------ include/uapi/drm/drm_sarea.h | 20 +------------------- 5 files changed, 8 insertions(+), 75 deletions(-) diff --git a/Documentation/gpu/drm-uapi.rst b/Documentation/gpu/drm-uapi.rst index 579e87cb9ff7..32206ce62931 100644 --- a/Documentation/gpu/drm-uapi.rst +++ b/Documentation/gpu/drm-uapi.rst @@ -118,6 +118,10 @@ is already rather painful for the DRM subsystem, with multiple different uAPIs for the same thing co-existing. If we add a few more complete mistakes into the mix every year it would be entirely unmanageable. +The DRM subsystem has however no concern with independent closed-source +userspace implementations. To officialize that position, the DRM uAPI headers +are covered by the MIT license. + .. _drm_render_node: Render nodes diff --git a/include/uapi/drm/drm.h b/include/uapi/drm/drm.h index 495462e44a17..bc7ef7684099 100644 --- a/include/uapi/drm/drm.h +++ b/include/uapi/drm/drm.h @@ -1,3 +1,4 @@ +/* SPDX-License-Identifier: MIT */ /* * Header for the Direct Rendering Manager * @@ -11,25 +12,6 @@ * Copyright 1999 Precision Insight, Inc., Cedar Park, Texas. * Copyright 2000 VA Linux Systems, Inc., Sunnyvale, California. * All rights reserved. - * - * Permission is hereby granted, free of charge, to any person obtaining a - * copy of this software and associated documentation files (the "Software"), - * to deal in the Software without restriction, including without limitation - * the rights to use, copy, modify, merge, publish, distribute, sublicense, - * and/or sell copies of the Software, and to permit persons to whom the - * Software is furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice (including the next - * paragraph) shall be included in all copies or substantial portions of the - * Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL - * VA LINUX SYSTEMS AND/OR ITS SUPPLIERS BE LIABLE FOR ANY CLAIM, DAMAGES OR - * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, - * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR - * OTHER DEALINGS IN THE SOFTWARE. */ #ifndef _DRM_H_ diff --git a/include/uapi/drm/drm_fourcc.h b/include/uapi/drm/drm_fourcc.h index ac66fa93b5a3..2caf8249f892 100644 --- a/include/uapi/drm/drm_fourcc.h +++ b/include/uapi/drm/drm_fourcc.h @@ -1,24 +1,6 @@ +/* SPDX-License-Identifier: MIT */ /* * Copyright 2011 Intel Corporation - * - * Permission is hereby granted, free of charge, to any person obtaining a - * copy of this software and associated documentation files (the "Software"), - * to deal in the Software without restriction, including without limitation - * the rights to use, copy, modify, merge, publish, distribute, sublicense, - * and/or sell copies of the Software, and to permit persons to whom the - * Software is furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice (including the next - * paragraph) shall be included in all copies or substantial portions of the - * Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL - * VA LINUX SYSTEMS AND/OR ITS SUPPLIERS BE LIABLE FOR ANY CLAIM, DAMAGES OR - * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, - * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR - * OTHER DEALINGS IN THE SOFTWARE. */ #ifndef DRM_FOURCC_H diff --git a/include/uapi/drm/drm_mode.h b/include/uapi/drm/drm_mode.h index a4bdc4bd11bc..381a3e857d4e 100644 --- a/include/uapi/drm/drm_mode.h +++ b/include/uapi/drm/drm_mode.h @@ -1,27 +1,10 @@ +/* SPDX-License-Identifier: MIT */ /* * Copyright (c) 2007 Dave Airlie * Copyright (c) 2007 Jakob Bornecrantz * Copyright (c) 2008 Red Hat Inc. * Copyright (c) 2007-2008 Tungsten Graphics, Inc., Cedar Park, TX., USA * Copyright (c) 2007-2008 Intel Corporation - * - * Permission is hereby granted, free of charge, to any person obtaining a - * copy of this software and associated documentation files (the "Software"), - * to deal in the Software without restriction, including without limitation - * the rights to use, copy, modify, merge, publish, distribute, sublicense, - * and/or sell copies of the Software, and to permit persons to whom the - * Software is furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING - * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS - * IN THE SOFTWARE. */ #ifndef _DRM_MODE_H diff --git a/include/uapi/drm/drm_sarea.h b/include/uapi/drm/drm_sarea.h index a951ced60ebe..1e38d028332d 100644 --- a/include/uapi/drm/drm_sarea.h +++ b/include/uapi/drm/drm_sarea.h @@ -1,3 +1,4 @@ +/* SPDX-License-Identifier: MIT */ /** * \file drm_sarea.h * \brief SAREA definitions @@ -8,25 +9,6 @@ /* * Copyright 2002 Tungsten Graphics, Inc., Cedar Park, Texas. * All Rights Reserved. - * - * Permission is hereby granted, free of charge, to any person obtaining a - * copy of this software and associated documentation files (the "Software"), - * to deal in the Software without restriction, including without limitation - * the rights to use, copy, modify, merge, publish, distribute, sublicense, - * and/or sell copies of the Software, and to permit persons to whom the - * Software is furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice (including the next - * paragraph) shall be included in all copies or substantial portions of the - * Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL - * TUNGSTEN GRAPHICS AND/OR ITS SUPPLIERS BE LIABLE FOR ANY CLAIM, DAMAGES OR - * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, - * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR - * OTHER DEALINGS IN THE SOFTWARE. */ #ifndef _DRM_SAREA_H_ From d4c14903bf5e28e740516c4fbb7db01e0dedf3af Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Christian=20K=C3=B6nig?= Date: Mon, 10 Nov 2025 19:58:10 +0100 Subject: [PATCH 092/145] dma-buf/dma_fence_array: remove unused functionality v4 MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Amdgpu was the only user of the signal on any feature and we dropped that use case recently, so we can remove that functionality. v2: update num_pending only after the fence is signaled v3: separate out simplifying dma_fence_array implementation v4: fix XE patch split fallout Signed-off-by: Christian König Reviewed-by: Tvrtko Ursulin Link: https://lore.kernel.org/r/20260422103012.1647-1-christian.koenig@amd.com --- drivers/dma-buf/dma-fence-array.c | 13 ++++--------- drivers/dma-buf/dma-fence-unwrap.c | 3 +-- drivers/dma-buf/dma-resv.c | 3 +-- drivers/dma-buf/st-dma-fence-unwrap.c | 2 +- drivers/gpu/drm/i915/gem/i915_gem_execbuffer.c | 3 +-- drivers/gpu/drm/xe/xe_sync.c | 2 +- drivers/gpu/drm/xe/xe_vm.c | 2 +- include/linux/dma-fence-array.h | 6 ++---- 8 files changed, 12 insertions(+), 22 deletions(-) diff --git a/drivers/dma-buf/dma-fence-array.c b/drivers/dma-buf/dma-fence-array.c index 089f69469524..5e10e8df372f 100644 --- a/drivers/dma-buf/dma-fence-array.c +++ b/drivers/dma-buf/dma-fence-array.c @@ -190,15 +190,13 @@ EXPORT_SYMBOL(dma_fence_array_alloc); * @fences: [in] array containing the fences * @context: [in] fence context to use * @seqno: [in] sequence number to use - * @signal_on_any: [in] signal on any fence in the array * * Implementation of @dma_fence_array_create without allocation. Useful to init * a preallocated dma fence array in the path of reclaim or dma fence signaling. */ void dma_fence_array_init(struct dma_fence_array *array, int num_fences, struct dma_fence **fences, - u64 context, unsigned seqno, - bool signal_on_any) + u64 context, unsigned seqno) { static struct lock_class_key dma_fence_array_lock_key; @@ -222,7 +220,7 @@ void dma_fence_array_init(struct dma_fence_array *array, */ lockdep_set_class(&array->base.inline_lock, &dma_fence_array_lock_key); - atomic_set(&array->num_pending, signal_on_any ? 1 : num_fences); + atomic_set(&array->num_pending, num_fences); array->fences = fences; array->base.error = PENDING_ERROR; @@ -249,7 +247,6 @@ EXPORT_SYMBOL(dma_fence_array_init); * @fences: [in] array containing the fences * @context: [in] fence context to use * @seqno: [in] sequence number to use - * @signal_on_any: [in] signal on any fence in the array * * Allocate a dma_fence_array object and initialize the base fence with * dma_fence_init(). @@ -264,8 +261,7 @@ EXPORT_SYMBOL(dma_fence_array_init); */ struct dma_fence_array *dma_fence_array_create(int num_fences, struct dma_fence **fences, - u64 context, unsigned seqno, - bool signal_on_any) + u64 context, unsigned seqno) { struct dma_fence_array *array; @@ -273,8 +269,7 @@ struct dma_fence_array *dma_fence_array_create(int num_fences, if (!array) return NULL; - dma_fence_array_init(array, num_fences, fences, - context, seqno, signal_on_any); + dma_fence_array_init(array, num_fences, fences, context, seqno); return array; } diff --git a/drivers/dma-buf/dma-fence-unwrap.c b/drivers/dma-buf/dma-fence-unwrap.c index 07fe9bf45aea..53bb40e70b27 100644 --- a/drivers/dma-buf/dma-fence-unwrap.c +++ b/drivers/dma-buf/dma-fence-unwrap.c @@ -180,8 +180,7 @@ struct dma_fence *__dma_fence_unwrap_merge(unsigned int num_fences, if (count > 1) { result = dma_fence_array_create(count, array, - dma_fence_context_alloc(1), - 1, false); + dma_fence_context_alloc(1), 1); if (!result) { for (i = 0; i < count; i++) dma_fence_put(array[i]); diff --git a/drivers/dma-buf/dma-resv.c b/drivers/dma-buf/dma-resv.c index ce9e6c04897f..39a92d9f2413 100644 --- a/drivers/dma-buf/dma-resv.c +++ b/drivers/dma-buf/dma-resv.c @@ -648,8 +648,7 @@ int dma_resv_get_singleton(struct dma_resv *obj, enum dma_resv_usage usage, } array = dma_fence_array_create(count, fences, - dma_fence_context_alloc(1), - 1, false); + dma_fence_context_alloc(1), 1); if (!array) { while (count--) dma_fence_put(fences[count]); diff --git a/drivers/dma-buf/st-dma-fence-unwrap.c b/drivers/dma-buf/st-dma-fence-unwrap.c index 51c87869b7b8..4e7ee25372ba 100644 --- a/drivers/dma-buf/st-dma-fence-unwrap.c +++ b/drivers/dma-buf/st-dma-fence-unwrap.c @@ -64,7 +64,7 @@ static struct dma_fence *mock_array(unsigned int num_fences, ...) array = dma_fence_array_create(num_fences, fences, dma_fence_context_alloc(1), - 1, false); + 1); if (!array) goto error_free; return &array->base; diff --git a/drivers/gpu/drm/i915/gem/i915_gem_execbuffer.c b/drivers/gpu/drm/i915/gem/i915_gem_execbuffer.c index 65ce54b20ec2..05997e8bbb29 100644 --- a/drivers/gpu/drm/i915/gem/i915_gem_execbuffer.c +++ b/drivers/gpu/drm/i915/gem/i915_gem_execbuffer.c @@ -3205,8 +3205,7 @@ eb_composite_fence_create(struct i915_execbuffer *eb, int out_fence_fd) fence_array = dma_fence_array_create(eb->num_batches, fences, eb->context->parallel.fence_context, - eb->context->parallel.seqno++, - false); + eb->context->parallel.seqno++); if (!fence_array) { kfree(fences); return ERR_PTR(-ENOMEM); diff --git a/drivers/gpu/drm/xe/xe_sync.c b/drivers/gpu/drm/xe/xe_sync.c index 24d6d9af20d6..37866768d64c 100644 --- a/drivers/gpu/drm/xe/xe_sync.c +++ b/drivers/gpu/drm/xe/xe_sync.c @@ -376,7 +376,7 @@ xe_sync_in_fence_get(struct xe_sync_entry *sync, int num_sync, xe_assert(vm->xe, current_fence == num_fence); cf = dma_fence_array_create(num_fence, fences, dma_fence_context_alloc(1), - 1, false); + 1); if (!cf) goto err_out; diff --git a/drivers/gpu/drm/xe/xe_vm.c b/drivers/gpu/drm/xe/xe_vm.c index 56e2db50bb36..62a87a051be7 100644 --- a/drivers/gpu/drm/xe/xe_vm.c +++ b/drivers/gpu/drm/xe/xe_vm.c @@ -3414,7 +3414,7 @@ static struct dma_fence *ops_execute(struct xe_vm *vm, xe_assert(vm->xe, current_fence == n_fence); dma_fence_array_init(cf, n_fence, fences, dma_fence_context_alloc(1), - 1, false); + 1); fence = &cf->base; for_each_tile(tile, vm->xe, id) { diff --git a/include/linux/dma-fence-array.h b/include/linux/dma-fence-array.h index 370b3d2bba37..1b1d87579c38 100644 --- a/include/linux/dma-fence-array.h +++ b/include/linux/dma-fence-array.h @@ -81,13 +81,11 @@ to_dma_fence_array(struct dma_fence *fence) struct dma_fence_array *dma_fence_array_alloc(int num_fences); void dma_fence_array_init(struct dma_fence_array *array, int num_fences, struct dma_fence **fences, - u64 context, unsigned seqno, - bool signal_on_any); + u64 context, unsigned seqno); struct dma_fence_array *dma_fence_array_create(int num_fences, struct dma_fence **fences, - u64 context, unsigned seqno, - bool signal_on_any); + u64 context, unsigned seqno); bool dma_fence_match_context(struct dma_fence *fence, u64 context); From 93dd05a23b5bc9c0d6be331b10eed876b8b9c1f1 Mon Sep 17 00:00:00 2001 From: Myeonghun Pak Date: Fri, 24 Apr 2026 21:40:39 +0900 Subject: [PATCH 093/145] drm/tve200: Fix probe cleanup after register failure tve200_modeset_init() creates a panel bridge and initializes the DRM mode config before tve200_probe() registers the DRM device. If drm_dev_register() fails, probe returns an error and the driver's remove callback is not called, so those modeset resources are left behind. Unwind the panel bridge and mode config on that failure path before disabling the clock and dropping the DRM device reference. Signed-off-by: Myeonghun Pak Signed-off-by: Linus Walleij Link: https://patch.msgid.link/20260424124118.38649-1-mhun512@gmail.com --- drivers/gpu/drm/tve200/tve200_drv.c | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/drivers/gpu/drm/tve200/tve200_drv.c b/drivers/gpu/drm/tve200/tve200_drv.c index a048e37f1c2c..562f3f11812a 100644 --- a/drivers/gpu/drm/tve200/tve200_drv.c +++ b/drivers/gpu/drm/tve200/tve200_drv.c @@ -221,12 +221,16 @@ static int tve200_probe(struct platform_device *pdev) ret = drm_dev_register(drm, 0); if (ret < 0) - goto clk_disable; + goto mode_config_cleanup; drm_client_setup_with_fourcc(drm, DRM_FORMAT_RGB565); return 0; +mode_config_cleanup: + if (priv->panel) + drm_panel_bridge_remove(priv->bridge); + drm_mode_config_cleanup(drm); clk_disable: clk_disable_unprepare(priv->pclk); dev_unref: From 4b494c72555f6249331b16add879c40e920d3f1e Mon Sep 17 00:00:00 2001 From: Cristian Cozzolino Date: Tue, 31 Mar 2026 11:47:09 +0200 Subject: [PATCH 094/145] dt-bindings: display: panel: Add Novatek NT35532 LCD DSI Document Novatek NT35532-based DSI display panel. Since it's not possible to identify panel vendor nor id, add a suitable compatible (matching the device's user, which makes use of this DDIC) and set "novatek,nt35532" as fallback. Reviewed-by: Krzysztof Kozlowski Signed-off-by: Cristian Cozzolino Signed-off-by: Neil Armstrong Link: https://patch.msgid.link/20260331-rimob-new-features-v5-1-5fcf42a29c12@protonmail.com --- .../display/panel/novatek,nt35532.yaml | 80 +++++++++++++++++++ MAINTAINERS | 5 ++ 2 files changed, 85 insertions(+) create mode 100644 Documentation/devicetree/bindings/display/panel/novatek,nt35532.yaml diff --git a/Documentation/devicetree/bindings/display/panel/novatek,nt35532.yaml b/Documentation/devicetree/bindings/display/panel/novatek,nt35532.yaml new file mode 100644 index 000000000000..ff6fdad7febf --- /dev/null +++ b/Documentation/devicetree/bindings/display/panel/novatek,nt35532.yaml @@ -0,0 +1,80 @@ +# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) +%YAML 1.2 +--- +$id: http://devicetree.org/schemas/display/panel/novatek,nt35532.yaml# +$schema: http://devicetree.org/meta-schemas/core.yaml# + +title: Novatek NT35532-based DSI display panels + +maintainers: + - Cristian Cozzolino + +allOf: + - $ref: panel-common.yaml# + +properties: + compatible: + items: + - enum: + - flipkart,rimob-panel-nt35532-cs + - const: novatek,nt35532 + + reg: + maxItems: 1 + + backlight: true + reset-gpios: true + + avdd-supply: + description: positive boost supply regulator + + avee-supply: + description: negative boost supply regulator + + vci-supply: + description: regulator that supplies the analog voltage + + vddam-supply: + description: power supply for MIPI interface + + vddi-supply: + description: regulator that supplies the I/O voltage + + port: true + +required: + - compatible + - reg + - reset-gpios + - vddi-supply + - port + +additionalProperties: false + +examples: + - | + #include + + dsi { + #address-cells = <1>; + #size-cells = <0>; + + panel@0 { + compatible = "flipkart,rimob-panel-nt35532-cs", "novatek,nt35532"; + reg = <0>; + + backlight = <&pmi8950_wled>; + reset-gpios = <&tlmm 61 GPIO_ACTIVE_LOW>; + avdd-supply = <&lab>; + avee-supply = <&ibb>; + vci-supply = <&pm8953_l17>; + vddi-supply = <&pm8953_l6>; + + port { + panel_in: endpoint { + remote-endpoint = <&dsi0_out>; + }; + }; + }; + }; +... diff --git a/MAINTAINERS b/MAINTAINERS index 54b941d6e8b2..22e8a34058dd 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -8150,6 +8150,11 @@ T: git https://gitlab.freedesktop.org/drm/misc/kernel.git F: Documentation/devicetree/bindings/display/panel/novatek,nt35510.yaml F: drivers/gpu/drm/panel/panel-novatek-nt35510.c +DRM DRIVER FOR NOVATEK NT35532 PANELS +M: Cristian Cozzolino +S: Maintained +F: Documentation/devicetree/bindings/display/panel/novatek,nt35532.yaml + DRM DRIVER FOR NOVATEK NT35560 PANELS M: Linus Walleij S: Maintained From 7a0dd1b5c55f73b962dfa807e726f7214def6065 Mon Sep 17 00:00:00 2001 From: Cristian Cozzolino Date: Tue, 31 Mar 2026 11:47:10 +0200 Subject: [PATCH 095/145] drm/panel: Add driver for Novatek NT35532 Add support for Novatek NT35532-based 1080p video mode DSI panel. Reviewed-by: Dmitry Baryshkov Signed-off-by: Cristian Cozzolino Signed-off-by: Neil Armstrong Link: https://patch.msgid.link/20260331-rimob-new-features-v5-2-5fcf42a29c12@protonmail.com --- MAINTAINERS | 1 + drivers/gpu/drm/panel/Kconfig | 10 + drivers/gpu/drm/panel/Makefile | 1 + drivers/gpu/drm/panel/panel-novatek-nt35532.c | 796 ++++++++++++++++++ 4 files changed, 808 insertions(+) create mode 100644 drivers/gpu/drm/panel/panel-novatek-nt35532.c diff --git a/MAINTAINERS b/MAINTAINERS index 22e8a34058dd..77b1f75c82e1 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -8154,6 +8154,7 @@ DRM DRIVER FOR NOVATEK NT35532 PANELS M: Cristian Cozzolino S: Maintained F: Documentation/devicetree/bindings/display/panel/novatek,nt35532.yaml +F: drivers/gpu/drm/panel/panel-novatek-nt35532.c DRM DRIVER FOR NOVATEK NT35560 PANELS M: Linus Walleij diff --git a/drivers/gpu/drm/panel/Kconfig b/drivers/gpu/drm/panel/Kconfig index 979109c27b9b..179037fa746d 100644 --- a/drivers/gpu/drm/panel/Kconfig +++ b/drivers/gpu/drm/panel/Kconfig @@ -562,6 +562,16 @@ config DRM_PANEL_NOVATEK_NT35510 around the Novatek NT35510 display controller, such as some Hydis panels. +config DRM_PANEL_NOVATEK_NT35532 + tristate "Novatek NT35532-based DSI video mode panel" + depends on OF + depends on DRM_MIPI_DSI + depends on BACKLIGHT_CLASS_DEVICE + select DRM_KMS_HELPER + help + Say Y or M here if you want to enable support for Novatek + NT35532-based 1080p video mode DSI panels. + config DRM_PANEL_NOVATEK_NT35560 tristate "Novatek NT35560 DSI command mode panel" depends on OF diff --git a/drivers/gpu/drm/panel/Makefile b/drivers/gpu/drm/panel/Makefile index 0d694acbfbb6..71374d4735d8 100644 --- a/drivers/gpu/drm/panel/Makefile +++ b/drivers/gpu/drm/panel/Makefile @@ -55,6 +55,7 @@ obj-$(CONFIG_DRM_PANEL_NEC_NL8048HL11) += panel-nec-nl8048hl11.o obj-$(CONFIG_DRM_PANEL_NEWVISION_NV3051D) += panel-newvision-nv3051d.o obj-$(CONFIG_DRM_PANEL_NEWVISION_NV3052C) += panel-newvision-nv3052c.o obj-$(CONFIG_DRM_PANEL_NOVATEK_NT35510) += panel-novatek-nt35510.o +obj-$(CONFIG_DRM_PANEL_NOVATEK_NT35532) += panel-novatek-nt35532.o obj-$(CONFIG_DRM_PANEL_NOVATEK_NT35560) += panel-novatek-nt35560.o obj-$(CONFIG_DRM_PANEL_NOVATEK_NT35950) += panel-novatek-nt35950.o obj-$(CONFIG_DRM_PANEL_NOVATEK_NT36523) += panel-novatek-nt36523.o diff --git a/drivers/gpu/drm/panel/panel-novatek-nt35532.c b/drivers/gpu/drm/panel/panel-novatek-nt35532.c new file mode 100644 index 000000000000..184f61bca7ca --- /dev/null +++ b/drivers/gpu/drm/panel/panel-novatek-nt35532.c @@ -0,0 +1,796 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * Generated with linux-mdss-dsi-panel-driver-generator from vendor device tree. + * Copyright (c) 2026 Cristian Cozzolino + */ + +#include +#include +#include +#include +#include +#include + +#include