2 * Copyright (C) 2012 Samsung Electronics
4 * Author: InKi Dae <inki.dae@samsung.com>
5 * Author: Donghwa Lee <dh09.lee@samsung.com>
7 * SPDX-License-Identifier: GPL-2.0+
19 #include <video_bridge.h>
21 #include <asm/arch/cpu.h>
22 #include <asm/arch/clock.h>
23 #include <asm/arch/clk.h>
24 #include <asm/arch/mipi_dsim.h>
25 #include <asm/arch/dp_info.h>
26 #include <asm/arch/fb.h>
27 #include <asm/arch/pinmux.h>
28 #include <asm/arch/system.h>
30 #include <linux/errno.h>
32 DECLARE_GLOBAL_DATA_PTR
;
35 FIMD_RGB_INTERFACE
= 1,
36 FIMD_CPU_INTERFACE
= 2,
39 enum exynos_fb_rgb_mode_t
{
46 struct exynos_fb_priv
{
47 ushort vl_col
; /* Number of columns (i.e. 640) */
48 ushort vl_row
; /* Number of rows (i.e. 480) */
49 ushort vl_rot
; /* Rotation of Display (0, 1, 2, 3) */
50 ushort vl_width
; /* Width of display area in millimeters */
51 ushort vl_height
; /* Height of display area in millimeters */
53 /* LCD configuration register */
54 u_char vl_freq
; /* Frequency */
55 u_char vl_clkp
; /* Clock polarity */
56 u_char vl_oep
; /* Output Enable polarity */
57 u_char vl_hsp
; /* Horizontal Sync polarity */
58 u_char vl_vsp
; /* Vertical Sync polarity */
59 u_char vl_dp
; /* Data polarity */
60 u_char vl_bpix
; /* Bits per pixel */
62 /* Horizontal control register. Timing from data sheet */
63 u_char vl_hspw
; /* Horz sync pulse width */
64 u_char vl_hfpd
; /* Wait before of line */
65 u_char vl_hbpd
; /* Wait end of line */
67 /* Vertical control register. */
68 u_char vl_vspw
; /* Vertical sync pulse width */
69 u_char vl_vfpd
; /* Wait before of frame */
70 u_char vl_vbpd
; /* Wait end of frame */
71 u_char vl_cmd_allow_len
; /* Wait end of frame */
74 unsigned int init_delay
;
75 unsigned int power_on_delay
;
76 unsigned int reset_delay
;
77 unsigned int interface_mode
;
78 unsigned int mipi_enabled
;
79 unsigned int dp_enabled
;
80 unsigned int cs_setup
;
81 unsigned int wr_setup
;
85 unsigned int logo_width
;
86 unsigned int logo_height
;
89 unsigned long logo_addr
;
90 unsigned int rgb_mode
;
91 unsigned int resolution
;
93 /* parent clock name(MPLL, EPLL or VPLL) */
94 unsigned int pclk_name
;
95 /* ratio value for source clock from parent clock. */
96 unsigned int sclk_div
;
98 unsigned int dual_lcd_enabled
;
99 struct exynos_fb
*reg
;
100 struct exynos_platform_mipi_dsim
*dsim_platform_data_dt
;
103 static void exynos_fimd_set_dualrgb(struct exynos_fb_priv
*priv
, bool enabled
)
105 struct exynos_fb
*reg
= priv
->reg
;
106 unsigned int cfg
= 0;
109 cfg
= EXYNOS_DUALRGB_BYPASS_DUAL
| EXYNOS_DUALRGB_LINESPLIT
|
110 EXYNOS_DUALRGB_VDEN_EN_ENABLE
;
112 /* in case of Line Split mode, MAIN_CNT doesn't neet to set. */
113 cfg
|= EXYNOS_DUALRGB_SUB_CNT(priv
->vl_col
/ 2) |
114 EXYNOS_DUALRGB_MAIN_CNT(0);
117 writel(cfg
, ®
->dualrgb
);
120 static void exynos_fimd_set_dp_clkcon(struct exynos_fb_priv
*priv
,
121 unsigned int enabled
)
123 struct exynos_fb
*reg
= priv
->reg
;
124 unsigned int cfg
= 0;
127 cfg
= EXYNOS_DP_CLK_ENABLE
;
129 writel(cfg
, ®
->dp_mie_clkcon
);
132 static void exynos_fimd_set_par(struct exynos_fb_priv
*priv
,
135 struct exynos_fb
*reg
= priv
->reg
;
136 unsigned int cfg
= 0;
138 /* set window control */
139 cfg
= readl((unsigned int)®
->wincon0
+
140 EXYNOS_WINCON(win_id
));
142 cfg
&= ~(EXYNOS_WINCON_BITSWP_ENABLE
| EXYNOS_WINCON_BYTESWP_ENABLE
|
143 EXYNOS_WINCON_HAWSWP_ENABLE
| EXYNOS_WINCON_WSWP_ENABLE
|
144 EXYNOS_WINCON_BURSTLEN_MASK
| EXYNOS_WINCON_BPPMODE_MASK
|
145 EXYNOS_WINCON_INRGB_MASK
| EXYNOS_WINCON_DATAPATH_MASK
);
147 /* DATAPATH is DMA */
148 cfg
|= EXYNOS_WINCON_DATAPATH_DMA
;
150 cfg
|= EXYNOS_WINCON_HAWSWP_ENABLE
;
152 /* dma burst is 16 */
153 cfg
|= EXYNOS_WINCON_BURSTLEN_16WORD
;
155 switch (priv
->vl_bpix
) {
157 cfg
|= EXYNOS_WINCON_BPPMODE_16BPP_565
;
160 cfg
|= EXYNOS_WINCON_BPPMODE_24BPP_888
;
164 writel(cfg
, (unsigned int)®
->wincon0
+
165 EXYNOS_WINCON(win_id
));
167 /* set window position to x=0, y=0*/
168 cfg
= EXYNOS_VIDOSD_LEFT_X(0) | EXYNOS_VIDOSD_TOP_Y(0);
169 writel(cfg
, (unsigned int)®
->vidosd0a
+
170 EXYNOS_VIDOSD(win_id
));
172 cfg
= EXYNOS_VIDOSD_RIGHT_X(priv
->vl_col
- 1) |
173 EXYNOS_VIDOSD_BOTTOM_Y(priv
->vl_row
- 1) |
174 EXYNOS_VIDOSD_RIGHT_X_E(1) |
175 EXYNOS_VIDOSD_BOTTOM_Y_E(0);
177 writel(cfg
, (unsigned int)®
->vidosd0b
+
178 EXYNOS_VIDOSD(win_id
));
180 /* set window size for window0*/
181 cfg
= EXYNOS_VIDOSD_SIZE(priv
->vl_col
* priv
->vl_row
);
182 writel(cfg
, (unsigned int)®
->vidosd0c
+
183 EXYNOS_VIDOSD(win_id
));
186 static void exynos_fimd_set_buffer_address(struct exynos_fb_priv
*priv
,
190 struct exynos_fb
*reg
= priv
->reg
;
191 unsigned long start_addr
, end_addr
;
193 start_addr
= lcd_base_addr
;
194 end_addr
= start_addr
+ ((priv
->vl_col
* (VNBITS(priv
->vl_bpix
) / 8)) *
197 writel(start_addr
, (unsigned int)®
->vidw00add0b0
+
198 EXYNOS_BUFFER_OFFSET(win_id
));
199 writel(end_addr
, (unsigned int)®
->vidw00add1b0
+
200 EXYNOS_BUFFER_OFFSET(win_id
));
203 static void exynos_fimd_set_clock(struct exynos_fb_priv
*priv
)
205 struct exynos_fb
*reg
= priv
->reg
;
206 unsigned int cfg
= 0, div
= 0, remainder
, remainder_div
;
207 unsigned long pixel_clock
;
208 unsigned long long src_clock
;
210 if (priv
->dual_lcd_enabled
) {
211 pixel_clock
= priv
->vl_freq
*
212 (priv
->vl_hspw
+ priv
->vl_hfpd
+
213 priv
->vl_hbpd
+ priv
->vl_col
/ 2) *
214 (priv
->vl_vspw
+ priv
->vl_vfpd
+
215 priv
->vl_vbpd
+ priv
->vl_row
);
216 } else if (priv
->interface_mode
== FIMD_CPU_INTERFACE
) {
217 pixel_clock
= priv
->vl_freq
*
218 priv
->vl_width
* priv
->vl_height
*
219 (priv
->cs_setup
+ priv
->wr_setup
+
220 priv
->wr_act
+ priv
->wr_hold
+ 1);
222 pixel_clock
= priv
->vl_freq
*
223 (priv
->vl_hspw
+ priv
->vl_hfpd
+
224 priv
->vl_hbpd
+ priv
->vl_col
) *
225 (priv
->vl_vspw
+ priv
->vl_vfpd
+
226 priv
->vl_vbpd
+ priv
->vl_row
);
229 cfg
= readl(®
->vidcon0
);
230 cfg
&= ~(EXYNOS_VIDCON0_CLKSEL_MASK
| EXYNOS_VIDCON0_CLKVALUP_MASK
|
231 EXYNOS_VIDCON0_CLKVAL_F(0xFF) | EXYNOS_VIDCON0_VCLKEN_MASK
|
232 EXYNOS_VIDCON0_CLKDIR_MASK
);
233 cfg
|= (EXYNOS_VIDCON0_CLKSEL_SCLK
| EXYNOS_VIDCON0_CLKVALUP_ALWAYS
|
234 EXYNOS_VIDCON0_VCLKEN_NORMAL
| EXYNOS_VIDCON0_CLKDIR_DIVIDED
);
236 src_clock
= (unsigned long long) get_lcd_clk();
238 /* get quotient and remainder. */
239 remainder
= do_div(src_clock
, pixel_clock
);
243 remainder_div
= remainder
/ pixel_clock
;
245 /* round about one places of decimals. */
246 if (remainder_div
>= 5)
249 /* in case of dual lcd mode. */
250 if (priv
->dual_lcd_enabled
)
253 cfg
|= EXYNOS_VIDCON0_CLKVAL_F(div
- 1);
254 writel(cfg
, ®
->vidcon0
);
257 void exynos_set_trigger(struct exynos_fb_priv
*priv
)
259 struct exynos_fb
*reg
= priv
->reg
;
260 unsigned int cfg
= 0;
262 cfg
= readl(®
->trigcon
);
264 cfg
|= (EXYNOS_I80SOFT_TRIG_EN
| EXYNOS_I80START_TRIG
);
266 writel(cfg
, ®
->trigcon
);
269 int exynos_is_i80_frame_done(struct exynos_fb_priv
*priv
)
271 struct exynos_fb
*reg
= priv
->reg
;
272 unsigned int cfg
= 0;
275 cfg
= readl(®
->trigcon
);
277 /* frame done func is valid only when TRIMODE[0] is set to 1. */
278 status
= (cfg
& EXYNOS_I80STATUS_TRIG_DONE
) ==
279 EXYNOS_I80STATUS_TRIG_DONE
;
284 static void exynos_fimd_lcd_on(struct exynos_fb_priv
*priv
)
286 struct exynos_fb
*reg
= priv
->reg
;
287 unsigned int cfg
= 0;
290 cfg
= readl(®
->vidcon0
);
291 cfg
|= (EXYNOS_VIDCON0_ENVID_ENABLE
| EXYNOS_VIDCON0_ENVID_F_ENABLE
);
292 writel(cfg
, ®
->vidcon0
);
295 static void exynos_fimd_window_on(struct exynos_fb_priv
*priv
,
298 struct exynos_fb
*reg
= priv
->reg
;
299 unsigned int cfg
= 0;
302 cfg
= readl((unsigned int)®
->wincon0
+
303 EXYNOS_WINCON(win_id
));
304 cfg
|= EXYNOS_WINCON_ENWIN_ENABLE
;
305 writel(cfg
, (unsigned int)®
->wincon0
+
306 EXYNOS_WINCON(win_id
));
308 cfg
= readl(®
->winshmap
);
309 cfg
|= EXYNOS_WINSHMAP_CH_ENABLE(win_id
);
310 writel(cfg
, ®
->winshmap
);
313 void exynos_fimd_lcd_off(struct exynos_fb_priv
*priv
)
315 struct exynos_fb
*reg
= priv
->reg
;
316 unsigned int cfg
= 0;
318 cfg
= readl(®
->vidcon0
);
319 cfg
&= (EXYNOS_VIDCON0_ENVID_DISABLE
| EXYNOS_VIDCON0_ENVID_F_DISABLE
);
320 writel(cfg
, ®
->vidcon0
);
323 void exynos_fimd_window_off(struct exynos_fb_priv
*priv
, unsigned int win_id
)
325 struct exynos_fb
*reg
= priv
->reg
;
326 unsigned int cfg
= 0;
328 cfg
= readl((unsigned int)®
->wincon0
+
329 EXYNOS_WINCON(win_id
));
330 cfg
&= EXYNOS_WINCON_ENWIN_DISABLE
;
331 writel(cfg
, (unsigned int)®
->wincon0
+
332 EXYNOS_WINCON(win_id
));
334 cfg
= readl(®
->winshmap
);
335 cfg
&= ~EXYNOS_WINSHMAP_CH_DISABLE(win_id
);
336 writel(cfg
, ®
->winshmap
);
340 * The reset value for FIMD SYSMMU register MMU_CTRL is 3
341 * on Exynos5420 and newer versions.
342 * This means FIMD SYSMMU is on by default on Exynos5420
343 * and newer versions.
344 * Since in u-boot we don't use SYSMMU, we should disable
346 * Note that there are 2 SYSMMU for FIMD: m0 and m1.
347 * m0 handles windows 0 and 4, and m1 handles windows 1, 2 and 3.
348 * We disable both of them here.
350 void exynos_fimd_disable_sysmmu(void)
358 count
= fdtdec_find_aliases_for_id(gd
->fdt_blob
, "fimd",
359 COMPAT_SAMSUNG_EXYNOS_SYSMMU
, node_list
, 2);
360 for (i
= 0; i
< count
; i
++) {
363 debug("Can't get device node for fimd sysmmu\n");
367 sysmmufimd
= (u32
*)fdtdec_get_addr(gd
->fdt_blob
, node
, "reg");
369 debug("Can't get base address for sysmmu fimdm0");
373 writel(0x0, sysmmufimd
);
377 void exynos_fimd_lcd_init(struct udevice
*dev
)
379 struct exynos_fb_priv
*priv
= dev_get_priv(dev
);
380 struct video_uc_platdata
*plat
= dev_get_uclass_platdata(dev
);
381 struct exynos_fb
*reg
= priv
->reg
;
382 unsigned int cfg
= 0, rgb_mode
;
386 node
= dev_of_offset(dev
);
387 if (fdtdec_get_bool(gd
->fdt_blob
, node
, "samsung,disable-sysmmu"))
388 exynos_fimd_disable_sysmmu();
390 offset
= exynos_fimd_get_base_offset();
392 rgb_mode
= priv
->rgb_mode
;
394 if (priv
->interface_mode
== FIMD_RGB_INTERFACE
) {
395 cfg
|= EXYNOS_VIDCON0_VIDOUT_RGB
;
396 writel(cfg
, ®
->vidcon0
);
398 cfg
= readl(®
->vidcon2
);
399 cfg
&= ~(EXYNOS_VIDCON2_WB_MASK
|
400 EXYNOS_VIDCON2_TVFORMATSEL_MASK
|
401 EXYNOS_VIDCON2_TVFORMATSEL_YUV_MASK
);
402 cfg
|= EXYNOS_VIDCON2_WB_DISABLE
;
403 writel(cfg
, ®
->vidcon2
);
408 cfg
|= EXYNOS_VIDCON1_IVCLK_RISING_EDGE
;
410 cfg
|= EXYNOS_VIDCON1_IHSYNC_INVERT
;
412 cfg
|= EXYNOS_VIDCON1_IVSYNC_INVERT
;
414 cfg
|= EXYNOS_VIDCON1_IVDEN_INVERT
;
416 writel(cfg
, (unsigned int)®
->vidcon1
+ offset
);
419 cfg
= EXYNOS_VIDTCON0_VFPD(priv
->vl_vfpd
- 1);
420 cfg
|= EXYNOS_VIDTCON0_VBPD(priv
->vl_vbpd
- 1);
421 cfg
|= EXYNOS_VIDTCON0_VSPW(priv
->vl_vspw
- 1);
422 writel(cfg
, (unsigned int)®
->vidtcon0
+ offset
);
424 cfg
= EXYNOS_VIDTCON1_HFPD(priv
->vl_hfpd
- 1);
425 cfg
|= EXYNOS_VIDTCON1_HBPD(priv
->vl_hbpd
- 1);
426 cfg
|= EXYNOS_VIDTCON1_HSPW(priv
->vl_hspw
- 1);
428 writel(cfg
, (unsigned int)®
->vidtcon1
+ offset
);
431 cfg
= EXYNOS_VIDTCON2_HOZVAL(priv
->vl_col
- 1) |
432 EXYNOS_VIDTCON2_LINEVAL(priv
->vl_row
- 1) |
433 EXYNOS_VIDTCON2_HOZVAL_E(priv
->vl_col
- 1) |
434 EXYNOS_VIDTCON2_LINEVAL_E(priv
->vl_row
- 1);
436 writel(cfg
, (unsigned int)®
->vidtcon2
+ offset
);
439 /* set display mode */
440 cfg
= readl(®
->vidcon0
);
441 cfg
&= ~EXYNOS_VIDCON0_PNRMODE_MASK
;
442 cfg
|= (rgb_mode
<< EXYNOS_VIDCON0_PNRMODE_SHIFT
);
443 writel(cfg
, ®
->vidcon0
);
446 exynos_fimd_set_par(priv
, priv
->win_id
);
448 /* set memory address */
449 exynos_fimd_set_buffer_address(priv
, priv
->win_id
, plat
->base
);
451 /* set buffer size */
452 cfg
= EXYNOS_VIDADDR_PAGEWIDTH(priv
->vl_col
*
453 VNBITS(priv
->vl_bpix
) / 8) |
454 EXYNOS_VIDADDR_PAGEWIDTH_E(priv
->vl_col
*
455 VNBITS(priv
->vl_bpix
) / 8) |
456 EXYNOS_VIDADDR_OFFSIZE(0) |
457 EXYNOS_VIDADDR_OFFSIZE_E(0);
459 writel(cfg
, (unsigned int)®
->vidw00add2
+
460 EXYNOS_BUFFER_SIZE(priv
->win_id
));
463 exynos_fimd_set_clock(priv
);
465 /* set rgb mode to dual lcd. */
466 exynos_fimd_set_dualrgb(priv
, priv
->dual_lcd_enabled
);
469 exynos_fimd_lcd_on(priv
);
472 exynos_fimd_window_on(priv
, priv
->win_id
);
474 exynos_fimd_set_dp_clkcon(priv
, priv
->dp_enabled
);
477 unsigned long exynos_fimd_calc_fbsize(struct exynos_fb_priv
*priv
)
479 return priv
->vl_col
* priv
->vl_row
* (VNBITS(priv
->vl_bpix
) / 8);
482 int exynos_fb_ofdata_to_platdata(struct udevice
*dev
)
484 struct exynos_fb_priv
*priv
= dev_get_priv(dev
);
485 unsigned int node
= dev_of_offset(dev
);
486 const void *blob
= gd
->fdt_blob
;
489 addr
= dev_get_addr(dev
);
490 if (addr
== FDT_ADDR_T_NONE
) {
491 debug("Can't get the FIMD base address\n");
494 priv
->reg
= (struct exynos_fb
*)addr
;
496 priv
->vl_col
= fdtdec_get_int(blob
, node
, "samsung,vl-col", 0);
497 if (priv
->vl_col
== 0) {
498 debug("Can't get XRES\n");
502 priv
->vl_row
= fdtdec_get_int(blob
, node
, "samsung,vl-row", 0);
503 if (priv
->vl_row
== 0) {
504 debug("Can't get YRES\n");
508 priv
->vl_width
= fdtdec_get_int(blob
, node
,
509 "samsung,vl-width", 0);
511 priv
->vl_height
= fdtdec_get_int(blob
, node
,
512 "samsung,vl-height", 0);
514 priv
->vl_freq
= fdtdec_get_int(blob
, node
, "samsung,vl-freq", 0);
515 if (priv
->vl_freq
== 0) {
516 debug("Can't get refresh rate\n");
520 if (fdtdec_get_bool(blob
, node
, "samsung,vl-clkp"))
521 priv
->vl_clkp
= VIDEO_ACTIVE_LOW
;
523 if (fdtdec_get_bool(blob
, node
, "samsung,vl-oep"))
524 priv
->vl_oep
= VIDEO_ACTIVE_LOW
;
526 if (fdtdec_get_bool(blob
, node
, "samsung,vl-hsp"))
527 priv
->vl_hsp
= VIDEO_ACTIVE_LOW
;
529 if (fdtdec_get_bool(blob
, node
, "samsung,vl-vsp"))
530 priv
->vl_vsp
= VIDEO_ACTIVE_LOW
;
532 if (fdtdec_get_bool(blob
, node
, "samsung,vl-dp"))
533 priv
->vl_dp
= VIDEO_ACTIVE_LOW
;
535 priv
->vl_bpix
= fdtdec_get_int(blob
, node
, "samsung,vl-bpix", 0);
536 if (priv
->vl_bpix
== 0) {
537 debug("Can't get bits per pixel\n");
541 priv
->vl_hspw
= fdtdec_get_int(blob
, node
, "samsung,vl-hspw", 0);
542 if (priv
->vl_hspw
== 0) {
543 debug("Can't get hsync width\n");
547 priv
->vl_hfpd
= fdtdec_get_int(blob
, node
, "samsung,vl-hfpd", 0);
548 if (priv
->vl_hfpd
== 0) {
549 debug("Can't get right margin\n");
553 priv
->vl_hbpd
= (u_char
)fdtdec_get_int(blob
, node
,
554 "samsung,vl-hbpd", 0);
555 if (priv
->vl_hbpd
== 0) {
556 debug("Can't get left margin\n");
560 priv
->vl_vspw
= (u_char
)fdtdec_get_int(blob
, node
,
561 "samsung,vl-vspw", 0);
562 if (priv
->vl_vspw
== 0) {
563 debug("Can't get vsync width\n");
567 priv
->vl_vfpd
= fdtdec_get_int(blob
, node
,
568 "samsung,vl-vfpd", 0);
569 if (priv
->vl_vfpd
== 0) {
570 debug("Can't get lower margin\n");
574 priv
->vl_vbpd
= fdtdec_get_int(blob
, node
, "samsung,vl-vbpd", 0);
575 if (priv
->vl_vbpd
== 0) {
576 debug("Can't get upper margin\n");
580 priv
->vl_cmd_allow_len
= fdtdec_get_int(blob
, node
,
581 "samsung,vl-cmd-allow-len", 0);
583 priv
->win_id
= fdtdec_get_int(blob
, node
, "samsung,winid", 0);
584 priv
->init_delay
= fdtdec_get_int(blob
, node
,
585 "samsung,init-delay", 0);
586 priv
->power_on_delay
= fdtdec_get_int(blob
, node
,
587 "samsung,power-on-delay", 0);
588 priv
->reset_delay
= fdtdec_get_int(blob
, node
,
589 "samsung,reset-delay", 0);
590 priv
->interface_mode
= fdtdec_get_int(blob
, node
,
591 "samsung,interface-mode", 0);
592 priv
->mipi_enabled
= fdtdec_get_int(blob
, node
,
593 "samsung,mipi-enabled", 0);
594 priv
->dp_enabled
= fdtdec_get_int(blob
, node
,
595 "samsung,dp-enabled", 0);
596 priv
->cs_setup
= fdtdec_get_int(blob
, node
,
597 "samsung,cs-setup", 0);
598 priv
->wr_setup
= fdtdec_get_int(blob
, node
,
599 "samsung,wr-setup", 0);
600 priv
->wr_act
= fdtdec_get_int(blob
, node
, "samsung,wr-act", 0);
601 priv
->wr_hold
= fdtdec_get_int(blob
, node
, "samsung,wr-hold", 0);
603 priv
->logo_on
= fdtdec_get_int(blob
, node
, "samsung,logo-on", 0);
605 priv
->logo_width
= fdtdec_get_int(blob
, node
,
606 "samsung,logo-width", 0);
607 priv
->logo_height
= fdtdec_get_int(blob
, node
,
608 "samsung,logo-height", 0);
609 priv
->logo_addr
= fdtdec_get_int(blob
, node
,
610 "samsung,logo-addr", 0);
613 priv
->rgb_mode
= fdtdec_get_int(blob
, node
,
614 "samsung,rgb-mode", 0);
615 priv
->pclk_name
= fdtdec_get_int(blob
, node
,
616 "samsung,pclk-name", 0);
617 priv
->sclk_div
= fdtdec_get_int(blob
, node
,
618 "samsung,sclk-div", 0);
619 priv
->dual_lcd_enabled
= fdtdec_get_int(blob
, node
,
620 "samsung,dual-lcd-enabled", 0);
625 static int exynos_fb_probe(struct udevice
*dev
)
627 struct video_priv
*uc_priv
= dev_get_uclass_priv(dev
);
628 struct exynos_fb_priv
*priv
= dev_get_priv(dev
);
629 struct udevice
*panel
, *bridge
;
633 debug("%s: start\n", __func__
);
634 set_system_display_ctrl();
637 #ifdef CONFIG_EXYNOS_MIPI_DSIM
638 exynos_init_dsim_platform_data(&panel_info
);
640 exynos_fimd_lcd_init(dev
);
642 ret
= uclass_first_device(UCLASS_PANEL
, &panel
);
644 printf("LCD panel failed to probe\n");
648 printf("LCD panel not found\n");
652 ret
= uclass_first_device(UCLASS_DISPLAY
, &dp
);
654 debug("%s: Display device error %d\n", __func__
, ret
);
658 debug("%s: Display device missing\n", __func__
);
661 ret
= display_enable(dp
, 18, NULL
);
663 debug("%s: Display enable error %d\n", __func__
, ret
);
667 /* backlight / pwm */
668 ret
= panel_enable_backlight(panel
);
670 debug("%s: backlight error: %d\n", __func__
, ret
);
674 ret
= uclass_get_device(UCLASS_VIDEO_BRIDGE
, 0, &bridge
);
676 ret
= video_bridge_set_backlight(bridge
, 80);
678 debug("%s: No video bridge, or no backlight on bridge\n",
680 exynos_pinmux_config(PERIPH_ID_PWM0
, 0);
683 uc_priv
->xsize
= priv
->vl_col
;
684 uc_priv
->ysize
= priv
->vl_row
;
685 uc_priv
->bpix
= priv
->vl_bpix
;
687 /* Enable flushing after LCD writes if requested */
688 video_set_flush_dcache(dev
, true);
693 static int exynos_fb_bind(struct udevice
*dev
)
695 struct video_uc_platdata
*plat
= dev_get_uclass_platdata(dev
);
697 /* This is the maximum panel size we expect to see */
698 plat
->size
= 1920 * 1080 * 2;
703 static const struct video_ops exynos_fb_ops
= {
706 static const struct udevice_id exynos_fb_ids
[] = {
707 { .compatible
= "samsung,exynos-fimd" },
711 U_BOOT_DRIVER(exynos_fb
) = {
714 .of_match
= exynos_fb_ids
,
715 .ops
= &exynos_fb_ops
,
716 .bind
= exynos_fb_bind
,
717 .probe
= exynos_fb_probe
,
718 .ofdata_to_platdata
= exynos_fb_ofdata_to_platdata
,
719 .priv_auto_alloc_size
= sizeof(struct exynos_fb_priv
),