scl-gpios = <&gpio5 16 GPIO_ACTIVE_HIGH>;
sda-gpios = <&gpio5 17 GPIO_ACTIVE_HIGH>;
status = "okay";
+
+ lvds_bridge: lvds-to-hdmi-bridge@4c {
+ compatible = "ite,it6263";
+ reg = <0x4c>;
+ reset-gpios = <&gpio1 10 GPIO_ACTIVE_LOW>;
+ status = "okay";
+
+ port {
+ it6263_in: endpoint {
+ remote-endpoint = <&lvds_out>;
+ };
+ };
+ };
};
&i2c3 {
status = "okay";
};
-&lcdif1 {
+&lcdif2 {
+ status = "okay";
+};
+
+&ldb {
+ status = "okay";
+
+ lvds-channel@0 {
+ fsl,data-mapping = "jeida";
+ fsl,data-width = <24>;
+ status = "okay";
+
+ display-timings {
+ native-mode = <&timing0>;
+
+ timing0: timing0 {
+ clock-frequency = <74250000>;
+ hactive = <1280>;
+ vactive = <720>;
+ hfront-porch = <220>;
+ hback-porch = <110>;
+ hsync-len = <40>;
+ vback-porch = <5>;
+ vfront-porch = <20>;
+ vsync-len = <5>;
+ };
+ };
+ port@1 {
+ reg = <1>;
+
+ lvds_out: endpoint {
+ remote-endpoint = <&it6263_in>;
+ };
+ };
+ };
+};
+
+&ldb_phy {
status = "okay";
};
usb0 = &usb_dwc3_0;
usb1 = &usb_dwc3_1;
spi0 = &flexspi;
- video0 = &lcdif1;
+ video0 = &lcdif2;
};
cpus {
domain-name = "hdmi_phy";
parent-domains = <&hdmimix_pd>;
};
+
+ lvds_phy_pd: lvdsphy-pd {
+ compatible = "fsl,imx8m-pm-domain";
+ #power-domain-cells = <0>;
+ domain-index = <19>;
+ domain-name = "lvds_phy";
+ parent-domains = <&mediamix_pd>;
+ };
};
pmu {
};
};
+ lcdif2: lcd-controller@32e90000 {
+ #address-cells = <1>;
+ #size-cells = <0>;
+ compatible = "fsl,imx8mp-lcdif2";
+ reg = <0x32e90000 0x10000>;
+ clocks = <&clk IMX8MP_CLK_MEDIA_DISP2_PIX_ROOT>,
+ <&clk IMX8MP_CLK_MEDIA_AXI_ROOT>,
+ <&clk IMX8MP_CLK_MEDIA_APB_ROOT>;
+ clock-names = "pix", "disp-axi", "disp-apb";
+ assigned-clocks = <&clk IMX8MP_CLK_MEDIA_DISP2_PIX>,
+ <&clk IMX8MP_CLK_MEDIA_AXI>,
+ <&clk IMX8MP_CLK_MEDIA_APB>;
+ assigned-clock-parents = <&clk IMX8MP_VIDEO_PLL1_OUT>,
+ <&clk IMX8MP_SYS_PLL2_1000M>,
+ <&clk IMX8MP_SYS_PLL1_800M>;
+ assigned-clock-rates = <0>, <500000000>, <200000000>;
+ interrupts = <GIC_SPI 6 IRQ_TYPE_LEVEL_HIGH>;
+ blk-ctl = <&mediamix_blk_ctl>;
+ power-domains = <&mediamix_pd>;
+ status = "disabled";
+
+ lcdif2_disp: port@0 {
+ #address-cells = <1>;
+ #size-cells = <0>;
+ reg = <0>;
+
+ lcdif2_disp_ldb_ch0: endpoint@0 {
+ reg = <0>;
+ remote-endpoint = <&ldb_ch0>;
+ };
+
+ lcdif2_disp_ldb_ch1: endpoint@1 {
+ reg = <1>;
+ remote-endpoint = <&ldb_ch1>;
+ };
+ };
+ };
+
mediamix_blk_ctl: blk-ctl@32ec0000 {
compatible = "fsl,imx8mp-mediamix-blk-ctl",
"syscon";
};
+ ldb: ldb@32ec005c {
+ #address-cells = <1>;
+ #size-cells = <0>;
+ compatible = "fsl,imx8mp-ldb";
+ clocks = <&clk IMX8MP_CLK_MEDIA_LDB_ROOT>;
+ clock-names = "ldb";
+ assigned-clocks = <&clk IMX8MP_CLK_MEDIA_LDB>;
+ assigned-clock-parents = <&clk IMX8MP_VIDEO_PLL1_OUT>;
+ gpr = <&mediamix_blk_ctl>;
+ power-domains = <&mediamix_pd>;
+ status = "disabled";
+
+ lvds-channel@0 {
+ #address-cells = <1>;
+ #size-cells = <0>;
+ reg = <0>;
+ phys = <&ldb_phy1>;
+ phy-names = "ldb_phy";
+ status = "disabled";
+
+ port@0 {
+ reg = <0>;
+
+ ldb_ch0: endpoint {
+ remote-endpoint = <&lcdif2_disp_ldb_ch0>;
+ };
+ };
+ };
+
+ lvds-channel@1 {
+ #address-cells = <1>;
+ #size-cells = <0>;
+ reg = <1>;
+ phys = <&ldb_phy2>;
+ phy-names = "ldb_phy";
+ status = "disabled";
+
+ port@0 {
+ reg = <0>;
+
+ ldb_ch1: endpoint {
+ remote-endpoint = <&lcdif2_disp_ldb_ch1>;
+ };
+ };
+ };
+ };
+
+ ldb_phy: phy@32ec0128 {
+ compatible = "fsl,imx8mp-lvds-phy";
+ #address-cells = <1>;
+ #size-cells = <0>;
+ gpr = <&mediamix_blk_ctl>;
+ clocks = <&clk IMX8MP_CLK_MEDIA_APB_ROOT>;
+ clock-names = "apb";
+ power-domains = <&mediamix_pd>;
+ status = "disabled";
+
+ ldb_phy1: port@0 {
+ reg = <0>;
+ #phy-cells = <0>;
+ };
+
+ ldb_phy2: port@1 {
+ reg = <1>;
+ #phy-cells = <0>;
+ };
+ };
+
ddr-pmu@3d800000 {
compatible = "fsl,imx8mp-ddr-pmu", "fsl,imx8m-ddr-pmu";
reg = <0x3d800000 0x400000>;
}
static struct imx_int_pll_rate_table imx8mm_fracpll_tbl[] = {
+ PLL_1443X_RATE(1039500000U, 693, 4, 2, 0),
PLL_1443X_RATE(1000000000U, 250, 3, 1, 0),
PLL_1443X_RATE(800000000U, 200, 3, 1, 0),
PLL_1443X_RATE(750000000U, 250, 2, 2, 0),
return 0;
}
-#define VIDEO_PLL_RATE 594000000U
+#define VIDEO_PLL_RATE 1039500000U
void mxs_set_lcdclk(uint32_t base_addr, uint32_t freq)
{
debug("mxs_set_lcdclk, pre = %d, post = %d\n", pre, post);
#ifdef CONFIG_IMX8MP
- clock_set_target_val(MEDIA_DISP1_PIX_CLK_ROOT, CLK_ROOT_ON | CLK_ROOT_SOURCE_SEL(1) | CLK_ROOT_PRE_DIV(pre - 1) | CLK_ROOT_POST_DIV(post - 1));
+ clock_set_target_val(MEDIA_DISP2_CLK_ROOT, CLK_ROOT_ON | CLK_ROOT_SOURCE_SEL(1) | CLK_ROOT_PRE_DIV(pre - 1) | CLK_ROOT_POST_DIV(post - 1));
#elif defined(CONFIG_IMX8MN)
clock_set_target_val(DISPLAY_PIXEL_CLK_ROOT, CLK_ROOT_ON | CLK_ROOT_SOURCE_SEL(1) | CLK_ROOT_PRE_DIV(pre - 1) | CLK_ROOT_POST_DIV(post - 1));
#else
if (enable) {
clock_enable(CCGR_DISPMIX, false);
- /* Set Video PLL to 594Mhz, p = 1, m = 99, k = 0, s = 2 */
+ /* Set Video PLL to 1039.5Mhz for LVDS, p = 4, m = 693, k = 0, s = 2 */
fracpll_configure(ANATOP_VIDEO_PLL, VIDEO_PLL_RATE);
- /* 400Mhz */
- clock_set_target_val(MEDIA_AXI_CLK_ROOT, CLK_ROOT_ON | CLK_ROOT_SOURCE_SEL(2) | CLK_ROOT_PRE_DIV(CLK_ROOT_PRE_DIV2));
+ /* 500Mhz */
+ clock_set_target_val(MEDIA_AXI_CLK_ROOT, CLK_ROOT_ON | CLK_ROOT_SOURCE_SEL(1) | CLK_ROOT_PRE_DIV(CLK_ROOT_PRE_DIV2));
/* 200Mhz */
clock_set_target_val(MEDIA_APB_CLK_ROOT, CLK_ROOT_ON | CLK_ROOT_SOURCE_SEL(2) |CLK_ROOT_PRE_DIV(CLK_ROOT_PRE_DIV4));
- /* 27Mhz MIPI DPHY PLL ref from video PLL */
- clock_set_target_val(MEDIA_MIPI_PHY1_REF_CLK_ROOT, CLK_ROOT_ON | CLK_ROOT_SOURCE_SEL(7) |CLK_ROOT_POST_DIV(CLK_ROOT_POST_DIV22));
+ /* 519.75Mhz LVDS PLL ref from video PLL */
+ clock_set_target_val(MEDIA_LDB_CLK_ROOT, CLK_ROOT_ON | CLK_ROOT_SOURCE_SEL(7) |CLK_ROOT_POST_DIV(CLK_ROOT_POST_DIV2));
clock_enable(CCGR_DISPMIX, true);
} else {
clock_enable(CCGR_DISPMIX, false);
CONFIG_DM_VIDEO=y
CONFIG_VIDEO_LCD_RAYDIUM_RM67191=y
CONFIG_VIDEO_ADV7535=y
+CONFIG_VIDEO_IMX8MP_LVDS=y
+CONFIG_VIDEO_IT6263_BRIDGE=y
CONFIG_SYS_WHITE_ON_BLACK=y
CONFIG_SPLASH_SCREEN=y
CONFIG_SPLASH_SCREEN_ALIGN=y
goto fail;
}
- /* Only handle devices that have a valid ofnode */
- if (dev_has_ofnode(dev) && !(dev->driver->flags & DM_FLAG_IGNORE_DEFAULT_CLKS)) {
- /*
- * Process 'assigned-{clocks/clock-parents/clock-rates}'
- * properties
- */
- ret = clk_set_defaults(dev, 0);
- if (ret)
- goto fail;
- }
+ // /* Only handle devices that have a valid ofnode */
+ // if (dev_has_ofnode(dev) && !(dev->driver->flags & DM_FLAG_IGNORE_DEFAULT_CLKS)) {
+ // /*
+ // * Process 'assigned-{clocks/clock-parents/clock-rates}'
+ // * properties
+ // */
+ // ret = clk_set_defaults(dev, 0);
+ // if (ret)
+ // goto fail;
+ // }
if (drv->probe) {
ret = drv->probe(dev);
help
Support for i.MX8 LDVS bridge controller for i.MX8 processors.
+config VIDEO_IMX8MP_LVDS
+ bool "i.MX8MP LDVS bridge support"
+ default n
+ depends on IMX8MP && DM_VIDEO
+ select DISPLAY
+ select VIDEO_LINK
+ help
+ Support for i.MX8MP LDVS bridge controller for i.MX8 processors.
+
config VIDEO_IMX_HDP_LOAD
bool "i.MX8 HDMI/DP firmware loading"
default n
obj-$(CONFIG_VIDEO_SEC_MIPI_DSI) += sec_mipi_dsim.o
obj-$(CONFIG_VIDEO_IMX_SEC_DSI) += sec_dsim_imx.o
obj-$(CONFIG_VIDEO_IMX_LCDIFV3) += imx_lcdifv3.o
+obj-$(CONFIG_VIDEO_IMX8MP_LVDS) += imx8mp_lvds.o
obj-$(CONFIG_VIDEO_NW_MIPI_DSI) += mipi_dsi_northwest.o
obj-$(CONFIG_VIDEO_IMX_NW_DSI) += nw_dsi_imx.o
obj-y += hdmi/
--- /dev/null
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Copyright 2022 NXP
+ */
+#include <common.h>
+#include <clk.h>
+#include <dm.h>
+#include <dm/device_compat.h>
+#include <display.h>
+#include <video.h>
+#include <video_bridge.h>
+#include <video_link.h>
+#include <asm/io.h>
+#include <dm/device-internal.h>
+#include <linux/iopoll.h>
+#include <linux/err.h>
+#include <clk.h>
+
+#include <power-domain.h>
+#include <regmap.h>
+#include <syscon.h>
+
+#define DRIVER_NAME "imx8mp-ldb"
+
+
+#define LVDS_CTRL 0x128
+#define HS_DISABLE (0 << 3)
+#define SPARE_IN(n) (((n) & 0x7) << 25)
+#define SPARE_IN_MASK 0xe000000
+#define TEST_RANDOM_NUM_EN BIT(24)
+#define TEST_MUX_SRC(n) (((n) & 0x3) << 22)
+#define TEST_MUX_SRC_MASK 0xc00000
+#define TEST_EN BIT(21)
+#define TEST_DIV4_EN BIT(20)
+#define VBG_ADJ(n) (((n) & 0x7) << 17)
+#define VBG_ADJ_MASK 0xe0000
+#define SLEW_ADJ(n) (((n) & 0x7) << 14)
+#define SLEW_ADJ_MASK 0x1c000
+#define CC_ADJ(n) (((n) & 0x7) << 11)
+#define CC_ADJ_MASK 0x3800
+#define CM_ADJ(n) (((n) & 0x7) << 8)
+#define CM_ADJ_MASK 0x700
+#define PRE_EMPH_ADJ(n) (((n) & 0x7) << 5)
+#define PRE_EMPH_ADJ_MASK 0xe0
+#define PRE_EMPH_EN BIT(4)
+#define HS_EN BIT(3)
+#define BG_EN BIT(2)
+#define CH_EN BIT(0)
+
+
+#define LDB_CTRL 0x5c
+#define LDB_CH0_MODE_EN_TO_DI0 (1 << 0)
+#define LDB_CH0_MODE_EN_TO_DI1 (3 << 0)
+#define LDB_CH0_MODE_EN_MASK (3 << 0)
+#define LDB_CH1_MODE_EN_TO_DI0 (1 << 2)
+#define LDB_CH1_MODE_EN_TO_DI1 (3 << 2)
+#define LDB_CH1_MODE_EN_MASK (3 << 2)
+#define CH0_DATA_WIDTH_24BIT (1 << 5)
+#define CH0_BIT_MAPPING_JEIDA (1 << 6)
+#define CH0_BIT_MAPPING_SPWG (0 << 6)
+#define LDB_REG_CH0_FIFO_RESET (1 << 11)
+#define LDB_REG_CH1_FIFO_RESET (1 << 12)
+#define LDB_REG_ASYNC_FIFO_EN (1 << 24)
+#define LDB_FIFO_THRESHOLD (4 << 25)
+
+#define CLK_EN 0x4
+
+#define usleep_range(a, b) udelay((b))
+
+#define serial_clk 74250*7000
+
+struct imx8mp_ldb_priv {
+ struct regmap *regmap;
+ struct udevice *conn_dev;
+ unsigned int ldb_id;
+ struct clk *ldb_root_clk;
+ struct clk *apb_root_clk;
+ struct display_timing timings;
+};
+
+
+static inline unsigned int media_blk_read(struct imx8mp_ldb_priv *priv, unsigned int reg)
+{
+ unsigned int val;
+
+ regmap_read(priv->regmap, reg, &val);
+
+ return val;
+}
+
+static inline void media_blk_write(struct imx8mp_ldb_priv *priv, unsigned int reg, unsigned int value)
+{
+ regmap_write(priv->regmap, reg, value);
+}
+
+static int imx8mp_lvds_phy_power_on(struct udevice *dev)
+{
+ struct imx8mp_ldb_priv *priv = dev_get_priv(dev);
+
+ unsigned int val;
+ u32 ldb_ctrl;
+ bool bg_en;
+
+ media_blk_write(priv, LVDS_CTRL, HS_DISABLE);
+
+ val = media_blk_read(priv,LVDS_CTRL);
+ bg_en = !!(val & BG_EN);
+ val |= BG_EN;
+ media_blk_write(priv, LVDS_CTRL, val);
+
+ if (!bg_en){
+ usleep_range(15, 20);
+ }
+
+ val = media_blk_read(priv, LVDS_CTRL);
+ val |= CH_EN;
+ val |= BIT(3);
+ media_blk_write(priv, LVDS_CTRL, val);
+
+ media_blk_write(priv, LDB_CTRL, LDB_CH0_MODE_EN_TO_DI0 | CH0_DATA_WIDTH_24BIT | CH0_BIT_MAPPING_JEIDA);
+
+ usleep_range(5, 10);
+
+ return 0;
+
+}
+
+int imx8mp_ldb_read_timing(struct udevice *dev, struct display_timing *timing)
+{
+ struct imx8mp_ldb_priv *priv = dev_get_priv(dev);
+
+ if (dev->plat_ == NULL)
+ return -EINVAL;
+
+ if (timing) {
+ memcpy(timing, &priv->timings, sizeof(struct display_timing));
+ return 0;
+ }
+
+ return -EINVAL;
+}
+
+static int imx8mp_ldb_probe(struct udevice *dev)
+{
+ struct imx8mp_ldb_priv *priv = dev_get_priv(dev);
+ int ret;
+
+ debug("%s\n", __func__);
+ printf("imx8mp_ldb_probe");
+
+ if (dev->plat_ == NULL) {
+ priv->regmap = syscon_regmap_lookup_by_phandle(dev, "gpr");
+ if (IS_ERR(priv->regmap)) {
+ debug("fail to get fsl,imx8mp-mediamix-blk-ctl regmap\n");
+ return PTR_ERR(priv->regmap);
+ }
+
+ /* Require to add alias in DTB */
+ priv->ldb_id = dev_seq(dev);
+
+ debug("ldb_id %u\n", priv->ldb_id);
+ }else{
+
+ priv->conn_dev = video_link_get_next_device(dev);
+ if (!priv->conn_dev) {
+ debug("can't find next device in video link\n");
+ }
+
+ ret = video_link_get_display_timings(&priv->timings);
+ if (ret) {
+ debug("decode display timing error %d\n", ret);
+ return ret;
+ }
+
+ if(priv->conn_dev && device_get_uclass_id(priv->conn_dev) == UCLASS_PANEL){
+ ret = panel_enable_backlight(priv->conn_dev);
+ if (ret) {
+ dev_err(dev, "fail to enable panel backlight\n");
+ return ret;
+ }
+ ret = panel_set_backlight(priv->conn_dev, 80);
+ if (ret) {
+ dev_err(dev, "fail to set panel backlight\n");
+ return ret;
+ }
+ }
+
+ if (IS_ENABLED(CONFIG_VIDEO_BRIDGE)) {
+ if (priv->conn_dev &&
+ device_get_uclass_id(priv->conn_dev) == UCLASS_VIDEO_BRIDGE) {
+
+ ret = video_bridge_attach(priv->conn_dev);
+ if (ret) {
+ dev_err(dev, "fail to attach bridge\n");
+ return ret;
+ }
+ ret = video_bridge_set_active(priv->conn_dev, true);
+ if (ret) {
+ dev_err(dev, "fail to active bridge\n");
+ return ret;
+ }
+ }
+ }
+ }
+ printf("imx8mp_ldb_probe\n");
+
+ return 0;
+
+}
+
+static int imx8mp_ldb_bind(struct udevice *dev)
+{
+ struct imx8mp_ldb_priv *priv = dev_get_priv(dev);
+ ofnode lvds_ch_node;
+ int ret = 0;
+
+ debug("%s\n", __func__);
+ lvds_ch_node = ofnode_find_subnode(dev_ofnode(dev), "lvds-channel@0");
+ if (ofnode_valid(lvds_ch_node)) {
+ ret = device_bind(dev, dev->driver, "lvds-channel@0", (void *)1,
+ lvds_ch_node, NULL);
+ if (ret)
+ debug("Error binding driver '%s': %d\n", dev->driver->name,
+ ret);
+ }
+
+ return ret;
+}
+
+
+int imx8mp_ldb_enable(struct udevice *dev, int panel_bpp,
+ const struct display_timing *timing)
+{
+ struct imx8mp_ldb_priv *priv = dev_get_priv(dev);
+ int ret;
+ debug("%s\n", __func__);
+
+ if (dev->plat_ == NULL) {
+
+ imx8mp_lvds_phy_power_on(dev);
+ } else {
+ display_enable(dev->parent, panel_bpp, &priv->timings);
+
+ if (IS_ENABLED(CONFIG_VIDEO_BRIDGE)) {
+ if (priv->conn_dev &&
+ device_get_uclass_id(priv->conn_dev) == UCLASS_VIDEO_BRIDGE) {
+ ret = video_bridge_set_backlight(priv->conn_dev, 80);
+ if (ret) {
+ dev_err(dev, "fail to set backlight\n");
+ return ret;
+ }
+ }
+ }
+ }
+
+ return 0;
+
+}
+
+struct dm_display_ops imx8mp_ldb_ops = {
+ .read_timing = imx8mp_ldb_read_timing,
+ .enable = imx8mp_ldb_enable,
+};
+
+static const struct udevice_id imx8mp_ldb_ids[] = {
+ { .compatible = "fsl,imx8mp-ldb" },
+ { }
+};
+
+U_BOOT_DRIVER(imx8mp_ldb) = {
+ .name = "imx8mp_ldb",
+ .id = UCLASS_DISPLAY,
+ .of_match = imx8mp_ldb_ids,
+ .bind = imx8mp_ldb_bind,
+ .probe = imx8mp_ldb_probe,
+ .ops = &imx8mp_ldb_ops,
+ .priv_auto = sizeof(struct imx8mp_ldb_priv),
+};
#include <asm/arch/sys_proto.h>
#include <linux/err.h>
#include <asm/io.h>
+#include <display.h>
#include "../../videomodes.h"
#include <linux/string.h>
writel(CTRL_INV_VS, (ulong)(priv->reg_base + LCDIFV3_CTRL_CLR));
/* SEC MIPI DSI specific */
- writel(CTRL_INV_PXCK, (ulong)(priv->reg_base + LCDIFV3_CTRL_CLR));
- writel(CTRL_INV_DE, (ulong)(priv->reg_base + LCDIFV3_CTRL_CLR));
+ //writel(CTRL_INV_PXCK, (ulong)(priv->reg_base + LCDIFV3_CTRL_CLR));
+ //writel(CTRL_INV_DE, (ulong)(priv->reg_base + LCDIFV3_CTRL_CLR));
}
lcdifv3_of_parse_thres(dev);
- if (priv->disp_dev) {
-#if IS_ENABLED(CONFIG_VIDEO_BRIDGE)
- if (device_get_uclass_id(priv->disp_dev) == UCLASS_VIDEO_BRIDGE) {
- ret = video_bridge_attach(priv->disp_dev);
- if (ret) {
- dev_err(dev, "fail to attach bridge\n");
- return ret;
- }
-
- ret = video_bridge_set_backlight(priv->disp_dev, 80);
- if (ret) {
- dev_err(dev, "fail to set backlight\n");
- return ret;
- }
- }
-#endif
+ printf("lcdifv3_video_probe000\n");
+
+ ret = display_enable(priv->disp_dev, NULL, NULL);
+ if (ret) {
+ debug("%s: Display enable error %d\n", __func__, ret);
+ return ret;
}
mode.xres = timings.hactive.typ;
static const struct udevice_id lcdifv3_video_ids[] = {
{ .compatible = "fsl,imx8mp-lcdif1" },
+ { .compatible = "fsl,imx8mp-lcdif2" },
{ /* sentinel */ }
};