All of lore.kernel.org
 help / color / mirror / Atom feed
From: Dario Binacchi <dariobin@libero.it>
To: u-boot@lists.denx.de
Subject: [PATCH v7 26/28] video: omap: split the legacy code from the DM code
Date: Thu, 24 Dec 2020 08:34:04 +0100	[thread overview]
Message-ID: <20201224073406.16764-27-dariobin@libero.it> (raw)
In-Reply-To: <20201224073406.16764-15-dariobin@libero.it>

The schedule for deprecating the features of the pre-driver-model puts
2019.17 as the deadline for the video subsystem. Furthermore, the latest
patches applied to the am335x-fb.c module have decreased the amount of
code shared with the pre-driver-model implementation. Splitting the two
implementations into two modules improves the readability of the code
and will make it easier to drop the pre-driver-model code.
I have not created a header file with the data structures and the
constants for accessing the LCD controller registers, but I preferred to
keep them inside the two c modules. This is a code replication until the
pre-driver-model version is dropped.

Signed-off-by: Dario Binacchi <dariobin@libero.it>

---

Changes in v7:
- Add linux/err.h header in am335x-fb.c to fix building errors for
  brxre1_defconfig.

Changes in v4:
- Include device_compat.h header for dev_xxx macros.

 drivers/video/Makefile       |   5 +-
 drivers/video/am335x-fb.c    | 335 ---------------------------
 drivers/video/am335x-fb.h    |  35 ---
 drivers/video/tilcdc-panel.c |   2 +-
 drivers/video/tilcdc-panel.h |   2 +-
 drivers/video/tilcdc.c       | 425 +++++++++++++++++++++++++++++++++++
 drivers/video/tilcdc.h       |  38 ++++
 7 files changed, 468 insertions(+), 374 deletions(-)
 create mode 100644 drivers/video/tilcdc.c
 create mode 100644 drivers/video/tilcdc.h

diff --git a/drivers/video/Makefile b/drivers/video/Makefile
index 132a63ecea..29f3434f7c 100644
--- a/drivers/video/Makefile
+++ b/drivers/video/Makefile
@@ -16,7 +16,9 @@ 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
+obj-$(CONFIG_AM335X_LCD) += tilcdc.o tilcdc-panel.o
+else
+obj-$(CONFIG_AM335X_LCD) += am335x-fb.o
 endif
 
 obj-${CONFIG_EXYNOS_FB} += exynos/
@@ -24,7 +26,6 @@ obj-${CONFIG_VIDEO_ROCKCHIP} += rockchip/
 obj-${CONFIG_VIDEO_STM32} += stm32/
 obj-${CONFIG_VIDEO_TEGRA124} += tegra124/
 
-obj-$(CONFIG_AM335X_LCD) += am335x-fb.o
 obj-$(CONFIG_ATI_RADEON_FB) += ati_radeon_fb.o videomodes.o
 obj-$(CONFIG_ATMEL_HLCD) += atmel_hlcdfb.o
 obj-$(CONFIG_ATMEL_LCD) += atmel_lcdfb.o
diff --git a/drivers/video/am335x-fb.c b/drivers/video/am335x-fb.c
index a0a635cc29..5fa6f794ec 100644
--- a/drivers/video/am335x-fb.c
+++ b/drivers/video/am335x-fb.c
@@ -12,22 +12,16 @@
  * - starts output DMA from gd->fb_base buffer
  */
 #include <common.h>
-#include <clk.h>
-#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>
 #include <asm/arch/omap.h>
 #include <asm/arch/sys_proto.h>
 #include <asm/io.h>
-#include <asm/utils.h>
 #include <linux/delay.h>
 #include <linux/err.h>
 #include "am335x-fb.h"
-#include "tilcdc-panel.h"
 
 #define LCDC_FMAX				200000000
 
@@ -115,8 +109,6 @@ struct am335x_lcdhw {
 
 DECLARE_GLOBAL_DATA_PTR;
 
-#if !CONFIG_IS_ENABLED(DM_VIDEO)
-
 #if !defined(LCD_CNTL_BASE)
 #error "hw-base address of LCD-Controller (LCD_CNTL_BASE) not defined!"
 #endif
@@ -323,330 +315,3 @@ int am335xfb_init(struct am335x_lcdpanel *panel)
 
 	return 0;
 }
