[PATCH v6 23/28] video: omap: add panel driver

Dario Binacchi dariobin at libero.it
Sun Nov 22 17:16:31 CET 2020


The previous version of am335x-fb.c contained the functionalities of two
drivers that this patch has split. It was a video type driver that used
the same registration compatible string that now registers a panel type
driver. The proof of this is that two compatible strings were referred
to within the same driver.
There are now two drivers, each with its own compatible string,
functions and API.
Furthermore, the panel driver, in addition to decoding the display
timings, is now also able to manage the backlight.

Signed-off-by: Dario Binacchi <dariobin at libero.it>
Reviewed-by: Simon Glass <sjg at chromium.org>

---

(no changes since v4)

Changes in v4:
- Include device_compat.h header for dev_xxx macros.
- Add Simon Glass review.

Changes in v3:
- Update the DTS lcdc node of the am335x boards because of the
  am33xx.dtsi resynced with Linux 5.9-rc7.

 arch/arm/dts/am335x-brppt1-mmc.dts       |  17 +-
 arch/arm/dts/am335x-brppt1-nand.dts      |  17 +-
 arch/arm/dts/am335x-brppt1-spi.dts       |  17 +-
 arch/arm/dts/am335x-brsmarc1.dts         |  20 +-
 arch/arm/dts/am335x-brxre1.dts           |  21 +-
 arch/arm/dts/am335x-evm-u-boot.dtsi      |  15 +-
 arch/arm/dts/am335x-evmsk-u-boot.dtsi    |  14 +-
 arch/arm/dts/am335x-guardian-u-boot.dtsi |  18 +-
 arch/arm/dts/am335x-pdu001-u-boot.dtsi   |  18 +-
 arch/arm/dts/am335x-pxm50-u-boot.dtsi    |  14 +-
 arch/arm/dts/am335x-rut-u-boot.dtsi      |  14 +-
 arch/arm/dts/da850-evm-u-boot.dtsi       |  18 +-
 drivers/video/Makefile                   |   1 +
 drivers/video/am335x-fb.c                | 255 ++++++++++-------------
 drivers/video/am335x-fb.h                |  31 +++
 drivers/video/tilcdc-panel.c             | 172 +++++++++++++++
 drivers/video/tilcdc-panel.h             |  14 ++
 17 files changed, 478 insertions(+), 198 deletions(-)
 create mode 100644 drivers/video/tilcdc-panel.c
 create mode 100644 drivers/video/tilcdc-panel.h

diff --git a/arch/arm/dts/am335x-brppt1-mmc.dts b/arch/arm/dts/am335x-brppt1-mmc.dts
index 6f919711f0..bd2f6c2e3e 100644
--- a/arch/arm/dts/am335x-brppt1-mmc.dts
+++ b/arch/arm/dts/am335x-brppt1-mmc.dts
@@ -53,8 +53,6 @@
 		bkl-pwm = <&pwmbacklight>;
 		bkl-tps = <&tps_bl>;
 
-		u-boot,dm-pre-reloc;
-
 		panel-info {
 			ac-bias		= <255>;
 			ac-bias-intrpt	= <0>;
@@ -238,8 +236,19 @@
 	status = "okay";
 };
 
