From 17349653415e9c321c4af36cc3decf4a0392b875 Mon Sep 17 00:00:00 2001
From: Zhiming Liu <zhiming.liu_1@nxp.com>
Date: Sat, 1 Jul 2023 13:20:14 +0800
Subject: [PATCH 2/2] Add imx93 lvds and panel driver

---
 arch/arm/dts/imx93-11x11-evk.dts    |  80 +++++++-
 arch/arm/mach-imx/imx9/clock.c      |   6 +-
 configs/imx93_11x11_evk_defconfig   |   7 +
 drivers/video/nxp/imx/Kconfig       |   8 +
 drivers/video/nxp/imx/Makefile      |   1 +
 drivers/video/nxp/imx/imx93_lvds.c  | 291 ++++++++++++++++++++++++++++
 drivers/video/nxp/imx/imx_lcdifv3.c |  55 +++---
 drivers/video/simple_panel.c        |  34 +++-
 8 files changed, 451 insertions(+), 31 deletions(-)
 create mode 100644 drivers/video/nxp/imx/imx93_lvds.c

diff --git a/arch/arm/dts/imx93-11x11-evk.dts b/arch/arm/dts/imx93-11x11-evk.dts
index fabf65bbb0..00a8bec5cf 100644
--- a/arch/arm/dts/imx93-11x11-evk.dts
+++ b/arch/arm/dts/imx93-11x11-evk.dts
@@ -20,6 +20,47 @@
 		i2c8 = &flexio_i2c_master;
 	};
 
+	backlight: backlight {
+		compatible = "pwm-backlight";
+		pwms = <&adp5585 0 100000 0>;
+		enable-gpios = <&adp5585gpio 8 GPIO_ACTIVE_HIGH>;
+		power-supply = <&reg_vdd_12v>;
+		status = "okay";
+
+		brightness-levels = < 0  1  2  3  4  5  6  7  8  9
+				     10 11 12 13 14 15 16 17 18 19
+				     20 21 22 23 24 25 26 27 28 29
+				     30 31 32 33 34 35 36 37 38 39
+				     40 41 42 43 44 45 46 47 48 49
+				     50 51 52 53 54 55 56 57 58 59
+				     60 61 62 63 64 65 66 67 68 69
+				     70 71 72 73 74 75 76 77 78 79
+				     80 81 82 83 84 85 86 87 88 89
+				     90 91 92 93 94 95 96 97 98 99
+				    100>;
+		default-brightness-level = <80>;
+	};
+
+	lvds_panel {
+		compatible = "boe,ev121wxm-n10-1850";
+		backlight = <&backlight>;
+
+
+		port {
+			panel_lvds_in: endpoint {
+				remote-endpoint = <&lvds_out>;
+			};
+		};
+	};
+
+	//fake adp5585 pwm
+	adp5585: adp5585pwm@34 {
+		compatible = "adp5585pwm";
+		reg = <0x34>;
+		#pwm-cells = <3>;
+		status = "okay";
+	};
+
 	reserved-memory {
 		#address-cells = <2>;
 		#size-cells = <2>;
@@ -57,6 +98,15 @@
 		reset-gpios = <&pcal6524 20 GPIO_ACTIVE_LOW>;
 	};
 