-
-#else /* CONFIG_DM_VIDEO */
-
-#define FBSIZE(t, p)	(((t).hactive.typ * (t).vactive.typ * (p).bpp) >> 3)
-
-enum {
-	LCD_MAX_WIDTH		= 2048,
-	LCD_MAX_HEIGHT		= 2048,
-	LCD_MAX_LOG2_BPP	= VIDEO_BPP32,
-};
-
-struct am335x_fb_priv {
-	struct am335x_lcdhw *regs;
-	struct clk gclk;
-	struct clk dpll_m2_clk;
-};
-
-static ulong tilcdc_set_pixel_clk_rate(struct udevice *dev, ulong rate)
-{
-	struct am335x_fb_priv *priv = dev_get_priv(dev);
-	struct am335x_lcdhw *regs = priv->regs;
-	ulong mult_rate, mult_round_rate, best_err, err;
-	u32 v;
-	int div, i;
-
-	best_err = rate;
-	div = 0;
-	for (i = 2; i <= 255; i++) {
-		mult_rate = rate * i;
-		mult_round_rate = clk_round_rate(&priv->gclk, mult_rate);
-		if (IS_ERR_VALUE(mult_round_rate))
-			return mult_round_rate;
-
-		err = mult_rate - mult_round_rate;
-		if (err < best_err) {
-			best_err = err;
-			div = i;
-			if (err == 0)
-				break;
-		}
-	}
-
-	if (div == 0) {
-		dev_err(dev, "failed to find a divisor\n");
-		return -EFAULT;
-	}
-
-	mult_rate = clk_set_rate(&priv->gclk, rate * div);
-	v = readl(&regs->ctrl) & ~LCDC_CTRL_CLK_DIVISOR_MASK;
-	v |= LCDC_CTRL_CLK_DIVISOR(div);
-	writel(v, &regs->ctrl);
-	rate = mult_rate / div;
-	dev_dbg(dev, "rate=%ld, div=%d, err=%ld\n", rate, div, err);
-	return rate;
-}
-
-static int am335x_fb_remove(struct udevice *dev)
-{
-	struct video_uc_platdata *uc_plat = dev_get_uclass_platdata(dev);
-	struct am335x_fb_priv *priv = dev_get_priv(dev);
-
-	uc_plat->base -= 0x20;
-	uc_plat->size += 0x20;
-	clk_release_all(&priv->gclk, 1);
-	clk_release_all(&priv->dpll_m2_clk, 1);
-	return 0;
-}
-
-static int am335x_fb_probe(struct udevice *dev)
-{
-	struct video_uc_platdata *uc_plat = dev_get_uclass_platdata(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 udevice *panel, *clk_dev;
-	struct tilcdc_panel_info info;
-	struct display_timing timing;
-	ulong rate;
-	u32 reg;
-	int err;
-
-	/* Before relocation we don't need to do anything */
-	if (!(gd->flags & GD_FLG_RELOC))
-		return 0;
-
-	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;
-	}
-
-	err = uclass_get_device_by_name(UCLASS_CLK, "lcd_gclk at 534", &clk_dev);
-	if (err) {
-		dev_err(dev, "failed to get lcd_gclk device\n");
-		return err;
-	}
-
-	err = clk_request(clk_dev, &priv->gclk);
-	if (err) {
-		dev_err(dev, "failed to get %s clock\n", clk_dev->name);
-		return err;
-	}
-
-	rate = tilcdc_set_pixel_clk_rate(dev, timing.pixelclock.typ);
-	if (IS_ERR_VALUE(rate)) {
-		dev_err(dev, "failed to set pixel clock rate\n");
-		return rate;
-	}
-
-	err = uclass_get_device_by_name(UCLASS_CLK, "dpll_disp_m2_ck at 4a4", &clk_dev);
-	if (err) {
-		dev_err(dev, "failed to get dpll_disp_m2 clock device\n");
-		return err;
-	}
-
-	err = clk_request(clk_dev, &priv->dpll_m2_clk);
-	if (err) {
-		dev_err(dev, "failed to get %s clock\n", clk_dev->name);
-		return err;
-	}
-
-	err = clk_set_parent(&priv->gclk, &priv->dpll_m2_clk);
-	if (err) {
-		dev_err(dev, "failed to set %s clock as %s's parent\n",
-			priv->dpll_m2_clk.dev->name, priv->gclk.dev->name);
-		return err;
-	}
-
-	/* palette default entry */
-	memset((void *)uc_plat->base, 0, 0x20);
-	*(unsigned int *)uc_plat->base = 0x4000;
-	/* point fb behind palette */
-	uc_plat->base += 0x20;
-	uc_plat->size -= 0x20;
-
-	writel(LCDC_CLKC_ENABLE_CORECLKEN | LCDC_CLKC_ENABLE_LIDDCLKEN |
-	       LCDC_CLKC_ENABLE_DMACLKEN, &regs->clkc_enable);
-	writel(0, &regs->raster_ctrl);
-
-	reg = readl(&regs->ctrl) & LCDC_CTRL_CLK_DIVISOR_MASK;
-	reg |= LCDC_CTRL_RASTER_MODE;
-	writel(reg, &regs->ctrl);
-
-	writel(uc_plat->base, &regs->lcddma_fb0_base);
-	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, info),
-	       &regs->lcddma_fb1_ceiling);
-
-	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;
-	case 2:
-		reg |= LCDC_DMA_CTRL_BURST_SIZE(LCDC_DMA_CTRL_BURST_2);
-		break;
-	case 4:
-		reg |= LCDC_DMA_CTRL_BURST_SIZE(LCDC_DMA_CTRL_BURST_4);
-		break;
-	case 8:
-		reg |= LCDC_DMA_CTRL_BURST_SIZE(LCDC_DMA_CTRL_BURST_8);
-		break;
-	case 16:
-		reg |= LCDC_DMA_CTRL_BURST_SIZE(LCDC_DMA_CTRL_BURST_16);
-		break;
-	}
-
-	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),
-	       &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),
-	       &regs->raster_timing1);
-
-	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)
-		reg |= LCDC_RASTER_TIMING_2_VSYNC_INVERT;
-
-	if (timing.flags & DISPLAY_FLAGS_HSYNC_LOW)
-		reg |= LCDC_RASTER_TIMING_2_HSYNC_INVERT;
-
-	if (info.invert_pxl_clk)
-		reg |= LCDC_RASTER_TIMING_2_PXCLK_INVERT;
-
-	if (info.sync_edge)
-		reg |= LCDC_RASTER_TIMING_2_HSVS_RISEFALL;
-
-	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(info.fdd);
-
-	if (info.tft_alt_mode)
-		reg |= LCDC_RASTER_CTRL_TFT_ALT_ENABLE;
-
-	if (info.bpp == 24)
-		reg |= LCDC_RASTER_CTRL_TFT_24BPP_MODE;
-	else if (info.bpp == 32)
-		reg |= LCDC_RASTER_CTRL_TFT_24BPP_MODE |
-			LCDC_RASTER_CTRL_TFT_24BPP_UNPACK;
-
-	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(info.bpp);
-
-	err = panel_enable_backlight(panel);
-	if (err) {
-		dev_err(dev, "failed to enable panel backlight\n");
-		return err;
-	}
-
-	return 0;
-}
-
-static int am335x_fb_ofdata_to_platdata(struct udevice *dev)
-{
-	struct am335x_fb_priv *priv = dev_get_priv(dev);
-
-	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;
-	}
-
-	dev_dbg(dev, "LCD: base address=0x%x\n", (unsigned int)priv->regs);
-	return 0;
-}
-
-static int am335x_fb_bind(struct udevice *dev)
-{
-	struct video_uc_platdata *uc_plat = dev_get_uclass_platdata(dev);
-
-	uc_plat->size = ((LCD_MAX_WIDTH * LCD_MAX_HEIGHT *
-			  (1 << LCD_MAX_LOG2_BPP)) >> 3) + 0x20;
-
-	dev_dbg(dev, "frame buffer size 0x%x\n", uc_plat->size);
-	return 0;
-}
-
-static const struct udevice_id am335x_fb_ids[] = {
-	{ .compatible = "ti,am33xx-tilcdc" },
-	{ }
-};
-
-U_BOOT_DRIVER(am335x_fb) = {
-	.name = "am335x_fb",
-	.id = UCLASS_VIDEO,
-	.of_match = am335x_fb_ids,
-	.bind = am335x_fb_bind,
-	.ofdata_to_platdata = am335x_fb_ofdata_to_platdata,
-	.probe = am335x_fb_probe,
-	.remove = am335x_fb_remove,
-	.priv_auto_alloc_size = sizeof(struct am335x_fb_priv),
-};
-
-#endif /* CONFIG_DM_VIDEO */
diff --git a/drivers/video/am335x-fb.h b/drivers/video/am335x-fb.h
index 4952dd96e9..ad9b015e09 100644
--- a/drivers/video/am335x-fb.h
+++ b/drivers/video/am335x-fb.h
@@ -7,8 +7,6 @@
 #ifndef AM335X_FB_H
 #define AM335X_FB_H
 
