From 61b70d7bc1df5843cd8fd9b4c6d8aed532080d66 Mon Sep 17 00:00:00 2001 From: Wesley Yao Date: Mon, 7 Nov 2022 15:52:23 +0800 Subject: [PATCH 01/16] dt-bindings: devfreq: rockchip_dfi: Add rk3528 support Signed-off-by: Wesley Yao Change-Id: I2ecbe8788d046ce745157042b9038380d732590d --- Documentation/devicetree/bindings/devfreq/event/rockchip-dfi.txt | 1 + 1 file changed, 1 insertion(+) diff --git a/Documentation/devicetree/bindings/devfreq/event/rockchip-dfi.txt b/Documentation/devicetree/bindings/devfreq/event/rockchip-dfi.txt index 8534c99d9f00..11207b77bfa8 100644 --- a/Documentation/devicetree/bindings/devfreq/event/rockchip-dfi.txt +++ b/Documentation/devicetree/bindings/devfreq/event/rockchip-dfi.txt @@ -10,6 +10,7 @@ Required properties: - "rockchip,rk3328-dfi" - for RK3328 SoCs. - "rockchip,rk3368-dfi" - for RK3368 SoCs. - "rockchip,rk3399-dfi" - for RK3399 SoCs. + - "rockchip,rk3528-dfi" - for RK3528 SoCs. - "rockchip,rk3562-dfi" - for RK3562 SoCs. - "rockchip,rk3568-dfi" - for RK3568 SoCs. - "rockchip,rv1126-dfi" - for RV1126 SoCs. From daf1596e95170c3d1523cfae97b28b687b6e8e16 Mon Sep 17 00:00:00 2001 From: Wesley Yao Date: Mon, 7 Nov 2022 15:57:20 +0800 Subject: [PATCH 02/16] PM / devfreq: rockchip-dfi: Add support for rk3528 dfi Signed-off-by: Wesley Yao Change-Id: Iaf29eebe4ccf3e9a25f5a76cd727af2410d514b3 --- drivers/devfreq/event/rockchip-dfi.c | 42 ++++++++++++++++++++++++++++ 1 file changed, 42 insertions(+) diff --git a/drivers/devfreq/event/rockchip-dfi.c b/drivers/devfreq/event/rockchip-dfi.c index 4aa090e78b0a..e65e4890da7d 100644 --- a/drivers/devfreq/event/rockchip-dfi.c +++ b/drivers/devfreq/event/rockchip-dfi.c @@ -52,6 +52,10 @@ #define RK3368_DFI_EN (0x30003 << 5) #define RK3368_DFI_DIS (0x30000 << 5) +#define RK3528_PMUGRF_OFFSET 0x70000 +#define RK3528_PMUGRF_OS_REG18 0x248 +#define RK3528_PMUGRF_OS_REG19 0x24c + #define MAX_DMC_NUM_CH 4 #define READ_DRAMTYPE_INFO(n) (((n) >> 13) & 0x7) #define READ_CH_INFO(n) (((n) >> 28) & 0x3) @@ -723,6 +727,41 @@ static __maybe_unused __init int rk3328_dfi_init(struct platform_device *pdev, return 0; } +static __maybe_unused __init int rk3528_dfi_init(struct platform_device *pdev, + struct rockchip_dfi *data, + struct devfreq_event_desc *desc) +{ + struct device_node *np = pdev->dev.of_node, *node; + struct resource *res; + u32 val_18, val_19; + + res = platform_get_resource(pdev, IORESOURCE_MEM, 0); + data->regs = devm_ioremap_resource(&pdev->dev, res); + if (IS_ERR(data->regs)) + return PTR_ERR(data->regs); + + node = of_parse_phandle(np, "rockchip,grf", 0); + if (node) { + data->regmap_grf = syscon_node_to_regmap(node); + if (IS_ERR(data->regmap_grf)) + return PTR_ERR(data->regmap_grf); + } + + regmap_read(data->regmap_grf, RK3528_PMUGRF_OFFSET + RK3528_PMUGRF_OS_REG18, &val_18); + regmap_read(data->regmap_grf, RK3528_PMUGRF_OFFSET + RK3528_PMUGRF_OS_REG19, &val_19); + if (READ_SYSREG_VERSION(val_19) >= 0x3) + data->dram_type = READ_DRAMTYPE_INFO_V3(val_18, val_19); + else + data->dram_type = READ_DRAMTYPE_INFO(val_18); + data->count_rate = 2; + data->ch_msk = 1; + data->clk = NULL; + + desc->ops = &rockchip_dfi_ops; + + return 0; +} + static const struct of_device_id rockchip_dfi_id_match[] = { #ifdef CONFIG_CPU_PX30 { .compatible = "rockchip,px30-dfi", .data = px30_dfi_init }, @@ -745,6 +784,9 @@ static const struct of_device_id rockchip_dfi_id_match[] = { #ifdef CONFIG_CPU_RK3399 { .compatible = "rockchip,rk3399-dfi", .data = rockchip_dfi_init }, #endif +#ifdef CONFIG_CPU_RK3528 + { .compatible = "rockchip,rk3528-dfi", .data = rk3528_dfi_init }, +#endif #ifdef CONFIG_CPU_RK3562 { .compatible = "rockchip,rk3562-dfi", .data = px30_dfi_init }, #endif From 1f98b6284d5be6f08c52f90c199de2995163dac5 Mon Sep 17 00:00:00 2001 From: Wesley Yao Date: Mon, 7 Nov 2022 15:58:23 +0800 Subject: [PATCH 03/16] dt-bindings: devfreq: rockchip_dmc: Add rk3528 support Signed-off-by: Wesley Yao Change-Id: I3150649f8f9f3083d54ba80de706937b4a0852da --- Documentation/devicetree/bindings/devfreq/rockchip_dmc.txt | 1 + 1 file changed, 1 insertion(+) diff --git a/Documentation/devicetree/bindings/devfreq/rockchip_dmc.txt b/Documentation/devicetree/bindings/devfreq/rockchip_dmc.txt index ff5c92f570ec..3f1f99c221a4 100644 --- a/Documentation/devicetree/bindings/devfreq/rockchip_dmc.txt +++ b/Documentation/devicetree/bindings/devfreq/rockchip_dmc.txt @@ -10,6 +10,7 @@ Required properties: - "rockchip,rk3308-dmc" - for RK3308 SoCs. - "rockchip,rk3328-dmc" - for RK3328 SoCs. - "rockchip,rk3399-dmc" - for RK3399 SoCs. + - "rockchip,rk3528-dmc" - for RK3528 SoCs. - "rockchip,rk3562-dmc" - for RK3562 SoCs. - "rockchip,rk3568-dmc" - for RK3568 SoCs. - "rockchip,rk3588-dmc" - for RK3588 SoCs. From a822375383a2cfb770b9ddf3d404cce56f5712f5 Mon Sep 17 00:00:00 2001 From: Wesley Yao Date: Mon, 7 Nov 2022 16:14:00 +0800 Subject: [PATCH 04/16] PM / devfreq: rockchip_dmc: Add support for rk3528 Signed-off-by: Wesley Yao Change-Id: I90b09d044769747e8858c23f3087c00b2fcb2f12 --- drivers/devfreq/rockchip_dmc.c | 75 +++++++++++++++++++++++++++++++++- 1 file changed, 74 insertions(+), 1 deletion(-) diff --git a/drivers/devfreq/rockchip_dmc.c b/drivers/devfreq/rockchip_dmc.c index 073e679701af..b32d32b7cef2 100644 --- a/drivers/devfreq/rockchip_dmc.c +++ b/drivers/devfreq/rockchip_dmc.c @@ -1771,6 +1771,79 @@ static __maybe_unused int rk3399_dmc_init(struct platform_device *pdev, return 0; } +static __maybe_unused int rk3528_dmc_init(struct platform_device *pdev, + struct rockchip_dmcfreq *dmcfreq) +{ + struct arm_smccc_res res; + int ret; + int complt_irq; + u32 complt_hwirq; + struct irq_data *complt_irq_data; + + res = sip_smc_dram(0, 0, ROCKCHIP_SIP_CONFIG_DRAM_GET_VERSION); + dev_notice(&pdev->dev, "current ATF version 0x%lx\n", res.a1); + if (res.a0 || res.a1 < 0x100) { + dev_err(&pdev->dev, "trusted firmware need update to V1.00 and above.\n"); + return -ENXIO; + } + + /* + * first 4KB is used for interface parameters + * after 4KB is dts parameters + * request share memory size 4KB * 2 + */ + res = sip_smc_request_share_mem(2, SHARE_PAGE_TYPE_DDR); + if (res.a0 != 0) { + dev_err(&pdev->dev, "no ATF memory for init\n"); + return -ENOMEM; + } + ddr_psci_param = (struct share_params *)res.a1; + /* Clear ddr_psci_param, size is 4KB * 2 */ + memset_io(ddr_psci_param, 0x0, 4096 * 2); + + wait_ctrl.dcf_en = 0; + + init_waitqueue_head(&wait_ctrl.wait_wq); + wait_ctrl.wait_en = 1; + wait_ctrl.wait_time_out_ms = 17 * 5; + + complt_irq = platform_get_irq_byname(pdev, "complete"); + if (complt_irq < 0) { + dev_err(&pdev->dev, "no IRQ for complt_irq: %d\n", complt_irq); + return complt_irq; + } + wait_ctrl.complt_irq = complt_irq; + + ret = devm_request_irq(&pdev->dev, complt_irq, wait_dcf_complete_irq, + 0, dev_name(&pdev->dev), &wait_ctrl); + if (ret < 0) { + dev_err(&pdev->dev, "cannot request complt_irq\n"); + return ret; + } + disable_irq(complt_irq); + + complt_irq_data = irq_get_irq_data(complt_irq); + complt_hwirq = irqd_to_hwirq(complt_irq_data); + ddr_psci_param->complt_hwirq = complt_hwirq; + + res = sip_smc_dram(SHARE_PAGE_TYPE_DDR, 0, ROCKCHIP_SIP_CONFIG_DRAM_INIT); + if (res.a0) { + dev_err(&pdev->dev, "rockchip_sip_config_dram_init error:%lx\n", res.a0); + return -ENOMEM; + } + + ret = rockchip_get_freq_info(dmcfreq); + if (ret < 0) { + dev_err(&pdev->dev, "cannot get frequency info\n"); + return ret; + } + dmcfreq->is_set_rate_direct = true; + + dmcfreq->set_auto_self_refresh = rockchip_ddr_set_auto_self_refresh; + + return 0; +} + static __maybe_unused int rk3568_dmc_init(struct platform_device *pdev, struct rockchip_dmcfreq *dmcfreq) { @@ -2039,7 +2112,7 @@ static const struct of_device_id rockchip_dmcfreq_of_match[] = { { .compatible = "rockchip,rk3399-dmc", .data = rk3399_dmc_init }, #endif #if IS_ENABLED(CONFIG_CPU_RK3528) - { .compatible = "rockchip,rk3528-dmc", .data = NULL }, + { .compatible = "rockchip,rk3528-dmc", .data = rk3528_dmc_init }, #endif #if IS_ENABLED(CONFIG_CPU_RK3562) { .compatible = "rockchip,rk3562-dmc", .data = rk3568_dmc_init }, From 31dd4c38e5b35daff974ed22caa55871b6342ae7 Mon Sep 17 00:00:00 2001 From: Wesley Yao Date: Thu, 10 Nov 2022 18:11:21 +0800 Subject: [PATCH 05/16] arm64: dts: rockchip: rk3528: Add ddr related nodes Signed-off-by: Wesley Yao Change-Id: I9d728a6a26c1156976958d242297e2a14ca28c66 --- arch/arm64/boot/dts/rockchip/rk3528.dtsi | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) diff --git a/arch/arm64/boot/dts/rockchip/rk3528.dtsi b/arch/arm64/boot/dts/rockchip/rk3528.dtsi index 66d48e7fcbdf..c3edb864822e 100644 --- a/arch/arm64/boot/dts/rockchip/rk3528.dtsi +++ b/arch/arm64/boot/dts/rockchip/rk3528.dtsi @@ -366,9 +366,20 @@ dmc: dmc { compatible = "rockchip,rk3528-dmc"; + interrupts = ; + interrupt-names = "complete"; + devfreq-events = <&dfi>; clocks = <&scmi_clk SCMI_CLK_DDR>; clock-names = "dmc_clk"; operating-points-v2 = <&dmc_opp_table>; + upthreshold = <40>; + downdifferential = <20>; + system-status-level = < + /* system status freq level */ + SYS_STATUS_NORMAL DMC_FREQ_LEVEL_HIGH + >; + auto-min-freq = <324000>; + auto-freq-en = <0>; status = "disabled"; }; @@ -1544,6 +1555,13 @@ }; }; + dfi: dfi@ff930000 { + reg = <0x0 0xff930000 0x0 0x400>; + compatible = "rockchip,rk3528-dfi"; + rockchip,grf = <&grf>; + status = "disabled"; + }; + spi0: spi@ff9c0000 { compatible = "rockchip,rk3066-spi"; reg = <0x0 0xff9c0000 0x0 0x1000>; From d285000cc83d3a24449f57c6caa6a661237b5b7a Mon Sep 17 00:00:00 2001 From: Wesley Yao Date: Fri, 14 Apr 2023 14:34:31 +0800 Subject: [PATCH 06/16] arm64: dts: rockchip: rk3528-evb: Enable dfi Signed-off-by: Wesley Yao Change-Id: Iccc421ab21a05f3f0f74a01dd6c334d0cc0b27ca --- arch/arm64/boot/dts/rockchip/rk3528-evb.dtsi | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/arch/arm64/boot/dts/rockchip/rk3528-evb.dtsi b/arch/arm64/boot/dts/rockchip/rk3528-evb.dtsi index 4d95d6276692..915a42c20b09 100644 --- a/arch/arm64/boot/dts/rockchip/rk3528-evb.dtsi +++ b/arch/arm64/boot/dts/rockchip/rk3528-evb.dtsi @@ -292,6 +292,10 @@ status = "okay"; }; +&dfi { + status = "okay"; +}; + &display_subsystem { status = "okay"; }; From fc947972add27ae94ed7dfb57246eb9e682a662e Mon Sep 17 00:00:00 2001 From: Wesley Yao Date: Fri, 14 Apr 2023 14:35:07 +0800 Subject: [PATCH 07/16] arm64: dts: rockchip: rk3528-demo: Enable dfi Signed-off-by: Wesley Yao Change-Id: I10b208e45b091d7e0090b6fca7ce68d35e7f2f48 --- arch/arm64/boot/dts/rockchip/rk3528-demo.dtsi | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/arch/arm64/boot/dts/rockchip/rk3528-demo.dtsi b/arch/arm64/boot/dts/rockchip/rk3528-demo.dtsi index 94d2bcaeb017..d9310275cf5f 100644 --- a/arch/arm64/boot/dts/rockchip/rk3528-demo.dtsi +++ b/arch/arm64/boot/dts/rockchip/rk3528-demo.dtsi @@ -258,6 +258,10 @@ status = "okay"; }; +&dfi { + status = "okay"; +}; + &display_subsystem { status = "okay"; }; From 7e9e093b8c04bfecea22c319f7e05125d062761a Mon Sep 17 00:00:00 2001 From: Zefa Chen Date: Tue, 6 Jun 2023 11:29:47 +0800 Subject: [PATCH 08/16] media: rockchip: vicap: add security testing for output format Signed-off-by: Zefa Chen Change-Id: I6c48543295eeef7c67e192bf16da44e533c07f09 --- drivers/media/platform/rockchip/cif/capture.c | 163 +++++++++++++++++- 1 file changed, 162 insertions(+), 1 deletion(-) diff --git a/drivers/media/platform/rockchip/cif/capture.c b/drivers/media/platform/rockchip/cif/capture.c index a188e552e969..c761ae9ceaa5 100644 --- a/drivers/media/platform/rockchip/cif/capture.c +++ b/drivers/media/platform/rockchip/cif/capture.c @@ -345,8 +345,35 @@ static const struct cif_output_fmt out_fmts[] = { .raw_bpp = 10, .csi_fmt_val = CSI_WRDDR_TYPE_RAW10, .fmt_type = CIF_FMT_TYPE_RAW, + }, { + .fourcc = V4L2_PIX_FMT_SRGGB16, + .cplanes = 1, + .mplanes = 1, + .bpp = { 16 }, + .raw_bpp = 16, + .fmt_type = CIF_FMT_TYPE_RAW, + }, { + .fourcc = V4L2_PIX_FMT_SGRBG16, + .cplanes = 1, + .mplanes = 1, + .bpp = { 16 }, + .raw_bpp = 16, + .fmt_type = CIF_FMT_TYPE_RAW, + }, { + .fourcc = V4L2_PIX_FMT_SGBRG16, + .cplanes = 1, + .mplanes = 1, + .bpp = { 16 }, + .raw_bpp = 16, + .fmt_type = CIF_FMT_TYPE_RAW, + }, { + .fourcc = V4L2_PIX_FMT_SBGGR16, + .cplanes = 1, + .mplanes = 1, + .bpp = { 16 }, + .raw_bpp = 16, + .fmt_type = CIF_FMT_TYPE_RAW, } - /* TODO: We can support NV12M/NV21M/NV16M/NV61M too */ }; @@ -524,6 +551,136 @@ static const struct cif_input_fmt in_fmts[] = { } }; +static int rkcif_output_fmt_check(struct rkcif_stream *stream, + const struct cif_output_fmt *output_fmt) +{ + const struct cif_input_fmt *input_fmt = stream->cif_fmt_in; + struct csi_channel_info *channel = &stream->cifdev->channels[stream->id]; + int ret = -EINVAL; + + switch (input_fmt->mbus_code) { + case MEDIA_BUS_FMT_YUYV8_2X8: + case MEDIA_BUS_FMT_YVYU8_2X8: + case MEDIA_BUS_FMT_UYVY8_2X8: + case MEDIA_BUS_FMT_VYUY8_2X8: + if (output_fmt->fourcc == V4L2_PIX_FMT_NV16 || + output_fmt->fourcc == V4L2_PIX_FMT_NV61 || + output_fmt->fourcc == V4L2_PIX_FMT_NV12 || + output_fmt->fourcc == V4L2_PIX_FMT_NV21 || + output_fmt->fourcc == V4L2_PIX_FMT_YUYV || + output_fmt->fourcc == V4L2_PIX_FMT_YVYU || + output_fmt->fourcc == V4L2_PIX_FMT_UYVY || + output_fmt->fourcc == V4L2_PIX_FMT_VYUY) + ret = 0; + break; + case MEDIA_BUS_FMT_SBGGR8_1X8: + case MEDIA_BUS_FMT_SGBRG8_1X8: + case MEDIA_BUS_FMT_SGRBG8_1X8: + case MEDIA_BUS_FMT_SRGGB8_1X8: + case MEDIA_BUS_FMT_Y8_1X8: + if (output_fmt->fourcc == V4L2_PIX_FMT_SRGGB8 || + output_fmt->fourcc == V4L2_PIX_FMT_SGRBG8 || + output_fmt->fourcc == V4L2_PIX_FMT_SGBRG8 || + output_fmt->fourcc == V4L2_PIX_FMT_SBGGR8 || + output_fmt->fourcc == V4L2_PIX_FMT_GREY) + ret = 0; + break; + case MEDIA_BUS_FMT_SBGGR10_1X10: + case MEDIA_BUS_FMT_SGBRG10_1X10: + case MEDIA_BUS_FMT_SGRBG10_1X10: + case MEDIA_BUS_FMT_SRGGB10_1X10: + case MEDIA_BUS_FMT_Y10_1X10: + if (output_fmt->fourcc == V4L2_PIX_FMT_SRGGB10 || + output_fmt->fourcc == V4L2_PIX_FMT_SGRBG10 || + output_fmt->fourcc == V4L2_PIX_FMT_SGBRG10 || + output_fmt->fourcc == V4L2_PIX_FMT_SBGGR10 || + output_fmt->fourcc == V4L2_PIX_FMT_Y10) + ret = 0; + break; + case MEDIA_BUS_FMT_SBGGR12_1X12: + case MEDIA_BUS_FMT_SGBRG12_1X12: + case MEDIA_BUS_FMT_SGRBG12_1X12: + case MEDIA_BUS_FMT_SRGGB12_1X12: + case MEDIA_BUS_FMT_Y12_1X12: + if (output_fmt->fourcc == V4L2_PIX_FMT_SRGGB12 || + output_fmt->fourcc == V4L2_PIX_FMT_SGRBG12 || + output_fmt->fourcc == V4L2_PIX_FMT_SGBRG12 || + output_fmt->fourcc == V4L2_PIX_FMT_SBGGR12 || + output_fmt->fourcc == V4L2_PIX_FMT_Y12) + ret = 0; + break; + case MEDIA_BUS_FMT_RGB888_1X24: + case MEDIA_BUS_FMT_BGR888_1X24: + if (output_fmt->fourcc == V4L2_PIX_FMT_RGB24 || + output_fmt->fourcc == V4L2_PIX_FMT_BGR24) + ret = 0; + break; + case MEDIA_BUS_FMT_RGB565_1X16: + if (output_fmt->fourcc == V4L2_PIX_FMT_RGB565) + ret = 0; + break; + case MEDIA_BUS_FMT_EBD_1X8: + if (output_fmt->fourcc == V4l2_PIX_FMT_EBD8 || + (channel->data_bit == 8 && + (output_fmt->fourcc == V4L2_PIX_FMT_SRGGB8 || + output_fmt->fourcc == V4L2_PIX_FMT_SGRBG8 || + output_fmt->fourcc == V4L2_PIX_FMT_SGBRG8 || + output_fmt->fourcc == V4L2_PIX_FMT_SBGGR8)) || + (channel->data_bit == 10 && + (output_fmt->fourcc == V4L2_PIX_FMT_SRGGB10 || + output_fmt->fourcc == V4L2_PIX_FMT_SGRBG10 || + output_fmt->fourcc == V4L2_PIX_FMT_SGBRG10 || + output_fmt->fourcc == V4L2_PIX_FMT_SBGGR10)) || + (channel->data_bit == 12 && + (output_fmt->fourcc == V4L2_PIX_FMT_SRGGB12 || + output_fmt->fourcc == V4L2_PIX_FMT_SGRBG12 || + output_fmt->fourcc == V4L2_PIX_FMT_SGBRG12 || + output_fmt->fourcc == V4L2_PIX_FMT_SBGGR12)) || + (channel->data_bit == 16 && + (output_fmt->fourcc == V4L2_PIX_FMT_SRGGB16 || + output_fmt->fourcc == V4L2_PIX_FMT_SGRBG16 || + output_fmt->fourcc == V4L2_PIX_FMT_SGBRG16 || + output_fmt->fourcc == V4L2_PIX_FMT_SBGGR16))) + ret = 0; + break; + case MEDIA_BUS_FMT_SPD_2X8: + if (output_fmt->fourcc == V4l2_PIX_FMT_SPD16 || + (channel->data_bit == 8 && + (output_fmt->fourcc == V4L2_PIX_FMT_SRGGB8 || + output_fmt->fourcc == V4L2_PIX_FMT_SGRBG8 || + output_fmt->fourcc == V4L2_PIX_FMT_SGBRG8 || + output_fmt->fourcc == V4L2_PIX_FMT_SBGGR8)) || + (channel->data_bit == 10 && + (output_fmt->fourcc == V4L2_PIX_FMT_SRGGB10 || + output_fmt->fourcc == V4L2_PIX_FMT_SGRBG10 || + output_fmt->fourcc == V4L2_PIX_FMT_SGBRG10 || + output_fmt->fourcc == V4L2_PIX_FMT_SBGGR10)) || + (channel->data_bit == 12 && + (output_fmt->fourcc == V4L2_PIX_FMT_SRGGB12 || + output_fmt->fourcc == V4L2_PIX_FMT_SGRBG12 || + output_fmt->fourcc == V4L2_PIX_FMT_SGBRG12 || + output_fmt->fourcc == V4L2_PIX_FMT_SBGGR12)) || + (channel->data_bit == 16 && + (output_fmt->fourcc == V4L2_PIX_FMT_SRGGB16 || + output_fmt->fourcc == V4L2_PIX_FMT_SGRBG16 || + output_fmt->fourcc == V4L2_PIX_FMT_SGBRG16 || + output_fmt->fourcc == V4L2_PIX_FMT_SBGGR16))) + ret = 0; + break; + default: + break; + } + if (ret) + v4l2_err(&stream->cifdev->v4l2_dev, + "input mbus_code 0x%x, can't transform to %c%c%c%c\n", + input_fmt->mbus_code, + output_fmt->fourcc & 0xff, + (output_fmt->fourcc >> 8) & 0xff, + (output_fmt->fourcc >> 16) & 0xff, + (output_fmt->fourcc >> 24) & 0xff); + return ret; +} + static int rkcif_stop_dma_capture(struct rkcif_stream *stream); struct rkcif_rx_buffer *to_cif_rx_buf(struct rkisp_rx_buf *dbufs) @@ -5815,6 +5972,10 @@ int rkcif_set_fmt(struct rkcif_stream *stream, return -EINVAL; } + ret = rkcif_output_fmt_check(stream, fmt); + if (ret) + return -EINVAL; + if (dev->terminal_sensor.sd) { ret = v4l2_subdev_call(dev->terminal_sensor.sd, core, ioctl, From 1a955904dc0d6f9d98a99b411f436cc68ee9e2a9 Mon Sep 17 00:00:00 2001 From: Zefa Chen Date: Tue, 6 Jun 2023 18:52:01 +0800 Subject: [PATCH 09/16] media: rockchip: vicap: only enum outout formats that terminal sensor support to use Signed-off-by: Zefa Chen Change-Id: I58d67a9c8ba65e18fd9031d3fc49f51beb47f067 --- drivers/media/platform/rockchip/cif/capture.c | 34 +++++++++++++++++-- drivers/media/platform/rockchip/cif/dev.h | 1 + 2 files changed, 33 insertions(+), 2 deletions(-) diff --git a/drivers/media/platform/rockchip/cif/capture.c b/drivers/media/platform/rockchip/cif/capture.c index c761ae9ceaa5..b8b664dc4a23 100644 --- a/drivers/media/platform/rockchip/cif/capture.c +++ b/drivers/media/platform/rockchip/cif/capture.c @@ -6398,12 +6398,42 @@ static int rkcif_enum_fmt_vid_cap_mplane(struct file *file, void *priv, struct v4l2_fmtdesc *f) { const struct cif_output_fmt *fmt = NULL; + struct rkcif_stream *stream = video_drvdata(file); + struct rkcif_device *dev = stream->cifdev; + const struct cif_input_fmt *cif_fmt_in = NULL; + struct v4l2_rect input_rect; + int i = 0; + int ret = 0; + int fource_idx = 0; if (f->index >= ARRAY_SIZE(out_fmts)) return -EINVAL; - fmt = &out_fmts[f->index]; - f->pixelformat = fmt->fourcc; + if (dev->terminal_sensor.sd) { + cif_fmt_in = get_input_fmt(dev->terminal_sensor.sd, + &input_rect, stream->id, + &dev->channels[stream->id]); + stream->cif_fmt_in = cif_fmt_in; + } else { + v4l2_err(&stream->cifdev->v4l2_dev, + "terminal subdev does not exist\n"); + return -EINVAL; + } + + if (f->index != 0) + fource_idx = stream->new_fource_idx; + + for (i = fource_idx; i < ARRAY_SIZE(out_fmts); i++) { + fmt = &out_fmts[i]; + ret = rkcif_output_fmt_check(stream, fmt); + if (!ret) { + f->pixelformat = fmt->fourcc; + stream->new_fource_idx = i + 1; + break; + } + } + if (i == ARRAY_SIZE(out_fmts)) + return -EINVAL; switch (f->pixelformat) { case V4l2_PIX_FMT_EBD8: diff --git a/drivers/media/platform/rockchip/cif/dev.h b/drivers/media/platform/rockchip/cif/dev.h index 41945c819445..a23d20aa0fcb 100644 --- a/drivers/media/platform/rockchip/cif/dev.h +++ b/drivers/media/platform/rockchip/cif/dev.h @@ -535,6 +535,7 @@ struct rkcif_stream { struct list_head vb_done_list; int last_rx_buf_idx; int last_frame_idx; + int new_fource_idx; bool stopping; bool crop_enable; bool crop_dyn_en; From 2f2bda6e44c29ccf09881111ab1e19dbc038ca6a Mon Sep 17 00:00:00 2001 From: Zefa Chen Date: Tue, 6 Jun 2023 12:07:09 +0800 Subject: [PATCH 10/16] media: rockchip: vicap: fixes s_selection, support to set crop area Signed-off-by: Zefa Chen Change-Id: Ia87c372d7b372bcb74a9ecf09b1789153baf51b9 --- drivers/media/platform/rockchip/cif/capture.c | 74 ++++++++++++++++--- 1 file changed, 64 insertions(+), 10 deletions(-) diff --git a/drivers/media/platform/rockchip/cif/capture.c b/drivers/media/platform/rockchip/cif/capture.c index b8b664dc4a23..0a557bd21570 100644 --- a/drivers/media/platform/rockchip/cif/capture.c +++ b/drivers/media/platform/rockchip/cif/capture.c @@ -6527,6 +6527,9 @@ static int rkcif_s_selection(struct file *file, void *fh, struct rkcif_device *dev = stream->cifdev; struct v4l2_subdev *sensor_sd; struct v4l2_subdev_selection sd_sel; + const struct v4l2_rect *rect = &s->r; + struct v4l2_rect sensor_crop; + struct v4l2_rect *raw_rect = &dev->terminal_sensor.raw_rect; u16 pad = 0; int ret = 0; @@ -6535,18 +6538,69 @@ static int rkcif_s_selection(struct file *file, void *fh, goto err; } - sensor_sd = get_remote_sensor(stream, &pad); + if (s->target == V4L2_SEL_TGT_CROP_BOUNDS) { + sensor_sd = get_remote_sensor(stream, &pad); - sd_sel.r = s->r; - sd_sel.pad = pad; - sd_sel.target = s->target; - sd_sel.which = V4L2_SUBDEV_FORMAT_ACTIVE; + sd_sel.r = s->r; + sd_sel.pad = pad; + sd_sel.target = s->target; + sd_sel.which = V4L2_SUBDEV_FORMAT_ACTIVE; - ret = v4l2_subdev_call(sensor_sd, pad, set_selection, NULL, &sd_sel); - if (!ret) { - s->r = sd_sel.r; - v4l2_dbg(1, rkcif_debug, &dev->v4l2_dev, "%s: pad:%d, which:%d, target:%d\n", - __func__, pad, sd_sel.which, sd_sel.target); + ret = v4l2_subdev_call(sensor_sd, pad, set_selection, NULL, &sd_sel); + if (!ret) { + s->r = sd_sel.r; + v4l2_dbg(1, rkcif_debug, &dev->v4l2_dev, "%s: pad:%d, which:%d, target:%d\n", + __func__, pad, sd_sel.which, sd_sel.target); + } + } else if (s->target == V4L2_SEL_TGT_CROP) { + ret = rkcif_sanity_check_fmt(stream, rect); + if (ret) { + v4l2_err(&dev->v4l2_dev, "set crop failed\n"); + return ret; + } + + if (stream->crop_mask & CROP_SRC_SENSOR) { + sensor_crop = stream->crop[CROP_SRC_SENSOR]; + if (rect->left + rect->width > sensor_crop.width || + rect->top + rect->height > sensor_crop.height) { + v4l2_err(&dev->v4l2_dev, + "crop size is bigger than sensor input:left:%d, top:%d, width:%d, height:%d\n", + sensor_crop.left, sensor_crop.top, + sensor_crop.width, sensor_crop.height); + return -EINVAL; + } + } else { + if (rect->left + rect->width > raw_rect->width || + rect->top + rect->height > raw_rect->height) { + v4l2_err(&dev->v4l2_dev, + "crop size is bigger than sensor raw input:left:%d, top:%d, width:%d, height:%d\n", + raw_rect->left, raw_rect->top, + raw_rect->width, raw_rect->height); + return -EINVAL; + } + } + + stream->crop[CROP_SRC_USR] = *rect; + stream->crop_enable = true; + stream->crop_mask |= CROP_SRC_USR_MASK; + stream->crop[CROP_SRC_ACT] = stream->crop[CROP_SRC_USR]; + if (stream->crop_mask & CROP_SRC_SENSOR) { + sensor_crop = stream->crop[CROP_SRC_SENSOR]; + stream->crop[CROP_SRC_ACT].left = sensor_crop.left + stream->crop[CROP_SRC_USR].left; + stream->crop[CROP_SRC_ACT].top = sensor_crop.top + stream->crop[CROP_SRC_USR].top; + } + + if (stream->state == RKCIF_STATE_STREAMING) { + stream->crop_dyn_en = true; + + v4l2_info(&dev->v4l2_dev, "enable dynamic crop, S_SELECTION(%ux%u@%u:%u) target: %d\n", + rect->width, rect->height, rect->left, rect->top, s->target); + } else { + v4l2_info(&dev->v4l2_dev, "static crop, S_SELECTION(%ux%u@%u:%u) target: %d\n", + rect->width, rect->height, rect->left, rect->top, s->target); + } + } else { + goto err; } return ret; From e11e649ac189b214b681c7cc3815daae441a808d Mon Sep 17 00:00:00 2001 From: Cai Wenzhong Date: Thu, 8 Jun 2023 09:16:13 +0800 Subject: [PATCH 11/16] media: i2c: max96712: version 1.04.00 Signed-off-by: Cai Wenzhong Change-Id: Icfd197f3bdf68f104bad82121b041962e3f3aa2e --- drivers/media/i2c/max96712.c | 722 ++++++++++++++++++++--------------- 1 file changed, 416 insertions(+), 306 deletions(-) diff --git a/drivers/media/i2c/max96712.c b/drivers/media/i2c/max96712.c index d47209e3c7fb..40172404b6ec 100644 --- a/drivers/media/i2c/max96712.c +++ b/drivers/media/i2c/max96712.c @@ -13,6 +13,8 @@ * frame sync period enable configure. * V1.3.00 t_lpx timing adjust from 53.4ns to 106.7ns. * mipi dpll predef rate set api. + * V1.4.00 i2c read/write api update. + * support for GMSL1 Link. * */ @@ -40,7 +42,7 @@ #include #include -#define DRIVER_VERSION KERNEL_VERSION(1, 0x03, 0x00) +#define DRIVER_VERSION KERNEL_VERSION(1, 0x04, 0x00) #ifndef V4L2_CID_DIGITAL_GAIN #define V4L2_CID_DIGITAL_GAIN V4L2_CID_GAIN @@ -52,21 +54,27 @@ #define MAX96712_CHIP_ID 0xA0 #define MAX96712_REG_CHIP_ID 0x0D +#define MAX96715_CHIP_ID 0x45 +#define MAX96715_REG_CHIP_ID 0x1E + #define MAX96717_CHIP_ID 0xBF #define MAX96717_REG_CHIP_ID 0x0D -#define MAX96712_REG_CTRL_MODE 0x08a0 -#define MAX96712_MODE_SW_STANDBY 0x04 -#define MAX96712_MODE_STREAMING 0xa4 - #define MAX96712_REMOTE_CTRL 0x0003 #define MAX96712_REMOTE_DISABLE 0xFF +/* max96712->link mask: link type = bit[7:4], link mask = bit[3:0] */ +#define MAX96712_GMSL_TYPE_LINK_A BIT(4) +#define MAX96712_GMSL_TYPE_LINK_B BIT(5) +#define MAX96712_GMSL_TYPE_LINK_C BIT(6) +#define MAX96712_GMSL_TYPE_LINK_D BIT(7) +#define MAX96712_GMSL_TYPE_MASK 0xF0 /* bit[7:4], GMSL link type: 0 = GMSL1, 1 = GMSL2 */ + #define MAX96712_LOCK_STATE_LINK_A BIT(0) #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 /* bit[3:0], GMSL link mask: 1 = disable, 1 = enable */ #define MAX96712_FORCE_ALL_CLOCK_EN 0 /* 1: enable, 0: disable */ @@ -77,11 +85,17 @@ #define MAX96712_NAME "max96712" +/* register length: 8bit or 16bit */ +#define MAX96712_REG_LENGTH_08BIT 1 +#define MAX96712_REG_LENGTH_16BIT 2 + +/* register value: 8bit or 16bit or 24bit */ #define MAX96712_REG_VALUE_08BIT 1 #define MAX96712_REG_VALUE_16BIT 2 #define MAX96712_REG_VALUE_24BIT 3 #define MAX96712_I2C_ADDR (0x29) +#define MAX96715_I2C_ADDR (0x40) #define MAX96717_I2C_ADDR (0x40) #define CAMERA_I2C_ADDR (0x30) @@ -104,8 +118,10 @@ static const char *const max96712_supply_names[] = { struct regval { u16 i2c_addr; - u16 addr; + u16 reg_len; + u16 reg; u8 val; + u8 mask; u16 delay; }; @@ -189,89 +205,89 @@ static struct rkmodule_csi_dphy_param rk3588_dcphy_param = { static const struct regval max96712_mipi_4lane_1920x1440_30fps[] = { // Link A/B/C/D all use GMSL2, and disabled - { 0x29, 0x0006, 0xf0, 0x00 }, // Link A/B/C/D: select GMSL2, Disabled + { 0x29, 2, 0x0006, 0xf0, 0x00, 0x00 }, // Link A/B/C/D: select GMSL2, Disabled // Disable MIPI CSI output - { 0x29, 0x040B, 0x00, 0x00 }, // CSI_OUT_EN=0, CSI output disabled + { 0x29, 2, 0x040B, 0x00, 0x00, 0x00 }, // CSI_OUT_EN=0, CSI output disabled // Increase CMU voltage - { 0x29, 0x06C2, 0x10, 0x0a }, // Increase CMU voltage to for wide temperature range + { 0x29, 2, 0x06C2, 0x10, 0x00, 0x0a }, // Increase CMU voltage to for wide temperature range // VGAHiGain - { 0x29, 0x14D1, 0x03, 0x00 }, // VGAHiGain - { 0x29, 0x15D1, 0x03, 0x00 }, // VGAHiGain - { 0x29, 0x16D1, 0x03, 0x00 }, // VGAHiGain - { 0x29, 0x17D1, 0x03, 0x0a }, // VGAHiGain + { 0x29, 2, 0x14D1, 0x03, 0x00, 0x00 }, // VGAHiGain + { 0x29, 2, 0x15D1, 0x03, 0x00, 0x00 }, // VGAHiGain + { 0x29, 2, 0x16D1, 0x03, 0x00, 0x00 }, // VGAHiGain + { 0x29, 2, 0x17D1, 0x03, 0x00, 0x0a }, // VGAHiGain // SSC Configuration - { 0x29, 0x1445, 0x00, 0x00 }, // Disable SSC - { 0x29, 0x1545, 0x00, 0x00 }, // Disable SSC - { 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, 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 - { 0x29, 0x092D, 0x15, 0x00 }, // SRC/DST 0/1/2 -> CSI2 Controller 1; + { 0x29, 2, 0x1445, 0x00, 0x00, 0x00 }, // Disable SSC + { 0x29, 2, 0x1545, 0x00, 0x00, 0x00 }, // Disable SSC + { 0x29, 2, 0x1645, 0x00, 0x00, 0x00 }, // Disable SSC + { 0x29, 2, 0x1745, 0x00, 0x00, 0x0a }, // Disable SSC + // GMSL2 Link Video Pipe Selection + { 0x29, 2, 0x00F0, 0x62, 0x00, 0x00 }, // Phy A -> Pipe Z -> Pipe 0; Phy B -> Pipe Z -> Pipe 1 + { 0x29, 2, 0x00F1, 0xea, 0x00, 0x00 }, // Phy C -> Pipe Z -> Pipe 2; Phy D -> Pipe Z -> Pipe 3 + { 0x29, 2, 0x00F4, 0x0f, 0x00, 0x00 }, // Enable all 4 Pipes + // Send YUV422, FS, and FE from Video Pipe 0 to Controller 1 + { 0x29, 2, 0x090B, 0x07, 0x00, 0x00 }, // Enable 0/1/2 SRC/DST Mappings + { 0x29, 2, 0x092D, 0x15, 0x00, 0x00 }, // SRC/DST 0/1/2 -> CSI2 Controller 1; // For the following MSB 2 bits = VC, LSB 6 bits = DT - { 0x29, 0x090D, 0x1e, 0x00 }, // SRC0 VC = 0, DT = YUV422 8bit - { 0x29, 0x090E, 0x1e, 0x00 }, // DST0 VC = 0, DT = YUV422 8bit - { 0x29, 0x090F, 0x00, 0x00 }, // SRC1 VC = 0, DT = Frame Start - { 0x29, 0x0910, 0x00, 0x00 }, // DST1 VC = 0, DT = Frame Start - { 0x29, 0x0911, 0x01, 0x00 }, // SRC2 VC = 0, DT = Frame End - { 0x29, 0x0912, 0x01, 0x00 }, // DST2 VC = 0, DT = Frame End - // Send YUV422, FS, and FE from Pipe 1 to Controller 1 - { 0x29, 0x094B, 0x07, 0x00 }, // Enable 0/1/2 SRC/DST Mappings - { 0x29, 0x096D, 0x15, 0x00 }, // SRC/DST 0/1/2 -> CSI2 Controller 1; + { 0x29, 2, 0x090D, 0x1e, 0x00, 0x00 }, // SRC0 VC = 0, DT = YUV422 8bit + { 0x29, 2, 0x090E, 0x1e, 0x00, 0x00 }, // DST0 VC = 0, DT = YUV422 8bit + { 0x29, 2, 0x090F, 0x00, 0x00, 0x00 }, // SRC1 VC = 0, DT = Frame Start + { 0x29, 2, 0x0910, 0x00, 0x00, 0x00 }, // DST1 VC = 0, DT = Frame Start + { 0x29, 2, 0x0911, 0x01, 0x00, 0x00 }, // SRC2 VC = 0, DT = Frame End + { 0x29, 2, 0x0912, 0x01, 0x00, 0x00 }, // DST2 VC = 0, DT = Frame End + // Send YUV422, FS, and FE from Video Pipe 1 to Controller 1 + { 0x29, 2, 0x094B, 0x07, 0x00, 0x00 }, // Enable 0/1/2 SRC/DST Mappings + { 0x29, 2, 0x096D, 0x15, 0x00, 0x00 }, // SRC/DST 0/1/2 -> CSI2 Controller 1; // For the following MSB 2 bits = VC, LSB 6 bits = DT - { 0x29, 0x094D, 0x1e, 0x00 }, // SRC0 VC = 0, DT = YUV422 8bit - { 0x29, 0x094E, 0x5e, 0x00 }, // DST0 VC = 1, DT = YUV422 8bit - { 0x29, 0x094F, 0x00, 0x00 }, // SRC1 VC = 0, DT = Frame Start - { 0x29, 0x0950, 0x40, 0x00 }, // DST1 VC = 1, DT = Frame Start - { 0x29, 0x0951, 0x01, 0x00 }, // SRC2 VC = 0, DT = Frame End - { 0x29, 0x0952, 0x41, 0x00 }, // DST2 VC = 1, DT = Frame End - // Send YUV422, FS, and FE from Pipe 2 to Controller 1 - { 0x29, 0x098B, 0x07, 0x00 }, // Enable 0/1/2 SRC/DST Mappings - { 0x29, 0x09AD, 0x15, 0x00 }, // SRC/DST 0/1/2 -> CSI2 Controller 1; + { 0x29, 2, 0x094D, 0x1e, 0x00, 0x00 }, // SRC0 VC = 0, DT = YUV422 8bit + { 0x29, 2, 0x094E, 0x5e, 0x00, 0x00 }, // DST0 VC = 1, DT = YUV422 8bit + { 0x29, 2, 0x094F, 0x00, 0x00, 0x00 }, // SRC1 VC = 0, DT = Frame Start + { 0x29, 2, 0x0950, 0x40, 0x00, 0x00 }, // DST1 VC = 1, DT = Frame Start + { 0x29, 2, 0x0951, 0x01, 0x00, 0x00 }, // SRC2 VC = 0, DT = Frame End + { 0x29, 2, 0x0952, 0x41, 0x00, 0x00 }, // DST2 VC = 1, DT = Frame End + // Send YUV422, FS, and FE from Video Pipe 2 to Controller 1 + { 0x29, 2, 0x098B, 0x07, 0x00, 0x00 }, // Enable 0/1/2 SRC/DST Mappings + { 0x29, 2, 0x09AD, 0x15, 0x00, 0x00 }, // SRC/DST 0/1/2 -> CSI2 Controller 1; // For the following MSB 2 bits = VC, LSB 6 bits = DT - { 0x29, 0x098D, 0x1e, 0x00 }, // SRC0 VC = 0, DT = YUV422 8bit - { 0x29, 0x098E, 0x9e, 0x00 }, // DST0 VC = 2, DT = YUV422 8bit - { 0x29, 0x098F, 0x00, 0x00 }, // SRC1 VC = 0, DT = Frame Start - { 0x29, 0x0990, 0x80, 0x00 }, // DST1 VC = 2, DT = Frame Start - { 0x29, 0x0991, 0x01, 0x00 }, // SRC2 VC = 0, DT = Frame End - { 0x29, 0x0992, 0x81, 0x00 }, // DST2 VC = 2, DT = Frame End - // Send YUV422, FS, and FE from Pipe 3 to Controller 1 - { 0x29, 0x09CB, 0x07, 0x00 }, // Enable 0/1/2 SRC/DST Mappings - { 0x29, 0x09ED, 0x15, 0x00 }, // SRC/DST 0/1/2 -> CSI2 Controller 1; + { 0x29, 2, 0x098D, 0x1e, 0x00, 0x00 }, // SRC0 VC = 0, DT = YUV422 8bit + { 0x29, 2, 0x098E, 0x9e, 0x00, 0x00 }, // DST0 VC = 2, DT = YUV422 8bit + { 0x29, 2, 0x098F, 0x00, 0x00, 0x00 }, // SRC1 VC = 0, DT = Frame Start + { 0x29, 2, 0x0990, 0x80, 0x00, 0x00 }, // DST1 VC = 2, DT = Frame Start + { 0x29, 2, 0x0991, 0x01, 0x00, 0x00 }, // SRC2 VC = 0, DT = Frame End + { 0x29, 2, 0x0992, 0x81, 0x00, 0x00 }, // DST2 VC = 2, DT = Frame End + // Send YUV422, FS, and FE from Video Pipe 3 to Controller 1 + { 0x29, 2, 0x09CB, 0x07, 0x00, 0x00 }, // Enable 0/1/2 SRC/DST Mappings + { 0x29, 2, 0x09ED, 0x15, 0x00, 0x00 }, // SRC/DST 0/1/2 -> CSI2 Controller 1; // For the following MSB 2 bits = VC, LSB 6 bits = DT - { 0x29, 0x09CD, 0x1e, 0x00 }, // SRC0 VC = 0, DT = YUV422 8bit - { 0x29, 0x09CE, 0xde, 0x00 }, // DST0 VC = 3, DT = YUV422 8bit - { 0x29, 0x09CF, 0x00, 0x00 }, // SRC1 VC = 0, DT = Frame Start - { 0x29, 0x09D0, 0xc0, 0x00 }, // DST1 VC = 3, DT = Frame Start - { 0x29, 0x09D1, 0x01, 0x00 }, // SRC2 VC = 0, DT = Frame End - { 0x29, 0x09D2, 0xc1, 0x00 }, // DST2 VC = 3, DT = Frame End + { 0x29, 2, 0x09CD, 0x1e, 0x00, 0x00 }, // SRC0 VC = 0, DT = YUV422 8bit + { 0x29, 2, 0x09CE, 0xde, 0x00, 0x00 }, // DST0 VC = 3, DT = YUV422 8bit + { 0x29, 2, 0x09CF, 0x00, 0x00, 0x00 }, // SRC1 VC = 0, DT = Frame Start + { 0x29, 2, 0x09D0, 0xc0, 0x00, 0x00 }, // DST1 VC = 3, DT = Frame Start + { 0x29, 2, 0x09D1, 0x01, 0x00, 0x00 }, // SRC2 VC = 0, DT = Frame End + { 0x29, 2, 0x09D2, 0xc1, 0x00, 0x00 }, // DST2 VC = 3, DT = Frame End // MIPI PHY Setting - { 0x29, 0x08A0, 0x24, 0x00 }, // DPHY0 enabled as clock, MIPI PHY Mode: 2x4 mode + { 0x29, 2, 0x08A0, 0x24, 0x00, 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 + { 0x29, 2, 0x08A3, 0xe4, 0x00, 0x00 }, // PHY1 D1->D3, D0->D2; PHY0 D1->D1, D0->D0 // Set 4 lane D-PHY, 2bit VC - { 0x29, 0x090A, 0xc0, 0x00 }, // MIPI PHY 0: 4 lanes, DPHY, 2bit VC - { 0x29, 0x094A, 0xc0, 0x00 }, // MIPI PHY 1: 4 lanes, DPHY, 2bit VC + { 0x29, 2, 0x090A, 0xc0, 0x00, 0x00 }, // MIPI PHY 0: 4 lanes, DPHY, 2bit VC + { 0x29, 2, 0x094A, 0xc0, 0x00, 0x00 }, // MIPI PHY 1: 4 lanes, DPHY, 2bit VC // Turn on MIPI PHYs - { 0x29, 0x08A2, 0x34, 0x00 }, // Enable MIPI PHY 0/1, t_lpx = 106.7ns + { 0x29, 2, 0x08A2, 0x34, 0x00, 0x00 }, // Enable MIPI PHY 0/1, t_lpx = 106.7ns // 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 - { 0x29, 0x040F, 0x7e, 0x00 }, // pipe 1 DT=0x1E: YUV422 8-bit - { 0x29, 0x0410, 0x7a, 0x00 }, // pipe 2 DT=0x1E, pipe 3 DT=0x1E: YUV422 8-bit - { 0x29, 0x0411, 0x90, 0x00 }, // pipe 1 bpp=0x10: Datatypes = 0x22, 0x1E, 0x2E - { 0x29, 0x0412, 0x40, 0x00 }, // pipe 2 bpp=0x10, pipe 3 bpp=0x10: Datatypes = 0x22, 0x1E, 0x2E + { 0x29, 2, 0x040B, 0x80, 0x00, 0x00 }, // pipe 0 bpp=0x10: Datatypes = 0x22, 0x1E, 0x2E + { 0x29, 2, 0x040E, 0x5e, 0x00, 0x00 }, // pipe 0 DT=0x1E: YUV422 8-bit + { 0x29, 2, 0x040F, 0x7e, 0x00, 0x00 }, // pipe 1 DT=0x1E: YUV422 8-bit + { 0x29, 2, 0x0410, 0x7a, 0x00, 0x00 }, // pipe 2 DT=0x1E, pipe 3 DT=0x1E: YUV422 8-bit + { 0x29, 2, 0x0411, 0x90, 0x00, 0x00 }, // pipe 1 bpp=0x10: Datatypes = 0x22, 0x1E, 0x2E + { 0x29, 2, 0x0412, 0x40, 0x00, 0x00 }, // pipe 2 bpp=0x10, pipe 3 bpp=0x10: Datatypes = 0x22, 0x1E, 0x2E // 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 + { 0x29, 2, 0x0003, 0xaa, 0x00, 0x00 }, // Enable Remote Control Channel Link A/B/C/D for Port 0 + { 0x29, 2, 0x0006, 0xff, 0x00, 0x64 }, // Enable all links and pipes // Serializer Setting - { 0x40, 0x0302, 0x10, 0x00 }, // improve CMU voltage performance to improve link robustness - { 0x40, 0x1417, 0x00, 0x00 }, // Errata - { 0x40, 0x1432, 0x7f, 0x00 }, - { 0x29, REG_NULL, 0x00, 0x00 }, + { 0x40, 2, 0x0302, 0x10, 0x00, 0x00 }, // improve CMU voltage performance to improve link robustness + { 0x40, 2, 0x1417, 0x00, 0x00, 0x00 }, // Errata + { 0x40, 2, 0x1432, 0x7f, 0x00, 0x00 }, + { 0x29, 2, REG_NULL, 0x00, 0x00, 0x00 }, }; static const struct max96712_mode supported_modes_4lane[] = { @@ -323,34 +339,41 @@ static const s64 link_freq_items[] = { MAX96712_LINK_FREQ_MHZ(1250), }; -/* Write registers up to 4 at a time */ static int max96712_write_reg(struct i2c_client *client, - u16 client_addr, u16 reg, u32 len, u8 val) + u16 client_addr, u16 reg, u16 reg_len, u16 val_len, u32 val) { u32 buf_i, val_i; u8 buf[6]; u8 *val_p; __be32 val_be; - dev_info(&client->dev, "addr(0x%02x) write reg(0x%04x, 0x%02x)\n", \ - client_addr, reg, val); + dev_info(&client->dev, "addr(0x%02x) write reg(0x%04x, %d, 0x%02x)\n", \ + client_addr, reg, reg_len, val); - if (len > 4) + if (val_len > 4) return -EINVAL; - buf[0] = reg >> 8; - buf[1] = reg & 0xff; + if (reg_len == 2) { + buf[0] = reg >> 8; + buf[1] = reg & 0xff; + + buf_i = 2; + } else { + buf[0] = reg & 0xff; + + buf_i = 1; + } val_be = cpu_to_be32(val); val_p = (u8 *)&val_be; - buf_i = 2; - val_i = 4 - len; + val_i = 4 - val_len; while (val_i < 4) buf[buf_i++] = val_p[val_i++]; + client->addr = client_addr; - if (i2c_master_send(client, buf, len + 2) != len + 2) { + if (i2c_master_send(client, buf, (val_len + reg_len)) != (val_len + reg_len)) { dev_err(&client->dev, "%s: writing register 0x%04x from 0x%02x failed\n", __func__, reg, client->addr); @@ -360,51 +383,34 @@ static int max96712_write_reg(struct i2c_client *client, return 0; } -static int max96712_write_array(struct i2c_client *client, - const struct regval *regs) -{ - u32 i; - int ret = 0; - - for (i = 0; ret == 0 && regs[i].addr != REG_NULL; i++) { - ret = max96712_write_reg(client, - regs[i].i2c_addr, regs[i].addr, - MAX96712_REG_VALUE_08BIT, - regs[i].val); - - if (regs[i].delay != 0) - msleep(regs[i].delay); - } - - return ret; -} - -/* Read registers up to 4 at a time */ static int max96712_read_reg(struct i2c_client *client, - u16 client_addr, u16 reg, u32 len, u8 *val) + u16 client_addr, u16 reg, u16 reg_len, u16 val_len, u8 *val) { struct i2c_msg msgs[2]; u8 *data_be_p; __be32 data_be = 0; __be16 reg_addr_be = cpu_to_be16(reg); + u8 *reg_be_p; int ret; - if (len > 4 || !len) + if (val_len > 4 || !val_len) return -EINVAL; client->addr = client_addr; data_be_p = (u8 *)&data_be; + reg_be_p = (u8 *)®_addr_be; + /* Write register address */ msgs[0].addr = client->addr; msgs[0].flags = 0; - msgs[0].len = 2; - msgs[0].buf = (u8 *)®_addr_be; + msgs[0].len = reg_len; + msgs[0].buf = ®_be_p[2 - reg_len]; /* Read data from register */ msgs[1].addr = client->addr; msgs[1].flags = I2C_M_RD; - msgs[1].len = len; - msgs[1].buf = &data_be_p[4 - len]; + msgs[1].len = val_len; + msgs[1].buf = &data_be_p[4 - val_len]; ret = i2c_transfer(client->adapter, msgs, ARRAY_SIZE(msgs)); if (ret != ARRAY_SIZE(msgs)) { @@ -417,41 +423,165 @@ 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); + dev_info(&client->dev, "addr(0x%02x) read reg(0x%04x, %d, 0x%02x)\n", \ + client_addr, reg, reg_len, *val); #endif return 0; } -static int __maybe_unused max96712_update_reg_bits(struct i2c_client *client, - u16 client_addr, u16 reg, u8 mask, u8 val) +static int max96712_update_reg_bits(struct i2c_client *client, + u16 client_addr, u16 reg, u16 reg_len, u8 mask, u8 val) { u8 value; + u32 val_len = MAX96712_REG_VALUE_08BIT; int ret; - ret = max96712_read_reg(client, client_addr, reg, MAX96712_REG_VALUE_08BIT, &value); + ret = max96712_read_reg(client, client_addr, reg, reg_len, val_len, &value); if (ret) return ret; value &= ~mask; value |= (val & mask); - ret = max96712_write_reg(client, client_addr, reg, MAX96712_REG_VALUE_08BIT, value); + ret = max96712_write_reg(client, client_addr, reg, reg_len, val_len, value); if (ret) return ret; return 0; } +static int max96712_write_array(struct i2c_client *client, + const struct regval *regs) +{ + u32 i; + int ret = 0; + + for (i = 0; ret == 0 && regs[i].reg != REG_NULL; i++) { + if (regs[i].mask != 0) + ret = max96712_update_reg_bits(client, regs[i].i2c_addr, + regs[i].reg, regs[i].reg_len, + regs[i].mask, regs[i].val); + else + ret = max96712_write_reg(client, regs[i].i2c_addr, + regs[i].reg, regs[i].reg_len, + MAX96712_REG_VALUE_08BIT, regs[i].val); + + if (regs[i].delay != 0) + msleep(regs[i].delay); + } + + return ret; +} + +static u8 max96712_get_link_lock_state(struct max96712 *max96712, u8 link_mask) +{ + struct i2c_client *client = max96712->client; + struct device *dev = &max96712->client->dev; + u8 lock = 0, lock_state = 0; + u8 link_type = 0; + + link_type = max96712->link_mask & MAX96712_GMSL_TYPE_MASK; + + if (link_mask & MAX96712_LOCK_STATE_LINK_A) { + if (link_type & MAX96712_GMSL_TYPE_LINK_A) { + // GMSL2 LinkA + max96712_read_reg(client, MAX96712_I2C_ADDR, + 0x001a, MAX96712_REG_LENGTH_16BIT, + MAX96712_REG_VALUE_08BIT, &lock); + if (lock & BIT(3)) { + lock_state |= MAX96712_LOCK_STATE_LINK_A; + dev_info(dev, "GMSL2 LinkA locked\n"); + } + } else { + // GMSL1 LinkA + max96712_read_reg(client, MAX96712_I2C_ADDR, + 0x0bcb, MAX96712_REG_LENGTH_16BIT, + MAX96712_REG_VALUE_08BIT, &lock); + if (lock & BIT(0)) { + lock_state |= MAX96712_LOCK_STATE_LINK_A; + dev_info(dev, "GMSL1 LinkA locked\n"); + } + } + } + + if (link_mask & MAX96712_LOCK_STATE_LINK_B) { + if (link_type & MAX96712_GMSL_TYPE_LINK_B) { + // GMSL2 LinkB + max96712_read_reg(client, MAX96712_I2C_ADDR, + 0x000a, MAX96712_REG_LENGTH_16BIT, + MAX96712_REG_VALUE_08BIT, &lock); + if (lock & BIT(3)) { + lock_state |= MAX96712_LOCK_STATE_LINK_B; + dev_info(dev, "GMSL2 LinkB locked\n"); + } + } else { + // GMSL1 LinkB + max96712_read_reg(client, MAX96712_I2C_ADDR, + 0x0ccb, MAX96712_REG_LENGTH_16BIT, + MAX96712_REG_VALUE_08BIT, &lock); + if (lock & BIT(0)) { + lock_state |= MAX96712_LOCK_STATE_LINK_B; + dev_info(dev, "GMSL1 LinkB locked\n"); + } + } + } + + if (link_mask & MAX96712_LOCK_STATE_LINK_C) { + if (link_type & MAX96712_GMSL_TYPE_LINK_C) { + // GMSL2 LinkC + max96712_read_reg(client, MAX96712_I2C_ADDR, + 0x000b, MAX96712_REG_LENGTH_16BIT, + MAX96712_REG_VALUE_08BIT, &lock); + if (lock & BIT(3)) { + lock_state |= MAX96712_LOCK_STATE_LINK_C; + dev_info(dev, "GMSL2 LinkC locked\n"); + } + } else { + // GMSL1 LinkC + max96712_read_reg(client, MAX96712_I2C_ADDR, + 0x0dcb, MAX96712_REG_LENGTH_16BIT, + MAX96712_REG_VALUE_08BIT, &lock); + if (lock & BIT(0)) { + lock_state |= MAX96712_LOCK_STATE_LINK_C; + dev_info(dev, "GMSL1 LinkC locked\n"); + } + } + } + + if (link_mask & MAX96712_LOCK_STATE_LINK_D) { + if (link_type & MAX96712_GMSL_TYPE_LINK_D) { + // GMSL2 LinkD + max96712_read_reg(client, MAX96712_I2C_ADDR, + 0x000c, MAX96712_REG_LENGTH_16BIT, + MAX96712_REG_VALUE_08BIT, &lock); + if (lock & BIT(3)) { + lock_state |= MAX96712_LOCK_STATE_LINK_D; + dev_info(dev, "GMSL2 LinkD locked\n"); + } + } else { + // GMSL1 LinkD + max96712_read_reg(client, MAX96712_I2C_ADDR, + 0x0ecb, MAX96712_REG_LENGTH_16BIT, + MAX96712_REG_VALUE_08BIT, &lock); + if (lock & BIT(0)) { + lock_state |= MAX96712_LOCK_STATE_LINK_D; + dev_info(dev, "GMSL1 LinkD locked\n"); + } + } + } + + return lock_state; +} + static int max96712_check_link_lock_state(struct max96712 *max96712) { struct i2c_client *client = max96712->client; struct device *dev = &max96712->client->dev; - u8 id = 0, lock = 0, lock_state = 0, link_mask = 0; - int ret, count; + u8 id = 0, lock_state = 0, link_mask = 0, link_type = 0; + int ret, i, time_ms; ret = max96712_read_reg(client, MAX96712_I2C_ADDR, - MAX96712_REG_CHIP_ID, + MAX96712_REG_CHIP_ID, MAX96712_REG_LENGTH_16BIT, MAX96712_REG_VALUE_08BIT, &id); if (id != MAX96712_CHIP_ID) { dev_err(dev, "Unexpected MAX96712 chip id(%02x), ret(%d)\n", id, ret); @@ -465,152 +595,144 @@ static int max96712_check_link_lock_state(struct max96712 *max96712) * CTRL2: Enable REG_MNL */ max96712_update_reg_bits(client, MAX96712_I2C_ADDR, - 0x0017, BIT(2), BIT(2)); + 0x0017, MAX96712_REG_LENGTH_16BIT, BIT(2), BIT(2)); max96712_update_reg_bits(client, MAX96712_I2C_ADDR, - 0x0019, BIT(4), BIT(4)); + 0x0019, MAX96712_REG_LENGTH_16BIT, BIT(4), BIT(4)); // CSI output disabled - max96712_write_reg(client, MAX96712_I2C_ADDR, 0x040B, + max96712_write_reg(client, MAX96712_I2C_ADDR, + 0x040B, MAX96712_REG_LENGTH_16BIT, 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); + // All links select mode by link_type and disable at beginning. + link_type = max96712->link_mask & MAX96712_GMSL_TYPE_MASK; + max96712_write_reg(client, MAX96712_I2C_ADDR, + 0x0006, MAX96712_REG_LENGTH_16BIT, + MAX96712_REG_VALUE_08BIT, link_type); + // Link Rate 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_write_reg(client, MAX96712_I2C_ADDR, + 0x0010, MAX96712_REG_LENGTH_16BIT, MAX96712_REG_VALUE_08BIT, 0x11); - max96712_write_reg(client, MAX96712_I2C_ADDR, 0x0011, + max96712_write_reg(client, MAX96712_I2C_ADDR, + 0x0011, MAX96712_REG_LENGTH_16BIT, 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_write_reg(client, MAX96712_I2C_ADDR, + 0x0010, MAX96712_REG_LENGTH_16BIT, MAX96712_REG_VALUE_08BIT, 0x22); - max96712_write_reg(client, MAX96712_I2C_ADDR, 0x0011, + max96712_write_reg(client, MAX96712_I2C_ADDR, + 0x0011, MAX96712_REG_LENGTH_16BIT, MAX96712_REG_VALUE_08BIT, 0x22); } - // Link A ~ Link D One-Shot Reset - link_mask = max96712->link_mask; - max96712_write_reg(client, MAX96712_I2C_ADDR, 0x0018, + // GMSL1: Enable HIM on deserializer on Link A/B/C/D + if ((link_type & MAX96712_GMSL_TYPE_LINK_A) == 0) { + max96712_write_reg(client, MAX96712_I2C_ADDR, + 0x0B06, MAX96712_REG_LENGTH_16BIT, + MAX96712_REG_VALUE_08BIT, 0xEF); + } + if ((link_type & MAX96712_GMSL_TYPE_LINK_B) == 0) { + max96712_write_reg(client, MAX96712_I2C_ADDR, + 0x0C06, MAX96712_REG_LENGTH_16BIT, + MAX96712_REG_VALUE_08BIT, 0xEF); + } + if ((link_type & MAX96712_GMSL_TYPE_LINK_C) == 0) { + max96712_write_reg(client, MAX96712_I2C_ADDR, + 0x0D06, MAX96712_REG_LENGTH_16BIT, + MAX96712_REG_VALUE_08BIT, 0xEF); + } + if ((link_type & MAX96712_GMSL_TYPE_LINK_D) == 0) { + max96712_write_reg(client, MAX96712_I2C_ADDR, + 0x0E06, MAX96712_REG_LENGTH_16BIT, + MAX96712_REG_VALUE_08BIT, 0xEF); + } + + // Link A ~ Link D One-Shot Reset depend on link_mask + link_mask = max96712->link_mask & MAX96712_LOCK_STATE_MASK; + max96712_write_reg(client, MAX96712_I2C_ADDR, + 0x0018, MAX96712_REG_LENGTH_16BIT, MAX96712_REG_VALUE_08BIT, link_mask); - max96712_write_reg(client, MAX96712_I2C_ADDR, 0x0006, - MAX96712_REG_VALUE_08BIT, 0xf0 | link_mask); - msleep(50); - for (count = 0; count < 20; count++) { - if ((lock_state & MAX96712_LOCK_STATE_LINK_A) == 0) { - max96712_read_reg(client, MAX96712_I2C_ADDR, 0x001a, - MAX96712_REG_VALUE_08BIT, &lock); - if (lock & BIT(3)) { + + // Link A ~ Link D enable depend on link_type and link_mask + max96712_write_reg(client, MAX96712_I2C_ADDR, + 0x0006, MAX96712_REG_LENGTH_16BIT, + MAX96712_REG_VALUE_08BIT, link_type | link_mask); + + time_ms = 50; + msleep(time_ms); + + for (i = 0; i < 20; i++) { + if ((lock_state & MAX96712_LOCK_STATE_LINK_A) == 0) + if (max96712_get_link_lock_state(max96712, MAX96712_LOCK_STATE_LINK_A)) { lock_state |= MAX96712_LOCK_STATE_LINK_A; - dev_info(dev, "LinkA lock success: 0x%x, count: %d\n", lock, count); + dev_info(dev, "LinkA locked time: %d ms\n", time_ms); } - } - if ((lock_state & MAX96712_LOCK_STATE_LINK_B) == 0) { - max96712_read_reg(client, MAX96712_I2C_ADDR, 0x000a, - MAX96712_REG_VALUE_08BIT, &lock); - if (lock & BIT(3)) { + if ((lock_state & MAX96712_LOCK_STATE_LINK_B) == 0) + if (max96712_get_link_lock_state(max96712, MAX96712_LOCK_STATE_LINK_B)) { lock_state |= MAX96712_LOCK_STATE_LINK_B; - dev_info(dev, "LinkB lock success: 0x%x, count: %d\n", lock, count); + dev_info(dev, "LinkB locked time: %d ms\n", time_ms); } - } - if ((lock_state & MAX96712_LOCK_STATE_LINK_C) == 0) { - max96712_read_reg(client, MAX96712_I2C_ADDR, 0x000b, - MAX96712_REG_VALUE_08BIT, &lock); - if (lock & BIT(3)) { + if ((lock_state & MAX96712_LOCK_STATE_LINK_C) == 0) + if (max96712_get_link_lock_state(max96712, MAX96712_LOCK_STATE_LINK_C)) { lock_state |= MAX96712_LOCK_STATE_LINK_C; - dev_info(dev, "LinkC lock success: 0x%x, count: %d\n", lock, count); + dev_info(dev, "LinkC locked time: %d ms\n", time_ms); } - } - if ((lock_state & MAX96712_LOCK_STATE_LINK_D) == 0) { - max96712_read_reg(client, MAX96712_I2C_ADDR, 0x000c, - MAX96712_REG_VALUE_08BIT, &lock); - if (lock & BIT(3)) { + if ((lock_state & MAX96712_LOCK_STATE_LINK_D) == 0) + if (max96712_get_link_lock_state(max96712, MAX96712_LOCK_STATE_LINK_D)) { lock_state |= MAX96712_LOCK_STATE_LINK_D; - dev_info(dev, "LinkD lock success: 0x%x, count: %d\n", lock, count); + dev_info(dev, "LinkD locked time: %d ms\n", time_ms); } - } - if ((lock_state & max96712->link_mask) == max96712->link_mask) { + if ((lock_state & link_mask) == link_mask) { dev_info(dev, "All Links are locked: 0x%x\n", lock_state); #if 0 ret = max96712_read_reg(client, MAX96717_I2C_ADDR, - MAX96717_REG_CHIP_ID, + MAX96717_REG_CHIP_ID, MAX96712_REG_LENGTH_16BIT, MAX96712_REG_VALUE_08BIT, &id); if (id != MAX96717_CHIP_ID) { dev_err(dev, "Unexpected MAX96717 chip id(%02x), ret(%d)\n", id, ret); return -ENODEV; } - dev_info(dev, "Detected MAX96717 chipid: %02x\n", id); + dev_info(dev, "Detected MAX96717 chipid: 0x%02x\n", id); +#endif +#if 0 + ret = max96712_read_reg(client, MAX96715_I2C_ADDR, + MAX96715_REG_CHIP_ID, MAX96712_REG_LENGTH_08BIT, + MAX96712_REG_VALUE_08BIT, &id); + if (id != MAX96715_CHIP_ID) { + dev_err(dev, "Unexpected MAX96715 chip id(%02x), ret(%d)\n", id, ret); + return -ENODEV; + } + dev_info(dev, "Detected MAX96715 chipid: 0x%02x\n", id); #endif return 0; } msleep(10); + time_ms += 10; } dev_err(dev, "Failed to detect camera link!\n"); return -ENODEV; } -static u8 max96712_get_lock_state(struct max96712 *max96712) -{ - struct i2c_client *client = max96712->client; - struct device *dev = &max96712->client->dev; - u8 lock = 0, lock_state = 0; - - if (max96712->link_mask & MAX96712_LOCK_STATE_LINK_A) { - max96712_read_reg(client, MAX96712_I2C_ADDR, 0x001a, - MAX96712_REG_VALUE_08BIT, &lock); - if (lock & BIT(3)) { - lock_state |= MAX96712_LOCK_STATE_LINK_A; - dev_info(dev, "LinkA locked\n"); - } - } - - if (max96712->link_mask & MAX96712_LOCK_STATE_LINK_B) { - max96712_read_reg(client, MAX96712_I2C_ADDR, 0x000a, - MAX96712_REG_VALUE_08BIT, &lock); - if (lock & BIT(3)) { - lock_state |= MAX96712_LOCK_STATE_LINK_B; - dev_info(dev, "LinkB locked\n"); - } - } - - if (max96712->link_mask & MAX96712_LOCK_STATE_LINK_C) { - max96712_read_reg(client, MAX96712_I2C_ADDR, 0x000b, - MAX96712_REG_VALUE_08BIT, &lock); - if (lock & BIT(3)) { - lock_state |= MAX96712_LOCK_STATE_LINK_C; - dev_info(dev, "LinkC locked\n"); - } - } - - if (max96712->link_mask & MAX96712_LOCK_STATE_LINK_D) { - max96712_read_reg(client, MAX96712_I2C_ADDR, 0x000c, - MAX96712_REG_VALUE_08BIT, &lock); - if (lock & BIT(3)) { - lock_state |= MAX96712_LOCK_STATE_LINK_D; - dev_info(dev, "LinkD locked\n"); - } - } - - return lock_state; -} - static irqreturn_t max96712_hot_plug_detect_irq_handler(int irq, void *dev_id) { struct max96712 *max96712 = dev_id; struct device *dev = &max96712->client->dev; - u8 lock_state = 0; + u8 lock_state = 0, link_mask = 0; + link_mask = max96712->link_mask & MAX96712_LOCK_STATE_MASK; if (max96712->streaming) { - lock_state = max96712_get_lock_state(max96712); - if (lock_state == max96712->link_mask) { + lock_state = max96712_get_link_lock_state(max96712, link_mask); + if (lock_state == link_mask) { dev_info(dev, "serializer plug in, lock_state = 0x%02x\n", lock_state); } else { dev_info(dev, "serializer plug out, lock_state = 0x%02x\n", lock_state); @@ -628,7 +750,8 @@ static int __maybe_unused max96712_dphy_dpll_predef_set(struct i2c_client *clien u8 mipi_tx_phy_enable = 0; ret = max96712_read_reg(client, MAX96712_I2C_ADDR, - 0x08A2, MAX96712_REG_VALUE_08BIT, &mipi_tx_phy_enable); + 0x08A2, MAX96712_REG_LENGTH_16BIT, + MAX96712_REG_VALUE_08BIT, &mipi_tx_phy_enable); if (ret) return ret; mipi_tx_phy_enable = (mipi_tx_phy_enable & 0xF0) >> 4; @@ -648,72 +771,66 @@ static int __maybe_unused max96712_dphy_dpll_predef_set(struct i2c_client *clien if (mipi_tx_phy_enable & BIT(0)) { // Hold DPLL in reset (config_soft_rst_n = 0) before changing the rate ret |= max96712_write_reg(client, MAX96712_I2C_ADDR, - 0x1C00, + 0x1C00, MAX96712_REG_LENGTH_16BIT, MAX96712_REG_VALUE_08BIT, 0xf4); // Set data rate and enable software override ret |= max96712_update_reg_bits(client, MAX96712_I2C_ADDR, - 0x0415, 0x3F, dpll_val); + 0x0415, MAX96712_REG_LENGTH_16BIT, 0x3F, dpll_val); // Release reset to DPLL (config_soft_rst_n = 1) ret |= max96712_write_reg(client, MAX96712_I2C_ADDR, - 0x1C00, - MAX96712_REG_VALUE_08BIT, - 0xf5); + 0x1C00, MAX96712_REG_LENGTH_16BIT, + MAX96712_REG_VALUE_08BIT, 0xf5); } // MIPI PHY1 if (mipi_tx_phy_enable & BIT(1)) { // Hold DPLL in reset (config_soft_rst_n = 0) before changing the rate ret |= max96712_write_reg(client, MAX96712_I2C_ADDR, - 0x1D00, - MAX96712_REG_VALUE_08BIT, - 0xf4); + 0x1D00, MAX96712_REG_LENGTH_16BIT, + MAX96712_REG_VALUE_08BIT, 0xf4); // Set data rate and enable software override ret |= max96712_update_reg_bits(client, MAX96712_I2C_ADDR, - 0x0418, 0x3F, dpll_val); + 0x0418, MAX96712_REG_LENGTH_16BIT, 0x3F, dpll_val); // Release reset to DPLL (config_soft_rst_n = 1) ret |= max96712_write_reg(client, MAX96712_I2C_ADDR, - 0x1D00, - MAX96712_REG_VALUE_08BIT, - 0xf5); + 0x1D00, MAX96712_REG_LENGTH_16BIT, + MAX96712_REG_VALUE_08BIT, 0xf5); } // MIPI PHY2 if (mipi_tx_phy_enable & BIT(2)) { // Hold DPLL in reset (config_soft_rst_n = 0) before changing the rate ret |= max96712_write_reg(client, MAX96712_I2C_ADDR, - 0x1E00, - MAX96712_REG_VALUE_08BIT, - 0xf4); + 0x1E00, MAX96712_REG_LENGTH_16BIT, + MAX96712_REG_VALUE_08BIT, 0xf4); // Set data rate and enable software override ret |= max96712_update_reg_bits(client, MAX96712_I2C_ADDR, - 0x041B, 0x3F, dpll_val); + 0x041B, MAX96712_REG_LENGTH_16BIT, 0x3F, dpll_val); // Release reset to DPLL (config_soft_rst_n = 1) ret |= max96712_write_reg(client, MAX96712_I2C_ADDR, - 0x1E00, - MAX96712_REG_VALUE_08BIT, - 0xf5); + 0x1E00, MAX96712_REG_LENGTH_16BIT, + MAX96712_REG_VALUE_08BIT, 0xf5); } // MIPI PHY3 if (mipi_tx_phy_enable & BIT(3)) { // Hold DPLL in reset (config_soft_rst_n = 0) before changing the rate ret |= max96712_write_reg(client, MAX96712_I2C_ADDR, - 0x1F00, - MAX96712_REG_VALUE_08BIT, - 0xf4); + 0x1F00, MAX96712_REG_LENGTH_16BIT, + MAX96712_REG_VALUE_08BIT, 0xf4); // Set data rate and enable software override ret |= max96712_update_reg_bits(client, MAX96712_I2C_ADDR, - 0x041E, 0x3F, dpll_val); + 0x041E, MAX96712_REG_LENGTH_16BIT, 0x3F, dpll_val); // Release reset to DPLL (config_soft_rst_n = 1) ret |= max96712_write_reg(client, MAX96712_I2C_ADDR, - 0x1F00, - MAX96712_REG_VALUE_08BIT, - 0xf5); + 0x1F00, MAX96712_REG_LENGTH_16BIT, + MAX96712_REG_VALUE_08BIT, 0xf5); } ret |= max96712_read_reg(client, MAX96712_I2C_ADDR, - 0x0400, MAX96712_REG_VALUE_08BIT, &dpll_lock); + 0x0400, MAX96712_REG_LENGTH_16BIT, + MAX96712_REG_VALUE_08BIT, &dpll_lock); if (ret) return ret; @@ -731,27 +848,23 @@ static int max96712_auto_init_deskew(struct i2c_client *client, u32 deskew_mask) // D-PHY Deskew Initial Calibration Control if (deskew_mask & BIT(0)) // MIPI PHY0 ret |= max96712_write_reg(client, MAX96712_I2C_ADDR, - 0x0903, - MAX96712_REG_VALUE_08BIT, - 0x80); + 0x0903, MAX96712_REG_LENGTH_16BIT, + MAX96712_REG_VALUE_08BIT, 0x80); if (deskew_mask & BIT(1)) // MIPI PHY1 ret |= max96712_write_reg(client, MAX96712_I2C_ADDR, - 0x0943, - MAX96712_REG_VALUE_08BIT, - 0x80); + 0x0943, MAX96712_REG_LENGTH_16BIT, + MAX96712_REG_VALUE_08BIT, 0x80); if (deskew_mask & BIT(2)) // MIPI PHY2 ret |= max96712_write_reg(client, MAX96712_I2C_ADDR, - 0x0983, - MAX96712_REG_VALUE_08BIT, - 0x80); + 0x0983, MAX96712_REG_LENGTH_16BIT, + MAX96712_REG_VALUE_08BIT, 0x80); if (deskew_mask & BIT(3)) // MIPI PHY3 ret |= max96712_write_reg(client, MAX96712_I2C_ADDR, - 0x09C3, - MAX96712_REG_VALUE_08BIT, - 0x80); + 0x09C3, MAX96712_REG_LENGTH_16BIT, + MAX96712_REG_VALUE_08BIT, 0x80); return ret; } @@ -770,30 +883,25 @@ static int max96712_frame_sync_period(struct i2c_client *client, u32 period) #if 1 // TODO: Sensor // SC320AT slave mode enable ret |= max96712_write_reg(client, 0x30, - 0x3222, - MAX96712_REG_VALUE_08BIT, - 0x01); + 0x3222, MAX96712_REG_LENGTH_16BIT, + MAX96712_REG_VALUE_08BIT, 0x01); // Increase the allowable error range of the trigger signal ret |= max96712_write_reg(client, 0x30, - 0x32e2, - MAX96712_REG_VALUE_08BIT, - 0x19); + 0x32e2, MAX96712_REG_LENGTH_16BIT, + MAX96712_REG_VALUE_08BIT, 0x19); #endif // Master link Video 0 for frame sync generation ret |= max96712_write_reg(client, MAX96712_I2C_ADDR, - 0x04A2, - MAX96712_REG_VALUE_08BIT, - 0x00); + 0x04A2, MAX96712_REG_LENGTH_16BIT, + MAX96712_REG_VALUE_08BIT, 0x00); // Disable Vsync-Fsync overlap window ret |= max96712_write_reg(client, MAX96712_I2C_ADDR, - 0x04AA, - MAX96712_REG_VALUE_08BIT, - 0x00); + 0x04AA, MAX96712_REG_LENGTH_16BIT, + MAX96712_REG_VALUE_08BIT, 0x00); ret |= max96712_write_reg(client, MAX96712_I2C_ADDR, - 0x04AB, - MAX96712_REG_VALUE_08BIT, - 0x00); + 0x04AB, MAX96712_REG_LENGTH_16BIT, + MAX96712_REG_VALUE_08BIT, 0x00); // Set FSYNC period to 25M/30 clock cycles. PCLK = 25MHz. Sync freq = 30Hz pclk = 25 * 1000 * 1000; @@ -805,45 +913,38 @@ static int max96712_frame_sync_period(struct i2c_client *client, u32 period) fsync_peroid_h, fsync_peroid_m, fsync_peroid_l); // FSYNC_PERIOD_H ret |= max96712_write_reg(client, MAX96712_I2C_ADDR, - 0x04A7, - MAX96712_REG_VALUE_08BIT, - fsync_peroid_h); + 0x04A7, MAX96712_REG_LENGTH_16BIT, + MAX96712_REG_VALUE_08BIT, fsync_peroid_h); // FSYNC_PERIOD_M ret |= max96712_write_reg(client, MAX96712_I2C_ADDR, - 0x04A6, - MAX96712_REG_VALUE_08BIT, - fsync_peroid_m); + 0x04A6, MAX96712_REG_LENGTH_16BIT, + MAX96712_REG_VALUE_08BIT, fsync_peroid_m); // FSYNC_PERIOD_L ret |= max96712_write_reg(client, MAX96712_I2C_ADDR, - 0x04A5, - MAX96712_REG_VALUE_08BIT, - fsync_peroid_l); + 0x04A5, MAX96712_REG_LENGTH_16BIT, + MAX96712_REG_VALUE_08BIT, fsync_peroid_l); // FSYNC is GMSL2 type, use osc for fsync, include all links/pipes in fsync gen ret |= max96712_write_reg(client, MAX96712_I2C_ADDR, - 0x04AF, - MAX96712_REG_VALUE_08BIT, - 0xcf); + 0x04AF, MAX96712_REG_LENGTH_16BIT, + MAX96712_REG_VALUE_08BIT, 0xcf); // FSYNC_TX_ID: set 4 to match MFP4 on serializer side ret |= max96712_write_reg(client, MAX96712_I2C_ADDR, - 0x04B1, - MAX96712_REG_VALUE_08BIT, - 0x20); + 0x04B1, MAX96712_REG_LENGTH_16BIT, + MAX96712_REG_VALUE_08BIT, 0x20); #if 1 // TODO: Serializer // Enable GPIO_RX_EN on serializer MFP4 ret |= max96712_write_reg(client, 0x40, - 0x02CA, - MAX96712_REG_VALUE_08BIT, - 0x84); + 0x02CA, MAX96712_REG_LENGTH_16BIT, + MAX96712_REG_VALUE_08BIT, 0x84); #endif // MFP2, VS not gen internally, GPIO not used to gen fsync, manual mode ret |= max96712_write_reg(client, MAX96712_I2C_ADDR, - 0x04A0, - MAX96712_REG_VALUE_08BIT, - 0x04); + 0x04A0, MAX96712_REG_LENGTH_16BIT, + MAX96712_REG_VALUE_08BIT, 0x04); return ret; } @@ -857,23 +958,23 @@ static int max96712_mipi_enable(struct i2c_client *client, bool enable) // Force all MIPI clocks running ret |= max96712_update_reg_bits(client, MAX96712_I2C_ADDR, - 0x08A0, BIT(7), BIT(7)); + 0x08A0, MAX96712_REG_LENGTH_16BIT, BIT(7), BIT(7)); #endif // CSI output enabled ret |= max96712_update_reg_bits(client, MAX96712_I2C_ADDR, - 0x040B, BIT(1), BIT(1)); + 0x040B, MAX96712_REG_LENGTH_16BIT, BIT(1), BIT(1)); } else { #if MAX96712_FORCE_ALL_CLOCK_EN // Normal mode ret |= max96712_update_reg_bits(client, MAX96712_I2C_ADDR, - 0x08A0, BIT(7), 0x00); + 0x08A0, MAX96712_REG_LENGTH_16BIT, BIT(7), 0x00); #endif // CSI output disabled ret |= max96712_update_reg_bits(client, MAX96712_I2C_ADDR, - 0x040B, BIT(1), 0x00); + 0x040B, MAX96712_REG_LENGTH_16BIT, BIT(1), 0x00); } return ret; @@ -945,8 +1046,10 @@ static int max96712_set_fmt(struct v4l2_subdev *sd, pixel_rate = (u32)link_freq_items[mode->link_freq_idx] / mode->bpp * 2 * data_lanes; __v4l2_ctrl_s_ctrl_int64(max96712->pixel_rate, pixel_rate); - dev_info(&max96712->client->dev, "mipi_freq_idx = %d\n", mode->link_freq_idx); - dev_info(&max96712->client->dev, "pixel_rate = %lld\n", pixel_rate); + dev_info(&max96712->client->dev, "mipi_freq_idx = %d, mipi_link_freq = %lld\n", + mode->link_freq_idx, link_freq_items[mode->link_freq_idx]); + dev_info(&max96712->client->dev, "pixel_rate = %lld, bpp = %d\n", + pixel_rate, mode->bpp); } mutex_unlock(&max96712->mutex); @@ -1624,7 +1727,8 @@ static int max96712_initialize_controls(struct max96712 *max96712) ARRAY_SIZE(link_freq_items) - 1, 0, link_freq_items); __v4l2_ctrl_s_ctrl(max96712->link_freq, mode->link_freq_idx); - dev_info(&max96712->client->dev, "mipi_freq_idx = %d\n", mode->link_freq_idx); + dev_info(&max96712->client->dev, "mipi_freq_idx = %d, mipi_link_freq = %lld\n", + mode->link_freq_idx, link_freq_items[mode->link_freq_idx]); /* pixel rate = link frequency * 2 * lanes / BITS_PER_SAMPLE */ data_lanes = max96712->bus_cfg.bus.mipi_csi2.num_data_lanes; @@ -1632,7 +1736,8 @@ static int max96712_initialize_controls(struct max96712 *max96712) max96712->pixel_rate = v4l2_ctrl_new_std(handler, NULL, V4L2_CID_PIXEL_RATE, 0, pixel_rate, 1, pixel_rate); - dev_info(&max96712->client->dev, "pixel_rate = %lld\n", pixel_rate); + dev_info(&max96712->client->dev, "pixel_rate = %lld, bpp = %d\n", + pixel_rate, mode->bpp); if (handler->error) { ret = handler->error; @@ -1670,42 +1775,47 @@ static int max96712_parse_dt(struct max96712 *max96712) u8 mipi_data_lanes = max96712->bus_cfg.bus.mipi_csi2.num_data_lanes; int ret = 0; - /* max96712 link Receiver Rate */ + /* max96712 link Receiver Rate: 3G or 6G */ 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); + dev_info(dev, "serdes link receiver rate: %d\n", max96712->rx_rate); - /* max96712 link mask: bit0 - LinkA, bit1 - LinkB, bit2 - LinkC, bit3 - LinkD */ + /* max96712 link mask: + * bit[3:0] = link enable mask: 0 = disable, 1 = enable: + * bit0 - LinkA, bit1 - LinkB, bit2 - LinkC, bit3 - LinkD + * bit[7:4] = link type, 0 = GMSL1, 1 = GMSL2: + * bit4 - LinkA, bit5 - LinkB, bit6 - LinkC, bit7 = LinkD + */ ret = of_property_read_u32(node, "link-mask", &max96712->link_mask); if (ret) { /* default link mask */ if (mipi_data_lanes == 4) - max96712->link_mask = 0x0F; /* Link A/B/C/D */ + max96712->link_mask = 0xFF; /* Link A/B/C/D: GMSL2 and enable */ else - max96712->link_mask = 0x03; /* Link A/B */ + max96712->link_mask = 0x33; /* Link A/B: GMSL2 and enable */ } else { - dev_info(dev, "link-mask property: %d\n", max96712->link_mask); + dev_info(dev, "link-mask property: 0x%08x\n", max96712->link_mask); } - dev_info(dev, "max96712 link mask: 0x%02x\n", max96712->link_mask); + dev_info(dev, "serdes link mask: 0x%02x\n", max96712->link_mask); /* auto initial deskew mask */ ret = of_property_read_u32(node, "auto-init-deskew-mask", &max96712->auto_init_deskew_mask); if (ret) max96712->auto_init_deskew_mask = 0x0F; // 0x0F: default enable all - dev_info(dev, "max96712 auto init deskew mask: 0x%02x\n", max96712->auto_init_deskew_mask); + dev_info(dev, "auto init deskew mask: 0x%02x\n", max96712->auto_init_deskew_mask); /* FSYNC period config */ ret = of_property_read_u32(node, "frame-sync-period", &max96712->frame_sync_period); if (ret) max96712->frame_sync_period = 0; // 0: disable (default) - dev_info(dev, "max96712 frame sync period: %d\n", max96712->frame_sync_period); + dev_info(dev, "frame sync period: %d\n", max96712->frame_sync_period); return 0; } @@ -1764,7 +1874,7 @@ static int max96712_probe(struct i2c_client *client, return -EINVAL; } mipi_data_lanes = max96712->bus_cfg.bus.mipi_csi2.num_data_lanes; - dev_info(dev, "max96712 data lanes %d\n", mipi_data_lanes); + dev_info(dev, "mipi csi2 phy data lanes %d\n", mipi_data_lanes); if (mipi_data_lanes == 4) { max96712->supported_modes = supported_modes_4lane; From 5c80c612ad2ccce8907f62433748275cde4e510e Mon Sep 17 00:00:00 2001 From: Shawn Lin Date: Fri, 9 Jun 2023 09:38:23 +0800 Subject: [PATCH 12/16] ARM: dts: rockchip: add idle state for sdmmc of rv1126-pinctrl Signed-off-by: Shawn Lin Change-Id: Ie72c4c8ac311aab1b02fb8c514c8652260aaa0e6 --- arch/arm/boot/dts/rv1126-pinctrl.dtsi | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/arch/arm/boot/dts/rv1126-pinctrl.dtsi b/arch/arm/boot/dts/rv1126-pinctrl.dtsi index b6ad54a71a5d..47c8874d8935 100644 --- a/arch/arm/boot/dts/rv1126-pinctrl.dtsi +++ b/arch/arm/boot/dts/rv1126-pinctrl.dtsi @@ -1220,6 +1220,17 @@ /* sdmmc0_pwr */ <0 RK_PC0 1 &pcfg_pull_none>; }; + + /omit-if-no-ref/ + sdmmc0_idle_pins: sdmmc0-idle-pins { + rockchip,pins = + <1 RK_PB0 RK_FUNC_GPIO &pcfg_pull_down>, + <1 RK_PB1 RK_FUNC_GPIO &pcfg_pull_down>, + <1 RK_PA4 RK_FUNC_GPIO &pcfg_pull_down>, + <1 RK_PA5 RK_FUNC_GPIO &pcfg_pull_down>, + <1 RK_PA6 RK_FUNC_GPIO &pcfg_pull_down>, + <1 RK_PA7 RK_FUNC_GPIO &pcfg_pull_down>; + }; }; spi0 { /omit-if-no-ref/ From 3dea3e0664b6d24ea8fe794c699130d46bf5b5de Mon Sep 17 00:00:00 2001 From: Shawn Lin Date: Fri, 9 Jun 2023 09:38:46 +0800 Subject: [PATCH 13/16] ARM: dts: rockchip: add idle state for sdmmc of rv1106-pinctrl Signed-off-by: Shawn Lin Change-Id: I77707268214b2d6433dc386b45015bb9d21b4cb2 --- arch/arm/boot/dts/rv1106-pinctrl.dtsi | 33 +++++++++++++++++++++++++++ 1 file changed, 33 insertions(+) diff --git a/arch/arm/boot/dts/rv1106-pinctrl.dtsi b/arch/arm/boot/dts/rv1106-pinctrl.dtsi index f0c4cf3b8ad0..a7bd376a2a65 100644 --- a/arch/arm/boot/dts/rv1106-pinctrl.dtsi +++ b/arch/arm/boot/dts/rv1106-pinctrl.dtsi @@ -731,6 +731,17 @@ /* sdmmc0_det */ <3 RK_PA1 1 &pcfg_pull_up>; }; + + /omit-if-no-ref/ + sdmmc0_idle_pins: sdmmc0-idle-pins { + rockchip,pins = + <3 RK_PA2 RK_FUNC_GPIO &pcfg_pull_down>, + <3 RK_PA3 RK_FUNC_GPIO &pcfg_pull_down>, + <3 RK_PA4 RK_FUNC_GPIO &pcfg_pull_down>, + <3 RK_PA5 RK_FUNC_GPIO &pcfg_pull_down>, + <3 RK_PA6 RK_FUNC_GPIO &pcfg_pull_down>, + <3 RK_PA7 RK_FUNC_GPIO &pcfg_pull_down>; + }; }; sdmmc1 { @@ -768,6 +779,17 @@ <2 RK_PA3 1 &pcfg_pull_up_drv_level_2>; }; + /omit-if-no-ref/ + sdmmc1m0_idle_pins: sdmmc1m0-idle-pins { + rockchip,pins = + <2 RK_PA0 RK_FUNC_GPIO &pcfg_pull_down>, + <2 RK_PA1 RK_FUNC_GPIO &pcfg_pull_down>, + <2 RK_PA2 RK_FUNC_GPIO &pcfg_pull_down>, + <2 RK_PA3 RK_FUNC_GPIO &pcfg_pull_down>, + <2 RK_PA4 RK_FUNC_GPIO &pcfg_pull_down>, + <2 RK_PA5 RK_FUNC_GPIO &pcfg_pull_down>; + }; + /omit-if-no-ref/ sdmmc1m1_bus4: sdmmc1m1-bus4 { rockchip,pins = @@ -794,6 +816,17 @@ /* sdmmc1_cmd_m1 */ <1 RK_PC3 5 &pcfg_pull_up_drv_level_2>; }; + + /omit-if-no-ref/ + sdmmc1m1_idle_pins: sdmmc1m1-idle-pins { + rockchip,pins = + <1 RK_PC0 RK_FUNC_GPIO &pcfg_pull_down>, + <1 RK_PC1 RK_FUNC_GPIO &pcfg_pull_down>, + <1 RK_PC2 RK_FUNC_GPIO &pcfg_pull_down>, + <1 RK_PC3 RK_FUNC_GPIO &pcfg_pull_down>, + <1 RK_PC4 RK_FUNC_GPIO &pcfg_pull_down>, + <1 RK_PC5 RK_FUNC_GPIO &pcfg_pull_down>; + }; }; spi0 { From c44a5ce05538d82565f7e7490a4279fa2c6b7808 Mon Sep 17 00:00:00 2001 From: Shawn Lin Date: Fri, 9 Jun 2023 09:39:15 +0800 Subject: [PATCH 14/16] ARM: dts: rockchip: rv1126: Add sdmmc idle state support In order to avoid power leak for affacting SD cards, add idle state to all related boards for RV1126 and change default state to normal state for the driver to totally control it. Signed-off-by: Shawn Lin Change-Id: If00ed994eb2a467bd5ef16fd52f51b490bea4b27 --- arch/arm/boot/dts/rv1126.dtsi | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/arch/arm/boot/dts/rv1126.dtsi b/arch/arm/boot/dts/rv1126.dtsi index 4705beded656..1c64f55d9929 100644 --- a/arch/arm/boot/dts/rv1126.dtsi +++ b/arch/arm/boot/dts/rv1126.dtsi @@ -2371,8 +2371,9 @@ clock-names = "biu", "ciu", "ciu-drive", "ciu-sample"; fifo-depth = <0x100>; max-frequency = <200000000>; - pinctrl-names = "default"; + pinctrl-names = "normal", "idle"; pinctrl-0 = <&sdmmc0_clk &sdmmc0_cmd &sdmmc0_det &sdmmc0_bus4>; + pinctrl-1 = <&sdmmc0_idle_pins &sdmmc0_det>; status = "disabled"; }; From 05bd7e4fe2776fc7bc596b55f731a7544057b4a8 Mon Sep 17 00:00:00 2001 From: Shawn Lin Date: Fri, 9 Jun 2023 09:40:10 +0800 Subject: [PATCH 15/16] ARM: dts: rockchip: rv1106 boards: Add sdmmc idle state support In order to avoid power leak for affacting SD cards, add idle state to all related boards for RV1106 series and change default state to normal state for the driver to totally control it. Signed-off-by: Shawn Lin Change-Id: I80089eecb2ce1d41f8aaca9a17f913f5fa971514 --- arch/arm/boot/dts/rv1103-evb-v10.dtsi | 3 ++- arch/arm/boot/dts/rv1103g-battery-ipc-v10.dts | 3 ++- arch/arm/boot/dts/rv1103g-battery-ipc-v11.dts | 3 ++- arch/arm/boot/dts/rv1106-ipc.dtsi | 3 ++- arch/arm/boot/dts/rv1106g-38x38-ipc-v10-spi-nand.dts | 3 ++- arch/arm/boot/dts/rv1106g-evb1-v10-dual-cam.dts | 3 ++- arch/arm/boot/dts/rv1106g-evb1-v10.dts | 3 ++- arch/arm/boot/dts/rv1106g-evb1-v11-cvr-dual-cam.dts | 3 ++- arch/arm/boot/dts/rv1106g-evb2-v10-dual-camera.dts | 3 ++- arch/arm/boot/dts/rv1106g-evb2-v10.dts | 3 ++- arch/arm/boot/dts/rv1106g-evb2-v11-emmc.dts | 3 ++- 11 files changed, 22 insertions(+), 11 deletions(-) diff --git a/arch/arm/boot/dts/rv1103-evb-v10.dtsi b/arch/arm/boot/dts/rv1103-evb-v10.dtsi index 45200019a59d..8cd27939ff21 100644 --- a/arch/arm/boot/dts/rv1103-evb-v10.dtsi +++ b/arch/arm/boot/dts/rv1103-evb-v10.dtsi @@ -81,8 +81,9 @@ cap-mmc-highspeed; cap-sd-highspeed; disable-wp; - pinctrl-names = "default"; + pinctrl-names = "normal", "idle"; pinctrl-0 = <&sdmmc0_clk &sdmmc0_cmd &sdmmc0_det &sdmmc0_bus4>; + pinctrl-1 = <&sdmmc0_idle_pins &sdmmc0_det>; status = "okay"; }; diff --git a/arch/arm/boot/dts/rv1103g-battery-ipc-v10.dts b/arch/arm/boot/dts/rv1103g-battery-ipc-v10.dts index c96f6f4f43cb..ee95a1819db7 100644 --- a/arch/arm/boot/dts/rv1103g-battery-ipc-v10.dts +++ b/arch/arm/boot/dts/rv1103g-battery-ipc-v10.dts @@ -286,8 +286,9 @@ cap-sdio-irq; keep-power-in-suspend; non-removable; - pinctrl-names = "default"; + pinctrl-names = "normal", "idle"; pinctrl-0 = <&sdmmc1m1_cmd &sdmmc1m1_clk &sdmmc1m1_bus4>; + pinctrl-1 = <&sdmmc1m1_idle_pins>; no-prescan-powerup; post-power-on-delay-ms = <0>; status = "okay"; diff --git a/arch/arm/boot/dts/rv1103g-battery-ipc-v11.dts b/arch/arm/boot/dts/rv1103g-battery-ipc-v11.dts index c5468385309b..e8a6f79d9bc7 100644 --- a/arch/arm/boot/dts/rv1103g-battery-ipc-v11.dts +++ b/arch/arm/boot/dts/rv1103g-battery-ipc-v11.dts @@ -287,8 +287,9 @@ cap-sdio-irq; keep-power-in-suspend; non-removable; - pinctrl-names = "default"; + pinctrl-names = "normal", "idle"; pinctrl-0 = <&sdmmc1m1_cmd &sdmmc1m1_clk &sdmmc1m1_bus4>; + pinctrl-1 = <&sdmmc1m1_idle_pins>; no-prescan-powerup; post-power-on-delay-ms = <0>; status = "okay"; diff --git a/arch/arm/boot/dts/rv1106-ipc.dtsi b/arch/arm/boot/dts/rv1106-ipc.dtsi index d4ac29301f1f..f1f3cf6eb8b4 100644 --- a/arch/arm/boot/dts/rv1106-ipc.dtsi +++ b/arch/arm/boot/dts/rv1106-ipc.dtsi @@ -288,8 +288,9 @@ cap-mmc-highspeed; cap-sd-highspeed; disable-wp; - pinctrl-names = "default"; + pinctrl-names = "normal", "idle"; pinctrl-0 = <&sdmmc0_clk &sdmmc0_cmd &sdmmc0_det &sdmmc0_bus4>; + pinctrl-1 = <&sdmmc0_idle_pins &sdmmc0_det>; status = "okay"; }; diff --git a/arch/arm/boot/dts/rv1106g-38x38-ipc-v10-spi-nand.dts b/arch/arm/boot/dts/rv1106g-38x38-ipc-v10-spi-nand.dts index 3452c2c20dd3..d7c76712c194 100644 --- a/arch/arm/boot/dts/rv1106g-38x38-ipc-v10-spi-nand.dts +++ b/arch/arm/boot/dts/rv1106g-38x38-ipc-v10-spi-nand.dts @@ -61,8 +61,9 @@ cap-mmc-highspeed; cap-sd-highspeed; disable-wp; - pinctrl-names = "default"; + pinctrl-names = "normal", "idle"; pinctrl-0 = <&sdmmc0_clk &sdmmc0_cmd &sdmmc0_det &sdmmc0_bus4>; + pinctrl-1 = <&sdmmc0_idle_pins &sdmmc0_det>; vmmc-supply = <&vcc3v3_sd>; status = "okay"; }; diff --git a/arch/arm/boot/dts/rv1106g-evb1-v10-dual-cam.dts b/arch/arm/boot/dts/rv1106g-evb1-v10-dual-cam.dts index 7997f8f1f543..2451564f35b3 100644 --- a/arch/arm/boot/dts/rv1106g-evb1-v10-dual-cam.dts +++ b/arch/arm/boot/dts/rv1106g-evb1-v10-dual-cam.dts @@ -150,8 +150,9 @@ cap-mmc-highspeed; cap-sd-highspeed; disable-wp; - pinctrl-names = "default"; + pinctrl-names = "normal", "idle"; pinctrl-0 = <&sdmmc0_clk &sdmmc0_cmd &sdmmc0_det &sdmmc0_bus4>; + pinctrl-1 = <&sdmmc0_idle_pins &sdmmc0_det>; sd-uhs-sdr12; sd-uhs-sdr25; sd-uhs-sdr50; diff --git a/arch/arm/boot/dts/rv1106g-evb1-v10.dts b/arch/arm/boot/dts/rv1106g-evb1-v10.dts index 9966352dbaa9..8f820d60fecc 100644 --- a/arch/arm/boot/dts/rv1106g-evb1-v10.dts +++ b/arch/arm/boot/dts/rv1106g-evb1-v10.dts @@ -150,8 +150,9 @@ cap-mmc-highspeed; cap-sd-highspeed; disable-wp; - pinctrl-names = "default"; + pinctrl-names = "normal", "idle"; pinctrl-0 = <&sdmmc0_clk &sdmmc0_cmd &sdmmc0_det &sdmmc0_bus4>; + pinctrl-1 = <&sdmmc0_idle_pins &sdmmc0_det>; sd-uhs-sdr12; sd-uhs-sdr25; sd-uhs-sdr50; diff --git a/arch/arm/boot/dts/rv1106g-evb1-v11-cvr-dual-cam.dts b/arch/arm/boot/dts/rv1106g-evb1-v11-cvr-dual-cam.dts index cb295ebd6a5d..0368b0f6575d 100644 --- a/arch/arm/boot/dts/rv1106g-evb1-v11-cvr-dual-cam.dts +++ b/arch/arm/boot/dts/rv1106g-evb1-v11-cvr-dual-cam.dts @@ -140,8 +140,9 @@ cap-mmc-highspeed; cap-sd-highspeed; disable-wp; - pinctrl-names = "default"; + pinctrl-names = "normal", "idle"; pinctrl-0 = <&sdmmc0_clk &sdmmc0_cmd &sdmmc0_det &sdmmc0_bus4>; + pinctrl-1 = <&sdmmc0_idle_pins &sdmmc0_det>; sd-uhs-sdr12; sd-uhs-sdr25; sd-uhs-sdr50; diff --git a/arch/arm/boot/dts/rv1106g-evb2-v10-dual-camera.dts b/arch/arm/boot/dts/rv1106g-evb2-v10-dual-camera.dts index 06cc1407fb6c..e748e20ca5aa 100644 --- a/arch/arm/boot/dts/rv1106g-evb2-v10-dual-camera.dts +++ b/arch/arm/boot/dts/rv1106g-evb2-v10-dual-camera.dts @@ -393,8 +393,9 @@ cap-mmc-highspeed; cap-sd-highspeed; disable-wp; - pinctrl-names = "default"; + pinctrl-names = "normal", "idle"; pinctrl-0 = <&sdmmc0_clk &sdmmc0_cmd &sdmmc0_det &sdmmc0_bus4>; + pinctrl-1 = <&sdmmc0_idle_pins &sdmmc0_det>; vmmc-supply = <&vcc3v3_sd>; status = "okay"; }; diff --git a/arch/arm/boot/dts/rv1106g-evb2-v10.dts b/arch/arm/boot/dts/rv1106g-evb2-v10.dts index 9efd2a1f1a1b..90274546bad1 100644 --- a/arch/arm/boot/dts/rv1106g-evb2-v10.dts +++ b/arch/arm/boot/dts/rv1106g-evb2-v10.dts @@ -263,8 +263,9 @@ cap-mmc-highspeed; cap-sd-highspeed; disable-wp; - pinctrl-names = "default"; + pinctrl-names = "normal", "idle"; pinctrl-0 = <&sdmmc0_clk &sdmmc0_cmd &sdmmc0_det &sdmmc0_bus4>; + pinctrl-1 = <&sdmmc0_idle_pins &sdmmc0_det>; vmmc-supply = <&vcc3v3_sd>; status = "okay"; }; diff --git a/arch/arm/boot/dts/rv1106g-evb2-v11-emmc.dts b/arch/arm/boot/dts/rv1106g-evb2-v11-emmc.dts index 37635912fd4b..653c4eb44af7 100644 --- a/arch/arm/boot/dts/rv1106g-evb2-v11-emmc.dts +++ b/arch/arm/boot/dts/rv1106g-evb2-v11-emmc.dts @@ -263,8 +263,9 @@ cap-mmc-highspeed; cap-sd-highspeed; disable-wp; - pinctrl-names = "default"; + pinctrl-names = "normal", "idle"; pinctrl-0 = <&sdmmc0_clk &sdmmc0_cmd &sdmmc0_det &sdmmc0_bus4>; + pinctrl-1 = <&sdmmc0_idle_pins &sdmmc0_det>; vmmc-supply = <&vcc3v3_sd>; status = "okay"; }; From 33f4a54037590ce6bf13e3568e33685dbe752588 Mon Sep 17 00:00:00 2001 From: Huibin Hong Date: Thu, 1 Jun 2023 01:51:52 +0000 Subject: [PATCH 16/16] fiq_debugger: tty write to tty fifo It means printf(user) write log to tty fifo, to reduce printf time. Signed-off-by: Huibin Hong Change-Id: Iaf55719e7089a7c3b3638e2976c97868eed3868e --- .../soc/rockchip/fiq_debugger/fiq_debugger.c | 24 ++- .../soc/rockchip/fiq_debugger/fiq_debugger.h | 3 + .../rockchip/fiq_debugger/rk_fiq_debugger.c | 141 ++++++++++++------ 3 files changed, 122 insertions(+), 46 deletions(-) diff --git a/drivers/soc/rockchip/fiq_debugger/fiq_debugger.c b/drivers/soc/rockchip/fiq_debugger/fiq_debugger.c index ddc6c6b3de9d..1f8e88e73acc 100644 --- a/drivers/soc/rockchip/fiq_debugger/fiq_debugger.c +++ b/drivers/soc/rockchip/fiq_debugger/fiq_debugger.c @@ -1202,6 +1202,15 @@ static void fiq_tty_close(struct tty_struct *tty, struct file *filp) tty_port_close(tty->port, tty, filp); } +void fiq_tty_wake_up(struct platform_device *pdev) +{ + struct fiq_debugger_state *state = platform_get_drvdata(pdev); + + if (tty_port_initialized(&state->tty_port)) + tty_port_tty_wakeup(&state->tty_port); +} +EXPORT_SYMBOL_GPL(fiq_tty_wake_up); + static int fiq_tty_write(struct tty_struct *tty, const unsigned char *buf, int count) { int i; @@ -1212,6 +1221,11 @@ static int fiq_tty_write(struct tty_struct *tty, const unsigned char *buf, int c if (!state->console_enable) return count; +#ifdef CONFIG_RK_CONSOLE_THREAD + if (state->pdata->tty_write) + return state->pdata->tty_write(state->pdev, buf, count); +#endif + fiq_debugger_uart_enable(state); #ifndef CONFIG_RK_CONSOLE_THREAD spin_lock_irq(&state->console_lock); @@ -1228,7 +1242,15 @@ static int fiq_tty_write(struct tty_struct *tty, const unsigned char *buf, int c static int fiq_tty_write_room(struct tty_struct *tty) { - return 16; +#ifdef CONFIG_RK_CONSOLE_THREAD + int line = tty->index; + struct fiq_debugger_state **states = tty->driver->driver_state; + struct fiq_debugger_state *state = states[line]; + + if (state->pdata->write_room) + return state->pdata->write_room(state->pdev); +#endif + return 2048; } #ifdef CONFIG_CONSOLE_POLL diff --git a/drivers/soc/rockchip/fiq_debugger/fiq_debugger.h b/drivers/soc/rockchip/fiq_debugger/fiq_debugger.h index cef21c591ea1..e2003e47904d 100644 --- a/drivers/soc/rockchip/fiq_debugger/fiq_debugger.h +++ b/drivers/soc/rockchip/fiq_debugger/fiq_debugger.h @@ -63,6 +63,8 @@ struct fiq_debugger_pdata { #ifdef CONFIG_RK_CONSOLE_THREAD void (*console_write)(struct platform_device *pdev, const char *s, unsigned int count); + int (*tty_write)(struct platform_device *pdev, const char *s, int count); + int (*write_room)(struct platform_device *pdev); #endif #ifdef CONFIG_FIQ_DEBUGGER_TRUST_ZONE void (*switch_cpu)(struct platform_device *pdev, u32 cpu); @@ -75,4 +77,5 @@ void gic_set_irq_secure(struct irq_data *d); void gic_set_irq_priority(struct irq_data *d, u8 pri); #endif +void fiq_tty_wake_up(struct platform_device *pdev); #endif diff --git a/drivers/soc/rockchip/fiq_debugger/rk_fiq_debugger.c b/drivers/soc/rockchip/fiq_debugger/rk_fiq_debugger.c index 148235d7a683..3c85c83e0320 100644 --- a/drivers/soc/rockchip/fiq_debugger/rk_fiq_debugger.c +++ b/drivers/soc/rockchip/fiq_debugger/rk_fiq_debugger.c @@ -229,23 +229,32 @@ static void debug_flush(struct platform_device *pdev) #ifdef CONFIG_RK_CONSOLE_THREAD #define FIFO_SIZE SZ_64K -#define LINE_MAX 1024 +#define TTY_FIFO_SIZE SZ_64K static DEFINE_KFIFO(fifo, unsigned char, FIFO_SIZE); -static char console_buf[LINE_MAX]; /* avoid FRAME WARN */ +static DEFINE_KFIFO(tty_fifo, unsigned char, TTY_FIFO_SIZE); static bool console_thread_stop; /* write on console_write */ static bool console_thread_running; /* write on console_thread */ static unsigned int console_dropped_messages; +static int write_room(struct platform_device *pdev) +{ + return (TTY_FIFO_SIZE - kfifo_len(&tty_fifo)); +} + static void console_putc(struct platform_device *pdev, unsigned int c) { struct rk_fiq_debugger *t; - unsigned int count = 500; + unsigned int count = 2; /* loop 2 times is enough */ + unsigned long us = 400; /* the time to send 60 byte for baudrate 1500000 */ t = container_of(dev_get_platdata(&pdev->dev), typeof(*t), pdata); + if (t->baudrate == 115200) + us = 5160; /* the time to send 60 byte for baudrate 115200 */ + while (!(rk_fiq_read(t, UART_USR) & UART_USR_TX_FIFO_NOT_FULL) && count--) - usleep_range(200, 210); + usleep_range(us, us + us / 20); rk_fiq_write(t, c, UART_TX); } @@ -253,12 +262,16 @@ static void console_putc(struct platform_device *pdev, unsigned int c) static void console_flush(struct platform_device *pdev) { struct rk_fiq_debugger *t; - unsigned int count = 500; + unsigned int count = 2; /* loop 2 times is enough */ + unsigned long us = 428; /* the time to send 64 byte for baudrate 1500000 */ t = container_of(dev_get_platdata(&pdev->dev), typeof(*t), pdata); + if (t->baudrate == 115200) + us = 5500; /* the time to send 64 byte for baudrate 115200 */ + while (!(rk_fiq_read_lsr(t) & UART_LSR_TEMT) && count--) - usleep_range(200, 210); + usleep_range(us, us + us / 20); } static void console_put(struct platform_device *pdev, @@ -281,17 +294,47 @@ static void debug_put(struct platform_device *pdev, } } +static void wake_up_console_thread(struct task_struct *console_task) +{ + /* + * Avoid dead lock on console_task->pi_lock and console_lock + * when call printk() in try_to_wake_up(). + * + * cpu0 hold console_lock, then try lock pi_lock fail: + * printk()->vprintk_emit()->console_unlock()->try_to_wake_up() + * ->lock(pi_lock)->deadlock + * + * cpu1 hold pi_lock, then try lock console_lock fail: + * console_thread()->console_put()->usleep_range()->run_hrtimer() + * ->hrtimer_wakeup()->try_to_wake_up()[hold_pi_lock]->printk() + * ->vprintk_emit()->console_trylock_spining()->cpu_relax()->deadlock + * + * if cpu0 does not hold console_lock, cpu1 also deadlock on pi_lock: + * ...->hrtimer_wakeup()->try_to_wake_up()[hold_pi_lock]->printk() + * ->vprintk_emit()->console_unlock()->try_to_wake_up() + * ->lock(pi_lock)->deadlock + * + * so when console_task is running on usleep_range(), printk() + * should not wakeup console_task to avoid lock(pi_lock) again, + * as run_hrtimer() will wakeup console_task later. + * console_thread_running==false guarantee that console_task + * is not running on usleep_range(). + */ + if (!READ_ONCE(console_thread_running)) + wake_up_process(console_task); +} + static int console_thread(void *data) { struct platform_device *pdev = data; - char *buf = console_buf; - unsigned int len; + char buf[64], c = 0; + unsigned int len = 0, len_tty = 0; while (1) { unsigned int dropped; set_current_state(TASK_INTERRUPTIBLE); - if (kfifo_is_empty(&fifo)) { + if (kfifo_is_empty(&fifo) && kfifo_is_empty(&tty_fifo)) { smp_store_mb(console_thread_running, false); schedule(); smp_store_mb(console_thread_running, true); @@ -299,18 +342,31 @@ static int console_thread(void *data) if (kthread_should_stop()) break; set_current_state(TASK_RUNNING); - while (!console_thread_stop) { - len = kfifo_out(&fifo, buf, LINE_MAX); - if (!len) - break; - console_put(pdev, buf, len); + + while (!console_thread_stop && (!kfifo_is_empty(&fifo) || !kfifo_is_empty(&tty_fifo))) { + while (kfifo_get(&fifo, &c)) { + console_put(pdev, &c, 1); + if (c == '\n') + break; + } + + while (kfifo_get(&tty_fifo, &c)) { + console_putc(pdev, c); + len_tty++; + if (c == '\n') + break; + } } + + if (len_tty > 0) + fiq_tty_wake_up(pdev); + len_tty = 0; + dropped = console_dropped_messages; if (dropped && !console_thread_stop) { console_dropped_messages = 0; smp_wmb(); - len = snprintf(buf, LINE_MAX, - "** %u console messages dropped **\n", + len = sprintf(buf, "** %u console messages dropped **\n", dropped); console_put(pdev, buf, len); } @@ -346,43 +402,35 @@ static void console_write(struct platform_device *pdev, const char *s, unsigned } else if (count) { unsigned int ret = 0; - if (kfifo_len(&fifo) + count < FIFO_SIZE) + if (kfifo_len(&fifo) + count <= FIFO_SIZE) ret = kfifo_in(&fifo, s, count); if (!ret) { console_dropped_messages++; smp_wmb(); } else { - /* - * Avoid dead lock on console_task->pi_lock and console_lock - * when call printk() in try_to_wake_up(). - * - * cpu0 hold console_lock, then try lock pi_lock fail: - * printk()->vprintk_emit()->console_unlock()->try_to_wake_up() - * ->lock(pi_lock)->deadlock - * - * cpu1 hold pi_lock, then try lock console_lock fail: - * console_thread()->console_put()->usleep_range()->run_hrtimer() - * ->hrtimer_wakeup()->try_to_wake_up()[hold_pi_lock]->printk() - * ->vprintk_emit()->console_trylock_spining()->cpu_relax()->deadlock - * - * if cpu0 does not hold console_lock, cpu1 also deadlock on pi_lock: - * ...->hrtimer_wakeup()->try_to_wake_up()[hold_pi_lock]->printk() - * ->vprintk_emit()->console_unlock()->try_to_wake_up() - * ->lock(pi_lock)->deadlock - * - * so when console_task is running on usleep_range(), printk() - * should not wakeup console_task to avoid lock(pi_lock) again, - * as run_hrtimer() will wakeup console_task later. - * console_thread_running==false guarantee that console_task - * is not running on usleep_range(). - */ - if (!READ_ONCE(console_thread_running)) - wake_up_process(t->console_task); + wake_up_console_thread(t->console_task); } } } -#endif +static int tty_write(struct platform_device *pdev, const char *s, int count) +{ + unsigned int ret = 0; + struct rk_fiq_debugger *t; + + t = container_of(dev_get_platdata(&pdev->dev), typeof(*t), pdata); + + if (count > 0) { + if (kfifo_len(&tty_fifo) + count <= TTY_FIFO_SIZE) + ret = kfifo_in(&tty_fifo, s, count); + + if (ret <= 0) + return 0; + wake_up_console_thread(t->console_task); + } + return count; +} +#endif static void fiq_enable(struct platform_device *pdev, unsigned int irq, bool on) { @@ -889,8 +937,11 @@ static void rk_serial_debug_init(void __iomem *base, phys_addr_t phy_base, #ifdef CONFIG_RK_CONSOLE_THREAD t->console_task = kthread_run(console_thread, pdev, "kconsole"); - if (!IS_ERR(t->console_task)) + if (!IS_ERR(t->console_task)) { t->pdata.console_write = console_write; + t->pdata.tty_write = tty_write; + t->pdata.write_room = write_room; + } #endif pdev->name = "fiq_debugger";