X-Git-Url: https://git.librecmc.org/?a=blobdiff_plain;f=drivers%2Fvideo%2Fam335x-fb.c;h=51c1af587f27b6b41f58584f83c4541d5f8b1187;hb=f541796af929fa28a78dc3162a0ba09d4fa3ce90;hp=6f956499d75332c1185afda7683210a212c7530b;hpb=62f3aaf89d01bdc9ff0e67d92f3bf085143edf8c;p=oweals%2Fu-boot.git diff --git a/drivers/video/am335x-fb.c b/drivers/video/am335x-fb.c index 6f956499d7..51c1af587f 100644 --- a/drivers/video/am335x-fb.c +++ b/drivers/video/am335x-fb.c @@ -1,18 +1,21 @@ +// SPDX-License-Identifier: GPL-2.0+ /* - * Copyright (C) 2013 Hannes Petermaier - * 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) * - * - supporting only 24bit RGB/TFT raster Mode (not using palette) + * - supporting 16/24/32bit RGB/TFT raster Mode (not using palette) * - sets up LCD controller as in 'am335x_lcdpanel' struct given * - starts output DMA from gd->fb_base buffer - * - * SPDX-License-Identifier: GPL-2.0+ */ #include +#include #include +#include +#include +#include #include #include "am335x-fb.h" @@ -20,6 +23,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) @@ -55,7 +59,7 @@ /* LCD Raster Ctrl Register */ #define LCD_TFT_24BPP_MODE (1 << 25) #define LCD_TFT_24BPP_UNPACK (1 << 26) -#define LCD_PALMODE_RAWDATA (0x10 << 20) +#define LCD_PALMODE_RAWDATA (0x02 << 20) #define LCD_TFT_MODE (0x01 << 7) #define LCD_RASTER_ENABLE (0x01 << 0) @@ -96,6 +100,7 @@ struct am335x_lcdhw { }; static struct am335x_lcdhw *lcdhw = (void *)LCD_CNTL_BASE; + DECLARE_GLOBAL_DATA_PTR; int lcd_get_size(int *line_length) @@ -106,40 +111,101 @@ int lcd_get_size(int *line_length) int am335xfb_init(struct am335x_lcdpanel *panel) { - if (0 == gd->fb_base) { + 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; } - if (0 == panel) { + if (panel == NULL) { printf("ERROR: missing ptr to am335x_lcdpanel!\n"); return -1; } + /* We can already set the bits for the raster_ctrl in this check */ + switch (panel->bpp) { + case 16: + break; + case 32: + raster_ctrl |= LCD_TFT_24BPP_UNPACK; + /* fallthrough */ + case 24: + raster_ctrl |= LCD_TFT_24BPP_MODE; + break; + default: + pr_err("am335x-fb: invalid bpp value: %d\n", panel->bpp); + 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; + /* point fb behind palette */ + 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"); 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) + 0x20; + lcdhw->lcddma_fb0_ceiling = gd->fb_base + FBSIZE(panel); lcdhw->lcddma_fb1_base = gd->fb_base; - lcdhw->lcddma_fb1_ceiling = gd->fb_base + FBSIZE(panel) + 0x20; + lcdhw->lcddma_fb1_ceiling = gd->fb_base + FBSIZE(panel); lcdhw->lcddma_ctrl = LCD_DMA_BURST_SIZE(LCD_DMA_BURST_16); lcdhw->raster_timing0 = LCD_HORLSB(panel->hactive) | @@ -157,14 +223,11 @@ int am335xfb_init(struct am335x_lcdpanel *panel) LCD_HBPMSB(panel->hbp) | LCD_HFPMSB(panel->hfp) | 0x0000FF00; /* clk cycles for ac-bias */ - lcdhw->raster_ctrl = LCD_TFT_24BPP_MODE | - LCD_TFT_24BPP_UNPACK | + lcdhw->raster_ctrl = raster_ctrl | LCD_PALMODE_RAWDATA | LCD_TFT_MODE | LCD_RASTER_ENABLE; - gd->fb_base += 0x20; /* point fb behind palette */ - debug("am335x-fb: waiting picture to be stable.\n."); mdelay(panel->pon_delay);