-#if !CONFIG_IS_ENABLED(DM_VIDEO)
-
 #define HSVS_CONTROL		BIT(25)	/*
 					 * 0 = lcd_lp and lcd_fp are driven on
 					 * opposite edges of pixel clock than
@@ -70,37 +68,4 @@ 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
index caf86c8383..e9c8e84e3b 100644
--- a/drivers/video/tilcdc-panel.c
+++ b/drivers/video/tilcdc-panel.c
@@ -15,7 +15,7 @@
 #include <panel.h>
 #include <asm/gpio.h>
 #include <linux/err.h>
-#include "am335x-fb.h"
+#include "tilcdc.h"
 
 struct tilcdc_panel_priv {
 	struct tilcdc_panel_info info;
diff --git a/drivers/video/tilcdc-panel.h b/drivers/video/tilcdc-panel.h
index 6b40731304..6bcfbf8a8b 100644
--- a/drivers/video/tilcdc-panel.h
+++ b/drivers/video/tilcdc-panel.h
@@ -6,7 +6,7 @@
 #ifndef _TILCDC_PANEL_H
 #define _TILCDC_PANEL_H
 
-#include "am335x-fb.h"
+#include "tilcdc.h"
 
 int tilcdc_panel_get_display_info(struct udevice *dev,
 				  struct tilcdc_panel_info *info);
diff --git a/drivers/video/tilcdc.c b/drivers/video/tilcdc.c
new file mode 100644
index 0000000000..6228c2399c
--- /dev/null
+++ b/drivers/video/tilcdc.c
@@ -0,0 +1,425 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * Copyright (C) 2020 Dario Binacchi <dariobin@libero.it>
+ */
+
+#include <common.h>
+#include <clk.h>
+#include <dm.h>
+#include <dm/device_compat.h>
+#include <lcd.h>
+#include <log.h>
+#include <panel.h>
+#include <video.h>
+#include <asm/io.h>
+#include <asm/utils.h>
+#include "tilcdc.h"
+#include "tilcdc-panel.h"
+
+#define LCDC_FMAX				200000000
+
+/* LCD Control Register */
+#define LCDC_CTRL_CLK_DIVISOR_MASK		GENMASK(15, 8)
+#define LCDC_CTRL_RASTER_MODE			BIT(0)
+#define LCDC_CTRL_CLK_DIVISOR(x)		(((x) & GENMASK(7, 0)) << 8)
+/* LCD Clock Enable Register */
+#define LCDC_CLKC_ENABLE_CORECLKEN		BIT(0)
+#define LCDC_CLKC_ENABLE_LIDDCLKEN		BIT(1)
+#define LCDC_CLKC_ENABLE_DMACLKEN		BIT(2)
+/* LCD DMA Control Register */
+#define LCDC_DMA_CTRL_BURST_SIZE(x)		(((x) & GENMASK(2, 0)) << 4)
+#define LCDC_DMA_CTRL_BURST_1			0x0
+#define LCDC_DMA_CTRL_BURST_2			0x1
+#define LCDC_DMA_CTRL_BURST_4			0x2
+#define LCDC_DMA_CTRL_BURST_8			0x3
+#define LCDC_DMA_CTRL_BURST_16			0x4
+#define LCDC_DMA_CTRL_FIFO_TH(x)		(((x) & GENMASK(2, 0)) << 8)
+/* LCD Timing_0 Register */
+#define LCDC_RASTER_TIMING_0_HORMSB(x)	((((x) - 1) & BIT(10)) >> 7)
+#define LCDC_RASTER_TIMING_0_HORLSB(x) (((((x) >> 4) - 1) & GENMASK(5, 0)) << 4)
+#define LCDC_RASTER_TIMING_0_HSWLSB(x)	((((x) - 1) & GENMASK(5, 0)) << 10)
+#define LCDC_RASTER_TIMING_0_HFPLSB(x)	((((x) - 1) & GENMASK(7, 0)) << 16)
+#define LCDC_RASTER_TIMING_0_HBPLSB(x)	((((x) - 1) & GENMASK(7, 0)) << 24)
+/* LCD Timing_1 Register */
+#define LCDC_RASTER_TIMING_1_VERLSB(x)		(((x) - 1) & GENMASK(9, 0))
+#define LCDC_RASTER_TIMING_1_VSW(x)	((((x) - 1) & GENMASK(5, 0)) << 10)
+#define LCDC_RASTER_TIMING_1_VFP(x)		(((x) & GENMASK(7, 0)) << 16)
+#define LCDC_RASTER_TIMING_1_VBP(x)		(((x) & GENMASK(7, 0)) << 24)
+/* LCD Timing_2 Register */
+#define LCDC_RASTER_TIMING_2_HFPMSB(x)	((((x) - 1) & GENMASK(9, 8)) >> 8)
+#define LCDC_RASTER_TIMING_2_HBPMSB(x)	((((x) - 1) & GENMASK(9, 8)) >> 4)
+#define LCDC_RASTER_TIMING_2_ACB(x)		(((x) & GENMASK(7, 0)) << 8)
+#define LCDC_RASTER_TIMING_2_ACBI(x)		(((x) & GENMASK(3, 0)) << 16)
+#define LCDC_RASTER_TIMING_2_VSYNC_INVERT	BIT(20)
+#define LCDC_RASTER_TIMING_2_HSYNC_INVERT	BIT(21)
+#define LCDC_RASTER_TIMING_2_PXCLK_INVERT	BIT(22)
+#define LCDC_RASTER_TIMING_2_DE_INVERT		BIT(23)
+#define LCDC_RASTER_TIMING_2_HSVS_RISEFALL	BIT(24)
+#define LCDC_RASTER_TIMING_2_HSVS_CONTROL	BIT(25)
+#define LCDC_RASTER_TIMING_2_VERMSB(x)		((((x) - 1) & BIT(10)) << 16)
+#define LCDC_RASTER_TIMING_2_HSWMSB(x)	((((x) - 1) & GENMASK(9, 6)) << 21)
+/* LCD Raster Ctrl Register */
+#define LCDC_RASTER_CTRL_ENABLE			BIT(0)
+#define LCDC_RASTER_CTRL_TFT_MODE		BIT(7)
+#define LCDC_RASTER_CTRL_DATA_ORDER		BIT(8)
+#define LCDC_RASTER_CTRL_REQDLY(x)		(((x) & GENMASK(7, 0)) << 12)
+#define LCDC_RASTER_CTRL_PALMODE_RAWDATA	(0x02 << 20)
+#define LCDC_RASTER_CTRL_TFT_ALT_ENABLE		BIT(23)
+#define LCDC_RASTER_CTRL_TFT_24BPP_MODE		BIT(25)
+#define LCDC_RASTER_CTRL_TFT_24BPP_UNPACK	BIT(26)
+
+enum {
+	LCDC_MAX_WIDTH = 2048,
+	LCDC_MAX_HEIGHT = 2048,
+	LCDC_MAX_LOG2_BPP = VIDEO_BPP32,
+};
+
+struct tilcdc_regs {
+	u32 pid;
+	u32 ctrl;
+	u32 gap0;
+	u32 lidd_ctrl;
+	u32 lidd_cs0_conf;
+	u32 lidd_cs0_addr;
+	u32 lidd_cs0_data;
+	u32 lidd_cs1_conf;
+	u32 lidd_cs1_addr;
+	u32 lidd_cs1_data;
+	u32 raster_ctrl;
+	u32 raster_timing0;
+	u32 raster_timing1;
+	u32 raster_timing2;
+	u32 raster_subpanel;
+	u32 raster_subpanel2;
+	u32 lcddma_ctrl;
+	u32 lcddma_fb0_base;
+	u32 lcddma_fb0_ceiling;
+	u32 lcddma_fb1_base;
+	u32 lcddma_fb1_ceiling;
+	u32 sysconfig;
+	u32 irqstatus_raw;
+	u32 irqstatus;
+	u32 irqenable_set;
+	u32 irqenable_clear;
+	u32 gap1;
+	u32 clkc_enable;
+	u32 clkc_reset;
+};
+
+struct tilcdc_priv {
+	struct tilcdc_regs *regs;
+	struct clk gclk;
+	struct clk dpll_m2_clk;
+};
+
+DECLARE_GLOBAL_DATA_PTR;
+
+static ulong tilcdc_set_pixel_clk_rate(struct udevice *dev, ulong rate)
+{
+	struct tilcdc_priv *priv = dev_get_priv(dev);
+	struct tilcdc_regs *regs = priv->regs;
+	ulong mult_rate, mult_round_rate, best_err, err;
+	u32 v;
+	int div, i;
+
+	best_err = rate;
+	div = 0;
+	for (i = 2; i <= 255; i++) {
+		mult_rate = rate * i;
+		mult_round_rate = clk_round_rate(&priv->gclk, mult_rate);
+		if (IS_ERR_VALUE(mult_round_rate))
+			return mult_round_rate;
+
+		err = mult_rate - mult_round_rate;
+		if (err < best_err) {
+			best_err = err;
+			div = i;
+			if (err == 0)
+				break;
+		}
+	}
+
+	if (div == 0) {
+		dev_err(dev, "failed to find a divisor\n");
+		return -EFAULT;
+	}
+
+	mult_rate = clk_set_rate(&priv->gclk, rate * div);
+	v = readl(&regs->ctrl) & ~LCDC_CTRL_CLK_DIVISOR_MASK;
+	v |= LCDC_CTRL_CLK_DIVISOR(div);
+	writel(v, &regs->ctrl);
+	rate = mult_rate / div;
+	dev_dbg(dev, "rate=%ld, div=%d, err=%ld\n", rate, div, err);
+	return rate;
+}
+
+static int tilcdc_remove(struct udevice *dev)
+{
+	struct video_uc_platdata *uc_plat = dev_get_uclass_platdata(dev);
+	struct tilcdc_priv *priv = dev_get_priv(dev);
+
+	uc_plat->base -= 0x20;
+	uc_plat->size += 0x20;
+	clk_release_all(&priv->gclk, 1);
+	clk_release_all(&priv->dpll_m2_clk, 1);
+	return 0;
+}
+
+static int tilcdc_probe(struct udevice *dev)
+{
+	struct video_uc_platdata *uc_plat = dev_get_uclass_platdata(dev);
+	struct video_priv *uc_priv = dev_get_uclass_priv(dev);
+	struct tilcdc_priv *priv = dev_get_priv(dev);
+	struct tilcdc_regs *regs = priv->regs;
+	struct udevice *panel, *clk_dev;
+	struct tilcdc_panel_info info;
+	struct display_timing timing;
+	ulong rate;
+	u32 reg;
+	int err;
+
+	/* Before relocation we don't need to do anything */
+	if (!(gd->flags & GD_FLG_RELOC))
+		return 0;
+
+	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 > LCDC_MAX_WIDTH)
+		timing.hactive.typ = LCDC_MAX_WIDTH;
+
+	if (timing.vactive.typ > LCDC_MAX_HEIGHT)
+		timing.vactive.typ = LCDC_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;
+	}
+
+	err = uclass_get_device_by_name(UCLASS_CLK, "lcd_gclk at 534", &clk_dev);
+	if (err) {
+		dev_err(dev, "failed to get lcd_gclk device\n");
+		return err;
+	}
+
+	err = clk_request(clk_dev, &priv->gclk);
+	if (err) {
+		dev_err(dev, "failed to get %s clock\n", clk_dev->name);
+		return err;
+	}
+
+	rate = tilcdc_set_pixel_clk_rate(dev, timing.pixelclock.typ);
+	if (IS_ERR_VALUE(rate)) {
+		dev_err(dev, "failed to set pixel clock rate\n");
+		return rate;
+	}
+
+	err = uclass_get_device_by_name(UCLASS_CLK, "dpll_disp_m2_ck at 4a4",
+					&clk_dev);
+	if (err) {
+		dev_err(dev, "failed to get dpll_disp_m2 clock device\n");
+		return err;
+	}
+
+	err = clk_request(clk_dev, &priv->dpll_m2_clk);
+	if (err) {
+		dev_err(dev, "failed to get %s clock\n", clk_dev->name);
+		return err;
+	}
+
+	err = clk_set_parent(&priv->gclk, &priv->dpll_m2_clk);
+	if (err) {
+		dev_err(dev, "failed to set %s clock as %s's parent\n",
+			priv->dpll_m2_clk.dev->name, priv->gclk.dev->name);
+		return err;
+	}
+
+	/* palette default entry */
+	memset((void *)uc_plat->base, 0, 0x20);
+	*(unsigned int *)uc_plat->base = 0x4000;
+	/* point fb behind palette */
+	uc_plat->base += 0x20;
+	uc_plat->size -= 0x20;
+
+	writel(LCDC_CLKC_ENABLE_CORECLKEN | LCDC_CLKC_ENABLE_LIDDCLKEN |
+	       LCDC_CLKC_ENABLE_DMACLKEN, &regs->clkc_enable);
+	writel(0, &regs->raster_ctrl);
+
+	reg = readl(&regs->ctrl) & LCDC_CTRL_CLK_DIVISOR_MASK;
+	reg |= LCDC_CTRL_RASTER_MODE;
+	writel(reg, &regs->ctrl);
+
+	reg = (timing.hactive.typ * timing.vactive.typ * info.bpp) >> 3;
+	reg += uc_plat->base;
+	writel(uc_plat->base, &regs->lcddma_fb0_base);
+	writel(reg, &regs->lcddma_fb0_ceiling);
+	writel(uc_plat->base, &regs->lcddma_fb1_base);
+	writel(reg, &regs->lcddma_fb1_ceiling);
+
+	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;
+	case 2:
+		reg |= LCDC_DMA_CTRL_BURST_SIZE(LCDC_DMA_CTRL_BURST_2);
+		break;
+	case 4:
+		reg |= LCDC_DMA_CTRL_BURST_SIZE(LCDC_DMA_CTRL_BURST_4);
+		break;
+	case 8:
+		reg |= LCDC_DMA_CTRL_BURST_SIZE(LCDC_DMA_CTRL_BURST_8);
+		break;
+	case 16:
+		reg |= LCDC_DMA_CTRL_BURST_SIZE(LCDC_DMA_CTRL_BURST_16);
+		break;
+	}
+
+	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),
+	       &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),
+	       &regs->raster_timing1);
+
+	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)
+		reg |= LCDC_RASTER_TIMING_2_VSYNC_INVERT;
+
+	if (timing.flags & DISPLAY_FLAGS_HSYNC_LOW)
+		reg |= LCDC_RASTER_TIMING_2_HSYNC_INVERT;
+
+	if (info.invert_pxl_clk)
+		reg |= LCDC_RASTER_TIMING_2_PXCLK_INVERT;
+
+	if (info.sync_edge)
+		reg |= LCDC_RASTER_TIMING_2_HSVS_RISEFALL;
+
+	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(info.fdd);
+
+	if (info.tft_alt_mode)
+		reg |= LCDC_RASTER_CTRL_TFT_ALT_ENABLE;
+
+	if (info.bpp == 24)
+		reg |= LCDC_RASTER_CTRL_TFT_24BPP_MODE;
+	else if (info.bpp == 32)
+		reg |= LCDC_RASTER_CTRL_TFT_24BPP_MODE |
+			LCDC_RASTER_CTRL_TFT_24BPP_UNPACK;
+
+	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(info.bpp);
+
+	err = panel_enable_backlight(panel);
+	if (err) {
+		dev_err(dev, "failed to enable panel backlight\n");
+		return err;
+	}
+
+	return 0;
+}
+
+static int tilcdc_ofdata_to_platdata(struct udevice *dev)
+{
+	struct tilcdc_priv *priv = dev_get_priv(dev);
+
+	priv->regs = (struct tilcdc_regs *)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;
+	}
+
+	dev_dbg(dev, "LCD: base address=0x%x\n", (unsigned int)priv->regs);
+	return 0;
+}
+
+static int tilcdc_bind(struct udevice *dev)
+{
+	struct video_uc_platdata *uc_plat = dev_get_uclass_platdata(dev);
+
+	uc_plat->size = ((LCDC_MAX_WIDTH * LCDC_MAX_HEIGHT *
+			  (1 << LCDC_MAX_LOG2_BPP)) >> 3) + 0x20;
+
+	dev_dbg(dev, "frame buffer size 0x%x\n", uc_plat->size);
+	return 0;
+}
+
+static const struct udevice_id tilcdc_ids[] = {
+	{.compatible = "ti,am33xx-tilcdc"},
+	{}
+};
+
+U_BOOT_DRIVER(tilcdc) = {
+	.name = "tilcdc",
+	.id = UCLASS_VIDEO,
+	.of_match = tilcdc_ids,
+	.bind = tilcdc_bind,
+	.ofdata_to_platdata = tilcdc_ofdata_to_platdata,
+	.probe = tilcdc_probe,
+	.remove = tilcdc_remove,
+	.priv_auto_alloc_size = sizeof(struct tilcdc_priv)
+};
diff --git a/drivers/video/tilcdc.h b/drivers/video/tilcdc.h
new file mode 100644
index 0000000000..2645921df6
--- /dev/null
+++ b/drivers/video/tilcdc.h
@@ -0,0 +1,38 @@
+/* SPDX-License-Identifier: GPL-2.0+ */
+/*
+ * Copyright (C) 2020 Dario Binacchi <dariobin@libero.it>
+ */
+
+#ifndef _TILCDC_H
+#define _TILCDC_H
+
+/**
+ * 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 /* _TILCDC_H */
-- 
2.17.1

  parent reply	other threads:[~2020-12-24  7:34 UTC|newest]

