[U-Boot] [PATCH 0/7] Enable MIPI dsi display for rk3399

From: "eric.gao" eric.gao@rock-chips.com
This serial patchs enable mipi dsi display for rk3399,and let the system log print to lcd. The function of each patch is decribe in the following.Thank you. Patch 1: Fix system halt when we enable bucks of PMIC rk808. Patch 2: Enable i2c for rk3399. Patch 3: Enable PMIC rk808 for display system using. Patch 4: Enable rkclk init,prepare aclk dclk for vop. Patch 5: Add mipi display,panel driver and so on. Patch 6: Enable print log to lcd. Patch 7: Fix crash when scrolling screen.
eric.gao (7): system halt when we enable bucks of PMIC rk808 Enable i2c for rk3399 Enable RK808 for rk3399 evb Enable rkclk init function Add mipi display support for rk3399 && rk3288 Enable print log file to lcd crash when scroll screen
arch/arm/dts/rk3399-evb.dts | 141 +++++++++ arch/arm/dts/rk3399.dtsi | 88 ++++++ arch/arm/include/asm/arch-rockchip/cru_rk3399.h | 2 +- arch/arm/include/asm/arch-rockchip/mipi_rk3399.h | 203 +++++++++++++ arch/arm/include/asm/arch-rockchip/vop_rk3288.h | 1 + arch/arm/mach-rockchip/rk3399/syscon_rk3399.c | 1 + configs/evb-rk3399_defconfig | 11 + drivers/clk/rockchip/clk_rk3399.c | 4 + drivers/i2c/rk_i2c.c | 1 + drivers/video/Kconfig | 2 + drivers/video/console_normal.c | 2 +- drivers/video/rockchip/Kconfig | 44 +++ drivers/video/rockchip/Makefile | 7 +- drivers/video/rockchip/panel.c | 81 +++++ drivers/video/rockchip/rk_mipi.c | 371 +++++++++++++++++++++++ drivers/video/rockchip/rk_vop.c | 12 +- include/configs/rk3399_common.h | 5 +- 17 files changed, 969 insertions(+), 7 deletions(-) create mode 100644 arch/arm/include/asm/arch-rockchip/mipi_rk3399.h create mode 100644 drivers/video/rockchip/Kconfig create mode 100644 drivers/video/rockchip/panel.c create mode 100644 drivers/video/rockchip/rk_mipi.c

