[U-Boot] [PATCH 0/5] Add LVDS support for rk3288.

From: jacob jacob-chen@iotwrt.com
This series patches add LVDS support for rk3288. I'm a newbie in submiting patches. If there are something wrong, hope to get help.
Jacob Chen (5): dm: video: Add a operation to display uclass rockchip: video: Add a display driver for rockchip LVDS rockchip: dts: Add LVDS support rockchip: video: Add LVDS support in vop driver doc: dt-bindings: Describe rockchip LVDS interface
arch/arm/dts/rk3288.dtsi | 46 ++++- arch/arm/include/asm/arch-rockchip/lvds_rk3288.h | 99 +++++++++ arch/arm/include/asm/arch-rockchip/vop_rk3288.h | 1 + doc/device-tree-bindings/video/rockchip-lvds.txt | 77 +++++++ drivers/video/display-uclass.c | 3 + drivers/video/rockchip/Makefile | 2 +- drivers/video/rockchip/rk_lvds.c | 246 +++++++++++++++++++++++ drivers/video/rockchip/rk_vop.c | 16 +- include/display.h | 11 +- 9 files changed, 496 insertions(+), 5 deletions(-) create mode 100644 arch/arm/include/asm/arch-rockchip/lvds_rk3288.h create mode 100644 doc/device-tree-bindings/video/rockchip-lvds.txt create mode 100644 drivers/video/rockchip/rk_lvds.c

