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. 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. 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/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 { 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"; }; 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/ diff --git a/arch/arm/boot/dts/rv1126.dtsi b/arch/arm/boot/dts/rv1126.dtsi index 4e68b589d1f0..26ae7b06fbd1 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"; }; 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"; }; 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"; }; 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>; diff --git a/drivers/devfreq/event/rockchip-dfi.c b/drivers/devfreq/event/rockchip-dfi.c index 6db7c494555f..df8143c6a242 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) @@ -722,6 +726,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 }, @@ -744,6 +783,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 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 }, diff --git a/drivers/media/i2c/max96712.c b/drivers/media/i2c/max96712.c index f3005a51bf51..f8d1ca376e30 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; diff --git a/drivers/media/platform/rockchip/cif/capture.c b/drivers/media/platform/rockchip/cif/capture.c index af31324e95c3..15f8837606ed 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) @@ -5742,6 +5899,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, @@ -6164,12 +6325,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: @@ -6263,6 +6454,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; @@ -6271,18 +6465,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; 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; diff --git a/drivers/soc/rockchip/fiq_debugger/fiq_debugger.c b/drivers/soc/rockchip/fiq_debugger/fiq_debugger.c index 365a46fc9874..ef7a4b1ee914 100644 --- a/drivers/soc/rockchip/fiq_debugger/fiq_debugger.c +++ b/drivers/soc/rockchip/fiq_debugger/fiq_debugger.c @@ -1201,6 +1201,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; @@ -1211,6 +1220,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); @@ -1227,7 +1241,15 @@ static int fiq_tty_write(struct tty_struct *tty, const unsigned char *buf, int c static unsigned 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 c11c25860bf5..9d8c210b815a 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";