uboot/drivers/video/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 <dm.h>
  16#include <lcd.h>
  17#include <log.h>
  18#include <video.h>
  19#include <asm/arch/clock.h>
  20#include <asm/arch/hardware.h>
  21#include <asm/arch/omap.h>
  22#include <asm/arch/sys_proto.h>
  23#include <asm/io.h>
  24#include <asm/utils.h>
  25#include <linux/delay.h>
  26#include <linux/err.h>
  27#include "am335x-fb.h"
  28
  29#define LCDC_FMAX                               200000000
  30
  31/* LCD Control Register */
  32#define LCDC_CTRL_CLK_DIVISOR_MASK              GENMASK(15, 8)
  33#define LCDC_CTRL_RASTER_MODE                   BIT(0)
  34#define LCDC_CTRL_CLK_DIVISOR(x)                (((x) & GENMASK(7, 0)) << 8)
  35/* LCD Clock Enable Register */
  36#define LCDC_CLKC_ENABLE_CORECLKEN              BIT(0)
  37#define LCDC_CLKC_ENABLE_LIDDCLKEN              BIT(1)
  38#define LCDC_CLKC_ENABLE_DMACLKEN               BIT(2)
  39/* LCD DMA Control Register */
  40#define LCDC_DMA_CTRL_BURST_SIZE(x)             (((x) & GENMASK(2, 0)) << 4)
  41#define LCDC_DMA_CTRL_BURST_1                   0x0
  42#define LCDC_DMA_CTRL_BURST_2                   0x1
  43#define LCDC_DMA_CTRL_BURST_4                   0x2
  44#define LCDC_DMA_CTRL_BURST_8                   0x3
  45#define LCDC_DMA_CTRL_BURST_16                  0x4
  46#define LCDC_DMA_CTRL_FIFO_TH(x)                (((x) & GENMASK(2, 0)) << 8)
  47/* LCD Timing_0 Register */
  48#define LCDC_RASTER_TIMING_0_HORMSB(x)  ((((x) - 1) & BIT(10)) >> 7)
  49#define LCDC_RASTER_TIMING_0_HORLSB(x) (((((x) >> 4) - 1) & GENMASK(5, 0)) << 4)
  50#define LCDC_RASTER_TIMING_0_HSWLSB(x)  ((((x) - 1) & GENMASK(5, 0)) << 10)
  51#define LCDC_RASTER_TIMING_0_HFPLSB(x)  ((((x) - 1) & GENMASK(7, 0)) << 16)
  52#define LCDC_RASTER_TIMING_0_HBPLSB(x)  ((((x) - 1) & GENMASK(7, 0)) << 24)
  53/* LCD Timing_1 Register */
  54#define LCDC_RASTER_TIMING_1_VERLSB(x)          (((x) - 1) & GENMASK(9, 0))
  55#define LCDC_RASTER_TIMING_1_VSW(x)     ((((x) - 1) & GENMASK(5, 0)) << 10)
  56#define LCDC_RASTER_TIMING_1_VFP(x)             (((x) & GENMASK(7, 0)) << 16)
  57#define LCDC_RASTER_TIMING_1_VBP(x)             (((x) & GENMASK(7, 0)) << 24)
  58/* LCD Timing_2 Register */
  59#define LCDC_RASTER_TIMING_2_HFPMSB(x)  ((((x) - 1) & GENMASK(9, 8)) >> 8)
  60#define LCDC_RASTER_TIMING_2_HBPMSB(x)  ((((x) - 1) & GENMASK(9, 8)) >> 4)
  61#define LCDC_RASTER_TIMING_2_ACB(x)             (((x) & GENMASK(7, 0)) << 8)
  62#define LCDC_RASTER_TIMING_2_ACBI(x)            (((x) & GENMASK(3, 0)) << 16)
  63#define LCDC_RASTER_TIMING_2_VSYNC_INVERT       BIT(20)
  64#define LCDC_RASTER_TIMING_2_HSYNC_INVERT       BIT(21)
  65#define LCDC_RASTER_TIMING_2_PXCLK_INVERT       BIT(22)
  66#define LCDC_RASTER_TIMING_2_DE_INVERT          BIT(23)
  67#define LCDC_RASTER_TIMING_2_HSVS_RISEFALL      BIT(24)
  68#define LCDC_RASTER_TIMING_2_HSVS_CONTROL       BIT(25)
  69#define LCDC_RASTER_TIMING_2_VERMSB(x)          ((((x) - 1) & BIT(10)) << 16)
  70#define LCDC_RASTER_TIMING_2_HSWMSB(x)  ((((x) - 1) & GENMASK(9, 6)) << 21)
  71/* LCD Raster Ctrl Register */
  72#define LCDC_RASTER_CTRL_ENABLE                 BIT(0)
  73#define LCDC_RASTER_CTRL_TFT_MODE               BIT(7)
  74#define LCDC_RASTER_CTRL_DATA_ORDER             BIT(8)
  75#define LCDC_RASTER_CTRL_REQDLY(x)              (((x) & GENMASK(7, 0)) << 12)
  76#define LCDC_RASTER_CTRL_PALMODE_RAWDATA        (0x02 << 20)
  77#define LCDC_RASTER_CTRL_TFT_ALT_ENABLE         BIT(23)
  78#define LCDC_RASTER_CTRL_TFT_24BPP_MODE         BIT(25)
  79#define LCDC_RASTER_CTRL_TFT_24BPP_UNPACK       BIT(26)
  80
  81struct am335x_lcdhw {
  82        unsigned int            pid;                    /* 0x00 */
  83        unsigned int            ctrl;                   /* 0x04 */
  84        unsigned int            gap0;                   /* 0x08 */
  85        unsigned int            lidd_ctrl;              /* 0x0C */
  86        unsigned int            lidd_cs0_conf;          /* 0x10 */
  87        unsigned int            lidd_cs0_addr;          /* 0x14 */
  88        unsigned int            lidd_cs0_data;          /* 0x18 */
  89        unsigned int            lidd_cs1_conf;          /* 0x1C */
  90        unsigned int            lidd_cs1_addr;          /* 0x20 */
  91        unsigned int            lidd_cs1_data;          /* 0x24 */
  92        unsigned int            raster_ctrl;            /* 0x28 */
  93        unsigned int            raster_timing0;         /* 0x2C */
  94        unsigned int            raster_timing1;         /* 0x30 */
  95        unsigned int            raster_timing2;         /* 0x34 */
  96        unsigned int            raster_subpanel;        /* 0x38 */
  97        unsigned int            raster_subpanel2;       /* 0x3C */
  98        unsigned int            lcddma_ctrl;            /* 0x40 */
  99        unsigned int            lcddma_fb0_base;        /* 0x44 */
 100        unsigned int            lcddma_fb0_ceiling;     /* 0x48 */
 101        unsigned int            lcddma_fb1_base;        /* 0x4C */
 102        unsigned int            lcddma_fb1_ceiling;     /* 0x50 */
 103        unsigned int            sysconfig;              /* 0x54 */
 104        unsigned int            irqstatus_raw;          /* 0x58 */
 105        unsigned int            irqstatus;              /* 0x5C */
 106        unsigned int            irqenable_set;          /* 0x60 */
 107        unsigned int            irqenable_clear;        /* 0x64 */
 108        unsigned int            gap1;                   /* 0x68 */
 109        unsigned int            clkc_enable;            /* 0x6C */
 110        unsigned int            clkc_reset;             /* 0x70 */
 111};
 112
 113struct dpll_data {
 114        unsigned long rounded_rate;
 115        u16 rounded_m;
 116        u8 rounded_n;
 117        u8 rounded_div;
 118};
 119
 120DECLARE_GLOBAL_DATA_PTR;
 121
 122/**
 123 * am335x_dpll_round_rate() - Round a target rate for an OMAP DPLL
 124 *
 125 * @dpll_data: struct dpll_data pointer for the DPLL
 126 * @rate:      New DPLL clock rate
 127 * @return rounded rate and the computed m, n and div values in the dpll_data
 128 *         structure, or -ve error code.
 129 */
 130static ulong am335x_dpll_round_rate(struct dpll_data *dd, ulong rate)
 131{
 132        unsigned int m, n, d;
 133        unsigned long rounded_rate;
 134        int err, err_r;
 135
 136        dd->rounded_rate = -EFAULT;
 137        err = rate;
 138        err_r = err;
 139
 140        for (d = 2; err && d < 255; d++) {
 141                for (m = 2; m < 2047; m++) {
 142                        if ((V_OSCK * m) < (rate * d))
 143                                continue;
 144
 145                        n = (V_OSCK * m) / (rate * d);
 146                        if (n > 127)
 147                                break;
 148
 149                        if (((V_OSCK * m) / n) > LCDC_FMAX)
 150                                break;
 151
 152                        rounded_rate = (V_OSCK * m) / n / d;
 153                        err = abs(rounded_rate - rate);
 154                        if (err < err_r) {
 155                                err_r = err;
 156                                dd->rounded_rate = rounded_rate;
 157                                dd->rounded_m = m;
 158                                dd->rounded_n = n;
 159                                dd->rounded_div = d;
 160                                if (err == 0)
 161                                        break;
 162                        }
 163                }
 164        }
 165
 166        debug("DPLL display: best error %d Hz (M %d, N %d, DIV %d)\n",
 167              err_r, dd->rounded_m, dd->rounded_n, dd->rounded_div);
 168
 169        return dd->rounded_rate;
 170}
 171
 172/**
 173 * am335x_fb_set_pixel_clk_rate() - Set pixel clock rate.
 174 *
 175 * @am335x_lcdhw: Base address of the LCD controller registers.
 176 * @rate:         New clock rate in Hz.
 177 * @return new rate, or -ve error code.
 178 */
 179static ulong am335x_fb_set_pixel_clk_rate(struct am335x_lcdhw *regs, ulong rate)
 180{
 181        struct dpll_params dpll_disp = { 1, 0, 1, -1, -1, -1, -1 };
 182        struct dpll_data dd;
 183        ulong round_rate;
 184        u32 reg;
 185
 186        round_rate = am335x_dpll_round_rate(&dd, rate);
 187        if (IS_ERR_VALUE(round_rate))
 188                return round_rate;
 189
 190        dpll_disp.m = dd.rounded_m;
 191        dpll_disp.n = dd.rounded_n;
 192        do_setup_dpll(&dpll_disp_regs, &dpll_disp);
 193
 194        reg = readl(&regs->ctrl) & ~LCDC_CTRL_CLK_DIVISOR_MASK;
 195        reg |= LCDC_CTRL_CLK_DIVISOR(dd.rounded_div);
 196        writel(reg, &regs->ctrl);
 197        return round_rate;
 198}
 199
 200#if !CONFIG_IS_ENABLED(DM_VIDEO)
 201
 202#if !defined(LCD_CNTL_BASE)
 203#error "hw-base address of LCD-Controller (LCD_CNTL_BASE) not defined!"
 204#endif
 205
 206/* Macro definitions */
 207#define FBSIZE(x)       (((x)->hactive * (x)->vactive * (x)->bpp) >> 3)
 208
 209#define LCDC_RASTER_TIMING_2_INVMASK(x)         ((x) & GENMASK(25, 20))
 210
 211static struct am335x_lcdhw *lcdhw = (void *)LCD_CNTL_BASE;
 212
 213int lcd_get_size(int *line_length)
 214{
 215        *line_length = (panel_info.vl_col * NBITS(panel_info.vl_bpix)) / 8;
 216        return *line_length * panel_info.vl_row + 0x20;
 217}
 218
 219int am335xfb_init(struct am335x_lcdpanel *panel)
 220{
 221        u32 raster_ctrl = 0;
 222        struct cm_dpll *const cmdpll = (struct cm_dpll *)CM_DPLL;
 223        ulong rate;
 224        u32 reg;
 225
 226        if (gd->fb_base == 0) {
 227                printf("ERROR: no valid fb_base stored in GLOBAL_DATA_PTR!\n");
 228                return -1;
 229        }
 230        if (panel == NULL) {
 231                printf("ERROR: missing ptr to am335x_lcdpanel!\n");
 232                return -1;
 233        }
 234
 235        /* We can already set the bits for the raster_ctrl in this check */
 236        switch (panel->bpp) {
 237        case 16:
 238                break;
 239        case 32:
 240                raster_ctrl |= LCDC_RASTER_CTRL_TFT_24BPP_UNPACK;
 241                /* fallthrough */
 242        case 24:
 243                raster_ctrl |= LCDC_RASTER_CTRL_TFT_24BPP_MODE;
 244                break;
 245        default:
 246                pr_err("am335x-fb: invalid bpp value: %d\n", panel->bpp);
 247                return -1;
 248        }
 249
 250        /* check given clock-frequency */
 251        if (panel->pxl_clk > (LCDC_FMAX / 2)) {
 252                pr_err("am335x-fb: requested pxl-clk: %d not supported!\n",
 253                       panel->pxl_clk);
 254                return -1;
 255        }
 256
 257        debug("setting up LCD-Controller for %dx%dx%d (hfp=%d,hbp=%d,hsw=%d / ",
 258              panel->hactive, panel->vactive, panel->bpp,
 259              panel->hfp, panel->hbp, panel->hsw);
 260        debug("vfp=%d,vbp=%d,vsw=%d / clk=%d)\n",
 261              panel->vfp, panel->vfp, panel->vsw, panel->pxl_clk);
 262        debug("using frambuffer at 0x%08x with size %d.\n",
 263              (unsigned int)gd->fb_base, FBSIZE(panel));
 264
 265        rate = am335x_fb_set_pixel_clk_rate(lcdhw, panel->pxl_clk);
 266        if (IS_ERR_VALUE(rate))
 267                return rate;
 268
 269        /* clock source for LCDC from dispPLL M2 */
 270        writel(0x0, &cmdpll->clklcdcpixelclk);
 271
 272        /* palette default entry */
 273        memset((void *)gd->fb_base, 0, 0x20);
 274        *(unsigned int *)gd->fb_base = 0x4000;
 275        /* point fb behind palette */
 276        gd->fb_base += 0x20;
 277
 278        /* turn ON display through powercontrol function if accessible */
 279        if (panel->panel_power_ctrl != NULL)
 280                panel->panel_power_ctrl(1);
 281
 282        debug("am335x-fb: wait for stable power ...\n");
 283        mdelay(panel->pup_delay);
 284        lcdhw->clkc_enable = LCDC_CLKC_ENABLE_CORECLKEN |
 285                LCDC_CLKC_ENABLE_LIDDCLKEN | LCDC_CLKC_ENABLE_DMACLKEN;
 286        lcdhw->raster_ctrl = 0;
 287
 288        reg = lcdhw->ctrl & LCDC_CTRL_CLK_DIVISOR_MASK;
 289        reg |= LCDC_CTRL_RASTER_MODE;
 290        lcdhw->ctrl = reg;
 291
 292        lcdhw->lcddma_fb0_base = gd->fb_base;
 293        lcdhw->lcddma_fb0_ceiling = gd->fb_base + FBSIZE(panel);
 294        lcdhw->lcddma_fb1_base = gd->fb_base;
 295        lcdhw->lcddma_fb1_ceiling = gd->fb_base + FBSIZE(panel);
 296        lcdhw->lcddma_ctrl = LCDC_DMA_CTRL_BURST_SIZE(LCDC_DMA_CTRL_BURST_16);
 297
 298        lcdhw->raster_timing0 = LCDC_RASTER_TIMING_0_HORLSB(panel->hactive) |
 299                                LCDC_RASTER_TIMING_0_HORMSB(panel->hactive) |
 300                                LCDC_RASTER_TIMING_0_HFPLSB(panel->hfp) |
 301                                LCDC_RASTER_TIMING_0_HBPLSB(panel->hbp) |
 302                                LCDC_RASTER_TIMING_0_HSWLSB(panel->hsw);
 303        lcdhw->raster_timing1 = LCDC_RASTER_TIMING_1_VBP(panel->vbp) |
 304                                LCDC_RASTER_TIMING_1_VFP(panel->vfp) |
 305                                LCDC_RASTER_TIMING_1_VSW(panel->vsw) |
 306                                LCDC_RASTER_TIMING_1_VERLSB(panel->vactive);
 307        lcdhw->raster_timing2 = LCDC_RASTER_TIMING_2_HSWMSB(panel->hsw) |
 308                                LCDC_RASTER_TIMING_2_VERMSB(panel->vactive) |
 309                                LCDC_RASTER_TIMING_2_INVMASK(panel->pol) |
 310                                LCDC_RASTER_TIMING_2_HBPMSB(panel->hbp) |
 311                                LCDC_RASTER_TIMING_2_HFPMSB(panel->hfp) |
 312                                0x0000FF00;     /* clk cycles for ac-bias */
 313        lcdhw->raster_ctrl =    raster_ctrl |
 314                                LCDC_RASTER_CTRL_PALMODE_RAWDATA |
 315                                LCDC_RASTER_CTRL_TFT_MODE |
 316                                LCDC_RASTER_CTRL_ENABLE;
 317
 318        debug("am335x-fb: waiting picture to be stable.\n.");
 319        mdelay(panel->pon_delay);
 320
 321        return 0;
 322}
 323
 324#else /* CONFIG_DM_VIDEO */
 325
 326#define FBSIZE(t, p)    (((t)->hactive.typ * (t)->vactive.typ * (p)->bpp) >> 3)
 327
 328enum {
 329        LCD_MAX_WIDTH           = 2048,
 330        LCD_MAX_HEIGHT          = 2048,
 331        LCD_MAX_LOG2_BPP        = VIDEO_BPP32,
 332};
 333
 334/**
 335 * tilcdc_panel_info: Panel parameters
 336 *
 337 * @ac_bias: AC Bias Pin Frequency
 338 * @ac_bias_intrpt: AC Bias Pin Transitions per Interrupt
 339 * @dma_burst_sz: DMA burst size
 340 * @bpp: Bits per pixel
 341 * @fdd: FIFO DMA Request Delay
 342 * @tft_alt_mode: TFT Alternative Signal Mapping (Only for active)
 343 * @invert_pxl_clk: Invert pixel clock
 344 * @sync_edge: Horizontal and Vertical Sync Edge: 0=rising 1=falling
 345 * @sync_ctrl: Horizontal and Vertical Sync: Control: 0=ignore
 346 * @raster_order: Raster Data Order Select: 1=Most-to-least 0=Least-to-most
 347 * @fifo_th: DMA FIFO threshold
 348 */
 349struct tilcdc_panel_info {
 350        u32 ac_bias;
 351        u32 ac_bias_intrpt;
 352        u32 dma_burst_sz;
 353        u32 bpp;
 354        u32 fdd;
 355        bool tft_alt_mode;
 356        bool invert_pxl_clk;
 357        u32 sync_edge;
 358        u32 sync_ctrl;
 359        u32 raster_order;
 360        u32 fifo_th;
 361};
 362
 363struct am335x_fb_priv {
 364        struct am335x_lcdhw *regs;
 365        struct tilcdc_panel_info panel;
 366        struct display_timing timing;
 367};
 368
 369static int am335x_fb_remove(struct udevice *dev)
 370{
 371        struct video_uc_platdata *uc_plat = dev_get_uclass_platdata(dev);
 372
 373        uc_plat->base -= 0x20;
 374        uc_plat->size += 0x20;
 375        return 0;
 376}
 377
 378static int am335x_fb_probe(struct udevice *dev)
 379{
 380        struct video_uc_platdata *uc_plat = dev_get_uclass_platdata(dev);
 381        struct video_priv *uc_priv = dev_get_uclass_priv(dev);
 382        struct am335x_fb_priv *priv = dev_get_priv(dev);
 383        struct am335x_lcdhw *regs = priv->regs;
 384        struct tilcdc_panel_info *panel = &priv->panel;
 385        struct display_timing *timing = &priv->timing;
 386        struct cm_dpll *const cmdpll = (struct cm_dpll *)CM_DPLL;
 387        u32 reg;
 388
 389        /* Before relocation we don't need to do anything */
 390        if (!(gd->flags & GD_FLG_RELOC))
 391                return 0;
 392
 393        am335x_fb_set_pixel_clk_rate(regs, timing->pixelclock.typ);
 394
 395        /* clock source for LCDC from dispPLL M2 */
 396        writel(0, &cmdpll->clklcdcpixelclk);
 397
 398        /* palette default entry */
 399        memset((void *)uc_plat->base, 0, 0x20);
 400        *(unsigned int *)uc_plat->base = 0x4000;
 401        /* point fb behind palette */
 402        uc_plat->base += 0x20;
 403        uc_plat->size -= 0x20;
 404
 405        writel(LCDC_CLKC_ENABLE_CORECLKEN | LCDC_CLKC_ENABLE_LIDDCLKEN |
 406               LCDC_CLKC_ENABLE_DMACLKEN, &regs->clkc_enable);
 407        writel(0, &regs->raster_ctrl);
 408
 409        reg = readl(&regs->ctrl) & LCDC_CTRL_CLK_DIVISOR_MASK;
 410        reg |= LCDC_CTRL_RASTER_MODE;
 411        writel(reg, &regs->ctrl);
 412
 413        writel(uc_plat->base, &regs->lcddma_fb0_base);
 414        writel(uc_plat->base + FBSIZE(timing, panel),
 415               &regs->lcddma_fb0_ceiling);
 416        writel(uc_plat->base, &regs->lcddma_fb1_base);
 417        writel(uc_plat->base + FBSIZE(timing, panel),
 418               &regs->lcddma_fb1_ceiling);
 419
 420        reg = LCDC_DMA_CTRL_FIFO_TH(panel->fifo_th);
 421        switch (panel->dma_burst_sz) {
 422        case 1:
 423                reg |= LCDC_DMA_CTRL_BURST_SIZE(LCDC_DMA_CTRL_BURST_1);
 424                break;
 425        case 2:
 426                reg |= LCDC_DMA_CTRL_BURST_SIZE(LCDC_DMA_CTRL_BURST_2);
 427                break;
 428        case 4:
 429                reg |= LCDC_DMA_CTRL_BURST_SIZE(LCDC_DMA_CTRL_BURST_4);
 430                break;
 431        case 8:
 432                reg |= LCDC_DMA_CTRL_BURST_SIZE(LCDC_DMA_CTRL_BURST_8);
 433                break;
 434        case 16:
 435                reg |= LCDC_DMA_CTRL_BURST_SIZE(LCDC_DMA_CTRL_BURST_16);
 436                break;
 437        }
 438
 439        writel(reg, &regs->lcddma_ctrl);
 440
 441        writel(LCDC_RASTER_TIMING_0_HORLSB(timing->hactive.typ) |
 442               LCDC_RASTER_TIMING_0_HORMSB(timing->hactive.typ) |
 443               LCDC_RASTER_TIMING_0_HFPLSB(timing->hfront_porch.typ) |
 444               LCDC_RASTER_TIMING_0_HBPLSB(timing->hback_porch.typ) |
 445               LCDC_RASTER_TIMING_0_HSWLSB(timing->hsync_len.typ),
 446               &regs->raster_timing0);
 447
 448        writel(LCDC_RASTER_TIMING_1_VBP(timing->vback_porch.typ) |
 449               LCDC_RASTER_TIMING_1_VFP(timing->vfront_porch.typ) |
 450               LCDC_RASTER_TIMING_1_VSW(timing->vsync_len.typ) |
 451               LCDC_RASTER_TIMING_1_VERLSB(timing->vactive.typ),
 452               &regs->raster_timing1);
 453
 454        reg = LCDC_RASTER_TIMING_2_ACB(panel->ac_bias) |
 455                LCDC_RASTER_TIMING_2_ACBI(panel->ac_bias_intrpt) |
 456                LCDC_RASTER_TIMING_2_HSWMSB(timing->hsync_len.typ) |
 457                LCDC_RASTER_TIMING_2_VERMSB(timing->vactive.typ) |
 458                LCDC_RASTER_TIMING_2_HBPMSB(timing->hback_porch.typ) |
 459                LCDC_RASTER_TIMING_2_HFPMSB(timing->hfront_porch.typ);
 460
 461        if (timing->flags & DISPLAY_FLAGS_VSYNC_LOW)
 462                reg |= LCDC_RASTER_TIMING_2_VSYNC_INVERT;
 463
 464        if (timing->flags & DISPLAY_FLAGS_HSYNC_LOW)
 465                reg |= LCDC_RASTER_TIMING_2_HSYNC_INVERT;
 466
 467        if (panel->invert_pxl_clk)
 468                reg |= LCDC_RASTER_TIMING_2_PXCLK_INVERT;
 469
 470        if (panel->sync_edge)
 471                reg |= LCDC_RASTER_TIMING_2_HSVS_RISEFALL;
 472
 473        if (panel->sync_ctrl)
 474                reg |= LCDC_RASTER_TIMING_2_HSVS_CONTROL;
 475
 476        writel(reg, &regs->raster_timing2);
 477
 478        reg = LCDC_RASTER_CTRL_PALMODE_RAWDATA | LCDC_RASTER_CTRL_TFT_MODE |
 479                LCDC_RASTER_CTRL_ENABLE | LCDC_RASTER_CTRL_REQDLY(panel->fdd);
 480
 481        if (panel->tft_alt_mode)
 482                reg |= LCDC_RASTER_CTRL_TFT_ALT_ENABLE;
 483
 484        if (panel->bpp == 24)
 485                reg |= LCDC_RASTER_CTRL_TFT_24BPP_MODE;
 486        else if (panel->bpp == 32)
 487                reg |= LCDC_RASTER_CTRL_TFT_24BPP_MODE |
 488                        LCDC_RASTER_CTRL_TFT_24BPP_UNPACK;
 489
 490        if (panel->raster_order)
 491                reg |= LCDC_RASTER_CTRL_DATA_ORDER;
 492
 493        writel(reg, &regs->raster_ctrl);
 494
 495        uc_priv->xsize = timing->hactive.typ;
 496        uc_priv->ysize = timing->vactive.typ;
 497        uc_priv->bpix = log_2_n_round_up(panel->bpp);
 498        return 0;
 499}
 500
 501static int am335x_fb_ofdata_to_platdata(struct udevice *dev)
 502{
 503        struct am335x_fb_priv *priv = dev_get_priv(dev);
 504        struct tilcdc_panel_info *panel = &priv->panel;
 505        struct display_timing *timing = &priv->timing;
 506        ofnode node;
 507        int err;
 508
 509        node = ofnode_by_compatible(ofnode_null(), "ti,am33xx-tilcdc");
 510        if (!ofnode_valid(node)) {
 511                dev_err(dev, "missing 'ti,am33xx-tilcdc' node\n");
 512                return -ENXIO;
 513        }
 514
 515        priv->regs = (struct am335x_lcdhw *)ofnode_get_addr(node);
 516        dev_dbg(dev, "LCD: base address=0x%x\n", (unsigned int)priv->regs);
 517
 518        err = ofnode_decode_display_timing(dev_ofnode(dev), 0, timing);
 519        if (err) {
 520                dev_err(dev, "failed to get display timing\n");
 521                return err;
 522        }
 523
 524        if (timing->pixelclock.typ > (LCDC_FMAX / 2)) {
 525                dev_err(dev, "invalid display clock-frequency: %d Hz\n",
 526                        timing->pixelclock.typ);
 527                return -EINVAL;
 528        }
 529
 530        if (timing->hactive.typ > LCD_MAX_WIDTH)
 531                timing->hactive.typ = LCD_MAX_WIDTH;
 532
 533        if (timing->vactive.typ > LCD_MAX_HEIGHT)
 534                timing->vactive.typ = LCD_MAX_HEIGHT;
 535
 536        node = ofnode_find_subnode(dev_ofnode(dev), "panel-info");
 537        if (!ofnode_valid(node)) {
 538                dev_err(dev, "missing 'panel-info' node\n");
 539                return -ENXIO;
 540        }
 541
 542        err |= ofnode_read_u32(node, "ac-bias", &panel->ac_bias);
 543        err |= ofnode_read_u32(node, "ac-bias-intrpt", &panel->ac_bias_intrpt);
 544        err |= ofnode_read_u32(node, "dma-burst-sz", &panel->dma_burst_sz);
 545        err |= ofnode_read_u32(node, "bpp", &panel->bpp);
 546        err |= ofnode_read_u32(node, "fdd", &panel->fdd);
 547        err |= ofnode_read_u32(node, "sync-edge", &panel->sync_edge);
 548        err |= ofnode_read_u32(node, "sync-ctrl", &panel->sync_ctrl);
 549        err |= ofnode_read_u32(node, "raster-order", &panel->raster_order);
 550        err |= ofnode_read_u32(node, "fifo-th", &panel->fifo_th);
 551        if (err) {
 552                dev_err(dev, "failed to get panel info\n");
 553                return err;
 554        }
 555
 556        switch (panel->bpp) {
 557        case 16:
 558        case 24:
 559        case 32:
 560                break;
 561        default:
 562                dev_err(dev, "invalid seting, bpp: %d\n", panel->bpp);
 563                return -EINVAL;
 564        }
 565
 566        switch (panel->dma_burst_sz) {
 567        case 1:
 568        case 2:
 569        case 4:
 570        case 8:
 571        case 16:
 572                break;
 573        default:
 574                dev_err(dev, "invalid setting, dma-burst-sz: %d\n",
 575                        panel->dma_burst_sz);
 576                return -EINVAL;
 577        }
 578
 579        /* optional */
 580        panel->tft_alt_mode = ofnode_read_bool(node, "tft-alt-mode");
 581        panel->invert_pxl_clk = ofnode_read_bool(node, "invert-pxl-clk");
 582
 583        dev_dbg(dev, "LCD: %dx%d, bpp=%d, clk=%d Hz\n", timing->hactive.typ,
 584                timing->vactive.typ, panel->bpp, timing->pixelclock.typ);
 585        dev_dbg(dev, "     hbp=%d, hfp=%d, hsw=%d\n", timing->hback_porch.typ,
 586                timing->hfront_porch.typ, timing->hsync_len.typ);
 587        dev_dbg(dev, "     vbp=%d, vfp=%d, vsw=%d\n", timing->vback_porch.typ,
 588                timing->vfront_porch.typ, timing->vsync_len.typ);
 589
 590        return 0;
 591}
 592
 593static int am335x_fb_bind(struct udevice *dev)
 594{
 595        struct video_uc_platdata *uc_plat = dev_get_uclass_platdata(dev);
 596
 597        uc_plat->size = ((LCD_MAX_WIDTH * LCD_MAX_HEIGHT *
 598                          (1 << LCD_MAX_LOG2_BPP)) >> 3) + 0x20;
 599
 600        dev_dbg(dev, "frame buffer size 0x%x\n", uc_plat->size);
 601        return 0;
 602}
 603
 604static const struct udevice_id am335x_fb_ids[] = {
 605        { .compatible = "ti,tilcdc,panel" },
 606        { }
 607};
 608
 609U_BOOT_DRIVER(am335x_fb) = {
 610        .name = "am335x_fb",
 611        .id = UCLASS_VIDEO,
 612        .of_match = am335x_fb_ids,
 613        .bind = am335x_fb_bind,
 614        .ofdata_to_platdata = am335x_fb_ofdata_to_platdata,
 615        .probe = am335x_fb_probe,
 616        .remove = am335x_fb_remove,
 617        .priv_auto_alloc_size = sizeof(struct am335x_fb_priv),
 618};
 619
 620#endif /* CONFIG_DM_VIDEO */
 621