-&lcdc {
-	status = "disabled";
+&l4_per {
+
+	segment at 300000 {
+
+		target-module at e000 {
+			u-boot,dm-pre-reloc;
+
+			lcdc: lcdc at 0 {
+				u-boot,dm-pre-reloc;
+				status = "disabled";
+			};
+		};
+	};
 };
 
 &elm {
diff --git a/arch/arm/dts/am335x-brppt1-nand.dts b/arch/arm/dts/am335x-brppt1-nand.dts
index 9d4340f591..67c609739f 100644
--- a/arch/arm/dts/am335x-brppt1-nand.dts
+++ b/arch/arm/dts/am335x-brppt1-nand.dts
@@ -53,8 +53,6 @@
 		bkl-pwm = <&pwmbacklight>;
 		bkl-tps = <&tps_bl>;
 
-		u-boot,dm-pre-reloc;
-
 		panel-info {
 			ac-bias		= <255>;
 			ac-bias-intrpt	= <0>;
@@ -228,8 +226,19 @@
 	status = "disabled";
 };
 
-&lcdc {
-	status = "disabled";
+&l4_per {
+
+	segment at 300000 {
+
+		target-module at e000 {
+			u-boot,dm-pre-reloc;
+
+			lcdc: lcdc at 0 {
+				u-boot,dm-pre-reloc;
+				status = "disabled";
+			};
+		};
+	};
 };
 
 &elm {
diff --git a/arch/arm/dts/am335x-brppt1-spi.dts b/arch/arm/dts/am335x-brppt1-spi.dts
index c078af8fba..ce3dce204d 100644
--- a/arch/arm/dts/am335x-brppt1-spi.dts
+++ b/arch/arm/dts/am335x-brppt1-spi.dts
@@ -54,8 +54,6 @@
 		bkl-pwm = <&pwmbacklight>;
 		bkl-tps = <&tps_bl>;
 
-		u-boot,dm-pre-reloc;
-
 		panel-info {
 			ac-bias		= <255>;
 			ac-bias-intrpt	= <0>;
@@ -259,8 +257,19 @@
 	status = "okay";
 };
 
-&lcdc {
-	status = "disabled";
+&l4_per {
+
+	segment at 300000 {
+
+		target-module at e000 {
+			u-boot,dm-pre-reloc;
+
+			lcdc: lcdc at 0 {
+				u-boot,dm-pre-reloc;
+				status = "disabled";
+			};
+		};
+	};
 };
 
 &elm {
diff --git a/arch/arm/dts/am335x-brsmarc1.dts b/arch/arm/dts/am335x-brsmarc1.dts
index 7e9516e8f8..25cdb11164 100644
--- a/arch/arm/dts/am335x-brsmarc1.dts
+++ b/arch/arm/dts/am335x-brsmarc1.dts
@@ -59,7 +59,6 @@
 		/*backlight = <&tps_bl>; */
 		compatible = "ti,tilcdc,panel";
 		status = "okay";
-		u-boot,dm-pre-reloc;
 
 		panel-info {
 			ac-bias		= <255>;
@@ -298,10 +297,21 @@
 	status = "okay";
 };
 
-&lcdc {
-	status = "okay";
-	ti,no-reset-on-init;
-	ti,no-idle-on-init;
+&l4_per {
+
+	segment at 300000 {
+
+		target-module at e000 {
+			u-boot,dm-pre-reloc;
+
+			lcdc: lcdc at 0 {
+				u-boot,dm-pre-reloc;
+				status = "okay";
+				ti,no-reset-on-init;
+				ti,no-idle-on-init;
+			};
+		};
+	};
 };
 
 &elm {
diff --git a/arch/arm/dts/am335x-brxre1.dts b/arch/arm/dts/am335x-brxre1.dts
index 6091a12fb7..485c8e3613 100644
--- a/arch/arm/dts/am335x-brxre1.dts
+++ b/arch/arm/dts/am335x-brxre1.dts
@@ -79,8 +79,6 @@
 
 		backlight = <&tps_bl>;
 
-		u-boot,dm-pre-reloc;
-
 		panel-info {
 			ac-bias		= <255>;
 			ac-bias-intrpt	= <0>;
@@ -254,10 +252,21 @@
 	status = "okay";
 };
 
-&lcdc {
-	status = "okay";
-	ti,no-reset-on-init;
-	ti,no-idle-on-init;
+&l4_per {
+
+	segment at 300000 {
+
+		target-module at e000 {
+			u-boot,dm-pre-reloc;
+
+			lcdc: lcdc at 0 {
+				u-boot,dm-pre-reloc;
+				status = "okay";
+				ti,no-reset-on-init;
+				ti,no-idle-on-init;
+			};
+		};
+	};
 };
 
 &elm {
diff --git a/arch/arm/dts/am335x-evm-u-boot.dtsi b/arch/arm/dts/am335x-evm-u-boot.dtsi
index 400a1d2cec..4cf5f9928d 100644
--- a/arch/arm/dts/am335x-evm-u-boot.dtsi
+++ b/arch/arm/dts/am335x-evm-u-boot.dtsi
@@ -5,13 +5,20 @@
 
 #include "am33xx-u-boot.dtsi"
 
-/ {
-	panel {
-		u-boot,dm-pre-reloc;
+&l4_per {
+
+	segment at 300000 {
+
+		target-module at e000 {
+			u-boot,dm-pre-reloc;
+
+			lcdc: lcdc at 0 {
+				u-boot,dm-pre-reloc;
+			};
+		};
 	};
 };
 
-
 &mmc3 {
 	status = "disabled";
 };
diff --git a/arch/arm/dts/am335x-evmsk-u-boot.dtsi b/arch/arm/dts/am335x-evmsk-u-boot.dtsi
index 96798330b1..1003f4d31a 100644
--- a/arch/arm/dts/am335x-evmsk-u-boot.dtsi
+++ b/arch/arm/dts/am335x-evmsk-u-boot.dtsi
@@ -7,8 +7,16 @@
 
 #include "am33xx-u-boot.dtsi"
 
-/ {
-	panel {
-		u-boot,dm-pre-reloc;
+&l4_per {
+
+	segment at 300000 {
+
+		target-module at e000 {
+			u-boot,dm-pre-reloc;
+
+			lcdc: lcdc at 0 {
+				u-boot,dm-pre-reloc;
+			};
+		};
 	};
 };
diff --git a/arch/arm/dts/am335x-guardian-u-boot.dtsi b/arch/arm/dts/am335x-guardian-u-boot.dtsi
index c866ce83f3..986f58e664 100644
--- a/arch/arm/dts/am335x-guardian-u-boot.dtsi
+++ b/arch/arm/dts/am335x-guardian-u-boot.dtsi
@@ -10,16 +10,26 @@
 	ocp {
 		u-boot,dm-pre-reloc;
 	};
-
-	panel {
-		u-boot,dm-pre-reloc;
-	};
 };
 
 &l4_wkup {
 	u-boot,dm-pre-reloc;
 };
 
+&l4_per {
+
+	segment at 300000 {
+
+		target-module at e000 {
+			u-boot,dm-pre-reloc;
+
+			lcdc: lcdc at 0 {
+				u-boot,dm-pre-reloc;
+			};
+		};
+	};
+};
+
 &mmc1 {
 	u-boot,dm-pre-reloc;
 };
diff --git a/arch/arm/dts/am335x-pdu001-u-boot.dtsi b/arch/arm/dts/am335x-pdu001-u-boot.dtsi
index 4f4fc411f9..686a152fd9 100644
--- a/arch/arm/dts/am335x-pdu001-u-boot.dtsi
+++ b/arch/arm/dts/am335x-pdu001-u-boot.dtsi
@@ -9,16 +9,26 @@
 	ocp {
 		u-boot,dm-pre-reloc;
 	};
-
-	panel {
-		u-boot,dm-pre-reloc;
-	};
 };
 
 &l4_wkup {
 	u-boot,dm-pre-reloc;
 };
 
+&l4_per {
+
+	segment at 300000 {
+
+		target-module at e000 {
+			u-boot,dm-pre-reloc;
+
+			lcdc: lcdc at 0 {
+				u-boot,dm-pre-reloc;
+			};
+		};
+	};
+};
+
 &scm {
 	u-boot,dm-pre-reloc;
 };
diff --git a/arch/arm/dts/am335x-pxm50-u-boot.dtsi b/arch/arm/dts/am335x-pxm50-u-boot.dtsi
index 65ed948c58..e5af9fdf89 100644
--- a/arch/arm/dts/am335x-pxm50-u-boot.dtsi
+++ b/arch/arm/dts/am335x-pxm50-u-boot.dtsi
@@ -7,8 +7,16 @@
 
 #include "am33xx-u-boot.dtsi"
 
-/ {
-	panel {
-		u-boot,dm-pre-reloc;
+&l4_per {
+
+	segment at 300000 {
+
+		target-module at e000 {
+			u-boot,dm-pre-reloc;
+
+			lcdc: lcdc at 0 {
+				u-boot,dm-pre-reloc;
+			};
+		};
 	};
 };
diff --git a/arch/arm/dts/am335x-rut-u-boot.dtsi b/arch/arm/dts/am335x-rut-u-boot.dtsi
index b16f75a764..a38c2dc607 100644
--- a/arch/arm/dts/am335x-rut-u-boot.dtsi
+++ b/arch/arm/dts/am335x-rut-u-boot.dtsi
@@ -7,8 +7,16 @@
 
 #include "am33xx-u-boot.dtsi"
 
-/ {
-	panel {
-		u-boot,dm-pre-reloc;
+&l4_per {
+
+	segment at 300000 {
+
+		target-module at e000 {
+			u-boot,dm-pre-reloc;
+
+			lcdc: lcdc at 0 {
+				u-boot,dm-pre-reloc;
+			};
+		};
 	};
 };
diff --git a/arch/arm/dts/da850-evm-u-boot.dtsi b/arch/arm/dts/da850-evm-u-boot.dtsi
index d588628641..020b9eb563 100644
--- a/arch/arm/dts/da850-evm-u-boot.dtsi
+++ b/arch/arm/dts/da850-evm-u-boot.dtsi
@@ -14,10 +14,6 @@
 	nand {
 		compatible = "ti,davinci-nand";
 	};
-
-	panel {
-		u-boot,dm-pre-reloc;
-	};
 };
 
 &eth0 {
@@ -28,6 +24,20 @@
 	compatible = "m25p64", "jedec,spi-nor";
 };
 
+&l4_per {
+
+	segment at 300000 {
+
+		target-module at e000 {
+			u-boot,dm-pre-reloc;
+
+			lcdc: lcdc at 0 {
+				u-boot,dm-pre-reloc;
+			};
+		};
+	};
+};
+
 &mmc0 {
 	u-boot,dm-spl;
 };
diff --git a/drivers/video/Makefile b/drivers/video/Makefile
index 67a492a2d6..132a63ecea 100644
--- a/drivers/video/Makefile
+++ b/drivers/video/Makefile
@@ -16,6 +16,7 @@ obj-$(CONFIG_DM_VIDEO) += video-uclass.o vidconsole-uclass.o
 obj-$(CONFIG_DM_VIDEO) += video_bmp.o
 obj-$(CONFIG_PANEL) += panel-uclass.o
 obj-$(CONFIG_SIMPLE_PANEL) += simple_panel.o
+obj-$(CONFIG_AM335X_LCD) += tilcdc-panel.o
 endif
 
 obj-${CONFIG_EXYNOS_FB} += exynos/
diff --git a/drivers/video/am335x-fb.c b/drivers/video/am335x-fb.c
index 2707ff59c7..dc959baa27 100644
--- a/drivers/video/am335x-fb.c
+++ b/drivers/video/am335x-fb.c
@@ -15,6 +15,7 @@
 #include <dm.h>
 #include <lcd.h>
 #include <log.h>
+#include <panel.h>
 #include <video.h>
 #include <asm/arch/clock.h>
 #include <asm/arch/hardware.h>
@@ -25,6 +26,7 @@
 #include <linux/delay.h>
 #include <linux/err.h>
 #include "am335x-fb.h"
+#include "tilcdc-panel.h"
 
 #define LCDC_FMAX				200000000
 
@@ -323,7 +325,7 @@ int am335xfb_init(struct am335x_lcdpanel *panel)
 
 #else /* CONFIG_DM_VIDEO */
 
-#define FBSIZE(t, p)	(((t)->hactive.typ * (t)->vactive.typ * (p)->bpp) >> 3)
+#define FBSIZE(t, p)	(((t).hactive.typ * (t).vactive.typ * (p).bpp) >> 3)
 
 enum {
 	LCD_MAX_WIDTH		= 2048,
@@ -331,39 +333,8 @@ enum {
 	LCD_MAX_LOG2_BPP	= VIDEO_BPP32,
 };
 
-/**
- * tilcdc_panel_info: Panel parameters
- *
- * @ac_bias: AC Bias Pin Frequency
- * @ac_bias_intrpt: AC Bias Pin Transitions per Interrupt
- * @dma_burst_sz: DMA burst size
- * @bpp: Bits per pixel
- * @fdd: FIFO DMA Request Delay
- * @tft_alt_mode: TFT Alternative Signal Mapping (Only for active)
- * @invert_pxl_clk: Invert pixel clock
- * @sync_edge: Horizontal and Vertical Sync Edge: 0=rising 1=falling
- * @sync_ctrl: Horizontal and Vertical Sync: Control: 0=ignore
- * @raster_order: Raster Data Order Select: 1=Most-to-least 0=Least-to-most
- * @fifo_th: DMA FIFO threshold
- */
-struct tilcdc_panel_info {
-	u32 ac_bias;
-	u32 ac_bias_intrpt;
-	u32 dma_burst_sz;
-	u32 bpp;
-	u32 fdd;
-	bool tft_alt_mode;
-	bool invert_pxl_clk;
-	u32 sync_edge;
-	u32 sync_ctrl;
-	u32 raster_order;
-	u32 fifo_th;
-};
-
 struct am335x_fb_priv {
 	struct am335x_lcdhw *regs;
-	struct tilcdc_panel_info panel;
-	struct display_timing timing;
 };
 
 static int am335x_fb_remove(struct udevice *dev)
@@ -381,16 +352,71 @@ static int am335x_fb_probe(struct udevice *dev)
 	struct video_priv *uc_priv = dev_get_uclass_priv(dev);
 	struct am335x_fb_priv *priv = dev_get_priv(dev);
 	struct am335x_lcdhw *regs = priv->regs;
-	struct tilcdc_panel_info *panel = &priv->panel;
-	struct display_timing *timing = &priv->timing;
+	struct udevice *panel;
+	struct tilcdc_panel_info info;
+	struct display_timing timing;
 	struct cm_dpll *const cmdpll = (struct cm_dpll *)CM_DPLL;
 	u32 reg;
+	int err;
 
 	/* Before relocation we don't need to do anything */
 	if (!(gd->flags & GD_FLG_RELOC))
 		return 0;
 
-	am335x_fb_set_pixel_clk_rate(regs, timing->pixelclock.typ);
+	err = uclass_get_device(UCLASS_PANEL, 0, &panel);
+	if (err) {
+		dev_err(dev, "failed to get panel\n");
+		return err;
+	}
+
+	err = panel_get_display_timing(panel, &timing);
+	if (err) {
+		dev_err(dev, "failed to get display timing\n");
+		return err;
+	}
+
+	if (timing.pixelclock.typ > (LCDC_FMAX / 2)) {
+		dev_err(dev, "invalid display clock-frequency: %d Hz\n",
+			timing.pixelclock.typ);
+		return -EINVAL;
+	}
+
+	if (timing.hactive.typ > LCD_MAX_WIDTH)
+		timing.hactive.typ = LCD_MAX_WIDTH;
+
+	if (timing.vactive.typ > LCD_MAX_HEIGHT)
+		timing.vactive.typ = LCD_MAX_HEIGHT;
+
+	err = tilcdc_panel_get_display_info(panel, &info);
+	if (err) {
+		dev_err(dev, "failed to get panel info\n");
+		return err;
+	}
+
+	switch (info.bpp) {
+	case 16:
+	case 24:
+	case 32:
+		break;
+	default:
+		dev_err(dev, "invalid seting, bpp: %d\n", info.bpp);
+		return -EINVAL;
+	}
+
+	switch (info.dma_burst_sz) {
+	case 1:
+	case 2:
+	case 4:
+	case 8:
+	case 16:
+		break;
+	default:
+		dev_err(dev, "invalid setting, dma-burst-sz: %d\n",
+			info.dma_burst_sz);
+		return -EINVAL;
+	}
+
+	am335x_fb_set_pixel_clk_rate(regs, timing.pixelclock.typ);
 
 	/* clock source for LCDC from dispPLL M2 */
 	writel(0, &cmdpll->clklcdcpixelclk);
@@ -411,14 +437,14 @@ static int am335x_fb_probe(struct udevice *dev)
 	writel(reg, &regs->ctrl);
 
 	writel(uc_plat->base, &regs->lcddma_fb0_base);
-	writel(uc_plat->base + FBSIZE(timing, panel),
+	writel(uc_plat->base + FBSIZE(timing, info),
 	       &regs->lcddma_fb0_ceiling);
 	writel(uc_plat->base, &regs->lcddma_fb1_base);
-	writel(uc_plat->base + FBSIZE(timing, panel),
+	writel(uc_plat->base + FBSIZE(timing, info),
 	       &regs->lcddma_fb1_ceiling);
 
-	reg = LCDC_DMA_CTRL_FIFO_TH(panel->fifo_th);
-	switch (panel->dma_burst_sz) {
+	reg = LCDC_DMA_CTRL_FIFO_TH(info.fifo_th);
+	switch (info.dma_burst_sz) {
 	case 1:
 		reg |= LCDC_DMA_CTRL_BURST_SIZE(LCDC_DMA_CTRL_BURST_1);
 		break;
@@ -438,155 +464,84 @@ static int am335x_fb_probe(struct udevice *dev)
 
 	writel(reg, &regs->lcddma_ctrl);
 
-	writel(LCDC_RASTER_TIMING_0_HORLSB(timing->hactive.typ) |
-	       LCDC_RASTER_TIMING_0_HORMSB(timing->hactive.typ) |
-	       LCDC_RASTER_TIMING_0_HFPLSB(timing->hfront_porch.typ) |
-	       LCDC_RASTER_TIMING_0_HBPLSB(timing->hback_porch.typ) |
-	       LCDC_RASTER_TIMING_0_HSWLSB(timing->hsync_len.typ),
+	writel(LCDC_RASTER_TIMING_0_HORLSB(timing.hactive.typ) |
+	       LCDC_RASTER_TIMING_0_HORMSB(timing.hactive.typ) |
+	       LCDC_RASTER_TIMING_0_HFPLSB(timing.hfront_porch.typ) |
+	       LCDC_RASTER_TIMING_0_HBPLSB(timing.hback_porch.typ) |
+	       LCDC_RASTER_TIMING_0_HSWLSB(timing.hsync_len.typ),
 	       &regs->raster_timing0);
 
-	writel(LCDC_RASTER_TIMING_1_VBP(timing->vback_porch.typ) |
-	       LCDC_RASTER_TIMING_1_VFP(timing->vfront_porch.typ) |
-	       LCDC_RASTER_TIMING_1_VSW(timing->vsync_len.typ) |
-	       LCDC_RASTER_TIMING_1_VERLSB(timing->vactive.typ),
+	writel(LCDC_RASTER_TIMING_1_VBP(timing.vback_porch.typ) |
+	       LCDC_RASTER_TIMING_1_VFP(timing.vfront_porch.typ) |
+	       LCDC_RASTER_TIMING_1_VSW(timing.vsync_len.typ) |
+	       LCDC_RASTER_TIMING_1_VERLSB(timing.vactive.typ),
 	       &regs->raster_timing1);
 
-	reg = LCDC_RASTER_TIMING_2_ACB(panel->ac_bias) |
-		LCDC_RASTER_TIMING_2_ACBI(panel->ac_bias_intrpt) |
-		LCDC_RASTER_TIMING_2_HSWMSB(timing->hsync_len.typ) |
-		LCDC_RASTER_TIMING_2_VERMSB(timing->vactive.typ) |
-		LCDC_RASTER_TIMING_2_HBPMSB(timing->hback_porch.typ) |
-		LCDC_RASTER_TIMING_2_HFPMSB(timing->hfront_porch.typ);
+	reg = LCDC_RASTER_TIMING_2_ACB(info.ac_bias) |
+		LCDC_RASTER_TIMING_2_ACBI(info.ac_bias_intrpt) |
+		LCDC_RASTER_TIMING_2_HSWMSB(timing.hsync_len.typ) |
+		LCDC_RASTER_TIMING_2_VERMSB(timing.vactive.typ) |
+		LCDC_RASTER_TIMING_2_HBPMSB(timing.hback_porch.typ) |
+		LCDC_RASTER_TIMING_2_HFPMSB(timing.hfront_porch.typ);
 
-	if (timing->flags & DISPLAY_FLAGS_VSYNC_LOW)
+	if (timing.flags & DISPLAY_FLAGS_VSYNC_LOW)
 		reg |= LCDC_RASTER_TIMING_2_VSYNC_INVERT;
 
-	if (timing->flags & DISPLAY_FLAGS_HSYNC_LOW)
+	if (timing.flags & DISPLAY_FLAGS_HSYNC_LOW)
 		reg |= LCDC_RASTER_TIMING_2_HSYNC_INVERT;
 
-	if (panel->invert_pxl_clk)
+	if (info.invert_pxl_clk)
 		reg |= LCDC_RASTER_TIMING_2_PXCLK_INVERT;
 
-	if (panel->sync_edge)
+	if (info.sync_edge)
 		reg |= LCDC_RASTER_TIMING_2_HSVS_RISEFALL;
 
-	if (panel->sync_ctrl)
+	if (info.sync_ctrl)
 		reg |= LCDC_RASTER_TIMING_2_HSVS_CONTROL;
 
 	writel(reg, &regs->raster_timing2);
 
 	reg = LCDC_RASTER_CTRL_PALMODE_RAWDATA | LCDC_RASTER_CTRL_TFT_MODE |
-		LCDC_RASTER_CTRL_ENABLE | LCDC_RASTER_CTRL_REQDLY(panel->fdd);
+		LCDC_RASTER_CTRL_ENABLE | LCDC_RASTER_CTRL_REQDLY(info.fdd);
 
-	if (panel->tft_alt_mode)
+	if (info.tft_alt_mode)
 		reg |= LCDC_RASTER_CTRL_TFT_ALT_ENABLE;
 
-	if (panel->bpp == 24)
+	if (info.bpp == 24)
 		reg |= LCDC_RASTER_CTRL_TFT_24BPP_MODE;
-	else if (panel->bpp == 32)
+	else if (info.bpp == 32)
 		reg |= LCDC_RASTER_CTRL_TFT_24BPP_MODE |
 			LCDC_RASTER_CTRL_TFT_24BPP_UNPACK;
 
-	if (panel->raster_order)
+	if (info.raster_order)
 		reg |= LCDC_RASTER_CTRL_DATA_ORDER;
 
 	writel(reg, &regs->raster_ctrl);
 
-	uc_priv->xsize = timing->hactive.typ;
-	uc_priv->ysize = timing->vactive.typ;
-	uc_priv->bpix = log_2_n_round_up(panel->bpp);
-	return 0;
-}
-
-static int am335x_fb_ofdata_to_platdata(struct udevice *dev)
-{
-	struct am335x_fb_priv *priv = dev_get_priv(dev);
-	struct tilcdc_panel_info *panel = &priv->panel;
-	struct display_timing *timing = &priv->timing;
-	ofnode node;
-	int err;
+	uc_priv->xsize = timing.hactive.typ;
+	uc_priv->ysize = timing.vactive.typ;
+	uc_priv->bpix = log_2_n_round_up(info.bpp);
 
-	node = ofnode_by_compatible(ofnode_null(), "ti,am33xx-tilcdc");
-	if (!ofnode_valid(node)) {
-		dev_err(dev, "missing 'ti,am33xx-tilcdc' node\n");
-		return -ENXIO;
-	}
-
-	priv->regs = (struct am335x_lcdhw *)ofnode_get_addr(node);
-	dev_dbg(dev, "LCD: base address=0x%x\n", (unsigned int)priv->regs);
-
-	err = ofnode_decode_display_timing(dev_ofnode(dev), 0, timing);
+	err = panel_enable_backlight(panel);
 	if (err) {
-		dev_err(dev, "failed to get display timing\n");
+		dev_err(dev, "failed to enable panel backlight\n");
 		return err;
 	}
 
-	if (timing->pixelclock.typ > (LCDC_FMAX / 2)) {
-		dev_err(dev, "invalid display clock-frequency: %d Hz\n",
-			timing->pixelclock.typ);
-		return -EINVAL;
-	}
-
-	if (timing->hactive.typ > LCD_MAX_WIDTH)
-		timing->hactive.typ = LCD_MAX_WIDTH;
-
-	if (timing->vactive.typ > LCD_MAX_HEIGHT)
-		timing->vactive.typ = LCD_MAX_HEIGHT;
-
-	node = ofnode_find_subnode(dev_ofnode(dev), "panel-info");
-	if (!ofnode_valid(node)) {
-		dev_err(dev, "missing 'panel-info' node\n");
-		return -ENXIO;
-	}
-
-	err |= ofnode_read_u32(node, "ac-bias", &panel->ac_bias);
-	err |= ofnode_read_u32(node, "ac-bias-intrpt", &panel->ac_bias_intrpt);
-	err |= ofnode_read_u32(node, "dma-burst-sz", &panel->dma_burst_sz);
-	err |= ofnode_read_u32(node, "bpp", &panel->bpp);
-	err |= ofnode_read_u32(node, "fdd", &panel->fdd);
-	err |= ofnode_read_u32(node, "sync-edge", &panel->sync_edge);
-	err |= ofnode_read_u32(node, "sync-ctrl", &panel->sync_ctrl);
-	err |= ofnode_read_u32(node, "raster-order", &panel->raster_order);
-	err |= ofnode_read_u32(node, "fifo-th", &panel->fifo_th);
-	if (err) {
-		dev_err(dev, "failed to get panel info\n");
-		return err;
-	}
+	return 0;
+}
 
-	switch (panel->bpp) {
-	case 16:
-	case 24:
-	case 32:
-		break;
-	default:
-		dev_err(dev, "invalid seting, bpp: %d\n", panel->bpp);
-		return -EINVAL;
-	}
+static int am335x_fb_ofdata_to_platdata(struct udevice *dev)
+{
+	struct am335x_fb_priv *priv = dev_get_priv(dev);
 
-	switch (panel->dma_burst_sz) {
-	case 1:
-	case 2:
-	case 4:
-	case 8:
-	case 16:
-		break;
-	default:
-		dev_err(dev, "invalid setting, dma-burst-sz: %d\n",
-			panel->dma_burst_sz);
+	priv->regs = (struct am335x_lcdhw *)dev_read_addr(dev);
+	if ((fdt_addr_t)priv->regs == FDT_ADDR_T_NONE) {
+		dev_err(dev, "failed to get base address\n");
 		return -EINVAL;
 	}
 
-	/* optional */
-	panel->tft_alt_mode = ofnode_read_bool(node, "tft-alt-mode");
-	panel->invert_pxl_clk = ofnode_read_bool(node, "invert-pxl-clk");
-
-	dev_dbg(dev, "LCD: %dx%d, bpp=%d, clk=%d Hz\n", timing->hactive.typ,
-		timing->vactive.typ, panel->bpp, timing->pixelclock.typ);
-	dev_dbg(dev, "     hbp=%d, hfp=%d, hsw=%d\n", timing->hback_porch.typ,
-		timing->hfront_porch.typ, timing->hsync_len.typ);
-	dev_dbg(dev, "     vbp=%d, vfp=%d, vsw=%d\n", timing->vback_porch.typ,
-		timing->vfront_porch.typ, timing->vsync_len.typ);
-
+	dev_dbg(dev, "LCD: base address=0x%x\n", (unsigned int)priv->regs);
 	return 0;
 }
 
@@ -602,7 +557,7 @@ static int am335x_fb_bind(struct udevice *dev)
 }
 
 static const struct udevice_id am335x_fb_ids[] = {
-	{ .compatible = "ti,tilcdc,panel" },
+	{ .compatible = "ti,am33xx-tilcdc" },
 	{ }
 };
 
diff --git a/drivers/video/am335x-fb.h b/drivers/video/am335x-fb.h
index c9f92bc389..4952dd96e9 100644
--- a/drivers/video/am335x-fb.h
+++ b/drivers/video/am335x-fb.h
@@ -70,6 +70,37 @@ struct am335x_lcdpanel {
 
 int am335xfb_init(struct am335x_lcdpanel *panel);
 
+#else /* CONFIG_DM_VIDEO */
+
+/**
+ * tilcdc_panel_info: Panel parameters
+ *
+ * @ac_bias: AC Bias Pin Frequency
+ * @ac_bias_intrpt: AC Bias Pin Transitions per Interrupt
+ * @dma_burst_sz: DMA burst size
+ * @bpp: Bits per pixel
+ * @fdd: FIFO DMA Request Delay
+ * @tft_alt_mode: TFT Alternative Signal Mapping (Only for active)
+ * @invert_pxl_clk: Invert pixel clock
+ * @sync_edge: Horizontal and Vertical Sync Edge: 0=rising 1=falling
+ * @sync_ctrl: Horizontal and Vertical Sync: Control: 0=ignore
+ * @raster_order: Raster Data Order Select: 1=Most-to-least 0=Least-to-most
+ * @fifo_th: DMA FIFO threshold
+ */
+struct tilcdc_panel_info {
+	u32 ac_bias;
+	u32 ac_bias_intrpt;
+	u32 dma_burst_sz;
+	u32 bpp;
+	u32 fdd;
+	bool tft_alt_mode;
+	bool invert_pxl_clk;
+	u32 sync_edge;
+	u32 sync_ctrl;
+	u32 raster_order;
+	u32 fifo_th;
+};
+
 #endif  /* CONFIG_DM_VIDEO */
 
 #endif  /* AM335X_FB_H */
diff --git a/drivers/video/tilcdc-panel.c b/drivers/video/tilcdc-panel.c
new file mode 100644
index 0000000000..caf86c8383
--- /dev/null
+++ b/drivers/video/tilcdc-panel.c
@@ -0,0 +1,172 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * OMAP panel support
+ *
+ * Copyright (C) 2020 Dario Binacchi <dariobin at libero.it>
+ */
+
+#include <common.h>
+#include <backlight.h>
+#include <clk.h>
+#include <display.h>
+#include <dm.h>
+#include <dm/device_compat.h>
+#include <log.h>
+#include <panel.h>
+#include <asm/gpio.h>
+#include <linux/err.h>
+#include "am335x-fb.h"
+
+struct tilcdc_panel_priv {
+	struct tilcdc_panel_info info;
+	struct display_timing timing;
+	struct udevice *backlight;
+	struct gpio_desc enable;
+};
+
+static int tilcdc_panel_enable_backlight(struct udevice *dev)
+{
+	struct tilcdc_panel_priv *priv = dev_get_priv(dev);
+
+	if (dm_gpio_is_valid(&priv->enable))
+		dm_gpio_set_value(&priv->enable, 1);
+
+	if (priv->backlight)
+		return backlight_enable(priv->backlight);
+
+	return 0;
+}
+
+static int tilcdc_panel_set_backlight(struct udevice *dev, int percent)
+{
+	struct tilcdc_panel_priv *priv = dev_get_priv(dev);
+
+	if (dm_gpio_is_valid(&priv->enable))
+		dm_gpio_set_value(&priv->enable, 1);
+
+	if (priv->backlight)
+		return backlight_set_brightness(priv->backlight, percent);
+
+	return 0;
+}
+
+int tilcdc_panel_get_display_info(struct udevice *dev,
+				  struct tilcdc_panel_info *info)
+{
+	struct tilcdc_panel_priv *priv = dev_get_priv(dev);
+
+	memcpy(info, &priv->info, sizeof(*info));
+	return 0;
+}
+
+static int tilcdc_panel_get_display_timing(struct udevice *dev,
+					   struct display_timing *timing)
+{
+	struct tilcdc_panel_priv *priv = dev_get_priv(dev);
+
+	memcpy(timing, &priv->timing, sizeof(*timing));
+	return 0;
+}
+
+static int tilcdc_panel_remove(struct udevice *dev)
+{
+	struct tilcdc_panel_priv *priv = dev_get_priv(dev);
+
+	if (dm_gpio_is_valid(&priv->enable))
+		dm_gpio_free(dev, &priv->enable);
+
+	return 0;
+}
+
+static int tilcdc_panel_probe(struct udevice *dev)
+{
+	struct tilcdc_panel_priv *priv = dev_get_priv(dev);
+	int err;
+
+	err = uclass_get_device_by_phandle(UCLASS_PANEL_BACKLIGHT, dev,
+					   "backlight", &priv->backlight);
+	if (err)
+		dev_warn(dev, "failed to get backlight\n");
+
+	err = gpio_request_by_name(dev, "enable-gpios", 0, &priv->enable,
+				   GPIOD_IS_OUT);
+	if (err) {
+		dev_warn(dev, "failed to get enable GPIO\n");
+		if (err != -ENOENT)
+			return err;
+	}
+
+	return 0;
+}
+
+static int tilcdc_panel_ofdata_to_platdata(struct udevice *dev)
+{
+	struct tilcdc_panel_priv *priv = dev_get_priv(dev);
+	ofnode node;
+	int err;
+
+	err = ofnode_decode_display_timing(dev_ofnode(dev), 0, &priv->timing);
+	if (err) {
+		dev_err(dev, "failed to get display timing\n");
+		return err;
+	}
+
+	node = dev_read_subnode(dev, "panel-info");
+	if (!ofnode_valid(node)) {
+		dev_err(dev, "missing 'panel-info' node\n");
+		return -ENXIO;
+	}
+
+	err |= ofnode_read_u32(node, "ac-bias", &priv->info.ac_bias);
+	err |= ofnode_read_u32(node, "ac-bias-intrpt",
+			       &priv->info.ac_bias_intrpt);
+	err |= ofnode_read_u32(node, "dma-burst-sz", &priv->info.dma_burst_sz);
+	err |= ofnode_read_u32(node, "bpp", &priv->info.bpp);
+	err |= ofnode_read_u32(node, "fdd", &priv->info.fdd);
+	err |= ofnode_read_u32(node, "sync-edge", &priv->info.sync_edge);
+	err |= ofnode_read_u32(node, "sync-ctrl", &priv->info.sync_ctrl);
+	err |= ofnode_read_u32(node, "raster-order", &priv->info.raster_order);
+	err |= ofnode_read_u32(node, "fifo-th", &priv->info.fifo_th);
+	if (err) {
+		dev_err(dev, "failed to get panel info\n");
+		return err;
+	}
+
+	/* optional */
+	priv->info.tft_alt_mode = ofnode_read_bool(node, "tft-alt-mode");
+	priv->info.invert_pxl_clk = ofnode_read_bool(node, "invert-pxl-clk");
+
+	dev_dbg(dev, "LCD: %dx%d, bpp=%d, clk=%d Hz\n",
+		priv->timing.hactive.typ, priv->timing.vactive.typ,
+		priv->info.bpp, priv->timing.pixelclock.typ);
+	dev_dbg(dev, "     hbp=%d, hfp=%d, hsw=%d\n",
+		priv->timing.hback_porch.typ, priv->timing.hfront_porch.typ,
+		priv->timing.hsync_len.typ);
+	dev_dbg(dev, "     vbp=%d, vfp=%d, vsw=%d\n",
+		priv->timing.vback_porch.typ, priv->timing.vfront_porch.typ,
+		priv->timing.vsync_len.typ);
+
+	return 0;
+}
+
+static const struct panel_ops tilcdc_panel_ops = {
+	.enable_backlight = tilcdc_panel_enable_backlight,
+	.set_backlight = tilcdc_panel_set_backlight,
+	.get_display_timing = tilcdc_panel_get_display_timing,
+};
+
+static const struct udevice_id tilcdc_panel_ids[] = {
+	{.compatible = "ti,tilcdc,panel"},
+	{}
+};
+
+U_BOOT_DRIVER(tilcdc_panel) = {
+	.name = "tilcdc_panel",
+	.id = UCLASS_PANEL,
+	.of_match = tilcdc_panel_ids,
+	.ops = &tilcdc_panel_ops,
+	.ofdata_to_platdata = tilcdc_panel_ofdata_to_platdata,
+	.probe = tilcdc_panel_probe,
+	.remove = tilcdc_panel_remove,
+	.priv_auto_alloc_size = sizeof(struct tilcdc_panel_priv),
+};
diff --git a/drivers/video/tilcdc-panel.h b/drivers/video/tilcdc-panel.h
new file mode 100644
index 0000000000..6b40731304
--- /dev/null
+++ b/drivers/video/tilcdc-panel.h
@@ -0,0 +1,14 @@
+/* SPDX-License-Identifier: GPL-2.0+ */
+/*
+ * Copyright (C) 2020 Dario Binacchi <dariobin at libero.it>
+ */
+
+#ifndef _TILCDC_PANEL_H
+#define _TILCDC_PANEL_H
+
+#include "am335x-fb.h"
+
+int tilcdc_panel_get_display_info(struct udevice *dev,
+				  struct tilcdc_panel_info *info);
+
+#endif /* _TILCDC_PANEL_H */
-- 
2.17.1



More information about the U-Boot mailing list