Thread overview: 16+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2020-12-24  7:33 [PATCH v7 14/28] clk: ti: omap4: add clock manager driver Dario Binacchi
2020-12-24  7:33 ` [PATCH v7 15/28] arm: dts: am335x: enable prcm_clocks auto binding Dario Binacchi
2020-12-24  7:33 ` [PATCH v7 16/28] clk: move clk-ti-sci driver to 'ti' directory Dario Binacchi
2020-12-24  7:33 ` [PATCH v7 17/28] fdt: translate address if #size-cells = <0> Dario Binacchi
2020-12-24  7:33 ` [PATCH v7 18/28] omap: timer: fix the rate setting Dario Binacchi
2020-12-24  7:33 ` [PATCH v7 19/28] arm: dts: am335x: enable scm_clocks auto binding Dario Binacchi
2020-12-24  7:33 ` [PATCH v7 20/28] pwm: ti: am33xx: add enhanced pwm driver Dario Binacchi
2020-12-24  7:33 ` [PATCH v7 21/28] bus: ti: am33xx: add pwm subsystem driver Dario Binacchi
2020-12-24  7:34 ` [PATCH v7 22/28] dm: core: add a function to decode display timings Dario Binacchi
2020-12-24  7:34 ` [PATCH v7 23/28] video: omap: add panel driver Dario Binacchi
2020-12-29  6:10   ` Lokesh Vutla
2020-12-24  7:34 ` [PATCH v7 24/28] video: omap: drop domain clock enabling by SOC api Dario Binacchi
2020-12-24  7:34 ` [PATCH v7 25/28] video: omap: set LCD clock rate through DM API Dario Binacchi
2020-12-24  7:34 ` Dario Binacchi [this message]
2020-12-24  7:34 ` [PATCH v7 27/28] video: omap: move drivers to 'ti' directory Dario Binacchi
2020-12-24  7:34 ` [PATCH v7 28/28] board: ti: am335x-ice: get CDCE913 clock device Dario Binacchi

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=20201224073406.16764-27-dariobin@libero.it \
    --to=dariobin@libero.it \
    --cc=u-boot@lists.denx.de \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.