From 3215192922675bdcb70239663b44cae1f0ae1792 Mon Sep 17 00:00:00 2001 From: Hannes Schmelzer Date: Tue, 9 Jan 2018 19:01:31 +0100 Subject: [PATCH 1/6] mach-omap2: add AM335x Display PLL register definition Adds the register definition of the Display DPLL Signed-off-by: Hannes Schmelzer Reviewed-by: Anatolij Gustschin --- arch/arm/include/asm/arch-am33xx/clock.h | 1 + arch/arm/mach-omap2/am33xx/clock_am33xx.c | 7 +++++++ 2 files changed, 8 insertions(+) diff --git a/arch/arm/include/asm/arch-am33xx/clock.h b/arch/arm/include/asm/arch-am33xx/clock.h index 5399bb81f0b..9dbcd3a4075 100644 --- a/arch/arm/include/asm/arch-am33xx/clock.h +++ b/arch/arm/include/asm/arch-am33xx/clock.h @@ -104,6 +104,7 @@ extern const struct dpll_regs dpll_mpu_regs; extern const struct dpll_regs dpll_core_regs; extern const struct dpll_regs dpll_per_regs; extern const struct dpll_regs dpll_ddr_regs; +extern const struct dpll_regs dpll_disp_regs; extern const struct dpll_params dpll_mpu_opp[NUM_CRYSTAL_FREQ][NUM_OPPS]; extern const struct dpll_params dpll_core_1000MHz[NUM_CRYSTAL_FREQ]; extern const struct dpll_params dpll_per_192MHz[NUM_CRYSTAL_FREQ]; diff --git a/arch/arm/mach-omap2/am33xx/clock_am33xx.c b/arch/arm/mach-omap2/am33xx/clock_am33xx.c index 1780bbdb6fb..9ab4d250d27 100644 --- a/arch/arm/mach-omap2/am33xx/clock_am33xx.c +++ b/arch/arm/mach-omap2/am33xx/clock_am33xx.c @@ -52,6 +52,13 @@ const struct dpll_regs dpll_ddr_regs = { .cm_div_m2_dpll = CM_WKUP + 0xA0, }; +const struct dpll_regs dpll_disp_regs = { + .cm_clkmode_dpll = CM_WKUP + 0x98, + .cm_idlest_dpll = CM_WKUP + 0x48, + .cm_clksel_dpll = CM_WKUP + 0x54, + .cm_div_m2_dpll = CM_WKUP + 0xA4, +}; + struct dpll_params dpll_mpu_opp100 = { CONFIG_SYS_MPUCLK, OSC-1, 1, -1, -1, -1, -1}; const struct dpll_params dpll_core_opp100 = { From e880a5e21988d8fef77b916486b26432218bb226 Mon Sep 17 00:00:00 2001 From: Hannes Schmelzer Date: Tue, 9 Jan 2018 19:01:32 +0100 Subject: [PATCH 2/6] am335x-fb: cosmetic: update-copyright Signed-off-by: Hannes Schmelzer Reviewed-by: Anatolij Gustschin --- drivers/video/am335x-fb.c | 4 ++-- drivers/video/am335x-fb.h | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/drivers/video/am335x-fb.c b/drivers/video/am335x-fb.c index a8b3e747a03..c8100d809c8 100644 --- a/drivers/video/am335x-fb.c +++ b/drivers/video/am335x-fb.c @@ -1,6 +1,6 @@ /* - * Copyright (C) 2013 Hannes Schmelzer - * Bernecker & Rainer Industrieelektronik GmbH - http://www.br-automation.com + * Copyright (C) 2013-2018 Hannes Schmelzer + * B&R Industrial Automation GmbH - http://www.br-automation.com * * minimal framebuffer driver for TI's AM335x SoC to be compatible with * Wolfgang Denk's LCD-Framework (CONFIG_LCD, common/lcd.c) diff --git a/drivers/video/am335x-fb.h b/drivers/video/am335x-fb.h index 3f4b567ce2d..903a8f160c1 100644 --- a/drivers/video/am335x-fb.h +++ b/drivers/video/am335x-fb.h @@ -1,6 +1,6 @@ /* - * Copyright (C) 2013 Hannes Schmelzer - - * Bernecker & Rainer Industrieelektronik GmbH - http://www.br-automation.com + * Copyright (C) 2013-2018 Hannes Schmelzer - + * B&R Industrial Automation GmbH - http://www.br-automation.com * * SPDX-License-Identifier: GPL-2.0+ */ From 0d8a7d6fa8b09f940b2087b3bc5696b59dd049df Mon Sep 17 00:00:00 2001 From: Hannes Schmelzer Date: Tue, 9 Jan 2018 19:01:33 +0100 Subject: [PATCH 3/6] am335x-fb: cosmetic: fix coding style Signed-off-by: Hannes Schmelzer Reviewed-by: Anatolij Gustschin --- drivers/video/am335x-fb.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/drivers/video/am335x-fb.c b/drivers/video/am335x-fb.c index c8100d809c8..697b701ebcd 100644 --- a/drivers/video/am335x-fb.c +++ b/drivers/video/am335x-fb.c @@ -108,11 +108,11 @@ int am335xfb_init(struct am335x_lcdpanel *panel) { u32 raster_ctrl = 0; - if (0 == gd->fb_base) { + if (gd->fb_base == 0) { printf("ERROR: no valid fb_base stored in GLOBAL_DATA_PTR!\n"); return -1; } - if (0 == panel) { + if (panel == NULL) { printf("ERROR: missing ptr to am335x_lcdpanel!\n"); return -1; } @@ -147,7 +147,7 @@ int am335xfb_init(struct am335x_lcdpanel *panel) gd->fb_base += 0x20; /* turn ON display through powercontrol function if accessible */ - if (0 != panel->panel_power_ctrl) + if (panel->panel_power_ctrl != NULL) panel->panel_power_ctrl(1); debug("am335x-fb: wait for stable power ...\n"); From 8a094f508c4576626cdcc1b5a7513066180cd798 Mon Sep 17 00:00:00 2001 From: Hannes Schmelzer Date: Tue, 9 Jan 2018 19:01:34 +0100 Subject: [PATCH 4/6] am335x-fb: setup display PLL 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 Reviewed-by: Anatolij Gustschin --- 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 697b701ebcd..a7892f799e8 100644 --- a/drivers/video/am335x-fb.c +++ b/drivers/video/am335x-fb.c @@ -12,7 +12,11 @@ * SPDX-License-Identifier: GPL-2.0+ */ #include +#include #include +#include +#include +#include #include #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 == 0) { 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 903a8f160c1..f99b3413348 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 From 0fcec5775207353fd7ffcdeaad7f490d9a56be2c Mon Sep 17 00:00:00 2001 From: Hannes Schmelzer Date: Tue, 9 Jan 2018 19:01:35 +0100 Subject: [PATCH 5/6] board/BuR: provide real clock-frequency instead a divider Actual am335x-fb implementation takes now a real clock frequency instead a divider. So this component doesn't need to know anymore some base frequency of the LCDC, we simply provide the pixel-clock frequency. Signed-off-by: Hannes Schmelzer Reviewed-by: Anatolij Gustschin --- board/BuR/common/common.c | 14 ++++---------- 1 file changed, 4 insertions(+), 10 deletions(-) diff --git a/board/BuR/common/common.c b/board/BuR/common/common.c index c1cd0100239..d82b8cdfe2e 100644 --- a/board/BuR/common/common.c +++ b/board/BuR/common/common.c @@ -139,13 +139,7 @@ int load_lcdtiming(struct am335x_lcdpanel *panel) pnltmp.vsw = FDTPROP(PATHTIM, "vsync-len"); pnltmp.pup_delay = FDTPROP(PATHTIM, "pupdelay"); pnltmp.pon_delay = FDTPROP(PATHTIM, "pondelay"); - - /* calc. proper clk-divisor */ - dtbprop = FDTPROP(PATHTIM, "clock-frequency"); - if (dtbprop != ~0UL) - pnltmp.pxl_clk_div = 192000000 / dtbprop; - else - pnltmp.pxl_clk_div = ~0UL; + pnltmp.pxl_clk = FDTPROP(PATHTIM, "clock-frequency"); /* check polarity of control-signals */ dtbprop = FDTPROP(PATHTIM, "hsync-active"); @@ -195,7 +189,7 @@ int load_lcdtiming(struct am335x_lcdpanel *panel) pnltmp.vfp = env_get_ulong("ds1_vfp", 10, ~0UL); pnltmp.vbp = env_get_ulong("ds1_vbp", 10, ~0UL); pnltmp.vsw = env_get_ulong("ds1_vsw", 10, ~0UL); - pnltmp.pxl_clk_div = env_get_ulong("ds1_pxlclkdiv", 10, ~0UL); + pnltmp.pxl_clk = env_get_ulong("ds1_pxlclk", 10, ~0UL); pnltmp.pol = env_get_ulong("ds1_pol", 16, ~0UL); pnltmp.pup_delay = env_get_ulong("ds1_pupdelay", 10, ~0UL); pnltmp.pon_delay = env_get_ulong("ds1_tondelay", 10, ~0UL); @@ -211,7 +205,7 @@ int load_lcdtiming(struct am335x_lcdpanel *panel) ~0UL == (pnltmp.vfp) || ~0UL == (pnltmp.vbp) || ~0UL == (pnltmp.vsw) || - ~0UL == (pnltmp.pxl_clk_div) || + ~0UL == (pnltmp.pxl_clk) || ~0UL == (pnltmp.pol) || ~0UL == (pnltmp.pup_delay) || ~0UL == (pnltmp.pon_delay) @@ -234,7 +228,7 @@ int load_lcdtiming(struct am335x_lcdpanel *panel) pnltmp.hactive, pnltmp.vactive, pnltmp.bpp, pnltmp.hfp, pnltmp.hbp, pnltmp.hsw, pnltmp.vfp, pnltmp.vbp, pnltmp.vsw, - pnltmp.pxl_clk_div, pnltmp.pol, pnltmp.pon_delay); + pnltmp.pxl_clk, pnltmp.pol, pnltmp.pon_delay); return -1; } From 193f6fb9e8659b63afcd09f24fec92d70497ccf5 Mon Sep 17 00:00:00 2001 From: Hannes Schmelzer Date: Tue, 9 Jan 2018 19:01:36 +0100 Subject: [PATCH 6/6] board/BuR: drop LCDC clock manipulation from board code The clock selection is done now from the am335x-fb code, so there is no more need doing this in the board code. Signed-off-by: Hannes Schmelzer Reviewed-by: Anatolij Gustschin --- board/BuR/brppt1/board.c | 3 --- board/BuR/brxre1/board.c | 2 -- 2 files changed, 5 deletions(-) diff --git a/board/BuR/brppt1/board.c b/board/BuR/brppt1/board.c index 6083479f2b0..9f7b2d98a61 100644 --- a/board/BuR/brppt1/board.c +++ b/board/BuR/brppt1/board.c @@ -120,9 +120,6 @@ void am33xx_spl_board_init(void) }; do_enable_clocks(clk_domains, clk_modules_tsspecific, 1); - /* setup LCD-Pixel Clock */ - writel(0x2, &cmdpll->clklcdcpixelclk); /* clock comes from perPLL M2 */ - /* setup I2C */ enable_i2c_pin_mux(); i2c_set_bus_num(0); diff --git a/board/BuR/brxre1/board.c b/board/BuR/brxre1/board.c index ca08f3cd908..7e834370216 100644 --- a/board/BuR/brxre1/board.c +++ b/board/BuR/brxre1/board.c @@ -114,8 +114,6 @@ void am33xx_spl_board_init(void) 0 }; do_enable_clocks(clk_domains, clk_modules_xre1specific, 1); - /* setup LCD-Pixel Clock */ - writel(0x2, CM_DPLL + 0x34); /* power-OFF LCD-Display */ gpio_direction_output(LCD_PWR, 0);