From: "eric.gao" eric.gao@rock-chips.com
if we enable PMIC rk808,the system will halt at very early stage ,log is shown as bellow.
INFO: plat_rockchip_pmu_init(1211): pd status 3e INFO: BL31: Initializing runtime services INFO: BL31: Preparing for EL3 exit to normal world INFO: Entry point address = 0x200000 INFO: SPSR = 0x3c9 time 44561b, 0 (<<----Just stop here)
It's caused by the absence of "{ }" in file rk3399/syscon_rk3399.c ,which will lead to memory overflow like below.According to Sysmap file ,we can find the function buck_get_value of rk808 is just follow the compatible struct, the pointer "of_match" point to "buck_get_value", but it is not a struct and don't have member of compatible, In this case,system crash. So,on the face, it looks like that rk808 is guilty. but he is really innocent.
while (of_match->compatible) { <<---------- if (!strcmp(of_match->compatible, compat)) { *of_idp = of_match; return 0; } of_match++; }
Signed-off-by: eric.gao eric.gao@rock-chips.com ---
arch/arm/mach-rockchip/rk3399/syscon_rk3399.c | 1 + 1 file changed, 1 insertion(+)
diff --git a/arch/arm/mach-rockchip/rk3399/syscon_rk3399.c b/arch/arm/mach-rockchip/rk3399/syscon_rk3399.c index d32985b..74d4552 100644 --- a/arch/arm/mach-rockchip/rk3399/syscon_rk3399.c +++ b/arch/arm/mach-rockchip/rk3399/syscon_rk3399.c @@ -14,6 +14,7 @@ static const struct udevice_id rk3399_syscon_ids[] = { { .compatible = "rockchip,rk3399-pmugrf", .data = ROCKCHIP_SYSCON_PMUGRF }, { .compatible = "rockchip,rk3399-pmusgrf", .data = ROCKCHIP_SYSCON_PMUSGRF }, { .compatible = "rockchip,rk3399-cic", .data = ROCKCHIP_SYSCON_CIC }, + { } };
U_BOOT_DRIVER(syscon_rk3399) = {

On 1 April 2017 at 08:42, eric.gao@rock-chips.com wrote:
From: "eric.gao" eric.gao@rock-chips.com
if we enable PMIC rk808,the system will halt at very early stage ,log is shown as bellow.
INFO: plat_rockchip_pmu_init(1211): pd status 3e INFO: BL31: Initializing runtime services INFO: BL31: Preparing for EL3 exit to normal world INFO: Entry point address = 0x200000 INFO: SPSR = 0x3c9 time 44561b, 0 (<<----Just stop here)
It's caused by the absence of "{ }" in file rk3399/syscon_rk3399.c ,which will lead to memory overflow like below.According to Sysmap file ,we can find the function buck_get_value of rk808 is just follow the compatible struct, the pointer "of_match" point to "buck_get_value", but it is not a struct and don't have member of compatible, In this case,system crash. So,on the face, it looks like that rk808 is guilty. but he is really innocent.
while (of_match->compatible) { <<---------- if (!strcmp(of_match->compatible, compat)) { *of_idp = of_match; return 0; } of_match++; }
Signed-off-by: eric.gao eric.gao@rock-chips.com
arch/arm/mach-rockchip/rk3399/syscon_rk3399.c | 1 + 1 file changed, 1 insertion(+)
Reviewed-by: Simon Glass sjg@chromium.org
(I'm assuming you will resend with the changes Kever mentioned, thanks)

From: "eric.gao" eric.gao@rock-chips.com
Signed-off-by: eric.gao eric.gao@rock-chips.com ---
arch/arm/dts/rk3399.dtsi | 16 ++++++++++++++++ configs/evb-rk3399_defconfig | 1 + drivers/i2c/rk_i2c.c | 1 + 3 files changed, 18 insertions(+)
diff --git a/arch/arm/dts/rk3399.dtsi b/arch/arm/dts/rk3399.dtsi index 456fdb6..93e3bf4 100644 --- a/arch/arm/dts/rk3399.dtsi +++ b/arch/arm/dts/rk3399.dtsi @@ -26,6 +26,7 @@ serial4 = &uart4; mmc0 = &sdhci; mmc1 = &sdmmc; + i2c0 = &i2c0; };
cpus { @@ -651,6 +652,21 @@ status = "disabled"; };
+ i2c0: i2c@ff3c0000 { + compatible = "rockchip,rk3399-i2c"; + reg = <0x0 0xff3c0000 0x0 0x1000>; + assigned-clocks = <&pmucru SCLK_I2C0_PMU>; + assigned-clock-rates = <200000000>; + clocks = <&pmucru SCLK_I2C0_PMU>, <&pmucru PCLK_I2C0_PMU>; + clock-names = "i2c", "pclk"; + interrupts = <GIC_SPI 57 IRQ_TYPE_LEVEL_HIGH 0>; + pinctrl-names = "default"; + pinctrl-0 = <&i2c0_xfer>; + #address-cells = <1>; + #size-cells = <0>; + status = "disabled"; + }; + pinctrl: pinctrl { u-boot,dm-pre-reloc; compatible = "rockchip,rk3399-pinctrl"; diff --git a/configs/evb-rk3399_defconfig b/configs/evb-rk3399_defconfig index bedc1fd..2e2f9a8 100644 --- a/configs/evb-rk3399_defconfig +++ b/configs/evb-rk3399_defconfig @@ -58,3 +58,4 @@ CONFIG_USB_EHCI_GENERIC=y CONFIG_USB_STORAGE=y CONFIG_USE_TINY_PRINTF=y CONFIG_ERRNO_STR=y +CONFIG_SYS_I2C_ROCKCHIP=y diff --git a/drivers/i2c/rk_i2c.c b/drivers/i2c/rk_i2c.c index 7c701cb..a4c8c2ba 100644 --- a/drivers/i2c/rk_i2c.c +++ b/drivers/i2c/rk_i2c.c @@ -381,6 +381,7 @@ static const struct dm_i2c_ops rockchip_i2c_ops = {
static const struct udevice_id rockchip_i2c_ids[] = { { .compatible = "rockchip,rk3288-i2c" }, + { .compatible = "rockchip,rk3399-i2c" }, { } };

Hello Eric,
Am 01.04.2017 um 16:42 schrieb eric.gao@rock-chips.com:
From: "eric.gao" eric.gao@rock-chips.com
Signed-off-by: eric.gao eric.gao@rock-chips.com
arch/arm/dts/rk3399.dtsi | 16 ++++++++++++++++ configs/evb-rk3399_defconfig | 1 + drivers/i2c/rk_i2c.c | 1 + 3 files changed, 18 insertions(+)
Reviewed-by: Heiko Schocher hs@denx.de
bye, Heiko
diff --git a/arch/arm/dts/rk3399.dtsi b/arch/arm/dts/rk3399.dtsi index 456fdb6..93e3bf4 100644 --- a/arch/arm/dts/rk3399.dtsi +++ b/arch/arm/dts/rk3399.dtsi @@ -26,6 +26,7 @@ serial4 = &uart4; mmc0 = &sdhci; mmc1 = &sdmmc;
i2c0 = &i2c0;
};
cpus {
@@ -651,6 +652,21 @@ status = "disabled"; };
- i2c0: i2c@ff3c0000 {
compatible = "rockchip,rk3399-i2c";
reg = <0x0 0xff3c0000 0x0 0x1000>;
assigned-clocks = <&pmucru SCLK_I2C0_PMU>;
assigned-clock-rates = <200000000>;
clocks = <&pmucru SCLK_I2C0_PMU>, <&pmucru PCLK_I2C0_PMU>;
clock-names = "i2c", "pclk";
interrupts = <GIC_SPI 57 IRQ_TYPE_LEVEL_HIGH 0>;
pinctrl-names = "default";
pinctrl-0 = <&i2c0_xfer>;
#address-cells = <1>;
#size-cells = <0>;
status = "disabled";
- };
- pinctrl: pinctrl { u-boot,dm-pre-reloc; compatible = "rockchip,rk3399-pinctrl";
diff --git a/configs/evb-rk3399_defconfig b/configs/evb-rk3399_defconfig index bedc1fd..2e2f9a8 100644 --- a/configs/evb-rk3399_defconfig +++ b/configs/evb-rk3399_defconfig @@ -58,3 +58,4 @@ CONFIG_USB_EHCI_GENERIC=y CONFIG_USB_STORAGE=y CONFIG_USE_TINY_PRINTF=y CONFIG_ERRNO_STR=y +CONFIG_SYS_I2C_ROCKCHIP=y diff --git a/drivers/i2c/rk_i2c.c b/drivers/i2c/rk_i2c.c index 7c701cb..a4c8c2ba 100644 --- a/drivers/i2c/rk_i2c.c +++ b/drivers/i2c/rk_i2c.c @@ -381,6 +381,7 @@ static const struct dm_i2c_ops rockchip_i2c_ops = {
static const struct udevice_id rockchip_i2c_ids[] = { { .compatible = "rockchip,rk3288-i2c" },
- { .compatible = "rockchip,rk3399-i2c" }, { } };

From: "eric.gao" eric.gao@rock-chips.com
Signed-off-by: eric.gao eric.gao@rock-chips.com ---
arch/arm/dts/rk3399-evb.dts | 108 +++++++++++++++++++++++++++++++++++++++++++ configs/evb-rk3399_defconfig | 5 ++ 2 files changed, 113 insertions(+)
diff --git a/arch/arm/dts/rk3399-evb.dts b/arch/arm/dts/rk3399-evb.dts index a959989..7a889c7 100644 --- a/arch/arm/dts/rk3399-evb.dts +++ b/arch/arm/dts/rk3399-evb.dts @@ -51,6 +51,22 @@ regulator-name = "vcc5v0_host"; gpio = <&gpio4 25 GPIO_ACTIVE_HIGH>; }; + + vccsys: vccsys { + compatible = "regulator-fixed"; + regulator-name = "vccsys"; + regulator-boot-on; + regulator-always-on; + }; + vcc33_sys: vcc33-sys { + compatible = "regulator-fixed"; + regulator-name = "vcc33_sys"; + regulator-always-on; + regulator-boot-on; + regulator-min-microvolt = <3300000>; + regulator-max-microvolt = <3300000>; + vin-supply = <&vccsys>; + }; };
&emmc_phy { @@ -110,6 +126,98 @@ status = "okay"; };
+&i2c0 { + status = "okay"; + + clock-frequency = <400000>; + i2c-scl-falling-time-ns = <50>; + i2c-scl-rising-time-ns = <100>; + u-boot,dm-pre-reloc; + + rk808: pmic@1b { + compatible = "rockchip,rk808"; + clock-output-names = "xin32k", "wifibt_32kin"; + interrupt-parent = <&gpio0>; + interrupts = <4 IRQ_TYPE_LEVEL_LOW>; + pinctrl-names = "default"; + pinctrl-0 = <&pmic_int_l>; + reg = <0x1b>; + rockchip,system-power-controller; + #clock-cells = <1>; + u-boot,dm-pre-reloc; + status = "okay"; + + vcc1-supply = <&vcc33_sys>; + vcc2-supply = <&vcc33_sys>; + vcc3-supply = <&vcc33_sys>; + vcc4-supply = <&vcc33_sys>; + vcc6-supply = <&vcc33_sys>; + vcc7-supply = <&vcc33_sys>; + vcc11-supply = <&vcc33_sys>; + vcc12-supply = <&vcc33_sys>; + vddio-supply = <&vcc1v8>; + regulators { + vdd_cpu_b: DCDC_REG1 { + regulator-always-on; + regulator-boot-on; + regulator-min-microvolt = <750000>; + regulator-max-microvolt = <1450000>; + regulator-name = "vdd_cpu_b"; + }; + + vdd_cpu_l: DCDC_REG2 { + regulator-always-on; + regulator-boot-on; + regulator-min-microvolt = <750000>; + regulator-max-microvolt = <1450000>; + regulator-name = "vdd_cpu_l"; + }; + + vcc135_ddr: DCDC_REG3 { + regulator-always-on; + regulator-boot-on; + regulator-name = "vcc135_ddr"; + }; + + vcc18: DCDC_REG4 { + regulator-always-on; + regulator-boot-on; + regulator-min-microvolt = <1800000>; + regulator-max-microvolt = <1800000>; + regulator-name = "vcc_18"; + }; + + vcc1v8_dvp: LDO_REG1 { + regulator-always-on; + regulator-boot-on; + regulator-min-microvolt = <1800000>; + regulator-max-microvolt = <1800000>; + regulator-name = "vcc18_dvp"; + }; + + vcc1v8: LDO_REG3 { + regulator-always-on; + regulator-boot-on; + regulator-min-microvolt = <1800000>; + regulator-max-microvolt = <1800000>; + regulator-name = "vdd_18"; + }; + + vcc3v0: LDO_REG8 { + regulator-min-microvolt = <3000000>; + regulator-max-microvolt = <3000000>; + regulator-name = "vcc3v0"; + }; + + vcc33_lcd: SWITCH_REG2 { + regulator-always-on; + regulator-boot-on; + regulator-name = "vcc33_lcd"; + }; + }; + }; +}; + &pinctrl { pmic { pmic_int_l: pmic-int-l { diff --git a/configs/evb-rk3399_defconfig b/configs/evb-rk3399_defconfig index 2e2f9a8..aac6d2d 100644 --- a/configs/evb-rk3399_defconfig +++ b/configs/evb-rk3399_defconfig @@ -59,3 +59,8 @@ CONFIG_USB_STORAGE=y CONFIG_USE_TINY_PRINTF=y CONFIG_ERRNO_STR=y CONFIG_SYS_I2C_ROCKCHIP=y +CONFIG_DM_PMIC=y +CONFIG_PMIC_CHILDREN=y +CONFIG_SPL_PMIC_CHILDREN=y +CONFIG_PMIC_RK808=y +CONFIG_REGULATOR_RK808=y

On 1 April 2017 at 08:42, eric.gao@rock-chips.com wrote:
From: "eric.gao" eric.gao@rock-chips.com
Signed-off-by: eric.gao eric.gao@rock-chips.com
arch/arm/dts/rk3399-evb.dts | 108 +++++++++++++++++++++++++++++++++++++++++++ configs/evb-rk3399_defconfig | 5 ++ 2 files changed, 113 insertions(+)
Reviewed-by: Simon Glass sjg@chromium.org

From: "eric.gao" eric.gao@rock-chips.com
Signed-off-by: eric.gao eric.gao@rock-chips.com ---
drivers/clk/rockchip/clk_rk3399.c | 4 ++++ 1 file changed, 4 insertions(+)
diff --git a/drivers/clk/rockchip/clk_rk3399.c b/drivers/clk/rockchip/clk_rk3399.c index 922ce7e..cfcd1e4 100644 --- a/drivers/clk/rockchip/clk_rk3399.c +++ b/drivers/clk/rockchip/clk_rk3399.c @@ -20,6 +20,10 @@
DECLARE_GLOBAL_DATA_PTR;
+#ifndef CONFIG_SPL_BUILD +#define CONFIG_SPL_BUILD +#endif + #if CONFIG_IS_ENABLED(OF_PLATDATA) struct rk3399_clk_plat { struct dtd_rockchip_rk3399_cru dtd;

Hi Eric,
Am Samstag, 1. April 2017, 22:42:54 CEST schrieb eric.gao@rock-chips.com:
From: "eric.gao" eric.gao@rock-chips.com
Signed-off-by: eric.gao eric.gao@rock-chips.com
drivers/clk/rockchip/clk_rk3399.c | 4 ++++ 1 file changed, 4 insertions(+)
diff --git a/drivers/clk/rockchip/clk_rk3399.c b/drivers/clk/rockchip/clk_rk3399.c index 922ce7e..cfcd1e4 100644 --- a/drivers/clk/rockchip/clk_rk3399.c +++ b/drivers/clk/rockchip/clk_rk3399.c @@ -20,6 +20,10 @@
DECLARE_GLOBAL_DATA_PTR;
+#ifndef CONFIG_SPL_BUILD +#define CONFIG_SPL_BUILD +#endif
That looks very strange. In all cases your commit message should explain why a change is necessary, i.e. what you want to achieve.
In this special case, also rkclk_init runs from SPL context and inits the clocks already, the full u-boot then finds the clocks already set up as necessary and should have no need to for rkclk_init at all itself.
Heiko

Dear Heiko,
Thanks for your review.
I will add commit for all patches.
The reason I add this declaration is that spl for rk3399 is still not ready, I used
ourself rkloader, which can not initial clock suitable for video module. Anyway,
I will drop this signal patch and wait for spl ready. Thank you.
On 2017年04月02日 19:52, Heiko Stuebner wrote:
Hi Eric,
Am Samstag, 1. April 2017, 22:42:54 CEST schrieb eric.gao@rock-chips.com:
From: "eric.gao" eric.gao@rock-chips.com
Signed-off-by: eric.gao eric.gao@rock-chips.com
drivers/clk/rockchip/clk_rk3399.c | 4 ++++ 1 file changed, 4 insertions(+)
diff --git a/drivers/clk/rockchip/clk_rk3399.c b/drivers/clk/rockchip/clk_rk3399.c index 922ce7e..cfcd1e4 100644 --- a/drivers/clk/rockchip/clk_rk3399.c +++ b/drivers/clk/rockchip/clk_rk3399.c @@ -20,6 +20,10 @@
DECLARE_GLOBAL_DATA_PTR;
+#ifndef CONFIG_SPL_BUILD +#define CONFIG_SPL_BUILD +#endif
That looks very strange. In all cases your commit message should explain why a change is necessary, i.e. what you want to achieve.
In this special case, also rkclk_init runs from SPL context and inits the clocks already, the full u-boot then finds the clocks already set up as necessary and should have no need to for rkclk_init at all itself.
Heiko

From: "eric.gao" eric.gao@rock-chips.com
Signed-off-by: eric.gao eric.gao@rock-chips.com ---
arch/arm/dts/rk3399-evb.dts | 33 ++ arch/arm/dts/rk3399.dtsi | 72 +++++ arch/arm/include/asm/arch-rockchip/cru_rk3399.h | 2 +- arch/arm/include/asm/arch-rockchip/mipi_rk3399.h | 203 +++++++++++++ arch/arm/include/asm/arch-rockchip/vop_rk3288.h | 1 + configs/evb-rk3399_defconfig | 4 + drivers/video/Kconfig | 2 + drivers/video/rockchip/Kconfig | 44 +++ drivers/video/rockchip/Makefile | 7 +- drivers/video/rockchip/panel.c | 81 +++++ drivers/video/rockchip/rk_mipi.c | 371 +++++++++++++++++++++++ drivers/video/rockchip/rk_vop.c | 12 +- 12 files changed, 827 insertions(+), 5 deletions(-) create mode 100644 arch/arm/include/asm/arch-rockchip/mipi_rk3399.h create mode 100644 drivers/video/rockchip/Kconfig create mode 100644 drivers/video/rockchip/panel.c create mode 100644 drivers/video/rockchip/rk_mipi.c
diff --git a/arch/arm/dts/rk3399-evb.dts b/arch/arm/dts/rk3399-evb.dts index 7a889c7..abb00e8 100644 --- a/arch/arm/dts/rk3399-evb.dts +++ b/arch/arm/dts/rk3399-evb.dts @@ -52,6 +52,10 @@ gpio = <&gpio4 25 GPIO_ACTIVE_HIGH>; };
+ panel:panel { + compatible = "BOE,TV080WUM"; + status = "disabled"; + }; vccsys: vccsys { compatible = "regulator-fixed"; regulator-name = "vccsys"; @@ -218,6 +222,35 @@ }; };
+&panel { + backlight_en = <&gpio1 13 GPIO_ACTIVE_HIGH>; + backlight_pwm = <&gpio4 18 GPIO_ACTIVE_HIGH>; + power-supply = <&vcc33_lcd>; + status = "okay"; +}; + +&mipi_dsi { + status = "okay"; + display-timings { + timing0 { + bits-per-pixel = <24>; + clock-frequency = <160000000>; + hfront-porch = <120>; + hsync-len = <20>; + hback-porch = <21>; + hactive = <1200>; + vfront-porch = <21>; + vsync-len = <3>; + vback-porch = <18>; + vactive = <1920>; + hsync-active = <0>; + vsync-active = <0>; + de-active = <1>; + pixelclk-active = <0>; + }; + }; +}; + &pinctrl { pmic { pmic_int_l: pmic-int-l { diff --git a/arch/arm/dts/rk3399.dtsi b/arch/arm/dts/rk3399.dtsi index 93e3bf4..c82e674 100644 --- a/arch/arm/dts/rk3399.dtsi +++ b/arch/arm/dts/rk3399.dtsi @@ -667,6 +667,78 @@ status = "disabled"; };
+ vopl: vop@ff8f0000 { + u-boot,dm-pre-reloc; + compatible = "rockchip,rk3399-vop-lit"; + reg = <0x0 0xff8f0000 0x0 0x3efc>; + interrupts = <GIC_SPI 119 IRQ_TYPE_LEVEL_HIGH 0>; + clocks = <&cru ACLK_VOP1>, <&cru DCLK_VOP1>, <&cru HCLK_VOP1>; + clock-names = "aclk_vop", "dclk_vop", "hclk_vop"; + resets = <&cru SRST_A_VOP1>, <&cru SRST_H_VOP1>, <&cru SRST_D_VOP1>; + reset-names = "axi", "ahb", "dclk"; + status = "okay"; + vopl_out: port { + #address-cells = <1>; + #size-cells = <0>; + vopl_out_mipi: endpoint@0 { + reg = <3>; + remote-endpoint = <&mipi_in_vopl>; + }; + }; + }; + + vopb: vop@ff900000 { + u-boot,dm-pre-reloc; + compatible = "rockchip,rk3399-vop-big"; + reg = <0x0 0xff900000 0x0 0x3efc>; + interrupts = <GIC_SPI 118 IRQ_TYPE_LEVEL_HIGH 0>; + clocks = <&cru ACLK_VOP0>, <&cru DCLK_VOP0>, <&cru HCLK_VOP0>; + #clock-cells = <0>; + clock-names = "aclk_vop", "dclk_vop", "hclk_vop"; + resets = <&cru SRST_A_VOP0>, <&cru SRST_H_VOP0>, <&cru SRST_D_VOP0>; + reset-names = "axi", "ahb", "dclk"; + /*power-domains = <&power RK3399_PD_VOPB>;*/ + status = "okay"; + vopb_out: port { + #address-cells = <1>; + #size-cells = <0>; + vopb_out_mipi: endpoint@0 { + reg = <3>; + remote-endpoint = <&mipi_in_vopb>; + }; + }; + }; + + mipi_dsi: mipi@ff960000 { + compatible = "rockchip,rk3399_mipi_dsi"; + reg = <0x0 0xff960000 0x0 0x8000>; + interrupts = <GIC_SPI 45 IRQ_TYPE_LEVEL_HIGH 0>; + clocks = <&cru SCLK_MIPIDPHY_REF>, <&cru PCLK_MIPI_DSI0>, + <&cru SCLK_DPHY_TX0_CFG>; + clock-names = "ref", "pclk", "phy_cfg"; + rockchip,grf = <&grf>; + #address-cells = <1>; + #size-cells = <0>; + status = "disabled"; + ports { + #address-cells = <1>; + #size-cells = <0>; + reg = <1>; + mipi_in: port { + #address-cells = <1>; + #size-cells = <0>; + mipi_in_vopb: endpoint@0 { + reg = <0>; + remote-endpoint = <&vopb_out_mipi>; + }; + mipi_in_vopl: endpoint@1 { + reg = <1>; + remote-endpoint = <&vopl_out_mipi>; + }; + }; + }; + }; + pinctrl: pinctrl { u-boot,dm-pre-reloc; compatible = "rockchip,rk3399-pinctrl"; diff --git a/arch/arm/include/asm/arch-rockchip/cru_rk3399.h b/arch/arm/include/asm/arch-rockchip/cru_rk3399.h index cf830d0..8aa08d4 100644 --- a/arch/arm/include/asm/arch-rockchip/cru_rk3399.h +++ b/arch/arm/include/asm/arch-rockchip/cru_rk3399.h @@ -74,7 +74,7 @@ check_member(rk3399_cru, sdio1_con[1], 0x594); #define OSC_HZ (24*MHz) #define APLL_HZ (600*MHz) #define GPLL_HZ (594*MHz) -#define CPLL_HZ (384*MHz) +#define CPLL_HZ (594*MHz) #define PPLL_HZ (676*MHz)
#define PMU_PCLK_HZ (48*MHz) diff --git a/arch/arm/include/asm/arch-rockchip/mipi_rk3399.h b/arch/arm/include/asm/arch-rockchip/mipi_rk3399.h new file mode 100644 index 0000000..478cb21 --- /dev/null +++ b/arch/arm/include/asm/arch-rockchip/mipi_rk3399.h @@ -0,0 +1,203 @@ +/* + * Copyright (C) 2017-2025 Fuzhou Rockchip Electronics Co., Ltd + * author: eric.gao@rock-chips.com + * create date: 2017-03-31 + * + * SPDX-License-Identifier: GPL-2.0+ + */ + +#ifndef RK33_MIPI_DSI_H +#define RK33_MIPI_DSI_H + +#define GRF_BASE 0xFF770000 +#define RK_GRF_CON20 0x06250 +#define RK_GRF_CON22 0x06258 +#define MHz 1000000 + +#define MIPI_DSI_HOST0_BASE 0xff960000 +#define MIPI_DSI_HOST1_BASE 0xff968000 + +/* + * function bits definition + * register addr | bits | offest + */ +#define DSI_HOST_BITS(addr, bits, bit_offset) \ + ((addr<<16) | (bits<<8) | (bit_offset)) + +/* DWC_DSI_VERSION_0X3133302A */ +#define VERSION DSI_HOST_BITS(0X000, 32, 0) +#define SHUTDOWNZ DSI_HOST_BITS(0X004, 1, 0) +#define TO_CLK_DIVISION DSI_HOST_BITS(0X008, 8, 8) +#define TX_ESC_CLK_DIVISION DSI_HOST_BITS(0X008, 8, 0) +#define DPI_VCID DSI_HOST_BITS(0X00C, 2, 0) +#define EN18_LOOSELY DSI_HOST_BITS(0X010, 1, 8) +#define DPI_COLOR_CODING DSI_HOST_BITS(0X010, 4, 0) +#define COLORM_ACTIVE_LOW DSI_HOST_BITS(0X014, 1, 4) +#define SHUTD_ACTIVE_LOW DSI_HOST_BITS(0X014, 1, 3) +#define HSYNC_ACTIVE_LOW DSI_HOST_BITS(0X014, 1, 2) +#define VSYNC_ACTIVE_LOW DSI_HOST_BITS(0X014, 1, 1) +#define DATAEN_ACTIVE_LOW DSI_HOST_BITS(0X014, 1, 0) +#define OUTVACT_LPCMD_TIME DSI_HOST_BITS(0X018, 8, 16) +#define INVACT_LPCMD_TIME DSI_HOST_BITS(0X018, 8, 0) +#define CRC_RX_EN DSI_HOST_BITS(0X02C, 1, 4) +#define ECC_RX_EN DSI_HOST_BITS(0X02C, 1, 3) +#define BTA_EN DSI_HOST_BITS(0X02C, 1, 2) +#define EOTP_RX_EN DSI_HOST_BITS(0X02C, 1, 1) +#define EOTP_TX_EN DSI_HOST_BITS(0X02C, 1, 0) +#define GEN_VID_RX DSI_HOST_BITS(0X030, 2, 0) +#define CMD_VIDEO_MODE DSI_HOST_BITS(0X034, 1, 0) +#define VPG_ORIENTATION DSI_HOST_BITS(0X038, 1, 24) +#define VPG_MODE DSI_HOST_BITS(0X038, 1, 20) +#define VPG_EN DSI_HOST_BITS(0X038, 1, 16) +#define LP_CMD_EN DSI_HOST_BITS(0X038, 1, 15) +#define FRAME_BTA_ACK_EN DSI_HOST_BITS(0X038, 1, 14) +#define LP_HFP_EN DSI_HOST_BITS(0X038, 1, 13) +#define LP_HBP_EN DSI_HOST_BITS(0X038, 1, 12) +#define LP_VACT_EN DSI_HOST_BITS(0X038, 1, 11) +#define LP_VFP_EN DSI_HOST_BITS(0X038, 1, 10) +#define LP_VBP_EN DSI_HOST_BITS(0X038, 1, 9) +#define LP_VSA_EN DSI_HOST_BITS(0X038, 1, 8) +#define VID_MODE_TYPE DSI_HOST_BITS(0X038, 2, 0) +#define VID_PKT_SIZE DSI_HOST_BITS(0X03C, 14, 0) +#define NUM_CHUNKS DSI_HOST_BITS(0X040, 13, 0) +#define NULL_PKT_SIZE DSI_HOST_BITS(0X044, 13, 0) +#define VID_HSA_TIME DSI_HOST_BITS(0X048, 12, 0) +#define VID_HBP_TIME DSI_HOST_BITS(0X04C, 12, 0) +#define VID_HLINE_TIME DSI_HOST_BITS(0X050, 15, 0) +#define VID_VSA_LINES DSI_HOST_BITS(0X054, 10, 0) +#define VID_VBP_LINES DSI_HOST_BITS(0X058, 10, 0) +#define VID_VFP_LINES DSI_HOST_BITS(0X05C, 10, 0) +#define VID_ACTIVE_LINES DSI_HOST_BITS(0X060, 14, 0) +#define EDPI_CMD_SIZE DSI_HOST_BITS(0X064, 16, 0) +#define MAX_RD_PKT_SIZE DSI_HOST_BITS(0X068, 1, 24) +#define DCS_LW_TX DSI_HOST_BITS(0X068, 1, 19) +#define DCS_SR_0P_TX DSI_HOST_BITS(0X068, 1, 18) +#define DCS_SW_1P_TX DSI_HOST_BITS(0X068, 1, 17) +#define DCS_SW_0P_TX DSI_HOST_BITS(0X068, 1, 16) +#define GEN_LW_TX DSI_HOST_BITS(0X068, 1, 14) +#define GEN_SR_2P_TX DSI_HOST_BITS(0X068, 1, 13) +#define GEN_SR_1P_TX DSI_HOST_BITS(0X068, 1, 12) +#define GEN_SR_0P_TX DSI_HOST_BITS(0X068, 1, 11) +#define GEN_SW_2P_TX DSI_HOST_BITS(0X068, 1, 10) +#define GEN_SW_1P_TX DSI_HOST_BITS(0X068, 1, 9) +#define GEN_SW_0P_TX DSI_HOST_BITS(0X068, 1, 8) +#define ACK_RQST_EN DSI_HOST_BITS(0X068, 1, 1) +#define TEAR_FX_EN DSI_HOST_BITS(0X068, 1, 0) +#define GEN_WC_MSBYTE DSI_HOST_BITS(0X06C, 14, 16) +#define GEN_WC_LSBYTE DSI_HOST_BITS(0X06C, 8, 8) +#define GEN_VC DSI_HOST_BITS(0X06C, 2, 6) +#define GEN_DT DSI_HOST_BITS(0X06C, 6, 0) +#define GEN_PLD_DATA DSI_HOST_BITS(0X070, 32, 0) +#define GEN_RD_CMD_BUSY DSI_HOST_BITS(0X074, 1, 6) +#define GEN_PLD_R_FULL DSI_HOST_BITS(0X074, 1, 5) +#define GEN_PLD_R_EMPTY DSI_HOST_BITS(0X074, 1, 4) +#define GEN_PLD_W_FULL DSI_HOST_BITS(0X074, 1, 3) +#define GEN_PLD_W_EMPTY DSI_HOST_BITS(0X074, 1, 2) +#define GEN_CMD_FULL DSI_HOST_BITS(0X074, 1, 1) +#define GEN_CMD_EMPTY DSI_HOST_BITS(0X074, 1, 0) +#define HSTX_TO_CNT DSI_HOST_BITS(0X078, 16, 16) +#define LPRX_TO_CNT DSI_HOST_BITS(0X078, 16, 0) +#define HS_RD_TO_CNT DSI_HOST_BITS(0X07C, 16, 0) +#define LP_RD_TO_CNT DSI_HOST_BITS(0X080, 16, 0) +#define PRESP_TO_MODE DSI_HOST_BITS(0X084, 1, 24) +#define HS_WR_TO_CNT DSI_HOST_BITS(0X084, 16, 0) +#define LP_WR_TO_CNT DSI_HOST_BITS(0X088, 16, 0) +#define BTA_TO_CNT DSI_HOST_BITS(0X08C, 16, 0) +#define AUTO_CLKLANE_CTRL DSI_HOST_BITS(0X094, 1, 1) +#define PHY_TXREQUESTCLKHS DSI_HOST_BITS(0X094, 1, 0) +#define PHY_HS2LP_TIME_CLK_LANE DSI_HOST_BITS(0X098, 10, 16) +#define PHY_HS2HS_TIME_CLK_LANE DSI_HOST_BITS(0X098, 10, 0) +#define PHY_HS2LP_TIME DSI_HOST_BITS(0X09C, 8, 24) +#define PHY_LP2HS_TIME DSI_HOST_BITS(0X09C, 8, 16) +#define MAX_RD_TIME DSI_HOST_BITS(0X09C, 15, 0) +#define PHY_FORCEPLL DSI_HOST_BITS(0X0A0, 1, 3) +#define PHY_ENABLECLK DSI_HOST_BITS(0X0A0, 1, 2) +#define PHY_RSTZ DSI_HOST_BITS(0X0A0, 1, 1) +#define PHY_SHUTDOWNZ DSI_HOST_BITS(0X0A0, 1, 0) +#define PHY_STOP_WAIT_TIME DSI_HOST_BITS(0X0A4, 8, 8) +#define N_LANES DSI_HOST_BITS(0X0A4, 2, 0) +#define PHY_TXEXITULPSLAN DSI_HOST_BITS(0X0A8, 1, 3) +#define PHY_TXREQULPSLAN DSI_HOST_BITS(0X0A8, 1, 2) +#define PHY_TXEXITULPSCLK DSI_HOST_BITS(0X0A8, 1, 1) +#define PHY_TXREQULPSCLK DSI_HOST_BITS(0X0A8, 1, 0) +#define PHY_TX_TRIGGERS DSI_HOST_BITS(0X0AC, 4, 0) +#define PHYSTOPSTATECLKLANE DSI_HOST_BITS(0X0B0, 1, 2) +#define PHYLOCK DSI_HOST_BITS(0X0B0, 1, 0) +#define PHY_TESTCLK DSI_HOST_BITS(0X0B4, 1, 1) +#define PHY_TESTCLR DSI_HOST_BITS(0X0B4, 1, 0) +#define PHY_TESTEN DSI_HOST_BITS(0X0B8, 1, 16) +#define PHY_TESTDOUT DSI_HOST_BITS(0X0B8, 8, 8) +#define PHY_TESTDIN DSI_HOST_BITS(0X0B8, 8, 0) +#define PHY_TEST_CTRL1 DSI_HOST_BITS(0X0B8, 17, 0) +#define PHY_TEST_CTRL0 DSI_HOST_BITS(0X0B4, 2, 0) +#define INT_ST0 DSI_HOST_BITS(0X0BC, 21, 0) +#define INT_ST1 DSI_HOST_BITS(0X0C0, 18, 0) +#define INT_MKS0 DSI_HOST_BITS(0X0C4, 21, 0) +#define INT_MKS1 DSI_HOST_BITS(0X0C8, 18, 0) +#define INT_FORCE0 DSI_HOST_BITS(0X0D8, 21, 0) +#define INT_FORCE1 DSI_HOST_BITS(0X0DC, 18, 0) + +#define code_hs_rx_clock 0x34 +#define code_hs_rx_lane0 0x44 +#define code_hs_rx_lane1 0x54 +#define code_hs_rx_lane2 0x84 +#define code_hs_rx_lane3 0x94 + +#define code_pll_input_div_rat 0x17 +#define code_pll_loop_div_rat 0x18 +#define code_pll_vcorange_vcocap 0x10 +#define code_pll_input_loop_div_rat 0x19 +#define code_pll_cpctrl 0x11 + +#define code_hstxdatalanerequsetstatetime 0x70 +#define code_hstxdatalanepreparestatetime 0x71 +#define code_hstxdatalanehszerostatetime 0x72 + +enum vid_mode_type_enum { + NON_BURST_SYNC_PLUSE = 0, + NON_BURST_SYNC_EVENT, + BURST_MODE, +}; + +enum cmd_video_mode { + VIDEO_MODE = 0, + CMD_MODE, +}; + +enum dpi_color_coding { + DPI_16BIT_CFG_1 = 0, + DPI_16BIT_CFG_2, + DPI_16BIT_CFG_3, + DPI_18BIT_CFG_1, + DPI_18BIT_CFG_2, + DPI_24BIT, + DPI_20BIT_YCBCR_422_LP, + DPI_24BIT_YCBCR_422, + DPI_16BIT_YCBCR_422, + DPI_30BIT, + DPI_36BIT, + DPI_12BIT_YCBCR_420, +}; + +enum vop_id { + VOP_B = 0, + VOP_L, +}; + +/* + * Name :rk_write_reg(reg,val) + * + * reg: register name from the above define file,it contain the addr, + * bits number and bits offset + * val: reg value that will be writen to register, it can't be over + * the real bit num limit, For example, TO_CLK_DIVISION have 8 + * bits space, so it's value can't great than 255 + */ +#define GET_VAL(reg, val) ((val & (~(0xffffffff << ((reg & 0xffff) >> 8)))) \ + << (reg&0xff)) | ((readl((reg >> 16)+MIPI_DSI_HOST0_BASE)) & \ + (~((0xffffffff<<(reg&0xff))&(0xffffffff>>\ + (32-(reg&0xff)-((reg>>8)&0xff)))))) +#define GET_ADDR(reg) (reg >> 16)+MIPI_DSI_HOST0_BASE +#define rk_write_reg(reg, val) writel(GET_VAL(reg, val), GET_ADDR(reg)); + +#endif /* end of RK33_MIPI_DSI_H */ diff --git a/arch/arm/include/asm/arch-rockchip/vop_rk3288.h b/arch/arm/include/asm/arch-rockchip/vop_rk3288.h index 0ce3d67..d5599ec 100644 --- a/arch/arm/include/asm/arch-rockchip/vop_rk3288.h +++ b/arch/arm/include/asm/arch-rockchip/vop_rk3288.h @@ -90,6 +90,7 @@ enum vop_modes { VOP_MODE_EDP = 0, VOP_MODE_HDMI, VOP_MODE_LVDS, + VOP_MODE_MIPI, VOP_MODE_NONE, VOP_MODE_AUTO_DETECT, VOP_MODE_UNKNOWN, diff --git a/configs/evb-rk3399_defconfig b/configs/evb-rk3399_defconfig index aac6d2d..b9cb0e8 100644 --- a/configs/evb-rk3399_defconfig +++ b/configs/evb-rk3399_defconfig @@ -64,3 +64,7 @@ CONFIG_PMIC_CHILDREN=y CONFIG_SPL_PMIC_CHILDREN=y CONFIG_PMIC_RK808=y CONFIG_REGULATOR_RK808=y +CONFIG_DM_VIDEO=y +CONFIG_DISPLAY=y +CONFIG_VIDEO_ROCKCHIP=y +CONFIG_DISPLAY_MIPI=y diff --git a/drivers/video/Kconfig b/drivers/video/Kconfig index 2069576..4b03a9a 100644 --- a/drivers/video/Kconfig +++ b/drivers/video/Kconfig @@ -405,6 +405,8 @@ config VIDEO_ROCKCHIP (DSI). This driver supports the on-chip video output device, and targets the Rockchip RK3288.
+source "drivers/video/rockchip/Kconfig" + config VIDEO_SANDBOX_SDL bool "Enable sandbox video console using SDL" depends on SANDBOX diff --git a/drivers/video/rockchip/Kconfig b/drivers/video/rockchip/Kconfig new file mode 100644 index 0000000..72473f6 --- /dev/null +++ b/drivers/video/rockchip/Kconfig @@ -0,0 +1,44 @@ +# +# video drivers configuration +# for rockchip soc +# + +menu "Video Display Port Select" + +config DISPLAY_MIPI + bool "MIPI Port" + depends on VIDEO_ROCKCHIP + help + Select MIPI dsi for video port. + if you want to enable these function,you need + to turn on the DM_VIDEO,VDEIO_ROCKCHIP together + what is more,you shoud also enable the related + power,such as lcd3v3, lcd1v8,lcd1v0 and so on. +config DISPLAY_EDP + bool "EDP Port" + depends on VIDEO_ROCKCHIP + help + Select EDP for video port. + if you want to enable these function,you need + to turn on the DM_VIDEO,VDEIO_ROCKCHIP together + what is more,you shoud also enable the related + power,such as lcd3v3, lcd1v8,lcd1v0 and so on. +config DISPLAY_LVDS + bool "LVDS Port" + depends on VIDEO_ROCKCHIP + help + Select LVDS for video port. + if you want to enable these function,you need + to turn on the DM_VIDEO,VDEIO_ROCKCHIP together + what is more,you shoud also enable the related + power,such as lcd3v3, lcd1v8,lcd1v0 and so on. +config DISPLAY_HDMI + bool "HDMI port" + depends on VIDEO_ROCKCHIP + help + Select HDMI for video port + if you want to enable these function,you need + to turn on the DM_VIDEO,VDEIO_ROCKCHIP together + what is more,you shoud also enable the related + power,such as lcd3v3, lcd1v8,lcd1v0 and so on. +endmenu diff --git a/drivers/video/rockchip/Makefile b/drivers/video/rockchip/Makefile index 7962f86..98b26ea 100644 --- a/drivers/video/rockchip/Makefile +++ b/drivers/video/rockchip/Makefile @@ -5,4 +5,9 @@ # SPDX-License-Identifier: GPL-2.0+ #
-obj-y += rk_edp.o rk_hdmi.o rk_vop.o rk_lvds.o +obj-$(CONFIG_VIDEO_ROCKCHIP) += rk_vop.o +obj-$(CONFIG_VIDEO_ROCKCHIP) += panel.o +obj-$(CONFIG_DISPLAY_MIPI) += rk_mipi.o +obj-$(CONFIG_DISPLAY_EDP) += rk_edp.o +obj-$(CONFIG_DISPLAY_LVDS) += rk_lvds.o +obj-$(CONFIG_DISPLAY_HDMI) += rk_hdmi.o diff --git a/drivers/video/rockchip/panel.c b/drivers/video/rockchip/panel.c new file mode 100644 index 0000000..8b02b0f --- /dev/null +++ b/drivers/video/rockchip/panel.c @@ -0,0 +1,81 @@ +/* + * Copyright (c) 2016, Fuzhou Rockchip Electronics Co., Ltd + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + */ + +#include <common.h> +#include <clk.h> +#include <display.h> +#include <dm.h> +#include <edid.h> +#include <panel.h> +#include <asm/hardware.h> +#include <regmap.h> +#include <syscon.h> +#include <asm/gpio.h> +#include <asm/io.h> +#include <asm/arch/mipi_rk3399.h> +#include <asm/arch/clock.h> +#include <asm/arch/grf_rk3288.h> +#include <dt-bindings/clock/rk3288-cru.h> + +DECLARE_GLOBAL_DATA_PTR; + +static int bind(struct udevice *dev) +{ + debug("Panel bind@%s_Line:%d\n", __func__, __LINE__); + return 0; +} + +static int probe(struct udevice *dev) +{ + debug("Panel probe@%s_Line:%d\n", __func__, __LINE__); + return 0; +} + +int rk_panel_enable_backlight(struct udevice *dev) +{ + struct gpio_desc bg_en, bg_pwm; + int node; + + node = fdt_node_offset_by_compatible(gd->fdt_blob, 0, "BOE,TV080WUM"); + if (node < 0) { + debug("Can't find node@%s_Line:%d\n", __func__, __LINE__); + return -EINVAL; + } + gpio_request_by_name_nodev(gd->fdt_blob, node, "backlight_en", + 0, &bg_en, GPIOD_IS_OUT); + gpio_request_by_name_nodev(gd->fdt_blob, node, + "backlight_pwm", 0, &bg_pwm, GPIOD_IS_OUT); + if (dm_gpio_is_valid(&bg_en)) { + dm_gpio_set_value(&bg_en, 1); + dm_gpio_set_value(&bg_pwm, 1); + } else { + debug("GPIO Invalid@%s_Line:%d\n", __func__, __LINE__); + return -EINVAL; + } + + return 0; +} + +static const struct panel_ops rk_panel_ops = { + .enable_backlight = rk_panel_enable_backlight, +}; + +static const struct udevice_id rk_panel_ids[] = { + { .compatible = "BOE,TV080WUM" }, + { } +}; + +U_BOOT_DRIVER(rk_panel) = { + .name = "rk_panel", + .id = UCLASS_PANEL, + .of_match = rk_panel_ids, + .bind = bind, + .probe = probe, + .ops = &rk_panel_ops, +}; diff --git a/drivers/video/rockchip/rk_mipi.c b/drivers/video/rockchip/rk_mipi.c new file mode 100644 index 0000000..84cfb96 --- /dev/null +++ b/drivers/video/rockchip/rk_mipi.c @@ -0,0 +1,371 @@ +/* + * Copyright (c) 2016, Fuzhou Rockchip Electronics Co., Ltd + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + */ + +#include <common.h> +#include <clk.h> +#include <display.h> +#include <dm.h> +#include <fdtdec.h> +#include <panel.h> +#include <asm/hardware.h> +#include <regmap.h> +#include <syscon.h> +#include <asm/gpio.h> +#include <asm/io.h> +#include <asm/arch/mipi_rk3399.h> +#include <asm/arch/clock.h> +#include <asm/arch/grf_rk3288.h> +#include <dt-bindings/clock/rk3288-cru.h> +#include <dm/uclass-internal.h> + +DECLARE_GLOBAL_DATA_PTR; + +struct mipi_dsi { + u32 ref_clk; + u32 sys_clk; + u32 pix_clk; + u32 phy_clk; + u32 txbyte_clk; + u32 txesc_clk; +}; + +int rk_mipi_read_timing(struct udevice *dev, struct display_timing *timing) +{ + if (fdtdec_decode_display_timing + (gd->fdt_blob, dev_of_offset(dev), 0, timing)) { + debug("%s: Failed to decode display timing\n", __func__); + return -EINVAL; + } + return 0; +} + +int rk_mipi_dsi_enable(struct udevice *dev, struct mipi_dsi *mipi, + const struct display_timing *timing) +{ + int node, timing_node; + int val; + struct display_plat *disp_uc_plat = dev_get_uclass_platdata(dev); + u32 txbyte_clk = mipi->txbyte_clk; + u32 txesc_clk = mipi->txesc_clk; + + txesc_clk = txbyte_clk/(txbyte_clk/txesc_clk + 1); + + /* Select the video source */ + switch (disp_uc_plat->source_id) { + case VOP_B: + val = 0x1 << 16 | 0x0; + writel(val, GRF_BASE+RK_GRF_CON20); + break; + case VOP_L: + val = 0x1 << 16 | 0x1; + writel(val, GRF_BASE+RK_GRF_CON20); + break; + default: + return -EINVAL; + } + + /* Set Controller as TX mode */ + val = 0x1 << 28 | 0x0 << 12; + val |= 0xf << 20 | 0x0 << 4; + val |= 0xf << 16 | 0x0; + writel(val, GRF_BASE+RK_GRF_CON22); + + /* Set Display timing parameter */ + rk_write_reg(VID_HSA_TIME, timing->hsync_len.typ); + rk_write_reg(VID_HBP_TIME, timing->hback_porch.typ); + rk_write_reg(VID_HLINE_TIME, + (timing->hsync_len.typ + + timing->hback_porch.typ + + timing->hactive.typ + + timing->hfront_porch.typ)); + rk_write_reg(VID_VSA_LINES, timing->vsync_len.typ); + rk_write_reg(VID_VBP_LINES, timing->vback_porch.typ); + rk_write_reg(VID_VFP_LINES, timing->vfront_porch.typ); + rk_write_reg(VID_ACTIVE_LINES, timing->vactive.typ); + + /* Set Signal Polarity */ + val = (timing->flags & DISPLAY_FLAGS_HSYNC_LOW) ? 1 : 0; + rk_write_reg(HSYNC_ACTIVE_LOW, val); + + val = (timing->flags & DISPLAY_FLAGS_VSYNC_LOW) ? 1 : 0; + rk_write_reg(VSYNC_ACTIVE_LOW, val); + + val = (timing->flags & DISPLAY_FLAGS_DE_LOW) ? 1 : 0; + rk_write_reg(DISPLAY_FLAGS_DE_LOW, val); + + val = (timing->flags & DISPLAY_FLAGS_PIXDATA_NEGEDGE) ? 1 : 0; + rk_write_reg(COLORM_ACTIVE_LOW, val); + + /* Set video mode */ + rk_write_reg(CMD_VIDEO_MODE, VIDEO_MODE); + + /* Set video mode transmission type as burst mode */ + rk_write_reg(VID_MODE_TYPE, BURST_MODE); + + /* Set pix num in a video package */ + rk_write_reg(VID_PKT_SIZE, 0x4b0); + + /* Set dpi color coding depth 24 bit */ + timing_node = fdt_subnode_offset(gd->fdt_blob, + dev_of_offset(dev), "display-timings"); + node = fdt_first_subnode(gd->fdt_blob, timing_node); + val = fdtdec_get_int(gd->fdt_blob, node, "bits-per-pixel", -1); + switch (val) { + case 16: + rk_write_reg(DPI_COLOR_CODING, DPI_16BIT_CFG_1); + break; + case 24: + rk_write_reg(DPI_COLOR_CODING, DPI_24BIT); + break; + case 30: + rk_write_reg(DPI_COLOR_CODING, DPI_30BIT); + break; + default: + rk_write_reg(DPI_COLOR_CODING, DPI_24BIT); + } + /* Enable low power mode */ + rk_write_reg(LP_CMD_EN, 1); + rk_write_reg(LP_HFP_EN, 1); + rk_write_reg(LP_VACT_EN, 1); + rk_write_reg(LP_VFP_EN, 1); + rk_write_reg(LP_VBP_EN, 1); + rk_write_reg(LP_VSA_EN, 1); + + /* Division for timeout counter clk */ + rk_write_reg(TO_CLK_DIVISION, 0x0a); + + /* Tx esc clk division from txbyte clk */ + rk_write_reg(TX_ESC_CLK_DIVISION, txbyte_clk/txesc_clk); + + /* + * Timeout count for hs<->lp + * transation between Line period + */ + rk_write_reg(HSTX_TO_CNT, 0x3e8); + + /* Phy State transfer timing */ + rk_write_reg(PHY_STOP_WAIT_TIME, 32); + rk_write_reg(PHY_TXREQUESTCLKHS, 1); + rk_write_reg(PHY_HS2LP_TIME, 0x14); + rk_write_reg(PHY_LP2HS_TIME, 0x10); + rk_write_reg(MAX_RD_TIME, 0x2710); + + /* Power on */ + rk_write_reg(SHUTDOWNZ, 1); + + return 0; +} + +/* + * rk mipi dphy write function + */ +static void rk_mipi_phy_write(unsigned char test_code, + unsigned char *test_data, + unsigned char size) +{ + int i = 0; + /* Write Test code */ + rk_write_reg(PHY_TESTCLK, 1); + rk_write_reg(PHY_TESTDIN, test_code); + rk_write_reg(PHY_TESTEN, 1); + rk_write_reg(PHY_TESTCLK, 0); + rk_write_reg(PHY_TESTEN, 0); + + /* Write Test data */ + for (i = 0; i < size; i++) { + rk_write_reg(PHY_TESTCLK, 0); + rk_write_reg(PHY_TESTDIN, test_data[i]); + rk_write_reg(PHY_TESTCLK, 1); + } +} + +/* + * mipi dphy config function. calculate the suitable prediv, + * feedback div,fsfreqrang value ,cap ,lpf and so on + * according to the given pix clk ratthe.and then enable phy + */ +static int rk_mipi_phy_enable(struct mipi_dsi *mipi) +{ + int i; + u64 fbdiv; + u64 prediv = 1; + u64 ddr_clk = mipi->phy_clk; + u32 refclk = mipi->ref_clk; + u32 remain = refclk; + unsigned char test_data[2] = {0}; + + /* dphy fsfreqrang */ + int rang[39][2] = { + {90, 0x01}, {100, 0x10}, {110, 0x20}, {130, 0x01}, + {140, 0x11}, {150, 0x21}, {170, 0x02}, {180, 0x12}, + {200, 0x22}, {220, 0x03}, {240, 0x13}, {250, 0x23}, + {270, 0x04}, {300, 0x14}, {330, 0x05}, {360, 0x15}, + {400, 0x25}, {450, 0x06}, {500, 0x16}, {550, 0x07}, + {600, 0x17}, {650, 0x08}, {700, 0x18}, {750, 0x09}, + {800, 0x19}, {850, 0x29}, {900, 0x39}, {950, 0x0a}, + {1000, 0x1a}, {1050, 0x2a}, {1100, 0x3a}, {1150, 0x0b}, + {1200, 0x1b}, {1250, 0x2b}, {1300, 0x3b}, {1350, 0x0c}, + {1400, 0x1c}, {1450, 0x2c}, {1500, 0x3c} }; + + /* Shutdown mode */ + rk_write_reg(PHY_SHUTDOWNZ, 0); + rk_write_reg(PHY_RSTZ, 0); + rk_write_reg(PHY_TESTCLR, 1); + mdelay(10); + /* Pll locking */ + rk_write_reg(PHY_TESTCLR, 0); + mdelay(10); + + /* config cp and lfp */ + test_data[0] = 0x80 | (ddr_clk / (200*MHz)) << 3 | 0x3; + rk_mipi_phy_write(0x10, test_data, 1); + + test_data[0] = 0x8; + rk_mipi_phy_write(0x11, test_data, 1); + + test_data[0] = 0x80 | 0x40; + rk_mipi_phy_write(0x12, test_data, 1); + + /* select the suitable value for fsfreqrang reg */ + for (i = 0; i < 39; i++) { + if (ddr_clk / (MHz) >= rang[i][0]) + break; + } + test_data[0] = rang[i][1] << 1; + rk_mipi_phy_write(code_hs_rx_lane0, test_data, 1); + /* + * Calculate the best ddrclk and it's + * corresponding div value, If the given + * pixelclock is great than 250M, the ddr + * clk will be fix 1500M.otherwise , it's + * equal to ddr_clk= pixclk*6. + */ + for (i = 1; i < 6; i++) { + if ((ddr_clk * i % refclk < remain) && + (ddr_clk * i / refclk) < 512) { + prediv = i; + remain = ddr_clk * i % refclk; + } + } + fbdiv = ddr_clk * prediv / refclk; + ddr_clk = refclk * fbdiv / prediv; + mipi->phy_clk = ddr_clk; + /* config prediv and feedback reg */ + test_data[0] = prediv - 1; + rk_mipi_phy_write(code_pll_input_div_rat, test_data, 1); + mdelay(2); + test_data[0] = (fbdiv - 1) & 0x1f; + rk_mipi_phy_write(code_pll_loop_div_rat, test_data, 1); + mdelay(2); + test_data[0] = (fbdiv - 1) >> 5 | 0x80; + rk_mipi_phy_write(code_pll_loop_div_rat, test_data, 1); + mdelay(2); + test_data[0] = 0x30; + rk_mipi_phy_write(code_pll_input_loop_div_rat, test_data, 1); + mdelay(2); + + /* rest config */ + test_data[0] = 0x4d; + rk_mipi_phy_write(0x20, test_data, 1); + + test_data[0] = 0x3d; + rk_mipi_phy_write(0x21, test_data, 1); + + test_data[0] = 0xdf; + rk_mipi_phy_write(0x21, test_data, 1); + + test_data[0] = 0x7; + rk_mipi_phy_write(0x22, test_data, 1); + + test_data[0] = 0x80 | 0x7; + rk_mipi_phy_write(0x22, test_data, 1); + + test_data[0] = 0x80 | 15; + rk_mipi_phy_write(code_hstxdatalanerequsetstatetime, + test_data, 1); + test_data[0] = 0x80 | 85; + rk_mipi_phy_write(code_hstxdatalanepreparestatetime, + test_data, 1); + test_data[0] = 0x40 | 10; + rk_mipi_phy_write(code_hstxdatalanehszerostatetime, + test_data, 1); + /* enter into stop mode */ + rk_write_reg(N_LANES, 0x03); + rk_write_reg(PHY_ENABLECLK, 1); + mdelay(10); + rk_write_reg(PHY_FORCEPLL, 1); + mdelay(10); + rk_write_reg(PHY_SHUTDOWNZ, 1); + mdelay(10); + rk_write_reg(PHY_RSTZ, 1); + mdelay(10); + + return 0; +} + +static int enable(struct udevice *dev, int panel_bpp, + const struct display_timing *timing) +{ + struct udevice *panel; + /* Check if there are avalble panel */ + if (uclass_first_device(UCLASS_PANEL, &panel)) { + debug("No panel found@%s_LINE:%d\n", __func__, __LINE__); + return -EINVAL; + } + return panel_enable_backlight(panel); +} + +/* + * probe function: check panel existence and reading + * it's timing. then config mipi dsi controller and + * enable it according to the timing parameter + */ +static int probe(struct udevice *dev) +{ + struct display_timing timing; + struct mipi_dsi mipi; + + /* Read panel timing,and save to struct timing */ + rk_mipi_read_timing(dev, &timing); + + /* fill the mipi controller parameter */ + mipi.ref_clk = 24*MHz; + mipi.sys_clk = mipi.ref_clk; + mipi.pix_clk = timing.pixelclock.typ; + mipi.phy_clk = mipi.pix_clk * 6; + mipi.txbyte_clk = mipi.phy_clk / 8; + mipi.txesc_clk = 20*MHz; + + /* config mipi dsi according to timing and enable it */ + rk_mipi_dsi_enable(dev, &mipi, &timing); + + /* init mipi dsi phy */ + rk_mipi_phy_enable(&mipi); + + return 0; +} + +static const struct dm_display_ops rk_mipi_dsi_ops = { + .read_timing = rk_mipi_read_timing, + .enable = enable, +}; + +static const struct udevice_id rk_mipi_dsi_ids[] = { + { .compatible = "rockchip,rk3399_mipi_dsi" }, + { } +}; + +U_BOOT_DRIVER(rk_mipi_dsi) = { + .name = "rk_mipi_dsi", + .id = UCLASS_DISPLAY, + .of_match = rk_mipi_dsi_ids, + .probe = probe, + .ops = &rk_mipi_dsi_ops, +}; + diff --git a/drivers/video/rockchip/rk_vop.c b/drivers/video/rockchip/rk_vop.c index aeecb58..1de00f1 100644 --- a/drivers/video/rockchip/rk_vop.c +++ b/drivers/video/rockchip/rk_vop.c @@ -109,6 +109,10 @@ void rkvop_mode_set(struct rk3288_vop *regs, clrsetbits_le32(®s->sys_ctrl, M_ALL_OUT_EN, V_HDMI_OUT_EN(1)); break; + case VOP_MODE_MIPI: + clrsetbits_le32(®s->sys_ctrl, M_ALL_OUT_EN, + V_MIPI_OUT_EN(1)); + break; case VOP_MODE_EDP: default: clrsetbits_le32(®s->sys_ctrl, M_ALL_OUT_EN, @@ -245,7 +249,7 @@ int rk_display_init(struct udevice *dev, ulong fbbase, ret = clk_get_by_index(dev, 1, &clk); if (!ret) ret = clk_set_rate(&clk, timing.pixelclock.typ); - if (ret) { + if (!ret) { debug("%s: Failed to set pixel clock: ret=%d\n", __func__, ret); return ret; } @@ -327,7 +331,7 @@ static int rk_vop_probe(struct udevice *dev) for (node = fdt_first_subnode(blob, port); node > 0; node = fdt_next_subnode(blob, node)) { - ret = rk_display_init(dev, plat->base, VIDEO_BPP16, node); + ret = rk_display_init(dev, plat->base, VIDEO_BPP32, node); if (ret) debug("Device failed: ret=%d\n", ret); if (!ret) @@ -342,7 +346,7 @@ static int rk_vop_bind(struct udevice *dev) { struct video_uc_platdata *plat = dev_get_uclass_platdata(dev);
- plat->size = 1920 * 1080 * 2; + plat->size = 1920 * 1200 * 4;
return 0; } @@ -351,6 +355,8 @@ static const struct video_ops rk_vop_ops = { };
static const struct udevice_id rk_vop_ids[] = { + { .compatible = "rockchip,rk3399-vop-big" }, + { .compatible = "rockchip,rk3399-vop-lit" }, { .compatible = "rockchip,rk3288-vop" }, { } };

Hi eric,
2017-04-01 22:42 GMT+08:00 eric.gao@rock-chips.com:
From: "eric.gao" eric.gao@rock-chips.com
Signed-off-by: eric.gao eric.gao@rock-chips.com
arch/arm/dts/rk3399-evb.dts | 33 ++ arch/arm/dts/rk3399.dtsi | 72 +++++ arch/arm/include/asm/arch-rockchip/cru_rk3399.h | 2 +- arch/arm/include/asm/arch-rockchip/mipi_rk3399.h | 203 +++++++++++++ arch/arm/include/asm/arch-rockchip/vop_rk3288.h | 1 + configs/evb-rk3399_defconfig | 4 + drivers/video/Kconfig | 2 + drivers/video/rockchip/Kconfig | 44 +++ drivers/video/rockchip/Makefile | 7 +- drivers/video/rockchip/panel.c | 81 +++++ drivers/video/rockchip/rk_mipi.c | 371 +++++++++++++++++++++++ drivers/video/rockchip/rk_vop.c | 12 +- 12 files changed, 827 insertions(+), 5 deletions(-) create mode 100644 arch/arm/include/asm/arch-rockchip/mipi_rk3399.h create mode 100644 drivers/video/rockchip/Kconfig create mode 100644 drivers/video/rockchip/panel.c create mode 100644 drivers/video/rockchip/rk_mipi.c
diff --git a/arch/arm/dts/rk3399-evb.dts b/arch/arm/dts/rk3399-evb.dts index 7a889c7..abb00e8 100644 --- a/arch/arm/dts/rk3399-evb.dts +++ b/arch/arm/dts/rk3399-evb.dts @@ -52,6 +52,10 @@ gpio = <&gpio4 25 GPIO_ACTIVE_HIGH>; };
panel:panel {
compatible = "BOE,TV080WUM";
status = "disabled";
}; vccsys: vccsys { compatible = "regulator-fixed"; regulator-name = "vccsys";
@@ -218,6 +222,35 @@ }; };
+&panel {
backlight_en = <&gpio1 13 GPIO_ACTIVE_HIGH>;
backlight_pwm = <&gpio4 18 GPIO_ACTIVE_HIGH>;
power-supply = <&vcc33_lcd>;
status = "okay";
+};
+&mipi_dsi {
status = "okay";
display-timings {
timing0 {
bits-per-pixel = <24>;
clock-frequency = <160000000>;
hfront-porch = <120>;
hsync-len = <20>;
hback-porch = <21>;
hactive = <1200>;
vfront-porch = <21>;
vsync-len = <3>;
vback-porch = <18>;
vactive = <1920>;
hsync-active = <0>;
vsync-active = <0>;
de-active = <1>;
pixelclk-active = <0>;
};
};
+};
Evb board can use different screens, so we'd better not hard-code the choice. And, Please split dts changes to a separate patch.
&pinctrl { pmic { pmic_int_l: pmic-int-l { diff --git a/arch/arm/dts/rk3399.dtsi b/arch/arm/dts/rk3399.dtsi index 93e3bf4..c82e674 100644 --- a/arch/arm/dts/rk3399.dtsi +++ b/arch/arm/dts/rk3399.dtsi @@ -667,6 +667,78 @@ status = "disabled"; };
vopl: vop@ff8f0000 {
u-boot,dm-pre-reloc;
compatible = "rockchip,rk3399-vop-lit";
reg = <0x0 0xff8f0000 0x0 0x3efc>;
interrupts = <GIC_SPI 119 IRQ_TYPE_LEVEL_HIGH 0>;
clocks = <&cru ACLK_VOP1>, <&cru DCLK_VOP1>, <&cru HCLK_VOP1>;
clock-names = "aclk_vop", "dclk_vop", "hclk_vop";
resets = <&cru SRST_A_VOP1>, <&cru SRST_H_VOP1>, <&cru SRST_D_VOP1>;
reset-names = "axi", "ahb", "dclk";
status = "okay";
vopl_out: port {
#address-cells = <1>;
#size-cells = <0>;
vopl_out_mipi: endpoint@0 {
reg = <3>;
remote-endpoint = <&mipi_in_vopl>;
};
};
};
vopb: vop@ff900000 {
u-boot,dm-pre-reloc;
compatible = "rockchip,rk3399-vop-big";
reg = <0x0 0xff900000 0x0 0x3efc>;
interrupts = <GIC_SPI 118 IRQ_TYPE_LEVEL_HIGH 0>;
clocks = <&cru ACLK_VOP0>, <&cru DCLK_VOP0>, <&cru HCLK_VOP0>;
#clock-cells = <0>;
clock-names = "aclk_vop", "dclk_vop", "hclk_vop";
resets = <&cru SRST_A_VOP0>, <&cru SRST_H_VOP0>, <&cru SRST_D_VOP0>;
reset-names = "axi", "ahb", "dclk";
/*power-domains = <&power RK3399_PD_VOPB>;*/
status = "okay";
vopb_out: port {
#address-cells = <1>;
#size-cells = <0>;
vopb_out_mipi: endpoint@0 {
reg = <3>;
remote-endpoint = <&mipi_in_vopb>;
};
};
};
mipi_dsi: mipi@ff960000 {
compatible = "rockchip,rk3399_mipi_dsi";
reg = <0x0 0xff960000 0x0 0x8000>;
interrupts = <GIC_SPI 45 IRQ_TYPE_LEVEL_HIGH 0>;
clocks = <&cru SCLK_MIPIDPHY_REF>, <&cru PCLK_MIPI_DSI0>,
<&cru SCLK_DPHY_TX0_CFG>;
clock-names = "ref", "pclk", "phy_cfg";
rockchip,grf = <&grf>;
#address-cells = <1>;
#size-cells = <0>;
status = "disabled";
ports {
#address-cells = <1>;
#size-cells = <0>;
reg = <1>;
mipi_in: port {
#address-cells = <1>;
#size-cells = <0>;
mipi_in_vopb: endpoint@0 {
reg = <0>;
remote-endpoint = <&vopb_out_mipi>;
};
mipi_in_vopl: endpoint@1 {
reg = <1>;
remote-endpoint = <&vopl_out_mipi>;
};
};
};
};
pinctrl: pinctrl { u-boot,dm-pre-reloc; compatible = "rockchip,rk3399-pinctrl";
diff --git a/arch/arm/include/asm/arch-rockchip/cru_rk3399.h b/arch/arm/include/asm/arch-rockchip/cru_rk3399.h index cf830d0..8aa08d4 100644 --- a/arch/arm/include/asm/arch-rockchip/cru_rk3399.h +++ b/arch/arm/include/asm/arch-rockchip/cru_rk3399.h @@ -74,7 +74,7 @@ check_member(rk3399_cru, sdio1_con[1], 0x594); #define OSC_HZ (24*MHz) #define APLL_HZ (600*MHz) #define GPLL_HZ (594*MHz) -#define CPLL_HZ (384*MHz) +#define CPLL_HZ (594*MHz) #define PPLL_HZ (676*MHz)
#define PMU_PCLK_HZ (48*MHz) diff --git a/arch/arm/include/asm/arch-rockchip/mipi_rk3399.h b/arch/arm/include/asm/arch-rockchip/mipi_rk3399.h new file mode 100644 index 0000000..478cb21 --- /dev/null +++ b/arch/arm/include/asm/arch-rockchip/mipi_rk3399.h @@ -0,0 +1,203 @@ +/*
- Copyright (C) 2017-2025 Fuzhou Rockchip Electronics Co., Ltd
- author: eric.gao@rock-chips.com
- create date: 2017-03-31
- SPDX-License-Identifier: GPL-2.0+
- */
+#ifndef RK33_MIPI_DSI_H +#define RK33_MIPI_DSI_H
+#define GRF_BASE 0xFF770000 +#define RK_GRF_CON20 0x06250 +#define RK_GRF_CON22 0x06258 +#define MHz 1000000
+#define MIPI_DSI_HOST0_BASE 0xff960000 +#define MIPI_DSI_HOST1_BASE 0xff968000
+/*
- function bits definition
- register addr | bits | offest
- */
+#define DSI_HOST_BITS(addr, bits, bit_offset) \
((addr<<16) | (bits<<8) | (bit_offset))
+/* DWC_DSI_VERSION_0X3133302A */ +#define VERSION DSI_HOST_BITS(0X000, 32, 0) +#define SHUTDOWNZ DSI_HOST_BITS(0X004, 1, 0) +#define TO_CLK_DIVISION DSI_HOST_BITS(0X008, 8, 8) +#define TX_ESC_CLK_DIVISION DSI_HOST_BITS(0X008, 8, 0) +#define DPI_VCID DSI_HOST_BITS(0X00C, 2, 0) +#define EN18_LOOSELY DSI_HOST_BITS(0X010, 1, 8) +#define DPI_COLOR_CODING DSI_HOST_BITS(0X010, 4, 0) +#define COLORM_ACTIVE_LOW DSI_HOST_BITS(0X014, 1, 4) +#define SHUTD_ACTIVE_LOW DSI_HOST_BITS(0X014, 1, 3) +#define HSYNC_ACTIVE_LOW DSI_HOST_BITS(0X014, 1, 2) +#define VSYNC_ACTIVE_LOW DSI_HOST_BITS(0X014, 1, 1) +#define DATAEN_ACTIVE_LOW DSI_HOST_BITS(0X014, 1, 0) +#define OUTVACT_LPCMD_TIME DSI_HOST_BITS(0X018, 8, 16) +#define INVACT_LPCMD_TIME DSI_HOST_BITS(0X018, 8, 0) +#define CRC_RX_EN DSI_HOST_BITS(0X02C, 1, 4) +#define ECC_RX_EN DSI_HOST_BITS(0X02C, 1, 3) +#define BTA_EN DSI_HOST_BITS(0X02C, 1, 2) +#define EOTP_RX_EN DSI_HOST_BITS(0X02C, 1, 1) +#define EOTP_TX_EN DSI_HOST_BITS(0X02C, 1, 0) +#define GEN_VID_RX DSI_HOST_BITS(0X030, 2, 0) +#define CMD_VIDEO_MODE DSI_HOST_BITS(0X034, 1, 0) +#define VPG_ORIENTATION DSI_HOST_BITS(0X038, 1, 24) +#define VPG_MODE DSI_HOST_BITS(0X038, 1, 20) +#define VPG_EN DSI_HOST_BITS(0X038, 1, 16) +#define LP_CMD_EN DSI_HOST_BITS(0X038, 1, 15) +#define FRAME_BTA_ACK_EN DSI_HOST_BITS(0X038, 1, 14) +#define LP_HFP_EN DSI_HOST_BITS(0X038, 1, 13) +#define LP_HBP_EN DSI_HOST_BITS(0X038, 1, 12) +#define LP_VACT_EN DSI_HOST_BITS(0X038, 1, 11) +#define LP_VFP_EN DSI_HOST_BITS(0X038, 1, 10) +#define LP_VBP_EN DSI_HOST_BITS(0X038, 1, 9) +#define LP_VSA_EN DSI_HOST_BITS(0X038, 1, 8) +#define VID_MODE_TYPE DSI_HOST_BITS(0X038, 2, 0) +#define VID_PKT_SIZE DSI_HOST_BITS(0X03C, 14, 0) +#define NUM_CHUNKS DSI_HOST_BITS(0X040, 13, 0) +#define NULL_PKT_SIZE DSI_HOST_BITS(0X044, 13, 0) +#define VID_HSA_TIME DSI_HOST_BITS(0X048, 12, 0) +#define VID_HBP_TIME DSI_HOST_BITS(0X04C, 12, 0) +#define VID_HLINE_TIME DSI_HOST_BITS(0X050, 15, 0) +#define VID_VSA_LINES DSI_HOST_BITS(0X054, 10, 0) +#define VID_VBP_LINES DSI_HOST_BITS(0X058, 10, 0) +#define VID_VFP_LINES DSI_HOST_BITS(0X05C, 10, 0) +#define VID_ACTIVE_LINES DSI_HOST_BITS(0X060, 14, 0) +#define EDPI_CMD_SIZE DSI_HOST_BITS(0X064, 16, 0) +#define MAX_RD_PKT_SIZE DSI_HOST_BITS(0X068, 1, 24) +#define DCS_LW_TX DSI_HOST_BITS(0X068, 1, 19) +#define DCS_SR_0P_TX DSI_HOST_BITS(0X068, 1, 18) +#define DCS_SW_1P_TX DSI_HOST_BITS(0X068, 1, 17) +#define DCS_SW_0P_TX DSI_HOST_BITS(0X068, 1, 16) +#define GEN_LW_TX DSI_HOST_BITS(0X068, 1, 14) +#define GEN_SR_2P_TX DSI_HOST_BITS(0X068, 1, 13) +#define GEN_SR_1P_TX DSI_HOST_BITS(0X068, 1, 12) +#define GEN_SR_0P_TX DSI_HOST_BITS(0X068, 1, 11) +#define GEN_SW_2P_TX DSI_HOST_BITS(0X068, 1, 10) +#define GEN_SW_1P_TX DSI_HOST_BITS(0X068, 1, 9) +#define GEN_SW_0P_TX DSI_HOST_BITS(0X068, 1, 8) +#define ACK_RQST_EN DSI_HOST_BITS(0X068, 1, 1) +#define TEAR_FX_EN DSI_HOST_BITS(0X068, 1, 0) +#define GEN_WC_MSBYTE DSI_HOST_BITS(0X06C, 14, 16) +#define GEN_WC_LSBYTE DSI_HOST_BITS(0X06C, 8, 8) +#define GEN_VC DSI_HOST_BITS(0X06C, 2, 6) +#define GEN_DT DSI_HOST_BITS(0X06C, 6, 0) +#define GEN_PLD_DATA DSI_HOST_BITS(0X070, 32, 0) +#define GEN_RD_CMD_BUSY DSI_HOST_BITS(0X074, 1, 6) +#define GEN_PLD_R_FULL DSI_HOST_BITS(0X074, 1, 5) +#define GEN_PLD_R_EMPTY DSI_HOST_BITS(0X074, 1, 4) +#define GEN_PLD_W_FULL DSI_HOST_BITS(0X074, 1, 3) +#define GEN_PLD_W_EMPTY DSI_HOST_BITS(0X074, 1, 2) +#define GEN_CMD_FULL DSI_HOST_BITS(0X074, 1, 1) +#define GEN_CMD_EMPTY DSI_HOST_BITS(0X074, 1, 0) +#define HSTX_TO_CNT DSI_HOST_BITS(0X078, 16, 16) +#define LPRX_TO_CNT DSI_HOST_BITS(0X078, 16, 0) +#define HS_RD_TO_CNT DSI_HOST_BITS(0X07C, 16, 0) +#define LP_RD_TO_CNT DSI_HOST_BITS(0X080, 16, 0) +#define PRESP_TO_MODE DSI_HOST_BITS(0X084, 1, 24) +#define HS_WR_TO_CNT DSI_HOST_BITS(0X084, 16, 0) +#define LP_WR_TO_CNT DSI_HOST_BITS(0X088, 16, 0) +#define BTA_TO_CNT DSI_HOST_BITS(0X08C, 16, 0) +#define AUTO_CLKLANE_CTRL DSI_HOST_BITS(0X094, 1, 1) +#define PHY_TXREQUESTCLKHS DSI_HOST_BITS(0X094, 1, 0) +#define PHY_HS2LP_TIME_CLK_LANE DSI_HOST_BITS(0X098, 10, 16) +#define PHY_HS2HS_TIME_CLK_LANE DSI_HOST_BITS(0X098, 10, 0) +#define PHY_HS2LP_TIME DSI_HOST_BITS(0X09C, 8, 24) +#define PHY_LP2HS_TIME DSI_HOST_BITS(0X09C, 8, 16) +#define MAX_RD_TIME DSI_HOST_BITS(0X09C, 15, 0) +#define PHY_FORCEPLL DSI_HOST_BITS(0X0A0, 1, 3) +#define PHY_ENABLECLK DSI_HOST_BITS(0X0A0, 1, 2) +#define PHY_RSTZ DSI_HOST_BITS(0X0A0, 1, 1) +#define PHY_SHUTDOWNZ DSI_HOST_BITS(0X0A0, 1, 0) +#define PHY_STOP_WAIT_TIME DSI_HOST_BITS(0X0A4, 8, 8) +#define N_LANES DSI_HOST_BITS(0X0A4, 2, 0) +#define PHY_TXEXITULPSLAN DSI_HOST_BITS(0X0A8, 1, 3) +#define PHY_TXREQULPSLAN DSI_HOST_BITS(0X0A8, 1, 2) +#define PHY_TXEXITULPSCLK DSI_HOST_BITS(0X0A8, 1, 1) +#define PHY_TXREQULPSCLK DSI_HOST_BITS(0X0A8, 1, 0) +#define PHY_TX_TRIGGERS DSI_HOST_BITS(0X0AC, 4, 0) +#define PHYSTOPSTATECLKLANE DSI_HOST_BITS(0X0B0, 1, 2) +#define PHYLOCK DSI_HOST_BITS(0X0B0, 1, 0) +#define PHY_TESTCLK DSI_HOST_BITS(0X0B4, 1, 1) +#define PHY_TESTCLR DSI_HOST_BITS(0X0B4, 1, 0) +#define PHY_TESTEN DSI_HOST_BITS(0X0B8, 1, 16) +#define PHY_TESTDOUT DSI_HOST_BITS(0X0B8, 8, 8) +#define PHY_TESTDIN DSI_HOST_BITS(0X0B8, 8, 0) +#define PHY_TEST_CTRL1 DSI_HOST_BITS(0X0B8, 17, 0) +#define PHY_TEST_CTRL0 DSI_HOST_BITS(0X0B4, 2, 0) +#define INT_ST0 DSI_HOST_BITS(0X0BC, 21, 0) +#define INT_ST1 DSI_HOST_BITS(0X0C0, 18, 0) +#define INT_MKS0 DSI_HOST_BITS(0X0C4, 21, 0) +#define INT_MKS1 DSI_HOST_BITS(0X0C8, 18, 0) +#define INT_FORCE0 DSI_HOST_BITS(0X0D8, 21, 0) +#define INT_FORCE1 DSI_HOST_BITS(0X0DC, 18, 0)
+#define code_hs_rx_clock 0x34 +#define code_hs_rx_lane0 0x44 +#define code_hs_rx_lane1 0x54 +#define code_hs_rx_lane2 0x84 +#define code_hs_rx_lane3 0x94
+#define code_pll_input_div_rat 0x17 +#define code_pll_loop_div_rat 0x18 +#define code_pll_vcorange_vcocap 0x10 +#define code_pll_input_loop_div_rat 0x19 +#define code_pll_cpctrl 0x11
+#define code_hstxdatalanerequsetstatetime 0x70 +#define code_hstxdatalanepreparestatetime 0x71 +#define code_hstxdatalanehszerostatetime 0x72
+enum vid_mode_type_enum {
NON_BURST_SYNC_PLUSE = 0,
NON_BURST_SYNC_EVENT,
BURST_MODE,
+};
+enum cmd_video_mode {
VIDEO_MODE = 0,
CMD_MODE,
+};
+enum dpi_color_coding {
DPI_16BIT_CFG_1 = 0,
DPI_16BIT_CFG_2,
DPI_16BIT_CFG_3,
DPI_18BIT_CFG_1,
DPI_18BIT_CFG_2,
DPI_24BIT,
DPI_20BIT_YCBCR_422_LP,
DPI_24BIT_YCBCR_422,
DPI_16BIT_YCBCR_422,
DPI_30BIT,
DPI_36BIT,
DPI_12BIT_YCBCR_420,
+};
+enum vop_id {
VOP_B = 0,
VOP_L,
+};
+/*
- Name :rk_write_reg(reg,val)
- reg: register name from the above define file,it contain the addr,
bits number and bits offset
- val: reg value that will be writen to register, it can't be over
the real bit num limit, For example, TO_CLK_DIVISION have 8
bits space, so it's value can't great than 255
- */
+#define GET_VAL(reg, val) ((val & (~(0xffffffff << ((reg & 0xffff) >> 8)))) \
<< (reg&0xff)) | ((readl((reg >> 16)+MIPI_DSI_HOST0_BASE)) & \
(~((0xffffffff<<(reg&0xff))&(0xffffffff>>\
(32-(reg&0xff)-((reg>>8)&0xff))))))
+#define GET_ADDR(reg) (reg >> 16)+MIPI_DSI_HOST0_BASE +#define rk_write_reg(reg, val) writel(GET_VAL(reg, val), GET_ADDR(reg));
+#endif /* end of RK33_MIPI_DSI_H */ diff --git a/arch/arm/include/asm/arch-rockchip/vop_rk3288.h b/arch/arm/include/asm/arch-rockchip/vop_rk3288.h index 0ce3d67..d5599ec 100644 --- a/arch/arm/include/asm/arch-rockchip/vop_rk3288.h +++ b/arch/arm/include/asm/arch-rockchip/vop_rk3288.h @@ -90,6 +90,7 @@ enum vop_modes { VOP_MODE_EDP = 0, VOP_MODE_HDMI, VOP_MODE_LVDS,
VOP_MODE_MIPI, VOP_MODE_NONE, VOP_MODE_AUTO_DETECT, VOP_MODE_UNKNOWN,
diff --git a/configs/evb-rk3399_defconfig b/configs/evb-rk3399_defconfig index aac6d2d..b9cb0e8 100644 --- a/configs/evb-rk3399_defconfig +++ b/configs/evb-rk3399_defconfig @@ -64,3 +64,7 @@ CONFIG_PMIC_CHILDREN=y CONFIG_SPL_PMIC_CHILDREN=y CONFIG_PMIC_RK808=y CONFIG_REGULATOR_RK808=y +CONFIG_DM_VIDEO=y +CONFIG_DISPLAY=y +CONFIG_VIDEO_ROCKCHIP=y +CONFIG_DISPLAY_MIPI=y diff --git a/drivers/video/Kconfig b/drivers/video/Kconfig index 2069576..4b03a9a 100644 --- a/drivers/video/Kconfig +++ b/drivers/video/Kconfig @@ -405,6 +405,8 @@ config VIDEO_ROCKCHIP (DSI). This driver supports the on-chip video output device, and targets the Rockchip RK3288.
+source "drivers/video/rockchip/Kconfig"
config VIDEO_SANDBOX_SDL bool "Enable sandbox video console using SDL" depends on SANDBOX diff --git a/drivers/video/rockchip/Kconfig b/drivers/video/rockchip/Kconfig new file mode 100644 index 0000000..72473f6 --- /dev/null +++ b/drivers/video/rockchip/Kconfig @@ -0,0 +1,44 @@ +# +# video drivers configuration +# for rockchip soc +#
+menu "Video Display Port Select"
+config DISPLAY_MIPI
bool "MIPI Port"
depends on VIDEO_ROCKCHIP
help
Select MIPI dsi for video port.
if you want to enable these function,you need
to turn on the DM_VIDEO,VDEIO_ROCKCHIP together
what is more,you shoud also enable the related
power,such as lcd3v3, lcd1v8,lcd1v0 and so on.
+config DISPLAY_EDP
bool "EDP Port"
depends on VIDEO_ROCKCHIP
help
Select EDP for video port.
if you want to enable these function,you need
to turn on the DM_VIDEO,VDEIO_ROCKCHIP together
what is more,you shoud also enable the related
power,such as lcd3v3, lcd1v8,lcd1v0 and so on.
+config DISPLAY_LVDS
bool "LVDS Port"
depends on VIDEO_ROCKCHIP
help
Select LVDS for video port.
if you want to enable these function,you need
to turn on the DM_VIDEO,VDEIO_ROCKCHIP together
what is more,you shoud also enable the related
power,such as lcd3v3, lcd1v8,lcd1v0 and so on.
+config DISPLAY_HDMI
bool "HDMI port"
depends on VIDEO_ROCKCHIP
help
Select HDMI for video port
if you want to enable these function,you need
to turn on the DM_VIDEO,VDEIO_ROCKCHIP together
what is more,you shoud also enable the related
power,such as lcd3v3, lcd1v8,lcd1v0 and so on.
+endmenu diff --git a/drivers/video/rockchip/Makefile b/drivers/video/rockchip/Makefile index 7962f86..98b26ea 100644 --- a/drivers/video/rockchip/Makefile +++ b/drivers/video/rockchip/Makefile @@ -5,4 +5,9 @@ # SPDX-License-Identifier: GPL-2.0+ #
-obj-y += rk_edp.o rk_hdmi.o rk_vop.o rk_lvds.o +obj-$(CONFIG_VIDEO_ROCKCHIP) += rk_vop.o +obj-$(CONFIG_VIDEO_ROCKCHIP) += panel.o +obj-$(CONFIG_DISPLAY_MIPI) += rk_mipi.o +obj-$(CONFIG_DISPLAY_EDP) += rk_edp.o +obj-$(CONFIG_DISPLAY_LVDS) += rk_lvds.o +obj-$(CONFIG_DISPLAY_HDMI) += rk_hdmi.o diff --git a/drivers/video/rockchip/panel.c b/drivers/video/rockchip/panel.c new file mode 100644 index 0000000..8b02b0f --- /dev/null +++ b/drivers/video/rockchip/panel.c @@ -0,0 +1,81 @@ +/*
- Copyright (c) 2016, Fuzhou Rockchip Electronics Co., Ltd
- This program is free software; you can redistribute it and/or modify
- it under the terms of the GNU General Public License as published by
- the Free Software Foundation; either version 2 of the License, or
- (at your option) any later version.
- */
+#include <common.h> +#include <clk.h> +#include <display.h> +#include <dm.h> +#include <edid.h> +#include <panel.h> +#include <asm/hardware.h> +#include <regmap.h> +#include <syscon.h> +#include <asm/gpio.h> +#include <asm/io.h> +#include <asm/arch/mipi_rk3399.h> +#include <asm/arch/clock.h> +#include <asm/arch/grf_rk3288.h> +#include <dt-bindings/clock/rk3288-cru.h>
+DECLARE_GLOBAL_DATA_PTR;
+static int bind(struct udevice *dev) +{
debug("Panel bind@%s_Line:%d\n", __func__, __LINE__);
return 0;
+}
+static int probe(struct udevice *dev) +{
debug("Panel probe@%s_Line:%d\n", __func__, __LINE__);
return 0;
+}
+int rk_panel_enable_backlight(struct udevice *dev) +{
struct gpio_desc bg_en, bg_pwm;
int node;
node = fdt_node_offset_by_compatible(gd->fdt_blob, 0, "BOE,TV080WUM");
if (node < 0) {
debug("Can't find node@%s_Line:%d\n", __func__, __LINE__);
return -EINVAL;
}
gpio_request_by_name_nodev(gd->fdt_blob, node, "backlight_en",
0, &bg_en, GPIOD_IS_OUT);
gpio_request_by_name_nodev(gd->fdt_blob, node,
"backlight_pwm", 0, &bg_pwm, GPIOD_IS_OUT);
if (dm_gpio_is_valid(&bg_en)) {
dm_gpio_set_value(&bg_en, 1);
dm_gpio_set_value(&bg_pwm, 1);
} else {
debug("GPIO Invalid@%s_Line:%d\n", __func__, __LINE__);
return -EINVAL;
}
return 0;
+}
+static const struct panel_ops rk_panel_ops = {
.enable_backlight = rk_panel_enable_backlight,
+};
+static const struct udevice_id rk_panel_ids[] = {
{ .compatible = "BOE,TV080WUM" },
{ }
+};
+U_BOOT_DRIVER(rk_panel) = {
.name = "rk_panel",
.id = UCLASS_PANEL,
.of_match = rk_panel_ids,
.bind = bind,
.probe = probe,
.ops = &rk_panel_ops,
+};
Why not use simple_panel?
diff --git a/drivers/video/rockchip/rk_mipi.c b/drivers/video/rockchip/rk_mipi.c new file mode 100644 index 0000000..84cfb96 --- /dev/null +++ b/drivers/video/rockchip/rk_mipi.c @@ -0,0 +1,371 @@ +/*
- Copyright (c) 2016, Fuzhou Rockchip Electronics Co., Ltd
- This program is free software; you can redistribute it and/or modify
- it under the terms of the GNU General Public License as published by
- the Free Software Foundation; either version 2 of the License, or
- (at your option) any later version.
- */
+#include <common.h> +#include <clk.h> +#include <display.h> +#include <dm.h> +#include <fdtdec.h> +#include <panel.h> +#include <asm/hardware.h> +#include <regmap.h> +#include <syscon.h> +#include <asm/gpio.h> +#include <asm/io.h> +#include <asm/arch/mipi_rk3399.h> +#include <asm/arch/clock.h> +#include <asm/arch/grf_rk3288.h> +#include <dt-bindings/clock/rk3288-cru.h> +#include <dm/uclass-internal.h>
+DECLARE_GLOBAL_DATA_PTR;
+struct mipi_dsi {
u32 ref_clk;
u32 sys_clk;
u32 pix_clk;
u32 phy_clk;
u32 txbyte_clk;
u32 txesc_clk;
+};
+int rk_mipi_read_timing(struct udevice *dev, struct display_timing *timing) +{
if (fdtdec_decode_display_timing
(gd->fdt_blob, dev_of_offset(dev), 0, timing)) {
debug("%s: Failed to decode display timing\n", __func__);
return -EINVAL;
}
return 0;
+}
+int rk_mipi_dsi_enable(struct udevice *dev, struct mipi_dsi *mipi,
const struct display_timing *timing)
+{
int node, timing_node;
int val;
struct display_plat *disp_uc_plat = dev_get_uclass_platdata(dev);
u32 txbyte_clk = mipi->txbyte_clk;
u32 txesc_clk = mipi->txesc_clk;
txesc_clk = txbyte_clk/(txbyte_clk/txesc_clk + 1);
/* Select the video source */
switch (disp_uc_plat->source_id) {
case VOP_B:
val = 0x1 << 16 | 0x0;
writel(val, GRF_BASE+RK_GRF_CON20);
break;
case VOP_L:
val = 0x1 << 16 | 0x1;
writel(val, GRF_BASE+RK_GRF_CON20);
break;
default:
return -EINVAL;
}
/* Set Controller as TX mode */
val = 0x1 << 28 | 0x0 << 12;
val |= 0xf << 20 | 0x0 << 4;
val |= 0xf << 16 | 0x0;
writel(val, GRF_BASE+RK_GRF_CON22);
/* Set Display timing parameter */
rk_write_reg(VID_HSA_TIME, timing->hsync_len.typ);
rk_write_reg(VID_HBP_TIME, timing->hback_porch.typ);
rk_write_reg(VID_HLINE_TIME,
(timing->hsync_len.typ +
timing->hback_porch.typ +
timing->hactive.typ +
timing->hfront_porch.typ));
rk_write_reg(VID_VSA_LINES, timing->vsync_len.typ);
rk_write_reg(VID_VBP_LINES, timing->vback_porch.typ);
rk_write_reg(VID_VFP_LINES, timing->vfront_porch.typ);
rk_write_reg(VID_ACTIVE_LINES, timing->vactive.typ);
/* Set Signal Polarity */
val = (timing->flags & DISPLAY_FLAGS_HSYNC_LOW) ? 1 : 0;
rk_write_reg(HSYNC_ACTIVE_LOW, val);
val = (timing->flags & DISPLAY_FLAGS_VSYNC_LOW) ? 1 : 0;
rk_write_reg(VSYNC_ACTIVE_LOW, val);
val = (timing->flags & DISPLAY_FLAGS_DE_LOW) ? 1 : 0;
rk_write_reg(DISPLAY_FLAGS_DE_LOW, val);
val = (timing->flags & DISPLAY_FLAGS_PIXDATA_NEGEDGE) ? 1 : 0;
rk_write_reg(COLORM_ACTIVE_LOW, val);
/* Set video mode */
rk_write_reg(CMD_VIDEO_MODE, VIDEO_MODE);
/* Set video mode transmission type as burst mode */
rk_write_reg(VID_MODE_TYPE, BURST_MODE);
/* Set pix num in a video package */
rk_write_reg(VID_PKT_SIZE, 0x4b0);
/* Set dpi color coding depth 24 bit */
timing_node = fdt_subnode_offset(gd->fdt_blob,
dev_of_offset(dev), "display-timings");
node = fdt_first_subnode(gd->fdt_blob, timing_node);
val = fdtdec_get_int(gd->fdt_blob, node, "bits-per-pixel", -1);
switch (val) {
case 16:
rk_write_reg(DPI_COLOR_CODING, DPI_16BIT_CFG_1);
break;
case 24:
rk_write_reg(DPI_COLOR_CODING, DPI_24BIT);
break;
case 30:
rk_write_reg(DPI_COLOR_CODING, DPI_30BIT);
break;
default:
rk_write_reg(DPI_COLOR_CODING, DPI_24BIT);
}
/* Enable low power mode */
rk_write_reg(LP_CMD_EN, 1);
rk_write_reg(LP_HFP_EN, 1);
rk_write_reg(LP_VACT_EN, 1);
rk_write_reg(LP_VFP_EN, 1);
rk_write_reg(LP_VBP_EN, 1);
rk_write_reg(LP_VSA_EN, 1);
/* Division for timeout counter clk */
rk_write_reg(TO_CLK_DIVISION, 0x0a);
/* Tx esc clk division from txbyte clk */
rk_write_reg(TX_ESC_CLK_DIVISION, txbyte_clk/txesc_clk);
/*
* Timeout count for hs<->lp
* transation between Line period
*/
rk_write_reg(HSTX_TO_CNT, 0x3e8);
/* Phy State transfer timing */
rk_write_reg(PHY_STOP_WAIT_TIME, 32);
rk_write_reg(PHY_TXREQUESTCLKHS, 1);
rk_write_reg(PHY_HS2LP_TIME, 0x14);
rk_write_reg(PHY_LP2HS_TIME, 0x10);
rk_write_reg(MAX_RD_TIME, 0x2710);
/* Power on */
rk_write_reg(SHUTDOWNZ, 1);
return 0;
+}
+/*
- rk mipi dphy write function
- */
+static void rk_mipi_phy_write(unsigned char test_code,
unsigned char *test_data,
unsigned char size)
+{
int i = 0;
/* Write Test code */
rk_write_reg(PHY_TESTCLK, 1);
rk_write_reg(PHY_TESTDIN, test_code);
rk_write_reg(PHY_TESTEN, 1);
rk_write_reg(PHY_TESTCLK, 0);
rk_write_reg(PHY_TESTEN, 0);
/* Write Test data */
for (i = 0; i < size; i++) {
rk_write_reg(PHY_TESTCLK, 0);
rk_write_reg(PHY_TESTDIN, test_data[i]);
rk_write_reg(PHY_TESTCLK, 1);
}
+}
+/*
- mipi dphy config function. calculate the suitable prediv,
- feedback div,fsfreqrang value ,cap ,lpf and so on
- according to the given pix clk ratthe.and then enable phy
- */
+static int rk_mipi_phy_enable(struct mipi_dsi *mipi) +{
int i;
u64 fbdiv;
u64 prediv = 1;
u64 ddr_clk = mipi->phy_clk;
u32 refclk = mipi->ref_clk;
u32 remain = refclk;
unsigned char test_data[2] = {0};
/* dphy fsfreqrang */
int rang[39][2] = {
{90, 0x01}, {100, 0x10}, {110, 0x20}, {130, 0x01},
{140, 0x11}, {150, 0x21}, {170, 0x02}, {180, 0x12},
{200, 0x22}, {220, 0x03}, {240, 0x13}, {250, 0x23},
{270, 0x04}, {300, 0x14}, {330, 0x05}, {360, 0x15},
{400, 0x25}, {450, 0x06}, {500, 0x16}, {550, 0x07},
{600, 0x17}, {650, 0x08}, {700, 0x18}, {750, 0x09},
{800, 0x19}, {850, 0x29}, {900, 0x39}, {950, 0x0a},
{1000, 0x1a}, {1050, 0x2a}, {1100, 0x3a}, {1150, 0x0b},
{1200, 0x1b}, {1250, 0x2b}, {1300, 0x3b}, {1350, 0x0c},
{1400, 0x1c}, {1450, 0x2c}, {1500, 0x3c} };
/* Shutdown mode */
rk_write_reg(PHY_SHUTDOWNZ, 0);
rk_write_reg(PHY_RSTZ, 0);
rk_write_reg(PHY_TESTCLR, 1);
mdelay(10);
/* Pll locking */
rk_write_reg(PHY_TESTCLR, 0);
mdelay(10);
/* config cp and lfp */
test_data[0] = 0x80 | (ddr_clk / (200*MHz)) << 3 | 0x3;
rk_mipi_phy_write(0x10, test_data, 1);
test_data[0] = 0x8;
rk_mipi_phy_write(0x11, test_data, 1);
test_data[0] = 0x80 | 0x40;
rk_mipi_phy_write(0x12, test_data, 1);
/* select the suitable value for fsfreqrang reg */
for (i = 0; i < 39; i++) {
if (ddr_clk / (MHz) >= rang[i][0])
break;
}
test_data[0] = rang[i][1] << 1;
rk_mipi_phy_write(code_hs_rx_lane0, test_data, 1);
/*
* Calculate the best ddrclk and it's
* corresponding div value, If the given
* pixelclock is great than 250M, the ddr
* clk will be fix 1500M.otherwise , it's
* equal to ddr_clk= pixclk*6.
*/
for (i = 1; i < 6; i++) {
if ((ddr_clk * i % refclk < remain) &&
(ddr_clk * i / refclk) < 512) {
prediv = i;
remain = ddr_clk * i % refclk;
}
}
fbdiv = ddr_clk * prediv / refclk;
ddr_clk = refclk * fbdiv / prediv;
mipi->phy_clk = ddr_clk;
/* config prediv and feedback reg */
test_data[0] = prediv - 1;
rk_mipi_phy_write(code_pll_input_div_rat, test_data, 1);
mdelay(2);
test_data[0] = (fbdiv - 1) & 0x1f;
rk_mipi_phy_write(code_pll_loop_div_rat, test_data, 1);
mdelay(2);
test_data[0] = (fbdiv - 1) >> 5 | 0x80;
rk_mipi_phy_write(code_pll_loop_div_rat, test_data, 1);
mdelay(2);
test_data[0] = 0x30;
rk_mipi_phy_write(code_pll_input_loop_div_rat, test_data, 1);
mdelay(2);
/* rest config */
test_data[0] = 0x4d;
rk_mipi_phy_write(0x20, test_data, 1);
test_data[0] = 0x3d;
rk_mipi_phy_write(0x21, test_data, 1);
test_data[0] = 0xdf;
rk_mipi_phy_write(0x21, test_data, 1);
test_data[0] = 0x7;
rk_mipi_phy_write(0x22, test_data, 1);
test_data[0] = 0x80 | 0x7;
rk_mipi_phy_write(0x22, test_data, 1);
test_data[0] = 0x80 | 15;
rk_mipi_phy_write(code_hstxdatalanerequsetstatetime,
test_data, 1);
test_data[0] = 0x80 | 85;
rk_mipi_phy_write(code_hstxdatalanepreparestatetime,
test_data, 1);
test_data[0] = 0x40 | 10;
rk_mipi_phy_write(code_hstxdatalanehszerostatetime,
test_data, 1);
/* enter into stop mode */
rk_write_reg(N_LANES, 0x03);
rk_write_reg(PHY_ENABLECLK, 1);
mdelay(10);
rk_write_reg(PHY_FORCEPLL, 1);
mdelay(10);
rk_write_reg(PHY_SHUTDOWNZ, 1);
mdelay(10);
rk_write_reg(PHY_RSTZ, 1);
mdelay(10);
return 0;
+}
+static int enable(struct udevice *dev, int panel_bpp,
const struct display_timing *timing)
+{
struct udevice *panel;
/* Check if there are avalble panel */
if (uclass_first_device(UCLASS_PANEL, &panel)) {
debug("No panel found@%s_LINE:%d\n", __func__, __LINE__);
return -EINVAL;
}
return panel_enable_backlight(panel);
+}
+/*
- probe function: check panel existence and reading
- it's timing. then config mipi dsi controller and
- enable it according to the timing parameter
- */
+static int probe(struct udevice *dev) +{
struct display_timing timing;
struct mipi_dsi mipi;
/* Read panel timing,and save to struct timing */
rk_mipi_read_timing(dev, &timing);
/* fill the mipi controller parameter */
mipi.ref_clk = 24*MHz;
mipi.sys_clk = mipi.ref_clk;
mipi.pix_clk = timing.pixelclock.typ;
mipi.phy_clk = mipi.pix_clk * 6;
mipi.txbyte_clk = mipi.phy_clk / 8;
mipi.txesc_clk = 20*MHz;
/* config mipi dsi according to timing and enable it */
rk_mipi_dsi_enable(dev, &mipi, &timing);
/* init mipi dsi phy */
rk_mipi_phy_enable(&mipi);
return 0;
+}
+static const struct dm_display_ops rk_mipi_dsi_ops = {
.read_timing = rk_mipi_read_timing,
.enable = enable,
+};
+static const struct udevice_id rk_mipi_dsi_ids[] = {
{ .compatible = "rockchip,rk3399_mipi_dsi" },
{ }
+};
+U_BOOT_DRIVER(rk_mipi_dsi) = {
.name = "rk_mipi_dsi",
.id = UCLASS_DISPLAY,
.of_match = rk_mipi_dsi_ids,
.probe = probe,
.ops = &rk_mipi_dsi_ops,
+};
diff --git a/drivers/video/rockchip/rk_vop.c b/drivers/video/rockchip/rk_vop.c index aeecb58..1de00f1 100644 --- a/drivers/video/rockchip/rk_vop.c +++ b/drivers/video/rockchip/rk_vop.c @@ -109,6 +109,10 @@ void rkvop_mode_set(struct rk3288_vop *regs, clrsetbits_le32(®s->sys_ctrl, M_ALL_OUT_EN, V_HDMI_OUT_EN(1)); break;
case VOP_MODE_MIPI:
clrsetbits_le32(®s->sys_ctrl, M_ALL_OUT_EN,
V_MIPI_OUT_EN(1));
break; case VOP_MODE_EDP: default: clrsetbits_le32(®s->sys_ctrl, M_ALL_OUT_EN,
@@ -245,7 +249,7 @@ int rk_display_init(struct udevice *dev, ulong fbbase, ret = clk_get_by_index(dev, 1, &clk); if (!ret) ret = clk_set_rate(&clk, timing.pixelclock.typ);
if (ret) {
if (!ret) { debug("%s: Failed to set pixel clock: ret=%d\n", __func__, ret); return ret; }
@@ -327,7 +331,7 @@ static int rk_vop_probe(struct udevice *dev) for (node = fdt_first_subnode(blob, port); node > 0; node = fdt_next_subnode(blob, node)) {
ret = rk_display_init(dev, plat->base, VIDEO_BPP16, node);
ret = rk_display_init(dev, plat->base, VIDEO_BPP32, node); if (ret) debug("Device failed: ret=%d\n", ret); if (!ret)
@@ -342,7 +346,7 @@ static int rk_vop_bind(struct udevice *dev) { struct video_uc_platdata *plat = dev_get_uclass_platdata(dev);
plat->size = 1920 * 1080 * 2;
plat->size = 1920 * 1200 * 4; return 0;
} @@ -351,6 +355,8 @@ static const struct video_ops rk_vop_ops = { };
static const struct udevice_id rk_vop_ids[] = {
{ .compatible = "rockchip,rk3399-vop-big" },
{ .compatible = "rockchip,rk3399-vop-lit" }, { .compatible = "rockchip,rk3288-vop" }, { }
};
{ .compatible = "rockchip,rk3288-vop" },
1.9.1
U-Boot mailing list U-Boot@lists.denx.de https://lists.denx.de/listinfo/u-boot

Hi Eric,
On 1 April 2017 at 08:42, eric.gao@rock-chips.com wrote:
From: "eric.gao" eric.gao@rock-chips.com
Signed-off-by: eric.gao eric.gao@rock-chips.com
arch/arm/dts/rk3399-evb.dts | 33 ++ arch/arm/dts/rk3399.dtsi | 72 +++++
Please can you put the .dts changes in a separate patch?
arch/arm/include/asm/arch-rockchip/cru_rk3399.h | 2 +- arch/arm/include/asm/arch-rockchip/mipi_rk3399.h | 203 +++++++++++++ arch/arm/include/asm/arch-rockchip/vop_rk3288.h | 1 + configs/evb-rk3399_defconfig | 4 +
Also enabling it for a board should be in a separate patch.
drivers/video/Kconfig | 2 + drivers/video/rockchip/Kconfig | 44 +++ drivers/video/rockchip/Makefile | 7 +- drivers/video/rockchip/panel.c | 81 +++++ drivers/video/rockchip/rk_mipi.c | 371 +++++++++++++++++++++++ drivers/video/rockchip/rk_vop.c | 12 +-
And the actual driver should be in a driver patch. So I think you want 3 patches altogether.
12 files changed, 827 insertions(+), 5 deletions(-) create mode 100644 arch/arm/include/asm/arch-rockchip/mipi_rk3399.h create mode 100644 drivers/video/rockchip/Kconfig create mode 100644 drivers/video/rockchip/panel.c create mode 100644 drivers/video/rockchip/rk_mipi.c
diff --git a/arch/arm/dts/rk3399-evb.dts b/arch/arm/dts/rk3399-evb.dts index 7a889c7..abb00e8 100644 --- a/arch/arm/dts/rk3399-evb.dts +++ b/arch/arm/dts/rk3399-evb.dts @@ -52,6 +52,10 @@ gpio = <&gpio4 25 GPIO_ACTIVE_HIGH>; };
panel:panel {
compatible = "BOE,TV080WUM";
status = "disabled";
}; vccsys: vccsys { compatible = "regulator-fixed"; regulator-name = "vccsys";
@@ -218,6 +222,35 @@ }; };
+&panel {
backlight_en = <&gpio1 13 GPIO_ACTIVE_HIGH>;
backlight_pwm = <&gpio4 18 GPIO_ACTIVE_HIGH>;
power-supply = <&vcc33_lcd>;
status = "okay";
+};
+&mipi_dsi {
status = "okay";
display-timings {
timing0 {
bits-per-pixel = <24>;
clock-frequency = <160000000>;
hfront-porch = <120>;
hsync-len = <20>;
hback-porch = <21>;
hactive = <1200>;
vfront-porch = <21>;
vsync-len = <3>;
vback-porch = <18>;
vactive = <1920>;
hsync-active = <0>;
vsync-active = <0>;
de-active = <1>;
pixelclk-active = <0>;
};
};
+};
&pinctrl { pmic { pmic_int_l: pmic-int-l { diff --git a/arch/arm/dts/rk3399.dtsi b/arch/arm/dts/rk3399.dtsi index 93e3bf4..c82e674 100644 --- a/arch/arm/dts/rk3399.dtsi +++ b/arch/arm/dts/rk3399.dtsi @@ -667,6 +667,78 @@ status = "disabled"; };
vopl: vop@ff8f0000 {
u-boot,dm-pre-reloc;
compatible = "rockchip,rk3399-vop-lit";
reg = <0x0 0xff8f0000 0x0 0x3efc>;
interrupts = <GIC_SPI 119 IRQ_TYPE_LEVEL_HIGH 0>;
clocks = <&cru ACLK_VOP1>, <&cru DCLK_VOP1>, <&cru HCLK_VOP1>;
clock-names = "aclk_vop", "dclk_vop", "hclk_vop";
resets = <&cru SRST_A_VOP1>, <&cru SRST_H_VOP1>, <&cru SRST_D_VOP1>;
reset-names = "axi", "ahb", "dclk";
status = "okay";
vopl_out: port {
#address-cells = <1>;
#size-cells = <0>;
vopl_out_mipi: endpoint@0 {
reg = <3>;
remote-endpoint = <&mipi_in_vopl>;
};
};
};
vopb: vop@ff900000 {
u-boot,dm-pre-reloc;
compatible = "rockchip,rk3399-vop-big";
reg = <0x0 0xff900000 0x0 0x3efc>;
interrupts = <GIC_SPI 118 IRQ_TYPE_LEVEL_HIGH 0>;
clocks = <&cru ACLK_VOP0>, <&cru DCLK_VOP0>, <&cru HCLK_VOP0>;
#clock-cells = <0>;
clock-names = "aclk_vop", "dclk_vop", "hclk_vop";
resets = <&cru SRST_A_VOP0>, <&cru SRST_H_VOP0>, <&cru SRST_D_VOP0>;
reset-names = "axi", "ahb", "dclk";
/*power-domains = <&power RK3399_PD_VOPB>;*/
status = "okay";
vopb_out: port {
#address-cells = <1>;
#size-cells = <0>;
vopb_out_mipi: endpoint@0 {
reg = <3>;
remote-endpoint = <&mipi_in_vopb>;
};
};
};
mipi_dsi: mipi@ff960000 {
compatible = "rockchip,rk3399_mipi_dsi";
reg = <0x0 0xff960000 0x0 0x8000>;
interrupts = <GIC_SPI 45 IRQ_TYPE_LEVEL_HIGH 0>;
clocks = <&cru SCLK_MIPIDPHY_REF>, <&cru PCLK_MIPI_DSI0>,
<&cru SCLK_DPHY_TX0_CFG>;
clock-names = "ref", "pclk", "phy_cfg";
rockchip,grf = <&grf>;
#address-cells = <1>;
#size-cells = <0>;
status = "disabled";
ports {
#address-cells = <1>;
#size-cells = <0>;
reg = <1>;
mipi_in: port {
#address-cells = <1>;
#size-cells = <0>;
mipi_in_vopb: endpoint@0 {
reg = <0>;
remote-endpoint = <&vopb_out_mipi>;
};
mipi_in_vopl: endpoint@1 {
reg = <1>;
remote-endpoint = <&vopl_out_mipi>;
};
};
};
};
pinctrl: pinctrl { u-boot,dm-pre-reloc; compatible = "rockchip,rk3399-pinctrl";
diff --git a/arch/arm/include/asm/arch-rockchip/cru_rk3399.h b/arch/arm/include/asm/arch-rockchip/cru_rk3399.h index cf830d0..8aa08d4 100644 --- a/arch/arm/include/asm/arch-rockchip/cru_rk3399.h +++ b/arch/arm/include/asm/arch-rockchip/cru_rk3399.h @@ -74,7 +74,7 @@ check_member(rk3399_cru, sdio1_con[1], 0x594); #define OSC_HZ (24*MHz) #define APLL_HZ (600*MHz) #define GPLL_HZ (594*MHz) -#define CPLL_HZ (384*MHz) +#define CPLL_HZ (594*MHz) #define PPLL_HZ (676*MHz)
#define PMU_PCLK_HZ (48*MHz) diff --git a/arch/arm/include/asm/arch-rockchip/mipi_rk3399.h b/arch/arm/include/asm/arch-rockchip/mipi_rk3399.h new file mode 100644 index 0000000..478cb21 --- /dev/null +++ b/arch/arm/include/asm/arch-rockchip/mipi_rk3399.h @@ -0,0 +1,203 @@ +/*
- Copyright (C) 2017-2025 Fuzhou Rockchip Electronics Co., Ltd
- author: eric.gao@rock-chips.com
- create date: 2017-03-31
- SPDX-License-Identifier: GPL-2.0+
- */
+#ifndef RK33_MIPI_DSI_H +#define RK33_MIPI_DSI_H
+#define GRF_BASE 0xFF770000
Can we get this from the device tree? We have a SYSCON for GRF I think.
+#define RK_GRF_CON20 0x06250 +#define RK_GRF_CON22 0x06258 +#define MHz 1000000
Don't we have this defined somewhere?
+#define MIPI_DSI_HOST0_BASE 0xff960000 +#define MIPI_DSI_HOST1_BASE 0xff968000
Can we get these from the device tree?
+/*
- function bits definition
Function bits for what? Can you expand the comment?
- register addr | bits | offest
- */
+#define DSI_HOST_BITS(addr, bits, bit_offset) \
((addr<<16) | (bits<<8) | (bit_offset))
+/* DWC_DSI_VERSION_0X3133302A */ +#define VERSION DSI_HOST_BITS(0X000, 32, 0) +#define SHUTDOWNZ DSI_HOST_BITS(0X004, 1, 0) +#define TO_CLK_DIVISION DSI_HOST_BITS(0X008, 8, 8) +#define TX_ESC_CLK_DIVISION DSI_HOST_BITS(0X008, 8, 0) +#define DPI_VCID DSI_HOST_BITS(0X00C, 2, 0) +#define EN18_LOOSELY DSI_HOST_BITS(0X010, 1, 8) +#define DPI_COLOR_CODING DSI_HOST_BITS(0X010, 4, 0) +#define COLORM_ACTIVE_LOW DSI_HOST_BITS(0X014, 1, 4) +#define SHUTD_ACTIVE_LOW DSI_HOST_BITS(0X014, 1, 3) +#define HSYNC_ACTIVE_LOW DSI_HOST_BITS(0X014, 1, 2) +#define VSYNC_ACTIVE_LOW DSI_HOST_BITS(0X014, 1, 1) +#define DATAEN_ACTIVE_LOW DSI_HOST_BITS(0X014, 1, 0) +#define OUTVACT_LPCMD_TIME DSI_HOST_BITS(0X018, 8, 16) +#define INVACT_LPCMD_TIME DSI_HOST_BITS(0X018, 8, 0) +#define CRC_RX_EN DSI_HOST_BITS(0X02C, 1, 4) +#define ECC_RX_EN DSI_HOST_BITS(0X02C, 1, 3) +#define BTA_EN DSI_HOST_BITS(0X02C, 1, 2) +#define EOTP_RX_EN DSI_HOST_BITS(0X02C, 1, 1) +#define EOTP_TX_EN DSI_HOST_BITS(0X02C, 1, 0) +#define GEN_VID_RX DSI_HOST_BITS(0X030, 2, 0) +#define CMD_VIDEO_MODE DSI_HOST_BITS(0X034, 1, 0) +#define VPG_ORIENTATION DSI_HOST_BITS(0X038, 1, 24) +#define VPG_MODE DSI_HOST_BITS(0X038, 1, 20) +#define VPG_EN DSI_HOST_BITS(0X038, 1, 16) +#define LP_CMD_EN DSI_HOST_BITS(0X038, 1, 15) +#define FRAME_BTA_ACK_EN DSI_HOST_BITS(0X038, 1, 14) +#define LP_HFP_EN DSI_HOST_BITS(0X038, 1, 13) +#define LP_HBP_EN DSI_HOST_BITS(0X038, 1, 12) +#define LP_VACT_EN DSI_HOST_BITS(0X038, 1, 11) +#define LP_VFP_EN DSI_HOST_BITS(0X038, 1, 10) +#define LP_VBP_EN DSI_HOST_BITS(0X038, 1, 9) +#define LP_VSA_EN DSI_HOST_BITS(0X038, 1, 8) +#define VID_MODE_TYPE DSI_HOST_BITS(0X038, 2, 0) +#define VID_PKT_SIZE DSI_HOST_BITS(0X03C, 14, 0) +#define NUM_CHUNKS DSI_HOST_BITS(0X040, 13, 0) +#define NULL_PKT_SIZE DSI_HOST_BITS(0X044, 13, 0) +#define VID_HSA_TIME DSI_HOST_BITS(0X048, 12, 0) +#define VID_HBP_TIME DSI_HOST_BITS(0X04C, 12, 0) +#define VID_HLINE_TIME DSI_HOST_BITS(0X050, 15, 0) +#define VID_VSA_LINES DSI_HOST_BITS(0X054, 10, 0) +#define VID_VBP_LINES DSI_HOST_BITS(0X058, 10, 0) +#define VID_VFP_LINES DSI_HOST_BITS(0X05C, 10, 0) +#define VID_ACTIVE_LINES DSI_HOST_BITS(0X060, 14, 0) +#define EDPI_CMD_SIZE DSI_HOST_BITS(0X064, 16, 0) +#define MAX_RD_PKT_SIZE DSI_HOST_BITS(0X068, 1, 24) +#define DCS_LW_TX DSI_HOST_BITS(0X068, 1, 19) +#define DCS_SR_0P_TX DSI_HOST_BITS(0X068, 1, 18) +#define DCS_SW_1P_TX DSI_HOST_BITS(0X068, 1, 17) +#define DCS_SW_0P_TX DSI_HOST_BITS(0X068, 1, 16) +#define GEN_LW_TX DSI_HOST_BITS(0X068, 1, 14) +#define GEN_SR_2P_TX DSI_HOST_BITS(0X068, 1, 13) +#define GEN_SR_1P_TX DSI_HOST_BITS(0X068, 1, 12) +#define GEN_SR_0P_TX DSI_HOST_BITS(0X068, 1, 11) +#define GEN_SW_2P_TX DSI_HOST_BITS(0X068, 1, 10) +#define GEN_SW_1P_TX DSI_HOST_BITS(0X068, 1, 9) +#define GEN_SW_0P_TX DSI_HOST_BITS(0X068, 1, 8) +#define ACK_RQST_EN DSI_HOST_BITS(0X068, 1, 1) +#define TEAR_FX_EN DSI_HOST_BITS(0X068, 1, 0) +#define GEN_WC_MSBYTE DSI_HOST_BITS(0X06C, 14, 16) +#define GEN_WC_LSBYTE DSI_HOST_BITS(0X06C, 8, 8) +#define GEN_VC DSI_HOST_BITS(0X06C, 2, 6) +#define GEN_DT DSI_HOST_BITS(0X06C, 6, 0) +#define GEN_PLD_DATA DSI_HOST_BITS(0X070, 32, 0) +#define GEN_RD_CMD_BUSY DSI_HOST_BITS(0X074, 1, 6) +#define GEN_PLD_R_FULL DSI_HOST_BITS(0X074, 1, 5) +#define GEN_PLD_R_EMPTY DSI_HOST_BITS(0X074, 1, 4) +#define GEN_PLD_W_FULL DSI_HOST_BITS(0X074, 1, 3) +#define GEN_PLD_W_EMPTY DSI_HOST_BITS(0X074, 1, 2) +#define GEN_CMD_FULL DSI_HOST_BITS(0X074, 1, 1) +#define GEN_CMD_EMPTY DSI_HOST_BITS(0X074, 1, 0) +#define HSTX_TO_CNT DSI_HOST_BITS(0X078, 16, 16) +#define LPRX_TO_CNT DSI_HOST_BITS(0X078, 16, 0) +#define HS_RD_TO_CNT DSI_HOST_BITS(0X07C, 16, 0) +#define LP_RD_TO_CNT DSI_HOST_BITS(0X080, 16, 0) +#define PRESP_TO_MODE DSI_HOST_BITS(0X084, 1, 24) +#define HS_WR_TO_CNT DSI_HOST_BITS(0X084, 16, 0) +#define LP_WR_TO_CNT DSI_HOST_BITS(0X088, 16, 0) +#define BTA_TO_CNT DSI_HOST_BITS(0X08C, 16, 0) +#define AUTO_CLKLANE_CTRL DSI_HOST_BITS(0X094, 1, 1) +#define PHY_TXREQUESTCLKHS DSI_HOST_BITS(0X094, 1, 0) +#define PHY_HS2LP_TIME_CLK_LANE DSI_HOST_BITS(0X098, 10, 16) +#define PHY_HS2HS_TIME_CLK_LANE DSI_HOST_BITS(0X098, 10, 0) +#define PHY_HS2LP_TIME DSI_HOST_BITS(0X09C, 8, 24) +#define PHY_LP2HS_TIME DSI_HOST_BITS(0X09C, 8, 16) +#define MAX_RD_TIME DSI_HOST_BITS(0X09C, 15, 0) +#define PHY_FORCEPLL DSI_HOST_BITS(0X0A0, 1, 3) +#define PHY_ENABLECLK DSI_HOST_BITS(0X0A0, 1, 2) +#define PHY_RSTZ DSI_HOST_BITS(0X0A0, 1, 1) +#define PHY_SHUTDOWNZ DSI_HOST_BITS(0X0A0, 1, 0) +#define PHY_STOP_WAIT_TIME DSI_HOST_BITS(0X0A4, 8, 8) +#define N_LANES DSI_HOST_BITS(0X0A4, 2, 0) +#define PHY_TXEXITULPSLAN DSI_HOST_BITS(0X0A8, 1, 3) +#define PHY_TXREQULPSLAN DSI_HOST_BITS(0X0A8, 1, 2) +#define PHY_TXEXITULPSCLK DSI_HOST_BITS(0X0A8, 1, 1) +#define PHY_TXREQULPSCLK DSI_HOST_BITS(0X0A8, 1, 0) +#define PHY_TX_TRIGGERS DSI_HOST_BITS(0X0AC, 4, 0) +#define PHYSTOPSTATECLKLANE DSI_HOST_BITS(0X0B0, 1, 2) +#define PHYLOCK DSI_HOST_BITS(0X0B0, 1, 0) +#define PHY_TESTCLK DSI_HOST_BITS(0X0B4, 1, 1) +#define PHY_TESTCLR DSI_HOST_BITS(0X0B4, 1, 0) +#define PHY_TESTEN DSI_HOST_BITS(0X0B8, 1, 16) +#define PHY_TESTDOUT DSI_HOST_BITS(0X0B8, 8, 8) +#define PHY_TESTDIN DSI_HOST_BITS(0X0B8, 8, 0) +#define PHY_TEST_CTRL1 DSI_HOST_BITS(0X0B8, 17, 0) +#define PHY_TEST_CTRL0 DSI_HOST_BITS(0X0B4, 2, 0) +#define INT_ST0 DSI_HOST_BITS(0X0BC, 21, 0) +#define INT_ST1 DSI_HOST_BITS(0X0C0, 18, 0) +#define INT_MKS0 DSI_HOST_BITS(0X0C4, 21, 0) +#define INT_MKS1 DSI_HOST_BITS(0X0C8, 18, 0) +#define INT_FORCE0 DSI_HOST_BITS(0X0D8, 21, 0) +#define INT_FORCE1 DSI_HOST_BITS(0X0DC, 18, 0)
+#define code_hs_rx_clock 0x34 +#define code_hs_rx_lane0 0x44 +#define code_hs_rx_lane1 0x54 +#define code_hs_rx_lane2 0x84 +#define code_hs_rx_lane3 0x94
+#define code_pll_input_div_rat 0x17 +#define code_pll_loop_div_rat 0x18 +#define code_pll_vcorange_vcocap 0x10 +#define code_pll_input_loop_div_rat 0x19 +#define code_pll_cpctrl 0x11
+#define code_hstxdatalanerequsetstatetime 0x70 +#define code_hstxdatalanepreparestatetime 0x71 +#define code_hstxdatalanehszerostatetime 0x72
Please use all caps for these defines.
+enum vid_mode_type_enum {
How about vid_mode_type_t as it is shorter
NON_BURST_SYNC_PLUSE = 0,
NON_BURST_SYNC_EVENT,
BURST_MODE,
+};
+enum cmd_video_mode {
VIDEO_MODE = 0,
CMD_MODE,
+};
+enum dpi_color_coding {
DPI_16BIT_CFG_1 = 0,
DPI_16BIT_CFG_2,
DPI_16BIT_CFG_3,
DPI_18BIT_CFG_1,
DPI_18BIT_CFG_2,
DPI_24BIT,
DPI_20BIT_YCBCR_422_LP,
DPI_24BIT_YCBCR_422,
DPI_16BIT_YCBCR_422,
DPI_30BIT,
DPI_36BIT,
DPI_12BIT_YCBCR_420,
+};
+enum vop_id {
VOP_B = 0,
VOP_L,
+};
+/*
- Name :rk_write_reg(reg,val)
- reg: register name from the above define file,it contain the addr,
bits number and bits offset
- val: reg value that will be writen to register, it can't be over
the real bit num limit, For example, TO_CLK_DIVISION have 8
bits space, so it's value can't great than 255
- */
+#define GET_VAL(reg, val) ((val & (~(0xffffffff << ((reg & 0xffff) >> 8)))) \
<< (reg&0xff)) | ((readl((reg >> 16)+MIPI_DSI_HOST0_BASE)) & \
(~((0xffffffff<<(reg&0xff))&(0xffffffff>>\
(32-(reg&0xff)-((reg>>8)&0xff))))))
What is the purpose of this? Could it instead be a table of values?
struct something { u8 addr; u8 bits; u8 offset; }
static const struct something some_table[] = { { 1, 2, 3}, ... };
+#define GET_ADDR(reg) (reg >> 16)+MIPI_DSI_HOST0_BASE
Can we drop this one?
+#define rk_write_reg(reg, val) writel(GET_VAL(reg, val), GET_ADDR(reg));
Is this different from rk_clrsetreg() ? Can you put this next to that function?
+#endif /* end of RK33_MIPI_DSI_H */ diff --git a/arch/arm/include/asm/arch-rockchip/vop_rk3288.h b/arch/arm/include/asm/arch-rockchip/vop_rk3288.h index 0ce3d67..d5599ec 100644 --- a/arch/arm/include/asm/arch-rockchip/vop_rk3288.h +++ b/arch/arm/include/asm/arch-rockchip/vop_rk3288.h @@ -90,6 +90,7 @@ enum vop_modes { VOP_MODE_EDP = 0, VOP_MODE_HDMI, VOP_MODE_LVDS,
VOP_MODE_MIPI, VOP_MODE_NONE, VOP_MODE_AUTO_DETECT, VOP_MODE_UNKNOWN,
diff --git a/configs/evb-rk3399_defconfig b/configs/evb-rk3399_defconfig index aac6d2d..b9cb0e8 100644 --- a/configs/evb-rk3399_defconfig +++ b/configs/evb-rk3399_defconfig @@ -64,3 +64,7 @@ CONFIG_PMIC_CHILDREN=y CONFIG_SPL_PMIC_CHILDREN=y CONFIG_PMIC_RK808=y CONFIG_REGULATOR_RK808=y +CONFIG_DM_VIDEO=y +CONFIG_DISPLAY=y +CONFIG_VIDEO_ROCKCHIP=y +CONFIG_DISPLAY_MIPI=y diff --git a/drivers/video/Kconfig b/drivers/video/Kconfig index 2069576..4b03a9a 100644 --- a/drivers/video/Kconfig +++ b/drivers/video/Kconfig @@ -405,6 +405,8 @@ config VIDEO_ROCKCHIP (DSI). This driver supports the on-chip video output device, and targets the Rockchip RK3288.
+source "drivers/video/rockchip/Kconfig"
config VIDEO_SANDBOX_SDL bool "Enable sandbox video console using SDL" depends on SANDBOX diff --git a/drivers/video/rockchip/Kconfig b/drivers/video/rockchip/Kconfig new file mode 100644 index 0000000..72473f6 --- /dev/null +++ b/drivers/video/rockchip/Kconfig @@ -0,0 +1,44 @@ +# +# video drivers configuration +# for rockchip soc +#
+menu "Video Display Port Select"
+config DISPLAY_MIPI
bool "MIPI Port"
depends on VIDEO_ROCKCHIP
help
Select MIPI dsi for video port.
if you want to enable these function,you need
to turn on the DM_VIDEO,VDEIO_ROCKCHIP together
what is more,you shoud also enable the related
power,such as lcd3v3, lcd1v8,lcd1v0 and so on.
+config DISPLAY_EDP
bool "EDP Port"
depends on VIDEO_ROCKCHIP
help
Select EDP for video port.
if you want to enable these function,you need
to turn on the DM_VIDEO,VDEIO_ROCKCHIP together
what is more,you shoud also enable the related
power,such as lcd3v3, lcd1v8,lcd1v0 and so on.
+config DISPLAY_LVDS
bool "LVDS Port"
depends on VIDEO_ROCKCHIP
help
Select LVDS for video port.
if you want to enable these function,you need
to turn on the DM_VIDEO,VDEIO_ROCKCHIP together
what is more,you shoud also enable the related
power,such as lcd3v3, lcd1v8,lcd1v0 and so on.
+config DISPLAY_HDMI
bool "HDMI port"
depends on VIDEO_ROCKCHIP
help
Select HDMI for video port
There are two different things:
- Compiling in the driver - Deciding which one to use
Here I think you have one config for both. I think the config should just decide whether to compile in the driver. The device tree, or some environment variable, should select which to use.
if you want to enable these function,you need
to turn on the DM_VIDEO,VDEIO_ROCKCHIP together
what is more,you shoud also enable the related
power,such as lcd3v3, lcd1v8,lcd1v0 and so on.
+endmenu
Is it possible to have more than one port? The above settings are in the device tree, aren't they? For example on firefly I think it uses HDMI if it can detect it.
diff --git a/drivers/video/rockchip/Makefile b/drivers/video/rockchip/Makefile index 7962f86..98b26ea 100644 --- a/drivers/video/rockchip/Makefile +++ b/drivers/video/rockchip/Makefile @@ -5,4 +5,9 @@ # SPDX-License-Identifier: GPL-2.0+ #
-obj-y += rk_edp.o rk_hdmi.o rk_vop.o rk_lvds.o +obj-$(CONFIG_VIDEO_ROCKCHIP) += rk_vop.o +obj-$(CONFIG_VIDEO_ROCKCHIP) += panel.o +obj-$(CONFIG_DISPLAY_MIPI) += rk_mipi.o +obj-$(CONFIG_DISPLAY_EDP) += rk_edp.o +obj-$(CONFIG_DISPLAY_LVDS) += rk_lvds.o +obj-$(CONFIG_DISPLAY_HDMI) += rk_hdmi.o diff --git a/drivers/video/rockchip/panel.c b/drivers/video/rockchip/panel.c new file mode 100644 index 0000000..8b02b0f --- /dev/null +++ b/drivers/video/rockchip/panel.c @@ -0,0 +1,81 @@ +/*
- Copyright (c) 2016, Fuzhou Rockchip Electronics Co., Ltd
- This program is free software; you can redistribute it and/or modify
- it under the terms of the GNU General Public License as published by
- the Free Software Foundation; either version 2 of the License, or
- (at your option) any later version.
Can you use SPDX?
- */
+#include <common.h> +#include <clk.h> +#include <display.h> +#include <dm.h> +#include <edid.h> +#include <panel.h> +#include <asm/hardware.h> +#include <regmap.h> +#include <syscon.h> +#include <asm/gpio.h> +#include <asm/io.h> +#include <asm/arch/mipi_rk3399.h> +#include <asm/arch/clock.h> +#include <asm/arch/grf_rk3288.h> +#include <dt-bindings/clock/rk3288-cru.h>
+DECLARE_GLOBAL_DATA_PTR;
+static int bind(struct udevice *dev) +{
debug("Panel bind@%s_Line:%d\n", __func__, __LINE__);
Please put a blank line before the last return in a function
return 0;
+}
+static int probe(struct udevice *dev) +{
debug("Panel probe@%s_Line:%d\n", __func__, __LINE__);
return 0;
+}
+int rk_panel_enable_backlight(struct udevice *dev)
static
+{
struct gpio_desc bg_en, bg_pwm;
int node;
node = fdt_node_offset_by_compatible(gd->fdt_blob, 0, "BOE,TV080WUM");
if (node < 0) {
debug("Can't find node@%s_Line:%d\n", __func__, __LINE__);
return -EINVAL;
}
This should be obtained via a phandle to a panel node, not searching for a particular compatible string.
gpio_request_by_name_nodev(gd->fdt_blob, node, "backlight_en",
0, &bg_en, GPIOD_IS_OUT);
This is a driver so you should be able to use the normal gpio_request_by_name()
gpio_request_by_name_nodev(gd->fdt_blob, node,
"backlight_pwm", 0, &bg_pwm, GPIOD_IS_OUT);
if (dm_gpio_is_valid(&bg_en)) {
dm_gpio_set_value(&bg_en, 1);
dm_gpio_set_value(&bg_pwm, 1);
} else {
debug("GPIO Invalid@%s_Line:%d\n", __func__, __LINE__);
return -EINVAL;
}
return 0;
+}
+static const struct panel_ops rk_panel_ops = {
.enable_backlight = rk_panel_enable_backlight,
+};
+static const struct udevice_id rk_panel_ids[] = {
{ .compatible = "BOE,TV080WUM" },
{ }
+};
+U_BOOT_DRIVER(rk_panel) = {
.name = "rk_panel",
.id = UCLASS_PANEL,
.of_match = rk_panel_ids,
.bind = bind,
.probe = probe,
.ops = &rk_panel_ops,
+}; diff --git a/drivers/video/rockchip/rk_mipi.c b/drivers/video/rockchip/rk_mipi.c new file mode 100644 index 0000000..84cfb96 --- /dev/null +++ b/drivers/video/rockchip/rk_mipi.c @@ -0,0 +1,371 @@ +/*
- Copyright (c) 2016, Fuzhou Rockchip Electronics Co., Ltd
- This program is free software; you can redistribute it and/or modify
- it under the terms of the GNU General Public License as published by
- the Free Software Foundation; either version 2 of the License, or
- (at your option) any later version.
- */
+#include <common.h> +#include <clk.h> +#include <display.h> +#include <dm.h> +#include <fdtdec.h> +#include <panel.h> +#include <asm/hardware.h>
This does below with the other asms.
+#include <regmap.h> +#include <syscon.h> +#include <asm/gpio.h> +#include <asm/io.h> +#include <asm/arch/mipi_rk3399.h> +#include <asm/arch/clock.h> +#include <asm/arch/grf_rk3288.h> +#include <dt-bindings/clock/rk3288-cru.h> +#include <dm/uclass-internal.h>
+DECLARE_GLOBAL_DATA_PTR;
+struct mipi_dsi {
u32 ref_clk;
u32 sys_clk;
u32 pix_clk;
u32 phy_clk;
u32 txbyte_clk;
u32 txesc_clk;
+};
+int rk_mipi_read_timing(struct udevice *dev, struct display_timing *timing) +{
if (fdtdec_decode_display_timing
(gd->fdt_blob, dev_of_offset(dev), 0, timing)) {
debug("%s: Failed to decode display timing\n", __func__);
return -EINVAL;
}
return 0;
+}
+int rk_mipi_dsi_enable(struct udevice *dev, struct mipi_dsi *mipi,
const struct display_timing *timing)
+{
int node, timing_node;
int val;
struct display_plat *disp_uc_plat = dev_get_uclass_platdata(dev);
u32 txbyte_clk = mipi->txbyte_clk;
u32 txesc_clk = mipi->txesc_clk;
txesc_clk = txbyte_clk/(txbyte_clk/txesc_clk + 1);
/* Select the video source */
switch (disp_uc_plat->source_id) {
case VOP_B:
val = 0x1 << 16 | 0x0;
writel(val, GRF_BASE+RK_GRF_CON20);
Spaces around +
GRF_BASE should come from a SYSCON or a phandle. Set it up in your ofdata_to_platdata() method, then you can use it in the driver.
break;
case VOP_L:
val = 0x1 << 16 | 0x1;
Can you have defines for these things?
writel(val, GRF_BASE+RK_GRF_CON20);
break;
default:
return -EINVAL;
}
/* Set Controller as TX mode */
val = 0x1 << 28 | 0x0 << 12;
val |= 0xf << 20 | 0x0 << 4;
val |= 0xf << 16 | 0x0;
writel(val, GRF_BASE+RK_GRF_CON22);
Defines for these?
/* Set Display timing parameter */
rk_write_reg(VID_HSA_TIME, timing->hsync_len.typ);
rk_write_reg(VID_HBP_TIME, timing->hback_porch.typ);
rk_write_reg(VID_HLINE_TIME,
(timing->hsync_len.typ +
timing->hback_porch.typ +
timing->hactive.typ +
timing->hfront_porch.typ));
rk_write_reg(VID_VSA_LINES, timing->vsync_len.typ);
rk_write_reg(VID_VBP_LINES, timing->vback_porch.typ);
rk_write_reg(VID_VFP_LINES, timing->vfront_porch.typ);
rk_write_reg(VID_ACTIVE_LINES, timing->vactive.typ);
/* Set Signal Polarity */
val = (timing->flags & DISPLAY_FLAGS_HSYNC_LOW) ? 1 : 0;
rk_write_reg(HSYNC_ACTIVE_LOW, val);
val = (timing->flags & DISPLAY_FLAGS_VSYNC_LOW) ? 1 : 0;
rk_write_reg(VSYNC_ACTIVE_LOW, val);
val = (timing->flags & DISPLAY_FLAGS_DE_LOW) ? 1 : 0;
rk_write_reg(DISPLAY_FLAGS_DE_LOW, val);
val = (timing->flags & DISPLAY_FLAGS_PIXDATA_NEGEDGE) ? 1 : 0;
rk_write_reg(COLORM_ACTIVE_LOW, val);
/* Set video mode */
rk_write_reg(CMD_VIDEO_MODE, VIDEO_MODE);
/* Set video mode transmission type as burst mode */
rk_write_reg(VID_MODE_TYPE, BURST_MODE);
/* Set pix num in a video package */
rk_write_reg(VID_PKT_SIZE, 0x4b0);
/* Set dpi color coding depth 24 bit */
timing_node = fdt_subnode_offset(gd->fdt_blob,
dev_of_offset(dev), "display-timings");
node = fdt_first_subnode(gd->fdt_blob, timing_node);
val = fdtdec_get_int(gd->fdt_blob, node, "bits-per-pixel", -1);
switch (val) {
case 16:
rk_write_reg(DPI_COLOR_CODING, DPI_16BIT_CFG_1);
break;
case 24:
rk_write_reg(DPI_COLOR_CODING, DPI_24BIT);
break;
case 30:
rk_write_reg(DPI_COLOR_CODING, DPI_30BIT);
break;
default:
rk_write_reg(DPI_COLOR_CODING, DPI_24BIT);
}
/* Enable low power mode */
rk_write_reg(LP_CMD_EN, 1);
rk_write_reg(LP_HFP_EN, 1);
rk_write_reg(LP_VACT_EN, 1);
rk_write_reg(LP_VFP_EN, 1);
rk_write_reg(LP_VBP_EN, 1);
rk_write_reg(LP_VSA_EN, 1);
/* Division for timeout counter clk */
rk_write_reg(TO_CLK_DIVISION, 0x0a);
/* Tx esc clk division from txbyte clk */
rk_write_reg(TX_ESC_CLK_DIVISION, txbyte_clk/txesc_clk);
/*
* Timeout count for hs<->lp
* transation between Line period
*/
rk_write_reg(HSTX_TO_CNT, 0x3e8);
/* Phy State transfer timing */
rk_write_reg(PHY_STOP_WAIT_TIME, 32);
rk_write_reg(PHY_TXREQUESTCLKHS, 1);
rk_write_reg(PHY_HS2LP_TIME, 0x14);
rk_write_reg(PHY_LP2HS_TIME, 0x10);
rk_write_reg(MAX_RD_TIME, 0x2710);
/* Power on */
rk_write_reg(SHUTDOWNZ, 1);
return 0;
+}
+/*
- rk mipi dphy write function
- */
+static void rk_mipi_phy_write(unsigned char test_code,
unsigned char *test_data,
unsigned char size)
+{
int i = 0;
/* Write Test code */
rk_write_reg(PHY_TESTCLK, 1);
rk_write_reg(PHY_TESTDIN, test_code);
rk_write_reg(PHY_TESTEN, 1);
rk_write_reg(PHY_TESTCLK, 0);
rk_write_reg(PHY_TESTEN, 0);
/* Write Test data */
for (i = 0; i < size; i++) {
rk_write_reg(PHY_TESTCLK, 0);
rk_write_reg(PHY_TESTDIN, test_data[i]);
rk_write_reg(PHY_TESTCLK, 1);
}
+}
+/*
- mipi dphy config function. calculate the suitable prediv,
- feedback div,fsfreqrang value ,cap ,lpf and so on
- according to the given pix clk ratthe.and then enable phy
- */
+static int rk_mipi_phy_enable(struct mipi_dsi *mipi) +{
int i;
u64 fbdiv;
u64 prediv = 1;
u64 ddr_clk = mipi->phy_clk;
u32 refclk = mipi->ref_clk;
u32 remain = refclk;
unsigned char test_data[2] = {0};
/* dphy fsfreqrang */
??
int rang[39][2] = {
{90, 0x01}, {100, 0x10}, {110, 0x20}, {130, 0x01},
Indent these lines
{140, 0x11}, {150, 0x21}, {170, 0x02}, {180, 0x12},
{200, 0x22}, {220, 0x03}, {240, 0x13}, {250, 0x23},
{270, 0x04}, {300, 0x14}, {330, 0x05}, {360, 0x15},
{400, 0x25}, {450, 0x06}, {500, 0x16}, {550, 0x07},
{600, 0x17}, {650, 0x08}, {700, 0x18}, {750, 0x09},
{800, 0x19}, {850, 0x29}, {900, 0x39}, {950, 0x0a},
{1000, 0x1a}, {1050, 0x2a}, {1100, 0x3a}, {1150, 0x0b},
{1200, 0x1b}, {1250, 0x2b}, {1300, 0x3b}, {1350, 0x0c},
{1400, 0x1c}, {1450, 0x2c}, {1500, 0x3c} };
/* Shutdown mode */
rk_write_reg(PHY_SHUTDOWNZ, 0);
rk_write_reg(PHY_RSTZ, 0);
rk_write_reg(PHY_TESTCLR, 1);
mdelay(10);
/* Pll locking */
rk_write_reg(PHY_TESTCLR, 0);
mdelay(10);
/* config cp and lfp */
test_data[0] = 0x80 | (ddr_clk / (200*MHz)) << 3 | 0x3;
rk_mipi_phy_write(0x10, test_data, 1);
test_data[0] = 0x8;
rk_mipi_phy_write(0x11, test_data, 1);
test_data[0] = 0x80 | 0x40;
rk_mipi_phy_write(0x12, test_data, 1);
/* select the suitable value for fsfreqrang reg */
for (i = 0; i < 39; i++) {
What is 39? Is is ARRAY_SIZE(rang)?
if (ddr_clk / (MHz) >= rang[i][0])
break;
}
test_data[0] = rang[i][1] << 1;
rk_mipi_phy_write(code_hs_rx_lane0, test_data, 1);
/*
* Calculate the best ddrclk and it's
* corresponding div value, If the given
* pixelclock is great than 250M, the ddr
* clk will be fix 1500M.otherwise , it's
* equal to ddr_clk= pixclk*6.
Can you use (say) 75 columns for this?
*/
for (i = 1; i < 6; i++) {
if ((ddr_clk * i % refclk < remain) &&
(ddr_clk * i / refclk) < 512) {
prediv = i;
remain = ddr_clk * i % refclk;
}
}
fbdiv = ddr_clk * prediv / refclk;
ddr_clk = refclk * fbdiv / prediv;
mipi->phy_clk = ddr_clk;
/* config prediv and feedback reg */
test_data[0] = prediv - 1;
rk_mipi_phy_write(code_pll_input_div_rat, test_data, 1);
mdelay(2);
test_data[0] = (fbdiv - 1) & 0x1f;
rk_mipi_phy_write(code_pll_loop_div_rat, test_data, 1);
mdelay(2);
test_data[0] = (fbdiv - 1) >> 5 | 0x80;
rk_mipi_phy_write(code_pll_loop_div_rat, test_data, 1);
mdelay(2);
test_data[0] = 0x30;
rk_mipi_phy_write(code_pll_input_loop_div_rat, test_data, 1);
mdelay(2);
What are these long delays for? Please add a comment.
/* rest config */
test_data[0] = 0x4d;
rk_mipi_phy_write(0x20, test_data, 1);
test_data[0] = 0x3d;
rk_mipi_phy_write(0x21, test_data, 1);
test_data[0] = 0xdf;
rk_mipi_phy_write(0x21, test_data, 1);
test_data[0] = 0x7;
rk_mipi_phy_write(0x22, test_data, 1);
test_data[0] = 0x80 | 0x7;
rk_mipi_phy_write(0x22, test_data, 1);
test_data[0] = 0x80 | 15;
rk_mipi_phy_write(code_hstxdatalanerequsetstatetime,
test_data, 1);
test_data[0] = 0x80 | 85;
rk_mipi_phy_write(code_hstxdatalanepreparestatetime,
test_data, 1);
test_data[0] = 0x40 | 10;
rk_mipi_phy_write(code_hstxdatalanehszerostatetime,
test_data, 1);
/* enter into stop mode */
rk_write_reg(N_LANES, 0x03);
rk_write_reg(PHY_ENABLECLK, 1);
mdelay(10);
rk_write_reg(PHY_FORCEPLL, 1);
mdelay(10);
rk_write_reg(PHY_SHUTDOWNZ, 1);
mdelay(10);
rk_write_reg(PHY_RSTZ, 1);
mdelay(10);
return 0;
+}
+static int enable(struct udevice *dev, int panel_bpp,
const struct display_timing *timing)
+{
struct udevice *panel;
/* Check if there are avalble panel */
if (uclass_first_device(UCLASS_PANEL, &panel)) {
I suppose you can pick the first panel, but can't you use the DT to tell you which one?
See rk_lvds.c for what it does.
debug("No panel found@%s_LINE:%d\n", __func__, __LINE__);
return -EINVAL;
}
return panel_enable_backlight(panel);
+}
+/*
- probe function: check panel existence and reading
- it's timing. then config mipi dsi controller and
- enable it according to the timing parameter
- */
+static int probe(struct udevice *dev)
Can you use rk_mipi_probe() etc. for these functions just to make them more unique?
+{
struct display_timing timing;
struct mipi_dsi mipi;
/* Read panel timing,and save to struct timing */
rk_mipi_read_timing(dev, &timing);
/* fill the mipi controller parameter */
mipi.ref_clk = 24*MHz;
mipi.sys_clk = mipi.ref_clk;
mipi.pix_clk = timing.pixelclock.typ;
mipi.phy_clk = mipi.pix_clk * 6;
mipi.txbyte_clk = mipi.phy_clk / 8;
mipi.txesc_clk = 20*MHz;
/* config mipi dsi according to timing and enable it */
rk_mipi_dsi_enable(dev, &mipi, &timing);
Check error?
/* init mipi dsi phy */
rk_mipi_phy_enable(&mipi);
Check error?
return 0;
+}
+static const struct dm_display_ops rk_mipi_dsi_ops = {
.read_timing = rk_mipi_read_timing,
.enable = enable,
+};
+static const struct udevice_id rk_mipi_dsi_ids[] = {
{ .compatible = "rockchip,rk3399_mipi_dsi" },
{ }
+};
+U_BOOT_DRIVER(rk_mipi_dsi) = {
.name = "rk_mipi_dsi",
.id = UCLASS_DISPLAY,
.of_match = rk_mipi_dsi_ids,
.probe = probe,
.ops = &rk_mipi_dsi_ops,
+};
diff --git a/drivers/video/rockchip/rk_vop.c b/drivers/video/rockchip/rk_vop.c index aeecb58..1de00f1 100644 --- a/drivers/video/rockchip/rk_vop.c +++ b/drivers/video/rockchip/rk_vop.c @@ -109,6 +109,10 @@ void rkvop_mode_set(struct rk3288_vop *regs, clrsetbits_le32(®s->sys_ctrl, M_ALL_OUT_EN, V_HDMI_OUT_EN(1)); break;
case VOP_MODE_MIPI:
clrsetbits_le32(®s->sys_ctrl, M_ALL_OUT_EN,
V_MIPI_OUT_EN(1));
break; case VOP_MODE_EDP: default: clrsetbits_le32(®s->sys_ctrl, M_ALL_OUT_EN,
@@ -245,7 +249,7 @@ int rk_display_init(struct udevice *dev, ulong fbbase, ret = clk_get_by_index(dev, 1, &clk); if (!ret) ret = clk_set_rate(&clk, timing.pixelclock.typ);
if (ret) {
if (!ret) {
Why is this changing?
debug("%s: Failed to set pixel clock: ret=%d\n", __func__, ret); return ret; }
@@ -327,7 +331,7 @@ static int rk_vop_probe(struct udevice *dev) for (node = fdt_first_subnode(blob, port); node > 0; node = fdt_next_subnode(blob, node)) {
ret = rk_display_init(dev, plat->base, VIDEO_BPP16, node);
ret = rk_display_init(dev, plat->base, VIDEO_BPP32, node);
Maybe we need a way to select which depth to use?
if (ret) debug("Device failed: ret=%d\n", ret); if (!ret)
@@ -342,7 +346,7 @@ static int rk_vop_bind(struct udevice *dev) { struct video_uc_platdata *plat = dev_get_uclass_platdata(dev);
plat->size = 1920 * 1080 * 2;
plat->size = 1920 * 1200 * 4;
And it should probably calculate this, so HDMI continues to work.
return 0;
} @@ -351,6 +355,8 @@ static const struct video_ops rk_vop_ops = { };
static const struct udevice_id rk_vop_ids[] = {
{ .compatible = "rockchip,rk3399-vop-big" },
{ .compatible = "rockchip,rk3399-vop-lit" }, { .compatible = "rockchip,rk3288-vop" }, { }
};
1.9.1
Regards, Simon

From: "eric.gao" eric.gao@rock-chips.com
Signed-off-by: eric.gao eric.gao@rock-chips.com ---
configs/evb-rk3399_defconfig | 1 + include/configs/rk3399_common.h | 5 ++++- 2 files changed, 5 insertions(+), 1 deletion(-)
diff --git a/configs/evb-rk3399_defconfig b/configs/evb-rk3399_defconfig index b9cb0e8..89b2e17 100644 --- a/configs/evb-rk3399_defconfig +++ b/configs/evb-rk3399_defconfig @@ -68,3 +68,4 @@ CONFIG_DM_VIDEO=y CONFIG_DISPLAY=y CONFIG_VIDEO_ROCKCHIP=y CONFIG_DISPLAY_MIPI=y +CONFIG_VIDCONSOLE_AS_LCD=y diff --git a/include/configs/rk3399_common.h b/include/configs/rk3399_common.h index 4ba81ac..6183f4e 100644 --- a/include/configs/rk3399_common.h +++ b/include/configs/rk3399_common.h @@ -69,7 +69,10 @@ #define CONFIG_EXTRA_ENV_SETTINGS \ ENV_MEM_LAYOUT_SETTINGS \ "partitions=" PARTS_DEFAULT \ - BOOTENV + BOOTENV \ + "stdin=serial,cros-ec-keyb\0" \ + "stdout=serial,vidconsole\0" \ + "stderr=serial,vidconsole\0"
#endif

On 1 April 2017 at 08:42, eric.gao@rock-chips.com wrote:
From: "eric.gao" eric.gao@rock-chips.com
Signed-off-by: eric.gao eric.gao@rock-chips.com
configs/evb-rk3399_defconfig | 1 + include/configs/rk3399_common.h | 5 ++++- 2 files changed, 5 insertions(+), 1 deletion(-)
Reviewed-by: Simon Glass sjg@chromium.org
diff --git a/configs/evb-rk3399_defconfig b/configs/evb-rk3399_defconfig index b9cb0e8..89b2e17 100644 --- a/configs/evb-rk3399_defconfig +++ b/configs/evb-rk3399_defconfig @@ -68,3 +68,4 @@ CONFIG_DM_VIDEO=y CONFIG_DISPLAY=y CONFIG_VIDEO_ROCKCHIP=y CONFIG_DISPLAY_MIPI=y +CONFIG_VIDCONSOLE_AS_LCD=y
But do you need this option?
diff --git a/include/configs/rk3399_common.h b/include/configs/rk3399_common.h index 4ba81ac..6183f4e 100644 --- a/include/configs/rk3399_common.h +++ b/include/configs/rk3399_common.h @@ -69,7 +69,10 @@ #define CONFIG_EXTRA_ENV_SETTINGS \ ENV_MEM_LAYOUT_SETTINGS \ "partitions=" PARTS_DEFAULT \
BOOTENV
BOOTENV \
"stdin=serial,cros-ec-keyb\0" \
"stdout=serial,vidconsole\0" \
"stderr=serial,vidconsole\0"
#endif
-- 1.9.1

Dear Glass,
Thank you, I will drop this patch and move it to README file.
On 2017年04月06日 11:44, Simon Glass wrote:
On 1 April 2017 at 08:42, eric.gao@rock-chips.com wrote:
From: "eric.gao" eric.gao@rock-chips.com
Signed-off-by: eric.gao eric.gao@rock-chips.com
configs/evb-rk3399_defconfig | 1 + include/configs/rk3399_common.h | 5 ++++- 2 files changed, 5 insertions(+), 1 deletion(-)
Reviewed-by: Simon Glass sjg@chromium.org
diff --git a/configs/evb-rk3399_defconfig b/configs/evb-rk3399_defconfig index b9cb0e8..89b2e17 100644 --- a/configs/evb-rk3399_defconfig +++ b/configs/evb-rk3399_defconfig @@ -68,3 +68,4 @@ CONFIG_DM_VIDEO=y CONFIG_DISPLAY=y CONFIG_VIDEO_ROCKCHIP=y CONFIG_DISPLAY_MIPI=y +CONFIG_VIDCONSOLE_AS_LCD=y
But do you need this option?
diff --git a/include/configs/rk3399_common.h b/include/configs/rk3399_common.h index 4ba81ac..6183f4e 100644 --- a/include/configs/rk3399_common.h +++ b/include/configs/rk3399_common.h @@ -69,7 +69,10 @@ #define CONFIG_EXTRA_ENV_SETTINGS \ ENV_MEM_LAYOUT_SETTINGS \ "partitions=" PARTS_DEFAULT \
BOOTENV
BOOTENV \
"stdin=serial,cros-ec-keyb\0" \
"stdout=serial,vidconsole\0" \
"stderr=serial,vidconsole\0"
#endif
-- 1.9.1

From: "eric.gao" eric.gao@rock-chips.com
After enable log printing to lcd,when the screen start scroll,the system crash.And the log is shown as bellow.
"Synchronous Abort" handler, esr 0x96000045 "Synchronous Abort" handler, esr 0x96000045
Checking the source code, we found that the variate "pixels" get a wrong value.
int pixels = VIDEO_FONT_HEIGHT * vid_priv->line_length;
"pixels" here means the value of pixels for a character,rather than the byte for a character. so the variate "pixels" is 4 times bigger than it's exact value. which will cause the memory overflow when the cpu run the following code.
for (i = 0; i < pixels; i++) *dst++ = clr; <<----
Signed-off-by: eric.gao eric.gao@rock-chips.com ---
drivers/video/console_normal.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/drivers/video/console_normal.c b/drivers/video/console_normal.c index 89a55dd..b627d48 100644 --- a/drivers/video/console_normal.c +++ b/drivers/video/console_normal.c @@ -18,7 +18,7 @@ static int console_normal_set_row(struct udevice *dev, uint row, int clr) { struct video_priv *vid_priv = dev_get_uclass_priv(dev->parent); void *line; - int pixels = VIDEO_FONT_HEIGHT * vid_priv->line_length; + int pixels = VIDEO_FONT_HEIGHT * vid_priv->xsize; int i;
line = vid_priv->fb + row * VIDEO_FONT_HEIGHT * vid_priv->line_length;

Hi Eric,
On 1 April 2017 at 08:42, eric.gao@rock-chips.com wrote:
From: "eric.gao" eric.gao@rock-chips.com
After enable log printing to lcd,when the screen start scroll,the system crash.And the log is shown as bellow.
"Synchronous Abort" handler, esr 0x96000045 "Synchronous Abort" handler, esr 0x96000045
Checking the source code, we found that the variate "pixels" get a wrong value.
int pixels = VIDEO_FONT_HEIGHT * vid_priv->line_length;
"pixels" here means the value of pixels for a character,rather than the byte for a character. so the variate "pixels" is 4 times bigger than it's exact value. which will cause the memory overflow when the cpu run the following code.
for (i = 0; i < pixels; i++) *dst++ = clr; <<----
Signed-off-by: eric.gao eric.gao@rock-chips.com
drivers/video/console_normal.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-)
Can you compare with this patch?
Reviewed-by: Simon Glass sjg@chromium.org
I did not apply it as it was part of a larger series, sorry.
Regards, Simon

Hi Eric,
1. Please use full name in you signature;
2. add commit message for all your commits;
3. add 'rockchip' and module name for all your patches.
4. 'From: ' in not need for patch from yourself.
Thanks, - Kever On 04/01/2017 10:42 PM, eric.gao@rock-chips.com wrote:
From: "eric.gao" eric.gao@rock-chips.com
This serial patchs enable mipi dsi display for rk3399,and let the system log print to lcd. The function of each patch is decribe in the following.Thank you. Patch 1: Fix system halt when we enable bucks of PMIC rk808. Patch 2: Enable i2c for rk3399. Patch 3: Enable PMIC rk808 for display system using. Patch 4: Enable rkclk init,prepare aclk dclk for vop. Patch 5: Add mipi display,panel driver and so on. Patch 6: Enable print log to lcd. Patch 7: Fix crash when scrolling screen.
eric.gao (7): system halt when we enable bucks of PMIC rk808 Enable i2c for rk3399 Enable RK808 for rk3399 evb Enable rkclk init function Add mipi display support for rk3399 && rk3288 Enable print log file to lcd crash when scroll screen
arch/arm/dts/rk3399-evb.dts | 141 +++++++++ arch/arm/dts/rk3399.dtsi | 88 ++++++ arch/arm/include/asm/arch-rockchip/cru_rk3399.h | 2 +- arch/arm/include/asm/arch-rockchip/mipi_rk3399.h | 203 +++++++++++++ arch/arm/include/asm/arch-rockchip/vop_rk3288.h | 1 + arch/arm/mach-rockchip/rk3399/syscon_rk3399.c | 1 + configs/evb-rk3399_defconfig | 11 + drivers/clk/rockchip/clk_rk3399.c | 4 + drivers/i2c/rk_i2c.c | 1 + drivers/video/Kconfig | 2 + drivers/video/console_normal.c | 2 +- drivers/video/rockchip/Kconfig | 44 +++ drivers/video/rockchip/Makefile | 7 +- drivers/video/rockchip/panel.c | 81 +++++ drivers/video/rockchip/rk_mipi.c | 371 +++++++++++++++++++++++ drivers/video/rockchip/rk_vop.c | 12 +- include/configs/rk3399_common.h | 5 +- 17 files changed, 969 insertions(+), 7 deletions(-) create mode 100644 arch/arm/include/asm/arch-rockchip/mipi_rk3399.h create mode 100644 drivers/video/rockchip/Kconfig create mode 100644 drivers/video/rockchip/panel.c create mode 100644 drivers/video/rockchip/rk_mipi.c
participants (7)
-
Eric
-
eric.gao@rock-chips.com
-
Heiko Schocher
-
Heiko Stuebner
-
Jacob Chen
-
Kever Yang
-
Simon Glass