From 57df858a46f0a4cc104716e0ec88864e5c386ca4 Mon Sep 17 00:00:00 2001 From: Jassi Brar Date: Mon, 9 Feb 2026 17:36:19 -0600 Subject: mailbox: add API to query available TX queue slots Clients sometimes need to know whether the mailbox TX queue has room before posting a new message. Rather than exposing internal queue state through a struct field, provide a proper accessor function that returns the number of available slots for a given channel. This lets clients choose to back off when the queue is full instead of hitting the -ENOBUFS error path and the misleading "Try increasing MBOX_TX_QUEUE_LEN" warning. Tested-by: Tanmay Shah Signed-off-by: Jassi Brar --- drivers/mailbox/mailbox.c | 23 +++++++++++++++++++++++ include/linux/mailbox_client.h | 1 + 2 files changed, 24 insertions(+) diff --git a/drivers/mailbox/mailbox.c b/drivers/mailbox/mailbox.c index 617ba505691d..354434cd1209 100644 --- a/drivers/mailbox/mailbox.c +++ b/drivers/mailbox/mailbox.c @@ -218,6 +218,29 @@ bool mbox_client_peek_data(struct mbox_chan *chan) } EXPORT_SYMBOL_GPL(mbox_client_peek_data); +/** + * mbox_chan_tx_slots_available - Query the number of available TX queue slots. + * @chan: Mailbox channel to query. + * + * Clients may call this to check how many messages can be queued via + * mbox_send_message() before the channel's TX queue is full. This helps + * clients avoid the -ENOBUFS error without needing to increase + * MBOX_TX_QUEUE_LEN. + * This can be called from atomic context. + * + * Return: Number of available slots in the channel's TX queue. + */ +unsigned int mbox_chan_tx_slots_available(struct mbox_chan *chan) +{ + unsigned int ret; + + guard(spinlock_irqsave)(&chan->lock); + ret = MBOX_TX_QUEUE_LEN - chan->msg_count; + + return ret; +} +EXPORT_SYMBOL_GPL(mbox_chan_tx_slots_available); + /** * mbox_send_message - For client to submit a message to be * sent to the remote. diff --git a/include/linux/mailbox_client.h b/include/linux/mailbox_client.h index c6eea9afb943..e5997120f45c 100644 --- a/include/linux/mailbox_client.h +++ b/include/linux/mailbox_client.h @@ -45,6 +45,7 @@ int mbox_send_message(struct mbox_chan *chan, void *mssg); int mbox_flush(struct mbox_chan *chan, unsigned long timeout); void mbox_client_txdone(struct mbox_chan *chan, int r); /* atomic */ bool mbox_client_peek_data(struct mbox_chan *chan); /* atomic */ +unsigned int mbox_chan_tx_slots_available(struct mbox_chan *chan); /* atomic */ void mbox_free_channel(struct mbox_chan *chan); /* may sleep */ #endif /* __MAILBOX_CLIENT_H */ -- cgit v1.2.3 From d946347edc4f0a7b846325323d77e936a4c90d0f Mon Sep 17 00:00:00 2001 From: Max Zhen Date: Wed, 25 Mar 2026 18:06:42 -0700 Subject: accel/amdxdna: Fix leak when pinning ubuf pages When pin_user_pages_fast() returns fewer pages than requested, the pages that were successfully pinned are not released, leading to a leak. Fix this by unpinning any partially pinned pages before returning failure. Fixes: bd72d4acda10 ("accel/amdxdna: Support user space allocated buffer") Reviewed-by: Mario Limonciello (AMD) Signed-off-by: Max Zhen Signed-off-by: Lizhi Hou Link: https://patch.msgid.link/20260326010642.2596525-1-lizhi.hou@amd.com --- drivers/accel/amdxdna/amdxdna_ubuf.c | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/drivers/accel/amdxdna/amdxdna_ubuf.c b/drivers/accel/amdxdna/amdxdna_ubuf.c index fb999aa25318..4c0647057759 100644 --- a/drivers/accel/amdxdna/amdxdna_ubuf.c +++ b/drivers/accel/amdxdna/amdxdna_ubuf.c @@ -196,13 +196,17 @@ struct dma_buf *amdxdna_get_ubuf(struct drm_device *dev, ret = pin_user_pages_fast(va_ent[i].vaddr, npages, FOLL_WRITE | FOLL_LONGTERM, &ubuf->pages[start]); - if (ret < 0 || ret != npages) { - ret = -ENOMEM; + if (ret >= 0) { + start += ret; + if (ret != npages) { + XDNA_ERR(xdna, "Partially pinned pages %d/%u", ret, npages); + ret = -ENOMEM; + goto destroy_pages; + } + } else { XDNA_ERR(xdna, "Failed to pin pages ret %d", ret); goto destroy_pages; } - - start += ret; } exp_info.ops = &amdxdna_ubuf_dmabuf_ops; -- cgit v1.2.3 From 3cc50e7f73fcf79f28660b9d91566b13cb62e520 Mon Sep 17 00:00:00 2001 From: Cristian Ciocaltea Date: Tue, 10 Mar 2026 00:44:29 +0200 Subject: drm/rockchip: inno-hdmi: Switch to drmm_kzalloc() Driver makes use of drmm_encoder_init() to initialize the encoder and automatically handle the cleanup by registering drm_encoder_cleanup() with drmm_add_action(). However, the internal structure containing the encoder part gets allocated with devm_kzalloc(), which happens while component_bind_all() is being called from Rockchip DRM driver. The component framework further ensures it is deallocated as part of releasing all the resources claimed during bind, which is triggered from component_unbind_all(). When the reference to the DRM device gets eventually dropped via drm_dev_put() in rockchip_drm_unbind(), drmm_encoder_alloc_release() attempts to access the now released encoder structure, leading to use-after-free. Ensure driver's internal structure is still reachable on encoder cleanup by switching from a device-managed allocation to a drm-managed one. Fixes: 969325a2597e ("drm/rockchip: inno-hdmi: Convert to drm bridge") Signed-off-by: Cristian Ciocaltea Signed-off-by: Heiko Stuebner Link: https://patch.msgid.link/20260310-drm-rk-fixes-v2-1-645ecfb43f49@collabora.com --- drivers/gpu/drm/rockchip/inno_hdmi-rockchip.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/drivers/gpu/drm/rockchip/inno_hdmi-rockchip.c b/drivers/gpu/drm/rockchip/inno_hdmi-rockchip.c index 97c20500f790..28e6fb09aae7 100644 --- a/drivers/gpu/drm/rockchip/inno_hdmi-rockchip.c +++ b/drivers/gpu/drm/rockchip/inno_hdmi-rockchip.c @@ -14,6 +14,7 @@ #include #include +#include #include #include "rockchip_drm_drv.h" @@ -90,7 +91,7 @@ static int inno_hdmi_rockchip_bind(struct device *dev, struct device *master, vo const struct inno_hdmi_plat_data *plat_data; int ret; - hdmi = devm_kzalloc(dev, sizeof(*hdmi), GFP_KERNEL); + hdmi = drmm_kzalloc(drm, sizeof(*hdmi), GFP_KERNEL); if (!hdmi) return -ENOMEM; -- cgit v1.2.3 From ed9da8d23020352ad24c528db09b5acdd78b81fd Mon Sep 17 00:00:00 2001 From: Cristian Ciocaltea Date: Tue, 10 Mar 2026 00:44:30 +0200 Subject: drm/rockchip: dw_dp: Switch to drmm_kzalloc() Driver makes use of drmm_encoder_init() to initialize the encoder and automatically handle the cleanup by registering drm_encoder_cleanup() with drmm_add_action(). However, the internal structure containing the encoder part gets allocated with devm_kzalloc(), which happens while component_bind_all() is being called from Rockchip DRM driver. The component framework further ensures it is deallocated as part of releasing all the resources claimed during bind, which is triggered from component_unbind_all(). When the reference to the DRM device gets eventually dropped via drm_dev_put() in rockchip_drm_unbind(), drmm_encoder_alloc_release() attempts to access the now released encoder structure, leading to use-after-free. Ensure driver's internal structure is still reachable on encoder cleanup by switching from a device-managed allocation to a drm-managed one. Fixes: d68ba7bac955 ("drm/rockchip: Add RK3588 DPTX output support") Signed-off-by: Cristian Ciocaltea Signed-off-by: Heiko Stuebner Link: https://patch.msgid.link/20260310-drm-rk-fixes-v2-2-645ecfb43f49@collabora.com --- drivers/gpu/drm/rockchip/dw_dp-rockchip.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/drivers/gpu/drm/rockchip/dw_dp-rockchip.c b/drivers/gpu/drm/rockchip/dw_dp-rockchip.c index dac3d202971e..532af476d250 100644 --- a/drivers/gpu/drm/rockchip/dw_dp-rockchip.c +++ b/drivers/gpu/drm/rockchip/dw_dp-rockchip.c @@ -13,6 +13,7 @@ #include #include #include +#include #include #include #include @@ -82,7 +83,7 @@ static int dw_dp_rockchip_bind(struct device *dev, struct device *master, void * struct drm_connector *connector; int ret; - dp = devm_kzalloc(dev, sizeof(*dp), GFP_KERNEL); + dp = drmm_kzalloc(drm_dev, sizeof(*dp), GFP_KERNEL); if (!dp) return -ENOMEM; -- cgit v1.2.3 From 9456381d8b60bb7dd42f2f04afe5ee4ce6e0bc12 Mon Sep 17 00:00:00 2001 From: Cristian Ciocaltea Date: Tue, 10 Mar 2026 00:44:31 +0200 Subject: drm/rockchip: dw_dp: Fix null-ptr-deref in dw_dp_remove() Attempting to access driver data in the platform driver ->remove() callback may lead to a null pointer dereference since there is no guaranty that the component ->bind() callback invoking platform_set_drvdata() was executed. A common scenario is when Rockchip DRM driver didn't manage to run component_bind_all() because of an (unrelated) error causing early return from rockchip_drm_bind(). Drop the unnecessary call to platform_get_drvdata() and, instead, reference the target device structure via platform_device. Fixes: d68ba7bac955 ("drm/rockchip: Add RK3588 DPTX output support") Signed-off-by: Cristian Ciocaltea Signed-off-by: Heiko Stuebner Link: https://patch.msgid.link/20260310-drm-rk-fixes-v2-3-645ecfb43f49@collabora.com --- drivers/gpu/drm/rockchip/dw_dp-rockchip.c | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/drivers/gpu/drm/rockchip/dw_dp-rockchip.c b/drivers/gpu/drm/rockchip/dw_dp-rockchip.c index 532af476d250..8945a245398c 100644 --- a/drivers/gpu/drm/rockchip/dw_dp-rockchip.c +++ b/drivers/gpu/drm/rockchip/dw_dp-rockchip.c @@ -133,9 +133,7 @@ static int dw_dp_probe(struct platform_device *pdev) static void dw_dp_remove(struct platform_device *pdev) { - struct rockchip_dw_dp *dp = platform_get_drvdata(pdev); - - component_del(dp->dev, &dw_dp_rockchip_component_ops); + component_del(&pdev->dev, &dw_dp_rockchip_component_ops); } static const struct dw_dp_plat_data rk3588_dp_plat_data = { -- cgit v1.2.3 From 26cb3e26efa7cc84289966cab871889f6ca93616 Mon Sep 17 00:00:00 2001 From: Cristian Ciocaltea Date: Tue, 10 Mar 2026 00:44:32 +0200 Subject: drm/rockchip: dw_dp: Simplify error handling Make the code a bit more compact by getting rid of the superfluous assignments around PTR_ERR(). While at it, also drop dev assignment in dw_dp_probe(). Signed-off-by: Cristian Ciocaltea Signed-off-by: Heiko Stuebner Link: https://patch.msgid.link/20260310-drm-rk-fixes-v2-4-645ecfb43f49@collabora.com --- drivers/gpu/drm/rockchip/dw_dp-rockchip.c | 21 +++++++-------------- 1 file changed, 7 insertions(+), 14 deletions(-) diff --git a/drivers/gpu/drm/rockchip/dw_dp-rockchip.c b/drivers/gpu/drm/rockchip/dw_dp-rockchip.c index 8945a245398c..fafefee8370d 100644 --- a/drivers/gpu/drm/rockchip/dw_dp-rockchip.c +++ b/drivers/gpu/drm/rockchip/dw_dp-rockchip.c @@ -104,20 +104,15 @@ static int dw_dp_rockchip_bind(struct device *dev, struct device *master, void * drm_encoder_helper_add(encoder, &dw_dp_encoder_helper_funcs); dp->base = dw_dp_bind(dev, encoder, plat_data); - if (IS_ERR(dp->base)) { - ret = PTR_ERR(dp->base); - return ret; - } + if (IS_ERR(dp->base)) + return PTR_ERR(dp->base); connector = drm_bridge_connector_init(drm_dev, encoder); - if (IS_ERR(connector)) { - ret = PTR_ERR(connector); - return dev_err_probe(dev, ret, "Failed to init bridge connector"); - } + if (IS_ERR(connector)) + return dev_err_probe(dev, PTR_ERR(connector), + "Failed to init bridge connector"); - drm_connector_attach_encoder(connector, encoder); - - return 0; + return drm_connector_attach_encoder(connector, encoder); } static const struct component_ops dw_dp_rockchip_component_ops = { @@ -126,9 +121,7 @@ static const struct component_ops dw_dp_rockchip_component_ops = { static int dw_dp_probe(struct platform_device *pdev) { - struct device *dev = &pdev->dev; - - return component_add(dev, &dw_dp_rockchip_component_ops); + return component_add(&pdev->dev, &dw_dp_rockchip_component_ops); } static void dw_dp_remove(struct platform_device *pdev) -- cgit v1.2.3 From 31a98842a11fcb52a2db9b1b498d5ac11793e35f Mon Sep 17 00:00:00 2001 From: Cristian Ciocaltea Date: Tue, 10 Mar 2026 00:44:33 +0200 Subject: drm/rockchip: dw_dp: Drop unnecessary #include Included header "rockchip_drm_vop.h" is not directly used, drop it. While at it, ensure #include directives are ordered alphabetically. Signed-off-by: Cristian Ciocaltea Signed-off-by: Heiko Stuebner Link: https://patch.msgid.link/20260310-drm-rk-fixes-v2-5-645ecfb43f49@collabora.com --- drivers/gpu/drm/rockchip/dw_dp-rockchip.c | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/drivers/gpu/drm/rockchip/dw_dp-rockchip.c b/drivers/gpu/drm/rockchip/dw_dp-rockchip.c index fafefee8370d..22c0911f1896 100644 --- a/drivers/gpu/drm/rockchip/dw_dp-rockchip.c +++ b/drivers/gpu/drm/rockchip/dw_dp-rockchip.c @@ -7,8 +7,11 @@ */ #include +#include #include #include +#include + #include #include #include @@ -19,11 +22,7 @@ #include #include -#include -#include - #include "rockchip_drm_drv.h" -#include "rockchip_drm_vop.h" struct rockchip_dw_dp { struct dw_dp *base; -- cgit v1.2.3 From e1f7b7cbd74c6561944f5dda345dab59ad391acb Mon Sep 17 00:00:00 2001 From: Cristian Ciocaltea Date: Tue, 10 Mar 2026 00:44:34 +0200 Subject: drm/rockchip: dw_hdmi_qp: Switch to drmm_encoder_init() Simplify encoder initialization and cleanup by making use of drmm_encoder_init(), which takes care of registering drm_encoder_cleanup() with drmm_add_action(). Signed-off-by: Cristian Ciocaltea Signed-off-by: Heiko Stuebner Link: https://patch.msgid.link/20260310-drm-rk-fixes-v2-6-645ecfb43f49@collabora.com --- drivers/gpu/drm/rockchip/dw_hdmi_qp-rockchip.c | 13 ++++++------- 1 file changed, 6 insertions(+), 7 deletions(-) diff --git a/drivers/gpu/drm/rockchip/dw_hdmi_qp-rockchip.c b/drivers/gpu/drm/rockchip/dw_hdmi_qp-rockchip.c index 1a09bcc96c3e..c78db7f8ab6c 100644 --- a/drivers/gpu/drm/rockchip/dw_hdmi_qp-rockchip.c +++ b/drivers/gpu/drm/rockchip/dw_hdmi_qp-rockchip.c @@ -21,6 +21,7 @@ #include #include #include +#include #include #include #include @@ -477,7 +478,7 @@ static int dw_hdmi_qp_rockchip_bind(struct device *dev, struct device *master, if (!pdev->dev.of_node) return -ENODEV; - hdmi = devm_kzalloc(&pdev->dev, sizeof(*hdmi), GFP_KERNEL); + hdmi = drmm_kzalloc(drm, sizeof(*hdmi), GFP_KERNEL); if (!hdmi) return -ENOMEM; @@ -586,16 +587,16 @@ static int dw_hdmi_qp_rockchip_bind(struct device *dev, struct device *master, return ret; drm_encoder_helper_add(encoder, &dw_hdmi_qp_rockchip_encoder_helper_funcs); - drm_simple_encoder_init(drm, encoder, DRM_MODE_ENCODER_TMDS); + ret = drmm_encoder_init(drm, encoder, NULL, DRM_MODE_ENCODER_TMDS, NULL); + if (ret) + return dev_err_probe(hdmi->dev, ret, "Failed to init encoder"); platform_set_drvdata(pdev, hdmi); hdmi->hdmi = dw_hdmi_qp_bind(pdev, encoder, &plat_data); - if (IS_ERR(hdmi->hdmi)) { - drm_encoder_cleanup(encoder); + if (IS_ERR(hdmi->hdmi)) return dev_err_probe(hdmi->dev, PTR_ERR(hdmi->hdmi), "Failed to bind dw-hdmi-qp"); - } connector = drm_bridge_connector_init(drm, encoder); if (IS_ERR(connector)) @@ -612,8 +613,6 @@ static void dw_hdmi_qp_rockchip_unbind(struct device *dev, struct rockchip_hdmi_qp *hdmi = dev_get_drvdata(dev); cancel_delayed_work_sync(&hdmi->hpd_work); - - drm_encoder_cleanup(&hdmi->encoder.encoder); } static const struct component_ops dw_hdmi_qp_rockchip_ops = { -- cgit v1.2.3 From 971a6d5d41315f3bfe1e1207f24da9a191c949ff Mon Sep 17 00:00:00 2001 From: Cristian Ciocaltea Date: Tue, 10 Mar 2026 00:44:36 +0200 Subject: drm/bridge: synopsys: dw-dp: Drop useless memory allocation The bridge gets allocated and initialized implicitly via the devm_drm_bridge_alloc() helper in dw_dp_bind(). However, this is preceded by an explicit allocation for the same dw_dp struct, which is never used anywhere as the return from devm_kzalloc() gets immediately overwritten by the aforementioned helper. Get rid of the unnecessary and confusing memory allocation. Signed-off-by: Cristian Ciocaltea Signed-off-by: Heiko Stuebner Link: https://patch.msgid.link/20260310-drm-rk-fixes-v2-8-645ecfb43f49@collabora.com --- drivers/gpu/drm/bridge/synopsys/dw-dp.c | 4 ---- 1 file changed, 4 deletions(-) diff --git a/drivers/gpu/drm/bridge/synopsys/dw-dp.c b/drivers/gpu/drm/bridge/synopsys/dw-dp.c index 45b37885d719..3f4530c117c7 100644 --- a/drivers/gpu/drm/bridge/synopsys/dw-dp.c +++ b/drivers/gpu/drm/bridge/synopsys/dw-dp.c @@ -1970,10 +1970,6 @@ struct dw_dp *dw_dp_bind(struct device *dev, struct drm_encoder *encoder, void __iomem *res; int ret; - dp = devm_kzalloc(dev, sizeof(*dp), GFP_KERNEL); - if (!dp) - return ERR_PTR(-ENOMEM); - dp = devm_drm_bridge_alloc(dev, struct dw_dp, bridge, &dw_dp_bridge_funcs); if (IS_ERR(dp)) return ERR_CAST(dp); -- cgit v1.2.3 From 9fc0da81916250f343599a4dd259f097196bf0fb Mon Sep 17 00:00:00 2001 From: Thomas Zimmermann Date: Fri, 27 Feb 2026 14:31:10 +0100 Subject: drm/rockchip: Test for imported buffers with drm_gem_is_imported() MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Instead of testing import_attach for imported GEM buffers, invoke drm_gem_is_imported() to do the test. The test itself does not change. Signed-off-by: Thomas Zimmermann Cc: Sandy Huang Cc: Heiko Stübner Cc: Andy Yan Cc: linux-rockchip@lists.infradead.org Fixes: b57aa47d39e9 ("drm/gem: Test for imported GEM buffers with helper") Closes: https://lore.kernel.org/dri-devel/38d09d34.4354.196379aa560.Coremail.andyshrk@163.com/ Signed-off-by: Heiko Stuebner Link: https://patch.msgid.link/20260227133113.235940-11-tzimmermann@suse.de --- drivers/gpu/drm/rockchip/rockchip_drm_gem.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/gpu/drm/rockchip/rockchip_drm_gem.c b/drivers/gpu/drm/rockchip/rockchip_drm_gem.c index 09d14a072d27..b188539dca0b 100644 --- a/drivers/gpu/drm/rockchip/rockchip_drm_gem.c +++ b/drivers/gpu/drm/rockchip/rockchip_drm_gem.c @@ -334,7 +334,7 @@ void rockchip_gem_free_object(struct drm_gem_object *obj) struct rockchip_drm_private *private = drm->dev_private; struct rockchip_gem_object *rk_obj = to_rockchip_obj(obj); - if (obj->import_attach) { + if (drm_gem_is_imported(obj)) { if (private->domain) { rockchip_gem_iommu_unmap(rk_obj); } else { -- cgit v1.2.3 From 45895f4d4d5f222d07412f90664f88b059627859 Mon Sep 17 00:00:00 2001 From: Chen Ni Date: Mon, 9 Feb 2026 11:31:23 +0800 Subject: drm/rockchip: analogix_dp: Add missing error check for platform_get_resource() Add missing error check for platform_get_resource() return value to prevent NULL pointer dereference when memory resource is not available. Fixes: 718b3bb9c0ab ("drm/rockchip: analogix_dp: Expand device data to support multiple edp display") Cc: stable@vger.kernel.org Signed-off-by: Chen Ni Reviewed-by: Dragan Simic Signed-off-by: Heiko Stuebner Link: https://patch.msgid.link/20260209033123.1089370-1-nichen@iscas.ac.cn --- drivers/gpu/drm/rockchip/analogix_dp-rockchip.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/drivers/gpu/drm/rockchip/analogix_dp-rockchip.c b/drivers/gpu/drm/rockchip/analogix_dp-rockchip.c index 96bd3dd239d2..387fb6259edd 100644 --- a/drivers/gpu/drm/rockchip/analogix_dp-rockchip.c +++ b/drivers/gpu/drm/rockchip/analogix_dp-rockchip.c @@ -461,6 +461,8 @@ static int rockchip_dp_probe(struct platform_device *pdev) return -ENOMEM; res = platform_get_resource(pdev, IORESOURCE_MEM, 0); + if (!res) + return -EINVAL; i = 0; while (dp_data[i].reg) { -- cgit v1.2.3 From 46c31e1604d121221167cb09380de8c7d53290b9 Mon Sep 17 00:00:00 2001 From: Sergey Shtylyov Date: Fri, 30 Jan 2026 23:35:42 +0300 Subject: drm/rockchip: cdn-dp: add missing check in cdn_dp_config_video() The result of cdn_dp_reg_write() is checked everywhere (with the error being logged by the callers) except one place in cdn_dp_config_video(). Add the missing result check, bailing out early on error... Found by Linux Verification Center (linuxtesting.org) with the Svace static analysis tool. Fixes: 1a0f7ed3abe2 ("drm/rockchip: cdn-dp: add cdn DP support for rk3399") Signed-off-by: Sergey Shtylyov Cc: stable@vger.kernel.org Reviewed-by: Chaoyi Chen Signed-off-by: Heiko Stuebner Link: https://patch.msgid.link/adf6b313-f7db-4d8f-9000-8c65446ba041@auroraos.dev --- drivers/gpu/drm/rockchip/cdn-dp-reg.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/drivers/gpu/drm/rockchip/cdn-dp-reg.c b/drivers/gpu/drm/rockchip/cdn-dp-reg.c index 0dc3804051a9..9b82b27770e5 100644 --- a/drivers/gpu/drm/rockchip/cdn-dp-reg.c +++ b/drivers/gpu/drm/rockchip/cdn-dp-reg.c @@ -685,6 +685,8 @@ int cdn_dp_config_video(struct cdn_dp_device *dp) val = div_u64(8 * (symbol + 1), bit_per_pix) - val; val += 2; ret = cdn_dp_reg_write(dp, DP_VC_TABLE(15), val); + if (ret) + goto err_config_video; switch (video->color_depth) { case 6: -- cgit v1.2.3 From 53b67da5f043d6d76de025cb1b7efd4a5151c697 Mon Sep 17 00:00:00 2001 From: Biju Das Date: Fri, 20 Mar 2026 16:41:47 +0000 Subject: dt-bindings: gpu: mali-bifrost: Add compatible for RZ/G3L SoC MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Add a compatible string for the Renesas RZ/G3L SoC variants that include a Mali-G31 GPU. These variants share the same restrictions on interrupts, clocks, and power domains as the RZ/G2L SoC, so extend the existing schema validation accordingly. Acked-by: Rob Herring (Arm) Signed-off-by: Biju Das Reviewed-by: Geert Uytterhoeven Link: https://patch.msgid.link/20260320164158.487406-2-biju.das.jz@bp.renesas.com Signed-off-by: Adrián Larumbe --- Documentation/devicetree/bindings/gpu/arm,mali-bifrost.yaml | 2 ++ 1 file changed, 2 insertions(+) diff --git a/Documentation/devicetree/bindings/gpu/arm,mali-bifrost.yaml b/Documentation/devicetree/bindings/gpu/arm,mali-bifrost.yaml index db49b8ff8c74..9db9f84ad964 100644 --- a/Documentation/devicetree/bindings/gpu/arm,mali-bifrost.yaml +++ b/Documentation/devicetree/bindings/gpu/arm,mali-bifrost.yaml @@ -26,6 +26,7 @@ properties: - realtek,rtd1619-mali - renesas,r9a07g044-mali - renesas,r9a07g054-mali + - renesas,r9a08g046-mali - renesas,r9a09g047-mali - renesas,r9a09g056-mali - renesas,r9a09g057-mali @@ -150,6 +151,7 @@ allOf: enum: - renesas,r9a07g044-mali - renesas,r9a07g054-mali + - renesas,r9a08g046-mali - renesas,r9a09g047-mali - renesas,r9a09g056-mali - renesas,r9a09g057-mali -- cgit v1.2.3 From 1a14d961660eaa17f21918d0cdf75a00b613ee05 Mon Sep 17 00:00:00 2001 From: Biju Das Date: Fri, 20 Mar 2026 16:41:48 +0000 Subject: drm/panfrost: Drop redundant optional clock checks in runtime PM MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The clk_enable() and clk_disable() APIs already handle NULL clock pointers gracefully — clk_enable() returns 0 and clk_disable() returns immediately when passed a NULL or optional clock. The explicit if (pfdev->bus_clock) guards around these calls in the runtime suspend/resume paths are therefore unnecessary. Remove them to simplify the code. Reviewed-by: Steven Price Signed-off-by: Biju Das Reviewed-by: Adrián Larumbe Link: https://patch.msgid.link/20260320164158.487406-3-biju.das.jz@bp.renesas.com Signed-off-by: Adrián Larumbe --- drivers/gpu/drm/panfrost/panfrost_device.c | 12 ++++-------- 1 file changed, 4 insertions(+), 8 deletions(-) diff --git a/drivers/gpu/drm/panfrost/panfrost_device.c b/drivers/gpu/drm/panfrost/panfrost_device.c index dedc13e56631..01e702a0b2f0 100644 --- a/drivers/gpu/drm/panfrost/panfrost_device.c +++ b/drivers/gpu/drm/panfrost/panfrost_device.c @@ -429,11 +429,9 @@ static int panfrost_device_runtime_resume(struct device *dev) if (ret) goto err_clk; - if (pfdev->bus_clock) { - ret = clk_enable(pfdev->bus_clock); - if (ret) - goto err_bus_clk; - } + ret = clk_enable(pfdev->bus_clock); + if (ret) + goto err_bus_clk; } panfrost_device_reset(pfdev, true); @@ -464,9 +462,7 @@ static int panfrost_device_runtime_suspend(struct device *dev) panfrost_gpu_power_off(pfdev); if (pfdev->comp->pm_features & BIT(GPU_PM_RT)) { - if (pfdev->bus_clock) - clk_disable(pfdev->bus_clock); - + clk_disable(pfdev->bus_clock); clk_disable(pfdev->clock); reset_control_assert(pfdev->rstc); } -- cgit v1.2.3 From 20ba3318eb19da7907ceb461ef3b5d65204070e6 Mon Sep 17 00:00:00 2001 From: Biju Das Date: Fri, 20 Mar 2026 16:41:49 +0000 Subject: drm/panfrost: Add bus_ace optional clock support for RZ/G2L MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit On RZ/G2L SoCs, the GPU MMU requires a bus_ace clock to operate correctly. Without it, unbind/bind cycles leave the GPU non-operational, manifesting as an AS_ACTIVE bit stuck and a soft reset timeout falling back to hard reset. Add bus_ace_clock as an optional clock, wiring it into init/fini, and the runtime suspend/resume paths alongside the existing optional bus_clock. Reviewed-by: Steven Price Signed-off-by: Biju Das Reviewed-by: Adrián Larumbe Link: https://patch.msgid.link/20260320164158.487406-4-biju.das.jz@bp.renesas.com Signed-off-by: Adrián Larumbe --- drivers/gpu/drm/panfrost/panfrost_device.c | 22 ++++++++++++++++++++++ drivers/gpu/drm/panfrost/panfrost_device.h | 1 + 2 files changed, 23 insertions(+) diff --git a/drivers/gpu/drm/panfrost/panfrost_device.c b/drivers/gpu/drm/panfrost/panfrost_device.c index 01e702a0b2f0..7fed22d555a5 100644 --- a/drivers/gpu/drm/panfrost/panfrost_device.c +++ b/drivers/gpu/drm/panfrost/panfrost_device.c @@ -70,8 +70,21 @@ static int panfrost_clk_init(struct panfrost_device *pfdev) goto disable_clock; } + pfdev->bus_ace_clock = devm_clk_get_optional(pfdev->base.dev, "bus_ace"); + if (IS_ERR(pfdev->bus_ace_clock)) { + err = PTR_ERR(pfdev->bus_ace_clock); + dev_err(pfdev->base.dev, "get bus_ace_clock failed %d\n", err); + goto disable_bus_clock; + } + + err = clk_prepare_enable(pfdev->bus_ace_clock); + if (err) + goto disable_bus_clock; + return 0; +disable_bus_clock: + clk_disable_unprepare(pfdev->bus_clock); disable_clock: clk_disable_unprepare(pfdev->clock); @@ -80,6 +93,7 @@ disable_clock: static void panfrost_clk_fini(struct panfrost_device *pfdev) { + clk_disable_unprepare(pfdev->bus_ace_clock); clk_disable_unprepare(pfdev->bus_clock); clk_disable_unprepare(pfdev->clock); } @@ -432,6 +446,10 @@ static int panfrost_device_runtime_resume(struct device *dev) ret = clk_enable(pfdev->bus_clock); if (ret) goto err_bus_clk; + + ret = clk_enable(pfdev->bus_ace_clock); + if (ret) + goto err_bus_ace_clk; } panfrost_device_reset(pfdev, true); @@ -439,6 +457,9 @@ static int panfrost_device_runtime_resume(struct device *dev) return 0; +err_bus_ace_clk: + if (pfdev->comp->pm_features & BIT(GPU_PM_RT)) + clk_disable(pfdev->bus_clock); err_bus_clk: if (pfdev->comp->pm_features & BIT(GPU_PM_RT)) clk_disable(pfdev->clock); @@ -462,6 +483,7 @@ static int panfrost_device_runtime_suspend(struct device *dev) panfrost_gpu_power_off(pfdev); if (pfdev->comp->pm_features & BIT(GPU_PM_RT)) { + clk_disable(pfdev->bus_ace_clock); clk_disable(pfdev->bus_clock); clk_disable(pfdev->clock); reset_control_assert(pfdev->rstc); diff --git a/drivers/gpu/drm/panfrost/panfrost_device.h b/drivers/gpu/drm/panfrost/panfrost_device.h index 0f3992412205..ec55c136b1b6 100644 --- a/drivers/gpu/drm/panfrost/panfrost_device.h +++ b/drivers/gpu/drm/panfrost/panfrost_device.h @@ -136,6 +136,7 @@ struct panfrost_device { void __iomem *iomem; struct clk *clock; struct clk *bus_clock; + struct clk *bus_ace_clock; struct regulator_bulk_data *regulators; struct reset_control *rstc; /* pm_domains for devices with more than one. */ -- cgit v1.2.3 From 45046f8718586376b00d3755352cd3e9992b3630 Mon Sep 17 00:00:00 2001 From: Biju Das Date: Fri, 20 Mar 2026 16:41:50 +0000 Subject: drm/panfrost: Add GPU_PM_RT support for RZ/G3L SoC MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit RZ/G3L SoC is embedded with Mali-G31 GPU system. Add GPU_PM_RT support as it needs to be assert/deassert the reset during suspend/resume. Reviewed-by: Steven Price Signed-off-by: Biju Das Reviewed-by: Adrián Larumbe Link: https://patch.msgid.link/20260320164158.487406-5-biju.das.jz@bp.renesas.com Signed-off-by: Adrián Larumbe --- drivers/gpu/drm/panfrost/panfrost_drv.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/gpu/drm/panfrost/panfrost_drv.c b/drivers/gpu/drm/panfrost/panfrost_drv.c index 711f5101aa04..3d0bdba2a474 100644 --- a/drivers/gpu/drm/panfrost/panfrost_drv.c +++ b/drivers/gpu/drm/panfrost/panfrost_drv.c @@ -1156,6 +1156,7 @@ static const struct of_device_id dt_match[] = { .data = &amlogic_data, }, { .compatible = "amlogic,meson-g12a-mali", .data = &amlogic_data, }, + { .compatible = "renesas,r9a08g046-mali", .data = &default_pm_rt_data }, { .compatible = "renesas,r9a09g047-mali", .data = &default_pm_rt_data }, { .compatible = "arm,mali-t604", .data = &default_data, }, { .compatible = "arm,mali-t624", .data = &default_data, }, -- cgit v1.2.3 From f468fef38716f667e805e0fa2c497c6b9c325bb9 Mon Sep 17 00:00:00 2001 From: Tomi Valkeinen Date: Wed, 11 Mar 2026 11:14:43 +0200 Subject: drm/tidss: Drop extra drm_mode_config_reset() call We are calling drm_mode_config_reset() twice at probe time. There's no reason for this and the second call can be removed, reducing work at probe time slightly. Fixes: 32a1795f57ee ("drm/tidss: New driver for TI Keystone platform Display SubSystem") Acked-by: Maxime Ripard Link: https://patch.msgid.link/20260311-tidss-minor-fixes-v2-1-cb4479784458@ideasonboard.com Signed-off-by: Tomi Valkeinen --- drivers/gpu/drm/tidss/tidss_kms.c | 2 -- 1 file changed, 2 deletions(-) diff --git a/drivers/gpu/drm/tidss/tidss_kms.c b/drivers/gpu/drm/tidss/tidss_kms.c index 8bb93194e5ac..b4779c09a1bf 100644 --- a/drivers/gpu/drm/tidss/tidss_kms.c +++ b/drivers/gpu/drm/tidss/tidss_kms.c @@ -287,8 +287,6 @@ int tidss_modeset_init(struct tidss_device *tidss) if (ret) return ret; - drm_mode_config_reset(ddev); - dev_dbg(tidss->dev, "%s done\n", __func__); return 0; -- cgit v1.2.3 From 83084bb36847cbd2b13743f7333aaca12613a72b Mon Sep 17 00:00:00 2001 From: Tomi Valkeinen Date: Wed, 11 Mar 2026 11:14:44 +0200 Subject: drm/tidss: Fix missing drm_bridge_add() call tidss encoder-bridge is not added with drm_bridge_add() call, which leads to: [drm] Missing drm_bridge_add() before attach Add the missing call, using devm_drm_bridge_add() variant to get the drm_bridge_remove() handled automatically. The commit marked with the Fixes tag (from v6.6) is the commit that added the encoder bridge without drm_bridge_add(). However, this fix is not directly applicable there as devm_drm_bridge_alloc() was not used to alloc the bridge, so using devm version for drm_bridge_add() wouldn't be safe. Instead, drm_bridge_add() and drm_bridge_remove() would be needed there, but that would require new plumbing code as we don't have a separate cleanup function in the tidss_encoder.c, not in the tidss_kms.c from which the encoder is created. Also, there has been no reported bugs caused by the missing drm_bridge_add(). The drm_bridge_add() initializes the bridge's hpd_mutex, but HPD is not used for the encoder bridge. drm_bridge_add() also adds the bridge to the global bridge_list, which is only used in of_drm_find_bridge(), and again that is not used for the encoder bridge. Thus, while the original commit is not right, there should be no bugs caused by it, and for the time being I'm not sending a patch for the stable kernels for the original commit. This fix applies on top of commit 66cdf05f8548 ("drm/tidss: encoder: convert to devm_drm_bridge_alloc()"), which changes the tidss_encoder.c to use the devm variant (added in v6.17). The warning print was added in v6.19, so applying this fix to v6.17+ gets rid of the warning for all kernel versions. Cc: stable@vger.kernel.org # v6.17+ Fixes: c932ced6b585 ("drm/tidss: Update encoder/bridge chain connect model") Acked-by: Maxime Ripard Link: https://patch.msgid.link/20260311-tidss-minor-fixes-v2-2-cb4479784458@ideasonboard.com Signed-off-by: Tomi Valkeinen --- drivers/gpu/drm/tidss/tidss_encoder.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/drivers/gpu/drm/tidss/tidss_encoder.c b/drivers/gpu/drm/tidss/tidss_encoder.c index 81a04f767770..db467bbcdb77 100644 --- a/drivers/gpu/drm/tidss/tidss_encoder.c +++ b/drivers/gpu/drm/tidss/tidss_encoder.c @@ -106,6 +106,8 @@ int tidss_encoder_create(struct tidss_device *tidss, enc = &t_enc->encoder; enc->possible_crtcs = possible_crtcs; + devm_drm_bridge_add(tidss->dev, &t_enc->bridge); + /* Attaching first bridge to the encoder */ ret = drm_bridge_attach(enc, &t_enc->bridge, NULL, DRM_BRIDGE_ATTACH_NO_CONNECTOR); -- cgit v1.2.3 From 61e3a508a45208f4f2824664f98d8f3bc6cd56fb Mon Sep 17 00:00:00 2001 From: Ville Syrjälä Date: Mon, 23 Mar 2026 23:36:45 +0200 Subject: drm/vblank: Extract get_vblank_counter_and_timestamp() MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit We have three copies of the "read vblank counter and timestamp in a loop" code. Consolidate to a single a function. Signed-off-by: Ville Syrjälä Link: https://patch.msgid.link/20260323213645.10965-1-ville.syrjala@linux.intel.com Reviewed-by: Suraj Kandpal --- drivers/gpu/drm/drm_vblank.c | 36 +++++++++++++++++++++--------------- 1 file changed, 21 insertions(+), 15 deletions(-) diff --git a/drivers/gpu/drm/drm_vblank.c b/drivers/gpu/drm/drm_vblank.c index f78bf37f1e0a..f90fb2d13e42 100644 --- a/drivers/gpu/drm/drm_vblank.c +++ b/drivers/gpu/drm/drm_vblank.c @@ -236,6 +236,21 @@ static u32 __get_vblank_counter(struct drm_device *dev, unsigned int pipe) return drm_vblank_no_hw_counter(dev, pipe); } +static bool get_vblank_counter_and_timestamp(struct drm_device *dev, unsigned int pipe, + u32 *cur_vblank, ktime_t *t_vblank, + bool in_vblank_irq) +{ + int count = DRM_TIMESTAMP_MAXRETRIES; + bool rc; + + do { + *cur_vblank = __get_vblank_counter(dev, pipe); + rc = drm_get_last_vbltimestamp(dev, pipe, t_vblank, in_vblank_irq); + } while (*cur_vblank != __get_vblank_counter(dev, pipe) && --count > 0); + + return rc; +} + /* * Reset the stored timestamp for the current vblank count to correspond * to the last vblank occurred. @@ -250,7 +265,6 @@ static void drm_reset_vblank_timestamp(struct drm_device *dev, unsigned int pipe u32 cur_vblank; bool rc; ktime_t t_vblank; - int count = DRM_TIMESTAMP_MAXRETRIES; spin_lock(&dev->vblank_time_lock); @@ -258,10 +272,8 @@ static void drm_reset_vblank_timestamp(struct drm_device *dev, unsigned int pipe * sample the current counter to avoid random jumps * when drm_vblank_enable() applies the diff */ - do { - cur_vblank = __get_vblank_counter(dev, pipe); - rc = drm_get_last_vbltimestamp(dev, pipe, &t_vblank, false); - } while (cur_vblank != __get_vblank_counter(dev, pipe) && --count > 0); + rc = get_vblank_counter_and_timestamp(dev, pipe, &cur_vblank, + &t_vblank, false); /* * Only reinitialize corresponding vblank timestamp if high-precision query @@ -299,7 +311,6 @@ static void drm_update_vblank_count(struct drm_device *dev, unsigned int pipe, u32 cur_vblank, diff; bool rc; ktime_t t_vblank; - int count = DRM_TIMESTAMP_MAXRETRIES; int framedur_ns = vblank->framedur_ns; u32 max_vblank_count = drm_max_vblank_count(dev, pipe); @@ -315,10 +326,8 @@ static void drm_update_vblank_count(struct drm_device *dev, unsigned int pipe, * updating its hardware counter while we are retrieving the * corresponding vblank timestamp. */ - do { - cur_vblank = __get_vblank_counter(dev, pipe); - rc = drm_get_last_vbltimestamp(dev, pipe, &t_vblank, in_vblank_irq); - } while (cur_vblank != __get_vblank_counter(dev, pipe) && --count > 0); + rc = get_vblank_counter_and_timestamp(dev, pipe, &cur_vblank, + &t_vblank, in_vblank_irq); if (max_vblank_count) { /* trust the hw counter when it's around */ @@ -1543,7 +1552,6 @@ static void drm_vblank_restore(struct drm_device *dev, unsigned int pipe) int framedur_ns; u64 diff_ns; u32 cur_vblank, diff = 1; - int count = DRM_TIMESTAMP_MAXRETRIES; u32 max_vblank_count = drm_max_vblank_count(dev, pipe); if (drm_WARN_ON(dev, pipe >= dev->num_crtcs)) @@ -1558,10 +1566,8 @@ static void drm_vblank_restore(struct drm_device *dev, unsigned int pipe) "Cannot compute missed vblanks without frame duration\n"); framedur_ns = vblank->framedur_ns; - do { - cur_vblank = __get_vblank_counter(dev, pipe); - drm_get_last_vbltimestamp(dev, pipe, &t_vblank, false); - } while (cur_vblank != __get_vblank_counter(dev, pipe) && --count > 0); + get_vblank_counter_and_timestamp(dev, pipe, &cur_vblank, + &t_vblank, false); diff_ns = ktime_to_ns(ktime_sub(t_vblank, vblank->time)); if (framedur_ns) -- cgit v1.2.3 From 5d9e708d2a69ab1f64a17aec810cd7c70c5b9fab Mon Sep 17 00:00:00 2001 From: Daniele Ceraolo Spurio Date: Tue, 24 Mar 2026 08:37:20 -0700 Subject: drm/xe/pxp: Clean up termination status on failure If the PXP HW termination fails during PXP start, the normal completion code won't be called, so the termination will remain uncomplete. To avoid unnecessary waits, mark the termination as completed from the error path. Note that we already do this if the termination fails when handling a termination irq from the HW. Fixes: f8caa80154c4 ("drm/xe/pxp: Add PXP queue tracking and session start") Signed-off-by: Daniele Ceraolo Spurio Cc: Alan Previn Teres Alexis Cc: Julia Filipchuk Reviewed-by: Julia Filipchuk Link: https://patch.msgid.link/20260324153718.3155504-7-daniele.ceraolospurio@intel.com --- drivers/gpu/drm/xe/xe_pxp.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/gpu/drm/xe/xe_pxp.c b/drivers/gpu/drm/xe/xe_pxp.c index e2978e48f660..b60ea85c3e11 100644 --- a/drivers/gpu/drm/xe/xe_pxp.c +++ b/drivers/gpu/drm/xe/xe_pxp.c @@ -583,6 +583,7 @@ wait_for_idle: drm_err(&pxp->xe->drm, "PXP termination failed before start\n"); mutex_lock(&pxp->mutex); pxp->status = XE_PXP_ERROR; + complete_all(&pxp->termination); goto out_unlock; } -- cgit v1.2.3 From f1b5a77fc9b6a90cd9a5e3db9d4c73ae1edfcfac Mon Sep 17 00:00:00 2001 From: Daniele Ceraolo Spurio Date: Tue, 24 Mar 2026 08:37:21 -0700 Subject: drm/xe/pxp: Remove incorrect handling of impossible state during suspend The default case of the PXP suspend switch is incorrectly exiting without releasing the lock. However, this case is impossible to hit because we're switching on an enum and all the valid enum values have their own cases. Therefore, we can just get rid of the default case and rely on the compiler to warn us if a new enum value is added and we forget to add it to the switch. Fixes: 51462211f4a9 ("drm/xe/pxp: add PXP PM support") Signed-off-by: Daniele Ceraolo Spurio Cc: Alan Previn Teres Alexis Cc: Julia Filipchuk Reviewed-by: Julia Filipchuk Link: https://patch.msgid.link/20260324153718.3155504-8-daniele.ceraolospurio@intel.com --- drivers/gpu/drm/xe/xe_pxp.c | 6 ------ 1 file changed, 6 deletions(-) diff --git a/drivers/gpu/drm/xe/xe_pxp.c b/drivers/gpu/drm/xe/xe_pxp.c index b60ea85c3e11..a054b57f5ae5 100644 --- a/drivers/gpu/drm/xe/xe_pxp.c +++ b/drivers/gpu/drm/xe/xe_pxp.c @@ -871,11 +871,6 @@ wait_for_activation: pxp->key_instance++; needs_queue_inval = true; break; - default: - drm_err(&pxp->xe->drm, "unexpected state during PXP suspend: %u", - pxp->status); - ret = -EIO; - goto out; } /* @@ -900,7 +895,6 @@ wait_for_activation: pxp->last_suspend_key_instance = pxp->key_instance; -out: return ret; } -- cgit v1.2.3 From 0850ec7bb2459602351639dccf7a68a03c9d1ee0 Mon Sep 17 00:00:00 2001 From: Daniele Ceraolo Spurio Date: Tue, 24 Mar 2026 08:37:22 -0700 Subject: drm/xe/pxp: Clear restart flag in pxp_start after jumping back If we don't clear the flag we'll keep jumping back at the beginning of the function once we reach the end. Fixes: ccd3c6820a90 ("drm/xe/pxp: Decouple queue addition from PXP start") Signed-off-by: Daniele Ceraolo Spurio Cc: Julia Filipchuk Reviewed-by: Julia Filipchuk Link: https://patch.msgid.link/20260324153718.3155504-9-daniele.ceraolospurio@intel.com --- drivers/gpu/drm/xe/xe_pxp.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/drivers/gpu/drm/xe/xe_pxp.c b/drivers/gpu/drm/xe/xe_pxp.c index a054b57f5ae5..aad3dfa3156e 100644 --- a/drivers/gpu/drm/xe/xe_pxp.c +++ b/drivers/gpu/drm/xe/xe_pxp.c @@ -512,7 +512,7 @@ static int __exec_queue_add(struct xe_pxp *pxp, struct xe_exec_queue *q) static int pxp_start(struct xe_pxp *pxp, u8 type) { int ret = 0; - bool restart = false; + bool restart; if (!xe_pxp_is_enabled(pxp)) return -ENODEV; @@ -541,6 +541,8 @@ wait_for_idle: msecs_to_jiffies(PXP_ACTIVATION_TIMEOUT_MS))) return -ETIMEDOUT; + restart = false; + mutex_lock(&pxp->mutex); /* If PXP is not already active, turn it on */ -- cgit v1.2.3 From 6eb04caaa972934c9b6cea0e0c29e466bf9a346f Mon Sep 17 00:00:00 2001 From: Daniele Ceraolo Spurio Date: Tue, 24 Mar 2026 08:37:23 -0700 Subject: drm/xe/pxp: Don't allow PXP on older PTL GSC FWs On PTL, older GSC FWs have a bug that can cause them to crash during PXP invalidation events, which leads to a complete loss of power management on the media GT. Therefore, we can't use PXP on FWs that have this bug, which was fixed in PTL GSC build 1396. Fixes: b1dcec9bd8a1 ("drm/xe/ptl: Enable PXP for PTL") Signed-off-by: Daniele Ceraolo Spurio Cc: Julia Filipchuk Reviewed-by: Julia Filipchuk Acked-by: Rodrigo Vivi Link: https://patch.msgid.link/20260324153718.3155504-10-daniele.ceraolospurio@intel.com --- drivers/gpu/drm/xe/xe_pxp.c | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/drivers/gpu/drm/xe/xe_pxp.c b/drivers/gpu/drm/xe/xe_pxp.c index aad3dfa3156e..7244090b0782 100644 --- a/drivers/gpu/drm/xe/xe_pxp.c +++ b/drivers/gpu/drm/xe/xe_pxp.c @@ -380,6 +380,18 @@ int xe_pxp_init(struct xe_device *xe) return 0; } + /* + * On PTL, older GSC FWs have a bug that can cause them to crash during + * PXP invalidation events, which leads to a complete loss of power + * management on the media GT. Therefore, we can't use PXP on FWs that + * have this bug, which was fixed in PTL GSC build 1396. + */ + if (xe->info.platform == XE_PANTHERLAKE && + gt->uc.gsc.fw.versions.found[XE_UC_FW_VER_RELEASE].build < 1396) { + drm_info(&xe->drm, "PXP requires PTL GSC build 1396 or newer\n"); + return 0; + } + pxp = drmm_kzalloc(&xe->drm, sizeof(struct xe_pxp), GFP_KERNEL); if (!pxp) { err = -ENOMEM; -- cgit v1.2.3 From e88b5cc6d6e5b1ba257f00e5c186ba137e6e8bc3 Mon Sep 17 00:00:00 2001 From: Terry Hsiao Date: Tue, 24 Mar 2026 14:14:44 +0800 Subject: drm/panel-edp: Add CSW PNB601LS1-2 and LGD LP116WHA-SPB1 The raw EDIDs for each panel: CSW - PNB601LS1-2 00 ff ff ff ff ff ff 00 0e 77 0a 11 00 00 00 00 30 23 01 04 a5 1a 0e 78 03 a1 35 9b 5e 58 91 25 1c 50 54 00 00 00 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 09 1e 56 dc 50 00 28 30 30 20 36 00 00 90 10 00 00 1a 06 14 56 dc 50 00 28 30 30 20 36 00 00 90 10 00 00 1a 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 02 00 0c 3d ff 0c 3c 7d 0e 0b 17 7d 00 00 00 00 e8 LGD - LP116WHA-SPB1 00 ff ff ff ff ff ff 00 30 e4 fe 07 01 01 00 00 00 24 01 04 a5 1a 0e 78 03 72 e5 9c 5e 5b 94 27 19 50 54 00 00 00 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 d5 21 56 a0 50 00 b2 30 30 20 f8 0c 00 90 10 00 00 1a 8e 16 56 a0 50 00 b2 30 30 20 f8 0c 00 90 10 00 00 1a 00 00 00 fd 00 28 3c 39 39 09 01 0a 20 20 20 20 20 20 00 00 00 02 00 0f 3d ff 0f 3c 7d 0d 0a 15 7d 00 00 00 01 da 70 20 79 02 00 25 00 09 57 52 01 57 52 01 28 3c 80 81 00 15 74 1a 00 00 03 01 28 3c 00 00 4a 5a 4a 5a 3c 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ef 90 Signed-off-by: Terry Hsiao Reviewed-by: Douglas Anderson Signed-off-by: Douglas Anderson Link: https://patch.msgid.link/20260324061444.242917-1-terry_hsiao@compal.corp-partner.google.com --- drivers/gpu/drm/panel/panel-edp.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/drivers/gpu/drm/panel/panel-edp.c b/drivers/gpu/drm/panel/panel-edp.c index 497dcd48f57b..f3cdaea89b29 100644 --- a/drivers/gpu/drm/panel/panel-edp.c +++ b/drivers/gpu/drm/panel/panel-edp.c @@ -2072,6 +2072,7 @@ static const struct edp_panel_entry edp_panels[] = { EDP_PANEL_ENTRY('C', 'S', 'W', 0x1100, &delay_200_500_e80_d50, "MNB601LS1-1"), EDP_PANEL_ENTRY('C', 'S', 'W', 0x1103, &delay_200_500_e80_d50, "MNB601LS1-3"), EDP_PANEL_ENTRY('C', 'S', 'W', 0x1104, &delay_200_500_e50_d100, "MNB601LS1-4"), + EDP_PANEL_ENTRY('C', 'S', 'W', 0x110a, &delay_200_500_e50, "PNB601LS1-2"), EDP_PANEL_ENTRY('C', 'S', 'W', 0x143f, &delay_200_500_e50, "MNE007QS3-6"), EDP_PANEL_ENTRY('C', 'S', 'W', 0x1448, &delay_200_500_e50, "MNE007QS3-7"), EDP_PANEL_ENTRY('C', 'S', 'W', 0x144b, &delay_200_500_e80, "MNE001BS1-4"), @@ -2119,6 +2120,7 @@ static const struct edp_panel_entry edp_panels[] = { EDP_PANEL_ENTRY('L', 'G', 'D', 0x05af, &delay_200_500_e200_d200, "Unknown"), EDP_PANEL_ENTRY('L', 'G', 'D', 0x05f1, &delay_200_500_e200_d200, "Unknown"), EDP_PANEL_ENTRY('L', 'G', 'D', 0x0778, &delay_200_500_e200_d200, "134WT1"), + EDP_PANEL_ENTRY('L', 'G', 'D', 0x07fe, &delay_200_500_e200_d200, "LP116WHA-SPB1"), EDP_PANEL_ENTRY('S', 'H', 'P', 0x1511, &delay_200_500_e50, "LQ140M1JW48"), EDP_PANEL_ENTRY('S', 'H', 'P', 0x1523, &delay_80_500_e50, "LQ140M1JW46"), -- cgit v1.2.3 From 140d5d411ab17926b47c9fce213fc065c12f8bea Mon Sep 17 00:00:00 2001 From: Zack McKevitt Date: Tue, 23 Dec 2025 18:24:25 +0100 Subject: accel/qaic: Update copyright headers to yearless format Update copyright headers in accordance with Qualcomm's current legal policy. Signed-off-by: Zack McKevitt Signed-off-by: Youssef Samir Reviewed-by: Jeff Hugo Signed-off-by: Jeff Hugo Link: https://patch.msgid.link/20251223172425.2283978-1-youssef.abdulrahman@oss.qualcomm.com --- drivers/accel/qaic/mhi_controller.c | 2 +- drivers/accel/qaic/mhi_controller.h | 9 ++++----- drivers/accel/qaic/qaic.h | 9 ++++----- drivers/accel/qaic/qaic_control.c | 2 +- drivers/accel/qaic/qaic_data.c | 2 +- drivers/accel/qaic/qaic_debugfs.c | 2 +- drivers/accel/qaic/qaic_debugfs.h | 2 +- drivers/accel/qaic/qaic_drv.c | 2 +- drivers/accel/qaic/qaic_ras.c | 1 - drivers/accel/qaic/qaic_ras.h | 1 + drivers/accel/qaic/qaic_ssr.c | 2 +- drivers/accel/qaic/qaic_ssr.h | 9 ++++----- drivers/accel/qaic/qaic_timesync.c | 3 ++- drivers/accel/qaic/qaic_timesync.h | 7 +++---- drivers/accel/qaic/sahara.c | 2 +- drivers/accel/qaic/sahara.h | 2 +- 16 files changed, 27 insertions(+), 30 deletions(-) diff --git a/drivers/accel/qaic/mhi_controller.c b/drivers/accel/qaic/mhi_controller.c index 4d787f77ce41..40e6d262ef21 100644 --- a/drivers/accel/qaic/mhi_controller.c +++ b/drivers/accel/qaic/mhi_controller.c @@ -1,7 +1,7 @@ // SPDX-License-Identifier: GPL-2.0-only /* Copyright (c) 2019-2021, The Linux Foundation. All rights reserved. */ -/* Copyright (c) 2021-2023 Qualcomm Innovation Center, Inc. All rights reserved. */ +/* Copyright (c) Qualcomm Technologies, Inc. and/or its subsidiaries. */ #include #include diff --git a/drivers/accel/qaic/mhi_controller.h b/drivers/accel/qaic/mhi_controller.h index 8939f6ae185e..c1940c839246 100644 --- a/drivers/accel/qaic/mhi_controller.h +++ b/drivers/accel/qaic/mhi_controller.h @@ -1,8 +1,7 @@ -/* SPDX-License-Identifier: GPL-2.0-only - * - * Copyright (c) 2019-2020, The Linux Foundation. All rights reserved. - * Copyright (c) 2023 Qualcomm Innovation Center, Inc. All rights reserved. - */ +/* SPDX-License-Identifier: GPL-2.0-only */ + +/* Copyright (c) 2019-2020, The Linux Foundation. All rights reserved. */ +/* Copyright (c) Qualcomm Technologies, Inc. and/or its subsidiaries. */ #ifndef MHICONTROLLERQAIC_H_ #define MHICONTROLLERQAIC_H_ diff --git a/drivers/accel/qaic/qaic.h b/drivers/accel/qaic/qaic.h index fa7a8155658c..83948358ada1 100644 --- a/drivers/accel/qaic/qaic.h +++ b/drivers/accel/qaic/qaic.h @@ -1,8 +1,7 @@ -/* SPDX-License-Identifier: GPL-2.0-only - * - * Copyright (c) 2019-2021, The Linux Foundation. All rights reserved. - * Copyright (c) 2021-2023 Qualcomm Innovation Center, Inc. All rights reserved. - */ +/* SPDX-License-Identifier: GPL-2.0-only */ + +/* Copyright (c) 2019-2021, The Linux Foundation. All rights reserved. */ +/* Copyright (c) Qualcomm Technologies, Inc. and/or its subsidiaries. */ #ifndef _QAIC_H_ #define _QAIC_H_ diff --git a/drivers/accel/qaic/qaic_control.c b/drivers/accel/qaic/qaic_control.c index f698d5dfd326..189b24693874 100644 --- a/drivers/accel/qaic/qaic_control.c +++ b/drivers/accel/qaic/qaic_control.c @@ -1,7 +1,7 @@ // SPDX-License-Identifier: GPL-2.0-only /* Copyright (c) 2019-2021, The Linux Foundation. All rights reserved. */ -/* Copyright (c) 2021-2023 Qualcomm Innovation Center, Inc. All rights reserved. */ +/* Copyright (c) Qualcomm Technologies, Inc. and/or its subsidiaries. */ #include #include diff --git a/drivers/accel/qaic/qaic_data.c b/drivers/accel/qaic/qaic_data.c index 95300c2f7d8a..b27c232021bd 100644 --- a/drivers/accel/qaic/qaic_data.c +++ b/drivers/accel/qaic/qaic_data.c @@ -1,7 +1,7 @@ // SPDX-License-Identifier: GPL-2.0-only /* Copyright (c) 2019-2021, The Linux Foundation. All rights reserved. */ -/* Copyright (c) 2021-2023 Qualcomm Innovation Center, Inc. All rights reserved. */ +/* Copyright (c) Qualcomm Technologies, Inc. and/or its subsidiaries. */ #include #include diff --git a/drivers/accel/qaic/qaic_debugfs.c b/drivers/accel/qaic/qaic_debugfs.c index 8dc4fe5bb560..5289d33744ba 100644 --- a/drivers/accel/qaic/qaic_debugfs.c +++ b/drivers/accel/qaic/qaic_debugfs.c @@ -1,7 +1,7 @@ // SPDX-License-Identifier: GPL-2.0-only /* Copyright (c) 2020, The Linux Foundation. All rights reserved. */ -/* Copyright (c) 2021-2024 Qualcomm Innovation Center, Inc. All rights reserved. */ +/* Copyright (c) Qualcomm Technologies, Inc. and/or its subsidiaries. */ #include #include diff --git a/drivers/accel/qaic/qaic_debugfs.h b/drivers/accel/qaic/qaic_debugfs.h index 05e74f84cf9f..59a002bab07c 100644 --- a/drivers/accel/qaic/qaic_debugfs.h +++ b/drivers/accel/qaic/qaic_debugfs.h @@ -1,7 +1,7 @@ /* SPDX-License-Identifier: GPL-2.0-only */ /* Copyright (c) 2020, The Linux Foundation. All rights reserved. */ -/* Copyright (c) 2024 Qualcomm Innovation Center, Inc. All rights reserved. */ +/* Copyright (c) Qualcomm Technologies, Inc. and/or its subsidiaries. */ #ifndef __QAIC_DEBUGFS_H__ #define __QAIC_DEBUGFS_H__ diff --git a/drivers/accel/qaic/qaic_drv.c b/drivers/accel/qaic/qaic_drv.c index 63fb8c7b4abc..1c7c57dabcd6 100644 --- a/drivers/accel/qaic/qaic_drv.c +++ b/drivers/accel/qaic/qaic_drv.c @@ -1,7 +1,7 @@ // SPDX-License-Identifier: GPL-2.0-only /* Copyright (c) 2019-2021, The Linux Foundation. All rights reserved. */ -/* Copyright (c) 2021-2023 Qualcomm Innovation Center, Inc. All rights reserved. */ +/* Copyright (c) Qualcomm Technologies, Inc. and/or its subsidiaries. */ #include #include diff --git a/drivers/accel/qaic/qaic_ras.c b/drivers/accel/qaic/qaic_ras.c index cc0b75461e1a..6a962c5cf048 100644 --- a/drivers/accel/qaic/qaic_ras.c +++ b/drivers/accel/qaic/qaic_ras.c @@ -1,7 +1,6 @@ // SPDX-License-Identifier: GPL-2.0-only /* Copyright (c) 2020-2021, The Linux Foundation. All rights reserved. */ -/* Copyright (c) 2022-2024 Qualcomm Innovation Center, Inc. All rights reserved. */ /* Copyright (c) Qualcomm Technologies, Inc. and/or its subsidiaries. */ #include diff --git a/drivers/accel/qaic/qaic_ras.h b/drivers/accel/qaic/qaic_ras.h index d44a4eeeb060..7b3fe9585ed9 100644 --- a/drivers/accel/qaic/qaic_ras.h +++ b/drivers/accel/qaic/qaic_ras.h @@ -1,4 +1,5 @@ /* SPDX-License-Identifier: GPL-2.0-only */ + /* Copyright (c) 2020, The Linux Foundation. All rights reserved. */ #ifndef __QAIC_RAS_H__ diff --git a/drivers/accel/qaic/qaic_ssr.c b/drivers/accel/qaic/qaic_ssr.c index a5bb6078824b..a98928654959 100644 --- a/drivers/accel/qaic/qaic_ssr.c +++ b/drivers/accel/qaic/qaic_ssr.c @@ -1,7 +1,7 @@ // SPDX-License-Identifier: GPL-2.0-only /* Copyright (c) 2020-2021, The Linux Foundation. All rights reserved. */ -/* Copyright (c) 2021-2024 Qualcomm Innovation Center, Inc. All rights reserved. */ +/* Copyright (c) Qualcomm Technologies, Inc. and/or its subsidiaries. */ #include #include diff --git a/drivers/accel/qaic/qaic_ssr.h b/drivers/accel/qaic/qaic_ssr.h index 97ccff305750..af074edbf967 100644 --- a/drivers/accel/qaic/qaic_ssr.h +++ b/drivers/accel/qaic/qaic_ssr.h @@ -1,8 +1,7 @@ -/* SPDX-License-Identifier: GPL-2.0-only - * - * Copyright (c) 2020, The Linux Foundation. All rights reserved. - * Copyright (c) 2021, 2024 Qualcomm Innovation Center, Inc. All rights reserved. - */ +/* SPDX-License-Identifier: GPL-2.0-only */ + +/* Copyright (c) 2020, The Linux Foundation. All rights reserved. */ +/* Copyright (c) Qualcomm Technologies, Inc. and/or its subsidiaries. */ #ifndef __QAIC_SSR_H__ #define __QAIC_SSR_H__ diff --git a/drivers/accel/qaic/qaic_timesync.c b/drivers/accel/qaic/qaic_timesync.c index 939462b9958d..9faf71f47bdc 100644 --- a/drivers/accel/qaic/qaic_timesync.c +++ b/drivers/accel/qaic/qaic_timesync.c @@ -1,5 +1,6 @@ // SPDX-License-Identifier: GPL-2.0-only -/* Copyright (c) 2023 Qualcomm Innovation Center, Inc. All rights reserved. */ + +/* Copyright (c) Qualcomm Technologies, Inc. and/or its subsidiaries. */ #include #include diff --git a/drivers/accel/qaic/qaic_timesync.h b/drivers/accel/qaic/qaic_timesync.h index 77b9c2b55057..6aeda1d62a35 100644 --- a/drivers/accel/qaic/qaic_timesync.h +++ b/drivers/accel/qaic/qaic_timesync.h @@ -1,7 +1,6 @@ -/* SPDX-License-Identifier: GPL-2.0-only - * - * Copyright (c) 2023 Qualcomm Innovation Center, Inc. All rights reserved. - */ +/* SPDX-License-Identifier: GPL-2.0-only */ + +/* Copyright (c) Qualcomm Technologies, Inc. and/or its subsidiaries. */ #ifndef __QAIC_TIMESYNC_H__ #define __QAIC_TIMESYNC_H__ diff --git a/drivers/accel/qaic/sahara.c b/drivers/accel/qaic/sahara.c index fd3c3b2d1fd3..9fea294e1d7b 100644 --- a/drivers/accel/qaic/sahara.c +++ b/drivers/accel/qaic/sahara.c @@ -1,6 +1,6 @@ // SPDX-License-Identifier: GPL-2.0-only -/* Copyright (c) 2024 Qualcomm Innovation Center, Inc. All rights reserved. */ +/* Copyright (c) Qualcomm Technologies, Inc. and/or its subsidiaries. */ #include #include diff --git a/drivers/accel/qaic/sahara.h b/drivers/accel/qaic/sahara.h index 640208acc0d1..08037281c80e 100644 --- a/drivers/accel/qaic/sahara.h +++ b/drivers/accel/qaic/sahara.h @@ -1,6 +1,6 @@ /* SPDX-License-Identifier: GPL-2.0-only */ -/* Copyright (c) 2024 Qualcomm Innovation Center, Inc. All rights reserved. */ +/* Copyright (c) Qualcomm Technologies, Inc. and/or its subsidiaries. */ #ifndef __SAHARA_H__ #define __SAHARA_H__ -- cgit v1.2.3 From 92f210c019ac29e72006070f75860448f91d9ddc Mon Sep 17 00:00:00 2001 From: Troy Hanson Date: Tue, 23 Dec 2025 18:02:26 +0100 Subject: accel/qaic: Simplify bootlog line handling Instead of storing and emitting bootlogs as individual null-terminated lines, concatenate them, and later emit them to debugfs in a single call. Do not insert a null terminator on messages received from the device. Instead use the message length when subsequently storing the message. Exclude trailing nulls to normalize AIC100 and AIC200 bootlog lines. Signed-off-by: Troy Hanson Signed-off-by: Youssef Samir Reviewed-by: Jeff Hugo Signed-off-by: Jeff Hugo Link: https://patch.msgid.link/20251223170226.2275812-1-youssef.abdulrahman@oss.qualcomm.com --- drivers/accel/qaic/qaic_debugfs.c | 25 +++++++++++++------------ 1 file changed, 13 insertions(+), 12 deletions(-) diff --git a/drivers/accel/qaic/qaic_debugfs.c b/drivers/accel/qaic/qaic_debugfs.c index 5289d33744ba..eca0b1fa1c14 100644 --- a/drivers/accel/qaic/qaic_debugfs.c +++ b/drivers/accel/qaic/qaic_debugfs.c @@ -27,6 +27,8 @@ struct bootlog_msg { /* Buffer for bootlog messages */ char str[BOOTLOG_MSG_SIZE]; + /* Length of bootlog message */ + size_t len; /* Root struct of device, used to access device resources */ struct qaic_device *qdev; /* Work struct to schedule work coming on QAIC_LOGGING channel */ @@ -46,18 +48,15 @@ static int bootlog_show(struct seq_file *s, void *unused) { struct bootlog_page *page; struct qaic_device *qdev; - void *page_end; + size_t len; void *log; qdev = s->private; mutex_lock(&qdev->bootlog_mutex); list_for_each_entry(page, &qdev->bootlog, node) { log = page + 1; - page_end = (void *)page + page->offset; - while (log < page_end) { - seq_printf(s, "%s", (char *)log); - log += strlen(log) + 1; - } + len = page->offset - sizeof(*page); + seq_write(s, log, len); } mutex_unlock(&qdev->bootlog_mutex); @@ -182,15 +181,14 @@ static void bootlog_commit(struct qaic_device *qdev, unsigned int size) static void bootlog_log(struct work_struct *work) { struct bootlog_msg *msg = container_of(work, struct bootlog_msg, work); - unsigned int len = strlen(msg->str) + 1; struct qaic_device *qdev = msg->qdev; void *log; mutex_lock(&qdev->bootlog_mutex); - log = bootlog_get_space(qdev, len); + log = bootlog_get_space(qdev, msg->len); if (log) { - memcpy(log, msg, len); - bootlog_commit(qdev, len); + memcpy(log, msg, msg->len); + bootlog_commit(qdev, msg->len); } mutex_unlock(&qdev->bootlog_mutex); @@ -271,8 +269,11 @@ static void qaic_bootlog_mhi_dl_xfer_cb(struct mhi_device *mhi_dev, struct mhi_r return; } - /* Force a null at the end of the transferred string */ - msg->str[mhi_result->bytes_xferd - 1] = 0; + msg->len = mhi_result->bytes_xferd; + + /* Exclude trailing null to normalize AIC100/AIC200 line endings */ + if (msg->len && msg->str[msg->len - 1] == '\0') + msg->len--; queue_work(qdev->bootlog_wq, &msg->work); } -- cgit v1.2.3 From dac97a6bd6c4a24e60a147cb2cf750eddb7594a8 Mon Sep 17 00:00:00 2001 From: Zack McKevitt Date: Tue, 23 Dec 2025 18:05:11 +0100 Subject: accel/qaic: Retain bootlogs that overflow When a bootlog requires multiple MHI messages to transfer fully, the messages prior to the final message may have MHI overflow status set. Preserve these log messages in the accumulating bootlog. Do not treat overflow as an error. Signed-off-by: Zack McKevitt Signed-off-by: Troy Hanson Signed-off-by: Youssef Samir Reviewed-by: Jeff Hugo Signed-off-by: Jeff Hugo Link: https://patch.msgid.link/20251223170511.2277302-1-youssef.abdulrahman@oss.qualcomm.com --- drivers/accel/qaic/qaic_debugfs.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/drivers/accel/qaic/qaic_debugfs.c b/drivers/accel/qaic/qaic_debugfs.c index eca0b1fa1c14..95c78e12dd61 100644 --- a/drivers/accel/qaic/qaic_debugfs.c +++ b/drivers/accel/qaic/qaic_debugfs.c @@ -263,8 +263,9 @@ static void qaic_bootlog_mhi_dl_xfer_cb(struct mhi_device *mhi_dev, struct mhi_r { struct qaic_device *qdev = dev_get_drvdata(&mhi_dev->dev); struct bootlog_msg *msg = mhi_result->buf_addr; + int status = mhi_result->transaction_status; - if (mhi_result->transaction_status) { + if (status && status != -EOVERFLOW) { devm_kfree(&qdev->pdev->dev, msg); return; } -- cgit v1.2.3 From 2247feb9badca5a4774df9a437bfc44fba4f22de Mon Sep 17 00:00:00 2001 From: Matthew Brost Date: Thu, 26 Feb 2026 17:52:25 -0800 Subject: drm/xe: Disable garbage collector work item on SVM close MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit When an SVM is closed, the garbage collector work item must be stopped synchronously and any future queuing must be prevented. Replace flush_work() with disable_work_sync() to ensure both conditions are met. Fixes: 63f6e480d115 ("drm/xe: Add SVM garbage collector") Cc: stable@vger.kernel.org Signed-off-by: Matthew Brost Reviewed-by: Thomas Hellström Link: https://patch.msgid.link/20260227015225.3081787-1-matthew.brost@intel.com --- drivers/gpu/drm/xe/xe_svm.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/gpu/drm/xe/xe_svm.c b/drivers/gpu/drm/xe/xe_svm.c index 5b627eed1eab..5933b2b6392b 100644 --- a/drivers/gpu/drm/xe/xe_svm.c +++ b/drivers/gpu/drm/xe/xe_svm.c @@ -931,7 +931,7 @@ int xe_svm_init(struct xe_vm *vm) void xe_svm_close(struct xe_vm *vm) { xe_assert(vm->xe, xe_vm_is_closed(vm)); - flush_work(&vm->svm.garbage_collector.work); + disable_work_sync(&vm->svm.garbage_collector.work); xe_svm_put_pagemaps(vm); drm_pagemap_release_owner(&vm->svm.peer); } -- cgit v1.2.3 From b08ceb443866808b881b12d4183008d214d816c1 Mon Sep 17 00:00:00 2001 From: Matthew Brost Date: Thu, 26 Mar 2026 14:01:15 -0700 Subject: drm/xe: Avoid memory allocations in xe_device_declare_wedged() xe_device_declare_wedged() runs in the DMA-fence signaling path, where GFP_KERNEL memory allocations are not allowed. However, registering xe_device_wedged_fini via drmm_add_action_or_reset() triggers a GFP_KERNEL allocation. Fix this by deferring the registration of xe_device_wedged_fini until late in the driver load sequence. Additionally, drop the wedged PM reference only if the device is actually wedged in xe_device_wedged_fini. Fixes: 452bca0edbd0 ("drm/xe: Don't suspend device upon wedge") Signed-off-by: Matthew Brost Reviewed-by: Rodrigo Vivi Link: https://patch.msgid.link/20260326210116.202585-2-matthew.brost@intel.com --- drivers/gpu/drm/xe/xe_device.c | 27 +++++++++++++-------------- 1 file changed, 13 insertions(+), 14 deletions(-) diff --git a/drivers/gpu/drm/xe/xe_device.c b/drivers/gpu/drm/xe/xe_device.c index 44d04ac0951a..91327f43a04d 100644 --- a/drivers/gpu/drm/xe/xe_device.c +++ b/drivers/gpu/drm/xe/xe_device.c @@ -833,6 +833,14 @@ static void detect_preproduction_hw(struct xe_device *xe) } } +static void xe_device_wedged_fini(struct drm_device *drm, void *arg) +{ + struct xe_device *xe = arg; + + if (atomic_read(&xe->wedged.flag)) + xe_pm_runtime_put(xe); +} + int xe_device_probe(struct xe_device *xe) { struct xe_tile *tile; @@ -1009,6 +1017,10 @@ int xe_device_probe(struct xe_device *xe) detect_preproduction_hw(xe); + err = drmm_add_action_or_reset(&xe->drm, xe_device_wedged_fini, xe); + if (err) + goto err_unregister_display; + return devm_add_action_or_reset(xe->drm.dev, xe_device_sanitize, xe); err_unregister_display: @@ -1240,13 +1252,6 @@ u64 xe_device_uncanonicalize_addr(struct xe_device *xe, u64 address) return address & GENMASK_ULL(xe->info.va_bits - 1, 0); } -static void xe_device_wedged_fini(struct drm_device *drm, void *arg) -{ - struct xe_device *xe = arg; - - xe_pm_runtime_put(xe); -} - /** * DOC: Xe Device Wedging * @@ -1324,15 +1329,9 @@ void xe_device_declare_wedged(struct xe_device *xe) return; } - xe_pm_runtime_get_noresume(xe); - - if (drmm_add_action_or_reset(&xe->drm, xe_device_wedged_fini, xe)) { - drm_err(&xe->drm, "Failed to register xe_device_wedged_fini clean-up. Although device is wedged.\n"); - return; - } - if (!atomic_xchg(&xe->wedged.flag, 1)) { xe->needs_flr_on_fini = true; + xe_pm_runtime_get_noresume(xe); drm_err(&xe->drm, "CRITICAL: Xe has declared device %s as wedged.\n" "IOCTLs and executions are blocked.\n" -- cgit v1.2.3 From 4a706bd93c4fb156a13477e26ffdf2e633edeb10 Mon Sep 17 00:00:00 2001 From: Matthew Brost Date: Thu, 26 Mar 2026 14:01:16 -0700 Subject: drm/xe: Drop registration of guc_submit_wedged_fini from xe_guc_submit_wedge() xe_guc_submit_wedge() runs in the DMA-fence signaling path, where GFP_KERNEL memory allocations are not permitted. However, registering guc_submit_wedged_fini via drmm_add_action_or_reset() triggers such an allocation. Avoid this by moving the logic from guc_submit_wedged_fini() into guc_submit_fini(), where wedged exec queue references are dropped during normal teardown. Fixes: 8ed9aaae39f3 ("drm/xe: Force wedged state and block GT reset upon any GPU hang") Signed-off-by: Matthew Brost Reviewed-by: Rodrigo Vivi Link: https://patch.msgid.link/20260326210116.202585-3-matthew.brost@intel.com --- drivers/gpu/drm/xe/xe_guc_submit.c | 33 +++++++++------------------------ 1 file changed, 9 insertions(+), 24 deletions(-) diff --git a/drivers/gpu/drm/xe/xe_guc_submit.c b/drivers/gpu/drm/xe/xe_guc_submit.c index a145234f662b..10556156eaad 100644 --- a/drivers/gpu/drm/xe/xe_guc_submit.c +++ b/drivers/gpu/drm/xe/xe_guc_submit.c @@ -259,24 +259,12 @@ static void guc_submit_sw_fini(struct drm_device *drm, void *arg) } static void guc_submit_fini(void *arg) -{ - struct xe_guc *guc = arg; - - /* Forcefully kill any remaining exec queues */ - xe_guc_ct_stop(&guc->ct); - guc_submit_reset_prepare(guc); - xe_guc_softreset(guc); - xe_guc_submit_stop(guc); - xe_uc_fw_sanitize(&guc->fw); - xe_guc_submit_pause_abort(guc); -} - -static void guc_submit_wedged_fini(void *arg) { struct xe_guc *guc = arg; struct xe_exec_queue *q; unsigned long index; + /* Drop any wedged queue refs */ mutex_lock(&guc->submission_state.lock); xa_for_each(&guc->submission_state.exec_queue_lookup, index, q) { if (exec_queue_wedged(q)) { @@ -286,6 +274,14 @@ static void guc_submit_wedged_fini(void *arg) } } mutex_unlock(&guc->submission_state.lock); + + /* Forcefully kill any remaining exec queues */ + xe_guc_ct_stop(&guc->ct); + guc_submit_reset_prepare(guc); + xe_guc_softreset(guc); + xe_guc_submit_stop(guc); + xe_uc_fw_sanitize(&guc->fw); + xe_guc_submit_pause_abort(guc); } static const struct xe_exec_queue_ops guc_exec_queue_ops; @@ -1320,10 +1316,8 @@ static void disable_scheduling_deregister(struct xe_guc *guc, void xe_guc_submit_wedge(struct xe_guc *guc) { struct xe_device *xe = guc_to_xe(guc); - struct xe_gt *gt = guc_to_gt(guc); struct xe_exec_queue *q; unsigned long index; - int err; xe_gt_assert(guc_to_gt(guc), guc_to_xe(guc)->wedged.mode); @@ -1335,15 +1329,6 @@ void xe_guc_submit_wedge(struct xe_guc *guc) return; if (xe->wedged.mode == XE_WEDGED_MODE_UPON_ANY_HANG_NO_RESET) { - err = devm_add_action_or_reset(guc_to_xe(guc)->drm.dev, - guc_submit_wedged_fini, guc); - if (err) { - xe_gt_err(gt, "Failed to register clean-up on wedged.mode=%s; " - "Although device is wedged.\n", - xe_wedged_mode_to_string(XE_WEDGED_MODE_UPON_ANY_HANG_NO_RESET)); - return; - } - mutex_lock(&guc->submission_state.lock); xa_for_each(&guc->submission_state.exec_queue_lookup, index, q) if (xe_exec_queue_get_unless_zero(q)) -- cgit v1.2.3 From f9f0df23193a8afee3bfb5fc34970c93792d7163 Mon Sep 17 00:00:00 2001 From: Rosen Penev Date: Tue, 10 Mar 2026 17:37:44 -0700 Subject: mailbox: rockchip: kzalloc + kcalloc to kzalloc Use a flexible array member to reduce allocations. Signed-off-by: Rosen Penev Signed-off-by: Jassi Brar --- drivers/mailbox/rockchip-mailbox.c | 9 ++------- 1 file changed, 2 insertions(+), 7 deletions(-) diff --git a/drivers/mailbox/rockchip-mailbox.c b/drivers/mailbox/rockchip-mailbox.c index 4d966cb2ed03..a1a7dee64356 100644 --- a/drivers/mailbox/rockchip-mailbox.c +++ b/drivers/mailbox/rockchip-mailbox.c @@ -46,7 +46,7 @@ struct rockchip_mbox { /* The maximum size of buf for each channel */ u32 buf_size; - struct rockchip_mbox_chan *chans; + struct rockchip_mbox_chan chans[]; }; static int rockchip_mbox_send_data(struct mbox_chan *chan, void *data) @@ -173,15 +173,10 @@ static int rockchip_mbox_probe(struct platform_device *pdev) drv_data = (const struct rockchip_mbox_data *) device_get_match_data(&pdev->dev); - mb = devm_kzalloc(&pdev->dev, sizeof(*mb), GFP_KERNEL); + mb = devm_kzalloc(&pdev->dev, struct_size(mb, chans, drv_data->num_chans), GFP_KERNEL); if (!mb) return -ENOMEM; - mb->chans = devm_kcalloc(&pdev->dev, drv_data->num_chans, - sizeof(*mb->chans), GFP_KERNEL); - if (!mb->chans) - return -ENOMEM; - mb->mbox.chans = devm_kcalloc(&pdev->dev, drv_data->num_chans, sizeof(*mb->mbox.chans), GFP_KERNEL); if (!mb->mbox.chans) -- cgit v1.2.3 From df1de2abf907ab4fef991eaddab1981c1a9354cf Mon Sep 17 00:00:00 2001 From: Rosen Penev Date: Tue, 10 Mar 2026 17:35:59 -0700 Subject: mailbox: hi6220: kzalloc + kcalloc to kzalloc Reduce allocations to a single one by using a flexible array member. Allows using __counted_by for extra runtime analysis. Signed-off-by: Rosen Penev Signed-off-by: Jassi Brar --- drivers/mailbox/hi6220-mailbox.c | 14 +++++--------- 1 file changed, 5 insertions(+), 9 deletions(-) diff --git a/drivers/mailbox/hi6220-mailbox.c b/drivers/mailbox/hi6220-mailbox.c index f77741ce42e7..69d15b6283e9 100644 --- a/drivers/mailbox/hi6220-mailbox.c +++ b/drivers/mailbox/hi6220-mailbox.c @@ -79,12 +79,12 @@ struct hi6220_mbox { /* region for mailbox */ void __iomem *base; - unsigned int chan_num; - struct hi6220_mbox_chan *mchan; - void *irq_map_chan[MBOX_CHAN_MAX]; struct mbox_chan *chan; struct mbox_controller controller; + + unsigned int chan_num; + struct hi6220_mbox_chan mchan[] __counted_by(chan_num); }; static void mbox_set_state(struct hi6220_mbox *mbox, @@ -267,16 +267,12 @@ static int hi6220_mbox_probe(struct platform_device *pdev) struct hi6220_mbox *mbox; int i, err; - mbox = devm_kzalloc(dev, sizeof(*mbox), GFP_KERNEL); + mbox = devm_kzalloc(dev, struct_size(mbox, mchan, MBOX_CHAN_MAX), GFP_KERNEL); if (!mbox) return -ENOMEM; - mbox->dev = dev; mbox->chan_num = MBOX_CHAN_MAX; - mbox->mchan = devm_kcalloc(dev, - mbox->chan_num, sizeof(*mbox->mchan), GFP_KERNEL); - if (!mbox->mchan) - return -ENOMEM; + mbox->dev = dev; mbox->chan = devm_kcalloc(dev, mbox->chan_num, sizeof(*mbox->chan), GFP_KERNEL); -- cgit v1.2.3 From 1e0ec9719f58d53da61adf830e81f4af892e4582 Mon Sep 17 00:00:00 2001 From: Felix Gu Date: Thu, 26 Feb 2026 00:33:24 +0800 Subject: mailbox: mtk-vcp-mailbox: Fix the return value in mtk_vcp_mbox_xlate() The return value of mtk_vcp_mbox_xlate() is checked by IS_ERR(), so return NULL is incorrect and could lead to a NULL pointer dereference. Fixes: b562abd95672 ("mailbox: mediatek: Add mtk-vcp-mailbox driver") Signed-off-by: Felix Gu Signed-off-by: Jassi Brar --- drivers/mailbox/mtk-vcp-mailbox.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/mailbox/mtk-vcp-mailbox.c b/drivers/mailbox/mtk-vcp-mailbox.c index cedad575528f..1b291b8ea15a 100644 --- a/drivers/mailbox/mtk-vcp-mailbox.c +++ b/drivers/mailbox/mtk-vcp-mailbox.c @@ -50,7 +50,7 @@ static struct mbox_chan *mtk_vcp_mbox_xlate(struct mbox_controller *mbox, const struct of_phandle_args *sp) { if (sp->args_count) - return NULL; + return ERR_PTR(-EINVAL); return &mbox->chans[0]; } -- cgit v1.2.3 From d2591db9c8ef19fbb4d24ed15e0c6edfa6bc7917 Mon Sep 17 00:00:00 2001 From: Jason-JH Lin Date: Mon, 23 Mar 2026 17:07:11 +0800 Subject: mailbox: mtk-cmdq: Fix CURR and END addr for task insert case Fix CURR and END address calculation for inserting a cmdq task into the task list by using cmdq_reg_shift_addr() for proper address converting. This ensures both CURR and END addresses are set correctly when enabling the thread. Fixes: a195c7ccfb7a ("mailbox: mtk-cmdq: Refine DMA address handling for the command buffer") Signed-off-by: Jason-JH Lin Signed-off-by: Jassi Brar --- drivers/mailbox/mtk-cmdq-mailbox.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/drivers/mailbox/mtk-cmdq-mailbox.c b/drivers/mailbox/mtk-cmdq-mailbox.c index d7c6b38888a3..547a10a8fad3 100644 --- a/drivers/mailbox/mtk-cmdq-mailbox.c +++ b/drivers/mailbox/mtk-cmdq-mailbox.c @@ -493,14 +493,14 @@ static int cmdq_mbox_send_data(struct mbox_chan *chan, void *data) if (curr_pa == end_pa - CMDQ_INST_SIZE || curr_pa == end_pa) { /* set to this task directly */ - writel(task->pa_base >> cmdq->pdata->shift, - thread->base + CMDQ_THR_CURR_ADDR); + gce_addr = cmdq_convert_gce_addr(task->pa_base, cmdq->pdata); + writel(gce_addr, thread->base + CMDQ_THR_CURR_ADDR); } else { cmdq_task_insert_into_thread(task); smp_mb(); /* modify jump before enable thread */ } - writel((task->pa_base + pkt->cmd_buf_size) >> cmdq->pdata->shift, - thread->base + CMDQ_THR_END_ADDR); + gce_addr = cmdq_convert_gce_addr(task->pa_base + pkt->cmd_buf_size, cmdq->pdata); + writel(gce_addr, thread->base + CMDQ_THR_END_ADDR); cmdq_thread_resume(thread); } list_move_tail(&task->list_entry, &thread->task_busy_list); -- cgit v1.2.3 From 8a19c5aa2f04c38926318d128f57f0c350bab4c6 Mon Sep 17 00:00:00 2001 From: Wolfram Sang Date: Fri, 27 Mar 2026 16:12:46 +0100 Subject: mailbox: exynos: drop superfluous mbox setting per channel The core initializes the 'mbox' field exactly like this, so don't duplicate it in the driver. Signed-off-by: Wolfram Sang Reviewed-by: Tudor Ambarus Tested-by: Tudor Ambarus Signed-off-by: Jassi Brar --- drivers/mailbox/exynos-mailbox.c | 4 ---- 1 file changed, 4 deletions(-) diff --git a/drivers/mailbox/exynos-mailbox.c b/drivers/mailbox/exynos-mailbox.c index 5f2d3b81c1db..d2355b128ba4 100644 --- a/drivers/mailbox/exynos-mailbox.c +++ b/drivers/mailbox/exynos-mailbox.c @@ -99,7 +99,6 @@ static int exynos_mbox_probe(struct platform_device *pdev) struct mbox_controller *mbox; struct mbox_chan *chans; struct clk *pclk; - int i; exynos_mbox = devm_kzalloc(dev, sizeof(*exynos_mbox), GFP_KERNEL); if (!exynos_mbox) @@ -129,9 +128,6 @@ static int exynos_mbox_probe(struct platform_device *pdev) mbox->ops = &exynos_mbox_chan_ops; mbox->of_xlate = exynos_mbox_of_xlate; - for (i = 0; i < EXYNOS_MBOX_CHAN_COUNT; i++) - chans[i].mbox = mbox; - exynos_mbox->mbox = mbox; platform_set_drvdata(pdev, exynos_mbox); -- cgit v1.2.3 From 9efbbf810ee3e50360daa83cb8e0cc5ab998cef3 Mon Sep 17 00:00:00 2001 From: Wolfram Sang Date: Fri, 27 Mar 2026 16:11:44 +0100 Subject: mailbox: test: really ignore optional memory resources Memory resources are optional but if the resource is empty devm_platform_get_and_ioremap_resource() prints an error nonetheless. Refactor the code to check the resources locally first and process them only if they are present. The -EBUSY error message of ioremap_resource() is still kept because it is correct. The comment which explains that a plain ioremap() is tried as a workaround is turned into a info message. So, a user will be informed about it, too. Signed-off-by: Wolfram Sang Reviewed-by: Geert Uytterhoeven Signed-off-by: Jassi Brar --- drivers/mailbox/mailbox-test.c | 37 +++++++++++++++++++++---------------- 1 file changed, 21 insertions(+), 16 deletions(-) diff --git a/drivers/mailbox/mailbox-test.c b/drivers/mailbox/mailbox-test.c index 3a28ab5c42e5..058c0fe4b9c2 100644 --- a/drivers/mailbox/mailbox-test.c +++ b/drivers/mailbox/mailbox-test.c @@ -355,11 +355,27 @@ mbox_test_request_channel(struct platform_device *pdev, const char *name) return channel; } +static void __iomem *mbox_test_ioremap(struct platform_device *pdev, unsigned int res_num) +{ + struct resource *res; + void __iomem *mmio; + + res = platform_get_resource(pdev, IORESOURCE_MEM, res_num); + if (!res) + return NULL; + + mmio = devm_ioremap_resource(&pdev->dev, res); + if (PTR_ERR(mmio) == -EBUSY) { + dev_info(&pdev->dev, "trying workaround with plain ioremap\n"); + return devm_ioremap(&pdev->dev, res->start, resource_size(res)); + } + + return IS_ERR(mmio) ? NULL : mmio; +} + static int mbox_test_probe(struct platform_device *pdev) { struct mbox_test_device *tdev; - struct resource *res; - resource_size_t size; int ret; tdev = devm_kzalloc(&pdev->dev, sizeof(*tdev), GFP_KERNEL); @@ -367,23 +383,12 @@ static int mbox_test_probe(struct platform_device *pdev) return -ENOMEM; /* It's okay for MMIO to be NULL */ - tdev->tx_mmio = devm_platform_get_and_ioremap_resource(pdev, 0, &res); - if (PTR_ERR(tdev->tx_mmio) == -EBUSY) { - /* if reserved area in SRAM, try just ioremap */ - size = resource_size(res); - tdev->tx_mmio = devm_ioremap(&pdev->dev, res->start, size); - } else if (IS_ERR(tdev->tx_mmio)) { - tdev->tx_mmio = NULL; - } + tdev->tx_mmio = mbox_test_ioremap(pdev, 0); /* If specified, second reg entry is Rx MMIO */ - tdev->rx_mmio = devm_platform_get_and_ioremap_resource(pdev, 1, &res); - if (PTR_ERR(tdev->rx_mmio) == -EBUSY) { - size = resource_size(res); - tdev->rx_mmio = devm_ioremap(&pdev->dev, res->start, size); - } else if (IS_ERR(tdev->rx_mmio)) { + tdev->rx_mmio = mbox_test_ioremap(pdev, 1); + if (!tdev->rx_mmio) tdev->rx_mmio = tdev->tx_mmio; - } tdev->tx_channel = mbox_test_request_channel(pdev, "tx"); tdev->rx_channel = mbox_test_request_channel(pdev, "rx"); -- cgit v1.2.3 From d81e6703b8f12bbb885967933d1730600bce02c7 Mon Sep 17 00:00:00 2001 From: Wolfram Sang Date: Mon, 23 Feb 2026 13:21:33 +0100 Subject: mailbox: correct kdoc title for mbox_bind_client "Request" is wrong, there is a separate function for requesting. This functions binds, so describe this. Signed-off-by: Wolfram Sang Signed-off-by: Jassi Brar --- drivers/mailbox/mailbox.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/mailbox/mailbox.c b/drivers/mailbox/mailbox.c index 354434cd1209..03473ae41ed1 100644 --- a/drivers/mailbox/mailbox.c +++ b/drivers/mailbox/mailbox.c @@ -364,7 +364,7 @@ static int __mbox_bind_client(struct mbox_chan *chan, struct mbox_client *cl) } /** - * mbox_bind_client - Request a mailbox channel. + * mbox_bind_client - Bind client to a mailbox channel. * @chan: The mailbox channel to bind the client to. * @cl: Identity of the client requesting the channel. * -- cgit v1.2.3 From 89e5d7d616009e5fada5da081b1d79cdd59150ab Mon Sep 17 00:00:00 2001 From: Wolfram Sang Date: Fri, 27 Mar 2026 16:10:21 +0100 Subject: mailbox: remove superfluous internal header Quite some controller drivers use the defines from the internal header already. This prevents controller drivers outside the mailbox directory. Move the defines to the public controller header to allow this again as the defines are not strictly internal anyhow. Signed-off-by: Wolfram Sang Reviewed-by: Sudeep Holla Reviewed-by: Daniel Baluta Signed-off-by: Jassi Brar --- drivers/mailbox/cix-mailbox.c | 2 -- drivers/mailbox/hi3660-mailbox.c | 2 -- drivers/mailbox/imx-mailbox.c | 2 -- drivers/mailbox/mailbox-sti.c | 2 -- drivers/mailbox/mailbox.c | 2 -- drivers/mailbox/mailbox.h | 12 ------------ drivers/mailbox/omap-mailbox.c | 2 -- drivers/mailbox/pcc.c | 2 -- drivers/mailbox/tegra-hsp.c | 2 -- include/linux/mailbox_controller.h | 5 +++++ 10 files changed, 5 insertions(+), 28 deletions(-) delete mode 100644 drivers/mailbox/mailbox.h diff --git a/drivers/mailbox/cix-mailbox.c b/drivers/mailbox/cix-mailbox.c index 443620e8ae37..864f98f21fc3 100644 --- a/drivers/mailbox/cix-mailbox.c +++ b/drivers/mailbox/cix-mailbox.c @@ -12,8 +12,6 @@ #include #include -#include "mailbox.h" - /* * The maximum transmission size is 32 words or 128 bytes. */ diff --git a/drivers/mailbox/hi3660-mailbox.c b/drivers/mailbox/hi3660-mailbox.c index 17c29e960fbf..9b727a2b54a5 100644 --- a/drivers/mailbox/hi3660-mailbox.c +++ b/drivers/mailbox/hi3660-mailbox.c @@ -15,8 +15,6 @@ #include #include -#include "mailbox.h" - #define MBOX_CHAN_MAX 32 #define MBOX_RX 0x0 diff --git a/drivers/mailbox/imx-mailbox.c b/drivers/mailbox/imx-mailbox.c index 003f9236c35e..22331b579489 100644 --- a/drivers/mailbox/imx-mailbox.c +++ b/drivers/mailbox/imx-mailbox.c @@ -23,8 +23,6 @@ #include #include -#include "mailbox.h" - #define IMX_MU_CHANS 24 /* TX0/RX0/RXDB[0-3] */ #define IMX_MU_SCU_CHANS 6 diff --git a/drivers/mailbox/mailbox-sti.c b/drivers/mailbox/mailbox-sti.c index b4b5bdd503cf..b6c9ecbbc8ec 100644 --- a/drivers/mailbox/mailbox-sti.c +++ b/drivers/mailbox/mailbox-sti.c @@ -21,8 +21,6 @@ #include #include -#include "mailbox.h" - #define STI_MBOX_INST_MAX 4 /* RAM saving: Max supported instances */ #define STI_MBOX_CHAN_MAX 20 /* RAM saving: Max supported channels */ diff --git a/drivers/mailbox/mailbox.c b/drivers/mailbox/mailbox.c index 03473ae41ed1..13de3d047853 100644 --- a/drivers/mailbox/mailbox.c +++ b/drivers/mailbox/mailbox.c @@ -18,8 +18,6 @@ #include #include -#include "mailbox.h" - static LIST_HEAD(mbox_cons); static DEFINE_MUTEX(con_mutex); diff --git a/drivers/mailbox/mailbox.h b/drivers/mailbox/mailbox.h deleted file mode 100644 index e1ec4efab693..000000000000 --- a/drivers/mailbox/mailbox.h +++ /dev/null @@ -1,12 +0,0 @@ -/* SPDX-License-Identifier: GPL-2.0-only */ - -#ifndef __MAILBOX_H -#define __MAILBOX_H - -#include - -#define TXDONE_BY_IRQ BIT(0) /* controller has remote RTR irq */ -#define TXDONE_BY_POLL BIT(1) /* controller can read status of last TX */ -#define TXDONE_BY_ACK BIT(2) /* S/W ACK received by Client ticks the TX */ - -#endif /* __MAILBOX_H */ diff --git a/drivers/mailbox/omap-mailbox.c b/drivers/mailbox/omap-mailbox.c index d9f100c18895..5772c6b9886a 100644 --- a/drivers/mailbox/omap-mailbox.c +++ b/drivers/mailbox/omap-mailbox.c @@ -22,8 +22,6 @@ #include #include -#include "mailbox.h" - #define MAILBOX_REVISION 0x000 #define MAILBOX_MESSAGE(m) (0x040 + 4 * (m)) #define MAILBOX_FIFOSTATUS(m) (0x080 + 4 * (m)) diff --git a/drivers/mailbox/pcc.c b/drivers/mailbox/pcc.c index 22e70af1ae5d..636879ae1db7 100644 --- a/drivers/mailbox/pcc.c +++ b/drivers/mailbox/pcc.c @@ -59,8 +59,6 @@ #include #include -#include "mailbox.h" - #define MBOX_IRQ_NAME "pcc-mbox" /** diff --git a/drivers/mailbox/tegra-hsp.c b/drivers/mailbox/tegra-hsp.c index ed9a0bb2bcd8..2231050bb5a9 100644 --- a/drivers/mailbox/tegra-hsp.c +++ b/drivers/mailbox/tegra-hsp.c @@ -16,8 +16,6 @@ #include -#include "mailbox.h" - #define HSP_INT_IE(x) (0x100 + ((x) * 4)) #define HSP_INT_IV 0x300 #define HSP_INT_IR 0x304 diff --git a/include/linux/mailbox_controller.h b/include/linux/mailbox_controller.h index 80a427c7ca29..16fef421c30c 100644 --- a/include/linux/mailbox_controller.h +++ b/include/linux/mailbox_controller.h @@ -3,6 +3,7 @@ #ifndef __MAILBOX_CONTROLLER_H #define __MAILBOX_CONTROLLER_H +#include #include #include #include @@ -11,6 +12,10 @@ struct mbox_chan; +#define TXDONE_BY_IRQ BIT(0) /* controller has remote RTR irq */ +#define TXDONE_BY_POLL BIT(1) /* controller can read status of last TX */ +#define TXDONE_BY_ACK BIT(2) /* S/W ACK received by Client ticks the TX */ + /** * struct mbox_chan_ops - methods to control mailbox channels * @send_data: The API asks the MBOX controller driver, in atomic -- cgit v1.2.3 From c58e9456e30c7098cbcd9f04571992be8a2e4e63 Mon Sep 17 00:00:00 2001 From: Jassi Brar Date: Fri, 27 Mar 2026 17:00:40 -0500 Subject: mailbox: Fix NULL message support in mbox_send_message() The active_req field serves double duty as both the "is a TX in flight" flag (NULL means idle) and the storage for the in-flight message pointer. When a client sends NULL via mbox_send_message(), active_req is set to NULL, which the framework misinterprets as "no active request". This breaks the TX state machine by: - tx_tick() short-circuits on (!mssg), skipping the tx_done callback and the tx_complete completion - txdone_hrtimer() skips the channel entirely since active_req is NULL, so poll-based TX-done detection never fires. Fix this by introducing a MBOX_NO_MSG sentinel value that means "no active request," freeing NULL to be valid message data. The sentinel is defined in the subsystem-internal mailbox.h so that controller drivers within drivers/mailbox/ can reference it, but it is not exposed to clients outside the subsystem. Fifteen in-tree callers send NULL (doorbell-style IPCs on Qualcomm, Tegra, TI, Xilinx, i.MX, SCMI, and PCC platforms). All were audited for regression: - Most already work around the bug via knows_txdone=true with a manual mbox_client_txdone() call, making the framework's tracking irrelevant. These are unaffected. - Poll-based callers (Xilinx zynqmp/r5) are strictly better off: the poll timer now correctly detects NULL-active channels instead of silently skipping them. - irq-qcom-mpm.c was a pre-existing bug -- the only Qualcomm caller that omitted the knows_txdone + mbox_client_txdone() pattern. Fixed in a companion commit ("irqchip/qcom-mpm: Fix missing mailbox TX done acknowledgment"). - No caller sets both a tx_done callback and sends NULL, nor combines tx_block=true with NULL sends, so the newly reachable callback/completion paths are never exercised. Also update tegra-hsp's flush callback, which directly inspects active_req to wait for the channel to drain: the old "!= NULL" check becomes "!= MBOX_NO_MSG", otherwise flush spins until timeout since the sentinel is non-NULL. The only tradeoff is that 'MBOX_NO_MSG' can not be used as a message by clients. Reported-by: Joonwon Kang Reviewed-by: Douglas Anderson Signed-off-by: Jassi Brar --- drivers/mailbox/mailbox.c | 15 ++++++++------- drivers/mailbox/tegra-hsp.c | 2 +- include/linux/mailbox_controller.h | 3 +++ 3 files changed, 12 insertions(+), 8 deletions(-) diff --git a/drivers/mailbox/mailbox.c b/drivers/mailbox/mailbox.c index 13de3d047853..138ffbcd4fde 100644 --- a/drivers/mailbox/mailbox.c +++ b/drivers/mailbox/mailbox.c @@ -50,7 +50,7 @@ static void msg_submit(struct mbox_chan *chan) int err = -EBUSY; scoped_guard(spinlock_irqsave, &chan->lock) { - if (!chan->msg_count || chan->active_req) + if (!chan->msg_count || chan->active_req != MBOX_NO_MSG) break; count = chan->msg_count; @@ -85,13 +85,13 @@ static void tx_tick(struct mbox_chan *chan, int r) scoped_guard(spinlock_irqsave, &chan->lock) { mssg = chan->active_req; - chan->active_req = NULL; + chan->active_req = MBOX_NO_MSG; } /* Submit next message */ msg_submit(chan); - if (!mssg) + if (mssg == MBOX_NO_MSG) return; /* Notify the client */ @@ -112,7 +112,7 @@ static enum hrtimer_restart txdone_hrtimer(struct hrtimer *hrtimer) for (i = 0; i < mbox->num_chans; i++) { struct mbox_chan *chan = &mbox->chans[i]; - if (chan->active_req && chan->cl) { + if (chan->active_req != MBOX_NO_MSG && chan->cl) { txdone = chan->mbox->ops->last_tx_done(chan); if (txdone) tx_tick(chan, 0); @@ -267,7 +267,7 @@ int mbox_send_message(struct mbox_chan *chan, void *mssg) { int t; - if (!chan || !chan->cl) + if (!chan || !chan->cl || mssg == MBOX_NO_MSG) return -EINVAL; t = add_to_rbuf(chan, mssg); @@ -340,7 +340,7 @@ static int __mbox_bind_client(struct mbox_chan *chan, struct mbox_client *cl) scoped_guard(spinlock_irqsave, &chan->lock) { chan->msg_free = 0; chan->msg_count = 0; - chan->active_req = NULL; + chan->active_req = MBOX_NO_MSG; chan->cl = cl; init_completion(&chan->tx_complete); @@ -498,7 +498,7 @@ void mbox_free_channel(struct mbox_chan *chan) /* The queued TX requests are simply aborted, no callbacks are made */ scoped_guard(spinlock_irqsave, &chan->lock) { chan->cl = NULL; - chan->active_req = NULL; + chan->active_req = MBOX_NO_MSG; if (chan->txdone_method == TXDONE_BY_ACK) chan->txdone_method = TXDONE_BY_POLL; } @@ -553,6 +553,7 @@ int mbox_controller_register(struct mbox_controller *mbox) chan->cl = NULL; chan->mbox = mbox; + chan->active_req = MBOX_NO_MSG; chan->txdone_method = txdone; spin_lock_init(&chan->lock); } diff --git a/drivers/mailbox/tegra-hsp.c b/drivers/mailbox/tegra-hsp.c index 2231050bb5a9..7b1e1b83ea29 100644 --- a/drivers/mailbox/tegra-hsp.c +++ b/drivers/mailbox/tegra-hsp.c @@ -495,7 +495,7 @@ static int tegra_hsp_mailbox_flush(struct mbox_chan *chan, mbox_chan_txdone(chan, 0); /* Wait until channel is empty */ - if (chan->active_req != NULL) + if (chan->active_req != MBOX_NO_MSG) continue; return 0; diff --git a/include/linux/mailbox_controller.h b/include/linux/mailbox_controller.h index 16fef421c30c..e3896b08f22e 100644 --- a/include/linux/mailbox_controller.h +++ b/include/linux/mailbox_controller.h @@ -12,6 +12,9 @@ struct mbox_chan; +/* Sentinel value distinguishing "no active request" from "NULL message data" */ +#define MBOX_NO_MSG ((void *)-1) + #define TXDONE_BY_IRQ BIT(0) /* controller has remote RTR irq */ #define TXDONE_BY_POLL BIT(1) /* controller can read status of last TX */ #define TXDONE_BY_ACK BIT(2) /* S/W ACK received by Client ticks the TX */ -- cgit v1.2.3 From 80784b427970219ebc338a6fb4118cde67a6c317 Mon Sep 17 00:00:00 2001 From: Dylan Wu Date: Mon, 9 Feb 2026 16:34:52 +0800 Subject: mailbox: cix: Add IRQF_NO_SUSPEND to mailbox interrupt During the system suspend process, device interrupts are masked in the noirq phase. However, SCMI often needs to exchange final messages with the firmware to complete the power-down transition. Without the IRQF_NO_SUSPEND flag, the mailbox ISR cannot run during this late stage, leading to SCMI communication timeouts and error messages like "SCMI protocol wait for resp timeout" during suspend. Add the IRQF_NO_SUSPEND flag to the interrupt request to ensure the mailbox can continue to handle responses during the noirq stages of suspend and resume, thereby ensuring a reliable power state transition. Signed-off-by: Dylan Wu Signed-off-by: Jassi Brar --- drivers/mailbox/cix-mailbox.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/mailbox/cix-mailbox.c b/drivers/mailbox/cix-mailbox.c index 864f98f21fc3..8cfaa91b75bd 100644 --- a/drivers/mailbox/cix-mailbox.c +++ b/drivers/mailbox/cix-mailbox.c @@ -403,7 +403,7 @@ static int cix_mbox_startup(struct mbox_chan *chan) int index = cp->index, ret; u32 val; - ret = request_irq(priv->irq, cix_mbox_isr, 0, + ret = request_irq(priv->irq, cix_mbox_isr, IRQF_NO_SUSPEND, dev_name(priv->dev), chan); if (ret) { dev_err(priv->dev, "Unable to acquire IRQ %d\n", priv->irq); -- cgit v1.2.3 From 220045247712ddfda1fcedfa61e91dae24e63bcf Mon Sep 17 00:00:00 2001 From: Abel Vesa Date: Fri, 27 Mar 2026 14:36:00 +0200 Subject: dt-bindings: mailbox: qcom-ipcc: Document the Eliza Inter-Processor Communication Controller Document the Inter-Processor Communication Controller (IPCC) found in the Qualcomm Eliza SoC. It is used to route interrupts across various subsystems. Signed-off-by: Abel Vesa Acked-by: Manivannan Sadhasivam Reviewed-by: Konrad Dybcio Signed-off-by: Jassi Brar --- Documentation/devicetree/bindings/mailbox/qcom-ipcc.yaml | 1 + 1 file changed, 1 insertion(+) diff --git a/Documentation/devicetree/bindings/mailbox/qcom-ipcc.yaml b/Documentation/devicetree/bindings/mailbox/qcom-ipcc.yaml index 7c4d6170491d..f5c584cf2146 100644 --- a/Documentation/devicetree/bindings/mailbox/qcom-ipcc.yaml +++ b/Documentation/devicetree/bindings/mailbox/qcom-ipcc.yaml @@ -24,6 +24,7 @@ properties: compatible: items: - enum: + - qcom,eliza-ipcc - qcom,glymur-ipcc - qcom,kaanapali-ipcc - qcom,milos-ipcc -- cgit v1.2.3 From df03d7c2bbc91d1e83f8b42881ad791353df7d94 Mon Sep 17 00:00:00 2001 From: Francois Dugast Date: Fri, 27 Mar 2026 21:27:49 +0100 Subject: drm/xe: Document GT statistics In the context of porting applications to SVM, the Xe GT statistics are used by application developers to validate expected behavior such as proper alignment, page fault count and migrations. As those statistics are made for kernel developers, they assume good understanding of driver internals, which is not always the case on the application side. Therefore, this commit documents the usage of GT statistics and clarifies the meaning of identifiers which correspond to the values exposed via debugfs. Documentation is close to identifiers declaration to make it easier to maintain when adding new entries in the future. v2: Fix page reclaim list (PRL) entries (Matthew Brost) Assisted-by: GitHub Copilot:claude-sonnet-4.6 Cc: Matthew Brost Reviewed-by: Matthew Brost Link: https://lore.kernel.org/r/20260327202749.222794-1-francois.dugast@intel.com Signed-off-by: Francois Dugast --- Documentation/gpu/xe/index.rst | 1 + Documentation/gpu/xe/xe_gt_stats.rst | 11 +++ drivers/gpu/drm/xe/xe_gt_stats.c | 41 ++++++++++++ drivers/gpu/drm/xe/xe_gt_stats_types.h | 118 +++++++++++++++++++++++++++++++++ 4 files changed, 171 insertions(+) create mode 100644 Documentation/gpu/xe/xe_gt_stats.rst diff --git a/Documentation/gpu/xe/index.rst b/Documentation/gpu/xe/index.rst index bc432c95d1a3..874ffcb6da3a 100644 --- a/Documentation/gpu/xe/index.rst +++ b/Documentation/gpu/xe/index.rst @@ -29,3 +29,4 @@ DG2, etc is provided to prototype the driver. xe_device xe-drm-usage-stats.rst xe_configfs + xe_gt_stats diff --git a/Documentation/gpu/xe/xe_gt_stats.rst b/Documentation/gpu/xe/xe_gt_stats.rst new file mode 100644 index 000000000000..5ff806abaddb --- /dev/null +++ b/Documentation/gpu/xe/xe_gt_stats.rst @@ -0,0 +1,11 @@ +.. SPDX-License-Identifier: (GPL-2.0+ OR MIT) + +================ +Xe GT Statistics +================ + +.. kernel-doc:: drivers/gpu/drm/xe/xe_gt_stats.c + :doc: Xe GT Statistics + +.. kernel-doc:: drivers/gpu/drm/xe/xe_gt_stats_types.h + :internal: diff --git a/drivers/gpu/drm/xe/xe_gt_stats.c b/drivers/gpu/drm/xe/xe_gt_stats.c index 59b3b23a54c8..789397514f3e 100644 --- a/drivers/gpu/drm/xe/xe_gt_stats.c +++ b/drivers/gpu/drm/xe/xe_gt_stats.c @@ -9,6 +9,47 @@ #include "xe_device.h" #include "xe_gt_stats.h" +/** + * DOC: Xe GT Statistics + * + * Overview + * ======== + * + * The Xe driver exposes per-GT statistics through the debugfs filesystem at:: + * + * /sys/kernel/debug/dri//gt/stats + * + * This interface requires the kernel to be built with ``CONFIG_DEBUG_FS=y``. + * + * Reading statistics + * ================== + * + * Reading the file prints all available statistics, one per line, in + * ``name: value`` format:: + * + * $ cat /sys/kernel/debug/dri/0/gt0/stats + * svm_pagefault_count: 0 + * tlb_inval_count: 1234 + * ... + * + * All values are 64-bit unsigned integers aggregated across all CPUs. + * Counters accumulate since the driver was loaded or since the last explicit + * reset. Timing counters use microseconds as their unit; data volume counters + * use KiB. + * + * Resetting statistics + * ==================== + * + * Writing a boolean true value to the file resets all counters to zero:: + * + * echo 1 > /sys/kernel/debug/dri/0/gt0/stats + * + * Any value accepted by ``kstrtobool()`` (e.g. ``1``, ``y``, ``yes``, + * ``on``) triggers the reset. Resetting while the GPU is active may yield + * unpredictable intermediate values; it is recommended to reset only when + * the GPU is idle. + */ + static void xe_gt_stats_fini(struct drm_device *drm, void *arg) { struct xe_gt *gt = arg; diff --git a/drivers/gpu/drm/xe/xe_gt_stats_types.h b/drivers/gpu/drm/xe/xe_gt_stats_types.h index 081c787ddcb6..425491bed6c4 100644 --- a/drivers/gpu/drm/xe/xe_gt_stats_types.h +++ b/drivers/gpu/drm/xe/xe_gt_stats_types.h @@ -8,6 +8,124 @@ #include +/** + * enum xe_gt_stats_id - GT statistics identifiers + * @XE_GT_STATS_ID_SVM_PAGEFAULT_COUNT: Total SVM page faults handled. + * @XE_GT_STATS_ID_TLB_INVAL: Total GPU Translation Lookaside Buffer (TLB) + * invalidations issued. + * @XE_GT_STATS_ID_SVM_TLB_INVAL_COUNT: TLB invalidations issued during SVM + * page-fault handling. + * @XE_GT_STATS_ID_SVM_TLB_INVAL_US: Cumulative time (µs) waiting for TLB + * invalidations during SVM page-fault handling. + * + * @XE_GT_STATS_ID_VMA_PAGEFAULT_COUNT: Buffer-object (non-SVM) page faults + * handled. + * @XE_GT_STATS_ID_VMA_PAGEFAULT_KB: Size (KiB) of VMAs involved in + * buffer-object page fault handling. + * @XE_GT_STATS_ID_INVALID_PREFETCH_PAGEFAULT_COUNT: GPU prefetch faults for + * addresses with no valid backing. + * + * @XE_GT_STATS_ID_SVM_4K_PAGEFAULT_COUNT: SVM page faults resolved by + * mapping 4K pages. + * @XE_GT_STATS_ID_SVM_64K_PAGEFAULT_COUNT: SVM page faults resolved by + * mapping 64K pages. + * @XE_GT_STATS_ID_SVM_2M_PAGEFAULT_COUNT: SVM page faults resolved by + * mapping 2M pages. + * @XE_GT_STATS_ID_SVM_4K_VALID_PAGEFAULT_COUNT: Valid SVM page faults + * at 4K page size, where the GPU mapping was already valid — resolved without + * creating new mappings. + * @XE_GT_STATS_ID_SVM_64K_VALID_PAGEFAULT_COUNT: Valid SVM page faults at 64K + * page size. + * @XE_GT_STATS_ID_SVM_2M_VALID_PAGEFAULT_COUNT: Valid SVM page faults at 2M + * page size. + * @XE_GT_STATS_ID_SVM_4K_PAGEFAULT_US: Cumulative time (µs) handling 4K SVM + * page faults. + * @XE_GT_STATS_ID_SVM_64K_PAGEFAULT_US: Cumulative time (µs) handling 64K + * SVM page faults. + * @XE_GT_STATS_ID_SVM_2M_PAGEFAULT_US: Cumulative time (µs) handling 2M SVM + * page faults. + * + * @XE_GT_STATS_ID_SVM_4K_MIGRATE_COUNT: 4K pages moved from CPU to device + * memory. + * @XE_GT_STATS_ID_SVM_64K_MIGRATE_COUNT: 64K pages moved from CPU to device + * memory. + * @XE_GT_STATS_ID_SVM_2M_MIGRATE_COUNT: 2M pages moved from CPU to device + * memory. + * @XE_GT_STATS_ID_SVM_4K_MIGRATE_US: Cumulative time (µs) moving 4K pages + * from CPU to device memory. + * @XE_GT_STATS_ID_SVM_64K_MIGRATE_US: Cumulative time (µs) moving 64K pages + * from CPU to device memory. + * @XE_GT_STATS_ID_SVM_2M_MIGRATE_US: Cumulative time (µs) moving 2M pages + * from CPU to device memory. + * + * @XE_GT_STATS_ID_SVM_DEVICE_COPY_US: Cumulative time (µs) for memory copies to + * device, across all page sizes. + * @XE_GT_STATS_ID_SVM_4K_DEVICE_COPY_US: Cumulative time (µs) for memory copies + * of 4K pages to device. + * @XE_GT_STATS_ID_SVM_64K_DEVICE_COPY_US: Cumulative time (µs) for memory + * copies of 64K pages to device. + * @XE_GT_STATS_ID_SVM_2M_DEVICE_COPY_US: Cumulative time (µs) for memory copies + * of 2M pages to device. + * @XE_GT_STATS_ID_SVM_CPU_COPY_US: Cumulative time (µs) for memory copies to + * CPU, across all page sizes. + * @XE_GT_STATS_ID_SVM_4K_CPU_COPY_US: Cumulative time (µs) for memory copies of + * 4K pages to CPU. + * @XE_GT_STATS_ID_SVM_64K_CPU_COPY_US: Cumulative time (µs) for memory copies + * of 64K pages to CPU. + * @XE_GT_STATS_ID_SVM_2M_CPU_COPY_US: Cumulative time (µs) for memory copies of + * 2M pages to CPU. + * @XE_GT_STATS_ID_SVM_DEVICE_COPY_KB: Data (KiB) copied to device across all + * page sizes. + * @XE_GT_STATS_ID_SVM_4K_DEVICE_COPY_KB: Data (KiB) copied to device for 4K + * pages. + * @XE_GT_STATS_ID_SVM_64K_DEVICE_COPY_KB: Data (KiB) copied to device for + * 64K pages. + * @XE_GT_STATS_ID_SVM_2M_DEVICE_COPY_KB: Data (KiB) copied to device for 2M + * pages. + * @XE_GT_STATS_ID_SVM_CPU_COPY_KB: Data (KiB) copied to CPU across all page + * sizes. + * @XE_GT_STATS_ID_SVM_4K_CPU_COPY_KB: Data (KiB) copied to CPU for 4K pages. + * @XE_GT_STATS_ID_SVM_64K_CPU_COPY_KB: Data (KiB) copied to CPU for 64K pages. + * @XE_GT_STATS_ID_SVM_2M_CPU_COPY_KB: Data (KiB) copied to CPU for 2M pages. + * + * @XE_GT_STATS_ID_SVM_4K_GET_PAGES_US: Cumulative time (µs) getting CPU + * memory pages for GPU access at 4K page size. + * @XE_GT_STATS_ID_SVM_64K_GET_PAGES_US: Cumulative time (µs) getting CPU + * memory pages for GPU access at 64K page size. + * @XE_GT_STATS_ID_SVM_2M_GET_PAGES_US: Cumulative time (µs) getting CPU + * memory pages for GPU access at 2M page size. + * @XE_GT_STATS_ID_SVM_4K_BIND_US: Cumulative time (µs) binding 4K pages + * into the GPU page table. + * @XE_GT_STATS_ID_SVM_64K_BIND_US: Cumulative time (µs) binding 64K pages + * into the GPU page table. + * @XE_GT_STATS_ID_SVM_2M_BIND_US: Cumulative time (µs) binding 2M pages + * into the GPU page table. + * + * @XE_GT_STATS_ID_HW_ENGINE_GROUP_SUSPEND_LR_QUEUE_COUNT: Times the + * scheduler preempted a long-running (LR) GPU exec queue. + * @XE_GT_STATS_ID_HW_ENGINE_GROUP_SKIP_LR_QUEUE_COUNT: Times the scheduler + * skipped suspend because the system was idle. + * @XE_GT_STATS_ID_HW_ENGINE_GROUP_WAIT_DMA_QUEUE_COUNT: Times the driver + * stalled waiting for prior GPU work to complete before scheduling more. + * @XE_GT_STATS_ID_HW_ENGINE_GROUP_SUSPEND_LR_QUEUE_US: Cumulative time + * (µs) spent preempting long-running (LR) GPU exec queues. + * @XE_GT_STATS_ID_HW_ENGINE_GROUP_WAIT_DMA_QUEUE_US: Cumulative time (µs) + * stalled waiting for prior GPU work to complete. + * + * @XE_GT_STATS_ID_PRL_4K_ENTRY_COUNT: 4K-page entries from the page reclaim + * list that were processed. + * @XE_GT_STATS_ID_PRL_64K_ENTRY_COUNT: 64K-page entries from the page reclaim + * list that were processed. + * @XE_GT_STATS_ID_PRL_2M_ENTRY_COUNT: 2M-page entries from the page reclaim + * list that were processed. + * @XE_GT_STATS_ID_PRL_ISSUED_COUNT: Times a page reclamation was issued. + * @XE_GT_STATS_ID_PRL_ABORTED_COUNT: Times the page reclaim process was + * aborted. + * + * @__XE_GT_STATS_NUM_IDS: Number of valid IDs; not a real counter. + * + * See Documentation/gpu/xe/xe_gt_stats.rst. + */ enum xe_gt_stats_id { XE_GT_STATS_ID_SVM_PAGEFAULT_COUNT, XE_GT_STATS_ID_TLB_INVAL, -- cgit v1.2.3 From e2d48e8395a43e8264660ac37a75f7644d4f5d8b Mon Sep 17 00:00:00 2001 From: Dibin Moolakadan Subrahmanian Date: Fri, 27 Mar 2026 12:14:52 +0530 Subject: drm/i915/dmc: Remove invalid PIPEDMC interrupt bits On display version 35+ PIPEDMC_ATS_FAULT and PIPEDMC_GTT_FAULT interrupt bits are no longer defined. Update the interrupt mask to drop these. Changes in v2: - Move PIPEDMC_ERROR interrupt enable to a separate patch (Ville Syrjala) Changes in v3: - Add Bspec reference (Suraj Kandpal) Changes in v4: - Move bspec position in commit message(Suraj Kandpal) Bspec: 70296 Signed-off-by: Dibin Moolakadan Subrahmanian Reviewed-by: Suraj Kandpal Signed-off-by: Suraj Kandpal Link: https://patch.msgid.link/20260327064453.2241523-2-dibin.moolakadan.subrahmanian@intel.com --- drivers/gpu/drm/i915/display/intel_dmc.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/drivers/gpu/drm/i915/display/intel_dmc.c b/drivers/gpu/drm/i915/display/intel_dmc.c index 1667a829e708..1d2e09471ba4 100644 --- a/drivers/gpu/drm/i915/display/intel_dmc.c +++ b/drivers/gpu/drm/i915/display/intel_dmc.c @@ -505,6 +505,9 @@ static void pipedmc_clock_gating_wa(struct intel_display *display, bool enable) static u32 pipedmc_interrupt_mask(struct intel_display *display) { + if (DISPLAY_VER(display) >= 35) + return PIPEDMC_FLIPQ_PROG_DONE; + /* * FIXME PIPEDMC_ERROR not enabled for now due to LNL pipe B * triggering it during the first DC state transition. Figure -- cgit v1.2.3 From ba48541c82dc6df5b18bd4a4db0f0c1617a37154 Mon Sep 17 00:00:00 2001 From: Dibin Moolakadan Subrahmanian Date: Fri, 27 Mar 2026 12:14:53 +0530 Subject: drm/i915/dmc: Enable PIPEDMC_ERROR interrupt Enable PIPEDMC_ERROR interrupt bit for display version 35+. Changes in v2: - Move PIPEDMC_ERROR interrupt enable to a separate patch (Ville Syrjala) Changes in v3: - Add Bspec reference (Suraj Kandpal) Changes in v4: - Add TODO to check the enablement of PIPEDMC_ERROR for PTL (Suraj Kandpal) Changes in v5: - Move TODO to the beginning of pipedmc_interrupt_mask() (Suraj Kandpal) Bspec: 70296 Signed-off-by: Dibin Moolakadan Subrahmanian Reviewed-by: Suraj Kandpal Signed-off-by: Suraj Kandpal Link: https://patch.msgid.link/20260327064453.2241523-3-dibin.moolakadan.subrahmanian@intel.com --- drivers/gpu/drm/i915/display/intel_dmc.c | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/drivers/gpu/drm/i915/display/intel_dmc.c b/drivers/gpu/drm/i915/display/intel_dmc.c index 1d2e09471ba4..2104164e136e 100644 --- a/drivers/gpu/drm/i915/display/intel_dmc.c +++ b/drivers/gpu/drm/i915/display/intel_dmc.c @@ -505,8 +505,13 @@ static void pipedmc_clock_gating_wa(struct intel_display *display, bool enable) static u32 pipedmc_interrupt_mask(struct intel_display *display) { + /* + * TODO: Check if PIPEDMC_ERROR bit enabling causes errors + * on PTL, enable it if validation passes + */ if (DISPLAY_VER(display) >= 35) - return PIPEDMC_FLIPQ_PROG_DONE; + return PIPEDMC_FLIPQ_PROG_DONE | + PIPEDMC_ERROR; /* * FIXME PIPEDMC_ERROR not enabled for now due to LNL pipe B -- cgit v1.2.3 From 0f21a14987ebae3c05ad1184ea872e7b7a7b8695 Mon Sep 17 00:00:00 2001 From: Ville Syrjälä Date: Wed, 25 Mar 2026 15:58:44 +0200 Subject: drm/i915/cdclk: Do the full CDCLK dance for min_voltage_level changes MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Apparently I forgot about the pipe min_voltage_level when I decoupled the CDCLK calculations from modesets. Even if the CDCLK frequency doesn't need changing we may still need to bump the voltage level to accommodate an increase in the port clock frequency. Currently, even if there is a full modeset, we won't notice the need to go through the full CDCLK calculations/programming, unless the set of enabled/active pipes changes, or the pipe/dbuf min CDCLK changes. Duplicate the same logic we use the pipe's min CDCLK frequency to also deal with its min voltage level. Note that the 'allow_voltage_level_decrease' stuff isn't really useful here since the min voltage level can only change during a full modeset. But I think sticking to the same approach in the three similar parts (pipe min cdclk, pipe min voltage level, dbuf min cdclk) is a good idea. Cc: stable@vger.kernel.org Tested-by: Mikhail Rudenko Closes: https://gitlab.freedesktop.org/drm/i915/kernel/-/issues/15826 Fixes: ba91b9eecb47 ("drm/i915/cdclk: Decouple cdclk from state->modeset") Signed-off-by: Ville Syrjälä Link: https://patch.msgid.link/20260325135849.12603-2-ville.syrjala@linux.intel.com Reviewed-by: Michał Grzelak --- drivers/gpu/drm/i915/display/intel_cdclk.c | 54 ++++++++++++++++++++++++++++++ 1 file changed, 54 insertions(+) diff --git a/drivers/gpu/drm/i915/display/intel_cdclk.c b/drivers/gpu/drm/i915/display/intel_cdclk.c index 121a12c5b8ac..a47736613f6e 100644 --- a/drivers/gpu/drm/i915/display/intel_cdclk.c +++ b/drivers/gpu/drm/i915/display/intel_cdclk.c @@ -2972,6 +2972,53 @@ static int intel_cdclk_update_crtc_min_cdclk(struct intel_atomic_state *state, return 0; } +static int intel_cdclk_update_crtc_min_voltage_level(struct intel_atomic_state *state, + struct intel_crtc *crtc, + u8 old_min_voltage_level, + u8 new_min_voltage_level, + bool *need_cdclk_calc) +{ + struct intel_display *display = to_intel_display(state); + struct intel_cdclk_state *cdclk_state; + bool allow_voltage_level_decrease = intel_any_crtc_needs_modeset(state); + int ret; + + if (new_min_voltage_level == old_min_voltage_level) + return 0; + + if (!allow_voltage_level_decrease && + new_min_voltage_level < old_min_voltage_level) + return 0; + + cdclk_state = intel_atomic_get_cdclk_state(state); + if (IS_ERR(cdclk_state)) + return PTR_ERR(cdclk_state); + + old_min_voltage_level = cdclk_state->min_voltage_level[crtc->pipe]; + + if (new_min_voltage_level == old_min_voltage_level) + return 0; + + if (!allow_voltage_level_decrease && + new_min_voltage_level < old_min_voltage_level) + return 0; + + cdclk_state->min_voltage_level[crtc->pipe] = new_min_voltage_level; + + ret = intel_atomic_lock_global_state(&cdclk_state->base); + if (ret) + return ret; + + *need_cdclk_calc = true; + + drm_dbg_kms(display->drm, + "[CRTC:%d:%s] min voltage level: %d -> %d\n", + crtc->base.base.id, crtc->base.name, + old_min_voltage_level, new_min_voltage_level); + + return 0; +} + int intel_cdclk_update_dbuf_bw_min_cdclk(struct intel_atomic_state *state, int old_min_cdclk, int new_min_cdclk, bool *need_cdclk_calc) @@ -3387,6 +3434,13 @@ static int intel_crtcs_calc_min_cdclk(struct intel_atomic_state *state, need_cdclk_calc); if (ret) return ret; + + ret = intel_cdclk_update_crtc_min_voltage_level(state, crtc, + old_crtc_state->min_voltage_level, + new_crtc_state->min_voltage_level, + need_cdclk_calc); + if (ret) + return ret; } return 0; -- cgit v1.2.3 From 799fe8dc2af52f35c78c4ac97f8e34994dfd8760 Mon Sep 17 00:00:00 2001 From: Ville Syrjälä Date: Wed, 25 Mar 2026 15:58:45 +0200 Subject: drm/i915/dp: Use crtc_state->enhanced_framing properly on ivb/hsw CPU eDP MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Looks like I missed the drm_dp_enhanced_frame_cap() in the ivb/hsw CPU eDP code when I introduced crtc_state->enhanced_framing. Fix it up so that the state we program to the hardware is guaranteed to match what we computed earlier. Cc: stable@vger.kernel.org Fixes: 3072a24c778a ("drm/i915: Introduce crtc_state->enhanced_framing") Signed-off-by: Ville Syrjälä Link: https://patch.msgid.link/20260325135849.12603-3-ville.syrjala@linux.intel.com Reviewed-by: Michał Grzelak --- drivers/gpu/drm/i915/display/g4x_dp.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/gpu/drm/i915/display/g4x_dp.c b/drivers/gpu/drm/i915/display/g4x_dp.c index d7de329abf19..5e74d8a3ba5c 100644 --- a/drivers/gpu/drm/i915/display/g4x_dp.c +++ b/drivers/gpu/drm/i915/display/g4x_dp.c @@ -136,7 +136,7 @@ static void intel_dp_prepare(struct intel_encoder *encoder, intel_dp->DP |= DP_SYNC_VS_HIGH; intel_dp->DP |= DP_LINK_TRAIN_OFF_CPT; - if (drm_dp_enhanced_frame_cap(intel_dp->dpcd)) + if (pipe_config->enhanced_framing) intel_dp->DP |= DP_ENHANCED_FRAMING; intel_dp->DP |= DP_PIPE_SEL_IVB(crtc->pipe); -- cgit v1.2.3 From c048609b05675ecae4bc10fc34fc4cb83e3264a4 Mon Sep 17 00:00:00 2001 From: Ville Syrjälä Date: Wed, 25 Mar 2026 15:58:46 +0200 Subject: drm/i915: Split the pipe_src dump to its own line MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The pipe_src dump doesn't really fit in with the rest of the guys (pixel_rate, port_clock, min_cdclk) included on the same line. Split pipe_src onto its own line, next to the related pfit stuff. Signed-off-by: Ville Syrjälä Link: https://patch.msgid.link/20260325135849.12603-4-ville.syrjala@linux.intel.com Reviewed-by: Michał Grzelak --- drivers/gpu/drm/i915/display/intel_crtc_state_dump.c | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/drivers/gpu/drm/i915/display/intel_crtc_state_dump.c b/drivers/gpu/drm/i915/display/intel_crtc_state_dump.c index 234843b8f83a..63a61caa059e 100644 --- a/drivers/gpu/drm/i915/display/intel_crtc_state_dump.c +++ b/drivers/gpu/drm/i915/display/intel_crtc_state_dump.c @@ -320,9 +320,9 @@ void intel_crtc_state_dump(const struct intel_crtc_state *pipe_config, drm_printf(&p, "pipe mode: " DRM_MODE_FMT "\n", DRM_MODE_ARG(&pipe_config->hw.pipe_mode)); intel_dump_crtc_timings(&p, &pipe_config->hw.pipe_mode); - drm_printf(&p, "port clock: %d, pipe src: " DRM_RECT_FMT ", pixel rate %d, min cdclk %d\n", - pipe_config->port_clock, DRM_RECT_ARG(&pipe_config->pipe_src), - pipe_config->pixel_rate, pipe_config->min_cdclk); + drm_printf(&p, "port clock: %d, pixel rate %d, min cdclk %d\n", + pipe_config->port_clock, pipe_config->pixel_rate, + pipe_config->min_cdclk); drm_printf(&p, "linetime: %d, ips linetime: %d\n", pipe_config->linetime, pipe_config->ips_linetime); @@ -334,6 +334,9 @@ void intel_crtc_state_dump(const struct intel_crtc_state *pipe_config, pipe_config->scaler_state.scaler_id, pipe_config->hw.scaling_filter); + drm_printf(&p, "pipe src: " DRM_RECT_FMT "\n", + DRM_RECT_ARG(&pipe_config->pipe_src)); + if (HAS_GMCH(display)) drm_printf(&p, "gmch pfit: control: 0x%08x, ratios: 0x%08x, lvds border: 0x%08x\n", pipe_config->gmch_pfit.control, -- cgit v1.2.3 From dd6eaa843c8f06949fab7de142affe05e75bb78e Mon Sep 17 00:00:00 2001 From: Ville Syrjälä Date: Wed, 25 Mar 2026 15:58:47 +0200 Subject: drm/i915: Include the crtc min_voltage_level in the state dump MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Include the pipe's min_voltage_level in its state dump, to help with debugging. Signed-off-by: Ville Syrjälä Link: https://patch.msgid.link/20260325135849.12603-5-ville.syrjala@linux.intel.com Reviewed-by: Michał Grzelak --- drivers/gpu/drm/i915/display/intel_crtc_state_dump.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/gpu/drm/i915/display/intel_crtc_state_dump.c b/drivers/gpu/drm/i915/display/intel_crtc_state_dump.c index 63a61caa059e..ec667a3d09d6 100644 --- a/drivers/gpu/drm/i915/display/intel_crtc_state_dump.c +++ b/drivers/gpu/drm/i915/display/intel_crtc_state_dump.c @@ -320,9 +320,9 @@ void intel_crtc_state_dump(const struct intel_crtc_state *pipe_config, drm_printf(&p, "pipe mode: " DRM_MODE_FMT "\n", DRM_MODE_ARG(&pipe_config->hw.pipe_mode)); intel_dump_crtc_timings(&p, &pipe_config->hw.pipe_mode); - drm_printf(&p, "port clock: %d, pixel rate %d, min cdclk %d\n", + drm_printf(&p, "port clock: %d, pixel rate %d, min cdclk %d, min voltage level %d\n", pipe_config->port_clock, pipe_config->pixel_rate, - pipe_config->min_cdclk); + pipe_config->min_cdclk, pipe_config->min_voltage_level); drm_printf(&p, "linetime: %d, ips linetime: %d\n", pipe_config->linetime, pipe_config->ips_linetime); -- cgit v1.2.3 From b878872b7d9078752ed7bd1be29786ff7c270b47 Mon Sep 17 00:00:00 2001 From: Ville Syrjälä Date: Wed, 25 Mar 2026 15:58:48 +0200 Subject: drm/i915: Eliminate out of place "HBlank" CamelCase MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Nothing else in the crtc state dump uses CamelCase, so don't use it for "HBlank" either. Signed-off-by: Ville Syrjälä Link: https://patch.msgid.link/20260325135849.12603-6-ville.syrjala@linux.intel.com Reviewed-by: Michał Grzelak --- drivers/gpu/drm/i915/display/intel_crtc_state_dump.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/gpu/drm/i915/display/intel_crtc_state_dump.c b/drivers/gpu/drm/i915/display/intel_crtc_state_dump.c index ec667a3d09d6..e0c292c703c1 100644 --- a/drivers/gpu/drm/i915/display/intel_crtc_state_dump.c +++ b/drivers/gpu/drm/i915/display/intel_crtc_state_dump.c @@ -250,7 +250,7 @@ void intel_crtc_state_dump(const struct intel_crtc_state *pipe_config, str_enabled_disabled(pipe_config->has_sel_update), str_enabled_disabled(pipe_config->has_panel_replay), str_enabled_disabled(pipe_config->enable_psr2_sel_fetch)); - drm_printf(&p, "minimum HBlank: %d\n", pipe_config->min_hblank); + drm_printf(&p, "minimum hblank: %d\n", pipe_config->min_hblank); } drm_printf(&p, "audio: %i, infoframes: %i, infoframes enabled: 0x%x\n", -- cgit v1.2.3 From 299d59abcc3907524239e10277c8dd8b714977e9 Mon Sep 17 00:00:00 2001 From: Ville Syrjälä Date: Wed, 25 Mar 2026 15:58:49 +0200 Subject: drm/i915: Move the sharpness filter dump next to pfit MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Group the sharpness filter parameters next to all the other pfit stuff in the state dump. Signed-off-by: Ville Syrjälä Link: https://patch.msgid.link/20260325135849.12603-7-ville.syrjala@linux.intel.com Reviewed-by: Michał Grzelak --- drivers/gpu/drm/i915/display/intel_crtc_state_dump.c | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/drivers/gpu/drm/i915/display/intel_crtc_state_dump.c b/drivers/gpu/drm/i915/display/intel_crtc_state_dump.c index e0c292c703c1..c85ba9a95322 100644 --- a/drivers/gpu/drm/i915/display/intel_crtc_state_dump.c +++ b/drivers/gpu/drm/i915/display/intel_crtc_state_dump.c @@ -348,6 +348,11 @@ void intel_crtc_state_dump(const struct intel_crtc_state *pipe_config, str_enabled_disabled(pipe_config->pch_pfit.enabled), str_yes_no(pipe_config->pch_pfit.force_thru)); + drm_printf(&p, "sharpness strength: %d, sharpness tap size: %d, sharpness enable: %d\n", + pipe_config->hw.casf_params.strength, + pipe_config->hw.casf_params.win_size, + pipe_config->hw.casf_params.casf_enable); + drm_printf(&p, "ips: %i, double wide: %i, drrs: %i\n", pipe_config->ips_enabled, pipe_config->double_wide, pipe_config->has_drrs); @@ -383,11 +388,6 @@ void intel_crtc_state_dump(const struct intel_crtc_state *pipe_config, intel_vdsc_state_dump(&p, 0, pipe_config); - drm_printf(&p, "sharpness strength: %d, sharpness tap size: %d, sharpness enable: %d\n", - pipe_config->hw.casf_params.strength, - pipe_config->hw.casf_params.win_size, - pipe_config->hw.casf_params.casf_enable); - dump_planes: if (!state) return; -- cgit v1.2.3 From bb2447ef6aee314f303b1a8e0ede6b98c8f6a529 Mon Sep 17 00:00:00 2001 From: Anoop Vijay Date: Fri, 27 Mar 2026 06:18:38 -0700 Subject: drm/xe/xe_sysctrl: Add System Controller types and device integration Add foundational type definitions for System Controller (sysctrl) support and integrate them into the xe_device structure. Introduce a capability flag in device descriptor and runtime information to record sysctrl presence on supported platforms. System Controller is a separate firmware-managed entity responsible for selected platform-level control and coordination tasks on Intel Xe3p discrete GPU platforms. The driver communicates with it via a mailbox interface for delegated operations. This commit introduces core data structures required for sysctrl support, including MMIO region definitions, a command mutex, and state tracking required for mailbox communication. No functional changes. This patch provides preparatory infrastructure for System Controller support. Signed-off-by: Anoop Vijay Reviewed-by: Umesh Nerlige Ramappa Signed-off-by: Umesh Nerlige Ramappa Link: https://patch.msgid.link/20260327131837.2192929-10-anoop.c.vijay@intel.com --- drivers/gpu/drm/xe/xe_device_types.h | 6 ++++++ drivers/gpu/drm/xe/xe_pci_types.h | 1 + drivers/gpu/drm/xe/xe_sysctrl_types.h | 32 ++++++++++++++++++++++++++++++++ 3 files changed, 39 insertions(+) create mode 100644 drivers/gpu/drm/xe/xe_sysctrl_types.h diff --git a/drivers/gpu/drm/xe/xe_device_types.h b/drivers/gpu/drm/xe/xe_device_types.h index 615218d775b1..150c76b2acaf 100644 --- a/drivers/gpu/drm/xe/xe_device_types.h +++ b/drivers/gpu/drm/xe/xe_device_types.h @@ -27,6 +27,7 @@ #include "xe_sriov_vf_ccs_types.h" #include "xe_step_types.h" #include "xe_survivability_mode_types.h" +#include "xe_sysctrl_types.h" #include "xe_tile_types.h" #include "xe_validation.h" @@ -196,6 +197,8 @@ struct xe_device { u8 has_soc_remapper_telem:1; /** @info.has_sriov: Supports SR-IOV */ u8 has_sriov:1; + /** @info.has_sysctrl: Supports System Controller */ + u8 has_sysctrl:1; /** @info.has_usm: Device has unified shared memory support */ u8 has_usm:1; /** @info.has_64bit_timestamp: Device supports 64-bit timestamps */ @@ -508,6 +511,9 @@ struct xe_device { /** @i2c: I2C host controller */ struct xe_i2c *i2c; + /** @sc: System Controller */ + struct xe_sysctrl sc; + /** @atomic_svm_timeslice_ms: Atomic SVM fault timeslice MS */ u32 atomic_svm_timeslice_ms; diff --git a/drivers/gpu/drm/xe/xe_pci_types.h b/drivers/gpu/drm/xe/xe_pci_types.h index 8eee4fb1c57c..08386c5eca27 100644 --- a/drivers/gpu/drm/xe/xe_pci_types.h +++ b/drivers/gpu/drm/xe/xe_pci_types.h @@ -57,6 +57,7 @@ struct xe_device_desc { u8 has_soc_remapper_sysctrl:1; u8 has_soc_remapper_telem:1; u8 has_sriov:1; + u8 has_sysctrl:1; u8 needs_scratch:1; u8 skip_guc_pc:1; u8 skip_mtcfg:1; diff --git a/drivers/gpu/drm/xe/xe_sysctrl_types.h b/drivers/gpu/drm/xe/xe_sysctrl_types.h new file mode 100644 index 000000000000..8217f6befe70 --- /dev/null +++ b/drivers/gpu/drm/xe/xe_sysctrl_types.h @@ -0,0 +1,32 @@ +/* SPDX-License-Identifier: MIT */ +/* + * Copyright © 2026 Intel Corporation + */ + +#ifndef _XE_SYSCTRL_TYPES_H_ +#define _XE_SYSCTRL_TYPES_H_ + +#include +#include + +struct xe_mmio; + +/** + * struct xe_sysctrl - System Controller driver context + * + * This structure maintains the runtime state for System Controller + * communication. All fields are initialized during xe_sysctrl_init() + * and protected appropriately for concurrent access. + */ +struct xe_sysctrl { + /** @mmio: MMIO region for system control registers */ + struct xe_mmio *mmio; + + /** @cmd_lock: Mutex protecting mailbox command operations */ + struct mutex cmd_lock; + + /** @phase_bit: Message boundary phase toggle bit (0 or 1) */ + bool phase_bit; +}; + +#endif -- cgit v1.2.3 From 281a79f78dfedf10f6c7de4334434c38eb5459dd Mon Sep 17 00:00:00 2001 From: Anoop Vijay Date: Fri, 27 Mar 2026 06:18:39 -0700 Subject: drm/xe/xe_sysctrl: Add System Controller mailbox register definitions Add register definitions for System Controller mailbox interface, including control, data, and protocol-related fields, along with base address and BAR configuration required by the driver. No functional changes. This patch introduces register definitions only. Signed-off-by: Anoop Vijay Reviewed-by: Umesh Nerlige Ramappa Signed-off-by: Umesh Nerlige Ramappa Link: https://patch.msgid.link/20260327131837.2192929-11-anoop.c.vijay@intel.com --- drivers/gpu/drm/xe/regs/xe_sysctrl_regs.h | 36 +++++++++++++++++++++++++++++++ 1 file changed, 36 insertions(+) create mode 100644 drivers/gpu/drm/xe/regs/xe_sysctrl_regs.h diff --git a/drivers/gpu/drm/xe/regs/xe_sysctrl_regs.h b/drivers/gpu/drm/xe/regs/xe_sysctrl_regs.h new file mode 100644 index 000000000000..59f3f3ec59a6 --- /dev/null +++ b/drivers/gpu/drm/xe/regs/xe_sysctrl_regs.h @@ -0,0 +1,36 @@ +/* SPDX-License-Identifier: MIT */ +/* + * Copyright © 2026 Intel Corporation + */ + +#ifndef _XE_SYSCTRL_REGS_H_ +#define _XE_SYSCTRL_REGS_H_ + +#include "xe_regs.h" + +#define SYSCTRL_BASE_OFFSET 0xdb000 +#define SYSCTRL_BASE (SOC_BASE + SYSCTRL_BASE_OFFSET) +#define SYSCTRL_MAILBOX_INDEX 0x03 +#define SYSCTRL_BAR_LENGTH 0x1000 + +#define SYSCTRL_MB_CTRL XE_REG(0x10) +#define SYSCTRL_MB_CTRL_RUN_BUSY REG_BIT(31) +#define SYSCTRL_MB_CTRL_IRQ REG_BIT(30) +#define SYSCTRL_MB_CTRL_RUN_BUSY_OUT REG_BIT(29) +#define SYSCTRL_MB_CTRL_PARAM3_MASK REG_GENMASK(28, 24) +#define SYSCTRL_MB_CTRL_PARAM2_MASK REG_GENMASK(23, 16) +#define SYSCTRL_MB_CTRL_PARAM1_MASK REG_GENMASK(15, 8) +#define SYSCTRL_MB_CTRL_COMMAND_MASK REG_GENMASK(7, 0) +#define SYSCTRL_MB_CTRL_CMD REG_FIELD_PREP(SYSCTRL_MB_CTRL_COMMAND_MASK, 5) + +#define SYSCTRL_MB_DATA0 XE_REG(0x14) +#define SYSCTRL_MB_DATA1 XE_REG(0x18) +#define SYSCTRL_MB_DATA2 XE_REG(0x1c) +#define SYSCTRL_MB_DATA3 XE_REG(0x20) + +#define SYSCTRL_FRAME_PHASE REG_BIT(24) +#define SYSCTRL_FRAME_CURRENT_MASK REG_GENMASK(21, 16) +#define SYSCTRL_FRAME_TOTAL_MASK REG_GENMASK(13, 8) +#define SYSCTRL_FRAME_COMMAND_MASK REG_GENMASK(7, 0) + +#endif -- cgit v1.2.3 From 37ace5254a2b1520753762527365ecad7fad797a Mon Sep 17 00:00:00 2001 From: Anoop Vijay Date: Fri, 27 Mar 2026 06:18:40 -0700 Subject: drm/xe/xe_sysctrl: Add ABI and mailbox interface headers Add ABI definitions, mailbox API, and command data structures required for System Controller communication. No functional changes. This patch introduces definitions for mailbox communication. Signed-off-by: Anoop Vijay Reviewed-by: Umesh Nerlige Ramappa Signed-off-by: Umesh Nerlige Ramappa Link: https://patch.msgid.link/20260327131837.2192929-12-anoop.c.vijay@intel.com --- drivers/gpu/drm/xe/abi/xe_sysctrl_abi.h | 65 +++++++++++++++++++++++++++ drivers/gpu/drm/xe/xe_sysctrl_mailbox.h | 31 +++++++++++++ drivers/gpu/drm/xe/xe_sysctrl_mailbox_types.h | 40 +++++++++++++++++ 3 files changed, 136 insertions(+) create mode 100644 drivers/gpu/drm/xe/abi/xe_sysctrl_abi.h create mode 100644 drivers/gpu/drm/xe/xe_sysctrl_mailbox.h create mode 100644 drivers/gpu/drm/xe/xe_sysctrl_mailbox_types.h diff --git a/drivers/gpu/drm/xe/abi/xe_sysctrl_abi.h b/drivers/gpu/drm/xe/abi/xe_sysctrl_abi.h new file mode 100644 index 000000000000..4cbde267ac44 --- /dev/null +++ b/drivers/gpu/drm/xe/abi/xe_sysctrl_abi.h @@ -0,0 +1,65 @@ +/* SPDX-License-Identifier: MIT */ +/* + * Copyright © 2026 Intel Corporation + */ + +#ifndef _XE_SYSCTRL_ABI_H_ +#define _XE_SYSCTRL_ABI_H_ + +#include + +/** + * DOC: System Controller ABI + * + * This header defines the Application Binary Interface (ABI) used by + * drm/xe to communicate with System Controller firmware on Intel Xe3p + * discrete GPU platforms. + * + * System Controller (sysctrl) is a firmware-managed entity on Intel + * dGPUs responsible for certain low-level platform management + * functions. + * + * Communication protocol: + * + * Communication uses a mailbox interface with messages composed of: + * + * - Application message header (struct xe_sysctrl_app_msg_hdr) + * containing group_id, command, and version + * - Variable-length, command-specific payload + * + * Message header format: + * + * The 32-bit application message header is packed as: + * + * - Bits [7:0] : Group ID identifying command group + * - Bits [15:8] : Command identifier within group + * - Bits [23:16] : Command version for interface compatibility + * - Bits [31:24] : Reserved, must be zero + * + * This header defines firmware ABI message formats and constants shared + * between driver and System Controller firmware. + */ + +/** + * struct xe_sysctrl_app_msg_hdr - Application layer message header + * @data: 32-bit header data + * + * Header structure for application-level messages. + */ +struct xe_sysctrl_app_msg_hdr { + u32 data; +} __packed; + +#define SYSCTRL_HDR_GROUP_ID_MASK GENMASK(7, 0) +#define SYSCTRL_HDR_COMMAND_MASK GENMASK(14, 8) +#define SYSCTRL_HDR_COMMAND_MAX 0x7f +#define SYSCTRL_HDR_IS_RESPONSE BIT(15) +#define SYSCTRL_HDR_RESERVED_MASK GENMASK(23, 16) +#define SYSCTRL_HDR_RESULT_MASK GENMASK(31, 24) + +#define APP_HDR_GROUP_ID_MASK GENMASK(7, 0) +#define APP_HDR_COMMAND_MASK GENMASK(15, 8) +#define APP_HDR_VERSION_MASK GENMASK(23, 16) +#define APP_HDR_RESERVED_MASK GENMASK(31, 24) + +#endif diff --git a/drivers/gpu/drm/xe/xe_sysctrl_mailbox.h b/drivers/gpu/drm/xe/xe_sysctrl_mailbox.h new file mode 100644 index 000000000000..91460be9e22c --- /dev/null +++ b/drivers/gpu/drm/xe/xe_sysctrl_mailbox.h @@ -0,0 +1,31 @@ +/* SPDX-License-Identifier: MIT */ +/* + * Copyright © 2026 Intel Corporation + */ + +#ifndef _XE_SYSCTRL_MAILBOX_H_ +#define _XE_SYSCTRL_MAILBOX_H_ + +#include +#include + +#include "abi/xe_sysctrl_abi.h" + +struct xe_sysctrl; +struct xe_sysctrl_mailbox_command; + +#define XE_SYSCTRL_APP_HDR_GROUP_ID(hdr) \ + FIELD_GET(APP_HDR_GROUP_ID_MASK, le32_to_cpu((hdr)->data)) + +#define XE_SYSCTRL_APP_HDR_COMMAND(hdr) \ + FIELD_GET(APP_HDR_COMMAND_MASK, le32_to_cpu((hdr)->data)) + +#define XE_SYSCTRL_APP_HDR_VERSION(hdr) \ + FIELD_GET(APP_HDR_VERSION_MASK, le32_to_cpu((hdr)->data)) + +void xe_sysctrl_mailbox_init(struct xe_sysctrl *sc); +int xe_sysctrl_send_command(struct xe_sysctrl *sc, + struct xe_sysctrl_mailbox_command *cmd, + size_t *rdata_len); + +#endif diff --git a/drivers/gpu/drm/xe/xe_sysctrl_mailbox_types.h b/drivers/gpu/drm/xe/xe_sysctrl_mailbox_types.h new file mode 100644 index 000000000000..89456aec6097 --- /dev/null +++ b/drivers/gpu/drm/xe/xe_sysctrl_mailbox_types.h @@ -0,0 +1,40 @@ +/* SPDX-License-Identifier: MIT */ +/* + * Copyright © 2026 Intel Corporation + */ + +#ifndef _XE_SYSCTRL_MAILBOX_TYPES_H_ +#define _XE_SYSCTRL_MAILBOX_TYPES_H_ + +#include + +#include "abi/xe_sysctrl_abi.h" + +/** + * struct xe_sysctrl_mailbox_command - System Controller mailbox command + */ +struct xe_sysctrl_mailbox_command { + /** @header: Application message header containing command information */ + struct xe_sysctrl_app_msg_hdr header; + + /** @data_in: Pointer to input payload data (can be NULL if no input data) */ + void *data_in; + + /** @data_in_len: Size of input payload in bytes (0 if no input data) */ + size_t data_in_len; + + /** @data_out: Pointer to output buffer for response data (can be NULL if no response) */ + void *data_out; + + /** @data_out_len: Size of output buffer in bytes (0 if no response expected) */ + size_t data_out_len; +}; + +#define XE_SYSCTRL_MB_FRAME_SIZE 16 +#define XE_SYSCTRL_MB_MAX_FRAMES 64 +#define XE_SYSCTRL_MB_MAX_MESSAGE_SIZE \ + (XE_SYSCTRL_MB_FRAME_SIZE * XE_SYSCTRL_MB_MAX_FRAMES) + +#define XE_SYSCTRL_MB_DEFAULT_TIMEOUT_MS 500 + +#endif -- cgit v1.2.3 From 5ea3f0dc8f9d33adf72532b366d0b7b91dae4d7f Mon Sep 17 00:00:00 2001 From: Anoop Vijay Date: Fri, 27 Mar 2026 06:18:41 -0700 Subject: drm/xe/xe_sysctrl: Add System Controller initialization support Add initialization and cleanup infrastructure for System Controller subsystem and integrate it into xe device probe path. During initialization, platform support is checked via has_sysctrl capability flag and the mailbox region is configured through SoC remapper interface. Signed-off-by: Anoop Vijay Reviewed-by: Umesh Nerlige Ramappa Signed-off-by: Umesh Nerlige Ramappa Link: https://patch.msgid.link/20260327131837.2192929-13-anoop.c.vijay@intel.com --- drivers/gpu/drm/xe/Makefile | 1 + drivers/gpu/drm/xe/xe_device.c | 5 +++ drivers/gpu/drm/xe/xe_sysctrl.c | 77 +++++++++++++++++++++++++++++++++++++++++ drivers/gpu/drm/xe/xe_sysctrl.h | 21 +++++++++++ 4 files changed, 104 insertions(+) create mode 100644 drivers/gpu/drm/xe/xe_sysctrl.c create mode 100644 drivers/gpu/drm/xe/xe_sysctrl.h diff --git a/drivers/gpu/drm/xe/Makefile b/drivers/gpu/drm/xe/Makefile index dab979287a96..800ab80f4b53 100644 --- a/drivers/gpu/drm/xe/Makefile +++ b/drivers/gpu/drm/xe/Makefile @@ -123,6 +123,7 @@ xe-y += xe_bb.o \ xe_step.o \ xe_survivability_mode.o \ xe_sync.o \ + xe_sysctrl.o \ xe_tile.o \ xe_tile_sysfs.o \ xe_tlb_inval.o \ diff --git a/drivers/gpu/drm/xe/xe_device.c b/drivers/gpu/drm/xe/xe_device.c index 91327f43a04d..4d4d7a35e089 100644 --- a/drivers/gpu/drm/xe/xe_device.c +++ b/drivers/gpu/drm/xe/xe_device.c @@ -65,6 +65,7 @@ #include "xe_survivability_mode.h" #include "xe_sriov.h" #include "xe_svm.h" +#include "xe_sysctrl.h" #include "xe_tile.h" #include "xe_ttm_stolen_mgr.h" #include "xe_ttm_sys_mgr.h" @@ -992,6 +993,10 @@ int xe_device_probe(struct xe_device *xe) if (err) goto err_unregister_display; + err = xe_sysctrl_init(xe); + if (err) + goto err_unregister_display; + err = xe_device_sysfs_init(xe); if (err) goto err_unregister_display; diff --git a/drivers/gpu/drm/xe/xe_sysctrl.c b/drivers/gpu/drm/xe/xe_sysctrl.c new file mode 100644 index 000000000000..f1b3af1748ad --- /dev/null +++ b/drivers/gpu/drm/xe/xe_sysctrl.c @@ -0,0 +1,77 @@ +// SPDX-License-Identifier: MIT +/* + * Copyright © 2026 Intel Corporation + */ + +#include +#include + +#include + +#include "regs/xe_sysctrl_regs.h" +#include "xe_device.h" +#include "xe_mmio.h" +#include "xe_soc_remapper.h" +#include "xe_sysctrl.h" +#include "xe_sysctrl_mailbox.h" +#include "xe_sysctrl_types.h" + +/** + * DOC: System Controller (sysctrl) + * + * System Controller (sysctrl) is a firmware-managed entity on Intel dGPUs + * responsible for selected low-level platform management functions. + * Communication between driver and System Controller is performed + * via a mailbox interface, enabling command and response exchange. + * + * This module provides initialization and support code for interacting + * with System Controller through the mailbox interface. + */ +static void sysctrl_fini(void *arg) +{ + struct xe_device *xe = arg; + + xe->soc_remapper.set_sysctrl_region(xe, 0); +} + +/** + * xe_sysctrl_init() - Initialize System Controller subsystem + * @xe: xe device instance + * + * Entry point for System Controller initialization, called from xe_device_probe. + * This function checks platform support and initializes the system controller. + * + * Return: 0 on success, error code on failure + */ +int xe_sysctrl_init(struct xe_device *xe) +{ + struct xe_tile *tile = xe_device_get_root_tile(xe); + struct xe_sysctrl *sc = &xe->sc; + int ret; + + if (!xe->info.has_soc_remapper_sysctrl) + return 0; + + if (!xe->info.has_sysctrl) + return 0; + + xe->soc_remapper.set_sysctrl_region(xe, SYSCTRL_MAILBOX_INDEX); + + ret = devm_add_action_or_reset(xe->drm.dev, sysctrl_fini, xe); + if (ret) + return ret; + + sc->mmio = devm_kzalloc(xe->drm.dev, sizeof(*sc->mmio), GFP_KERNEL); + if (!sc->mmio) + return -ENOMEM; + + xe_mmio_init(sc->mmio, tile, tile->mmio.regs, tile->mmio.regs_size); + sc->mmio->adj_offset = SYSCTRL_BASE; + sc->mmio->adj_limit = U32_MAX; + + ret = devm_mutex_init(xe->drm.dev, &sc->cmd_lock); + if (ret) + return ret; + + return 0; +} diff --git a/drivers/gpu/drm/xe/xe_sysctrl.h b/drivers/gpu/drm/xe/xe_sysctrl.h new file mode 100644 index 000000000000..d5d8735038ae --- /dev/null +++ b/drivers/gpu/drm/xe/xe_sysctrl.h @@ -0,0 +1,21 @@ +/* SPDX-License-Identifier: MIT */ +/* + * Copyright © 2026 Intel Corporation + */ + +#ifndef _XE_SYSCTRL_H_ +#define _XE_SYSCTRL_H_ + +#include + +#include "xe_device_types.h" +#include "xe_sysctrl_types.h" + +static inline struct xe_device *sc_to_xe(struct xe_sysctrl *sc) +{ + return container_of(sc, struct xe_device, sc); +} + +int xe_sysctrl_init(struct xe_device *xe); + +#endif -- cgit v1.2.3 From 1f95f618182b5c99d46378141e0fb84f09bf914b Mon Sep 17 00:00:00 2001 From: Anoop Vijay Date: Fri, 27 Mar 2026 06:18:42 -0700 Subject: drm/xe/xe_sysctrl: Add System Controller mailbox communication support Add mailbox communication layer required for interacting with System Controller firmware, enabling command submission and response handling. This patch implements command/response handling logic, including error and timeout handling. Signed-off-by: Anoop Vijay Reviewed-by: Umesh Nerlige Ramappa Signed-off-by: Umesh Nerlige Ramappa Link: https://patch.msgid.link/20260327131837.2192929-14-anoop.c.vijay@intel.com --- drivers/gpu/drm/xe/Makefile | 1 + drivers/gpu/drm/xe/xe_sysctrl.c | 2 + drivers/gpu/drm/xe/xe_sysctrl_mailbox.c | 371 ++++++++++++++++++++++++++++++++ 3 files changed, 374 insertions(+) create mode 100644 drivers/gpu/drm/xe/xe_sysctrl_mailbox.c diff --git a/drivers/gpu/drm/xe/Makefile b/drivers/gpu/drm/xe/Makefile index 800ab80f4b53..f9abaf687d46 100644 --- a/drivers/gpu/drm/xe/Makefile +++ b/drivers/gpu/drm/xe/Makefile @@ -124,6 +124,7 @@ xe-y += xe_bb.o \ xe_survivability_mode.o \ xe_sync.o \ xe_sysctrl.o \ + xe_sysctrl_mailbox.o \ xe_tile.o \ xe_tile_sysfs.o \ xe_tlb_inval.o \ diff --git a/drivers/gpu/drm/xe/xe_sysctrl.c b/drivers/gpu/drm/xe/xe_sysctrl.c index f1b3af1748ad..850f9dd7e9f0 100644 --- a/drivers/gpu/drm/xe/xe_sysctrl.c +++ b/drivers/gpu/drm/xe/xe_sysctrl.c @@ -73,5 +73,7 @@ int xe_sysctrl_init(struct xe_device *xe) if (ret) return ret; + xe_sysctrl_mailbox_init(sc); + return 0; } diff --git a/drivers/gpu/drm/xe/xe_sysctrl_mailbox.c b/drivers/gpu/drm/xe/xe_sysctrl_mailbox.c new file mode 100644 index 000000000000..3caa9f15875f --- /dev/null +++ b/drivers/gpu/drm/xe/xe_sysctrl_mailbox.c @@ -0,0 +1,371 @@ +// SPDX-License-Identifier: MIT +/* + * Copyright © 2026 Intel Corporation + */ + +#include +#include +#include +#include +#include + +#include "regs/xe_sysctrl_regs.h" +#include "xe_device.h" +#include "xe_mmio.h" +#include "xe_pm.h" +#include "xe_printk.h" +#include "xe_sysctrl.h" +#include "xe_sysctrl_mailbox.h" +#include "xe_sysctrl_mailbox_types.h" + +struct xe_sysctrl_mailbox_msg_hdr { + __le32 data; +} __packed; + +#define XE_SYSCTRL_HDR_GROUP_ID(hdr) \ + FIELD_GET(SYSCTRL_HDR_GROUP_ID_MASK, le32_to_cpu((hdr)->data)) + +#define XE_SYSCTRL_HDR_COMMAND(hdr) \ + FIELD_GET(SYSCTRL_HDR_COMMAND_MASK, le32_to_cpu((hdr)->data)) + +#define XE_SYSCTRL_HDR_IS_RESPONSE(hdr) \ + FIELD_GET(SYSCTRL_HDR_IS_RESPONSE, le32_to_cpu((hdr)->data)) + +#define XE_SYSCTRL_HDR_RESULT(hdr) \ + FIELD_GET(SYSCTRL_HDR_RESULT_MASK, le32_to_cpu((hdr)->data)) + +static bool sysctrl_wait_bit_clear(struct xe_sysctrl *sc, u32 bit_mask, + unsigned int timeout_ms) +{ + int ret; + + ret = xe_mmio_wait32_not(sc->mmio, SYSCTRL_MB_CTRL, bit_mask, bit_mask, + timeout_ms * 1000, NULL, false); + + return ret == 0; +} + +static bool sysctrl_wait_bit_set(struct xe_sysctrl *sc, u32 bit_mask, + unsigned int timeout_ms) +{ + int ret; + + ret = xe_mmio_wait32(sc->mmio, SYSCTRL_MB_CTRL, bit_mask, bit_mask, + timeout_ms * 1000, NULL, false); + + return ret == 0; +} + +static int sysctrl_write_frame(struct xe_sysctrl *sc, const void *frame, + size_t len) +{ + static const struct xe_reg regs[] = { + SYSCTRL_MB_DATA0, SYSCTRL_MB_DATA1, SYSCTRL_MB_DATA2, SYSCTRL_MB_DATA3 + }; + struct xe_device *xe = sc_to_xe(sc); + u32 val[XE_SYSCTRL_MB_FRAME_SIZE / sizeof(u32)] = {0}; + u32 dw = DIV_ROUND_UP(len, sizeof(u32)); + u32 i; + + xe_assert(xe, len > 0 && len <= XE_SYSCTRL_MB_FRAME_SIZE); + + memcpy(val, frame, len); + + for (i = 0; i < dw; i++) + xe_mmio_write32(sc->mmio, regs[i], val[i]); + + return 0; +} + +static int sysctrl_read_frame(struct xe_sysctrl *sc, void *frame, + size_t len) +{ + static const struct xe_reg regs[] = { + SYSCTRL_MB_DATA0, SYSCTRL_MB_DATA1, SYSCTRL_MB_DATA2, SYSCTRL_MB_DATA3 + }; + struct xe_device *xe = sc_to_xe(sc); + u32 val[XE_SYSCTRL_MB_FRAME_SIZE / sizeof(u32)] = {0}; + u32 dw = DIV_ROUND_UP(len, sizeof(u32)); + u32 i; + + xe_assert(xe, len > 0 && len <= XE_SYSCTRL_MB_FRAME_SIZE); + + for (i = 0; i < dw; i++) + val[i] = xe_mmio_read32(sc->mmio, regs[i]); + + memcpy(frame, val, len); + + return 0; +} + +static void sysctrl_clear_response(struct xe_sysctrl *sc) +{ + xe_mmio_rmw32(sc->mmio, SYSCTRL_MB_CTRL, SYSCTRL_MB_CTRL_RUN_BUSY_OUT, 0); +} + +static int sysctrl_prepare_command(struct xe_device *xe, + u8 group_id, u8 command, + const void *data_in, size_t data_in_len, + u8 **mbox_cmd, size_t *cmd_size) +{ + struct xe_sysctrl_mailbox_msg_hdr *hdr; + size_t size; + u8 *buffer; + + xe_assert(xe, command <= SYSCTRL_HDR_COMMAND_MAX); + + if (data_in_len > XE_SYSCTRL_MB_MAX_MESSAGE_SIZE - sizeof(*hdr)) { + xe_err(xe, "sysctrl: Input data too large: %zu bytes\n", data_in_len); + return -EINVAL; + } + + size = sizeof(*hdr) + data_in_len; + + buffer = kmalloc(size, GFP_KERNEL); + if (!buffer) + return -ENOMEM; + + hdr = (struct xe_sysctrl_mailbox_msg_hdr *)buffer; + hdr->data = cpu_to_le32(FIELD_PREP(SYSCTRL_HDR_GROUP_ID_MASK, group_id) | + FIELD_PREP(SYSCTRL_HDR_COMMAND_MASK, command)); + + if (data_in && data_in_len) + memcpy(buffer + sizeof(*hdr), data_in, data_in_len); + + *mbox_cmd = buffer; + *cmd_size = size; + + return 0; +} + +static int sysctrl_send_frames(struct xe_sysctrl *sc, + const u8 *mbox_cmd, + size_t cmd_size, unsigned int timeout_ms) +{ + struct xe_device *xe = sc_to_xe(sc); + u32 ctrl_reg, total_frames, frame; + size_t bytes_sent, frame_size; + + total_frames = DIV_ROUND_UP(cmd_size, XE_SYSCTRL_MB_FRAME_SIZE); + + if (!sysctrl_wait_bit_clear(sc, SYSCTRL_MB_CTRL_RUN_BUSY, timeout_ms)) { + xe_err(xe, "sysctrl: Mailbox busy\n"); + return -EBUSY; + } + + sc->phase_bit ^= 1; + bytes_sent = 0; + + for (frame = 0; frame < total_frames; frame++) { + frame_size = min_t(size_t, cmd_size - bytes_sent, XE_SYSCTRL_MB_FRAME_SIZE); + + if (sysctrl_write_frame(sc, mbox_cmd + bytes_sent, frame_size)) { + xe_err(xe, "sysctrl: Failed to write frame %u\n", frame); + sc->phase_bit = 0; + return -EIO; + } + + ctrl_reg = SYSCTRL_MB_CTRL_RUN_BUSY | + REG_FIELD_PREP(SYSCTRL_FRAME_CURRENT_MASK, frame) | + REG_FIELD_PREP(SYSCTRL_FRAME_TOTAL_MASK, total_frames - 1) | + SYSCTRL_MB_CTRL_CMD | + (sc->phase_bit ? SYSCTRL_FRAME_PHASE : 0); + + xe_mmio_write32(sc->mmio, SYSCTRL_MB_CTRL, ctrl_reg); + + if (!sysctrl_wait_bit_clear(sc, SYSCTRL_MB_CTRL_RUN_BUSY, timeout_ms)) { + xe_err(xe, "sysctrl: Frame %u acknowledgment timeout\n", frame); + sc->phase_bit = 0; + return -ETIMEDOUT; + } + + bytes_sent += frame_size; + } + + return 0; +} + +static int sysctrl_process_frame(struct xe_sysctrl *sc, void *out, + size_t frame_size, unsigned int timeout_ms, + bool *done) +{ + u32 curr_frame, total_frames, ctrl_reg; + struct xe_device *xe = sc_to_xe(sc); + int ret; + + if (!sysctrl_wait_bit_set(sc, SYSCTRL_MB_CTRL_RUN_BUSY_OUT, timeout_ms)) { + xe_err(xe, "sysctrl: Response frame timeout\n"); + return -ETIMEDOUT; + } + + ctrl_reg = xe_mmio_read32(sc->mmio, SYSCTRL_MB_CTRL); + total_frames = FIELD_GET(SYSCTRL_FRAME_TOTAL_MASK, ctrl_reg); + curr_frame = FIELD_GET(SYSCTRL_FRAME_CURRENT_MASK, ctrl_reg); + + ret = sysctrl_read_frame(sc, out, frame_size); + if (ret) + return ret; + + sysctrl_clear_response(sc); + + if (curr_frame == total_frames) + *done = true; + + return 0; +} + +static int sysctrl_receive_frames(struct xe_sysctrl *sc, + const struct xe_sysctrl_mailbox_msg_hdr *req, + void *data_out, size_t data_out_len, + size_t *rdata_len, unsigned int timeout_ms) +{ + struct xe_sysctrl_mailbox_msg_hdr *hdr; + struct xe_device *xe = sc_to_xe(sc); + size_t remain = sizeof(*hdr) + data_out_len; + u8 *buffer __free(kfree) = kzalloc(remain, GFP_KERNEL); + size_t frame_size; + bool done = false; + int ret = 0; + u8 *out; + + if (!buffer) + return -ENOMEM; + + out = buffer; + while (!done && remain) { + frame_size = min_t(size_t, remain, XE_SYSCTRL_MB_FRAME_SIZE); + + ret = sysctrl_process_frame(sc, out, frame_size, timeout_ms, + &done); + if (ret) + return ret; + + remain -= frame_size; + out += frame_size; + } + + hdr = (struct xe_sysctrl_mailbox_msg_hdr *)buffer; + + if (!XE_SYSCTRL_HDR_IS_RESPONSE(hdr) || + XE_SYSCTRL_HDR_GROUP_ID(hdr) != XE_SYSCTRL_HDR_GROUP_ID(req) || + XE_SYSCTRL_HDR_COMMAND(hdr) != XE_SYSCTRL_HDR_COMMAND(req)) { + xe_err(xe, "sysctrl: Response header mismatch\n"); + return -EPROTO; + } + + if (XE_SYSCTRL_HDR_RESULT(hdr) != 0) { + xe_err(xe, "sysctrl: Firmware error: 0x%02lx\n", + XE_SYSCTRL_HDR_RESULT(hdr)); + return -EIO; + } + + memcpy(data_out, hdr + 1, data_out_len); + *rdata_len = out - buffer - sizeof(*hdr); + + return 0; +} + +static int sysctrl_send_command(struct xe_sysctrl *sc, + const u8 *mbox_cmd, size_t cmd_size, + void *data_out, size_t data_out_len, + size_t *rdata_len, unsigned int timeout_ms) +{ + const struct xe_sysctrl_mailbox_msg_hdr *hdr; + size_t received; + int ret; + + ret = sysctrl_send_frames(sc, mbox_cmd, cmd_size, timeout_ms); + if (ret) + return ret; + + if (!data_out || !rdata_len) + return 0; + + hdr = (const struct xe_sysctrl_mailbox_msg_hdr *)mbox_cmd; + + ret = sysctrl_receive_frames(sc, hdr, data_out, data_out_len, + &received, timeout_ms); + if (ret) + return ret; + + *rdata_len = received; + + return 0; +} + +/** + * xe_sysctrl_mailbox_init - Initialize System Controller mailbox interface + * @sc: System controller structure + * + * Initialize system controller mailbox interface for communication. + */ +void xe_sysctrl_mailbox_init(struct xe_sysctrl *sc) +{ + u32 ctrl_reg; + + ctrl_reg = xe_mmio_read32(sc->mmio, SYSCTRL_MB_CTRL); + sc->phase_bit = (ctrl_reg & SYSCTRL_FRAME_PHASE) ? 1 : 0; +} + +/** + * xe_sysctrl_send_command() - Send mailbox command to System Controller + * @sc: System Controller instance + * @cmd: Command descriptor containing request header and payload buffers + * @rdata_len: Pointer to store actual response data length + * + * Sends a mailbox command to System Controller firmware using + * System Controller mailbox and waits for a response. + * + * Request payload is provided via @cmd->data_in and @cmd->data_in_len. + * If a response is expected, @cmd->data_out must point to a buffer of + * size @cmd->data_out_len supplied by caller. + * + * On success, @rdata_len is updated with number of valid response bytes + * returned by firmware, bounded by @cmd->data_out_len. + * + * Return: 0 on success, or negative errno on failure. + */ +int xe_sysctrl_send_command(struct xe_sysctrl *sc, + struct xe_sysctrl_mailbox_command *cmd, + size_t *rdata_len) +{ + struct xe_device *xe = sc_to_xe(sc); + u8 group_id, command_code; + u8 *mbox_cmd = NULL; + size_t cmd_size = 0; + int ret; + + guard(xe_pm_runtime_noresume)(xe); + + if (!xe->info.has_sysctrl) + return -ENODEV; + + xe_assert(xe, cmd->data_in || cmd->data_out); + xe_assert(xe, !cmd->data_in || cmd->data_in_len); + xe_assert(xe, !cmd->data_out || cmd->data_out_len); + + group_id = XE_SYSCTRL_APP_HDR_GROUP_ID(&cmd->header); + command_code = XE_SYSCTRL_APP_HDR_COMMAND(&cmd->header); + + might_sleep(); + + ret = sysctrl_prepare_command(xe, group_id, command_code, + cmd->data_in, cmd->data_in_len, + &mbox_cmd, &cmd_size); + if (ret) { + xe_err(xe, "sysctrl: Failed to prepare command: %pe\n", ERR_PTR(ret)); + return ret; + } + + guard(mutex)(&sc->cmd_lock); + + ret = sysctrl_send_command(sc, mbox_cmd, cmd_size, + cmd->data_out, cmd->data_out_len, rdata_len, + XE_SYSCTRL_MB_DEFAULT_TIMEOUT_MS); + if (ret) + xe_err(xe, "sysctrl: Mailbox command failed: %pe\n", ERR_PTR(ret)); + + kfree(mbox_cmd); + + return ret; +} -- cgit v1.2.3 From 02eca6edcb324bc37495930c344e235a90f42d72 Mon Sep 17 00:00:00 2001 From: Anoop Vijay Date: Fri, 27 Mar 2026 06:18:43 -0700 Subject: drm/xe/xe_sysctrl: Add System Controller power management support MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Add resume handling for System Controller to support system (S3/S4) and runtime power management transitions. On resume, restore SoC remapper configuration and mailbox interface to re‑establish communication with firmware. Signed-off-by: Anoop Vijay Reviewed-by: Umesh Nerlige Ramappa Reviewed-by: Badal Nilawar Signed-off-by: Umesh Nerlige Ramappa Link: https://patch.msgid.link/20260327131837.2192929-15-anoop.c.vijay@intel.com --- drivers/gpu/drm/xe/xe_pm.c | 6 ++++++ drivers/gpu/drm/xe/xe_sysctrl.c | 22 ++++++++++++++++++++++ drivers/gpu/drm/xe/xe_sysctrl.h | 1 + 3 files changed, 29 insertions(+) diff --git a/drivers/gpu/drm/xe/xe_pm.c b/drivers/gpu/drm/xe/xe_pm.c index 01185f10a883..d4672eb07476 100644 --- a/drivers/gpu/drm/xe/xe_pm.c +++ b/drivers/gpu/drm/xe/xe_pm.c @@ -26,6 +26,7 @@ #include "xe_pcode.h" #include "xe_pxp.h" #include "xe_sriov_vf_ccs.h" +#include "xe_sysctrl.h" #include "xe_trace.h" #include "xe_vm.h" #include "xe_wa.h" @@ -259,6 +260,8 @@ int xe_pm_resume(struct xe_device *xe) xe_i2c_pm_resume(xe, true); + xe_sysctrl_pm_resume(xe); + xe_irq_resume(xe); for_each_gt(gt, xe, id) { @@ -670,6 +673,9 @@ int xe_pm_runtime_resume(struct xe_device *xe) xe_i2c_pm_resume(xe, xe->d3cold.allowed); + if (xe->d3cold.allowed) + xe_sysctrl_pm_resume(xe); + xe_irq_resume(xe); for_each_gt(gt, xe, id) { diff --git a/drivers/gpu/drm/xe/xe_sysctrl.c b/drivers/gpu/drm/xe/xe_sysctrl.c index 850f9dd7e9f0..2bcef304eb9a 100644 --- a/drivers/gpu/drm/xe/xe_sysctrl.c +++ b/drivers/gpu/drm/xe/xe_sysctrl.c @@ -77,3 +77,25 @@ int xe_sysctrl_init(struct xe_device *xe) return 0; } + +/** + * xe_sysctrl_pm_resume() - System Controller resume handler + * @xe: xe device instance + * + * Invoked during system resume (S3/S4 to S0) and runtime resume from D3cold. + * Restores SoC remapper configuration and reinitializes mailbox interface. + */ +void xe_sysctrl_pm_resume(struct xe_device *xe) +{ + struct xe_sysctrl *sc = &xe->sc; + + if (!xe->info.has_soc_remapper_sysctrl) + return; + + if (!xe->info.has_sysctrl) + return; + + xe->soc_remapper.set_sysctrl_region(xe, SYSCTRL_MAILBOX_INDEX); + + xe_sysctrl_mailbox_init(sc); +} diff --git a/drivers/gpu/drm/xe/xe_sysctrl.h b/drivers/gpu/drm/xe/xe_sysctrl.h index d5d8735038ae..f3b0f3716b2f 100644 --- a/drivers/gpu/drm/xe/xe_sysctrl.h +++ b/drivers/gpu/drm/xe/xe_sysctrl.h @@ -17,5 +17,6 @@ static inline struct xe_device *sc_to_xe(struct xe_sysctrl *sc) } int xe_sysctrl_init(struct xe_device *xe); +void xe_sysctrl_pm_resume(struct xe_device *xe); #endif -- cgit v1.2.3 From a902767f91ba9818b792f1137d3a835310c7d265 Mon Sep 17 00:00:00 2001 From: Anoop Vijay Date: Fri, 27 Mar 2026 06:18:44 -0700 Subject: drm/xe/xe_pci: Enable System Controller support on CRI platform Enable System Controller support on CRI by setting has_sysctrl capability flag in device descriptor and runtime device information. This allows sysctrl subsystem and mailbox communication to be initialized on CRI platforms. Signed-off-by: Anoop Vijay Reviewed-by: Umesh Nerlige Ramappa Signed-off-by: Umesh Nerlige Ramappa Link: https://patch.msgid.link/20260327131837.2192929-16-anoop.c.vijay@intel.com --- drivers/gpu/drm/xe/xe_pci.c | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/drivers/gpu/drm/xe/xe_pci.c b/drivers/gpu/drm/xe/xe_pci.c index 01673d2b2464..26eb58e11056 100644 --- a/drivers/gpu/drm/xe/xe_pci.c +++ b/drivers/gpu/drm/xe/xe_pci.c @@ -465,6 +465,7 @@ static const struct xe_device_desc cri_desc = { .has_soc_remapper_sysctrl = true, .has_soc_remapper_telem = true, .has_sriov = true, + .has_sysctrl = true, .max_gt_per_tile = 2, MULTI_LRC_MASK, .require_force_probe = true, @@ -763,6 +764,7 @@ static int xe_info_init_early(struct xe_device *xe, xe->info.has_soc_remapper_telem = desc->has_soc_remapper_telem; xe->info.has_sriov = xe_configfs_primary_gt_allowed(to_pci_dev(xe->drm.dev)) && desc->has_sriov; + xe->info.has_sysctrl = desc->has_sysctrl; xe->info.skip_guc_pc = desc->skip_guc_pc; xe->info.skip_mtcfg = desc->skip_mtcfg; xe->info.skip_pcode = desc->skip_pcode; @@ -959,6 +961,12 @@ static int xe_info_init(struct xe_device *xe, xe->info.has_64bit_timestamp = graphics_desc->has_64bit_timestamp; xe->info.has_mem_copy_instr = GRAPHICS_VER(xe) >= 20; + if (IS_SRIOV_VF(xe)) { + xe->info.has_sysctrl = 0; + xe->info.has_soc_remapper_sysctrl = 0; + xe->info.has_soc_remapper_telem = 0; + } + xe_info_probe_tile_count(xe); for_each_remote_tile(tile, xe, id) { -- cgit v1.2.3 From 72d918472886b6e1b998b756303816737929ef0a Mon Sep 17 00:00:00 2001 From: Shuicheng Lin Date: Mon, 16 Mar 2026 22:27:23 +0000 Subject: drm/xe/ggtt: Remove duplicate XE_GGTT_FLAGS_64K macro definition XE_GGTT_FLAGS_64K is defined twice in xe_ggtt.c: once at file scope (alongside XE_GGTT_FLAGS_ONLINE) and once inside struct xe_ggtt. The duplicate inside the struct was originally the only definition when the struct lived in xe_ggtt_types.h, but when commit 4f3a998a173b ("drm/xe: Open-code GGTT MMIO access protection") added the file-scope definitions for both FLAGS_64K and FLAGS_ONLINE, it did not remove the pre-existing one inside the struct. Remove the redundant definition inside struct xe_ggtt, keeping only the file-scope pair at the top of the file. Cc: Matthew Brost Reviewed-by: Zongyao Bai Signed-off-by: Shuicheng Lin Link: https://patch.msgid.link/20260316222723.1722591-2-shuicheng.lin@intel.com --- drivers/gpu/drm/xe/xe_ggtt.c | 1 - 1 file changed, 1 deletion(-) diff --git a/drivers/gpu/drm/xe/xe_ggtt.c b/drivers/gpu/drm/xe/xe_ggtt.c index a848d1a41b9b..3552fa3cac4b 100644 --- a/drivers/gpu/drm/xe/xe_ggtt.c +++ b/drivers/gpu/drm/xe/xe_ggtt.c @@ -115,7 +115,6 @@ struct xe_ggtt { /** @size: Total usable size of this GGTT */ u64 size; -#define XE_GGTT_FLAGS_64K BIT(0) /** * @flags: Flags for this GGTT * Acceptable flags: -- cgit v1.2.3 From 5bf888673e0dda5a53220fa0c4956271a46c353c Mon Sep 17 00:00:00 2001 From: Jason Gunthorpe Date: Fri, 13 Mar 2026 14:41:05 -0300 Subject: udmabuf: Do not create malformed scatterlists Using a sg_set_folio() loop for every 4K results in a malformed scatterlist because sg_set_folio() has an issue with offsets > PAGE_SIZE and because scatterlist expects the creator to build a list which consolidates any physical contiguity. sg_alloc_table_from_pages() creates a valid scatterlist directly from a struct page array, so go back to that. Remove the offsets allocation and just store an array of tail pages as it did before the below commit. Everything wants that anyhow. Fixes: 0c8b91ef5100 ("udmabuf: add back support for mapping hugetlb pages") Reported-by: Julian Orth Closes: https://lore.kernel.org/all/20260308-scatterlist-v1-1-39c4566b0bba@gmail.com/ Signed-off-by: Jason Gunthorpe Reviewed-by: Vivek Kasireddy Signed-off-by: Vivek Kasireddy Link: https://patch.msgid.link/0-v1-42779f29381a+4b9-udmabuf_sg_jgg@nvidia.com --- drivers/dma-buf/udmabuf.c | 49 +++++++++++++---------------------------------- 1 file changed, 13 insertions(+), 36 deletions(-) diff --git a/drivers/dma-buf/udmabuf.c b/drivers/dma-buf/udmabuf.c index 94b8ecb892bb..5d6878604451 100644 --- a/drivers/dma-buf/udmabuf.c +++ b/drivers/dma-buf/udmabuf.c @@ -26,10 +26,10 @@ MODULE_PARM_DESC(size_limit_mb, "Max size of a dmabuf, in megabytes. Default is struct udmabuf { pgoff_t pagecount; - struct folio **folios; + struct page **pages; /** - * Unlike folios, pinned_folios is only used for unpin. + * Unlike pages, pinned_folios is only used for unpin. * So, nr_pinned is not the same to pagecount, the pinned_folios * only set each folio which already pinned when udmabuf_create. * Note that, since a folio may be pinned multiple times, each folio @@ -41,7 +41,6 @@ struct udmabuf { struct sg_table *sg; struct miscdevice *device; - pgoff_t *offsets; }; static vm_fault_t udmabuf_vm_fault(struct vm_fault *vmf) @@ -55,8 +54,7 @@ static vm_fault_t udmabuf_vm_fault(struct vm_fault *vmf) if (pgoff >= ubuf->pagecount) return VM_FAULT_SIGBUS; - pfn = folio_pfn(ubuf->folios[pgoff]); - pfn += ubuf->offsets[pgoff] >> PAGE_SHIFT; + pfn = page_to_pfn(ubuf->pages[pgoff]); ret = vmf_insert_pfn(vma, vmf->address, pfn); if (ret & VM_FAULT_ERROR) @@ -73,8 +71,7 @@ static vm_fault_t udmabuf_vm_fault(struct vm_fault *vmf) if (WARN_ON(pgoff >= ubuf->pagecount)) break; - pfn = folio_pfn(ubuf->folios[pgoff]); - pfn += ubuf->offsets[pgoff] >> PAGE_SHIFT; + pfn = page_to_pfn(ubuf->pages[pgoff]); /** * If the below vmf_insert_pfn() fails, we do not return an @@ -109,22 +106,11 @@ static int mmap_udmabuf(struct dma_buf *buf, struct vm_area_struct *vma) static int vmap_udmabuf(struct dma_buf *buf, struct iosys_map *map) { struct udmabuf *ubuf = buf->priv; - struct page **pages; void *vaddr; - pgoff_t pg; dma_resv_assert_held(buf->resv); - pages = kvmalloc_objs(*pages, ubuf->pagecount); - if (!pages) - return -ENOMEM; - - for (pg = 0; pg < ubuf->pagecount; pg++) - pages[pg] = folio_page(ubuf->folios[pg], - ubuf->offsets[pg] >> PAGE_SHIFT); - - vaddr = vm_map_ram(pages, ubuf->pagecount, -1); - kvfree(pages); + vaddr = vm_map_ram(ubuf->pages, ubuf->pagecount, -1); if (!vaddr) return -EINVAL; @@ -146,22 +132,18 @@ static struct sg_table *get_sg_table(struct device *dev, struct dma_buf *buf, { struct udmabuf *ubuf = buf->priv; struct sg_table *sg; - struct scatterlist *sgl; - unsigned int i = 0; int ret; sg = kzalloc_obj(*sg); if (!sg) return ERR_PTR(-ENOMEM); - ret = sg_alloc_table(sg, ubuf->pagecount, GFP_KERNEL); + ret = sg_alloc_table_from_pages(sg, ubuf->pages, ubuf->pagecount, 0, + ubuf->pagecount << PAGE_SHIFT, + GFP_KERNEL); if (ret < 0) goto err_alloc; - for_each_sg(sg->sgl, sgl, ubuf->pagecount, i) - sg_set_folio(sgl, ubuf->folios[i], PAGE_SIZE, - ubuf->offsets[i]); - ret = dma_map_sgtable(dev, sg, direction, 0); if (ret < 0) goto err_map; @@ -207,12 +189,8 @@ static void unpin_all_folios(struct udmabuf *ubuf) static __always_inline int init_udmabuf(struct udmabuf *ubuf, pgoff_t pgcnt) { - ubuf->folios = kvmalloc_objs(*ubuf->folios, pgcnt); - if (!ubuf->folios) - return -ENOMEM; - - ubuf->offsets = kvzalloc_objs(*ubuf->offsets, pgcnt); - if (!ubuf->offsets) + ubuf->pages = kvmalloc_objs(*ubuf->pages, pgcnt); + if (!ubuf->pages) return -ENOMEM; ubuf->pinned_folios = kvmalloc_objs(*ubuf->pinned_folios, pgcnt); @@ -225,8 +203,7 @@ static __always_inline int init_udmabuf(struct udmabuf *ubuf, pgoff_t pgcnt) static __always_inline void deinit_udmabuf(struct udmabuf *ubuf) { unpin_all_folios(ubuf); - kvfree(ubuf->offsets); - kvfree(ubuf->folios); + kvfree(ubuf->pages); } static void release_udmabuf(struct dma_buf *buf) @@ -344,8 +321,8 @@ static long udmabuf_pin_folios(struct udmabuf *ubuf, struct file *memfd, ubuf->pinned_folios[nr_pinned++] = folios[cur_folio]; for (; subpgoff < fsize; subpgoff += PAGE_SIZE) { - ubuf->folios[upgcnt] = folios[cur_folio]; - ubuf->offsets[upgcnt] = subpgoff; + ubuf->pages[upgcnt] = folio_page(folios[cur_folio], + subpgoff >> PAGE_SHIFT); ++upgcnt; if (++cur_pgcnt >= pgcnt) -- cgit v1.2.3 From fb7b1a0ab25a6077d26cb3829e31743972d4f31d Mon Sep 17 00:00:00 2001 From: Mikhail Gavrilov Date: Sun, 15 Mar 2026 04:27:22 +0500 Subject: udmabuf: fix DMA direction mismatch in release_udmabuf() begin_cpu_udmabuf() maps the sg_table with the caller-provided direction (e.g., DMA_TO_DEVICE for a write-only sync), and caches it in ubuf->sg for reuse. However, release_udmabuf() always unmaps this sg_table with a hardcoded DMA_BIDIRECTIONAL, regardless of the direction that was originally used for the mapping. With CONFIG_DMA_API_DEBUG=y this produces: DMA-API: misc udmabuf: device driver frees DMA memory with different direction [device address=0x000000044a123000] [size=4096 bytes] [mapped with DMA_TO_DEVICE] [unmapped with DMA_BIDIRECTIONAL] The issue was found during video playback when GStreamer performed a write-only DMA_BUF_IOCTL_SYNC on a udmabuf. It can be reproduced with CONFIG_DMA_API_DEBUG=y by creating a udmabuf from a memfd, performing a write-only sync (DMA_BUF_SYNC_WRITE without DMA_BUF_SYNC_READ), and closing the file descriptor. Fix this by storing the DMA direction used when the sg_table is first created in begin_cpu_udmabuf(), and passing that same direction to put_sg_table() in release_udmabuf(). Fixes: 284562e1f348 ("udmabuf: implement begin_cpu_access/end_cpu_access hooks") Cc: stable@vger.kernel.org Signed-off-by: Mikhail Gavrilov Reviewed-by: Vivek Kasireddy Signed-off-by: Vivek Kasireddy Link: https://patch.msgid.link/20260314232722.15555-1-mikhail.v.gavrilov@gmail.com --- drivers/dma-buf/udmabuf.c | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/drivers/dma-buf/udmabuf.c b/drivers/dma-buf/udmabuf.c index 5d6878604451..94b26ea706a3 100644 --- a/drivers/dma-buf/udmabuf.c +++ b/drivers/dma-buf/udmabuf.c @@ -40,6 +40,7 @@ struct udmabuf { struct folio **pinned_folios; struct sg_table *sg; + enum dma_data_direction sg_dir; struct miscdevice *device; }; @@ -212,7 +213,7 @@ static void release_udmabuf(struct dma_buf *buf) struct device *dev = ubuf->device->this_device; if (ubuf->sg) - put_sg_table(dev, ubuf->sg, DMA_BIDIRECTIONAL); + put_sg_table(dev, ubuf->sg, ubuf->sg_dir); deinit_udmabuf(ubuf); kfree(ubuf); @@ -230,6 +231,8 @@ static int begin_cpu_udmabuf(struct dma_buf *buf, if (IS_ERR(ubuf->sg)) { ret = PTR_ERR(ubuf->sg); ubuf->sg = NULL; + } else { + ubuf->sg_dir = direction; } } else { dma_sync_sgtable_for_cpu(dev, ubuf->sg, direction); -- cgit v1.2.3 From 328815979c4a45e71410391d57cd7299c7c6d405 Mon Sep 17 00:00:00 2001 From: Chenyu Chen Date: Fri, 27 Mar 2026 16:21:58 +0800 Subject: drm/edid: Parse AMD Vendor-Specific Data Block Parse the AMD VSDB v3 from CTA extension blocks and store the result in struct drm_amd_vsdb_info, a new field of drm_display_info. This includes replay mode, panel type, and luminance ranges. Signed-off-by: Chenyu Chen Reviewed-by: Mario Limonciello (AMD) Link: https://patch.msgid.link/20260327082342.1286878-2-chen-yu.chen@amd.com Signed-off-by: Mario Limonciello (AMD) --- drivers/gpu/drm/drm_edid.c | 72 +++++++++++++++++++++++++++++++++++++++++++++ include/drm/drm_connector.h | 38 ++++++++++++++++++++++++ 2 files changed, 110 insertions(+) diff --git a/drivers/gpu/drm/drm_edid.c b/drivers/gpu/drm/drm_edid.c index 5f9fcd7d9ce4..4385d13bd382 100644 --- a/drivers/gpu/drm/drm_edid.c +++ b/drivers/gpu/drm/drm_edid.c @@ -99,6 +99,29 @@ enum drm_edid_internal_quirk { }; #define MICROSOFT_IEEE_OUI 0xca125c +#define AMD_IEEE_OUI 0x00001A + +#define AMD_VSDB_V3_PAYLOAD_MIN_LEN 15 +#define AMD_VSDB_V3_PAYLOAD_MAX_LEN 20 + +struct amd_vsdb_v3_payload { + u8 oui[3]; + u8 version; + u8 feature_caps; + u8 rsvd0[3]; + u8 cs_eotf_support; + u8 lum1_max; + u8 lum1_min; + u8 lum2_max; + u8 lum2_min; + u8 rsvd1[2]; + /* + * Bytes beyond AMD_VSDB_V3_PAYLOAD_MIN_LEN are optional; a + * monitor may provide a payload as short as 15 bytes. Always + * check cea_db_payload_len() before accessing extra[]. + */ + u8 extra[AMD_VSDB_V3_PAYLOAD_MAX_LEN - AMD_VSDB_V3_PAYLOAD_MIN_LEN]; +} __packed; struct detailed_mode_closure { struct drm_connector *connector; @@ -5205,6 +5228,13 @@ static bool cea_db_is_microsoft_vsdb(const struct cea_db *db) cea_db_payload_len(db) == 21; } +static bool cea_db_is_amd_vsdb(const struct cea_db *db) +{ + return cea_db_is_vendor(db, AMD_IEEE_OUI) && + cea_db_payload_len(db) >= AMD_VSDB_V3_PAYLOAD_MIN_LEN && + cea_db_payload_len(db) <= AMD_VSDB_V3_PAYLOAD_MAX_LEN; +} + static bool cea_db_is_vcdb(const struct cea_db *db) { return cea_db_is_extended_tag(db, CTA_EXT_DB_VIDEO_CAP) && @@ -6401,6 +6431,45 @@ static void drm_parse_microsoft_vsdb(struct drm_connector *connector, connector->base.id, connector->name, version, db[5]); } +static void drm_parse_amd_vsdb(struct drm_connector *connector, + const struct cea_db *db) +{ + struct drm_display_info *info = &connector->display_info; + const u8 *data = cea_db_data(db); + const struct amd_vsdb_v3_payload *p; + + p = (const struct amd_vsdb_v3_payload *)data; + + if (p->version != 0x03) { + drm_dbg_kms(connector->dev, + "[CONNECTOR:%d:%s] Unsupported AMD VSDB version %u\n", + connector->base.id, connector->name, p->version); + return; + } + + info->amd_vsdb.version = p->version; + info->amd_vsdb.replay_mode = p->feature_caps & 0x40; + info->amd_vsdb.panel_type = (p->cs_eotf_support & 0xC0) >> 6; + info->amd_vsdb.luminance_range1.max_luminance = p->lum1_max; + info->amd_vsdb.luminance_range1.min_luminance = p->lum1_min; + info->amd_vsdb.luminance_range2.max_luminance = p->lum2_max; + info->amd_vsdb.luminance_range2.min_luminance = p->lum2_min; + + /* + * The AMD VSDB v3 payload length is variable (15..20 bytes). + * All fields through p->rsvd1 (byte 14) are always present, + * but p->extra[] (bytes 15+) may not be. Any future access to + * extra[] must be guarded with a runtime length check to avoid + * out-of-bounds reads on shorter (but spec-valid) payloads. + * For example: + * + * int len = cea_db_payload_len(db); + * + * if (len > AMD_VSDB_V3_PAYLOAD_MIN_LEN) + * info->amd_vsdb.foo = p->extra[0]; + */ +} + static void drm_parse_cea_ext(struct drm_connector *connector, const struct drm_edid *drm_edid) { @@ -6449,6 +6518,8 @@ static void drm_parse_cea_ext(struct drm_connector *connector, drm_parse_hdmi_forum_scds(connector, data); else if (cea_db_is_microsoft_vsdb(db)) drm_parse_microsoft_vsdb(connector, data); + else if (cea_db_is_amd_vsdb(db)) + drm_parse_amd_vsdb(connector, db); else if (cea_db_is_y420cmdb(db)) parse_cta_y420cmdb(connector, db, &y420cmdb_map); else if (cea_db_is_y420vdb(db)) @@ -6641,6 +6712,7 @@ static void drm_reset_display_info(struct drm_connector *connector) info->quirks = 0; info->source_physical_address = CEC_PHYS_ADDR_INVALID; + memset(&info->amd_vsdb, 0, sizeof(info->amd_vsdb)); } static void update_displayid_info(struct drm_connector *connector, diff --git a/include/drm/drm_connector.h b/include/drm/drm_connector.h index af8b92d2d5b7..f83f28cae207 100644 --- a/include/drm/drm_connector.h +++ b/include/drm/drm_connector.h @@ -693,6 +693,39 @@ enum drm_bus_flags { DRM_BUS_FLAG_SHARP_SIGNALS = BIT(8), }; +/** + * struct drm_amd_vsdb_info - AMD-specific VSDB information + * + * This structure holds information parsed from the AMD Vendor-Specific Data + * Block (VSDB) version 3. + */ +struct drm_amd_vsdb_info { + /** + * @version: Version of the Vendor-Specific Data Block (VSDB) + */ + u8 version; + + /** + * @replay_mode: Panel Replay supported + */ + bool replay_mode; + + /** + * @panel_type: Panel technology type + */ + u8 panel_type; + + /** + * @luminance_range1: Luminance for max back light + */ + struct drm_luminance_range_info luminance_range1; + + /** + * @luminance_range2: Luminance for min back light + */ + struct drm_luminance_range_info luminance_range2; +}; + /** * struct drm_display_info - runtime data about the connected sink * @@ -883,6 +916,11 @@ struct drm_display_info { * Defaults to CEC_PHYS_ADDR_INVALID (0xffff). */ u16 source_physical_address; + + /** + * @amd_vsdb: AMD-specific VSDB information. + */ + struct drm_amd_vsdb_info amd_vsdb; }; int drm_display_info_set_bus_formats(struct drm_display_info *info, -- cgit v1.2.3 From f263bcdcc05e99f26f7bb0b0ba860dccd60256dc Mon Sep 17 00:00:00 2001 From: Chenyu Chen Date: Fri, 27 Mar 2026 16:21:59 +0800 Subject: drm/amd/display: Use drm_display_info for AMD VSDB data Replace the raw EDID byte-walking in parse_amd_vsdb() with a read from connector->display_info.amd_vsdb, now populated by drm_edid. Factor out panel type determination into dm_set_panel_type(), which checks VSDB panel_type, DPCD ext caps, and a luminance heuristic as fallbacks. Signed-off-by: Chenyu Chen Reviewed-by: Mario Limonciello (AMD) Link: https://patch.msgid.link/20260327082342.1286878-3-chen-yu.chen@amd.com Signed-off-by: Mario Limonciello (AMD) --- drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c | 120 ++++++++++++---------- drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.h | 14 --- 2 files changed, 68 insertions(+), 66 deletions(-) diff --git a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c index 205a7fab1037..69fe3f5421e8 100644 --- a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c +++ b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c @@ -3825,6 +3825,66 @@ static struct drm_mode_config_helper_funcs amdgpu_dm_mode_config_helperfuncs = { .atomic_commit_setup = amdgpu_dm_atomic_setup_commit, }; +#define DDC_MANUFACTURERNAME_SAMSUNG 0x2D4C + +static void dm_set_panel_type(struct amdgpu_dm_connector *aconnector) +{ + struct drm_connector *connector = &aconnector->base; + struct drm_display_info *display_info = &connector->display_info; + struct dc_link *link = aconnector->dc_link; + struct amdgpu_device *adev; + + adev = drm_to_adev(connector->dev); + + link->panel_type = PANEL_TYPE_NONE; + + switch (display_info->amd_vsdb.panel_type) { + case AMD_VSDB_PANEL_TYPE_OLED: + link->panel_type = PANEL_TYPE_OLED; + break; + case AMD_VSDB_PANEL_TYPE_MINILED: + link->panel_type = PANEL_TYPE_MINILED; + break; + } + + /* If VSDB didn't determine panel type, check DPCD ext caps */ + if (link->panel_type == PANEL_TYPE_NONE) { + if (link->dpcd_sink_ext_caps.bits.miniled == 1) + link->panel_type = PANEL_TYPE_MINILED; + if (link->dpcd_sink_ext_caps.bits.oled == 1) + link->panel_type = PANEL_TYPE_OLED; + } + + /* + * TODO: get panel type from DID2 that has device technology field + * to specify if it's OLED or not. But we need to wait for DID2 + * support in DC and EDID parser to be able to use it here. + */ + + if (link->panel_type == PANEL_TYPE_NONE) { + struct drm_amd_vsdb_info *vsdb = &display_info->amd_vsdb; + u32 lum1_max = vsdb->luminance_range1.max_luminance; + u32 lum2_max = vsdb->luminance_range2.max_luminance; + + if (vsdb->version && link->local_sink && + link->local_sink->edid_caps.manufacturer_id == + DDC_MANUFACTURERNAME_SAMSUNG && + lum1_max >= ((lum2_max * 3) / 2)) + link->panel_type = PANEL_TYPE_MINILED; + } + + if (link->panel_type == PANEL_TYPE_OLED) + drm_object_property_set_value(&connector->base, + adev_to_drm(adev)->mode_config.panel_type_property, + DRM_MODE_PANEL_TYPE_OLED); + else + drm_object_property_set_value(&connector->base, + adev_to_drm(adev)->mode_config.panel_type_property, + DRM_MODE_PANEL_TYPE_UNKNOWN); + + drm_dbg_kms(aconnector->base.dev, "Panel type: %d\n", link->panel_type); +} + static void update_connector_ext_caps(struct amdgpu_dm_connector *aconnector) { const struct drm_panel_backlight_quirk *panel_backlight_quirk; @@ -3846,10 +3906,6 @@ static void update_connector_ext_caps(struct amdgpu_dm_connector *aconnector) caps->ext_caps = &aconnector->dc_link->dpcd_sink_ext_caps; caps->aux_support = false; - drm_object_property_set_value(&conn_base->base, - adev_to_drm(adev)->mode_config.panel_type_property, - caps->ext_caps->bits.oled ? DRM_MODE_PANEL_TYPE_OLED : DRM_MODE_PANEL_TYPE_UNKNOWN); - if (caps->ext_caps->bits.oled == 1 /* * || @@ -4023,6 +4079,7 @@ void amdgpu_dm_update_connector_after_detect( amdgpu_dm_update_freesync_caps(connector, aconnector->drm_edid); update_connector_ext_caps(aconnector); + dm_set_panel_type(aconnector); } else { hdmi_cec_unset_edid(aconnector); drm_dp_cec_unset_edid(&aconnector->dm_dp_aux.aux); @@ -13170,56 +13227,15 @@ static void parse_edid_displayid_vrr(struct drm_connector *connector, } } -static int parse_amd_vsdb(struct amdgpu_dm_connector *aconnector, - const struct edid *edid, struct amdgpu_hdmi_vsdb_info *vsdb_info) +static int get_amd_vsdb(struct amdgpu_dm_connector *aconnector, + struct amdgpu_hdmi_vsdb_info *vsdb_info) { - u8 *edid_ext = NULL; - int i; - int j = 0; - int total_ext_block_len; - - if (edid == NULL || edid->extensions == 0) - return -ENODEV; - - /* Find DisplayID extension */ - for (i = 0; i < edid->extensions; i++) { - edid_ext = (void *)(edid + (i + 1)); - if (edid_ext[0] == DISPLAYID_EXT) - break; - } - - total_ext_block_len = EDID_LENGTH * edid->extensions; - while (j < total_ext_block_len - sizeof(struct amd_vsdb_block)) { - struct amd_vsdb_block *amd_vsdb = (struct amd_vsdb_block *)&edid_ext[j]; - unsigned int ieeeId = (amd_vsdb->ieee_id[2] << 16) | (amd_vsdb->ieee_id[1] << 8) | (amd_vsdb->ieee_id[0]); - - if (ieeeId == HDMI_AMD_VENDOR_SPECIFIC_DATA_BLOCK_IEEE_REGISTRATION_ID && - amd_vsdb->version == HDMI_AMD_VENDOR_SPECIFIC_DATA_BLOCK_VERSION_3) { - u8 panel_type; - vsdb_info->replay_mode = (amd_vsdb->feature_caps & AMD_VSDB_VERSION_3_FEATURECAP_REPLAYMODE) ? true : false; - vsdb_info->amd_vsdb_version = HDMI_AMD_VENDOR_SPECIFIC_DATA_BLOCK_VERSION_3; - drm_dbg_kms(aconnector->base.dev, "Panel supports Replay Mode: %d\n", vsdb_info->replay_mode); - panel_type = (amd_vsdb->color_space_eotf_support & AMD_VDSB_VERSION_3_PANEL_TYPE_MASK) >> AMD_VDSB_VERSION_3_PANEL_TYPE_SHIFT; - switch (panel_type) { - case AMD_VSDB_PANEL_TYPE_OLED: - aconnector->dc_link->panel_type = PANEL_TYPE_OLED; - break; - case AMD_VSDB_PANEL_TYPE_MINILED: - aconnector->dc_link->panel_type = PANEL_TYPE_MINILED; - break; - default: - aconnector->dc_link->panel_type = PANEL_TYPE_NONE; - break; - } - drm_dbg_kms(aconnector->base.dev, "Panel type: %d\n", - aconnector->dc_link->panel_type); + struct drm_connector *connector = &aconnector->base; - return true; - } - j++; - } + vsdb_info->replay_mode = connector->display_info.amd_vsdb.replay_mode; + vsdb_info->amd_vsdb_version = connector->display_info.amd_vsdb.version; - return false; + return connector->display_info.amd_vsdb.version != 0; } static int parse_hdmi_amd_vsdb(struct amdgpu_dm_connector *aconnector, @@ -13322,7 +13338,7 @@ void amdgpu_dm_update_freesync_caps(struct drm_connector *connector, freesync_capable = true; } - parse_amd_vsdb(amdgpu_dm_connector, edid, &vsdb_info); + get_amd_vsdb(amdgpu_dm_connector, &vsdb_info); if (vsdb_info.replay_mode) { amdgpu_dm_connector->vsdb_info.replay_mode = vsdb_info.replay_mode; diff --git a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.h b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.h index d1a14e0c12bd..63ce1f52b697 100644 --- a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.h +++ b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.h @@ -53,12 +53,6 @@ #define AMDGPU_DMUB_NOTIFICATION_MAX 8 -#define HDMI_AMD_VENDOR_SPECIFIC_DATA_BLOCK_IEEE_REGISTRATION_ID 0x00001A -#define AMD_VSDB_VERSION_3_FEATURECAP_REPLAYMODE 0x40 -#define AMD_VDSB_VERSION_3_PANEL_TYPE_MASK 0xC0 -#define AMD_VDSB_VERSION_3_PANEL_TYPE_SHIFT 6 -#define HDMI_AMD_VENDOR_SPECIFIC_DATA_BLOCK_VERSION_3 0x3 - enum amd_vsdb_panel_type { AMD_VSDB_PANEL_TYPE_DEFAULT = 0, AMD_VSDB_PANEL_TYPE_MINILED, @@ -97,14 +91,6 @@ struct dc_plane_state; struct dmub_notification; struct dmub_cmd_fused_request; -struct amd_vsdb_block { - unsigned char ieee_id[3]; - unsigned char version; - unsigned char feature_caps; - unsigned char reserved[3]; - unsigned char color_space_eotf_support; -}; - struct common_irq_params { struct amdgpu_device *adev; enum dc_irq_source irq_src; -- cgit v1.2.3 From f47bf47a1afaf5a8ad3629f1fd4a5a0150ae59e9 Mon Sep 17 00:00:00 2001 From: Chen Ni Date: Fri, 27 Mar 2026 11:29:23 +0800 Subject: drm/xe/vm: Convert comma to semicolon Using a ',' in place of a ';' can have unintended side effects. Although that is not the case here, it seems best to use ';' unless ',' is intended. Found by inspection. No functional change intended. Compile tested only. Signed-off-by: Chen Ni Reviewed-by: Shuicheng Lin Signed-off-by: Shuicheng Lin Link: https://patch.msgid.link/20260327032923.649869-1-nichen@iscas.ac.cn --- drivers/gpu/drm/xe/xe_vm.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/gpu/drm/xe/xe_vm.c b/drivers/gpu/drm/xe/xe_vm.c index 56e2db50bb36..72559bd33946 100644 --- a/drivers/gpu/drm/xe/xe_vm.c +++ b/drivers/gpu/drm/xe/xe_vm.c @@ -634,9 +634,9 @@ void xe_vm_add_fault_entry_pf(struct xe_vm *vm, struct xe_pagefault *pf) e->address_precision = SZ_4K; e->access_type = pf->consumer.access_type; e->fault_type = FIELD_GET(XE_PAGEFAULT_TYPE_MASK, - pf->consumer.fault_type_level), + pf->consumer.fault_type_level); e->fault_level = FIELD_GET(XE_PAGEFAULT_LEVEL_MASK, - pf->consumer.fault_type_level), + pf->consumer.fault_type_level); list_add_tail(&e->list, &vm->faults.list); vm->faults.len++; -- cgit v1.2.3 From 3b6e473cdc9c8494a1030fcde5589aa22deb02c9 Mon Sep 17 00:00:00 2001 From: Ville Syrjälä Date: Mon, 30 Mar 2026 23:26:28 +0300 Subject: drm/i915/dp: Implement the POST_LT_ADJ_REQ sequence MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Implement the POST_LT_ADJ_REQ sequence, which should be used to further fine tune the link if TPS4 is not supported. The POST_LT_ADJ_REQ sequence will be performed after the normal link training has succeeded. Only the final hop between the last LTTPR and DPRX will perform the POST_LT_ADJ_REQ adjustment. The earlier hops will use TPS4 instead since it's mandatory for LTTPRs. The sequence will terminate when the sink clears the "in progress" flag, the vswing/pre-emphasis values have changed six times, or the vswing/pre-emphasis values have remained unchanged for 200 ms. Tested-by: Imre Deak Reviewed-by: Imre Deak Signed-off-by: Ville Syrjälä Link: https://patch.msgid.link/20260330202629.28616-2-ville.syrjala@linux.intel.com --- .../gpu/drm/i915/display/intel_dp_link_training.c | 124 ++++++++++++++++++++- .../gpu/drm/i915/display/intel_dp_link_training.h | 2 +- drivers/gpu/drm/i915/display/intel_dp_mst.c | 2 +- 3 files changed, 124 insertions(+), 4 deletions(-) diff --git a/drivers/gpu/drm/i915/display/intel_dp_link_training.c b/drivers/gpu/drm/i915/display/intel_dp_link_training.c index 54c585c59b90..a26094223f78 100644 --- a/drivers/gpu/drm/i915/display/intel_dp_link_training.c +++ b/drivers/gpu/drm/i915/display/intel_dp_link_training.c @@ -742,11 +742,14 @@ static void intel_dp_update_downspread_ctrl(struct intel_dp *intel_dp, void intel_dp_link_training_set_bw(struct intel_dp *intel_dp, int link_bw, int rate_select, int lane_count, - bool enhanced_framing) + bool enhanced_framing, bool post_lt_adj_req) { if (enhanced_framing) lane_count |= DP_LANE_COUNT_ENHANCED_FRAME_EN; + if (post_lt_adj_req) + lane_count |= DP_POST_LT_ADJ_REQ_GRANTED; + if (link_bw) { /* DP and eDP v1.3 and earlier link bw set method. */ u8 link_config[] = { link_bw, lane_count }; @@ -825,12 +828,21 @@ static u32 intel_dp_training_pattern(struct intel_dp *intel_dp, return DP_TRAINING_PATTERN_2; } +static bool intel_dp_use_post_lt_adj_req(struct intel_dp *intel_dp, + const struct intel_crtc_state *crtc_state) +{ + return intel_dp->set_idle_link_train && + drm_dp_post_lt_adj_req_supported(intel_dp->dpcd) && + intel_dp_training_pattern(intel_dp, crtc_state, DP_PHY_DPRX) != DP_TRAINING_PATTERN_4; +} + static void intel_dp_update_link_bw_set(struct intel_dp *intel_dp, const struct intel_crtc_state *crtc_state, u8 link_bw, u8 rate_select) { intel_dp_link_training_set_bw(intel_dp, link_bw, rate_select, crtc_state->lane_count, - crtc_state->enhanced_framing); + crtc_state->enhanced_framing, + intel_dp_use_post_lt_adj_req(intel_dp, crtc_state)); } /* @@ -1091,6 +1103,109 @@ intel_dp_link_training_channel_equalization(struct intel_dp *intel_dp, return channel_eq; } +static bool +intel_dp_post_lt_adj_req(struct intel_dp *intel_dp, + const struct intel_crtc_state *crtc_state) +{ + u8 link_status[DP_LINK_STATUS_SIZE]; + unsigned long deadline; + bool timeout = false; + bool success = false; + int changes = 0; + + if (!intel_dp_use_post_lt_adj_req(intel_dp, crtc_state)) + return true; + + if (drm_dp_dpcd_read_phy_link_status(&intel_dp->aux, DP_PHY_DPRX, + link_status) < 0) { + lt_err(intel_dp, DP_PHY_DPRX, "Failed to get link status\n"); + return false; + } + + deadline = jiffies + msecs_to_jiffies_timeout(200); + + for (;;) { + /* Make sure clock is still ok */ + if (!drm_dp_clock_recovery_ok(link_status, + crtc_state->lane_count)) { + intel_dp_dump_link_status(intel_dp, DP_PHY_DPRX, link_status); + lt_dbg(intel_dp, DP_PHY_DPRX, + "Clock recovery check failed, cannot continue POST_LT_ADJ_REQ\n"); + break; + } + + if (!drm_dp_channel_eq_ok(link_status, + crtc_state->lane_count)) { + intel_dp_dump_link_status(intel_dp, DP_PHY_DPRX, link_status); + lt_dbg(intel_dp, DP_PHY_DPRX, "Channel EQ check failed. cannot continue POST_LT_ADJ_REQ\n"); + break; + } + + if (!drm_dp_post_lt_adj_req_in_progress(link_status)) { + success = true; + intel_dp_dump_link_status(intel_dp, DP_PHY_DPRX, link_status); + lt_dbg(intel_dp, DP_PHY_DPRX, + "POST_LT_ADJ_REQ done (%d changes). DP Training successful\n", changes); + break; + } + + if (changes == 6) { + success = true; + intel_dp_dump_link_status(intel_dp, DP_PHY_DPRX, link_status); + lt_dbg(intel_dp, DP_PHY_DPRX, + "POST_LT_ADJ_REQ limit reached (%d changes). DP Training successful\n", changes); + break; + } + + if (timeout) { + success = true; + intel_dp_dump_link_status(intel_dp, DP_PHY_DPRX, link_status); + lt_dbg(intel_dp, DP_PHY_DPRX, + "POST_LT_ADJ_REQ timeout reached (%d changes). DP Training successful\n", changes); + break; + } + + fsleep(5000); + + if (drm_dp_dpcd_read_phy_link_status(&intel_dp->aux, DP_PHY_DPRX, + link_status) < 0) { + lt_err(intel_dp, DP_PHY_DPRX, "Failed to get link status\n"); + break; + } + + /* Update training set as requested by target */ + if (intel_dp_get_adjust_train(intel_dp, crtc_state, DP_PHY_DPRX, link_status)) { + deadline = jiffies + msecs_to_jiffies_timeout(200); + changes++; + + if (!intel_dp_update_link_train(intel_dp, crtc_state, DP_PHY_DPRX)) { + lt_err(intel_dp, DP_PHY_DPRX, "Failed to update link training\n"); + break; + } + } else if (time_after(jiffies, deadline)) { + timeout = true; + } + } + + return success; +} + +static void intel_dp_stop_post_lt_adj_req(struct intel_dp *intel_dp, + const struct intel_crtc_state *crtc_state) +{ + u8 lane_count; + + if (!intel_dp_use_post_lt_adj_req(intel_dp, crtc_state)) + return; + + /* clear DP_POST_LT_ADJ_REQ_GRANTED */ + lane_count = crtc_state->lane_count; + if (crtc_state->enhanced_framing) + lane_count |= DP_LANE_COUNT_ENHANCED_FRAME_EN; + + drm_dp_dpcd_writeb(&intel_dp->aux, DP_LANE_COUNT_SET, lane_count); +} + static bool intel_dp_disable_dpcd_training_pattern(struct intel_dp *intel_dp, enum drm_dp_phy dp_phy) { @@ -1389,6 +1504,11 @@ intel_dp_link_train_all_phys(struct intel_dp *intel_dp, intel_dp_disable_dpcd_training_pattern(intel_dp, DP_PHY_DPRX); intel_dp->set_idle_link_train(intel_dp, crtc_state); + if (ret) + ret = intel_dp_post_lt_adj_req(intel_dp, crtc_state); + + intel_dp_stop_post_lt_adj_req(intel_dp, crtc_state); + return ret; } diff --git a/drivers/gpu/drm/i915/display/intel_dp_link_training.h b/drivers/gpu/drm/i915/display/intel_dp_link_training.h index 1ba22ed6db08..33dcbde6a408 100644 --- a/drivers/gpu/drm/i915/display/intel_dp_link_training.h +++ b/drivers/gpu/drm/i915/display/intel_dp_link_training.h @@ -21,7 +21,7 @@ void intel_dp_link_training_set_mode(struct intel_dp *intel_dp, int link_rate, bool is_vrr); void intel_dp_link_training_set_bw(struct intel_dp *intel_dp, int link_bw, int rate_select, int lane_count, - bool enhanced_framing); + bool enhanced_framing, bool post_lt_adj_req); bool intel_dp_get_adjust_train(struct intel_dp *intel_dp, const struct intel_crtc_state *crtc_state, diff --git a/drivers/gpu/drm/i915/display/intel_dp_mst.c b/drivers/gpu/drm/i915/display/intel_dp_mst.c index 887b6de14e46..e8de17834dcd 100644 --- a/drivers/gpu/drm/i915/display/intel_dp_mst.c +++ b/drivers/gpu/drm/i915/display/intel_dp_mst.c @@ -2144,7 +2144,7 @@ void intel_dp_mst_prepare_probe(struct intel_dp *intel_dp) intel_dp_link_training_set_mode(intel_dp, link_rate, false); intel_dp_link_training_set_bw(intel_dp, link_bw, rate_select, lane_count, - drm_dp_enhanced_frame_cap(intel_dp->dpcd)); + drm_dp_enhanced_frame_cap(intel_dp->dpcd), false); intel_mst_set_probed_link_params(intel_dp, link_rate, lane_count); } -- cgit v1.2.3 From 28c83ed7ceea67b3b411ddb30ff1e3181fc3af94 Mon Sep 17 00:00:00 2001 From: Michal Wajdeczko Date: Fri, 27 Mar 2026 21:24:06 +0100 Subject: drm/xe/uc: Track uc firmware state changes Under CONFIG_DRM_XE_DEBUG_GUC print debug messages with each uc firmware state transition to better visualize the changes. [drm:xe_uc_fw_change_status [xe]] Tile0: GT0: GuC UNINITIALIZED->SELECTED [drm:xe_uc_fw_change_status [xe]] Tile0: GT0: GuC SELECTED->AVAILABLE [drm:xe_uc_fw_change_status [xe]] Tile0: GT0: GuC AVAILABLE->LOADABLE [drm:xe_uc_fw_change_status [xe]] Tile0: GT0: GuC LOADABLE->TRANSFERRED [drm:xe_uc_fw_change_status [xe]] Tile0: GT0: GuC TRANSFERRED->RUNNING Signed-off-by: Michal Wajdeczko Reviewed-by: Matthew Brost Link: https://patch.msgid.link/20260327202407.563-1-michal.wajdeczko@intel.com --- drivers/gpu/drm/xe/xe_uc_fw.c | 11 +++++++++++ drivers/gpu/drm/xe/xe_uc_fw.h | 4 ++++ 2 files changed, 15 insertions(+) diff --git a/drivers/gpu/drm/xe/xe_uc_fw.c b/drivers/gpu/drm/xe/xe_uc_fw.c index 9cebb2490245..df2aa196f6f9 100644 --- a/drivers/gpu/drm/xe/xe_uc_fw.c +++ b/drivers/gpu/drm/xe/xe_uc_fw.c @@ -214,6 +214,17 @@ static struct xe_device *uc_fw_to_xe(struct xe_uc_fw *uc_fw) return gt_to_xe(uc_fw_to_gt(uc_fw)); } +#if IS_ENABLED(CONFIG_DRM_XE_DEBUG_GUC) +void xe_uc_fw_change_status(struct xe_uc_fw *uc_fw, enum xe_uc_fw_status status) +{ + xe_gt_dbg(uc_fw_to_gt(uc_fw), "%s %s->%s\n", + xe_uc_fw_type_repr(uc_fw->type), + xe_uc_fw_status_repr(uc_fw->status), + xe_uc_fw_status_repr(status)); + uc_fw->__status = status; +} +#endif + static void uc_fw_auto_select(struct xe_device *xe, struct xe_uc_fw *uc_fw) { diff --git a/drivers/gpu/drm/xe/xe_uc_fw.h b/drivers/gpu/drm/xe/xe_uc_fw.h index 6195e353f269..bb281b72a677 100644 --- a/drivers/gpu/drm/xe/xe_uc_fw.h +++ b/drivers/gpu/drm/xe/xe_uc_fw.h @@ -25,11 +25,15 @@ static inline u32 xe_uc_fw_rsa_offset(struct xe_uc_fw *uc_fw) return sizeof(struct uc_css_header) + uc_fw->ucode_size + uc_fw->css_offset; } +#if IS_ENABLED(CONFIG_DRM_XE_DEBUG_GUC) +void xe_uc_fw_change_status(struct xe_uc_fw *uc_fw, enum xe_uc_fw_status status); +#else static inline void xe_uc_fw_change_status(struct xe_uc_fw *uc_fw, enum xe_uc_fw_status status) { uc_fw->__status = status; } +#endif static inline const char *xe_uc_fw_status_repr(enum xe_uc_fw_status status) -- cgit v1.2.3 From d0672008cde3a8616c517d53d657300dce3c36a7 Mon Sep 17 00:00:00 2001 From: Nareshkumar Gollakoti Date: Thu, 26 Mar 2026 12:04:09 +0530 Subject: drm/xe: Set GT rp min frequency as 1.2GHz default for BMG/CRI While previously applied only to both tiles GT0(Graphics) and Media(GT1) the BMG G21(Battle image) platform via workaround Wa_14022085890, this 1.2 GHz minimum is now the default for GT0(Graphics) tile of BMG and CRI platforms. Setting this frequency floor(1.2GHz) default is critical in multi GPU environment for supporting effective Peer-to-Peer(P2P) transactions. v2: - Fix Indentation(Thomas) - Add comment about power impact(Stuart) v3:(Thomas/Ankur/Matt Roper) - Add setting frequency to only GT0(Graphics) Tile of BMG/CRI v4:(Stuart) - Move WA check to pc_needs_min_freq_change function Signed-off-by: Nareshkumar Gollakoti Reviewed-by: Vinay Belgaumkar Link: https://patch.msgid.link/20260326063407.985568-4-naresh.kumar.g@intel.com Signed-off-by: Matt Roper --- drivers/gpu/drm/xe/xe_guc_pc.c | 32 ++++++++++++++++++++++++++++++-- 1 file changed, 30 insertions(+), 2 deletions(-) diff --git a/drivers/gpu/drm/xe/xe_guc_pc.c b/drivers/gpu/drm/xe/xe_guc_pc.c index bb8c4e793492..7ecd91ad6192 100644 --- a/drivers/gpu/drm/xe/xe_guc_pc.c +++ b/drivers/gpu/drm/xe/xe_guc_pc.c @@ -890,9 +890,26 @@ void xe_guc_pc_init_early(struct xe_guc_pc *pc) pc_init_fused_rp_values(pc); } +static bool pc_needs_min_freq_change(struct xe_guc_pc *pc) +{ + struct xe_device *xe = pc_to_xe(pc); + struct xe_gt *gt = pc_to_gt(pc); + + if (XE_DEVICE_WA(xe, 14022085890)) + return true; + + if (xe_gt_is_media_type(gt)) + return false; + + if (xe->info.platform == XE_BATTLEMAGE || + xe->info.platform == XE_CRESCENTISLAND) + return true; + + return false; +} + static int pc_adjust_freq_bounds(struct xe_guc_pc *pc) { - struct xe_tile *tile = gt_to_tile(pc_to_gt(pc)); int ret; lockdep_assert_held(&pc->freq_lock); @@ -919,7 +936,18 @@ static int pc_adjust_freq_bounds(struct xe_guc_pc *pc) if (pc_get_min_freq(pc) > pc->rp0_freq) ret = pc_set_min_freq(pc, pc->rp0_freq); - if (XE_DEVICE_WA(tile_to_xe(tile), 14022085890)) + /* + * Setting GT RP min frequency to 1.2GHz by default for + * GT0(Graphics) Tile of BMG and CRI. + * + * While BMG G21 WA will apply min frequency for + * both GT0(Graphics) and GT1(Media) Tile. + * + * This is an active frequency, so if the device is idle + * we aren't expecting high power output across board + * + */ + if (pc_needs_min_freq_change(pc)) ret = pc_set_min_freq(pc, max(BMG_MIN_FREQ, pc_get_min_freq(pc))); out: -- cgit v1.2.3 From 9e7585fb70b24b96de7c444e56c1baf28c0f71a2 Mon Sep 17 00:00:00 2001 From: Mallesh Koujalagi Date: Fri, 27 Mar 2026 15:54:15 +0530 Subject: drm/xe: Apply WA_14026999295 to engine Apply WA_14026999295 to following IPs: Xe3p_XPC v2: - Move WA to "Xe3p_XPC" section at bottom of table. (Matt) Reviewed-by: Matt Roper Signed-off-by: Mallesh Koujalagi Link: https://patch.msgid.link/20260327102414.780515-2-mallesh.koujalagi@intel.com Signed-off-by: Matt Roper --- drivers/gpu/drm/xe/regs/xe_gt_regs.h | 1 + drivers/gpu/drm/xe/xe_wa.c | 8 ++++++++ 2 files changed, 9 insertions(+) diff --git a/drivers/gpu/drm/xe/regs/xe_gt_regs.h b/drivers/gpu/drm/xe/regs/xe_gt_regs.h index 4ebaa0888a43..aa267c2f6162 100644 --- a/drivers/gpu/drm/xe/regs/xe_gt_regs.h +++ b/drivers/gpu/drm/xe/regs/xe_gt_regs.h @@ -528,6 +528,7 @@ #define ROW_CHICKEN3 XE_REG_MCR(0xe49c, XE_REG_OPTION_MASKED) #define XE2_EUPEND_CHK_FLUSH_DIS REG_BIT(14) +#define DIS_EU_GRF_POISON_TO_LSC REG_BIT(13) #define DIS_FIX_EOT1_FLUSH REG_BIT(9) #define TDL_TSL_CHICKEN XE_REG_MCR(0xe4c4, XE_REG_OPTION_MASKED) diff --git a/drivers/gpu/drm/xe/xe_wa.c b/drivers/gpu/drm/xe/xe_wa.c index 546296f0220b..c3fef8fd73f7 100644 --- a/drivers/gpu/drm/xe/xe_wa.c +++ b/drivers/gpu/drm/xe/xe_wa.c @@ -601,6 +601,14 @@ static const struct xe_rtp_entry_sr engine_was[] = { FUNC(xe_rtp_match_first_render_or_compute)), XE_RTP_ACTIONS(SET(ROW_CHICKEN5, CPSS_AWARE_DIS)) }, + + /* Xe3p_XPC */ + + { XE_RTP_NAME("14026999295"), + XE_RTP_RULES(GRAPHICS_VERSION(3511), + FUNC(xe_rtp_match_first_render_or_compute)), + XE_RTP_ACTIONS(SET(ROW_CHICKEN3, DIS_EU_GRF_POISON_TO_LSC)) + }, }; static const struct xe_rtp_entry_sr lrc_was[] = { -- cgit v1.2.3 From 81ca36e0beaafe5f62fc1eadd99f8dcdf51161c0 Mon Sep 17 00:00:00 2001 From: Zbigniew Kempczyński Date: Tue, 31 Mar 2026 15:43:31 +0200 Subject: drm/xe/pat: Print PAT_ATS during register dump MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit For Xe2 and beyond we miss printing PAT_ATS register. Signed-off-by: Zbigniew Kempczyński Cc: Matthew Auld Reviewed-by: Matthew Auld Link: https://patch.msgid.link/20260331134330.2535519-2-zbigniew.kempczynski@intel.com Signed-off-by: Matt Roper --- drivers/gpu/drm/xe/xe_pat.c | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/drivers/gpu/drm/xe/xe_pat.c b/drivers/gpu/drm/xe/xe_pat.c index 356f53bdb83c..75aaae7b003d 100644 --- a/drivers/gpu/drm/xe/xe_pat.c +++ b/drivers/gpu/drm/xe/xe_pat.c @@ -531,6 +531,14 @@ static int xe2_dump(struct xe_gt *gt, struct drm_printer *p) drm_printf(p, "Page Table Access:\n"); xe->pat.ops->entry_dump(p, "PTA_MODE", pat, false); + if (xe_gt_is_media_type(gt)) + pat = xe_mmio_read32(>->mmio, XE_REG(_PAT_ATS)); + else + pat = xe_gt_mcr_unicast_read_any(gt, XE_REG_MCR(_PAT_ATS)); + + drm_printf(p, "PCIe ATS/PASID:\n"); + xe->pat.ops->entry_dump(p, "PAT_ATS ", pat, false); + return 0; } -- cgit v1.2.3 From 504e2b4ab97a51d56d966cd36d0997ad30b65b2d Mon Sep 17 00:00:00 2001 From: Mikhail Gavrilov Date: Tue, 31 Mar 2026 11:16:57 +0500 Subject: dma-buf/udmabuf: skip redundant cpu sync to fix cacheline EEXIST warning When CONFIG_DMA_API_DEBUG_SG is enabled, importing a udmabuf into a DRM driver (e.g. amdgpu for video playback in GNOME Videos / Showtime) triggers a spurious warning: DMA-API: amdgpu 0000:03:00.0: cacheline tracking EEXIST, \ overlapping mappings aren't supported WARNING: kernel/dma/debug.c:619 at add_dma_entry+0x473/0x5f0 The call chain is: amdgpu_cs_ioctl -> amdgpu_ttm_backend_bind -> dma_buf_map_attachment -> [udmabuf] map_udmabuf -> get_sg_table -> dma_map_sgtable(dev, sg, direction, 0) // attrs=0 -> debug_dma_map_sg -> add_dma_entry -> EEXIST This happens because udmabuf builds a per-page scatter-gather list via sg_set_folio(). When begin_cpu_udmabuf() has already created an sg table mapped for the misc device, and an importer such as amdgpu maps the same pages for its own device via map_udmabuf(), the DMA debug infrastructure sees two active mappings whose physical addresses share cacheline boundaries and warns about the overlap. The DMA_ATTR_SKIP_CPU_SYNC flag suppresses this check in add_dma_entry() because it signals that no CPU cache maintenance is performed at map/unmap time, making the cacheline overlap harmless. All other major dma-buf exporters already pass this flag: - drm_gem_map_dma_buf() passes DMA_ATTR_SKIP_CPU_SYNC - amdgpu_dma_buf_map() passes DMA_ATTR_SKIP_CPU_SYNC The CPU sync at map/unmap time is also redundant for udmabuf: begin_cpu_udmabuf() and end_cpu_udmabuf() already perform explicit cache synchronization via dma_sync_sgtable_for_cpu/device() when CPU access is requested through the dma-buf interface. Pass DMA_ATTR_SKIP_CPU_SYNC to dma_map_sgtable() and dma_unmap_sgtable() in udmabuf to suppress the spurious warning and skip the redundant sync. Fixes: 284562e1f348 ("udmabuf: implement begin_cpu_access/end_cpu_access hooks") Cc: stable@vger.kernel.org Signed-off-by: Mikhail Gavrilov Acked-by: Vivek Kasireddy Signed-off-by: Vivek Kasireddy Link: https://patch.msgid.link/20260331061657.79983-1-mikhail.v.gavrilov@gmail.com --- drivers/dma-buf/udmabuf.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/dma-buf/udmabuf.c b/drivers/dma-buf/udmabuf.c index 94b26ea706a3..bced421c0d65 100644 --- a/drivers/dma-buf/udmabuf.c +++ b/drivers/dma-buf/udmabuf.c @@ -145,7 +145,7 @@ static struct sg_table *get_sg_table(struct device *dev, struct dma_buf *buf, if (ret < 0) goto err_alloc; - ret = dma_map_sgtable(dev, sg, direction, 0); + ret = dma_map_sgtable(dev, sg, direction, DMA_ATTR_SKIP_CPU_SYNC); if (ret < 0) goto err_map; return sg; @@ -160,7 +160,7 @@ err_alloc: static void put_sg_table(struct device *dev, struct sg_table *sg, enum dma_data_direction direction) { - dma_unmap_sgtable(dev, sg, direction, 0); + dma_unmap_sgtable(dev, sg, direction, DMA_ATTR_SKIP_CPU_SYNC); sg_free_table(sg); kfree(sg); } -- cgit v1.2.3 From 8c0b8e3949b155b97660914ce1b29b82523a9363 Mon Sep 17 00:00:00 2001 From: Marco Crivellari Date: Tue, 4 Nov 2025 17:57:31 +0100 Subject: drm/tilcdc: 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/20251104165731.315074-1-marco.crivellari@suse.com --- drivers/gpu/drm/tilcdc/tilcdc_crtc.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/gpu/drm/tilcdc/tilcdc_crtc.c b/drivers/gpu/drm/tilcdc/tilcdc_crtc.c index 4d3b7059cd5b..e5fd1e74de91 100644 --- a/drivers/gpu/drm/tilcdc/tilcdc_crtc.c +++ b/drivers/gpu/drm/tilcdc/tilcdc_crtc.c @@ -926,7 +926,7 @@ irqreturn_t tilcdc_crtc_irq(struct drm_crtc *crtc) drm_err(dev, "%s(0x%08x): Sync lost flood detected, recovering", __func__, stat); - queue_work(system_wq, + queue_work(system_percpu_wq, &tilcdc_crtc->recover_work); tilcdc_write(dev, LCDC_INT_ENABLE_CLR_REG, LCDC_SYNC_LOST); -- cgit v1.2.3 From e4de0fadeb6f8eec909368cb07b2d08320582897 Mon Sep 17 00:00:00 2001 From: Jani Nikula Date: Tue, 31 Mar 2026 14:40:54 +0300 Subject: drm/{i915, xe}: convert VLV sideband display wrappers into real functions MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Convert the VLV sideband static inline wrappers into real functions. This will help the follow-up work of moving the VLV sideband to the display parent interface. The downside is that we'll have to build vlv_sideband.c as part of xe build, to avoid a plethora of stubs. Reviewed-by: Ville Syrjälä Link: https://patch.msgid.link/57740dc3a820cb5fc1cfcd28e4be58b2cb48020d.1774957233.git.jani.nikula@intel.com Signed-off-by: Jani Nikula --- drivers/gpu/drm/i915/display/vlv_sideband.c | 125 +++++++++++++++++++++ drivers/gpu/drm/i915/display/vlv_sideband.h | 165 +++++----------------------- drivers/gpu/drm/xe/Makefile | 3 +- 3 files changed, 156 insertions(+), 137 deletions(-) diff --git a/drivers/gpu/drm/i915/display/vlv_sideband.c b/drivers/gpu/drm/i915/display/vlv_sideband.c index e18045f2b89d..2472e0412728 100644 --- a/drivers/gpu/drm/i915/display/vlv_sideband.c +++ b/drivers/gpu/drm/i915/display/vlv_sideband.c @@ -8,6 +8,71 @@ #include "intel_dpio_phy.h" #include "vlv_sideband.h" +void vlv_bunit_get(struct drm_device *drm) +{ + vlv_iosf_sb_get(drm, BIT(VLV_IOSF_SB_BUNIT)); +} + +u32 vlv_bunit_read(struct drm_device *drm, u32 reg) +{ + return vlv_iosf_sb_read(drm, VLV_IOSF_SB_BUNIT, reg); +} + +void vlv_bunit_write(struct drm_device *drm, u32 reg, u32 val) +{ + vlv_iosf_sb_write(drm, VLV_IOSF_SB_BUNIT, reg, val); +} + +void vlv_bunit_put(struct drm_device *drm) +{ + vlv_iosf_sb_put(drm, BIT(VLV_IOSF_SB_BUNIT)); +} + +void vlv_cck_get(struct drm_device *drm) +{ + vlv_iosf_sb_get(drm, BIT(VLV_IOSF_SB_CCK)); +} + +u32 vlv_cck_read(struct drm_device *drm, u32 reg) +{ + return vlv_iosf_sb_read(drm, VLV_IOSF_SB_CCK, reg); +} + +void vlv_cck_write(struct drm_device *drm, u32 reg, u32 val) +{ + vlv_iosf_sb_write(drm, VLV_IOSF_SB_CCK, reg, val); +} + +void vlv_cck_put(struct drm_device *drm) +{ + vlv_iosf_sb_put(drm, BIT(VLV_IOSF_SB_CCK)); +} + +void vlv_ccu_get(struct drm_device *drm) +{ + vlv_iosf_sb_get(drm, BIT(VLV_IOSF_SB_CCU)); +} + +u32 vlv_ccu_read(struct drm_device *drm, u32 reg) +{ + return vlv_iosf_sb_read(drm, VLV_IOSF_SB_CCU, reg); +} + +void vlv_ccu_write(struct drm_device *drm, u32 reg, u32 val) +{ + vlv_iosf_sb_write(drm, VLV_IOSF_SB_CCU, reg, val); +} + +void vlv_ccu_put(struct drm_device *drm) +{ + vlv_iosf_sb_put(drm, BIT(VLV_IOSF_SB_CCU)); +} + +void vlv_dpio_get(struct drm_device *drm) +{ + vlv_iosf_sb_get(drm, BIT(VLV_IOSF_SB_DPIO) | BIT(VLV_IOSF_SB_DPIO_2)); +} + static enum vlv_iosf_sb_unit vlv_dpio_phy_to_unit(struct intel_display *display, enum dpio_phy phy) { @@ -48,3 +113,63 @@ void vlv_dpio_write(struct drm_device *drm, vlv_iosf_sb_write(drm, unit, reg, val); } + +void vlv_dpio_put(struct drm_device *drm) +{ + vlv_iosf_sb_put(drm, BIT(VLV_IOSF_SB_DPIO) | BIT(VLV_IOSF_SB_DPIO_2)); +} + +void vlv_flisdsi_get(struct drm_device *drm) +{ + vlv_iosf_sb_get(drm, BIT(VLV_IOSF_SB_FLISDSI)); +} + +u32 vlv_flisdsi_read(struct drm_device *drm, u32 reg) +{ + return vlv_iosf_sb_read(drm, VLV_IOSF_SB_FLISDSI, reg); +} + +void vlv_flisdsi_write(struct drm_device *drm, u32 reg, u32 val) +{ + vlv_iosf_sb_write(drm, VLV_IOSF_SB_FLISDSI, reg, val); +} + +void vlv_flisdsi_put(struct drm_device *drm) +{ + vlv_iosf_sb_put(drm, BIT(VLV_IOSF_SB_FLISDSI)); +} + +void vlv_nc_get(struct drm_device *drm) +{ + vlv_iosf_sb_get(drm, BIT(VLV_IOSF_SB_NC)); +} + +u32 vlv_nc_read(struct drm_device *drm, u8 addr) +{ + return vlv_iosf_sb_read(drm, VLV_IOSF_SB_NC, addr); +} + +void vlv_nc_put(struct drm_device *drm) +{ + vlv_iosf_sb_put(drm, BIT(VLV_IOSF_SB_NC)); +} + +void vlv_punit_get(struct drm_device *drm) +{ + vlv_iosf_sb_get(drm, BIT(VLV_IOSF_SB_PUNIT)); +} + +u32 vlv_punit_read(struct drm_device *drm, u32 addr) +{ + return vlv_iosf_sb_read(drm, VLV_IOSF_SB_PUNIT, addr); +} + +int vlv_punit_write(struct drm_device *drm, u32 addr, u32 val) +{ + return vlv_iosf_sb_write(drm, VLV_IOSF_SB_PUNIT, addr, val); +} + +void vlv_punit_put(struct drm_device *drm) +{ + vlv_iosf_sb_put(drm, BIT(VLV_IOSF_SB_PUNIT)); +} diff --git a/drivers/gpu/drm/i915/display/vlv_sideband.h b/drivers/gpu/drm/i915/display/vlv_sideband.h index 2c240d81fead..065273726379 100644 --- a/drivers/gpu/drm/i915/display/vlv_sideband.h +++ b/drivers/gpu/drm/i915/display/vlv_sideband.h @@ -4,7 +4,6 @@ #ifndef _VLV_SIDEBAND_H_ #define _VLV_SIDEBAND_H_ -#include #include #include "vlv_iosf_sb.h" @@ -13,144 +12,38 @@ enum dpio_phy; struct drm_device; -static inline void vlv_bunit_get(struct drm_device *drm) -{ - vlv_iosf_sb_get(drm, BIT(VLV_IOSF_SB_BUNIT)); -} +void vlv_bunit_get(struct drm_device *drm); +u32 vlv_bunit_read(struct drm_device *drm, u32 reg); +void vlv_bunit_write(struct drm_device *drm, u32 reg, u32 val); +void vlv_bunit_put(struct drm_device *drm); -static inline u32 vlv_bunit_read(struct drm_device *drm, u32 reg) -{ - return vlv_iosf_sb_read(drm, VLV_IOSF_SB_BUNIT, reg); -} +void vlv_cck_get(struct drm_device *drm); +u32 vlv_cck_read(struct drm_device *drm, u32 reg); +void vlv_cck_write(struct drm_device *drm, u32 reg, u32 val); +void vlv_cck_put(struct drm_device *drm); -static inline void vlv_bunit_write(struct drm_device *drm, u32 reg, u32 val) -{ - vlv_iosf_sb_write(drm, VLV_IOSF_SB_BUNIT, reg, val); -} +void vlv_ccu_get(struct drm_device *drm); +u32 vlv_ccu_read(struct drm_device *drm, u32 reg); +void vlv_ccu_write(struct drm_device *drm, u32 reg, u32 val); +void vlv_ccu_put(struct drm_device *drm); -static inline void vlv_bunit_put(struct drm_device *drm) -{ - vlv_iosf_sb_put(drm, BIT(VLV_IOSF_SB_BUNIT)); -} - -static inline void vlv_cck_get(struct drm_device *drm) -{ - vlv_iosf_sb_get(drm, BIT(VLV_IOSF_SB_CCK)); -} - -static inline u32 vlv_cck_read(struct drm_device *drm, u32 reg) -{ - return vlv_iosf_sb_read(drm, VLV_IOSF_SB_CCK, reg); -} - -static inline void vlv_cck_write(struct drm_device *drm, u32 reg, u32 val) -{ - vlv_iosf_sb_write(drm, VLV_IOSF_SB_CCK, reg, val); -} - -static inline void vlv_cck_put(struct drm_device *drm) -{ - vlv_iosf_sb_put(drm, BIT(VLV_IOSF_SB_CCK)); -} - -static inline void vlv_ccu_get(struct drm_device *drm) -{ - vlv_iosf_sb_get(drm, BIT(VLV_IOSF_SB_CCU)); -} - -static inline u32 vlv_ccu_read(struct drm_device *drm, u32 reg) -{ - return vlv_iosf_sb_read(drm, VLV_IOSF_SB_CCU, reg); -} - -static inline void vlv_ccu_write(struct drm_device *drm, u32 reg, u32 val) -{ - vlv_iosf_sb_write(drm, VLV_IOSF_SB_CCU, reg, val); -} - -static inline void vlv_ccu_put(struct drm_device *drm) -{ - vlv_iosf_sb_put(drm, BIT(VLV_IOSF_SB_CCU)); -} - -static inline void vlv_dpio_get(struct drm_device *drm) -{ - vlv_iosf_sb_get(drm, BIT(VLV_IOSF_SB_DPIO) | BIT(VLV_IOSF_SB_DPIO_2)); -} - -#ifdef I915 +void vlv_dpio_get(struct drm_device *drm); u32 vlv_dpio_read(struct drm_device *drm, enum dpio_phy phy, int reg); -void vlv_dpio_write(struct drm_device *drm, - enum dpio_phy phy, int reg, u32 val); -#else -static inline u32 vlv_dpio_read(struct drm_device *drm, int phy, int reg) -{ - return 0; -} -static inline void vlv_dpio_write(struct drm_device *drm, - int phy, int reg, u32 val) -{ -} -#endif - -static inline void vlv_dpio_put(struct drm_device *drm) -{ - vlv_iosf_sb_put(drm, BIT(VLV_IOSF_SB_DPIO) | BIT(VLV_IOSF_SB_DPIO_2)); -} - -static inline void vlv_flisdsi_get(struct drm_device *drm) -{ - vlv_iosf_sb_get(drm, BIT(VLV_IOSF_SB_FLISDSI)); -} - -static inline u32 vlv_flisdsi_read(struct drm_device *drm, u32 reg) -{ - return vlv_iosf_sb_read(drm, VLV_IOSF_SB_FLISDSI, reg); -} - -static inline void vlv_flisdsi_write(struct drm_device *drm, u32 reg, u32 val) -{ - vlv_iosf_sb_write(drm, VLV_IOSF_SB_FLISDSI, reg, val); -} - -static inline void vlv_flisdsi_put(struct drm_device *drm) -{ - vlv_iosf_sb_put(drm, BIT(VLV_IOSF_SB_FLISDSI)); -} - -static inline void vlv_nc_get(struct drm_device *drm) -{ - vlv_iosf_sb_get(drm, BIT(VLV_IOSF_SB_NC)); -} - -static inline u32 vlv_nc_read(struct drm_device *drm, u8 addr) -{ - return vlv_iosf_sb_read(drm, VLV_IOSF_SB_NC, addr); -} - -static inline void vlv_nc_put(struct drm_device *drm) -{ - vlv_iosf_sb_put(drm, BIT(VLV_IOSF_SB_NC)); -} - -static inline void vlv_punit_get(struct drm_device *drm) -{ - vlv_iosf_sb_get(drm, BIT(VLV_IOSF_SB_PUNIT)); -} - -static inline u32 vlv_punit_read(struct drm_device *drm, u32 addr) -{ - return vlv_iosf_sb_read(drm, VLV_IOSF_SB_PUNIT, addr); -} - -static inline int vlv_punit_write(struct drm_device *drm, u32 addr, u32 val) -{ - return vlv_iosf_sb_write(drm, VLV_IOSF_SB_PUNIT, addr, val); -} - -static inline void vlv_punit_put(struct drm_device *drm) -{ - vlv_iosf_sb_put(drm, BIT(VLV_IOSF_SB_PUNIT)); -} +void vlv_dpio_write(struct drm_device *drm, enum dpio_phy phy, int reg, u32 val); +void vlv_dpio_put(struct drm_device *drm); + +void vlv_flisdsi_get(struct drm_device *drm); +u32 vlv_flisdsi_read(struct drm_device *drm, u32 reg); +void vlv_flisdsi_write(struct drm_device *drm, u32 reg, u32 val); +void vlv_flisdsi_put(struct drm_device *drm); + +void vlv_nc_get(struct drm_device *drm); +u32 vlv_nc_read(struct drm_device *drm, u8 addr); +void vlv_nc_put(struct drm_device *drm); + +void vlv_punit_get(struct drm_device *drm); +u32 vlv_punit_read(struct drm_device *drm, u32 addr); +int vlv_punit_write(struct drm_device *drm, u32 addr, u32 val); +void vlv_punit_put(struct drm_device *drm); #endif /* _VLV_SIDEBAND_H_ */ diff --git a/drivers/gpu/drm/xe/Makefile b/drivers/gpu/drm/xe/Makefile index 49de1c22a469..3bbd45ea327a 100644 --- a/drivers/gpu/drm/xe/Makefile +++ b/drivers/gpu/drm/xe/Makefile @@ -330,7 +330,8 @@ xe-$(CONFIG_DRM_XE_DISPLAY) += \ i915-display/skl_prefill.o \ i915-display/skl_scaler.o \ i915-display/skl_universal_plane.o \ - i915-display/skl_watermark.o + i915-display/skl_watermark.o \ + i915-display/vlv_sideband.o ifeq ($(CONFIG_ACPI),y) xe-$(CONFIG_DRM_XE_DISPLAY) += \ -- cgit v1.2.3 From 1edb41ff02ec4fcb91b6d5e8944cb255ba1ed0e8 Mon Sep 17 00:00:00 2001 From: Jani Nikula Date: Tue, 31 Mar 2026 14:40:55 +0300 Subject: drm/i915: pass struct intel_display * to VLV sideband wrappers MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit In display code, the display pointer will be all around more convenient. Reviewed-by: Ville Syrjälä Link: https://patch.msgid.link/a355fe0642f7e6566a22e85bda455092e49e3b68.1774957233.git.jani.nikula@intel.com Signed-off-by: Jani Nikula --- drivers/gpu/drm/i915/display/i9xx_wm.c | 32 ++-- drivers/gpu/drm/i915/display/intel_cdclk.c | 32 ++-- drivers/gpu/drm/i915/display/intel_display_power.c | 6 +- .../drm/i915/display/intel_display_power_well.c | 64 ++++---- drivers/gpu/drm/i915/display/intel_dpio_phy.c | 174 ++++++++++----------- drivers/gpu/drm/i915/display/intel_dpll.c | 116 +++++++------- drivers/gpu/drm/i915/display/vlv_clock.c | 13 +- drivers/gpu/drm/i915/display/vlv_dsi.c | 20 +-- drivers/gpu/drm/i915/display/vlv_dsi_pll.c | 38 ++--- drivers/gpu/drm/i915/display/vlv_sideband.c | 110 +++++++------ drivers/gpu/drm/i915/display/vlv_sideband.h | 70 ++++----- 11 files changed, 337 insertions(+), 338 deletions(-) diff --git a/drivers/gpu/drm/i915/display/i9xx_wm.c b/drivers/gpu/drm/i915/display/i9xx_wm.c index 9e170e79dcf6..c39d56e2ea26 100644 --- a/drivers/gpu/drm/i915/display/i9xx_wm.c +++ b/drivers/gpu/drm/i915/display/i9xx_wm.c @@ -118,41 +118,41 @@ static void chv_set_memory_dvfs(struct intel_display *display, bool enable) u32 val; int ret; - vlv_punit_get(display->drm); + vlv_punit_get(display); - val = vlv_punit_read(display->drm, PUNIT_REG_DDR_SETUP2); + val = vlv_punit_read(display, PUNIT_REG_DDR_SETUP2); if (enable) val &= ~FORCE_DDR_HIGH_FREQ; else val |= FORCE_DDR_HIGH_FREQ; val &= ~FORCE_DDR_LOW_FREQ; val |= FORCE_DDR_FREQ_REQ_ACK; - vlv_punit_write(display->drm, PUNIT_REG_DDR_SETUP2, val); + vlv_punit_write(display, PUNIT_REG_DDR_SETUP2, val); - ret = poll_timeout_us(val = vlv_punit_read(display->drm, PUNIT_REG_DDR_SETUP2), + ret = poll_timeout_us(val = vlv_punit_read(display, PUNIT_REG_DDR_SETUP2), (val & FORCE_DDR_FREQ_REQ_ACK) == 0, 500, 3000, false); if (ret) drm_err(display->drm, "timed out waiting for Punit DDR DVFS request\n"); - vlv_punit_put(display->drm); + vlv_punit_put(display); } static void chv_set_memory_pm5(struct intel_display *display, bool enable) { u32 val; - vlv_punit_get(display->drm); + vlv_punit_get(display); - val = vlv_punit_read(display->drm, PUNIT_REG_DSPSSPM); + val = vlv_punit_read(display, PUNIT_REG_DSPSSPM); if (enable) val |= DSP_MAXFIFO_PM5_ENABLE; else val &= ~DSP_MAXFIFO_PM5_ENABLE; - vlv_punit_write(display->drm, PUNIT_REG_DSPSSPM, val); + vlv_punit_write(display, PUNIT_REG_DSPSSPM, val); - vlv_punit_put(display->drm); + vlv_punit_put(display); } #define FW_WM(value, plane) \ @@ -3918,9 +3918,9 @@ static void vlv_wm_get_hw_state(struct intel_display *display) wm->level = VLV_WM_LEVEL_PM2; if (display->platform.cherryview) { - vlv_punit_get(display->drm); + vlv_punit_get(display); - val = vlv_punit_read(display->drm, PUNIT_REG_DSPSSPM); + val = vlv_punit_read(display, PUNIT_REG_DSPSSPM); if (val & DSP_MAXFIFO_PM5_ENABLE) wm->level = VLV_WM_LEVEL_PM5; @@ -3933,11 +3933,11 @@ static void vlv_wm_get_hw_state(struct intel_display *display) * HIGH/LOW bits so that we don't actually change * the current state. */ - val = vlv_punit_read(display->drm, PUNIT_REG_DDR_SETUP2); + val = vlv_punit_read(display, PUNIT_REG_DDR_SETUP2); val |= FORCE_DDR_FREQ_REQ_ACK; - vlv_punit_write(display->drm, PUNIT_REG_DDR_SETUP2, val); + vlv_punit_write(display, PUNIT_REG_DDR_SETUP2, val); - ret = poll_timeout_us(val = vlv_punit_read(display->drm, PUNIT_REG_DDR_SETUP2), + ret = poll_timeout_us(val = vlv_punit_read(display, PUNIT_REG_DDR_SETUP2), (val & FORCE_DDR_FREQ_REQ_ACK) == 0, 500, 3000, false); if (ret) { @@ -3946,12 +3946,12 @@ static void vlv_wm_get_hw_state(struct intel_display *display) "assuming DDR DVFS is disabled\n"); display->wm.num_levels = VLV_WM_LEVEL_PM5 + 1; } else { - val = vlv_punit_read(display->drm, PUNIT_REG_DDR_SETUP2); + val = vlv_punit_read(display, PUNIT_REG_DDR_SETUP2); if ((val & FORCE_DDR_HIGH_FREQ) == 0) wm->level = VLV_WM_LEVEL_DDR_DVFS; } - vlv_punit_put(display->drm); + vlv_punit_put(display); } for_each_intel_crtc(display->drm, crtc) { diff --git a/drivers/gpu/drm/i915/display/intel_cdclk.c b/drivers/gpu/drm/i915/display/intel_cdclk.c index a47736613f6e..8e0424a2c16f 100644 --- a/drivers/gpu/drm/i915/display/intel_cdclk.c +++ b/drivers/gpu/drm/i915/display/intel_cdclk.c @@ -613,9 +613,9 @@ static void vlv_get_cdclk(struct intel_display *display, cdclk_config->vco = vlv_clock_get_hpll_vco(display->drm); cdclk_config->cdclk = vlv_clock_get_cdclk(display->drm); - vlv_punit_get(display->drm); - val = vlv_punit_read(display->drm, PUNIT_REG_DSPSSPM); - vlv_punit_put(display->drm); + vlv_punit_get(display); + val = vlv_punit_read(display, PUNIT_REG_DSPSSPM); + vlv_punit_put(display); if (display->platform.valleyview) cdclk_config->voltage_level = (val & DSPFREQGUAR_MASK) >> @@ -696,12 +696,12 @@ static void vlv_set_cdclk(struct intel_display *display, BIT(VLV_IOSF_SB_BUNIT) | BIT(VLV_IOSF_SB_PUNIT)); - val = vlv_punit_read(display->drm, PUNIT_REG_DSPSSPM); + val = vlv_punit_read(display, PUNIT_REG_DSPSSPM); val &= ~DSPFREQGUAR_MASK; val |= (cmd << DSPFREQGUAR_SHIFT); - vlv_punit_write(display->drm, PUNIT_REG_DSPSSPM, val); + vlv_punit_write(display, PUNIT_REG_DSPSSPM, val); - ret = poll_timeout_us(val = vlv_punit_read(display->drm, PUNIT_REG_DSPSSPM), + ret = poll_timeout_us(val = vlv_punit_read(display, PUNIT_REG_DSPSSPM), (val & DSPFREQSTAT_MASK) == (cmd << DSPFREQSTAT_SHIFT), 500, 50 * 1000, false); if (ret) @@ -714,12 +714,12 @@ static void vlv_set_cdclk(struct intel_display *display, cdclk) - 1; /* adjust cdclk divider */ - val = vlv_cck_read(display->drm, CCK_DISPLAY_CLOCK_CONTROL); + val = vlv_cck_read(display, CCK_DISPLAY_CLOCK_CONTROL); val &= ~CCK_FREQUENCY_VALUES; val |= divider; - vlv_cck_write(display->drm, CCK_DISPLAY_CLOCK_CONTROL, val); + vlv_cck_write(display, CCK_DISPLAY_CLOCK_CONTROL, val); - ret = poll_timeout_us(val = vlv_cck_read(display->drm, CCK_DISPLAY_CLOCK_CONTROL), + ret = poll_timeout_us(val = vlv_cck_read(display, CCK_DISPLAY_CLOCK_CONTROL), (val & CCK_FREQUENCY_STATUS) == (divider << CCK_FREQUENCY_STATUS_SHIFT), 500, 50 * 1000, false); if (ret) @@ -727,7 +727,7 @@ static void vlv_set_cdclk(struct intel_display *display, } /* adjust self-refresh exit latency value */ - val = vlv_bunit_read(display->drm, BUNIT_REG_BISOC); + val = vlv_bunit_read(display, BUNIT_REG_BISOC); val &= ~0x7f; /* @@ -738,7 +738,7 @@ static void vlv_set_cdclk(struct intel_display *display, val |= 4500 / 250; /* 4.5 usec */ else val |= 3000 / 250; /* 3.0 usec */ - vlv_bunit_write(display->drm, BUNIT_REG_BISOC, val); + vlv_bunit_write(display, BUNIT_REG_BISOC, val); vlv_iosf_sb_put(display->drm, BIT(VLV_IOSF_SB_CCK) | @@ -780,19 +780,19 @@ static void chv_set_cdclk(struct intel_display *display, */ wakeref = intel_display_power_get(display, POWER_DOMAIN_DISPLAY_CORE); - vlv_punit_get(display->drm); - val = vlv_punit_read(display->drm, PUNIT_REG_DSPSSPM); + vlv_punit_get(display); + val = vlv_punit_read(display, PUNIT_REG_DSPSSPM); val &= ~DSPFREQGUAR_MASK_CHV; val |= (cmd << DSPFREQGUAR_SHIFT_CHV); - vlv_punit_write(display->drm, PUNIT_REG_DSPSSPM, val); + vlv_punit_write(display, PUNIT_REG_DSPSSPM, val); - ret = poll_timeout_us(val = vlv_punit_read(display->drm, PUNIT_REG_DSPSSPM), + ret = poll_timeout_us(val = vlv_punit_read(display, PUNIT_REG_DSPSSPM), (val & DSPFREQSTAT_MASK_CHV) == (cmd << DSPFREQSTAT_SHIFT_CHV), 500, 50 * 1000, false); if (ret) drm_err(display->drm, "timed out waiting for CDCLK change\n"); - vlv_punit_put(display->drm); + vlv_punit_put(display); intel_update_cdclk(display); diff --git a/drivers/gpu/drm/i915/display/intel_display_power.c b/drivers/gpu/drm/i915/display/intel_display_power.c index ec96b141c74c..b1c91de9d798 100644 --- a/drivers/gpu/drm/i915/display/intel_display_power.c +++ b/drivers/gpu/drm/i915/display/intel_display_power.c @@ -1890,9 +1890,9 @@ static bool vlv_punit_is_power_gated(struct intel_display *display, u32 reg0) { bool ret; - vlv_punit_get(display->drm); - ret = (vlv_punit_read(display->drm, reg0) & SSPM0_SSC_MASK) == SSPM0_SSC_PWR_GATE; - vlv_punit_put(display->drm); + vlv_punit_get(display); + ret = (vlv_punit_read(display, reg0) & SSPM0_SSC_MASK) == SSPM0_SSC_PWR_GATE; + vlv_punit_put(display); return ret; } diff --git a/drivers/gpu/drm/i915/display/intel_display_power_well.c b/drivers/gpu/drm/i915/display/intel_display_power_well.c index f855f0f88694..f96a5088d138 100644 --- a/drivers/gpu/drm/i915/display/intel_display_power_well.c +++ b/drivers/gpu/drm/i915/display/intel_display_power_well.c @@ -1189,28 +1189,28 @@ static void vlv_set_power_well(struct intel_display *display, state = enable ? PUNIT_PWRGT_PWR_ON(pw_idx) : PUNIT_PWRGT_PWR_GATE(pw_idx); - vlv_punit_get(display->drm); + vlv_punit_get(display); - val = vlv_punit_read(display->drm, PUNIT_REG_PWRGT_STATUS); + val = vlv_punit_read(display, PUNIT_REG_PWRGT_STATUS); if ((val & mask) == state) goto out; - ctrl = vlv_punit_read(display->drm, PUNIT_REG_PWRGT_CTRL); + ctrl = vlv_punit_read(display, PUNIT_REG_PWRGT_CTRL); ctrl &= ~mask; ctrl |= state; - vlv_punit_write(display->drm, PUNIT_REG_PWRGT_CTRL, ctrl); + vlv_punit_write(display, PUNIT_REG_PWRGT_CTRL, ctrl); - ret = poll_timeout_us(val = vlv_punit_read(display->drm, PUNIT_REG_PWRGT_STATUS), + ret = poll_timeout_us(val = vlv_punit_read(display, PUNIT_REG_PWRGT_STATUS), (val & mask) == state, 500, 100 * 1000, false); if (ret) drm_err(display->drm, "timeout setting power well state %08x (%08x)\n", state, - vlv_punit_read(display->drm, PUNIT_REG_PWRGT_CTRL)); + vlv_punit_read(display, PUNIT_REG_PWRGT_CTRL)); out: - vlv_punit_put(display->drm); + vlv_punit_put(display); } static void vlv_power_well_enable(struct intel_display *display, @@ -1237,9 +1237,9 @@ static bool vlv_power_well_enabled(struct intel_display *display, mask = PUNIT_PWRGT_MASK(pw_idx); ctrl = PUNIT_PWRGT_PWR_ON(pw_idx); - vlv_punit_get(display->drm); + vlv_punit_get(display); - state = vlv_punit_read(display->drm, PUNIT_REG_PWRGT_STATUS) & mask; + state = vlv_punit_read(display, PUNIT_REG_PWRGT_STATUS) & mask; /* * We only ever set the power-on and power-gate states, anything * else is unexpected. @@ -1253,10 +1253,10 @@ static bool vlv_power_well_enabled(struct intel_display *display, * A transient state at this point would mean some unexpected party * is poking at the power controls too. */ - ctrl = vlv_punit_read(display->drm, PUNIT_REG_PWRGT_CTRL) & mask; + ctrl = vlv_punit_read(display, PUNIT_REG_PWRGT_CTRL) & mask; drm_WARN_ON(display->drm, ctrl != state); - vlv_punit_put(display->drm); + vlv_punit_put(display); return enabled; } @@ -1533,30 +1533,30 @@ static void chv_dpio_cmn_power_well_enable(struct intel_display *display, drm_err(display->drm, "Display PHY %d is not power up\n", phy); - vlv_dpio_get(display->drm); + vlv_dpio_get(display); /* Enable dynamic power down */ - tmp = vlv_dpio_read(display->drm, phy, CHV_CMN_DW28); + tmp = vlv_dpio_read(display, phy, CHV_CMN_DW28); tmp |= DPIO_DYNPWRDOWNEN_CH0 | DPIO_CL1POWERDOWNEN | DPIO_SUS_CLK_CONFIG_GATE_CLKREQ; - vlv_dpio_write(display->drm, phy, CHV_CMN_DW28, tmp); + vlv_dpio_write(display, phy, CHV_CMN_DW28, tmp); if (id == VLV_DISP_PW_DPIO_CMN_BC) { - tmp = vlv_dpio_read(display->drm, phy, CHV_CMN_DW6_CH1); + tmp = vlv_dpio_read(display, phy, CHV_CMN_DW6_CH1); tmp |= DPIO_DYNPWRDOWNEN_CH1; - vlv_dpio_write(display->drm, phy, CHV_CMN_DW6_CH1, tmp); + vlv_dpio_write(display, phy, CHV_CMN_DW6_CH1, tmp); } else { /* * Force the non-existing CL2 off. BXT does this * too, so maybe it saves some power even though * CL2 doesn't exist? */ - tmp = vlv_dpio_read(display->drm, phy, CHV_CMN_DW30); + tmp = vlv_dpio_read(display, phy, CHV_CMN_DW30); tmp |= DPIO_CL2_LDOFUSE_PWRENB; - vlv_dpio_write(display->drm, phy, CHV_CMN_DW30, tmp); + vlv_dpio_write(display, phy, CHV_CMN_DW30, tmp); } - vlv_dpio_put(display->drm); + vlv_dpio_put(display); display->power.chv_phy_control |= PHY_COM_LANE_RESET_DEASSERT(phy); intel_de_write(display, DISPLAY_PHY_CONTROL, @@ -1624,9 +1624,9 @@ static void assert_chv_phy_powergate(struct intel_display *display, enum dpio_ph else reg = CHV_CMN_DW6_CH1; - vlv_dpio_get(display->drm); - val = vlv_dpio_read(display->drm, phy, reg); - vlv_dpio_put(display->drm); + vlv_dpio_get(display); + val = vlv_dpio_read(display, phy, reg); + vlv_dpio_put(display); /* * This assumes !override is only used when the port is disabled. @@ -1740,9 +1740,9 @@ static bool chv_pipe_power_well_enabled(struct intel_display *display, bool enabled; u32 state, ctrl; - vlv_punit_get(display->drm); + vlv_punit_get(display); - state = vlv_punit_read(display->drm, PUNIT_REG_DSPSSPM) & DP_SSS_MASK(pipe); + state = vlv_punit_read(display, PUNIT_REG_DSPSSPM) & DP_SSS_MASK(pipe); /* * We only ever set the power-on and power-gate states, anything * else is unexpected. @@ -1755,10 +1755,10 @@ static bool chv_pipe_power_well_enabled(struct intel_display *display, * A transient state at this point would mean some unexpected party * is poking at the power controls too. */ - ctrl = vlv_punit_read(display->drm, PUNIT_REG_DSPSSPM) & DP_SSC_MASK(pipe); + ctrl = vlv_punit_read(display, PUNIT_REG_DSPSSPM) & DP_SSC_MASK(pipe); drm_WARN_ON(display->drm, ctrl << 16 != state); - vlv_punit_put(display->drm); + vlv_punit_put(display); return enabled; } @@ -1774,29 +1774,29 @@ static void chv_set_pipe_power_well(struct intel_display *display, state = enable ? DP_SSS_PWR_ON(pipe) : DP_SSS_PWR_GATE(pipe); - vlv_punit_get(display->drm); + vlv_punit_get(display); - ctrl = vlv_punit_read(display->drm, PUNIT_REG_DSPSSPM); + ctrl = vlv_punit_read(display, PUNIT_REG_DSPSSPM); if ((ctrl & DP_SSS_MASK(pipe)) == state) goto out; ctrl &= ~DP_SSC_MASK(pipe); ctrl |= enable ? DP_SSC_PWR_ON(pipe) : DP_SSC_PWR_GATE(pipe); - vlv_punit_write(display->drm, PUNIT_REG_DSPSSPM, ctrl); + vlv_punit_write(display, PUNIT_REG_DSPSSPM, ctrl); - ret = poll_timeout_us(ctrl = vlv_punit_read(display->drm, PUNIT_REG_DSPSSPM), + ret = poll_timeout_us(ctrl = vlv_punit_read(display, PUNIT_REG_DSPSSPM), (ctrl & DP_SSS_MASK(pipe)) == state, 500, 100 * 1000, false); if (ret) drm_err(display->drm, "timeout setting power well state %08x (%08x)\n", state, - vlv_punit_read(display->drm, PUNIT_REG_DSPSSPM)); + vlv_punit_read(display, PUNIT_REG_DSPSSPM)); #undef COND out: - vlv_punit_put(display->drm); + vlv_punit_put(display); } static void chv_pipe_power_well_sync_hw(struct intel_display *display, diff --git a/drivers/gpu/drm/i915/display/intel_dpio_phy.c b/drivers/gpu/drm/i915/display/intel_dpio_phy.c index 8027bab2951b..0e16132d0923 100644 --- a/drivers/gpu/drm/i915/display/intel_dpio_phy.c +++ b/drivers/gpu/drm/i915/display/intel_dpio_phy.c @@ -724,46 +724,46 @@ void chv_set_phy_signal_level(struct intel_encoder *encoder, u32 val; int i; - vlv_dpio_get(display->drm); + vlv_dpio_get(display); /* Clear calc init */ - val = vlv_dpio_read(display->drm, phy, VLV_PCS01_DW10(ch)); + val = vlv_dpio_read(display, phy, VLV_PCS01_DW10(ch)); val &= ~(DPIO_PCS_SWING_CALC_TX0_TX2 | DPIO_PCS_SWING_CALC_TX1_TX3); val &= ~(DPIO_PCS_TX1DEEMP_MASK | DPIO_PCS_TX2DEEMP_MASK); val |= DPIO_PCS_TX1DEEMP_9P5 | DPIO_PCS_TX2DEEMP_9P5; - vlv_dpio_write(display->drm, phy, VLV_PCS01_DW10(ch), val); + vlv_dpio_write(display, phy, VLV_PCS01_DW10(ch), val); if (crtc_state->lane_count > 2) { - val = vlv_dpio_read(display->drm, phy, VLV_PCS23_DW10(ch)); + val = vlv_dpio_read(display, phy, VLV_PCS23_DW10(ch)); val &= ~(DPIO_PCS_SWING_CALC_TX0_TX2 | DPIO_PCS_SWING_CALC_TX1_TX3); val &= ~(DPIO_PCS_TX1DEEMP_MASK | DPIO_PCS_TX2DEEMP_MASK); val |= DPIO_PCS_TX1DEEMP_9P5 | DPIO_PCS_TX2DEEMP_9P5; - vlv_dpio_write(display->drm, phy, VLV_PCS23_DW10(ch), val); + vlv_dpio_write(display, phy, VLV_PCS23_DW10(ch), val); } - val = vlv_dpio_read(display->drm, phy, VLV_PCS01_DW9(ch)); + val = vlv_dpio_read(display, phy, VLV_PCS01_DW9(ch)); val &= ~(DPIO_PCS_TX1MARGIN_MASK | DPIO_PCS_TX2MARGIN_MASK); val |= DPIO_PCS_TX1MARGIN_000 | DPIO_PCS_TX2MARGIN_000; - vlv_dpio_write(display->drm, phy, VLV_PCS01_DW9(ch), val); + vlv_dpio_write(display, phy, VLV_PCS01_DW9(ch), val); if (crtc_state->lane_count > 2) { - val = vlv_dpio_read(display->drm, phy, VLV_PCS23_DW9(ch)); + val = vlv_dpio_read(display, phy, VLV_PCS23_DW9(ch)); val &= ~(DPIO_PCS_TX1MARGIN_MASK | DPIO_PCS_TX2MARGIN_MASK); val |= DPIO_PCS_TX1MARGIN_000 | DPIO_PCS_TX2MARGIN_000; - vlv_dpio_write(display->drm, phy, VLV_PCS23_DW9(ch), val); + vlv_dpio_write(display, phy, VLV_PCS23_DW9(ch), val); } /* Program swing deemph */ for (i = 0; i < crtc_state->lane_count; i++) { - val = vlv_dpio_read(display->drm, phy, CHV_TX_DW4(ch, i)); + val = vlv_dpio_read(display, phy, CHV_TX_DW4(ch, i)); val &= ~DPIO_SWING_DEEMPH9P5_MASK; val |= DPIO_SWING_DEEMPH9P5(deemph_reg_value); - vlv_dpio_write(display->drm, phy, CHV_TX_DW4(ch, i), val); + vlv_dpio_write(display, phy, CHV_TX_DW4(ch, i), val); } /* Program swing margin */ for (i = 0; i < crtc_state->lane_count; i++) { - val = vlv_dpio_read(display->drm, phy, CHV_TX_DW2(ch, i)); + val = vlv_dpio_read(display, phy, CHV_TX_DW2(ch, i)); val &= ~DPIO_SWING_MARGIN000_MASK; val |= DPIO_SWING_MARGIN000(margin_reg_value); @@ -776,7 +776,7 @@ void chv_set_phy_signal_level(struct intel_encoder *encoder, val &= ~DPIO_UNIQ_TRANS_SCALE_MASK; val |= DPIO_UNIQ_TRANS_SCALE(0x9a); - vlv_dpio_write(display->drm, phy, CHV_TX_DW2(ch, i), val); + vlv_dpio_write(display, phy, CHV_TX_DW2(ch, i), val); } /* @@ -786,26 +786,26 @@ void chv_set_phy_signal_level(struct intel_encoder *encoder, * 27 for ch0 and ch1. */ for (i = 0; i < crtc_state->lane_count; i++) { - val = vlv_dpio_read(display->drm, phy, CHV_TX_DW3(ch, i)); + val = vlv_dpio_read(display, phy, CHV_TX_DW3(ch, i)); if (uniq_trans_scale) val |= DPIO_TX_UNIQ_TRANS_SCALE_EN; else val &= ~DPIO_TX_UNIQ_TRANS_SCALE_EN; - vlv_dpio_write(display->drm, phy, CHV_TX_DW3(ch, i), val); + vlv_dpio_write(display, phy, CHV_TX_DW3(ch, i), val); } /* Start swing calculation */ - val = vlv_dpio_read(display->drm, phy, VLV_PCS01_DW10(ch)); + val = vlv_dpio_read(display, phy, VLV_PCS01_DW10(ch)); val |= DPIO_PCS_SWING_CALC_TX0_TX2 | DPIO_PCS_SWING_CALC_TX1_TX3; - vlv_dpio_write(display->drm, phy, VLV_PCS01_DW10(ch), val); + vlv_dpio_write(display, phy, VLV_PCS01_DW10(ch), val); if (crtc_state->lane_count > 2) { - val = vlv_dpio_read(display->drm, phy, VLV_PCS23_DW10(ch)); + val = vlv_dpio_read(display, phy, VLV_PCS23_DW10(ch)); val |= DPIO_PCS_SWING_CALC_TX0_TX2 | DPIO_PCS_SWING_CALC_TX1_TX3; - vlv_dpio_write(display->drm, phy, VLV_PCS23_DW10(ch), val); + vlv_dpio_write(display, phy, VLV_PCS23_DW10(ch), val); } - vlv_dpio_put(display->drm); + vlv_dpio_put(display); } static void __chv_data_lane_soft_reset(struct intel_encoder *encoder, @@ -818,38 +818,38 @@ static void __chv_data_lane_soft_reset(struct intel_encoder *encoder, enum dpio_phy phy = vlv_dig_port_to_phy(dig_port); u32 val; - val = vlv_dpio_read(display->drm, phy, VLV_PCS01_DW0(ch)); + val = vlv_dpio_read(display, phy, VLV_PCS01_DW0(ch)); if (reset) val &= ~(DPIO_PCS_TX_LANE2_RESET | DPIO_PCS_TX_LANE1_RESET); else val |= DPIO_PCS_TX_LANE2_RESET | DPIO_PCS_TX_LANE1_RESET; - vlv_dpio_write(display->drm, phy, VLV_PCS01_DW0(ch), val); + vlv_dpio_write(display, phy, VLV_PCS01_DW0(ch), val); if (crtc_state->lane_count > 2) { - val = vlv_dpio_read(display->drm, phy, VLV_PCS23_DW0(ch)); + val = vlv_dpio_read(display, phy, VLV_PCS23_DW0(ch)); if (reset) val &= ~(DPIO_PCS_TX_LANE2_RESET | DPIO_PCS_TX_LANE1_RESET); else val |= DPIO_PCS_TX_LANE2_RESET | DPIO_PCS_TX_LANE1_RESET; - vlv_dpio_write(display->drm, phy, VLV_PCS23_DW0(ch), val); + vlv_dpio_write(display, phy, VLV_PCS23_DW0(ch), val); } - val = vlv_dpio_read(display->drm, phy, VLV_PCS01_DW1(ch)); + val = vlv_dpio_read(display, phy, VLV_PCS01_DW1(ch)); val |= CHV_PCS_REQ_SOFTRESET_EN; if (reset) val &= ~DPIO_PCS_CLK_SOFT_RESET; else val |= DPIO_PCS_CLK_SOFT_RESET; - vlv_dpio_write(display->drm, phy, VLV_PCS01_DW1(ch), val); + vlv_dpio_write(display, phy, VLV_PCS01_DW1(ch), val); if (crtc_state->lane_count > 2) { - val = vlv_dpio_read(display->drm, phy, VLV_PCS23_DW1(ch)); + val = vlv_dpio_read(display, phy, VLV_PCS23_DW1(ch)); val |= CHV_PCS_REQ_SOFTRESET_EN; if (reset) val &= ~DPIO_PCS_CLK_SOFT_RESET; else val |= DPIO_PCS_CLK_SOFT_RESET; - vlv_dpio_write(display->drm, phy, VLV_PCS23_DW1(ch), val); + vlv_dpio_write(display, phy, VLV_PCS23_DW1(ch), val); } } @@ -859,9 +859,9 @@ void chv_data_lane_soft_reset(struct intel_encoder *encoder, { struct intel_display *display = to_intel_display(encoder); - vlv_dpio_get(display->drm); + vlv_dpio_get(display); __chv_data_lane_soft_reset(encoder, crtc_state, reset); - vlv_dpio_put(display->drm); + vlv_dpio_put(display); } void chv_phy_pre_pll_enable(struct intel_encoder *encoder, @@ -887,47 +887,47 @@ void chv_phy_pre_pll_enable(struct intel_encoder *encoder, chv_phy_powergate_lanes(encoder, true, lane_mask); - vlv_dpio_get(display->drm); + vlv_dpio_get(display); /* Assert data lane reset */ __chv_data_lane_soft_reset(encoder, crtc_state, true); /* program left/right clock distribution */ if (pipe != PIPE_B) { - val = vlv_dpio_read(display->drm, phy, CHV_CMN_DW5_CH0); + val = vlv_dpio_read(display, phy, CHV_CMN_DW5_CH0); val &= ~(CHV_BUFLEFTENA1_MASK | CHV_BUFRIGHTENA1_MASK); if (ch == DPIO_CH0) val |= CHV_BUFLEFTENA1_FORCE; if (ch == DPIO_CH1) val |= CHV_BUFRIGHTENA1_FORCE; - vlv_dpio_write(display->drm, phy, CHV_CMN_DW5_CH0, val); + vlv_dpio_write(display, phy, CHV_CMN_DW5_CH0, val); } else { - val = vlv_dpio_read(display->drm, phy, CHV_CMN_DW1_CH1); + val = vlv_dpio_read(display, phy, CHV_CMN_DW1_CH1); val &= ~(CHV_BUFLEFTENA2_MASK | CHV_BUFRIGHTENA2_MASK); if (ch == DPIO_CH0) val |= CHV_BUFLEFTENA2_FORCE; if (ch == DPIO_CH1) val |= CHV_BUFRIGHTENA2_FORCE; - vlv_dpio_write(display->drm, phy, CHV_CMN_DW1_CH1, val); + vlv_dpio_write(display, phy, CHV_CMN_DW1_CH1, val); } /* program clock channel usage */ - val = vlv_dpio_read(display->drm, phy, VLV_PCS01_DW8(ch)); + val = vlv_dpio_read(display, phy, VLV_PCS01_DW8(ch)); val |= DPIO_PCS_USEDCLKCHANNEL_OVRRIDE; if (pipe == PIPE_B) val |= DPIO_PCS_USEDCLKCHANNEL; else val &= ~DPIO_PCS_USEDCLKCHANNEL; - vlv_dpio_write(display->drm, phy, VLV_PCS01_DW8(ch), val); + vlv_dpio_write(display, phy, VLV_PCS01_DW8(ch), val); if (crtc_state->lane_count > 2) { - val = vlv_dpio_read(display->drm, phy, VLV_PCS23_DW8(ch)); + val = vlv_dpio_read(display, phy, VLV_PCS23_DW8(ch)); val |= DPIO_PCS_USEDCLKCHANNEL_OVRRIDE; if (pipe == PIPE_B) val |= DPIO_PCS_USEDCLKCHANNEL; else val &= ~DPIO_PCS_USEDCLKCHANNEL; - vlv_dpio_write(display->drm, phy, VLV_PCS23_DW8(ch), val); + vlv_dpio_write(display, phy, VLV_PCS23_DW8(ch), val); } /* @@ -935,14 +935,14 @@ void chv_phy_pre_pll_enable(struct intel_encoder *encoder, * matches the pipe, but here we need to * pick the CL based on the port. */ - val = vlv_dpio_read(display->drm, phy, CHV_CMN_DW19(ch)); + val = vlv_dpio_read(display, phy, CHV_CMN_DW19(ch)); if (pipe == PIPE_B) val |= CHV_CMN_USEDCLKCHANNEL; else val &= ~CHV_CMN_USEDCLKCHANNEL; - vlv_dpio_write(display->drm, phy, CHV_CMN_DW19(ch), val); + vlv_dpio_write(display, phy, CHV_CMN_DW19(ch), val); - vlv_dpio_put(display->drm); + vlv_dpio_put(display); } void chv_phy_pre_encoder_enable(struct intel_encoder *encoder, @@ -956,17 +956,17 @@ void chv_phy_pre_encoder_enable(struct intel_encoder *encoder, int data, i, stagger; u32 val; - vlv_dpio_get(display->drm); + vlv_dpio_get(display); /* allow hardware to manage TX FIFO reset source */ - val = vlv_dpio_read(display->drm, phy, VLV_PCS01_DW11(ch)); + val = vlv_dpio_read(display, phy, VLV_PCS01_DW11(ch)); val &= ~DPIO_LANEDESKEW_STRAP_OVRD; - vlv_dpio_write(display->drm, phy, VLV_PCS01_DW11(ch), val); + vlv_dpio_write(display, phy, VLV_PCS01_DW11(ch), val); if (crtc_state->lane_count > 2) { - val = vlv_dpio_read(display->drm, phy, VLV_PCS23_DW11(ch)); + val = vlv_dpio_read(display, phy, VLV_PCS23_DW11(ch)); val &= ~DPIO_LANEDESKEW_STRAP_OVRD; - vlv_dpio_write(display->drm, phy, VLV_PCS23_DW11(ch), val); + vlv_dpio_write(display, phy, VLV_PCS23_DW11(ch), val); } /* Program Tx lane latency optimal setting*/ @@ -976,7 +976,7 @@ void chv_phy_pre_encoder_enable(struct intel_encoder *encoder, data = 0; else data = (i == 1) ? 0 : DPIO_UPAR; - vlv_dpio_write(display->drm, phy, CHV_TX_DW14(ch, i), data); + vlv_dpio_write(display, phy, CHV_TX_DW14(ch, i), data); } /* Data lane stagger programming */ @@ -991,17 +991,17 @@ void chv_phy_pre_encoder_enable(struct intel_encoder *encoder, else stagger = 0x2; - val = vlv_dpio_read(display->drm, phy, VLV_PCS01_DW11(ch)); + val = vlv_dpio_read(display, phy, VLV_PCS01_DW11(ch)); val |= DPIO_TX2_STAGGER_MASK(0x1f); - vlv_dpio_write(display->drm, phy, VLV_PCS01_DW11(ch), val); + vlv_dpio_write(display, phy, VLV_PCS01_DW11(ch), val); if (crtc_state->lane_count > 2) { - val = vlv_dpio_read(display->drm, phy, VLV_PCS23_DW11(ch)); + val = vlv_dpio_read(display, phy, VLV_PCS23_DW11(ch)); val |= DPIO_TX2_STAGGER_MASK(0x1f); - vlv_dpio_write(display->drm, phy, VLV_PCS23_DW11(ch), val); + vlv_dpio_write(display, phy, VLV_PCS23_DW11(ch), val); } - vlv_dpio_write(display->drm, phy, VLV_PCS01_DW12(ch), + vlv_dpio_write(display, phy, VLV_PCS01_DW12(ch), DPIO_LANESTAGGER_STRAP(stagger) | DPIO_LANESTAGGER_STRAP_OVRD | DPIO_TX1_STAGGER_MASK(0x1f) | @@ -1009,7 +1009,7 @@ void chv_phy_pre_encoder_enable(struct intel_encoder *encoder, DPIO_TX2_STAGGER_MULT(0)); if (crtc_state->lane_count > 2) { - vlv_dpio_write(display->drm, phy, VLV_PCS23_DW12(ch), + vlv_dpio_write(display, phy, VLV_PCS23_DW12(ch), DPIO_LANESTAGGER_STRAP(stagger) | DPIO_LANESTAGGER_STRAP_OVRD | DPIO_TX1_STAGGER_MASK(0x1f) | @@ -1020,7 +1020,7 @@ void chv_phy_pre_encoder_enable(struct intel_encoder *encoder, /* Deassert data lane reset */ __chv_data_lane_soft_reset(encoder, crtc_state, false); - vlv_dpio_put(display->drm); + vlv_dpio_put(display); } void chv_phy_release_cl2_override(struct intel_encoder *encoder) @@ -1042,20 +1042,20 @@ void chv_phy_post_pll_disable(struct intel_encoder *encoder, enum pipe pipe = to_intel_crtc(old_crtc_state->uapi.crtc)->pipe; u32 val; - vlv_dpio_get(display->drm); + vlv_dpio_get(display); /* disable left/right clock distribution */ if (pipe != PIPE_B) { - val = vlv_dpio_read(display->drm, phy, CHV_CMN_DW5_CH0); + val = vlv_dpio_read(display, phy, CHV_CMN_DW5_CH0); val &= ~(CHV_BUFLEFTENA1_MASK | CHV_BUFRIGHTENA1_MASK); - vlv_dpio_write(display->drm, phy, CHV_CMN_DW5_CH0, val); + vlv_dpio_write(display, phy, CHV_CMN_DW5_CH0, val); } else { - val = vlv_dpio_read(display->drm, phy, CHV_CMN_DW1_CH1); + val = vlv_dpio_read(display, phy, CHV_CMN_DW1_CH1); val &= ~(CHV_BUFLEFTENA2_MASK | CHV_BUFRIGHTENA2_MASK); - vlv_dpio_write(display->drm, phy, CHV_CMN_DW1_CH1, val); + vlv_dpio_write(display, phy, CHV_CMN_DW1_CH1, val); } - vlv_dpio_put(display->drm); + vlv_dpio_put(display); /* * Leave the power down bit cleared for at least one @@ -1079,22 +1079,22 @@ void vlv_set_phy_signal_level(struct intel_encoder *encoder, enum dpio_channel ch = vlv_dig_port_to_channel(dig_port); enum dpio_phy phy = vlv_dig_port_to_phy(dig_port); - vlv_dpio_get(display->drm); + vlv_dpio_get(display); - vlv_dpio_write(display->drm, phy, VLV_TX_DW5_GRP(ch), 0x00000000); - vlv_dpio_write(display->drm, phy, VLV_TX_DW4_GRP(ch), demph_reg_value); - vlv_dpio_write(display->drm, phy, VLV_TX_DW2_GRP(ch), + vlv_dpio_write(display, phy, VLV_TX_DW5_GRP(ch), 0x00000000); + vlv_dpio_write(display, phy, VLV_TX_DW4_GRP(ch), demph_reg_value); + vlv_dpio_write(display, phy, VLV_TX_DW2_GRP(ch), uniqtranscale_reg_value); - vlv_dpio_write(display->drm, phy, VLV_TX_DW3_GRP(ch), 0x0C782040); + vlv_dpio_write(display, phy, VLV_TX_DW3_GRP(ch), 0x0C782040); if (tx3_demph) - vlv_dpio_write(display->drm, phy, VLV_TX_DW4(ch, 3), tx3_demph); + vlv_dpio_write(display, phy, VLV_TX_DW4(ch, 3), tx3_demph); - vlv_dpio_write(display->drm, phy, VLV_PCS_DW11_GRP(ch), 0x00030000); - vlv_dpio_write(display->drm, phy, VLV_PCS_DW9_GRP(ch), preemph_reg_value); - vlv_dpio_write(display->drm, phy, VLV_TX_DW5_GRP(ch), DPIO_TX_OCALINIT_EN); + vlv_dpio_write(display, phy, VLV_PCS_DW11_GRP(ch), 0x00030000); + vlv_dpio_write(display, phy, VLV_PCS_DW9_GRP(ch), preemph_reg_value); + vlv_dpio_write(display, phy, VLV_TX_DW5_GRP(ch), DPIO_TX_OCALINIT_EN); - vlv_dpio_put(display->drm); + vlv_dpio_put(display); } void vlv_phy_pre_pll_enable(struct intel_encoder *encoder, @@ -1106,23 +1106,23 @@ void vlv_phy_pre_pll_enable(struct intel_encoder *encoder, enum dpio_phy phy = vlv_dig_port_to_phy(dig_port); /* Program Tx lane resets to default */ - vlv_dpio_get(display->drm); + vlv_dpio_get(display); - vlv_dpio_write(display->drm, phy, VLV_PCS_DW0_GRP(ch), + vlv_dpio_write(display, phy, VLV_PCS_DW0_GRP(ch), DPIO_PCS_TX_LANE2_RESET | DPIO_PCS_TX_LANE1_RESET); - vlv_dpio_write(display->drm, phy, VLV_PCS_DW1_GRP(ch), + vlv_dpio_write(display, phy, VLV_PCS_DW1_GRP(ch), DPIO_PCS_CLK_CRI_RXEB_EIOS_EN | DPIO_PCS_CLK_CRI_RXDIGFILTSG_EN | DPIO_PCS_CLK_DATAWIDTH_8_10 | DPIO_PCS_CLK_SOFT_RESET); /* Fix up inter-pair skew failure */ - vlv_dpio_write(display->drm, phy, VLV_PCS_DW12_GRP(ch), 0x00750f00); - vlv_dpio_write(display->drm, phy, VLV_TX_DW11_GRP(ch), 0x00001500); - vlv_dpio_write(display->drm, phy, VLV_TX_DW14_GRP(ch), 0x40400000); + vlv_dpio_write(display, phy, VLV_PCS_DW12_GRP(ch), 0x00750f00); + vlv_dpio_write(display, phy, VLV_TX_DW11_GRP(ch), 0x00001500); + vlv_dpio_write(display, phy, VLV_TX_DW14_GRP(ch), 0x40400000); - vlv_dpio_put(display->drm); + vlv_dpio_put(display); } void vlv_phy_pre_encoder_enable(struct intel_encoder *encoder, @@ -1137,20 +1137,20 @@ void vlv_phy_pre_encoder_enable(struct intel_encoder *encoder, enum pipe pipe = crtc->pipe; u32 val; - vlv_dpio_get(display->drm); + vlv_dpio_get(display); /* Enable clock channels for this port */ val = DPIO_PCS_USEDCLKCHANNEL_OVRRIDE; if (pipe == PIPE_B) val |= DPIO_PCS_USEDCLKCHANNEL; val |= 0xc4; - vlv_dpio_write(display->drm, phy, VLV_PCS_DW8_GRP(ch), val); + vlv_dpio_write(display, phy, VLV_PCS_DW8_GRP(ch), val); /* Program lane clock */ - vlv_dpio_write(display->drm, phy, VLV_PCS_DW14_GRP(ch), 0x00760018); - vlv_dpio_write(display->drm, phy, VLV_PCS_DW23_GRP(ch), 0x00400888); + vlv_dpio_write(display, phy, VLV_PCS_DW14_GRP(ch), 0x00760018); + vlv_dpio_write(display, phy, VLV_PCS_DW23_GRP(ch), 0x00400888); - vlv_dpio_put(display->drm); + vlv_dpio_put(display); } void vlv_phy_reset_lanes(struct intel_encoder *encoder, @@ -1161,10 +1161,10 @@ void vlv_phy_reset_lanes(struct intel_encoder *encoder, enum dpio_channel ch = vlv_dig_port_to_channel(dig_port); enum dpio_phy phy = vlv_dig_port_to_phy(dig_port); - vlv_dpio_get(display->drm); - vlv_dpio_write(display->drm, phy, VLV_PCS_DW0_GRP(ch), 0x00000000); - vlv_dpio_write(display->drm, phy, VLV_PCS_DW1_GRP(ch), 0x00e00060); - vlv_dpio_put(display->drm); + vlv_dpio_get(display); + vlv_dpio_write(display, phy, VLV_PCS_DW0_GRP(ch), 0x00000000); + vlv_dpio_write(display, phy, VLV_PCS_DW1_GRP(ch), 0x00e00060); + vlv_dpio_put(display); } void vlv_wait_port_ready(struct intel_encoder *encoder, diff --git a/drivers/gpu/drm/i915/display/intel_dpll.c b/drivers/gpu/drm/i915/display/intel_dpll.c index c7d37e74fbe9..a1aa88598013 100644 --- a/drivers/gpu/drm/i915/display/intel_dpll.c +++ b/drivers/gpu/drm/i915/display/intel_dpll.c @@ -528,9 +528,9 @@ void vlv_crtc_clock_get(struct intel_crtc_state *crtc_state) if ((hw_state->dpll & DPLL_VCO_ENABLE) == 0) return; - vlv_dpio_get(display->drm); - tmp = vlv_dpio_read(display->drm, phy, VLV_PLL_DW3(ch)); - vlv_dpio_put(display->drm); + vlv_dpio_get(display); + tmp = vlv_dpio_read(display, phy, VLV_PLL_DW3(ch)); + vlv_dpio_put(display); clock.m1 = REG_FIELD_GET(DPIO_M1_DIV_MASK, tmp); clock.m2 = REG_FIELD_GET(DPIO_M2_DIV_MASK, tmp); @@ -556,13 +556,13 @@ void chv_crtc_clock_get(struct intel_crtc_state *crtc_state) if ((hw_state->dpll & DPLL_VCO_ENABLE) == 0) return; - vlv_dpio_get(display->drm); - cmn_dw13 = vlv_dpio_read(display->drm, phy, CHV_CMN_DW13(ch)); - pll_dw0 = vlv_dpio_read(display->drm, phy, CHV_PLL_DW0(ch)); - pll_dw1 = vlv_dpio_read(display->drm, phy, CHV_PLL_DW1(ch)); - pll_dw2 = vlv_dpio_read(display->drm, phy, CHV_PLL_DW2(ch)); - pll_dw3 = vlv_dpio_read(display->drm, phy, CHV_PLL_DW3(ch)); - vlv_dpio_put(display->drm); + vlv_dpio_get(display); + cmn_dw13 = vlv_dpio_read(display, phy, CHV_CMN_DW13(ch)); + pll_dw0 = vlv_dpio_read(display, phy, CHV_PLL_DW0(ch)); + pll_dw1 = vlv_dpio_read(display, phy, CHV_PLL_DW1(ch)); + pll_dw2 = vlv_dpio_read(display, phy, CHV_PLL_DW2(ch)); + pll_dw3 = vlv_dpio_read(display, phy, CHV_PLL_DW3(ch)); + vlv_dpio_put(display); clock.m1 = REG_FIELD_GET(DPIO_CHV_M1_DIV_MASK, pll_dw1) == DPIO_CHV_M1_DIV_BY_2 ? 2 : 0; clock.m2 = REG_FIELD_GET(DPIO_CHV_M2_DIV_MASK, pll_dw0) << 22; @@ -1866,24 +1866,24 @@ static void vlv_pllb_recal_opamp(struct intel_display *display, * PLLB opamp always calibrates to max value of 0x3f, force enable it * and set it to a reasonable value instead. */ - tmp = vlv_dpio_read(display->drm, phy, VLV_PLL_DW17(ch)); + tmp = vlv_dpio_read(display, phy, VLV_PLL_DW17(ch)); tmp &= 0xffffff00; tmp |= 0x00000030; - vlv_dpio_write(display->drm, phy, VLV_PLL_DW17(ch), tmp); + vlv_dpio_write(display, phy, VLV_PLL_DW17(ch), tmp); - tmp = vlv_dpio_read(display->drm, phy, VLV_REF_DW11); + tmp = vlv_dpio_read(display, phy, VLV_REF_DW11); tmp &= 0x00ffffff; tmp |= 0x8c000000; - vlv_dpio_write(display->drm, phy, VLV_REF_DW11, tmp); + vlv_dpio_write(display, phy, VLV_REF_DW11, tmp); - tmp = vlv_dpio_read(display->drm, phy, VLV_PLL_DW17(ch)); + tmp = vlv_dpio_read(display, phy, VLV_PLL_DW17(ch)); tmp &= 0xffffff00; - vlv_dpio_write(display->drm, phy, VLV_PLL_DW17(ch), tmp); + vlv_dpio_write(display, phy, VLV_PLL_DW17(ch), tmp); - tmp = vlv_dpio_read(display->drm, phy, VLV_REF_DW11); + tmp = vlv_dpio_read(display, phy, VLV_REF_DW11); tmp &= 0x00ffffff; tmp |= 0xb0000000; - vlv_dpio_write(display->drm, phy, VLV_REF_DW11, tmp); + vlv_dpio_write(display, phy, VLV_REF_DW11, tmp); } static void vlv_prepare_pll(const struct intel_crtc_state *crtc_state) @@ -1896,7 +1896,7 @@ static void vlv_prepare_pll(const struct intel_crtc_state *crtc_state) enum pipe pipe = crtc->pipe; u32 tmp, coreclk; - vlv_dpio_get(display->drm); + vlv_dpio_get(display); /* See eDP HDMI DPIO driver vbios notes doc */ @@ -1905,15 +1905,15 @@ static void vlv_prepare_pll(const struct intel_crtc_state *crtc_state) vlv_pllb_recal_opamp(display, phy, ch); /* Set up Tx target for periodic Rcomp update */ - vlv_dpio_write(display->drm, phy, VLV_PCS_DW17_BCAST, 0x0100000f); + vlv_dpio_write(display, phy, VLV_PCS_DW17_BCAST, 0x0100000f); /* Disable target IRef on PLL */ - tmp = vlv_dpio_read(display->drm, phy, VLV_PLL_DW16(ch)); + tmp = vlv_dpio_read(display, phy, VLV_PLL_DW16(ch)); tmp &= 0x00ffffff; - vlv_dpio_write(display->drm, phy, VLV_PLL_DW16(ch), tmp); + vlv_dpio_write(display, phy, VLV_PLL_DW16(ch), tmp); /* Disable fast lock */ - vlv_dpio_write(display->drm, phy, VLV_CMN_DW0, 0x610); + vlv_dpio_write(display, phy, VLV_CMN_DW0, 0x610); /* Set idtafcrecal before PLL is enabled */ tmp = DPIO_M1_DIV(clock->m1) | @@ -1929,42 +1929,42 @@ static void vlv_prepare_pll(const struct intel_crtc_state *crtc_state) * Note: don't use the DAC post divider as it seems unstable. */ tmp |= DPIO_S1_DIV(DPIO_S1_DIV_HDMIDP); - vlv_dpio_write(display->drm, phy, VLV_PLL_DW3(ch), tmp); + vlv_dpio_write(display, phy, VLV_PLL_DW3(ch), tmp); tmp |= DPIO_ENABLE_CALIBRATION; - vlv_dpio_write(display->drm, phy, VLV_PLL_DW3(ch), tmp); + vlv_dpio_write(display, phy, VLV_PLL_DW3(ch), tmp); /* Set HBR and RBR LPF coefficients */ if (crtc_state->port_clock == 162000 || intel_crtc_has_type(crtc_state, INTEL_OUTPUT_ANALOG) || intel_crtc_has_type(crtc_state, INTEL_OUTPUT_HDMI)) - vlv_dpio_write(display->drm, phy, VLV_PLL_DW18(ch), 0x009f0003); + vlv_dpio_write(display, phy, VLV_PLL_DW18(ch), 0x009f0003); else - vlv_dpio_write(display->drm, phy, VLV_PLL_DW18(ch), 0x00d0000f); + vlv_dpio_write(display, phy, VLV_PLL_DW18(ch), 0x00d0000f); if (intel_crtc_has_dp_encoder(crtc_state)) { /* Use SSC source */ if (pipe == PIPE_A) - vlv_dpio_write(display->drm, phy, VLV_PLL_DW5(ch), 0x0df40000); + vlv_dpio_write(display, phy, VLV_PLL_DW5(ch), 0x0df40000); else - vlv_dpio_write(display->drm, phy, VLV_PLL_DW5(ch), 0x0df70000); + vlv_dpio_write(display, phy, VLV_PLL_DW5(ch), 0x0df70000); } else { /* HDMI or VGA */ /* Use bend source */ if (pipe == PIPE_A) - vlv_dpio_write(display->drm, phy, VLV_PLL_DW5(ch), 0x0df70000); + vlv_dpio_write(display, phy, VLV_PLL_DW5(ch), 0x0df70000); else - vlv_dpio_write(display->drm, phy, VLV_PLL_DW5(ch), 0x0df40000); + vlv_dpio_write(display, phy, VLV_PLL_DW5(ch), 0x0df40000); } - coreclk = vlv_dpio_read(display->drm, phy, VLV_PLL_DW7(ch)); + coreclk = vlv_dpio_read(display, phy, VLV_PLL_DW7(ch)); coreclk = (coreclk & 0x0000ff00) | 0x01c00000; if (intel_crtc_has_dp_encoder(crtc_state)) coreclk |= 0x01000000; - vlv_dpio_write(display->drm, phy, VLV_PLL_DW7(ch), coreclk); + vlv_dpio_write(display, phy, VLV_PLL_DW7(ch), coreclk); - vlv_dpio_write(display->drm, phy, VLV_PLL_DW19(ch), 0x87871000); + vlv_dpio_write(display, phy, VLV_PLL_DW19(ch), 0x87871000); - vlv_dpio_put(display->drm); + vlv_dpio_put(display); } static void _vlv_enable_pll(const struct intel_crtc_state *crtc_state) @@ -2019,44 +2019,44 @@ static void chv_prepare_pll(const struct intel_crtc_state *crtc_state) m2_frac = clock->m2 & 0x3fffff; - vlv_dpio_get(display->drm); + vlv_dpio_get(display); /* p1 and p2 divider */ - vlv_dpio_write(display->drm, phy, CHV_CMN_DW13(ch), + vlv_dpio_write(display, phy, CHV_CMN_DW13(ch), DPIO_CHV_S1_DIV(5) | DPIO_CHV_P1_DIV(clock->p1) | DPIO_CHV_P2_DIV(clock->p2) | DPIO_CHV_K_DIV(1)); /* Feedback post-divider - m2 */ - vlv_dpio_write(display->drm, phy, CHV_PLL_DW0(ch), + vlv_dpio_write(display, phy, CHV_PLL_DW0(ch), DPIO_CHV_M2_DIV(clock->m2 >> 22)); /* Feedback refclk divider - n and m1 */ - vlv_dpio_write(display->drm, phy, CHV_PLL_DW1(ch), + vlv_dpio_write(display, phy, CHV_PLL_DW1(ch), DPIO_CHV_M1_DIV(DPIO_CHV_M1_DIV_BY_2) | DPIO_CHV_N_DIV(1)); /* M2 fraction division */ - vlv_dpio_write(display->drm, phy, CHV_PLL_DW2(ch), + vlv_dpio_write(display, phy, CHV_PLL_DW2(ch), DPIO_CHV_M2_FRAC_DIV(m2_frac)); /* M2 fraction division enable */ - tmp = vlv_dpio_read(display->drm, phy, CHV_PLL_DW3(ch)); + tmp = vlv_dpio_read(display, phy, CHV_PLL_DW3(ch)); tmp &= ~(DPIO_CHV_FEEDFWD_GAIN_MASK | DPIO_CHV_FRAC_DIV_EN); tmp |= DPIO_CHV_FEEDFWD_GAIN(2); if (m2_frac) tmp |= DPIO_CHV_FRAC_DIV_EN; - vlv_dpio_write(display->drm, phy, CHV_PLL_DW3(ch), tmp); + vlv_dpio_write(display, phy, CHV_PLL_DW3(ch), tmp); /* Program digital lock detect threshold */ - tmp = vlv_dpio_read(display->drm, phy, CHV_PLL_DW9(ch)); + tmp = vlv_dpio_read(display, phy, CHV_PLL_DW9(ch)); tmp &= ~(DPIO_CHV_INT_LOCK_THRESHOLD_MASK | DPIO_CHV_INT_LOCK_THRESHOLD_SEL_COARSE); tmp |= DPIO_CHV_INT_LOCK_THRESHOLD(0x5); if (!m2_frac) tmp |= DPIO_CHV_INT_LOCK_THRESHOLD_SEL_COARSE; - vlv_dpio_write(display->drm, phy, CHV_PLL_DW9(ch), tmp); + vlv_dpio_write(display, phy, CHV_PLL_DW9(ch), tmp); /* Loop filter */ if (clock->vco == 5400000) { @@ -2081,19 +2081,19 @@ static void chv_prepare_pll(const struct intel_crtc_state *crtc_state) DPIO_CHV_GAIN_CTRL(0x3); tribuf_calcntr = 0; } - vlv_dpio_write(display->drm, phy, CHV_PLL_DW6(ch), loopfilter); + vlv_dpio_write(display, phy, CHV_PLL_DW6(ch), loopfilter); - tmp = vlv_dpio_read(display->drm, phy, CHV_PLL_DW8(ch)); + tmp = vlv_dpio_read(display, phy, CHV_PLL_DW8(ch)); tmp &= ~DPIO_CHV_TDC_TARGET_CNT_MASK; tmp |= DPIO_CHV_TDC_TARGET_CNT(tribuf_calcntr); - vlv_dpio_write(display->drm, phy, CHV_PLL_DW8(ch), tmp); + vlv_dpio_write(display, phy, CHV_PLL_DW8(ch), tmp); /* AFC Recal */ - vlv_dpio_write(display->drm, phy, CHV_CMN_DW14(ch), - vlv_dpio_read(display->drm, phy, CHV_CMN_DW14(ch)) | + vlv_dpio_write(display, phy, CHV_CMN_DW14(ch), + vlv_dpio_read(display, phy, CHV_CMN_DW14(ch)) | DPIO_AFC_RECAL); - vlv_dpio_put(display->drm); + vlv_dpio_put(display); } static void _chv_enable_pll(const struct intel_crtc_state *crtc_state) @@ -2106,14 +2106,14 @@ static void _chv_enable_pll(const struct intel_crtc_state *crtc_state) enum pipe pipe = crtc->pipe; u32 tmp; - vlv_dpio_get(display->drm); + vlv_dpio_get(display); /* Enable back the 10bit clock to display controller */ - tmp = vlv_dpio_read(display->drm, phy, CHV_CMN_DW14(ch)); + tmp = vlv_dpio_read(display, phy, CHV_CMN_DW14(ch)); tmp |= DPIO_DCLKP_EN; - vlv_dpio_write(display->drm, phy, CHV_CMN_DW14(ch), tmp); + vlv_dpio_write(display, phy, CHV_CMN_DW14(ch), tmp); - vlv_dpio_put(display->drm); + vlv_dpio_put(display); /* * Need to wait > 100ns between dclkp clock enable bit and PLL enable. @@ -2247,14 +2247,14 @@ void chv_disable_pll(struct intel_display *display, enum pipe pipe) intel_de_write(display, DPLL(display, pipe), val); intel_de_posting_read(display, DPLL(display, pipe)); - vlv_dpio_get(display->drm); + vlv_dpio_get(display); /* Disable 10bit clock to display controller */ - val = vlv_dpio_read(display->drm, phy, CHV_CMN_DW14(ch)); + val = vlv_dpio_read(display, phy, CHV_CMN_DW14(ch)); val &= ~DPIO_DCLKP_EN; - vlv_dpio_write(display->drm, phy, CHV_CMN_DW14(ch), val); + vlv_dpio_write(display, phy, CHV_CMN_DW14(ch), val); - vlv_dpio_put(display->drm); + vlv_dpio_put(display); } void i9xx_disable_pll(const struct intel_crtc_state *crtc_state) diff --git a/drivers/gpu/drm/i915/display/vlv_clock.c b/drivers/gpu/drm/i915/display/vlv_clock.c index 1abdae453514..a589cdb74903 100644 --- a/drivers/gpu/drm/i915/display/vlv_clock.c +++ b/drivers/gpu/drm/i915/display/vlv_clock.c @@ -22,11 +22,11 @@ int vlv_clock_get_hpll_vco(struct drm_device *drm) int hpll_freq, vco_freq[] = { 800, 1600, 2000, 2400 }; if (!display->vlv_clock.hpll_freq) { - vlv_cck_get(drm); + vlv_cck_get(display); /* Obtain SKU information */ - hpll_freq = vlv_cck_read(drm, CCK_FUSE_REG) & + hpll_freq = vlv_cck_read(display, CCK_FUSE_REG) & CCK_FUSE_HPLL_FREQ_MASK; - vlv_cck_put(drm); + vlv_cck_put(display); display->vlv_clock.hpll_freq = vco_freq[hpll_freq] * 1000; @@ -39,12 +39,13 @@ int vlv_clock_get_hpll_vco(struct drm_device *drm) static int vlv_clock_get_cck(struct drm_device *drm, const char *name, u32 reg, int ref_freq) { + struct intel_display *display = to_intel_display(drm); u32 val; int divider; - vlv_cck_get(drm); - val = vlv_cck_read(drm, reg); - vlv_cck_put(drm); + vlv_cck_get(display); + val = vlv_cck_read(display, reg); + vlv_cck_put(display); divider = val & CCK_FREQUENCY_VALUES; diff --git a/drivers/gpu/drm/i915/display/vlv_dsi.c b/drivers/gpu/drm/i915/display/vlv_dsi.c index d4db73c184e5..76e8cd0f65a4 100644 --- a/drivers/gpu/drm/i915/display/vlv_dsi.c +++ b/drivers/gpu/drm/i915/display/vlv_dsi.c @@ -254,16 +254,16 @@ static int dpi_send_cmd(struct intel_dsi *intel_dsi, u32 cmd, bool hs, static void band_gap_reset(struct intel_display *display) { - vlv_flisdsi_get(display->drm); + vlv_flisdsi_get(display); - vlv_flisdsi_write(display->drm, 0x08, 0x0001); - vlv_flisdsi_write(display->drm, 0x0F, 0x0005); - vlv_flisdsi_write(display->drm, 0x0F, 0x0025); + vlv_flisdsi_write(display, 0x08, 0x0001); + vlv_flisdsi_write(display, 0x0F, 0x0005); + vlv_flisdsi_write(display, 0x0F, 0x0025); udelay(150); - vlv_flisdsi_write(display->drm, 0x0F, 0x0000); - vlv_flisdsi_write(display->drm, 0x08, 0x0000); + vlv_flisdsi_write(display, 0x0F, 0x0000); + vlv_flisdsi_write(display, 0x08, 0x0000); - vlv_flisdsi_put(display->drm); + vlv_flisdsi_put(display); } static int intel_dsi_compute_config(struct intel_encoder *encoder, @@ -461,11 +461,11 @@ static void vlv_dsi_device_ready(struct intel_encoder *encoder) drm_dbg_kms(display->drm, "\n"); - vlv_flisdsi_get(display->drm); + vlv_flisdsi_get(display); /* program rcomp for compliance, reduce from 50 ohms to 45 ohms * needed everytime after power gate */ - vlv_flisdsi_write(display->drm, 0x04, 0x0004); - vlv_flisdsi_put(display->drm); + vlv_flisdsi_write(display, 0x04, 0x0004); + vlv_flisdsi_put(display); /* bandgap reset is needed after everytime we do power gate */ band_gap_reset(display); diff --git a/drivers/gpu/drm/i915/display/vlv_dsi_pll.c b/drivers/gpu/drm/i915/display/vlv_dsi_pll.c index a2da6285890b..68b73cca2aec 100644 --- a/drivers/gpu/drm/i915/display/vlv_dsi_pll.c +++ b/drivers/gpu/drm/i915/display/vlv_dsi_pll.c @@ -219,11 +219,11 @@ void vlv_dsi_pll_enable(struct intel_encoder *encoder, drm_dbg_kms(display->drm, "\n"); - vlv_cck_get(display->drm); + vlv_cck_get(display); - vlv_cck_write(display->drm, CCK_REG_DSI_PLL_CONTROL, 0); - vlv_cck_write(display->drm, CCK_REG_DSI_PLL_DIVIDER, config->dsi_pll.div); - vlv_cck_write(display->drm, CCK_REG_DSI_PLL_CONTROL, + vlv_cck_write(display, CCK_REG_DSI_PLL_CONTROL, 0); + vlv_cck_write(display, CCK_REG_DSI_PLL_DIVIDER, config->dsi_pll.div); + vlv_cck_write(display, CCK_REG_DSI_PLL_CONTROL, config->dsi_pll.ctrl & ~DSI_PLL_VCO_EN); /* wait at least 0.5 us after ungating before enabling VCO, @@ -231,17 +231,17 @@ void vlv_dsi_pll_enable(struct intel_encoder *encoder, */ usleep_range(10, 50); - vlv_cck_write(display->drm, CCK_REG_DSI_PLL_CONTROL, config->dsi_pll.ctrl); + vlv_cck_write(display, CCK_REG_DSI_PLL_CONTROL, config->dsi_pll.ctrl); - ret = poll_timeout_us(val = vlv_cck_read(display->drm, CCK_REG_DSI_PLL_CONTROL), + ret = poll_timeout_us(val = vlv_cck_read(display, CCK_REG_DSI_PLL_CONTROL), val & DSI_PLL_LOCK, 500, 20 * 1000, false); if (ret) { - vlv_cck_put(display->drm); + vlv_cck_put(display); drm_err(display->drm, "DSI PLL lock failed\n"); return; } - vlv_cck_put(display->drm); + vlv_cck_put(display); drm_dbg_kms(display->drm, "DSI PLL locked\n"); } @@ -253,14 +253,14 @@ void vlv_dsi_pll_disable(struct intel_encoder *encoder) drm_dbg_kms(display->drm, "\n"); - vlv_cck_get(display->drm); + vlv_cck_get(display); - tmp = vlv_cck_read(display->drm, CCK_REG_DSI_PLL_CONTROL); + tmp = vlv_cck_read(display, CCK_REG_DSI_PLL_CONTROL); tmp &= ~DSI_PLL_VCO_EN; tmp |= DSI_PLL_LDO_GATE; - vlv_cck_write(display->drm, CCK_REG_DSI_PLL_CONTROL, tmp); + vlv_cck_write(display, CCK_REG_DSI_PLL_CONTROL, tmp); - vlv_cck_put(display->drm); + vlv_cck_put(display); } static bool has_dsic_clock(struct intel_display *display) @@ -333,10 +333,10 @@ u32 vlv_dsi_get_pclk(struct intel_encoder *encoder, drm_dbg_kms(display->drm, "\n"); - vlv_cck_get(display->drm); - pll_ctl = vlv_cck_read(display->drm, CCK_REG_DSI_PLL_CONTROL); - pll_div = vlv_cck_read(display->drm, CCK_REG_DSI_PLL_DIVIDER); - vlv_cck_put(display->drm); + vlv_cck_get(display); + pll_ctl = vlv_cck_read(display, CCK_REG_DSI_PLL_CONTROL); + pll_div = vlv_cck_read(display, CCK_REG_DSI_PLL_DIVIDER); + vlv_cck_put(display); config->dsi_pll.ctrl = pll_ctl & ~DSI_PLL_LOCK; config->dsi_pll.div = pll_div; @@ -603,9 +603,9 @@ static void assert_dsi_pll(struct intel_display *display, bool state) { bool cur_state; - vlv_cck_get(display->drm); - cur_state = vlv_cck_read(display->drm, CCK_REG_DSI_PLL_CONTROL) & DSI_PLL_VCO_EN; - vlv_cck_put(display->drm); + vlv_cck_get(display); + cur_state = vlv_cck_read(display, CCK_REG_DSI_PLL_CONTROL) & DSI_PLL_VCO_EN; + vlv_cck_put(display); INTEL_DISPLAY_STATE_WARN(display, cur_state != state, "DSI PLL state assertion failure (expected %s, current %s)\n", diff --git a/drivers/gpu/drm/i915/display/vlv_sideband.c b/drivers/gpu/drm/i915/display/vlv_sideband.c index 2472e0412728..a9c812da3c91 100644 --- a/drivers/gpu/drm/i915/display/vlv_sideband.c +++ b/drivers/gpu/drm/i915/display/vlv_sideband.c @@ -8,69 +8,69 @@ #include "intel_dpio_phy.h" #include "vlv_sideband.h" -void vlv_bunit_get(struct drm_device *drm) +void vlv_bunit_get(struct intel_display *display) { - vlv_iosf_sb_get(drm, BIT(VLV_IOSF_SB_BUNIT)); + vlv_iosf_sb_get(display->drm, BIT(VLV_IOSF_SB_BUNIT)); } -u32 vlv_bunit_read(struct drm_device *drm, u32 reg) +u32 vlv_bunit_read(struct intel_display *display, u32 reg) { - return vlv_iosf_sb_read(drm, VLV_IOSF_SB_BUNIT, reg); + return vlv_iosf_sb_read(display->drm, VLV_IOSF_SB_BUNIT, reg); } -void vlv_bunit_write(struct drm_device *drm, u32 reg, u32 val) +void vlv_bunit_write(struct intel_display *display, u32 reg, u32 val) { - vlv_iosf_sb_write(drm, VLV_IOSF_SB_BUNIT, reg, val); + vlv_iosf_sb_write(display->drm, VLV_IOSF_SB_BUNIT, reg, val); } -void vlv_bunit_put(struct drm_device *drm) +void vlv_bunit_put(struct intel_display *display) { - vlv_iosf_sb_put(drm, BIT(VLV_IOSF_SB_BUNIT)); + vlv_iosf_sb_put(display->drm, BIT(VLV_IOSF_SB_BUNIT)); } -void vlv_cck_get(struct drm_device *drm) +void vlv_cck_get(struct intel_display *display) { - vlv_iosf_sb_get(drm, BIT(VLV_IOSF_SB_CCK)); + vlv_iosf_sb_get(display->drm, BIT(VLV_IOSF_SB_CCK)); } -u32 vlv_cck_read(struct drm_device *drm, u32 reg) +u32 vlv_cck_read(struct intel_display *display, u32 reg) { - return vlv_iosf_sb_read(drm, VLV_IOSF_SB_CCK, reg); + return vlv_iosf_sb_read(display->drm, VLV_IOSF_SB_CCK, reg); } -void vlv_cck_write(struct drm_device *drm, u32 reg, u32 val) +void vlv_cck_write(struct intel_display *display, u32 reg, u32 val) { - vlv_iosf_sb_write(drm, VLV_IOSF_SB_CCK, reg, val); + vlv_iosf_sb_write(display->drm, VLV_IOSF_SB_CCK, reg, val); } -void vlv_cck_put(struct drm_device *drm) +void vlv_cck_put(struct intel_display *display) { - vlv_iosf_sb_put(drm, BIT(VLV_IOSF_SB_CCK)); + vlv_iosf_sb_put(display->drm, BIT(VLV_IOSF_SB_CCK)); } -void vlv_ccu_get(struct drm_device *drm) +void vlv_ccu_get(struct intel_display *display) { - vlv_iosf_sb_get(drm, BIT(VLV_IOSF_SB_CCU)); + vlv_iosf_sb_get(display->drm, BIT(VLV_IOSF_SB_CCU)); } -u32 vlv_ccu_read(struct drm_device *drm, u32 reg) +u32 vlv_ccu_read(struct intel_display *display, u32 reg) { - return vlv_iosf_sb_read(drm, VLV_IOSF_SB_CCU, reg); + return vlv_iosf_sb_read(display->drm, VLV_IOSF_SB_CCU, reg); } -void vlv_ccu_write(struct drm_device *drm, u32 reg, u32 val) +void vlv_ccu_write(struct intel_display *display, u32 reg, u32 val) { - vlv_iosf_sb_write(drm, VLV_IOSF_SB_CCU, reg, val); + vlv_iosf_sb_write(display->drm, VLV_IOSF_SB_CCU, reg, val); } -void vlv_ccu_put(struct drm_device *drm) +void vlv_ccu_put(struct intel_display *display) { - vlv_iosf_sb_put(drm, BIT(VLV_IOSF_SB_CCU)); + vlv_iosf_sb_put(display->drm, BIT(VLV_IOSF_SB_CCU)); } -void vlv_dpio_get(struct drm_device *drm) +void vlv_dpio_get(struct intel_display *display) { - vlv_iosf_sb_get(drm, BIT(VLV_IOSF_SB_DPIO) | BIT(VLV_IOSF_SB_DPIO_2)); + vlv_iosf_sb_get(display->drm, BIT(VLV_IOSF_SB_DPIO) | BIT(VLV_IOSF_SB_DPIO_2)); } static enum vlv_iosf_sb_unit vlv_dpio_phy_to_unit(struct intel_display *display, @@ -86,13 +86,12 @@ static enum vlv_iosf_sb_unit vlv_dpio_phy_to_unit(struct intel_display *display, return VLV_IOSF_SB_DPIO; } -u32 vlv_dpio_read(struct drm_device *drm, enum dpio_phy phy, int reg) +u32 vlv_dpio_read(struct intel_display *display, enum dpio_phy phy, int reg) { - struct intel_display *display = to_intel_display(drm); enum vlv_iosf_sb_unit unit = vlv_dpio_phy_to_unit(display, phy); u32 val; - val = vlv_iosf_sb_read(drm, unit, reg); + val = vlv_iosf_sb_read(display->drm, unit, reg); /* * FIXME: There might be some registers where all 1's is a valid value, @@ -105,71 +104,70 @@ u32 vlv_dpio_read(struct drm_device *drm, enum dpio_phy phy, int reg) return val; } -void vlv_dpio_write(struct drm_device *drm, +void vlv_dpio_write(struct intel_display *display, enum dpio_phy phy, int reg, u32 val) { - struct intel_display *display = to_intel_display(drm); enum vlv_iosf_sb_unit unit = vlv_dpio_phy_to_unit(display, phy); - vlv_iosf_sb_write(drm, unit, reg, val); + vlv_iosf_sb_write(display->drm, unit, reg, val); } -void vlv_dpio_put(struct drm_device *drm) +void vlv_dpio_put(struct intel_display *display) { - vlv_iosf_sb_put(drm, BIT(VLV_IOSF_SB_DPIO) | BIT(VLV_IOSF_SB_DPIO_2)); + vlv_iosf_sb_put(display->drm, BIT(VLV_IOSF_SB_DPIO) | BIT(VLV_IOSF_SB_DPIO_2)); } -void vlv_flisdsi_get(struct drm_device *drm) +void vlv_flisdsi_get(struct intel_display *display) { - vlv_iosf_sb_get(drm, BIT(VLV_IOSF_SB_FLISDSI)); + vlv_iosf_sb_get(display->drm, BIT(VLV_IOSF_SB_FLISDSI)); } -u32 vlv_flisdsi_read(struct drm_device *drm, u32 reg) +u32 vlv_flisdsi_read(struct intel_display *display, u32 reg) { - return vlv_iosf_sb_read(drm, VLV_IOSF_SB_FLISDSI, reg); + return vlv_iosf_sb_read(display->drm, VLV_IOSF_SB_FLISDSI, reg); } -void vlv_flisdsi_write(struct drm_device *drm, u32 reg, u32 val) +void vlv_flisdsi_write(struct intel_display *display, u32 reg, u32 val) { - vlv_iosf_sb_write(drm, VLV_IOSF_SB_FLISDSI, reg, val); + vlv_iosf_sb_write(display->drm, VLV_IOSF_SB_FLISDSI, reg, val); } -void vlv_flisdsi_put(struct drm_device *drm) +void vlv_flisdsi_put(struct intel_display *display) { - vlv_iosf_sb_put(drm, BIT(VLV_IOSF_SB_FLISDSI)); + vlv_iosf_sb_put(display->drm, BIT(VLV_IOSF_SB_FLISDSI)); } -void vlv_nc_get(struct drm_device *drm) +void vlv_nc_get(struct intel_display *display) { - vlv_iosf_sb_get(drm, BIT(VLV_IOSF_SB_NC)); + vlv_iosf_sb_get(display->drm, BIT(VLV_IOSF_SB_NC)); } -u32 vlv_nc_read(struct drm_device *drm, u8 addr) +u32 vlv_nc_read(struct intel_display *display, u8 addr) { - return vlv_iosf_sb_read(drm, VLV_IOSF_SB_NC, addr); + return vlv_iosf_sb_read(display->drm, VLV_IOSF_SB_NC, addr); } -void vlv_nc_put(struct drm_device *drm) +void vlv_nc_put(struct intel_display *display) { - vlv_iosf_sb_put(drm, BIT(VLV_IOSF_SB_NC)); + vlv_iosf_sb_put(display->drm, BIT(VLV_IOSF_SB_NC)); } -void vlv_punit_get(struct drm_device *drm) +void vlv_punit_get(struct intel_display *display) { - vlv_iosf_sb_get(drm, BIT(VLV_IOSF_SB_PUNIT)); + vlv_iosf_sb_get(display->drm, BIT(VLV_IOSF_SB_PUNIT)); } -u32 vlv_punit_read(struct drm_device *drm, u32 addr) +u32 vlv_punit_read(struct intel_display *display, u32 addr) { - return vlv_iosf_sb_read(drm, VLV_IOSF_SB_PUNIT, addr); + return vlv_iosf_sb_read(display->drm, VLV_IOSF_SB_PUNIT, addr); } -int vlv_punit_write(struct drm_device *drm, u32 addr, u32 val) +int vlv_punit_write(struct intel_display *display, u32 addr, u32 val) { - return vlv_iosf_sb_write(drm, VLV_IOSF_SB_PUNIT, addr, val); + return vlv_iosf_sb_write(display->drm, VLV_IOSF_SB_PUNIT, addr, val); } -void vlv_punit_put(struct drm_device *drm) +void vlv_punit_put(struct intel_display *display) { - vlv_iosf_sb_put(drm, BIT(VLV_IOSF_SB_PUNIT)); + vlv_iosf_sb_put(display->drm, BIT(VLV_IOSF_SB_PUNIT)); } diff --git a/drivers/gpu/drm/i915/display/vlv_sideband.h b/drivers/gpu/drm/i915/display/vlv_sideband.h index 065273726379..8751a070b0ae 100644 --- a/drivers/gpu/drm/i915/display/vlv_sideband.h +++ b/drivers/gpu/drm/i915/display/vlv_sideband.h @@ -10,40 +10,40 @@ #include "vlv_iosf_sb_reg.h" enum dpio_phy; -struct drm_device; - -void vlv_bunit_get(struct drm_device *drm); -u32 vlv_bunit_read(struct drm_device *drm, u32 reg); -void vlv_bunit_write(struct drm_device *drm, u32 reg, u32 val); -void vlv_bunit_put(struct drm_device *drm); - -void vlv_cck_get(struct drm_device *drm); -u32 vlv_cck_read(struct drm_device *drm, u32 reg); -void vlv_cck_write(struct drm_device *drm, u32 reg, u32 val); -void vlv_cck_put(struct drm_device *drm); - -void vlv_ccu_get(struct drm_device *drm); -u32 vlv_ccu_read(struct drm_device *drm, u32 reg); -void vlv_ccu_write(struct drm_device *drm, u32 reg, u32 val); -void vlv_ccu_put(struct drm_device *drm); - -void vlv_dpio_get(struct drm_device *drm); -u32 vlv_dpio_read(struct drm_device *drm, enum dpio_phy phy, int reg); -void vlv_dpio_write(struct drm_device *drm, enum dpio_phy phy, int reg, u32 val); -void vlv_dpio_put(struct drm_device *drm); - -void vlv_flisdsi_get(struct drm_device *drm); -u32 vlv_flisdsi_read(struct drm_device *drm, u32 reg); -void vlv_flisdsi_write(struct drm_device *drm, u32 reg, u32 val); -void vlv_flisdsi_put(struct drm_device *drm); - -void vlv_nc_get(struct drm_device *drm); -u32 vlv_nc_read(struct drm_device *drm, u8 addr); -void vlv_nc_put(struct drm_device *drm); - -void vlv_punit_get(struct drm_device *drm); -u32 vlv_punit_read(struct drm_device *drm, u32 addr); -int vlv_punit_write(struct drm_device *drm, u32 addr, u32 val); -void vlv_punit_put(struct drm_device *drm); +struct intel_display; + +void vlv_bunit_get(struct intel_display *display); +u32 vlv_bunit_read(struct intel_display *display, u32 reg); +void vlv_bunit_write(struct intel_display *display, u32 reg, u32 val); +void vlv_bunit_put(struct intel_display *display); + +void vlv_cck_get(struct intel_display *display); +u32 vlv_cck_read(struct intel_display *display, u32 reg); +void vlv_cck_write(struct intel_display *display, u32 reg, u32 val); +void vlv_cck_put(struct intel_display *display); + +void vlv_ccu_get(struct intel_display *display); +u32 vlv_ccu_read(struct intel_display *display, u32 reg); +void vlv_ccu_write(struct intel_display *display, u32 reg, u32 val); +void vlv_ccu_put(struct intel_display *display); + +void vlv_dpio_get(struct intel_display *display); +u32 vlv_dpio_read(struct intel_display *display, enum dpio_phy phy, int reg); +void vlv_dpio_write(struct intel_display *display, enum dpio_phy phy, int reg, u32 val); +void vlv_dpio_put(struct intel_display *display); + +void vlv_flisdsi_get(struct intel_display *display); +u32 vlv_flisdsi_read(struct intel_display *display, u32 reg); +void vlv_flisdsi_write(struct intel_display *display, u32 reg, u32 val); +void vlv_flisdsi_put(struct intel_display *display); + +void vlv_nc_get(struct intel_display *display); +u32 vlv_nc_read(struct intel_display *display, u8 addr); +void vlv_nc_put(struct intel_display *display); + +void vlv_punit_get(struct intel_display *display); +u32 vlv_punit_read(struct intel_display *display, u32 addr); +int vlv_punit_write(struct intel_display *display, u32 addr, u32 val); +void vlv_punit_put(struct intel_display *display); #endif /* _VLV_SIDEBAND_H_ */ -- cgit v1.2.3 From cad5a5ed3aed160c0ae371e60c9e94a967391b3d Mon Sep 17 00:00:00 2001 From: Jani Nikula Date: Tue, 31 Mar 2026 14:40:56 +0300 Subject: drm/i915/dram: prefer display abstractions for VLV sideband MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Use the display wrappers for VLV sideband in dram code. Reviewed-by: Ville Syrjälä Link: https://patch.msgid.link/c971f1a1eccceeb5599ccea5909443afe24b20d3.1774957233.git.jani.nikula@intel.com Signed-off-by: Jani Nikula --- drivers/gpu/drm/i915/display/intel_dram.c | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/drivers/gpu/drm/i915/display/intel_dram.c b/drivers/gpu/drm/i915/display/intel_dram.c index bd281d4b4c05..1686f808a084 100644 --- a/drivers/gpu/drm/i915/display/intel_dram.c +++ b/drivers/gpu/drm/i915/display/intel_dram.c @@ -16,7 +16,7 @@ #include "intel_mchbar_regs.h" #include "intel_parent.h" #include "intel_uncore.h" -#include "vlv_iosf_sb.h" +#include "vlv_sideband.h" struct dram_dimm_info { u16 size; @@ -109,9 +109,9 @@ static unsigned int chv_mem_freq(struct intel_display *display) { u32 val; - vlv_iosf_sb_get(display->drm, BIT(VLV_IOSF_SB_CCK)); - val = vlv_iosf_sb_read(display->drm, VLV_IOSF_SB_CCK, CCK_FUSE_REG); - vlv_iosf_sb_put(display->drm, BIT(VLV_IOSF_SB_CCK)); + vlv_cck_get(display); + val = vlv_cck_read(display, CCK_FUSE_REG); + vlv_cck_put(display); switch ((val >> 2) & 0x7) { case 3: @@ -125,9 +125,9 @@ static unsigned int vlv_mem_freq(struct intel_display *display) { u32 val; - vlv_iosf_sb_get(display->drm, BIT(VLV_IOSF_SB_PUNIT)); - val = vlv_iosf_sb_read(display->drm, VLV_IOSF_SB_PUNIT, PUNIT_REG_GPU_FREQ_STS); - vlv_iosf_sb_put(display->drm, BIT(VLV_IOSF_SB_PUNIT)); + vlv_punit_get(display); + val = vlv_punit_read(display, PUNIT_REG_GPU_FREQ_STS); + vlv_punit_put(display); switch ((val >> 6) & 3) { case 0: -- cgit v1.2.3 From 0563e28e0851ff327542f180974d14c525981a6f Mon Sep 17 00:00:00 2001 From: Jani Nikula Date: Tue, 31 Mar 2026 14:40:57 +0300 Subject: drm/i915: move VLV IOSF sideband to display parent interface MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Remove another direct dependency from display to i915 core by moving the VLV IOSF sideband calls to the display parent interface. Xe doesn't need this, so it'll remain optional and NULL. Reviewed-by: Ville Syrjälä Link: https://patch.msgid.link/15dfc67b58f5b5b381be0f9bc66d60b43bebfecf.1774957233.git.jani.nikula@intel.com Signed-off-by: Jani Nikula --- drivers/gpu/drm/i915/display/intel_cdclk.c | 16 ++++---- drivers/gpu/drm/i915/display/intel_parent.c | 34 +++++++++++++++++ drivers/gpu/drm/i915/display/intel_parent.h | 7 ++++ drivers/gpu/drm/i915/display/vlv_sideband.c | 55 ++++++++++++++-------------- drivers/gpu/drm/i915/i915_driver.c | 1 + drivers/gpu/drm/i915/vlv_iosf_sb.c | 8 ++++ drivers/gpu/drm/i915/vlv_iosf_sb.h | 2 + include/drm/intel/display_parent_interface.h | 11 ++++++ 8 files changed, 99 insertions(+), 35 deletions(-) diff --git a/drivers/gpu/drm/i915/display/intel_cdclk.c b/drivers/gpu/drm/i915/display/intel_cdclk.c index 8e0424a2c16f..4a663dddf896 100644 --- a/drivers/gpu/drm/i915/display/intel_cdclk.c +++ b/drivers/gpu/drm/i915/display/intel_cdclk.c @@ -691,10 +691,10 @@ static void vlv_set_cdclk(struct intel_display *display, */ wakeref = intel_display_power_get(display, POWER_DOMAIN_DISPLAY_CORE); - vlv_iosf_sb_get(display->drm, - BIT(VLV_IOSF_SB_CCK) | - BIT(VLV_IOSF_SB_BUNIT) | - BIT(VLV_IOSF_SB_PUNIT)); + intel_parent_vlv_iosf_get(display, + BIT(VLV_IOSF_SB_CCK) | + BIT(VLV_IOSF_SB_BUNIT) | + BIT(VLV_IOSF_SB_PUNIT)); val = vlv_punit_read(display, PUNIT_REG_DSPSSPM); val &= ~DSPFREQGUAR_MASK; @@ -740,10 +740,10 @@ static void vlv_set_cdclk(struct intel_display *display, val |= 3000 / 250; /* 3.0 usec */ vlv_bunit_write(display, BUNIT_REG_BISOC, val); - vlv_iosf_sb_put(display->drm, - BIT(VLV_IOSF_SB_CCK) | - BIT(VLV_IOSF_SB_BUNIT) | - BIT(VLV_IOSF_SB_PUNIT)); + intel_parent_vlv_iosf_put(display, + BIT(VLV_IOSF_SB_CCK) | + BIT(VLV_IOSF_SB_BUNIT) | + BIT(VLV_IOSF_SB_PUNIT)); intel_update_cdclk(display); diff --git a/drivers/gpu/drm/i915/display/intel_parent.c b/drivers/gpu/drm/i915/display/intel_parent.c index 2e3bad2b3e6b..4e01423a0392 100644 --- a/drivers/gpu/drm/i915/display/intel_parent.c +++ b/drivers/gpu/drm/i915/display/intel_parent.c @@ -22,6 +22,7 @@ #include "intel_display_core.h" #include "intel_parent.h" +#include "vlv_iosf_sb.h" /* dpt */ struct intel_dpt *intel_parent_dpt_create(struct intel_display *display, @@ -338,6 +339,39 @@ void intel_parent_stolen_node_free(struct intel_display *display, const struct i display->parent->stolen->node_free(node); } +/* vlv iosf */ +void intel_parent_vlv_iosf_get(struct intel_display *display, unsigned long unit_mask) +{ + if (drm_WARN_ON_ONCE(display->drm, !display->parent->vlv_iosf)) + return; + + display->parent->vlv_iosf->get(display->drm, unit_mask); +} + +void intel_parent_vlv_iosf_put(struct intel_display *display, unsigned long unit_mask) +{ + if (drm_WARN_ON_ONCE(display->drm, !display->parent->vlv_iosf)) + return; + + display->parent->vlv_iosf->put(display->drm, unit_mask); +} + +u32 intel_parent_vlv_iosf_read(struct intel_display *display, enum vlv_iosf_sb_unit unit, u32 addr) +{ + if (drm_WARN_ON_ONCE(display->drm, !display->parent->vlv_iosf)) + return 0; + + return display->parent->vlv_iosf->read(display->drm, unit, addr); +} + +int intel_parent_vlv_iosf_write(struct intel_display *display, enum vlv_iosf_sb_unit unit, u32 addr, u32 val) +{ + if (drm_WARN_ON_ONCE(display->drm, !display->parent->vlv_iosf)) + return -EINVAL; + + return display->parent->vlv_iosf->write(display->drm, unit, addr, val); +} + /* vma */ int intel_parent_vma_fence_id(struct intel_display *display, const struct i915_vma *vma) { diff --git a/drivers/gpu/drm/i915/display/intel_parent.h b/drivers/gpu/drm/i915/display/intel_parent.h index 2013e5ed5aa9..1e89d24163cc 100644 --- a/drivers/gpu/drm/i915/display/intel_parent.h +++ b/drivers/gpu/drm/i915/display/intel_parent.h @@ -6,6 +6,7 @@ #include +enum vlv_iosf_sb_unit; struct dma_fence; struct drm_file; struct drm_gem_object; @@ -109,6 +110,12 @@ u64 intel_parent_stolen_node_size(struct intel_display *display, const struct in struct intel_stolen_node *intel_parent_stolen_node_alloc(struct intel_display *display); void intel_parent_stolen_node_free(struct intel_display *display, const struct intel_stolen_node *node); +/* vlv iosf */ +void intel_parent_vlv_iosf_get(struct intel_display *display, unsigned long unit_mask); +void intel_parent_vlv_iosf_put(struct intel_display *display, unsigned long unit_mask); +u32 intel_parent_vlv_iosf_read(struct intel_display *display, enum vlv_iosf_sb_unit unit, u32 addr); +int intel_parent_vlv_iosf_write(struct intel_display *display, enum vlv_iosf_sb_unit unit, u32 addr, u32 val); + /* vma */ int intel_parent_vma_fence_id(struct intel_display *display, const struct i915_vma *vma); diff --git a/drivers/gpu/drm/i915/display/vlv_sideband.c b/drivers/gpu/drm/i915/display/vlv_sideband.c index a9c812da3c91..068f58bd9a2b 100644 --- a/drivers/gpu/drm/i915/display/vlv_sideband.c +++ b/drivers/gpu/drm/i915/display/vlv_sideband.c @@ -6,71 +6,72 @@ #include "intel_display_core.h" #include "intel_display_types.h" #include "intel_dpio_phy.h" +#include "intel_parent.h" #include "vlv_sideband.h" void vlv_bunit_get(struct intel_display *display) { - vlv_iosf_sb_get(display->drm, BIT(VLV_IOSF_SB_BUNIT)); + intel_parent_vlv_iosf_get(display, BIT(VLV_IOSF_SB_BUNIT)); } u32 vlv_bunit_read(struct intel_display *display, u32 reg) { - return vlv_iosf_sb_read(display->drm, VLV_IOSF_SB_BUNIT, reg); + return intel_parent_vlv_iosf_read(display, VLV_IOSF_SB_BUNIT, reg); } void vlv_bunit_write(struct intel_display *display, u32 reg, u32 val) { - vlv_iosf_sb_write(display->drm, VLV_IOSF_SB_BUNIT, reg, val); + intel_parent_vlv_iosf_write(display, VLV_IOSF_SB_BUNIT, reg, val); } void vlv_bunit_put(struct intel_display *display) { - vlv_iosf_sb_put(display->drm, BIT(VLV_IOSF_SB_BUNIT)); + intel_parent_vlv_iosf_put(display, BIT(VLV_IOSF_SB_BUNIT)); } void vlv_cck_get(struct intel_display *display) { - vlv_iosf_sb_get(display->drm, BIT(VLV_IOSF_SB_CCK)); + intel_parent_vlv_iosf_get(display, BIT(VLV_IOSF_SB_CCK)); } u32 vlv_cck_read(struct intel_display *display, u32 reg) { - return vlv_iosf_sb_read(display->drm, VLV_IOSF_SB_CCK, reg); + return intel_parent_vlv_iosf_read(display, VLV_IOSF_SB_CCK, reg); } void vlv_cck_write(struct intel_display *display, u32 reg, u32 val) { - vlv_iosf_sb_write(display->drm, VLV_IOSF_SB_CCK, reg, val); + intel_parent_vlv_iosf_write(display, VLV_IOSF_SB_CCK, reg, val); } void vlv_cck_put(struct intel_display *display) { - vlv_iosf_sb_put(display->drm, BIT(VLV_IOSF_SB_CCK)); + intel_parent_vlv_iosf_put(display, BIT(VLV_IOSF_SB_CCK)); } void vlv_ccu_get(struct intel_display *display) { - vlv_iosf_sb_get(display->drm, BIT(VLV_IOSF_SB_CCU)); + intel_parent_vlv_iosf_get(display, BIT(VLV_IOSF_SB_CCU)); } u32 vlv_ccu_read(struct intel_display *display, u32 reg) { - return vlv_iosf_sb_read(display->drm, VLV_IOSF_SB_CCU, reg); + return intel_parent_vlv_iosf_read(display, VLV_IOSF_SB_CCU, reg); } void vlv_ccu_write(struct intel_display *display, u32 reg, u32 val) { - vlv_iosf_sb_write(display->drm, VLV_IOSF_SB_CCU, reg, val); + intel_parent_vlv_iosf_write(display, VLV_IOSF_SB_CCU, reg, val); } void vlv_ccu_put(struct intel_display *display) { - vlv_iosf_sb_put(display->drm, BIT(VLV_IOSF_SB_CCU)); + intel_parent_vlv_iosf_put(display, BIT(VLV_IOSF_SB_CCU)); } void vlv_dpio_get(struct intel_display *display) { - vlv_iosf_sb_get(display->drm, BIT(VLV_IOSF_SB_DPIO) | BIT(VLV_IOSF_SB_DPIO_2)); + intel_parent_vlv_iosf_get(display, BIT(VLV_IOSF_SB_DPIO) | BIT(VLV_IOSF_SB_DPIO_2)); } static enum vlv_iosf_sb_unit vlv_dpio_phy_to_unit(struct intel_display *display, @@ -91,7 +92,7 @@ u32 vlv_dpio_read(struct intel_display *display, enum dpio_phy phy, int reg) enum vlv_iosf_sb_unit unit = vlv_dpio_phy_to_unit(display, phy); u32 val; - val = vlv_iosf_sb_read(display->drm, unit, reg); + val = intel_parent_vlv_iosf_read(display, unit, reg); /* * FIXME: There might be some registers where all 1's is a valid value, @@ -109,65 +110,65 @@ void vlv_dpio_write(struct intel_display *display, { enum vlv_iosf_sb_unit unit = vlv_dpio_phy_to_unit(display, phy); - vlv_iosf_sb_write(display->drm, unit, reg, val); + intel_parent_vlv_iosf_write(display, unit, reg, val); } void vlv_dpio_put(struct intel_display *display) { - vlv_iosf_sb_put(display->drm, BIT(VLV_IOSF_SB_DPIO) | BIT(VLV_IOSF_SB_DPIO_2)); + intel_parent_vlv_iosf_put(display, BIT(VLV_IOSF_SB_DPIO) | BIT(VLV_IOSF_SB_DPIO_2)); } void vlv_flisdsi_get(struct intel_display *display) { - vlv_iosf_sb_get(display->drm, BIT(VLV_IOSF_SB_FLISDSI)); + intel_parent_vlv_iosf_get(display, BIT(VLV_IOSF_SB_FLISDSI)); } u32 vlv_flisdsi_read(struct intel_display *display, u32 reg) { - return vlv_iosf_sb_read(display->drm, VLV_IOSF_SB_FLISDSI, reg); + return intel_parent_vlv_iosf_read(display, VLV_IOSF_SB_FLISDSI, reg); } void vlv_flisdsi_write(struct intel_display *display, u32 reg, u32 val) { - vlv_iosf_sb_write(display->drm, VLV_IOSF_SB_FLISDSI, reg, val); + intel_parent_vlv_iosf_write(display, VLV_IOSF_SB_FLISDSI, reg, val); } void vlv_flisdsi_put(struct intel_display *display) { - vlv_iosf_sb_put(display->drm, BIT(VLV_IOSF_SB_FLISDSI)); + intel_parent_vlv_iosf_put(display, BIT(VLV_IOSF_SB_FLISDSI)); } void vlv_nc_get(struct intel_display *display) { - vlv_iosf_sb_get(display->drm, BIT(VLV_IOSF_SB_NC)); + intel_parent_vlv_iosf_get(display, BIT(VLV_IOSF_SB_NC)); } u32 vlv_nc_read(struct intel_display *display, u8 addr) { - return vlv_iosf_sb_read(display->drm, VLV_IOSF_SB_NC, addr); + return intel_parent_vlv_iosf_read(display, VLV_IOSF_SB_NC, addr); } void vlv_nc_put(struct intel_display *display) { - vlv_iosf_sb_put(display->drm, BIT(VLV_IOSF_SB_NC)); + intel_parent_vlv_iosf_put(display, BIT(VLV_IOSF_SB_NC)); } void vlv_punit_get(struct intel_display *display) { - vlv_iosf_sb_get(display->drm, BIT(VLV_IOSF_SB_PUNIT)); + intel_parent_vlv_iosf_get(display, BIT(VLV_IOSF_SB_PUNIT)); } u32 vlv_punit_read(struct intel_display *display, u32 addr) { - return vlv_iosf_sb_read(display->drm, VLV_IOSF_SB_PUNIT, addr); + return intel_parent_vlv_iosf_read(display, VLV_IOSF_SB_PUNIT, addr); } int vlv_punit_write(struct intel_display *display, u32 addr, u32 val) { - return vlv_iosf_sb_write(display->drm, VLV_IOSF_SB_PUNIT, addr, val); + return intel_parent_vlv_iosf_write(display, VLV_IOSF_SB_PUNIT, addr, val); } void vlv_punit_put(struct intel_display *display) { - vlv_iosf_sb_put(display->drm, BIT(VLV_IOSF_SB_PUNIT)); + intel_parent_vlv_iosf_put(display, BIT(VLV_IOSF_SB_PUNIT)); } diff --git a/drivers/gpu/drm/i915/i915_driver.c b/drivers/gpu/drm/i915/i915_driver.c index 385a634c3ed0..c10cab38935a 100644 --- a/drivers/gpu/drm/i915/i915_driver.c +++ b/drivers/gpu/drm/i915/i915_driver.c @@ -780,6 +780,7 @@ static const struct intel_display_parent_interface parent = { .rpm = &i915_display_rpm_interface, .rps = &i915_display_rps_interface, .stolen = &i915_display_stolen_interface, + .vlv_iosf = &i915_display_vlv_iosf_interface, .vma = &i915_display_vma_interface, .fence_priority_display = fence_priority_display, diff --git a/drivers/gpu/drm/i915/vlv_iosf_sb.c b/drivers/gpu/drm/i915/vlv_iosf_sb.c index 38a75651b0dc..1f0332b4ad0d 100644 --- a/drivers/gpu/drm/i915/vlv_iosf_sb.c +++ b/drivers/gpu/drm/i915/vlv_iosf_sb.c @@ -4,6 +4,7 @@ */ #include +#include #include "i915_drv.h" #include "i915_iosf_mbi.h" @@ -229,3 +230,10 @@ void vlv_iosf_sb_fini(struct drm_i915_private *i915) if (IS_VALLEYVIEW(i915) || IS_CHERRYVIEW(i915)) mutex_destroy(&i915->vlv_iosf_sb.lock); } + +const struct intel_display_vlv_iosf_interface i915_display_vlv_iosf_interface = { + .get = vlv_iosf_sb_get, + .put = vlv_iosf_sb_put, + .read = vlv_iosf_sb_read, + .write = vlv_iosf_sb_write, +}; diff --git a/drivers/gpu/drm/i915/vlv_iosf_sb.h b/drivers/gpu/drm/i915/vlv_iosf_sb.h index e2fea29a30ea..e4002d5b5a2e 100644 --- a/drivers/gpu/drm/i915/vlv_iosf_sb.h +++ b/drivers/gpu/drm/i915/vlv_iosf_sb.h @@ -34,4 +34,6 @@ void vlv_iosf_sb_put(struct drm_device *drm, unsigned long unit_mask); u32 vlv_iosf_sb_read(struct drm_device *drm, enum vlv_iosf_sb_unit unit, u32 addr); int vlv_iosf_sb_write(struct drm_device *drm, enum vlv_iosf_sb_unit unit, u32 addr, u32 val); +extern const struct intel_display_vlv_iosf_interface i915_display_vlv_iosf_interface; + #endif /* _VLV_IOSF_SB_H_ */ diff --git a/include/drm/intel/display_parent_interface.h b/include/drm/intel/display_parent_interface.h index 97ec94a2e749..c0d18d5577f3 100644 --- a/include/drm/intel/display_parent_interface.h +++ b/include/drm/intel/display_parent_interface.h @@ -6,6 +6,7 @@ #include +enum vlv_iosf_sb_unit; struct dma_fence; struct drm_crtc; struct drm_device; @@ -176,6 +177,13 @@ struct intel_display_stolen_interface { void (*node_free)(const struct intel_stolen_node *node); }; +struct intel_display_vlv_iosf_interface { + void (*get)(struct drm_device *drm, unsigned long unit_mask); + void (*put)(struct drm_device *drm, unsigned long unit_mask); + u32 (*read)(struct drm_device *drm, enum vlv_iosf_sb_unit unit, u32 addr); + int (*write)(struct drm_device *drm, enum vlv_iosf_sb_unit unit, u32 addr, u32 val); +}; + struct intel_display_vma_interface { int (*fence_id)(const struct i915_vma *vma); }; @@ -235,6 +243,9 @@ struct intel_display_parent_interface { /** @stolen: Stolen memory. */ const struct intel_display_stolen_interface *stolen; + /** @vlv_iosf: VLV IOSF sideband. Optional. */ + const struct intel_display_vlv_iosf_interface *vlv_iosf; + /** @vma: VMA interface. Optional. */ const struct intel_display_vma_interface *vma; -- cgit v1.2.3 From 2c0c1e9a6663c1c62d53a92592ec60ae169a8ee9 Mon Sep 17 00:00:00 2001 From: Jani Nikula Date: Tue, 31 Mar 2026 14:40:58 +0300 Subject: drm/{i915, xe}: add shared header for VLV IOSF sideband units and registers MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Move vlv_iosf_sb_reg.h to include/drm/intel/vlv_iosf_sb_regs.h. Use _regs.h suffix to align better with other register headers. Move enum vlv_iosf_sb_unit there as well, breaking the final include tie related to IOSF sideband between display and i915 core. With this, we can completely remove the xe compat vls_iosf_sb*.h headers. Reviewed-by: Ville Syrjälä Link: https://patch.msgid.link/41b060b0d6453de39ca775eab10ee12b25c45b7d.1774957233.git.jani.nikula@intel.com Signed-off-by: Jani Nikula --- .../gpu/drm/i915/display/intel_display_power_map.c | 2 +- .../drm/i915/display/intel_display_power_well.c | 1 - drivers/gpu/drm/i915/display/intel_parent.c | 2 +- drivers/gpu/drm/i915/display/vlv_sideband.h | 3 +- drivers/gpu/drm/i915/vlv_iosf_sb.h | 14 +- drivers/gpu/drm/i915/vlv_iosf_sb_reg.h | 180 ------------------- .../gpu/drm/xe/compat-i915-headers/vlv_iosf_sb.h | 42 ----- .../drm/xe/compat-i915-headers/vlv_iosf_sb_reg.h | 6 - include/drm/intel/vlv_iosf_sb_regs.h | 192 +++++++++++++++++++++ 9 files changed, 196 insertions(+), 246 deletions(-) delete mode 100644 drivers/gpu/drm/i915/vlv_iosf_sb_reg.h delete mode 100644 drivers/gpu/drm/xe/compat-i915-headers/vlv_iosf_sb.h delete mode 100644 drivers/gpu/drm/xe/compat-i915-headers/vlv_iosf_sb_reg.h create mode 100644 include/drm/intel/vlv_iosf_sb_regs.h diff --git a/drivers/gpu/drm/i915/display/intel_display_power_map.c b/drivers/gpu/drm/i915/display/intel_display_power_map.c index 65204d68a759..3400080d78d2 100644 --- a/drivers/gpu/drm/i915/display/intel_display_power_map.c +++ b/drivers/gpu/drm/i915/display/intel_display_power_map.c @@ -4,13 +4,13 @@ */ #include +#include #include "intel_display_core.h" #include "intel_display_power_map.h" #include "intel_display_power_well.h" #include "intel_display_regs.h" #include "intel_display_types.h" -#include "vlv_iosf_sb_reg.h" #define __LIST_INLINE_ELEMS(__elem_type, ...) \ ((__elem_type[]) { __VA_ARGS__ }) diff --git a/drivers/gpu/drm/i915/display/intel_display_power_well.c b/drivers/gpu/drm/i915/display/intel_display_power_well.c index f96a5088d138..6fbfd46461b0 100644 --- a/drivers/gpu/drm/i915/display/intel_display_power_well.c +++ b/drivers/gpu/drm/i915/display/intel_display_power_well.c @@ -34,7 +34,6 @@ #include "intel_vga.h" #include "skl_watermark.h" #include "vlv_dpio_phy_regs.h" -#include "vlv_iosf_sb_reg.h" #include "vlv_sideband.h" /* diff --git a/drivers/gpu/drm/i915/display/intel_parent.c b/drivers/gpu/drm/i915/display/intel_parent.c index 4e01423a0392..47ce3b6fdd5b 100644 --- a/drivers/gpu/drm/i915/display/intel_parent.c +++ b/drivers/gpu/drm/i915/display/intel_parent.c @@ -19,10 +19,10 @@ #include #include +#include #include "intel_display_core.h" #include "intel_parent.h" -#include "vlv_iosf_sb.h" /* dpt */ struct intel_dpt *intel_parent_dpt_create(struct intel_display *display, diff --git a/drivers/gpu/drm/i915/display/vlv_sideband.h b/drivers/gpu/drm/i915/display/vlv_sideband.h index 8751a070b0ae..60a66abc1649 100644 --- a/drivers/gpu/drm/i915/display/vlv_sideband.h +++ b/drivers/gpu/drm/i915/display/vlv_sideband.h @@ -6,8 +6,7 @@ #include -#include "vlv_iosf_sb.h" -#include "vlv_iosf_sb_reg.h" +#include enum dpio_phy; struct intel_display; diff --git a/drivers/gpu/drm/i915/vlv_iosf_sb.h b/drivers/gpu/drm/i915/vlv_iosf_sb.h index e4002d5b5a2e..8129ba11c750 100644 --- a/drivers/gpu/drm/i915/vlv_iosf_sb.h +++ b/drivers/gpu/drm/i915/vlv_iosf_sb.h @@ -8,23 +8,11 @@ #include -#include "vlv_iosf_sb_reg.h" +#include struct drm_device; struct drm_i915_private; -enum vlv_iosf_sb_unit { - VLV_IOSF_SB_BUNIT, - VLV_IOSF_SB_CCK, - VLV_IOSF_SB_CCU, - VLV_IOSF_SB_DPIO, - VLV_IOSF_SB_DPIO_2, - VLV_IOSF_SB_FLISDSI, - VLV_IOSF_SB_GPIO, - VLV_IOSF_SB_NC, - VLV_IOSF_SB_PUNIT, -}; - void vlv_iosf_sb_init(struct drm_i915_private *i915); void vlv_iosf_sb_fini(struct drm_i915_private *i915); diff --git a/drivers/gpu/drm/i915/vlv_iosf_sb_reg.h b/drivers/gpu/drm/i915/vlv_iosf_sb_reg.h deleted file mode 100644 index f977fb3b6e17..000000000000 --- a/drivers/gpu/drm/i915/vlv_iosf_sb_reg.h +++ /dev/null @@ -1,180 +0,0 @@ -/* SPDX-License-Identifier: MIT */ -/* - * Copyright © 2022 Intel Corporation - */ - -#ifndef _VLV_IOSF_SB_REG_H_ -#define _VLV_IOSF_SB_REG_H_ - -/* See configdb bunit SB addr map */ -#define BUNIT_REG_BISOC 0x11 - -/* PUNIT_REG_*SSPM0 */ -#define _SSPM0_SSC(val) ((val) << 0) -#define SSPM0_SSC_MASK _SSPM0_SSC(0x3) -#define SSPM0_SSC_PWR_ON _SSPM0_SSC(0x0) -#define SSPM0_SSC_CLK_GATE _SSPM0_SSC(0x1) -#define SSPM0_SSC_RESET _SSPM0_SSC(0x2) -#define SSPM0_SSC_PWR_GATE _SSPM0_SSC(0x3) -#define _SSPM0_SSS(val) ((val) << 24) -#define SSPM0_SSS_MASK _SSPM0_SSS(0x3) -#define SSPM0_SSS_PWR_ON _SSPM0_SSS(0x0) -#define SSPM0_SSS_CLK_GATE _SSPM0_SSS(0x1) -#define SSPM0_SSS_RESET _SSPM0_SSS(0x2) -#define SSPM0_SSS_PWR_GATE _SSPM0_SSS(0x3) - -/* PUNIT_REG_*SSPM1 */ -#define SSPM1_FREQSTAT_SHIFT 24 -#define SSPM1_FREQSTAT_MASK (0x1f << SSPM1_FREQSTAT_SHIFT) -#define SSPM1_FREQGUAR_SHIFT 8 -#define SSPM1_FREQGUAR_MASK (0x1f << SSPM1_FREQGUAR_SHIFT) -#define SSPM1_FREQ_SHIFT 0 -#define SSPM1_FREQ_MASK (0x1f << SSPM1_FREQ_SHIFT) - -#define PUNIT_REG_VEDSSPM0 0x32 -#define PUNIT_REG_VEDSSPM1 0x33 - -#define PUNIT_REG_DSPSSPM 0x36 -#define DSPFREQSTAT_SHIFT_CHV 24 -#define DSPFREQSTAT_MASK_CHV (0x1f << DSPFREQSTAT_SHIFT_CHV) -#define DSPFREQGUAR_SHIFT_CHV 8 -#define DSPFREQGUAR_MASK_CHV (0x1f << DSPFREQGUAR_SHIFT_CHV) -#define DSPFREQSTAT_SHIFT 30 -#define DSPFREQSTAT_MASK (0x3 << DSPFREQSTAT_SHIFT) -#define DSPFREQGUAR_SHIFT 14 -#define DSPFREQGUAR_MASK (0x3 << DSPFREQGUAR_SHIFT) -#define DSP_MAXFIFO_PM5_STATUS (1 << 22) /* chv */ -#define DSP_AUTO_CDCLK_GATE_DISABLE (1 << 7) /* chv */ -#define DSP_MAXFIFO_PM5_ENABLE (1 << 6) /* chv */ -#define _DP_SSC(val, pipe) ((val) << (2 * (pipe))) -#define DP_SSC_MASK(pipe) _DP_SSC(0x3, (pipe)) -#define DP_SSC_PWR_ON(pipe) _DP_SSC(0x0, (pipe)) -#define DP_SSC_CLK_GATE(pipe) _DP_SSC(0x1, (pipe)) -#define DP_SSC_RESET(pipe) _DP_SSC(0x2, (pipe)) -#define DP_SSC_PWR_GATE(pipe) _DP_SSC(0x3, (pipe)) -#define _DP_SSS(val, pipe) ((val) << (2 * (pipe) + 16)) -#define DP_SSS_MASK(pipe) _DP_SSS(0x3, (pipe)) -#define DP_SSS_PWR_ON(pipe) _DP_SSS(0x0, (pipe)) -#define DP_SSS_CLK_GATE(pipe) _DP_SSS(0x1, (pipe)) -#define DP_SSS_RESET(pipe) _DP_SSS(0x2, (pipe)) -#define DP_SSS_PWR_GATE(pipe) _DP_SSS(0x3, (pipe)) - -#define PUNIT_REG_ISPSSPM0 0x39 -#define PUNIT_REG_ISPSSPM1 0x3a - -#define PUNIT_REG_PWRGT_CTRL 0x60 -#define PUNIT_REG_PWRGT_STATUS 0x61 -#define PUNIT_PWRGT_MASK(pw_idx) (3 << ((pw_idx) * 2)) -#define PUNIT_PWRGT_PWR_ON(pw_idx) (0 << ((pw_idx) * 2)) -#define PUNIT_PWRGT_CLK_GATE(pw_idx) (1 << ((pw_idx) * 2)) -#define PUNIT_PWRGT_RESET(pw_idx) (2 << ((pw_idx) * 2)) -#define PUNIT_PWRGT_PWR_GATE(pw_idx) (3 << ((pw_idx) * 2)) - -#define PUNIT_PWGT_IDX_RENDER 0 -#define PUNIT_PWGT_IDX_MEDIA 1 -#define PUNIT_PWGT_IDX_DISP2D 3 -#define PUNIT_PWGT_IDX_DPIO_CMN_BC 5 -#define PUNIT_PWGT_IDX_DPIO_TX_B_LANES_01 6 -#define PUNIT_PWGT_IDX_DPIO_TX_B_LANES_23 7 -#define PUNIT_PWGT_IDX_DPIO_TX_C_LANES_01 8 -#define PUNIT_PWGT_IDX_DPIO_TX_C_LANES_23 9 -#define PUNIT_PWGT_IDX_DPIO_RX0 10 -#define PUNIT_PWGT_IDX_DPIO_RX1 11 -#define PUNIT_PWGT_IDX_DPIO_CMN_D 12 - -#define PUNIT_REG_GPU_LFM 0xd3 -#define PUNIT_REG_GPU_FREQ_REQ 0xd4 -#define PUNIT_REG_GPU_FREQ_STS 0xd8 -#define GPLLENABLE (1 << 4) -#define GENFREQSTATUS (1 << 0) -#define PUNIT_REG_MEDIA_TURBO_FREQ_REQ 0xdc -#define PUNIT_REG_CZ_TIMESTAMP 0xce - -#define PUNIT_FUSE_BUS2 0xf6 /* bits 47:40 */ -#define PUNIT_FUSE_BUS1 0xf5 /* bits 55:48 */ - -#define FB_GFX_FMAX_AT_VMAX_FUSE 0x136 -#define FB_GFX_FREQ_FUSE_MASK 0xff -#define FB_GFX_FMAX_AT_VMAX_2SS4EU_FUSE_SHIFT 24 -#define FB_GFX_FMAX_AT_VMAX_2SS6EU_FUSE_SHIFT 16 -#define FB_GFX_FMAX_AT_VMAX_2SS8EU_FUSE_SHIFT 8 - -#define FB_GFX_FMIN_AT_VMIN_FUSE 0x137 -#define FB_GFX_FMIN_AT_VMIN_FUSE_SHIFT 8 - -#define PUNIT_REG_DDR_SETUP2 0x139 -#define FORCE_DDR_FREQ_REQ_ACK (1 << 8) -#define FORCE_DDR_LOW_FREQ (1 << 1) -#define FORCE_DDR_HIGH_FREQ (1 << 0) - -#define PUNIT_GPU_STATUS_REG 0xdb -#define PUNIT_GPU_STATUS_MAX_FREQ_SHIFT 16 -#define PUNIT_GPU_STATUS_MAX_FREQ_MASK 0xff -#define PUNIT_GPU_STATIS_GFX_MIN_FREQ_SHIFT 8 -#define PUNIT_GPU_STATUS_GFX_MIN_FREQ_MASK 0xff - -#define PUNIT_GPU_DUTYCYCLE_REG 0xdf -#define PUNIT_GPU_DUTYCYCLE_RPE_FREQ_SHIFT 8 -#define PUNIT_GPU_DUTYCYCLE_RPE_FREQ_MASK 0xff - -#define IOSF_NC_FB_GFX_FREQ_FUSE 0x1c -#define FB_GFX_MAX_FREQ_FUSE_SHIFT 3 -#define FB_GFX_MAX_FREQ_FUSE_MASK 0x000007f8 -#define FB_GFX_FGUARANTEED_FREQ_FUSE_SHIFT 11 -#define FB_GFX_FGUARANTEED_FREQ_FUSE_MASK 0x0007f800 -#define IOSF_NC_FB_GFX_FMAX_FUSE_HI 0x34 -#define FB_FMAX_VMIN_FREQ_HI_MASK 0x00000007 -#define IOSF_NC_FB_GFX_FMAX_FUSE_LO 0x30 -#define FB_FMAX_VMIN_FREQ_LO_SHIFT 27 -#define FB_FMAX_VMIN_FREQ_LO_MASK 0xf8000000 - -#define VLV_TURBO_SOC_OVERRIDE 0x04 -#define VLV_OVERRIDE_EN 1 -#define VLV_SOC_TDP_EN (1 << 1) -#define VLV_BIAS_CPU_125_SOC_875 (6 << 2) -#define CHV_BIAS_CPU_50_SOC_50 (3 << 2) - -/* vlv2 north clock has */ -#define CCK_FUSE_REG 0x8 -#define CCK_FUSE_HPLL_FREQ_MASK 0x3 -#define CCK_REG_DSI_PLL_FUSE 0x44 -#define CCK_REG_DSI_PLL_CONTROL 0x48 -#define DSI_PLL_VCO_EN (1 << 31) -#define DSI_PLL_LDO_GATE (1 << 30) -#define DSI_PLL_P1_POST_DIV_SHIFT 17 -#define DSI_PLL_P1_POST_DIV_MASK (0x1ff << 17) -#define DSI_PLL_P2_MUX_DSI0_DIV2 (1 << 13) -#define DSI_PLL_P3_MUX_DSI1_DIV2 (1 << 12) -#define DSI_PLL_MUX_MASK (3 << 9) -#define DSI_PLL_MUX_DSI0_DSIPLL (0 << 10) -#define DSI_PLL_MUX_DSI0_CCK (1 << 10) -#define DSI_PLL_MUX_DSI1_DSIPLL (0 << 9) -#define DSI_PLL_MUX_DSI1_CCK (1 << 9) -#define DSI_PLL_CLK_GATE_MASK (0xf << 5) -#define DSI_PLL_CLK_GATE_DSI0_DSIPLL (1 << 8) -#define DSI_PLL_CLK_GATE_DSI1_DSIPLL (1 << 7) -#define DSI_PLL_CLK_GATE_DSI0_CCK (1 << 6) -#define DSI_PLL_CLK_GATE_DSI1_CCK (1 << 5) -#define DSI_PLL_LOCK (1 << 0) -#define CCK_REG_DSI_PLL_DIVIDER 0x4c -#define DSI_PLL_LFSR (1 << 31) -#define DSI_PLL_FRACTION_EN (1 << 30) -#define DSI_PLL_FRAC_COUNTER_SHIFT 27 -#define DSI_PLL_FRAC_COUNTER_MASK (7 << 27) -#define DSI_PLL_USYNC_CNT_SHIFT 18 -#define DSI_PLL_USYNC_CNT_MASK (0x1ff << 18) -#define DSI_PLL_N1_DIV_SHIFT 16 -#define DSI_PLL_N1_DIV_MASK (3 << 16) -#define DSI_PLL_M1_DIV_SHIFT 0 -#define DSI_PLL_M1_DIV_MASK (0x1ff << 0) -#define CCK_CZ_CLOCK_CONTROL 0x62 -#define CCK_GPLL_CLOCK_CONTROL 0x67 -#define CCK_DISPLAY_CLOCK_CONTROL 0x6b -#define CCK_DISPLAY_REF_CLOCK_CONTROL 0x6c -#define CCK_TRUNK_FORCE_ON (1 << 17) -#define CCK_TRUNK_FORCE_OFF (1 << 16) -#define CCK_FREQUENCY_STATUS (0x1f << 8) -#define CCK_FREQUENCY_STATUS_SHIFT 8 -#define CCK_FREQUENCY_VALUES (0x1f << 0) - -#endif /* _VLV_IOSF_SB_REG_H_ */ diff --git a/drivers/gpu/drm/xe/compat-i915-headers/vlv_iosf_sb.h b/drivers/gpu/drm/xe/compat-i915-headers/vlv_iosf_sb.h deleted file mode 100644 index 69e1935e9cdf..000000000000 --- a/drivers/gpu/drm/xe/compat-i915-headers/vlv_iosf_sb.h +++ /dev/null @@ -1,42 +0,0 @@ -/* SPDX-License-Identifier: MIT */ -/* - * Copyright © 2013-2021 Intel Corporation - */ - -#ifndef _VLV_IOSF_SB_H_ -#define _VLV_IOSF_SB_H_ - -#include - -#include "vlv_iosf_sb_reg.h" - -struct drm_device; - -enum vlv_iosf_sb_unit { - VLV_IOSF_SB_BUNIT, - VLV_IOSF_SB_CCK, - VLV_IOSF_SB_CCU, - VLV_IOSF_SB_DPIO, - VLV_IOSF_SB_DPIO_2, - VLV_IOSF_SB_FLISDSI, - VLV_IOSF_SB_GPIO, - VLV_IOSF_SB_NC, - VLV_IOSF_SB_PUNIT, -}; - -static inline void vlv_iosf_sb_get(struct drm_device *drm, unsigned long ports) -{ -} -static inline u32 vlv_iosf_sb_read(struct drm_device *drm, enum vlv_iosf_sb_unit unit, u32 addr) -{ - return 0; -} -static inline int vlv_iosf_sb_write(struct drm_device *drm, enum vlv_iosf_sb_unit unit, u32 addr, u32 val) -{ - return 0; -} -static inline void vlv_iosf_sb_put(struct drm_device *drm, unsigned long ports) -{ -} - -#endif /* _VLV_IOSF_SB_H_ */ diff --git a/drivers/gpu/drm/xe/compat-i915-headers/vlv_iosf_sb_reg.h b/drivers/gpu/drm/xe/compat-i915-headers/vlv_iosf_sb_reg.h deleted file mode 100644 index cb7fa8e794a6..000000000000 --- a/drivers/gpu/drm/xe/compat-i915-headers/vlv_iosf_sb_reg.h +++ /dev/null @@ -1,6 +0,0 @@ -/* SPDX-License-Identifier: MIT */ -/* - * Copyright © 2023 Intel Corporation - */ - -#include "../../i915/vlv_iosf_sb_reg.h" diff --git a/include/drm/intel/vlv_iosf_sb_regs.h b/include/drm/intel/vlv_iosf_sb_regs.h new file mode 100644 index 000000000000..42d1def5534b --- /dev/null +++ b/include/drm/intel/vlv_iosf_sb_regs.h @@ -0,0 +1,192 @@ +/* SPDX-License-Identifier: MIT */ +/* + * Copyright © 2022 Intel Corporation + */ + +#ifndef _VLV_IOSF_SB_REGS_H_ +#define _VLV_IOSF_SB_REGS_H_ + +enum vlv_iosf_sb_unit { + VLV_IOSF_SB_BUNIT, + VLV_IOSF_SB_CCK, + VLV_IOSF_SB_CCU, + VLV_IOSF_SB_DPIO, + VLV_IOSF_SB_DPIO_2, + VLV_IOSF_SB_FLISDSI, + VLV_IOSF_SB_GPIO, + VLV_IOSF_SB_NC, + VLV_IOSF_SB_PUNIT, +}; + +/* See configdb bunit SB addr map */ +#define BUNIT_REG_BISOC 0x11 + +/* PUNIT_REG_*SSPM0 */ +#define _SSPM0_SSC(val) ((val) << 0) +#define SSPM0_SSC_MASK _SSPM0_SSC(0x3) +#define SSPM0_SSC_PWR_ON _SSPM0_SSC(0x0) +#define SSPM0_SSC_CLK_GATE _SSPM0_SSC(0x1) +#define SSPM0_SSC_RESET _SSPM0_SSC(0x2) +#define SSPM0_SSC_PWR_GATE _SSPM0_SSC(0x3) +#define _SSPM0_SSS(val) ((val) << 24) +#define SSPM0_SSS_MASK _SSPM0_SSS(0x3) +#define SSPM0_SSS_PWR_ON _SSPM0_SSS(0x0) +#define SSPM0_SSS_CLK_GATE _SSPM0_SSS(0x1) +#define SSPM0_SSS_RESET _SSPM0_SSS(0x2) +#define SSPM0_SSS_PWR_GATE _SSPM0_SSS(0x3) + +/* PUNIT_REG_*SSPM1 */ +#define SSPM1_FREQSTAT_SHIFT 24 +#define SSPM1_FREQSTAT_MASK (0x1f << SSPM1_FREQSTAT_SHIFT) +#define SSPM1_FREQGUAR_SHIFT 8 +#define SSPM1_FREQGUAR_MASK (0x1f << SSPM1_FREQGUAR_SHIFT) +#define SSPM1_FREQ_SHIFT 0 +#define SSPM1_FREQ_MASK (0x1f << SSPM1_FREQ_SHIFT) + +#define PUNIT_REG_VEDSSPM0 0x32 +#define PUNIT_REG_VEDSSPM1 0x33 + +#define PUNIT_REG_DSPSSPM 0x36 +#define DSPFREQSTAT_SHIFT_CHV 24 +#define DSPFREQSTAT_MASK_CHV (0x1f << DSPFREQSTAT_SHIFT_CHV) +#define DSPFREQGUAR_SHIFT_CHV 8 +#define DSPFREQGUAR_MASK_CHV (0x1f << DSPFREQGUAR_SHIFT_CHV) +#define DSPFREQSTAT_SHIFT 30 +#define DSPFREQSTAT_MASK (0x3 << DSPFREQSTAT_SHIFT) +#define DSPFREQGUAR_SHIFT 14 +#define DSPFREQGUAR_MASK (0x3 << DSPFREQGUAR_SHIFT) +#define DSP_MAXFIFO_PM5_STATUS (1 << 22) /* chv */ +#define DSP_AUTO_CDCLK_GATE_DISABLE (1 << 7) /* chv */ +#define DSP_MAXFIFO_PM5_ENABLE (1 << 6) /* chv */ +#define _DP_SSC(val, pipe) ((val) << (2 * (pipe))) +#define DP_SSC_MASK(pipe) _DP_SSC(0x3, (pipe)) +#define DP_SSC_PWR_ON(pipe) _DP_SSC(0x0, (pipe)) +#define DP_SSC_CLK_GATE(pipe) _DP_SSC(0x1, (pipe)) +#define DP_SSC_RESET(pipe) _DP_SSC(0x2, (pipe)) +#define DP_SSC_PWR_GATE(pipe) _DP_SSC(0x3, (pipe)) +#define _DP_SSS(val, pipe) ((val) << (2 * (pipe) + 16)) +#define DP_SSS_MASK(pipe) _DP_SSS(0x3, (pipe)) +#define DP_SSS_PWR_ON(pipe) _DP_SSS(0x0, (pipe)) +#define DP_SSS_CLK_GATE(pipe) _DP_SSS(0x1, (pipe)) +#define DP_SSS_RESET(pipe) _DP_SSS(0x2, (pipe)) +#define DP_SSS_PWR_GATE(pipe) _DP_SSS(0x3, (pipe)) + +#define PUNIT_REG_ISPSSPM0 0x39 +#define PUNIT_REG_ISPSSPM1 0x3a + +#define PUNIT_REG_PWRGT_CTRL 0x60 +#define PUNIT_REG_PWRGT_STATUS 0x61 +#define PUNIT_PWRGT_MASK(pw_idx) (3 << ((pw_idx) * 2)) +#define PUNIT_PWRGT_PWR_ON(pw_idx) (0 << ((pw_idx) * 2)) +#define PUNIT_PWRGT_CLK_GATE(pw_idx) (1 << ((pw_idx) * 2)) +#define PUNIT_PWRGT_RESET(pw_idx) (2 << ((pw_idx) * 2)) +#define PUNIT_PWRGT_PWR_GATE(pw_idx) (3 << ((pw_idx) * 2)) + +#define PUNIT_PWGT_IDX_RENDER 0 +#define PUNIT_PWGT_IDX_MEDIA 1 +#define PUNIT_PWGT_IDX_DISP2D 3 +#define PUNIT_PWGT_IDX_DPIO_CMN_BC 5 +#define PUNIT_PWGT_IDX_DPIO_TX_B_LANES_01 6 +#define PUNIT_PWGT_IDX_DPIO_TX_B_LANES_23 7 +#define PUNIT_PWGT_IDX_DPIO_TX_C_LANES_01 8 +#define PUNIT_PWGT_IDX_DPIO_TX_C_LANES_23 9 +#define PUNIT_PWGT_IDX_DPIO_RX0 10 +#define PUNIT_PWGT_IDX_DPIO_RX1 11 +#define PUNIT_PWGT_IDX_DPIO_CMN_D 12 + +#define PUNIT_REG_GPU_LFM 0xd3 +#define PUNIT_REG_GPU_FREQ_REQ 0xd4 +#define PUNIT_REG_GPU_FREQ_STS 0xd8 +#define GPLLENABLE (1 << 4) +#define GENFREQSTATUS (1 << 0) +#define PUNIT_REG_MEDIA_TURBO_FREQ_REQ 0xdc +#define PUNIT_REG_CZ_TIMESTAMP 0xce + +#define PUNIT_FUSE_BUS2 0xf6 /* bits 47:40 */ +#define PUNIT_FUSE_BUS1 0xf5 /* bits 55:48 */ + +#define FB_GFX_FMAX_AT_VMAX_FUSE 0x136 +#define FB_GFX_FREQ_FUSE_MASK 0xff +#define FB_GFX_FMAX_AT_VMAX_2SS4EU_FUSE_SHIFT 24 +#define FB_GFX_FMAX_AT_VMAX_2SS6EU_FUSE_SHIFT 16 +#define FB_GFX_FMAX_AT_VMAX_2SS8EU_FUSE_SHIFT 8 + +#define FB_GFX_FMIN_AT_VMIN_FUSE 0x137 +#define FB_GFX_FMIN_AT_VMIN_FUSE_SHIFT 8 + +#define PUNIT_REG_DDR_SETUP2 0x139 +#define FORCE_DDR_FREQ_REQ_ACK (1 << 8) +#define FORCE_DDR_LOW_FREQ (1 << 1) +#define FORCE_DDR_HIGH_FREQ (1 << 0) + +#define PUNIT_GPU_STATUS_REG 0xdb +#define PUNIT_GPU_STATUS_MAX_FREQ_SHIFT 16 +#define PUNIT_GPU_STATUS_MAX_FREQ_MASK 0xff +#define PUNIT_GPU_STATIS_GFX_MIN_FREQ_SHIFT 8 +#define PUNIT_GPU_STATUS_GFX_MIN_FREQ_MASK 0xff + +#define PUNIT_GPU_DUTYCYCLE_REG 0xdf +#define PUNIT_GPU_DUTYCYCLE_RPE_FREQ_SHIFT 8 +#define PUNIT_GPU_DUTYCYCLE_RPE_FREQ_MASK 0xff + +#define IOSF_NC_FB_GFX_FREQ_FUSE 0x1c +#define FB_GFX_MAX_FREQ_FUSE_SHIFT 3 +#define FB_GFX_MAX_FREQ_FUSE_MASK 0x000007f8 +#define FB_GFX_FGUARANTEED_FREQ_FUSE_SHIFT 11 +#define FB_GFX_FGUARANTEED_FREQ_FUSE_MASK 0x0007f800 +#define IOSF_NC_FB_GFX_FMAX_FUSE_HI 0x34 +#define FB_FMAX_VMIN_FREQ_HI_MASK 0x00000007 +#define IOSF_NC_FB_GFX_FMAX_FUSE_LO 0x30 +#define FB_FMAX_VMIN_FREQ_LO_SHIFT 27 +#define FB_FMAX_VMIN_FREQ_LO_MASK 0xf8000000 + +#define VLV_TURBO_SOC_OVERRIDE 0x04 +#define VLV_OVERRIDE_EN 1 +#define VLV_SOC_TDP_EN (1 << 1) +#define VLV_BIAS_CPU_125_SOC_875 (6 << 2) +#define CHV_BIAS_CPU_50_SOC_50 (3 << 2) + +/* vlv2 north clock has */ +#define CCK_FUSE_REG 0x8 +#define CCK_FUSE_HPLL_FREQ_MASK 0x3 +#define CCK_REG_DSI_PLL_FUSE 0x44 +#define CCK_REG_DSI_PLL_CONTROL 0x48 +#define DSI_PLL_VCO_EN (1 << 31) +#define DSI_PLL_LDO_GATE (1 << 30) +#define DSI_PLL_P1_POST_DIV_SHIFT 17 +#define DSI_PLL_P1_POST_DIV_MASK (0x1ff << 17) +#define DSI_PLL_P2_MUX_DSI0_DIV2 (1 << 13) +#define DSI_PLL_P3_MUX_DSI1_DIV2 (1 << 12) +#define DSI_PLL_MUX_MASK (3 << 9) +#define DSI_PLL_MUX_DSI0_DSIPLL (0 << 10) +#define DSI_PLL_MUX_DSI0_CCK (1 << 10) +#define DSI_PLL_MUX_DSI1_DSIPLL (0 << 9) +#define DSI_PLL_MUX_DSI1_CCK (1 << 9) +#define DSI_PLL_CLK_GATE_MASK (0xf << 5) +#define DSI_PLL_CLK_GATE_DSI0_DSIPLL (1 << 8) +#define DSI_PLL_CLK_GATE_DSI1_DSIPLL (1 << 7) +#define DSI_PLL_CLK_GATE_DSI0_CCK (1 << 6) +#define DSI_PLL_CLK_GATE_DSI1_CCK (1 << 5) +#define DSI_PLL_LOCK (1 << 0) +#define CCK_REG_DSI_PLL_DIVIDER 0x4c +#define DSI_PLL_LFSR (1 << 31) +#define DSI_PLL_FRACTION_EN (1 << 30) +#define DSI_PLL_FRAC_COUNTER_SHIFT 27 +#define DSI_PLL_FRAC_COUNTER_MASK (7 << 27) +#define DSI_PLL_USYNC_CNT_SHIFT 18 +#define DSI_PLL_USYNC_CNT_MASK (0x1ff << 18) +#define DSI_PLL_N1_DIV_SHIFT 16 +#define DSI_PLL_N1_DIV_MASK (3 << 16) +#define DSI_PLL_M1_DIV_SHIFT 0 +#define DSI_PLL_M1_DIV_MASK (0x1ff << 0) +#define CCK_CZ_CLOCK_CONTROL 0x62 +#define CCK_GPLL_CLOCK_CONTROL 0x67 +#define CCK_DISPLAY_CLOCK_CONTROL 0x6b +#define CCK_DISPLAY_REF_CLOCK_CONTROL 0x6c +#define CCK_TRUNK_FORCE_ON (1 << 17) +#define CCK_TRUNK_FORCE_OFF (1 << 16) +#define CCK_FREQUENCY_STATUS (0x1f << 8) +#define CCK_FREQUENCY_STATUS_SHIFT 8 +#define CCK_FREQUENCY_VALUES (0x1f << 0) + +#endif /* _VLV_IOSF_SB_REGS_H_ */ -- cgit v1.2.3 From bf64bcf4baab24944be3f6252192abb87af84686 Mon Sep 17 00:00:00 2001 From: Ville Syrjälä Date: Tue, 31 Mar 2026 18:42:48 +0300 Subject: drm/i915/qgv: Use intel_de_read() for MTL_MEM_SS_INFO* reads MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The MTL_MEM_SS_INFO* are just regular display registers. Use intel_de_read() to access them. Reviewed-by: Jani Nikula Signed-off-by: Ville Syrjälä Link: https://patch.msgid.link/20260331154259.24600-2-ville.syrjala@linux.intel.com --- drivers/gpu/drm/i915/display/intel_bw.c | 6 +++--- drivers/gpu/drm/i915/display/intel_dram.c | 4 ++-- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/drivers/gpu/drm/i915/display/intel_bw.c b/drivers/gpu/drm/i915/display/intel_bw.c index 07b4531a4376..18b80147ddc7 100644 --- a/drivers/gpu/drm/i915/display/intel_bw.c +++ b/drivers/gpu/drm/i915/display/intel_bw.c @@ -9,6 +9,7 @@ #include "intel_bw.h" #include "intel_crtc.h" +#include "intel_de.h" #include "intel_display_core.h" #include "intel_display_regs.h" #include "intel_display_types.h" @@ -211,12 +212,11 @@ static int icl_pcode_restrict_qgv_points(struct intel_display *display, static int mtl_read_qgv_point_info(struct intel_display *display, struct intel_qgv_point *sp, int point) { - struct intel_uncore *uncore = to_intel_uncore(display->drm); u32 val, val2; u16 dclk; - val = intel_uncore_read(uncore, MTL_MEM_SS_INFO_QGV_POINT_LOW(point)); - val2 = intel_uncore_read(uncore, MTL_MEM_SS_INFO_QGV_POINT_HIGH(point)); + val = intel_de_read(display, MTL_MEM_SS_INFO_QGV_POINT_LOW(point)); + val2 = intel_de_read(display, MTL_MEM_SS_INFO_QGV_POINT_HIGH(point)); dclk = REG_FIELD_GET(MTL_DCLK_MASK, val); sp->dclk = DIV_ROUND_CLOSEST(16667 * dclk, 1000); sp->t_rp = REG_FIELD_GET(MTL_TRP_MASK, val); diff --git a/drivers/gpu/drm/i915/display/intel_dram.c b/drivers/gpu/drm/i915/display/intel_dram.c index 1686f808a084..d655ed163f13 100644 --- a/drivers/gpu/drm/i915/display/intel_dram.c +++ b/drivers/gpu/drm/i915/display/intel_dram.c @@ -9,6 +9,7 @@ #include #include +#include "intel_de.h" #include "intel_display_core.h" #include "intel_display_utils.h" #include "intel_display_regs.h" @@ -767,8 +768,7 @@ static int gen12_get_dram_info(struct intel_display *display, struct dram_info * static int xelpdp_get_dram_info(struct intel_display *display, struct dram_info *dram_info) { - struct intel_uncore *uncore = to_intel_uncore(display->drm); - u32 val = intel_uncore_read(uncore, MTL_MEM_SS_INFO_GLOBAL); + u32 val = intel_de_read(display, MTL_MEM_SS_INFO_GLOBAL); switch (REG_FIELD_GET(MTL_DDR_TYPE_MASK, val)) { case 0: -- cgit v1.2.3 From 81dbca71885df32b0683104d1f49065d792870e0 Mon Sep 17 00:00:00 2001 From: Ville Syrjälä Date: Tue, 31 Mar 2026 18:42:49 +0300 Subject: drm/i915/mchbar: Provide intel_mchbar_read*() abstraction MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit MCHBAR registers are a bit special in that: - we access them through the mirror - the mirror is read only on HSW+ - the mirror requires the actual MCHBAR to be enabled in device 0:0.0 - the mirror is gone on MTL+ So I'd prefer to treat MCHBAR registers as a bit special in the code as well, and do all accesses to them via dedicated functions. Prodive such functions in the form of intel_mchbar_read*(). v2: Put the function arguments on one line No intel_uncore_read64() on xe, use intel_uncore_read64_2x32() Name the new function intel_mchbar_read64_2x32() as well Reviewed-by: Jani Nikula Signed-off-by: Ville Syrjälä Link: https://patch.msgid.link/20260331154259.24600-3-ville.syrjala@linux.intel.com --- drivers/gpu/drm/i915/Makefile | 1 + drivers/gpu/drm/i915/display/intel_mchbar.c | 30 +++++++++++++++++++++++++++++ drivers/gpu/drm/i915/display/intel_mchbar.h | 19 ++++++++++++++++++ drivers/gpu/drm/xe/Makefile | 1 + 4 files changed, 51 insertions(+) create mode 100644 drivers/gpu/drm/i915/display/intel_mchbar.c create mode 100644 drivers/gpu/drm/i915/display/intel_mchbar.h diff --git a/drivers/gpu/drm/i915/Makefile b/drivers/gpu/drm/i915/Makefile index b677720a1c2d..0e48305df8b2 100644 --- a/drivers/gpu/drm/i915/Makefile +++ b/drivers/gpu/drm/i915/Makefile @@ -295,6 +295,7 @@ i915-y += \ display/intel_link_bw.o \ display/intel_load_detect.o \ display/intel_lpe_audio.o \ + display/intel_mchbar.o \ display/intel_modeset_lock.o \ display/intel_modeset_setup.o \ display/intel_modeset_verify.o \ diff --git a/drivers/gpu/drm/i915/display/intel_mchbar.c b/drivers/gpu/drm/i915/display/intel_mchbar.c new file mode 100644 index 000000000000..2636fe60ef37 --- /dev/null +++ b/drivers/gpu/drm/i915/display/intel_mchbar.c @@ -0,0 +1,30 @@ +// SPDX-License-Identifier: MIT +/* + * Copyright © 2026 Intel Corporation + */ + +#include "intel_display_core.h" +#include "intel_mchbar.h" +#include "intel_uncore.h" + +u16 intel_mchbar_read16(struct intel_display *display, i915_reg_t reg) +{ + struct intel_uncore *uncore = to_intel_uncore(display->drm); + + return intel_uncore_read16(uncore, reg); +} + +u32 intel_mchbar_read(struct intel_display *display, i915_reg_t reg) +{ + struct intel_uncore *uncore = to_intel_uncore(display->drm); + + return intel_uncore_read(uncore, reg); +} + +u64 intel_mchbar_read64_2x32(struct intel_display *display, i915_reg_t reg) +{ + struct intel_uncore *uncore = to_intel_uncore(display->drm); + i915_reg_t upper_reg = _MMIO(i915_mmio_reg_offset(reg) + 4); + + return intel_uncore_read64_2x32(uncore, reg, upper_reg); +} diff --git a/drivers/gpu/drm/i915/display/intel_mchbar.h b/drivers/gpu/drm/i915/display/intel_mchbar.h new file mode 100644 index 000000000000..002a4454e8ed --- /dev/null +++ b/drivers/gpu/drm/i915/display/intel_mchbar.h @@ -0,0 +1,19 @@ +/* SPDX-License-Identifier: MIT */ +/* + * Copyright © 2026 Intel Corporation + */ + +#ifndef __INTEL_MCHBAR_H__ +#define __INTEL_MCHBAR_H__ + +#include + +#include "i915_reg_defs.h" + +struct intel_display; + +u16 intel_mchbar_read16(struct intel_display *display, i915_reg_t reg); +u32 intel_mchbar_read(struct intel_display *display, i915_reg_t reg); +u64 intel_mchbar_read64_2x32(struct intel_display *display, i915_reg_t reg); + +#endif /* __INTEL_MCHBAR_H__ */ diff --git a/drivers/gpu/drm/xe/Makefile b/drivers/gpu/drm/xe/Makefile index 3bbd45ea327a..015ca5412f86 100644 --- a/drivers/gpu/drm/xe/Makefile +++ b/drivers/gpu/drm/xe/Makefile @@ -304,6 +304,7 @@ xe-$(CONFIG_DRM_XE_DISPLAY) += \ i915-display/intel_link_bw.o \ i915-display/intel_lspcon.o \ i915-display/intel_lt_phy.o \ + i915-display/intel_mchbar.o \ i915-display/intel_modeset_lock.o \ i915-display/intel_modeset_setup.o \ i915-display/intel_modeset_verify.o \ -- cgit v1.2.3 From 03f8a13cc18c95bede16d55c08c0dda39f8e23fd Mon Sep 17 00:00:00 2001 From: Ville Syrjälä Date: Tue, 31 Mar 2026 18:42:50 +0300 Subject: drm/i915/mchbar: Define the end of the MCHBAR mirror MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Add defines for the end of the MCHBAR mirror. I'm planning to use this for some range sanity checks. BSpec: 51771 Reviewed-by: Jani Nikula Signed-off-by: Ville Syrjälä Link: https://patch.msgid.link/20260331154259.24600-4-ville.syrjala@linux.intel.com --- drivers/gpu/drm/i915/intel_mchbar_regs.h | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/drivers/gpu/drm/i915/intel_mchbar_regs.h b/drivers/gpu/drm/i915/intel_mchbar_regs.h index 614d4017b57b..ca0d421be16c 100644 --- a/drivers/gpu/drm/i915/intel_mchbar_regs.h +++ b/drivers/gpu/drm/i915/intel_mchbar_regs.h @@ -16,11 +16,16 @@ * every way. It is not accessible from the CP register read instructions. * * Starting from Haswell, you can't write registers using the MCHBAR mirror, - * just read. + * just read. On MTL+ the mirror no longer exists. */ #define MCHBAR_MIRROR_BASE 0x10000 +#define MCHBAR_MIRROR_END 0x13fff + #define MCHBAR_MIRROR_BASE_SNB 0x140000 +#define MCHBAR_MIRROR_END_SNB 0x147fff +#define MCHBAR_MIRROR_END_ICL_RKL 0x14ffff +#define MCHBAR_MIRROR_END_TGL 0x15ffff #define CTG_STOLEN_RESERVED _MMIO(MCHBAR_MIRROR_BASE + 0x34) #define ELK_STOLEN_RESERVED _MMIO(MCHBAR_MIRROR_BASE + 0x48) -- cgit v1.2.3 From 84b0366809193fc6238e37c9839cd4b24db5e909 Mon Sep 17 00:00:00 2001 From: Ville Syrjälä Date: Tue, 31 Mar 2026 18:42:51 +0300 Subject: drm/i915/mchbar: WARN when accessing non-MCHBAR registers via intel_mchbar_read*() MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The intel_mchbar_read*() functions should only be used for accessing MCHBAR registers. Warn if someone tries to use them for other registers. I suppose we could even have a dedicated type for MCHBAR registers. But that is true for many other special register types as well, and so far we haven't bothered adding any special types apart from i915_mcr_reg_t. v2: Print the register offset (Jani) Mention i915_mcr_reg_t (Jani) Reviewed-by: Jani Nikula Signed-off-by: Ville Syrjälä Link: https://patch.msgid.link/20260331154259.24600-5-ville.syrjala@linux.intel.com --- drivers/gpu/drm/i915/display/intel_mchbar.c | 56 +++++++++++++++++++++++++++++ 1 file changed, 56 insertions(+) diff --git a/drivers/gpu/drm/i915/display/intel_mchbar.c b/drivers/gpu/drm/i915/display/intel_mchbar.c index 2636fe60ef37..a404fa38c9bd 100644 --- a/drivers/gpu/drm/i915/display/intel_mchbar.c +++ b/drivers/gpu/drm/i915/display/intel_mchbar.c @@ -3,14 +3,66 @@ * Copyright © 2026 Intel Corporation */ +#include + +#include + #include "intel_display_core.h" #include "intel_mchbar.h" +#include "intel_mchbar_regs.h" #include "intel_uncore.h" +static bool has_mchbar_mirror(struct intel_display *display) +{ + return DISPLAY_VER(display) < 14; +} + +static u32 mchbar_mirror_base(struct intel_display *display) +{ + if (DISPLAY_VER(display) >= 6) + return MCHBAR_MIRROR_BASE_SNB; + else + return MCHBAR_MIRROR_BASE; +} + +static u32 mchbar_mirror_end(struct intel_display *display) +{ + if (DISPLAY_VER(display) >= 12 && !display->platform.rocketlake) + return MCHBAR_MIRROR_END_TGL; + else if (DISPLAY_VER(display) >= 11) + return MCHBAR_MIRROR_END_ICL_RKL; + else if (DISPLAY_VER(display) >= 6) + return MCHBAR_MIRROR_END_SNB; + else + return MCHBAR_MIRROR_END; +} + +static u32 mchbar_mirror_len(struct intel_display *display) +{ + return mchbar_mirror_end(display) - mchbar_mirror_base(display) + 1; +} + +static bool is_mchbar_reg(struct intel_display *display, i915_reg_t reg) +{ + return has_mchbar_mirror(display) && + in_range32(i915_mmio_reg_offset(reg), + mchbar_mirror_base(display), + mchbar_mirror_len(display)); +} + +static void assert_is_mchbar_reg(struct intel_display *display, i915_reg_t reg) +{ + drm_WARN(display->drm, !is_mchbar_reg(display, reg), + "Reading non-MCHBAR register 0x%x\n", + i915_mmio_reg_offset(reg)); +} + u16 intel_mchbar_read16(struct intel_display *display, i915_reg_t reg) { struct intel_uncore *uncore = to_intel_uncore(display->drm); + assert_is_mchbar_reg(display, reg); + return intel_uncore_read16(uncore, reg); } @@ -18,6 +70,8 @@ u32 intel_mchbar_read(struct intel_display *display, i915_reg_t reg) { struct intel_uncore *uncore = to_intel_uncore(display->drm); + assert_is_mchbar_reg(display, reg); + return intel_uncore_read(uncore, reg); } @@ -26,5 +80,7 @@ u64 intel_mchbar_read64_2x32(struct intel_display *display, i915_reg_t reg) struct intel_uncore *uncore = to_intel_uncore(display->drm); i915_reg_t upper_reg = _MMIO(i915_mmio_reg_offset(reg) + 4); + assert_is_mchbar_reg(display, reg); + return intel_uncore_read64_2x32(uncore, reg, upper_reg); } -- cgit v1.2.3 From 1b274a3de2f198d22b367abd0e48cd05887b2abb Mon Sep 17 00:00:00 2001 From: Ville Syrjälä Date: Tue, 31 Mar 2026 18:42:52 +0300 Subject: drm/i915/mchbar: Use intel_mchbar_read() instead of intel_de_read() MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit We are doing a few accesses to MCHBAR registers with intel_de_read(). Use the dedicated intel_mchbar_read() instead. Reviewed-by: Jani Nikula Signed-off-by: Ville Syrjälä Link: https://patch.msgid.link/20260331154259.24600-6-ville.syrjala@linux.intel.com --- drivers/gpu/drm/i915/display/intel_cdclk.c | 5 +++-- drivers/gpu/drm/i915/display/intel_display_power.c | 3 ++- 2 files changed, 5 insertions(+), 3 deletions(-) diff --git a/drivers/gpu/drm/i915/display/intel_cdclk.c b/drivers/gpu/drm/i915/display/intel_cdclk.c index 4a663dddf896..835a332e9686 100644 --- a/drivers/gpu/drm/i915/display/intel_cdclk.c +++ b/drivers/gpu/drm/i915/display/intel_cdclk.c @@ -41,6 +41,7 @@ #include "intel_display_utils.h" #include "intel_display_wa.h" #include "intel_dram.h" +#include "intel_mchbar.h" #include "intel_mchbar_regs.h" #include "intel_parent.h" #include "intel_pci_config.h" @@ -376,8 +377,8 @@ static unsigned int intel_hpll_vco(struct intel_display *display) else return 0; - tmp = intel_de_read(display, display->platform.pineview || - display->platform.mobile ? HPLLVCO_MOBILE : HPLLVCO); + tmp = intel_mchbar_read(display, display->platform.pineview || + display->platform.mobile ? HPLLVCO_MOBILE : HPLLVCO); vco = vco_table[tmp & 0x7]; if (vco == 0) diff --git a/drivers/gpu/drm/i915/display/intel_display_power.c b/drivers/gpu/drm/i915/display/intel_display_power.c index b1c91de9d798..98e5a794fab7 100644 --- a/drivers/gpu/drm/i915/display/intel_display_power.c +++ b/drivers/gpu/drm/i915/display/intel_display_power.c @@ -24,6 +24,7 @@ #include "intel_display_wa.h" #include "intel_dmc.h" #include "intel_dram.h" +#include "intel_mchbar.h" #include "intel_mchbar_regs.h" #include "intel_parent.h" #include "intel_pch_refclk.h" @@ -1252,7 +1253,7 @@ static void assert_can_disable_lcpll(struct intel_display *display) static u32 hsw_read_dcomp(struct intel_display *display) { if (display->platform.haswell) - return intel_de_read(display, D_COMP_HSW); + return intel_mchbar_read(display, D_COMP_HSW); else return intel_de_read(display, D_COMP_BDW); } -- cgit v1.2.3 From a076686acab63a2a632304af277751752e8a28d7 Mon Sep 17 00:00:00 2001 From: Ville Syrjälä Date: Tue, 31 Mar 2026 18:42:53 +0300 Subject: drm/i915/mchbar: Use intel_mchbar_read*() instead of intel_uncore_read*() MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Replace all the naked intel_uncore_read*() accesses to MCHBAR registers with the dedicated intel_mchbar_read*(). v2: Rebase due to the intel_mchbar_read64_2x32() rename Reviewed-by: Jani Nikula Signed-off-by: Ville Syrjälä Link: https://patch.msgid.link/20260331154259.24600-7-ville.syrjala@linux.intel.com --- drivers/gpu/drm/i915/display/i9xx_wm.c | 10 ++++------ drivers/gpu/drm/i915/display/intel_bw.c | 11 +++++------ drivers/gpu/drm/i915/display/intel_dram.c | 29 ++++++++++------------------- 3 files changed, 19 insertions(+), 31 deletions(-) diff --git a/drivers/gpu/drm/i915/display/i9xx_wm.c b/drivers/gpu/drm/i915/display/i9xx_wm.c index c39d56e2ea26..3dbfb850fe1d 100644 --- a/drivers/gpu/drm/i915/display/i9xx_wm.c +++ b/drivers/gpu/drm/i915/display/i9xx_wm.c @@ -19,6 +19,7 @@ #include "intel_display_utils.h" #include "intel_dram.h" #include "intel_fb.h" +#include "intel_mchbar.h" #include "intel_mchbar_regs.h" #include "intel_wm.h" #include "skl_watermark.h" @@ -2742,12 +2743,11 @@ static void ilk_compute_wm_level(struct intel_display *display, static void hsw_read_wm_latency(struct intel_display *display, u16 wm[]) { - struct intel_uncore *uncore = to_intel_uncore(display->drm); u64 sskpd; display->wm.num_levels = 5; - sskpd = intel_uncore_read64(uncore, MCH_SSKPD); + sskpd = intel_mchbar_read64_2x32(display, MCH_SSKPD); wm[0] = REG_FIELD_GET64(SSKPD_NEW_WM0_MASK_HSW, sskpd); if (wm[0] == 0) @@ -2760,12 +2760,11 @@ static void hsw_read_wm_latency(struct intel_display *display, u16 wm[]) static void snb_read_wm_latency(struct intel_display *display, u16 wm[]) { - struct intel_uncore *uncore = to_intel_uncore(display->drm); u32 sskpd; display->wm.num_levels = 4; - sskpd = intel_uncore_read(uncore, MCH_SSKPD); + sskpd = intel_mchbar_read(display, MCH_SSKPD); wm[0] = REG_FIELD_GET(SSKPD_WM0_MASK_SNB, sskpd); wm[1] = REG_FIELD_GET(SSKPD_WM1_MASK_SNB, sskpd); @@ -2775,12 +2774,11 @@ static void snb_read_wm_latency(struct intel_display *display, u16 wm[]) static void ilk_read_wm_latency(struct intel_display *display, u16 wm[]) { - struct intel_uncore *uncore = to_intel_uncore(display->drm); u32 mltr; display->wm.num_levels = 3; - mltr = intel_uncore_read(uncore, MLTR_ILK); + mltr = intel_mchbar_read(display, MLTR_ILK); /* ILK primary LP0 latency is 700 ns */ wm[0] = 7; diff --git a/drivers/gpu/drm/i915/display/intel_bw.c b/drivers/gpu/drm/i915/display/intel_bw.c index 18b80147ddc7..e6c8fd630294 100644 --- a/drivers/gpu/drm/i915/display/intel_bw.c +++ b/drivers/gpu/drm/i915/display/intel_bw.c @@ -15,9 +15,9 @@ #include "intel_display_types.h" #include "intel_display_utils.h" #include "intel_dram.h" +#include "intel_mchbar.h" #include "intel_mchbar_regs.h" #include "intel_parent.h" -#include "intel_uncore.h" #include "skl_watermark.h" struct intel_bw_state { @@ -75,11 +75,10 @@ static int dg1_mchbar_read_qgv_point_info(struct intel_display *display, struct intel_qgv_point *sp, int point) { - struct intel_uncore *uncore = to_intel_uncore(display->drm); u32 dclk_ratio, dclk_reference; u32 val; - val = intel_uncore_read(uncore, SA_PERF_STATUS_0_0_0_MCHBAR_PC); + val = intel_mchbar_read(display, SA_PERF_STATUS_0_0_0_MCHBAR_PC); dclk_ratio = REG_FIELD_GET(DG1_QCLK_RATIO_MASK, val); if (val & DG1_QCLK_REFERENCE) dclk_reference = 6; /* 6 * 16.666 MHz = 100 MHz */ @@ -87,18 +86,18 @@ static int dg1_mchbar_read_qgv_point_info(struct intel_display *display, dclk_reference = 8; /* 8 * 16.666 MHz = 133 MHz */ sp->dclk = DIV_ROUND_UP((16667 * dclk_ratio * dclk_reference) + 500, 1000); - val = intel_uncore_read(uncore, SKL_MC_BIOS_DATA_0_0_0_MCHBAR_PCU); + val = intel_mchbar_read(display, SKL_MC_BIOS_DATA_0_0_0_MCHBAR_PCU); if (val & DG1_GEAR_TYPE) sp->dclk *= 2; if (sp->dclk == 0) return -EINVAL; - val = intel_uncore_read(uncore, MCHBAR_CH0_CR_TC_PRE_0_0_0_MCHBAR); + val = intel_mchbar_read(display, MCHBAR_CH0_CR_TC_PRE_0_0_0_MCHBAR); sp->t_rp = REG_FIELD_GET(DG1_DRAM_T_RP_MASK, val); sp->t_rdpre = REG_FIELD_GET(DG1_DRAM_T_RDPRE_MASK, val); - val = intel_uncore_read(uncore, MCHBAR_CH0_CR_TC_PRE_0_0_0_MCHBAR_HIGH); + val = intel_mchbar_read(display, MCHBAR_CH0_CR_TC_PRE_0_0_0_MCHBAR_HIGH); sp->t_rcd = REG_FIELD_GET(DG1_DRAM_T_RCD_MASK, val); sp->t_ras = REG_FIELD_GET(DG1_DRAM_T_RAS_MASK, val); diff --git a/drivers/gpu/drm/i915/display/intel_dram.c b/drivers/gpu/drm/i915/display/intel_dram.c index d655ed163f13..2079c63e3649 100644 --- a/drivers/gpu/drm/i915/display/intel_dram.c +++ b/drivers/gpu/drm/i915/display/intel_dram.c @@ -14,9 +14,9 @@ #include "intel_display_utils.h" #include "intel_display_regs.h" #include "intel_dram.h" +#include "intel_mchbar.h" #include "intel_mchbar_regs.h" #include "intel_parent.h" -#include "intel_uncore.h" #include "vlv_sideband.h" struct dram_dimm_info { @@ -59,18 +59,15 @@ const char *intel_dram_type_str(enum intel_dram_type type) static enum intel_dram_type pnv_dram_type(struct intel_display *display) { - struct intel_uncore *uncore = to_intel_uncore(display->drm); - - return intel_uncore_read(uncore, CSHRDDR3CTL) & CSHRDDR3CTL_DDR3 ? + return intel_mchbar_read(display, CSHRDDR3CTL) & CSHRDDR3CTL_DDR3 ? INTEL_DRAM_DDR3 : INTEL_DRAM_DDR2; } static unsigned int pnv_mem_freq(struct intel_display *display) { - struct intel_uncore *uncore = to_intel_uncore(display->drm); u32 tmp; - tmp = intel_uncore_read(uncore, CLKCFG); + tmp = intel_mchbar_read(display, CLKCFG); switch (tmp & CLKCFG_MEM_MASK) { case CLKCFG_MEM_533: @@ -86,10 +83,9 @@ static unsigned int pnv_mem_freq(struct intel_display *display) static unsigned int ilk_mem_freq(struct intel_display *display) { - struct intel_uncore *uncore = to_intel_uncore(display->drm); u16 ddrpll; - ddrpll = intel_uncore_read16(uncore, DDRMPLL1); + ddrpll = intel_mchbar_read16(display, DDRMPLL1); switch (ddrpll & 0xff) { case 0xc: return 800000; @@ -159,7 +155,6 @@ unsigned int intel_mem_freq(struct intel_display *display) static unsigned int i9xx_fsb_freq(struct intel_display *display) { - struct intel_uncore *uncore = to_intel_uncore(display->drm); u32 fsb; /* @@ -170,7 +165,7 @@ static unsigned int i9xx_fsb_freq(struct intel_display *display) * don't know which registers have that information, * and all the relevant docs have gone to bit heaven :( */ - fsb = intel_uncore_read(uncore, CLKCFG) & CLKCFG_FSB_MASK; + fsb = intel_mchbar_read(display, CLKCFG) & CLKCFG_FSB_MASK; if (display->platform.pineview || display->platform.mobile) { switch (fsb) { @@ -215,10 +210,9 @@ static unsigned int i9xx_fsb_freq(struct intel_display *display) static unsigned int ilk_fsb_freq(struct intel_display *display) { - struct intel_uncore *uncore = to_intel_uncore(display->drm); u16 fsb; - fsb = intel_uncore_read16(uncore, CSIPLL0) & 0x3ff; + fsb = intel_mchbar_read16(display, CSIPLL0) & 0x3ff; switch (fsb) { case 0x00c: @@ -485,7 +479,6 @@ intel_is_dram_symmetric(const struct dram_channel_info *ch0, static int skl_dram_get_channels_info(struct intel_display *display, struct dram_info *dram_info) { - struct intel_uncore *uncore = to_intel_uncore(display->drm); struct dram_channel_info ch0 = {}, ch1 = {}; u32 val; int ret; @@ -493,12 +486,12 @@ skl_dram_get_channels_info(struct intel_display *display, struct dram_info *dram /* Assume 16Gb+ DIMMs are present until proven otherwise */ dram_info->has_16gb_dimms = true; - val = intel_uncore_read(uncore, SKL_MAD_DIMM_CH0_0_0_0_MCHBAR_MCMAIN); + val = intel_mchbar_read(display, SKL_MAD_DIMM_CH0_0_0_0_MCHBAR_MCMAIN); ret = skl_dram_get_channel_info(display, &ch0, 0, val); if (ret == 0) dram_info->num_channels++; - val = intel_uncore_read(uncore, SKL_MAD_DIMM_CH1_0_0_0_MCHBAR_MCMAIN); + val = intel_mchbar_read(display, SKL_MAD_DIMM_CH1_0_0_0_MCHBAR_MCMAIN); ret = skl_dram_get_channel_info(display, &ch1, 1, val); if (ret == 0) dram_info->num_channels++; @@ -529,10 +522,9 @@ skl_dram_get_channels_info(struct intel_display *display, struct dram_info *dram static enum intel_dram_type skl_get_dram_type(struct intel_display *display) { - struct intel_uncore *uncore = to_intel_uncore(display->drm); u32 val; - val = intel_uncore_read(uncore, SKL_MAD_INTER_CHANNEL_0_0_0_MCHBAR_MCMAIN); + val = intel_mchbar_read(display, SKL_MAD_INTER_CHANNEL_0_0_0_MCHBAR_MCMAIN); switch (val & SKL_DRAM_DDR_TYPE_MASK) { case SKL_DRAM_DDR_TYPE_DDR3: @@ -643,7 +635,6 @@ static void bxt_get_dimm_info(struct dram_dimm_info *dimm, u32 val) static int bxt_get_dram_info(struct intel_display *display, struct dram_info *dram_info) { - struct intel_uncore *uncore = to_intel_uncore(display->drm); u32 val; u8 valid_ranks = 0; int i; @@ -655,7 +646,7 @@ static int bxt_get_dram_info(struct intel_display *display, struct dram_info *dr struct dram_dimm_info dimm; enum intel_dram_type type; - val = intel_uncore_read(uncore, BXT_D_CR_DRP0_DUNIT(i)); + val = intel_mchbar_read(display, BXT_D_CR_DRP0_DUNIT(i)); if (val == 0xFFFFFFFF) continue; -- cgit v1.2.3 From ed3643fb137386a6c8b9475a74e93ed0e63b5ce2 Mon Sep 17 00:00:00 2001 From: Ville Syrjälä Date: Tue, 31 Mar 2026 18:42:54 +0300 Subject: drm/i915/de: Add intel_de_read16() MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit We'll need a replacement for intel_uncore_read16() in order to untangle intel_mchbar_read16() from uncore. As with the 8 bit counterpart this doesn't need to work on modern platforms so we can forgo all the DMC wakelock stuff and whatnot. Reviewed-by: Jani Nikula Signed-off-by: Ville Syrjälä Link: https://patch.msgid.link/20260331154259.24600-8-ville.syrjala@linux.intel.com --- drivers/gpu/drm/i915/display/intel_de.c | 8 ++++++++ drivers/gpu/drm/i915/display/intel_de.h | 1 + 2 files changed, 9 insertions(+) diff --git a/drivers/gpu/drm/i915/display/intel_de.c b/drivers/gpu/drm/i915/display/intel_de.c index d2a418da2d54..a96e83d76eaa 100644 --- a/drivers/gpu/drm/i915/display/intel_de.c +++ b/drivers/gpu/drm/i915/display/intel_de.c @@ -176,3 +176,11 @@ void intel_de_write8(struct intel_display *display, i915_reg_t reg, u8 val) intel_uncore_write8(__to_uncore(display), reg, val); } + +u16 intel_de_read16(struct intel_display *display, i915_reg_t reg) +{ + /* this is only used on MCHBAR registers on pre-SNB */ + drm_WARN_ON(display->drm, DISPLAY_VER(display) >= 6); + + return intel_uncore_read16(__to_uncore(display), reg); +} diff --git a/drivers/gpu/drm/i915/display/intel_de.h b/drivers/gpu/drm/i915/display/intel_de.h index f87b84ab9d6d..3f9861b7a589 100644 --- a/drivers/gpu/drm/i915/display/intel_de.h +++ b/drivers/gpu/drm/i915/display/intel_de.h @@ -19,6 +19,7 @@ static inline struct intel_uncore *__to_uncore(struct intel_display *display) u8 intel_de_read8(struct intel_display *display, i915_reg_t reg); void intel_de_write8(struct intel_display *display, i915_reg_t reg, u8 val); +u16 intel_de_read16(struct intel_display *display, i915_reg_t reg); static inline u32 intel_de_read(struct intel_display *display, i915_reg_t reg) -- cgit v1.2.3 From 581feef63443b589b4f2013ae3a5480f4d435fb8 Mon Sep 17 00:00:00 2001 From: Ville Syrjälä Date: Tue, 31 Mar 2026 18:42:55 +0300 Subject: drm/i915/de: s/intel_de_read64_2x32()/intel_de_read64_2x32_volatile()/ MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The raison d'etre of intel_de_read64_2x32() is that it can handle registers where volatile values are split across two registers. I don't like that it's being used needlessly. Rename it to intel_de_read64_2x32_volatile() to make it more clear when it should be used. Reviewed-by: Jani Nikula Signed-off-by: Ville Syrjälä Link: https://patch.msgid.link/20260331154259.24600-9-ville.syrjala@linux.intel.com --- drivers/gpu/drm/i915/display/intel_de.h | 4 ++-- drivers/gpu/drm/i915/display/intel_vblank.c | 4 ++-- drivers/gpu/drm/i915/display/intel_vrr.c | 8 ++++---- 3 files changed, 8 insertions(+), 8 deletions(-) diff --git a/drivers/gpu/drm/i915/display/intel_de.h b/drivers/gpu/drm/i915/display/intel_de.h index 3f9861b7a589..295e7176b732 100644 --- a/drivers/gpu/drm/i915/display/intel_de.h +++ b/drivers/gpu/drm/i915/display/intel_de.h @@ -36,8 +36,8 @@ intel_de_read(struct intel_display *display, i915_reg_t reg) } static inline u64 -intel_de_read64_2x32(struct intel_display *display, - i915_reg_t lower_reg, i915_reg_t upper_reg) +intel_de_read64_2x32_volatile(struct intel_display *display, + i915_reg_t lower_reg, i915_reg_t upper_reg) { u64 val; diff --git a/drivers/gpu/drm/i915/display/intel_vblank.c b/drivers/gpu/drm/i915/display/intel_vblank.c index 1b7cfe226ff8..0726a2abed38 100644 --- a/drivers/gpu/drm/i915/display/intel_vblank.c +++ b/drivers/gpu/drm/i915/display/intel_vblank.c @@ -109,8 +109,8 @@ u32 i915_get_vblank_counter(struct drm_crtc *crtc) * we get a low value that's stable across two reads of the high * register. */ - frame = intel_de_read64_2x32(display, PIPEFRAMEPIXEL(display, pipe), - PIPEFRAME(display, pipe)); + frame = intel_de_read64_2x32_volatile(display, PIPEFRAMEPIXEL(display, pipe), + PIPEFRAME(display, pipe)); pixel = frame & PIPE_PIXEL_MASK; frame = (frame >> PIPE_FRAME_LOW_SHIFT) & 0xffffff; diff --git a/drivers/gpu/drm/i915/display/intel_vrr.c b/drivers/gpu/drm/i915/display/intel_vrr.c index 8a957804cb97..ae5385e92889 100644 --- a/drivers/gpu/drm/i915/display/intel_vrr.c +++ b/drivers/gpu/drm/i915/display/intel_vrr.c @@ -1053,11 +1053,11 @@ void intel_vrr_get_config(struct intel_crtc_state *crtc_state) if (crtc_state->cmrr.enable) { crtc_state->cmrr.cmrr_n = - intel_de_read64_2x32(display, TRANS_CMRR_N_LO(display, cpu_transcoder), - TRANS_CMRR_N_HI(display, cpu_transcoder)); + intel_de_read64_2x32_volatile(display, TRANS_CMRR_N_LO(display, cpu_transcoder), + TRANS_CMRR_N_HI(display, cpu_transcoder)); crtc_state->cmrr.cmrr_m = - intel_de_read64_2x32(display, TRANS_CMRR_M_LO(display, cpu_transcoder), - TRANS_CMRR_M_HI(display, cpu_transcoder)); + intel_de_read64_2x32_volatile(display, TRANS_CMRR_M_LO(display, cpu_transcoder), + TRANS_CMRR_M_HI(display, cpu_transcoder)); } if (DISPLAY_VER(display) >= 13) { -- cgit v1.2.3 From 57369c91daa619a17ac528578b39955b86f8a522 Mon Sep 17 00:00:00 2001 From: Ville Syrjälä Date: Tue, 31 Mar 2026 18:42:56 +0300 Subject: drm/i915/de: Add a simple intel_de_read64_2x32() MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit intel_de_read64_2x32_volatile() is a complex beast because it needs to deal with volatile register values. For simpler cases we can simply do a pair normal intel_de_read()s. My main reason for hating overuse of intel_de_read64_2x32_volatile() is that it makes register tracepoints confusing. It always does three accesses in the somewhat weird udw,ldw,udw order, confusing the reader of the trace. Much more clear if we just observe the two reads in the natural little endian order. We also have no non-volatile use case where the LDW and UDW are stored in non-consecutive registers, so we can just pass along a single register offset. v2: Put the function arguments on one line (Jani) Reviewed-by: Jani Nikula Signed-off-by: Ville Syrjälä Link: https://patch.msgid.link/20260331154259.24600-10-ville.syrjala@linux.intel.com --- drivers/gpu/drm/i915/display/intel_de.h | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/drivers/gpu/drm/i915/display/intel_de.h b/drivers/gpu/drm/i915/display/intel_de.h index 295e7176b732..14f9dc7b6dfd 100644 --- a/drivers/gpu/drm/i915/display/intel_de.h +++ b/drivers/gpu/drm/i915/display/intel_de.h @@ -53,6 +53,18 @@ intel_de_read64_2x32_volatile(struct intel_display *display, return val; } +static inline u64 +intel_de_read64_2x32(struct intel_display *display, i915_reg_t reg) +{ + i915_reg_t upper_reg = _MMIO(i915_mmio_reg_offset(reg) + 4); + u32 lower, upper; + + lower = intel_de_read(display, reg); + upper = intel_de_read(display, upper_reg); + + return (u64)upper << 32 | lower; +} + static inline void intel_de_posting_read(struct intel_display *display, i915_reg_t reg) { -- cgit v1.2.3 From 38105260bac19ecf9c7abee7a3eb0e43f51de36e Mon Sep 17 00:00:00 2001 From: Ville Syrjälä Date: Tue, 31 Mar 2026 18:42:57 +0300 Subject: drm/i915/vrr: Use intel_de_read64_2x32() MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Replace the pointless use of intel_de_read64_2x32_volatile() with the simpler intel_de_read64_2x32(). Reviewed-by: Jani Nikula Signed-off-by: Ville Syrjälä Link: https://patch.msgid.link/20260331154259.24600-11-ville.syrjala@linux.intel.com --- drivers/gpu/drm/i915/display/intel_vrr.c | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/drivers/gpu/drm/i915/display/intel_vrr.c b/drivers/gpu/drm/i915/display/intel_vrr.c index ae5385e92889..fae1186a90b2 100644 --- a/drivers/gpu/drm/i915/display/intel_vrr.c +++ b/drivers/gpu/drm/i915/display/intel_vrr.c @@ -1053,11 +1053,9 @@ void intel_vrr_get_config(struct intel_crtc_state *crtc_state) if (crtc_state->cmrr.enable) { crtc_state->cmrr.cmrr_n = - intel_de_read64_2x32_volatile(display, TRANS_CMRR_N_LO(display, cpu_transcoder), - TRANS_CMRR_N_HI(display, cpu_transcoder)); + intel_de_read64_2x32(display, TRANS_CMRR_N_LO(display, cpu_transcoder)); crtc_state->cmrr.cmrr_m = - intel_de_read64_2x32_volatile(display, TRANS_CMRR_M_LO(display, cpu_transcoder), - TRANS_CMRR_M_HI(display, cpu_transcoder)); + intel_de_read64_2x32(display, TRANS_CMRR_M_LO(display, cpu_transcoder)); } if (DISPLAY_VER(display) >= 13) { -- cgit v1.2.3 From 86435ca5140bca8bef52809560d7678b6a9a5400 Mon Sep 17 00:00:00 2001 From: Ville Syrjälä Date: Tue, 31 Mar 2026 18:42:58 +0300 Subject: drm/i915/mchbar: Use intel_de_read*() for MCHBAR register accesses MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Replace the naked intel_uncore_read*() with intel_de_read*() in the MCHBAR code. v2: Rebase due to intel_uncore_read64_2x32() Reviewed-by: Jani Nikula Signed-off-by: Ville Syrjälä Link: https://patch.msgid.link/20260331154259.24600-12-ville.syrjala@linux.intel.com --- drivers/gpu/drm/i915/display/intel_mchbar.c | 15 ++++----------- 1 file changed, 4 insertions(+), 11 deletions(-) diff --git a/drivers/gpu/drm/i915/display/intel_mchbar.c b/drivers/gpu/drm/i915/display/intel_mchbar.c index a404fa38c9bd..16fcfe1e93ec 100644 --- a/drivers/gpu/drm/i915/display/intel_mchbar.c +++ b/drivers/gpu/drm/i915/display/intel_mchbar.c @@ -7,10 +7,10 @@ #include +#include "intel_de.h" #include "intel_display_core.h" #include "intel_mchbar.h" #include "intel_mchbar_regs.h" -#include "intel_uncore.h" static bool has_mchbar_mirror(struct intel_display *display) { @@ -59,28 +59,21 @@ static void assert_is_mchbar_reg(struct intel_display *display, i915_reg_t reg) u16 intel_mchbar_read16(struct intel_display *display, i915_reg_t reg) { - struct intel_uncore *uncore = to_intel_uncore(display->drm); - assert_is_mchbar_reg(display, reg); - return intel_uncore_read16(uncore, reg); + return intel_de_read16(display, reg); } u32 intel_mchbar_read(struct intel_display *display, i915_reg_t reg) { - struct intel_uncore *uncore = to_intel_uncore(display->drm); - assert_is_mchbar_reg(display, reg); - return intel_uncore_read(uncore, reg); + return intel_de_read(display, reg); } u64 intel_mchbar_read64_2x32(struct intel_display *display, i915_reg_t reg) { - struct intel_uncore *uncore = to_intel_uncore(display->drm); - i915_reg_t upper_reg = _MMIO(i915_mmio_reg_offset(reg) + 4); - assert_is_mchbar_reg(display, reg); - return intel_uncore_read64_2x32(uncore, reg, upper_reg); + return intel_de_read64_2x32(display, reg); } -- cgit v1.2.3 From d4a06088f40e7c3b4abd79dc13cba81c01f18465 Mon Sep 17 00:00:00 2001 From: Ville Syrjälä Date: Tue, 31 Mar 2026 18:42:59 +0300 Subject: drm/i915/rom: Use intel_de for SPI ROM register access MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Since we moved intel_rom.c back into the display code, just use intel_de_{read,write}() for the register accesses. Reviewed-by: Jani Nikula Signed-off-by: Ville Syrjälä Link: https://patch.msgid.link/20260331154259.24600-13-ville.syrjala@linux.intel.com --- drivers/gpu/drm/i915/display/intel_rom.c | 19 ++++++++++--------- 1 file changed, 10 insertions(+), 9 deletions(-) diff --git a/drivers/gpu/drm/i915/display/intel_rom.c b/drivers/gpu/drm/i915/display/intel_rom.c index d573059fb0d9..54f842c09fb0 100644 --- a/drivers/gpu/drm/i915/display/intel_rom.c +++ b/drivers/gpu/drm/i915/display/intel_rom.c @@ -7,8 +7,9 @@ #include +#include "intel_de.h" +#include "intel_display_types.h" #include "intel_rom.h" -#include "intel_uncore.h" #include "intel_oprom_regs.h" struct intel_rom { @@ -17,7 +18,7 @@ struct intel_rom { void __iomem *oprom; /* for SPI */ - struct intel_uncore *uncore; + struct intel_display *display; loff_t offset; size_t size; @@ -30,10 +31,10 @@ struct intel_rom { static u32 spi_read32(struct intel_rom *rom, loff_t offset) { - intel_uncore_write(rom->uncore, PRIMARY_SPI_ADDRESS, - rom->offset + offset); + intel_de_write(rom->display, PRIMARY_SPI_ADDRESS, + rom->offset + offset); - return intel_uncore_read(rom->uncore, PRIMARY_SPI_TRIGGER); + return intel_de_read(rom->display, PRIMARY_SPI_TRIGGER); } static u16 spi_read16(struct intel_rom *rom, loff_t offset) @@ -50,13 +51,13 @@ struct intel_rom *intel_rom_spi(struct drm_device *drm) if (!rom) return NULL; - rom->uncore = to_intel_uncore(drm); + rom->display = to_intel_display(drm); - static_region = intel_uncore_read(rom->uncore, SPI_STATIC_REGIONS); + static_region = intel_de_read(rom->display, SPI_STATIC_REGIONS); static_region &= OPTIONROM_SPI_REGIONID_MASK; - intel_uncore_write(rom->uncore, PRIMARY_SPI_REGIONID, static_region); + intel_de_write(rom->display, PRIMARY_SPI_REGIONID, static_region); - rom->offset = intel_uncore_read(rom->uncore, OROM_OFFSET) & OROM_OFFSET_MASK; + rom->offset = intel_de_read(rom->display, OROM_OFFSET) & OROM_OFFSET_MASK; rom->size = 0x200000; -- cgit v1.2.3 From 896070686b16cc45cca7854be2049923b2b303d3 Mon Sep 17 00:00:00 2001 From: Jonathan Cavitt Date: Tue, 31 Mar 2026 18:12:17 +0000 Subject: drm/xe/vm: Add missing pad and extensions check Add missing pad and extensions check to xe_vm_get_property_ioctl v2: - Combine with other check (Auld) Fixes: 50c577eab051 ("drm/xe/xe_vm: Implement xe_vm_get_property_ioctl") Suggested-by: Matthew Auld Signed-off-by: Jonathan Cavitt Reviewed-by: Matthew Auld Reviewed-by: Matthew Brost Signed-off-by: Matthew Auld Link: https://patch.msgid.link/20260331181216.37775-2-jonathan.cavitt@intel.com --- drivers/gpu/drm/xe/xe_vm.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/drivers/gpu/drm/xe/xe_vm.c b/drivers/gpu/drm/xe/xe_vm.c index 72559bd33946..2408b547ca3d 100644 --- a/drivers/gpu/drm/xe/xe_vm.c +++ b/drivers/gpu/drm/xe/xe_vm.c @@ -4156,7 +4156,8 @@ int xe_vm_get_property_ioctl(struct drm_device *drm, void *data, int ret = 0; if (XE_IOCTL_DBG(xe, (args->reserved[0] || args->reserved[1] || - args->reserved[2]))) + args->reserved[2] || args->extensions || + args->pad))) return -EINVAL; vm = xe_vm_lookup(xef, args->vm_id); -- cgit v1.2.3 From 5a55a5da1f01274c07359b09abec952ec9f05105 Mon Sep 17 00:00:00 2001 From: Lizhi Hou Date: Mon, 30 Mar 2026 09:37:00 -0700 Subject: accel/amdxdna: Create shared functions for AIE2 and AIE4 The AIE4 platform uses a mailbox management channel mechanism similar to AIE2 to communicate with the firmware. Create aie.h and aie.c and move the functions and structures that can be shared by both platforms from the AIE2-specific files into these common files. This allows AIE2 and AIE4 to reuse the same implementation and reduces code duplication. Reviewed-by: Mario Limonciello (AMD) Signed-off-by: Lizhi Hou Link: https://patch.msgid.link/20260330163705.3153647-2-lizhi.hou@amd.com --- drivers/accel/amdxdna/Makefile | 1 + drivers/accel/amdxdna/aie.c | 89 ++++++++++++++++++++ drivers/accel/amdxdna/aie.h | 31 +++++++ drivers/accel/amdxdna/aie2_ctx.c | 4 +- drivers/accel/amdxdna/aie2_error.c | 12 +-- drivers/accel/amdxdna/aie2_message.c | 138 ++++++++++++-------------------- drivers/accel/amdxdna/aie2_pci.c | 107 ++++++++----------------- drivers/accel/amdxdna/aie2_pci.h | 26 ++---- drivers/accel/amdxdna/aie2_pm.c | 6 +- drivers/accel/amdxdna/aie2_smu.c | 22 ++--- drivers/accel/amdxdna/amdxdna_pci_drv.h | 8 ++ drivers/accel/amdxdna/npu1_regs.c | 4 +- drivers/accel/amdxdna/npu4_regs.c | 4 +- drivers/accel/amdxdna/npu5_regs.c | 2 +- drivers/accel/amdxdna/npu6_regs.c | 2 +- 15 files changed, 246 insertions(+), 210 deletions(-) create mode 100644 drivers/accel/amdxdna/aie.c create mode 100644 drivers/accel/amdxdna/aie.h diff --git a/drivers/accel/amdxdna/Makefile b/drivers/accel/amdxdna/Makefile index cf9bf19dedb9..5c7911554c46 100644 --- a/drivers/accel/amdxdna/Makefile +++ b/drivers/accel/amdxdna/Makefile @@ -1,6 +1,7 @@ # SPDX-License-Identifier: GPL-2.0-only amdxdna-y := \ + aie.o \ aie2_ctx.o \ aie2_error.o \ aie2_message.o \ diff --git a/drivers/accel/amdxdna/aie.c b/drivers/accel/amdxdna/aie.c new file mode 100644 index 000000000000..4b3d4493128e --- /dev/null +++ b/drivers/accel/amdxdna/aie.c @@ -0,0 +1,89 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Copyright (C) 2026, Advanced Micro Devices, Inc. + */ + +#include + +#include "aie.h" +#include "amdxdna_mailbox_helper.h" +#include "amdxdna_mailbox.h" +#include "amdxdna_pci_drv.h" + +void aie_dump_mgmt_chann_debug(struct aie_device *aie) +{ + struct amdxdna_dev *xdna = aie->xdna; + + XDNA_DBG(xdna, "i2x tail 0x%x", aie->mgmt_i2x.mb_tail_ptr_reg); + XDNA_DBG(xdna, "i2x head 0x%x", aie->mgmt_i2x.mb_head_ptr_reg); + XDNA_DBG(xdna, "i2x ringbuf 0x%x", aie->mgmt_i2x.rb_start_addr); + XDNA_DBG(xdna, "i2x rsize 0x%x", aie->mgmt_i2x.rb_size); + XDNA_DBG(xdna, "x2i tail 0x%x", aie->mgmt_x2i.mb_tail_ptr_reg); + XDNA_DBG(xdna, "x2i head 0x%x", aie->mgmt_x2i.mb_head_ptr_reg); + XDNA_DBG(xdna, "x2i ringbuf 0x%x", aie->mgmt_x2i.rb_start_addr); + XDNA_DBG(xdna, "x2i rsize 0x%x", aie->mgmt_x2i.rb_size); + XDNA_DBG(xdna, "x2i chann index 0x%x", aie->mgmt_chan_idx); + XDNA_DBG(xdna, "mailbox protocol major 0x%x", aie->mgmt_prot_major); + XDNA_DBG(xdna, "mailbox protocol minor 0x%x", aie->mgmt_prot_minor); +} + +void aie_destroy_chann(struct aie_device *aie, struct mailbox_channel **chann) +{ + struct amdxdna_dev *xdna = aie->xdna; + + drm_WARN_ON(&xdna->ddev, !mutex_is_locked(&xdna->dev_lock)); + + if (!*chann) + return; + + xdna_mailbox_stop_channel(*chann); + xdna_mailbox_free_channel(*chann); + *chann = NULL; +} + +int aie_send_mgmt_msg_wait(struct aie_device *aie, struct xdna_mailbox_msg *msg) +{ + struct amdxdna_dev *xdna = aie->xdna; + struct xdna_notify *hdl = msg->handle; + int ret; + + drm_WARN_ON(&xdna->ddev, !mutex_is_locked(&xdna->dev_lock)); + + if (!aie->mgmt_chann) + return -ENODEV; + + ret = xdna_send_msg_wait(xdna, aie->mgmt_chann, msg); + if (ret == -ETIME) + aie_destroy_chann(aie, &aie->mgmt_chann); + + if (!ret && *hdl->status) { + XDNA_ERR(xdna, "command opcode 0x%x failed, status 0x%x", + msg->opcode, *hdl->data); + ret = -EINVAL; + } + + return ret; +} + +int aie_check_protocol(struct aie_device *aie, u32 fw_major, u32 fw_minor) +{ + const struct amdxdna_fw_feature_tbl *feature; + bool found = false; + + for (feature = aie->xdna->dev_info->fw_feature_tbl; + feature->major; feature++) { + if (feature->major != fw_major) + continue; + if (fw_minor < feature->min_minor) + continue; + if (feature->max_minor > 0 && fw_minor > feature->max_minor) + continue; + + aie->feature_mask |= feature->features; + + /* firmware version matches one of the driver support entry */ + found = true; + } + + return found ? 0 : -EOPNOTSUPP; +} diff --git a/drivers/accel/amdxdna/aie.h b/drivers/accel/amdxdna/aie.h new file mode 100644 index 000000000000..1bea14b79c7c --- /dev/null +++ b/drivers/accel/amdxdna/aie.h @@ -0,0 +1,31 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* + * Copyright (C) 2026, Advanced Micro Devices, Inc. + */ +#ifndef _AIE_H_ +#define _AIE_H_ + +#include "amdxdna_pci_drv.h" +#include "amdxdna_mailbox.h" + +struct aie_device { + struct amdxdna_dev *xdna; + struct mailbox_channel *mgmt_chann; + struct xdna_mailbox_chann_res mgmt_x2i; + struct xdna_mailbox_chann_res mgmt_i2x; + u32 mgmt_chan_idx; + u32 mgmt_prot_major; + u32 mgmt_prot_minor; + unsigned long feature_mask; +}; + +#define DECLARE_AIE_MSG(name, op) \ + DECLARE_XDNA_MSG_COMMON(name, op, -1) +#define AIE_FEATURE_ON(aie, feature) test_bit(feature, &(aie)->feature_mask) + +void aie_dump_mgmt_chann_debug(struct aie_device *aie); +void aie_destroy_chann(struct aie_device *aie, struct mailbox_channel **chann); +int aie_send_mgmt_msg_wait(struct aie_device *aie, struct xdna_mailbox_msg *msg); +int aie_check_protocol(struct aie_device *aie, u32 fw_major, u32 fw_minor); + +#endif /* _AIE_H_ */ diff --git a/drivers/accel/amdxdna/aie2_ctx.c b/drivers/accel/amdxdna/aie2_ctx.c index 286379d9511d..8db32f8e2362 100644 --- a/drivers/accel/amdxdna/aie2_ctx.c +++ b/drivers/accel/amdxdna/aie2_ctx.c @@ -515,7 +515,7 @@ static int aie2_alloc_resource(struct amdxdna_hwctx *hwctx) struct alloc_requests *xrs_req; int ret; - if (AIE2_FEATURE_ON(xdna->dev_handle, AIE2_TEMPORAL_ONLY)) { + 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); @@ -552,7 +552,7 @@ static void aie2_release_resource(struct amdxdna_hwctx *hwctx) struct amdxdna_dev *xdna = hwctx->client->xdna; int ret; - if (AIE2_FEATURE_ON(xdna->dev_handle, AIE2_TEMPORAL_ONLY)) { + 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); diff --git a/drivers/accel/amdxdna/aie2_error.c b/drivers/accel/amdxdna/aie2_error.c index 58abb59b6153..9d20e956c020 100644 --- a/drivers/accel/amdxdna/aie2_error.c +++ b/drivers/accel/amdxdna/aie2_error.c @@ -249,12 +249,12 @@ static u32 aie2_error_backtrack(struct amdxdna_dev_hdl *ndev, void *err_info, u3 enum aie_error_category cat; cat = aie_get_error_category(err->row, err->event_id, err->mod_type); - XDNA_ERR(ndev->xdna, "Row: %d, Col: %d, module %d, event ID %d, category %d", + XDNA_ERR(ndev->aie.xdna, "Row: %d, Col: %d, module %d, event ID %d, category %d", err->row, err->col, err->mod_type, err->event_id, cat); if (err->col >= 32) { - XDNA_WARN(ndev->xdna, "Invalid column number"); + XDNA_WARN(ndev->aie.xdna, "Invalid column number"); break; } @@ -294,7 +294,7 @@ static void aie2_error_worker(struct work_struct *err_work) e = container_of(err_work, struct async_event, work); - xdna = e->ndev->xdna; + xdna = e->ndev->aie.xdna; if (e->resp.status == MAX_AIE2_STATUS_CODE) return; @@ -329,7 +329,7 @@ static void aie2_error_worker(struct work_struct *err_work) void aie2_error_async_events_free(struct amdxdna_dev_hdl *ndev) { - struct amdxdna_dev *xdna = ndev->xdna; + struct amdxdna_dev *xdna = ndev->aie.xdna; struct async_events *events; events = ndev->async_events; @@ -344,7 +344,7 @@ void aie2_error_async_events_free(struct amdxdna_dev_hdl *ndev) int aie2_error_async_events_alloc(struct amdxdna_dev_hdl *ndev) { - struct amdxdna_dev *xdna = ndev->xdna; + struct amdxdna_dev *xdna = ndev->aie.xdna; u32 total_col = ndev->total_col; u32 total_size = ASYNC_BUF_SIZE * total_col; struct async_events *events; @@ -402,7 +402,7 @@ free_events: int aie2_get_array_async_error(struct amdxdna_dev_hdl *ndev, struct amdxdna_drm_get_array *args) { - struct amdxdna_dev *xdna = ndev->xdna; + struct amdxdna_dev *xdna = ndev->aie.xdna; drm_WARN_ON(&xdna->ddev, !mutex_is_locked(&xdna->dev_lock)); diff --git a/drivers/accel/amdxdna/aie2_message.c b/drivers/accel/amdxdna/aie2_message.c index a1c546c3e81c..ccf87b1aa1cc 100644 --- a/drivers/accel/amdxdna/aie2_message.c +++ b/drivers/accel/amdxdna/aie2_message.c @@ -16,6 +16,7 @@ #include #include +#include "aie.h" #include "aie2_msg_priv.h" #include "aie2_pci.h" #include "amdxdna_ctx.h" @@ -24,38 +25,12 @@ #include "amdxdna_mailbox_helper.h" #include "amdxdna_pci_drv.h" -#define DECLARE_AIE2_MSG(name, op) \ - DECLARE_XDNA_MSG_COMMON(name, op, MAX_AIE2_STATUS_CODE) - #define EXEC_MSG_OPS(xdna) ((xdna)->dev_handle->exec_msg_ops) -static int aie2_send_mgmt_msg_wait(struct amdxdna_dev_hdl *ndev, - struct xdna_mailbox_msg *msg) -{ - struct amdxdna_dev *xdna = ndev->xdna; - struct xdna_notify *hdl = msg->handle; - int ret; - - if (!ndev->mgmt_chann) - return -ENODEV; - - ret = xdna_send_msg_wait(xdna, ndev->mgmt_chann, msg); - if (ret == -ETIME) - aie2_destroy_mgmt_chann(ndev); - - if (!ret && *hdl->status != AIE2_STATUS_SUCCESS) { - XDNA_ERR(xdna, "command opcode 0x%x failed, status 0x%x", - msg->opcode, *hdl->data); - ret = -EINVAL; - } - - return ret; -} - void *aie2_alloc_msg_buffer(struct amdxdna_dev_hdl *ndev, u32 *size, dma_addr_t *dma_addr) { - struct amdxdna_dev *xdna = ndev->xdna; + struct amdxdna_dev *xdna = ndev->aie.xdna; void *vaddr; int order; @@ -79,7 +54,7 @@ void *aie2_alloc_msg_buffer(struct amdxdna_dev_hdl *ndev, u32 *size, void aie2_free_msg_buffer(struct amdxdna_dev_hdl *ndev, size_t size, void *cpu_addr, dma_addr_t dma_addr) { - struct amdxdna_dev *xdna = ndev->xdna; + struct amdxdna_dev *xdna = ndev->aie.xdna; if (amdxdna_iova_on(xdna)) { amdxdna_iommu_free(xdna, size, cpu_addr, dma_addr); @@ -91,12 +66,12 @@ void aie2_free_msg_buffer(struct amdxdna_dev_hdl *ndev, size_t size, int aie2_suspend_fw(struct amdxdna_dev_hdl *ndev) { - DECLARE_AIE2_MSG(suspend, MSG_OP_SUSPEND); + DECLARE_AIE_MSG(suspend, MSG_OP_SUSPEND); int ret; - ret = aie2_send_mgmt_msg_wait(ndev, &msg); + ret = aie_send_mgmt_msg_wait(&ndev->aie, &msg); if (ret) { - XDNA_ERR(ndev->xdna, "Failed to suspend fw, ret %d", ret); + XDNA_ERR(ndev->aie.xdna, "Failed to suspend fw, ret %d", ret); return ret; } @@ -105,22 +80,22 @@ int aie2_suspend_fw(struct amdxdna_dev_hdl *ndev) int aie2_resume_fw(struct amdxdna_dev_hdl *ndev) { - DECLARE_AIE2_MSG(suspend, MSG_OP_RESUME); + DECLARE_AIE_MSG(suspend, MSG_OP_RESUME); - return aie2_send_mgmt_msg_wait(ndev, &msg); + return aie_send_mgmt_msg_wait(&ndev->aie, &msg); } int aie2_set_runtime_cfg(struct amdxdna_dev_hdl *ndev, u32 type, u64 value) { - DECLARE_AIE2_MSG(set_runtime_cfg, MSG_OP_SET_RUNTIME_CONFIG); + DECLARE_AIE_MSG(set_runtime_cfg, MSG_OP_SET_RUNTIME_CONFIG); int ret; req.type = type; req.value = value; - ret = aie2_send_mgmt_msg_wait(ndev, &msg); + ret = aie_send_mgmt_msg_wait(&ndev->aie, &msg); if (ret) { - XDNA_ERR(ndev->xdna, "Failed to set runtime config, ret %d", ret); + XDNA_ERR(ndev->aie.xdna, "Failed to set runtime config, ret %d", ret); return ret; } @@ -129,13 +104,13 @@ int aie2_set_runtime_cfg(struct amdxdna_dev_hdl *ndev, u32 type, u64 value) int aie2_get_runtime_cfg(struct amdxdna_dev_hdl *ndev, u32 type, u64 *value) { - DECLARE_AIE2_MSG(get_runtime_cfg, MSG_OP_GET_RUNTIME_CONFIG); + DECLARE_AIE_MSG(get_runtime_cfg, MSG_OP_GET_RUNTIME_CONFIG); int ret; req.type = type; - ret = aie2_send_mgmt_msg_wait(ndev, &msg); + ret = aie_send_mgmt_msg_wait(&ndev->aie, &msg); if (ret) { - XDNA_ERR(ndev->xdna, "Failed to get runtime config, ret %d", ret); + XDNA_ERR(ndev->aie.xdna, "Failed to get runtime config, ret %d", ret); return ret; } @@ -145,20 +120,20 @@ int aie2_get_runtime_cfg(struct amdxdna_dev_hdl *ndev, u32 type, u64 *value) int aie2_assign_mgmt_pasid(struct amdxdna_dev_hdl *ndev, u16 pasid) { - DECLARE_AIE2_MSG(assign_mgmt_pasid, MSG_OP_ASSIGN_MGMT_PASID); + DECLARE_AIE_MSG(assign_mgmt_pasid, MSG_OP_ASSIGN_MGMT_PASID); req.pasid = pasid; - return aie2_send_mgmt_msg_wait(ndev, &msg); + return aie_send_mgmt_msg_wait(&ndev->aie, &msg); } int aie2_query_aie_version(struct amdxdna_dev_hdl *ndev, struct aie_version *version) { - DECLARE_AIE2_MSG(aie_version_info, MSG_OP_QUERY_AIE_VERSION); - struct amdxdna_dev *xdna = ndev->xdna; + DECLARE_AIE_MSG(aie_version_info, MSG_OP_QUERY_AIE_VERSION); + struct amdxdna_dev *xdna = ndev->aie.xdna; int ret; - ret = aie2_send_mgmt_msg_wait(ndev, &msg); + ret = aie_send_mgmt_msg_wait(&ndev->aie, &msg); if (ret) return ret; @@ -173,10 +148,10 @@ int aie2_query_aie_version(struct amdxdna_dev_hdl *ndev, struct aie_version *ver int aie2_query_aie_metadata(struct amdxdna_dev_hdl *ndev, struct aie_metadata *metadata) { - DECLARE_AIE2_MSG(aie_tile_info, MSG_OP_QUERY_AIE_TILE_INFO); + DECLARE_AIE_MSG(aie_tile_info, MSG_OP_QUERY_AIE_TILE_INFO); int ret; - ret = aie2_send_mgmt_msg_wait(ndev, &msg); + ret = aie_send_mgmt_msg_wait(&ndev->aie, &msg); if (ret) return ret; @@ -211,10 +186,10 @@ int aie2_query_aie_metadata(struct amdxdna_dev_hdl *ndev, struct aie_metadata *m int aie2_query_firmware_version(struct amdxdna_dev_hdl *ndev, struct amdxdna_fw_ver *fw_ver) { - DECLARE_AIE2_MSG(firmware_version, MSG_OP_GET_FIRMWARE_VERSION); + DECLARE_AIE_MSG(firmware_version, MSG_OP_GET_FIRMWARE_VERSION); int ret; - ret = aie2_send_mgmt_msg_wait(ndev, &msg); + ret = aie_send_mgmt_msg_wait(&ndev->aie, &msg); if (ret) return ret; @@ -228,12 +203,12 @@ int aie2_query_firmware_version(struct amdxdna_dev_hdl *ndev, static int aie2_destroy_context_req(struct amdxdna_dev_hdl *ndev, u32 id) { - DECLARE_AIE2_MSG(destroy_ctx, MSG_OP_DESTROY_CONTEXT); - struct amdxdna_dev *xdna = ndev->xdna; + DECLARE_AIE_MSG(destroy_ctx, MSG_OP_DESTROY_CONTEXT); + struct amdxdna_dev *xdna = ndev->aie.xdna; int ret; req.context_id = id; - ret = aie2_send_mgmt_msg_wait(ndev, &msg); + ret = aie_send_mgmt_msg_wait(&ndev->aie, &msg); if (ret && ret != -ENODEV) XDNA_WARN(xdna, "Destroy context failed, ret %d", ret); else if (ret == -ENODEV) @@ -245,7 +220,7 @@ static int aie2_destroy_context_req(struct amdxdna_dev_hdl *ndev, u32 id) static u32 aie2_get_context_priority(struct amdxdna_dev_hdl *ndev, struct amdxdna_hwctx *hwctx) { - if (!AIE2_FEATURE_ON(ndev, AIE2_PREEMPT)) + if (!AIE_FEATURE_ON(&ndev->aie, AIE2_PREEMPT)) return PRIORITY_HIGH; switch (hwctx->qos.priority) { @@ -264,8 +239,8 @@ static u32 aie2_get_context_priority(struct amdxdna_dev_hdl *ndev, int aie2_create_context(struct amdxdna_dev_hdl *ndev, struct amdxdna_hwctx *hwctx) { - DECLARE_AIE2_MSG(create_ctx, MSG_OP_CREATE_CONTEXT); - struct amdxdna_dev *xdna = ndev->xdna; + DECLARE_AIE_MSG(create_ctx, MSG_OP_CREATE_CONTEXT); + struct amdxdna_dev *xdna = ndev->aie.xdna; struct xdna_mailbox_chann_res x2i; struct xdna_mailbox_chann_res i2x; struct cq_pair *cq_pair; @@ -280,7 +255,7 @@ int aie2_create_context(struct amdxdna_dev_hdl *ndev, struct amdxdna_hwctx *hwct req.pasid = amdxdna_pasid_on(hwctx->client) ? hwctx->client->pasid : 0; req.context_priority = aie2_get_context_priority(ndev, hwctx); - ret = aie2_send_mgmt_msg_wait(ndev, &msg); + ret = aie_send_mgmt_msg_wait(&ndev->aie, &msg); if (ret) return ret; @@ -344,7 +319,7 @@ del_ctx_req: int aie2_destroy_context(struct amdxdna_dev_hdl *ndev, struct amdxdna_hwctx *hwctx) { - struct amdxdna_dev *xdna = ndev->xdna; + struct amdxdna_dev *xdna = ndev->aie.xdna; int ret; if (!hwctx->priv->mbox_chann) @@ -363,14 +338,14 @@ int aie2_destroy_context(struct amdxdna_dev_hdl *ndev, struct amdxdna_hwctx *hwc int aie2_map_host_buf(struct amdxdna_dev_hdl *ndev, u32 context_id, u64 addr, u64 size) { - DECLARE_AIE2_MSG(map_host_buffer, MSG_OP_MAP_HOST_BUFFER); - struct amdxdna_dev *xdna = ndev->xdna; + DECLARE_AIE_MSG(map_host_buffer, MSG_OP_MAP_HOST_BUFFER); + struct amdxdna_dev *xdna = ndev->aie.xdna; int ret; req.context_id = context_id; req.buf_addr = addr; req.buf_size = size; - ret = aie2_send_mgmt_msg_wait(ndev, &msg); + ret = aie_send_mgmt_msg_wait(&ndev->aie, &msg); if (ret) return ret; @@ -392,8 +367,8 @@ static int amdxdna_hwctx_col_map(struct amdxdna_hwctx *hwctx, void *arg) int aie2_query_status(struct amdxdna_dev_hdl *ndev, char __user *buf, u32 size, u32 *cols_filled) { - DECLARE_AIE2_MSG(aie_column_info, MSG_OP_QUERY_COL_STATUS); - struct amdxdna_dev *xdna = ndev->xdna; + DECLARE_AIE_MSG(aie_column_info, MSG_OP_QUERY_COL_STATUS); + struct amdxdna_dev *xdna = ndev->aie.xdna; u32 buf_sz = size, aie_bitmap = 0; struct amdxdna_client *client; dma_addr_t dma_addr; @@ -415,7 +390,7 @@ int aie2_query_status(struct amdxdna_dev_hdl *ndev, char __user *buf, req.aie_bitmap = aie_bitmap; drm_clflush_virt_range(buff_addr, size); /* device can access */ - ret = aie2_send_mgmt_msg_wait(ndev, &msg); + ret = aie_send_mgmt_msg_wait(&ndev->aie, &msg); if (ret) { XDNA_ERR(xdna, "Error during NPU query, status %d", ret); goto fail; @@ -446,8 +421,8 @@ int aie2_query_telemetry(struct amdxdna_dev_hdl *ndev, char __user *buf, u32 size, struct amdxdna_drm_query_telemetry_header *header) { - DECLARE_AIE2_MSG(get_telemetry, MSG_OP_GET_TELEMETRY); - struct amdxdna_dev *xdna = ndev->xdna; + DECLARE_AIE_MSG(get_telemetry, MSG_OP_GET_TELEMETRY); + struct amdxdna_dev *xdna = ndev->aie.xdna; dma_addr_t dma_addr; u32 buf_sz = size; u8 *addr; @@ -465,7 +440,7 @@ int aie2_query_telemetry(struct amdxdna_dev_hdl *ndev, req.type = header->type; drm_clflush_virt_range(addr, size); /* device can access */ - ret = aie2_send_mgmt_msg_wait(ndev, &msg); + ret = aie_send_mgmt_msg_wait(&ndev->aie, &msg); if (ret) { XDNA_ERR(xdna, "Query telemetry failed, status %d", ret); goto free_buf; @@ -506,8 +481,8 @@ int aie2_register_asyn_event_msg(struct amdxdna_dev_hdl *ndev, dma_addr_t addr, req.buf_addr = addr; req.buf_size = size; - XDNA_DBG(ndev->xdna, "Register addr 0x%llx size 0x%x", addr, size); - return xdna_mailbox_send_msg(ndev->mgmt_chann, &msg, TX_TIMEOUT); + XDNA_DBG(ndev->aie.xdna, "Register addr 0x%llx size 0x%x", addr, size); + return xdna_mailbox_send_msg(ndev->aie.mgmt_chann, &msg, TX_TIMEOUT); } int aie2_config_cu(struct amdxdna_hwctx *hwctx, @@ -866,7 +841,6 @@ static int aie2_init_exec_req(void *req, struct amdxdna_gem_obj *cmd_abo, int ret; u32 op; - op = amdxdna_cmd_get_op(cmd_abo); switch (op) { case ERT_START_CU: @@ -915,12 +889,12 @@ aie2_cmdlist_fill_slot(void *slot, struct amdxdna_gem_obj *cmd_abo, ret = EXEC_MSG_OPS(xdna)->fill_dpu_slot(cmd_abo, slot, size); break; case ERT_START_NPU_PREEMPT: - if (!AIE2_FEATURE_ON(xdna->dev_handle, AIE2_PREEMPT)) + if (!AIE_FEATURE_ON(&xdna->dev_handle->aie, AIE2_PREEMPT)) return -EOPNOTSUPP; ret = EXEC_MSG_OPS(xdna)->fill_preempt_slot(cmd_abo, slot, size); break; case ERT_START_NPU_PREEMPT_ELF: - if (!AIE2_FEATURE_ON(xdna->dev_handle, AIE2_PREEMPT)) + if (!AIE_FEATURE_ON(&xdna->dev_handle->aie, AIE2_PREEMPT)) return -EOPNOTSUPP; ret = EXEC_MSG_OPS(xdna)->fill_elf_slot(cmd_abo, slot, size); break; @@ -935,26 +909,12 @@ aie2_cmdlist_fill_slot(void *slot, struct amdxdna_gem_obj *cmd_abo, void aie2_msg_init(struct amdxdna_dev_hdl *ndev) { - if (AIE2_FEATURE_ON(ndev, AIE2_NPU_COMMAND)) + if (AIE_FEATURE_ON(&ndev->aie, AIE2_NPU_COMMAND)) ndev->exec_msg_ops = &npu_exec_message_ops; else ndev->exec_msg_ops = &legacy_exec_message_ops; } -void aie2_destroy_mgmt_chann(struct amdxdna_dev_hdl *ndev) -{ - struct amdxdna_dev *xdna = ndev->xdna; - - drm_WARN_ON(&xdna->ddev, !mutex_is_locked(&xdna->dev_lock)); - - if (!ndev->mgmt_chann) - return; - - xdna_mailbox_stop_channel(ndev->mgmt_chann); - xdna_mailbox_free_channel(ndev->mgmt_chann); - ndev->mgmt_chann = NULL; -} - static inline struct amdxdna_gem_obj * aie2_cmdlist_get_cmd_buf(struct amdxdna_sched_job *job) { @@ -1199,14 +1159,14 @@ int aie2_config_debug_bo(struct amdxdna_hwctx *hwctx, struct amdxdna_sched_job * int aie2_query_app_health(struct amdxdna_dev_hdl *ndev, u32 context_id, struct app_health_report *report) { - DECLARE_AIE2_MSG(get_app_health, MSG_OP_GET_APP_HEALTH); - struct amdxdna_dev *xdna = ndev->xdna; + DECLARE_AIE_MSG(get_app_health, MSG_OP_GET_APP_HEALTH); + struct amdxdna_dev *xdna = ndev->aie.xdna; struct app_health_report *buf; dma_addr_t dma_addr; u32 buf_size; int ret; - if (!AIE2_FEATURE_ON(ndev, AIE2_APP_HEALTH)) { + if (!AIE_FEATURE_ON(&ndev->aie, AIE2_APP_HEALTH)) { XDNA_DBG(xdna, "App health feature not supported"); return -EOPNOTSUPP; } @@ -1223,7 +1183,7 @@ int aie2_query_app_health(struct amdxdna_dev_hdl *ndev, u32 context_id, req.buf_size = buf_size; drm_clflush_virt_range(buf, sizeof(*report)); - ret = aie2_send_mgmt_msg_wait(ndev, &msg); + ret = aie_send_mgmt_msg_wait(&ndev->aie, &msg); if (ret) { XDNA_ERR(xdna, "Get app health failed, ret %d status 0x%x", ret, resp.status); goto free_buf; diff --git a/drivers/accel/amdxdna/aie2_pci.c b/drivers/accel/amdxdna/aie2_pci.c index f1ac4e00bd9f..03bac963516d 100644 --- a/drivers/accel/amdxdna/aie2_pci.c +++ b/drivers/accel/amdxdna/aie2_pci.c @@ -60,45 +60,6 @@ struct mgmt_mbox_chann_info { __u32 rsvd[4]; }; -static int aie2_check_protocol(struct amdxdna_dev_hdl *ndev, u32 fw_major, u32 fw_minor) -{ - const struct aie2_fw_feature_tbl *feature; - bool found = false; - - for (feature = ndev->priv->fw_feature_tbl; feature->major; feature++) { - if (feature->major != fw_major) - continue; - if (fw_minor < feature->min_minor) - continue; - if (feature->max_minor > 0 && fw_minor > feature->max_minor) - continue; - - ndev->feature_mask |= feature->features; - - /* firmware version matches one of the driver support entry */ - found = true; - } - - return found ? 0 : -EOPNOTSUPP; -} - -static void aie2_dump_chann_info_debug(struct amdxdna_dev_hdl *ndev) -{ - struct amdxdna_dev *xdna = ndev->xdna; - - XDNA_DBG(xdna, "i2x tail 0x%x", ndev->mgmt_i2x.mb_tail_ptr_reg); - XDNA_DBG(xdna, "i2x head 0x%x", ndev->mgmt_i2x.mb_head_ptr_reg); - XDNA_DBG(xdna, "i2x ringbuf 0x%x", ndev->mgmt_i2x.rb_start_addr); - XDNA_DBG(xdna, "i2x rsize 0x%x", ndev->mgmt_i2x.rb_size); - XDNA_DBG(xdna, "x2i tail 0x%x", ndev->mgmt_x2i.mb_tail_ptr_reg); - XDNA_DBG(xdna, "x2i head 0x%x", ndev->mgmt_x2i.mb_head_ptr_reg); - XDNA_DBG(xdna, "x2i ringbuf 0x%x", ndev->mgmt_x2i.rb_start_addr); - XDNA_DBG(xdna, "x2i rsize 0x%x", ndev->mgmt_x2i.rb_size); - XDNA_DBG(xdna, "x2i chann index 0x%x", ndev->mgmt_chan_idx); - XDNA_DBG(xdna, "mailbox protocol major 0x%x", ndev->mgmt_prot_major); - XDNA_DBG(xdna, "mailbox protocol minor 0x%x", ndev->mgmt_prot_minor); -} - static int aie2_get_mgmt_chann_info(struct amdxdna_dev_hdl *ndev) { struct mgmt_mbox_chann_info info_regs; @@ -128,13 +89,13 @@ static int aie2_get_mgmt_chann_info(struct amdxdna_dev_hdl *ndev) reg[i] = readl(ndev->sram_base + off + i * sizeof(u32)); if (info_regs.magic != MGMT_MBOX_MAGIC) { - XDNA_ERR(ndev->xdna, "Invalid mbox magic 0x%x", info_regs.magic); + XDNA_ERR(ndev->aie.xdna, "Invalid mbox magic 0x%x", info_regs.magic); ret = -EINVAL; goto done; } - i2x = &ndev->mgmt_i2x; - x2i = &ndev->mgmt_x2i; + i2x = &ndev->aie.mgmt_i2x; + x2i = &ndev->aie.mgmt_x2i; i2x->mb_head_ptr_reg = AIE2_MBOX_OFF(ndev, info_regs.i2x_head); i2x->mb_tail_ptr_reg = AIE2_MBOX_OFF(ndev, info_regs.i2x_tail); @@ -146,14 +107,15 @@ static int aie2_get_mgmt_chann_info(struct amdxdna_dev_hdl *ndev) x2i->rb_start_addr = AIE2_SRAM_OFF(ndev, info_regs.x2i_buf); x2i->rb_size = info_regs.x2i_buf_sz; - ndev->mgmt_chan_idx = info_regs.msi_id; - ndev->mgmt_prot_major = info_regs.prot_major; - ndev->mgmt_prot_minor = info_regs.prot_minor; + ndev->aie.mgmt_chan_idx = info_regs.msi_id; + ndev->aie.mgmt_prot_major = info_regs.prot_major; + ndev->aie.mgmt_prot_minor = info_regs.prot_minor; - ret = aie2_check_protocol(ndev, ndev->mgmt_prot_major, ndev->mgmt_prot_minor); + ret = aie_check_protocol(&ndev->aie, ndev->aie.mgmt_prot_major, + ndev->aie.mgmt_prot_minor); done: - aie2_dump_chann_info_debug(ndev); + aie_dump_mgmt_chann_debug(&ndev->aie); /* Must clear address at FW_ALIVE_OFF */ writel(0, SRAM_GET_ADDR(ndev, FW_ALIVE_OFF)); @@ -173,13 +135,14 @@ int aie2_runtime_cfg(struct amdxdna_dev_hdl *ndev, continue; if (cfg->feature_mask && - bitmap_subset(&cfg->feature_mask, &ndev->feature_mask, AIE2_FEATURE_MAX)) + bitmap_subset(&cfg->feature_mask, &ndev->aie.feature_mask, + AIE2_FEATURE_MAX)) continue; value = val ? *val : cfg->value; ret = aie2_set_runtime_cfg(ndev, cfg->type, value); if (ret) { - XDNA_ERR(ndev->xdna, "Set type %d value %d failed", + XDNA_ERR(ndev->aie.xdna, "Set type %d value %d failed", cfg->type, value); return ret; } @@ -194,13 +157,13 @@ static int aie2_xdna_reset(struct amdxdna_dev_hdl *ndev) ret = aie2_suspend_fw(ndev); if (ret) { - XDNA_ERR(ndev->xdna, "Suspend firmware failed"); + XDNA_ERR(ndev->aie.xdna, "Suspend firmware failed"); return ret; } ret = aie2_resume_fw(ndev); if (ret) { - XDNA_ERR(ndev->xdna, "Resume firmware failed"); + XDNA_ERR(ndev->aie.xdna, "Resume firmware failed"); return ret; } @@ -213,19 +176,19 @@ static int aie2_mgmt_fw_init(struct amdxdna_dev_hdl *ndev) ret = aie2_runtime_cfg(ndev, AIE2_RT_CFG_INIT, NULL); if (ret) { - XDNA_ERR(ndev->xdna, "Runtime config failed"); + XDNA_ERR(ndev->aie.xdna, "Runtime config failed"); return ret; } ret = aie2_assign_mgmt_pasid(ndev, 0); if (ret) { - XDNA_ERR(ndev->xdna, "Can not assign PASID"); + XDNA_ERR(ndev->aie.xdna, "Can not assign PASID"); return ret; } ret = aie2_xdna_reset(ndev); if (ret) { - XDNA_ERR(ndev->xdna, "Reset firmware failed"); + XDNA_ERR(ndev->aie.xdna, "Reset firmware failed"); return ret; } @@ -236,21 +199,21 @@ static int aie2_mgmt_fw_query(struct amdxdna_dev_hdl *ndev) { int ret; - ret = aie2_query_firmware_version(ndev, &ndev->xdna->fw_ver); + ret = aie2_query_firmware_version(ndev, &ndev->aie.xdna->fw_ver); if (ret) { - XDNA_ERR(ndev->xdna, "query firmware version failed"); + XDNA_ERR(ndev->aie.xdna, "query firmware version failed"); return ret; } ret = aie2_query_aie_version(ndev, &ndev->version); if (ret) { - XDNA_ERR(ndev->xdna, "Query AIE version failed"); + XDNA_ERR(ndev->aie.xdna, "Query AIE version failed"); return ret; } ret = aie2_query_aie_metadata(ndev, &ndev->metadata); if (ret) { - XDNA_ERR(ndev->xdna, "Query AIE metadata failed"); + XDNA_ERR(ndev->aie.xdna, "Query AIE metadata failed"); return ret; } @@ -262,8 +225,8 @@ static int aie2_mgmt_fw_query(struct amdxdna_dev_hdl *ndev) static void aie2_mgmt_fw_fini(struct amdxdna_dev_hdl *ndev) { if (aie2_suspend_fw(ndev)) - XDNA_ERR(ndev->xdna, "Suspend_fw failed"); - XDNA_DBG(ndev->xdna, "Firmware suspended"); + XDNA_ERR(ndev->aie.xdna, "Suspend_fw failed"); + XDNA_DBG(ndev->aie.xdna, "Firmware suspended"); } static int aie2_xrs_load(void *cb_arg, struct xrs_action_load *action) @@ -331,7 +294,7 @@ static void aie2_hw_stop(struct amdxdna_dev *xdna) aie2_runtime_cfg(ndev, AIE2_RT_CFG_CLK_GATING, NULL); aie2_mgmt_fw_fini(ndev); - aie2_destroy_mgmt_chann(ndev); + aie_destroy_chann(&ndev->aie, &ndev->aie.mgmt_chann); drmm_kfree(&xdna->ddev, ndev->mbox); ndev->mbox = NULL; aie2_psp_stop(ndev->psp_hdl); @@ -374,8 +337,8 @@ static int aie2_hw_start(struct amdxdna_dev *xdna) goto disable_dev; } - ndev->mgmt_chann = xdna_mailbox_alloc_channel(ndev->mbox); - if (!ndev->mgmt_chann) { + ndev->aie.mgmt_chann = xdna_mailbox_alloc_channel(ndev->mbox); + if (!ndev->aie.mgmt_chann) { XDNA_ERR(xdna, "failed to alloc channel"); ret = -ENODEV; goto disable_dev; @@ -399,17 +362,17 @@ static int aie2_hw_start(struct amdxdna_dev *xdna) goto stop_psp; } - mgmt_mb_irq = pci_irq_vector(pdev, ndev->mgmt_chan_idx); + mgmt_mb_irq = pci_irq_vector(pdev, ndev->aie.mgmt_chan_idx); if (mgmt_mb_irq < 0) { ret = mgmt_mb_irq; XDNA_ERR(xdna, "failed to alloc irq vector, ret %d", ret); goto stop_psp; } - xdna_mailbox_intr_reg = ndev->mgmt_i2x.mb_head_ptr_reg + 4; - ret = xdna_mailbox_start_channel(ndev->mgmt_chann, - &ndev->mgmt_x2i, - &ndev->mgmt_i2x, + xdna_mailbox_intr_reg = ndev->aie.mgmt_i2x.mb_head_ptr_reg + 4; + ret = xdna_mailbox_start_channel(ndev->aie.mgmt_chann, + &ndev->aie.mgmt_x2i, + &ndev->aie.mgmt_i2x, xdna_mailbox_intr_reg, mgmt_mb_irq); if (ret) { @@ -448,14 +411,14 @@ static int aie2_hw_start(struct amdxdna_dev *xdna) stop_fw: aie2_suspend_fw(ndev); - xdna_mailbox_stop_channel(ndev->mgmt_chann); + xdna_mailbox_stop_channel(ndev->aie.mgmt_chann); stop_psp: aie2_psp_stop(ndev->psp_hdl); fini_smu: aie2_smu_fini(ndev); free_channel: - xdna_mailbox_free_channel(ndev->mgmt_chann); - ndev->mgmt_chann = NULL; + xdna_mailbox_free_channel(ndev->aie.mgmt_chann); + ndev->aie.mgmt_chann = NULL; disable_dev: pci_disable_device(pdev); @@ -516,7 +479,7 @@ static int aie2_init(struct amdxdna_dev *xdna) return -ENOMEM; ndev->priv = xdna->dev_info->dev_priv; - ndev->xdna = xdna; + ndev->aie.xdna = xdna; for (i = 0; i < ARRAY_SIZE(npu_fw); i++) { fw_full_path = kasprintf(GFP_KERNEL, "%s%s", ndev->priv->fw_path, npu_fw[i]); diff --git a/drivers/accel/amdxdna/aie2_pci.h b/drivers/accel/amdxdna/aie2_pci.h index efcf4be035f0..90fb0aafaf40 100644 --- a/drivers/accel/amdxdna/aie2_pci.h +++ b/drivers/accel/amdxdna/aie2_pci.h @@ -10,6 +10,7 @@ #include #include +#include "aie.h" #include "aie2_msg_priv.h" #include "amdxdna_mailbox.h" @@ -20,7 +21,7 @@ #define AIE2_DEVM_BASE 0x4000000 #define AIE2_DEVM_SIZE SZ_64M -#define NDEV2PDEV(ndev) (to_pci_dev((ndev)->xdna->ddev.dev)) +#define NDEV2PDEV(ndev) (to_pci_dev((ndev)->aie.xdna->ddev.dev)) #define AIE2_SRAM_OFF(ndev, addr) ((addr) - (ndev)->priv->sram_dev_addr) #define AIE2_MBOX_OFF(ndev, addr) ((addr) - (ndev)->priv->mbox_dev_addr) @@ -45,7 +46,7 @@ ({ \ typeof(ndev) _ndev = (ndev); \ ((_ndev)->priv->mbox_size) ? (_ndev)->priv->mbox_size : \ - pci_resource_len(NDEV2PDEV(_ndev), (_ndev)->xdna->dev_info->mbox_bar); \ + pci_resource_len(NDEV2PDEV(_ndev), (_ndev)->aie.xdna->dev_info->mbox_bar); \ }) #if IS_ENABLED(CONFIG_AMD_PMF) @@ -203,23 +204,16 @@ struct aie2_exec_msg_ops { }; struct amdxdna_dev_hdl { - struct amdxdna_dev *xdna; + struct aie_device aie; const struct amdxdna_dev_priv *priv; void __iomem *sram_base; void __iomem *smu_base; void __iomem *mbox_base; struct psp_device *psp_hdl; - struct xdna_mailbox_chann_res mgmt_x2i; - struct xdna_mailbox_chann_res mgmt_i2x; - u32 mgmt_chan_idx; - u32 mgmt_prot_major; - u32 mgmt_prot_minor; - u32 total_col; struct aie_version version; struct aie_metadata metadata; - unsigned long feature_mask; struct aie2_exec_msg_ops *exec_msg_ops; /* power management and clock*/ @@ -237,7 +231,6 @@ struct amdxdna_dev_hdl { /* Mailbox and the management channel */ struct mailbox *mbox; - struct mailbox_channel *mgmt_chann; struct async_events *async_events; enum aie2_dev_status dev_status; @@ -266,21 +259,12 @@ enum aie2_fw_feature { AIE2_FEATURE_MAX }; -struct aie2_fw_feature_tbl { - u64 features; - u32 major; - u32 max_minor; - u32 min_minor; -}; - #define AIE2_ALL_FEATURES GENMASK_ULL(AIE2_FEATURE_MAX - 1, AIE2_NPU_COMMAND) -#define AIE2_FEATURE_ON(ndev, feature) test_bit(feature, &(ndev)->feature_mask) struct amdxdna_dev_priv { const char *fw_path; const struct rt_config *rt_config; const struct dpm_clk_freq *dpm_clk_tbl; - const struct aie2_fw_feature_tbl *fw_feature_tbl; #define COL_ALIGN_NONE 0 #define COL_ALIGN_NATURE 1 @@ -306,7 +290,7 @@ extern const struct dpm_clk_freq npu1_dpm_clk_table[]; extern const struct dpm_clk_freq npu4_dpm_clk_table[]; extern const struct rt_config npu1_default_rt_cfg[]; extern const struct rt_config npu4_default_rt_cfg[]; -extern const struct aie2_fw_feature_tbl npu4_fw_feature_table[]; +extern const struct amdxdna_fw_feature_tbl npu4_fw_feature_table[]; /* aie2_smu.c */ int aie2_smu_init(struct amdxdna_dev_hdl *ndev); diff --git a/drivers/accel/amdxdna/aie2_pm.c b/drivers/accel/amdxdna/aie2_pm.c index 29bd4403a94d..5ec6728d04fd 100644 --- a/drivers/accel/amdxdna/aie2_pm.c +++ b/drivers/accel/amdxdna/aie2_pm.c @@ -31,14 +31,14 @@ int aie2_pm_set_dpm(struct amdxdna_dev_hdl *ndev, u32 dpm_level) { int ret; - ret = amdxdna_pm_resume_get_locked(ndev->xdna); + ret = amdxdna_pm_resume_get_locked(ndev->aie.xdna); if (ret) return ret; ret = ndev->priv->hw_ops.set_dpm(ndev, dpm_level); if (!ret) ndev->dpm_level = dpm_level; - amdxdna_pm_suspend_put(ndev->xdna); + amdxdna_pm_suspend_put(ndev->aie.xdna); return ret; } @@ -81,7 +81,7 @@ int aie2_pm_init(struct amdxdna_dev_hdl *ndev) int aie2_pm_set_mode(struct amdxdna_dev_hdl *ndev, enum amdxdna_power_mode_type target) { - struct amdxdna_dev *xdna = ndev->xdna; + struct amdxdna_dev *xdna = ndev->aie.xdna; u32 clk_gating, dpm_level; int ret; diff --git a/drivers/accel/amdxdna/aie2_smu.c b/drivers/accel/amdxdna/aie2_smu.c index d8c31924e501..727637dac3a8 100644 --- a/drivers/accel/amdxdna/aie2_smu.c +++ b/drivers/accel/amdxdna/aie2_smu.c @@ -46,7 +46,7 @@ static int aie2_smu_exec(struct amdxdna_dev_hdl *ndev, u32 reg_cmd, ret = readx_poll_timeout(readl, SMU_REG(ndev, SMU_RESP_REG), resp, resp, AIE2_INTERVAL, AIE2_TIMEOUT); if (ret) { - XDNA_ERR(ndev->xdna, "smu cmd %d timed out", reg_cmd); + XDNA_ERR(ndev->aie.xdna, "smu cmd %d timed out", reg_cmd); return ret; } @@ -54,7 +54,7 @@ static int aie2_smu_exec(struct amdxdna_dev_hdl *ndev, u32 reg_cmd, *out = readl(SMU_REG(ndev, SMU_OUT_REG)); if (resp != SMU_RESULT_OK) { - XDNA_ERR(ndev->xdna, "smu cmd %d failed, 0x%x", reg_cmd, resp); + XDNA_ERR(ndev->aie.xdna, "smu cmd %d failed, 0x%x", reg_cmd, resp); return -EINVAL; } @@ -69,7 +69,7 @@ int npu1_set_dpm(struct amdxdna_dev_hdl *ndev, u32 dpm_level) ret = aie2_smu_exec(ndev, AIE2_SMU_SET_MPNPUCLK_FREQ, ndev->priv->dpm_clk_tbl[dpm_level].npuclk, &freq); if (ret) { - XDNA_ERR(ndev->xdna, "Set npu clock to %d failed, ret %d\n", + XDNA_ERR(ndev->aie.xdna, "Set npu clock to %d failed, ret %d\n", ndev->priv->dpm_clk_tbl[dpm_level].npuclk, ret); return ret; } @@ -78,7 +78,7 @@ int npu1_set_dpm(struct amdxdna_dev_hdl *ndev, u32 dpm_level) ret = aie2_smu_exec(ndev, AIE2_SMU_SET_HCLK_FREQ, ndev->priv->dpm_clk_tbl[dpm_level].hclk, &freq); if (ret) { - XDNA_ERR(ndev->xdna, "Set h clock to %d failed, ret %d\n", + XDNA_ERR(ndev->aie.xdna, "Set h clock to %d failed, ret %d\n", ndev->priv->dpm_clk_tbl[dpm_level].hclk, ret); return ret; } @@ -87,7 +87,7 @@ int npu1_set_dpm(struct amdxdna_dev_hdl *ndev, u32 dpm_level) ndev->max_tops = 2 * ndev->total_col; ndev->curr_tops = ndev->max_tops * freq / 1028; - XDNA_DBG(ndev->xdna, "MP-NPU clock %d, H clock %d\n", + XDNA_DBG(ndev->aie.xdna, "MP-NPU clock %d, H clock %d\n", ndev->npuclk_freq, ndev->hclk_freq); return 0; @@ -99,14 +99,14 @@ int npu4_set_dpm(struct amdxdna_dev_hdl *ndev, u32 dpm_level) ret = aie2_smu_exec(ndev, AIE2_SMU_SET_HARD_DPMLEVEL, dpm_level, NULL); if (ret) { - XDNA_ERR(ndev->xdna, "Set hard dpm level %d failed, ret %d ", + XDNA_ERR(ndev->aie.xdna, "Set hard dpm level %d failed, ret %d ", dpm_level, ret); return ret; } ret = aie2_smu_exec(ndev, AIE2_SMU_SET_SOFT_DPMLEVEL, dpm_level, NULL); if (ret) { - XDNA_ERR(ndev->xdna, "Set soft dpm level %d failed, ret %d", + XDNA_ERR(ndev->aie.xdna, "Set soft dpm level %d failed, ret %d", dpm_level, ret); return ret; } @@ -116,7 +116,7 @@ int npu4_set_dpm(struct amdxdna_dev_hdl *ndev, u32 dpm_level) ndev->max_tops = NPU4_DPM_TOPS(ndev, ndev->max_dpm_level); ndev->curr_tops = NPU4_DPM_TOPS(ndev, dpm_level); - XDNA_DBG(ndev->xdna, "MP-NPU clock %d, H clock %d\n", + XDNA_DBG(ndev->aie.xdna, "MP-NPU clock %d, H clock %d\n", ndev->npuclk_freq, ndev->hclk_freq); return 0; @@ -132,13 +132,13 @@ int aie2_smu_init(struct amdxdna_dev_hdl *ndev) */ ret = aie2_smu_exec(ndev, AIE2_SMU_POWER_OFF, 0, NULL); if (ret) { - XDNA_ERR(ndev->xdna, "Access power failed, ret %d", ret); + XDNA_ERR(ndev->aie.xdna, "Access power failed, ret %d", ret); return ret; } ret = aie2_smu_exec(ndev, AIE2_SMU_POWER_ON, 0, NULL); if (ret) { - XDNA_ERR(ndev->xdna, "Power on failed, ret %d", ret); + XDNA_ERR(ndev->aie.xdna, "Power on failed, ret %d", ret); return ret; } @@ -152,5 +152,5 @@ void aie2_smu_fini(struct amdxdna_dev_hdl *ndev) ndev->priv->hw_ops.set_dpm(ndev, 0); ret = aie2_smu_exec(ndev, AIE2_SMU_POWER_OFF, 0, NULL); if (ret) - XDNA_ERR(ndev->xdna, "Power off failed, ret %d", ret); + XDNA_ERR(ndev->aie.xdna, "Power off failed, ret %d", ret); } diff --git a/drivers/accel/amdxdna/amdxdna_pci_drv.h b/drivers/accel/amdxdna/amdxdna_pci_drv.h index 0661749917d6..5e0bf565a1ae 100644 --- a/drivers/accel/amdxdna/amdxdna_pci_drv.h +++ b/drivers/accel/amdxdna/amdxdna_pci_drv.h @@ -66,6 +66,13 @@ struct amdxdna_dev_ops { int (*get_array)(struct amdxdna_client *client, struct amdxdna_drm_get_array *args); }; +struct amdxdna_fw_feature_tbl { + u64 features; + u32 major; + u32 max_minor; + u32 min_minor; +}; + /* * struct amdxdna_dev_info - Device hardware information * Record device static information, like reg, mbox, PSP, SMU bar index @@ -83,6 +90,7 @@ struct amdxdna_dev_info { size_t dev_mem_size; char *vbnv; const struct amdxdna_dev_priv *dev_priv; + const struct amdxdna_fw_feature_tbl *fw_feature_tbl; const struct amdxdna_dev_ops *ops; }; diff --git a/drivers/accel/amdxdna/npu1_regs.c b/drivers/accel/amdxdna/npu1_regs.c index 1320e924e548..2ea7568a2e99 100644 --- a/drivers/accel/amdxdna/npu1_regs.c +++ b/drivers/accel/amdxdna/npu1_regs.c @@ -65,7 +65,7 @@ const struct dpm_clk_freq npu1_dpm_clk_table[] = { { 0 } }; -static const struct aie2_fw_feature_tbl npu1_fw_feature_table[] = { +static const struct amdxdna_fw_feature_tbl npu1_fw_feature_table[] = { { .major = 5, .min_minor = 7 }, { .features = BIT_U64(AIE2_NPU_COMMAND), .major = 5, .min_minor = 8 }, { 0 } @@ -75,7 +75,6 @@ static const struct amdxdna_dev_priv npu1_dev_priv = { .fw_path = "amdnpu/1502_00/", .rt_config = npu1_default_rt_cfg, .dpm_clk_tbl = npu1_dpm_clk_table, - .fw_feature_tbl = npu1_fw_feature_table, .col_align = COL_ALIGN_NONE, .mbox_dev_addr = NPU1_MBOX_BAR_BASE, .mbox_size = 0, /* Use BAR size */ @@ -120,5 +119,6 @@ const struct amdxdna_dev_info dev_npu1_info = { .vbnv = "RyzenAI-npu1", .device_type = AMDXDNA_DEV_TYPE_KMQ, .dev_priv = &npu1_dev_priv, + .fw_feature_tbl = npu1_fw_feature_table, .ops = &aie2_ops, }; diff --git a/drivers/accel/amdxdna/npu4_regs.c b/drivers/accel/amdxdna/npu4_regs.c index 619bff042e52..9689c56c83be 100644 --- a/drivers/accel/amdxdna/npu4_regs.c +++ b/drivers/accel/amdxdna/npu4_regs.c @@ -88,7 +88,7 @@ const struct dpm_clk_freq npu4_dpm_clk_table[] = { { 0 } }; -const struct aie2_fw_feature_tbl npu4_fw_feature_table[] = { +const struct amdxdna_fw_feature_tbl npu4_fw_feature_table[] = { { .major = 6, .min_minor = 12 }, { .features = BIT_U64(AIE2_NPU_COMMAND), .major = 6, .min_minor = 15 }, { .features = BIT_U64(AIE2_PREEMPT), .major = 6, .min_minor = 12 }, @@ -102,7 +102,6 @@ static const struct amdxdna_dev_priv npu4_dev_priv = { .fw_path = "amdnpu/17f0_10/", .rt_config = npu4_default_rt_cfg, .dpm_clk_tbl = npu4_dpm_clk_table, - .fw_feature_tbl = npu4_fw_feature_table, .col_align = COL_ALIGN_NATURE, .mbox_dev_addr = NPU4_MBOX_BAR_BASE, .mbox_size = 0, /* Use BAR size */ @@ -147,5 +146,6 @@ const struct amdxdna_dev_info dev_npu4_info = { .vbnv = "RyzenAI-npu4", .device_type = AMDXDNA_DEV_TYPE_KMQ, .dev_priv = &npu4_dev_priv, + .fw_feature_tbl = npu4_fw_feature_table, .ops = &aie2_ops, /* NPU4 can share NPU1's callback */ }; diff --git a/drivers/accel/amdxdna/npu5_regs.c b/drivers/accel/amdxdna/npu5_regs.c index c0ac5daf32ee..98ee8780f3f5 100644 --- a/drivers/accel/amdxdna/npu5_regs.c +++ b/drivers/accel/amdxdna/npu5_regs.c @@ -66,7 +66,6 @@ static const struct amdxdna_dev_priv npu5_dev_priv = { .fw_path = "amdnpu/17f0_11/", .rt_config = npu4_default_rt_cfg, .dpm_clk_tbl = npu4_dpm_clk_table, - .fw_feature_tbl = npu4_fw_feature_table, .col_align = COL_ALIGN_NATURE, .mbox_dev_addr = NPU5_MBOX_BAR_BASE, .mbox_size = 0, /* Use BAR size */ @@ -111,5 +110,6 @@ const struct amdxdna_dev_info dev_npu5_info = { .vbnv = "RyzenAI-npu5", .device_type = AMDXDNA_DEV_TYPE_KMQ, .dev_priv = &npu5_dev_priv, + .fw_feature_tbl = npu4_fw_feature_table, .ops = &aie2_ops, }; diff --git a/drivers/accel/amdxdna/npu6_regs.c b/drivers/accel/amdxdna/npu6_regs.c index ce591ed0d483..31400cca5ec4 100644 --- a/drivers/accel/amdxdna/npu6_regs.c +++ b/drivers/accel/amdxdna/npu6_regs.c @@ -66,7 +66,6 @@ static const struct amdxdna_dev_priv npu6_dev_priv = { .fw_path = "amdnpu/17f0_10/", .rt_config = npu4_default_rt_cfg, .dpm_clk_tbl = npu4_dpm_clk_table, - .fw_feature_tbl = npu4_fw_feature_table, .col_align = COL_ALIGN_NATURE, .mbox_dev_addr = NPU6_MBOX_BAR_BASE, .mbox_size = 0, /* Use BAR size */ @@ -112,5 +111,6 @@ const struct amdxdna_dev_info dev_npu6_info = { .vbnv = "RyzenAI-npu6", .device_type = AMDXDNA_DEV_TYPE_KMQ, .dev_priv = &npu6_dev_priv, + .fw_feature_tbl = npu4_fw_feature_table, .ops = &aie2_ops, }; -- cgit v1.2.3 From c02697cb9388b48086314fca90758016bd51b8e4 Mon Sep 17 00:00:00 2001 From: David Zhang Date: Mon, 30 Mar 2026 09:37:01 -0700 Subject: accel/amdxdna: Add basic support for AIE4 devices Add initial support for AIE4 devices (PCI device IDs 0x17F2 and 0x1B0B), including: Device initialization Basic mailbox communication SR-IOV enablement This lays the groundwork for full AIE4 support. Co-developed-by: Hayden Laccabue Signed-off-by: Hayden Laccabue Signed-off-by: David Zhang Reviewed-by: Mario Limonciello (AMD) Signed-off-by: Lizhi Hou Link: https://patch.msgid.link/20260330163705.3153647-3-lizhi.hou@amd.com --- drivers/accel/amdxdna/Makefile | 5 + drivers/accel/amdxdna/aie.h | 3 + drivers/accel/amdxdna/aie2_pci.c | 2 +- drivers/accel/amdxdna/aie2_pci.h | 3 - drivers/accel/amdxdna/aie2_smu.c | 2 +- drivers/accel/amdxdna/aie4_message.c | 27 +++ drivers/accel/amdxdna/aie4_msg_priv.h | 49 +++++ drivers/accel/amdxdna/aie4_pci.c | 364 ++++++++++++++++++++++++++++++++ drivers/accel/amdxdna/aie4_pci.h | 48 +++++ drivers/accel/amdxdna/aie4_sriov.c | 88 ++++++++ drivers/accel/amdxdna/amdxdna_mailbox.c | 19 +- drivers/accel/amdxdna/amdxdna_mailbox.h | 8 +- drivers/accel/amdxdna/amdxdna_pci_drv.c | 19 +- drivers/accel/amdxdna/amdxdna_pci_drv.h | 2 + drivers/accel/amdxdna/npu3_regs.c | 39 ++++ include/uapi/drm/amdxdna_accel.h | 3 +- 16 files changed, 666 insertions(+), 15 deletions(-) create mode 100644 drivers/accel/amdxdna/aie4_message.c create mode 100644 drivers/accel/amdxdna/aie4_msg_priv.h create mode 100644 drivers/accel/amdxdna/aie4_pci.c create mode 100644 drivers/accel/amdxdna/aie4_pci.h create mode 100644 drivers/accel/amdxdna/aie4_sriov.c create mode 100644 drivers/accel/amdxdna/npu3_regs.c diff --git a/drivers/accel/amdxdna/Makefile b/drivers/accel/amdxdna/Makefile index 5c7911554c46..a61cd6c0db30 100644 --- a/drivers/accel/amdxdna/Makefile +++ b/drivers/accel/amdxdna/Makefile @@ -10,6 +10,8 @@ amdxdna-y := \ aie2_psp.o \ aie2_smu.o \ aie2_solver.o \ + aie4_message.o \ + aie4_pci.o \ amdxdna_ctx.o \ amdxdna_gem.o \ amdxdna_iommu.o \ @@ -20,7 +22,10 @@ amdxdna-y := \ amdxdna_sysfs.o \ amdxdna_ubuf.o \ npu1_regs.o \ + npu3_regs.o \ npu4_regs.o \ npu5_regs.o \ npu6_regs.o + +amdxdna-$(CONFIG_PCI_IOV) += aie4_sriov.o obj-$(CONFIG_DRM_ACCEL_AMDXDNA) = amdxdna.o diff --git a/drivers/accel/amdxdna/aie.h b/drivers/accel/amdxdna/aie.h index 1bea14b79c7c..6c53870d0098 100644 --- a/drivers/accel/amdxdna/aie.h +++ b/drivers/accel/amdxdna/aie.h @@ -8,6 +8,9 @@ #include "amdxdna_pci_drv.h" #include "amdxdna_mailbox.h" +#define AIE_INTERVAL 20000 /* us */ +#define AIE_TIMEOUT 1000000 /* us */ + struct aie_device { struct amdxdna_dev *xdna; struct mailbox_channel *mgmt_chann; diff --git a/drivers/accel/amdxdna/aie2_pci.c b/drivers/accel/amdxdna/aie2_pci.c index 03bac963516d..708d0b7fd2e3 100644 --- a/drivers/accel/amdxdna/aie2_pci.c +++ b/drivers/accel/amdxdna/aie2_pci.c @@ -79,7 +79,7 @@ static int aie2_get_mgmt_chann_info(struct amdxdna_dev_hdl *ndev) * is alive. */ ret = readx_poll_timeout(readl, SRAM_GET_ADDR(ndev, FW_ALIVE_OFF), - addr, addr, AIE2_INTERVAL, AIE2_TIMEOUT); + addr, addr, AIE_INTERVAL, AIE_TIMEOUT); if (ret || !addr) return -ETIME; diff --git a/drivers/accel/amdxdna/aie2_pci.h b/drivers/accel/amdxdna/aie2_pci.h index 90fb0aafaf40..96960a2219a4 100644 --- a/drivers/accel/amdxdna/aie2_pci.h +++ b/drivers/accel/amdxdna/aie2_pci.h @@ -14,9 +14,6 @@ #include "aie2_msg_priv.h" #include "amdxdna_mailbox.h" -#define AIE2_INTERVAL 20000 /* us */ -#define AIE2_TIMEOUT 1000000 /* us */ - /* Firmware determines device memory base address and size */ #define AIE2_DEVM_BASE 0x4000000 #define AIE2_DEVM_SIZE SZ_64M diff --git a/drivers/accel/amdxdna/aie2_smu.c b/drivers/accel/amdxdna/aie2_smu.c index 727637dac3a8..1b966bbef2e5 100644 --- a/drivers/accel/amdxdna/aie2_smu.c +++ b/drivers/accel/amdxdna/aie2_smu.c @@ -44,7 +44,7 @@ static int aie2_smu_exec(struct amdxdna_dev_hdl *ndev, u32 reg_cmd, writel(1, SMU_REG(ndev, SMU_INTR_REG)); ret = readx_poll_timeout(readl, SMU_REG(ndev, SMU_RESP_REG), resp, - resp, AIE2_INTERVAL, AIE2_TIMEOUT); + resp, AIE_INTERVAL, AIE_TIMEOUT); if (ret) { XDNA_ERR(ndev->aie.xdna, "smu cmd %d timed out", reg_cmd); return ret; diff --git a/drivers/accel/amdxdna/aie4_message.c b/drivers/accel/amdxdna/aie4_message.c new file mode 100644 index 000000000000..d621dd32ac40 --- /dev/null +++ b/drivers/accel/amdxdna/aie4_message.c @@ -0,0 +1,27 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Copyright (C) 2026, Advanced Micro Devices, Inc. + */ + +#include +#include +#include + +#include "aie.h" +#include "aie4_msg_priv.h" +#include "aie4_pci.h" +#include "amdxdna_mailbox.h" +#include "amdxdna_mailbox_helper.h" +#include "amdxdna_pci_drv.h" + +int aie4_suspend_fw(struct amdxdna_dev_hdl *ndev) +{ + DECLARE_AIE_MSG(aie4_msg_suspend, AIE4_MSG_OP_SUSPEND); + int ret; + + ret = aie_send_mgmt_msg_wait(&ndev->aie, &msg); + if (ret) + XDNA_ERR(ndev->aie.xdna, "Failed to suspend fw, ret %d", ret); + + return ret; +} diff --git a/drivers/accel/amdxdna/aie4_msg_priv.h b/drivers/accel/amdxdna/aie4_msg_priv.h new file mode 100644 index 000000000000..88463cc3a98a --- /dev/null +++ b/drivers/accel/amdxdna/aie4_msg_priv.h @@ -0,0 +1,49 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* + * Copyright (C) 2026, Advanced Micro Devices, Inc. + */ + +#ifndef _AIE4_MSG_PRIV_H_ +#define _AIE4_MSG_PRIV_H_ + +#include + +enum aie4_msg_opcode { + AIE4_MSG_OP_SUSPEND = 0x10003, + + AIE4_MSG_OP_CREATE_VFS = 0x20001, + AIE4_MSG_OP_DESTROY_VFS = 0x20002, +}; + +enum aie4_msg_status { + AIE4_MSG_STATUS_SUCCESS = 0x0, + AIE4_MSG_STATUS_ERROR = 0x1, + AIE4_MSG_STATUS_NOTSUPP = 0x2, + MAX_AIE4_MSG_STATUS_CODE = 0x4, +}; + +struct aie4_msg_suspend_req { + __u32 rsvd; +} __packed; + +struct aie4_msg_suspend_resp { + enum aie4_msg_status status; +} __packed; + +struct aie4_msg_create_vfs_req { + __u32 vf_cnt; +} __packed; + +struct aie4_msg_create_vfs_resp { + enum aie4_msg_status status; +} __packed; + +struct aie4_msg_destroy_vfs_req { + __u32 rsvd; +} __packed; + +struct aie4_msg_destroy_vfs_resp { + enum aie4_msg_status status; +} __packed; + +#endif /* _AIE4_MSG_PRIV_H_ */ diff --git a/drivers/accel/amdxdna/aie4_pci.c b/drivers/accel/amdxdna/aie4_pci.c new file mode 100644 index 000000000000..0f360c1ccebd --- /dev/null +++ b/drivers/accel/amdxdna/aie4_pci.c @@ -0,0 +1,364 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Copyright (C) 2026, Advanced Micro Devices, Inc. + */ + +#include +#include +#include + +#include "aie4_pci.h" +#include "amdxdna_pci_drv.h" + +#define NO_IOHUB 0 + +/* + * The management mailbox channel is allocated by firmware. + * The related register and ring buffer information is on SRAM BAR. + * This struct is the register layout. + */ +struct mailbox_info { + __u32 valid; + __u32 protocol_major; + __u32 protocol_minor; + __u32 x2i_tail_offset; + __u32 x2i_head_offset; + __u32 x2i_buffer_addr; + __u32 x2i_buffer_size; + __u32 i2x_tail_offset; + __u32 i2x_head_offset; + __u32 i2x_buffer_addr; + __u32 i2x_buffer_size; + __u32 i2x_msi_idx; + __u32 reserved[4]; +}; + +static int aie4_fw_is_alive(struct amdxdna_dev *xdna) +{ + const struct amdxdna_dev_priv *npriv = xdna->dev_info->dev_priv; + struct amdxdna_dev_hdl *ndev = xdna->dev_handle; + u32 __iomem *src; + u32 fw_is_valid; + int ret; + + src = ndev->rbuf_base + npriv->mbox_info_off; + + ret = readx_poll_timeout(readl, src + offsetof(struct mailbox_info, valid), + fw_is_valid, (fw_is_valid == 0x1), + AIE_INTERVAL, AIE_TIMEOUT); + if (ret) + XDNA_ERR(xdna, "fw_is_valid=%d after %d ms", + fw_is_valid, DIV_ROUND_CLOSEST(AIE_TIMEOUT, 1000000)); + + return ret; +} + +static void aie4_read_mbox_info(struct amdxdna_dev *xdna, + struct mailbox_info *mbox_info) +{ + const struct amdxdna_dev_priv *npriv = xdna->dev_info->dev_priv; + struct amdxdna_dev_hdl *ndev = xdna->dev_handle; + u32 *dst = (u32 *)mbox_info; + u32 __iomem *src; + int i; + + src = ndev->rbuf_base + npriv->mbox_info_off; + + for (i = 0; i < sizeof(*mbox_info) / sizeof(u32); i++) + dst[i] = readl(&src[i]); +} + +static int aie4_mailbox_info(struct amdxdna_dev *xdna, + struct mailbox_info *mbox_info) +{ + int ret; + + ret = aie4_fw_is_alive(xdna); + if (ret) + return ret; + + aie4_read_mbox_info(xdna, mbox_info); + + ret = aie_check_protocol(&xdna->dev_handle->aie, + mbox_info->protocol_major, + mbox_info->protocol_minor); + if (ret) + XDNA_ERR(xdna, "mailbox major.minor %d.%d is not supported", + mbox_info->protocol_major, mbox_info->protocol_minor); + + return ret; +} + +static void aie4_mailbox_fini(struct amdxdna_dev_hdl *ndev) +{ + struct amdxdna_dev *xdna = ndev->aie.xdna; + + aie_destroy_chann(&ndev->aie, &ndev->aie.mgmt_chann); + drmm_kfree(&xdna->ddev, ndev->mbox); + ndev->mbox = NULL; +} + +static int aie4_irq_init(struct amdxdna_dev *xdna) +{ + struct pci_dev *pdev = to_pci_dev(xdna->ddev.dev); + int ret, nvec; + + nvec = pci_msix_vec_count(pdev); + XDNA_DBG(xdna, "irq vectors:%d", nvec); + if (nvec <= 0) { + XDNA_ERR(xdna, "does not get number of interrupt vector"); + return -EINVAL; + } + + ret = pci_alloc_irq_vectors(pdev, nvec, nvec, PCI_IRQ_MSIX); + if (ret < 0) { + XDNA_ERR(xdna, "failed to alloc irq vector, ret: %d", ret); + return ret; + } + + return 0; +} + +static int aie4_mailbox_start(struct amdxdna_dev *xdna, + struct mailbox_info *mbi) +{ + struct pci_dev *pdev = to_pci_dev(xdna->ddev.dev); + struct amdxdna_dev_hdl *ndev = xdna->dev_handle; + const struct amdxdna_dev_priv *npriv = xdna->dev_info->dev_priv; + struct xdna_mailbox_chann_res *i2x; + struct xdna_mailbox_chann_res *x2i; + int mgmt_mb_irq; + int ret; + + struct xdna_mailbox_res mbox_res = { + .ringbuf_base = ndev->rbuf_base, + .ringbuf_size = pci_resource_len(pdev, npriv->mbox_rbuf_bar), + .mbox_base = ndev->mbox_base, + .mbox_size = pci_resource_len(pdev, npriv->mbox_bar), + .name = "xdna_aie4_mailbox", + }; + + i2x = &ndev->aie.mgmt_i2x; + x2i = &ndev->aie.mgmt_x2i; + + x2i->mb_head_ptr_reg = mbi->x2i_head_offset; + x2i->mb_tail_ptr_reg = mbi->x2i_tail_offset; + x2i->rb_start_addr = mbi->x2i_buffer_addr; + x2i->rb_size = mbi->x2i_buffer_size; + + i2x->rb_start_addr = mbi->i2x_buffer_addr; + i2x->rb_size = mbi->i2x_buffer_size; + i2x->mb_head_ptr_reg = mbi->i2x_head_offset; + i2x->mb_tail_ptr_reg = mbi->i2x_tail_offset; + + ndev->aie.mgmt_chan_idx = mbi->i2x_msi_idx; + aie_dump_mgmt_chann_debug(&ndev->aie); + + ndev->mbox = xdnam_mailbox_create(&xdna->ddev, &mbox_res); + if (!ndev->mbox) { + XDNA_ERR(xdna, "failed to create mailbox device"); + return -ENODEV; + } + + ndev->aie.mgmt_chann = xdna_mailbox_alloc_channel(ndev->mbox); + if (!ndev->aie.mgmt_chann) { + XDNA_ERR(xdna, "failed to alloc mailbox channel"); + return -ENODEV; + } + + mgmt_mb_irq = pci_irq_vector(pdev, ndev->aie.mgmt_chan_idx); + if (mgmt_mb_irq < 0) { + XDNA_ERR(xdna, "failed to alloc irq vector, return %d", mgmt_mb_irq); + ret = mgmt_mb_irq; + goto free_channel; + } + + ret = xdna_mailbox_start_channel(ndev->aie.mgmt_chann, + &ndev->aie.mgmt_x2i, + &ndev->aie.mgmt_i2x, + NO_IOHUB, + mgmt_mb_irq); + if (ret) { + XDNA_ERR(xdna, "failed to start management mailbox channel"); + ret = -EINVAL; + goto free_channel; + } + + XDNA_DBG(xdna, "Mailbox management channel created"); + return 0; + +free_channel: + xdna_mailbox_free_channel(ndev->aie.mgmt_chann); + ndev->aie.mgmt_chann = NULL; + return ret; +} + +static int aie4_mailbox_init(struct amdxdna_dev *xdna) +{ + struct mailbox_info mbox_info; + int ret; + + ret = aie4_mailbox_info(xdna, &mbox_info); + if (ret) + return ret; + + return aie4_mailbox_start(xdna, &mbox_info); +} + +static void aie4_fw_unload(struct amdxdna_dev_hdl *ndev) +{ + /* TODO */ +} + +static int aie4_fw_load(struct amdxdna_dev_hdl *ndev) +{ + /* TODO */ + return 0; +} + +static int aie4_hw_start(struct amdxdna_dev *xdna) +{ + struct amdxdna_dev_hdl *ndev = xdna->dev_handle; + int ret; + + ret = aie4_fw_load(ndev); + if (ret) + return ret; + + ret = aie4_mailbox_init(xdna); + if (ret) + goto fw_unload; + + return 0; + +fw_unload: + aie4_fw_unload(ndev); + + return ret; +} + +static void aie4_mgmt_fw_fini(struct amdxdna_dev_hdl *ndev) +{ + int ret; + + /* No paired resume needed, fw is stateless */ + ret = aie4_suspend_fw(ndev); + if (ret) + XDNA_ERR(ndev->aie.xdna, "suspend_fw failed, ret %d", ret); + else + XDNA_DBG(ndev->aie.xdna, "npu firmware suspended"); +} + +static void aie4_hw_stop(struct amdxdna_dev *xdna) +{ + struct amdxdna_dev_hdl *ndev = xdna->dev_handle; + + drm_WARN_ON(&xdna->ddev, !mutex_is_locked(&xdna->dev_lock)); + + aie4_mgmt_fw_fini(ndev); + aie4_mailbox_fini(ndev); + + aie4_fw_unload(ndev); +} + +static int aie4_pcidev_init(struct amdxdna_dev_hdl *ndev) +{ + struct amdxdna_dev *xdna = ndev->aie.xdna; + struct pci_dev *pdev = to_pci_dev(xdna->ddev.dev); + void __iomem *tbl[PCI_NUM_RESOURCES] = {0}; + unsigned long bars = 0; + int ret, i; + + /* Enable managed PCI device */ + ret = pcim_enable_device(pdev); + if (ret) { + XDNA_ERR(xdna, "pcim enable device failed, ret %d", ret); + return ret; + } + + ret = dma_set_mask_and_coherent(&pdev->dev, DMA_BIT_MASK(64)); + if (ret) { + XDNA_ERR(xdna, "failed to set DMA mask to 64:%d", ret); + return ret; + } + + set_bit(xdna->dev_info->mbox_bar, &bars); + set_bit(xdna->dev_info->sram_bar, &bars); + + for (i = 0; i < PCI_NUM_RESOURCES; i++) { + if (!test_bit(i, &bars)) + continue; + tbl[i] = pcim_iomap(pdev, i, 0); + if (!tbl[i]) { + XDNA_ERR(xdna, "map bar %d failed", i); + return -ENOMEM; + } + } + + ndev->mbox_base = tbl[xdna->dev_info->mbox_bar]; + ndev->rbuf_base = tbl[xdna->dev_info->sram_bar]; + + pci_set_master(pdev); + + ret = aie4_irq_init(xdna); + if (ret) + goto clear_master; + + ret = aie4_hw_start(xdna); + if (ret) + goto clear_master; + + return 0; + +clear_master: + pci_clear_master(pdev); + + return ret; +} + +static void aie4_pcidev_fini(struct amdxdna_dev_hdl *ndev) +{ + struct amdxdna_dev *xdna = ndev->aie.xdna; + struct pci_dev *pdev = to_pci_dev(xdna->ddev.dev); + + aie4_hw_stop(xdna); + + pci_clear_master(pdev); +} + +static void aie4_fini(struct amdxdna_dev *xdna) +{ + struct amdxdna_dev_hdl *ndev = xdna->dev_handle; + + aie4_sriov_stop(ndev); + aie4_pcidev_fini(ndev); +} + +static int aie4_init(struct amdxdna_dev *xdna) +{ + struct amdxdna_dev_hdl *ndev; + int ret; + + ndev = drmm_kzalloc(&xdna->ddev, sizeof(*ndev), GFP_KERNEL); + if (!ndev) + return -ENOMEM; + + ndev->priv = xdna->dev_info->dev_priv; + ndev->aie.xdna = xdna; + xdna->dev_handle = ndev; + + ret = aie4_pcidev_init(ndev); + if (ret) { + XDNA_ERR(xdna, "Setup PCI device failed, ret %d", ret); + return ret; + } + + XDNA_DBG(xdna, "aie4 init finished"); + return 0; +} + +const struct amdxdna_dev_ops aie4_ops = { + .init = aie4_init, + .fini = aie4_fini, + .sriov_configure = aie4_sriov_configure, +}; diff --git a/drivers/accel/amdxdna/aie4_pci.h b/drivers/accel/amdxdna/aie4_pci.h new file mode 100644 index 000000000000..f3810a969431 --- /dev/null +++ b/drivers/accel/amdxdna/aie4_pci.h @@ -0,0 +1,48 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* + * Copyright (C) 2026, Advanced Micro Devices, Inc. + */ + +#ifndef _AIE4_PCI_H_ +#define _AIE4_PCI_H_ + +#include +#include +#include + +#include "aie.h" +#include "amdxdna_mailbox.h" + +struct amdxdna_dev_priv { + u32 mbox_bar; + u32 mbox_rbuf_bar; + u64 mbox_info_off; +}; + +struct amdxdna_dev_hdl { + struct aie_device aie; + const struct amdxdna_dev_priv *priv; + void __iomem *mbox_base; + void __iomem *rbuf_base; + + struct mailbox *mbox; +}; + +/* aie4_message.c */ +int aie4_suspend_fw(struct amdxdna_dev_hdl *ndev); + +/* aie4_sriov.c */ +#if IS_ENABLED(CONFIG_PCI_IOV) +int aie4_sriov_configure(struct amdxdna_dev *xdna, int num_vfs); +int aie4_sriov_stop(struct amdxdna_dev_hdl *ndev); +#else +#define aie4_sriov_configure NULL +static inline int aie4_sriov_stop(struct amdxdna_dev_hdl *ndev) +{ + return 0; +} +#endif + +extern const struct amdxdna_dev_ops aie4_ops; + +#endif /* _AIE4_PCI_H_ */ diff --git a/drivers/accel/amdxdna/aie4_sriov.c b/drivers/accel/amdxdna/aie4_sriov.c new file mode 100644 index 000000000000..e1ce633768a5 --- /dev/null +++ b/drivers/accel/amdxdna/aie4_sriov.c @@ -0,0 +1,88 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Copyright (C) 2026, Advanced Micro Devices, Inc. + */ + +#include +#include +#include + +#include "aie.h" +#include "aie4_msg_priv.h" +#include "aie4_pci.h" +#include "amdxdna_mailbox.h" +#include "amdxdna_mailbox_helper.h" +#include "amdxdna_pci_drv.h" + +static int aie4_destroy_vfs(struct amdxdna_dev_hdl *ndev) +{ + DECLARE_AIE_MSG(aie4_msg_destroy_vfs, AIE4_MSG_OP_DESTROY_VFS); + int ret; + + ret = aie_send_mgmt_msg_wait(&ndev->aie, &msg); + if (ret) + XDNA_ERR(ndev->aie.xdna, "destroy vfs op failed: %d", ret); + + return ret; +} + +static int aie4_create_vfs(struct amdxdna_dev_hdl *ndev, int num_vfs) +{ + DECLARE_AIE_MSG(aie4_msg_create_vfs, AIE4_MSG_OP_CREATE_VFS); + int ret; + + req.vf_cnt = num_vfs; + ret = aie_send_mgmt_msg_wait(&ndev->aie, &msg); + if (ret) + XDNA_ERR(ndev->aie.xdna, "create vfs op failed: %d", ret); + + return ret; +} + +int aie4_sriov_stop(struct amdxdna_dev_hdl *ndev) +{ + struct amdxdna_dev *xdna = ndev->aie.xdna; + struct pci_dev *pdev = to_pci_dev(xdna->ddev.dev); + int ret; + + if (!pci_num_vf(pdev)) + return 0; + + ret = pci_vfs_assigned(pdev); + if (ret) { + XDNA_ERR(xdna, "VFs are still assigned to VMs"); + return -EPERM; + } + + pci_disable_sriov(pdev); + return aie4_destroy_vfs(ndev); +} + +static int aie4_sriov_start(struct amdxdna_dev_hdl *ndev, int num_vfs) +{ + struct amdxdna_dev *xdna = ndev->aie.xdna; + struct pci_dev *pdev = to_pci_dev(xdna->ddev.dev); + int ret; + + ret = aie4_create_vfs(ndev, num_vfs); + if (ret) + return ret; + + ret = pci_enable_sriov(pdev, num_vfs); + if (ret) { + XDNA_ERR(xdna, "configure VFs failed, ret: %d", ret); + aie4_destroy_vfs(ndev); + return ret; + } + + return num_vfs; +} + +int aie4_sriov_configure(struct amdxdna_dev *xdna, int num_vfs) +{ + struct amdxdna_dev_hdl *ndev = xdna->dev_handle; + + drm_WARN_ON(&xdna->ddev, !mutex_is_locked(&xdna->dev_lock)); + + return (num_vfs) ? aie4_sriov_start(ndev, num_vfs) : aie4_sriov_stop(ndev); +} diff --git a/drivers/accel/amdxdna/amdxdna_mailbox.c b/drivers/accel/amdxdna/amdxdna_mailbox.c index e681a090752d..84a7e92562ad 100644 --- a/drivers/accel/amdxdna/amdxdna_mailbox.c +++ b/drivers/accel/amdxdna/amdxdna_mailbox.c @@ -112,6 +112,18 @@ static u32 mailbox_reg_read(struct mailbox_channel *mb_chann, u32 mbox_reg) return readl(ringbuf_addr); } +static inline void mailbox_irq_acknowledge(struct mailbox_channel *mb_chann) +{ + if (mb_chann->iohub_int_addr) + mailbox_reg_write(mb_chann, mb_chann->iohub_int_addr, 0); +} + +static inline u32 mailbox_irq_status(struct mailbox_channel *mb_chann) +{ + return (mb_chann->iohub_int_addr) ? + mailbox_reg_read(mb_chann, mb_chann->iohub_int_addr) : 0; +} + static inline void mailbox_set_headptr(struct mailbox_channel *mb_chann, u32 headptr_val) { @@ -199,7 +211,6 @@ mailbox_send_msg(struct mailbox_channel *mb_chann, struct mailbox_msg *mb_msg) start_addr = mb_chann->res[CHAN_RES_X2I].rb_start_addr; tmp_tail = tail + mb_msg->pkg_size; - check_again: if (tail >= head && tmp_tail > ringbuf_size) { write_addr = mb_chann->mb->res.ringbuf_base + start_addr + tail; @@ -357,7 +368,7 @@ static void mailbox_rx_worker(struct work_struct *rx_work) } again: - mailbox_reg_write(mb_chann, mb_chann->iohub_int_addr, 0); + mailbox_irq_acknowledge(mb_chann); while (1) { /* @@ -382,7 +393,7 @@ again: * the interrupt register to make sure there is not any new response * before exiting. */ - if (mailbox_reg_read(mb_chann, mb_chann->iohub_int_addr)) + if (mailbox_irq_status(mb_chann)) goto again; } @@ -520,7 +531,7 @@ xdna_mailbox_start_channel(struct mailbox_channel *mb_chann, } mb_chann->bad_state = false; - mailbox_reg_write(mb_chann, mb_chann->iohub_int_addr, 0); + mailbox_irq_acknowledge(mb_chann); MB_DBG(mb_chann, "Mailbox channel started (irq: %d)", mb_chann->msix_irq); return 0; diff --git a/drivers/accel/amdxdna/amdxdna_mailbox.h b/drivers/accel/amdxdna/amdxdna_mailbox.h index 8b1e00945da4..2908404303ae 100644 --- a/drivers/accel/amdxdna/amdxdna_mailbox.h +++ b/drivers/accel/amdxdna/amdxdna_mailbox.h @@ -1,10 +1,10 @@ /* SPDX-License-Identifier: GPL-2.0 */ /* - * Copyright (C) 2022-2024, Advanced Micro Devices, Inc. + * Copyright (C) 2022-2026, Advanced Micro Devices, Inc. */ -#ifndef _AIE2_MAILBOX_H_ -#define _AIE2_MAILBOX_H_ +#ifndef _AIE_MAILBOX_H_ +#define _AIE_MAILBOX_H_ struct mailbox; struct mailbox_channel; @@ -124,4 +124,4 @@ void xdna_mailbox_stop_channel(struct mailbox_channel *mailbox_chann); int xdna_mailbox_send_msg(struct mailbox_channel *mailbox_chann, const struct xdna_mailbox_msg *msg, u64 tx_timeout); -#endif /* _AIE2_MAILBOX_ */ +#endif /* _AIE_MAILBOX_ */ diff --git a/drivers/accel/amdxdna/amdxdna_pci_drv.c b/drivers/accel/amdxdna/amdxdna_pci_drv.c index b50a7d1f8a11..09d7d88bb6f1 100644 --- a/drivers/accel/amdxdna/amdxdna_pci_drv.c +++ b/drivers/accel/amdxdna/amdxdna_pci_drv.c @@ -37,9 +37,10 @@ MODULE_FIRMWARE("amdnpu/17f0_11/npu_7.sbin"); * 0.6: Support preemption * 0.7: Support getting power and utilization data * 0.8: Support BO usage query + * 0.9: Add new device type AMDXDNA_DEV_TYPE_PF */ #define AMDXDNA_DRIVER_MAJOR 0 -#define AMDXDNA_DRIVER_MINOR 8 +#define AMDXDNA_DRIVER_MINOR 9 /* * Bind the driver base on (vendor_id, device_id) pair and later use the @@ -49,6 +50,8 @@ MODULE_FIRMWARE("amdnpu/17f0_11/npu_7.sbin"); static const struct pci_device_id pci_ids[] = { { PCI_DEVICE(PCI_VENDOR_ID_AMD, 0x1502) }, { PCI_DEVICE(PCI_VENDOR_ID_AMD, 0x17f0) }, + { PCI_DEVICE(PCI_VENDOR_ID_AMD, 0x17f2) }, + { PCI_DEVICE(PCI_VENDOR_ID_AMD, 0x1B0B) }, {0} }; @@ -59,6 +62,8 @@ static const struct amdxdna_device_id amdxdna_ids[] = { { 0x17f0, 0x10, &dev_npu4_info }, { 0x17f0, 0x11, &dev_npu5_info }, { 0x17f0, 0x20, &dev_npu6_info }, + { 0x17f2, 0x10, &dev_npu3_pf_info }, + { 0x1B0B, 0x10, &dev_npu3_pf_info }, {0} }; @@ -365,12 +370,24 @@ static const struct dev_pm_ops amdxdna_pm_ops = { RUNTIME_PM_OPS(amdxdna_pm_suspend, amdxdna_pm_resume, NULL) }; +static int amdxdna_sriov_configure(struct pci_dev *pdev, int num_vfs) +{ + struct amdxdna_dev *xdna = pci_get_drvdata(pdev); + + guard(mutex)(&xdna->dev_lock); + if (xdna->dev_info->ops->sriov_configure) + return xdna->dev_info->ops->sriov_configure(xdna, num_vfs); + + return -ENOENT; +} + static struct pci_driver amdxdna_pci_driver = { .name = KBUILD_MODNAME, .id_table = pci_ids, .probe = amdxdna_probe, .remove = amdxdna_remove, .driver.pm = &amdxdna_pm_ops, + .sriov_configure = amdxdna_sriov_configure, }; module_pci_driver(amdxdna_pci_driver); diff --git a/drivers/accel/amdxdna/amdxdna_pci_drv.h b/drivers/accel/amdxdna/amdxdna_pci_drv.h index 5e0bf565a1ae..eabbf57f2b38 100644 --- a/drivers/accel/amdxdna/amdxdna_pci_drv.h +++ b/drivers/accel/amdxdna/amdxdna_pci_drv.h @@ -55,6 +55,7 @@ struct amdxdna_dev_ops { void (*fini)(struct amdxdna_dev *xdna); int (*resume)(struct amdxdna_dev *xdna); int (*suspend)(struct amdxdna_dev *xdna); + int (*sriov_configure)(struct amdxdna_dev *xdna, int num_vfs); int (*hwctx_init)(struct amdxdna_hwctx *hwctx); void (*hwctx_fini)(struct amdxdna_hwctx *hwctx); int (*hwctx_config)(struct amdxdna_hwctx *hwctx, u32 type, u64 value, void *buf, u32 size); @@ -157,6 +158,7 @@ struct amdxdna_client { /* Add device info below */ extern const struct amdxdna_dev_info dev_npu1_info; +extern const struct amdxdna_dev_info dev_npu3_pf_info; extern const struct amdxdna_dev_info dev_npu4_info; extern const struct amdxdna_dev_info dev_npu5_info; extern const struct amdxdna_dev_info dev_npu6_info; diff --git a/drivers/accel/amdxdna/npu3_regs.c b/drivers/accel/amdxdna/npu3_regs.c new file mode 100644 index 000000000000..f6e20f4858db --- /dev/null +++ b/drivers/accel/amdxdna/npu3_regs.c @@ -0,0 +1,39 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Copyright (C) 2026, Advanced Micro Devices, Inc. + */ + +#include +#include + +#include "aie4_pci.h" +#include "amdxdna_pci_drv.h" + +#define NPU3_MBOX_BAR 0 + +#define NPU3_MBOX_BUFFER_BAR 2 +#define NPU3_MBOX_INFO_OFF 0x0 + +/* PCIe BAR Index for NPU3 */ +#define NPU3_REG_BAR_INDEX 0 + +static const struct amdxdna_fw_feature_tbl npu3_fw_feature_table[] = { + { .major = 5, .min_minor = 10 }, + { 0 } +}; + +static const struct amdxdna_dev_priv npu3_dev_priv = { + .mbox_bar = NPU3_MBOX_BAR, + .mbox_rbuf_bar = NPU3_MBOX_BUFFER_BAR, + .mbox_info_off = NPU3_MBOX_INFO_OFF, +}; + +const struct amdxdna_dev_info dev_npu3_pf_info = { + .mbox_bar = NPU3_MBOX_BAR, + .sram_bar = NPU3_MBOX_BUFFER_BAR, + .vbnv = "RyzenAI-npu3-pf", + .device_type = AMDXDNA_DEV_TYPE_PF, + .dev_priv = &npu3_dev_priv, + .fw_feature_tbl = npu3_fw_feature_table, + .ops = &aie4_ops, +}; diff --git a/include/uapi/drm/amdxdna_accel.h b/include/uapi/drm/amdxdna_accel.h index 61d3686fa3b1..0b11e8e3ea5d 100644 --- a/include/uapi/drm/amdxdna_accel.h +++ b/include/uapi/drm/amdxdna_accel.h @@ -29,7 +29,8 @@ extern "C" { enum amdxdna_device_type { AMDXDNA_DEV_TYPE_UNKNOWN = -1, - AMDXDNA_DEV_TYPE_KMQ, + AMDXDNA_DEV_TYPE_KMQ = 0, + AMDXDNA_DEV_TYPE_PF = 2, }; enum amdxdna_drm_ioctl_id { -- cgit v1.2.3 From dd2f592b55dfce0028ed1710d71ff51ef6576064 Mon Sep 17 00:00:00 2001 From: David Zhang Date: Mon, 30 Mar 2026 09:37:02 -0700 Subject: accel/amdxdna: Create common PSP interfaces for AIE2 and AIE4 The AIE2 and AIE4 use the similar interface to PSP (Platform Security Processor). Move the PSP implementation into aie_psp.c so both platforms use the same path and future AIE4 PSP work can build on it. Co-developed-by: Hayden Laccabue Signed-off-by: Hayden Laccabue Signed-off-by: David Zhang Reviewed-by: Mario Limonciello (AMD) Signed-off-by: Lizhi Hou Link: https://patch.msgid.link/20260330163705.3153647-4-lizhi.hou@amd.com --- drivers/accel/amdxdna/Makefile | 2 +- drivers/accel/amdxdna/aie.h | 41 +++++++++ drivers/accel/amdxdna/aie2_message.c | 2 +- drivers/accel/amdxdna/aie2_pci.c | 12 +-- drivers/accel/amdxdna/aie2_pci.h | 44 +--------- drivers/accel/amdxdna/aie2_psp.c | 161 ----------------------------------- drivers/accel/amdxdna/aie_psp.c | 158 ++++++++++++++++++++++++++++++++++ 7 files changed, 211 insertions(+), 209 deletions(-) delete mode 100644 drivers/accel/amdxdna/aie2_psp.c create mode 100644 drivers/accel/amdxdna/aie_psp.c diff --git a/drivers/accel/amdxdna/Makefile b/drivers/accel/amdxdna/Makefile index a61cd6c0db30..d3c0fe765a8b 100644 --- a/drivers/accel/amdxdna/Makefile +++ b/drivers/accel/amdxdna/Makefile @@ -2,12 +2,12 @@ amdxdna-y := \ aie.o \ + aie_psp.o \ aie2_ctx.o \ aie2_error.o \ aie2_message.o \ aie2_pci.o \ aie2_pm.o \ - aie2_psp.o \ aie2_smu.o \ aie2_solver.o \ aie4_message.o \ diff --git a/drivers/accel/amdxdna/aie.h b/drivers/accel/amdxdna/aie.h index 6c53870d0098..124c0f7e9ca0 100644 --- a/drivers/accel/amdxdna/aie.h +++ b/drivers/accel/amdxdna/aie.h @@ -11,6 +11,8 @@ #define AIE_INTERVAL 20000 /* us */ #define AIE_TIMEOUT 1000000 /* us */ +struct psp_device; + struct aie_device { struct amdxdna_dev *xdna; struct mailbox_channel *mgmt_chann; @@ -20,15 +22,54 @@ struct aie_device { u32 mgmt_prot_major; u32 mgmt_prot_minor; unsigned long feature_mask; + + struct psp_device *psp_hdl; }; #define DECLARE_AIE_MSG(name, op) \ DECLARE_XDNA_MSG_COMMON(name, op, -1) #define AIE_FEATURE_ON(aie, feature) test_bit(feature, &(aie)->feature_mask) +#define PSP_REG_BAR(ndev, idx) ((ndev)->priv->psp_regs_off[(idx)].bar_idx) +#define PSP_REG_OFF(ndev, idx) ((ndev)->priv->psp_regs_off[(idx)].offset) + +#define DEFINE_BAR_OFFSET(reg_name, bar, reg_addr) \ + [reg_name] = {bar##_BAR_INDEX, (reg_addr) - bar##_BAR_BASE} + +enum psp_reg_idx { + PSP_CMD_REG = 0, + PSP_ARG0_REG, + PSP_ARG1_REG, + PSP_ARG2_REG, + PSP_NUM_IN_REGS, /* number of input registers */ + PSP_INTR_REG = PSP_NUM_IN_REGS, + PSP_STATUS_REG, + PSP_RESP_REG, + PSP_PWAITMODE_REG, + PSP_MAX_REGS /* Keep this at the end */ +}; + +struct aie_bar_off_pair { + int bar_idx; + u32 offset; +}; + +struct psp_config { + const void *fw_buf; + u32 fw_size; + void __iomem *psp_regs[PSP_MAX_REGS]; +}; + +/* aie.c */ void aie_dump_mgmt_chann_debug(struct aie_device *aie); void aie_destroy_chann(struct aie_device *aie, struct mailbox_channel **chann); int aie_send_mgmt_msg_wait(struct aie_device *aie, struct xdna_mailbox_msg *msg); int aie_check_protocol(struct aie_device *aie, u32 fw_major, u32 fw_minor); +/* aie_psp.c */ +struct psp_device *aiem_psp_create(struct drm_device *ddev, struct psp_config *conf); +int aie_psp_start(struct psp_device *psp); +void aie_psp_stop(struct psp_device *psp); +int aie_psp_waitmode_poll(struct psp_device *psp); + #endif /* _AIE_H_ */ diff --git a/drivers/accel/amdxdna/aie2_message.c b/drivers/accel/amdxdna/aie2_message.c index ccf87b1aa1cc..e5e7da7a8f40 100644 --- a/drivers/accel/amdxdna/aie2_message.c +++ b/drivers/accel/amdxdna/aie2_message.c @@ -75,7 +75,7 @@ int aie2_suspend_fw(struct amdxdna_dev_hdl *ndev) return ret; } - return aie2_psp_waitmode_poll(ndev->psp_hdl); + return aie_psp_waitmode_poll(ndev->aie.psp_hdl); } int aie2_resume_fw(struct amdxdna_dev_hdl *ndev) diff --git a/drivers/accel/amdxdna/aie2_pci.c b/drivers/accel/amdxdna/aie2_pci.c index 708d0b7fd2e3..e4b7893bd429 100644 --- a/drivers/accel/amdxdna/aie2_pci.c +++ b/drivers/accel/amdxdna/aie2_pci.c @@ -297,7 +297,7 @@ static void aie2_hw_stop(struct amdxdna_dev *xdna) aie_destroy_chann(&ndev->aie, &ndev->aie.mgmt_chann); drmm_kfree(&xdna->ddev, ndev->mbox); ndev->mbox = NULL; - aie2_psp_stop(ndev->psp_hdl); + aie_psp_stop(ndev->aie.psp_hdl); aie2_smu_fini(ndev); aie2_error_async_events_free(ndev); pci_disable_device(pdev); @@ -350,7 +350,7 @@ static int aie2_hw_start(struct amdxdna_dev *xdna) goto free_channel; } - ret = aie2_psp_start(ndev->psp_hdl); + ret = aie_psp_start(ndev->aie.psp_hdl); if (ret) { XDNA_ERR(xdna, "failed to start psp, ret %d", ret); goto fini_smu; @@ -413,7 +413,7 @@ stop_fw: aie2_suspend_fw(ndev); xdna_mailbox_stop_channel(ndev->aie.mgmt_chann); stop_psp: - aie2_psp_stop(ndev->psp_hdl); + aie_psp_stop(ndev->aie.psp_hdl); fini_smu: aie2_smu_fini(ndev); free_channel: @@ -463,7 +463,7 @@ static int aie2_init(struct amdxdna_dev *xdna) void __iomem *tbl[PCI_NUM_RESOURCES] = {0}; struct init_config xrs_cfg = { 0 }; struct amdxdna_dev_hdl *ndev; - struct psp_config psp_conf; + struct psp_config psp_conf = { 0 }; const struct firmware *fw; unsigned long bars = 0; char *fw_full_path; @@ -551,8 +551,8 @@ static int aie2_init(struct amdxdna_dev *xdna) psp_conf.fw_buf = fw->data; for (i = 0; i < PSP_MAX_REGS; i++) psp_conf.psp_regs[i] = tbl[PSP_REG_BAR(ndev, i)] + PSP_REG_OFF(ndev, i); - ndev->psp_hdl = aie2m_psp_create(&xdna->ddev, &psp_conf); - if (!ndev->psp_hdl) { + ndev->aie.psp_hdl = aiem_psp_create(&xdna->ddev, &psp_conf); + if (!ndev->aie.psp_hdl) { XDNA_ERR(xdna, "failed to create psp"); ret = -ENOMEM; goto release_fw; diff --git a/drivers/accel/amdxdna/aie2_pci.h b/drivers/accel/amdxdna/aie2_pci.h index 96960a2219a4..4f036b9fa096 100644 --- a/drivers/accel/amdxdna/aie2_pci.h +++ b/drivers/accel/amdxdna/aie2_pci.h @@ -1,6 +1,6 @@ /* SPDX-License-Identifier: GPL-2.0 */ /* - * Copyright (C) 2023-2024, Advanced Micro Devices, Inc. + * Copyright (C) 2023-2026, Advanced Micro Devices, Inc. */ #ifndef _AIE2_PCI_H_ @@ -23,8 +23,6 @@ #define AIE2_SRAM_OFF(ndev, addr) ((addr) - (ndev)->priv->sram_dev_addr) #define AIE2_MBOX_OFF(ndev, addr) ((addr) - (ndev)->priv->mbox_dev_addr) -#define PSP_REG_BAR(ndev, idx) ((ndev)->priv->psp_regs_off[(idx)].bar_idx) -#define PSP_REG_OFF(ndev, idx) ((ndev)->priv->psp_regs_off[(idx)].offset) #define SRAM_REG_OFF(ndev, idx) ((ndev)->priv->sram_offs[(idx)].offset) #define SMU_REG(ndev, idx) \ @@ -88,30 +86,11 @@ enum aie2_sram_reg_idx { SRAM_MAX_INDEX /* Keep this at the end */ }; -enum psp_reg_idx { - PSP_CMD_REG = 0, - PSP_ARG0_REG, - PSP_ARG1_REG, - PSP_ARG2_REG, - PSP_NUM_IN_REGS, /* number of input registers */ - PSP_INTR_REG = PSP_NUM_IN_REGS, - PSP_STATUS_REG, - PSP_RESP_REG, - PSP_PWAITMODE_REG, - PSP_MAX_REGS /* Keep this at the end */ -}; - struct amdxdna_client; struct amdxdna_fw_ver; struct amdxdna_hwctx; struct amdxdna_sched_job; -struct psp_config { - const void *fw_buf; - u32 fw_size; - void __iomem *psp_regs[PSP_MAX_REGS]; -}; - struct aie_version { u16 major; u16 minor; @@ -206,7 +185,6 @@ struct amdxdna_dev_hdl { void __iomem *sram_base; void __iomem *smu_base; void __iomem *mbox_base; - struct psp_device *psp_hdl; u32 total_col; struct aie_version version; @@ -236,14 +214,6 @@ struct amdxdna_dev_hdl { struct amdxdna_async_error last_async_err; }; -#define DEFINE_BAR_OFFSET(reg_name, bar, reg_addr) \ - [reg_name] = {bar##_BAR_INDEX, (reg_addr) - bar##_BAR_BASE} - -struct aie2_bar_off_pair { - int bar_idx; - u32 offset; -}; - struct aie2_hw_ops { int (*set_dpm)(struct amdxdna_dev_hdl *ndev, u32 dpm_level); }; @@ -271,9 +241,9 @@ struct amdxdna_dev_priv { u32 mbox_size; u32 hwctx_limit; u32 sram_dev_addr; - struct aie2_bar_off_pair sram_offs[SRAM_MAX_INDEX]; - struct aie2_bar_off_pair psp_regs_off[PSP_MAX_REGS]; - struct aie2_bar_off_pair smu_regs_off[SMU_MAX_REGS]; + struct aie_bar_off_pair sram_offs[SRAM_MAX_INDEX]; + struct aie_bar_off_pair psp_regs_off[PSP_MAX_REGS]; + struct aie_bar_off_pair smu_regs_off[SMU_MAX_REGS]; struct aie2_hw_ops hw_ops; }; @@ -300,12 +270,6 @@ int aie2_pm_init(struct amdxdna_dev_hdl *ndev); int aie2_pm_set_mode(struct amdxdna_dev_hdl *ndev, enum amdxdna_power_mode_type target); int aie2_pm_set_dpm(struct amdxdna_dev_hdl *ndev, u32 dpm_level); -/* aie2_psp.c */ -struct psp_device *aie2m_psp_create(struct drm_device *ddev, struct psp_config *conf); -int aie2_psp_start(struct psp_device *psp); -void aie2_psp_stop(struct psp_device *psp); -int aie2_psp_waitmode_poll(struct psp_device *psp); - /* aie2_error.c */ int aie2_error_async_events_alloc(struct amdxdna_dev_hdl *ndev); void aie2_error_async_events_free(struct amdxdna_dev_hdl *ndev); diff --git a/drivers/accel/amdxdna/aie2_psp.c b/drivers/accel/amdxdna/aie2_psp.c deleted file mode 100644 index 3a7130577e3e..000000000000 --- a/drivers/accel/amdxdna/aie2_psp.c +++ /dev/null @@ -1,161 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0 -/* - * Copyright (C) 2022-2024, Advanced Micro Devices, Inc. - */ - -#include -#include -#include -#include -#include -#include -#include - -#include "aie2_pci.h" -#include "amdxdna_mailbox.h" -#include "amdxdna_pci_drv.h" - -#define PSP_STATUS_READY BIT(31) - -/* PSP commands */ -#define PSP_VALIDATE 1 -#define PSP_START 2 -#define PSP_RELEASE_TMR 3 - -/* PSP special arguments */ -#define PSP_START_COPY_FW 1 - -/* PSP response error code */ -#define PSP_ERROR_CANCEL 0xFFFF0002 -#define PSP_ERROR_BAD_STATE 0xFFFF0007 - -#define PSP_FW_ALIGN 0x10000 -#define PSP_POLL_INTERVAL 20000 /* us */ -#define PSP_POLL_TIMEOUT 1000000 /* us */ - -#define PSP_REG(p, reg) ((p)->psp_regs[reg]) - -struct psp_device { - struct drm_device *ddev; - struct psp_config conf; - u32 fw_buf_sz; - u64 fw_paddr; - void *fw_buffer; - void __iomem *psp_regs[PSP_MAX_REGS]; -}; - -static int psp_exec(struct psp_device *psp, u32 *reg_vals) -{ - u32 resp_code; - int ret, i; - u32 ready; - - /* Write command and argument registers */ - for (i = 0; i < PSP_NUM_IN_REGS; i++) - writel(reg_vals[i], PSP_REG(psp, i)); - - /* clear and set PSP INTR register to kick off */ - writel(0, PSP_REG(psp, PSP_INTR_REG)); - writel(1, PSP_REG(psp, PSP_INTR_REG)); - - /* PSP should be busy. Wait for ready, so we know task is done. */ - ret = readx_poll_timeout(readl, PSP_REG(psp, PSP_STATUS_REG), ready, - FIELD_GET(PSP_STATUS_READY, ready), - PSP_POLL_INTERVAL, PSP_POLL_TIMEOUT); - if (ret) { - drm_err(psp->ddev, "PSP is not ready, ret 0x%x", ret); - return ret; - } - - resp_code = readl(PSP_REG(psp, PSP_RESP_REG)); - if (resp_code) { - drm_err(psp->ddev, "fw return error 0x%x", resp_code); - return -EIO; - } - - return 0; -} - -int aie2_psp_waitmode_poll(struct psp_device *psp) -{ - struct amdxdna_dev *xdna = to_xdna_dev(psp->ddev); - u32 mode_reg; - int ret; - - ret = readx_poll_timeout(readl, PSP_REG(psp, PSP_PWAITMODE_REG), mode_reg, - (mode_reg & 0x1) == 1, - PSP_POLL_INTERVAL, PSP_POLL_TIMEOUT); - if (ret) - XDNA_ERR(xdna, "fw waitmode reg error, ret %d", ret); - - return ret; -} - -void aie2_psp_stop(struct psp_device *psp) -{ - u32 reg_vals[PSP_NUM_IN_REGS] = { PSP_RELEASE_TMR, }; - int ret; - - ret = psp_exec(psp, reg_vals); - if (ret) - drm_err(psp->ddev, "release tmr failed, ret %d", ret); -} - -int aie2_psp_start(struct psp_device *psp) -{ - u32 reg_vals[PSP_NUM_IN_REGS]; - int ret; - - reg_vals[0] = PSP_VALIDATE; - reg_vals[1] = lower_32_bits(psp->fw_paddr); - reg_vals[2] = upper_32_bits(psp->fw_paddr); - reg_vals[3] = psp->fw_buf_sz; - - ret = psp_exec(psp, reg_vals); - if (ret) { - drm_err(psp->ddev, "failed to validate fw, ret %d", ret); - return ret; - } - - memset(reg_vals, 0, sizeof(reg_vals)); - reg_vals[0] = PSP_START; - reg_vals[1] = PSP_START_COPY_FW; - ret = psp_exec(psp, reg_vals); - if (ret) { - drm_err(psp->ddev, "failed to start fw, ret %d", ret); - return ret; - } - - return 0; -} - -struct psp_device *aie2m_psp_create(struct drm_device *ddev, struct psp_config *conf) -{ - struct psp_device *psp; - u64 offset; - - psp = drmm_kzalloc(ddev, sizeof(*psp), GFP_KERNEL); - if (!psp) - return NULL; - - psp->ddev = ddev; - memcpy(psp->psp_regs, conf->psp_regs, sizeof(psp->psp_regs)); - - psp->fw_buf_sz = ALIGN(conf->fw_size, PSP_FW_ALIGN); - psp->fw_buffer = drmm_kmalloc(ddev, psp->fw_buf_sz + PSP_FW_ALIGN, GFP_KERNEL); - if (!psp->fw_buffer) { - drm_err(ddev, "no memory for fw buffer"); - return NULL; - } - - /* - * AMD Platform Security Processor(PSP) requires host physical - * address to load NPU firmware. - */ - psp->fw_paddr = virt_to_phys(psp->fw_buffer); - offset = ALIGN(psp->fw_paddr, PSP_FW_ALIGN) - psp->fw_paddr; - psp->fw_paddr += offset; - memcpy(psp->fw_buffer + offset, conf->fw_buf, conf->fw_size); - - return psp; -} diff --git a/drivers/accel/amdxdna/aie_psp.c b/drivers/accel/amdxdna/aie_psp.c new file mode 100644 index 000000000000..8743b812a449 --- /dev/null +++ b/drivers/accel/amdxdna/aie_psp.c @@ -0,0 +1,158 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Copyright (C) 2026, Advanced Micro Devices, Inc. + */ + +#include +#include +#include +#include +#include +#include + +#include "aie.h" + +#define PSP_STATUS_READY BIT(31) + +/* PSP commands */ +#define PSP_VALIDATE 1 +#define PSP_START 2 +#define PSP_RELEASE_TMR 3 + +/* PSP special arguments */ +#define PSP_START_COPY_FW 1 + +/* PSP response error code */ +#define PSP_ERROR_CANCEL 0xFFFF0002 +#define PSP_ERROR_BAD_STATE 0xFFFF0007 + +#define PSP_FW_ALIGN 0x10000 +#define PSP_POLL_INTERVAL 20000 /* us */ +#define PSP_POLL_TIMEOUT 1000000 /* us */ + +#define PSP_REG(p, reg) ((p)->psp_regs[reg]) + +struct psp_device { + struct drm_device *ddev; + struct psp_config conf; + u32 fw_buf_sz; + u64 fw_paddr; + void *fw_buffer; + void __iomem *psp_regs[PSP_MAX_REGS]; +}; + +static int psp_exec(struct psp_device *psp, u32 *reg_vals) +{ + u32 resp_code; + int ret, i; + u32 ready; + + /* Write command and argument registers */ + for (i = 0; i < PSP_NUM_IN_REGS; i++) + writel(reg_vals[i], PSP_REG(psp, i)); + + /* clear and set PSP INTR register to kick off */ + writel(0, PSP_REG(psp, PSP_INTR_REG)); + writel(1, PSP_REG(psp, PSP_INTR_REG)); + + /* PSP should be busy. Wait for ready, so we know task is done. */ + ret = readx_poll_timeout(readl, PSP_REG(psp, PSP_STATUS_REG), ready, + FIELD_GET(PSP_STATUS_READY, ready), + PSP_POLL_INTERVAL, PSP_POLL_TIMEOUT); + if (ret) { + drm_err(psp->ddev, "PSP is not ready, ret 0x%x", ret); + return ret; + } + + resp_code = readl(PSP_REG(psp, PSP_RESP_REG)); + if (resp_code) { + drm_err(psp->ddev, "fw return error 0x%x", resp_code); + return -EIO; + } + + return 0; +} + +int aie_psp_waitmode_poll(struct psp_device *psp) +{ + struct amdxdna_dev *xdna = to_xdna_dev(psp->ddev); + u32 mode_reg; + int ret; + + ret = readx_poll_timeout(readl, PSP_REG(psp, PSP_PWAITMODE_REG), mode_reg, + (mode_reg & 0x1) == 1, + PSP_POLL_INTERVAL, PSP_POLL_TIMEOUT); + if (ret) + XDNA_ERR(xdna, "fw waitmode reg error, ret %d", ret); + + return ret; +} + +void aie_psp_stop(struct psp_device *psp) +{ + u32 reg_vals[PSP_NUM_IN_REGS] = { PSP_RELEASE_TMR, }; + int ret; + + ret = psp_exec(psp, reg_vals); + if (ret) + drm_err(psp->ddev, "release tmr failed, ret %d", ret); +} + +int aie_psp_start(struct psp_device *psp) +{ + u32 reg_vals[PSP_NUM_IN_REGS]; + int ret; + + reg_vals[0] = PSP_VALIDATE; + reg_vals[1] = lower_32_bits(psp->fw_paddr); + reg_vals[2] = upper_32_bits(psp->fw_paddr); + reg_vals[3] = psp->fw_buf_sz; + + ret = psp_exec(psp, reg_vals); + if (ret) { + drm_err(psp->ddev, "failed to validate fw, ret %d", ret); + return ret; + } + + memset(reg_vals, 0, sizeof(reg_vals)); + reg_vals[0] = PSP_START; + reg_vals[1] = PSP_START_COPY_FW; + ret = psp_exec(psp, reg_vals); + if (ret) { + drm_err(psp->ddev, "failed to start fw, ret %d", ret); + return ret; + } + + return 0; +} + +struct psp_device *aiem_psp_create(struct drm_device *ddev, struct psp_config *conf) +{ + struct psp_device *psp; + u64 offset; + + psp = drmm_kzalloc(ddev, sizeof(*psp), GFP_KERNEL); + if (!psp) + return NULL; + + psp->ddev = ddev; + memcpy(psp->psp_regs, conf->psp_regs, sizeof(psp->psp_regs)); + + psp->fw_buf_sz = ALIGN(conf->fw_size, PSP_FW_ALIGN); + psp->fw_buffer = drmm_kmalloc(ddev, psp->fw_buf_sz + PSP_FW_ALIGN, GFP_KERNEL); + if (!psp->fw_buffer) { + drm_err(ddev, "no memory for fw buffer"); + return NULL; + } + + /* + * AMD Platform Security Processor(PSP) requires host physical + * address to load NPU firmware. + */ + psp->fw_paddr = virt_to_phys(psp->fw_buffer); + offset = ALIGN(psp->fw_paddr, PSP_FW_ALIGN) - psp->fw_paddr; + psp->fw_paddr += offset; + memcpy(psp->fw_buffer + offset, conf->fw_buf, conf->fw_size); + + return psp; +} -- cgit v1.2.3 From e69ef21408fb8ed2be602e8056a5abd5b6212fd7 Mon Sep 17 00:00:00 2001 From: David Zhang Date: Mon, 30 Mar 2026 09:37:03 -0700 Subject: accel/amdxdna: Add AIE4 firmware loading Add support for loading AIE4 firmware through the common PSP interfaces. Compared to AIE2, AIE4 introduces an additional CERT firmware image. aiem_psp_create() performs CERT setup when the CERT image size is non-zero. Co-developed-by: Hayden Laccabue Signed-off-by: Hayden Laccabue Signed-off-by: David Zhang Reviewed-by: Mario Limonciello (AMD) Signed-off-by: Lizhi Hou Link: https://patch.msgid.link/20260330163705.3153647-5-lizhi.hou@amd.com --- drivers/accel/amdxdna/aie.h | 4 ++ drivers/accel/amdxdna/aie2_pci.c | 2 + drivers/accel/amdxdna/aie4_pci.c | 100 +++++++++++++++++++++++++-- drivers/accel/amdxdna/aie4_pci.h | 4 ++ drivers/accel/amdxdna/aie_psp.c | 141 +++++++++++++++++++++++++++++--------- drivers/accel/amdxdna/npu3_regs.c | 22 ++++++ 6 files changed, 237 insertions(+), 36 deletions(-) diff --git a/drivers/accel/amdxdna/aie.h b/drivers/accel/amdxdna/aie.h index 124c0f7e9ca0..423ed34af9ee 100644 --- a/drivers/accel/amdxdna/aie.h +++ b/drivers/accel/amdxdna/aie.h @@ -57,7 +57,11 @@ struct aie_bar_off_pair { struct psp_config { const void *fw_buf; u32 fw_size; + const void *certfw_buf; + u32 certfw_size; void __iomem *psp_regs[PSP_MAX_REGS]; + u32 arg2_mask; + u32 notify_val; }; /* aie.c */ diff --git a/drivers/accel/amdxdna/aie2_pci.c b/drivers/accel/amdxdna/aie2_pci.c index e4b7893bd429..0489e668cd73 100644 --- a/drivers/accel/amdxdna/aie2_pci.c +++ b/drivers/accel/amdxdna/aie2_pci.c @@ -549,6 +549,8 @@ static int aie2_init(struct amdxdna_dev *xdna) psp_conf.fw_size = fw->size; psp_conf.fw_buf = fw->data; + psp_conf.arg2_mask = GENMASK(23, 0); + psp_conf.notify_val = 1; for (i = 0; i < PSP_MAX_REGS; i++) psp_conf.psp_regs[i] = tbl[PSP_REG_BAR(ndev, i)] + PSP_REG_OFF(ndev, i); ndev->aie.psp_hdl = aiem_psp_create(&xdna->ddev, &psp_conf); diff --git a/drivers/accel/amdxdna/aie4_pci.c b/drivers/accel/amdxdna/aie4_pci.c index 0f360c1ccebd..c65b5ef97049 100644 --- a/drivers/accel/amdxdna/aie4_pci.c +++ b/drivers/accel/amdxdna/aie4_pci.c @@ -6,11 +6,14 @@ #include #include #include +#include +#include #include "aie4_pci.h" #include "amdxdna_pci_drv.h" -#define NO_IOHUB 0 +#define NO_IOHUB 0 +#define PSP_NOTIFY_INTR 0xD007BE11 /* * The management mailbox channel is allocated by firmware. @@ -207,13 +210,12 @@ static int aie4_mailbox_init(struct amdxdna_dev *xdna) static void aie4_fw_unload(struct amdxdna_dev_hdl *ndev) { - /* TODO */ + aie_psp_stop(ndev->aie.psp_hdl); } static int aie4_fw_load(struct amdxdna_dev_hdl *ndev) { - /* TODO */ - return 0; + return aie_psp_start(ndev->aie.psp_hdl); } static int aie4_hw_start(struct amdxdna_dev *xdna) @@ -261,11 +263,90 @@ static void aie4_hw_stop(struct amdxdna_dev *xdna) aie4_fw_unload(ndev); } +static int aie4_request_firmware(struct amdxdna_dev_hdl *ndev, + const struct firmware **npufw, + const struct firmware **certfw) +{ + struct amdxdna_dev *xdna = ndev->aie.xdna; + struct pci_dev *pdev = to_pci_dev(xdna->ddev.dev); + char fw_name[128]; + int ret; + + ret = snprintf(fw_name, sizeof(fw_name), "amdnpu/%04x_%02x/%s", + pdev->device, pdev->revision, ndev->priv->npufw_path); + if (ret >= sizeof(fw_name)) { + XDNA_ERR(xdna, "npu firmware path is truncated"); + return -EINVAL; + } + + ret = request_firmware(npufw, fw_name, &pdev->dev); + if (ret) { + XDNA_ERR(xdna, "failed to request_firmware %s, ret %d", fw_name, ret); + return ret; + } + + ret = snprintf(fw_name, sizeof(fw_name), "amdnpu/%04x_%02x/%s", + pdev->device, pdev->revision, ndev->priv->certfw_path); + if (ret >= sizeof(fw_name)) { + XDNA_ERR(xdna, "cert firmware path is truncated"); + ret = -EINVAL; + goto release_npufw; + } + + ret = request_firmware(certfw, fw_name, &pdev->dev); + if (ret) { + XDNA_ERR(xdna, "failed to request_firmware %s, ret %d", fw_name, ret); + goto release_npufw; + } + + return 0; + +release_npufw: + release_firmware(*npufw); + + return ret; +} + +static void aie4_release_firmware(struct amdxdna_dev_hdl *ndev, + const struct firmware *npufw, + const struct firmware *certfw) +{ + release_firmware(certfw); + release_firmware(npufw); +} + +static int aie4_prepare_firmware(struct amdxdna_dev_hdl *ndev, + const struct firmware *npufw, + const struct firmware *certfw, + void __iomem *tbl[PCI_NUM_RESOURCES]) +{ + struct amdxdna_dev *xdna = ndev->aie.xdna; + struct psp_config psp_conf; + int i; + + psp_conf.fw_size = npufw->size; + psp_conf.fw_buf = npufw->data; + psp_conf.certfw_size = certfw->size; + psp_conf.certfw_buf = certfw->data; + psp_conf.arg2_mask = ~0; + psp_conf.notify_val = PSP_NOTIFY_INTR; + for (i = 0; i < PSP_MAX_REGS; i++) + psp_conf.psp_regs[i] = tbl[PSP_REG_BAR(ndev, i)] + PSP_REG_OFF(ndev, i); + ndev->aie.psp_hdl = aiem_psp_create(&xdna->ddev, &psp_conf); + if (!ndev->aie.psp_hdl) { + XDNA_ERR(xdna, "failed to create psp"); + return -ENOMEM; + } + + return 0; +} + static int aie4_pcidev_init(struct amdxdna_dev_hdl *ndev) { struct amdxdna_dev *xdna = ndev->aie.xdna; struct pci_dev *pdev = to_pci_dev(xdna->ddev.dev); void __iomem *tbl[PCI_NUM_RESOURCES] = {0}; + const struct firmware *npufw, *certfw; unsigned long bars = 0; int ret, i; @@ -282,6 +363,8 @@ static int aie4_pcidev_init(struct amdxdna_dev_hdl *ndev) return ret; } + for (i = 0; i < PSP_MAX_REGS; i++) + set_bit(PSP_REG_BAR(ndev, i), &bars); set_bit(xdna->dev_info->mbox_bar, &bars); set_bit(xdna->dev_info->sram_bar, &bars); @@ -300,6 +383,15 @@ static int aie4_pcidev_init(struct amdxdna_dev_hdl *ndev) pci_set_master(pdev); + ret = aie4_request_firmware(ndev, &npufw, &certfw); + if (ret) + goto clear_master; + + ret = aie4_prepare_firmware(ndev, npufw, certfw, tbl); + aie4_release_firmware(ndev, npufw, certfw); + if (ret) + goto clear_master; + ret = aie4_irq_init(xdna); if (ret) goto clear_master; diff --git a/drivers/accel/amdxdna/aie4_pci.h b/drivers/accel/amdxdna/aie4_pci.h index f3810a969431..ee388ccf7196 100644 --- a/drivers/accel/amdxdna/aie4_pci.h +++ b/drivers/accel/amdxdna/aie4_pci.h @@ -14,9 +14,13 @@ #include "amdxdna_mailbox.h" struct amdxdna_dev_priv { + const char *npufw_path; + const char *certfw_path; u32 mbox_bar; u32 mbox_rbuf_bar; u64 mbox_info_off; + + struct aie_bar_off_pair psp_regs_off[PSP_MAX_REGS]; }; struct amdxdna_dev_hdl { diff --git a/drivers/accel/amdxdna/aie_psp.c b/drivers/accel/amdxdna/aie_psp.c index 8743b812a449..458dca7cc5a0 100644 --- a/drivers/accel/amdxdna/aie_psp.c +++ b/drivers/accel/amdxdna/aie_psp.c @@ -18,6 +18,7 @@ #define PSP_VALIDATE 1 #define PSP_START 2 #define PSP_RELEASE_TMR 3 +#define PSP_VALIDATE_CERT 4 /* PSP special arguments */ #define PSP_START_COPY_FW 1 @@ -27,10 +28,20 @@ #define PSP_ERROR_BAD_STATE 0xFFFF0007 #define PSP_FW_ALIGN 0x10000 +#define PSP_CFW_ALIGN 0x8000 #define PSP_POLL_INTERVAL 20000 /* us */ #define PSP_POLL_TIMEOUT 1000000 /* us */ -#define PSP_REG(p, reg) ((p)->psp_regs[reg]) +#define PSP_REG(p, reg) ((p)->conf.psp_regs[reg]) +#define PSP_SET_CMD(psp, reg_vals, cmd, arg0, arg1, arg2) \ +({ \ + u32 *_regs = reg_vals; \ + u32 _cmd = cmd; \ + _regs[0] = _cmd; \ + _regs[1] = arg0; \ + _regs[2] = arg1; \ + _regs[3] = ((arg2) | ((_cmd) << 24)) & (psp)->conf.arg2_mask; \ +}) struct psp_device { struct drm_device *ddev; @@ -38,7 +49,9 @@ struct psp_device { u32 fw_buf_sz; u64 fw_paddr; void *fw_buffer; - void __iomem *psp_regs[PSP_MAX_REGS]; + u32 certfw_buf_sz; + u64 certfw_paddr; + void *certfw_buffer; }; static int psp_exec(struct psp_device *psp, u32 *reg_vals) @@ -47,13 +60,22 @@ static int psp_exec(struct psp_device *psp, u32 *reg_vals) int ret, i; u32 ready; + /* Check for PSP ready before any write */ + ret = readx_poll_timeout(readl, PSP_REG(psp, PSP_STATUS_REG), ready, + FIELD_GET(PSP_STATUS_READY, ready), + PSP_POLL_INTERVAL, PSP_POLL_TIMEOUT); + if (ret) { + drm_err(psp->ddev, "PSP is not ready, ret 0x%x", ret); + return ret; + } + /* Write command and argument registers */ for (i = 0; i < PSP_NUM_IN_REGS; i++) writel(reg_vals[i], PSP_REG(psp, i)); /* clear and set PSP INTR register to kick off */ writel(0, PSP_REG(psp, PSP_INTR_REG)); - writel(1, PSP_REG(psp, PSP_INTR_REG)); + writel(psp->conf.notify_val, PSP_REG(psp, PSP_INTR_REG)); /* PSP should be busy. Wait for ready, so we know task is done. */ ret = readx_poll_timeout(readl, PSP_REG(psp, PSP_STATUS_REG), ready, @@ -90,69 +112,124 @@ int aie_psp_waitmode_poll(struct psp_device *psp) void aie_psp_stop(struct psp_device *psp) { - u32 reg_vals[PSP_NUM_IN_REGS] = { PSP_RELEASE_TMR, }; + u32 reg_vals[PSP_NUM_IN_REGS]; int ret; + PSP_SET_CMD(psp, reg_vals, PSP_RELEASE_TMR, 0, 0, 0); + ret = psp_exec(psp, reg_vals); if (ret) drm_err(psp->ddev, "release tmr failed, ret %d", ret); } -int aie_psp_start(struct psp_device *psp) +static int psp_validate_fw(struct psp_device *psp, u8 cmd, u64 paddr, u32 buf_sz) { u32 reg_vals[PSP_NUM_IN_REGS]; int ret; - reg_vals[0] = PSP_VALIDATE; - reg_vals[1] = lower_32_bits(psp->fw_paddr); - reg_vals[2] = upper_32_bits(psp->fw_paddr); - reg_vals[3] = psp->fw_buf_sz; + PSP_SET_CMD(psp, reg_vals, cmd, lower_32_bits(paddr), + upper_32_bits(paddr), buf_sz); ret = psp_exec(psp, reg_vals); - if (ret) { + if (ret) drm_err(psp->ddev, "failed to validate fw, ret %d", ret); - return ret; - } - memset(reg_vals, 0, sizeof(reg_vals)); - reg_vals[0] = PSP_START; - reg_vals[1] = PSP_START_COPY_FW; + return ret; +} + +static int psp_start(struct psp_device *psp) +{ + u32 reg_vals[PSP_NUM_IN_REGS]; + int ret; + + PSP_SET_CMD(psp, reg_vals, PSP_START, PSP_START_COPY_FW, 0, 0); + ret = psp_exec(psp, reg_vals); - if (ret) { + if (ret) drm_err(psp->ddev, "failed to start fw, ret %d", ret); + + return ret; +} + +int aie_psp_start(struct psp_device *psp) +{ + int ret; + + ret = psp_validate_fw(psp, PSP_VALIDATE, + psp->fw_paddr, psp->fw_buf_sz); + if (ret) return ret; - } - return 0; + if (!psp->certfw_buf_sz) + goto psp_start; + + ret = psp_validate_fw(psp, PSP_VALIDATE_CERT, + psp->certfw_paddr, psp->certfw_buf_sz); + if (ret) + return ret; +psp_start: + return psp_start(psp); +} + +/* + * PSP requires host physical address to load firmware. + * Allocate a buffer, obtain its physical address, align, and copy data in. + */ +static void *psp_alloc_fw_buf(struct psp_device *psp, const void *fw_data, + u32 fw_size, u32 align, u32 *buf_sz, + u64 *paddr) +{ + u32 alloc_sz; + void *buffer; + u64 offset; + + *buf_sz = ALIGN(fw_size, align); + alloc_sz = *buf_sz + align; + + buffer = drmm_kmalloc(psp->ddev, alloc_sz, GFP_KERNEL); + if (!buffer) + return NULL; + + *paddr = virt_to_phys(buffer); + offset = ALIGN(*paddr, align) - *paddr; + *paddr += offset; + memcpy(buffer + offset, fw_data, fw_size); + + return buffer; } struct psp_device *aiem_psp_create(struct drm_device *ddev, struct psp_config *conf) { struct psp_device *psp; - u64 offset; psp = drmm_kzalloc(ddev, sizeof(*psp), GFP_KERNEL); if (!psp) return NULL; psp->ddev = ddev; - memcpy(psp->psp_regs, conf->psp_regs, sizeof(psp->psp_regs)); + psp->fw_buffer = psp_alloc_fw_buf(psp, conf->fw_buf, conf->fw_size, + PSP_FW_ALIGN, &psp->fw_buf_sz, + &psp->fw_paddr); + if (!psp->fw_buffer) + return NULL; + + if (!conf->certfw_size) { + drm_dbg(ddev, "no cert fw"); + goto done; + } - psp->fw_buf_sz = ALIGN(conf->fw_size, PSP_FW_ALIGN); - psp->fw_buffer = drmm_kmalloc(ddev, psp->fw_buf_sz + PSP_FW_ALIGN, GFP_KERNEL); - if (!psp->fw_buffer) { - drm_err(ddev, "no memory for fw buffer"); + /* CERT firmware */ + psp->certfw_buffer = psp_alloc_fw_buf(psp, conf->certfw_buf, + conf->certfw_size, PSP_CFW_ALIGN, + &psp->certfw_buf_sz, + &psp->certfw_paddr); + if (!psp->certfw_buffer) { + drm_err(ddev, "no memory for cert fw buffer"); return NULL; } - /* - * AMD Platform Security Processor(PSP) requires host physical - * address to load NPU firmware. - */ - psp->fw_paddr = virt_to_phys(psp->fw_buffer); - offset = ALIGN(psp->fw_paddr, PSP_FW_ALIGN) - psp->fw_paddr; - psp->fw_paddr += offset; - memcpy(psp->fw_buffer + offset, conf->fw_buf, conf->fw_size); +done: + memcpy(&psp->conf, conf, sizeof(psp->conf)); return psp; } diff --git a/drivers/accel/amdxdna/npu3_regs.c b/drivers/accel/amdxdna/npu3_regs.c index f6e20f4858db..b896c8b80760 100644 --- a/drivers/accel/amdxdna/npu3_regs.c +++ b/drivers/accel/amdxdna/npu3_regs.c @@ -16,6 +16,15 @@ /* PCIe BAR Index for NPU3 */ #define NPU3_REG_BAR_INDEX 0 +#define NPU3_PSP_BAR_INDEX 4 + +#define MMNPU_APERTURE3_BASE 0x3810000 +#define NPU3_PSP_BAR_BASE MMNPU_APERTURE3_BASE + +#define MPASP_C2PMSG_123_ALT_1 0x3810AEC +#define MPASP_C2PMSG_156_ALT_1 0x3810B70 +#define MPASP_C2PMSG_157_ALT_1 0x3810B74 +#define MPASP_C2PMSG_73_ALT_1 0x3810A24 static const struct amdxdna_fw_feature_tbl npu3_fw_feature_table[] = { { .major = 5, .min_minor = 10 }, @@ -23,14 +32,27 @@ static const struct amdxdna_fw_feature_tbl npu3_fw_feature_table[] = { }; static const struct amdxdna_dev_priv npu3_dev_priv = { + .npufw_path = "npu.dev.sbin", + .certfw_path = "cert.dev.sbin", .mbox_bar = NPU3_MBOX_BAR, .mbox_rbuf_bar = NPU3_MBOX_BUFFER_BAR, .mbox_info_off = NPU3_MBOX_INFO_OFF, + .psp_regs_off = { + DEFINE_BAR_OFFSET(PSP_CMD_REG, NPU3_PSP, MPASP_C2PMSG_123_ALT_1), + DEFINE_BAR_OFFSET(PSP_ARG0_REG, NPU3_PSP, MPASP_C2PMSG_156_ALT_1), + DEFINE_BAR_OFFSET(PSP_ARG1_REG, NPU3_PSP, MPASP_C2PMSG_157_ALT_1), + DEFINE_BAR_OFFSET(PSP_ARG2_REG, NPU3_PSP, MPASP_C2PMSG_123_ALT_1), + DEFINE_BAR_OFFSET(PSP_INTR_REG, NPU3_PSP, MPASP_C2PMSG_73_ALT_1), + DEFINE_BAR_OFFSET(PSP_STATUS_REG, NPU3_PSP, MPASP_C2PMSG_123_ALT_1), + DEFINE_BAR_OFFSET(PSP_RESP_REG, NPU3_PSP, MPASP_C2PMSG_156_ALT_1), + /* npu3 doesn't use 8th pwaitmode register */ + }, }; const struct amdxdna_dev_info dev_npu3_pf_info = { .mbox_bar = NPU3_MBOX_BAR, .sram_bar = NPU3_MBOX_BUFFER_BAR, + .psp_bar = NPU3_PSP_BAR_INDEX, .vbnv = "RyzenAI-npu3-pf", .device_type = AMDXDNA_DEV_TYPE_PF, .dev_priv = &npu3_dev_priv, -- cgit v1.2.3 From 8167332554226b0c16ffc3b262afe562e6714bc1 Mon Sep 17 00:00:00 2001 From: David Zhang Date: Mon, 30 Mar 2026 09:37:04 -0700 Subject: accel/amdxdna: Create common SMU interfaces for AIE2 and AIE4 AIE2 and AIE4 use similar interfaces to the SMU (System Management Unit). Move the SMU implementation into aie_smu.c and provide common interfaces for both platforms. This allows AIE2 and AIE4 to share the same implementation and reduces code duplication. Co-developed-by: Hayden Laccabue Signed-off-by: Hayden Laccabue Signed-off-by: David Zhang Reviewed-by: Mario Limonciello (AMD) Signed-off-by: Lizhi Hou Link: https://patch.msgid.link/20260330163705.3153647-6-lizhi.hou@amd.com --- drivers/accel/amdxdna/Makefile | 2 +- drivers/accel/amdxdna/aie.h | 25 ++++++ drivers/accel/amdxdna/aie2_pci.c | 22 +++++- drivers/accel/amdxdna/aie2_pci.h | 20 ----- drivers/accel/amdxdna/aie2_smu.c | 156 -------------------------------------- drivers/accel/amdxdna/aie_smu.c | 153 +++++++++++++++++++++++++++++++++++++ drivers/accel/amdxdna/npu1_regs.c | 21 +++++ drivers/accel/amdxdna/npu4_regs.c | 26 +++++++ 8 files changed, 245 insertions(+), 180 deletions(-) delete mode 100644 drivers/accel/amdxdna/aie2_smu.c create mode 100644 drivers/accel/amdxdna/aie_smu.c diff --git a/drivers/accel/amdxdna/Makefile b/drivers/accel/amdxdna/Makefile index d3c0fe765a8b..79369e497540 100644 --- a/drivers/accel/amdxdna/Makefile +++ b/drivers/accel/amdxdna/Makefile @@ -3,12 +3,12 @@ amdxdna-y := \ aie.o \ aie_psp.o \ + aie_smu.o \ aie2_ctx.o \ aie2_error.o \ aie2_message.o \ aie2_pci.o \ aie2_pm.o \ - aie2_smu.o \ aie2_solver.o \ aie4_message.o \ aie4_pci.o \ diff --git a/drivers/accel/amdxdna/aie.h b/drivers/accel/amdxdna/aie.h index 423ed34af9ee..ba4c9ee21823 100644 --- a/drivers/accel/amdxdna/aie.h +++ b/drivers/accel/amdxdna/aie.h @@ -12,6 +12,7 @@ #define AIE_TIMEOUT 1000000 /* us */ struct psp_device; +struct smu_device; struct aie_device { struct amdxdna_dev *xdna; @@ -24,6 +25,7 @@ struct aie_device { unsigned long feature_mask; struct psp_device *psp_hdl; + struct smu_device *smu_hdl; }; #define DECLARE_AIE_MSG(name, op) \ @@ -33,9 +35,21 @@ struct aie_device { #define PSP_REG_BAR(ndev, idx) ((ndev)->priv->psp_regs_off[(idx)].bar_idx) #define PSP_REG_OFF(ndev, idx) ((ndev)->priv->psp_regs_off[(idx)].offset) +#define SMU_REG_BAR(ndev, idx) ((ndev)->priv->smu_regs_off[(idx)].bar_idx) +#define SMU_REG_OFF(ndev, idx) ((ndev)->priv->smu_regs_off[(idx)].offset) + #define DEFINE_BAR_OFFSET(reg_name, bar, reg_addr) \ [reg_name] = {bar##_BAR_INDEX, (reg_addr) - bar##_BAR_BASE} +enum smu_reg_idx { + SMU_CMD_REG = 0, + SMU_ARG_REG, + SMU_INTR_REG, + SMU_RESP_REG, + SMU_OUT_REG, + SMU_MAX_REGS /* Keep this at the end */ +}; + enum psp_reg_idx { PSP_CMD_REG = 0, PSP_ARG0_REG, @@ -54,6 +68,10 @@ struct aie_bar_off_pair { u32 offset; }; +struct smu_config { + void __iomem *smu_regs[SMU_MAX_REGS]; +}; + struct psp_config { const void *fw_buf; u32 fw_size; @@ -76,4 +94,11 @@ int aie_psp_start(struct psp_device *psp); void aie_psp_stop(struct psp_device *psp); int aie_psp_waitmode_poll(struct psp_device *psp); +/* aie_smu.c */ +struct smu_device *aiem_smu_create(struct drm_device *ddev, struct smu_config *conf); +int aie_smu_init(struct smu_device *smu); +void aie_smu_fini(struct smu_device *smu); +int aie_smu_set_clocks(struct smu_device *smu, u32 *npuclk, u32 *hclk); +int aie_smu_set_dpm(struct smu_device *smu, u32 dpm_level); + #endif /* _AIE_H_ */ diff --git a/drivers/accel/amdxdna/aie2_pci.c b/drivers/accel/amdxdna/aie2_pci.c index 0489e668cd73..164e188ba501 100644 --- a/drivers/accel/amdxdna/aie2_pci.c +++ b/drivers/accel/amdxdna/aie2_pci.c @@ -282,6 +282,12 @@ static struct xrs_action_ops aie2_xrs_actions = { .set_dft_dpm_level = aie2_xrs_set_dft_dpm_level, }; +static void aie2_smu_fini(struct amdxdna_dev_hdl *ndev) +{ + ndev->priv->hw_ops.set_dpm(ndev, 0); + aie_smu_fini(ndev->aie.smu_hdl); +} + static void aie2_hw_stop(struct amdxdna_dev *xdna) { struct pci_dev *pdev = to_pci_dev(xdna->ddev.dev); @@ -344,7 +350,7 @@ static int aie2_hw_start(struct amdxdna_dev *xdna) goto disable_dev; } - ret = aie2_smu_init(ndev); + ret = aie_smu_init(ndev->aie.smu_hdl); if (ret) { XDNA_ERR(xdna, "failed to init smu, ret %d", ret); goto free_channel; @@ -464,6 +470,7 @@ static int aie2_init(struct amdxdna_dev *xdna) struct init_config xrs_cfg = { 0 }; struct amdxdna_dev_hdl *ndev; struct psp_config psp_conf = { 0 }; + struct smu_config smu_conf; const struct firmware *fw; unsigned long bars = 0; char *fw_full_path; @@ -508,9 +515,10 @@ static int aie2_init(struct amdxdna_dev *xdna) for (i = 0; i < PSP_MAX_REGS; i++) set_bit(PSP_REG_BAR(ndev, i), &bars); + for (i = 0; i < SMU_MAX_REGS; i++) + set_bit(SMU_REG_BAR(ndev, i), &bars); set_bit(xdna->dev_info->sram_bar, &bars); - set_bit(xdna->dev_info->smu_bar, &bars); set_bit(xdna->dev_info->mbox_bar, &bars); for (i = 0; i < PCI_NUM_RESOURCES; i++) { @@ -525,7 +533,6 @@ static int aie2_init(struct amdxdna_dev *xdna) } ndev->sram_base = tbl[xdna->dev_info->sram_bar]; - ndev->smu_base = tbl[xdna->dev_info->smu_bar]; ndev->mbox_base = tbl[xdna->dev_info->mbox_bar]; ret = dma_set_mask_and_coherent(&pdev->dev, DMA_BIT_MASK(64)); @@ -559,6 +566,15 @@ static int aie2_init(struct amdxdna_dev *xdna) ret = -ENOMEM; goto release_fw; } + + for (i = 0; i < SMU_MAX_REGS; i++) + smu_conf.smu_regs[i] = tbl[SMU_REG_BAR(ndev, i)] + SMU_REG_OFF(ndev, i); + ndev->aie.smu_hdl = aiem_smu_create(&xdna->ddev, &smu_conf); + if (!ndev->aie.smu_hdl) { + XDNA_ERR(xdna, "failed to create smu"); + ret = -ENOMEM; + goto release_fw; + } xdna->dev_handle = ndev; ret = aie2_hw_start(xdna); diff --git a/drivers/accel/amdxdna/aie2_pci.h b/drivers/accel/amdxdna/aie2_pci.h index 4f036b9fa096..7c308672b5fe 100644 --- a/drivers/accel/amdxdna/aie2_pci.h +++ b/drivers/accel/amdxdna/aie2_pci.h @@ -25,11 +25,6 @@ #define SRAM_REG_OFF(ndev, idx) ((ndev)->priv->sram_offs[(idx)].offset) -#define SMU_REG(ndev, idx) \ -({ \ - typeof(ndev) _ndev = ndev; \ - ((_ndev)->smu_base + (_ndev)->priv->smu_regs_off[(idx)].offset); \ -}) #define SRAM_GET_ADDR(ndev, idx) \ ({ \ typeof(ndev) _ndev = ndev; \ @@ -71,15 +66,6 @@ }) #endif -enum aie2_smu_reg_idx { - SMU_CMD_REG = 0, - SMU_ARG_REG, - SMU_INTR_REG, - SMU_RESP_REG, - SMU_OUT_REG, - SMU_MAX_REGS /* Keep this at the end */ -}; - enum aie2_sram_reg_idx { MBOX_CHANN_OFF = 0, FW_ALIVE_OFF, @@ -183,7 +169,6 @@ struct amdxdna_dev_hdl { struct aie_device aie; const struct amdxdna_dev_priv *priv; void __iomem *sram_base; - void __iomem *smu_base; void __iomem *mbox_base; u32 total_col; @@ -258,11 +243,6 @@ extern const struct dpm_clk_freq npu4_dpm_clk_table[]; extern const struct rt_config npu1_default_rt_cfg[]; extern const struct rt_config npu4_default_rt_cfg[]; extern const struct amdxdna_fw_feature_tbl npu4_fw_feature_table[]; - -/* aie2_smu.c */ -int aie2_smu_init(struct amdxdna_dev_hdl *ndev); -void aie2_smu_fini(struct amdxdna_dev_hdl *ndev); -int npu1_set_dpm(struct amdxdna_dev_hdl *ndev, u32 dpm_level); int npu4_set_dpm(struct amdxdna_dev_hdl *ndev, u32 dpm_level); /* aie2_pm.c */ diff --git a/drivers/accel/amdxdna/aie2_smu.c b/drivers/accel/amdxdna/aie2_smu.c deleted file mode 100644 index 1b966bbef2e5..000000000000 --- a/drivers/accel/amdxdna/aie2_smu.c +++ /dev/null @@ -1,156 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0 -/* - * Copyright (C) 2022-2024, Advanced Micro Devices, Inc. - */ - -#include -#include -#include -#include -#include - -#include "aie2_pci.h" -#include "amdxdna_pci_drv.h" - -#define SMU_RESULT_OK 1 - -/* SMU commands */ -#define AIE2_SMU_POWER_ON 0x3 -#define AIE2_SMU_POWER_OFF 0x4 -#define AIE2_SMU_SET_MPNPUCLK_FREQ 0x5 -#define AIE2_SMU_SET_HCLK_FREQ 0x6 -#define AIE2_SMU_SET_SOFT_DPMLEVEL 0x7 -#define AIE2_SMU_SET_HARD_DPMLEVEL 0x8 - -#define NPU4_DPM_TOPS(ndev, dpm_level) \ -({ \ - typeof(ndev) _ndev = ndev; \ - (4096 * (_ndev)->total_col * \ - (_ndev)->priv->dpm_clk_tbl[dpm_level].hclk / 1000000); \ -}) - -static int aie2_smu_exec(struct amdxdna_dev_hdl *ndev, u32 reg_cmd, - u32 reg_arg, u32 *out) -{ - u32 resp; - int ret; - - writel(0, SMU_REG(ndev, SMU_RESP_REG)); - writel(reg_arg, SMU_REG(ndev, SMU_ARG_REG)); - writel(reg_cmd, SMU_REG(ndev, SMU_CMD_REG)); - - /* Clear and set SMU_INTR_REG to kick off */ - writel(0, SMU_REG(ndev, SMU_INTR_REG)); - writel(1, SMU_REG(ndev, SMU_INTR_REG)); - - ret = readx_poll_timeout(readl, SMU_REG(ndev, SMU_RESP_REG), resp, - resp, AIE_INTERVAL, AIE_TIMEOUT); - if (ret) { - XDNA_ERR(ndev->aie.xdna, "smu cmd %d timed out", reg_cmd); - return ret; - } - - if (out) - *out = readl(SMU_REG(ndev, SMU_OUT_REG)); - - if (resp != SMU_RESULT_OK) { - XDNA_ERR(ndev->aie.xdna, "smu cmd %d failed, 0x%x", reg_cmd, resp); - return -EINVAL; - } - - return 0; -} - -int npu1_set_dpm(struct amdxdna_dev_hdl *ndev, u32 dpm_level) -{ - u32 freq; - int ret; - - ret = aie2_smu_exec(ndev, AIE2_SMU_SET_MPNPUCLK_FREQ, - ndev->priv->dpm_clk_tbl[dpm_level].npuclk, &freq); - if (ret) { - XDNA_ERR(ndev->aie.xdna, "Set npu clock to %d failed, ret %d\n", - ndev->priv->dpm_clk_tbl[dpm_level].npuclk, ret); - return ret; - } - ndev->npuclk_freq = freq; - - ret = aie2_smu_exec(ndev, AIE2_SMU_SET_HCLK_FREQ, - ndev->priv->dpm_clk_tbl[dpm_level].hclk, &freq); - if (ret) { - XDNA_ERR(ndev->aie.xdna, "Set h clock to %d failed, ret %d\n", - ndev->priv->dpm_clk_tbl[dpm_level].hclk, ret); - return ret; - } - - ndev->hclk_freq = freq; - ndev->max_tops = 2 * ndev->total_col; - ndev->curr_tops = ndev->max_tops * freq / 1028; - - XDNA_DBG(ndev->aie.xdna, "MP-NPU clock %d, H clock %d\n", - ndev->npuclk_freq, ndev->hclk_freq); - - return 0; -} - -int npu4_set_dpm(struct amdxdna_dev_hdl *ndev, u32 dpm_level) -{ - int ret; - - ret = aie2_smu_exec(ndev, AIE2_SMU_SET_HARD_DPMLEVEL, dpm_level, NULL); - if (ret) { - XDNA_ERR(ndev->aie.xdna, "Set hard dpm level %d failed, ret %d ", - dpm_level, ret); - return ret; - } - - ret = aie2_smu_exec(ndev, AIE2_SMU_SET_SOFT_DPMLEVEL, dpm_level, NULL); - if (ret) { - XDNA_ERR(ndev->aie.xdna, "Set soft dpm level %d failed, ret %d", - dpm_level, ret); - return ret; - } - - ndev->npuclk_freq = ndev->priv->dpm_clk_tbl[dpm_level].npuclk; - ndev->hclk_freq = ndev->priv->dpm_clk_tbl[dpm_level].hclk; - ndev->max_tops = NPU4_DPM_TOPS(ndev, ndev->max_dpm_level); - ndev->curr_tops = NPU4_DPM_TOPS(ndev, dpm_level); - - XDNA_DBG(ndev->aie.xdna, "MP-NPU clock %d, H clock %d\n", - ndev->npuclk_freq, ndev->hclk_freq); - - return 0; -} - -int aie2_smu_init(struct amdxdna_dev_hdl *ndev) -{ - int ret; - - /* - * Failing to set power off indicates an unrecoverable hardware or - * firmware error. - */ - ret = aie2_smu_exec(ndev, AIE2_SMU_POWER_OFF, 0, NULL); - if (ret) { - XDNA_ERR(ndev->aie.xdna, "Access power failed, ret %d", ret); - return ret; - } - - ret = aie2_smu_exec(ndev, AIE2_SMU_POWER_ON, 0, NULL); - if (ret) { - XDNA_ERR(ndev->aie.xdna, "Power on failed, ret %d", ret); - return ret; - } - - return 0; -} - -void aie2_smu_fini(struct amdxdna_dev_hdl *ndev) -{ - int ret; - - ndev->priv->hw_ops.set_dpm(ndev, 0); - ret = aie2_smu_exec(ndev, AIE2_SMU_POWER_OFF, 0, NULL); - if (ret) - XDNA_ERR(ndev->aie.xdna, "Power off failed, ret %d", ret); -} diff --git a/drivers/accel/amdxdna/aie_smu.c b/drivers/accel/amdxdna/aie_smu.c new file mode 100644 index 000000000000..62aea550aabc --- /dev/null +++ b/drivers/accel/amdxdna/aie_smu.c @@ -0,0 +1,153 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Copyright (C) 2026, Advanced Micro Devices, Inc. + */ + +#include "drm/amdxdna_accel.h" +#include +#include +#include +#include +#include + +#include "aie.h" + +#define SMU_RESULT_OK 1 + +/* SMU commands */ +#define AIE_SMU_POWER_ON 0x3 +#define AIE_SMU_POWER_OFF 0x4 +#define AIE_SMU_SET_MPNPUCLK_FREQ 0x5 +#define AIE_SMU_SET_HCLK_FREQ 0x6 +#define AIE_SMU_SET_SOFT_DPMLEVEL 0x7 +#define AIE_SMU_SET_HARD_DPMLEVEL 0x8 + +#define SMU_REG(s, reg) ((s)->smu_regs[reg]) + +struct smu_device { + struct drm_device *ddev; + struct smu_config conf; + void __iomem *smu_regs[SMU_MAX_REGS]; +}; + +static int aie_smu_exec(struct smu_device *smu, u32 reg_cmd, u32 reg_arg, u32 *out) +{ + u32 resp; + int ret; + + writel(0, SMU_REG(smu, SMU_RESP_REG)); + writel(reg_arg, SMU_REG(smu, SMU_ARG_REG)); + writel(reg_cmd, SMU_REG(smu, SMU_CMD_REG)); + + /* Clear and set SMU_INTR_REG to kick off */ + writel(0, SMU_REG(smu, SMU_INTR_REG)); + writel(1, SMU_REG(smu, SMU_INTR_REG)); + + ret = readx_poll_timeout(readl, SMU_REG(smu, SMU_RESP_REG), resp, + resp, AIE_INTERVAL, AIE_TIMEOUT); + if (ret) { + drm_err(smu->ddev, "smu cmd %d timed out", reg_cmd); + return ret; + } + + if (out) + *out = readl(SMU_REG(smu, SMU_OUT_REG)); + + if (resp != SMU_RESULT_OK) { + drm_err(smu->ddev, "smu cmd %d failed, 0x%x", reg_cmd, resp); + return -EINVAL; + } + + return 0; +} + +int aie_smu_init(struct smu_device *smu) +{ + int ret; + + /* + * Failing to set power off indicates an unrecoverable hardware or + * firmware error. + */ + ret = aie_smu_exec(smu, AIE_SMU_POWER_OFF, 0, NULL); + if (ret) { + drm_err(smu->ddev, "Access power failed, ret %d", ret); + return ret; + } + + ret = aie_smu_exec(smu, AIE_SMU_POWER_ON, 0, NULL); + if (ret) { + drm_err(smu->ddev, "Power on failed, ret %d", ret); + return ret; + } + + return 0; +} + +void aie_smu_fini(struct smu_device *smu) +{ + int ret; + + ret = aie_smu_exec(smu, AIE_SMU_POWER_OFF, 0, NULL); + if (ret) + drm_err(smu->ddev, "Power off failed, ret %d", ret); +} + +int aie_smu_set_clocks(struct smu_device *smu, u32 *npuclk, u32 *hclk) +{ + int ret; + + if (npuclk) { + ret = aie_smu_exec(smu, AIE_SMU_SET_MPNPUCLK_FREQ, *npuclk, npuclk); + if (ret) { + drm_err(smu->ddev, "Set mpnpu clock to %d failed, ret %d", *npuclk, ret); + return ret; + } + } + + if (hclk) { + ret = aie_smu_exec(smu, AIE_SMU_SET_HCLK_FREQ, *hclk, hclk); + if (ret) { + drm_err(smu->ddev, "Set hclock to %d failed, ret %d", + *hclk, ret); + return ret; + } + } + + return 0; +} + +int aie_smu_set_dpm(struct smu_device *smu, u32 dpm_level) +{ + int ret; + + ret = aie_smu_exec(smu, AIE_SMU_SET_HARD_DPMLEVEL, dpm_level, NULL); + if (ret) { + drm_err(smu->ddev, "Set hard dpm level %d failed, ret %d", + dpm_level, ret); + return ret; + } + + ret = aie_smu_exec(smu, AIE_SMU_SET_SOFT_DPMLEVEL, dpm_level, NULL); + if (ret) { + drm_err(smu->ddev, "Set soft dpm level %d failed, ret %d", + dpm_level, ret); + return ret; + } + + return 0; +} + +struct smu_device *aiem_smu_create(struct drm_device *ddev, struct smu_config *conf) +{ + struct smu_device *smu; + + smu = drmm_kzalloc(ddev, sizeof(*smu), GFP_KERNEL); + if (!smu) + return NULL; + + smu->ddev = ddev; + memcpy(smu->smu_regs, conf->smu_regs, sizeof(smu->smu_regs)); + + return smu; +} diff --git a/drivers/accel/amdxdna/npu1_regs.c b/drivers/accel/amdxdna/npu1_regs.c index 2ea7568a2e99..a83e44f378ad 100644 --- a/drivers/accel/amdxdna/npu1_regs.c +++ b/drivers/accel/amdxdna/npu1_regs.c @@ -71,6 +71,27 @@ static const struct amdxdna_fw_feature_tbl npu1_fw_feature_table[] = { { 0 } }; +static int npu1_set_dpm(struct amdxdna_dev_hdl *ndev, u32 dpm_level) +{ + u32 npuclk, hclk; + int ret; + + npuclk = ndev->priv->dpm_clk_tbl[dpm_level].npuclk; + hclk = ndev->priv->dpm_clk_tbl[dpm_level].hclk; + ret = aie_smu_set_clocks(ndev->aie.smu_hdl, &npuclk, &hclk); + if (ret) + return ret; + + ndev->npuclk_freq = npuclk; + ndev->hclk_freq = hclk; + ndev->max_tops = 2 * ndev->total_col; + ndev->curr_tops = ndev->max_tops * hclk / 1028; + + XDNA_DBG(ndev->aie.xdna, "MP-NPU clock %d, H clock %d\n", + ndev->npuclk_freq, ndev->hclk_freq); + return 0; +} + static const struct amdxdna_dev_priv npu1_dev_priv = { .fw_path = "amdnpu/1502_00/", .rt_config = npu1_default_rt_cfg, diff --git a/drivers/accel/amdxdna/npu4_regs.c b/drivers/accel/amdxdna/npu4_regs.c index 9689c56c83be..5d68171f4ec2 100644 --- a/drivers/accel/amdxdna/npu4_regs.c +++ b/drivers/accel/amdxdna/npu4_regs.c @@ -63,6 +63,13 @@ #define NPU4_SMU_BAR_BASE MMNPU_APERTURE4_BASE #define NPU4_SRAM_BAR_BASE MMNPU_APERTURE1_BASE +#define NPU4_DPM_TOPS(ndev, dpm_level) \ +({ \ + typeof(ndev) _ndev = ndev; \ + (4096 * (_ndev)->total_col * \ + (_ndev)->priv->dpm_clk_tbl[dpm_level].hclk / 1000000); \ +}) + const struct rt_config npu4_default_rt_cfg[] = { { 5, 1, AIE2_RT_CFG_INIT }, /* PDI APP LOAD MODE */ { 10, 1, AIE2_RT_CFG_INIT }, /* DEBUG BUF */ @@ -98,6 +105,25 @@ const struct amdxdna_fw_feature_tbl npu4_fw_feature_table[] = { { 0 } }; +int npu4_set_dpm(struct amdxdna_dev_hdl *ndev, u32 dpm_level) +{ + int ret; + + ret = aie_smu_set_dpm(ndev->aie.smu_hdl, dpm_level); + if (ret) + return ret; + + ndev->npuclk_freq = ndev->priv->dpm_clk_tbl[dpm_level].npuclk; + ndev->hclk_freq = ndev->priv->dpm_clk_tbl[dpm_level].hclk; + ndev->max_tops = NPU4_DPM_TOPS(ndev, ndev->max_dpm_level); + ndev->curr_tops = NPU4_DPM_TOPS(ndev, dpm_level); + + XDNA_DBG(ndev->aie.xdna, "MP-NPU clock %d, H clock %d\n", + ndev->npuclk_freq, ndev->hclk_freq); + + return 0; +} + static const struct amdxdna_dev_priv npu4_dev_priv = { .fw_path = "amdnpu/17f0_10/", .rt_config = npu4_default_rt_cfg, -- cgit v1.2.3 From 43c9a66ea129cc5fd5d8920700ea75f4a6c42942 Mon Sep 17 00:00:00 2001 From: David Zhang Date: Mon, 30 Mar 2026 09:37:05 -0700 Subject: accel/amdxdna: Add AIE4 power on and off support Implement AIE4 power on and off control using the common SMU interfaces. Co-developed-by: Hayden Laccabue Signed-off-by: Hayden Laccabue Signed-off-by: David Zhang Reviewed-by: Mario Limonciello (AMD) Signed-off-by: Lizhi Hou Link: https://patch.msgid.link/20260330163705.3153647-7-lizhi.hou@amd.com --- drivers/accel/amdxdna/aie4_pci.c | 28 +++++++++++++++++++++++++++- drivers/accel/amdxdna/aie4_pci.h | 1 + drivers/accel/amdxdna/npu3_regs.c | 16 ++++++++++++++++ 3 files changed, 44 insertions(+), 1 deletion(-) diff --git a/drivers/accel/amdxdna/aie4_pci.c b/drivers/accel/amdxdna/aie4_pci.c index c65b5ef97049..f50e0bc566e4 100644 --- a/drivers/accel/amdxdna/aie4_pci.c +++ b/drivers/accel/amdxdna/aie4_pci.c @@ -211,11 +211,26 @@ static int aie4_mailbox_init(struct amdxdna_dev *xdna) static void aie4_fw_unload(struct amdxdna_dev_hdl *ndev) { aie_psp_stop(ndev->aie.psp_hdl); + aie_smu_fini(ndev->aie.smu_hdl); } static int aie4_fw_load(struct amdxdna_dev_hdl *ndev) { - return aie_psp_start(ndev->aie.psp_hdl); + int ret; + + ret = aie_smu_init(ndev->aie.smu_hdl); + if (ret) { + XDNA_ERR(ndev->aie.xdna, "failed to init smu, ret %d", ret); + return ret; + } + + ret = aie_psp_start(ndev->aie.psp_hdl); + if (ret) { + XDNA_ERR(ndev->aie.xdna, "failed to start psp, ret %d", ret); + aie_smu_fini(ndev->aie.smu_hdl); + } + + return ret; } static int aie4_hw_start(struct amdxdna_dev *xdna) @@ -322,6 +337,7 @@ static int aie4_prepare_firmware(struct amdxdna_dev_hdl *ndev, { struct amdxdna_dev *xdna = ndev->aie.xdna; struct psp_config psp_conf; + struct smu_config smu_conf; int i; psp_conf.fw_size = npufw->size; @@ -338,6 +354,14 @@ static int aie4_prepare_firmware(struct amdxdna_dev_hdl *ndev, return -ENOMEM; } + for (i = 0; i < SMU_MAX_REGS; i++) + smu_conf.smu_regs[i] = tbl[SMU_REG_BAR(ndev, i)] + SMU_REG_OFF(ndev, i); + ndev->aie.smu_hdl = aiem_smu_create(&xdna->ddev, &smu_conf); + if (!ndev->aie.smu_hdl) { + XDNA_ERR(xdna, "failed to create smu"); + return -ENOMEM; + } + return 0; } @@ -365,6 +389,8 @@ static int aie4_pcidev_init(struct amdxdna_dev_hdl *ndev) for (i = 0; i < PSP_MAX_REGS; i++) set_bit(PSP_REG_BAR(ndev, i), &bars); + for (i = 0; i < SMU_MAX_REGS; i++) + set_bit(SMU_REG_BAR(ndev, i), &bars); set_bit(xdna->dev_info->mbox_bar, &bars); set_bit(xdna->dev_info->sram_bar, &bars); diff --git a/drivers/accel/amdxdna/aie4_pci.h b/drivers/accel/amdxdna/aie4_pci.h index ee388ccf7196..aa1495c3370b 100644 --- a/drivers/accel/amdxdna/aie4_pci.h +++ b/drivers/accel/amdxdna/aie4_pci.h @@ -21,6 +21,7 @@ struct amdxdna_dev_priv { u64 mbox_info_off; struct aie_bar_off_pair psp_regs_off[PSP_MAX_REGS]; + struct aie_bar_off_pair smu_regs_off[SMU_MAX_REGS]; }; struct amdxdna_dev_hdl { diff --git a/drivers/accel/amdxdna/npu3_regs.c b/drivers/accel/amdxdna/npu3_regs.c index b896c8b80760..5a0bbc916094 100644 --- a/drivers/accel/amdxdna/npu3_regs.c +++ b/drivers/accel/amdxdna/npu3_regs.c @@ -17,15 +17,23 @@ /* PCIe BAR Index for NPU3 */ #define NPU3_REG_BAR_INDEX 0 #define NPU3_PSP_BAR_INDEX 4 +#define NPU3_SMU_BAR_INDEX 5 #define MMNPU_APERTURE3_BASE 0x3810000 +#define MMNPU_APERTURE4_BASE 0x3B10000 + #define NPU3_PSP_BAR_BASE MMNPU_APERTURE3_BASE +#define NPU3_SMU_BAR_BASE MMNPU_APERTURE4_BASE #define MPASP_C2PMSG_123_ALT_1 0x3810AEC #define MPASP_C2PMSG_156_ALT_1 0x3810B70 #define MPASP_C2PMSG_157_ALT_1 0x3810B74 #define MPASP_C2PMSG_73_ALT_1 0x3810A24 +#define MP1_C2PMSG_59_ALT_1 0x3B109EC +#define MP1_C2PMSG_61_ALT_1 0x3B109F4 +#define MP1_C2PMSG_60_ALT_1 0x3B109F0 + static const struct amdxdna_fw_feature_tbl npu3_fw_feature_table[] = { { .major = 5, .min_minor = 10 }, { 0 } @@ -47,12 +55,20 @@ static const struct amdxdna_dev_priv npu3_dev_priv = { DEFINE_BAR_OFFSET(PSP_RESP_REG, NPU3_PSP, MPASP_C2PMSG_156_ALT_1), /* npu3 doesn't use 8th pwaitmode register */ }, + .smu_regs_off = { + DEFINE_BAR_OFFSET(SMU_CMD_REG, NPU3_SMU, MP1_C2PMSG_59_ALT_1), + DEFINE_BAR_OFFSET(SMU_ARG_REG, NPU3_SMU, MP1_C2PMSG_61_ALT_1), + DEFINE_BAR_OFFSET(SMU_INTR_REG, NPU3_SMU, MMNPU_APERTURE4_BASE), + DEFINE_BAR_OFFSET(SMU_RESP_REG, NPU3_SMU, MP1_C2PMSG_60_ALT_1), + DEFINE_BAR_OFFSET(SMU_OUT_REG, NPU3_SMU, MP1_C2PMSG_61_ALT_1), + }, }; const struct amdxdna_dev_info dev_npu3_pf_info = { .mbox_bar = NPU3_MBOX_BAR, .sram_bar = NPU3_MBOX_BUFFER_BAR, .psp_bar = NPU3_PSP_BAR_INDEX, + .smu_bar = NPU3_SMU_BAR_INDEX, .vbnv = "RyzenAI-npu3-pf", .device_type = AMDXDNA_DEV_TYPE_PF, .dev_priv = &npu3_dev_priv, -- cgit v1.2.3 From b82a225e57a334335a21462b75ee2223bc6efe6d Mon Sep 17 00:00:00 2001 From: Matthew Brost Date: Wed, 25 Mar 2026 16:16:08 -0700 Subject: drm/gpusvm: Reject VMAs with VM_IO or VM_PFNMAP when creating SVM ranges MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit VMAs marked with VM_IO or VM_PFNMAP are not backed by struct page objects, which GPUSVM requires in order to operate correctly. In particular, get_pages() relies on hmm_range_fault() to resolve struct pages for the target range. Attempting to create an SVM range on such VMAs results in repeated get_pages() failures and can lead to an infinite loop inside a driver’s page‑fault handler. Prevent this by rejecting ranges on VM_IO or VM_PFNMAP VMAs and returning -EIO. Fixes: 99624bdff867 ("drm/gpusvm: Add support for GPU Shared Virtual Memory") Signed-off-by: Matthew Brost Reviewed-by: Himal Prasad Ghimiray Link: https://patch.msgid.link/20260325231608.25581-1-matthew.brost@intel.com --- drivers/gpu/drm/drm_gpusvm.c | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/drivers/gpu/drm/drm_gpusvm.c b/drivers/gpu/drm/drm_gpusvm.c index 4b928fda5b12..7993e85c0566 100644 --- a/drivers/gpu/drm/drm_gpusvm.c +++ b/drivers/gpu/drm/drm_gpusvm.c @@ -1065,6 +1065,11 @@ drm_gpusvm_range_find_or_insert(struct drm_gpusvm *gpusvm, goto err_notifier_remove; } + if (vas->vm_flags & (VM_IO | VM_PFNMAP)) { + err = -EIO; + goto err_notifier_remove; + } + range = drm_gpusvm_range_find(notifier, fault_addr, fault_addr + 1); if (range) goto out_mmunlock; -- cgit v1.2.3 From f649e63d4a6423eda8eb208638849fd6396aedd7 Mon Sep 17 00:00:00 2001 From: Max Zhen Date: Tue, 31 Mar 2026 10:26:35 -0700 Subject: accel/amdxdna: Support read-only user-pointer BO mappings Update the amdxdna user-pointer (ubuf) BO path to support creating buffer objects from read-only user mappings. Detect read-only VMAs by checking VMA permissions across all user virtual address ranges associated with the BO. When all entries are read-only, pin user pages without FOLL_WRITE and export the resulting dmabuf as read-only (O_RDONLY). This allows userptr BOs backed by read-only mappings to be safely imported and used without requiring write access, which was previously rejected due to unconditional FOLL_WRITE usage. Reviewed-by: Mario Limonciello (AMD) Signed-off-by: Max Zhen Signed-off-by: Lizhi Hou Link: https://patch.msgid.link/20260331172635.3275296-1-lizhi.hou@amd.com --- drivers/accel/amdxdna/amdxdna_ubuf.c | 29 +++++++++++++++++++++++++++-- 1 file changed, 27 insertions(+), 2 deletions(-) diff --git a/drivers/accel/amdxdna/amdxdna_ubuf.c b/drivers/accel/amdxdna/amdxdna_ubuf.c index 4c0647057759..3769210c55cc 100644 --- a/drivers/accel/amdxdna/amdxdna_ubuf.c +++ b/drivers/accel/amdxdna/amdxdna_ubuf.c @@ -125,6 +125,26 @@ static const struct dma_buf_ops amdxdna_ubuf_dmabuf_ops = { .vunmap = amdxdna_ubuf_vunmap, }; +static int readonly_va_entry(struct amdxdna_drm_va_entry *va_ent) +{ + struct mm_struct *mm = current->mm; + struct vm_area_struct *vma; + int ret; + + mmap_read_lock(mm); + + vma = find_vma(mm, va_ent->vaddr); + if (!vma || + vma->vm_start > va_ent->vaddr || + vma->vm_end - va_ent->vaddr < va_ent->len) + ret = -ENOENT; + else + ret = vma->vm_flags & VM_WRITE ? 0 : 1; + + mmap_read_unlock(mm); + return ret; +} + struct dma_buf *amdxdna_get_ubuf(struct drm_device *dev, u32 num_entries, void __user *va_entries) { @@ -134,6 +154,7 @@ struct dma_buf *amdxdna_get_ubuf(struct drm_device *dev, struct amdxdna_ubuf_priv *ubuf; u32 npages, start = 0; struct dma_buf *dbuf; + bool readonly = true; int i, ret; DEFINE_DMA_BUF_EXPORT_INFO(exp_info); @@ -172,6 +193,10 @@ struct dma_buf *amdxdna_get_ubuf(struct drm_device *dev, ret = -EINVAL; goto free_ent; } + + /* Pin pages as writable as long as not all entries are read-only. */ + if (readonly && readonly_va_entry(&va_ent[i]) != 1) + readonly = false; } ubuf->nr_pages = exp_info.size >> PAGE_SHIFT; @@ -194,7 +219,7 @@ struct dma_buf *amdxdna_get_ubuf(struct drm_device *dev, npages = va_ent[i].len >> PAGE_SHIFT; ret = pin_user_pages_fast(va_ent[i].vaddr, npages, - FOLL_WRITE | FOLL_LONGTERM, + (readonly ? 0 : FOLL_WRITE) | FOLL_LONGTERM, &ubuf->pages[start]); if (ret >= 0) { start += ret; @@ -211,7 +236,7 @@ struct dma_buf *amdxdna_get_ubuf(struct drm_device *dev, exp_info.ops = &amdxdna_ubuf_dmabuf_ops; exp_info.priv = ubuf; - exp_info.flags = O_RDWR | O_CLOEXEC; + exp_info.flags = (readonly ? O_RDONLY : O_RDWR) | O_CLOEXEC; dbuf = dma_buf_export(&exp_info); if (IS_ERR(dbuf)) { -- cgit v1.2.3 From da0cdc1c329dd2ff09c41fbbe9fbd9c92c5d2c6e Mon Sep 17 00:00:00 2001 From: Jouni Högander Date: Fri, 27 Mar 2026 13:45:53 +0200 Subject: drm/i915/psr: Do not use pipe_src as borders for SU area MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This far using crtc_state->pipe_src as borders for Selective Update area haven't caused visible problems as drm_rect_width(crtc_state->pipe_src) == crtc_state->hw.adjusted_mode.crtc_hdisplay and drm_rect_height(crtc_state->pipe_src) == crtc_state->hw.adjusted_mode.crtc_vdisplay when pipe scaling is not used. On the other hand using pipe scaling is forcing full frame updates and all the Selective Update area calculations are skipped. Now this improper usage of crtc_state->pipe_src is causing following warnings: <4> [7771.978166] xe 0000:00:02.0: [drm] drm_WARN_ON_ONCE(su_lines % vdsc_cfg->slice_height) after WARN_ON_ONCE was added by commit: "drm/i915/dsc: Add helper for writing DSC Selective Update ET parameters" These warnings are seen when DSC and pipe scaling are enabled simultaneously. This is because on full frame update SU area is improperly set as pipe_src which is not aligned with DSC slice height. Fix these by creating local rectangle using crtc_state->hw.adjusted_mode.crtc_hdisplay and crtc_state->hw.adjusted_mode.crtc_vdisplay. Use this local rectangle as borders for SU area. Fixes: d6774b8c3c58 ("drm/i915: Ensure damage clip area is within pipe area") Cc: # v6.0+ Signed-off-by: Jouni Högander Reviewed-by: Mika Kahola Link: https://patch.msgid.link/20260327114553.195285-1-jouni.hogander@intel.com --- drivers/gpu/drm/i915/display/intel_psr.c | 30 +++++++++++++++++++----------- 1 file changed, 19 insertions(+), 11 deletions(-) diff --git a/drivers/gpu/drm/i915/display/intel_psr.c b/drivers/gpu/drm/i915/display/intel_psr.c index 2f1b48cd8efd..998c3faf5f2e 100644 --- a/drivers/gpu/drm/i915/display/intel_psr.c +++ b/drivers/gpu/drm/i915/display/intel_psr.c @@ -2689,9 +2689,9 @@ static u32 psr2_pipe_srcsz_early_tpt_calc(struct intel_crtc_state *crtc_state, static void clip_area_update(struct drm_rect *overlap_damage_area, struct drm_rect *damage_area, - struct drm_rect *pipe_src) + struct drm_rect *display_area) { - if (!drm_rect_intersect(damage_area, pipe_src)) + if (!drm_rect_intersect(damage_area, display_area)) return; if (overlap_damage_area->y1 == -1) { @@ -2742,6 +2742,7 @@ static bool intel_psr2_sel_fetch_pipe_alignment(struct intel_crtc_state *crtc_st static void intel_psr2_sel_fetch_et_alignment(struct intel_atomic_state *state, struct intel_crtc *crtc, + struct drm_rect *display_area, bool *cursor_in_su_area) { struct intel_crtc_state *crtc_state = intel_atomic_get_new_crtc_state(state, crtc); @@ -2769,7 +2770,7 @@ intel_psr2_sel_fetch_et_alignment(struct intel_atomic_state *state, continue; clip_area_update(&crtc_state->psr2_su_area, &new_plane_state->uapi.dst, - &crtc_state->pipe_src); + display_area); *cursor_in_su_area = true; } } @@ -2866,6 +2867,12 @@ int intel_psr2_sel_fetch_update(struct intel_atomic_state *state, struct intel_crtc_state *crtc_state = intel_atomic_get_new_crtc_state(state, crtc); struct intel_plane_state *new_plane_state, *old_plane_state; struct intel_plane *plane; + struct drm_rect display_area = { + .x1 = 0, + .y1 = 0, + .x2 = crtc_state->hw.adjusted_mode.crtc_hdisplay, + .y2 = crtc_state->hw.adjusted_mode.crtc_vdisplay, + }; bool full_update = false, su_area_changed; int i, ret; @@ -2879,7 +2886,7 @@ int intel_psr2_sel_fetch_update(struct intel_atomic_state *state, crtc_state->psr2_su_area.x1 = 0; crtc_state->psr2_su_area.y1 = -1; - crtc_state->psr2_su_area.x2 = drm_rect_width(&crtc_state->pipe_src); + crtc_state->psr2_su_area.x2 = drm_rect_width(&display_area); crtc_state->psr2_su_area.y2 = -1; /* @@ -2917,14 +2924,14 @@ int intel_psr2_sel_fetch_update(struct intel_atomic_state *state, damaged_area.y1 = old_plane_state->uapi.dst.y1; damaged_area.y2 = old_plane_state->uapi.dst.y2; clip_area_update(&crtc_state->psr2_su_area, &damaged_area, - &crtc_state->pipe_src); + &display_area); } if (new_plane_state->uapi.visible) { damaged_area.y1 = new_plane_state->uapi.dst.y1; damaged_area.y2 = new_plane_state->uapi.dst.y2; clip_area_update(&crtc_state->psr2_su_area, &damaged_area, - &crtc_state->pipe_src); + &display_area); } continue; } else if (new_plane_state->uapi.alpha != old_plane_state->uapi.alpha) { @@ -2932,7 +2939,7 @@ int intel_psr2_sel_fetch_update(struct intel_atomic_state *state, damaged_area.y1 = new_plane_state->uapi.dst.y1; damaged_area.y2 = new_plane_state->uapi.dst.y2; clip_area_update(&crtc_state->psr2_su_area, &damaged_area, - &crtc_state->pipe_src); + &display_area); continue; } @@ -2948,7 +2955,7 @@ int intel_psr2_sel_fetch_update(struct intel_atomic_state *state, damaged_area.x1 += new_plane_state->uapi.dst.x1 - src.x1; damaged_area.x2 += new_plane_state->uapi.dst.x1 - src.x1; - clip_area_update(&crtc_state->psr2_su_area, &damaged_area, &crtc_state->pipe_src); + clip_area_update(&crtc_state->psr2_su_area, &damaged_area, &display_area); } /* @@ -2983,7 +2990,8 @@ int intel_psr2_sel_fetch_update(struct intel_atomic_state *state, * cursor is added into affected planes even when * cursor is not updated by itself. */ - intel_psr2_sel_fetch_et_alignment(state, crtc, &cursor_in_su_area); + intel_psr2_sel_fetch_et_alignment(state, crtc, &display_area, + &cursor_in_su_area); su_area_changed = intel_psr2_sel_fetch_pipe_alignment(crtc_state); @@ -3059,8 +3067,8 @@ int intel_psr2_sel_fetch_update(struct intel_atomic_state *state, skip_sel_fetch_set_loop: if (full_update) - clip_area_update(&crtc_state->psr2_su_area, &crtc_state->pipe_src, - &crtc_state->pipe_src); + clip_area_update(&crtc_state->psr2_su_area, &display_area, + &display_area); psr2_man_trk_ctl_calc(crtc_state, full_update); crtc_state->pipe_srcsz_early_tpt = -- cgit v1.2.3 From 37b58ada0c39eb7c0b04f96615407e26e73834b5 Mon Sep 17 00:00:00 2001 From: Jani Nikula Date: Tue, 31 Mar 2026 12:49:14 +0300 Subject: drm/xe/fbdev: put intel_fbdev_fb_prefer_stolen() behind IS_ENABLED(CONFIG_DRM_FBDEV_EMULATION) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Unify the behaviour with i915. Similar to commit b63c6b9b7f5e ("drm/i915/fbdev: fix link failure without FBDEV emulation"). The difference is that unlike i915, xe doesn't build display/intel_fbdev_fb.c conditional to CONFIG_DRM_FBDEV_EMULATION. Reviewed-by: Michał Grzelak Link: https://patch.msgid.link/245880a591fe5267a1c06bfbbcc42a4dd9f2e4ee.1774950508.git.jani.nikula@intel.com Signed-off-by: Jani Nikula --- drivers/gpu/drm/xe/display/xe_initial_plane.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/gpu/drm/xe/display/xe_initial_plane.c b/drivers/gpu/drm/xe/display/xe_initial_plane.c index 8bcae552dddc..d44746f4966c 100644 --- a/drivers/gpu/drm/xe/display/xe_initial_plane.c +++ b/drivers/gpu/drm/xe/display/xe_initial_plane.c @@ -86,6 +86,7 @@ initial_plane_bo(struct xe_device *xe, flags |= XE_BO_FLAG_STOLEN; if (IS_ENABLED(CONFIG_FRAMEBUFFER_CONSOLE) && + IS_ENABLED(CONFIG_DRM_FBDEV_EMULATION) && !intel_fbdev_fb_prefer_stolen(&xe->drm, plane_config->size)) { drm_info(&xe->drm, "Initial FB size exceeds half of stolen, discarding\n"); return NULL; -- cgit v1.2.3 From b35b3148a78a5c545b2ac7981c182238431286cb Mon Sep 17 00:00:00 2001 From: Jani Nikula Date: Tue, 31 Mar 2026 12:49:15 +0300 Subject: drm/{i915, xe}/fbdev: drop drm device parameter from intel_fbdev_fb_fill_info() MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The struct drm_device *drm parameter of intel_fbdev_fb_fill_info() is redundant, as you can obtain the same information via obj->dev. Drop the drm parameter, and move obj as first (or the context) parameter. Reviewed-by: Michał Grzelak Link: https://patch.msgid.link/6c617dc41c07b0e3e9af01b82d0d1dadbd4760fc.1774950508.git.jani.nikula@intel.com Signed-off-by: Jani Nikula --- drivers/gpu/drm/i915/display/intel_fbdev.c | 2 +- drivers/gpu/drm/i915/display/intel_fbdev_fb.c | 8 ++++---- drivers/gpu/drm/i915/display/intel_fbdev_fb.h | 4 ++-- drivers/gpu/drm/xe/display/intel_fbdev_fb.c | 6 +++--- 4 files changed, 10 insertions(+), 10 deletions(-) diff --git a/drivers/gpu/drm/i915/display/intel_fbdev.c b/drivers/gpu/drm/i915/display/intel_fbdev.c index bdaaf3edba0c..6401aaaba199 100644 --- a/drivers/gpu/drm/i915/display/intel_fbdev.c +++ b/drivers/gpu/drm/i915/display/intel_fbdev.c @@ -327,7 +327,7 @@ int intel_fbdev_driver_fbdev_probe(struct drm_fb_helper *helper, obj = intel_fb_bo(&fb->base); - ret = intel_fbdev_fb_fill_info(display->drm, info, obj, vma); + ret = intel_fbdev_fb_fill_info(obj, info, vma); if (ret) goto out_unpin; diff --git a/drivers/gpu/drm/i915/display/intel_fbdev_fb.c b/drivers/gpu/drm/i915/display/intel_fbdev_fb.c index 6f84eb6355de..a696ce42d10b 100644 --- a/drivers/gpu/drm/i915/display/intel_fbdev_fb.c +++ b/drivers/gpu/drm/i915/display/intel_fbdev_fb.c @@ -66,10 +66,10 @@ void intel_fbdev_fb_bo_destroy(struct drm_gem_object *obj) drm_gem_object_put(obj); } -int intel_fbdev_fb_fill_info(struct drm_device *drm, struct fb_info *info, - struct drm_gem_object *_obj, struct i915_vma *vma) +int intel_fbdev_fb_fill_info(struct drm_gem_object *_obj, struct fb_info *info, + struct i915_vma *vma) { - struct drm_i915_private *i915 = to_i915(drm); + struct drm_i915_private *i915 = to_i915(_obj->dev); struct drm_i915_gem_object *obj = to_intel_bo(_obj); struct i915_gem_ww_ctx ww; void __iomem *vaddr; @@ -101,7 +101,7 @@ int intel_fbdev_fb_fill_info(struct drm_device *drm, struct fb_info *info, vaddr = i915_vma_pin_iomap(vma); if (IS_ERR(vaddr)) { - drm_err(drm, + drm_err(&i915->drm, "Failed to remap framebuffer into virtual memory (%pe)\n", vaddr); ret = PTR_ERR(vaddr); continue; diff --git a/drivers/gpu/drm/i915/display/intel_fbdev_fb.h b/drivers/gpu/drm/i915/display/intel_fbdev_fb.h index 34ed2b9c2b4f..ddba45e9839d 100644 --- a/drivers/gpu/drm/i915/display/intel_fbdev_fb.h +++ b/drivers/gpu/drm/i915/display/intel_fbdev_fb.h @@ -17,8 +17,8 @@ struct i915_vma; u32 intel_fbdev_fb_pitch_align(u32 stride); struct drm_gem_object *intel_fbdev_fb_bo_create(struct drm_device *drm, int size); void intel_fbdev_fb_bo_destroy(struct drm_gem_object *obj); -int intel_fbdev_fb_fill_info(struct drm_device *drm, struct fb_info *info, - struct drm_gem_object *obj, struct i915_vma *vma); +int intel_fbdev_fb_fill_info(struct drm_gem_object *obj, struct fb_info *info, + struct i915_vma *vma); bool intel_fbdev_fb_prefer_stolen(struct drm_device *drm, unsigned int size); #endif diff --git a/drivers/gpu/drm/xe/display/intel_fbdev_fb.c b/drivers/gpu/drm/xe/display/intel_fbdev_fb.c index d7030e4d814c..23fa54ee781e 100644 --- a/drivers/gpu/drm/xe/display/intel_fbdev_fb.c +++ b/drivers/gpu/drm/xe/display/intel_fbdev_fb.c @@ -91,11 +91,11 @@ void intel_fbdev_fb_bo_destroy(struct drm_gem_object *obj) xe_bo_unpin_map_no_vm(gem_to_xe_bo(obj)); } -int intel_fbdev_fb_fill_info(struct drm_device *drm, struct fb_info *info, - struct drm_gem_object *_obj, struct i915_vma *vma) +int intel_fbdev_fb_fill_info(struct drm_gem_object *_obj, struct fb_info *info, + struct i915_vma *vma) { struct xe_bo *obj = gem_to_xe_bo(_obj); - struct pci_dev *pdev = to_pci_dev(drm->dev); + struct pci_dev *pdev = to_pci_dev(_obj->dev->dev); if (!(obj->flags & XE_BO_FLAG_SYSTEM)) { if (obj->flags & XE_BO_FLAG_STOLEN) -- cgit v1.2.3 From 89f55d5859f894aada0a09f1539901a628d9a0fb Mon Sep 17 00:00:00 2001 From: Jani Nikula Date: Tue, 31 Mar 2026 12:49:16 +0300 Subject: drm/{i915, xe}: move fbdev fb calls to parent interface MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Move the driver specific fbdev fb calls to the display parent interface. Reuse the existing struct intel_display_bo_interface, as this is mostly about gem objects. Put everything behind IS_ENABLED(CONFIG_DRM_FBDEV_EMULATION) to catch configuration issues at build or link time. v2: Rebase Reviewed-by: Michał Grzelak # v1 Link: https://patch.msgid.link/a6bb24909a58181cfc41b91a4c6538a181d27158.1774950508.git.jani.nikula@intel.com Signed-off-by: Jani Nikula --- drivers/gpu/drm/i915/Makefile | 3 +- drivers/gpu/drm/i915/display/intel_bo.c | 27 ++++++ drivers/gpu/drm/i915/display/intel_bo.h | 8 ++ drivers/gpu/drm/i915/display/intel_fbdev.c | 14 +-- drivers/gpu/drm/i915/display/intel_fbdev_fb.c | 118 ------------------------- drivers/gpu/drm/i915/display/intel_fbdev_fb.h | 24 ----- drivers/gpu/drm/i915/i915_bo.c | 116 ++++++++++++++++++++++++ drivers/gpu/drm/i915/i915_bo.h | 6 ++ drivers/gpu/drm/i915/i915_initial_plane.c | 4 +- drivers/gpu/drm/xe/Makefile | 1 - drivers/gpu/drm/xe/display/intel_fbdev_fb.c | 120 ------------------------- drivers/gpu/drm/xe/display/xe_display_bo.c | 121 ++++++++++++++++++++++++++ drivers/gpu/drm/xe/display/xe_display_bo.h | 6 ++ drivers/gpu/drm/xe/display/xe_initial_plane.c | 4 +- include/drm/intel/display_parent_interface.h | 7 ++ 15 files changed, 303 insertions(+), 276 deletions(-) delete mode 100644 drivers/gpu/drm/i915/display/intel_fbdev_fb.c delete mode 100644 drivers/gpu/drm/i915/display/intel_fbdev_fb.h delete mode 100644 drivers/gpu/drm/xe/display/intel_fbdev_fb.c diff --git a/drivers/gpu/drm/i915/Makefile b/drivers/gpu/drm/i915/Makefile index 0e48305df8b2..272c292f06ed 100644 --- a/drivers/gpu/drm/i915/Makefile +++ b/drivers/gpu/drm/i915/Makefile @@ -326,8 +326,7 @@ i915-$(CONFIG_ACPI) += \ display/intel_acpi.o \ display/intel_opregion.o i915-$(CONFIG_DRM_FBDEV_EMULATION) += \ - display/intel_fbdev.o \ - display/intel_fbdev_fb.o + display/intel_fbdev.o i915-$(CONFIG_DEBUG_FS) += \ display/intel_display_debugfs.o \ display/intel_display_debugfs_params.o \ diff --git a/drivers/gpu/drm/i915/display/intel_bo.c b/drivers/gpu/drm/i915/display/intel_bo.c index 3b82d38a0504..8ecdbb7e39f3 100644 --- a/drivers/gpu/drm/i915/display/intel_bo.c +++ b/drivers/gpu/drm/i915/display/intel_bo.c @@ -85,3 +85,30 @@ struct drm_gem_object *intel_bo_framebuffer_lookup(struct intel_display *display { return display->parent->bo->framebuffer_lookup(display->drm, filp, user_mode_cmd); } + +#if IS_ENABLED(CONFIG_DRM_FBDEV_EMULATION) +u32 intel_bo_fbdev_pitch_align(struct intel_display *display, u32 stride) +{ + return display->parent->bo->fbdev_pitch_align(stride); +} + +struct drm_gem_object *intel_bo_fbdev_create(struct intel_display *display, int size) +{ + return display->parent->bo->fbdev_create(display->drm, size); +} + +void intel_bo_fbdev_destroy(struct drm_gem_object *obj) +{ + struct intel_display *display = to_intel_display(obj->dev); + + display->parent->bo->fbdev_destroy(obj); +} + +int intel_bo_fbdev_fill_info(struct drm_gem_object *obj, struct fb_info *info, + struct i915_vma *vma) +{ + struct intel_display *display = to_intel_display(obj->dev); + + return display->parent->bo->fbdev_fill_info(obj, info, vma); +} +#endif diff --git a/drivers/gpu/drm/i915/display/intel_bo.h b/drivers/gpu/drm/i915/display/intel_bo.h index aec188c706c2..348f7fa66960 100644 --- a/drivers/gpu/drm/i915/display/intel_bo.h +++ b/drivers/gpu/drm/i915/display/intel_bo.h @@ -10,6 +10,8 @@ struct drm_file; struct drm_gem_object; struct drm_mode_fb_cmd2; struct drm_scanout_buffer; +struct fb_info; +struct i915_vma; struct intel_display; struct intel_framebuffer; struct seq_file; @@ -31,4 +33,10 @@ struct drm_gem_object *intel_bo_framebuffer_lookup(struct intel_display *display struct drm_file *filp, const struct drm_mode_fb_cmd2 *user_mode_cmd); +u32 intel_bo_fbdev_pitch_align(struct intel_display *display, u32 stride); +struct drm_gem_object *intel_bo_fbdev_create(struct intel_display *display, int size); +void intel_bo_fbdev_destroy(struct drm_gem_object *obj); +int intel_bo_fbdev_fill_info(struct drm_gem_object *obj, struct fb_info *info, + struct i915_vma *vma); + #endif /* __INTEL_BO__ */ diff --git a/drivers/gpu/drm/i915/display/intel_fbdev.c b/drivers/gpu/drm/i915/display/intel_fbdev.c index 6401aaaba199..14ac01c1b3eb 100644 --- a/drivers/gpu/drm/i915/display/intel_fbdev.c +++ b/drivers/gpu/drm/i915/display/intel_fbdev.c @@ -54,7 +54,6 @@ #include "intel_fb.h" #include "intel_fb_pin.h" #include "intel_fbdev.h" -#include "intel_fbdev_fb.h" #include "intel_frontbuffer.h" struct intel_fbdev { @@ -204,7 +203,8 @@ static const struct drm_fb_helper_funcs intel_fb_helper_funcs = { .fb_set_suspend = intelfb_set_suspend, }; -static void intel_fbdev_fill_mode_cmd(struct drm_fb_helper_surface_size *sizes, +static void intel_fbdev_fill_mode_cmd(struct intel_display *display, + struct drm_fb_helper_surface_size *sizes, struct drm_mode_fb_cmd2 *mode_cmd) { /* we don't do packed 24bpp */ @@ -215,7 +215,7 @@ static void intel_fbdev_fill_mode_cmd(struct drm_fb_helper_surface_size *sizes, mode_cmd->width = sizes->surface_width; mode_cmd->height = sizes->surface_height; - mode_cmd->pitches[0] = intel_fbdev_fb_pitch_align(mode_cmd->width * DIV_ROUND_UP(sizes->surface_bpp, 8)); + mode_cmd->pitches[0] = intel_bo_fbdev_pitch_align(display, mode_cmd->width * DIV_ROUND_UP(sizes->surface_bpp, 8)); mode_cmd->pixel_format = drm_mode_legacy_fb_format(sizes->surface_bpp, sizes->surface_depth); mode_cmd->modifier[0] = DRM_FORMAT_MOD_LINEAR; @@ -230,12 +230,12 @@ __intel_fbdev_fb_alloc(struct intel_display *display, struct drm_gem_object *obj; int size; - intel_fbdev_fill_mode_cmd(sizes, &mode_cmd); + intel_fbdev_fill_mode_cmd(display, sizes, &mode_cmd); size = mode_cmd.pitches[0] * mode_cmd.height; size = PAGE_ALIGN(size); - obj = intel_fbdev_fb_bo_create(display->drm, size); + obj = intel_bo_fbdev_create(display, size); if (IS_ERR(obj)) { fb = ERR_CAST(obj); goto err; @@ -247,7 +247,7 @@ __intel_fbdev_fb_alloc(struct intel_display *display, mode_cmd.modifier[0]), &mode_cmd); if (IS_ERR(fb)) { - intel_fbdev_fb_bo_destroy(obj); + intel_bo_fbdev_destroy(obj); goto err; } @@ -327,7 +327,7 @@ int intel_fbdev_driver_fbdev_probe(struct drm_fb_helper *helper, obj = intel_fb_bo(&fb->base); - ret = intel_fbdev_fb_fill_info(obj, info, vma); + ret = intel_bo_fbdev_fill_info(obj, info, vma); if (ret) goto out_unpin; diff --git a/drivers/gpu/drm/i915/display/intel_fbdev_fb.c b/drivers/gpu/drm/i915/display/intel_fbdev_fb.c deleted file mode 100644 index a696ce42d10b..000000000000 --- a/drivers/gpu/drm/i915/display/intel_fbdev_fb.c +++ /dev/null @@ -1,118 +0,0 @@ -/* SPDX-License-Identifier: MIT */ -/* - * Copyright © 2023 Intel Corporation - */ - -#include - -#include - -#include "gem/i915_gem_lmem.h" - -#include "i915_drv.h" -#include "intel_fbdev_fb.h" - -u32 intel_fbdev_fb_pitch_align(u32 stride) -{ - return ALIGN(stride, 64); -} - -bool intel_fbdev_fb_prefer_stolen(struct drm_device *drm, unsigned int size) -{ - struct drm_i915_private *i915 = to_i915(drm); - - /* Skip stolen on MTL as Wa_22018444074 mitigation. */ - if (IS_METEORLAKE(i915)) - return false; - - /* - * If the FB is too big, just don't use it since fbdev is not very - * important and we should probably use that space with FBC or other - * features. - */ - return i915->dsm.usable_size >= size * 2; -} - -struct drm_gem_object *intel_fbdev_fb_bo_create(struct drm_device *drm, int size) -{ - struct drm_i915_private *i915 = to_i915(drm); - struct drm_i915_gem_object *obj; - - obj = ERR_PTR(-ENODEV); - if (HAS_LMEM(i915)) { - obj = i915_gem_object_create_lmem(i915, size, - I915_BO_ALLOC_CONTIGUOUS | - I915_BO_ALLOC_USER); - } else { - if (intel_fbdev_fb_prefer_stolen(drm, size)) - obj = i915_gem_object_create_stolen(i915, size); - else - drm_info(drm, "Allocating fbdev: Stolen memory not preferred.\n"); - - if (IS_ERR(obj)) - obj = i915_gem_object_create_shmem(i915, size); - } - - if (IS_ERR(obj)) { - drm_err(drm, "failed to allocate framebuffer (%pe)\n", obj); - return ERR_PTR(-ENOMEM); - } - - return &obj->base; -} - -void intel_fbdev_fb_bo_destroy(struct drm_gem_object *obj) -{ - drm_gem_object_put(obj); -} - -int intel_fbdev_fb_fill_info(struct drm_gem_object *_obj, struct fb_info *info, - struct i915_vma *vma) -{ - struct drm_i915_private *i915 = to_i915(_obj->dev); - struct drm_i915_gem_object *obj = to_intel_bo(_obj); - struct i915_gem_ww_ctx ww; - void __iomem *vaddr; - int ret; - - if (i915_gem_object_is_lmem(obj)) { - struct intel_memory_region *mem = obj->mm.region; - - /* Use fbdev's framebuffer from lmem for discrete */ - info->fix.smem_start = - (unsigned long)(mem->io.start + - i915_gem_object_get_dma_address(obj, 0) - - mem->region.start); - info->fix.smem_len = obj->base.size; - } else { - struct i915_ggtt *ggtt = to_gt(i915)->ggtt; - - /* Our framebuffer is the entirety of fbdev's system memory */ - info->fix.smem_start = - (unsigned long)(ggtt->gmadr.start + i915_ggtt_offset(vma)); - info->fix.smem_len = vma->size; - } - - for_i915_gem_ww(&ww, ret, false) { - ret = i915_gem_object_lock(vma->obj, &ww); - - if (ret) - continue; - - vaddr = i915_vma_pin_iomap(vma); - if (IS_ERR(vaddr)) { - drm_err(&i915->drm, - "Failed to remap framebuffer into virtual memory (%pe)\n", vaddr); - ret = PTR_ERR(vaddr); - continue; - } - } - - if (ret) - return ret; - - info->screen_base = vaddr; - info->screen_size = intel_bo_to_drm_bo(obj)->size; - - return 0; -} diff --git a/drivers/gpu/drm/i915/display/intel_fbdev_fb.h b/drivers/gpu/drm/i915/display/intel_fbdev_fb.h deleted file mode 100644 index ddba45e9839d..000000000000 --- a/drivers/gpu/drm/i915/display/intel_fbdev_fb.h +++ /dev/null @@ -1,24 +0,0 @@ -/* SPDX-License-Identifier: MIT */ -/* - * Copyright © 2023 Intel Corporation - */ - -#ifndef __INTEL_FBDEV_FB_H__ -#define __INTEL_FBDEV_FB_H__ - -#include - -struct drm_device; -struct drm_gem_object; -struct drm_mode_fb_cmd2; -struct fb_info; -struct i915_vma; - -u32 intel_fbdev_fb_pitch_align(u32 stride); -struct drm_gem_object *intel_fbdev_fb_bo_create(struct drm_device *drm, int size); -void intel_fbdev_fb_bo_destroy(struct drm_gem_object *obj); -int intel_fbdev_fb_fill_info(struct drm_gem_object *obj, struct fb_info *info, - struct i915_vma *vma); -bool intel_fbdev_fb_prefer_stolen(struct drm_device *drm, unsigned int size); - -#endif diff --git a/drivers/gpu/drm/i915/i915_bo.c b/drivers/gpu/drm/i915/i915_bo.c index 1789f7cab05c..7e38d002478e 100644 --- a/drivers/gpu/drm/i915/i915_bo.c +++ b/drivers/gpu/drm/i915/i915_bo.c @@ -1,11 +1,14 @@ // SPDX-License-Identifier: MIT /* Copyright © 2024 Intel Corporation */ +#include + #include #include #include #include "display/intel_fb.h" +#include "gem/i915_gem_lmem.h" #include "gem/i915_gem_mman.h" #include "gem/i915_gem_object.h" #include "gem/i915_gem_object_frontbuffer.h" @@ -141,6 +144,113 @@ i915_bo_framebuffer_lookup(struct drm_device *drm, return intel_bo_to_drm_bo(obj); } +#if IS_ENABLED(CONFIG_DRM_FBDEV_EMULATION) +static u32 i915_bo_fbdev_pitch_align(u32 stride) +{ + return ALIGN(stride, 64); +} + +bool i915_bo_fbdev_prefer_stolen(struct drm_device *drm, unsigned int size) +{ + struct drm_i915_private *i915 = to_i915(drm); + + /* Skip stolen on MTL as Wa_22018444074 mitigation. */ + if (IS_METEORLAKE(i915)) + return false; + + /* + * If the FB is too big, just don't use it since fbdev is not very + * important and we should probably use that space with FBC or other + * features. + */ + return i915->dsm.usable_size >= size * 2; +} + +static struct drm_gem_object *i915_bo_fbdev_create(struct drm_device *drm, int size) +{ + struct drm_i915_private *i915 = to_i915(drm); + struct drm_i915_gem_object *obj; + + obj = ERR_PTR(-ENODEV); + if (HAS_LMEM(i915)) { + obj = i915_gem_object_create_lmem(i915, size, + I915_BO_ALLOC_CONTIGUOUS | + I915_BO_ALLOC_USER); + } else { + if (i915_bo_fbdev_prefer_stolen(drm, size)) + obj = i915_gem_object_create_stolen(i915, size); + else + drm_info(drm, "Allocating fbdev: Stolen memory not preferred.\n"); + + if (IS_ERR(obj)) + obj = i915_gem_object_create_shmem(i915, size); + } + + if (IS_ERR(obj)) { + drm_err(drm, "failed to allocate framebuffer (%pe)\n", obj); + return ERR_PTR(-ENOMEM); + } + + return &obj->base; +} + +static void i915_bo_fbdev_destroy(struct drm_gem_object *obj) +{ + drm_gem_object_put(obj); +} + +static int i915_bo_fbdev_fill_info(struct drm_gem_object *_obj, struct fb_info *info, + struct i915_vma *vma) +{ + struct drm_i915_private *i915 = to_i915(_obj->dev); + struct drm_i915_gem_object *obj = to_intel_bo(_obj); + struct i915_gem_ww_ctx ww; + void __iomem *vaddr; + int ret; + + if (i915_gem_object_is_lmem(obj)) { + struct intel_memory_region *mem = obj->mm.region; + + /* Use fbdev's framebuffer from lmem for discrete */ + info->fix.smem_start = + (unsigned long)(mem->io.start + + i915_gem_object_get_dma_address(obj, 0) - + mem->region.start); + info->fix.smem_len = obj->base.size; + } else { + struct i915_ggtt *ggtt = to_gt(i915)->ggtt; + + /* Our framebuffer is the entirety of fbdev's system memory */ + info->fix.smem_start = + (unsigned long)(ggtt->gmadr.start + i915_ggtt_offset(vma)); + info->fix.smem_len = vma->size; + } + + for_i915_gem_ww(&ww, ret, false) { + ret = i915_gem_object_lock(vma->obj, &ww); + + if (ret) + continue; + + vaddr = i915_vma_pin_iomap(vma); + if (IS_ERR(vaddr)) { + drm_err(&i915->drm, + "Failed to remap framebuffer into virtual memory (%pe)\n", vaddr); + ret = PTR_ERR(vaddr); + continue; + } + } + + if (ret) + return ret; + + info->screen_base = vaddr; + info->screen_size = intel_bo_to_drm_bo(obj)->size; + + return 0; +} +#endif + const struct intel_display_bo_interface i915_display_bo_interface = { .is_tiled = i915_bo_is_tiled, .is_userptr = i915_bo_is_userptr, @@ -153,4 +263,10 @@ const struct intel_display_bo_interface i915_display_bo_interface = { .framebuffer_init = i915_bo_framebuffer_init, .framebuffer_fini = i915_bo_framebuffer_fini, .framebuffer_lookup = i915_bo_framebuffer_lookup, +#if IS_ENABLED(CONFIG_DRM_FBDEV_EMULATION) + .fbdev_create = i915_bo_fbdev_create, + .fbdev_destroy = i915_bo_fbdev_destroy, + .fbdev_fill_info = i915_bo_fbdev_fill_info, + .fbdev_pitch_align = i915_bo_fbdev_pitch_align, +#endif }; diff --git a/drivers/gpu/drm/i915/i915_bo.h b/drivers/gpu/drm/i915/i915_bo.h index 57255d052dd9..2a0f3050dd42 100644 --- a/drivers/gpu/drm/i915/i915_bo.h +++ b/drivers/gpu/drm/i915/i915_bo.h @@ -4,6 +4,12 @@ #ifndef __I915_BO_H__ #define __I915_BO_H__ +#include + +struct drm_device; + +bool i915_bo_fbdev_prefer_stolen(struct drm_device *drm, unsigned int size); + extern const struct intel_display_bo_interface i915_display_bo_interface; #endif /* __I915_BO_H__ */ diff --git a/drivers/gpu/drm/i915/i915_initial_plane.c b/drivers/gpu/drm/i915/i915_initial_plane.c index 390a9248d631..f4d631a395d0 100644 --- a/drivers/gpu/drm/i915/i915_initial_plane.c +++ b/drivers/gpu/drm/i915/i915_initial_plane.c @@ -9,10 +9,10 @@ #include "display/intel_crtc.h" #include "display/intel_display_types.h" #include "display/intel_fb.h" -#include "display/intel_fbdev_fb.h" #include "gem/i915_gem_lmem.h" #include "gem/i915_gem_region.h" +#include "i915_bo.h" #include "i915_drv.h" #include "i915_initial_plane.h" @@ -118,7 +118,7 @@ initial_plane_vma(struct drm_i915_private *i915, if (IS_ENABLED(CONFIG_DRM_FBDEV_EMULATION) && IS_ENABLED(CONFIG_FRAMEBUFFER_CONSOLE) && mem == i915->mm.stolen_region && - !intel_fbdev_fb_prefer_stolen(&i915->drm, size)) { + !i915_bo_fbdev_prefer_stolen(&i915->drm, size)) { drm_dbg_kms(&i915->drm, "Initial FB size exceeds half of stolen, discarding\n"); return NULL; } diff --git a/drivers/gpu/drm/xe/Makefile b/drivers/gpu/drm/xe/Makefile index 015ca5412f86..288d621e9ccb 100644 --- a/drivers/gpu/drm/xe/Makefile +++ b/drivers/gpu/drm/xe/Makefile @@ -211,7 +211,6 @@ $(obj)/i915-display/%.o: $(srctree)/drivers/gpu/drm/i915/display/%.c FORCE # Display code specific to xe xe-$(CONFIG_DRM_XE_DISPLAY) += \ - display/intel_fbdev_fb.o \ display/xe_display.o \ display/xe_display_bo.o \ display/xe_display_pcode.o \ diff --git a/drivers/gpu/drm/xe/display/intel_fbdev_fb.c b/drivers/gpu/drm/xe/display/intel_fbdev_fb.c deleted file mode 100644 index 23fa54ee781e..000000000000 --- a/drivers/gpu/drm/xe/display/intel_fbdev_fb.c +++ /dev/null @@ -1,120 +0,0 @@ -/* SPDX-License-Identifier: MIT */ -/* - * Copyright © 2023 Intel Corporation - */ - -#include - -#include "intel_fbdev_fb.h" -#include "xe_bo.h" -#include "xe_ttm_stolen_mgr.h" -#include "xe_wa.h" - -#include - -/* - * FIXME: There shouldn't be any reason to have XE_PAGE_SIZE stride - * alignment. The same 64 as i915 uses should be fine, and we shouldn't need to - * have driver specific values. However, dropping the stride alignment to 64 - * leads to underflowing the bo pin count in the atomic cleanup work. - */ -u32 intel_fbdev_fb_pitch_align(u32 stride) -{ - return ALIGN(stride, XE_PAGE_SIZE); -} - -bool intel_fbdev_fb_prefer_stolen(struct drm_device *drm, unsigned int size) -{ - struct xe_device *xe = to_xe_device(drm); - struct ttm_resource_manager *stolen; - - stolen = ttm_manager_type(&xe->ttm, XE_PL_STOLEN); - if (!stolen) - return false; - - if (IS_DGFX(xe)) - return false; - - if (XE_DEVICE_WA(xe, 22019338487_display)) - return false; - - /* - * If the FB is too big, just don't use it since fbdev is not very - * important and we should probably use that space with FBC or other - * features. - */ - return stolen->size >= size * 2; -} - -struct drm_gem_object *intel_fbdev_fb_bo_create(struct drm_device *drm, int size) -{ - struct xe_device *xe = to_xe_device(drm); - struct xe_bo *obj; - - obj = ERR_PTR(-ENODEV); - - if (intel_fbdev_fb_prefer_stolen(drm, size)) { - obj = xe_bo_create_pin_map_novm(xe, xe_device_get_root_tile(xe), - size, - ttm_bo_type_kernel, - XE_BO_FLAG_FORCE_WC | - XE_BO_FLAG_STOLEN | - XE_BO_FLAG_GGTT, - false); - if (!IS_ERR(obj)) - drm_info(&xe->drm, "Allocated fbdev into stolen\n"); - else - drm_info(&xe->drm, "Allocated fbdev into stolen failed: %li\n", PTR_ERR(obj)); - } else { - drm_info(&xe->drm, "Allocating fbdev: Stolen memory not preferred.\n"); - } - - if (IS_ERR(obj)) { - obj = xe_bo_create_pin_map_novm(xe, xe_device_get_root_tile(xe), size, - ttm_bo_type_kernel, - XE_BO_FLAG_FORCE_WC | - XE_BO_FLAG_VRAM_IF_DGFX(xe_device_get_root_tile(xe)) | - XE_BO_FLAG_GGTT, - false); - } - - if (IS_ERR(obj)) { - drm_err(&xe->drm, "failed to allocate framebuffer (%pe)\n", obj); - return ERR_PTR(-ENOMEM); - } - - return &obj->ttm.base; -} - -void intel_fbdev_fb_bo_destroy(struct drm_gem_object *obj) -{ - xe_bo_unpin_map_no_vm(gem_to_xe_bo(obj)); -} - -int intel_fbdev_fb_fill_info(struct drm_gem_object *_obj, struct fb_info *info, - struct i915_vma *vma) -{ - struct xe_bo *obj = gem_to_xe_bo(_obj); - struct pci_dev *pdev = to_pci_dev(_obj->dev->dev); - - if (!(obj->flags & XE_BO_FLAG_SYSTEM)) { - if (obj->flags & XE_BO_FLAG_STOLEN) - info->fix.smem_start = xe_ttm_stolen_io_offset(obj, 0); - else - info->fix.smem_start = - pci_resource_start(pdev, 2) + - xe_bo_addr(obj, 0, XE_PAGE_SIZE); - - info->fix.smem_len = obj->ttm.base.size; - } else { - /* XXX: Pure fiction, as the BO may not be physically accessible.. */ - info->fix.smem_start = 0; - info->fix.smem_len = obj->ttm.base.size; - } - XE_WARN_ON(iosys_map_is_null(&obj->vmap)); - - info->screen_base = obj->vmap.vaddr_iomem; - info->screen_size = obj->ttm.base.size; - - return 0; -} diff --git a/drivers/gpu/drm/xe/display/xe_display_bo.c b/drivers/gpu/drm/xe/display/xe_display_bo.c index 1d81b9908265..bb5eba226240 100644 --- a/drivers/gpu/drm/xe/display/xe_display_bo.c +++ b/drivers/gpu/drm/xe/display/xe_display_bo.c @@ -1,6 +1,8 @@ // SPDX-License-Identifier: MIT /* Copyright © 2024 Intel Corporation */ +#include + #include #include @@ -8,6 +10,10 @@ #include "xe_bo.h" #include "xe_display_bo.h" #include "xe_pxp.h" +#include "xe_ttm_stolen_mgr.h" +#include "xe_wa.h" + +#include static bool xe_display_bo_is_protected(struct drm_gem_object *obj) { @@ -101,6 +107,115 @@ xe_display_bo_framebuffer_lookup(struct drm_device *drm, return gem; } +#if IS_ENABLED(CONFIG_DRM_FBDEV_EMULATION) +/* + * FIXME: There shouldn't be any reason to have XE_PAGE_SIZE stride + * alignment. The same 64 as i915 uses should be fine, and we shouldn't need to + * have driver specific values. However, dropping the stride alignment to 64 + * leads to underflowing the bo pin count in the atomic cleanup work. + */ +static u32 xe_display_bo_fbdev_pitch_align(u32 stride) +{ + return ALIGN(stride, XE_PAGE_SIZE); +} + +bool xe_display_bo_fbdev_prefer_stolen(struct drm_device *drm, unsigned int size) +{ + struct xe_device *xe = to_xe_device(drm); + struct ttm_resource_manager *stolen; + + stolen = ttm_manager_type(&xe->ttm, XE_PL_STOLEN); + if (!stolen) + return false; + + if (IS_DGFX(xe)) + return false; + + if (XE_DEVICE_WA(xe, 22019338487_display)) + return false; + + /* + * If the FB is too big, just don't use it since fbdev is not very + * important and we should probably use that space with FBC or other + * features. + */ + return stolen->size >= size * 2; +} + +static struct drm_gem_object *xe_display_bo_fbdev_create(struct drm_device *drm, int size) +{ + struct xe_device *xe = to_xe_device(drm); + struct xe_bo *obj; + + obj = ERR_PTR(-ENODEV); + + if (xe_display_bo_fbdev_prefer_stolen(drm, size)) { + obj = xe_bo_create_pin_map_novm(xe, xe_device_get_root_tile(xe), + size, + ttm_bo_type_kernel, + XE_BO_FLAG_FORCE_WC | + XE_BO_FLAG_STOLEN | + XE_BO_FLAG_GGTT, + false); + if (!IS_ERR(obj)) + drm_info(&xe->drm, "Allocated fbdev into stolen\n"); + else + drm_info(&xe->drm, "Allocated fbdev into stolen failed: %li\n", PTR_ERR(obj)); + } else { + drm_info(&xe->drm, "Allocating fbdev: Stolen memory not preferred.\n"); + } + + if (IS_ERR(obj)) { + obj = xe_bo_create_pin_map_novm(xe, xe_device_get_root_tile(xe), size, + ttm_bo_type_kernel, + XE_BO_FLAG_FORCE_WC | + XE_BO_FLAG_VRAM_IF_DGFX(xe_device_get_root_tile(xe)) | + XE_BO_FLAG_GGTT, + false); + } + + if (IS_ERR(obj)) { + drm_err(&xe->drm, "failed to allocate framebuffer (%pe)\n", obj); + return ERR_PTR(-ENOMEM); + } + + return &obj->ttm.base; +} + +static void xe_display_bo_fbdev_destroy(struct drm_gem_object *obj) +{ + xe_bo_unpin_map_no_vm(gem_to_xe_bo(obj)); +} + +static int xe_display_bo_fbdev_fill_info(struct drm_gem_object *_obj, struct fb_info *info, + struct i915_vma *vma) +{ + struct xe_bo *obj = gem_to_xe_bo(_obj); + struct pci_dev *pdev = to_pci_dev(_obj->dev->dev); + + if (!(obj->flags & XE_BO_FLAG_SYSTEM)) { + if (obj->flags & XE_BO_FLAG_STOLEN) + info->fix.smem_start = xe_ttm_stolen_io_offset(obj, 0); + else + info->fix.smem_start = + pci_resource_start(pdev, 2) + + xe_bo_addr(obj, 0, XE_PAGE_SIZE); + + info->fix.smem_len = obj->ttm.base.size; + } else { + /* XXX: Pure fiction, as the BO may not be physically accessible.. */ + info->fix.smem_start = 0; + info->fix.smem_len = obj->ttm.base.size; + } + XE_WARN_ON(iosys_map_is_null(&obj->vmap)); + + info->screen_base = obj->vmap.vaddr_iomem; + info->screen_size = obj->ttm.base.size; + + return 0; +} +#endif + const struct intel_display_bo_interface xe_display_bo_interface = { .is_protected = xe_display_bo_is_protected, .key_check = xe_pxp_obj_key_check, @@ -109,4 +224,10 @@ const struct intel_display_bo_interface xe_display_bo_interface = { .framebuffer_init = xe_display_bo_framebuffer_init, .framebuffer_fini = xe_display_bo_framebuffer_fini, .framebuffer_lookup = xe_display_bo_framebuffer_lookup, +#if IS_ENABLED(CONFIG_DRM_FBDEV_EMULATION) + .fbdev_create = xe_display_bo_fbdev_create, + .fbdev_destroy = xe_display_bo_fbdev_destroy, + .fbdev_fill_info = xe_display_bo_fbdev_fill_info, + .fbdev_pitch_align = xe_display_bo_fbdev_pitch_align, +#endif }; diff --git a/drivers/gpu/drm/xe/display/xe_display_bo.h b/drivers/gpu/drm/xe/display/xe_display_bo.h index 6879c104b0b1..8980e6ecf54a 100644 --- a/drivers/gpu/drm/xe/display/xe_display_bo.h +++ b/drivers/gpu/drm/xe/display/xe_display_bo.h @@ -4,6 +4,12 @@ #ifndef __XE_DISPLAY_BO_H__ #define __XE_DISPLAY_BO_H__ +#include + +struct drm_device; + +bool xe_display_bo_fbdev_prefer_stolen(struct drm_device *drm, unsigned int size); + extern const struct intel_display_bo_interface xe_display_bo_interface; #endif diff --git a/drivers/gpu/drm/xe/display/xe_initial_plane.c b/drivers/gpu/drm/xe/display/xe_initial_plane.c index d44746f4966c..73ae502bb2a5 100644 --- a/drivers/gpu/drm/xe/display/xe_initial_plane.c +++ b/drivers/gpu/drm/xe/display/xe_initial_plane.c @@ -12,8 +12,8 @@ #include "intel_display_types.h" #include "intel_fb.h" #include "intel_fb_pin.h" -#include "intel_fbdev_fb.h" #include "xe_bo.h" +#include "xe_display_bo.h" #include "xe_display_vma.h" #include "xe_ggtt.h" #include "xe_mmio.h" @@ -87,7 +87,7 @@ initial_plane_bo(struct xe_device *xe, if (IS_ENABLED(CONFIG_FRAMEBUFFER_CONSOLE) && IS_ENABLED(CONFIG_DRM_FBDEV_EMULATION) && - !intel_fbdev_fb_prefer_stolen(&xe->drm, plane_config->size)) { + !xe_display_bo_fbdev_prefer_stolen(&xe->drm, plane_config->size)) { drm_info(&xe->drm, "Initial FB size exceeds half of stolen, discarding\n"); return NULL; } diff --git a/include/drm/intel/display_parent_interface.h b/include/drm/intel/display_parent_interface.h index c0d18d5577f3..258e6388ef77 100644 --- a/include/drm/intel/display_parent_interface.h +++ b/include/drm/intel/display_parent_interface.h @@ -16,6 +16,7 @@ struct drm_gem_object; struct drm_mode_fb_cmd2; struct drm_plane_state; struct drm_scanout_buffer; +struct fb_info; struct i915_vma; struct intel_dpt; struct intel_dsb_buffer; @@ -44,6 +45,12 @@ struct intel_display_bo_interface { struct drm_gem_object *(*framebuffer_lookup)(struct drm_device *drm, struct drm_file *filp, const struct drm_mode_fb_cmd2 *user_mode_cmd); +#if IS_ENABLED(CONFIG_DRM_FBDEV_EMULATION) + struct drm_gem_object *(*fbdev_create)(struct drm_device *drm, int size); + void (*fbdev_destroy)(struct drm_gem_object *obj); + int (*fbdev_fill_info)(struct drm_gem_object *obj, struct fb_info *info, struct i915_vma *vma); + u32 (*fbdev_pitch_align)(u32 stride); +#endif }; struct intel_display_dpt_interface { -- cgit v1.2.3 From 3fd0d237c940f86857ee2bb194c06fa9a1333085 Mon Sep 17 00:00:00 2001 From: Jani Nikula Date: Tue, 31 Mar 2026 12:49:17 +0300 Subject: drm/i915: pass struct drm_i915_private to i915_bo_fbdev_prefer_stolen() MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This is i915 core code, use struct drm_i915_private for simplicity. Reviewed-by: Michał Grzelak Link: https://patch.msgid.link/321edddfd7509fd2cff0303747cdf18bb0cb911d.1774950508.git.jani.nikula@intel.com Signed-off-by: Jani Nikula --- drivers/gpu/drm/i915/i915_bo.c | 6 ++---- drivers/gpu/drm/i915/i915_bo.h | 4 ++-- drivers/gpu/drm/i915/i915_initial_plane.c | 2 +- 3 files changed, 5 insertions(+), 7 deletions(-) diff --git a/drivers/gpu/drm/i915/i915_bo.c b/drivers/gpu/drm/i915/i915_bo.c index 7e38d002478e..559341103ca7 100644 --- a/drivers/gpu/drm/i915/i915_bo.c +++ b/drivers/gpu/drm/i915/i915_bo.c @@ -150,10 +150,8 @@ static u32 i915_bo_fbdev_pitch_align(u32 stride) return ALIGN(stride, 64); } -bool i915_bo_fbdev_prefer_stolen(struct drm_device *drm, unsigned int size) +bool i915_bo_fbdev_prefer_stolen(struct drm_i915_private *i915, unsigned int size) { - struct drm_i915_private *i915 = to_i915(drm); - /* Skip stolen on MTL as Wa_22018444074 mitigation. */ if (IS_METEORLAKE(i915)) return false; @@ -177,7 +175,7 @@ static struct drm_gem_object *i915_bo_fbdev_create(struct drm_device *drm, int s I915_BO_ALLOC_CONTIGUOUS | I915_BO_ALLOC_USER); } else { - if (i915_bo_fbdev_prefer_stolen(drm, size)) + if (i915_bo_fbdev_prefer_stolen(i915, size)) obj = i915_gem_object_create_stolen(i915, size); else drm_info(drm, "Allocating fbdev: Stolen memory not preferred.\n"); diff --git a/drivers/gpu/drm/i915/i915_bo.h b/drivers/gpu/drm/i915/i915_bo.h index 2a0f3050dd42..39ba62696550 100644 --- a/drivers/gpu/drm/i915/i915_bo.h +++ b/drivers/gpu/drm/i915/i915_bo.h @@ -6,9 +6,9 @@ #include -struct drm_device; +struct drm_i915_private; -bool i915_bo_fbdev_prefer_stolen(struct drm_device *drm, unsigned int size); +bool i915_bo_fbdev_prefer_stolen(struct drm_i915_private *i915, unsigned int size); extern const struct intel_display_bo_interface i915_display_bo_interface; diff --git a/drivers/gpu/drm/i915/i915_initial_plane.c b/drivers/gpu/drm/i915/i915_initial_plane.c index f4d631a395d0..c1a12bf6b66c 100644 --- a/drivers/gpu/drm/i915/i915_initial_plane.c +++ b/drivers/gpu/drm/i915/i915_initial_plane.c @@ -118,7 +118,7 @@ initial_plane_vma(struct drm_i915_private *i915, if (IS_ENABLED(CONFIG_DRM_FBDEV_EMULATION) && IS_ENABLED(CONFIG_FRAMEBUFFER_CONSOLE) && mem == i915->mm.stolen_region && - !i915_bo_fbdev_prefer_stolen(&i915->drm, size)) { + !i915_bo_fbdev_prefer_stolen(i915, size)) { drm_dbg_kms(&i915->drm, "Initial FB size exceeds half of stolen, discarding\n"); return NULL; } -- cgit v1.2.3 From 8e005ef09ba5a973e9401fa21b653339a5effda1 Mon Sep 17 00:00:00 2001 From: Jani Nikula Date: Tue, 31 Mar 2026 12:49:18 +0300 Subject: drm/xe: pass struct xe_device to xe_display_bo_fbdev_prefer_stolen() MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This is xe core code, use struct xe_device for simplicity. Reviewed-by: Michał Grzelak Link: https://patch.msgid.link/56bd532dc5cf460cdbf17c7781f18db5378a28e6.1774950508.git.jani.nikula@intel.com Signed-off-by: Jani Nikula --- drivers/gpu/drm/xe/display/xe_display_bo.c | 5 ++--- drivers/gpu/drm/xe/display/xe_display_bo.h | 4 ++-- drivers/gpu/drm/xe/display/xe_initial_plane.c | 2 +- 3 files changed, 5 insertions(+), 6 deletions(-) diff --git a/drivers/gpu/drm/xe/display/xe_display_bo.c b/drivers/gpu/drm/xe/display/xe_display_bo.c index bb5eba226240..dc0d78ff2d79 100644 --- a/drivers/gpu/drm/xe/display/xe_display_bo.c +++ b/drivers/gpu/drm/xe/display/xe_display_bo.c @@ -119,9 +119,8 @@ static u32 xe_display_bo_fbdev_pitch_align(u32 stride) return ALIGN(stride, XE_PAGE_SIZE); } -bool xe_display_bo_fbdev_prefer_stolen(struct drm_device *drm, unsigned int size) +bool xe_display_bo_fbdev_prefer_stolen(struct xe_device *xe, unsigned int size) { - struct xe_device *xe = to_xe_device(drm); struct ttm_resource_manager *stolen; stolen = ttm_manager_type(&xe->ttm, XE_PL_STOLEN); @@ -149,7 +148,7 @@ static struct drm_gem_object *xe_display_bo_fbdev_create(struct drm_device *drm, obj = ERR_PTR(-ENODEV); - if (xe_display_bo_fbdev_prefer_stolen(drm, size)) { + if (xe_display_bo_fbdev_prefer_stolen(xe, size)) { obj = xe_bo_create_pin_map_novm(xe, xe_device_get_root_tile(xe), size, ttm_bo_type_kernel, diff --git a/drivers/gpu/drm/xe/display/xe_display_bo.h b/drivers/gpu/drm/xe/display/xe_display_bo.h index 8980e6ecf54a..c72056884ff4 100644 --- a/drivers/gpu/drm/xe/display/xe_display_bo.h +++ b/drivers/gpu/drm/xe/display/xe_display_bo.h @@ -6,9 +6,9 @@ #include -struct drm_device; +struct xe_device; -bool xe_display_bo_fbdev_prefer_stolen(struct drm_device *drm, unsigned int size); +bool xe_display_bo_fbdev_prefer_stolen(struct xe_device *xe, unsigned int size); extern const struct intel_display_bo_interface xe_display_bo_interface; diff --git a/drivers/gpu/drm/xe/display/xe_initial_plane.c b/drivers/gpu/drm/xe/display/xe_initial_plane.c index 73ae502bb2a5..1c7a4e8c390c 100644 --- a/drivers/gpu/drm/xe/display/xe_initial_plane.c +++ b/drivers/gpu/drm/xe/display/xe_initial_plane.c @@ -87,7 +87,7 @@ initial_plane_bo(struct xe_device *xe, if (IS_ENABLED(CONFIG_FRAMEBUFFER_CONSOLE) && IS_ENABLED(CONFIG_DRM_FBDEV_EMULATION) && - !xe_display_bo_fbdev_prefer_stolen(&xe->drm, plane_config->size)) { + !xe_display_bo_fbdev_prefer_stolen(xe, plane_config->size)) { drm_info(&xe->drm, "Initial FB size exceeds half of stolen, discarding\n"); return NULL; } -- cgit v1.2.3 From c79bc999442ff3c0908ab8bce92b2a3cb7d59861 Mon Sep 17 00:00:00 2001 From: Matt Roper Date: Wed, 1 Apr 2026 13:12:44 -0700 Subject: drm/xe: Drop redundant rtp entries for Wa_14019988906 & Wa_14019877138 There appears to have been a silent merge conflict between some commits updating the workaround tables on Xe's -fixes and -next branches: - Commit bc6387a2e0c1 ("drm/xe/xe2_hpg: Fix handling of Wa_14019988906 & Wa_14019877138") from the fixes branch moved the Xe2_HPG instance of two workarounds touching the PSS_CHICKEN register from the engine_was[] table to the lrc_was[] table; the equivalent implementation for all other platforms/IPs were already properly located on lrc_was[]. This commit on the fixes branch is a cherry-pick of commit e04c609eedf4 ("drm/xe/xe2_hpg: Fix handling of Wa_14019988906 & Wa_14019877138") that already existed on the next branch. - Commit 55b19abb6c44 ("drm/xe: Consolidate workaround entries for Wa_14019877138") and commit c2142a1a8415 ("drm/xe: Consolidate workaround entries for Wa_14019988906") consolidated the individual entries per IP generation for each workaround into single, larger range-based entries. During merge conflict resolution the Xe2_HPG-specific entries (i.e., those with rule "GRAPHICS_VERSION_RANGE(2001, 2002)") were accidentally resurrected, even though the table already contains the consolidated entries that match a superset of thse ranges. These redundant entries don't cause any build failures but do trigger a dmesg error during probe on BMG-G21 devices: xe 0000:03:00.0: [drm] *ERROR* Tile0: GT0: discarding save-restore reg 7044 (clear: 00000400, set: 00000400, masked: yes, mcr: yes): ret=-22 xe 0000:03:00.0: [drm] *ERROR* Tile0: GT0: discarding save-restore reg 7044 (clear: 00000020, set: 00000020, masked: yes, mcr: yes): ret=-22 Re-drop the Xe2_HPG-specific table entries to eliminate the error. Closes: https://gitlab.freedesktop.org/drm/xe/kernel/-/work_items/7433 Fixes: 17b95278ae6a ("Merge tag 'drm-xe-next-2026-03-02' of https://gitlab.freedesktop.org/drm/xe/kernel into drm-next") Cc: Dave Airlie Signed-off-by: Matt Roper Reviewed-by: Shuicheng Lin Link: https://patch.msgid.link/20260401-wa_merge_conflict-v1-1-b477ab53fedc@intel.com Signed-off-by: Maarten Lankhorst --- drivers/gpu/drm/xe/xe_wa.c | 8 -------- 1 file changed, 8 deletions(-) diff --git a/drivers/gpu/drm/xe/xe_wa.c b/drivers/gpu/drm/xe/xe_wa.c index c3fef8fd73f7..2ec70be78bf9 100644 --- a/drivers/gpu/drm/xe/xe_wa.c +++ b/drivers/gpu/drm/xe/xe_wa.c @@ -751,14 +751,6 @@ static const struct xe_rtp_entry_sr lrc_was[] = { XE_RTP_RULES(GRAPHICS_VERSION(2001), ENGINE_CLASS(RENDER)), XE_RTP_ACTIONS(SET(WM_CHICKEN3, HIZ_PLANE_COMPRESSION_DIS)) }, - { XE_RTP_NAME("14019988906"), - XE_RTP_RULES(GRAPHICS_VERSION_RANGE(2001, 2002), ENGINE_CLASS(RENDER)), - XE_RTP_ACTIONS(SET(XEHP_PSS_CHICKEN, FLSH_IGNORES_PSD)) - }, - { XE_RTP_NAME("14019877138"), - XE_RTP_RULES(GRAPHICS_VERSION_RANGE(2001, 2002), ENGINE_CLASS(RENDER)), - XE_RTP_ACTIONS(SET(XEHP_PSS_CHICKEN, FD_END_COLLECT)) - }, { XE_RTP_NAME("14021490052"), XE_RTP_RULES(GRAPHICS_VERSION(2001), ENGINE_CLASS(RENDER)), XE_RTP_ACTIONS(SET(FF_MODE, -- cgit v1.2.3 From 19e2815babd4c51a51ebabfe68daa90eb26309c3 Mon Sep 17 00:00:00 2001 From: Maíra Canal Date: Mon, 30 Mar 2026 14:51:47 -0300 Subject: drm/vc4: Use devm_request_irq() for automatic cleanup MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Switch from request_irq()/free_irq() to the device-managed alternative devm_request_irq(), letting device-managed resource cleanup handle IRQ teardown automatically. While here, inline vc4_irq_prepare() into vc4_irq_install() since it's the only caller. Reviewed-by: Melissa Wen Link: https://patch.msgid.link/20260330-vc4-misc-fixes-v1-5-92defc940a29@igalia.com Signed-off-by: Maíra Canal --- drivers/gpu/drm/vc4/vc4_irq.c | 33 ++++++++++++--------------------- 1 file changed, 12 insertions(+), 21 deletions(-) diff --git a/drivers/gpu/drm/vc4/vc4_irq.c b/drivers/gpu/drm/vc4/vc4_irq.c index 63e88f90eef7..8e5141bb5075 100644 --- a/drivers/gpu/drm/vc4/vc4_irq.c +++ b/drivers/gpu/drm/vc4/vc4_irq.c @@ -47,7 +47,6 @@ #include -#include #include #include "vc4_drv.h" @@ -242,23 +241,6 @@ vc4_irq(int irq, void *arg) return status; } -static void -vc4_irq_prepare(struct drm_device *dev) -{ - struct vc4_dev *vc4 = to_vc4_dev(dev); - - if (!vc4->v3d) - return; - - init_waitqueue_head(&vc4->job_wait_queue); - INIT_WORK(&vc4->overflow_mem_work, vc4_overflow_mem_work); - - /* Clear any pending interrupts someone might have left around - * for us. - */ - V3D_WRITE(V3D_INTCTL, V3D_DRIVER_IRQS); -} - void vc4_irq_enable(struct drm_device *dev) { @@ -307,12 +289,22 @@ int vc4_irq_install(struct drm_device *dev, int irq) if (WARN_ON_ONCE(vc4->gen > VC4_GEN_4)) return -ENODEV; + if (!vc4->v3d) + return -ENODEV; + if (irq == IRQ_NOTCONNECTED) return -ENOTCONN; - vc4_irq_prepare(dev); + init_waitqueue_head(&vc4->job_wait_queue); + INIT_WORK(&vc4->overflow_mem_work, vc4_overflow_mem_work); + + /* Clear any pending interrupts someone might have left around + * for us. + */ + V3D_WRITE(V3D_INTCTL, V3D_DRIVER_IRQS); - ret = request_irq(irq, vc4_irq, 0, dev->driver->name, dev); + ret = devm_request_irq(dev->dev, irq, vc4_irq, 0, + dev_name(dev->dev), dev); if (ret) return ret; @@ -329,7 +321,6 @@ void vc4_irq_uninstall(struct drm_device *dev) return; vc4_irq_disable(dev); - free_irq(vc4->irq, dev); } /** Reinitializes interrupt registers when a GPU reset is performed. */ -- cgit v1.2.3 From 4b9c36c83b34f710da9573291404f6a2246251c1 Mon Sep 17 00:00:00 2001 From: Maíra Canal Date: Mon, 30 Mar 2026 14:51:48 -0300 Subject: drm/vc4: Clean-up UAPI header inclusion MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit "uapi/drm/vc4_drm.h" is already included through "vc4_drv.h". Therefore, remove its direct inclusion from several files. Suggested-by: Melissa Wen Reviewed-by: Melissa Wen Link: https://patch.msgid.link/20260330-vc4-misc-fixes-v1-6-92defc940a29@igalia.com Signed-off-by: Maíra Canal --- drivers/gpu/drm/vc4/vc4_bo.c | 1 - drivers/gpu/drm/vc4/vc4_drv.c | 2 -- drivers/gpu/drm/vc4/vc4_gem.c | 1 - drivers/gpu/drm/vc4/vc4_plane.c | 2 -- drivers/gpu/drm/vc4/vc4_render_cl.c | 1 - drivers/gpu/drm/vc4/vc4_validate.c | 1 - 6 files changed, 8 deletions(-) diff --git a/drivers/gpu/drm/vc4/vc4_bo.c b/drivers/gpu/drm/vc4/vc4_bo.c index f45ba47b4ba8..355c26581a41 100644 --- a/drivers/gpu/drm/vc4/vc4_bo.c +++ b/drivers/gpu/drm/vc4/vc4_bo.c @@ -22,7 +22,6 @@ #include #include "vc4_drv.h" -#include "uapi/drm/vc4_drm.h" static const struct drm_gem_object_funcs vc4_gem_object_funcs; diff --git a/drivers/gpu/drm/vc4/vc4_drv.c b/drivers/gpu/drm/vc4/vc4_drv.c index a14ecb769461..616caf9d9915 100644 --- a/drivers/gpu/drm/vc4/vc4_drv.c +++ b/drivers/gpu/drm/vc4/vc4_drv.c @@ -41,8 +41,6 @@ #include -#include "uapi/drm/vc4_drm.h" - #include "vc4_drv.h" #include "vc4_regs.h" diff --git a/drivers/gpu/drm/vc4/vc4_gem.c b/drivers/gpu/drm/vc4/vc4_gem.c index 2d3df5e621c1..c01cba3acf42 100644 --- a/drivers/gpu/drm/vc4/vc4_gem.c +++ b/drivers/gpu/drm/vc4/vc4_gem.c @@ -33,7 +33,6 @@ #include #include -#include "uapi/drm/vc4_drm.h" #include "vc4_drv.h" #include "vc4_regs.h" #include "vc4_trace.h" diff --git a/drivers/gpu/drm/vc4/vc4_plane.c b/drivers/gpu/drm/vc4/vc4_plane.c index 91d499fefba2..a81bad3519cc 100644 --- a/drivers/gpu/drm/vc4/vc4_plane.c +++ b/drivers/gpu/drm/vc4/vc4_plane.c @@ -26,8 +26,6 @@ #include #include -#include "uapi/drm/vc4_drm.h" - #include "vc4_drv.h" #include "vc4_regs.h" diff --git a/drivers/gpu/drm/vc4/vc4_render_cl.c b/drivers/gpu/drm/vc4/vc4_render_cl.c index edc471e71c0e..c264d21bc3fe 100644 --- a/drivers/gpu/drm/vc4/vc4_render_cl.c +++ b/drivers/gpu/drm/vc4/vc4_render_cl.c @@ -37,7 +37,6 @@ #include -#include "uapi/drm/vc4_drm.h" #include "vc4_drv.h" #include "vc4_packet.h" diff --git a/drivers/gpu/drm/vc4/vc4_validate.c b/drivers/gpu/drm/vc4/vc4_validate.c index 545c4c3608f5..7f2fadfde7a8 100644 --- a/drivers/gpu/drm/vc4/vc4_validate.c +++ b/drivers/gpu/drm/vc4/vc4_validate.c @@ -45,7 +45,6 @@ #include -#include "uapi/drm/vc4_drm.h" #include "vc4_drv.h" #include "vc4_packet.h" -- cgit v1.2.3 From 71c8224a18825102ee1e5e70498f96f6c2d2a81d Mon Sep 17 00:00:00 2001 From: Boris Brezillon Date: Wed, 1 Apr 2026 15:48:45 +0200 Subject: drm/gem: Consider GEM object reclaimable if shrinking fails If the object wasn't moved to a different LRU after the shrink callback returns, it means the buffer is still reclaimable. Update the remaining counter to reflect that. v2: - Collect R-b v3: - Collect R-b v4: - No changes v5: - No changes v6: - No changes v7: - No changes Reviewed-by: Liviu Dudau Reviewed-by: Steven Price Link: https://patch.msgid.link/20260401134854.2275433-2-boris.brezillon@collabora.com Signed-off-by: Boris Brezillon --- drivers/gpu/drm/drm_gem.c | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/drivers/gpu/drm/drm_gem.c b/drivers/gpu/drm/drm_gem.c index 0377a5fd402d..3a309aeaaee5 100644 --- a/drivers/gpu/drm/drm_gem.c +++ b/drivers/gpu/drm/drm_gem.c @@ -1700,6 +1700,16 @@ drm_gem_lru_scan(struct drm_gem_lru *lru, */ WARN_ON(obj->lru == &still_in_lru); WARN_ON(obj->lru == lru); + } else if (obj->lru == &still_in_lru) { + /* + * If the object wasn't moved and wasn't shrunk either, + * it's still remaining as reclaimable. Note that + * obj->lru is supposed to be checked with the LRU lock + * held for an accurate result, but we don't care about + * accuracy here. Worst thing that could happen is an + * extra scan. + */ + *remaining += obj->size >> PAGE_SHIFT; } dma_resv_unlock(obj->resv); -- cgit v1.2.3 From 83d4d8eac73ffe9d9fefe7429b75b314569ae02d Mon Sep 17 00:00:00 2001 From: Boris Brezillon Date: Wed, 1 Apr 2026 15:48:46 +0200 Subject: drm/panthor: Remove unused panthor_vm_op_ctx::map::new_vma field This field is never used, drop it. v7: - New patch Reviewed-by: Liviu Dudau Link: https://patch.msgid.link/20260401134854.2275433-3-boris.brezillon@collabora.com Signed-off-by: Boris Brezillon --- drivers/gpu/drm/panthor/panthor_mmu.c | 5 ----- 1 file changed, 5 deletions(-) diff --git a/drivers/gpu/drm/panthor/panthor_mmu.c b/drivers/gpu/drm/panthor/panthor_mmu.c index f8c41e36afa4..ab67286e3a6e 100644 --- a/drivers/gpu/drm/panthor/panthor_mmu.c +++ b/drivers/gpu/drm/panthor/panthor_mmu.c @@ -197,11 +197,6 @@ struct panthor_vm_op_ctx { * to allocate in ::run_job(). */ struct sg_table *sgt; - - /** - * @map.new_vma: The new VMA object that will be inserted to the VA tree. - */ - struct panthor_vma *new_vma; } map; }; -- cgit v1.2.3 From cf91128f3d5fd99a333ca4ecc0f13049a7024b0c Mon Sep 17 00:00:00 2001 From: Boris Brezillon Date: Wed, 1 Apr 2026 15:48:47 +0200 Subject: drm/panthor: Move panthor_gems_debugfs_init() to panthor_gem.c There's no reason for panthor_drv to know about panthor_gem.c internals, so let's move the GEM debugfs init logic to panthor_gem.c. v2: - Collect R-bs v3: -No changes v4: - No changes v5: - No changes v6: - No changes v7: - No changes Reviewed-by: Liviu Dudau Reviewed-by: Steven Price Link: https://patch.msgid.link/20260401134854.2275433-4-boris.brezillon@collabora.com Signed-off-by: Boris Brezillon --- drivers/gpu/drm/panthor/panthor_drv.c | 26 +------------------------- drivers/gpu/drm/panthor/panthor_gem.c | 29 +++++++++++++++++++++++++++-- drivers/gpu/drm/panthor/panthor_gem.h | 3 +-- 3 files changed, 29 insertions(+), 29 deletions(-) diff --git a/drivers/gpu/drm/panthor/panthor_drv.c b/drivers/gpu/drm/panthor/panthor_drv.c index 87d27c3c1456..b1339d4db0a9 100644 --- a/drivers/gpu/drm/panthor/panthor_drv.c +++ b/drivers/gpu/drm/panthor/panthor_drv.c @@ -1756,34 +1756,10 @@ static const struct file_operations panthor_drm_driver_fops = { }; #ifdef CONFIG_DEBUG_FS -static int panthor_gems_show(struct seq_file *m, void *data) -{ - struct drm_info_node *node = m->private; - struct drm_device *dev = node->minor->dev; - struct panthor_device *ptdev = container_of(dev, struct panthor_device, base); - - panthor_gem_debugfs_print_bos(ptdev, m); - - return 0; -} - -static struct drm_info_list panthor_debugfs_list[] = { - {"gems", panthor_gems_show, 0, NULL}, -}; - -static int panthor_gems_debugfs_init(struct drm_minor *minor) -{ - drm_debugfs_create_files(panthor_debugfs_list, - ARRAY_SIZE(panthor_debugfs_list), - minor->debugfs_root, minor); - - return 0; -} - static void panthor_debugfs_init(struct drm_minor *minor) { panthor_mmu_debugfs_init(minor); - panthor_gems_debugfs_init(minor); + panthor_gem_debugfs_init(minor); } #endif diff --git a/drivers/gpu/drm/panthor/panthor_gem.c b/drivers/gpu/drm/panthor/panthor_gem.c index 6d14b0269574..c7b8b84a8f8b 100644 --- a/drivers/gpu/drm/panthor/panthor_gem.c +++ b/drivers/gpu/drm/panthor/panthor_gem.c @@ -9,6 +9,8 @@ #include #include +#include +#include #include #include @@ -683,8 +685,8 @@ static void panthor_gem_debugfs_bo_print(struct panthor_gem_object *bo, totals->reclaimable += resident_size; } -void panthor_gem_debugfs_print_bos(struct panthor_device *ptdev, - struct seq_file *m) +static void panthor_gem_debugfs_print_bos(struct panthor_device *ptdev, + struct seq_file *m) { struct gem_size_totals totals = {0}; struct panthor_gem_object *bo; @@ -704,4 +706,27 @@ void panthor_gem_debugfs_print_bos(struct panthor_device *ptdev, seq_printf(m, "Total size: %zd, Total resident: %zd, Total reclaimable: %zd\n", totals.size, totals.resident, totals.reclaimable); } + +static int panthor_gem_show_bos(struct seq_file *m, void *data) +{ + struct drm_info_node *node = m->private; + struct drm_device *dev = node->minor->dev; + struct panthor_device *ptdev = + container_of(dev, struct panthor_device, base); + + panthor_gem_debugfs_print_bos(ptdev, m); + + return 0; +} + +static struct drm_info_list panthor_gem_debugfs_list[] = { + { "gems", panthor_gem_show_bos, 0, NULL }, +}; + +void panthor_gem_debugfs_init(struct drm_minor *minor) +{ + drm_debugfs_create_files(panthor_gem_debugfs_list, + ARRAY_SIZE(panthor_gem_debugfs_list), + minor->debugfs_root, minor); +} #endif diff --git a/drivers/gpu/drm/panthor/panthor_gem.h b/drivers/gpu/drm/panthor/panthor_gem.h index 22519c570b5a..94b2d17cf032 100644 --- a/drivers/gpu/drm/panthor/panthor_gem.h +++ b/drivers/gpu/drm/panthor/panthor_gem.h @@ -203,8 +203,7 @@ panthor_kernel_bo_create(struct panthor_device *ptdev, struct panthor_vm *vm, void panthor_kernel_bo_destroy(struct panthor_kernel_bo *bo); #ifdef CONFIG_DEBUG_FS -void panthor_gem_debugfs_print_bos(struct panthor_device *pfdev, - struct seq_file *m); +void panthor_gem_debugfs_init(struct drm_minor *minor); #endif #endif /* __PANTHOR_GEM_H__ */ -- cgit v1.2.3 From f36adaaf3d0cd8423086ad2ee332970bab0dacd3 Mon Sep 17 00:00:00 2001 From: Boris Brezillon Date: Wed, 1 Apr 2026 15:48:48 +0200 Subject: drm/panthor: Group panthor_kernel_bo_xxx() helpers Move all panthor_kernel_bo_xxx() helpers at the end of the file, just before the debugfs init logic. This will make further panthor_gem.c refactoring more readable. v2: - Collect R-bs v3: - No changes v4: - No changes v5: - No changes v6: - No changes v7: - No changes Reviewed-by: Liviu Dudau Reviewed-by: Steven Price Link: https://patch.msgid.link/20260401134854.2275433-5-boris.brezillon@collabora.com Signed-off-by: Boris Brezillon --- drivers/gpu/drm/panthor/panthor_gem.c | 212 +++++++++++++++++----------------- 1 file changed, 106 insertions(+), 106 deletions(-) diff --git a/drivers/gpu/drm/panthor/panthor_gem.c b/drivers/gpu/drm/panthor/panthor_gem.c index c7b8b84a8f8b..5065f99c9bc4 100644 --- a/drivers/gpu/drm/panthor/panthor_gem.c +++ b/drivers/gpu/drm/panthor/panthor_gem.c @@ -132,112 +132,6 @@ static void panthor_gem_free_object(struct drm_gem_object *obj) drm_gem_object_put(vm_root_gem); } -/** - * panthor_kernel_bo_destroy() - Destroy a kernel buffer object - * @bo: Kernel buffer object to destroy. If NULL or an ERR_PTR(), the destruction - * is skipped. - */ -void panthor_kernel_bo_destroy(struct panthor_kernel_bo *bo) -{ - struct panthor_vm *vm; - - if (IS_ERR_OR_NULL(bo)) - return; - - vm = bo->vm; - panthor_kernel_bo_vunmap(bo); - - drm_WARN_ON(bo->obj->dev, - to_panthor_bo(bo->obj)->exclusive_vm_root_gem != panthor_vm_root_gem(vm)); - panthor_vm_unmap_range(vm, bo->va_node.start, bo->va_node.size); - panthor_vm_free_va(vm, &bo->va_node); - drm_gem_object_put(bo->obj); - panthor_vm_put(vm); - kfree(bo); -} - -/** - * panthor_kernel_bo_create() - Create and map a GEM object to a VM - * @ptdev: Device. - * @vm: VM to map the GEM to. If NULL, the kernel object is not GPU mapped. - * @size: Size of the buffer object. - * @bo_flags: Combination of drm_panthor_bo_flags flags. - * @vm_map_flags: Combination of drm_panthor_vm_bind_op_flags (only those - * that are related to map operations). - * @gpu_va: GPU address assigned when mapping to the VM. - * If gpu_va == PANTHOR_VM_KERNEL_AUTO_VA, the virtual address will be - * automatically allocated. - * @name: Descriptive label of the BO's contents - * - * Return: A valid pointer in case of success, an ERR_PTR() otherwise. - */ -struct panthor_kernel_bo * -panthor_kernel_bo_create(struct panthor_device *ptdev, struct panthor_vm *vm, - size_t size, u32 bo_flags, u32 vm_map_flags, - u64 gpu_va, const char *name) -{ - struct drm_gem_shmem_object *obj; - struct panthor_kernel_bo *kbo; - struct panthor_gem_object *bo; - u32 debug_flags = PANTHOR_DEBUGFS_GEM_USAGE_FLAG_KERNEL; - int ret; - - if (drm_WARN_ON(&ptdev->base, !vm)) - return ERR_PTR(-EINVAL); - - kbo = kzalloc_obj(*kbo); - if (!kbo) - return ERR_PTR(-ENOMEM); - - obj = drm_gem_shmem_create(&ptdev->base, size); - if (IS_ERR(obj)) { - ret = PTR_ERR(obj); - goto err_free_bo; - } - - bo = to_panthor_bo(&obj->base); - kbo->obj = &obj->base; - bo->flags = bo_flags; - bo->base.map_wc = should_map_wc(bo, vm); - bo->exclusive_vm_root_gem = panthor_vm_root_gem(vm); - drm_gem_object_get(bo->exclusive_vm_root_gem); - bo->base.base.resv = bo->exclusive_vm_root_gem->resv; - - if (vm == panthor_fw_vm(ptdev)) - debug_flags |= PANTHOR_DEBUGFS_GEM_USAGE_FLAG_FW_MAPPED; - - panthor_gem_kernel_bo_set_label(kbo, name); - panthor_gem_debugfs_set_usage_flags(to_panthor_bo(kbo->obj), debug_flags); - - /* The system and GPU MMU page size might differ, which becomes a - * problem for FW sections that need to be mapped at explicit address - * since our PAGE_SIZE alignment might cover a VA range that's - * expected to be used for another section. - * Make sure we never map more than we need. - */ - size = ALIGN(size, panthor_vm_page_size(vm)); - ret = panthor_vm_alloc_va(vm, gpu_va, size, &kbo->va_node); - if (ret) - goto err_put_obj; - - ret = panthor_vm_map_bo_range(vm, bo, 0, size, kbo->va_node.start, vm_map_flags); - if (ret) - goto err_free_va; - - kbo->vm = panthor_vm_get(vm); - return kbo; - -err_free_va: - panthor_vm_free_va(vm, &kbo->va_node); - -err_put_obj: - drm_gem_object_put(&obj->base); - -err_free_bo: - kfree(kbo); - return ERR_PTR(ret); -} - static struct sg_table * panthor_gem_prime_map_dma_buf(struct dma_buf_attachment *attach, enum dma_data_direction dir) @@ -603,6 +497,112 @@ panthor_gem_sync(struct drm_gem_object *obj, u32 type, return 0; } +/** + * panthor_kernel_bo_destroy() - Destroy a kernel buffer object + * @bo: Kernel buffer object to destroy. If NULL or an ERR_PTR(), the destruction + * is skipped. + */ +void panthor_kernel_bo_destroy(struct panthor_kernel_bo *bo) +{ + struct panthor_vm *vm; + + if (IS_ERR_OR_NULL(bo)) + return; + + vm = bo->vm; + panthor_kernel_bo_vunmap(bo); + + drm_WARN_ON(bo->obj->dev, + to_panthor_bo(bo->obj)->exclusive_vm_root_gem != panthor_vm_root_gem(vm)); + panthor_vm_unmap_range(vm, bo->va_node.start, bo->va_node.size); + panthor_vm_free_va(vm, &bo->va_node); + drm_gem_object_put(bo->obj); + panthor_vm_put(vm); + kfree(bo); +} + +/** + * panthor_kernel_bo_create() - Create and map a GEM object to a VM + * @ptdev: Device. + * @vm: VM to map the GEM to. If NULL, the kernel object is not GPU mapped. + * @size: Size of the buffer object. + * @bo_flags: Combination of drm_panthor_bo_flags flags. + * @vm_map_flags: Combination of drm_panthor_vm_bind_op_flags (only those + * that are related to map operations). + * @gpu_va: GPU address assigned when mapping to the VM. + * If gpu_va == PANTHOR_VM_KERNEL_AUTO_VA, the virtual address will be + * automatically allocated. + * @name: Descriptive label of the BO's contents + * + * Return: A valid pointer in case of success, an ERR_PTR() otherwise. + */ +struct panthor_kernel_bo * +panthor_kernel_bo_create(struct panthor_device *ptdev, struct panthor_vm *vm, + size_t size, u32 bo_flags, u32 vm_map_flags, + u64 gpu_va, const char *name) +{ + struct drm_gem_shmem_object *obj; + struct panthor_kernel_bo *kbo; + struct panthor_gem_object *bo; + u32 debug_flags = PANTHOR_DEBUGFS_GEM_USAGE_FLAG_KERNEL; + int ret; + + if (drm_WARN_ON(&ptdev->base, !vm)) + return ERR_PTR(-EINVAL); + + kbo = kzalloc_obj(*kbo); + if (!kbo) + return ERR_PTR(-ENOMEM); + + obj = drm_gem_shmem_create(&ptdev->base, size); + if (IS_ERR(obj)) { + ret = PTR_ERR(obj); + goto err_free_bo; + } + + bo = to_panthor_bo(&obj->base); + kbo->obj = &obj->base; + bo->flags = bo_flags; + bo->base.map_wc = should_map_wc(bo, vm); + bo->exclusive_vm_root_gem = panthor_vm_root_gem(vm); + drm_gem_object_get(bo->exclusive_vm_root_gem); + bo->base.base.resv = bo->exclusive_vm_root_gem->resv; + + if (vm == panthor_fw_vm(ptdev)) + debug_flags |= PANTHOR_DEBUGFS_GEM_USAGE_FLAG_FW_MAPPED; + + panthor_gem_kernel_bo_set_label(kbo, name); + panthor_gem_debugfs_set_usage_flags(to_panthor_bo(kbo->obj), debug_flags); + + /* The system and GPU MMU page size might differ, which becomes a + * problem for FW sections that need to be mapped at explicit address + * since our PAGE_SIZE alignment might cover a VA range that's + * expected to be used for another section. + * Make sure we never map more than we need. + */ + size = ALIGN(size, panthor_vm_page_size(vm)); + ret = panthor_vm_alloc_va(vm, gpu_va, size, &kbo->va_node); + if (ret) + goto err_put_obj; + + ret = panthor_vm_map_bo_range(vm, bo, 0, size, kbo->va_node.start, vm_map_flags); + if (ret) + goto err_free_va; + + kbo->vm = panthor_vm_get(vm); + return kbo; + +err_free_va: + panthor_vm_free_va(vm, &kbo->va_node); + +err_put_obj: + drm_gem_object_put(&obj->base); + +err_free_bo: + kfree(kbo); + return ERR_PTR(ret); +} + #ifdef CONFIG_DEBUG_FS struct gem_size_totals { size_t size; -- cgit v1.2.3 From 2b207c47c9cfcdfbaff1be61d09c71b1edc3f0ce Mon Sep 17 00:00:00 2001 From: Boris Brezillon Date: Wed, 1 Apr 2026 15:48:49 +0200 Subject: drm/panthor: Don't call drm_gpuvm_bo_extobj_add() if the object is private drm_gpuvm_bo_extobj_add() is a NOP if the object is private, but it forces us to take/release the VM resv lock, so let's do that only when we know the object can be shared. v3: - New commit v4: - Collect R-bs v5: - No changes v6: - No changes v7: - No changes Reviewed-by: Steven Price Reviewed-by: Liviu Dudau Link: https://patch.msgid.link/20260401134854.2275433-6-boris.brezillon@collabora.com Signed-off-by: Boris Brezillon --- drivers/gpu/drm/panthor/panthor_mmu.c | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/drivers/gpu/drm/panthor/panthor_mmu.c b/drivers/gpu/drm/panthor/panthor_mmu.c index ab67286e3a6e..ac11c8c6a863 100644 --- a/drivers/gpu/drm/panthor/panthor_mmu.c +++ b/drivers/gpu/drm/panthor/panthor_mmu.c @@ -1278,9 +1278,11 @@ static int panthor_vm_prepare_map_op_ctx(struct panthor_vm_op_ctx *op_ctx, } /* Insert BO into the extobj list last, when we know nothing can fail. */ - dma_resv_lock(panthor_vm_resv(vm), NULL); - drm_gpuvm_bo_extobj_add(op_ctx->map.vm_bo); - dma_resv_unlock(panthor_vm_resv(vm)); + if (bo->base.base.resv != panthor_vm_resv(vm)) { + dma_resv_lock(panthor_vm_resv(vm), NULL); + drm_gpuvm_bo_extobj_add(op_ctx->map.vm_bo); + dma_resv_unlock(panthor_vm_resv(vm)); + } return 0; -- cgit v1.2.3 From 68cbf96b1e9b96af3ad866b96b5c2092cb915c6c Mon Sep 17 00:00:00 2001 From: Boris Brezillon Date: Wed, 1 Apr 2026 15:48:50 +0200 Subject: drm/panthor: Part ways with drm_gem_shmem_object While drm_gem_shmem_object does most of the job we need it to do, the way sub-resources (pages, sgt, vmap) are handled and their lifetimes gets in the way of BO reclaim. There has been attempts to address that [1], but in the meantime, new gem_shmem users were introduced (accel drivers), and some of them manually free some of these resources. This makes things harder to control/sanitize/validate. Thomas Zimmerman is not a huge fan of enforcing lifetimes of sub-resources and forcing gem_shmem users to go through new gem_shmem helpers when they need manual control of some sort, and I believe this is a dead end if we don't force users to follow some stricter rules through carefully designed helpers, because there will always be one user doing crazy things with gem_shmem_object internals, which ends up tripping out the common helpers when they are called. The consensus we reached was that we would be better off forking gem_shmem in panthor. So here we are, parting ways with gem_shmem. The current transition tries to minimize the changes, but there are still some aspects that are different, the main one being that we no longer have a pages_use_count, and pages stays around until the GEM object is destroyed (or when evicted once we've added a shrinker). The sgt also no longer retains pages. This is losely based on how msm does things by the way. If there's any interest in sharing code (probably with msm, since the panthor shrinker is going to be losely based on the msm implementation), we can always change gears and do that once we have everything working/merged. [1]https://patchwork.kernel.org/project/dri-devel/patch/20240105184624.508603-1-dmitry.osipenko@collabora.com/ v2: - Fix refcounting - Add a _locked suffix to a bunch of functions expecting the resv lock to be held - Take the lock before releasing resources in panthor_gem_free_object() v3: - Use ERR_CAST() to fix an ERR-ptr deref - Add missing resv_[un]lock() around a panthor_gem_backing_unpin_locked() call v4: - Fix an error path in panthor_gem_vmap_get_locked() - Don't leave bo->base.pages with an ERR_PTR() - Make panthor_gem_{pin,unpin}[_locked]() more consistent - Don't fail in panthor_gem_dev_map_get_sgt_locked() if the pages are not allocated v5: - Add missing static specifier on our vm_ops v6: - Fix huge_fault handling - s/uint32_t/u32/ - s/drm_dbg_kms/drm_dbg_driver/ - Collect R-bs v7: - No changes Reviewed-by: Steven Price Reviewed-by: Liviu Dudau Link: https://patch.msgid.link/20260401134854.2275433-7-boris.brezillon@collabora.com Signed-off-by: Boris Brezillon --- drivers/gpu/drm/panthor/Kconfig | 1 - drivers/gpu/drm/panthor/panthor_drv.c | 7 +- drivers/gpu/drm/panthor/panthor_fw.c | 16 +- drivers/gpu/drm/panthor/panthor_gem.c | 696 ++++++++++++++++++++++++++------ drivers/gpu/drm/panthor/panthor_gem.h | 62 ++- drivers/gpu/drm/panthor/panthor_mmu.c | 48 +-- drivers/gpu/drm/panthor/panthor_sched.c | 9 +- 7 files changed, 670 insertions(+), 169 deletions(-) diff --git a/drivers/gpu/drm/panthor/Kconfig b/drivers/gpu/drm/panthor/Kconfig index 55b40ad07f3b..911e7f4810c3 100644 --- a/drivers/gpu/drm/panthor/Kconfig +++ b/drivers/gpu/drm/panthor/Kconfig @@ -8,7 +8,6 @@ config DRM_PANTHOR depends on MMU select DEVFREQ_GOV_SIMPLE_ONDEMAND select DRM_EXEC - select DRM_GEM_SHMEM_HELPER select DRM_GPUVM select DRM_SCHED select IOMMU_IO_PGTABLE_LPAE diff --git a/drivers/gpu/drm/panthor/panthor_drv.c b/drivers/gpu/drm/panthor/panthor_drv.c index b1339d4db0a9..73fc983dc9b4 100644 --- a/drivers/gpu/drm/panthor/panthor_drv.c +++ b/drivers/gpu/drm/panthor/panthor_drv.c @@ -21,6 +21,7 @@ #include #include #include +#include #include #include #include @@ -1578,7 +1579,7 @@ static int panthor_ioctl_bo_query_info(struct drm_device *ddev, void *data, args->create_flags = bo->flags; args->extra_flags = 0; - if (drm_gem_is_imported(&bo->base.base)) + if (drm_gem_is_imported(&bo->base)) args->extra_flags |= DRM_PANTHOR_BO_IS_IMPORTED; drm_gem_object_put(obj); @@ -1793,8 +1794,7 @@ static const struct drm_driver panthor_drm_driver = { .major = 1, .minor = 8, - .gem_create_object = panthor_gem_create_object, - .gem_prime_import_sg_table = drm_gem_shmem_prime_import_sg_table, + .gem_prime_import_sg_table = panthor_gem_prime_import_sg_table, .gem_prime_import = panthor_gem_prime_import, #ifdef CONFIG_DEBUG_FS .debugfs_init = panthor_debugfs_init, @@ -1944,3 +1944,4 @@ module_exit(panthor_exit); MODULE_AUTHOR("Panthor Project Developers"); MODULE_DESCRIPTION("Panthor DRM Driver"); MODULE_LICENSE("Dual MIT/GPL"); +MODULE_IMPORT_NS("DMA_BUF"); diff --git a/drivers/gpu/drm/panthor/panthor_fw.c b/drivers/gpu/drm/panthor/panthor_fw.c index 8886002e1d31..be0da5b1f3ab 100644 --- a/drivers/gpu/drm/panthor/panthor_fw.c +++ b/drivers/gpu/drm/panthor/panthor_fw.c @@ -628,7 +628,6 @@ static int panthor_fw_load_section_entry(struct panthor_device *ptdev, u32 cache_mode = hdr.flags & CSF_FW_BINARY_IFACE_ENTRY_CACHE_MODE_MASK; struct panthor_gem_object *bo; u32 vm_map_flags = 0; - struct sg_table *sgt; u64 va = hdr.va.start; if (!(hdr.flags & CSF_FW_BINARY_IFACE_ENTRY_WR)) @@ -666,11 +665,12 @@ static int panthor_fw_load_section_entry(struct panthor_device *ptdev, panthor_fw_init_section_mem(ptdev, section); bo = to_panthor_bo(section->mem->obj); - sgt = drm_gem_shmem_get_pages_sgt(&bo->base); - if (IS_ERR(sgt)) - return PTR_ERR(sgt); - dma_sync_sgtable_for_device(ptdev->base.dev, sgt, DMA_TO_DEVICE); + /* An sgt should have been requested when the kernel BO was GPU-mapped. */ + if (drm_WARN_ON_ONCE(&ptdev->base, !bo->dmap.sgt)) + return -EINVAL; + + dma_sync_sgtable_for_device(ptdev->base.dev, bo->dmap.sgt, DMA_TO_DEVICE); } if (hdr.va.start == CSF_MCU_SHARED_REGION_START) @@ -730,8 +730,10 @@ panthor_reload_fw_sections(struct panthor_device *ptdev, bool full_reload) continue; panthor_fw_init_section_mem(ptdev, section); - sgt = drm_gem_shmem_get_pages_sgt(&to_panthor_bo(section->mem->obj)->base); - if (!drm_WARN_ON(&ptdev->base, IS_ERR_OR_NULL(sgt))) + + /* An sgt should have been requested when the kernel BO was GPU-mapped. */ + sgt = to_panthor_bo(section->mem->obj)->dmap.sgt; + if (!drm_WARN_ON_ONCE(&ptdev->base, !sgt)) dma_sync_sgtable_for_device(ptdev->base.dev, sgt, DMA_TO_DEVICE); } } diff --git a/drivers/gpu/drm/panthor/panthor_gem.c b/drivers/gpu/drm/panthor/panthor_gem.c index 5065f99c9bc4..0723a0dc0127 100644 --- a/drivers/gpu/drm/panthor/panthor_gem.c +++ b/drivers/gpu/drm/panthor/panthor_gem.c @@ -8,9 +8,11 @@ #include #include #include +#include #include #include +#include #include #include @@ -44,7 +46,7 @@ static void panthor_gem_debugfs_bo_init(struct panthor_gem_object *bo) static void panthor_gem_debugfs_bo_add(struct panthor_gem_object *bo) { - struct panthor_device *ptdev = container_of(bo->base.base.dev, + struct panthor_device *ptdev = container_of(bo->base.dev, struct panthor_device, base); bo->debugfs.creator.tgid = current->tgid; @@ -57,7 +59,7 @@ static void panthor_gem_debugfs_bo_add(struct panthor_gem_object *bo) static void panthor_gem_debugfs_bo_rm(struct panthor_gem_object *bo) { - struct panthor_device *ptdev = container_of(bo->base.base.dev, + struct panthor_device *ptdev = container_of(bo->base.dev, struct panthor_device, base); if (list_empty(&bo->debugfs.node)) @@ -80,9 +82,9 @@ static void panthor_gem_debugfs_bo_init(struct panthor_gem_object *bo) {} #endif static bool -should_map_wc(struct panthor_gem_object *bo, struct panthor_vm *exclusive_vm) +should_map_wc(struct panthor_gem_object *bo) { - struct panthor_device *ptdev = container_of(bo->base.base.dev, struct panthor_device, base); + struct panthor_device *ptdev = container_of(bo->base.dev, struct panthor_device, base); /* We can't do uncached mappings if the device is coherent, * because the zeroing done by the shmem layer at page allocation @@ -112,6 +114,210 @@ should_map_wc(struct panthor_gem_object *bo, struct panthor_vm *exclusive_vm) return true; } +static void +panthor_gem_backing_cleanup_locked(struct panthor_gem_object *bo) +{ + dma_resv_assert_held(bo->base.resv); + + if (!bo->backing.pages) + return; + + drm_gem_put_pages(&bo->base, bo->backing.pages, true, false); + bo->backing.pages = NULL; +} + +static int +panthor_gem_backing_get_pages_locked(struct panthor_gem_object *bo) +{ + struct page **pages; + + dma_resv_assert_held(bo->base.resv); + + if (bo->backing.pages) + return 0; + + pages = drm_gem_get_pages(&bo->base); + if (IS_ERR(pages)) { + drm_dbg_driver(bo->base.dev, "Failed to get pages (%pe)\n", pages); + return PTR_ERR(pages); + } + + bo->backing.pages = pages; + return 0; +} + +static int panthor_gem_backing_pin_locked(struct panthor_gem_object *bo) +{ + int ret; + + dma_resv_assert_held(bo->base.resv); + drm_WARN_ON_ONCE(bo->base.dev, drm_gem_is_imported(&bo->base)); + + if (refcount_inc_not_zero(&bo->backing.pin_count)) + return 0; + + ret = panthor_gem_backing_get_pages_locked(bo); + if (!ret) + refcount_set(&bo->backing.pin_count, 1); + + return ret; +} + +static void panthor_gem_backing_unpin_locked(struct panthor_gem_object *bo) +{ + dma_resv_assert_held(bo->base.resv); + drm_WARN_ON_ONCE(bo->base.dev, drm_gem_is_imported(&bo->base)); + + if (refcount_dec_and_test(&bo->backing.pin_count)) { + /* We don't release anything when pin_count drops to zero. + * Pages stay there until an explicit cleanup is requested. + */ + } +} + +static void +panthor_gem_dev_map_cleanup_locked(struct panthor_gem_object *bo) +{ + dma_resv_assert_held(bo->base.resv); + + if (!bo->dmap.sgt) + return; + + dma_unmap_sgtable(drm_dev_dma_dev(bo->base.dev), bo->dmap.sgt, DMA_BIDIRECTIONAL, 0); + sg_free_table(bo->dmap.sgt); + kfree(bo->dmap.sgt); + bo->dmap.sgt = NULL; +} + +static struct sg_table * +panthor_gem_dev_map_get_sgt_locked(struct panthor_gem_object *bo) +{ + struct sg_table *sgt; + int ret; + + dma_resv_assert_held(bo->base.resv); + + if (bo->dmap.sgt) + return bo->dmap.sgt; + + /* Pages stay around after they've been allocated. At least that stands + * until we add a shrinker. + */ + ret = panthor_gem_backing_get_pages_locked(bo); + if (ret) + return ERR_PTR(ret); + + sgt = drm_prime_pages_to_sg(bo->base.dev, bo->backing.pages, + bo->base.size >> PAGE_SHIFT); + if (IS_ERR(sgt)) + return sgt; + + /* Map the pages for use by the h/w. */ + ret = dma_map_sgtable(drm_dev_dma_dev(bo->base.dev), sgt, DMA_BIDIRECTIONAL, 0); + if (ret) + goto err_free_sgt; + + bo->dmap.sgt = sgt; + return sgt; + +err_free_sgt: + sg_free_table(sgt); + kfree(sgt); + return ERR_PTR(ret); +} + +struct sg_table * +panthor_gem_get_dev_sgt(struct panthor_gem_object *bo) +{ + struct sg_table *sgt; + + dma_resv_lock(bo->base.resv, NULL); + sgt = panthor_gem_dev_map_get_sgt_locked(bo); + dma_resv_unlock(bo->base.resv); + + return sgt; +} + +static void +panthor_gem_vmap_cleanup_locked(struct panthor_gem_object *bo) +{ + if (!bo->cmap.vaddr) + return; + + vunmap(bo->cmap.vaddr); + bo->cmap.vaddr = NULL; + panthor_gem_backing_unpin_locked(bo); +} + +static int +panthor_gem_prep_for_cpu_map_locked(struct panthor_gem_object *bo) +{ + if (should_map_wc(bo)) { + struct sg_table *sgt; + + sgt = panthor_gem_dev_map_get_sgt_locked(bo); + if (IS_ERR(sgt)) + return PTR_ERR(sgt); + } + + return 0; +} + +static void * +panthor_gem_vmap_get_locked(struct panthor_gem_object *bo) +{ + pgprot_t prot = PAGE_KERNEL; + void *vaddr; + int ret; + + dma_resv_assert_held(bo->base.resv); + + if (drm_WARN_ON_ONCE(bo->base.dev, drm_gem_is_imported(&bo->base))) + return ERR_PTR(-EINVAL); + + if (refcount_inc_not_zero(&bo->cmap.vaddr_use_count)) { + drm_WARN_ON_ONCE(bo->base.dev, !bo->cmap.vaddr); + return bo->cmap.vaddr; + } + + ret = panthor_gem_backing_pin_locked(bo); + if (ret) + return ERR_PTR(ret); + + ret = panthor_gem_prep_for_cpu_map_locked(bo); + if (ret) + goto err_unpin; + + if (should_map_wc(bo)) + prot = pgprot_writecombine(prot); + + vaddr = vmap(bo->backing.pages, bo->base.size >> PAGE_SHIFT, VM_MAP, prot); + if (!vaddr) { + ret = -ENOMEM; + goto err_unpin; + } + + bo->cmap.vaddr = vaddr; + refcount_set(&bo->cmap.vaddr_use_count, 1); + return vaddr; + +err_unpin: + panthor_gem_backing_unpin_locked(bo); + return ERR_PTR(ret); +} + +static void +panthor_gem_vmap_put_locked(struct panthor_gem_object *bo) +{ + dma_resv_assert_held(bo->base.resv); + + if (drm_WARN_ON_ONCE(bo->base.dev, drm_gem_is_imported(&bo->base))) + return; + + if (refcount_dec_and_test(&bo->cmap.vaddr_use_count)) + panthor_gem_vmap_cleanup_locked(bo); +} + static void panthor_gem_free_object(struct drm_gem_object *obj) { struct panthor_gem_object *bo = to_panthor_bo(obj); @@ -127,8 +333,19 @@ static void panthor_gem_free_object(struct drm_gem_object *obj) mutex_destroy(&bo->label.lock); - drm_gem_free_mmap_offset(&bo->base.base); - drm_gem_shmem_free(&bo->base); + if (drm_gem_is_imported(obj)) { + drm_prime_gem_destroy(obj, bo->dmap.sgt); + } else { + dma_resv_lock(obj->resv, NULL); + panthor_gem_vmap_cleanup_locked(bo); + panthor_gem_dev_map_cleanup_locked(bo); + panthor_gem_backing_cleanup_locked(bo); + dma_resv_unlock(obj->resv); + } + + drm_gem_object_release(obj); + + kfree(bo); drm_gem_object_put(vm_root_gem); } @@ -159,15 +376,15 @@ panthor_gem_prime_begin_cpu_access(struct dma_buf *dma_buf, { struct drm_gem_object *obj = dma_buf->priv; struct drm_device *dev = obj->dev; - struct drm_gem_shmem_object *shmem = to_drm_gem_shmem_obj(obj); + struct panthor_gem_object *bo = to_panthor_bo(obj); struct dma_buf_attachment *attach; dma_resv_lock(obj->resv, NULL); - if (shmem->sgt) - dma_sync_sgtable_for_cpu(dev->dev, shmem->sgt, dir); + if (bo->dmap.sgt) + dma_sync_sgtable_for_cpu(drm_dev_dma_dev(dev), bo->dmap.sgt, dir); - if (shmem->vaddr) - invalidate_kernel_vmap_range(shmem->vaddr, shmem->base.size); + if (bo->cmap.vaddr) + invalidate_kernel_vmap_range(bo->cmap.vaddr, bo->base.size); list_for_each_entry(attach, &dma_buf->attachments, node) { struct sg_table *sgt = attach->priv; @@ -186,7 +403,7 @@ panthor_gem_prime_end_cpu_access(struct dma_buf *dma_buf, { struct drm_gem_object *obj = dma_buf->priv; struct drm_device *dev = obj->dev; - struct drm_gem_shmem_object *shmem = to_drm_gem_shmem_obj(obj); + struct panthor_gem_object *bo = to_panthor_bo(obj); struct dma_buf_attachment *attach; dma_resv_lock(obj->resv, NULL); @@ -197,11 +414,11 @@ panthor_gem_prime_end_cpu_access(struct dma_buf *dma_buf, dma_sync_sgtable_for_device(attach->dev, sgt, dir); } - if (shmem->vaddr) - flush_kernel_vmap_range(shmem->vaddr, shmem->base.size); + if (bo->cmap.vaddr) + flush_kernel_vmap_range(bo->cmap.vaddr, bo->base.size); - if (shmem->sgt) - dma_sync_sgtable_for_device(dev->dev, shmem->sgt, dir); + if (bo->dmap.sgt) + dma_sync_sgtable_for_device(drm_dev_dma_dev(dev), bo->dmap.sgt, dir); dma_resv_unlock(obj->resv); return 0; @@ -258,53 +475,345 @@ panthor_gem_prime_import(struct drm_device *dev, return drm_gem_prime_import(dev, dma_buf); } +static void panthor_gem_print_info(struct drm_printer *p, unsigned int indent, + const struct drm_gem_object *obj) +{ + const struct panthor_gem_object *bo = to_panthor_bo(obj); + + if (drm_gem_is_imported(&bo->base)) + return; + + drm_printf_indent(p, indent, "resident=%s\n", str_true_false(bo->backing.pages)); + drm_printf_indent(p, indent, "pages_pin_count=%u\n", refcount_read(&bo->backing.pin_count)); + drm_printf_indent(p, indent, "vmap_use_count=%u\n", + refcount_read(&bo->cmap.vaddr_use_count)); + drm_printf_indent(p, indent, "vaddr=%p\n", bo->cmap.vaddr); +} + +static int panthor_gem_pin_locked(struct drm_gem_object *obj) +{ + if (!drm_gem_is_imported(obj)) + return panthor_gem_backing_pin_locked(to_panthor_bo(obj)); + + return 0; +} + +static void panthor_gem_unpin_locked(struct drm_gem_object *obj) +{ + if (!drm_gem_is_imported(obj)) + panthor_gem_backing_unpin_locked(to_panthor_bo(obj)); +} + +int panthor_gem_pin(struct panthor_gem_object *bo) +{ + int ret = 0; + + if (drm_gem_is_imported(&bo->base)) + return 0; + + if (refcount_inc_not_zero(&bo->backing.pin_count)) + return 0; + + dma_resv_lock(bo->base.resv, NULL); + ret = panthor_gem_backing_pin_locked(bo); + dma_resv_unlock(bo->base.resv); + + return ret; +} + +void panthor_gem_unpin(struct panthor_gem_object *bo) +{ + if (drm_gem_is_imported(&bo->base)) + return; + + if (refcount_dec_not_one(&bo->backing.pin_count)) + return; + + dma_resv_lock(bo->base.resv, NULL); + panthor_gem_backing_unpin_locked(bo); + dma_resv_unlock(bo->base.resv); +} + +static struct sg_table *panthor_gem_get_sg_table(struct drm_gem_object *obj) +{ + struct panthor_gem_object *bo = to_panthor_bo(obj); + + drm_WARN_ON_ONCE(obj->dev, drm_gem_is_imported(obj)); + drm_WARN_ON_ONCE(obj->dev, !bo->backing.pages); + drm_WARN_ON_ONCE(obj->dev, !refcount_read(&bo->backing.pin_count)); + + return drm_prime_pages_to_sg(obj->dev, bo->backing.pages, obj->size >> PAGE_SHIFT); +} + +static int panthor_gem_vmap_locked(struct drm_gem_object *obj, + struct iosys_map *map) +{ + struct panthor_gem_object *bo = to_panthor_bo(obj); + void *vaddr; + + dma_resv_assert_held(obj->resv); + + if (drm_gem_is_imported(obj)) + return dma_buf_vmap(obj->import_attach->dmabuf, map); + + vaddr = panthor_gem_vmap_get_locked(bo); + if (IS_ERR(vaddr)) + return PTR_ERR(vaddr); + + iosys_map_set_vaddr(map, vaddr); + return 0; +} + +static void panthor_gem_vunmap_locked(struct drm_gem_object *obj, + struct iosys_map *map) +{ + struct panthor_gem_object *bo = to_panthor_bo(obj); + + dma_resv_assert_held(obj->resv); + + if (drm_gem_is_imported(obj)) { + dma_buf_vunmap(obj->import_attach->dmabuf, map); + } else { + drm_WARN_ON_ONCE(obj->dev, bo->cmap.vaddr != map->vaddr); + panthor_gem_vmap_put_locked(bo); + } +} + +static int panthor_gem_mmap(struct drm_gem_object *obj, struct vm_area_struct *vma) +{ + struct panthor_gem_object *bo = to_panthor_bo(obj); + int ret; + + if (drm_gem_is_imported(obj)) { + /* Reset both vm_ops and vm_private_data, so we don't end up with + * vm_ops pointing to our implementation if the dma-buf backend + * doesn't set those fields. + */ + vma->vm_private_data = NULL; + vma->vm_ops = NULL; + + ret = dma_buf_mmap(obj->dma_buf, vma, 0); + + /* Drop the reference drm_gem_mmap_obj() acquired.*/ + if (!ret) + drm_gem_object_put(obj); + + return ret; + } + + if (is_cow_mapping(vma->vm_flags)) + return -EINVAL; + + dma_resv_lock(obj->resv, NULL); + ret = panthor_gem_backing_get_pages_locked(bo); + if (!ret) + ret = panthor_gem_prep_for_cpu_map_locked(bo); + dma_resv_unlock(obj->resv); + + if (ret) + return ret; + + vm_flags_set(vma, VM_PFNMAP | VM_DONTEXPAND | VM_DONTDUMP); + vma->vm_page_prot = vm_get_page_prot(vma->vm_flags); + if (should_map_wc(bo)) + vma->vm_page_prot = pgprot_writecombine(vma->vm_page_prot); + + return 0; +} + static enum drm_gem_object_status panthor_gem_status(struct drm_gem_object *obj) { struct panthor_gem_object *bo = to_panthor_bo(obj); enum drm_gem_object_status res = 0; - if (drm_gem_is_imported(&bo->base.base) || bo->base.pages) + if (drm_gem_is_imported(&bo->base) || bo->backing.pages) res |= DRM_GEM_OBJECT_RESIDENT; return res; } +static vm_fault_t insert_page(struct vm_fault *vmf, unsigned int order, struct page *page) +{ + if (!order) { + return vmf_insert_pfn(vmf->vma, vmf->address, page_to_pfn(page)); +#ifdef CONFIG_ARCH_SUPPORTS_PMD_PFNMAP + } else if (order == PMD_ORDER) { + unsigned long pfn = page_to_pfn(page); + unsigned long paddr = pfn << PAGE_SHIFT; + bool aligned = (vmf->address & ~PMD_MASK) == (paddr & ~PMD_MASK); + + if (aligned && + folio_test_pmd_mappable(page_folio(page))) { + pfn &= PMD_MASK >> PAGE_SHIFT; + return vmf_insert_pfn_pmd(vmf, pfn, vmf->flags & FAULT_FLAG_WRITE); + } +#endif + } + + return VM_FAULT_FALLBACK; +} + +static vm_fault_t panthor_gem_any_fault(struct vm_fault *vmf, unsigned int order) +{ + struct vm_area_struct *vma = vmf->vma; + struct drm_gem_object *obj = vma->vm_private_data; + struct panthor_gem_object *bo = to_panthor_bo(vma->vm_private_data); + loff_t num_pages = obj->size >> PAGE_SHIFT; + vm_fault_t ret; + pgoff_t page_offset; + + if (order && order != PMD_ORDER) + return VM_FAULT_FALLBACK; + + /* Offset to faulty address in the VMA. */ + page_offset = vmf->pgoff - vma->vm_pgoff; + + dma_resv_lock(bo->base.resv, NULL); + + if (page_offset >= num_pages || + drm_WARN_ON_ONCE(obj->dev, !bo->backing.pages)) { + ret = VM_FAULT_SIGBUS; + goto out; + } + + ret = insert_page(vmf, order, bo->backing.pages[page_offset]); + + out: + dma_resv_unlock(bo->base.resv); + + return ret; +} + +static vm_fault_t panthor_gem_fault(struct vm_fault *vmf) +{ + return panthor_gem_any_fault(vmf, 0); +} + +static void panthor_gem_vm_open(struct vm_area_struct *vma) +{ + struct panthor_gem_object *bo = to_panthor_bo(vma->vm_private_data); + + drm_WARN_ON(bo->base.dev, drm_gem_is_imported(&bo->base)); + + dma_resv_lock(bo->base.resv, NULL); + + /* We should have already pinned the pages when the buffer was first + * mmap'd, vm_open() just grabs an additional reference for the new + * mm the vma is getting copied into (ie. on fork()). + */ + drm_WARN_ON_ONCE(bo->base.dev, !bo->backing.pages); + + dma_resv_unlock(bo->base.resv); + + drm_gem_vm_open(vma); +} + +static const struct vm_operations_struct panthor_gem_vm_ops = { + .fault = panthor_gem_fault, +#ifdef CONFIG_ARCH_SUPPORTS_PMD_PFNMAP + .huge_fault = panthor_gem_any_fault, +#endif + .open = panthor_gem_vm_open, + .close = drm_gem_vm_close, +}; + static const struct drm_gem_object_funcs panthor_gem_funcs = { .free = panthor_gem_free_object, - .print_info = drm_gem_shmem_object_print_info, - .pin = drm_gem_shmem_object_pin, - .unpin = drm_gem_shmem_object_unpin, - .get_sg_table = drm_gem_shmem_object_get_sg_table, - .vmap = drm_gem_shmem_object_vmap, - .vunmap = drm_gem_shmem_object_vunmap, - .mmap = drm_gem_shmem_object_mmap, + .print_info = panthor_gem_print_info, + .pin = panthor_gem_pin_locked, + .unpin = panthor_gem_unpin_locked, + .get_sg_table = panthor_gem_get_sg_table, + .vmap = panthor_gem_vmap_locked, + .vunmap = panthor_gem_vunmap_locked, + .mmap = panthor_gem_mmap, .status = panthor_gem_status, .export = panthor_gem_prime_export, - .vm_ops = &drm_gem_shmem_vm_ops, + .vm_ops = &panthor_gem_vm_ops, }; -/** - * panthor_gem_create_object - Implementation of driver->gem_create_object. - * @ddev: DRM device - * @size: Size in bytes of the memory the object will reference - * - * This lets the GEM helpers allocate object structs for us, and keep - * our BO stats correct. - */ -struct drm_gem_object *panthor_gem_create_object(struct drm_device *ddev, size_t size) +static struct panthor_gem_object * +panthor_gem_alloc_object(u32 flags) { - struct panthor_gem_object *obj; + struct panthor_gem_object *bo; - obj = kzalloc_obj(*obj); - if (!obj) + bo = kzalloc_obj(*bo); + if (!bo) return ERR_PTR(-ENOMEM); - obj->base.base.funcs = &panthor_gem_funcs; - mutex_init(&obj->label.lock); + bo->base.funcs = &panthor_gem_funcs; + bo->flags = flags; + mutex_init(&bo->label.lock); + panthor_gem_debugfs_bo_init(bo); + return bo; +} + +static struct panthor_gem_object * +panthor_gem_create(struct drm_device *dev, size_t size, uint32_t flags, + struct panthor_vm *exclusive_vm, u32 usage_flags) +{ + struct panthor_gem_object *bo; + int ret; + + bo = panthor_gem_alloc_object(flags); + if (IS_ERR(bo)) + return bo; + + size = PAGE_ALIGN(size); + ret = drm_gem_object_init(dev, &bo->base, size); + if (ret) + goto err_put; + + /* Our buffers are kept pinned, so allocating them + * from the MOVABLE zone is a really bad idea, and + * conflicts with CMA. See comments above new_inode() + * why this is required _and_ expected if you're + * going to pin these pages. + */ + mapping_set_gfp_mask(bo->base.filp->f_mapping, + GFP_HIGHUSER | __GFP_RETRY_MAYFAIL | __GFP_NOWARN); + + ret = drm_gem_create_mmap_offset(&bo->base); + if (ret) + goto err_put; + + if (exclusive_vm) { + bo->exclusive_vm_root_gem = panthor_vm_root_gem(exclusive_vm); + drm_gem_object_get(bo->exclusive_vm_root_gem); + bo->base.resv = bo->exclusive_vm_root_gem->resv; + } + + panthor_gem_debugfs_set_usage_flags(bo, usage_flags); + return bo; + +err_put: + drm_gem_object_put(&bo->base); + return ERR_PTR(ret); +} + +struct drm_gem_object * +panthor_gem_prime_import_sg_table(struct drm_device *dev, + struct dma_buf_attachment *attach, + struct sg_table *sgt) +{ + struct panthor_gem_object *bo; + int ret; + + bo = panthor_gem_alloc_object(0); + if (IS_ERR(bo)) + return ERR_CAST(bo); + + drm_gem_private_object_init(dev, &bo->base, attach->dmabuf->size); - panthor_gem_debugfs_bo_init(obj); + ret = drm_gem_create_mmap_offset(&bo->base); + if (ret) + goto err_put; - return &obj->base.base; + bo->dmap.sgt = sgt; + return &bo->base; + +err_put: + drm_gem_object_put(&bo->base); + return ERR_PTR(ret); } /** @@ -325,54 +834,22 @@ panthor_gem_create_with_handle(struct drm_file *file, u64 *size, u32 flags, u32 *handle) { int ret; - struct drm_gem_shmem_object *shmem; struct panthor_gem_object *bo; - shmem = drm_gem_shmem_create(ddev, *size); - if (IS_ERR(shmem)) - return PTR_ERR(shmem); - - bo = to_panthor_bo(&shmem->base); - bo->flags = flags; - bo->base.map_wc = should_map_wc(bo, exclusive_vm); - - if (exclusive_vm) { - bo->exclusive_vm_root_gem = panthor_vm_root_gem(exclusive_vm); - drm_gem_object_get(bo->exclusive_vm_root_gem); - bo->base.base.resv = bo->exclusive_vm_root_gem->resv; - } - - panthor_gem_debugfs_set_usage_flags(bo, 0); - - /* If this is a write-combine mapping, we query the sgt to force a CPU - * cache flush (dma_map_sgtable() is called when the sgt is created). - * This ensures the zero-ing is visible to any uncached mapping created - * by vmap/mmap. - * FIXME: Ideally this should be done when pages are allocated, not at - * BO creation time. - */ - if (shmem->map_wc) { - struct sg_table *sgt; - - sgt = drm_gem_shmem_get_pages_sgt(shmem); - if (IS_ERR(sgt)) { - ret = PTR_ERR(sgt); - goto out_put_gem; - } - } + bo = panthor_gem_create(ddev, *size, flags, exclusive_vm, 0); + if (IS_ERR(bo)) + return PTR_ERR(bo); /* * Allocate an id of idr table where the obj is registered * and handle has the id what user can see. */ - ret = drm_gem_handle_create(file, &shmem->base, handle); + ret = drm_gem_handle_create(file, &bo->base, handle); if (!ret) - *size = bo->base.base.size; + *size = bo->base.size; -out_put_gem: /* drop reference from allocate - handle holds it now. */ - drm_gem_object_put(&shmem->base); - + drm_gem_object_put(&bo->base); return ret; } @@ -417,18 +894,17 @@ panthor_gem_sync(struct drm_gem_object *obj, u32 type, u64 offset, u64 size) { struct panthor_gem_object *bo = to_panthor_bo(obj); - struct drm_gem_shmem_object *shmem = &bo->base; - const struct drm_device *dev = shmem->base.dev; + struct device *dma_dev = drm_dev_dma_dev(bo->base.dev); struct sg_table *sgt; struct scatterlist *sgl; unsigned int count; /* Make sure the range is in bounds. */ - if (offset + size < offset || offset + size > shmem->base.size) + if (offset + size < offset || offset + size > bo->base.size) return -EINVAL; /* Disallow CPU-cache maintenance on imported buffers. */ - if (drm_gem_is_imported(&shmem->base)) + if (drm_gem_is_imported(&bo->base)) return -EINVAL; switch (type) { @@ -441,14 +917,14 @@ panthor_gem_sync(struct drm_gem_object *obj, u32 type, } /* Don't bother if it's WC-mapped */ - if (shmem->map_wc) + if (should_map_wc(bo)) return 0; /* Nothing to do if the size is zero. */ if (size == 0) return 0; - sgt = drm_gem_shmem_get_pages_sgt(shmem); + sgt = panthor_gem_get_dev_sgt(bo); if (IS_ERR(sgt)) return PTR_ERR(sgt); @@ -489,9 +965,9 @@ panthor_gem_sync(struct drm_gem_object *obj, u32 type, * * for the flush+invalidate case. */ - dma_sync_single_for_device(dev->dev, paddr, len, DMA_TO_DEVICE); + dma_sync_single_for_device(dma_dev, paddr, len, DMA_TO_DEVICE); if (type == DRM_PANTHOR_BO_SYNC_CPU_CACHE_FLUSH_AND_INVALIDATE) - dma_sync_single_for_cpu(dev->dev, paddr, len, DMA_FROM_DEVICE); + dma_sync_single_for_cpu(dma_dev, paddr, len, DMA_FROM_DEVICE); } return 0; @@ -541,7 +1017,6 @@ panthor_kernel_bo_create(struct panthor_device *ptdev, struct panthor_vm *vm, size_t size, u32 bo_flags, u32 vm_map_flags, u64 gpu_va, const char *name) { - struct drm_gem_shmem_object *obj; struct panthor_kernel_bo *kbo; struct panthor_gem_object *bo; u32 debug_flags = PANTHOR_DEBUGFS_GEM_USAGE_FLAG_KERNEL; @@ -554,25 +1029,18 @@ panthor_kernel_bo_create(struct panthor_device *ptdev, struct panthor_vm *vm, if (!kbo) return ERR_PTR(-ENOMEM); - obj = drm_gem_shmem_create(&ptdev->base, size); - if (IS_ERR(obj)) { - ret = PTR_ERR(obj); - goto err_free_bo; - } - - bo = to_panthor_bo(&obj->base); - kbo->obj = &obj->base; - bo->flags = bo_flags; - bo->base.map_wc = should_map_wc(bo, vm); - bo->exclusive_vm_root_gem = panthor_vm_root_gem(vm); - drm_gem_object_get(bo->exclusive_vm_root_gem); - bo->base.base.resv = bo->exclusive_vm_root_gem->resv; - if (vm == panthor_fw_vm(ptdev)) debug_flags |= PANTHOR_DEBUGFS_GEM_USAGE_FLAG_FW_MAPPED; + bo = panthor_gem_create(&ptdev->base, size, bo_flags, vm, debug_flags); + if (IS_ERR(bo)) { + ret = PTR_ERR(bo); + goto err_free_kbo; + } + + kbo->obj = &bo->base; + panthor_gem_kernel_bo_set_label(kbo, name); - panthor_gem_debugfs_set_usage_flags(to_panthor_bo(kbo->obj), debug_flags); /* The system and GPU MMU page size might differ, which becomes a * problem for FW sections that need to be mapped at explicit address @@ -596,9 +1064,9 @@ err_free_va: panthor_vm_free_va(vm, &kbo->va_node); err_put_obj: - drm_gem_object_put(&obj->base); + drm_gem_object_put(&bo->base); -err_free_bo: +err_free_kbo: kfree(kbo); return ERR_PTR(ret); } @@ -646,7 +1114,7 @@ static void panthor_gem_debugfs_bo_print(struct panthor_gem_object *bo, struct seq_file *m, struct gem_size_totals *totals) { - unsigned int refcount = kref_read(&bo->base.base.refcount); + unsigned int refcount = kref_read(&bo->base.refcount); char creator_info[32] = {}; size_t resident_size; u32 gem_usage_flags = bo->debugfs.flags; @@ -656,21 +1124,21 @@ static void panthor_gem_debugfs_bo_print(struct panthor_gem_object *bo, if (!refcount) return; - resident_size = bo->base.pages ? bo->base.base.size : 0; + resident_size = bo->backing.pages ? bo->base.size : 0; snprintf(creator_info, sizeof(creator_info), "%s/%d", bo->debugfs.creator.process_name, bo->debugfs.creator.tgid); seq_printf(m, "%-32s%-16d%-16d%-16zd%-16zd0x%-16lx", creator_info, - bo->base.base.name, + bo->base.name, refcount, - bo->base.base.size, + bo->base.size, resident_size, - drm_vma_node_start(&bo->base.base.vma_node)); + drm_vma_node_start(&bo->base.vma_node)); - if (drm_gem_is_imported(&bo->base.base)) + if (drm_gem_is_imported(&bo->base)) gem_state_flags |= PANTHOR_DEBUGFS_GEM_STATE_FLAG_IMPORTED; - if (bo->base.base.dma_buf) + if (bo->base.dma_buf) gem_state_flags |= PANTHOR_DEBUGFS_GEM_STATE_FLAG_EXPORTED; seq_printf(m, "0x%-8x 0x%-10x", gem_state_flags, gem_usage_flags); @@ -679,10 +1147,8 @@ static void panthor_gem_debugfs_bo_print(struct panthor_gem_object *bo, seq_printf(m, "%s\n", bo->label.str ? : ""); } - totals->size += bo->base.base.size; + totals->size += bo->base.size; totals->resident += resident_size; - if (bo->base.madv > 0) - totals->reclaimable += resident_size; } static void panthor_gem_debugfs_print_bos(struct panthor_device *ptdev, diff --git a/drivers/gpu/drm/panthor/panthor_gem.h b/drivers/gpu/drm/panthor/panthor_gem.h index 94b2d17cf032..b66478c9590c 100644 --- a/drivers/gpu/drm/panthor/panthor_gem.h +++ b/drivers/gpu/drm/panthor/panthor_gem.h @@ -5,7 +5,7 @@ #ifndef __PANTHOR_GEM_H__ #define __PANTHOR_GEM_H__ -#include +#include #include #include @@ -60,12 +60,51 @@ struct panthor_gem_debugfs { u32 flags; }; +/** + * struct panthor_gem_backing - GEM memory backing related data + */ +struct panthor_gem_backing { + /** @pages: Pages requested with drm_gem_get_pages() */ + struct page **pages; + + /** @pin_count: Number of active pin requests on this GEM */ + refcount_t pin_count; +}; + +/** + * struct panthor_gem_cpu_map - GEM CPU mapping related data + */ +struct panthor_gem_cpu_map { + /** @vaddr: Address returned by vmap() */ + void *vaddr; + + /** @vaddr_use_count: Number of active vmap() requests on this GEM */ + refcount_t vaddr_use_count; +}; + +/** + * struct panthor_gem_dev_map - GEM device mapping related data + */ +struct panthor_gem_dev_map { + /** @sgt: Device mapped sg_table for this GEM */ + struct sg_table *sgt; +}; + /** * struct panthor_gem_object - Driver specific GEM object. */ struct panthor_gem_object { - /** @base: Inherit from drm_gem_shmem_object. */ - struct drm_gem_shmem_object base; + /** @base: Inherit from drm_gem_object. */ + struct drm_gem_object base; + + /** @backing: Memory backing state */ + struct panthor_gem_backing backing; + + /** @cmap: CPU mapping state */ + struct panthor_gem_cpu_map cmap; + + /** @dmap: Device mapping state */ + struct panthor_gem_dev_map dmap; /** * @exclusive_vm_root_gem: Root GEM of the exclusive VM this GEM object @@ -130,22 +169,25 @@ struct panthor_kernel_bo { void *kmap; }; -static inline -struct panthor_gem_object *to_panthor_bo(struct drm_gem_object *obj) -{ - return container_of(to_drm_gem_shmem_obj(obj), struct panthor_gem_object, base); -} +#define to_panthor_bo(obj) container_of_const(obj, struct panthor_gem_object, base) void panthor_gem_init(struct panthor_device *ptdev); -struct drm_gem_object *panthor_gem_create_object(struct drm_device *ddev, size_t size); - +struct drm_gem_object * +panthor_gem_prime_import_sg_table(struct drm_device *dev, + struct dma_buf_attachment *attach, + struct sg_table *sgt); int panthor_gem_create_with_handle(struct drm_file *file, struct drm_device *ddev, struct panthor_vm *exclusive_vm, u64 *size, u32 flags, uint32_t *handle); +struct sg_table * +panthor_gem_get_dev_sgt(struct panthor_gem_object *bo); +int panthor_gem_pin(struct panthor_gem_object *bo); +void panthor_gem_unpin(struct panthor_gem_object *bo); + void panthor_gem_bo_set_label(struct drm_gem_object *obj, const char *label); void panthor_gem_kernel_bo_set_label(struct panthor_kernel_bo *bo, const char *label); int panthor_gem_sync(struct drm_gem_object *obj, diff --git a/drivers/gpu/drm/panthor/panthor_mmu.c b/drivers/gpu/drm/panthor/panthor_mmu.c index ac11c8c6a863..1f42ff505883 100644 --- a/drivers/gpu/drm/panthor/panthor_mmu.c +++ b/drivers/gpu/drm/panthor/panthor_mmu.c @@ -5,6 +5,7 @@ #include #include #include +#include #include #include #include @@ -1078,8 +1079,7 @@ static void panthor_vm_bo_free(struct drm_gpuvm_bo *vm_bo) { struct panthor_gem_object *bo = to_panthor_bo(vm_bo->obj); - if (!drm_gem_is_imported(&bo->base.base)) - drm_gem_shmem_unpin(&bo->base); + panthor_gem_unpin(bo); kfree(vm_bo); } @@ -1201,7 +1201,7 @@ static int panthor_vm_prepare_map_op_ctx(struct panthor_vm_op_ctx *op_ctx, return -EINVAL; /* Make sure the VA and size are in-bounds. */ - if (size > bo->base.base.size || offset > bo->base.base.size - size) + if (size > bo->base.size || offset > bo->base.size - size) return -EINVAL; /* If the BO has an exclusive VM attached, it can't be mapped to other VMs. */ @@ -1218,39 +1218,30 @@ static int panthor_vm_prepare_map_op_ctx(struct panthor_vm_op_ctx *op_ctx, if (ret) goto err_cleanup; - if (!drm_gem_is_imported(&bo->base.base)) { - /* Pre-reserve the BO pages, so the map operation doesn't have to - * allocate. This pin is dropped in panthor_vm_bo_free(), so - * once we have successfully called drm_gpuvm_bo_create(), - * GPUVM will take care of dropping the pin for us. - */ - ret = drm_gem_shmem_pin(&bo->base); - if (ret) - goto err_cleanup; - } + /* Pre-reserve the BO pages, so the map operation doesn't have to + * allocate. + */ + ret = panthor_gem_pin(bo); + if (ret) + goto err_cleanup; - sgt = drm_gem_shmem_get_pages_sgt(&bo->base); + sgt = panthor_gem_get_dev_sgt(bo); if (IS_ERR(sgt)) { - if (!drm_gem_is_imported(&bo->base.base)) - drm_gem_shmem_unpin(&bo->base); - + panthor_gem_unpin(bo); ret = PTR_ERR(sgt); goto err_cleanup; } op_ctx->map.sgt = sgt; - preallocated_vm_bo = drm_gpuvm_bo_create(&vm->base, &bo->base.base); + preallocated_vm_bo = drm_gpuvm_bo_create(&vm->base, &bo->base); if (!preallocated_vm_bo) { - if (!drm_gem_is_imported(&bo->base.base)) - drm_gem_shmem_unpin(&bo->base); - + panthor_gem_unpin(bo); ret = -ENOMEM; goto err_cleanup; } op_ctx->map.vm_bo = drm_gpuvm_bo_obtain_prealloc(preallocated_vm_bo); - op_ctx->map.bo_offset = offset; /* L1, L2 and L3 page tables. @@ -1278,7 +1269,7 @@ static int panthor_vm_prepare_map_op_ctx(struct panthor_vm_op_ctx *op_ctx, } /* Insert BO into the extobj list last, when we know nothing can fail. */ - if (bo->base.base.resv != panthor_vm_resv(vm)) { + if (bo->base.resv != panthor_vm_resv(vm)) { dma_resv_lock(panthor_vm_resv(vm), NULL); drm_gpuvm_bo_extobj_add(op_ctx->map.vm_bo); dma_resv_unlock(panthor_vm_resv(vm)); @@ -2049,9 +2040,9 @@ static void panthor_vma_link(struct panthor_vm *vm, { struct panthor_gem_object *bo = to_panthor_bo(vma->base.gem.obj); - mutex_lock(&bo->base.base.gpuva.lock); + mutex_lock(&bo->base.gpuva.lock); drm_gpuva_link(&vma->base, vm_bo); - mutex_unlock(&bo->base.base.gpuva.lock); + mutex_unlock(&bo->base.gpuva.lock); } static void panthor_vma_unlink(struct panthor_vma *vma) @@ -2103,11 +2094,12 @@ static int panthor_gpuva_sm_step_map(struct drm_gpuva_op *op, void *priv) static bool iova_mapped_as_huge_page(struct drm_gpuva_op_map *op, u64 addr) { + struct panthor_gem_object *bo = to_panthor_bo(op->gem.obj); const struct page *pg; pgoff_t bo_offset; bo_offset = addr - op->va.addr + op->gem.offset; - pg = to_panthor_bo(op->gem.obj)->base.pages[bo_offset >> PAGE_SHIFT]; + pg = bo->backing.pages[bo_offset >> PAGE_SHIFT]; return folio_size(page_folio(pg)) >= SZ_2M; } @@ -2176,7 +2168,7 @@ static int panthor_gpuva_sm_step_remap(struct drm_gpuva_op *op, u64 size = op->remap.prev->va.addr + op->remap.prev->va.range - unmap_start; ret = panthor_vm_map_pages(vm, unmap_start, flags_to_prot(unmap_vma->flags), - bo->base.sgt, offset, size); + bo->dmap.sgt, offset, size); if (ret) return ret; @@ -2190,7 +2182,7 @@ static int panthor_gpuva_sm_step_remap(struct drm_gpuva_op *op, u64 size = unmap_start + unmap_range - op->remap.next->va.addr; ret = panthor_vm_map_pages(vm, addr, flags_to_prot(unmap_vma->flags), - bo->base.sgt, op->remap.next->gem.offset, size); + bo->dmap.sgt, op->remap.next->gem.offset, size); if (ret) return ret; diff --git a/drivers/gpu/drm/panthor/panthor_sched.c b/drivers/gpu/drm/panthor/panthor_sched.c index 2fe04d0f0e3a..97581943a138 100644 --- a/drivers/gpu/drm/panthor/panthor_sched.c +++ b/drivers/gpu/drm/panthor/panthor_sched.c @@ -3,7 +3,7 @@ #include #include -#include +#include #include #include #include @@ -871,8 +871,7 @@ panthor_queue_get_syncwait_obj(struct panthor_group *group, struct panthor_queue int ret; if (queue->syncwait.kmap) { - bo = container_of(queue->syncwait.obj, - struct panthor_gem_object, base.base); + bo = to_panthor_bo(queue->syncwait.obj); goto out_sync; } @@ -882,7 +881,7 @@ panthor_queue_get_syncwait_obj(struct panthor_group *group, struct panthor_queue if (drm_WARN_ON(&ptdev->base, IS_ERR_OR_NULL(bo))) goto err_put_syncwait_obj; - queue->syncwait.obj = &bo->base.base; + queue->syncwait.obj = &bo->base; ret = drm_gem_vmap(queue->syncwait.obj, &map); if (drm_WARN_ON(&ptdev->base, ret)) goto err_put_syncwait_obj; @@ -896,7 +895,7 @@ out_sync: * panthor_gem_sync() is a NOP if map_wc=true, so no need to check * it here. */ - panthor_gem_sync(&bo->base.base, + panthor_gem_sync(&bo->base, DRM_PANTHOR_BO_SYNC_CPU_CACHE_FLUSH_AND_INVALIDATE, queue->syncwait.offset, queue->syncwait.sync64 ? -- cgit v1.2.3 From f80c3886ed7b297518e375dbbfb69ceb7b9e7610 Mon Sep 17 00:00:00 2001 From: Boris Brezillon Date: Wed, 1 Apr 2026 15:48:51 +0200 Subject: drm/panthor: Lazily allocate pages on mmap() Defer pages allocation until their first access. v2: - Don't deal with FAULT_FLAG_INTERRUPTIBLE - Make sure bo->backing.pages is never an ERR_PTR() - Drop a useless vm_fault_t local var - Fix comment in panthor_gem_fault() v3: - Collect R-bs v4: - No changes v5: - No changes v6: - Fix huge_fault handling v7: - No changes Reviewed-by: Steven Price Reviewed-by: Liviu Dudau Link: https://patch.msgid.link/20260401134854.2275433-8-boris.brezillon@collabora.com Signed-off-by: Boris Brezillon --- drivers/gpu/drm/panthor/panthor_gem.c | 114 ++++++++++++++++++++++------------ 1 file changed, 73 insertions(+), 41 deletions(-) diff --git a/drivers/gpu/drm/panthor/panthor_gem.c b/drivers/gpu/drm/panthor/panthor_gem.c index 0723a0dc0127..d9c3a71da29b 100644 --- a/drivers/gpu/drm/panthor/panthor_gem.c +++ b/drivers/gpu/drm/panthor/panthor_gem.c @@ -604,15 +604,6 @@ static int panthor_gem_mmap(struct drm_gem_object *obj, struct vm_area_struct *v if (is_cow_mapping(vma->vm_flags)) return -EINVAL; - dma_resv_lock(obj->resv, NULL); - ret = panthor_gem_backing_get_pages_locked(bo); - if (!ret) - ret = panthor_gem_prep_for_cpu_map_locked(bo); - dma_resv_unlock(obj->resv); - - if (ret) - return ret; - vm_flags_set(vma, VM_PFNMAP | VM_DONTEXPAND | VM_DONTDUMP); vma->vm_page_prot = vm_get_page_prot(vma->vm_flags); if (should_map_wc(bo)) @@ -653,59 +644,100 @@ static vm_fault_t insert_page(struct vm_fault *vmf, unsigned int order, struct p return VM_FAULT_FALLBACK; } -static vm_fault_t panthor_gem_any_fault(struct vm_fault *vmf, unsigned int order) +static vm_fault_t nonblocking_page_setup(struct vm_fault *vmf, + unsigned int order, + pgoff_t page_offset) { struct vm_area_struct *vma = vmf->vma; - struct drm_gem_object *obj = vma->vm_private_data; struct panthor_gem_object *bo = to_panthor_bo(vma->vm_private_data); - loff_t num_pages = obj->size >> PAGE_SHIFT; vm_fault_t ret; - pgoff_t page_offset; - if (order && order != PMD_ORDER) - return VM_FAULT_FALLBACK; + if (!dma_resv_trylock(bo->base.resv)) + return VM_FAULT_RETRY; - /* Offset to faulty address in the VMA. */ - page_offset = vmf->pgoff - vma->vm_pgoff; + if (bo->backing.pages) + ret = insert_page(vmf, order, bo->backing.pages[page_offset]); + else + ret = VM_FAULT_RETRY; - dma_resv_lock(bo->base.resv, NULL); + dma_resv_unlock(bo->base.resv); + return ret; +} - if (page_offset >= num_pages || - drm_WARN_ON_ONCE(obj->dev, !bo->backing.pages)) { - ret = VM_FAULT_SIGBUS; - goto out; - } +static vm_fault_t blocking_page_setup(struct vm_fault *vmf, unsigned int order, + struct panthor_gem_object *bo, + pgoff_t page_offset, bool mmap_lock_held) +{ + vm_fault_t ret; + int err; + + err = dma_resv_lock_interruptible(bo->base.resv, NULL); + if (err) + return mmap_lock_held ? VM_FAULT_NOPAGE : VM_FAULT_RETRY; - ret = insert_page(vmf, order, bo->backing.pages[page_offset]); + err = panthor_gem_backing_get_pages_locked(bo); + if (!err) + err = panthor_gem_prep_for_cpu_map_locked(bo); + + if (err) { + ret = mmap_lock_held ? VM_FAULT_SIGBUS : VM_FAULT_RETRY; + } else { + struct page *page = bo->backing.pages[page_offset]; + + if (mmap_lock_held) + ret = insert_page(vmf, order, page); + else + ret = VM_FAULT_RETRY; + } - out: dma_resv_unlock(bo->base.resv); return ret; } -static vm_fault_t panthor_gem_fault(struct vm_fault *vmf) -{ - return panthor_gem_any_fault(vmf, 0); -} - -static void panthor_gem_vm_open(struct vm_area_struct *vma) +static vm_fault_t panthor_gem_any_fault(struct vm_fault *vmf, unsigned int order) { + struct vm_area_struct *vma = vmf->vma; struct panthor_gem_object *bo = to_panthor_bo(vma->vm_private_data); + loff_t num_pages = bo->base.size >> PAGE_SHIFT; + pgoff_t page_offset; + vm_fault_t ret; - drm_WARN_ON(bo->base.dev, drm_gem_is_imported(&bo->base)); + if (order && order != PMD_ORDER) + return VM_FAULT_FALLBACK; - dma_resv_lock(bo->base.resv, NULL); + /* Offset to faulty address in the VMA. */ + page_offset = vmf->pgoff - vma->vm_pgoff; + if (page_offset >= num_pages) + return VM_FAULT_SIGBUS; - /* We should have already pinned the pages when the buffer was first - * mmap'd, vm_open() just grabs an additional reference for the new - * mm the vma is getting copied into (ie. on fork()). - */ - drm_WARN_ON_ONCE(bo->base.dev, !bo->backing.pages); + ret = nonblocking_page_setup(vmf, order, page_offset); + if (ret != VM_FAULT_RETRY) + return ret; - dma_resv_unlock(bo->base.resv); + /* Check if we're allowed to retry. */ + if (fault_flag_allow_retry_first(vmf->flags)) { + /* If we're allowed to retry but not wait here, return + * immediately, the wait will be done when the fault + * handler is called again, with the mmap_lock held. + */ + if (vmf->flags & FAULT_FLAG_RETRY_NOWAIT) + return VM_FAULT_RETRY; + + /* Wait with the mmap lock released, if we're allowed to. */ + drm_gem_object_get(&bo->base); + mmap_read_unlock(vmf->vma->vm_mm); + ret = blocking_page_setup(vmf, order, bo, page_offset, false); + drm_gem_object_put(&bo->base); + return ret; + } + + return blocking_page_setup(vmf, order, bo, page_offset, true); +} - drm_gem_vm_open(vma); +static vm_fault_t panthor_gem_fault(struct vm_fault *vmf) +{ + return panthor_gem_any_fault(vmf, 0); } static const struct vm_operations_struct panthor_gem_vm_ops = { @@ -713,7 +745,7 @@ static const struct vm_operations_struct panthor_gem_vm_ops = { #ifdef CONFIG_ARCH_SUPPORTS_PMD_PFNMAP .huge_fault = panthor_gem_any_fault, #endif - .open = panthor_gem_vm_open, + .open = drm_gem_vm_open, .close = drm_gem_vm_close, }; -- cgit v1.2.3 From 1013bf53650ecabaf36433be6e178322095270af Mon Sep 17 00:00:00 2001 From: Boris Brezillon Date: Wed, 1 Apr 2026 15:48:52 +0200 Subject: drm/panthor: Split panthor_vm_prepare_map_op_ctx() to prepare for reclaim We're gonna need just the page table reservation logic when we restore evicted BO mappings, so let's prepare for that by extracting the op_ctx init and page table pre-allocation into separate helpers. v2: - Collect R-bs v3: - No changes v4: - No changes v5: - No changes v6: - No changes v7: - No changes Reviewed-by: Liviu Dudau Reviewed-by: Steven Price Link: https://patch.msgid.link/20260401134854.2275433-9-boris.brezillon@collabora.com Signed-off-by: Boris Brezillon --- drivers/gpu/drm/panthor/panthor_mmu.c | 68 +++++++++++++++++++++-------------- 1 file changed, 41 insertions(+), 27 deletions(-) diff --git a/drivers/gpu/drm/panthor/panthor_mmu.c b/drivers/gpu/drm/panthor/panthor_mmu.c index 1f42ff505883..b78f694ca92b 100644 --- a/drivers/gpu/drm/panthor/panthor_mmu.c +++ b/drivers/gpu/drm/panthor/panthor_mmu.c @@ -1175,6 +1175,44 @@ panthor_vm_op_ctx_prealloc_vmas(struct panthor_vm_op_ctx *op_ctx) return 0; } +static void panthor_vm_init_op_ctx(struct panthor_vm_op_ctx *op_ctx, + u64 size, u64 va, u32 flags) +{ + memset(op_ctx, 0, sizeof(*op_ctx)); + op_ctx->flags = flags; + op_ctx->va.range = size; + op_ctx->va.addr = va; +} + +static int panthor_vm_op_ctx_prealloc_pts(struct panthor_vm_op_ctx *op_ctx) +{ + u64 size = op_ctx->va.range; + u64 va = op_ctx->va.addr; + int ret; + + /* L1, L2 and L3 page tables. + * We could optimize L3 allocation by iterating over the sgt and merging + * 2M contiguous blocks, but it's simpler to over-provision and return + * the pages if they're not used. + */ + u64 pt_count = ((ALIGN(va + size, 1ull << 39) - ALIGN_DOWN(va, 1ull << 39)) >> 39) + + ((ALIGN(va + size, 1ull << 30) - ALIGN_DOWN(va, 1ull << 30)) >> 30) + + ((ALIGN(va + size, 1ull << 21) - ALIGN_DOWN(va, 1ull << 21)) >> 21); + + op_ctx->rsvd_page_tables.pages = kzalloc_objs(*op_ctx->rsvd_page_tables.pages, + pt_count); + if (!op_ctx->rsvd_page_tables.pages) + return -ENOMEM; + + ret = kmem_cache_alloc_bulk(pt_cache, GFP_KERNEL, pt_count, + op_ctx->rsvd_page_tables.pages); + op_ctx->rsvd_page_tables.count = ret; + if (ret != pt_count) + return -ENOMEM; + + return 0; +} + #define PANTHOR_VM_BIND_OP_MAP_FLAGS \ (DRM_PANTHOR_VM_BIND_OP_MAP_READONLY | \ DRM_PANTHOR_VM_BIND_OP_MAP_NOEXEC | \ @@ -1190,7 +1228,6 @@ static int panthor_vm_prepare_map_op_ctx(struct panthor_vm_op_ctx *op_ctx, { struct drm_gpuvm_bo *preallocated_vm_bo; struct sg_table *sgt = NULL; - u64 pt_count; int ret; if (!bo) @@ -1209,10 +1246,7 @@ static int panthor_vm_prepare_map_op_ctx(struct panthor_vm_op_ctx *op_ctx, bo->exclusive_vm_root_gem != panthor_vm_root_gem(vm)) return -EINVAL; - memset(op_ctx, 0, sizeof(*op_ctx)); - op_ctx->flags = flags; - op_ctx->va.range = size; - op_ctx->va.addr = va; + panthor_vm_init_op_ctx(op_ctx, size, va, flags); ret = panthor_vm_op_ctx_prealloc_vmas(op_ctx); if (ret) @@ -1244,29 +1278,9 @@ static int panthor_vm_prepare_map_op_ctx(struct panthor_vm_op_ctx *op_ctx, op_ctx->map.vm_bo = drm_gpuvm_bo_obtain_prealloc(preallocated_vm_bo); op_ctx->map.bo_offset = offset; - /* L1, L2 and L3 page tables. - * We could optimize L3 allocation by iterating over the sgt and merging - * 2M contiguous blocks, but it's simpler to over-provision and return - * the pages if they're not used. - */ - pt_count = ((ALIGN(va + size, 1ull << 39) - ALIGN_DOWN(va, 1ull << 39)) >> 39) + - ((ALIGN(va + size, 1ull << 30) - ALIGN_DOWN(va, 1ull << 30)) >> 30) + - ((ALIGN(va + size, 1ull << 21) - ALIGN_DOWN(va, 1ull << 21)) >> 21); - - op_ctx->rsvd_page_tables.pages = kzalloc_objs(*op_ctx->rsvd_page_tables.pages, - pt_count); - if (!op_ctx->rsvd_page_tables.pages) { - ret = -ENOMEM; - goto err_cleanup; - } - - ret = kmem_cache_alloc_bulk(pt_cache, GFP_KERNEL, pt_count, - op_ctx->rsvd_page_tables.pages); - op_ctx->rsvd_page_tables.count = ret; - if (ret != pt_count) { - ret = -ENOMEM; + ret = panthor_vm_op_ctx_prealloc_pts(op_ctx); + if (ret) goto err_cleanup; - } /* Insert BO into the extobj list last, when we know nothing can fail. */ if (bo->base.resv != panthor_vm_resv(vm)) { -- cgit v1.2.3 From 3218aae54542f7f079bc9777c71b052de2208819 Mon Sep 17 00:00:00 2001 From: Boris Brezillon Date: Wed, 1 Apr 2026 15:48:53 +0200 Subject: drm/panthor: Track the number of mmap on a BO This will be used to order things by reclaimability. v2: - Fix refcounting v3: - Fix refcounting (again) v4: - Collect R-b v5: - Collect R-b v6: - Warn on is_imported() (not supposed to happen since mmap is redirected to the dmabuf layer) instead of adding a conditional in panthor_gem_vm_open() v7: - No changes Reviewed-by: Steven Price Reviewed-by: Liviu Dudau Link: https://patch.msgid.link/20260401134854.2275433-10-boris.brezillon@collabora.com Signed-off-by: Boris Brezillon --- drivers/gpu/drm/panthor/panthor_gem.c | 42 +++++++++++++++++++++++++++++++++-- drivers/gpu/drm/panthor/panthor_gem.h | 3 +++ 2 files changed, 43 insertions(+), 2 deletions(-) diff --git a/drivers/gpu/drm/panthor/panthor_gem.c b/drivers/gpu/drm/panthor/panthor_gem.c index d9c3a71da29b..eb139759beda 100644 --- a/drivers/gpu/drm/panthor/panthor_gem.c +++ b/drivers/gpu/drm/panthor/panthor_gem.c @@ -488,6 +488,7 @@ static void panthor_gem_print_info(struct drm_printer *p, unsigned int indent, drm_printf_indent(p, indent, "vmap_use_count=%u\n", refcount_read(&bo->cmap.vaddr_use_count)); drm_printf_indent(p, indent, "vaddr=%p\n", bo->cmap.vaddr); + drm_printf_indent(p, indent, "mmap_count=%u\n", refcount_read(&bo->cmap.mmap_count)); } static int panthor_gem_pin_locked(struct drm_gem_object *obj) @@ -604,6 +605,13 @@ static int panthor_gem_mmap(struct drm_gem_object *obj, struct vm_area_struct *v if (is_cow_mapping(vma->vm_flags)) return -EINVAL; + if (!refcount_inc_not_zero(&bo->cmap.mmap_count)) { + dma_resv_lock(obj->resv, NULL); + if (!refcount_inc_not_zero(&bo->cmap.mmap_count)) + refcount_set(&bo->cmap.mmap_count, 1); + dma_resv_unlock(obj->resv); + } + vm_flags_set(vma, VM_PFNMAP | VM_DONTEXPAND | VM_DONTDUMP); vma->vm_page_prot = vm_get_page_prot(vma->vm_flags); if (should_map_wc(bo)) @@ -740,13 +748,43 @@ static vm_fault_t panthor_gem_fault(struct vm_fault *vmf) return panthor_gem_any_fault(vmf, 0); } +static void panthor_gem_vm_open(struct vm_area_struct *vma) +{ + struct panthor_gem_object *bo = to_panthor_bo(vma->vm_private_data); + + drm_WARN_ON(bo->base.dev, drm_gem_is_imported(&bo->base)); + drm_WARN_ON(bo->base.dev, !refcount_inc_not_zero(&bo->cmap.mmap_count)); + + drm_gem_vm_open(vma); +} + +static void panthor_gem_vm_close(struct vm_area_struct *vma) +{ + struct panthor_gem_object *bo = to_panthor_bo(vma->vm_private_data); + + if (drm_gem_is_imported(&bo->base)) + goto out; + + if (refcount_dec_not_one(&bo->cmap.mmap_count)) + goto out; + + dma_resv_lock(bo->base.resv, NULL); + if (refcount_dec_and_test(&bo->cmap.mmap_count)) { + /* Nothing to do, pages are reclaimed lazily. */ + } + dma_resv_unlock(bo->base.resv); + +out: + drm_gem_object_put(&bo->base); +} + static const struct vm_operations_struct panthor_gem_vm_ops = { .fault = panthor_gem_fault, #ifdef CONFIG_ARCH_SUPPORTS_PMD_PFNMAP .huge_fault = panthor_gem_any_fault, #endif - .open = drm_gem_vm_open, - .close = drm_gem_vm_close, + .open = panthor_gem_vm_open, + .close = panthor_gem_vm_close, }; static const struct drm_gem_object_funcs panthor_gem_funcs = { diff --git a/drivers/gpu/drm/panthor/panthor_gem.h b/drivers/gpu/drm/panthor/panthor_gem.h index b66478c9590c..c0a18dca732c 100644 --- a/drivers/gpu/drm/panthor/panthor_gem.h +++ b/drivers/gpu/drm/panthor/panthor_gem.h @@ -80,6 +80,9 @@ struct panthor_gem_cpu_map { /** @vaddr_use_count: Number of active vmap() requests on this GEM */ refcount_t vaddr_use_count; + + /** @mmap_count: Number of active mmap() requests on this GEM */ + refcount_t mmap_count; }; /** -- cgit v1.2.3 From fb42964e2a76f68a5fb581d382b5d2be2d5bda9b Mon Sep 17 00:00:00 2001 From: Akash Goel Date: Wed, 1 Apr 2026 15:48:54 +0200 Subject: drm/panthor: Add a GEM shrinker This implementation is losely based on the MSM shrinker, and it's relying on the drm_gpuvm eviction/validation infrastructure. Right now we only support swapout/eviction, but we could add an extra flag to specify when buffer content doesn't need to be preserved to avoid the swapout/swapin dance. Locking is a bit of a nightmare, but using _trylock() all the way in the reclaim path seems to make lockdep happy. And yes, we might be missing opportunities to reclaim when the system is under heavy GPU load/heavy memory pressure/heavy GPU VM activity, but that's better than no reclaim at all. v2: - Move gpu_mapped_shared next to the mmapped LRU - Add a bunch of missing is_[vm_bo,vma]_evicted() tests - Only test mmap_count to check if a BO is mmaped - Remove stale comment about shrinker not being a thing - Allow pin_count to be non-zero in panthor_gem_swapin_locked() - Fix panthor_gem_sync() to check for BO residency before doing the CPU sync - Fix the value returned by panthor_gem_shrinker_count() in case some memory has been released - Check drmm_mutex_init() ret code - Explicitly mention that PANTHOR_GEM_UNRECLAIMABLE is the initial state of all BOs v3: - Make panthor_gem_try_evict() static - Collect {A,R}-bs v4: - Update the reclaim_state in panthor_gem_mmap() - Don't reclaim GPU-mapped BOs if can_block() returns false - Skip evicited vm_bos in panthor_vm_update_bo_reclaim_lru_locked() to avoid spurious WARN_ON()s - Explain why we have to do this select_evicted_vma/repopulate_evicted_vma dance v5: - Properly report the reclaimable size in panthor_gem_debugfs_print_bos() - Check panthor_vm_lock_region() errors in panthor_vm_evict_bo_mappings_locked() - Fix lock order inversion (dma_resv_wait_timeout() inside gpuva.lock) v6: - Don't remap if the unmapped VMA is evicted. - Drop a stale comment in panthor_gem_dev_map_get_sgt_locked() - s/PANTHOR_GEM_GPU_MAPPED_PRIVATE/PANTHOR_GEM_GPU_MAPPED_SINGLE_VM/ - s/PANTHOR_GEM_GPU_MAPPED_SHARED/PANTHOR_GEM_GPU_MAPPED_MULTI_VM/ - Just count the number of vm_bo to determine the reclaim state in is_gpu_mapped() - Drop a redundant panthor_gem_backing_get_pages_locked() call in panthor_gem_swapin_locked() - Add more comments to panthor_vm_evict_bo_mappings_locked() to convince Claude it's actually safe. - Add a comment in panthor_gem_shrinker_count() to mention the race and hopefully clear Claude's concerns. - Rework the "is-still-in-list" check we have in panthor_mmu_reclaim_priv_bos() to address Claude's concerns - Don't call panthor_vm_unlock_region() if panthor_vm_lock_region() fails in remap_evicted_vma(). Was harmless, but confusing, as pointed out by Claude - Fix can_block() to allow blocking on KSWAPD_RECLAIM-only in a kswapd context - Fix a lockdep warning when the last ref on a BO is released in the shrinker path, where the resv lock can't be acquired other than with a try_lock() v7: - Skip drm_gpuvm_bo_deferred_cleanup() when repopulating VMAs to fix a deadlock Signed-off-by: Akash Goel Acked-by: Liviu Dudau Reviewed-by: Steven Price Link: https://patch.msgid.link/20260401134854.2275433-11-boris.brezillon@collabora.com Co-developed-by: Boris Brezillon Signed-off-by: Boris Brezillon --- drivers/gpu/drm/panthor/panthor_device.c | 11 +- drivers/gpu/drm/panthor/panthor_device.h | 73 +++++ drivers/gpu/drm/panthor/panthor_gem.c | 508 +++++++++++++++++++++++++++++-- drivers/gpu/drm/panthor/panthor_gem.h | 68 +++++ drivers/gpu/drm/panthor/panthor_mmu.c | 397 ++++++++++++++++++++++-- drivers/gpu/drm/panthor/panthor_mmu.h | 8 + 6 files changed, 1027 insertions(+), 38 deletions(-) diff --git a/drivers/gpu/drm/panthor/panthor_device.c b/drivers/gpu/drm/panthor/panthor_device.c index 54fbb1aa07c5..bc62a498a8a8 100644 --- a/drivers/gpu/drm/panthor/panthor_device.c +++ b/drivers/gpu/drm/panthor/panthor_device.c @@ -2,6 +2,7 @@ /* Copyright 2018 Marty E. Plummer */ /* Copyright 2019 Linaro, Ltd, Rob Herring */ /* Copyright 2023 Collabora ltd. */ +/* Copyright 2025 ARM Limited. All rights reserved. */ #include #include @@ -122,6 +123,7 @@ void panthor_device_unplug(struct panthor_device *ptdev) panthor_sched_unplug(ptdev); panthor_fw_unplug(ptdev); panthor_mmu_unplug(ptdev); + panthor_gem_shrinker_unplug(ptdev); panthor_gpu_unplug(ptdev); panthor_pwr_unplug(ptdev); @@ -291,10 +293,14 @@ int panthor_device_init(struct panthor_device *ptdev) if (ret) goto err_unplug_gpu; - ret = panthor_mmu_init(ptdev); + ret = panthor_gem_shrinker_init(ptdev); if (ret) goto err_unplug_gpu; + ret = panthor_mmu_init(ptdev); + if (ret) + goto err_unplug_shrinker; + ret = panthor_fw_init(ptdev); if (ret) goto err_unplug_mmu; @@ -326,6 +332,9 @@ err_unplug_fw: err_unplug_mmu: panthor_mmu_unplug(ptdev); +err_unplug_shrinker: + panthor_gem_shrinker_unplug(ptdev); + err_unplug_gpu: panthor_gpu_unplug(ptdev); diff --git a/drivers/gpu/drm/panthor/panthor_device.h b/drivers/gpu/drm/panthor/panthor_device.h index b6696f73a536..5cba272f9b4d 100644 --- a/drivers/gpu/drm/panthor/panthor_device.h +++ b/drivers/gpu/drm/panthor/panthor_device.h @@ -14,6 +14,7 @@ #include #include +#include #include #include #include @@ -178,6 +179,78 @@ struct panthor_device { /** @devfreq: Device frequency scaling management data. */ struct panthor_devfreq *devfreq; + /** @reclaim: Reclaim related stuff */ + struct { + /** @reclaim.shrinker: Shrinker instance */ + struct shrinker *shrinker; + + /** @reclaim.lock: Lock protecting all LRUs */ + struct mutex lock; + + /** + * @reclaim.unused: BOs with unused pages + * + * Basically all buffers that got mmapped, vmapped or GPU mapped and + * then unmapped. There should be no contention on these buffers, + * making them ideal to reclaim. + */ + struct drm_gem_lru unused; + + /** + * @reclaim.mmapped: mmap()-ed buffers + * + * Those are relatively easy to reclaim since we don't need user + * agreement, we can simply teardown the mapping and let it fault on + * the next access. + */ + struct drm_gem_lru mmapped; + + /** + * @reclaim.gpu_mapped_shared: shared BO LRU list + * + * That's the most tricky BO type to reclaim, because it involves + * tearing down all mappings in all VMs where this BO is mapped, + * which increases the risk of contention and thus decreases the + * likeliness of success. + */ + struct drm_gem_lru gpu_mapped_shared; + + /** + * @reclaim.vms: VM LRU list + * + * VMs that have reclaimable BOs only mapped to a single VM are placed + * in this LRU. Reclaiming such BOs implies waiting for VM idleness + * (no in-flight GPU jobs targeting this VM), meaning we can't reclaim + * those if we're in a context where we can't block/sleep. + */ + struct list_head vms; + + /** + * @reclaim.gpu_mapped_count: Global counter of pages that are GPU mapped + * + * Allows us to get the number of reclaimable pages without walking + * the vms and gpu_mapped_shared LRUs. + */ + long gpu_mapped_count; + + /** + * @reclaim.retry_count: Number of times we ran the shrinker without being + * able to reclaim stuff + * + * Used to stop scanning GEMs when too many attempts were made + * without progress. + */ + atomic_t retry_count; + +#ifdef CONFIG_DEBUG_FS + /** + * @reclaim.nr_pages_reclaimed_on_last_scan: Number of pages reclaimed on the last + * shrinker scan + */ + unsigned long nr_pages_reclaimed_on_last_scan; +#endif + } reclaim; + /** @unplug: Device unplug related fields. */ struct { /** @lock: Lock used to serialize unplug operations. */ diff --git a/drivers/gpu/drm/panthor/panthor_gem.c b/drivers/gpu/drm/panthor/panthor_gem.c index eb139759beda..69cef05b6ef7 100644 --- a/drivers/gpu/drm/panthor/panthor_gem.c +++ b/drivers/gpu/drm/panthor/panthor_gem.c @@ -2,8 +2,10 @@ /* Copyright 2019 Linaro, Ltd, Rob Herring */ /* Copyright 2023 Collabora ltd. */ /* Copyright 2025 Amazon.com, Inc. or its affiliates */ +/* Copyright 2025 ARM Limited. All rights reserved. */ #include +#include #include #include #include @@ -12,6 +14,8 @@ #include #include +#include +#include #include #include #include @@ -114,10 +118,116 @@ should_map_wc(struct panthor_gem_object *bo) return true; } +static bool is_gpu_mapped(struct panthor_gem_object *bo, + enum panthor_gem_reclaim_state *state) +{ + struct drm_gpuvm_bo *vm_bo; + u32 vm_count = 0; + + drm_gem_for_each_gpuvm_bo(vm_bo, &bo->base) { + /* Skip evicted GPU mappings. */ + if (vm_bo->evicted) + continue; + + if (vm_count++) { + *state = PANTHOR_GEM_GPU_MAPPED_MULTI_VM; + break; + } + + *state = PANTHOR_GEM_GPU_MAPPED_SINGLE_VM; + } + + return vm_count > 0; +} + +static enum panthor_gem_reclaim_state +panthor_gem_evaluate_reclaim_state_locked(struct panthor_gem_object *bo) +{ + enum panthor_gem_reclaim_state gpu_mapped_state; + + dma_resv_assert_held(bo->base.resv); + lockdep_assert_held(&bo->base.gpuva.lock); + + /* If pages have not been allocated, there's nothing to reclaim. */ + if (!bo->backing.pages) + return PANTHOR_GEM_UNRECLAIMABLE; + + /* If memory is pinned, we prevent reclaim. */ + if (refcount_read(&bo->backing.pin_count)) + return PANTHOR_GEM_UNRECLAIMABLE; + + if (is_gpu_mapped(bo, &gpu_mapped_state)) + return gpu_mapped_state; + + if (refcount_read(&bo->cmap.mmap_count)) + return PANTHOR_GEM_MMAPPED; + + return PANTHOR_GEM_UNUSED; +} + +void panthor_gem_update_reclaim_state_locked(struct panthor_gem_object *bo, + enum panthor_gem_reclaim_state *old_statep) +{ + struct panthor_device *ptdev = container_of(bo->base.dev, struct panthor_device, base); + enum panthor_gem_reclaim_state old_state = bo->reclaim_state; + enum panthor_gem_reclaim_state new_state; + bool was_gpu_mapped, is_gpu_mapped; + + if (old_statep) + *old_statep = old_state; + + new_state = panthor_gem_evaluate_reclaim_state_locked(bo); + if (new_state == old_state) + return; + + was_gpu_mapped = old_state == PANTHOR_GEM_GPU_MAPPED_MULTI_VM || + old_state == PANTHOR_GEM_GPU_MAPPED_SINGLE_VM; + is_gpu_mapped = new_state == PANTHOR_GEM_GPU_MAPPED_MULTI_VM || + new_state == PANTHOR_GEM_GPU_MAPPED_SINGLE_VM; + + if (is_gpu_mapped && !was_gpu_mapped) + ptdev->reclaim.gpu_mapped_count += bo->base.size >> PAGE_SHIFT; + else if (!is_gpu_mapped && was_gpu_mapped) + ptdev->reclaim.gpu_mapped_count -= bo->base.size >> PAGE_SHIFT; + + switch (new_state) { + case PANTHOR_GEM_UNUSED: + drm_gem_lru_move_tail(&ptdev->reclaim.unused, &bo->base); + break; + case PANTHOR_GEM_MMAPPED: + drm_gem_lru_move_tail(&ptdev->reclaim.mmapped, &bo->base); + break; + case PANTHOR_GEM_GPU_MAPPED_SINGLE_VM: + panthor_vm_update_bo_reclaim_lru_locked(bo); + break; + case PANTHOR_GEM_GPU_MAPPED_MULTI_VM: + drm_gem_lru_move_tail(&ptdev->reclaim.gpu_mapped_shared, &bo->base); + break; + case PANTHOR_GEM_UNRECLAIMABLE: + drm_gem_lru_remove(&bo->base); + break; + default: + drm_WARN(&ptdev->base, true, "invalid GEM reclaim state (%d)\n", new_state); + break; + } + + bo->reclaim_state = new_state; +} + +static void +bo_assert_locked_or_gone(struct panthor_gem_object *bo) +{ + /* If the refcount is zero, the BO is being freed, and we + * allow the lock to not be held in that particular case. + */ + if (kref_read(&bo->base.refcount)) + dma_resv_assert_held(bo->base.resv); +} + static void panthor_gem_backing_cleanup_locked(struct panthor_gem_object *bo) { - dma_resv_assert_held(bo->base.resv); + bo_assert_locked_or_gone(bo); if (!bo->backing.pages) return; @@ -157,28 +267,35 @@ static int panthor_gem_backing_pin_locked(struct panthor_gem_object *bo) return 0; ret = panthor_gem_backing_get_pages_locked(bo); - if (!ret) + if (!ret) { refcount_set(&bo->backing.pin_count, 1); + mutex_lock(&bo->base.gpuva.lock); + panthor_gem_update_reclaim_state_locked(bo, NULL); + mutex_unlock(&bo->base.gpuva.lock); + } return ret; } static void panthor_gem_backing_unpin_locked(struct panthor_gem_object *bo) { - dma_resv_assert_held(bo->base.resv); + bo_assert_locked_or_gone(bo); drm_WARN_ON_ONCE(bo->base.dev, drm_gem_is_imported(&bo->base)); if (refcount_dec_and_test(&bo->backing.pin_count)) { /* We don't release anything when pin_count drops to zero. * Pages stay there until an explicit cleanup is requested. */ + mutex_lock(&bo->base.gpuva.lock); + panthor_gem_update_reclaim_state_locked(bo, NULL); + mutex_unlock(&bo->base.gpuva.lock); } } static void panthor_gem_dev_map_cleanup_locked(struct panthor_gem_object *bo) { - dma_resv_assert_held(bo->base.resv); + bo_assert_locked_or_gone(bo); if (!bo->dmap.sgt) return; @@ -200,9 +317,6 @@ panthor_gem_dev_map_get_sgt_locked(struct panthor_gem_object *bo) if (bo->dmap.sgt) return bo->dmap.sgt; - /* Pages stay around after they've been allocated. At least that stands - * until we add a shrinker. - */ ret = panthor_gem_backing_get_pages_locked(bo); if (ret) return ERR_PTR(ret); @@ -336,11 +450,19 @@ static void panthor_gem_free_object(struct drm_gem_object *obj) if (drm_gem_is_imported(obj)) { drm_prime_gem_destroy(obj, bo->dmap.sgt); } else { - dma_resv_lock(obj->resv, NULL); + /* The last ref on the GEM object can be released + * by the shrinker, which can't block on the resv + * lock acquisition. In practice, even if we were + * taking the lock, it wouldn't block because we're + * the last piece of code having a visibility on + * this GEM, but lockdep can't see that, so we've + * just tought the _cleanup_locked() helpers about + * this "being freed" exception, and we call those + * without the lock held here. + */ panthor_gem_vmap_cleanup_locked(bo); panthor_gem_dev_map_cleanup_locked(bo); panthor_gem_backing_cleanup_locked(bo); - dma_resv_unlock(obj->resv); } drm_gem_object_release(obj); @@ -535,6 +657,41 @@ void panthor_gem_unpin(struct panthor_gem_object *bo) dma_resv_unlock(bo->base.resv); } +int panthor_gem_swapin_locked(struct panthor_gem_object *bo) +{ + struct sg_table *sgt; + + dma_resv_assert_held(bo->base.resv); + + if (drm_WARN_ON_ONCE(bo->base.dev, drm_gem_is_imported(&bo->base))) + return -EINVAL; + + sgt = panthor_gem_dev_map_get_sgt_locked(bo); + if (IS_ERR(sgt)) + return PTR_ERR(sgt); + + return 0; +} + +static void panthor_gem_evict_locked(struct panthor_gem_object *bo) +{ + dma_resv_assert_held(bo->base.resv); + lockdep_assert_held(&bo->base.gpuva.lock); + + if (drm_WARN_ON_ONCE(bo->base.dev, drm_gem_is_imported(&bo->base))) + return; + + if (drm_WARN_ON_ONCE(bo->base.dev, refcount_read(&bo->backing.pin_count))) + return; + + if (drm_WARN_ON_ONCE(bo->base.dev, !bo->backing.pages)) + return; + + panthor_gem_dev_map_cleanup_locked(bo); + panthor_gem_backing_cleanup_locked(bo); + panthor_gem_update_reclaim_state_locked(bo, NULL); +} + static struct sg_table *panthor_gem_get_sg_table(struct drm_gem_object *obj) { struct panthor_gem_object *bo = to_panthor_bo(obj); @@ -607,8 +764,12 @@ static int panthor_gem_mmap(struct drm_gem_object *obj, struct vm_area_struct *v if (!refcount_inc_not_zero(&bo->cmap.mmap_count)) { dma_resv_lock(obj->resv, NULL); - if (!refcount_inc_not_zero(&bo->cmap.mmap_count)) + if (!refcount_inc_not_zero(&bo->cmap.mmap_count)) { refcount_set(&bo->cmap.mmap_count, 1); + mutex_lock(&bo->base.gpuva.lock); + panthor_gem_update_reclaim_state_locked(bo, NULL); + mutex_unlock(&bo->base.gpuva.lock); + } dma_resv_unlock(obj->resv); } @@ -692,6 +853,10 @@ static vm_fault_t blocking_page_setup(struct vm_fault *vmf, unsigned int order, } else { struct page *page = bo->backing.pages[page_offset]; + mutex_lock(&bo->base.gpuva.lock); + panthor_gem_update_reclaim_state_locked(bo, NULL); + mutex_unlock(&bo->base.gpuva.lock); + if (mmap_lock_held) ret = insert_page(vmf, order, page); else @@ -734,7 +899,12 @@ static vm_fault_t panthor_gem_any_fault(struct vm_fault *vmf, unsigned int order /* Wait with the mmap lock released, if we're allowed to. */ drm_gem_object_get(&bo->base); - mmap_read_unlock(vmf->vma->vm_mm); + + if (vmf->flags & FAULT_FLAG_VMA_LOCK) + vma_end_read(vmf->vma); + else + mmap_read_unlock(vmf->vma->vm_mm); + ret = blocking_page_setup(vmf, order, bo, page_offset, false); drm_gem_object_put(&bo->base); return ret; @@ -770,7 +940,9 @@ static void panthor_gem_vm_close(struct vm_area_struct *vma) dma_resv_lock(bo->base.resv, NULL); if (refcount_dec_and_test(&bo->cmap.mmap_count)) { - /* Nothing to do, pages are reclaimed lazily. */ + mutex_lock(&bo->base.gpuva.lock); + panthor_gem_update_reclaim_state_locked(bo, NULL); + mutex_unlock(&bo->base.gpuva.lock); } dma_resv_unlock(bo->base.resv); @@ -810,6 +982,7 @@ panthor_gem_alloc_object(u32 flags) if (!bo) return ERR_PTR(-ENOMEM); + bo->reclaim_state = PANTHOR_GEM_UNRECLAIMABLE; bo->base.funcs = &panthor_gem_funcs; bo->flags = flags; mutex_init(&bo->label.lock); @@ -968,6 +1141,7 @@ panthor_gem_sync(struct drm_gem_object *obj, u32 type, struct sg_table *sgt; struct scatterlist *sgl; unsigned int count; + int ret; /* Make sure the range is in bounds. */ if (offset + size < offset || offset + size > bo->base.size) @@ -994,9 +1168,21 @@ panthor_gem_sync(struct drm_gem_object *obj, u32 type, if (size == 0) return 0; - sgt = panthor_gem_get_dev_sgt(bo); - if (IS_ERR(sgt)) - return PTR_ERR(sgt); + ret = dma_resv_lock_interruptible(bo->base.resv, NULL); + if (ret) + return ret; + + /* If there's no pages, there's no point pulling those back, bail out early. */ + if (!bo->backing.pages) { + ret = 0; + goto out_unlock; + } + + sgt = panthor_gem_dev_map_get_sgt_locked(bo); + if (IS_ERR(sgt)) { + ret = PTR_ERR(sgt); + goto out_unlock; + } for_each_sgtable_dma_sg(sgt, sgl, count) { if (size == 0) @@ -1040,7 +1226,11 @@ panthor_gem_sync(struct drm_gem_object *obj, u32 type, dma_sync_single_for_cpu(dma_dev, paddr, len, DMA_FROM_DEVICE); } - return 0; + ret = 0; + +out_unlock: + dma_resv_unlock(bo->base.resv); + return ret; } /** @@ -1050,11 +1240,13 @@ panthor_gem_sync(struct drm_gem_object *obj, u32 type, */ void panthor_kernel_bo_destroy(struct panthor_kernel_bo *bo) { + struct panthor_device *ptdev; struct panthor_vm *vm; if (IS_ERR_OR_NULL(bo)) return; + ptdev = container_of(bo->obj->dev, struct panthor_device, base); vm = bo->vm; panthor_kernel_bo_vunmap(bo); @@ -1062,6 +1254,8 @@ void panthor_kernel_bo_destroy(struct panthor_kernel_bo *bo) to_panthor_bo(bo->obj)->exclusive_vm_root_gem != panthor_vm_root_gem(vm)); panthor_vm_unmap_range(vm, bo->va_node.start, bo->va_node.size); panthor_vm_free_va(vm, &bo->va_node); + if (vm == panthor_fw_vm(ptdev)) + panthor_gem_unpin(to_panthor_bo(bo->obj)); drm_gem_object_put(bo->obj); panthor_vm_put(vm); kfree(bo); @@ -1110,6 +1304,12 @@ panthor_kernel_bo_create(struct panthor_device *ptdev, struct panthor_vm *vm, kbo->obj = &bo->base; + if (vm == panthor_fw_vm(ptdev)) { + ret = panthor_gem_pin(bo); + if (ret) + goto err_put_obj; + } + panthor_gem_kernel_bo_set_label(kbo, name); /* The system and GPU MMU page size might differ, which becomes a @@ -1121,7 +1321,7 @@ panthor_kernel_bo_create(struct panthor_device *ptdev, struct panthor_vm *vm, size = ALIGN(size, panthor_vm_page_size(vm)); ret = panthor_vm_alloc_va(vm, gpu_va, size, &kbo->va_node); if (ret) - goto err_put_obj; + goto err_unpin; ret = panthor_vm_map_bo_range(vm, bo, 0, size, kbo->va_node.start, vm_map_flags); if (ret) @@ -1133,6 +1333,10 @@ panthor_kernel_bo_create(struct panthor_device *ptdev, struct panthor_vm *vm, err_free_va: panthor_vm_free_va(vm, &kbo->va_node); +err_unpin: + if (vm == panthor_fw_vm(ptdev)) + panthor_gem_unpin(bo); + err_put_obj: drm_gem_object_put(&bo->base); @@ -1141,6 +1345,241 @@ err_free_kbo: return ERR_PTR(ret); } +static bool can_swap(void) +{ + return get_nr_swap_pages() > 0; +} + +static bool can_block(struct shrink_control *sc) +{ + /* If direct reclaim is allowed, we can always block. + * If kswapd reclaim is allowed, we can block, but only if we're called + * by the kswapd thread. + */ + return (sc->gfp_mask & __GFP_DIRECT_RECLAIM) || + ((sc->gfp_mask & __GFP_KSWAPD_RECLAIM) && current_is_kswapd()); +} + +static unsigned long +panthor_gem_shrinker_count(struct shrinker *shrinker, struct shrink_control *sc) +{ + struct panthor_device *ptdev = shrinker->private_data; + unsigned long count; + + /* We currently don't have a flag to tell when the content of a + * BO can be discarded. + */ + if (!can_swap()) + return 0; + + /* This is racy, but that's okay because the returned count is just a + * hint. That's also what MSM is doing (no atomic var, it's relying on + * the fact unsigned long access is usually atomic), so if it's good + * enough for them, it's good enough for us too. + */ + count = ptdev->reclaim.unused.count; + count += ptdev->reclaim.mmapped.count; + + if (can_block(sc)) + count += ptdev->reclaim.gpu_mapped_count; + + return count ? count : SHRINK_EMPTY; +} + +static bool panthor_gem_try_evict_no_resv_wait(struct drm_gem_object *obj, + struct ww_acquire_ctx *ticket) +{ + /* + * Track last locked entry for unwinding locks in error and + * success paths + */ + struct panthor_gem_object *bo = to_panthor_bo(obj); + struct drm_gpuvm_bo *vm_bo, *last_locked = NULL; + enum panthor_gem_reclaim_state old_state; + int ret = 0; + + /* To avoid potential lock ordering issue between bo_gpuva and + * mapping->i_mmap_rwsem, unmap the pages from CPU side before + * acquring the bo_gpuva lock. As the bo_resv lock is held, CPU + * page fault handler won't be able to map in the pages whilst + * eviction is in progress. + */ + drm_vma_node_unmap(&bo->base.vma_node, bo->base.dev->anon_inode->i_mapping); + + /* We take this lock when walking the list to prevent + * insertion/deletion. + */ + /* We can only trylock in that path, because + * - allocation might happen while some of these locks are held + * - lock ordering is different in other paths + * vm_resv -> bo_resv -> bo_gpuva + * vs + * bo_resv -> bo_gpuva -> vm_resv + * + * If we fail to lock that's fine, we back off and will get + * back to it later. + */ + if (!mutex_trylock(&bo->base.gpuva.lock)) + return false; + + drm_gem_for_each_gpuvm_bo(vm_bo, obj) { + struct dma_resv *resv = drm_gpuvm_resv(vm_bo->vm); + + if (resv == obj->resv) + continue; + + if (!dma_resv_trylock(resv)) { + ret = -EDEADLK; + goto out_unlock; + } + + last_locked = vm_bo; + } + + /* Update the state before trying to evict the buffer, if the state was + * updated to something that's harder to reclaim (higher value in the + * enum), skip it (will be processed when the relevant LRU is). + */ + panthor_gem_update_reclaim_state_locked(bo, &old_state); + if (old_state < bo->reclaim_state) { + ret = -EAGAIN; + goto out_unlock; + } + + /* Couldn't teardown the GPU mappings? Skip. */ + ret = panthor_vm_evict_bo_mappings_locked(bo); + if (ret) + goto out_unlock; + + /* If everything went fine, evict the object. */ + panthor_gem_evict_locked(bo); + +out_unlock: + if (last_locked) { + drm_gem_for_each_gpuvm_bo(vm_bo, obj) { + struct dma_resv *resv = drm_gpuvm_resv(vm_bo->vm); + + if (resv == obj->resv) + continue; + + dma_resv_unlock(resv); + + if (last_locked == vm_bo) + break; + } + } + mutex_unlock(&bo->base.gpuva.lock); + + return ret == 0; +} + +static bool panthor_gem_try_evict(struct drm_gem_object *obj, + struct ww_acquire_ctx *ticket) +{ + struct panthor_gem_object *bo = to_panthor_bo(obj); + + /* Wait was too long, skip. */ + if (dma_resv_wait_timeout(obj->resv, DMA_RESV_USAGE_BOOKKEEP, false, 10) <= 0) + return false; + + return panthor_gem_try_evict_no_resv_wait(&bo->base, ticket); +} + +static unsigned long +panthor_gem_shrinker_scan(struct shrinker *shrinker, struct shrink_control *sc) +{ + struct panthor_device *ptdev = shrinker->private_data; + unsigned long remaining = 0; + unsigned long freed = 0; + + if (!can_swap()) + goto out; + + freed += drm_gem_lru_scan(&ptdev->reclaim.unused, + sc->nr_to_scan - freed, &remaining, + panthor_gem_try_evict_no_resv_wait, NULL); + if (freed >= sc->nr_to_scan) + goto out; + + freed += drm_gem_lru_scan(&ptdev->reclaim.mmapped, + sc->nr_to_scan - freed, &remaining, + panthor_gem_try_evict_no_resv_wait, NULL); + if (freed >= sc->nr_to_scan) + goto out; + + if (!can_block(sc)) + goto out; + + freed += panthor_mmu_reclaim_priv_bos(ptdev, sc->nr_to_scan - freed, + &remaining, panthor_gem_try_evict); + if (freed >= sc->nr_to_scan) + goto out; + + freed += drm_gem_lru_scan(&ptdev->reclaim.gpu_mapped_shared, + sc->nr_to_scan - freed, &remaining, + panthor_gem_try_evict, NULL); + +out: +#ifdef CONFIG_DEBUG_FS + /* This is racy, but that's okay, because this is just debugfs + * reporting and doesn't need to be accurate. + */ + ptdev->reclaim.nr_pages_reclaimed_on_last_scan = freed; +#endif + + /* If there are things to reclaim, try a couple times before giving up. */ + if (!freed && remaining > 0 && + atomic_inc_return(&ptdev->reclaim.retry_count) < 2) + return 0; + + atomic_set(&ptdev->reclaim.retry_count, 0); + + if (freed) + return freed; + + /* There's nothing left to reclaim, or the resources are contended. Give up now. */ + return SHRINK_STOP; +} + +int panthor_gem_shrinker_init(struct panthor_device *ptdev) +{ + struct shrinker *shrinker; + int ret; + + ret = drmm_mutex_init(&ptdev->base, &ptdev->reclaim.lock); + if (ret) + return ret; + + INIT_LIST_HEAD(&ptdev->reclaim.vms); + drm_gem_lru_init(&ptdev->reclaim.unused, &ptdev->reclaim.lock); + drm_gem_lru_init(&ptdev->reclaim.mmapped, &ptdev->reclaim.lock); + drm_gem_lru_init(&ptdev->reclaim.gpu_mapped_shared, &ptdev->reclaim.lock); + ptdev->reclaim.gpu_mapped_count = 0; + + /* Teach lockdep about lock ordering wrt. shrinker: */ + fs_reclaim_acquire(GFP_KERNEL); + might_lock(&ptdev->reclaim.lock); + fs_reclaim_release(GFP_KERNEL); + + shrinker = shrinker_alloc(0, "drm-panthor-gem"); + if (!shrinker) + return -ENOMEM; + + shrinker->count_objects = panthor_gem_shrinker_count; + shrinker->scan_objects = panthor_gem_shrinker_scan; + shrinker->private_data = ptdev; + ptdev->reclaim.shrinker = shrinker; + + shrinker_register(shrinker); + return 0; +} + +void panthor_gem_shrinker_unplug(struct panthor_device *ptdev) +{ + if (ptdev->reclaim.shrinker) + shrinker_free(ptdev->reclaim.shrinker); +} + #ifdef CONFIG_DEBUG_FS struct gem_size_totals { size_t size; @@ -1184,6 +1623,7 @@ static void panthor_gem_debugfs_bo_print(struct panthor_gem_object *bo, struct seq_file *m, struct gem_size_totals *totals) { + enum panthor_gem_reclaim_state reclaim_state = bo->reclaim_state; unsigned int refcount = kref_read(&bo->base.refcount); char creator_info[32] = {}; size_t resident_size; @@ -1219,6 +1659,8 @@ static void panthor_gem_debugfs_bo_print(struct panthor_gem_object *bo, totals->size += bo->base.size; totals->resident += resident_size; + if (reclaim_state != PANTHOR_GEM_UNRECLAIMABLE) + totals->reclaimable += resident_size; } static void panthor_gem_debugfs_print_bos(struct panthor_device *ptdev, @@ -1259,10 +1701,42 @@ static struct drm_info_list panthor_gem_debugfs_list[] = { { "gems", panthor_gem_show_bos, 0, NULL }, }; +static int shrink_get(void *data, u64 *val) +{ + struct panthor_device *ptdev = + container_of(data, struct panthor_device, base); + + *val = ptdev->reclaim.nr_pages_reclaimed_on_last_scan; + return 0; +} + +static int shrink_set(void *data, u64 val) +{ + struct panthor_device *ptdev = + container_of(data, struct panthor_device, base); + struct shrink_control sc = { + .gfp_mask = GFP_KERNEL, + .nr_to_scan = val, + }; + + fs_reclaim_acquire(GFP_KERNEL); + if (ptdev->reclaim.shrinker) + panthor_gem_shrinker_scan(ptdev->reclaim.shrinker, &sc); + fs_reclaim_release(GFP_KERNEL); + + return 0; +} + +DEFINE_DEBUGFS_ATTRIBUTE(panthor_gem_debugfs_shrink_fops, + shrink_get, shrink_set, + "0x%08llx\n"); + void panthor_gem_debugfs_init(struct drm_minor *minor) { drm_debugfs_create_files(panthor_gem_debugfs_list, ARRAY_SIZE(panthor_gem_debugfs_list), minor->debugfs_root, minor); + debugfs_create_file("shrink", 0600, minor->debugfs_root, + minor->dev, &panthor_gem_debugfs_shrink_fops); } #endif diff --git a/drivers/gpu/drm/panthor/panthor_gem.h b/drivers/gpu/drm/panthor/panthor_gem.h index c0a18dca732c..ae0491d0b121 100644 --- a/drivers/gpu/drm/panthor/panthor_gem.h +++ b/drivers/gpu/drm/panthor/panthor_gem.h @@ -1,6 +1,7 @@ /* SPDX-License-Identifier: GPL-2.0 or MIT */ /* Copyright 2019 Linaro, Ltd, Rob Herring */ /* Copyright 2023 Collabora ltd. */ +/* Copyright 2025 ARM Limited. All rights reserved. */ #ifndef __PANTHOR_GEM_H__ #define __PANTHOR_GEM_H__ @@ -93,6 +94,65 @@ struct panthor_gem_dev_map { struct sg_table *sgt; }; +/** + * enum panthor_gem_reclaim_state - Reclaim state of a GEM object + * + * This is defined in descending reclaimability order and some part + * of the code depends on that. + */ +enum panthor_gem_reclaim_state { + /** + * @PANTHOR_GEM_UNUSED: GEM is currently unused + * + * This can happen when the GEM was previously vmap-ed, mmap-ed, + * and/or GPU mapped and got unmapped. Because pages are lazily + * returned to the shmem layer, we want to keep a list of such + * BOs, because they should be fairly easy to reclaim (no need + * to wait for GPU to be done, and no need to tear down user + * mappings either). + */ + PANTHOR_GEM_UNUSED, + + /** + * @PANTHOR_GEM_MMAPPED: GEM is currently mmap-ed + * + * When a GEM has pages allocated and the mmap_count is > 0, the + * GEM is placed in the mmapped list. This comes right after + * unused because we can relatively easily tear down user mappings. + */ + PANTHOR_GEM_MMAPPED, + + /** + * @PANTHOR_GEM_GPU_MAPPED_SINGLE_VM: GEM is GPU mapped to only one VM + * + * When a GEM is mapped to a single VM, reclaim requests have more + * chances to succeed, because we only need to synchronize against + * a single GPU context. This is more annoying than reclaiming + * mmap-ed pages still, because we have to wait for in-flight jobs + * to land, and we might not be able to acquire all necessary locks + * at reclaim time either. + */ + PANTHOR_GEM_GPU_MAPPED_SINGLE_VM, + + /** + * @PANTHOR_GEM_GPU_MAPPED_MULTI_VM: GEM is GPU mapped to multiple VMs + * + * Like PANTHOR_GEM_GPU_MAPPED_SINGLE_VM, but the synchronization across + * VMs makes such BOs harder to reclaim. + */ + PANTHOR_GEM_GPU_MAPPED_MULTI_VM, + + /** + * @PANTHOR_GEM_UNRECLAIMABLE: GEM can't be reclaimed + * + * Happens when the GEM memory is pinned. It's also the state all GEM + * objects start in, because no memory is allocated until explicitly + * requested by a CPU or GPU map, meaning there's nothing to reclaim + * until such an allocation happens. + */ + PANTHOR_GEM_UNRECLAIMABLE, +}; + /** * struct panthor_gem_object - Driver specific GEM object. */ @@ -109,6 +169,9 @@ struct panthor_gem_object { /** @dmap: Device mapping state */ struct panthor_gem_dev_map dmap; + /** @reclaim_state: Cached reclaim state */ + enum panthor_gem_reclaim_state reclaim_state; + /** * @exclusive_vm_root_gem: Root GEM of the exclusive VM this GEM object * is attached to. @@ -190,6 +253,11 @@ struct sg_table * panthor_gem_get_dev_sgt(struct panthor_gem_object *bo); int panthor_gem_pin(struct panthor_gem_object *bo); void panthor_gem_unpin(struct panthor_gem_object *bo); +int panthor_gem_swapin_locked(struct panthor_gem_object *bo); +void panthor_gem_update_reclaim_state_locked(struct panthor_gem_object *bo, + enum panthor_gem_reclaim_state *old_state); +int panthor_gem_shrinker_init(struct panthor_device *ptdev); +void panthor_gem_shrinker_unplug(struct panthor_device *ptdev); void panthor_gem_bo_set_label(struct drm_gem_object *obj, const char *label); void panthor_gem_kernel_bo_set_label(struct panthor_kernel_bo *bo, const char *label); diff --git a/drivers/gpu/drm/panthor/panthor_mmu.c b/drivers/gpu/drm/panthor/panthor_mmu.c index b78f694ca92b..fa8b31df85c9 100644 --- a/drivers/gpu/drm/panthor/panthor_mmu.c +++ b/drivers/gpu/drm/panthor/panthor_mmu.c @@ -1,6 +1,7 @@ // SPDX-License-Identifier: GPL-2.0 or MIT /* Copyright 2019 Linaro, Ltd, Rob Herring */ /* Copyright 2023 Collabora ltd. */ +/* Copyright 2025 ARM Limited. All rights reserved. */ #include #include @@ -131,6 +132,9 @@ struct panthor_vma { * Only map related flags are accepted. */ u32 flags; + + /** @evicted: True if the VMA has been evicted. */ + bool evicted; }; /** @@ -198,6 +202,9 @@ struct panthor_vm_op_ctx { * to allocate in ::run_job(). */ struct sg_table *sgt; + + /** @map.bo: the BO being mapped. */ + struct panthor_gem_object *bo; } map; }; @@ -380,6 +387,18 @@ struct panthor_vm { /** @locked_region.size: Size of the locked region. */ u64 size; } locked_region; + + /** @reclaim: Fields related to BO reclaim. */ + struct { + /** @reclaim.lru: LRU of BOs that are only mapped to this VM. */ + struct drm_gem_lru lru; + + /** + * @reclaim.lru_node: Node used to insert the VM in + * panthor_device::reclaim::vms. + */ + struct list_head lru_node; + } reclaim; }; /** @@ -684,6 +703,16 @@ int panthor_vm_active(struct panthor_vm *vm) if (refcount_inc_not_zero(&vm->as.active_cnt)) goto out_dev_exit; + /* As soon as active is called, we place the VM at the end of the VM LRU. + * If something fails after that, the only downside is that this VM that + * never became active in the first place will be reclaimed last, but + * that's an acceptable trade-off. + */ + mutex_lock(&ptdev->reclaim.lock); + if (vm->reclaim.lru.count) + list_move_tail(&vm->reclaim.lru_node, &ptdev->reclaim.vms); + mutex_unlock(&ptdev->reclaim.lock); + /* Make sure we don't race with lock/unlock_region() calls * happening around VM bind operations. */ @@ -1079,7 +1108,15 @@ static void panthor_vm_bo_free(struct drm_gpuvm_bo *vm_bo) { struct panthor_gem_object *bo = to_panthor_bo(vm_bo->obj); - panthor_gem_unpin(bo); + /* We couldn't call this when we unlinked, because the resv lock can't + * be taken in the dma signalling path, so call it now. + */ + dma_resv_lock(bo->base.resv, NULL); + mutex_lock(&bo->base.gpuva.lock); + panthor_gem_update_reclaim_state_locked(bo, NULL); + mutex_unlock(&bo->base.gpuva.lock); + dma_resv_unlock(bo->base.resv); + kfree(vm_bo); } @@ -1088,6 +1125,16 @@ static void panthor_vm_cleanup_op_ctx(struct panthor_vm_op_ctx *op_ctx, { u32 remaining_pt_count = op_ctx->rsvd_page_tables.count - op_ctx->rsvd_page_tables.ptr; + u32 op_type = op_ctx->flags & DRM_PANTHOR_VM_BIND_OP_TYPE_MASK; + + /* If this is a map operation and no BO is attached, we're being called + * from vm_bo_validate() and we can't acquire the VM lock because it's + * already held. In that case, we just skip the deferred vm_bo cleanup, + * which is fine, because the vm_bo validation is not calling + * drm_gpuvm_bo_put_deferred(). + */ + bool skip_deferred_cleanup = op_type == DRM_PANTHOR_VM_BIND_OP_TYPE_MAP && + !op_ctx->map.bo; if (remaining_pt_count) { kmem_cache_free_bulk(pt_cache, remaining_pt_count, @@ -1100,10 +1147,16 @@ static void panthor_vm_cleanup_op_ctx(struct panthor_vm_op_ctx *op_ctx, if (op_ctx->map.vm_bo) drm_gpuvm_bo_put_deferred(op_ctx->map.vm_bo); + if (op_ctx->map.bo) { + panthor_gem_unpin(op_ctx->map.bo); + drm_gem_object_put(&op_ctx->map.bo->base); + } + for (u32 i = 0; i < ARRAY_SIZE(op_ctx->preallocated_vmas); i++) kfree(op_ctx->preallocated_vmas[i]); - drm_gpuvm_bo_deferred_cleanup(&vm->base); + if (!skip_deferred_cleanup) + drm_gpuvm_bo_deferred_cleanup(&vm->base); } static void @@ -1259,18 +1312,17 @@ static int panthor_vm_prepare_map_op_ctx(struct panthor_vm_op_ctx *op_ctx, if (ret) goto err_cleanup; + drm_gem_object_get(&bo->base); + op_ctx->map.bo = bo; + sgt = panthor_gem_get_dev_sgt(bo); if (IS_ERR(sgt)) { - panthor_gem_unpin(bo); ret = PTR_ERR(sgt); goto err_cleanup; } - op_ctx->map.sgt = sgt; - preallocated_vm_bo = drm_gpuvm_bo_create(&vm->base, &bo->base); if (!preallocated_vm_bo) { - panthor_gem_unpin(bo); ret = -ENOMEM; goto err_cleanup; } @@ -1289,6 +1341,13 @@ static int panthor_vm_prepare_map_op_ctx(struct panthor_vm_op_ctx *op_ctx, dma_resv_unlock(panthor_vm_resv(vm)); } + /* And finally update the BO state. */ + dma_resv_lock(bo->base.resv, NULL); + mutex_lock(&bo->base.gpuva.lock); + panthor_gem_update_reclaim_state_locked(bo, NULL); + mutex_unlock(&bo->base.gpuva.lock); + dma_resv_unlock(bo->base.resv); + return 0; err_cleanup: @@ -1876,6 +1935,10 @@ static void panthor_vm_free(struct drm_gpuvm *gpuvm) struct panthor_vm *vm = container_of(gpuvm, struct panthor_vm, base); struct panthor_device *ptdev = vm->ptdev; + mutex_lock(&ptdev->reclaim.lock); + list_del_init(&vm->reclaim.lru_node); + mutex_unlock(&ptdev->reclaim.lock); + mutex_lock(&vm->heaps.lock); if (drm_WARN_ON(&ptdev->base, vm->heaps.pool)) panthor_heap_pool_destroy(vm->heaps.pool); @@ -2089,7 +2152,7 @@ static int panthor_gpuva_sm_step_map(struct drm_gpuva_op *op, void *priv) panthor_vma_init(vma, op_ctx->flags & PANTHOR_VM_MAP_FLAGS); ret = panthor_vm_map_pages(vm, op->map.va.addr, flags_to_prot(vma->flags), - op_ctx->map.sgt, op->map.gem.offset, + op_ctx->map.bo->dmap.sgt, op->map.gem.offset, op->map.va.range); if (ret) { panthor_vm_op_ctx_return_vma(op_ctx, vma); @@ -2173,21 +2236,27 @@ static int panthor_gpuva_sm_step_remap(struct drm_gpuva_op *op, * atomicity. panthor_vm_lock_region() bails out early if the new region * is already part of the locked region, so no need to do this check here. */ - panthor_vm_lock_region(vm, unmap_start, unmap_range); - panthor_vm_unmap_pages(vm, unmap_start, unmap_range); + if (!unmap_vma->evicted) { + panthor_vm_lock_region(vm, unmap_start, unmap_range); + panthor_vm_unmap_pages(vm, unmap_start, unmap_range); + } if (op->remap.prev) { struct panthor_gem_object *bo = to_panthor_bo(op->remap.prev->gem.obj); u64 offset = op->remap.prev->gem.offset + unmap_start - op->remap.prev->va.addr; u64 size = op->remap.prev->va.addr + op->remap.prev->va.range - unmap_start; - ret = panthor_vm_map_pages(vm, unmap_start, flags_to_prot(unmap_vma->flags), - bo->dmap.sgt, offset, size); - if (ret) - return ret; + if (!unmap_vma->evicted) { + ret = panthor_vm_map_pages(vm, unmap_start, + flags_to_prot(unmap_vma->flags), + bo->dmap.sgt, offset, size); + if (ret) + return ret; + } prev_vma = panthor_vm_op_ctx_get_vma(op_ctx); panthor_vma_init(prev_vma, unmap_vma->flags); + prev_vma->evicted = unmap_vma->evicted; } if (op->remap.next) { @@ -2195,13 +2264,17 @@ static int panthor_gpuva_sm_step_remap(struct drm_gpuva_op *op, u64 addr = op->remap.next->va.addr; u64 size = unmap_start + unmap_range - op->remap.next->va.addr; - ret = panthor_vm_map_pages(vm, addr, flags_to_prot(unmap_vma->flags), - bo->dmap.sgt, op->remap.next->gem.offset, size); - if (ret) - return ret; + if (!unmap_vma->evicted) { + ret = panthor_vm_map_pages(vm, addr, flags_to_prot(unmap_vma->flags), + bo->dmap.sgt, op->remap.next->gem.offset, + size); + if (ret) + return ret; + } next_vma = panthor_vm_op_ctx_get_vma(op_ctx); panthor_vma_init(next_vma, unmap_vma->flags); + next_vma->evicted = unmap_vma->evicted; } drm_gpuva_remap(prev_vma ? &prev_vma->base : NULL, @@ -2231,19 +2304,230 @@ static int panthor_gpuva_sm_step_unmap(struct drm_gpuva_op *op, struct panthor_vma *unmap_vma = container_of(op->unmap.va, struct panthor_vma, base); struct panthor_vm *vm = priv; - panthor_vm_unmap_pages(vm, unmap_vma->base.va.addr, - unmap_vma->base.va.range); + if (!unmap_vma->evicted) { + panthor_vm_unmap_pages(vm, unmap_vma->base.va.addr, + unmap_vma->base.va.range); + } + drm_gpuva_unmap(&op->unmap); panthor_vma_unlink(unmap_vma); return 0; } +void panthor_vm_update_bo_reclaim_lru_locked(struct panthor_gem_object *bo) +{ + struct panthor_device *ptdev = container_of(bo->base.dev, struct panthor_device, base); + struct panthor_vm *vm = NULL; + struct drm_gpuvm_bo *vm_bo; + + dma_resv_assert_held(bo->base.resv); + lockdep_assert_held(&bo->base.gpuva.lock); + + drm_gem_for_each_gpuvm_bo(vm_bo, &bo->base) { + if (vm_bo->evicted) + continue; + + /* We're only supposed to have one non-evicted vm_bo in the list if we get + * there. + */ + drm_WARN_ON(&ptdev->base, vm); + vm = container_of(vm_bo->vm, struct panthor_vm, base); + + mutex_lock(&ptdev->reclaim.lock); + drm_gem_lru_move_tail_locked(&vm->reclaim.lru, &bo->base); + if (list_empty(&vm->reclaim.lru_node)) + list_move(&vm->reclaim.lru_node, &ptdev->reclaim.vms); + mutex_unlock(&ptdev->reclaim.lock); + } +} + +int panthor_vm_evict_bo_mappings_locked(struct panthor_gem_object *bo) +{ + struct drm_gpuvm_bo *vm_bo; + int ret = 0; + + drm_gem_for_each_gpuvm_bo(vm_bo, &bo->base) { + struct panthor_vm *vm = container_of(vm_bo->vm, struct panthor_vm, base); + struct drm_gpuva *va; + + /* Skip already evicted GPU mappings. */ + if (vm_bo->evicted) + continue; + + if (!mutex_trylock(&vm->op_lock)) + return -EDEADLK; + + drm_gpuvm_bo_evict(vm_bo, true); + drm_gpuvm_bo_for_each_va(va, vm_bo) { + struct panthor_vma *vma = container_of(va, struct panthor_vma, base); + + if (vma->evicted) + continue; + + /* If something fail in the middle of a VM_BO eviction, the VM_BO + * is considered fully evicted, but some of its VMAs might still be + * active. That's okay because the pages won't be released if this + * function returns an error. + * + * On the next job targeting this VM, the partially evicted VM_BO + * will be validated, causing all its evicted VMAs to be repopulated + * before the job runs. So no GPU fault expected. + */ + ret = panthor_vm_lock_region(vm, va->va.addr, va->va.range); + if (ret) + break; + + panthor_vm_unmap_pages(vm, va->va.addr, va->va.range); + panthor_vm_unlock_region(vm); + vma->evicted = true; + } + + mutex_unlock(&vm->op_lock); + + if (ret) + break; + } + + return ret; +} + +static struct panthor_vma *select_evicted_vma(struct drm_gpuvm_bo *vm_bo, + struct panthor_vm_op_ctx *op_ctx) +{ + struct panthor_vm *vm = container_of(vm_bo->vm, struct panthor_vm, base); + struct panthor_vma *first_evicted_vma = NULL; + struct drm_gpuva *va; + + /* Take op_lock to protect against va insertion/removal. */ + mutex_lock(&vm->op_lock); + drm_gpuvm_bo_for_each_va(va, vm_bo) { + struct panthor_vma *vma = container_of(va, struct panthor_vma, base); + + if (vma->evicted) { + first_evicted_vma = vma; + panthor_vm_init_op_ctx(op_ctx, va->va.range, va->va.addr, vma->flags); + op_ctx->map.bo_offset = va->gem.offset; + break; + } + } + mutex_unlock(&vm->op_lock); + + return first_evicted_vma; +} + +static int remap_evicted_vma(struct drm_gpuvm_bo *vm_bo, + struct panthor_vma *evicted_vma, + struct panthor_vm_op_ctx *op_ctx) +{ + struct panthor_vm *vm = container_of(vm_bo->vm, struct panthor_vm, base); + struct panthor_gem_object *bo = to_panthor_bo(vm_bo->obj); + struct drm_gpuva *va; + bool found = false; + int ret; + + ret = panthor_vm_op_ctx_prealloc_pts(op_ctx); + if (ret) + goto out_cleanup; + + /* Take op_lock to protect against va insertion/removal. Note that the + * evicted_vma selection was done with the same lock held, but we had + * to release it so we can allocate PTs, because this very same lock + * is taken in a DMA-signalling path. + */ + mutex_lock(&vm->op_lock); + drm_gpuvm_bo_for_each_va(va, vm_bo) { + struct panthor_vma *vma = container_of(va, struct panthor_vma, base); + + if (vma != evicted_vma) + continue; + + /* Because we had to release the lock between the evicted_vma selection + * and its repopulation, we can't rely solely on pointer equality (the + * VMA might have been freed and a new one allocated at the same address). + * If the evicted bit is still set, we're sure it's our VMA, because + * population/eviction is serialized with the BO resv lock. + */ + if (vma->evicted) + found = true; + + break; + } + + if (found) { + vm->op_ctx = op_ctx; + ret = panthor_vm_lock_region(vm, evicted_vma->base.va.addr, + evicted_vma->base.va.range); + if (!ret) { + ret = panthor_vm_map_pages(vm, evicted_vma->base.va.addr, + flags_to_prot(evicted_vma->flags), + bo->dmap.sgt, + evicted_vma->base.gem.offset, + evicted_vma->base.va.range); + if (!ret) + evicted_vma->evicted = false; + + panthor_vm_unlock_region(vm); + } + + vm->op_ctx = NULL; + } + + mutex_unlock(&vm->op_lock); + +out_cleanup: + panthor_vm_cleanup_op_ctx(op_ctx, vm); + return ret; +} + +static int panthor_vm_restore_vmas(struct drm_gpuvm_bo *vm_bo) +{ + struct panthor_vm *vm = container_of(vm_bo->vm, struct panthor_vm, base); + struct panthor_gem_object *bo = to_panthor_bo(vm_bo->obj); + struct panthor_vm_op_ctx op_ctx; + + if (drm_WARN_ON_ONCE(&vm->ptdev->base, !bo->dmap.sgt)) + return -EINVAL; + + for (struct panthor_vma *vma = select_evicted_vma(vm_bo, &op_ctx); + vma; vma = select_evicted_vma(vm_bo, &op_ctx)) { + int ret; + + ret = remap_evicted_vma(vm_bo, vma, &op_ctx); + if (ret) + return ret; + } + + return 0; +} + +static int panthor_vm_bo_validate(struct drm_gpuvm_bo *vm_bo, + struct drm_exec *exec) +{ + struct panthor_gem_object *bo = to_panthor_bo(vm_bo->obj); + int ret; + + ret = panthor_gem_swapin_locked(bo); + if (ret) + return ret; + + ret = panthor_vm_restore_vmas(vm_bo); + if (ret) + return ret; + + drm_gpuvm_bo_evict(vm_bo, false); + mutex_lock(&bo->base.gpuva.lock); + panthor_gem_update_reclaim_state_locked(bo, NULL); + mutex_unlock(&bo->base.gpuva.lock); + return 0; +} + static const struct drm_gpuvm_ops panthor_gpuvm_ops = { .vm_free = panthor_vm_free, .vm_bo_free = panthor_vm_bo_free, .sm_step_map = panthor_gpuva_sm_step_map, .sm_step_remap = panthor_gpuva_sm_step_remap, .sm_step_unmap = panthor_gpuva_sm_step_unmap, + .vm_bo_validate = panthor_vm_bo_validate, }; /** @@ -2458,6 +2742,8 @@ panthor_vm_create(struct panthor_device *ptdev, bool for_mcu, vm->kernel_auto_va.start = auto_kernel_va_start; vm->kernel_auto_va.end = vm->kernel_auto_va.start + auto_kernel_va_size - 1; + drm_gem_lru_init(&vm->reclaim.lru, &ptdev->reclaim.lock); + INIT_LIST_HEAD(&vm->reclaim.lru_node); INIT_LIST_HEAD(&vm->node); INIT_LIST_HEAD(&vm->as.lru_node); vm->as.id = -1; @@ -2805,7 +3091,78 @@ int panthor_vm_prepare_mapped_bos_resvs(struct drm_exec *exec, struct panthor_vm if (ret) return ret; - return drm_gpuvm_prepare_objects(&vm->base, exec, slot_count); + ret = drm_gpuvm_prepare_objects(&vm->base, exec, slot_count); + if (ret) + return ret; + + return drm_gpuvm_validate(&vm->base, exec); +} + +unsigned long +panthor_mmu_reclaim_priv_bos(struct panthor_device *ptdev, + unsigned int nr_to_scan, unsigned long *remaining, + bool (*shrink)(struct drm_gem_object *, + struct ww_acquire_ctx *)) +{ + unsigned long freed = 0; + LIST_HEAD(remaining_vms); + LIST_HEAD(vms); + + mutex_lock(&ptdev->reclaim.lock); + list_splice_init(&ptdev->reclaim.vms, &vms); + + while (freed < nr_to_scan) { + struct panthor_vm *vm; + + vm = list_first_entry_or_null(&vms, typeof(*vm), + reclaim.lru_node); + if (!vm) + break; + + if (!kref_get_unless_zero(&vm->base.kref)) { + list_del_init(&vm->reclaim.lru_node); + continue; + } + + mutex_unlock(&ptdev->reclaim.lock); + + freed += drm_gem_lru_scan(&vm->reclaim.lru, nr_to_scan - freed, + remaining, shrink, NULL); + + mutex_lock(&ptdev->reclaim.lock); + + /* If the VM is still in the temporary list, remove it so we + * can proceed with the next VM. + */ + if (vm == list_first_entry_or_null(&vms, typeof(*vm), reclaim.lru_node)) { + list_del_init(&vm->reclaim.lru_node); + + /* Keep the VM around if there are still things to + * reclaim, so we can preserve the LRU order when + * re-inserting in ptdev->reclaim.vms at the end. + */ + if (vm->reclaim.lru.count > 0) + list_add_tail(&vm->reclaim.lru_node, &remaining_vms); + } + + mutex_unlock(&ptdev->reclaim.lock); + + panthor_vm_put(vm); + + mutex_lock(&ptdev->reclaim.lock); + } + + /* Re-insert VMs with remaining data to reclaim at the beginning of + * the LRU. Note that any activeness change on the VM that happened + * while we were reclaiming would have moved the VM out of our + * temporary [remaining_]vms list, meaning anything we re-insert here + * preserves the LRU order. + */ + list_splice_tail(&vms, &remaining_vms); + list_splice(&remaining_vms, &ptdev->reclaim.vms); + mutex_unlock(&ptdev->reclaim.lock); + + return freed; } /** diff --git a/drivers/gpu/drm/panthor/panthor_mmu.h b/drivers/gpu/drm/panthor/panthor_mmu.h index 0e268fdfdb2f..3522fbbce369 100644 --- a/drivers/gpu/drm/panthor/panthor_mmu.h +++ b/drivers/gpu/drm/panthor/panthor_mmu.h @@ -1,6 +1,7 @@ /* SPDX-License-Identifier: GPL-2.0 or MIT */ /* Copyright 2019 Linaro, Ltd, Rob Herring */ /* Copyright 2023 Collabora ltd. */ +/* Copyright 2025 ARM Limited. All rights reserved. */ #ifndef __PANTHOR_MMU_H__ #define __PANTHOR_MMU_H__ @@ -46,6 +47,13 @@ struct panthor_vm *panthor_vm_create(struct panthor_device *ptdev, bool for_mcu, u64 kernel_auto_va_start, u64 kernel_auto_va_size); +void panthor_vm_update_bo_reclaim_lru_locked(struct panthor_gem_object *bo); +int panthor_vm_evict_bo_mappings_locked(struct panthor_gem_object *bo); +unsigned long +panthor_mmu_reclaim_priv_bos(struct panthor_device *ptdev, + unsigned int nr_to_scan, unsigned long *remaining, + bool (*shrink)(struct drm_gem_object *, + struct ww_acquire_ctx *)); int panthor_vm_prepare_mapped_bos_resvs(struct drm_exec *exec, struct panthor_vm *vm, u32 slot_count); -- cgit v1.2.3 From 72d0c064564192d4fba2bf00f78ae303206fa2cc Mon Sep 17 00:00:00 2001 From: Xin Wang Date: Thu, 2 Apr 2026 11:05:50 -0700 Subject: drm/xe: improve readability of debugfs engine info output Improve the readability of the info debugfs output by replacing raw numeric engine masks with human-readable engine and class names. Also print per-GT engine capability data in a form that is easier for a human to interpret directly, and as a side effect simpler for IGT tests to use when validating engine capabilities. Reviewed-by: Niranjana Vishwanathapura Reviewed-by: Matt Roper Signed-off-by: Xin Wang Link: https://patch.msgid.link/20260402180552.24121-2-x.wang@intel.com Signed-off-by: Matt Roper --- drivers/gpu/drm/xe/xe_debugfs.c | 41 +++++++++++++++++++++++++++++++++++++---- 1 file changed, 37 insertions(+), 4 deletions(-) diff --git a/drivers/gpu/drm/xe/xe_debugfs.c b/drivers/gpu/drm/xe/xe_debugfs.c index 844cfafe1ec7..490d7ef7e812 100644 --- a/drivers/gpu/drm/xe/xe_debugfs.c +++ b/drivers/gpu/drm/xe/xe_debugfs.c @@ -15,9 +15,11 @@ #include "xe_bo.h" #include "xe_device.h" #include "xe_force_wake.h" +#include "xe_gt.h" #include "xe_gt_debugfs.h" #include "xe_gt_printk.h" #include "xe_guc_ads.h" +#include "xe_hw_engine.h" #include "xe_mmio.h" #include "xe_pm.h" #include "xe_psmi.h" @@ -61,6 +63,37 @@ static struct xe_device *node_to_xe(struct drm_info_node *node) return to_xe_device(node->minor->dev); } +static void print_engine_class_mask(struct drm_printer *p, u16 mask) +{ + if (!mask) { + drm_printf(p, " none\n"); + return; + } + + for (enum xe_engine_class ec = 0; ec < XE_ENGINE_CLASS_MAX; ec++) { + if (mask & BIT(ec)) + drm_printf(p, " %s", xe_hw_engine_class_to_str(ec)); + } + drm_printf(p, "\n"); +} + +static void print_engine_mask(struct drm_printer *p, struct xe_gt *gt, u64 mask) +{ + struct xe_hw_engine *hwe; + enum xe_hw_engine_id id; + + if (!mask) { + drm_printf(p, " none\n"); + return; + } + + for_each_hw_engine(hwe, gt, id) { + if (mask & BIT_ULL(id)) + drm_printf(p, " %s", hwe->name); + } + drm_printf(p, "\n"); +} + static int info(struct seq_file *m, void *data) { struct xe_device *xe = node_to_xe(m->private); @@ -91,10 +124,10 @@ static int info(struct seq_file *m, void *data) for_each_gt(gt, xe, id) { drm_printf(&p, "gt%d force wake %d\n", id, xe_force_wake_ref(gt_to_fw(gt), XE_FW_GT)); - drm_printf(&p, "gt%d engine_mask 0x%llx\n", id, - gt->info.engine_mask); - drm_printf(&p, "gt%d multi_queue_engine_class_mask 0x%x\n", id, - gt->info.multi_queue_engine_class_mask); + drm_printf(&p, "gt%d engines", id); + print_engine_mask(&p, gt, gt->info.engine_mask); + drm_printf(&p, "gt%d multi_queue_engine_classes", id); + print_engine_class_mask(&p, gt->info.multi_queue_engine_class_mask); } return 0; -- cgit v1.2.3 From cc708deedf686c68e84851e89a2f7844dc0536ae Mon Sep 17 00:00:00 2001 From: Xin Wang Date: Thu, 2 Apr 2026 11:05:51 -0700 Subject: drm/xe: expose multi-lrc engine classes in debugfs info Expose multi_lrc_engine_classes in the info debugfs output as a useful extra piece of information for debugging. Reviewed-by: Niranjana Vishwanathapura Signed-off-by: Xin Wang Link: https://patch.msgid.link/20260402180552.24121-3-x.wang@intel.com Signed-off-by: Matt Roper --- drivers/gpu/drm/xe/xe_debugfs.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/drivers/gpu/drm/xe/xe_debugfs.c b/drivers/gpu/drm/xe/xe_debugfs.c index 490d7ef7e812..c9d4484821af 100644 --- a/drivers/gpu/drm/xe/xe_debugfs.c +++ b/drivers/gpu/drm/xe/xe_debugfs.c @@ -121,6 +121,8 @@ static int info(struct seq_file *m, void *data) drm_printf(&p, "has_flat_ccs %s\n", str_yes_no(xe->info.has_flat_ccs)); drm_printf(&p, "has_usm %s\n", str_yes_no(xe->info.has_usm)); drm_printf(&p, "skip_guc_pc %s\n", str_yes_no(xe->info.skip_guc_pc)); + drm_printf(&p, "multi_lrc_engine_classes"); + print_engine_class_mask(&p, xe->info.multi_lrc_mask); for_each_gt(gt, xe, id) { drm_printf(&p, "gt%d force wake %d\n", id, xe_force_wake_ref(gt_to_fw(gt), XE_FW_GT)); -- cgit v1.2.3 From 6e87001fe19f251e2ae14373bc76554358a13df2 Mon Sep 17 00:00:00 2001 From: Lizhi Hou Date: Thu, 2 Apr 2026 10:41:48 -0700 Subject: accel/amdxdna: Adjust size for copy_to_user() The amount of data returned to user space should be limited by the buffer size provided by the application. If the buffer is smaller than the data size, return only the portion that fits instead of failing. Fixes: 850d71f6bf4c ("accel/amdxdna: Add query functions") Reviewed-by: Mario Limonciello (AMD) Signed-off-by: Lizhi Hou Link: https://patch.msgid.link/20260402174148.3527757-1-lizhi.hou@amd.com --- drivers/accel/amdxdna/aie2_error.c | 5 ++- drivers/accel/amdxdna/aie2_message.c | 20 +++++++----- drivers/accel/amdxdna/aie2_pci.c | 59 +++++++++++++++++++++--------------- 3 files changed, 50 insertions(+), 34 deletions(-) diff --git a/drivers/accel/amdxdna/aie2_error.c b/drivers/accel/amdxdna/aie2_error.c index 9d20e956c020..70007b4363cd 100644 --- a/drivers/accel/amdxdna/aie2_error.c +++ b/drivers/accel/amdxdna/aie2_error.c @@ -406,8 +406,11 @@ int aie2_get_array_async_error(struct amdxdna_dev_hdl *ndev, struct amdxdna_drm_ drm_WARN_ON(&xdna->ddev, !mutex_is_locked(&xdna->dev_lock)); + if (!args->num_element) + return -EINVAL; + args->num_element = 1; - args->element_size = sizeof(ndev->last_async_err); + args->element_size = min(args->element_size, sizeof(ndev->last_async_err)); if (copy_to_user(u64_to_user_ptr(args->buffer), &ndev->last_async_err, args->element_size)) return -EFAULT; diff --git a/drivers/accel/amdxdna/aie2_message.c b/drivers/accel/amdxdna/aie2_message.c index e5e7da7a8f40..e52dc7ea9fc7 100644 --- a/drivers/accel/amdxdna/aie2_message.c +++ b/drivers/accel/amdxdna/aie2_message.c @@ -369,12 +369,13 @@ int aie2_query_status(struct amdxdna_dev_hdl *ndev, char __user *buf, { DECLARE_AIE_MSG(aie_column_info, MSG_OP_QUERY_COL_STATUS); struct amdxdna_dev *xdna = ndev->aie.xdna; - u32 buf_sz = size, aie_bitmap = 0; + u32 buf_sz, aie_bitmap = 0; struct amdxdna_client *client; dma_addr_t dma_addr; u8 *buff_addr; int ret; + buf_sz = ndev->metadata.cols * ndev->metadata.size; buff_addr = aie2_alloc_msg_buffer(ndev, &buf_sz, &dma_addr); if (IS_ERR(buff_addr)) return PTR_ERR(buff_addr); @@ -398,13 +399,14 @@ int aie2_query_status(struct amdxdna_dev_hdl *ndev, char __user *buf, XDNA_DBG(xdna, "Query NPU status completed"); - if (size < resp.size) { + if (buf_sz < resp.size) { ret = -EINVAL; - XDNA_ERR(xdna, "Bad buffer size. Available: %u. Needs: %u", size, resp.size); + XDNA_ERR(xdna, "Bad buffer size. Available: %u. Needs: %u", buf_sz, resp.size); goto fail; } - if (copy_to_user(buf, buff_addr, resp.size)) { + size = min(size, resp.size); + if (copy_to_user(buf, buff_addr, size)) { ret = -EFAULT; XDNA_ERR(xdna, "Failed to copy NPU status to user space"); goto fail; @@ -424,13 +426,14 @@ int aie2_query_telemetry(struct amdxdna_dev_hdl *ndev, DECLARE_AIE_MSG(get_telemetry, MSG_OP_GET_TELEMETRY); struct amdxdna_dev *xdna = ndev->aie.xdna; dma_addr_t dma_addr; - u32 buf_sz = size; + u32 buf_sz; u8 *addr; int ret; if (header->type >= MAX_TELEMETRY_TYPE) return -EINVAL; + buf_sz = min(size, SZ_4M); addr = aie2_alloc_msg_buffer(ndev, &buf_sz, &dma_addr); if (IS_ERR(addr)) return PTR_ERR(addr); @@ -446,13 +449,14 @@ int aie2_query_telemetry(struct amdxdna_dev_hdl *ndev, goto free_buf; } - if (size < resp.size) { + if (buf_sz < resp.size) { ret = -EINVAL; - XDNA_ERR(xdna, "Bad buffer size. Available: %u. Needs: %u", size, resp.size); + XDNA_ERR(xdna, "Bad buffer size. Available: %u. Needs: %u", buf_sz, resp.size); goto free_buf; } - if (copy_to_user(buf, addr, resp.size)) { + size = min(size, resp.size); + if (copy_to_user(buf, addr, size)) { ret = -EFAULT; XDNA_ERR(xdna, "Failed to copy telemetry to user space"); goto free_buf; diff --git a/drivers/accel/amdxdna/aie2_pci.c b/drivers/accel/amdxdna/aie2_pci.c index 164e188ba501..041cbc8cd7e5 100644 --- a/drivers/accel/amdxdna/aie2_pci.c +++ b/drivers/accel/amdxdna/aie2_pci.c @@ -620,23 +620,19 @@ static void aie2_fini(struct amdxdna_dev *xdna) static int aie2_get_aie_status(struct amdxdna_client *client, struct amdxdna_drm_get_info *args) { - struct amdxdna_drm_query_aie_status status; + struct amdxdna_drm_query_aie_status status = {}; struct amdxdna_dev *xdna = client->xdna; struct amdxdna_dev_hdl *ndev; + u32 buf_sz; int ret; ndev = xdna->dev_handle; - if (copy_from_user(&status, u64_to_user_ptr(args->buffer), sizeof(status))) { + buf_sz = min(args->buffer_size, sizeof(status)); + if (copy_from_user(&status, u64_to_user_ptr(args->buffer), buf_sz)) { XDNA_ERR(xdna, "Failed to copy AIE request into kernel"); return -EFAULT; } - if (ndev->metadata.cols * ndev->metadata.size < status.buffer_size) { - XDNA_ERR(xdna, "Invalid buffer size. Given Size: %u. Need Size: %u.", - status.buffer_size, ndev->metadata.cols * ndev->metadata.size); - return -EINVAL; - } - ret = aie2_query_status(ndev, u64_to_user_ptr(status.buffer), status.buffer_size, &status.cols_filled); if (ret) { @@ -644,7 +640,7 @@ static int aie2_get_aie_status(struct amdxdna_client *client, return ret; } - if (copy_to_user(u64_to_user_ptr(args->buffer), &status, sizeof(status))) { + if (copy_to_user(u64_to_user_ptr(args->buffer), &status, buf_sz)) { XDNA_ERR(xdna, "Failed to copy AIE request info to user space"); return -EFAULT; } @@ -659,6 +655,7 @@ static int aie2_get_aie_metadata(struct amdxdna_client *client, struct amdxdna_dev *xdna = client->xdna; struct amdxdna_dev_hdl *ndev; int ret = 0; + u32 buf_sz; ndev = xdna->dev_handle; meta = kzalloc_obj(*meta); @@ -690,7 +687,8 @@ static int aie2_get_aie_metadata(struct amdxdna_client *client, meta->shim.lock_count = ndev->metadata.shim.lock_count; meta->shim.event_reg_count = ndev->metadata.shim.event_reg_count; - if (copy_to_user(u64_to_user_ptr(args->buffer), meta, sizeof(*meta))) + buf_sz = min(args->buffer_size, sizeof(*meta)); + if (copy_to_user(u64_to_user_ptr(args->buffer), meta, buf_sz)) ret = -EFAULT; kfree(meta); @@ -703,12 +701,14 @@ static int aie2_get_aie_version(struct amdxdna_client *client, struct amdxdna_drm_query_aie_version version; struct amdxdna_dev *xdna = client->xdna; struct amdxdna_dev_hdl *ndev; + u32 buf_sz; ndev = xdna->dev_handle; version.major = ndev->version.major; version.minor = ndev->version.minor; - if (copy_to_user(u64_to_user_ptr(args->buffer), &version, sizeof(version))) + buf_sz = min(args->buffer_size, sizeof(version)); + if (copy_to_user(u64_to_user_ptr(args->buffer), &version, buf_sz)) return -EFAULT; return 0; @@ -719,13 +719,15 @@ static int aie2_get_firmware_version(struct amdxdna_client *client, { struct amdxdna_drm_query_firmware_version version; struct amdxdna_dev *xdna = client->xdna; + u32 buf_sz; version.major = xdna->fw_ver.major; version.minor = xdna->fw_ver.minor; version.patch = xdna->fw_ver.sub; version.build = xdna->fw_ver.build; - if (copy_to_user(u64_to_user_ptr(args->buffer), &version, sizeof(version))) + buf_sz = min(args->buffer_size, sizeof(version)); + if (copy_to_user(u64_to_user_ptr(args->buffer), &version, buf_sz)) return -EFAULT; return 0; @@ -737,11 +739,13 @@ static int aie2_get_power_mode(struct amdxdna_client *client, struct amdxdna_drm_get_power_mode mode = {}; struct amdxdna_dev *xdna = client->xdna; struct amdxdna_dev_hdl *ndev; + u32 buf_sz; ndev = xdna->dev_handle; mode.power_mode = ndev->pw_mode; - if (copy_to_user(u64_to_user_ptr(args->buffer), &mode, sizeof(mode))) + buf_sz = min(args->buffer_size, sizeof(mode)); + if (copy_to_user(u64_to_user_ptr(args->buffer), &mode, buf_sz)) return -EFAULT; return 0; @@ -754,6 +758,7 @@ static int aie2_get_clock_metadata(struct amdxdna_client *client, struct amdxdna_dev *xdna = client->xdna; struct amdxdna_dev_hdl *ndev; int ret = 0; + u32 buf_sz; ndev = xdna->dev_handle; clock = kzalloc_obj(*clock); @@ -766,7 +771,8 @@ static int aie2_get_clock_metadata(struct amdxdna_client *client, snprintf(clock->h_clock.name, sizeof(clock->h_clock.name), "H Clock"); clock->h_clock.freq_mhz = ndev->hclk_freq; - if (copy_to_user(u64_to_user_ptr(args->buffer), clock, sizeof(*clock))) + buf_sz = min(args->buffer_size, sizeof(*clock)); + if (copy_to_user(u64_to_user_ptr(args->buffer), clock, buf_sz)) ret = -EFAULT; kfree(clock); @@ -792,12 +798,14 @@ static int aie2_get_sensors(struct amdxdna_client *client, scnprintf(sensor.label, sizeof(sensor.label), "Total Power"); scnprintf(sensor.units, sizeof(sensor.units), "mW"); + if (args->buffer_size < sizeof(sensor)) + goto out; + if (copy_to_user(u64_to_user_ptr(args->buffer), &sensor, sizeof(sensor))) return -EFAULT; + args->buffer_size -= sizeof(sensor); sensors_count++; - if (args->buffer_size <= sensors_count * sizeof(sensor)) - goto out; for (i = 0; i < min_t(u32, ndev->total_col, 8); i++) { memset(&sensor, 0, sizeof(sensor)); @@ -807,13 +815,15 @@ static int aie2_get_sensors(struct amdxdna_client *client, scnprintf(sensor.label, sizeof(sensor.label), "Column %d Utilization", i); scnprintf(sensor.units, sizeof(sensor.units), "%%"); + if (args->buffer_size < sizeof(sensor)) + goto out; + if (copy_to_user(u64_to_user_ptr(args->buffer) + sensors_count * sizeof(sensor), &sensor, sizeof(sensor))) return -EFAULT; + args->buffer_size -= sizeof(sensor); sensors_count++; - if (args->buffer_size <= sensors_count * sizeof(sensor)) - goto out; } out: @@ -909,6 +919,7 @@ static int aie2_query_resource_info(struct amdxdna_client *client, const struct amdxdna_dev_priv *priv; struct amdxdna_dev_hdl *ndev; struct amdxdna_dev *xdna; + u32 buf_sz; xdna = client->xdna; ndev = xdna->dev_handle; @@ -920,7 +931,8 @@ static int aie2_query_resource_info(struct amdxdna_client *client, res_info.npu_tops_curr = ndev->curr_tops; res_info.npu_task_curr = ndev->hwctx_num; - if (copy_to_user(u64_to_user_ptr(args->buffer), &res_info, sizeof(res_info))) + buf_sz = min(args->buffer_size, sizeof(res_info)); + if (copy_to_user(u64_to_user_ptr(args->buffer), &res_info, buf_sz)) return -EFAULT; return 0; @@ -956,12 +968,7 @@ static int aie2_get_telemetry(struct amdxdna_client *client, XDNA_ERR(xdna, "Invalid buffer size"); return -EINVAL; } - telemetry_data_sz = args->buffer_size - header_sz; - if (telemetry_data_sz > SZ_4M) { - XDNA_ERR(xdna, "Buffer size is too big, %d", telemetry_data_sz); - return -EINVAL; - } header = kzalloc(header_sz, GFP_KERNEL); if (!header) @@ -1002,6 +1009,7 @@ static int aie2_get_preempt_state(struct amdxdna_client *client, struct amdxdna_drm_attribute_state state = {}; struct amdxdna_dev *xdna = client->xdna; struct amdxdna_dev_hdl *ndev; + u32 buf_sz; ndev = xdna->dev_handle; if (args->param == DRM_AMDXDNA_GET_FORCE_PREEMPT_STATE) @@ -1009,7 +1017,8 @@ static int aie2_get_preempt_state(struct amdxdna_client *client, else if (args->param == DRM_AMDXDNA_GET_FRAME_BOUNDARY_PREEMPT_STATE) state.state = ndev->frame_boundary_preempt; - if (copy_to_user(u64_to_user_ptr(args->buffer), &state, sizeof(state))) + buf_sz = min(args->buffer_size, sizeof(state)); + if (copy_to_user(u64_to_user_ptr(args->buffer), &state, buf_sz)) return -EFAULT; return 0; -- cgit v1.2.3 From f9a21696e37b069c96b81fa0ad8392b7b6d4a47e Mon Sep 17 00:00:00 2001 From: Julia Filipchuk Date: Tue, 3 Mar 2026 16:34:24 -0800 Subject: drm/xe: Enable Wa_14025515070 Corrects a failure on context switch. On registration of context with indirect ring state will correct state of targeted and idle command streamers. This Wa requires GuC 70.53+ (uapi 1.26+). If indirect_ring_state is enabled and Wa is unavailable, notify and disable indirect_ring_state. Added additional XE_RTP_PASTE macros for expansion of longer rules. Reviewed-by: Daniele Ceraolo Spurio Signed-off-by: Julia Filipchuk Signed-off-by: Vinay Belgaumkar Link: https://patch.msgid.link/20260304003431.758201-4-julia.filipchuk@intel.com --- drivers/gpu/drm/xe/abi/guc_klvs_abi.h | 1 + drivers/gpu/drm/xe/xe_guc.c | 8 ++++++++ drivers/gpu/drm/xe/xe_guc_ads.c | 3 +++ drivers/gpu/drm/xe/xe_rtp_helpers.h | 2 ++ drivers/gpu/drm/xe/xe_wa_oob.rules | 7 +++++++ 5 files changed, 21 insertions(+) diff --git a/drivers/gpu/drm/xe/abi/guc_klvs_abi.h b/drivers/gpu/drm/xe/abi/guc_klvs_abi.h index e33bd622ab44..f0815500177b 100644 --- a/drivers/gpu/drm/xe/abi/guc_klvs_abi.h +++ b/drivers/gpu/drm/xe/abi/guc_klvs_abi.h @@ -496,6 +496,7 @@ enum xe_guc_klv_ids { GUC_WA_KLV_WAKE_POWER_DOMAINS_FOR_OUTBOUND_MMIO = 0x900a, GUC_WA_KLV_RESET_BB_STACK_PTR_ON_VF_SWITCH = 0x900b, GUC_WA_KLV_RESTORE_UNSAVED_MEDIA_CONTROL_REG = 0x900c, + GUC_WA_KLV_CLR_CS_INDIRECT_RING_STATE_IF_IDLE_AT_CTX_REG = 0x900e, }; #endif diff --git a/drivers/gpu/drm/xe/xe_guc.c b/drivers/gpu/drm/xe/xe_guc.c index ccebb437e37f..e762eada21db 100644 --- a/drivers/gpu/drm/xe/xe_guc.c +++ b/drivers/gpu/drm/xe/xe_guc.c @@ -780,6 +780,14 @@ int xe_guc_init(struct xe_guc *guc) if (GUC_SUBMIT_VER(guc) < MAKE_GUC_VER(1, 14, 0)) xe->info.has_page_reclaim_hw_assist = false; + /* Disable indirect_ring_state if missing GuC 70.53+ WA 14025515070. */ + if (gt->info.has_indirect_ring_state && + XE_GT_WA(gt, 14025515070) && + GUC_SUBMIT_VER(guc) < MAKE_GUC_VER(1, 26, 0)) { + gt->info.has_indirect_ring_state = 0; + xe_gt_notice(gt, "indirect ring state requires WA in GuC submit ver 1.26+\n"); + } + if (IS_SRIOV_VF(xe)) { ret = devm_add_action_or_reset(xe->drm.dev, vf_guc_fini_hw, guc); if (ret) diff --git a/drivers/gpu/drm/xe/xe_guc_ads.c b/drivers/gpu/drm/xe/xe_guc_ads.c index 81b5f01b1f65..92c6981fe220 100644 --- a/drivers/gpu/drm/xe/xe_guc_ads.c +++ b/drivers/gpu/drm/xe/xe_guc_ads.c @@ -360,6 +360,9 @@ static void guc_waklv_init(struct xe_guc_ads *ads) if (XE_GT_WA(gt, 14020001231)) guc_waklv_enable(ads, NULL, 0, &offset, &remain, GUC_WORKAROUND_KLV_DISABLE_PSMI_INTERRUPTS_AT_C6_ENTRY_RESTORE_AT_EXIT); + if (XE_GT_WA(gt, 14025515070) && GUC_FIRMWARE_VER_AT_LEAST(>->uc.guc, 70, 53)) + guc_waklv_enable(ads, NULL, 0, &offset, &remain, + GUC_WA_KLV_CLR_CS_INDIRECT_RING_STATE_IF_IDLE_AT_CTX_REG); size = guc_ads_waklv_size(ads) - remain; if (!size) diff --git a/drivers/gpu/drm/xe/xe_rtp_helpers.h b/drivers/gpu/drm/xe/xe_rtp_helpers.h index a33b0ae98bbc..86eee60c04a1 100644 --- a/drivers/gpu/drm/xe/xe_rtp_helpers.h +++ b/drivers/gpu/drm/xe/xe_rtp_helpers.h @@ -66,6 +66,8 @@ #define XE_RTP_PASTE_10(prefix_, sep_, args_) _XE_RTP_CONCAT(prefix_, FIRST_ARG args_) __XE_RTP_PASTE_SEP_ ## sep_ XE_RTP_PASTE_9(prefix_, sep_, _XE_TUPLE_TAIL args_) #define XE_RTP_PASTE_11(prefix_, sep_, args_) _XE_RTP_CONCAT(prefix_, FIRST_ARG args_) __XE_RTP_PASTE_SEP_ ## sep_ XE_RTP_PASTE_10(prefix_, sep_, _XE_TUPLE_TAIL args_) #define XE_RTP_PASTE_12(prefix_, sep_, args_) _XE_RTP_CONCAT(prefix_, FIRST_ARG args_) __XE_RTP_PASTE_SEP_ ## sep_ XE_RTP_PASTE_11(prefix_, sep_, _XE_TUPLE_TAIL args_) +#define XE_RTP_PASTE_13(prefix_, sep_, args_) _XE_RTP_CONCAT(prefix_, FIRST_ARG args_) __XE_RTP_PASTE_SEP_ ## sep_ XE_RTP_PASTE_12(prefix_, sep_, _XE_TUPLE_TAIL args_) +#define XE_RTP_PASTE_14(prefix_, sep_, args_) _XE_RTP_CONCAT(prefix_, FIRST_ARG args_) __XE_RTP_PASTE_SEP_ ## sep_ XE_RTP_PASTE_13(prefix_, sep_, _XE_TUPLE_TAIL args_) /* * XE_RTP_DROP_CAST - Drop cast to convert a compound statement to a initializer diff --git a/drivers/gpu/drm/xe/xe_wa_oob.rules b/drivers/gpu/drm/xe/xe_wa_oob.rules index 80b54b195f20..f8a185103b80 100644 --- a/drivers/gpu/drm/xe/xe_wa_oob.rules +++ b/drivers/gpu/drm/xe/xe_wa_oob.rules @@ -51,6 +51,13 @@ MEDIA_VERSION_RANGE(2000, 3002), FUNC(xe_rtp_match_psmi_enabled) 16023683509 MEDIA_VERSION(2000), FUNC(xe_rtp_match_psmi_enabled) MEDIA_VERSION(3000), MEDIA_STEP(A0, B0), FUNC(xe_rtp_match_psmi_enabled) +14025515070 GRAPHICS_VERSION(2004) + MEDIA_VERSION_RANGE(1301, 3000) + MEDIA_VERSION(3002) + GRAPHICS_VERSION_RANGE(3000, 3001) + GRAPHICS_VERSION_RANGE(3003, 3005) + MEDIA_VERSION(3500) + GRAPHICS_VERSION(3510), GRAPHICS_STEP(A0, B0) 15015404425_disable PLATFORM(PANTHERLAKE), MEDIA_STEP(B0, FOREVER) 16026007364 MEDIA_VERSION(3000) -- cgit v1.2.3 From 13743bd628bc9d9a0e2fe53488b2891aedf7cc74 Mon Sep 17 00:00:00 2001 From: Vinay Belgaumkar Date: Tue, 31 Mar 2026 18:27:10 -0700 Subject: drm/xe: Fix bug in idledly unit conversion We only need to convert to picosecond units before writing to RING_IDLEDLY. Fixes: 7c53ff050ba8 ("drm/xe: Apply Wa_16023105232") Cc: Tangudu Tilak Tirumalesh Acked-by: Tangudu Tilak Tirumalesh Signed-off-by: Vinay Belgaumkar Link: https://patch.msgid.link/20260401012710.4165547-1-vinay.belgaumkar@intel.com --- drivers/gpu/drm/xe/xe_hw_engine.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/drivers/gpu/drm/xe/xe_hw_engine.c b/drivers/gpu/drm/xe/xe_hw_engine.c index 337baf0a6e87..6dd05fac6595 100644 --- a/drivers/gpu/drm/xe/xe_hw_engine.c +++ b/drivers/gpu/drm/xe/xe_hw_engine.c @@ -597,9 +597,8 @@ static void adjust_idledly(struct xe_hw_engine *hwe) maxcnt *= maxcnt_units_ns; if (xe_gt_WARN_ON(gt, idledly >= maxcnt || inhibit_switch)) { - idledly = DIV_ROUND_CLOSEST(((maxcnt - 1) * maxcnt_units_ns), + idledly = DIV_ROUND_CLOSEST(((maxcnt - 1) * 1000), idledly_units_ps); - idledly = DIV_ROUND_CLOSEST(idledly, 1000); xe_mmio_write32(>->mmio, RING_IDLEDLY(hwe->mmio_base), idledly); } } -- cgit v1.2.3 From de1e32ef1d625ee4d717bcf10c23df2722324f62 Mon Sep 17 00:00:00 2001 From: Maíra Canal Date: Tue, 31 Mar 2026 09:35:51 -0300 Subject: drm/v3d: Use devm_reset_control_get_optional_exclusive() MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Simplify optional reset handling by using the function devm_reset_control_get_optional_exclusive(). Reviewed-by: Melissa Wen Reviewed-by: Philipp Zabel Reviewed-by: Florian Fainelli Link: https://patch.msgid.link/20260331-v3d-power-management-v9-1-f52ff87bfd36@igalia.com Signed-off-by: Maíra Canal --- drivers/gpu/drm/v3d/v3d_drv.c | 15 +++++++-------- 1 file changed, 7 insertions(+), 8 deletions(-) diff --git a/drivers/gpu/drm/v3d/v3d_drv.c b/drivers/gpu/drm/v3d/v3d_drv.c index 4b441afcb602..c5e7c778ec7a 100644 --- a/drivers/gpu/drm/v3d/v3d_drv.c +++ b/drivers/gpu/drm/v3d/v3d_drv.c @@ -401,18 +401,17 @@ static int v3d_platform_drm_probe(struct platform_device *pdev) v3d_perfmon_init(v3d); - v3d->reset = devm_reset_control_get_exclusive(dev, NULL); + v3d->reset = devm_reset_control_get_optional_exclusive(dev, NULL); if (IS_ERR(v3d->reset)) { - ret = PTR_ERR(v3d->reset); - - if (ret == -EPROBE_DEFER) - goto clk_disable; + ret = dev_err_probe(dev, PTR_ERR(v3d->reset), + "Failed to get reset control\n"); + goto clk_disable; + } - v3d->reset = NULL; + if (!v3d->reset) { ret = map_regs(v3d, &v3d->bridge_regs, "bridge"); if (ret) { - dev_err(dev, - "Failed to get reset control or bridge regs\n"); + dev_err(dev, "Failed to get bridge registers\n"); goto clk_disable; } } -- cgit v1.2.3 From ffd7371ed4179827dcf401543b37b69e5781f924 Mon Sep 17 00:00:00 2001 From: Maíra Canal Date: Tue, 31 Mar 2026 09:35:52 -0300 Subject: drm/v3d: Allocate all resources before enabling the clock MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Move all resource allocation operations before actually enabling the clock, as those operations don't require the GPU to be powered on. This is a preparation for runtime PM support. The next commit will move all code related to powering on and initiating the GPU into the runtime PM resume callback and all resource allocation will happen before resume(). Reviewed-by: Melissa Wen Reviewed-by: Florian Fainelli Link: https://patch.msgid.link/20260331-v3d-power-management-v9-2-f52ff87bfd36@igalia.com Signed-off-by: Maíra Canal --- drivers/gpu/drm/v3d/v3d_drv.c | 93 ++++++++++++++++++++++--------------------- drivers/gpu/drm/v3d/v3d_drv.h | 1 + drivers/gpu/drm/v3d/v3d_gem.c | 17 ++++---- drivers/gpu/drm/v3d/v3d_irq.c | 15 +++---- 4 files changed, 61 insertions(+), 65 deletions(-) diff --git a/drivers/gpu/drm/v3d/v3d_drv.c b/drivers/gpu/drm/v3d/v3d_drv.c index c5e7c778ec7a..e57b36f4d81a 100644 --- a/drivers/gpu/drm/v3d/v3d_drv.c +++ b/drivers/gpu/drm/v3d/v3d_drv.c @@ -363,14 +363,50 @@ static int v3d_platform_drm_probe(struct platform_device *pdev) return ret; } + if (v3d->ver < V3D_GEN_41) { + ret = map_regs(v3d, &v3d->gca_regs, "gca"); + if (ret) + return ret; + } + + v3d->reset = devm_reset_control_get_optional_exclusive(dev, NULL); + if (IS_ERR(v3d->reset)) + return dev_err_probe(dev, PTR_ERR(v3d->reset), + "Failed to get reset control\n"); + + if (!v3d->reset) { + ret = map_regs(v3d, &v3d->bridge_regs, "bridge"); + if (ret) { + dev_err(dev, "Failed to get bridge registers\n"); + return ret; + } + } + v3d->clk = devm_clk_get_optional(dev, NULL); if (IS_ERR(v3d->clk)) return dev_err_probe(dev, PTR_ERR(v3d->clk), "Failed to get V3D clock\n"); + ret = v3d_irq_init(v3d); + if (ret) + return ret; + + v3d_perfmon_init(v3d); + + v3d->mmu_scratch = dma_alloc_wc(dev, 4096, &v3d->mmu_scratch_paddr, + GFP_KERNEL | __GFP_NOWARN | __GFP_ZERO); + if (!v3d->mmu_scratch) { + dev_err(dev, "Failed to allocate MMU scratch page\n"); + return -ENOMEM; + } + + ret = v3d_gem_init(drm); + if (ret) + goto dma_free; + ret = clk_prepare_enable(v3d->clk); if (ret) { dev_err(&pdev->dev, "Couldn't enable the V3D clock\n"); - return ret; + goto gem_destroy; } v3d_idle_sms(v3d); @@ -399,44 +435,9 @@ static int v3d_platform_drm_probe(struct platform_device *pdev) ident3 = V3D_READ(V3D_HUB_IDENT3); v3d->rev = V3D_GET_FIELD(ident3, V3D_HUB_IDENT3_IPREV); - v3d_perfmon_init(v3d); - - v3d->reset = devm_reset_control_get_optional_exclusive(dev, NULL); - if (IS_ERR(v3d->reset)) { - ret = dev_err_probe(dev, PTR_ERR(v3d->reset), - "Failed to get reset control\n"); - goto clk_disable; - } - - if (!v3d->reset) { - ret = map_regs(v3d, &v3d->bridge_regs, "bridge"); - if (ret) { - dev_err(dev, "Failed to get bridge registers\n"); - goto clk_disable; - } - } - - if (v3d->ver < V3D_GEN_41) { - ret = map_regs(v3d, &v3d->gca_regs, "gca"); - if (ret) - goto clk_disable; - } - - v3d->mmu_scratch = dma_alloc_wc(dev, 4096, &v3d->mmu_scratch_paddr, - GFP_KERNEL | __GFP_NOWARN | __GFP_ZERO); - if (!v3d->mmu_scratch) { - dev_err(dev, "Failed to allocate MMU scratch page\n"); - ret = -ENOMEM; - goto clk_disable; - } - - ret = v3d_gem_init(drm); - if (ret) - goto dma_free; - - ret = v3d_irq_init(v3d); - if (ret) - goto gem_destroy; + v3d_init_hw_state(v3d); + v3d_mmu_set_page_table(v3d); + v3d_irq_enable(v3d); ret = drm_dev_register(drm, 0); if (ret) @@ -452,12 +453,13 @@ drm_unregister: drm_dev_unregister(drm); irq_disable: v3d_irq_disable(v3d); +clk_disable: + v3d_power_off_sms(v3d); + clk_disable_unprepare(v3d->clk); gem_destroy: v3d_gem_destroy(drm); dma_free: dma_free_wc(dev, 4096, v3d->mmu_scratch, v3d->mmu_scratch_paddr); -clk_disable: - clk_disable_unprepare(v3d->clk); return ret; } @@ -471,14 +473,13 @@ static void v3d_platform_drm_remove(struct platform_device *pdev) drm_dev_unregister(drm); - v3d_gem_destroy(drm); - - dma_free_wc(v3d->drm.dev, 4096, v3d->mmu_scratch, - v3d->mmu_scratch_paddr); - v3d_power_off_sms(v3d); clk_disable_unprepare(v3d->clk); + + v3d_gem_destroy(drm); + + dma_free_wc(dev, 4096, v3d->mmu_scratch, v3d->mmu_scratch_paddr); } static struct platform_driver v3d_platform_driver = { diff --git a/drivers/gpu/drm/v3d/v3d_drv.h b/drivers/gpu/drm/v3d/v3d_drv.h index 6a3cad933439..ebf406b615bb 100644 --- a/drivers/gpu/drm/v3d/v3d_drv.h +++ b/drivers/gpu/drm/v3d/v3d_drv.h @@ -565,6 +565,7 @@ struct dma_fence *v3d_fence_create(struct v3d_dev *v3d, enum v3d_queue q); /* v3d_gem.c */ extern bool super_pages; +void v3d_init_hw_state(struct v3d_dev *v3d); int v3d_gem_init(struct drm_device *dev); void v3d_gem_destroy(struct drm_device *dev); void v3d_reset_sms(struct v3d_dev *v3d); diff --git a/drivers/gpu/drm/v3d/v3d_gem.c b/drivers/gpu/drm/v3d/v3d_gem.c index 75d9eccd7966..1ee3c038d5f6 100644 --- a/drivers/gpu/drm/v3d/v3d_gem.c +++ b/drivers/gpu/drm/v3d/v3d_gem.c @@ -36,13 +36,6 @@ v3d_init_core(struct v3d_dev *v3d, int core) V3D_CORE_WRITE(core, V3D_CTL_L2TFLEND, ~0); } -/* Sets invariant state for the HW. */ -static void -v3d_init_hw_state(struct v3d_dev *v3d) -{ - v3d_init_core(v3d, 0); -} - static void v3d_idle_axi(struct v3d_dev *v3d, int core) { @@ -259,6 +252,13 @@ v3d_invalidate_caches(struct v3d_dev *v3d) v3d_invalidate_slices(v3d, 0); } +/* Sets invariant state for the HW. */ +void +v3d_init_hw_state(struct v3d_dev *v3d) +{ + v3d_init_core(v3d, 0); +} + static void v3d_huge_mnt_init(struct v3d_dev *v3d) { @@ -328,9 +328,6 @@ v3d_gem_init(struct drm_device *dev) goto err_dma_alloc; } - v3d_init_hw_state(v3d); - v3d_mmu_set_page_table(v3d); - v3d_huge_mnt_init(v3d); ret = v3d_sched_init(v3d); diff --git a/drivers/gpu/drm/v3d/v3d_irq.c b/drivers/gpu/drm/v3d/v3d_irq.c index c28e74ab5442..86efaef2722c 100644 --- a/drivers/gpu/drm/v3d/v3d_irq.c +++ b/drivers/gpu/drm/v3d/v3d_irq.c @@ -248,17 +248,10 @@ v3d_hub_irq(int irq, void *arg) int v3d_irq_init(struct v3d_dev *v3d) { - int irq, ret, core; + int irq, ret; INIT_WORK(&v3d->overflow_mem_work, v3d_overflow_mem_work); - /* Clear any pending interrupts someone might have left around - * for us. - */ - for (core = 0; core < v3d->cores; core++) - V3D_CORE_WRITE(core, V3D_CTL_INT_CLR, V3D_CORE_IRQS(v3d->ver)); - V3D_WRITE(V3D_HUB_INT_CLR, V3D_HUB_IRQS(v3d->ver)); - irq = platform_get_irq_optional(v3d_to_pdev(v3d), 1); if (irq == -EPROBE_DEFER) return irq; @@ -296,7 +289,6 @@ v3d_irq_init(struct v3d_dev *v3d) goto fail; } - v3d_irq_enable(v3d); return 0; fail: @@ -310,6 +302,11 @@ v3d_irq_enable(struct v3d_dev *v3d) { int core; + /* Clear any pending interrupts someone might have left around for us. */ + for (core = 0; core < v3d->cores; core++) + V3D_CORE_WRITE(core, V3D_CTL_INT_CLR, V3D_CORE_IRQS(v3d->ver)); + V3D_WRITE(V3D_HUB_INT_CLR, V3D_HUB_IRQS(v3d->ver)); + /* Enable our set of interrupts, masking out any others. */ for (core = 0; core < v3d->cores; core++) { V3D_CORE_WRITE(core, V3D_CTL_INT_MSK_SET, ~V3D_CORE_IRQS(v3d->ver)); -- cgit v1.2.3 From 458f2a712ab42b7d3615208862922dc35fe90ef9 Mon Sep 17 00:00:00 2001 From: Maíra Canal Date: Tue, 31 Mar 2026 09:35:53 -0300 Subject: drm/v3d: Introduce Runtime Power Management MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Commit 90a64adb0876 ("drm/v3d: Get rid of pm code") removed the last bits of power management code that V3D had, which were actually never hooked. Therefore, currently, the GPU clock is enabled during probe and only disabled when removing the driver. Implement proper power management using the kernel's Runtime PM framework. Reviewed-by: Melissa Wen Reviewed-by: Florian Fainelli Link: https://patch.msgid.link/20260331-v3d-power-management-v9-3-f52ff87bfd36@igalia.com Signed-off-by: Maíra Canal --- drivers/gpu/drm/v3d/Makefile | 1 + drivers/gpu/drm/v3d/v3d_debugfs.c | 23 ++++++++++- drivers/gpu/drm/v3d/v3d_drv.c | 84 +++++++++++++++++-------------------- drivers/gpu/drm/v3d/v3d_drv.h | 17 ++++++++ drivers/gpu/drm/v3d/v3d_mmu.c | 10 ++++- drivers/gpu/drm/v3d/v3d_perfmon.c | 18 ++++++-- drivers/gpu/drm/v3d/v3d_power.c | 87 +++++++++++++++++++++++++++++++++++++++ drivers/gpu/drm/v3d/v3d_submit.c | 19 +++++++-- 8 files changed, 200 insertions(+), 59 deletions(-) create mode 100644 drivers/gpu/drm/v3d/v3d_power.c diff --git a/drivers/gpu/drm/v3d/Makefile b/drivers/gpu/drm/v3d/Makefile index b7d673f1153b..601b834e377e 100644 --- a/drivers/gpu/drm/v3d/Makefile +++ b/drivers/gpu/drm/v3d/Makefile @@ -10,6 +10,7 @@ v3d-y := \ v3d_irq.o \ v3d_mmu.o \ v3d_perfmon.o \ + v3d_power.o \ v3d_trace_points.o \ v3d_sched.o \ v3d_sysfs.o \ diff --git a/drivers/gpu/drm/v3d/v3d_debugfs.c b/drivers/gpu/drm/v3d/v3d_debugfs.c index 89f24eec62a7..634cc796ba23 100644 --- a/drivers/gpu/drm/v3d/v3d_debugfs.c +++ b/drivers/gpu/drm/v3d/v3d_debugfs.c @@ -97,7 +97,11 @@ static int v3d_v3d_debugfs_regs(struct seq_file *m, void *unused) struct drm_debugfs_entry *entry = m->private; struct drm_device *dev = entry->dev; struct v3d_dev *v3d = to_v3d_dev(dev); - int i, core; + int i, core, ret; + + ret = v3d_pm_runtime_get(v3d); + if (ret) + return ret; for (i = 0; i < ARRAY_SIZE(v3d_hub_reg_defs); i++) { const struct v3d_reg_def *def = &v3d_hub_reg_defs[i]; @@ -139,6 +143,8 @@ static int v3d_v3d_debugfs_regs(struct seq_file *m, void *unused) } } + v3d_pm_runtime_put(v3d); + return 0; } @@ -148,7 +154,11 @@ static int v3d_v3d_debugfs_ident(struct seq_file *m, void *unused) struct drm_device *dev = entry->dev; struct v3d_dev *v3d = to_v3d_dev(dev); u32 ident0, ident1, ident2, ident3, cores; - int core; + int core, ret; + + ret = v3d_pm_runtime_get(v3d); + if (ret) + return ret; ident0 = V3D_READ(V3D_HUB_IDENT0); ident1 = V3D_READ(V3D_HUB_IDENT1); @@ -207,6 +217,8 @@ static int v3d_v3d_debugfs_ident(struct seq_file *m, void *unused) } } + v3d_pm_runtime_put(v3d); + return 0; } @@ -234,6 +246,11 @@ static int v3d_measure_clock(struct seq_file *m, void *unused) uint32_t cycles; int core = 0; int measure_ms = 1000; + int ret; + + ret = v3d_pm_runtime_get(v3d); + if (ret) + return ret; if (v3d->ver >= V3D_GEN_41) { int cycle_count_reg = V3D_PCTR_CYCLE_COUNT(v3d->ver); @@ -253,6 +270,8 @@ static int v3d_measure_clock(struct seq_file *m, void *unused) msleep(measure_ms); cycles = V3D_CORE_READ(core, V3D_PCTR_0_PCTR0); + v3d_pm_runtime_put(v3d); + seq_printf(m, "cycles: %d (%d.%d Mhz)\n", cycles, cycles / (measure_ms * 1000), diff --git a/drivers/gpu/drm/v3d/v3d_drv.c b/drivers/gpu/drm/v3d/v3d_drv.c index e57b36f4d81a..fc81dd1247e3 100644 --- a/drivers/gpu/drm/v3d/v3d_drv.c +++ b/drivers/gpu/drm/v3d/v3d_drv.c @@ -59,6 +59,7 @@ static int v3d_get_param_ioctl(struct drm_device *dev, void *data, [DRM_V3D_PARAM_V3D_CORE0_IDENT1] = V3D_CTL_IDENT1, [DRM_V3D_PARAM_V3D_CORE0_IDENT2] = V3D_CTL_IDENT2, }; + int ret; if (args->pad != 0) return -EINVAL; @@ -75,12 +76,19 @@ static int v3d_get_param_ioctl(struct drm_device *dev, void *data, if (args->value != 0) return -EINVAL; + ret = v3d_pm_runtime_get(v3d); + if (ret) + return ret; + if (args->param >= DRM_V3D_PARAM_V3D_CORE0_IDENT0 && args->param <= DRM_V3D_PARAM_V3D_CORE0_IDENT2) { args->value = V3D_CORE_READ(0, offset); } else { args->value = V3D_READ(offset); } + + v3d_pm_runtime_put(v3d); + return 0; } @@ -290,36 +298,6 @@ static const struct of_device_id v3d_of_match[] = { }; MODULE_DEVICE_TABLE(of, v3d_of_match); -static void -v3d_idle_sms(struct v3d_dev *v3d) -{ - if (v3d->ver < V3D_GEN_71) - return; - - V3D_SMS_WRITE(V3D_SMS_TEE_CS, V3D_SMS_CLEAR_POWER_OFF); - - if (wait_for((V3D_GET_FIELD(V3D_SMS_READ(V3D_SMS_TEE_CS), - V3D_SMS_STATE) == V3D_SMS_IDLE), 100)) { - drm_err(&v3d->drm, "Failed to power up SMS\n"); - } - - v3d_reset_sms(v3d); -} - -static void -v3d_power_off_sms(struct v3d_dev *v3d) -{ - if (v3d->ver < V3D_GEN_71) - return; - - V3D_SMS_WRITE(V3D_SMS_TEE_CS, V3D_SMS_POWER_OFF); - - if (wait_for((V3D_GET_FIELD(V3D_SMS_READ(V3D_SMS_TEE_CS), - V3D_SMS_STATE) == V3D_SMS_POWER_OFF_STATE), 100)) { - drm_err(&v3d->drm, "Failed to power off SMS\n"); - } -} - static int map_regs(struct v3d_dev *v3d, void __iomem **regs, const char *name) { @@ -403,19 +381,26 @@ static int v3d_platform_drm_probe(struct platform_device *pdev) if (ret) goto dma_free; - ret = clk_prepare_enable(v3d->clk); - if (ret) { - dev_err(&pdev->dev, "Couldn't enable the V3D clock\n"); + ret = devm_pm_runtime_enable(dev); + if (ret) goto gem_destroy; - } - v3d_idle_sms(v3d); + ret = pm_runtime_resume_and_get(dev); + if (ret) + goto gem_destroy; + + /* If PM is disabled, we need to call v3d_power_resume() manually. */ + if (!IS_ENABLED(CONFIG_PM)) { + ret = v3d_power_resume(dev); + if (ret) + goto gem_destroy; + } mmu_debug = V3D_READ(V3D_MMU_DEBUG_INFO); mask = DMA_BIT_MASK(30 + V3D_GET_FIELD(mmu_debug, V3D_MMU_PA_WIDTH)); ret = dma_set_mask_and_coherent(dev, mask); if (ret) - goto clk_disable; + goto runtime_pm_put; dma_set_max_seg_size(&pdev->dev, UINT_MAX); @@ -435,27 +420,26 @@ static int v3d_platform_drm_probe(struct platform_device *pdev) ident3 = V3D_READ(V3D_HUB_IDENT3); v3d->rev = V3D_GET_FIELD(ident3, V3D_HUB_IDENT3_IPREV); - v3d_init_hw_state(v3d); - v3d_mmu_set_page_table(v3d); - v3d_irq_enable(v3d); + pm_runtime_set_autosuspend_delay(dev, 100); + pm_runtime_use_autosuspend(dev); ret = drm_dev_register(drm, 0); if (ret) - goto irq_disable; + goto runtime_pm_put; ret = v3d_sysfs_init(dev); if (ret) goto drm_unregister; + pm_runtime_mark_last_busy(dev); + pm_runtime_put_autosuspend(dev); + return 0; drm_unregister: drm_dev_unregister(drm); -irq_disable: - v3d_irq_disable(v3d); -clk_disable: - v3d_power_off_sms(v3d); - clk_disable_unprepare(v3d->clk); +runtime_pm_put: + pm_runtime_put_sync_suspend(dev); gem_destroy: v3d_gem_destroy(drm); dma_free: @@ -473,21 +457,27 @@ static void v3d_platform_drm_remove(struct platform_device *pdev) drm_dev_unregister(drm); - v3d_power_off_sms(v3d); + pm_runtime_suspend(dev); - clk_disable_unprepare(v3d->clk); + /* If PM is disabled, we need to call v3d_power_suspend() manually. */ + if (!IS_ENABLED(CONFIG_PM)) + v3d_power_suspend(dev); v3d_gem_destroy(drm); dma_free_wc(dev, 4096, v3d->mmu_scratch, v3d->mmu_scratch_paddr); } +static DEFINE_RUNTIME_DEV_PM_OPS(v3d_pm_ops, v3d_power_suspend, + v3d_power_resume, NULL); + static struct platform_driver v3d_platform_driver = { .probe = v3d_platform_drm_probe, .remove = v3d_platform_drm_remove, .driver = { .name = "v3d", .of_match_table = v3d_of_match, + .pm = pm_ptr(&v3d_pm_ops), }, }; diff --git a/drivers/gpu/drm/v3d/v3d_drv.h b/drivers/gpu/drm/v3d/v3d_drv.h index ebf406b615bb..4ebe175a8c6b 100644 --- a/drivers/gpu/drm/v3d/v3d_drv.h +++ b/drivers/gpu/drm/v3d/v3d_drv.h @@ -3,6 +3,7 @@ #include #include +#include #include #include @@ -324,6 +325,8 @@ struct v3d_job { /* Callback for the freeing of the job on refcount going to 0. */ void (*free)(struct kref *ref); + + bool has_pm_ref; }; struct v3d_bin_job { @@ -597,6 +600,20 @@ int v3d_mmu_set_page_table(struct v3d_dev *v3d); void v3d_mmu_insert_ptes(struct v3d_bo *bo); void v3d_mmu_remove_ptes(struct v3d_bo *bo); +/* v3d_power.c */ +int v3d_power_suspend(struct device *dev); +int v3d_power_resume(struct device *dev); + +static __always_inline int v3d_pm_runtime_get(struct v3d_dev *v3d) +{ + return pm_runtime_resume_and_get(v3d->drm.dev); +} + +static __always_inline int v3d_pm_runtime_put(struct v3d_dev *v3d) +{ + return pm_runtime_put_autosuspend(v3d->drm.dev); +} + /* v3d_sched.c */ void v3d_timestamp_query_info_free(struct v3d_timestamp_query_info *query_info, unsigned int count); diff --git a/drivers/gpu/drm/v3d/v3d_mmu.c b/drivers/gpu/drm/v3d/v3d_mmu.c index c513a393c031..630c64e51d2f 100644 --- a/drivers/gpu/drm/v3d/v3d_mmu.c +++ b/drivers/gpu/drm/v3d/v3d_mmu.c @@ -39,7 +39,11 @@ static bool v3d_mmu_is_aligned(u32 page, u32 page_address, size_t alignment) int v3d_mmu_flush_all(struct v3d_dev *v3d) { - int ret; + int ret = 0; + + /* Flush the PTs only if we're already awake */ + if (!pm_runtime_get_if_active(v3d->drm.dev)) + return 0; V3D_WRITE(V3D_MMUC_CONTROL, V3D_MMUC_CONTROL_FLUSH | V3D_MMUC_CONTROL_ENABLE); @@ -48,7 +52,7 @@ int v3d_mmu_flush_all(struct v3d_dev *v3d) V3D_MMUC_CONTROL_FLUSHING), 100); if (ret) { dev_err(v3d->drm.dev, "MMUC flush wait idle failed\n"); - return ret; + goto pm_put; } V3D_WRITE(V3D_MMU_CTL, V3D_READ(V3D_MMU_CTL) | @@ -59,6 +63,8 @@ int v3d_mmu_flush_all(struct v3d_dev *v3d) if (ret) dev_err(v3d->drm.dev, "MMU TLB clear wait idle failed\n"); +pm_put: + v3d_pm_runtime_put(v3d); return ret; } diff --git a/drivers/gpu/drm/v3d/v3d_perfmon.c b/drivers/gpu/drm/v3d/v3d_perfmon.c index 8e0249580bba..02451fc09dbb 100644 --- a/drivers/gpu/drm/v3d/v3d_perfmon.c +++ b/drivers/gpu/drm/v3d/v3d_perfmon.c @@ -232,6 +232,9 @@ void v3d_perfmon_start(struct v3d_dev *v3d, struct v3d_perfmon *perfmon) if (WARN_ON_ONCE(!perfmon || v3d->active_perfmon)) return; + if (!pm_runtime_get_if_active(v3d->drm.dev)) + return; + ncounters = perfmon->ncounters; mask = GENMASK(ncounters - 1, 0); @@ -257,6 +260,8 @@ void v3d_perfmon_start(struct v3d_dev *v3d, struct v3d_perfmon *perfmon) V3D_CORE_WRITE(0, V3D_PCTR_0_OVERFLOW, mask); v3d->active_perfmon = perfmon; + + v3d_pm_runtime_put(v3d); } void v3d_perfmon_stop(struct v3d_dev *v3d, struct v3d_perfmon *perfmon, @@ -268,10 +273,11 @@ void v3d_perfmon_stop(struct v3d_dev *v3d, struct v3d_perfmon *perfmon, return; mutex_lock(&perfmon->lock); - if (perfmon != v3d->active_perfmon) { - mutex_unlock(&perfmon->lock); - return; - } + if (perfmon != v3d->active_perfmon) + goto out; + + if (!pm_runtime_get_if_active(v3d->drm.dev)) + goto out_clear; if (capture) for (i = 0; i < perfmon->ncounters; i++) @@ -279,7 +285,11 @@ void v3d_perfmon_stop(struct v3d_dev *v3d, struct v3d_perfmon *perfmon, V3D_CORE_WRITE(0, V3D_V4_PCTR_0_EN, 0); + v3d_pm_runtime_put(v3d); + +out_clear: v3d->active_perfmon = NULL; +out: mutex_unlock(&perfmon->lock); } diff --git a/drivers/gpu/drm/v3d/v3d_power.c b/drivers/gpu/drm/v3d/v3d_power.c new file mode 100644 index 000000000000..769e90032b04 --- /dev/null +++ b/drivers/gpu/drm/v3d/v3d_power.c @@ -0,0 +1,87 @@ +// SPDX-License-Identifier: GPL-2.0+ +/* Copyright (C) 2026 Raspberry Pi */ + +#include + +#include + +#include "v3d_drv.h" +#include "v3d_regs.h" + +static int +v3d_resume_sms(struct v3d_dev *v3d) +{ + if (v3d->ver < V3D_GEN_71) + return 0; + + V3D_SMS_WRITE(V3D_SMS_TEE_CS, V3D_SMS_CLEAR_POWER_OFF); + + if (wait_for((V3D_GET_FIELD(V3D_SMS_READ(V3D_SMS_TEE_CS), + V3D_SMS_STATE) == V3D_SMS_IDLE), 100)) { + drm_err(&v3d->drm, "Failed to power up SMS\n"); + return -ETIMEDOUT; + } + + v3d_reset_sms(v3d); + + return 0; +} + +static int +v3d_suspend_sms(struct v3d_dev *v3d) +{ + if (v3d->ver < V3D_GEN_71) + return 0; + + V3D_SMS_WRITE(V3D_SMS_TEE_CS, V3D_SMS_POWER_OFF); + + if (wait_for((V3D_GET_FIELD(V3D_SMS_READ(V3D_SMS_TEE_CS), + V3D_SMS_STATE) == V3D_SMS_POWER_OFF_STATE), 100)) { + drm_err(&v3d->drm, "Failed to power off SMS\n"); + return -ETIMEDOUT; + } + + return 0; +} + +int v3d_power_suspend(struct device *dev) +{ + struct drm_device *drm = dev_get_drvdata(dev); + struct v3d_dev *v3d = to_v3d_dev(drm); + int ret; + + v3d_irq_disable(v3d); + + ret = v3d_suspend_sms(v3d); + if (ret) { + v3d_irq_enable(v3d); + return ret; + } + + clk_disable_unprepare(v3d->clk); + + return 0; +} + +int v3d_power_resume(struct device *dev) +{ + struct drm_device *drm = dev_get_drvdata(dev); + struct v3d_dev *v3d = to_v3d_dev(drm); + int ret; + + ret = clk_prepare_enable(v3d->clk); + if (ret) + return ret; + + ret = v3d_resume_sms(v3d); + if (ret) { + clk_disable_unprepare(v3d->clk); + return ret; + } + + v3d_init_hw_state(v3d); + v3d_mmu_set_page_table(v3d); + v3d_irq_enable(v3d); + + return 0; +} diff --git a/drivers/gpu/drm/v3d/v3d_submit.c b/drivers/gpu/drm/v3d/v3d_submit.c index 8f061b6a05c6..f75da2e3533e 100644 --- a/drivers/gpu/drm/v3d/v3d_submit.c +++ b/drivers/gpu/drm/v3d/v3d_submit.c @@ -106,6 +106,9 @@ v3d_job_free(struct kref *ref) v3d_stats_put(job->client_stats); v3d_stats_put(job->global_stats); + if (job->has_pm_ref) + v3d_pm_runtime_put(job->v3d); + kfree(job); } @@ -187,13 +190,13 @@ v3d_job_init(struct v3d_dev *v3d, struct drm_file *file_priv, if (copy_from_user(&in, handle++, sizeof(in))) { ret = -EFAULT; drm_dbg(&v3d->drm, "Failed to copy wait dep handle.\n"); - goto fail_deps; + goto fail_job_init; } ret = drm_sched_job_add_syncobj_dependency(&job->base, file_priv, in.handle, 0); // TODO: Investigate why this was filtered out for the IOCTL. if (ret && ret != -ENOENT) - goto fail_deps; + goto fail_job_init; } } } else { @@ -201,7 +204,15 @@ v3d_job_init(struct v3d_dev *v3d, struct drm_file *file_priv, // TODO: Investigate why this was filtered out for the IOCTL. if (ret && ret != -ENOENT) - goto fail_deps; + goto fail_job_init; + } + + /* CPU jobs don't require hardware resources */ + if (queue != V3D_CPU) { + ret = v3d_pm_runtime_get(v3d); + if (ret) + goto fail_job_init; + job->has_pm_ref = true; } kref_init(&job->refcount); @@ -211,7 +222,7 @@ v3d_job_init(struct v3d_dev *v3d, struct drm_file *file_priv, return 0; -fail_deps: +fail_job_init: drm_sched_job_cleanup(&job->base); return ret; } -- cgit v1.2.3 From dc2d30e7db8321a6696d266838f7af7e9d1c7155 Mon Sep 17 00:00:00 2001 From: Simon Ser Date: Fri, 27 Mar 2026 17:18:29 +0000 Subject: drm/doc: document DRM_IOCTL_SYNCOBJ_EVENTFD MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit struct drm_syncobj_eventfd was documented, but DRM_IOCTL_SYNCOBJ_EVENTFD was not. This prevents references to this define from being properly linkified in docs. Signed-off-by: Simon Ser Reviewed-by: Christian König Reviewed-by: Pekka Paalanen Cc: Simona Vetter Cc: Daniel Stone Cc: Michel Dänzer Link: https://patch.msgid.link/20260327171812.128290-1-contact@emersion.fr --- include/uapi/drm/drm.h | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/include/uapi/drm/drm.h b/include/uapi/drm/drm.h index 27cc159c1d27..495462e44a17 100644 --- a/include/uapi/drm/drm.h +++ b/include/uapi/drm/drm.h @@ -1323,6 +1323,13 @@ extern "C" { */ #define DRM_IOCTL_MODE_GETFB2 DRM_IOWR(0xCE, struct drm_mode_fb_cmd2) +/** + * DRM_IOCTL_SYNCOBJ_EVENTFD - Register an eventfd to be signalled by a syncobj. + * + * This can be used to integrate a syncobj in an event loop. + * + * The IOCTL argument is a struct drm_syncobj_eventfd. + */ #define DRM_IOCTL_SYNCOBJ_EVENTFD DRM_IOWR(0xCF, struct drm_syncobj_eventfd) /** -- cgit v1.2.3 From ec4f4970eb744fd7d6d135f40f5c83bd05982e72 Mon Sep 17 00:00:00 2001 From: Gustavo Sousa Date: Wed, 1 Apr 2026 19:10:51 -0300 Subject: drm/xe/xe3p_lpg: Add missing indirect ring state feature flag Even though commit 8fcb7dfb8bbf ("drm/xe/xe3p_lpg: Add support for graphics IP 35.10") mentions that the support for Indirect Ring State exists for Xe3p_LPG, it missed actually setting the feature flag in graphics_xe3p_lpg. Fix that by adding the missing member. Fixes: 8fcb7dfb8bbf ("drm/xe/xe3p_lpg: Add support for graphics IP 35.10") Reviewed-by: Matt Roper Link: https://patch.msgid.link/20260401-xe3p_lpg-indirect-ring-state-v1-1-0e4b5edf6898@intel.com Signed-off-by: Gustavo Sousa --- drivers/gpu/drm/xe/xe_pci.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/gpu/drm/xe/xe_pci.c b/drivers/gpu/drm/xe/xe_pci.c index 26eb58e11056..b1b89d09e42b 100644 --- a/drivers/gpu/drm/xe/xe_pci.c +++ b/drivers/gpu/drm/xe/xe_pci.c @@ -118,6 +118,7 @@ static const struct xe_graphics_desc graphics_xe2 = { static const struct xe_graphics_desc graphics_xe3p_lpg = { XE2_GFX_FEATURES, + .has_indirect_ring_state = 1, .multi_queue_engine_class_mask = BIT(XE_ENGINE_CLASS_COPY) | BIT(XE_ENGINE_CLASS_COMPUTE), .num_geometry_xecore_fuse_regs = 3, .num_compute_xecore_fuse_regs = 3, -- cgit v1.2.3 From e7ac8ddfefa3729e858ac9c5a0c9af3a53d4c699 Mon Sep 17 00:00:00 2001 From: Shuicheng Lin Date: Tue, 17 Mar 2026 21:57:17 +0000 Subject: drm/xe: Add missing include guards to unprotected headers Two headers lack include guards entirely, which can cause duplicate definition errors if they are included more than once (directly or transitively). Add standard _XE__H_ include guards to: - xe_dep_scheduler.h: forward declarations and function prototypes - xe_pcode_api.h: PCODE mailbox register definitions No functional change. Suggested-by: Nitin Gote Assisted-by: GitHub Copilot:claude-opus-4.6 Reviewed-by: Nitin Gote Link: https://patch.msgid.link/20260317215732.2208976-8-shuicheng.lin@intel.com Signed-off-by: Shuicheng Lin --- drivers/gpu/drm/xe/xe_dep_scheduler.h | 5 +++++ drivers/gpu/drm/xe/xe_pcode_api.h | 5 +++++ 2 files changed, 10 insertions(+) diff --git a/drivers/gpu/drm/xe/xe_dep_scheduler.h b/drivers/gpu/drm/xe/xe_dep_scheduler.h index 853961eec64b..f314fb5d80f5 100644 --- a/drivers/gpu/drm/xe/xe_dep_scheduler.h +++ b/drivers/gpu/drm/xe/xe_dep_scheduler.h @@ -3,6 +3,9 @@ * Copyright © 2025 Intel Corporation */ +#ifndef _XE_DEP_SCHEDULER_H_ +#define _XE_DEP_SCHEDULER_H_ + #include struct drm_sched_entity; @@ -19,3 +22,5 @@ void xe_dep_scheduler_fini(struct xe_dep_scheduler *dep_scheduler); struct drm_sched_entity * xe_dep_scheduler_entity(struct xe_dep_scheduler *dep_scheduler); + +#endif diff --git a/drivers/gpu/drm/xe/xe_pcode_api.h b/drivers/gpu/drm/xe/xe_pcode_api.h index 85cc7478b787..b619030b9e17 100644 --- a/drivers/gpu/drm/xe/xe_pcode_api.h +++ b/drivers/gpu/drm/xe/xe_pcode_api.h @@ -3,6 +3,9 @@ * Copyright © 2022 Intel Corporation */ +#ifndef _XE_PCODE_API_H_ +#define _XE_PCODE_API_H_ + /* Internal to xe_pcode */ #include "regs/xe_reg_defs.h" @@ -101,3 +104,5 @@ #define BMG_PCIE_CAP XE_REG(0x138340) #define LINK_DOWNGRADE REG_GENMASK(1, 0) #define DOWNGRADE_CAPABLE 2 + +#endif -- cgit v1.2.3 From d45c7454ee32ca91c9e00427ae08ac221765c7b5 Mon Sep 17 00:00:00 2001 From: Shuicheng Lin Date: Tue, 17 Mar 2026 21:57:18 +0000 Subject: drm/xe: Add missing _H to include guard suffixes Ten headers use _XE__ or __XE___ as their include guard but omit the _H that the rest of the xe codebase uses. Normalize them to _XE__H_ to follow the dominant convention (_XE__H_) used by ~232 of ~260 xe headers. Files fixed: - xe_migrate.h: _XE_MIGRATE_ -> _XE_MIGRATE_H_ - xe_pt_walk.h: __XE_PT_WALK__ -> _XE_PT_WALK_H_ - xe_reg_sr.h: _XE_REG_SR_ -> _XE_REG_SR_H_ - xe_reg_sr_types.h: _XE_REG_SR_TYPES_ -> _XE_REG_SR_TYPES_H_ - xe_reg_whitelist.h: _XE_REG_WHITELIST_ -> _XE_REG_WHITELIST_H_ - xe_rtp.h: _XE_RTP_ -> _XE_RTP_H_ - xe_rtp_helpers.h: _XE_RTP_HELPERS_ -> _XE_RTP_HELPERS_H_ - xe_rtp_types.h: _XE_RTP_TYPES_ -> _XE_RTP_TYPES_H_ - xe_tuning.h: _XE_TUNING_ -> _XE_TUNING_H_ - xe_wa.h: _XE_WA_ -> _XE_WA_H_ No functional change. Suggested-by: Nitin Gote Assisted-by: GitHub Copilot:claude-opus-4.6 Reviewed-by: Nitin Gote Link: https://patch.msgid.link/20260317215732.2208976-9-shuicheng.lin@intel.com Signed-off-by: Shuicheng Lin --- drivers/gpu/drm/xe/xe_migrate.h | 4 ++-- drivers/gpu/drm/xe/xe_pt_walk.h | 4 ++-- drivers/gpu/drm/xe/xe_reg_sr.h | 4 ++-- drivers/gpu/drm/xe/xe_reg_sr_types.h | 4 ++-- drivers/gpu/drm/xe/xe_reg_whitelist.h | 4 ++-- drivers/gpu/drm/xe/xe_rtp.h | 4 ++-- drivers/gpu/drm/xe/xe_rtp_helpers.h | 4 ++-- drivers/gpu/drm/xe/xe_rtp_types.h | 4 ++-- drivers/gpu/drm/xe/xe_tuning.h | 4 ++-- drivers/gpu/drm/xe/xe_wa.h | 4 ++-- 10 files changed, 20 insertions(+), 20 deletions(-) diff --git a/drivers/gpu/drm/xe/xe_migrate.h b/drivers/gpu/drm/xe/xe_migrate.h index 169279d9d8c2..965c45889c72 100644 --- a/drivers/gpu/drm/xe/xe_migrate.h +++ b/drivers/gpu/drm/xe/xe_migrate.h @@ -3,8 +3,8 @@ * Copyright © 2020 Intel Corporation */ -#ifndef _XE_MIGRATE_ -#define _XE_MIGRATE_ +#ifndef _XE_MIGRATE_H_ +#define _XE_MIGRATE_H_ #include diff --git a/drivers/gpu/drm/xe/xe_pt_walk.h b/drivers/gpu/drm/xe/xe_pt_walk.h index 5c02c244f7de..07c8f409f236 100644 --- a/drivers/gpu/drm/xe/xe_pt_walk.h +++ b/drivers/gpu/drm/xe/xe_pt_walk.h @@ -2,8 +2,8 @@ /* * Copyright © 2022 Intel Corporation */ -#ifndef __XE_PT_WALK__ -#define __XE_PT_WALK__ +#ifndef _XE_PT_WALK_H_ +#define _XE_PT_WALK_H_ #include #include diff --git a/drivers/gpu/drm/xe/xe_reg_sr.h b/drivers/gpu/drm/xe/xe_reg_sr.h index 1ec6e8ecf278..d26cf4713383 100644 --- a/drivers/gpu/drm/xe/xe_reg_sr.h +++ b/drivers/gpu/drm/xe/xe_reg_sr.h @@ -3,8 +3,8 @@ * Copyright © 2022 Intel Corporation */ -#ifndef _XE_REG_SR_ -#define _XE_REG_SR_ +#ifndef _XE_REG_SR_H_ +#define _XE_REG_SR_H_ /* * Reg save/restore bookkeeping diff --git a/drivers/gpu/drm/xe/xe_reg_sr_types.h b/drivers/gpu/drm/xe/xe_reg_sr_types.h index ebe11f237fa2..0a6695db2967 100644 --- a/drivers/gpu/drm/xe/xe_reg_sr_types.h +++ b/drivers/gpu/drm/xe/xe_reg_sr_types.h @@ -3,8 +3,8 @@ * Copyright © 2022 Intel Corporation */ -#ifndef _XE_REG_SR_TYPES_ -#define _XE_REG_SR_TYPES_ +#ifndef _XE_REG_SR_TYPES_H_ +#define _XE_REG_SR_TYPES_H_ #include #include diff --git a/drivers/gpu/drm/xe/xe_reg_whitelist.h b/drivers/gpu/drm/xe/xe_reg_whitelist.h index 69b121d377da..3b64b42fe96e 100644 --- a/drivers/gpu/drm/xe/xe_reg_whitelist.h +++ b/drivers/gpu/drm/xe/xe_reg_whitelist.h @@ -3,8 +3,8 @@ * Copyright © 2023 Intel Corporation */ -#ifndef _XE_REG_WHITELIST_ -#define _XE_REG_WHITELIST_ +#ifndef _XE_REG_WHITELIST_H_ +#define _XE_REG_WHITELIST_H_ #include diff --git a/drivers/gpu/drm/xe/xe_rtp.h b/drivers/gpu/drm/xe/xe_rtp.h index 7d6daa7eb1e4..4537ff46a17f 100644 --- a/drivers/gpu/drm/xe/xe_rtp.h +++ b/drivers/gpu/drm/xe/xe_rtp.h @@ -3,8 +3,8 @@ * Copyright © 2022 Intel Corporation */ -#ifndef _XE_RTP_ -#define _XE_RTP_ +#ifndef _XE_RTP_H_ +#define _XE_RTP_H_ #include #include diff --git a/drivers/gpu/drm/xe/xe_rtp_helpers.h b/drivers/gpu/drm/xe/xe_rtp_helpers.h index 86eee60c04a1..ffa8b2f8828d 100644 --- a/drivers/gpu/drm/xe/xe_rtp_helpers.h +++ b/drivers/gpu/drm/xe/xe_rtp_helpers.h @@ -3,8 +3,8 @@ * Copyright © 2023 Intel Corporation */ -#ifndef _XE_RTP_HELPERS_ -#define _XE_RTP_HELPERS_ +#ifndef _XE_RTP_HELPERS_H_ +#define _XE_RTP_HELPERS_H_ #ifndef _XE_RTP_INCLUDE_PRIVATE_HELPERS #error "This header is supposed to be included by xe_rtp.h only" diff --git a/drivers/gpu/drm/xe/xe_rtp_types.h b/drivers/gpu/drm/xe/xe_rtp_types.h index 166251615be1..0265c16d2762 100644 --- a/drivers/gpu/drm/xe/xe_rtp_types.h +++ b/drivers/gpu/drm/xe/xe_rtp_types.h @@ -3,8 +3,8 @@ * Copyright © 2022 Intel Corporation */ -#ifndef _XE_RTP_TYPES_ -#define _XE_RTP_TYPES_ +#ifndef _XE_RTP_TYPES_H_ +#define _XE_RTP_TYPES_H_ #include diff --git a/drivers/gpu/drm/xe/xe_tuning.h b/drivers/gpu/drm/xe/xe_tuning.h index c1cc5927fda7..d18e187debf6 100644 --- a/drivers/gpu/drm/xe/xe_tuning.h +++ b/drivers/gpu/drm/xe/xe_tuning.h @@ -3,8 +3,8 @@ * Copyright © 2022 Intel Corporation */ -#ifndef _XE_TUNING_ -#define _XE_TUNING_ +#ifndef _XE_TUNING_H_ +#define _XE_TUNING_H_ struct drm_printer; struct xe_gt; diff --git a/drivers/gpu/drm/xe/xe_wa.h b/drivers/gpu/drm/xe/xe_wa.h index 8fd6a5af0910..a5f7d33c1b32 100644 --- a/drivers/gpu/drm/xe/xe_wa.h +++ b/drivers/gpu/drm/xe/xe_wa.h @@ -3,8 +3,8 @@ * Copyright © 2022 Intel Corporation */ -#ifndef _XE_WA_ -#define _XE_WA_ +#ifndef _XE_WA_H_ +#define _XE_WA_H_ #include "xe_assert.h" -- cgit v1.2.3 From b85ff232d25128f7cea47021f419f5aa13101609 Mon Sep 17 00:00:00 2001 From: Shuicheng Lin Date: Tue, 17 Mar 2026 21:57:19 +0000 Subject: drm/xe: Add missing trailing underscore to include guards Four headers use _XE__H (no trailing underscore) as their include guard. Normalize them to _XE__H_ to match the dominant convention used across the xe codebase. Files fixed: - xe_guc_capture.h: _XE_GUC_CAPTURE_H -> _XE_GUC_CAPTURE_H_ - xe_guc_capture_types.h: _XE_GUC_CAPTURE_TYPES_H -> _XE_GUC_CAPTURE_TYPES_H_ - xe_guc_fwif.h: _XE_GUC_FWIF_H -> _XE_GUC_FWIF_H_ - xe_uc_fw_abi.h: _XE_UC_FW_ABI_H -> _XE_UC_FW_ABI_H_ No functional change. Suggested-by: Nitin Gote Assisted-by: GitHub Copilot:claude-opus-4.6 Reviewed-by: Nitin Gote Link: https://patch.msgid.link/20260317215732.2208976-10-shuicheng.lin@intel.com Signed-off-by: Shuicheng Lin --- drivers/gpu/drm/xe/xe_guc_capture.h | 4 ++-- drivers/gpu/drm/xe/xe_guc_capture_types.h | 4 ++-- drivers/gpu/drm/xe/xe_guc_fwif.h | 4 ++-- drivers/gpu/drm/xe/xe_uc_fw_abi.h | 4 ++-- 4 files changed, 8 insertions(+), 8 deletions(-) diff --git a/drivers/gpu/drm/xe/xe_guc_capture.h b/drivers/gpu/drm/xe/xe_guc_capture.h index 34d6fdc64f56..dca97d52b192 100644 --- a/drivers/gpu/drm/xe/xe_guc_capture.h +++ b/drivers/gpu/drm/xe/xe_guc_capture.h @@ -3,8 +3,8 @@ * Copyright © 2021-2024 Intel Corporation */ -#ifndef _XE_GUC_CAPTURE_H -#define _XE_GUC_CAPTURE_H +#ifndef _XE_GUC_CAPTURE_H_ +#define _XE_GUC_CAPTURE_H_ #include #include "abi/guc_capture_abi.h" diff --git a/drivers/gpu/drm/xe/xe_guc_capture_types.h b/drivers/gpu/drm/xe/xe_guc_capture_types.h index 6cb439115597..af7e21777b06 100644 --- a/drivers/gpu/drm/xe/xe_guc_capture_types.h +++ b/drivers/gpu/drm/xe/xe_guc_capture_types.h @@ -3,8 +3,8 @@ * Copyright © 2021-2024 Intel Corporation */ -#ifndef _XE_GUC_CAPTURE_TYPES_H -#define _XE_GUC_CAPTURE_TYPES_H +#ifndef _XE_GUC_CAPTURE_TYPES_H_ +#define _XE_GUC_CAPTURE_TYPES_H_ #include #include "regs/xe_reg_defs.h" diff --git a/drivers/gpu/drm/xe/xe_guc_fwif.h b/drivers/gpu/drm/xe/xe_guc_fwif.h index b73fae063fac..3fbda4798cff 100644 --- a/drivers/gpu/drm/xe/xe_guc_fwif.h +++ b/drivers/gpu/drm/xe/xe_guc_fwif.h @@ -3,8 +3,8 @@ * Copyright © 2022 Intel Corporation */ -#ifndef _XE_GUC_FWIF_H -#define _XE_GUC_FWIF_H +#ifndef _XE_GUC_FWIF_H_ +#define _XE_GUC_FWIF_H_ #include diff --git a/drivers/gpu/drm/xe/xe_uc_fw_abi.h b/drivers/gpu/drm/xe/xe_uc_fw_abi.h index 3c9a63d13032..74b888904fdc 100644 --- a/drivers/gpu/drm/xe/xe_uc_fw_abi.h +++ b/drivers/gpu/drm/xe/xe_uc_fw_abi.h @@ -3,8 +3,8 @@ * Copyright © 2022 Intel Corporation */ -#ifndef _XE_UC_FW_ABI_H -#define _XE_UC_FW_ABI_H +#ifndef _XE_UC_FW_ABI_H_ +#define _XE_UC_FW_ABI_H_ #include #include -- cgit v1.2.3 From 57aad39219d334c4b505aa37dad658005f8a58ec Mon Sep 17 00:00:00 2001 From: Shuicheng Lin Date: Tue, 17 Mar 2026 21:57:20 +0000 Subject: drm/xe: Add missing leading underscore to include guards Two headers use XE__H_ (no leading underscore) as their include guard. Normalize them to _XE__H_ to match the convention used across the xe codebase. Files fixed: - xe_drm_ras.h: XE_DRM_RAS_H_ -> _XE_DRM_RAS_H_ - xe_hw_error.h: XE_HW_ERROR_H_ -> _XE_HW_ERROR_H_ No functional change. Suggested-by: Nitin Gote Assisted-by: GitHub Copilot:claude-opus-4.6 Reviewed-by: Nitin Gote Link: https://patch.msgid.link/20260317215732.2208976-11-shuicheng.lin@intel.com Signed-off-by: Shuicheng Lin --- drivers/gpu/drm/xe/xe_drm_ras.h | 4 ++-- drivers/gpu/drm/xe/xe_hw_error.h | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/drivers/gpu/drm/xe/xe_drm_ras.h b/drivers/gpu/drm/xe/xe_drm_ras.h index 5cc8f0124411..365c70e93e82 100644 --- a/drivers/gpu/drm/xe/xe_drm_ras.h +++ b/drivers/gpu/drm/xe/xe_drm_ras.h @@ -2,8 +2,8 @@ /* * Copyright © 2026 Intel Corporation */ -#ifndef XE_DRM_RAS_H_ -#define XE_DRM_RAS_H_ +#ifndef _XE_DRM_RAS_H_ +#define _XE_DRM_RAS_H_ struct xe_device; diff --git a/drivers/gpu/drm/xe/xe_hw_error.h b/drivers/gpu/drm/xe/xe_hw_error.h index d86e28c5180c..5e3a11424108 100644 --- a/drivers/gpu/drm/xe/xe_hw_error.h +++ b/drivers/gpu/drm/xe/xe_hw_error.h @@ -2,8 +2,8 @@ /* * Copyright © 2025 Intel Corporation */ -#ifndef XE_HW_ERROR_H_ -#define XE_HW_ERROR_H_ +#ifndef _XE_HW_ERROR_H_ +#define _XE_HW_ERROR_H_ #include -- cgit v1.2.3 From 62ef3e610b347b743042c9ab3b942b4be7aab501 Mon Sep 17 00:00:00 2001 From: Shuicheng Lin Date: Tue, 17 Mar 2026 21:57:21 +0000 Subject: drm/xe: Normalize double-underscore include guards to single-underscore Six headers use __XE__H__ (double-underscore prefix and suffix) as their include guards. Normalize them to the single-underscore _XE__H_ convention used by the rest of the xe codebase. Files fixed: - xe_eu_stall.h: __XE_EU_STALL_H__ -> _XE_EU_STALL_H_ - xe_nvm.h: __XE_NVM_H__ -> _XE_NVM_H_ - xe_pxp.h: __XE_PXP_H__ -> _XE_PXP_H_ - xe_pxp_debugfs.h: __XE_PXP_DEBUGFS_H__ -> _XE_PXP_DEBUGFS_H_ - xe_pxp_submit.h: __XE_PXP_SUBMIT_H__ -> _XE_PXP_SUBMIT_H_ - xe_pxp_types.h: __XE_PXP_TYPES_H__ -> _XE_PXP_TYPES_H_ No functional change. Suggested-by: Nitin Gote Assisted-by: GitHub Copilot:claude-opus-4.6 Reviewed-by: Nitin Gote Link: https://patch.msgid.link/20260317215732.2208976-12-shuicheng.lin@intel.com Signed-off-by: Shuicheng Lin --- drivers/gpu/drm/xe/xe_eu_stall.h | 4 ++-- drivers/gpu/drm/xe/xe_nvm.h | 4 ++-- drivers/gpu/drm/xe/xe_pxp.h | 6 +++--- drivers/gpu/drm/xe/xe_pxp_debugfs.h | 6 +++--- drivers/gpu/drm/xe/xe_pxp_submit.h | 6 +++--- drivers/gpu/drm/xe/xe_pxp_types.h | 6 +++--- 6 files changed, 16 insertions(+), 16 deletions(-) diff --git a/drivers/gpu/drm/xe/xe_eu_stall.h b/drivers/gpu/drm/xe/xe_eu_stall.h index d1c76e503799..842bef9f6872 100644 --- a/drivers/gpu/drm/xe/xe_eu_stall.h +++ b/drivers/gpu/drm/xe/xe_eu_stall.h @@ -3,8 +3,8 @@ * Copyright © 2025 Intel Corporation */ -#ifndef __XE_EU_STALL_H__ -#define __XE_EU_STALL_H__ +#ifndef _XE_EU_STALL_H_ +#define _XE_EU_STALL_H_ #include "xe_gt_types.h" #include "xe_sriov.h" diff --git a/drivers/gpu/drm/xe/xe_nvm.h b/drivers/gpu/drm/xe/xe_nvm.h index fd3467ad35a4..b14722103f81 100644 --- a/drivers/gpu/drm/xe/xe_nvm.h +++ b/drivers/gpu/drm/xe/xe_nvm.h @@ -3,8 +3,8 @@ * Copyright(c) 2019-2025 Intel Corporation. All rights reserved. */ -#ifndef __XE_NVM_H__ -#define __XE_NVM_H__ +#ifndef _XE_NVM_H_ +#define _XE_NVM_H_ struct xe_device; diff --git a/drivers/gpu/drm/xe/xe_pxp.h b/drivers/gpu/drm/xe/xe_pxp.h index 71a23280b900..4fb6e0afffd2 100644 --- a/drivers/gpu/drm/xe/xe_pxp.h +++ b/drivers/gpu/drm/xe/xe_pxp.h @@ -3,8 +3,8 @@ * Copyright(c) 2024, Intel Corporation. All rights reserved. */ -#ifndef __XE_PXP_H__ -#define __XE_PXP_H__ +#ifndef _XE_PXP_H_ +#define _XE_PXP_H_ #include @@ -32,4 +32,4 @@ int xe_pxp_key_assign(struct xe_pxp *pxp, struct xe_bo *bo); int xe_pxp_bo_key_check(struct xe_pxp *pxp, struct xe_bo *bo); int xe_pxp_obj_key_check(struct drm_gem_object *obj); -#endif /* __XE_PXP_H__ */ +#endif /* _XE_PXP_H_ */ diff --git a/drivers/gpu/drm/xe/xe_pxp_debugfs.h b/drivers/gpu/drm/xe/xe_pxp_debugfs.h index 988466aad50b..2997de0c90b2 100644 --- a/drivers/gpu/drm/xe/xe_pxp_debugfs.h +++ b/drivers/gpu/drm/xe/xe_pxp_debugfs.h @@ -3,11 +3,11 @@ * Copyright © 2024 Intel Corporation */ -#ifndef __XE_PXP_DEBUGFS_H__ -#define __XE_PXP_DEBUGFS_H__ +#ifndef _XE_PXP_DEBUGFS_H_ +#define _XE_PXP_DEBUGFS_H_ struct xe_pxp; void xe_pxp_debugfs_register(struct xe_pxp *pxp); -#endif /* __XE_PXP_DEBUGFS_H__ */ +#endif /* _XE_PXP_DEBUGFS_H_ */ diff --git a/drivers/gpu/drm/xe/xe_pxp_submit.h b/drivers/gpu/drm/xe/xe_pxp_submit.h index c9efda02f4b0..dbbbe6b92bb2 100644 --- a/drivers/gpu/drm/xe/xe_pxp_submit.h +++ b/drivers/gpu/drm/xe/xe_pxp_submit.h @@ -3,8 +3,8 @@ * Copyright(c) 2024, Intel Corporation. All rights reserved. */ -#ifndef __XE_PXP_SUBMIT_H__ -#define __XE_PXP_SUBMIT_H__ +#ifndef _XE_PXP_SUBMIT_H_ +#define _XE_PXP_SUBMIT_H_ #include @@ -19,4 +19,4 @@ int xe_pxp_submit_session_termination(struct xe_pxp *pxp, u32 id); int xe_pxp_submit_session_invalidation(struct xe_pxp_gsc_client_resources *gsc_res, u32 id); -#endif /* __XE_PXP_SUBMIT_H__ */ +#endif /* _XE_PXP_SUBMIT_H_ */ diff --git a/drivers/gpu/drm/xe/xe_pxp_types.h b/drivers/gpu/drm/xe/xe_pxp_types.h index 53e9d48d10fb..ec86306e16f4 100644 --- a/drivers/gpu/drm/xe/xe_pxp_types.h +++ b/drivers/gpu/drm/xe/xe_pxp_types.h @@ -3,8 +3,8 @@ * Copyright(c) 2024, Intel Corporation. All rights reserved. */ -#ifndef __XE_PXP_TYPES_H__ -#define __XE_PXP_TYPES_H__ +#ifndef _XE_PXP_TYPES_H_ +#define _XE_PXP_TYPES_H_ #include #include @@ -132,4 +132,4 @@ struct xe_pxp { u32 last_suspend_key_instance; }; -#endif /* __XE_PXP_TYPES_H__ */ +#endif /* _XE_PXP_TYPES_H_ */ -- cgit v1.2.3 From 3d353d6c535319894c3e1b9349cae0531159f087 Mon Sep 17 00:00:00 2001 From: Animesh Manna Date: Mon, 30 Mar 2026 19:06:18 +0530 Subject: drm/display: Add drm helper to check pr optimization support MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Add api to check panel replay optimization supported or not to drm-core DP tunneling framework which can be used by other driver as well. v2: Split generic drm changes from Intel specific changes. [Jouni] Reviewed-by: Jouni Högander Suggested-by: Imre Deak Signed-off-by: Animesh Manna Acked-by: Maarten Lankhorst Link: https://patch.msgid.link/20260330133620.3750559-2-animesh.manna@intel.com --- drivers/gpu/drm/display/drm_dp_tunnel.c | 17 +++++++++++++++++ include/drm/display/drm_dp_tunnel.h | 6 ++++++ 2 files changed, 23 insertions(+) diff --git a/drivers/gpu/drm/display/drm_dp_tunnel.c b/drivers/gpu/drm/display/drm_dp_tunnel.c index 6519b4244728..08dc5d26b2c5 100644 --- a/drivers/gpu/drm/display/drm_dp_tunnel.c +++ b/drivers/gpu/drm/display/drm_dp_tunnel.c @@ -149,6 +149,7 @@ struct drm_dp_tunnel { bool bw_alloc_enabled:1; bool has_io_error:1; bool destroyed:1; + bool pr_optimization_support:1; }; struct drm_dp_tunnel_group_state; @@ -508,6 +509,8 @@ create_tunnel(struct drm_dp_tunnel_mgr *mgr, tunnel->bw_alloc_supported = tunnel_reg_bw_alloc_supported(regs); tunnel->bw_alloc_enabled = tunnel_reg_bw_alloc_enabled(regs); + tunnel->pr_optimization_support = tunnel_reg(regs, DP_TUNNELING_CAPABILITIES) & + DP_PANEL_REPLAY_OPTIMIZATION_SUPPORT; if (!add_tunnel_to_group(mgr, drv_group_id, tunnel)) { kfree(tunnel); @@ -1036,6 +1039,20 @@ bool drm_dp_tunnel_bw_alloc_is_enabled(const struct drm_dp_tunnel *tunnel) } EXPORT_SYMBOL(drm_dp_tunnel_bw_alloc_is_enabled); +/** + * drm_dp_tunnel_pr_optimization_supported - Query the PR BW optimization support + * @tunnel: Tunnel object + * + * Query if the PR BW optimization is supported for @tunnel. + * + * Returns %true if the PR BW optimiation is supported for @tunnel. + */ +bool drm_dp_tunnel_pr_optimization_supported(const struct drm_dp_tunnel *tunnel) +{ + return tunnel && tunnel->pr_optimization_support; +} +EXPORT_SYMBOL(drm_dp_tunnel_pr_optimization_supported); + static int clear_bw_req_state(struct drm_dp_aux *aux) { u8 bw_req_mask = DP_BW_REQUEST_SUCCEEDED | DP_BW_REQUEST_FAILED; diff --git a/include/drm/display/drm_dp_tunnel.h b/include/drm/display/drm_dp_tunnel.h index 87212c847915..4aa3ce9fd829 100644 --- a/include/drm/display/drm_dp_tunnel.h +++ b/include/drm/display/drm_dp_tunnel.h @@ -53,6 +53,7 @@ int drm_dp_tunnel_destroy(struct drm_dp_tunnel *tunnel); int drm_dp_tunnel_enable_bw_alloc(struct drm_dp_tunnel *tunnel); int drm_dp_tunnel_disable_bw_alloc(struct drm_dp_tunnel *tunnel); bool drm_dp_tunnel_bw_alloc_is_enabled(const struct drm_dp_tunnel *tunnel); +bool drm_dp_tunnel_pr_optimization_supported(const struct drm_dp_tunnel *tunnel); int drm_dp_tunnel_alloc_bw(struct drm_dp_tunnel *tunnel, int bw); int drm_dp_tunnel_get_allocated_bw(struct drm_dp_tunnel *tunnel); int drm_dp_tunnel_update_state(struct drm_dp_tunnel *tunnel); @@ -140,6 +141,11 @@ static inline bool drm_dp_tunnel_bw_alloc_is_enabled(const struct drm_dp_tunnel return false; } +static inline bool drm_dp_tunnel_pr_optimization_supported(const struct drm_dp_tunnel *tunnel) +{ + return false; +} + static inline int drm_dp_tunnel_alloc_bw(struct drm_dp_tunnel *tunnel, int bw) { -- cgit v1.2.3 From aa46f5470cb1c62740dc8e7125b8ae53d151066f Mon Sep 17 00:00:00 2001 From: Animesh Manna Date: Mon, 30 Mar 2026 19:06:19 +0530 Subject: drm/i915/display: Add hook to check optimization support for Intel platforms MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Add a hook that uses the drm core tunneling function to check whether panel replay bandwidth optimization support is present. v2: Move DISPLAY_VER() check to intel_dp_tunnel_pr_optimization_supported(). [Jouni] Reviewed-by: Jouni Högander Signed-off-by: Animesh Manna Link: https://patch.msgid.link/20260330133620.3750559-3-animesh.manna@intel.com --- drivers/gpu/drm/i915/display/intel_dp_tunnel.c | 18 ++++++++++++++++++ drivers/gpu/drm/i915/display/intel_dp_tunnel.h | 6 ++++++ 2 files changed, 24 insertions(+) diff --git a/drivers/gpu/drm/i915/display/intel_dp_tunnel.c b/drivers/gpu/drm/i915/display/intel_dp_tunnel.c index 7363c9817297..11712a151f72 100644 --- a/drivers/gpu/drm/i915/display/intel_dp_tunnel.c +++ b/drivers/gpu/drm/i915/display/intel_dp_tunnel.c @@ -296,6 +296,24 @@ bool intel_dp_tunnel_bw_alloc_is_enabled(struct intel_dp *intel_dp) return drm_dp_tunnel_bw_alloc_is_enabled(intel_dp->tunnel); } +/** + * intel_dp_tunnel_pr_optimization_supported - Query the PR BW optimization support + * @intel_dp: DP port object + * + * Query whether a DP tunnel supports the PR BW optimization. + * + * Returns %true if the BW allocation mode is supported on @intel_dp. + */ +bool intel_dp_tunnel_pr_optimization_supported(struct intel_dp *intel_dp) +{ + struct intel_display *display = to_intel_display(intel_dp); + + if (DISPLAY_VER(display) < 35) + return false; + + return drm_dp_tunnel_pr_optimization_supported(intel_dp->tunnel); +} + /** * intel_dp_tunnel_suspend - Suspend a DP tunnel connected on a port * @intel_dp: DP port object diff --git a/drivers/gpu/drm/i915/display/intel_dp_tunnel.h b/drivers/gpu/drm/i915/display/intel_dp_tunnel.h index 10ab9eebcef6..8273e681a512 100644 --- a/drivers/gpu/drm/i915/display/intel_dp_tunnel.h +++ b/drivers/gpu/drm/i915/display/intel_dp_tunnel.h @@ -32,6 +32,7 @@ void intel_dp_tunnel_resume(struct intel_dp *intel_dp, void intel_dp_tunnel_suspend(struct intel_dp *intel_dp); bool intel_dp_tunnel_bw_alloc_is_enabled(struct intel_dp *intel_dp); +bool intel_dp_tunnel_pr_optimization_supported(struct intel_dp *intel_dp); void intel_dp_tunnel_atomic_cleanup_inherited_state(struct intel_atomic_state *state); @@ -76,6 +77,11 @@ static inline bool intel_dp_tunnel_bw_alloc_is_enabled(struct intel_dp *intel_dp return false; } +static inline bool intel_dp_tunnel_pr_optimization_supported(struct intel_dp *intel_dp) +{ + return false; +} + static inline void intel_dp_tunnel_atomic_cleanup_inherited_state(struct intel_atomic_state *state) {} -- cgit v1.2.3 From ff1b43b7db95650976f9568bb0d62e59ec66e605 Mon Sep 17 00:00:00 2001 From: Animesh Manna Date: Mon, 30 Mar 2026 19:06:20 +0530 Subject: drm/i915/display: Panel Replay BW optimization for DP2.0 tunneling MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Unused bandwidth can be used by external display agents for Panel Replay enabled DP panel during idleness with link on. Enable source to replace dummy data from the display with data from another agent by programming TRANS_DP2_CTL [Panel Replay Tunneling Enable]. v2: - Enable pr bw optimization along with panel replay enable. [Jani] v3: - Write TRANS_DP2_CTL once for both bw optimization and panel replay enable. [Jani] v4: - Read DPCD once in init() and store in panel_replay_caps. [Jouni] v5: - Avoid reading DPCD for edp. [Jouni] - Use drm_dp_dpcd_read_byte() and some cosmetic changes. [Jani] v6: - Extend the corresponding interface defined in drm_dp_tunnel.c to query the Panel Replay optimization capability. [Imre] v7: - Clear TRANS_DP2_PR_TUNNELING_ENABLE if pr bw optimization is not allowed. [Jouni] - Move intel_dp_is_edp() check. [Jouni] Bspec: 68920 Reviewed-by: Arun R Murthy Reviewed-by: Jouni Högander Signed-off-by: Animesh Manna Link: https://patch.msgid.link/20260330133620.3750559-4-animesh.manna@intel.com --- drivers/gpu/drm/i915/display/intel_display_regs.h | 1 + drivers/gpu/drm/i915/display/intel_psr.c | 25 +++++++++++++++++++++-- 2 files changed, 24 insertions(+), 2 deletions(-) diff --git a/drivers/gpu/drm/i915/display/intel_display_regs.h b/drivers/gpu/drm/i915/display/intel_display_regs.h index 4746e9ebd920..dada8dc27ea4 100644 --- a/drivers/gpu/drm/i915/display/intel_display_regs.h +++ b/drivers/gpu/drm/i915/display/intel_display_regs.h @@ -2263,6 +2263,7 @@ #define TRANS_DP2_CTL(trans) _MMIO_TRANS(trans, _TRANS_DP2_CTL_A, _TRANS_DP2_CTL_B) #define TRANS_DP2_128B132B_CHANNEL_CODING REG_BIT(31) #define TRANS_DP2_PANEL_REPLAY_ENABLE REG_BIT(30) +#define TRANS_DP2_PR_TUNNELING_ENABLE REG_BIT(26) #define TRANS_DP2_DEBUG_ENABLE REG_BIT(23) #define _TRANS_DP2_VFREQHIGH_A 0x600a4 diff --git a/drivers/gpu/drm/i915/display/intel_psr.c b/drivers/gpu/drm/i915/display/intel_psr.c index 998c3faf5f2e..a927b73c3f6e 100644 --- a/drivers/gpu/drm/i915/display/intel_psr.c +++ b/drivers/gpu/drm/i915/display/intel_psr.c @@ -44,6 +44,7 @@ #include "intel_dmc.h" #include "intel_dp.h" #include "intel_dp_aux.h" +#include "intel_dp_tunnel.h" #include "intel_dsb.h" #include "intel_frontbuffer.h" #include "intel_hdmi.h" @@ -1031,11 +1032,27 @@ static u8 frames_before_su_entry(struct intel_dp *intel_dp) return frames_before_su_entry; } +static bool intel_psr_allow_pr_bw_optimization(struct intel_dp *intel_dp) +{ + if (intel_dp_is_edp(intel_dp)) + return false; + + if (!intel_dp_tunnel_bw_alloc_is_enabled(intel_dp)) + return false; + + if (!intel_dp_tunnel_pr_optimization_supported(intel_dp)) + return false; + + return true; +} + static void dg2_activate_panel_replay(struct intel_dp *intel_dp) { struct intel_display *display = to_intel_display(intel_dp); struct intel_psr *psr = &intel_dp->psr; enum transcoder cpu_transcoder = intel_dp->psr.transcoder; + u32 dp2_ctl_set = TRANS_DP2_PANEL_REPLAY_ENABLE; + u32 dp2_ctl_clear = 0; if (intel_dp_is_edp(intel_dp) && psr->sel_update_enabled) { u32 val = psr->su_region_et_enabled ? @@ -1048,12 +1065,16 @@ static void dg2_activate_panel_replay(struct intel_dp *intel_dp) val); } + if (intel_psr_allow_pr_bw_optimization(intel_dp)) + dp2_ctl_set |= TRANS_DP2_PR_TUNNELING_ENABLE; + else + dp2_ctl_clear = TRANS_DP2_PR_TUNNELING_ENABLE; + intel_de_rmw(display, PSR2_MAN_TRK_CTL(display, intel_dp->psr.transcoder), 0, ADLP_PSR2_MAN_TRK_CTL_SF_CONTINUOS_FULL_FRAME); - intel_de_rmw(display, TRANS_DP2_CTL(intel_dp->psr.transcoder), 0, - TRANS_DP2_PANEL_REPLAY_ENABLE); + intel_de_rmw(display, TRANS_DP2_CTL(intel_dp->psr.transcoder), dp2_ctl_clear, dp2_ctl_set); } static void hsw_activate_psr2(struct intel_dp *intel_dp) -- cgit v1.2.3 From 4606467a75cfc16721937272ed29462a750b60c8 Mon Sep 17 00:00:00 2001 From: Shivam Kumar Date: Wed, 18 Mar 2026 18:56:58 -0400 Subject: nvmet-tcp: check INIT_FAILED before nvmet_req_uninit in digest error path In nvmet_tcp_try_recv_ddgst(), when a data digest mismatch is detected, nvmet_req_uninit() is called unconditionally. However, if the command arrived via the nvmet_tcp_handle_req_failure() path, nvmet_req_init() had returned false and percpu_ref_tryget_live() was never executed. The unconditional percpu_ref_put() inside nvmet_req_uninit() then causes a refcount underflow, leading to a WARNING in percpu_ref_switch_to_atomic_rcu, a use-after-free diagnostic, and eventually a permanent workqueue deadlock. Check cmd->flags & NVMET_TCP_F_INIT_FAILED before calling nvmet_req_uninit(), matching the existing pattern in nvmet_tcp_execute_request(). Reviewed-by: Christoph Hellwig Signed-off-by: Shivam Kumar Signed-off-by: Keith Busch --- drivers/nvme/target/tcp.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/drivers/nvme/target/tcp.c b/drivers/nvme/target/tcp.c index 4b8b02341ddc..69e971b179ae 100644 --- a/drivers/nvme/target/tcp.c +++ b/drivers/nvme/target/tcp.c @@ -1310,7 +1310,8 @@ static int nvmet_tcp_try_recv_ddgst(struct nvmet_tcp_queue *queue) queue->idx, cmd->req.cmd->common.command_id, queue->pdu.cmd.hdr.type, le32_to_cpu(cmd->recv_ddgst), le32_to_cpu(cmd->exp_ddgst)); - nvmet_req_uninit(&cmd->req); + if (!(cmd->flags & NVMET_TCP_F_INIT_FAILED)) + nvmet_req_uninit(&cmd->req); nvmet_tcp_free_cmd_buffers(cmd); nvmet_tcp_fatal_error(queue); ret = -EPROTO; -- cgit v1.2.3 From 796f35c684c51b7242f3bcc8302a89ec8b7f8b61 Mon Sep 17 00:00:00 2001 From: Chen-Yu Tsai Date: Thu, 26 Mar 2026 17:43:03 +0800 Subject: drm/exynos: Internalize exynos_drm_gem_free_object() exynos_drm_gem_free_object() is only provided as a callback for GEM objects. It does not need to be exposed to the rest of the driver. Move it above where it is used and internalize it to just the GEM functions. Signed-off-by: Chen-Yu Tsai Tested-by: Marek Szyprowski Acked-by: Marek Szyprowski Signed-off-by: Inki Dae --- drivers/gpu/drm/exynos/exynos_drm_gem.c | 10 +++++----- drivers/gpu/drm/exynos/exynos_drm_gem.h | 3 --- 2 files changed, 5 insertions(+), 8 deletions(-) diff --git a/drivers/gpu/drm/exynos/exynos_drm_gem.c b/drivers/gpu/drm/exynos/exynos_drm_gem.c index 69ef6cda1ce9..59fd736a1fb9 100644 --- a/drivers/gpu/drm/exynos/exynos_drm_gem.c +++ b/drivers/gpu/drm/exynos/exynos_drm_gem.c @@ -133,6 +133,11 @@ void exynos_drm_gem_destroy(struct exynos_drm_gem *exynos_gem) kfree(exynos_gem); } +static void exynos_drm_gem_free_object(struct drm_gem_object *obj) +{ + exynos_drm_gem_destroy(to_exynos_gem(obj)); +} + static const struct vm_operations_struct exynos_drm_gem_vm_ops = { .open = drm_gem_vm_open, .close = drm_gem_vm_close, @@ -318,11 +323,6 @@ int exynos_drm_gem_get_ioctl(struct drm_device *dev, void *data, return 0; } -void exynos_drm_gem_free_object(struct drm_gem_object *obj) -{ - exynos_drm_gem_destroy(to_exynos_gem(obj)); -} - int exynos_drm_gem_dumb_create(struct drm_file *file_priv, struct drm_device *dev, struct drm_mode_create_dumb *args) diff --git a/drivers/gpu/drm/exynos/exynos_drm_gem.h b/drivers/gpu/drm/exynos/exynos_drm_gem.h index 79d7e1a87419..8b5bd20ae8c1 100644 --- a/drivers/gpu/drm/exynos/exynos_drm_gem.h +++ b/drivers/gpu/drm/exynos/exynos_drm_gem.h @@ -88,9 +88,6 @@ static inline void exynos_drm_gem_put(struct exynos_drm_gem *exynos_gem) int exynos_drm_gem_get_ioctl(struct drm_device *dev, void *data, struct drm_file *file_priv); -/* free gem object. */ -void exynos_drm_gem_free_object(struct drm_gem_object *obj); - /* create memory region for drm framebuffer. */ int exynos_drm_gem_dumb_create(struct drm_file *file_priv, struct drm_device *dev, -- cgit v1.2.3 From e457a1a9585b941e2aa771142b63c951f6a3d54e Mon Sep 17 00:00:00 2001 From: Chen-Yu Tsai Date: Thu, 26 Mar 2026 17:43:04 +0800 Subject: drm/exynos: Use DRM core dedicated DMA device tracking facility The exynos driver tracks a dedicated DMA device in its private data. The DRM core already has facilities to do this, and it is integrated into DRM PRIME imports and GEM DMA helpers. Convert the exynos driver to use the core's dedicated DMA device tracking facility. Also get rid of exynos_drm_gem_prime_import() as it is identical to drm_gem_prime_import() after the conversion. Signed-off-by: Chen-Yu Tsai Tested-by: Marek Szyprowski Acked-by: Marek Szyprowski Signed-off-by: Inki Dae --- drivers/gpu/drm/exynos/exynos_drm_dma.c | 11 ++++++----- drivers/gpu/drm/exynos/exynos_drm_drv.c | 1 - drivers/gpu/drm/exynos/exynos_drm_drv.h | 8 -------- drivers/gpu/drm/exynos/exynos_drm_g2d.c | 11 ++++++----- drivers/gpu/drm/exynos/exynos_drm_gem.c | 27 +++++++++++---------------- drivers/gpu/drm/exynos/exynos_drm_gem.h | 2 -- 6 files changed, 23 insertions(+), 37 deletions(-) diff --git a/drivers/gpu/drm/exynos/exynos_drm_dma.c b/drivers/gpu/drm/exynos/exynos_drm_dma.c index 6a6761935224..bde2b86a7a7d 100644 --- a/drivers/gpu/drm/exynos/exynos_drm_dma.c +++ b/drivers/gpu/drm/exynos/exynos_drm_dma.c @@ -8,6 +8,7 @@ #include #include +#include #include #include @@ -45,7 +46,7 @@ static int drm_iommu_attach_device(struct drm_device *drm_dev, struct exynos_drm_private *priv = drm_dev->dev_private; int ret = 0; - if (get_dma_ops(priv->dma_dev) != get_dma_ops(subdrv_dev)) { + if (get_dma_ops(drm_dev_dma_dev(drm_dev)) != get_dma_ops(subdrv_dev)) { DRM_DEV_ERROR(subdrv_dev, "Device %s lacks support for IOMMU\n", dev_name(subdrv_dev)); return -EINVAL; @@ -97,8 +98,8 @@ int exynos_drm_register_dma(struct drm_device *drm, struct device *dev, { struct exynos_drm_private *priv = drm->dev_private; - if (!priv->dma_dev) { - priv->dma_dev = dev; + if (drm_dev_dma_dev(drm) == drm->dev) { + drm_dev_set_dma_dev(drm, dev); DRM_INFO("Exynos DRM: using %s device for DMA mapping operations\n", dev_name(dev)); } @@ -113,7 +114,7 @@ int exynos_drm_register_dma(struct drm_device *drm, struct device *dev, mapping = arm_iommu_create_mapping(dev, EXYNOS_DEV_ADDR_START, EXYNOS_DEV_ADDR_SIZE); else if (IS_ENABLED(CONFIG_IOMMU_DMA)) - mapping = iommu_get_domain_for_dev(priv->dma_dev); + mapping = iommu_get_domain_for_dev(dev); if (!mapping) return -ENODEV; @@ -139,5 +140,5 @@ void exynos_drm_cleanup_dma(struct drm_device *drm) arm_iommu_release_mapping(priv->mapping); priv->mapping = NULL; - priv->dma_dev = NULL; + drm_dev_set_dma_dev(drm, NULL); } diff --git a/drivers/gpu/drm/exynos/exynos_drm_drv.c b/drivers/gpu/drm/exynos/exynos_drm_drv.c index 2101a74dc1ed..9ee30086879f 100644 --- a/drivers/gpu/drm/exynos/exynos_drm_drv.c +++ b/drivers/gpu/drm/exynos/exynos_drm_drv.c @@ -109,7 +109,6 @@ static const struct drm_driver exynos_drm_driver = { .open = exynos_drm_open, .postclose = exynos_drm_postclose, .dumb_create = exynos_drm_gem_dumb_create, - .gem_prime_import = exynos_drm_gem_prime_import, .gem_prime_import_sg_table = exynos_drm_gem_prime_import_sg_table, EXYNOS_DRM_FBDEV_DRIVER_OPS, .ioctls = exynos_ioctls, diff --git a/drivers/gpu/drm/exynos/exynos_drm_drv.h b/drivers/gpu/drm/exynos/exynos_drm_drv.h index 06c29ff2aac0..1ab7195d09ae 100644 --- a/drivers/gpu/drm/exynos/exynos_drm_drv.h +++ b/drivers/gpu/drm/exynos/exynos_drm_drv.h @@ -198,7 +198,6 @@ struct drm_exynos_file_private { */ struct exynos_drm_private { struct device *g2d_dev; - struct device *dma_dev; struct device *vidi_dev; void *mapping; @@ -208,13 +207,6 @@ struct exynos_drm_private { wait_queue_head_t wait; }; -static inline struct device *to_dma_dev(struct drm_device *dev) -{ - struct exynos_drm_private *priv = dev->dev_private; - - return priv->dma_dev; -} - static inline bool is_drm_iommu_supported(struct drm_device *drm_dev) { struct exynos_drm_private *priv = drm_dev->dev_private; diff --git a/drivers/gpu/drm/exynos/exynos_drm_g2d.c b/drivers/gpu/drm/exynos/exynos_drm_g2d.c index 348603262af0..85a3a247dfca 100644 --- a/drivers/gpu/drm/exynos/exynos_drm_g2d.c +++ b/drivers/gpu/drm/exynos/exynos_drm_g2d.c @@ -20,6 +20,7 @@ #include #include +#include #include #include #include @@ -278,7 +279,7 @@ static int g2d_init_cmdlist(struct g2d_data *g2d) g2d->cmdlist_dma_attrs = DMA_ATTR_WRITE_COMBINE; - g2d->cmdlist_pool_virt = dma_alloc_attrs(to_dma_dev(g2d->drm_dev), + g2d->cmdlist_pool_virt = dma_alloc_attrs(drm_dev_dma_dev(g2d->drm_dev), G2D_CMDLIST_POOL_SIZE, &g2d->cmdlist_pool, GFP_KERNEL, g2d->cmdlist_dma_attrs); @@ -311,7 +312,7 @@ static int g2d_init_cmdlist(struct g2d_data *g2d) return 0; err: - dma_free_attrs(to_dma_dev(g2d->drm_dev), G2D_CMDLIST_POOL_SIZE, + dma_free_attrs(drm_dev_dma_dev(g2d->drm_dev), G2D_CMDLIST_POOL_SIZE, g2d->cmdlist_pool_virt, g2d->cmdlist_pool, g2d->cmdlist_dma_attrs); return ret; @@ -322,7 +323,7 @@ static void g2d_fini_cmdlist(struct g2d_data *g2d) kfree(g2d->cmdlist_node); if (g2d->cmdlist_pool_virt && g2d->cmdlist_pool) { - dma_free_attrs(to_dma_dev(g2d->drm_dev), + dma_free_attrs(drm_dev_dma_dev(g2d->drm_dev), G2D_CMDLIST_POOL_SIZE, g2d->cmdlist_pool_virt, g2d->cmdlist_pool, g2d->cmdlist_dma_attrs); @@ -397,7 +398,7 @@ static void g2d_userptr_put_dma_addr(struct g2d_data *g2d, return; out: - dma_unmap_sgtable(to_dma_dev(g2d->drm_dev), g2d_userptr->sgt, + dma_unmap_sgtable(drm_dev_dma_dev(g2d->drm_dev), g2d_userptr->sgt, DMA_BIDIRECTIONAL, 0); unpin_user_pages_dirty_lock(g2d_userptr->pages, g2d_userptr->npages, @@ -506,7 +507,7 @@ static dma_addr_t *g2d_userptr_get_dma_addr(struct g2d_data *g2d, g2d_userptr->sgt = sgt; - ret = dma_map_sgtable(to_dma_dev(g2d->drm_dev), sgt, + ret = dma_map_sgtable(drm_dev_dma_dev(g2d->drm_dev), sgt, DMA_BIDIRECTIONAL, 0); if (ret) { DRM_DEV_ERROR(g2d->dev, "failed to map sgt with dma region.\n"); diff --git a/drivers/gpu/drm/exynos/exynos_drm_gem.c b/drivers/gpu/drm/exynos/exynos_drm_gem.c index 59fd736a1fb9..9ec76163609f 100644 --- a/drivers/gpu/drm/exynos/exynos_drm_gem.c +++ b/drivers/gpu/drm/exynos/exynos_drm_gem.c @@ -10,6 +10,7 @@ #include #include +#include #include #include #include @@ -29,7 +30,7 @@ static int exynos_drm_alloc_buf(struct exynos_drm_gem *exynos_gem, bool kvmap) unsigned long attr = 0; if (exynos_gem->dma_addr) { - DRM_DEV_DEBUG_KMS(to_dma_dev(dev), "already allocated.\n"); + DRM_DEV_DEBUG_KMS(drm_dev_dma_dev(dev), "already allocated.\n"); return 0; } @@ -54,18 +55,18 @@ static int exynos_drm_alloc_buf(struct exynos_drm_gem *exynos_gem, bool kvmap) attr |= DMA_ATTR_NO_KERNEL_MAPPING; exynos_gem->dma_attrs = attr; - exynos_gem->cookie = dma_alloc_attrs(to_dma_dev(dev), exynos_gem->size, + exynos_gem->cookie = dma_alloc_attrs(drm_dev_dma_dev(dev), exynos_gem->size, &exynos_gem->dma_addr, GFP_KERNEL, exynos_gem->dma_attrs); if (!exynos_gem->cookie) { - DRM_DEV_ERROR(to_dma_dev(dev), "failed to allocate buffer.\n"); + DRM_DEV_ERROR(drm_dev_dma_dev(dev), "failed to allocate buffer.\n"); return -ENOMEM; } if (kvmap) exynos_gem->kvaddr = exynos_gem->cookie; - DRM_DEV_DEBUG_KMS(to_dma_dev(dev), "dma_addr(0x%lx), size(0x%lx)\n", + DRM_DEV_DEBUG_KMS(drm_dev_dma_dev(dev), "dma_addr(0x%lx), size(0x%lx)\n", (unsigned long)exynos_gem->dma_addr, exynos_gem->size); return 0; } @@ -82,7 +83,7 @@ static void exynos_drm_free_buf(struct exynos_drm_gem *exynos_gem) DRM_DEV_DEBUG_KMS(dev->dev, "dma_addr(0x%lx), size(0x%lx)\n", (unsigned long)exynos_gem->dma_addr, exynos_gem->size); - dma_free_attrs(to_dma_dev(dev), exynos_gem->size, exynos_gem->cookie, + dma_free_attrs(drm_dev_dma_dev(dev), exynos_gem->size, exynos_gem->cookie, (dma_addr_t)exynos_gem->dma_addr, exynos_gem->dma_attrs); } @@ -101,7 +102,7 @@ static int exynos_drm_gem_handle_create(struct drm_gem_object *obj, if (ret) return ret; - DRM_DEV_DEBUG_KMS(to_dma_dev(obj->dev), "gem handle = 0x%x\n", *handle); + DRM_DEV_DEBUG_KMS(drm_dev_dma_dev(obj->dev), "gem handle = 0x%x\n", *handle); /* drop reference from allocate - handle holds it now. */ drm_gem_object_put(obj); @@ -113,7 +114,7 @@ void exynos_drm_gem_destroy(struct exynos_drm_gem *exynos_gem) { struct drm_gem_object *obj = &exynos_gem->base; - DRM_DEV_DEBUG_KMS(to_dma_dev(obj->dev), "handle count = %d\n", + DRM_DEV_DEBUG_KMS(drm_dev_dma_dev(obj->dev), "handle count = %d\n", obj->handle_count); /* @@ -289,7 +290,7 @@ static int exynos_drm_gem_mmap_buffer(struct exynos_drm_gem *exynos_gem, if (vm_size > exynos_gem->size) return -EINVAL; - ret = dma_mmap_attrs(to_dma_dev(drm_dev), vma, exynos_gem->cookie, + ret = dma_mmap_attrs(drm_dev_dma_dev(drm_dev), vma, exynos_gem->cookie, exynos_gem->dma_addr, exynos_gem->size, exynos_gem->dma_attrs); if (ret < 0) { @@ -372,7 +373,7 @@ static int exynos_drm_gem_mmap(struct drm_gem_object *obj, struct vm_area_struct vm_flags_set(vma, VM_IO | VM_DONTEXPAND | VM_DONTDUMP); - DRM_DEV_DEBUG_KMS(to_dma_dev(obj->dev), "flags = 0x%x\n", + DRM_DEV_DEBUG_KMS(drm_dev_dma_dev(obj->dev), "flags = 0x%x\n", exynos_gem->flags); /* non-cachable as default. */ @@ -398,12 +399,6 @@ err_close_vm: } /* low-level interface prime helpers */ -struct drm_gem_object *exynos_drm_gem_prime_import(struct drm_device *dev, - struct dma_buf *dma_buf) -{ - return drm_gem_prime_import_dev(dev, dma_buf, to_dma_dev(dev)); -} - struct sg_table *exynos_drm_gem_prime_get_sg_table(struct drm_gem_object *obj) { struct exynos_drm_gem *exynos_gem = to_exynos_gem(obj); @@ -415,7 +410,7 @@ struct sg_table *exynos_drm_gem_prime_get_sg_table(struct drm_gem_object *obj) if (!sgt) return ERR_PTR(-ENOMEM); - ret = dma_get_sgtable_attrs(to_dma_dev(drm_dev), sgt, exynos_gem->cookie, + ret = dma_get_sgtable_attrs(drm_dev_dma_dev(drm_dev), sgt, exynos_gem->cookie, exynos_gem->dma_addr, exynos_gem->size, exynos_gem->dma_attrs); if (ret) { diff --git a/drivers/gpu/drm/exynos/exynos_drm_gem.h b/drivers/gpu/drm/exynos/exynos_drm_gem.h index 8b5bd20ae8c1..b6785f1136ab 100644 --- a/drivers/gpu/drm/exynos/exynos_drm_gem.h +++ b/drivers/gpu/drm/exynos/exynos_drm_gem.h @@ -94,8 +94,6 @@ int exynos_drm_gem_dumb_create(struct drm_file *file_priv, struct drm_mode_create_dumb *args); /* low-level interface prime helpers */ -struct drm_gem_object *exynos_drm_gem_prime_import(struct drm_device *dev, - struct dma_buf *dma_buf); struct sg_table *exynos_drm_gem_prime_get_sg_table(struct drm_gem_object *obj); struct drm_gem_object * exynos_drm_gem_prime_import_sg_table(struct drm_device *dev, -- cgit v1.2.3 From 11e898373fba6b1d27b15ab4beff592701a57293 Mon Sep 17 00:00:00 2001 From: Chen-Yu Tsai Date: Thu, 26 Mar 2026 17:43:05 +0800 Subject: drm/exynos: Drop exynos_drm_gem.size field A size field is already included in the base GEM object, and is initialized through drm_gem_object_init() with the same value. Drop the field in the subclass to save some space. More changes to make exynos_drm_gem a subclass of drm_gem_dma_object will follow. Signed-off-by: Chen-Yu Tsai Tested-by: Marek Szyprowski Acked-by: Marek Szyprowski Signed-off-by: Inki Dae --- drivers/gpu/drm/exynos/exynos_drm_fb.c | 2 +- drivers/gpu/drm/exynos/exynos_drm_g2d.c | 2 +- drivers/gpu/drm/exynos/exynos_drm_gem.c | 17 ++++++++--------- drivers/gpu/drm/exynos/exynos_drm_gem.h | 3 --- drivers/gpu/drm/exynos/exynos_drm_ipp.c | 2 +- 5 files changed, 11 insertions(+), 15 deletions(-) diff --git a/drivers/gpu/drm/exynos/exynos_drm_fb.c b/drivers/gpu/drm/exynos/exynos_drm_fb.c index ab0e0c74ec47..125b87adfdc4 100644 --- a/drivers/gpu/drm/exynos/exynos_drm_fb.c +++ b/drivers/gpu/drm/exynos/exynos_drm_fb.c @@ -119,7 +119,7 @@ exynos_user_fb_create(struct drm_device *dev, struct drm_file *file_priv, goto err; } - if (size > exynos_gem[i]->size) { + if (size > exynos_gem[i]->base.size) { i++; ret = -EINVAL; goto err; diff --git a/drivers/gpu/drm/exynos/exynos_drm_g2d.c b/drivers/gpu/drm/exynos/exynos_drm_g2d.c index 85a3a247dfca..e92a4d872c41 100644 --- a/drivers/gpu/drm/exynos/exynos_drm_g2d.c +++ b/drivers/gpu/drm/exynos/exynos_drm_g2d.c @@ -720,7 +720,7 @@ static int g2d_map_cmdlist_gem(struct g2d_data *g2d, } if (!g2d_check_buf_desc_is_valid(g2d, buf_desc, - reg_type, exynos_gem->size)) { + reg_type, exynos_gem->base.size)) { exynos_drm_gem_put(exynos_gem); ret = -EFAULT; goto err; diff --git a/drivers/gpu/drm/exynos/exynos_drm_gem.c b/drivers/gpu/drm/exynos/exynos_drm_gem.c index 9ec76163609f..d9d42809a1a9 100644 --- a/drivers/gpu/drm/exynos/exynos_drm_gem.c +++ b/drivers/gpu/drm/exynos/exynos_drm_gem.c @@ -55,7 +55,7 @@ static int exynos_drm_alloc_buf(struct exynos_drm_gem *exynos_gem, bool kvmap) attr |= DMA_ATTR_NO_KERNEL_MAPPING; exynos_gem->dma_attrs = attr; - exynos_gem->cookie = dma_alloc_attrs(drm_dev_dma_dev(dev), exynos_gem->size, + exynos_gem->cookie = dma_alloc_attrs(drm_dev_dma_dev(dev), exynos_gem->base.size, &exynos_gem->dma_addr, GFP_KERNEL, exynos_gem->dma_attrs); if (!exynos_gem->cookie) { @@ -67,7 +67,7 @@ static int exynos_drm_alloc_buf(struct exynos_drm_gem *exynos_gem, bool kvmap) exynos_gem->kvaddr = exynos_gem->cookie; DRM_DEV_DEBUG_KMS(drm_dev_dma_dev(dev), "dma_addr(0x%lx), size(0x%lx)\n", - (unsigned long)exynos_gem->dma_addr, exynos_gem->size); + (unsigned long)exynos_gem->dma_addr, exynos_gem->base.size); return 0; } @@ -81,9 +81,9 @@ static void exynos_drm_free_buf(struct exynos_drm_gem *exynos_gem) } DRM_DEV_DEBUG_KMS(dev->dev, "dma_addr(0x%lx), size(0x%lx)\n", - (unsigned long)exynos_gem->dma_addr, exynos_gem->size); + (unsigned long)exynos_gem->dma_addr, exynos_gem->base.size); - dma_free_attrs(drm_dev_dma_dev(dev), exynos_gem->size, exynos_gem->cookie, + dma_free_attrs(drm_dev_dma_dev(dev), exynos_gem->base.size, exynos_gem->cookie, (dma_addr_t)exynos_gem->dma_addr, exynos_gem->dma_attrs); } @@ -162,7 +162,6 @@ static struct exynos_drm_gem *exynos_drm_gem_init(struct drm_device *dev, if (!exynos_gem) return ERR_PTR(-ENOMEM); - exynos_gem->size = size; obj = &exynos_gem->base; obj->funcs = &exynos_drm_gem_object_funcs; @@ -287,11 +286,11 @@ static int exynos_drm_gem_mmap_buffer(struct exynos_drm_gem *exynos_gem, vm_size = vma->vm_end - vma->vm_start; /* check if user-requested size is valid. */ - if (vm_size > exynos_gem->size) + if (vm_size > exynos_gem->base.size) return -EINVAL; ret = dma_mmap_attrs(drm_dev_dma_dev(drm_dev), vma, exynos_gem->cookie, - exynos_gem->dma_addr, exynos_gem->size, + exynos_gem->dma_addr, exynos_gem->base.size, exynos_gem->dma_attrs); if (ret < 0) { DRM_ERROR("failed to mmap.\n"); @@ -317,7 +316,7 @@ int exynos_drm_gem_get_ioctl(struct drm_device *dev, void *data, exynos_gem = to_exynos_gem(obj); args->flags = exynos_gem->flags; - args->size = exynos_gem->size; + args->size = obj->size; drm_gem_object_put(obj); @@ -411,7 +410,7 @@ struct sg_table *exynos_drm_gem_prime_get_sg_table(struct drm_gem_object *obj) return ERR_PTR(-ENOMEM); ret = dma_get_sgtable_attrs(drm_dev_dma_dev(drm_dev), sgt, exynos_gem->cookie, - exynos_gem->dma_addr, exynos_gem->size, + exynos_gem->dma_addr, obj->size, exynos_gem->dma_attrs); if (ret) { DRM_ERROR("failed to get sgtable, %d\n", ret); diff --git a/drivers/gpu/drm/exynos/exynos_drm_gem.h b/drivers/gpu/drm/exynos/exynos_drm_gem.h index b6785f1136ab..3ff9fa9955ea 100644 --- a/drivers/gpu/drm/exynos/exynos_drm_gem.h +++ b/drivers/gpu/drm/exynos/exynos_drm_gem.h @@ -22,8 +22,6 @@ * - a new handle to this gem object would be created * by drm_gem_handle_create(). * @flags: indicate memory type to allocated buffer and cache attruibute. - * @size: size requested from user, in bytes and this size is aligned - * in page unit. * @cookie: cookie returned by dma_alloc_attrs * @kvaddr: kernel virtual address to allocated memory region (for fbdev) * @dma_addr: bus address(accessed by dma) to allocated memory region. @@ -38,7 +36,6 @@ struct exynos_drm_gem { struct drm_gem_object base; unsigned int flags; - unsigned long size; void *cookie; void *kvaddr; dma_addr_t dma_addr; diff --git a/drivers/gpu/drm/exynos/exynos_drm_ipp.c b/drivers/gpu/drm/exynos/exynos_drm_ipp.c index ee3d61345a66..43bc4f63bb84 100644 --- a/drivers/gpu/drm/exynos/exynos_drm_ipp.c +++ b/drivers/gpu/drm/exynos/exynos_drm_ipp.c @@ -364,7 +364,7 @@ static int exynos_drm_ipp_task_setup_buffer(struct exynos_drm_ipp_buffer *buf, } buf->exynos_gem[i] = gem; - if (size + buf->buf.offset[i] > buf->exynos_gem[i]->size) { + if (size + buf->buf.offset[i] > buf->exynos_gem[i]->base.size) { i++; ret = -EINVAL; goto gem_free; -- cgit v1.2.3 From 0867757f1eec0a246c70b2407a1bbed949170821 Mon Sep 17 00:00:00 2001 From: Chen-Yu Tsai Date: Thu, 26 Mar 2026 17:43:06 +0800 Subject: drm/exynos: Drop MAX_FB_BUFFER in favor of DRM_FORMAT_MAX_PLANES MAX_FB_BUFFER refers to the maximum number of buffer planes for a framebuffer. This is the same as DRM_FORMAT_MAX_PLANES, which denotes the maximum number of planes. Signed-off-by: Chen-Yu Tsai Tested-by: Marek Szyprowski Acked-by: Marek Szyprowski Signed-off-by: Inki Dae --- drivers/gpu/drm/exynos/exynos_drm_drv.h | 1 - drivers/gpu/drm/exynos/exynos_drm_fb.c | 4 ++-- drivers/gpu/drm/exynos/exynos_drm_ipp.h | 4 ++-- 3 files changed, 4 insertions(+), 5 deletions(-) diff --git a/drivers/gpu/drm/exynos/exynos_drm_drv.h b/drivers/gpu/drm/exynos/exynos_drm_drv.h index 1ab7195d09ae..b126cd129944 100644 --- a/drivers/gpu/drm/exynos/exynos_drm_drv.h +++ b/drivers/gpu/drm/exynos/exynos_drm_drv.h @@ -19,7 +19,6 @@ #define MAX_CRTC 3 #define MAX_PLANE 5 -#define MAX_FB_BUFFER 4 #define DEFAULT_WIN 0 diff --git a/drivers/gpu/drm/exynos/exynos_drm_fb.c b/drivers/gpu/drm/exynos/exynos_drm_fb.c index 125b87adfdc4..93f387b12126 100644 --- a/drivers/gpu/drm/exynos/exynos_drm_fb.c +++ b/drivers/gpu/drm/exynos/exynos_drm_fb.c @@ -99,7 +99,7 @@ exynos_user_fb_create(struct drm_device *dev, struct drm_file *file_priv, const struct drm_format_info *info, const struct drm_mode_fb_cmd2 *mode_cmd) { - struct exynos_drm_gem *exynos_gem[MAX_FB_BUFFER]; + struct exynos_drm_gem *exynos_gem[DRM_FORMAT_MAX_PLANES]; struct drm_framebuffer *fb; int i; int ret; @@ -145,7 +145,7 @@ dma_addr_t exynos_drm_fb_dma_addr(struct drm_framebuffer *fb, int index) { struct exynos_drm_gem *exynos_gem; - if (WARN_ON_ONCE(index >= MAX_FB_BUFFER)) + if (WARN_ON_ONCE(index >= DRM_FORMAT_MAX_PLANES)) return 0; exynos_gem = to_exynos_gem(fb->obj[index]); diff --git a/drivers/gpu/drm/exynos/exynos_drm_ipp.h b/drivers/gpu/drm/exynos/exynos_drm_ipp.h index 67a0805ee009..2842c8af0b7c 100644 --- a/drivers/gpu/drm/exynos/exynos_drm_ipp.h +++ b/drivers/gpu/drm/exynos/exynos_drm_ipp.h @@ -70,9 +70,9 @@ struct exynos_drm_ipp_buffer { struct drm_exynos_ipp_task_buffer buf; struct drm_exynos_ipp_task_rect rect; - struct exynos_drm_gem *exynos_gem[MAX_FB_BUFFER]; + struct exynos_drm_gem *exynos_gem[DRM_FORMAT_MAX_PLANES]; const struct drm_format_info *format; - dma_addr_t dma_addr[MAX_FB_BUFFER]; + dma_addr_t dma_addr[DRM_FORMAT_MAX_PLANES]; }; /** -- cgit v1.2.3 From 28f60e912cc21d4f5e208661e9c4ffe8488046a9 Mon Sep 17 00:00:00 2001 From: Nemesa Garg Date: Thu, 2 Apr 2026 11:43:10 +0530 Subject: drm/i915/pfit: Prevent negative coordinates in center mode MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit When the pipe_src width or height are greater than adjusted_mode hdisplay and vdisplay, computed x and y offsets for center mode can be negative. Writing negative values into the pch_fit registers result in a state error. Add a check to clamp these values so that they are never negative. v2: Compare in terms of pipe_src width and height.[Ville] v3: Change width/height to pipe_src_w/h in logging. [Ville] Signed-off-by: Nemesa Garg Signed-off-by: Ville Syrjälä Link: https://patch.msgid.link/20260402061310.111073-1-nemesa.garg@intel.com --- drivers/gpu/drm/i915/display/intel_pfit.c | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/drivers/gpu/drm/i915/display/intel_pfit.c b/drivers/gpu/drm/i915/display/intel_pfit.c index 6dda496190e0..2dec4ccf74ce 100644 --- a/drivers/gpu/drm/i915/display/intel_pfit.c +++ b/drivers/gpu/drm/i915/display/intel_pfit.c @@ -186,6 +186,7 @@ static int pch_panel_fitting(struct intel_crtc_state *crtc_state, const struct drm_connector_state *conn_state) { struct intel_display *display = to_intel_display(crtc_state); + struct intel_crtc *crtc = to_intel_crtc(crtc_state->uapi.crtc); const struct drm_display_mode *adjusted_mode = &crtc_state->hw.adjusted_mode; int pipe_src_w = drm_rect_width(&crtc_state->pipe_src); @@ -200,6 +201,16 @@ static int pch_panel_fitting(struct intel_crtc_state *crtc_state, switch (conn_state->scaling_mode) { case DRM_MODE_SCALE_CENTER: + if (adjusted_mode->crtc_hdisplay < pipe_src_w || + adjusted_mode->crtc_vdisplay < pipe_src_h) { + drm_dbg_kms(display->drm, + "[CRTC:%d:%s] pfit center mode source (%dx%d) exceeds display (%dx%d)\n", + crtc->base.base.id, crtc->base.name, + pipe_src_w, pipe_src_h, + adjusted_mode->crtc_hdisplay, + adjusted_mode->crtc_vdisplay); + return -EINVAL; + } width = pipe_src_w; height = pipe_src_h; x = (adjusted_mode->crtc_hdisplay - width + 1)/2; -- cgit v1.2.3 From f844177c6811fd322aa84ed5c32f0e39743446c2 Mon Sep 17 00:00:00 2001 From: Max Zhen Date: Mon, 6 Apr 2026 14:14:03 -0700 Subject: accel/amdxdna: Handle DETACH_DEBUG_BO through config_debug_bo path Route DETACH_DEBUG_BO through aie2_config_debug_bo() the same way as ATTACH_DEBUG_BO. The scheduler switch in aie2_sched_job_run() already handles ATTACH_DEBUG_BO with aie2_config_debug_bo(), but DETACH_DEBUG_BO was not included in that path. Add an explicit fallthrough so both attach and detach operations use the same handler. This fixes debug BO detach handling by ensuring the detach command is processed by the expected configuration path. Fixes: 7ea046838021 ("accel/amdxdna: Support firmware debug buffer") Signed-off-by: Max Zhen Reviewed-by: Mario Limonciello (AMD) Signed-off-by: Lizhi Hou Link: https://patch.msgid.link/20260406211403.4011988-1-lizhi.hou@amd.com --- drivers/accel/amdxdna/aie2_ctx.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/accel/amdxdna/aie2_ctx.c b/drivers/accel/amdxdna/aie2_ctx.c index 8db32f8e2362..f97755d60fa3 100644 --- a/drivers/accel/amdxdna/aie2_ctx.c +++ b/drivers/accel/amdxdna/aie2_ctx.c @@ -360,6 +360,7 @@ aie2_sched_job_run(struct drm_sched_job *sched_job) ret = aie2_sync_bo(hwctx, job, aie2_sched_drvcmd_resp_handler); break; case ATTACH_DEBUG_BO: + case DETACH_DEBUG_BO: ret = aie2_config_debug_bo(hwctx, job, aie2_sched_drvcmd_resp_handler); break; default: -- cgit v1.2.3 From 7d7188501a7d307d56e132fce5513339d72ce48d Mon Sep 17 00:00:00 2001 From: Jani Nikula Date: Tue, 7 Apr 2026 13:04:35 +0300 Subject: drm/i915: move intel_fb_pin.c to i915_fb_pin.c MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit intel_fb_pin.c is the final file in display/ that's specific to i915 only. Move it to i915 core, renaming it to i915_fb_pin.c. It'll still depend on a lot of display stuff, unfortunately. Reviewed-by: Ville Syrjälä Link: https://patch.msgid.link/ab1ffc08bcd1364715396142f91780b6261bbe65.1775556190.git.jani.nikula@intel.com Signed-off-by: Jani Nikula --- drivers/gpu/drm/i915/Makefile | 2 +- drivers/gpu/drm/i915/display/intel_fb_pin.c | 357 --------------------------- drivers/gpu/drm/i915/i915_fb_pin.c | 358 ++++++++++++++++++++++++++++ 3 files changed, 359 insertions(+), 358 deletions(-) delete mode 100644 drivers/gpu/drm/i915/display/intel_fb_pin.c create mode 100644 drivers/gpu/drm/i915/i915_fb_pin.c diff --git a/drivers/gpu/drm/i915/Makefile b/drivers/gpu/drm/i915/Makefile index 272c292f06ed..fa632f4e505c 100644 --- a/drivers/gpu/drm/i915/Makefile +++ b/drivers/gpu/drm/i915/Makefile @@ -80,6 +80,7 @@ i915-y += \ i915_display_pc8.o \ i915_dpt.o \ i915_dsb_buffer.o \ + i915_fb_pin.o \ i915_hdcp_gsc.o \ i915_initial_plane.o \ i915_overlay.o \ @@ -279,7 +280,6 @@ i915-y += \ display/intel_drrs.o \ display/intel_dsb.o \ display/intel_fb.o \ - display/intel_fb_pin.o \ display/intel_fbc.o \ display/intel_fdi.o \ display/intel_fifo_underrun.o \ diff --git a/drivers/gpu/drm/i915/display/intel_fb_pin.c b/drivers/gpu/drm/i915/display/intel_fb_pin.c deleted file mode 100644 index 738d77a1468a..000000000000 --- a/drivers/gpu/drm/i915/display/intel_fb_pin.c +++ /dev/null @@ -1,357 +0,0 @@ -// SPDX-License-Identifier: MIT -/* - * Copyright © 2021 Intel Corporation - */ - -/** - * DOC: display pinning helpers - */ - -#include - -#include "gem/i915_gem_domain.h" -#include "gem/i915_gem_object.h" - -#include "i915_drv.h" -#include "i915_vma.h" -#include "intel_display_core.h" -#include "intel_display_rpm.h" -#include "intel_display_types.h" -#include "i915_dpt.h" -#include "intel_fb.h" -#include "intel_fb_pin.h" -#include "intel_plane.h" - -static struct i915_vma * -intel_fb_pin_to_dpt(const struct drm_framebuffer *fb, - const struct i915_gtt_view *view, - unsigned int alignment, - unsigned long *out_flags, - struct intel_dpt *dpt) -{ - struct drm_device *dev = fb->dev; - struct intel_display *display = to_intel_display(dev); - struct drm_i915_private *dev_priv = to_i915(dev); - struct drm_gem_object *_obj = intel_fb_bo(fb); - struct drm_i915_gem_object *obj = to_intel_bo(_obj); - struct i915_address_space *vm = i915_dpt_to_vm(dpt); - struct i915_gem_ww_ctx ww; - struct i915_vma *vma; - int ret; - - /* - * We are not syncing against the binding (and potential migrations) - * below, so this vm must never be async. - */ - if (drm_WARN_ON(&dev_priv->drm, vm->bind_async_flags)) - return ERR_PTR(-EINVAL); - - if (WARN_ON(!i915_gem_object_is_framebuffer(obj))) - return ERR_PTR(-EINVAL); - - atomic_inc(&display->restore.pending_fb_pin); - - for_i915_gem_ww(&ww, ret, true) { - ret = i915_gem_object_lock(obj, &ww); - if (ret) - continue; - - if (HAS_LMEM(dev_priv)) { - unsigned int flags = obj->flags; - - /* - * For this type of buffer we need to able to read from the CPU - * the clear color value found in the buffer, hence we need to - * ensure it is always in the mappable part of lmem, if this is - * a small-bar device. - */ - if (intel_fb_rc_ccs_cc_plane(fb) >= 0) - flags &= ~I915_BO_ALLOC_GPU_ONLY; - ret = __i915_gem_object_migrate(obj, &ww, INTEL_REGION_LMEM_0, - flags); - if (ret) - continue; - } - - ret = i915_gem_object_set_cache_level(obj, I915_CACHE_NONE); - if (ret) - continue; - - vma = i915_vma_instance(obj, vm, view); - if (IS_ERR(vma)) { - ret = PTR_ERR(vma); - continue; - } - - if (i915_vma_misplaced(vma, 0, alignment, 0)) { - ret = i915_vma_unbind(vma); - if (ret) - continue; - } - - ret = i915_vma_pin_ww(vma, &ww, 0, alignment, PIN_GLOBAL); - if (ret) - continue; - } - if (ret) { - vma = ERR_PTR(ret); - goto err; - } - - vma->display_alignment = max(vma->display_alignment, alignment); - - i915_gem_object_flush_if_display(obj); - - i915_vma_get(vma); -err: - atomic_dec(&display->restore.pending_fb_pin); - - return vma; -} - -struct i915_vma * -intel_fb_pin_to_ggtt(const struct drm_framebuffer *fb, - const struct i915_gtt_view *view, - unsigned int alignment, - unsigned int phys_alignment, - unsigned int vtd_guard, - bool uses_fence, - unsigned long *out_flags) -{ - struct drm_device *dev = fb->dev; - struct intel_display *display = to_intel_display(dev); - struct drm_i915_private *dev_priv = to_i915(dev); - struct drm_gem_object *_obj = intel_fb_bo(fb); - struct drm_i915_gem_object *obj = to_intel_bo(_obj); - struct ref_tracker *wakeref; - struct i915_gem_ww_ctx ww; - struct i915_vma *vma; - unsigned int pinctl; - int ret; - - if (drm_WARN_ON(dev, !i915_gem_object_is_framebuffer(obj))) - return ERR_PTR(-EINVAL); - - if (drm_WARN_ON(dev, alignment && !is_power_of_2(alignment))) - return ERR_PTR(-EINVAL); - - /* - * Global gtt pte registers are special registers which actually forward - * writes to a chunk of system memory. Which means that there is no risk - * that the register values disappear as soon as we call - * intel_runtime_pm_put(), so it is correct to wrap only the - * pin/unpin/fence and not more. - */ - wakeref = intel_display_rpm_get(display); - - atomic_inc(&display->restore.pending_fb_pin); - - /* - * Valleyview is definitely limited to scanning out the first - * 512MiB. Lets presume this behaviour was inherited from the - * g4x display engine and that all earlier gen are similarly - * limited. Testing suggests that it is a little more - * complicated than this. For example, Cherryview appears quite - * happy to scanout from anywhere within its global aperture. - */ - pinctl = 0; - if (HAS_GMCH(display)) - pinctl |= PIN_MAPPABLE; - - i915_gem_ww_ctx_init(&ww, true); -retry: - ret = i915_gem_object_lock(obj, &ww); - if (!ret && phys_alignment) - ret = i915_gem_object_attach_phys(obj, phys_alignment); - else if (!ret && HAS_LMEM(dev_priv)) - ret = i915_gem_object_migrate(obj, &ww, INTEL_REGION_LMEM_0); - if (!ret) - ret = i915_gem_object_pin_pages(obj); - if (ret) - goto err; - - vma = i915_gem_object_pin_to_display_plane(obj, &ww, alignment, - vtd_guard, view, pinctl); - if (IS_ERR(vma)) { - ret = PTR_ERR(vma); - goto err_unpin; - } - - if (uses_fence && i915_vma_is_map_and_fenceable(vma)) { - /* - * Install a fence for tiled scan-out. Pre-i965 always needs a - * fence, whereas 965+ only requires a fence if using - * framebuffer compression. For simplicity, we always, when - * possible, install a fence as the cost is not that onerous. - * - * If we fail to fence the tiled scanout, then either the - * modeset will reject the change (which is highly unlikely as - * the affected systems, all but one, do not have unmappable - * space) or we will not be able to enable full powersaving - * techniques (also likely not to apply due to various limits - * FBC and the like impose on the size of the buffer, which - * presumably we violated anyway with this unmappable buffer). - * Anyway, it is presumably better to stumble onwards with - * something and try to run the system in a "less than optimal" - * mode that matches the user configuration. - */ - ret = i915_vma_pin_fence(vma); - if (ret != 0 && DISPLAY_VER(display) < 4) { - i915_vma_unpin(vma); - goto err_unpin; - } - ret = 0; - - if (vma->fence) - *out_flags |= PLANE_HAS_FENCE; - } - - i915_vma_get(vma); - -err_unpin: - i915_gem_object_unpin_pages(obj); -err: - if (ret == -EDEADLK) { - ret = i915_gem_ww_ctx_backoff(&ww); - if (!ret) - goto retry; - } - i915_gem_ww_ctx_fini(&ww); - if (ret) - vma = ERR_PTR(ret); - - atomic_dec(&display->restore.pending_fb_pin); - intel_display_rpm_put(display, wakeref); - return vma; -} - -void intel_fb_unpin_vma(struct i915_vma *vma, unsigned long flags) -{ - if (flags & PLANE_HAS_FENCE) - i915_vma_unpin_fence(vma); - i915_vma_unpin(vma); - i915_vma_put(vma); -} - -static unsigned int -intel_plane_fb_min_alignment(const struct intel_plane_state *plane_state) -{ - const struct intel_framebuffer *fb = to_intel_framebuffer(plane_state->hw.fb); - - return fb->min_alignment; -} - -static unsigned int -intel_plane_fb_min_phys_alignment(const struct intel_plane_state *plane_state) -{ - struct intel_plane *plane = to_intel_plane(plane_state->uapi.plane); - const struct drm_framebuffer *fb = plane_state->hw.fb; - - if (!intel_plane_needs_physical(plane)) - return 0; - - return plane->min_alignment(plane, fb, 0); -} - -static unsigned int -intel_plane_fb_vtd_guard(const struct intel_plane_state *plane_state) -{ - return intel_fb_view_vtd_guard(plane_state->hw.fb, - &plane_state->view, - plane_state->hw.rotation); -} - -int intel_plane_pin_fb(struct intel_plane_state *plane_state, - const struct intel_plane_state *old_plane_state) -{ - struct intel_display *display = to_intel_display(plane_state); - struct intel_plane *plane = to_intel_plane(plane_state->uapi.plane); - const struct intel_framebuffer *fb = - to_intel_framebuffer(plane_state->hw.fb); - struct i915_vma *vma; - - if (!intel_fb_uses_dpt(&fb->base)) { - vma = intel_fb_pin_to_ggtt(&fb->base, &plane_state->view.gtt, - intel_plane_fb_min_alignment(plane_state), - intel_plane_fb_min_phys_alignment(plane_state), - intel_plane_fb_vtd_guard(plane_state), - intel_plane_uses_fence(plane_state), - &plane_state->flags); - if (IS_ERR(vma)) - return PTR_ERR(vma); - - plane_state->ggtt_vma = vma; - - } else { - unsigned int alignment = intel_plane_fb_min_alignment(plane_state); - - vma = i915_dpt_pin_to_ggtt(fb->dpt, alignment / 512); - if (IS_ERR(vma)) - return PTR_ERR(vma); - - plane_state->ggtt_vma = vma; - - vma = intel_fb_pin_to_dpt(&fb->base, &plane_state->view.gtt, - alignment, &plane_state->flags, - fb->dpt); - if (IS_ERR(vma)) { - i915_dpt_unpin_from_ggtt(fb->dpt); - plane_state->ggtt_vma = NULL; - return PTR_ERR(vma); - } - - plane_state->dpt_vma = vma; - - WARN_ON(plane_state->ggtt_vma == plane_state->dpt_vma); - - /* - * The DPT object contains only one vma, and there is no VT-d - * guard, so the VMA's offset within the DPT is always 0. - */ - drm_WARN_ON(display->drm, i915_dpt_offset(plane_state->dpt_vma)); - } - - /* - * Pre-populate the dma address before we enter the vblank - * evade critical section as i915_gem_object_get_dma_address() - * will trigger might_sleep() even if it won't actually sleep, - * which is the case when the fb has already been pinned. - */ - if (intel_plane_needs_physical(plane)) { - struct drm_i915_gem_object *obj = to_intel_bo(intel_fb_bo(&fb->base)); - - plane_state->surf = i915_gem_object_get_dma_address(obj, 0) + - plane->surf_offset(plane_state); - } else { - plane_state->surf = i915_ggtt_offset(plane_state->ggtt_vma) + - plane->surf_offset(plane_state); - } - - return 0; -} - -void intel_plane_unpin_fb(struct intel_plane_state *old_plane_state) -{ - const struct intel_framebuffer *fb = - to_intel_framebuffer(old_plane_state->hw.fb); - struct i915_vma *vma; - - if (!intel_fb_uses_dpt(&fb->base)) { - vma = fetch_and_zero(&old_plane_state->ggtt_vma); - if (vma) - intel_fb_unpin_vma(vma, old_plane_state->flags); - } else { - vma = fetch_and_zero(&old_plane_state->dpt_vma); - if (vma) - intel_fb_unpin_vma(vma, old_plane_state->flags); - - vma = fetch_and_zero(&old_plane_state->ggtt_vma); - if (vma) - i915_dpt_unpin_from_ggtt(fb->dpt); - } -} - -void intel_fb_get_map(struct i915_vma *vma, struct iosys_map *map) -{ - iosys_map_set_vaddr_iomem(map, i915_vma_get_iomap(vma)); -} diff --git a/drivers/gpu/drm/i915/i915_fb_pin.c b/drivers/gpu/drm/i915/i915_fb_pin.c new file mode 100644 index 000000000000..580acbb14ada --- /dev/null +++ b/drivers/gpu/drm/i915/i915_fb_pin.c @@ -0,0 +1,358 @@ +// SPDX-License-Identifier: MIT +/* + * Copyright © 2021 Intel Corporation + */ + +/** + * DOC: display pinning helpers + */ + +#include + +#include "display/intel_display_core.h" +#include "display/intel_display_rpm.h" +#include "display/intel_display_types.h" +#include "display/intel_fb.h" +#include "display/intel_fb_pin.h" +#include "display/intel_plane.h" + +#include "gem/i915_gem_domain.h" +#include "gem/i915_gem_object.h" + +#include "i915_dpt.h" +#include "i915_drv.h" +#include "i915_vma.h" + +static struct i915_vma * +intel_fb_pin_to_dpt(const struct drm_framebuffer *fb, + const struct i915_gtt_view *view, + unsigned int alignment, + unsigned long *out_flags, + struct intel_dpt *dpt) +{ + struct drm_device *dev = fb->dev; + struct intel_display *display = to_intel_display(dev); + struct drm_i915_private *dev_priv = to_i915(dev); + struct drm_gem_object *_obj = intel_fb_bo(fb); + struct drm_i915_gem_object *obj = to_intel_bo(_obj); + struct i915_address_space *vm = i915_dpt_to_vm(dpt); + struct i915_gem_ww_ctx ww; + struct i915_vma *vma; + int ret; + + /* + * We are not syncing against the binding (and potential migrations) + * below, so this vm must never be async. + */ + if (drm_WARN_ON(&dev_priv->drm, vm->bind_async_flags)) + return ERR_PTR(-EINVAL); + + if (WARN_ON(!i915_gem_object_is_framebuffer(obj))) + return ERR_PTR(-EINVAL); + + atomic_inc(&display->restore.pending_fb_pin); + + for_i915_gem_ww(&ww, ret, true) { + ret = i915_gem_object_lock(obj, &ww); + if (ret) + continue; + + if (HAS_LMEM(dev_priv)) { + unsigned int flags = obj->flags; + + /* + * For this type of buffer we need to able to read from the CPU + * the clear color value found in the buffer, hence we need to + * ensure it is always in the mappable part of lmem, if this is + * a small-bar device. + */ + if (intel_fb_rc_ccs_cc_plane(fb) >= 0) + flags &= ~I915_BO_ALLOC_GPU_ONLY; + ret = __i915_gem_object_migrate(obj, &ww, INTEL_REGION_LMEM_0, + flags); + if (ret) + continue; + } + + ret = i915_gem_object_set_cache_level(obj, I915_CACHE_NONE); + if (ret) + continue; + + vma = i915_vma_instance(obj, vm, view); + if (IS_ERR(vma)) { + ret = PTR_ERR(vma); + continue; + } + + if (i915_vma_misplaced(vma, 0, alignment, 0)) { + ret = i915_vma_unbind(vma); + if (ret) + continue; + } + + ret = i915_vma_pin_ww(vma, &ww, 0, alignment, PIN_GLOBAL); + if (ret) + continue; + } + if (ret) { + vma = ERR_PTR(ret); + goto err; + } + + vma->display_alignment = max(vma->display_alignment, alignment); + + i915_gem_object_flush_if_display(obj); + + i915_vma_get(vma); +err: + atomic_dec(&display->restore.pending_fb_pin); + + return vma; +} + +struct i915_vma * +intel_fb_pin_to_ggtt(const struct drm_framebuffer *fb, + const struct i915_gtt_view *view, + unsigned int alignment, + unsigned int phys_alignment, + unsigned int vtd_guard, + bool uses_fence, + unsigned long *out_flags) +{ + struct drm_device *dev = fb->dev; + struct intel_display *display = to_intel_display(dev); + struct drm_i915_private *dev_priv = to_i915(dev); + struct drm_gem_object *_obj = intel_fb_bo(fb); + struct drm_i915_gem_object *obj = to_intel_bo(_obj); + struct ref_tracker *wakeref; + struct i915_gem_ww_ctx ww; + struct i915_vma *vma; + unsigned int pinctl; + int ret; + + if (drm_WARN_ON(dev, !i915_gem_object_is_framebuffer(obj))) + return ERR_PTR(-EINVAL); + + if (drm_WARN_ON(dev, alignment && !is_power_of_2(alignment))) + return ERR_PTR(-EINVAL); + + /* + * Global gtt pte registers are special registers which actually forward + * writes to a chunk of system memory. Which means that there is no risk + * that the register values disappear as soon as we call + * intel_runtime_pm_put(), so it is correct to wrap only the + * pin/unpin/fence and not more. + */ + wakeref = intel_display_rpm_get(display); + + atomic_inc(&display->restore.pending_fb_pin); + + /* + * Valleyview is definitely limited to scanning out the first + * 512MiB. Lets presume this behaviour was inherited from the + * g4x display engine and that all earlier gen are similarly + * limited. Testing suggests that it is a little more + * complicated than this. For example, Cherryview appears quite + * happy to scanout from anywhere within its global aperture. + */ + pinctl = 0; + if (HAS_GMCH(display)) + pinctl |= PIN_MAPPABLE; + + i915_gem_ww_ctx_init(&ww, true); +retry: + ret = i915_gem_object_lock(obj, &ww); + if (!ret && phys_alignment) + ret = i915_gem_object_attach_phys(obj, phys_alignment); + else if (!ret && HAS_LMEM(dev_priv)) + ret = i915_gem_object_migrate(obj, &ww, INTEL_REGION_LMEM_0); + if (!ret) + ret = i915_gem_object_pin_pages(obj); + if (ret) + goto err; + + vma = i915_gem_object_pin_to_display_plane(obj, &ww, alignment, + vtd_guard, view, pinctl); + if (IS_ERR(vma)) { + ret = PTR_ERR(vma); + goto err_unpin; + } + + if (uses_fence && i915_vma_is_map_and_fenceable(vma)) { + /* + * Install a fence for tiled scan-out. Pre-i965 always needs a + * fence, whereas 965+ only requires a fence if using + * framebuffer compression. For simplicity, we always, when + * possible, install a fence as the cost is not that onerous. + * + * If we fail to fence the tiled scanout, then either the + * modeset will reject the change (which is highly unlikely as + * the affected systems, all but one, do not have unmappable + * space) or we will not be able to enable full powersaving + * techniques (also likely not to apply due to various limits + * FBC and the like impose on the size of the buffer, which + * presumably we violated anyway with this unmappable buffer). + * Anyway, it is presumably better to stumble onwards with + * something and try to run the system in a "less than optimal" + * mode that matches the user configuration. + */ + ret = i915_vma_pin_fence(vma); + if (ret != 0 && DISPLAY_VER(display) < 4) { + i915_vma_unpin(vma); + goto err_unpin; + } + ret = 0; + + if (vma->fence) + *out_flags |= PLANE_HAS_FENCE; + } + + i915_vma_get(vma); + +err_unpin: + i915_gem_object_unpin_pages(obj); +err: + if (ret == -EDEADLK) { + ret = i915_gem_ww_ctx_backoff(&ww); + if (!ret) + goto retry; + } + i915_gem_ww_ctx_fini(&ww); + if (ret) + vma = ERR_PTR(ret); + + atomic_dec(&display->restore.pending_fb_pin); + intel_display_rpm_put(display, wakeref); + return vma; +} + +void intel_fb_unpin_vma(struct i915_vma *vma, unsigned long flags) +{ + if (flags & PLANE_HAS_FENCE) + i915_vma_unpin_fence(vma); + i915_vma_unpin(vma); + i915_vma_put(vma); +} + +static unsigned int +intel_plane_fb_min_alignment(const struct intel_plane_state *plane_state) +{ + const struct intel_framebuffer *fb = to_intel_framebuffer(plane_state->hw.fb); + + return fb->min_alignment; +} + +static unsigned int +intel_plane_fb_min_phys_alignment(const struct intel_plane_state *plane_state) +{ + struct intel_plane *plane = to_intel_plane(plane_state->uapi.plane); + const struct drm_framebuffer *fb = plane_state->hw.fb; + + if (!intel_plane_needs_physical(plane)) + return 0; + + return plane->min_alignment(plane, fb, 0); +} + +static unsigned int +intel_plane_fb_vtd_guard(const struct intel_plane_state *plane_state) +{ + return intel_fb_view_vtd_guard(plane_state->hw.fb, + &plane_state->view, + plane_state->hw.rotation); +} + +int intel_plane_pin_fb(struct intel_plane_state *plane_state, + const struct intel_plane_state *old_plane_state) +{ + struct intel_display *display = to_intel_display(plane_state); + struct intel_plane *plane = to_intel_plane(plane_state->uapi.plane); + const struct intel_framebuffer *fb = + to_intel_framebuffer(plane_state->hw.fb); + struct i915_vma *vma; + + if (!intel_fb_uses_dpt(&fb->base)) { + vma = intel_fb_pin_to_ggtt(&fb->base, &plane_state->view.gtt, + intel_plane_fb_min_alignment(plane_state), + intel_plane_fb_min_phys_alignment(plane_state), + intel_plane_fb_vtd_guard(plane_state), + intel_plane_uses_fence(plane_state), + &plane_state->flags); + if (IS_ERR(vma)) + return PTR_ERR(vma); + + plane_state->ggtt_vma = vma; + + } else { + unsigned int alignment = intel_plane_fb_min_alignment(plane_state); + + vma = i915_dpt_pin_to_ggtt(fb->dpt, alignment / 512); + if (IS_ERR(vma)) + return PTR_ERR(vma); + + plane_state->ggtt_vma = vma; + + vma = intel_fb_pin_to_dpt(&fb->base, &plane_state->view.gtt, + alignment, &plane_state->flags, + fb->dpt); + if (IS_ERR(vma)) { + i915_dpt_unpin_from_ggtt(fb->dpt); + plane_state->ggtt_vma = NULL; + return PTR_ERR(vma); + } + + plane_state->dpt_vma = vma; + + WARN_ON(plane_state->ggtt_vma == plane_state->dpt_vma); + + /* + * The DPT object contains only one vma, and there is no VT-d + * guard, so the VMA's offset within the DPT is always 0. + */ + drm_WARN_ON(display->drm, i915_dpt_offset(plane_state->dpt_vma)); + } + + /* + * Pre-populate the dma address before we enter the vblank + * evade critical section as i915_gem_object_get_dma_address() + * will trigger might_sleep() even if it won't actually sleep, + * which is the case when the fb has already been pinned. + */ + if (intel_plane_needs_physical(plane)) { + struct drm_i915_gem_object *obj = to_intel_bo(intel_fb_bo(&fb->base)); + + plane_state->surf = i915_gem_object_get_dma_address(obj, 0) + + plane->surf_offset(plane_state); + } else { + plane_state->surf = i915_ggtt_offset(plane_state->ggtt_vma) + + plane->surf_offset(plane_state); + } + + return 0; +} + +void intel_plane_unpin_fb(struct intel_plane_state *old_plane_state) +{ + const struct intel_framebuffer *fb = + to_intel_framebuffer(old_plane_state->hw.fb); + struct i915_vma *vma; + + if (!intel_fb_uses_dpt(&fb->base)) { + vma = fetch_and_zero(&old_plane_state->ggtt_vma); + if (vma) + intel_fb_unpin_vma(vma, old_plane_state->flags); + } else { + vma = fetch_and_zero(&old_plane_state->dpt_vma); + if (vma) + intel_fb_unpin_vma(vma, old_plane_state->flags); + + vma = fetch_and_zero(&old_plane_state->ggtt_vma); + if (vma) + i915_dpt_unpin_from_ggtt(fb->dpt); + } +} + +void intel_fb_get_map(struct i915_vma *vma, struct iosys_map *map) +{ + iosys_map_set_vaddr_iomem(map, i915_vma_get_iomap(vma)); +} -- cgit v1.2.3 From 3823bf019d3b31ccd3e79860b7a3e20c719a1db4 Mon Sep 17 00:00:00 2001 From: Jani Nikula Date: Tue, 7 Apr 2026 13:04:36 +0300 Subject: drm/i915/pin: s/dev_priv/i915/ and drop struct drm_device usage MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Improve consistency within i915_fb_pin.c by replacing dev_priv naming with i915, and dropping struct drm_device usage. Reviewed-by: Ville Syrjälä Link: https://patch.msgid.link/3a4ac0a732a561a487e46838bde6327cff5ccb38.1775556190.git.jani.nikula@intel.com Signed-off-by: Jani Nikula --- drivers/gpu/drm/i915/i915_fb_pin.c | 24 +++++++++++------------- 1 file changed, 11 insertions(+), 13 deletions(-) diff --git a/drivers/gpu/drm/i915/i915_fb_pin.c b/drivers/gpu/drm/i915/i915_fb_pin.c index 580acbb14ada..9ef10cb3e3aa 100644 --- a/drivers/gpu/drm/i915/i915_fb_pin.c +++ b/drivers/gpu/drm/i915/i915_fb_pin.c @@ -30,9 +30,8 @@ intel_fb_pin_to_dpt(const struct drm_framebuffer *fb, unsigned long *out_flags, struct intel_dpt *dpt) { - struct drm_device *dev = fb->dev; - struct intel_display *display = to_intel_display(dev); - struct drm_i915_private *dev_priv = to_i915(dev); + struct intel_display *display = to_intel_display(fb->dev); + struct drm_i915_private *i915 = to_i915(fb->dev); struct drm_gem_object *_obj = intel_fb_bo(fb); struct drm_i915_gem_object *obj = to_intel_bo(_obj); struct i915_address_space *vm = i915_dpt_to_vm(dpt); @@ -44,7 +43,7 @@ intel_fb_pin_to_dpt(const struct drm_framebuffer *fb, * We are not syncing against the binding (and potential migrations) * below, so this vm must never be async. */ - if (drm_WARN_ON(&dev_priv->drm, vm->bind_async_flags)) + if (drm_WARN_ON(&i915->drm, vm->bind_async_flags)) return ERR_PTR(-EINVAL); if (WARN_ON(!i915_gem_object_is_framebuffer(obj))) @@ -57,7 +56,7 @@ intel_fb_pin_to_dpt(const struct drm_framebuffer *fb, if (ret) continue; - if (HAS_LMEM(dev_priv)) { + if (HAS_LMEM(i915)) { unsigned int flags = obj->flags; /* @@ -119,9 +118,8 @@ intel_fb_pin_to_ggtt(const struct drm_framebuffer *fb, bool uses_fence, unsigned long *out_flags) { - struct drm_device *dev = fb->dev; - struct intel_display *display = to_intel_display(dev); - struct drm_i915_private *dev_priv = to_i915(dev); + struct intel_display *display = to_intel_display(fb->dev); + struct drm_i915_private *i915 = to_i915(fb->dev); struct drm_gem_object *_obj = intel_fb_bo(fb); struct drm_i915_gem_object *obj = to_intel_bo(_obj); struct ref_tracker *wakeref; @@ -130,10 +128,10 @@ intel_fb_pin_to_ggtt(const struct drm_framebuffer *fb, unsigned int pinctl; int ret; - if (drm_WARN_ON(dev, !i915_gem_object_is_framebuffer(obj))) + if (drm_WARN_ON(&i915->drm, !i915_gem_object_is_framebuffer(obj))) return ERR_PTR(-EINVAL); - if (drm_WARN_ON(dev, alignment && !is_power_of_2(alignment))) + if (drm_WARN_ON(&i915->drm, alignment && !is_power_of_2(alignment))) return ERR_PTR(-EINVAL); /* @@ -164,7 +162,7 @@ retry: ret = i915_gem_object_lock(obj, &ww); if (!ret && phys_alignment) ret = i915_gem_object_attach_phys(obj, phys_alignment); - else if (!ret && HAS_LMEM(dev_priv)) + else if (!ret && HAS_LMEM(i915)) ret = i915_gem_object_migrate(obj, &ww, INTEL_REGION_LMEM_0); if (!ret) ret = i915_gem_object_pin_pages(obj); @@ -265,7 +263,7 @@ intel_plane_fb_vtd_guard(const struct intel_plane_state *plane_state) int intel_plane_pin_fb(struct intel_plane_state *plane_state, const struct intel_plane_state *old_plane_state) { - struct intel_display *display = to_intel_display(plane_state); + struct drm_i915_private *i915 = to_i915(plane_state->uapi.plane->dev); struct intel_plane *plane = to_intel_plane(plane_state->uapi.plane); const struct intel_framebuffer *fb = to_intel_framebuffer(plane_state->hw.fb); @@ -309,7 +307,7 @@ int intel_plane_pin_fb(struct intel_plane_state *plane_state, * The DPT object contains only one vma, and there is no VT-d * guard, so the VMA's offset within the DPT is always 0. */ - drm_WARN_ON(display->drm, i915_dpt_offset(plane_state->dpt_vma)); + drm_WARN_ON(&i915->drm, i915_dpt_offset(plane_state->dpt_vma)); } /* -- cgit v1.2.3 From e5bec90aade0166eff1ae10327ad0c71026eb582 Mon Sep 17 00:00:00 2001 From: Jani Nikula Date: Tue, 7 Apr 2026 13:04:37 +0300 Subject: drm/i915/pin: switch to i915 core runtime pm MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Remove a dependency on struct intel_display from i915 core code. Reviewed-by: Ville Syrjälä Link: https://patch.msgid.link/c06366c1c6f9202be5d0b6ea649c20aba414e5bc.1775556190.git.jani.nikula@intel.com Signed-off-by: Jani Nikula --- drivers/gpu/drm/i915/i915_fb_pin.c | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/drivers/gpu/drm/i915/i915_fb_pin.c b/drivers/gpu/drm/i915/i915_fb_pin.c index 9ef10cb3e3aa..1018f4b7bc2c 100644 --- a/drivers/gpu/drm/i915/i915_fb_pin.c +++ b/drivers/gpu/drm/i915/i915_fb_pin.c @@ -10,7 +10,6 @@ #include #include "display/intel_display_core.h" -#include "display/intel_display_rpm.h" #include "display/intel_display_types.h" #include "display/intel_fb.h" #include "display/intel_fb_pin.h" @@ -122,7 +121,7 @@ intel_fb_pin_to_ggtt(const struct drm_framebuffer *fb, struct drm_i915_private *i915 = to_i915(fb->dev); struct drm_gem_object *_obj = intel_fb_bo(fb); struct drm_i915_gem_object *obj = to_intel_bo(_obj); - struct ref_tracker *wakeref; + intel_wakeref_t wakeref; struct i915_gem_ww_ctx ww; struct i915_vma *vma; unsigned int pinctl; @@ -141,7 +140,7 @@ intel_fb_pin_to_ggtt(const struct drm_framebuffer *fb, * intel_runtime_pm_put(), so it is correct to wrap only the * pin/unpin/fence and not more. */ - wakeref = intel_display_rpm_get(display); + wakeref = intel_runtime_pm_get(&i915->runtime_pm); atomic_inc(&display->restore.pending_fb_pin); @@ -220,7 +219,7 @@ err: vma = ERR_PTR(ret); atomic_dec(&display->restore.pending_fb_pin); - intel_display_rpm_put(display, wakeref); + intel_runtime_pm_put(&i915->runtime_pm, wakeref); return vma; } -- cgit v1.2.3 From 102d44b3a8fad96e94e9ccd0579986c14a1f2f75 Mon Sep 17 00:00:00 2001 From: Suraj Kandpal Date: Tue, 7 Apr 2026 08:37:11 +0530 Subject: drm/i915/backlight: Fix VESA backlight possible check condition MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit VESA backlight enable is possible when BACKLIGHT_AUX_ENABLE_CAPABLE is true via AUX command or when BACKLIGHT_PIN_ENABLE_CAPABLE is true via eDP connector pin. Similarly, backlight brightness adjustment can be done via AUX-based control or PWM pin-based control. It means there can be three configurations: 1) Full AUX-based: Enable and adjustment both via AUX. We currently support this (apart from the AUX luminance-based backlight control). 2) Hybrid: Enable via the BL_ENABLE pin, adjustment via either AUX or PWM. 3) Fully PWM pin-based: Enable via the BL_ENABLE pin, adjustment via PWM. Since that only 1 is supported as of now we need to make sure we do not try to manipulate backlight when BACKLIGHT_AUX_ENABLE_CAPABLE is not set. Also fix return value when condition is not fulfilled. Closes: https://gitlab.freedesktop.org/drm/i915/kernel/-/work_items/15907 Fixes: 0fb03890d182 ("drm/i915/backlight: Check if VESA backlight is possible") Signed-off-by: Suraj Kandpal Tested-by: Ville Syrjälä Reviewed-by: Ankit Nautiyal Link: https://patch.msgid.link/20260407030710.1440046-1-suraj.kandpal@intel.com --- drivers/gpu/drm/i915/display/intel_dp_aux_backlight.c | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/drivers/gpu/drm/i915/display/intel_dp_aux_backlight.c b/drivers/gpu/drm/i915/display/intel_dp_aux_backlight.c index d0c76632a946..a8d56ebf06a2 100644 --- a/drivers/gpu/drm/i915/display/intel_dp_aux_backlight.c +++ b/drivers/gpu/drm/i915/display/intel_dp_aux_backlight.c @@ -615,8 +615,13 @@ check_if_vesa_backlight_possible(struct intel_dp *intel_dp) int ret; u8 bit_min, bit_max; - if (!(intel_dp->edp_dpcd[2] & DP_EDP_BACKLIGHT_BRIGHTNESS_AUX_SET_CAP)) - return true; + /* + * Since we only support Fully AUX Based VESA Backlight interface make sure + * backlight enable is possible via AUX along with backlight adjustment + */ + if (!(intel_dp->edp_dpcd[1] & DP_EDP_BACKLIGHT_AUX_ENABLE_CAP && + intel_dp->edp_dpcd[2] & DP_EDP_BACKLIGHT_BRIGHTNESS_AUX_SET_CAP)) + return false; ret = drm_dp_dpcd_read_byte(&intel_dp->aux, DP_EDP_PWMGEN_BIT_COUNT_CAP_MIN, &bit_min); if (ret < 0) -- cgit v1.2.3 From c95ac578846326994c8006713acaad77bc8edd38 Mon Sep 17 00:00:00 2001 From: Yicong Hui Date: Sun, 5 Apr 2026 20:23:09 +0100 Subject: drm/panthor: Fix kernel-doc warning in panthor_sched.c Fix the following W=1 kerneldoc warnings by adding the missing parameter descriptions for @ptdev and @events in panthor_sched_report_fw_events() and @ptdev in panthor_sched_report_mmu_fault() Warning: drivers/gpu/drm/panthor/panthor_sched.c:1898 function parameter 'ptdev' not described in 'panthor_sched_report_fw_events' Warning: drivers/gpu/drm/panthor/panthor_sched.c:1898 function parameter 'events' not described in 'panthor_sched_report_fw_events' Warning: drivers/gpu/drm/panthor/panthor_sched.c:2783 function parameter 'ptdev' not described in 'panthor_sched_report_mmu_fault' Fixes: de8548813824 ("drm/panthor: Add the scheduler logical block") Signed-off-by: Yicong Hui Reviewed-by: Boris Brezillon Reviewed-by: Steven Price Signed-off-by: Steven Price Link: https://patch.msgid.link/20260405192309.389039-1-yiconghui@gmail.com --- drivers/gpu/drm/panthor/panthor_sched.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/drivers/gpu/drm/panthor/panthor_sched.c b/drivers/gpu/drm/panthor/panthor_sched.c index 97581943a138..3bb1cb5a2656 100644 --- a/drivers/gpu/drm/panthor/panthor_sched.c +++ b/drivers/gpu/drm/panthor/panthor_sched.c @@ -1893,6 +1893,8 @@ static void process_fw_events_work(struct work_struct *work) /** * panthor_sched_report_fw_events() - Report FW events to the scheduler. + * @ptdev: Device. + * @events: Bitmask of pending FW events to report. */ void panthor_sched_report_fw_events(struct panthor_device *ptdev, u32 events) { @@ -2778,6 +2780,7 @@ static void panthor_group_start(struct panthor_group *group) /** * panthor_sched_report_mmu_fault() - Report MMU faults to the scheduler. + * @ptdev: Device. */ void panthor_sched_report_mmu_fault(struct panthor_device *ptdev) { -- cgit v1.2.3 From 94b1152fb80c1cba5d6706f0b5b2137511e57fbd Mon Sep 17 00:00:00 2001 From: Thomas Zimmermann Date: Fri, 27 Mar 2026 14:32:54 +0100 Subject: drm/ast: Move 32-bit register-access helpers to ast_drv.{c, h} The helpers ast_mindwm() and ast_moutdwm() access the I/O memory of the various IP modules on the Aspeed device. This is based on the "P-Bus to AHB Bridge" interface. Reimplement the access function with properly defined constants and helper macros. - Define P2A constants for the related registers and addresses. The P2A interface is located in the memory range at [0x00000000, 0x00010000]. - Memory access is segmented. An address' upper 16-bit select the memory segment, the lower 16-bit select the offset within the segment. Implement segment selection in a shared helper __ast_segsel(). Validate that the segment hs been changes. This logic has previously been part of __ast_moudwm() and __ast_mindwm(). Relax the CPU while busy-waiting. - Put intra-segment reads and writes in the helpers __ast_rdseg32() and __ast_wrseg32(). The helpers set the segment offset automatically. - Reimplement the existing interfaces on top of these helpers. Put the new implementation next to the other I/O helpers. v2: - fix typo in commit description (Jocelyn) Signed-off-by: Thomas Zimmermann Reviewed-by: Jocelyn Falempe Link: https://patch.msgid.link/20260327133532.79696-3-tzimmermann@suse.de --- drivers/gpu/drm/ast/ast_drv.c | 59 ++++++++++++++++++++++++++++++++++++++++++ drivers/gpu/drm/ast/ast_drv.h | 59 ++++++++++++++++++++++++++---------------- drivers/gpu/drm/ast/ast_post.c | 38 --------------------------- drivers/gpu/drm/ast/ast_post.h | 3 --- drivers/gpu/drm/ast/ast_reg.h | 12 +++++++++ 5 files changed, 108 insertions(+), 63 deletions(-) diff --git a/drivers/gpu/drm/ast/ast_drv.c b/drivers/gpu/drm/ast/ast_drv.c index b9a9b050b546..05ec3542ab62 100644 --- a/drivers/gpu/drm/ast/ast_drv.c +++ b/drivers/gpu/drm/ast/ast_drv.c @@ -47,6 +47,65 @@ static int ast_modeset = -1; MODULE_PARM_DESC(modeset, "Disable/Enable modesetting"); module_param_named(modeset, ast_modeset, int, 0400); +/* + * Register access + */ + +/* Select R/W segment */ +static void __ast_selseg(void __iomem *regs, u32 r) +{ + u32 p2a04, p2a04_base; + + p2a04 = r & AST_REG_P2A04_BASE_MASK; + __ast_write32(regs, AST_REG_P2A04, p2a04); + __ast_write32(regs, AST_REG_P2A00, AST_REG_P2A00_PROTECTION_KEY); + + do { + cpu_relax(); + p2a04_base = __ast_read32(regs, AST_REG_P2A04); + p2a04_base &= AST_REG_P2A04_BASE_MASK; + } while (p2a04_base != p2a04); +} + +/* Read within segment */ +static u32 __ast_rdseg32(void __iomem *regs, u32 r) +{ + return __ast_read32(regs, AST_REG_P2A_ADDR(r)); +} + +/* Write within segment */ +static void __ast_wrseg32(void __iomem *regs, u32 r, u32 v) +{ + __ast_write32(regs, AST_REG_P2A_ADDR(r), v); +} + +u32 __ast_mindwm(void __iomem *regs, u32 r) +{ + __ast_selseg(regs, r); + + return __ast_rdseg32(regs, r); +} + +void __ast_moutdwm(void __iomem *regs, u32 r, u32 v) +{ + __ast_selseg(regs, r); + __ast_wrseg32(regs, r, v); +} + +u32 ast_mindwm(struct ast_device *ast, u32 r) +{ + return __ast_mindwm(ast->regs, r); +} + +void ast_moutdwm(struct ast_device *ast, u32 r, u32 v) +{ + __ast_moutdwm(ast->regs, r, v); +} + +/* + * AST device + */ + void ast_device_init(struct ast_device *ast, enum ast_chip chip, enum ast_config_mode config_mode, diff --git a/drivers/gpu/drm/ast/ast_drv.h b/drivers/gpu/drm/ast/ast_drv.h index 787e38c6c17d..3eedf8239333 100644 --- a/drivers/gpu/drm/ast/ast_drv.h +++ b/drivers/gpu/drm/ast/ast_drv.h @@ -259,26 +259,20 @@ static inline bool __ast_gen_is_eq(struct ast_device *ast, unsigned long gen) #define IS_AST_GEN6(__ast) __ast_gen_is_eq(__ast, 6) #define IS_AST_GEN7(__ast) __ast_gen_is_eq(__ast, 7) +/* + * MMIO access + */ + static inline u8 __ast_read8(const void __iomem *addr, u32 reg) { return ioread8(addr + reg); } -static inline u32 __ast_read32(const void __iomem *addr, u32 reg) -{ - return ioread32(addr + reg); -} - static inline void __ast_write8(void __iomem *addr, u32 reg, u8 val) { iowrite8(val, addr + reg); } -static inline void __ast_write32(void __iomem *addr, u32 reg, u32 val) -{ - iowrite32(val, addr + reg); -} - static inline u8 __ast_read8_i(void __iomem *addr, u32 reg, u8 index) { __ast_write8(addr, reg, index); @@ -307,16 +301,6 @@ static inline void __ast_write8_i_masked(void __iomem *addr, u32 reg, u8 index, __ast_write8_i(addr, reg, index, tmp | val); } -static inline u32 ast_read32(struct ast_device *ast, u32 reg) -{ - return __ast_read32(ast->regs, reg); -} - -static inline void ast_write32(struct ast_device *ast, u32 reg, u32 val) -{ - __ast_write32(ast->regs, reg, val); -} - static inline u8 ast_io_read8(struct ast_device *ast, u32 reg) { return __ast_read8(ast->ioregs, reg); @@ -349,6 +333,39 @@ static inline void ast_set_index_reg_mask(struct ast_device *ast, u32 base, u8 i __ast_write8_i_masked(ast->ioregs, base, index, preserve_mask, val); } +/* + * Register access + */ + +static inline u32 __ast_read32(const void __iomem *addr, u32 reg) +{ + return ioread32(addr + reg); +} + +static inline void __ast_write32(void __iomem *addr, u32 reg, u32 val) +{ + iowrite32(val, addr + reg); +} + +static inline u32 ast_read32(struct ast_device *ast, u32 reg) +{ + return __ast_read32(ast->regs, reg); +} + +static inline void ast_write32(struct ast_device *ast, u32 reg, u32 val) +{ + __ast_write32(ast->regs, reg, val); +} + +u32 __ast_mindwm(void __iomem *regs, u32 r); +void __ast_moutdwm(void __iomem *regs, u32 r, u32 v); +u32 ast_mindwm(struct ast_device *ast, u32 r); +void ast_moutdwm(struct ast_device *ast, u32 r, u32 v); + +/* + * VBIOS + */ + struct ast_vbios_stdtable { u8 misc; u8 seq[4]; @@ -517,8 +534,6 @@ struct drm_device *ast_2600_device_create(struct pci_dev *pdev, /* ast post */ int ast_post_gpu(struct ast_device *ast); -u32 ast_mindwm(struct ast_device *ast, u32 r); -void ast_moutdwm(struct ast_device *ast, u32 r, u32 v); int ast_vga_output_init(struct ast_device *ast); int ast_sil164_output_init(struct ast_device *ast); diff --git a/drivers/gpu/drm/ast/ast_post.c b/drivers/gpu/drm/ast/ast_post.c index b72914dbed38..5cec5d735b6a 100644 --- a/drivers/gpu/drm/ast/ast_post.c +++ b/drivers/gpu/drm/ast/ast_post.c @@ -34,44 +34,6 @@ #include "ast_drv.h" #include "ast_post.h" -u32 __ast_mindwm(void __iomem *regs, u32 r) -{ - u32 data; - - __ast_write32(regs, 0xf004, r & 0xffff0000); - __ast_write32(regs, 0xf000, 0x1); - - do { - data = __ast_read32(regs, 0xf004) & 0xffff0000; - } while (data != (r & 0xffff0000)); - - return __ast_read32(regs, 0x10000 + (r & 0x0000ffff)); -} - -void __ast_moutdwm(void __iomem *regs, u32 r, u32 v) -{ - u32 data; - - __ast_write32(regs, 0xf004, r & 0xffff0000); - __ast_write32(regs, 0xf000, 0x1); - - do { - data = __ast_read32(regs, 0xf004) & 0xffff0000; - } while (data != (r & 0xffff0000)); - - __ast_write32(regs, 0x10000 + (r & 0x0000ffff), v); -} - -u32 ast_mindwm(struct ast_device *ast, u32 r) -{ - return __ast_mindwm(ast->regs, r); -} - -void ast_moutdwm(struct ast_device *ast, u32 r, u32 v) -{ - __ast_moutdwm(ast->regs, r, v); -} - int ast_post_gpu(struct ast_device *ast) { int ret; diff --git a/drivers/gpu/drm/ast/ast_post.h b/drivers/gpu/drm/ast/ast_post.h index aa5d247bebe8..41cd753b7f67 100644 --- a/drivers/gpu/drm/ast/ast_post.h +++ b/drivers/gpu/drm/ast/ast_post.h @@ -35,9 +35,6 @@ struct ast_dramstruct { #define AST_DRAMSTRUCT_IS(_entry, _name) \ ((_entry)->index == __AST_DRAMSTRUCT_INDEX(_name)) -u32 __ast_mindwm(void __iomem *regs, u32 r); -void __ast_moutdwm(void __iomem *regs, u32 r, u32 v); - bool mmc_test(struct ast_device *ast, u32 datagen, u8 test_ctl); bool mmc_test_burst(struct ast_device *ast, u32 datagen); diff --git a/drivers/gpu/drm/ast/ast_reg.h b/drivers/gpu/drm/ast/ast_reg.h index 30578e3b07e4..ca9403efc7f9 100644 --- a/drivers/gpu/drm/ast/ast_reg.h +++ b/drivers/gpu/drm/ast/ast_reg.h @@ -75,4 +75,16 @@ #define AST_IO_VGAIR1_R (0x5A) #define AST_IO_VGAIR1_VREFRESH BIT(3) +/* + * P-Bus to AHB Bridge (0x00000000 - 0x0001ffff) + */ + +#define AST_REG_P2A_BASE (0x00000000) +#define AST_REG_P2A(__offset) (AST_REG_P2A_BASE + (__offset)) +#define AST_REG_P2A_ADDR(__addr) AST_REG_P2A(0x10000 + ((__addr) & GENMASK(15, 0))) +#define AST_REG_P2A00 AST_REG_P2A(0xf000) +#define AST_REG_P2A00_PROTECTION_KEY (0x01) +#define AST_REG_P2A04 AST_REG_P2A(0xf004) +#define AST_REG_P2A04_BASE_MASK GENMASK(31, 16) + #endif -- cgit v1.2.3 From e1e31ef34f63bdbee392a5b02d590bacb2296595 Mon Sep 17 00:00:00 2001 From: Thomas Zimmermann Date: Fri, 27 Mar 2026 14:32:55 +0100 Subject: drm/ast: Use constants for AHBC registers AHBC is the Advanced High-Speed Bus Controller. AHBC registers are located in the memory range within [0x1e600000, 0x1e61ffff]. Refer to them with constants named AST_REG_AHBC, where is the byte offset into the range. Signed-off-by: Thomas Zimmermann Reviewed-by: Jocelyn Falempe Link: https://patch.msgid.link/20260327133532.79696-4-tzimmermann@suse.de --- drivers/gpu/drm/ast/ast_2500.c | 6 +++--- drivers/gpu/drm/ast/ast_reg.h | 11 +++++++++++ 2 files changed, 14 insertions(+), 3 deletions(-) diff --git a/drivers/gpu/drm/ast/ast_2500.c b/drivers/gpu/drm/ast/ast_2500.c index 2a52af0ded56..f751a27e7eb3 100644 --- a/drivers/gpu/drm/ast/ast_2500.c +++ b/drivers/gpu/drm/ast/ast_2500.c @@ -109,9 +109,9 @@ void ast_2500_patch_ahb(void __iomem *regs) u32 data; /* Clear bus lock condition */ - __ast_moutdwm(regs, 0x1e600000, 0xAEED1A03); - __ast_moutdwm(regs, 0x1e600084, 0x00010000); - __ast_moutdwm(regs, 0x1e600088, 0x00000000); + __ast_moutdwm(regs, AST_REG_AHBC00, AST_REG_AHBC00_PROTECT_KEY); + __ast_moutdwm(regs, AST_REG_AHBC84, 0x00010000); + __ast_moutdwm(regs, AST_REG_AHBC88, 0x00000000); __ast_moutdwm(regs, 0x1e6e2000, 0x1688A8A8); data = __ast_mindwm(regs, 0x1e6e2070); diff --git a/drivers/gpu/drm/ast/ast_reg.h b/drivers/gpu/drm/ast/ast_reg.h index ca9403efc7f9..0bc033dbac55 100644 --- a/drivers/gpu/drm/ast/ast_reg.h +++ b/drivers/gpu/drm/ast/ast_reg.h @@ -87,4 +87,15 @@ #define AST_REG_P2A04 AST_REG_P2A(0xf004) #define AST_REG_P2A04_BASE_MASK GENMASK(31, 16) +/* + * AHB Controller (0x1e600000 - 0x1e61ffff) + */ + +#define AST_REG_AHBC_BASE (0x1e600000) +#define AST_REG_AHBC(__offset) (AST_REG_AHBC_BASE + (__offset)) +#define AST_REG_AHBC00 AST_REG_AHBC(0x00) +#define AST_REG_AHBC00_PROTECT_KEY (0xaeed1a03) +#define AST_REG_AHBC84 AST_REG_AHBC(0x84) +#define AST_REG_AHBC88 AST_REG_AHBC(0x88) + #endif -- cgit v1.2.3 From 392993767d940fd3d0db35e64b5fcf4e00f2ea49 Mon Sep 17 00:00:00 2001 From: Thomas Zimmermann Date: Fri, 27 Mar 2026 14:32:56 +0100 Subject: drm/ast: Use constants for MCR registers SDRAM registers are located in the memory range at [0x1e160000, 0x1e160fff]. Refer to them with constants named AST_REG_MCR, where n is the byte offset into the range. Replacing the magic values in the ast driver was done with grep and sed as shown below git grep -l \,\ 0x1e6e00 | xargs sed -i -e 's/, 0x1e6e00/, AST_REG_MCR/g' git grep -l \,\ 0x1E6E00 | xargs sed -i -e 's/, 0x1E6E00/, AST_REG_MCR/g' plus some manual fixes. Signed-off-by: Thomas Zimmermann Reviewed-by: Jocelyn Falempe Link: https://patch.msgid.link/20260327133532.79696-5-tzimmermann@suse.de --- drivers/gpu/drm/ast/ast_2000.c | 2 +- drivers/gpu/drm/ast/ast_2100.c | 30 ++-- drivers/gpu/drm/ast/ast_2300.c | 330 ++++++++++++++++++++-------------------- drivers/gpu/drm/ast/ast_2500.c | 224 +++++++++++++-------------- drivers/gpu/drm/ast/ast_dp501.c | 6 +- drivers/gpu/drm/ast/ast_drv.c | 2 +- drivers/gpu/drm/ast/ast_post.c | 10 +- drivers/gpu/drm/ast/ast_reg.h | 71 +++++++++ 8 files changed, 373 insertions(+), 302 deletions(-) diff --git a/drivers/gpu/drm/ast/ast_2000.c b/drivers/gpu/drm/ast/ast_2000.c index fa3bc23ce098..204646bb1fa0 100644 --- a/drivers/gpu/drm/ast/ast_2000.c +++ b/drivers/gpu/drm/ast/ast_2000.c @@ -106,7 +106,7 @@ static void ast_post_chip_2000(struct ast_device *ast) if ((j & 0x80) == 0) { /* VGA only */ dram_reg_info = ast2000_dram_table_data; - ast_write32(ast, 0xf004, 0x1e6e0000); + ast_write32(ast, 0xf004, AST_REG_MCR00); ast_write32(ast, 0xf000, 0x1); ast_write32(ast, 0x10100, 0xa8); diff --git a/drivers/gpu/drm/ast/ast_2100.c b/drivers/gpu/drm/ast/ast_2100.c index 05aeb0624d41..28cd36571b7f 100644 --- a/drivers/gpu/drm/ast/ast_2100.c +++ b/drivers/gpu/drm/ast/ast_2100.c @@ -43,7 +43,7 @@ static enum ast_dram_layout ast_2100_get_dram_layout_p2a(struct ast_device *ast) u32 mcr_cfg; enum ast_dram_layout dram_layout; - ast_write32(ast, 0xf004, 0x1e6e0000); + ast_write32(ast, 0xf004, AST_REG_MCR00); ast_write32(ast, 0xf000, 0x1); mcr_cfg = ast_read32(ast, 0x10004); @@ -209,28 +209,28 @@ static u32 mmctestburst2_ast2150(struct ast_device *ast, u32 datagen) { u32 data, timeout; - ast_moutdwm(ast, 0x1e6e0070, 0x00000000); - ast_moutdwm(ast, 0x1e6e0070, 0x00000001 | (datagen << 3)); + ast_moutdwm(ast, AST_REG_MCR70, 0x00000000); + ast_moutdwm(ast, AST_REG_MCR70, 0x00000001 | (datagen << 3)); timeout = 0; do { - data = ast_mindwm(ast, 0x1e6e0070) & 0x40; + data = ast_mindwm(ast, AST_REG_MCR70) & 0x40; if (++timeout > TIMEOUT_AST2150) { - ast_moutdwm(ast, 0x1e6e0070, 0x00000000); + ast_moutdwm(ast, AST_REG_MCR70, 0x00000000); return 0xffffffff; } } while (!data); - ast_moutdwm(ast, 0x1e6e0070, 0x00000000); - ast_moutdwm(ast, 0x1e6e0070, 0x00000003 | (datagen << 3)); + ast_moutdwm(ast, AST_REG_MCR70, 0x00000000); + ast_moutdwm(ast, AST_REG_MCR70, 0x00000003 | (datagen << 3)); timeout = 0; do { - data = ast_mindwm(ast, 0x1e6e0070) & 0x40; + data = ast_mindwm(ast, AST_REG_MCR70) & 0x40; if (++timeout > TIMEOUT_AST2150) { - ast_moutdwm(ast, 0x1e6e0070, 0x00000000); + ast_moutdwm(ast, AST_REG_MCR70, 0x00000000); return 0xffffffff; } } while (!data); - data = (ast_mindwm(ast, 0x1e6e0070) & 0x80) >> 7; - ast_moutdwm(ast, 0x1e6e0070, 0x00000000); + data = (ast_mindwm(ast, AST_REG_MCR70) & 0x80) >> 7; + ast_moutdwm(ast, AST_REG_MCR70, 0x00000000); return data; } @@ -249,7 +249,7 @@ static int cbrscan_ast2150(struct ast_device *ast, int busw) u32 patcnt, loop; for (patcnt = 0; patcnt < CBR_PATNUM_AST2150; patcnt++) { - ast_moutdwm(ast, 0x1e6e007c, pattern_AST2150[patcnt]); + ast_moutdwm(ast, AST_REG_MCR7C, pattern_AST2150[patcnt]); for (loop = 0; loop < CBR_PASSNUM_AST2150; loop++) { if (cbrtest_ast2150(ast)) break; @@ -276,7 +276,7 @@ cbr_start: passcnt = 0; for (dlli = 0; dlli < 100; dlli++) { - ast_moutdwm(ast, 0x1e6e0068, dlli | (dlli << 8) | (dlli << 16) | (dlli << 24)); + ast_moutdwm(ast, AST_REG_MCR68, dlli | (dlli << 8) | (dlli << 16) | (dlli << 24)); data = cbrscan_ast2150(ast, busw); if (data != 0) { if (data & 0x1) { @@ -294,7 +294,7 @@ cbr_start: goto cbr_start; dlli = dll_min[0] + (((dll_max[0] - dll_min[0]) * 7) >> 4); - ast_moutdwm(ast, 0x1e6e0068, dlli | (dlli << 8) | (dlli << 16) | (dlli << 24)); + ast_moutdwm(ast, AST_REG_MCR68, dlli | (dlli << 8) | (dlli << 16) | (dlli << 24)); } static void ast_post_chip_2100(struct ast_device *ast) @@ -312,7 +312,7 @@ static void ast_post_chip_2100(struct ast_device *ast) else dram_reg_info = ast1100_dram_table_data; - ast_write32(ast, 0xf004, 0x1e6e0000); + ast_write32(ast, 0xf004, AST_REG_MCR00); ast_write32(ast, 0xf000, 0x1); ast_write32(ast, 0x12000, 0x1688A8A8); do { diff --git a/drivers/gpu/drm/ast/ast_2300.c b/drivers/gpu/drm/ast/ast_2300.c index 5f50d9f91ffd..56fe9e9f5c66 100644 --- a/drivers/gpu/drm/ast/ast_2300.c +++ b/drivers/gpu/drm/ast/ast_2300.c @@ -129,19 +129,19 @@ static u32 mmc_test2(struct ast_device *ast, u32 datagen, u8 test_ctl) { u32 data, timeout; - ast_moutdwm(ast, 0x1e6e0070, 0x00000000); - ast_moutdwm(ast, 0x1e6e0070, (datagen << 3) | test_ctl); + ast_moutdwm(ast, AST_REG_MCR70, 0x00000000); + ast_moutdwm(ast, AST_REG_MCR70, (datagen << 3) | test_ctl); timeout = 0; do { - data = ast_mindwm(ast, 0x1e6e0070) & 0x1000; + data = ast_mindwm(ast, AST_REG_MCR70) & 0x1000; if (++timeout > TIMEOUT) { - ast_moutdwm(ast, 0x1e6e0070, 0x0); + ast_moutdwm(ast, AST_REG_MCR70, 0x0); return 0xffffffff; } } while (!data); - data = ast_mindwm(ast, 0x1e6e0078); + data = ast_mindwm(ast, AST_REG_MCR78); data = (data | (data >> 16)) & 0xffff; - ast_moutdwm(ast, 0x1e6e0070, 0x00000000); + ast_moutdwm(ast, AST_REG_MCR70, 0x00000000); return data; } @@ -186,7 +186,7 @@ static int cbr_scan(struct ast_device *ast) data2 = 3; for (patcnt = 0; patcnt < CBR_PATNUM; patcnt++) { - ast_moutdwm(ast, 0x1e6e007c, pattern[patcnt]); + ast_moutdwm(ast, AST_REG_MCR7C, pattern[patcnt]); for (loop = 0; loop < CBR_PASSNUM2; loop++) { data = cbr_test(ast); if (data != 0) { @@ -222,7 +222,7 @@ static u32 cbr_scan2(struct ast_device *ast) data2 = 0xffff; for (patcnt = 0; patcnt < CBR_PATNUM; patcnt++) { - ast_moutdwm(ast, 0x1e6e007c, pattern[patcnt]); + ast_moutdwm(ast, AST_REG_MCR7C, pattern[patcnt]); for (loop = 0; loop < CBR_PASSNUM2; loop++) { data = cbr_test2(ast); if (data != 0) { @@ -252,7 +252,7 @@ static bool cbr_scan3(struct ast_device *ast) u32 patcnt, loop; for (patcnt = 0; patcnt < CBR_PATNUM; patcnt++) { - ast_moutdwm(ast, 0x1e6e007c, pattern[patcnt]); + ast_moutdwm(ast, AST_REG_MCR7C, pattern[patcnt]); for (loop = 0; loop < 2; loop++) { if (cbr_test3(ast)) break; @@ -274,8 +274,8 @@ FINETUNE_START: } passcnt = 0; for (dlli = 0; dlli < 76; dlli++) { - ast_moutdwm(ast, 0x1E6E0068, 0x00001400 | (dlli << 16) | (dlli << 24)); - ast_moutdwm(ast, 0x1E6E0074, CBR_SIZE1); + ast_moutdwm(ast, AST_REG_MCR68, 0x00001400 | (dlli << 16) | (dlli << 24)); + ast_moutdwm(ast, AST_REG_MCR74, CBR_SIZE1); data = cbr_scan2(ast); if (data != 0) { mask = 0x00010001; @@ -330,7 +330,7 @@ FINETUNE_DONE: data |= dlli << 21; } } - ast_moutdwm(ast, 0x1E6E0080, data); + ast_moutdwm(ast, AST_REG_MCR80, data); data = 0; for (cnt = 8; cnt < 16; cnt++) { @@ -354,7 +354,7 @@ FINETUNE_DONE: data |= dlli << 21; } } - ast_moutdwm(ast, 0x1E6E0084, data); + ast_moutdwm(ast, AST_REG_MCR84, data); return status; } /* finetuneDQI_L */ @@ -367,10 +367,10 @@ static void finetuneDQSI(struct ast_device *ast) char tag[2][76]; /* Disable DQI CBR */ - reg_mcr0c = ast_mindwm(ast, 0x1E6E000C); - reg_mcr18 = ast_mindwm(ast, 0x1E6E0018); + reg_mcr0c = ast_mindwm(ast, AST_REG_MCR0C); + reg_mcr18 = ast_mindwm(ast, AST_REG_MCR18); reg_mcr18 &= 0x0000ffff; - ast_moutdwm(ast, 0x1E6E0018, reg_mcr18); + ast_moutdwm(ast, AST_REG_MCR18, reg_mcr18); for (dlli = 0; dlli < 76; dlli++) { tag[0][dlli] = 0x0; @@ -386,14 +386,14 @@ static void finetuneDQSI(struct ast_device *ast) passcnt[0] = 0; passcnt[1] = 0; for (dqsip = 0; dqsip < 2; dqsip++) { - ast_moutdwm(ast, 0x1E6E000C, 0); - ast_moutdwm(ast, 0x1E6E0018, reg_mcr18 | (dqidly << 16) | (dqsip << 23)); - ast_moutdwm(ast, 0x1E6E000C, reg_mcr0c); + ast_moutdwm(ast, AST_REG_MCR0C, 0); + ast_moutdwm(ast, AST_REG_MCR18, reg_mcr18 | (dqidly << 16) | (dqsip << 23)); + ast_moutdwm(ast, AST_REG_MCR0C, reg_mcr0c); for (dlli = 0; dlli < 76; dlli++) { - ast_moutdwm(ast, 0x1E6E0068, + ast_moutdwm(ast, AST_REG_MCR68, 0x00001300 | (dlli << 16) | (dlli << 24)); - ast_moutdwm(ast, 0x1E6E0070, 0); - ast_moutdwm(ast, 0x1E6E0074, CBR_SIZE0); + ast_moutdwm(ast, AST_REG_MCR70, 0); + ast_moutdwm(ast, AST_REG_MCR74, CBR_SIZE0); if (cbr_scan3(ast)) { if (dlli == 0) break; @@ -457,7 +457,7 @@ static void finetuneDQSI(struct ast_device *ast) } } reg_mcr18 = reg_mcr18 | (g_dqidly << 16) | (g_dqsip << 23); - ast_moutdwm(ast, 0x1E6E0018, reg_mcr18); + ast_moutdwm(ast, AST_REG_MCR18, reg_mcr18); } static bool cbr_dll2(struct ast_device *ast, struct ast2300_dram_param *param) @@ -476,8 +476,8 @@ CBR_START2: dllmax[1] = 0x0; passcnt = 0; for (dlli = 0; dlli < 76; dlli++) { - ast_moutdwm(ast, 0x1E6E0068, 0x00001300 | (dlli << 16) | (dlli << 24)); - ast_moutdwm(ast, 0x1E6E0074, CBR_SIZE2); + ast_moutdwm(ast, AST_REG_MCR68, 0x00001300 | (dlli << 16) | (dlli << 24)); + ast_moutdwm(ast, AST_REG_MCR74, CBR_SIZE2); data = cbr_scan(ast); if (data != 0) { if (data & 0x1) { @@ -508,7 +508,7 @@ CBR_DONE2: dlli = (dllmin[1] + dllmax[1]) >> 1; dlli <<= 8; dlli += (dllmin[0] + dllmax[0]) >> 1; - ast_moutdwm(ast, 0x1E6E0068, ast_mindwm(ast, 0x1E720058) | (dlli << 16)); + ast_moutdwm(ast, AST_REG_MCR68, ast_mindwm(ast, 0x1E720058) | (dlli << 16)); return status; } /* CBRDLL2 */ @@ -758,115 +758,115 @@ static void ddr3_init(struct ast_device *ast, struct ast2300_dram_param *param) u32 data, data2, retry = 0; ddr3_init_start: - ast_moutdwm(ast, 0x1E6E0000, 0xFC600309); - ast_moutdwm(ast, 0x1E6E0018, 0x00000100); - ast_moutdwm(ast, 0x1E6E0024, 0x00000000); - ast_moutdwm(ast, 0x1E6E0034, 0x00000000); + ast_moutdwm(ast, AST_REG_MCR00, AST_REG_MCR00_PROTECTION_KEY); + ast_moutdwm(ast, AST_REG_MCR18, 0x00000100); + ast_moutdwm(ast, AST_REG_MCR24, 0x00000000); + ast_moutdwm(ast, AST_REG_MCR34, 0x00000000); udelay(10); - ast_moutdwm(ast, 0x1E6E0064, param->reg_MADJ); - ast_moutdwm(ast, 0x1E6E0068, param->reg_SADJ); + ast_moutdwm(ast, AST_REG_MCR64, param->reg_MADJ); + ast_moutdwm(ast, AST_REG_MCR68, param->reg_SADJ); udelay(10); - ast_moutdwm(ast, 0x1E6E0064, param->reg_MADJ | 0xC0000); + ast_moutdwm(ast, AST_REG_MCR64, param->reg_MADJ | 0xC0000); udelay(10); - ast_moutdwm(ast, 0x1E6E0004, param->dram_config); - ast_moutdwm(ast, 0x1E6E0008, 0x90040f); - ast_moutdwm(ast, 0x1E6E0010, param->reg_AC1); - ast_moutdwm(ast, 0x1E6E0014, param->reg_AC2); - ast_moutdwm(ast, 0x1E6E0020, param->reg_DQSIC); - ast_moutdwm(ast, 0x1E6E0080, 0x00000000); - ast_moutdwm(ast, 0x1E6E0084, 0x00000000); - ast_moutdwm(ast, 0x1E6E0088, param->reg_DQIDLY); - ast_moutdwm(ast, 0x1E6E0018, 0x4000A170); - ast_moutdwm(ast, 0x1E6E0018, 0x00002370); - ast_moutdwm(ast, 0x1E6E0038, 0x00000000); - ast_moutdwm(ast, 0x1E6E0040, 0xFF444444); - ast_moutdwm(ast, 0x1E6E0044, 0x22222222); - ast_moutdwm(ast, 0x1E6E0048, 0x22222222); - ast_moutdwm(ast, 0x1E6E004C, 0x00000002); - ast_moutdwm(ast, 0x1E6E0050, 0x80000000); - ast_moutdwm(ast, 0x1E6E0050, 0x00000000); - ast_moutdwm(ast, 0x1E6E0054, 0); - ast_moutdwm(ast, 0x1E6E0060, param->reg_DRV); - ast_moutdwm(ast, 0x1E6E006C, param->reg_IOZ); - ast_moutdwm(ast, 0x1E6E0070, 0x00000000); - ast_moutdwm(ast, 0x1E6E0074, 0x00000000); - ast_moutdwm(ast, 0x1E6E0078, 0x00000000); - ast_moutdwm(ast, 0x1E6E007C, 0x00000000); + ast_moutdwm(ast, AST_REG_MCR04, param->dram_config); + ast_moutdwm(ast, AST_REG_MCR08, 0x90040f); + ast_moutdwm(ast, AST_REG_MCR10, param->reg_AC1); + ast_moutdwm(ast, AST_REG_MCR14, param->reg_AC2); + ast_moutdwm(ast, AST_REG_MCR20, param->reg_DQSIC); + ast_moutdwm(ast, AST_REG_MCR80, 0x00000000); + ast_moutdwm(ast, AST_REG_MCR84, 0x00000000); + ast_moutdwm(ast, AST_REG_MCR88, param->reg_DQIDLY); + ast_moutdwm(ast, AST_REG_MCR18, 0x4000A170); + ast_moutdwm(ast, AST_REG_MCR18, 0x00002370); + ast_moutdwm(ast, AST_REG_MCR38, 0x00000000); + ast_moutdwm(ast, AST_REG_MCR40, 0xFF444444); + ast_moutdwm(ast, AST_REG_MCR44, 0x22222222); + ast_moutdwm(ast, AST_REG_MCR48, 0x22222222); + ast_moutdwm(ast, AST_REG_MCR4C, 0x00000002); + ast_moutdwm(ast, AST_REG_MCR50, 0x80000000); + ast_moutdwm(ast, AST_REG_MCR50, 0x00000000); + ast_moutdwm(ast, AST_REG_MCR54, 0); + ast_moutdwm(ast, AST_REG_MCR60, param->reg_DRV); + ast_moutdwm(ast, AST_REG_MCR6C, param->reg_IOZ); + ast_moutdwm(ast, AST_REG_MCR70, 0x00000000); + ast_moutdwm(ast, AST_REG_MCR74, 0x00000000); + ast_moutdwm(ast, AST_REG_MCR78, 0x00000000); + ast_moutdwm(ast, AST_REG_MCR7C, 0x00000000); /* Wait MCLK2X lock to MCLK */ do { - data = ast_mindwm(ast, 0x1E6E001C); + data = ast_mindwm(ast, AST_REG_MCR1C); } while (!(data & 0x08000000)); - data = ast_mindwm(ast, 0x1E6E001C); + data = ast_mindwm(ast, AST_REG_MCR1C); data = (data >> 8) & 0xff; while ((data & 0x08) || ((data & 0x7) < 2) || (data < 4)) { - data2 = (ast_mindwm(ast, 0x1E6E0064) & 0xfff3ffff) + 4; + data2 = (ast_mindwm(ast, AST_REG_MCR64) & 0xfff3ffff) + 4; if ((data2 & 0xff) > param->madj_max) break; - ast_moutdwm(ast, 0x1E6E0064, data2); + ast_moutdwm(ast, AST_REG_MCR64, data2); if (data2 & 0x00100000) data2 = ((data2 & 0xff) >> 3) + 3; else data2 = ((data2 & 0xff) >> 2) + 5; - data = ast_mindwm(ast, 0x1E6E0068) & 0xffff00ff; + data = ast_mindwm(ast, AST_REG_MCR68) & 0xffff00ff; data2 += data & 0xff; data = data | (data2 << 8); - ast_moutdwm(ast, 0x1E6E0068, data); + ast_moutdwm(ast, AST_REG_MCR68, data); udelay(10); - ast_moutdwm(ast, 0x1E6E0064, ast_mindwm(ast, 0x1E6E0064) | 0xC0000); + ast_moutdwm(ast, AST_REG_MCR64, ast_mindwm(ast, AST_REG_MCR64) | 0xC0000); udelay(10); - data = ast_mindwm(ast, 0x1E6E0018) & 0xfffff1ff; - ast_moutdwm(ast, 0x1E6E0018, data); + data = ast_mindwm(ast, AST_REG_MCR18) & 0xfffff1ff; + ast_moutdwm(ast, AST_REG_MCR18, data); data = data | 0x200; - ast_moutdwm(ast, 0x1E6E0018, data); + ast_moutdwm(ast, AST_REG_MCR18, data); do { - data = ast_mindwm(ast, 0x1E6E001C); + data = ast_mindwm(ast, AST_REG_MCR1C); } while (!(data & 0x08000000)); - data = ast_mindwm(ast, 0x1E6E001C); + data = ast_mindwm(ast, AST_REG_MCR1C); data = (data >> 8) & 0xff; } - ast_moutdwm(ast, 0x1E720058, ast_mindwm(ast, 0x1E6E0068) & 0xffff); - data = ast_mindwm(ast, 0x1E6E0018) | 0xC00; - ast_moutdwm(ast, 0x1E6E0018, data); + ast_moutdwm(ast, 0x1E720058, ast_mindwm(ast, AST_REG_MCR68) & 0xffff); + data = ast_mindwm(ast, AST_REG_MCR18) | 0xC00; + ast_moutdwm(ast, AST_REG_MCR18, data); - ast_moutdwm(ast, 0x1E6E0034, 0x00000001); - ast_moutdwm(ast, 0x1E6E000C, 0x00000040); + ast_moutdwm(ast, AST_REG_MCR34, 0x00000001); + ast_moutdwm(ast, AST_REG_MCR0C, 0x00000040); udelay(50); /* Mode Register Setting */ - ast_moutdwm(ast, 0x1E6E002C, param->reg_MRS | 0x100); - ast_moutdwm(ast, 0x1E6E0030, param->reg_EMRS); - ast_moutdwm(ast, 0x1E6E0028, 0x00000005); - ast_moutdwm(ast, 0x1E6E0028, 0x00000007); - ast_moutdwm(ast, 0x1E6E0028, 0x00000003); - ast_moutdwm(ast, 0x1E6E0028, 0x00000001); - ast_moutdwm(ast, 0x1E6E002C, param->reg_MRS); - ast_moutdwm(ast, 0x1E6E000C, 0x00005C08); - ast_moutdwm(ast, 0x1E6E0028, 0x00000001); - - ast_moutdwm(ast, 0x1E6E000C, 0x00005C01); + ast_moutdwm(ast, AST_REG_MCR2C, param->reg_MRS | 0x100); + ast_moutdwm(ast, AST_REG_MCR30, param->reg_EMRS); + ast_moutdwm(ast, AST_REG_MCR28, 0x00000005); + ast_moutdwm(ast, AST_REG_MCR28, 0x00000007); + ast_moutdwm(ast, AST_REG_MCR28, 0x00000003); + ast_moutdwm(ast, AST_REG_MCR28, 0x00000001); + ast_moutdwm(ast, AST_REG_MCR2C, param->reg_MRS); + ast_moutdwm(ast, AST_REG_MCR0C, 0x00005C08); + ast_moutdwm(ast, AST_REG_MCR28, 0x00000001); + + ast_moutdwm(ast, AST_REG_MCR0C, 0x00005C01); data = 0; if (param->wodt) data = 0x300; if (param->rodt) data = data | 0x3000 | ((param->reg_AC2 & 0x60000) >> 3); - ast_moutdwm(ast, 0x1E6E0034, data | 0x3); + ast_moutdwm(ast, AST_REG_MCR34, data | 0x3); /* Calibrate the DQSI delay */ if ((cbr_dll2(ast, param) == false) && (retry++ < 10)) goto ddr3_init_start; - ast_moutdwm(ast, 0x1E6E0120, param->reg_FREQ); + ast_moutdwm(ast, AST_REG_MCR120, param->reg_FREQ); /* ECC Memory Initialization */ #ifdef ECC - ast_moutdwm(ast, 0x1E6E007C, 0x00000000); - ast_moutdwm(ast, 0x1E6E0070, 0x221); + ast_moutdwm(ast, AST_REG_MCR7C, 0x00000000); + ast_moutdwm(ast, AST_REG_MCR70, 0x221); do { - data = ast_mindwm(ast, 0x1E6E0070); + data = ast_mindwm(ast, AST_REG_MCR70); } while (!(data & 0x00001000)); - ast_moutdwm(ast, 0x1E6E0070, 0x00000000); - ast_moutdwm(ast, 0x1E6E0050, 0x80000000); - ast_moutdwm(ast, 0x1E6E0050, 0x00000000); + ast_moutdwm(ast, AST_REG_MCR70, 0x00000000); + ast_moutdwm(ast, AST_REG_MCR50, 0x80000000); + ast_moutdwm(ast, AST_REG_MCR50, 0x00000000); #endif } @@ -1121,104 +1121,104 @@ static void ddr2_init(struct ast_device *ast, struct ast2300_dram_param *param) u32 data, data2, retry = 0; ddr2_init_start: - ast_moutdwm(ast, 0x1E6E0000, 0xFC600309); - ast_moutdwm(ast, 0x1E6E0018, 0x00000100); - ast_moutdwm(ast, 0x1E6E0024, 0x00000000); - ast_moutdwm(ast, 0x1E6E0064, param->reg_MADJ); - ast_moutdwm(ast, 0x1E6E0068, param->reg_SADJ); + ast_moutdwm(ast, AST_REG_MCR00, AST_REG_MCR00_PROTECTION_KEY); + ast_moutdwm(ast, AST_REG_MCR18, 0x00000100); + ast_moutdwm(ast, AST_REG_MCR24, 0x00000000); + ast_moutdwm(ast, AST_REG_MCR64, param->reg_MADJ); + ast_moutdwm(ast, AST_REG_MCR68, param->reg_SADJ); udelay(10); - ast_moutdwm(ast, 0x1E6E0064, param->reg_MADJ | 0xC0000); + ast_moutdwm(ast, AST_REG_MCR64, param->reg_MADJ | 0xC0000); udelay(10); - ast_moutdwm(ast, 0x1E6E0004, param->dram_config); - ast_moutdwm(ast, 0x1E6E0008, 0x90040f); - ast_moutdwm(ast, 0x1E6E0010, param->reg_AC1); - ast_moutdwm(ast, 0x1E6E0014, param->reg_AC2); - ast_moutdwm(ast, 0x1E6E0020, param->reg_DQSIC); - ast_moutdwm(ast, 0x1E6E0080, 0x00000000); - ast_moutdwm(ast, 0x1E6E0084, 0x00000000); - ast_moutdwm(ast, 0x1E6E0088, param->reg_DQIDLY); - ast_moutdwm(ast, 0x1E6E0018, 0x4000A130); - ast_moutdwm(ast, 0x1E6E0018, 0x00002330); - ast_moutdwm(ast, 0x1E6E0038, 0x00000000); - ast_moutdwm(ast, 0x1E6E0040, 0xFF808000); - ast_moutdwm(ast, 0x1E6E0044, 0x88848466); - ast_moutdwm(ast, 0x1E6E0048, 0x44440008); - ast_moutdwm(ast, 0x1E6E004C, 0x00000000); - ast_moutdwm(ast, 0x1E6E0050, 0x80000000); - ast_moutdwm(ast, 0x1E6E0050, 0x00000000); - ast_moutdwm(ast, 0x1E6E0054, 0); - ast_moutdwm(ast, 0x1E6E0060, param->reg_DRV); - ast_moutdwm(ast, 0x1E6E006C, param->reg_IOZ); - ast_moutdwm(ast, 0x1E6E0070, 0x00000000); - ast_moutdwm(ast, 0x1E6E0074, 0x00000000); - ast_moutdwm(ast, 0x1E6E0078, 0x00000000); - ast_moutdwm(ast, 0x1E6E007C, 0x00000000); + ast_moutdwm(ast, AST_REG_MCR04, param->dram_config); + ast_moutdwm(ast, AST_REG_MCR08, 0x90040f); + ast_moutdwm(ast, AST_REG_MCR10, param->reg_AC1); + ast_moutdwm(ast, AST_REG_MCR14, param->reg_AC2); + ast_moutdwm(ast, AST_REG_MCR20, param->reg_DQSIC); + ast_moutdwm(ast, AST_REG_MCR80, 0x00000000); + ast_moutdwm(ast, AST_REG_MCR84, 0x00000000); + ast_moutdwm(ast, AST_REG_MCR88, param->reg_DQIDLY); + ast_moutdwm(ast, AST_REG_MCR18, 0x4000A130); + ast_moutdwm(ast, AST_REG_MCR18, 0x00002330); + ast_moutdwm(ast, AST_REG_MCR38, 0x00000000); + ast_moutdwm(ast, AST_REG_MCR40, 0xFF808000); + ast_moutdwm(ast, AST_REG_MCR44, 0x88848466); + ast_moutdwm(ast, AST_REG_MCR48, 0x44440008); + ast_moutdwm(ast, AST_REG_MCR4C, 0x00000000); + ast_moutdwm(ast, AST_REG_MCR50, 0x80000000); + ast_moutdwm(ast, AST_REG_MCR50, 0x00000000); + ast_moutdwm(ast, AST_REG_MCR54, 0); + ast_moutdwm(ast, AST_REG_MCR60, param->reg_DRV); + ast_moutdwm(ast, AST_REG_MCR6C, param->reg_IOZ); + ast_moutdwm(ast, AST_REG_MCR70, 0x00000000); + ast_moutdwm(ast, AST_REG_MCR74, 0x00000000); + ast_moutdwm(ast, AST_REG_MCR78, 0x00000000); + ast_moutdwm(ast, AST_REG_MCR7C, 0x00000000); /* Wait MCLK2X lock to MCLK */ do { - data = ast_mindwm(ast, 0x1E6E001C); + data = ast_mindwm(ast, AST_REG_MCR1C); } while (!(data & 0x08000000)); - data = ast_mindwm(ast, 0x1E6E001C); + data = ast_mindwm(ast, AST_REG_MCR1C); data = (data >> 8) & 0xff; while ((data & 0x08) || ((data & 0x7) < 2) || (data < 4)) { - data2 = (ast_mindwm(ast, 0x1E6E0064) & 0xfff3ffff) + 4; + data2 = (ast_mindwm(ast, AST_REG_MCR64) & 0xfff3ffff) + 4; if ((data2 & 0xff) > param->madj_max) break; - ast_moutdwm(ast, 0x1E6E0064, data2); + ast_moutdwm(ast, AST_REG_MCR64, data2); if (data2 & 0x00100000) data2 = ((data2 & 0xff) >> 3) + 3; else data2 = ((data2 & 0xff) >> 2) + 5; - data = ast_mindwm(ast, 0x1E6E0068) & 0xffff00ff; + data = ast_mindwm(ast, AST_REG_MCR68) & 0xffff00ff; data2 += data & 0xff; data = data | (data2 << 8); - ast_moutdwm(ast, 0x1E6E0068, data); + ast_moutdwm(ast, AST_REG_MCR68, data); udelay(10); - ast_moutdwm(ast, 0x1E6E0064, ast_mindwm(ast, 0x1E6E0064) | 0xC0000); + ast_moutdwm(ast, AST_REG_MCR64, ast_mindwm(ast, AST_REG_MCR64) | 0xC0000); udelay(10); - data = ast_mindwm(ast, 0x1E6E0018) & 0xfffff1ff; - ast_moutdwm(ast, 0x1E6E0018, data); + data = ast_mindwm(ast, AST_REG_MCR18) & 0xfffff1ff; + ast_moutdwm(ast, AST_REG_MCR18, data); data = data | 0x200; - ast_moutdwm(ast, 0x1E6E0018, data); + ast_moutdwm(ast, AST_REG_MCR18, data); do { - data = ast_mindwm(ast, 0x1E6E001C); + data = ast_mindwm(ast, AST_REG_MCR1C); } while (!(data & 0x08000000)); - data = ast_mindwm(ast, 0x1E6E001C); + data = ast_mindwm(ast, AST_REG_MCR1C); data = (data >> 8) & 0xff; } - ast_moutdwm(ast, 0x1E720058, ast_mindwm(ast, 0x1E6E0008) & 0xffff); - data = ast_mindwm(ast, 0x1E6E0018) | 0xC00; - ast_moutdwm(ast, 0x1E6E0018, data); + ast_moutdwm(ast, 0x1E720058, ast_mindwm(ast, AST_REG_MCR08) & 0xffff); + data = ast_mindwm(ast, AST_REG_MCR18) | 0xC00; + ast_moutdwm(ast, AST_REG_MCR18, data); - ast_moutdwm(ast, 0x1E6E0034, 0x00000001); - ast_moutdwm(ast, 0x1E6E000C, 0x00000000); + ast_moutdwm(ast, AST_REG_MCR34, 0x00000001); + ast_moutdwm(ast, AST_REG_MCR0C, 0x00000000); udelay(50); /* Mode Register Setting */ - ast_moutdwm(ast, 0x1E6E002C, param->reg_MRS | 0x100); - ast_moutdwm(ast, 0x1E6E0030, param->reg_EMRS); - ast_moutdwm(ast, 0x1E6E0028, 0x00000005); - ast_moutdwm(ast, 0x1E6E0028, 0x00000007); - ast_moutdwm(ast, 0x1E6E0028, 0x00000003); - ast_moutdwm(ast, 0x1E6E0028, 0x00000001); - - ast_moutdwm(ast, 0x1E6E000C, 0x00005C08); - ast_moutdwm(ast, 0x1E6E002C, param->reg_MRS); - ast_moutdwm(ast, 0x1E6E0028, 0x00000001); - ast_moutdwm(ast, 0x1E6E0030, param->reg_EMRS | 0x380); - ast_moutdwm(ast, 0x1E6E0028, 0x00000003); - ast_moutdwm(ast, 0x1E6E0030, param->reg_EMRS); - ast_moutdwm(ast, 0x1E6E0028, 0x00000003); - - ast_moutdwm(ast, 0x1E6E000C, 0x7FFF5C01); + ast_moutdwm(ast, AST_REG_MCR2C, param->reg_MRS | 0x100); + ast_moutdwm(ast, AST_REG_MCR30, param->reg_EMRS); + ast_moutdwm(ast, AST_REG_MCR28, 0x00000005); + ast_moutdwm(ast, AST_REG_MCR28, 0x00000007); + ast_moutdwm(ast, AST_REG_MCR28, 0x00000003); + ast_moutdwm(ast, AST_REG_MCR28, 0x00000001); + + ast_moutdwm(ast, AST_REG_MCR0C, 0x00005C08); + ast_moutdwm(ast, AST_REG_MCR2C, param->reg_MRS); + ast_moutdwm(ast, AST_REG_MCR28, 0x00000001); + ast_moutdwm(ast, AST_REG_MCR30, param->reg_EMRS | 0x380); + ast_moutdwm(ast, AST_REG_MCR28, 0x00000003); + ast_moutdwm(ast, AST_REG_MCR30, param->reg_EMRS); + ast_moutdwm(ast, AST_REG_MCR28, 0x00000003); + + ast_moutdwm(ast, AST_REG_MCR0C, 0x7FFF5C01); data = 0; if (param->wodt) data = 0x500; if (param->rodt) data = data | 0x3000 | ((param->reg_AC2 & 0x60000) >> 3); - ast_moutdwm(ast, 0x1E6E0034, data | 0x3); - ast_moutdwm(ast, 0x1E6E0120, param->reg_FREQ); + ast_moutdwm(ast, AST_REG_MCR34, data | 0x3); + ast_moutdwm(ast, AST_REG_MCR120, param->reg_FREQ); /* Calibrate the DQSI delay */ if ((cbr_dll2(ast, param) == false) && (retry++ < 10)) @@ -1226,14 +1226,14 @@ ddr2_init_start: /* ECC Memory Initialization */ #ifdef ECC - ast_moutdwm(ast, 0x1E6E007C, 0x00000000); - ast_moutdwm(ast, 0x1E6E0070, 0x221); + ast_moutdwm(ast, AST_REG_MCR7C, 0x00000000); + ast_moutdwm(ast, AST_REG_MCR70, 0x221); do { - data = ast_mindwm(ast, 0x1E6E0070); + data = ast_mindwm(ast, AST_REG_MCR70); } while (!(data & 0x00001000)); - ast_moutdwm(ast, 0x1E6E0070, 0x00000000); - ast_moutdwm(ast, 0x1E6E0050, 0x80000000); - ast_moutdwm(ast, 0x1E6E0050, 0x00000000); + ast_moutdwm(ast, AST_REG_MCR70, 0x00000000); + ast_moutdwm(ast, AST_REG_MCR50, 0x80000000); + ast_moutdwm(ast, AST_REG_MCR50, 0x00000000); #endif } @@ -1245,7 +1245,7 @@ static void ast_post_chip_2300(struct ast_device *ast) reg = ast_get_index_reg_mask(ast, AST_IO_VGACRI, 0xd0, 0xff); if ((reg & 0x80) == 0) {/* vga only */ - ast_write32(ast, 0xf004, 0x1e6e0000); + ast_write32(ast, 0xf004, AST_REG_MCR00); ast_write32(ast, 0xf000, 0x1); ast_write32(ast, 0x12000, 0x1688a8a8); do { diff --git a/drivers/gpu/drm/ast/ast_2500.c b/drivers/gpu/drm/ast/ast_2500.c index f751a27e7eb3..4a9df920509f 100644 --- a/drivers/gpu/drm/ast/ast_2500.c +++ b/drivers/gpu/drm/ast/ast_2500.c @@ -148,8 +148,8 @@ static bool mmc_test_single_2500(struct ast_device *ast, u32 datagen) static bool cbr_test_2500(struct ast_device *ast) { - ast_moutdwm(ast, 0x1E6E0074, 0x0000FFFF); - ast_moutdwm(ast, 0x1E6E007C, 0xFF00FF00); + ast_moutdwm(ast, AST_REG_MCR74, 0x0000FFFF); + ast_moutdwm(ast, AST_REG_MCR7C, 0xFF00FF00); if (!mmc_test_burst(ast, 0)) return false; if (!mmc_test_single_2500(ast, 0)) @@ -159,8 +159,8 @@ static bool cbr_test_2500(struct ast_device *ast) static bool ddr_test_2500(struct ast_device *ast) { - ast_moutdwm(ast, 0x1E6E0074, 0x0000FFFF); - ast_moutdwm(ast, 0x1E6E007C, 0xFF00FF00); + ast_moutdwm(ast, AST_REG_MCR74, 0x0000FFFF); + ast_moutdwm(ast, AST_REG_MCR7C, 0xFF00FF00); if (!mmc_test_burst(ast, 0)) return false; if (!mmc_test_burst(ast, 1)) @@ -176,25 +176,25 @@ static bool ddr_test_2500(struct ast_device *ast) static void ddr_init_common_2500(struct ast_device *ast) { - ast_moutdwm(ast, 0x1E6E0034, 0x00020080); - ast_moutdwm(ast, 0x1E6E0008, 0x2003000F); - ast_moutdwm(ast, 0x1E6E0038, 0x00000FFF); - ast_moutdwm(ast, 0x1E6E0040, 0x88448844); - ast_moutdwm(ast, 0x1E6E0044, 0x24422288); - ast_moutdwm(ast, 0x1E6E0048, 0x22222222); - ast_moutdwm(ast, 0x1E6E004C, 0x22222222); - ast_moutdwm(ast, 0x1E6E0050, 0x80000000); - ast_moutdwm(ast, 0x1E6E0208, 0x00000000); - ast_moutdwm(ast, 0x1E6E0218, 0x00000000); - ast_moutdwm(ast, 0x1E6E0220, 0x00000000); - ast_moutdwm(ast, 0x1E6E0228, 0x00000000); - ast_moutdwm(ast, 0x1E6E0230, 0x00000000); - ast_moutdwm(ast, 0x1E6E02A8, 0x00000000); - ast_moutdwm(ast, 0x1E6E02B0, 0x00000000); - ast_moutdwm(ast, 0x1E6E0240, 0x86000000); - ast_moutdwm(ast, 0x1E6E0244, 0x00008600); - ast_moutdwm(ast, 0x1E6E0248, 0x80000000); - ast_moutdwm(ast, 0x1E6E024C, 0x80808080); + ast_moutdwm(ast, AST_REG_MCR34, 0x00020080); + ast_moutdwm(ast, AST_REG_MCR08, 0x2003000F); + ast_moutdwm(ast, AST_REG_MCR38, 0x00000FFF); + ast_moutdwm(ast, AST_REG_MCR40, 0x88448844); + ast_moutdwm(ast, AST_REG_MCR44, 0x24422288); + ast_moutdwm(ast, AST_REG_MCR48, 0x22222222); + ast_moutdwm(ast, AST_REG_MCR4C, 0x22222222); + ast_moutdwm(ast, AST_REG_MCR50, 0x80000000); + ast_moutdwm(ast, AST_REG_MCR208, 0x00000000); + ast_moutdwm(ast, AST_REG_MCR218, 0x00000000); + ast_moutdwm(ast, AST_REG_MCR220, 0x00000000); + ast_moutdwm(ast, AST_REG_MCR228, 0x00000000); + ast_moutdwm(ast, AST_REG_MCR230, 0x00000000); + ast_moutdwm(ast, AST_REG_MCR2A8, 0x00000000); + ast_moutdwm(ast, AST_REG_MCR2B0, 0x00000000); + ast_moutdwm(ast, AST_REG_MCR240, 0x86000000); + ast_moutdwm(ast, AST_REG_MCR244, 0x00008600); + ast_moutdwm(ast, AST_REG_MCR248, 0x80000000); + ast_moutdwm(ast, AST_REG_MCR24C, 0x80808080); } static void ddr_phy_init_2500(struct ast_device *ast) @@ -202,26 +202,26 @@ static void ddr_phy_init_2500(struct ast_device *ast) u32 data, pass, timecnt; pass = 0; - ast_moutdwm(ast, 0x1E6E0060, 0x00000005); + ast_moutdwm(ast, AST_REG_MCR60, 0x00000005); while (!pass) { for (timecnt = 0; timecnt < TIMEOUT; timecnt++) { - data = ast_mindwm(ast, 0x1E6E0060) & 0x1; + data = ast_mindwm(ast, AST_REG_MCR60) & 0x1; if (!data) break; } if (timecnt != TIMEOUT) { - data = ast_mindwm(ast, 0x1E6E0300) & 0x000A0000; + data = ast_mindwm(ast, AST_REG_MCR300) & 0x000A0000; if (!data) pass = 1; } if (!pass) { - ast_moutdwm(ast, 0x1E6E0060, 0x00000000); + ast_moutdwm(ast, AST_REG_MCR60, 0x00000000); udelay(10); /* delay 10 us */ - ast_moutdwm(ast, 0x1E6E0060, 0x00000005); + ast_moutdwm(ast, AST_REG_MCR60, 0x00000005); } } - ast_moutdwm(ast, 0x1E6E0060, 0x00000006); + ast_moutdwm(ast, AST_REG_MCR60, 0x00000006); } /* @@ -235,8 +235,8 @@ static void check_dram_size_2500(struct ast_device *ast, u32 tRFC) { u32 reg_04, reg_14; - reg_04 = ast_mindwm(ast, 0x1E6E0004) & 0xfffffffc; - reg_14 = ast_mindwm(ast, 0x1E6E0014) & 0xffffff00; + reg_04 = ast_mindwm(ast, AST_REG_MCR04) & 0xfffffffc; + reg_14 = ast_mindwm(ast, AST_REG_MCR14) & 0xffffff00; ast_moutdwm(ast, 0xA0100000, 0x41424344); ast_moutdwm(ast, 0x90100000, 0x35363738); @@ -258,21 +258,21 @@ static void check_dram_size_2500(struct ast_device *ast, u32 tRFC) } else { reg_14 |= tRFC & 0xFF; } - ast_moutdwm(ast, 0x1E6E0004, reg_04); - ast_moutdwm(ast, 0x1E6E0014, reg_14); + ast_moutdwm(ast, AST_REG_MCR04, reg_04); + ast_moutdwm(ast, AST_REG_MCR14, reg_14); } static void enable_cache_2500(struct ast_device *ast) { u32 reg_04, data; - reg_04 = ast_mindwm(ast, 0x1E6E0004); - ast_moutdwm(ast, 0x1E6E0004, reg_04 | 0x1000); + reg_04 = ast_mindwm(ast, AST_REG_MCR04); + ast_moutdwm(ast, AST_REG_MCR04, reg_04 | 0x1000); do - data = ast_mindwm(ast, 0x1E6E0004); + data = ast_mindwm(ast, AST_REG_MCR04); while (!(data & 0x80000)); - ast_moutdwm(ast, 0x1E6E0004, reg_04 | 0x400); + ast_moutdwm(ast, AST_REG_MCR04, reg_04 | 0x400); } static void set_mpll_2500(struct ast_device *ast) @@ -280,13 +280,13 @@ static void set_mpll_2500(struct ast_device *ast) u32 addr, data, param; /* Reset MMC */ - ast_moutdwm(ast, 0x1E6E0000, 0xFC600309); - ast_moutdwm(ast, 0x1E6E0034, 0x00020080); + ast_moutdwm(ast, AST_REG_MCR00, AST_REG_MCR00_PROTECTION_KEY); + ast_moutdwm(ast, AST_REG_MCR34, 0x00020080); for (addr = 0x1e6e0004; addr < 0x1e6e0090;) { ast_moutdwm(ast, addr, 0x0); addr += 4; } - ast_moutdwm(ast, 0x1E6E0034, 0x00020000); + ast_moutdwm(ast, AST_REG_MCR34, 0x00020000); ast_moutdwm(ast, 0x1E6E2000, 0x1688A8A8); data = ast_mindwm(ast, 0x1E6E2070) & 0x00800000; @@ -310,50 +310,50 @@ static void reset_mmc_2500(struct ast_device *ast) ast_moutdwm(ast, 0x1E78504C, 0x00000013); mdelay(100); ast_moutdwm(ast, 0x1E785054, 0x00000077); - ast_moutdwm(ast, 0x1E6E0000, 0xFC600309); + ast_moutdwm(ast, AST_REG_MCR00, AST_REG_MCR00_PROTECTION_KEY); } static void ddr3_init_2500(struct ast_device *ast, const u32 *ddr_table) { - ast_moutdwm(ast, 0x1E6E0004, 0x00000303); - ast_moutdwm(ast, 0x1E6E0010, ddr_table[REGIDX_010]); - ast_moutdwm(ast, 0x1E6E0014, ddr_table[REGIDX_014]); - ast_moutdwm(ast, 0x1E6E0018, ddr_table[REGIDX_018]); - ast_moutdwm(ast, 0x1E6E0020, ddr_table[REGIDX_020]); /* MODEREG4/6 */ - ast_moutdwm(ast, 0x1E6E0024, ddr_table[REGIDX_024]); /* MODEREG5 */ - ast_moutdwm(ast, 0x1E6E002C, ddr_table[REGIDX_02C] | 0x100); /* MODEREG0/2 */ - ast_moutdwm(ast, 0x1E6E0030, ddr_table[REGIDX_030]); /* MODEREG1/3 */ + ast_moutdwm(ast, AST_REG_MCR04, 0x00000303); + ast_moutdwm(ast, AST_REG_MCR10, ddr_table[REGIDX_010]); + ast_moutdwm(ast, AST_REG_MCR14, ddr_table[REGIDX_014]); + ast_moutdwm(ast, AST_REG_MCR18, ddr_table[REGIDX_018]); + ast_moutdwm(ast, AST_REG_MCR20, ddr_table[REGIDX_020]); /* MODEREG4/6 */ + ast_moutdwm(ast, AST_REG_MCR24, ddr_table[REGIDX_024]); /* MODEREG5 */ + ast_moutdwm(ast, AST_REG_MCR2C, ddr_table[REGIDX_02C] | 0x100); /* MODEREG0/2 */ + ast_moutdwm(ast, AST_REG_MCR30, ddr_table[REGIDX_030]); /* MODEREG1/3 */ /* DDR PHY Setting */ - ast_moutdwm(ast, 0x1E6E0200, 0x02492AAE); - ast_moutdwm(ast, 0x1E6E0204, 0x00001001); - ast_moutdwm(ast, 0x1E6E020C, 0x55E00B0B); - ast_moutdwm(ast, 0x1E6E0210, 0x20000000); - ast_moutdwm(ast, 0x1E6E0214, ddr_table[REGIDX_214]); - ast_moutdwm(ast, 0x1E6E02E0, ddr_table[REGIDX_2E0]); - ast_moutdwm(ast, 0x1E6E02E4, ddr_table[REGIDX_2E4]); - ast_moutdwm(ast, 0x1E6E02E8, ddr_table[REGIDX_2E8]); - ast_moutdwm(ast, 0x1E6E02EC, ddr_table[REGIDX_2EC]); - ast_moutdwm(ast, 0x1E6E02F0, ddr_table[REGIDX_2F0]); - ast_moutdwm(ast, 0x1E6E02F4, ddr_table[REGIDX_2F4]); - ast_moutdwm(ast, 0x1E6E02F8, ddr_table[REGIDX_2F8]); - ast_moutdwm(ast, 0x1E6E0290, 0x00100008); - ast_moutdwm(ast, 0x1E6E02C0, 0x00000006); + ast_moutdwm(ast, AST_REG_MCR200, 0x02492AAE); + ast_moutdwm(ast, AST_REG_MCR204, 0x00001001); + ast_moutdwm(ast, AST_REG_MCR20C, 0x55E00B0B); + ast_moutdwm(ast, AST_REG_MCR210, 0x20000000); + ast_moutdwm(ast, AST_REG_MCR214, ddr_table[REGIDX_214]); + ast_moutdwm(ast, AST_REG_MCR2E0, ddr_table[REGIDX_2E0]); + ast_moutdwm(ast, AST_REG_MCR2E4, ddr_table[REGIDX_2E4]); + ast_moutdwm(ast, AST_REG_MCR2E8, ddr_table[REGIDX_2E8]); + ast_moutdwm(ast, AST_REG_MCR2EC, ddr_table[REGIDX_2EC]); + ast_moutdwm(ast, AST_REG_MCR2F0, ddr_table[REGIDX_2F0]); + ast_moutdwm(ast, AST_REG_MCR2F4, ddr_table[REGIDX_2F4]); + ast_moutdwm(ast, AST_REG_MCR2F8, ddr_table[REGIDX_2F8]); + ast_moutdwm(ast, AST_REG_MCR290, 0x00100008); + ast_moutdwm(ast, AST_REG_MCR2C0, 0x00000006); /* Controller Setting */ - ast_moutdwm(ast, 0x1E6E0034, 0x00020091); + ast_moutdwm(ast, AST_REG_MCR34, 0x00020091); /* Wait DDR PHY init done */ ddr_phy_init_2500(ast); - ast_moutdwm(ast, 0x1E6E0120, ddr_table[REGIDX_PLL]); - ast_moutdwm(ast, 0x1E6E000C, 0x42AA5C81); - ast_moutdwm(ast, 0x1E6E0034, 0x0001AF93); + ast_moutdwm(ast, AST_REG_MCR120, ddr_table[REGIDX_PLL]); + ast_moutdwm(ast, AST_REG_MCR0C, 0x42AA5C81); + ast_moutdwm(ast, AST_REG_MCR34, 0x0001AF93); check_dram_size_2500(ast, ddr_table[REGIDX_RFC]); enable_cache_2500(ast); - ast_moutdwm(ast, 0x1E6E001C, 0x00000008); - ast_moutdwm(ast, 0x1E6E0038, 0xFFFFFF00); + ast_moutdwm(ast, AST_REG_MCR1C, 0x00000008); + ast_moutdwm(ast, AST_REG_MCR38, 0xFFFFFF00); } static void ddr4_init_2500(struct ast_device *ast, const u32 *ddr_table) @@ -363,34 +363,34 @@ static void ddr4_init_2500(struct ast_device *ast, const u32 *ddr_table) u32 min_ddr_vref = 0, min_phy_vref = 0; u32 max_ddr_vref = 0, max_phy_vref = 0; - ast_moutdwm(ast, 0x1E6E0004, 0x00000313); - ast_moutdwm(ast, 0x1E6E0010, ddr_table[REGIDX_010]); - ast_moutdwm(ast, 0x1E6E0014, ddr_table[REGIDX_014]); - ast_moutdwm(ast, 0x1E6E0018, ddr_table[REGIDX_018]); - ast_moutdwm(ast, 0x1E6E0020, ddr_table[REGIDX_020]); /* MODEREG4/6 */ - ast_moutdwm(ast, 0x1E6E0024, ddr_table[REGIDX_024]); /* MODEREG5 */ - ast_moutdwm(ast, 0x1E6E002C, ddr_table[REGIDX_02C] | 0x100); /* MODEREG0/2 */ - ast_moutdwm(ast, 0x1E6E0030, ddr_table[REGIDX_030]); /* MODEREG1/3 */ + ast_moutdwm(ast, AST_REG_MCR04, 0x00000313); + ast_moutdwm(ast, AST_REG_MCR10, ddr_table[REGIDX_010]); + ast_moutdwm(ast, AST_REG_MCR14, ddr_table[REGIDX_014]); + ast_moutdwm(ast, AST_REG_MCR18, ddr_table[REGIDX_018]); + ast_moutdwm(ast, AST_REG_MCR20, ddr_table[REGIDX_020]); /* MODEREG4/6 */ + ast_moutdwm(ast, AST_REG_MCR24, ddr_table[REGIDX_024]); /* MODEREG5 */ + ast_moutdwm(ast, AST_REG_MCR2C, ddr_table[REGIDX_02C] | 0x100); /* MODEREG0/2 */ + ast_moutdwm(ast, AST_REG_MCR30, ddr_table[REGIDX_030]); /* MODEREG1/3 */ /* DDR PHY Setting */ - ast_moutdwm(ast, 0x1E6E0200, 0x42492AAE); - ast_moutdwm(ast, 0x1E6E0204, 0x09002000); - ast_moutdwm(ast, 0x1E6E020C, 0x55E00B0B); - ast_moutdwm(ast, 0x1E6E0210, 0x20000000); - ast_moutdwm(ast, 0x1E6E0214, ddr_table[REGIDX_214]); - ast_moutdwm(ast, 0x1E6E02E0, ddr_table[REGIDX_2E0]); - ast_moutdwm(ast, 0x1E6E02E4, ddr_table[REGIDX_2E4]); - ast_moutdwm(ast, 0x1E6E02E8, ddr_table[REGIDX_2E8]); - ast_moutdwm(ast, 0x1E6E02EC, ddr_table[REGIDX_2EC]); - ast_moutdwm(ast, 0x1E6E02F0, ddr_table[REGIDX_2F0]); - ast_moutdwm(ast, 0x1E6E02F4, ddr_table[REGIDX_2F4]); - ast_moutdwm(ast, 0x1E6E02F8, ddr_table[REGIDX_2F8]); - ast_moutdwm(ast, 0x1E6E0290, 0x00100008); - ast_moutdwm(ast, 0x1E6E02C4, 0x3C183C3C); - ast_moutdwm(ast, 0x1E6E02C8, 0x00631E0E); + ast_moutdwm(ast, AST_REG_MCR200, 0x42492AAE); + ast_moutdwm(ast, AST_REG_MCR204, 0x09002000); + ast_moutdwm(ast, AST_REG_MCR20C, 0x55E00B0B); + ast_moutdwm(ast, AST_REG_MCR210, 0x20000000); + ast_moutdwm(ast, AST_REG_MCR214, ddr_table[REGIDX_214]); + ast_moutdwm(ast, AST_REG_MCR2E0, ddr_table[REGIDX_2E0]); + ast_moutdwm(ast, AST_REG_MCR2E4, ddr_table[REGIDX_2E4]); + ast_moutdwm(ast, AST_REG_MCR2E8, ddr_table[REGIDX_2E8]); + ast_moutdwm(ast, AST_REG_MCR2EC, ddr_table[REGIDX_2EC]); + ast_moutdwm(ast, AST_REG_MCR2F0, ddr_table[REGIDX_2F0]); + ast_moutdwm(ast, AST_REG_MCR2F4, ddr_table[REGIDX_2F4]); + ast_moutdwm(ast, AST_REG_MCR2F8, ddr_table[REGIDX_2F8]); + ast_moutdwm(ast, AST_REG_MCR290, 0x00100008); + ast_moutdwm(ast, AST_REG_MCR2C4, 0x3C183C3C); + ast_moutdwm(ast, AST_REG_MCR2C8, 0x00631E0E); /* Controller Setting */ - ast_moutdwm(ast, 0x1E6E0034, 0x0001A991); + ast_moutdwm(ast, AST_REG_MCR34, 0x0001A991); /* Train PHY Vref first */ pass = 0; @@ -398,17 +398,17 @@ static void ddr4_init_2500(struct ast_device *ast, const u32 *ddr_table) for (retrycnt = 0; retrycnt < 4 && pass == 0; retrycnt++) { max_phy_vref = 0x0; pass = 0; - ast_moutdwm(ast, 0x1E6E02C0, 0x00001C06); + ast_moutdwm(ast, AST_REG_MCR2C0, 0x00001C06); for (phy_vref = 0x40; phy_vref < 0x80; phy_vref++) { - ast_moutdwm(ast, 0x1E6E000C, 0x00000000); - ast_moutdwm(ast, 0x1E6E0060, 0x00000000); - ast_moutdwm(ast, 0x1E6E02CC, phy_vref | (phy_vref << 8)); + ast_moutdwm(ast, AST_REG_MCR0C, 0x00000000); + ast_moutdwm(ast, AST_REG_MCR60, 0x00000000); + ast_moutdwm(ast, AST_REG_MCR2CC, phy_vref | (phy_vref << 8)); /* Fire DFI Init */ ddr_phy_init_2500(ast); - ast_moutdwm(ast, 0x1E6E000C, 0x00005C01); + ast_moutdwm(ast, AST_REG_MCR0C, 0x00005C01); if (cbr_test_2500(ast)) { pass++; - data = ast_mindwm(ast, 0x1E6E03D0); + data = ast_mindwm(ast, AST_REG_MCR3D0); data2 = data >> 8; data = data & 0xff; if (data > data2) @@ -422,7 +422,7 @@ static void ddr4_init_2500(struct ast_device *ast, const u32 *ddr_table) } } } - ast_moutdwm(ast, 0x1E6E02CC, min_phy_vref | (min_phy_vref << 8)); + ast_moutdwm(ast, AST_REG_MCR2CC, min_phy_vref | (min_phy_vref << 8)); /* Train DDR Vref next */ pass = 0; @@ -432,12 +432,12 @@ static void ddr4_init_2500(struct ast_device *ast, const u32 *ddr_table) max_ddr_vref = 0x0; pass = 0; for (ddr_vref = 0x00; ddr_vref < 0x40; ddr_vref++) { - ast_moutdwm(ast, 0x1E6E000C, 0x00000000); - ast_moutdwm(ast, 0x1E6E0060, 0x00000000); - ast_moutdwm(ast, 0x1E6E02C0, 0x00000006 | (ddr_vref << 8)); + ast_moutdwm(ast, AST_REG_MCR0C, 0x00000000); + ast_moutdwm(ast, AST_REG_MCR60, 0x00000000); + ast_moutdwm(ast, AST_REG_MCR2C0, 0x00000006 | (ddr_vref << 8)); /* Fire DFI Init */ ddr_phy_init_2500(ast); - ast_moutdwm(ast, 0x1E6E000C, 0x00005C01); + ast_moutdwm(ast, AST_REG_MCR0C, 0x00005C01); if (cbr_test_2500(ast)) { pass++; if (min_ddr_vref > ddr_vref) @@ -450,22 +450,22 @@ static void ddr4_init_2500(struct ast_device *ast, const u32 *ddr_table) } } - ast_moutdwm(ast, 0x1E6E000C, 0x00000000); - ast_moutdwm(ast, 0x1E6E0060, 0x00000000); + ast_moutdwm(ast, AST_REG_MCR0C, 0x00000000); + ast_moutdwm(ast, AST_REG_MCR60, 0x00000000); ddr_vref = (min_ddr_vref + max_ddr_vref + 1) >> 1; - ast_moutdwm(ast, 0x1E6E02C0, 0x00000006 | (ddr_vref << 8)); + ast_moutdwm(ast, AST_REG_MCR2C0, 0x00000006 | (ddr_vref << 8)); /* Wait DDR PHY init done */ ddr_phy_init_2500(ast); - ast_moutdwm(ast, 0x1E6E0120, ddr_table[REGIDX_PLL]); - ast_moutdwm(ast, 0x1E6E000C, 0x42AA5C81); - ast_moutdwm(ast, 0x1E6E0034, 0x0001AF93); + ast_moutdwm(ast, AST_REG_MCR120, ddr_table[REGIDX_PLL]); + ast_moutdwm(ast, AST_REG_MCR0C, 0x42AA5C81); + ast_moutdwm(ast, AST_REG_MCR34, 0x0001AF93); check_dram_size_2500(ast, ddr_table[REGIDX_RFC]); enable_cache_2500(ast); - ast_moutdwm(ast, 0x1E6E001C, 0x00000008); - ast_moutdwm(ast, 0x1E6E0038, 0xFFFFFF00); + ast_moutdwm(ast, AST_REG_MCR1C, 0x00000008); + ast_moutdwm(ast, AST_REG_MCR38, 0xFFFFFF00); } static bool ast_dram_init_2500(struct ast_device *ast) diff --git a/drivers/gpu/drm/ast/ast_dp501.c b/drivers/gpu/drm/ast/ast_dp501.c index 677c52c0d99a..8c2243cf8187 100644 --- a/drivers/gpu/drm/ast/ast_dp501.c +++ b/drivers/gpu/drm/ast/ast_dp501.c @@ -230,7 +230,7 @@ static bool ast_launch_m68k(struct ast_device *ast) } /* Get BootAddress */ ast_moutdwm(ast, 0x1e6e2000, 0x1688a8a8); - data = ast_mindwm(ast, 0x1e6e0004); + data = ast_mindwm(ast, AST_REG_MCR04); switch (data & 0x03) { case 0: boot_address = 0x44000000; @@ -348,7 +348,7 @@ static bool ast_init_dvo(struct ast_device *ast) { u8 jreg; u32 data; - ast_write32(ast, 0xf004, 0x1e6e0000); + ast_write32(ast, 0xf004, AST_REG_MCR00); ast_write32(ast, 0xf000, 0x1); ast_write32(ast, 0x12000, 0x1688a8a8); @@ -425,7 +425,7 @@ static void ast_init_analog(struct ast_device *ast) * bridge. First configure the P2U to target the SCU * in case it isn't at this stage. */ - ast_write32(ast, 0xf004, 0x1e6e0000); + ast_write32(ast, 0xf004, AST_REG_MCR00); ast_write32(ast, 0xf000, 0x1); /* Then unlock the SCU with the magic password */ diff --git a/drivers/gpu/drm/ast/ast_drv.c b/drivers/gpu/drm/ast/ast_drv.c index 05ec3542ab62..3da0cce0a3f6 100644 --- a/drivers/gpu/drm/ast/ast_drv.c +++ b/drivers/gpu/drm/ast/ast_drv.c @@ -268,7 +268,7 @@ static int ast_detect_chip(struct pci_dev *pdev, config_mode = ast_use_p2a; /* Read SCU7c (silicon revision register) */ - __ast_write32(regs, 0xf004, 0x1e6e0000); + __ast_write32(regs, 0xf004, AST_REG_MCR00); __ast_write32(regs, 0xf000, 0x1); scu_rev = __ast_read32(regs, 0x1207c); } diff --git a/drivers/gpu/drm/ast/ast_post.c b/drivers/gpu/drm/ast/ast_post.c index 5cec5d735b6a..297230f1efaf 100644 --- a/drivers/gpu/drm/ast/ast_post.c +++ b/drivers/gpu/drm/ast/ast_post.c @@ -69,19 +69,19 @@ bool mmc_test(struct ast_device *ast, u32 datagen, u8 test_ctl) { u32 data, timeout; - ast_moutdwm(ast, 0x1e6e0070, 0x00000000); - ast_moutdwm(ast, 0x1e6e0070, (datagen << 3) | test_ctl); + ast_moutdwm(ast, AST_REG_MCR70, 0x00000000); + ast_moutdwm(ast, AST_REG_MCR70, (datagen << 3) | test_ctl); timeout = 0; do { - data = ast_mindwm(ast, 0x1e6e0070) & 0x3000; + data = ast_mindwm(ast, AST_REG_MCR70) & 0x3000; if (data & 0x2000) return false; if (++timeout > TIMEOUT) { - ast_moutdwm(ast, 0x1e6e0070, 0x00000000); + ast_moutdwm(ast, AST_REG_MCR70, 0x00000000); return false; } } while (!data); - ast_moutdwm(ast, 0x1e6e0070, 0x0); + ast_moutdwm(ast, AST_REG_MCR70, 0x0); return true; } diff --git a/drivers/gpu/drm/ast/ast_reg.h b/drivers/gpu/drm/ast/ast_reg.h index 0bc033dbac55..a54733dc2675 100644 --- a/drivers/gpu/drm/ast/ast_reg.h +++ b/drivers/gpu/drm/ast/ast_reg.h @@ -98,4 +98,75 @@ #define AST_REG_AHBC84 AST_REG_AHBC(0x84) #define AST_REG_AHBC88 AST_REG_AHBC(0x88) +/* + * SDRAM Memory Controller (0x1e6e0000 - 0x1e6e0fff) + */ + +#define AST_REG_MCR_BASE (0x1e6e0000) +#define AST_REG_MCR(__offset) (AST_REG_MCR_BASE + (__offset)) +#define AST_REG_MCR00 AST_REG_MCR(0x00) +#define AST_REG_MCR00_PROTECTION_KEY (0xfc600309) +#define AST_REG_MCR04 AST_REG_MCR(0x04) +#define AST_REG_MCR08 AST_REG_MCR(0x08) +#define AST_REG_MCR0C AST_REG_MCR(0x0c) +#define AST_REG_MCR10 AST_REG_MCR(0x10) +#define AST_REG_MCR14 AST_REG_MCR(0x14) +#define AST_REG_MCR18 AST_REG_MCR(0x18) +#define AST_REG_MCR1C AST_REG_MCR(0x1c) +#define AST_REG_MCR20 AST_REG_MCR(0x20) +#define AST_REG_MCR24 AST_REG_MCR(0x24) +#define AST_REG_MCR28 AST_REG_MCR(0x28) +#define AST_REG_MCR2C AST_REG_MCR(0x2C) +#define AST_REG_MCR30 AST_REG_MCR(0x30) +#define AST_REG_MCR34 AST_REG_MCR(0x34) +#define AST_REG_MCR38 AST_REG_MCR(0x38) +#define AST_REG_MCR40 AST_REG_MCR(0x40) +#define AST_REG_MCR44 AST_REG_MCR(0x44) +#define AST_REG_MCR48 AST_REG_MCR(0x48) +#define AST_REG_MCR4C AST_REG_MCR(0x4C) +#define AST_REG_MCR50 AST_REG_MCR(0x50) +#define AST_REG_MCR54 AST_REG_MCR(0x54) +#define AST_REG_MCR60 AST_REG_MCR(0x60) +#define AST_REG_MCR64 AST_REG_MCR(0x64) +#define AST_REG_MCR68 AST_REG_MCR(0x68) +#define AST_REG_MCR6C AST_REG_MCR(0x6c) +#define AST_REG_MCR70 AST_REG_MCR(0x70) +#define AST_REG_MCR74 AST_REG_MCR(0x74) +#define AST_REG_MCR78 AST_REG_MCR(0x78) +#define AST_REG_MCR7C AST_REG_MCR(0x7c) +#define AST_REG_MCR80 AST_REG_MCR(0x80) +#define AST_REG_MCR84 AST_REG_MCR(0x84) +#define AST_REG_MCR88 AST_REG_MCR(0x88) +#define AST_REG_MCR120 AST_REG_MCR(0x120) +#define AST_REG_MCR200 AST_REG_MCR(0x200) +#define AST_REG_MCR204 AST_REG_MCR(0x204) +#define AST_REG_MCR208 AST_REG_MCR(0x208) +#define AST_REG_MCR20C AST_REG_MCR(0x20C) +#define AST_REG_MCR210 AST_REG_MCR(0x210) +#define AST_REG_MCR214 AST_REG_MCR(0x214) +#define AST_REG_MCR218 AST_REG_MCR(0x218) +#define AST_REG_MCR220 AST_REG_MCR(0x220) +#define AST_REG_MCR228 AST_REG_MCR(0x228) +#define AST_REG_MCR230 AST_REG_MCR(0x230) +#define AST_REG_MCR2A8 AST_REG_MCR(0x2a8) +#define AST_REG_MCR2B0 AST_REG_MCR(0x2b0) +#define AST_REG_MCR240 AST_REG_MCR(0x240) +#define AST_REG_MCR244 AST_REG_MCR(0x244) +#define AST_REG_MCR248 AST_REG_MCR(0x248) +#define AST_REG_MCR24C AST_REG_MCR(0x24c) +#define AST_REG_MCR290 AST_REG_MCR(0x290) +#define AST_REG_MCR2C0 AST_REG_MCR(0x2c0) +#define AST_REG_MCR2C4 AST_REG_MCR(0x2c4) +#define AST_REG_MCR2C8 AST_REG_MCR(0x2c8) +#define AST_REG_MCR2CC AST_REG_MCR(0x2cc) +#define AST_REG_MCR2E0 AST_REG_MCR(0x2e0) +#define AST_REG_MCR2E4 AST_REG_MCR(0x2e4) +#define AST_REG_MCR2E8 AST_REG_MCR(0x2e8) +#define AST_REG_MCR2EC AST_REG_MCR(0x2ec) +#define AST_REG_MCR2F0 AST_REG_MCR(0x2f0) +#define AST_REG_MCR2F4 AST_REG_MCR(0x2f4) +#define AST_REG_MCR2F8 AST_REG_MCR(0x2f8) +#define AST_REG_MCR300 AST_REG_MCR(0x300) +#define AST_REG_MCR3D0 AST_REG_MCR(0x3d0) + #endif -- cgit v1.2.3 From 06c076cb300b9eabb016e4898d5743e5fad959bb Mon Sep 17 00:00:00 2001 From: Thomas Zimmermann Date: Fri, 27 Mar 2026 14:32:57 +0100 Subject: drm/ast: Use constants for SCU registers SCU is the System Control Unit. SCU registers are located in the memory range at [0x1e6e2000, 0x1e6e2fff]. Refer to them with constants named AST_REG_SCU, where is the byte offset into the range. Replacing the magic values in the ast driver was done with grep and sed as shown below git grep -l \,\ 0x1e6e2 | xargs sed -i -e 's/, 0x1e6e2/, AST_REG_SCU/g' git grep -l \,\ 0x1E6E2 | xargs sed -i -e 's/, 0x1E6E2/, AST_REG_SCU/g' plus some manual fixes. Signed-off-by: Thomas Zimmermann Reviewed-by: Jocelyn Falempe Link: https://patch.msgid.link/20260327133532.79696-6-tzimmermann@suse.de --- drivers/gpu/drm/ast/ast_2300.c | 50 ++++++++++++++++++++--------------------- drivers/gpu/drm/ast/ast_2500.c | 44 ++++++++++++++++++------------------ drivers/gpu/drm/ast/ast_dp501.c | 20 ++++++++--------- drivers/gpu/drm/ast/ast_reg.h | 19 ++++++++++++++++ 4 files changed, 76 insertions(+), 57 deletions(-) diff --git a/drivers/gpu/drm/ast/ast_2300.c b/drivers/gpu/drm/ast/ast_2300.c index 56fe9e9f5c66..1fe947178124 100644 --- a/drivers/gpu/drm/ast/ast_2300.c +++ b/drivers/gpu/drm/ast/ast_2300.c @@ -516,10 +516,10 @@ static void get_ddr3_info(struct ast_device *ast, struct ast2300_dram_param *par { u32 trap, trap_AC2, trap_MRS; - ast_moutdwm(ast, 0x1E6E2000, 0x1688A8A8); + ast_moutdwm(ast, AST_REG_SCU000, AST_REG_SCU000_PROTECTION_KEY); /* Ger trap info */ - trap = (ast_mindwm(ast, 0x1E6E2070) >> 25) & 0x3; + trap = (ast_mindwm(ast, AST_REG_SCU070) >> 25) & 0x3; trap_AC2 = 0x00020000 + (trap << 16); trap_AC2 |= 0x00300000 + ((trap & 0x2) << 19); trap_MRS = 0x00000010 + (trap << 4); @@ -533,7 +533,7 @@ static void get_ddr3_info(struct ast_device *ast, struct ast2300_dram_param *par switch (param->dram_freq) { case 336: - ast_moutdwm(ast, 0x1E6E2020, 0x0190); + ast_moutdwm(ast, AST_REG_SCU020, 0x0190); param->wodt = 0; param->reg_AC1 = 0x22202725; param->reg_AC2 = 0xAA007613 | trap_AC2; @@ -561,7 +561,7 @@ static void get_ddr3_info(struct ast_device *ast, struct ast2300_dram_param *par break; default: case 396: - ast_moutdwm(ast, 0x1E6E2020, 0x03F1); + ast_moutdwm(ast, AST_REG_SCU020, 0x03F1); param->wodt = 1; param->reg_AC1 = 0x33302825; param->reg_AC2 = 0xCC009617 | trap_AC2; @@ -591,7 +591,7 @@ static void get_ddr3_info(struct ast_device *ast, struct ast2300_dram_param *par break; case 408: - ast_moutdwm(ast, 0x1E6E2020, 0x01F0); + ast_moutdwm(ast, AST_REG_SCU020, 0x01F0); param->wodt = 1; param->reg_AC1 = 0x33302825; param->reg_AC2 = 0xCC009617 | trap_AC2; @@ -621,7 +621,7 @@ static void get_ddr3_info(struct ast_device *ast, struct ast2300_dram_param *par break; case 456: - ast_moutdwm(ast, 0x1E6E2020, 0x0230); + ast_moutdwm(ast, AST_REG_SCU020, 0x0230); param->wodt = 0; param->reg_AC1 = 0x33302926; param->reg_AC2 = 0xCD44961A; @@ -635,7 +635,7 @@ static void get_ddr3_info(struct ast_device *ast, struct ast2300_dram_param *par param->dll2_finetune_step = 4; break; case 504: - ast_moutdwm(ast, 0x1E6E2020, 0x0270); + ast_moutdwm(ast, AST_REG_SCU020, 0x0270); param->wodt = 1; param->reg_AC1 = 0x33302926; param->reg_AC2 = 0xDE44A61D; @@ -649,7 +649,7 @@ static void get_ddr3_info(struct ast_device *ast, struct ast2300_dram_param *par param->dll2_finetune_step = 4; break; case 528: - ast_moutdwm(ast, 0x1E6E2020, 0x0290); + ast_moutdwm(ast, AST_REG_SCU020, 0x0290); param->wodt = 1; param->rodt = 1; param->reg_AC1 = 0x33302926; @@ -665,7 +665,7 @@ static void get_ddr3_info(struct ast_device *ast, struct ast2300_dram_param *par param->dll2_finetune_step = 3; break; case 576: - ast_moutdwm(ast, 0x1E6E2020, 0x0140); + ast_moutdwm(ast, AST_REG_SCU020, 0x0140); param->reg_MADJ = 0x00136868; param->reg_SADJ = 0x00004534; param->wodt = 1; @@ -683,7 +683,7 @@ static void get_ddr3_info(struct ast_device *ast, struct ast2300_dram_param *par param->dll2_finetune_step = 3; break; case 600: - ast_moutdwm(ast, 0x1E6E2020, 0x02E1); + ast_moutdwm(ast, AST_REG_SCU020, 0x02E1); param->reg_MADJ = 0x00136868; param->reg_SADJ = 0x00004534; param->wodt = 1; @@ -701,7 +701,7 @@ static void get_ddr3_info(struct ast_device *ast, struct ast2300_dram_param *par param->dll2_finetune_step = 3; break; case 624: - ast_moutdwm(ast, 0x1E6E2020, 0x0160); + ast_moutdwm(ast, AST_REG_SCU020, 0x0160); param->reg_MADJ = 0x00136868; param->reg_SADJ = 0x00004534; param->wodt = 1; @@ -874,10 +874,10 @@ static void get_ddr2_info(struct ast_device *ast, struct ast2300_dram_param *par { u32 trap, trap_AC2, trap_MRS; - ast_moutdwm(ast, 0x1E6E2000, 0x1688A8A8); + ast_moutdwm(ast, AST_REG_SCU000, AST_REG_SCU000_PROTECTION_KEY); /* Ger trap info */ - trap = (ast_mindwm(ast, 0x1E6E2070) >> 25) & 0x3; + trap = (ast_mindwm(ast, AST_REG_SCU070) >> 25) & 0x3; trap_AC2 = (trap << 20) | (trap << 16); trap_AC2 += 0x00110000; trap_MRS = 0x00000040 | (trap << 4); @@ -890,7 +890,7 @@ static void get_ddr2_info(struct ast_device *ast, struct ast2300_dram_param *par switch (param->dram_freq) { case 264: - ast_moutdwm(ast, 0x1E6E2020, 0x0130); + ast_moutdwm(ast, AST_REG_SCU020, 0x0130); param->wodt = 0; param->reg_AC1 = 0x11101513; param->reg_AC2 = 0x78117011; @@ -905,7 +905,7 @@ static void get_ddr2_info(struct ast_device *ast, struct ast2300_dram_param *par param->dll2_finetune_step = 3; break; case 336: - ast_moutdwm(ast, 0x1E6E2020, 0x0190); + ast_moutdwm(ast, AST_REG_SCU020, 0x0190); param->wodt = 1; param->reg_AC1 = 0x22202613; param->reg_AC2 = 0xAA009016 | trap_AC2; @@ -936,7 +936,7 @@ static void get_ddr2_info(struct ast_device *ast, struct ast2300_dram_param *par break; default: case 396: - ast_moutdwm(ast, 0x1E6E2020, 0x03F1); + ast_moutdwm(ast, AST_REG_SCU020, 0x03F1); param->wodt = 1; param->rodt = 0; param->reg_AC1 = 0x33302714; @@ -970,7 +970,7 @@ static void get_ddr2_info(struct ast_device *ast, struct ast2300_dram_param *par break; case 408: - ast_moutdwm(ast, 0x1E6E2020, 0x01F0); + ast_moutdwm(ast, AST_REG_SCU020, 0x01F0); param->wodt = 1; param->rodt = 0; param->reg_AC1 = 0x33302714; @@ -1003,7 +1003,7 @@ static void get_ddr2_info(struct ast_device *ast, struct ast2300_dram_param *par break; case 456: - ast_moutdwm(ast, 0x1E6E2020, 0x0230); + ast_moutdwm(ast, AST_REG_SCU020, 0x0230); param->wodt = 0; param->reg_AC1 = 0x33302815; param->reg_AC2 = 0xCD44B01E; @@ -1018,7 +1018,7 @@ static void get_ddr2_info(struct ast_device *ast, struct ast2300_dram_param *par param->dll2_finetune_step = 3; break; case 504: - ast_moutdwm(ast, 0x1E6E2020, 0x0261); + ast_moutdwm(ast, AST_REG_SCU020, 0x0261); param->wodt = 1; param->rodt = 1; param->reg_AC1 = 0x33302815; @@ -1034,7 +1034,7 @@ static void get_ddr2_info(struct ast_device *ast, struct ast2300_dram_param *par param->dll2_finetune_step = 3; break; case 528: - ast_moutdwm(ast, 0x1E6E2020, 0x0120); + ast_moutdwm(ast, AST_REG_SCU020, 0x0120); param->wodt = 1; param->rodt = 1; param->reg_AC1 = 0x33302815; @@ -1050,7 +1050,7 @@ static void get_ddr2_info(struct ast_device *ast, struct ast2300_dram_param *par param->dll2_finetune_step = 3; break; case 552: - ast_moutdwm(ast, 0x1E6E2020, 0x02A1); + ast_moutdwm(ast, AST_REG_SCU020, 0x02A1); param->wodt = 1; param->rodt = 1; param->reg_AC1 = 0x43402915; @@ -1066,7 +1066,7 @@ static void get_ddr2_info(struct ast_device *ast, struct ast2300_dram_param *par param->dll2_finetune_step = 3; break; case 576: - ast_moutdwm(ast, 0x1E6E2020, 0x0140); + ast_moutdwm(ast, AST_REG_SCU020, 0x0140); param->wodt = 1; param->rodt = 1; param->reg_AC1 = 0x43402915; @@ -1264,7 +1264,7 @@ static void ast_post_chip_2300(struct ast_device *ast) param.dram_freq = 396; param.dram_type = AST_DDR3; - temp = ast_mindwm(ast, 0x1e6e2070); + temp = ast_mindwm(ast, AST_REG_SCU070); if (temp & 0x01000000) param.dram_type = AST_DDR2; switch (temp & 0x18000000) { @@ -1306,8 +1306,8 @@ static void ast_post_chip_2300(struct ast_device *ast) ddr2_init(ast, ¶m); } - temp = ast_mindwm(ast, 0x1e6e2040); - ast_moutdwm(ast, 0x1e6e2040, temp | 0x40); + temp = ast_mindwm(ast, AST_REG_SCU040); + ast_moutdwm(ast, AST_REG_SCU040, temp | 0x40); } /* wait ready */ diff --git a/drivers/gpu/drm/ast/ast_2500.c b/drivers/gpu/drm/ast/ast_2500.c index 4a9df920509f..d141b34548a9 100644 --- a/drivers/gpu/drm/ast/ast_2500.c +++ b/drivers/gpu/drm/ast/ast_2500.c @@ -112,9 +112,9 @@ void ast_2500_patch_ahb(void __iomem *regs) __ast_moutdwm(regs, AST_REG_AHBC00, AST_REG_AHBC00_PROTECT_KEY); __ast_moutdwm(regs, AST_REG_AHBC84, 0x00010000); __ast_moutdwm(regs, AST_REG_AHBC88, 0x00000000); - __ast_moutdwm(regs, 0x1e6e2000, 0x1688A8A8); + __ast_moutdwm(regs, AST_REG_SCU000, AST_REG_SCU000_PROTECTION_KEY); - data = __ast_mindwm(regs, 0x1e6e2070); + data = __ast_mindwm(regs, AST_REG_SCU070); if (data & 0x08000000) { /* check fast reset */ /* * If "Fast restet" is enabled for ARM-ICE debugger, @@ -134,11 +134,11 @@ void ast_2500_patch_ahb(void __iomem *regs) } do { - __ast_moutdwm(regs, 0x1e6e2000, 0x1688A8A8); - data = __ast_mindwm(regs, 0x1e6e2000); + __ast_moutdwm(regs, AST_REG_SCU000, AST_REG_SCU000_PROTECTION_KEY); + data = __ast_mindwm(regs, AST_REG_SCU000); } while (data != 1); - __ast_moutdwm(regs, 0x1e6e207c, 0x08000000); /* clear fast reset */ + __ast_moutdwm(regs, AST_REG_SCU07C, 0x08000000); /* clear fast reset */ } static bool mmc_test_single_2500(struct ast_device *ast, u32 datagen) @@ -288,17 +288,17 @@ static void set_mpll_2500(struct ast_device *ast) } ast_moutdwm(ast, AST_REG_MCR34, 0x00020000); - ast_moutdwm(ast, 0x1E6E2000, 0x1688A8A8); - data = ast_mindwm(ast, 0x1E6E2070) & 0x00800000; + ast_moutdwm(ast, AST_REG_SCU000, AST_REG_SCU000_PROTECTION_KEY); + data = ast_mindwm(ast, AST_REG_SCU070) & 0x00800000; if (data) { /* CLKIN = 25MHz */ param = 0x930023E0; - ast_moutdwm(ast, 0x1E6E2160, 0x00011320); + ast_moutdwm(ast, AST_REG_SCU160, 0x00011320); } else { /* CLKIN = 24MHz */ param = 0x93002400; } - ast_moutdwm(ast, 0x1E6E2020, param); + ast_moutdwm(ast, AST_REG_SCU020, param); udelay(100); } @@ -480,18 +480,18 @@ static bool ast_dram_init_2500(struct ast_device *ast) reset_mmc_2500(ast); ddr_init_common_2500(ast); - data = ast_mindwm(ast, 0x1E6E2070); + data = ast_mindwm(ast, AST_REG_SCU070); if (data & 0x01000000) ddr4_init_2500(ast, ast2500_ddr4_1600_timing_table); else ddr3_init_2500(ast, ast2500_ddr3_1600_timing_table); } while (!ddr_test_2500(ast)); - ast_moutdwm(ast, 0x1E6E2040, ast_mindwm(ast, 0x1E6E2040) | 0x41); + ast_moutdwm(ast, AST_REG_SCU040, ast_mindwm(ast, AST_REG_SCU040) | 0x41); /* Patch code */ - data = ast_mindwm(ast, 0x1E6E200C) & 0xF9FFFFFF; - ast_moutdwm(ast, 0x1E6E200C, data | 0x10000000); + data = ast_mindwm(ast, AST_REG_SCU00C) & 0xF9FFFFFF; + ast_moutdwm(ast, AST_REG_SCU00C, data | 0x10000000); return true; } @@ -524,17 +524,17 @@ static void ast_post_chip_2500(struct ast_device *ast) * SCU7C is Write clear reg to SCU70 * [23]:= write 1 and then SCU70[23] will be clear as 0b. */ - ast_moutdwm(ast, 0x1E6E2090, 0x20000000); - ast_moutdwm(ast, 0x1E6E2094, 0x00004000); - if (ast_mindwm(ast, 0x1E6E2070) & 0x00800000) { - ast_moutdwm(ast, 0x1E6E207C, 0x00800000); + ast_moutdwm(ast, AST_REG_SCU090, 0x20000000); + ast_moutdwm(ast, AST_REG_SCU094, 0x00004000); + if (ast_mindwm(ast, AST_REG_SCU070) & 0x00800000) { + ast_moutdwm(ast, AST_REG_SCU07C, 0x00800000); mdelay(100); - ast_moutdwm(ast, 0x1E6E2070, 0x00800000); + ast_moutdwm(ast, AST_REG_SCU070, 0x00800000); } /* Modify eSPI reset pin */ - temp = ast_mindwm(ast, 0x1E6E2070); + temp = ast_mindwm(ast, AST_REG_SCU070); if (temp & 0x02000000) - ast_moutdwm(ast, 0x1E6E207C, 0x00004000); + ast_moutdwm(ast, AST_REG_SCU07C, 0x00004000); /* Slow down CPU/AHB CLK in VGA only mode */ temp = ast_read32(ast, 0x12008); @@ -544,8 +544,8 @@ static void ast_post_chip_2500(struct ast_device *ast) if (!ast_dram_init_2500(ast)) drm_err(dev, "DRAM init failed !\n"); - temp = ast_mindwm(ast, 0x1e6e2040); - ast_moutdwm(ast, 0x1e6e2040, temp | 0x40); + temp = ast_mindwm(ast, AST_REG_SCU040); + ast_moutdwm(ast, AST_REG_SCU040, temp | 0x40); } /* wait ready */ diff --git a/drivers/gpu/drm/ast/ast_dp501.c b/drivers/gpu/drm/ast/ast_dp501.c index 8c2243cf8187..23142119d733 100644 --- a/drivers/gpu/drm/ast/ast_dp501.c +++ b/drivers/gpu/drm/ast/ast_dp501.c @@ -183,7 +183,7 @@ static void ast_set_dp501_video_output(struct ast_device *ast, u8 mode) static u32 get_fw_base(struct ast_device *ast) { - return ast_mindwm(ast, 0x1e6e2104) & 0x7fffffff; + return ast_mindwm(ast, AST_REG_SCU104) & 0x7fffffff; } bool ast_backup_fw(struct ast_device *ast, u8 *addr, u32 size) @@ -194,7 +194,7 @@ bool ast_backup_fw(struct ast_device *ast, u8 *addr, u32 size) if (ast->config_mode != ast_use_p2a) return false; - data = ast_mindwm(ast, 0x1e6e2100) & 0x01; + data = ast_mindwm(ast, AST_REG_SCU100) & 0x01; if (data) { boot_address = get_fw_base(ast); for (i = 0; i < size; i += 4) @@ -214,7 +214,7 @@ static bool ast_launch_m68k(struct ast_device *ast) if (ast->config_mode != ast_use_p2a) return false; - data = ast_mindwm(ast, 0x1e6e2100) & 0x01; + data = ast_mindwm(ast, AST_REG_SCU100) & 0x01; if (!data) { if (ast->dp501_fw_addr) { @@ -229,7 +229,7 @@ static bool ast_launch_m68k(struct ast_device *ast) len = ast->dp501_fw->size; } /* Get BootAddress */ - ast_moutdwm(ast, 0x1e6e2000, 0x1688a8a8); + ast_moutdwm(ast, AST_REG_SCU000, AST_REG_SCU000_PROTECTION_KEY); data = ast_mindwm(ast, AST_REG_MCR04); switch (data & 0x03) { case 0: @@ -255,16 +255,16 @@ static bool ast_launch_m68k(struct ast_device *ast) } /* Init SCU */ - ast_moutdwm(ast, 0x1e6e2000, 0x1688a8a8); + ast_moutdwm(ast, AST_REG_SCU000, AST_REG_SCU000_PROTECTION_KEY); /* Launch FW */ - ast_moutdwm(ast, 0x1e6e2104, 0x80000000 + boot_address); - ast_moutdwm(ast, 0x1e6e2100, 1); + ast_moutdwm(ast, AST_REG_SCU104, 0x80000000 + boot_address); + ast_moutdwm(ast, AST_REG_SCU100, 1); /* Update Scratch */ - data = ast_mindwm(ast, 0x1e6e2040) & 0xfffff1ff; /* D[11:9] = 100b: UEFI handling */ - data |= 0x800; - ast_moutdwm(ast, 0x1e6e2040, data); + data = ast_mindwm(ast, AST_REG_SCU040) & 0xfffff1ff; + data |= 0x800; /* D[11:9] = 100b: UEFI handling */ + ast_moutdwm(ast, AST_REG_SCU040, data); jreg = ast_get_index_reg_mask(ast, AST_IO_VGACRI, 0x99, 0xfc); /* D[1:0]: Reserved Video Buffer */ jreg |= 0x02; diff --git a/drivers/gpu/drm/ast/ast_reg.h b/drivers/gpu/drm/ast/ast_reg.h index a54733dc2675..e8d4991186ca 100644 --- a/drivers/gpu/drm/ast/ast_reg.h +++ b/drivers/gpu/drm/ast/ast_reg.h @@ -169,4 +169,23 @@ #define AST_REG_MCR300 AST_REG_MCR(0x300) #define AST_REG_MCR3D0 AST_REG_MCR(0x3d0) +/* + * System Control Unit (0x1e6e2000 - 0x1e6e2fff) + */ + +#define AST_REG_SCU_BASE (0x1e6e2000) +#define AST_REG_SCU(__offset) (AST_REG_SCU_BASE + (__offset)) +#define AST_REG_SCU000 AST_REG_SCU(0x000) +#define AST_REG_SCU000_PROTECTION_KEY (0x1688a8a8) +#define AST_REG_SCU00C AST_REG_SCU(0x00c) +#define AST_REG_SCU020 AST_REG_SCU(0x020) +#define AST_REG_SCU040 AST_REG_SCU(0x040) +#define AST_REG_SCU070 AST_REG_SCU(0x070) +#define AST_REG_SCU07C AST_REG_SCU(0x07c) +#define AST_REG_SCU090 AST_REG_SCU(0x090) +#define AST_REG_SCU094 AST_REG_SCU(0x094) +#define AST_REG_SCU100 AST_REG_SCU(0x100) +#define AST_REG_SCU104 AST_REG_SCU(0x104) +#define AST_REG_SCU160 AST_REG_SCU(0x160) + #endif -- cgit v1.2.3 From f9f57e03d2c661d5f8d46886d407ad648b8b670f Mon Sep 17 00:00:00 2001 From: Thomas Zimmermann Date: Fri, 27 Mar 2026 14:32:58 +0100 Subject: drm/ast: Use constants for A2P registers A2P is the AHB-to-P Bridge. A2P registers are located at the memory range at [0x1e720000, 0x1e73ffff]. Refer to them with constants named AST_REG_A2P, where is the byte offset into the range. Signed-off-by: Thomas Zimmermann Reviewed-by: Jocelyn Falempe Link: https://patch.msgid.link/20260327133532.79696-7-tzimmermann@suse.de --- drivers/gpu/drm/ast/ast_2300.c | 6 +++--- drivers/gpu/drm/ast/ast_reg.h | 8 ++++++++ 2 files changed, 11 insertions(+), 3 deletions(-) diff --git a/drivers/gpu/drm/ast/ast_2300.c b/drivers/gpu/drm/ast/ast_2300.c index 1fe947178124..96d9909d942c 100644 --- a/drivers/gpu/drm/ast/ast_2300.c +++ b/drivers/gpu/drm/ast/ast_2300.c @@ -508,7 +508,7 @@ CBR_DONE2: dlli = (dllmin[1] + dllmax[1]) >> 1; dlli <<= 8; dlli += (dllmin[0] + dllmax[0]) >> 1; - ast_moutdwm(ast, AST_REG_MCR68, ast_mindwm(ast, 0x1E720058) | (dlli << 16)); + ast_moutdwm(ast, AST_REG_MCR68, ast_mindwm(ast, AST_REG_A2P58) | (dlli << 16)); return status; } /* CBRDLL2 */ @@ -826,7 +826,7 @@ ddr3_init_start: data = ast_mindwm(ast, AST_REG_MCR1C); data = (data >> 8) & 0xff; } - ast_moutdwm(ast, 0x1E720058, ast_mindwm(ast, AST_REG_MCR68) & 0xffff); + ast_moutdwm(ast, AST_REG_A2P58, ast_mindwm(ast, AST_REG_MCR68) & 0xffff); data = ast_mindwm(ast, AST_REG_MCR18) | 0xC00; ast_moutdwm(ast, AST_REG_MCR18, data); @@ -1188,7 +1188,7 @@ ddr2_init_start: data = ast_mindwm(ast, AST_REG_MCR1C); data = (data >> 8) & 0xff; } - ast_moutdwm(ast, 0x1E720058, ast_mindwm(ast, AST_REG_MCR08) & 0xffff); + ast_moutdwm(ast, AST_REG_A2P58, ast_mindwm(ast, AST_REG_MCR08) & 0xffff); data = ast_mindwm(ast, AST_REG_MCR18) | 0xC00; ast_moutdwm(ast, AST_REG_MCR18, data); diff --git a/drivers/gpu/drm/ast/ast_reg.h b/drivers/gpu/drm/ast/ast_reg.h index e8d4991186ca..730072a3c2cd 100644 --- a/drivers/gpu/drm/ast/ast_reg.h +++ b/drivers/gpu/drm/ast/ast_reg.h @@ -188,4 +188,12 @@ #define AST_REG_SCU104 AST_REG_SCU(0x104) #define AST_REG_SCU160 AST_REG_SCU(0x160) +/* + * AHB-to-P Bus Bridge (0x1e720000 - 0x1e73ffff) + */ + +#define AST_REG_A2P_BASE (0x1e720000) +#define AST_REG_A2P(__offset) (AST_REG_A2P_BASE + (__offset)) +#define AST_REG_A2P58 AST_REG_A2P(0x58) + #endif -- cgit v1.2.3 From a0320ef5a99090d5c5ee1f5fd40409b0c0035430 Mon Sep 17 00:00:00 2001 From: Thomas Zimmermann Date: Fri, 27 Mar 2026 14:32:59 +0100 Subject: drm/ast: Use constants for WDT registers WDT is the Watchdog timer. WDC registers are located at the memory range at [0x1e785000, 0x1e785fff]. There are currently up to 8 watchdog timers in the range, of which 2 are being used by AST2500. Refer to them with macros named AST_REG_WDT, where is the byte offset into the watchdog timer's memory range. Each macro also takes the index of the watchdog timer to access. A new watchdog timer starts at each 0x40 byte offset. Signed-off-by: Thomas Zimmermann Reviewed-by: Jocelyn Falempe Link: https://patch.msgid.link/20260327133532.79696-8-tzimmermann@suse.de --- drivers/gpu/drm/ast/ast_2500.c | 20 ++++++++++---------- drivers/gpu/drm/ast/ast_reg.h | 13 +++++++++++++ 2 files changed, 23 insertions(+), 10 deletions(-) diff --git a/drivers/gpu/drm/ast/ast_2500.c b/drivers/gpu/drm/ast/ast_2500.c index d141b34548a9..f0639f1ef062 100644 --- a/drivers/gpu/drm/ast/ast_2500.c +++ b/drivers/gpu/drm/ast/ast_2500.c @@ -127,9 +127,9 @@ void ast_2500_patch_ahb(void __iomem *regs) * [1]:= 1:WDT will be cleeared and disabled after timeout occurs * [0]:= 1:WDT enable */ - __ast_moutdwm(regs, 0x1E785004, 0x00000010); - __ast_moutdwm(regs, 0x1E785008, 0x00004755); - __ast_moutdwm(regs, 0x1E78500c, 0x00000033); + __ast_moutdwm(regs, AST_REG_WDT04(0), 0x00000010); + __ast_moutdwm(regs, AST_REG_WDT08(0), 0x00004755); + __ast_moutdwm(regs, AST_REG_WDT0C(0), 0x00000033); udelay(1000); } @@ -304,12 +304,12 @@ static void set_mpll_2500(struct ast_device *ast) static void reset_mmc_2500(struct ast_device *ast) { - ast_moutdwm(ast, 0x1E78505C, 0x00000004); - ast_moutdwm(ast, 0x1E785044, 0x00000001); - ast_moutdwm(ast, 0x1E785048, 0x00004755); - ast_moutdwm(ast, 0x1E78504C, 0x00000013); + ast_moutdwm(ast, AST_REG_WDT1C(1), 0x00000004); + ast_moutdwm(ast, AST_REG_WDT04(1), 0x00000001); + ast_moutdwm(ast, AST_REG_WDT08(1), 0x00004755); + ast_moutdwm(ast, AST_REG_WDT0C(1), 0x00000013); mdelay(100); - ast_moutdwm(ast, 0x1E785054, 0x00000077); + ast_moutdwm(ast, AST_REG_WDT14(1), 0x00000077); ast_moutdwm(ast, AST_REG_MCR00, AST_REG_MCR00_PROTECTION_KEY); } @@ -508,8 +508,8 @@ static void ast_post_chip_2500(struct ast_device *ast) ast_2500_patch_ahb(ast->regs); /* Disable watchdog */ - ast_moutdwm(ast, 0x1E78502C, 0x00000000); - ast_moutdwm(ast, 0x1E78504C, 0x00000000); + ast_moutdwm(ast, AST_REG_WDT2C(0), 0x00000000); + ast_moutdwm(ast, AST_REG_WDT0C(1), 0x00000000); /* * Reset USB port to patch USB unknown device issue diff --git a/drivers/gpu/drm/ast/ast_reg.h b/drivers/gpu/drm/ast/ast_reg.h index 730072a3c2cd..5effe6897b51 100644 --- a/drivers/gpu/drm/ast/ast_reg.h +++ b/drivers/gpu/drm/ast/ast_reg.h @@ -196,4 +196,17 @@ #define AST_REG_A2P(__offset) (AST_REG_A2P_BASE + (__offset)) #define AST_REG_A2P58 AST_REG_A2P(0x58) +/* + * Watchdog timer (0x1e785000 - 0x1e785fff) + */ + +#define AST_REG_WDT_BASE(__n) (0x1e785000 + (__n) * 0x40) +#define AST_REG_WDT(__n, __offset) (AST_REG_WDT_BASE((__n)) + (__offset)) +#define AST_REG_WDT04(__n) AST_REG_WDT((__n), 0x04) +#define AST_REG_WDT08(__n) AST_REG_WDT((__n), 0x08) +#define AST_REG_WDT0C(__n) AST_REG_WDT((__n), 0x0c) +#define AST_REG_WDT14(__n) AST_REG_WDT((__n), 0x14) +#define AST_REG_WDT1C(__n) AST_REG_WDT((__n), 0x1c) +#define AST_REG_WDT2C(__n) AST_REG_WDT((__n), 0x2c) + #endif -- cgit v1.2.3 From 5da1fcb9cb69a3274b77747ffcc3f0a2223e253d Mon Sep 17 00:00:00 2001 From: Thomas Zimmermann Date: Fri, 27 Mar 2026 14:33:00 +0100 Subject: drm/ast: Use constants for SDRAM registers Aspeed hardware allows for acceessing the SDRAM from the host. SDRAM registers are located at the memory range at [0x80000000, 0xffffffff]. Refer to memory access with the macro AST_SDRAM(). Also add a TODO item for the nonsensical documentation next to its caller. Signed-off-by: Thomas Zimmermann Reviewed-by: Jocelyn Falempe Link: https://patch.msgid.link/20260327133532.79696-9-tzimmermann@suse.de --- drivers/gpu/drm/ast/ast_2500.c | 17 ++++++++++------- drivers/gpu/drm/ast/ast_reg.h | 7 +++++++ 2 files changed, 17 insertions(+), 7 deletions(-) diff --git a/drivers/gpu/drm/ast/ast_2500.c b/drivers/gpu/drm/ast/ast_2500.c index f0639f1ef062..39f401dd1f47 100644 --- a/drivers/gpu/drm/ast/ast_2500.c +++ b/drivers/gpu/drm/ast/ast_2500.c @@ -225,6 +225,9 @@ static void ddr_phy_init_2500(struct ast_device *ast) } /* + * TODO: Review and fix the comments. The function below only detects + * up to 1 GiB of SDRAM. + * * Check DRAM Size * 1Gb : 0x80000000 ~ 0x87FFFFFF * 2Gb : 0x80000000 ~ 0x8FFFFFFF @@ -238,21 +241,21 @@ static void check_dram_size_2500(struct ast_device *ast, u32 tRFC) reg_04 = ast_mindwm(ast, AST_REG_MCR04) & 0xfffffffc; reg_14 = ast_mindwm(ast, AST_REG_MCR14) & 0xffffff00; - ast_moutdwm(ast, 0xA0100000, 0x41424344); - ast_moutdwm(ast, 0x90100000, 0x35363738); - ast_moutdwm(ast, 0x88100000, 0x292A2B2C); - ast_moutdwm(ast, 0x80100000, 0x1D1E1F10); + ast_moutdwm(ast, AST_SDRAM(0x20100000), 0x41424344); + ast_moutdwm(ast, AST_SDRAM(0x10100000), 0x35363738); + ast_moutdwm(ast, AST_SDRAM(0x08100000), 0x292A2B2C); + ast_moutdwm(ast, AST_SDRAM(0x00100000), 0x1D1E1F10); /* Check 8Gbit */ - if (ast_mindwm(ast, 0xA0100000) == 0x41424344) { + if (ast_mindwm(ast, AST_SDRAM(0x20100000)) == 0x41424344) { reg_04 |= 0x03; reg_14 |= (tRFC >> 24) & 0xFF; /* Check 4Gbit */ - } else if (ast_mindwm(ast, 0x90100000) == 0x35363738) { + } else if (ast_mindwm(ast, AST_SDRAM(0x10100000)) == 0x35363738) { reg_04 |= 0x02; reg_14 |= (tRFC >> 16) & 0xFF; /* Check 2Gbit */ - } else if (ast_mindwm(ast, 0x88100000) == 0x292A2B2C) { + } else if (ast_mindwm(ast, AST_SDRAM(0x08100000)) == 0x292A2B2C) { reg_04 |= 0x01; reg_14 |= (tRFC >> 8) & 0xFF; } else { diff --git a/drivers/gpu/drm/ast/ast_reg.h b/drivers/gpu/drm/ast/ast_reg.h index 5effe6897b51..78fabe2a9c81 100644 --- a/drivers/gpu/drm/ast/ast_reg.h +++ b/drivers/gpu/drm/ast/ast_reg.h @@ -209,4 +209,11 @@ #define AST_REG_WDT1C(__n) AST_REG_WDT((__n), 0x1c) #define AST_REG_WDT2C(__n) AST_REG_WDT((__n), 0x2c) +/* + * SDRAM (0x80000000 - 0xffffffff) + */ + +#define AST_SDRAM_BASE (0x80000000) +#define AST_SDRAM(__offset) (AST_SDRAM_BASE + (__offset)) + #endif -- cgit v1.2.3 From 5e9ced3d6c291a956c8d39ee77bcd7cbbd3891fc Mon Sep 17 00:00:00 2001 From: Thomas Zimmermann Date: Fri, 27 Mar 2026 14:33:01 +0100 Subject: drm/ast: Store register addresses in struct ast_dramstruct Struct ast_dramstruct contains a 16-bit index field that either contains a magic value or serves as index into the P2A address segment at 0x1e600000. This segment serves MCR and SCU registers, which the ast_dramstruct programs. It's fragile and relies upon the ast_post_chip_*() functions to set up the segment correctly. Replace the 16-bit index with a full 32-bit address of the SCU and MCR addresses. Initialize the DRAM tables with full register constants and write them out with ast_moutdwm(). This sets the correct segment on each write. Drop __AST_DRAMSTRUCT_DRAM_TYPE as it simply referred to MCR04. Use the latter for initializing the DRAM tables. Signed-off-by: Thomas Zimmermann Reviewed-by: Jocelyn Falempe Link: https://patch.msgid.link/20260327133532.79696-10-tzimmermann@suse.de --- drivers/gpu/drm/ast/ast_2000.c | 43 +++++---- drivers/gpu/drm/ast/ast_2100.c | 195 ++++++++++++++++++++--------------------- drivers/gpu/drm/ast/ast_post.h | 17 ++-- drivers/gpu/drm/ast/ast_reg.h | 4 + 4 files changed, 131 insertions(+), 128 deletions(-) diff --git a/drivers/gpu/drm/ast/ast_2000.c b/drivers/gpu/drm/ast/ast_2000.c index 204646bb1fa0..e683edf595e2 100644 --- a/drivers/gpu/drm/ast/ast_2000.c +++ b/drivers/gpu/drm/ast/ast_2000.c @@ -69,30 +69,30 @@ void ast_2000_set_def_ext_reg(struct ast_device *ast) } static const struct ast_dramstruct ast2000_dram_table_data[] = { - { 0x0108, 0x00000000 }, - { 0x0120, 0x00004a21 }, + AST_DRAMSTRUCT_REG(AST_REG_MCR108, 0x00000000), + AST_DRAMSTRUCT_REG(AST_REG_MCR120, 0x00004a21), AST_DRAMSTRUCT_UDELAY(67u), - { 0x0000, 0xFFFFFFFF }, - AST_DRAMSTRUCT_INIT(DRAM_TYPE, 0x00000089), - { 0x0008, 0x22331353 }, - { 0x000C, 0x0d07000b }, - { 0x0010, 0x11113333 }, - { 0x0020, 0x00110350 }, - { 0x0028, 0x1e0828f0 }, - { 0x0024, 0x00000001 }, - { 0x001C, 0x00000000 }, - { 0x0014, 0x00000003 }, + AST_DRAMSTRUCT_REG(AST_REG_MCR00, 0xffffffff), /* FIXME: This locks the MCR registers. */ + AST_DRAMSTRUCT_REG(AST_REG_MCR04, 0x00000089), /* DRAM type */ + AST_DRAMSTRUCT_REG(AST_REG_MCR08, 0x22331353), + AST_DRAMSTRUCT_REG(AST_REG_MCR0C, 0x0d07000b), + AST_DRAMSTRUCT_REG(AST_REG_MCR10, 0x11113333), + AST_DRAMSTRUCT_REG(AST_REG_MCR20, 0x00110350), + AST_DRAMSTRUCT_REG(AST_REG_MCR28, 0x1e0828f0), + AST_DRAMSTRUCT_REG(AST_REG_MCR24, 0x00000001), + AST_DRAMSTRUCT_REG(AST_REG_MCR1C, 0x00000000), + AST_DRAMSTRUCT_REG(AST_REG_MCR14, 0x00000003), AST_DRAMSTRUCT_UDELAY(67u), - { 0x0018, 0x00000131 }, - { 0x0014, 0x00000001 }, + AST_DRAMSTRUCT_REG(AST_REG_MCR18, 0x00000131), + AST_DRAMSTRUCT_REG(AST_REG_MCR14, 0x00000001), AST_DRAMSTRUCT_UDELAY(67u), - { 0x0018, 0x00000031 }, - { 0x0014, 0x00000001 }, + AST_DRAMSTRUCT_REG(AST_REG_MCR18, 0x00000031), + AST_DRAMSTRUCT_REG(AST_REG_MCR14, 0x00000001), AST_DRAMSTRUCT_UDELAY(67u), - { 0x0028, 0x1e0828f1 }, - { 0x0024, 0x00000003 }, - { 0x002C, 0x1f0f28fb }, - { 0x0030, 0xFFFFFE01 }, + AST_DRAMSTRUCT_REG(AST_REG_MCR28, 0x1e0828f1), + AST_DRAMSTRUCT_REG(AST_REG_MCR24, 0x00000003), + AST_DRAMSTRUCT_REG(AST_REG_MCR2C, 0x1f0f28fb), + AST_DRAMSTRUCT_REG(AST_REG_MCR30, 0xfffffe01), AST_DRAMSTRUCT_INVALID, }; @@ -119,8 +119,7 @@ static void ast_post_chip_2000(struct ast_device *ast) for (i = 0; i < 15; i++) udelay(dram_reg_info->data); } else { - ast_write32(ast, 0x10000 + dram_reg_info->index, - dram_reg_info->data); + ast_moutdwm(ast, dram_reg_info->index, dram_reg_info->data); } dram_reg_info++; } diff --git a/drivers/gpu/drm/ast/ast_2100.c b/drivers/gpu/drm/ast/ast_2100.c index 28cd36571b7f..930e9f2d0ccf 100644 --- a/drivers/gpu/drm/ast/ast_2100.c +++ b/drivers/gpu/drm/ast/ast_2100.c @@ -72,108 +72,108 @@ static enum ast_dram_layout ast_2100_get_dram_layout_p2a(struct ast_device *ast) */ static const struct ast_dramstruct ast1100_dram_table_data[] = { - { 0x2000, 0x1688a8a8 }, - { 0x2020, 0x000041f0 }, + AST_DRAMSTRUCT_REG(AST_REG_SCU000, AST_REG_SCU000_PROTECTION_KEY), + AST_DRAMSTRUCT_REG(AST_REG_SCU020, 0x000041f0), AST_DRAMSTRUCT_UDELAY(67u), - { 0x0000, 0xfc600309 }, - { 0x006C, 0x00909090 }, - { 0x0064, 0x00050000 }, - AST_DRAMSTRUCT_INIT(DRAM_TYPE, 0x00000585), - { 0x0008, 0x0011030f }, - { 0x0010, 0x22201724 }, - { 0x0018, 0x1e29011a }, - { 0x0020, 0x00c82222 }, - { 0x0014, 0x01001523 }, - { 0x001C, 0x1024010d }, - { 0x0024, 0x00cb2522 }, - { 0x0038, 0xffffff82 }, - { 0x003C, 0x00000000 }, - { 0x0040, 0x00000000 }, - { 0x0044, 0x00000000 }, - { 0x0048, 0x00000000 }, - { 0x004C, 0x00000000 }, - { 0x0050, 0x00000000 }, - { 0x0054, 0x00000000 }, - { 0x0058, 0x00000000 }, - { 0x005C, 0x00000000 }, - { 0x0060, 0x032aa02a }, - { 0x0064, 0x002d3000 }, - { 0x0068, 0x00000000 }, - { 0x0070, 0x00000000 }, - { 0x0074, 0x00000000 }, - { 0x0078, 0x00000000 }, - { 0x007C, 0x00000000 }, - { 0x0034, 0x00000001 }, + AST_DRAMSTRUCT_REG(AST_REG_MCR00, AST_REG_MCR00_PROTECTION_KEY), + AST_DRAMSTRUCT_REG(AST_REG_MCR6C, 0x00909090), + AST_DRAMSTRUCT_REG(AST_REG_MCR64, 0x00050000), + AST_DRAMSTRUCT_REG(AST_REG_MCR04, 0x00000585), // DRAM type + AST_DRAMSTRUCT_REG(AST_REG_MCR08, 0x0011030f), + AST_DRAMSTRUCT_REG(AST_REG_MCR10, 0x22201724), + AST_DRAMSTRUCT_REG(AST_REG_MCR18, 0x1e29011a), + AST_DRAMSTRUCT_REG(AST_REG_MCR20, 0x00c82222), + AST_DRAMSTRUCT_REG(AST_REG_MCR14, 0x01001523), + AST_DRAMSTRUCT_REG(AST_REG_MCR1C, 0x1024010d), + AST_DRAMSTRUCT_REG(AST_REG_MCR24, 0x00cb2522), + AST_DRAMSTRUCT_REG(AST_REG_MCR38, 0xffffff82), + AST_DRAMSTRUCT_REG(AST_REG_MCR3C, 0x00000000), + AST_DRAMSTRUCT_REG(AST_REG_MCR40, 0x00000000), + AST_DRAMSTRUCT_REG(AST_REG_MCR44, 0x00000000), + AST_DRAMSTRUCT_REG(AST_REG_MCR48, 0x00000000), + AST_DRAMSTRUCT_REG(AST_REG_MCR4C, 0x00000000), + AST_DRAMSTRUCT_REG(AST_REG_MCR50, 0x00000000), + AST_DRAMSTRUCT_REG(AST_REG_MCR54, 0x00000000), + AST_DRAMSTRUCT_REG(AST_REG_MCR58, 0x00000000), + AST_DRAMSTRUCT_REG(AST_REG_MCR5C, 0x00000000), + AST_DRAMSTRUCT_REG(AST_REG_MCR60, 0x032aa02a), + AST_DRAMSTRUCT_REG(AST_REG_MCR64, 0x002d3000), + AST_DRAMSTRUCT_REG(AST_REG_MCR68, 0x00000000), + AST_DRAMSTRUCT_REG(AST_REG_MCR70, 0x00000000), + AST_DRAMSTRUCT_REG(AST_REG_MCR74, 0x00000000), + AST_DRAMSTRUCT_REG(AST_REG_MCR78, 0x00000000), + AST_DRAMSTRUCT_REG(AST_REG_MCR7C, 0x00000000), + AST_DRAMSTRUCT_REG(AST_REG_MCR34, 0x00000001), AST_DRAMSTRUCT_UDELAY(67u), - { 0x002C, 0x00000732 }, - { 0x0030, 0x00000040 }, - { 0x0028, 0x00000005 }, - { 0x0028, 0x00000007 }, - { 0x0028, 0x00000003 }, - { 0x0028, 0x00000001 }, - { 0x000C, 0x00005a08 }, - { 0x002C, 0x00000632 }, - { 0x0028, 0x00000001 }, - { 0x0030, 0x000003c0 }, - { 0x0028, 0x00000003 }, - { 0x0030, 0x00000040 }, - { 0x0028, 0x00000003 }, - { 0x000C, 0x00005a21 }, - { 0x0034, 0x00007c03 }, - { 0x0120, 0x00004c41 }, + AST_DRAMSTRUCT_REG(AST_REG_MCR2C, 0x00000732), + AST_DRAMSTRUCT_REG(AST_REG_MCR30, 0x00000040), + AST_DRAMSTRUCT_REG(AST_REG_MCR28, 0x00000005), + AST_DRAMSTRUCT_REG(AST_REG_MCR28, 0x00000007), + AST_DRAMSTRUCT_REG(AST_REG_MCR28, 0x00000003), + AST_DRAMSTRUCT_REG(AST_REG_MCR28, 0x00000001), + AST_DRAMSTRUCT_REG(AST_REG_MCR0C, 0x00005a08), + AST_DRAMSTRUCT_REG(AST_REG_MCR2C, 0x00000632), + AST_DRAMSTRUCT_REG(AST_REG_MCR28, 0x00000001), + AST_DRAMSTRUCT_REG(AST_REG_MCR30, 0x000003c0), + AST_DRAMSTRUCT_REG(AST_REG_MCR28, 0x00000003), + AST_DRAMSTRUCT_REG(AST_REG_MCR30, 0x00000040), + AST_DRAMSTRUCT_REG(AST_REG_MCR28, 0x00000003), + AST_DRAMSTRUCT_REG(AST_REG_MCR0C, 0x00005a21), + AST_DRAMSTRUCT_REG(AST_REG_MCR34, 0x00007c03), + AST_DRAMSTRUCT_REG(AST_REG_MCR120, 0x00004c41), AST_DRAMSTRUCT_INVALID, }; static const struct ast_dramstruct ast2100_dram_table_data[] = { - { 0x2000, 0x1688a8a8 }, - { 0x2020, 0x00004120 }, + AST_DRAMSTRUCT_REG(AST_REG_SCU000, AST_REG_SCU000_PROTECTION_KEY), + AST_DRAMSTRUCT_REG(AST_REG_SCU020, 0x00004120), AST_DRAMSTRUCT_UDELAY(67u), - { 0x0000, 0xfc600309 }, - { 0x006C, 0x00909090 }, - { 0x0064, 0x00070000 }, - AST_DRAMSTRUCT_INIT(DRAM_TYPE, 0x00000489), - { 0x0008, 0x0011030f }, - { 0x0010, 0x32302926 }, - { 0x0018, 0x274c0122 }, - { 0x0020, 0x00ce2222 }, - { 0x0014, 0x01001523 }, - { 0x001C, 0x1024010d }, - { 0x0024, 0x00cb2522 }, - { 0x0038, 0xffffff82 }, - { 0x003C, 0x00000000 }, - { 0x0040, 0x00000000 }, - { 0x0044, 0x00000000 }, - { 0x0048, 0x00000000 }, - { 0x004C, 0x00000000 }, - { 0x0050, 0x00000000 }, - { 0x0054, 0x00000000 }, - { 0x0058, 0x00000000 }, - { 0x005C, 0x00000000 }, - { 0x0060, 0x0f2aa02a }, - { 0x0064, 0x003f3005 }, - { 0x0068, 0x02020202 }, - { 0x0070, 0x00000000 }, - { 0x0074, 0x00000000 }, - { 0x0078, 0x00000000 }, - { 0x007C, 0x00000000 }, - { 0x0034, 0x00000001 }, + AST_DRAMSTRUCT_REG(AST_REG_MCR00, AST_REG_MCR00_PROTECTION_KEY), + AST_DRAMSTRUCT_REG(AST_REG_MCR6C, 0x00909090), + AST_DRAMSTRUCT_REG(AST_REG_MCR64, 0x00070000), + AST_DRAMSTRUCT_REG(AST_REG_MCR04, 0x00000489), // DRAM type + AST_DRAMSTRUCT_REG(AST_REG_MCR08, 0x0011030f), + AST_DRAMSTRUCT_REG(AST_REG_MCR10, 0x32302926), + AST_DRAMSTRUCT_REG(AST_REG_MCR18, 0x274c0122), + AST_DRAMSTRUCT_REG(AST_REG_MCR20, 0x00ce2222), + AST_DRAMSTRUCT_REG(AST_REG_MCR14, 0x01001523), + AST_DRAMSTRUCT_REG(AST_REG_MCR1C, 0x1024010d), + AST_DRAMSTRUCT_REG(AST_REG_MCR24, 0x00cb2522), + AST_DRAMSTRUCT_REG(AST_REG_MCR38, 0xffffff82), + AST_DRAMSTRUCT_REG(AST_REG_MCR3C, 0x00000000), + AST_DRAMSTRUCT_REG(AST_REG_MCR40, 0x00000000), + AST_DRAMSTRUCT_REG(AST_REG_MCR44, 0x00000000), + AST_DRAMSTRUCT_REG(AST_REG_MCR48, 0x00000000), + AST_DRAMSTRUCT_REG(AST_REG_MCR4C, 0x00000000), + AST_DRAMSTRUCT_REG(AST_REG_MCR50, 0x00000000), + AST_DRAMSTRUCT_REG(AST_REG_MCR54, 0x00000000), + AST_DRAMSTRUCT_REG(AST_REG_MCR58, 0x00000000), + AST_DRAMSTRUCT_REG(AST_REG_MCR5C, 0x00000000), + AST_DRAMSTRUCT_REG(AST_REG_MCR60, 0x0f2aa02a), + AST_DRAMSTRUCT_REG(AST_REG_MCR64, 0x003f3005), + AST_DRAMSTRUCT_REG(AST_REG_MCR68, 0x02020202), + AST_DRAMSTRUCT_REG(AST_REG_MCR70, 0x00000000), + AST_DRAMSTRUCT_REG(AST_REG_MCR74, 0x00000000), + AST_DRAMSTRUCT_REG(AST_REG_MCR78, 0x00000000), + AST_DRAMSTRUCT_REG(AST_REG_MCR7C, 0x00000000), + AST_DRAMSTRUCT_REG(AST_REG_MCR34, 0x00000001), AST_DRAMSTRUCT_UDELAY(67u), - { 0x002C, 0x00000942 }, - { 0x0030, 0x00000040 }, - { 0x0028, 0x00000005 }, - { 0x0028, 0x00000007 }, - { 0x0028, 0x00000003 }, - { 0x0028, 0x00000001 }, - { 0x000C, 0x00005a08 }, - { 0x002C, 0x00000842 }, - { 0x0028, 0x00000001 }, - { 0x0030, 0x000003c0 }, - { 0x0028, 0x00000003 }, - { 0x0030, 0x00000040 }, - { 0x0028, 0x00000003 }, - { 0x000C, 0x00005a21 }, - { 0x0034, 0x00007c03 }, - { 0x0120, 0x00005061 }, + AST_DRAMSTRUCT_REG(AST_REG_MCR2C, 0x00000942), + AST_DRAMSTRUCT_REG(AST_REG_MCR30, 0x00000040), + AST_DRAMSTRUCT_REG(AST_REG_MCR28, 0x00000005), + AST_DRAMSTRUCT_REG(AST_REG_MCR28, 0x00000007), + AST_DRAMSTRUCT_REG(AST_REG_MCR28, 0x00000003), + AST_DRAMSTRUCT_REG(AST_REG_MCR28, 0x00000001), + AST_DRAMSTRUCT_REG(AST_REG_MCR0C, 0x00005a08), + AST_DRAMSTRUCT_REG(AST_REG_MCR2C, 0x00000842), + AST_DRAMSTRUCT_REG(AST_REG_MCR28, 0x00000001), + AST_DRAMSTRUCT_REG(AST_REG_MCR30, 0x000003c0), + AST_DRAMSTRUCT_REG(AST_REG_MCR28, 0x00000003), + AST_DRAMSTRUCT_REG(AST_REG_MCR30, 0x00000040), + AST_DRAMSTRUCT_REG(AST_REG_MCR28, 0x00000003), + AST_DRAMSTRUCT_REG(AST_REG_MCR0C, 0x00005a21), + AST_DRAMSTRUCT_REG(AST_REG_MCR34, 0x00007c03), + AST_DRAMSTRUCT_REG(AST_REG_MCR120, 0x00005061), AST_DRAMSTRUCT_INVALID, }; @@ -328,7 +328,7 @@ static void ast_post_chip_2100(struct ast_device *ast) if (AST_DRAMSTRUCT_IS(dram_reg_info, UDELAY)) { for (i = 0; i < 15; i++) udelay(dram_reg_info->data); - } else if (AST_DRAMSTRUCT_IS(dram_reg_info, DRAM_TYPE)) { + } else if (AST_DRAMSTRUCT_IS_REG(dram_reg_info, AST_REG_MCR04)) { switch (dram_layout) { case AST_DRAM_1Gx16: data = 0x00000d89; @@ -344,10 +344,9 @@ static void ast_post_chip_2100(struct ast_device *ast) temp = ast_read32(ast, 0x12070); temp &= 0xc; temp <<= 2; - ast_write32(ast, 0x10000 + dram_reg_info->index, data | temp); + ast_moutdwm(ast, dram_reg_info->index, data | temp); } else { - ast_write32(ast, 0x10000 + dram_reg_info->index, - dram_reg_info->data); + ast_moutdwm(ast, dram_reg_info->index, dram_reg_info->data); } dram_reg_info++; } diff --git a/drivers/gpu/drm/ast/ast_post.h b/drivers/gpu/drm/ast/ast_post.h index 41cd753b7f67..41b2db08a870 100644 --- a/drivers/gpu/drm/ast/ast_post.h +++ b/drivers/gpu/drm/ast/ast_post.h @@ -10,13 +10,10 @@ struct ast_device; /* DRAM timing tables */ struct ast_dramstruct { - u16 index; + u32 index; u32 data; }; -/* hardware fields */ -#define __AST_DRAMSTRUCT_DRAM_TYPE 0x0004 - /* control commands */ #define __AST_DRAMSTRUCT_UDELAY 0xff00 #define __AST_DRAMSTRUCT_INVALID 0xffff @@ -24,14 +21,18 @@ struct ast_dramstruct { #define __AST_DRAMSTRUCT_INDEX(_name) \ (__AST_DRAMSTRUCT_ ## _name) -#define AST_DRAMSTRUCT_INIT(_name, _value) \ - { __AST_DRAMSTRUCT_INDEX(_name), (_value) } +#define __AST_DRAMSTRUCT_INIT(_index, _value) \ + { (_index), (_value) } +#define AST_DRAMSTRUCT_REG(_reg, _value) \ + __AST_DRAMSTRUCT_INIT(_reg, _value) #define AST_DRAMSTRUCT_UDELAY(_usecs) \ - AST_DRAMSTRUCT_INIT(UDELAY, _usecs) + __AST_DRAMSTRUCT_INIT(__AST_DRAMSTRUCT_UDELAY, _usecs) #define AST_DRAMSTRUCT_INVALID \ - AST_DRAMSTRUCT_INIT(INVALID, U32_MAX) + __AST_DRAMSTRUCT_INIT(__AST_DRAMSTRUCT_INVALID, U32_MAX) +#define AST_DRAMSTRUCT_IS_REG(_entry, _reg) \ + ((_entry)->index == (_reg)) #define AST_DRAMSTRUCT_IS(_entry, _name) \ ((_entry)->index == __AST_DRAMSTRUCT_INDEX(_name)) diff --git a/drivers/gpu/drm/ast/ast_reg.h b/drivers/gpu/drm/ast/ast_reg.h index 78fabe2a9c81..a01af2bfbae6 100644 --- a/drivers/gpu/drm/ast/ast_reg.h +++ b/drivers/gpu/drm/ast/ast_reg.h @@ -120,12 +120,15 @@ #define AST_REG_MCR30 AST_REG_MCR(0x30) #define AST_REG_MCR34 AST_REG_MCR(0x34) #define AST_REG_MCR38 AST_REG_MCR(0x38) +#define AST_REG_MCR3C AST_REG_MCR(0x3c) #define AST_REG_MCR40 AST_REG_MCR(0x40) #define AST_REG_MCR44 AST_REG_MCR(0x44) #define AST_REG_MCR48 AST_REG_MCR(0x48) #define AST_REG_MCR4C AST_REG_MCR(0x4C) #define AST_REG_MCR50 AST_REG_MCR(0x50) #define AST_REG_MCR54 AST_REG_MCR(0x54) +#define AST_REG_MCR58 AST_REG_MCR(0x58) +#define AST_REG_MCR5C AST_REG_MCR(0x5c) #define AST_REG_MCR60 AST_REG_MCR(0x60) #define AST_REG_MCR64 AST_REG_MCR(0x64) #define AST_REG_MCR68 AST_REG_MCR(0x68) @@ -137,6 +140,7 @@ #define AST_REG_MCR80 AST_REG_MCR(0x80) #define AST_REG_MCR84 AST_REG_MCR(0x84) #define AST_REG_MCR88 AST_REG_MCR(0x88) +#define AST_REG_MCR108 AST_REG_MCR(0x108) #define AST_REG_MCR120 AST_REG_MCR(0x120) #define AST_REG_MCR200 AST_REG_MCR(0x200) #define AST_REG_MCR204 AST_REG_MCR(0x204) -- cgit v1.2.3 From d467bcab7b8a8c4494290f830bd6c3b6830a8ebf Mon Sep 17 00:00:00 2001 From: Thomas Zimmermann Date: Fri, 27 Mar 2026 14:33:02 +0100 Subject: drm/ast: Gen1: Fix open-coded register access Replace all open-coded access to MCR registers in Gen1 with the appropriate calls to ast_moutdwm() and ast_mindwm(). Use MCR register constants. For the poll loop on MCR100, add ast_moutdwm_poll(). The helper polls the register until it has been updated to the given value. Relax the CPU while busy-waiting. Signed-off-by: Thomas Zimmermann Reviewed-by: Jocelyn Falempe Link: https://patch.msgid.link/20260327133532.79696-11-tzimmermann@suse.de --- drivers/gpu/drm/ast/ast_2000.c | 18 +++++++----------- drivers/gpu/drm/ast/ast_drv.c | 12 ++++++++++++ drivers/gpu/drm/ast/ast_drv.h | 1 + drivers/gpu/drm/ast/ast_reg.h | 2 ++ 4 files changed, 22 insertions(+), 11 deletions(-) diff --git a/drivers/gpu/drm/ast/ast_2000.c b/drivers/gpu/drm/ast/ast_2000.c index e683edf595e2..4cf951b3533d 100644 --- a/drivers/gpu/drm/ast/ast_2000.c +++ b/drivers/gpu/drm/ast/ast_2000.c @@ -99,20 +99,15 @@ static const struct ast_dramstruct ast2000_dram_table_data[] = { static void ast_post_chip_2000(struct ast_device *ast) { u8 j; - u32 temp, i; - const struct ast_dramstruct *dram_reg_info; + u32 i; j = ast_get_index_reg_mask(ast, AST_IO_VGACRI, 0xd0, 0xff); if ((j & 0x80) == 0) { /* VGA only */ - dram_reg_info = ast2000_dram_table_data; - ast_write32(ast, 0xf004, AST_REG_MCR00); - ast_write32(ast, 0xf000, 0x1); - ast_write32(ast, 0x10100, 0xa8); + const struct ast_dramstruct *dram_reg_info = ast2000_dram_table_data; + u32 mcr140; - do { - ; - } while (ast_read32(ast, 0x10100) != 0xa8); + ast_moutdwm_poll(ast, AST_REG_MCR100, 0xa8, 0xa8); while (!AST_DRAMSTRUCT_IS(dram_reg_info, INVALID)) { if (AST_DRAMSTRUCT_IS(dram_reg_info, UDELAY)) { @@ -124,8 +119,9 @@ static void ast_post_chip_2000(struct ast_device *ast) dram_reg_info++; } - temp = ast_read32(ast, 0x10140); - ast_write32(ast, 0x10140, temp | 0x40); + mcr140 = ast_mindwm(ast, AST_REG_MCR140); + mcr140 |= 0x00000040; + ast_moutdwm(ast, AST_REG_MCR140, mcr140); } /* wait ready */ diff --git a/drivers/gpu/drm/ast/ast_drv.c b/drivers/gpu/drm/ast/ast_drv.c index 3da0cce0a3f6..6fe549f16309 100644 --- a/drivers/gpu/drm/ast/ast_drv.c +++ b/drivers/gpu/drm/ast/ast_drv.c @@ -102,6 +102,18 @@ void ast_moutdwm(struct ast_device *ast, u32 r, u32 v) __ast_moutdwm(ast->regs, r, v); } +void ast_moutdwm_poll(struct ast_device *ast, u32 r, u32 v, u32 res) +{ + void __iomem *regs = ast->regs; + + __ast_selseg(regs, r); + __ast_wrseg32(regs, r, v); + + do { + cpu_relax(); + } while (__ast_rdseg32(regs, r) != res); +} + /* * AST device */ diff --git a/drivers/gpu/drm/ast/ast_drv.h b/drivers/gpu/drm/ast/ast_drv.h index 3eedf8239333..4f221b848d68 100644 --- a/drivers/gpu/drm/ast/ast_drv.h +++ b/drivers/gpu/drm/ast/ast_drv.h @@ -361,6 +361,7 @@ u32 __ast_mindwm(void __iomem *regs, u32 r); void __ast_moutdwm(void __iomem *regs, u32 r, u32 v); u32 ast_mindwm(struct ast_device *ast, u32 r); void ast_moutdwm(struct ast_device *ast, u32 r, u32 v); +void ast_moutdwm_poll(struct ast_device *ast, u32 r, u32 v, u32 res); /* * VBIOS diff --git a/drivers/gpu/drm/ast/ast_reg.h b/drivers/gpu/drm/ast/ast_reg.h index a01af2bfbae6..9ebdbbde9a47 100644 --- a/drivers/gpu/drm/ast/ast_reg.h +++ b/drivers/gpu/drm/ast/ast_reg.h @@ -140,8 +140,10 @@ #define AST_REG_MCR80 AST_REG_MCR(0x80) #define AST_REG_MCR84 AST_REG_MCR(0x84) #define AST_REG_MCR88 AST_REG_MCR(0x88) +#define AST_REG_MCR100 AST_REG_MCR(0x100) #define AST_REG_MCR108 AST_REG_MCR(0x108) #define AST_REG_MCR120 AST_REG_MCR(0x120) +#define AST_REG_MCR140 AST_REG_MCR(0x140) #define AST_REG_MCR200 AST_REG_MCR(0x200) #define AST_REG_MCR204 AST_REG_MCR(0x204) #define AST_REG_MCR208 AST_REG_MCR(0x208) -- cgit v1.2.3 From fe727ff281239eeefea4e9d2ffb9544b82d7c46f Mon Sep 17 00:00:00 2001 From: Thomas Zimmermann Date: Fri, 27 Mar 2026 14:33:03 +0100 Subject: drm/ast: Gen2: Fix open-coded register access Replace all open-coded access to MCR and SCU registers in Gen2 with the appropriate calls to ast_moutdwm() and ast_mindwm(). Use MCR and SCU register constants. Name variables according to registers. The values in MCR04 that control VRAM allocation do not look correct. Leave a FIXME comment for later investigation. Signed-off-by: Thomas Zimmermann Reviewed-by: Jocelyn Falempe Link: https://patch.msgid.link/20260327133532.79696-12-tzimmermann@suse.de --- drivers/gpu/drm/ast/ast_2100.c | 73 ++++++++++++++++++++++-------------------- 1 file changed, 38 insertions(+), 35 deletions(-) diff --git a/drivers/gpu/drm/ast/ast_2100.c b/drivers/gpu/drm/ast/ast_2100.c index 930e9f2d0ccf..5cf8ad9c3446 100644 --- a/drivers/gpu/drm/ast/ast_2100.c +++ b/drivers/gpu/drm/ast/ast_2100.c @@ -40,21 +40,19 @@ static enum ast_dram_layout ast_2100_get_dram_layout_p2a(struct ast_device *ast) { - u32 mcr_cfg; + u32 mcr04; enum ast_dram_layout dram_layout; - ast_write32(ast, 0xf004, AST_REG_MCR00); - ast_write32(ast, 0xf000, 0x1); - mcr_cfg = ast_read32(ast, 0x10004); + mcr04 = ast_mindwm(ast, AST_REG_MCR04); - switch (mcr_cfg & 0x0c) { + switch (mcr04 & GENMASK(3, 2)) { case 0: case 4: default: dram_layout = AST_DRAM_512Mx16; break; case 8: - if (mcr_cfg & 0x40) + if (mcr04 & 0x40) dram_layout = AST_DRAM_1Gx16; else dram_layout = AST_DRAM_512Mx32; @@ -300,51 +298,52 @@ cbr_start: static void ast_post_chip_2100(struct ast_device *ast) { u8 j; - u32 data, temp, i; - const struct ast_dramstruct *dram_reg_info; - enum ast_dram_layout dram_layout = ast_2100_get_dram_layout_p2a(ast); + u32 i; + enum ast_dram_layout dram_layout = ast_2100_get_dram_layout_p2a(ast); + u32 mcr120; + u32 scu00c, scu040; j = ast_get_index_reg_mask(ast, AST_IO_VGACRI, 0xd0, 0xff); if ((j & 0x80) == 0) { /* VGA only */ + const struct ast_dramstruct *dram_reg_info; + if (ast->chip == AST2100 || ast->chip == AST2200) dram_reg_info = ast2100_dram_table_data; else dram_reg_info = ast1100_dram_table_data; - ast_write32(ast, 0xf004, AST_REG_MCR00); - ast_write32(ast, 0xf000, 0x1); - ast_write32(ast, 0x12000, 0x1688A8A8); - do { - ; - } while (ast_read32(ast, 0x12000) != 0x01); - - ast_write32(ast, 0x10000, 0xfc600309); - do { - ; - } while (ast_read32(ast, 0x10000) != 0x01); + ast_moutdwm_poll(ast, AST_REG_SCU000, AST_REG_SCU000_PROTECTION_KEY, 0x01); + ast_moutdwm_poll(ast, AST_REG_MCR00, AST_REG_MCR00_PROTECTION_KEY, 0x01); while (!AST_DRAMSTRUCT_IS(dram_reg_info, INVALID)) { if (AST_DRAMSTRUCT_IS(dram_reg_info, UDELAY)) { for (i = 0; i < 15; i++) udelay(dram_reg_info->data); } else if (AST_DRAMSTRUCT_IS_REG(dram_reg_info, AST_REG_MCR04)) { + u32 mcr04; + u32 scu070; + switch (dram_layout) { case AST_DRAM_1Gx16: - data = 0x00000d89; + mcr04 = 0x00000d89; break; case AST_DRAM_1Gx32: - data = 0x00000c8d; + mcr04 = 0x00000c8d; break; default: - data = dram_reg_info->data; + mcr04 = dram_reg_info->data; break; } - temp = ast_read32(ast, 0x12070); - temp &= 0xc; - temp <<= 2; - ast_moutdwm(ast, dram_reg_info->index, data | temp); + /* + * FIXME: There might be bits already in MCR04[5:4]. Should + * we only do this in the default case? + */ + scu070 = ast_mindwm(ast, AST_REG_SCU070); + mcr04 |= (scu070 & GENMASK(3, 2)) << 2; + + ast_moutdwm(ast, dram_reg_info->index, mcr04); } else { ast_moutdwm(ast, dram_reg_info->index, dram_reg_info->data); } @@ -352,19 +351,23 @@ static void ast_post_chip_2100(struct ast_device *ast) } /* AST 2100/2150 DRAM calibration */ - data = ast_read32(ast, 0x10120); - if (data == 0x5061) { /* 266Mhz */ - data = ast_read32(ast, 0x10004); - if (data & 0x40) + mcr120 = ast_mindwm(ast, AST_REG_MCR120); + if (mcr120 == 0x5061) { /* 266Mhz */ + u32 mcr04 = ast_mindwm(ast, AST_REG_MCR04); + + if (mcr04 & 0x40) cbrdlli_ast2150(ast, 16); /* 16 bits */ else cbrdlli_ast2150(ast, 32); /* 32 bits */ } - temp = ast_read32(ast, 0x1200c); - ast_write32(ast, 0x1200c, temp & 0xfffffffd); - temp = ast_read32(ast, 0x12040); - ast_write32(ast, 0x12040, temp | 0x40); + scu00c = ast_mindwm(ast, AST_REG_SCU00C); + scu00c &= 0xfffffffd; + ast_moutdwm(ast, AST_REG_SCU00C, scu00c); + + scu040 = ast_mindwm(ast, AST_REG_SCU040); + scu040 |= 0x00000040; + ast_moutdwm(ast, AST_REG_SCU040, scu040); } /* wait ready */ -- cgit v1.2.3 From 24946c2aa0f1bbafe8089187aa08fb5d417fd069 Mon Sep 17 00:00:00 2001 From: Thomas Zimmermann Date: Fri, 27 Mar 2026 14:33:04 +0100 Subject: drm/ast: Gen4: Fix open-coded register access Replace all open-coded access to MCR and SCU registers in Gen4 with the appropriate calls to ast_moutdwm() and ast_mindwm(). Use MCR and SCU register constants. Name variables according to registers. Signed-off-by: Thomas Zimmermann Reviewed-by: Jocelyn Falempe Link: https://patch.msgid.link/20260327133532.79696-13-tzimmermann@suse.de --- drivers/gpu/drm/ast/ast_2300.c | 24 +++++++++--------------- drivers/gpu/drm/ast/ast_reg.h | 1 + 2 files changed, 10 insertions(+), 15 deletions(-) diff --git a/drivers/gpu/drm/ast/ast_2300.c b/drivers/gpu/drm/ast/ast_2300.c index 96d9909d942c..cbeac6990c27 100644 --- a/drivers/gpu/drm/ast/ast_2300.c +++ b/drivers/gpu/drm/ast/ast_2300.c @@ -1245,22 +1245,15 @@ static void ast_post_chip_2300(struct ast_device *ast) reg = ast_get_index_reg_mask(ast, AST_IO_VGACRI, 0xd0, 0xff); if ((reg & 0x80) == 0) {/* vga only */ - ast_write32(ast, 0xf004, AST_REG_MCR00); - ast_write32(ast, 0xf000, 0x1); - ast_write32(ast, 0x12000, 0x1688a8a8); - do { - ; - } while (ast_read32(ast, 0x12000) != 0x1); + u32 scu008, scu040; - ast_write32(ast, 0x10000, 0xfc600309); - do { - ; - } while (ast_read32(ast, 0x10000) != 0x1); + ast_moutdwm_poll(ast, AST_REG_SCU000, AST_REG_SCU000_PROTECTION_KEY, 0x01); + ast_moutdwm_poll(ast, AST_REG_MCR00, AST_REG_MCR00_PROTECTION_KEY, 0x01); /* Slow down CPU/AHB CLK in VGA only mode */ - temp = ast_read32(ast, 0x12008); - temp |= 0x73; - ast_write32(ast, 0x12008, temp); + scu008 = ast_mindwm(ast, AST_REG_SCU008); + scu008 |= 0x00000073; + ast_moutdwm(ast, AST_REG_SCU008, scu008); param.dram_freq = 396; param.dram_type = AST_DDR3; @@ -1306,8 +1299,9 @@ static void ast_post_chip_2300(struct ast_device *ast) ddr2_init(ast, ¶m); } - temp = ast_mindwm(ast, AST_REG_SCU040); - ast_moutdwm(ast, AST_REG_SCU040, temp | 0x40); + scu040 = ast_mindwm(ast, AST_REG_SCU040); + scu040 |= 0x00000040; + ast_moutdwm(ast, AST_REG_SCU040, scu040); } /* wait ready */ diff --git a/drivers/gpu/drm/ast/ast_reg.h b/drivers/gpu/drm/ast/ast_reg.h index 9ebdbbde9a47..c3473cad4545 100644 --- a/drivers/gpu/drm/ast/ast_reg.h +++ b/drivers/gpu/drm/ast/ast_reg.h @@ -183,6 +183,7 @@ #define AST_REG_SCU(__offset) (AST_REG_SCU_BASE + (__offset)) #define AST_REG_SCU000 AST_REG_SCU(0x000) #define AST_REG_SCU000_PROTECTION_KEY (0x1688a8a8) +#define AST_REG_SCU008 AST_REG_SCU(0x008) #define AST_REG_SCU00C AST_REG_SCU(0x00c) #define AST_REG_SCU020 AST_REG_SCU(0x020) #define AST_REG_SCU040 AST_REG_SCU(0x040) -- cgit v1.2.3 From 562aa0d24d9ef22f3e39c6e4dd99eeba4617edb2 Mon Sep 17 00:00:00 2001 From: Thomas Zimmermann Date: Fri, 27 Mar 2026 14:33:05 +0100 Subject: drm/ast: Gen6: Fix open-coded register access Replace all open-coded access to MCR and SCU registers in Gen6 with the appropriate calls to ast_moutdwm() and ast_mindwm(). Use MCR and SCU register constants. Name variables according to registers. v2: - also fix MCR constants Signed-off-by: Thomas Zimmermann Reviewed-by: Jocelyn Falempe Link: https://patch.msgid.link/20260327133532.79696-14-tzimmermann@suse.de --- drivers/gpu/drm/ast/ast_2500.c | 16 ++++++++-------- drivers/gpu/drm/ast/ast_reg.h | 1 + 2 files changed, 9 insertions(+), 8 deletions(-) diff --git a/drivers/gpu/drm/ast/ast_2500.c b/drivers/gpu/drm/ast/ast_2500.c index 39f401dd1f47..03a67ec9684b 100644 --- a/drivers/gpu/drm/ast/ast_2500.c +++ b/drivers/gpu/drm/ast/ast_2500.c @@ -280,15 +280,13 @@ static void enable_cache_2500(struct ast_device *ast) static void set_mpll_2500(struct ast_device *ast) { - u32 addr, data, param; + u32 mcr, data, param; /* Reset MMC */ ast_moutdwm(ast, AST_REG_MCR00, AST_REG_MCR00_PROTECTION_KEY); ast_moutdwm(ast, AST_REG_MCR34, 0x00020080); - for (addr = 0x1e6e0004; addr < 0x1e6e0090;) { - ast_moutdwm(ast, addr, 0x0); - addr += 4; - } + for (mcr = AST_REG_MCR04; mcr <= AST_REG_MCR8C; mcr += 4) + ast_moutdwm(ast, mcr, 0x00000000); ast_moutdwm(ast, AST_REG_MCR34, 0x00020000); ast_moutdwm(ast, AST_REG_SCU000, AST_REG_SCU000_PROTECTION_KEY); @@ -507,6 +505,8 @@ static void ast_post_chip_2500(struct ast_device *ast) reg = ast_get_index_reg_mask(ast, AST_IO_VGACRI, 0xd0, 0xff); if ((reg & AST_IO_VGACRD0_VRAM_INIT_STATUS_MASK) == 0) {/* vga only */ + u32 scu008; + /* Clear bus lock condition */ ast_2500_patch_ahb(ast->regs); @@ -540,9 +540,9 @@ static void ast_post_chip_2500(struct ast_device *ast) ast_moutdwm(ast, AST_REG_SCU07C, 0x00004000); /* Slow down CPU/AHB CLK in VGA only mode */ - temp = ast_read32(ast, 0x12008); - temp |= 0x73; - ast_write32(ast, 0x12008, temp); + scu008 = ast_mindwm(ast, AST_REG_SCU008); + scu008 |= 0x00000073; + ast_moutdwm(ast, AST_REG_SCU008, scu008); if (!ast_dram_init_2500(ast)) drm_err(dev, "DRAM init failed !\n"); diff --git a/drivers/gpu/drm/ast/ast_reg.h b/drivers/gpu/drm/ast/ast_reg.h index c3473cad4545..b7259d44a822 100644 --- a/drivers/gpu/drm/ast/ast_reg.h +++ b/drivers/gpu/drm/ast/ast_reg.h @@ -140,6 +140,7 @@ #define AST_REG_MCR80 AST_REG_MCR(0x80) #define AST_REG_MCR84 AST_REG_MCR(0x84) #define AST_REG_MCR88 AST_REG_MCR(0x88) +#define AST_REG_MCR8C AST_REG_MCR(0x8c) #define AST_REG_MCR100 AST_REG_MCR(0x100) #define AST_REG_MCR108 AST_REG_MCR(0x108) #define AST_REG_MCR120 AST_REG_MCR(0x120) -- cgit v1.2.3 From e60dccc256c89b9ce86dcbddad27dd7d1c6c095c Mon Sep 17 00:00:00 2001 From: Thomas Zimmermann Date: Fri, 27 Mar 2026 14:33:06 +0100 Subject: drm/ast: dp501: Fix open-coded register access Replace all open-coded access to SCU registers in DP501 support with the appropriate calls to ast_moutdwm() and ast_mindwm(). Use SCU register constants. Name variables according to registers. Signed-off-by: Thomas Zimmermann Reviewed-by: Jocelyn Falempe Link: https://patch.msgid.link/20260327133532.79696-15-tzimmermann@suse.de --- drivers/gpu/drm/ast/ast_dp501.c | 124 +++++++++++++++++++--------------------- drivers/gpu/drm/ast/ast_reg.h | 6 ++ 2 files changed, 64 insertions(+), 66 deletions(-) diff --git a/drivers/gpu/drm/ast/ast_dp501.c b/drivers/gpu/drm/ast/ast_dp501.c index 23142119d733..98d8491ce6c9 100644 --- a/drivers/gpu/drm/ast/ast_dp501.c +++ b/drivers/gpu/drm/ast/ast_dp501.c @@ -347,68 +347,65 @@ static int ast_dp512_read_edid_block(void *data, u8 *buf, unsigned int block, si static bool ast_init_dvo(struct ast_device *ast) { u8 jreg; - u32 data; - ast_write32(ast, 0xf004, AST_REG_MCR00); - ast_write32(ast, 0xf000, 0x1); - ast_write32(ast, 0x12000, 0x1688a8a8); + u32 scu02c; + + ast_moutdwm(ast, AST_REG_SCU000, AST_REG_SCU000_PROTECTION_KEY); jreg = ast_get_index_reg_mask(ast, AST_IO_VGACRI, 0xd0, 0xff); if (!(jreg & 0x80)) { + u32 scu008; + /* Init SCU DVO Settings */ - data = ast_read32(ast, 0x12008); - /* delay phase */ - data &= 0xfffff8ff; - data |= 0x00000500; - ast_write32(ast, 0x12008, data); + + scu008 = ast_mindwm(ast, AST_REG_SCU008); + scu008 &= 0xfffff8ff; + scu008 |= 0x00000500; /* delay phase */ + ast_moutdwm(ast, AST_REG_SCU008, scu008); if (IS_AST_GEN4(ast)) { - data = ast_read32(ast, 0x12084); - /* multi-pins for DVO single-edge */ - data |= 0xfffe0000; - ast_write32(ast, 0x12084, data); - - data = ast_read32(ast, 0x12088); - /* multi-pins for DVO single-edge */ - data |= 0x000fffff; - ast_write32(ast, 0x12088, data); - - data = ast_read32(ast, 0x12090); - /* multi-pins for DVO single-edge */ - data &= 0xffffffcf; - data |= 0x00000020; - ast_write32(ast, 0x12090, data); + u32 scu084, scu088, scu090; + + scu084 = ast_mindwm(ast, AST_REG_SCU084); + scu084 |= 0xfffe0000; /* multi-pins for DVO single-edge */ + ast_moutdwm(ast, AST_REG_SCU084, scu084); + + scu088 = ast_mindwm(ast, AST_REG_SCU088); + scu088 |= 0x000fffff; /* multi-pins for DVO single-edge */ + ast_moutdwm(ast, AST_REG_SCU088, scu088); + + scu090 = ast_mindwm(ast, AST_REG_SCU090); + scu090 &= 0xffffffcf; + scu090 |= 0x00000020; /* multi-pins for DVO single-edge */ + ast_moutdwm(ast, AST_REG_SCU090, scu090); } else { /* AST GEN5+ */ - data = ast_read32(ast, 0x12088); - /* multi-pins for DVO single-edge */ - data |= 0x30000000; - ast_write32(ast, 0x12088, data); - - data = ast_read32(ast, 0x1208c); - /* multi-pins for DVO single-edge */ - data |= 0x000000cf; - ast_write32(ast, 0x1208c, data); - - data = ast_read32(ast, 0x120a4); - /* multi-pins for DVO single-edge */ - data |= 0xffff0000; - ast_write32(ast, 0x120a4, data); - - data = ast_read32(ast, 0x120a8); - /* multi-pins for DVO single-edge */ - data |= 0x0000000f; - ast_write32(ast, 0x120a8, data); - - data = ast_read32(ast, 0x12094); - /* multi-pins for DVO single-edge */ - data |= 0x00000002; - ast_write32(ast, 0x12094, data); + u32 scu088, scu08c, scu0a4, scu0a8, scu094; + + scu088 = ast_mindwm(ast, AST_REG_SCU088); + scu088 |= 0x30000000; /* multi-pins for DVO single-edge */ + ast_moutdwm(ast, AST_REG_SCU088, scu088); + + scu08c = ast_mindwm(ast, AST_REG_SCU08C); + scu08c |= 0x000000cf; /* multi-pins for DVO single-edge */ + ast_moutdwm(ast, AST_REG_SCU08C, scu08c); + + scu0a4 = ast_mindwm(ast, AST_REG_SCU0A4); + scu0a4 |= 0xffff0000; /* multi-pins for DVO single-edge */ + ast_moutdwm(ast, AST_REG_SCU0A4, scu0a4); + + scu0a8 = ast_mindwm(ast, AST_REG_SCU0A8); + scu0a8 |= 0x0000000f; /* multi-pins for DVO single-edge */ + ast_moutdwm(ast, AST_REG_SCU0A8, scu0a8); + + scu094 = ast_mindwm(ast, AST_REG_SCU094); + scu094 |= 0x00000002; /* multi-pins for DVO single-edge */ + ast_moutdwm(ast, AST_REG_SCU094, scu094); } } /* Force to DVO */ - data = ast_read32(ast, 0x1202c); - data &= 0xfffbffff; - ast_write32(ast, 0x1202c, data); + scu02c = ast_mindwm(ast, AST_REG_SCU02C); + scu02c &= 0xfffbffff; + ast_moutdwm(ast, AST_REG_SCU02C, scu02c); /* Init VGA DVO Settings */ ast_set_index_reg_mask(ast, AST_IO_VGACRI, 0xa3, 0xcf, 0x80); @@ -418,25 +415,20 @@ static bool ast_init_dvo(struct ast_device *ast) static void ast_init_analog(struct ast_device *ast) { - u32 data; + u32 scu02c; /* * Set DAC source to VGA mode in SCU2C via the P2A - * bridge. First configure the P2U to target the SCU - * in case it isn't at this stage. + * bridge. */ - ast_write32(ast, 0xf004, AST_REG_MCR00); - ast_write32(ast, 0xf000, 0x1); - - /* Then unlock the SCU with the magic password */ - ast_write32(ast, 0x12000, 0x1688a8a8); - ast_write32(ast, 0x12000, 0x1688a8a8); - ast_write32(ast, 0x12000, 0x1688a8a8); - - /* Finally, clear bits [17:16] of SCU2c */ - data = ast_read32(ast, 0x1202c); - data &= 0xfffcffff; - ast_write32(ast, 0x1202c, data); + + /* Unlock the SCU with the magic password */ + ast_moutdwm_poll(ast, AST_REG_SCU000, AST_REG_SCU000_PROTECTION_KEY, 0x01); + + /* Clear bits [17:16] of SCU2C */ + scu02c = ast_mindwm(ast, AST_REG_SCU02C); + scu02c &= 0xfffcffff; + ast_moutdwm(ast, AST_REG_SCU02C, scu02c); /* Disable DVO */ ast_set_index_reg_mask(ast, AST_IO_VGACRI, 0xa3, 0xcf, 0x00); diff --git a/drivers/gpu/drm/ast/ast_reg.h b/drivers/gpu/drm/ast/ast_reg.h index b7259d44a822..92cfa02b642f 100644 --- a/drivers/gpu/drm/ast/ast_reg.h +++ b/drivers/gpu/drm/ast/ast_reg.h @@ -187,11 +187,17 @@ #define AST_REG_SCU008 AST_REG_SCU(0x008) #define AST_REG_SCU00C AST_REG_SCU(0x00c) #define AST_REG_SCU020 AST_REG_SCU(0x020) +#define AST_REG_SCU02C AST_REG_SCU(0x02c) #define AST_REG_SCU040 AST_REG_SCU(0x040) #define AST_REG_SCU070 AST_REG_SCU(0x070) #define AST_REG_SCU07C AST_REG_SCU(0x07c) +#define AST_REG_SCU084 AST_REG_SCU(0x084) +#define AST_REG_SCU088 AST_REG_SCU(0x088) +#define AST_REG_SCU08C AST_REG_SCU(0x08c) #define AST_REG_SCU090 AST_REG_SCU(0x090) #define AST_REG_SCU094 AST_REG_SCU(0x094) +#define AST_REG_SCU0A4 AST_REG_SCU(0x0a4) +#define AST_REG_SCU0A8 AST_REG_SCU(0x0a8) #define AST_REG_SCU100 AST_REG_SCU(0x100) #define AST_REG_SCU104 AST_REG_SCU(0x104) #define AST_REG_SCU160 AST_REG_SCU(0x160) -- cgit v1.2.3 From 53217ef45611a14d32d77f6a0627069780d23f3e Mon Sep 17 00:00:00 2001 From: Thomas Zimmermann Date: Fri, 27 Mar 2026 14:33:07 +0100 Subject: drm/ast: Fix open-coded scu_rev access Replace all open-coded access to P2A and SCU registers in the device detection with the appropriate calls to ast_moutdwm() and ast_mindwm(). Use P2A and MCR register constants. Name variables according to registers. Signed-off-by: Thomas Zimmermann Reviewed-by: Jocelyn Falempe Link: https://patch.msgid.link/20260327133532.79696-16-tzimmermann@suse.de --- drivers/gpu/drm/ast/ast_drv.c | 13 ++++++------- drivers/gpu/drm/ast/ast_reg.h | 1 + 2 files changed, 7 insertions(+), 7 deletions(-) diff --git a/drivers/gpu/drm/ast/ast_drv.c b/drivers/gpu/drm/ast/ast_drv.c index 6fe549f16309..ba6cf5fa901c 100644 --- a/drivers/gpu/drm/ast/ast_drv.c +++ b/drivers/gpu/drm/ast/ast_drv.c @@ -242,7 +242,7 @@ static int ast_detect_chip(struct pci_dev *pdev, enum ast_config_mode config_mode = ast_use_defaults; uint32_t scu_rev = 0xffffffff; enum ast_chip chip; - u32 data; + u32 data, p2a04, scu07c; u8 vgacrd0, vgacrd1; /* @@ -275,14 +275,13 @@ static int ast_detect_chip(struct pci_dev *pdev, } /* Double check that it's actually working */ - data = __ast_read32(regs, 0xf004); - if ((data != 0xffffffff) && (data != 0x00)) { + p2a04 = __ast_read32(regs, AST_REG_P2A04); + if (p2a04 != 0xffffffff && p2a04 != 0x00000000) { config_mode = ast_use_p2a; - /* Read SCU7c (silicon revision register) */ - __ast_write32(regs, 0xf004, AST_REG_MCR00); - __ast_write32(regs, 0xf000, 0x1); - scu_rev = __ast_read32(regs, 0x1207c); + /* Read SCU7C (silicon revision register) */ + scu07c = __ast_mindwm(regs, AST_REG_SCU07C); + scu_rev = scu07c & AST_REG_SCU07C_CHIP_BONDING_MASK; } } } diff --git a/drivers/gpu/drm/ast/ast_reg.h b/drivers/gpu/drm/ast/ast_reg.h index 92cfa02b642f..ea7dc382aee7 100644 --- a/drivers/gpu/drm/ast/ast_reg.h +++ b/drivers/gpu/drm/ast/ast_reg.h @@ -191,6 +191,7 @@ #define AST_REG_SCU040 AST_REG_SCU(0x040) #define AST_REG_SCU070 AST_REG_SCU(0x070) #define AST_REG_SCU07C AST_REG_SCU(0x07c) +#define AST_REG_SCU07C_CHIP_BONDING_MASK GENMASK(15, 8) #define AST_REG_SCU084 AST_REG_SCU(0x084) #define AST_REG_SCU088 AST_REG_SCU(0x088) #define AST_REG_SCU08C AST_REG_SCU(0x08c) -- cgit v1.2.3 From d54377e487a7576d076e4993e80b7d1cded81b0a Mon Sep 17 00:00:00 2001 From: Jani Nikula Date: Tue, 7 Apr 2026 22:36:26 +0300 Subject: drm/i915/mchbar: include intel_mchbar_regs.h from intel_mchbar.h MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit As an exception to the rule of not including unnecessary headers from headers, include intel_mchbar_regs.h from intel_mchbar.h. In order to use the interfaces in intel_mchbar.h you will always have to include the registers anyway, so the includes are in pairs everywhere. There is zero asymmetry. Simplify. Reviewed-by: Ville Syrjälä Link: https://patch.msgid.link/e44dc2daf3fc39d02c3f598c323caa3c08a54304.1775590536.git.jani.nikula@intel.com Signed-off-by: Jani Nikula --- drivers/gpu/drm/i915/display/i9xx_wm.c | 1 - drivers/gpu/drm/i915/display/intel_bw.c | 1 - drivers/gpu/drm/i915/display/intel_cdclk.c | 1 - drivers/gpu/drm/i915/display/intel_display_power.c | 1 - drivers/gpu/drm/i915/display/intel_dram.c | 1 - drivers/gpu/drm/i915/display/intel_mchbar.c | 1 - drivers/gpu/drm/i915/display/intel_mchbar.h | 1 + 7 files changed, 1 insertion(+), 6 deletions(-) diff --git a/drivers/gpu/drm/i915/display/i9xx_wm.c b/drivers/gpu/drm/i915/display/i9xx_wm.c index 3dbfb850fe1d..02ac6f9a3d0e 100644 --- a/drivers/gpu/drm/i915/display/i9xx_wm.c +++ b/drivers/gpu/drm/i915/display/i9xx_wm.c @@ -20,7 +20,6 @@ #include "intel_dram.h" #include "intel_fb.h" #include "intel_mchbar.h" -#include "intel_mchbar_regs.h" #include "intel_wm.h" #include "skl_watermark.h" #include "vlv_sideband.h" diff --git a/drivers/gpu/drm/i915/display/intel_bw.c b/drivers/gpu/drm/i915/display/intel_bw.c index e6c8fd630294..474438fc1ebc 100644 --- a/drivers/gpu/drm/i915/display/intel_bw.c +++ b/drivers/gpu/drm/i915/display/intel_bw.c @@ -16,7 +16,6 @@ #include "intel_display_utils.h" #include "intel_dram.h" #include "intel_mchbar.h" -#include "intel_mchbar_regs.h" #include "intel_parent.h" #include "skl_watermark.h" diff --git a/drivers/gpu/drm/i915/display/intel_cdclk.c b/drivers/gpu/drm/i915/display/intel_cdclk.c index 835a332e9686..82955cf16c4c 100644 --- a/drivers/gpu/drm/i915/display/intel_cdclk.c +++ b/drivers/gpu/drm/i915/display/intel_cdclk.c @@ -42,7 +42,6 @@ #include "intel_display_wa.h" #include "intel_dram.h" #include "intel_mchbar.h" -#include "intel_mchbar_regs.h" #include "intel_parent.h" #include "intel_pci_config.h" #include "intel_plane.h" diff --git a/drivers/gpu/drm/i915/display/intel_display_power.c b/drivers/gpu/drm/i915/display/intel_display_power.c index 98e5a794fab7..4091b7c4914f 100644 --- a/drivers/gpu/drm/i915/display/intel_display_power.c +++ b/drivers/gpu/drm/i915/display/intel_display_power.c @@ -25,7 +25,6 @@ #include "intel_dmc.h" #include "intel_dram.h" #include "intel_mchbar.h" -#include "intel_mchbar_regs.h" #include "intel_parent.h" #include "intel_pch_refclk.h" #include "intel_pmdemand.h" diff --git a/drivers/gpu/drm/i915/display/intel_dram.c b/drivers/gpu/drm/i915/display/intel_dram.c index 2079c63e3649..f103f7cba018 100644 --- a/drivers/gpu/drm/i915/display/intel_dram.c +++ b/drivers/gpu/drm/i915/display/intel_dram.c @@ -15,7 +15,6 @@ #include "intel_display_regs.h" #include "intel_dram.h" #include "intel_mchbar.h" -#include "intel_mchbar_regs.h" #include "intel_parent.h" #include "vlv_sideband.h" diff --git a/drivers/gpu/drm/i915/display/intel_mchbar.c b/drivers/gpu/drm/i915/display/intel_mchbar.c index 16fcfe1e93ec..a0d0a796c6bb 100644 --- a/drivers/gpu/drm/i915/display/intel_mchbar.c +++ b/drivers/gpu/drm/i915/display/intel_mchbar.c @@ -10,7 +10,6 @@ #include "intel_de.h" #include "intel_display_core.h" #include "intel_mchbar.h" -#include "intel_mchbar_regs.h" static bool has_mchbar_mirror(struct intel_display *display) { diff --git a/drivers/gpu/drm/i915/display/intel_mchbar.h b/drivers/gpu/drm/i915/display/intel_mchbar.h index 002a4454e8ed..51ecd6075bdf 100644 --- a/drivers/gpu/drm/i915/display/intel_mchbar.h +++ b/drivers/gpu/drm/i915/display/intel_mchbar.h @@ -9,6 +9,7 @@ #include #include "i915_reg_defs.h" +#include "intel_mchbar_regs.h" struct intel_display; -- cgit v1.2.3 From aa7d8dfae8a5069259da73c0184d6aa7b7d61ca4 Mon Sep 17 00:00:00 2001 From: Jani Nikula Date: Tue, 7 Apr 2026 22:36:27 +0300 Subject: drm/i915/mchbar: drop unnecessary intel_mchbar_regs.h include MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit There are some unnecessary includes. Remove. Suggested-by: Ville Syrjälä Reviewed-by: Ville Syrjälä Link: https://patch.msgid.link/7eaf98e648240e3011bfb85d0330787074c39205.1775590536.git.jani.nikula@intel.com Signed-off-by: Jani Nikula --- drivers/gpu/drm/i915/gt/intel_gt_pm_debugfs.c | 1 - drivers/gpu/drm/i915/gt/uc/intel_guc_slpc.c | 1 - drivers/gpu/drm/i915/gvt/handlers.c | 1 - 3 files changed, 3 deletions(-) diff --git a/drivers/gpu/drm/i915/gt/intel_gt_pm_debugfs.c b/drivers/gpu/drm/i915/gt/intel_gt_pm_debugfs.c index babaf16e72f2..adf2512e2ed5 100644 --- a/drivers/gpu/drm/i915/gt/intel_gt_pm_debugfs.c +++ b/drivers/gpu/drm/i915/gt/intel_gt_pm_debugfs.c @@ -19,7 +19,6 @@ #include "intel_gt_pm_debugfs.h" #include "intel_gt_regs.h" #include "intel_llc.h" -#include "intel_mchbar_regs.h" #include "intel_pcode.h" #include "intel_rc6.h" #include "intel_rps.h" diff --git a/drivers/gpu/drm/i915/gt/uc/intel_guc_slpc.c b/drivers/gpu/drm/i915/gt/uc/intel_guc_slpc.c index fa9af08f9708..a75f05ff1110 100644 --- a/drivers/gpu/drm/i915/gt/uc/intel_guc_slpc.c +++ b/drivers/gpu/drm/i915/gt/uc/intel_guc_slpc.c @@ -16,7 +16,6 @@ #include "i915_wait_util.h" #include "intel_guc_print.h" #include "intel_guc_slpc.h" -#include "intel_mchbar_regs.h" /** * DOC: SLPC - Dynamic Frequency management diff --git a/drivers/gpu/drm/i915/gvt/handlers.c b/drivers/gpu/drm/i915/gvt/handlers.c index a34f56630af9..9f61867e2478 100644 --- a/drivers/gpu/drm/i915/gvt/handlers.c +++ b/drivers/gpu/drm/i915/gvt/handlers.c @@ -71,7 +71,6 @@ #include "i915_drv.h" #include "i915_pvinfo.h" #include "i915_reg.h" -#include "intel_mchbar_regs.h" #include "sched_policy.h" /* XXX FIXME i915 has changed PP_XXX definition */ -- cgit v1.2.3 From d96366c7027aa1f335d1391983ff3c140f02c64e Mon Sep 17 00:00:00 2001 From: Jani Nikula Date: Tue, 7 Apr 2026 22:36:28 +0300 Subject: drm/i915/mchbar: move intel_mchbar_regs.h under include/drm/intel MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Since the mchbar registers are used from both i915 display and core, move intel_mchbar_regs.h to include/drm/intel/mchbar_regs.h. Drop the intel_ prefix from the name to reduce tautology. With this, we can drop the corresponding xe display compat header. v2: Rebase Reviewed-by: Ville Syrjälä Link: https://patch.msgid.link/6c951b2c05db74ea517d52a3912986f7eb886422.1775590536.git.jani.nikula@intel.com Signed-off-by: Jani Nikula --- drivers/gpu/drm/i915/display/intel_mchbar.h | 3 +- drivers/gpu/drm/i915/gem/i915_gem_stolen.c | 2 +- drivers/gpu/drm/i915/gt/intel_ggtt_fencing.c | 2 +- drivers/gpu/drm/i915/gt/intel_llc.c | 2 +- drivers/gpu/drm/i915/gt/intel_reset.c | 3 +- drivers/gpu/drm/i915/gt/intel_rps.c | 4 +- drivers/gpu/drm/i915/i915_debugfs.c | 2 +- drivers/gpu/drm/i915/i915_freq.c | 2 +- drivers/gpu/drm/i915/i915_hwmon.c | 2 +- drivers/gpu/drm/i915/intel_clock_gating.c | 4 +- drivers/gpu/drm/i915/intel_gvt_mmio_table.c | 2 +- drivers/gpu/drm/i915/intel_mchbar_regs.h | 273 --------------------- .../drm/xe/compat-i915-headers/intel_mchbar_regs.h | 6 - include/drm/intel/mchbar_regs.h | 273 +++++++++++++++++++++ 14 files changed, 288 insertions(+), 292 deletions(-) delete mode 100644 drivers/gpu/drm/i915/intel_mchbar_regs.h delete mode 100644 drivers/gpu/drm/xe/compat-i915-headers/intel_mchbar_regs.h create mode 100644 include/drm/intel/mchbar_regs.h diff --git a/drivers/gpu/drm/i915/display/intel_mchbar.h b/drivers/gpu/drm/i915/display/intel_mchbar.h index 51ecd6075bdf..fb645c64796c 100644 --- a/drivers/gpu/drm/i915/display/intel_mchbar.h +++ b/drivers/gpu/drm/i915/display/intel_mchbar.h @@ -8,8 +8,9 @@ #include +#include + #include "i915_reg_defs.h" -#include "intel_mchbar_regs.h" struct intel_display; diff --git a/drivers/gpu/drm/i915/gem/i915_gem_stolen.c b/drivers/gpu/drm/i915/gem/i915_gem_stolen.c index 77f85359f279..5838fb33104d 100644 --- a/drivers/gpu/drm/i915/gem/i915_gem_stolen.c +++ b/drivers/gpu/drm/i915/gem/i915_gem_stolen.c @@ -10,6 +10,7 @@ #include #include #include +#include #include "gem/i915_gem_lmem.h" #include "gem/i915_gem_region.h" @@ -23,7 +24,6 @@ #include "i915_reg.h" #include "i915_utils.h" #include "i915_vgpu.h" -#include "intel_mchbar_regs.h" #include "intel_pci_config.h" struct intel_stolen_node { diff --git a/drivers/gpu/drm/i915/gt/intel_ggtt_fencing.c b/drivers/gpu/drm/i915/gt/intel_ggtt_fencing.c index ac9aede82320..6efc1ed3831b 100644 --- a/drivers/gpu/drm/i915/gt/intel_ggtt_fencing.c +++ b/drivers/gpu/drm/i915/gt/intel_ggtt_fencing.c @@ -7,6 +7,7 @@ #include #include +#include #include "display/intel_display.h" #include "i915_drv.h" @@ -15,7 +16,6 @@ #include "i915_pvinfo.h" #include "i915_vgpu.h" #include "intel_gt_regs.h" -#include "intel_mchbar_regs.h" /** * DOC: fence register handling diff --git a/drivers/gpu/drm/i915/gt/intel_llc.c b/drivers/gpu/drm/i915/gt/intel_llc.c index bcd707e3d436..82d9a8e50867 100644 --- a/drivers/gpu/drm/i915/gt/intel_llc.c +++ b/drivers/gpu/drm/i915/gt/intel_llc.c @@ -7,12 +7,12 @@ #include #include +#include #include "i915_drv.h" #include "i915_reg.h" #include "intel_gt.h" #include "intel_llc.h" -#include "intel_mchbar_regs.h" #include "intel_pcode.h" #include "intel_rps.h" diff --git a/drivers/gpu/drm/i915/gt/intel_reset.c b/drivers/gpu/drm/i915/gt/intel_reset.c index 984d0056c01c..4d0ea953eb6e 100644 --- a/drivers/gpu/drm/i915/gt/intel_reset.c +++ b/drivers/gpu/drm/i915/gt/intel_reset.c @@ -7,6 +7,8 @@ #include #include +#include + #include "display/intel_display_reset.h" #include "display/intel_overlay.h" #include "gem/i915_gem_context.h" @@ -27,7 +29,6 @@ #include "intel_gt_pm.h" #include "intel_gt_print.h" #include "intel_gt_requests.h" -#include "intel_mchbar_regs.h" #include "intel_pci_config.h" #include "intel_reset.h" diff --git a/drivers/gpu/drm/i915/gt/intel_rps.c b/drivers/gpu/drm/i915/gt/intel_rps.c index 844f2716a386..a33b19c04737 100644 --- a/drivers/gpu/drm/i915/gt/intel_rps.c +++ b/drivers/gpu/drm/i915/gt/intel_rps.c @@ -5,9 +5,10 @@ #include -#include #include +#include #include +#include #include "display/intel_display_rps.h" #include "display/vlv_clock.h" @@ -25,7 +26,6 @@ #include "intel_gt_pm_irq.h" #include "intel_gt_print.h" #include "intel_gt_regs.h" -#include "intel_mchbar_regs.h" #include "intel_pcode.h" #include "intel_rps.h" #include "vlv_iosf_sb.h" diff --git a/drivers/gpu/drm/i915/i915_debugfs.c b/drivers/gpu/drm/i915/i915_debugfs.c index 4778ba664ec7..a3e27f9e4f47 100644 --- a/drivers/gpu/drm/i915/i915_debugfs.c +++ b/drivers/gpu/drm/i915/i915_debugfs.c @@ -34,6 +34,7 @@ #include #include #include +#include #include "gem/i915_gem_context.h" #include "gt/intel_gt.h" @@ -57,7 +58,6 @@ #include "i915_reg.h" #include "i915_scheduler.h" #include "i915_wait_util.h" -#include "intel_mchbar_regs.h" static inline struct drm_i915_private *node_to_i915(struct drm_info_node *node) { diff --git a/drivers/gpu/drm/i915/i915_freq.c b/drivers/gpu/drm/i915/i915_freq.c index 9bdaea34aef9..9547d087555f 100644 --- a/drivers/gpu/drm/i915/i915_freq.c +++ b/drivers/gpu/drm/i915/i915_freq.c @@ -2,10 +2,10 @@ /* Copyright © 2025 Intel Corporation */ #include +#include #include "i915_drv.h" #include "i915_freq.h" -#include "intel_mchbar_regs.h" unsigned int i9xx_fsb_freq(struct drm_i915_private *i915) { diff --git a/drivers/gpu/drm/i915/i915_hwmon.c b/drivers/gpu/drm/i915/i915_hwmon.c index c4a799f5fe92..da643b38064c 100644 --- a/drivers/gpu/drm/i915/i915_hwmon.c +++ b/drivers/gpu/drm/i915/i915_hwmon.c @@ -10,11 +10,11 @@ #include #include +#include #include "i915_drv.h" #include "i915_hwmon.h" #include "i915_reg.h" -#include "intel_mchbar_regs.h" #include "intel_pcode.h" #include "gt/intel_gt.h" #include "gt/intel_gt_regs.h" diff --git a/drivers/gpu/drm/i915/intel_clock_gating.c b/drivers/gpu/drm/i915/intel_clock_gating.c index ee2489a2fbe7..515f83c82abc 100644 --- a/drivers/gpu/drm/i915/intel_clock_gating.c +++ b/drivers/gpu/drm/i915/intel_clock_gating.c @@ -26,8 +26,9 @@ */ #include -#include #include +#include +#include #include "display/i9xx_plane_regs.h" #include "display/intel_display.h" @@ -42,7 +43,6 @@ #include "i915_drv.h" #include "i915_reg.h" #include "intel_clock_gating.h" -#include "intel_mchbar_regs.h" #include "vlv_iosf_sb.h" struct drm_i915_clock_gating_funcs { diff --git a/drivers/gpu/drm/i915/intel_gvt_mmio_table.c b/drivers/gpu/drm/i915/intel_gvt_mmio_table.c index ae42818ab6e0..de118fae0a49 100644 --- a/drivers/gpu/drm/i915/intel_gvt_mmio_table.c +++ b/drivers/gpu/drm/i915/intel_gvt_mmio_table.c @@ -7,6 +7,7 @@ #include #include +#include #include "display/bxt_dpio_phy_regs.h" #include "display/i9xx_plane_regs.h" @@ -44,7 +45,6 @@ #include "i915_pvinfo.h" #include "i915_reg.h" #include "intel_gvt.h" -#include "intel_mchbar_regs.h" #define MMIO_F(reg, s) do { \ int ret; \ diff --git a/drivers/gpu/drm/i915/intel_mchbar_regs.h b/drivers/gpu/drm/i915/intel_mchbar_regs.h deleted file mode 100644 index ca0d421be16c..000000000000 --- a/drivers/gpu/drm/i915/intel_mchbar_regs.h +++ /dev/null @@ -1,273 +0,0 @@ -/* SPDX-License-Identifier: MIT */ -/* - * Copyright © 2022 Intel Corporation - */ - -#ifndef __INTEL_MCHBAR_REGS__ -#define __INTEL_MCHBAR_REGS__ - -#include "i915_reg_defs.h" - -/* - * MCHBAR mirror. - * - * This mirrors the MCHBAR MMIO space whose location is determined by - * device 0 function 0's pci config register 0x44 or 0x48 and matches it in - * every way. It is not accessible from the CP register read instructions. - * - * Starting from Haswell, you can't write registers using the MCHBAR mirror, - * just read. On MTL+ the mirror no longer exists. - */ - -#define MCHBAR_MIRROR_BASE 0x10000 -#define MCHBAR_MIRROR_END 0x13fff - -#define MCHBAR_MIRROR_BASE_SNB 0x140000 -#define MCHBAR_MIRROR_END_SNB 0x147fff -#define MCHBAR_MIRROR_END_ICL_RKL 0x14ffff -#define MCHBAR_MIRROR_END_TGL 0x15ffff - -#define CTG_STOLEN_RESERVED _MMIO(MCHBAR_MIRROR_BASE + 0x34) -#define ELK_STOLEN_RESERVED _MMIO(MCHBAR_MIRROR_BASE + 0x48) -#define G4X_STOLEN_RESERVED_ADDR1_MASK (0xFFFF << 16) -#define G4X_STOLEN_RESERVED_ADDR2_MASK (0xFFF << 4) -#define G4X_STOLEN_RESERVED_ENABLE (1 << 0) - -/* Pineview MCH register contains DDR3 setting */ -#define CSHRDDR3CTL _MMIO(MCHBAR_MIRROR_BASE + 0x1a8) -#define CSHRDDR3CTL_DDR3 (1 << 2) - -/* 915-945 and GM965 MCH register controlling DRAM channel access */ -#define DCC _MMIO(MCHBAR_MIRROR_BASE + 0x200) -#define DCC_ADDRESSING_MODE_SINGLE_CHANNEL (0 << 0) -#define DCC_ADDRESSING_MODE_DUAL_CHANNEL_ASYMMETRIC (1 << 0) -#define DCC_ADDRESSING_MODE_DUAL_CHANNEL_INTERLEAVED (2 << 0) -#define DCC_ADDRESSING_MODE_MASK (3 << 0) -#define DCC_CHANNEL_XOR_DISABLE (1 << 10) -#define DCC_CHANNEL_XOR_BIT_17 (1 << 9) -#define DCC2 _MMIO(MCHBAR_MIRROR_BASE + 0x204) -#define DCC2_MODIFIED_ENHANCED_DISABLE (1 << 20) - -/* 965 MCH register controlling DRAM channel configuration */ -#define C0DRB3_BW _MMIO(MCHBAR_MIRROR_BASE + 0x206) -#define C1DRB3_BW _MMIO(MCHBAR_MIRROR_BASE + 0x606) - -/* Clocking configuration register */ -#define CLKCFG _MMIO(MCHBAR_MIRROR_BASE + 0xc00) -#define CLKCFG_FSB_400 (0 << 0) /* hrawclk 100 */ -#define CLKCFG_FSB_400_ALT (5 << 0) /* hrawclk 100 */ -#define CLKCFG_FSB_533 (1 << 0) /* hrawclk 133 */ -#define CLKCFG_FSB_667 (3 << 0) /* hrawclk 166 */ -#define CLKCFG_FSB_800 (2 << 0) /* hrawclk 200 */ -#define CLKCFG_FSB_1067 (6 << 0) /* hrawclk 266 */ -#define CLKCFG_FSB_1067_ALT (0 << 0) /* hrawclk 266 */ -#define CLKCFG_FSB_1333 (7 << 0) /* hrawclk 333 */ -#define CLKCFG_FSB_1333_ALT (4 << 0) /* hrawclk 333 */ -#define CLKCFG_FSB_1600_ALT (6 << 0) /* hrawclk 400 */ -#define CLKCFG_FSB_MASK (7 << 0) -#define CLKCFG_MEM_533 (1 << 4) -#define CLKCFG_MEM_667 (2 << 4) -#define CLKCFG_MEM_800 (3 << 4) -#define CLKCFG_MEM_MASK (7 << 4) - -#define HPLLVCO_MOBILE _MMIO(MCHBAR_MIRROR_BASE + 0xc0f) -#define HPLLVCO _MMIO(MCHBAR_MIRROR_BASE + 0xc38) - -#define TSC1 _MMIO(MCHBAR_MIRROR_BASE + 0x1001) -#define TSE (1 << 0) -#define TR1 _MMIO(MCHBAR_MIRROR_BASE + 0x1006) -#define TSFS _MMIO(MCHBAR_MIRROR_BASE + 0x1020) -#define TSFS_SLOPE_MASK 0x0000ff00 -#define TSFS_SLOPE_SHIFT 8 -#define TSFS_INTR_MASK 0x000000ff - -/* Memory latency timer register */ -#define MLTR_ILK _MMIO(MCHBAR_MIRROR_BASE + 0x1222) -/* the unit of memory self-refresh latency time is 0.5us */ -#define MLTR_WM2_MASK REG_GENMASK(13, 8) -#define MLTR_WM1_MASK REG_GENMASK(5, 0) - -#define CSIPLL0 _MMIO(MCHBAR_MIRROR_BASE + 0x2c10) -#define DDRMPLL1 _MMIO(MCHBAR_MIRROR_BASE + 0x2c20) - -#define ILK_GDSR _MMIO(MCHBAR_MIRROR_BASE + 0x2ca4) -#define ILK_GRDOM_FULL (0 << 1) -#define ILK_GRDOM_RENDER (1 << 1) -#define ILK_GRDOM_MEDIA (3 << 1) -#define ILK_GRDOM_MASK (3 << 1) -#define ILK_GRDOM_RESET_ENABLE (1 << 0) - -#define BXT_D_CR_DRP0_DUNIT8 0x1000 -#define BXT_D_CR_DRP0_DUNIT9 0x1200 -#define BXT_D_CR_DRP0_DUNIT_START 8 -#define BXT_D_CR_DRP0_DUNIT_END 11 -#define BXT_D_CR_DRP0_DUNIT(x) _MMIO(MCHBAR_MIRROR_BASE_SNB + \ - _PICK_EVEN((x) - 8, BXT_D_CR_DRP0_DUNIT8,\ - BXT_D_CR_DRP0_DUNIT9)) -#define BXT_DRAM_RANK_MASK 0x3 -#define BXT_DRAM_RANK_SINGLE 0x1 -#define BXT_DRAM_RANK_DUAL 0x3 -#define BXT_DRAM_WIDTH_MASK (0x3 << 4) -#define BXT_DRAM_WIDTH_SHIFT 4 -#define BXT_DRAM_WIDTH_X8 (0x0 << 4) -#define BXT_DRAM_WIDTH_X16 (0x1 << 4) -#define BXT_DRAM_WIDTH_X32 (0x2 << 4) -#define BXT_DRAM_WIDTH_X64 (0x3 << 4) -#define BXT_DRAM_SIZE_MASK (0x7 << 6) -#define BXT_DRAM_SIZE_SHIFT 6 -#define BXT_DRAM_SIZE_4GBIT (0x0 << 6) -#define BXT_DRAM_SIZE_6GBIT (0x1 << 6) -#define BXT_DRAM_SIZE_8GBIT (0x2 << 6) -#define BXT_DRAM_SIZE_12GBIT (0x3 << 6) -#define BXT_DRAM_SIZE_16GBIT (0x4 << 6) -#define BXT_DRAM_TYPE_MASK (0x7 << 22) -#define BXT_DRAM_TYPE_SHIFT 22 -#define BXT_DRAM_TYPE_DDR3 (0x0 << 22) -#define BXT_DRAM_TYPE_LPDDR3 (0x1 << 22) -#define BXT_DRAM_TYPE_LPDDR4 (0x2 << 22) -#define BXT_DRAM_TYPE_DDR4 (0x4 << 22) - -#define MCHBAR_CH0_CR_TC_PRE_0_0_0_MCHBAR _MMIO(MCHBAR_MIRROR_BASE_SNB + 0x4000) -#define DG1_DRAM_T_RDPRE_MASK REG_GENMASK(16, 11) -#define DG1_DRAM_T_RP_MASK REG_GENMASK(6, 0) -#define MCHBAR_CH0_CR_TC_PRE_0_0_0_MCHBAR_HIGH _MMIO(MCHBAR_MIRROR_BASE_SNB + 0x4004) -#define DG1_DRAM_T_RCD_MASK REG_GENMASK(15, 9) -#define DG1_DRAM_T_RAS_MASK REG_GENMASK(8, 1) - -#define SKL_MAD_INTER_CHANNEL_0_0_0_MCHBAR_MCMAIN _MMIO(MCHBAR_MIRROR_BASE_SNB + 0x5000) -#define SKL_DRAM_DDR_TYPE_MASK REG_GENMASK(1, 0) -#define SKL_DRAM_DDR_TYPE_DDR4 REG_FIELD_PREP(SKL_DRAM_DDR_TYPE_MASK, 0) -#define SKL_DRAM_DDR_TYPE_DDR3 REG_FIELD_PREP(SKL_DRAM_DDR_TYPE_MASK, 1) -#define SKL_DRAM_DDR_TYPE_LPDDR3 REG_FIELD_PREP(SKL_DRAM_DDR_TYPE_MASK, 2) -#define SKL_DRAM_DDR_TYPE_LPDDR4 REG_FIELD_PREP(SKL_DRAM_DDR_TYPE_MASK, 3) - -/* snb MCH registers for reading the DRAM channel configuration */ -#define MAD_DIMM_C0 _MMIO(MCHBAR_MIRROR_BASE_SNB + 0x5004) -#define MAD_DIMM_C1 _MMIO(MCHBAR_MIRROR_BASE_SNB + 0x5008) -#define MAD_DIMM_C2 _MMIO(MCHBAR_MIRROR_BASE_SNB + 0x500C) -#define MAD_DIMM_ECC_MASK (0x3 << 24) -#define MAD_DIMM_ECC_OFF (0x0 << 24) -#define MAD_DIMM_ECC_IO_ON_LOGIC_OFF (0x1 << 24) -#define MAD_DIMM_ECC_IO_OFF_LOGIC_ON (0x2 << 24) -#define MAD_DIMM_ECC_ON (0x3 << 24) -#define MAD_DIMM_ENH_INTERLEAVE (0x1 << 22) -#define MAD_DIMM_RANK_INTERLEAVE (0x1 << 21) -#define MAD_DIMM_B_WIDTH_X16 (0x1 << 20) /* X8 chips if unset */ -#define MAD_DIMM_A_WIDTH_X16 (0x1 << 19) /* X8 chips if unset */ -#define MAD_DIMM_B_DUAL_RANK (0x1 << 18) -#define MAD_DIMM_A_DUAL_RANK (0x1 << 17) -#define MAD_DIMM_A_SELECT (0x1 << 16) -/* DIMM sizes are in multiples of 256mb. */ -#define MAD_DIMM_B_SIZE_SHIFT 8 -#define MAD_DIMM_B_SIZE_MASK (0xff << MAD_DIMM_B_SIZE_SHIFT) -#define MAD_DIMM_A_SIZE_SHIFT 0 -#define MAD_DIMM_A_SIZE_MASK (0xff << MAD_DIMM_A_SIZE_SHIFT) - -#define SKL_MAD_DIMM_CH0_0_0_0_MCHBAR_MCMAIN _MMIO(MCHBAR_MIRROR_BASE_SNB + 0x500C) -#define SKL_MAD_DIMM_CH1_0_0_0_MCHBAR_MCMAIN _MMIO(MCHBAR_MIRROR_BASE_SNB + 0x5010) -#define SKL_DIMM_S_RANK_MASK REG_GENMASK(26, 26) -#define SKL_DIMM_S_RANK_1 REG_FIELD_PREP(SKL_DIMM_S_RANK_MASK, 0) -#define SKL_DIMM_S_RANK_2 REG_FIELD_PREP(SKL_DIMM_S_RANK_MASK, 1) -#define SKL_DIMM_S_WIDTH_MASK REG_GENMASK(25, 24) -#define SKL_DIMM_S_WIDTH_X8 REG_FIELD_PREP(SKL_DIMM_S_WIDTH_MASK, 0) -#define SKL_DIMM_S_WIDTH_X16 REG_FIELD_PREP(SKL_DIMM_S_WIDTH_MASK, 1) -#define SKL_DIMM_S_WIDTH_X32 REG_FIELD_PREP(SKL_DIMM_S_WIDTH_MASK, 2) -#define SKL_DIMM_S_SIZE_MASK REG_GENMASK(21, 16) -#define SKL_DIMM_L_RANK_MASK REG_GENMASK(10, 10) -#define SKL_DIMM_L_RANK_1 REG_FIELD_PREP(SKL_DIMM_L_RANK_MASK, 0) -#define SKL_DIMM_L_RANK_2 REG_FIELD_PREP(SKL_DIMM_L_RANK_MASK, 1) -#define SKL_DIMM_L_WIDTH_MASK REG_GENMASK(9, 8) -#define SKL_DIMM_L_WIDTH_X8 REG_FIELD_PREP(SKL_DIMM_L_WIDTH_MASK, 0) -#define SKL_DIMM_L_WIDTH_X16 REG_FIELD_PREP(SKL_DIMM_L_WIDTH_MASK, 1) -#define SKL_DIMM_L_WIDTH_X32 REG_FIELD_PREP(SKL_DIMM_L_WIDTH_MASK, 2) -#define SKL_DIMM_L_SIZE_MASK REG_GENMASK(5, 0) -#define ICL_DIMM_S_RANK_MASK REG_GENMASK(27, 26) -#define ICL_DIMM_S_RANK_1 REG_FIELD_PREP(ICL_DIMM_S_RANK_MASK, 0) -#define ICL_DIMM_S_RANK_2 REG_FIELD_PREP(ICL_DIMM_S_RANK_MASK, 1) -#define ICL_DIMM_S_WIDTH_MASK REG_GENMASK(25, 24) -#define ICL_DIMM_S_WIDTH_X8 REG_FIELD_PREP(ICL_DIMM_S_WIDTH_MASK, 0) -#define ICL_DIMM_S_WIDTH_X16 REG_FIELD_PREP(ICL_DIMM_S_WIDTH_MASK, 1) -#define ICL_DIMM_S_WIDTH_X32 REG_FIELD_PREP(ICL_DIMM_S_WIDTH_MASK, 2) -#define ICL_DIMM_S_SIZE_MASK REG_GENMASK(22, 16) -#define ICL_DIMM_L_RANK_MASK REG_GENMASK(10, 9) -#define ICL_DIMM_L_RANK_1 REG_FIELD_PREP(ICL_DIMM_L_RANK_MASK, 0) -#define ICL_DIMM_L_RANK_2 REG_FIELD_PREP(ICL_DIMM_L_RANK_MASK, 1) -#define ICL_DIMM_L_RANK_3 REG_FIELD_PREP(ICL_DIMM_L_RANK_MASK, 2) -#define ICL_DIMM_L_RANK_4 REG_FIELD_PREP(ICL_DIMM_L_RANK_MASK, 3) -#define ICL_DIMM_L_WIDTH_MASK REG_GENMASK(8, 7) -#define ICL_DIMM_L_WIDTH_X8 REG_FIELD_PREP(ICL_DIMM_L_WIDTH_MASK, 0) -#define ICL_DIMM_L_WIDTH_X16 REG_FIELD_PREP(ICL_DIMM_L_WIDTH_MASK, 1) -#define ICL_DIMM_L_WIDTH_X32 REG_FIELD_PREP(ICL_DIMM_L_WIDTH_MASK, 2) -#define ICL_DIMM_L_SIZE_MASK REG_GENMASK(6, 0) - -#define SA_PERF_STATUS_0_0_0_MCHBAR_PC _MMIO(MCHBAR_MIRROR_BASE_SNB + 0x5918) -#define DG1_QCLK_RATIO_MASK REG_GENMASK(9, 2) -#define DG1_QCLK_REFERENCE REG_BIT(10) - -/* - * *_PACKAGE_POWER_SKU - SKU power and timing parameters. - */ -#define PCU_PACKAGE_POWER_SKU _MMIO(MCHBAR_MIRROR_BASE_SNB + 0x5930) -#define PKG_PKG_TDP GENMASK_ULL(14, 0) -#define PKG_MIN_PWR GENMASK_ULL(30, 16) -#define PKG_MAX_PWR GENMASK_ULL(46, 32) -#define PKG_MAX_WIN GENMASK_ULL(54, 48) -#define PKG_MAX_WIN_X GENMASK_ULL(54, 53) -#define PKG_MAX_WIN_Y GENMASK_ULL(52, 48) - -#define PCU_PACKAGE_POWER_SKU_UNIT _MMIO(MCHBAR_MIRROR_BASE_SNB + 0x5938) -#define PKG_PWR_UNIT REG_GENMASK(3, 0) -#define PKG_ENERGY_UNIT REG_GENMASK(12, 8) -#define PKG_TIME_UNIT REG_GENMASK(19, 16) -#define PCU_PACKAGE_ENERGY_STATUS _MMIO(MCHBAR_MIRROR_BASE_SNB + 0x593c) - -#define GEN6_GT_PERF_STATUS _MMIO(MCHBAR_MIRROR_BASE_SNB + 0x5948) - -#define PCU_PACKAGE_TEMPERATURE _MMIO(MCHBAR_MIRROR_BASE_SNB + 0x5978) -#define TEMP_MASK REG_GENMASK(7, 0) - -#define GEN6_RP_STATE_LIMITS _MMIO(MCHBAR_MIRROR_BASE_SNB + 0x5994) -#define GEN6_RP_STATE_CAP _MMIO(MCHBAR_MIRROR_BASE_SNB + 0x5998) -#define RP0_CAP_MASK REG_GENMASK(7, 0) -#define RP1_CAP_MASK REG_GENMASK(15, 8) -#define RPN_CAP_MASK REG_GENMASK(23, 16) - -#define GEN10_FREQ_INFO_REC _MMIO(MCHBAR_MIRROR_BASE_SNB + 0x5ef0) -#define RPE_MASK REG_GENMASK(15, 8) -#define PCU_PACKAGE_RAPL_LIMIT _MMIO(MCHBAR_MIRROR_BASE_SNB + 0x59a0) -#define PKG_PWR_LIM_1 REG_GENMASK(14, 0) -#define PKG_PWR_LIM_1_EN REG_BIT(15) -#define PKG_PWR_LIM_1_TIME REG_GENMASK(23, 17) -#define PKG_PWR_LIM_1_TIME_X REG_GENMASK(23, 22) -#define PKG_PWR_LIM_1_TIME_Y REG_GENMASK(21, 17) - -/* snb MCH registers for priority tuning */ -#define MCH_SSKPD _MMIO(MCHBAR_MIRROR_BASE_SNB + 0x5d10) -#define SSKPD_NEW_WM0_MASK_HSW REG_GENMASK64(63, 56) -#define SSKPD_WM4_MASK_HSW REG_GENMASK64(40, 32) -#define SSKPD_WM3_MASK_HSW REG_GENMASK64(28, 20) -#define SSKPD_WM2_MASK_HSW REG_GENMASK64(19, 12) -#define SSKPD_WM1_MASK_HSW REG_GENMASK64(11, 4) -#define SSKPD_OLD_WM0_MASK_HSW REG_GENMASK64(3, 0) -#define SSKPD_WM3_MASK_SNB REG_GENMASK(29, 24) -#define SSKPD_WM2_MASK_SNB REG_GENMASK(21, 16) -#define SSKPD_WM1_MASK_SNB REG_GENMASK(13, 8) -#define SSKPD_WM0_MASK_SNB REG_GENMASK(5, 0) - -/* Memory controller frequency in MCHBAR for Haswell (possible SNB+) */ -#define DCLK _MMIO(MCHBAR_MIRROR_BASE_SNB + 0x5e04) -#define SKL_MC_BIOS_DATA_0_0_0_MCHBAR_PCU _MMIO(MCHBAR_MIRROR_BASE_SNB + 0x5e04) -#define DG1_GEAR_TYPE REG_BIT(16) - -/* - * Please see hsw_read_dcomp() and hsw_write_dcomp() before using this register, - * since on HSW we can't write to it using intel_uncore_write. - */ -#define D_COMP_HSW _MMIO(MCHBAR_MIRROR_BASE_SNB + 0x5f0c) -#define D_COMP_RCOMP_IN_PROGRESS (1 << 9) -#define D_COMP_COMP_FORCE (1 << 8) -#define D_COMP_COMP_DISABLE (1 << 0) - -#define BXT_GT_PERF_STATUS _MMIO(MCHBAR_MIRROR_BASE_SNB + 0x7070) - -#endif /* __INTEL_MCHBAR_REGS */ diff --git a/drivers/gpu/drm/xe/compat-i915-headers/intel_mchbar_regs.h b/drivers/gpu/drm/xe/compat-i915-headers/intel_mchbar_regs.h deleted file mode 100644 index 55b316985340..000000000000 --- a/drivers/gpu/drm/xe/compat-i915-headers/intel_mchbar_regs.h +++ /dev/null @@ -1,6 +0,0 @@ -/* SPDX-License-Identifier: MIT */ -/* - * Copyright © 2023 Intel Corporation - */ - -#include "../../i915/intel_mchbar_regs.h" diff --git a/include/drm/intel/mchbar_regs.h b/include/drm/intel/mchbar_regs.h new file mode 100644 index 000000000000..ca0d421be16c --- /dev/null +++ b/include/drm/intel/mchbar_regs.h @@ -0,0 +1,273 @@ +/* SPDX-License-Identifier: MIT */ +/* + * Copyright © 2022 Intel Corporation + */ + +#ifndef __INTEL_MCHBAR_REGS__ +#define __INTEL_MCHBAR_REGS__ + +#include "i915_reg_defs.h" + +/* + * MCHBAR mirror. + * + * This mirrors the MCHBAR MMIO space whose location is determined by + * device 0 function 0's pci config register 0x44 or 0x48 and matches it in + * every way. It is not accessible from the CP register read instructions. + * + * Starting from Haswell, you can't write registers using the MCHBAR mirror, + * just read. On MTL+ the mirror no longer exists. + */ + +#define MCHBAR_MIRROR_BASE 0x10000 +#define MCHBAR_MIRROR_END 0x13fff + +#define MCHBAR_MIRROR_BASE_SNB 0x140000 +#define MCHBAR_MIRROR_END_SNB 0x147fff +#define MCHBAR_MIRROR_END_ICL_RKL 0x14ffff +#define MCHBAR_MIRROR_END_TGL 0x15ffff + +#define CTG_STOLEN_RESERVED _MMIO(MCHBAR_MIRROR_BASE + 0x34) +#define ELK_STOLEN_RESERVED _MMIO(MCHBAR_MIRROR_BASE + 0x48) +#define G4X_STOLEN_RESERVED_ADDR1_MASK (0xFFFF << 16) +#define G4X_STOLEN_RESERVED_ADDR2_MASK (0xFFF << 4) +#define G4X_STOLEN_RESERVED_ENABLE (1 << 0) + +/* Pineview MCH register contains DDR3 setting */ +#define CSHRDDR3CTL _MMIO(MCHBAR_MIRROR_BASE + 0x1a8) +#define CSHRDDR3CTL_DDR3 (1 << 2) + +/* 915-945 and GM965 MCH register controlling DRAM channel access */ +#define DCC _MMIO(MCHBAR_MIRROR_BASE + 0x200) +#define DCC_ADDRESSING_MODE_SINGLE_CHANNEL (0 << 0) +#define DCC_ADDRESSING_MODE_DUAL_CHANNEL_ASYMMETRIC (1 << 0) +#define DCC_ADDRESSING_MODE_DUAL_CHANNEL_INTERLEAVED (2 << 0) +#define DCC_ADDRESSING_MODE_MASK (3 << 0) +#define DCC_CHANNEL_XOR_DISABLE (1 << 10) +#define DCC_CHANNEL_XOR_BIT_17 (1 << 9) +#define DCC2 _MMIO(MCHBAR_MIRROR_BASE + 0x204) +#define DCC2_MODIFIED_ENHANCED_DISABLE (1 << 20) + +/* 965 MCH register controlling DRAM channel configuration */ +#define C0DRB3_BW _MMIO(MCHBAR_MIRROR_BASE + 0x206) +#define C1DRB3_BW _MMIO(MCHBAR_MIRROR_BASE + 0x606) + +/* Clocking configuration register */ +#define CLKCFG _MMIO(MCHBAR_MIRROR_BASE + 0xc00) +#define CLKCFG_FSB_400 (0 << 0) /* hrawclk 100 */ +#define CLKCFG_FSB_400_ALT (5 << 0) /* hrawclk 100 */ +#define CLKCFG_FSB_533 (1 << 0) /* hrawclk 133 */ +#define CLKCFG_FSB_667 (3 << 0) /* hrawclk 166 */ +#define CLKCFG_FSB_800 (2 << 0) /* hrawclk 200 */ +#define CLKCFG_FSB_1067 (6 << 0) /* hrawclk 266 */ +#define CLKCFG_FSB_1067_ALT (0 << 0) /* hrawclk 266 */ +#define CLKCFG_FSB_1333 (7 << 0) /* hrawclk 333 */ +#define CLKCFG_FSB_1333_ALT (4 << 0) /* hrawclk 333 */ +#define CLKCFG_FSB_1600_ALT (6 << 0) /* hrawclk 400 */ +#define CLKCFG_FSB_MASK (7 << 0) +#define CLKCFG_MEM_533 (1 << 4) +#define CLKCFG_MEM_667 (2 << 4) +#define CLKCFG_MEM_800 (3 << 4) +#define CLKCFG_MEM_MASK (7 << 4) + +#define HPLLVCO_MOBILE _MMIO(MCHBAR_MIRROR_BASE + 0xc0f) +#define HPLLVCO _MMIO(MCHBAR_MIRROR_BASE + 0xc38) + +#define TSC1 _MMIO(MCHBAR_MIRROR_BASE + 0x1001) +#define TSE (1 << 0) +#define TR1 _MMIO(MCHBAR_MIRROR_BASE + 0x1006) +#define TSFS _MMIO(MCHBAR_MIRROR_BASE + 0x1020) +#define TSFS_SLOPE_MASK 0x0000ff00 +#define TSFS_SLOPE_SHIFT 8 +#define TSFS_INTR_MASK 0x000000ff + +/* Memory latency timer register */ +#define MLTR_ILK _MMIO(MCHBAR_MIRROR_BASE + 0x1222) +/* the unit of memory self-refresh latency time is 0.5us */ +#define MLTR_WM2_MASK REG_GENMASK(13, 8) +#define MLTR_WM1_MASK REG_GENMASK(5, 0) + +#define CSIPLL0 _MMIO(MCHBAR_MIRROR_BASE + 0x2c10) +#define DDRMPLL1 _MMIO(MCHBAR_MIRROR_BASE + 0x2c20) + +#define ILK_GDSR _MMIO(MCHBAR_MIRROR_BASE + 0x2ca4) +#define ILK_GRDOM_FULL (0 << 1) +#define ILK_GRDOM_RENDER (1 << 1) +#define ILK_GRDOM_MEDIA (3 << 1) +#define ILK_GRDOM_MASK (3 << 1) +#define ILK_GRDOM_RESET_ENABLE (1 << 0) + +#define BXT_D_CR_DRP0_DUNIT8 0x1000 +#define BXT_D_CR_DRP0_DUNIT9 0x1200 +#define BXT_D_CR_DRP0_DUNIT_START 8 +#define BXT_D_CR_DRP0_DUNIT_END 11 +#define BXT_D_CR_DRP0_DUNIT(x) _MMIO(MCHBAR_MIRROR_BASE_SNB + \ + _PICK_EVEN((x) - 8, BXT_D_CR_DRP0_DUNIT8,\ + BXT_D_CR_DRP0_DUNIT9)) +#define BXT_DRAM_RANK_MASK 0x3 +#define BXT_DRAM_RANK_SINGLE 0x1 +#define BXT_DRAM_RANK_DUAL 0x3 +#define BXT_DRAM_WIDTH_MASK (0x3 << 4) +#define BXT_DRAM_WIDTH_SHIFT 4 +#define BXT_DRAM_WIDTH_X8 (0x0 << 4) +#define BXT_DRAM_WIDTH_X16 (0x1 << 4) +#define BXT_DRAM_WIDTH_X32 (0x2 << 4) +#define BXT_DRAM_WIDTH_X64 (0x3 << 4) +#define BXT_DRAM_SIZE_MASK (0x7 << 6) +#define BXT_DRAM_SIZE_SHIFT 6 +#define BXT_DRAM_SIZE_4GBIT (0x0 << 6) +#define BXT_DRAM_SIZE_6GBIT (0x1 << 6) +#define BXT_DRAM_SIZE_8GBIT (0x2 << 6) +#define BXT_DRAM_SIZE_12GBIT (0x3 << 6) +#define BXT_DRAM_SIZE_16GBIT (0x4 << 6) +#define BXT_DRAM_TYPE_MASK (0x7 << 22) +#define BXT_DRAM_TYPE_SHIFT 22 +#define BXT_DRAM_TYPE_DDR3 (0x0 << 22) +#define BXT_DRAM_TYPE_LPDDR3 (0x1 << 22) +#define BXT_DRAM_TYPE_LPDDR4 (0x2 << 22) +#define BXT_DRAM_TYPE_DDR4 (0x4 << 22) + +#define MCHBAR_CH0_CR_TC_PRE_0_0_0_MCHBAR _MMIO(MCHBAR_MIRROR_BASE_SNB + 0x4000) +#define DG1_DRAM_T_RDPRE_MASK REG_GENMASK(16, 11) +#define DG1_DRAM_T_RP_MASK REG_GENMASK(6, 0) +#define MCHBAR_CH0_CR_TC_PRE_0_0_0_MCHBAR_HIGH _MMIO(MCHBAR_MIRROR_BASE_SNB + 0x4004) +#define DG1_DRAM_T_RCD_MASK REG_GENMASK(15, 9) +#define DG1_DRAM_T_RAS_MASK REG_GENMASK(8, 1) + +#define SKL_MAD_INTER_CHANNEL_0_0_0_MCHBAR_MCMAIN _MMIO(MCHBAR_MIRROR_BASE_SNB + 0x5000) +#define SKL_DRAM_DDR_TYPE_MASK REG_GENMASK(1, 0) +#define SKL_DRAM_DDR_TYPE_DDR4 REG_FIELD_PREP(SKL_DRAM_DDR_TYPE_MASK, 0) +#define SKL_DRAM_DDR_TYPE_DDR3 REG_FIELD_PREP(SKL_DRAM_DDR_TYPE_MASK, 1) +#define SKL_DRAM_DDR_TYPE_LPDDR3 REG_FIELD_PREP(SKL_DRAM_DDR_TYPE_MASK, 2) +#define SKL_DRAM_DDR_TYPE_LPDDR4 REG_FIELD_PREP(SKL_DRAM_DDR_TYPE_MASK, 3) + +/* snb MCH registers for reading the DRAM channel configuration */ +#define MAD_DIMM_C0 _MMIO(MCHBAR_MIRROR_BASE_SNB + 0x5004) +#define MAD_DIMM_C1 _MMIO(MCHBAR_MIRROR_BASE_SNB + 0x5008) +#define MAD_DIMM_C2 _MMIO(MCHBAR_MIRROR_BASE_SNB + 0x500C) +#define MAD_DIMM_ECC_MASK (0x3 << 24) +#define MAD_DIMM_ECC_OFF (0x0 << 24) +#define MAD_DIMM_ECC_IO_ON_LOGIC_OFF (0x1 << 24) +#define MAD_DIMM_ECC_IO_OFF_LOGIC_ON (0x2 << 24) +#define MAD_DIMM_ECC_ON (0x3 << 24) +#define MAD_DIMM_ENH_INTERLEAVE (0x1 << 22) +#define MAD_DIMM_RANK_INTERLEAVE (0x1 << 21) +#define MAD_DIMM_B_WIDTH_X16 (0x1 << 20) /* X8 chips if unset */ +#define MAD_DIMM_A_WIDTH_X16 (0x1 << 19) /* X8 chips if unset */ +#define MAD_DIMM_B_DUAL_RANK (0x1 << 18) +#define MAD_DIMM_A_DUAL_RANK (0x1 << 17) +#define MAD_DIMM_A_SELECT (0x1 << 16) +/* DIMM sizes are in multiples of 256mb. */ +#define MAD_DIMM_B_SIZE_SHIFT 8 +#define MAD_DIMM_B_SIZE_MASK (0xff << MAD_DIMM_B_SIZE_SHIFT) +#define MAD_DIMM_A_SIZE_SHIFT 0 +#define MAD_DIMM_A_SIZE_MASK (0xff << MAD_DIMM_A_SIZE_SHIFT) + +#define SKL_MAD_DIMM_CH0_0_0_0_MCHBAR_MCMAIN _MMIO(MCHBAR_MIRROR_BASE_SNB + 0x500C) +#define SKL_MAD_DIMM_CH1_0_0_0_MCHBAR_MCMAIN _MMIO(MCHBAR_MIRROR_BASE_SNB + 0x5010) +#define SKL_DIMM_S_RANK_MASK REG_GENMASK(26, 26) +#define SKL_DIMM_S_RANK_1 REG_FIELD_PREP(SKL_DIMM_S_RANK_MASK, 0) +#define SKL_DIMM_S_RANK_2 REG_FIELD_PREP(SKL_DIMM_S_RANK_MASK, 1) +#define SKL_DIMM_S_WIDTH_MASK REG_GENMASK(25, 24) +#define SKL_DIMM_S_WIDTH_X8 REG_FIELD_PREP(SKL_DIMM_S_WIDTH_MASK, 0) +#define SKL_DIMM_S_WIDTH_X16 REG_FIELD_PREP(SKL_DIMM_S_WIDTH_MASK, 1) +#define SKL_DIMM_S_WIDTH_X32 REG_FIELD_PREP(SKL_DIMM_S_WIDTH_MASK, 2) +#define SKL_DIMM_S_SIZE_MASK REG_GENMASK(21, 16) +#define SKL_DIMM_L_RANK_MASK REG_GENMASK(10, 10) +#define SKL_DIMM_L_RANK_1 REG_FIELD_PREP(SKL_DIMM_L_RANK_MASK, 0) +#define SKL_DIMM_L_RANK_2 REG_FIELD_PREP(SKL_DIMM_L_RANK_MASK, 1) +#define SKL_DIMM_L_WIDTH_MASK REG_GENMASK(9, 8) +#define SKL_DIMM_L_WIDTH_X8 REG_FIELD_PREP(SKL_DIMM_L_WIDTH_MASK, 0) +#define SKL_DIMM_L_WIDTH_X16 REG_FIELD_PREP(SKL_DIMM_L_WIDTH_MASK, 1) +#define SKL_DIMM_L_WIDTH_X32 REG_FIELD_PREP(SKL_DIMM_L_WIDTH_MASK, 2) +#define SKL_DIMM_L_SIZE_MASK REG_GENMASK(5, 0) +#define ICL_DIMM_S_RANK_MASK REG_GENMASK(27, 26) +#define ICL_DIMM_S_RANK_1 REG_FIELD_PREP(ICL_DIMM_S_RANK_MASK, 0) +#define ICL_DIMM_S_RANK_2 REG_FIELD_PREP(ICL_DIMM_S_RANK_MASK, 1) +#define ICL_DIMM_S_WIDTH_MASK REG_GENMASK(25, 24) +#define ICL_DIMM_S_WIDTH_X8 REG_FIELD_PREP(ICL_DIMM_S_WIDTH_MASK, 0) +#define ICL_DIMM_S_WIDTH_X16 REG_FIELD_PREP(ICL_DIMM_S_WIDTH_MASK, 1) +#define ICL_DIMM_S_WIDTH_X32 REG_FIELD_PREP(ICL_DIMM_S_WIDTH_MASK, 2) +#define ICL_DIMM_S_SIZE_MASK REG_GENMASK(22, 16) +#define ICL_DIMM_L_RANK_MASK REG_GENMASK(10, 9) +#define ICL_DIMM_L_RANK_1 REG_FIELD_PREP(ICL_DIMM_L_RANK_MASK, 0) +#define ICL_DIMM_L_RANK_2 REG_FIELD_PREP(ICL_DIMM_L_RANK_MASK, 1) +#define ICL_DIMM_L_RANK_3 REG_FIELD_PREP(ICL_DIMM_L_RANK_MASK, 2) +#define ICL_DIMM_L_RANK_4 REG_FIELD_PREP(ICL_DIMM_L_RANK_MASK, 3) +#define ICL_DIMM_L_WIDTH_MASK REG_GENMASK(8, 7) +#define ICL_DIMM_L_WIDTH_X8 REG_FIELD_PREP(ICL_DIMM_L_WIDTH_MASK, 0) +#define ICL_DIMM_L_WIDTH_X16 REG_FIELD_PREP(ICL_DIMM_L_WIDTH_MASK, 1) +#define ICL_DIMM_L_WIDTH_X32 REG_FIELD_PREP(ICL_DIMM_L_WIDTH_MASK, 2) +#define ICL_DIMM_L_SIZE_MASK REG_GENMASK(6, 0) + +#define SA_PERF_STATUS_0_0_0_MCHBAR_PC _MMIO(MCHBAR_MIRROR_BASE_SNB + 0x5918) +#define DG1_QCLK_RATIO_MASK REG_GENMASK(9, 2) +#define DG1_QCLK_REFERENCE REG_BIT(10) + +/* + * *_PACKAGE_POWER_SKU - SKU power and timing parameters. + */ +#define PCU_PACKAGE_POWER_SKU _MMIO(MCHBAR_MIRROR_BASE_SNB + 0x5930) +#define PKG_PKG_TDP GENMASK_ULL(14, 0) +#define PKG_MIN_PWR GENMASK_ULL(30, 16) +#define PKG_MAX_PWR GENMASK_ULL(46, 32) +#define PKG_MAX_WIN GENMASK_ULL(54, 48) +#define PKG_MAX_WIN_X GENMASK_ULL(54, 53) +#define PKG_MAX_WIN_Y GENMASK_ULL(52, 48) + +#define PCU_PACKAGE_POWER_SKU_UNIT _MMIO(MCHBAR_MIRROR_BASE_SNB + 0x5938) +#define PKG_PWR_UNIT REG_GENMASK(3, 0) +#define PKG_ENERGY_UNIT REG_GENMASK(12, 8) +#define PKG_TIME_UNIT REG_GENMASK(19, 16) +#define PCU_PACKAGE_ENERGY_STATUS _MMIO(MCHBAR_MIRROR_BASE_SNB + 0x593c) + +#define GEN6_GT_PERF_STATUS _MMIO(MCHBAR_MIRROR_BASE_SNB + 0x5948) + +#define PCU_PACKAGE_TEMPERATURE _MMIO(MCHBAR_MIRROR_BASE_SNB + 0x5978) +#define TEMP_MASK REG_GENMASK(7, 0) + +#define GEN6_RP_STATE_LIMITS _MMIO(MCHBAR_MIRROR_BASE_SNB + 0x5994) +#define GEN6_RP_STATE_CAP _MMIO(MCHBAR_MIRROR_BASE_SNB + 0x5998) +#define RP0_CAP_MASK REG_GENMASK(7, 0) +#define RP1_CAP_MASK REG_GENMASK(15, 8) +#define RPN_CAP_MASK REG_GENMASK(23, 16) + +#define GEN10_FREQ_INFO_REC _MMIO(MCHBAR_MIRROR_BASE_SNB + 0x5ef0) +#define RPE_MASK REG_GENMASK(15, 8) +#define PCU_PACKAGE_RAPL_LIMIT _MMIO(MCHBAR_MIRROR_BASE_SNB + 0x59a0) +#define PKG_PWR_LIM_1 REG_GENMASK(14, 0) +#define PKG_PWR_LIM_1_EN REG_BIT(15) +#define PKG_PWR_LIM_1_TIME REG_GENMASK(23, 17) +#define PKG_PWR_LIM_1_TIME_X REG_GENMASK(23, 22) +#define PKG_PWR_LIM_1_TIME_Y REG_GENMASK(21, 17) + +/* snb MCH registers for priority tuning */ +#define MCH_SSKPD _MMIO(MCHBAR_MIRROR_BASE_SNB + 0x5d10) +#define SSKPD_NEW_WM0_MASK_HSW REG_GENMASK64(63, 56) +#define SSKPD_WM4_MASK_HSW REG_GENMASK64(40, 32) +#define SSKPD_WM3_MASK_HSW REG_GENMASK64(28, 20) +#define SSKPD_WM2_MASK_HSW REG_GENMASK64(19, 12) +#define SSKPD_WM1_MASK_HSW REG_GENMASK64(11, 4) +#define SSKPD_OLD_WM0_MASK_HSW REG_GENMASK64(3, 0) +#define SSKPD_WM3_MASK_SNB REG_GENMASK(29, 24) +#define SSKPD_WM2_MASK_SNB REG_GENMASK(21, 16) +#define SSKPD_WM1_MASK_SNB REG_GENMASK(13, 8) +#define SSKPD_WM0_MASK_SNB REG_GENMASK(5, 0) + +/* Memory controller frequency in MCHBAR for Haswell (possible SNB+) */ +#define DCLK _MMIO(MCHBAR_MIRROR_BASE_SNB + 0x5e04) +#define SKL_MC_BIOS_DATA_0_0_0_MCHBAR_PCU _MMIO(MCHBAR_MIRROR_BASE_SNB + 0x5e04) +#define DG1_GEAR_TYPE REG_BIT(16) + +/* + * Please see hsw_read_dcomp() and hsw_write_dcomp() before using this register, + * since on HSW we can't write to it using intel_uncore_write. + */ +#define D_COMP_HSW _MMIO(MCHBAR_MIRROR_BASE_SNB + 0x5f0c) +#define D_COMP_RCOMP_IN_PROGRESS (1 << 9) +#define D_COMP_COMP_FORCE (1 << 8) +#define D_COMP_COMP_DISABLE (1 << 0) + +#define BXT_GT_PERF_STATUS _MMIO(MCHBAR_MIRROR_BASE_SNB + 0x7070) + +#endif /* __INTEL_MCHBAR_REGS */ -- cgit v1.2.3 From 65d2b7bf1a4f7c765a2c8dfa9254aa799c55040b Mon Sep 17 00:00:00 2001 From: Jani Nikula Date: Tue, 7 Apr 2026 22:36:29 +0300 Subject: drm/i915: drop unnecessary intel_pci_config.h include MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit There's an unnecessary include. Drop it. Suggested-by: Ville Syrjälä Reviewed-by: Ville Syrjälä Link: https://patch.msgid.link/8323c99f379809b2973c99ebe54c21fd274d246c.1775590536.git.jani.nikula@intel.com Signed-off-by: Jani Nikula --- drivers/gpu/drm/i915/i915_driver.c | 1 - 1 file changed, 1 deletion(-) diff --git a/drivers/gpu/drm/i915/i915_driver.c b/drivers/gpu/drm/i915/i915_driver.c index c10cab38935a..129013c5fb42 100644 --- a/drivers/gpu/drm/i915/i915_driver.c +++ b/drivers/gpu/drm/i915/i915_driver.c @@ -122,7 +122,6 @@ #include "intel_cpu_info.h" #include "intel_gvt.h" #include "intel_memory_region.h" -#include "intel_pci_config.h" #include "intel_pcode.h" #include "intel_region_ttm.h" #include "vlv_iosf_sb.h" -- cgit v1.2.3 From 8b1858aaaa20255a42d8eefe7e913c161331af0c Mon Sep 17 00:00:00 2001 From: Jani Nikula Date: Tue, 7 Apr 2026 22:36:30 +0300 Subject: drm/i915/pci: move intel_pci_config.h under include/drm/intel MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Since the PCI registers are used from both i915 display and core, move intel_pci_config.h to include/drm/intel/pci_config.h. Drop the intel_ prefix from the name to reduce tautology. With this, we can drop the corresponding xe display compat header. v2: Rebase Reviewed-by: Ville Syrjälä Link: https://patch.msgid.link/5aac6c711c3f0a09fc52f322455a4a4b35f80a82.1775590536.git.jani.nikula@intel.com Signed-off-by: Jani Nikula --- drivers/gpu/drm/i915/display/i9xx_display_sr.c | 2 +- drivers/gpu/drm/i915/display/intel_backlight.c | 2 +- drivers/gpu/drm/i915/display/intel_cdclk.c | 2 +- drivers/gpu/drm/i915/display/intel_lpe_audio.c | 2 +- drivers/gpu/drm/i915/display/intel_opregion.c | 2 +- drivers/gpu/drm/i915/gem/i915_gem_stolen.c | 2 +- drivers/gpu/drm/i915/gt/intel_ggtt.c | 2 +- drivers/gpu/drm/i915/gt/intel_gt.c | 2 +- drivers/gpu/drm/i915/gt/intel_region_lmem.c | 2 +- drivers/gpu/drm/i915/gt/intel_reset.c | 2 +- drivers/gpu/drm/i915/gvt/cfg_space.c | 2 +- drivers/gpu/drm/i915/i915_gmch.c | 2 +- drivers/gpu/drm/i915/i915_overlay.c | 2 +- drivers/gpu/drm/i915/i915_pci.c | 2 +- drivers/gpu/drm/i915/intel_pci_config.h | 110 --------------------- .../drm/xe/compat-i915-headers/intel_pci_config.h | 6 -- include/drm/intel/pci_config.h | 110 +++++++++++++++++++++ 17 files changed, 124 insertions(+), 130 deletions(-) delete mode 100644 drivers/gpu/drm/i915/intel_pci_config.h delete mode 100644 drivers/gpu/drm/xe/compat-i915-headers/intel_pci_config.h create mode 100644 include/drm/intel/pci_config.h diff --git a/drivers/gpu/drm/i915/display/i9xx_display_sr.c b/drivers/gpu/drm/i915/display/i9xx_display_sr.c index 935419441709..1eb2f636cc65 100644 --- a/drivers/gpu/drm/i915/display/i9xx_display_sr.c +++ b/drivers/gpu/drm/i915/display/i9xx_display_sr.c @@ -4,13 +4,13 @@ */ #include +#include #include "i9xx_display_sr.h" #include "i9xx_wm_regs.h" #include "intel_de.h" #include "intel_display_regs.h" #include "intel_gmbus.h" -#include "intel_pci_config.h" static void i9xx_display_save_swf(struct intel_display *display) { diff --git a/drivers/gpu/drm/i915/display/intel_backlight.c b/drivers/gpu/drm/i915/display/intel_backlight.c index 34e95f05936e..b128896cb1c2 100644 --- a/drivers/gpu/drm/i915/display/intel_backlight.c +++ b/drivers/gpu/drm/i915/display/intel_backlight.c @@ -11,6 +11,7 @@ #include #include +#include #include "intel_backlight.h" #include "intel_backlight_regs.h" @@ -23,7 +24,6 @@ #include "intel_dp_aux_backlight.h" #include "intel_dsi_dcs_backlight.h" #include "intel_panel.h" -#include "intel_pci_config.h" #include "intel_pps.h" #include "intel_quirks.h" diff --git a/drivers/gpu/drm/i915/display/intel_cdclk.c b/drivers/gpu/drm/i915/display/intel_cdclk.c index 82955cf16c4c..8feba2e0333b 100644 --- a/drivers/gpu/drm/i915/display/intel_cdclk.c +++ b/drivers/gpu/drm/i915/display/intel_cdclk.c @@ -28,6 +28,7 @@ #include #include #include +#include #include "hsw_ips.h" #include "intel_atomic.h" @@ -43,7 +44,6 @@ #include "intel_dram.h" #include "intel_mchbar.h" #include "intel_parent.h" -#include "intel_pci_config.h" #include "intel_plane.h" #include "intel_psr.h" #include "intel_step.h" diff --git a/drivers/gpu/drm/i915/display/intel_lpe_audio.c b/drivers/gpu/drm/i915/display/intel_lpe_audio.c index 117b60656ca1..775493306a83 100644 --- a/drivers/gpu/drm/i915/display/intel_lpe_audio.c +++ b/drivers/gpu/drm/i915/display/intel_lpe_audio.c @@ -70,11 +70,11 @@ #include #include +#include #include "intel_audio_regs.h" #include "intel_de.h" #include "intel_lpe_audio.h" -#include "intel_pci_config.h" #define HAS_LPE_AUDIO(display) ((display)->audio.lpe.platdev) diff --git a/drivers/gpu/drm/i915/display/intel_opregion.c b/drivers/gpu/drm/i915/display/intel_opregion.c index e25be56e678b..9f88b7cac9f7 100644 --- a/drivers/gpu/drm/i915/display/intel_opregion.c +++ b/drivers/gpu/drm/i915/display/intel_opregion.c @@ -34,13 +34,13 @@ #include #include #include +#include #include "intel_acpi.h" #include "intel_backlight.h" #include "intel_display_core.h" #include "intel_display_types.h" #include "intel_opregion.h" -#include "intel_pci_config.h" #define OPREGION_HEADER_OFFSET 0 #define OPREGION_ACPI_OFFSET 0x100 diff --git a/drivers/gpu/drm/i915/gem/i915_gem_stolen.c b/drivers/gpu/drm/i915/gem/i915_gem_stolen.c index 5838fb33104d..1cfdcf5c1118 100644 --- a/drivers/gpu/drm/i915/gem/i915_gem_stolen.c +++ b/drivers/gpu/drm/i915/gem/i915_gem_stolen.c @@ -11,6 +11,7 @@ #include #include #include +#include #include "gem/i915_gem_lmem.h" #include "gem/i915_gem_region.h" @@ -24,7 +25,6 @@ #include "i915_reg.h" #include "i915_utils.h" #include "i915_vgpu.h" -#include "intel_pci_config.h" struct intel_stolen_node { struct drm_i915_private *i915; diff --git a/drivers/gpu/drm/i915/gt/intel_ggtt.c b/drivers/gpu/drm/i915/gt/intel_ggtt.c index 08c4e735481b..64ca5bbc53c6 100644 --- a/drivers/gpu/drm/i915/gt/intel_ggtt.c +++ b/drivers/gpu/drm/i915/gt/intel_ggtt.c @@ -12,6 +12,7 @@ #include #include #include +#include #include "gem/i915_gem_lmem.h" @@ -20,7 +21,6 @@ #include "intel_gpu_commands.h" #include "intel_gt.h" #include "intel_gt_regs.h" -#include "intel_pci_config.h" #include "intel_ring.h" #include "i915_drv.h" #include "i915_pci.h" diff --git a/drivers/gpu/drm/i915/gt/intel_gt.c b/drivers/gpu/drm/i915/gt/intel_gt.c index d76121e117e1..5c7f862f7100 100644 --- a/drivers/gpu/drm/i915/gt/intel_gt.c +++ b/drivers/gpu/drm/i915/gt/intel_gt.c @@ -6,6 +6,7 @@ #include #include #include +#include #include "gem/i915_gem_internal.h" #include "gem/i915_gem_lmem.h" @@ -28,7 +29,6 @@ #include "intel_gt_requests.h" #include "intel_migrate.h" #include "intel_mocs.h" -#include "intel_pci_config.h" #include "intel_rc6.h" #include "intel_renderstate.h" #include "intel_rps.h" diff --git a/drivers/gpu/drm/i915/gt/intel_region_lmem.c b/drivers/gpu/drm/i915/gt/intel_region_lmem.c index a30060fd4429..b8a39567a334 100644 --- a/drivers/gpu/drm/i915/gt/intel_region_lmem.c +++ b/drivers/gpu/drm/i915/gt/intel_region_lmem.c @@ -4,12 +4,12 @@ */ #include +#include #include "i915_drv.h" #include "i915_pci.h" #include "i915_reg.h" #include "intel_memory_region.h" -#include "intel_pci_config.h" #include "intel_region_lmem.h" #include "intel_region_ttm.h" #include "gem/i915_gem_lmem.h" diff --git a/drivers/gpu/drm/i915/gt/intel_reset.c b/drivers/gpu/drm/i915/gt/intel_reset.c index 4d0ea953eb6e..37272871b0f2 100644 --- a/drivers/gpu/drm/i915/gt/intel_reset.c +++ b/drivers/gpu/drm/i915/gt/intel_reset.c @@ -8,6 +8,7 @@ #include #include +#include #include "display/intel_display_reset.h" #include "display/intel_overlay.h" @@ -29,7 +30,6 @@ #include "intel_gt_pm.h" #include "intel_gt_print.h" #include "intel_gt_requests.h" -#include "intel_pci_config.h" #include "intel_reset.h" #define RESET_MAX_RETRIES 3 diff --git a/drivers/gpu/drm/i915/gvt/cfg_space.c b/drivers/gpu/drm/i915/gvt/cfg_space.c index 1937e04d3791..e00c1478a24e 100644 --- a/drivers/gpu/drm/i915/gvt/cfg_space.c +++ b/drivers/gpu/drm/i915/gvt/cfg_space.c @@ -32,10 +32,10 @@ */ #include +#include #include "gvt.h" #include "i915_drv.h" -#include "intel_pci_config.h" enum { INTEL_GVT_PCI_BAR_GTTMMIO = 0, diff --git a/drivers/gpu/drm/i915/i915_gmch.c b/drivers/gpu/drm/i915/i915_gmch.c index 2d55831b3c58..b0ef6ef577a3 100644 --- a/drivers/gpu/drm/i915/i915_gmch.c +++ b/drivers/gpu/drm/i915/i915_gmch.c @@ -5,10 +5,10 @@ #include #include +#include #include "i915_drv.h" #include "i915_gmch.h" -#include "intel_pci_config.h" static void i915_gmch_bridge_release(struct drm_device *dev, void *bridge) { diff --git a/drivers/gpu/drm/i915/i915_overlay.c b/drivers/gpu/drm/i915/i915_overlay.c index c2d712bd2b0d..2d7aff51e39b 100644 --- a/drivers/gpu/drm/i915/i915_overlay.c +++ b/drivers/gpu/drm/i915/i915_overlay.c @@ -7,6 +7,7 @@ #include #include +#include #include "gem/i915_gem_internal.h" #include "gem/i915_gem_object_frontbuffer.h" @@ -18,7 +19,6 @@ #include "i915_drv.h" #include "i915_overlay.h" #include "i915_reg.h" -#include "intel_pci_config.h" #include "display/intel_frontbuffer.h" diff --git a/drivers/gpu/drm/i915/i915_pci.c b/drivers/gpu/drm/i915/i915_pci.c index d966a00520f1..82415af47d54 100644 --- a/drivers/gpu/drm/i915/i915_pci.c +++ b/drivers/gpu/drm/i915/i915_pci.c @@ -24,6 +24,7 @@ #include #include +#include #include #include "display/intel_display_driver.h" @@ -35,7 +36,6 @@ #include "i915_drv.h" #include "i915_pci.h" #include "i915_reg.h" -#include "intel_pci_config.h" __diag_push(); __diag_ignore_all("-Woverride-init", "Allow field initialization overrides for device info"); diff --git a/drivers/gpu/drm/i915/intel_pci_config.h b/drivers/gpu/drm/i915/intel_pci_config.h deleted file mode 100644 index ebe040828e20..000000000000 --- a/drivers/gpu/drm/i915/intel_pci_config.h +++ /dev/null @@ -1,110 +0,0 @@ -/* SPDX-License-Identifier: MIT */ -/* - * Copyright © 2022 Intel Corporation - */ - -#ifndef __INTEL_PCI_CONFIG_H__ -#define __INTEL_PCI_CONFIG_H__ - -/* PCI BARs */ -#define GEN2_GMADR_BAR 0 -#define GEN2_MMADR_BAR 1 /* MMIO+GTT, despite the name */ -#define GEN2_IO_BAR 2 /* 85x/865 */ - -#define GEN3_MMADR_BAR 0 /* MMIO only */ -#define GEN3_IO_BAR 1 -#define GEN3_GMADR_BAR 2 -#define GEN3_GTTADR_BAR 3 /* GTT only */ - -#define GEN4_GTTMMADR_BAR 0 /* MMIO+GTT */ -#define GEN4_GMADR_BAR 2 -#define GEN4_IO_BAR 4 - -#define GEN12_LMEM_BAR 2 - -static inline int intel_mmio_bar(int graphics_ver) -{ - switch (graphics_ver) { - case 2: return GEN2_MMADR_BAR; - case 3: return GEN3_MMADR_BAR; - default: return GEN4_GTTMMADR_BAR; - } -} - -/* BSM in include/drm/intel/i915_drm.h */ - -#define MCHBAR_I915 0x44 -#define MCHBAR_I965 0x48 -#define MCHBAR_SIZE (4 * 4096) - -#define DEVEN 0x54 -#define DEVEN_MCHBAR_EN (1 << 28) - -#define HPLLCC 0xc0 /* 85x only */ -#define GC_CLOCK_CONTROL_MASK (0x7 << 0) -#define GC_CLOCK_133_200 (0 << 0) -#define GC_CLOCK_100_200 (1 << 0) -#define GC_CLOCK_100_133 (2 << 0) -#define GC_CLOCK_133_266 (3 << 0) -#define GC_CLOCK_133_200_2 (4 << 0) -#define GC_CLOCK_133_266_2 (5 << 0) -#define GC_CLOCK_166_266 (6 << 0) -#define GC_CLOCK_166_250 (7 << 0) - -#define I915_GDRST 0xc0 -#define GRDOM_FULL (0 << 2) -#define GRDOM_RENDER (1 << 2) -#define GRDOM_MEDIA (3 << 2) -#define GRDOM_MASK (3 << 2) -#define GRDOM_RESET_STATUS (1 << 1) -#define GRDOM_RESET_ENABLE (1 << 0) - -/* BSpec only has register offset, PCI device and bit found empirically */ -#define I830_CLOCK_GATE 0xc8 /* device 0 */ -#define I830_L2_CACHE_CLOCK_GATE_DISABLE (1 << 2) - -#define GCDGMBUS 0xcc - -#define GCFGC2 0xda -#define GCFGC 0xf0 /* 915+ only */ -#define GC_LOW_FREQUENCY_ENABLE (1 << 7) -#define GC_DISPLAY_CLOCK_190_200_MHZ (0 << 4) -#define GC_DISPLAY_CLOCK_333_320_MHZ (4 << 4) -#define GC_DISPLAY_CLOCK_267_MHZ_PNV (0 << 4) -#define GC_DISPLAY_CLOCK_333_MHZ_PNV (1 << 4) -#define GC_DISPLAY_CLOCK_444_MHZ_PNV (2 << 4) -#define GC_DISPLAY_CLOCK_200_MHZ_PNV (5 << 4) -#define GC_DISPLAY_CLOCK_133_MHZ_PNV (6 << 4) -#define GC_DISPLAY_CLOCK_167_MHZ_PNV (7 << 4) -#define GC_DISPLAY_CLOCK_MASK (7 << 4) -#define GM45_GC_RENDER_CLOCK_MASK (0xf << 0) -#define GM45_GC_RENDER_CLOCK_266_MHZ (8 << 0) -#define GM45_GC_RENDER_CLOCK_320_MHZ (9 << 0) -#define GM45_GC_RENDER_CLOCK_400_MHZ (0xb << 0) -#define GM45_GC_RENDER_CLOCK_533_MHZ (0xc << 0) -#define I965_GC_RENDER_CLOCK_MASK (0xf << 0) -#define I965_GC_RENDER_CLOCK_267_MHZ (2 << 0) -#define I965_GC_RENDER_CLOCK_333_MHZ (3 << 0) -#define I965_GC_RENDER_CLOCK_444_MHZ (4 << 0) -#define I965_GC_RENDER_CLOCK_533_MHZ (5 << 0) -#define I945_GC_RENDER_CLOCK_MASK (7 << 0) -#define I945_GC_RENDER_CLOCK_166_MHZ (0 << 0) -#define I945_GC_RENDER_CLOCK_200_MHZ (1 << 0) -#define I945_GC_RENDER_CLOCK_250_MHZ (3 << 0) -#define I945_GC_RENDER_CLOCK_400_MHZ (5 << 0) -#define I915_GC_RENDER_CLOCK_MASK (7 << 0) -#define I915_GC_RENDER_CLOCK_166_MHZ (0 << 0) -#define I915_GC_RENDER_CLOCK_200_MHZ (1 << 0) -#define I915_GC_RENDER_CLOCK_333_MHZ (4 << 0) - -#define ASLE 0xe4 -#define ASLS 0xfc - -#define SWSCI 0xe8 -#define SWSCI_SCISEL (1 << 15) -#define SWSCI_GSSCIE (1 << 0) - -/* legacy/combination backlight modes, also called LBB */ -#define LBPC 0xf4 - -#endif /* __INTEL_PCI_CONFIG_H__ */ diff --git a/drivers/gpu/drm/xe/compat-i915-headers/intel_pci_config.h b/drivers/gpu/drm/xe/compat-i915-headers/intel_pci_config.h deleted file mode 100644 index 8c15867fd613..000000000000 --- a/drivers/gpu/drm/xe/compat-i915-headers/intel_pci_config.h +++ /dev/null @@ -1,6 +0,0 @@ -/* SPDX-License-Identifier: MIT */ -/* - * Copyright © 2023 Intel Corporation - */ - -#include "../../i915/intel_pci_config.h" diff --git a/include/drm/intel/pci_config.h b/include/drm/intel/pci_config.h new file mode 100644 index 000000000000..ebe040828e20 --- /dev/null +++ b/include/drm/intel/pci_config.h @@ -0,0 +1,110 @@ +/* SPDX-License-Identifier: MIT */ +/* + * Copyright © 2022 Intel Corporation + */ + +#ifndef __INTEL_PCI_CONFIG_H__ +#define __INTEL_PCI_CONFIG_H__ + +/* PCI BARs */ +#define GEN2_GMADR_BAR 0 +#define GEN2_MMADR_BAR 1 /* MMIO+GTT, despite the name */ +#define GEN2_IO_BAR 2 /* 85x/865 */ + +#define GEN3_MMADR_BAR 0 /* MMIO only */ +#define GEN3_IO_BAR 1 +#define GEN3_GMADR_BAR 2 +#define GEN3_GTTADR_BAR 3 /* GTT only */ + +#define GEN4_GTTMMADR_BAR 0 /* MMIO+GTT */ +#define GEN4_GMADR_BAR 2 +#define GEN4_IO_BAR 4 + +#define GEN12_LMEM_BAR 2 + +static inline int intel_mmio_bar(int graphics_ver) +{ + switch (graphics_ver) { + case 2: return GEN2_MMADR_BAR; + case 3: return GEN3_MMADR_BAR; + default: return GEN4_GTTMMADR_BAR; + } +} + +/* BSM in include/drm/intel/i915_drm.h */ + +#define MCHBAR_I915 0x44 +#define MCHBAR_I965 0x48 +#define MCHBAR_SIZE (4 * 4096) + +#define DEVEN 0x54 +#define DEVEN_MCHBAR_EN (1 << 28) + +#define HPLLCC 0xc0 /* 85x only */ +#define GC_CLOCK_CONTROL_MASK (0x7 << 0) +#define GC_CLOCK_133_200 (0 << 0) +#define GC_CLOCK_100_200 (1 << 0) +#define GC_CLOCK_100_133 (2 << 0) +#define GC_CLOCK_133_266 (3 << 0) +#define GC_CLOCK_133_200_2 (4 << 0) +#define GC_CLOCK_133_266_2 (5 << 0) +#define GC_CLOCK_166_266 (6 << 0) +#define GC_CLOCK_166_250 (7 << 0) + +#define I915_GDRST 0xc0 +#define GRDOM_FULL (0 << 2) +#define GRDOM_RENDER (1 << 2) +#define GRDOM_MEDIA (3 << 2) +#define GRDOM_MASK (3 << 2) +#define GRDOM_RESET_STATUS (1 << 1) +#define GRDOM_RESET_ENABLE (1 << 0) + +/* BSpec only has register offset, PCI device and bit found empirically */ +#define I830_CLOCK_GATE 0xc8 /* device 0 */ +#define I830_L2_CACHE_CLOCK_GATE_DISABLE (1 << 2) + +#define GCDGMBUS 0xcc + +#define GCFGC2 0xda +#define GCFGC 0xf0 /* 915+ only */ +#define GC_LOW_FREQUENCY_ENABLE (1 << 7) +#define GC_DISPLAY_CLOCK_190_200_MHZ (0 << 4) +#define GC_DISPLAY_CLOCK_333_320_MHZ (4 << 4) +#define GC_DISPLAY_CLOCK_267_MHZ_PNV (0 << 4) +#define GC_DISPLAY_CLOCK_333_MHZ_PNV (1 << 4) +#define GC_DISPLAY_CLOCK_444_MHZ_PNV (2 << 4) +#define GC_DISPLAY_CLOCK_200_MHZ_PNV (5 << 4) +#define GC_DISPLAY_CLOCK_133_MHZ_PNV (6 << 4) +#define GC_DISPLAY_CLOCK_167_MHZ_PNV (7 << 4) +#define GC_DISPLAY_CLOCK_MASK (7 << 4) +#define GM45_GC_RENDER_CLOCK_MASK (0xf << 0) +#define GM45_GC_RENDER_CLOCK_266_MHZ (8 << 0) +#define GM45_GC_RENDER_CLOCK_320_MHZ (9 << 0) +#define GM45_GC_RENDER_CLOCK_400_MHZ (0xb << 0) +#define GM45_GC_RENDER_CLOCK_533_MHZ (0xc << 0) +#define I965_GC_RENDER_CLOCK_MASK (0xf << 0) +#define I965_GC_RENDER_CLOCK_267_MHZ (2 << 0) +#define I965_GC_RENDER_CLOCK_333_MHZ (3 << 0) +#define I965_GC_RENDER_CLOCK_444_MHZ (4 << 0) +#define I965_GC_RENDER_CLOCK_533_MHZ (5 << 0) +#define I945_GC_RENDER_CLOCK_MASK (7 << 0) +#define I945_GC_RENDER_CLOCK_166_MHZ (0 << 0) +#define I945_GC_RENDER_CLOCK_200_MHZ (1 << 0) +#define I945_GC_RENDER_CLOCK_250_MHZ (3 << 0) +#define I945_GC_RENDER_CLOCK_400_MHZ (5 << 0) +#define I915_GC_RENDER_CLOCK_MASK (7 << 0) +#define I915_GC_RENDER_CLOCK_166_MHZ (0 << 0) +#define I915_GC_RENDER_CLOCK_200_MHZ (1 << 0) +#define I915_GC_RENDER_CLOCK_333_MHZ (4 << 0) + +#define ASLE 0xe4 +#define ASLS 0xfc + +#define SWSCI 0xe8 +#define SWSCI_SCISEL (1 << 15) +#define SWSCI_GSSCIE (1 << 0) + +/* legacy/combination backlight modes, also called LBB */ +#define LBPC 0xf4 + +#endif /* __INTEL_PCI_CONFIG_H__ */ -- cgit v1.2.3 From 9cd74f935306cd857f46686975c43383e1d95f94 Mon Sep 17 00:00:00 2001 From: Alessio Belle Date: Mon, 30 Mar 2026 08:56:36 +0100 Subject: drm/imagination: Count paired job fence as dependency in prepare_job() The DRM scheduler's prepare_job() callback counts the remaining non-signaled native dependencies for a job, preventing job submission until those (plus job data and fence update) can fit in the job queue's CCCB. This means checking which dependencies can be waited upon in the firmware, i.e. whether they are backed by a UFO object, i.e. whether their drm_sched_fence::parent has been assigned to a pvr_queue_fence::base fence. That happens when the job owning the fence is submitted to the firmware. Paired geometry and fragment jobs are submitted at the same time, which means the dependency between them can't be checked this way before submission. Update job_count_remaining_native_deps() to take into account the dependency between paired jobs. This fixes cases where prepare_job() underestimated the space left in an almost full fragment CCCB, wrongly unblocking run_job(), which then returned early without writing the full sequence of commands to the CCCB. The above lead to kernel warnings such as the following and potentially job timeouts (depending on waiters on the missing commands): [ 375.702979] WARNING: drivers/gpu/drm/imagination/pvr_cccb.c:178 at pvr_cccb_write_command_with_header+0x2c4/0x330 [powervr], CPU#1: kworker/u16:3/47 [ 375.703160] Modules linked in: [ 375.703571] CPU: 1 UID: 0 PID: 47 Comm: kworker/u16:3 Tainted: G W 7.0.0-rc2-g817eb6b11ad5 #40 PREEMPT [ 375.703613] Tainted: [W]=WARN [ 375.703627] Hardware name: Texas Instruments AM625 SK (DT) [ 375.703645] Workqueue: powervr-sched drm_sched_run_job_work [gpu_sched] [ 375.703741] pstate: 80000005 (Nzcv daif -PAN -UAO -TCO -DIT -SSBS BTYPE=--) [ 375.703764] pc : pvr_cccb_write_command_with_header+0x2c4/0x330 [powervr] [ 375.703847] lr : pvr_queue_submit_job_to_cccb+0x578/0xa70 [powervr] [ 375.703921] sp : ffff800084a97650 [ 375.703934] x29: ffff800084a97740 x28: 0000000000000958 x27: ffff80008565d000 [ 375.703979] x26: 0000000000000030 x25: ffff800084a97680 x24: 0000000000001000 [ 375.704017] x23: ffff800084a97820 x22: 1ffff00010952ecc x21: 0000000000000008 [ 375.704056] x20: 00000000000006a8 x19: ffff00002ff7da88 x18: 0000000000000000 [ 375.704093] x17: 0000000020020000 x16: 0000000000020000 x15: 0000000000000000 [ 375.704132] x14: 0000000000000000 x13: 0000000000000000 x12: 0000000000000000 [ 375.704168] x11: 000000000000f2f2 x10: 00000000f3000000 x9 : 00000000f3f3f3f3 [ 375.704206] x8 : 00000000f2f2f200 x7 : ffff700010952ecc x6 : 0000000000000008 [ 375.704243] x5 : 0000000000000000 x4 : 1ffff00010acba00 x3 : 0000000000000000 [ 375.704279] x2 : 0000000000000007 x1 : 0000000000000fff x0 : 000000000000002f [ 375.704317] Call trace: [ 375.704331] pvr_cccb_write_command_with_header+0x2c4/0x330 [powervr] (P) [ 375.704411] pvr_queue_submit_job_to_cccb+0x578/0xa70 [powervr] [ 375.704487] pvr_queue_run_job+0x3a4/0x990 [powervr] [ 375.704562] drm_sched_run_job_work+0x580/0xd48 [gpu_sched] [ 375.704623] process_one_work+0x520/0x1288 [ 375.704658] worker_thread+0x3f0/0xb3c [ 375.704680] kthread+0x334/0x3d8 [ 375.704706] ret_from_fork+0x10/0x20 [ 375.704736] ---[ end trace 0000000000000000 ]--- Fixes: eaf01ee5ba28 ("drm/imagination: Implement job submission and scheduling") Cc: stable@vger.kernel.org Signed-off-by: Alessio Belle Reviewed-by: Brajesh Gupta Link: https://patch.msgid.link/20260330-job-submission-fixes-cleanup-v1-1-7de8c09cef8c@imgtec.com Signed-off-by: Matt Coster --- drivers/gpu/drm/imagination/pvr_queue.c | 27 +++++++++++++++++++++++---- 1 file changed, 23 insertions(+), 4 deletions(-) diff --git a/drivers/gpu/drm/imagination/pvr_queue.c b/drivers/gpu/drm/imagination/pvr_queue.c index dd88949f6194..836feaa0b295 100644 --- a/drivers/gpu/drm/imagination/pvr_queue.c +++ b/drivers/gpu/drm/imagination/pvr_queue.c @@ -179,7 +179,7 @@ static const struct dma_fence_ops pvr_queue_job_fence_ops = { /** * to_pvr_queue_job_fence() - Return a pvr_queue_fence object if the fence is - * backed by a UFO. + * already backed by a UFO. * @f: The dma_fence to turn into a pvr_queue_fence. * * Return: @@ -356,6 +356,15 @@ static u32 job_cmds_size(struct pvr_job *job, u32 ufo_wait_count) pvr_cccb_get_size_of_cmd_with_hdr(job->cmd_len); } +static bool +is_paired_job_fence(struct dma_fence *fence, struct pvr_job *job) +{ + /* This assumes "fence" is one of "job"'s drm_sched_job::dependencies */ + return job->type == DRM_PVR_JOB_TYPE_FRAGMENT && + job->paired_job && + &job->paired_job->base.s_fence->scheduled == fence; +} + /** * job_count_remaining_native_deps() - Count the number of non-signaled native dependencies. * @job: Job to operate on. @@ -371,6 +380,17 @@ static unsigned long job_count_remaining_native_deps(struct pvr_job *job) xa_for_each(&job->base.dependencies, index, fence) { struct pvr_queue_fence *jfence; + if (is_paired_job_fence(fence, job)) { + /* + * A fence between paired jobs won't resolve to a pvr_queue_fence (i.e. + * be backed by a UFO) until the jobs have been submitted, together. + * The submitting code will insert a partial render fence command for this. + */ + WARN_ON(dma_fence_is_signaled(fence)); + remaining_count++; + continue; + } + jfence = to_pvr_queue_job_fence(fence); if (!jfence) continue; @@ -630,9 +650,8 @@ static void pvr_queue_submit_job_to_cccb(struct pvr_job *job) if (!jfence) continue; - /* Skip the partial render fence, we will place it at the end. */ - if (job->type == DRM_PVR_JOB_TYPE_FRAGMENT && job->paired_job && - &job->paired_job->base.s_fence->scheduled == fence) + /* This fence will be placed last, as partial render fence. */ + if (is_paired_job_fence(fence, job)) continue; if (dma_fence_is_signaled(&jfence->base)) -- cgit v1.2.3 From 4baf9e70cb756d78dd56419f8baee2978a72d0c3 Mon Sep 17 00:00:00 2001 From: Alessio Belle Date: Mon, 30 Mar 2026 08:56:37 +0100 Subject: drm/imagination: Fit paired fragment job in the correct CCCB For geometry jobs with a paired fragment job, at the moment, the DRM scheduler's prepare_job() callback: - checks for internal (driver) dependencies for the geometry job; - calls into pvr_queue_get_paired_frag_job_dep() to check for external dependencies for the fragment job (the two jobs are submitted together but the common scheduler code doesn't know about it, so this needs to be done at this point in time); - calls into the prepare_job() callback again, but for the fragment job, to check its internal dependencies as well, passing the fragment job's drm_sched_job and the geometry job's drm_sched_entity / pvr_queue. The problem with the last step is that pvr_queue_prepare_job() doesn't always take the mismatched fragment job and geometry queue into account, in particular when checking whether there is space for the fragment command to be submitted, so the code ends up checking for space in the geometry (i.e. wrong) CCCB. The rest of the nested prepare_job() callback happens to work fine at the moment as the other internal dependencies are not relevant for a paired fragment job. Move the initialisation of a paired fragment job's done fence and CCCB fence to pvr_queue_get_paired_frag_job_dep(), inferring the correct queue from the fragment job itself. This fixes cases where prepare_job() wrongly assumed that there was enough space for a paired fragment job in its own CCCB, unblocking run_job(), which then returned early without writing the full sequence of commands to the CCCB. The above lead to kernel warnings such as the following and potentially job timeouts (depending on waiters on the missing commands): [ 552.421075] WARNING: drivers/gpu/drm/imagination/pvr_cccb.c:178 at pvr_cccb_write_command_with_header+0x2c4/0x330 [powervr], CPU#2: kworker/u16:5/63 [ 552.421230] Modules linked in: [ 552.421592] CPU: 2 UID: 0 PID: 63 Comm: kworker/u16:5 Tainted: G W 7.0.0-rc2-gc5d053e4dccb #39 PREEMPT [ 552.421625] Tainted: [W]=WARN [ 552.421637] Hardware name: Texas Instruments AM625 SK (DT) [ 552.421655] Workqueue: powervr-sched drm_sched_run_job_work [gpu_sched] [ 552.421744] pstate: 80000005 (Nzcv daif -PAN -UAO -TCO -DIT -SSBS BTYPE=--) [ 552.421766] pc : pvr_cccb_write_command_with_header+0x2c4/0x330 [powervr] [ 552.421850] lr : pvr_queue_submit_job_to_cccb+0x57c/0xa74 [powervr] [ 552.421923] sp : ffff800084c47650 [ 552.421936] x29: ffff800084c47740 x28: 0000000000000df8 x27: ffff800088a77000 [ 552.421979] x26: 0000000000000030 x25: ffff800084c47680 x24: 0000000000001000 [ 552.422017] x23: ffff800084c47820 x22: 1ffff00010988ecc x21: 0000000000000008 [ 552.422055] x20: 0000000000000208 x19: ffff000006ad5a88 x18: 0000000000000000 [ 552.422093] x17: 0000000020020000 x16: 0000000000020000 x15: 0000000000000000 [ 552.422130] x14: 0000000000000000 x13: 0000000000000000 x12: 0000000000000000 [ 552.422167] x11: 000000000000f2f2 x10: 00000000f3000000 x9 : 00000000f3f3f3f3 [ 552.422204] x8 : 00000000f2f2f200 x7 : ffff700010988ecc x6 : 0000000000000008 [ 552.422241] x5 : 0000000000000000 x4 : 1ffff0001114ee00 x3 : 0000000000000000 [ 552.422278] x2 : 0000000000000007 x1 : 0000000000000fff x0 : 000000000000002f [ 552.422316] Call trace: [ 552.422330] pvr_cccb_write_command_with_header+0x2c4/0x330 [powervr] (P) [ 552.422411] pvr_queue_submit_job_to_cccb+0x57c/0xa74 [powervr] [ 552.422486] pvr_queue_run_job+0x3a4/0x990 [powervr] [ 552.422562] drm_sched_run_job_work+0x580/0xd48 [gpu_sched] [ 552.422623] process_one_work+0x520/0x1288 [ 552.422657] worker_thread+0x3f0/0xb3c [ 552.422679] kthread+0x334/0x3d8 [ 552.422706] ret_from_fork+0x10/0x20 Fixes: eaf01ee5ba28 ("drm/imagination: Implement job submission and scheduling") Cc: stable@vger.kernel.org Signed-off-by: Alessio Belle Reviewed-by: Brajesh Gupta Link: https://patch.msgid.link/20260330-job-submission-fixes-cleanup-v1-2-7de8c09cef8c@imgtec.com Signed-off-by: Matt Coster --- drivers/gpu/drm/imagination/pvr_queue.c | 32 ++++++++++++++------------------ 1 file changed, 14 insertions(+), 18 deletions(-) diff --git a/drivers/gpu/drm/imagination/pvr_queue.c b/drivers/gpu/drm/imagination/pvr_queue.c index 836feaa0b295..f1e54e6d940d 100644 --- a/drivers/gpu/drm/imagination/pvr_queue.c +++ b/drivers/gpu/drm/imagination/pvr_queue.c @@ -488,10 +488,11 @@ pvr_queue_get_job_kccb_fence(struct pvr_queue *queue, struct pvr_job *job) } static struct dma_fence * -pvr_queue_get_paired_frag_job_dep(struct pvr_queue *queue, struct pvr_job *job) +pvr_queue_get_paired_frag_job_dep(struct pvr_job *job) { struct pvr_job *frag_job = job->type == DRM_PVR_JOB_TYPE_GEOMETRY ? job->paired_job : NULL; + struct pvr_queue *frag_queue = frag_job ? frag_job->ctx->queues.fragment : NULL; struct dma_fence *f; unsigned long index; @@ -510,7 +511,10 @@ pvr_queue_get_paired_frag_job_dep(struct pvr_queue *queue, struct pvr_job *job) return dma_fence_get(f); } - return frag_job->base.sched->ops->prepare_job(&frag_job->base, &queue->entity); + /* Initialize the paired fragment job's done_fence, so we can signal it. */ + pvr_queue_job_fence_init(frag_job->done_fence, frag_queue); + + return pvr_queue_get_job_cccb_fence(frag_queue, frag_job); } /** @@ -529,11 +533,6 @@ pvr_queue_prepare_job(struct drm_sched_job *sched_job, struct pvr_queue *queue = container_of(s_entity, struct pvr_queue, entity); struct dma_fence *internal_dep = NULL; - /* - * Initialize the done_fence, so we can signal it. This must be done - * here because otherwise by the time of run_job() the job will end up - * in the pending list without a valid fence. - */ if (job->type == DRM_PVR_JOB_TYPE_FRAGMENT && job->paired_job) { /* * This will be called on a paired fragment job after being @@ -543,18 +542,15 @@ pvr_queue_prepare_job(struct drm_sched_job *sched_job, */ if (job->paired_job->has_pm_ref) return NULL; - - /* - * In this case we need to use the job's own ctx to initialise - * the done_fence. The other steps are done in the ctx of the - * paired geometry job. - */ - pvr_queue_job_fence_init(job->done_fence, - job->ctx->queues.fragment); - } else { - pvr_queue_job_fence_init(job->done_fence, queue); } + /* + * Initialize the done_fence, so we can signal it. This must be done + * here because otherwise by the time of run_job() the job will end up + * in the pending list without a valid fence. + */ + pvr_queue_job_fence_init(job->done_fence, queue); + /* CCCB fence is used to make sure we have enough space in the CCCB to * submit our commands. */ @@ -575,7 +571,7 @@ pvr_queue_prepare_job(struct drm_sched_job *sched_job, /* The paired job fence should come last, when everything else is ready. */ if (!internal_dep) - internal_dep = pvr_queue_get_paired_frag_job_dep(queue, job); + internal_dep = pvr_queue_get_paired_frag_job_dep(job); return internal_dep; } -- cgit v1.2.3 From 18998b3cb7595850b8b2da55adb3fdc7aef8bc22 Mon Sep 17 00:00:00 2001 From: Alessio Belle Date: Mon, 30 Mar 2026 08:56:38 +0100 Subject: drm/imagination: Skip check on paired job fence during job submission While submitting a paired fragment job, there is no need to manually look for, and skip, the paired job fence, as the existing logic to resolve dependencies to pvr_queue_fence objects will have failed to resolve it already and continued with the next one. Point this out where the fence is actually accessed and drop the related check. Signed-off-by: Alessio Belle Reviewed-by: Brajesh Gupta Link: https://patch.msgid.link/20260330-job-submission-fixes-cleanup-v1-3-7de8c09cef8c@imgtec.com Signed-off-by: Matt Coster --- drivers/gpu/drm/imagination/pvr_queue.c | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/drivers/gpu/drm/imagination/pvr_queue.c b/drivers/gpu/drm/imagination/pvr_queue.c index f1e54e6d940d..527eae1309d8 100644 --- a/drivers/gpu/drm/imagination/pvr_queue.c +++ b/drivers/gpu/drm/imagination/pvr_queue.c @@ -646,10 +646,6 @@ static void pvr_queue_submit_job_to_cccb(struct pvr_job *job) if (!jfence) continue; - /* This fence will be placed last, as partial render fence. */ - if (is_paired_job_fence(fence, job)) - continue; - if (dma_fence_is_signaled(&jfence->base)) continue; @@ -664,8 +660,13 @@ static void pvr_queue_submit_job_to_cccb(struct pvr_job *job) } } - /* Partial render fence goes last. */ if (job->type == DRM_PVR_JOB_TYPE_FRAGMENT && job->paired_job) { + /* + * The loop above will only process dependencies backed by a UFO i.e. with + * a valid parent fence assigned, but the paired job dependency won't have + * one until both jobs have been submitted. Access the parent fence directly + * here instead, submitting it last as partial render fence. + */ jfence = to_pvr_queue_job_fence(job->paired_job->done_fence); if (!WARN_ON(!jfence)) { pvr_fw_object_get_fw_addr(jfence->queue->timeline_ufo.fw_obj, -- cgit v1.2.3 From c162e655092de8de2e0f7776d72919dd5e3b84f2 Mon Sep 17 00:00:00 2001 From: Alessio Belle Date: Mon, 30 Mar 2026 08:56:39 +0100 Subject: drm/imagination: Rename pvr_queue_fence_is_ufo_backed() to reflect usage This function is only used by the synchronization code to figure out if a fence belongs to this driver. Rename it to pvr_queue_fence_is_native() and update its documentation to reflect its current purpose. Signed-off-by: Alessio Belle Reviewed-by: Brajesh Gupta Link: https://patch.msgid.link/20260330-job-submission-fixes-cleanup-v1-4-7de8c09cef8c@imgtec.com Signed-off-by: Matt Coster --- drivers/gpu/drm/imagination/pvr_queue.c | 14 +++++++------- drivers/gpu/drm/imagination/pvr_queue.h | 2 +- drivers/gpu/drm/imagination/pvr_sync.c | 4 ++-- 3 files changed, 10 insertions(+), 10 deletions(-) diff --git a/drivers/gpu/drm/imagination/pvr_queue.c b/drivers/gpu/drm/imagination/pvr_queue.c index 527eae1309d8..df0a110ed96f 100644 --- a/drivers/gpu/drm/imagination/pvr_queue.c +++ b/drivers/gpu/drm/imagination/pvr_queue.c @@ -898,16 +898,16 @@ static const struct drm_sched_backend_ops pvr_queue_sched_ops = { }; /** - * pvr_queue_fence_is_ufo_backed() - Check if a dma_fence is backed by a UFO object + * pvr_queue_fence_is_native() - Check if a dma_fence is native to this driver. * @f: Fence to test. * - * A UFO-backed fence is a fence that can be signaled or waited upon FW-side. - * pvr_job::done_fence objects are backed by the timeline UFO attached to the queue - * they are pushed to, but those fences are not directly exposed to the outside - * world, so we also need to check if the fence we're being passed is a - * drm_sched_fence that was coming from our driver. + * Check if the fence we're being passed is a drm_sched_fence that is coming from this driver. + * + * It may be a UFO-backed fence i.e. a fence that can be signaled or waited upon FW-side, + * such as pvr_job::done_fence objects that are backed by the timeline UFO attached to the queue + * they are pushed to. */ -bool pvr_queue_fence_is_ufo_backed(struct dma_fence *f) +bool pvr_queue_fence_is_native(struct dma_fence *f) { struct drm_sched_fence *sched_fence = f ? to_drm_sched_fence(f) : NULL; diff --git a/drivers/gpu/drm/imagination/pvr_queue.h b/drivers/gpu/drm/imagination/pvr_queue.h index fc1986d73fc8..4aa72665ce25 100644 --- a/drivers/gpu/drm/imagination/pvr_queue.h +++ b/drivers/gpu/drm/imagination/pvr_queue.h @@ -141,7 +141,7 @@ struct pvr_queue { u64 callstack_addr; }; -bool pvr_queue_fence_is_ufo_backed(struct dma_fence *f); +bool pvr_queue_fence_is_native(struct dma_fence *f); int pvr_queue_job_init(struct pvr_job *job, u64 drm_client_id); diff --git a/drivers/gpu/drm/imagination/pvr_sync.c b/drivers/gpu/drm/imagination/pvr_sync.c index 3582616ff722..757a18b1ab8f 100644 --- a/drivers/gpu/drm/imagination/pvr_sync.c +++ b/drivers/gpu/drm/imagination/pvr_sync.c @@ -211,7 +211,7 @@ pvr_sync_add_dep_to_job(struct drm_sched_job *job, struct dma_fence *f) int err = 0; dma_fence_unwrap_for_each(uf, &iter, f) { - if (pvr_queue_fence_is_ufo_backed(uf)) + if (pvr_queue_fence_is_native(uf)) native_fence_count++; } @@ -227,7 +227,7 @@ pvr_sync_add_dep_to_job(struct drm_sched_job *job, struct dma_fence *f) if (err) continue; - if (pvr_queue_fence_is_ufo_backed(uf)) { + if (pvr_queue_fence_is_native(uf)) { struct drm_sched_fence *s_fence = to_drm_sched_fence(uf); /* If this is a native dependency, we wait for the scheduled fence, -- cgit v1.2.3 From 5dae1a21f1e7128a19c68212422383f700699d01 Mon Sep 17 00:00:00 2001 From: Alessio Belle Date: Mon, 30 Mar 2026 08:56:40 +0100 Subject: drm/imagination: Rename fence returned by pvr_queue_job_arm() Rename from done_fence to finished_fence, both because the function returns a drm_sched_fence's finished fence, and to avoid confusion with the job fence, which is called the same but has a different purpose. Signed-off-by: Alessio Belle Reviewed-by: Brajesh Gupta Link: https://patch.msgid.link/20260330-job-submission-fixes-cleanup-v1-5-7de8c09cef8c@imgtec.com Signed-off-by: Matt Coster --- drivers/gpu/drm/imagination/pvr_job.c | 8 ++++---- drivers/gpu/drm/imagination/pvr_sync.c | 4 ++-- drivers/gpu/drm/imagination/pvr_sync.h | 2 +- 3 files changed, 7 insertions(+), 7 deletions(-) diff --git a/drivers/gpu/drm/imagination/pvr_job.c b/drivers/gpu/drm/imagination/pvr_job.c index 0c2f511a6178..dd9f5df01e08 100644 --- a/drivers/gpu/drm/imagination/pvr_job.c +++ b/drivers/gpu/drm/imagination/pvr_job.c @@ -326,7 +326,7 @@ prepare_job_syncs(struct pvr_file *pvr_file, struct pvr_job_data *job_data, struct xarray *signal_array) { - struct dma_fence *done_fence; + struct dma_fence *finished_fence; int err = pvr_sync_signal_array_collect_ops(signal_array, from_pvr_file(pvr_file), job_data->sync_op_count, @@ -359,13 +359,13 @@ prepare_job_syncs(struct pvr_file *pvr_file, return err; } - /* We need to arm the job to get the job done fence. */ - done_fence = pvr_queue_job_arm(job_data->job); + /* We need to arm the job to get the job finished fence. */ + finished_fence = pvr_queue_job_arm(job_data->job); err = pvr_sync_signal_array_update_fences(signal_array, job_data->sync_op_count, job_data->sync_ops, - done_fence); + finished_fence); return err; } diff --git a/drivers/gpu/drm/imagination/pvr_sync.c b/drivers/gpu/drm/imagination/pvr_sync.c index 757a18b1ab8f..936f840a5221 100644 --- a/drivers/gpu/drm/imagination/pvr_sync.c +++ b/drivers/gpu/drm/imagination/pvr_sync.c @@ -160,7 +160,7 @@ int pvr_sync_signal_array_update_fences(struct xarray *array, u32 sync_op_count, const struct drm_pvr_sync_op *sync_ops, - struct dma_fence *done_fence) + struct dma_fence *finished_fence) { for (u32 i = 0; i < sync_op_count; i++) { struct dma_fence *old_fence; @@ -175,7 +175,7 @@ pvr_sync_signal_array_update_fences(struct xarray *array, return -EINVAL; old_fence = sig_sync->fence; - sig_sync->fence = dma_fence_get(done_fence); + sig_sync->fence = dma_fence_get(finished_fence); dma_fence_put(old_fence); if (WARN_ON(!sig_sync->fence)) diff --git a/drivers/gpu/drm/imagination/pvr_sync.h b/drivers/gpu/drm/imagination/pvr_sync.h index db6ccfda104a..48501ad27794 100644 --- a/drivers/gpu/drm/imagination/pvr_sync.h +++ b/drivers/gpu/drm/imagination/pvr_sync.h @@ -70,7 +70,7 @@ int pvr_sync_signal_array_update_fences(struct xarray *array, u32 sync_op_count, const struct drm_pvr_sync_op *sync_ops, - struct dma_fence *done_fence); + struct dma_fence *finished_fence); void pvr_sync_signal_array_push_fences(struct xarray *array); -- cgit v1.2.3 From 402562e60c6c1b15ee359ba7ffed907baa886a99 Mon Sep 17 00:00:00 2001 From: Alessio Belle Date: Mon, 30 Mar 2026 08:56:41 +0100 Subject: drm/imagination: Move repeated job fence check to its own function This should make the code slightly clearer. Signed-off-by: Alessio Belle Reviewed-by: Brajesh Gupta Link: https://patch.msgid.link/20260330-job-submission-fixes-cleanup-v1-6-7de8c09cef8c@imgtec.com Signed-off-by: Matt Coster --- drivers/gpu/drm/imagination/pvr_queue.c | 25 ++++++++++++++++++++----- 1 file changed, 20 insertions(+), 5 deletions(-) diff --git a/drivers/gpu/drm/imagination/pvr_queue.c b/drivers/gpu/drm/imagination/pvr_queue.c index df0a110ed96f..4a49d954562e 100644 --- a/drivers/gpu/drm/imagination/pvr_queue.c +++ b/drivers/gpu/drm/imagination/pvr_queue.c @@ -177,6 +177,24 @@ static const struct dma_fence_ops pvr_queue_job_fence_ops = { .release = pvr_queue_fence_release, }; +/** + * pvr_queue_fence_is_ufo_backed() - Check if a dma_fence is backed by a UFO. + * @f: The dma_fence to check. + * + * Return: + * * true if the dma_fence is backed by a UFO, or + * * false otherwise. + */ +static inline bool +pvr_queue_fence_is_ufo_backed(struct dma_fence *f) +{ + /* + * Currently the only dma_fence backed by a UFO object is the job fence, + * e.g. pvr_job::done_fence, wrapped by a pvr_queue_fence object. + */ + return f && f->ops == &pvr_queue_job_fence_ops; +} + /** * to_pvr_queue_job_fence() - Return a pvr_queue_fence object if the fence is * already backed by a UFO. @@ -194,7 +212,7 @@ to_pvr_queue_job_fence(struct dma_fence *f) if (sched_fence) f = sched_fence->parent; - if (f && f->ops == &pvr_queue_job_fence_ops) + if (pvr_queue_fence_is_ufo_backed(f)) return container_of(f, struct pvr_queue_fence, base); return NULL; @@ -915,10 +933,7 @@ bool pvr_queue_fence_is_native(struct dma_fence *f) sched_fence->sched->ops == &pvr_queue_sched_ops) return true; - if (f && f->ops == &pvr_queue_job_fence_ops) - return true; - - return false; + return pvr_queue_fence_is_ufo_backed(f); } /** -- cgit v1.2.3 From 5c81eb2970133ad073214eb1e5b0c34a1ae793eb Mon Sep 17 00:00:00 2001 From: Alessio Belle Date: Mon, 30 Mar 2026 08:56:42 +0100 Subject: drm/imagination: Update check to skip prepare_job() for fragment jobs By the time prepare_job() is called on a paired fragment job, the paired geometry job might already be finished and its PM reference dropped. Check the fragment job's PM reference instead which is a bit more likely to be still set. This is a very minor optimization. Signed-off-by: Alessio Belle Reviewed-by: Brajesh Gupta Link: https://patch.msgid.link/20260330-job-submission-fixes-cleanup-v1-7-7de8c09cef8c@imgtec.com Signed-off-by: Matt Coster --- drivers/gpu/drm/imagination/pvr_queue.c | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/drivers/gpu/drm/imagination/pvr_queue.c b/drivers/gpu/drm/imagination/pvr_queue.c index 4a49d954562e..303f4d6cc09e 100644 --- a/drivers/gpu/drm/imagination/pvr_queue.c +++ b/drivers/gpu/drm/imagination/pvr_queue.c @@ -553,12 +553,13 @@ pvr_queue_prepare_job(struct drm_sched_job *sched_job, if (job->type == DRM_PVR_JOB_TYPE_FRAGMENT && job->paired_job) { /* - * This will be called on a paired fragment job after being - * submitted to firmware. We can tell if this is the case and - * bail early from whether run_job() has been called on the - * geometry job, which would issue a pm ref. + * This will be called on a paired fragment job after being submitted + * to the firmware as part of the paired geometry job's submission. + * We can tell if this is the case and bail early from whether run_job() + * has been called on the geometry job, which would issue a pm ref on + * this job as well. */ - if (job->paired_job->has_pm_ref) + if (job->has_pm_ref) return NULL; } -- cgit v1.2.3 From 62a36c2da774800bef893bc4bf8922fb9c07c1d0 Mon Sep 17 00:00:00 2001 From: Alessio Belle Date: Mon, 30 Mar 2026 08:56:43 +0100 Subject: drm/imagination: Minor improvements to job submission code documentation Mixed list of clarifications and typo fixes. Signed-off-by: Alessio Belle Reviewed-by: Brajesh Gupta Link: https://patch.msgid.link/20260330-job-submission-fixes-cleanup-v1-8-7de8c09cef8c@imgtec.com Signed-off-by: Matt Coster --- drivers/gpu/drm/imagination/pvr_queue.c | 38 ++++++++++++++-------- .../gpu/drm/imagination/pvr_rogue_fwif_shared.h | 10 +----- 2 files changed, 26 insertions(+), 22 deletions(-) diff --git a/drivers/gpu/drm/imagination/pvr_queue.c b/drivers/gpu/drm/imagination/pvr_queue.c index 303f4d6cc09e..b5bec656d13c 100644 --- a/drivers/gpu/drm/imagination/pvr_queue.c +++ b/drivers/gpu/drm/imagination/pvr_queue.c @@ -200,6 +200,13 @@ pvr_queue_fence_is_ufo_backed(struct dma_fence *f) * already backed by a UFO. * @f: The dma_fence to turn into a pvr_queue_fence. * + * This could be called on: + * - a job fence directly, in which case it simply returns the containing pvr_queue_fence; + * - a drm_sched_fence's scheduled or finished fence, in which case it will first try to follow + * the parent pointer to find the job fence (note that the parent pointer is initialized + * only after the run_job() callback is called on the drm_sched_fence's owning job); + * - any other dma_fence, in which case it will return NULL. + * * Return: * * A non-NULL pvr_queue_fence object if the dma_fence is backed by a UFO, or * * NULL otherwise. @@ -367,11 +374,14 @@ static u32 ufo_cmds_size(u32 elem_count) static u32 job_cmds_size(struct pvr_job *job, u32 ufo_wait_count) { - /* One UFO cmd for the fence signaling, one UFO cmd per native fence native, - * and a command for the job itself. + /* + * One UFO command per native fence this job will be waiting on (unless any are + * signaled by the time the job is submitted), plus a command for the job itself, + * plus one UFO command for the fence signaling. */ - return ufo_cmds_size(1) + ufo_cmds_size(ufo_wait_count) + - pvr_cccb_get_size_of_cmd_with_hdr(job->cmd_len); + return ufo_cmds_size(ufo_wait_count) + + pvr_cccb_get_size_of_cmd_with_hdr(job->cmd_len) + + ufo_cmds_size(1); } static bool @@ -517,12 +527,16 @@ pvr_queue_get_paired_frag_job_dep(struct pvr_job *job) if (!frag_job) return NULL; + /* Have the geometry job wait on the paired fragment job's dependencies as well. */ xa_for_each(&frag_job->base.dependencies, index, f) { /* Skip already signaled fences. */ if (dma_fence_is_signaled(f)) continue; - /* Skip our own fence. */ + /* + * The paired job fence won't be signaled until both jobs have + * been submitted, so we can't wait on it to schedule them. + */ if (f == &job->base.s_fence->scheduled) continue; @@ -665,6 +679,7 @@ static void pvr_queue_submit_job_to_cccb(struct pvr_job *job) if (!jfence) continue; + /* Some dependencies might have been signaled since prepare_job() */ if (dma_fence_is_signaled(&jfence->base)) continue; @@ -714,7 +729,7 @@ static void pvr_queue_submit_job_to_cccb(struct pvr_job *job) pvr_cccb_write_command_with_header(cccb, job->fw_ccb_cmd_type, job->cmd_len, job->cmd, job->id, job->id); - /* Signal the job fence. */ + /* Update command to signal the job fence. */ pvr_fw_object_get_fw_addr(queue->timeline_ufo.fw_obj, &ufos[0].addr); ufos[0].value = job->done_fence->seqno; pvr_cccb_write_command_with_header(cccb, ROGUE_FWIF_CCB_CMD_TYPE_UPDATE, @@ -744,10 +759,8 @@ static struct dma_fence *pvr_queue_run_job(struct drm_sched_job *sched_job) } /* The only kind of jobs that can be paired are geometry and fragment, and - * we bail out early if we see a fragment job that's paired with a geomtry - * job. - * Paired jobs must also target the same context and point to the same - * HWRT. + * we bail out early if we see a fragment job that's paired with a geometry job. + * Paired jobs must also target the same context and point to the same HWRT. */ if (WARN_ON(job->paired_job && (job->type != DRM_PVR_JOB_TYPE_GEOMETRY || @@ -966,9 +979,8 @@ pvr_queue_signal_done_fences(struct pvr_queue *queue) } /** - * pvr_queue_check_job_waiting_for_cccb_space() - Check if the job waiting for CCCB space - * can be unblocked - * pushed to the CCCB + * pvr_queue_check_job_waiting_for_cccb_space() - Check if a job waiting for CCCB space + * can be unblocked and pushed to the CCCB. * @queue: Queue to check * * If we have a job waiting for CCCB, and this job now fits in the CCCB, we signal diff --git a/drivers/gpu/drm/imagination/pvr_rogue_fwif_shared.h b/drivers/gpu/drm/imagination/pvr_rogue_fwif_shared.h index 869d904e3649..fe54c1cad7a9 100644 --- a/drivers/gpu/drm/imagination/pvr_rogue_fwif_shared.h +++ b/drivers/gpu/drm/imagination/pvr_rogue_fwif_shared.h @@ -14,15 +14,7 @@ #define ROGUE_NUM_GEOM_CORES_SIZE 2U -/* - * Maximum number of UFOs in a CCB command. - * The number is based on having 32 sync prims (as originally), plus 32 sync - * checkpoints. - * Once the use of sync prims is no longer supported, we will retain - * the same total (64) as the number of sync checkpoints which may be - * supporting a fence is not visible to the client driver and has to - * allow for the number of different timelines involved in fence merges. - */ +/* Maximum number of UFOs in a CCB command. */ #define ROGUE_FWIF_CCB_CMD_MAX_UFOS (32U + 32U) /* -- cgit v1.2.3 From fd60a1c32e671e21cdd890bb578ced0d521810ac Mon Sep 17 00:00:00 2001 From: Ville Syrjälä Date: Tue, 7 Apr 2026 20:52:35 +0300 Subject: drm/i915/casf: s/casf_enable/enable/ MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The 'casf_enable' boolean is already inside a casf specific structure, so drop the extra 'casf_' namespace from the bool. Reviewed-by: Michał Grzelak Reviewed-by: Nemesa Garg Signed-off-by: Ville Syrjälä Link: https://patch.msgid.link/20260407175244.19654-2-ville.syrjala@linux.intel.com --- drivers/gpu/drm/i915/display/intel_casf.c | 8 ++++---- drivers/gpu/drm/i915/display/intel_crtc_state_dump.c | 2 +- drivers/gpu/drm/i915/display/intel_display.c | 6 +++--- drivers/gpu/drm/i915/display/intel_display_types.h | 2 +- drivers/gpu/drm/i915/display/skl_scaler.c | 4 ++-- 5 files changed, 11 insertions(+), 11 deletions(-) diff --git a/drivers/gpu/drm/i915/display/intel_casf.c b/drivers/gpu/drm/i915/display/intel_casf.c index b167af31de5b..32e6f7c8acdd 100644 --- a/drivers/gpu/drm/i915/display/intel_casf.c +++ b/drivers/gpu/drm/i915/display/intel_casf.c @@ -110,7 +110,7 @@ int intel_casf_compute_config(struct intel_crtc_state *crtc_state) return 0; if (crtc_state->uapi.sharpness_strength == 0) { - crtc_state->hw.casf_params.casf_enable = false; + crtc_state->hw.casf_params.enable = false; crtc_state->hw.casf_params.strength = 0; return 0; } @@ -121,7 +121,7 @@ int intel_casf_compute_config(struct intel_crtc_state *crtc_state) return -EINVAL; } - crtc_state->hw.casf_params.casf_enable = true; + crtc_state->hw.casf_params.enable = true; /* * HW takes a value in form (1.0 + strength) in 4.4 fixed format. @@ -155,7 +155,7 @@ void intel_casf_sharpness_get_config(struct intel_crtc_state *crtc_state) else crtc_state->hw.casf_params.strength = REG_FIELD_GET(FILTER_STRENGTH_MASK, sharp); - crtc_state->hw.casf_params.casf_enable = true; + crtc_state->hw.casf_params.enable = true; crtc_state->hw.casf_params.win_size = REG_FIELD_GET(FILTER_SIZE_MASK, sharp); } @@ -163,7 +163,7 @@ void intel_casf_sharpness_get_config(struct intel_crtc_state *crtc_state) bool intel_casf_needs_scaler(const struct intel_crtc_state *crtc_state) { - if (crtc_state->hw.casf_params.casf_enable) + if (crtc_state->hw.casf_params.enable) return true; return false; diff --git a/drivers/gpu/drm/i915/display/intel_crtc_state_dump.c b/drivers/gpu/drm/i915/display/intel_crtc_state_dump.c index c85ba9a95322..a11a79a0211e 100644 --- a/drivers/gpu/drm/i915/display/intel_crtc_state_dump.c +++ b/drivers/gpu/drm/i915/display/intel_crtc_state_dump.c @@ -351,7 +351,7 @@ void intel_crtc_state_dump(const struct intel_crtc_state *pipe_config, drm_printf(&p, "sharpness strength: %d, sharpness tap size: %d, sharpness enable: %d\n", pipe_config->hw.casf_params.strength, pipe_config->hw.casf_params.win_size, - pipe_config->hw.casf_params.casf_enable); + pipe_config->hw.casf_params.enable); drm_printf(&p, "ips: %i, double wide: %i, drrs: %i\n", pipe_config->ips_enabled, pipe_config->double_wide, diff --git a/drivers/gpu/drm/i915/display/intel_display.c b/drivers/gpu/drm/i915/display/intel_display.c index 10b6c6fcb03f..78d97441f682 100644 --- a/drivers/gpu/drm/i915/display/intel_display.c +++ b/drivers/gpu/drm/i915/display/intel_display.c @@ -994,7 +994,7 @@ static bool intel_casf_enabling(const struct intel_crtc_state *new_crtc_state, if (!new_crtc_state->hw.active) return false; - return is_enabling(hw.casf_params.casf_enable, old_crtc_state, new_crtc_state); + return is_enabling(hw.casf_params.enable, old_crtc_state, new_crtc_state); } static bool intel_casf_disabling(const struct intel_crtc_state *old_crtc_state, @@ -1003,7 +1003,7 @@ static bool intel_casf_disabling(const struct intel_crtc_state *old_crtc_state, if (!new_crtc_state->hw.active) return false; - return is_disabling(hw.casf_params.casf_enable, old_crtc_state, new_crtc_state); + return is_disabling(hw.casf_params.enable, old_crtc_state, new_crtc_state); } static bool intel_crtc_lobf_enabling(const struct intel_crtc_state *old_crtc_state, @@ -5371,7 +5371,7 @@ intel_pipe_config_compare(const struct intel_crtc_state *current_config, PIPE_CONF_CHECK_I(scaler_state.scaler_id); PIPE_CONF_CHECK_I(pixel_rate); - PIPE_CONF_CHECK_BOOL(hw.casf_params.casf_enable); + PIPE_CONF_CHECK_BOOL(hw.casf_params.enable); PIPE_CONF_CHECK_I(hw.casf_params.win_size); PIPE_CONF_CHECK_I(hw.casf_params.strength); diff --git a/drivers/gpu/drm/i915/display/intel_display_types.h b/drivers/gpu/drm/i915/display/intel_display_types.h index e2496db1642a..83bb5d19b6f6 100644 --- a/drivers/gpu/drm/i915/display/intel_display_types.h +++ b/drivers/gpu/drm/i915/display/intel_display_types.h @@ -997,7 +997,7 @@ struct intel_casf { struct scaler_filter_coeff coeff[SCALER_FILTER_NUM_TAPS]; u8 strength; u8 win_size; - bool casf_enable; + bool enable; }; struct intel_crtc_state { diff --git a/drivers/gpu/drm/i915/display/skl_scaler.c b/drivers/gpu/drm/i915/display/skl_scaler.c index 7c5cb188ebf0..cfa17ddb4018 100644 --- a/drivers/gpu/drm/i915/display/skl_scaler.c +++ b/drivers/gpu/drm/i915/display/skl_scaler.c @@ -986,13 +986,13 @@ void skl_scaler_get_config(struct intel_crtc_state *crtc_state) if (HAS_CASF(display) && id == 1) intel_casf_sharpness_get_config(crtc_state); - if (!crtc_state->hw.casf_params.casf_enable) + if (!crtc_state->hw.casf_params.enable) crtc_state->pch_pfit.enabled = true; pos = intel_de_read(display, SKL_PS_WIN_POS(crtc->pipe, i)); size = intel_de_read(display, SKL_PS_WIN_SZ(crtc->pipe, i)); - if (!crtc_state->hw.casf_params.casf_enable) + if (!crtc_state->hw.casf_params.enable) drm_rect_init(&crtc_state->pch_pfit.dst, REG_FIELD_GET(PS_WIN_XPOS_MASK, pos), REG_FIELD_GET(PS_WIN_YPOS_MASK, pos), -- cgit v1.2.3 From e68b7710066c032bba47e6a544d4b3920fe4bd8b Mon Sep 17 00:00:00 2001 From: Ville Syrjälä Date: Tue, 7 Apr 2026 20:52:36 +0300 Subject: drm/i915/casf: Make a proper hw state copy of the sharpness_strength MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Make a copy of the uapi.sharpness_strength property value in our hw state. This is how we deal with having proper state for joined pipes. Reviewed-by: Michał Grzelak Reviewed-by: Nemesa Garg Signed-off-by: Ville Syrjälä Link: https://patch.msgid.link/20260407175244.19654-3-ville.syrjala@linux.intel.com --- drivers/gpu/drm/i915/display/intel_casf.c | 4 ++-- drivers/gpu/drm/i915/display/intel_crtc_state_dump.c | 5 +++-- drivers/gpu/drm/i915/display/intel_display.c | 6 ++++++ drivers/gpu/drm/i915/display/intel_display_debugfs.c | 5 +++-- drivers/gpu/drm/i915/display/intel_display_types.h | 1 + drivers/gpu/drm/i915/display/intel_modeset_setup.c | 1 + 6 files changed, 16 insertions(+), 6 deletions(-) diff --git a/drivers/gpu/drm/i915/display/intel_casf.c b/drivers/gpu/drm/i915/display/intel_casf.c index 32e6f7c8acdd..4316d8214e80 100644 --- a/drivers/gpu/drm/i915/display/intel_casf.c +++ b/drivers/gpu/drm/i915/display/intel_casf.c @@ -109,7 +109,7 @@ int intel_casf_compute_config(struct intel_crtc_state *crtc_state) if (!HAS_CASF(display)) return 0; - if (crtc_state->uapi.sharpness_strength == 0) { + if (crtc_state->hw.sharpness_strength == 0) { crtc_state->hw.casf_params.enable = false; crtc_state->hw.casf_params.strength = 0; return 0; @@ -132,7 +132,7 @@ int intel_casf_compute_config(struct intel_crtc_state *crtc_state) * Also 85 + 16 = 101. */ crtc_state->hw.casf_params.strength = - min(crtc_state->uapi.sharpness_strength, 0xEF) + 0x10; + min(crtc_state->hw.sharpness_strength, 0xEF) + 0x10; intel_casf_compute_win_size(crtc_state); diff --git a/drivers/gpu/drm/i915/display/intel_crtc_state_dump.c b/drivers/gpu/drm/i915/display/intel_crtc_state_dump.c index a11a79a0211e..42676adf6062 100644 --- a/drivers/gpu/drm/i915/display/intel_crtc_state_dump.c +++ b/drivers/gpu/drm/i915/display/intel_crtc_state_dump.c @@ -328,11 +328,12 @@ void intel_crtc_state_dump(const struct intel_crtc_state *pipe_config, pipe_config->linetime, pipe_config->ips_linetime); if (DISPLAY_VER(display) >= 9) - drm_printf(&p, "num_scalers: %d, scaler_users: 0x%x, scaler_id: %d, scaling_filter: %d\n", + drm_printf(&p, "num_scalers: %d, scaler_users: 0x%x, scaler_id: %d, scaling_filter: %d, sharpness_strength: %d\n", crtc->num_scalers, pipe_config->scaler_state.scaler_users, pipe_config->scaler_state.scaler_id, - pipe_config->hw.scaling_filter); + pipe_config->hw.scaling_filter, + pipe_config->hw.sharpness_strength); drm_printf(&p, "pipe src: " DRM_RECT_FMT "\n", DRM_RECT_ARG(&pipe_config->pipe_src)); diff --git a/drivers/gpu/drm/i915/display/intel_display.c b/drivers/gpu/drm/i915/display/intel_display.c index 78d97441f682..a02c58b5a34d 100644 --- a/drivers/gpu/drm/i915/display/intel_display.c +++ b/drivers/gpu/drm/i915/display/intel_display.c @@ -4550,6 +4550,7 @@ intel_crtc_copy_uapi_to_hw_state_modeset(struct intel_atomic_state *state, drm_mode_copy(&crtc_state->hw.adjusted_mode, &crtc_state->uapi.adjusted_mode); crtc_state->hw.scaling_filter = crtc_state->uapi.scaling_filter; + crtc_state->hw.sharpness_strength = crtc_state->uapi.sharpness_strength; intel_crtc_copy_uapi_to_hw_state_nomodeset(state, crtc); } @@ -4615,6 +4616,7 @@ copy_joiner_crtc_state_modeset(struct intel_atomic_state *state, drm_mode_copy(&secondary_crtc_state->hw.adjusted_mode, &primary_crtc_state->hw.adjusted_mode); secondary_crtc_state->hw.scaling_filter = primary_crtc_state->hw.scaling_filter; + secondary_crtc_state->hw.sharpness_strength = primary_crtc_state->hw.sharpness_strength; if (primary_crtc_state->dp_tunnel_ref.tunnel) drm_dp_tunnel_ref_get(primary_crtc_state->dp_tunnel_ref.tunnel, @@ -6441,6 +6443,10 @@ int intel_atomic_check(struct drm_device *dev, if (new_crtc_state->uapi.scaling_filter != old_crtc_state->uapi.scaling_filter) new_crtc_state->uapi.mode_changed = true; + + if (new_crtc_state->uapi.sharpness_strength != + old_crtc_state->uapi.sharpness_strength) + new_crtc_state->uapi.mode_changed = true; } intel_vrr_check_modeset(state); diff --git a/drivers/gpu/drm/i915/display/intel_display_debugfs.c b/drivers/gpu/drm/i915/display/intel_display_debugfs.c index 2614c4863c87..f244a2b5d139 100644 --- a/drivers/gpu/drm/i915/display/intel_display_debugfs.c +++ b/drivers/gpu/drm/i915/display/intel_display_debugfs.c @@ -416,11 +416,12 @@ static void intel_scaler_info(struct seq_file *m, struct intel_crtc *crtc) /* Not all platforms have a scaler */ if (num_scalers) { - seq_printf(m, "\tnum_scalers=%d, scaler_users=%x scaler_id=%d scaling_filter=%d", + seq_printf(m, "\tnum_scalers=%d, scaler_users=%x scaler_id=%d scaling_filter=%d sharpness_strength=%d", num_scalers, crtc_state->scaler_state.scaler_users, crtc_state->scaler_state.scaler_id, - crtc_state->hw.scaling_filter); + crtc_state->hw.scaling_filter, + crtc_state->hw.sharpness_strength); for (i = 0; i < num_scalers; i++) { const struct intel_scaler *sc = diff --git a/drivers/gpu/drm/i915/display/intel_display_types.h b/drivers/gpu/drm/i915/display/intel_display_types.h index 83bb5d19b6f6..af0d870de342 100644 --- a/drivers/gpu/drm/i915/display/intel_display_types.h +++ b/drivers/gpu/drm/i915/display/intel_display_types.h @@ -1036,6 +1036,7 @@ struct intel_crtc_state { struct drm_property_blob *degamma_lut, *gamma_lut, *ctm; struct drm_display_mode mode, pipe_mode, adjusted_mode; enum drm_scaling_filter scaling_filter; + u8 sharpness_strength; struct intel_casf casf_params; } hw; diff --git a/drivers/gpu/drm/i915/display/intel_modeset_setup.c b/drivers/gpu/drm/i915/display/intel_modeset_setup.c index 4086f16a12bf..40a65a0d7ec7 100644 --- a/drivers/gpu/drm/i915/display/intel_modeset_setup.c +++ b/drivers/gpu/drm/i915/display/intel_modeset_setup.c @@ -333,6 +333,7 @@ static void intel_crtc_copy_hw_to_uapi_state(struct intel_crtc_state *crtc_state crtc_state->uapi.adjusted_mode = crtc_state->hw.adjusted_mode; crtc_state->uapi.scaling_filter = crtc_state->hw.scaling_filter; + crtc_state->uapi.sharpness_strength = crtc_state->hw.sharpness_strength; if (DISPLAY_INFO(display)->color.degamma_lut_size) { /* assume 1:1 mapping */ -- cgit v1.2.3 From 3790c44364cd995481136cdbb2457fd9ae0127dc Mon Sep 17 00:00:00 2001 From: Ville Syrjälä Date: Tue, 7 Apr 2026 20:52:37 +0300 Subject: drm/i915/casf: Move the casf state to better place MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The casf state is placed inside the 'hw' state for some reason. That is only really meant for things we have to duplicate from the uapi state. The rest can live on its own in our actual state. And since casf is just one aspect of the pfit/pipe scaler the proper place for it seems to be under pch_pfit. Reviewed-by: Michał Grzelak Reviewed-by: Nemesa Garg Signed-off-by: Ville Syrjälä Link: https://patch.msgid.link/20260407175244.19654-4-ville.syrjala@linux.intel.com --- drivers/gpu/drm/i915/display/intel_casf.c | 40 +++++++++++----------- .../gpu/drm/i915/display/intel_crtc_state_dump.c | 6 ++-- drivers/gpu/drm/i915/display/intel_display.c | 12 +++---- drivers/gpu/drm/i915/display/intel_display_types.h | 2 +- drivers/gpu/drm/i915/display/skl_scaler.c | 4 +-- 5 files changed, 32 insertions(+), 32 deletions(-) diff --git a/drivers/gpu/drm/i915/display/intel_casf.c b/drivers/gpu/drm/i915/display/intel_casf.c index 4316d8214e80..5a8ffb40d30d 100644 --- a/drivers/gpu/drm/i915/display/intel_casf.c +++ b/drivers/gpu/drm/i915/display/intel_casf.c @@ -82,7 +82,7 @@ void intel_casf_update_strength(struct intel_crtc_state *crtc_state) int win_size; intel_de_rmw(display, SHARPNESS_CTL(crtc->pipe), FILTER_STRENGTH_MASK, - FILTER_STRENGTH(crtc_state->hw.casf_params.strength)); + FILTER_STRENGTH(crtc_state->pch_pfit.casf.strength)); win_size = intel_de_read(display, SKL_PS_WIN_SZ(crtc->pipe, 1)); @@ -95,11 +95,11 @@ static void intel_casf_compute_win_size(struct intel_crtc_state *crtc_state) u32 total_pixels = mode->hdisplay * mode->vdisplay; if (total_pixels <= MAX_PIXELS_FOR_3_TAP_FILTER) - crtc_state->hw.casf_params.win_size = SHARPNESS_FILTER_SIZE_3X3; + crtc_state->pch_pfit.casf.win_size = SHARPNESS_FILTER_SIZE_3X3; else if (total_pixels <= MAX_PIXELS_FOR_5_TAP_FILTER) - crtc_state->hw.casf_params.win_size = SHARPNESS_FILTER_SIZE_5X5; + crtc_state->pch_pfit.casf.win_size = SHARPNESS_FILTER_SIZE_5X5; else - crtc_state->hw.casf_params.win_size = SHARPNESS_FILTER_SIZE_7X7; + crtc_state->pch_pfit.casf.win_size = SHARPNESS_FILTER_SIZE_7X7; } int intel_casf_compute_config(struct intel_crtc_state *crtc_state) @@ -110,8 +110,8 @@ int intel_casf_compute_config(struct intel_crtc_state *crtc_state) return 0; if (crtc_state->hw.sharpness_strength == 0) { - crtc_state->hw.casf_params.enable = false; - crtc_state->hw.casf_params.strength = 0; + crtc_state->pch_pfit.casf.enable = false; + crtc_state->pch_pfit.casf.strength = 0; return 0; } @@ -121,7 +121,7 @@ int intel_casf_compute_config(struct intel_crtc_state *crtc_state) return -EINVAL; } - crtc_state->hw.casf_params.enable = true; + crtc_state->pch_pfit.casf.enable = true; /* * HW takes a value in form (1.0 + strength) in 4.4 fixed format. @@ -131,7 +131,7 @@ int intel_casf_compute_config(struct intel_crtc_state *crtc_state) * 6.3125 in 4.4 format is b01100101 which is equal to 101. * Also 85 + 16 = 101. */ - crtc_state->hw.casf_params.strength = + crtc_state->pch_pfit.casf.strength = min(crtc_state->hw.sharpness_strength, 0xEF) + 0x10; intel_casf_compute_win_size(crtc_state); @@ -151,19 +151,19 @@ void intel_casf_sharpness_get_config(struct intel_crtc_state *crtc_state) if (sharp & FILTER_EN) { if (drm_WARN_ON(display->drm, REG_FIELD_GET(FILTER_STRENGTH_MASK, sharp) < 16)) - crtc_state->hw.casf_params.strength = 0; + crtc_state->pch_pfit.casf.strength = 0; else - crtc_state->hw.casf_params.strength = + crtc_state->pch_pfit.casf.strength = REG_FIELD_GET(FILTER_STRENGTH_MASK, sharp); - crtc_state->hw.casf_params.enable = true; - crtc_state->hw.casf_params.win_size = + crtc_state->pch_pfit.casf.enable = true; + crtc_state->pch_pfit.casf.win_size = REG_FIELD_GET(FILTER_SIZE_MASK, sharp); } } bool intel_casf_needs_scaler(const struct intel_crtc_state *crtc_state) { - if (crtc_state->hw.casf_params.enable) + if (crtc_state->pch_pfit.casf.enable) return true; return false; @@ -179,7 +179,7 @@ static u32 casf_coeff(struct intel_crtc_state *crtc_state, int t) struct scaler_filter_coeff value; u32 coeff; - value = crtc_state->hw.casf_params.coeff[t]; + value = crtc_state->pch_pfit.casf.coeff[t]; value.sign = 0; coeff = value.sign << 15 | value.exp << 12 | value.mantissa << 3; @@ -189,7 +189,7 @@ static u32 casf_coeff(struct intel_crtc_state *crtc_state, int t) /* * 17 phase of 7 taps requires 119 coefficients in 60 dwords per set. * To enable casf: program scaler coefficients with the coeffients - * that are calculated and stored in hw.casf_params.coeff as per + * that are calculated and stored in pch_pfit.casf.coeff as per * SCALER_COEFFICIENT_FORMAT */ static void intel_casf_write_coeff(struct intel_crtc_state *crtc_state) @@ -247,9 +247,9 @@ void intel_casf_scaler_compute_config(struct intel_crtc_state *crtc_state) u16 sumcoeff = 0; int i; - if (crtc_state->hw.casf_params.win_size == 0) + if (crtc_state->pch_pfit.casf.win_size == 0) filtercoeff = filtercoeff_1; - else if (crtc_state->hw.casf_params.win_size == 1) + else if (crtc_state->pch_pfit.casf.win_size == 1) filtercoeff = filtercoeff_2; else filtercoeff = filtercoeff_3; @@ -259,7 +259,7 @@ void intel_casf_scaler_compute_config(struct intel_crtc_state *crtc_state) for (i = 0; i < SCALER_FILTER_NUM_TAPS; i++) { filter_coeff[i] = (*(filtercoeff + i) * 100 / sumcoeff); - convert_sharpness_coef_binary(&crtc_state->hw.casf_params.coeff[i], + convert_sharpness_coef_binary(&crtc_state->pch_pfit.casf.coeff[i], filter_coeff[i]); } } @@ -274,9 +274,9 @@ void intel_casf_enable(struct intel_crtc_state *crtc_state) intel_casf_write_coeff(crtc_state); - sharpness_ctl = FILTER_EN | FILTER_STRENGTH(crtc_state->hw.casf_params.strength); + sharpness_ctl = FILTER_EN | FILTER_STRENGTH(crtc_state->pch_pfit.casf.strength); - sharpness_ctl |= crtc_state->hw.casf_params.win_size; + sharpness_ctl |= crtc_state->pch_pfit.casf.win_size; intel_de_write(display, SHARPNESS_CTL(crtc->pipe), sharpness_ctl); diff --git a/drivers/gpu/drm/i915/display/intel_crtc_state_dump.c b/drivers/gpu/drm/i915/display/intel_crtc_state_dump.c index 42676adf6062..4493483f10a9 100644 --- a/drivers/gpu/drm/i915/display/intel_crtc_state_dump.c +++ b/drivers/gpu/drm/i915/display/intel_crtc_state_dump.c @@ -350,9 +350,9 @@ void intel_crtc_state_dump(const struct intel_crtc_state *pipe_config, str_yes_no(pipe_config->pch_pfit.force_thru)); drm_printf(&p, "sharpness strength: %d, sharpness tap size: %d, sharpness enable: %d\n", - pipe_config->hw.casf_params.strength, - pipe_config->hw.casf_params.win_size, - pipe_config->hw.casf_params.enable); + pipe_config->pch_pfit.casf.strength, + pipe_config->pch_pfit.casf.win_size, + pipe_config->pch_pfit.casf.enable); drm_printf(&p, "ips: %i, double wide: %i, drrs: %i\n", pipe_config->ips_enabled, pipe_config->double_wide, diff --git a/drivers/gpu/drm/i915/display/intel_display.c b/drivers/gpu/drm/i915/display/intel_display.c index a02c58b5a34d..e02e69467871 100644 --- a/drivers/gpu/drm/i915/display/intel_display.c +++ b/drivers/gpu/drm/i915/display/intel_display.c @@ -994,7 +994,7 @@ static bool intel_casf_enabling(const struct intel_crtc_state *new_crtc_state, if (!new_crtc_state->hw.active) return false; - return is_enabling(hw.casf_params.enable, old_crtc_state, new_crtc_state); + return is_enabling(pch_pfit.casf.enable, old_crtc_state, new_crtc_state); } static bool intel_casf_disabling(const struct intel_crtc_state *old_crtc_state, @@ -1003,7 +1003,7 @@ static bool intel_casf_disabling(const struct intel_crtc_state *old_crtc_state, if (!new_crtc_state->hw.active) return false; - return is_disabling(hw.casf_params.enable, old_crtc_state, new_crtc_state); + return is_disabling(pch_pfit.casf.enable, old_crtc_state, new_crtc_state); } static bool intel_crtc_lobf_enabling(const struct intel_crtc_state *old_crtc_state, @@ -5370,12 +5370,12 @@ intel_pipe_config_compare(const struct intel_crtc_state *current_config, PIPE_CONF_CHECK_BOOL(pch_pfit.enabled); PIPE_CONF_CHECK_RECT(pch_pfit.dst); + PIPE_CONF_CHECK_BOOL(pch_pfit.casf.enable); + PIPE_CONF_CHECK_I(pch_pfit.casf.win_size); + PIPE_CONF_CHECK_I(pch_pfit.casf.strength); PIPE_CONF_CHECK_I(scaler_state.scaler_id); PIPE_CONF_CHECK_I(pixel_rate); - PIPE_CONF_CHECK_BOOL(hw.casf_params.enable); - PIPE_CONF_CHECK_I(hw.casf_params.win_size); - PIPE_CONF_CHECK_I(hw.casf_params.strength); PIPE_CONF_CHECK_X(gamma_mode); if (display->platform.cherryview) @@ -6819,7 +6819,7 @@ static void intel_pre_update_crtc(struct intel_atomic_state *state, if (intel_casf_enabling(new_crtc_state, old_crtc_state)) intel_casf_enable(new_crtc_state); - else if (new_crtc_state->hw.casf_params.strength != old_crtc_state->hw.casf_params.strength) + else if (new_crtc_state->pch_pfit.casf.strength != old_crtc_state->pch_pfit.casf.strength) intel_casf_update_strength(new_crtc_state); intel_fbc_update(state, crtc); diff --git a/drivers/gpu/drm/i915/display/intel_display_types.h b/drivers/gpu/drm/i915/display/intel_display_types.h index af0d870de342..ca2581fb7bbd 100644 --- a/drivers/gpu/drm/i915/display/intel_display_types.h +++ b/drivers/gpu/drm/i915/display/intel_display_types.h @@ -1037,7 +1037,6 @@ struct intel_crtc_state { struct drm_display_mode mode, pipe_mode, adjusted_mode; enum drm_scaling_filter scaling_filter; u8 sharpness_strength; - struct intel_casf casf_params; } hw; /* actual state of LUTs */ @@ -1224,6 +1223,7 @@ struct intel_crtc_state { /* Panel fitter placement and size for Ironlake+ */ struct { + struct intel_casf casf; struct drm_rect dst; bool enabled; bool force_thru; diff --git a/drivers/gpu/drm/i915/display/skl_scaler.c b/drivers/gpu/drm/i915/display/skl_scaler.c index cfa17ddb4018..e9fe5c0bf6ff 100644 --- a/drivers/gpu/drm/i915/display/skl_scaler.c +++ b/drivers/gpu/drm/i915/display/skl_scaler.c @@ -986,13 +986,13 @@ void skl_scaler_get_config(struct intel_crtc_state *crtc_state) if (HAS_CASF(display) && id == 1) intel_casf_sharpness_get_config(crtc_state); - if (!crtc_state->hw.casf_params.enable) + if (!crtc_state->pch_pfit.casf.enable) crtc_state->pch_pfit.enabled = true; pos = intel_de_read(display, SKL_PS_WIN_POS(crtc->pipe, i)); size = intel_de_read(display, SKL_PS_WIN_SZ(crtc->pipe, i)); - if (!crtc_state->hw.casf_params.enable) + if (!crtc_state->pch_pfit.casf.enable) drm_rect_init(&crtc_state->pch_pfit.dst, REG_FIELD_GET(PS_WIN_XPOS_MASK, pos), REG_FIELD_GET(PS_WIN_YPOS_MASK, pos), -- cgit v1.2.3 From 17d70a0760f2baa739f84d2c0933e0e0876f541c Mon Sep 17 00:00:00 2001 From: Ville Syrjälä Date: Tue, 7 Apr 2026 20:52:38 +0300 Subject: drm/i915/casf: Extract scaler_has_casf() MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Extract a small helper to determine if the scaler supports the sharpness filter or not. Reviewed-by: Michał Grzelak Reviewed-by: Nemesa Garg Signed-off-by: Ville Syrjälä Link: https://patch.msgid.link/20260407175244.19654-5-ville.syrjala@linux.intel.com --- drivers/gpu/drm/i915/display/skl_scaler.c | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/drivers/gpu/drm/i915/display/skl_scaler.c b/drivers/gpu/drm/i915/display/skl_scaler.c index e9fe5c0bf6ff..525afd736195 100644 --- a/drivers/gpu/drm/i915/display/skl_scaler.c +++ b/drivers/gpu/drm/i915/display/skl_scaler.c @@ -323,19 +323,24 @@ int skl_update_scaler_plane(struct intel_crtc_state *crtc_state, need_scaler); } +static bool scaler_has_casf(struct intel_display *display, int scaler_id) +{ + return HAS_CASF(display) && scaler_id == 1; +} + static int intel_allocate_scaler(struct intel_crtc_scaler_state *scaler_state, struct intel_crtc *crtc, struct intel_plane_state *plane_state, bool casf_scaler) { + struct intel_display *display = to_intel_display(crtc); int i; for (i = 0; i < crtc->num_scalers; i++) { if (scaler_state->scalers[i].in_use) continue; - /* CASF needs second scaler */ - if (!plane_state && casf_scaler && i != 1) + if (casf_scaler && !scaler_has_casf(display, i)) continue; scaler_state->scalers[i].in_use = true; @@ -982,8 +987,7 @@ void skl_scaler_get_config(struct intel_crtc_state *crtc_state) id = i; - /* Read CASF regs for second scaler */ - if (HAS_CASF(display) && id == 1) + if (scaler_has_casf(display, i)) intel_casf_sharpness_get_config(crtc_state); if (!crtc_state->pch_pfit.casf.enable) -- cgit v1.2.3 From 7583232af13e1a0b0a44cc7c0af9db56a7de30e6 Mon Sep 17 00:00:00 2001 From: Ville Syrjälä Date: Tue, 7 Apr 2026 20:52:39 +0300 Subject: drm/i915/casf: Handle CASF in skl_scaler_get_filter_select() MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Nuke the duplicate CASF_SCALER_FILTER_SELECT and just have skl_scaler_get_filter_select() return the proper value for sharpness filter use. It is the same "use programmable coefficients" value we already use for the nearest neighbor filtering. Reviewed-by: Michał Grzelak Reviewed-by: Nemesa Garg Signed-off-by: Ville Syrjälä Link: https://patch.msgid.link/20260407175244.19654-6-ville.syrjala@linux.intel.com --- drivers/gpu/drm/i915/display/skl_scaler.c | 17 +++++------------ 1 file changed, 5 insertions(+), 12 deletions(-) diff --git a/drivers/gpu/drm/i915/display/skl_scaler.c b/drivers/gpu/drm/i915/display/skl_scaler.c index 525afd736195..d8bf65c6b4a7 100644 --- a/drivers/gpu/drm/i915/display/skl_scaler.c +++ b/drivers/gpu/drm/i915/display/skl_scaler.c @@ -730,9 +730,9 @@ static void glk_program_nearest_filter_coefs(struct intel_display *display, GLK_PS_COEF_INDEX_SET(pipe, id, set), 0); } -static u32 skl_scaler_get_filter_select(enum drm_scaling_filter filter) +static u32 skl_scaler_get_filter_select(enum drm_scaling_filter filter, bool casf) { - if (filter == DRM_SCALING_FILTER_NEAREST_NEIGHBOR) + if (filter == DRM_SCALING_FILTER_NEAREST_NEIGHBOR || casf) return (PS_FILTER_PROGRAMMED | PS_Y_VERT_FILTER_SELECT(0) | PS_Y_HORZ_FILTER_SELECT(0) | @@ -757,13 +757,6 @@ static void skl_scaler_setup_filter(struct intel_display *display, } } -#define CASF_SCALER_FILTER_SELECT \ - (PS_FILTER_PROGRAMMED | \ - PS_Y_VERT_FILTER_SELECT(0) | \ - PS_Y_HORZ_FILTER_SELECT(0) | \ - PS_UV_VERT_FILTER_SELECT(0) | \ - PS_UV_HORZ_FILTER_SELECT(0)) - void skl_scaler_setup_casf(struct intel_crtc_state *crtc_state) { struct intel_crtc *crtc = to_intel_crtc(crtc_state->uapi.crtc); @@ -794,7 +787,7 @@ void skl_scaler_setup_casf(struct intel_crtc_state *crtc_state) trace_intel_pipe_scaler_update_arm(crtc, id, x, y, width, height); ps_ctrl = PS_SCALER_EN | PS_BINDING_PIPE | scaler_state->scalers[id].mode | - CASF_SCALER_FILTER_SELECT; + skl_scaler_get_filter_select(crtc_state->hw.scaling_filter, true); intel_de_write_fw(display, SKL_PS_CTRL(pipe, id), ps_ctrl); intel_de_write_fw(display, SKL_PS_WIN_POS(pipe, id), @@ -844,7 +837,7 @@ void skl_pfit_enable(const struct intel_crtc_state *crtc_state) id = scaler_state->scaler_id; ps_ctrl = PS_SCALER_EN | PS_BINDING_PIPE | scaler_state->scalers[id].mode | - skl_scaler_get_filter_select(crtc_state->hw.scaling_filter); + skl_scaler_get_filter_select(crtc_state->hw.scaling_filter, false); trace_intel_pipe_scaler_update_arm(crtc, id, x, y, width, height); @@ -910,7 +903,7 @@ skl_program_plane_scaler(struct intel_dsb *dsb, } ps_ctrl = PS_SCALER_EN | PS_BINDING_PLANE(plane->id) | scaler->mode | - skl_scaler_get_filter_select(plane_state->hw.scaling_filter); + skl_scaler_get_filter_select(plane_state->hw.scaling_filter, false); trace_intel_plane_scaler_update_arm(plane, scaler_id, crtc_x, crtc_y, crtc_w, crtc_h); -- cgit v1.2.3 From 114a836384b9786df3cbe815fccf9cf1a72761b6 Mon Sep 17 00:00:00 2001 From: Ville Syrjälä Date: Tue, 7 Apr 2026 20:52:40 +0300 Subject: drm/i915/casf: Constify crtc_state MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Make the crtc_state const everywhere in the sharpness filter code where it doesn't need to be mutated. Reviewed-by: Michał Grzelak Reviewed-by: Nemesa Garg Signed-off-by: Ville Syrjälä Link: https://patch.msgid.link/20260407175244.19654-7-ville.syrjala@linux.intel.com --- drivers/gpu/drm/i915/display/intel_casf.c | 8 ++++---- drivers/gpu/drm/i915/display/intel_casf.h | 4 ++-- drivers/gpu/drm/i915/display/skl_scaler.c | 8 ++++---- drivers/gpu/drm/i915/display/skl_scaler.h | 2 +- 4 files changed, 11 insertions(+), 11 deletions(-) diff --git a/drivers/gpu/drm/i915/display/intel_casf.c b/drivers/gpu/drm/i915/display/intel_casf.c index 5a8ffb40d30d..f777aae3fc57 100644 --- a/drivers/gpu/drm/i915/display/intel_casf.c +++ b/drivers/gpu/drm/i915/display/intel_casf.c @@ -75,7 +75,7 @@ static void intel_casf_filter_lut_load(struct intel_crtc *crtc, sharpness_lut[i]); } -void intel_casf_update_strength(struct intel_crtc_state *crtc_state) +void intel_casf_update_strength(const struct intel_crtc_state *crtc_state) { struct intel_display *display = to_intel_display(crtc_state); struct intel_crtc *crtc = to_intel_crtc(crtc_state->uapi.crtc); @@ -174,7 +174,7 @@ static int casf_coeff_tap(int i) return i % SCALER_FILTER_NUM_TAPS; } -static u32 casf_coeff(struct intel_crtc_state *crtc_state, int t) +static u32 casf_coeff(const struct intel_crtc_state *crtc_state, int t) { struct scaler_filter_coeff value; u32 coeff; @@ -192,7 +192,7 @@ static u32 casf_coeff(struct intel_crtc_state *crtc_state, int t) * that are calculated and stored in pch_pfit.casf.coeff as per * SCALER_COEFFICIENT_FORMAT */ -static void intel_casf_write_coeff(struct intel_crtc_state *crtc_state) +static void intel_casf_write_coeff(const struct intel_crtc_state *crtc_state) { struct intel_display *display = to_intel_display(crtc_state); struct intel_crtc *crtc = to_intel_crtc(crtc_state->uapi.crtc); @@ -264,7 +264,7 @@ void intel_casf_scaler_compute_config(struct intel_crtc_state *crtc_state) } } -void intel_casf_enable(struct intel_crtc_state *crtc_state) +void intel_casf_enable(const struct intel_crtc_state *crtc_state) { struct intel_display *display = to_intel_display(crtc_state); struct intel_crtc *crtc = to_intel_crtc(crtc_state->uapi.crtc); diff --git a/drivers/gpu/drm/i915/display/intel_casf.h b/drivers/gpu/drm/i915/display/intel_casf.h index b3fb0bcb3f5b..c4f984b73348 100644 --- a/drivers/gpu/drm/i915/display/intel_casf.h +++ b/drivers/gpu/drm/i915/display/intel_casf.h @@ -11,9 +11,9 @@ struct intel_crtc_state; int intel_casf_compute_config(struct intel_crtc_state *crtc_state); -void intel_casf_update_strength(struct intel_crtc_state *new_crtc_state); +void intel_casf_update_strength(const struct intel_crtc_state *new_crtc_state); void intel_casf_sharpness_get_config(struct intel_crtc_state *crtc_state); -void intel_casf_enable(struct intel_crtc_state *crtc_state); +void intel_casf_enable(const struct intel_crtc_state *crtc_state); void intel_casf_disable(const struct intel_crtc_state *crtc_state); void intel_casf_scaler_compute_config(struct intel_crtc_state *crtc_state); bool intel_casf_needs_scaler(const struct intel_crtc_state *crtc_state); diff --git a/drivers/gpu/drm/i915/display/skl_scaler.c b/drivers/gpu/drm/i915/display/skl_scaler.c index d8bf65c6b4a7..762f4bb46c2d 100644 --- a/drivers/gpu/drm/i915/display/skl_scaler.c +++ b/drivers/gpu/drm/i915/display/skl_scaler.c @@ -757,13 +757,13 @@ static void skl_scaler_setup_filter(struct intel_display *display, } } -void skl_scaler_setup_casf(struct intel_crtc_state *crtc_state) +void skl_scaler_setup_casf(const struct intel_crtc_state *crtc_state) { struct intel_crtc *crtc = to_intel_crtc(crtc_state->uapi.crtc); struct intel_display *display = to_intel_display(crtc); - struct drm_display_mode *adjusted_mode = - &crtc_state->hw.adjusted_mode; - struct intel_crtc_scaler_state *scaler_state = + const struct drm_display_mode *adjusted_mode = + &crtc_state->hw.adjusted_mode; + const struct intel_crtc_scaler_state *scaler_state = &crtc_state->scaler_state; struct drm_rect src, dest; int id, width, height; diff --git a/drivers/gpu/drm/i915/display/skl_scaler.h b/drivers/gpu/drm/i915/display/skl_scaler.h index 7e8d819c019d..20ecf373eb19 100644 --- a/drivers/gpu/drm/i915/display/skl_scaler.h +++ b/drivers/gpu/drm/i915/display/skl_scaler.h @@ -36,7 +36,7 @@ void skl_scaler_disable(const struct intel_crtc_state *old_crtc_state); void skl_scaler_get_config(struct intel_crtc_state *crtc_state); -void skl_scaler_setup_casf(struct intel_crtc_state *crtc_state); +void skl_scaler_setup_casf(const struct intel_crtc_state *crtc_state); enum drm_mode_status skl_scaler_mode_valid(struct intel_display *display, -- cgit v1.2.3 From 9a459db0ae1d742c9183b9a092d060f29b979964 Mon Sep 17 00:00:00 2001 From: Ville Syrjälä Date: Tue, 7 Apr 2026 20:52:41 +0300 Subject: drm/i915/casf: Remove redundant argument from intel_casf_filter_lut_load() MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit intel_casf_filter_lut_load() can find the crtc from the crtc_state. No need to pass in both. Reviewed-by: Michał Grzelak Reviewed-by: Nemesa Garg Signed-off-by: Ville Syrjälä Link: https://patch.msgid.link/20260407175244.19654-8-ville.syrjala@linux.intel.com --- drivers/gpu/drm/i915/display/intel_casf.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/drivers/gpu/drm/i915/display/intel_casf.c b/drivers/gpu/drm/i915/display/intel_casf.c index f777aae3fc57..21e84a4f9ff5 100644 --- a/drivers/gpu/drm/i915/display/intel_casf.c +++ b/drivers/gpu/drm/i915/display/intel_casf.c @@ -61,10 +61,10 @@ const u16 filtercoeff_3[] = { FILTER_COEFF_0_125, }; -static void intel_casf_filter_lut_load(struct intel_crtc *crtc, - const struct intel_crtc_state *crtc_state) +static void intel_casf_filter_lut_load(const struct intel_crtc_state *crtc_state) { struct intel_display *display = to_intel_display(crtc_state); + struct intel_crtc *crtc = to_intel_crtc(crtc_state->uapi.crtc); int i; intel_de_write(display, SHRPLUT_INDEX(crtc->pipe), @@ -270,7 +270,7 @@ void intel_casf_enable(const struct intel_crtc_state *crtc_state) struct intel_crtc *crtc = to_intel_crtc(crtc_state->uapi.crtc); u32 sharpness_ctl; - intel_casf_filter_lut_load(crtc, crtc_state); + intel_casf_filter_lut_load(crtc_state); intel_casf_write_coeff(crtc_state); -- cgit v1.2.3 From d4686f34bbebabeee3130678f01a17bd7cd58e64 Mon Sep 17 00:00:00 2001 From: Ville Syrjälä Date: Tue, 7 Apr 2026 20:52:42 +0300 Subject: drm/i915/pfit: Call intel_pfit_compute_config() unconditionally on (e)DP/HDMI MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit We now have three different reasons for calling intel_pfit_compute_config(): - actual pfit scaling/centering - YCbCr 4:2:0 output - sharpness filter So let's just call intel_pfit_compute_config() unconditionally from both the DP and HDMI code. Both gmch and ilk+ pfit code should be capable of judging whether anything actually needs the pfit. The only slightly questionable thing in the gmch code is the dithering knob, but that's only a thing on gen2/3 which don't even have HDMI/DP outputs, and so not an issue here. Reviewed-by: Michał Grzelak Reviewed-by: Nemesa Garg Signed-off-by: Ville Syrjälä Link: https://patch.msgid.link/20260407175244.19654-9-ville.syrjala@linux.intel.com --- drivers/gpu/drm/i915/display/intel_dp.c | 9 +++------ drivers/gpu/drm/i915/display/intel_hdmi.c | 8 +++----- 2 files changed, 6 insertions(+), 11 deletions(-) diff --git a/drivers/gpu/drm/i915/display/intel_dp.c b/drivers/gpu/drm/i915/display/intel_dp.c index 4955bd8b11d7..ff3904b77492 100644 --- a/drivers/gpu/drm/i915/display/intel_dp.c +++ b/drivers/gpu/drm/i915/display/intel_dp.c @@ -3545,12 +3545,9 @@ intel_dp_compute_config(struct intel_encoder *encoder, if (ret) return ret; - if ((intel_dp_is_edp(intel_dp) && fixed_mode) || - pipe_config->output_format == INTEL_OUTPUT_FORMAT_YCBCR420) { - ret = intel_pfit_compute_config(pipe_config, conn_state); - if (ret) - return ret; - } + ret = intel_pfit_compute_config(pipe_config, conn_state); + if (ret) + return ret; pipe_config->limited_color_range = intel_dp_limited_color_range(pipe_config, conn_state); diff --git a/drivers/gpu/drm/i915/display/intel_hdmi.c b/drivers/gpu/drm/i915/display/intel_hdmi.c index 05e898d10a2b..17bd2c207453 100644 --- a/drivers/gpu/drm/i915/display/intel_hdmi.c +++ b/drivers/gpu/drm/i915/display/intel_hdmi.c @@ -2380,11 +2380,9 @@ int intel_hdmi_compute_config(struct intel_encoder *encoder, return ret; } - if (intel_hdmi_is_ycbcr420(pipe_config)) { - ret = intel_pfit_compute_config(pipe_config, conn_state); - if (ret) - return ret; - } + ret = intel_pfit_compute_config(pipe_config, conn_state); + if (ret) + return ret; pipe_config->limited_color_range = intel_hdmi_limited_color_range(pipe_config, conn_state); -- cgit v1.2.3 From 5400b7eb666968f77e79f42531c5a138394f2f3f Mon Sep 17 00:00:00 2001 From: Ville Syrjälä Date: Tue, 7 Apr 2026 20:52:43 +0300 Subject: drm/i915/casf: Integrate the sharpness filter properly into the scaler code MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The sharpness filter is just a special mode of the pipe scaler. It doesn't warrant all this special casing everywhere. Just integrate it properly into the scaler code so that it's treated no different from the other pipe scaler uses (scaling,centering, YCbCr 4:2:0 output). v2: Also reject scaling_filter vs. sharpness Reviewed-by: Nemesa Garg Signed-off-by: Ville Syrjälä Link: https://patch.msgid.link/20260407175244.19654-10-ville.syrjala@linux.intel.com --- drivers/gpu/drm/i915/display/intel_casf.c | 62 ++------------------ drivers/gpu/drm/i915/display/intel_casf.h | 6 +- drivers/gpu/drm/i915/display/intel_display.c | 34 +---------- drivers/gpu/drm/i915/display/intel_pfit.c | 13 ++++- drivers/gpu/drm/i915/display/skl_scaler.c | 85 +++++++++++----------------- drivers/gpu/drm/i915/display/skl_scaler.h | 2 - 6 files changed, 53 insertions(+), 149 deletions(-) diff --git a/drivers/gpu/drm/i915/display/intel_casf.c b/drivers/gpu/drm/i915/display/intel_casf.c index 21e84a4f9ff5..c2d2746c5f04 100644 --- a/drivers/gpu/drm/i915/display/intel_casf.c +++ b/drivers/gpu/drm/i915/display/intel_casf.c @@ -75,20 +75,6 @@ static void intel_casf_filter_lut_load(const struct intel_crtc_state *crtc_state sharpness_lut[i]); } -void intel_casf_update_strength(const struct intel_crtc_state *crtc_state) -{ - struct intel_display *display = to_intel_display(crtc_state); - struct intel_crtc *crtc = to_intel_crtc(crtc_state->uapi.crtc); - int win_size; - - intel_de_rmw(display, SHARPNESS_CTL(crtc->pipe), FILTER_STRENGTH_MASK, - FILTER_STRENGTH(crtc_state->pch_pfit.casf.strength)); - - win_size = intel_de_read(display, SKL_PS_WIN_SZ(crtc->pipe, 1)); - - intel_de_write_fw(display, SKL_PS_WIN_SZ(crtc->pipe, 1), win_size); -} - static void intel_casf_compute_win_size(struct intel_crtc_state *crtc_state) { const struct drm_display_mode *mode = &crtc_state->hw.adjusted_mode; @@ -102,18 +88,14 @@ static void intel_casf_compute_win_size(struct intel_crtc_state *crtc_state) crtc_state->pch_pfit.casf.win_size = SHARPNESS_FILTER_SIZE_7X7; } +static void intel_casf_scaler_compute_coef(struct intel_crtc_state *crtc_state); + int intel_casf_compute_config(struct intel_crtc_state *crtc_state) { struct intel_display *display = to_intel_display(crtc_state); - if (!HAS_CASF(display)) - return 0; - - if (crtc_state->hw.sharpness_strength == 0) { - crtc_state->pch_pfit.casf.enable = false; - crtc_state->pch_pfit.casf.strength = 0; + if (crtc_state->hw.sharpness_strength == 0) return 0; - } /* CASF with joiner not supported in hardware */ if (crtc_state->joiner_pipes) { @@ -136,7 +118,7 @@ int intel_casf_compute_config(struct intel_crtc_state *crtc_state) intel_casf_compute_win_size(crtc_state); - intel_casf_scaler_compute_config(crtc_state); + intel_casf_scaler_compute_coef(crtc_state); return 0; } @@ -161,14 +143,6 @@ void intel_casf_sharpness_get_config(struct intel_crtc_state *crtc_state) } } -bool intel_casf_needs_scaler(const struct intel_crtc_state *crtc_state) -{ - if (crtc_state->pch_pfit.casf.enable) - return true; - - return false; -} - static int casf_coeff_tap(int i) { return i % SCALER_FILTER_NUM_TAPS; @@ -240,7 +214,7 @@ static void convert_sharpness_coef_binary(struct scaler_filter_coeff *coeff, } } -void intel_casf_scaler_compute_config(struct intel_crtc_state *crtc_state) +static void intel_casf_scaler_compute_coef(struct intel_crtc_state *crtc_state) { const u16 *filtercoeff; u16 filter_coeff[SCALER_FILTER_NUM_TAPS]; @@ -264,32 +238,8 @@ void intel_casf_scaler_compute_config(struct intel_crtc_state *crtc_state) } } -void intel_casf_enable(const struct intel_crtc_state *crtc_state) +void intel_casf_setup(const struct intel_crtc_state *crtc_state) { - struct intel_display *display = to_intel_display(crtc_state); - struct intel_crtc *crtc = to_intel_crtc(crtc_state->uapi.crtc); - u32 sharpness_ctl; - intel_casf_filter_lut_load(crtc_state); - intel_casf_write_coeff(crtc_state); - - sharpness_ctl = FILTER_EN | FILTER_STRENGTH(crtc_state->pch_pfit.casf.strength); - - sharpness_ctl |= crtc_state->pch_pfit.casf.win_size; - - intel_de_write(display, SHARPNESS_CTL(crtc->pipe), sharpness_ctl); - - skl_scaler_setup_casf(crtc_state); -} - -void intel_casf_disable(const struct intel_crtc_state *crtc_state) -{ - struct intel_display *display = to_intel_display(crtc_state); - struct intel_crtc *crtc = to_intel_crtc(crtc_state->uapi.crtc); - - intel_de_write(display, SKL_PS_CTRL(crtc->pipe, 1), 0); - intel_de_write(display, SKL_PS_WIN_POS(crtc->pipe, 1), 0); - intel_de_write(display, SHARPNESS_CTL(crtc->pipe), 0); - intel_de_write(display, SKL_PS_WIN_SZ(crtc->pipe, 1), 0); } diff --git a/drivers/gpu/drm/i915/display/intel_casf.h b/drivers/gpu/drm/i915/display/intel_casf.h index c4f984b73348..3ebb7522af0a 100644 --- a/drivers/gpu/drm/i915/display/intel_casf.h +++ b/drivers/gpu/drm/i915/display/intel_casf.h @@ -11,11 +11,7 @@ struct intel_crtc_state; int intel_casf_compute_config(struct intel_crtc_state *crtc_state); -void intel_casf_update_strength(const struct intel_crtc_state *new_crtc_state); void intel_casf_sharpness_get_config(struct intel_crtc_state *crtc_state); -void intel_casf_enable(const struct intel_crtc_state *crtc_state); -void intel_casf_disable(const struct intel_crtc_state *crtc_state); -void intel_casf_scaler_compute_config(struct intel_crtc_state *crtc_state); -bool intel_casf_needs_scaler(const struct intel_crtc_state *crtc_state); +void intel_casf_setup(const struct intel_crtc_state *crtc_state); #endif /* __INTEL_CASF_H__ */ diff --git a/drivers/gpu/drm/i915/display/intel_display.c b/drivers/gpu/drm/i915/display/intel_display.c index e02e69467871..58a654ca0d20 100644 --- a/drivers/gpu/drm/i915/display/intel_display.c +++ b/drivers/gpu/drm/i915/display/intel_display.c @@ -58,7 +58,6 @@ #include "intel_audio.h" #include "intel_bo.h" #include "intel_bw.h" -#include "intel_casf.h" #include "intel_cdclk.h" #include "intel_clock_gating.h" #include "intel_color.h" @@ -988,24 +987,6 @@ static bool audio_disabling(const struct intel_crtc_state *old_crtc_state, memcmp(old_crtc_state->eld, new_crtc_state->eld, MAX_ELD_BYTES) != 0); } -static bool intel_casf_enabling(const struct intel_crtc_state *new_crtc_state, - const struct intel_crtc_state *old_crtc_state) -{ - if (!new_crtc_state->hw.active) - return false; - - return is_enabling(pch_pfit.casf.enable, old_crtc_state, new_crtc_state); -} - -static bool intel_casf_disabling(const struct intel_crtc_state *old_crtc_state, - const struct intel_crtc_state *new_crtc_state) -{ - if (!new_crtc_state->hw.active) - return false; - - return is_disabling(pch_pfit.casf.enable, old_crtc_state, new_crtc_state); -} - static bool intel_crtc_lobf_enabling(const struct intel_crtc_state *old_crtc_state, const struct intel_crtc_state *new_crtc_state) { @@ -1187,9 +1168,6 @@ static void intel_pre_plane_update(struct intel_atomic_state *state, if (audio_disabling(old_crtc_state, new_crtc_state)) intel_encoders_audio_disable(state, crtc); - if (intel_casf_disabling(old_crtc_state, new_crtc_state)) - intel_casf_disable(new_crtc_state); - intel_drrs_deactivate(old_crtc_state); if (hsw_ips_pre_update(state, crtc)) @@ -4308,14 +4286,9 @@ static int intel_crtc_atomic_check(struct intel_atomic_state *state, return ret; } - ret = intel_casf_compute_config(crtc_state); - if (ret) - return ret; - if (DISPLAY_VER(display) >= 9) { if (intel_crtc_needs_modeset(crtc_state) || - intel_crtc_needs_fastset(crtc_state) || - intel_casf_needs_scaler(crtc_state)) { + intel_crtc_needs_fastset(crtc_state)) { ret = skl_update_scaler_crtc(crtc_state); if (ret) return ret; @@ -6817,11 +6790,6 @@ static void intel_pre_update_crtc(struct intel_atomic_state *state, intel_vrr_set_transcoder_timings(new_crtc_state); } - if (intel_casf_enabling(new_crtc_state, old_crtc_state)) - intel_casf_enable(new_crtc_state); - else if (new_crtc_state->pch_pfit.casf.strength != old_crtc_state->pch_pfit.casf.strength) - intel_casf_update_strength(new_crtc_state); - intel_fbc_update(state, crtc); drm_WARN_ON(display->drm, !intel_display_power_is_enabled(display, POWER_DOMAIN_DC_OFF)); diff --git a/drivers/gpu/drm/i915/display/intel_pfit.c b/drivers/gpu/drm/i915/display/intel_pfit.c index 2dec4ccf74ce..5b170c74a510 100644 --- a/drivers/gpu/drm/i915/display/intel_pfit.c +++ b/drivers/gpu/drm/i915/display/intel_pfit.c @@ -196,7 +196,8 @@ static int pch_panel_fitting(struct intel_crtc_state *crtc_state, /* Native modes don't need fitting */ if (adjusted_mode->crtc_hdisplay == pipe_src_w && adjusted_mode->crtc_vdisplay == pipe_src_h && - crtc_state->output_format != INTEL_OUTPUT_FORMAT_YCBCR420) + crtc_state->output_format != INTEL_OUTPUT_FORMAT_YCBCR420 && + crtc_state->hw.sharpness_strength == 0) return 0; switch (conn_state->scaling_mode) { @@ -260,6 +261,16 @@ static int pch_panel_fitting(struct intel_crtc_state *crtc_state, return -EINVAL; } + if (crtc_state->hw.sharpness_strength && + (width != pipe_src_w || height != pipe_src_h || + crtc_state->hw.scaling_filter != DRM_SCALING_FILTER_DEFAULT || + crtc_state->output_format != INTEL_OUTPUT_FORMAT_RGB)) { + drm_dbg_kms(display->drm, + "[CRTC:%d:%s] no scaling/YCbCr output with sharpness filter\n", + crtc->base.base.id, crtc->base.name); + return -EINVAL; + } + drm_rect_init(&crtc_state->pch_pfit.dst, x, y, width, height); crtc_state->pch_pfit.enabled = true; diff --git a/drivers/gpu/drm/i915/display/skl_scaler.c b/drivers/gpu/drm/i915/display/skl_scaler.c index 762f4bb46c2d..308b8d363bba 100644 --- a/drivers/gpu/drm/i915/display/skl_scaler.c +++ b/drivers/gpu/drm/i915/display/skl_scaler.c @@ -270,6 +270,11 @@ int skl_update_scaler_crtc(struct intel_crtc_state *crtc_state) { const struct drm_display_mode *pipe_mode = &crtc_state->hw.pipe_mode; int width, height; + int ret; + + ret = intel_casf_compute_config(crtc_state); + if (ret) + return ret; if (crtc_state->pch_pfit.enabled) { width = drm_rect_width(&crtc_state->pch_pfit.dst); @@ -284,8 +289,7 @@ int skl_update_scaler_crtc(struct intel_crtc_state *crtc_state) drm_rect_width(&crtc_state->pipe_src), drm_rect_height(&crtc_state->pipe_src), width, height, NULL, 0, - crtc_state->pch_pfit.enabled || - intel_casf_needs_scaler(crtc_state)); + crtc_state->pch_pfit.enabled); } /** @@ -534,14 +538,11 @@ static int setup_crtc_scaler(struct intel_atomic_state *state, struct intel_crtc_scaler_state *scaler_state = &crtc_state->scaler_state; - if (intel_casf_needs_scaler(crtc_state) && crtc_state->pch_pfit.enabled) - return -EINVAL; - return intel_atomic_setup_scaler(crtc_state, hweight32(scaler_state->scaler_users), crtc, "CRTC", crtc->base.base.id, NULL, &scaler_state->scaler_id, - intel_casf_needs_scaler(crtc_state)); + crtc_state->pch_pfit.casf.enable); } static int setup_plane_scaler(struct intel_atomic_state *state, @@ -757,43 +758,14 @@ static void skl_scaler_setup_filter(struct intel_display *display, } } -void skl_scaler_setup_casf(const struct intel_crtc_state *crtc_state) +static u32 casf_sharpness_ctl(const struct intel_crtc_state *crtc_state) { - struct intel_crtc *crtc = to_intel_crtc(crtc_state->uapi.crtc); - struct intel_display *display = to_intel_display(crtc); - const struct drm_display_mode *adjusted_mode = - &crtc_state->hw.adjusted_mode; - const struct intel_crtc_scaler_state *scaler_state = - &crtc_state->scaler_state; - struct drm_rect src, dest; - int id, width, height; - int x = 0, y = 0; - enum pipe pipe = crtc->pipe; - u32 ps_ctrl; - - width = adjusted_mode->crtc_hdisplay; - height = adjusted_mode->crtc_vdisplay; - - drm_rect_init(&dest, x, y, width, height); - - width = drm_rect_width(&dest); - height = drm_rect_height(&dest); - id = scaler_state->scaler_id; - - drm_rect_init(&src, 0, 0, - drm_rect_width(&crtc_state->pipe_src) << 16, - drm_rect_height(&crtc_state->pipe_src) << 16); - - trace_intel_pipe_scaler_update_arm(crtc, id, x, y, width, height); - - ps_ctrl = PS_SCALER_EN | PS_BINDING_PIPE | scaler_state->scalers[id].mode | - skl_scaler_get_filter_select(crtc_state->hw.scaling_filter, true); + if (!crtc_state->pch_pfit.casf.enable) + return 0; - intel_de_write_fw(display, SKL_PS_CTRL(pipe, id), ps_ctrl); - intel_de_write_fw(display, SKL_PS_WIN_POS(pipe, id), - PS_WIN_XPOS(x) | PS_WIN_YPOS(y)); - intel_de_write_fw(display, SKL_PS_WIN_SZ(pipe, id), - PS_WIN_XSIZE(width) | PS_WIN_YSIZE(height)); + return FILTER_EN | + FILTER_STRENGTH(crtc_state->pch_pfit.casf.strength) | + crtc_state->pch_pfit.casf.win_size; } void skl_pfit_enable(const struct intel_crtc_state *crtc_state) @@ -837,12 +809,20 @@ void skl_pfit_enable(const struct intel_crtc_state *crtc_state) id = scaler_state->scaler_id; ps_ctrl = PS_SCALER_EN | PS_BINDING_PIPE | scaler_state->scalers[id].mode | - skl_scaler_get_filter_select(crtc_state->hw.scaling_filter, false); + skl_scaler_get_filter_select(crtc_state->hw.scaling_filter, + crtc_state->pch_pfit.casf.enable); trace_intel_pipe_scaler_update_arm(crtc, id, x, y, width, height); - skl_scaler_setup_filter(display, NULL, pipe, id, 0, - crtc_state->hw.scaling_filter); + if (crtc_state->pch_pfit.casf.enable) + intel_casf_setup(crtc_state); + else + skl_scaler_setup_filter(display, NULL, pipe, id, 0, + crtc_state->hw.scaling_filter); + + if (scaler_has_casf(display, id)) + intel_de_write_fw(display, SHARPNESS_CTL(crtc->pipe), + casf_sharpness_ctl(crtc_state)); intel_de_write_fw(display, SKL_PS_CTRL(pipe, id), ps_ctrl); @@ -930,6 +910,9 @@ static void skl_detach_scaler(struct intel_dsb *dsb, trace_intel_scaler_disable_arm(crtc, id); + if (scaler_has_casf(display, id)) + intel_de_write_dsb(display, dsb, SHARPNESS_CTL(crtc->pipe), 0); + intel_de_write_dsb(display, dsb, SKL_PS_CTRL(crtc->pipe, id), 0); intel_de_write_dsb(display, dsb, SKL_PS_WIN_POS(crtc->pipe, id), 0); intel_de_write_dsb(display, dsb, SKL_PS_WIN_SZ(crtc->pipe, id), 0); @@ -983,18 +966,16 @@ void skl_scaler_get_config(struct intel_crtc_state *crtc_state) if (scaler_has_casf(display, i)) intel_casf_sharpness_get_config(crtc_state); - if (!crtc_state->pch_pfit.casf.enable) - crtc_state->pch_pfit.enabled = true; + crtc_state->pch_pfit.enabled = true; pos = intel_de_read(display, SKL_PS_WIN_POS(crtc->pipe, i)); size = intel_de_read(display, SKL_PS_WIN_SZ(crtc->pipe, i)); - if (!crtc_state->pch_pfit.casf.enable) - drm_rect_init(&crtc_state->pch_pfit.dst, - REG_FIELD_GET(PS_WIN_XPOS_MASK, pos), - REG_FIELD_GET(PS_WIN_YPOS_MASK, pos), - REG_FIELD_GET(PS_WIN_XSIZE_MASK, size), - REG_FIELD_GET(PS_WIN_YSIZE_MASK, size)); + drm_rect_init(&crtc_state->pch_pfit.dst, + REG_FIELD_GET(PS_WIN_XPOS_MASK, pos), + REG_FIELD_GET(PS_WIN_YPOS_MASK, pos), + REG_FIELD_GET(PS_WIN_XSIZE_MASK, size), + REG_FIELD_GET(PS_WIN_YSIZE_MASK, size)); scaler_state->scalers[i].in_use = true; break; diff --git a/drivers/gpu/drm/i915/display/skl_scaler.h b/drivers/gpu/drm/i915/display/skl_scaler.h index 20ecf373eb19..5deabca909e6 100644 --- a/drivers/gpu/drm/i915/display/skl_scaler.h +++ b/drivers/gpu/drm/i915/display/skl_scaler.h @@ -36,8 +36,6 @@ void skl_scaler_disable(const struct intel_crtc_state *old_crtc_state); void skl_scaler_get_config(struct intel_crtc_state *crtc_state); -void skl_scaler_setup_casf(const struct intel_crtc_state *crtc_state); - enum drm_mode_status skl_scaler_mode_valid(struct intel_display *display, const struct drm_display_mode *mode, -- cgit v1.2.3 From b20a9b5f9c4baeae0b2e143046b195b910c59714 Mon Sep 17 00:00:00 2001 From: Steven Price Date: Wed, 8 Apr 2026 10:12:42 +0100 Subject: drm/panthor: Fix kernel-doc in panthor_sched.c so it's visible Various substructures defined in panthor_sched.c have kernel-doc which is silently ignored because it doesn't include the full path to the member. Fix these issues so that the kernel-doc text is actually output by including the name of the parent. Fixes: de8548813824 ("drm/panthor: Add the scheduler logical block") Signed-off-by: Steven Price Reviewed-by: Boris Brezillon Reviewed-by: Liviu Dudau Link: https://patch.msgid.link/20260408091242.799074-1-steven.price@arm.com --- drivers/gpu/drm/panthor/panthor_sched.c | 72 ++++++++++++++++----------------- 1 file changed, 36 insertions(+), 36 deletions(-) diff --git a/drivers/gpu/drm/panthor/panthor_sched.c b/drivers/gpu/drm/panthor/panthor_sched.c index 3bb1cb5a2656..a06d91875beb 100644 --- a/drivers/gpu/drm/panthor/panthor_sched.c +++ b/drivers/gpu/drm/panthor/panthor_sched.c @@ -221,7 +221,7 @@ struct panthor_scheduler { /** @groups: Various lists used to classify groups. */ struct { /** - * @runnable: Runnable group lists. + * @groups.runnable: Runnable group lists. * * When a group has queues that want to execute something, * its panthor_group::run_node should be inserted here. @@ -231,7 +231,7 @@ struct panthor_scheduler { struct list_head runnable[PANTHOR_CSG_PRIORITY_COUNT]; /** - * @idle: Idle group lists. + * @groups.idle: Idle group lists. * * When all queues of a group are idle (either because they * have nothing to execute, or because they are blocked), the @@ -242,7 +242,7 @@ struct panthor_scheduler { struct list_head idle[PANTHOR_CSG_PRIORITY_COUNT]; /** - * @waiting: List of groups whose queues are blocked on a + * @groups.waiting: List of groups whose queues are blocked on a * synchronization object. * * Insert panthor_group::wait_node here when a group is waiting @@ -283,17 +283,17 @@ struct panthor_scheduler { /** @pm: Power management related fields. */ struct { - /** @has_ref: True if the scheduler owns a runtime PM reference. */ + /** @pm.has_ref: True if the scheduler owns a runtime PM reference. */ bool has_ref; } pm; /** @reset: Reset related fields. */ struct { - /** @lock: Lock protecting the other reset fields. */ + /** @reset.lock: Lock protecting the other reset fields. */ struct mutex lock; /** - * @in_progress: True if a reset is in progress. + * @reset.in_progress: True if a reset is in progress. * * Set to true in panthor_sched_pre_reset() and back to false in * panthor_sched_post_reset(). @@ -301,7 +301,7 @@ struct panthor_scheduler { atomic_t in_progress; /** - * @stopped_groups: List containing all groups that were stopped + * @reset.stopped_groups: List containing all groups that were stopped * before a reset. * * Insert panthor_group::run_node in the pre_reset path. @@ -395,19 +395,19 @@ struct panthor_queue { /** @iface: Firmware interface. */ struct { - /** @mem: FW memory allocated for this interface. */ + /** @iface.mem: FW memory allocated for this interface. */ struct panthor_kernel_bo *mem; - /** @input: Input interface. */ + /** @iface.input: Input interface. */ struct panthor_fw_ringbuf_input_iface *input; - /** @output: Output interface. */ + /** @iface.output: Output interface. */ const struct panthor_fw_ringbuf_output_iface *output; - /** @input_fw_va: FW virtual address of the input interface buffer. */ + /** @iface.input_fw_va: FW virtual address of the input interface buffer. */ u32 input_fw_va; - /** @output_fw_va: FW virtual address of the output interface buffer. */ + /** @iface.output_fw_va: FW virtual address of the output interface buffer. */ u32 output_fw_va; } iface; @@ -416,26 +416,26 @@ struct panthor_queue { * queue is waiting on. */ struct { - /** @gpu_va: GPU address of the synchronization object. */ + /** @syncwait.gpu_va: GPU address of the synchronization object. */ u64 gpu_va; - /** @ref: Reference value to compare against. */ + /** @syncwait.ref: Reference value to compare against. */ u64 ref; - /** @gt: True if this is a greater-than test. */ + /** @syncwait.gt: True if this is a greater-than test. */ bool gt; - /** @sync64: True if this is a 64-bit sync object. */ + /** @syncwait.sync64: True if this is a 64-bit sync object. */ bool sync64; - /** @bo: Buffer object holding the synchronization object. */ + /** @syncwait.obj: Buffer object holding the synchronization object. */ struct drm_gem_object *obj; - /** @offset: Offset of the synchronization object inside @bo. */ + /** @syncwait.offset: Offset of the synchronization object inside @bo. */ u64 offset; /** - * @kmap: Kernel mapping of the buffer object holding the + * @syncwait.kmap: Kernel mapping of the buffer object holding the * synchronization object. */ void *kmap; @@ -443,21 +443,21 @@ struct panthor_queue { /** @fence_ctx: Fence context fields. */ struct { - /** @lock: Used to protect access to all fences allocated by this context. */ + /** @fence_ctx.lock: Used to protect access to all fences allocated by this context. */ spinlock_t lock; /** - * @id: Fence context ID. + * @fence_ctx.id: Fence context ID. * * Allocated with dma_fence_context_alloc(). */ u64 id; - /** @seqno: Sequence number of the last initialized fence. */ + /** @fence_ctx.seqno: Sequence number of the last initialized fence. */ atomic64_t seqno; /** - * @last_fence: Fence of the last submitted job. + * @fence_ctx.last_fence: Fence of the last submitted job. * * We return this fence when we get an empty command stream. * This way, we are guaranteed that all earlier jobs have completed @@ -467,7 +467,7 @@ struct panthor_queue { struct dma_fence *last_fence; /** - * @in_flight_jobs: List containing all in-flight jobs. + * @fence_ctx.in_flight_jobs: List containing all in-flight jobs. * * Used to keep track and signal panthor_job::done_fence when the * synchronization object attached to the queue is signaled. @@ -477,13 +477,13 @@ struct panthor_queue { /** @profiling: Job profiling data slots and access information. */ struct { - /** @slots: Kernel BO holding the slots. */ + /** @profiling.slots: Kernel BO holding the slots. */ struct panthor_kernel_bo *slots; - /** @slot_count: Number of jobs ringbuffer can hold at once. */ + /** @profiling.slot_count: Number of jobs ringbuffer can hold at once. */ u32 slot_count; - /** @seqno: Index of the next available profiling information slot. */ + /** @profiling.seqno: Index of the next available profiling information slot. */ u32 seqno; } profiling; }; @@ -627,7 +627,7 @@ struct panthor_group { /** @fdinfo: Per-file info exposed through /proc//fdinfo */ struct { - /** @data: Total sampled values for jobs in queues from this group. */ + /** @fdinfo.data: Total sampled values for jobs in queues from this group. */ struct panthor_gpu_usage data; /** @@ -805,15 +805,15 @@ struct panthor_job { /** @call_info: Information about the userspace command stream call. */ struct { - /** @start: GPU address of the userspace command stream. */ + /** @call_info.start: GPU address of the userspace command stream. */ u64 start; - /** @size: Size of the userspace command stream. */ + /** @call_info.size: Size of the userspace command stream. */ u32 size; /** - * @latest_flush: Flush ID at the time the userspace command - * stream was built. + * @call_info.latest_flush: Flush ID at the time the userspace + * command stream was built. * * Needed for the flush reduction mechanism. */ @@ -822,10 +822,10 @@ struct panthor_job { /** @ringbuf: Position of this job is in the ring buffer. */ struct { - /** @start: Start offset. */ + /** @ringbuf.start: Start offset. */ u64 start; - /** @end: End offset. */ + /** @ringbuf.end: End offset. */ u64 end; } ringbuf; @@ -840,10 +840,10 @@ struct panthor_job { /** @profiling: Job profiling information. */ struct { - /** @mask: Current device job profiling enablement bitmask. */ + /** @profiling.mask: Current device job profiling enablement bitmask. */ u32 mask; - /** @slot: Job index in the profiling slots BO. */ + /** @profiling.slot: Job index in the profiling slots BO. */ u32 slot; } profiling; }; -- cgit v1.2.3 From 723277b15ed97185ce6f75abbf19f06e00f0a6f5 Mon Sep 17 00:00:00 2001 From: Geliang Tang Date: Tue, 31 Mar 2026 16:17:31 +0800 Subject: nvme: add missing MODULE_ALIAS for fabrics transports The generic fabrics layer uses request_module("nvme-%s", opts->transport) to auto-load transport modules. Currently, the nvme-tcp, nvme-rdma, and nvme-fc modules lack MODULE_ALIAS entries for these names, which prevents the kernel from automatically finding and loading them when requested. Reviewed-by: Christoph Hellwig Signed-off-by: Geliang Tang Signed-off-by: Keith Busch --- drivers/nvme/host/fc.c | 1 + drivers/nvme/host/rdma.c | 1 + drivers/nvme/host/tcp.c | 1 + 3 files changed, 3 insertions(+) diff --git a/drivers/nvme/host/fc.c b/drivers/nvme/host/fc.c index e1bb4707183c..e4f4528fe2a2 100644 --- a/drivers/nvme/host/fc.c +++ b/drivers/nvme/host/fc.c @@ -3968,3 +3968,4 @@ module_exit(nvme_fc_exit_module); MODULE_DESCRIPTION("NVMe host FC transport driver"); MODULE_LICENSE("GPL v2"); +MODULE_ALIAS("nvme-fc"); diff --git a/drivers/nvme/host/rdma.c b/drivers/nvme/host/rdma.c index 57111139e84f..1ec6e867aedb 100644 --- a/drivers/nvme/host/rdma.c +++ b/drivers/nvme/host/rdma.c @@ -2432,3 +2432,4 @@ module_exit(nvme_rdma_cleanup_module); MODULE_DESCRIPTION("NVMe host RDMA transport driver"); MODULE_LICENSE("GPL v2"); +MODULE_ALIAS("nvme-rdma"); diff --git a/drivers/nvme/host/tcp.c b/drivers/nvme/host/tcp.c index 243dab830dc8..02c95c32b07e 100644 --- a/drivers/nvme/host/tcp.c +++ b/drivers/nvme/host/tcp.c @@ -3071,3 +3071,4 @@ module_exit(nvme_tcp_cleanup_module); MODULE_DESCRIPTION("NVMe host TCP transport driver"); MODULE_LICENSE("GPL v2"); +MODULE_ALIAS("nvme-tcp"); -- cgit v1.2.3 From 0a5a94648627a438067fc8a6dd178187ceb112fb Mon Sep 17 00:00:00 2001 From: Aurelien Aptel Date: Wed, 8 Apr 2026 09:02:26 +0000 Subject: nvmet: introduce new mdts configuration entry Using this port configuration, one will be able to set the Maximum Data Transfer Size (MDTS) for any controller that will be associated to the configured port. The default value remains 0 (no limit). Signed-off-by: Max Gurtovoy Signed-off-by: Aurelien Aptel Reviewed-by: Christoph Hellwig Signed-off-by: Keith Busch --- drivers/nvme/target/admin-cmd.c | 8 ++------ drivers/nvme/target/configfs.c | 27 +++++++++++++++++++++++++++ drivers/nvme/target/core.c | 8 ++++++++ drivers/nvme/target/nvmet.h | 13 +++++++++++++ drivers/nvme/target/zns.c | 6 +----- 5 files changed, 51 insertions(+), 11 deletions(-) diff --git a/drivers/nvme/target/admin-cmd.c b/drivers/nvme/target/admin-cmd.c index 3794ef258556..3842087209da 100644 --- a/drivers/nvme/target/admin-cmd.c +++ b/drivers/nvme/target/admin-cmd.c @@ -687,12 +687,8 @@ static void nvmet_execute_identify_ctrl(struct nvmet_req *req) id->cmic = NVME_CTRL_CMIC_MULTI_PORT | NVME_CTRL_CMIC_MULTI_CTRL | NVME_CTRL_CMIC_ANA; - /* Limit MDTS according to transport capability */ - if (ctrl->ops->get_mdts) - id->mdts = ctrl->ops->get_mdts(ctrl); - else - id->mdts = 0; - + /* Limit MDTS according to port config or transport capability */ + id->mdts = nvmet_ctrl_mdts(req); id->cntlid = cpu_to_le16(ctrl->cntlid); id->ver = cpu_to_le32(ctrl->subsys->ver); diff --git a/drivers/nvme/target/configfs.c b/drivers/nvme/target/configfs.c index 463348c7f097..b88f897f06e2 100644 --- a/drivers/nvme/target/configfs.c +++ b/drivers/nvme/target/configfs.c @@ -301,6 +301,31 @@ static ssize_t nvmet_param_max_queue_size_store(struct config_item *item, CONFIGFS_ATTR(nvmet_, param_max_queue_size); +static ssize_t nvmet_param_mdts_show(struct config_item *item, char *page) +{ + struct nvmet_port *port = to_nvmet_port(item); + + return snprintf(page, PAGE_SIZE, "%d\n", port->mdts); +} + +static ssize_t nvmet_param_mdts_store(struct config_item *item, + const char *page, size_t count) +{ + struct nvmet_port *port = to_nvmet_port(item); + int ret; + + if (nvmet_is_port_enabled(port, __func__)) + return -EACCES; + ret = kstrtoint(page, 0, &port->mdts); + if (ret) { + pr_err("Invalid value '%s' for mdts\n", page); + return -EINVAL; + } + return count; +} + +CONFIGFS_ATTR(nvmet_, param_mdts); + #ifdef CONFIG_BLK_DEV_INTEGRITY static ssize_t nvmet_param_pi_enable_show(struct config_item *item, char *page) @@ -1995,6 +2020,7 @@ static struct configfs_attribute *nvmet_port_attrs[] = { &nvmet_attr_addr_tsas, &nvmet_attr_param_inline_data_size, &nvmet_attr_param_max_queue_size, + &nvmet_attr_param_mdts, #ifdef CONFIG_BLK_DEV_INTEGRITY &nvmet_attr_param_pi_enable, #endif @@ -2053,6 +2079,7 @@ static struct config_group *nvmet_ports_make(struct config_group *group, INIT_LIST_HEAD(&port->referrals); port->inline_data_size = -1; /* < 0 == let the transport choose */ port->max_queue_size = -1; /* < 0 == let the transport choose */ + port->mdts = -1; /* < 0 == let the transport choose */ port->disc_addr.trtype = NVMF_TRTYPE_MAX; port->disc_addr.portid = cpu_to_le16(portid); diff --git a/drivers/nvme/target/core.c b/drivers/nvme/target/core.c index 03cc7d5f9683..33db6c5534e2 100644 --- a/drivers/nvme/target/core.c +++ b/drivers/nvme/target/core.c @@ -368,6 +368,14 @@ int nvmet_enable_port(struct nvmet_port *port) NVMET_MIN_QUEUE_SIZE, NVMET_MAX_QUEUE_SIZE); + /* + * If the transport didn't set the mdts properly, then clamp it to the + * target limits. Also set default values in case the transport didn't + * set it at all. + */ + if (port->mdts < 0 || port->mdts > NVMET_MAX_MDTS) + port->mdts = 0; + port->enabled = true; port->tr_ops = ops; return 0; diff --git a/drivers/nvme/target/nvmet.h b/drivers/nvme/target/nvmet.h index 5db8f0d6e3f2..64af6bf569bf 100644 --- a/drivers/nvme/target/nvmet.h +++ b/drivers/nvme/target/nvmet.h @@ -214,6 +214,7 @@ struct nvmet_port { bool enabled; int inline_data_size; int max_queue_size; + int mdts; const struct nvmet_fabrics_ops *tr_ops; bool pi_enable; }; @@ -672,6 +673,7 @@ void nvmet_add_async_event(struct nvmet_ctrl *ctrl, u8 event_type, #define NVMET_MAX_QUEUE_SIZE 1024 #define NVMET_NR_QUEUES 128 #define NVMET_MAX_CMD(ctrl) (NVME_CAP_MQES(ctrl->cap) + 1) +#define NVMET_MAX_MDTS 255 /* * Nice round number that makes a list of nsids fit into a page. @@ -760,6 +762,17 @@ static inline bool nvmet_is_pci_ctrl(struct nvmet_ctrl *ctrl) return ctrl->port->disc_addr.trtype == NVMF_TRTYPE_PCI; } +/* Limit MDTS according to port config or transport capability */ +static inline u8 nvmet_ctrl_mdts(struct nvmet_req *req) +{ + struct nvmet_ctrl *ctrl = req->sq->ctrl; + u8 mdts = req->port->mdts; + + if (!ctrl->ops->get_mdts) + return mdts; + return min_not_zero(ctrl->ops->get_mdts(ctrl), mdts); +} + #ifdef CONFIG_NVME_TARGET_PASSTHRU void nvmet_passthru_subsys_free(struct nvmet_subsys *subsys); int nvmet_passthru_ctrl_enable(struct nvmet_subsys *subsys); diff --git a/drivers/nvme/target/zns.c b/drivers/nvme/target/zns.c index aeaf73b54c3a..f00921931eb6 100644 --- a/drivers/nvme/target/zns.c +++ b/drivers/nvme/target/zns.c @@ -69,7 +69,6 @@ bool nvmet_bdev_zns_enable(struct nvmet_ns *ns) void nvmet_execute_identify_ctrl_zns(struct nvmet_req *req) { u8 zasl = req->sq->ctrl->subsys->zasl; - struct nvmet_ctrl *ctrl = req->sq->ctrl; struct nvme_id_ctrl_zns *id; u16 status; @@ -79,10 +78,7 @@ void nvmet_execute_identify_ctrl_zns(struct nvmet_req *req) goto out; } - if (ctrl->ops->get_mdts) - id->zasl = min_t(u8, ctrl->ops->get_mdts(ctrl), zasl); - else - id->zasl = zasl; + id->zasl = min_not_zero(nvmet_ctrl_mdts(req), zasl); status = nvmet_copy_to_sgl(req, 0, id, sizeof(*id)); -- cgit v1.2.3 From 23528aa3320a74b028e990b5a939fed32a8afc2f Mon Sep 17 00:00:00 2001 From: Shivaji Kant Date: Mon, 6 Apr 2026 09:21:32 +0000 Subject: nvme: enable PCI P2PDMA support for RDMA transport Enable BLK_FEAT_PCI_P2PDMA on the NVMe when the underlying RDMA controller supports it. Suggested-by: Pranjal Shrivastava Reviewed-by: Pranjal Shrivastava Reviewed-by: Henrique Carvalho Reviewed-by: Christoph Hellwig Signed-off-by: Shivaji Kant Signed-off-by: Keith Busch --- drivers/nvme/host/rdma.c | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/drivers/nvme/host/rdma.c b/drivers/nvme/host/rdma.c index 1ec6e867aedb..f77c960f7632 100644 --- a/drivers/nvme/host/rdma.c +++ b/drivers/nvme/host/rdma.c @@ -2189,6 +2189,13 @@ out_fail: nvme_rdma_reconnect_or_remove(ctrl, ret); } +static bool nvme_rdma_supports_pci_p2pdma(struct nvme_ctrl *ctrl) +{ + struct nvme_rdma_ctrl *r_ctrl = to_rdma_ctrl(ctrl); + + return ib_dma_pci_p2p_dma_supported(r_ctrl->device->dev); +} + static const struct nvme_ctrl_ops nvme_rdma_ctrl_ops = { .name = "rdma", .module = THIS_MODULE, @@ -2203,6 +2210,7 @@ static const struct nvme_ctrl_ops nvme_rdma_ctrl_ops = { .get_address = nvmf_get_address, .stop_ctrl = nvme_rdma_stop_ctrl, .get_virt_boundary = nvme_get_virt_boundary, + .supports_pci_p2pdma = nvme_rdma_supports_pci_p2pdma, }; /* -- cgit v1.2.3 From 764c0e2abf3b7c8611a3695af26febfffe236c68 Mon Sep 17 00:00:00 2001 From: Tejas Upadhyay Date: Tue, 7 Apr 2026 11:21:08 +0530 Subject: Use xe_map_resource_to_region helper instead of direct access Renaming: The helper function res_to_mem_region is now xe_map_resource_to_region. Abstraction: The patch removes instances where block->private was accessed directly to obtain VRAM region data allowing VRAM manager to own block->private for future use cases. V2(MattB): Add more detail about patch also adjust variable placement Reviewed-by: Matthew Brost Link: https://patch.msgid.link/20260407055107.2782450-2-tejas.upadhyay@intel.com Signed-off-by: Tejas Upadhyay --- drivers/gpu/drm/xe/xe_bo.c | 21 ++++----------------- drivers/gpu/drm/xe/xe_svm.c | 10 ++-------- drivers/gpu/drm/xe/xe_vram.c | 22 ++++++++++++++++++++++ drivers/gpu/drm/xe/xe_vram.h | 2 ++ 4 files changed, 30 insertions(+), 25 deletions(-) diff --git a/drivers/gpu/drm/xe/xe_bo.c b/drivers/gpu/drm/xe/xe_bo.c index a7c2dc7f224c..daac53168dba 100644 --- a/drivers/gpu/drm/xe/xe_bo.c +++ b/drivers/gpu/drm/xe/xe_bo.c @@ -173,19 +173,6 @@ mem_type_to_migrate(struct xe_device *xe, u32 mem_type) return tile->migrate; } -static struct xe_vram_region *res_to_mem_region(struct ttm_resource *res) -{ - struct xe_device *xe = ttm_to_xe_device(res->bo->bdev); - struct ttm_resource_manager *mgr; - struct xe_ttm_vram_mgr *vram_mgr; - - xe_assert(xe, resource_is_vram(res)); - mgr = ttm_manager_type(&xe->ttm, res->mem_type); - vram_mgr = to_xe_ttm_vram_mgr(mgr); - - return container_of(vram_mgr, struct xe_vram_region, ttm); -} - static void try_add_system(struct xe_device *xe, struct xe_bo *bo, u32 bo_flags, u32 *c) { @@ -635,7 +622,7 @@ static int xe_ttm_io_mem_reserve(struct ttm_device *bdev, return 0; case XE_PL_VRAM0: case XE_PL_VRAM1: { - struct xe_vram_region *vram = res_to_mem_region(mem); + struct xe_vram_region *vram = xe_map_resource_to_region(mem); if (!xe_ttm_resource_visible(mem)) return -EINVAL; @@ -1642,7 +1629,7 @@ static unsigned long xe_ttm_io_mem_pfn(struct ttm_buffer_object *ttm_bo, if (ttm_bo->resource->mem_type == XE_PL_STOLEN) return xe_ttm_stolen_io_offset(bo, page_offset << PAGE_SHIFT) >> PAGE_SHIFT; - vram = res_to_mem_region(ttm_bo->resource); + vram = xe_map_resource_to_region(ttm_bo->resource); xe_res_first(ttm_bo->resource, (u64)page_offset << PAGE_SHIFT, 0, &cursor); return (vram->io_start + cursor.start) >> PAGE_SHIFT; } @@ -1782,7 +1769,7 @@ static int xe_ttm_access_memory(struct ttm_buffer_object *ttm_bo, goto out; } - vram = res_to_mem_region(ttm_bo->resource); + vram = xe_map_resource_to_region(ttm_bo->resource); xe_res_first(ttm_bo->resource, offset & PAGE_MASK, xe_bo_size(bo) - (offset & PAGE_MASK), &cursor); @@ -2923,7 +2910,7 @@ uint64_t vram_region_gpu_offset(struct ttm_resource *res) case XE_PL_SYSTEM: return 0; default: - return res_to_mem_region(res)->dpa_base; + return xe_map_resource_to_region(res)->dpa_base; } return 0; } diff --git a/drivers/gpu/drm/xe/xe_svm.c b/drivers/gpu/drm/xe/xe_svm.c index 5933b2b6392b..ba67355f64cb 100644 --- a/drivers/gpu/drm/xe/xe_svm.c +++ b/drivers/gpu/drm/xe/xe_svm.c @@ -786,12 +786,12 @@ static int xe_svm_populate_devmem_pfn(struct drm_pagemap_devmem *devmem_allocati struct xe_bo *bo = to_xe_bo(devmem_allocation); struct ttm_resource *res = bo->ttm.resource; struct list_head *blocks = &to_xe_ttm_vram_mgr_resource(res)->blocks; + struct xe_vram_region *vr = xe_map_resource_to_region(res); + struct gpu_buddy *buddy = vram_to_buddy(vr); struct gpu_buddy_block *block; int j = 0; list_for_each_entry(block, blocks, link) { - struct xe_vram_region *vr = block->private; - struct gpu_buddy *buddy = vram_to_buddy(vr); u64 block_pfn = block_offset_to_pfn(devmem_allocation->dpagemap, gpu_buddy_block_offset(block)); int i; @@ -1061,9 +1061,7 @@ static int xe_drm_pagemap_populate_mm(struct drm_pagemap *dpagemap, struct dma_fence *pre_migrate_fence = NULL; struct xe_device *xe = vr->xe; struct device *dev = xe->drm.dev; - struct gpu_buddy_block *block; struct xe_validation_ctx vctx; - struct list_head *blocks; struct drm_exec exec; struct xe_bo *bo; int err = 0, idx; @@ -1100,10 +1098,6 @@ static int xe_drm_pagemap_populate_mm(struct drm_pagemap *dpagemap, &dpagemap_devmem_ops, dpagemap, end - start, pre_migrate_fence); - blocks = &to_xe_ttm_vram_mgr_resource(bo->ttm.resource)->blocks; - list_for_each_entry(block, blocks, link) - block->private = vr; - xe_bo_get(bo); /* Ensure the device has a pm ref while there are device pages active. */ diff --git a/drivers/gpu/drm/xe/xe_vram.c b/drivers/gpu/drm/xe/xe_vram.c index 0538dcb8b18c..23eb7edbdd57 100644 --- a/drivers/gpu/drm/xe/xe_vram.c +++ b/drivers/gpu/drm/xe/xe_vram.c @@ -13,6 +13,7 @@ #include "regs/xe_gt_regs.h" #include "regs/xe_regs.h" #include "xe_assert.h" +#include "xe_bo.h" #include "xe_device.h" #include "xe_force_wake.h" #include "xe_gt_mcr.h" @@ -249,6 +250,27 @@ static int vram_region_init(struct xe_device *xe, struct xe_vram_region *vram, return 0; } +/** + * xe_map_resource_to_region - Map ttm resource to vram memory region + * @res: The ttm resource + * + * Get vram memory region using vram memory manager managing this resource + * + * Returns: pointer to xe_vram_region + */ +struct xe_vram_region *xe_map_resource_to_region(struct ttm_resource *res) +{ + struct xe_device *xe = ttm_to_xe_device(res->bo->bdev); + struct ttm_resource_manager *mgr; + struct xe_ttm_vram_mgr *vram_mgr; + + xe_assert(xe, mem_type_is_vram(res->mem_type)); + mgr = ttm_manager_type(&xe->ttm, res->mem_type); + vram_mgr = to_xe_ttm_vram_mgr(mgr); + + return container_of(vram_mgr, struct xe_vram_region, ttm); +} + /** * xe_vram_probe() - Probe VRAM configuration * @xe: the &xe_device diff --git a/drivers/gpu/drm/xe/xe_vram.h b/drivers/gpu/drm/xe/xe_vram.h index 72860f714fc6..dd1c8bf17922 100644 --- a/drivers/gpu/drm/xe/xe_vram.h +++ b/drivers/gpu/drm/xe/xe_vram.h @@ -10,7 +10,9 @@ struct xe_device; struct xe_vram_region; +struct ttm_resource; +struct xe_vram_region *xe_map_resource_to_region(struct ttm_resource *res); int xe_vram_probe(struct xe_device *xe); struct xe_vram_region *xe_vram_region_alloc(struct xe_device *xe, u8 id, u32 placement); -- cgit v1.2.3 From 2b923203b0f0ad1f1f56b956fd0b23dc4fcc73dd Mon Sep 17 00:00:00 2001 From: Jonathan Cavitt Date: Mon, 16 Mar 2026 16:20:04 +0000 Subject: drm/xe/tlb: Init range tilemask err to zero MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Initialize err = 0 in xe_tlb_inval_range_tilemask_submit to prevent a possible uninitialized value return in the case where the tile_mask somehow doesn't match any available tile ids. This targets a static analysis issue. Signed-off-by: Jonathan Cavitt Reviewed-by: Thomas Hellström Link: https://patch.msgid.link/20260316162003.64643-2-jonathan.cavitt@intel.com Signed-off-by: Shuicheng Lin --- drivers/gpu/drm/xe/xe_tlb_inval.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/gpu/drm/xe/xe_tlb_inval.c b/drivers/gpu/drm/xe/xe_tlb_inval.c index 10dcd4abb00f..bbd21d393062 100644 --- a/drivers/gpu/drm/xe/xe_tlb_inval.c +++ b/drivers/gpu/drm/xe/xe_tlb_inval.c @@ -529,7 +529,7 @@ int xe_tlb_inval_range_tilemask_submit(struct xe_device *xe, u32 asid, struct xe_tile *tile; u32 fence_id = 0; u8 id; - int err; + int err = 0; batch->num_fences = 0; if (!tile_mask) -- cgit v1.2.3 From 3233db7682e759d101028285386ee7a11183fa2a Mon Sep 17 00:00:00 2001 From: Shuicheng Lin Date: Tue, 7 Apr 2026 03:00:41 +0000 Subject: drm/xe/uapi: Fix typos and spelling errors in xe_drm.h documentation Fix the following typos and spelling errors in doc comments: - creaed -> created (drm_xe_query_config) - mmaping -> mmapping (drm_xe_gem_create) - 0xdeadbeaf -> 0xdeadbeef (drm_xe_gem_mmap_offset) - x2 and xe3 platform -> Xe2 and Xe3 platforms - flat -> flag (drm_xe_wait_user_fence) - MONOTONIC_CLOCK -> CLOCK_MONOTONIC (correct POSIX name) - neverending -> never ending (drm_xe_wait_user_fence) Assisted-by: GitHub Copilot:claude-opus-4.6 Reviewed-by: Xin Wang Link: https://patch.msgid.link/20260407030046.3394004-2-shuicheng.lin@intel.com Signed-off-by: Shuicheng Lin --- include/uapi/drm/xe_drm.h | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/include/uapi/drm/xe_drm.h b/include/uapi/drm/xe_drm.h index ae2fda23ce7c..f17355684083 100644 --- a/include/uapi/drm/xe_drm.h +++ b/include/uapi/drm/xe_drm.h @@ -410,7 +410,7 @@ struct drm_xe_query_mem_regions { * device supports the userspace hint %DRM_XE_GEM_CREATE_FLAG_NO_COMPRESSION. * This is exposed only on Xe2+. * - %DRM_XE_QUERY_CONFIG_FLAG_HAS_DISABLE_STATE_CACHE_PERF_FIX - Flag is set - * if a queue can be creaed with + * if a queue can be created with * %DRM_XE_EXEC_QUEUE_SET_DISABLE_STATE_CACHE_PERF_FIX * - %DRM_XE_QUERY_CONFIG_MIN_ALIGNMENT - Minimal memory alignment * required by this device, typically SZ_4K or SZ_64K @@ -888,7 +888,7 @@ struct drm_xe_gem_create { #define DRM_XE_GEM_CPU_CACHING_WC 2 /** * @cpu_caching: The CPU caching mode to select for this object. If - * mmaping the object the mode selected here will also be used. The + * mmapping the object the mode selected here will also be used. The * exception is when mapping system memory (including data evicted * to system) on discrete GPUs. The caching mode selected will * then be overridden to DRM_XE_GEM_CPU_CACHING_WB, and coherency @@ -931,7 +931,7 @@ struct drm_xe_gem_create { * * err = ioctl(fd, DRM_IOCTL_XE_GEM_MMAP_OFFSET, &mmo); * map = mmap(NULL, size, PROT_WRITE, MAP_SHARED, fd, mmo.offset); - * map[i] = 0xdeadbeaf; // issue barrier + * map[i] = 0xdeadbeef; // issue barrier */ struct drm_xe_gem_mmap_offset { /** @extensions: Pointer to the first extension struct, if any */ @@ -958,8 +958,8 @@ struct drm_xe_gem_mmap_offset { * - %DRM_XE_VM_CREATE_FLAG_SCRATCH_PAGE - Map the whole virtual address * space of the VM to scratch page. A vm_bind would overwrite the scratch * page mapping. This flag is mutually exclusive with the - * %DRM_XE_VM_CREATE_FLAG_FAULT_MODE flag, with an exception of on x2 and - * xe3 platform. + * %DRM_XE_VM_CREATE_FLAG_FAULT_MODE flag, with an exception on Xe2 and + * Xe3 platforms. * - %DRM_XE_VM_CREATE_FLAG_LR_MODE - An LR, or Long Running VM accepts * exec submissions to its exec_queues that don't have an upper time * limit on the job execution time. But exec submissions to these @@ -1695,9 +1695,9 @@ struct drm_xe_wait_user_fence { * Without DRM_XE_UFENCE_WAIT_FLAG_ABSTIME flag set (relative timeout) * it contains timeout expressed in nanoseconds to wait (fence will * expire at now() + timeout). - * When DRM_XE_UFENCE_WAIT_FLAG_ABSTIME flat is set (absolute timeout) wait - * will end at timeout (uses system MONOTONIC_CLOCK). - * Passing negative timeout leads to neverending wait. + * When DRM_XE_UFENCE_WAIT_FLAG_ABSTIME flag is set (absolute timeout) wait + * will end at timeout (uses system CLOCK_MONOTONIC). + * Passing negative timeout leads to never ending wait. * * On relative timeout this value is updated with timeout left * (for restarting the call in case of signal delivery). -- cgit v1.2.3 From 65d53c13d43b8b5690c326807c1535b1d19138e8 Mon Sep 17 00:00:00 2001 From: Shuicheng Lin Date: Tue, 7 Apr 2026 03:00:42 +0000 Subject: drm/xe/uapi: Fix grammar errors in xe_drm.h documentation Fix various grammar issues in doc comments: - flag are only valid -> flag is only valid - should only ever used -> should only ever be used - if isn't already -> if it isn't already - Type of the this -> Type of this - When sync passed in -> When sync is passed in - the users responsibility -> the user's responsibility - must qword aligned -> must be qword aligned - for a observation -> for an observation - a memory ranges -> memory ranges - for each memory ranges -> for each memory range. - Second ioctl call -> second ioctl call Assisted-by: GitHub Copilot:claude-opus-4.6 Reviewed-by: Xin Wang Link: https://patch.msgid.link/20260407030046.3394004-3-shuicheng.lin@intel.com Signed-off-by: Shuicheng Lin --- include/uapi/drm/xe_drm.h | 22 +++++++++++----------- 1 file changed, 11 insertions(+), 11 deletions(-) diff --git a/include/uapi/drm/xe_drm.h b/include/uapi/drm/xe_drm.h index f17355684083..1d3406416d8c 100644 --- a/include/uapi/drm/xe_drm.h +++ b/include/uapi/drm/xe_drm.h @@ -1045,7 +1045,7 @@ struct drm_xe_vm_destroy { * set, no mappings are created rather the range is reserved for CPU address * mirroring which will be populated on GPU page faults or prefetches. Only * valid on VMs with DRM_XE_VM_CREATE_FLAG_FAULT_MODE set. The CPU address - * mirror flag are only valid for DRM_XE_VM_BIND_OP_MAP operations, the BO + * mirror flag is only valid for DRM_XE_VM_BIND_OP_MAP operations, the BO * handle MBZ, and the BO offset MBZ. * - %DRM_XE_VM_BIND_FLAG_MADVISE_AUTORESET - Can be used in combination with * %DRM_XE_VM_BIND_FLAG_CPU_ADDR_MIRROR to reset madvises when the underlying @@ -1109,7 +1109,7 @@ struct drm_xe_vm_bind_op { * ppGTT WT -> COH_NONE * ppGTT WB -> COH_AT_LEAST_1WAY * - * In practice UC/WC/WT should only ever used for scanout surfaces on + * In practice UC/WC/WT should only ever be used for scanout surfaces on * such platforms (or perhaps in general for dma-buf if shared with * another device) since it is only the display engine that is actually * incoherent. Everything else should typically use WB given that we @@ -1366,7 +1366,7 @@ struct drm_xe_vm_get_property { * drm_xe_pxp_session_type. %DRM_XE_PXP_TYPE_NONE is the default behavior, so * there is no need to explicitly set that. When a queue of type * %DRM_XE_PXP_TYPE_HWDRM is created, the PXP default HWDRM session - * (%XE_PXP_HWDRM_DEFAULT_SESSION) will be started, if isn't already running. + * (%XE_PXP_HWDRM_DEFAULT_SESSION) will be started, if it isn't already running. * The user is expected to query the PXP status via the query ioctl (see * %DRM_XE_DEVICE_QUERY_PXP_STATUS) and to wait for PXP to be ready before * attempting to create a queue with this property. When a queue is created @@ -1546,7 +1546,7 @@ struct drm_xe_sync { #define DRM_XE_SYNC_TYPE_SYNCOBJ 0x0 #define DRM_XE_SYNC_TYPE_TIMELINE_SYNCOBJ 0x1 #define DRM_XE_SYNC_TYPE_USER_FENCE 0x2 - /** @type: Type of the this sync object */ + /** @type: Type of this sync object */ __u32 type; #define DRM_XE_SYNC_FLAG_SIGNAL (1 << 0) @@ -1559,9 +1559,9 @@ struct drm_xe_sync { /** * @addr: Address of user fence. When sync is passed in via exec - * IOCTL this is a GPU address in the VM. When sync passed in via + * IOCTL this is a GPU address in the VM. When sync is passed in via * VM bind IOCTL this is a user pointer. In either case, it is - * the users responsibility that this address is present and + * the user's responsibility that this address is present and * mapped when the user fence is signalled. Must be qword * aligned. */ @@ -1664,7 +1664,7 @@ struct drm_xe_wait_user_fence { __u64 extensions; /** - * @addr: user pointer address to wait on, must qword aligned + * @addr: user pointer address to wait on, must be qword aligned */ __u64 addr; @@ -1769,7 +1769,7 @@ enum drm_xe_observation_ioctls { /** @DRM_XE_OBSERVATION_IOCTL_ENABLE: Enable data capture for an observation stream */ DRM_XE_OBSERVATION_IOCTL_ENABLE = _IO('i', 0x0), - /** @DRM_XE_OBSERVATION_IOCTL_DISABLE: Disable data capture for a observation stream */ + /** @DRM_XE_OBSERVATION_IOCTL_DISABLE: Disable data capture for an observation stream */ DRM_XE_OBSERVATION_IOCTL_DISABLE = _IO('i', 0x1), /** @DRM_XE_OBSERVATION_IOCTL_CONFIG: Change observation stream configuration */ @@ -2373,12 +2373,12 @@ struct drm_xe_madvise { * * This structure is provided by userspace and filled by KMD in response to the * DRM_IOCTL_XE_VM_QUERY_MEM_RANGES_ATTRS ioctl. It describes memory attributes of - * a memory ranges within a user specified address range in a VM. + * memory ranges within a user specified address range in a VM. * * The structure includes information such as atomic access policy, * page attribute table (PAT) index, and preferred memory location. * Userspace allocates an array of these structures and passes a pointer to the - * ioctl to retrieve attributes for each memory ranges + * ioctl to retrieve attributes for each memory range. * * @extensions: Pointer to the first extension struct, if any * @start: Start address of the memory range @@ -2443,7 +2443,7 @@ struct drm_xe_mem_range_attr { * If second call fails with -ENOSPC, it means memory ranges changed between * first call and now, retry IOCTL again with @num_mem_ranges = 0, * @sizeof_mem_ranges_attr = 0 and @vector_of_vma_mem_attr = NULL followed by - * Second ioctl call. + * second ioctl call. * * Example: * -- cgit v1.2.3 From ea842c235828152258fc5197212e896bc59d7b83 Mon Sep 17 00:00:00 2001 From: Shuicheng Lin Date: Tue, 7 Apr 2026 03:00:43 +0000 Subject: drm/xe/uapi: Fix wrong names and references in xe_drm.h Fix incorrect field names, struct names, ioctl names, and descriptions in doc comments: - probed_size -> @cpu_visible_size (correct field name) - @flags description was copy of @placement -> fix to reference DRM_XE_GEM_CREATE_FLAG_* - %XE_PXP_HWDRM_DEFAULT_SESSION -> %DRM_XE_PXP_HWDRM_DEFAULT_SESSION (missing DRM_ prefix) - Remove undefined %DRM_XE_UFENCE_WAIT_FLAG_SOFT_OP - &DRM_XE_OBSERVATION -> &DRM_IOCTL_XE_OBSERVATION - id's/struct's -> IDs/structs (fix incorrect possessive forms) - drm_xe_query_oa_units -> drm_xe_oa_unit - DRM_IOCTL_XE_VM_QUERY_MEM_RANGES_ATTRS -> DRM_IOCTL_XE_VM_QUERY_MEM_RANGE_ATTRS - DRM_IOCTL_XE_VM_QUERY_MEM_ATTRIBUTES -> DRM_IOCTL_XE_VM_QUERY_MEM_RANGE_ATTRS - @sizeof_mem_ranges_attr -> @sizeof_mem_range_attr - @vector_of_vma_mem_attr -> @vector_of_mem_attr v3: id -> ID. (Xin) split cross-reference fix to seperate patch. Assisted-by: GitHub Copilot:claude-opus-4.6 Cc: Xin Wang Reviewed-by: Xin Wang Link: https://patch.msgid.link/20260407030046.3394004-4-shuicheng.lin@intel.com Signed-off-by: Shuicheng Lin --- include/uapi/drm/xe_drm.h | 26 ++++++++++++-------------- 1 file changed, 12 insertions(+), 14 deletions(-) diff --git a/include/uapi/drm/xe_drm.h b/include/uapi/drm/xe_drm.h index 1d3406416d8c..ad8e3b69a3d7 100644 --- a/include/uapi/drm/xe_drm.h +++ b/include/uapi/drm/xe_drm.h @@ -349,7 +349,7 @@ struct drm_xe_mem_region { * is smaller than @total_size then this is referred to as a * small BAR system. * - * On systems without small BAR (full BAR), the probed_size will + * On systems without small BAR (full BAR), the @cpu_visible_size will * always equal the @total_size, since all of it will be CPU * accessible. * @@ -862,8 +862,7 @@ struct drm_xe_gem_create { #define DRM_XE_GEM_CREATE_FLAG_NEEDS_VISIBLE_VRAM (1 << 2) #define DRM_XE_GEM_CREATE_FLAG_NO_COMPRESSION (1 << 3) /** - * @flags: Flags, currently a mask of memory instances of where BO can - * be placed + * @flags: Flags for the GEM object, see DRM_XE_GEM_CREATE_FLAG_* */ __u32 flags; @@ -1366,7 +1365,7 @@ struct drm_xe_vm_get_property { * drm_xe_pxp_session_type. %DRM_XE_PXP_TYPE_NONE is the default behavior, so * there is no need to explicitly set that. When a queue of type * %DRM_XE_PXP_TYPE_HWDRM is created, the PXP default HWDRM session - * (%XE_PXP_HWDRM_DEFAULT_SESSION) will be started, if it isn't already running. + * (%DRM_XE_PXP_HWDRM_DEFAULT_SESSION) will be started, if it isn't already running. * The user is expected to query the PXP status via the query ioctl (see * %DRM_XE_DEVICE_QUERY_PXP_STATUS) and to wait for PXP to be ready before * attempting to create a queue with this property. When a queue is created @@ -1651,7 +1650,6 @@ struct drm_xe_exec { * * and the @flags can be: * - %DRM_XE_UFENCE_WAIT_FLAG_ABSTIME - * - %DRM_XE_UFENCE_WAIT_FLAG_SOFT_OP * * The @mask values can be for example: * - 0xffu for u8 @@ -1741,7 +1739,7 @@ enum drm_xe_observation_op { }; /** - * struct drm_xe_observation_param - Input of &DRM_XE_OBSERVATION + * struct drm_xe_observation_param - Input of &DRM_IOCTL_XE_OBSERVATION * * The observation layer enables multiplexing observation streams of * multiple types. The actual params for a particular stream operation are @@ -1902,10 +1900,10 @@ enum drm_xe_oa_format_type { }; /** - * enum drm_xe_oa_property_id - OA stream property id's + * enum drm_xe_oa_property_id - OA stream property IDs * * Stream params are specified as a chain of @drm_xe_ext_set_property - * struct's, with @property values from enum @drm_xe_oa_property_id and + * structs, with @property values from enum @drm_xe_oa_property_id and * @drm_xe_user_extension base.name set to @DRM_XE_OA_EXTENSION_SET_PROPERTY. * @param field in struct @drm_xe_observation_param points to the first * @drm_xe_ext_set_property struct. @@ -1919,7 +1917,7 @@ enum drm_xe_oa_property_id { /** * @DRM_XE_OA_PROPERTY_OA_UNIT_ID: ID of the OA unit on which to open * the OA stream, see @oa_unit_id in 'struct - * drm_xe_query_oa_units'. Defaults to 0 if not provided. + * drm_xe_oa_unit'. Defaults to 0 if not provided. */ DRM_XE_OA_PROPERTY_OA_UNIT_ID = 1, @@ -2369,10 +2367,10 @@ struct drm_xe_madvise { }; /** - * struct drm_xe_mem_range_attr - Output of &DRM_IOCTL_XE_VM_QUERY_MEM_RANGES_ATTRS + * struct drm_xe_mem_range_attr - Output of &DRM_IOCTL_XE_VM_QUERY_MEM_RANGE_ATTRS * * This structure is provided by userspace and filled by KMD in response to the - * DRM_IOCTL_XE_VM_QUERY_MEM_RANGES_ATTRS ioctl. It describes memory attributes of + * DRM_IOCTL_XE_VM_QUERY_MEM_RANGE_ATTRS ioctl. It describes memory attributes of * memory ranges within a user specified address range in a VM. * * The structure includes information such as atomic access policy, @@ -2427,7 +2425,7 @@ struct drm_xe_mem_range_attr { }; /** - * struct drm_xe_vm_query_mem_range_attr - Input of &DRM_IOCTL_XE_VM_QUERY_MEM_ATTRIBUTES + * struct drm_xe_vm_query_mem_range_attr - Input of &DRM_IOCTL_XE_VM_QUERY_MEM_RANGE_ATTRS * * This structure is used to query memory attributes of memory regions * within a user specified address range in a VM. It provides detailed @@ -2435,14 +2433,14 @@ struct drm_xe_mem_range_attr { * page attribute table (PAT) index, and preferred memory location. * * Userspace first calls the ioctl with @num_mem_ranges = 0, - * @sizeof_mem_ranges_attr = 0 and @vector_of_vma_mem_attr = NULL to retrieve + * @sizeof_mem_range_attr = 0 and @vector_of_mem_attr = NULL to retrieve * the number of memory regions and size of each memory range attribute. * Then, it allocates a buffer of that size and calls the ioctl again to fill * the buffer with memory range attributes. * * If second call fails with -ENOSPC, it means memory ranges changed between * first call and now, retry IOCTL again with @num_mem_ranges = 0, - * @sizeof_mem_ranges_attr = 0 and @vector_of_vma_mem_attr = NULL followed by + * @sizeof_mem_range_attr = 0 and @vector_of_mem_attr = NULL followed by * second ioctl call. * * Example: -- cgit v1.2.3 From 4bd87e7c4d467ce1f9e3b56abebeffc2ba45a2fb Mon Sep 17 00:00:00 2001 From: Shuicheng Lin Date: Tue, 7 Apr 2026 03:00:44 +0000 Subject: drm/xe/uapi: Fix kernel-doc cross-reference syntax in xe_drm.h Fix incorrect kernel-doc cross-reference markup syntax throughout xe_drm.h: - @struct_name -> &struct name for cross-references to other structs (19 occurrences) - struct @name -> &struct name where struct keyword was mixed with @ syntax (8 occurrences) - enum @name -> &enum name for cross-references to other enums (5 occurrences) - &CONSTANT / @CONSTANT -> %CONSTANT for defines and enum values (15 occurrences) - @field references to members of other structs -> plain text, since @ only applies to the current struct's members (9 occurrences) Per kernel-doc conventions (Documentation/doc-guide/kernel-doc.rst): - '&struct name' creates hyperlinks to struct definitions - '&enum name' creates hyperlinks to enum definitions - '%NAME' references constants and defines - '@name' is only for parameters/members of the current context Assisted-by: GitHub Copilot:claude-opus-4.6 Suggested-by: Xin Wang Reviewed-by: Xin Wang Link: https://patch.msgid.link/20260407030046.3394004-5-shuicheng.lin@intel.com Signed-off-by: Shuicheng Lin --- include/uapi/drm/xe_drm.h | 106 +++++++++++++++++++++++----------------------- 1 file changed, 53 insertions(+), 53 deletions(-) diff --git a/include/uapi/drm/xe_drm.h b/include/uapi/drm/xe_drm.h index ad8e3b69a3d7..8751ad7b845f 100644 --- a/include/uapi/drm/xe_drm.h +++ b/include/uapi/drm/xe_drm.h @@ -229,9 +229,9 @@ struct drm_xe_ext_set_property { /** * struct drm_xe_engine_class_instance - instance of an engine class * - * It is returned as part of the @drm_xe_engine, but it also is used as - * the input of engine selection for both @drm_xe_exec_queue_create and - * @drm_xe_query_engine_cycles + * It is returned as part of the &struct drm_xe_engine, but it also is used as + * the input of engine selection for both &struct drm_xe_exec_queue_create and + * &struct drm_xe_query_engine_cycles * * The @engine_class can be: * - %DRM_XE_ENGINE_CLASS_RENDER @@ -264,7 +264,7 @@ struct drm_xe_engine_class_instance { * struct drm_xe_engine - describe hardware engine */ struct drm_xe_engine { - /** @instance: The @drm_xe_engine_class_instance */ + /** @instance: The &struct drm_xe_engine_class_instance */ struct drm_xe_engine_class_instance instance; /** @reserved: Reserved */ @@ -274,9 +274,9 @@ struct drm_xe_engine { /** * struct drm_xe_query_engines - describe engines * - * If a query is made with a struct @drm_xe_device_query where .query + * If a query is made with a &struct drm_xe_device_query where .query * is equal to %DRM_XE_DEVICE_QUERY_ENGINES, then the reply uses an array of - * struct @drm_xe_query_engines in .data. + * &struct drm_xe_query_engines in .data. */ struct drm_xe_query_engines { /** @num_engines: number of engines returned in @engines */ @@ -825,7 +825,7 @@ struct drm_xe_device_query { * * This ioctl supports setting the following properties via the * %DRM_XE_GEM_CREATE_EXTENSION_SET_PROPERTY extension, which uses the - * generic @drm_xe_ext_set_property struct: + * generic &struct drm_xe_ext_set_property: * * - %DRM_XE_GEM_CREATE_SET_PROPERTY_PXP_TYPE - set the type of PXP session * this object will be used with. Valid values are listed in enum @@ -1198,10 +1198,10 @@ struct drm_xe_vm_bind_op { /** * struct drm_xe_vm_bind - Input of &DRM_IOCTL_XE_VM_BIND * - * Below is an example of a minimal use of @drm_xe_vm_bind to + * Below is an example of a minimal use of &struct drm_xe_vm_bind to * asynchronously bind the buffer `data` at address `BIND_ADDRESS` to * illustrate `userptr`. It can be synchronized by using the example - * provided for @drm_xe_sync. + * provided for &struct drm_xe_sync. * * .. code-block:: C * @@ -1354,7 +1354,7 @@ struct drm_xe_vm_get_property { * * This ioctl supports setting the following properties via the * %DRM_XE_EXEC_QUEUE_EXTENSION_SET_PROPERTY extension, which uses the - * generic @drm_xe_ext_set_property struct: + * generic &struct drm_xe_ext_set_property: * * - %DRM_XE_EXEC_QUEUE_SET_PROPERTY_PRIORITY - set the queue priority. * CAP_SYS_NICE is required to set a value above normal. @@ -1389,9 +1389,9 @@ struct drm_xe_vm_get_property { * enable render color cache keying on BTP+BTI instead of just BTI * (only valid for render queues). * - * The example below shows how to use @drm_xe_exec_queue_create to create + * The example below shows how to use &struct drm_xe_exec_queue_create to create * a simple exec_queue (no parallel submission) of class - * &DRM_XE_ENGINE_CLASS_RENDER. + * %DRM_XE_ENGINE_CLASS_RENDER. * * .. code-block:: C * @@ -1514,7 +1514,7 @@ struct drm_xe_exec_queue_get_property { * and the @flags can be: * - %DRM_XE_SYNC_FLAG_SIGNAL * - * A minimal use of @drm_xe_sync looks like this: + * A minimal use of &struct drm_xe_sync looks like this: * * .. code-block:: C * @@ -1580,10 +1580,10 @@ struct drm_xe_sync { /** * struct drm_xe_exec - Input of &DRM_IOCTL_XE_EXEC * - * This is an example to use @drm_xe_exec for execution of the object - * at BIND_ADDRESS (see example in @drm_xe_vm_bind) by an exec_queue - * (see example in @drm_xe_exec_queue_create). It can be synchronized - * by using the example provided for @drm_xe_sync. + * This is an example to use &struct drm_xe_exec for execution of the object + * at BIND_ADDRESS (see example in &struct drm_xe_vm_bind) by an exec_queue + * (see example in &struct drm_xe_exec_queue_create). It can be synchronized + * by using the example provided for &struct drm_xe_sync. * * .. code-block:: C * @@ -1749,9 +1749,9 @@ enum drm_xe_observation_op { struct drm_xe_observation_param { /** @extensions: Pointer to the first extension struct, if any */ __u64 extensions; - /** @observation_type: observation stream type, of enum @drm_xe_observation_type */ + /** @observation_type: observation stream type, of &enum drm_xe_observation_type */ __u64 observation_type; - /** @observation_op: observation stream op, of enum @drm_xe_observation_op */ + /** @observation_op: observation stream op, of &enum drm_xe_observation_op */ __u64 observation_op; /** @param: Pointer to actual stream params */ __u64 param; @@ -1810,7 +1810,7 @@ struct drm_xe_oa_unit { /** @oa_unit_id: OA unit ID */ __u32 oa_unit_id; - /** @oa_unit_type: OA unit type of @drm_xe_oa_unit_type */ + /** @oa_unit_type: OA unit type of &enum drm_xe_oa_unit_type */ __u32 oa_unit_type; /** @capabilities: OA capabilities bit-mask */ @@ -1873,7 +1873,7 @@ struct drm_xe_query_oa_units { /** @pad: MBZ */ __u32 pad; /** - * @oa_units: struct @drm_xe_oa_unit array returned for this device. + * @oa_units: &struct drm_xe_oa_unit array returned for this device. * Written below as a u64 array to avoid problems with nested flexible * arrays with some compilers */ @@ -1902,22 +1902,22 @@ enum drm_xe_oa_format_type { /** * enum drm_xe_oa_property_id - OA stream property IDs * - * Stream params are specified as a chain of @drm_xe_ext_set_property - * structs, with @property values from enum @drm_xe_oa_property_id and - * @drm_xe_user_extension base.name set to @DRM_XE_OA_EXTENSION_SET_PROPERTY. - * @param field in struct @drm_xe_observation_param points to the first - * @drm_xe_ext_set_property struct. + * Stream params are specified as a chain of &struct drm_xe_ext_set_property + * structs, with property values from &enum drm_xe_oa_property_id and + * &struct drm_xe_user_extension base.name set to %DRM_XE_OA_EXTENSION_SET_PROPERTY. + * The param field in &struct drm_xe_observation_param points to the first + * &struct drm_xe_ext_set_property struct. * * Exactly the same mechanism is also used for stream reconfiguration using the - * @DRM_XE_OBSERVATION_IOCTL_CONFIG observation stream fd ioctl, though only a + * %DRM_XE_OBSERVATION_IOCTL_CONFIG observation stream fd ioctl, though only a * subset of properties below can be specified for stream reconfiguration. */ enum drm_xe_oa_property_id { #define DRM_XE_OA_EXTENSION_SET_PROPERTY 0 /** * @DRM_XE_OA_PROPERTY_OA_UNIT_ID: ID of the OA unit on which to open - * the OA stream, see @oa_unit_id in 'struct - * drm_xe_oa_unit'. Defaults to 0 if not provided. + * the OA stream, see oa_unit_id in &struct drm_xe_oa_unit. + * Defaults to 0 if not provided. */ DRM_XE_OA_PROPERTY_OA_UNIT_ID = 1, @@ -1930,7 +1930,7 @@ enum drm_xe_oa_property_id { /** * @DRM_XE_OA_PROPERTY_OA_METRIC_SET: OA metrics defining contents of OA - * reports, previously added via @DRM_XE_OBSERVATION_OP_ADD_CONFIG. + * reports, previously added via %DRM_XE_OBSERVATION_OP_ADD_CONFIG. */ DRM_XE_OA_PROPERTY_OA_METRIC_SET, @@ -1938,7 +1938,7 @@ enum drm_xe_oa_property_id { DRM_XE_OA_PROPERTY_OA_FORMAT, /* * OA_FORMAT's are specified the same way as in PRM/Bspec 52198/60942, - * in terms of the following quantities: a. enum @drm_xe_oa_format_type + * in terms of the following quantities: a. &enum drm_xe_oa_format_type * b. Counter select c. Counter size and d. BC report. Also refer to the * oa_formats array in drivers/gpu/drm/xe/xe_oa.c. */ @@ -1955,19 +1955,19 @@ enum drm_xe_oa_property_id { /** * @DRM_XE_OA_PROPERTY_OA_DISABLED: A value of 1 will open the OA - * stream in a DISABLED state (see @DRM_XE_OBSERVATION_IOCTL_ENABLE). + * stream in a DISABLED state (see %DRM_XE_OBSERVATION_IOCTL_ENABLE). */ DRM_XE_OA_PROPERTY_OA_DISABLED, /** * @DRM_XE_OA_PROPERTY_EXEC_QUEUE_ID: Open the stream for a specific - * @exec_queue_id. OA queries can be executed on this exec queue. + * exec_queue_id. OA queries can be executed on this exec queue. */ DRM_XE_OA_PROPERTY_EXEC_QUEUE_ID, /** * @DRM_XE_OA_PROPERTY_OA_ENGINE_INSTANCE: Optional engine instance to - * pass along with @DRM_XE_OA_PROPERTY_EXEC_QUEUE_ID or will default to 0. + * pass along with %DRM_XE_OA_PROPERTY_EXEC_QUEUE_ID or will default to 0. */ DRM_XE_OA_PROPERTY_OA_ENGINE_INSTANCE, @@ -1979,16 +1979,16 @@ enum drm_xe_oa_property_id { /** * @DRM_XE_OA_PROPERTY_NUM_SYNCS: Number of syncs in the sync array - * specified in @DRM_XE_OA_PROPERTY_SYNCS + * specified in %DRM_XE_OA_PROPERTY_SYNCS */ DRM_XE_OA_PROPERTY_NUM_SYNCS, /** - * @DRM_XE_OA_PROPERTY_SYNCS: Pointer to struct @drm_xe_sync array - * with array size specified via @DRM_XE_OA_PROPERTY_NUM_SYNCS. OA + * @DRM_XE_OA_PROPERTY_SYNCS: Pointer to &struct drm_xe_sync array + * with array size specified via %DRM_XE_OA_PROPERTY_NUM_SYNCS. OA * configuration will wait till input fences signal. Output fences * will signal after the new OA configuration takes effect. For - * @DRM_XE_SYNC_TYPE_USER_FENCE, @addr is a user pointer, similar + * %DRM_XE_SYNC_TYPE_USER_FENCE, addr is a user pointer, similar * to the VM bind case. */ DRM_XE_OA_PROPERTY_SYNCS, @@ -2011,9 +2011,9 @@ enum drm_xe_oa_property_id { /** * struct drm_xe_oa_config - OA metric configuration * - * Multiple OA configs can be added using @DRM_XE_OBSERVATION_OP_ADD_CONFIG. A + * Multiple OA configs can be added using %DRM_XE_OBSERVATION_OP_ADD_CONFIG. A * particular config can be specified when opening an OA stream using - * @DRM_XE_OA_PROPERTY_OA_METRIC_SET property. + * %DRM_XE_OA_PROPERTY_OA_METRIC_SET property. */ struct drm_xe_oa_config { /** @extensions: Pointer to the first extension struct, if any */ @@ -2034,7 +2034,7 @@ struct drm_xe_oa_config { /** * struct drm_xe_oa_stream_status - OA stream status returned from - * @DRM_XE_OBSERVATION_IOCTL_STATUS observation stream fd ioctl. Userspace can + * %DRM_XE_OBSERVATION_IOCTL_STATUS observation stream fd ioctl. Userspace can * call the ioctl to query stream status in response to EIO errno from * observation fd read(). */ @@ -2055,7 +2055,7 @@ struct drm_xe_oa_stream_status { /** * struct drm_xe_oa_stream_info - OA stream info returned from - * @DRM_XE_OBSERVATION_IOCTL_INFO observation stream fd ioctl + * %DRM_XE_OBSERVATION_IOCTL_INFO observation stream fd ioctl */ struct drm_xe_oa_stream_info { /** @extensions: Pointer to the first extension struct, if any */ @@ -2092,27 +2092,27 @@ enum drm_xe_pxp_session_type { * enum drm_xe_eu_stall_property_id - EU stall sampling input property ids. * * These properties are passed to the driver at open as a chain of - * @drm_xe_ext_set_property structures with @property set to these - * properties' enums and @value set to the corresponding values of these - * properties. @drm_xe_user_extension base.name should be set to - * @DRM_XE_EU_STALL_EXTENSION_SET_PROPERTY. + * &struct drm_xe_ext_set_property structures with property set to these + * properties' enums and value set to the corresponding values of these + * properties. &struct drm_xe_user_extension base.name should be set to + * %DRM_XE_EU_STALL_EXTENSION_SET_PROPERTY. * * With the file descriptor obtained from open, user space must enable - * the EU stall stream fd with @DRM_XE_OBSERVATION_IOCTL_ENABLE before + * the EU stall stream fd with %DRM_XE_OBSERVATION_IOCTL_ENABLE before * calling read(). EIO errno from read() indicates HW dropped data * due to full buffer. */ enum drm_xe_eu_stall_property_id { #define DRM_XE_EU_STALL_EXTENSION_SET_PROPERTY 0 /** - * @DRM_XE_EU_STALL_PROP_GT_ID: @gt_id of the GT on which + * @DRM_XE_EU_STALL_PROP_GT_ID: gt_id of the GT on which * EU stall data will be captured. */ DRM_XE_EU_STALL_PROP_GT_ID = 1, /** * @DRM_XE_EU_STALL_PROP_SAMPLE_RATE: Sampling rate in - * GPU cycles from @sampling_rates in struct @drm_xe_query_eu_stall + * GPU cycles from sampling_rates in &struct drm_xe_query_eu_stall */ DRM_XE_EU_STALL_PROP_SAMPLE_RATE, @@ -2127,9 +2127,9 @@ enum drm_xe_eu_stall_property_id { /** * struct drm_xe_query_eu_stall - Information about EU stall sampling. * - * If a query is made with a struct @drm_xe_device_query where .query - * is equal to @DRM_XE_DEVICE_QUERY_EU_STALL, then the reply uses - * struct @drm_xe_query_eu_stall in .data. + * If a query is made with a &struct drm_xe_device_query where .query + * is equal to %DRM_XE_DEVICE_QUERY_EU_STALL, then the reply uses + * &struct drm_xe_query_eu_stall in .data. */ struct drm_xe_query_eu_stall { /** @extensions: Pointer to the first extension struct, if any */ @@ -2240,7 +2240,7 @@ struct drm_xe_madvise { /** * @preferred_mem_loc.region_instance : Region instance. - * MBZ if @devmem_fd <= &DRM_XE_PREFERRED_LOC_DEFAULT_DEVICE. + * MBZ if @devmem_fd <= %DRM_XE_PREFERRED_LOC_DEFAULT_DEVICE. * Otherwise should point to the desired device * VRAM instance of the device indicated by * @preferred_mem_loc.devmem_fd. -- cgit v1.2.3 From 96cc9d79df5f7092c3807fad0d2fc3415cbd66b2 Mon Sep 17 00:00:00 2001 From: Shuicheng Lin Date: Tue, 7 Apr 2026 03:00:45 +0000 Subject: drm/xe/uapi: Fix code examples in xe_drm.h documentation Fix incorrect field names and formatting in code examples: - .num_bb_per_exec -> .width (renamed struct field in exec_queue_create examples) - .num_eng_per_bb -> .num_placements (renamed struct field in exec_queue_create examples) - .atomic_val -> .atomic.val (correct nested struct field access in madvise example) - Remove unnecessary backslash escaping in UUID format string (%\08x -> %08x) - Fix descriptive text trapped inside code-block in exec_queue_create doc (split into two code blocks) v3: one more fix of split code-block in exec_queue_create doc. Assisted-by: GitHub Copilot:claude-opus-4.6 Cc: Xin Wang Reviewed-by: Xin Wang Link: https://patch.msgid.link/20260407030046.3394004-6-shuicheng.lin@intel.com Signed-off-by: Shuicheng Lin --- include/uapi/drm/xe_drm.h | 22 ++++++++++++---------- 1 file changed, 12 insertions(+), 10 deletions(-) diff --git a/include/uapi/drm/xe_drm.h b/include/uapi/drm/xe_drm.h index 8751ad7b845f..58614f62d65b 100644 --- a/include/uapi/drm/xe_drm.h +++ b/include/uapi/drm/xe_drm.h @@ -1401,23 +1401,25 @@ struct drm_xe_vm_get_property { * struct drm_xe_exec_queue_create exec_queue_create = { * .extensions = 0, * .vm_id = vm, - * .num_bb_per_exec = 1, - * .num_eng_per_bb = 1, + * .width = 1, + * .num_placements = 1, * .instances = to_user_pointer(&instance), * }; * ioctl(fd, DRM_IOCTL_XE_EXEC_QUEUE_CREATE, &exec_queue_create); * - * Allow users to provide a hint to kernel for cases demanding low latency - * profile. Please note it will have impact on power consumption. User can - * indicate low latency hint with flag while creating exec queue as - * mentioned below, + * Allow users to provide a hint to kernel for cases demanding low latency + * profile. Please note it will have impact on power consumption. User can + * indicate low latency hint with flag while creating exec queue as + * mentioned below: + * + * .. code-block:: C * * struct drm_xe_exec_queue_create exec_queue_create = { * .flags = DRM_XE_EXEC_QUEUE_LOW_LATENCY_HINT, * .extensions = 0, * .vm_id = vm, - * .num_bb_per_exec = 1, - * .num_eng_per_bb = 1, + * .width = 1, + * .num_placements = 1, * .instances = to_user_pointer(&instance), * }; * ioctl(fd, DRM_IOCTL_XE_EXEC_QUEUE_CREATE, &exec_queue_create); @@ -2019,7 +2021,7 @@ struct drm_xe_oa_config { /** @extensions: Pointer to the first extension struct, if any */ __u64 extensions; - /** @uuid: String formatted like "%\08x-%\04x-%\04x-%\04x-%\012x" */ + /** @uuid: String formatted like "%08x-%04x-%04x-%04x-%012x" */ char uuid[36]; /** @n_regs: Number of regs in @regs_ptr */ @@ -2181,7 +2183,7 @@ struct drm_xe_query_eu_stall { * .start = 0x100000, * .range = 0x2000, * .type = DRM_XE_MEM_RANGE_ATTR_ATOMIC, - * .atomic_val = DRM_XE_ATOMIC_DEVICE, + * .atomic.val = DRM_XE_ATOMIC_DEVICE, * }; * * ioctl(fd, DRM_IOCTL_XE_MADVISE, &madvise); -- cgit v1.2.3 From 5150b57dacf9563ab29661c8e8a37a73f5a9fc54 Mon Sep 17 00:00:00 2001 From: Shuicheng Lin Date: Tue, 7 Apr 2026 03:00:46 +0000 Subject: drm/xe/uapi: Fix doc formatting and completeness in xe_drm.h - Fix missing leading space before closing */ in comment block - Add DRM_IOCTL_XE_EXEC_QUEUE_SET_PROPERTY to the IOCTL overview list - Add missing query types to the device query doc list: DRM_XE_DEVICE_QUERY_UC_FW_VERSION, DRM_XE_DEVICE_QUERY_OA_UNITS, DRM_XE_DEVICE_QUERY_EU_STALL - Fix ioctl's -> ioctls (not possessive, 2 occurrences) - Remove duplicate parameter docs from drm_xe_mem_range_attr overview (already documented as inline member comments) - Fix extra whitespace before /** on 2 lines in drm_xe_mem_range_attr - Add missing blank line before DRM_XE_VM_BIND_FLAG_DECOMPRESS bullet to fix RST block quote warning v3: more fix (item 4 to 7). Assisted-by: GitHub Copilot:claude-opus-4.6 Cc: Xin Wang Reviewed-by: Xin Wang Link: https://patch.msgid.link/20260407030046.3394004-7-shuicheng.lin@intel.com Signed-off-by: Shuicheng Lin --- include/uapi/drm/xe_drm.h | 20 ++++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/include/uapi/drm/xe_drm.h b/include/uapi/drm/xe_drm.h index 58614f62d65b..48e9f1fdb78d 100644 --- a/include/uapi/drm/xe_drm.h +++ b/include/uapi/drm/xe_drm.h @@ -83,6 +83,7 @@ extern "C" { * - &DRM_IOCTL_XE_OBSERVATION * - &DRM_IOCTL_XE_MADVISE * - &DRM_IOCTL_XE_VM_QUERY_MEM_RANGE_ATTRS + * - &DRM_IOCTL_XE_EXEC_QUEUE_SET_PROPERTY * - &DRM_IOCTL_XE_VM_GET_PROPERTY */ @@ -167,7 +168,7 @@ extern "C" { * Typically the struct drm_xe_user_extension would be embedded in some uAPI * struct, and in this case we would feed it the head of the chain(i.e ext1), * which would then apply all of the above extensions. -*/ + */ /** * struct drm_xe_user_extension - Base class for defining a chain of extensions @@ -705,7 +706,10 @@ struct drm_xe_query_pxp_status { * attributes. * - %DRM_XE_DEVICE_QUERY_GT_TOPOLOGY * - %DRM_XE_DEVICE_QUERY_ENGINE_CYCLES + * - %DRM_XE_DEVICE_QUERY_UC_FW_VERSION + * - %DRM_XE_DEVICE_QUERY_OA_UNITS * - %DRM_XE_DEVICE_QUERY_PXP_STATUS + * - %DRM_XE_DEVICE_QUERY_EU_STALL * * If size is set to 0, the driver fills it with the required size for * the requested type of data to query. If size is equal to the required @@ -1060,6 +1064,7 @@ struct drm_xe_vm_destroy { * not invoke autoreset. Neither will stack variables going out of scope. * Therefore it's recommended to always explicitly reset the madvises when * freeing the memory backing a region used in a &DRM_IOCTL_XE_MADVISE call. + * * - %DRM_XE_VM_BIND_FLAG_DECOMPRESS - Request on-device decompression for a MAP. * When set on a MAP bind operation, request the driver schedule an on-device * in-place decompression (via the migrate/resolve path) for the GPU mapping @@ -1760,10 +1765,10 @@ struct drm_xe_observation_param { }; /** - * enum drm_xe_observation_ioctls - Observation stream fd ioctl's + * enum drm_xe_observation_ioctls - Observation stream fd ioctls * * Information exchanged between userspace and kernel for observation fd - * ioctl's is stream type specific + * ioctls is stream type specific */ enum drm_xe_observation_ioctls { /** @DRM_XE_OBSERVATION_IOCTL_ENABLE: Enable data capture for an observation stream */ @@ -2379,14 +2384,9 @@ struct drm_xe_madvise { * page attribute table (PAT) index, and preferred memory location. * Userspace allocates an array of these structures and passes a pointer to the * ioctl to retrieve attributes for each memory range. - * - * @extensions: Pointer to the first extension struct, if any - * @start: Start address of the memory range - * @end: End address of the virtual memory range - * */ struct drm_xe_mem_range_attr { - /** @extensions: Pointer to the first extension struct, if any */ + /** @extensions: Pointer to the first extension struct, if any */ __u64 extensions; /** @start: start of the memory range */ @@ -2413,7 +2413,7 @@ struct drm_xe_mem_range_attr { __u32 reserved; } atomic; - /** @pat_index: Page attribute table index */ + /** @pat_index: Page attribute table index */ struct { /** @pat_index.val: PAT index */ __u32 val; -- cgit v1.2.3 From ea8e356acb165cb1fd75537a52e1f66e5e76c538 Mon Sep 17 00:00:00 2001 From: Maurizio Lombardi Date: Mon, 16 Mar 2026 15:39:35 +0100 Subject: nvmet-tcp: propagate nvmet_tcp_build_pdu_iovec() errors to its callers Currently, when nvmet_tcp_build_pdu_iovec() detects an out-of-bounds PDU length or offset, it triggers nvmet_tcp_fatal_error(cmd->queue) and returns early. However, because the function returns void, the callers are entirely unaware that a fatal error has occurred and that the cmd->recv_msg.msg_iter was left uninitialized. Callers such as nvmet_tcp_handle_h2c_data_pdu() proceed to blindly overwrite the queue state with queue->rcv_state = NVMET_TCP_RECV_DATA Consequently, the socket receiving loop may attempt to read incoming network data into the uninitialized iterator. Fix this by shifting the error handling responsibility to the callers. Fixes: 52a0a9854934 ("nvmet-tcp: add bounds checks in nvmet_tcp_build_pdu_iovec") Reviewed-by: Hannes Reinecke Reviewed-by: Yunje Shin Reviewed-by: Chaitanya Kulkarni Signed-off-by: Maurizio Lombardi Signed-off-by: Keith Busch --- drivers/nvme/target/tcp.c | 51 +++++++++++++++++++++++++++-------------------- 1 file changed, 29 insertions(+), 22 deletions(-) diff --git a/drivers/nvme/target/tcp.c b/drivers/nvme/target/tcp.c index 69e971b179ae..3ade734c8bcf 100644 --- a/drivers/nvme/target/tcp.c +++ b/drivers/nvme/target/tcp.c @@ -351,7 +351,7 @@ static void nvmet_tcp_free_cmd_buffers(struct nvmet_tcp_cmd *cmd) static void nvmet_tcp_fatal_error(struct nvmet_tcp_queue *queue); -static void nvmet_tcp_build_pdu_iovec(struct nvmet_tcp_cmd *cmd) +static int nvmet_tcp_build_pdu_iovec(struct nvmet_tcp_cmd *cmd) { struct bio_vec *iov = cmd->iov; struct scatterlist *sg; @@ -364,22 +364,19 @@ static void nvmet_tcp_build_pdu_iovec(struct nvmet_tcp_cmd *cmd) offset = cmd->rbytes_done; cmd->sg_idx = offset / PAGE_SIZE; sg_offset = offset % PAGE_SIZE; - if (!cmd->req.sg_cnt || cmd->sg_idx >= cmd->req.sg_cnt) { - nvmet_tcp_fatal_error(cmd->queue); - return; - } + if (!cmd->req.sg_cnt || cmd->sg_idx >= cmd->req.sg_cnt) + return -EPROTO; + sg = &cmd->req.sg[cmd->sg_idx]; sg_remaining = cmd->req.sg_cnt - cmd->sg_idx; while (length) { - if (!sg_remaining) { - nvmet_tcp_fatal_error(cmd->queue); - return; - } - if (!sg->length || sg->length <= sg_offset) { - nvmet_tcp_fatal_error(cmd->queue); - return; - } + if (!sg_remaining) + return -EPROTO; + + if (!sg->length || sg->length <= sg_offset) + return -EPROTO; + u32 iov_len = min_t(u32, length, sg->length - sg_offset); bvec_set_page(iov, sg_page(sg), iov_len, @@ -394,6 +391,7 @@ static void nvmet_tcp_build_pdu_iovec(struct nvmet_tcp_cmd *cmd) iov_iter_bvec(&cmd->recv_msg.msg_iter, ITER_DEST, cmd->iov, nr_pages, cmd->pdu_len); + return 0; } static void nvmet_tcp_fatal_error(struct nvmet_tcp_queue *queue) @@ -931,7 +929,7 @@ static int nvmet_tcp_handle_icreq(struct nvmet_tcp_queue *queue) return 0; } -static void nvmet_tcp_handle_req_failure(struct nvmet_tcp_queue *queue, +static int nvmet_tcp_handle_req_failure(struct nvmet_tcp_queue *queue, struct nvmet_tcp_cmd *cmd, struct nvmet_req *req) { size_t data_len = le32_to_cpu(req->cmd->common.dptr.sgl.length); @@ -947,19 +945,23 @@ static void nvmet_tcp_handle_req_failure(struct nvmet_tcp_queue *queue, if (!nvme_is_write(cmd->req.cmd) || !data_len || data_len > cmd->req.port->inline_data_size) { nvmet_prepare_receive_pdu(queue); - return; + return 0; } ret = nvmet_tcp_map_data(cmd); if (unlikely(ret)) { pr_err("queue %d: failed to map data\n", queue->idx); nvmet_tcp_fatal_error(queue); - return; + return -EPROTO; } queue->rcv_state = NVMET_TCP_RECV_DATA; - nvmet_tcp_build_pdu_iovec(cmd); cmd->flags |= NVMET_TCP_F_INIT_FAILED; + ret = nvmet_tcp_build_pdu_iovec(cmd); + if (unlikely(ret)) + pr_err("queue %d: failed to build PDU iovec\n", queue->idx); + + return ret; } static int nvmet_tcp_handle_h2c_data_pdu(struct nvmet_tcp_queue *queue) @@ -1011,7 +1013,10 @@ static int nvmet_tcp_handle_h2c_data_pdu(struct nvmet_tcp_queue *queue) goto err_proto; } cmd->pdu_recv = 0; - nvmet_tcp_build_pdu_iovec(cmd); + if (unlikely(nvmet_tcp_build_pdu_iovec(cmd))) { + pr_err("queue %d: failed to build PDU iovec\n", queue->idx); + goto err_proto; + } queue->cmd = cmd; queue->rcv_state = NVMET_TCP_RECV_DATA; @@ -1074,8 +1079,7 @@ static int nvmet_tcp_done_recv_pdu(struct nvmet_tcp_queue *queue) le32_to_cpu(req->cmd->common.dptr.sgl.length), le16_to_cpu(req->cqe->status)); - nvmet_tcp_handle_req_failure(queue, queue->cmd, req); - return 0; + return nvmet_tcp_handle_req_failure(queue, queue->cmd, req); } ret = nvmet_tcp_map_data(queue->cmd); @@ -1092,8 +1096,11 @@ static int nvmet_tcp_done_recv_pdu(struct nvmet_tcp_queue *queue) if (nvmet_tcp_need_data_in(queue->cmd)) { if (nvmet_tcp_has_inline_data(queue->cmd)) { queue->rcv_state = NVMET_TCP_RECV_DATA; - nvmet_tcp_build_pdu_iovec(queue->cmd); - return 0; + ret = nvmet_tcp_build_pdu_iovec(queue->cmd); + if (unlikely(ret)) + pr_err("queue %d: failed to build PDU iovec\n", + queue->idx); + return ret; } /* send back R2T */ nvmet_tcp_queue_response(&queue->cmd->req); -- cgit v1.2.3 From bad44c9c312f07b590ad7be892a95693baba976e Mon Sep 17 00:00:00 2001 From: Maurizio Lombardi Date: Mon, 16 Mar 2026 15:39:36 +0100 Subject: nvmet-tcp: remove redundant calls to nvmet_tcp_fatal_error() Executing nvmet_tcp_fatal_error() is generally the responsibility of the caller (nvmet_tcp_try_recv); all other functions should just return the error code. Remove the nvmet_tcp_fatal_error() function, it's not needed anymore. Reviewed-by: Hannes Reinecke Reviewed-by: Chaitanya Kulkarni Signed-off-by: Maurizio Lombardi Signed-off-by: Keith Busch --- drivers/nvme/target/tcp.c | 37 +++++++------------------------------ 1 file changed, 7 insertions(+), 30 deletions(-) diff --git a/drivers/nvme/target/tcp.c b/drivers/nvme/target/tcp.c index 3ade734c8bcf..a4c3c62e33f5 100644 --- a/drivers/nvme/target/tcp.c +++ b/drivers/nvme/target/tcp.c @@ -349,8 +349,6 @@ static void nvmet_tcp_free_cmd_buffers(struct nvmet_tcp_cmd *cmd) cmd->req.sg = NULL; } -static void nvmet_tcp_fatal_error(struct nvmet_tcp_queue *queue); - static int nvmet_tcp_build_pdu_iovec(struct nvmet_tcp_cmd *cmd) { struct bio_vec *iov = cmd->iov; @@ -394,22 +392,13 @@ static int nvmet_tcp_build_pdu_iovec(struct nvmet_tcp_cmd *cmd) return 0; } -static void nvmet_tcp_fatal_error(struct nvmet_tcp_queue *queue) -{ - queue->rcv_state = NVMET_TCP_RECV_ERR; - if (queue->nvme_sq.ctrl) - nvmet_ctrl_fatal_error(queue->nvme_sq.ctrl); - else - kernel_sock_shutdown(queue->sock, SHUT_RDWR); -} - static void nvmet_tcp_socket_error(struct nvmet_tcp_queue *queue, int status) { queue->rcv_state = NVMET_TCP_RECV_ERR; - if (status == -EPIPE || status == -ECONNRESET) + if (status == -EPIPE || status == -ECONNRESET || !queue->nvme_sq.ctrl) kernel_sock_shutdown(queue->sock, SHUT_RDWR); else - nvmet_tcp_fatal_error(queue); + nvmet_ctrl_fatal_error(queue->nvme_sq.ctrl); } static int nvmet_tcp_map_data(struct nvmet_tcp_cmd *cmd) @@ -885,7 +874,6 @@ static int nvmet_tcp_handle_icreq(struct nvmet_tcp_queue *queue) if (le32_to_cpu(icreq->hdr.plen) != sizeof(struct nvme_tcp_icreq_pdu)) { pr_err("bad nvme-tcp pdu length (%d)\n", le32_to_cpu(icreq->hdr.plen)); - nvmet_tcp_fatal_error(queue); return -EPROTO; } @@ -951,7 +939,6 @@ static int nvmet_tcp_handle_req_failure(struct nvmet_tcp_queue *queue, ret = nvmet_tcp_map_data(cmd); if (unlikely(ret)) { pr_err("queue %d: failed to map data\n", queue->idx); - nvmet_tcp_fatal_error(queue); return -EPROTO; } @@ -1024,7 +1011,6 @@ static int nvmet_tcp_handle_h2c_data_pdu(struct nvmet_tcp_queue *queue) err_proto: /* FIXME: use proper transport errors */ - nvmet_tcp_fatal_error(queue); return -EPROTO; } @@ -1039,7 +1025,6 @@ static int nvmet_tcp_done_recv_pdu(struct nvmet_tcp_queue *queue) if (hdr->type != nvme_tcp_icreq) { pr_err("unexpected pdu type (%d) before icreq\n", hdr->type); - nvmet_tcp_fatal_error(queue); return -EPROTO; } return nvmet_tcp_handle_icreq(queue); @@ -1048,7 +1033,6 @@ static int nvmet_tcp_done_recv_pdu(struct nvmet_tcp_queue *queue) if (unlikely(hdr->type == nvme_tcp_icreq)) { pr_err("queue %d: received icreq pdu in state %d\n", queue->idx, queue->state); - nvmet_tcp_fatal_error(queue); return -EPROTO; } @@ -1065,7 +1049,6 @@ static int nvmet_tcp_done_recv_pdu(struct nvmet_tcp_queue *queue) pr_err("queue %d: out of commands (%d) send_list_len: %d, opcode: %d", queue->idx, queue->nr_cmds, queue->send_list_len, nvme_cmd->common.opcode); - nvmet_tcp_fatal_error(queue); return -ENOMEM; } @@ -1086,9 +1069,9 @@ static int nvmet_tcp_done_recv_pdu(struct nvmet_tcp_queue *queue) if (unlikely(ret)) { pr_err("queue %d: failed to map data\n", queue->idx); if (nvmet_tcp_has_inline_data(queue->cmd)) - nvmet_tcp_fatal_error(queue); - else - nvmet_req_complete(req, ret); + return -EPROTO; + + nvmet_req_complete(req, ret); ret = -EAGAIN; goto out; } @@ -1211,7 +1194,6 @@ recv: if (unlikely(!nvmet_tcp_pdu_valid(hdr->type))) { pr_err("unexpected pdu type %d\n", hdr->type); - nvmet_tcp_fatal_error(queue); return -EIO; } @@ -1225,16 +1207,12 @@ recv: } if (queue->hdr_digest && - nvmet_tcp_verify_hdgst(queue, &queue->pdu, hdr->hlen)) { - nvmet_tcp_fatal_error(queue); /* fatal */ + nvmet_tcp_verify_hdgst(queue, &queue->pdu, hdr->hlen)) return -EPROTO; - } if (queue->data_digest && - nvmet_tcp_check_ddgst(queue, &queue->pdu)) { - nvmet_tcp_fatal_error(queue); /* fatal */ + nvmet_tcp_check_ddgst(queue, &queue->pdu)) return -EPROTO; - } return nvmet_tcp_done_recv_pdu(queue); } @@ -1320,7 +1298,6 @@ static int nvmet_tcp_try_recv_ddgst(struct nvmet_tcp_queue *queue) if (!(cmd->flags & NVMET_TCP_F_INIT_FAILED)) nvmet_req_uninit(&cmd->req); nvmet_tcp_free_cmd_buffers(cmd); - nvmet_tcp_fatal_error(queue); ret = -EPROTO; goto out; } -- cgit v1.2.3 From 332021557104ccf46d40ef7bae3f12a53f56edf3 Mon Sep 17 00:00:00 2001 From: Ville Syrjälä Date: Tue, 7 Apr 2026 21:30:15 +0300 Subject: drm/i915/dp: Don't use DP link min bpp for the FRL link bandwidth check MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit intel_dp_mode_min_link_bpp_x16() gives us the min bpp for the DP link before the PCON, however intel_dp_mode_valid_downstream() is trying to check for sufficient bandwidth on the HDMI FRL link after the PCON. So the use of intel_dp_mode_min_link_bpp_x16() here is incorrect. Presumably even with FRL HDMI still can't go below 8bpc, so we should just use that to give us the minimum required FRL bandwidth. And this needs to account for the sink format (for 4:2:0 sub-sampling) since that is what will be flowing over the HDMI link. Cc: Ankit Nautiyal Cc: Nicolas Frattaroli Signed-off-by: Ville Syrjälä Link: https://patch.msgid.link/20260407183015.16256-1-ville.syrjala@linux.intel.com Reviewed-by: Ankit Nautiyal Reviewed-by: Nicolas Frattaroli --- drivers/gpu/drm/i915/display/intel_dp.c | 20 ++++++++++++++------ 1 file changed, 14 insertions(+), 6 deletions(-) diff --git a/drivers/gpu/drm/i915/display/intel_dp.c b/drivers/gpu/drm/i915/display/intel_dp.c index ff3904b77492..b8b6d62fb275 100644 --- a/drivers/gpu/drm/i915/display/intel_dp.c +++ b/drivers/gpu/drm/i915/display/intel_dp.c @@ -1317,6 +1317,15 @@ intel_dp_tmds_clock_valid(struct intel_dp *intel_dp, return MODE_OK; } +static int frl_required_bw(int clock, int bpc, + enum intel_output_format sink_format) +{ + if (sink_format == INTEL_OUTPUT_FORMAT_YCBCR420) + clock /= 2; + + return clock * bpc * 3; +} + static enum drm_mode_status intel_dp_mode_valid_downstream(struct intel_connector *connector, const struct drm_display_mode *mode, @@ -1327,13 +1336,14 @@ intel_dp_mode_valid_downstream(struct intel_connector *connector, enum drm_mode_status status; enum intel_output_format sink_format; + sink_format = intel_dp_sink_format(connector, mode); + /* If PCON supports FRL MODE, check FRL bandwidth constraints */ if (intel_dp->dfp.pcon_max_frl_bw) { - int link_bpp_x16 = intel_dp_mode_min_link_bpp_x16(connector, mode); - int target_bw; - int max_frl_bw; + int target_bw, max_frl_bw; - target_bw = fxp_q4_to_int_roundup(link_bpp_x16) * target_clock; + /* Assume 8bpc for the FRL bandwidth check */ + target_bw = frl_required_bw(target_clock, 8, sink_format); max_frl_bw = intel_dp->dfp.pcon_max_frl_bw; @@ -1350,8 +1360,6 @@ intel_dp_mode_valid_downstream(struct intel_connector *connector, target_clock > intel_dp->dfp.max_dotclock) return MODE_CLOCK_HIGH; - sink_format = intel_dp_sink_format(connector, mode); - /* Assume 8bpc for the DP++/HDMI/DVI TMDS clock check */ status = intel_dp_tmds_clock_valid(intel_dp, target_clock, 8, sink_format, true); -- cgit v1.2.3 From acfc688bc51b661ed59c1065052282010aa64e50 Mon Sep 17 00:00:00 2001 From: Dibin Moolakadan Subrahmanian Date: Tue, 7 Apr 2026 16:21:02 +0530 Subject: drm/i915/dmc: Reduce wakelock hold time __intel_dmc_wl_release() schedules delayed work which releases the DMC wakelock after a fixed timeout of 50 ms. Until the delayed work runs, the wakelock remains held and prevents entry into deeper DC states. Reduce DMC_WAKELOCK_HOLD_TIME from 50 ms to 5 ms. This should allow the system to enter deeper DC states sooner once MMIO activity settles down. Changes in v2: - Drop detailed explanation from commit message and keep it concise (Suraj Kandpal, Luca Coelho) Signed-off-by: Dibin Moolakadan Subrahmanian Reviewed-by: Luca Coelho Signed-off-by: Suraj Kandpal Link: https://patch.msgid.link/20260407105102.3730973-1-dibin.moolakadan.subrahmanian@intel.com --- drivers/gpu/drm/i915/display/intel_dmc_wl.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/gpu/drm/i915/display/intel_dmc_wl.c b/drivers/gpu/drm/i915/display/intel_dmc_wl.c index 73a3101514f3..ddf1a1f1ebc3 100644 --- a/drivers/gpu/drm/i915/display/intel_dmc_wl.c +++ b/drivers/gpu/drm/i915/display/intel_dmc_wl.c @@ -46,7 +46,7 @@ * atomic variant of waiting MMIO. */ #define DMC_WAKELOCK_CTL_TIMEOUT_US 5000 -#define DMC_WAKELOCK_HOLD_TIME 50 +#define DMC_WAKELOCK_HOLD_TIME 5 /* * Possible non-negative values for the enable_dmc_wl param. -- cgit v1.2.3 From b71dee88e4b544d8b2f5d1406ca290f329a30ce4 Mon Sep 17 00:00:00 2001 From: Jani Nikula Date: Mon, 30 Mar 2026 16:02:34 +0300 Subject: drm/xe/step: switch to the shared step definitions with i915 Use the shared stepping enums from include/drm/intel/step.h. For now, define xe_step as intel_step to avoid mass renames at the same time. For compat, we can remove the reverse macro. Reviewed-by: Luca Coelho Reviewed-by: Gustavo Sousa Link: https://patch.msgid.link/8173d9d753b343ba127d86277344248a6b1d0c3f.1774875688.git.jani.nikula@intel.com Signed-off-by: Jani Nikula --- .../gpu/drm/xe/compat-i915-headers/intel_step.h | 4 +- drivers/gpu/drm/xe/xe_step_types.h | 63 ++-------------------- 2 files changed, 5 insertions(+), 62 deletions(-) diff --git a/drivers/gpu/drm/xe/compat-i915-headers/intel_step.h b/drivers/gpu/drm/xe/compat-i915-headers/intel_step.h index 0eabe2866f5f..cb55a659856b 100644 --- a/drivers/gpu/drm/xe/compat-i915-headers/intel_step.h +++ b/drivers/gpu/drm/xe/compat-i915-headers/intel_step.h @@ -6,8 +6,6 @@ #ifndef __INTEL_STEP_H__ #define __INTEL_STEP_H__ -#include "xe_step_types.h" - -#define intel_step xe_step +#include #endif /* __INTEL_STEP_H__ */ diff --git a/drivers/gpu/drm/xe/xe_step_types.h b/drivers/gpu/drm/xe/xe_step_types.h index 43ca73850739..808385f81804 100644 --- a/drivers/gpu/drm/xe/xe_step_types.h +++ b/drivers/gpu/drm/xe/xe_step_types.h @@ -8,6 +8,10 @@ #include +#include + +#define xe_step intel_step + struct xe_step_info { u8 platform; u8 graphics; @@ -15,63 +19,4 @@ struct xe_step_info { u8 basedie; }; -#define STEP_ENUM_VAL(name) STEP_##name, - -/* - * Always define four minor steppings 0-3 for each stepping to match GMD ID - * spacing of values. See xe_step_gmdid_get(). - */ -#define STEP_NAME_LIST(func) \ - func(A0) \ - func(A1) \ - func(A2) \ - func(A3) \ - func(B0) \ - func(B1) \ - func(B2) \ - func(B3) \ - func(C0) \ - func(C1) \ - func(C2) \ - func(C3) \ - func(D0) \ - func(D1) \ - func(D2) \ - func(D3) \ - func(E0) \ - func(E1) \ - func(E2) \ - func(E3) \ - func(F0) \ - func(F1) \ - func(F2) \ - func(F3) \ - func(G0) \ - func(G1) \ - func(G2) \ - func(G3) \ - func(H0) \ - func(H1) \ - func(H2) \ - func(H3) \ - func(I0) \ - func(I1) \ - func(I2) \ - func(I3) \ - func(J0) \ - func(J1) \ - func(J2) \ - func(J3) - -/* - * Symbolic steppings that do not match the hardware. These are valid both as gt - * and display steppings as symbolic names. - */ -enum xe_step { - STEP_NONE = 0, - STEP_NAME_LIST(STEP_ENUM_VAL) - STEP_FUTURE, - STEP_FOREVER, -}; - #endif -- cgit v1.2.3 From 90788699d8ff81f1b1056c5e506392737340b78f Mon Sep 17 00:00:00 2001 From: Jani Nikula Date: Mon, 30 Mar 2026 16:02:35 +0300 Subject: drm/xe/step: switch from enum xe_step to intel_step naming Remove the xe_step macro, and use the enum intel_step name directly. Reviewed-by: Luca Coelho Reviewed-by: Gustavo Sousa Link: https://patch.msgid.link/87530eaa2052ae4a3c97c7fb87e261d1f73341a7.1774875688.git.jani.nikula@intel.com Signed-off-by: Jani Nikula --- drivers/gpu/drm/xe/tests/xe_pci.c | 4 ++-- drivers/gpu/drm/xe/xe_step.c | 2 +- drivers/gpu/drm/xe/xe_step.h | 4 ++-- drivers/gpu/drm/xe/xe_step_types.h | 2 -- 4 files changed, 5 insertions(+), 7 deletions(-) diff --git a/drivers/gpu/drm/xe/tests/xe_pci.c b/drivers/gpu/drm/xe/tests/xe_pci.c index f3179b31f13e..860409c579f8 100644 --- a/drivers/gpu/drm/xe/tests/xe_pci.c +++ b/drivers/gpu/drm/xe/tests/xe_pci.c @@ -131,12 +131,12 @@ static const char *subplatform_prefix(enum xe_subplatform s) return s == XE_SUBPLATFORM_NONE ? "" : " "; } -static const char *step_prefix(enum xe_step step) +static const char *step_prefix(enum intel_step step) { return step == STEP_NONE ? "" : " "; } -static const char *step_name(enum xe_step step) +static const char *step_name(enum intel_step step) { return step == STEP_NONE ? "" : xe_step_name(step); } diff --git a/drivers/gpu/drm/xe/xe_step.c b/drivers/gpu/drm/xe/xe_step.c index d0f888c31831..fb9c31613ca7 100644 --- a/drivers/gpu/drm/xe/xe_step.c +++ b/drivers/gpu/drm/xe/xe_step.c @@ -278,7 +278,7 @@ void xe_step_gmdid_get(struct xe_device *xe, case STEP_##name: \ return #name; -const char *xe_step_name(enum xe_step step) +const char *xe_step_name(enum intel_step step) { switch (step) { STEP_NAME_LIST(STEP_NAME_CASE); diff --git a/drivers/gpu/drm/xe/xe_step.h b/drivers/gpu/drm/xe/xe_step.h index 41f1c95c46e5..ea36b22cc297 100644 --- a/drivers/gpu/drm/xe/xe_step.h +++ b/drivers/gpu/drm/xe/xe_step.h @@ -18,8 +18,8 @@ void xe_step_pre_gmdid_get(struct xe_device *xe); void xe_step_gmdid_get(struct xe_device *xe, u32 graphics_gmdid_revid, u32 media_gmdid_revid); -static inline u32 xe_step_to_gmdid(enum xe_step step) { return step - STEP_A0; } +static inline u32 xe_step_to_gmdid(enum intel_step step) { return step - STEP_A0; } -const char *xe_step_name(enum xe_step step); +const char *xe_step_name(enum intel_step step); #endif diff --git a/drivers/gpu/drm/xe/xe_step_types.h b/drivers/gpu/drm/xe/xe_step_types.h index 808385f81804..f60572b93523 100644 --- a/drivers/gpu/drm/xe/xe_step_types.h +++ b/drivers/gpu/drm/xe/xe_step_types.h @@ -10,8 +10,6 @@ #include -#define xe_step intel_step - struct xe_step_info { u8 platform; u8 graphics; -- cgit v1.2.3 From baf310b9836445ca9056f04ec347293963a1cc6e Mon Sep 17 00:00:00 2001 From: Jani Nikula Date: Mon, 30 Mar 2026 16:02:36 +0300 Subject: drm/i915/display: switch to including common step file directly Instead of using the proxy intel_step.h in display, just include the common step file directly where needed. This allows us to remove the compat intel_step.h header. Reviewed-by: Luca Coelho Reviewed-by: Gustavo Sousa Link: https://patch.msgid.link/83b5f13b7f863b9cbc61499bcff22af5cd822a0b.1774875688.git.jani.nikula@intel.com Signed-off-by: Jani Nikula --- drivers/gpu/drm/i915/display/intel_cdclk.c | 2 +- drivers/gpu/drm/i915/display/intel_ddi.c | 2 +- drivers/gpu/drm/i915/display/intel_display_device.c | 2 +- drivers/gpu/drm/i915/display/intel_display_power.c | 2 +- drivers/gpu/drm/i915/display/intel_display_wa.c | 2 +- drivers/gpu/drm/i915/display/intel_dp_mst.c | 2 +- drivers/gpu/drm/i915/display/intel_dpll_mgr.c | 2 +- drivers/gpu/drm/i915/display/intel_fbc.c | 2 +- drivers/gpu/drm/i915/display/intel_flipq.c | 2 +- drivers/gpu/drm/i915/display/intel_hdcp.c | 2 +- drivers/gpu/drm/i915/display/intel_pmdemand.c | 2 +- drivers/gpu/drm/i915/display/intel_psr.c | 2 +- drivers/gpu/drm/i915/display/skl_universal_plane.c | 2 +- drivers/gpu/drm/xe/compat-i915-headers/intel_step.h | 11 ----------- 14 files changed, 13 insertions(+), 24 deletions(-) delete mode 100644 drivers/gpu/drm/xe/compat-i915-headers/intel_step.h diff --git a/drivers/gpu/drm/i915/display/intel_cdclk.c b/drivers/gpu/drm/i915/display/intel_cdclk.c index a47736613f6e..e3b044ee3e16 100644 --- a/drivers/gpu/drm/i915/display/intel_cdclk.c +++ b/drivers/gpu/drm/i915/display/intel_cdclk.c @@ -28,6 +28,7 @@ #include #include #include +#include #include "hsw_ips.h" #include "intel_atomic.h" @@ -46,7 +47,6 @@ #include "intel_pci_config.h" #include "intel_plane.h" #include "intel_psr.h" -#include "intel_step.h" #include "intel_vdsc.h" #include "skl_watermark.h" #include "skl_watermark_regs.h" diff --git a/drivers/gpu/drm/i915/display/intel_ddi.c b/drivers/gpu/drm/i915/display/intel_ddi.c index ebefa889bc8c..178074316a2c 100644 --- a/drivers/gpu/drm/i915/display/intel_ddi.c +++ b/drivers/gpu/drm/i915/display/intel_ddi.c @@ -33,6 +33,7 @@ #include #include #include +#include #include "icl_dsi.h" #include "intel_alpm.h" @@ -81,7 +82,6 @@ #include "intel_psr.h" #include "intel_quirks.h" #include "intel_snps_phy.h" -#include "intel_step.h" #include "intel_tc.h" #include "intel_vdsc.h" #include "intel_vdsc_regs.h" diff --git a/drivers/gpu/drm/i915/display/intel_display_device.c b/drivers/gpu/drm/i915/display/intel_display_device.c index be55ef8ea617..7260990038dd 100644 --- a/drivers/gpu/drm/i915/display/intel_display_device.c +++ b/drivers/gpu/drm/i915/display/intel_display_device.c @@ -9,6 +9,7 @@ #include #include #include +#include #include "intel_cx0_phy_regs.h" #include "intel_de.h" @@ -21,7 +22,6 @@ #include "intel_display_types.h" #include "intel_display_wa.h" #include "intel_fbc.h" -#include "intel_step.h" __diag_push(); __diag_ignore_all("-Woverride-init", "Allow field initialization overrides for display info"); diff --git a/drivers/gpu/drm/i915/display/intel_display_power.c b/drivers/gpu/drm/i915/display/intel_display_power.c index ec96b141c74c..1a2de99ad78f 100644 --- a/drivers/gpu/drm/i915/display/intel_display_power.c +++ b/drivers/gpu/drm/i915/display/intel_display_power.c @@ -8,6 +8,7 @@ #include #include +#include #include "intel_backlight_regs.h" #include "intel_cdclk.h" @@ -30,7 +31,6 @@ #include "intel_pmdemand.h" #include "intel_pps_regs.h" #include "intel_snps_phy.h" -#include "intel_step.h" #include "skl_watermark.h" #include "skl_watermark_regs.h" #include "vlv_sideband.h" diff --git a/drivers/gpu/drm/i915/display/intel_display_wa.c b/drivers/gpu/drm/i915/display/intel_display_wa.c index 081a4092cd13..7d3d63a59882 100644 --- a/drivers/gpu/drm/i915/display/intel_display_wa.c +++ b/drivers/gpu/drm/i915/display/intel_display_wa.c @@ -4,12 +4,12 @@ */ #include +#include #include "intel_de.h" #include "intel_display_core.h" #include "intel_display_regs.h" #include "intel_display_wa.h" -#include "intel_step.h" static void gen11_display_wa_apply(struct intel_display *display) { diff --git a/drivers/gpu/drm/i915/display/intel_dp_mst.c b/drivers/gpu/drm/i915/display/intel_dp_mst.c index 887b6de14e46..96c5bcf7e21e 100644 --- a/drivers/gpu/drm/i915/display/intel_dp_mst.c +++ b/drivers/gpu/drm/i915/display/intel_dp_mst.c @@ -32,6 +32,7 @@ #include #include #include +#include #include "intel_atomic.h" #include "intel_audio.h" @@ -56,7 +57,6 @@ #include "intel_link_bw.h" #include "intel_pfit.h" #include "intel_psr.h" -#include "intel_step.h" #include "intel_vdsc.h" #include "intel_vrr.h" #include "skl_scaler.h" diff --git a/drivers/gpu/drm/i915/display/intel_dpll_mgr.c b/drivers/gpu/drm/i915/display/intel_dpll_mgr.c index f5d4f7146fbc..e97b38f5d98e 100644 --- a/drivers/gpu/drm/i915/display/intel_dpll_mgr.c +++ b/drivers/gpu/drm/i915/display/intel_dpll_mgr.c @@ -25,6 +25,7 @@ #include #include +#include #include "bxt_dpio_phy_regs.h" #include "intel_cx0_phy.h" @@ -41,7 +42,6 @@ #include "intel_lt_phy.h" #include "intel_mg_phy_regs.h" #include "intel_pch_refclk.h" -#include "intel_step.h" #include "intel_tc.h" /** diff --git a/drivers/gpu/drm/i915/display/intel_fbc.c b/drivers/gpu/drm/i915/display/intel_fbc.c index ea0ce00c8474..55cb3ceb3523 100644 --- a/drivers/gpu/drm/i915/display/intel_fbc.c +++ b/drivers/gpu/drm/i915/display/intel_fbc.c @@ -44,6 +44,7 @@ #include #include #include +#include #include "i9xx_plane_regs.h" #include "intel_de.h" @@ -58,7 +59,6 @@ #include "intel_fbc_regs.h" #include "intel_frontbuffer.h" #include "intel_parent.h" -#include "intel_step.h" #define for_each_fbc_id(__display, __fbc_id) \ for ((__fbc_id) = INTEL_FBC_A; (__fbc_id) < I915_MAX_FBCS; (__fbc_id)++) \ diff --git a/drivers/gpu/drm/i915/display/intel_flipq.c b/drivers/gpu/drm/i915/display/intel_flipq.c index 253dc2e96d2d..333d28faf4ca 100644 --- a/drivers/gpu/drm/i915/display/intel_flipq.c +++ b/drivers/gpu/drm/i915/display/intel_flipq.c @@ -6,6 +6,7 @@ #include #include +#include #include "intel_crtc.h" #include "intel_de.h" @@ -17,7 +18,6 @@ #include "intel_dmc_regs.h" #include "intel_dsb.h" #include "intel_flipq.h" -#include "intel_step.h" #include "intel_vblank.h" #include "intel_vrr.h" diff --git a/drivers/gpu/drm/i915/display/intel_hdcp.c b/drivers/gpu/drm/i915/display/intel_hdcp.c index 892eab4b6f92..9b4ff3b80b05 100644 --- a/drivers/gpu/drm/i915/display/intel_hdcp.c +++ b/drivers/gpu/drm/i915/display/intel_hdcp.c @@ -18,6 +18,7 @@ #include #include #include +#include #include "intel_connector.h" #include "intel_de.h" @@ -33,7 +34,6 @@ #include "intel_hdcp_regs.h" #include "intel_hdcp_shim.h" #include "intel_parent.h" -#include "intel_step.h" #define USE_HDCP_GSC(__display) (DISPLAY_VER(__display) >= 14) diff --git a/drivers/gpu/drm/i915/display/intel_pmdemand.c b/drivers/gpu/drm/i915/display/intel_pmdemand.c index 244806a26da3..7819b724795b 100644 --- a/drivers/gpu/drm/i915/display/intel_pmdemand.c +++ b/drivers/gpu/drm/i915/display/intel_pmdemand.c @@ -6,6 +6,7 @@ #include #include +#include #include "intel_atomic.h" #include "intel_bw.h" @@ -17,7 +18,6 @@ #include "intel_display_utils.h" #include "intel_display_wa.h" #include "intel_pmdemand.h" -#include "intel_step.h" #include "skl_watermark.h" struct pmdemand_params { diff --git a/drivers/gpu/drm/i915/display/intel_psr.c b/drivers/gpu/drm/i915/display/intel_psr.c index 2f1b48cd8efd..7750a0282d60 100644 --- a/drivers/gpu/drm/i915/display/intel_psr.c +++ b/drivers/gpu/drm/i915/display/intel_psr.c @@ -28,6 +28,7 @@ #include #include #include +#include #include "intel_alpm.h" #include "intel_atomic.h" @@ -51,7 +52,6 @@ #include "intel_psr_regs.h" #include "intel_quirks.h" #include "intel_snps_phy.h" -#include "intel_step.h" #include "intel_vblank.h" #include "intel_vdsc.h" #include "intel_vrr.h" diff --git a/drivers/gpu/drm/i915/display/skl_universal_plane.c b/drivers/gpu/drm/i915/display/skl_universal_plane.c index 11ba42c67e3e..7a9d494334b5 100644 --- a/drivers/gpu/drm/i915/display/skl_universal_plane.c +++ b/drivers/gpu/drm/i915/display/skl_universal_plane.c @@ -8,6 +8,7 @@ #include #include #include +#include #include "intel_bo.h" #include "intel_color.h" @@ -25,7 +26,6 @@ #include "intel_plane.h" #include "intel_psr.h" #include "intel_psr_regs.h" -#include "intel_step.h" #include "skl_scaler.h" #include "skl_universal_plane.h" #include "skl_universal_plane_regs.h" diff --git a/drivers/gpu/drm/xe/compat-i915-headers/intel_step.h b/drivers/gpu/drm/xe/compat-i915-headers/intel_step.h deleted file mode 100644 index cb55a659856b..000000000000 --- a/drivers/gpu/drm/xe/compat-i915-headers/intel_step.h +++ /dev/null @@ -1,11 +0,0 @@ -/* SPDX-License-Identifier: MIT */ -/* - * Copyright © 2023 Intel Corporation - */ - -#ifndef __INTEL_STEP_H__ -#define __INTEL_STEP_H__ - -#include - -#endif /* __INTEL_STEP_H__ */ -- cgit v1.2.3 From d842ed8f3417d848046eea2c40de78a1993eb3df Mon Sep 17 00:00:00 2001 From: Damon Ding Date: Thu, 9 Apr 2026 14:52:45 +0800 Subject: drm/bridge: analogix_dp: Add &analogix_dp_plat_data.next_bridge In order to move the panel/bridge parsing and attachmenet to the Analogix side, add component struct drm_bridge *next_bridge to platform data struct analogix_dp_plat_data. The movement makes sense because the panel/bridge should logically be positioned behind the Analogix bridge in the display pipeline. Signed-off-by: Damon Ding Reviewed-by: Dmitry Baryshkov Reviewed-by: Luca Ceresoli Tested-by: Marek Szyprowski Tested-by: Heiko Stuebner # rk3588 Link: https://patch.msgid.link/20260409065301.446670-2-damon.ding@rock-chips.com Signed-off-by: Luca Ceresoli --- include/drm/bridge/analogix_dp.h | 1 + 1 file changed, 1 insertion(+) diff --git a/include/drm/bridge/analogix_dp.h b/include/drm/bridge/analogix_dp.h index cf17646c1310..582357c20640 100644 --- a/include/drm/bridge/analogix_dp.h +++ b/include/drm/bridge/analogix_dp.h @@ -27,6 +27,7 @@ static inline bool is_rockchip(enum analogix_dp_devtype type) struct analogix_dp_plat_data { enum analogix_dp_devtype dev_type; struct drm_panel *panel; + struct drm_bridge *next_bridge; struct drm_encoder *encoder; struct drm_connector *connector; bool skip_connector; -- cgit v1.2.3 From ba2db93cf3d569a4525a02cd0ed5ec5f979e3afd Mon Sep 17 00:00:00 2001 From: Damon Ding Date: Thu, 9 Apr 2026 14:52:46 +0800 Subject: drm/bridge: Move legacy bridge driver out of imx directory for multi-platform use As suggested by Dmitry, the DRM legacy bridge driver can be pulled out of imx/ subdir for multi-platform use. The driver is also renamed to make it more generic and suitable for platforms other than i.MX. Signed-off-by: Damon Ding Suggested-by: Dmitry Baryshkov Reviewed-by: Luca Ceresoli Tested-by: Marek Szyprowski Tested-by: Heiko Stuebner # rk3588 Link: https://patch.msgid.link/20260409065301.446670-3-damon.ding@rock-chips.com Signed-off-by: Luca Ceresoli --- drivers/gpu/drm/bridge/Kconfig | 10 +++ drivers/gpu/drm/bridge/Makefile | 1 + drivers/gpu/drm/bridge/imx/Kconfig | 10 --- drivers/gpu/drm/bridge/imx/Makefile | 1 - drivers/gpu/drm/bridge/imx/imx-legacy-bridge.c | 91 ------------------------ drivers/gpu/drm/bridge/of-display-mode-bridge.c | 93 +++++++++++++++++++++++++ drivers/gpu/drm/imx/ipuv3/Kconfig | 4 +- drivers/gpu/drm/imx/ipuv3/imx-ldb.c | 6 +- drivers/gpu/drm/imx/ipuv3/parallel-display.c | 5 +- include/drm/bridge/imx.h | 17 ----- include/drm/bridge/of-display-mode-bridge.h | 17 +++++ 11 files changed, 129 insertions(+), 126 deletions(-) delete mode 100644 drivers/gpu/drm/bridge/imx/imx-legacy-bridge.c create mode 100644 drivers/gpu/drm/bridge/of-display-mode-bridge.c delete mode 100644 include/drm/bridge/imx.h create mode 100644 include/drm/bridge/of-display-mode-bridge.h diff --git a/drivers/gpu/drm/bridge/Kconfig b/drivers/gpu/drm/bridge/Kconfig index c3209b0f4678..f81b566c82a1 100644 --- a/drivers/gpu/drm/bridge/Kconfig +++ b/drivers/gpu/drm/bridge/Kconfig @@ -262,6 +262,16 @@ config DRM_NXP_PTN3460 help NXP PTN3460 eDP-LVDS bridge chip driver. +config DRM_OF_DISPLAY_MODE_BRIDGE + tristate + depends on DRM_BRIDGE && OF + help + This is a DRM bridge implementation that uses of_get_drm_display_mode + to acquire display mode. + + It exists for compatibility with legacy display mode parsing, in order + to conform to the panel-bridge framework. + config DRM_PARADE_PS8622 tristate "Parade eDP/LVDS bridge" depends on OF diff --git a/drivers/gpu/drm/bridge/Makefile b/drivers/gpu/drm/bridge/Makefile index beab5b695a6e..15cc821d85b7 100644 --- a/drivers/gpu/drm/bridge/Makefile +++ b/drivers/gpu/drm/bridge/Makefile @@ -22,6 +22,7 @@ obj-$(CONFIG_DRM_LVDS_CODEC) += lvds-codec.o obj-$(CONFIG_DRM_MEGACHIPS_STDPXXXX_GE_B850V3_FW) += megachips-stdpxxxx-ge-b850v3-fw.o obj-$(CONFIG_DRM_MICROCHIP_LVDS_SERIALIZER) += microchip-lvds.o obj-$(CONFIG_DRM_NXP_PTN3460) += nxp-ptn3460.o +obj-$(CONFIG_DRM_OF_DISPLAY_MODE_BRIDGE) += of-display-mode-bridge.o obj-$(CONFIG_DRM_PARADE_PS8622) += parade-ps8622.o obj-$(CONFIG_DRM_PARADE_PS8640) += parade-ps8640.o obj-$(CONFIG_DRM_SAMSUNG_DSIM) += samsung-dsim.o diff --git a/drivers/gpu/drm/bridge/imx/Kconfig b/drivers/gpu/drm/bridge/imx/Kconfig index b9028a5e5a06..8877b9789868 100644 --- a/drivers/gpu/drm/bridge/imx/Kconfig +++ b/drivers/gpu/drm/bridge/imx/Kconfig @@ -3,16 +3,6 @@ if ARCH_MXC || COMPILE_TEST config DRM_IMX_LDB_HELPER tristate -config DRM_IMX_LEGACY_BRIDGE - tristate - depends on DRM_IMX - help - This is a DRM bridge implementation for the DRM i.MX IPUv3 driver, - that uses of_get_drm_display_mode to acquire display mode. - - Newer designs should not use this bridge and should use proper panel - driver instead. - config DRM_IMX8MP_DW_HDMI_BRIDGE tristate "Freescale i.MX8MP HDMI-TX bridge support" depends on OF diff --git a/drivers/gpu/drm/bridge/imx/Makefile b/drivers/gpu/drm/bridge/imx/Makefile index 8d01fda25451..69d9f9abbe36 100644 --- a/drivers/gpu/drm/bridge/imx/Makefile +++ b/drivers/gpu/drm/bridge/imx/Makefile @@ -1,5 +1,4 @@ obj-$(CONFIG_DRM_IMX_LDB_HELPER) += imx-ldb-helper.o -obj-$(CONFIG_DRM_IMX_LEGACY_BRIDGE) += imx-legacy-bridge.o obj-$(CONFIG_DRM_IMX8MP_DW_HDMI_BRIDGE) += imx8mp-hdmi-tx.o obj-$(CONFIG_DRM_IMX8MP_HDMI_PAI) += imx8mp-hdmi-pai.o obj-$(CONFIG_DRM_IMX8MP_HDMI_PVI) += imx8mp-hdmi-pvi.o diff --git a/drivers/gpu/drm/bridge/imx/imx-legacy-bridge.c b/drivers/gpu/drm/bridge/imx/imx-legacy-bridge.c deleted file mode 100644 index 0e31d5000e7c..000000000000 --- a/drivers/gpu/drm/bridge/imx/imx-legacy-bridge.c +++ /dev/null @@ -1,91 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0+ -/* - * Freescale i.MX drm driver - * - * bridge driver for legacy DT bindings, utilizing display-timings node - */ - -#include - -#include -#include -#include -#include - -#include