blob: aa850bcb8190c6120f1776133c602e255c81b5f2 [file] [log] [blame]
Ronald G. Minnichc0d5eb22013-08-01 11:38:05 -07001/*
2 * Copyright 2013 Google Inc.
3 * Copyright (C) 2012 Samsung Electronics
4 *
5 * Author: InKi Dae <inki.dae@samsung.com>
6 * Author: Donghwa Lee <dh09.lee@samsung.com>
7 *
8 * This program is free software; you can redistribute it and/or
9 * modify it under the terms of the GNU General Public License as
10 * published by the Free Software Foundation; either version 2 of
11 * the License, or (at your option) any later version.
12 *
13 * This program is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 * GNU General Public License for more details.
Ronald G. Minnichc0d5eb22013-08-01 11:38:05 -070017 */
18
Julius Wernerfa938c72013-08-29 14:17:36 -070019#include <arch/io.h>
20#include <console/console.h>
Julius Werner80af4422014-10-20 13:18:56 -070021#include <delay.h>
22#include <soc/clk.h>
23#include <soc/dp.h>
24#include <soc/fimd.h>
25#include <soc/periph.h>
26#include <soc/sysreg.h>
27#include <timer.h>
Ronald G. Minnichc0d5eb22013-08-01 11:38:05 -070028
29/* fairly useful debugging stuff. */
30#if 0
31static inline void fwadl(unsigned long l,void *v) {
32 writel(l, v);
33 printk(BIOS_SPEW, "W %p %p\n", v, (void *)l);
34}
35#define lwritel(a,b) fwadl((unsigned long)(a), (void *)(b))
36
37static inline unsigned long fradl(void *v) {
38 unsigned long l = readl(v);
39 printk(BIOS_SPEW, "R %p %p\n", v, (void *)l);
40 return l;
41}
42
43#define lreadl(a) fradl((void *)(a))
44
45#else
Julius Werner2f37bd62015-02-19 14:51:15 -080046#define lwritel(a,b) write32((void *)(b), (unsigned long)(a))
47#define lreadl(a) read32((void *)(a))
Ronald G. Minnichc0d5eb22013-08-01 11:38:05 -070048#endif
49
50/* not sure where we want this so ... */
51static unsigned long get_lcd_clk(void)
52{
Ronald G. Minnichc0d5eb22013-08-01 11:38:05 -070053 u32 pclk, sclk;
54 unsigned int sel;
55 unsigned int ratio;
56
57 /*
58 * CLK_SRC_DISP10
59 * CLKMUX_FIMD1 [4]
60 * 0: SCLK_RPLL
61 * 1: SCLK_SPLL
62 */
Julius Wernerfa938c72013-08-29 14:17:36 -070063 sel = lreadl(&exynos_clock->clk_src_disp10);
Ronald G. Minnichc0d5eb22013-08-01 11:38:05 -070064 sel &= (1 << 4);
65
66 if (sel){
67 sclk = get_pll_clk(SPLL);
68 } else {
69 sclk = get_pll_clk(RPLL);
70 }
71
72 /*
73 * CLK_DIV_DISP10
74 * FIMD1_RATIO [3:0]
75 */
Julius Wernerfa938c72013-08-29 14:17:36 -070076 ratio = lreadl(&exynos_clock->clk_div_disp10);
Ronald G. Minnichc0d5eb22013-08-01 11:38:05 -070077 ratio = ratio & 0xf;
78
79 pclk = sclk / (ratio + 1);
80
81 return pclk;
82}
83
84static void exynos_fimd_set_dualrgb(vidinfo_t *vid, unsigned int enabled)
85{
86 unsigned int cfg = 0;
87 printk(BIOS_SPEW, "%s %s\n", __func__, enabled ? "enabled" : "not enabled");
88 if (enabled) {
89 cfg = EXYNOS_DUALRGB_BYPASS_DUAL | EXYNOS_DUALRGB_LINESPLIT |
90 EXYNOS_DUALRGB_VDEN_EN_ENABLE;
91
Martin Roth1fc2ba52014-12-07 14:59:11 -070092 /* in case of Line Split mode, MAIN_CNT doesn't need to be set. */
Ronald G. Minnichc0d5eb22013-08-01 11:38:05 -070093 cfg |= EXYNOS_DUALRGB_SUB_CNT(vid->vl_col / 2) |
94 EXYNOS_DUALRGB_MAIN_CNT(0);
95 }
96
97 lwritel(cfg, &FIMD_CTRL->dualrgb);
98}
99
100static void exynos_fimd_set_dp_clkcon(unsigned int enabled)
101{
102 unsigned int cfg = 0;
103
104 if (enabled){
105 cfg = EXYNOS_DP_CLK_ENABLE;
106 }
107
108 lwritel(cfg, &FIMD_CTRL->dp_mie_clkcon);
109}
110
111static void exynos_fimd_set_par(vidinfo_t *vid, unsigned int win_id)
112{
113 unsigned int cfg = 0;
114 printk(BIOS_SPEW, "%s %d\n", __func__, win_id);
115 /* set window control */
116 cfg = lreadl(&FIMD_CTRL->wincon0 +
117 EXYNOS_WINCON(win_id));
118
119 cfg &= ~(EXYNOS_WINCON_BITSWP_ENABLE | EXYNOS_WINCON_BYTESWP_ENABLE |
120 EXYNOS_WINCON_HAWSWP_ENABLE | EXYNOS_WINCON_WSWP_ENABLE |
121 EXYNOS_WINCON_BURSTLEN_MASK | EXYNOS_WINCON_BPPMODE_MASK |
122 EXYNOS_WINCON_INRGB_MASK | EXYNOS_WINCON_DATAPATH_MASK);
123
124 /* DATAPATH is DMA */
125 cfg |= EXYNOS_WINCON_DATAPATH_DMA;
126
127 cfg |= EXYNOS_WINCON_HAWSWP_ENABLE;
128
129 /* dma burst is 16 */
130 cfg |= EXYNOS_WINCON_BURSTLEN_16WORD;
131
132 cfg |= EXYNOS_WINCON_BPPMODE_16BPP_565;
133
134 lwritel(cfg, &FIMD_CTRL->wincon0 +
135 EXYNOS_WINCON(win_id));
136
137 /* set window position to x=0, y=0*/
138 cfg = EXYNOS_VIDOSD_LEFT_X(0) | EXYNOS_VIDOSD_TOP_Y(0);
139 lwritel(cfg, &FIMD_CTRL->vidosd0a +
140 EXYNOS_VIDOSD(win_id));
141
142 cfg = EXYNOS_VIDOSD_RIGHT_X(vid->vl_col - 1) |
143 EXYNOS_VIDOSD_BOTTOM_Y(vid->vl_row - 1) |
144 EXYNOS_VIDOSD_RIGHT_X_E(1) |
145 EXYNOS_VIDOSD_BOTTOM_Y_E(0);
146
147 lwritel(cfg, &FIMD_CTRL->vidosd0b +
148 EXYNOS_VIDOSD(win_id));
149 /* set window size for window0*/
150 cfg = EXYNOS_VIDOSD_SIZE(vid->vl_col * vid->vl_row);
151 lwritel(cfg, &FIMD_CTRL->vidosd0c +
152 EXYNOS_VIDOSD(win_id));
153}
154
155static void exynos_fimd_set_buffer_address(vidinfo_t *vid,
156 void *screen_base, int win_id)
157{
158 u32 start_addr, end_addr;
159 printk(BIOS_SPEW, "%s %d\n", __func__, win_id);
160 start_addr = (u32)screen_base;
161 end_addr = start_addr + ((vid->vl_col * ((1<<vid->vl_bpix) / 8)) *
162 vid->vl_row);
163
164 lwritel(start_addr, &FIMD_CTRL->vidw00add0b0 +
165 EXYNOS_BUFFER_OFFSET(win_id));
166 lwritel(end_addr, &FIMD_CTRL->vidw00add1b0 +
167 EXYNOS_BUFFER_OFFSET(win_id));
168}
169
170static void exynos_fimd_set_clock(vidinfo_t *vid)
171{
172 unsigned int cfg = 0, div = 0, remainder = 0, remainder_div;
173 unsigned long pixel_clock;
174 unsigned long long src_clock;
175 printk(BIOS_SPEW, "%s\n", __func__);
176 if (vid->dual_lcd_enabled) {
177 pixel_clock = vid->vl_freq *
178 (vid->vl_hspw + vid->vl_hfpd +
179 vid->vl_hbpd + vid->vl_col / 2) *
180 (vid->vl_vspw + vid->vl_vfpd +
181 vid->vl_vbpd + vid->vl_row);
182 } else if (vid->interface_mode == FIMD_CPU_INTERFACE) {
183 pixel_clock = vid->vl_freq *
184 vid->vl_width * vid->vl_height *
185 (vid->cs_setup + vid->wr_setup +
186 vid->wr_act + vid->wr_hold + 1);
187 } else {
188 pixel_clock = vid->vl_freq *
189 (vid->vl_hspw + vid->vl_hfpd +
190 vid->vl_hbpd + vid->vl_col) *
191 (vid->vl_vspw + vid->vl_vfpd +
192 vid->vl_vbpd + vid->vl_row);
193 }
194 printk(BIOS_SPEW, "Pixel clock is %lx\n", pixel_clock);
195
196 cfg = lreadl(&FIMD_CTRL->vidcon0);
197 cfg &= ~(EXYNOS_VIDCON0_CLKSEL_MASK | EXYNOS_VIDCON0_CLKVALUP_MASK |
198 EXYNOS_VIDCON0_CLKVAL_F(0xFF) | EXYNOS_VIDCON0_VCLKEN_MASK |
199 EXYNOS_VIDCON0_CLKDIR_MASK);
200 cfg |= (EXYNOS_VIDCON0_CLKSEL_SCLK | EXYNOS_VIDCON0_CLKVALUP_ALWAYS |
201 EXYNOS_VIDCON0_VCLKEN_NORMAL | EXYNOS_VIDCON0_CLKDIR_DIVIDED);
202
203 src_clock = (unsigned long long) get_lcd_clk();
204
205 /* get quotient and remainder. */
206 remainder = src_clock % pixel_clock;
207 src_clock /= pixel_clock;
208
209 div = src_clock;
210
211 remainder *= 10;
212 remainder_div = remainder / pixel_clock;
213
214 /* round about one places of decimals. */
215 if (remainder_div >= 5)
216 div++;
217
218 /* in case of dual lcd mode. */
219 if (vid->dual_lcd_enabled)
220 div--;
221
222 cfg |= EXYNOS_VIDCON0_CLKVAL_F(div - 1);
223 lwritel(cfg, &FIMD_CTRL->vidcon0);
224}
225
226void exynos_set_trigger(void)
227{
228 unsigned int cfg = 0;
229 printk(BIOS_SPEW, "%s\n", __func__);
230 cfg = lreadl(&FIMD_CTRL->trigcon);
231
232 cfg |= (EXYNOS_I80SOFT_TRIG_EN | EXYNOS_I80START_TRIG);
233
234 lwritel(cfg, &FIMD_CTRL->trigcon);
235}
236
237int exynos_is_i80_frame_done(void)
238{
239 unsigned int cfg = 0;
240 int status;
241 printk(BIOS_SPEW, "%s\n", __func__);
242 cfg = lreadl(&FIMD_CTRL->trigcon);
243
244 /* frame done func is valid only when TRIMODE[0] is set to 1. */
245 status = (cfg & EXYNOS_I80STATUS_TRIG_DONE) ==
246 EXYNOS_I80STATUS_TRIG_DONE;
247
248 return status;
249}
250
251static void exynos_fimd_lcd_on(void)
252{
253 unsigned int cfg = 0;
254
255 printk(BIOS_SPEW, "%s\n", __func__);
256 /* display on */
257 cfg = lreadl(&FIMD_CTRL->vidcon0);
258 cfg |= (EXYNOS_VIDCON0_ENVID_ENABLE | EXYNOS_VIDCON0_ENVID_F_ENABLE);
259 lwritel(cfg, &FIMD_CTRL->vidcon0);
260}
261
262static void exynos_fimd_window_on(unsigned int win_id)
263{
264 unsigned int cfg = 0;
265 printk(BIOS_SPEW, "%s %d\n", __func__, win_id);
266 /* enable window */
267 cfg = lreadl(&FIMD_CTRL->wincon0 +
268 EXYNOS_WINCON(win_id));
269 cfg |= EXYNOS_WINCON_ENWIN_ENABLE;
270 lwritel(cfg, &FIMD_CTRL->wincon0 +
271 EXYNOS_WINCON(win_id));
272
273 cfg = lreadl(&FIMD_CTRL->winshmap);
274 cfg |= EXYNOS_WINSHMAP_CH_ENABLE(win_id);
275 lwritel(cfg, &FIMD_CTRL->winshmap);
276 cfg = lreadl(&FIMD_CTRL->winshmap);
277}
278
279void exynos_fimd_lcd_off(void)
280{
281 unsigned int cfg = 0;
282 printk(BIOS_SPEW, "%s\n", __func__);
283
284 cfg = lreadl(&FIMD_CTRL->vidcon0);
285 cfg &= (EXYNOS_VIDCON0_ENVID_DISABLE | EXYNOS_VIDCON0_ENVID_F_DISABLE);
286 lwritel(cfg, &FIMD_CTRL->vidcon0);
287}
288
289void exynos_fimd_window_off(unsigned int win_id)
290{
291 unsigned int cfg = 0;
292 printk(BIOS_SPEW, "%s %d\n", __func__, win_id);
293
294 cfg = lreadl(&FIMD_CTRL->wincon0 +
295 EXYNOS_WINCON(win_id));
296 cfg &= EXYNOS_WINCON_ENWIN_DISABLE;
297 lwritel(cfg, &FIMD_CTRL->wincon0 +
298 EXYNOS_WINCON(win_id));
299
300 cfg = lreadl(&FIMD_CTRL->winshmap);
301 cfg &= ~EXYNOS_WINSHMAP_CH_DISABLE(win_id);
302 lwritel(cfg, &FIMD_CTRL->winshmap);
303}
304
305static void exynos5_set_system_display(void)
306{
Elyes HAOUAS88607a42018-10-05 10:36:45 +0200307 unsigned int cfg = 0;
Ronald G. Minnichc0d5eb22013-08-01 11:38:05 -0700308
Elyes HAOUAS88607a42018-10-05 10:36:45 +0200309 /*
310 * system register path set
311 * 0: MIE/MDNIE
312 * 1: FIMD Bypass
313 */
314 cfg = lreadl(&exynos_sysreg->disp1blk_cfg);
315 cfg |= (1 << 15);
316 lwritel(cfg, &exynos_sysreg->disp1blk_cfg);
Ronald G. Minnichc0d5eb22013-08-01 11:38:05 -0700317}
318
319void exynos_fimd_lcd_init(vidinfo_t *vid)
320{
321 unsigned int cfg = 0, rgb_mode;
322 unsigned int offset;
323
324 offset = exynos_fimd_get_base_offset();
325 printk(BIOS_SPEW, "%s\n", __func__);
326 exynos5_set_system_display();
327
328 rgb_mode = vid->rgb_mode;
329
330 if (vid->interface_mode == FIMD_RGB_INTERFACE) {
331 printk(BIOS_SPEW, "%s FIMD_RGB_INTERFACE\n", __func__);
332
333 cfg |= EXYNOS_VIDCON0_VIDOUT_RGB;
334 lwritel(cfg, &FIMD_CTRL->vidcon0);
335
336 cfg = lreadl(&FIMD_CTRL->vidcon2);
337 cfg &= ~(EXYNOS_VIDCON2_WB_MASK |
338 EXYNOS_VIDCON2_TVFORMATSEL_MASK |
339 EXYNOS_VIDCON2_TVFORMATSEL_YUV_MASK);
340 cfg |= EXYNOS_VIDCON2_WB_DISABLE;
341 lwritel(cfg, &FIMD_CTRL->vidcon2);
342
343 /* set polarity */
344 cfg = 0;
345 if (!vid->vl_clkp)
346 cfg |= EXYNOS_VIDCON1_IVCLK_RISING_EDGE;
347 if (!vid->vl_hsp)
348 cfg |= EXYNOS_VIDCON1_IHSYNC_INVERT;
349 if (!vid->vl_vsp)
350 cfg |= EXYNOS_VIDCON1_IVSYNC_INVERT;
351 if (!vid->vl_dp)
352 cfg |= EXYNOS_VIDCON1_IVDEN_INVERT;
353
354 lwritel(cfg, &FIMD_CTRL->vidcon1 + offset);
355
356 /* set timing */
357 cfg = EXYNOS_VIDTCON0_VFPD(vid->vl_vfpd - 1);
358 cfg |= EXYNOS_VIDTCON0_VBPD(vid->vl_vbpd - 1);
359 cfg |= EXYNOS_VIDTCON0_VSPW(vid->vl_vspw - 1);
360 lwritel(cfg, &FIMD_CTRL->vidtcon0 + offset);
361
362 cfg = EXYNOS_VIDTCON1_HFPD(vid->vl_hfpd - 1);
363 cfg |= EXYNOS_VIDTCON1_HBPD(vid->vl_hbpd - 1);
364 cfg |= EXYNOS_VIDTCON1_HSPW(vid->vl_hspw - 1);
365
366 lwritel(cfg, &FIMD_CTRL->vidtcon1 + offset);
367
368 /* set lcd size */
369 cfg = EXYNOS_VIDTCON2_HOZVAL(vid->vl_col - 1) |
370 EXYNOS_VIDTCON2_LINEVAL(vid->vl_row - 1) |
371 EXYNOS_VIDTCON2_HOZVAL_E(vid->vl_col - 1) |
372 EXYNOS_VIDTCON2_LINEVAL_E(vid->vl_row - 1);
373
374 lwritel(cfg, &FIMD_CTRL->vidtcon2 + offset);
375 }
376
377 /* set display mode */
378 cfg = lreadl(&FIMD_CTRL->vidcon0);
379 cfg &= ~EXYNOS_VIDCON0_PNRMODE_MASK;
380 cfg |= (rgb_mode << EXYNOS_VIDCON0_PNRMODE_SHIFT);
381 lwritel(cfg, &FIMD_CTRL->vidcon0);
382
383 /* set par */
384 exynos_fimd_set_par(vid, vid->win_id);
385
386 /* set memory address */
387 exynos_fimd_set_buffer_address(vid, vid->screen_base, vid->win_id);
388
389 /* set buffer size */
390 cfg = EXYNOS_VIDADDR_PAGEWIDTH(vid->vl_col * (1<<vid->vl_bpix) / 8) |
391 EXYNOS_VIDADDR_PAGEWIDTH_E(vid->vl_col * (1<<vid->vl_bpix) / 8) |
392 EXYNOS_VIDADDR_OFFSIZE(0) |
393 EXYNOS_VIDADDR_OFFSIZE_E(0);
394
395 lwritel(cfg, &FIMD_CTRL->vidw00add2 +
396 EXYNOS_BUFFER_SIZE(vid->win_id));
397
398 /* set clock */
399 exynos_fimd_set_clock(vid);
400
401 /* set rgb mode to dual lcd. */
402 exynos_fimd_set_dualrgb(vid, vid->dual_lcd_enabled);
403
404 /* display on */
405 exynos_fimd_lcd_on();
406
407 /* window on */
408 exynos_fimd_window_on(vid->win_id);
409
410 exynos_fimd_set_dp_clkcon(vid->dp_enabled);
411 exynos5_set_system_display();
412 printk(BIOS_SPEW, "%s: done\n", __func__);
413}
414
415unsigned long exynos_fimd_calc_fbsize(vidinfo_t *vid)
416{
417 printk(BIOS_SPEW, "%s\n", __func__);
418 return vid->vl_col * vid->vl_row * ((1<<vid->vl_bpix) / 8);
419}
420
421void exynos_fimd_lcd_disable(void)
422{
423 int i;
424 printk(BIOS_SPEW, "%s\n", __func__);
425
426 for (i = 0; i < 4; i++)
427 exynos_fimd_window_off(i);
428}