Lines Matching +full:layer +full:- +full:alpha +full:- +full:mode
1 // SPDX-License-Identifier: GPL-2.0-only
2 /* linux/drivers/video/s3c-fb.c
5 * Copyright 2008-2010 Simtec Electronics
15 #include <linux/dma-mapping.h>
31 * setting of the alpha-blending functions that each window has, so only
35 * output timings and as the control for the output power-down state.
38 /* note, the previous use of <mach/regs-fb.h> to get platform specific data
58 #define VALID_BPP(x) (1 << ((x) - 1))
67 * struct s3c_fb_variant - fb variant information
111 * @has_osd_alpha: Set if can change alpha transparency for a window.
116 * @valid_bpp: 1 bit per BPP setting to show valid bits-per-pixel.
131 * struct s3c_fb_driverdata - per-device type driver data for init time.
141 * struct s3c_fb_palette - palette information
145 * @a: Alpha bitfield.
155 * struct s3c_fb_win - per window private data for each framebuffer.
178 * struct s3c_fb_vsync - vsync information
188 * struct s3c_fb - overall hardware state of the hardware
201 * @vsync_info: VSYNC-related information (count, queues...)
223 * s3c_fb_validate_win_bpp - validate the bits-per-pixel for this mode.
229 return win->variant.valid_bpp & VALID_BPP(bpp); in s3c_fb_validate_win_bpp()
233 * s3c_fb_check_var() - framebuffer layer request to verify a given mode.
237 * Framebuffer layer call to verify the given information and allow us to
243 struct s3c_fb_win *win = info->par; in s3c_fb_check_var()
244 struct s3c_fb *sfb = win->parent; in s3c_fb_check_var()
246 dev_dbg(sfb->dev, "checking parameters\n"); in s3c_fb_check_var()
248 var->xres_virtual = max(var->xres_virtual, var->xres); in s3c_fb_check_var()
249 var->yres_virtual = max(var->yres_virtual, var->yres); in s3c_fb_check_var()
251 if (!s3c_fb_validate_win_bpp(win, var->bits_per_pixel)) { in s3c_fb_check_var()
252 dev_dbg(sfb->dev, "win %d: unsupported bpp %d\n", in s3c_fb_check_var()
253 win->index, var->bits_per_pixel); in s3c_fb_check_var()
254 return -EINVAL; in s3c_fb_check_var()
258 var->transp.offset = 0; in s3c_fb_check_var()
259 var->transp.length = 0; in s3c_fb_check_var()
261 switch (var->bits_per_pixel) { in s3c_fb_check_var()
266 if (sfb->variant.palette[win->index] != 0) { in s3c_fb_check_var()
267 /* non palletised, A:1,R:2,G:3,B:2 mode */ in s3c_fb_check_var()
268 var->red.offset = 5; in s3c_fb_check_var()
269 var->green.offset = 2; in s3c_fb_check_var()
270 var->blue.offset = 0; in s3c_fb_check_var()
271 var->red.length = 2; in s3c_fb_check_var()
272 var->green.length = 3; in s3c_fb_check_var()
273 var->blue.length = 2; in s3c_fb_check_var()
274 var->transp.offset = 7; in s3c_fb_check_var()
275 var->transp.length = 1; in s3c_fb_check_var()
277 var->red.offset = 0; in s3c_fb_check_var()
278 var->red.length = var->bits_per_pixel; in s3c_fb_check_var()
279 var->green = var->red; in s3c_fb_check_var()
280 var->blue = var->red; in s3c_fb_check_var()
285 /* 666 with one bit alpha/transparency */ in s3c_fb_check_var()
286 var->transp.offset = 18; in s3c_fb_check_var()
287 var->transp.length = 1; in s3c_fb_check_var()
290 var->bits_per_pixel = 32; in s3c_fb_check_var()
293 var->red.offset = 12; in s3c_fb_check_var()
294 var->green.offset = 6; in s3c_fb_check_var()
295 var->blue.offset = 0; in s3c_fb_check_var()
296 var->red.length = 6; in s3c_fb_check_var()
297 var->green.length = 6; in s3c_fb_check_var()
298 var->blue.length = 6; in s3c_fb_check_var()
303 var->red.offset = 11; in s3c_fb_check_var()
304 var->green.offset = 5; in s3c_fb_check_var()
305 var->blue.offset = 0; in s3c_fb_check_var()
306 var->red.length = 5; in s3c_fb_check_var()
307 var->green.length = 6; in s3c_fb_check_var()
308 var->blue.length = 5; in s3c_fb_check_var()
314 var->transp.length = var->bits_per_pixel - 24; in s3c_fb_check_var()
315 var->transp.offset = 24; in s3c_fb_check_var()
319 var->bits_per_pixel = 32; in s3c_fb_check_var()
320 var->red.offset = 16; in s3c_fb_check_var()
321 var->red.length = 8; in s3c_fb_check_var()
322 var->green.offset = 8; in s3c_fb_check_var()
323 var->green.length = 8; in s3c_fb_check_var()
324 var->blue.offset = 0; in s3c_fb_check_var()
325 var->blue.length = 8; in s3c_fb_check_var()
329 dev_err(sfb->dev, "invalid bpp\n"); in s3c_fb_check_var()
330 return -EINVAL; in s3c_fb_check_var()
333 dev_dbg(sfb->dev, "%s: verified parameters\n", __func__); in s3c_fb_check_var()
338 * s3c_fb_calc_pixclk() - calculate the divider to create the pixel clock.
351 if (sfb->variant.has_clksel) in s3c_fb_calc_pixclk()
352 clk = clk_get_rate(sfb->bus_clk); in s3c_fb_calc_pixclk()
354 clk = clk_get_rate(sfb->lcd_clk); in s3c_fb_calc_pixclk()
362 dev_dbg(sfb->dev, "pixclk=%u, clk=%lu, div=%d (%lu)\n", in s3c_fb_calc_pixclk()
369 * s3c_fb_align_word() - align pixel count to word boundary
388 * vidosd_set_size() - set OSD size for a window
395 struct s3c_fb *sfb = win->parent; in vidosd_set_size()
398 if (win->variant.osd_size_off) in vidosd_set_size()
399 writel(size, sfb->regs + OSD_BASE(win->index, sfb->variant) in vidosd_set_size()
400 + win->variant.osd_size_off); in vidosd_set_size()
404 * vidosd_set_alpha() - set alpha transparency for a window
407 * @alpha: alpha register value
409 static void vidosd_set_alpha(struct s3c_fb_win *win, u32 alpha) in vidosd_set_alpha() argument
411 struct s3c_fb *sfb = win->parent; in vidosd_set_alpha()
413 if (win->variant.has_osd_alpha) in vidosd_set_alpha()
414 writel(alpha, sfb->regs + VIDOSD_C(win->index, sfb->variant)); in vidosd_set_alpha()
418 * shadow_protect_win() - disable updating values from shadow registers at vsync
425 struct s3c_fb *sfb = win->parent; in shadow_protect_win()
429 if (sfb->variant.has_prtcon) { in shadow_protect_win()
430 writel(PRTCON_PROTECT, sfb->regs + PRTCON); in shadow_protect_win()
431 } else if (sfb->variant.has_shadowcon) { in shadow_protect_win()
432 reg = readl(sfb->regs + SHADOWCON); in shadow_protect_win()
433 writel(reg | SHADOWCON_WINx_PROTECT(win->index), in shadow_protect_win()
434 sfb->regs + SHADOWCON); in shadow_protect_win()
437 if (sfb->variant.has_prtcon) { in shadow_protect_win()
438 writel(0, sfb->regs + PRTCON); in shadow_protect_win()
439 } else if (sfb->variant.has_shadowcon) { in shadow_protect_win()
440 reg = readl(sfb->regs + SHADOWCON); in shadow_protect_win()
441 writel(reg & ~SHADOWCON_WINx_PROTECT(win->index), in shadow_protect_win()
442 sfb->regs + SHADOWCON); in shadow_protect_win()
448 * s3c_fb_enable() - Set the state of the main LCD output
454 u32 vidcon0 = readl(sfb->regs + VIDCON0); in s3c_fb_enable()
456 if (enable && !sfb->output_on) in s3c_fb_enable()
457 pm_runtime_get_sync(sfb->dev); in s3c_fb_enable()
472 writel(vidcon0, sfb->regs + VIDCON0); in s3c_fb_enable()
474 if (!enable && sfb->output_on) in s3c_fb_enable()
475 pm_runtime_put_sync(sfb->dev); in s3c_fb_enable()
477 sfb->output_on = enable; in s3c_fb_enable()
481 * s3c_fb_set_par() - framebuffer request to set new framebuffer state.
484 * Framebuffer layer request to set a new mode for the specified framebuffer
488 struct fb_var_screeninfo *var = &info->var; in s3c_fb_set_par()
489 struct s3c_fb_win *win = info->par; in s3c_fb_set_par()
490 struct s3c_fb *sfb = win->parent; in s3c_fb_set_par()
491 void __iomem *regs = sfb->regs; in s3c_fb_set_par()
493 int win_no = win->index; in s3c_fb_set_par()
494 u32 alpha = 0; in s3c_fb_set_par() local
498 dev_dbg(sfb->dev, "setting framebuffer parameters\n"); in s3c_fb_set_par()
500 pm_runtime_get_sync(sfb->dev); in s3c_fb_set_par()
504 switch (var->bits_per_pixel) { in s3c_fb_set_par()
509 info->fix.visual = FB_VISUAL_TRUECOLOR; in s3c_fb_set_par()
512 if (win->variant.palette_sz >= 256) in s3c_fb_set_par()
513 info->fix.visual = FB_VISUAL_PSEUDOCOLOR; in s3c_fb_set_par()
515 info->fix.visual = FB_VISUAL_TRUECOLOR; in s3c_fb_set_par()
518 info->fix.visual = FB_VISUAL_MONO01; in s3c_fb_set_par()
521 info->fix.visual = FB_VISUAL_PSEUDOCOLOR; in s3c_fb_set_par()
525 info->fix.line_length = (var->xres_virtual * var->bits_per_pixel) / 8; in s3c_fb_set_par()
527 info->fix.xpanstep = info->var.xres_virtual > info->var.xres ? 1 : 0; in s3c_fb_set_par()
528 info->fix.ypanstep = info->var.yres_virtual > info->var.yres ? 1 : 0; in s3c_fb_set_par()
533 if (!sfb->output_on) in s3c_fb_set_par()
541 writel(info->fix.smem_start, buf + sfb->variant.buf_start); in s3c_fb_set_par()
543 data = info->fix.smem_start + info->fix.line_length * var->yres; in s3c_fb_set_par()
544 writel(data, buf + sfb->variant.buf_end); in s3c_fb_set_par()
546 pagewidth = (var->xres * var->bits_per_pixel) >> 3; in s3c_fb_set_par()
547 data = VIDW_BUF_SIZE_OFFSET(info->fix.line_length - pagewidth) | in s3c_fb_set_par()
549 VIDW_BUF_SIZE_OFFSET_E(info->fix.line_length - pagewidth) | in s3c_fb_set_par()
551 writel(data, regs + sfb->variant.buf_size + (win_no * 4)); in s3c_fb_set_par()
557 writel(data, regs + VIDOSD_A(win_no, sfb->variant)); in s3c_fb_set_par()
559 data = VIDOSDxB_BOTRIGHT_X(s3c_fb_align_word(var->bits_per_pixel, in s3c_fb_set_par()
560 var->xres - 1)) | in s3c_fb_set_par()
561 VIDOSDxB_BOTRIGHT_Y(var->yres - 1) | in s3c_fb_set_par()
562 VIDOSDxB_BOTRIGHT_X_E(s3c_fb_align_word(var->bits_per_pixel, in s3c_fb_set_par()
563 var->xres - 1)) | in s3c_fb_set_par()
564 VIDOSDxB_BOTRIGHT_Y_E(var->yres - 1); in s3c_fb_set_par()
566 writel(data, regs + VIDOSD_B(win_no, sfb->variant)); in s3c_fb_set_par()
568 data = var->xres * var->yres; in s3c_fb_set_par()
570 alpha = VIDISD14C_ALPHA1_R(0xf) | in s3c_fb_set_par()
574 vidosd_set_alpha(win, alpha); in s3c_fb_set_par()
578 if (sfb->variant.has_shadowcon) { in s3c_fb_set_par()
579 data = readl(sfb->regs + SHADOWCON); in s3c_fb_set_par()
581 writel(data, sfb->regs + SHADOWCON); in s3c_fb_set_par()
585 sfb->enabled |= (1 << win->index); in s3c_fb_set_par()
587 /* note, since we have to round up the bits-per-pixel, we end up in s3c_fb_set_par()
589 * exactly which mode of operation is intended. */ in s3c_fb_set_par()
591 switch (var->bits_per_pixel) { in s3c_fb_set_par()
608 if (var->transp.length != 0) in s3c_fb_set_par()
616 if (var->transp.length != 0) in s3c_fb_set_par()
625 if (var->red.length == 6) { in s3c_fb_set_par()
626 if (var->transp.length != 0) in s3c_fb_set_par()
630 } else if (var->transp.length == 1) in s3c_fb_set_par()
633 else if ((var->transp.length == 4) || in s3c_fb_set_par()
634 (var->transp.length == 8)) in s3c_fb_set_par()
648 void __iomem *keycon = regs + sfb->variant.keycon; in s3c_fb_set_par()
656 keycon += (win_no - 1) * 8; in s3c_fb_set_par()
662 writel(data, regs + sfb->variant.wincon + (win_no * 4)); in s3c_fb_set_par()
663 writel(0x0, regs + sfb->variant.winmap + (win_no * 4)); in s3c_fb_set_par()
665 /* Set alpha value width */ in s3c_fb_set_par()
666 if (sfb->variant.has_blendcon) { in s3c_fb_set_par()
667 data = readl(sfb->regs + BLENDCON); in s3c_fb_set_par()
669 if (var->transp.length > 4) in s3c_fb_set_par()
673 writel(data, sfb->regs + BLENDCON); in s3c_fb_set_par()
678 pm_runtime_put_sync(sfb->dev); in s3c_fb_set_par()
684 * s3c_fb_update_palette() - set or schedule a palette update.
705 palreg = sfb->regs + sfb->variant.palette[win->index]; in s3c_fb_update_palette()
707 dev_dbg(sfb->dev, "%s: win %d, reg %d (%p): %08x\n", in s3c_fb_update_palette()
708 __func__, win->index, reg, palreg, value); in s3c_fb_update_palette()
710 win->palette_buffer[reg] = value; in s3c_fb_update_palette()
712 palcon = readl(sfb->regs + WPALCON); in s3c_fb_update_palette()
713 writel(palcon | WPALCON_PAL_UPDATE, sfb->regs + WPALCON); in s3c_fb_update_palette()
715 if (win->variant.palette_16bpp) in s3c_fb_update_palette()
720 writel(palcon, sfb->regs + WPALCON); in s3c_fb_update_palette()
727 chan >>= 16 - bf->length; in chan_to_field()
728 return chan << bf->offset; in chan_to_field()
732 * s3c_fb_setcolreg() - framebuffer layer request to change palette.
737 * @transp: The transparency (alpha) field for the palette data.
744 struct s3c_fb_win *win = info->par; in s3c_fb_setcolreg()
745 struct s3c_fb *sfb = win->parent; in s3c_fb_setcolreg()
748 dev_dbg(sfb->dev, "%s: win %d: %d => rgb=%d/%d/%d\n", in s3c_fb_setcolreg()
749 __func__, win->index, regno, red, green, blue); in s3c_fb_setcolreg()
751 pm_runtime_get_sync(sfb->dev); in s3c_fb_setcolreg()
753 switch (info->fix.visual) { in s3c_fb_setcolreg()
755 /* true-colour, use pseudo-palette */ in s3c_fb_setcolreg()
758 u32 *pal = info->pseudo_palette; in s3c_fb_setcolreg()
760 val = chan_to_field(red, &info->var.red); in s3c_fb_setcolreg()
761 val |= chan_to_field(green, &info->var.green); in s3c_fb_setcolreg()
762 val |= chan_to_field(blue, &info->var.blue); in s3c_fb_setcolreg()
769 if (regno < win->variant.palette_sz) { in s3c_fb_setcolreg()
770 val = chan_to_field(red, &win->palette.r); in s3c_fb_setcolreg()
771 val |= chan_to_field(green, &win->palette.g); in s3c_fb_setcolreg()
772 val |= chan_to_field(blue, &win->palette.b); in s3c_fb_setcolreg()
780 pm_runtime_put_sync(sfb->dev); in s3c_fb_setcolreg()
784 pm_runtime_put_sync(sfb->dev); in s3c_fb_setcolreg()
789 * s3c_fb_blank() - blank or unblank the given window
793 * Framebuffer layer request to change the power state.
797 struct s3c_fb_win *win = info->par; in s3c_fb_blank()
798 struct s3c_fb *sfb = win->parent; in s3c_fb_blank()
799 unsigned int index = win->index; in s3c_fb_blank()
801 u32 output_on = sfb->output_on; in s3c_fb_blank()
803 dev_dbg(sfb->dev, "blank mode %d\n", blank_mode); in s3c_fb_blank()
805 pm_runtime_get_sync(sfb->dev); in s3c_fb_blank()
807 wincon = readl(sfb->regs + sfb->variant.wincon + (index * 4)); in s3c_fb_blank()
812 sfb->enabled &= ~(1 << index); in s3c_fb_blank()
819 sfb->regs + sfb->variant.winmap + (index * 4)); in s3c_fb_blank()
825 writel(0x0, sfb->regs + sfb->variant.winmap + (index * 4)); in s3c_fb_blank()
828 sfb->enabled |= (1 << index); in s3c_fb_blank()
834 pm_runtime_put_sync(sfb->dev); in s3c_fb_blank()
839 writel(wincon, sfb->regs + sfb->variant.wincon + (index * 4)); in s3c_fb_blank()
846 s3c_fb_enable(sfb, sfb->enabled ? 1 : 0); in s3c_fb_blank()
849 pm_runtime_put_sync(sfb->dev); in s3c_fb_blank()
851 return output_on == sfb->output_on; in s3c_fb_blank()
855 * s3c_fb_pan_display() - Pan the display.
868 struct s3c_fb_win *win = info->par; in s3c_fb_pan_display()
869 struct s3c_fb *sfb = win->parent; in s3c_fb_pan_display()
870 void __iomem *buf = sfb->regs + win->index * 8; in s3c_fb_pan_display()
873 pm_runtime_get_sync(sfb->dev); in s3c_fb_pan_display()
876 start_boff = var->yoffset * info->fix.line_length; in s3c_fb_pan_display()
878 if (info->var.bits_per_pixel >= 8) { in s3c_fb_pan_display()
879 start_boff += var->xoffset * (info->var.bits_per_pixel >> 3); in s3c_fb_pan_display()
881 switch (info->var.bits_per_pixel) { in s3c_fb_pan_display()
883 start_boff += var->xoffset >> 1; in s3c_fb_pan_display()
886 start_boff += var->xoffset >> 2; in s3c_fb_pan_display()
889 start_boff += var->xoffset >> 3; in s3c_fb_pan_display()
892 dev_err(sfb->dev, "invalid bpp\n"); in s3c_fb_pan_display()
893 pm_runtime_put_sync(sfb->dev); in s3c_fb_pan_display()
894 return -EINVAL; in s3c_fb_pan_display()
898 end_boff = start_boff + info->var.yres * info->fix.line_length; in s3c_fb_pan_display()
900 /* Temporarily turn off per-vsync update from shadow registers until in s3c_fb_pan_display()
904 writel(info->fix.smem_start + start_boff, buf + sfb->variant.buf_start); in s3c_fb_pan_display()
905 writel(info->fix.smem_start + end_boff, buf + sfb->variant.buf_end); in s3c_fb_pan_display()
909 pm_runtime_put_sync(sfb->dev); in s3c_fb_pan_display()
914 * s3c_fb_enable_irq() - enable framebuffer interrupts
919 void __iomem *regs = sfb->regs; in s3c_fb_enable_irq()
922 if (!test_and_set_bit(S3C_FB_VSYNC_IRQ_EN, &sfb->irq_flags)) { in s3c_fb_enable_irq()
939 * s3c_fb_disable_irq() - disable framebuffer interrupts
944 void __iomem *regs = sfb->regs; in s3c_fb_disable_irq()
947 if (test_and_clear_bit(S3C_FB_VSYNC_IRQ_EN, &sfb->irq_flags)) { in s3c_fb_disable_irq()
961 void __iomem *regs = sfb->regs; in s3c_fb_irq()
964 spin_lock(&sfb->slock); in s3c_fb_irq()
973 sfb->vsync_info.count++; in s3c_fb_irq()
974 wake_up_interruptible(&sfb->vsync_info.wait); in s3c_fb_irq()
982 spin_unlock(&sfb->slock); in s3c_fb_irq()
987 * s3c_fb_wait_for_vsync() - sleep until next VSYNC interrupt or timeout
997 return -ENODEV; in s3c_fb_wait_for_vsync()
999 pm_runtime_get_sync(sfb->dev); in s3c_fb_wait_for_vsync()
1001 count = sfb->vsync_info.count; in s3c_fb_wait_for_vsync()
1003 ret = wait_event_interruptible_timeout(sfb->vsync_info.wait, in s3c_fb_wait_for_vsync()
1004 count != sfb->vsync_info.count, in s3c_fb_wait_for_vsync()
1007 pm_runtime_put_sync(sfb->dev); in s3c_fb_wait_for_vsync()
1010 return -ETIMEDOUT; in s3c_fb_wait_for_vsync()
1018 struct s3c_fb_win *win = info->par; in s3c_fb_ioctl()
1019 struct s3c_fb *sfb = win->parent; in s3c_fb_ioctl()
1026 ret = -EFAULT; in s3c_fb_ioctl()
1033 ret = -ENOTTY; in s3c_fb_ioctl()
1051 * s3c_fb_missing_pixclock() - calculates pixel clock
1052 * @mode: The video mode to change.
1056 static void s3c_fb_missing_pixclock(struct fb_videomode *mode) in s3c_fb_missing_pixclock() argument
1061 div = mode->left_margin + mode->hsync_len + mode->right_margin + in s3c_fb_missing_pixclock()
1062 mode->xres; in s3c_fb_missing_pixclock()
1063 div *= mode->upper_margin + mode->vsync_len + mode->lower_margin + in s3c_fb_missing_pixclock()
1064 mode->yres; in s3c_fb_missing_pixclock()
1065 div *= mode->refresh ? : 60; in s3c_fb_missing_pixclock()
1069 mode->pixclock = pixclk; in s3c_fb_missing_pixclock()
1073 * s3c_fb_alloc_memory() - allocate display memory for framebuffer window
1081 struct s3c_fb_pd_win *windata = win->windata; in s3c_fb_alloc_memory()
1083 struct fb_info *fbi = win->fbinfo; in s3c_fb_alloc_memory()
1086 dev_dbg(sfb->dev, "allocating memory for display\n"); in s3c_fb_alloc_memory()
1088 real_size = windata->xres * windata->yres; in s3c_fb_alloc_memory()
1089 virt_size = windata->virtual_x * windata->virtual_y; in s3c_fb_alloc_memory()
1091 dev_dbg(sfb->dev, "real_size=%u (%u.%u), virt_size=%u (%u.%u)\n", in s3c_fb_alloc_memory()
1092 real_size, windata->xres, windata->yres, in s3c_fb_alloc_memory()
1093 virt_size, windata->virtual_x, windata->virtual_y); in s3c_fb_alloc_memory()
1096 size *= (windata->max_bpp > 16) ? 32 : windata->max_bpp; in s3c_fb_alloc_memory()
1099 fbi->fix.smem_len = size; in s3c_fb_alloc_memory()
1102 dev_dbg(sfb->dev, "want %u bytes for window\n", size); in s3c_fb_alloc_memory()
1104 fbi->screen_buffer = dma_alloc_wc(sfb->dev, size, &map_dma, GFP_KERNEL); in s3c_fb_alloc_memory()
1105 if (!fbi->screen_buffer) in s3c_fb_alloc_memory()
1106 return -ENOMEM; in s3c_fb_alloc_memory()
1108 dev_dbg(sfb->dev, "mapped %x to %p\n", in s3c_fb_alloc_memory()
1109 (unsigned int)map_dma, fbi->screen_buffer); in s3c_fb_alloc_memory()
1111 memset(fbi->screen_buffer, 0x0, size); in s3c_fb_alloc_memory()
1112 fbi->fix.smem_start = map_dma; in s3c_fb_alloc_memory()
1118 * s3c_fb_free_memory() - free the display memory for the given window
1126 struct fb_info *fbi = win->fbinfo; in s3c_fb_free_memory()
1128 if (fbi->screen_buffer) in s3c_fb_free_memory()
1129 dma_free_wc(sfb->dev, PAGE_ALIGN(fbi->fix.smem_len), in s3c_fb_free_memory()
1130 fbi->screen_buffer, fbi->fix.smem_start); in s3c_fb_free_memory()
1134 * s3c_fb_release_win() - release resources for a framebuffer window.
1145 if (win->fbinfo) { in s3c_fb_release_win()
1146 if (sfb->variant.has_shadowcon) { in s3c_fb_release_win()
1147 data = readl(sfb->regs + SHADOWCON); in s3c_fb_release_win()
1148 data &= ~SHADOWCON_CHx_ENABLE(win->index); in s3c_fb_release_win()
1149 data &= ~SHADOWCON_CHx_LOCAL_ENABLE(win->index); in s3c_fb_release_win()
1150 writel(data, sfb->regs + SHADOWCON); in s3c_fb_release_win()
1152 unregister_framebuffer(win->fbinfo); in s3c_fb_release_win()
1153 if (win->fbinfo->cmap.len) in s3c_fb_release_win()
1154 fb_dealloc_cmap(&win->fbinfo->cmap); in s3c_fb_release_win()
1156 framebuffer_release(win->fbinfo); in s3c_fb_release_win()
1161 * s3c_fb_probe_win() - register an hardware window
1181 dev_dbg(sfb->dev, "probing window %d, variant %p\n", win_no, variant); in s3c_fb_probe_win()
1183 init_waitqueue_head(&sfb->vsync_info.wait); in s3c_fb_probe_win()
1185 palette_size = variant->palette_sz * 4; in s3c_fb_probe_win()
1188 palette_size * sizeof(u32), sfb->dev); in s3c_fb_probe_win()
1190 return -ENOMEM; in s3c_fb_probe_win()
1192 windata = sfb->pdata->win[win_no]; in s3c_fb_probe_win()
1193 initmode = *sfb->pdata->vtiming; in s3c_fb_probe_win()
1195 WARN_ON(windata->max_bpp == 0); in s3c_fb_probe_win()
1196 WARN_ON(windata->xres == 0); in s3c_fb_probe_win()
1197 WARN_ON(windata->yres == 0); in s3c_fb_probe_win()
1199 win = fbinfo->par; in s3c_fb_probe_win()
1201 win->variant = *variant; in s3c_fb_probe_win()
1202 win->fbinfo = fbinfo; in s3c_fb_probe_win()
1203 win->parent = sfb; in s3c_fb_probe_win()
1204 win->windata = windata; in s3c_fb_probe_win()
1205 win->index = win_no; in s3c_fb_probe_win()
1206 win->palette_buffer = (u32 *)(win + 1); in s3c_fb_probe_win()
1210 dev_err(sfb->dev, "failed to allocate display memory\n"); in s3c_fb_probe_win()
1215 if (win->variant.palette_16bpp) { in s3c_fb_probe_win()
1217 win->palette.r.offset = 11; in s3c_fb_probe_win()
1218 win->palette.r.length = 5; in s3c_fb_probe_win()
1219 win->palette.g.offset = 5; in s3c_fb_probe_win()
1220 win->palette.g.length = 6; in s3c_fb_probe_win()
1221 win->palette.b.offset = 0; in s3c_fb_probe_win()
1222 win->palette.b.length = 5; in s3c_fb_probe_win()
1225 /* Set 8bpp or 8bpp and 1bit alpha */ in s3c_fb_probe_win()
1226 win->palette.r.offset = 16; in s3c_fb_probe_win()
1227 win->palette.r.length = 8; in s3c_fb_probe_win()
1228 win->palette.g.offset = 8; in s3c_fb_probe_win()
1229 win->palette.g.length = 8; in s3c_fb_probe_win()
1230 win->palette.b.offset = 0; in s3c_fb_probe_win()
1231 win->palette.b.length = 8; in s3c_fb_probe_win()
1234 /* setup the initial video mode from the window */ in s3c_fb_probe_win()
1235 initmode.xres = windata->xres; in s3c_fb_probe_win()
1236 initmode.yres = windata->yres; in s3c_fb_probe_win()
1237 fb_videomode_to_var(&fbinfo->var, &initmode); in s3c_fb_probe_win()
1239 fbinfo->fix.type = FB_TYPE_PACKED_PIXELS; in s3c_fb_probe_win()
1240 fbinfo->fix.accel = FB_ACCEL_NONE; in s3c_fb_probe_win()
1241 fbinfo->var.activate = FB_ACTIVATE_NOW; in s3c_fb_probe_win()
1242 fbinfo->var.vmode = FB_VMODE_NONINTERLACED; in s3c_fb_probe_win()
1243 fbinfo->var.bits_per_pixel = windata->default_bpp; in s3c_fb_probe_win()
1244 fbinfo->fbops = &s3c_fb_ops; in s3c_fb_probe_win()
1245 fbinfo->pseudo_palette = &win->pseudo_palette; in s3c_fb_probe_win()
1249 ret = s3c_fb_check_var(&fbinfo->var, fbinfo); in s3c_fb_probe_win()
1251 dev_err(sfb->dev, "check_var failed on initial video params\n"); in s3c_fb_probe_win()
1257 ret = fb_alloc_cmap(&fbinfo->cmap, win->variant.palette_sz, 1); in s3c_fb_probe_win()
1259 fb_set_cmap(&fbinfo->cmap, fbinfo); in s3c_fb_probe_win()
1261 dev_err(sfb->dev, "failed to allocate fb cmap\n"); in s3c_fb_probe_win()
1265 dev_dbg(sfb->dev, "about to register framebuffer\n"); in s3c_fb_probe_win()
1271 dev_err(sfb->dev, "failed to register framebuffer\n"); in s3c_fb_probe_win()
1275 dev_info(sfb->dev, "window %d: fb %s\n", win_no, fbinfo->fix.id); in s3c_fb_probe_win()
1281 * s3c_fb_set_rgb_timing() - set video timing for rgb interface.
1288 struct fb_videomode *vmode = sfb->pdata->vtiming; in s3c_fb_set_rgb_timing()
1289 void __iomem *regs = sfb->regs; in s3c_fb_set_rgb_timing()
1293 if (!vmode->pixclock) in s3c_fb_set_rgb_timing()
1296 clkdiv = s3c_fb_calc_pixclk(sfb, vmode->pixclock); in s3c_fb_set_rgb_timing()
1298 data = sfb->pdata->vidcon0; in s3c_fb_set_rgb_timing()
1302 data |= VIDCON0_CLKVAL_F(clkdiv-1) | VIDCON0_CLKDIR; in s3c_fb_set_rgb_timing()
1306 if (sfb->variant.is_2443) in s3c_fb_set_rgb_timing()
1310 data = VIDTCON0_VBPD(vmode->upper_margin - 1) | in s3c_fb_set_rgb_timing()
1311 VIDTCON0_VFPD(vmode->lower_margin - 1) | in s3c_fb_set_rgb_timing()
1312 VIDTCON0_VSPW(vmode->vsync_len - 1); in s3c_fb_set_rgb_timing()
1313 writel(data, regs + sfb->variant.vidtcon); in s3c_fb_set_rgb_timing()
1315 data = VIDTCON1_HBPD(vmode->left_margin - 1) | in s3c_fb_set_rgb_timing()
1316 VIDTCON1_HFPD(vmode->right_margin - 1) | in s3c_fb_set_rgb_timing()
1317 VIDTCON1_HSPW(vmode->hsync_len - 1); in s3c_fb_set_rgb_timing()
1318 writel(data, regs + sfb->variant.vidtcon + 4); in s3c_fb_set_rgb_timing()
1320 data = VIDTCON2_LINEVAL(vmode->yres - 1) | in s3c_fb_set_rgb_timing()
1321 VIDTCON2_HOZVAL(vmode->xres - 1) | in s3c_fb_set_rgb_timing()
1322 VIDTCON2_LINEVAL_E(vmode->yres - 1) | in s3c_fb_set_rgb_timing()
1323 VIDTCON2_HOZVAL_E(vmode->xres - 1); in s3c_fb_set_rgb_timing()
1324 writel(data, regs + sfb->variant.vidtcon + 8); in s3c_fb_set_rgb_timing()
1328 * s3c_fb_clear_win() - clear hardware window registers.
1336 void __iomem *regs = sfb->regs; in s3c_fb_clear_win()
1339 writel(0, regs + sfb->variant.wincon + (win * 4)); in s3c_fb_clear_win()
1340 writel(0, regs + VIDOSD_A(win, sfb->variant)); in s3c_fb_clear_win()
1341 writel(0, regs + VIDOSD_B(win, sfb->variant)); in s3c_fb_clear_win()
1342 writel(0, regs + VIDOSD_C(win, sfb->variant)); in s3c_fb_clear_win()
1344 if (sfb->variant.has_shadowcon) { in s3c_fb_clear_win()
1345 reg = readl(sfb->regs + SHADOWCON); in s3c_fb_clear_win()
1349 writel(reg, sfb->regs + SHADOWCON); in s3c_fb_clear_win()
1357 struct device *dev = &pdev->dev; in s3c_fb_probe()
1365 fbdrv = (struct s3c_fb_driverdata *)platid->driver_data; in s3c_fb_probe()
1367 if (fbdrv->variant.nr_windows > S3C_FB_MAX_WIN) { in s3c_fb_probe()
1369 return -EINVAL; in s3c_fb_probe()
1372 pd = dev_get_platdata(&pdev->dev); in s3c_fb_probe()
1375 return -EINVAL; in s3c_fb_probe()
1380 return -ENOMEM; in s3c_fb_probe()
1384 sfb->dev = dev; in s3c_fb_probe()
1385 sfb->pdata = pd; in s3c_fb_probe()
1386 sfb->variant = fbdrv->variant; in s3c_fb_probe()
1388 spin_lock_init(&sfb->slock); in s3c_fb_probe()
1390 sfb->bus_clk = devm_clk_get(dev, "lcd"); in s3c_fb_probe()
1391 if (IS_ERR(sfb->bus_clk)) in s3c_fb_probe()
1392 return dev_err_probe(dev, PTR_ERR(sfb->bus_clk), in s3c_fb_probe()
1395 clk_prepare_enable(sfb->bus_clk); in s3c_fb_probe()
1397 if (!sfb->variant.has_clksel) { in s3c_fb_probe()
1398 sfb->lcd_clk = devm_clk_get(dev, "sclk_fimd"); in s3c_fb_probe()
1399 if (IS_ERR(sfb->lcd_clk)) { in s3c_fb_probe()
1400 ret = dev_err_probe(dev, PTR_ERR(sfb->lcd_clk), in s3c_fb_probe()
1405 clk_prepare_enable(sfb->lcd_clk); in s3c_fb_probe()
1408 pm_runtime_enable(sfb->dev); in s3c_fb_probe()
1410 sfb->regs = devm_platform_ioremap_resource(pdev, 0); in s3c_fb_probe()
1411 if (IS_ERR(sfb->regs)) { in s3c_fb_probe()
1412 ret = PTR_ERR(sfb->regs); in s3c_fb_probe()
1416 sfb->irq_no = platform_get_irq(pdev, 0); in s3c_fb_probe()
1417 if (sfb->irq_no < 0) { in s3c_fb_probe()
1418 ret = -ENOENT; in s3c_fb_probe()
1422 ret = devm_request_irq(dev, sfb->irq_no, s3c_fb_irq, in s3c_fb_probe()
1429 dev_dbg(dev, "got resources (regs %p), probing windows\n", sfb->regs); in s3c_fb_probe()
1432 pm_runtime_get_sync(sfb->dev); in s3c_fb_probe()
1436 pd->setup_gpio(); in s3c_fb_probe()
1438 writel(pd->vidcon1, sfb->regs + VIDCON1); in s3c_fb_probe()
1440 /* set video clock running at under-run */ in s3c_fb_probe()
1441 if (sfb->variant.has_fixvclk) { in s3c_fb_probe()
1442 reg = readl(sfb->regs + VIDCON1); in s3c_fb_probe()
1445 writel(reg, sfb->regs + VIDCON1); in s3c_fb_probe()
1450 for (win = 0; win < fbdrv->variant.nr_windows; win++) in s3c_fb_probe()
1454 for (win = 0; win < (fbdrv->variant.nr_windows - 1); win++) { in s3c_fb_probe()
1455 void __iomem *regs = sfb->regs + sfb->variant.keycon; in s3c_fb_probe()
1466 for (win = 0; win < fbdrv->variant.nr_windows; win++) { in s3c_fb_probe()
1467 if (!pd->win[win]) in s3c_fb_probe()
1470 ret = s3c_fb_probe_win(sfb, win, fbdrv->win[win], in s3c_fb_probe()
1471 &sfb->windows[win]); in s3c_fb_probe()
1474 for (; win >= 0; win--) in s3c_fb_probe()
1475 s3c_fb_release_win(sfb, sfb->windows[win]); in s3c_fb_probe()
1481 pm_runtime_put_sync(sfb->dev); in s3c_fb_probe()
1486 pm_runtime_put_sync(sfb->dev); in s3c_fb_probe()
1489 pm_runtime_disable(sfb->dev); in s3c_fb_probe()
1491 if (!sfb->variant.has_clksel) in s3c_fb_probe()
1492 clk_disable_unprepare(sfb->lcd_clk); in s3c_fb_probe()
1495 clk_disable_unprepare(sfb->bus_clk); in s3c_fb_probe()
1501 * s3c_fb_remove() - Cleanup on module finalisation
1512 pm_runtime_get_sync(sfb->dev); in s3c_fb_remove()
1515 if (sfb->windows[win]) in s3c_fb_remove()
1516 s3c_fb_release_win(sfb, sfb->windows[win]); in s3c_fb_remove()
1518 if (!sfb->variant.has_clksel) in s3c_fb_remove()
1519 clk_disable_unprepare(sfb->lcd_clk); in s3c_fb_remove()
1521 clk_disable_unprepare(sfb->bus_clk); in s3c_fb_remove()
1523 pm_runtime_put_sync(sfb->dev); in s3c_fb_remove()
1524 pm_runtime_disable(sfb->dev); in s3c_fb_remove()
1534 pm_runtime_get_sync(sfb->dev); in s3c_fb_suspend()
1536 for (win_no = S3C_FB_MAX_WIN - 1; win_no >= 0; win_no--) { in s3c_fb_suspend()
1537 win = sfb->windows[win_no]; in s3c_fb_suspend()
1541 /* use the blank function to push into power-down */ in s3c_fb_suspend()
1542 s3c_fb_blank(FB_BLANK_POWERDOWN, win->fbinfo); in s3c_fb_suspend()
1545 if (!sfb->variant.has_clksel) in s3c_fb_suspend()
1546 clk_disable_unprepare(sfb->lcd_clk); in s3c_fb_suspend()
1548 clk_disable_unprepare(sfb->bus_clk); in s3c_fb_suspend()
1550 pm_runtime_put_sync(sfb->dev); in s3c_fb_suspend()
1558 struct s3c_fb_platdata *pd = sfb->pdata; in s3c_fb_resume()
1563 pm_runtime_get_sync(sfb->dev); in s3c_fb_resume()
1565 clk_prepare_enable(sfb->bus_clk); in s3c_fb_resume()
1567 if (!sfb->variant.has_clksel) in s3c_fb_resume()
1568 clk_prepare_enable(sfb->lcd_clk); in s3c_fb_resume()
1571 pd->setup_gpio(); in s3c_fb_resume()
1572 writel(pd->vidcon1, sfb->regs + VIDCON1); in s3c_fb_resume()
1574 /* set video clock running at under-run */ in s3c_fb_resume()
1575 if (sfb->variant.has_fixvclk) { in s3c_fb_resume()
1576 reg = readl(sfb->regs + VIDCON1); in s3c_fb_resume()
1579 writel(reg, sfb->regs + VIDCON1); in s3c_fb_resume()
1583 for (win_no = 0; win_no < sfb->variant.nr_windows; win_no++) in s3c_fb_resume()
1586 for (win_no = 0; win_no < sfb->variant.nr_windows - 1; win_no++) { in s3c_fb_resume()
1587 void __iomem *regs = sfb->regs + sfb->variant.keycon; in s3c_fb_resume()
1588 win = sfb->windows[win_no]; in s3c_fb_resume()
1603 win = sfb->windows[win_no]; in s3c_fb_resume()
1608 s3c_fb_set_par(win->fbinfo); in s3c_fb_resume()
1611 pm_runtime_put_sync(sfb->dev); in s3c_fb_resume()
1622 if (!sfb->variant.has_clksel) in s3c_fb_runtime_suspend()
1623 clk_disable_unprepare(sfb->lcd_clk); in s3c_fb_runtime_suspend()
1625 clk_disable_unprepare(sfb->bus_clk); in s3c_fb_runtime_suspend()
1633 struct s3c_fb_platdata *pd = sfb->pdata; in s3c_fb_runtime_resume()
1635 clk_prepare_enable(sfb->bus_clk); in s3c_fb_runtime_resume()
1637 if (!sfb->variant.has_clksel) in s3c_fb_runtime_resume()
1638 clk_prepare_enable(sfb->lcd_clk); in s3c_fb_runtime_resume()
1641 pd->setup_gpio(); in s3c_fb_runtime_resume()
1642 writel(pd->vidcon1, sfb->regs + VIDCON1); in s3c_fb_runtime_resume()
1774 .name = "s3c-fb",
1777 .name = "s3c2443-fb",
1795 .name = "s3c-fb",