From ea5b730b650ba83b0a6e07029bd2bf24979aec4e Mon Sep 17 00:00:00 2001 From: Zhichao Guo Date: Thu, 27 Apr 2023 10:02:40 +0800 Subject: [PATCH 001/223] ARM: dts: rockchip: rv1106g-evb1-v11: Add vdd_arm changes Modify the micorvolt of vdd_arm to support the new hardware. Signed-off-by: Zhichao Guo Change-Id: Id4e102c0a72898c27e0f2547e08c5d5095edfb76 --- arch/arm/boot/dts/rv1106g-evb1-v11.dts | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/arch/arm/boot/dts/rv1106g-evb1-v11.dts b/arch/arm/boot/dts/rv1106g-evb1-v11.dts index da292aa7b804..00faf0588980 100644 --- a/arch/arm/boot/dts/rv1106g-evb1-v11.dts +++ b/arch/arm/boot/dts/rv1106g-evb1-v11.dts @@ -37,3 +37,9 @@ &usbdrd_dwc3 { dr_mode = "peripheral"; }; + +&vdd_arm { + regulator-min-microvolt = <800000>; + regulator-max-microvolt = <1000000>; + regulator-init-microvolt = <900000>; +}; From c23e3b088dc112d8a9e69b2e7d8d7baebfc7b13d Mon Sep 17 00:00:00 2001 From: Sugar Zhang Date: Tue, 10 Jan 2023 18:39:13 +0800 Subject: [PATCH 002/223] ASoC: dummy_codec: Add support for more capabilities * Support 8-bits width * Support Mono channel * Support up to 384k samplerate Signed-off-by: Sugar Zhang Change-Id: I9f1c10bad2bfb9a3beee1dd91508158e79da2492 --- sound/soc/codecs/dummy-codec.c | 14 ++++++++------ 1 file changed, 8 insertions(+), 6 deletions(-) diff --git a/sound/soc/codecs/dummy-codec.c b/sound/soc/codecs/dummy-codec.c index 35756c753357..2cb3ae65d4f7 100644 --- a/sound/soc/codecs/dummy-codec.c +++ b/sound/soc/codecs/dummy-codec.c @@ -48,20 +48,22 @@ struct snd_soc_dai_driver dummy_dai = { .name = "dummy_codec", .playback = { .stream_name = "Dummy Playback", - .channels_min = 2, + .channels_min = 1, .channels_max = 384, - .rates = SNDRV_PCM_RATE_8000_192000, - .formats = (SNDRV_PCM_FMTBIT_S16_LE | + .rates = SNDRV_PCM_RATE_8000_384000, + .formats = (SNDRV_PCM_FMTBIT_S8 | + SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S20_3LE | SNDRV_PCM_FMTBIT_S24_LE | SNDRV_PCM_FMTBIT_S32_LE), }, .capture = { .stream_name = "Dummy Capture", - .channels_min = 2, + .channels_min = 1, .channels_max = 384, - .rates = SNDRV_PCM_RATE_8000_192000, - .formats = (SNDRV_PCM_FMTBIT_S16_LE | + .rates = SNDRV_PCM_RATE_8000_384000, + .formats = (SNDRV_PCM_FMTBIT_S8 | + SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S20_3LE | SNDRV_PCM_FMTBIT_S24_LE | SNDRV_PCM_FMTBIT_S32_LE), From 0ee19616d579df908f0d0a752aeac16e0b7bf5b8 Mon Sep 17 00:00:00 2001 From: Sugar Zhang Date: Mon, 24 Apr 2023 18:46:34 +0800 Subject: [PATCH 003/223] ASoC: rockchip: sai: Fix Master / Slave Mode Switch Signed-off-by: Sugar Zhang Change-Id: Ia9dcf0c52de6a4d4487bdc02601ad9b546e8e435 --- sound/soc/rockchip/rockchip_sai.c | 65 +++++++++++++++++++++++++++++-- 1 file changed, 62 insertions(+), 3 deletions(-) diff --git a/sound/soc/rockchip/rockchip_sai.c b/sound/soc/rockchip/rockchip_sai.c index e6f25b5a44df..f14afd95a148 100644 --- a/sound/soc/rockchip/rockchip_sai.c +++ b/sound/soc/rockchip/rockchip_sai.c @@ -792,7 +792,7 @@ static const char * const mono_text[] = { "Disable", "Enable" }; static DECLARE_TLV_DB_SCALE(rmss_tlv, 0, 128, 0); -static const char * const mss_text[] = { "Master", "Slave" }; +static const char * const mss_text[] = { "Slave", "Master" }; static const char * const ckp_text[] = { "Normal", "Inverted" }; @@ -839,7 +839,8 @@ static SOC_ENUM_SINGLE_DECL(rmono_switch, SAI_MONO_CR, 1, mono_text); static SOC_ENUM_SINGLE_DECL(tmono_switch, SAI_MONO_CR, 0, mono_text); /* CKR */ -static SOC_ENUM_SINGLE_DECL(mss_switch, SAI_CKR, 2, mss_text); +static const struct soc_enum mss_switch = + SOC_ENUM_SINGLE_EXT(ARRAY_SIZE(mss_text), mss_text); static SOC_ENUM_SINGLE_DECL(sp_switch, SAI_CKR, 1, ckp_text); static SOC_ENUM_SINGLE_DECL(fp_switch, SAI_CKR, 0, ckp_text); @@ -970,6 +971,61 @@ static int rockchip_sai_rx_lanes_put(struct snd_kcontrol *kcontrol, return 1; } +static int rockchip_sai_mss_get(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct snd_soc_component *component = snd_soc_kcontrol_component(kcontrol); + struct rk_sai_dev *sai = snd_soc_component_get_drvdata(component); + + ucontrol->value.enumerated.item[0] = sai->is_master_mode; + + return 0; +} + +static int rockchip_sai_mss_put(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct snd_soc_component *component = snd_soc_kcontrol_component(kcontrol); + struct rk_sai_dev *sai = snd_soc_component_get_drvdata(component); + bool mss; + + /* MUST: do not update mode while stream is running */ + if (snd_soc_component_active(component)) + return -EPERM; + + mss = !!ucontrol->value.enumerated.item[0]; + if (mss == sai->is_master_mode) + return 0; + + sai->is_master_mode = mss; + + pm_runtime_get_sync(sai->dev); + if (sai->is_master_mode) { + /* Switch from Slave to Master */ + regmap_update_bits(sai->regmap, SAI_CKR, + SAI_CKR_MSS_MASK, + SAI_CKR_MSS_MASTER); + regmap_update_bits(sai->regmap, SAI_XFER, + SAI_XFER_CLK_MASK | + SAI_XFER_FSS_MASK, + SAI_XFER_CLK_EN | + SAI_XFER_FSS_EN); + } else { + /* Switch from Master to Slave */ + regmap_update_bits(sai->regmap, SAI_CKR, + SAI_CKR_MSS_MASK, + SAI_CKR_MSS_SLAVE); + regmap_update_bits(sai->regmap, SAI_XFER, + SAI_XFER_CLK_MASK | + SAI_XFER_FSS_MASK, + SAI_XFER_CLK_DIS | + SAI_XFER_FSS_DIS); + } + pm_runtime_put(sai->dev); + + return 1; +} + static DECLARE_TLV_DB_SCALE(fs_shift_tlv, 0, 8192, 0); static const struct snd_kcontrol_new rockchip_sai_controls[] = { @@ -1001,7 +1057,8 @@ static const struct snd_kcontrol_new rockchip_sai_controls[] = { SOC_ENUM("Receive Mono Switch", rmono_switch), SOC_ENUM("Transmit Mono Switch", tmono_switch), - SOC_ENUM("Master / Slave Mode Select", mss_switch), + SOC_ENUM_EXT("Master / Slave Mode Select", mss_switch, + rockchip_sai_mss_get, rockchip_sai_mss_put), SOC_ENUM("Sclk Polarity", sp_switch), SOC_ENUM("Frame Sync Polarity", fp_switch), @@ -1079,6 +1136,8 @@ static int rockchip_sai_probe(struct platform_device *pdev) sai->dev = &pdev->dev; sai->fw_ratio = 1; + /* match to register default */ + sai->is_master_mode = true; dev_set_drvdata(&pdev->dev, sai); sai->rst_h = devm_reset_control_get_optional_exclusive(&pdev->dev, "h"); From c961c5bb561e3cd313e786f54e35304741f140ea Mon Sep 17 00:00:00 2001 From: Sugar Zhang Date: Mon, 24 Apr 2023 19:08:52 +0800 Subject: [PATCH 004/223] ASoC: rockchip: sai: Add support for Clk-Auto Switch This patch add support for Clk-Auto Switch. Signed-off-by: Sugar Zhang Change-Id: I2d3b10fcf4cc55ba005d1c9da1049190882f7494 --- sound/soc/rockchip/rockchip_sai.c | 35 ++++++++++++++++++++++++++++++- 1 file changed, 34 insertions(+), 1 deletion(-) diff --git a/sound/soc/rockchip/rockchip_sai.c b/sound/soc/rockchip/rockchip_sai.c index f14afd95a148..ac5c4f69de33 100644 --- a/sound/soc/rockchip/rockchip_sai.c +++ b/sound/soc/rockchip/rockchip_sai.c @@ -50,6 +50,7 @@ struct rk_sai_dev { bool has_playback; bool is_master_mode; bool is_tdm; + bool is_clk_auto; }; static int sai_runtime_suspend(struct device *dev) @@ -460,6 +461,8 @@ static int rockchip_sai_hw_params(struct snd_pcm_substream *substream, if (sai->is_master_mode) { bclk_rate = sai->fw_ratio * slot_width * ch_per_lane * params_rate(params); + if (sai->is_clk_auto) + clk_set_rate(sai->mclk, bclk_rate); mclk_rate = clk_get_rate(sai->mclk); if (mclk_rate < bclk_rate) { dev_err(sai->dev, "Mismatch mclk: %u, expected %u at least\n", @@ -507,7 +510,7 @@ static int rockchip_sai_set_sysclk(struct snd_soc_dai *dai, int clk_id, struct rk_sai_dev *sai = snd_soc_dai_get_drvdata(dai); int ret; - if (!freq) + if (!freq || sai->is_clk_auto) return 0; ret = clk_set_rate(sai->mclk, freq); @@ -1026,6 +1029,32 @@ static int rockchip_sai_mss_put(struct snd_kcontrol *kcontrol, return 1; } +static int rockchip_sai_clk_auto_get(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct snd_soc_component *component = snd_soc_kcontrol_component(kcontrol); + struct rk_sai_dev *sai = snd_soc_component_get_drvdata(component); + + ucontrol->value.integer.value[0] = sai->is_clk_auto; + + return 0; +} + +static int rockchip_sai_clk_auto_put(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct snd_soc_component *component = snd_soc_kcontrol_component(kcontrol); + struct rk_sai_dev *sai = snd_soc_component_get_drvdata(component); + bool clk_auto = ucontrol->value.integer.value[0]; + + if (clk_auto == sai->is_clk_auto) + return 0; + + sai->is_clk_auto = clk_auto; + + return 1; +} + static DECLARE_TLV_DB_SCALE(fs_shift_tlv, 0, 8192, 0); static const struct snd_kcontrol_new rockchip_sai_controls[] = { @@ -1085,6 +1114,10 @@ static const struct snd_kcontrol_new rockchip_sai_controls[] = { 0, 8192, 0, fs_shift_tlv), SOC_SINGLE_TLV("Receive Frame Shift Select", SAI_RX_SHIFT, 0, 8192, 0, fs_shift_tlv), + + SOC_SINGLE_BOOL_EXT("Clk Auto Switch", 0, + rockchip_sai_clk_auto_get, + rockchip_sai_clk_auto_put), }; static const struct snd_soc_component_driver rockchip_sai_component = { From c6977c7aacda5d689527ea8318a369eac8e738fe Mon Sep 17 00:00:00 2001 From: Sugar Zhang Date: Thu, 4 May 2023 10:33:44 +0800 Subject: [PATCH 005/223] ASoC: rockchip: sai: Remove the space prefix for SBW Signed-off-by: Sugar Zhang Change-Id: I78ca99a10c2461f80e0c2ad7062bbfc0de3b6590 --- sound/soc/rockchip/rockchip_sai.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/sound/soc/rockchip/rockchip_sai.c b/sound/soc/rockchip/rockchip_sai.c index ac5c4f69de33..729778676f84 100644 --- a/sound/soc/rockchip/rockchip_sai.c +++ b/sound/soc/rockchip/rockchip_sai.c @@ -786,8 +786,8 @@ static const char * const fbm_text[] = { "MSB", "LSB" }; static const char * const vdj_text[] = { "Right J", "Left J" }; static const char * const sbw_text[] = { - " 0", " 0", " 0", " 0", " 0", " 0", " 0", " 8", - " 9", "10", "11", "12", "13", "14", "15", "16", + "0", "0", "0", "0", "0", "0", "0", "8", + "9", "10", "11", "12", "13", "14", "15", "16", "17", "18", "19", "20", "21", "22", "23", "24", "25", "26", "27", "28", "29", "30", "31", "32", }; From 8cc161a8e13cac022beade78c95a1c866ca351e7 Mon Sep 17 00:00:00 2001 From: Yandong Lin Date: Wed, 26 Apr 2023 21:02:42 +0800 Subject: [PATCH 006/223] video: rockchip: mpp: stop vepu2 before reset In some platform, can not do pmu_idle_request before cru reset. Resetting without pmu_idle_request while the hw is running will result in a bus err. So stop hw first before cru reset to prevent the issue. Signed-off-by: Yandong Lin Change-Id: I62ace147a0d72adb774fed989b34c7bf22af48ac --- drivers/video/rockchip/mpp/mpp_vepu2.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/drivers/video/rockchip/mpp/mpp_vepu2.c b/drivers/video/rockchip/mpp/mpp_vepu2.c index f736ff2150c5..12aef5ebe75b 100644 --- a/drivers/video/rockchip/mpp/mpp_vepu2.c +++ b/drivers/video/rockchip/mpp/mpp_vepu2.c @@ -863,6 +863,8 @@ static int vepu_reset(struct mpp_dev *mpp) struct vepu_dev *enc = to_vepu_dev(mpp); struct vepu_ccu *ccu = enc->ccu; + mpp_write(mpp, VEPU2_REG_ENC_EN, 0); + udelay(5); if (enc->rst_a && enc->rst_h) { /* Don't skip this or iommu won't work after reset */ mpp_pmu_idle_request(mpp, true); From 49bf5942cf4c5f39642b2cba81566d3b0da48dfa Mon Sep 17 00:00:00 2001 From: Yandong Lin Date: Fri, 28 Apr 2023 10:37:03 +0800 Subject: [PATCH 007/223] video: rockchip: mpp: fix dule-core synergy stuck issue There is a issue of stuck during dual-core collabration, and the hw timeout count will be blocked by default, and only soft timeout can be triggered to exit. However, the soft timeout is too loog, so config reg to not mask the hw timeout. Signed-off-by: Yandong Lin Change-Id: If801b8ba3b463094ea497fae829f772de7ade382 --- drivers/video/rockchip/mpp/mpp_rkvdec2_link.c | 43 ++++++++++--------- 1 file changed, 23 insertions(+), 20 deletions(-) diff --git a/drivers/video/rockchip/mpp/mpp_rkvdec2_link.c b/drivers/video/rockchip/mpp/mpp_rkvdec2_link.c index fcb3ae1659d9..f3b36e06a93d 100644 --- a/drivers/video/rockchip/mpp/mpp_rkvdec2_link.c +++ b/drivers/video/rockchip/mpp/mpp_rkvdec2_link.c @@ -1301,6 +1301,25 @@ void rkvdec2_link_session_deinit(struct mpp_session *session) mpp_debug_leave(); } +#define RKVDEC2_1080P_PIXELS (1920*1080) +#define RKVDEC2_4K_PIXELS (4096*2304) +#define RKVDEC2_8K_PIXELS (7680*4320) +#define RKVDEC2_CCU_TIMEOUT_20MS (0xefffff) +#define RKVDEC2_CCU_TIMEOUT_50MS (0x2cfffff) +#define RKVDEC2_CCU_TIMEOUT_100MS (0x4ffffff) + +static u32 rkvdec2_ccu_get_timeout_threshold(struct rkvdec2_task *task) +{ + u32 pixels = task->pixels; + + if (pixels < RKVDEC2_1080P_PIXELS) + return RKVDEC2_CCU_TIMEOUT_20MS; + else if (pixels < RKVDEC2_4K_PIXELS) + return RKVDEC2_CCU_TIMEOUT_50MS; + else + return RKVDEC2_CCU_TIMEOUT_100MS; +} + int rkvdec2_attach_ccu(struct device *dev, struct rkvdec2_dev *dec) { int ret; @@ -1732,6 +1751,9 @@ static int rkvdec2_soft_ccu_enqueue(struct mpp_dev *mpp, struct mpp_task *mpp_ta mpp_write_relaxed(mpp, RKVDEC_REG_CLR_CACHE2_BASE, 1); mpp_iommu_flush_tlb(mpp->iommu_info); + /* disable multicore pu/colmv offset req timeout reset */ + task->reg[RKVDEC_REG_EN_MODE_SET] |= BIT(1); + task->reg[RKVDEC_REG_TIMEOUT_THRESHOLD] = rkvdec2_ccu_get_timeout_threshold(task); /* set registers for hardware */ reg_en = mpp_task->hw_info->reg_en; for (i = 0; i < task->w_req_cnt; i++) { @@ -2175,25 +2197,6 @@ static int rkvdec2_hard_ccu_reset(struct mpp_taskqueue *queue, struct rkvdec2_cc return 0; } -#define RKVDEC2_1080P_PIXELS (1920*1080) -#define RKVDEC2_4K_PIXELS (4096*2304) -#define RKVDEC2_8K_PIXELS (7680*4320) -#define RKVDEC2_TIMEOUT_20MS (0xefffff) -#define RKVDEC2_TIMEOUT_50MS (0x2cfffff) -#define RKVDEC2_TIMEOUT_100MS (0x4ffffff) - -static u32 rkvdec2_get_timeout_threshold(struct rkvdec2_task *task) -{ - u32 pixels = task->pixels; - - if (pixels < RKVDEC2_1080P_PIXELS) - return RKVDEC2_TIMEOUT_20MS; - else if (pixels < RKVDEC2_4K_PIXELS) - return RKVDEC2_TIMEOUT_50MS; - else - return RKVDEC2_TIMEOUT_100MS; -} - static struct mpp_task * rkvdec2_hard_ccu_prepare(struct mpp_task *mpp_task, struct rkvdec2_ccu *ccu, struct rkvdec_link_info *hw) @@ -2235,7 +2238,7 @@ rkvdec2_hard_ccu_prepare(struct mpp_task *mpp_task, /* disable multicore pu/colmv offset req timeout reset */ task->reg[RKVDEC_REG_EN_MODE_SET] |= BIT(1); - task->reg[RKVDEC_REG_TIMEOUT_THRESHOLD] = rkvdec2_get_timeout_threshold(task); + task->reg[RKVDEC_REG_TIMEOUT_THRESHOLD] = rkvdec2_ccu_get_timeout_threshold(task); for (i = 0; i < hw->part_w_num; i++) { off = part[i].tb_reg_off; From 54b0bc7bac9ebd548fe8155f99f823fa56edc336 Mon Sep 17 00:00:00 2001 From: Sugar Zhang Date: Tue, 28 Mar 2023 22:15:51 +0800 Subject: [PATCH 008/223] ASoC: rockchip: sai: Add support for CLK-ALWAYS-ON quirks This patch add support for keeping BCLK / FSYNC always on. it's required by some devices, such as HDMI, PA, etc. For example: on HDMI situation There are some TVs require maintaining N/CTS packets or AUDS packets to keep audio logic active, otherwise, the first tone may be lost. In order to optimize the user experience, we need to ensure continuous transmission of N/CTS and AUDS packets from the HDMI-TX, so that the SINK TV devices can maintain audio logic activation, promptly process audio data, and achieve the completeness of the first tone. We init a 48k I2S-STANDARD clock timing as default. Change-Id: I298b0ad2d53bdc41927f567c2af481f2a0bd5422 Signed-off-by: Sugar Zhang --- sound/soc/rockchip/rockchip_sai.c | 62 +++++++++++++++++++++++++++++++ 1 file changed, 62 insertions(+) diff --git a/sound/soc/rockchip/rockchip_sai.c b/sound/soc/rockchip/rockchip_sai.c index 729778676f84..ac63cb110221 100644 --- a/sound/soc/rockchip/rockchip_sai.c +++ b/sound/soc/rockchip/rockchip_sai.c @@ -26,6 +26,9 @@ #define FW_RATIO_MIN 1 #define MAXBURST_PER_FIFO 8 +#define DEFAULT_FS 48000 +#define QUIRK_ALWAYS_ON BIT(0) + enum fpw_mode { FPW_ONE_BCLK_WIDTH, FPW_ONE_SLOT_WIDTH, @@ -44,6 +47,7 @@ struct rk_sai_dev { struct snd_pcm_substream *substreams[SNDRV_PCM_STREAM_LAST + 1]; unsigned int tx_lanes; unsigned int rx_lanes; + unsigned int quirks; enum fpw_mode fpw; int fw_ratio; bool has_capture; @@ -53,6 +57,16 @@ struct rk_sai_dev { bool is_clk_auto; }; +static const struct sai_of_quirks { + char *quirk; + int id; +} of_quirks[] = { + { + .quirk = "rockchip,always-on", + .id = QUIRK_ALWAYS_ON, + }, +}; + static int sai_runtime_suspend(struct device *dev) { struct rk_sai_dev *sai = dev_get_drvdata(dev); @@ -1154,6 +1168,50 @@ static irqreturn_t rockchip_sai_isr(int irq, void *devid) return IRQ_HANDLED; } +static int rockchip_sai_keep_clk_always_on(struct rk_sai_dev *sai) +{ + unsigned int mclk_rate, bclk_rate, div_bclk; + + sai->is_master_mode = true; + + /* init I2S fmt default */ + rockchip_sai_fmt_create(sai, SND_SOC_DAIFMT_I2S); + + regmap_update_bits(sai->regmap, SAI_FSCR, + SAI_FSCR_FW_MASK | + SAI_FSCR_FPW_MASK, + SAI_FSCR_FW(64) | + SAI_FSCR_FPW(32)); + + mclk_rate = clk_get_rate(sai->mclk); + bclk_rate = DEFAULT_FS * 64; + div_bclk = DIV_ROUND_CLOSEST(mclk_rate, bclk_rate); + + regmap_update_bits(sai->regmap, SAI_CKR, SAI_CKR_MDIV_MASK, + SAI_CKR_MDIV(div_bclk)); + + pm_runtime_forbid(sai->dev); + + dev_info(sai->dev, "CLK-ALWAYS-ON: mclk: %d, bclk: %d, fsync: %d\n", + mclk_rate, bclk_rate, DEFAULT_FS); + + return 0; +} + +static int rockchip_sai_parse_quirks(struct rk_sai_dev *sai) +{ + int ret = 0, i = 0; + + for (i = 0; i < ARRAY_SIZE(of_quirks); i++) + if (device_property_read_bool(sai->dev, of_quirks[i].quirk)) + sai->quirks |= of_quirks[i].id; + + if (sai->quirks & QUIRK_ALWAYS_ON) + ret = rockchip_sai_keep_clk_always_on(sai); + + return ret; +} + static int rockchip_sai_probe(struct platform_device *pdev) { struct device_node *node = pdev->dev.of_node; @@ -1212,6 +1270,10 @@ static int rockchip_sai_probe(struct platform_device *pdev) return PTR_ERR(sai->hclk); } + ret = rockchip_sai_parse_quirks(sai); + if (ret) + return ret; + pm_runtime_enable(&pdev->dev); if (!pm_runtime_enabled(&pdev->dev)) { ret = sai_runtime_resume(&pdev->dev); From 2d2b53637edbb567af50754d407ca419826e47ba Mon Sep 17 00:00:00 2001 From: Sugar Zhang Date: Thu, 20 Apr 2023 16:31:30 +0800 Subject: [PATCH 009/223] ASoC: rockchip: sai: Add support for Multi-DAIs This patch add property 'rockchip,no-dmaengine' to support register DAI without PCM, and it's usually used for Multi-DAIs which combine DAIs into a union one. Change-Id: I4e0da8fae2c692601e05118442218de0f7b4efee Signed-off-by: Sugar Zhang --- sound/soc/rockchip/rockchip_sai.c | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/sound/soc/rockchip/rockchip_sai.c b/sound/soc/rockchip/rockchip_sai.c index ac63cb110221..57c9ff1a7136 100644 --- a/sound/soc/rockchip/rockchip_sai.c +++ b/sound/soc/rockchip/rockchip_sai.c @@ -1291,6 +1291,11 @@ static int rockchip_sai_probe(struct platform_device *pdev) if (ret) goto err_runtime_suspend; + if (device_property_read_bool(&pdev->dev, "rockchip,no-dmaengine")) { + dev_info(&pdev->dev, "Used for Multi-DAI\n"); + return 0; + } + ret = devm_snd_dmaengine_pcm_register(&pdev->dev, NULL, 0); if (ret) goto err_runtime_suspend; From 3300cecb864233d370731dd1a3cc94b9835ed5f1 Mon Sep 17 00:00:00 2001 From: Sugar Zhang Date: Fri, 28 Apr 2023 18:34:49 +0800 Subject: [PATCH 010/223] ASoC: rockchip: sai: Fix BCLK glitch After FS idle, should wait at least 2 BCLK cycle to make sure the CLK gate operation done, and then disable mclk. Otherwise, the BCLK is still ungated. once the mclk is enabled, there maybe a risk that a few BCLK cycle leak. especially for low speed situation, such as 8k samplerate. The best way is to use delay per samplerate, but, the max time is quite a tiny value, so, let's make it simple to use the max time. the max BCLK cycle time is: 31us @ 8K-8Bit (64K BCLK) udelay(40); Should wait for one BCLK ready after DIV and then ungate clk to achieve the clean clk. the max BCLK cycle time is: 15.6us @ 8K-8Bit (64K BCLK) udelay(20); Increase the max timeout to 1ms to fix FS idle failed. because it's not enough for 8k samplerate. rockchip-sai ff810000.sai: Failed to idle FS Signed-off-by: Sugar Zhang Change-Id: Ia9da291dd8586236bb32cc0376a6de389f2f0a40 --- sound/soc/rockchip/rockchip_sai.c | 40 +++++++++++++++++++++++++++---- 1 file changed, 36 insertions(+), 4 deletions(-) diff --git a/sound/soc/rockchip/rockchip_sai.c b/sound/soc/rockchip/rockchip_sai.c index 57c9ff1a7136..54907fd05a8b 100644 --- a/sound/soc/rockchip/rockchip_sai.c +++ b/sound/soc/rockchip/rockchip_sai.c @@ -27,6 +27,7 @@ #define MAXBURST_PER_FIFO 8 #define DEFAULT_FS 48000 +#define TIMEOUT_US 1000 #define QUIRK_ALWAYS_ON BIT(0) enum fpw_mode { @@ -81,11 +82,26 @@ static int sai_runtime_suspend(struct device *dev) SAI_XFER_FSS_DIS); ret = regmap_read_poll_timeout_atomic(sai->regmap, SAI_XFER, val, - (val & SAI_XFER_FS_IDLE), 10, 100); + (val & SAI_XFER_FS_IDLE), 10, TIMEOUT_US); if (ret < 0) dev_warn(sai->dev, "Failed to idle FS\n"); regcache_cache_only(sai->regmap, true); + /* + * After FS idle, should wait at least 2 BCLK cycle to make sure + * the CLK gate operation done, and then disable mclk. + * + * Otherwise, the BCLK is still ungated. once the mclk is enabled, + * there maybe a risk that a few BCLK cycle leak. especially for + * low speed situation, such as 8k samplerate. + * + * The best way is to use delay per samplerate, but, the max time + * is quite a tiny value, so, let's make it simple to use the max + * time. + * + * The max BCLK cycle time is: 31us @ 8K-8Bit (64K BCLK) + */ + udelay(40); clk_disable_unprepare(sai->mclk); clk_disable_unprepare(sai->hclk); @@ -111,7 +127,7 @@ static int sai_runtime_resume(struct device *dev) if (ret) goto err_regmap; - if (sai->is_master_mode) + if (sai->quirks & QUIRK_ALWAYS_ON && sai->is_master_mode) regmap_update_bits(sai->regmap, SAI_XFER, SAI_XFER_CLK_MASK | SAI_XFER_FSS_MASK, @@ -204,7 +220,7 @@ static int rockchip_sai_clear(struct rk_sai_dev *sai, unsigned int clr) regmap_update_bits(sai->regmap, SAI_CLR, clr, clr); ret = regmap_read_poll_timeout_atomic(sai->regmap, SAI_CLR, val, - !(val & clr), 10, 100); + !(val & clr), 10, TIMEOUT_US); if (ret < 0) { dev_warn(sai->dev, "Failed to clear %u\n", clr); goto reset; @@ -250,7 +266,7 @@ static void rockchip_sai_xfer_stop(struct rk_sai_dev *sai, int stream) regmap_update_bits(sai->regmap, SAI_XFER, msk, val); ret = regmap_read_poll_timeout_atomic(sai->regmap, SAI_XFER, val, - (val & idle), 10, 100); + (val & idle), 10, TIMEOUT_US); if (ret < 0) dev_warn(sai->dev, "Failed to idle stream %d\n", stream); @@ -488,6 +504,22 @@ static int rockchip_sai_hw_params(struct snd_pcm_substream *substream, regmap_update_bits(sai->regmap, SAI_CKR, SAI_CKR_MDIV_MASK, SAI_CKR_MDIV(div_bclk)); + /* + * Should wait for one BCLK ready after DIV and then ungate + * output clk to achieve the clean clk. + * + * The best way is to use delay per samplerate, but, the max time + * is quite a tiny value, so, let's make it simple to use the max + * time. + * + * The max BCLK cycle time is: 15.6us @ 8K-8Bit (64K BCLK) + */ + udelay(20); + regmap_update_bits(sai->regmap, SAI_XFER, + SAI_XFER_CLK_MASK | + SAI_XFER_FSS_MASK, + SAI_XFER_CLK_EN | + SAI_XFER_FSS_EN); } return 0; From e32b8efaef86e0d72d6f63061a9c2f75108a88bf Mon Sep 17 00:00:00 2001 From: Sugar Zhang Date: Thu, 4 May 2023 17:04:28 +0800 Subject: [PATCH 011/223] ASoC: rockchip: sai: Add support for PCM R/W Wait Time ALSA core blocks userspace for 10 seconds for PCM R/W default. Consider the situation BT-slave which acts as SLAVE mode, when BT-master offline sometime, the CLK lost, user have to wait the core timeout(10s), it's quite bad experience. This patch allows userspace to override the WAIT_TIME to recover more quickly from terminal audio stream. especially for stream which have no mechanism to detect the LINK offline. Usage: /# amixer -c 0 contents | grep Wait numid=43,iface=PCM,name='PCM Read Wait Time MS' numid=44,iface=PCM,name='PCM Write Wait Time MS' /# amixer -c 0 cset numid=43 500 numid=43,iface=PCM,name='PCM Read Wait Time MS' ; type=INTEGER,access=rw------,values=1,min=0,max=10000,step=1 : values=500 Signed-off-by: Sugar Zhang Change-Id: I73e98d54388a50672c5ed710db448cd13c0e1098 --- sound/soc/rockchip/rockchip_sai.c | 84 ++++++++++++++++++++++++++++++- 1 file changed, 82 insertions(+), 2 deletions(-) diff --git a/sound/soc/rockchip/rockchip_sai.c b/sound/soc/rockchip/rockchip_sai.c index 54907fd05a8b..0fdfba0636d3 100644 --- a/sound/soc/rockchip/rockchip_sai.c +++ b/sound/soc/rockchip/rockchip_sai.c @@ -28,6 +28,7 @@ #define DEFAULT_FS 48000 #define TIMEOUT_US 1000 +#define WAIT_TIME_MS_MAX 10000 #define QUIRK_ALWAYS_ON BIT(0) enum fpw_mode { @@ -46,6 +47,7 @@ struct rk_sai_dev { struct snd_dmaengine_dai_dma_data capture_dma_data; struct snd_dmaengine_dai_dma_data playback_dma_data; struct snd_pcm_substream *substreams[SNDRV_PCM_STREAM_LAST + 1]; + unsigned int wait_time[SNDRV_PCM_STREAM_LAST + 1]; unsigned int tx_lanes; unsigned int rx_lanes; unsigned int quirks; @@ -581,11 +583,15 @@ static int rockchip_sai_startup(struct snd_pcm_substream *substream, struct snd_soc_dai *dai) { struct rk_sai_dev *sai = snd_soc_dai_get_drvdata(dai); + int stream = substream->stream; - if (sai->substreams[substream->stream]) + if (sai->substreams[stream]) return -EBUSY; - sai->substreams[substream->stream] = substream; + if (sai->wait_time[stream]) + substream->wait_time = msecs_to_jiffies(sai->wait_time[stream]); + + sai->substreams[stream] = substream; return 0; } @@ -1101,6 +1107,73 @@ static int rockchip_sai_clk_auto_put(struct snd_kcontrol *kcontrol, return 1; } +static int rockchip_sai_wait_time_info(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_info *uinfo) +{ + uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER; + uinfo->count = 1; + uinfo->value.integer.min = 0; + uinfo->value.integer.max = WAIT_TIME_MS_MAX; + uinfo->value.integer.step = 1; + + return 0; +} + +static int rockchip_sai_rd_wait_time_get(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct snd_soc_component *component = snd_soc_kcontrol_component(kcontrol); + struct rk_sai_dev *sai = snd_soc_component_get_drvdata(component); + + ucontrol->value.integer.value[0] = sai->wait_time[SNDRV_PCM_STREAM_CAPTURE]; + + return 0; +} + +static int rockchip_sai_rd_wait_time_put(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct snd_soc_component *component = snd_soc_kcontrol_component(kcontrol); + struct rk_sai_dev *sai = snd_soc_component_get_drvdata(component); + + if (ucontrol->value.integer.value[0] > WAIT_TIME_MS_MAX) + return -EINVAL; + + sai->wait_time[SNDRV_PCM_STREAM_CAPTURE] = ucontrol->value.integer.value[0]; + + return 1; +} + +static int rockchip_sai_wr_wait_time_get(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct snd_soc_component *component = snd_soc_kcontrol_component(kcontrol); + struct rk_sai_dev *sai = snd_soc_component_get_drvdata(component); + + ucontrol->value.integer.value[0] = sai->wait_time[SNDRV_PCM_STREAM_PLAYBACK]; + + return 0; +} + +static int rockchip_sai_wr_wait_time_put(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct snd_soc_component *component = snd_soc_kcontrol_component(kcontrol); + struct rk_sai_dev *sai = snd_soc_component_get_drvdata(component); + + if (ucontrol->value.integer.value[0] > WAIT_TIME_MS_MAX) + return -EINVAL; + + sai->wait_time[SNDRV_PCM_STREAM_PLAYBACK] = ucontrol->value.integer.value[0]; + + return 1; +} + +#define SAI_PCM_WAIT_TIME(xname, xhandler_get, xhandler_put) \ +{ .iface = SNDRV_CTL_ELEM_IFACE_PCM, .name = xname, \ + .info = rockchip_sai_wait_time_info, \ + .get = xhandler_get, .put = xhandler_put } + static DECLARE_TLV_DB_SCALE(fs_shift_tlv, 0, 8192, 0); static const struct snd_kcontrol_new rockchip_sai_controls[] = { @@ -1164,6 +1237,13 @@ static const struct snd_kcontrol_new rockchip_sai_controls[] = { SOC_SINGLE_BOOL_EXT("Clk Auto Switch", 0, rockchip_sai_clk_auto_get, rockchip_sai_clk_auto_put), + + SAI_PCM_WAIT_TIME("PCM Read Wait Time MS", + rockchip_sai_rd_wait_time_get, + rockchip_sai_rd_wait_time_put), + SAI_PCM_WAIT_TIME("PCM Write Wait Time MS", + rockchip_sai_wr_wait_time_get, + rockchip_sai_wr_wait_time_put), }; static const struct snd_soc_component_driver rockchip_sai_component = { From 93eff125bf15892b986d8f5945708aff6b0152da Mon Sep 17 00:00:00 2001 From: Cai Wenzhong Date: Tue, 18 Apr 2023 16:31:56 +0800 Subject: [PATCH 012/223] media: i2c: max96712 driver update to version 1.01.00 Signed-off-by: Cai Wenzhong Change-Id: I05df8c399686a5908c2077936e24027e46a1e18b --- drivers/media/i2c/max96712.c | 145 ++++++++++++++++++++--------------- 1 file changed, 85 insertions(+), 60 deletions(-) diff --git a/drivers/media/i2c/max96712.c b/drivers/media/i2c/max96712.c index e654658dfdbb..ce69dda27b02 100644 --- a/drivers/media/i2c/max96712.c +++ b/drivers/media/i2c/max96712.c @@ -5,6 +5,7 @@ * Copyright (C) 2023 Rockchip Electronics Co., Ltd. * * V1.0.00 first version. + * V1.1.00 support Frame synchronization, stream on speed optimization. * */ @@ -31,15 +32,21 @@ #include #include -#define DRIVER_VERSION KERNEL_VERSION(1, 0x00, 0x00) +#define DRIVER_VERSION KERNEL_VERSION(1, 0x01, 0x00) #ifndef V4L2_CID_DIGITAL_GAIN #define V4L2_CID_DIGITAL_GAIN V4L2_CID_GAIN #endif +#define MAX96712_NAME "max96712" +#define MAX96712_MEDIA_BUS_FMT MEDIA_BUS_FMT_UYVY8_2X8 + +#define MAX96712_MIPI_LANES 4 +#define MAX96712_BITS_PER_SAMPLE 8 + #define MAX96712_LINK_FREQ_1000MHZ 1000000000UL /* pixel rate = link frequency * 2 * lanes / BITS_PER_SAMPLE */ -#define MAX96712_PIXEL_RATE (MAX96712_LINK_FREQ_1000MHZ * 2LL * 4LL / 8LL) +#define MAX96712_PIXEL_RATE (MAX96712_LINK_FREQ_1000MHZ * 2LL * MAX96712_MIPI_LANES / MAX96712_BITS_PER_SAMPLE) #define MAX96712_XVCLK_FREQ 25000000 #define MAX96712_CHIP_ID 0xA0 @@ -59,13 +66,10 @@ #define MAX96712_LOCK_STATE_LINK_B BIT(1) #define MAX96712_LOCK_STATE_LINK_C BIT(2) #define MAX96712_LOCK_STATE_LINK_D BIT(3) -#define MAX96712_LOCK_STATE_MASK 0x0F /*0x01: Link A, 0x0F: Link A/B/C/D */ +#define MAX96712_LOCK_STATE_MASK 0x0F /* 0x01: Link A, 0x0F: Link A/B/C/D */ #define REG_NULL 0xFFFF -#define MAX96712_LANES 4 -#define MAX96712_BITS_PER_SAMPLE 8 - #define OF_CAMERA_PINCTRL_STATE_DEFAULT "rockchip,camera_default" #define OF_CAMERA_PINCTRL_STATE_SLEEP "rockchip,camera_sleep" @@ -73,11 +77,9 @@ #define MAX96712_REG_VALUE_16BIT 2 #define MAX96712_REG_VALUE_24BIT 3 -#define MAX96712_NAME "max96712" -#define MAX96712_MEDIA_BUS_FMT MEDIA_BUS_FMT_UYVY8_2X8 - #define MAX96712_I2C_ADDR (0x29) #define MAX96717_I2C_ADDR (0x40) +#define CAMERA_I2C_ADDR (0x30) #define MAX96712_GET_BIT(x, bit) ((x & (1 << bit)) >> bit) #define MAX96712_GET_BIT_M_TO_N(x, m, n) \ @@ -171,8 +173,8 @@ static const struct regval max96712_mipi_1920x1440_30fps[] = { { 0x29, 0x1645, 0x00, 0x00 }, // Disable SSC { 0x29, 0x1745, 0x00, 0x0a }, // Disable SSC // Video Pipe Selection - { 0x29, 0x00F0, 0x62, 0x00 }, // GMSL2 Phy A -> Pipe Z -> Pipe 0 ; GMSL2 Phy B -> Pipe Z -> Pipe 1 - { 0x29, 0x00F1, 0xea, 0x00 }, // GMSL2 Phy C -> Pipe Z -> Pipe 2 ; GMSL2 Phy D -> Pipe Z -> Pipe 3 + { 0x29, 0x00F0, 0x62, 0x00 }, // GMSL2 Phy A -> Pipe Z -> Pipe 0; GMSL2 Phy B -> Pipe Z -> Pipe 1 + { 0x29, 0x00F1, 0xea, 0x00 }, // GMSL2 Phy C -> Pipe Z -> Pipe 2; GMSL2 Phy D -> Pipe Z -> Pipe 3 { 0x29, 0x00F4, 0x0f, 0x00 }, // Enable all 4 Pipes // Send YUV422, FS, and FE from Pipe 0 to Controller 1 { 0x29, 0x090B, 0x07, 0x00 }, // Enable 0/1/2 SRC/DST Mappings @@ -215,7 +217,7 @@ static const struct regval max96712_mipi_1920x1440_30fps[] = { { 0x29, 0x09D1, 0x01, 0x00 }, // SRC2 VC = 0, DT = Frame End { 0x29, 0x09D2, 0xc1, 0x00 }, // DST2 VC = 3, DT = Frame End // MIPI PHY Setting - { 0x29, 0x08A0, 0x24, 0x00 }, // force_clk0_en: DPHY0 enabled as clock, MIPI PHY Mode: 2x4 mode + { 0x29, 0x08A0, 0x24, 0x00 }, // DPHY0 enabled as clock, MIPI PHY Mode: 2x4 mode // Set Lane Mapping for 4-lane port A { 0x29, 0x08A3, 0xe4, 0x00 }, // PHY1 D1->D3, D0->D2; PHY0 D1->D1, D0->D0 // Set 4 lane D-PHY, 2bit VC @@ -235,15 +237,6 @@ static const struct regval max96712_mipi_1920x1440_30fps[] = { // Release reset to DPLL (config_soft_rst_n = 1) { 0x29, 0x1C00, 0xf5, 0x00 }, { 0x29, 0x1D00, 0xf5, 0x00 }, - // Frame Synchronization (FSYNC) - { 0x29, 0x04A2, 0x00, 0x00 }, // Master link Video 0 for frame sync generation - { 0x29, 0x04AA, 0x00, 0x00 }, // Disable Vsync-Fsync overlap window - { 0x29, 0x04AB, 0x00, 0x00 }, // Disable Vsync-Fsync overlap window - { 0x29, 0x04A7, 0x0c, 0x00 }, // FSYNC_PERIOD_H, Set FSYNC period to 25M/30 clock cycles. PCLK = 25MHz. Sync freq = 30Hz - { 0x29, 0x04A6, 0xb7, 0x00 }, // FSYNC_PERIOD_M - { 0x29, 0x04A5, 0x35, 0x00 }, // FSYNC_PERIOD_L - { 0x29, 0x04AF, 0xcf, 0x00 }, // FSYNC is GMSL2 type, use osc for fsync, include all links/pipes in fsync gen - { 0x29, 0x04A0, 0x02, 0x00 }, // MFP2, VS not gen internally, GPIO not used to gen fsync, auto mode // YUV422 8bit software override for all pipes since connected GMSL1 is under parallel mode { 0x29, 0x040B, 0x80, 0x00 }, // pipe 0 bpp=0x10: Datatypes = 0x22, 0x1E, 0x2E { 0x29, 0x040E, 0x5e, 0x00 }, // pipe 0 DT=0x1E: YUV422 8-bit @@ -254,6 +247,18 @@ static const struct regval max96712_mipi_1920x1440_30fps[] = { // Enable all links and pipes { 0x29, 0x0003, 0xaa, 0x00 }, // Enable Remote Control Channel Link A/B/C/D for Port 0 { 0x29, 0x0006, 0xff, 0x64 }, // Enable all links and pipes + // Frame Synchronization (FSYNC) + { 0x30, 0x3222, 0x01, 0x00 }, // SC320AT slave mode enable + { 0x29, 0x04A2, 0x00, 0x00 }, // Master link Video 0 for frame sync generation + { 0x29, 0x04AA, 0x00, 0x00 }, // Disable Vsync-Fsync overlap window + { 0x29, 0x04AB, 0x00, 0x00 }, // Disable Vsync-Fsync overlap window + { 0x29, 0x04A7, 0x0c, 0x00 }, // FSYNC_PERIOD_H, Set FSYNC period to 25M/30 clock cycles. PCLK = 25MHz. Sync freq = 30Hz + { 0x29, 0x04A6, 0xb7, 0x00 }, // FSYNC_PERIOD_M + { 0x29, 0x04A5, 0x35, 0x00 }, // FSYNC_PERIOD_L + { 0x29, 0x04AF, 0xcf, 0x00 }, // FSYNC is GMSL2 type, use osc for fsync, include all links/pipes in fsync gen + { 0x29, 0x04B1, 0x20, 0x00 }, // FSYNC_TX_ID: set 4 to match MFP4 on serializer side + { 0x40, 0x02CA, 0x84, 0x00 }, // Enable GPIO_RX_EN on serializer MFP4 + { 0x29, 0x04A0, 0x04, 0x00 }, // MFP2, VS not gen internally, GPIO not used to gen fsync, manual mode // Serializer Setting { 0x40, 0x0302, 0x10, 0x00 }, // improve CMU voltage performance to improve link robustness { 0x40, 0x1417, 0x00, 0x00 }, // Errata @@ -271,7 +276,7 @@ static const struct max96712_mode supported_modes[] = { }, .reg_list = max96712_mipi_1920x1440_30fps, .link_freq_idx = 0, - .bpp = 8, + .bpp = MAX96712_BITS_PER_SAMPLE, .vc[PAD0] = V4L2_MBUS_CSI2_CHANNEL_0, .vc[PAD1] = V4L2_MBUS_CSI2_CHANNEL_1, .vc[PAD2] = V4L2_MBUS_CSI2_CHANNEL_2, @@ -331,7 +336,9 @@ static int max96712_write_array(struct i2c_client *client, regs[i].i2c_addr, regs[i].addr, MAX96712_REG_VALUE_08BIT, regs[i].val); - msleep(regs[i].delay); + + if (regs[i].delay != 0) + msleep(regs[i].delay); } return ret; @@ -374,6 +381,11 @@ static int max96712_read_reg(struct i2c_client *client, *val = be32_to_cpu(data_be); +#if 0 + dev_info(&client->dev, "addr(0x%02x) read reg(0x%04x, 0x%02x)\n", \ + client_addr, reg, *val); +#endif + return 0; } @@ -413,8 +425,31 @@ static int max96712_check_link_lock_state(struct max96712 *max96712) dev_info(dev, "Detected MAX96712 chipid: %02x\n", id); - // Link A ~ Link D Transmitter Rate: 187.5Mbps, Receiver Rate: 6Gbps - if (max96712->rx_rate == MAX96712_RX_RATE_6GBPS) { + /* IF VDD = 1.2V: Enable REG_ENABLE and REG_MNL + * CTRL0: Enable REG_ENABLE + * CTRL2: Enable REG_MNL + */ + max96712_update_reg_bits(client, MAX96712_I2C_ADDR, + 0x0017, BIT(2), BIT(2)); + max96712_update_reg_bits(client, MAX96712_I2C_ADDR, + 0x0019, BIT(4), BIT(4)); + + // CSI output disabled + max96712_write_reg(client, MAX96712_I2C_ADDR, 0x040B, + MAX96712_REG_VALUE_08BIT, 0x00); + + // All links select GMSL2 mode and disable at beginning. + max96712_write_reg(client, MAX96712_I2C_ADDR, 0x0006, + MAX96712_REG_VALUE_08BIT, 0xf0); + + if (max96712->rx_rate == MAX96712_RX_RATE_3GBPS) { + // Link A ~ Link D Transmitter Rate: 187.5Mbps, Receiver Rate: 3Gbps + max96712_write_reg(client, MAX96712_I2C_ADDR, 0x0010, + MAX96712_REG_VALUE_08BIT, 0x11); + max96712_write_reg(client, MAX96712_I2C_ADDR, 0x0011, + MAX96712_REG_VALUE_08BIT, 0x11); + } else { + // Link A ~ Link D Transmitter Rate: 187.5Mbps, Receiver Rate: 6Gbps max96712_write_reg(client, MAX96712_I2C_ADDR, 0x0010, MAX96712_REG_VALUE_08BIT, 0x22); max96712_write_reg(client, MAX96712_I2C_ADDR, 0x0011, @@ -491,27 +526,23 @@ static int max96712_mipi_enable(struct i2c_client *client, bool enable) int ret = 0; if (enable) { - /* Force all MIPI clocks running */ - ret |= max96712_write_reg(client, MAX96712_I2C_ADDR, - MAX96712_REG_CTRL_MODE, - MAX96712_REG_VALUE_08BIT, - MAX96712_MODE_STREAMING); - /* CSI output enabled */ - ret |= max96712_write_reg(client, MAX96712_I2C_ADDR, - 0x40B, - MAX96712_REG_VALUE_08BIT, - 0x02); + // Force all MIPI clocks running + ret |= max96712_update_reg_bits(client, + MAX96712_I2C_ADDR, + 0x08A0, BIT(7), BIT(7)); + // CSI output enabled + ret |= max96712_update_reg_bits(client, + MAX96712_I2C_ADDR, + 0x040B, BIT(1), BIT(1)); } else { - /* Normal mode */ - ret |= max96712_write_reg(client, MAX96712_I2C_ADDR, - MAX96712_REG_CTRL_MODE, - MAX96712_REG_VALUE_08BIT, - MAX96712_MODE_SW_STANDBY); - /* CSI output disabled */ - ret |= max96712_write_reg(client, MAX96712_I2C_ADDR, - 0x40B, - MAX96712_REG_VALUE_08BIT, - 0x00); + // Normal mode + ret |= max96712_update_reg_bits(client, + MAX96712_I2C_ADDR, + 0x08A0, BIT(7), 0x00); + // CSI output disabled + ret |= max96712_update_reg_bits(client, + MAX96712_I2C_ADDR, + 0x040B, BIT(1), 0x00); } return ret; @@ -690,21 +721,12 @@ static long max96712_ioctl(struct v4l2_subdev *sd, unsigned int cmd, void *arg) max96712_get_module_inf(max96712, (struct rkmodule_inf *)arg); break; case RKMODULE_SET_QUICK_STREAM: - stream = *((u32 *)arg); if (stream) - ret = max96712_write_reg(max96712->client, - MAX96712_I2C_ADDR, - MAX96712_REG_CTRL_MODE, - MAX96712_REG_VALUE_08BIT, - MAX96712_MODE_STREAMING); + ret = max96712_mipi_enable(max96712->client, true); else - ret = max96712_write_reg(max96712->client, - MAX96712_I2C_ADDR, - MAX96712_REG_CTRL_MODE, - MAX96712_REG_VALUE_08BIT, - MAX96712_MODE_SW_STANDBY); + ret = max96712_mipi_enable(max96712->client, false); break; case RKMODULE_GET_VICAP_RST_INFO: max96712_get_vicap_rst_inf( @@ -715,8 +737,6 @@ static long max96712_ioctl(struct v4l2_subdev *sd, unsigned int cmd, void *arg) max96712, *(struct rkmodule_vicap_reset_info *)arg); break; case RKMODULE_GET_START_STREAM_SEQ: - // +*(int *)arg = RKMODULE_START_STREAM_FRONT; - // *(int *)arg = RKMODULE_START_STREAM_BEHIND; break; default: ret = -ENOIOCTLCMD; @@ -970,7 +990,6 @@ static int __max96712_power_on(struct max96712 *max96712) if (!IS_ERR(max96712->pwdn_gpio)) gpiod_set_value_cansleep(max96712->pwdn_gpio, 1); - /* 8192 cycles prior to first SCCB transaction */ delay_us = max96712_cal_delay(8192); usleep_range(delay_us, delay_us * 2); @@ -1249,7 +1268,13 @@ static int max96712_probe(struct i2c_client *client, } /* max96712 link Receiver Rate */ - max96712->rx_rate = MAX96712_RX_RATE_6GBPS; + ret = of_property_read_u32(node, "link-rx-rate", + &max96712->rx_rate); + if (ret) + max96712->rx_rate = MAX96712_RX_RATE_6GBPS; + else + dev_info(dev, "link-rx-rate property: %d\n", max96712->rx_rate); + dev_info(dev, "max96712 link receiver rate: %d\n", max96712->rx_rate); mutex_init(&max96712->mutex); From 71c39f46c9a8625896bec9e7f163ce3fb16a4292 Mon Sep 17 00:00:00 2001 From: Zhang Yubing Date: Mon, 24 Apr 2023 14:19:01 +0800 Subject: [PATCH 013/223] drm/rockchip: dw-dp: optimizing connected status detect process In some case, the hpd is detected but the aux is not ready. It's better to detect aux status before get link info from dpcd. When the dptx send a aux request transaction, the dptx's max aux timeout value is 3.2 ms, set the timeout value as 10ms is enough. Signed-off-by: Zhang Yubing Change-Id: Id878c0c2c1c5690ac08bad477ea96ac12b674edb --- drivers/gpu/drm/rockchip/dw-dp.c | 21 ++++++++++++++++----- 1 file changed, 16 insertions(+), 5 deletions(-) diff --git a/drivers/gpu/drm/rockchip/dw-dp.c b/drivers/gpu/drm/rockchip/dw-dp.c index 076b127b9fd2..66522bfb7e77 100644 --- a/drivers/gpu/drm/rockchip/dw-dp.c +++ b/drivers/gpu/drm/rockchip/dw-dp.c @@ -2670,7 +2670,7 @@ static ssize_t dw_dp_aux_transfer(struct drm_dp_aux *aux, struct drm_dp_aux_msg *msg) { struct dw_dp *dp = container_of(aux, struct dw_dp, aux); - unsigned long timeout = msecs_to_jiffies(250); + unsigned long timeout = msecs_to_jiffies(10); u32 status, value; ssize_t ret = 0; @@ -2702,7 +2702,7 @@ static ssize_t dw_dp_aux_transfer(struct drm_dp_aux *aux, status = wait_for_completion_timeout(&dp->complete, timeout); if (!status) { - dev_err(dp->dev, "timeout waiting for AUX reply\n"); + dev_dbg(dp->dev, "timeout waiting for AUX reply\n"); return -ETIMEDOUT; } @@ -3145,22 +3145,33 @@ static void dw_dp_bridge_atomic_disable(struct drm_bridge *bridge, static bool dw_dp_detect_dpcd(struct dw_dp *dp) { + u8 value; int ret; ret = phy_power_on(dp->phy); if (ret) - return false; + goto fail_power_on; + + ret = drm_dp_dpcd_readb(&dp->aux, DP_DPCD_REV, &value); + if (ret < 0) { + dev_err(dp->dev, "aux failed to read dpcd: %d\n", ret); + goto fail_probe; + } ret = dw_dp_link_probe(dp); if (ret) { - phy_power_off(dp->phy); dev_err(dp->dev, "failed to probe DP link: %d\n", ret); - return false; + goto fail_probe; } phy_power_off(dp->phy); return true; + +fail_probe: + phy_power_off(dp->phy); +fail_power_on: + return false; } static enum drm_connector_status dw_dp_bridge_detect(struct drm_bridge *bridge) From cd2099edfb22b6bee5e81fbb0fba997fe2dcf5f2 Mon Sep 17 00:00:00 2001 From: Guochun Huang Date: Tue, 25 Apr 2023 14:03:26 +0000 Subject: [PATCH 014/223] drm/rockchip: dsi: find panel/bridge only once in dual dsi application Change-Id: I96bb1b040a1df30d52d27815d54e4bf1509a2ea8 Signed-off-by: Guochun Huang --- .../gpu/drm/rockchip/dw-mipi-dsi-rockchip.c | 34 ++++--------------- 1 file changed, 7 insertions(+), 27 deletions(-) diff --git a/drivers/gpu/drm/rockchip/dw-mipi-dsi-rockchip.c b/drivers/gpu/drm/rockchip/dw-mipi-dsi-rockchip.c index 25aed790a9f0..0e21d4897b75 100644 --- a/drivers/gpu/drm/rockchip/dw-mipi-dsi-rockchip.c +++ b/drivers/gpu/drm/rockchip/dw-mipi-dsi-rockchip.c @@ -982,13 +982,6 @@ static int dw_mipi_dsi_rockchip_bind(struct device *dev, struct device *second; int ret; - ret = drm_of_find_panel_or_bridge(dsi->dev->of_node, 1, 0, - &dsi->panel, &dsi->bridge); - if (ret) { - dev_err(dsi->dev, "failed to find panel or bridge: %d\n", ret); - return ret; - } - second = dw_mipi_dsi_rockchip_find_second(dsi); if (IS_ERR(second)) return PTR_ERR(second); @@ -1009,6 +1002,13 @@ static int dw_mipi_dsi_rockchip_bind(struct device *dev, if (dsi->is_slave) return 0; + ret = drm_of_find_panel_or_bridge(dsi->dev->of_node, 1, -1, + &dsi->panel, &dsi->bridge); + if (ret) { + dev_err(dsi->dev, "failed to find panel or bridge: %d\n", ret); + return ret; + } + ret = clk_prepare_enable(dsi->pllref_clk); if (ret) { DRM_DEV_ERROR(dev, "Failed to enable pllref_clk: %d\n", ret); @@ -1064,7 +1064,6 @@ static const struct component_ops dw_mipi_dsi_rockchip_ops = { static int dw_mipi_dsi_rockchip_component_add(struct dw_mipi_dsi_rockchip *dsi) { - struct device *second; int ret; ret = component_add(dsi->dev, &dw_mipi_dsi_rockchip_ops); @@ -1074,30 +1073,11 @@ static int dw_mipi_dsi_rockchip_component_add(struct dw_mipi_dsi_rockchip *dsi) return ret; } - second = dw_mipi_dsi_rockchip_find_second(dsi); - if (IS_ERR(second)) - return PTR_ERR(second); - if (second) { - ret = component_add(second, &dw_mipi_dsi_rockchip_ops); - if (ret) { - DRM_DEV_ERROR(second, - "Failed to register component: %d\n", - ret); - return ret; - } - } - return 0; } static int dw_mipi_dsi_rockchip_component_del(struct dw_mipi_dsi_rockchip *dsi) { - struct device *second; - - second = dw_mipi_dsi_rockchip_find_second(dsi); - if (second && !IS_ERR(second)) - component_del(second, &dw_mipi_dsi_rockchip_ops); - component_del(dsi->dev, &dw_mipi_dsi_rockchip_ops); return 0; From 4f8507b871fbcdf269bb55315f7b86865eb57c78 Mon Sep 17 00:00:00 2001 From: Guochun Huang Date: Wed, 26 Apr 2023 09:59:16 +0000 Subject: [PATCH 015/223] drm/rockchip: dsi: fix dual channel dsi specify lane rate by "rockchip,lane-rate" Change-Id: Ibec1cc59352e4eae4ee079eb2c741fce18726795 Signed-off-by: Guochun Huang --- .../gpu/drm/rockchip/dw-mipi-dsi-rockchip.c | 63 ++++++++++++------- 1 file changed, 40 insertions(+), 23 deletions(-) diff --git a/drivers/gpu/drm/rockchip/dw-mipi-dsi-rockchip.c b/drivers/gpu/drm/rockchip/dw-mipi-dsi-rockchip.c index 0e21d4897b75..aea25bf1861c 100644 --- a/drivers/gpu/drm/rockchip/dw-mipi-dsi-rockchip.c +++ b/drivers/gpu/drm/rockchip/dw-mipi-dsi-rockchip.c @@ -572,36 +572,20 @@ static void dw_mipi_dsi_phy_power_off(void *priv_data) dsi->phy_enabled = false; } -static int -dw_mipi_dsi_get_lane_mbps(void *priv_data, const struct drm_display_mode *mode, - unsigned long mode_flags, u32 lanes, u32 format, - unsigned int *lane_mbps) +static unsigned int dw_mipi_dsi_calculate_lane_mpbs(struct dw_mipi_dsi_rockchip *dsi, + const struct drm_display_mode *mode, + u32 lanes, int bpp) { - struct dw_mipi_dsi_rockchip *dsi = priv_data; struct device *dev = dsi->dev; - int bpp; - unsigned long mpclk, tmp; unsigned int target_mbps = 1000; unsigned int max_mbps; - unsigned long best_freq = 0; - unsigned long fvco_min, fvco_max, fin, fout; - unsigned int min_prediv, max_prediv; - unsigned int _prediv, best_prediv; - unsigned long _fbdiv, best_fbdiv; - unsigned long min_delta = ULONG_MAX; - unsigned long target_pclk, hs_clk_rate; unsigned int value; - int ret; + unsigned long mpclk, tmp; + + if (dsi->is_slave) + return dsi->lane_mbps; max_mbps = dsi->cdata->max_bit_rate_per_lane / USEC_PER_SEC; - dsi->format = format; - bpp = mipi_dsi_pixel_format_to_bpp(dsi->format); - if (bpp < 0) { - DRM_DEV_ERROR(dsi->dev, - "failed to get bpp for pixel format %d\n", - dsi->format); - return bpp; - } /* optional override of the desired bandwidth */ if (!of_property_read_u32(dev->of_node, "rockchip,lane-rate", &value)) { @@ -621,6 +605,39 @@ dw_mipi_dsi_get_lane_mbps(void *priv_data, const struct drm_display_mode *mode, } } + if (dsi->slave) + dsi->slave->lane_mbps = target_mbps; + + return target_mbps; +} + +static int +dw_mipi_dsi_get_lane_mbps(void *priv_data, const struct drm_display_mode *mode, + unsigned long mode_flags, u32 lanes, u32 format, + unsigned int *lane_mbps) +{ + struct dw_mipi_dsi_rockchip *dsi = priv_data; + unsigned long best_freq = 0; + unsigned long fvco_min, fvco_max, fin, fout; + unsigned int min_prediv, max_prediv; + unsigned int _prediv, best_prediv; + unsigned long _fbdiv, best_fbdiv; + unsigned long min_delta = ULONG_MAX; + unsigned long target_pclk, hs_clk_rate; + unsigned int target_mbps; + int bpp, ret; + + dsi->format = format; + bpp = mipi_dsi_pixel_format_to_bpp(dsi->format); + if (bpp < 0) { + DRM_DEV_ERROR(dsi->dev, + "failed to get bpp for pixel format %d\n", + dsi->format); + return bpp; + } + + target_mbps = dw_mipi_dsi_calculate_lane_mpbs(dsi, mode, lanes, bpp); + /* for external phy only a the mipi_dphy_config is necessary */ if (dsi->phy) { target_pclk = DIV_ROUND_CLOSEST_ULL(target_mbps * lanes, bpp); From 5e1298153da08955562380b75d57c145f35672eb Mon Sep 17 00:00:00 2001 From: Guochun Huang Date: Wed, 26 Apr 2023 10:35:31 +0000 Subject: [PATCH 016/223] drm/bridge: dw-mipi-dsi: fix request hs clk in dual channel dsi Change-Id: Ia11c4fed8aee39a6dd6a8315132b83c1888ea462 Signed-off-by: Guochun Huang --- drivers/gpu/drm/bridge/synopsys/dw-mipi-dsi.c | 9 +++------ 1 file changed, 3 insertions(+), 6 deletions(-) diff --git a/drivers/gpu/drm/bridge/synopsys/dw-mipi-dsi.c b/drivers/gpu/drm/bridge/synopsys/dw-mipi-dsi.c index 9251cc8c563e..a680731ce4d9 100644 --- a/drivers/gpu/drm/bridge/synopsys/dw-mipi-dsi.c +++ b/drivers/gpu/drm/bridge/synopsys/dw-mipi-dsi.c @@ -994,16 +994,13 @@ static void dw_mipi_dsi_enable(struct dw_mipi_dsi *dsi) if (dsi->mode_flags & MIPI_DSI_MODE_VIDEO) { dw_mipi_dsi_set_mode(dsi, MIPI_DSI_MODE_VIDEO); - if (dsi->slave) - dw_mipi_dsi_set_mode(dsi->slave, MIPI_DSI_MODE_VIDEO); } else { dsi_write(dsi, DSI_EDPI_CMD_SIZE, dsi->mode.hdisplay); dw_mipi_dsi_set_mode(dsi, 0); - if (dsi->slave) { - dsi_write(dsi->slave, DSI_EDPI_CMD_SIZE, dsi->mode.hdisplay); - dw_mipi_dsi_set_mode(dsi->slave, 0); - } } + + if (dsi->slave) + dw_mipi_dsi_enable(dsi->slave); } static void dw_mipi_dsi_bridge_enable(struct drm_bridge *bridge) From bbaafe573055b0c8326fe5c79fdc99a5f28aa928 Mon Sep 17 00:00:00 2001 From: Cai Wenzhong Date: Fri, 5 May 2023 11:11:24 +0800 Subject: [PATCH 017/223] arm64: dts: rockchip: rk3588-vehicle: fix max96712 gpio pinctrl error. 1. add max96712 lock-gpios for hot plug irq detect. 2. fix max96712 lock and errb gpio pinctrl error. Signed-off-by: Cai Wenzhong Change-Id: I0576da7290c659ea14016158b324bd1eda38dcf2 --- .../boot/dts/rockchip/rk3588-vehicle-evb-maxim-max96712.dtsi | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/arch/arm64/boot/dts/rockchip/rk3588-vehicle-evb-maxim-max96712.dtsi b/arch/arm64/boot/dts/rockchip/rk3588-vehicle-evb-maxim-max96712.dtsi index ee7041e8aa5b..7f75e114f06c 100644 --- a/arch/arm64/boot/dts/rockchip/rk3588-vehicle-evb-maxim-max96712.dtsi +++ b/arch/arm64/boot/dts/rockchip/rk3588-vehicle-evb-maxim-max96712.dtsi @@ -62,6 +62,7 @@ rockchip,grf = <&sys_grf>; power-gpios = <&gpio4 RK_PA6 GPIO_ACTIVE_HIGH>; //reset-gpios = <&gpio1 RK_PB2 GPIO_ACTIVE_HIGH>; + lock-gpios = <&gpio3 RK_PB4 GPIO_ACTIVE_HIGH>; rockchip,camera-module-index = <0>; rockchip,camera-module-facing = "back"; rockchip,camera-module-name = "max96712"; @@ -143,11 +144,11 @@ &pinctrl { max96712 { max96712_errb: max96712-errb { - rockchip,pins = <3 RK_PD1 RK_FUNC_GPIO &pcfg_pull_up>; + rockchip,pins = <0 RK_PC2 RK_FUNC_GPIO &pcfg_pull_up>; }; max96712_int: max96712-int { - rockchip,pins = <3 RK_PB7 RK_FUNC_GPIO &pcfg_pull_up>; + rockchip,pins = <3 RK_PB4 RK_FUNC_GPIO &pcfg_pull_up>; }; }; }; From b169885cd828dd6329e988dd33ebda60c18c5350 Mon Sep 17 00:00:00 2001 From: Jason Song Date: Fri, 5 May 2023 14:05:39 +0800 Subject: [PATCH 018/223] arm64: dts: rockchip: rk3588-vehicle-evb-v20: reduce sdio power on delay. on vehicle evb, sdio wifi power on delay recommend 10ms at least. Signed-off-by: Jason Song Change-Id: I0d489b080f0a6323eb14261eaf557e3e3f0e13ee --- arch/arm64/boot/dts/rockchip/rk3588-vehicle-evb-v20.dtsi | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/arch/arm64/boot/dts/rockchip/rk3588-vehicle-evb-v20.dtsi b/arch/arm64/boot/dts/rockchip/rk3588-vehicle-evb-v20.dtsi index f97f6bb94c01..4504495610b6 100644 --- a/arch/arm64/boot/dts/rockchip/rk3588-vehicle-evb-v20.dtsi +++ b/arch/arm64/boot/dts/rockchip/rk3588-vehicle-evb-v20.dtsi @@ -61,7 +61,7 @@ * - SDIO_RESET_L_WL_REG_ON * - PDN (power down when low) */ - post-power-on-delay-ms = <200>; + post-power-on-delay-ms = <10>; reset-gpios = <&gpio1 RK_PB3 GPIO_ACTIVE_LOW>; status = "okay"; }; From d160fb836c81a0e0afc5b69e1191f5ca2cd484fe Mon Sep 17 00:00:00 2001 From: Yandong Lin Date: Fri, 28 Apr 2023 16:07:52 +0800 Subject: [PATCH 019/223] video: rockchip: mpp: fix rkjpegd define Signed-off-by: Yandong Lin Change-Id: I41ba84bc119e701d52b217e399d78c795c532446 --- drivers/video/rockchip/mpp/mpp_common.c | 1 + drivers/video/rockchip/mpp/mpp_common.h | 2 +- drivers/video/rockchip/mpp/mpp_jpgdec.c | 2 +- 3 files changed, 3 insertions(+), 2 deletions(-) diff --git a/drivers/video/rockchip/mpp/mpp_common.c b/drivers/video/rockchip/mpp/mpp_common.c index 9d4ec9734a9d..dbc625c2a491 100644 --- a/drivers/video/rockchip/mpp/mpp_common.c +++ b/drivers/video/rockchip/mpp/mpp_common.c @@ -71,6 +71,7 @@ const char *mpp_device_name[MPP_DEVICE_BUTT] = { [MPP_DEVICE_HEVC_DEC] = "HEVC_DEC", [MPP_DEVICE_RKVDEC] = "RKVDEC", [MPP_DEVICE_AVSPLUS_DEC] = "AVSPLUS_DEC", + [MPP_DEVICE_RKJPEGD] = "RKJPEGD", [MPP_DEVICE_RKVENC] = "RKVENC", [MPP_DEVICE_VEPU1] = "VEPU1", [MPP_DEVICE_VEPU2] = "VEPU2", diff --git a/drivers/video/rockchip/mpp/mpp_common.h b/drivers/video/rockchip/mpp/mpp_common.h index f20bd7307726..a088d62975f9 100644 --- a/drivers/video/rockchip/mpp/mpp_common.h +++ b/drivers/video/rockchip/mpp/mpp_common.h @@ -58,7 +58,7 @@ enum MPP_DEVICE_TYPE { MPP_DEVICE_HEVC_DEC = 8, /* 0x00000100 */ MPP_DEVICE_RKVDEC = 9, /* 0x00000200 */ MPP_DEVICE_AVSPLUS_DEC = 12, /* 0x00001000 */ - MPP_DEVICE_JPGDEC = 13, /* 0x00002000 */ + MPP_DEVICE_RKJPEGD = 13, /* 0x00002000 */ MPP_DEVICE_RKVENC = 16, /* 0x00010000 */ MPP_DEVICE_VEPU1 = 17, /* 0x00020000 */ diff --git a/drivers/video/rockchip/mpp/mpp_jpgdec.c b/drivers/video/rockchip/mpp/mpp_jpgdec.c index 0f204e22e0e6..753b061f22ea 100644 --- a/drivers/video/rockchip/mpp/mpp_jpgdec.c +++ b/drivers/video/rockchip/mpp/mpp_jpgdec.c @@ -558,7 +558,7 @@ static struct mpp_dev_ops jpgdec_v1_dev_ops = { }; static const struct mpp_dev_var jpgdec_v1_data = { - .device_type = MPP_DEVICE_JPGDEC, + .device_type = MPP_DEVICE_RKJPEGD, .hw_info = &jpgdec_v1_hw_info, .trans_info = jpgdec_v1_trans, .hw_ops = &jpgdec_v1_hw_ops, From 6c65f4a7e9b696a0fe38d326f6f30c9eacd6408c Mon Sep 17 00:00:00 2001 From: Yandong Lin Date: Fri, 5 May 2023 16:49:45 +0800 Subject: [PATCH 020/223] video: rockchip: mpp: fix soft timeout to 500 ms for rkvdec2_link Signed-off-by: Yandong Lin Change-Id: Ia27ab31db22655f13037c2aafde8bde2ad534c4b --- drivers/video/rockchip/mpp/mpp_rkvdec2_link.c | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/drivers/video/rockchip/mpp/mpp_rkvdec2_link.c b/drivers/video/rockchip/mpp/mpp_rkvdec2_link.c index f3b36e06a93d..c21687925081 100644 --- a/drivers/video/rockchip/mpp/mpp_rkvdec2_link.c +++ b/drivers/video/rockchip/mpp/mpp_rkvdec2_link.c @@ -18,7 +18,7 @@ #include "hack/mpp_rkvdec2_link_hack_rk3568.c" -#define WORK_TIMEOUT_MS (200) +#define WORK_TIMEOUT_MS (500) #define WAIT_TIMEOUT_MS (2000) #define RKVDEC2_LINK_HACK_TASK_FLAG (0xff) @@ -375,7 +375,7 @@ static int rkvdec2_link_enqueue(struct rkvdec_link_dev *link_dec, wmb(); mpp_iommu_flush_tlb(link_dec->mpp->iommu_info); - mpp_task_run_begin(mpp_task, timing_en, WORK_TIMEOUT_MS); + mpp_task_run_begin(mpp_task, timing_en, MPP_WORK_TIMEOUT_DELAY); link_dec->task_running++; /* configure done */ @@ -837,8 +837,8 @@ static void rkvdec2_link_timeout_proc(struct work_struct *work_s) dec = to_rkvdec2_dev(mpp); atomic_inc(&dec->link_dec->task_timeout); - dev_err(mpp->dev, "session %d task %d timeout, cnt %d\n", - session->index, task->task_index, + dev_err(mpp->dev, "session %d task %d state %#lx timeout, cnt %d\n", + session->index, task->task_index, task->state, atomic_read(&dec->link_dec->task_timeout)); rkvdec2_link_trigger_work(mpp); @@ -1199,7 +1199,7 @@ int rkvdec2_link_wait_result(struct mpp_session *session, mpp_session_pop_done(session, mpp_task); } else { - mpp_err("task %d:%d statue %lx timeout -> abort\n", + mpp_err("task %d:%d state %lx timeout -> abort\n", session->index, mpp_task->task_id, mpp_task->state); atomic_inc(&mpp_task->abort_request); From 6291a1be8f8a699bd08c0349fe62617219c325b3 Mon Sep 17 00:00:00 2001 From: Sandy Huang Date: Sat, 6 May 2023 09:50:35 +0800 Subject: [PATCH 021/223] drm/rockchip: vop2: add writeback virtual height support Signed-off-by: Sandy Huang Change-Id: I6971328ca0c931d884cd093310020f34a48d908c --- drivers/gpu/drm/rockchip/rockchip_drm_vop2.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/gpu/drm/rockchip/rockchip_drm_vop2.c b/drivers/gpu/drm/rockchip/rockchip_drm_vop2.c index 299b6404cfa1..2e00837c0fe3 100644 --- a/drivers/gpu/drm/rockchip/rockchip_drm_vop2.c +++ b/drivers/gpu/drm/rockchip/rockchip_drm_vop2.c @@ -3167,7 +3167,7 @@ static int vop2_wb_encoder_atomic_check(struct drm_encoder *encoder, } if ((fb->width > cstate->mode.hdisplay) || - ((fb->height != cstate->mode.vdisplay) && + ((fb->height < cstate->mode.vdisplay) && (fb->height != (cstate->mode.vdisplay >> 1)))) { DRM_DEBUG_KMS("Invalid framebuffer size %ux%u, Only support x scale down and 1/2 y scale down\n", fb->width, fb->height); From 1b151c0aef43cb8a27d0c65eafd86e47ea9fb8c7 Mon Sep 17 00:00:00 2001 From: Chandler Chen Date: Wed, 15 Feb 2023 11:30:38 +0800 Subject: [PATCH 022/223] video: rockchip: mpp: increase iep2 timeout threshold Signed-off-by: Chandler Chen Change-Id: If585f9086150ef261d1cc6aa6054110aba3e1a80 --- drivers/video/rockchip/mpp/mpp_iep2.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/video/rockchip/mpp/mpp_iep2.c b/drivers/video/rockchip/mpp/mpp_iep2.c index d00516b2bca3..8d1926957f69 100644 --- a/drivers/video/rockchip/mpp/mpp_iep2.c +++ b/drivers/video/rockchip/mpp/mpp_iep2.c @@ -439,7 +439,7 @@ static void iep2_config(struct mpp_dev *mpp, struct iep_task *task) mpp_write_relaxed(mpp, IEP2_REG_SRC_ADDR_NXTV, bot->cr); } - reg = IEP2_REG_TIMEOUT_CFG_EN | 0x7fffff; + reg = IEP2_REG_TIMEOUT_CFG_EN | 0x3ffffff; mpp_write_relaxed(mpp, IEP2_REG_TIMEOUT_CFG, reg); mpp_write_relaxed(mpp, IEP2_REG_SRC_ADDR_PREY, cfg->src[2].y); From b32714ef3631e39d507c69b7fff75722905ea925 Mon Sep 17 00:00:00 2001 From: Felix Zeng Date: Wed, 12 Apr 2023 10:37:14 +0800 Subject: [PATCH 023/223] driver: rknpu: Update rknpu driver, version: 0.8.8 * Add nbuf memory support * Add rknpu session for each instance * Add multi core irq status timeout log * Fix job run count error Signed-off-by: Felix Zeng Change-Id: I408e535fa1b3f8c853682a8ebaa245e3d7c188fb --- drivers/rknpu/Makefile | 1 + drivers/rknpu/include/rknpu_drv.h | 15 +- drivers/rknpu/include/rknpu_gem.h | 6 + drivers/rknpu/include/rknpu_ioctl.h | 4 +- drivers/rknpu/include/rknpu_iommu.h | 36 ++++ drivers/rknpu/include/rknpu_job.h | 4 +- drivers/rknpu/include/rknpu_mem.h | 7 +- drivers/rknpu/include/rknpu_mm.h | 18 -- drivers/rknpu/rknpu_drv.c | 105 ++++++++- drivers/rknpu/rknpu_gem.c | 319 ++++++++++++++++++++-------- drivers/rknpu/rknpu_iommu.c | 58 +++++ drivers/rknpu/rknpu_job.c | 42 ++-- drivers/rknpu/rknpu_mem.c | 76 +++++-- drivers/rknpu/rknpu_mm.c | 51 ----- 14 files changed, 524 insertions(+), 218 deletions(-) create mode 100644 drivers/rknpu/include/rknpu_iommu.h create mode 100644 drivers/rknpu/rknpu_iommu.c diff --git a/drivers/rknpu/Makefile b/drivers/rknpu/Makefile index 41dacc93157c..a8d265d7338a 100644 --- a/drivers/rknpu/Makefile +++ b/drivers/rknpu/Makefile @@ -9,6 +9,7 @@ rknpu-y += rknpu_drv.o rknpu-y += rknpu_reset.o rknpu-y += rknpu_job.o rknpu-y += rknpu_debugger.o +rknpu-y += rknpu_iommu.o rknpu-$(CONFIG_ROCKCHIP_RKNPU_SRAM) += rknpu_mm.o rknpu-$(CONFIG_ROCKCHIP_RKNPU_FENCE) += rknpu_fence.o rknpu-$(CONFIG_ROCKCHIP_RKNPU_DRM_GEM) += rknpu_gem.o diff --git a/drivers/rknpu/include/rknpu_drv.h b/drivers/rknpu/include/rknpu_drv.h index 67da03cb63bb..13280c18a2fd 100644 --- a/drivers/rknpu/include/rknpu_drv.h +++ b/drivers/rknpu/include/rknpu_drv.h @@ -30,10 +30,10 @@ #define DRIVER_NAME "rknpu" #define DRIVER_DESC "RKNPU driver" -#define DRIVER_DATE "20230202" +#define DRIVER_DATE "20230428" #define DRIVER_MAJOR 0 #define DRIVER_MINOR 8 -#define DRIVER_PATCHLEVEL 5 +#define DRIVER_PATCHLEVEL 8 #define LOG_TAG "RKNPU" @@ -73,6 +73,8 @@ struct rknpu_config { const struct rknpu_reset_data *resets; int num_irqs; int num_resets; + __u64 nbuf_phyaddr; + __u64 nbuf_size; }; struct rknpu_timer { @@ -149,12 +151,21 @@ struct rknpu_device { ktime_t kt; phys_addr_t sram_start; phys_addr_t sram_end; + phys_addr_t nbuf_start; + phys_addr_t nbuf_end; uint32_t sram_size; + uint32_t nbuf_size; void __iomem *sram_base_io; + void __iomem *nbuf_base_io; struct rknpu_mm *sram_mm; unsigned long power_put_delay; }; +struct rknpu_session { + struct rknpu_device *rknpu_dev; + struct list_head list; +}; + int rknpu_power_get(struct rknpu_device *rknpu_dev); int rknpu_power_put(struct rknpu_device *rknpu_dev); diff --git a/drivers/rknpu/include/rknpu_gem.h b/drivers/rknpu/include/rknpu_gem.h index 954586607b16..0afc87bba322 100644 --- a/drivers/rknpu/include/rknpu_gem.h +++ b/drivers/rknpu/include/rknpu_gem.h @@ -48,6 +48,7 @@ struct rknpu_gem_object { unsigned int flags; unsigned long size; unsigned long sram_size; + unsigned long nbuf_size; struct rknpu_mm_obj *sram_obj; dma_addr_t iova_start; unsigned long iova_size; @@ -61,6 +62,11 @@ struct rknpu_gem_object { struct drm_mm_node mm_node; }; +enum rknpu_cache_type { + RKNPU_CACHE_SRAM = 1 << 0, + RKNPU_CACHE_NBUF = 1 << 1, +}; + /* create a new buffer with gem object */ struct rknpu_gem_object *rknpu_gem_object_create(struct drm_device *dev, unsigned int flags, diff --git a/drivers/rknpu/include/rknpu_ioctl.h b/drivers/rknpu/include/rknpu_ioctl.h index fc7225fb7b47..6294ac59274d 100644 --- a/drivers/rknpu/include/rknpu_ioctl.h +++ b/drivers/rknpu/include/rknpu_ioctl.h @@ -77,11 +77,13 @@ enum e_rknpu_mem_type { RKNPU_MEM_NON_DMA32 = 1 << 7, /* request SRAM */ RKNPU_MEM_TRY_ALLOC_SRAM = 1 << 8, + /* request NBUF */ + RKNPU_MEM_TRY_ALLOC_NBUF = 1 << 9, RKNPU_MEM_MASK = RKNPU_MEM_NON_CONTIGUOUS | RKNPU_MEM_CACHEABLE | RKNPU_MEM_WRITE_COMBINE | RKNPU_MEM_KERNEL_MAPPING | RKNPU_MEM_IOMMU | RKNPU_MEM_ZEROING | RKNPU_MEM_SECURE | RKNPU_MEM_NON_DMA32 | - RKNPU_MEM_TRY_ALLOC_SRAM + RKNPU_MEM_TRY_ALLOC_SRAM | RKNPU_MEM_TRY_ALLOC_NBUF }; /* sync mode definitions. */ diff --git a/drivers/rknpu/include/rknpu_iommu.h b/drivers/rknpu/include/rknpu_iommu.h new file mode 100644 index 000000000000..3951764072a7 --- /dev/null +++ b/drivers/rknpu/include/rknpu_iommu.h @@ -0,0 +1,36 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* + * Copyright (C) Rockchip Electronics Co.Ltd + * Author: Felix Zeng + */ + +#ifndef __LINUX_RKNPU_IOMMU_H +#define __LINUX_RKNPU_IOMMU_H + +#include +#include +#include +#include +#include + +#include "rknpu_drv.h" + +enum iommu_dma_cookie_type { + IOMMU_DMA_IOVA_COOKIE, + IOMMU_DMA_MSI_COOKIE, +}; + +struct rknpu_iommu_dma_cookie { + enum iommu_dma_cookie_type type; + + /* Full allocator for IOMMU_DMA_IOVA_COOKIE */ + struct iova_domain iovad; +}; + +dma_addr_t rknpu_iommu_dma_alloc_iova(struct iommu_domain *domain, size_t size, + u64 dma_limit, struct device *dev); + +void rknpu_iommu_dma_free_iova(struct rknpu_iommu_dma_cookie *cookie, + dma_addr_t iova, size_t size); + +#endif diff --git a/drivers/rknpu/include/rknpu_job.h b/drivers/rknpu/include/rknpu_job.h index 6ef52d439277..73f27190a8c3 100644 --- a/drivers/rknpu/include/rknpu_job.h +++ b/drivers/rknpu/include/rknpu_job.h @@ -43,8 +43,8 @@ struct rknpu_job { struct dma_fence *fence; ktime_t timestamp; uint32_t use_core_num; - uint32_t run_count; - uint32_t interrupt_count; + atomic_t run_count; + atomic_t interrupt_count; ktime_t hw_recoder_time; }; diff --git a/drivers/rknpu/include/rknpu_mem.h b/drivers/rknpu/include/rknpu_mem.h index 925535c85f06..69975408f434 100644 --- a/drivers/rknpu/include/rknpu_mem.h +++ b/drivers/rknpu/include/rknpu_mem.h @@ -33,11 +33,14 @@ struct rknpu_mem_object { struct page **pages; struct sg_table *sgt; struct dma_buf *dmabuf; + struct list_head head; unsigned int owner; }; -int rknpu_mem_create_ioctl(struct rknpu_device *rknpu_dev, unsigned long data); -int rknpu_mem_destroy_ioctl(struct rknpu_device *rknpu_dev, unsigned long data); +int rknpu_mem_create_ioctl(struct rknpu_device *rknpu_dev, unsigned long data, + struct file *file); +int rknpu_mem_destroy_ioctl(struct rknpu_device *rknpu_dev, unsigned long data, + struct file *file); int rknpu_mem_sync_ioctl(struct rknpu_device *rknpu_dev, unsigned long data); #endif diff --git a/drivers/rknpu/include/rknpu_mm.h b/drivers/rknpu/include/rknpu_mm.h index b764892d1dc4..52fa044e18e2 100644 --- a/drivers/rknpu/include/rknpu_mm.h +++ b/drivers/rknpu/include/rknpu_mm.h @@ -40,22 +40,4 @@ int rknpu_mm_free(struct rknpu_mm *mm, struct rknpu_mm_obj *mm_obj); int rknpu_mm_dump(struct seq_file *m, void *data); -enum iommu_dma_cookie_type { - IOMMU_DMA_IOVA_COOKIE, - IOMMU_DMA_MSI_COOKIE, -}; - -struct rknpu_iommu_dma_cookie { - enum iommu_dma_cookie_type type; - - /* Full allocator for IOMMU_DMA_IOVA_COOKIE */ - struct iova_domain iovad; -}; - -dma_addr_t rknpu_iommu_dma_alloc_iova(struct iommu_domain *domain, size_t size, - u64 dma_limit, struct device *dev); - -void rknpu_iommu_dma_free_iova(struct rknpu_iommu_dma_cookie *cookie, - dma_addr_t iova, size_t size); - #endif diff --git a/drivers/rknpu/rknpu_drv.c b/drivers/rknpu/rknpu_drv.c index bbcf19af8794..3b008142d31d 100644 --- a/drivers/rknpu/rknpu_drv.c +++ b/drivers/rknpu/rknpu_drv.c @@ -116,7 +116,9 @@ static const struct rknpu_config rk356x_rknpu_config = { .irqs = rknpu_irqs, .resets = rknpu_resets, .num_irqs = ARRAY_SIZE(rknpu_irqs), - .num_resets = ARRAY_SIZE(rknpu_resets) + .num_resets = ARRAY_SIZE(rknpu_resets), + .nbuf_phyaddr = 0, + .nbuf_size = 0 }; static const struct rknpu_config rk3588_rknpu_config = { @@ -132,7 +134,9 @@ static const struct rknpu_config rk3588_rknpu_config = { .irqs = rk3588_npu_irqs, .resets = rk3588_npu_resets, .num_irqs = ARRAY_SIZE(rk3588_npu_irqs), - .num_resets = ARRAY_SIZE(rk3588_npu_resets) + .num_resets = ARRAY_SIZE(rk3588_npu_resets), + .nbuf_phyaddr = 0, + .nbuf_size = 0 }; static const struct rknpu_config rv1106_rknpu_config = { @@ -148,7 +152,9 @@ static const struct rknpu_config rv1106_rknpu_config = { .irqs = rknpu_irqs, .resets = rknpu_resets, .num_irqs = ARRAY_SIZE(rknpu_irqs), - .num_resets = ARRAY_SIZE(rknpu_resets) + .num_resets = ARRAY_SIZE(rknpu_resets), + .nbuf_phyaddr = 0, + .nbuf_size = 0 }; static const struct rknpu_config rk3562_rknpu_config = { @@ -164,7 +170,9 @@ static const struct rknpu_config rk3562_rknpu_config = { .irqs = rknpu_irqs, .resets = rknpu_resets, .num_irqs = ARRAY_SIZE(rknpu_irqs), - .num_resets = ARRAY_SIZE(rknpu_resets) + .num_resets = ARRAY_SIZE(rknpu_resets), + .nbuf_phyaddr = 0xfe400000, + .nbuf_size = 256 * 1024 }; /* driver probe and init */ @@ -353,11 +361,56 @@ static int rknpu_action(struct rknpu_device *rknpu_dev, #ifdef CONFIG_ROCKCHIP_RKNPU_DMA_HEAP static int rknpu_open(struct inode *inode, struct file *file) { + struct rknpu_device *rknpu_dev = + container_of(file->private_data, struct rknpu_device, miscdev); + struct rknpu_session *session = NULL; + + session = kzalloc(sizeof(*session), GFP_KERNEL); + if (!session) { + LOG_ERROR("rknpu session alloc failed\n"); + return -ENOMEM; + } + + session->rknpu_dev = rknpu_dev; + INIT_LIST_HEAD(&session->list); + + file->private_data = (void *)session; + return nonseekable_open(inode, file); } static int rknpu_release(struct inode *inode, struct file *file) { + struct rknpu_mem_object *entry; + struct rknpu_session *session = file->private_data; + struct rknpu_device *rknpu_dev = session->rknpu_dev; + LIST_HEAD(local_list); + + spin_lock(&rknpu_dev->lock); + list_replace_init(&session->list, &local_list); + file->private_data = NULL; + spin_unlock(&rknpu_dev->lock); + + while (!list_empty(&local_list)) { + entry = list_first_entry(&local_list, struct rknpu_mem_object, + head); + + LOG_DEBUG( + "Fd close free rknpu_obj: %#llx, rknpu_obj->dma_addr: %#llx\n", + (__u64)(uintptr_t)entry, (__u64)entry->dma_addr); + + vunmap(entry->kv_addr); + entry->kv_addr = NULL; + + if (!entry->owner) + dma_buf_put(entry->dmabuf); + + list_del(&entry->head); + kfree(entry); + } + + kfree(session); + return 0; } @@ -389,8 +442,12 @@ static int rknpu_action_ioctl(struct rknpu_device *rknpu_dev, static long rknpu_ioctl(struct file *file, uint32_t cmd, unsigned long arg) { long ret = -EINVAL; - struct rknpu_device *rknpu_dev = - container_of(file->private_data, struct rknpu_device, miscdev); + struct rknpu_device *rknpu_dev = NULL; + + if (!file->private_data) + return -EINVAL; + + rknpu_dev = ((struct rknpu_session *)file->private_data)->rknpu_dev; rknpu_power_get(rknpu_dev); @@ -402,12 +459,12 @@ static long rknpu_ioctl(struct file *file, uint32_t cmd, unsigned long arg) ret = rknpu_submit_ioctl(rknpu_dev, arg); break; case IOCTL_RKNPU_MEM_CREATE: - ret = rknpu_mem_create_ioctl(rknpu_dev, arg); + ret = rknpu_mem_create_ioctl(rknpu_dev, arg, file); break; case RKNPU_MEM_MAP: break; case IOCTL_RKNPU_MEM_DESTROY: - ret = rknpu_mem_destroy_ioctl(rknpu_dev, arg); + ret = rknpu_mem_destroy_ioctl(rknpu_dev, arg, file); break; case IOCTL_RKNPU_MEM_SYNC: ret = rknpu_mem_sync_ioctl(rknpu_dev, arg); @@ -1603,6 +1660,31 @@ static int rknpu_find_sram_resource(struct rknpu_device *rknpu_dev) return 0; } +static int rknpu_find_nbuf_resource(struct rknpu_device *rknpu_dev) +{ + struct device *dev = rknpu_dev->dev; + + if (rknpu_dev->config->nbuf_size == 0) + return -EINVAL; + + rknpu_dev->nbuf_start = rknpu_dev->config->nbuf_phyaddr; + rknpu_dev->nbuf_size = rknpu_dev->config->nbuf_size; + rknpu_dev->nbuf_base_io = + devm_ioremap(dev, rknpu_dev->nbuf_start, rknpu_dev->nbuf_size); + if (IS_ERR(rknpu_dev->nbuf_base_io)) { + LOG_DEV_ERROR(dev, "failed to remap nbuf base io!\n"); + rknpu_dev->nbuf_base_io = NULL; + } + + rknpu_dev->nbuf_end = rknpu_dev->nbuf_start + rknpu_dev->nbuf_size; + + LOG_DEV_INFO(dev, "nbuf region: [%pa, %pa), nbuf size: %#x\n", + &rknpu_dev->nbuf_start, &rknpu_dev->nbuf_end, + rknpu_dev->nbuf_size); + + return 0; +} + static int rknpu_probe(struct platform_device *pdev) { struct resource *res = NULL; @@ -1819,7 +1901,8 @@ static int rknpu_probe(struct platform_device *pdev) INIT_DEFERRABLE_WORK(&rknpu_dev->power_off_work, rknpu_power_off_delay_work); - if (IS_ENABLED(CONFIG_ROCKCHIP_RKNPU_SRAM) && rknpu_dev->iommu_en) { + if (IS_ENABLED(CONFIG_NO_GKI) && + IS_ENABLED(CONFIG_ROCKCHIP_RKNPU_SRAM) && rknpu_dev->iommu_en) { if (!rknpu_find_sram_resource(rknpu_dev)) { ret = rknpu_mm_create(rknpu_dev->sram_size, PAGE_SIZE, &rknpu_dev->sram_mm); @@ -1830,6 +1913,10 @@ static int rknpu_probe(struct platform_device *pdev) } } + if (IS_ENABLED(CONFIG_NO_GKI) && rknpu_dev->iommu_en && + rknpu_dev->config->nbuf_size > 0) + rknpu_find_nbuf_resource(rknpu_dev); + rknpu_power_off(rknpu_dev); atomic_set(&rknpu_dev->power_refcount, 0); atomic_set(&rknpu_dev->cmdline_power_refcount, 0); diff --git a/drivers/rknpu/rknpu_gem.c b/drivers/rknpu/rknpu_gem.c index 38d3197fad76..f97be2b58e9b 100644 --- a/drivers/rknpu/rknpu_gem.c +++ b/drivers/rknpu/rknpu_gem.c @@ -25,6 +25,7 @@ #include "rknpu_drv.h" #include "rknpu_ioctl.h" #include "rknpu_gem.h" +#include "rknpu_iommu.h" #define RKNPU_GEM_ALLOC_FROM_PAGES 1 @@ -379,7 +380,8 @@ static void rknpu_gem_release(struct rknpu_gem_object *rknpu_obj) kfree(rknpu_obj); } -static int rknpu_gem_alloc_buf_with_sram(struct rknpu_gem_object *rknpu_obj) +static int rknpu_gem_alloc_buf_with_cache(struct rknpu_gem_object *rknpu_obj, + enum rknpu_cache_type cache_type) { struct drm_device *drm = rknpu_obj->base.dev; struct rknpu_device *rknpu_dev = drm->dev_private; @@ -392,8 +394,28 @@ static int rknpu_gem_alloc_buf_with_sram(struct rknpu_gem_object *rknpu_obj) unsigned long offset = 0; int i = 0; int ret = -EINVAL; + phys_addr_t cache_start = 0; + unsigned long cache_offset = 0; + unsigned long cache_size = 0; - /* iova map to sram */ + switch (cache_type) { + case RKNPU_CACHE_SRAM: + cache_start = rknpu_dev->sram_start; + cache_offset = rknpu_obj->sram_obj->range_start * + rknpu_dev->sram_mm->chunk_size; + cache_size = rknpu_obj->sram_size; + break; + case RKNPU_CACHE_NBUF: + cache_start = rknpu_dev->nbuf_start; + cache_offset = 0; + cache_size = rknpu_obj->nbuf_size; + break; + default: + LOG_ERROR("Unknown rknpu_cache_type: %d", cache_type); + return -EINVAL; + } + + /* iova map to cache */ domain = iommu_get_domain_for_dev(rknpu_dev->dev); if (!domain) { LOG_ERROR("failed to get iommu domain!"); @@ -402,8 +424,7 @@ static int rknpu_gem_alloc_buf_with_sram(struct rknpu_gem_object *rknpu_obj) cookie = domain->iova_cookie; iovad = &cookie->iovad; - rknpu_obj->iova_size = - iova_align(iovad, rknpu_obj->sram_size + rknpu_obj->size); + rknpu_obj->iova_size = iova_align(iovad, cache_size + rknpu_obj->size); rknpu_obj->iova_start = rknpu_iommu_dma_alloc_iova( domain, rknpu_obj->iova_size, dma_get_mask(drm->dev), drm->dev); if (!rknpu_obj->iova_start) { @@ -415,20 +436,20 @@ static int rknpu_gem_alloc_buf_with_sram(struct rknpu_gem_object *rknpu_obj) &rknpu_obj->iova_start, rknpu_obj->iova_size); /* - * Overview SRAM + DDR map to IOVA + * Overview cache + DDR map to IOVA * -------- - * sram_size: rknpu_obj->sram_size - * - allocate from SRAM, this size value has been page-aligned + * cache_size: + * - allocate from CACHE, this size value has been page-aligned * size: rknpu_obj->size * - allocate from DDR pages, this size value has been page-aligned * iova_size: rknpu_obj->iova_size - * - from iova_align(sram_size + size) - * - it may be larger than the (sram_size + size), and the larger part is not mapped + * - from iova_align(cache_size + size) + * - it may be larger than the (cache_size + size), and the larger part is not mapped * -------- * - * |<- sram_size ->| |<- - - - size - - - ->| + * |<- cache_size ->| |<- - - - size - - - ->| * +---------------+ +----------------------+ - * | SRAM | | DDR | + * | CACHE | | DDR | * +---------------+ +----------------------+ * | | * | V | V | @@ -438,20 +459,18 @@ static int rknpu_gem_alloc_buf_with_sram(struct rknpu_gem_object *rknpu_obj) * |<- - - - - - - iova_size - - - - - - ->| * */ - offset = rknpu_obj->sram_obj->range_start * - rknpu_dev->sram_mm->chunk_size; ret = iommu_map(domain, rknpu_obj->iova_start, - rknpu_dev->sram_start + offset, rknpu_obj->sram_size, + cache_start + cache_offset, cache_size, IOMMU_READ | IOMMU_WRITE); if (ret) { - LOG_ERROR("sram iommu_map error: %d\n", ret); + LOG_ERROR("cache iommu_map error: %d\n", ret); goto free_iova; } rknpu_obj->dma_addr = rknpu_obj->iova_start; if (rknpu_obj->size == 0) { - LOG_INFO("allocate sram size: %lu\n", rknpu_obj->sram_size); + LOG_INFO("allocate cache size: %lu\n", cache_size); return 0; } @@ -459,7 +478,7 @@ static int rknpu_gem_alloc_buf_with_sram(struct rknpu_gem_object *rknpu_obj) if (IS_ERR(rknpu_obj->pages)) { ret = PTR_ERR(rknpu_obj->pages); LOG_ERROR("failed to get pages: %d\n", ret); - goto sram_unmap; + goto cache_unmap; } rknpu_obj->num_pages = rknpu_obj->size >> PAGE_SHIFT; @@ -478,7 +497,7 @@ static int rknpu_gem_alloc_buf_with_sram(struct rknpu_gem_object *rknpu_obj) } length = rknpu_obj->size; - offset = rknpu_obj->iova_start + rknpu_obj->sram_size; + offset = rknpu_obj->iova_start + cache_size; for_each_sg(rknpu_obj->sgt->sgl, s, rknpu_obj->sgt->nents, i) { size = (length < s->length) ? length : s->length; @@ -497,13 +516,13 @@ static int rknpu_gem_alloc_buf_with_sram(struct rknpu_gem_object *rknpu_obj) break; } - LOG_INFO("allocate size: %lu with sram size: %lu\n", rknpu_obj->size, - rknpu_obj->sram_size); + LOG_INFO("allocate size: %lu with cache size: %lu\n", rknpu_obj->size, + cache_size); return 0; sgl_unmap: - iommu_unmap(domain, rknpu_obj->iova_start + rknpu_obj->sram_size, + iommu_unmap(domain, rknpu_obj->iova_start + cache_size, rknpu_obj->size - length); sg_free_table(rknpu_obj->sgt); kfree(rknpu_obj->sgt); @@ -511,8 +530,8 @@ sgl_unmap: put_pages: drm_gem_put_pages(&rknpu_obj->base, rknpu_obj->pages, false, false); -sram_unmap: - iommu_unmap(domain, rknpu_obj->iova_start, rknpu_obj->sram_size); +cache_unmap: + iommu_unmap(domain, rknpu_obj->iova_start, cache_size); free_iova: rknpu_iommu_dma_free_iova(domain->iova_cookie, rknpu_obj->iova_start, @@ -521,20 +540,31 @@ free_iova: return ret; } -static void rknpu_gem_free_buf_with_sram(struct rknpu_gem_object *rknpu_obj) +static void rknpu_gem_free_buf_with_cache(struct rknpu_gem_object *rknpu_obj, + enum rknpu_cache_type cache_type) { struct drm_device *drm = rknpu_obj->base.dev; struct rknpu_device *rknpu_dev = drm->dev_private; struct iommu_domain *domain = NULL; + unsigned long cache_size = 0; + + switch (cache_type) { + case RKNPU_CACHE_SRAM: + cache_size = rknpu_obj->sram_size; + break; + case RKNPU_CACHE_NBUF: + cache_size = rknpu_obj->nbuf_size; + break; + default: + LOG_ERROR("Unknown rknpu_cache_type: %d", cache_type); + return; + } domain = iommu_get_domain_for_dev(rknpu_dev->dev); if (domain) { - iommu_unmap(domain, rknpu_obj->iova_start, - rknpu_obj->sram_size); + iommu_unmap(domain, rknpu_obj->iova_start, cache_size); if (rknpu_obj->size > 0) - iommu_unmap(domain, - rknpu_obj->iova_start + - rknpu_obj->sram_size, + iommu_unmap(domain, rknpu_obj->iova_start + cache_size, rknpu_obj->size); rknpu_iommu_dma_free_iova(domain->iova_cookie, rknpu_obj->iova_start, @@ -617,11 +647,37 @@ struct rknpu_gem_object *rknpu_gem_object_create(struct drm_device *drm, if (real_sram_size > 0) { rknpu_obj->sram_size = real_sram_size; - ret = rknpu_gem_alloc_buf_with_sram(rknpu_obj); + ret = rknpu_gem_alloc_buf_with_cache(rknpu_obj, + RKNPU_CACHE_SRAM); if (ret < 0) goto mm_free; remain_ddr_size = 0; } + } else if (IS_ENABLED(CONFIG_NO_GKI) && + (flags & RKNPU_MEM_TRY_ALLOC_NBUF) && + rknpu_dev->nbuf_size > 0) { + size_t nbuf_size = 0; + + rknpu_obj = rknpu_gem_init(drm, remain_ddr_size); + if (IS_ERR(rknpu_obj)) + return rknpu_obj; + + nbuf_size = remain_ddr_size <= rknpu_dev->nbuf_size ? + remain_ddr_size : + rknpu_dev->nbuf_size; + + /* set memory type and cache attribute from user side. */ + rknpu_obj->flags = flags; + + if (nbuf_size > 0) { + rknpu_obj->nbuf_size = nbuf_size; + + ret = rknpu_gem_alloc_buf_with_cache(rknpu_obj, + RKNPU_CACHE_NBUF); + if (ret < 0) + goto gem_release; + remain_ddr_size = 0; + } } if (remain_ddr_size > 0) { @@ -639,10 +695,11 @@ struct rknpu_gem_object *rknpu_gem_object_create(struct drm_device *drm, if (rknpu_obj) LOG_DEBUG( - "created dma addr: %pad, cookie: %p, ddr size: %lu, sram size: %lu, attrs: %#lx, flags: %#x\n", + "created dma addr: %pad, cookie: %p, ddr size: %lu, sram size: %lu, nbuf size: %lu, attrs: %#lx, flags: %#x\n", &rknpu_obj->dma_addr, rknpu_obj->cookie, rknpu_obj->size, rknpu_obj->sram_size, - rknpu_obj->dma_attrs, rknpu_obj->flags); + rknpu_obj->nbuf_size, rknpu_obj->dma_attrs, + rknpu_obj->flags); return rknpu_obj; @@ -683,7 +740,12 @@ void rknpu_gem_object_destroy(struct rknpu_gem_object *rknpu_obj) if (rknpu_obj->sram_obj != NULL) rknpu_mm_free(rknpu_dev->sram_mm, rknpu_obj->sram_obj); - rknpu_gem_free_buf_with_sram(rknpu_obj); + rknpu_gem_free_buf_with_cache(rknpu_obj, + RKNPU_CACHE_SRAM); + } else if (IS_ENABLED(CONFIG_NO_GKI) && + rknpu_obj->nbuf_size > 0) { + rknpu_gem_free_buf_with_cache(rknpu_obj, + RKNPU_CACHE_NBUF); } else { rknpu_gem_free_buf(rknpu_obj); } @@ -808,6 +870,75 @@ static int rknpu_gem_mmap_pages(struct rknpu_gem_object *rknpu_obj, } #endif +static int rknpu_gem_mmap_cache(struct rknpu_gem_object *rknpu_obj, + struct vm_area_struct *vma, + enum rknpu_cache_type cache_type) +{ + struct drm_device *drm = rknpu_obj->base.dev; +#if RKNPU_GEM_ALLOC_FROM_PAGES + struct rknpu_device *rknpu_dev = drm->dev_private; +#endif + unsigned long vm_size = 0; + int ret = -EINVAL; + unsigned long offset = 0; + unsigned long num_pages = 0; + int i = 0; + phys_addr_t cache_start = 0; + unsigned long cache_offset = 0; + unsigned long cache_size = 0; + + switch (cache_type) { + case RKNPU_CACHE_SRAM: + cache_start = rknpu_dev->sram_start; + cache_offset = rknpu_obj->sram_obj->range_start * + rknpu_dev->sram_mm->chunk_size; + cache_size = rknpu_obj->sram_size; + break; + case RKNPU_CACHE_NBUF: + cache_start = rknpu_dev->nbuf_start; + cache_offset = 0; + cache_size = rknpu_obj->nbuf_size; + break; + default: + LOG_ERROR("Unknown rknpu_cache_type: %d", cache_type); + return -EINVAL; + } + + vma->vm_flags |= VM_MIXEDMAP; + + vm_size = vma->vm_end - vma->vm_start; + + /* + * Convert a physical address in a cache area to a page frame number (PFN), + * and store the resulting PFN in the vm_pgoff field of the given VMA. + * + * NOTE: This conversion carries a risk because the resulting PFN is not a true + * page frame number and may not be valid or usable in all contexts. + */ + vma->vm_pgoff = __phys_to_pfn(cache_start + cache_offset); + + ret = remap_pfn_range(vma, vma->vm_start, vma->vm_pgoff, cache_size, + vma->vm_page_prot); + if (ret) + return -EAGAIN; + + if (rknpu_obj->size == 0) + return 0; + + offset = cache_size; + + num_pages = (vm_size - cache_size) / PAGE_SIZE; + for (i = 0; i < num_pages; ++i) { + ret = vm_insert_page(vma, vma->vm_start + offset, + rknpu_obj->pages[i]); + if (ret < 0) + return ret; + offset += PAGE_SIZE; + } + + return 0; +} + static int rknpu_gem_mmap_buffer(struct rknpu_gem_object *rknpu_obj, struct vm_area_struct *vma) { @@ -832,38 +963,10 @@ static int rknpu_gem_mmap_buffer(struct rknpu_gem_object *rknpu_obj, if (vm_size > rknpu_obj->size) return -EINVAL; - if (rknpu_obj->sram_size > 0) { - unsigned long offset = 0; - unsigned long num_pages = 0; - int i = 0; - - vma->vm_flags |= VM_MIXEDMAP; - - offset = rknpu_obj->sram_obj->range_start * - rknpu_dev->sram_mm->chunk_size; - vma->vm_pgoff = __phys_to_pfn(rknpu_dev->sram_start + offset); - - ret = remap_pfn_range(vma, vma->vm_start, vma->vm_pgoff, - rknpu_obj->sram_size, vma->vm_page_prot); - if (ret) - return -EAGAIN; - - if (rknpu_obj->size == 0) - return 0; - - offset = rknpu_obj->sram_size; - - num_pages = (vm_size - rknpu_obj->sram_size) / PAGE_SIZE; - for (i = 0; i < num_pages; ++i) { - ret = vm_insert_page(vma, vma->vm_start + offset, - rknpu_obj->pages[i]); - if (ret < 0) - return ret; - offset += PAGE_SIZE; - } - - return 0; - } + if (rknpu_obj->sram_size > 0) + return rknpu_gem_mmap_cache(rknpu_obj, vma, RKNPU_CACHE_SRAM); + else if (rknpu_obj->nbuf_size > 0) + return rknpu_gem_mmap_cache(rknpu_obj, vma, RKNPU_CACHE_NBUF); #if RKNPU_GEM_ALLOC_FROM_PAGES if ((rknpu_obj->flags & RKNPU_MEM_NON_CONTIGUOUS) && @@ -1199,6 +1302,55 @@ int rknpu_gem_prime_mmap(struct drm_gem_object *obj, struct vm_area_struct *vma) return rknpu_gem_mmap_obj(obj, vma); } +static int rknpu_cache_sync(struct rknpu_gem_object *rknpu_obj, + unsigned long *length, unsigned long *offset, + enum rknpu_cache_type cache_type) +{ + struct drm_gem_object *obj = &rknpu_obj->base; + struct rknpu_device *rknpu_dev = obj->dev->dev_private; + void __iomem *cache_base_io = NULL; + unsigned long cache_offset = 0; + unsigned long cache_size = 0; + + switch (cache_type) { + case RKNPU_CACHE_SRAM: + cache_base_io = rknpu_dev->sram_base_io; + cache_offset = rknpu_obj->sram_obj->range_start * + rknpu_dev->sram_mm->chunk_size; + cache_size = rknpu_obj->sram_size; + break; + case RKNPU_CACHE_NBUF: + cache_base_io = rknpu_dev->nbuf_base_io; + cache_offset = 0; + cache_size = rknpu_obj->nbuf_size; + break; + default: + LOG_ERROR("Unknown rknpu_cache_type: %d", cache_type); + return -EINVAL; + } + + if ((*offset + *length) <= cache_size) { + __dma_map_area(cache_base_io + *offset + cache_offset, *length, + DMA_TO_DEVICE); + __dma_unmap_area(cache_base_io + *offset + cache_offset, + *length, DMA_FROM_DEVICE); + *length = 0; + *offset = 0; + } else if (*offset >= cache_size) { + *offset -= cache_size; + } else { + unsigned long cache_length = cache_size - *offset; + + __dma_map_area(cache_base_io + *offset + cache_offset, + cache_length, DMA_TO_DEVICE); + __dma_unmap_area(cache_base_io + *offset + cache_offset, + cache_length, DMA_FROM_DEVICE); + *length -= cache_length; + *offset = 0; + } + return 0; +} + int rknpu_gem_sync_ioctl(struct drm_device *dev, void *data, struct drm_file *file_priv) { @@ -1233,36 +1385,15 @@ int rknpu_gem_sync_ioctl(struct drm_device *dev, void *data, length = args->size; offset = args->offset; - if (IS_ENABLED(CONFIG_ROCKCHIP_RKNPU_SRAM) && + if (IS_ENABLED(CONFIG_NO_GKI) && + IS_ENABLED(CONFIG_ROCKCHIP_RKNPU_SRAM) && rknpu_obj->sram_size > 0) { - struct drm_gem_object *obj = &rknpu_obj->base; - struct rknpu_device *rknpu_dev = obj->dev->dev_private; - unsigned long sram_offset = - rknpu_obj->sram_obj->range_start * - rknpu_dev->sram_mm->chunk_size; - if ((offset + length) <= rknpu_obj->sram_size) { - __dma_map_area(rknpu_dev->sram_base_io + - offset + sram_offset, - length, DMA_TO_DEVICE); - __dma_unmap_area(rknpu_dev->sram_base_io + - offset + sram_offset, - length, DMA_FROM_DEVICE); - length = 0; - offset = 0; - } else if (offset >= rknpu_obj->sram_size) { - offset -= rknpu_obj->sram_size; - } else { - unsigned long sram_length = - rknpu_obj->sram_size - offset; - __dma_map_area(rknpu_dev->sram_base_io + - offset + sram_offset, - sram_length, DMA_TO_DEVICE); - __dma_unmap_area(rknpu_dev->sram_base_io + - offset + sram_offset, - sram_length, DMA_FROM_DEVICE); - length -= sram_length; - offset = 0; - } + rknpu_cache_sync(rknpu_obj, &length, &offset, + RKNPU_CACHE_SRAM); + } else if (IS_ENABLED(CONFIG_NO_GKI) && + rknpu_obj->nbuf_size > 0) { + rknpu_cache_sync(rknpu_obj, &length, &offset, + RKNPU_CACHE_NBUF); } for_each_sg(rknpu_obj->sgt->sgl, sg, rknpu_obj->sgt->nents, diff --git a/drivers/rknpu/rknpu_iommu.c b/drivers/rknpu/rknpu_iommu.c new file mode 100644 index 000000000000..39cc8f8be7c2 --- /dev/null +++ b/drivers/rknpu/rknpu_iommu.c @@ -0,0 +1,58 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Copyright (C) Rockchip Electronics Co.Ltd + * Author: Felix Zeng + */ + +#include "rknpu_iommu.h" + +dma_addr_t rknpu_iommu_dma_alloc_iova(struct iommu_domain *domain, size_t size, + u64 dma_limit, struct device *dev) +{ + struct rknpu_iommu_dma_cookie *cookie = (void *)domain->iova_cookie; + struct iova_domain *iovad = &cookie->iovad; + unsigned long shift, iova_len, iova = 0; +#if (KERNEL_VERSION(5, 4, 0) > LINUX_VERSION_CODE) + dma_addr_t limit; +#endif + + shift = iova_shift(iovad); + iova_len = size >> shift; + /* + * 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); + +#if (KERNEL_VERSION(5, 10, 0) <= LINUX_VERSION_CODE) + 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_t(u64, dma_limit, domain->geometry.aperture_end); + +#if (KERNEL_VERSION(5, 4, 0) <= LINUX_VERSION_CODE) + iova = alloc_iova_fast(iovad, iova_len, dma_limit >> shift, true); +#else + limit = min_t(dma_addr_t, dma_limit >> shift, iovad->end_pfn); + + iova = alloc_iova_fast(iovad, iova_len, limit, true); +#endif + + return (dma_addr_t)iova << shift; +} + +void rknpu_iommu_dma_free_iova(struct rknpu_iommu_dma_cookie *cookie, + dma_addr_t iova, size_t size) +{ + struct iova_domain *iovad = &cookie->iovad; + + free_iova_fast(iovad, iova_pfn(iovad, iova), size >> iova_shift(iovad)); +} diff --git a/drivers/rknpu/rknpu_job.c b/drivers/rknpu/rknpu_job.c index 6be7824a90ce..6a167c4a72c7 100644 --- a/drivers/rknpu/rknpu_job.c +++ b/drivers/rknpu/rknpu_job.c @@ -124,8 +124,8 @@ static inline struct rknpu_job *rknpu_job_alloc(struct rknpu_device *rknpu_dev, job->use_core_num = (args->core_mask & RKNPU_CORE0_MASK) + ((args->core_mask & RKNPU_CORE1_MASK) >> 1) + ((args->core_mask & RKNPU_CORE2_MASK) >> 2); - job->run_count = job->use_core_num; - job->interrupt_count = job->use_core_num; + atomic_set(&job->run_count, job->use_core_num); + atomic_set(&job->interrupt_count, job->use_core_num); #ifdef CONFIG_ROCKCHIP_RKNPU_DRM_GEM task_obj = (struct rknpu_gem_object *)(uintptr_t)args->task_obj_addr; if (task_obj) @@ -358,11 +358,10 @@ static void rknpu_job_next(struct rknpu_device *rknpu_dev, int core_index) list_del_init(&job->head[core_index]); job->in_queue[core_index] = false; subcore_data->job = job; - job->run_count--; job->hw_recoder_time = ktime_get(); spin_unlock_irqrestore(&rknpu_dev->irq_lock, flags); - if (job->run_count == 0) { + if (atomic_dec_and_test(&job->run_count)) { if (job->args->core_mask & RKNPU_CORE0_MASK) job->ret = rknpu_job_commit(job, 0); if (job->args->core_mask & RKNPU_CORE1_MASK) @@ -384,12 +383,11 @@ static void rknpu_job_done(struct rknpu_job *job, int ret, int core_index) spin_lock_irqsave(&rknpu_dev->irq_lock, flags); subcore_data->job = NULL; subcore_data->task_num -= rknn_get_task_number(job, core_index); - job->interrupt_count--; subcore_data->timer.busy_time += ktime_us_delta(now, job->hw_recoder_time); spin_unlock_irqrestore(&rknpu_dev->irq_lock, flags); - if (job->interrupt_count == 0) { + if (atomic_dec_and_test(&job->interrupt_count)) { int use_core_num = job->use_core_num; job->flags |= RKNPU_JOB_DONE; @@ -449,8 +447,8 @@ static void rknpu_job_schedule(struct rknpu_job *job) job->args->core_mask = rknpu_core_mask(core_index); job->use_core_num = 1; - job->interrupt_count = 1; - job->run_count = 1; + atomic_set(&job->run_count, job->use_core_num); + atomic_set(&job->interrupt_count, job->use_core_num); } spin_lock_irqsave(&rknpu_dev->irq_lock, flags); @@ -474,8 +472,6 @@ static void rknpu_job_abort(struct rknpu_job *job) { struct rknpu_device *rknpu_dev = job->rknpu_dev; struct rknpu_subcore_data *subcore_data = NULL; - int core_index = rknpu_core_index(job->args->core_mask); - void __iomem *rknpu_core_base = rknpu_dev->base[core_index]; unsigned long flags; int i = 0; @@ -495,14 +491,24 @@ static void rknpu_job_abort(struct rknpu_job *job) } if (job->ret == -ETIMEDOUT) { - LOG_ERROR( - "job timeout, flags: %#x, irq status: %#x, raw status: %#x, require mask: %#x, task counter: %#x, elapsed time: %lldus\n", - job->flags, REG_READ(RKNPU_OFFSET_INT_STATUS), - REG_READ(RKNPU_OFFSET_INT_RAW_STATUS), - job->int_mask[core_index], - (REG_READ(rknpu_dev->config->pc_task_status_offset) & - rknpu_dev->config->pc_task_number_mask), - ktime_to_us(ktime_sub(ktime_get(), job->timestamp))); + LOG_ERROR("job timeout, flags: %#x:\n", job->flags); + for (i = 0; i < rknpu_dev->config->num_irqs; i++) { + if (job->args->core_mask & rknpu_core_mask(i)) { + void __iomem *rknpu_core_base = + rknpu_dev->base[i]; + LOG_ERROR( + "\tcore %d irq status: %#x, raw status: %#x, require mask: %#x, task counter: %#x, elapsed time: %lldus\n", + i, REG_READ(RKNPU_OFFSET_INT_STATUS), + REG_READ(RKNPU_OFFSET_INT_RAW_STATUS), + job->int_mask[i], + (REG_READ( + rknpu_dev->config + ->pc_task_status_offset) & + rknpu_dev->config->pc_task_number_mask), + ktime_to_us(ktime_sub(ktime_get(), + job->timestamp))); + } + } rknpu_soft_reset(rknpu_dev); } else { LOG_ERROR( diff --git a/drivers/rknpu/rknpu_mem.c b/drivers/rknpu/rknpu_mem.c index 4fd686687992..ff7e92d0174e 100644 --- a/drivers/rknpu/rknpu_mem.c +++ b/drivers/rknpu/rknpu_mem.c @@ -15,7 +15,8 @@ #include "rknpu_ioctl.h" #include "rknpu_mem.h" -int rknpu_mem_create_ioctl(struct rknpu_device *rknpu_dev, unsigned long data) +int rknpu_mem_create_ioctl(struct rknpu_device *rknpu_dev, unsigned long data, + struct file *file) { struct rknpu_mem_create args; int ret = -EINVAL; @@ -27,6 +28,7 @@ int rknpu_mem_create_ioctl(struct rknpu_device *rknpu_dev, unsigned long data) struct page **pages; struct page *page; struct rknpu_mem_object *rknpu_obj = NULL; + struct rknpu_session *session = NULL; int i, fd; unsigned int length, page_count; @@ -65,6 +67,8 @@ int rknpu_mem_create_ioctl(struct rknpu_device *rknpu_dev, unsigned long data) O_CLOEXEC | O_RDWR, 0x0, dev_name(rknpu_dev->dev)); if (IS_ERR(dmabuf)) { + LOG_ERROR("dmabuf alloc failed, args.size = %llu\n", + args.size); ret = PTR_ERR(dmabuf); goto err_free_obj; } @@ -74,6 +78,7 @@ int rknpu_mem_create_ioctl(struct rknpu_device *rknpu_dev, unsigned long data) fd = dma_buf_fd(dmabuf, O_CLOEXEC | O_RDWR); if (fd < 0) { + LOG_ERROR("dmabuf fd get failed\n"); ret = -EFAULT; goto err_free_dma_buf; } @@ -81,12 +86,14 @@ int rknpu_mem_create_ioctl(struct rknpu_device *rknpu_dev, unsigned long data) attachment = dma_buf_attach(dmabuf, rknpu_dev->dev); if (IS_ERR(attachment)) { + LOG_ERROR("dma_buf_attach failed\n"); ret = PTR_ERR(attachment); goto err_free_dma_buf; } table = dma_buf_map_attachment(attachment, DMA_BIDIRECTIONAL); if (IS_ERR(table)) { + LOG_ERROR("dma_buf_attach failed\n"); dma_buf_detach(dmabuf, attachment); ret = PTR_ERR(table); goto err_free_dma_buf; @@ -103,6 +110,7 @@ int rknpu_mem_create_ioctl(struct rknpu_device *rknpu_dev, unsigned long data) page_count = length >> PAGE_SHIFT; pages = kmalloc_array(page_count, sizeof(struct page), GFP_KERNEL); if (!pages) { + LOG_ERROR("alloc pages failed\n"); ret = -ENOMEM; goto err_detach_dma_buf; } @@ -112,6 +120,7 @@ int rknpu_mem_create_ioctl(struct rknpu_device *rknpu_dev, unsigned long data) rknpu_obj->kv_addr = vmap(pages, page_count, VM_MAP, PAGE_KERNEL); if (!rknpu_obj->kv_addr) { + LOG_ERROR("vmap pages addr failed\n"); ret = -ENOMEM; goto err_free_pages; } @@ -141,6 +150,18 @@ int rknpu_mem_create_ioctl(struct rknpu_device *rknpu_dev, unsigned long data) dma_buf_unmap_attachment(attachment, table, DMA_BIDIRECTIONAL); dma_buf_detach(dmabuf, attachment); + spin_lock(&rknpu_dev->lock); + + session = file->private_data; + if (!session) { + spin_unlock(&rknpu_dev->lock); + ret = -EFAULT; + goto err_unmap_kv_addr; + } + list_add_tail(&rknpu_obj->head, &session->list); + + spin_unlock(&rknpu_dev->lock); + return 0; err_unmap_kv_addr: @@ -166,11 +187,12 @@ err_free_obj: return ret; } -int rknpu_mem_destroy_ioctl(struct rknpu_device *rknpu_dev, unsigned long data) +int rknpu_mem_destroy_ioctl(struct rknpu_device *rknpu_dev, unsigned long data, + struct file *file) { - struct rknpu_mem_object *rknpu_obj = NULL; + struct rknpu_mem_object *rknpu_obj, *entry, *q; + struct rknpu_session *session = NULL; struct rknpu_mem_destroy args; - struct dma_buf *dmabuf; int ret = -EFAULT; if (unlikely(copy_from_user(&args, (struct rknpu_mem_destroy *)data, @@ -188,19 +210,35 @@ int rknpu_mem_destroy_ioctl(struct rknpu_device *rknpu_dev, unsigned long data) } rknpu_obj = (struct rknpu_mem_object *)(uintptr_t)args.obj_addr; - dmabuf = rknpu_obj->dmabuf; LOG_DEBUG( "free args.handle: %d, rknpu_obj: %#llx, rknpu_obj->dma_addr: %#llx\n", args.handle, (__u64)(uintptr_t)rknpu_obj, (__u64)rknpu_obj->dma_addr); - vunmap(rknpu_obj->kv_addr); - rknpu_obj->kv_addr = NULL; + spin_lock(&rknpu_dev->lock); + session = file->private_data; + if (!session) { + spin_unlock(&rknpu_dev->lock); + ret = -EFAULT; + return ret; + } + list_for_each_entry_safe(entry, q, &session->list, head) { + if (entry == rknpu_obj) { + list_del(&entry->head); + break; + } + } + spin_unlock(&rknpu_dev->lock); - if (!rknpu_obj->owner) - dma_buf_put(dmabuf); + if (rknpu_obj == entry) { + vunmap(rknpu_obj->kv_addr); + rknpu_obj->kv_addr = NULL; - kfree(rknpu_obj); + if (!rknpu_obj->owner) + dma_buf_put(rknpu_obj->dmabuf); + + kfree(rknpu_obj); + } return 0; } @@ -209,11 +247,9 @@ int rknpu_mem_destroy_ioctl(struct rknpu_device *rknpu_dev, unsigned long data) * begin cpu access => for_cpu = true * end cpu access => for_cpu = false */ -static void __maybe_unused rknpu_dma_buf_sync(struct rknpu_device *rknpu_dev, - struct rknpu_mem_object *rknpu_obj, - u32 offset, u32 length, - enum dma_data_direction dir, - bool for_cpu) +static void __maybe_unused rknpu_dma_buf_sync( + struct rknpu_device *rknpu_dev, struct rknpu_mem_object *rknpu_obj, + u32 offset, u32 length, enum dma_data_direction dir, bool for_cpu) { struct device *dev = rknpu_dev->dev; struct sg_table *sgt = rknpu_obj->sgt; @@ -278,14 +314,12 @@ int rknpu_mem_sync_ioctl(struct rknpu_device *rknpu_dev, unsigned long data) #ifndef CONFIG_DMABUF_PARTIAL if (args.flags & RKNPU_MEM_SYNC_TO_DEVICE) { - rknpu_dma_buf_sync(rknpu_dev, rknpu_obj, - args.offset, args.size, DMA_TO_DEVICE, - false); + rknpu_dma_buf_sync(rknpu_dev, rknpu_obj, args.offset, args.size, + DMA_TO_DEVICE, false); } if (args.flags & RKNPU_MEM_SYNC_FROM_DEVICE) { - rknpu_dma_buf_sync(rknpu_dev, rknpu_obj, - args.offset, args.size, DMA_FROM_DEVICE, - true); + rknpu_dma_buf_sync(rknpu_dev, rknpu_obj, args.offset, args.size, + DMA_FROM_DEVICE, true); } #else if (args.flags & RKNPU_MEM_SYNC_TO_DEVICE) { diff --git a/drivers/rknpu/rknpu_mm.c b/drivers/rknpu/rknpu_mm.c index 9a13c3e256a4..a21bb6ded182 100644 --- a/drivers/rknpu/rknpu_mm.c +++ b/drivers/rknpu/rknpu_mm.c @@ -236,54 +236,3 @@ int rknpu_mm_dump(struct seq_file *m, void *data) return 0; } - -dma_addr_t rknpu_iommu_dma_alloc_iova(struct iommu_domain *domain, size_t size, - u64 dma_limit, struct device *dev) -{ - struct rknpu_iommu_dma_cookie *cookie = domain->iova_cookie; - struct iova_domain *iovad = &cookie->iovad; - unsigned long shift, iova_len, iova = 0; -#if (KERNEL_VERSION(5, 4, 0) > LINUX_VERSION_CODE) - dma_addr_t limit; -#endif - - shift = iova_shift(iovad); - iova_len = size >> shift; - /* - * 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); - -#if (KERNEL_VERSION(5, 10, 0) <= LINUX_VERSION_CODE) - 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_t(u64, dma_limit, domain->geometry.aperture_end); - -#if (KERNEL_VERSION(5, 4, 0) <= LINUX_VERSION_CODE) - iova = alloc_iova_fast(iovad, iova_len, dma_limit >> shift, true); -#else - limit = min_t(dma_addr_t, dma_limit >> shift, iovad->end_pfn); - - iova = alloc_iova_fast(iovad, iova_len, limit, true); -#endif - - return (dma_addr_t)iova << shift; -} - -void rknpu_iommu_dma_free_iova(struct rknpu_iommu_dma_cookie *cookie, - dma_addr_t iova, size_t size) -{ - struct iova_domain *iovad = &cookie->iovad; - - free_iova_fast(iovad, iova_pfn(iovad, iova), size >> iova_shift(iovad)); -} From 93687d7025046d67e1be450c89b628e6f9ef44c0 Mon Sep 17 00:00:00 2001 From: Luo Wei Date: Sat, 6 May 2023 16:35:43 +0800 Subject: [PATCH 024/223] arm64: dts: rockchip: rk3588-vehicle-evb: add dis_u2_susphy_quirk config Signed-off-by: Luo Wei Change-Id: I893e152316fd0e9fe5d75bd94b3c89eb05af8331 --- arch/arm64/boot/dts/rockchip/rk3588-vehicle-evb-v20.dtsi | 1 + arch/arm64/boot/dts/rockchip/rk3588-vehicle-evb.dtsi | 1 + 2 files changed, 2 insertions(+) diff --git a/arch/arm64/boot/dts/rockchip/rk3588-vehicle-evb-v20.dtsi b/arch/arm64/boot/dts/rockchip/rk3588-vehicle-evb-v20.dtsi index 4504495610b6..1b303e6fa6a4 100644 --- a/arch/arm64/boot/dts/rockchip/rk3588-vehicle-evb-v20.dtsi +++ b/arch/arm64/boot/dts/rockchip/rk3588-vehicle-evb-v20.dtsi @@ -304,5 +304,6 @@ &usbdrd_dwc3_1 { dr_mode = "host"; maximum-speed = "high-speed"; + snps,dis_u2_susphy_quirk; status = "okay"; }; diff --git a/arch/arm64/boot/dts/rockchip/rk3588-vehicle-evb.dtsi b/arch/arm64/boot/dts/rockchip/rk3588-vehicle-evb.dtsi index 166bcd049890..cf70138ee5bc 100644 --- a/arch/arm64/boot/dts/rockchip/rk3588-vehicle-evb.dtsi +++ b/arch/arm64/boot/dts/rockchip/rk3588-vehicle-evb.dtsi @@ -624,5 +624,6 @@ &usbdrd_dwc3_1 { dr_mode = "host"; maximum-speed = "high-speed"; + snps,dis_u2_susphy_quirk; status = "okay"; }; From d7e1493f44491676d2c8caabe065fbe90a5cca38 Mon Sep 17 00:00:00 2001 From: Cai YiWei Date: Sat, 6 May 2023 18:09:50 +0800 Subject: [PATCH 025/223] media: rockchip: isp: fix isp rockit frame rate err Change-Id: I1a730c26168f15be6c7a145bf7fe830316640447 Signed-off-by: Cai YiWei --- drivers/media/platform/rockchip/isp/capture.h | 1 + drivers/media/platform/rockchip/isp/capture_v32.c | 5 ++++- drivers/media/platform/rockchip/isp/isp_rockit.c | 6 ++++-- 3 files changed, 9 insertions(+), 3 deletions(-) diff --git a/drivers/media/platform/rockchip/isp/capture.h b/drivers/media/platform/rockchip/isp/capture.h index b76c075d90fc..bbdcf1e6df6e 100644 --- a/drivers/media/platform/rockchip/isp/capture.h +++ b/drivers/media/platform/rockchip/isp/capture.h @@ -287,6 +287,7 @@ struct rkisp_stream { struct frame_debug_info dbg; int conn_id; u32 memory; + u32 skip_frame; union { struct rkisp_stream_sp sp; struct rkisp_stream_mp mp; diff --git a/drivers/media/platform/rockchip/isp/capture_v32.c b/drivers/media/platform/rockchip/isp/capture_v32.c index a87ef1a878c5..05b5356841d2 100644 --- a/drivers/media/platform/rockchip/isp/capture_v32.c +++ b/drivers/media/platform/rockchip/isp/capture_v32.c @@ -1399,10 +1399,12 @@ static int mi_frame_end(struct rkisp_stream *stream, u32 state) struct rkisp_stream *vir = &dev->cap_dev.stream[RKISP_STREAM_VIR]; u64 ns = 0; - if (dev->skip_frame) { + if (dev->skip_frame || stream->skip_frame) { spin_lock_irqsave(&stream->vbq_lock, lock_flags); list_add_tail(&buf->queue, &stream->buf_queue); spin_unlock_irqrestore(&stream->vbq_lock, lock_flags); + if (stream->skip_frame) + stream->skip_frame--; goto end; } @@ -1540,6 +1542,7 @@ static int rkisp_start(struct rkisp_stream *stream) stream->ops->enable_mi(stream); stream->streaming = true; + stream->skip_frame = 0; return 0; } diff --git a/drivers/media/platform/rockchip/isp/isp_rockit.c b/drivers/media/platform/rockchip/isp/isp_rockit.c index b969592a5a2e..0ba72aad0c73 100644 --- a/drivers/media/platform/rockchip/isp/isp_rockit.c +++ b/drivers/media/platform/rockchip/isp/isp_rockit.c @@ -591,9 +591,11 @@ bool rkisp_rockit_ctrl_fps(struct rkisp_stream *stream) *fps_cnt = fps_in - dst_fps; *fps_cnt += dst_fps; - if (*fps_cnt < fps_in) + if (*fps_cnt < fps_in) { *is_discard = true; - else { + if (stream->next_buf || !list_empty(&stream->buf_queue)) + stream->skip_frame = 1; + } else { *fps_cnt -= fps_in; *is_discard = false; ++cur_fps[stream->id]; From e6d7502e9109c1f437a1974629fb529d7383504e Mon Sep 17 00:00:00 2001 From: Steven Liu Date: Sat, 6 May 2023 15:49:16 +0800 Subject: [PATCH 026/223] pinctrl/rockchip: fix rk3568 pull comments Signed-off-by: Steven Liu Change-Id: Ic06e6d428524b56bc8a227cb328bfe50ed0801f4 --- drivers/pinctrl/pinctrl-rockchip.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/pinctrl/pinctrl-rockchip.c b/drivers/pinctrl/pinctrl-rockchip.c index 73c81474d0f8..81191ae3f8ed 100644 --- a/drivers/pinctrl/pinctrl-rockchip.c +++ b/drivers/pinctrl/pinctrl-rockchip.c @@ -3231,7 +3231,7 @@ static int rockchip_set_pull(struct rockchip_pin_bank *bank, } } /* - * In the TRM, pull-up being 1 for everything except the GPIO0_D0-D6, + * In the TRM, pull-up being 1 for everything except the GPIO0_D3-D6, * where that pull up value becomes 3. */ if (ctrl->type == RK3568 && bank->bank_num == 0 && pin_num >= 27 && pin_num <= 30) { From 84a53e9fe3039d0c04582e31a8a342114f8f7f6b Mon Sep 17 00:00:00 2001 From: Frank Wang Date: Mon, 8 May 2023 17:03:02 +0800 Subject: [PATCH 027/223] dt-bindings: mailbox: rockchip: add tx poll period property Specify TX Done polling interval in milliseconds with the "rockchip,txpoll-period-ms" property. Signed-off-by: Frank Wang Change-Id: I91f25e6b5e6ef05cf90147b2e609c71c6ed61df7 --- Documentation/devicetree/bindings/mailbox/rockchip-mailbox.txt | 1 + 1 file changed, 1 insertion(+) diff --git a/Documentation/devicetree/bindings/mailbox/rockchip-mailbox.txt b/Documentation/devicetree/bindings/mailbox/rockchip-mailbox.txt index aba0813f1054..c3a5be01c1e4 100644 --- a/Documentation/devicetree/bindings/mailbox/rockchip-mailbox.txt +++ b/Documentation/devicetree/bindings/mailbox/rockchip-mailbox.txt @@ -20,6 +20,7 @@ Required properties: Optional properties : - wakeup-source: Mailbox irq can be used as a wakeup source. + - rockchip,txpoll-period-ms: TX Done polling interval in milliseconds. Example: -------- From 1d2a962eadeb9c21920795a482f82a721d1fcdf8 Mon Sep 17 00:00:00 2001 From: Frank Wang Date: Mon, 8 May 2023 15:30:04 +0800 Subject: [PATCH 028/223] mailbox: rockchip: amend txdone method to polling Since there is no txdone irq in the Rockchip mailbox IP, invoking mbox_chan_txdone()/mbox_client_txdone() after mbox_send_message() to tick the TX would be free the active request which have not been sent out if the controller returned the EBUSY state before. So amend the txdone method to polling to fix it. The TX polling interval can specify in DT with "rockchip,txpoll-period-ms" property, if it is not set, the driver would hardcode to 5 milliseconds. Signed-off-by: Frank Wang Change-Id: Ic26d3245dd8bd90ebad30fce9ece2f4452814f7f --- drivers/mailbox/rockchip-mailbox.c | 19 ++++++++++++++++++- 1 file changed, 18 insertions(+), 1 deletion(-) diff --git a/drivers/mailbox/rockchip-mailbox.c b/drivers/mailbox/rockchip-mailbox.c index a30949964ccb..66ebea280092 100644 --- a/drivers/mailbox/rockchip-mailbox.c +++ b/drivers/mailbox/rockchip-mailbox.c @@ -24,6 +24,8 @@ #define MAILBOX_B2A_CMD(x) (0x30 + (x) * 8) #define MAILBOX_B2A_DAT(x) (0x34 + (x) * 8) +#define MAILBOX_POLLING_MS 5 /* default polling interval 5ms */ + struct rockchip_mbox_data { int num_chans; }; @@ -99,10 +101,21 @@ static void rockchip_mbox_shutdown(struct mbox_chan *chan) spin_unlock(&mb->cfg_lock); } +static bool rockchip_mbox_last_tx_done(struct mbox_chan *chan) +{ + struct rockchip_mbox *mb = dev_get_drvdata(chan->mbox->dev); + struct rockchip_mbox_chan *chans = chan->con_priv; + u32 status; + + status = readl_relaxed(mb->mbox_base + MAILBOX_A2B_STATUS); + return !(status & (1U << chans->idx)); +} + static const struct mbox_chan_ops rockchip_mbox_chan_ops = { .send_data = rockchip_mbox_send_data, .startup = rockchip_mbox_startup, .shutdown = rockchip_mbox_shutdown, + .last_tx_done = rockchip_mbox_last_tx_done, }; int rockchip_mbox_read_msg(struct mbox_chan *chan, @@ -172,6 +185,7 @@ static int rockchip_mbox_probe(struct platform_device *pdev) const struct rockchip_mbox_data *drv_data; struct resource *res; int ret, irq, i; + u32 txpoll_period; if (!pdev->dev.of_node) return -ENODEV; @@ -203,9 +217,12 @@ static int rockchip_mbox_probe(struct platform_device *pdev) mb->mbox.dev = &pdev->dev; mb->mbox.num_chans = drv_data->num_chans; mb->mbox.ops = &rockchip_mbox_chan_ops; - mb->mbox.txdone_irq = true; spin_lock_init(&mb->cfg_lock); + mb->mbox.txdone_poll = true; + ret = device_property_read_u32(&pdev->dev, "rockchip,txpoll-period-ms", &txpoll_period); + mb->mbox.txpoll_period = !ret ? txpoll_period : MAILBOX_POLLING_MS; + res = platform_get_resource(pdev, IORESOURCE_MEM, 0); if (!res) return -ENODEV; From ebee330352cc6411470caac530909f4d2516e563 Mon Sep 17 00:00:00 2001 From: Algea Cao Date: Thu, 27 Apr 2023 16:30:50 +0800 Subject: [PATCH 029/223] drm/rockchip: dw_hdmi-qp: Fix kernel logo color error If other display port such as edp bind failed, hdmi will re-bind. The conditions for determining whether uboot logo is enabled are unreliable. Changing judgment flag to an unused reg. Signed-off-by: Algea Cao Change-Id: I2b634ae159934bb62ea1a08864bf8b1b9cbb479d --- drivers/gpu/drm/bridge/synopsys/dw-hdmi-qp.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/drivers/gpu/drm/bridge/synopsys/dw-hdmi-qp.c b/drivers/gpu/drm/bridge/synopsys/dw-hdmi-qp.c index 19d09adc0fbe..fe5ed0b3e4a9 100644 --- a/drivers/gpu/drm/bridge/synopsys/dw-hdmi-qp.c +++ b/drivers/gpu/drm/bridge/synopsys/dw-hdmi-qp.c @@ -3280,7 +3280,8 @@ __dw_hdmi_probe(struct platform_device *pdev, hdmi_writel(hdmi, 0, MAINUNIT_0_INT_MASK_N); hdmi_writel(hdmi, 0, MAINUNIT_1_INT_MASK_N); hdmi_writel(hdmi, 428571429, TIMER_BASE_CONFIG0); - if ((hdmi_readl(hdmi, CMU_STATUS) & DISPLAY_CLK_MONITOR) == DISPLAY_CLK_LOCKED) { + if (hdmi->phy.ops->read_hpd(hdmi, hdmi->phy.data) == connector_status_connected && + (hdmi_readl(hdmi, VIDEO_INTERFACE_CONFIG0) & BIT(21))) { hdmi->initialized = true; hdmi->disabled = false; } From 907d06745a16d2b3489052cd23b6f5426ec10b19 Mon Sep 17 00:00:00 2001 From: Damon Ding Date: Mon, 10 Apr 2023 14:31:57 +0800 Subject: [PATCH 030/223] drm/rockchip: vop2: fix hactive 4-pixel alignment in mode_fixup For RK3588 and RK3568, the hactive of video timing must be 4-pixel aligned. Signed-off-by: Damon Ding Change-Id: I2485e27420b365104c5c876708600fb59189e1af --- drivers/gpu/drm/rockchip/rockchip_drm_vop2.c | 21 ++++++++++++++++++++ 1 file changed, 21 insertions(+) diff --git a/drivers/gpu/drm/rockchip/rockchip_drm_vop2.c b/drivers/gpu/drm/rockchip/rockchip_drm_vop2.c index 2e00837c0fe3..65331d4564b8 100644 --- a/drivers/gpu/drm/rockchip/rockchip_drm_vop2.c +++ b/drivers/gpu/drm/rockchip/rockchip_drm_vop2.c @@ -6502,11 +6502,32 @@ static bool vop2_crtc_mode_fixup(struct drm_crtc *crtc, struct drm_display_mode *adj_mode) { struct vop2_video_port *vp = to_vop2_video_port(crtc); + struct vop2 *vop2 = vp->vop2; struct drm_connector *connector; struct drm_connector_list_iter conn_iter; struct drm_crtc_state *new_crtc_state = container_of(mode, struct drm_crtc_state, mode); struct rockchip_crtc_state *vcstate = to_rockchip_crtc_state(new_crtc_state); + /* + * For RK3568 and RK3588, the hactive of video timing must + * be 4-pixel aligned. + */ + if (vop2->version == VOP_VERSION_RK3568 || vop2->version == VOP_VERSION_RK3588) { + if (adj_mode->hdisplay % 4) { + u16 old_hdisplay = adj_mode->hdisplay; + u16 align; + + align = 4 - (adj_mode->hdisplay % 4); + adj_mode->hdisplay += align; + adj_mode->hsync_start += align; + adj_mode->hsync_end += align; + adj_mode->htotal += align; + + DRM_WARN("VP%d: hactive need to be aligned with 4-pixel, %d -> %d\n", + vp->id, old_hdisplay, adj_mode->hdisplay); + } + } + drm_mode_set_crtcinfo(adj_mode, CRTC_INTERLACE_HALVE_V | CRTC_STEREO_DOUBLE); if (mode->flags & DRM_MODE_FLAG_DBLCLK || vcstate->output_if & VOP_OUTPUT_IF_BT656) From b01336f37db475b026e583b2bc69e958c4de5431 Mon Sep 17 00:00:00 2001 From: Chandler Chen Date: Sat, 6 May 2023 11:02:23 +0800 Subject: [PATCH 031/223] arm64: dts: rockchip: rk3588s: add clock config for avsd 1.assign normal-rate for avsd aclk 2.add disable-auto-freq Signed-off-by: Chandler Chen Change-Id: I8424afa8155802ff6cbbeb8d0d340d9d3271c9b3 --- arch/arm64/boot/dts/rockchip/rk3588s.dtsi | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/arch/arm64/boot/dts/rockchip/rk3588s.dtsi b/arch/arm64/boot/dts/rockchip/rk3588s.dtsi index e6d593aa3810..08677a2e5b0a 100644 --- a/arch/arm64/boot/dts/rockchip/rk3588s.dtsi +++ b/arch/arm64/boot/dts/rockchip/rk3588s.dtsi @@ -3086,9 +3086,13 @@ interrupt-names = "irq_avsd"; clocks = <&cru ACLK_VPU>, <&cru HCLK_VPU>; clock-names = "aclk_vcodec", "hclk_vcodec"; + rockchip,normal-rates = <594000000>, <0>; + assigned-clocks = <&cru ACLK_VPU>; + assigned-clock-rates = <594000000>; resets = <&cru SRST_A_VPU>, <&cru SRST_H_VPU>; reset-names = "shared_video_a", "shared_video_h"; rockchip,skip-pmu-idle-request; + rockchip,disable-auto-freq; iommus = <&vdpu_mmu>; power-domains = <&power RK3588_PD_VDPU>; rockchip,srv = <&mpp_srv>; From 95949accd3b4f5ef3c1de71e4067cc4a92650f76 Mon Sep 17 00:00:00 2001 From: Yandong Lin Date: Mon, 20 Mar 2023 14:54:15 +0800 Subject: [PATCH 032/223] video: rockchip: mpp: fix some issue for ccu flow 1. Simplify some code. 2. Use mpp_time_diff_with_hw_time to get hw time. 3. Loop to get task from pending list after task enqueue hw successfully. Signed-off-by: Yandong Lin Change-Id: Icfecbc6b620efbf410076ca3765fb921d1665260 --- drivers/video/rockchip/mpp/mpp_rkvdec2_link.c | 184 +++++++++--------- 1 file changed, 92 insertions(+), 92 deletions(-) diff --git a/drivers/video/rockchip/mpp/mpp_rkvdec2_link.c b/drivers/video/rockchip/mpp/mpp_rkvdec2_link.c index c21687925081..eb0e62097460 100644 --- a/drivers/video/rockchip/mpp/mpp_rkvdec2_link.c +++ b/drivers/video/rockchip/mpp/mpp_rkvdec2_link.c @@ -1385,7 +1385,8 @@ static void rkvdec2_ccu_timeout_work(struct work_struct *work_s) return; } mpp = mpp_get_task_used_device(task, task->session); - mpp_err("%s, task timeout\n", dev_name(mpp->dev)); + mpp_err("%s, task %d state %#lx timeout\n", dev_name(mpp->dev), + task->task_index, task->state); set_bit(TASK_STATE_TIMEOUT, &task->state); atomic_inc(&mpp->reset_request); atomic_inc(&mpp->queue->reset_request); @@ -1878,73 +1879,70 @@ void rkvdec2_soft_ccu_worker(struct kthread_work *work_s) mpp_debug_enter(); - /* process all finished task in running list */ + /* 1. process all finished task in running list */ rkvdec2_soft_ccu_dequeue(queue); - /* process reset request */ + /* 2. process reset request */ if (atomic_read(&queue->reset_request)) { - if (rkvdec2_core_working(queue)) - goto out; - rkvdec2_ccu_power_on(queue, dec->ccu); - rkvdec2_soft_ccu_reset(queue, dec->ccu); + if (!rkvdec2_core_working(queue)) { + rkvdec2_ccu_power_on(queue, dec->ccu); + rkvdec2_soft_ccu_reset(queue, dec->ccu); + } } -get_task: - /* get one task form pending list */ - mutex_lock(&queue->pending_lock); - mpp_task = list_first_entry_or_null(&queue->pending_list, - struct mpp_task, queue_link); - mutex_unlock(&queue->pending_lock); - if (!mpp_task) - goto done; - - if (test_bit(TASK_STATE_ABORT, &mpp_task->state)) { + /* 3. process pending task */ + while (1) { + if (atomic_read(&queue->reset_request)) + break; + /* get one task form pending list */ mutex_lock(&queue->pending_lock); - list_del_init(&mpp_task->queue_link); - - set_bit(TASK_STATE_ABORT_READY, &mpp_task->state); - set_bit(TASK_STATE_PROC_DONE, &mpp_task->state); - + mpp_task = list_first_entry_or_null(&queue->pending_list, + struct mpp_task, queue_link); mutex_unlock(&queue->pending_lock); - wake_up(&mpp_task->wait); - kref_put(&mpp_task->ref, rkvdec2_link_free_task); - goto get_task; - } - /* find one core is idle */ - mpp = rkvdec2_get_idle_core(queue, mpp_task); - if (!mpp) - goto out; + if (!mpp_task) + break; - if (timing_en) { - mpp_task->on_run = ktime_get(); - set_bit(TASK_TIMING_RUN, &mpp_task->state); + if (test_bit(TASK_STATE_ABORT, &mpp_task->state)) { + mutex_lock(&queue->pending_lock); + list_del_init(&mpp_task->queue_link); + + set_bit(TASK_STATE_ABORT_READY, &mpp_task->state); + set_bit(TASK_STATE_PROC_DONE, &mpp_task->state); + + mutex_unlock(&queue->pending_lock); + wake_up(&mpp_task->wait); + kref_put(&mpp_task->ref, rkvdec2_link_free_task); + continue; + } + /* find one core is idle */ + mpp = rkvdec2_get_idle_core(queue, mpp_task); + if (!mpp) + break; + + if (timing_en) { + mpp_task->on_run = ktime_get(); + set_bit(TASK_TIMING_RUN, &mpp_task->state); + } + + /* set session index */ + rkvdec2_set_core_info(mpp_task->reg, mpp_task->session->index); + /* set rcb buffer */ + mpp_set_rcbbuf(mpp, mpp_task->session, mpp_task); + + INIT_DELAYED_WORK(&mpp_task->timeout_work, rkvdec2_ccu_timeout_work); + rkvdec2_ccu_power_on(queue, dec->ccu); + rkvdec2_soft_ccu_enqueue(mpp, mpp_task); + /* pending to running */ + mpp_taskqueue_pending_to_run(queue, mpp_task); + set_bit(TASK_STATE_RUNNING, &mpp_task->state); } - /* set session index */ - rkvdec2_set_core_info(mpp_task->reg, mpp_task->session->index); - /* set rcb buffer */ - mpp_set_rcbbuf(mpp, mpp_task->session, mpp_task); - - /* pending to running */ - mutex_lock(&queue->pending_lock); - list_move_tail(&mpp_task->queue_link, &queue->running_list); - mutex_unlock(&queue->pending_lock); - set_bit(TASK_STATE_RUNNING, &mpp_task->state); - - mpp_debug(DEBUG_TASK_INFO, "pid %d, start hw %s\n", - mpp_task->session->pid, dev_name(mpp->dev)); - set_bit(TASK_STATE_START, &mpp_task->state); - INIT_DELAYED_WORK(&mpp_task->timeout_work, rkvdec2_ccu_timeout_work); - schedule_delayed_work(&mpp_task->timeout_work, msecs_to_jiffies(WORK_TIMEOUT_MS)); - rkvdec2_ccu_power_on(queue, dec->ccu); - rkvdec2_soft_ccu_enqueue(mpp, mpp_task); - -done: + /* 4. poweroff when running and pending list are empty */ if (list_empty(&queue->running_list) && list_empty(&queue->pending_list)) rkvdec2_ccu_power_off(queue, dec->ccu); -out: - /* session detach out of queue */ + + /* 5. check session detach out of queue */ rkvdec2_ccu_link_session_detach(mpp, queue); mpp_debug_leave(); @@ -2089,9 +2087,12 @@ static int rkvdec2_hard_ccu_dequeue(struct mpp_taskqueue *queue, ccu_decoded_num, ccu_total_dec_num); if (irq_status || timeout_flag || abort_flag) { + struct rkvdec2_dev *dec = to_rkvdec2_dev(queue->cores[0]); + set_bit(TASK_STATE_HANDLE, &mpp_task->state); cancel_delayed_work(&mpp_task->timeout_work); - mpp_time_diff(mpp_task); + mpp_task->hw_cycles = tb_reg[hw->tb_reg_cycle]; + mpp_time_diff_with_hw_time(mpp_task, dec->cycle_clk->real_rate_hz); task->irq_status = irq_status; if (irq_status) @@ -2309,6 +2310,7 @@ static int rkvdec2_hard_ccu_enqueue(struct rkvdec2_ccu *ccu, { u32 ccu_en, work_mode, link_mode; struct rkvdec2_task *task = to_rkvdec2_task(mpp_task); + u32 timing_en = mpp->srv->timing_en; mpp_debug_enter(); @@ -2358,20 +2360,15 @@ static int rkvdec2_hard_ccu_enqueue(struct rkvdec2_ccu *ccu, mpp_iommu_flush_tlb(mpp->iommu_info); /* wmb */ wmb(); + INIT_DELAYED_WORK(&mpp_task->timeout_work, rkvdec2_ccu_timeout_work); + mpp_task_run_begin(mpp_task, timing_en, MPP_WORK_TIMEOUT_DELAY); /* configure done */ writel(RKVDEC_CCU_BIT_CFG_DONE, ccu->reg_base + RKVDEC_CCU_CFG_DONE_BASE); + mpp_task_run_end(mpp_task, timing_en); - mpp_time_record(mpp_task); - set_bit(TASK_STATE_START, &mpp_task->state); - INIT_DELAYED_WORK(&mpp_task->timeout_work, rkvdec2_ccu_timeout_work); - schedule_delayed_work(&mpp_task->timeout_work, msecs_to_jiffies(WORK_TIMEOUT_MS)); /* pending to running */ - if (!test_bit(TASK_STATE_RUNNING, &mpp_task->state)) { - mutex_lock(&queue->pending_lock); - set_bit(TASK_STATE_RUNNING, &mpp_task->state); - list_move_tail(&mpp_task->queue_link, &queue->running_list); - mutex_unlock(&queue->pending_lock); - } + set_bit(TASK_STATE_RUNNING, &mpp_task->state); + mpp_taskqueue_pending_to_run(queue, mpp_task); mpp_dbg_ccu("session %d task %d iova=%08x task->state=%lx link_mode=%08x\n", mpp_task->session->index, mpp_task->task_index, (u32)task->table->iova, mpp_task->state, @@ -2488,10 +2485,10 @@ void rkvdec2_hard_ccu_worker(struct kthread_work *work_s) mpp_debug_enter(); - /* process all finished task in running list */ + /* 1. process all finished task in running list */ rkvdec2_hard_ccu_dequeue(queue, dec->ccu, dec->link_dec->info); - /* process reset request */ + /* 2. process reset request */ if (atomic_read(&queue->reset_request) && (list_empty(&queue->running_list) || !dec->ccu->ccu_core_work_mode)) { /* @@ -2516,41 +2513,44 @@ void rkvdec2_hard_ccu_worker(struct kthread_work *work_s) if (!list_empty(&queue->running_list)) rkvdec2_hard_ccu_resend_tasks(mpp, queue); } -get_task: - /* get one task form pending list */ - mutex_lock(&queue->pending_lock); - mpp_task = list_first_entry_or_null(&queue->pending_list, - struct mpp_task, queue_link); - mutex_unlock(&queue->pending_lock); - if (!mpp_task) - goto done; - if (test_bit(TASK_STATE_ABORT, &mpp_task->state)) { + /* 3. process pending task */ + while (1) { + if (atomic_read(&queue->reset_request)) + break; + + /* get one task form pending list */ mutex_lock(&queue->pending_lock); - list_del_init(&mpp_task->queue_link); + mpp_task = list_first_entry_or_null(&queue->pending_list, + struct mpp_task, queue_link); mutex_unlock(&queue->pending_lock); - kref_put(&mpp_task->ref, mpp_free_task); - goto get_task; + + if (!mpp_task) + break; + if (test_bit(TASK_STATE_ABORT, &mpp_task->state)) { + mutex_lock(&queue->pending_lock); + list_del_init(&mpp_task->queue_link); + mutex_unlock(&queue->pending_lock); + kref_put(&mpp_task->ref, mpp_free_task); + continue; + } + + mpp_task = rkvdec2_hard_ccu_prepare(mpp_task, dec->ccu, dec->link_dec->info); + if (!mpp_task) + break; + + rkvdec2_ccu_power_on(queue, dec->ccu); + rkvdec2_hard_ccu_enqueue(dec->ccu, mpp_task, queue, mpp); } - if (atomic_read(&queue->reset_request)) - mpp_task = NULL; - else - mpp_task = rkvdec2_hard_ccu_prepare(mpp_task, dec->ccu, dec->link_dec->info); - - if (!mpp_task) - goto done; - - rkvdec2_ccu_power_on(queue, dec->ccu); - rkvdec2_hard_ccu_enqueue(dec->ccu, mpp_task, queue, mpp); -done: + /* 4. poweroff when running and pending list are empty */ mutex_lock(&queue->pending_lock); if (list_empty(&queue->running_list) && list_empty(&queue->pending_list)) rkvdec2_ccu_power_off(queue, dec->ccu); mutex_unlock(&queue->pending_lock); - /* session detach out of queue */ + /* 5. check session detach out of queue */ mpp_session_cleanup_detach(queue, work_s); mpp_debug_leave(); From 23bc9d31c3c374ac731291ecfda2959e52fbb92e Mon Sep 17 00:00:00 2001 From: Wyon Bi Date: Sat, 6 May 2023 08:41:09 +0000 Subject: [PATCH 033/223] mfd: max96745: Add pwdnb GPIO support Signed-off-by: Wyon Bi Change-Id: I1e19c365325196c3d6ff652079db2f816f31f4ad --- drivers/mfd/max96745.c | 14 ++++++++++++++ include/linux/mfd/max96745.h | 1 + 2 files changed, 15 insertions(+) diff --git a/drivers/mfd/max96745.c b/drivers/mfd/max96745.c index c212aa5edccb..f65ba34a3b22 100644 --- a/drivers/mfd/max96745.c +++ b/drivers/mfd/max96745.c @@ -108,6 +108,9 @@ static void max96745_power_off(void *data) { struct max96745 *max96745 = data; + if (max96745->pwdnb_gpio) + gpiod_direction_output(max96745->pwdnb_gpio, 1); + if (max96745->enable_gpio) gpiod_direction_output(max96745->enable_gpio, 0); } @@ -124,6 +127,11 @@ static void max96745_power_on(struct max96745 *max96745) msleep(200); } + if (max96745->pwdnb_gpio) { + gpiod_direction_output(max96745->pwdnb_gpio, 0); + msleep(30); + } + /* Set for I2C Fast-mode speed */ regmap_write(max96745->regmap, 0x0070, 0x16); @@ -253,6 +261,12 @@ static int max96745_i2c_probe(struct i2c_client *client) return dev_err_probe(dev, PTR_ERR(max96745->enable_gpio), "failed to get enable GPIO\n"); + max96745->pwdnb_gpio = devm_gpiod_get_optional(dev, "pwdnb", + GPIOD_ASIS); + if (IS_ERR(max96745->pwdnb_gpio)) + return dev_err_probe(dev, PTR_ERR(max96745->pwdnb_gpio), + "failed to get pwdnb GPIO\n"); + max96745->extcon = devm_extcon_dev_allocate(dev, max96745_cable); if (IS_ERR(max96745->extcon)) return dev_err_probe(dev, PTR_ERR(max96745->extcon), diff --git a/include/linux/mfd/max96745.h b/include/linux/mfd/max96745.h index f4784ce52284..f2159a23b2e8 100644 --- a/include/linux/mfd/max96745.h +++ b/include/linux/mfd/max96745.h @@ -15,6 +15,7 @@ struct max96745 { struct regmap *regmap; struct i2c_mux_core *muxc; struct gpio_desc *enable_gpio; + struct gpio_desc *pwdnb_gpio; struct extcon_dev *extcon; bool idle_disc; }; From 64d9662793eb04080033d858cf364800d83f7fd3 Mon Sep 17 00:00:00 2001 From: Wyon Bi Date: Sat, 6 May 2023 08:43:23 +0000 Subject: [PATCH 034/223] drm/panel: maxim-max96752f: Add power supply regulator support Signed-off-by: Wyon Bi Change-Id: Idbc26fb9d76b5c6afc1ddd35de715b22157ccbcd --- drivers/gpu/drm/panel/panel-maxim-max96752f.c | 89 ++++++++++++++++--- 1 file changed, 76 insertions(+), 13 deletions(-) diff --git a/drivers/gpu/drm/panel/panel-maxim-max96752f.c b/drivers/gpu/drm/panel/panel-maxim-max96752f.c index 7212f1ccd437..de5f08198e99 100644 --- a/drivers/gpu/drm/panel/panel-maxim-max96752f.c +++ b/drivers/gpu/drm/panel/panel-maxim-max96752f.c @@ -13,6 +13,7 @@ #include #include #include +#include #include #include