1 /* linux/drivers/video/samsung/s3cfb_fimd6x.c
3 * Copyright (c) 2010 Samsung Electronics Co., Ltd.
4 * http://www.samsung.com/
6 * Register interface file for Samsung Display Controller (FIMD) driver
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.
13 #include <linux/delay.h>
14 #include <linux/device.h>
17 #include <linux/clk.h>
19 #include <plat/clock.h>
20 #include <plat/fb-s5p.h>
21 #include <plat/regs-fb-s5p.h>
25 void s3cfb_check_line_count(struct s3cfb_global *ctrl)
27 int timeout = 30 * 5300;
31 if (!(readl(ctrl->regs + S3C_VIDCON1) & 0x7ff0000))
34 } while (i < timeout);
37 dev_err(ctrl->dev, "line count mismatch\n");
38 s3cfb_display_on(ctrl);
42 int s3cfb_check_vsync_status(struct s3cfb_global *ctrl)
46 if (unlikely(!ctrl->regs)) {
47 dev_err(ctrl->dev, "reg is zero\n");
51 cfg = (readl(ctrl->regs + S3C_VIDCON1) & S3C_VIDCON1_VSTATUS_MASK);
53 if (cfg != S3C_VIDCON1_VSTATUS_ACTIVE && cfg != S3C_VIDCON1_VSTATUS_BACK)
59 int s3cfb_set_output(struct s3cfb_global *ctrl)
63 cfg = readl(ctrl->regs + S3C_VIDCON0);
64 cfg &= ~S3C_VIDCON0_VIDOUT_MASK;
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;
82 dev_err(ctrl->dev, "invalid output type: %d\n", ctrl->output);
86 writel(cfg, ctrl->regs + S3C_VIDCON0);
88 cfg = readl(ctrl->regs + S3C_VIDCON2);
89 cfg &= ~(S3C_VIDCON2_WB_MASK | S3C_VIDCON2_TVFORMATSEL_MASK | \
90 S3C_VIDCON2_TVFORMATSEL_YUV_MASK);
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);
110 dev_err(ctrl->dev, "invalid output type: %d\n", ctrl->output);
114 writel(cfg, ctrl->regs + S3C_VIDCON2);
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);
125 #ifdef CONFIG_FB_S5P_MIPI_DSIM
126 void s3cfb_set_trigger(struct s3cfb_global *ctrl)
130 reg = readl(ctrl->regs + S3C_TRIGCON);
132 reg |= 1 << 0 | 1 << 1;
134 writel(reg, ctrl->regs + S3C_TRIGCON);
138 int s3cfb_set_display_mode(struct s3cfb_global *ctrl)
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);
150 int s3cfb_display_on(struct s3cfb_global *ctrl)
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);
158 dev_dbg(ctrl->dev, "global display is on\n");
163 int s3cfb_display_off(struct s3cfb_global *ctrl)
165 u32 cfg, fimd_count = 0;
167 cfg = readl(ctrl->regs + S3C_VIDCON0);
168 cfg |= S3C_VIDCON0_ENVID_ENABLE;
169 cfg &= ~S3C_VIDCON0_ENVID_F_ENABLE;
171 writel(cfg, ctrl->regs + S3C_VIDCON0);
174 if (++fimd_count > 2000000) {
175 dev_err(ctrl->dev, "FIMD off fail\n");
178 if (!(readl(ctrl->regs + S3C_VIDCON0) & 0x1))
183 int s3cfb_frame_off(struct s3cfb_global *ctrl)
187 cfg = readl(ctrl->regs + S3C_VIDCON0);
188 cfg &= ~S3C_VIDCON0_ENVID_F_ENABLE;
189 writel(cfg, ctrl->regs + S3C_VIDCON0);
191 dev_dbg(ctrl->dev, "current frame display is off\n");
196 int s3cfb_set_clock(struct s3cfb_global *ctrl)
198 struct s3c_platform_fb *pdata = to_fb_plat(ctrl->dev);
199 u32 cfg, maxclk, src_clk, vclk, div;
201 /* spec is under 100MHz */
202 maxclk = 100 * 1000000;
204 cfg = readl(ctrl->regs + S3C_VIDCON0);
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);
212 src_clk = clk_get_rate(ctrl->clock);
213 printk(KERN_DEBUG "FIMD src sclk = %d\n", src_clk);
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);
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);
229 cfg |= S3C_VIDCON0_CLKSEL_HCLK;
230 src_clk = ctrl->clock->parent->rate;
231 printk(KERN_DEBUG "FIMD src hclk = %d\n", src_clk);
235 vclk = PICOS2KHZ(ctrl->fb[pdata->default_win]->var.pixclock) * 1000;
238 dev_info(ctrl->dev, "vclk(%d) should be smaller than %d\n",
243 div = DIV_ROUND_CLOSEST(src_clk, vclk);
246 dev_err(ctrl->dev, "div(%d) should be non-zero\n", div);
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);
254 cfg &= ~S3C_VIDCON0_CLKVAL_F(0xff);
255 cfg |= S3C_VIDCON0_CLKVAL_F(div - 1);
256 writel(cfg, ctrl->regs + S3C_VIDCON0);
258 dev_info(ctrl->dev, "parent clock: %d, vclk: %d, vclk div: %d\n",
264 int s3cfb_set_polarity(struct s3cfb_global *ctrl)
266 struct s3cfb_lcd_polarity *pol;
269 pol = &ctrl->lcd->polarity;
272 /* Set VCLK hold scheme */
273 cfg &= S3C_VIDCON1_FIXVCLK_MASK;
274 cfg |= S3C_VIDCON1_FIXVCLK_VCLK_RUN_VDEN_DIS;
277 cfg |= S3C_VIDCON1_IVCLK_RISING_EDGE;
280 cfg |= S3C_VIDCON1_IHSYNC_INVERT;
283 cfg |= S3C_VIDCON1_IVSYNC_INVERT;
286 cfg |= S3C_VIDCON1_IVDEN_INVERT;
288 writel(cfg, ctrl->regs + S3C_VIDCON1);
293 int s3cfb_set_polarity_only(struct s3cfb_global *ctrl)
295 struct s3cfb_lcd_polarity *pol;
298 pol = &ctrl->lcd->polarity;
301 cfg |= S3C_VIDCON1_IVCLK_RISING_EDGE;
304 cfg |= S3C_VIDCON1_IHSYNC_INVERT;
307 cfg |= S3C_VIDCON1_IVSYNC_INVERT;
310 cfg |= S3C_VIDCON1_IVDEN_INVERT;
312 writel(cfg, ctrl->regs + S3C_VIDCON1);
317 int s3cfb_set_timing(struct s3cfb_global *ctrl)
319 struct s3cfb_lcd_timing *time;
322 time = &ctrl->lcd->timing;
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);
330 writel(cfg, ctrl->regs + S3C_VIDTCON0);
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);
339 writel(cfg, ctrl->regs + S3C_VIDTCON1);
344 int s3cfb_set_lcd_size(struct s3cfb_global *ctrl)
348 #ifdef CONFIG_FB_S5P_WA101S
349 cfg |= S3C_VIDTCON2_HOZVAL(ctrl->lcd->width - 1 + 6);
351 cfg |= S3C_VIDTCON2_HOZVAL(ctrl->lcd->width - 1);
354 cfg |= S3C_VIDTCON2_LINEVAL(ctrl->lcd->height - 1);
356 writel(cfg, ctrl->regs + S3C_VIDTCON2);
361 int s3cfb_set_global_interrupt(struct s3cfb_global *ctrl, int enable)
365 cfg = readl(ctrl->regs + S3C_VIDINTCON0);
366 cfg &= ~(S3C_VIDINTCON0_INTFRMEN_ENABLE | S3C_VIDINTCON0_INT_ENABLE);
369 dev_dbg(ctrl->dev, "video interrupt is on\n");
370 cfg |= (S3C_VIDINTCON0_INTFRMEN_ENABLE |
371 S3C_VIDINTCON0_INT_ENABLE);
373 dev_dbg(ctrl->dev, "video interrupt is off\n");
374 cfg |= (S3C_VIDINTCON0_INTFRMEN_DISABLE |
375 S3C_VIDINTCON0_INT_DISABLE);
378 writel(cfg, ctrl->regs + S3C_VIDINTCON0);
383 int s3cfb_set_vsync_interrupt(struct s3cfb_global *ctrl, int enable)
387 cfg = readl(ctrl->regs + S3C_VIDINTCON0);
388 cfg &= ~S3C_VIDINTCON0_FRAMESEL0_MASK;
391 dev_dbg(ctrl->dev, "vsync interrupt is on\n");
392 cfg |= S3C_VIDINTCON0_FRAMESEL0_VSYNC;
394 dev_dbg(ctrl->dev, "vsync interrupt is off\n");
395 cfg &= ~S3C_VIDINTCON0_FRAMESEL0_VSYNC;
398 writel(cfg, ctrl->regs + S3C_VIDINTCON0);
403 int s3cfb_get_vsync_interrupt(struct s3cfb_global *ctrl)
407 cfg = readl(ctrl->regs + S3C_VIDINTCON0);
408 cfg &= S3C_VIDINTCON0_FRAMESEL0_VSYNC;
410 if (cfg & S3C_VIDINTCON0_FRAMESEL0_VSYNC) {
411 dev_dbg(ctrl->dev, "vsync interrupt is on\n");
414 dev_dbg(ctrl->dev, "vsync interrupt is off\n");
420 #ifdef CONFIG_FB_S5P_TRACE_UNDERRUN
421 int s3cfb_set_fifo_interrupt(struct s3cfb_global *ctrl, int enable)
425 cfg = readl(ctrl->regs + S3C_VIDINTCON0);
427 cfg &= ~(S3C_VIDINTCON0_FIFOSEL_MASK | S3C_VIDINTCON0_FIFOLEVEL_MASK);
428 cfg |= (S3C_VIDINTCON0_FIFOSEL_ALL | S3C_VIDINTCON0_FIFOLEVEL_EMPTY);
431 dev_dbg(ctrl->dev, "fifo interrupt is on\n");
432 cfg |= (S3C_VIDINTCON0_INTFIFO_ENABLE |
433 S3C_VIDINTCON0_INT_ENABLE);
435 dev_dbg(ctrl->dev, "fifo interrupt is off\n");
436 cfg &= ~(S3C_VIDINTCON0_INTFIFO_ENABLE |
437 S3C_VIDINTCON0_INT_ENABLE);
440 writel(cfg, ctrl->regs + S3C_VIDINTCON0);
446 int s3cfb_clear_interrupt(struct s3cfb_global *ctrl)
450 cfg = readl(ctrl->regs + S3C_VIDINTCON1);
452 if (cfg & S3C_VIDINTCON1_INTFIFOPEND)
453 dev_info(ctrl->dev, "fifo underrun occur\n");
455 cfg |= (S3C_VIDINTCON1_INTVPPEND | S3C_VIDINTCON1_INTI80PEND |
456 S3C_VIDINTCON1_INTFRMPEND | S3C_VIDINTCON1_INTFIFOPEND);
458 writel(cfg, ctrl->regs + S3C_VIDINTCON1);
463 int s3cfb_channel_localpath_on(struct s3cfb_global *ctrl, int id)
465 struct s3c_platform_fb *pdata = to_fb_plat(ctrl->dev);
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);
474 dev_dbg(ctrl->dev, "[fb%d] local path enabled\n", id);
479 int s3cfb_channel_localpath_off(struct s3cfb_global *ctrl, int id)
481 struct s3c_platform_fb *pdata = to_fb_plat(ctrl->dev);
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);
490 dev_dbg(ctrl->dev, "[fb%d] local path disabled\n", id);
495 int s3cfb_window_on(struct s3cfb_global *ctrl, int id)
497 struct s3c_platform_fb *pdata = to_fb_plat(ctrl->dev);
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);
506 cfg = readl(ctrl->regs + S3C_WINCON(id));
507 cfg |= S3C_WINCON_ENWIN_ENABLE;
508 writel(cfg, ctrl->regs + S3C_WINCON(id));
510 dev_dbg(ctrl->dev, "[fb%d] turn on\n", id);
515 int s3cfb_window_off(struct s3cfb_global *ctrl, int id)
517 struct s3c_platform_fb *pdata = to_fb_plat(ctrl->dev);
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));
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);
531 dev_dbg(ctrl->dev, "[fb%d] turn off\n", id);
536 int s3cfb_win_map_on(struct s3cfb_global *ctrl, int id, int color)
540 cfg |= S3C_WINMAP_ENABLE;
541 cfg |= S3C_WINMAP_COLOR(color);
542 writel(cfg, ctrl->regs + S3C_WINMAP(id));
544 dev_dbg(ctrl->dev, "[fb%d] win map on : 0x%08x\n", id, color);
549 int s3cfb_win_map_off(struct s3cfb_global *ctrl, int id)
551 writel(0, ctrl->regs + S3C_WINMAP(id));
553 dev_dbg(ctrl->dev, "[fb%d] win map off\n", id);
558 int s3cfb_set_window_control(struct s3cfb_global *ctrl, int id)
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;
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);
573 cfg = readl(ctrl->regs + S3C_WINCON(id));
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);
580 if (win->path != DATA_PATH_DMA) {
581 dev_dbg(ctrl->dev, "[fb%d] data path: fifo\n", id);
583 cfg |= S3C_WINCON_DATAPATH_LOCAL;
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;
594 cfg &= ~(S3C_WINCON1_LOCALSEL_MASK |
595 S3C_WINCON1_VP_ENABLE);
597 if (win->local_channel == 0) {
598 cfg |= S3C_WINCON1_LOCALSEL_FIMC1;
600 cfg |= (S3C_WINCON1_LOCALSEL_VP |
601 S3C_WINCON1_VP_ENABLE);
605 dev_dbg(ctrl->dev, "[fb%d] data path: dma\n", id);
607 cfg |= S3C_WINCON_DATAPATH_DMA;
609 if (fb->var.bits_per_pixel == 16 && pdata->swap & FB_SWAP_HWORD)
610 cfg |= S3C_WINCON_HAWSWP_ENABLE;
612 if (fb->var.bits_per_pixel == 32 && pdata->swap & FB_SWAP_WORD)
613 cfg |= S3C_WINCON_WSWP_ENABLE;
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;
621 cfg |= S3C_WINCON_BURSTLEN_16WORD;
624 switch (fb->var.bits_per_pixel) {
626 if (var->transp.length == 1) {
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) {
632 "[fb%d] bpp mode: A4-R4-G4-B4\n", id);
633 cfg |= S3C_WINCON_BPPMODE_16BPP_A444;
636 "[fb%d] bpp mode: R5-G6-B5\n", id);
637 cfg |= S3C_WINCON_BPPMODE_16BPP_565;
641 case 24: /* packed 24 bpp: nothing to do for 6.x fimd */
645 if (var->transp.length == 0) {
647 "[fb%d] bpp mode: R8-G8-B8\n", id);
648 cfg |= S3C_WINCON_BPPMODE_24BPP_888;
651 "[fb%d] bpp mode: A8-R8-G8-B8\n", id);
652 cfg |= S3C_WINCON_BPPMODE_32BPP;
658 writel(cfg, ctrl->regs + S3C_WINCON(id));
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);
669 int s3cfb_get_win_cur_buf_addr(struct s3cfb_global *ctrl, int id)
671 dma_addr_t start_addr = 0;
673 start_addr = readl(ctrl->regs + S3C_VIDADDR_START0(id) + S3C_SHD_WIN_BASE);
675 dev_dbg(ctrl->dev, "[fb%d] start_addr: 0x%08x\n", id, start_addr);
680 int s3cfb_set_buffer_address(struct s3cfb_global *ctrl, int id)
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;
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));
693 end_addr = start_addr + fix->line_length * var->yres;
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);
702 writel(start_addr, ctrl->regs + S3C_VIDADDR_START0(id));
703 writel(end_addr, ctrl->regs + S3C_VIDADDR_END0(id));
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);
711 dev_dbg(ctrl->dev, "[fb%d] start_addr: 0x%08x, end_addr: 0x%08x\n",
712 id, start_addr, end_addr);
717 int s3cfb_set_alpha_value(struct s3cfb_global *ctrl, int value)
719 writel(value, ctrl->regs + S3C_BLENDCON);
724 int s3cfb_set_alpha_mode(struct s3cfb_global *ctrl, int id, unsigned int mode)
726 if (id <= 0 || id > 5)
729 if (mode == BLENDING_PREMULT)
730 writel(0xc1, ctrl->regs + S3C_BLENDEQ1 + 4 * (id - 1));
732 writel(0xc2, ctrl->regs + S3C_BLENDEQ1 + 4 * (id - 1));
737 int s3cfb_set_alpha_value_width(struct s3cfb_global *ctrl, int id)
739 struct fb_var_screeninfo *var = &ctrl->fb[id]->var;
741 if (var->bits_per_pixel == 32 && var->transp.length > 4)
742 writel(1, ctrl->regs + S3C_BLENDCON);
744 writel(0, ctrl->regs + S3C_BLENDCON);
749 int s3cfb_set_alpha_blending(struct s3cfb_global *ctrl, int id)
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;
758 dev_err(ctrl->dev, "[fb%d] does not support alpha blending\n",
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);
769 cfg = readl(ctrl->regs + S3C_WINCON(id));
770 cfg &= ~(S3C_WINCON_BLD_MASK | S3C_WINCON_ALPHA_SEL_MASK);
772 if (alpha->mode == PIXEL_BLENDING) {
773 dev_dbg(ctrl->dev, "[fb%d] alpha mode: pixel blending\n", id);
775 /* fixing to DATA[31:24] for alpha value */
776 cfg |= (S3C_WINCON_BLD_PIXEL | S3C_WINCON_ALPHA1_SEL);
778 dev_dbg(ctrl->dev, "[fb%d] alpha mode: plane %d blending\n",
781 cfg |= S3C_WINCON_BLD_PLANE;
783 if (alpha->channel == 0) {
784 cfg |= S3C_WINCON_ALPHA0_SEL;
785 avalue = (alpha->value << S3C_VIDOSD_ALPHA0_SHIFT);
787 cfg |= S3C_WINCON_ALPHA1_SEL;
788 avalue = (alpha->value << S3C_VIDOSD_ALPHA1_SHIFT);
792 writel(cfg, ctrl->regs + S3C_WINCON(id));
793 writel(avalue, ctrl->regs + S3C_VIDOSD_C(id));
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);
804 int s3cfb_set_oneshot(struct s3cfb_global *ctrl, int id)
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;
811 u32 offset = (var->xres_virtual - var->xres) * var->bits_per_pixel / 8;
812 dma_addr_t start_addr = 0, end_addr = 0;
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);
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));
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));
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);
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));
838 end_addr = start_addr + fix->line_length * var->yres;
841 writel(start_addr, ctrl->regs + S3C_VIDADDR_START0(id));
842 writel(end_addr, ctrl->regs + S3C_VIDADDR_END0(id));
844 dev_dbg(ctrl->dev, "[fb%d] start_addr: 0x%08x, end_addr: 0x%08x\n",
845 id, start_addr, end_addr);
847 /* s3cfb_set_window_size */
849 cfg = S3C_VIDOSD_SIZE(var->xres * var->yres);
851 writel(cfg, ctrl->regs + S3C_VIDOSD_C(id));
853 writel(cfg, ctrl->regs + S3C_VIDOSD_D(id));
855 dev_dbg(ctrl->dev, "[fb%d] resolution: %d x %d\n", id,
856 var->xres, var->yres);
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));
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);
874 int s3cfb_set_window_position(struct s3cfb_global *ctrl, int id)
876 struct fb_var_screeninfo *var = &ctrl->fb[id]->var;
877 struct s3cfb_window *win = ctrl->fb[id]->par;
880 shw = readl(ctrl->regs + S3C_WINSHMAP);
881 shw |= S3C_WINSHMAP_PROTECT(id);
882 writel(shw, ctrl->regs + S3C_WINSHMAP);
884 cfg = S3C_VIDOSD_LEFT_X(win->x) | S3C_VIDOSD_TOP_Y(win->y);
885 writel(cfg, ctrl->regs + S3C_VIDOSD_A(id));
887 cfg = S3C_VIDOSD_RIGHT_X(win->x + var->xres - 1) |
888 S3C_VIDOSD_BOTTOM_Y(win->y + var->yres - 1);
890 writel(cfg, ctrl->regs + S3C_VIDOSD_B(id));
892 shw = readl(ctrl->regs + S3C_WINSHMAP);
893 shw &= ~(S3C_WINSHMAP_PROTECT(id));
894 writel(shw, ctrl->regs + S3C_WINSHMAP);
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);
902 int s3cfb_set_window_size(struct s3cfb_global *ctrl, int id)
904 struct fb_var_screeninfo *var = &ctrl->fb[id]->var;
910 cfg = S3C_VIDOSD_SIZE(var->xres * var->yres);
913 writel(cfg, ctrl->regs + S3C_VIDOSD_C(id));
915 writel(cfg, ctrl->regs + S3C_VIDOSD_D(id));
917 dev_dbg(ctrl->dev, "[fb%d] resolution: %d x %d\n", id,
918 var->xres, var->yres);
923 int s3cfb_set_buffer_size(struct s3cfb_global *ctrl, int id)
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;
931 cfg = S3C_VIDADDR_PAGEWIDTH(var->xres * var->bits_per_pixel / 8);
932 cfg |= S3C_VIDADDR_OFFSIZE(offset);
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);
940 writel(cfg, ctrl->regs + S3C_VIDADDR_SIZE(id));
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);
951 int s3cfb_set_chroma_key(struct s3cfb_global *ctrl, int id)
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;
960 dev_err(ctrl->dev, "[fb%d] does not support chroma key\n", id);
964 cfg = (S3C_KEYCON0_KEYBLEN_DISABLE | S3C_KEYCON0_DIRCON_MATCH_FG);
967 cfg |= S3C_KEYCON0_KEY_ENABLE;
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);
975 writel(cfg, ctrl->regs + S3C_KEYCON(id));
977 cfg = S3C_KEYCON1_COLVAL(chroma->key);
978 writel(cfg, ctrl->regs + S3C_KEYVAL(id));
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);
986 dev_dbg(ctrl->dev, "[fb%d] chroma key: 0x%08x, %s\n", id, cfg,
987 chroma->enabled ? "enabled" : "disabled");
992 int s3cfb_set_dualrgb(struct s3cfb_global *ctrl, int mode)
994 writel(mode, ctrl->regs + S3C_DUALRGB);