]>
Commit | Line | Data |
---|---|---|
6d4339f6 DL |
1 | /* |
2 | * Copyright (C) 2012 Samsung Electronics | |
3 | * | |
4 | * Author: InKi Dae <inki.dae@samsung.com> | |
5 | * Author: Donghwa Lee <dh09.lee@samsung.com> | |
6 | * | |
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. | |
11 | * | |
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. | |
16 | * | |
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, | |
20 | * MA 02111-1307 USA | |
21 | */ | |
22 | ||
23 | #include <config.h> | |
24 | #include <common.h> | |
25 | #include <asm/io.h> | |
26 | #include <lcd.h> | |
27 | #include <div64.h> | |
28 | #include <asm/arch/clk.h> | |
29 | #include <asm/arch/clock.h> | |
30 | #include <asm/arch/cpu.h> | |
31 | #include "exynos_fb.h" | |
32 | ||
33 | static unsigned long *lcd_base_addr; | |
34 | static vidinfo_t *pvid; | |
35 | ||
36 | void exynos_fimd_lcd_init_mem(u_long screen_base, u_long fb_size, | |
37 | u_long palette_size) | |
38 | { | |
39 | lcd_base_addr = (unsigned long *)screen_base; | |
40 | } | |
41 | ||
42 | static void exynos_fimd_set_dualrgb(unsigned int enabled) | |
43 | { | |
ee93dcfa DL |
44 | struct exynos_fb *fimd_ctrl = |
45 | (struct exynos_fb *)samsung_get_base_fimd(); | |
6d4339f6 DL |
46 | unsigned int cfg = 0; |
47 | ||
48 | if (enabled) { | |
49 | cfg = EXYNOS_DUALRGB_BYPASS_DUAL | EXYNOS_DUALRGB_LINESPLIT | | |
50 | EXYNOS_DUALRGB_VDEN_EN_ENABLE; | |
51 | ||
52 | /* in case of Line Split mode, MAIN_CNT doesn't neet to set. */ | |
53 | cfg |= EXYNOS_DUALRGB_SUB_CNT(pvid->vl_col / 2) | | |
54 | EXYNOS_DUALRGB_MAIN_CNT(0); | |
55 | } | |
56 | ||
57 | writel(cfg, &fimd_ctrl->dualrgb); | |
58 | } | |
59 | ||
a29c8322 DL |
60 | static void exynos_fimd_set_dp_clkcon(unsigned int enabled) |
61 | { | |
62 | ||
63 | struct exynos_fb *fimd_ctrl = | |
64 | (struct exynos_fb *)samsung_get_base_fimd(); | |
65 | unsigned int cfg = 0; | |
66 | ||
67 | if (enabled) | |
68 | cfg = EXYNOS_DP_CLK_ENABLE; | |
69 | ||
70 | writel(cfg, &fimd_ctrl->dp_mie_clkcon); | |
71 | } | |
72 | ||
6d4339f6 DL |
73 | static void exynos_fimd_set_par(unsigned int win_id) |
74 | { | |
75 | unsigned int cfg = 0; | |
ee93dcfa DL |
76 | struct exynos_fb *fimd_ctrl = |
77 | (struct exynos_fb *)samsung_get_base_fimd(); | |
6d4339f6 DL |
78 | |
79 | /* set window control */ | |
80 | cfg = readl((unsigned int)&fimd_ctrl->wincon0 + | |
81 | EXYNOS_WINCON(win_id)); | |
82 | ||
83 | cfg &= ~(EXYNOS_WINCON_BITSWP_ENABLE | EXYNOS_WINCON_BYTESWP_ENABLE | | |
84 | EXYNOS_WINCON_HAWSWP_ENABLE | EXYNOS_WINCON_WSWP_ENABLE | | |
85 | EXYNOS_WINCON_BURSTLEN_MASK | EXYNOS_WINCON_BPPMODE_MASK | | |
86 | EXYNOS_WINCON_INRGB_MASK | EXYNOS_WINCON_DATAPATH_MASK); | |
87 | ||
88 | /* DATAPATH is DMA */ | |
89 | cfg |= EXYNOS_WINCON_DATAPATH_DMA; | |
90 | ||
61b59e27 AK |
91 | if (pvid->logo_on) /* To get proprietary LOGO */ |
92 | cfg |= EXYNOS_WINCON_WSWP_ENABLE; | |
93 | else /* To get output console on LCD */ | |
94 | cfg |= EXYNOS_WINCON_HAWSWP_ENABLE; | |
6d4339f6 DL |
95 | |
96 | /* dma burst is 16 */ | |
97 | cfg |= EXYNOS_WINCON_BURSTLEN_16WORD; | |
98 | ||
61b59e27 AK |
99 | if (pvid->logo_on) /* To get proprietary LOGO */ |
100 | cfg |= EXYNOS_WINCON_BPPMODE_24BPP_888; | |
101 | else /* To get output console on LCD */ | |
102 | cfg |= EXYNOS_WINCON_BPPMODE_16BPP_565; | |
6d4339f6 DL |
103 | |
104 | writel(cfg, (unsigned int)&fimd_ctrl->wincon0 + | |
105 | EXYNOS_WINCON(win_id)); | |
106 | ||
107 | /* set window position to x=0, y=0*/ | |
108 | cfg = EXYNOS_VIDOSD_LEFT_X(0) | EXYNOS_VIDOSD_TOP_Y(0); | |
109 | writel(cfg, (unsigned int)&fimd_ctrl->vidosd0a + | |
110 | EXYNOS_VIDOSD(win_id)); | |
111 | ||
112 | cfg = EXYNOS_VIDOSD_RIGHT_X(pvid->vl_col - 1) | | |
ee93dcfa DL |
113 | EXYNOS_VIDOSD_BOTTOM_Y(pvid->vl_row - 1) | |
114 | EXYNOS_VIDOSD_RIGHT_X_E(1) | | |
115 | EXYNOS_VIDOSD_BOTTOM_Y_E(0); | |
116 | ||
6d4339f6 DL |
117 | writel(cfg, (unsigned int)&fimd_ctrl->vidosd0b + |
118 | EXYNOS_VIDOSD(win_id)); | |
119 | ||
120 | /* set window size for window0*/ | |
121 | cfg = EXYNOS_VIDOSD_SIZE(pvid->vl_col * pvid->vl_row); | |
122 | writel(cfg, (unsigned int)&fimd_ctrl->vidosd0c + | |
123 | EXYNOS_VIDOSD(win_id)); | |
124 | } | |
125 | ||
126 | static void exynos_fimd_set_buffer_address(unsigned int win_id) | |
127 | { | |
128 | unsigned long start_addr, end_addr; | |
ee93dcfa DL |
129 | struct exynos_fb *fimd_ctrl = |
130 | (struct exynos_fb *)samsung_get_base_fimd(); | |
6d4339f6 DL |
131 | |
132 | start_addr = (unsigned long)lcd_base_addr; | |
f78095e4 | 133 | end_addr = start_addr + ((pvid->vl_col * (NBITS(pvid->vl_bpix) / 8)) * |
6d4339f6 DL |
134 | pvid->vl_row); |
135 | ||
136 | writel(start_addr, (unsigned int)&fimd_ctrl->vidw00add0b0 + | |
137 | EXYNOS_BUFFER_OFFSET(win_id)); | |
138 | writel(end_addr, (unsigned int)&fimd_ctrl->vidw00add1b0 + | |
139 | EXYNOS_BUFFER_OFFSET(win_id)); | |
140 | } | |
141 | ||
142 | static void exynos_fimd_set_clock(vidinfo_t *pvid) | |
143 | { | |
144 | unsigned int cfg = 0, div = 0, remainder, remainder_div; | |
145 | unsigned long pixel_clock; | |
146 | unsigned long long src_clock; | |
ee93dcfa DL |
147 | struct exynos_fb *fimd_ctrl = |
148 | (struct exynos_fb *)samsung_get_base_fimd(); | |
6d4339f6 DL |
149 | |
150 | if (pvid->dual_lcd_enabled) { | |
151 | pixel_clock = pvid->vl_freq * | |
152 | (pvid->vl_hspw + pvid->vl_hfpd + | |
153 | pvid->vl_hbpd + pvid->vl_col / 2) * | |
154 | (pvid->vl_vspw + pvid->vl_vfpd + | |
155 | pvid->vl_vbpd + pvid->vl_row); | |
156 | } else if (pvid->interface_mode == FIMD_CPU_INTERFACE) { | |
157 | pixel_clock = pvid->vl_freq * | |
158 | pvid->vl_width * pvid->vl_height * | |
159 | (pvid->cs_setup + pvid->wr_setup + | |
160 | pvid->wr_act + pvid->wr_hold + 1); | |
161 | } else { | |
162 | pixel_clock = pvid->vl_freq * | |
163 | (pvid->vl_hspw + pvid->vl_hfpd + | |
164 | pvid->vl_hbpd + pvid->vl_col) * | |
165 | (pvid->vl_vspw + pvid->vl_vfpd + | |
166 | pvid->vl_vbpd + pvid->vl_row); | |
167 | } | |
168 | ||
169 | cfg = readl(&fimd_ctrl->vidcon0); | |
170 | cfg &= ~(EXYNOS_VIDCON0_CLKSEL_MASK | EXYNOS_VIDCON0_CLKVALUP_MASK | | |
171 | EXYNOS_VIDCON0_CLKVAL_F(0xFF) | EXYNOS_VIDCON0_VCLKEN_MASK | | |
172 | EXYNOS_VIDCON0_CLKDIR_MASK); | |
173 | cfg |= (EXYNOS_VIDCON0_CLKSEL_SCLK | EXYNOS_VIDCON0_CLKVALUP_ALWAYS | | |
174 | EXYNOS_VIDCON0_VCLKEN_NORMAL | EXYNOS_VIDCON0_CLKDIR_DIVIDED); | |
175 | ||
6d4339f6 DL |
176 | src_clock = (unsigned long long) get_lcd_clk(); |
177 | ||
178 | /* get quotient and remainder. */ | |
179 | remainder = do_div(src_clock, pixel_clock); | |
180 | div = src_clock; | |
181 | ||
182 | remainder *= 10; | |
183 | remainder_div = remainder / pixel_clock; | |
184 | ||
185 | /* round about one places of decimals. */ | |
186 | if (remainder_div >= 5) | |
187 | div++; | |
188 | ||
189 | /* in case of dual lcd mode. */ | |
190 | if (pvid->dual_lcd_enabled) | |
191 | div--; | |
192 | ||
193 | cfg |= EXYNOS_VIDCON0_CLKVAL_F(div - 1); | |
194 | writel(cfg, &fimd_ctrl->vidcon0); | |
195 | } | |
196 | ||
197 | void exynos_set_trigger(void) | |
198 | { | |
199 | unsigned int cfg = 0; | |
ee93dcfa DL |
200 | struct exynos_fb *fimd_ctrl = |
201 | (struct exynos_fb *)samsung_get_base_fimd(); | |
6d4339f6 DL |
202 | |
203 | cfg = readl(&fimd_ctrl->trigcon); | |
204 | ||
205 | cfg |= (EXYNOS_I80SOFT_TRIG_EN | EXYNOS_I80START_TRIG); | |
206 | ||
207 | writel(cfg, &fimd_ctrl->trigcon); | |
208 | } | |
209 | ||
210 | int exynos_is_i80_frame_done(void) | |
211 | { | |
212 | unsigned int cfg = 0; | |
213 | int status; | |
ee93dcfa DL |
214 | struct exynos_fb *fimd_ctrl = |
215 | (struct exynos_fb *)samsung_get_base_fimd(); | |
6d4339f6 DL |
216 | |
217 | cfg = readl(&fimd_ctrl->trigcon); | |
218 | ||
219 | /* frame done func is valid only when TRIMODE[0] is set to 1. */ | |
220 | status = (cfg & EXYNOS_I80STATUS_TRIG_DONE) == | |
221 | EXYNOS_I80STATUS_TRIG_DONE; | |
222 | ||
223 | return status; | |
224 | } | |
225 | ||
226 | static void exynos_fimd_lcd_on(void) | |
227 | { | |
228 | unsigned int cfg = 0; | |
ee93dcfa DL |
229 | struct exynos_fb *fimd_ctrl = |
230 | (struct exynos_fb *)samsung_get_base_fimd(); | |
6d4339f6 DL |
231 | |
232 | /* display on */ | |
233 | cfg = readl(&fimd_ctrl->vidcon0); | |
234 | cfg |= (EXYNOS_VIDCON0_ENVID_ENABLE | EXYNOS_VIDCON0_ENVID_F_ENABLE); | |
235 | writel(cfg, &fimd_ctrl->vidcon0); | |
236 | } | |
237 | ||
238 | static void exynos_fimd_window_on(unsigned int win_id) | |
239 | { | |
240 | unsigned int cfg = 0; | |
ee93dcfa DL |
241 | struct exynos_fb *fimd_ctrl = |
242 | (struct exynos_fb *)samsung_get_base_fimd(); | |
6d4339f6 DL |
243 | |
244 | /* enable window */ | |
245 | cfg = readl((unsigned int)&fimd_ctrl->wincon0 + | |
246 | EXYNOS_WINCON(win_id)); | |
247 | cfg |= EXYNOS_WINCON_ENWIN_ENABLE; | |
248 | writel(cfg, (unsigned int)&fimd_ctrl->wincon0 + | |
249 | EXYNOS_WINCON(win_id)); | |
250 | ||
251 | cfg = readl(&fimd_ctrl->winshmap); | |
252 | cfg |= EXYNOS_WINSHMAP_CH_ENABLE(win_id); | |
253 | writel(cfg, &fimd_ctrl->winshmap); | |
254 | } | |
255 | ||
256 | void exynos_fimd_lcd_off(void) | |
257 | { | |
258 | unsigned int cfg = 0; | |
ee93dcfa DL |
259 | struct exynos_fb *fimd_ctrl = |
260 | (struct exynos_fb *)samsung_get_base_fimd(); | |
6d4339f6 DL |
261 | |
262 | cfg = readl(&fimd_ctrl->vidcon0); | |
263 | cfg &= (EXYNOS_VIDCON0_ENVID_DISABLE | EXYNOS_VIDCON0_ENVID_F_DISABLE); | |
264 | writel(cfg, &fimd_ctrl->vidcon0); | |
265 | } | |
266 | ||
267 | void exynos_fimd_window_off(unsigned int win_id) | |
268 | { | |
269 | unsigned int cfg = 0; | |
ee93dcfa DL |
270 | struct exynos_fb *fimd_ctrl = |
271 | (struct exynos_fb *)samsung_get_base_fimd(); | |
6d4339f6 DL |
272 | |
273 | cfg = readl((unsigned int)&fimd_ctrl->wincon0 + | |
274 | EXYNOS_WINCON(win_id)); | |
275 | cfg &= EXYNOS_WINCON_ENWIN_DISABLE; | |
276 | writel(cfg, (unsigned int)&fimd_ctrl->wincon0 + | |
277 | EXYNOS_WINCON(win_id)); | |
278 | ||
279 | cfg = readl(&fimd_ctrl->winshmap); | |
280 | cfg &= ~EXYNOS_WINSHMAP_CH_DISABLE(win_id); | |
281 | writel(cfg, &fimd_ctrl->winshmap); | |
282 | } | |
283 | ||
ee93dcfa | 284 | |
6d4339f6 DL |
285 | void exynos_fimd_lcd_init(vidinfo_t *vid) |
286 | { | |
287 | unsigned int cfg = 0, rgb_mode; | |
ee93dcfa DL |
288 | unsigned int offset; |
289 | struct exynos_fb *fimd_ctrl = | |
290 | (struct exynos_fb *)samsung_get_base_fimd(); | |
291 | ||
292 | offset = exynos_fimd_get_base_offset(); | |
6d4339f6 DL |
293 | |
294 | /* store panel info to global variable */ | |
295 | pvid = vid; | |
296 | ||
90464971 | 297 | rgb_mode = vid->rgb_mode; |
6d4339f6 DL |
298 | |
299 | if (vid->interface_mode == FIMD_RGB_INTERFACE) { | |
300 | cfg |= EXYNOS_VIDCON0_VIDOUT_RGB; | |
301 | writel(cfg, &fimd_ctrl->vidcon0); | |
302 | ||
303 | cfg = readl(&fimd_ctrl->vidcon2); | |
304 | cfg &= ~(EXYNOS_VIDCON2_WB_MASK | | |
305 | EXYNOS_VIDCON2_TVFORMATSEL_MASK | | |
306 | EXYNOS_VIDCON2_TVFORMATSEL_YUV_MASK); | |
307 | cfg |= EXYNOS_VIDCON2_WB_DISABLE; | |
308 | writel(cfg, &fimd_ctrl->vidcon2); | |
309 | ||
310 | /* set polarity */ | |
311 | cfg = 0; | |
312 | if (!pvid->vl_clkp) | |
313 | cfg |= EXYNOS_VIDCON1_IVCLK_RISING_EDGE; | |
314 | if (!pvid->vl_hsp) | |
315 | cfg |= EXYNOS_VIDCON1_IHSYNC_INVERT; | |
316 | if (!pvid->vl_vsp) | |
317 | cfg |= EXYNOS_VIDCON1_IVSYNC_INVERT; | |
318 | if (!pvid->vl_dp) | |
319 | cfg |= EXYNOS_VIDCON1_IVDEN_INVERT; | |
320 | ||
ee93dcfa | 321 | writel(cfg, (unsigned int)&fimd_ctrl->vidcon1 + offset); |
6d4339f6 DL |
322 | |
323 | /* set timing */ | |
324 | cfg = EXYNOS_VIDTCON0_VFPD(pvid->vl_vfpd - 1); | |
325 | cfg |= EXYNOS_VIDTCON0_VBPD(pvid->vl_vbpd - 1); | |
326 | cfg |= EXYNOS_VIDTCON0_VSPW(pvid->vl_vspw - 1); | |
ee93dcfa | 327 | writel(cfg, (unsigned int)&fimd_ctrl->vidtcon0 + offset); |
6d4339f6 DL |
328 | |
329 | cfg = EXYNOS_VIDTCON1_HFPD(pvid->vl_hfpd - 1); | |
330 | cfg |= EXYNOS_VIDTCON1_HBPD(pvid->vl_hbpd - 1); | |
331 | cfg |= EXYNOS_VIDTCON1_HSPW(pvid->vl_hspw - 1); | |
332 | ||
ee93dcfa | 333 | writel(cfg, (unsigned int)&fimd_ctrl->vidtcon1 + offset); |
6d4339f6 DL |
334 | |
335 | /* set lcd size */ | |
ee93dcfa DL |
336 | cfg = EXYNOS_VIDTCON2_HOZVAL(pvid->vl_col - 1) | |
337 | EXYNOS_VIDTCON2_LINEVAL(pvid->vl_row - 1) | | |
338 | EXYNOS_VIDTCON2_HOZVAL_E(pvid->vl_col - 1) | | |
339 | EXYNOS_VIDTCON2_LINEVAL_E(pvid->vl_row - 1); | |
6d4339f6 | 340 | |
ee93dcfa | 341 | writel(cfg, (unsigned int)&fimd_ctrl->vidtcon2 + offset); |
6d4339f6 DL |
342 | } |
343 | ||
344 | /* set display mode */ | |
345 | cfg = readl(&fimd_ctrl->vidcon0); | |
346 | cfg &= ~EXYNOS_VIDCON0_PNRMODE_MASK; | |
347 | cfg |= (rgb_mode << EXYNOS_VIDCON0_PNRMODE_SHIFT); | |
348 | writel(cfg, &fimd_ctrl->vidcon0); | |
349 | ||
350 | /* set par */ | |
351 | exynos_fimd_set_par(pvid->win_id); | |
352 | ||
353 | /* set memory address */ | |
354 | exynos_fimd_set_buffer_address(pvid->win_id); | |
355 | ||
356 | /* set buffer size */ | |
ee93dcfa DL |
357 | cfg = EXYNOS_VIDADDR_PAGEWIDTH(pvid->vl_col * NBITS(pvid->vl_bpix) / 8) | |
358 | EXYNOS_VIDADDR_PAGEWIDTH_E(pvid->vl_col * NBITS(pvid->vl_bpix) / 8) | | |
359 | EXYNOS_VIDADDR_OFFSIZE(0) | | |
360 | EXYNOS_VIDADDR_OFFSIZE_E(0); | |
361 | ||
6d4339f6 DL |
362 | writel(cfg, (unsigned int)&fimd_ctrl->vidw00add2 + |
363 | EXYNOS_BUFFER_SIZE(pvid->win_id)); | |
364 | ||
365 | /* set clock */ | |
366 | exynos_fimd_set_clock(pvid); | |
367 | ||
368 | /* set rgb mode to dual lcd. */ | |
369 | exynos_fimd_set_dualrgb(pvid->dual_lcd_enabled); | |
370 | ||
371 | /* display on */ | |
372 | exynos_fimd_lcd_on(); | |
373 | ||
374 | /* window on */ | |
375 | exynos_fimd_window_on(pvid->win_id); | |
a29c8322 DL |
376 | |
377 | exynos_fimd_set_dp_clkcon(pvid->dp_enabled); | |
6d4339f6 DL |
378 | } |
379 | ||
380 | unsigned long exynos_fimd_calc_fbsize(void) | |
381 | { | |
f78095e4 | 382 | return pvid->vl_col * pvid->vl_row * (NBITS(pvid->vl_bpix) / 8); |
6d4339f6 | 383 | } |