2 * Copyright (C) 2012 Samsung Electronics
4 * Author: InKi Dae <inki.dae@samsung.com>
5 * Author: Donghwa Lee <dh09.lee@samsung.com>
7 * This program is free software; you can redistribute it and/or
8 * modify it under the terms of the GNU General Public License as
9 * published by the Free Software Foundation; either version 2 of
10 * the License, or (at your option) any later version.
12 * This program is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 * GNU General Public License for more details.
17 * You should have received a copy of the GNU General Public License
18 * along with this program; if not, write to the Free Software
19 * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
30 #include <asm/arch/clk.h>
31 #include <asm/arch/clock.h>
32 #include <asm/arch/cpu.h>
33 #include "exynos_fb.h"
35 DECLARE_GLOBAL_DATA_PTR
;
37 static unsigned long *lcd_base_addr
;
38 static vidinfo_t
*pvid
;
39 static struct exynos_fb
*fimd_ctrl
;
41 void exynos_fimd_lcd_init_mem(u_long screen_base
, u_long fb_size
,
44 lcd_base_addr
= (unsigned long *)screen_base
;
47 static void exynos_fimd_set_dualrgb(unsigned int enabled
)
52 cfg
= EXYNOS_DUALRGB_BYPASS_DUAL
| EXYNOS_DUALRGB_LINESPLIT
|
53 EXYNOS_DUALRGB_VDEN_EN_ENABLE
;
55 /* in case of Line Split mode, MAIN_CNT doesn't neet to set. */
56 cfg
|= EXYNOS_DUALRGB_SUB_CNT(pvid
->vl_col
/ 2) |
57 EXYNOS_DUALRGB_MAIN_CNT(0);
60 writel(cfg
, &fimd_ctrl
->dualrgb
);
63 static void exynos_fimd_set_dp_clkcon(unsigned int enabled
)
68 cfg
= EXYNOS_DP_CLK_ENABLE
;
70 writel(cfg
, &fimd_ctrl
->dp_mie_clkcon
);
73 static void exynos_fimd_set_par(unsigned int win_id
)
77 /* set window control */
78 cfg
= readl((unsigned int)&fimd_ctrl
->wincon0
+
79 EXYNOS_WINCON(win_id
));
81 cfg
&= ~(EXYNOS_WINCON_BITSWP_ENABLE
| EXYNOS_WINCON_BYTESWP_ENABLE
|
82 EXYNOS_WINCON_HAWSWP_ENABLE
| EXYNOS_WINCON_WSWP_ENABLE
|
83 EXYNOS_WINCON_BURSTLEN_MASK
| EXYNOS_WINCON_BPPMODE_MASK
|
84 EXYNOS_WINCON_INRGB_MASK
| EXYNOS_WINCON_DATAPATH_MASK
);
87 cfg
|= EXYNOS_WINCON_DATAPATH_DMA
;
89 if (pvid
->logo_on
) /* To get proprietary LOGO */
90 cfg
|= EXYNOS_WINCON_WSWP_ENABLE
;
91 else /* To get output console on LCD */
92 cfg
|= EXYNOS_WINCON_HAWSWP_ENABLE
;
95 cfg
|= EXYNOS_WINCON_BURSTLEN_16WORD
;
97 if (pvid
->logo_on
) /* To get proprietary LOGO */
98 cfg
|= EXYNOS_WINCON_BPPMODE_24BPP_888
;
99 else /* To get output console on LCD */
100 cfg
|= EXYNOS_WINCON_BPPMODE_16BPP_565
;
102 writel(cfg
, (unsigned int)&fimd_ctrl
->wincon0
+
103 EXYNOS_WINCON(win_id
));
105 /* set window position to x=0, y=0*/
106 cfg
= EXYNOS_VIDOSD_LEFT_X(0) | EXYNOS_VIDOSD_TOP_Y(0);
107 writel(cfg
, (unsigned int)&fimd_ctrl
->vidosd0a
+
108 EXYNOS_VIDOSD(win_id
));
110 cfg
= EXYNOS_VIDOSD_RIGHT_X(pvid
->vl_col
- 1) |
111 EXYNOS_VIDOSD_BOTTOM_Y(pvid
->vl_row
- 1) |
112 EXYNOS_VIDOSD_RIGHT_X_E(1) |
113 EXYNOS_VIDOSD_BOTTOM_Y_E(0);
115 writel(cfg
, (unsigned int)&fimd_ctrl
->vidosd0b
+
116 EXYNOS_VIDOSD(win_id
));
118 /* set window size for window0*/
119 cfg
= EXYNOS_VIDOSD_SIZE(pvid
->vl_col
* pvid
->vl_row
);
120 writel(cfg
, (unsigned int)&fimd_ctrl
->vidosd0c
+
121 EXYNOS_VIDOSD(win_id
));
124 static void exynos_fimd_set_buffer_address(unsigned int win_id
)
126 unsigned long start_addr
, end_addr
;
128 start_addr
= (unsigned long)lcd_base_addr
;
129 end_addr
= start_addr
+ ((pvid
->vl_col
* (NBITS(pvid
->vl_bpix
) / 8)) *
132 writel(start_addr
, (unsigned int)&fimd_ctrl
->vidw00add0b0
+
133 EXYNOS_BUFFER_OFFSET(win_id
));
134 writel(end_addr
, (unsigned int)&fimd_ctrl
->vidw00add1b0
+
135 EXYNOS_BUFFER_OFFSET(win_id
));
138 static void exynos_fimd_set_clock(vidinfo_t
*pvid
)
140 unsigned int cfg
= 0, div
= 0, remainder
, remainder_div
;
141 unsigned long pixel_clock
;
142 unsigned long long src_clock
;
144 if (pvid
->dual_lcd_enabled
) {
145 pixel_clock
= pvid
->vl_freq
*
146 (pvid
->vl_hspw
+ pvid
->vl_hfpd
+
147 pvid
->vl_hbpd
+ pvid
->vl_col
/ 2) *
148 (pvid
->vl_vspw
+ pvid
->vl_vfpd
+
149 pvid
->vl_vbpd
+ pvid
->vl_row
);
150 } else if (pvid
->interface_mode
== FIMD_CPU_INTERFACE
) {
151 pixel_clock
= pvid
->vl_freq
*
152 pvid
->vl_width
* pvid
->vl_height
*
153 (pvid
->cs_setup
+ pvid
->wr_setup
+
154 pvid
->wr_act
+ pvid
->wr_hold
+ 1);
156 pixel_clock
= pvid
->vl_freq
*
157 (pvid
->vl_hspw
+ pvid
->vl_hfpd
+
158 pvid
->vl_hbpd
+ pvid
->vl_col
) *
159 (pvid
->vl_vspw
+ pvid
->vl_vfpd
+
160 pvid
->vl_vbpd
+ pvid
->vl_row
);
163 cfg
= readl(&fimd_ctrl
->vidcon0
);
164 cfg
&= ~(EXYNOS_VIDCON0_CLKSEL_MASK
| EXYNOS_VIDCON0_CLKVALUP_MASK
|
165 EXYNOS_VIDCON0_CLKVAL_F(0xFF) | EXYNOS_VIDCON0_VCLKEN_MASK
|
166 EXYNOS_VIDCON0_CLKDIR_MASK
);
167 cfg
|= (EXYNOS_VIDCON0_CLKSEL_SCLK
| EXYNOS_VIDCON0_CLKVALUP_ALWAYS
|
168 EXYNOS_VIDCON0_VCLKEN_NORMAL
| EXYNOS_VIDCON0_CLKDIR_DIVIDED
);
170 src_clock
= (unsigned long long) get_lcd_clk();
172 /* get quotient and remainder. */
173 remainder
= do_div(src_clock
, pixel_clock
);
177 remainder_div
= remainder
/ pixel_clock
;
179 /* round about one places of decimals. */
180 if (remainder_div
>= 5)
183 /* in case of dual lcd mode. */
184 if (pvid
->dual_lcd_enabled
)
187 cfg
|= EXYNOS_VIDCON0_CLKVAL_F(div
- 1);
188 writel(cfg
, &fimd_ctrl
->vidcon0
);
191 void exynos_set_trigger(void)
193 unsigned int cfg
= 0;
195 cfg
= readl(&fimd_ctrl
->trigcon
);
197 cfg
|= (EXYNOS_I80SOFT_TRIG_EN
| EXYNOS_I80START_TRIG
);
199 writel(cfg
, &fimd_ctrl
->trigcon
);
202 int exynos_is_i80_frame_done(void)
204 unsigned int cfg
= 0;
207 cfg
= readl(&fimd_ctrl
->trigcon
);
209 /* frame done func is valid only when TRIMODE[0] is set to 1. */
210 status
= (cfg
& EXYNOS_I80STATUS_TRIG_DONE
) ==
211 EXYNOS_I80STATUS_TRIG_DONE
;
216 static void exynos_fimd_lcd_on(void)
218 unsigned int cfg
= 0;
221 cfg
= readl(&fimd_ctrl
->vidcon0
);
222 cfg
|= (EXYNOS_VIDCON0_ENVID_ENABLE
| EXYNOS_VIDCON0_ENVID_F_ENABLE
);
223 writel(cfg
, &fimd_ctrl
->vidcon0
);
226 static void exynos_fimd_window_on(unsigned int win_id
)
228 unsigned int cfg
= 0;
231 cfg
= readl((unsigned int)&fimd_ctrl
->wincon0
+
232 EXYNOS_WINCON(win_id
));
233 cfg
|= EXYNOS_WINCON_ENWIN_ENABLE
;
234 writel(cfg
, (unsigned int)&fimd_ctrl
->wincon0
+
235 EXYNOS_WINCON(win_id
));
237 cfg
= readl(&fimd_ctrl
->winshmap
);
238 cfg
|= EXYNOS_WINSHMAP_CH_ENABLE(win_id
);
239 writel(cfg
, &fimd_ctrl
->winshmap
);
242 void exynos_fimd_lcd_off(void)
244 unsigned int cfg
= 0;
246 cfg
= readl(&fimd_ctrl
->vidcon0
);
247 cfg
&= (EXYNOS_VIDCON0_ENVID_DISABLE
| EXYNOS_VIDCON0_ENVID_F_DISABLE
);
248 writel(cfg
, &fimd_ctrl
->vidcon0
);
251 void exynos_fimd_window_off(unsigned int win_id
)
253 unsigned int cfg
= 0;
255 cfg
= readl((unsigned int)&fimd_ctrl
->wincon0
+
256 EXYNOS_WINCON(win_id
));
257 cfg
&= EXYNOS_WINCON_ENWIN_DISABLE
;
258 writel(cfg
, (unsigned int)&fimd_ctrl
->wincon0
+
259 EXYNOS_WINCON(win_id
));
261 cfg
= readl(&fimd_ctrl
->winshmap
);
262 cfg
&= ~EXYNOS_WINSHMAP_CH_DISABLE(win_id
);
263 writel(cfg
, &fimd_ctrl
->winshmap
);
267 void exynos_fimd_lcd_init(vidinfo_t
*vid
)
269 unsigned int cfg
= 0, rgb_mode
;
271 #ifdef CONFIG_OF_CONTROL
274 node
= fdtdec_next_compatible(gd
->fdt_blob
,
275 0, COMPAT_SAMSUNG_EXYNOS_FIMD
);
277 debug("exynos_fb: Can't get device node for fimd\n");
279 fimd_ctrl
= (struct exynos_fb
*)fdtdec_get_addr(gd
->fdt_blob
,
281 if (fimd_ctrl
== NULL
)
282 debug("Can't get the FIMD base address\n");
284 fimd_ctrl
= (struct exynos_fb
*)samsung_get_base_fimd();
286 offset
= exynos_fimd_get_base_offset();
288 /* store panel info to global variable */
291 rgb_mode
= vid
->rgb_mode
;
293 if (vid
->interface_mode
== FIMD_RGB_INTERFACE
) {
294 cfg
|= EXYNOS_VIDCON0_VIDOUT_RGB
;
295 writel(cfg
, &fimd_ctrl
->vidcon0
);
297 cfg
= readl(&fimd_ctrl
->vidcon2
);
298 cfg
&= ~(EXYNOS_VIDCON2_WB_MASK
|
299 EXYNOS_VIDCON2_TVFORMATSEL_MASK
|
300 EXYNOS_VIDCON2_TVFORMATSEL_YUV_MASK
);
301 cfg
|= EXYNOS_VIDCON2_WB_DISABLE
;
302 writel(cfg
, &fimd_ctrl
->vidcon2
);
307 cfg
|= EXYNOS_VIDCON1_IVCLK_RISING_EDGE
;
309 cfg
|= EXYNOS_VIDCON1_IHSYNC_INVERT
;
311 cfg
|= EXYNOS_VIDCON1_IVSYNC_INVERT
;
313 cfg
|= EXYNOS_VIDCON1_IVDEN_INVERT
;
315 writel(cfg
, (unsigned int)&fimd_ctrl
->vidcon1
+ offset
);
318 cfg
= EXYNOS_VIDTCON0_VFPD(pvid
->vl_vfpd
- 1);
319 cfg
|= EXYNOS_VIDTCON0_VBPD(pvid
->vl_vbpd
- 1);
320 cfg
|= EXYNOS_VIDTCON0_VSPW(pvid
->vl_vspw
- 1);
321 writel(cfg
, (unsigned int)&fimd_ctrl
->vidtcon0
+ offset
);
323 cfg
= EXYNOS_VIDTCON1_HFPD(pvid
->vl_hfpd
- 1);
324 cfg
|= EXYNOS_VIDTCON1_HBPD(pvid
->vl_hbpd
- 1);
325 cfg
|= EXYNOS_VIDTCON1_HSPW(pvid
->vl_hspw
- 1);
327 writel(cfg
, (unsigned int)&fimd_ctrl
->vidtcon1
+ offset
);
330 cfg
= EXYNOS_VIDTCON2_HOZVAL(pvid
->vl_col
- 1) |
331 EXYNOS_VIDTCON2_LINEVAL(pvid
->vl_row
- 1) |
332 EXYNOS_VIDTCON2_HOZVAL_E(pvid
->vl_col
- 1) |
333 EXYNOS_VIDTCON2_LINEVAL_E(pvid
->vl_row
- 1);
335 writel(cfg
, (unsigned int)&fimd_ctrl
->vidtcon2
+ offset
);
338 /* set display mode */
339 cfg
= readl(&fimd_ctrl
->vidcon0
);
340 cfg
&= ~EXYNOS_VIDCON0_PNRMODE_MASK
;
341 cfg
|= (rgb_mode
<< EXYNOS_VIDCON0_PNRMODE_SHIFT
);
342 writel(cfg
, &fimd_ctrl
->vidcon0
);
345 exynos_fimd_set_par(pvid
->win_id
);
347 /* set memory address */
348 exynos_fimd_set_buffer_address(pvid
->win_id
);
350 /* set buffer size */
351 cfg
= EXYNOS_VIDADDR_PAGEWIDTH(pvid
->vl_col
* NBITS(pvid
->vl_bpix
) / 8) |
352 EXYNOS_VIDADDR_PAGEWIDTH_E(pvid
->vl_col
* NBITS(pvid
->vl_bpix
) / 8) |
353 EXYNOS_VIDADDR_OFFSIZE(0) |
354 EXYNOS_VIDADDR_OFFSIZE_E(0);
356 writel(cfg
, (unsigned int)&fimd_ctrl
->vidw00add2
+
357 EXYNOS_BUFFER_SIZE(pvid
->win_id
));
360 exynos_fimd_set_clock(pvid
);
362 /* set rgb mode to dual lcd. */
363 exynos_fimd_set_dualrgb(pvid
->dual_lcd_enabled
);
366 exynos_fimd_lcd_on();
369 exynos_fimd_window_on(pvid
->win_id
);
371 exynos_fimd_set_dp_clkcon(pvid
->dp_enabled
);
374 unsigned long exynos_fimd_calc_fbsize(void)
376 return pvid
->vl_col
* pvid
->vl_row
* (NBITS(pvid
->vl_bpix
) / 8);