The current display class only allow to get timing from edid. So add a operation to get timing directly from driver. In driver, I will use fdtdec_decode_display_timing to get timing.
Signed-off-by: Jacob Chen jacob-chen@iotwrt.com Signed-off-by: jacob jacob-chen@iotwrt.com ---
drivers/video/display-uclass.c | 3 +++ include/display.h | 11 ++++++++++- 2 files changed, 13 insertions(+), 1 deletion(-)
diff --git a/drivers/video/display-uclass.c b/drivers/video/display-uclass.c index 31522ea..e4763de 100644 --- a/drivers/video/display-uclass.c +++ b/drivers/video/display-uclass.c @@ -36,6 +36,9 @@ int display_read_timing(struct udevice *dev, struct display_timing *timing) u8 buf[EDID_EXT_SIZE]; int ret;
+ if (ops && ops->read_timing) + return ops->read_timing(dev, timing); + if (!ops || !ops->read_edid) return -ENOSYS; ret = ops->read_edid(dev, buf, sizeof(buf)); diff --git a/include/display.h b/include/display.h index c180e76..b1c4766 100644 --- a/include/display.h +++ b/include/display.h @@ -23,7 +23,7 @@ struct display_plat { };
/** - * display_read_timing() - Read timing information from EDID + * display_read_timing() - Read timing information * * @dev: Device to read from * @return 0 if OK, -ve on error @@ -43,6 +43,15 @@ int display_enable(struct udevice *dev, int panel_bpp,
struct dm_display_ops { /** + * read_timing() - Read information directly + * + * @dev: Device to read from + * @timing: Display timings + * @return 0 if OK, -ve on error + */ + int (*read_timing)(struct udevice *dev, struct display_timing *timing); + + /** * read_edid() - Read information from EDID * * @dev: Device to read from

On 12 March 2016 at 06:13, Jacob Chen jacob-chen@iotwrt.com wrote:
The current display class only allow to get timing from edid. So add a operation to get timing directly from driver. In driver, I will use fdtdec_decode_display_timing to get timing.
Signed-off-by: Jacob Chen jacob-chen@iotwrt.com Signed-off-by: jacob jacob-chen@iotwrt.com
drivers/video/display-uclass.c | 3 +++ include/display.h | 11 ++++++++++- 2 files changed, 13 insertions(+), 1 deletion(-)
Acked-by: Simon Glass sjg@chromium.org

Some Rockchip SoCs support LVDS output. Add a display driver for this so that these displays can be used on supported boards.
Signed-off-by: Jacob Chen jacob-chen@iotwrt.com Signed-off-by: jacob jacob-chen@iotwrt.com ---
arch/arm/include/asm/arch-rockchip/lvds_rk3288.h | 99 +++++++++ drivers/video/rockchip/Makefile | 2 +- drivers/video/rockchip/rk_lvds.c | 246 +++++++++++++++++++++++ 3 files changed, 346 insertions(+), 1 deletion(-) create mode 100644 arch/arm/include/asm/arch-rockchip/lvds_rk3288.h create mode 100644 drivers/video/rockchip/rk_lvds.c
diff --git a/arch/arm/include/asm/arch-rockchip/lvds_rk3288.h b/arch/arm/include/asm/arch-rockchip/lvds_rk3288.h new file mode 100644 index 0000000..de16f3d --- /dev/null +++ b/arch/arm/include/asm/arch-rockchip/lvds_rk3288.h @@ -0,0 +1,99 @@ +/* + * Copyright 2016 Rockchip Inc. + * + * SPDX-License-Identifier: GPL-2.0+ + */ + +#ifndef _ASM_ARCH_LVDS_RK3288_H +#define _ASM_ARCH_LVDS_RK3288_H + +#define RK3288_LVDS_CH0_REG0 0x00 +#define RK3288_LVDS_CH0_REG0_LVDS_EN BIT(7) +#define RK3288_LVDS_CH0_REG0_TTL_EN BIT(6) +#define RK3288_LVDS_CH0_REG0_LANECK_EN BIT(5) +#define RK3288_LVDS_CH0_REG0_LANE4_EN BIT(4) +#define RK3288_LVDS_CH0_REG0_LANE3_EN BIT(3) +#define RK3288_LVDS_CH0_REG0_LANE2_EN BIT(2) +#define RK3288_LVDS_CH0_REG0_LANE1_EN BIT(1) +#define RK3288_LVDS_CH0_REG0_LANE0_EN BIT(0) + +#define RK3288_LVDS_CH0_REG1 0x04 +#define RK3288_LVDS_CH0_REG1_LANECK_BIAS BIT(5) +#define RK3288_LVDS_CH0_REG1_LANE4_BIAS BIT(4) +#define RK3288_LVDS_CH0_REG1_LANE3_BIAS BIT(3) +#define RK3288_LVDS_CH0_REG1_LANE2_BIAS BIT(2) +#define RK3288_LVDS_CH0_REG1_LANE1_BIAS BIT(1) +#define RK3288_LVDS_CH0_REG1_LANE0_BIAS BIT(0) + +#define RK3288_LVDS_CH0_REG2 0x08 +#define RK3288_LVDS_CH0_REG2_RESERVE_ON BIT(7) +#define RK3288_LVDS_CH0_REG2_LANECK_LVDS_MODE BIT(6) +#define RK3288_LVDS_CH0_REG2_LANE4_LVDS_MODE BIT(5) +#define RK3288_LVDS_CH0_REG2_LANE3_LVDS_MODE BIT(4) +#define RK3288_LVDS_CH0_REG2_LANE2_LVDS_MODE BIT(3) +#define RK3288_LVDS_CH0_REG2_LANE1_LVDS_MODE BIT(2) +#define RK3288_LVDS_CH0_REG2_LANE0_LVDS_MODE BIT(1) +#define RK3288_LVDS_CH0_REG2_PLL_FBDIV8 BIT(0) + +#define RK3288_LVDS_CH0_REG3 0x0c +#define RK3288_LVDS_CH0_REG3_PLL_FBDIV_MASK 0xff + +#define RK3288_LVDS_CH0_REG4 0x10 +#define RK3288_LVDS_CH0_REG4_LANECK_TTL_MODE BIT(5) +#define RK3288_LVDS_CH0_REG4_LANE4_TTL_MODE BIT(4) +#define RK3288_LVDS_CH0_REG4_LANE3_TTL_MODE BIT(3) +#define RK3288_LVDS_CH0_REG4_LANE2_TTL_MODE BIT(2) +#define RK3288_LVDS_CH0_REG4_LANE1_TTL_MODE BIT(1) +#define RK3288_LVDS_CH0_REG4_LANE0_TTL_MODE BIT(0) + +#define RK3288_LVDS_CH0_REG5 0x14 +#define RK3288_LVDS_CH0_REG5_LANECK_TTL_DATA BIT(5) +#define RK3288_LVDS_CH0_REG5_LANE4_TTL_DATA BIT(4) +#define RK3288_LVDS_CH0_REG5_LANE3_TTL_DATA BIT(3) +#define RK3288_LVDS_CH0_REG5_LANE2_TTL_DATA BIT(2) +#define RK3288_LVDS_CH0_REG5_LANE1_TTL_DATA BIT(1) +#define RK3288_LVDS_CH0_REG5_LANE0_TTL_DATA BIT(0) + +#define RK3288_LVDS_CFG_REGC 0x30 +#define RK3288_LVDS_CFG_REGC_PLL_ENABLE 0x00 +#define RK3288_LVDS_CFG_REGC_PLL_DISABLE 0xff + +#define RK3288_LVDS_CH0_REGD 0x34 +#define RK3288_LVDS_CH0_REGD_PLL_PREDIV_MASK 0x1f + +#define RK3288_LVDS_CH0_REG20 0x80 +#define RK3288_LVDS_CH0_REG20_MSB 0x45 +#define RK3288_LVDS_CH0_REG20_LSB 0x44 + +#define RK3288_LVDS_CFG_REG21 0x84 +#define RK3288_LVDS_CFG_REG21_TX_ENABLE 0x92 +#define RK3288_LVDS_CFG_REG21_TX_DISABLE 0x00 + +/* fbdiv value is split over 2 registers, with bit8 in reg2 */ +#define RK3288_LVDS_PLL_FBDIV_REG2(_fbd) \ + (_fbd & BIT(8) ? RK3288_LVDS_CH0_REG2_PLL_FBDIV8 : 0) +#define RK3288_LVDS_PLL_FBDIV_REG3(_fbd) \ + (_fbd & RK3288_LVDS_CH0_REG3_PLL_FBDIV_MASK) +#define RK3288_LVDS_PLL_PREDIV_REGD(_pd) \ + (_pd & RK3288_LVDS_CH0_REGD_PLL_PREDIV_MASK) + +#define RK3288_LVDS_SOC_CON6_SEL_VOP_LIT BIT(3) + +#define LVDS_FMT_MASK (0x07 << 16) +#define LVDS_MSB (0x01 << 3) +#define LVDS_DUAL (0x01 << 4) +#define LVDS_FMT_1 (0x01 << 5) +#define LVDS_TTL_EN (0x01 << 6) +#define LVDS_START_PHASE_RST_1 (0x01 << 7) +#define LVDS_DCLK_INV (0x01 << 8) +#define LVDS_CH0_EN (0x01 << 11) +#define LVDS_CH1_EN (0x01 << 12) +#define LVDS_PWRDN (0x01 << 15) + +#define LVDS_24BIT (0 << 1) +#define LVDS_18BIT (1 << 1) +#define LVDS_FORMAT_VESA (0 << 0) +#define LVDS_FORMAT_JEIDA (1 << 0) + + +#endif diff --git a/drivers/video/rockchip/Makefile b/drivers/video/rockchip/Makefile index 0e9a8ac..7962f86 100644 --- a/drivers/video/rockchip/Makefile +++ b/drivers/video/rockchip/Makefile @@ -5,4 +5,4 @@ # SPDX-License-Identifier: GPL-2.0+ #
-obj-y += rk_edp.o rk_hdmi.o rk_vop.o +obj-y += rk_edp.o rk_hdmi.o rk_vop.o rk_lvds.o diff --git a/drivers/video/rockchip/rk_lvds.c b/drivers/video/rockchip/rk_lvds.c new file mode 100644 index 0000000..f44ef98 --- /dev/null +++ b/drivers/video/rockchip/rk_lvds.c @@ -0,0 +1,246 @@ +/* + * Copyright 2016 Rockchip Inc. + * + * SPDX-License-Identifier: GPL-2.0+ + */ + +#include <common.h> +#include <clk.h> +#include <display.h> +#include <dm.h> +#include <edid.h> +#include <panel.h> +#include <regmap.h> +#include <syscon.h> +#include <asm/gpio.h> +#include <asm/io.h> +#include <asm/arch/clock.h> +#include <asm/arch/lvds_rk3288.h> +#include <asm/arch/grf_rk3288.h> +#include <dt-bindings/clock/rk3288-cru.h> + +DECLARE_GLOBAL_DATA_PTR; + +#define DISPLAY_OUTPUT_RGB 0 +#define DISPLAY_OUTPUT_LVDS 1 +#define DISPLAY_OUTPUT_DUAL_LVDS 2 + +struct rk_lvds_priv { + void __iomem *regs; + struct rk3288_grf *grf; + struct udevice *panel; + + int output; + int format; +}; + +static inline void lvds_writel(struct rk_lvds_priv *lvds, u32 offset, u32 val) +{ + writel(val, lvds->regs + offset); + + writel(val, lvds->regs + offset + 0x100); +} + +int rk_lvds_enable(struct udevice *dev, int panel_bpp, + const struct display_timing *edid) +{ + struct rk_lvds_priv *priv = dev_get_priv(dev); + struct display_plat *uc_plat = dev_get_uclass_platdata(dev); + int ret = 0; + unsigned int val = 0; + + ret = panel_enable_backlight(priv->panel); + if (ret) { + debug("%s: backlight error: %d\n", __func__, ret); + return ret; + } + + /* Select the video source */ + if (uc_plat->source_id) + val = RK3288_LVDS_SOC_CON6_SEL_VOP_LIT | + (RK3288_LVDS_SOC_CON6_SEL_VOP_LIT << 16); + else + val = RK3288_LVDS_SOC_CON6_SEL_VOP_LIT << 16; + ret = rk_setreg(&priv->grf->soc_con6, val); + + /* Select data transfer format */ + val = priv->format; + if (priv->output == DISPLAY_OUTPUT_DUAL_LVDS) + val |= LVDS_DUAL | LVDS_CH0_EN | LVDS_CH1_EN; + else if (priv->output == DISPLAY_OUTPUT_LVDS) + val |= LVDS_CH0_EN; + else if (priv->output == DISPLAY_OUTPUT_RGB) + val |= LVDS_TTL_EN | LVDS_CH0_EN | LVDS_CH1_EN; + val |= (0xffff << 16); + rk_setreg(&priv->grf->soc_con7, val); + + /* Enable LVDS PHY */ + if (priv->output == DISPLAY_OUTPUT_RGB) { + lvds_writel(priv, RK3288_LVDS_CH0_REG0, + RK3288_LVDS_CH0_REG0_TTL_EN | + RK3288_LVDS_CH0_REG0_LANECK_EN | + RK3288_LVDS_CH0_REG0_LANE4_EN | + RK3288_LVDS_CH0_REG0_LANE3_EN | + RK3288_LVDS_CH0_REG0_LANE2_EN | + RK3288_LVDS_CH0_REG0_LANE1_EN | + RK3288_LVDS_CH0_REG0_LANE0_EN); + lvds_writel(priv, RK3288_LVDS_CH0_REG2, + RK3288_LVDS_PLL_FBDIV_REG2(0x46)); + + lvds_writel(priv, RK3288_LVDS_CH0_REG3, + RK3288_LVDS_PLL_FBDIV_REG3(0x46)); + lvds_writel(priv, RK3288_LVDS_CH0_REG4, + RK3288_LVDS_CH0_REG4_LANECK_TTL_MODE | + RK3288_LVDS_CH0_REG4_LANE4_TTL_MODE | + RK3288_LVDS_CH0_REG4_LANE3_TTL_MODE | + RK3288_LVDS_CH0_REG4_LANE2_TTL_MODE | + RK3288_LVDS_CH0_REG4_LANE1_TTL_MODE | + RK3288_LVDS_CH0_REG4_LANE0_TTL_MODE); + lvds_writel(priv, RK3288_LVDS_CH0_REG5, + RK3288_LVDS_CH0_REG5_LANECK_TTL_DATA | + RK3288_LVDS_CH0_REG5_LANE4_TTL_DATA | + RK3288_LVDS_CH0_REG5_LANE3_TTL_DATA | + RK3288_LVDS_CH0_REG5_LANE2_TTL_DATA | + RK3288_LVDS_CH0_REG5_LANE1_TTL_DATA | + RK3288_LVDS_CH0_REG5_LANE0_TTL_DATA); + lvds_writel(priv, RK3288_LVDS_CH0_REGD, + RK3288_LVDS_PLL_PREDIV_REGD(0x0a)); + lvds_writel(priv, RK3288_LVDS_CH0_REG20, + RK3288_LVDS_CH0_REG20_LSB); + } else { + lvds_writel(priv, RK3288_LVDS_CH0_REG0, + RK3288_LVDS_CH0_REG0_LVDS_EN | + RK3288_LVDS_CH0_REG0_LANECK_EN | + RK3288_LVDS_CH0_REG0_LANE4_EN | + RK3288_LVDS_CH0_REG0_LANE3_EN | + RK3288_LVDS_CH0_REG0_LANE2_EN | + RK3288_LVDS_CH0_REG0_LANE1_EN | + RK3288_LVDS_CH0_REG0_LANE0_EN); + lvds_writel(priv, RK3288_LVDS_CH0_REG1, + RK3288_LVDS_CH0_REG1_LANECK_BIAS | + RK3288_LVDS_CH0_REG1_LANE4_BIAS | + RK3288_LVDS_CH0_REG1_LANE3_BIAS | + RK3288_LVDS_CH0_REG1_LANE2_BIAS | + RK3288_LVDS_CH0_REG1_LANE1_BIAS | + RK3288_LVDS_CH0_REG1_LANE0_BIAS); + lvds_writel(priv, RK3288_LVDS_CH0_REG2, + RK3288_LVDS_CH0_REG2_RESERVE_ON | + RK3288_LVDS_CH0_REG2_LANECK_LVDS_MODE | + RK3288_LVDS_CH0_REG2_LANE4_LVDS_MODE | + RK3288_LVDS_CH0_REG2_LANE3_LVDS_MODE | + RK3288_LVDS_CH0_REG2_LANE2_LVDS_MODE | + RK3288_LVDS_CH0_REG2_LANE1_LVDS_MODE | + RK3288_LVDS_CH0_REG2_LANE0_LVDS_MODE | + RK3288_LVDS_PLL_FBDIV_REG2(0x46)); + lvds_writel(priv, RK3288_LVDS_CH0_REG3, + RK3288_LVDS_PLL_FBDIV_REG3(0x46)); + lvds_writel(priv, RK3288_LVDS_CH0_REG4, 0x00); + lvds_writel(priv, RK3288_LVDS_CH0_REG5, 0x00); + lvds_writel(priv, RK3288_LVDS_CH0_REGD, + RK3288_LVDS_PLL_PREDIV_REGD(0x0a)); + lvds_writel(priv, RK3288_LVDS_CH0_REG20, + RK3288_LVDS_CH0_REG20_LSB); + } + + /* Power on */ + writel(RK3288_LVDS_CFG_REGC_PLL_ENABLE, + priv->regs + RK3288_LVDS_CFG_REGC); + + writel(RK3288_LVDS_CFG_REG21_TX_ENABLE, + priv->regs + RK3288_LVDS_CFG_REG21); + + return 0; +} + +int rk_lvds_read_timing(struct udevice *dev, struct display_timing *timing) +{ + if (fdtdec_decode_display_timing + (gd->fdt_blob, dev->of_offset, 0, timing)) { + debug("%s: Failed to decode display timing\n", __func__); + return -EINVAL; + } + + return 0; +} + +static int rk_lvds_ofdata_to_platdata(struct udevice *dev) +{ + struct rk_lvds_priv *priv = dev_get_priv(dev); + const void *blob = gd->fdt_blob; + int node = dev->of_offset; + int ret; + priv->regs = (void *)dev_get_addr(dev); + priv->grf = syscon_get_first_range(ROCKCHIP_SYSCON_GRF); + + ret = fdtdec_get_uint(blob, node, "rockchip,output", -1); + if (ret != -1) { + priv->output = ret; + debug("LVDS output : %d\n", ret); + } else { + /* default set it as output rgb */ + priv->output = DISPLAY_OUTPUT_RGB; + } + + ret = fdtdec_get_uint(blob, node, "rockchip,data-mapping", -1); + if (ret != -1) { + priv->format = ret; + debug("LVDS data-mapping : %d\n", ret); + } else { + /* default set it as format jeida */ + priv->format = LVDS_FORMAT_JEIDA; + } + + ret = fdtdec_get_uint(blob, node, "rockchip,data-width", -1); + if (ret != -1) { + debug("LVDS data-width : %d\n", ret); + if (ret == 24) { + priv->format |= LVDS_24BIT; + } else if (ret == 18) { + priv->format |= LVDS_18BIT; + } else { + debug("rockchip-lvds unsupport data-width[%d]\n", ret); + ret = -EINVAL; + return ret; + } + } else { + priv->format |= LVDS_24BIT; + } + + return 0; +} + +int rk_lvds_probe(struct udevice *dev) +{ + struct rk_lvds_priv *priv = dev_get_priv(dev); + int ret; + + ret = uclass_get_device_by_phandle(UCLASS_PANEL, dev, "rockchip,panel", + &priv->panel); + if (ret) { + debug("%s: Cannot find panel for '%s' (ret=%d)\n", __func__, + dev->name, ret); + return ret; + } + + return 0; +} + +static const struct dm_display_ops lvds_rockchip_ops = { + .read_timing = rk_lvds_read_timing, + .enable = rk_lvds_enable, +}; + +static const struct udevice_id rockchip_lvds_ids[] = { + {.compatible = "rockchip,rk3288-lvds"}, + {} +}; + +U_BOOT_DRIVER(lvds_rockchip) = { + .name = "lvds_rockchip", + .id = UCLASS_DISPLAY, + .of_match = rockchip_lvds_ids, + .ops = &lvds_rockchip_ops, + .ofdata_to_platdata = rk_lvds_ofdata_to_platdata, + .probe = rk_lvds_probe, + .priv_auto_alloc_size = sizeof(struct rk_lvds_priv), +};

