Re: [PATCH 07/14] drm/imx: dc: Add DPR channel support
From: Liu Ying <victor.liu@nxp.com>
Date: 2025-09-22 03:42:44
Also in:
dri-devel, imx, linux-devicetree, lkml
On 09/19/2025, Frank Li wrote:
On Fri, Jul 04, 2025 at 05:03:54PM +0800, Liu Ying wrote:quoted
Display Prefetch Resolve Channel(DPRC) is a part of a prefetch engine. It fetches display data, transforms it to linear format and stores it to DPRC's RTRAM. PRG, as the other part of a prefetch engine, acts as a gasket between the RTRAM controller and a FetchUnit. Add a platform driver to support the DPRC. Signed-off-by: Liu Ying <victor.liu@nxp.com> --- drivers/gpu/drm/imx/dc/Kconfig | 1 + drivers/gpu/drm/imx/dc/Makefile | 6 +- drivers/gpu/drm/imx/dc/dc-dprc.c | 499 +++++++++++++++++++++++++++++++++++++++ drivers/gpu/drm/imx/dc/dc-dprc.h | 35 +++ drivers/gpu/drm/imx/dc/dc-drv.c | 1 + drivers/gpu/drm/imx/dc/dc-drv.h | 1 + drivers/gpu/drm/imx/dc/dc-prg.c | 12 + drivers/gpu/drm/imx/dc/dc-prg.h | 4 + 8 files changed, 556 insertions(+), 3 deletions(-)diff --git a/drivers/gpu/drm/imx/dc/Kconfig b/drivers/gpu/drm/imx/dc/Kconfig index 415993207f2e3487f09602050fa9284fd0955cc7..507dc9a92d96be225cd9b10968a037dad286b327 100644 --- a/drivers/gpu/drm/imx/dc/Kconfig +++ b/drivers/gpu/drm/imx/dc/Kconfig...quoted
+ return false; + + if (!dc_prg_stride_supported(dprc->prg, prg_stride, baddr)) + return false; + + return true; +} + +static int dc_dprc_probe(struct platform_device *pdev) +{ + struct device *dev = &pdev->dev; + struct device_node *np = dev->of_node; + struct resource *res; + void __iomem *base; + struct dc_dprc *dprc; + int ret, wrap_irq;If have new version, try keep reverse christmas tree order for nice look.
Ack.
quoted
+ + dprc = devm_kzalloc(dev, sizeof(*dprc), GFP_KERNEL); + if (!dprc) + return -ENOMEM; + + ret = imx_scu_get_handle(&dprc->ipc_handle); + if (ret) + return dev_err_probe(dev, ret, "failed to get SCU ipc handle\n"); + + base = devm_platform_get_and_ioremap_resource(pdev, 0, &res); + if (IS_ERR(base)) + return PTR_ERR(base); + + dprc->reg = devm_regmap_init_mmio(dev, base, &dc_dprc_regmap_config); + if (IS_ERR(dprc->reg)) + return PTR_ERR(dprc->reg); + + wrap_irq = platform_get_irq_byname(pdev, "dpr_wrap"); + if (wrap_irq < 0) + return -ENODEV; + + dprc->clk_apb = devm_clk_get(dev, "apb"); + if (IS_ERR(dprc->clk_apb)) + return dev_err_probe(dev, PTR_ERR(dprc->clk_apb), + "failed to get APB clock\n"); + + dprc->clk_b = devm_clk_get(dev, "b"); + if (IS_ERR(dprc->clk_b)) + return dev_err_probe(dev, PTR_ERR(dprc->clk_b), + "failed to get B clock\n"); + + dprc->clk_rtram = devm_clk_get(dev, "rtram"); + if (IS_ERR(dprc->clk_rtram)) + return dev_err_probe(dev, PTR_ERR(dprc->clk_rtram), + "failed to get RTRAM clock\n");use clk bulk API will simple clock handlers code, include suspend/resume codes.
Ack.
Frankquoted
+ + ret = of_property_read_u32(np, "fsl,sc-resource", &dprc->sc_resource); + if (ret) { + dev_err(dev, "failed to get SC resource %d\n", ret); + return ret; + } + + dprc->prg = dc_prg_lookup_by_phandle(dev, "fsl,prgs", 0); + if (!dprc->prg) + return dev_err_probe(dev, -EPROBE_DEFER, + "failed to lookup PRG\n"); + + dc_prg_set_dprc(dprc->prg, dprc); + + dprc->dev = dev; + spin_lock_init(&dprc->lock); + + ret = devm_request_irq(dev, wrap_irq, dc_dprc_wrap_irq_handler, + IRQF_SHARED, dev_name(dev), dprc); + if (ret < 0) { + dev_err(dev, "failed to request dpr_wrap IRQ(%d): %d\n", + wrap_irq, ret); + return ret; + } + + dev_set_drvdata(dev, dprc); + + ret = devm_pm_runtime_enable(dev); + if (ret) + return dev_err_probe(dev, ret, "failed to enable PM runtime\n"); + + return 0; +} + +static int dc_dprc_runtime_suspend(struct device *dev) +{ + struct dc_dprc *dprc = dev_get_drvdata(dev); + + clk_disable_unprepare(dprc->clk_rtram); + clk_disable_unprepare(dprc->clk_b); + clk_disable_unprepare(dprc->clk_apb); + + return 0; +} + +static int dc_dprc_runtime_resume(struct device *dev) +{ + struct dc_dprc *dprc = dev_get_drvdata(dev); + int ret; + + ret = clk_prepare_enable(dprc->clk_apb); + if (ret) { + dev_err(dev, "failed to enable APB clock: %d\n", ret); + goto err1; + } + + ret = clk_prepare_enable(dprc->clk_b); + if (ret) { + dev_err(dev, "failed to enable B clock: %d\n", ret); + goto err2; + } + + ret = clk_prepare_enable(dprc->clk_rtram); + if (ret) { + dev_err(dev, "failed to enable RTRAM clock: %d\n", ret); + goto err3; + } + + dc_dprc_reset(dprc); + + /* disable all control IRQs and enable all error IRQs */ + guard(spinlock_irqsave)(&dprc->lock); + regmap_write(dprc->reg, IRQ_MASK, IRQ_CTRL_MASK); + + return 0; +err3: + clk_disable_unprepare(dprc->clk_b); +err2: + clk_disable_unprepare(dprc->clk_apb); +err1: + return ret; +} + +static const struct dev_pm_ops dc_dprc_pm_ops = { + RUNTIME_PM_OPS(dc_dprc_runtime_suspend, dc_dprc_runtime_resume, NULL) +}; + +static const struct of_device_id dc_dprc_dt_ids[] = { + { .compatible = "fsl,imx8qxp-dpr-channel", }, + { /* sentinel */ } +}; + +struct platform_driver dc_dprc_driver = { + .probe = dc_dprc_probe, + .driver = { + .name = "imx8-dc-dpr-channel", + .suppress_bind_attrs = true, + .of_match_table = dc_dprc_dt_ids, + .pm = pm_ptr(&dc_dprc_pm_ops), + }, +};diff --git a/drivers/gpu/drm/imx/dc/dc-dprc.h b/drivers/gpu/drm/imx/dc/dc-dprc.h new file mode 100644 index 0000000000000000000000000000000000000000..f977858b57fec2f19775a97dc0baf011ca177c0b --- /dev/null +++ b/drivers/gpu/drm/imx/dc/dc-dprc.h@@ -0,0 +1,35 @@ +/* SPDX-License-Identifier: GPL-2.0+ */ +/* + * Copyright 2025 NXP + */ + +#ifndef __DC_DPRC_H__ +#define __DC_DPRC_H__ + +#include <linux/device.h> +#include <linux/types.h> + +#include <drm/drm_fourcc.h> + +struct dc_dprc; + +void dc_dprc_configure(struct dc_dprc *dprc, unsigned int stream_id, + unsigned int width, unsigned int height, + unsigned int stride, + const struct drm_format_info *format, + dma_addr_t baddr, bool start); + +void dc_dprc_disable_repeat_en(struct dc_dprc *dprc); + +void dc_dprc_disable(struct dc_dprc *dprc); + +void dc_dprc_disable_at_boot(struct dc_dprc *dprc); + +bool dc_dprc_rtram_width_supported(struct dc_dprc *dprc, unsigned int width); + +bool dc_dprc_stride_supported(struct dc_dprc *dprc, + unsigned int stride, unsigned int width, + const struct drm_format_info *format, + dma_addr_t baddr); + +#endifdiff --git a/drivers/gpu/drm/imx/dc/dc-drv.c b/drivers/gpu/drm/imx/dc/dc-drv.c index 9bdcfc5aee976ef77bea6b3f6f3ac5f11249798f..17b9c4d0953d46be0a2cd276f06298d848fdcbdd 100644 --- a/drivers/gpu/drm/imx/dc/dc-drv.c +++ b/drivers/gpu/drm/imx/dc/dc-drv.c@@ -269,6 +269,7 @@ static struct platform_driver dc_driver = { static struct platform_driver * const dc_drivers[] = { &dc_cf_driver, &dc_de_driver, + &dc_dprc_driver, &dc_ed_driver, &dc_fg_driver, &dc_fl_driver,diff --git a/drivers/gpu/drm/imx/dc/dc-drv.h b/drivers/gpu/drm/imx/dc/dc-drv.h index 557e7d90e4ea8ca2af59027b3152163cf7f9a618..93a8ce4e7c314770b64ccb631628b7e79648c791 100644 --- a/drivers/gpu/drm/imx/dc/dc-drv.h +++ b/drivers/gpu/drm/imx/dc/dc-drv.h@@ -74,6 +74,7 @@ int dc_plane_init(struct dc_drm_device *dc_drm, struct dc_plane *dc_plane); extern struct platform_driver dc_cf_driver; extern struct platform_driver dc_de_driver; +extern struct platform_driver dc_dprc_driver; extern struct platform_driver dc_ed_driver; extern struct platform_driver dc_fg_driver; extern struct platform_driver dc_fl_driver;diff --git a/drivers/gpu/drm/imx/dc/dc-prg.c b/drivers/gpu/drm/imx/dc/dc-prg.c index 9a1a312c0aeebf47bcf50ffa77971aa3bb431a12..bb6c47133e90f9bc5eb3fb0e30c3f338ec82213b 100644 --- a/drivers/gpu/drm/imx/dc/dc-prg.c +++ b/drivers/gpu/drm/imx/dc/dc-prg.c@@ -19,6 +19,7 @@ #include <linux/pm_runtime.h> #include <linux/regmap.h> +#include "dc-dprc.h" #include "dc-prg.h" #define SET 0x4@@ -63,6 +64,7 @@ struct dc_prg { struct list_head list; struct clk *clk_apb; struct clk *clk_rtram; + struct dc_dprc *dprc; }; static DEFINE_MUTEX(dc_prg_list_mutex);@@ -217,6 +219,16 @@ dc_prg_lookup_by_phandle(struct device *dev, const char *name, int index) return NULL; } +void dc_prg_set_dprc(struct dc_prg *prg, struct dc_dprc *dprc) +{ + prg->dprc = dprc; +} + +struct dc_dprc *dc_prg_get_dprc(struct dc_prg *prg) +{ + return prg->dprc; +} + static int dc_prg_probe(struct platform_device *pdev) { struct device *dev = &pdev->dev;diff --git a/drivers/gpu/drm/imx/dc/dc-prg.h b/drivers/gpu/drm/imx/dc/dc-prg.h index 6fd9b050bfa12334720f83ff9ceaf337e3048a54..f29d154f7de597b9d20d5e71303049f6f8b022d6 100644 --- a/drivers/gpu/drm/imx/dc/dc-prg.h +++ b/drivers/gpu/drm/imx/dc/dc-prg.h@@ -32,4 +32,8 @@ bool dc_prg_stride_supported(struct dc_prg *prg, struct dc_prg * dc_prg_lookup_by_phandle(struct device *dev, const char *name, int index); +void dc_prg_set_dprc(struct dc_prg *prg, struct dc_dprc *dprc); + +struct dc_dprc *dc_prg_get_dprc(struct dc_prg *prg); + #endif --2.34.1
-- Regards, Liu Ying