+	reg_vdd_12v: regulator-vdd-12v {
+		compatible = "regulator-fixed";
+		regulator-name = "reg_vdd_12v";
+		regulator-min-microvolt = <12000000>;
+		regulator-max-microvolt = <12000000>;
+		gpio = <&pcal6524 14 GPIO_ACTIVE_HIGH>;
+		enable-active-high;
+	};
+
 	reg_vref_1v8: regulator-adc-vref {
 		compatible = "regulator-fixed";
 		regulator-name = "vref_1v8";
@@ -90,11 +140,11 @@
 };
 
 &dphy {
-	status = "okay";
+	status = "disabled";
 };
 
 &dsi {
-	status = "okay";
+	status = "disabled";
 
 	ports {
 		port@1 {
@@ -111,9 +161,30 @@
 	};
 };
 
+&ldb_phy {
+	status = "okay";
+};
+
+&ldb {
+	status = "okay";
+
+	lvds-channel@0 {
+		status = "okay";
+
+		port@1 {
+			reg = <1>;
+
+			lvds_out: endpoint {
+				remote-endpoint = <&panel_lvds_in>;
+			};
+		};
+	};
+};
+
+
 &lcdif {
 	status = "okay";
-	assigned-clock-rates = <484000000>, <121000000>, <400000000>, <133333333>;
+	assigned-clock-rates = <498000000>, <71142857>, <400000000>, <133333333>;
 };
 
 &lpi2c1 {
@@ -130,7 +201,7 @@
 		reg = <0x3d>;
 		adi,addr-cec = <0x3c>;
 		adi,dsi-lanes = <4>;
-		status = "okay";
+		status = "disabled";
 
 		port {
 			adv7535_to_dsi: endpoint {
@@ -260,6 +331,7 @@
 		gpio-controller;
 		#gpio-cells = <2>;
 	};
+
 };
 
 &lpi2c3 {
diff --git a/arch/arm/mach-imx/imx9/clock.c b/arch/arm/mach-imx/imx9/clock.c
index 3e2c395988..6fa4ebec3d 100644
--- a/arch/arm/mach-imx/imx9/clock.c
+++ b/arch/arm/mach-imx/imx9/clock.c
@@ -36,6 +36,7 @@ static struct imx_fracpll_rate_table imx9_fracpll_tbl[] = {
 	FRAC_PLL_RATE(1000000000U, 1, 166, 4, 2, 3), /* 1000Mhz */
 	FRAC_PLL_RATE(933000000U, 1, 155, 4, 1, 2), /* 933Mhz */
 	FRAC_PLL_RATE(700000000U, 1, 145, 5, 5, 6), /* 700Mhz */
+	FRAC_PLL_RATE(498000000U, 1, 166, 8, 0, 1),/* rate, rdiv, mfi, odiv, mfn, mfd */
 	FRAC_PLL_RATE(484000000U, 1, 121, 6, 0, 1),
 	FRAC_PLL_RATE(445333333U, 1, 167, 9, 0, 1),
 	FRAC_PLL_RATE(466000000U, 1, 155, 8, 1, 3), /* 466Mhz */
@@ -904,9 +905,12 @@ void mxs_set_lcdclk(u32 base_addr, u32 freq)
 
 	/* Select to video PLL */
 	debug("%s, best_pll = %u, div = %u\n", __func__, best_pll, best_div);
-
+	//VIDEO_PLL_CLK      ==> pixel clock * 7
 	configure_fracpll(VIDEO_PLL_CLK, best_pll);
+	//MEDIA_DISP_PIX_CLK ==> pixel clock ==> 71.143MHz
 	ccm_clk_root_cfg(MEDIA_DISP_PIX_CLK_ROOT, VIDEO_PLL_CLK, best_div);
+	//MEDIA_LDB_CLK_ROOT ==> pixel clock * 7
+	ccm_clk_root_cfg(MEDIA_LDB_CLK_ROOT, VIDEO_PLL_CLK, 1);
 }
 
 /*
diff --git a/configs/imx93_11x11_evk_defconfig b/configs/imx93_11x11_evk_defconfig
index cb8619c8fe..d2fdf589b8 100644
--- a/configs/imx93_11x11_evk_defconfig
+++ b/configs/imx93_11x11_evk_defconfig
@@ -168,6 +168,11 @@ CONFIG_PHY_IMX93_MIPI_DPHY=y
 CONFIG_MIPI_DPHY_HELPERS=y
 CONFIG_VIDEO_IMX_LCDIFV3=y
 CONFIG_VIDEO_IMX_DW_DSI=y
+CONFIG_VIDEO_IMX93_LVDS=y
+CONFIG_DM_PWM=y
+CONFIG_PWM_ADP5585=y
+CONFIG_BACKLIGHT=y
+CONFIG_BACKLIGHT_PWM=y
 CONFIG_DM_VIDEO=y
 CONFIG_BMP_16BPP=y
 CONFIG_BMP_24BPP=y
@@ -179,6 +184,8 @@ CONFIG_SYS_WHITE_ON_BLACK=y
 CONFIG_SPLASH_SCREEN=y
 CONFIG_SPLASH_SCREEN_ALIGN=y
 CONFIG_CMD_BMP=y
+CONFIG_SIMPLE_PANEL=y
+
 
 CONFIG_CMD_DEKBLOB=y
 CONFIG_IMX_ELE_DEK_ENCAP=y
diff --git a/drivers/video/nxp/imx/Kconfig b/drivers/video/nxp/imx/Kconfig
index 1824b969fb..5ddc76cbb6 100644
--- a/drivers/video/nxp/imx/Kconfig
+++ b/drivers/video/nxp/imx/Kconfig
@@ -34,6 +34,14 @@ config VIDEO_IMX8_LVDS
 	help
 	  Support for i.MX8 LDVS bridge controller for i.MX8 processors.
 
+config VIDEO_IMX93_LVDS
+	bool "i.MX93 LDVS bridge support"
+	default n
+	depends on IMX93 && DM_VIDEO
+	select DISPLAY
+	select VIDEO_LINK
+	help
+	  Support for i.MX93 LDVS bridge controller for i.MX9 processors.
 config VIDEO_IMX_HDP_LOAD
 	bool "i.MX8 HDMI/DP firmware loading"
 	default n
diff --git a/drivers/video/nxp/imx/Makefile b/drivers/video/nxp/imx/Makefile
index 019789fe0c..4b8ffc103b 100644
--- a/drivers/video/nxp/imx/Makefile
+++ b/drivers/video/nxp/imx/Makefile
@@ -7,6 +7,7 @@ obj-$(CONFIG_VIDEO_IPUV3) += mxc_ipuv3_fb.o ipu_common.o ipu_disp.o
 obj-$(CONFIG_VIDEO_IMXDPUV1) += imxdpuv1.o imx8_dc.o
 obj-$(CONFIG_VIDEO_IMX6SX_LVDS) += imx6sx_ldb.o
 obj-$(CONFIG_VIDEO_IMX8_LVDS) += imx8_lvds.o
+obj-$(CONFIG_VIDEO_IMX93_LVDS) += imx93_lvds.o
 obj-$(CONFIG_VIDEO_IMX8M_DCSS) += imx8m_dcss.o
 obj-$(CONFIG_VIDEO_SEC_MIPI_DSI) += sec_mipi_dsim.o
 obj-$(CONFIG_VIDEO_IMX_SEC_DSI) += sec_dsim_imx.o
diff --git a/drivers/video/nxp/imx/imx93_lvds.c b/drivers/video/nxp/imx/imx93_lvds.c
new file mode 100644
index 0000000000..65b821c7f4
--- /dev/null
+++ b/drivers/video/nxp/imx/imx93_lvds.c
@@ -0,0 +1,291 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Copyright 2023 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 "imx93-ldb"
+
+
+#define LVDS_CTRL		0x24
+#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		0x20
+#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 msleep(a)			udelay(a * 1000)
+
+/* 71143Khz should be replaced with your panel pixel clock */
+#define serial_clk 71143*7000
+
+struct imx93_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;
+	void __iomem *base;
+};
+
+static inline unsigned int media_blk_read(struct imx93_ldb_priv *priv, unsigned int reg)
+{
+	unsigned int val;
+	readsl(priv->base + reg, &val, 32);
+
+	return val;
+}
+
+static inline void media_blk_write(struct imx93_ldb_priv *priv, unsigned int reg, unsigned int value)
+{
+	setbits_le32(priv->base + reg, value);
+}
+
+static int imx93_lvds_phy_power_on(struct udevice *dev)
+{
+	struct imx93_ldb_priv *priv = dev_get_priv(dev);
+
+	unsigned int lvds_val, ldb_val;
+	u32 ldb_ctrl;
+	int ret;
+	bool bg_en;
+	debug("%s\n", __func__);
+
+    /* LVDS_CTRL */
+	media_blk_write(priv, LVDS_CTRL, HS_DISABLE);
+
+	lvds_val = media_blk_read(priv, LVDS_CTRL);
+	bg_en = !!(lvds_val & BG_EN);
+	lvds_val |= BG_EN;
+	media_blk_write(priv, LVDS_CTRL, lvds_val);
+
+	if (!bg_en){
+		usleep_range(15, 20);
+	}
+
+	lvds_val = media_blk_read(priv, LVDS_CTRL);
+	lvds_val |= CH_EN | CC_ADJ(0x2) | PRE_EMPH_EN | PRE_EMPH_ADJ(0x3);
+	media_blk_write(priv, LVDS_CTRL, lvds_val);
+
+	/* read final LVDS_CTRL value for debug*/
+	lvds_val = media_blk_read(priv, LVDS_CTRL);
+	debug("read lvds_val: 0x%d\n",lvds_val);
+
+    /* LDB_CTRL */
+    ldb_val &= ~LDB_CH0_MODE_EN_MASK;
+    ldb_val |= LDB_CH0_MODE_EN_TO_DI0 | CH0_DATA_WIDTH_24BIT;
+	media_blk_write(priv, LDB_CTRL, ldb_val);
+
+	/* read final LDB_CTRL value for debug*/
+	ldb_val = media_blk_read(priv, LDB_CTRL);
+	debug("read ldb_val: 0x%d\n",ldb_val);
+
+	usleep_range(5, 10);
+
+	return 0;
+
+}
+
+int imx93_ldb_read_timing(struct udevice *dev, struct display_timing *timing)
+{
+	struct imx93_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 imx93_ldb_probe(struct udevice *dev)
+{
+	struct imx93_ldb_priv *priv = dev_get_priv(dev);
+	int ret;
+
+	debug("%s\n", __func__);
+
+	if (dev->plat_ == NULL) {
+		priv->base = 0x4ac10000;//media blk base address
+
+		/* 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;
+			}
+			// fake pwm-adp5585 driver, so we can't use real pwm
+			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;
+				}
+			}
+		}
+	}
+
+	return 0;
+
+}
+
+static int imx93_ldb_bind(struct udevice *dev)
+{
+	struct imx93_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 imx93_ldb_enable(struct udevice *dev, int panel_bpp,
+		      const struct display_timing *timing)
+{
+	struct imx93_ldb_priv *priv = dev_get_priv(dev);
+	int ret;
+	debug("%s\n", __func__);
+
+	if (dev->plat_ == NULL) {
+
+		imx93_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 imx93_ldb_ops = {
+	.read_timing = imx93_ldb_read_timing,
+	.enable = imx93_ldb_enable,
+};
+
+static const struct udevice_id imx93_ldb_ids[] = {
+	{ .compatible = "fsl,imx93-ldb" },
+	{ }
+};
+
+U_BOOT_DRIVER(imx93_ldb) = {
+	.name				= "imx93_ldb",
+	.id				= UCLASS_DISPLAY,
+	.of_match			= imx93_ldb_ids,
+	.bind				= imx93_ldb_bind,
+	.probe				= imx93_ldb_probe,
+	.ops				= &imx93_ldb_ops,
+	.priv_auto		= sizeof(struct imx93_ldb_priv),
+	.flags 			= DM_FLAG_DEFAULT_PD_CTRL_OFF,
+};
\ No newline at end of file
diff --git a/drivers/video/nxp/imx/imx_lcdifv3.c b/drivers/video/nxp/imx/imx_lcdifv3.c
index 66e6ad6a86..011b2a3fb5 100644
--- a/drivers/video/nxp/imx/imx_lcdifv3.c
+++ b/drivers/video/nxp/imx/imx_lcdifv3.c
@@ -28,6 +28,7 @@
 #include <dm.h>
 #include <dm/device-internal.h>
 #include <dm/device_compat.h>
+#include <display.h>
 
 #define	PS2KHZ(ps)	(1000000000UL / (ps))
 #define HZ2PS(hz)	(1000000000UL / ((hz) / 1000))
@@ -110,8 +111,9 @@ static void lcdifv3_set_mode(struct lcdifv3_priv *priv,
 		writel(CTRL_INV_HS, (ulong)(priv->reg_base + LCDIFV3_CTRL_SET));
 
 	/* 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));
+	// comment CTRL_INV_DE, the default CTRL_INV_DE is DE->HIGH ACTIVE
+	// writel(CTRL_INV_PXCK, (ulong)(priv->reg_base + LCDIFV3_CTRL_CLR));
+	// writel(CTRL_INV_DE, (ulong)(priv->reg_base + LCDIFV3_CTRL_CLR));
 
 }
 
@@ -350,28 +352,33 @@ static int lcdifv3_video_probe(struct udevice *dev)
 
 	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_check_timing(priv->disp_dev, &timings);
-			if (ret) {
-				dev_err(dev, "fail to check timing\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
+// 	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_check_timing(priv->disp_dev, &timings);
+// 			if (ret) {
+// 				dev_err(dev, "fail to check timing\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
+// 	}
+	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;
diff --git a/drivers/video/simple_panel.c b/drivers/video/simple_panel.c
index f9281d5e83..692c96dcaa 100644
--- a/drivers/video/simple_panel.c
+++ b/drivers/video/simple_panel.c
@@ -18,12 +18,27 @@ struct simple_panel_priv {
 	struct gpio_desc enable;
 };
 
+/* define your panel timing here and
+ * copy it in simple_panel_get_display_timing */
+static const struct display_timing boe_ev121wxm_n10_1850_timing = {
+	.pixelclock.typ		= 71143000,
+	.hactive.typ		= 1280,
+	.hfront_porch.typ	= 32,
+	.hback_porch.typ	= 80,
+	.hsync_len.typ		= 48,
+	.vactive.typ		= 800,
+	.vfront_porch.typ	= 6,
+	.vback_porch.typ	= 14,
+	.vsync_len.typ		= 3,
+};
+
 static int simple_panel_enable_backlight(struct udevice *dev)
 {
 	struct simple_panel_priv *priv = dev_get_priv(dev);
 	int ret;
+	debug("%s\n", __func__);
 
-	dm_gpio_set_value(&priv->enable, 1);
+	//dm_gpio_set_value(&priv->enable, 1);
 	if (priv->backlight) {
 		debug("%s: start, backlight = '%s'\n", __func__, priv->backlight->name);
 		ret = backlight_enable(priv->backlight);
@@ -40,8 +55,10 @@ static int simple_panel_set_backlight(struct udevice *dev, int percent)
 	struct simple_panel_priv *priv = dev_get_priv(dev);
 	int ret;
 
+	debug("%s\n", __func__);
+
 	debug("%s: start, backlight = '%s'\n", __func__, priv->backlight->name);
-	dm_gpio_set_value(&priv->enable, 1);
+	//dm_gpio_set_value(&priv->enable, 1);
 	if (priv->backlight) {
 		ret = backlight_set_brightness(priv->backlight, percent);
 		debug("%s: done, ret = %d\n", __func__, ret);
@@ -57,6 +74,8 @@ static int simple_panel_of_to_plat(struct udevice *dev)
 	struct simple_panel_priv *priv = dev_get_priv(dev);
 	int ret;
 
+	debug("%s\n", __func__);
+
 	if (IS_ENABLED(CONFIG_DM_REGULATOR)) {
 		ret = uclass_get_device_by_phandle(UCLASS_REGULATOR, dev,
 						   "power-supply", &priv->reg);
@@ -91,6 +110,8 @@ static int simple_panel_probe(struct udevice *dev)
 	struct simple_panel_priv *priv = dev_get_priv(dev);
 	int ret;
 
+	debug("%s\n", __func__);
+
 	if (IS_ENABLED(CONFIG_DM_REGULATOR) && priv->reg) {
 		debug("%s: Enable regulator '%s'\n", __func__, priv->reg->name);
 		ret = regulator_set_enable(priv->reg, true);
@@ -100,10 +121,18 @@ static int simple_panel_probe(struct udevice *dev)
 
 	return 0;
 }
+static int simple_panel_get_display_timing(struct udevice *dev,
+					    struct display_timing *timings)
+{
+	memcpy(timings, &boe_ev121wxm_n10_1850_timing, sizeof(*timings));
+
+	return 0;
+}
 
 static const struct panel_ops simple_panel_ops = {
 	.enable_backlight	= simple_panel_enable_backlight,
 	.set_backlight		= simple_panel_set_backlight,
+	.get_display_timing = simple_panel_get_display_timing,
 };
 
 static const struct udevice_id simple_panel_ids[] = {
@@ -115,6 +144,7 @@ static const struct udevice_id simple_panel_ids[] = {
 	{ .compatible = "lg,lb070wv8" },
 	{ .compatible = "sharp,lq123p1jx31" },
 	{ .compatible = "boe,nv101wxmn51" },
+	{ .compatible = "boe,ev121wxm-n10-1850" },
 	{ }
 };
 
-- 
2.34.1