Hi Jacob,
On 12 March 2016 at 06:13, Jacob Chen jacob-chen@iotwrt.com wrote:
Some Rockchip SoCs support LVDS output. Add a display driver for this so that these displays can be used on supported boards.
Signed-off-by: Jacob Chen jacob-chen@iotwrt.com Signed-off-by: jacob jacob-chen@iotwrt.com
arch/arm/include/asm/arch-rockchip/lvds_rk3288.h | 99 +++++++++ drivers/video/rockchip/Makefile | 2 +- drivers/video/rockchip/rk_lvds.c | 246 +++++++++++++++++++++++ 3 files changed, 346 insertions(+), 1 deletion(-) create mode 100644 arch/arm/include/asm/arch-rockchip/lvds_rk3288.h create mode 100644 drivers/video/rockchip/rk_lvds.c
This looks OK - a few nits below.
diff --git a/arch/arm/include/asm/arch-rockchip/lvds_rk3288.h b/arch/arm/include/asm/arch-rockchip/lvds_rk3288.h new file mode 100644 index 0000000..de16f3d --- /dev/null +++ b/arch/arm/include/asm/arch-rockchip/lvds_rk3288.h @@ -0,0 +1,99 @@ +/*
- Copyright 2016 Rockchip Inc.
- SPDX-License-Identifier: GPL-2.0+
- */
+#ifndef _ASM_ARCH_LVDS_RK3288_H +#define _ASM_ARCH_LVDS_RK3288_H
+#define RK3288_LVDS_CH0_REG0 0x00 +#define RK3288_LVDS_CH0_REG0_LVDS_EN BIT(7) +#define RK3288_LVDS_CH0_REG0_TTL_EN BIT(6) +#define RK3288_LVDS_CH0_REG0_LANECK_EN BIT(5) +#define RK3288_LVDS_CH0_REG0_LANE4_EN BIT(4) +#define RK3288_LVDS_CH0_REG0_LANE3_EN BIT(3) +#define RK3288_LVDS_CH0_REG0_LANE2_EN BIT(2) +#define RK3288_LVDS_CH0_REG0_LANE1_EN BIT(1) +#define RK3288_LVDS_CH0_REG0_LANE0_EN BIT(0)
+#define RK3288_LVDS_CH0_REG1 0x04 +#define RK3288_LVDS_CH0_REG1_LANECK_BIAS BIT(5) +#define RK3288_LVDS_CH0_REG1_LANE4_BIAS BIT(4) +#define RK3288_LVDS_CH0_REG1_LANE3_BIAS BIT(3) +#define RK3288_LVDS_CH0_REG1_LANE2_BIAS BIT(2) +#define RK3288_LVDS_CH0_REG1_LANE1_BIAS BIT(1) +#define RK3288_LVDS_CH0_REG1_LANE0_BIAS BIT(0)
+#define RK3288_LVDS_CH0_REG2 0x08 +#define RK3288_LVDS_CH0_REG2_RESERVE_ON BIT(7) +#define RK3288_LVDS_CH0_REG2_LANECK_LVDS_MODE BIT(6) +#define RK3288_LVDS_CH0_REG2_LANE4_LVDS_MODE BIT(5) +#define RK3288_LVDS_CH0_REG2_LANE3_LVDS_MODE BIT(4) +#define RK3288_LVDS_CH0_REG2_LANE2_LVDS_MODE BIT(3) +#define RK3288_LVDS_CH0_REG2_LANE1_LVDS_MODE BIT(2) +#define RK3288_LVDS_CH0_REG2_LANE0_LVDS_MODE BIT(1) +#define RK3288_LVDS_CH0_REG2_PLL_FBDIV8 BIT(0)
+#define RK3288_LVDS_CH0_REG3 0x0c +#define RK3288_LVDS_CH0_REG3_PLL_FBDIV_MASK 0xff
+#define RK3288_LVDS_CH0_REG4 0x10 +#define RK3288_LVDS_CH0_REG4_LANECK_TTL_MODE BIT(5) +#define RK3288_LVDS_CH0_REG4_LANE4_TTL_MODE BIT(4) +#define RK3288_LVDS_CH0_REG4_LANE3_TTL_MODE BIT(3) +#define RK3288_LVDS_CH0_REG4_LANE2_TTL_MODE BIT(2) +#define RK3288_LVDS_CH0_REG4_LANE1_TTL_MODE BIT(1) +#define RK3288_LVDS_CH0_REG4_LANE0_TTL_MODE BIT(0)
+#define RK3288_LVDS_CH0_REG5 0x14 +#define RK3288_LVDS_CH0_REG5_LANECK_TTL_DATA BIT(5) +#define RK3288_LVDS_CH0_REG5_LANE4_TTL_DATA BIT(4) +#define RK3288_LVDS_CH0_REG5_LANE3_TTL_DATA BIT(3) +#define RK3288_LVDS_CH0_REG5_LANE2_TTL_DATA BIT(2) +#define RK3288_LVDS_CH0_REG5_LANE1_TTL_DATA BIT(1) +#define RK3288_LVDS_CH0_REG5_LANE0_TTL_DATA BIT(0)
+#define RK3288_LVDS_CFG_REGC 0x30 +#define RK3288_LVDS_CFG_REGC_PLL_ENABLE 0x00 +#define RK3288_LVDS_CFG_REGC_PLL_DISABLE 0xff
+#define RK3288_LVDS_CH0_REGD 0x34 +#define RK3288_LVDS_CH0_REGD_PLL_PREDIV_MASK 0x1f
+#define RK3288_LVDS_CH0_REG20 0x80 +#define RK3288_LVDS_CH0_REG20_MSB 0x45 +#define RK3288_LVDS_CH0_REG20_LSB 0x44
+#define RK3288_LVDS_CFG_REG21 0x84 +#define RK3288_LVDS_CFG_REG21_TX_ENABLE 0x92 +#define RK3288_LVDS_CFG_REG21_TX_DISABLE 0x00
+/* fbdiv value is split over 2 registers, with bit8 in reg2 */ +#define RK3288_LVDS_PLL_FBDIV_REG2(_fbd) \
(_fbd & BIT(8) ? RK3288_LVDS_CH0_REG2_PLL_FBDIV8 : 0)
+#define RK3288_LVDS_PLL_FBDIV_REG3(_fbd) \
(_fbd & RK3288_LVDS_CH0_REG3_PLL_FBDIV_MASK)
+#define RK3288_LVDS_PLL_PREDIV_REGD(_pd) \
(_pd & RK3288_LVDS_CH0_REGD_PLL_PREDIV_MASK)
+#define RK3288_LVDS_SOC_CON6_SEL_VOP_LIT BIT(3)
+#define LVDS_FMT_MASK (0x07 << 16)
+#define LVDS_MSB (0x01 << 3) +#define LVDS_DUAL (0x01 << 4) +#define LVDS_FMT_1 (0x01 << 5) +#define LVDS_TTL_EN (0x01 << 6) +#define LVDS_START_PHASE_RST_1 (0x01 << 7) +#define LVDS_DCLK_INV (0x01 << 8) +#define LVDS_CH0_EN (0x01 << 11) +#define LVDS_CH1_EN (0x01 << 12) +#define LVDS_PWRDN (0x01 << 15)
Can you drop the 0x0 prefix on these? It doesn't seem useful.
+#define LVDS_24BIT (0 << 1) +#define LVDS_18BIT (1 << 1) +#define LVDS_FORMAT_VESA (0 << 0) +#define LVDS_FORMAT_JEIDA (1 << 0)
+#endif diff --git a/drivers/video/rockchip/Makefile b/drivers/video/rockchip/Makefile index 0e9a8ac..7962f86 100644 --- a/drivers/video/rockchip/Makefile +++ b/drivers/video/rockchip/Makefile @@ -5,4 +5,4 @@ # SPDX-License-Identifier: GPL-2.0+ #
-obj-y += rk_edp.o rk_hdmi.o rk_vop.o +obj-y += rk_edp.o rk_hdmi.o rk_vop.o rk_lvds.o diff --git a/drivers/video/rockchip/rk_lvds.c b/drivers/video/rockchip/rk_lvds.c new file mode 100644 index 0000000..f44ef98 --- /dev/null +++ b/drivers/video/rockchip/rk_lvds.c @@ -0,0 +1,246 @@ +/*
- Copyright 2016 Rockchip Inc.
- SPDX-License-Identifier: GPL-2.0+
- */
+#include <common.h> +#include <clk.h> +#include <display.h> +#include <dm.h> +#include <edid.h> +#include <panel.h> +#include <regmap.h> +#include <syscon.h> +#include <asm/gpio.h> +#include <asm/io.h> +#include <asm/arch/clock.h> +#include <asm/arch/lvds_rk3288.h> +#include <asm/arch/grf_rk3288.h> +#include <dt-bindings/clock/rk3288-cru.h>
+DECLARE_GLOBAL_DATA_PTR;
+#define DISPLAY_OUTPUT_RGB 0 +#define DISPLAY_OUTPUT_LVDS 1 +#define DISPLAY_OUTPUT_DUAL_LVDS 2
+struct rk_lvds_priv {
void __iomem *regs;
struct rk3288_grf *grf;
struct udevice *panel;
int output;
int format;
Please add comments as to what these members are above the struct:
/** * struct rk_lvds_priv - Holds private LVDS driver data * @regs: ... ...
+};
+static inline void lvds_writel(struct rk_lvds_priv *lvds, u32 offset, u32 val) +{
writel(val, lvds->regs + offset);
writel(val, lvds->regs + offset + 0x100);
+}
+int rk_lvds_enable(struct udevice *dev, int panel_bpp,
const struct display_timing *edid)
+{
struct rk_lvds_priv *priv = dev_get_priv(dev);
struct display_plat *uc_plat = dev_get_uclass_platdata(dev);
int ret = 0;
unsigned int val = 0;
ret = panel_enable_backlight(priv->panel);
if (ret) {
debug("%s: backlight error: %d\n", __func__, ret);
return ret;
}
/* Select the video source */
if (uc_plat->source_id)
val = RK3288_LVDS_SOC_CON6_SEL_VOP_LIT |
(RK3288_LVDS_SOC_CON6_SEL_VOP_LIT << 16);
else
val = RK3288_LVDS_SOC_CON6_SEL_VOP_LIT << 16;
ret = rk_setreg(&priv->grf->soc_con6, val);
/* Select data transfer format */
val = priv->format;
if (priv->output == DISPLAY_OUTPUT_DUAL_LVDS)
val |= LVDS_DUAL | LVDS_CH0_EN | LVDS_CH1_EN;
else if (priv->output == DISPLAY_OUTPUT_LVDS)
val |= LVDS_CH0_EN;
else if (priv->output == DISPLAY_OUTPUT_RGB)
val |= LVDS_TTL_EN | LVDS_CH0_EN | LVDS_CH1_EN;
val |= (0xffff << 16);
rk_setreg(&priv->grf->soc_con7, val);
/* Enable LVDS PHY */
if (priv->output == DISPLAY_OUTPUT_RGB) {
lvds_writel(priv, RK3288_LVDS_CH0_REG0,
RK3288_LVDS_CH0_REG0_TTL_EN |
RK3288_LVDS_CH0_REG0_LANECK_EN |
RK3288_LVDS_CH0_REG0_LANE4_EN |
RK3288_LVDS_CH0_REG0_LANE3_EN |
RK3288_LVDS_CH0_REG0_LANE2_EN |
RK3288_LVDS_CH0_REG0_LANE1_EN |
RK3288_LVDS_CH0_REG0_LANE0_EN);
lvds_writel(priv, RK3288_LVDS_CH0_REG2,
RK3288_LVDS_PLL_FBDIV_REG2(0x46));
lvds_writel(priv, RK3288_LVDS_CH0_REG3,
RK3288_LVDS_PLL_FBDIV_REG3(0x46));
lvds_writel(priv, RK3288_LVDS_CH0_REG4,
RK3288_LVDS_CH0_REG4_LANECK_TTL_MODE |
RK3288_LVDS_CH0_REG4_LANE4_TTL_MODE |
RK3288_LVDS_CH0_REG4_LANE3_TTL_MODE |
RK3288_LVDS_CH0_REG4_LANE2_TTL_MODE |
RK3288_LVDS_CH0_REG4_LANE1_TTL_MODE |
RK3288_LVDS_CH0_REG4_LANE0_TTL_MODE);
lvds_writel(priv, RK3288_LVDS_CH0_REG5,
RK3288_LVDS_CH0_REG5_LANECK_TTL_DATA |
RK3288_LVDS_CH0_REG5_LANE4_TTL_DATA |
RK3288_LVDS_CH0_REG5_LANE3_TTL_DATA |
RK3288_LVDS_CH0_REG5_LANE2_TTL_DATA |
RK3288_LVDS_CH0_REG5_LANE1_TTL_DATA |
RK3288_LVDS_CH0_REG5_LANE0_TTL_DATA);
lvds_writel(priv, RK3288_LVDS_CH0_REGD,
RK3288_LVDS_PLL_PREDIV_REGD(0x0a));
lvds_writel(priv, RK3288_LVDS_CH0_REG20,
RK3288_LVDS_CH0_REG20_LSB);
} else {
lvds_writel(priv, RK3288_LVDS_CH0_REG0,
RK3288_LVDS_CH0_REG0_LVDS_EN |
RK3288_LVDS_CH0_REG0_LANECK_EN |
RK3288_LVDS_CH0_REG0_LANE4_EN |
RK3288_LVDS_CH0_REG0_LANE3_EN |
RK3288_LVDS_CH0_REG0_LANE2_EN |
RK3288_LVDS_CH0_REG0_LANE1_EN |
RK3288_LVDS_CH0_REG0_LANE0_EN);
lvds_writel(priv, RK3288_LVDS_CH0_REG1,
RK3288_LVDS_CH0_REG1_LANECK_BIAS |
RK3288_LVDS_CH0_REG1_LANE4_BIAS |
RK3288_LVDS_CH0_REG1_LANE3_BIAS |
RK3288_LVDS_CH0_REG1_LANE2_BIAS |
RK3288_LVDS_CH0_REG1_LANE1_BIAS |
RK3288_LVDS_CH0_REG1_LANE0_BIAS);
lvds_writel(priv, RK3288_LVDS_CH0_REG2,
RK3288_LVDS_CH0_REG2_RESERVE_ON |
RK3288_LVDS_CH0_REG2_LANECK_LVDS_MODE |
RK3288_LVDS_CH0_REG2_LANE4_LVDS_MODE |
RK3288_LVDS_CH0_REG2_LANE3_LVDS_MODE |
RK3288_LVDS_CH0_REG2_LANE2_LVDS_MODE |
RK3288_LVDS_CH0_REG2_LANE1_LVDS_MODE |
RK3288_LVDS_CH0_REG2_LANE0_LVDS_MODE |
RK3288_LVDS_PLL_FBDIV_REG2(0x46));
lvds_writel(priv, RK3288_LVDS_CH0_REG3,
RK3288_LVDS_PLL_FBDIV_REG3(0x46));
lvds_writel(priv, RK3288_LVDS_CH0_REG4, 0x00);
lvds_writel(priv, RK3288_LVDS_CH0_REG5, 0x00);
lvds_writel(priv, RK3288_LVDS_CH0_REGD,
RK3288_LVDS_PLL_PREDIV_REGD(0x0a));
lvds_writel(priv, RK3288_LVDS_CH0_REG20,
RK3288_LVDS_CH0_REG20_LSB);
}
/* Power on */
writel(RK3288_LVDS_CFG_REGC_PLL_ENABLE,
priv->regs + RK3288_LVDS_CFG_REGC);
writel(RK3288_LVDS_CFG_REG21_TX_ENABLE,
priv->regs + RK3288_LVDS_CFG_REG21);
return 0;
+}
+int rk_lvds_read_timing(struct udevice *dev, struct display_timing *timing) +{
if (fdtdec_decode_display_timing
(gd->fdt_blob, dev->of_offset, 0, timing)) {
debug("%s: Failed to decode display timing\n", __func__);
return -EINVAL;
}
return 0;
+}
+static int rk_lvds_ofdata_to_platdata(struct udevice *dev) +{
struct rk_lvds_priv *priv = dev_get_priv(dev);
const void *blob = gd->fdt_blob;
int node = dev->of_offset;
int ret;
priv->regs = (void *)dev_get_addr(dev);
priv->grf = syscon_get_first_range(ROCKCHIP_SYSCON_GRF);
ret = fdtdec_get_uint(blob, node, "rockchip,output", -1);
if (ret != -1) {
priv->output = ret;
debug("LVDS output : %d\n", ret);
} else {
/* default set it as output rgb */
priv->output = DISPLAY_OUTPUT_RGB;
}
ret = fdtdec_get_uint(blob, node, "rockchip,data-mapping", -1);
if (ret != -1) {
priv->format = ret;
debug("LVDS data-mapping : %d\n", ret);
} else {
/* default set it as format jeida */
priv->format = LVDS_FORMAT_JEIDA;
}
ret = fdtdec_get_uint(blob, node, "rockchip,data-width", -1);
Do you have a binding file for these settings?
if (ret != -1) {
debug("LVDS data-width : %d\n", ret);
if (ret == 24) {
priv->format |= LVDS_24BIT;
} else if (ret == 18) {
priv->format |= LVDS_18BIT;
} else {
debug("rockchip-lvds unsupport data-width[%d]\n", ret);
ret = -EINVAL;
return ret;
}
} else {
priv->format |= LVDS_24BIT;
}
return 0;
+}
+int rk_lvds_probe(struct udevice *dev) +{
struct rk_lvds_priv *priv = dev_get_priv(dev);
int ret;
ret = uclass_get_device_by_phandle(UCLASS_PANEL, dev, "rockchip,panel",
&priv->panel);
if (ret) {
debug("%s: Cannot find panel for '%s' (ret=%d)\n", __func__,
dev->name, ret);
return ret;
}
return 0;
+}
+static const struct dm_display_ops lvds_rockchip_ops = {
.read_timing = rk_lvds_read_timing,
.enable = rk_lvds_enable,
+};
+static const struct udevice_id rockchip_lvds_ids[] = {
{.compatible = "rockchip,rk3288-lvds"},
{}
+};
+U_BOOT_DRIVER(lvds_rockchip) = {
.name = "lvds_rockchip",
.id = UCLASS_DISPLAY,
.of_match = rockchip_lvds_ids,
.ops = &lvds_rockchip_ops,
.ofdata_to_platdata = rk_lvds_ofdata_to_platdata,
.probe = rk_lvds_probe,
.priv_auto_alloc_size = sizeof(struct rk_lvds_priv),
+};
2.3.5
Regards, Simon

