blob: 675d9e17758003019a2ee7783f9a105878070d08 [file] [log] [blame]
Donghwa Lee6d4339f2012-04-05 19:36:17 +00001/*
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
33static unsigned long *lcd_base_addr;
34static vidinfo_t *pvid;
Ajay Kumar47ff6072013-02-21 23:52:59 +000035static struct exynos_fb *fimd_ctrl;
Donghwa Lee6d4339f2012-04-05 19:36:17 +000036
37void exynos_fimd_lcd_init_mem(u_long screen_base, u_long fb_size,
38 u_long palette_size)
39{
40 lcd_base_addr = (unsigned long *)screen_base;
41}
42
43static void exynos_fimd_set_dualrgb(unsigned int enabled)
44{
Donghwa Lee6d4339f2012-04-05 19:36:17 +000045 unsigned int cfg = 0;
46
47 if (enabled) {
48 cfg = EXYNOS_DUALRGB_BYPASS_DUAL | EXYNOS_DUALRGB_LINESPLIT |
49 EXYNOS_DUALRGB_VDEN_EN_ENABLE;
50
51 /* in case of Line Split mode, MAIN_CNT doesn't neet to set. */
52 cfg |= EXYNOS_DUALRGB_SUB_CNT(pvid->vl_col / 2) |
53 EXYNOS_DUALRGB_MAIN_CNT(0);
54 }
55
56 writel(cfg, &fimd_ctrl->dualrgb);
57}
58
Donghwa Leea29c8322012-07-02 01:16:08 +000059static void exynos_fimd_set_dp_clkcon(unsigned int enabled)
60{
Donghwa Leea29c8322012-07-02 01:16:08 +000061 unsigned int cfg = 0;
62
63 if (enabled)
64 cfg = EXYNOS_DP_CLK_ENABLE;
65
66 writel(cfg, &fimd_ctrl->dp_mie_clkcon);
67}
68
Donghwa Lee6d4339f2012-04-05 19:36:17 +000069static void exynos_fimd_set_par(unsigned int win_id)
70{
71 unsigned int cfg = 0;
Donghwa Lee6d4339f2012-04-05 19:36:17 +000072
73 /* set window control */
74 cfg = readl((unsigned int)&fimd_ctrl->wincon0 +
75 EXYNOS_WINCON(win_id));
76
77 cfg &= ~(EXYNOS_WINCON_BITSWP_ENABLE | EXYNOS_WINCON_BYTESWP_ENABLE |
78 EXYNOS_WINCON_HAWSWP_ENABLE | EXYNOS_WINCON_WSWP_ENABLE |
79 EXYNOS_WINCON_BURSTLEN_MASK | EXYNOS_WINCON_BPPMODE_MASK |
80 EXYNOS_WINCON_INRGB_MASK | EXYNOS_WINCON_DATAPATH_MASK);
81
82 /* DATAPATH is DMA */
83 cfg |= EXYNOS_WINCON_DATAPATH_DMA;
84
Ajay Kumar61b59e22013-01-08 20:42:25 +000085 if (pvid->logo_on) /* To get proprietary LOGO */
86 cfg |= EXYNOS_WINCON_WSWP_ENABLE;
87 else /* To get output console on LCD */
88 cfg |= EXYNOS_WINCON_HAWSWP_ENABLE;
Donghwa Lee6d4339f2012-04-05 19:36:17 +000089
90 /* dma burst is 16 */
91 cfg |= EXYNOS_WINCON_BURSTLEN_16WORD;
92
Ajay Kumar61b59e22013-01-08 20:42:25 +000093 if (pvid->logo_on) /* To get proprietary LOGO */
94 cfg |= EXYNOS_WINCON_BPPMODE_24BPP_888;
95 else /* To get output console on LCD */
96 cfg |= EXYNOS_WINCON_BPPMODE_16BPP_565;
Donghwa Lee6d4339f2012-04-05 19:36:17 +000097
98 writel(cfg, (unsigned int)&fimd_ctrl->wincon0 +
99 EXYNOS_WINCON(win_id));
100
101 /* set window position to x=0, y=0*/
102 cfg = EXYNOS_VIDOSD_LEFT_X(0) | EXYNOS_VIDOSD_TOP_Y(0);
103 writel(cfg, (unsigned int)&fimd_ctrl->vidosd0a +
104 EXYNOS_VIDOSD(win_id));
105
106 cfg = EXYNOS_VIDOSD_RIGHT_X(pvid->vl_col - 1) |
Donghwa Leeee93dcf2012-07-26 15:30:49 +0000107 EXYNOS_VIDOSD_BOTTOM_Y(pvid->vl_row - 1) |
108 EXYNOS_VIDOSD_RIGHT_X_E(1) |
109 EXYNOS_VIDOSD_BOTTOM_Y_E(0);
110
Donghwa Lee6d4339f2012-04-05 19:36:17 +0000111 writel(cfg, (unsigned int)&fimd_ctrl->vidosd0b +
112 EXYNOS_VIDOSD(win_id));
113
114 /* set window size for window0*/
115 cfg = EXYNOS_VIDOSD_SIZE(pvid->vl_col * pvid->vl_row);
116 writel(cfg, (unsigned int)&fimd_ctrl->vidosd0c +
117 EXYNOS_VIDOSD(win_id));
118}
119
120static void exynos_fimd_set_buffer_address(unsigned int win_id)
121{
122 unsigned long start_addr, end_addr;
Donghwa Lee6d4339f2012-04-05 19:36:17 +0000123
124 start_addr = (unsigned long)lcd_base_addr;
Donghwa Leef78095e2012-04-23 15:37:05 +0000125 end_addr = start_addr + ((pvid->vl_col * (NBITS(pvid->vl_bpix) / 8)) *
Donghwa Lee6d4339f2012-04-05 19:36:17 +0000126 pvid->vl_row);
127
128 writel(start_addr, (unsigned int)&fimd_ctrl->vidw00add0b0 +
129 EXYNOS_BUFFER_OFFSET(win_id));
130 writel(end_addr, (unsigned int)&fimd_ctrl->vidw00add1b0 +
131 EXYNOS_BUFFER_OFFSET(win_id));
132}
133
134static void exynos_fimd_set_clock(vidinfo_t *pvid)
135{
136 unsigned int cfg = 0, div = 0, remainder, remainder_div;
137 unsigned long pixel_clock;
138 unsigned long long src_clock;
Donghwa Lee6d4339f2012-04-05 19:36:17 +0000139
140 if (pvid->dual_lcd_enabled) {
141 pixel_clock = pvid->vl_freq *
142 (pvid->vl_hspw + pvid->vl_hfpd +
143 pvid->vl_hbpd + pvid->vl_col / 2) *
144 (pvid->vl_vspw + pvid->vl_vfpd +
145 pvid->vl_vbpd + pvid->vl_row);
146 } else if (pvid->interface_mode == FIMD_CPU_INTERFACE) {
147 pixel_clock = pvid->vl_freq *
148 pvid->vl_width * pvid->vl_height *
149 (pvid->cs_setup + pvid->wr_setup +
150 pvid->wr_act + pvid->wr_hold + 1);
151 } else {
152 pixel_clock = pvid->vl_freq *
153 (pvid->vl_hspw + pvid->vl_hfpd +
154 pvid->vl_hbpd + pvid->vl_col) *
155 (pvid->vl_vspw + pvid->vl_vfpd +
156 pvid->vl_vbpd + pvid->vl_row);
157 }
158
159 cfg = readl(&fimd_ctrl->vidcon0);
160 cfg &= ~(EXYNOS_VIDCON0_CLKSEL_MASK | EXYNOS_VIDCON0_CLKVALUP_MASK |
161 EXYNOS_VIDCON0_CLKVAL_F(0xFF) | EXYNOS_VIDCON0_VCLKEN_MASK |
162 EXYNOS_VIDCON0_CLKDIR_MASK);
163 cfg |= (EXYNOS_VIDCON0_CLKSEL_SCLK | EXYNOS_VIDCON0_CLKVALUP_ALWAYS |
164 EXYNOS_VIDCON0_VCLKEN_NORMAL | EXYNOS_VIDCON0_CLKDIR_DIVIDED);
165
Donghwa Lee6d4339f2012-04-05 19:36:17 +0000166 src_clock = (unsigned long long) get_lcd_clk();
167
168 /* get quotient and remainder. */
169 remainder = do_div(src_clock, pixel_clock);
170 div = src_clock;
171
172 remainder *= 10;
173 remainder_div = remainder / pixel_clock;
174
175 /* round about one places of decimals. */
176 if (remainder_div >= 5)
177 div++;
178
179 /* in case of dual lcd mode. */
180 if (pvid->dual_lcd_enabled)
181 div--;
182
183 cfg |= EXYNOS_VIDCON0_CLKVAL_F(div - 1);
184 writel(cfg, &fimd_ctrl->vidcon0);
185}
186
187void exynos_set_trigger(void)
188{
189 unsigned int cfg = 0;
Donghwa Lee6d4339f2012-04-05 19:36:17 +0000190
191 cfg = readl(&fimd_ctrl->trigcon);
192
193 cfg |= (EXYNOS_I80SOFT_TRIG_EN | EXYNOS_I80START_TRIG);
194
195 writel(cfg, &fimd_ctrl->trigcon);
196}
197
198int exynos_is_i80_frame_done(void)
199{
200 unsigned int cfg = 0;
201 int status;
Donghwa Lee6d4339f2012-04-05 19:36:17 +0000202
203 cfg = readl(&fimd_ctrl->trigcon);
204
205 /* frame done func is valid only when TRIMODE[0] is set to 1. */
206 status = (cfg & EXYNOS_I80STATUS_TRIG_DONE) ==
207 EXYNOS_I80STATUS_TRIG_DONE;
208
209 return status;
210}
211
212static void exynos_fimd_lcd_on(void)
213{
214 unsigned int cfg = 0;
Donghwa Lee6d4339f2012-04-05 19:36:17 +0000215
216 /* display on */
217 cfg = readl(&fimd_ctrl->vidcon0);
218 cfg |= (EXYNOS_VIDCON0_ENVID_ENABLE | EXYNOS_VIDCON0_ENVID_F_ENABLE);
219 writel(cfg, &fimd_ctrl->vidcon0);
220}
221
222static void exynos_fimd_window_on(unsigned int win_id)
223{
224 unsigned int cfg = 0;
Donghwa Lee6d4339f2012-04-05 19:36:17 +0000225
226 /* enable window */
227 cfg = readl((unsigned int)&fimd_ctrl->wincon0 +
228 EXYNOS_WINCON(win_id));
229 cfg |= EXYNOS_WINCON_ENWIN_ENABLE;
230 writel(cfg, (unsigned int)&fimd_ctrl->wincon0 +
231 EXYNOS_WINCON(win_id));
232
233 cfg = readl(&fimd_ctrl->winshmap);
234 cfg |= EXYNOS_WINSHMAP_CH_ENABLE(win_id);
235 writel(cfg, &fimd_ctrl->winshmap);
236}
237
238void exynos_fimd_lcd_off(void)
239{
240 unsigned int cfg = 0;
Donghwa Lee6d4339f2012-04-05 19:36:17 +0000241
242 cfg = readl(&fimd_ctrl->vidcon0);
243 cfg &= (EXYNOS_VIDCON0_ENVID_DISABLE | EXYNOS_VIDCON0_ENVID_F_DISABLE);
244 writel(cfg, &fimd_ctrl->vidcon0);
245}
246
247void exynos_fimd_window_off(unsigned int win_id)
248{
249 unsigned int cfg = 0;
Donghwa Lee6d4339f2012-04-05 19:36:17 +0000250
251 cfg = readl((unsigned int)&fimd_ctrl->wincon0 +
252 EXYNOS_WINCON(win_id));
253 cfg &= EXYNOS_WINCON_ENWIN_DISABLE;
254 writel(cfg, (unsigned int)&fimd_ctrl->wincon0 +
255 EXYNOS_WINCON(win_id));
256
257 cfg = readl(&fimd_ctrl->winshmap);
258 cfg &= ~EXYNOS_WINSHMAP_CH_DISABLE(win_id);
259 writel(cfg, &fimd_ctrl->winshmap);
260}
261
Donghwa Leeee93dcf2012-07-26 15:30:49 +0000262
Donghwa Lee6d4339f2012-04-05 19:36:17 +0000263void exynos_fimd_lcd_init(vidinfo_t *vid)
264{
265 unsigned int cfg = 0, rgb_mode;
Donghwa Leeee93dcf2012-07-26 15:30:49 +0000266 unsigned int offset;
Ajay Kumar47ff6072013-02-21 23:52:59 +0000267 fimd_ctrl = (struct exynos_fb *)samsung_get_base_fimd();
Donghwa Leeee93dcf2012-07-26 15:30:49 +0000268
269 offset = exynos_fimd_get_base_offset();
Donghwa Lee6d4339f2012-04-05 19:36:17 +0000270
271 /* store panel info to global variable */
272 pvid = vid;
273
Donghwa Lee90464972012-05-09 19:23:46 +0000274 rgb_mode = vid->rgb_mode;
Donghwa Lee6d4339f2012-04-05 19:36:17 +0000275
276 if (vid->interface_mode == FIMD_RGB_INTERFACE) {
277 cfg |= EXYNOS_VIDCON0_VIDOUT_RGB;
278 writel(cfg, &fimd_ctrl->vidcon0);
279
280 cfg = readl(&fimd_ctrl->vidcon2);
281 cfg &= ~(EXYNOS_VIDCON2_WB_MASK |
282 EXYNOS_VIDCON2_TVFORMATSEL_MASK |
283 EXYNOS_VIDCON2_TVFORMATSEL_YUV_MASK);
284 cfg |= EXYNOS_VIDCON2_WB_DISABLE;
285 writel(cfg, &fimd_ctrl->vidcon2);
286
287 /* set polarity */
288 cfg = 0;
289 if (!pvid->vl_clkp)
290 cfg |= EXYNOS_VIDCON1_IVCLK_RISING_EDGE;
291 if (!pvid->vl_hsp)
292 cfg |= EXYNOS_VIDCON1_IHSYNC_INVERT;
293 if (!pvid->vl_vsp)
294 cfg |= EXYNOS_VIDCON1_IVSYNC_INVERT;
295 if (!pvid->vl_dp)
296 cfg |= EXYNOS_VIDCON1_IVDEN_INVERT;
297
Donghwa Leeee93dcf2012-07-26 15:30:49 +0000298 writel(cfg, (unsigned int)&fimd_ctrl->vidcon1 + offset);
Donghwa Lee6d4339f2012-04-05 19:36:17 +0000299
300 /* set timing */
301 cfg = EXYNOS_VIDTCON0_VFPD(pvid->vl_vfpd - 1);
302 cfg |= EXYNOS_VIDTCON0_VBPD(pvid->vl_vbpd - 1);
303 cfg |= EXYNOS_VIDTCON0_VSPW(pvid->vl_vspw - 1);
Donghwa Leeee93dcf2012-07-26 15:30:49 +0000304 writel(cfg, (unsigned int)&fimd_ctrl->vidtcon0 + offset);
Donghwa Lee6d4339f2012-04-05 19:36:17 +0000305
306 cfg = EXYNOS_VIDTCON1_HFPD(pvid->vl_hfpd - 1);
307 cfg |= EXYNOS_VIDTCON1_HBPD(pvid->vl_hbpd - 1);
308 cfg |= EXYNOS_VIDTCON1_HSPW(pvid->vl_hspw - 1);
309
Donghwa Leeee93dcf2012-07-26 15:30:49 +0000310 writel(cfg, (unsigned int)&fimd_ctrl->vidtcon1 + offset);
Donghwa Lee6d4339f2012-04-05 19:36:17 +0000311
312 /* set lcd size */
Donghwa Leeee93dcf2012-07-26 15:30:49 +0000313 cfg = EXYNOS_VIDTCON2_HOZVAL(pvid->vl_col - 1) |
314 EXYNOS_VIDTCON2_LINEVAL(pvid->vl_row - 1) |
315 EXYNOS_VIDTCON2_HOZVAL_E(pvid->vl_col - 1) |
316 EXYNOS_VIDTCON2_LINEVAL_E(pvid->vl_row - 1);
Donghwa Lee6d4339f2012-04-05 19:36:17 +0000317
Donghwa Leeee93dcf2012-07-26 15:30:49 +0000318 writel(cfg, (unsigned int)&fimd_ctrl->vidtcon2 + offset);
Donghwa Lee6d4339f2012-04-05 19:36:17 +0000319 }
320
321 /* set display mode */
322 cfg = readl(&fimd_ctrl->vidcon0);
323 cfg &= ~EXYNOS_VIDCON0_PNRMODE_MASK;
324 cfg |= (rgb_mode << EXYNOS_VIDCON0_PNRMODE_SHIFT);
325 writel(cfg, &fimd_ctrl->vidcon0);
326
327 /* set par */
328 exynos_fimd_set_par(pvid->win_id);
329
330 /* set memory address */
331 exynos_fimd_set_buffer_address(pvid->win_id);
332
333 /* set buffer size */
Donghwa Leeee93dcf2012-07-26 15:30:49 +0000334 cfg = EXYNOS_VIDADDR_PAGEWIDTH(pvid->vl_col * NBITS(pvid->vl_bpix) / 8) |
335 EXYNOS_VIDADDR_PAGEWIDTH_E(pvid->vl_col * NBITS(pvid->vl_bpix) / 8) |
336 EXYNOS_VIDADDR_OFFSIZE(0) |
337 EXYNOS_VIDADDR_OFFSIZE_E(0);
338
Donghwa Lee6d4339f2012-04-05 19:36:17 +0000339 writel(cfg, (unsigned int)&fimd_ctrl->vidw00add2 +
340 EXYNOS_BUFFER_SIZE(pvid->win_id));
341
342 /* set clock */
343 exynos_fimd_set_clock(pvid);
344
345 /* set rgb mode to dual lcd. */
346 exynos_fimd_set_dualrgb(pvid->dual_lcd_enabled);
347
348 /* display on */
349 exynos_fimd_lcd_on();
350
351 /* window on */
352 exynos_fimd_window_on(pvid->win_id);
Donghwa Leea29c8322012-07-02 01:16:08 +0000353
354 exynos_fimd_set_dp_clkcon(pvid->dp_enabled);
Donghwa Lee6d4339f2012-04-05 19:36:17 +0000355}
356
357unsigned long exynos_fimd_calc_fbsize(void)
358{
Donghwa Leef78095e2012-04-23 15:37:05 +0000359 return pvid->vl_col * pvid->vl_row * (NBITS(pvid->vl_bpix) / 8);
Donghwa Lee6d4339f2012-04-05 19:36:17 +0000360}