[U-Boot] [PATCH v3 0/8] rockchip: video: rk3399: enable HDMI output

This series provides HDMI enablement for the RK3399 and will support video console on the RK3399 either with VOP-lit or VOP-big: - pinctrl and clk support for the hdmi node - a refactoring of rk_vop.c and rk_hdmi.c to allow for the minor differences between the RK3288 and RK3399 VOP and HDMI blocks
With this version, it has been rebased to Simon's next branch and requires the (recently submitted) fix for the RK8xx power manager driver to work reliably.
This has been tested using 'bmp display' and 'setenv stdout vidconsole' on the RK3399-Q7 with various HDMI monitors, both for VOP-lit and VOP-big (setting the other one to 'disabled').
Changes in v3: - splits the VOP driver into SOC-specific and common portions - moves the "maximum x" and "maximum y" resolution config into Kconfig (instead of having hard-coded values that may need to be revised each time someone adds a new device or new features) - split into separate drivers for the SOC-specific portion of the driver - rebase to sjg/next - enable both hdmi and vopb (as both VOPs are now disabled by default) - enable RK8XX support instead to RK808 support (rebased to sjg/next)
Changes in v2: - renamed to CONFIG_DW_HDMI (from CONFIG_DESIGNWARE_HDMI) for consistency with naming in the MMC and USB subsystems - removed DEBUG from the patch (as was done in our production branches, but missing from the patch-prep branch) - updated SJG's comment (with a TODO for the RK3288) to reflect the new code structure - rebase to master after CMD_BMP was migrated to Kconfig - don't device CONFIG_BMP_24BPP twice in config_whitelist (apparently there had been both the _24BPP and the _24BMP whitelisted before and I didn't even spot it ... thanks go to Simon for catching this) - enable SYS_WHITE_ON_BLACK via defconfig - enable CMD_BMP in the puma-rk3399_defconfig (following a rebase to the upstream master after CMD_BMP was migrate to Kconfig)
Philipp Tomsich (8): rockchip: video: introduce CONFIG_DW_HDMI and select for Rockchip HDMI rockchip: video: rk3399: enable HDMI output (from the rk_vop) for the RK3399 rockchip: video: rk3399: add HDMI TX support on the RK3399 rockchip: dts: rk3399: enable HDMI output in the DTS video: bmp: rename CONFIG_BMP_24BMP to CONFIG_BMP_24BPP rockchip: board: puma_rk3399: enable BMP_16BPP, BMP_24BPP and BMP_32BPP rockchip: defconfig: puma-rk3399: enable RK808 support rockchip: defconfig: puma-rk3399: update defconfig with video-support
arch/arm/dts/rk3399-puma.dts | 9 ++ arch/arm/dts/rk3399.dtsi | 39 +++++ arch/arm/include/asm/arch-rockchip/grf_rk3399.h | 3 + arch/arm/include/asm/arch-rockchip/vop_rk3288.h | 11 ++ common/lcd.c | 4 +- configs/puma-rk3399_defconfig | 12 ++ drivers/video/Kconfig | 9 ++ drivers/video/Makefile | 1 + drivers/video/rockchip/Kconfig | 30 +++- drivers/video/rockchip/Makefile | 6 +- drivers/video/rockchip/rk3288_hdmi.c | 116 +++++++++++++++ drivers/video/rockchip/rk3288_vop.c | 95 ++++++++++++ drivers/video/rockchip/rk3399_hdmi.c | 81 +++++++++++ drivers/video/rockchip/rk3399_vop.c | 105 ++++++++++++++ drivers/video/rockchip/rk_hdmi.c | 114 ++++----------- drivers/video/rockchip/rk_hdmi.h | 32 ++++ drivers/video/rockchip/rk_vop.c | 185 ++++++++++++------------ drivers/video/rockchip/rk_vop.h | 32 ++++ drivers/video/video_bmp.c | 4 +- include/configs/brxre1.h | 2 +- include/configs/puma_rk3399.h | 4 +- scripts/config_whitelist.txt | 1 - 22 files changed, 698 insertions(+), 197 deletions(-) create mode 100644 drivers/video/rockchip/rk3288_hdmi.c create mode 100644 drivers/video/rockchip/rk3288_vop.c create mode 100644 drivers/video/rockchip/rk3399_hdmi.c create mode 100644 drivers/video/rockchip/rk3399_vop.c create mode 100644 drivers/video/rockchip/rk_hdmi.h create mode 100644 drivers/video/rockchip/rk_vop.h

Instead of having drivers/video/rockchip/Kconfig point outside of its hierarchy for dw_hdmi.o, we should use a configuration-option to include the Designware HDMI support.
This change introduces a new config option (not to be selected via menuconfig, but to be selected from a dependent video driver's configuration option) that enables dw_hdmi.o and selects it whenever the HDMI support for Rockchip SoCs is selected.
Signed-off-by: Philipp Tomsich philipp.tomsich@theobroma-systems.com
Reviewed-by: Simon Glass sjg@chromium.org
---
Changes in v3: None Changes in v2: - renamed to CONFIG_DW_HDMI (from CONFIG_DESIGNWARE_HDMI) for consistency with naming in the MMC and USB subsystems
drivers/video/Kconfig | 9 +++++++++ drivers/video/Makefile | 1 + drivers/video/rockchip/Kconfig | 1 + drivers/video/rockchip/Makefile | 2 +- 4 files changed, 12 insertions(+), 1 deletion(-)
diff --git a/drivers/video/Kconfig b/drivers/video/Kconfig index 446cca9..61dfed8 100644 --- a/drivers/video/Kconfig +++ b/drivers/video/Kconfig @@ -619,4 +619,13 @@ config LCD CONFIG option. See the README for details. Drives which have been converted to driver model will instead used CONFIG_DM_VIDEO.
+config VIDEO_DW_HDMI + bool + help + Enables the common driver code for the Designware HDMI TX + block found in SoCs from various vendors. + As this does not provide any functionality by itself (but + rather requires a SoC-specific glue driver to call it), it + can not be enabled from the configuration menu. + endmenu diff --git a/drivers/video/Makefile b/drivers/video/Makefile index a80af31..58f5de5 100644 --- a/drivers/video/Makefile +++ b/drivers/video/Makefile @@ -57,6 +57,7 @@ obj-$(CONFIG_VIDEO_VESA) += vesa.o obj-$(CONFIG_FORMIKE) += formike.o obj-$(CONFIG_LG4573) += lg4573.o obj-$(CONFIG_AM335X_LCD) += am335x-fb.o +obj-$(CONFIG_VIDEO_DW_HDMI) += dw_hdmi.o
obj-${CONFIG_VIDEO_TEGRA124} += tegra124/ obj-${CONFIG_EXYNOS_FB} += exynos/ diff --git a/drivers/video/rockchip/Kconfig b/drivers/video/rockchip/Kconfig index 9267b28..80e399f 100644 --- a/drivers/video/rockchip/Kconfig +++ b/drivers/video/rockchip/Kconfig @@ -35,6 +35,7 @@ config DISPLAY_ROCKCHIP_LVDS
config DISPLAY_ROCKCHIP_HDMI bool "HDMI port" + select VIDEO_DW_HDMI depends on VIDEO_ROCKCHIP help This enables High-Definition Multimedia Interface display support. diff --git a/drivers/video/rockchip/Makefile b/drivers/video/rockchip/Makefile index c742902..cd54b12 100644 --- a/drivers/video/rockchip/Makefile +++ b/drivers/video/rockchip/Makefile @@ -9,6 +9,6 @@ ifdef CONFIG_VIDEO_ROCKCHIP obj-y += rk_vop.o obj-$(CONFIG_DISPLAY_ROCKCHIP_EDP) += rk_edp.o obj-$(CONFIG_DISPLAY_ROCKCHIP_LVDS) += rk_lvds.o -obj-$(CONFIG_DISPLAY_ROCKCHIP_HDMI) += rk_hdmi.o ../dw_hdmi.o +obj-$(CONFIG_DISPLAY_ROCKCHIP_HDMI) += rk_hdmi.o obj-$(CONFIG_DISPLAY_ROCKCHIP_MIPI) += rk_mipi.o endif

On Fri, 5 May 2017 21:48:26 +0200 Philipp Tomsich philipp.tomsich@theobroma-systems.com wrote:
Instead of having drivers/video/rockchip/Kconfig point outside of its hierarchy for dw_hdmi.o, we should use a configuration-option to include the Designware HDMI support.
This change introduces a new config option (not to be selected via menuconfig, but to be selected from a dependent video driver's configuration option) that enables dw_hdmi.o and selects it whenever the HDMI support for Rockchip SoCs is selected.
Signed-off-by: Philipp Tomsich philipp.tomsich@theobroma-systems.com Reviewed-by: Simon Glass sjg@chromium.org
Changes in v3: None Changes in v2:
- renamed to CONFIG_DW_HDMI (from CONFIG_DESIGNWARE_HDMI) for consistency with naming in the MMC and USB subsystems
drivers/video/Kconfig | 9 +++++++++ drivers/video/Makefile | 1 + drivers/video/rockchip/Kconfig | 1 + drivers/video/rockchip/Makefile | 2 +- 4 files changed, 12 insertions(+), 1 deletion(-)
applied to u-boot-video/master (with VIDEO_DW_HDMI in subject). Thanks!
-- Anatolij

This commit enables RK3399 support for HDMI through the following changes: - adds a driverdata structure to mirror some subtle version differences between the RK3399 VOPs and those in the RK3288 (e.g. the pin-polarity configuration) - configures the VOP to output 32bpp for HDMI - handles whether a VOP can output 10BIT data or not (i.e. RGBaaa vs. RGB888) using the driverdata structure
And as we touch this file anyway, we also increase the size of the framebuffer to a slightly overzealous 4K2K@32bpp.
Signed-off-by: Philipp Tomsich philipp.tomsich@theobroma-systems.com
---
Changes in v3: - splits the VOP driver into SOC-specific and common portions - moves the "maximum x" and "maximum y" resolution config into Kconfig (instead of having hard-coded values that may need to be revised each time someone adds a new device or new features)
Changes in v2: None
arch/arm/include/asm/arch-rockchip/vop_rk3288.h | 11 ++ drivers/video/rockchip/Kconfig | 29 +++- drivers/video/rockchip/Makefile | 2 + drivers/video/rockchip/rk3288_vop.c | 95 ++++++++++++ drivers/video/rockchip/rk3399_vop.c | 105 ++++++++++++++ drivers/video/rockchip/rk_vop.c | 185 ++++++++++++------------ drivers/video/rockchip/rk_vop.h | 32 ++++ 7 files changed, 359 insertions(+), 100 deletions(-) create mode 100644 drivers/video/rockchip/rk3288_vop.c create mode 100644 drivers/video/rockchip/rk3399_vop.c create mode 100644 drivers/video/rockchip/rk_vop.h
diff --git a/arch/arm/include/asm/arch-rockchip/vop_rk3288.h b/arch/arm/include/asm/arch-rockchip/vop_rk3288.h index d5599ec..21e59be 100644 --- a/arch/arm/include/asm/arch-rockchip/vop_rk3288.h +++ b/arch/arm/include/asm/arch-rockchip/vop_rk3288.h @@ -197,9 +197,20 @@ enum vop_modes { #define V_DSP_DEN_POL(x) (((x) & 1) << 6) #define V_DSP_VSYNC_POL(x) (((x) & 1) << 5) #define V_DSP_HSYNC_POL(x) (((x) & 1) << 4) +#define V_DSP_PIN_POL(x) (((x) & 0xf) << 4) #define V_DSP_OUT_MODE(x) ((x) & 0xf)
/* VOP_DSP_CTRL1 */ +#define V_RK3399_DSP_MIPI_POL(x) ((x) << 28) +#define V_RK3399_DSP_EDP_POL(x) ((x) << 24) +#define V_RK3399_DSP_HDMI_POL(x) ((x) << 20) +#define V_RK3399_DSP_LVDS_POL(x) ((x) << 16) + +#define M_RK3399_DSP_MIPI_POL (V_RK3399_DSP_MIPI_POL(0xf)) +#define M_RK3399_DSP_EDP_POL (V_RK3399_DSP_EDP_POL(0xf)) +#define M_RK3399_DSP_HDMI_POL (V_RK3399_DSP_HDMI_POL(0xf)) +#define M_RK3399_DSP_LVDS_POL (V_RK3399_DSP_LVDS_POL(0xf)) + #define M_DSP_LAYER3_SEL (3 << 14) #define M_DSP_LAYER2_SEL (3 << 12) #define M_DSP_LAYER1_SEL (3 << 10) diff --git a/drivers/video/rockchip/Kconfig b/drivers/video/rockchip/Kconfig index 80e399f..b1d7c62 100644 --- a/drivers/video/rockchip/Kconfig +++ b/drivers/video/rockchip/Kconfig @@ -12,11 +12,30 @@ menuconfig VIDEO_ROCKCHIP bool "Enable Rockchip Video Support" depends on DM_VIDEO help - Rockchip SoCs provide video output capabilities for High-Definition - Multimedia Interface (HDMI), Low-voltage Differential Signalling - (LVDS), embedded DisplayPort (eDP) and Display Serial Interface - (DSI). This driver supports the on-chip video output device, and - targets the Rockchip RK3288 and RK3399. + Rockchip SoCs provide video output capabilities for High-Definition + Multimedia Interface (HDMI), Low-voltage Differential Signalling + (LVDS), embedded DisplayPort (eDP) and Display Serial Interface (DSI). + + This driver supports the on-chip video output device, and targets the + Rockchip RK3288 and RK3399. + +config VIDEO_ROCKCHIP_MAX_XRES + int "Maximum horizontal resolution (for memory allocation purposes)" + depends on VIDEO_ROCKCHIP + default 1920 + help + The maximum horizontal resolution to support for the framebuffer. + This configuration is used for reserving/allocating memory for the + framebuffer during device-model binding/probing. + +config VIDEO_ROCKCHIP_MAX_YRES + int "Maximum vertical resolution (for memory allocation purposes)" + depends on VIDEO_ROCKCHIP + default 1080 + help + The maximum vertical resolution to support for the framebuffer. + This configuration is used for reserving/allocating memory for the + framebuffer during device-model binding/probing.
if VIDEO_ROCKCHIP
diff --git a/drivers/video/rockchip/Makefile b/drivers/video/rockchip/Makefile index cd54b12..495d5f7 100644 --- a/drivers/video/rockchip/Makefile +++ b/drivers/video/rockchip/Makefile @@ -7,6 +7,8 @@
ifdef CONFIG_VIDEO_ROCKCHIP obj-y += rk_vop.o +obj-$(CONFIG_ROCKCHIP_RK3288) += rk3288_vop.o +obj-$(CONFIG_ROCKCHIP_RK3399) += rk3399_vop.o obj-$(CONFIG_DISPLAY_ROCKCHIP_EDP) += rk_edp.o obj-$(CONFIG_DISPLAY_ROCKCHIP_LVDS) += rk_lvds.o obj-$(CONFIG_DISPLAY_ROCKCHIP_HDMI) += rk_hdmi.o diff --git a/drivers/video/rockchip/rk3288_vop.c b/drivers/video/rockchip/rk3288_vop.c new file mode 100644 index 0000000..e3e1ec7 --- /dev/null +++ b/drivers/video/rockchip/rk3288_vop.c @@ -0,0 +1,95 @@ +/* + * Copyright (c) 2017 Theobroma Systems Design und Consulting GmbH + * Copyright (c) 2015 Google, Inc + * Copyright 2014 Rockchip Inc. + * + * SPDX-License-Identifier: GPL-2.0+ + */ + +#include <common.h> +#include <display.h> +#include <dm.h> +#include <regmap.h> +#include <syscon.h> +#include <video.h> +#include <asm/hardware.h> +#include <asm/io.h> +#include <asm/arch/clock.h> +#include <asm/arch/grf_rk3288.h> +#include "rk_vop.h" + +DECLARE_GLOBAL_DATA_PTR; + +static void rk3288_set_pin_polarity(struct udevice *dev, + enum vop_modes mode, u32 polarity) +{ + struct rk_vop_priv *priv = dev_get_priv(dev); + struct rk3288_vop *regs = priv->regs; + + /* The RK3328 VOP (v3.1) has its polarity configuration in ctrl0 */ + clrsetbits_le32(®s->dsp_ctrl0, + M_DSP_DCLK_POL | M_DSP_DEN_POL | + M_DSP_VSYNC_POL | M_DSP_HSYNC_POL, + V_DSP_PIN_POL(polarity)); +} + +static void rk3288_set_io_vsel(struct udevice *dev) +{ + struct rk3288_grf *grf = syscon_get_first_range(ROCKCHIP_SYSCON_GRF); + + /* lcdc(vop) iodomain select 1.8V */ + rk_setreg(&grf->io_vsel, 1 << 0); +} + +/* + * Try some common regulators. We should really get these from the + * device tree somehow. + */ +static const char * const rk3288_regulator_names[] = { + "vcc18_lcd", + "VCC18_LCD", + "vdd10_lcd_pwren_h", + "vdd10_lcd", + "VDD10_LCD", + "vcc33_lcd" +}; + +static int rk3288_vop_probe(struct udevice *dev) +{ + /* Before relocation we don't need to do anything */ + if (!(gd->flags & GD_FLG_RELOC)) + return 0; + + /* Set the LCDC(vop) iodomain to 1.8V */ + rk3288_set_io_vsel(dev); + + /* Probe regulators required for the RK3288 VOP */ + rk_vop_probe_regulators(dev, rk3288_regulator_names, + ARRAY_SIZE(rk3288_regulator_names)); + + return rk_vop_probe(dev); +} + +struct rkvop_driverdata rk3288_driverdata = { + .features = VOP_FEATURE_OUTPUT_10BIT, + .set_pin_polarity = rk3288_set_pin_polarity, +}; + +static const struct udevice_id rk3288_vop_ids[] = { + { .compatible = "rockchip,rk3288-vop", + .data = (ulong)&rk3288_driverdata }, + { } +}; + +static const struct video_ops rk3288_vop_ops = { +}; + +U_BOOT_DRIVER(rk_vop) = { + .name = "rk3288_vop", + .id = UCLASS_VIDEO, + .of_match = rk3288_vop_ids, + .ops = &rk3288_vop_ops, + .bind = rk_vop_bind, + .probe = rk3288_vop_probe, + .priv_auto_alloc_size = sizeof(struct rk_vop_priv), +}; diff --git a/drivers/video/rockchip/rk3399_vop.c b/drivers/video/rockchip/rk3399_vop.c new file mode 100644 index 0000000..91a40ab --- /dev/null +++ b/drivers/video/rockchip/rk3399_vop.c @@ -0,0 +1,105 @@ +/* + * Copyright (c) 2017 Theobroma Systems Design und Consulting GmbH + * Copyright (c) 2015 Google, Inc + * Copyright 2014 Rockchip Inc. + * + * SPDX-License-Identifier: GPL-2.0+ + */ + +#include <common.h> +#include <display.h> +#include <dm.h> +#include <regmap.h> +#include <video.h> +#include <asm/hardware.h> +#include <asm/io.h> +#include "rk_vop.h" + +DECLARE_GLOBAL_DATA_PTR; + +static void rk3399_set_pin_polarity(struct udevice *dev, + enum vop_modes mode, u32 polarity) +{ + struct rk_vop_priv *priv = dev_get_priv(dev); + struct rk3288_vop *regs = priv->regs; + + /* + * The RK3399 VOPs (v3.5 and v3.6) require a per-mode setting of + * the polarity configuration (in ctrl1). + */ + switch (mode) { + case VOP_MODE_HDMI: + clrsetbits_le32(®s->dsp_ctrl1, + M_RK3399_DSP_HDMI_POL, + V_RK3399_DSP_HDMI_POL(polarity)); + break; + + case VOP_MODE_EDP: + clrsetbits_le32(®s->dsp_ctrl1, + M_RK3399_DSP_EDP_POL, + V_RK3399_DSP_EDP_POL(polarity)); + break; + + case VOP_MODE_MIPI: + clrsetbits_le32(®s->dsp_ctrl1, + M_RK3399_DSP_MIPI_POL, + V_RK3399_DSP_MIPI_POL(polarity)); + break; + + case VOP_MODE_LVDS: + /* The RK3399 has neither parallel RGB nor LVDS output. */ + default: + debug("%s: unsupported output mode %x\n", __func__, mode); + } +} + +/* + * Try some common regulators. We should really get these from the + * device tree somehow. + */ +static const char * const rk3399_regulator_names[] = { + "vcc33_lcd" +}; + +static int rk3399_vop_probe(struct udevice *dev) +{ + /* Before relocation we don't need to do anything */ + if (!(gd->flags & GD_FLG_RELOC)) + return 0; + + /* Probe regulators required for the RK3399 VOP */ + rk_vop_probe_regulators(dev, rk3399_regulator_names, + ARRAY_SIZE(rk3399_regulator_names)); + + return rk_vop_probe(dev); +} + +struct rkvop_driverdata rk3399_lit_driverdata = { + .set_pin_polarity = rk3399_set_pin_polarity, +}; + +struct rkvop_driverdata rk3399_big_driverdata = { + .features = VOP_FEATURE_OUTPUT_10BIT, + .set_pin_polarity = rk3399_set_pin_polarity, +}; + +static const struct udevice_id rk3399_vop_ids[] = { + { .compatible = "rockchip,rk3399-vop-big", + .data = (ulong)&rk3399_big_driverdata }, + { .compatible = "rockchip,rk3399-vop-lit", + .data = (ulong)&rk3399_lit_driverdata }, + { } +}; + +static const struct video_ops rk3399_vop_ops = { +}; + +U_BOOT_DRIVER(rk3399_vop) = { + .name = "rk3399_vop", + .id = UCLASS_VIDEO, + .of_match = rk3399_vop_ids, + .ops = &rk3399_vop_ops, + .bind = rk_vop_bind, + .probe = rk3399_vop_probe, + .priv_auto_alloc_size = sizeof(struct rk_vop_priv), +}; diff --git a/drivers/video/rockchip/rk_vop.c b/drivers/video/rockchip/rk_vop.c index aa6ca8c..c15f93d 100644 --- a/drivers/video/rockchip/rk_vop.c +++ b/drivers/video/rockchip/rk_vop.c @@ -17,24 +17,25 @@ #include <asm/hardware.h> #include <asm/io.h> #include <asm/arch/clock.h> -#include <asm/arch/cru_rk3288.h> -#include <asm/arch/grf_rk3288.h> #include <asm/arch/edp_rk3288.h> #include <asm/arch/vop_rk3288.h> #include <dm/device-internal.h> #include <dm/uclass-internal.h> -#include <dt-bindings/clock/rk3288-cru.h> #include <power/regulator.h> +#include "rk_vop.h"
DECLARE_GLOBAL_DATA_PTR;
-struct rk_vop_priv { - struct rk3288_vop *regs; - struct rk3288_grf *grf; +enum vop_pol { + HSYNC_POSITIVE = 0, + VSYNC_POSITIVE = 1, + DEN_NEGATIVE = 2, + DCLK_INVERT = 3 };
-void rkvop_enable(struct rk3288_vop *regs, ulong fbbase, - int fb_bits_per_pixel, const struct display_timing *edid) +static void rkvop_enable(struct rk3288_vop *regs, ulong fbbase, + int fb_bits_per_pixel, + const struct display_timing *edid) { u32 lb_mode; u32 rgb_mode; @@ -89,54 +90,83 @@ void rkvop_enable(struct rk3288_vop *regs, ulong fbbase, writel(0x01, ®s->reg_cfg_done); /* enable reg config */ }
-void rkvop_mode_set(struct rk3288_vop *regs, - const struct display_timing *edid, enum vop_modes mode) +static void rkvop_set_pin_polarity(struct udevice *dev, + enum vop_modes mode, u32 polarity) { - u32 hactive = edid->hactive.typ; - u32 vactive = edid->vactive.typ; - u32 hsync_len = edid->hsync_len.typ; - u32 hback_porch = edid->hback_porch.typ; - u32 vsync_len = edid->vsync_len.typ; - u32 vback_porch = edid->vback_porch.typ; - u32 hfront_porch = edid->hfront_porch.typ; - u32 vfront_porch = edid->vfront_porch.typ; - uint flags; - int mode_flags; + struct rkvop_driverdata *ops = + (struct rkvop_driverdata *)dev_get_driver_data(dev); + + if (ops->set_pin_polarity) + ops->set_pin_polarity(dev, mode, polarity); +} + +static void rkvop_enable_output(struct udevice *dev, enum vop_modes mode) +{ + struct rk_vop_priv *priv = dev_get_priv(dev); + struct rk3288_vop *regs = priv->regs;
switch (mode) { case VOP_MODE_HDMI: clrsetbits_le32(®s->sys_ctrl, M_ALL_OUT_EN, V_HDMI_OUT_EN(1)); break; + case VOP_MODE_EDP: - default: clrsetbits_le32(®s->sys_ctrl, M_ALL_OUT_EN, V_EDP_OUT_EN(1)); break; + case VOP_MODE_LVDS: clrsetbits_le32(®s->sys_ctrl, M_ALL_OUT_EN, V_RGB_OUT_EN(1)); break; + case VOP_MODE_MIPI: clrsetbits_le32(®s->sys_ctrl, M_ALL_OUT_EN, V_MIPI_OUT_EN(1)); - break; + break; + + default: + debug("%s: unsupported output mode %x\n", __func__, mode); } +}
- if (mode == VOP_MODE_HDMI || mode == VOP_MODE_EDP) - /* RGBaaa */ - mode_flags = 15; - else - /* RGB888 */ - mode_flags = 0; +static void rkvop_mode_set(struct udevice *dev, + const struct display_timing *edid, + enum vop_modes mode) +{ + struct rk_vop_priv *priv = dev_get_priv(dev); + struct rk3288_vop *regs = priv->regs; + struct rkvop_driverdata *data = + (struct rkvop_driverdata *)dev_get_driver_data(dev);
- flags = V_DSP_OUT_MODE(mode_flags) | - V_DSP_HSYNC_POL(!!(edid->flags & DISPLAY_FLAGS_HSYNC_HIGH)) | - V_DSP_VSYNC_POL(!!(edid->flags & DISPLAY_FLAGS_VSYNC_HIGH)); + u32 hactive = edid->hactive.typ; + u32 vactive = edid->vactive.typ; + u32 hsync_len = edid->hsync_len.typ; + u32 hback_porch = edid->hback_porch.typ; + u32 vsync_len = edid->vsync_len.typ; + u32 vback_porch = edid->vback_porch.typ; + u32 hfront_porch = edid->hfront_porch.typ; + u32 vfront_porch = edid->vfront_porch.typ; + int mode_flags; + u32 pin_polarity; + + pin_polarity = BIT(DCLK_INVERT); + if (edid->flags & DISPLAY_FLAGS_HSYNC_HIGH) + pin_polarity |= BIT(HSYNC_POSITIVE); + if (edid->flags & DISPLAY_FLAGS_VSYNC_HIGH) + pin_polarity |= BIT(VSYNC_POSITIVE); + + rkvop_set_pin_polarity(dev, mode, pin_polarity); + rkvop_enable_output(dev, mode);
- clrsetbits_le32(®s->dsp_ctrl0, - M_DSP_OUT_MODE | M_DSP_VSYNC_POL | M_DSP_HSYNC_POL, - flags); + mode_flags = 0; /* RGB888 */ + if ((data->features & VOP_FEATURE_OUTPUT_10BIT) && + (mode == VOP_MODE_HDMI || mode == VOP_MODE_EDP)) + mode_flags = 15; /* RGBaaa */ + + clrsetbits_le32(®s->dsp_ctrl0, M_DSP_OUT_MODE, + V_DSP_OUT_MODE(mode_flags));
writel(V_HSYNC(hsync_len) | V_HORPRD(hsync_len + hback_porch + hactive + hfront_porch), @@ -185,7 +215,7 @@ void rkvop_mode_set(struct rk3288_vop *regs, * node within the VOP's 'port' list. * @return 0 if OK, -ve if something went wrong */ -int rk_display_init(struct udevice *dev, ulong fbbase, int ep_node) +static int rk_display_init(struct udevice *dev, ulong fbbase, int ep_node) { struct video_priv *uc_priv = dev_get_uclass_priv(dev); const void *blob = gd->fdt_blob; @@ -255,18 +285,18 @@ int rk_display_init(struct udevice *dev, ulong fbbase, int ep_node) /* Set bitwidth for vop display according to vop mode */ switch (vop_id) { case VOP_MODE_EDP: - case VOP_MODE_HDMI: case VOP_MODE_LVDS: l2bpp = VIDEO_BPP16; break; + case VOP_MODE_HDMI: case VOP_MODE_MIPI: l2bpp = VIDEO_BPP32; break; default: l2bpp = VIDEO_BPP16; } - rkvop_mode_set(regs, &timing, vop_id);
+ rkvop_mode_set(dev, &timing, vop_id); rkvop_enable(regs, fbbase, 1 << l2bpp, &timing);
ret = display_enable(disp, 1 << l2bpp, &timing); @@ -281,53 +311,37 @@ int rk_display_init(struct udevice *dev, ulong fbbase, int ep_node) return 0; }
-static int rk_vop_probe(struct udevice *dev) +void rk_vop_probe_regulators(struct udevice *dev, + const char * const *names, int cnt) +{ + int i, ret; + const char *name; + struct udevice *reg; + + for (i = 0; i < cnt; ++i) { + name = names[i]; + debug("%s: probing regulator '%s'\n", dev->name, name); + + ret = regulator_autoset_by_name(name, ®); + if (!ret) + ret = regulator_set_enable(reg, true); + } +} + +int rk_vop_probe(struct udevice *dev) { struct video_uc_platdata *plat = dev_get_uclass_platdata(dev); const void *blob = gd->fdt_blob; struct rk_vop_priv *priv = dev_get_priv(dev); - struct udevice *reg; - int ret, port, node; + int ret = 0; + int port, node;
/* Before relocation we don't need to do anything */ if (!(gd->flags & GD_FLG_RELOC)) return 0;
- priv->grf = syscon_get_first_range(ROCKCHIP_SYSCON_GRF); priv->regs = (struct rk3288_vop *)dev_get_addr(dev);
- /* lcdc(vop) iodomain select 1.8V */ - rk_setreg(&priv->grf->io_vsel, 1 << 0); - - /* - * Try some common regulators. We should really get these from the - * device tree somehow. - */ - ret = regulator_autoset_by_name("vcc18_lcd", ®); - if (ret) - debug("%s: Cannot autoset regulator vcc18_lcd\n", __func__); - ret = regulator_autoset_by_name("VCC18_LCD", ®); - if (ret) - debug("%s: Cannot autoset regulator VCC18_LCD\n", __func__); - ret = regulator_autoset_by_name("vdd10_lcd_pwren_h", ®); - if (ret) { - debug("%s: Cannot autoset regulator vdd10_lcd_pwren_h\n", - __func__); - } - ret = regulator_autoset_by_name("vdd10_lcd", ®); - if (ret) { - debug("%s: Cannot autoset regulator vdd10_lcd\n", - __func__); - } - ret = regulator_autoset_by_name("VDD10_LCD", ®); - if (ret) { - debug("%s: Cannot autoset regulator VDD10_LCD\n", - __func__); - } - ret = regulator_autoset_by_name("vcc33_lcd", ®); - if (ret) - debug("%s: Cannot autoset regulator vcc33_lcd\n", __func__); - /* * Try all the ports until we find one that works. In practice this * tries EDP first if available, then HDMI. @@ -353,31 +367,12 @@ static int rk_vop_probe(struct udevice *dev) return ret; }
-static int rk_vop_bind(struct udevice *dev) +int rk_vop_bind(struct udevice *dev) { struct video_uc_platdata *plat = dev_get_uclass_platdata(dev);
- plat->size = 1920 * 1200 * 4; + plat->size = 4 * (CONFIG_VIDEO_ROCKCHIP_MAX_XRES * + CONFIG_VIDEO_ROCKCHIP_MAX_YRES);
return 0; } - -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" }, - { } -}; - -U_BOOT_DRIVER(rk_vop) = { - .name = "rk_vop", - .id = UCLASS_VIDEO, - .of_match = rk_vop_ids, - .ops = &rk_vop_ops, - .bind = rk_vop_bind, - .probe = rk_vop_probe, - .priv_auto_alloc_size = sizeof(struct rk_vop_priv), -}; diff --git a/drivers/video/rockchip/rk_vop.h b/drivers/video/rockchip/rk_vop.h new file mode 100644 index 0000000..f65ac17 --- /dev/null +++ b/drivers/video/rockchip/rk_vop.h @@ -0,0 +1,32 @@ +/* + * Copyright (c) 2017 Theobroma Systems Design und Consulting GmbH + * + * SPDX-License-Identifier: GPL-2.0+ + */ + +#ifndef __RK_VOP_H__ +#define __RK_VOP_H__ + +#include <asm/arch/vop_rk3288.h> + +struct rk_vop_priv { + void *regs; +}; + +enum vop_features { + VOP_FEATURE_OUTPUT_10BIT = (1 << 0), +}; + +struct rkvop_driverdata { + /* configuration */ + u32 features; + /* block-specific setters/getters */ + void (*set_pin_polarity)(struct udevice *, enum vop_modes, u32); +}; + +int rk_vop_probe(struct udevice *dev); +int rk_vop_bind(struct udevice *dev); +void rk_vop_probe_regulators(struct udevice *dev, + const char * const *names, int cnt); + +#endif

Hi Philipp,
On 5 May 2017 at 13:48, Philipp Tomsich philipp.tomsich@theobroma-systems.com wrote:
This commit enables RK3399 support for HDMI through the following changes:
- adds a driverdata structure to mirror some subtle version differences between the RK3399 VOPs and those in the RK3288 (e.g. the pin-polarity configuration)
- configures the VOP to output 32bpp for HDMI
- handles whether a VOP can output 10BIT data or not (i.e. RGBaaa vs. RGB888) using the driverdata structure
And as we touch this file anyway, we also increase the size of the framebuffer to a slightly overzealous 4K2K@32bpp.
Signed-off-by: Philipp Tomsich philipp.tomsich@theobroma-systems.com
Changes in v3:
- splits the VOP driver into SOC-specific and common portions
- moves the "maximum x" and "maximum y" resolution config into Kconfig (instead of having hard-coded values that may need to be revised each time someone adds a new device or new features)
Changes in v2: None
arch/arm/include/asm/arch-rockchip/vop_rk3288.h | 11 ++ drivers/video/rockchip/Kconfig | 29 +++- drivers/video/rockchip/Makefile | 2 + drivers/video/rockchip/rk3288_vop.c | 95 ++++++++++++ drivers/video/rockchip/rk3399_vop.c | 105 ++++++++++++++ drivers/video/rockchip/rk_vop.c | 185 ++++++++++++------------ drivers/video/rockchip/rk_vop.h | 32 ++++ 7 files changed, 359 insertions(+), 100 deletions(-) create mode 100644 drivers/video/rockchip/rk3288_vop.c create mode 100644 drivers/video/rockchip/rk3399_vop.c create mode 100644 drivers/video/rockchip/rk_vop.h
This looks really good, but there is too much going on in this patch. Can you please split it into patches like:
- Kconfig change for max res - the change to use rk_vop_probe_regulators - splitting out rk3288_vop.c - adding rk3399 support
A few comments below..
diff --git a/arch/arm/include/asm/arch-rockchip/vop_rk3288.h b/arch/arm/include/asm/arch-rockchip/vop_rk3288.h index d5599ec..21e59be 100644 --- a/arch/arm/include/asm/arch-rockchip/vop_rk3288.h +++ b/arch/arm/include/asm/arch-rockchip/vop_rk3288.h @@ -197,9 +197,20 @@ enum vop_modes { #define V_DSP_DEN_POL(x) (((x) & 1) << 6) #define V_DSP_VSYNC_POL(x) (((x) & 1) << 5) #define V_DSP_HSYNC_POL(x) (((x) & 1) << 4) +#define V_DSP_PIN_POL(x) (((x) & 0xf) << 4)
I'm not keen on this sort of thing. I'd prefer to have SHIFT and MASK defines for these values
#define V_DSP_PIN_POLL_SHIFT 4 #define V_DSP_PIN_POLL_MASK (0xf << V_DSP_PIN_POLL_SHIFT)
and then have the C code do the right thing.
#define V_DSP_OUT_MODE(x) ((x) & 0xf)
/* VOP_DSP_CTRL1 */ +#define V_RK3399_DSP_MIPI_POL(x) ((x) << 28) +#define V_RK3399_DSP_EDP_POL(x) ((x) << 24) +#define V_RK3399_DSP_HDMI_POL(x) ((x) << 20) +#define V_RK3399_DSP_LVDS_POL(x) ((x) << 16)
+#define M_RK3399_DSP_MIPI_POL (V_RK3399_DSP_MIPI_POL(0xf)) +#define M_RK3399_DSP_EDP_POL (V_RK3399_DSP_EDP_POL(0xf)) +#define M_RK3399_DSP_HDMI_POL (V_RK3399_DSP_HDMI_POL(0xf)) +#define M_RK3399_DSP_LVDS_POL (V_RK3399_DSP_LVDS_POL(0xf))
#define M_DSP_LAYER3_SEL (3 << 14) #define M_DSP_LAYER2_SEL (3 << 12) #define M_DSP_LAYER1_SEL (3 << 10) diff --git a/drivers/video/rockchip/Kconfig b/drivers/video/rockchip/Kconfig index 80e399f..b1d7c62 100644 --- a/drivers/video/rockchip/Kconfig +++ b/drivers/video/rockchip/Kconfig @@ -12,11 +12,30 @@ menuconfig VIDEO_ROCKCHIP bool "Enable Rockchip Video Support" depends on DM_VIDEO help
Rockchip SoCs provide video output capabilities for High-Definition
Multimedia Interface (HDMI), Low-voltage Differential Signalling
(LVDS), embedded DisplayPort (eDP) and Display Serial Interface
(DSI). This driver supports the on-chip video output device, and
targets the Rockchip RK3288 and RK3399.
Rockchip SoCs provide video output capabilities for High-Definition
Multimedia Interface (HDMI), Low-voltage Differential Signalling
(LVDS), embedded DisplayPort (eDP) and Display Serial Interface (DSI).
This driver supports the on-chip video output device, and targets the
Rockchip RK3288 and RK3399.
It looks like you are changing an exiting option - this should go in its own patch too.
+config VIDEO_ROCKCHIP_MAX_XRES
int "Maximum horizontal resolution (for memory allocation purposes)"
depends on VIDEO_ROCKCHIP
default 1920
help
The maximum horizontal resolution to support for the framebuffer.
This configuration is used for reserving/allocating memory for the
framebuffer during device-model binding/probing.
+config VIDEO_ROCKCHIP_MAX_YRES
int "Maximum vertical resolution (for memory allocation purposes)"
depends on VIDEO_ROCKCHIP
default 1080
help
The maximum vertical resolution to support for the framebuffer.
This configuration is used for reserving/allocating memory for the
framebuffer during device-model binding/probing.
if VIDEO_ROCKCHIP
diff --git a/drivers/video/rockchip/Makefile b/drivers/video/rockchip/Makefile index cd54b12..495d5f7 100644 --- a/drivers/video/rockchip/Makefile +++ b/drivers/video/rockchip/Makefile @@ -7,6 +7,8 @@
ifdef CONFIG_VIDEO_ROCKCHIP obj-y += rk_vop.o +obj-$(CONFIG_ROCKCHIP_RK3288) += rk3288_vop.o +obj-$(CONFIG_ROCKCHIP_RK3399) += rk3399_vop.o obj-$(CONFIG_DISPLAY_ROCKCHIP_EDP) += rk_edp.o obj-$(CONFIG_DISPLAY_ROCKCHIP_LVDS) += rk_lvds.o obj-$(CONFIG_DISPLAY_ROCKCHIP_HDMI) += rk_hdmi.o diff --git a/drivers/video/rockchip/rk3288_vop.c b/drivers/video/rockchip/rk3288_vop.c new file mode 100644 index 0000000..e3e1ec7 --- /dev/null +++ b/drivers/video/rockchip/rk3288_vop.c @@ -0,0 +1,95 @@ +/*
- Copyright (c) 2017 Theobroma Systems Design und Consulting GmbH
- Copyright (c) 2015 Google, Inc
- Copyright 2014 Rockchip Inc.
- SPDX-License-Identifier: GPL-2.0+
- */
+#include <common.h> +#include <display.h> +#include <dm.h> +#include <regmap.h> +#include <syscon.h> +#include <video.h> +#include <asm/hardware.h> +#include <asm/io.h> +#include <asm/arch/clock.h> +#include <asm/arch/grf_rk3288.h> +#include "rk_vop.h"
+DECLARE_GLOBAL_DATA_PTR;
+static void rk3288_set_pin_polarity(struct udevice *dev,
enum vop_modes mode, u32 polarity)
+{
struct rk_vop_priv *priv = dev_get_priv(dev);
struct rk3288_vop *regs = priv->regs;
/* The RK3328 VOP (v3.1) has its polarity configuration in ctrl0 */
clrsetbits_le32(®s->dsp_ctrl0,
M_DSP_DCLK_POL | M_DSP_DEN_POL |
M_DSP_VSYNC_POL | M_DSP_HSYNC_POL,
V_DSP_PIN_POL(polarity));
+}
+static void rk3288_set_io_vsel(struct udevice *dev) +{
struct rk3288_grf *grf = syscon_get_first_range(ROCKCHIP_SYSCON_GRF);
/* lcdc(vop) iodomain select 1.8V */
rk_setreg(&grf->io_vsel, 1 << 0);
+}
+/*
- Try some common regulators. We should really get these from the
- device tree somehow.
Any thoughts on how to do that? If so, please add them here.
- */
+static const char * const rk3288_regulator_names[] = {
"vcc18_lcd",
"VCC18_LCD",
"vdd10_lcd_pwren_h",
"vdd10_lcd",
"VDD10_LCD",
"vcc33_lcd"
+};
+static int rk3288_vop_probe(struct udevice *dev) +{
/* Before relocation we don't need to do anything */
if (!(gd->flags & GD_FLG_RELOC))
return 0;
/* Set the LCDC(vop) iodomain to 1.8V */
rk3288_set_io_vsel(dev);
/* Probe regulators required for the RK3288 VOP */
rk_vop_probe_regulators(dev, rk3288_regulator_names,
ARRAY_SIZE(rk3288_regulator_names));
return rk_vop_probe(dev);
+}
+struct rkvop_driverdata rk3288_driverdata = {
.features = VOP_FEATURE_OUTPUT_10BIT,
.set_pin_polarity = rk3288_set_pin_polarity,
+};
+static const struct udevice_id rk3288_vop_ids[] = {
{ .compatible = "rockchip,rk3288-vop",
.data = (ulong)&rk3288_driverdata },
{ }
+};
+static const struct video_ops rk3288_vop_ops = { +};
+U_BOOT_DRIVER(rk_vop) = {
.name = "rk3288_vop",
.id = UCLASS_VIDEO,
.of_match = rk3288_vop_ids,
.ops = &rk3288_vop_ops,
.bind = rk_vop_bind,
.probe = rk3288_vop_probe,
.priv_auto_alloc_size = sizeof(struct rk_vop_priv),
+}; diff --git a/drivers/video/rockchip/rk3399_vop.c b/drivers/video/rockchip/rk3399_vop.c new file mode 100644 index 0000000..91a40ab --- /dev/null +++ b/drivers/video/rockchip/rk3399_vop.c @@ -0,0 +1,105 @@ +/*
- Copyright (c) 2017 Theobroma Systems Design und Consulting GmbH
- Copyright (c) 2015 Google, Inc
- Copyright 2014 Rockchip Inc.
- SPDX-License-Identifier: GPL-2.0+
- */
+#include <common.h> +#include <display.h> +#include <dm.h> +#include <regmap.h> +#include <video.h> +#include <asm/hardware.h> +#include <asm/io.h> +#include "rk_vop.h"
+DECLARE_GLOBAL_DATA_PTR;
+static void rk3399_set_pin_polarity(struct udevice *dev,
enum vop_modes mode, u32 polarity)
+{
struct rk_vop_priv *priv = dev_get_priv(dev);
struct rk3288_vop *regs = priv->regs;
/*
* The RK3399 VOPs (v3.5 and v3.6) require a per-mode setting of
* the polarity configuration (in ctrl1).
*/
switch (mode) {
case VOP_MODE_HDMI:
clrsetbits_le32(®s->dsp_ctrl1,
M_RK3399_DSP_HDMI_POL,
V_RK3399_DSP_HDMI_POL(polarity));
break;
case VOP_MODE_EDP:
clrsetbits_le32(®s->dsp_ctrl1,
M_RK3399_DSP_EDP_POL,
V_RK3399_DSP_EDP_POL(polarity));
break;
case VOP_MODE_MIPI:
clrsetbits_le32(®s->dsp_ctrl1,
M_RK3399_DSP_MIPI_POL,
V_RK3399_DSP_MIPI_POL(polarity));
break;
case VOP_MODE_LVDS:
/* The RK3399 has neither parallel RGB nor LVDS output. */
default:
debug("%s: unsupported output mode %x\n", __func__, mode);
}
+}
+/*
- Try some common regulators. We should really get these from the
- device tree somehow.
- */
+static const char * const rk3399_regulator_names[] = {
"vcc33_lcd"
+};
+static int rk3399_vop_probe(struct udevice *dev) +{
/* Before relocation we don't need to do anything */
if (!(gd->flags & GD_FLG_RELOC))
return 0;
/* Probe regulators required for the RK3399 VOP */
rk_vop_probe_regulators(dev, rk3399_regulator_names,
ARRAY_SIZE(rk3399_regulator_names));
return rk_vop_probe(dev);
+}
+struct rkvop_driverdata rk3399_lit_driverdata = {
.set_pin_polarity = rk3399_set_pin_polarity,
+};
+struct rkvop_driverdata rk3399_big_driverdata = {
.features = VOP_FEATURE_OUTPUT_10BIT,
.set_pin_polarity = rk3399_set_pin_polarity,
+};
+static const struct udevice_id rk3399_vop_ids[] = {
{ .compatible = "rockchip,rk3399-vop-big",
.data = (ulong)&rk3399_big_driverdata },
{ .compatible = "rockchip,rk3399-vop-lit",
.data = (ulong)&rk3399_lit_driverdata },
{ }
+};
+static const struct video_ops rk3399_vop_ops = { +};
+U_BOOT_DRIVER(rk3399_vop) = {
.name = "rk3399_vop",
.id = UCLASS_VIDEO,
.of_match = rk3399_vop_ids,
.ops = &rk3399_vop_ops,
.bind = rk_vop_bind,
.probe = rk3399_vop_probe,
.priv_auto_alloc_size = sizeof(struct rk_vop_priv),
+}; diff --git a/drivers/video/rockchip/rk_vop.c b/drivers/video/rockchip/rk_vop.c index aa6ca8c..c15f93d 100644 --- a/drivers/video/rockchip/rk_vop.c +++ b/drivers/video/rockchip/rk_vop.c @@ -17,24 +17,25 @@ #include <asm/hardware.h> #include <asm/io.h> #include <asm/arch/clock.h> -#include <asm/arch/cru_rk3288.h> -#include <asm/arch/grf_rk3288.h> #include <asm/arch/edp_rk3288.h> #include <asm/arch/vop_rk3288.h> #include <dm/device-internal.h> #include <dm/uclass-internal.h> -#include <dt-bindings/clock/rk3288-cru.h> #include <power/regulator.h> +#include "rk_vop.h"
DECLARE_GLOBAL_DATA_PTR;
-struct rk_vop_priv {
struct rk3288_vop *regs;
struct rk3288_grf *grf;
+enum vop_pol {
HSYNC_POSITIVE = 0,
VSYNC_POSITIVE = 1,
DEN_NEGATIVE = 2,
DCLK_INVERT = 3
};
-void rkvop_enable(struct rk3288_vop *regs, ulong fbbase,
int fb_bits_per_pixel, const struct display_timing *edid)
+static void rkvop_enable(struct rk3288_vop *regs, ulong fbbase,
int fb_bits_per_pixel,
const struct display_timing *edid)
{ u32 lb_mode; u32 rgb_mode; @@ -89,54 +90,83 @@ void rkvop_enable(struct rk3288_vop *regs, ulong fbbase, writel(0x01, ®s->reg_cfg_done); /* enable reg config */ }
-void rkvop_mode_set(struct rk3288_vop *regs,
const struct display_timing *edid, enum vop_modes mode)
+static void rkvop_set_pin_polarity(struct udevice *dev,
enum vop_modes mode, u32 polarity)
{
u32 hactive = edid->hactive.typ;
u32 vactive = edid->vactive.typ;
u32 hsync_len = edid->hsync_len.typ;
u32 hback_porch = edid->hback_porch.typ;
u32 vsync_len = edid->vsync_len.typ;
u32 vback_porch = edid->vback_porch.typ;
u32 hfront_porch = edid->hfront_porch.typ;
u32 vfront_porch = edid->vfront_porch.typ;
uint flags;
int mode_flags;
struct rkvop_driverdata *ops =
(struct rkvop_driverdata *)dev_get_driver_data(dev);
if (ops->set_pin_polarity)
ops->set_pin_polarity(dev, mode, polarity);
+}
+static void rkvop_enable_output(struct udevice *dev, enum vop_modes mode) +{
struct rk_vop_priv *priv = dev_get_priv(dev);
struct rk3288_vop *regs = priv->regs; switch (mode) { case VOP_MODE_HDMI: clrsetbits_le32(®s->sys_ctrl, M_ALL_OUT_EN, V_HDMI_OUT_EN(1)); break;
case VOP_MODE_EDP:
default: clrsetbits_le32(®s->sys_ctrl, M_ALL_OUT_EN, V_EDP_OUT_EN(1)); break;
case VOP_MODE_LVDS: clrsetbits_le32(®s->sys_ctrl, M_ALL_OUT_EN, V_RGB_OUT_EN(1)); break;
case VOP_MODE_MIPI: clrsetbits_le32(®s->sys_ctrl, M_ALL_OUT_EN, V_MIPI_OUT_EN(1));
break;
break;
default:
debug("%s: unsupported output mode %x\n", __func__, mode); }
+}
if (mode == VOP_MODE_HDMI || mode == VOP_MODE_EDP)
/* RGBaaa */
mode_flags = 15;
else
/* RGB888 */
mode_flags = 0;
+static void rkvop_mode_set(struct udevice *dev,
const struct display_timing *edid,
enum vop_modes mode)
+{
struct rk_vop_priv *priv = dev_get_priv(dev);
struct rk3288_vop *regs = priv->regs;
struct rkvop_driverdata *data =
(struct rkvop_driverdata *)dev_get_driver_data(dev);
flags = V_DSP_OUT_MODE(mode_flags) |
V_DSP_HSYNC_POL(!!(edid->flags & DISPLAY_FLAGS_HSYNC_HIGH)) |
V_DSP_VSYNC_POL(!!(edid->flags & DISPLAY_FLAGS_VSYNC_HIGH));
u32 hactive = edid->hactive.typ;
u32 vactive = edid->vactive.typ;
u32 hsync_len = edid->hsync_len.typ;
u32 hback_porch = edid->hback_porch.typ;
u32 vsync_len = edid->vsync_len.typ;
u32 vback_porch = edid->vback_porch.typ;
u32 hfront_porch = edid->hfront_porch.typ;
u32 vfront_porch = edid->vfront_porch.typ;
int mode_flags;
u32 pin_polarity;
pin_polarity = BIT(DCLK_INVERT);
if (edid->flags & DISPLAY_FLAGS_HSYNC_HIGH)
pin_polarity |= BIT(HSYNC_POSITIVE);
if (edid->flags & DISPLAY_FLAGS_VSYNC_HIGH)
pin_polarity |= BIT(VSYNC_POSITIVE);
rkvop_set_pin_polarity(dev, mode, pin_polarity);
rkvop_enable_output(dev, mode);
clrsetbits_le32(®s->dsp_ctrl0,
M_DSP_OUT_MODE | M_DSP_VSYNC_POL | M_DSP_HSYNC_POL,
flags);
mode_flags = 0; /* RGB888 */
if ((data->features & VOP_FEATURE_OUTPUT_10BIT) &&
(mode == VOP_MODE_HDMI || mode == VOP_MODE_EDP))
mode_flags = 15; /* RGBaaa */
clrsetbits_le32(®s->dsp_ctrl0, M_DSP_OUT_MODE,
V_DSP_OUT_MODE(mode_flags)); writel(V_HSYNC(hsync_len) | V_HORPRD(hsync_len + hback_porch + hactive + hfront_porch),
@@ -185,7 +215,7 @@ void rkvop_mode_set(struct rk3288_vop *regs,
node within the VOP's 'port' list.
- @return 0 if OK, -ve if something went wrong
*/ -int rk_display_init(struct udevice *dev, ulong fbbase, int ep_node) +static int rk_display_init(struct udevice *dev, ulong fbbase, int ep_node) { struct video_priv *uc_priv = dev_get_uclass_priv(dev); const void *blob = gd->fdt_blob; @@ -255,18 +285,18 @@ int rk_display_init(struct udevice *dev, ulong fbbase, int ep_node) /* Set bitwidth for vop display according to vop mode */ switch (vop_id) { case VOP_MODE_EDP:
case VOP_MODE_HDMI: case VOP_MODE_LVDS: l2bpp = VIDEO_BPP16; break;
case VOP_MODE_HDMI: case VOP_MODE_MIPI: l2bpp = VIDEO_BPP32; break; default: l2bpp = VIDEO_BPP16; }
rkvop_mode_set(regs, &timing, vop_id);
rkvop_mode_set(dev, &timing, vop_id); rkvop_enable(regs, fbbase, 1 << l2bpp, &timing); ret = display_enable(disp, 1 << l2bpp, &timing);
@@ -281,53 +311,37 @@ int rk_display_init(struct udevice *dev, ulong fbbase, int ep_node) return 0; }
-static int rk_vop_probe(struct udevice *dev) +void rk_vop_probe_regulators(struct udevice *dev,
const char * const *names, int cnt)
+{
int i, ret;
const char *name;
struct udevice *reg;
for (i = 0; i < cnt; ++i) {
name = names[i];
debug("%s: probing regulator '%s'\n", dev->name, name);
ret = regulator_autoset_by_name(name, ®);
if (!ret)
ret = regulator_set_enable(reg, true);
}
+}
+int rk_vop_probe(struct udevice *dev) { struct video_uc_platdata *plat = dev_get_uclass_platdata(dev); const void *blob = gd->fdt_blob; struct rk_vop_priv *priv = dev_get_priv(dev);
struct udevice *reg;
int ret, port, node;
int ret = 0;
int port, node; /* Before relocation we don't need to do anything */ if (!(gd->flags & GD_FLG_RELOC)) return 0;
priv->grf = syscon_get_first_range(ROCKCHIP_SYSCON_GRF); priv->regs = (struct rk3288_vop *)dev_get_addr(dev);
/* lcdc(vop) iodomain select 1.8V */
rk_setreg(&priv->grf->io_vsel, 1 << 0);
/*
* Try some common regulators. We should really get these from the
* device tree somehow.
*/
ret = regulator_autoset_by_name("vcc18_lcd", ®);
if (ret)
debug("%s: Cannot autoset regulator vcc18_lcd\n", __func__);
ret = regulator_autoset_by_name("VCC18_LCD", ®);
if (ret)
debug("%s: Cannot autoset regulator VCC18_LCD\n", __func__);
ret = regulator_autoset_by_name("vdd10_lcd_pwren_h", ®);
if (ret) {
debug("%s: Cannot autoset regulator vdd10_lcd_pwren_h\n",
__func__);
}
ret = regulator_autoset_by_name("vdd10_lcd", ®);
if (ret) {
debug("%s: Cannot autoset regulator vdd10_lcd\n",
__func__);
}
ret = regulator_autoset_by_name("VDD10_LCD", ®);
if (ret) {
debug("%s: Cannot autoset regulator VDD10_LCD\n",
__func__);
}
ret = regulator_autoset_by_name("vcc33_lcd", ®);
if (ret)
debug("%s: Cannot autoset regulator vcc33_lcd\n", __func__);
/* * Try all the ports until we find one that works. In practice this * tries EDP first if available, then HDMI.
@@ -353,31 +367,12 @@ static int rk_vop_probe(struct udevice *dev) return ret; }
-static int rk_vop_bind(struct udevice *dev) +int rk_vop_bind(struct udevice *dev) { struct video_uc_platdata *plat = dev_get_uclass_platdata(dev);
plat->size = 1920 * 1200 * 4;
plat->size = 4 * (CONFIG_VIDEO_ROCKCHIP_MAX_XRES *
CONFIG_VIDEO_ROCKCHIP_MAX_YRES); return 0;
}
-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" },
{ }
-};
-U_BOOT_DRIVER(rk_vop) = {
.name = "rk_vop",
.id = UCLASS_VIDEO,
.of_match = rk_vop_ids,
.ops = &rk_vop_ops,
.bind = rk_vop_bind,
.probe = rk_vop_probe,
.priv_auto_alloc_size = sizeof(struct rk_vop_priv),
-}; diff --git a/drivers/video/rockchip/rk_vop.h b/drivers/video/rockchip/rk_vop.h new file mode 100644 index 0000000..f65ac17 --- /dev/null +++ b/drivers/video/rockchip/rk_vop.h @@ -0,0 +1,32 @@ +/*
- Copyright (c) 2017 Theobroma Systems Design und Consulting GmbH
- SPDX-License-Identifier: GPL-2.0+
- */
+#ifndef __RK_VOP_H__ +#define __RK_VOP_H__
+#include <asm/arch/vop_rk3288.h>
+struct rk_vop_priv {
void *regs;
+};
+enum vop_features {
VOP_FEATURE_OUTPUT_10BIT = (1 << 0),
+};
+struct rkvop_driverdata {
/* configuration */
u32 features;
/* block-specific setters/getters */
void (*set_pin_polarity)(struct udevice *, enum vop_modes, u32);
+};
+int rk_vop_probe(struct udevice *dev); +int rk_vop_bind(struct udevice *dev); +void rk_vop_probe_regulators(struct udevice *dev,
const char * const *names, int cnt);
Please add function comments.
+#endif
1.9.1
Regards, Simon

This commit enables the RK3399 HDMI TX, which is very similar to the one found on the RK3288. As requested by Simon, this splits the HDMI driver into a SOC-specific portion (rk3399_hdmi.c, rk3288_hdmi.c) and a common portion (rk_hdmi.c).
Note that the I2C communication for reading the EDID works well with the default settings, but does not with the alternate settings used on the RK3288... so this configuration aspect also is part of the driverdata.
Having some sort of DTS-based configuration for the regulator dependencies would be nice for the future, but for now we simply use lists of regulator names (also via driverdata) that we probe.
Signed-off-by: Philipp Tomsich philipp.tomsich@theobroma-systems.com ---
Changes in v3: - split into separate drivers for the SOC-specific portion of the driver - rebase to sjg/next
Changes in v2: - removed DEBUG from the patch (as was done in our production branches, but missing from the patch-prep branch) - updated SJG's comment (with a TODO for the RK3288) to reflect the new code structure
arch/arm/include/asm/arch-rockchip/grf_rk3399.h | 3 + drivers/video/rockchip/Makefile | 4 +- drivers/video/rockchip/rk3288_hdmi.c | 116 ++++++++++++++++++++++++ drivers/video/rockchip/rk3399_hdmi.c | 81 +++++++++++++++++ drivers/video/rockchip/rk_hdmi.c | 114 +++++------------------ drivers/video/rockchip/rk_hdmi.h | 32 +++++++ 6 files changed, 260 insertions(+), 90 deletions(-) create mode 100644 drivers/video/rockchip/rk3288_hdmi.c create mode 100644 drivers/video/rockchip/rk3399_hdmi.c create mode 100644 drivers/video/rockchip/rk_hdmi.h
diff --git a/arch/arm/include/asm/arch-rockchip/grf_rk3399.h b/arch/arm/include/asm/arch-rockchip/grf_rk3399.h index eda9956..8d21eb7 100644 --- a/arch/arm/include/asm/arch-rockchip/grf_rk3399.h +++ b/arch/arm/include/asm/arch-rockchip/grf_rk3399.h @@ -534,6 +534,9 @@ enum { GRF_DSI0_VOP_SEL_MASK = 1 << GRF_DSI0_VOP_SEL_SHIFT, GRF_DSI0_VOP_SEL_B = 0, GRF_DSI0_VOP_SEL_L = 1, + GRF_RK3399_HDMI_VOP_SEL_MASK = 1 << 6, + GRF_RK3399_HDMI_VOP_SEL_B = 0 << 6, + GRF_RK3399_HDMI_VOP_SEL_L = 1 << 6,
/* GRF_SOC_CON22 */ GRF_DPHY_TX0_RXMODE_SHIFT = 0, diff --git a/drivers/video/rockchip/Makefile b/drivers/video/rockchip/Makefile index 495d5f7..872dc0f 100644 --- a/drivers/video/rockchip/Makefile +++ b/drivers/video/rockchip/Makefile @@ -11,6 +11,8 @@ obj-$(CONFIG_ROCKCHIP_RK3288) += rk3288_vop.o obj-$(CONFIG_ROCKCHIP_RK3399) += rk3399_vop.o obj-$(CONFIG_DISPLAY_ROCKCHIP_EDP) += rk_edp.o obj-$(CONFIG_DISPLAY_ROCKCHIP_LVDS) += rk_lvds.o -obj-$(CONFIG_DISPLAY_ROCKCHIP_HDMI) += rk_hdmi.o +obj-hdmi-$(CONFIG_ROCKCHIP_RK3288) += rk3288_hdmi.o +obj-hdmi-$(CONFIG_ROCKCHIP_RK3399) += rk3399_hdmi.o +obj-$(CONFIG_DISPLAY_ROCKCHIP_HDMI) += rk_hdmi.o $(obj-hdmi-y) obj-$(CONFIG_DISPLAY_ROCKCHIP_MIPI) += rk_mipi.o endif diff --git a/drivers/video/rockchip/rk3288_hdmi.c b/drivers/video/rockchip/rk3288_hdmi.c new file mode 100644 index 0000000..eae0dd2 --- /dev/null +++ b/drivers/video/rockchip/rk3288_hdmi.c @@ -0,0 +1,116 @@ +/* + * Copyright (c) 2017 Theobroma Systems Design und Consulting GmbH + * + * SPDX-License-Identifier: GPL-2.0+ + */ + +#include <common.h> +#include <clk.h> +#include <display.h> +#include <dm.h> +#include <dw_hdmi.h> +#include <edid.h> +#include <regmap.h> +#include <syscon.h> +#include <asm/gpio.h> +#include <asm/io.h> +#include <asm/arch/clock.h> +#include <asm/arch/hardware.h> +#include <asm/arch/grf_rk3288.h> +#include <power/regulator.h> +#include "rk_hdmi.h" + +static int rk3288_hdmi_enable(struct udevice *dev, int panel_bpp, + const struct display_timing *edid) +{ + struct rk_hdmi_priv *priv = dev_get_priv(dev); + struct display_plat *uc_plat = dev_get_uclass_platdata(dev); + int vop_id = uc_plat->source_id; + struct rk3288_grf *grf = priv->grf; + + /* hdmi source select hdmi controller */ + rk_setreg(&grf->soc_con6, 1 << 15); + + /* hdmi data from vop id */ + rk_clrsetreg(&grf->soc_con6, 1 << 4, (vop_id == 1) ? (1 << 4) : 0); + + return 0; +} + +static int rk3288_hdmi_ofdata_to_platdata(struct udevice *dev) +{ + struct rk_hdmi_priv *priv = dev_get_priv(dev); + struct dw_hdmi *hdmi = &priv->hdmi; + + hdmi->i2c_clk_high = 0x7a; + hdmi->i2c_clk_low = 0x8d; + + /* + * TODO(sjg@chromium.org): The above values don't work - these + * ones work better, but generate lots of errors in the data. + */ + hdmi->i2c_clk_high = 0x0d; + hdmi->i2c_clk_low = 0x0d; + + return rk_hdmi_ofdata_to_platdata(dev); +} + +static int rk3288_clk_config(struct udevice *dev) +{ + struct display_plat *uc_plat = dev_get_uclass_platdata(dev); + struct clk clk; + int ret; + + /* + * Configure the maximum clock to permit whatever resolution the + * monitor wants + */ + ret = clk_get_by_index(uc_plat->src_dev, 0, &clk); + if (ret >= 0) { + ret = clk_set_rate(&clk, 384000000); + clk_free(&clk); + } + if (ret < 0) { + debug("%s: Failed to set clock in source device '%s': ret=%d\n", + __func__, uc_plat->src_dev->name, ret); + return ret; + } + + return 0; +} + +static const char * const rk3288_regulator_names[] = { + "vcc50_hdmi" +}; + +static int rk3288_hdmi_probe(struct udevice *dev) +{ + /* Enable VOP clock for RK3288 */ + rk3288_clk_config(dev); + + /* Enable regulators required for HDMI */ + rk_hdmi_probe_regulators(dev, rk3288_regulator_names, + ARRAY_SIZE(rk3288_regulator_names)); + + return rk_hdmi_probe(dev); +} + +static const struct dm_display_ops rk3288_hdmi_ops = { + .read_edid = rk_hdmi_read_edid, + .enable = rk3288_hdmi_enable, +}; + +static const struct udevice_id rk3288_hdmi_ids[] = { + { .compatible = "rockchip,rk3288-dw-hdmi" }, + { } +}; + +U_BOOT_DRIVER(rk3288_hdmi_rockchip) = { + .name = "rk3288_hdmi_rockchip", + .id = UCLASS_DISPLAY, + .of_match = rk3288_hdmi_ids, + .ops = &rk3288_hdmi_ops, + .ofdata_to_platdata = rk3288_hdmi_ofdata_to_platdata, + .probe = rk3288_hdmi_probe, + .priv_auto_alloc_size = sizeof(struct rk_hdmi_priv), +}; diff --git a/drivers/video/rockchip/rk3399_hdmi.c b/drivers/video/rockchip/rk3399_hdmi.c new file mode 100644 index 0000000..b1e5097 --- /dev/null +++ b/drivers/video/rockchip/rk3399_hdmi.c @@ -0,0 +1,81 @@ +/* + * Copyright (c) 2017 Theobroma Systems Design und Consulting GmbH + * + * SPDX-License-Identifier: GPL-2.0+ + */ + +#include <common.h> +#include <clk.h> +#include <display.h> +#include <dm.h> +#include <dw_hdmi.h> +#include <edid.h> +#include <regmap.h> +#include <syscon.h> +#include <asm/gpio.h> +#include <asm/io.h> +#include <asm/arch/clock.h> +#include <asm/arch/hardware.h> +#include <asm/arch/grf_rk3399.h> +#include <power/regulator.h> +#include "rk_hdmi.h" + +static int rk3399_hdmi_enable(struct udevice *dev, int panel_bpp, + const struct display_timing *edid) +{ + struct rk_hdmi_priv *priv = dev_get_priv(dev); + struct display_plat *uc_plat = dev_get_uclass_platdata(dev); + int vop_id = uc_plat->source_id; + struct rk3399_grf_regs *grf = priv->grf; + + /* select the hdmi encoder input data from our source_id */ + rk_clrsetreg(&grf->soc_con20, GRF_RK3399_HDMI_VOP_SEL_MASK, + (vop_id == 1) ? GRF_RK3399_HDMI_VOP_SEL_L : 0); + + return dw_hdmi_enable(&priv->hdmi, edid); +} + +static int rk3399_hdmi_ofdata_to_platdata(struct udevice *dev) +{ + struct rk_hdmi_priv *priv = dev_get_priv(dev); + struct dw_hdmi *hdmi = &priv->hdmi; + + hdmi->i2c_clk_high = 0x7a; + hdmi->i2c_clk_low = 0x8d; + + return rk_hdmi_ofdata_to_platdata(dev); +} + +static const char * const rk3399_regulator_names[] = { + "vcc1v8_hdmi", + "vcc0v9_hdmi" +}; + +static int rk3399_hdmi_probe(struct udevice *dev) +{ + /* Enable regulators required for HDMI */ + rk_hdmi_probe_regulators(dev, rk3399_regulator_names, + ARRAY_SIZE(rk3399_regulator_names)); + + return rk_hdmi_probe(dev); +} + +static const struct dm_display_ops rk3399_hdmi_ops = { + .read_edid = rk_hdmi_read_edid, + .enable = rk3399_hdmi_enable, +}; + +static const struct udevice_id rk3399_hdmi_ids[] = { + { .compatible = "rockchip,rk3399-dw-hdmi" }, + { } +}; + +U_BOOT_DRIVER(rk3399_hdmi_rockchip) = { + .name = "rk3399_hdmi_rockchip", + .id = UCLASS_DISPLAY, + .of_match = rk3399_hdmi_ids, + .ops = &rk3399_hdmi_ops, + .ofdata_to_platdata = rk3399_hdmi_ofdata_to_platdata, + .probe = rk3399_hdmi_probe, + .priv_auto_alloc_size = sizeof(struct rk_hdmi_priv), +}; diff --git a/drivers/video/rockchip/rk_hdmi.c b/drivers/video/rockchip/rk_hdmi.c index db07588..25f84a7 100644 --- a/drivers/video/rockchip/rk_hdmi.c +++ b/drivers/video/rockchip/rk_hdmi.c @@ -1,4 +1,5 @@ /* + * Copyright (c) 2017 Theobroma Systems Design und Consulting GmbH * Copyright (c) 2015 Google, Inc * Copyright 2014 Rockchip Inc. * @@ -16,13 +17,9 @@ #include <asm/gpio.h> #include <asm/io.h> #include <asm/arch/clock.h> -#include <asm/arch/grf_rk3288.h> -#include <power/regulator.h> - -struct rk_hdmi_priv { - struct dw_hdmi hdmi; - struct rk3288_grf *grf; -}; +#include <asm/arch/hardware.h> +#include "rk_hdmi.h" +#include "rk_vop.h" /* for rk_vop_probe_regulators */
static const struct hdmi_phy_config rockchip_phy_config[] = { { @@ -35,6 +32,9 @@ static const struct hdmi_phy_config rockchip_phy_config[] = { .mpixelclock = 297000000, .sym_ctr = 0x8039, .term = 0x0005, .vlev_ctr = 0x028d, }, { + .mpixelclock = 584000000, + .sym_ctr = 0x8039, .term = 0x0000, .vlev_ctr = 0x019d, + }, { .mpixelclock = ~0ul, .sym_ctr = 0x0000, .term = 0x0000, .vlev_ctr = 0x0000, } @@ -60,27 +60,25 @@ static const struct hdmi_mpll_config rockchip_mpll_cfg[] = { .mpixelclock = 148500000, .cpce = 0x0051, .gmp = 0x0003, .curr = 0x0000, }, { + .mpixelclock = 272000000, + .cpce = 0x0040, .gmp = 0x0003, .curr = 0x0000, + }, { + .mpixelclock = 340000000, + .cpce = 0x0040, .gmp = 0x0003, .curr = 0x0000, + }, { .mpixelclock = ~0ul, .cpce = 0x0051, .gmp = 0x0003, .curr = 0x0000, } };
-static int rk_hdmi_read_edid(struct udevice *dev, u8 *buf, int buf_size) +int rk_hdmi_read_edid(struct udevice *dev, u8 *buf, int buf_size) { struct rk_hdmi_priv *priv = dev_get_priv(dev);
return dw_hdmi_read_edid(&priv->hdmi, buf, buf_size); }
-static int rk_hdmi_enable(struct udevice *dev, int panel_bpp, - const struct display_timing *edid) -{ - struct rk_hdmi_priv *priv = dev_get_priv(dev); - - return dw_hdmi_enable(&priv->hdmi, edid); -} - -static int rk_hdmi_ofdata_to_platdata(struct udevice *dev) +int rk_hdmi_ofdata_to_platdata(struct udevice *dev) { struct rk_hdmi_priv *priv = dev_get_priv(dev); struct dw_hdmi *hdmi = &priv->hdmi; @@ -88,15 +86,9 @@ static int rk_hdmi_ofdata_to_platdata(struct udevice *dev) hdmi->ioaddr = (ulong)dev_get_addr(dev); hdmi->mpll_cfg = rockchip_mpll_cfg; hdmi->phy_cfg = rockchip_phy_config; - hdmi->i2c_clk_high = 0x7a; - hdmi->i2c_clk_low = 0x8d; - - /* - * TODO(sjg@chromium.org): The above values don't work - these ones - * work better, but generate lots of errors in the data. - */ - hdmi->i2c_clk_high = 0x0d; - hdmi->i2c_clk_low = 0x0d; + + /* hdmi->i2c_clk_{high,low} are set up by the SoC driver */ + hdmi->reg_io_width = 4; hdmi->phy_set = dw_hdmi_phy_cfg;
@@ -105,53 +97,17 @@ static int rk_hdmi_ofdata_to_platdata(struct udevice *dev) return 0; }
-static int rk_hdmi_probe(struct udevice *dev) +void rk_hdmi_probe_regulators(struct udevice *dev, + const char * const *names, int cnt) +{ + rk_vop_probe_regulators(dev, names, cnt); +} + +int rk_hdmi_probe(struct udevice *dev) { - struct display_plat *uc_plat = dev_get_uclass_platdata(dev); struct rk_hdmi_priv *priv = dev_get_priv(dev); struct dw_hdmi *hdmi = &priv->hdmi; - struct udevice *reg; - struct clk clk; int ret; - int vop_id = uc_plat->source_id; - - ret = clk_get_by_index(dev, 0, &clk); - if (ret >= 0) { - ret = clk_set_rate(&clk, 0); - clk_free(&clk); - } - if (ret) { - debug("%s: Failed to set hdmi clock: ret=%d\n", __func__, ret); - return ret; - } - - /* - * Configure the maximum clock to permit whatever resolution the - * monitor wants - */ - ret = clk_get_by_index(uc_plat->src_dev, 0, &clk); - if (ret >= 0) { - ret = clk_set_rate(&clk, 384000000); - clk_free(&clk); - } - if (ret < 0) { - debug("%s: Failed to set clock in source device '%s': ret=%d\n", - __func__, uc_plat->src_dev->name, ret); - return ret; - } - - ret = regulator_get_by_platname("vcc50_hdmi", ®); - if (!ret) - ret = regulator_set_enable(reg, true); - if (ret) - debug("%s: Cannot set regulator vcc50_hdmi\n", __func__); - - /* hdmi source select hdmi controller */ - rk_setreg(&priv->grf->soc_con6, 1 << 15); - - /* hdmi data from vop id */ - rk_clrsetreg(&priv->grf->soc_con6, 1 << 4, - (vop_id == 1) ? (1 << 4) : 0);
ret = dw_hdmi_phy_wait_for_hpd(hdmi); if (ret < 0) { @@ -164,23 +120,3 @@ static int rk_hdmi_probe(struct udevice *dev)
return 0; } - -static const struct dm_display_ops rk_hdmi_ops = { - .read_edid = rk_hdmi_read_edid, - .enable = rk_hdmi_enable, -}; - -static const struct udevice_id rk_hdmi_ids[] = { - { .compatible = "rockchip,rk3288-dw-hdmi" }, - { } -}; - -U_BOOT_DRIVER(hdmi_rockchip) = { - .name = "hdmi_rockchip", - .id = UCLASS_DISPLAY, - .of_match = rk_hdmi_ids, - .ops = &rk_hdmi_ops, - .ofdata_to_platdata = rk_hdmi_ofdata_to_platdata, - .probe = rk_hdmi_probe, - .priv_auto_alloc_size = sizeof(struct rk_hdmi_priv), -}; diff --git a/drivers/video/rockchip/rk_hdmi.h b/drivers/video/rockchip/rk_hdmi.h new file mode 100644 index 0000000..501ed3a --- /dev/null +++ b/drivers/video/rockchip/rk_hdmi.h @@ -0,0 +1,32 @@ +/* + * Copyright (c) 2017 Theobroma Systems Design und Consulting GmbH + * + * SPDX-License-Identifier: GPL-2.0+ + */ + +#ifndef __RK_HDMI_H__ +#define __RK_HDMI_H__ + +struct rkhdmi_driverdata { + /* configuration */ + u8 i2c_clk_high; + u8 i2c_clk_low; + const char * const *regulator_names; + u32 regulator_names_cnt; + /* setters/getters */ + int (*set_input_vop)(struct udevice *dev); + int (*clk_config)(struct udevice *dev); +}; + +struct rk_hdmi_priv { + struct dw_hdmi hdmi; + void *grf; +}; + +int rk_hdmi_read_edid(struct udevice *dev, u8 *buf, int buf_size); +void rk_hdmi_probe_regulators(struct udevice *dev, + const char * const *names, int cnt); +int rk_hdmi_ofdata_to_platdata(struct udevice *dev); +int rk_hdmi_probe(struct udevice *dev); + +#endif

Hi Philipp,
On 5 May 2017 at 13:48, Philipp Tomsich philipp.tomsich@theobroma-systems.com wrote:
This commit enables the RK3399 HDMI TX, which is very similar to the one found on the RK3288. As requested by Simon, this splits the HDMI driver into a SOC-specific portion (rk3399_hdmi.c, rk3288_hdmi.c) and a common portion (rk_hdmi.c).
Note that the I2C communication for reading the EDID works well with the default settings, but does not with the alternate settings used on the RK3288... so this configuration aspect also is part of the driverdata.
Having some sort of DTS-based configuration for the regulator dependencies would be nice for the future, but for now we simply use lists of regulator names (also via driverdata) that we probe.
Signed-off-by: Philipp Tomsich philipp.tomsich@theobroma-systems.com
Changes in v3:
- split into separate drivers for the SOC-specific portion of the driver
- rebase to sjg/next
Changes in v2:
- removed DEBUG from the patch (as was done in our production branches, but missing from the patch-prep branch)
- updated SJG's comment (with a TODO for the RK3288) to reflect the new code structure
arch/arm/include/asm/arch-rockchip/grf_rk3399.h | 3 + drivers/video/rockchip/Makefile | 4 +- drivers/video/rockchip/rk3288_hdmi.c | 116 ++++++++++++++++++++++++ drivers/video/rockchip/rk3399_hdmi.c | 81 +++++++++++++++++ drivers/video/rockchip/rk_hdmi.c | 114 +++++------------------ drivers/video/rockchip/rk_hdmi.h | 32 +++++++ 6 files changed, 260 insertions(+), 90 deletions(-) create mode 100644 drivers/video/rockchip/rk3288_hdmi.c create mode 100644 drivers/video/rockchip/rk3399_hdmi.c create mode 100644 drivers/video/rockchip/rk_hdmi.h
Again this patch does too much. Please can you split out the refactor (moving the rk3288 code into its own file) from the patch that adds the new feature?
diff --git a/arch/arm/include/asm/arch-rockchip/grf_rk3399.h b/arch/arm/include/asm/arch-rockchip/grf_rk3399.h index eda9956..8d21eb7 100644 --- a/arch/arm/include/asm/arch-rockchip/grf_rk3399.h +++ b/arch/arm/include/asm/arch-rockchip/grf_rk3399.h @@ -534,6 +534,9 @@ enum { GRF_DSI0_VOP_SEL_MASK = 1 << GRF_DSI0_VOP_SEL_SHIFT, GRF_DSI0_VOP_SEL_B = 0, GRF_DSI0_VOP_SEL_L = 1,
GRF_RK3399_HDMI_VOP_SEL_MASK = 1 << 6,
GRF_RK3399_HDMI_VOP_SEL_B = 0 << 6,
GRF_RK3399_HDMI_VOP_SEL_L = 1 << 6, /* GRF_SOC_CON22 */ GRF_DPHY_TX0_RXMODE_SHIFT = 0,
diff --git a/drivers/video/rockchip/Makefile b/drivers/video/rockchip/Makefile index 495d5f7..872dc0f 100644 --- a/drivers/video/rockchip/Makefile +++ b/drivers/video/rockchip/Makefile @@ -11,6 +11,8 @@ obj-$(CONFIG_ROCKCHIP_RK3288) += rk3288_vop.o obj-$(CONFIG_ROCKCHIP_RK3399) += rk3399_vop.o obj-$(CONFIG_DISPLAY_ROCKCHIP_EDP) += rk_edp.o obj-$(CONFIG_DISPLAY_ROCKCHIP_LVDS) += rk_lvds.o -obj-$(CONFIG_DISPLAY_ROCKCHIP_HDMI) += rk_hdmi.o +obj-hdmi-$(CONFIG_ROCKCHIP_RK3288) += rk3288_hdmi.o +obj-hdmi-$(CONFIG_ROCKCHIP_RK3399) += rk3399_hdmi.o +obj-$(CONFIG_DISPLAY_ROCKCHIP_HDMI) += rk_hdmi.o $(obj-hdmi-y) obj-$(CONFIG_DISPLAY_ROCKCHIP_MIPI) += rk_mipi.o endif diff --git a/drivers/video/rockchip/rk3288_hdmi.c b/drivers/video/rockchip/rk3288_hdmi.c new file mode 100644 index 0000000..eae0dd2 --- /dev/null +++ b/drivers/video/rockchip/rk3288_hdmi.c @@ -0,0 +1,116 @@ +/*
- Copyright (c) 2017 Theobroma Systems Design und Consulting GmbH
- SPDX-License-Identifier: GPL-2.0+
- */
+#include <common.h> +#include <clk.h> +#include <display.h> +#include <dm.h> +#include <dw_hdmi.h> +#include <edid.h> +#include <regmap.h> +#include <syscon.h> +#include <asm/gpio.h> +#include <asm/io.h> +#include <asm/arch/clock.h> +#include <asm/arch/hardware.h> +#include <asm/arch/grf_rk3288.h> +#include <power/regulator.h> +#include "rk_hdmi.h"
We may need all these headers but please drop anything that are not needed.
+static int rk3288_hdmi_enable(struct udevice *dev, int panel_bpp,
const struct display_timing *edid)
+{
struct rk_hdmi_priv *priv = dev_get_priv(dev);
struct display_plat *uc_plat = dev_get_uclass_platdata(dev);
int vop_id = uc_plat->source_id;
struct rk3288_grf *grf = priv->grf;
/* hdmi source select hdmi controller */
rk_setreg(&grf->soc_con6, 1 << 15);
/* hdmi data from vop id */
rk_clrsetreg(&grf->soc_con6, 1 << 4, (vop_id == 1) ? (1 << 4) : 0);
return 0;
+}
+static int rk3288_hdmi_ofdata_to_platdata(struct udevice *dev) +{
struct rk_hdmi_priv *priv = dev_get_priv(dev);
struct dw_hdmi *hdmi = &priv->hdmi;
hdmi->i2c_clk_high = 0x7a;
hdmi->i2c_clk_low = 0x8d;
/*
* TODO(sjg@chromium.org): The above values don't work - these
* ones work better, but generate lots of errors in the data.
*/
hdmi->i2c_clk_high = 0x0d;
hdmi->i2c_clk_low = 0x0d;
return rk_hdmi_ofdata_to_platdata(dev);
+}
+static int rk3288_clk_config(struct udevice *dev) +{
struct display_plat *uc_plat = dev_get_uclass_platdata(dev);
struct clk clk;
int ret;
/*
* Configure the maximum clock to permit whatever resolution the
* monitor wants
*/
ret = clk_get_by_index(uc_plat->src_dev, 0, &clk);
if (ret >= 0) {
ret = clk_set_rate(&clk, 384000000);
clk_free(&clk);
}
if (ret < 0) {
debug("%s: Failed to set clock in source device '%s': ret=%d\n",
__func__, uc_plat->src_dev->name, ret);
return ret;
}
return 0;
+}
+static const char * const rk3288_regulator_names[] = {
"vcc50_hdmi"
+};
+static int rk3288_hdmi_probe(struct udevice *dev) +{
/* Enable VOP clock for RK3288 */
rk3288_clk_config(dev);
/* Enable regulators required for HDMI */
rk_hdmi_probe_regulators(dev, rk3288_regulator_names,
ARRAY_SIZE(rk3288_regulator_names));
return rk_hdmi_probe(dev);
+}
+static const struct dm_display_ops rk3288_hdmi_ops = {
.read_edid = rk_hdmi_read_edid,
.enable = rk3288_hdmi_enable,
+};
+static const struct udevice_id rk3288_hdmi_ids[] = {
{ .compatible = "rockchip,rk3288-dw-hdmi" },
{ }
+};
+U_BOOT_DRIVER(rk3288_hdmi_rockchip) = {
.name = "rk3288_hdmi_rockchip",
.id = UCLASS_DISPLAY,
.of_match = rk3288_hdmi_ids,
.ops = &rk3288_hdmi_ops,
.ofdata_to_platdata = rk3288_hdmi_ofdata_to_platdata,
.probe = rk3288_hdmi_probe,
.priv_auto_alloc_size = sizeof(struct rk_hdmi_priv),
+}; diff --git a/drivers/video/rockchip/rk3399_hdmi.c b/drivers/video/rockchip/rk3399_hdmi.c new file mode 100644 index 0000000..b1e5097 --- /dev/null +++ b/drivers/video/rockchip/rk3399_hdmi.c @@ -0,0 +1,81 @@ +/*
- Copyright (c) 2017 Theobroma Systems Design und Consulting GmbH
- SPDX-License-Identifier: GPL-2.0+
- */
+#include <common.h> +#include <clk.h> +#include <display.h> +#include <dm.h> +#include <dw_hdmi.h> +#include <edid.h> +#include <regmap.h> +#include <syscon.h> +#include <asm/gpio.h> +#include <asm/io.h> +#include <asm/arch/clock.h> +#include <asm/arch/hardware.h> +#include <asm/arch/grf_rk3399.h> +#include <power/regulator.h> +#include "rk_hdmi.h"
+static int rk3399_hdmi_enable(struct udevice *dev, int panel_bpp,
const struct display_timing *edid)
+{
struct rk_hdmi_priv *priv = dev_get_priv(dev);
struct display_plat *uc_plat = dev_get_uclass_platdata(dev);
int vop_id = uc_plat->source_id;
struct rk3399_grf_regs *grf = priv->grf;
/* select the hdmi encoder input data from our source_id */
rk_clrsetreg(&grf->soc_con20, GRF_RK3399_HDMI_VOP_SEL_MASK,
(vop_id == 1) ? GRF_RK3399_HDMI_VOP_SEL_L : 0);
return dw_hdmi_enable(&priv->hdmi, edid);
+}
+static int rk3399_hdmi_ofdata_to_platdata(struct udevice *dev) +{
struct rk_hdmi_priv *priv = dev_get_priv(dev);
struct dw_hdmi *hdmi = &priv->hdmi;
hdmi->i2c_clk_high = 0x7a;
hdmi->i2c_clk_low = 0x8d;
return rk_hdmi_ofdata_to_platdata(dev);
+}
+static const char * const rk3399_regulator_names[] = {
"vcc1v8_hdmi",
"vcc0v9_hdmi"
+};
+static int rk3399_hdmi_probe(struct udevice *dev) +{
/* Enable regulators required for HDMI */
rk_hdmi_probe_regulators(dev, rk3399_regulator_names,
ARRAY_SIZE(rk3399_regulator_names));
return rk_hdmi_probe(dev);
+}
+static const struct dm_display_ops rk3399_hdmi_ops = {
.read_edid = rk_hdmi_read_edid,
.enable = rk3399_hdmi_enable,
+};
+static const struct udevice_id rk3399_hdmi_ids[] = {
{ .compatible = "rockchip,rk3399-dw-hdmi" },
{ }
+};
+U_BOOT_DRIVER(rk3399_hdmi_rockchip) = {
.name = "rk3399_hdmi_rockchip",
.id = UCLASS_DISPLAY,
.of_match = rk3399_hdmi_ids,
.ops = &rk3399_hdmi_ops,
.ofdata_to_platdata = rk3399_hdmi_ofdata_to_platdata,
.probe = rk3399_hdmi_probe,
.priv_auto_alloc_size = sizeof(struct rk_hdmi_priv),
+}; diff --git a/drivers/video/rockchip/rk_hdmi.c b/drivers/video/rockchip/rk_hdmi.c index db07588..25f84a7 100644 --- a/drivers/video/rockchip/rk_hdmi.c +++ b/drivers/video/rockchip/rk_hdmi.c @@ -1,4 +1,5 @@ /*
- Copyright (c) 2017 Theobroma Systems Design und Consulting GmbH
- Copyright (c) 2015 Google, Inc
- Copyright 2014 Rockchip Inc.
@@ -16,13 +17,9 @@ #include <asm/gpio.h> #include <asm/io.h> #include <asm/arch/clock.h> -#include <asm/arch/grf_rk3288.h> -#include <power/regulator.h>
-struct rk_hdmi_priv {
struct dw_hdmi hdmi;
struct rk3288_grf *grf;
-}; +#include <asm/arch/hardware.h> +#include "rk_hdmi.h" +#include "rk_vop.h" /* for rk_vop_probe_regulators */
static const struct hdmi_phy_config rockchip_phy_config[] = { { @@ -35,6 +32,9 @@ static const struct hdmi_phy_config rockchip_phy_config[] = { .mpixelclock = 297000000, .sym_ctr = 0x8039, .term = 0x0005, .vlev_ctr = 0x028d, }, {
.mpixelclock = 584000000,
.sym_ctr = 0x8039, .term = 0x0000, .vlev_ctr = 0x019d,
}, { .mpixelclock = ~0ul, .sym_ctr = 0x0000, .term = 0x0000, .vlev_ctr = 0x0000, }
@@ -60,27 +60,25 @@ static const struct hdmi_mpll_config rockchip_mpll_cfg[] = { .mpixelclock = 148500000, .cpce = 0x0051, .gmp = 0x0003, .curr = 0x0000, }, {
.mpixelclock = 272000000,
.cpce = 0x0040, .gmp = 0x0003, .curr = 0x0000,
}, {
.mpixelclock = 340000000,
.cpce = 0x0040, .gmp = 0x0003, .curr = 0x0000,
}, { .mpixelclock = ~0ul, .cpce = 0x0051, .gmp = 0x0003, .curr = 0x0000, }
};
-static int rk_hdmi_read_edid(struct udevice *dev, u8 *buf, int buf_size) +int rk_hdmi_read_edid(struct udevice *dev, u8 *buf, int buf_size) { struct rk_hdmi_priv *priv = dev_get_priv(dev);
return dw_hdmi_read_edid(&priv->hdmi, buf, buf_size);
}
-static int rk_hdmi_enable(struct udevice *dev, int panel_bpp,
const struct display_timing *edid)
-{
struct rk_hdmi_priv *priv = dev_get_priv(dev);
return dw_hdmi_enable(&priv->hdmi, edid);
-}
-static int rk_hdmi_ofdata_to_platdata(struct udevice *dev) +int rk_hdmi_ofdata_to_platdata(struct udevice *dev) { struct rk_hdmi_priv *priv = dev_get_priv(dev); struct dw_hdmi *hdmi = &priv->hdmi; @@ -88,15 +86,9 @@ static int rk_hdmi_ofdata_to_platdata(struct udevice *dev) hdmi->ioaddr = (ulong)dev_get_addr(dev); hdmi->mpll_cfg = rockchip_mpll_cfg; hdmi->phy_cfg = rockchip_phy_config;
hdmi->i2c_clk_high = 0x7a;
hdmi->i2c_clk_low = 0x8d;
/*
* TODO(sjg@chromium.org): The above values don't work - these ones
* work better, but generate lots of errors in the data.
*/
hdmi->i2c_clk_high = 0x0d;
hdmi->i2c_clk_low = 0x0d;
/* hdmi->i2c_clk_{high,low} are set up by the SoC driver */
hdmi->reg_io_width = 4; hdmi->phy_set = dw_hdmi_phy_cfg;
@@ -105,53 +97,17 @@ static int rk_hdmi_ofdata_to_platdata(struct udevice *dev) return 0; }
-static int rk_hdmi_probe(struct udevice *dev) +void rk_hdmi_probe_regulators(struct udevice *dev,
const char * const *names, int cnt)
+{
rk_vop_probe_regulators(dev, names, cnt);
+}
+int rk_hdmi_probe(struct udevice *dev) {
struct display_plat *uc_plat = dev_get_uclass_platdata(dev); struct rk_hdmi_priv *priv = dev_get_priv(dev); struct dw_hdmi *hdmi = &priv->hdmi;
struct udevice *reg;
struct clk clk; int ret;
int vop_id = uc_plat->source_id;
ret = clk_get_by_index(dev, 0, &clk);
if (ret >= 0) {
ret = clk_set_rate(&clk, 0);
clk_free(&clk);
}
if (ret) {
debug("%s: Failed to set hdmi clock: ret=%d\n", __func__, ret);
return ret;
}
/*
* Configure the maximum clock to permit whatever resolution the
* monitor wants
*/
ret = clk_get_by_index(uc_plat->src_dev, 0, &clk);
if (ret >= 0) {
ret = clk_set_rate(&clk, 384000000);
clk_free(&clk);
}
if (ret < 0) {
debug("%s: Failed to set clock in source device '%s': ret=%d\n",
__func__, uc_plat->src_dev->name, ret);
return ret;
}
ret = regulator_get_by_platname("vcc50_hdmi", ®);
if (!ret)
ret = regulator_set_enable(reg, true);
if (ret)
debug("%s: Cannot set regulator vcc50_hdmi\n", __func__);
/* hdmi source select hdmi controller */
rk_setreg(&priv->grf->soc_con6, 1 << 15);
/* hdmi data from vop id */
rk_clrsetreg(&priv->grf->soc_con6, 1 << 4,
(vop_id == 1) ? (1 << 4) : 0); ret = dw_hdmi_phy_wait_for_hpd(hdmi); if (ret < 0) {
@@ -164,23 +120,3 @@ static int rk_hdmi_probe(struct udevice *dev)
return 0;
}
-static const struct dm_display_ops rk_hdmi_ops = {
.read_edid = rk_hdmi_read_edid,
.enable = rk_hdmi_enable,
-};
-static const struct udevice_id rk_hdmi_ids[] = {
{ .compatible = "rockchip,rk3288-dw-hdmi" },
{ }
-};
-U_BOOT_DRIVER(hdmi_rockchip) = {
.name = "hdmi_rockchip",
.id = UCLASS_DISPLAY,
.of_match = rk_hdmi_ids,
.ops = &rk_hdmi_ops,
.ofdata_to_platdata = rk_hdmi_ofdata_to_platdata,
.probe = rk_hdmi_probe,
.priv_auto_alloc_size = sizeof(struct rk_hdmi_priv),
-}; diff --git a/drivers/video/rockchip/rk_hdmi.h b/drivers/video/rockchip/rk_hdmi.h new file mode 100644 index 0000000..501ed3a --- /dev/null +++ b/drivers/video/rockchip/rk_hdmi.h @@ -0,0 +1,32 @@ +/*
- Copyright (c) 2017 Theobroma Systems Design und Consulting GmbH
- SPDX-License-Identifier: GPL-2.0+
- */
+#ifndef __RK_HDMI_H__ +#define __RK_HDMI_H__
/** * struct rkhdmi_driverdata - comment here * * @i2c_clk_high: what this is ...
+struct rkhdmi_driverdata {
/* configuration */
u8 i2c_clk_high;
u8 i2c_clk_low;
const char * const *regulator_names;
u32 regulator_names_cnt;
/* setters/getters */
int (*set_input_vop)(struct udevice *dev);
int (*clk_config)(struct udevice *dev);
+};
+struct rk_hdmi_priv {
struct dw_hdmi hdmi;
void *grf;
+};
+int rk_hdmi_read_edid(struct udevice *dev, u8 *buf, int buf_size); +void rk_hdmi_probe_regulators(struct udevice *dev,
const char * const *names, int cnt);
+int rk_hdmi_ofdata_to_platdata(struct udevice *dev); +int rk_hdmi_probe(struct udevice *dev);
Please add function comments
+#endif
1.9.1
Regards, Simon

This commit enables HDMI output in the DTS by adding the necessary nodes to vopl/vopb and by adding the HDMI node.
Signed-off-by: Philipp Tomsich philipp.tomsich@theobroma-systems.com
---
Changes in v3: - enable both hdmi and vopb (as both VOPs are now disabled by default)
Changes in v2: None
arch/arm/dts/rk3399-puma.dts | 9 +++++++++ arch/arm/dts/rk3399.dtsi | 39 +++++++++++++++++++++++++++++++++++++++ 2 files changed, 48 insertions(+)
diff --git a/arch/arm/dts/rk3399-puma.dts b/arch/arm/dts/rk3399-puma.dts index 312d70e..bcc8cb8 100644 --- a/arch/arm/dts/rk3399-puma.dts +++ b/arch/arm/dts/rk3399-puma.dts @@ -192,3 +192,12 @@ &spi5 { status = "okay"; }; + +&vopb { + status = "okay"; +}; + +&hdmi { + status = "okay"; +}; + diff --git a/arch/arm/dts/rk3399.dtsi b/arch/arm/dts/rk3399.dtsi index f3d3f53..7f1fc50 100644 --- a/arch/arm/dts/rk3399.dtsi +++ b/arch/arm/dts/rk3399.dtsi @@ -1419,6 +1419,11 @@ reg = <3>; remote-endpoint = <&mipi_in_vopl>; }; + + vopl_out_hdmi: endpoint@1 { + reg = <1>; + remote-endpoint = <&hdmi_in_vopl>; + }; }; };
@@ -1440,6 +1445,40 @@ reg = <3>; remote-endpoint = <&mipi_in_vopb>; }; + + vopb_out_hdmi: endpoint@1 { + reg = <1>; + remote-endpoint = <&hdmi_in_vopb>; + }; + }; + }; + + hdmi: hdmi@ff940000 { + compatible = "rockchip,rk3399-dw-hdmi"; + reg = <0x0 0xff940000 0x0 0x20000>; + reg-io-width = <4>; + rockchip,grf = <&grf>; + pinctrl-names = "default"; + pinctrl-0 = <&hdmi_i2c_xfer>; + power-domains = <&power RK3399_PD_HDCP>; + interrupts = <GIC_SPI 23 IRQ_TYPE_LEVEL_HIGH 0>; + clocks = <&cru PCLK_HDMI_CTRL>, <&cru SCLK_HDMI_SFR>, <&cru PLL_VPLL>, <&cru PCLK_VIO_GRF>; + clock-names = "iahb", "isfr", "vpll", "grf"; + status = "disabled"; + + ports { + hdmi_in: port { + #address-cells = <1>; + #size-cells = <0>; + hdmi_in_vopb: endpoint@0 { + reg = <0>; + remote-endpoint = <&vopb_out_hdmi>; + }; + hdmi_in_vopl: endpoint@1 { + reg = <1>; + remote-endpoint = <&vopl_out_hdmi>; + }; + }; }; };

Hi Philipp,
On 5 May 2017 at 13:48, Philipp Tomsich philipp.tomsich@theobroma-systems.com wrote:
This commit enables HDMI output in the DTS by adding the necessary nodes to vopl/vopb and by adding the HDMI node.
Signed-off-by: Philipp Tomsich philipp.tomsich@theobroma-systems.com
Changes in v3:
- enable both hdmi and vopb (as both VOPs are now disabled by default)
Changes in v2: None
arch/arm/dts/rk3399-puma.dts | 9 +++++++++ arch/arm/dts/rk3399.dtsi | 39 +++++++++++++++++++++++++++++++++++++++ 2 files changed, 48 insertions(+)
Acked-by: Simon Glass sjg@chromium.org
Normally would split the generic rk3399.dtsi change into its own patch, since the other one is board-specific.

Due to a typo, the 24 bit-per-pixel configuration ends in 24BMP instead of 24BPP. This change renames it throughout the source tree for consistency and to make moving these options into Kconfig easier and less error-prone.
Signed-off-by: Philipp Tomsich philipp.tomsich@theobroma-systems.com Reviewed-by: Simon Glass sjg@chromium.org Reviewed-by: Hannes Schmelzer hannes.schmelzer@br-automation.com ---
Changes in v3: None Changes in v2: - rebase to master after CMD_BMP was migrated to Kconfig - don't device CONFIG_BMP_24BPP twice in config_whitelist (apparently there had been both the _24BPP and the _24BMP whitelisted before and I didn't even spot it ... thanks go to Simon for catching this)
common/lcd.c | 4 ++-- drivers/video/video_bmp.c | 4 ++-- include/configs/brxre1.h | 2 +- scripts/config_whitelist.txt | 1 - 4 files changed, 5 insertions(+), 6 deletions(-)
diff --git a/common/lcd.c b/common/lcd.c index 783626e..2405146 100644 --- a/common/lcd.c +++ b/common/lcd.c @@ -704,7 +704,7 @@ int lcd_display_bitmap(ulong bmp_image, int x, int y) } break; #endif /* CONFIG_BMP_16BPP */ -#if defined(CONFIG_BMP_24BMP) +#if defined(CONFIG_BMP_24BPP) case 24: for (i = 0; i < height; ++i) { for (j = 0; j < width; j++) { @@ -716,7 +716,7 @@ int lcd_display_bitmap(ulong bmp_image, int x, int y) fb -= lcd_line_length + width * (bpix / 8); } break; -#endif /* CONFIG_BMP_24BMP */ +#endif /* CONFIG_BMP_24BPP */ #if defined(CONFIG_BMP_32BPP) case 32: for (i = 0; i < height; ++i) { diff --git a/drivers/video/video_bmp.c b/drivers/video/video_bmp.c index 32a4e7f..f803067 100644 --- a/drivers/video/video_bmp.c +++ b/drivers/video/video_bmp.c @@ -316,7 +316,7 @@ int video_bmp_display(struct udevice *dev, ulong bmp_image, int x, int y, } break; #endif /* CONFIG_BMP_16BPP */ -#if defined(CONFIG_BMP_24BMP) +#if defined(CONFIG_BMP_24BPP) case 24: for (i = 0; i < height; ++i) { for (j = 0; j < width; j++) { @@ -328,7 +328,7 @@ int video_bmp_display(struct udevice *dev, ulong bmp_image, int x, int y, fb -= priv->line_length + width * (bpix / 8); } break; -#endif /* CONFIG_BMP_24BMP */ +#endif /* CONFIG_BMP_24BPP */ #if defined(CONFIG_BMP_32BPP) case 32: for (i = 0; i < height; ++i) { diff --git a/include/configs/brxre1.h b/include/configs/brxre1.h index 49f223a..9984689 100644 --- a/include/configs/brxre1.h +++ b/include/configs/brxre1.h @@ -21,7 +21,7 @@
#define CONFIG_VIDEO_BMP_GZIP #define CONFIG_SYS_VIDEO_LOGO_MAX_SIZE (1366*767*4) -#define CONFIG_BMP_24BMP +#define CONFIG_BMP_24BPP #define CONFIG_BMP_32BPP
/* memory */ diff --git a/scripts/config_whitelist.txt b/scripts/config_whitelist.txt index ed349b9..558e7ec 100644 --- a/scripts/config_whitelist.txt +++ b/scripts/config_whitelist.txt @@ -236,7 +236,6 @@ CONFIG_BL1_SIZE CONFIG_BL2_OFFSET CONFIG_BL2_SIZE CONFIG_BMP_16BPP -CONFIG_BMP_24BMP CONFIG_BMP_24BPP CONFIG_BMP_32BPP CONFIG_BOARDDIR

On Fri, 5 May 2017 21:48:30 +0200 Philipp Tomsich philipp.tomsich@theobroma-systems.com wrote:
Due to a typo, the 24 bit-per-pixel configuration ends in 24BMP instead of 24BPP. This change renames it throughout the source tree for consistency and to make moving these options into Kconfig easier and less error-prone.
Signed-off-by: Philipp Tomsich philipp.tomsich@theobroma-systems.com Reviewed-by: Simon Glass sjg@chromium.org Reviewed-by: Hannes Schmelzer hannes.schmelzer@br-automation.com
Changes in v3: None Changes in v2:
- rebase to master after CMD_BMP was migrated to Kconfig
- don't device CONFIG_BMP_24BPP twice in config_whitelist (apparently there had been both the _24BPP and the _24BMP whitelisted before and I didn't even spot it ... thanks go to Simon for catching this)
common/lcd.c | 4 ++-- drivers/video/video_bmp.c | 4 ++-- include/configs/brxre1.h | 2 +- scripts/config_whitelist.txt | 1 - 4 files changed, 5 insertions(+), 6 deletions(-)
applied to u-boot-video/master, thanks!
-- Anatolij

With video output support for the RK3399-Q7 (Puma) available, we want CMD_BMP enabled and the support for 16bit, 24bit and 32bit BMPs defined.
Signed-off-by: Philipp Tomsich philipp.tomsich@theobroma-systems.com
---
Changes in v3: None Changes in v2: - enable SYS_WHITE_ON_BLACK via defconfig
configs/puma-rk3399_defconfig | 1 + include/configs/puma_rk3399.h | 4 +++- 2 files changed, 4 insertions(+), 1 deletion(-)
diff --git a/configs/puma-rk3399_defconfig b/configs/puma-rk3399_defconfig index 207445d..a8f60ae 100644 --- a/configs/puma-rk3399_defconfig +++ b/configs/puma-rk3399_defconfig @@ -47,6 +47,7 @@ CONFIG_MMC_SDHCI_ROCKCHIP=y CONFIG_SPI_FLASH=y CONFIG_SPI_FLASH_WINBOND=y CONFIG_PHY_MICREL=y +CONFIG_PHY_MICREL_KSZ9031=y CONFIG_DM_ETH=y CONFIG_ETH_DESIGNWARE=y CONFIG_GMAC_ROCKCHIP=y diff --git a/include/configs/puma_rk3399.h b/include/configs/puma_rk3399.h index 4081362..af1dae8 100644 --- a/include/configs/puma_rk3399.h +++ b/include/configs/puma_rk3399.h @@ -26,6 +26,8 @@ #define CONFIG_SERIAL_TAG #define CONFIG_ENV_OVERWRITE
-#define CONFIG_SYS_WHITE_ON_BLACK +#define CONFIG_BMP_16BPP +#define CONFIG_BMP_24BPP +#define CONFIG_BMP_32BPP
#endif

Hi Philipp,
On 5 May 2017 at 13:48, Philipp Tomsich philipp.tomsich@theobroma-systems.com wrote:
With video output support for the RK3399-Q7 (Puma) available, we want CMD_BMP enabled and the support for 16bit, 24bit and 32bit BMPs defined.
Signed-off-by: Philipp Tomsich philipp.tomsich@theobroma-systems.com
Changes in v3: None Changes in v2:
- enable SYS_WHITE_ON_BLACK via defconfig
I cannot see this in this patch.
configs/puma-rk3399_defconfig | 1 + include/configs/puma_rk3399.h | 4 +++- 2 files changed, 4 insertions(+), 1 deletion(-)
Acked-by: Simon Glass sjg@chromium.org
diff --git a/configs/puma-rk3399_defconfig b/configs/puma-rk3399_defconfig index 207445d..a8f60ae 100644 --- a/configs/puma-rk3399_defconfig +++ b/configs/puma-rk3399_defconfig @@ -47,6 +47,7 @@ CONFIG_MMC_SDHCI_ROCKCHIP=y CONFIG_SPI_FLASH=y CONFIG_SPI_FLASH_WINBOND=y CONFIG_PHY_MICREL=y +CONFIG_PHY_MICREL_KSZ9031=y CONFIG_DM_ETH=y CONFIG_ETH_DESIGNWARE=y CONFIG_GMAC_ROCKCHIP=y diff --git a/include/configs/puma_rk3399.h b/include/configs/puma_rk3399.h index 4081362..af1dae8 100644 --- a/include/configs/puma_rk3399.h +++ b/include/configs/puma_rk3399.h @@ -26,6 +26,8 @@ #define CONFIG_SERIAL_TAG #define CONFIG_ENV_OVERWRITE
-#define CONFIG_SYS_WHITE_ON_BLACK +#define CONFIG_BMP_16BPP +#define CONFIG_BMP_24BPP +#define CONFIG_BMP_32BPP
#endif
1.9.1
Regards, Simon

Changes in v3: - SYS_WHITE_ON_BLACK has been migrated to KConfig (upstream) and is on by default.
On 14 May 2017, at 11:13, Simon Glass sjg@chromium.org wrote:
Hi Philipp,
On 5 May 2017 at 13:48, Philipp Tomsich <philipp.tomsich@theobroma-systems.com mailto:philipp.tomsich@theobroma-systems.com> wrote:
With video output support for the RK3399-Q7 (Puma) available, we want CMD_BMP enabled and the support for 16bit, 24bit and 32bit BMPs defined.
Signed-off-by: Philipp Tomsich <philipp.tomsich@theobroma-systems.com mailto:philipp.tomsich@theobroma-systems.com>
Changes in v3: None Changes in v2:
- enable SYS_WHITE_ON_BLACK via defconfig
I cannot see this in this patch.
configs/puma-rk3399_defconfig | 1 + include/configs/puma_rk3399.h | 4 +++- 2 files changed, 4 insertions(+), 1 deletion(-)
Acked-by: Simon Glass <sjg@chromium.org mailto:sjg@chromium.org>
diff --git a/configs/puma-rk3399_defconfig b/configs/puma-rk3399_defconfig index 207445d..a8f60ae 100644 --- a/configs/puma-rk3399_defconfig +++ b/configs/puma-rk3399_defconfig @@ -47,6 +47,7 @@ CONFIG_MMC_SDHCI_ROCKCHIP=y CONFIG_SPI_FLASH=y CONFIG_SPI_FLASH_WINBOND=y CONFIG_PHY_MICREL=y +CONFIG_PHY_MICREL_KSZ9031=y CONFIG_DM_ETH=y CONFIG_ETH_DESIGNWARE=y CONFIG_GMAC_ROCKCHIP=y diff --git a/include/configs/puma_rk3399.h b/include/configs/puma_rk3399.h index 4081362..af1dae8 100644 --- a/include/configs/puma_rk3399.h +++ b/include/configs/puma_rk3399.h @@ -26,6 +26,8 @@ #define CONFIG_SERIAL_TAG #define CONFIG_ENV_OVERWRITE
-#define CONFIG_SYS_WHITE_ON_BLACK +#define CONFIG_BMP_16BPP +#define CONFIG_BMP_24BPP +#define CONFIG_BMP_32BPP
#endif
1.9.1
Regards, Simon

Signed-off-by: Philipp Tomsich philipp.tomsich@theobroma-systems.com
---
Changes in v3: - enable RK8XX support instead to RK808 support (rebased to sjg/next)
Changes in v2: None
configs/puma-rk3399_defconfig | 3 +++ 1 file changed, 3 insertions(+)
diff --git a/configs/puma-rk3399_defconfig b/configs/puma-rk3399_defconfig index a8f60ae..33faf1f 100644 --- a/configs/puma-rk3399_defconfig +++ b/configs/puma-rk3399_defconfig @@ -54,8 +54,11 @@ CONFIG_GMAC_ROCKCHIP=y CONFIG_PINCTRL=y CONFIG_SPL_PINCTRL=y CONFIG_PINCTRL_ROCKCHIP_RK3399=y +CONFIG_DM_PMIC=y +CONFIG_PMIC_RK8XX=y CONFIG_REGULATOR_PWM=y CONFIG_DM_REGULATOR_FIXED=y +CONFIG_REGULATOR_RK8XX=y CONFIG_PWM_ROCKCHIP=y CONFIG_RAM=y CONFIG_SPL_RAM=y

On 5 May 2017 at 13:48, Philipp Tomsich philipp.tomsich@theobroma-systems.com wrote:
Signed-off-by: Philipp Tomsich philipp.tomsich@theobroma-systems.com
Changes in v3:
- enable RK8XX support instead to RK808 support (rebased to sjg/next)
Changes in v2: None
configs/puma-rk3399_defconfig | 3 +++ 1 file changed, 3 insertions(+)
Acked-by: Simon Glass sjg@chromium.org
diff --git a/configs/puma-rk3399_defconfig b/configs/puma-rk3399_defconfig index a8f60ae..33faf1f 100644 --- a/configs/puma-rk3399_defconfig +++ b/configs/puma-rk3399_defconfig @@ -54,8 +54,11 @@ CONFIG_GMAC_ROCKCHIP=y CONFIG_PINCTRL=y CONFIG_SPL_PINCTRL=y CONFIG_PINCTRL_ROCKCHIP_RK3399=y +CONFIG_DM_PMIC=y +CONFIG_PMIC_RK8XX=y CONFIG_REGULATOR_PWM=y CONFIG_DM_REGULATOR_FIXED=y +CONFIG_REGULATOR_RK8XX=y CONFIG_PWM_ROCKCHIP=y CONFIG_RAM=y CONFIG_SPL_RAM=y -- 1.9.1

With HDMI output for the RK3399 working, this update the RK3399-Q7 (Puma) defconfig for the new functionality: 1. enables PMIC command (to check if the HDMI voltages are correct) +CONFIG_CMD_PMIC=y +CONFIG_CMD_REGULATOR=y 2. enables video-output (via HDMI) +CONFIG_DM_VIDEO=y +CONFIG_DISPLAY=y +CONFIG_VIDEO_ROCKCHIP=y +CONFIG_DISPLAY_ROCKCHIP_HDMI=y 3. turns on the 'dcache'-command (for a dcache flush) for our QA to fill the framebuffer using 'mw.l' +CONFIG_CMD_CACHE=y 4. turns on the 'bmp'-command +CONFIG_CMD_BMP=y
Signed-off-by: Philipp Tomsich philipp.tomsich@theobroma-systems.com
---
Changes in v3: None Changes in v2: - enable CMD_BMP in the puma-rk3399_defconfig (following a rebase to the upstream master after CMD_BMP was migrate to Kconfig)
configs/puma-rk3399_defconfig | 8 ++++++++ 1 file changed, 8 insertions(+)
diff --git a/configs/puma-rk3399_defconfig b/configs/puma-rk3399_defconfig index 33faf1f..b3c30a3 100644 --- a/configs/puma-rk3399_defconfig +++ b/configs/puma-rk3399_defconfig @@ -27,7 +27,11 @@ CONFIG_CMD_SPI=y CONFIG_CMD_USB=y CONFIG_CMD_USB_MASS_STORAGE=y # CONFIG_CMD_SETEXPR is not set +CONFIG_CMD_BMP=y +CONFIG_CMD_CACHE=y CONFIG_CMD_TIME=y +CONFIG_CMD_PMIC=y +CONFIG_CMD_REGULATOR=y CONFIG_SPL_OF_CONTROL=y CONFIG_OF_SPL_REMOVE_PROPS="pinctrl-0 pinctrl-names clock-names interrupt-parent assigned-clocks assigned-clock-rates assigned-clock-parents" CONFIG_REGMAP=y @@ -82,4 +86,8 @@ CONFIG_USB_GADGET_DOWNLOAD=y CONFIG_G_DNL_MANUFACTURER="Theobroma Systems" CONFIG_G_DNL_VENDOR_NUM=0x2294 CONFIG_G_DNL_PRODUCT_NUM=0x3399 +CONFIG_DM_VIDEO=y +CONFIG_DISPLAY=y +CONFIG_VIDEO_ROCKCHIP=y +CONFIG_DISPLAY_ROCKCHIP_HDMI=y CONFIG_ERRNO_STR=y

On 5 May 2017 at 13:48, Philipp Tomsich philipp.tomsich@theobroma-systems.com wrote:
With HDMI output for the RK3399 working, this update the RK3399-Q7 (Puma) defconfig for the new functionality:
- enables PMIC command (to check if the HDMI voltages are correct) +CONFIG_CMD_PMIC=y +CONFIG_CMD_REGULATOR=y
- enables video-output (via HDMI) +CONFIG_DM_VIDEO=y +CONFIG_DISPLAY=y +CONFIG_VIDEO_ROCKCHIP=y +CONFIG_DISPLAY_ROCKCHIP_HDMI=y
- turns on the 'dcache'-command (for a dcache flush) for our QA to fill the framebuffer using 'mw.l' +CONFIG_CMD_CACHE=y
- turns on the 'bmp'-command +CONFIG_CMD_BMP=y
Signed-off-by: Philipp Tomsich philipp.tomsich@theobroma-systems.com
Changes in v3: None Changes in v2:
- enable CMD_BMP in the puma-rk3399_defconfig (following a rebase to the upstream master after CMD_BMP was migrate to Kconfig)
configs/puma-rk3399_defconfig | 8 ++++++++ 1 file changed, 8 insertions(+)
Acked-by: Simon Glass sjg@chromium.org
participants (4)
-
Anatolij Gustschin
-
Dr. Philipp Tomsich
-
Philipp Tomsich
-
Simon Glass