From 09c47e99dfce50dfe1111f7c598a40c12f13e8c6 Mon Sep 17 00:00:00 2001 From: Wei Dun Date: Fri, 29 Aug 2025 17:31:04 +0800 Subject: [PATCH 01/21] media: rockchip: vpss: set stride 0 for 4-byte-align stride Change-Id: I91537bccf3475f0859e3f47faa259b84969e0753 Signed-off-by: Wei Dun --- .../media/platform/rockchip/vpss/stream_v20.c | 37 ++++++++++++++++++- .../platform/rockchip/vpss/vpss_offline_v20.c | 6 ++- 2 files changed, 40 insertions(+), 3 deletions(-) diff --git a/drivers/media/platform/rockchip/vpss/stream_v20.c b/drivers/media/platform/rockchip/vpss/stream_v20.c index 3dd25b48356a..a14861e4ad01 100644 --- a/drivers/media/platform/rockchip/vpss/stream_v20.c +++ b/drivers/media/platform/rockchip/vpss/stream_v20.c @@ -967,8 +967,13 @@ static void scl_config_mi(struct rkvpss_stream *stream) if (fmt->fmt_type == FMT_FBC) val = 0; - else - val = out_fmt->plane_fmt[0].bytesperline; + else { + /* If 16-aligned, use stride; otherwise set to 0 */ + if (IS_ALIGNED(out_fmt->plane_fmt[0].bytesperline, 16)) + val = out_fmt->plane_fmt[0].bytesperline; + else + val = 0; + } reg = stream->config->mi.stride; rkvpss_unite_write(dev, reg, val); @@ -2264,6 +2269,34 @@ static int rkvpss_set_fmt(struct rkvpss_stream *stream, } } + /* Add format alignment checks */ + v4l2_dbg(1, rkvpss_debug, &dev->v4l2_dev, + "format alignment check: width=%d, height=%d, fourcc=0x%x\n", + pixm->width, pixm->height, fmt->fourcc); + if (fmt->fourcc == V4L2_PIX_FMT_FBC0 || + fmt->fourcc == V4L2_PIX_FMT_FBC2) { + if (!IS_ALIGNED(pixm->width, 64)) { + v4l2_err(&dev->v4l2_dev, + "stream:%d fbc output width %d is not 64 aligned\n", + stream->id, pixm->width); + return -EINVAL; + } + if (!IS_ALIGNED(pixm->height, 4)) { + v4l2_err(&dev->v4l2_dev, + "stream:%d fbc output height %d is not 4 aligned\n", + stream->id, pixm->height); + return -EINVAL; + } + } else { + /* Check width alignment for non-FBC formats */ + if (!IS_ALIGNED(pixm->width, 4)) { + v4l2_err(&dev->v4l2_dev, + "stream:%d output width %d is not 4 aligned\n", + stream->id, pixm->width); + return -EINVAL; + } + } + pixm->num_planes = fmt->mplanes; pixm->field = V4L2_FIELD_NONE; if (!pixm->quantization) diff --git a/drivers/media/platform/rockchip/vpss/vpss_offline_v20.c b/drivers/media/platform/rockchip/vpss/vpss_offline_v20.c index 97b8647a8f71..119da7518eda 100644 --- a/drivers/media/platform/rockchip/vpss/vpss_offline_v20.c +++ b/drivers/media/platform/rockchip/vpss/vpss_offline_v20.c @@ -1537,7 +1537,11 @@ static int write_config(struct rkvpss_offline_dev *ofl, rkvpss_hw_write(hw, reg + i * 0x100, val); reg = RKVPSS_MI_CHN0_WR_Y_STRIDE; - val = cfg->output[i].stride; + /* If 16-aligned, use stride; otherwise set to 0 */ + if (IS_ALIGNED(cfg->output[i].stride, 16)) + val = cfg->output[i].stride; + else + val = 0; rkvpss_hw_write(hw, reg + i * 0x100, val); reg = RKVPSS_MI_CHN0_WR_Y_SIZE; From 42b93983b3274f1e739ed5de0e51f04e01f97d91 Mon Sep 17 00:00:00 2001 From: Xing Zheng Date: Thu, 21 Aug 2025 21:25:15 +0800 Subject: [PATCH 02/21] soc: rockchip: aoa_middleware: fix NULL pointer during rmmod rk_aoa.ko Because the call: platform_set_drvdata(pdev, am_d); in aoa_mmap_probe() is overwritten by the subsequent call: platform_set_drvdata(pdev, amw_d); therefore, the am_d handle needs to be saved separately. Also, previously allocated IRQ and platform resources must be released. And, fix the issue where repeated insmod operations couldn't be performed due to resource usage. After successfully executing the command `insmod rk_aoa.ko` for the first time, executing `rmmod rk_aoa` to uninstall the file and then executing `insmod rk_aoa.ko` again will result in the following error: ---- [ 93.352370] platform 208b0000.aoa: can't request region for resource [mem 0x208b0000-0x208b0fff] [ 93.352401] aoa-middleware aoa_middleware: probe rockchip aoa failed: -16 [ 93.352411] aoa-middleware: probe of aoa_middleware failed with error -16 ---- Furthermore, the pdev functions for aoa_drv and lp_rkdma are manually probed via aoa_middleware and cannot be automatically released via the devm mechanism. Therefore, you must manually allocate resources in the probe function and release them manually in the remove function. Signed-off-by: Xing Zheng Change-Id: I454c970de620f1dc7007bf530e2e0650c81066e4 --- drivers/soc/rockchip/aoa_middleware/aoa_drv.c | 62 +++++++++--- .../rockchip/aoa_middleware/aoa_middleware.c | 96 +++++++++++++++---- .../soc/rockchip/aoa_middleware/aoa_mmap.c | 22 ++--- .../soc/rockchip/aoa_middleware/aoa_mmap.h | 4 +- .../soc/rockchip/aoa_middleware/lp_rkdma.c | 68 ++++++++++--- 5 files changed, 193 insertions(+), 59 deletions(-) diff --git a/drivers/soc/rockchip/aoa_middleware/aoa_drv.c b/drivers/soc/rockchip/aoa_middleware/aoa_drv.c index 084775879078..aa3dc7ec699d 100644 --- a/drivers/soc/rockchip/aoa_middleware/aoa_drv.c +++ b/drivers/soc/rockchip/aoa_middleware/aoa_drv.c @@ -19,6 +19,7 @@ struct rk_aoa_dev { struct device *dev; struct reset_control *rst; void __iomem *base; + int irq; }; static const struct of_device_id rockchip_aoa_match[] __maybe_unused = { @@ -46,36 +47,69 @@ int rockchip_aoa_probe(struct platform_device *pdev) struct device_node *node = pdev->dev.of_node; struct rk_aoa_dev *aoa; int ret, irq; + struct resource *res; - aoa = devm_kzalloc(&pdev->dev, sizeof(*aoa), GFP_KERNEL); - if (!aoa) - return -ENOMEM; + aoa = kzalloc(sizeof(*aoa), GFP_KERNEL); + if (!aoa) { + ret = -ENOMEM; + goto err_out; + } aoa->dev = &pdev->dev; - dev_set_drvdata(&pdev->dev, aoa); + res = platform_get_resource(pdev, IORESOURCE_MEM, 0); + if (!res) { + ret = -ENODEV; + goto err_free_aoa; + } - aoa->base = devm_platform_ioremap_resource(pdev, 0); - if (IS_ERR(aoa->base)) - return PTR_ERR(aoa->base); + aoa->base = ioremap(res->start, resource_size(res)); + if (!aoa->base) { + ret = -ENOMEM; + goto err_free_aoa; + } - aoa->rst = devm_reset_control_array_get_optional_exclusive(aoa->dev); - if (IS_ERR(aoa->rst)) - return PTR_ERR(aoa->rst); + aoa->rst = of_reset_control_array_get_optional_exclusive(node); + if (IS_ERR(aoa->rst)) { + ret = PTR_ERR(aoa->rst); + goto err_unmap; + } irq = platform_get_irq_optional(pdev, 0); if (irq > 0) { - ret = devm_request_irq(&pdev->dev, irq, rockchip_aoa_isr, - IRQF_SHARED, node->name, aoa); + ret = request_irq(irq, rockchip_aoa_isr, 0, node->name, aoa); if (ret) { dev_err(&pdev->dev, "Failed to request irq %d\n", irq); - return ret; + goto err_put_rst; } } - + aoa->irq = irq; + dev_set_drvdata(&pdev->dev, aoa); return 0; + +err_put_rst: + reset_control_put(aoa->rst); +err_unmap: + iounmap(aoa->base); +err_free_aoa: + kfree(aoa); +err_out: + return ret; } int rockchip_aoa_remove(struct platform_device *pdev) { + struct rk_aoa_dev *aoa = platform_get_drvdata(pdev); + + if (aoa) { + if (aoa->irq > 0) { + disable_irq(aoa->irq); + free_irq(aoa->irq, aoa); + } + + reset_control_put(aoa->rst); + iounmap(aoa->base); + kfree(aoa); + dev_set_drvdata(&pdev->dev, NULL); + } return 0; } diff --git a/drivers/soc/rockchip/aoa_middleware/aoa_middleware.c b/drivers/soc/rockchip/aoa_middleware/aoa_middleware.c index a05be63789ff..dab1f7697d5e 100644 --- a/drivers/soc/rockchip/aoa_middleware/aoa_middleware.c +++ b/drivers/soc/rockchip/aoa_middleware/aoa_middleware.c @@ -37,6 +37,7 @@ struct aoa_middleware_devs { struct device *dev; struct platform_device *pdev_aoa; struct platform_device *pdev_dma; + void *am_d; }; static struct fasync_struct *rk_aoa_fasync_queue; @@ -167,88 +168,143 @@ static struct miscdevice rk_dma_notifier_misc = { static int aoa_middleware_probe(struct platform_device *pdev) { struct aoa_middleware_devs *amw_d; - struct platform_device *pdev_slave; - struct device_node *np; - int ret; + struct platform_device *pdev_slave = NULL; + struct device_node *np = NULL; + void *am_map = NULL; + int ret = 0; amw_d = devm_kzalloc(&pdev->dev, sizeof(*amw_d), GFP_KERNEL); if (!amw_d) return -ENOMEM; amw_d->dev = &pdev->dev; + amw_d->pdev_aoa = NULL; + amw_d->pdev_dma = NULL; + amw_d->am_d = NULL; /* prepare rockchip aoa control driver */ np = of_parse_phandle(pdev->dev.of_node, "rockchip,aoa", 0); if (!np || !of_device_is_available(np)) { dev_err(&pdev->dev, "can't find 'rockchip,aoa' node\n"); - return -ENODEV; + ret = -ENODEV; + goto err_out; } + pdev_slave = of_find_device_by_node(np); of_node_put(np); if (!pdev_slave) { dev_err(&pdev->dev, "get aoa node failed\n"); - return -ENODEV; + ret = -ENODEV; + goto err_out; } + ret = rockchip_aoa_probe(pdev_slave); if (ret) { dev_err(&pdev->dev, "probe rockchip aoa failed: %d\n", ret); - return ret; + goto err_put_aoa; } amw_d->pdev_aoa = pdev_slave; + pdev_slave = NULL; /* prepare rockchip low-power dma driver */ np = of_parse_phandle(pdev->dev.of_node, "rockchip,dma", 0); if (!np || !of_device_is_available(np)) { dev_err(&pdev->dev, "can't find 'rockchip,dma' node\n"); - return -ENODEV; + ret = -ENODEV; + goto err_unprobe_aoa; } + pdev_slave = of_find_device_by_node(np); of_node_put(np); if (!pdev_slave) { dev_err(&pdev->dev, "get dma node failed\n"); - return -ENODEV; + ret = -ENODEV; + goto err_unprobe_aoa; } + ret = lp_rkdma_probe(pdev_slave); if (ret) { dev_err(&pdev->dev, "probe rockchip dma failed: %d\n", ret); - return ret; + goto err_put_dma; } amw_d->pdev_dma = pdev_slave; + pdev_slave = NULL; - /* prepare aoa memory mapping */ - ret = aoa_mmap_probe(pdev); - if (ret) { + am_map = aoa_mmap_probe(pdev); + if (IS_ERR_OR_NULL(am_map)) { + if (IS_ERR(am_map)) + ret = PTR_ERR(am_map); + else + ret = -EINVAL; dev_err(&pdev->dev, "%s: aoa mmap probe failed (%d)\n", __func__, ret); - return ret; + goto err_unprobe_dma; } + amw_d->am_d = am_map; - /* prepare aoa/dma notifiers */ ret = misc_register(&rk_aoa_notifier_misc); if (ret) { dev_err(&pdev->dev, "%s: aoa notifier misc register failed (%d)\n", __func__, ret); - return ret; + goto err_mmap_remove; } ret = misc_register(&rk_dma_notifier_misc); if (ret) { dev_err(&pdev->dev, "%s: dma notifier misc register failed (%d)\n", __func__, ret); - return ret; + goto err_unregister_aoa_misc; } platform_set_drvdata(pdev, amw_d); dev_info(&pdev->dev, "%s: all aoa middlewares are registered\n", __func__); return 0; + +err_unregister_aoa_misc: + misc_deregister(&rk_aoa_notifier_misc); +err_mmap_remove: + if (amw_d->am_d) { + aoa_mmap_remove(pdev, amw_d->am_d); + amw_d->am_d = NULL; + } +err_unprobe_dma: + if (amw_d->pdev_dma) + lp_rkdma_remove(amw_d->pdev_dma); +err_put_dma: + if (amw_d->pdev_dma) { + platform_device_put(amw_d->pdev_dma); + amw_d->pdev_dma = NULL; + } +err_unprobe_aoa: + if (amw_d->pdev_aoa) + rockchip_aoa_remove(amw_d->pdev_aoa); +err_put_aoa: + if (amw_d->pdev_aoa) { + platform_device_put(amw_d->pdev_aoa); + amw_d->pdev_aoa = NULL; + } +err_out: + if (pdev_slave) + platform_device_put(pdev_slave); + return ret; } static int aoa_middleware_remove(struct platform_device *pdev) { struct aoa_middleware_devs *amw_d = platform_get_drvdata(pdev); - if (IS_ERR(amw_d)) + if (IS_ERR_OR_NULL(amw_d)) return -EINVAL; - rockchip_aoa_remove(amw_d->pdev_aoa); - lp_rkdma_remove(amw_d->pdev_dma); - aoa_mmap_remove(pdev); + if (amw_d->pdev_aoa) { + rockchip_aoa_remove(amw_d->pdev_aoa); + platform_device_put(amw_d->pdev_aoa); + amw_d->pdev_aoa = NULL; + } + + if (amw_d->pdev_dma) { + lp_rkdma_remove(amw_d->pdev_dma); + platform_device_put(amw_d->pdev_dma); + amw_d->pdev_dma = NULL; + } + + aoa_mmap_remove(pdev, amw_d->am_d); misc_deregister(&rk_dma_notifier_misc); misc_deregister(&rk_aoa_notifier_misc); diff --git a/drivers/soc/rockchip/aoa_middleware/aoa_mmap.c b/drivers/soc/rockchip/aoa_middleware/aoa_mmap.c index 55bce67ea3f6..f95278ed345a 100644 --- a/drivers/soc/rockchip/aoa_middleware/aoa_mmap.c +++ b/drivers/soc/rockchip/aoa_middleware/aoa_mmap.c @@ -95,7 +95,7 @@ static const struct file_operations aoa_mmap_fops = { .unlocked_ioctl = aoa_mmap_ioctl, }; -int aoa_mmap_probe(struct platform_device *pdev) +void *aoa_mmap_probe(struct platform_device *pdev) { struct aoa_mmap_dev *am_d; struct resource res; @@ -104,20 +104,20 @@ int aoa_mmap_probe(struct platform_device *pdev) am_d = devm_kzalloc(&pdev->dev, sizeof(*am_d), GFP_KERNEL); if (!am_d) - return -ENOMEM; + return ERR_PTR(-ENOMEM); am_d->dev = &pdev->dev; res_node = of_parse_phandle(pdev->dev.of_node, "memory-region", 0); if (!res_node) { dev_err(&pdev->dev, "failed to get memory region node\n"); - return -ENODEV; + return NULL; } ret = of_address_to_resource(res_node, 0, &res); of_node_put(res_node); if (ret) { dev_err(&pdev->dev, "failed to get reserved region address\n"); - return -ENODEV; + return NULL; } am_d->phys = res.start; @@ -127,7 +127,7 @@ int aoa_mmap_probe(struct platform_device *pdev) am_d->kvirt = devm_ioremap(am_d->dev, am_d->phys, am_d->size); if (!am_d->kvirt) { dev_err(am_d->dev, "ioremap failed\n"); - return -ENOMEM; + return NULL; } am_d->misc.minor = MISC_DYNAMIC_MINOR; @@ -137,19 +137,19 @@ int aoa_mmap_probe(struct platform_device *pdev) ret = misc_register(&am_d->misc); if (ret) { dev_err(am_d->dev, "misc_register failed: %d\n", ret); - return ret; + return NULL; } - platform_set_drvdata(pdev, am_d); dev_info(am_d->dev, "aoa_mmap_mem: mapped phys=%pa size=%u\n", &am_d->phys, am_d->size); - return 0; + return am_d; } -int aoa_mmap_remove(struct platform_device *pdev) +int aoa_mmap_remove(struct platform_device *pdev, void *am_d) { - struct aoa_mmap_dev *am_d = platform_get_drvdata(pdev); + if (!am_d) + return -ENOMEM; - misc_deregister(&am_d->misc); + misc_deregister(&((struct aoa_mmap_dev *)am_d)->misc); return 0; } diff --git a/drivers/soc/rockchip/aoa_middleware/aoa_mmap.h b/drivers/soc/rockchip/aoa_middleware/aoa_mmap.h index 5e0e7438dda7..4ee2fb24efe0 100644 --- a/drivers/soc/rockchip/aoa_middleware/aoa_mmap.h +++ b/drivers/soc/rockchip/aoa_middleware/aoa_mmap.h @@ -9,7 +9,7 @@ #ifndef __AOA_MMAP_H__ #define __AOA_MMAP_H__ -int aoa_mmap_probe(struct platform_device *pdev); -int aoa_mmap_remove(struct platform_device *pdev); +void *aoa_mmap_probe(struct platform_device *pdev); +int aoa_mmap_remove(struct platform_device *pdev, void *am_d); #endif /* __AOA_MMAP_H__ */ diff --git a/drivers/soc/rockchip/aoa_middleware/lp_rkdma.c b/drivers/soc/rockchip/aoa_middleware/lp_rkdma.c index 4f0e938539ca..84eb3c93a223 100644 --- a/drivers/soc/rockchip/aoa_middleware/lp_rkdma.c +++ b/drivers/soc/rockchip/aoa_middleware/lp_rkdma.c @@ -169,20 +169,35 @@ static irqreturn_t lp_rkdma_irq_handler(int irq, void *dev_id) int lp_rkdma_probe(struct platform_device *pdev) { struct lp_rkdma_dev *d; + struct resource *res; int i, ret; - d = devm_kzalloc(&pdev->dev, sizeof(*d), GFP_KERNEL); - if (!d) - return -ENOMEM; + d = kzalloc(sizeof(*d), GFP_KERNEL); + if (!d) { + ret = -ENOMEM; + goto err_out; + } - d->base = devm_platform_ioremap_resource(pdev, 0); - if (IS_ERR(d->base)) - return PTR_ERR(d->base); + res = platform_get_resource(pdev, IORESOURCE_MEM, 0); + if (!res) { + ret = -ENODEV; + goto err_free_d; + } + if (!request_mem_region(res->start, resource_size(res), dev_name(&pdev->dev))) { + ret = -EBUSY; + goto err_free_d; + } + d->base = ioremap(res->start, resource_size(res)); + if (!d->base) { + ret = -ENOMEM; + goto err_free_region; + } - d->num_clks = devm_clk_bulk_get_all(&pdev->dev, &d->clks); + d->num_clks = clk_bulk_get_all(&pdev->dev, &d->clks); if (d->num_clks < 1) { dev_err(&pdev->dev, "Failed to get clk\n"); - return -ENODEV; + ret = -ENODEV; + goto err_free_ioremap; } d->irq = platform_get_irq(pdev, 0); @@ -193,13 +208,13 @@ int lp_rkdma_probe(struct platform_device *pdev) ret = clk_bulk_prepare_enable(d->num_clks, d->clks); if (ret < 0) { dev_err(&pdev->dev, "Failed to enable clk: %d\n", ret); - return ret; + goto err_put_clks; } lp_rkdma_init(d); /* init lch channel */ - d->lch = devm_kcalloc(&pdev->dev, d->dma_channels, sizeof(struct lp_rkdma_lch), GFP_KERNEL); + d->lch = kcalloc(d->dma_channels, sizeof(struct lp_rkdma_lch), GFP_KERNEL); if (!d->lch) { ret = -ENOMEM; goto err_disable_clk; @@ -212,17 +227,46 @@ int lp_rkdma_probe(struct platform_device *pdev) l->base = RK_DMA_LCHn_REG(i, 0); } - return devm_request_irq(&pdev->dev, d->irq, lp_rkdma_irq_handler, 0, dev_name(&pdev->dev), d); + ret = request_irq(d->irq, lp_rkdma_irq_handler, 0, dev_name(&pdev->dev), d); + if (ret) + goto err_free_lch; + return 0; +err_free_lch: + kfree(d->lch); err_disable_clk: clk_bulk_disable_unprepare(d->num_clks, d->clks); +err_put_clks: + clk_bulk_put_all(d->num_clks, d->clks); +err_free_ioremap: + iounmap(d->base); +err_free_region: + release_mem_region(res->start, resource_size(res)); +err_free_d: + kfree(d); +err_out: return ret; } int lp_rkdma_remove(struct platform_device *pdev) { struct lp_rkdma_dev *d = platform_get_drvdata(pdev); + struct resource *res = platform_get_resource(pdev, IORESOURCE_MEM, 0); - clk_bulk_disable_unprepare(d->num_clks, d->clks); + if (d) { + if (d->irq > 0) { + disable_irq(d->irq); + free_irq(d->irq, d); + } + + clk_bulk_disable_unprepare(d->num_clks, d->clks); + clk_bulk_put_all(d->num_clks, d->clks); + kfree(d->lch); + iounmap(d->base); + if (res) + release_mem_region(res->start, resource_size(res)); + kfree(d); + platform_set_drvdata(pdev, NULL); + } return 0; } From 5806024db1f64acff5f1d72c2c081c6843247580 Mon Sep 17 00:00:00 2001 From: Xing Zheng Date: Sat, 30 Aug 2025 18:23:37 +0800 Subject: [PATCH 03/21] soc: rockchip: aoa_middleware: fix the log storm caused by DMA interrupt not being closed during repeated insmod Abnormal log appears steps: insmod rk_aoa.ko start sample_aoa_capture kill sample_aoa_capture rmmod rk_aoa insmod rk_aoa.ko ---- [ 788.184730] Invalid dma_count: 110 [ 788.200733] Invalid dma_count: 111 [ 788.216741] Invalid dma_count: 112 [ 788.232745] Invalid dma_count: 0 [ 788.248748] Invalid dma_count: 1 ---- Therefore, we need to make sure that the DMA interrupt is disabled again when rmmod rk_aoa.ko. Signed-off-by: Xing Zheng Change-Id: If9ebff47b8307c2f1759678e5aa050f530ae5041 --- drivers/soc/rockchip/aoa_middleware/lp_rkdma.c | 17 +++++++---------- 1 file changed, 7 insertions(+), 10 deletions(-) diff --git a/drivers/soc/rockchip/aoa_middleware/lp_rkdma.c b/drivers/soc/rockchip/aoa_middleware/lp_rkdma.c index 84eb3c93a223..2bc1c871d040 100644 --- a/drivers/soc/rockchip/aoa_middleware/lp_rkdma.c +++ b/drivers/soc/rockchip/aoa_middleware/lp_rkdma.c @@ -106,11 +106,10 @@ struct lp_rkdma_dev { static int lp_rkdma_init(struct lp_rkdma_dev *d) { - int i, lch, pch, buswidth, maxburst, dep, addrwidth; + int lch, pch, buswidth, maxburst, dep, addrwidth; u32 cap0, cap1, ver; - writel(CMN_CFG_EN | CMN_CFG_IE_EN, RK_DMA_CMN_CFG); - + /* Just get base infos of rkdma */ ver = readl(RK_DMA_CMN_VER); cap0 = readl(RK_DMA_CMN_CAP0); cap1 = readl(RK_DMA_CMN_CAP1); @@ -129,13 +128,6 @@ static int lp_rkdma_init(struct lp_rkdma_dev *d) d->dma_channels = CMN_LCH_NUM(cap0); d->dma_requests = CMN_LCH_NUM(cap0); - writel(0xffffffff, RK_DMA_CMN_DYNCTL); - writel(0xffffffff, RK_DMA_CMN_IS0); - writel(0xffffffff, RK_DMA_CMN_IS1); - - for (i = 0; i < pch; i++) - writel(CMN_PCH_EN(i), RK_DMA_CMN_PCH_EN); - dev_info(d->dev, "Lowpower RKDMA: NR_LCH-%d NR_PCH-%d PCH_BUF-%dx%dBytes AXI_LEN-%d ADDR-%dBits V%lu.%lu\n", lch, pch, dep, buswidth, maxburst, addrwidth, CMN_VER_MAJOR(ver), CMN_VER_MINOR(ver)); @@ -251,8 +243,13 @@ err_out: int lp_rkdma_remove(struct platform_device *pdev) { struct lp_rkdma_dev *d = platform_get_drvdata(pdev); + struct lp_rkdma_lch *l = &d->lch[0]; struct resource *res = platform_get_resource(pdev, IORESOURCE_MEM, 0); + /* make sure disable IRQ requests during removing module */ + writel(0x0, RK_DMA_LCH_CTL0); + writel(0x0, RK_DMA_LCH_IE); + if (d) { if (d->irq > 0) { disable_irq(d->irq); From f97790a06e40cfb36fbb6af69cc5b34dffa2996c Mon Sep 17 00:00:00 2001 From: Xing Zheng Date: Tue, 2 Sep 2025 20:15:01 +0800 Subject: [PATCH 04/21] soc: rockchip: aoa_middleware: remove global variables as much as possible to avoid multi-core racing issues Signed-off-by: Xing Zheng Change-Id: If08e2f68a86c61fc94f58371f2b9e78ffbf8fc3c --- drivers/soc/rockchip/aoa_middleware/aoa_drv.c | 6 +- drivers/soc/rockchip/aoa_middleware/aoa_drv.h | 2 +- .../rockchip/aoa_middleware/aoa_middleware.c | 124 +++++++++++++----- .../rockchip/aoa_middleware/aoa_middleware.h | 4 +- .../soc/rockchip/aoa_middleware/lp_rkdma.c | 6 +- .../soc/rockchip/aoa_middleware/lp_rkdma.h | 2 +- 6 files changed, 102 insertions(+), 42 deletions(-) diff --git a/drivers/soc/rockchip/aoa_middleware/aoa_drv.c b/drivers/soc/rockchip/aoa_middleware/aoa_drv.c index aa3dc7ec699d..397e39bf9387 100644 --- a/drivers/soc/rockchip/aoa_middleware/aoa_drv.c +++ b/drivers/soc/rockchip/aoa_middleware/aoa_drv.c @@ -20,6 +20,7 @@ struct rk_aoa_dev { struct reset_control *rst; void __iomem *base; int irq; + void *data; }; static const struct of_device_id rockchip_aoa_match[] __maybe_unused = { @@ -36,13 +37,13 @@ static irqreturn_t rockchip_aoa_isr(int irq, void *devid) writel(st, aoa->base + AOA_AAD_IRQ_ST); for (s = 1; s < 8; s++) { if (st & (1 << s)) - aoa_middleware_aoa_notifier(s); + aoa_middleware_aoa_notifier(s, aoa->data); } return IRQ_HANDLED; } -int rockchip_aoa_probe(struct platform_device *pdev) +int rockchip_aoa_probe(struct platform_device *pdev, void *data) { struct device_node *node = pdev->dev.of_node; struct rk_aoa_dev *aoa; @@ -83,6 +84,7 @@ int rockchip_aoa_probe(struct platform_device *pdev) } } aoa->irq = irq; + aoa->data = data; dev_set_drvdata(&pdev->dev, aoa); return 0; diff --git a/drivers/soc/rockchip/aoa_middleware/aoa_drv.h b/drivers/soc/rockchip/aoa_middleware/aoa_drv.h index 697ad36f28c8..859b582abbc1 100644 --- a/drivers/soc/rockchip/aoa_middleware/aoa_drv.h +++ b/drivers/soc/rockchip/aoa_middleware/aoa_drv.h @@ -9,7 +9,7 @@ #ifndef __AOA_DRV_H__ #define __AOA_DRV_H__ -int rockchip_aoa_probe(struct platform_device *pdev); +int rockchip_aoa_probe(struct platform_device *pdev, void *data); int rockchip_aoa_remove(struct platform_device *pdev); #endif /* __AOA_DRV_H__ */ diff --git a/drivers/soc/rockchip/aoa_middleware/aoa_middleware.c b/drivers/soc/rockchip/aoa_middleware/aoa_middleware.c index dab1f7697d5e..1e59829f698a 100644 --- a/drivers/soc/rockchip/aoa_middleware/aoa_middleware.c +++ b/drivers/soc/rockchip/aoa_middleware/aoa_middleware.c @@ -38,36 +38,60 @@ struct aoa_middleware_devs { struct platform_device *pdev_aoa; struct platform_device *pdev_dma; void *am_d; + struct notify_rkdma *nty_rkdma; + struct notify_ns *nty_ns; + struct miscdevice misc_notifier_aoa; + struct miscdevice misc_notifier_dma; + struct fasync_struct *rk_aoa_fasync_queue; + struct fasync_struct *rk_dma_fasync_queue; }; -static struct fasync_struct *rk_aoa_fasync_queue; -static struct fasync_struct *rk_dma_fasync_queue; - -static struct notify_rkdma g_notify; -static struct notify_ns g_dma_ns; - -int aoa_middleware_aoa_notifier(s32 status) +int aoa_middleware_aoa_notifier(s32 status, void *data) { + struct aoa_middleware_devs *amw_d = data; + + if (!amw_d) { + pr_err("%s: amw_d pointer is null\n", __func__); + return -EINVAL; + } + /* AOA Notify starting from SIGRTMIN + 1 */ - kill_fasync(&rk_aoa_fasync_queue, SIGRTMIN + status, POLL_IN); + kill_fasync(&amw_d->rk_aoa_fasync_queue, SIGRTMIN + status, POLL_IN); return 0; } EXPORT_SYMBOL(aoa_middleware_aoa_notifier); -int aoa_middleware_dma_notifier(s32 dma_count) +int aoa_middleware_dma_notifier(s32 dma_count, void *data) { - struct notify_rkdma *n_rkdma = &g_notify; - struct notify_ns *n_ns = &g_dma_ns; + struct aoa_middleware_devs *amw_d = data; + struct notify_rkdma *n_rkdma; + struct notify_ns *n_ns; struct timespec64 ts; s32 delta_id; + if (!amw_d) { + pr_err("%s: amw_d pointer is null\n", __func__); + return -EINVAL; + } + if (!amw_d->nty_rkdma) { + pr_err("%s: nty_rkdma pointer is null\n", __func__); + return -EINVAL; + } + if (!amw_d->nty_ns) { + pr_err("%s: nty_ns pointer is null\n", __func__); + return -EINVAL; + } + + n_rkdma = amw_d->nty_rkdma; + n_ns = amw_d->nty_ns; + ktime_get_boottime_ts64(&ts); n_ns->ns = timespec64_to_ns(&ts); - kill_fasync(&rk_dma_fasync_queue, SIGRTMIN + 0, POLL_IN); + kill_fasync(&amw_d->rk_dma_fasync_queue, SIGRTMIN + 0, POLL_IN); /* ns_id: start from 1, range: 0 ~ (periods-1) */ if (dma_count < 0 || dma_count >= n_rkdma->periods) { - pr_err("Invalid dma_count: %d\n", dma_count); + pr_err("Invalid dma_count: %d >= periods: %d\n", dma_count, n_rkdma->periods); return -EINVAL; } dma_count = array_index_nospec(dma_count, n_rkdma->periods); @@ -98,32 +122,56 @@ int aoa_middleware_dma_notifier(s32 dma_count) } EXPORT_SYMBOL(aoa_middleware_dma_notifier); +static int rk_aoa_notifier_open(struct inode *inode, struct file *file) +{ + struct miscdevice *misc = file->private_data; + struct aoa_middleware_devs *amw_d = container_of(misc, struct aoa_middleware_devs, misc_notifier_aoa); + + file->private_data = amw_d; + return 0; +} + static int rk_aoa_notifier_fasync(int fd, struct file *file, int mode) { - return fasync_helper(fd, file, mode, &rk_aoa_fasync_queue); + struct aoa_middleware_devs *amw_d = file->private_data; + + return fasync_helper(fd, file, mode, &amw_d->rk_aoa_fasync_queue); } static const struct file_operations rk_aoa_notifier_fops = { .owner = THIS_MODULE, + .open = rk_aoa_notifier_open, .fasync = rk_aoa_notifier_fasync, }; -static struct miscdevice rk_aoa_notifier_misc = { - .minor = MISC_DYNAMIC_MINOR, - .name = "rk-aoa-notifier", - .fops = &rk_aoa_notifier_fops, -}; +static int rk_dma_notifier_open(struct inode *inode, struct file *file) +{ + struct miscdevice *misc = file->private_data; + struct aoa_middleware_devs *amw_d = container_of(misc, struct aoa_middleware_devs, misc_notifier_dma); + + file->private_data = amw_d; + return 0; +} static int rk_dma_notifier_fasync(int fd, struct file *file, int mode) { - return fasync_helper(fd, file, mode, &rk_dma_fasync_queue); + struct aoa_middleware_devs *amw_d = file->private_data; + + return fasync_helper(fd, file, mode, &amw_d->rk_dma_fasync_queue); } static long rk_dma_notifier_ioctl(struct file *file, unsigned int cmd, unsigned long arg) { - struct notify_rkdma *n_rkdma = &g_notify; + struct aoa_middleware_devs *amw_d = file->private_data; + struct notify_rkdma *n_rkdma; struct notify_ns n_ns_user; + if (IS_ERR_OR_NULL(amw_d)) + return -EINVAL; + if (IS_ERR_OR_NULL(amw_d->nty_rkdma)) + return -EINVAL; + n_rkdma = amw_d->nty_rkdma; + switch (cmd) { case NOTIFY_RKDMA_SET_PERIODS: n_rkdma->periods = arg; @@ -154,17 +202,12 @@ static long rk_dma_notifier_ioctl(struct file *file, unsigned int cmd, unsigned static const struct file_operations rk_dma_notifier_fops = { .owner = THIS_MODULE, + .open = rk_dma_notifier_open, .fasync = rk_dma_notifier_fasync, .compat_ioctl = rk_dma_notifier_ioctl, .unlocked_ioctl = rk_dma_notifier_ioctl, }; -static struct miscdevice rk_dma_notifier_misc = { - .minor = MISC_DYNAMIC_MINOR, - .name = "rk-dma-notifier", - .fops = &rk_dma_notifier_fops, -}; - static int aoa_middleware_probe(struct platform_device *pdev) { struct aoa_middleware_devs *amw_d; @@ -176,6 +219,12 @@ static int aoa_middleware_probe(struct platform_device *pdev) amw_d = devm_kzalloc(&pdev->dev, sizeof(*amw_d), GFP_KERNEL); if (!amw_d) return -ENOMEM; + amw_d->nty_rkdma = devm_kzalloc(&pdev->dev, sizeof(*amw_d->nty_rkdma), GFP_KERNEL); + if (!amw_d->nty_rkdma) + return -ENOMEM; + amw_d->nty_ns = devm_kzalloc(&pdev->dev, sizeof(*amw_d->nty_ns), GFP_KERNEL); + if (!amw_d->nty_ns) + return -ENOMEM; amw_d->dev = &pdev->dev; amw_d->pdev_aoa = NULL; amw_d->pdev_dma = NULL; @@ -197,7 +246,7 @@ static int aoa_middleware_probe(struct platform_device *pdev) goto err_out; } - ret = rockchip_aoa_probe(pdev_slave); + ret = rockchip_aoa_probe(pdev_slave, (void *)amw_d); if (ret) { dev_err(&pdev->dev, "probe rockchip aoa failed: %d\n", ret); goto err_put_aoa; @@ -221,7 +270,7 @@ static int aoa_middleware_probe(struct platform_device *pdev) goto err_unprobe_aoa; } - ret = lp_rkdma_probe(pdev_slave); + ret = lp_rkdma_probe(pdev_slave, (void *)amw_d); if (ret) { dev_err(&pdev->dev, "probe rockchip dma failed: %d\n", ret); goto err_put_dma; @@ -240,13 +289,20 @@ static int aoa_middleware_probe(struct platform_device *pdev) } amw_d->am_d = am_map; - ret = misc_register(&rk_aoa_notifier_misc); + /* prepare aoa/dma notifiers */ + amw_d->misc_notifier_aoa.minor = MISC_DYNAMIC_MINOR; + amw_d->misc_notifier_aoa.name = "rk-aoa-notifier"; + amw_d->misc_notifier_aoa.fops = &rk_aoa_notifier_fops; + ret = misc_register(&amw_d->misc_notifier_aoa); if (ret) { dev_err(&pdev->dev, "%s: aoa notifier misc register failed (%d)\n", __func__, ret); goto err_mmap_remove; } - ret = misc_register(&rk_dma_notifier_misc); + amw_d->misc_notifier_dma.minor = MISC_DYNAMIC_MINOR; + amw_d->misc_notifier_dma.name = "rk-dma-notifier"; + amw_d->misc_notifier_dma.fops = &rk_dma_notifier_fops; + ret = misc_register(&amw_d->misc_notifier_dma); if (ret) { dev_err(&pdev->dev, "%s: dma notifier misc register failed (%d)\n", __func__, ret); goto err_unregister_aoa_misc; @@ -257,7 +313,7 @@ static int aoa_middleware_probe(struct platform_device *pdev) return 0; err_unregister_aoa_misc: - misc_deregister(&rk_aoa_notifier_misc); + misc_deregister(&amw_d->misc_notifier_aoa); err_mmap_remove: if (amw_d->am_d) { aoa_mmap_remove(pdev, amw_d->am_d); @@ -306,8 +362,8 @@ static int aoa_middleware_remove(struct platform_device *pdev) aoa_mmap_remove(pdev, amw_d->am_d); - misc_deregister(&rk_dma_notifier_misc); - misc_deregister(&rk_aoa_notifier_misc); + misc_deregister(&amw_d->misc_notifier_aoa); + misc_deregister(&amw_d->misc_notifier_dma); dev_info(&pdev->dev, "%s: all aoa middlewares are unregistered\n", __func__); return 0; diff --git a/drivers/soc/rockchip/aoa_middleware/aoa_middleware.h b/drivers/soc/rockchip/aoa_middleware/aoa_middleware.h index 5c51d6028899..a0a4d1aefacb 100644 --- a/drivers/soc/rockchip/aoa_middleware/aoa_middleware.h +++ b/drivers/soc/rockchip/aoa_middleware/aoa_middleware.h @@ -9,7 +9,7 @@ #ifndef __AOA_MIDDLEWARE_H__ #define __AOA_MIDDLEWARE_H__ -int aoa_middleware_aoa_notifier(s32 status); -int aoa_middleware_dma_notifier(s32 dma_count); +int aoa_middleware_aoa_notifier(s32 status, void *data); +int aoa_middleware_dma_notifier(s32 dma_count, void *data); #endif /* __AOA_MIDDLEWARE_H__ */ diff --git a/drivers/soc/rockchip/aoa_middleware/lp_rkdma.c b/drivers/soc/rockchip/aoa_middleware/lp_rkdma.c index 2bc1c871d040..5447f792f027 100644 --- a/drivers/soc/rockchip/aoa_middleware/lp_rkdma.c +++ b/drivers/soc/rockchip/aoa_middleware/lp_rkdma.c @@ -102,6 +102,7 @@ struct lp_rkdma_dev { u32 dma_channels; u32 dma_requests; u32 version; + void *data; }; static int lp_rkdma_init(struct lp_rkdma_dev *d) @@ -142,7 +143,7 @@ static irqreturn_t lp_rkdma_irq_handler(int irq, void *dev_id) u64 is = 0, is_raw = 0; u32 i = 0; - aoa_middleware_dma_notifier(readl(RK_DMA_LCH_LLI_CNT)); + aoa_middleware_dma_notifier(readl(RK_DMA_LCH_LLI_CNT), d->data); is = readq(RK_DMA_CMN_IS0); is_raw = is; @@ -158,7 +159,7 @@ static irqreturn_t lp_rkdma_irq_handler(int irq, void *dev_id) return IRQ_HANDLED; } -int lp_rkdma_probe(struct platform_device *pdev) +int lp_rkdma_probe(struct platform_device *pdev, void *data) { struct lp_rkdma_dev *d; struct resource *res; @@ -218,6 +219,7 @@ int lp_rkdma_probe(struct platform_device *pdev) l->id = i; l->base = RK_DMA_LCHn_REG(i, 0); } + d->data = data; ret = request_irq(d->irq, lp_rkdma_irq_handler, 0, dev_name(&pdev->dev), d); if (ret) diff --git a/drivers/soc/rockchip/aoa_middleware/lp_rkdma.h b/drivers/soc/rockchip/aoa_middleware/lp_rkdma.h index e79bcf1d4db5..b439966fcf10 100644 --- a/drivers/soc/rockchip/aoa_middleware/lp_rkdma.h +++ b/drivers/soc/rockchip/aoa_middleware/lp_rkdma.h @@ -9,7 +9,7 @@ #ifndef __LP_RKDMA_H__ #define __LP_RKDMA_H__ -int lp_rkdma_probe(struct platform_device *pdev); +int lp_rkdma_probe(struct platform_device *pdev, void *data); int lp_rkdma_remove(struct platform_device *pdev); #endif /* __LP_RKDMA_H__ */ From 8bf958c071739920f3814524716444d94b44f904 Mon Sep 17 00:00:00 2001 From: Zefa Chen Date: Tue, 2 Sep 2025 09:43:49 +0800 Subject: [PATCH 05/21] media: rockchip: vicap disables its dma adapter when in debug mode Change-Id: If30a5b3011734d5ae1a7c76f72753d0e1906a2ac Signed-off-by: Zefa Chen --- drivers/media/platform/rockchip/cif/capture.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/media/platform/rockchip/cif/capture.c b/drivers/media/platform/rockchip/cif/capture.c index e5d691085789..abddc1a87585 100644 --- a/drivers/media/platform/rockchip/cif/capture.c +++ b/drivers/media/platform/rockchip/cif/capture.c @@ -5240,7 +5240,7 @@ static int rkcif_csi_channel_set_rv1126b(struct rkcif_stream *stream, val |= (0x2 << 20); if (stream->rounding_bit) val |= stream->rounding_bit; - if (!dev->terminal_sensor.hdmi_input_en) + if (!dev->terminal_sensor.hdmi_input_en && !stream->sw_dbg_en) val |= DMA_ADAPT_EN_RV1126B; rkcif_write_register(dev, get_reg_index_of_id_ctrl0(channel->id), val); From 4cab224038c775e6430f677b14b70ef5d8a2a397 Mon Sep 17 00:00:00 2001 From: Simon Xue Date: Mon, 18 Aug 2025 10:21:04 +0800 Subject: [PATCH 06/21] dma-buf: rk_heaps: add rk-system-heap Change-Id: Iebcb584b76f528140a8621a33bf554f413075abd Signed-off-by: Simon Xue --- drivers/dma-buf/rk_heaps/Kconfig | 8 + drivers/dma-buf/rk_heaps/Makefile | 1 + drivers/dma-buf/rk_heaps/rk-dma-heap.c | 42 +++- drivers/dma-buf/rk_heaps/rk-dma-heap.h | 21 +- drivers/dma-buf/rk_heaps/rk-system-heap.c | 247 ++++++++++++++++++++++ include/linux/rk-dma-heap.h | 32 +++ 6 files changed, 347 insertions(+), 4 deletions(-) create mode 100644 drivers/dma-buf/rk_heaps/rk-system-heap.c diff --git a/drivers/dma-buf/rk_heaps/Kconfig b/drivers/dma-buf/rk_heaps/Kconfig index 6ca3fbe765ee..e77267bd0322 100644 --- a/drivers/dma-buf/rk_heaps/Kconfig +++ b/drivers/dma-buf/rk_heaps/Kconfig @@ -35,6 +35,14 @@ config DMABUF_HEAPS_ROCKCHIP_CMA_ALIGNMENT If unsure, leave the default value "8". +config DMABUF_HEAPS_ROCKCHIP_SYSTEM_HEAP + tristate "DMA-BUF RockChip system Heap" + depends on DMABUF_HEAPS_ROCKCHIP + help + Choose this option to enable dma-buf RockChip SYSTEM heap. This heap is backed + by the system pages. If your system has these + regions, you should say Y here. + config DMABUF_RK_HEAPS_DEBUG bool "DMA-BUF RockChip Heap Debug" depends on DMABUF_HEAPS_ROCKCHIP diff --git a/drivers/dma-buf/rk_heaps/Makefile b/drivers/dma-buf/rk_heaps/Makefile index 30d44bb7d801..e0ba0351ea7b 100644 --- a/drivers/dma-buf/rk_heaps/Makefile +++ b/drivers/dma-buf/rk_heaps/Makefile @@ -4,3 +4,4 @@ rk-cma-heap-objs := rk-dma-cma.o rk-cma-heap.o obj-$(CONFIG_DMABUF_HEAPS_ROCKCHIP) += rk-dma-heap.o obj-$(CONFIG_DMABUF_HEAPS_ROCKCHIP_CMA_HEAP) += rk-cma-heap.o +obj-$(CONFIG_DMABUF_HEAPS_ROCKCHIP_SYSTEM_HEAP) += rk-system-heap.o diff --git a/drivers/dma-buf/rk_heaps/rk-dma-heap.c b/drivers/dma-buf/rk_heaps/rk-dma-heap.c index 1c68a7549e8a..26ba62f58d8f 100644 --- a/drivers/dma-buf/rk_heaps/rk-dma-heap.c +++ b/drivers/dma-buf/rk_heaps/rk-dma-heap.c @@ -215,6 +215,25 @@ void rk_dma_heap_total_dec(struct rk_dma_heap *heap, size_t len) mutex_unlock(&rk_heap_list_lock); } +int rk_dma_heap_alloc_pages(struct rk_dma_heap *heap, + struct page **pages, size_t len, gfp_t flags, + const char *name) +{ + len = PAGE_ALIGN(len); + if (!len) + return -EINVAL; + + return heap->ops->alloc_pages(heap, pages, len, flags, name); +} +EXPORT_SYMBOL_GPL(rk_dma_heap_alloc_pages); + +void rk_dma_heap_free_pages(struct rk_dma_heap *heap, + struct page **pages, unsigned int count) +{ + return heap->ops->free_pages(heap, pages, count); +} +EXPORT_SYMBOL_GPL(rk_dma_heap_free_pages); + static int rk_dma_heap_open(struct inode *inode, struct file *file) { struct rk_dma_heap *heap; @@ -398,7 +417,7 @@ struct rk_dma_heap *rk_dma_heap_add(const struct rk_dma_heap_export_info *exp_in return ERR_PTR(-EINVAL); } - if (!exp_info->ops || !exp_info->ops->allocate) { + if (!exp_info->ops || (!exp_info->permit_noalloc && !exp_info->ops->allocate)) { pr_err("rk_dma_heap: Cannot add heap with invalid ops struct\n"); return ERR_PTR(-EINVAL); } @@ -423,8 +442,10 @@ struct rk_dma_heap *rk_dma_heap_add(const struct rk_dma_heap_export_info *exp_in heap->support_cma = exp_info->support_cma; INIT_LIST_HEAD(&heap->dmabuf_list); INIT_LIST_HEAD(&heap->contig_list); + INIT_LIST_HEAD(&heap->pages_list); mutex_init(&heap->dmabuf_lock); mutex_init(&heap->contig_lock); + mutex_init(&heap->pages_lock); /* Find unused minor number */ ret = xa_alloc(&rk_dma_heap_minors, &minor, heap, @@ -450,7 +471,7 @@ struct rk_dma_heap *rk_dma_heap_add(const struct rk_dma_heap_export_info *exp_in NULL, heap->heap_devt, NULL, - heap->name); + "%s", heap->name); if (IS_ERR(heap->heap_dev)) { pr_err("rk_dma_heap: Unable to create device\n"); err_ret = ERR_CAST(heap->heap_dev); @@ -551,6 +572,21 @@ static int rk_dma_heap_dump_contig(void *data) return 0; } +static int rk_dma_heap_dump_pages(void *data) +{ + struct rk_dma_heap *heap = (struct rk_dma_heap *)data; + struct rk_dma_heap_pages_buf *buf; + + mutex_lock(&heap->pages_lock); + list_for_each_entry(buf, &heap->pages_list, node) { + seq_printf(heap->s, "\tAlloc by (%-20s)\t%lx (%lu KiB)\n", + buf->orig_alloc, buf->size, K(buf->size)); + } + mutex_unlock(&heap->pages_lock); + + return 0; +} + static ssize_t rk_total_pools_kb_show(struct kobject *kobj, struct kobj_attribute *attr, char *buf) { @@ -616,6 +652,7 @@ static int rk_dma_heap_debug_show(struct seq_file *s, void *unused) heap->s = s; dma_buf_get_each(rk_dma_heap_dump_dmabuf, heap); rk_dma_heap_dump_contig(heap); + rk_dma_heap_dump_pages(heap); total += heap->total_size; } seq_printf(s, "\nTotal : 0x%lx (%lu KiB)\n", total, K(total)); @@ -665,6 +702,7 @@ static int rk_dma_heap_proc_show(struct seq_file *s, void *unused) heap->s = s; dma_buf_get_each(rk_dma_heap_dump_dmabuf, heap); rk_dma_heap_dump_contig(heap); + rk_dma_heap_dump_pages(heap); total += heap->total_size; } seq_printf(s, "\nTotal : 0x%lx (%lu KiB)\n", total, K(total)); diff --git a/drivers/dma-buf/rk_heaps/rk-dma-heap.h b/drivers/dma-buf/rk_heaps/rk-dma-heap.h index 11cce03e862d..88d2b1155aa2 100644 --- a/drivers/dma-buf/rk_heaps/rk-dma-heap.h +++ b/drivers/dma-buf/rk_heaps/rk-dma-heap.h @@ -35,7 +35,10 @@ struct rk_vmap_pfn_data { * struct rk_dma_heap_ops - ops to operate on a given heap * @allocate: allocate dmabuf and return struct dma_buf ptr * @get_pool_size: if heap maintains memory pools, get pool size in bytes - * + @alloc_contig_pages: alloc pages from CMA + @free_contig_pages: free pages to CMA + * @alloc_pages: alloc pages from system + * @free_pages: free pages to system * allocate returns dmabuf on success, ERR_PTR(-errno) on error. */ struct rk_dma_heap_ops { @@ -44,12 +47,16 @@ struct rk_dma_heap_ops { unsigned long fd_flags, unsigned long heap_flags, const char *name); + long (*get_pool_size)(struct rk_dma_heap *heap); struct page *(*alloc_contig_pages)(struct rk_dma_heap *heap, size_t len, const char *name); void (*free_contig_pages)(struct rk_dma_heap *heap, struct page *pages, size_t len, const char *name); - long (*get_pool_size)(struct rk_dma_heap *heap); + int (*alloc_pages)(struct rk_dma_heap *heap, struct page **pages, + size_t len, gfp_t flags, const char *name); + void (*free_pages)(struct rk_dma_heap *heap, + struct page **pages, unsigned int count); }; /** @@ -65,6 +72,7 @@ struct rk_dma_heap_export_info { const struct rk_dma_heap_ops *ops; void *priv; bool support_cma; + bool permit_noalloc; }; /** @@ -88,6 +96,8 @@ struct rk_dma_heap { struct mutex dmabuf_lock; struct list_head contig_list; /* contig buffer attach to this node */ struct mutex contig_lock; + struct list_head pages_list; + struct mutex pages_lock; struct cdev heap_cdev; struct kref refcount; struct device *heap_dev; @@ -112,6 +122,13 @@ struct rk_dma_heap_contig_buf { phys_addr_t end; }; +struct rk_dma_heap_pages_buf { + struct list_head node; + unsigned long size; + const char *orig_alloc; + phys_addr_t start; +}; + /** * rk_dma_heap_get_drvdata() - get per-heap driver data * @heap: DMA-Heap to retrieve private data for diff --git a/drivers/dma-buf/rk_heaps/rk-system-heap.c b/drivers/dma-buf/rk_heaps/rk-system-heap.c new file mode 100644 index 000000000000..1ee656445ae2 --- /dev/null +++ b/drivers/dma-buf/rk_heaps/rk-system-heap.c @@ -0,0 +1,247 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * DMABUF System heap exporter + * + * Copyright (C) 2011 Google, Inc. + * Copyright (C) 2012, 2019, 2020 Linaro Ltd. + * + * Also utilizing parts of Andrew Davis' SRAM heap: + * Copyright (C) 2019 Texas Instruments Incorporated - http://www.ti.com/ + * Andrew F. Davis + * + * Copyright (C) 2025 Rockchip Electronics Co., Ltd. + * Author: Simon Xue + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "../../../mm/cma.h" +#include "rk-dma-heap.h" + +struct rk_system_heap { + struct rk_dma_heap *heap; +}; + +static int rk_system_heap_remove_pages_list(struct rk_dma_heap *heap, + struct page *page) +{ + struct rk_dma_heap_pages_buf *buf; + + mutex_lock(&heap->pages_lock); + list_for_each_entry(buf, &heap->pages_list, node) { + if (buf->start == page_to_phys(page)) { + dma_heap_print("<%s> free pages %ld to system\n", + buf->orig_alloc, buf->size); + list_del(&buf->node); + kfree(buf->orig_alloc); + kfree(buf); + break; + } + } + mutex_unlock(&heap->pages_lock); + + return 0; +} + +static int rk_system_heap_add_pages_list(struct rk_dma_heap *heap, + struct page *first_page, + unsigned long size, const char *name) +{ + struct rk_dma_heap_pages_buf *buf; + const char *name_tmp; + + buf = kzalloc(sizeof(*buf), GFP_KERNEL); + if (!buf) + return -ENOMEM; + + INIT_LIST_HEAD(&buf->node); + if (!name) + name_tmp = current->comm; + else + name_tmp = name; + + buf->orig_alloc = kstrndup(name_tmp, RK_DMA_HEAP_NAME_LEN, GFP_KERNEL); + if (!buf->orig_alloc) { + kfree(buf); + return -ENOMEM; + } + + buf->size = size; + buf->start = page_to_phys(first_page); + + mutex_lock(&heap->pages_lock); + list_add_tail(&buf->node, &heap->pages_list); + mutex_unlock(&heap->pages_lock); + + dma_heap_print("<%s> alloc %ld from system\n", buf->orig_alloc, size); + + return 0; +} + + +static int rk_system_heap_allocate_pages(struct rk_dma_heap *heap, + struct page **pages, + size_t size, gfp_t flags, + const char *name) +{ + int ret; + unsigned int last_page = 0; + struct page *first_page = NULL; + unsigned long num_pages = size >> PAGE_SHIFT; + size_t raw_size = size; + + while (size > 0) { + struct page *page; + int order; + int i; + + order = get_order(size); + /* Don't over allocate*/ + if ((PAGE_SIZE << order) > size && order > 0) + order--; + + page = NULL; + while (!page) { + page = alloc_pages(GFP_KERNEL | __GFP_ZERO | + __GFP_NOWARN | flags, order); + if (page) { + if (!first_page) + first_page = page; + break; + } + + if (order == 0) { + while (last_page--) + __free_page(pages[last_page]); + return -ENOMEM; + } + order--; + } + + split_page(page, order); + for (i = 0; i < (1 << order); i++) + pages[last_page++] = &page[i]; + + size -= PAGE_SIZE << order; + } + + ret = rk_system_heap_add_pages_list(heap, first_page, raw_size, name); + if (ret) + goto free_pages; + + rk_dma_heap_total_inc(heap, raw_size); + + return 0; + +free_pages: + while (num_pages--) { + __free_page(pages[num_pages]); + pages[num_pages] = NULL; + } + + return ret; +} + +static void rk_system_heap_free_pages(struct rk_dma_heap *heap, + struct page **pages, unsigned int num_pages) +{ + /* Need more reasonable way */ + rk_system_heap_remove_pages_list(heap, pages[0]); + + rk_dma_heap_total_dec(heap, num_pages << PAGE_SHIFT); + + while (num_pages--) { + __free_page(pages[num_pages]); + pages[num_pages] = NULL; + } +} + +static const struct rk_dma_heap_ops rk_system_heap_ops = { + .alloc_pages = rk_system_heap_allocate_pages, + .free_pages = rk_system_heap_free_pages, +}; + +static int set_heap_dev_dma(struct device *heap_dev) +{ + int err = 0; + + if (!heap_dev) + return -EINVAL; + + dma_coerce_mask_and_coherent(heap_dev, DMA_BIT_MASK(64)); + + if (!heap_dev->dma_parms) { + heap_dev->dma_parms = devm_kzalloc(heap_dev, + sizeof(*heap_dev->dma_parms), + GFP_KERNEL); + if (!heap_dev->dma_parms) + return -ENOMEM; + + err = dma_set_max_seg_size(heap_dev, (unsigned int)DMA_BIT_MASK(64)); + if (err) { + devm_kfree(heap_dev, heap_dev->dma_parms); + dev_err(heap_dev, "Failed to set DMA segment size, err:%d\n", err); + return err; + } + } + + return 0; +} + +static int __rk_add_system_heap(void) +{ + struct rk_system_heap *sytem_heap; + struct rk_dma_heap_export_info exp_info; + int ret; + + sytem_heap = kzalloc(sizeof(*sytem_heap), GFP_KERNEL); + if (!sytem_heap) + return -ENOMEM; + + exp_info.name = "rk-system-heap"; + exp_info.ops = &rk_system_heap_ops; + exp_info.priv = sytem_heap; + exp_info.permit_noalloc = true; + + sytem_heap->heap = rk_dma_heap_add(&exp_info); + if (IS_ERR(sytem_heap->heap)) { + ret = PTR_ERR(sytem_heap->heap); + + kfree(sytem_heap); + return ret; + } + + ret = set_heap_dev_dma(rk_dma_heap_get_dev(sytem_heap->heap)); + if (ret) { + rk_dma_heap_put(sytem_heap->heap); + kfree(sytem_heap); + return ret; + } + + return 0; +} + +static int __init rk_add_system_heap(void) +{ + return __rk_add_system_heap(); +} + +#if defined(CONFIG_VIDEO_ROCKCHIP_THUNDER_BOOT_ISP) && !defined(CONFIG_INITCALL_ASYNC) +subsys_initcall(rk_add_system_heap); +#else +module_init(rk_add_system_heap); +#endif + +MODULE_DESCRIPTION("RockChip DMA-BUF SYSTEM Heap"); +MODULE_LICENSE("GPL"); diff --git a/include/linux/rk-dma-heap.h b/include/linux/rk-dma-heap.h index f9b06cc18068..75292ac1ad12 100644 --- a/include/linux/rk-dma-heap.h +++ b/include/linux/rk-dma-heap.h @@ -100,6 +100,26 @@ struct page *rk_dma_heap_alloc_contig_pages(struct rk_dma_heap *heap, void rk_dma_heap_free_contig_pages(struct rk_dma_heap *heap, struct page *pages, size_t len, const char *name); +/** + * rk_dma_heap_alloc_pages - Allocate pages from system + * @heap: dma_heap for debug + * @pages: pages where to store + * @len: size to allocate + * @flags: flags used to alloc page + * @name: the name who allocate + */ +int rk_dma_heap_alloc_pages(struct rk_dma_heap *heap, + struct page **pages, size_t len, gfp_t flags, + const char *name); + +/** + * rk_dma_heap_free_pages - Free pages to system + * @heap: dma_heap for debug + * @pages: pages to free to system + * @count: page count to free + */ +void rk_dma_heap_free_pages(struct rk_dma_heap *heap, + struct page **pages, unsigned int count); #else static inline int rk_dma_heap_set_dev(struct device *heap_dev) { @@ -145,5 +165,17 @@ static inline void rk_dma_heap_free_contig_pages(struct rk_dma_heap *heap, struc size_t len, const char *name) { } + +static inline int rk_dma_heap_alloc_pages(struct rk_dma_heap *heap, + struct page **pages, size_t len, + gfp_t flags, const char *name) +{ + return -ENODEV; +} + +static inline void rk_dma_heap_free_pages(struct rk_dma_heap *heap, + struct page **pages, unsigned int count) +{ +} #endif #endif /* _DMA_HEAPS_H */ From 4827685ea82a1ad8a801ea0813032f8b127893fd Mon Sep 17 00:00:00 2001 From: Simon Xue Date: Mon, 18 Aug 2025 10:21:37 +0800 Subject: [PATCH 07/21] media: videobuf2-cma-sg: support rk-system-heap Change-Id: I49f03a6221279882a02d5b11cf76fc85f5d3c931 Signed-off-by: Simon Xue --- .../media/common/videobuf2/videobuf2-cma-sg.c | 35 ++++++++++++++++--- 1 file changed, 31 insertions(+), 4 deletions(-) diff --git a/drivers/media/common/videobuf2/videobuf2-cma-sg.c b/drivers/media/common/videobuf2/videobuf2-cma-sg.c index 5b246aadb401..3d9e5664ad26 100644 --- a/drivers/media/common/videobuf2/videobuf2-cma-sg.c +++ b/drivers/media/common/videobuf2/videobuf2-cma-sg.c @@ -44,12 +44,13 @@ struct vb2_cma_sg_buf { struct vb2_buffer *vb; struct rk_dma_heap *contig_heap; + struct rk_dma_heap *heap; }; static void vb2_cma_sg_put(void *buf_priv); -static int vb2_cma_sg_alloc_compacted(struct vb2_cma_sg_buf *buf, - gfp_t gfp_flags) +static int vb2_cma_sg_alloc_pages(struct vb2_cma_sg_buf *buf, + gfp_t gfp_flags) { unsigned int last_page = 0; unsigned long size = buf->size; @@ -61,7 +62,7 @@ static int vb2_cma_sg_alloc_compacted(struct vb2_cma_sg_buf *buf, order = get_order(size); /* Don't over allocate*/ - if ((PAGE_SIZE << order) > size) + if ((PAGE_SIZE << order) > size && order > 0) order--; pages = NULL; @@ -89,7 +90,7 @@ static int vb2_cma_sg_alloc_compacted(struct vb2_cma_sg_buf *buf, return 0; } -static void vb2_cma_sg_free_compacted(struct vb2_cma_sg_buf *buf) +static void vb2_cma_sg_free_pages(struct vb2_cma_sg_buf *buf) { int num_pages = buf->num_pages; @@ -99,6 +100,32 @@ static void vb2_cma_sg_free_compacted(struct vb2_cma_sg_buf *buf) } } +static int vb2_cma_sg_alloc_compacted(struct vb2_cma_sg_buf *buf, + gfp_t gfp_flags) +{ + struct rk_dma_heap *heap = rk_dma_heap_find("rk-system-heap"); + + if (!heap) + return vb2_cma_sg_alloc_pages(buf, gfp_flags); + + buf->heap = heap; + + return rk_dma_heap_alloc_pages(heap, buf->pages, buf->size, gfp_flags, + dev_name(buf->dev)); +} + +static void vb2_cma_sg_free_compacted(struct vb2_cma_sg_buf *buf) +{ + if (!buf->heap) { + vb2_cma_sg_free_pages(buf); + return; + } + + rk_dma_heap_free_pages(buf->heap, buf->pages, buf->num_pages); + rk_dma_heap_put(buf->heap); + buf->heap = NULL; +} + static int vb2_cma_sg_alloc_contiguous(struct vb2_cma_sg_buf *buf) { struct rk_dma_heap *heap __maybe_unused; From 50947fe0d667aa22702e230bcb2fe16c5ee8a2ed Mon Sep 17 00:00:00 2001 From: Sugar Zhang Date: Mon, 1 Sep 2025 11:56:06 +0800 Subject: [PATCH 08/21] soc: rockchip: cpuinfo: Add rockchip_set_spec_sn Parse 'spec-sn' as rockchip_soc_id bit[7:0]. e.g. cpuinfo { compatible = "rockchip,cpuinfo"; nvmem-cells = <&otp_id>, <&cpu_version>, <&cpu_code>, <&specification_serial_number>; nvmem-cell-names = "id", "cpu-version", "cpu-code", "spec-sn"; }; * bit[7~0]: 0x1 ~ 0x1a --- A ~ Z Signed-off-by: Sugar Zhang Change-Id: Ic1d3d384343f4bde0e65c7826260d5dcc5149e80 --- drivers/soc/rockchip/rockchip-cpuinfo.c | 41 +++++++++++++++++++++++++ include/linux/rockchip/cpu.h | 1 + 2 files changed, 42 insertions(+) diff --git a/drivers/soc/rockchip/rockchip-cpuinfo.c b/drivers/soc/rockchip/rockchip-cpuinfo.c index 6e25271669a1..98b9898eaa15 100644 --- a/drivers/soc/rockchip/rockchip-cpuinfo.c +++ b/drivers/soc/rockchip/rockchip-cpuinfo.c @@ -65,6 +65,45 @@ static int rk3566_soc_init(struct device *dev) return 0; } +static int rockchip_set_spec_sn(struct device *dev) +{ + struct nvmem_cell *cell; + u8 *val; + + cell = nvmem_cell_get(dev, "spec-sn1"); + if (!IS_ERR(cell)) { + val = nvmem_cell_read(cell, NULL); + nvmem_cell_put(cell); + if (IS_ERR(val)) + return PTR_ERR(val); + + if (*val) { + rockchip_soc_id &= ~ROCKCHIP_SOC_SSN_MASK; + rockchip_soc_id |= *val; + kfree(val); + + return 0; + } + + kfree(val); + } + + cell = nvmem_cell_get(dev, "spec-sn"); + if (!IS_ERR(cell)) { + val = nvmem_cell_read(cell, NULL); + nvmem_cell_put(cell); + if (IS_ERR(val)) + return PTR_ERR(val); + + rockchip_soc_id &= ~ROCKCHIP_SOC_SSN_MASK; + rockchip_soc_id |= *val; + + kfree(val); + } + + return 0; +} + static int rockchip_cpuinfo_probe(struct platform_device *pdev) { struct device *dev = &pdev->dev; @@ -80,6 +119,8 @@ static int rockchip_cpuinfo_probe(struct platform_device *pdev) goto skip_cpu_code; } + rockchip_set_spec_sn(dev); + cell = nvmem_cell_get(dev, "cpu-code1"); if (!IS_ERR(cell)) { efuse_buf = nvmem_cell_read(cell, &len); diff --git a/include/linux/rockchip/cpu.h b/include/linux/rockchip/cpu.h index 53f5cb758d39..45a2001bd814 100644 --- a/include/linux/rockchip/cpu.h +++ b/include/linux/rockchip/cpu.h @@ -248,6 +248,7 @@ static inline bool cpu_is_rk3567(void) { return false; } static inline bool cpu_is_rk3568(void) { return false; } #endif +#define ROCKCHIP_SOC_SSN_MASK 0xff #define ROCKCHIP_SOC_MASK (ROCKCHIP_CPU_MASK | 0xff) #define ROCKCHIP_SOC_PX30 (ROCKCHIP_CPU_PX30 | 0x00) #define ROCKCHIP_SOC_PX30S (ROCKCHIP_CPU_PX30 | 0x01) From 53c6a1e7e3c94f461235613dd0eb8aa0d124f506 Mon Sep 17 00:00:00 2001 From: Sugar Zhang Date: Mon, 1 Sep 2025 15:21:04 +0800 Subject: [PATCH 09/21] soc: rockchip: cpuinfo: Add RV1126B-P Signed-off-by: Sugar Zhang Change-Id: I1f8db7fbd27ec0bbd68c341d10bf647ef3e157b2 --- include/linux/rockchip/cpu.h | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/include/linux/rockchip/cpu.h b/include/linux/rockchip/cpu.h index 45a2001bd814..f8794a97fbe5 100644 --- a/include/linux/rockchip/cpu.h +++ b/include/linux/rockchip/cpu.h @@ -255,9 +255,10 @@ static inline bool cpu_is_rk3568(void) { return false; } #define ROCKCHIP_SOC_RV1103 (ROCKCHIP_CPU_RV1103 | 0x00) #define ROCKCHIP_SOC_RV1106 (ROCKCHIP_CPU_RV1106 | 0x00) #define ROCKCHIP_SOC_RV1109 (ROCKCHIP_CPU_RV1109 | 0x00) -#define ROCKCHIP_SOC_RV1109B (ROCKCHIP_CPU_RV1109B | 0x00) +#define ROCKCHIP_SOC_RV1109B (ROCKCHIP_CPU_RV1109B | 0x01) #define ROCKCHIP_SOC_RV1126 (ROCKCHIP_CPU_RV1126 | 0x00) -#define ROCKCHIP_SOC_RV1126B (ROCKCHIP_CPU_RV1126B | 0x00) +#define ROCKCHIP_SOC_RV1126B (ROCKCHIP_CPU_RV1126B | 0x01) +#define ROCKCHIP_SOC_RV1126BP (ROCKCHIP_CPU_RV1126B | 0x10) #define ROCKCHIP_SOC_RK3126 (ROCKCHIP_CPU_RK312X | 0x00) #define ROCKCHIP_SOC_RK3126B (ROCKCHIP_CPU_RK312X | 0x10) #define ROCKCHIP_SOC_RK3126C (ROCKCHIP_CPU_RK312X | 0x20) @@ -293,6 +294,7 @@ ROCKCHIP_SOC(RV1126, rv1109, RV1109) ROCKCHIP_SOC(RV1126, rv1126, RV1126) ROCKCHIP_SOC(RV1126B, rv1109b, RV1109B) ROCKCHIP_SOC(RV1126B, rv1126b, RV1126B) +ROCKCHIP_SOC(RV1126B, rv1126bp, RV1126BP) ROCKCHIP_SOC(RK312X, rk3126, RK3126) ROCKCHIP_SOC(RK312X, rk3126b, RK3126B) ROCKCHIP_SOC(RK312X, rk3126c, RK3126C) From 3e176f1746ec681066649af0f9ab74edff79078d Mon Sep 17 00:00:00 2001 From: Sugar Zhang Date: Mon, 1 Sep 2025 14:59:58 +0800 Subject: [PATCH 10/21] arm64: dts: rockchip: rv1126b: Add spec-sn for cpuinfo RV1126B: rockchip-cpuinfo cpuinfo: SoC : 1126xb01 RV1126B-P: rockchip-cpuinfo cpuinfo: SoC : 1126xb10 Note: * x: don't care. * bit[7~0]: 0x1 ~ 0x1a --- A ~ Z Signed-off-by: Sugar Zhang Change-Id: Ibe21215fd1829e19aea6070419ee565abf05ca97 --- arch/arm64/boot/dts/rockchip/rv1126b.dtsi | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/arch/arm64/boot/dts/rockchip/rv1126b.dtsi b/arch/arm64/boot/dts/rockchip/rv1126b.dtsi index 3cc7792d19c3..84b8db03c024 100644 --- a/arch/arm64/boot/dts/rockchip/rv1126b.dtsi +++ b/arch/arm64/boot/dts/rockchip/rv1126b.dtsi @@ -405,8 +405,8 @@ cpuinfo { compatible = "rockchip,cpuinfo"; - nvmem-cells = <&otp_id>, <&cpu_version>, <&cpu_code>; - nvmem-cell-names = "id", "cpu-version", "cpu-code"; + nvmem-cells = <&otp_id>, <&cpu_version>, <&cpu_code>, <&specification_serial_number>; + nvmem-cell-names = "id", "cpu-version", "cpu-code", "spec-sn"; }; /* dphy0 full mode */ @@ -1942,7 +1942,7 @@ cpu_code: cpu-code@2 { reg = <0x02 0x2>; }; - specification_serial_number: specification-serial-number@7 { + specification_serial_number: specification-serial-number@8 { reg = <0x08 0x1>; bits = <0 5>; }; From 60f3ee74d0eb1f14ec684b01b0fc0cd88c0fe78c Mon Sep 17 00:00:00 2001 From: LiuDiMing Lin Date: Mon, 1 Sep 2025 14:13:37 +0800 Subject: [PATCH 11/21] ARM: dts: rockchip: Add rv1126b-evb2-v10-tb-800w-emmc support Signed-off-by: LiuDiMing Lin Change-Id: Ie4d07b4c2d27e12422e4a9c22146c63814e53269 --- arch/arm/boot/dts/Makefile | 1 + .../dts/rv1126b-evb2-v10-tb-800w-emmc.dts | 82 +++++++++++++++++++ 2 files changed, 83 insertions(+) create mode 100644 arch/arm/boot/dts/rv1126b-evb2-v10-tb-800w-emmc.dts diff --git a/arch/arm/boot/dts/Makefile b/arch/arm/boot/dts/Makefile index 8c2e97c96f99..50d3467e800b 100644 --- a/arch/arm/boot/dts/Makefile +++ b/arch/arm/boot/dts/Makefile @@ -1199,6 +1199,7 @@ dtb-$(CONFIG_ARCH_ROCKCHIP) += \ rv1126b-evb2-v10-sii9022-bt1120-to-hdmi.dtb \ rv1126b-evb2-v10-tb-400w-emmc.dtb \ rv1126b-evb2-v10-tb-400w-spi-nor.dtb \ + rv1126b-evb2-v10-tb-800w-emmc.dtb \ rv1126b-evb2-v12.dtb \ rv1126b-evb2-v12-aov-dual-cam.dtb \ rv1126b-evb2-v12-fastboot-emmc.dtb \ diff --git a/arch/arm/boot/dts/rv1126b-evb2-v10-tb-800w-emmc.dts b/arch/arm/boot/dts/rv1126b-evb2-v10-tb-800w-emmc.dts new file mode 100644 index 000000000000..1e24b3a9b20b --- /dev/null +++ b/arch/arm/boot/dts/rv1126b-evb2-v10-tb-800w-emmc.dts @@ -0,0 +1,82 @@ +// SPDX-License-Identifier: (GPL-2.0+ OR MIT) +/* + * Copyright (c) 2025 Rockchip Electronics Co., Ltd. + */ + +/dts-v1/; +#include "arm64/rockchip/rv1126b.dtsi" +#include "arm64/rockchip/rv1126b-evb.dtsi" +#include "arm64/rockchip/rv1126b-evb2-v10.dtsi" +#include "rv1126b-thunder-boot-cam.dtsi" +#include "rv1126b-thunder-boot-emmc.dtsi" + +/ { + model = "Rockchip RV1126B EVB2 V10 TB 800W eMMC Board"; + compatible = "rockchip,rv1126b-evb2-v10-tb-800w-emmc", "rockchip,rv1126b"; + + chosen { + bootargs = "loglevel=0 initcall_nr_threads=-1 initcall_debug=0 earlycon=uart8250,mmio32,0x20810000 console=ttyFIQ0 root=/dev/rd0 rootfstype=erofs rootflags=dax snd_soc_core.prealloc_buffer_size_kbytes=16 coherent_pool=32K"; + }; +}; + +&emmc { + bus-width = <8>; + cap-mmc-highspeed; + non-removable; + mmc-hs200-1_8v; + rockchip,default-sample-phase = <90>; + no-sdio; + no-sd; + status = "okay"; +}; + +&fspi0 { + status = "disabled"; +}; + +&i2c3 { + clock-frequency = <400000>; + pinctrl-names = "default"; + pinctrl-0 = <&i2c3m1_pins>; + rockchip,amp-shared; + status = "okay"; + + sc850sl: sc850sl@30 { + compatible = "smartsens,sc850sl"; + reg = <0x30>; + clocks = <&cru CLK_MIPI0_OUT2IO>; + clock-names = "xvclk"; + reset-gpios = <&gpio4 RK_PA7 GPIO_ACTIVE_LOW>; + pwdn-gpios = <&gpio4 RK_PA2 GPIO_ACTIVE_HIGH>; + pinctrl-names = "default"; + pinctrl-0 = <&cam_clk0_pins>; + rockchip,camera-module-index = <0>; + rockchip,camera-module-facing = "back"; + rockchip,camera-module-name = "default"; + rockchip,camera-module-lens-name = "default"; + port { + cam0_out: endpoint { + remote-endpoint = <&csi_dphy_input0>; + data-lanes = <1 2 3 4>; + }; + }; + }; +}; + +&ramdisk_r { + reg = <0x48c40000 (60 * 0x00100000)>; +}; + +&ramdisk_c { + reg = <0x4c840000 (30 * 0x00100000)>; +}; + +&rkisp_thunderboot { + /* reg's offset MUST match with RTOS */ + /* + * vicap, capture raw10, ceil(w*10/8/256)*256*h *4(buf num) + sizeof(rkisp_thunderboot_resmem_head) + * e.g. 2688x1520: 0x14c8000 + 0x9000 + * e.g. 3840x2160: 0x2814000 + 0x9000 + */ + reg = <0x41320000 0x281d000>; +}; From c7314afb32840129b29dc6b74563749348f72bc3 Mon Sep 17 00:00:00 2001 From: LiuDiMing Lin Date: Mon, 1 Sep 2025 14:15:19 +0800 Subject: [PATCH 12/21] ARM: configs: rv1126b-tb: Support SC850SL Signed-off-by: LiuDiMing Lin Change-Id: I43f2c14fa52a8962d4c3024c427575235de2e218 --- arch/arm/configs/rv1126b-tb.config | 1 + 1 file changed, 1 insertion(+) diff --git a/arch/arm/configs/rv1126b-tb.config b/arch/arm/configs/rv1126b-tb.config index edb8f397e819..06a2cf4f5792 100644 --- a/arch/arm/configs/rv1126b-tb.config +++ b/arch/arm/configs/rv1126b-tb.config @@ -40,6 +40,7 @@ CONFIG_VIDEO_ROCKCHIP_ISP=y CONFIG_VIDEO_ROCKCHIP_VPSS=y CONFIG_VIDEO_SC200AI=y CONFIG_VIDEO_SC450AI=y +CONFIG_VIDEO_SC850SL=y # CONFIG_AD2S1200 is not set # CONFIG_AD2S1210 is not set # CONFIG_AD2S90 is not set From 1f9a1cc25fd0965299e841a09f5a2f020635cee9 Mon Sep 17 00:00:00 2001 From: Zefa Chen Date: Thu, 28 Aug 2025 15:03:01 +0800 Subject: [PATCH 13/21] media: rockchip: vicap distinguish share interrupts Change-Id: Idaae50c8a1e6a9ea897b0063c4e181866b32e490 Signed-off-by: Zefa Chen --- drivers/media/platform/rockchip/cif/hw.c | 17 +++++++++++------ drivers/media/platform/rockchip/cif/hw.h | 1 + 2 files changed, 12 insertions(+), 6 deletions(-) diff --git a/drivers/media/platform/rockchip/cif/hw.c b/drivers/media/platform/rockchip/cif/hw.c index b15786173bb6..e8e1f5d5a396 100644 --- a/drivers/media/platform/rockchip/cif/hw.c +++ b/drivers/media/platform/rockchip/cif/hw.c @@ -1767,8 +1767,15 @@ static int rkcif_plat_hw_probe(struct platform_device *pdev) if (irq < 0) return irq; - if (data->chip_id == CHIP_RV1106_CIF || - data->chip_id == CHIP_RV1103B_CIF) { + if (data->chip_id == CHIP_PX30_CIF || + data->chip_id == CHIP_RK1808_CIF || + data->chip_id == CHIP_RV1126_CIF || + data->chip_id == CHIP_RV1126_CIF_LITE || + data->chip_id == CHIP_RK3568_CIF) + cif_hw->is_irq_share = true; + else + cif_hw->is_irq_share = false; + if (!cif_hw->is_irq_share) { irq_set_status_flags(irq, IRQ_NOAUTOEN); ret = devm_request_irq(dev, irq, rkcif_irq_handler, 0, @@ -1970,8 +1977,7 @@ static int __maybe_unused rkcif_runtime_suspend(struct device *dev) return 0; rkcif_disable_sys_clk(cif_hw); - if (cif_hw->chip_id == CHIP_RV1106_CIF || - cif_hw->chip_id == CHIP_RV1103B_CIF) + if (!cif_hw->is_irq_share) disable_irq(cif_hw->irq); return pinctrl_pm_select_sleep_state(dev); @@ -1990,8 +1996,7 @@ static int __maybe_unused rkcif_runtime_resume(struct device *dev) rkcif_enable_sys_clk(cif_hw); rkcif_hw_soft_reset(cif_hw, true); - if (cif_hw->chip_id == CHIP_RV1106_CIF || - cif_hw->chip_id == CHIP_RV1103B_CIF) + if (!cif_hw->is_irq_share) enable_irq(cif_hw->irq); return 0; diff --git a/drivers/media/platform/rockchip/cif/hw.h b/drivers/media/platform/rockchip/cif/hw.h index c0ecbf2ab78c..5a8771372910 100644 --- a/drivers/media/platform/rockchip/cif/hw.h +++ b/drivers/media/platform/rockchip/cif/hw.h @@ -167,6 +167,7 @@ struct rkcif_hw { u64 irq_time; bool is_rk3588s2; bool is_in_reset; + bool is_irq_share; }; void rkcif_hw_soft_reset(struct rkcif_hw *cif_hw, bool is_rst_iommu); From a0f99badf026c155a5d82262710282997e6a53ef Mon Sep 17 00:00:00 2001 From: Ziyuan Xu Date: Wed, 3 Sep 2025 11:13:10 +0800 Subject: [PATCH 14/21] ARM: dts: rockchip: rv1126b-thunder-boot: Add i2c3 clocks to thunder_boot_rkisp Change-Id: Ifcdc0b3a3acf5a34ed3f95fc1a088636175d1005 Signed-off-by: Ziyuan Xu --- arch/arm/boot/dts/rv1126b-thunder-boot.dtsi | 2 ++ 1 file changed, 2 insertions(+) diff --git a/arch/arm/boot/dts/rv1126b-thunder-boot.dtsi b/arch/arm/boot/dts/rv1126b-thunder-boot.dtsi index c16aa894e0cb..2b4622d05edb 100644 --- a/arch/arm/boot/dts/rv1126b-thunder-boot.dtsi +++ b/arch/arm/boot/dts/rv1126b-thunder-boot.dtsi @@ -21,6 +21,7 @@ <&cru DCLK_VICAP>, <&cru ISP0CLK_VICAP>, <&cru PCLK_CSI2HOST0>, <&cru DCLK_CSI2HOST0>, + <&cru CLK_I2C3>, <&cru PCLK_I2C3>, <&cru CLK_I2C4>, <&cru PCLK_I2C4>; clock-names = "clk_hpmcu", "pclk_hpmcu_intmux", "pclk_hpmcu_mailbox", @@ -32,6 +33,7 @@ "dclk_cif", "isp0clk_cif", "pclk_csi2host0", "dclk_csi2host0", + "clk_i2c3", "pclk_i2c3", "clk_i2c4", "pclk_i2c4"; }; From 3d0138ac3517125f2a0e8390cce1a96e7bf08378 Mon Sep 17 00:00:00 2001 From: Frank Wang Date: Mon, 25 Aug 2025 10:09:16 +0800 Subject: [PATCH 15/21] usb: storage: Add quirk for Teclast CoolFlash During the long-term loop playback test of videos stored in the USB flash drive, it was found that the Teclast CoolFlash drive (idVendor=346d, idProduct=5678) disconnects abnormally, and the serial port reports the following error messages. [ T227] xhci-hcd xhci-hcd.7.auto: Timeout while waiting for setup device command [ T227] usb 2-1: device not accepting address 2, error -62 [ T227] xhci-hcd xhci-hcd.7.auto: Timeout while waiting for setup device command [ T227] usb 2-1: device not accepting address 2, error -62 [ T7577] xhci-hcd xhci-hcd.7.auto: xHCI host not responding to stop endpoint command [ T7577] xhci-hcd xhci-hcd.7.auto: xHCI host controller not responding, assume dead [ T7577] xhci-hcd xhci-hcd.7.auto: HC died; cleaning up [ T227] xhci-hcd xhci-hcd.7.auto: Timeout while waiting for stop endpoint command [ T7578] usb 2-1: USB disconnect, device number 2 [ T227] sd 1:0:0:0: [sde] tag#0 UNKNOWN(0x2003) Result: hostbyte=0x07 driverbyte=DRIVER_OK cmd_age=27s Adding this quirk to limit max_sectors to 64 sectors to avoid issue occurring. Signed-off-by: Frank Wang Change-Id: Ie2f72a5d95e566818789f1280452cad239a57d62 --- drivers/usb/storage/unusual_devs.h | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/drivers/usb/storage/unusual_devs.h b/drivers/usb/storage/unusual_devs.h index 1bfaf5050569..3db83281bad8 100644 --- a/drivers/usb/storage/unusual_devs.h +++ b/drivers/usb/storage/unusual_devs.h @@ -2387,6 +2387,12 @@ UNUSUAL_DEV( 0x3340, 0xffff, 0x0000, 0x0000, USB_SC_DEVICE,USB_PR_DEVICE,NULL, US_FL_MAX_SECTORS_64 ), +UNUSUAL_DEV( 0x346d, 0x5678, 0x0000, 0xffff, + "Teclast", + "CoolFlash", + USB_SC_DEVICE, USB_PR_DEVICE, NULL, + US_FL_GO_SLOW | US_FL_MAX_SECTORS_64 | US_FL_IGNORE_RESIDUE ), + /* Reported by Cyril Roelandt */ UNUSUAL_DEV( 0x357d, 0x7788, 0x0114, 0x0114, "JMicron", From 6d1a9ac5db3acac58fdc4dca26b0d8d3c847e88e Mon Sep 17 00:00:00 2001 From: Jon Lin Date: Fri, 29 Aug 2025 14:45:44 +0800 Subject: [PATCH 16/21] misc: rockchip: pcie-rkep: Use the matching dma_mmap_coherent The memory allocated by dma_alloc_coherent can be mapped using the matching dma_mmap_coherent interface. Change-Id: I7289d490771a86985ec5ed19af5c3cbbfb9810c2 Signed-off-by: Jon Lin --- drivers/misc/rockchip/pcie-rkep.c | 32 ++++++++++++++++++++++++------- 1 file changed, 25 insertions(+), 7 deletions(-) diff --git a/drivers/misc/rockchip/pcie-rkep.c b/drivers/misc/rockchip/pcie-rkep.c index a919ccebca2d..5cdd78fcae09 100644 --- a/drivers/misc/rockchip/pcie-rkep.c +++ b/drivers/misc/rockchip/pcie-rkep.c @@ -396,6 +396,18 @@ static int rkep_mem_continuous_buffer_free(struct pcie_file *pcie_file, return ret; } +static void *rkep_mem_continuous_buffer_to_virt(struct pcie_file *pcie_file, uint64_t dma_addr) +{ + struct pcie_ep_continuous_buffer_req *buffer_req, *tmp; + + list_for_each_entry_safe(buffer_req, tmp, &pcie_file->cont_buffer_list, cont_buffer_list) { + if (buffer_req->dma_addr == dma_addr) + return buffer_req->vir_addr; + } + + return NULL; +} + static int pcie_rkep_open(struct inode *inode, struct file *file) { struct miscdevice *miscdev = file->private_data; @@ -696,15 +708,21 @@ static int pcie_rkep_mmap(struct file *file, struct vm_area_struct *vma) return -EINVAL; } - if (pcie_file->cur_mmap_res == PCIE_EP_MMAP_RESOURCE_USER_MEM || - pcie_file->cur_mmap_res == PCIE_EP_MMAP_RESOURCE_CONTINUOUS_BUFFER) + if (pcie_file->cur_mmap_res == PCIE_EP_MMAP_RESOURCE_USER_MEM) { vma->vm_page_prot = pgprot_writecombine(vma->vm_page_prot); - else + err = remap_pfn_range(vma, vma->vm_start, + __phys_to_pfn(addr), + size, vma->vm_page_prot); + } else if (pcie_file->cur_mmap_res == PCIE_EP_MMAP_RESOURCE_CONTINUOUS_BUFFER) { + err = dma_mmap_coherent(&pcie_rkep->pdev->dev, vma, + rkep_mem_continuous_buffer_to_virt(pcie_file, addr), + addr, size); + } else { vma->vm_page_prot = pgprot_noncached(vma->vm_page_prot); - - err = remap_pfn_range(vma, vma->vm_start, - __phys_to_pfn(addr), - size, vma->vm_page_prot); + err = remap_pfn_range(vma, vma->vm_start, + __phys_to_pfn(addr), + size, vma->vm_page_prot); + } if (err) return -EAGAIN; From 53adf7a62fb41954e9c6c4774d87a55853d9ba01 Mon Sep 17 00:00:00 2001 From: Zhibao Huang Date: Thu, 28 Aug 2025 15:48:07 +0800 Subject: [PATCH 17/21] ARM: configs: rockchip_linux_defconfig enable RK628 hdmitx and videoin Change-Id: Ie71e3c0f9a7b351058e5fc64c686a6355ca50ce1 Signed-off-by: ZhiBao Huang --- arch/arm/configs/rockchip_linux_defconfig | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/arch/arm/configs/rockchip_linux_defconfig b/arch/arm/configs/rockchip_linux_defconfig index 3a8b9886c56e..46268530e900 100644 --- a/arch/arm/configs/rockchip_linux_defconfig +++ b/arch/arm/configs/rockchip_linux_defconfig @@ -160,6 +160,8 @@ CONFIG_ZRAM=y CONFIG_BLK_DEV_LOOP=y CONFIG_BLK_DEV_RAM=y CONFIG_BLK_DEV_RAM_COUNT=1 +CONFIG_RK628_MISC=y +CONFIG_RK628_MISC_HDMITX=y CONFIG_SCSI=y CONFIG_BLK_DEV_SD=y CONFIG_BLK_DEV_SR=y @@ -284,6 +286,8 @@ CONFIG_VIDEO_OV5647=y CONFIG_VIDEO_OV8858=y CONFIG_VIDEO_OV13850=y CONFIG_VIDEO_SGM3784=y +CONFIG_VIDEO_RK628_CSI=y +CONFIG_VIDEO_RK628_BT1120=y CONFIG_DRM=y CONFIG_DRM_IGNORE_IOTCL_PERMIT=y CONFIG_DRM_LOAD_EDID_FIRMWARE=y From 7f26bae32839a53ceef24b5d4af149799c2c7a72 Mon Sep 17 00:00:00 2001 From: Caesar Wang Date: Thu, 4 Sep 2025 09:56:01 +0800 Subject: [PATCH 18/21] arm64/configs: enable CONFIG_DMABUF_PARTIAL for rockchip_linux_defconfig Change-Id: If7c07bb84eebcca14471077590c5a461859c8c9b Signed-off-by: Caesar Wang --- arch/arm64/configs/rockchip_linux_defconfig | 1 + 1 file changed, 1 insertion(+) diff --git a/arch/arm64/configs/rockchip_linux_defconfig b/arch/arm64/configs/rockchip_linux_defconfig index 96894fa18f4d..5b51f21a21c2 100644 --- a/arch/arm64/configs/rockchip_linux_defconfig +++ b/arch/arm64/configs/rockchip_linux_defconfig @@ -524,6 +524,7 @@ CONFIG_DMADEVICES=y CONFIG_PL330_DMA=y CONFIG_ROCKCHIP_DMA=y CONFIG_RK_DMABUF_DEBUG=y +CONFIG_DMABUF_PARTIAL=y CONFIG_SW_SYNC=y CONFIG_DMABUF_HEAPS=y CONFIG_DMABUF_SYSFS_STATS=y From d0f521ef68319f16a01bfc6f99aba69d6c2853fe Mon Sep 17 00:00:00 2001 From: Guochun Huang Date: Wed, 3 Sep 2025 11:05:28 +0800 Subject: [PATCH 19/21] drm/rockchip: dsi: solve dsi failed to enter command mode before system sleeping dsi may failed to send command to panel before system sleeping: [ 95.191478][ T336] dw-mipi-dsi2 27d80000.dsi: failed to enter command mode [ 95.211617][ T336] dw-mipi-dsi2 27d80000.dsi: [drm:cri_fifos_wait_avail] *ERROR* command interface is busy [ 95.211744][ T336] panel-simple-dsi 27d80000.dsi.0: failed to write dcs cmd: -110 Change-Id: I24ea8bda3fc001145120c69e73bc786a1843a2a1 Signed-off-by: Guochun Huang --- drivers/gpu/drm/rockchip/dw-mipi-dsi2-rockchip.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/drivers/gpu/drm/rockchip/dw-mipi-dsi2-rockchip.c b/drivers/gpu/drm/rockchip/dw-mipi-dsi2-rockchip.c index f66bb94ad0cb..e26d7ddc8614 100644 --- a/drivers/gpu/drm/rockchip/dw-mipi-dsi2-rockchip.c +++ b/drivers/gpu/drm/rockchip/dw-mipi-dsi2-rockchip.c @@ -172,7 +172,7 @@ #define DSI2_INT_FORCE_CRI 0x0468 #define DSI2_MAX_REGISGER DSI2_INT_FORCE_CRI -#define MODE_STATUS_TIMEOUT_US 10000 +#define MODE_STATUS_TIMEOUT_US 20000 #define CMD_PKT_STATUS_TIMEOUT_US 20000 #define PSEC_PER_SEC 1000000000000LL @@ -435,7 +435,7 @@ static void dw_mipi_dsi2_set_vid_mode(struct dw_mipi_dsi2 *dsi2) regmap_write(dsi2->regmap, DSI2_MODE_CTRL, VIDEO_MODE); ret = regmap_read_poll_timeout(dsi2->regmap, DSI2_MODE_STATUS, - mode, mode & VIDEO_MODE, + mode, mode == VIDEO_MODE, 1000, MODE_STATUS_TIMEOUT_US); if (ret < 0) dev_err(dsi2->dev, "failed to enter video mode\n"); @@ -448,7 +448,7 @@ static void dw_mipi_dsi2_set_data_stream_mode(struct dw_mipi_dsi2 *dsi2) regmap_write(dsi2->regmap, DSI2_MODE_CTRL, DATA_STREAM_MODE); ret = regmap_read_poll_timeout(dsi2->regmap, DSI2_MODE_STATUS, - mode, mode & DATA_STREAM_MODE, + mode, mode == DATA_STREAM_MODE, 1000, MODE_STATUS_TIMEOUT_US); if (ret < 0) dev_err(dsi2->dev, "failed to enter data stream mode\n"); @@ -461,7 +461,7 @@ static void dw_mipi_dsi2_set_cmd_mode(struct dw_mipi_dsi2 *dsi2) regmap_write(dsi2->regmap, DSI2_MODE_CTRL, COMMAND_MODE); ret = regmap_read_poll_timeout(dsi2->regmap, DSI2_MODE_STATUS, - mode, mode & COMMAND_MODE, + mode, mode == COMMAND_MODE, 1000, MODE_STATUS_TIMEOUT_US); if (ret < 0) dev_err(dsi2->dev, "failed to enter command mode\n"); From d52be97549f550a7da66be27bf1af27142247dd4 Mon Sep 17 00:00:00 2001 From: Caesar Wang Date: Thu, 4 Sep 2025 09:57:03 +0800 Subject: [PATCH 20/21] arm64/configs: rv1126b.config: enable CONFIG_ROCKCHIP_DVBM Change-Id: I03fd425806214bda651a2c78080cbce88847b7b9 Signed-off-by: Caesar Wang --- arch/arm64/configs/rv1126b.config | 1 + 1 file changed, 1 insertion(+) diff --git a/arch/arm64/configs/rv1126b.config b/arch/arm64/configs/rv1126b.config index 2f8102b20737..2d72a9ce594d 100644 --- a/arch/arm64/configs/rv1126b.config +++ b/arch/arm64/configs/rv1126b.config @@ -1,2 +1,3 @@ +CONFIG_ROCKCHIP_DVBM=y CONFIG_ROCKCHIP_RKNPU_PROC_FS=y CONFIG_ROCKCHIP_RKNPU_DMA_HEAP=y From ff98cc67d000b978ef16edcbabdf5d54b7bdd667 Mon Sep 17 00:00:00 2001 From: Caesar Wang Date: Thu, 4 Sep 2025 11:34:13 +0800 Subject: [PATCH 21/21] arm64/configs: rockchip_linux_defconfig: enable CONFIG_HWSPINLOCK_ROCKCHIP Change-Id: I81f75a71d612d8c94e8a7950db616a80ea5e2ae8 Signed-off-by: Caesar Wang --- arch/arm64/configs/rockchip_linux_defconfig | 2 ++ 1 file changed, 2 insertions(+) diff --git a/arch/arm64/configs/rockchip_linux_defconfig b/arch/arm64/configs/rockchip_linux_defconfig index 5b51f21a21c2..69ee5f79dd71 100644 --- a/arch/arm64/configs/rockchip_linux_defconfig +++ b/arch/arm64/configs/rockchip_linux_defconfig @@ -538,6 +538,8 @@ CONFIG_COMMON_CLK_RK808=y CONFIG_COMMON_CLK_SCMI=y CONFIG_COMMON_CLK_PWM=y CONFIG_ROCKCHIP_CLK_PVTPLL=y +CONFIG_HWSPINLOCK=y +CONFIG_HWSPINLOCK_ROCKCHIP=y CONFIG_MAILBOX=y CONFIG_ROCKCHIP_MBOX=y CONFIG_ROCKCHIP_IOMMU=y