1 // SPDX-License-Identifier: GPL-2.0+
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>
7 * minimal framebuffer driver for TI's AM335x SoC to be compatible with
8 * Wolfgang Denk's LCD-Framework (CONFIG_LCD, common/lcd.c)
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
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>
24 #include <asm/utils.h>
25 #include <linux/err.h>
26 #include "am335x-fb.h"
28 #define LCDC_FMAX 200000000
30 /* LCD Control Register */
31 #define LCDC_CTRL_CLK_DIVISOR_MASK GENMASK(15, 8)
32 #define LCDC_CTRL_RASTER_MODE BIT(0)
33 #define LCDC_CTRL_CLK_DIVISOR(x) (((x) & GENMASK(7, 0)) << 8)
34 /* LCD Clock Enable Register */
35 #define LCDC_CLKC_ENABLE_CORECLKEN BIT(0)
36 #define LCDC_CLKC_ENABLE_LIDDCLKEN BIT(1)
37 #define LCDC_CLKC_ENABLE_DMACLKEN BIT(2)
38 /* LCD DMA Control Register */
39 #define LCDC_DMA_CTRL_BURST_SIZE(x) (((x) & GENMASK(2, 0)) << 4)
40 #define LCDC_DMA_CTRL_BURST_1 0x0
41 #define LCDC_DMA_CTRL_BURST_2 0x1
42 #define LCDC_DMA_CTRL_BURST_4 0x2
43 #define LCDC_DMA_CTRL_BURST_8 0x3
44 #define LCDC_DMA_CTRL_BURST_16 0x4
45 #define LCDC_DMA_CTRL_FIFO_TH(x) (((x) & GENMASK(2, 0)) << 8)
46 /* LCD Timing_0 Register */
47 #define LCDC_RASTER_TIMING_0_HORMSB(x) ((((x) - 1) & BIT(10)) >> 7)
48 #define LCDC_RASTER_TIMING_0_HORLSB(x) (((((x) >> 4) - 1) & GENMASK(5, 0)) << 4)
49 #define LCDC_RASTER_TIMING_0_HSWLSB(x) ((((x) - 1) & GENMASK(5, 0)) << 10)
50 #define LCDC_RASTER_TIMING_0_HFPLSB(x) ((((x) - 1) & GENMASK(7, 0)) << 16)
51 #define LCDC_RASTER_TIMING_0_HBPLSB(x) ((((x) - 1) & GENMASK(7, 0)) << 24)
52 /* LCD Timing_1 Register */
53 #define LCDC_RASTER_TIMING_1_VERLSB(x) (((x) - 1) & GENMASK(9, 0))
54 #define LCDC_RASTER_TIMING_1_VSW(x) ((((x) - 1) & GENMASK(5, 0)) << 10)
55 #define LCDC_RASTER_TIMING_1_VFP(x) (((x) & GENMASK(7, 0)) << 16)
56 #define LCDC_RASTER_TIMING_1_VBP(x) (((x) & GENMASK(7, 0)) << 24)
57 /* LCD Timing_2 Register */
58 #define LCDC_RASTER_TIMING_2_HFPMSB(x) ((((x) - 1) & GENMASK(9, 8)) >> 8)
59 #define LCDC_RASTER_TIMING_2_HBPMSB(x) ((((x) - 1) & GENMASK(9, 8)) >> 4)
60 #define LCDC_RASTER_TIMING_2_ACB(x) (((x) & GENMASK(7, 0)) << 8)
61 #define LCDC_RASTER_TIMING_2_ACBI(x) (((x) & GENMASK(3, 0)) << 16)
62 #define LCDC_RASTER_TIMING_2_VSYNC_INVERT BIT(20)
63 #define LCDC_RASTER_TIMING_2_HSYNC_INVERT BIT(21)
64 #define LCDC_RASTER_TIMING_2_PXCLK_INVERT BIT(22)
65 #define LCDC_RASTER_TIMING_2_DE_INVERT BIT(23)
66 #define LCDC_RASTER_TIMING_2_HSVS_RISEFALL BIT(24)
67 #define LCDC_RASTER_TIMING_2_HSVS_CONTROL BIT(25)
68 #define LCDC_RASTER_TIMING_2_VERMSB(x) ((((x) - 1) & BIT(10)) << 16)
69 #define LCDC_RASTER_TIMING_2_HSWMSB(x) ((((x) - 1) & GENMASK(9, 6)) << 21)
70 /* LCD Raster Ctrl Register */
71 #define LCDC_RASTER_CTRL_ENABLE BIT(0)
72 #define LCDC_RASTER_CTRL_TFT_MODE BIT(7)
73 #define LCDC_RASTER_CTRL_DATA_ORDER BIT(8)
74 #define LCDC_RASTER_CTRL_REQDLY(x) (((x) & GENMASK(7, 0)) << 12)
75 #define LCDC_RASTER_CTRL_PALMODE_RAWDATA (0x02 << 20)
76 #define LCDC_RASTER_CTRL_TFT_ALT_ENABLE BIT(23)
77 #define LCDC_RASTER_CTRL_TFT_24BPP_MODE BIT(25)
78 #define LCDC_RASTER_CTRL_TFT_24BPP_UNPACK BIT(26)
81 unsigned int pid
; /* 0x00 */
82 unsigned int ctrl
; /* 0x04 */
83 unsigned int gap0
; /* 0x08 */
84 unsigned int lidd_ctrl
; /* 0x0C */
85 unsigned int lidd_cs0_conf
; /* 0x10 */
86 unsigned int lidd_cs0_addr
; /* 0x14 */
87 unsigned int lidd_cs0_data
; /* 0x18 */
88 unsigned int lidd_cs1_conf
; /* 0x1C */
89 unsigned int lidd_cs1_addr
; /* 0x20 */
90 unsigned int lidd_cs1_data
; /* 0x24 */
91 unsigned int raster_ctrl
; /* 0x28 */
92 unsigned int raster_timing0
; /* 0x2C */
93 unsigned int raster_timing1
; /* 0x30 */
94 unsigned int raster_timing2
; /* 0x34 */
95 unsigned int raster_subpanel
; /* 0x38 */
96 unsigned int raster_subpanel2
; /* 0x3C */
97 unsigned int lcddma_ctrl
; /* 0x40 */
98 unsigned int lcddma_fb0_base
; /* 0x44 */
99 unsigned int lcddma_fb0_ceiling
; /* 0x48 */
100 unsigned int lcddma_fb1_base
; /* 0x4C */
101 unsigned int lcddma_fb1_ceiling
; /* 0x50 */
102 unsigned int sysconfig
; /* 0x54 */
103 unsigned int irqstatus_raw
; /* 0x58 */
104 unsigned int irqstatus
; /* 0x5C */
105 unsigned int irqenable_set
; /* 0x60 */
106 unsigned int irqenable_clear
; /* 0x64 */
107 unsigned int gap1
; /* 0x68 */
108 unsigned int clkc_enable
; /* 0x6C */
109 unsigned int clkc_reset
; /* 0x70 */
113 unsigned long rounded_rate
;
119 DECLARE_GLOBAL_DATA_PTR
;
122 * am335x_dpll_round_rate() - Round a target rate for an OMAP DPLL
124 * @dpll_data: struct dpll_data pointer for the DPLL
125 * @rate: New DPLL clock rate
126 * @return rounded rate and the computed m, n and div values in the dpll_data
127 * structure, or -ve error code.
129 static ulong
am335x_dpll_round_rate(struct dpll_data
*dd
, ulong rate
)
131 unsigned int m
, n
, d
;
132 unsigned long rounded_rate
;
135 dd
->rounded_rate
= -EFAULT
;
139 for (d
= 2; err
&& d
< 255; d
++) {
140 for (m
= 2; m
< 2047; m
++) {
141 if ((V_OSCK
* m
) < (rate
* d
))
144 n
= (V_OSCK
* m
) / (rate
* d
);
148 if (((V_OSCK
* m
) / n
) > LCDC_FMAX
)
151 rounded_rate
= (V_OSCK
* m
) / n
/ d
;
152 err
= abs(rounded_rate
- rate
);
155 dd
->rounded_rate
= rounded_rate
;
165 debug("DPLL display: best error %d Hz (M %d, N %d, DIV %d)\n",
166 err_r
, dd
->rounded_m
, dd
->rounded_n
, dd
->rounded_div
);
168 return dd
->rounded_rate
;
172 * am335x_fb_set_pixel_clk_rate() - Set pixel clock rate.
174 * @am335x_lcdhw: Base address of the LCD controller registers.
175 * @rate: New clock rate in Hz.
176 * @return new rate, or -ve error code.
178 static ulong
am335x_fb_set_pixel_clk_rate(struct am335x_lcdhw
*regs
, ulong rate
)
180 struct dpll_params dpll_disp
= { 1, 0, 1, -1, -1, -1, -1 };
185 round_rate
= am335x_dpll_round_rate(&dd
, rate
);
186 if (IS_ERR_VALUE(round_rate
))
189 dpll_disp
.m
= dd
.rounded_m
;
190 dpll_disp
.n
= dd
.rounded_n
;
191 do_setup_dpll(&dpll_disp_regs
, &dpll_disp
);
193 reg
= readl(®s
->ctrl
) & ~LCDC_CTRL_CLK_DIVISOR_MASK
;
194 reg
|= LCDC_CTRL_CLK_DIVISOR(dd
.rounded_div
);
195 writel(reg
, ®s
->ctrl
);
199 #if !CONFIG_IS_ENABLED(DM_VIDEO)
201 #if !defined(LCD_CNTL_BASE)
202 #error "hw-base address of LCD-Controller (LCD_CNTL_BASE) not defined!"
205 /* Macro definitions */
206 #define FBSIZE(x) (((x)->hactive * (x)->vactive * (x)->bpp) >> 3)
208 #define LCDC_RASTER_TIMING_2_INVMASK(x) ((x) & GENMASK(25, 20))
210 static struct am335x_lcdhw
*lcdhw
= (void *)LCD_CNTL_BASE
;
212 int lcd_get_size(int *line_length
)
214 *line_length
= (panel_info
.vl_col
* NBITS(panel_info
.vl_bpix
)) / 8;
215 return *line_length
* panel_info
.vl_row
+ 0x20;
218 int am335xfb_init(struct am335x_lcdpanel
*panel
)
221 struct cm_dpll
*const cmdpll
= (struct cm_dpll
*)CM_DPLL
;
225 if (gd
->fb_base
== 0) {
226 printf("ERROR: no valid fb_base stored in GLOBAL_DATA_PTR!\n");
230 printf("ERROR: missing ptr to am335x_lcdpanel!\n");
234 /* We can already set the bits for the raster_ctrl in this check */
235 switch (panel
->bpp
) {
239 raster_ctrl
|= LCDC_RASTER_CTRL_TFT_24BPP_UNPACK
;
242 raster_ctrl
|= LCDC_RASTER_CTRL_TFT_24BPP_MODE
;
245 pr_err("am335x-fb: invalid bpp value: %d\n", panel
->bpp
);
249 /* check given clock-frequency */
250 if (panel
->pxl_clk
> (LCDC_FMAX
/ 2)) {
251 pr_err("am335x-fb: requested pxl-clk: %d not supported!\n",
256 debug("setting up LCD-Controller for %dx%dx%d (hfp=%d,hbp=%d,hsw=%d / ",
257 panel
->hactive
, panel
->vactive
, panel
->bpp
,
258 panel
->hfp
, panel
->hbp
, panel
->hsw
);
259 debug("vfp=%d,vbp=%d,vsw=%d / clk=%d)\n",
260 panel
->vfp
, panel
->vfp
, panel
->vsw
, panel
->pxl_clk
);
261 debug("using frambuffer at 0x%08x with size %d.\n",
262 (unsigned int)gd
->fb_base
, FBSIZE(panel
));
264 rate
= am335x_fb_set_pixel_clk_rate(lcdhw
, panel
->pxl_clk
);
265 if (IS_ERR_VALUE(rate
))
268 /* clock source for LCDC from dispPLL M2 */
269 writel(0x0, &cmdpll
->clklcdcpixelclk
);
271 /* palette default entry */
272 memset((void *)gd
->fb_base
, 0, 0x20);
273 *(unsigned int *)gd
->fb_base
= 0x4000;
274 /* point fb behind palette */
277 /* turn ON display through powercontrol function if accessible */
278 if (panel
->panel_power_ctrl
!= NULL
)
279 panel
->panel_power_ctrl(1);
281 debug("am335x-fb: wait for stable power ...\n");
282 mdelay(panel
->pup_delay
);
283 lcdhw
->clkc_enable
= LCDC_CLKC_ENABLE_CORECLKEN
|
284 LCDC_CLKC_ENABLE_LIDDCLKEN
| LCDC_CLKC_ENABLE_DMACLKEN
;
285 lcdhw
->raster_ctrl
= 0;
287 reg
= lcdhw
->ctrl
& LCDC_CTRL_CLK_DIVISOR_MASK
;
288 reg
|= LCDC_CTRL_RASTER_MODE
;
291 lcdhw
->lcddma_fb0_base
= gd
->fb_base
;
292 lcdhw
->lcddma_fb0_ceiling
= gd
->fb_base
+ FBSIZE(panel
);
293 lcdhw
->lcddma_fb1_base
= gd
->fb_base
;
294 lcdhw
->lcddma_fb1_ceiling
= gd
->fb_base
+ FBSIZE(panel
);
295 lcdhw
->lcddma_ctrl
= LCDC_DMA_CTRL_BURST_SIZE(LCDC_DMA_CTRL_BURST_16
);
297 lcdhw
->raster_timing0
= LCDC_RASTER_TIMING_0_HORLSB(panel
->hactive
) |
298 LCDC_RASTER_TIMING_0_HORMSB(panel
->hactive
) |
299 LCDC_RASTER_TIMING_0_HFPLSB(panel
->hfp
) |
300 LCDC_RASTER_TIMING_0_HBPLSB(panel
->hbp
) |
301 LCDC_RASTER_TIMING_0_HSWLSB(panel
->hsw
);
302 lcdhw
->raster_timing1
= LCDC_RASTER_TIMING_1_VBP(panel
->vbp
) |
303 LCDC_RASTER_TIMING_1_VFP(panel
->vfp
) |
304 LCDC_RASTER_TIMING_1_VSW(panel
->vsw
) |
305 LCDC_RASTER_TIMING_1_VERLSB(panel
->vactive
);
306 lcdhw
->raster_timing2
= LCDC_RASTER_TIMING_2_HSWMSB(panel
->hsw
) |
307 LCDC_RASTER_TIMING_2_VERMSB(panel
->vactive
) |
308 LCDC_RASTER_TIMING_2_INVMASK(panel
->pol
) |
309 LCDC_RASTER_TIMING_2_HBPMSB(panel
->hbp
) |
310 LCDC_RASTER_TIMING_2_HFPMSB(panel
->hfp
) |
311 0x0000FF00; /* clk cycles for ac-bias */
312 lcdhw
->raster_ctrl
= raster_ctrl
|
313 LCDC_RASTER_CTRL_PALMODE_RAWDATA
|
314 LCDC_RASTER_CTRL_TFT_MODE
|
315 LCDC_RASTER_CTRL_ENABLE
;
317 debug("am335x-fb: waiting picture to be stable.\n.");
318 mdelay(panel
->pon_delay
);
323 #else /* CONFIG_DM_VIDEO */
325 #define FBSIZE(t, p) (((t)->hactive.typ * (t)->vactive.typ * (p)->bpp) >> 3)
328 LCD_MAX_WIDTH
= 2048,
329 LCD_MAX_HEIGHT
= 2048,
330 LCD_MAX_LOG2_BPP
= VIDEO_BPP32
,
334 * tilcdc_panel_info: Panel parameters
336 * @ac_bias: AC Bias Pin Frequency
337 * @ac_bias_intrpt: AC Bias Pin Transitions per Interrupt
338 * @dma_burst_sz: DMA burst size
339 * @bpp: Bits per pixel
340 * @fdd: FIFO DMA Request Delay
341 * @tft_alt_mode: TFT Alternative Signal Mapping (Only for active)
342 * @invert_pxl_clk: Invert pixel clock
343 * @sync_edge: Horizontal and Vertical Sync Edge: 0=rising 1=falling
344 * @sync_ctrl: Horizontal and Vertical Sync: Control: 0=ignore
345 * @raster_order: Raster Data Order Select: 1=Most-to-least 0=Least-to-most
346 * @fifo_th: DMA FIFO threshold
348 struct tilcdc_panel_info
{
362 struct am335x_fb_priv
{
363 struct am335x_lcdhw
*regs
;
364 struct tilcdc_panel_info panel
;
365 struct display_timing timing
;
368 static int am335x_fb_remove(struct udevice
*dev
)
370 struct video_uc_platdata
*uc_plat
= dev_get_uclass_platdata(dev
);
372 uc_plat
->base
-= 0x20;
373 uc_plat
->size
+= 0x20;
377 static int am335x_fb_probe(struct udevice
*dev
)
379 struct video_uc_platdata
*uc_plat
= dev_get_uclass_platdata(dev
);
380 struct video_priv
*uc_priv
= dev_get_uclass_priv(dev
);
381 struct am335x_fb_priv
*priv
= dev_get_priv(dev
);
382 struct am335x_lcdhw
*regs
= priv
->regs
;
383 struct tilcdc_panel_info
*panel
= &priv
->panel
;
384 struct display_timing
*timing
= &priv
->timing
;
385 struct cm_dpll
*const cmdpll
= (struct cm_dpll
*)CM_DPLL
;
388 /* Before relocation we don't need to do anything */
389 if (!(gd
->flags
& GD_FLG_RELOC
))
392 am335x_fb_set_pixel_clk_rate(regs
, timing
->pixelclock
.typ
);
394 /* clock source for LCDC from dispPLL M2 */
395 writel(0, &cmdpll
->clklcdcpixelclk
);
397 /* palette default entry */
398 memset((void *)uc_plat
->base
, 0, 0x20);
399 *(unsigned int *)uc_plat
->base
= 0x4000;
400 /* point fb behind palette */
401 uc_plat
->base
+= 0x20;
402 uc_plat
->size
-= 0x20;
404 writel(LCDC_CLKC_ENABLE_CORECLKEN
| LCDC_CLKC_ENABLE_LIDDCLKEN
|
405 LCDC_CLKC_ENABLE_DMACLKEN
, ®s
->clkc_enable
);
406 writel(0, ®s
->raster_ctrl
);
408 reg
= readl(®s
->ctrl
) & LCDC_CTRL_CLK_DIVISOR_MASK
;
409 reg
|= LCDC_CTRL_RASTER_MODE
;
410 writel(reg
, ®s
->ctrl
);
412 writel(uc_plat
->base
, ®s
->lcddma_fb0_base
);
413 writel(uc_plat
->base
+ FBSIZE(timing
, panel
),
414 ®s
->lcddma_fb0_ceiling
);
415 writel(uc_plat
->base
, ®s
->lcddma_fb1_base
);
416 writel(uc_plat
->base
+ FBSIZE(timing
, panel
),
417 ®s
->lcddma_fb1_ceiling
);
419 reg
= LCDC_DMA_CTRL_FIFO_TH(panel
->fifo_th
);
420 switch (panel
->dma_burst_sz
) {
422 reg
|= LCDC_DMA_CTRL_BURST_SIZE(LCDC_DMA_CTRL_BURST_1
);
425 reg
|= LCDC_DMA_CTRL_BURST_SIZE(LCDC_DMA_CTRL_BURST_2
);
428 reg
|= LCDC_DMA_CTRL_BURST_SIZE(LCDC_DMA_CTRL_BURST_4
);
431 reg
|= LCDC_DMA_CTRL_BURST_SIZE(LCDC_DMA_CTRL_BURST_8
);
434 reg
|= LCDC_DMA_CTRL_BURST_SIZE(LCDC_DMA_CTRL_BURST_16
);
438 writel(reg
, ®s
->lcddma_ctrl
);
440 writel(LCDC_RASTER_TIMING_0_HORLSB(timing
->hactive
.typ
) |
441 LCDC_RASTER_TIMING_0_HORMSB(timing
->hactive
.typ
) |
442 LCDC_RASTER_TIMING_0_HFPLSB(timing
->hfront_porch
.typ
) |
443 LCDC_RASTER_TIMING_0_HBPLSB(timing
->hback_porch
.typ
) |
444 LCDC_RASTER_TIMING_0_HSWLSB(timing
->hsync_len
.typ
),
445 ®s
->raster_timing0
);
447 writel(LCDC_RASTER_TIMING_1_VBP(timing
->vback_porch
.typ
) |
448 LCDC_RASTER_TIMING_1_VFP(timing
->vfront_porch
.typ
) |
449 LCDC_RASTER_TIMING_1_VSW(timing
->vsync_len
.typ
) |
450 LCDC_RASTER_TIMING_1_VERLSB(timing
->vactive
.typ
),
451 ®s
->raster_timing1
);
453 reg
= LCDC_RASTER_TIMING_2_ACB(panel
->ac_bias
) |
454 LCDC_RASTER_TIMING_2_ACBI(panel
->ac_bias_intrpt
) |
455 LCDC_RASTER_TIMING_2_HSWMSB(timing
->hsync_len
.typ
) |
456 LCDC_RASTER_TIMING_2_VERMSB(timing
->vactive
.typ
) |
457 LCDC_RASTER_TIMING_2_HBPMSB(timing
->hback_porch
.typ
) |
458 LCDC_RASTER_TIMING_2_HFPMSB(timing
->hfront_porch
.typ
);
460 if (timing
->flags
& DISPLAY_FLAGS_VSYNC_LOW
)
461 reg
|= LCDC_RASTER_TIMING_2_VSYNC_INVERT
;
463 if (timing
->flags
& DISPLAY_FLAGS_HSYNC_LOW
)
464 reg
|= LCDC_RASTER_TIMING_2_HSYNC_INVERT
;
466 if (panel
->invert_pxl_clk
)
467 reg
|= LCDC_RASTER_TIMING_2_PXCLK_INVERT
;
469 if (panel
->sync_edge
)
470 reg
|= LCDC_RASTER_TIMING_2_HSVS_RISEFALL
;
472 if (panel
->sync_ctrl
)
473 reg
|= LCDC_RASTER_TIMING_2_HSVS_CONTROL
;
475 writel(reg
, ®s
->raster_timing2
);
477 reg
= LCDC_RASTER_CTRL_PALMODE_RAWDATA
| LCDC_RASTER_CTRL_TFT_MODE
|
478 LCDC_RASTER_CTRL_ENABLE
| LCDC_RASTER_CTRL_REQDLY(panel
->fdd
);
480 if (panel
->tft_alt_mode
)
481 reg
|= LCDC_RASTER_CTRL_TFT_ALT_ENABLE
;
483 if (panel
->bpp
== 24)
484 reg
|= LCDC_RASTER_CTRL_TFT_24BPP_MODE
;
485 else if (panel
->bpp
== 32)
486 reg
|= LCDC_RASTER_CTRL_TFT_24BPP_MODE
|
487 LCDC_RASTER_CTRL_TFT_24BPP_UNPACK
;
489 if (panel
->raster_order
)
490 reg
|= LCDC_RASTER_CTRL_DATA_ORDER
;
492 writel(reg
, ®s
->raster_ctrl
);
494 uc_priv
->xsize
= timing
->hactive
.typ
;
495 uc_priv
->ysize
= timing
->vactive
.typ
;
496 uc_priv
->bpix
= log_2_n_round_up(panel
->bpp
);
500 static int am335x_fb_ofdata_to_platdata(struct udevice
*dev
)
502 struct am335x_fb_priv
*priv
= dev_get_priv(dev
);
503 struct tilcdc_panel_info
*panel
= &priv
->panel
;
504 struct display_timing
*timing
= &priv
->timing
;
508 node
= ofnode_by_compatible(ofnode_null(), "ti,am33xx-tilcdc");
509 if (!ofnode_valid(node
)) {
510 dev_err(dev
, "missing 'ti,am33xx-tilcdc' node\n");
514 priv
->regs
= (struct am335x_lcdhw
*)ofnode_get_addr(node
);
515 dev_dbg(dev
, "LCD: base address=0x%x\n", (unsigned int)priv
->regs
);
517 err
= ofnode_decode_display_timing(dev_ofnode(dev
), 0, timing
);
519 dev_err(dev
, "failed to get display timing\n");
523 if (timing
->pixelclock
.typ
> (LCDC_FMAX
/ 2)) {
524 dev_err(dev
, "invalid display clock-frequency: %d Hz\n",
525 timing
->pixelclock
.typ
);
529 if (timing
->hactive
.typ
> LCD_MAX_WIDTH
)
530 timing
->hactive
.typ
= LCD_MAX_WIDTH
;
532 if (timing
->vactive
.typ
> LCD_MAX_HEIGHT
)
533 timing
->vactive
.typ
= LCD_MAX_HEIGHT
;
535 node
= ofnode_find_subnode(dev_ofnode(dev
), "panel-info");
536 if (!ofnode_valid(node
)) {
537 dev_err(dev
, "missing 'panel-info' node\n");
541 err
|= ofnode_read_u32(node
, "ac-bias", &panel
->ac_bias
);
542 err
|= ofnode_read_u32(node
, "ac-bias-intrpt", &panel
->ac_bias_intrpt
);
543 err
|= ofnode_read_u32(node
, "dma-burst-sz", &panel
->dma_burst_sz
);
544 err
|= ofnode_read_u32(node
, "bpp", &panel
->bpp
);
545 err
|= ofnode_read_u32(node
, "fdd", &panel
->fdd
);
546 err
|= ofnode_read_u32(node
, "sync-edge", &panel
->sync_edge
);
547 err
|= ofnode_read_u32(node
, "sync-ctrl", &panel
->sync_ctrl
);
548 err
|= ofnode_read_u32(node
, "raster-order", &panel
->raster_order
);
549 err
|= ofnode_read_u32(node
, "fifo-th", &panel
->fifo_th
);
551 dev_err(dev
, "failed to get panel info\n");
555 switch (panel
->bpp
) {
561 dev_err(dev
, "invalid seting, bpp: %d\n", panel
->bpp
);
565 switch (panel
->dma_burst_sz
) {
573 dev_err(dev
, "invalid setting, dma-burst-sz: %d\n",
574 panel
->dma_burst_sz
);
579 panel
->tft_alt_mode
= ofnode_read_bool(node
, "tft-alt-mode");
580 panel
->invert_pxl_clk
= ofnode_read_bool(node
, "invert-pxl-clk");
582 dev_dbg(dev
, "LCD: %dx%d, bpp=%d, clk=%d Hz\n", timing
->hactive
.typ
,
583 timing
->vactive
.typ
, panel
->bpp
, timing
->pixelclock
.typ
);
584 dev_dbg(dev
, " hbp=%d, hfp=%d, hsw=%d\n", timing
->hback_porch
.typ
,
585 timing
->hfront_porch
.typ
, timing
->hsync_len
.typ
);
586 dev_dbg(dev
, " vbp=%d, vfp=%d, vsw=%d\n", timing
->vback_porch
.typ
,
587 timing
->vfront_porch
.typ
, timing
->vsync_len
.typ
);
592 static int am335x_fb_bind(struct udevice
*dev
)
594 struct video_uc_platdata
*uc_plat
= dev_get_uclass_platdata(dev
);
596 uc_plat
->size
= ((LCD_MAX_WIDTH
* LCD_MAX_HEIGHT
*
597 (1 << LCD_MAX_LOG2_BPP
)) >> 3) + 0x20;
599 dev_dbg(dev
, "frame buffer size 0x%x\n", uc_plat
->size
);
603 static const struct udevice_id am335x_fb_ids
[] = {
604 { .compatible
= "ti,tilcdc,panel" },
608 U_BOOT_DRIVER(am335x_fb
) = {
611 .of_match
= am335x_fb_ids
,
612 .bind
= am335x_fb_bind
,
613 .ofdata_to_platdata
= am335x_fb_ofdata_to_platdata
,
614 .probe
= am335x_fb_probe
,
615 .remove
= am335x_fb_remove
,
616 .priv_auto_alloc_size
= sizeof(struct am335x_fb_priv
),
619 #endif /* CONFIG_DM_VIDEO */