Add these node to be used in rockchip LVDS and VOP driver.
Signed-off-by: Jacob Chen jacob-chen@iotwrt.com Signed-off-by: jacob jacob-chen@iotwrt.com ---
arch/arm/dts/rk3288.dtsi | 46 +++++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 45 insertions(+), 1 deletion(-)
diff --git a/arch/arm/dts/rk3288.dtsi b/arch/arm/dts/rk3288.dtsi index e51c75c..ba29b38 100644 --- a/arch/arm/dts/rk3288.dtsi +++ b/arch/arm/dts/rk3288.dtsi @@ -683,6 +683,10 @@ reg = <1>; remote-endpoint = <&hdmi_in_vopb>; }; + vopb_out_lvds: endpoint@2 { + reg = <2>; + remote-endpoint = <&lvds_in_vopb>; + }; }; };
@@ -719,7 +723,10 @@ reg = <1>; remote-endpoint = <&hdmi_in_vopl>; }; - + vopl_out_lvds: endpoint@2 { + reg = <2>; + remote-endpoint = <&lvds_in_vopl>; + }; }; };
@@ -786,6 +793,34 @@ }; };
+ lvds: lvds@ff96c000 { + compatible = "rockchip,rk3288-lvds"; + reg = <0xff96c000 0x4000>; + clocks = <&cru PCLK_LVDS_PHY>; + clock-names = "pclk_lvds"; + pinctrl-names = "default"; + pinctrl-0 = <&lcdc0_ctl>; + rockchip,grf = <&grf>; + status = "disabled"; + ports { + #address-cells = <1>; + #size-cells = <0>; + lvds_in: port@0 { + reg = <0>; + #address-cells = <1>; + #size-cells = <0>; + lvds_in_vopb: endpoint@0 { + reg = <0>; + remote-endpoint = <&vopb_out_lvds>; + }; + lvds_in_vopl: endpoint@1 { + reg = <1>; + remote-endpoint = <&vopl_out_lvds>; + }; + }; + }; + }; + hdmi_audio: hdmi_audio { compatible = "rockchip,rk3288-hdmi-audio"; i2s-controller = <&i2s>; @@ -1109,6 +1144,15 @@ }; };
+ lcdc0 { + lcdc0_ctl: lcdc0-ctl { + rockchip,pins = <1 24 RK_FUNC_1 &pcfg_pull_none>, + <1 25 RK_FUNC_1 &pcfg_pull_none>, + <1 26 RK_FUNC_1 &pcfg_pull_none>, + <1 27 RK_FUNC_1 &pcfg_pull_none>; + }; + }; + sdmmc { sdmmc_clk: sdmmc-clk { rockchip,pins = <6 20 RK_FUNC_1 &pcfg_pull_none>;

On 12 March 2016 at 06:13, Jacob Chen jacob-chen@iotwrt.com wrote:
Add these node to be used in rockchip LVDS and VOP driver.
Signed-off-by: Jacob Chen jacob-chen@iotwrt.com Signed-off-by: jacob jacob-chen@iotwrt.com
arch/arm/dts/rk3288.dtsi | 46 +++++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 45 insertions(+), 1 deletion(-)
Acked-by: Simon Glass sjg@chromium.org

LVDS have a different display out mode, add code to get right flag.
The vop_ip decied display device and the remote_vop_id decied which vop was being used. So we should use the remote_vop_id to set DCLK_VOP.
Signed-off-by: Jacob Chen jacob-chen@iotwrt.com Signed-off-by: jacob jacob-chen@iotwrt.com ---
arch/arm/include/asm/arch-rockchip/vop_rk3288.h | 1 + drivers/video/rockchip/rk_vop.c | 16 ++++++++++++++-- 2 files changed, 15 insertions(+), 2 deletions(-)
diff --git a/arch/arm/include/asm/arch-rockchip/vop_rk3288.h b/arch/arm/include/asm/arch-rockchip/vop_rk3288.h index 0104ba3..0ce3d67 100644 --- a/arch/arm/include/asm/arch-rockchip/vop_rk3288.h +++ b/arch/arm/include/asm/arch-rockchip/vop_rk3288.h @@ -89,6 +89,7 @@ enum { enum vop_modes { VOP_MODE_EDP = 0, VOP_MODE_HDMI, + VOP_MODE_LVDS, VOP_MODE_NONE, VOP_MODE_AUTO_DETECT, VOP_MODE_UNKNOWN, diff --git a/drivers/video/rockchip/rk_vop.c b/drivers/video/rockchip/rk_vop.c index adbc68f..a54af17 100644 --- a/drivers/video/rockchip/rk_vop.c +++ b/drivers/video/rockchip/rk_vop.c @@ -102,6 +102,7 @@ void rkvop_mode_set(struct rk3288_vop *regs, u32 hfront_porch = edid->hfront_porch.typ; u32 vfront_porch = edid->vfront_porch.typ; uint flags; + int mode_flags;
switch (mode) { case VOP_MODE_HDMI: @@ -113,9 +114,20 @@ void rkvop_mode_set(struct rk3288_vop *regs, 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; }
- flags = V_DSP_OUT_MODE(15) | + if (mode == VOP_MODE_HDMI || mode == VOP_MODE_EDP) + /* RGBaaa */ + mode_flags = 15; + else + /* RGB888 */ + mode_flags = 0; + + 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));
@@ -227,7 +239,7 @@ int rk_display_init(struct udevice *dev, ulong fbbase,
ret = rkclk_get_clk(CLK_NEW, &clk); if (!ret) { - ret = clk_set_periph_rate(clk, DCLK_VOP0 + vop_id, + ret = clk_set_periph_rate(clk, DCLK_VOP0 + remote_vop_id, timing.pixelclock.typ); } if (ret) {

On 12 March 2016 at 06:13, Jacob Chen jacob-chen@iotwrt.com wrote:
LVDS have a different display out mode, add code to get right flag.
The vop_ip decied display device and the remote_vop_id decied which vop was being used. So we should use the remote_vop_id to set DCLK_VOP.
Signed-off-by: Jacob Chen jacob-chen@iotwrt.com Signed-off-by: jacob jacob-chen@iotwrt.com
arch/arm/include/asm/arch-rockchip/vop_rk3288.h | 1 + drivers/video/rockchip/rk_vop.c | 16 ++++++++++++++-- 2 files changed, 15 insertions(+), 2 deletions(-)
Acked-by: Simon Glass sjg@chromium.org

I didn't have a common board to enable LVDS. So add this dcocument to help others who want to enable LVDS in their board.
Signed-off-by: Jacob Chen jacob-chen@iotwrt.com Signed-off-by: jacob jacob-chen@iotwrt.com ---
doc/device-tree-bindings/video/rockchip-lvds.txt | 77 ++++++++++++++++++++++++ 1 file changed, 77 insertions(+) create mode 100644 doc/device-tree-bindings/video/rockchip-lvds.txt
diff --git a/doc/device-tree-bindings/video/rockchip-lvds.txt b/doc/device-tree-bindings/video/rockchip-lvds.txt new file mode 100644 index 0000000..60437f2 --- /dev/null +++ b/doc/device-tree-bindings/video/rockchip-lvds.txt @@ -0,0 +1,77 @@ +Rockchip LVDS interface +------------------ + +(Required properties: +- compatible: "rockchip,rk3288-lvds"; + +- reg: physical base address of the controller and length + of memory mapped region. +- clocks: must include clock specifiers corresponding to entries in the + clock-names property. +- clock-names: must contain "pclk_lvds" + +- rockchip,grf: phandle to the general register files syscon + +- rockchip,data-mapping: should be <0> for "vesa" or <1> for "jeida", + This describes how the color bits are laid out in the + serialized LVDS signal. +- rockchip,data-width : should be <18> or <24>; +- rockchip,output: should be <0> for "rgb", <1> for "lvds" or <2> for "duallvds", + This describes the output face. + +- display-timings : described by + doc/devicetree/device-tree-bindings/video/display-timing.txt. + +Example: + lvds: lvds@ff96c000 { + compatible = "rockchip,rk3288-lvds"; + reg = <0xff96c000 0x4000>; + clocks = <&cru PCLK_LVDS_PHY>; + clock-names = "pclk_lvds"; + pinctrl-names = "default"; + pinctrl-0 = <&lcdc0_ctl>; + rockchip,grf = <&grf>; + status = "disabled"; + ports { + #address-cells = <1>; + #size-cells = <0>; + + lvds_in: port@0 { + reg = <0>; + + #address-cells = <1>; + #size-cells = <0>; + + lvds_in_vopb: endpoint@0 { + reg = <0>; + remote-endpoint = <&vopb_out_lvds>; + }; + lvds_in_vopl: endpoint@1 { + reg = <1>; + remote-endpoint = <&vopl_out_lvds>; + }; + }; + }; + }; + + &lvds { + rockchip,data-mapping = <0>; + rockchip,data-width = <24>; + rockchip,output = <2>; + rockchip,panel = <&panel>; + status = "okay"; + + display-timings { + timing@0 { + clock-frequency = <40000000>; + hactive = <1920>; + vactive = <1080>; + hsync-len = <44>; + hfront-porch = <88>; + hback-porch = <148>; + vfront-porch = <4>; + vback-porch = <36>; + vsync-len = <5>; + }; + }; + }; \ No newline at end of file

On 12 March 2016 at 06:13, Jacob Chen jacob-chen@iotwrt.com wrote:
I didn't have a common board to enable LVDS. So add this dcocument to help others who want to enable LVDS in their board.
Signed-off-by: Jacob Chen jacob-chen@iotwrt.com Signed-off-by: jacob jacob-chen@iotwrt.com
doc/device-tree-bindings/video/rockchip-lvds.txt | 77 ++++++++++++++++++++++++ 1 file changed, 77 insertions(+) create mode 100644 doc/device-tree-bindings/video/rockchip-lvds.txt
Acked-by: Simon Glass sjg@chromium.org
Please see nit below.
diff --git a/doc/device-tree-bindings/video/rockchip-lvds.txt b/doc/device-tree-bindings/video/rockchip-lvds.txt new file mode 100644 index 0000000..60437f2 --- /dev/null +++ b/doc/device-tree-bindings/video/rockchip-lvds.txt @@ -0,0 +1,77 @@ +Rockchip LVDS interface +------------------
+(Required properties:
Do you need the '(' ?
+- compatible: "rockchip,rk3288-lvds";
+- reg: physical base address of the controller and length
of memory mapped region.
+- clocks: must include clock specifiers corresponding to entries in the
clock-names property.
+- clock-names: must contain "pclk_lvds"
+- rockchip,grf: phandle to the general register files syscon
+- rockchip,data-mapping: should be <0> for "vesa" or <1> for "jeida",
This describes how the color bits are laid out in the
serialized LVDS signal.
+- rockchip,data-width : should be <18> or <24>; +- rockchip,output: should be <0> for "rgb", <1> for "lvds" or <2> for "duallvds",
This describes the output face.
+- display-timings : described by
doc/devicetree/device-tree-bindings/video/display-timing.txt.
+Example:
lvds: lvds@ff96c000 {
compatible = "rockchip,rk3288-lvds";
reg = <0xff96c000 0x4000>;
clocks = <&cru PCLK_LVDS_PHY>;
clock-names = "pclk_lvds";
pinctrl-names = "default";
pinctrl-0 = <&lcdc0_ctl>;
rockchip,grf = <&grf>;
status = "disabled";
ports {
#address-cells = <1>;
#size-cells = <0>;
lvds_in: port@0 {
reg = <0>;
#address-cells = <1>;
#size-cells = <0>;
lvds_in_vopb: endpoint@0 {
reg = <0>;
remote-endpoint = <&vopb_out_lvds>;
};
lvds_in_vopl: endpoint@1 {
reg = <1>;
remote-endpoint = <&vopl_out_lvds>;
};
};
};
};
+'
&lvds {
rockchip,data-mapping = <0>;
rockchip,data-width = <24>;
rockchip,output = <2>;
rockchip,panel = <&panel>;
status = "okay";
display-timings {
timing@0 {
clock-frequency = <40000000>;
hactive = <1920>;
vactive = <1080>;
hsync-len = <44>;
hfront-porch = <88>;
hback-porch = <148>;
vfront-porch = <4>;
vback-porch = <36>;
vsync-len = <5>;
};
};
};
\ No newline at end of file
Can you add one?
-- 2.3.5
Regards, Simon

Hi Jacob,
On 12 March 2016 at 06:13, Jacob Chen jacob-chen@iotwrt.com wrote:
From: jacob jacob-chen@iotwrt.com
This series patches add LVDS support for rk3288. I'm a newbie in submiting patches. If there are something wrong, hope to get help.
It looks very tidy!
Jacob Chen (5): dm: video: Add a operation to display uclass rockchip: video: Add a display driver for rockchip LVDS rockchip: dts: Add LVDS support rockchip: video: Add LVDS support in vop driver doc: dt-bindings: Describe rockchip LVDS interface
arch/arm/dts/rk3288.dtsi | 46 ++++- arch/arm/include/asm/arch-rockchip/lvds_rk3288.h | 99 +++++++++ arch/arm/include/asm/arch-rockchip/vop_rk3288.h | 1 + doc/device-tree-bindings/video/rockchip-lvds.txt | 77 +++++++ drivers/video/display-uclass.c | 3 + drivers/video/rockchip/Makefile | 2 +- drivers/video/rockchip/rk_lvds.c | 246 +++++++++++++++++++++++ drivers/video/rockchip/rk_vop.c | 16 +- include/display.h | 11 +- 9 files changed, 496 insertions(+), 5 deletions(-) create mode 100644 arch/arm/include/asm/arch-rockchip/lvds_rk3288.h create mode 100644 doc/device-tree-bindings/video/rockchip-lvds.txt create mode 100644 drivers/video/rockchip/rk_lvds.c
-- 2.3.5
Regards, Simon
participants (2)
-
Jacob Chen
-
Simon Glass