uboot/drivers/video/ti/am335x-fb.c
<<
>>
Prefs
   1// SPDX-License-Identifier: GPL-2.0+
   2/*
   3 * Copyright (C) 2013-2018 Hannes Schmelzer <oe5hpm@oevsv.at>
   4 * B&R Industrial Automation GmbH - http://www.br-automation.com
   5 * Copyright (C) 2020 Dario Binacchi <dariobin@libero.it>
   6 *
   7 * minimal framebuffer driver for TI's AM335x SoC to be compatible with
   8 * Wolfgang Denk's LCD-Framework (CONFIG_LCD, common/lcd.c)
   9 *
  10 * - supporting 16/24/32bit RGB/TFT raster Mode (not using palette)
  11 * - sets up LCD controller as in 'am335x_lcdpanel' struct given
  12 * - starts output DMA from gd->fb_base buffer
  13 */
  14#include <common.h>
  15#include <lcd.h>
  16#include <log.h>
  17#include <asm/arch/clock.h>
  18#include <asm/arch/hardware.h>
  19#include <asm/arch/omap.h>
  20#include <asm/arch/sys_proto.h>
  21#include <asm/global_data.h>
  22#include <asm/io.h>
  23#include <linux/delay.h>
  24#include <linux/err.h>
  25#include "am335x-fb.h"
  26
  27#define LCDC_FMAX                               200000000
  28
  29/* LCD Control Register */
  30#define LCDC_CTRL_CLK_DIVISOR_MASK              GENMASK(15, 8)
  31#define LCDC_CTRL_RASTER_MODE                   BIT(0)
  32#define LCDC_CTRL_CLK_DIVISOR(x)                (((x) & GENMASK(7, 0)) << 8)
  33/* LCD Clock Enable Register */
  34#define LCDC_CLKC_ENABLE_CORECLKEN              BIT(0)
  35#define LCDC_CLKC_ENABLE_LIDDCLKEN              BIT(1)
  36#define LCDC_CLKC_ENABLE_DMACLKEN               BIT(2)
  37/* LCD DMA Control Register */
  38#define LCDC_DMA_CTRL_BURST_SIZE(x)             (((x) & GENMASK(2, 0)) << 4)
  39#define LCDC_DMA_CTRL_BURST_1                   0x0
  40#define LCDC_DMA_CTRL_BURST_2                   0x1
  41#define LCDC_DMA_CTRL_BURST_4                   0x2
  42#define LCDC_DMA_CTRL_BURST_8                   0x3
  43#define LCDC_DMA_CTRL_BURST_16                  0x4
  44#define LCDC_DMA_CTRL_FIFO_TH(x)                (((x) & GENMASK(2, 0)) << 8)
  45/* LCD Timing_0 Register */
  46#define LCDC_RASTER_TIMING_0_HORMSB(x)  ((((x) - 1) & BIT(10)) >> 7)
  47#define LCDC_RASTER_TIMING_0_HORLSB(x) (((((x) >> 4) - 1) & GENMASK(5, 0)) << 4)
  48#define LCDC_RASTER_TIMING_0_HSWLSB(x)  ((((x) - 1) & GENMASK(5, 0)) << 10)
  49#define LCDC_RASTER_TIMING_0_HFPLSB(x)  ((((x) - 1) & GENMASK(7, 0)) << 16)
  50#define LCDC_RASTER_TIMING_0_HBPLSB(x)  ((((x) - 1) & GENMASK(7, 0)) << 24)
  51/* LCD Timing_1 Register */
  52#define LCDC_RASTER_TIMING_1_VERLSB(x)          (((x) - 1) & GENMASK(9, 0))
  53#define LCDC_RASTER_TIMING_1_VSW(x)     ((((x) - 1) & GENMASK(5, 0)) << 10)
  54#define LCDC_RASTER_TIMING_1_VFP(x)             (((x) & GENMASK(7, 0)) << 16)
  55#define LCDC_RASTER_TIMING_1_VBP(x)             (((x) & GENMASK(7, 0)) << 24)
  56/* LCD Timing_2 Register */
  57#define LCDC_RASTER_TIMING_2_HFPMSB(x)  ((((x) - 1) & GENMASK(9, 8)) >> 8)
  58#define LCDC_RASTER_TIMING_2_HBPMSB(x)  ((((x) - 1) & GENMASK(9, 8)) >> 4)
  59#define LCDC_RASTER_TIMING_2_ACB(x)             (((x) & GENMASK(7, 0)) << 8)
  60#define LCDC_RASTER_TIMING_2_ACBI(x)            (((x) & GENMASK(3, 0)) << 16)
  61#define LCDC_RASTER_TIMING_2_VSYNC_INVERT       BIT(20)
  62#define LCDC_RASTER_TIMING_2_HSYNC_INVERT       BIT(21)
  63#define LCDC_RASTER_TIMING_2_PXCLK_INVERT       BIT(22)
  64#define LCDC_RASTER_TIMING_2_DE_INVERT          BIT(23)
  65#define LCDC_RASTER_TIMING_2_HSVS_RISEFALL      BIT(24)
  66#define LCDC_RASTER_TIMING_2_HSVS_CONTROL       BIT(25)
  67#define LCDC_RASTER_TIMING_2_VERMSB(x)          ((((x) - 1) & BIT(10)) << 16)
  68#define LCDC_RASTER_TIMING_2_HSWMSB(x)  ((((x) - 1) & GENMASK(9, 6)) << 21)
  69/* LCD Raster Ctrl Register */
  70#define LCDC_RASTER_CTRL_ENABLE                 BIT(0)
  71#define LCDC_RASTER_CTRL_TFT_MODE               BIT(7)
  72#define LCDC_RASTER_CTRL_DATA_ORDER             BIT(8)
  73#define LCDC_RASTER_CTRL_REQDLY(x)              (((x) & GENMASK(7, 0)) << 12)
  74#define LCDC_RASTER_CTRL_PALMODE_RAWDATA        (0x02 << 20)
  75#define LCDC_RASTER_CTRL_TFT_ALT_ENABLE         BIT(23)
  76#define LCDC_RASTER_CTRL_TFT_24BPP_MODE         BIT(25)
  77#define LCDC_RASTER_CTRL_TFT_24BPP_UNPACK       BIT(26)
  78
  79struct am335x_lcdhw {
  80        unsigned int            pid;                    /* 0x00 */
  81        unsigned int            ctrl;                   /* 0x04 */
  82        unsigned int            gap0;                   /* 0x08 */
  83        unsigned int            lidd_ctrl;              /* 0x0C */
  84        unsigned int            lidd_cs0_conf;          /* 0x10 */
  85        unsigned int            lidd_cs0_addr;          /* 0x14 */
  86        unsigned int            lidd_cs0_data;          /* 0x18 */
  87        unsigned int            lidd_cs1_conf;          /* 0x1C */
  88        unsigned int            lidd_cs1_addr;          /* 0x20 */
  89        unsigned int            lidd_cs1_data;          /* 0x24 */
  90        unsigned int            raster_ctrl;            /* 0x28 */
  91        unsigned int            raster_timing0;         /* 0x2C */
  92        unsigned int            raster_timing1;         /* 0x30 */
  93        unsigned int            raster_timing2;         /* 0x34 */
  94        unsigned int            raster_subpanel;        /* 0x38 */
  95        unsigned int            raster_subpanel2;       /* 0x3C */
  96        unsigned int            lcddma_ctrl;            /* 0x40 */
  97        unsigned int            lcddma_fb0_base;        /* 0x44 */
  98        unsigned int            lcddma_fb0_ceiling;     /* 0x48 */
  99        unsigned int            lcddma_fb1_base;        /* 0x4C */
 100        unsigned int            lcddma_fb1_ceiling;     /* 0x50 */
 101        unsigned int            sysconfig;              /* 0x54 */
 102        unsigned int            irqstatus_raw;          /* 0x58 */
 103        unsigned int            irqstatus;              /* 0x5C */
 104        unsigned int            irqenable_set;          /* 0x60 */
 105        unsigned int            irqenable_clear;        /* 0x64 */
 106        unsigned int            gap1;                   /* 0x68 */
 107        unsigned int            clkc_enable;            /* 0x6C */
 108        unsigned int            clkc_reset;             /* 0x70 */
 109};
 110
 111DECLARE_GLOBAL_DATA_PTR;
 112
 113#if !defined(LCD_CNTL_BASE)
 114#error "hw-base address of LCD-Controller (LCD_CNTL_BASE) not defined!"
 115#endif
 116
 117/* Macro definitions */
 118#define FBSIZE(x)       (((x)->hactive * (x)->vactive * (x)->bpp) >> 3)
 119
 120#define LCDC_RASTER_TIMING_2_INVMASK(x)         ((x) & GENMASK(25, 20))
 121
 122static struct am335x_lcdhw *lcdhw = (void *)LCD_CNTL_BASE;
 123
 124int lcd_get_size(int *line_length)
 125{
 126        *line_length = (panel_info.vl_col * NBITS(panel_info.vl_bpix)) / 8;
 127        return *line_length * panel_info.vl_row + 0x20;
 128}
 129
 130struct dpll_data {
 131        unsigned long rounded_rate;
 132        u16 rounded_m;
 133        u8 rounded_n;
 134        u8 rounded_div;
 135};
 136
 137/**
 138 * am335x_dpll_round_rate() - Round a target rate for an OMAP DPLL
 139 *
 140 * @dpll_data: struct dpll_data pointer for the DPLL
 141 * @rate:      New DPLL clock rate
 142 * @return rounded rate and the computed m, n and div values in the dpll_data
 143 *         structure, or -ve error code.
 144 */
 145static ulong am335x_dpll_round_rate(struct dpll_data *dd, ulong rate)
 146{
 147        unsigned int m, n, d;
 148        unsigned long rounded_rate;
 149        int err, err_r;
 150
 151        dd->rounded_rate = -EFAULT;
 152        err = rate;
 153        err_r = err;
 154
 155        for (d = 2; err && d < 255; d++) {
 156                for (m = 2; m < 2047; m++) {
 157                        if ((V_OSCK * m) < (rate * d))
 158                                continue;
 159
 160                        n = (V_OSCK * m) / (rate * d);
 161                        if (n > 127)
 162                                break;
 163
 164                        if (((V_OSCK * m) / n) > LCDC_FMAX)
 165                                break;
 166
 167                        rounded_rate = (V_OSCK * m) / n / d;
 168                        err = abs(rounded_rate - rate);
 169                        if (err < err_r) {
 170                                err_r = err;
 171                                dd->rounded_rate = rounded_rate;
 172                                dd->rounded_m = m;
 173                                dd->rounded_n = n;
 174                                dd->rounded_div = d;
 175                                if (err == 0)
 176                                        break;
 177                        }
 178                }
 179        }
 180
 181        debug("DPLL display: best error %d Hz (M %d, N %d, DIV %d)\n",
 182              err_r, dd->rounded_m, dd->rounded_n, dd->rounded_div);
 183
 184        return dd->rounded_rate;
 185}
 186
 187/**
 188 * am335x_fb_set_pixel_clk_rate() - Set pixel clock rate.
 189 *
 190 * @am335x_lcdhw: Base address of the LCD controller registers.
 191 * @rate:         New clock rate in Hz.
 192 * @return new rate, or -ve error code.
 193 */
 194static ulong am335x_fb_set_pixel_clk_rate(struct am335x_lcdhw *regs, ulong rate)
 195{
 196        struct dpll_params dpll_disp = { 1, 0, 1, -1, -1, -1, -1 };
 197        struct dpll_data dd;
 198        ulong round_rate;
 199        u32 reg;
 200
 201        round_rate = am335x_dpll_round_rate(&dd, rate);
 202        if (IS_ERR_VALUE(round_rate))
 203                return round_rate;
 204
 205        dpll_disp.m = dd.rounded_m;
 206        dpll_disp.n = dd.rounded_n;
 207        do_setup_dpll(&dpll_disp_regs, &dpll_disp);
 208
 209        reg = readl(&regs->ctrl) & ~LCDC_CTRL_CLK_DIVISOR_MASK;
 210        reg |= LCDC_CTRL_CLK_DIVISOR(dd.rounded_div);
 211        writel(reg, &regs->ctrl);
 212        return round_rate;
 213}
 214
 215int am335xfb_init(struct am335x_lcdpanel *panel)
 216{
 217        u32 raster_ctrl = 0;
 218        struct cm_dpll *const cmdpll = (struct cm_dpll *)CM_DPLL;
 219        ulong rate;
 220        u32 reg;
 221
 222        if (gd->fb_base == 0) {
 223                printf("ERROR: no valid fb_base stored in GLOBAL_DATA_PTR!\n");
 224                return -1;
 225        }
 226        if (panel == NULL) {
 227                printf("ERROR: missing ptr to am335x_lcdpanel!\n");
 228                return -1;
 229        }
 230
 231        /* We can already set the bits for the raster_ctrl in this check */
 232        switch (panel->bpp) {
 233        case 16:
 234                break;
 235        case 32:
 236                raster_ctrl |= LCDC_RASTER_CTRL_TFT_24BPP_UNPACK;
 237                /* fallthrough */
 238        case 24:
 239                raster_ctrl |= LCDC_RASTER_CTRL_TFT_24BPP_MODE;
 240                break;
 241        default:
 242                pr_err("am335x-fb: invalid bpp value: %d\n", panel->bpp);
 243                return -1;
 244        }
 245
 246        /* check given clock-frequency */
 247        if (panel->pxl_clk > (LCDC_FMAX / 2)) {
 248                pr_err("am335x-fb: requested pxl-clk: %d not supported!\n",
 249                       panel->pxl_clk);
 250                return -1;
 251        }
 252
 253        debug("setting up LCD-Controller for %dx%dx%d (hfp=%d,hbp=%d,hsw=%d / ",
 254              panel->hactive, panel->vactive, panel->bpp,
 255              panel->hfp, panel->hbp, panel->hsw);
 256        debug("vfp=%d,vbp=%d,vsw=%d / clk=%d)\n",
 257              panel->vfp, panel->vfp, panel->vsw, panel->pxl_clk);
 258        debug("using frambuffer at 0x%08x with size %d.\n",
 259              (unsigned int)gd->fb_base, FBSIZE(panel));
 260
 261        rate = am335x_fb_set_pixel_clk_rate(lcdhw, panel->pxl_clk);
 262        if (IS_ERR_VALUE(rate))
 263                return rate;
 264
 265        /* clock source for LCDC from dispPLL M2 */
 266        writel(0x0, &cmdpll->clklcdcpixelclk);
 267
 268        /* palette default entry */
 269        memset((void *)gd->fb_base, 0, 0x20);
 270        *(unsigned int *)gd->fb_base = 0x4000;
 271        /* point fb behind palette */
 272        gd->fb_base += 0x20;
 273
 274        /* turn ON display through powercontrol function if accessible */
 275        if (panel->panel_power_ctrl != NULL)
 276                panel->panel_power_ctrl(1);
 277
 278        debug("am335x-fb: wait for stable power ...\n");
 279        mdelay(panel->pup_delay);
 280        lcdhw->clkc_enable = LCDC_CLKC_ENABLE_CORECLKEN |
 281                LCDC_CLKC_ENABLE_LIDDCLKEN | LCDC_CLKC_ENABLE_DMACLKEN;
 282        lcdhw->raster_ctrl = 0;
 283
 284        reg = lcdhw->ctrl & LCDC_CTRL_CLK_DIVISOR_MASK;
 285        reg |= LCDC_CTRL_RASTER_MODE;
 286        lcdhw->ctrl = reg;
 287
 288        lcdhw->lcddma_fb0_base = gd->fb_base;
 289        lcdhw->lcddma_fb0_ceiling = gd->fb_base + FBSIZE(panel);
 290        lcdhw->lcddma_fb1_base = gd->fb_base;
 291        lcdhw->lcddma_fb1_ceiling = gd->fb_base + FBSIZE(panel);
 292        lcdhw->lcddma_ctrl = LCDC_DMA_CTRL_BURST_SIZE(LCDC_DMA_CTRL_BURST_16);
 293
 294        lcdhw->raster_timing0 = LCDC_RASTER_TIMING_0_HORLSB(panel->hactive) |
 295                                LCDC_RASTER_TIMING_0_HORMSB(panel->hactive) |
 296                                LCDC_RASTER_TIMING_0_HFPLSB(panel->hfp) |
 297                                LCDC_RASTER_TIMING_0_HBPLSB(panel->hbp) |
 298                                LCDC_RASTER_TIMING_0_HSWLSB(panel->hsw);
 299        lcdhw->raster_timing1 = LCDC_RASTER_TIMING_1_VBP(panel->vbp) |
 300                                LCDC_RASTER_TIMING_1_VFP(panel->vfp) |
 301                                LCDC_RASTER_TIMING_1_VSW(panel->vsw) |
 302                                LCDC_RASTER_TIMING_1_VERLSB(panel->vactive);
 303        lcdhw->raster_timing2 = LCDC_RASTER_TIMING_2_HSWMSB(panel->hsw) |
 304                                LCDC_RASTER_TIMING_2_VERMSB(panel->vactive) |
 305                                LCDC_RASTER_TIMING_2_INVMASK(panel->pol) |
 306                                LCDC_RASTER_TIMING_2_HBPMSB(panel->hbp) |
 307                                LCDC_RASTER_TIMING_2_HFPMSB(panel->hfp) |
 308                                0x0000FF00;     /* clk cycles for ac-bias */
 309        lcdhw->raster_ctrl =    raster_ctrl |
 310                                LCDC_RASTER_CTRL_PALMODE_RAWDATA |
 311                                LCDC_RASTER_CTRL_TFT_MODE |
 312                                LCDC_RASTER_CTRL_ENABLE;
 313
 314        debug("am335x-fb: waiting picture to be stable.\n.");
 315        mdelay(panel->pon_delay);
 316
 317        return 0;
 318}
 319