1 /* SPDX-License-Identifier: GPL-2.0-or-later */
3 #include <device/mmio.h>
4 #include <console/console.h>
8 #include <soc/periph.h>
9 #include <soc/sysreg.h>
11 /* fairly useful debugging stuff. */
13 static inline void fwadl(unsigned long l
,void *v
) {
15 printk(BIOS_SPEW
, "W %p %p\n", v
, (void *)l
);
17 #define lwritel(a,b) fwadl((unsigned long)(a), (void *)(b))
19 static inline unsigned long fradl(void *v
) {
20 unsigned long l
= readl(v
);
21 printk(BIOS_SPEW
, "R %p %p\n", v
, (void *)l
);
25 #define lreadl(a) fradl((void *)(a))
28 #define lwritel(a,b) write32((void *)(b), (unsigned long)(a))
29 #define lreadl(a) read32((void *)(a))
32 /* not sure where we want this so ... */
33 static unsigned long get_lcd_clk(void)
45 sel
= lreadl(&exynos_clock
->clk_src_disp10
);
49 sclk
= get_pll_clk(SPLL
);
51 sclk
= get_pll_clk(RPLL
);
58 ratio
= lreadl(&exynos_clock
->clk_div_disp10
);
61 pclk
= sclk
/ (ratio
+ 1);
66 static void exynos_fimd_set_dualrgb(vidinfo_t
*vid
, unsigned int enabled
)
69 printk(BIOS_SPEW
, "%s %s\n", __func__
, enabled
? "enabled" : "not enabled");
71 cfg
= EXYNOS_DUALRGB_BYPASS_DUAL
| EXYNOS_DUALRGB_LINESPLIT
|
72 EXYNOS_DUALRGB_VDEN_EN_ENABLE
;
74 /* in case of Line Split mode, MAIN_CNT doesn't need to be set. */
75 cfg
|= EXYNOS_DUALRGB_SUB_CNT(vid
->vl_col
/ 2) |
76 EXYNOS_DUALRGB_MAIN_CNT(0);
79 lwritel(cfg
, &FIMD_CTRL
->dualrgb
);
82 static void exynos_fimd_set_dp_clkcon(unsigned int enabled
)
87 cfg
= EXYNOS_DP_CLK_ENABLE
;
90 lwritel(cfg
, &FIMD_CTRL
->dp_mie_clkcon
);
93 static void exynos_fimd_set_par(vidinfo_t
*vid
, unsigned int win_id
)
96 printk(BIOS_SPEW
, "%s %d\n", __func__
, win_id
);
97 /* set window control */
98 cfg
= lreadl(&FIMD_CTRL
->wincon0
+
99 EXYNOS_WINCON(win_id
));
101 cfg
&= ~(EXYNOS_WINCON_BITSWP_ENABLE
| EXYNOS_WINCON_BYTESWP_ENABLE
|
102 EXYNOS_WINCON_HAWSWP_ENABLE
| EXYNOS_WINCON_WSWP_ENABLE
|
103 EXYNOS_WINCON_BURSTLEN_MASK
| EXYNOS_WINCON_BPPMODE_MASK
|
104 EXYNOS_WINCON_INRGB_MASK
| EXYNOS_WINCON_DATAPATH_MASK
);
106 /* DATAPATH is DMA */
107 cfg
|= EXYNOS_WINCON_DATAPATH_DMA
;
109 cfg
|= EXYNOS_WINCON_HAWSWP_ENABLE
;
111 /* dma burst is 16 */
112 cfg
|= EXYNOS_WINCON_BURSTLEN_16WORD
;
114 cfg
|= EXYNOS_WINCON_BPPMODE_16BPP_565
;
116 lwritel(cfg
, &FIMD_CTRL
->wincon0
+
117 EXYNOS_WINCON(win_id
));
119 /* set window position to x=0, y=0*/
120 cfg
= EXYNOS_VIDOSD_LEFT_X(0) | EXYNOS_VIDOSD_TOP_Y(0);
121 lwritel(cfg
, &FIMD_CTRL
->vidosd0a
+
122 EXYNOS_VIDOSD(win_id
));
124 cfg
= EXYNOS_VIDOSD_RIGHT_X(vid
->vl_col
- 1) |
125 EXYNOS_VIDOSD_BOTTOM_Y(vid
->vl_row
- 1) |
126 EXYNOS_VIDOSD_RIGHT_X_E(1) |
127 EXYNOS_VIDOSD_BOTTOM_Y_E(0);
129 lwritel(cfg
, &FIMD_CTRL
->vidosd0b
+
130 EXYNOS_VIDOSD(win_id
));
131 /* set window size for window0*/
132 cfg
= EXYNOS_VIDOSD_SIZE(vid
->vl_col
* vid
->vl_row
);
133 lwritel(cfg
, &FIMD_CTRL
->vidosd0c
+
134 EXYNOS_VIDOSD(win_id
));
137 static void exynos_fimd_set_buffer_address(vidinfo_t
*vid
,
138 void *screen_base
, int win_id
)
140 u32 start_addr
, end_addr
;
141 printk(BIOS_SPEW
, "%s %d\n", __func__
, win_id
);
142 start_addr
= (u32
)screen_base
;
143 end_addr
= start_addr
+ ((vid
->vl_col
* ((1<<vid
->vl_bpix
) / 8)) *
146 lwritel(start_addr
, &FIMD_CTRL
->vidw00add0b0
+
147 EXYNOS_BUFFER_OFFSET(win_id
));
148 lwritel(end_addr
, &FIMD_CTRL
->vidw00add1b0
+
149 EXYNOS_BUFFER_OFFSET(win_id
));
152 static void exynos_fimd_set_clock(vidinfo_t
*vid
)
154 unsigned int cfg
= 0, div
= 0, remainder
= 0, remainder_div
;
155 unsigned long pixel_clock
;
156 unsigned long long src_clock
;
157 printk(BIOS_SPEW
, "%s\n", __func__
);
158 if (vid
->dual_lcd_enabled
) {
159 pixel_clock
= vid
->vl_freq
*
160 (vid
->vl_hspw
+ vid
->vl_hfpd
+
161 vid
->vl_hbpd
+ vid
->vl_col
/ 2) *
162 (vid
->vl_vspw
+ vid
->vl_vfpd
+
163 vid
->vl_vbpd
+ vid
->vl_row
);
164 } else if (vid
->interface_mode
== FIMD_CPU_INTERFACE
) {
165 pixel_clock
= vid
->vl_freq
*
166 vid
->vl_width
* vid
->vl_height
*
167 (vid
->cs_setup
+ vid
->wr_setup
+
168 vid
->wr_act
+ vid
->wr_hold
+ 1);
170 pixel_clock
= vid
->vl_freq
*
171 (vid
->vl_hspw
+ vid
->vl_hfpd
+
172 vid
->vl_hbpd
+ vid
->vl_col
) *
173 (vid
->vl_vspw
+ vid
->vl_vfpd
+
174 vid
->vl_vbpd
+ vid
->vl_row
);
176 printk(BIOS_SPEW
, "Pixel clock is %lx\n", pixel_clock
);
178 cfg
= lreadl(&FIMD_CTRL
->vidcon0
);
179 cfg
&= ~(EXYNOS_VIDCON0_CLKSEL_MASK
| EXYNOS_VIDCON0_CLKVALUP_MASK
|
180 EXYNOS_VIDCON0_CLKVAL_F(0xFF) | EXYNOS_VIDCON0_VCLKEN_MASK
|
181 EXYNOS_VIDCON0_CLKDIR_MASK
);
182 cfg
|= (EXYNOS_VIDCON0_CLKSEL_SCLK
| EXYNOS_VIDCON0_CLKVALUP_ALWAYS
|
183 EXYNOS_VIDCON0_VCLKEN_NORMAL
| EXYNOS_VIDCON0_CLKDIR_DIVIDED
);
185 src_clock
= (unsigned long long)get_lcd_clk();
187 /* get quotient and remainder. */
188 remainder
= src_clock
% pixel_clock
;
189 src_clock
/= pixel_clock
;
194 remainder_div
= remainder
/ pixel_clock
;
196 /* round about one places of decimals. */
197 if (remainder_div
>= 5)
200 /* in case of dual lcd mode. */
201 if (vid
->dual_lcd_enabled
)
204 cfg
|= EXYNOS_VIDCON0_CLKVAL_F(div
- 1);
205 lwritel(cfg
, &FIMD_CTRL
->vidcon0
);
208 void exynos_set_trigger(void)
210 unsigned int cfg
= 0;
211 printk(BIOS_SPEW
, "%s\n", __func__
);
212 cfg
= lreadl(&FIMD_CTRL
->trigcon
);
214 cfg
|= (EXYNOS_I80SOFT_TRIG_EN
| EXYNOS_I80START_TRIG
);
216 lwritel(cfg
, &FIMD_CTRL
->trigcon
);
219 int exynos_is_i80_frame_done(void)
221 unsigned int cfg
= 0;
223 printk(BIOS_SPEW
, "%s\n", __func__
);
224 cfg
= lreadl(&FIMD_CTRL
->trigcon
);
226 /* frame done func is valid only when TRIMODE[0] is set to 1. */
227 status
= (cfg
& EXYNOS_I80STATUS_TRIG_DONE
) ==
228 EXYNOS_I80STATUS_TRIG_DONE
;
233 static void exynos_fimd_lcd_on(void)
235 unsigned int cfg
= 0;
237 printk(BIOS_SPEW
, "%s\n", __func__
);
239 cfg
= lreadl(&FIMD_CTRL
->vidcon0
);
240 cfg
|= (EXYNOS_VIDCON0_ENVID_ENABLE
| EXYNOS_VIDCON0_ENVID_F_ENABLE
);
241 lwritel(cfg
, &FIMD_CTRL
->vidcon0
);
244 static void exynos_fimd_window_on(unsigned int win_id
)
246 unsigned int cfg
= 0;
247 printk(BIOS_SPEW
, "%s %d\n", __func__
, win_id
);
249 cfg
= lreadl(&FIMD_CTRL
->wincon0
+
250 EXYNOS_WINCON(win_id
));
251 cfg
|= EXYNOS_WINCON_ENWIN_ENABLE
;
252 lwritel(cfg
, &FIMD_CTRL
->wincon0
+
253 EXYNOS_WINCON(win_id
));
255 cfg
= lreadl(&FIMD_CTRL
->winshmap
);
256 cfg
|= EXYNOS_WINSHMAP_CH_ENABLE(win_id
);
257 lwritel(cfg
, &FIMD_CTRL
->winshmap
);
258 cfg
= lreadl(&FIMD_CTRL
->winshmap
);
261 void exynos_fimd_lcd_off(void)
263 unsigned int cfg
= 0;
264 printk(BIOS_SPEW
, "%s\n", __func__
);
266 cfg
= lreadl(&FIMD_CTRL
->vidcon0
);
267 cfg
&= (EXYNOS_VIDCON0_ENVID_DISABLE
| EXYNOS_VIDCON0_ENVID_F_DISABLE
);
268 lwritel(cfg
, &FIMD_CTRL
->vidcon0
);
271 void exynos_fimd_window_off(unsigned int win_id
)
273 unsigned int cfg
= 0;
274 printk(BIOS_SPEW
, "%s %d\n", __func__
, win_id
);
276 cfg
= lreadl(&FIMD_CTRL
->wincon0
+
277 EXYNOS_WINCON(win_id
));
278 cfg
&= EXYNOS_WINCON_ENWIN_DISABLE
;
279 lwritel(cfg
, &FIMD_CTRL
->wincon0
+
280 EXYNOS_WINCON(win_id
));
282 cfg
= lreadl(&FIMD_CTRL
->winshmap
);
283 cfg
&= ~EXYNOS_WINSHMAP_CH_DISABLE(win_id
);
284 lwritel(cfg
, &FIMD_CTRL
->winshmap
);
287 static void exynos5_set_system_display(void)
289 unsigned int cfg
= 0;
292 * system register path set
296 cfg
= lreadl(&exynos_sysreg
->disp1blk_cfg
);
298 lwritel(cfg
, &exynos_sysreg
->disp1blk_cfg
);
301 void exynos_fimd_lcd_init(vidinfo_t
*vid
)
303 unsigned int cfg
= 0, rgb_mode
;
304 struct exynos_fb
*fimd
;
306 fimd
= (void *)(FIMD_CTRL_ADDR
+ EXYNOS5_LCD_IF_BASE_OFFSET
);
308 printk(BIOS_SPEW
, "%s\n", __func__
);
309 exynos5_set_system_display();
311 rgb_mode
= vid
->rgb_mode
;
313 if (vid
->interface_mode
== FIMD_RGB_INTERFACE
) {
314 printk(BIOS_SPEW
, "%s FIMD_RGB_INTERFACE\n", __func__
);
316 cfg
|= EXYNOS_VIDCON0_VIDOUT_RGB
;
317 lwritel(cfg
, &FIMD_CTRL
->vidcon0
);
319 cfg
= lreadl(&FIMD_CTRL
->vidcon2
);
320 cfg
&= ~(EXYNOS_VIDCON2_WB_MASK
|
321 EXYNOS_VIDCON2_TVFORMATSEL_MASK
|
322 EXYNOS_VIDCON2_TVFORMATSEL_YUV_MASK
);
323 cfg
|= EXYNOS_VIDCON2_WB_DISABLE
;
324 lwritel(cfg
, &FIMD_CTRL
->vidcon2
);
329 cfg
|= EXYNOS_VIDCON1_IVCLK_RISING_EDGE
;
331 cfg
|= EXYNOS_VIDCON1_IHSYNC_INVERT
;
333 cfg
|= EXYNOS_VIDCON1_IVSYNC_INVERT
;
335 cfg
|= EXYNOS_VIDCON1_IVDEN_INVERT
;
337 lwritel(cfg
, &fimd
->vidcon1
);
340 cfg
= EXYNOS_VIDTCON0_VFPD(vid
->vl_vfpd
- 1);
341 cfg
|= EXYNOS_VIDTCON0_VBPD(vid
->vl_vbpd
- 1);
342 cfg
|= EXYNOS_VIDTCON0_VSPW(vid
->vl_vspw
- 1);
343 lwritel(cfg
, &fimd
->vidtcon0
);
345 cfg
= EXYNOS_VIDTCON1_HFPD(vid
->vl_hfpd
- 1);
346 cfg
|= EXYNOS_VIDTCON1_HBPD(vid
->vl_hbpd
- 1);
347 cfg
|= EXYNOS_VIDTCON1_HSPW(vid
->vl_hspw
- 1);
349 lwritel(cfg
, &fimd
->vidtcon1
);
352 cfg
= EXYNOS_VIDTCON2_HOZVAL(vid
->vl_col
- 1) |
353 EXYNOS_VIDTCON2_LINEVAL(vid
->vl_row
- 1) |
354 EXYNOS_VIDTCON2_HOZVAL_E(vid
->vl_col
- 1) |
355 EXYNOS_VIDTCON2_LINEVAL_E(vid
->vl_row
- 1);
357 lwritel(cfg
, &fimd
->vidtcon2
);
360 /* set display mode */
361 cfg
= lreadl(&FIMD_CTRL
->vidcon0
);
362 cfg
&= ~EXYNOS_VIDCON0_PNRMODE_MASK
;
363 cfg
|= (rgb_mode
<< EXYNOS_VIDCON0_PNRMODE_SHIFT
);
364 lwritel(cfg
, &FIMD_CTRL
->vidcon0
);
367 exynos_fimd_set_par(vid
, vid
->win_id
);
369 /* set memory address */
370 exynos_fimd_set_buffer_address(vid
, vid
->screen_base
, vid
->win_id
);
372 /* set buffer size */
373 cfg
= EXYNOS_VIDADDR_PAGEWIDTH(vid
->vl_col
* (1<<vid
->vl_bpix
) / 8) |
374 EXYNOS_VIDADDR_PAGEWIDTH_E(vid
->vl_col
* (1<<vid
->vl_bpix
) / 8) |
375 EXYNOS_VIDADDR_OFFSIZE(0) |
376 EXYNOS_VIDADDR_OFFSIZE_E(0);
378 lwritel(cfg
, &FIMD_CTRL
->vidw00add2
+
379 EXYNOS_BUFFER_SIZE(vid
->win_id
));
382 exynos_fimd_set_clock(vid
);
384 /* set rgb mode to dual lcd. */
385 exynos_fimd_set_dualrgb(vid
, vid
->dual_lcd_enabled
);
388 exynos_fimd_lcd_on();
391 exynos_fimd_window_on(vid
->win_id
);
393 exynos_fimd_set_dp_clkcon(vid
->dp_enabled
);
394 exynos5_set_system_display();
395 printk(BIOS_SPEW
, "%s: done\n", __func__
);
398 unsigned long exynos_fimd_calc_fbsize(vidinfo_t
*vid
)
400 printk(BIOS_SPEW
, "%s\n", __func__
);
401 return vid
->vl_col
* vid
->vl_row
* ((1<<vid
->vl_bpix
) / 8);
404 void exynos_fimd_lcd_disable(void)
407 printk(BIOS_SPEW
, "%s\n", __func__
);
409 for (i
= 0; i
< 4; i
++)
410 exynos_fimd_window_off(i
);