Initial commit
[kernel/linux-3.0.git] / drivers / video / samsung / s3cfb_fimd6x.c
1 /* linux/drivers/video/samsung/s3cfb_fimd6x.c
2  *
3  * Copyright (c) 2010 Samsung Electronics Co., Ltd.
4  *              http://www.samsung.com/
5  *
6  * Register interface file for Samsung Display Controller (FIMD) driver
7  *
8  * This program is free software; you can redistribute it and/or modify
9  * it under the terms of the GNU General Public License version 2 as
10  * published by the Free Software Foundation.
11 */
12
13 #include <linux/delay.h>
14 #include <linux/device.h>
15 #include <linux/fb.h>
16 #include <linux/io.h>
17 #include <linux/clk.h>
18 #include <mach/map.h>
19 #include <plat/clock.h>
20 #include <plat/fb-s5p.h>
21 #include <plat/regs-fb-s5p.h>
22
23 #include "s3cfb.h"
24
25 void s3cfb_check_line_count(struct s3cfb_global *ctrl)
26 {
27         int timeout = 30 * 5300;
28         int i = 0;
29
30         do {
31                 if (!(readl(ctrl->regs + S3C_VIDCON1) & 0x7ff0000))
32                         break;
33                 i++;
34         } while (i < timeout);
35
36         if (i == timeout) {
37                 dev_err(ctrl->dev, "line count mismatch\n");
38                 s3cfb_display_on(ctrl);
39         }
40 }
41
42 int s3cfb_check_vsync_status(struct s3cfb_global *ctrl)
43 {
44         u32 cfg;
45
46         if (unlikely(!ctrl->regs)) {
47                 dev_err(ctrl->dev, "reg is zero\n");
48                 return 0;
49         }
50
51         cfg = (readl(ctrl->regs + S3C_VIDCON1) & S3C_VIDCON1_VSTATUS_MASK);
52
53         if (cfg != S3C_VIDCON1_VSTATUS_ACTIVE && cfg != S3C_VIDCON1_VSTATUS_BACK)
54                 return 1;
55         else
56                 return 0;
57 }
58
59 int s3cfb_set_output(struct s3cfb_global *ctrl)
60 {
61         u32 cfg;
62
63         cfg = readl(ctrl->regs + S3C_VIDCON0);
64         cfg &= ~S3C_VIDCON0_VIDOUT_MASK;
65
66         if (ctrl->output == OUTPUT_RGB)
67                 cfg |= S3C_VIDCON0_VIDOUT_RGB;
68         else if (ctrl->output == OUTPUT_ITU)
69                 cfg |= S3C_VIDCON0_VIDOUT_ITU;
70         else if (ctrl->output == OUTPUT_I80LDI0) {
71                 cfg |= S3C_VIDCON0_VIDOUT_I80LDI0;
72                 cfg |= S3C_VIDCON0_DSI_ENABLE;
73         } else if (ctrl->output == OUTPUT_I80LDI1)
74                 cfg |= S3C_VIDCON0_VIDOUT_I80LDI1;
75         else if (ctrl->output == OUTPUT_WB_RGB)
76                 cfg |= S3C_VIDCON0_VIDOUT_WB_RGB;
77         else if (ctrl->output == OUTPUT_WB_I80LDI0)
78                 cfg |= S3C_VIDCON0_VIDOUT_WB_I80LDI0;
79         else if (ctrl->output == OUTPUT_WB_I80LDI1)
80                 cfg |= S3C_VIDCON0_VIDOUT_WB_I80LDI1;
81         else {
82                 dev_err(ctrl->dev, "invalid output type: %d\n", ctrl->output);
83                 return -EINVAL;
84         }
85
86         writel(cfg, ctrl->regs + S3C_VIDCON0);
87
88         cfg = readl(ctrl->regs + S3C_VIDCON2);
89         cfg &= ~(S3C_VIDCON2_WB_MASK | S3C_VIDCON2_TVFORMATSEL_MASK | \
90                                         S3C_VIDCON2_TVFORMATSEL_YUV_MASK);
91
92         if (ctrl->output == OUTPUT_RGB)
93                 cfg |= S3C_VIDCON2_WB_DISABLE;
94         else if (ctrl->output == OUTPUT_ITU)
95                 cfg |= S3C_VIDCON2_WB_DISABLE;
96         else if (ctrl->output == OUTPUT_I80LDI0)
97                 cfg |= S3C_VIDCON2_WB_DISABLE;
98         else if (ctrl->output == OUTPUT_I80LDI1)
99                 cfg |= S3C_VIDCON2_WB_DISABLE;
100         else if (ctrl->output == OUTPUT_WB_RGB)
101                 cfg |= (S3C_VIDCON2_WB_ENABLE | S3C_VIDCON2_TVFORMATSEL_SW | \
102                                         S3C_VIDCON2_TVFORMATSEL_YUV444);
103         else if (ctrl->output == OUTPUT_WB_I80LDI0)
104                 cfg |= (S3C_VIDCON2_WB_ENABLE | S3C_VIDCON2_TVFORMATSEL_SW | \
105                                         S3C_VIDCON2_TVFORMATSEL_YUV444);
106         else if (ctrl->output == OUTPUT_WB_I80LDI1)
107                 cfg |= (S3C_VIDCON2_WB_ENABLE | S3C_VIDCON2_TVFORMATSEL_SW | \
108                                         S3C_VIDCON2_TVFORMATSEL_YUV444);
109         else {
110                 dev_err(ctrl->dev, "invalid output type: %d\n", ctrl->output);
111                 return -EINVAL;
112         }
113
114         writel(cfg, ctrl->regs + S3C_VIDCON2);
115
116         if (ctrl->output == OUTPUT_I80LDI0) {
117                 cfg = readl(ctrl->regs + S3C_I80IFCONA0);
118                 cfg |= ((1<<0)|(1<<8));
119                 writel(cfg, ctrl->regs + S3C_I80IFCONA0);
120         }
121
122         return 0;
123 }
124
125 #ifdef CONFIG_FB_S5P_MIPI_DSIM
126 void s3cfb_set_trigger(struct s3cfb_global *ctrl)
127 {
128         u32 reg = 0;
129
130         reg = readl(ctrl->regs + S3C_TRIGCON);
131
132         reg |= 1 << 0 | 1 << 1;
133
134         writel(reg, ctrl->regs + S3C_TRIGCON);
135 }
136 #endif
137
138 int s3cfb_set_display_mode(struct s3cfb_global *ctrl)
139 {
140         u32 cfg;
141
142         cfg = readl(ctrl->regs + S3C_VIDCON0);
143         cfg &= ~S3C_VIDCON0_PNRMODE_MASK;
144         cfg |= (ctrl->rgb_mode << S3C_VIDCON0_PNRMODE_SHIFT);
145         writel(cfg, ctrl->regs + S3C_VIDCON0);
146
147         return 0;
148 }
149
150 int s3cfb_display_on(struct s3cfb_global *ctrl)
151 {
152         u32 cfg;
153
154         cfg = readl(ctrl->regs + S3C_VIDCON0);
155         cfg |= (S3C_VIDCON0_ENVID_ENABLE | S3C_VIDCON0_ENVID_F_ENABLE);
156         writel(cfg, ctrl->regs + S3C_VIDCON0);
157
158         dev_dbg(ctrl->dev, "global display is on\n");
159
160         return 0;
161 }
162
163 int s3cfb_display_off(struct s3cfb_global *ctrl)
164 {
165         u32 cfg, fimd_count = 0;
166
167         cfg = readl(ctrl->regs + S3C_VIDCON0);
168         cfg |= S3C_VIDCON0_ENVID_ENABLE;
169         cfg &= ~S3C_VIDCON0_ENVID_F_ENABLE;
170
171         writel(cfg, ctrl->regs + S3C_VIDCON0);
172
173         do {
174                 if (++fimd_count > 2000000) {
175                         dev_err(ctrl->dev, "FIMD off fail\n");
176                         return 1;
177                 }
178                 if (!(readl(ctrl->regs + S3C_VIDCON0) & 0x1))
179                         return 0;
180         } while (1);
181 }
182
183 int s3cfb_frame_off(struct s3cfb_global *ctrl)
184 {
185         u32 cfg;
186
187         cfg = readl(ctrl->regs + S3C_VIDCON0);
188         cfg &= ~S3C_VIDCON0_ENVID_F_ENABLE;
189         writel(cfg, ctrl->regs + S3C_VIDCON0);
190
191         dev_dbg(ctrl->dev, "current frame display is off\n");
192
193         return 0;
194 }
195
196 int s3cfb_set_clock(struct s3cfb_global *ctrl)
197 {
198         struct s3c_platform_fb *pdata = to_fb_plat(ctrl->dev);
199         u32 cfg, maxclk, src_clk, vclk, div;
200
201         /* spec is under 100MHz */
202         maxclk = 100 * 1000000;
203
204         cfg = readl(ctrl->regs + S3C_VIDCON0);
205
206         if (pdata->hw_ver == 0x70) {
207                 cfg &= ~(S3C_VIDCON0_CLKVALUP_MASK |
208                         S3C_VIDCON0_VCLKEN_MASK);
209                 cfg |= (S3C_VIDCON0_CLKVALUP_ALWAYS |
210                         S3C_VIDCON0_VCLKEN_FREERUN);
211
212                 src_clk = clk_get_rate(ctrl->clock);
213                 printk(KERN_DEBUG "FIMD src sclk = %d\n", src_clk);
214         } else {
215                 cfg &= ~(S3C_VIDCON0_CLKSEL_MASK |
216                         S3C_VIDCON0_CLKVALUP_MASK |
217                         S3C_VIDCON0_VCLKEN_MASK |
218                         S3C_VIDCON0_CLKDIR_MASK);
219                 cfg |= (S3C_VIDCON0_CLKVALUP_ALWAYS |
220                         S3C_VIDCON0_VCLKEN_NORMAL |
221                         S3C_VIDCON0_CLKDIR_DIVIDED);
222
223                 if (strcmp(pdata->clk_name, "sclk_fimd") == 0) {
224                         cfg |= S3C_VIDCON0_CLKSEL_SCLK;
225                         src_clk = clk_get_rate(ctrl->clock);
226                         printk(KERN_DEBUG "FIMD src sclk = %d\n", src_clk);
227
228                 } else {
229                         cfg |= S3C_VIDCON0_CLKSEL_HCLK;
230                         src_clk = ctrl->clock->parent->rate;
231                         printk(KERN_DEBUG "FIMD src hclk = %d\n", src_clk);
232                 }
233         }
234
235         vclk = PICOS2KHZ(ctrl->fb[pdata->default_win]->var.pixclock) * 1000;
236
237         if (vclk > maxclk) {
238                 dev_info(ctrl->dev, "vclk(%d) should be smaller than %d\n",
239                         vclk, maxclk);
240                 /* vclk = maxclk; */
241         }
242
243         div = DIV_ROUND_CLOSEST(src_clk, vclk);
244
245         if (div == 0) {
246                 dev_err(ctrl->dev, "div(%d) should be non-zero\n", div);
247                 div = 1;
248         }
249
250         if ((src_clk/div) > maxclk)
251                 dev_info(ctrl->dev, "vclk(%d) should be smaller than %d Hz\n",
252                         src_clk/div, maxclk);
253
254         cfg &= ~S3C_VIDCON0_CLKVAL_F(0xff);
255         cfg |= S3C_VIDCON0_CLKVAL_F(div - 1);
256         writel(cfg, ctrl->regs + S3C_VIDCON0);
257
258         dev_info(ctrl->dev, "parent clock: %d, vclk: %d, vclk div: %d\n",
259                         src_clk, vclk, div);
260
261         return 0;
262 }
263
264 int s3cfb_set_polarity(struct s3cfb_global *ctrl)
265 {
266         struct s3cfb_lcd_polarity *pol;
267         u32 cfg;
268
269         pol = &ctrl->lcd->polarity;
270         cfg = 0;
271
272         /* Set VCLK hold scheme */
273         cfg &= S3C_VIDCON1_FIXVCLK_MASK;
274         cfg |= S3C_VIDCON1_FIXVCLK_VCLK_RUN_VDEN_DIS;
275
276         if (pol->rise_vclk)
277                 cfg |= S3C_VIDCON1_IVCLK_RISING_EDGE;
278
279         if (pol->inv_hsync)
280                 cfg |= S3C_VIDCON1_IHSYNC_INVERT;
281
282         if (pol->inv_vsync)
283                 cfg |= S3C_VIDCON1_IVSYNC_INVERT;
284
285         if (pol->inv_vden)
286                 cfg |= S3C_VIDCON1_IVDEN_INVERT;
287
288         writel(cfg, ctrl->regs + S3C_VIDCON1);
289
290         return 0;
291 }
292
293 int s3cfb_set_polarity_only(struct s3cfb_global *ctrl)
294 {
295         struct s3cfb_lcd_polarity *pol;
296         u32 cfg = 0;
297
298         pol = &ctrl->lcd->polarity;
299
300         if (pol->rise_vclk)
301                 cfg |= S3C_VIDCON1_IVCLK_RISING_EDGE;
302
303         if (pol->inv_hsync)
304                 cfg |= S3C_VIDCON1_IHSYNC_INVERT;
305
306         if (pol->inv_vsync)
307                 cfg |= S3C_VIDCON1_IVSYNC_INVERT;
308
309         if (pol->inv_vden)
310                 cfg |= S3C_VIDCON1_IVDEN_INVERT;
311
312         writel(cfg, ctrl->regs + S3C_VIDCON1);
313
314         return 0;
315 }
316
317 int s3cfb_set_timing(struct s3cfb_global *ctrl)
318 {
319         struct s3cfb_lcd_timing *time;
320         u32 cfg;
321
322         time = &ctrl->lcd->timing;
323         cfg = 0;
324
325         cfg |= S3C_VIDTCON0_VBPDE(time->v_bpe - 1);
326         cfg |= S3C_VIDTCON0_VBPD(time->v_bp - 1);
327         cfg |= S3C_VIDTCON0_VFPD(time->v_fp - 1);
328         cfg |= S3C_VIDTCON0_VSPW(time->v_sw - 1);
329
330         writel(cfg, ctrl->regs + S3C_VIDTCON0);
331
332         cfg = 0;
333
334         cfg |= S3C_VIDTCON1_VFPDE(time->v_fpe - 1);
335         cfg |= S3C_VIDTCON1_HBPD(time->h_bp - 1);
336         cfg |= S3C_VIDTCON1_HFPD(time->h_fp - 1);
337         cfg |= S3C_VIDTCON1_HSPW(time->h_sw - 1);
338
339         writel(cfg, ctrl->regs + S3C_VIDTCON1);
340
341         return 0;
342 }
343
344 int s3cfb_set_lcd_size(struct s3cfb_global *ctrl)
345 {
346         u32 cfg = 0;
347
348 #ifdef CONFIG_FB_S5P_WA101S
349         cfg |= S3C_VIDTCON2_HOZVAL(ctrl->lcd->width - 1 + 6);
350 #else
351         cfg |= S3C_VIDTCON2_HOZVAL(ctrl->lcd->width - 1);
352 #endif
353
354         cfg |= S3C_VIDTCON2_LINEVAL(ctrl->lcd->height - 1);
355
356         writel(cfg, ctrl->regs + S3C_VIDTCON2);
357
358         return 0;
359 }
360
361 int s3cfb_set_global_interrupt(struct s3cfb_global *ctrl, int enable)
362 {
363         u32 cfg = 0;
364
365         cfg = readl(ctrl->regs + S3C_VIDINTCON0);
366         cfg &= ~(S3C_VIDINTCON0_INTFRMEN_ENABLE | S3C_VIDINTCON0_INT_ENABLE);
367
368         if (enable) {
369                 dev_dbg(ctrl->dev, "video interrupt is on\n");
370                 cfg |= (S3C_VIDINTCON0_INTFRMEN_ENABLE |
371                         S3C_VIDINTCON0_INT_ENABLE);
372         } else {
373                 dev_dbg(ctrl->dev, "video interrupt is off\n");
374                 cfg |= (S3C_VIDINTCON0_INTFRMEN_DISABLE |
375                         S3C_VIDINTCON0_INT_DISABLE);
376         }
377
378         writel(cfg, ctrl->regs + S3C_VIDINTCON0);
379
380         return 0;
381 }
382
383 int s3cfb_set_vsync_interrupt(struct s3cfb_global *ctrl, int enable)
384 {
385         u32 cfg = 0;
386
387         cfg = readl(ctrl->regs + S3C_VIDINTCON0);
388         cfg &= ~S3C_VIDINTCON0_FRAMESEL0_MASK;
389
390         if (enable) {
391                 dev_dbg(ctrl->dev, "vsync interrupt is on\n");
392                 cfg |= S3C_VIDINTCON0_FRAMESEL0_VSYNC;
393         } else {
394                 dev_dbg(ctrl->dev, "vsync interrupt is off\n");
395                 cfg &= ~S3C_VIDINTCON0_FRAMESEL0_VSYNC;
396         }
397
398         writel(cfg, ctrl->regs + S3C_VIDINTCON0);
399
400         return 0;
401 }
402
403 int s3cfb_get_vsync_interrupt(struct s3cfb_global *ctrl)
404 {
405         u32 cfg = 0;
406
407         cfg = readl(ctrl->regs + S3C_VIDINTCON0);
408         cfg &= S3C_VIDINTCON0_FRAMESEL0_VSYNC;
409
410         if (cfg & S3C_VIDINTCON0_FRAMESEL0_VSYNC) {
411                 dev_dbg(ctrl->dev, "vsync interrupt is on\n");
412                 return 1;
413         } else {
414                 dev_dbg(ctrl->dev, "vsync interrupt is off\n");
415                 return 0;
416         }
417 }
418
419
420 #ifdef CONFIG_FB_S5P_TRACE_UNDERRUN
421 int s3cfb_set_fifo_interrupt(struct s3cfb_global *ctrl, int enable)
422 {
423         u32 cfg = 0;
424
425         cfg = readl(ctrl->regs + S3C_VIDINTCON0);
426
427         cfg &= ~(S3C_VIDINTCON0_FIFOSEL_MASK | S3C_VIDINTCON0_FIFOLEVEL_MASK);
428         cfg |= (S3C_VIDINTCON0_FIFOSEL_ALL | S3C_VIDINTCON0_FIFOLEVEL_EMPTY);
429
430         if (enable) {
431                 dev_dbg(ctrl->dev, "fifo interrupt is on\n");
432                 cfg |= (S3C_VIDINTCON0_INTFIFO_ENABLE |
433                         S3C_VIDINTCON0_INT_ENABLE);
434         } else {
435                 dev_dbg(ctrl->dev, "fifo interrupt is off\n");
436                 cfg &= ~(S3C_VIDINTCON0_INTFIFO_ENABLE |
437                         S3C_VIDINTCON0_INT_ENABLE);
438         }
439
440         writel(cfg, ctrl->regs + S3C_VIDINTCON0);
441
442         return 0;
443 }
444 #endif
445
446 int s3cfb_clear_interrupt(struct s3cfb_global *ctrl)
447 {
448         u32 cfg = 0;
449
450         cfg = readl(ctrl->regs + S3C_VIDINTCON1);
451
452         if (cfg & S3C_VIDINTCON1_INTFIFOPEND)
453                 dev_info(ctrl->dev, "fifo underrun occur\n");
454
455         cfg |= (S3C_VIDINTCON1_INTVPPEND | S3C_VIDINTCON1_INTI80PEND |
456                 S3C_VIDINTCON1_INTFRMPEND | S3C_VIDINTCON1_INTFIFOPEND);
457
458         writel(cfg, ctrl->regs + S3C_VIDINTCON1);
459
460         return 0;
461 }
462
463 int s3cfb_channel_localpath_on(struct s3cfb_global *ctrl, int id)
464 {
465         struct s3c_platform_fb *pdata = to_fb_plat(ctrl->dev);
466         u32 cfg;
467
468         if ((pdata->hw_ver == 0x62) || (pdata->hw_ver == 0x70)) {
469                 cfg = readl(ctrl->regs + S3C_WINSHMAP);
470                 cfg |= S3C_WINSHMAP_LOCAL_ENABLE(id);
471                 writel(cfg, ctrl->regs + S3C_WINSHMAP);
472         }
473
474         dev_dbg(ctrl->dev, "[fb%d] local path enabled\n", id);
475
476         return 0;
477 }
478
479 int s3cfb_channel_localpath_off(struct s3cfb_global *ctrl, int id)
480 {
481         struct s3c_platform_fb *pdata = to_fb_plat(ctrl->dev);
482         u32 cfg;
483
484         if ((pdata->hw_ver == 0x62) || (pdata->hw_ver == 0x70)) {
485                 cfg = readl(ctrl->regs + S3C_WINSHMAP);
486                 cfg &= ~S3C_WINSHMAP_LOCAL_DISABLE(id);
487                 writel(cfg, ctrl->regs + S3C_WINSHMAP);
488         }
489
490         dev_dbg(ctrl->dev, "[fb%d] local path disabled\n", id);
491
492         return 0;
493 }
494
495 int s3cfb_window_on(struct s3cfb_global *ctrl, int id)
496 {
497         struct s3c_platform_fb *pdata = to_fb_plat(ctrl->dev);
498         u32 cfg;
499
500         if ((pdata->hw_ver == 0x62) || (pdata->hw_ver == 0x70)) {
501                 cfg = readl(ctrl->regs + S3C_WINSHMAP);
502                 cfg |= S3C_WINSHMAP_CH_ENABLE(id);
503                 writel(cfg, ctrl->regs + S3C_WINSHMAP);
504         }
505
506         cfg = readl(ctrl->regs + S3C_WINCON(id));
507         cfg |= S3C_WINCON_ENWIN_ENABLE;
508         writel(cfg, ctrl->regs + S3C_WINCON(id));
509
510         dev_dbg(ctrl->dev, "[fb%d] turn on\n", id);
511
512         return 0;
513 }
514
515 int s3cfb_window_off(struct s3cfb_global *ctrl, int id)
516 {
517         struct s3c_platform_fb *pdata = to_fb_plat(ctrl->dev);
518         u32 cfg;
519
520         cfg = readl(ctrl->regs + S3C_WINCON(id));
521         cfg &= ~(S3C_WINCON_ENWIN_ENABLE | S3C_WINCON_DATAPATH_MASK);
522         cfg |= S3C_WINCON_DATAPATH_DMA;
523         writel(cfg, ctrl->regs + S3C_WINCON(id));
524
525         if ((pdata->hw_ver == 0x62) || (pdata->hw_ver == 0x70)) {
526                 cfg = readl(ctrl->regs + S3C_WINSHMAP);
527                 cfg &= ~S3C_WINSHMAP_CH_DISABLE(id);
528                 writel(cfg, ctrl->regs + S3C_WINSHMAP);
529         }
530
531         dev_dbg(ctrl->dev, "[fb%d] turn off\n", id);
532
533         return 0;
534 }
535
536 int s3cfb_win_map_on(struct s3cfb_global *ctrl, int id, int color)
537 {
538         u32 cfg = 0;
539
540         cfg |= S3C_WINMAP_ENABLE;
541         cfg |= S3C_WINMAP_COLOR(color);
542         writel(cfg, ctrl->regs + S3C_WINMAP(id));
543
544         dev_dbg(ctrl->dev, "[fb%d] win map on : 0x%08x\n", id, color);
545
546         return 0;
547 }
548
549 int s3cfb_win_map_off(struct s3cfb_global *ctrl, int id)
550 {
551         writel(0, ctrl->regs + S3C_WINMAP(id));
552
553         dev_dbg(ctrl->dev, "[fb%d] win map off\n", id);
554
555         return 0;
556 }
557
558 int s3cfb_set_window_control(struct s3cfb_global *ctrl, int id)
559 {
560         struct s3c_platform_fb *pdata = to_fb_plat(ctrl->dev);
561         struct fb_info *fb = ctrl->fb[id];
562         struct fb_var_screeninfo *var = &fb->var;
563         struct s3cfb_window *win = fb->par;
564         u32 cfg;
565         u32 shw;
566
567         if ((pdata->hw_ver == 0x62) || (pdata->hw_ver == 0x70)) {
568                 shw = readl(ctrl->regs + S3C_WINSHMAP);
569                 shw |= S3C_WINSHMAP_PROTECT(id);
570                 writel(shw, ctrl->regs + S3C_WINSHMAP);
571         }
572
573         cfg = readl(ctrl->regs + S3C_WINCON(id));
574
575         cfg &= ~(S3C_WINCON_BITSWP_ENABLE | S3C_WINCON_BYTESWP_ENABLE |
576                 S3C_WINCON_HAWSWP_ENABLE | S3C_WINCON_WSWP_ENABLE |
577                 S3C_WINCON_BURSTLEN_MASK | S3C_WINCON_BPPMODE_MASK |
578                 S3C_WINCON_INRGB_MASK | S3C_WINCON_DATAPATH_MASK);
579
580         if (win->path != DATA_PATH_DMA) {
581                 dev_dbg(ctrl->dev, "[fb%d] data path: fifo\n", id);
582
583                 cfg |= S3C_WINCON_DATAPATH_LOCAL;
584
585                 if (win->path == DATA_PATH_FIFO) {
586                         cfg |= S3C_WINCON_INRGB_RGB;
587                         cfg |= S3C_WINCON_BPPMODE_24BPP_888;
588                 } else if (win->path == DATA_PATH_IPC) {
589                         cfg |= S3C_WINCON_INRGB_YUV;
590                         cfg |= S3C_WINCON_BPPMODE_24BPP_888;
591                 }
592
593                 if (id == 1) {
594                         cfg &= ~(S3C_WINCON1_LOCALSEL_MASK |
595                                 S3C_WINCON1_VP_ENABLE);
596
597                         if (win->local_channel == 0) {
598                                 cfg |= S3C_WINCON1_LOCALSEL_FIMC1;
599                         } else {
600                                 cfg |= (S3C_WINCON1_LOCALSEL_VP |
601                                         S3C_WINCON1_VP_ENABLE);
602                         }
603                 }
604         } else {
605                 dev_dbg(ctrl->dev, "[fb%d] data path: dma\n", id);
606
607                 cfg |= S3C_WINCON_DATAPATH_DMA;
608
609                 if (fb->var.bits_per_pixel == 16 && pdata->swap & FB_SWAP_HWORD)
610                         cfg |= S3C_WINCON_HAWSWP_ENABLE;
611
612                 if (fb->var.bits_per_pixel == 32 && pdata->swap & FB_SWAP_WORD)
613                         cfg |= S3C_WINCON_WSWP_ENABLE;
614
615                 /* dma burst */
616                 if (win->dma_burst == 4)
617                         cfg |= S3C_WINCON_BURSTLEN_4WORD;
618                 else if (win->dma_burst == 8)
619                         cfg |= S3C_WINCON_BURSTLEN_8WORD;
620                 else
621                         cfg |= S3C_WINCON_BURSTLEN_16WORD;
622
623                 /* bpp mode set */
624                 switch (fb->var.bits_per_pixel) {
625                 case 16:
626                         if (var->transp.length == 1) {
627                                 dev_dbg(ctrl->dev,
628                                         "[fb%d] bpp mode: A1-R5-G5-B5\n", id);
629                                 cfg |= S3C_WINCON_BPPMODE_16BPP_A555;
630                         } else if (var->transp.length == 4) {
631                                 dev_dbg(ctrl->dev,
632                                         "[fb%d] bpp mode: A4-R4-G4-B4\n", id);
633                                 cfg |= S3C_WINCON_BPPMODE_16BPP_A444;
634                         } else {
635                                 dev_dbg(ctrl->dev,
636                                         "[fb%d] bpp mode: R5-G6-B5\n", id);
637                                 cfg |= S3C_WINCON_BPPMODE_16BPP_565;
638                         }
639                         break;
640
641                 case 24: /* packed 24 bpp: nothing to do for 6.x fimd */
642                         break;
643
644                 case 32:
645                         if (var->transp.length == 0) {
646                                 dev_dbg(ctrl->dev,
647                                         "[fb%d] bpp mode: R8-G8-B8\n", id);
648                                 cfg |= S3C_WINCON_BPPMODE_24BPP_888;
649                         } else {
650                                 dev_dbg(ctrl->dev,
651                                         "[fb%d] bpp mode: A8-R8-G8-B8\n", id);
652                                 cfg |= S3C_WINCON_BPPMODE_32BPP;
653                         }
654                         break;
655                 }
656         }
657
658         writel(cfg, ctrl->regs + S3C_WINCON(id));
659
660         if ((pdata->hw_ver == 0x62) || (pdata->hw_ver == 0x70)) {
661                 shw = readl(ctrl->regs + S3C_WINSHMAP);
662                 shw &= ~(S3C_WINSHMAP_PROTECT(id));
663                 writel(shw, ctrl->regs + S3C_WINSHMAP);
664         }
665
666         return 0;
667 }
668
669 int s3cfb_get_win_cur_buf_addr(struct s3cfb_global *ctrl, int id)
670 {
671         dma_addr_t start_addr = 0;
672
673         start_addr = readl(ctrl->regs + S3C_VIDADDR_START0(id) + S3C_SHD_WIN_BASE);
674
675         dev_dbg(ctrl->dev, "[fb%d] start_addr: 0x%08x\n", id, start_addr);
676
677         return start_addr;
678 }
679
680 int s3cfb_set_buffer_address(struct s3cfb_global *ctrl, int id)
681 {
682         struct fb_fix_screeninfo *fix = &ctrl->fb[id]->fix;
683         struct fb_var_screeninfo *var = &ctrl->fb[id]->var;
684         struct s3c_platform_fb *pdata = to_fb_plat(ctrl->dev);
685         dma_addr_t start_addr = 0, end_addr = 0;
686         u32 shw;
687
688         if (fix->smem_start) {
689                 start_addr = fix->smem_start + ((var->xres_virtual *
690                                 var->yoffset + var->xoffset) *
691                                 (var->bits_per_pixel / 8));
692
693                 end_addr = start_addr + fix->line_length * var->yres;
694         }
695
696         if ((pdata->hw_ver == 0x62) || (pdata->hw_ver == 0x70)) {
697                 shw = readl(ctrl->regs + S3C_WINSHMAP);
698                 shw |= S3C_WINSHMAP_PROTECT(id);
699                 writel(shw, ctrl->regs + S3C_WINSHMAP);
700         }
701
702         writel(start_addr, ctrl->regs + S3C_VIDADDR_START0(id));
703         writel(end_addr, ctrl->regs + S3C_VIDADDR_END0(id));
704
705         if ((pdata->hw_ver == 0x62) || (pdata->hw_ver == 0x70)) {
706                 shw = readl(ctrl->regs + S3C_WINSHMAP);
707                 shw &= ~(S3C_WINSHMAP_PROTECT(id));
708                 writel(shw, ctrl->regs + S3C_WINSHMAP);
709         }
710
711         dev_dbg(ctrl->dev, "[fb%d] start_addr: 0x%08x, end_addr: 0x%08x\n",
712                 id, start_addr, end_addr);
713
714         return 0;
715 }
716
717 int s3cfb_set_alpha_value(struct s3cfb_global *ctrl, int value)
718 {
719         writel(value, ctrl->regs + S3C_BLENDCON);
720
721         return 0;
722 }
723
724 int s3cfb_set_alpha_mode(struct s3cfb_global *ctrl, int id, unsigned int mode)
725 {
726         if (id <= 0 || id > 5)
727                 return 0;
728
729         if (mode == BLENDING_PREMULT)
730                 writel(0xc1, ctrl->regs + S3C_BLENDEQ1 + 4 * (id - 1));
731         else
732                 writel(0xc2, ctrl->regs + S3C_BLENDEQ1 + 4 * (id - 1));
733
734         return 0;
735 }
736
737 int s3cfb_set_alpha_value_width(struct s3cfb_global *ctrl, int id)
738 {
739         struct fb_var_screeninfo *var = &ctrl->fb[id]->var;
740
741         if (var->bits_per_pixel == 32 && var->transp.length > 4)
742                 writel(1, ctrl->regs + S3C_BLENDCON);
743         else
744                 writel(0, ctrl->regs + S3C_BLENDCON);
745
746         return 0;
747 }
748
749 int s3cfb_set_alpha_blending(struct s3cfb_global *ctrl, int id)
750 {
751         struct s3c_platform_fb *pdata = to_fb_plat(ctrl->dev);
752         struct s3cfb_window *win = ctrl->fb[id]->par;
753         struct s3cfb_alpha *alpha = &win->alpha;
754         u32 avalue = 0, cfg;
755         u32 shw;
756
757         if (id == 0) {
758                 dev_err(ctrl->dev, "[fb%d] does not support alpha blending\n",
759                         id);
760                 return -EINVAL;
761         }
762
763         if ((pdata->hw_ver == 0x62) || (pdata->hw_ver == 0x70)) {
764                 shw = readl(ctrl->regs + S3C_WINSHMAP);
765                 shw |= S3C_WINSHMAP_PROTECT(id);
766                 writel(shw, ctrl->regs + S3C_WINSHMAP);
767         }
768
769         cfg = readl(ctrl->regs + S3C_WINCON(id));
770         cfg &= ~(S3C_WINCON_BLD_MASK | S3C_WINCON_ALPHA_SEL_MASK);
771
772         if (alpha->mode == PIXEL_BLENDING) {
773                 dev_dbg(ctrl->dev, "[fb%d] alpha mode: pixel blending\n", id);
774
775                 /* fixing to DATA[31:24] for alpha value */
776                 cfg |= (S3C_WINCON_BLD_PIXEL | S3C_WINCON_ALPHA1_SEL);
777         } else {
778                 dev_dbg(ctrl->dev, "[fb%d] alpha mode: plane %d blending\n",
779                         id, alpha->channel);
780
781                 cfg |= S3C_WINCON_BLD_PLANE;
782
783                 if (alpha->channel == 0) {
784                         cfg |= S3C_WINCON_ALPHA0_SEL;
785                         avalue = (alpha->value << S3C_VIDOSD_ALPHA0_SHIFT);
786                 } else {
787                         cfg |= S3C_WINCON_ALPHA1_SEL;
788                         avalue = (alpha->value << S3C_VIDOSD_ALPHA1_SHIFT);
789                 }
790         }
791
792         writel(cfg, ctrl->regs + S3C_WINCON(id));
793         writel(avalue, ctrl->regs + S3C_VIDOSD_C(id));
794
795         if ((pdata->hw_ver == 0x62) || (pdata->hw_ver == 0x70)) {
796                 shw = readl(ctrl->regs + S3C_WINSHMAP);
797                 shw &= ~(S3C_WINSHMAP_PROTECT(id));
798                 writel(shw, ctrl->regs + S3C_WINSHMAP);
799         }
800
801         return 0;
802 }
803
804 int s3cfb_set_oneshot(struct s3cfb_global *ctrl, int id)
805 {
806         struct s3c_platform_fb *pdata = to_fb_plat(ctrl->dev);
807         struct fb_var_screeninfo *var = &ctrl->fb[id]->var;
808         struct fb_fix_screeninfo *fix = &ctrl->fb[id]->fix;
809         struct s3cfb_window *win = ctrl->fb[id]->par;
810         u32 cfg, shw;
811         u32 offset = (var->xres_virtual - var->xres) * var->bits_per_pixel / 8;
812         dma_addr_t start_addr = 0, end_addr = 0;
813
814         /*  Shadow Register Protection */
815         if ((pdata->hw_ver == 0x62) || (pdata->hw_ver == 0x70)) {
816                 shw = readl(ctrl->regs + S3C_WINSHMAP);
817                 shw |= S3C_WINSHMAP_PROTECT(id);
818                 writel(shw, ctrl->regs + S3C_WINSHMAP);
819         }
820
821         /*  s3cfb_set_window_position */
822         cfg = S3C_VIDOSD_LEFT_X(win->x) | S3C_VIDOSD_TOP_Y(win->y);
823         writel(cfg, ctrl->regs + S3C_VIDOSD_A(id));
824
825         cfg = S3C_VIDOSD_RIGHT_X(win->x + var->xres - 1) |
826                 S3C_VIDOSD_BOTTOM_Y(win->y + var->yres - 1);
827         writel(cfg, ctrl->regs + S3C_VIDOSD_B(id));
828
829         dev_dbg(ctrl->dev, "[fb%d] offset: (%d, %d, %d, %d)\n", id,
830                         win->x, win->y, win->x + var->xres - 1, win->y + var->yres - 1);
831
832         /* s3cfb_set_buffer_address */
833         if (fix->smem_start) {
834                 start_addr = fix->smem_start + ((var->xres_virtual *
835                                 var->yoffset + var->xoffset) *
836                                 (var->bits_per_pixel / 8));
837
838                 end_addr = start_addr + fix->line_length * var->yres;
839         }
840
841         writel(start_addr, ctrl->regs + S3C_VIDADDR_START0(id));
842         writel(end_addr, ctrl->regs + S3C_VIDADDR_END0(id));
843
844         dev_dbg(ctrl->dev, "[fb%d] start_addr: 0x%08x, end_addr: 0x%08x\n",
845                 id, start_addr, end_addr);
846
847         /*  s3cfb_set_window_size */
848         if (id <= 2) {
849                 cfg = S3C_VIDOSD_SIZE(var->xres * var->yres);
850                 if (id == 0)
851                         writel(cfg, ctrl->regs + S3C_VIDOSD_C(id));
852                 else
853                         writel(cfg, ctrl->regs + S3C_VIDOSD_D(id));
854
855                 dev_dbg(ctrl->dev, "[fb%d] resolution: %d x %d\n", id,
856                                 var->xres, var->yres);
857         }
858
859         /*  s3cfb_set_buffer_size */
860         cfg = S3C_VIDADDR_PAGEWIDTH(var->xres * var->bits_per_pixel / 8);
861         cfg |= S3C_VIDADDR_OFFSIZE(offset);
862         writel(cfg, ctrl->regs + S3C_VIDADDR_SIZE(id));
863
864         /*  Shadow Register Un-Protection */
865         if ((pdata->hw_ver == 0x62) || (pdata->hw_ver == 0x70)) {
866                 shw = readl(ctrl->regs + S3C_WINSHMAP);
867                 shw &= ~(S3C_WINSHMAP_PROTECT(id));
868                 writel(shw, ctrl->regs + S3C_WINSHMAP);
869         }
870
871         return 0;
872 }
873
874 int s3cfb_set_window_position(struct s3cfb_global *ctrl, int id)
875 {
876         struct fb_var_screeninfo *var = &ctrl->fb[id]->var;
877         struct s3cfb_window *win = ctrl->fb[id]->par;
878         u32 cfg, shw;
879
880         shw = readl(ctrl->regs + S3C_WINSHMAP);
881         shw |= S3C_WINSHMAP_PROTECT(id);
882         writel(shw, ctrl->regs + S3C_WINSHMAP);
883
884         cfg = S3C_VIDOSD_LEFT_X(win->x) | S3C_VIDOSD_TOP_Y(win->y);
885         writel(cfg, ctrl->regs + S3C_VIDOSD_A(id));
886
887         cfg = S3C_VIDOSD_RIGHT_X(win->x + var->xres - 1) |
888                 S3C_VIDOSD_BOTTOM_Y(win->y + var->yres - 1);
889
890         writel(cfg, ctrl->regs + S3C_VIDOSD_B(id));
891
892         shw = readl(ctrl->regs + S3C_WINSHMAP);
893         shw &= ~(S3C_WINSHMAP_PROTECT(id));
894         writel(shw, ctrl->regs + S3C_WINSHMAP);
895
896         dev_dbg(ctrl->dev, "[fb%d] offset: (%d, %d, %d, %d)\n", id,
897                 win->x, win->y, win->x + var->xres - 1, win->y + var->yres - 1);
898
899         return 0;
900 }
901
902 int s3cfb_set_window_size(struct s3cfb_global *ctrl, int id)
903 {
904         struct fb_var_screeninfo *var = &ctrl->fb[id]->var;
905         u32 cfg;
906
907         if (id > 2)
908                 return 0;
909
910         cfg = S3C_VIDOSD_SIZE(var->xres * var->yres);
911
912         if (id == 0)
913                 writel(cfg, ctrl->regs + S3C_VIDOSD_C(id));
914         else
915                 writel(cfg, ctrl->regs + S3C_VIDOSD_D(id));
916
917         dev_dbg(ctrl->dev, "[fb%d] resolution: %d x %d\n", id,
918                 var->xres, var->yres);
919
920         return 0;
921 }
922
923 int s3cfb_set_buffer_size(struct s3cfb_global *ctrl, int id)
924 {
925         struct s3c_platform_fb *pdata = to_fb_plat(ctrl->dev);
926         struct fb_var_screeninfo *var = &ctrl->fb[id]->var;
927         u32 offset = (var->xres_virtual - var->xres) * var->bits_per_pixel / 8;
928         u32 cfg = 0;
929         u32 shw;
930
931         cfg = S3C_VIDADDR_PAGEWIDTH(var->xres * var->bits_per_pixel / 8);
932         cfg |= S3C_VIDADDR_OFFSIZE(offset);
933
934         if ((pdata->hw_ver == 0x62) || (pdata->hw_ver == 0x70)) {
935                 shw = readl(ctrl->regs + S3C_WINSHMAP);
936                 shw |= S3C_WINSHMAP_PROTECT(id);
937                 writel(shw, ctrl->regs + S3C_WINSHMAP);
938         }
939
940         writel(cfg, ctrl->regs + S3C_VIDADDR_SIZE(id));
941
942         if ((pdata->hw_ver == 0x62) || (pdata->hw_ver == 0x70)) {
943                 shw = readl(ctrl->regs + S3C_WINSHMAP);
944                 shw &= ~(S3C_WINSHMAP_PROTECT(id));
945                 writel(shw, ctrl->regs + S3C_WINSHMAP);
946         }
947
948         return 0;
949 }
950
951 int s3cfb_set_chroma_key(struct s3cfb_global *ctrl, int id)
952 {
953         struct s3c_platform_fb *pdata = to_fb_plat(ctrl->dev);
954         struct s3cfb_window *win = ctrl->fb[id]->par;
955         struct s3cfb_chroma *chroma = &win->chroma;
956         u32 cfg = 0;
957         u32 shw;
958
959         if (id == 0) {
960                 dev_err(ctrl->dev, "[fb%d] does not support chroma key\n", id);
961                 return -EINVAL;
962         }
963
964         cfg = (S3C_KEYCON0_KEYBLEN_DISABLE | S3C_KEYCON0_DIRCON_MATCH_FG);
965
966         if (chroma->enabled)
967                 cfg |= S3C_KEYCON0_KEY_ENABLE;
968
969         if ((pdata->hw_ver == 0x62) || (pdata->hw_ver == 0x70)) {
970                 shw = readl(ctrl->regs + S3C_WINSHMAP);
971                 shw |= S3C_WINSHMAP_PROTECT(id);
972                 writel(shw, ctrl->regs + S3C_WINSHMAP);
973         }
974
975         writel(cfg, ctrl->regs + S3C_KEYCON(id));
976
977         cfg = S3C_KEYCON1_COLVAL(chroma->key);
978         writel(cfg, ctrl->regs + S3C_KEYVAL(id));
979
980         if ((pdata->hw_ver == 0x62) || (pdata->hw_ver == 0x70)) {
981                 shw = readl(ctrl->regs + S3C_WINSHMAP);
982                 shw &= ~(S3C_WINSHMAP_PROTECT(id));
983                 writel(shw, ctrl->regs + S3C_WINSHMAP);
984         }
985
986         dev_dbg(ctrl->dev, "[fb%d] chroma key: 0x%08x, %s\n", id, cfg,
987                 chroma->enabled ? "enabled" : "disabled");
988
989         return 0;
990 }
991
992 int s3cfb_set_dualrgb(struct s3cfb_global *ctrl, int mode)
993 {
994         writel(mode, ctrl->regs + S3C_DUALRGB);
995
996         return 0;
997 }
998