From 10c09cfd314be2cda5d03cf596756776ea27dfd6 Mon Sep 17 00:00:00 2001 From: Yu Qiaowei Date: Wed, 16 Apr 2025 18:03:07 +0800 Subject: [PATCH 01/17] video: rockchip: rga3: fix crash caused by vir_addr call in 'mm' debug mode Change-Id: I16223557d18f5f0bd99f468b34713157897e0f5d Signed-off-by: Yu Qiaowei --- drivers/video/rockchip/rga3/rga_mm.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/drivers/video/rockchip/rga3/rga_mm.c b/drivers/video/rockchip/rga3/rga_mm.c index 12b3342c0b67..740009008e59 100644 --- a/drivers/video/rockchip/rga3/rga_mm.c +++ b/drivers/video/rockchip/rga3/rga_mm.c @@ -1920,6 +1920,8 @@ static int rga_mm_map_channel_job_buffer(struct rga_job *job, goto error_free_buffer; } + buffer->session = job->session; + if (DEBUGGER_EN(MM)) { rga_job_log(job, "map buffer:\n"); rga_mm_dump_buffer(buffer); From f3dd6b3cc454027987b8c7f0a65c31af9d8f746c Mon Sep 17 00:00:00 2001 From: LongChang Ma Date: Sat, 12 Apr 2025 11:36:25 +0800 Subject: [PATCH 02/17] media: i2c: sc450ai: adjust 2lane setting vblank value Signed-off-by: LongChang Ma Change-Id: Id64fe9ad58a816fb5ba96afc99bbcb6235fc8fc7 --- drivers/media/i2c/sc450ai.c | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/drivers/media/i2c/sc450ai.c b/drivers/media/i2c/sc450ai.c index b55baa096692..59273dba8f63 100644 --- a/drivers/media/i2c/sc450ai.c +++ b/drivers/media/i2c/sc450ai.c @@ -408,10 +408,11 @@ static const struct regval sc450ai_linear_10_2688x1520_30fps_2lane_regs[] = { {0x3209, 0x80}, {0x320a, 0x05}, {0x320b, 0xf0}, - {0x320c, 0x02}, + {0x320c, 0x02}, //hts {0x320d, 0xee}, - {0x320e, 0x06}, - {0x320f, 0x18}, + {0x320e, 0x06}, //vts + // {0x320f, 0x18}, + {0x320f, 0x38}, {0x3214, 0x11}, {0x3215, 0x11}, {0x3220, 0x00}, @@ -1197,7 +1198,7 @@ static const struct sc450ai_mode supported_modes_2lane[] = { }, .exp_def = 0x0080,//mark .hts_def = 0x2ee * 4, - .vts_def = 0x0618, + .vts_def = 0x0638, .bus_fmt = MEDIA_BUS_FMT_SBGGR10_1X10, .reg_list = sc450ai_linear_10_2688x1520_30fps_2lane_regs, .hdr_mode = NO_HDR, From b730a5ac781f03c6cd8f7bc884b442e033366605 Mon Sep 17 00:00:00 2001 From: Jon Lin Date: Wed, 18 Sep 2024 18:22:22 +0800 Subject: [PATCH 03/17] PCI: rockchip: dw-ep: Support link up status double check Change-Id: I6b1807ea1dce5c05a040823717b50edf7a6109d9 Signed-off-by: Jon Lin --- .../pci/controller/dwc/pcie-dw-ep-rockchip.c | 18 +++++++++++------- 1 file changed, 11 insertions(+), 7 deletions(-) diff --git a/drivers/pci/controller/dwc/pcie-dw-ep-rockchip.c b/drivers/pci/controller/dwc/pcie-dw-ep-rockchip.c index bdf9480d83a9..6949ef902bff 100644 --- a/drivers/pci/controller/dwc/pcie-dw-ep-rockchip.c +++ b/drivers/pci/controller/dwc/pcie-dw-ep-rockchip.c @@ -744,7 +744,7 @@ static int rockchip_pcie_config_host(struct rockchip_pcie *rockchip) struct device *dev = rockchip->pci.dev; struct dw_pcie *pci = &rockchip->pci; u32 reg, val; - int ret, retry, i; + int ret, retries, i; /* Detecting ATU features to achieve DWC ATU interface development */ dw_pcie_iatu_detect(&rockchip->pci); @@ -811,7 +811,8 @@ static int rockchip_pcie_config_host(struct rockchip_pcie *rockchip) } rockchip_pcie_writel_apb(rockchip, reg, PCIE_CLIENT_INTR_STATUS_MISC); - for (retry = 0; retry < 1000; retry++) { + retries = 1000; + for (i = 0; i < retries; i++) { if (dw_pcie_link_up(&rockchip->pci)) { /* * We may be here in case of L0 in Gen1. But if EP is capable @@ -820,10 +821,13 @@ static int rockchip_pcie_config_host(struct rockchip_pcie *rockchip) * that LTSSM max timeout is 24ms per period, we can wait a bit * more for Gen switch. */ - msleep(2000); - dev_info(dev, "PCIe Link up, LTSSM is 0x%x\n", - rockchip_pcie_readl_apb(rockchip, PCIE_CLIENT_LTSSM_STATUS)); - break; + msleep(50); + /* In case link drop after linkup, double check it */ + if (dw_pcie_link_up(pci)) { + dev_info(pci->dev, "PCIe Link up, LTSSM is 0x%x\n", + rockchip_pcie_readl_apb(rockchip, PCIE_CLIENT_LTSSM_STATUS)); + break; + } } dev_info_ratelimited(dev, "PCIe Linking... LTSSM is 0x%x\n", @@ -831,7 +835,7 @@ static int rockchip_pcie_config_host(struct rockchip_pcie *rockchip) msleep(20); } - if (retry >= 10000) { + if (i >= retries) { ret = -ENODEV; return ret; } From a5ee25a6ff3b32ee7e8b63a9b443624b7876ed26 Mon Sep 17 00:00:00 2001 From: Jon Lin Date: Thu, 29 Aug 2024 22:55:55 +0800 Subject: [PATCH 04/17] misc: rockchip: pcie-rkep: Support BAR1 and BAR5 mmap Change-Id: I59983fd9cd0153966eb0f539ae9b082f05dae5b1 Signed-off-by: Jon Lin --- drivers/misc/rockchip/pcie-rkep.c | 16 ++++++++++++++++ include/uapi/linux/rk-pcie-ep.h | 2 ++ 2 files changed, 18 insertions(+) diff --git a/drivers/misc/rockchip/pcie-rkep.c b/drivers/misc/rockchip/pcie-rkep.c index 44b7bf0744b4..d3b0c8baa772 100644 --- a/drivers/misc/rockchip/pcie-rkep.c +++ b/drivers/misc/rockchip/pcie-rkep.c @@ -558,6 +558,14 @@ static int pcie_rkep_mmap(struct file *file, struct vm_area_struct *vma) } addr = pci_resource_start(dev, 0); break; + case PCIE_EP_MMAP_RESOURCE_BAR1: + bar_size = pci_resource_len(dev, 1); + if (size > bar_size) { + dev_warn(&pcie_rkep->pdev->dev, "bar1 mmap size is out of limitation\n"); + return -EINVAL; + } + addr = pci_resource_start(dev, 1); + break; case PCIE_EP_MMAP_RESOURCE_BAR2: bar_size = pci_resource_len(dev, 2); if (size > bar_size) { @@ -574,6 +582,14 @@ static int pcie_rkep_mmap(struct file *file, struct vm_area_struct *vma) } addr = pci_resource_start(dev, 4); break; + case PCIE_EP_MMAP_RESOURCE_BAR5: + bar_size = pci_resource_len(dev, 5); + if (size > bar_size) { + dev_warn(&pcie_rkep->pdev->dev, "bar5 mmap size is out of limitation\n"); + return -EINVAL; + } + addr = pci_resource_start(dev, 5); + break; case PCIE_EP_MMAP_RESOURCE_USER_MEM: if (size > RKEP_USER_MEM_SIZE) { dev_warn(&pcie_rkep->pdev->dev, "mmap size is out of limitation\n"); diff --git a/include/uapi/linux/rk-pcie-ep.h b/include/uapi/linux/rk-pcie-ep.h index d89748eed925..64d83c0ab5c9 100644 --- a/include/uapi/linux/rk-pcie-ep.h +++ b/include/uapi/linux/rk-pcie-ep.h @@ -69,6 +69,8 @@ enum pcie_ep_mmap_resource { PCIE_EP_MMAP_RESOURCE_USER_MEM, PCIE_EP_MMAP_RESOURCE_RK3568_RC_DBI, PCIE_EP_MMAP_RESOURCE_RK3588_RC_DBI, + PCIE_EP_MMAP_RESOURCE_BAR1, + PCIE_EP_MMAP_RESOURCE_BAR5, PCIE_EP_MMAP_RESOURCE_MAX, }; From e31d0ecd305ee7364e1fb21b3e4af29e62e6c0ca Mon Sep 17 00:00:00 2001 From: Jon Lin Date: Thu, 17 Oct 2024 17:00:16 +0800 Subject: [PATCH 05/17] PCI: rockchip: dw-ep: Support BAR1 and BAR5 mmap Change-Id: Ibc34c387ca69ba17d64cc2c91a2be1d6fc2faa22 Signed-off-by: Jon Lin --- .../pci/controller/dwc/pcie-dw-ep-rockchip.c | 30 +++++++++++++++++-- 1 file changed, 28 insertions(+), 2 deletions(-) diff --git a/drivers/pci/controller/dwc/pcie-dw-ep-rockchip.c b/drivers/pci/controller/dwc/pcie-dw-ep-rockchip.c index 6949ef902bff..2b19e0eed47f 100644 --- a/drivers/pci/controller/dwc/pcie-dw-ep-rockchip.c +++ b/drivers/pci/controller/dwc/pcie-dw-ep-rockchip.c @@ -423,6 +423,11 @@ static void rockchip_pcie_resize_bar_nsticky(struct rockchip_pcie *rockchip) dw_pcie_writel_dbi(pci, resbar_base + 0x8 + bar * 0x8, 0x2c0); rockchip_pcie_ep_set_bar_flag(rockchip, bar, PCI_BASE_ADDRESS_MEM_TYPE_32); + bar = BAR_1; + dw_pcie_writel_dbi(pci, resbar_base + 0x4 + bar * 0x8, 0x10); + dw_pcie_writel_dbi(pci, resbar_base + 0x8 + bar * 0x8, 0xc0); + rockchip_pcie_ep_set_bar_flag(rockchip, bar, PCI_BASE_ADDRESS_MEM_TYPE_32); + bar = BAR_2; dw_pcie_writel_dbi(pci, resbar_base + 0x4 + bar * 0x8, 0x400); dw_pcie_writel_dbi(pci, resbar_base + 0x8 + bar * 0x8, 0x6c0); @@ -434,11 +439,18 @@ static void rockchip_pcie_resize_bar_nsticky(struct rockchip_pcie *rockchip) dw_pcie_writel_dbi(pci, resbar_base + 0x8 + bar * 0x8, 0xc0); rockchip_pcie_ep_set_bar_flag(rockchip, bar, PCI_BASE_ADDRESS_MEM_TYPE_32); + bar = BAR_5; + dw_pcie_writel_dbi(pci, resbar_base + 0x4 + bar * 0x8, 0x10); + dw_pcie_writel_dbi(pci, resbar_base + 0x8 + bar * 0x8, 0xc0); + rockchip_pcie_ep_set_bar_flag(rockchip, bar, PCI_BASE_ADDRESS_MEM_TYPE_32); + /* Disable BAR1 BAR5*/ bar = BAR_1; - dw_pcie_writel_dbi(pci, PCIE_TYPE0_HDR_DBI2_OFFSET + 0x10 + bar * 4, 0); + if (!rockchip->ib_target_size[bar]) + dw_pcie_writel_dbi(pci, PCIE_TYPE0_HDR_DBI2_OFFSET + 0x10 + bar * 4, 0); bar = BAR_5; - dw_pcie_writel_dbi(pci, PCIE_TYPE0_HDR_DBI2_OFFSET + 0x10 + bar * 4, 0); + if (!rockchip->ib_target_size[bar]) + dw_pcie_writel_dbi(pci, PCIE_TYPE0_HDR_DBI2_OFFSET + 0x10 + bar * 4, 0); dw_pcie_dbi_ro_wr_dis(&rockchip->pci); } @@ -1157,6 +1169,13 @@ static int pcie_ep_mmap(struct file *file, struct vm_area_struct *vma) } addr = rockchip->ib_target_address[0]; break; + case PCIE_EP_MMAP_RESOURCE_BAR1: + if (size > rockchip->ib_target_size[1]) { + dev_warn(rockchip->pci.dev, "bar1 mmap size is out of limitation\n"); + return -EINVAL; + } + addr = rockchip->ib_target_address[1]; + break; case PCIE_EP_MMAP_RESOURCE_BAR2: if (size > rockchip->ib_target_size[2]) { dev_warn(rockchip->pci.dev, "bar2 mmap size is out of limitation\n"); @@ -1164,6 +1183,13 @@ static int pcie_ep_mmap(struct file *file, struct vm_area_struct *vma) } addr = rockchip->ib_target_address[2]; break; + case PCIE_EP_MMAP_RESOURCE_BAR5: + if (size > rockchip->ib_target_size[5]) { + dev_warn(rockchip->pci.dev, "bar5 mmap size is out of limitation\n"); + return -EINVAL; + } + addr = rockchip->ib_target_address[5]; + break; default: dev_err(rockchip->pci.dev, "cur mmap_res %d is unsurreport\n", rockchip->cur_mmap_res); return -EINVAL; From ad8d1ad7f295d32478077c9040d67edd070e78fb Mon Sep 17 00:00:00 2001 From: Jon Lin Date: Sun, 9 Mar 2025 17:00:44 +0800 Subject: [PATCH 06/17] PCI: rockchip: dw-ep: Support ltssm fifo debug Set RK_PCIE_DBG to 1 to enable ltssm fifo debug. Change-Id: If88824e7bb7455006b0cf7ceac5bb901bf76f282 Signed-off-by: Jon Lin --- .../pci/controller/dwc/pcie-dw-ep-rockchip.c | 41 +++++++++++++++++++ 1 file changed, 41 insertions(+) diff --git a/drivers/pci/controller/dwc/pcie-dw-ep-rockchip.c b/drivers/pci/controller/dwc/pcie-dw-ep-rockchip.c index 2b19e0eed47f..92e611618dc6 100644 --- a/drivers/pci/controller/dwc/pcie-dw-ep-rockchip.c +++ b/drivers/pci/controller/dwc/pcie-dw-ep-rockchip.c @@ -35,6 +35,17 @@ #define to_rockchip_pcie(x) dev_get_drvdata((x)->dev) +#define RK_PCIE_DBG 0 + +#define PCIE_CLIENT_DBG_FIFO_MODE_CON 0x310 +#define PCIE_CLIENT_DBG_FIFO_PTN_HIT_D0 0x320 +#define PCIE_CLIENT_DBG_FIFO_PTN_HIT_D1 0x324 +#define PCIE_CLIENT_DBG_FIFO_TRN_HIT_D0 0x328 +#define PCIE_CLIENT_DBG_FIFO_TRN_HIT_D1 0x32c +#define PCIE_CLIENT_DBG_FIFO_STATUS 0x350 +#define PCIE_CLIENT_DBG_TRANSITION_DATA 0xffff0000 +#define PCIE_CLIENT_DBF_EN 0xffff0007 + #define PCIE_DMA_OFFSET 0x380000 #define PCIE_DMA_CTRL_OFF 0x8 @@ -751,6 +762,33 @@ static void rockchip_pcie_hide_broken_ats_cap(struct dw_pcie *pci) dw_pcie_dbi_ro_wr_dis(pci); } +static void rockchip_pcie_enable_debug(struct rockchip_pcie *rockchip) +{ + rockchip_pcie_writel_apb(rockchip, PCIE_CLIENT_DBG_TRANSITION_DATA, + PCIE_CLIENT_DBG_FIFO_PTN_HIT_D0); + rockchip_pcie_writel_apb(rockchip, PCIE_CLIENT_DBG_TRANSITION_DATA, + PCIE_CLIENT_DBG_FIFO_PTN_HIT_D1); + rockchip_pcie_writel_apb(rockchip, PCIE_CLIENT_DBG_TRANSITION_DATA, + PCIE_CLIENT_DBG_FIFO_TRN_HIT_D0); + rockchip_pcie_writel_apb(rockchip, PCIE_CLIENT_DBG_TRANSITION_DATA, + PCIE_CLIENT_DBG_FIFO_TRN_HIT_D1); + rockchip_pcie_writel_apb(rockchip, PCIE_CLIENT_DBF_EN, + PCIE_CLIENT_DBG_FIFO_MODE_CON); +} + +static void rockchip_pcie_debug_dump(struct rockchip_pcie *rockchip) +{ +#if RK_PCIE_DBG + u32 loop; + + dev_info(rockchip->pci.dev, "ltssm = 0x%x\n", + rockchip_pcie_readl_apb(rockchip, PCIE_CLIENT_LTSSM_STATUS)); + for (loop = 0; loop < 64; loop++) + dev_info(rockchip->pci.dev, "fifo_status = 0x%x\n", + rockchip_pcie_readl_apb(rockchip, PCIE_CLIENT_DBG_FIFO_STATUS)); +#endif +} + static int rockchip_pcie_config_host(struct rockchip_pcie *rockchip) { struct device *dev = rockchip->pci.dev; @@ -822,6 +860,7 @@ static int rockchip_pcie_config_host(struct rockchip_pcie *rockchip) dev_info(dev, "hot reset ever\n"); } rockchip_pcie_writel_apb(rockchip, reg, PCIE_CLIENT_INTR_STATUS_MISC); + rockchip_pcie_enable_debug(rockchip); retries = 1000; for (i = 0; i < retries; i++) { @@ -838,12 +877,14 @@ static int rockchip_pcie_config_host(struct rockchip_pcie *rockchip) if (dw_pcie_link_up(pci)) { dev_info(pci->dev, "PCIe Link up, LTSSM is 0x%x\n", rockchip_pcie_readl_apb(rockchip, PCIE_CLIENT_LTSSM_STATUS)); + rockchip_pcie_debug_dump(rockchip); break; } } dev_info_ratelimited(dev, "PCIe Linking... LTSSM is 0x%x\n", rockchip_pcie_readl_apb(rockchip, PCIE_CLIENT_LTSSM_STATUS)); + rockchip_pcie_debug_dump(rockchip); msleep(20); } From 34ba677dedf2dc1338bd5fcecc2169c5d32a75bd Mon Sep 17 00:00:00 2001 From: Jon Lin Date: Sun, 9 Mar 2025 17:03:04 +0800 Subject: [PATCH 07/17] PCI: rockchip: dw-ep: Support setting link_gen Change-Id: I1b93b04e45a39e93e774a2ade8a00865f1e6f5ed Signed-off-by: Jon Lin --- drivers/pci/controller/dwc/pcie-dw-ep-rockchip.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/drivers/pci/controller/dwc/pcie-dw-ep-rockchip.c b/drivers/pci/controller/dwc/pcie-dw-ep-rockchip.c index 92e611618dc6..9ece92aa6519 100644 --- a/drivers/pci/controller/dwc/pcie-dw-ep-rockchip.c +++ b/drivers/pci/controller/dwc/pcie-dw-ep-rockchip.c @@ -22,6 +22,7 @@ #include #include +#include "../../pci.h" #include "../rockchip-pcie-dma.h" #include "pcie-designware.h" #include "pcie-dw-dmatest.h" @@ -322,6 +323,8 @@ static int rockchip_pcie_get_io_resource(struct platform_device *pdev, return -ENODEV; } + rockchip->pci.link_gen = of_pci_get_max_link_speed(np); + return 0; } From 1b882fcf73b840228c51177e4c5aad40e3945906 Mon Sep 17 00:00:00 2001 From: Jon Lin Date: Wed, 18 Sep 2024 15:05:49 +0800 Subject: [PATCH 08/17] PCI: rockchip: dw_ep: Support rockchip,ep-power-independent sually, RK EP is directly powered by RC, and the entire device reset switch of EP is controlled by PERST#. If EP is powered independently, EP will enter the initialization phase independently of RC. In order to wait for the REFCLK provided by RC to stabilize, the definition of reset-gpio has been added to identify PERST# gpio signal translation. Change-Id: I45f6d176a0a71615ccbbde11f419475ad8600dd3 Signed-off-by: Jon Lin --- .../pci/controller/dwc/pcie-dw-ep-rockchip.c | 129 +++++++++++++++++- 1 file changed, 124 insertions(+), 5 deletions(-) diff --git a/drivers/pci/controller/dwc/pcie-dw-ep-rockchip.c b/drivers/pci/controller/dwc/pcie-dw-ep-rockchip.c index 9ece92aa6519..8c9fb20f9809 100644 --- a/drivers/pci/controller/dwc/pcie-dw-ep-rockchip.c +++ b/drivers/pci/controller/dwc/pcie-dw-ep-rockchip.c @@ -126,6 +126,8 @@ #define PCIE_BAR_MAX_NUM 6 #define PCIE_HOTRESET_TMOUT_US 10000 +#define PCIE_WAKE_DELAY_US 2000 /* 2 ms */ + struct rockchip_pcie { struct dw_pcie pci; void __iomem *apb_base; @@ -133,7 +135,11 @@ struct rockchip_pcie { struct clk_bulk_data *clks; int clk_cnt; struct reset_control *rst; - struct gpio_desc *rst_gpio; + struct gpio_desc *perst_gpio; + struct gpio_desc *wake_gpio; + int perst_irq; + bool ep_power_independent; + struct completion ep_perst_deassert_complete; unsigned long *ib_window_map; unsigned long *ob_window_map; u32 num_ib_windows; @@ -172,6 +178,8 @@ static const struct of_device_id rockchip_pcie_ep_of_match[] = { MODULE_DEVICE_TABLE(of, rockchip_pcie_ep_of_match); +static irqreturn_t rockchip_pcie_perst_irq_handler(int irq, void *arg); + static void rockchip_pcie_devmode_update(struct rockchip_pcie *rockchip, int mode, int submode) { rockchip->obj_info->devmode.mode = mode; @@ -227,10 +235,24 @@ static int rockchip_pcie_get_io_resource(struct platform_device *pdev, char name[8]; int i, idx; - rockchip->rst_gpio = devm_gpiod_get_optional(dev, "reset", GPIOD_IN); - if (IS_ERR(rockchip->rst_gpio)) { + rockchip->perst_gpio = devm_gpiod_get_optional(dev, "reset", GPIOD_IN); + if (IS_ERR(rockchip->perst_gpio)) { dev_err(dev, "Failed to get reset gpio\n"); - return PTR_ERR(rockchip->rst_gpio); + return PTR_ERR(rockchip->perst_gpio); + } + + if (device_property_read_bool(dev, "rockchip,ep-power-independent")) { + rockchip->ep_power_independent = true; + if (!rockchip->perst_gpio) { + dev_err(dev, "When the EP power supply is independent of the RC, the perst_gpio is necessary\n"); + return -EINVAL; + } + } + + rockchip->wake_gpio = devm_gpiod_get_optional(dev, "wake", GPIOD_OUT_LOW); + if (IS_ERR(rockchip->wake_gpio)) { + dev_err(dev, "Failed to get wake gpio\n"); + return PTR_ERR(rockchip->wake_gpio); } apb_res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "pcie-apb"); @@ -364,7 +386,17 @@ static int rockchip_pcie_get_resource(struct platform_device *pdev, return -EINVAL; } - return 0; + if (rockchip->perst_gpio) { + rockchip->perst_irq = gpiod_to_irq(rockchip->perst_gpio); + ret = devm_request_threaded_irq(&pdev->dev, rockchip->perst_irq, NULL, + rockchip_pcie_perst_irq_handler, + IRQF_TRIGGER_HIGH | IRQF_ONESHOT | IRQF_NO_AUTOEN, + "perst_irq", rockchip); + if (ret) + dev_err(&pdev->dev, "Failed to request PERST IRQ\n"); + } + + return ret; } static int rockchip_pci_find_ext_capability(struct rockchip_pcie *rockchip, int cap) @@ -557,6 +589,38 @@ static int rockchip_pcie_poll_irq_user(struct rockchip_pcie *rockchip, struct pc return 0; } +static int rockchip_pcie_perst_deassert(struct rockchip_pcie *rockchip) +{ + gpiod_set_value_cansleep(rockchip->wake_gpio, 0); + usleep_range(PCIE_WAKE_DELAY_US, PCIE_WAKE_DELAY_US + 500); + gpiod_set_value_cansleep(rockchip->wake_gpio, 1); + + if (rockchip->ep_power_independent) + complete(&rockchip->ep_perst_deassert_complete); + + return 0; +} + +static irqreturn_t rockchip_pcie_perst_irq_handler(int irq, void *arg) +{ + struct rockchip_pcie *rockchip = arg; + struct device *dev = rockchip->pci.dev; + u32 perst; + + perst = gpiod_get_value(rockchip->perst_gpio); + if (perst) { + dev_dbg(dev, "PERST asserted by host. Shutting down the PCIe link!\n"); + } else { + dev_dbg(dev, "PERST de-asserted by host. Starting link training!\n"); + rockchip_pcie_perst_deassert(rockchip); + } + + irq_set_irq_type(gpiod_to_irq(rockchip->perst_gpio), + (perst ? IRQF_TRIGGER_HIGH : IRQF_TRIGGER_LOW)); + + return IRQ_HANDLED; +} + static irqreturn_t rockchip_pcie_sys_irq_handler(int irq, void *arg) { struct rockchip_pcie *rockchip = arg; @@ -680,6 +744,18 @@ static int rockchip_pcie_init_host(struct rockchip_pcie *rockchip) struct device *dev = rockchip->pci.dev; int ret; + if (rockchip->ep_power_independent && gpiod_get_value(rockchip->perst_gpio)) { + init_completion(&rockchip->ep_perst_deassert_complete); + dev_info(dev, "Waiting for perst# de-assert\n"); + enable_irq(rockchip->perst_irq); + ret = wait_for_completion_timeout(&rockchip->ep_perst_deassert_complete, 30 * HZ); + if (!ret) { + dev_err(dev, "Not waiting for a valid PERST signal\n"); + return ret; + } + dev_info(dev, "perst# de-assert\n"); + } + ret = clk_bulk_prepare_enable(rockchip->clk_cnt, rockchip->clks); if (ret) return 0; @@ -1339,11 +1415,54 @@ deinit_host: return ret; } +static int __maybe_unused rockchip_dw_pcie_suspend(struct device *dev) +{ + struct rockchip_pcie *rockchip = dev_get_drvdata(dev); + + rockchip_pcie_deinit_host(rockchip); + + return 0; +} + +static int __maybe_unused rockchip_dw_pcie_resume(struct device *dev) +{ + struct rockchip_pcie *rockchip = dev_get_drvdata(dev); + int ret; + + ret = rockchip_pcie_init_host(rockchip); + if (ret) { + dev_err(dev, "Failed to init host!\n"); + return ret; + } + + ret = rockchip_pcie_config_host(rockchip); + if (ret) { + dev_err(dev, "Failed to config host!\n"); + goto deinit_host; + } + + gpiod_set_value_cansleep(rockchip->wake_gpio, 0); + usleep_range(PCIE_WAKE_DELAY_US, PCIE_WAKE_DELAY_US + 500); + gpiod_set_value_cansleep(rockchip->wake_gpio, 1); + + return ret; +deinit_host: + rockchip_pcie_deinit_host(rockchip); + + return ret; +} + +static const struct dev_pm_ops rockchip_dw_pcie_pm_ops = { + SET_NOIRQ_SYSTEM_SLEEP_PM_OPS(rockchip_dw_pcie_suspend, + rockchip_dw_pcie_resume) +}; + static struct platform_driver rk_plat_pcie_driver = { .driver = { .name = "rk-pcie-ep", .of_match_table = rockchip_pcie_ep_of_match, .suppress_bind_attrs = true, + .pm = &rockchip_dw_pcie_pm_ops, }, .probe = rockchip_pcie_ep_probe, }; From ab74750ff8d67f3788ab5e17f019f5fd9f6e875f Mon Sep 17 00:00:00 2001 From: Liang Chen Date: Thu, 17 Apr 2025 16:59:43 +0800 Subject: [PATCH 09/17] clk: rockchip: clk-pvtpll: update cpu/npu pvtpll config for rv1126b Change-Id: I3a594b18b8c6ced41f13fd6abdc7783b8083612d Signed-off-by: Liang Chen --- drivers/clk/rockchip/clk-pvtpll.c | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/drivers/clk/rockchip/clk-pvtpll.c b/drivers/clk/rockchip/clk-pvtpll.c index 22289bf57bac..ff21f7e258ce 100644 --- a/drivers/clk/rockchip/clk-pvtpll.c +++ b/drivers/clk/rockchip/clk-pvtpll.c @@ -152,10 +152,10 @@ static struct pvtpll_table rv1126b_aisp_pvtpll_table[] = { static struct pvtpll_table rv1126b_core_pvtpll_table[] = { /* rate_hz, ring_sel, length */ - ROCKCHIP_PVTPLL_VOLT_SEL(1608000000, 0, 30, 0), - ROCKCHIP_PVTPLL_VOLT_SEL(1512000000, 0, 30, 7), - ROCKCHIP_PVTPLL_VOLT_SEL(1416000000, 0, 34, 6), - ROCKCHIP_PVTPLL_VOLT_SEL(1296000000, 0, 38, 5), + ROCKCHIP_PVTPLL_VOLT_SEL(1608000000, 0, 30, 7), + ROCKCHIP_PVTPLL_VOLT_SEL(1512000000, 0, 30, 5), + ROCKCHIP_PVTPLL_VOLT_SEL(1416000000, 0, 34, 4), + ROCKCHIP_PVTPLL_VOLT_SEL(1296000000, 0, 38, 3), ROCKCHIP_PVTPLL_VOLT_SEL(1200000000, 0, 38, 3), ROCKCHIP_PVTPLL_VOLT_SEL(1008000000, 0, 52, 3), ROCKCHIP_PVTPLL_VOLT_SEL(816000000, 0, 84, 3), @@ -173,10 +173,10 @@ static struct pvtpll_table rv1126b_isp_pvtpll_table[] = { static struct pvtpll_table rv1126b_npu_pvtpll_table[] = { /* rate_hz, ring_se, length, volt_sel_thr */ - ROCKCHIP_PVTPLL_VOLT_SEL(1000000000, 0, 12, 7), - ROCKCHIP_PVTPLL_VOLT_SEL(950000000, 0, 12, 5), - ROCKCHIP_PVTPLL_VOLT_SEL(900000000, 0, 14, 4), - ROCKCHIP_PVTPLL_VOLT_SEL(800000000, 0, 16, 4), + ROCKCHIP_PVTPLL_VOLT_SEL(1000000000, 0, 12, 5), + ROCKCHIP_PVTPLL_VOLT_SEL(950000000, 0, 12, 3), + ROCKCHIP_PVTPLL_VOLT_SEL(900000000, 0, 14, 2), + ROCKCHIP_PVTPLL_VOLT_SEL(800000000, 0, 16, 2), ROCKCHIP_PVTPLL_VOLT_SEL(700000000, 0, 36, 3), }; From 683c36d1dbe939540e5192c2bef8345b75a64c7a Mon Sep 17 00:00:00 2001 From: Liang Chen Date: Thu, 17 Apr 2025 11:27:19 +0800 Subject: [PATCH 10/17] arm64: dts: rockchip: rv1126b: update opp-table for cpu/npu Adjust pvtm-voltage-sel table of cpu to calibrate cpufreq better. Change-Id: I36f440eee378b3d6865d6beb148ee3a5677fcb22 Signed-off-by: Liang Chen --- arch/arm64/boot/dts/rockchip/rv1126b.dtsi | 52 +++++++++-------------- 1 file changed, 19 insertions(+), 33 deletions(-) diff --git a/arch/arm64/boot/dts/rockchip/rv1126b.dtsi b/arch/arm64/boot/dts/rockchip/rv1126b.dtsi index f6a66bcab364..e50a2ab934fb 100644 --- a/arch/arm64/boot/dts/rockchip/rv1126b.dtsi +++ b/arch/arm64/boot/dts/rockchip/rv1126b.dtsi @@ -308,15 +308,15 @@ nvmem-cell-names = "leakage"; rockchip,pvtm-voltage-sel = < - 0 1639 0 - 1640 1684 1 - 1685 1729 2 - 1730 1774 3 - 1775 1819 4 - 1820 1864 5 - 1865 1909 6 - 1910 1954 7 - 1955 1999 8 + 0 1669 0 + 1670 1714 1 + 1715 1759 2 + 1760 1804 3 + 1805 1849 4 + 1850 1894 5 + 1895 1939 6 + 1940 1984 7 + 1985 2029 8 >; rockchip,pvtm-pvtpll; rockchip,pvtm-offset = <0x54>; @@ -354,52 +354,44 @@ }; opp-1200000000 { opp-hz = /bits/ 64 <1200000000>; - opp-microvolt = <900000 900000 1050000>; + opp-microvolt = <900000 900000 1100000>; opp-microvolt-L0 = <950000 950000 1100000>; opp-microvolt-L1 = <925000 925000 1100000>; clock-latency-ns = <40000>; }; opp-1296000000 { opp-hz = /bits/ 64 <1296000000>; - opp-microvolt = <900000 900000 1050000>; + opp-microvolt = <950000 950000 1100000>; opp-microvolt-L0 = <1000000 1000000 1100000>; opp-microvolt-L1 = <975000 975000 1100000>; - opp-microvolt-L2 = <950000 950000 1100000>; - opp-microvolt-L3 = <925000 925000 1100000>; clock-latency-ns = <40000>; }; opp-1416000000 { opp-hz = /bits/ 64 <1416000000>; - opp-microvolt = <900000 900000 1050000>; + opp-microvolt = <950000 950000 1100000>; opp-microvolt-L0 = <1025000 1025000 1100000>; opp-microvolt-L1 = <1000000 1000000 1100000>; opp-microvolt-L2 = <975000 975000 1100000>; - opp-microvolt-L3 = <950000 950000 1100000>; - opp-microvolt-L4 = <925000 925000 1100000>; clock-latency-ns = <40000>; }; opp-1512000000 { opp-hz = /bits/ 64 <1512000000>; - opp-microvolt = <900000 900000 1050000>; + opp-microvolt = <950000 950000 1100000>; opp-microvolt-L0 = <1050000 1050000 1100000>; opp-microvolt-L1 = <1025000 1025000 1100000>; opp-microvolt-L2 = <1000000 1000000 1100000>; opp-microvolt-L3 = <975000 975000 1100000>; - opp-microvolt-L4 = <950000 950000 1100000>; - opp-microvolt-L5 = <925000 925000 1100000>; clock-latency-ns = <40000>; }; opp-1608000000 { opp-hz = /bits/ 64 <1608000000>; - opp-microvolt = <900000 900000 1050000>; + opp-microvolt = <950000 950000 1100000>; opp-microvolt-L0 = <1100000 1100000 1100000>; opp-microvolt-L1 = <1075000 1075000 1100000>; opp-microvolt-L2 = <1050000 1050000 1100000>; opp-microvolt-L3 = <1025000 1025000 1100000>; opp-microvolt-L4 = <1000000 1000000 1100000>; opp-microvolt-L5 = <975000 975000 1100000>; - opp-microvolt-L6 = <950000 950000 1100000>; - opp-microvolt-L7 = <925000 925000 1100000>; clock-latency-ns = <40000>; }; }; @@ -3321,37 +3313,31 @@ opp-396000000 { opp-hz = /bits/ 64 <396000000>; - opp-microvolt = <850000 850000 1000000>; + opp-microvolt = <850000 850000 1050000>; opp-microvolt-L0 = <900000 900000 1050000>; opp-microvolt-L1 = <875000 875000 1050000>; }; opp-700000000 { opp-hz = /bits/ 64 <700000000>; - opp-microvolt = <850000 850000 1000000>; + opp-microvolt = <850000 850000 1050000>; opp-microvolt-L0 = <900000 900000 1050000>; opp-microvolt-L1 = <875000 875000 1050000>; }; opp-800000000 { opp-hz = /bits/ 64 <800000000>; - opp-microvolt = <850000 850000 1000000>; + opp-microvolt = <900000 900000 1050000>; opp-microvolt-L0 = <925000 925000 1050000>; - opp-microvolt-L1 = <900000 900000 1050000>; - opp-microvolt-L2 = <875000 875000 1050000>; }; opp-900000000 { opp-hz = /bits/ 64 <900000000>; - opp-microvolt = <900000 900000 1000000>; + opp-microvolt = <950000 950000 1050000>; opp-microvolt-L0 = <975000 975000 1050000>; - opp-microvolt-L1 = <950000 950000 1050000>; - opp-microvolt-L2 = <925000 925000 1050000>; }; opp-950000000 { opp-hz = /bits/ 64 <950000000>; - opp-microvolt = <900000 900000 1050000>; + opp-microvolt = <950000 950000 1050000>; opp-microvolt-L0 = <1000000 1000000 1050000>; opp-microvolt-L1 = <975000 975000 1050000>; - opp-microvolt-L2 = <950000 950000 1050000>; - opp-microvolt-L3 = <925000 925000 1050000>; }; }; From dae6de0d5d48a9003fb09f83360625ffeaad673d Mon Sep 17 00:00:00 2001 From: Xu Hongfei Date: Thu, 17 Apr 2025 17:19:01 +0800 Subject: [PATCH 11/17] media: rockchip: fec: add support for offset and stride configuration Signed-off-by: Xu Hongfei Change-Id: If1ac6a30be8b4d1a2c60a9696cb1b33122c1f407 --- .../media/platform/rockchip/fec/fec_offline.c | 76 +++++++++++++------ drivers/media/platform/rockchip/fec/procfs.c | 16 +++- 2 files changed, 67 insertions(+), 25 deletions(-) diff --git a/drivers/media/platform/rockchip/fec/fec_offline.c b/drivers/media/platform/rockchip/fec/fec_offline.c index 95ef4ef2904b..769201b1f44f 100644 --- a/drivers/media/platform/rockchip/fec/fec_offline.c +++ b/drivers/media/platform/rockchip/fec/fec_offline.c @@ -273,8 +273,13 @@ static int fec_running(struct file *file, struct rkfec_in_out *buf) u32 val; u32 in_w = buf->in_width, in_h = buf->in_height; u32 out_w = buf->out_width, out_h = buf->out_height; + /* Calculate virtual width in bytes */ u32 in_stride, out_stride_y, out_stride_uv; + /* Calculate uv offset in bytes */ u32 in_uv_offset, out_uv_offset; + /* Calculate byte offset based on pixel offset */ + u32 in_y_start = 0, in_uv_start = 0, out_y_start = 0, out_uv_start = 0; + u32 y_base, c_base; void __iomem *base = ofl->hw->base_addr; int ret = -EINVAL; ktime_t t = 0; @@ -289,6 +294,11 @@ static int fec_running(struct file *file, struct rkfec_in_out *buf) buf->out_fourcc, buf->out_fourcc >> 8, buf->out_fourcc >> 16, buf->out_fourcc >> 24); + v4l2_dbg(3, rkfec_debug, &ofl->v4l2_dev, + "in: stride %d, offset %d, out: stride %d, offset %d\n", + buf->buf_cfg.in_stride, buf->buf_cfg.in_offs, + buf->buf_cfg.out_stride, buf->buf_cfg.out_offs); + if (hw->fec_ver == RKFEC_V20) { if (hw->soft_reset) hw->soft_reset(hw); @@ -310,14 +320,18 @@ static int fec_running(struct file *file, struct rkfec_in_out *buf) case V4L2_PIX_FMT_NV12: in_fmt = SW_FEC_RD_FMT(1); rd_mode = SW_FEC_RD_MODE(0); - in_stride = (buf->buf_cfg.in_stride + 15) / 16 * 16; + in_stride = ALIGN(buf->buf_cfg.in_stride, 16); in_uv_offset = in_stride * in_h; + in_y_start = buf->buf_cfg.in_offs; + in_uv_start = in_y_start; break; case V4L2_PIX_FMT_TILE420: in_fmt = SW_FEC_RD_FMT(0); rd_mode = SW_FEC_RD_MODE(1); - in_stride = (buf->buf_cfg.in_stride * 6 + 15) / 16 * 16; + in_stride = ALIGN(buf->buf_cfg.in_stride * 6, 16); in_uv_offset = in_stride * in_h; + in_y_start = buf->buf_cfg.in_offs * 6; + in_uv_start = in_y_start; break; default: v4l2_err(&ofl->v4l2_dev, @@ -331,16 +345,20 @@ static int fec_running(struct file *file, struct rkfec_in_out *buf) case V4L2_PIX_FMT_NV12: out_fmt = SW_FEC_WR_FMT(1); wr_mode = SW_FEC_WR_MODE(0); - out_stride_y = (buf->buf_cfg.out_stride + 15) / 16 * 16; + out_stride_y = ALIGN(buf->buf_cfg.out_stride, 16); out_stride_uv = out_stride_y; out_uv_offset = out_stride_y * out_h; + out_y_start = buf->buf_cfg.out_offs; + out_uv_start = out_y_start; break; case V4L2_PIX_FMT_TILE420: out_fmt = SW_FEC_WR_FMT(0); wr_mode = SW_FEC_WR_MODE(1); - out_stride_y = (buf->buf_cfg.out_stride * 6 + 15) / 16 * 16; + out_stride_y = ALIGN(buf->buf_cfg.out_stride * 6, 16); out_stride_uv = out_stride_y; out_uv_offset = out_stride_y * out_h; + out_y_start = buf->buf_cfg.out_offs * 6; + out_uv_start = out_y_start; break; case V4L2_PIX_FMT_FBC0: out_fmt = SW_FEC_WR_FMT(0); @@ -349,13 +367,24 @@ static int fec_running(struct file *file, struct rkfec_in_out *buf) out_stride_uv = (buf->buf_cfg.out_stride + 63) / 64 * 16; // Head stride is c channel out_uv_offset = out_stride_uv * out_h / 4; + out_y_start = buf->buf_cfg.out_offs / 64 * 384; + out_uv_start = buf->buf_cfg.out_offs / 64 * 16; break; case V4L2_PIX_FMT_QUAD: out_fmt = SW_FEC_WR_FMT(0); wr_mode = SW_FEC_WR_MODE(3); - out_stride_y = (buf->buf_cfg.out_stride * 3 + 15) / 16 * 16; + out_stride_y = ALIGN(buf->buf_cfg.out_stride * 3, 16); out_stride_uv = out_stride_y; out_uv_offset = out_stride_y * out_h; + + if (buf->buf_cfg.out_offs > 0) { + v4l2_err(&ofl->v4l2_dev, + "Offset is not supported in %c%c%c%c\n", + buf->out_fourcc, buf->out_fourcc >> 8, + buf->out_fourcc >> 16, buf->out_fourcc >> 24); + out_y_start = 0; + out_uv_start = 0; + } break; default: v4l2_err(&ofl->v4l2_dev, "no support out format:%c%c%c%c\n", @@ -372,11 +401,10 @@ static int fec_running(struct file *file, struct rkfec_in_out *buf) sg_talbe = GET_SG_TABLE(mem_ops, off_buf); if (!sg_talbe) goto free_buf; - val = sg_dma_address(sg_talbe->sgl); - val += buf->buf_cfg.in_offs; - writel(val, base + RKFEC_RD_Y_BASE); - val += in_uv_offset; - writel(val, base + RKFEC_RD_C_BASE); + y_base = sg_dma_address(sg_talbe->sgl); + c_base = y_base + in_uv_offset; + writel(y_base + in_y_start, base + RKFEC_RD_Y_BASE); + writel(c_base + in_uv_start, base + RKFEC_RD_C_BASE); /* output picture buf */ off_buf = buf_add(file, buf->buf_cfg.out_pic_fd, buf->buf_cfg.out_size); @@ -386,21 +414,21 @@ static int fec_running(struct file *file, struct rkfec_in_out *buf) sg_talbe = GET_SG_TABLE(mem_ops, off_buf); if (!sg_talbe) goto free_buf; - val = sg_dma_address(sg_talbe->sgl); if (buf->out_fourcc == V4L2_PIX_FMT_FBC0) { - val += buf->buf_cfg.out_offs; - writel(val, base + RKFEC_WR_C_BASE); - val += out_uv_offset; - writel(val, base + RKFEC_WR_Y_BASE); + c_base = sg_dma_address(sg_talbe->sgl); + y_base = c_base + out_uv_offset; - val = SW_FEC_WR_FBCE_HEAD_OFFSET(out_uv_offset); - writel(val, base + RKFEC_WR_FBCE_HEAD_OFFSET); + if (buf->buf_cfg.out_offs > 0) + writel((out_uv_offset + out_y_start) << 4, + base + RKFEC_WR_FBCE_HEAD_OFFSET); + else + writel(out_uv_offset << 4, base + RKFEC_WR_FBCE_HEAD_OFFSET); } else { - val += buf->buf_cfg.out_offs; - writel(val, base + RKFEC_WR_Y_BASE); - val += out_uv_offset; - writel(val, base + RKFEC_WR_C_BASE); + y_base = sg_dma_address(sg_talbe->sgl); + c_base = y_base + out_uv_offset; } + writel(y_base + out_y_start, base + RKFEC_WR_Y_BASE); + writel(c_base + out_uv_start, base + RKFEC_WR_C_BASE); /* lut buf */ off_buf = buf_add(file, buf->buf_cfg.lut_fd, buf->buf_cfg.lut_size); @@ -465,14 +493,16 @@ static int fec_running(struct file *file, struct rkfec_in_out *buf) ofl->in_fmt.width = in_w; ofl->in_fmt.height = in_h; ofl->in_fmt.pixelformat = buf->in_fourcc; - ofl->in_fmt.bytesperline = buf->buf_cfg.in_stride; + ofl->in_fmt.bytesperline = in_stride; ofl->in_fmt.sizeimage = buf->buf_cfg.in_size; + ofl->in_fmt.offset = buf->buf_cfg.in_offs; ofl->out_fmt.width = out_w; ofl->out_fmt.height = out_h; ofl->out_fmt.pixelformat = buf->out_fourcc; - ofl->out_fmt.bytesperline = buf->buf_cfg.out_stride; + ofl->out_fmt.bytesperline = out_stride_y; ofl->out_fmt.sizeimage = buf->buf_cfg.out_size; + ofl->out_fmt.offset = buf->buf_cfg.out_offs; ret = wait_for_completion_timeout(&ofl->cmpl, msecs_to_jiffies(300)); if (!ret) { diff --git a/drivers/media/platform/rockchip/fec/procfs.c b/drivers/media/platform/rockchip/fec/procfs.c index aabfe8bd9c40..28b494550a1d 100644 --- a/drivers/media/platform/rockchip/fec/procfs.c +++ b/drivers/media/platform/rockchip/fec/procfs.c @@ -37,13 +37,21 @@ static void offline_fec_show_hw(struct seq_file *p, struct rkfec_hw_dev *hw) "4x4" }; + static const char * const cacheline[] = { + "64B", + "64B", + "128B", + "128B" + }; + if (hw->dev->power.usage_count.counter <= 0) { seq_printf(p, "\n%s\n", "HW close"); return; } val = readl(hw->base_addr + RKFEC_CTRL); - seq_printf(p, "%-10s RD_fmt:%s RD_mode:%s WR_fmt:%s WR_mode:%s WR_fbce:%s (0x%x)\n", "CTRL", + seq_printf(p, "%-10s RD_fmt:%s RD_mode:%s WR_fmt:%s WR_mode:%s WR_fbce_unc:%s (0x%x)\n", + "CTRL", val & BIT(2) ? "semi" : "interleave", (val >> 4) & 0x3 ? "semi" : "rast", val & BIT(8) ? "semi" : "interleave", wr_mode[val >> 9], @@ -75,6 +83,9 @@ static void offline_fec_show_hw(struct seq_file *p, struct rkfec_hw_dev *hw) val = readl(hw->base_addr + RKFEC_STATUS1); seq_printf(p, "%-10s 0x%x\n", "STATUS1", val & 0x3FFFFF); + + val = readl(hw->base_addr + RKFEC_CACHE_CTRL); + seq_printf(p, "%-10s %s\n", "Cacheline", cacheline[(val >> 4) & 0x3]); } static int offline_fec_show(struct seq_file *p, void *v) @@ -110,7 +121,7 @@ static int offline_fec_show(struct seq_file *p, void *v) ofl->debug.frameloss, ofl->debug.frame_timeout_cnt); - seq_printf(p, "%-10s Format:%c%c%c%c Size:%dx%d Sizeimage(%d) (frame:%d rate:%dms frameloss:%d\n", + seq_printf(p, "%-10s Format:%c%c%c%c Size:%dx%d Offset(%d) Sizeimage(%d) (frame:%d rate:%dms frameloss:%d\n", "Output", ofl->out_fmt.pixelformat, ofl->out_fmt.pixelformat >> 8, @@ -118,6 +129,7 @@ static int offline_fec_show(struct seq_file *p, void *v) ofl->out_fmt.pixelformat >> 24, ofl->out_fmt.width, ofl->out_fmt.height, + ofl->out_fmt.offset, ofl->out_fmt.sizeimage, ofl->curr_frame.fe_seq, (u32)(ofl->curr_frame.fe_timestamp - ofl->prev_frame.fe_timestamp) / 1000 / 1000, From 96aab710fbf615d8420eddcede11a4cbcefd3c29 Mon Sep 17 00:00:00 2001 From: Su Yuefu Date: Fri, 11 Apr 2025 17:56:32 +0800 Subject: [PATCH 12/17] arm64: dts: rockchip: rv1126b-evb2-v10: fixes error of cam reset pin of sc850sl Signed-off-by: Su Yuefu Change-Id: I908e8b1e30b49b2058b0cd00d5075e631be8f0ae --- arch/arm64/boot/dts/rockchip/rv1126b-evb2-v10.dts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/arch/arm64/boot/dts/rockchip/rv1126b-evb2-v10.dts b/arch/arm64/boot/dts/rockchip/rv1126b-evb2-v10.dts index cf105f8eecc4..f3a7677ba283 100644 --- a/arch/arm64/boot/dts/rockchip/rv1126b-evb2-v10.dts +++ b/arch/arm64/boot/dts/rockchip/rv1126b-evb2-v10.dts @@ -585,7 +585,7 @@ }; &sc850sl { - reset-gpios = <&gpio4 RK_PA7 GPIO_ACTIVE_LOW>; + reset-gpios = <&gpio4 RK_PA7 GPIO_ACTIVE_HIGH>; }; &sdmmc0 { From 97932bdf73063697acd862d3f9fdc706decf0927 Mon Sep 17 00:00:00 2001 From: Zhang Yubing Date: Thu, 20 Mar 2025 10:25:21 +0800 Subject: [PATCH 13/17] drm/rockchip: dp_aux_client: parse timing by child node name The child node may be not parsed by the order config in dts, it would be better get child node by name to avoid mismatch. Change-Id: Ibce47f44720f279eb53f063a351d3b859a371fd8 Signed-off-by: Zhang Yubing --- .../gpu/drm/rockchip/rockchip_dp_mst_aux_client.c | 12 +++++++++--- 1 file changed, 9 insertions(+), 3 deletions(-) diff --git a/drivers/gpu/drm/rockchip/rockchip_dp_mst_aux_client.c b/drivers/gpu/drm/rockchip/rockchip_dp_mst_aux_client.c index 6baf5039fb54..d7bc91adc841 100644 --- a/drivers/gpu/drm/rockchip/rockchip_dp_mst_aux_client.c +++ b/drivers/gpu/drm/rockchip/rockchip_dp_mst_aux_client.c @@ -183,6 +183,7 @@ static int rockchip_dp_aux_client_parse(struct rockchip_dp_aux_client *aux_clien struct drm_display_mode mode_buf, *mode = &mode_buf; int rc, port_num, i; struct edid *edid; + char name[10]; const u8 edid_buf[EDID_LENGTH] = { 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x44, 0x6D, @@ -205,13 +206,18 @@ static int rockchip_dp_aux_client_parse(struct rockchip_dp_aux_client *aux_clien if (!ports) return -ENOMEM; - i = 0; - for_each_child_of_node(of_node, node) { + for (i = 0; i < port_num; i++) { struct display_timing dt; struct videomode vm; + snprintf(name, sizeof(name), "mst-dp%d", i); + node = of_get_child_by_name(of_node, name); + if (!node) + return -EINVAL; + edid = kzalloc(sizeof(*edid), GFP_KERNEL); if (!edid) { + of_node_put(node); rc = -ENOMEM; goto fail; } @@ -222,13 +228,13 @@ static int rockchip_dp_aux_client_parse(struct rockchip_dp_aux_client *aux_clien drm_display_mode_from_videomode(&vm, mode); rockchip_dp_sim_update_dtd(edid, mode); } + of_node_put(node); rockchip_dp_sim_update_checksum(edid); memcpy(&ports[i], &output_port, sizeof(*ports)); ports[i].peer_guid[0] = i; ports[i].edid = (u8 *)edid; ports[i].edid_size = sizeof(*edid); - i++; } rc = rockchip_dp_mst_sim_update(aux_client->mst_ctx, port_num, ports); From 6609d45ac5967236197a3546fff85995b8e42fea Mon Sep 17 00:00:00 2001 From: Zhang Yubing Date: Thu, 17 Apr 2025 11:05:47 +0800 Subject: [PATCH 14/17] drm/rockchip: dw-dp: mst mode don't allow external bridge create connector In mst mode, dptx driver will dynamic create and destroy connector according to the attach mst device. If a external bridge is add for dp in mst mode, this bridge is not allow to create connector. Change-Id: I811baf5116e4c2cd1d12b04ead2054abcccbdffd Signed-off-by: Zhang Yubing --- drivers/gpu/drm/rockchip/dw-dp.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/drivers/gpu/drm/rockchip/dw-dp.c b/drivers/gpu/drm/rockchip/dw-dp.c index 843ac09a17a3..d77c05ccd6c2 100644 --- a/drivers/gpu/drm/rockchip/dw-dp.c +++ b/drivers/gpu/drm/rockchip/dw-dp.c @@ -4145,7 +4145,8 @@ static int dw_dp_mst_find_ext_bridges(struct dw_dp *dp) return ret; if (mst_enc->next_bridge) { - ret = drm_bridge_attach(&mst_enc->encoder, mst_enc->next_bridge, NULL, 0); + ret = drm_bridge_attach(&mst_enc->encoder, mst_enc->next_bridge, NULL, + DRM_BRIDGE_ATTACH_NO_CONNECTOR); if (ret) { DRM_DEV_ERROR(dp->dev, "failed to attach next bridge: %d\n", ret); return ret; From 4719bd6e80df0e89e34a211dfb0e66a8188eb349 Mon Sep 17 00:00:00 2001 From: Xu Hongfei Date: Thu, 17 Apr 2025 19:59:36 +0800 Subject: [PATCH 15/17] media: rockchip: fec: add module parameter user_debug Signed-off-by: Xu Hongfei Change-Id: I1bd315aff2ee527241a29afff557e23531cbc440 --- drivers/media/platform/rockchip/fec/fec_offline.c | 4 ++++ drivers/media/platform/rockchip/ispp/fec.c | 4 ++++ 2 files changed, 8 insertions(+) diff --git a/drivers/media/platform/rockchip/fec/fec_offline.c b/drivers/media/platform/rockchip/fec/fec_offline.c index 769201b1f44f..b89146a6126b 100644 --- a/drivers/media/platform/rockchip/fec/fec_offline.c +++ b/drivers/media/platform/rockchip/fec/fec_offline.c @@ -21,6 +21,10 @@ static int rkfec_cache_linesize = 2; module_param_named(cache_linesize, rkfec_cache_linesize, int, 0644); MODULE_PARM_DESC(cache_linesize, "Cache linesize (0-3)"); +static int rkfec_user_debug; +module_param_named(user_debug, rkfec_user_debug, int, 0644); +MODULE_PARM_DESC(user_debug, "Debug level (0-6)"); + #if IS_LINUX_VERSION_AT_LEAST_6_1 #define GET_SG_TABLE(mem_ops, off_buf) mem_ops->cookie(&(off_buf)->vb, (off_buf)->mem) #else diff --git a/drivers/media/platform/rockchip/ispp/fec.c b/drivers/media/platform/rockchip/ispp/fec.c index 643322314fab..113a932faaca 100644 --- a/drivers/media/platform/rockchip/ispp/fec.c +++ b/drivers/media/platform/rockchip/ispp/fec.c @@ -18,6 +18,10 @@ #include "stream.h" #include "common.h" +static int rkfec_user_debug; +module_param_named(user_debug, rkfec_user_debug, int, 0644); +MODULE_PARM_DESC(user_debug, "Debug level (0-6)"); + struct rkispp_fec_buf { struct list_head list; struct file *file; From b6558f3a76ee98a39539945dc32dd967cfdba441 Mon Sep 17 00:00:00 2001 From: Sach Lin Date: Fri, 18 Apr 2025 07:25:41 +0000 Subject: [PATCH 16/17] media: rockchip: avsp: add support for fbce head offset Signed-off-by: Sach Lin Change-Id: Ic72bd2cc5e23af9cac2ee46884da9e0c3b0ea317 --- drivers/media/platform/rockchip/avsp/avsp.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/drivers/media/platform/rockchip/avsp/avsp.c b/drivers/media/platform/rockchip/avsp/avsp.c index 3f9ad5a92676..c28de5f0ade9 100644 --- a/drivers/media/platform/rockchip/avsp/avsp.c +++ b/drivers/media/platform/rockchip/avsp/avsp.c @@ -342,12 +342,14 @@ static int avsp_rcs_run(struct file *file, struct rkavsp_rcs_in_out *buf) writel(val, base + AVSP_RCS_WR_C_BASE); break; case AVSP_MODE_FBCE: - out_offs = rcs_wr_stride_c * in_h; c_addr = val + (rcs_out_start_offset / 64) * 16; writel(c_addr, base + AVSP_RCS_WR_C_BASE); - val += ((rcs_out_start_offset / 64) * 384); + out_offs = rcs_wr_stride_c * in_h + ((rcs_out_start_offset / 64) * 384); val += out_offs; writel(val, base + AVSP_RCS_WR_Y_BASE); + + val = out_offs; + writel(val << 4, base + AVSP_RCS_WR_FBCE_HEAD_OFFSET); break; default: val += (rcs_out_start_offset * 6); From d4a3012c2476400a7fa77dd204c2266c375b8961 Mon Sep 17 00:00:00 2001 From: Yu Qiaowei Date: Wed, 16 Apr 2025 15:16:49 +0800 Subject: [PATCH 17/17] video: rockchip: rga3: remove dependency on CONFIG_IOMMU_IOVA Since 'CONFIG_IOMMU_IOVA' is often disabled on 32-bit systems, causing iommu_map API calls to fail, the DMA mapping API is used instead. Change-Id: I7226ddf6a04e0af4c6b1b029bb5a32ede04c0810 Signed-off-by: Yu Qiaowei --- .../video/rockchip/rga3/include/rga_dma_buf.h | 18 +- drivers/video/rockchip/rga3/include/rga_drv.h | 11 +- drivers/video/rockchip/rga3/include/rga_mm.h | 2 +- drivers/video/rockchip/rga3/rga_debugger.c | 4 +- drivers/video/rockchip/rga3/rga_dma_buf.c | 248 +++++------------- drivers/video/rockchip/rga3/rga_mm.c | 202 +++++++------- 6 files changed, 192 insertions(+), 293 deletions(-) diff --git a/drivers/video/rockchip/rga3/include/rga_dma_buf.h b/drivers/video/rockchip/rga3/include/rga_dma_buf.h index fefea23914e2..05a801c0705c 100644 --- a/drivers/video/rockchip/rga3/include/rga_dma_buf.h +++ b/drivers/video/rockchip/rga3/include/rga_dma_buf.h @@ -26,18 +26,18 @@ int rga_buf_size_cal(unsigned long yrgb_addr, unsigned long uv_addr, int rga_virtual_memory_check(void *vaddr, u32 w, u32 h, u32 format, int fd); int rga_dma_memory_check(struct rga_dma_buffer *rga_dma_buffer, struct rga_img_info_t *img); -int rga_iommu_map_sgt(struct sg_table *sgt, size_t size, - struct rga_dma_buffer *buffer, - struct device *rga_dev); -int rga_iommu_map(phys_addr_t paddr, size_t size, - struct rga_dma_buffer *buffer, - struct device *rga_dev); -void rga_iommu_unmap(struct rga_dma_buffer *buffer); +int rga_dma_map_phys_addr(phys_addr_t phys_addr, size_t size, struct rga_dma_buffer *buffer, + enum dma_data_direction dir, struct device *map_dev); +void rga_dma_unmap_phys_addr(struct rga_dma_buffer *buffer); + +int rga_dma_map_sgt(struct sg_table *sgt, struct rga_dma_buffer *buffer, + enum dma_data_direction dir, struct device *map_dev); +void rga_dma_unmap_sgt(struct rga_dma_buffer *buffer); int rga_dma_map_buf(struct dma_buf *dma_buf, struct rga_dma_buffer *rga_dma_buffer, - enum dma_data_direction dir, struct device *rga_dev); + enum dma_data_direction dir, struct device *map_dev); int rga_dma_map_fd(int fd, struct rga_dma_buffer *rga_dma_buffer, - enum dma_data_direction dir, struct device *rga_dev); + enum dma_data_direction dir, struct device *map_dev); void rga_dma_unmap_buf(struct rga_dma_buffer *rga_dma_buffer); void rga_dma_sync_flush_range(void *pstart, void *pend, struct rga_scheduler_t *scheduler); diff --git a/drivers/video/rockchip/rga3/include/rga_drv.h b/drivers/video/rockchip/rga3/include/rga_drv.h index f934e38c6a83..0d41d4be2e8a 100644 --- a/drivers/video/rockchip/rga3/include/rga_drv.h +++ b/drivers/video/rockchip/rga3/include/rga_drv.h @@ -182,8 +182,11 @@ struct rga_dma_buffer { */ size_t offset; - /* The scheduler of the mapping */ - struct rga_scheduler_t *scheduler; + /* + * The device used by dma-buf mapping, which usually corresponds to the + * default domain or the current device. + */ + struct device *map_dev; }; struct rga_virt_addr { @@ -192,6 +195,7 @@ struct rga_virt_addr { struct page **pages; int pages_order; int page_count; + /* Actual effective size */ unsigned long size; /* The offset of the first page of the virtual address */ @@ -227,6 +231,9 @@ struct rga_internal_buffer { struct kref refcount; struct rga_session *session; + + /* The scheduler of the mapping */ + struct rga_scheduler_t *scheduler; }; struct rga_scheduler_t; diff --git a/drivers/video/rockchip/rga3/include/rga_mm.h b/drivers/video/rockchip/rga3/include/rga_mm.h index d68fd75dcb45..a75f2470b928 100644 --- a/drivers/video/rockchip/rga3/include/rga_mm.h +++ b/drivers/video/rockchip/rga3/include/rga_mm.h @@ -42,7 +42,7 @@ static inline bool rga_mm_is_invalid_dma_buffer(struct rga_dma_buffer *buffer) if (buffer == NULL) return true; - return buffer->scheduler == NULL ? true : false; + return buffer->map_dev == NULL ? true : false; } struct rga_internal_buffer *rga_mm_lookup_handle(struct rga_mm *mm_session, uint32_t handle); diff --git a/drivers/video/rockchip/rga3/rga_debugger.c b/drivers/video/rockchip/rga3/rga_debugger.c index 93c5fcf3ec48..572035977338 100644 --- a/drivers/video/rockchip/rga3/rga_debugger.c +++ b/drivers/video/rockchip/rga3/rga_debugger.c @@ -286,7 +286,7 @@ static int rga_mm_session_show(struct seq_file *m, void *data) (unsigned long)dump_buffer->dma_buffer->iova, dump_buffer->dma_buffer->sgt, dump_buffer->dma_buffer->size, - dump_buffer->dma_buffer->scheduler->core); + dump_buffer->scheduler->core); if (dump_buffer->mm_flag & RGA_MEM_PHYSICAL_CONTIGUOUS) seq_printf(m, "\t is contiguous, pa = 0x%lx\n", @@ -310,7 +310,7 @@ static int rga_mm_session_show(struct seq_file *m, void *data) (unsigned long)dump_buffer->dma_buffer->offset, dump_buffer->dma_buffer->sgt, dump_buffer->dma_buffer->size, - dump_buffer->dma_buffer->scheduler->core); + dump_buffer->scheduler->core); if (dump_buffer->mm_flag & RGA_MEM_PHYSICAL_CONTIGUOUS) seq_printf(m, "\t is contiguous, pa = 0x%lx\n", diff --git a/drivers/video/rockchip/rga3/rga_dma_buf.c b/drivers/video/rockchip/rga3/rga_dma_buf.c index e72470e5c5f5..96609d0784fe 100644 --- a/drivers/video/rockchip/rga3/rga_dma_buf.c +++ b/drivers/video/rockchip/rga3/rga_dma_buf.c @@ -11,20 +11,6 @@ #include "rga_job.h" #include "rga_debugger.h" -static int rga_dma_info_to_prot(enum dma_data_direction dir) -{ - switch (dir) { - case DMA_BIDIRECTIONAL: - return IOMMU_READ | IOMMU_WRITE; - case DMA_TO_DEVICE: - return IOMMU_READ; - case DMA_FROM_DEVICE: - return IOMMU_WRITE; - default: - return 0; - } -} - int rga_buf_size_cal(unsigned long yrgb_addr, unsigned long uv_addr, unsigned long v_addr, int format, uint32_t w, uint32_t h, unsigned long *StartAddr, unsigned long *size) @@ -198,165 +184,6 @@ int rga_buf_size_cal(unsigned long yrgb_addr, unsigned long uv_addr, return pageCount; } -static dma_addr_t rga_iommu_dma_alloc_iova(struct iommu_domain *domain, - size_t size, u64 dma_limit, - struct device *dev) -{ - struct rga_iommu_dma_cookie *cookie = (void *)domain->iova_cookie; - struct iova_domain *iovad = &cookie->iovad; - unsigned long shift, iova_len, iova = 0; - - shift = iova_shift(iovad); - iova_len = size >> shift; - -#if (LINUX_VERSION_CODE < KERNEL_VERSION(6, 1, 0)) - /* - * Freeing non-power-of-two-sized allocations back into the IOVA caches - * will come back to bite us badly, so we have to waste a bit of space - * rounding up anything cacheable to make sure that can't happen. The - * order of the unadjusted size will still match upon freeing. - */ - if (iova_len < (1 << (IOVA_RANGE_CACHE_MAX_SIZE - 1))) - iova_len = roundup_pow_of_two(iova_len); -#endif - -#if (LINUX_VERSION_CODE >= KERNEL_VERSION(5, 10, 0)) - dma_limit = min_not_zero(dma_limit, dev->bus_dma_limit); -#else - if (dev->bus_dma_mask) - dma_limit &= dev->bus_dma_mask; -#endif - - if (domain->geometry.force_aperture) - dma_limit = min(dma_limit, (u64)domain->geometry.aperture_end); - -#if (LINUX_VERSION_CODE > KERNEL_VERSION(4, 19, 111) && \ - LINUX_VERSION_CODE < KERNEL_VERSION(5, 4, 0)) - iova = alloc_iova_fast(iovad, iova_len, - min_t(dma_addr_t, dma_limit >> shift, iovad->end_pfn), - true); -#else - iova = alloc_iova_fast(iovad, iova_len, dma_limit >> shift, true); -#endif - - return (dma_addr_t)iova << shift; -} - -static void rga_iommu_dma_free_iova(struct iommu_domain *domain, - dma_addr_t iova, size_t size) -{ - struct rga_iommu_dma_cookie *cookie = (void *)domain->iova_cookie; - struct iova_domain *iovad = &cookie->iovad; - - free_iova_fast(iovad, iova_pfn(iovad, iova), size >> iova_shift(iovad)); -} - -static inline struct iommu_domain *rga_iommu_get_dma_domain(struct device *dev) -{ - return iommu_get_domain_for_dev(dev); -} - -void rga_iommu_unmap(struct rga_dma_buffer *buffer) -{ - if (buffer == NULL) - return; - if (buffer->iova == 0) - return; - - iommu_unmap(buffer->domain, buffer->iova, buffer->size); - rga_iommu_dma_free_iova(buffer->domain, buffer->iova, buffer->size); -} - -int rga_iommu_map_sgt(struct sg_table *sgt, size_t size, - struct rga_dma_buffer *buffer, - struct device *rga_dev) -{ - struct iommu_domain *domain = NULL; - struct rga_iommu_dma_cookie *cookie; - struct iova_domain *iovad; - dma_addr_t iova; - size_t map_size; - unsigned long align_size; - - if (sgt == NULL) { - rga_err("can not map iommu, because sgt is null!\n"); - return -EINVAL; - } - - domain = rga_iommu_get_dma_domain(rga_dev); - cookie = (void *)domain->iova_cookie; - iovad = &cookie->iovad; - align_size = iova_align(iovad, size); - - if (DEBUGGER_EN(MSG)) - rga_log("iova_align size = %ld", align_size); - - iova = rga_iommu_dma_alloc_iova(domain, align_size, rga_dev->coherent_dma_mask, rga_dev); - if (!iova) { - rga_err("rga_iommu_dma_alloc_iova failed"); - return -ENOMEM; - } - - map_size = iommu_map_sg(domain, iova, sgt->sgl, sgt->orig_nents, - rga_dma_info_to_prot(DMA_BIDIRECTIONAL)); - if (map_size < align_size) { - rga_err("iommu can not map sgt to iova"); - rga_iommu_dma_free_iova(domain, iova, align_size); - return -EINVAL; - } - - buffer->domain = domain; - buffer->iova = iova; - buffer->size = align_size; - - return 0; -} - -int rga_iommu_map(phys_addr_t paddr, size_t size, - struct rga_dma_buffer *buffer, - struct device *rga_dev) -{ - int ret; - struct iommu_domain *domain = NULL; - struct rga_iommu_dma_cookie *cookie; - struct iova_domain *iovad; - dma_addr_t iova; - unsigned long align_size; - - if (paddr == 0) { - rga_err("can not map iommu, because phys_addr is 0!\n"); - return -EINVAL; - } - - domain = rga_iommu_get_dma_domain(rga_dev); - cookie = (void *)domain->iova_cookie; - iovad = &cookie->iovad; - align_size = iova_align(iovad, size); - - if (DEBUGGER_EN(MSG)) - rga_log("iova_align size = %ld", align_size); - - iova = rga_iommu_dma_alloc_iova(domain, align_size, rga_dev->coherent_dma_mask, rga_dev); - if (!iova) { - rga_err("rga_iommu_dma_alloc_iova failed"); - return -ENOMEM; - } - - ret = iommu_map(domain, iova, paddr, align_size, - rga_dma_info_to_prot(DMA_BIDIRECTIONAL)); - if (ret) { - rga_err("iommu can not map phys_addr to iova"); - rga_iommu_dma_free_iova(domain, iova, align_size); - return ret; - } - - buffer->domain = domain; - buffer->iova = iova; - buffer->size = align_size; - - return 0; -} - int rga_virtual_memory_check(void *vaddr, u32 w, u32 h, u32 format, int fd) { int bits = 32; @@ -424,8 +251,67 @@ int rga_dma_memory_check(struct rga_dma_buffer *rga_dma_buffer, struct rga_img_i return ret; } +int rga_dma_map_phys_addr(phys_addr_t phys_addr, size_t size, struct rga_dma_buffer *buffer, + enum dma_data_direction dir, struct device *map_dev) +{ + dma_addr_t addr; + + addr = dma_map_resource(map_dev, phys_addr, size, dir, 0); + if (addr == DMA_MAPPING_ERROR) { + rga_err("dma_map_resouce failed!\n"); + return -EINVAL; + } + + buffer->dma_addr = addr; + buffer->dir = dir; + buffer->size = size; + buffer->map_dev = map_dev; + + return 0; +} + +void rga_dma_unmap_phys_addr(struct rga_dma_buffer *buffer) +{ + dma_unmap_resource(buffer->map_dev, buffer->dma_addr, buffer->size, buffer->dir, 0); +} + +int rga_dma_map_sgt(struct sg_table *sgt, struct rga_dma_buffer *buffer, + enum dma_data_direction dir, struct device *map_dev) +{ + int i, ret = 0; + struct scatterlist *sg = NULL; + + ret = dma_map_sg(map_dev, sgt->sgl, sgt->orig_nents, dir); + if (ret <= 0) { + rga_err("dma_map_sg failed! ret = %d\n", ret); + return ret < 0 ? ret : -EINVAL; + } + sgt->nents = ret; + + buffer->sgt = sgt; + buffer->dma_addr = sg_dma_address(sgt->sgl); + buffer->dir = dir; + buffer->size = 0; + for_each_sgtable_sg(sgt, sg, i) + buffer->size += sg_dma_len(sg); + buffer->map_dev = map_dev; + + return 0; +} + +void rga_dma_unmap_sgt(struct rga_dma_buffer *buffer) +{ + if (!buffer->sgt) + return; + + dma_unmap_sg(buffer->map_dev, + buffer->sgt->sgl, + buffer->sgt->orig_nents, + buffer->dir); +} + int rga_dma_map_buf(struct dma_buf *dma_buf, struct rga_dma_buffer *rga_dma_buffer, - enum dma_data_direction dir, struct device *rga_dev) + enum dma_data_direction dir, struct device *map_dev) { struct dma_buf_attachment *attach = NULL; struct sg_table *sgt = NULL; @@ -439,7 +325,7 @@ int rga_dma_map_buf(struct dma_buf *dma_buf, struct rga_dma_buffer *rga_dma_buff return -EINVAL; } - attach = dma_buf_attach(dma_buf, rga_dev); + attach = dma_buf_attach(dma_buf, map_dev); if (IS_ERR(attach)) { ret = PTR_ERR(attach); rga_err("Failed to attach dma_buf, ret[%d]\n", ret); @@ -461,6 +347,7 @@ int rga_dma_map_buf(struct dma_buf *dma_buf, struct rga_dma_buffer *rga_dma_buff rga_dma_buffer->size = 0; for_each_sgtable_sg(sgt, sg, i) rga_dma_buffer->size += sg_dma_len(sg); + rga_dma_buffer->map_dev = map_dev; return ret; @@ -475,7 +362,7 @@ err_get_attach: } int rga_dma_map_fd(int fd, struct rga_dma_buffer *rga_dma_buffer, - enum dma_data_direction dir, struct device *rga_dev) + enum dma_data_direction dir, struct device *map_dev) { struct dma_buf *dma_buf = NULL; struct dma_buf_attachment *attach = NULL; @@ -490,7 +377,7 @@ int rga_dma_map_fd(int fd, struct rga_dma_buffer *rga_dma_buffer, return ret; } - attach = dma_buf_attach(dma_buf, rga_dev); + attach = dma_buf_attach(dma_buf, map_dev); if (IS_ERR(attach)) { ret = PTR_ERR(attach); rga_err("Failed to attach dma_buf, ret[%d]\n", ret); @@ -512,6 +399,7 @@ int rga_dma_map_fd(int fd, struct rga_dma_buffer *rga_dma_buffer, rga_dma_buffer->size = 0; for_each_sgtable_sg(sgt, sg, i) rga_dma_buffer->size += sg_dma_len(sg); + rga_dma_buffer->map_dev = map_dev; return ret; @@ -551,12 +439,12 @@ int rga_dma_free(struct rga_dma_buffer *buffer) return -EINVAL; } - dma_free_coherent(buffer->scheduler->dev, buffer->size, buffer->vaddr, buffer->dma_addr); + dma_free_coherent(buffer->map_dev, buffer->size, buffer->vaddr, buffer->dma_addr); buffer->vaddr = NULL; buffer->dma_addr = 0; buffer->iova = 0; buffer->size = 0; - buffer->scheduler = NULL; + buffer->map_dev = NULL; kfree(buffer); @@ -581,7 +469,7 @@ struct rga_dma_buffer *rga_dma_alloc_coherent(struct rga_scheduler_t *scheduler, buffer->size = align_size; buffer->dma_addr = dma_addr; - buffer->scheduler = scheduler; + buffer->map_dev = scheduler->dev; if (scheduler->data->mmu == RGA_IOMMU) buffer->iova = buffer->dma_addr; diff --git a/drivers/video/rockchip/rga3/rga_mm.c b/drivers/video/rockchip/rga3/rga_mm.c index 740009008e59..eb34fde9d769 100644 --- a/drivers/video/rockchip/rga3/rga_mm.c +++ b/drivers/video/rockchip/rga3/rga_mm.c @@ -179,11 +179,10 @@ static struct sg_table *rga_alloc_sgt(struct rga_virt_addr *virt_addr) } /* get sg form pages. */ - /* iova requires minimum page alignment, so sgt cannot have offset */ ret = sg_alloc_table_from_pages(sgt, virt_addr->pages, virt_addr->page_count, - 0, + virt_addr->offset, virt_addr->size, GFP_KERNEL); if (ret) { @@ -232,7 +231,6 @@ static int rga_alloc_virt_addr(struct rga_virt_addr **virt_addr_p, unsigned int count; int img_size; size_t offset; - unsigned long size; struct page **pages = NULL; struct rga_virt_addr *virt_addr = NULL; @@ -246,10 +244,9 @@ static int rga_alloc_virt_addr(struct rga_virt_addr **virt_addr_p, offset = viraddr & (~PAGE_MASK); count = RGA_GET_PAGE_COUNT(img_size + offset); - size = count * PAGE_SIZE; - if (!size) { - rga_err("failed to calculating buffer size! size = %ld, count = %d, offset = %ld\n", - size, count, (unsigned long)offset); + if (!count) { + rga_err("failed to calculating buffer size! img_size = %d, count = %d, offset = %ld\n", + img_size, count, (unsigned long)offset); rga_dump_memory_parm(memory_parm); return -EFAULT; } @@ -292,7 +289,7 @@ static int rga_alloc_virt_addr(struct rga_virt_addr **virt_addr_p, virt_addr->pages = pages; virt_addr->pages_order = order; virt_addr->page_count = count; - virt_addr->size = size; + virt_addr->size = img_size; virt_addr->offset = offset; virt_addr->result = result; @@ -398,18 +395,17 @@ static int rga_mm_map_dma_buffer(struct rga_external_buffer *external_buffer, return ex_buffer_size == 0 ? -EINVAL : ex_buffer_size; } - /* - * dma-buf api needs to use default_domain of main dev, - * and not IOMMU for devices without iommu_info ptr. - */ - map_dev = scheduler->iommu_info ? scheduler->iommu_info->default_dev : scheduler->dev; - buffer = kzalloc(sizeof(*buffer), GFP_KERNEL); if (buffer == NULL) { rga_err("%s alloc internal_buffer error!\n", __func__); return -ENOMEM; } + /* + * dma-buf api needs to use default_domain of main dev, + * and not IOMMU for devices without iommu_info ptr. + */ + map_dev = scheduler->iommu_info ? scheduler->iommu_info->default_dev : scheduler->dev; switch (external_buffer->type) { case RGA_DMA_BUFFER: ret = rga_dma_map_fd((int)external_buffer->memory, @@ -440,8 +436,6 @@ static int rga_mm_map_dma_buffer(struct rga_external_buffer *external_buffer, goto unmap_buffer; } - buffer->scheduler = scheduler; - if (scheduler->data->mmu == RGA_IOMMU) buffer->iova = buffer->dma_addr; @@ -473,6 +467,8 @@ static int rga_mm_map_dma_buffer(struct rga_external_buffer *external_buffer, internal_buffer->dma_buffer = buffer; internal_buffer->mm_flag = mm_flag; internal_buffer->phys_addr = phys_addr ? phys_addr : 0; + internal_buffer->size = buffer->size - buffer->offset; + internal_buffer->scheduler = scheduler; return 0; @@ -492,19 +488,7 @@ static void rga_mm_unmap_virt_addr(struct rga_internal_buffer *internal_buffer) if (rga_mm_is_invalid_dma_buffer(internal_buffer->dma_buffer)) return; - switch (internal_buffer->dma_buffer->scheduler->data->mmu) { - case RGA_IOMMU: - rga_iommu_unmap(internal_buffer->dma_buffer); - break; - case RGA_MMU: - dma_unmap_sg(internal_buffer->dma_buffer->scheduler->dev, - internal_buffer->dma_buffer->sgt->sgl, - internal_buffer->dma_buffer->sgt->orig_nents, - DMA_BIDIRECTIONAL); - break; - default: - break; - } + rga_dma_unmap_sgt(internal_buffer->dma_buffer); if (internal_buffer->mm_flag & RGA_MEM_PHYSICAL_CONTIGUOUS && internal_buffer->phys_addr > 0) @@ -532,6 +516,7 @@ static int rga_mm_map_virt_addr(struct rga_external_buffer *external_buffer, struct sg_table *sgt; struct rga_virt_addr *virt_addr; struct rga_dma_buffer *buffer; + struct device *map_dev; struct rga_scheduler_t *scheduler; scheduler = job ? job->scheduler : @@ -578,6 +563,11 @@ static int rga_mm_map_virt_addr(struct rga_external_buffer *external_buffer, } mm_flag |= RGA_MEM_PHYSICAL_CONTIGUOUS; + } else if (scheduler->data->mmu == RGA_NONE_MMU) { + rga_err("Current %s[%d] cannot support physically discontinuous virtual address!\n", + rga_get_mmu_type_str(scheduler->data->mmu), scheduler->data->mmu); + ret = -EOPNOTSUPP; + goto free_sgt; } /* @@ -601,47 +591,28 @@ static int rga_mm_map_virt_addr(struct rga_external_buffer *external_buffer, goto free_sgt; } - switch (scheduler->data->mmu) { - case RGA_IOMMU: - ret = rga_iommu_map_sgt(sgt, virt_addr->size, buffer, scheduler->dev); - if (ret < 0) { - rga_err("%s core[%d] iommu_map virtual address error!\n", - __func__, scheduler->core); - goto free_dma_buffer; - } - - buffer->dma_addr = buffer->iova; - - break; - case RGA_MMU: - ret = dma_map_sg(scheduler->dev, sgt->sgl, sgt->orig_nents, DMA_BIDIRECTIONAL); - if (ret == 0) { - rga_err("%s core[%d] dma_map_sgt error! va = 0x%lx, nents = %d\n", - __func__, scheduler->core, - (unsigned long)virt_addr->addr, sgt->orig_nents); - ret = -EINVAL; - goto free_dma_buffer; - } - break; - default: - if (mm_flag & RGA_MEM_PHYSICAL_CONTIGUOUS) - break; - - rga_err("Current %s[%d] cannot support physically discontinuous virtual address!\n", - rga_get_mmu_type_str(scheduler->data->mmu), scheduler->data->mmu); - ret = -EOPNOTSUPP; + /* + * dma-buf api needs to use default_domain of main dev, + * and not IOMMU for devices without iommu_info ptr. + */ + map_dev = scheduler->iommu_info ? scheduler->iommu_info->default_dev : scheduler->dev; + ret = rga_dma_map_sgt(sgt, buffer, DMA_BIDIRECTIONAL, map_dev); + if (ret < 0) { + rga_err("%s core[%d] rga map sgt failed! va = 0x%lx, orig_nents = %d\n", + __func__, scheduler->core, + (unsigned long)virt_addr->addr, sgt->orig_nents); goto free_dma_buffer; } - buffer->sgt = sgt; - buffer->offset = virt_addr->offset; - buffer->size = virt_addr->size; - buffer->scheduler = scheduler; + if (scheduler->data->mmu == RGA_IOMMU) + buffer->iova = buffer->dma_addr; internal_buffer->virt_addr = virt_addr; internal_buffer->dma_buffer = buffer; internal_buffer->mm_flag = mm_flag; internal_buffer->phys_addr = phys_addr ? phys_addr + virt_addr->offset : 0; + internal_buffer->size = buffer->size - buffer->offset; + internal_buffer->scheduler = scheduler; return 0; @@ -661,16 +632,12 @@ put_current_mm: static void rga_mm_unmap_phys_addr(struct rga_internal_buffer *internal_buffer) { - WARN_ON(internal_buffer->dma_buffer == NULL); + if (internal_buffer->dma_buffer != NULL) { + rga_dma_unmap_phys_addr(internal_buffer->dma_buffer); + kfree(internal_buffer->dma_buffer); + internal_buffer->dma_buffer = NULL; + } - if (rga_mm_is_invalid_dma_buffer(internal_buffer->dma_buffer)) - return; - - if (internal_buffer->dma_buffer->scheduler->data->mmu == RGA_IOMMU) - rga_iommu_unmap(internal_buffer->dma_buffer); - - kfree(internal_buffer->dma_buffer); - internal_buffer->dma_buffer = NULL; internal_buffer->phys_addr = 0; internal_buffer->size = 0; } @@ -683,7 +650,8 @@ static int rga_mm_map_phys_addr(struct rga_external_buffer *external_buffer, phys_addr_t phys_addr; int buffer_size; uint32_t mm_flag = 0; - struct rga_dma_buffer *buffer; + struct rga_dma_buffer *buffer = NULL; + struct device *map_dev; struct rga_scheduler_t *scheduler; scheduler = job ? job->scheduler : @@ -717,26 +685,34 @@ static int rga_mm_map_phys_addr(struct rga_external_buffer *external_buffer, return -EINVAL; } - buffer = kzalloc(sizeof(*buffer), GFP_KERNEL); - if (buffer == NULL) { - rga_err("%s alloc internal dma buffer error!\n", __func__); - return -ENOMEM; - } - if (scheduler->data->mmu == RGA_IOMMU) { - ret = rga_iommu_map(phys_addr, buffer_size, buffer, scheduler->dev); + buffer = kzalloc(sizeof(*buffer), GFP_KERNEL); + if (buffer == NULL) { + rga_err("%s alloc internal dma buffer error!\n", __func__); + return -ENOMEM; + } + + /* + * dma-buf api needs to use default_domain of main dev, + * and not IOMMU for devices without iommu_info ptr. + */ + map_dev = scheduler->iommu_info ? + scheduler->iommu_info->default_dev : scheduler->dev; + ret = rga_dma_map_phys_addr(phys_addr, buffer_size, buffer, + DMA_BIDIRECTIONAL, map_dev); if (ret < 0) { rga_err("%s core[%d] map phys_addr error!\n", __func__, scheduler->core); goto free_dma_buffer; } + + buffer->iova = buffer->dma_addr; } - buffer->scheduler = scheduler; - - internal_buffer->phys_addr = phys_addr; - internal_buffer->size = buffer_size; - internal_buffer->mm_flag = mm_flag; internal_buffer->dma_buffer = buffer; + internal_buffer->mm_flag = mm_flag; + internal_buffer->phys_addr = phys_addr; + internal_buffer->size = buffer ? buffer->size : buffer_size; + internal_buffer->scheduler = scheduler; return 0; @@ -785,8 +761,6 @@ static int rga_mm_map_buffer(struct rga_external_buffer *external_buffer, if (ret < 0) return ret; - internal_buffer->size = internal_buffer->dma_buffer->size - - internal_buffer->dma_buffer->offset; internal_buffer->mm_flag |= RGA_MEM_NEED_USE_IOMMU; break; case RGA_VIRTUAL_ADDRESS: @@ -796,8 +770,6 @@ static int rga_mm_map_buffer(struct rga_external_buffer *external_buffer, if (ret < 0) return ret; - internal_buffer->size = internal_buffer->virt_addr->size - - internal_buffer->virt_addr->offset; internal_buffer->mm_flag |= RGA_MEM_NEED_USE_IOMMU; break; case RGA_PHYSICAL_ADDRESS: @@ -1002,7 +974,7 @@ void rga_mm_dump_buffer(struct rga_internal_buffer *dump_buffer) (unsigned long)dump_buffer->dma_buffer->offset, dump_buffer->dma_buffer->sgt, dump_buffer->dma_buffer->size, - dump_buffer->dma_buffer->scheduler->core); + dump_buffer->scheduler->core); if (dump_buffer->mm_flag & RGA_MEM_PHYSICAL_CONTIGUOUS) rga_log("is contiguous, pa = 0x%lx\n", @@ -1026,7 +998,7 @@ void rga_mm_dump_buffer(struct rga_internal_buffer *dump_buffer) (unsigned long)dump_buffer->dma_buffer->offset, dump_buffer->dma_buffer->sgt, dump_buffer->dma_buffer->size, - dump_buffer->dma_buffer->scheduler->core); + dump_buffer->scheduler->core); if (dump_buffer->mm_flag & RGA_MEM_PHYSICAL_CONTIGUOUS) rga_buf_log(dump_buffer, "is contiguous, pa = 0x%lx\n", @@ -1034,6 +1006,16 @@ void rga_mm_dump_buffer(struct rga_internal_buffer *dump_buffer) break; case RGA_PHYSICAL_ADDRESS: rga_buf_log(dump_buffer, "pa = 0x%lx\n", (unsigned long)dump_buffer->phys_addr); + + if (rga_mm_is_invalid_dma_buffer(dump_buffer->dma_buffer)) + break; + + rga_buf_log(dump_buffer, "iova = 0x%lx, dma_addr = 0x%lx, offset = 0x%lx, size = %ld, map_core = 0x%x\n", + (unsigned long)dump_buffer->dma_buffer->iova, + (unsigned long)dump_buffer->dma_buffer->dma_addr, + (unsigned long)dump_buffer->dma_buffer->offset, + dump_buffer->dma_buffer->size, + dump_buffer->scheduler->core); break; default: rga_buf_err(dump_buffer, "Illegal buffer! type= %d\n", dump_buffer->type); @@ -1129,7 +1111,7 @@ static int rga_mm_sgt_to_page_table(struct sg_table *sg, * The length of each sgl is expected to be obtained here, not * the length of the entire dma_buf, so sg_dma_len() is not used. */ - len = sgl->length >> PAGE_SHIFT; + len = (sgl->length + (PAGE_SIZE - 1)) >> PAGE_SHIFT; if (use_dma_address) /* @@ -1148,6 +1130,8 @@ static int rga_mm_sgt_to_page_table(struct sg_table *sg, else Address = sg_phys(sgl); + Address &= PAGE_MASK; + for (i = 0; i < len; i++) { if (mapped_size + i >= pageCount) { break_flag = 1; @@ -1335,16 +1319,26 @@ static int rga_mm_sync_dma_sg_for_device(struct rga_internal_buffer *buffer, struct rga_scheduler_t *scheduler; ktime_t timestamp = ktime_get(); - scheduler = buffer->dma_buffer->scheduler; + scheduler = buffer->scheduler; if (scheduler == NULL) { rga_job_err(job, "%s(%d), failed to get scheduler, core = 0x%x\n", __func__, __LINE__, job->core); return -EFAULT; } - if (buffer->mm_flag & RGA_MEM_PHYSICAL_CONTIGUOUS && - scheduler->data->mmu != RGA_IOMMU) { - dma_sync_single_for_device(scheduler->dev, buffer->phys_addr, buffer->size, dir); + if (buffer->mm_flag & RGA_MEM_PHYSICAL_CONTIGUOUS) { + if (scheduler->data->mmu == RGA_IOMMU) { + if (rga_mm_is_invalid_dma_buffer(buffer->dma_buffer)) { + rga_job_err(job, "invalid dma-buffer with IOMMU device!\n"); + return -EFAULT; + } + + dma_sync_single_for_device(buffer->dma_buffer->map_dev, + buffer->dma_buffer->iova, buffer->dma_buffer->size, dir); + } else { + dma_sync_single_for_device(scheduler->dev, + buffer->phys_addr, buffer->size, dir); + } } else { sgt = rga_mm_lookup_sgt(buffer); if (sgt == NULL) { @@ -1372,16 +1366,26 @@ static int rga_mm_sync_dma_sg_for_cpu(struct rga_internal_buffer *buffer, struct rga_scheduler_t *scheduler; ktime_t timestamp = ktime_get(); - scheduler = buffer->dma_buffer->scheduler; + scheduler = buffer->scheduler; if (scheduler == NULL) { rga_job_err(job, "%s(%d), failed to get scheduler, core = 0x%x\n", __func__, __LINE__, job->core); return -EFAULT; } - if (buffer->mm_flag & RGA_MEM_PHYSICAL_CONTIGUOUS && - scheduler->data->mmu != RGA_IOMMU) { - dma_sync_single_for_cpu(scheduler->dev, buffer->phys_addr, buffer->size, dir); + if (buffer->mm_flag & RGA_MEM_PHYSICAL_CONTIGUOUS) { + if (scheduler->data->mmu == RGA_IOMMU) { + if (rga_mm_is_invalid_dma_buffer(buffer->dma_buffer)) { + rga_job_err(job, "invalid dma-buffer with IOMMU device!\n"); + return -EFAULT; + } + + dma_sync_single_for_cpu(buffer->dma_buffer->map_dev, + buffer->dma_buffer->iova, buffer->dma_buffer->size, dir); + } else { + dma_sync_single_for_cpu(scheduler->dev, + buffer->phys_addr, buffer->size, dir); + } } else { sgt = rga_mm_lookup_sgt(buffer); if (sgt == NULL) {