Back to home page

OSCL-LXR

 
 

    


0001 // SPDX-License-Identifier: GPL-2.0-only
0002 /* linux/drivers/video/s3c-fb.c
0003  *
0004  * Copyright 2008 Openmoko Inc.
0005  * Copyright 2008-2010 Simtec Electronics
0006  *      Ben Dooks <ben@simtec.co.uk>
0007  *      http://armlinux.simtec.co.uk/
0008  *
0009  * Samsung SoC Framebuffer driver
0010 */
0011 
0012 #include <linux/kernel.h>
0013 #include <linux/module.h>
0014 #include <linux/platform_device.h>
0015 #include <linux/dma-mapping.h>
0016 #include <linux/slab.h>
0017 #include <linux/init.h>
0018 #include <linux/clk.h>
0019 #include <linux/fb.h>
0020 #include <linux/io.h>
0021 #include <linux/uaccess.h>
0022 #include <linux/interrupt.h>
0023 #include <linux/pm_runtime.h>
0024 #include <linux/platform_data/video_s3c.h>
0025 
0026 #include <video/samsung_fimd.h>
0027 
0028 /* This driver will export a number of framebuffer interfaces depending
0029  * on the configuration passed in via the platform data. Each fb instance
0030  * maps to a hardware window. Currently there is no support for runtime
0031  * setting of the alpha-blending functions that each window has, so only
0032  * window 0 is actually useful.
0033  *
0034  * Window 0 is treated specially, it is used for the basis of the LCD
0035  * output timings and as the control for the output power-down state.
0036 */
0037 
0038 /* note, the previous use of <mach/regs-fb.h> to get platform specific data
0039  * has been replaced by using the platform device name to pick the correct
0040  * configuration data for the system.
0041 */
0042 
0043 #ifdef CONFIG_FB_S3C_DEBUG_REGWRITE
0044 #undef writel
0045 #define writel(v, r) do { \
0046     pr_debug("%s: %08x => %p\n", __func__, (unsigned int)v, r); \
0047     __raw_writel(v, r); \
0048 } while (0)
0049 #endif /* FB_S3C_DEBUG_REGWRITE */
0050 
0051 /* irq_flags bits */
0052 #define S3C_FB_VSYNC_IRQ_EN 0
0053 
0054 #define VSYNC_TIMEOUT_MSEC 50
0055 
0056 struct s3c_fb;
0057 
0058 #define VALID_BPP(x) (1 << ((x) - 1))
0059 
0060 #define OSD_BASE(win, variant) ((variant).osd + ((win) * (variant).osd_stride))
0061 #define VIDOSD_A(win, variant) (OSD_BASE(win, variant) + 0x00)
0062 #define VIDOSD_B(win, variant) (OSD_BASE(win, variant) + 0x04)
0063 #define VIDOSD_C(win, variant) (OSD_BASE(win, variant) + 0x08)
0064 #define VIDOSD_D(win, variant) (OSD_BASE(win, variant) + 0x0C)
0065 
0066 /**
0067  * struct s3c_fb_variant - fb variant information
0068  * @is_2443: Set if S3C2443/S3C2416 style hardware.
0069  * @nr_windows: The number of windows.
0070  * @vidtcon: The base for the VIDTCONx registers
0071  * @wincon: The base for the WINxCON registers.
0072  * @winmap: The base for the WINxMAP registers.
0073  * @keycon: The abse for the WxKEYCON registers.
0074  * @buf_start: Offset of buffer start registers.
0075  * @buf_size: Offset of buffer size registers.
0076  * @buf_end: Offset of buffer end registers.
0077  * @osd: The base for the OSD registers.
0078  * @osd_stride: stride of osd
0079  * @palette: Address of palette memory, or 0 if none.
0080  * @has_prtcon: Set if has PRTCON register.
0081  * @has_shadowcon: Set if has SHADOWCON register.
0082  * @has_blendcon: Set if has BLENDCON register.
0083  * @has_clksel: Set if VIDCON0 register has CLKSEL bit.
0084  * @has_fixvclk: Set if VIDCON1 register has FIXVCLK bits.
0085  */
0086 struct s3c_fb_variant {
0087     unsigned int    is_2443:1;
0088     unsigned short  nr_windows;
0089     unsigned int    vidtcon;
0090     unsigned short  wincon;
0091     unsigned short  winmap;
0092     unsigned short  keycon;
0093     unsigned short  buf_start;
0094     unsigned short  buf_end;
0095     unsigned short  buf_size;
0096     unsigned short  osd;
0097     unsigned short  osd_stride;
0098     unsigned short  palette[S3C_FB_MAX_WIN];
0099 
0100     unsigned int    has_prtcon:1;
0101     unsigned int    has_shadowcon:1;
0102     unsigned int    has_blendcon:1;
0103     unsigned int    has_clksel:1;
0104     unsigned int    has_fixvclk:1;
0105 };
0106 
0107 /**
0108  * struct s3c_fb_win_variant
0109  * @has_osd_c: Set if has OSD C register.
0110  * @has_osd_d: Set if has OSD D register.
0111  * @has_osd_alpha: Set if can change alpha transparency for a window.
0112  * @palette_sz: Size of palette in entries.
0113  * @palette_16bpp: Set if palette is 16bits wide.
0114  * @osd_size_off: If != 0, supports setting up OSD for a window; the appropriate
0115  *                register is located at the given offset from OSD_BASE.
0116  * @valid_bpp: 1 bit per BPP setting to show valid bits-per-pixel.
0117  *
0118  * valid_bpp bit x is set if (x+1)BPP is supported.
0119  */
0120 struct s3c_fb_win_variant {
0121     unsigned int    has_osd_c:1;
0122     unsigned int    has_osd_d:1;
0123     unsigned int    has_osd_alpha:1;
0124     unsigned int    palette_16bpp:1;
0125     unsigned short  osd_size_off;
0126     unsigned short  palette_sz;
0127     u32     valid_bpp;
0128 };
0129 
0130 /**
0131  * struct s3c_fb_driverdata - per-device type driver data for init time.
0132  * @variant: The variant information for this driver.
0133  * @win: The window information for each window.
0134  */
0135 struct s3c_fb_driverdata {
0136     struct s3c_fb_variant   variant;
0137     struct s3c_fb_win_variant *win[S3C_FB_MAX_WIN];
0138 };
0139 
0140 /**
0141  * struct s3c_fb_palette - palette information
0142  * @r: Red bitfield.
0143  * @g: Green bitfield.
0144  * @b: Blue bitfield.
0145  * @a: Alpha bitfield.
0146  */
0147 struct s3c_fb_palette {
0148     struct fb_bitfield  r;
0149     struct fb_bitfield  g;
0150     struct fb_bitfield  b;
0151     struct fb_bitfield  a;
0152 };
0153 
0154 /**
0155  * struct s3c_fb_win - per window private data for each framebuffer.
0156  * @windata: The platform data supplied for the window configuration.
0157  * @parent: The hardware that this window is part of.
0158  * @fbinfo: Pointer pack to the framebuffer info for this window.
0159  * @variant: The variant information for this window.
0160  * @palette_buffer: Buffer/cache to hold palette entries.
0161  * @pseudo_palette: For use in TRUECOLOUR modes for entries 0..15/
0162  * @index: The window number of this window.
0163  * @palette: The bitfields for changing r/g/b into a hardware palette entry.
0164  */
0165 struct s3c_fb_win {
0166     struct s3c_fb_pd_win    *windata;
0167     struct s3c_fb       *parent;
0168     struct fb_info      *fbinfo;
0169     struct s3c_fb_palette    palette;
0170     struct s3c_fb_win_variant variant;
0171 
0172     u32         *palette_buffer;
0173     u32          pseudo_palette[16];
0174     unsigned int         index;
0175 };
0176 
0177 /**
0178  * struct s3c_fb_vsync - vsync information
0179  * @wait:   a queue for processes waiting for vsync
0180  * @count:  vsync interrupt count
0181  */
0182 struct s3c_fb_vsync {
0183     wait_queue_head_t   wait;
0184     unsigned int        count;
0185 };
0186 
0187 /**
0188  * struct s3c_fb - overall hardware state of the hardware
0189  * @slock: The spinlock protection for this data structure.
0190  * @dev: The device that we bound to, for printing, etc.
0191  * @bus_clk: The clk (hclk) feeding our interface and possibly pixclk.
0192  * @lcd_clk: The clk (sclk) feeding pixclk.
0193  * @regs: The mapped hardware registers.
0194  * @variant: Variant information for this hardware.
0195  * @enabled: A bitmask of enabled hardware windows.
0196  * @output_on: Flag if the physical output is enabled.
0197  * @pdata: The platform configuration data passed with the device.
0198  * @windows: The hardware windows that have been claimed.
0199  * @irq_no: IRQ line number
0200  * @irq_flags: irq flags
0201  * @vsync_info: VSYNC-related information (count, queues...)
0202  */
0203 struct s3c_fb {
0204     spinlock_t      slock;
0205     struct device       *dev;
0206     struct clk      *bus_clk;
0207     struct clk      *lcd_clk;
0208     void __iomem        *regs;
0209     struct s3c_fb_variant    variant;
0210 
0211     unsigned char        enabled;
0212     bool             output_on;
0213 
0214     struct s3c_fb_platdata  *pdata;
0215     struct s3c_fb_win   *windows[S3C_FB_MAX_WIN];
0216 
0217     int          irq_no;
0218     unsigned long        irq_flags;
0219     struct s3c_fb_vsync  vsync_info;
0220 };
0221 
0222 /**
0223  * s3c_fb_validate_win_bpp - validate the bits-per-pixel for this mode.
0224  * @win: The device window.
0225  * @bpp: The bit depth.
0226  */
0227 static bool s3c_fb_validate_win_bpp(struct s3c_fb_win *win, unsigned int bpp)
0228 {
0229     return win->variant.valid_bpp & VALID_BPP(bpp);
0230 }
0231 
0232 /**
0233  * s3c_fb_check_var() - framebuffer layer request to verify a given mode.
0234  * @var: The screen information to verify.
0235  * @info: The framebuffer device.
0236  *
0237  * Framebuffer layer call to verify the given information and allow us to
0238  * update various information depending on the hardware capabilities.
0239  */
0240 static int s3c_fb_check_var(struct fb_var_screeninfo *var,
0241                 struct fb_info *info)
0242 {
0243     struct s3c_fb_win *win = info->par;
0244     struct s3c_fb *sfb = win->parent;
0245 
0246     dev_dbg(sfb->dev, "checking parameters\n");
0247 
0248     var->xres_virtual = max(var->xres_virtual, var->xres);
0249     var->yres_virtual = max(var->yres_virtual, var->yres);
0250 
0251     if (!s3c_fb_validate_win_bpp(win, var->bits_per_pixel)) {
0252         dev_dbg(sfb->dev, "win %d: unsupported bpp %d\n",
0253             win->index, var->bits_per_pixel);
0254         return -EINVAL;
0255     }
0256 
0257     /* always ensure these are zero, for drop through cases below */
0258     var->transp.offset = 0;
0259     var->transp.length = 0;
0260 
0261     switch (var->bits_per_pixel) {
0262     case 1:
0263     case 2:
0264     case 4:
0265     case 8:
0266         if (sfb->variant.palette[win->index] != 0) {
0267             /* non palletised, A:1,R:2,G:3,B:2 mode */
0268             var->red.offset     = 5;
0269             var->green.offset   = 2;
0270             var->blue.offset    = 0;
0271             var->red.length     = 2;
0272             var->green.length   = 3;
0273             var->blue.length    = 2;
0274             var->transp.offset  = 7;
0275             var->transp.length  = 1;
0276         } else {
0277             var->red.offset = 0;
0278             var->red.length = var->bits_per_pixel;
0279             var->green  = var->red;
0280             var->blue   = var->red;
0281         }
0282         break;
0283 
0284     case 19:
0285         /* 666 with one bit alpha/transparency */
0286         var->transp.offset  = 18;
0287         var->transp.length  = 1;
0288         fallthrough;
0289     case 18:
0290         var->bits_per_pixel = 32;
0291 
0292         /* 666 format */
0293         var->red.offset     = 12;
0294         var->green.offset   = 6;
0295         var->blue.offset    = 0;
0296         var->red.length     = 6;
0297         var->green.length   = 6;
0298         var->blue.length    = 6;
0299         break;
0300 
0301     case 16:
0302         /* 16 bpp, 565 format */
0303         var->red.offset     = 11;
0304         var->green.offset   = 5;
0305         var->blue.offset    = 0;
0306         var->red.length     = 5;
0307         var->green.length   = 6;
0308         var->blue.length    = 5;
0309         break;
0310 
0311     case 32:
0312     case 28:
0313     case 25:
0314         var->transp.length  = var->bits_per_pixel - 24;
0315         var->transp.offset  = 24;
0316         fallthrough;
0317     case 24:
0318         /* our 24bpp is unpacked, so 32bpp */
0319         var->bits_per_pixel = 32;
0320         var->red.offset     = 16;
0321         var->red.length     = 8;
0322         var->green.offset   = 8;
0323         var->green.length   = 8;
0324         var->blue.offset    = 0;
0325         var->blue.length    = 8;
0326         break;
0327 
0328     default:
0329         dev_err(sfb->dev, "invalid bpp\n");
0330         return -EINVAL;
0331     }
0332 
0333     dev_dbg(sfb->dev, "%s: verified parameters\n", __func__);
0334     return 0;
0335 }
0336 
0337 /**
0338  * s3c_fb_calc_pixclk() - calculate the divider to create the pixel clock.
0339  * @sfb: The hardware state.
0340  * @pixclk: The pixel clock wanted, in picoseconds.
0341  *
0342  * Given the specified pixel clock, work out the necessary divider to get
0343  * close to the output frequency.
0344  */
0345 static int s3c_fb_calc_pixclk(struct s3c_fb *sfb, unsigned int pixclk)
0346 {
0347     unsigned long clk;
0348     unsigned long long tmp;
0349     unsigned int result;
0350 
0351     if (sfb->variant.has_clksel)
0352         clk = clk_get_rate(sfb->bus_clk);
0353     else
0354         clk = clk_get_rate(sfb->lcd_clk);
0355 
0356     tmp = (unsigned long long)clk;
0357     tmp *= pixclk;
0358 
0359     do_div(tmp, 1000000000UL);
0360     result = (unsigned int)tmp / 1000;
0361 
0362     dev_dbg(sfb->dev, "pixclk=%u, clk=%lu, div=%d (%lu)\n",
0363         pixclk, clk, result, result ? clk / result : clk);
0364 
0365     return result;
0366 }
0367 
0368 /**
0369  * s3c_fb_align_word() - align pixel count to word boundary
0370  * @bpp: The number of bits per pixel
0371  * @pix: The value to be aligned.
0372  *
0373  * Align the given pixel count so that it will start on an 32bit word
0374  * boundary.
0375  */
0376 static int s3c_fb_align_word(unsigned int bpp, unsigned int pix)
0377 {
0378     int pix_per_word;
0379 
0380     if (bpp > 16)
0381         return pix;
0382 
0383     pix_per_word = (8 * 32) / bpp;
0384     return ALIGN(pix, pix_per_word);
0385 }
0386 
0387 /**
0388  * vidosd_set_size() - set OSD size for a window
0389  *
0390  * @win: the window to set OSD size for
0391  * @size: OSD size register value
0392  */
0393 static void vidosd_set_size(struct s3c_fb_win *win, u32 size)
0394 {
0395     struct s3c_fb *sfb = win->parent;
0396 
0397     /* OSD can be set up if osd_size_off != 0 for this window */
0398     if (win->variant.osd_size_off)
0399         writel(size, sfb->regs + OSD_BASE(win->index, sfb->variant)
0400                 + win->variant.osd_size_off);
0401 }
0402 
0403 /**
0404  * vidosd_set_alpha() - set alpha transparency for a window
0405  *
0406  * @win: the window to set OSD size for
0407  * @alpha: alpha register value
0408  */
0409 static void vidosd_set_alpha(struct s3c_fb_win *win, u32 alpha)
0410 {
0411     struct s3c_fb *sfb = win->parent;
0412 
0413     if (win->variant.has_osd_alpha)
0414         writel(alpha, sfb->regs + VIDOSD_C(win->index, sfb->variant));
0415 }
0416 
0417 /**
0418  * shadow_protect_win() - disable updating values from shadow registers at vsync
0419  *
0420  * @win: window to protect registers for
0421  * @protect: 1 to protect (disable updates)
0422  */
0423 static void shadow_protect_win(struct s3c_fb_win *win, bool protect)
0424 {
0425     struct s3c_fb *sfb = win->parent;
0426     u32 reg;
0427 
0428     if (protect) {
0429         if (sfb->variant.has_prtcon) {
0430             writel(PRTCON_PROTECT, sfb->regs + PRTCON);
0431         } else if (sfb->variant.has_shadowcon) {
0432             reg = readl(sfb->regs + SHADOWCON);
0433             writel(reg | SHADOWCON_WINx_PROTECT(win->index),
0434                 sfb->regs + SHADOWCON);
0435         }
0436     } else {
0437         if (sfb->variant.has_prtcon) {
0438             writel(0, sfb->regs + PRTCON);
0439         } else if (sfb->variant.has_shadowcon) {
0440             reg = readl(sfb->regs + SHADOWCON);
0441             writel(reg & ~SHADOWCON_WINx_PROTECT(win->index),
0442                 sfb->regs + SHADOWCON);
0443         }
0444     }
0445 }
0446 
0447 /**
0448  * s3c_fb_enable() - Set the state of the main LCD output
0449  * @sfb: The main framebuffer state.
0450  * @enable: The state to set.
0451  */
0452 static void s3c_fb_enable(struct s3c_fb *sfb, int enable)
0453 {
0454     u32 vidcon0 = readl(sfb->regs + VIDCON0);
0455 
0456     if (enable && !sfb->output_on)
0457         pm_runtime_get_sync(sfb->dev);
0458 
0459     if (enable) {
0460         vidcon0 |= VIDCON0_ENVID | VIDCON0_ENVID_F;
0461     } else {
0462         /* see the note in the framebuffer datasheet about
0463          * why you cannot take both of these bits down at the
0464          * same time. */
0465 
0466         if (vidcon0 & VIDCON0_ENVID) {
0467             vidcon0 |= VIDCON0_ENVID;
0468             vidcon0 &= ~VIDCON0_ENVID_F;
0469         }
0470     }
0471 
0472     writel(vidcon0, sfb->regs + VIDCON0);
0473 
0474     if (!enable && sfb->output_on)
0475         pm_runtime_put_sync(sfb->dev);
0476 
0477     sfb->output_on = enable;
0478 }
0479 
0480 /**
0481  * s3c_fb_set_par() - framebuffer request to set new framebuffer state.
0482  * @info: The framebuffer to change.
0483  *
0484  * Framebuffer layer request to set a new mode for the specified framebuffer
0485  */
0486 static int s3c_fb_set_par(struct fb_info *info)
0487 {
0488     struct fb_var_screeninfo *var = &info->var;
0489     struct s3c_fb_win *win = info->par;
0490     struct s3c_fb *sfb = win->parent;
0491     void __iomem *regs = sfb->regs;
0492     void __iomem *buf;
0493     int win_no = win->index;
0494     u32 alpha = 0;
0495     u32 data;
0496     u32 pagewidth;
0497 
0498     dev_dbg(sfb->dev, "setting framebuffer parameters\n");
0499 
0500     pm_runtime_get_sync(sfb->dev);
0501 
0502     shadow_protect_win(win, 1);
0503 
0504     switch (var->bits_per_pixel) {
0505     case 32:
0506     case 24:
0507     case 16:
0508     case 12:
0509         info->fix.visual = FB_VISUAL_TRUECOLOR;
0510         break;
0511     case 8:
0512         if (win->variant.palette_sz >= 256)
0513             info->fix.visual = FB_VISUAL_PSEUDOCOLOR;
0514         else
0515             info->fix.visual = FB_VISUAL_TRUECOLOR;
0516         break;
0517     case 1:
0518         info->fix.visual = FB_VISUAL_MONO01;
0519         break;
0520     default:
0521         info->fix.visual = FB_VISUAL_PSEUDOCOLOR;
0522         break;
0523     }
0524 
0525     info->fix.line_length = (var->xres_virtual * var->bits_per_pixel) / 8;
0526 
0527     info->fix.xpanstep = info->var.xres_virtual > info->var.xres ? 1 : 0;
0528     info->fix.ypanstep = info->var.yres_virtual > info->var.yres ? 1 : 0;
0529 
0530     /* disable the window whilst we update it */
0531     writel(0, regs + WINCON(win_no));
0532 
0533     if (!sfb->output_on)
0534         s3c_fb_enable(sfb, 1);
0535 
0536     /* write the buffer address */
0537 
0538     /* start and end registers stride is 8 */
0539     buf = regs + win_no * 8;
0540 
0541     writel(info->fix.smem_start, buf + sfb->variant.buf_start);
0542 
0543     data = info->fix.smem_start + info->fix.line_length * var->yres;
0544     writel(data, buf + sfb->variant.buf_end);
0545 
0546     pagewidth = (var->xres * var->bits_per_pixel) >> 3;
0547     data = VIDW_BUF_SIZE_OFFSET(info->fix.line_length - pagewidth) |
0548            VIDW_BUF_SIZE_PAGEWIDTH(pagewidth) |
0549            VIDW_BUF_SIZE_OFFSET_E(info->fix.line_length - pagewidth) |
0550            VIDW_BUF_SIZE_PAGEWIDTH_E(pagewidth);
0551     writel(data, regs + sfb->variant.buf_size + (win_no * 4));
0552 
0553     /* write 'OSD' registers to control position of framebuffer */
0554 
0555     data = VIDOSDxA_TOPLEFT_X(0) | VIDOSDxA_TOPLEFT_Y(0) |
0556            VIDOSDxA_TOPLEFT_X_E(0) | VIDOSDxA_TOPLEFT_Y_E(0);
0557     writel(data, regs + VIDOSD_A(win_no, sfb->variant));
0558 
0559     data = VIDOSDxB_BOTRIGHT_X(s3c_fb_align_word(var->bits_per_pixel,
0560                              var->xres - 1)) |
0561            VIDOSDxB_BOTRIGHT_Y(var->yres - 1) |
0562            VIDOSDxB_BOTRIGHT_X_E(s3c_fb_align_word(var->bits_per_pixel,
0563                              var->xres - 1)) |
0564            VIDOSDxB_BOTRIGHT_Y_E(var->yres - 1);
0565 
0566     writel(data, regs + VIDOSD_B(win_no, sfb->variant));
0567 
0568     data = var->xres * var->yres;
0569 
0570     alpha = VIDISD14C_ALPHA1_R(0xf) |
0571         VIDISD14C_ALPHA1_G(0xf) |
0572         VIDISD14C_ALPHA1_B(0xf);
0573 
0574     vidosd_set_alpha(win, alpha);
0575     vidosd_set_size(win, data);
0576 
0577     /* Enable DMA channel for this window */
0578     if (sfb->variant.has_shadowcon) {
0579         data = readl(sfb->regs + SHADOWCON);
0580         data |= SHADOWCON_CHx_ENABLE(win_no);
0581         writel(data, sfb->regs + SHADOWCON);
0582     }
0583 
0584     data = WINCONx_ENWIN;
0585     sfb->enabled |= (1 << win->index);
0586 
0587     /* note, since we have to round up the bits-per-pixel, we end up
0588      * relying on the bitfield information for r/g/b/a to work out
0589      * exactly which mode of operation is intended. */
0590 
0591     switch (var->bits_per_pixel) {
0592     case 1:
0593         data |= WINCON0_BPPMODE_1BPP;
0594         data |= WINCONx_BITSWP;
0595         data |= WINCONx_BURSTLEN_4WORD;
0596         break;
0597     case 2:
0598         data |= WINCON0_BPPMODE_2BPP;
0599         data |= WINCONx_BITSWP;
0600         data |= WINCONx_BURSTLEN_8WORD;
0601         break;
0602     case 4:
0603         data |= WINCON0_BPPMODE_4BPP;
0604         data |= WINCONx_BITSWP;
0605         data |= WINCONx_BURSTLEN_8WORD;
0606         break;
0607     case 8:
0608         if (var->transp.length != 0)
0609             data |= WINCON1_BPPMODE_8BPP_1232;
0610         else
0611             data |= WINCON0_BPPMODE_8BPP_PALETTE;
0612         data |= WINCONx_BURSTLEN_8WORD;
0613         data |= WINCONx_BYTSWP;
0614         break;
0615     case 16:
0616         if (var->transp.length != 0)
0617             data |= WINCON1_BPPMODE_16BPP_A1555;
0618         else
0619             data |= WINCON0_BPPMODE_16BPP_565;
0620         data |= WINCONx_HAWSWP;
0621         data |= WINCONx_BURSTLEN_16WORD;
0622         break;
0623     case 24:
0624     case 32:
0625         if (var->red.length == 6) {
0626             if (var->transp.length != 0)
0627                 data |= WINCON1_BPPMODE_19BPP_A1666;
0628             else
0629                 data |= WINCON1_BPPMODE_18BPP_666;
0630         } else if (var->transp.length == 1)
0631             data |= WINCON1_BPPMODE_25BPP_A1888
0632                 | WINCON1_BLD_PIX;
0633         else if ((var->transp.length == 4) ||
0634             (var->transp.length == 8))
0635             data |= WINCON1_BPPMODE_28BPP_A4888
0636                 | WINCON1_BLD_PIX | WINCON1_ALPHA_SEL;
0637         else
0638             data |= WINCON0_BPPMODE_24BPP_888;
0639 
0640         data |= WINCONx_WSWP;
0641         data |= WINCONx_BURSTLEN_16WORD;
0642         break;
0643     }
0644 
0645     /* Enable the colour keying for the window below this one */
0646     if (win_no > 0) {
0647         u32 keycon0_data = 0, keycon1_data = 0;
0648         void __iomem *keycon = regs + sfb->variant.keycon;
0649 
0650         keycon0_data = ~(WxKEYCON0_KEYBL_EN |
0651                 WxKEYCON0_KEYEN_F |
0652                 WxKEYCON0_DIRCON) | WxKEYCON0_COMPKEY(0);
0653 
0654         keycon1_data = WxKEYCON1_COLVAL(0xffffff);
0655 
0656         keycon += (win_no - 1) * 8;
0657 
0658         writel(keycon0_data, keycon + WKEYCON0);
0659         writel(keycon1_data, keycon + WKEYCON1);
0660     }
0661 
0662     writel(data, regs + sfb->variant.wincon + (win_no * 4));
0663     writel(0x0, regs + sfb->variant.winmap + (win_no * 4));
0664 
0665     /* Set alpha value width */
0666     if (sfb->variant.has_blendcon) {
0667         data = readl(sfb->regs + BLENDCON);
0668         data &= ~BLENDCON_NEW_MASK;
0669         if (var->transp.length > 4)
0670             data |= BLENDCON_NEW_8BIT_ALPHA_VALUE;
0671         else
0672             data |= BLENDCON_NEW_4BIT_ALPHA_VALUE;
0673         writel(data, sfb->regs + BLENDCON);
0674     }
0675 
0676     shadow_protect_win(win, 0);
0677 
0678     pm_runtime_put_sync(sfb->dev);
0679 
0680     return 0;
0681 }
0682 
0683 /**
0684  * s3c_fb_update_palette() - set or schedule a palette update.
0685  * @sfb: The hardware information.
0686  * @win: The window being updated.
0687  * @reg: The palette index being changed.
0688  * @value: The computed palette value.
0689  *
0690  * Change the value of a palette register, either by directly writing to
0691  * the palette (this requires the palette RAM to be disconnected from the
0692  * hardware whilst this is in progress) or schedule the update for later.
0693  *
0694  * At the moment, since we have no VSYNC interrupt support, we simply set
0695  * the palette entry directly.
0696  */
0697 static void s3c_fb_update_palette(struct s3c_fb *sfb,
0698                   struct s3c_fb_win *win,
0699                   unsigned int reg,
0700                   u32 value)
0701 {
0702     void __iomem *palreg;
0703     u32 palcon;
0704 
0705     palreg = sfb->regs + sfb->variant.palette[win->index];
0706 
0707     dev_dbg(sfb->dev, "%s: win %d, reg %d (%p): %08x\n",
0708         __func__, win->index, reg, palreg, value);
0709 
0710     win->palette_buffer[reg] = value;
0711 
0712     palcon = readl(sfb->regs + WPALCON);
0713     writel(palcon | WPALCON_PAL_UPDATE, sfb->regs + WPALCON);
0714 
0715     if (win->variant.palette_16bpp)
0716         writew(value, palreg + (reg * 2));
0717     else
0718         writel(value, palreg + (reg * 4));
0719 
0720     writel(palcon, sfb->regs + WPALCON);
0721 }
0722 
0723 static inline unsigned int chan_to_field(unsigned int chan,
0724                      struct fb_bitfield *bf)
0725 {
0726     chan &= 0xffff;
0727     chan >>= 16 - bf->length;
0728     return chan << bf->offset;
0729 }
0730 
0731 /**
0732  * s3c_fb_setcolreg() - framebuffer layer request to change palette.
0733  * @regno: The palette index to change.
0734  * @red: The red field for the palette data.
0735  * @green: The green field for the palette data.
0736  * @blue: The blue field for the palette data.
0737  * @transp: The transparency (alpha) field for the palette data.
0738  * @info: The framebuffer being changed.
0739  */
0740 static int s3c_fb_setcolreg(unsigned regno,
0741                 unsigned red, unsigned green, unsigned blue,
0742                 unsigned transp, struct fb_info *info)
0743 {
0744     struct s3c_fb_win *win = info->par;
0745     struct s3c_fb *sfb = win->parent;
0746     unsigned int val;
0747 
0748     dev_dbg(sfb->dev, "%s: win %d: %d => rgb=%d/%d/%d\n",
0749         __func__, win->index, regno, red, green, blue);
0750 
0751     pm_runtime_get_sync(sfb->dev);
0752 
0753     switch (info->fix.visual) {
0754     case FB_VISUAL_TRUECOLOR:
0755         /* true-colour, use pseudo-palette */
0756 
0757         if (regno < 16) {
0758             u32 *pal = info->pseudo_palette;
0759 
0760             val  = chan_to_field(red,   &info->var.red);
0761             val |= chan_to_field(green, &info->var.green);
0762             val |= chan_to_field(blue,  &info->var.blue);
0763 
0764             pal[regno] = val;
0765         }
0766         break;
0767 
0768     case FB_VISUAL_PSEUDOCOLOR:
0769         if (regno < win->variant.palette_sz) {
0770             val  = chan_to_field(red, &win->palette.r);
0771             val |= chan_to_field(green, &win->palette.g);
0772             val |= chan_to_field(blue, &win->palette.b);
0773 
0774             s3c_fb_update_palette(sfb, win, regno, val);
0775         }
0776 
0777         break;
0778 
0779     default:
0780         pm_runtime_put_sync(sfb->dev);
0781         return 1;   /* unknown type */
0782     }
0783 
0784     pm_runtime_put_sync(sfb->dev);
0785     return 0;
0786 }
0787 
0788 /**
0789  * s3c_fb_blank() - blank or unblank the given window
0790  * @blank_mode: The blank state from FB_BLANK_*
0791  * @info: The framebuffer to blank.
0792  *
0793  * Framebuffer layer request to change the power state.
0794  */
0795 static int s3c_fb_blank(int blank_mode, struct fb_info *info)
0796 {
0797     struct s3c_fb_win *win = info->par;
0798     struct s3c_fb *sfb = win->parent;
0799     unsigned int index = win->index;
0800     u32 wincon;
0801     u32 output_on = sfb->output_on;
0802 
0803     dev_dbg(sfb->dev, "blank mode %d\n", blank_mode);
0804 
0805     pm_runtime_get_sync(sfb->dev);
0806 
0807     wincon = readl(sfb->regs + sfb->variant.wincon + (index * 4));
0808 
0809     switch (blank_mode) {
0810     case FB_BLANK_POWERDOWN:
0811         wincon &= ~WINCONx_ENWIN;
0812         sfb->enabled &= ~(1 << index);
0813         fallthrough;    /* to FB_BLANK_NORMAL */
0814 
0815     case FB_BLANK_NORMAL:
0816         /* disable the DMA and display 0x0 (black) */
0817         shadow_protect_win(win, 1);
0818         writel(WINxMAP_MAP | WINxMAP_MAP_COLOUR(0x0),
0819                sfb->regs + sfb->variant.winmap + (index * 4));
0820         shadow_protect_win(win, 0);
0821         break;
0822 
0823     case FB_BLANK_UNBLANK:
0824         shadow_protect_win(win, 1);
0825         writel(0x0, sfb->regs + sfb->variant.winmap + (index * 4));
0826         shadow_protect_win(win, 0);
0827         wincon |= WINCONx_ENWIN;
0828         sfb->enabled |= (1 << index);
0829         break;
0830 
0831     case FB_BLANK_VSYNC_SUSPEND:
0832     case FB_BLANK_HSYNC_SUSPEND:
0833     default:
0834         pm_runtime_put_sync(sfb->dev);
0835         return 1;
0836     }
0837 
0838     shadow_protect_win(win, 1);
0839     writel(wincon, sfb->regs + sfb->variant.wincon + (index * 4));
0840 
0841     /* Check the enabled state to see if we need to be running the
0842      * main LCD interface, as if there are no active windows then
0843      * it is highly likely that we also do not need to output
0844      * anything.
0845      */
0846     s3c_fb_enable(sfb, sfb->enabled ? 1 : 0);
0847     shadow_protect_win(win, 0);
0848 
0849     pm_runtime_put_sync(sfb->dev);
0850 
0851     return output_on == sfb->output_on;
0852 }
0853 
0854 /**
0855  * s3c_fb_pan_display() - Pan the display.
0856  *
0857  * Note that the offsets can be written to the device at any time, as their
0858  * values are latched at each vsync automatically. This also means that only
0859  * the last call to this function will have any effect on next vsync, but
0860  * there is no need to sleep waiting for it to prevent tearing.
0861  *
0862  * @var: The screen information to verify.
0863  * @info: The framebuffer device.
0864  */
0865 static int s3c_fb_pan_display(struct fb_var_screeninfo *var,
0866                   struct fb_info *info)
0867 {
0868     struct s3c_fb_win *win  = info->par;
0869     struct s3c_fb *sfb  = win->parent;
0870     void __iomem *buf   = sfb->regs + win->index * 8;
0871     unsigned int start_boff, end_boff;
0872 
0873     pm_runtime_get_sync(sfb->dev);
0874 
0875     /* Offset in bytes to the start of the displayed area */
0876     start_boff = var->yoffset * info->fix.line_length;
0877     /* X offset depends on the current bpp */
0878     if (info->var.bits_per_pixel >= 8) {
0879         start_boff += var->xoffset * (info->var.bits_per_pixel >> 3);
0880     } else {
0881         switch (info->var.bits_per_pixel) {
0882         case 4:
0883             start_boff += var->xoffset >> 1;
0884             break;
0885         case 2:
0886             start_boff += var->xoffset >> 2;
0887             break;
0888         case 1:
0889             start_boff += var->xoffset >> 3;
0890             break;
0891         default:
0892             dev_err(sfb->dev, "invalid bpp\n");
0893             pm_runtime_put_sync(sfb->dev);
0894             return -EINVAL;
0895         }
0896     }
0897     /* Offset in bytes to the end of the displayed area */
0898     end_boff = start_boff + info->var.yres * info->fix.line_length;
0899 
0900     /* Temporarily turn off per-vsync update from shadow registers until
0901      * both start and end addresses are updated to prevent corruption */
0902     shadow_protect_win(win, 1);
0903 
0904     writel(info->fix.smem_start + start_boff, buf + sfb->variant.buf_start);
0905     writel(info->fix.smem_start + end_boff, buf + sfb->variant.buf_end);
0906 
0907     shadow_protect_win(win, 0);
0908 
0909     pm_runtime_put_sync(sfb->dev);
0910     return 0;
0911 }
0912 
0913 /**
0914  * s3c_fb_enable_irq() - enable framebuffer interrupts
0915  * @sfb: main hardware state
0916  */
0917 static void s3c_fb_enable_irq(struct s3c_fb *sfb)
0918 {
0919     void __iomem *regs = sfb->regs;
0920     u32 irq_ctrl_reg;
0921 
0922     if (!test_and_set_bit(S3C_FB_VSYNC_IRQ_EN, &sfb->irq_flags)) {
0923         /* IRQ disabled, enable it */
0924         irq_ctrl_reg = readl(regs + VIDINTCON0);
0925 
0926         irq_ctrl_reg |= VIDINTCON0_INT_ENABLE;
0927         irq_ctrl_reg |= VIDINTCON0_INT_FRAME;
0928 
0929         irq_ctrl_reg &= ~VIDINTCON0_FRAMESEL0_MASK;
0930         irq_ctrl_reg |= VIDINTCON0_FRAMESEL0_VSYNC;
0931         irq_ctrl_reg &= ~VIDINTCON0_FRAMESEL1_MASK;
0932         irq_ctrl_reg |= VIDINTCON0_FRAMESEL1_NONE;
0933 
0934         writel(irq_ctrl_reg, regs + VIDINTCON0);
0935     }
0936 }
0937 
0938 /**
0939  * s3c_fb_disable_irq() - disable framebuffer interrupts
0940  * @sfb: main hardware state
0941  */
0942 static void s3c_fb_disable_irq(struct s3c_fb *sfb)
0943 {
0944     void __iomem *regs = sfb->regs;
0945     u32 irq_ctrl_reg;
0946 
0947     if (test_and_clear_bit(S3C_FB_VSYNC_IRQ_EN, &sfb->irq_flags)) {
0948         /* IRQ enabled, disable it */
0949         irq_ctrl_reg = readl(regs + VIDINTCON0);
0950 
0951         irq_ctrl_reg &= ~VIDINTCON0_INT_FRAME;
0952         irq_ctrl_reg &= ~VIDINTCON0_INT_ENABLE;
0953 
0954         writel(irq_ctrl_reg, regs + VIDINTCON0);
0955     }
0956 }
0957 
0958 static irqreturn_t s3c_fb_irq(int irq, void *dev_id)
0959 {
0960     struct s3c_fb *sfb = dev_id;
0961     void __iomem  *regs = sfb->regs;
0962     u32 irq_sts_reg;
0963 
0964     spin_lock(&sfb->slock);
0965 
0966     irq_sts_reg = readl(regs + VIDINTCON1);
0967 
0968     if (irq_sts_reg & VIDINTCON1_INT_FRAME) {
0969 
0970         /* VSYNC interrupt, accept it */
0971         writel(VIDINTCON1_INT_FRAME, regs + VIDINTCON1);
0972 
0973         sfb->vsync_info.count++;
0974         wake_up_interruptible(&sfb->vsync_info.wait);
0975     }
0976 
0977     /* We only support waiting for VSYNC for now, so it's safe
0978      * to always disable irqs here.
0979      */
0980     s3c_fb_disable_irq(sfb);
0981 
0982     spin_unlock(&sfb->slock);
0983     return IRQ_HANDLED;
0984 }
0985 
0986 /**
0987  * s3c_fb_wait_for_vsync() - sleep until next VSYNC interrupt or timeout
0988  * @sfb: main hardware state
0989  * @crtc: head index.
0990  */
0991 static int s3c_fb_wait_for_vsync(struct s3c_fb *sfb, u32 crtc)
0992 {
0993     unsigned long count;
0994     int ret;
0995 
0996     if (crtc != 0)
0997         return -ENODEV;
0998 
0999     pm_runtime_get_sync(sfb->dev);
1000 
1001     count = sfb->vsync_info.count;
1002     s3c_fb_enable_irq(sfb);
1003     ret = wait_event_interruptible_timeout(sfb->vsync_info.wait,
1004                        count != sfb->vsync_info.count,
1005                        msecs_to_jiffies(VSYNC_TIMEOUT_MSEC));
1006 
1007     pm_runtime_put_sync(sfb->dev);
1008 
1009     if (ret == 0)
1010         return -ETIMEDOUT;
1011 
1012     return 0;
1013 }
1014 
1015 static int s3c_fb_ioctl(struct fb_info *info, unsigned int cmd,
1016             unsigned long arg)
1017 {
1018     struct s3c_fb_win *win = info->par;
1019     struct s3c_fb *sfb = win->parent;
1020     int ret;
1021     u32 crtc;
1022 
1023     switch (cmd) {
1024     case FBIO_WAITFORVSYNC:
1025         if (get_user(crtc, (u32 __user *)arg)) {
1026             ret = -EFAULT;
1027             break;
1028         }
1029 
1030         ret = s3c_fb_wait_for_vsync(sfb, crtc);
1031         break;
1032     default:
1033         ret = -ENOTTY;
1034     }
1035 
1036     return ret;
1037 }
1038 
1039 static const struct fb_ops s3c_fb_ops = {
1040     .owner      = THIS_MODULE,
1041     .fb_check_var   = s3c_fb_check_var,
1042     .fb_set_par = s3c_fb_set_par,
1043     .fb_blank   = s3c_fb_blank,
1044     .fb_setcolreg   = s3c_fb_setcolreg,
1045     .fb_fillrect    = cfb_fillrect,
1046     .fb_copyarea    = cfb_copyarea,
1047     .fb_imageblit   = cfb_imageblit,
1048     .fb_pan_display = s3c_fb_pan_display,
1049     .fb_ioctl   = s3c_fb_ioctl,
1050 };
1051 
1052 /**
1053  * s3c_fb_missing_pixclock() - calculates pixel clock
1054  * @mode: The video mode to change.
1055  *
1056  * Calculate the pixel clock when none has been given through platform data.
1057  */
1058 static void s3c_fb_missing_pixclock(struct fb_videomode *mode)
1059 {
1060     u64 pixclk = 1000000000000ULL;
1061     u32 div;
1062 
1063     div  = mode->left_margin + mode->hsync_len + mode->right_margin +
1064            mode->xres;
1065     div *= mode->upper_margin + mode->vsync_len + mode->lower_margin +
1066            mode->yres;
1067     div *= mode->refresh ? : 60;
1068 
1069     do_div(pixclk, div);
1070 
1071     mode->pixclock = pixclk;
1072 }
1073 
1074 /**
1075  * s3c_fb_alloc_memory() - allocate display memory for framebuffer window
1076  * @sfb: The base resources for the hardware.
1077  * @win: The window to initialise memory for.
1078  *
1079  * Allocate memory for the given framebuffer.
1080  */
1081 static int s3c_fb_alloc_memory(struct s3c_fb *sfb, struct s3c_fb_win *win)
1082 {
1083     struct s3c_fb_pd_win *windata = win->windata;
1084     unsigned int real_size, virt_size, size;
1085     struct fb_info *fbi = win->fbinfo;
1086     dma_addr_t map_dma;
1087 
1088     dev_dbg(sfb->dev, "allocating memory for display\n");
1089 
1090     real_size = windata->xres * windata->yres;
1091     virt_size = windata->virtual_x * windata->virtual_y;
1092 
1093     dev_dbg(sfb->dev, "real_size=%u (%u.%u), virt_size=%u (%u.%u)\n",
1094         real_size, windata->xres, windata->yres,
1095         virt_size, windata->virtual_x, windata->virtual_y);
1096 
1097     size = (real_size > virt_size) ? real_size : virt_size;
1098     size *= (windata->max_bpp > 16) ? 32 : windata->max_bpp;
1099     size /= 8;
1100 
1101     fbi->fix.smem_len = size;
1102     size = PAGE_ALIGN(size);
1103 
1104     dev_dbg(sfb->dev, "want %u bytes for window\n", size);
1105 
1106     fbi->screen_buffer = dma_alloc_wc(sfb->dev, size, &map_dma, GFP_KERNEL);
1107     if (!fbi->screen_buffer)
1108         return -ENOMEM;
1109 
1110     dev_dbg(sfb->dev, "mapped %x to %p\n",
1111         (unsigned int)map_dma, fbi->screen_buffer);
1112 
1113     memset(fbi->screen_buffer, 0x0, size);
1114     fbi->fix.smem_start = map_dma;
1115 
1116     return 0;
1117 }
1118 
1119 /**
1120  * s3c_fb_free_memory() - free the display memory for the given window
1121  * @sfb: The base resources for the hardware.
1122  * @win: The window to free the display memory for.
1123  *
1124  * Free the display memory allocated by s3c_fb_alloc_memory().
1125  */
1126 static void s3c_fb_free_memory(struct s3c_fb *sfb, struct s3c_fb_win *win)
1127 {
1128     struct fb_info *fbi = win->fbinfo;
1129 
1130     if (fbi->screen_buffer)
1131         dma_free_wc(sfb->dev, PAGE_ALIGN(fbi->fix.smem_len),
1132                 fbi->screen_buffer, fbi->fix.smem_start);
1133 }
1134 
1135 /**
1136  * s3c_fb_release_win() - release resources for a framebuffer window.
1137  * @sfb: The base resources for the hardware.
1138  * @win: The window to cleanup the resources for.
1139  *
1140  * Release the resources that where claimed for the hardware window,
1141  * such as the framebuffer instance and any memory claimed for it.
1142  */
1143 static void s3c_fb_release_win(struct s3c_fb *sfb, struct s3c_fb_win *win)
1144 {
1145     u32 data;
1146 
1147     if (win->fbinfo) {
1148         if (sfb->variant.has_shadowcon) {
1149             data = readl(sfb->regs + SHADOWCON);
1150             data &= ~SHADOWCON_CHx_ENABLE(win->index);
1151             data &= ~SHADOWCON_CHx_LOCAL_ENABLE(win->index);
1152             writel(data, sfb->regs + SHADOWCON);
1153         }
1154         unregister_framebuffer(win->fbinfo);
1155         if (win->fbinfo->cmap.len)
1156             fb_dealloc_cmap(&win->fbinfo->cmap);
1157         s3c_fb_free_memory(sfb, win);
1158         framebuffer_release(win->fbinfo);
1159     }
1160 }
1161 
1162 /**
1163  * s3c_fb_probe_win() - register an hardware window
1164  * @sfb: The base resources for the hardware
1165  * @win_no: The window number
1166  * @variant: The variant information for this window.
1167  * @res: Pointer to where to place the resultant window.
1168  *
1169  * Allocate and do the basic initialisation for one of the hardware's graphics
1170  * windows.
1171  */
1172 static int s3c_fb_probe_win(struct s3c_fb *sfb, unsigned int win_no,
1173                 struct s3c_fb_win_variant *variant,
1174                 struct s3c_fb_win **res)
1175 {
1176     struct fb_videomode initmode;
1177     struct s3c_fb_pd_win *windata;
1178     struct s3c_fb_win *win;
1179     struct fb_info *fbinfo;
1180     int palette_size;
1181     int ret;
1182 
1183     dev_dbg(sfb->dev, "probing window %d, variant %p\n", win_no, variant);
1184 
1185     init_waitqueue_head(&sfb->vsync_info.wait);
1186 
1187     palette_size = variant->palette_sz * 4;
1188 
1189     fbinfo = framebuffer_alloc(sizeof(struct s3c_fb_win) +
1190                    palette_size * sizeof(u32), sfb->dev);
1191     if (!fbinfo)
1192         return -ENOMEM;
1193 
1194     windata = sfb->pdata->win[win_no];
1195     initmode = *sfb->pdata->vtiming;
1196 
1197     WARN_ON(windata->max_bpp == 0);
1198     WARN_ON(windata->xres == 0);
1199     WARN_ON(windata->yres == 0);
1200 
1201     win = fbinfo->par;
1202     *res = win;
1203     win->variant = *variant;
1204     win->fbinfo = fbinfo;
1205     win->parent = sfb;
1206     win->windata = windata;
1207     win->index = win_no;
1208     win->palette_buffer = (u32 *)(win + 1);
1209 
1210     ret = s3c_fb_alloc_memory(sfb, win);
1211     if (ret) {
1212         dev_err(sfb->dev, "failed to allocate display memory\n");
1213         return ret;
1214     }
1215 
1216     /* setup the r/b/g positions for the window's palette */
1217     if (win->variant.palette_16bpp) {
1218         /* Set RGB 5:6:5 as default */
1219         win->palette.r.offset = 11;
1220         win->palette.r.length = 5;
1221         win->palette.g.offset = 5;
1222         win->palette.g.length = 6;
1223         win->palette.b.offset = 0;
1224         win->palette.b.length = 5;
1225 
1226     } else {
1227         /* Set 8bpp or 8bpp and 1bit alpha */
1228         win->palette.r.offset = 16;
1229         win->palette.r.length = 8;
1230         win->palette.g.offset = 8;
1231         win->palette.g.length = 8;
1232         win->palette.b.offset = 0;
1233         win->palette.b.length = 8;
1234     }
1235 
1236     /* setup the initial video mode from the window */
1237     initmode.xres = windata->xres;
1238     initmode.yres = windata->yres;
1239     fb_videomode_to_var(&fbinfo->var, &initmode);
1240 
1241     fbinfo->fix.type    = FB_TYPE_PACKED_PIXELS;
1242     fbinfo->fix.accel   = FB_ACCEL_NONE;
1243     fbinfo->var.activate    = FB_ACTIVATE_NOW;
1244     fbinfo->var.vmode   = FB_VMODE_NONINTERLACED;
1245     fbinfo->var.bits_per_pixel = windata->default_bpp;
1246     fbinfo->fbops       = &s3c_fb_ops;
1247     fbinfo->flags       = FBINFO_FLAG_DEFAULT;
1248     fbinfo->pseudo_palette  = &win->pseudo_palette;
1249 
1250     /* prepare to actually start the framebuffer */
1251 
1252     ret = s3c_fb_check_var(&fbinfo->var, fbinfo);
1253     if (ret < 0) {
1254         dev_err(sfb->dev, "check_var failed on initial video params\n");
1255         return ret;
1256     }
1257 
1258     /* create initial colour map */
1259 
1260     ret = fb_alloc_cmap(&fbinfo->cmap, win->variant.palette_sz, 1);
1261     if (ret == 0)
1262         fb_set_cmap(&fbinfo->cmap, fbinfo);
1263     else
1264         dev_err(sfb->dev, "failed to allocate fb cmap\n");
1265 
1266     s3c_fb_set_par(fbinfo);
1267 
1268     dev_dbg(sfb->dev, "about to register framebuffer\n");
1269 
1270     /* run the check_var and set_par on our configuration. */
1271 
1272     ret = register_framebuffer(fbinfo);
1273     if (ret < 0) {
1274         dev_err(sfb->dev, "failed to register framebuffer\n");
1275         return ret;
1276     }
1277 
1278     dev_info(sfb->dev, "window %d: fb %s\n", win_no, fbinfo->fix.id);
1279 
1280     return 0;
1281 }
1282 
1283 /**
1284  * s3c_fb_set_rgb_timing() - set video timing for rgb interface.
1285  * @sfb: The base resources for the hardware.
1286  *
1287  * Set horizontal and vertical lcd rgb interface timing.
1288  */
1289 static void s3c_fb_set_rgb_timing(struct s3c_fb *sfb)
1290 {
1291     struct fb_videomode *vmode = sfb->pdata->vtiming;
1292     void __iomem *regs = sfb->regs;
1293     int clkdiv;
1294     u32 data;
1295 
1296     if (!vmode->pixclock)
1297         s3c_fb_missing_pixclock(vmode);
1298 
1299     clkdiv = s3c_fb_calc_pixclk(sfb, vmode->pixclock);
1300 
1301     data = sfb->pdata->vidcon0;
1302     data &= ~(VIDCON0_CLKVAL_F_MASK | VIDCON0_CLKDIR);
1303 
1304     if (clkdiv > 1)
1305         data |= VIDCON0_CLKVAL_F(clkdiv-1) | VIDCON0_CLKDIR;
1306     else
1307         data &= ~VIDCON0_CLKDIR;    /* 1:1 clock */
1308 
1309     if (sfb->variant.is_2443)
1310         data |= (1 << 5);
1311     writel(data, regs + VIDCON0);
1312 
1313     data = VIDTCON0_VBPD(vmode->upper_margin - 1) |
1314            VIDTCON0_VFPD(vmode->lower_margin - 1) |
1315            VIDTCON0_VSPW(vmode->vsync_len - 1);
1316     writel(data, regs + sfb->variant.vidtcon);
1317 
1318     data = VIDTCON1_HBPD(vmode->left_margin - 1) |
1319            VIDTCON1_HFPD(vmode->right_margin - 1) |
1320            VIDTCON1_HSPW(vmode->hsync_len - 1);
1321     writel(data, regs + sfb->variant.vidtcon + 4);
1322 
1323     data = VIDTCON2_LINEVAL(vmode->yres - 1) |
1324            VIDTCON2_HOZVAL(vmode->xres - 1) |
1325            VIDTCON2_LINEVAL_E(vmode->yres - 1) |
1326            VIDTCON2_HOZVAL_E(vmode->xres - 1);
1327     writel(data, regs + sfb->variant.vidtcon + 8);
1328 }
1329 
1330 /**
1331  * s3c_fb_clear_win() - clear hardware window registers.
1332  * @sfb: The base resources for the hardware.
1333  * @win: The window to process.
1334  *
1335  * Reset the specific window registers to a known state.
1336  */
1337 static void s3c_fb_clear_win(struct s3c_fb *sfb, int win)
1338 {
1339     void __iomem *regs = sfb->regs;
1340     u32 reg;
1341 
1342     writel(0, regs + sfb->variant.wincon + (win * 4));
1343     writel(0, regs + VIDOSD_A(win, sfb->variant));
1344     writel(0, regs + VIDOSD_B(win, sfb->variant));
1345     writel(0, regs + VIDOSD_C(win, sfb->variant));
1346 
1347     if (sfb->variant.has_shadowcon) {
1348         reg = readl(sfb->regs + SHADOWCON);
1349         reg &= ~(SHADOWCON_WINx_PROTECT(win) |
1350             SHADOWCON_CHx_ENABLE(win) |
1351             SHADOWCON_CHx_LOCAL_ENABLE(win));
1352         writel(reg, sfb->regs + SHADOWCON);
1353     }
1354 }
1355 
1356 static int s3c_fb_probe(struct platform_device *pdev)
1357 {
1358     const struct platform_device_id *platid;
1359     struct s3c_fb_driverdata *fbdrv;
1360     struct device *dev = &pdev->dev;
1361     struct s3c_fb_platdata *pd;
1362     struct s3c_fb *sfb;
1363     int win;
1364     int ret = 0;
1365     u32 reg;
1366 
1367     platid = platform_get_device_id(pdev);
1368     fbdrv = (struct s3c_fb_driverdata *)platid->driver_data;
1369 
1370     if (fbdrv->variant.nr_windows > S3C_FB_MAX_WIN) {
1371         dev_err(dev, "too many windows, cannot attach\n");
1372         return -EINVAL;
1373     }
1374 
1375     pd = dev_get_platdata(&pdev->dev);
1376     if (!pd) {
1377         dev_err(dev, "no platform data specified\n");
1378         return -EINVAL;
1379     }
1380 
1381     sfb = devm_kzalloc(dev, sizeof(*sfb), GFP_KERNEL);
1382     if (!sfb)
1383         return -ENOMEM;
1384 
1385     dev_dbg(dev, "allocate new framebuffer %p\n", sfb);
1386 
1387     sfb->dev = dev;
1388     sfb->pdata = pd;
1389     sfb->variant = fbdrv->variant;
1390 
1391     spin_lock_init(&sfb->slock);
1392 
1393     sfb->bus_clk = devm_clk_get(dev, "lcd");
1394     if (IS_ERR(sfb->bus_clk))
1395         return dev_err_probe(dev, PTR_ERR(sfb->bus_clk),
1396                      "failed to get bus clock\n");
1397 
1398     clk_prepare_enable(sfb->bus_clk);
1399 
1400     if (!sfb->variant.has_clksel) {
1401         sfb->lcd_clk = devm_clk_get(dev, "sclk_fimd");
1402         if (IS_ERR(sfb->lcd_clk)) {
1403             ret = dev_err_probe(dev, PTR_ERR(sfb->lcd_clk),
1404                         "failed to get lcd clock\n");
1405             goto err_bus_clk;
1406         }
1407 
1408         clk_prepare_enable(sfb->lcd_clk);
1409     }
1410 
1411     pm_runtime_enable(sfb->dev);
1412 
1413     sfb->regs = devm_platform_ioremap_resource(pdev, 0);
1414     if (IS_ERR(sfb->regs)) {
1415         ret = PTR_ERR(sfb->regs);
1416         goto err_lcd_clk;
1417     }
1418 
1419     sfb->irq_no = platform_get_irq(pdev, 0);
1420     if (sfb->irq_no < 0) {
1421         ret = -ENOENT;
1422         goto err_lcd_clk;
1423     }
1424 
1425     ret = devm_request_irq(dev, sfb->irq_no, s3c_fb_irq,
1426               0, "s3c_fb", sfb);
1427     if (ret) {
1428         dev_err(dev, "irq request failed\n");
1429         goto err_lcd_clk;
1430     }
1431 
1432     dev_dbg(dev, "got resources (regs %p), probing windows\n", sfb->regs);
1433 
1434     platform_set_drvdata(pdev, sfb);
1435     pm_runtime_get_sync(sfb->dev);
1436 
1437     /* setup gpio and output polarity controls */
1438 
1439     pd->setup_gpio();
1440 
1441     writel(pd->vidcon1, sfb->regs + VIDCON1);
1442 
1443     /* set video clock running at under-run */
1444     if (sfb->variant.has_fixvclk) {
1445         reg = readl(sfb->regs + VIDCON1);
1446         reg &= ~VIDCON1_VCLK_MASK;
1447         reg |= VIDCON1_VCLK_RUN;
1448         writel(reg, sfb->regs + VIDCON1);
1449     }
1450 
1451     /* zero all windows before we do anything */
1452 
1453     for (win = 0; win < fbdrv->variant.nr_windows; win++)
1454         s3c_fb_clear_win(sfb, win);
1455 
1456     /* initialise colour key controls */
1457     for (win = 0; win < (fbdrv->variant.nr_windows - 1); win++) {
1458         void __iomem *regs = sfb->regs + sfb->variant.keycon;
1459 
1460         regs += (win * 8);
1461         writel(0xffffff, regs + WKEYCON0);
1462         writel(0xffffff, regs + WKEYCON1);
1463     }
1464 
1465     s3c_fb_set_rgb_timing(sfb);
1466 
1467     /* we have the register setup, start allocating framebuffers */
1468 
1469     for (win = 0; win < fbdrv->variant.nr_windows; win++) {
1470         if (!pd->win[win])
1471             continue;
1472 
1473         ret = s3c_fb_probe_win(sfb, win, fbdrv->win[win],
1474                        &sfb->windows[win]);
1475         if (ret < 0) {
1476             dev_err(dev, "failed to create window %d\n", win);
1477             for (; win >= 0; win--)
1478                 s3c_fb_release_win(sfb, sfb->windows[win]);
1479             goto err_pm_runtime;
1480         }
1481     }
1482 
1483     platform_set_drvdata(pdev, sfb);
1484     pm_runtime_put_sync(sfb->dev);
1485 
1486     return 0;
1487 
1488 err_pm_runtime:
1489     pm_runtime_put_sync(sfb->dev);
1490 
1491 err_lcd_clk:
1492     pm_runtime_disable(sfb->dev);
1493 
1494     if (!sfb->variant.has_clksel)
1495         clk_disable_unprepare(sfb->lcd_clk);
1496 
1497 err_bus_clk:
1498     clk_disable_unprepare(sfb->bus_clk);
1499 
1500     return ret;
1501 }
1502 
1503 /**
1504  * s3c_fb_remove() - Cleanup on module finalisation
1505  * @pdev: The platform device we are bound to.
1506  *
1507  * Shutdown and then release all the resources that the driver allocated
1508  * on initialisation.
1509  */
1510 static int s3c_fb_remove(struct platform_device *pdev)
1511 {
1512     struct s3c_fb *sfb = platform_get_drvdata(pdev);
1513     int win;
1514 
1515     pm_runtime_get_sync(sfb->dev);
1516 
1517     for (win = 0; win < S3C_FB_MAX_WIN; win++)
1518         if (sfb->windows[win])
1519             s3c_fb_release_win(sfb, sfb->windows[win]);
1520 
1521     if (!sfb->variant.has_clksel)
1522         clk_disable_unprepare(sfb->lcd_clk);
1523 
1524     clk_disable_unprepare(sfb->bus_clk);
1525 
1526     pm_runtime_put_sync(sfb->dev);
1527     pm_runtime_disable(sfb->dev);
1528 
1529     return 0;
1530 }
1531 
1532 #ifdef CONFIG_PM_SLEEP
1533 static int s3c_fb_suspend(struct device *dev)
1534 {
1535     struct s3c_fb *sfb = dev_get_drvdata(dev);
1536     struct s3c_fb_win *win;
1537     int win_no;
1538 
1539     pm_runtime_get_sync(sfb->dev);
1540 
1541     for (win_no = S3C_FB_MAX_WIN - 1; win_no >= 0; win_no--) {
1542         win = sfb->windows[win_no];
1543         if (!win)
1544             continue;
1545 
1546         /* use the blank function to push into power-down */
1547         s3c_fb_blank(FB_BLANK_POWERDOWN, win->fbinfo);
1548     }
1549 
1550     if (!sfb->variant.has_clksel)
1551         clk_disable_unprepare(sfb->lcd_clk);
1552 
1553     clk_disable_unprepare(sfb->bus_clk);
1554 
1555     pm_runtime_put_sync(sfb->dev);
1556 
1557     return 0;
1558 }
1559 
1560 static int s3c_fb_resume(struct device *dev)
1561 {
1562     struct s3c_fb *sfb = dev_get_drvdata(dev);
1563     struct s3c_fb_platdata *pd = sfb->pdata;
1564     struct s3c_fb_win *win;
1565     int win_no;
1566     u32 reg;
1567 
1568     pm_runtime_get_sync(sfb->dev);
1569 
1570     clk_prepare_enable(sfb->bus_clk);
1571 
1572     if (!sfb->variant.has_clksel)
1573         clk_prepare_enable(sfb->lcd_clk);
1574 
1575     /* setup gpio and output polarity controls */
1576     pd->setup_gpio();
1577     writel(pd->vidcon1, sfb->regs + VIDCON1);
1578 
1579     /* set video clock running at under-run */
1580     if (sfb->variant.has_fixvclk) {
1581         reg = readl(sfb->regs + VIDCON1);
1582         reg &= ~VIDCON1_VCLK_MASK;
1583         reg |= VIDCON1_VCLK_RUN;
1584         writel(reg, sfb->regs + VIDCON1);
1585     }
1586 
1587     /* zero all windows before we do anything */
1588     for (win_no = 0; win_no < sfb->variant.nr_windows; win_no++)
1589         s3c_fb_clear_win(sfb, win_no);
1590 
1591     for (win_no = 0; win_no < sfb->variant.nr_windows - 1; win_no++) {
1592         void __iomem *regs = sfb->regs + sfb->variant.keycon;
1593         win = sfb->windows[win_no];
1594         if (!win)
1595             continue;
1596 
1597         shadow_protect_win(win, 1);
1598         regs += (win_no * 8);
1599         writel(0xffffff, regs + WKEYCON0);
1600         writel(0xffffff, regs + WKEYCON1);
1601         shadow_protect_win(win, 0);
1602     }
1603 
1604     s3c_fb_set_rgb_timing(sfb);
1605 
1606     /* restore framebuffers */
1607     for (win_no = 0; win_no < S3C_FB_MAX_WIN; win_no++) {
1608         win = sfb->windows[win_no];
1609         if (!win)
1610             continue;
1611 
1612         dev_dbg(dev, "resuming window %d\n", win_no);
1613         s3c_fb_set_par(win->fbinfo);
1614     }
1615 
1616     pm_runtime_put_sync(sfb->dev);
1617 
1618     return 0;
1619 }
1620 #endif
1621 
1622 #ifdef CONFIG_PM
1623 static int s3c_fb_runtime_suspend(struct device *dev)
1624 {
1625     struct s3c_fb *sfb = dev_get_drvdata(dev);
1626 
1627     if (!sfb->variant.has_clksel)
1628         clk_disable_unprepare(sfb->lcd_clk);
1629 
1630     clk_disable_unprepare(sfb->bus_clk);
1631 
1632     return 0;
1633 }
1634 
1635 static int s3c_fb_runtime_resume(struct device *dev)
1636 {
1637     struct s3c_fb *sfb = dev_get_drvdata(dev);
1638     struct s3c_fb_platdata *pd = sfb->pdata;
1639 
1640     clk_prepare_enable(sfb->bus_clk);
1641 
1642     if (!sfb->variant.has_clksel)
1643         clk_prepare_enable(sfb->lcd_clk);
1644 
1645     /* setup gpio and output polarity controls */
1646     pd->setup_gpio();
1647     writel(pd->vidcon1, sfb->regs + VIDCON1);
1648 
1649     return 0;
1650 }
1651 #endif
1652 
1653 #define VALID_BPP124 (VALID_BPP(1) | VALID_BPP(2) | VALID_BPP(4))
1654 #define VALID_BPP1248 (VALID_BPP124 | VALID_BPP(8))
1655 
1656 static struct s3c_fb_win_variant s3c_fb_data_64xx_wins[] = {
1657     [0] = {
1658         .has_osd_c  = 1,
1659         .osd_size_off   = 0x8,
1660         .palette_sz = 256,
1661         .valid_bpp  = (VALID_BPP1248 | VALID_BPP(16) |
1662                    VALID_BPP(18) | VALID_BPP(24)),
1663     },
1664     [1] = {
1665         .has_osd_c  = 1,
1666         .has_osd_d  = 1,
1667         .osd_size_off   = 0xc,
1668         .has_osd_alpha  = 1,
1669         .palette_sz = 256,
1670         .valid_bpp  = (VALID_BPP1248 | VALID_BPP(16) |
1671                    VALID_BPP(18) | VALID_BPP(19) |
1672                    VALID_BPP(24) | VALID_BPP(25) |
1673                    VALID_BPP(28)),
1674     },
1675     [2] = {
1676         .has_osd_c  = 1,
1677         .has_osd_d  = 1,
1678         .osd_size_off   = 0xc,
1679         .has_osd_alpha  = 1,
1680         .palette_sz = 16,
1681         .palette_16bpp  = 1,
1682         .valid_bpp  = (VALID_BPP1248 | VALID_BPP(16) |
1683                    VALID_BPP(18) | VALID_BPP(19) |
1684                    VALID_BPP(24) | VALID_BPP(25) |
1685                    VALID_BPP(28)),
1686     },
1687     [3] = {
1688         .has_osd_c  = 1,
1689         .has_osd_alpha  = 1,
1690         .palette_sz = 16,
1691         .palette_16bpp  = 1,
1692         .valid_bpp  = (VALID_BPP124  | VALID_BPP(16) |
1693                    VALID_BPP(18) | VALID_BPP(19) |
1694                    VALID_BPP(24) | VALID_BPP(25) |
1695                    VALID_BPP(28)),
1696     },
1697     [4] = {
1698         .has_osd_c  = 1,
1699         .has_osd_alpha  = 1,
1700         .palette_sz = 4,
1701         .palette_16bpp  = 1,
1702         .valid_bpp  = (VALID_BPP(1) | VALID_BPP(2) |
1703                    VALID_BPP(16) | VALID_BPP(18) |
1704                    VALID_BPP(19) | VALID_BPP(24) |
1705                    VALID_BPP(25) | VALID_BPP(28)),
1706     },
1707 };
1708 
1709 static struct s3c_fb_driverdata s3c_fb_data_64xx = {
1710     .variant = {
1711         .nr_windows = 5,
1712         .vidtcon    = VIDTCON0,
1713         .wincon     = WINCON(0),
1714         .winmap     = WINxMAP(0),
1715         .keycon     = WKEYCON,
1716         .osd        = VIDOSD_BASE,
1717         .osd_stride = 16,
1718         .buf_start  = VIDW_BUF_START(0),
1719         .buf_size   = VIDW_BUF_SIZE(0),
1720         .buf_end    = VIDW_BUF_END(0),
1721 
1722         .palette = {
1723             [0] = 0x400,
1724             [1] = 0x800,
1725             [2] = 0x300,
1726             [3] = 0x320,
1727             [4] = 0x340,
1728         },
1729 
1730         .has_prtcon = 1,
1731         .has_clksel = 1,
1732     },
1733     .win[0] = &s3c_fb_data_64xx_wins[0],
1734     .win[1] = &s3c_fb_data_64xx_wins[1],
1735     .win[2] = &s3c_fb_data_64xx_wins[2],
1736     .win[3] = &s3c_fb_data_64xx_wins[3],
1737     .win[4] = &s3c_fb_data_64xx_wins[4],
1738 };
1739 
1740 /* S3C2443/S3C2416 style hardware */
1741 static struct s3c_fb_driverdata s3c_fb_data_s3c2443 = {
1742     .variant = {
1743         .nr_windows = 2,
1744         .is_2443    = 1,
1745 
1746         .vidtcon    = 0x08,
1747         .wincon     = 0x14,
1748         .winmap     = 0xd0,
1749         .keycon     = 0xb0,
1750         .osd        = 0x28,
1751         .osd_stride = 12,
1752         .buf_start  = 0x64,
1753         .buf_size   = 0x94,
1754         .buf_end    = 0x7c,
1755 
1756         .palette = {
1757             [0] = 0x400,
1758             [1] = 0x800,
1759         },
1760         .has_clksel = 1,
1761     },
1762     .win[0] = &(struct s3c_fb_win_variant) {
1763         .palette_sz = 256,
1764         .valid_bpp  = VALID_BPP1248 | VALID_BPP(16) | VALID_BPP(24),
1765     },
1766     .win[1] = &(struct s3c_fb_win_variant) {
1767         .has_osd_c  = 1,
1768         .has_osd_alpha  = 1,
1769         .palette_sz = 256,
1770         .valid_bpp  = (VALID_BPP1248 | VALID_BPP(16) |
1771                    VALID_BPP(18) | VALID_BPP(19) |
1772                    VALID_BPP(24) | VALID_BPP(25) |
1773                    VALID_BPP(28)),
1774     },
1775 };
1776 
1777 static const struct platform_device_id s3c_fb_driver_ids[] = {
1778     {
1779         .name       = "s3c-fb",
1780         .driver_data    = (unsigned long)&s3c_fb_data_64xx,
1781     }, {
1782         .name       = "s3c2443-fb",
1783         .driver_data    = (unsigned long)&s3c_fb_data_s3c2443,
1784     },
1785     {},
1786 };
1787 MODULE_DEVICE_TABLE(platform, s3c_fb_driver_ids);
1788 
1789 static const struct dev_pm_ops s3cfb_pm_ops = {
1790     SET_SYSTEM_SLEEP_PM_OPS(s3c_fb_suspend, s3c_fb_resume)
1791     SET_RUNTIME_PM_OPS(s3c_fb_runtime_suspend, s3c_fb_runtime_resume,
1792                NULL)
1793 };
1794 
1795 static struct platform_driver s3c_fb_driver = {
1796     .probe      = s3c_fb_probe,
1797     .remove     = s3c_fb_remove,
1798     .id_table   = s3c_fb_driver_ids,
1799     .driver     = {
1800         .name   = "s3c-fb",
1801         .pm = &s3cfb_pm_ops,
1802     },
1803 };
1804 
1805 module_platform_driver(s3c_fb_driver);
1806 
1807 MODULE_AUTHOR("Ben Dooks <ben@simtec.co.uk>");
1808 MODULE_DESCRIPTION("Samsung S3C SoC Framebuffer driver");
1809 MODULE_LICENSE("GPL");