[U-Boot] [PATCH 4/6] am335x-fb: setup display PLL

Hannes Schmelzer oe5hpm at oevsv.at
Tue Jan 9 06:58:45 UTC 2018


The LCDC IP-core an be feed from several clock sources, one of those is
a dedicated DPLL for generating a dividable base-clock for this IP-core.

The TRM specifies the maximum input frequency for the LCCD with 200 MHz,
so we must not exceed this value with the PLL frequency (which can lock
much higher).

This patch tries every combination of multipliers and divisors of the
PLL and the IP-core itself for getting as near as possible the the
requested panel->pxl_clk.

Signed-off-by: Hannes Schmelzer <oe5hpm at oevsv.at>
---

 drivers/video/am335x-fb.c | 54 ++++++++++++++++++++++++++++++++++++++++++++---
 drivers/video/am335x-fb.h |  2 +-
 2 files changed, 52 insertions(+), 4 deletions(-)

diff --git a/drivers/video/am335x-fb.c b/drivers/video/am335x-fb.c
index 5494c3c..1be28e3 100644
--- a/drivers/video/am335x-fb.c
+++ b/drivers/video/am335x-fb.c
@@ -12,7 +12,11 @@
  * SPDX-License-Identifier:	GPL-2.0+
  */
 #include <common.h>
+#include <asm/io.h>
 #include <asm/arch/hardware.h>
+#include <asm/arch/omap.h>
+#include <asm/arch/clock.h>
+#include <asm/arch/sys_proto.h>
 #include <lcd.h>
 #include "am335x-fb.h"
 
@@ -20,6 +24,7 @@
 #error "hw-base address of LCD-Controller (LCD_CNTL_BASE) not defined!"
 #endif
 
+#define LCDC_FMAX				200000000
 
 /* LCD Control Register */
 #define LCD_CLK_DIVISOR(x)			((x) << 8)
@@ -96,6 +101,7 @@ struct am335x_lcdhw {
 };
 
 static struct am335x_lcdhw *lcdhw = (void *)LCD_CNTL_BASE;
+
 DECLARE_GLOBAL_DATA_PTR;
 
 int lcd_get_size(int *line_length)
@@ -108,6 +114,11 @@ int am335xfb_init(struct am335x_lcdpanel *panel)
 {
 	u32 raster_ctrl = 0;
 
+	struct cm_dpll *const cmdpll = (struct cm_dpll *)CM_DPLL;
+	struct dpll_params dpll_disp = { 1, 0, 1, -1, -1, -1, -1 };
+	unsigned int m, n, d, best_d = 2;
+	int err = 0, err_r = 0;
+
 	if (gd->fb_base == NULL) {
 		printf("ERROR: no valid fb_base stored in GLOBAL_DATA_PTR!\n");
 		return -1;
@@ -132,14 +143,51 @@ int am335xfb_init(struct am335x_lcdpanel *panel)
 		return -1;
 	}
 
+	/* check given clock-frequency */
+	if (panel->pxl_clk > (LCDC_FMAX / 2)) {
+		pr_err("am335x-fb: requested pxl-clk: %d not supported!\n",
+		       panel->pxl_clk);
+		return -1;
+	}
+
 	debug("setting up LCD-Controller for %dx%dx%d (hfp=%d,hbp=%d,hsw=%d / ",
 	      panel->hactive, panel->vactive, panel->bpp,
 	      panel->hfp, panel->hbp, panel->hsw);
-	debug("vfp=%d,vbp=%d,vsw=%d / clk-div=%d)\n",
-	      panel->vfp, panel->vfp, panel->vsw, panel->pxl_clk_div);
+	debug("vfp=%d,vbp=%d,vsw=%d / clk=%d)\n",
+	      panel->vfp, panel->vfp, panel->vsw, panel->pxl_clk);
 	debug("using frambuffer at 0x%08x with size %d.\n",
 	      (unsigned int)gd->fb_base, FBSIZE(panel));
 
+	/* setup display pll for requested clock frequency */
+	err = panel->pxl_clk;
+	err_r = err;
+
+	for (d = 2; d < 255; d++) {
+		for (m = 2; m < 2047; m++) {
+			if ((V_OSCK * m) < (panel->pxl_clk * d))
+				continue;
+			n = (V_OSCK * m) / (panel->pxl_clk * d);
+			if (n > 127)
+				break;
+			if (((V_OSCK * m) / n) > LCDC_FMAX)
+				break;
+
+			err = abs((V_OSCK * m) / n / d - panel->pxl_clk);
+			if (err < err_r) {
+				err_r = err;
+				dpll_disp.m = m;
+				dpll_disp.n = n;
+				best_d = d;
+			}
+		}
+	}
+	debug("%s: PLL: best error %d Hz (M %d, N %d, DISP %d)\n",
+	      __func__, err_r, dpll_disp.m, dpll_disp.n, best_d);
+	do_setup_dpll(&dpll_disp_regs, &dpll_disp);
+
+	/* clock source for LCDC from dispPLL M2 */
+	writel(0x0, &cmdpll->clklcdcpixelclk);
+
 	/* palette default entry */
 	memset((void *)gd->fb_base, 0, 0x20);
 	*(unsigned int *)gd->fb_base = 0x4000;
@@ -154,7 +202,7 @@ int am335xfb_init(struct am335x_lcdpanel *panel)
 	mdelay(panel->pup_delay);
 	lcdhw->clkc_enable = LCD_CORECLKEN | LCD_LIDDCLKEN | LCD_DMACLKEN;
 	lcdhw->raster_ctrl = 0;
-	lcdhw->ctrl = LCD_CLK_DIVISOR(panel->pxl_clk_div) | LCD_RASTER_MODE;
+	lcdhw->ctrl = LCD_CLK_DIVISOR(best_d) | LCD_RASTER_MODE;
 	lcdhw->lcddma_fb0_base = gd->fb_base;
 	lcdhw->lcddma_fb0_ceiling = gd->fb_base + FBSIZE(panel);
 	lcdhw->lcddma_fb1_base = gd->fb_base;
diff --git a/drivers/video/am335x-fb.h b/drivers/video/am335x-fb.h
index 1980eda..e25c361 100644
--- a/drivers/video/am335x-fb.h
+++ b/drivers/video/am335x-fb.h
@@ -53,7 +53,7 @@ struct am335x_lcdpanel {
 	unsigned int	vfp;		/* Vertical front porch */
 	unsigned int	vbp;		/* Vertical back porch */
 	unsigned int	vsw;		/* Vertical Sync Pulse Width */
-	unsigned int	pxl_clk_div;	/* Pixel clock divider*/
+	unsigned int	pxl_clk;	/* Pixel clock */
 	unsigned int	pol;		/* polarity of sync, clock signals */
 	unsigned int	pup_delay;	/*
 					 * time in ms after power on to
-- 
2.7.4



More information about the U-Boot mailing list