]> git.kernelconcepts.de Git - karo-tx-linux.git/blob - drivers/video/mxc/mxc_ipuv3_fb.c
video: mxc: search for display-timings in the mxcfb node, rather than ldb or mxc_lcdif
[karo-tx-linux.git] / drivers / video / mxc / mxc_ipuv3_fb.c
1 /*
2  * Copyright 2004-2014 Freescale Semiconductor, Inc. All Rights Reserved.
3  */
4
5 /*
6  * The code contained herein is licensed under the GNU General Public
7  * License. You may obtain a copy of the GNU General Public License
8  * Version 2 or later at the following locations:
9  *
10  * http://www.opensource.org/licenses/gpl-license.html
11  * http://www.gnu.org/copyleft/gpl.html
12  */
13
14 /*!
15  * @defgroup Framebuffer Framebuffer Driver for SDC and ADC.
16  */
17
18 /*!
19  * @file mxcfb.c
20  *
21  * @brief MXC Frame buffer driver for SDC
22  *
23  * @ingroup Framebuffer
24  */
25
26 /*!
27  * Include files
28  */
29 #include <linux/clk.h>
30 #include <linux/console.h>
31 #include <linux/delay.h>
32 #include <linux/dma-mapping.h>
33 #include <linux/errno.h>
34 #include <linux/fb.h>
35 #include <linux/fsl_devices.h>
36 #include <linux/init.h>
37 #include <linux/interrupt.h>
38 #include <linux/io.h>
39 #include <linux/ioport.h>
40 #include <linux/ipu.h>
41 #include <linux/ipu-v3.h>
42 #include <linux/kernel.h>
43 #include <linux/module.h>
44 #include <linux/mxcfb.h>
45 #include <linux/of_device.h>
46 #include <linux/platform_device.h>
47 #include <linux/sched.h>
48 #include <linux/slab.h>
49 #include <linux/string.h>
50 #include <linux/uaccess.h>
51 #include <video/of_display_timing.h>
52 #include <video/of_videomode.h>
53 #include <video/videomode.h>
54 #include "mxc_dispdrv.h"
55
56 /*
57  * Driver name
58  */
59 #define MXCFB_NAME      "mxc_sdc_fb"
60
61 /* Display port number */
62 #define MXCFB_PORT_NUM  2
63 /*!
64  * Structure containing the MXC specific framebuffer information.
65  */
66 struct mxcfb_info {
67         int default_bpp;
68         int cur_blank;
69         int next_blank;
70         ipu_channel_t ipu_ch;
71         int ipu_id;
72         int ipu_di;
73         u32 ipu_di_pix_fmt;
74         bool ipu_int_clk;
75         bool overlay;
76         bool alpha_chan_en;
77         bool late_init;
78         bool first_set_par;
79         dma_addr_t alpha_phy_addr0;
80         dma_addr_t alpha_phy_addr1;
81         void *alpha_virt_addr0;
82         void *alpha_virt_addr1;
83         uint32_t alpha_mem_len;
84         uint32_t ipu_ch_irq;
85         uint32_t ipu_ch_nf_irq;
86         uint32_t ipu_alp_ch_irq;
87         uint32_t cur_ipu_buf;
88         uint32_t cur_ipu_alpha_buf;
89
90         u32 pseudo_palette[16];
91
92         enum display_flags disp_flags;
93         struct completion flip_complete;
94         struct completion alpha_flip_complete;
95         struct completion vsync_complete;
96
97         void *ipu;
98         struct fb_info *ovfbi;
99
100         struct mxc_dispdrv_handle *dispdrv;
101
102         struct fb_var_screeninfo cur_var;
103 };
104
105 struct mxcfb_pfmt {
106         u32 fb_pix_fmt;
107         int bpp;
108         struct fb_bitfield red;
109         struct fb_bitfield green;
110         struct fb_bitfield blue;
111         struct fb_bitfield transp;
112 };
113
114 static const struct mxcfb_pfmt mxcfb_pfmts[] = {
115         /*     pixel         bpp    red         green        blue      transp */
116         {IPU_PIX_FMT_RGB565, 16, {11, 5, 0}, { 5, 6, 0}, { 0, 5, 0}, { 0, 0, 0} },
117         {IPU_PIX_FMT_RGB24,  24, { 0, 8, 0}, { 8, 8, 0}, {16, 8, 0}, { 0, 0, 0} },
118         {IPU_PIX_FMT_BGR24,  24, {16, 8, 0}, { 8, 8, 0}, { 0, 8, 0}, { 0, 0, 0} },
119         {IPU_PIX_FMT_RGB32,  32, { 0, 8, 0}, { 8, 8, 0}, {16, 8, 0}, {24, 8, 0} },
120         {IPU_PIX_FMT_BGR32,  32, {16, 8, 0}, { 8, 8, 0}, { 0, 8, 0}, {24, 8, 0} },
121         {IPU_PIX_FMT_ABGR32, 32, {24, 8, 0}, {16, 8, 0}, { 8, 8, 0}, { 0, 8, 0} },
122 };
123
124 struct mxcfb_alloc_list {
125         struct list_head list;
126         dma_addr_t phy_addr;
127         void *cpu_addr;
128         u32 size;
129 };
130
131 enum {
132         BOTH_ON,
133         SRC_ON,
134         TGT_ON,
135         BOTH_OFF
136 };
137
138 static bool g_dp_in_use[2];
139 LIST_HEAD(fb_alloc_list);
140
141 /* Return default standard(RGB) pixel format */
142 static uint32_t bpp_to_pixfmt(int bpp)
143 {
144         uint32_t pixfmt = 0;
145
146         switch (bpp) {
147         case 24:
148                 pixfmt = IPU_PIX_FMT_BGR24;
149                 break;
150         case 32:
151                 pixfmt = IPU_PIX_FMT_BGR32;
152                 break;
153         case 16:
154                 pixfmt = IPU_PIX_FMT_RGB565;
155                 break;
156         }
157         return pixfmt;
158 }
159
160 static inline int bitfield_is_equal(struct fb_bitfield f1,
161                                     struct fb_bitfield f2)
162 {
163         return !memcmp(&f1, &f2, sizeof(f1));
164 }
165
166 static int pixfmt_to_var(uint32_t pixfmt, struct fb_var_screeninfo *var)
167 {
168         int i, ret = -1;
169
170         for (i = 0; i < ARRAY_SIZE(mxcfb_pfmts); i++) {
171                 if (pixfmt == mxcfb_pfmts[i].fb_pix_fmt) {
172                         var->red    = mxcfb_pfmts[i].red;
173                         var->green  = mxcfb_pfmts[i].green;
174                         var->blue   = mxcfb_pfmts[i].blue;
175                         var->transp = mxcfb_pfmts[i].transp;
176                         var->bits_per_pixel = mxcfb_pfmts[i].bpp;
177                         ret = 0;
178                         break;
179                 }
180         }
181         return ret;
182 }
183
184 static int bpp_to_var(int bpp, struct fb_var_screeninfo *var)
185 {
186         uint32_t pixfmt = 0;
187
188         pixfmt = bpp_to_pixfmt(bpp);
189         if (pixfmt)
190                 return pixfmt_to_var(pixfmt, var);
191         else
192                 return -1;
193 }
194
195 static int check_var_pixfmt(struct fb_var_screeninfo *var)
196 {
197         int i, ret = -1;
198
199         for (i = 0; i < ARRAY_SIZE(mxcfb_pfmts); i++) {
200                 if (bitfield_is_equal(var->red, mxcfb_pfmts[i].red) &&
201                     bitfield_is_equal(var->green, mxcfb_pfmts[i].green) &&
202                     bitfield_is_equal(var->blue, mxcfb_pfmts[i].blue) &&
203                     bitfield_is_equal(var->transp, mxcfb_pfmts[i].transp) &&
204                     var->bits_per_pixel == mxcfb_pfmts[i].bpp) {
205                         ret = 0;
206                         break;
207                 }
208         }
209         return ret;
210 }
211
212 static uint32_t fbi_to_pixfmt(struct fb_info *fbi)
213 {
214         int i;
215         uint32_t pixfmt = 0;
216
217         if (fbi->var.nonstd)
218                 return fbi->var.nonstd;
219
220         for (i = 0; i < ARRAY_SIZE(mxcfb_pfmts); i++) {
221                 if (bitfield_is_equal(fbi->var.red, mxcfb_pfmts[i].red) &&
222                     bitfield_is_equal(fbi->var.green, mxcfb_pfmts[i].green) &&
223                     bitfield_is_equal(fbi->var.blue, mxcfb_pfmts[i].blue) &&
224                     bitfield_is_equal(fbi->var.transp, mxcfb_pfmts[i].transp)) {
225                         pixfmt = mxcfb_pfmts[i].fb_pix_fmt;
226                         break;
227                 }
228         }
229
230         if (pixfmt == 0)
231                 dev_err(fbi->device, "cannot get pixel format\n");
232
233         return pixfmt;
234 }
235
236 static struct fb_info *found_registered_fb(ipu_channel_t ipu_ch, int ipu_id)
237 {
238         int i;
239         struct mxcfb_info *mxc_fbi;
240         struct fb_info *fbi = NULL;
241
242         for (i = 0; i < num_registered_fb; i++) {
243                 mxc_fbi = registered_fb[i]->par;
244
245                 if ((mxc_fbi->ipu_ch == ipu_ch) &&
246                         (mxc_fbi->ipu_id == ipu_id)) {
247                         fbi = registered_fb[i];
248                         break;
249                 }
250         }
251         return fbi;
252 }
253
254 static irqreturn_t mxcfb_irq_handler(int irq, void *dev_id);
255 static irqreturn_t mxcfb_nf_irq_handler(int irq, void *dev_id);
256 static int mxcfb_blank(int blank, struct fb_info *info);
257 static int mxcfb_map_video_memory(struct fb_info *fbi);
258 static int mxcfb_unmap_video_memory(struct fb_info *fbi);
259
260 /*
261  * Set fixed framebuffer parameters based on variable settings.
262  *
263  * @param       info     framebuffer information pointer
264  */
265 static int mxcfb_set_fix(struct fb_info *info)
266 {
267         struct fb_fix_screeninfo *fix = &info->fix;
268         struct fb_var_screeninfo *var = &info->var;
269
270         fix->line_length = var->xres_virtual * var->bits_per_pixel / 8;
271
272         fix->type = FB_TYPE_PACKED_PIXELS;
273         fix->accel = FB_ACCEL_NONE;
274         fix->visual = FB_VISUAL_TRUECOLOR;
275         fix->xpanstep = 1;
276         fix->ywrapstep = 1;
277         fix->ypanstep = 1;
278
279         return 0;
280 }
281
282 static int _setup_disp_channel1(struct fb_info *fbi)
283 {
284         ipu_channel_params_t params;
285         struct mxcfb_info *mxc_fbi = fbi->par;
286
287         memset(&params, 0, sizeof(params));
288
289         if (mxc_fbi->ipu_ch == MEM_DC_SYNC) {
290                 params.mem_dc_sync.di = mxc_fbi->ipu_di;
291                 if (fbi->var.vmode & FB_VMODE_INTERLACED)
292                         params.mem_dc_sync.interlaced = true;
293                 params.mem_dc_sync.out_pixel_fmt = mxc_fbi->ipu_di_pix_fmt;
294                 params.mem_dc_sync.in_pixel_fmt = fbi_to_pixfmt(fbi);
295         } else {
296                 params.mem_dp_bg_sync.di = mxc_fbi->ipu_di;
297                 if (fbi->var.vmode & FB_VMODE_INTERLACED)
298                         params.mem_dp_bg_sync.interlaced = true;
299                 params.mem_dp_bg_sync.out_pixel_fmt = mxc_fbi->ipu_di_pix_fmt;
300                 params.mem_dp_bg_sync.in_pixel_fmt = fbi_to_pixfmt(fbi);
301                 if (mxc_fbi->alpha_chan_en)
302                         params.mem_dp_bg_sync.alpha_chan_en = true;
303         }
304         ipu_init_channel(mxc_fbi->ipu, mxc_fbi->ipu_ch, &params);
305
306         return 0;
307 }
308
309 static int _setup_disp_channel2(struct fb_info *fbi)
310 {
311         int retval = 0;
312         struct mxcfb_info *mxc_fbi = fbi->par;
313         int fb_stride;
314         unsigned long base;
315         unsigned int fr_xoff, fr_yoff, fr_w, fr_h;
316
317         switch (fbi_to_pixfmt(fbi)) {
318         case IPU_PIX_FMT_YUV420P2:
319         case IPU_PIX_FMT_YVU420P:
320         case IPU_PIX_FMT_NV12:
321         case IPU_PIX_FMT_YUV422P:
322         case IPU_PIX_FMT_YVU422P:
323         case IPU_PIX_FMT_YUV420P:
324         case IPU_PIX_FMT_YUV444P:
325                 fb_stride = fbi->var.xres_virtual;
326                 break;
327         default:
328                 fb_stride = fbi->fix.line_length;
329         }
330
331         base = fbi->fix.smem_start;
332         fr_xoff = fbi->var.xoffset;
333         fr_w = fbi->var.xres_virtual;
334         if (!(fbi->var.vmode & FB_VMODE_YWRAP)) {
335                 dev_dbg(fbi->device, "Y wrap disabled\n");
336                 fr_yoff = fbi->var.yoffset % fbi->var.yres;
337                 fr_h = fbi->var.yres;
338                 base += fbi->fix.line_length * fbi->var.yres *
339                         (fbi->var.yoffset / fbi->var.yres);
340         } else {
341                 dev_dbg(fbi->device, "Y wrap enabled\n");
342                 fr_yoff = fbi->var.yoffset;
343                 fr_h = fbi->var.yres_virtual;
344         }
345         base += fr_yoff * fb_stride + fr_xoff;
346
347         mxc_fbi->cur_ipu_buf = 2;
348         init_completion(&mxc_fbi->flip_complete);
349         /*
350          * We don't need to wait for vsync at the first time
351          * we do pan display after fb is initialized, as IPU will
352          * switch to the newly selected buffer automatically,
353          * so we call complete() for both mxc_fbi->flip_complete
354          * and mxc_fbi->alpha_flip_complete.
355          */
356         complete(&mxc_fbi->flip_complete);
357         if (mxc_fbi->alpha_chan_en) {
358                 mxc_fbi->cur_ipu_alpha_buf = 1;
359                 init_completion(&mxc_fbi->alpha_flip_complete);
360                 complete(&mxc_fbi->alpha_flip_complete);
361         }
362
363         retval = ipu_init_channel_buffer(mxc_fbi->ipu,
364                                          mxc_fbi->ipu_ch, IPU_INPUT_BUFFER,
365                                          fbi_to_pixfmt(fbi),
366                                          fbi->var.xres, fbi->var.yres,
367                                          fb_stride,
368                                          fbi->var.rotate,
369                                          base,
370                                          base,
371                                          fbi->var.accel_flags &
372                                                 FB_ACCEL_DOUBLE_FLAG ? 0 : base,
373                                          0, 0);
374         if (retval) {
375                 dev_err(fbi->device,
376                         "ipu_init_channel_buffer error %d\n", retval);
377                 return retval;
378         }
379
380         /* update u/v offset */
381         ipu_update_channel_offset(mxc_fbi->ipu, mxc_fbi->ipu_ch,
382                         IPU_INPUT_BUFFER,
383                         fbi_to_pixfmt(fbi),
384                         fr_w,
385                         fr_h,
386                         fr_w,
387                         0, 0,
388                         fr_yoff,
389                         fr_xoff);
390
391         if (mxc_fbi->alpha_chan_en) {
392                 retval = ipu_init_channel_buffer(mxc_fbi->ipu,
393                                                  mxc_fbi->ipu_ch,
394                                                  IPU_ALPHA_IN_BUFFER,
395                                                  IPU_PIX_FMT_GENERIC,
396                                                  fbi->var.xres, fbi->var.yres,
397                                                  fbi->var.xres,
398                                                  fbi->var.rotate,
399                                                  mxc_fbi->alpha_phy_addr1,
400                                                  mxc_fbi->alpha_phy_addr0,
401                                                  0,
402                                                  0, 0);
403                 if (retval) {
404                         dev_err(fbi->device,
405                                 "ipu_init_channel_buffer error %d\n", retval);
406                         return retval;
407                 }
408         }
409
410         return retval;
411 }
412
413 static bool mxcfb_need_to_set_par(struct fb_info *fbi)
414 {
415         struct mxcfb_info *mxc_fbi = fbi->par;
416
417         if ((fbi->var.activate & FB_ACTIVATE_FORCE) &&
418             (fbi->var.activate & FB_ACTIVATE_MASK) == FB_ACTIVATE_NOW)
419                 return true;
420
421         /*
422          * Ignore xoffset and yoffset update,
423          * because pan display handles this case.
424          */
425         mxc_fbi->cur_var.xoffset = fbi->var.xoffset;
426         mxc_fbi->cur_var.yoffset = fbi->var.yoffset;
427
428         return !!memcmp(&mxc_fbi->cur_var, &fbi->var,
429                         sizeof(struct fb_var_screeninfo));
430 }
431
432 /*
433  * Set framebuffer parameters and change the operating mode.
434  *
435  * @param       info     framebuffer information pointer
436  */
437 static int mxcfb_set_par(struct fb_info *fbi)
438 {
439         int retval = 0;
440         u32 mem_len, alpha_mem_len;
441         ipu_di_signal_cfg_t sig_cfg;
442         struct mxcfb_info *mxc_fbi = fbi->par;
443
444         int16_t ov_pos_x = 0, ov_pos_y = 0;
445         int ov_pos_ret = 0;
446         struct mxcfb_info *mxc_fbi_fg = NULL;
447         bool ovfbi_enable = false;
448
449         if (ipu_ch_param_bad_alpha_pos(fbi_to_pixfmt(fbi)) &&
450             mxc_fbi->alpha_chan_en) {
451                 dev_err(fbi->device,
452                         "Bad pixel format for graphics plane fb\n");
453                 return -EINVAL;
454         }
455
456         if (mxc_fbi->ovfbi)
457                 mxc_fbi_fg = mxc_fbi->ovfbi->par;
458
459         if (mxc_fbi->ovfbi && mxc_fbi_fg)
460                 if (mxc_fbi_fg->next_blank == FB_BLANK_UNBLANK)
461                         ovfbi_enable = true;
462
463         if (!mxcfb_need_to_set_par(fbi))
464                 return 0;
465
466         dev_dbg(fbi->device, "Reconfiguring framebuffer\n");
467
468         if (fbi->var.xres == 0 || fbi->var.yres == 0)
469                 return 0;
470
471         if (ovfbi_enable) {
472                 ov_pos_ret = ipu_disp_get_window_pos(
473                                                 mxc_fbi_fg->ipu, mxc_fbi_fg->ipu_ch,
474                                                 &ov_pos_x, &ov_pos_y);
475                 if (ov_pos_ret < 0)
476                         dev_err(fbi->device, "Get overlay pos failed, dispdrv:%s.\n",
477                                         mxc_fbi->dispdrv->drv->name);
478
479                 ipu_clear_irq(mxc_fbi_fg->ipu, mxc_fbi_fg->ipu_ch_irq);
480                 ipu_disable_irq(mxc_fbi_fg->ipu, mxc_fbi_fg->ipu_ch_irq);
481                 ipu_clear_irq(mxc_fbi_fg->ipu, mxc_fbi_fg->ipu_ch_nf_irq);
482                 ipu_disable_irq(mxc_fbi_fg->ipu, mxc_fbi_fg->ipu_ch_nf_irq);
483                 ipu_disable_channel(mxc_fbi_fg->ipu, mxc_fbi_fg->ipu_ch, true);
484                 ipu_uninit_channel(mxc_fbi_fg->ipu, mxc_fbi_fg->ipu_ch);
485         }
486
487         ipu_clear_irq(mxc_fbi->ipu, mxc_fbi->ipu_ch_irq);
488         ipu_disable_irq(mxc_fbi->ipu, mxc_fbi->ipu_ch_irq);
489         ipu_clear_irq(mxc_fbi->ipu, mxc_fbi->ipu_ch_nf_irq);
490         ipu_disable_irq(mxc_fbi->ipu, mxc_fbi->ipu_ch_nf_irq);
491         ipu_disable_channel(mxc_fbi->ipu, mxc_fbi->ipu_ch, true);
492         ipu_uninit_channel(mxc_fbi->ipu, mxc_fbi->ipu_ch);
493
494         /*
495          * Disable IPU hsp clock if it is enabled for an
496          * additional time in ipu common driver.
497          */
498         if (mxc_fbi->first_set_par && mxc_fbi->late_init)
499                 ipu_disable_hsp_clk(mxc_fbi->ipu);
500
501         mxcfb_set_fix(fbi);
502
503         mem_len = fbi->var.yres_virtual * fbi->fix.line_length;
504         if (!fbi->fix.smem_start || (mem_len > fbi->fix.smem_len)) {
505                 if (fbi->fix.smem_start)
506                         mxcfb_unmap_video_memory(fbi);
507
508                 if (mxcfb_map_video_memory(fbi) < 0)
509                         return -ENOMEM;
510         }
511
512         if (mxc_fbi->first_set_par) {
513                 /*
514                  * Clear the screen in case uboot fb pixel format is not
515                  * the same to kernel fb pixel format.
516                  */
517                 if (mxc_fbi->late_init)
518                         memset(fbi->screen_base, 0, fbi->fix.smem_len);
519
520                 mxc_fbi->first_set_par = false;
521         }
522
523         if (mxc_fbi->alpha_chan_en) {
524                 alpha_mem_len = fbi->var.xres * fbi->var.yres;
525                 if ((!mxc_fbi->alpha_phy_addr0 && !mxc_fbi->alpha_phy_addr1) ||
526                     (alpha_mem_len > mxc_fbi->alpha_mem_len)) {
527                         if (mxc_fbi->alpha_phy_addr0)
528                                 dma_free_coherent(fbi->device,
529                                                   mxc_fbi->alpha_mem_len,
530                                                   mxc_fbi->alpha_virt_addr0,
531                                                   mxc_fbi->alpha_phy_addr0);
532                         if (mxc_fbi->alpha_phy_addr1)
533                                 dma_free_coherent(fbi->device,
534                                                   mxc_fbi->alpha_mem_len,
535                                                   mxc_fbi->alpha_virt_addr1,
536                                                   mxc_fbi->alpha_phy_addr1);
537
538                         mxc_fbi->alpha_virt_addr0 =
539                                         dma_alloc_coherent(fbi->device,
540                                                   alpha_mem_len,
541                                                   &mxc_fbi->alpha_phy_addr0,
542                                                   GFP_DMA | GFP_KERNEL);
543
544                         mxc_fbi->alpha_virt_addr1 =
545                                         dma_alloc_coherent(fbi->device,
546                                                   alpha_mem_len,
547                                                   &mxc_fbi->alpha_phy_addr1,
548                                                   GFP_DMA | GFP_KERNEL);
549                         if (mxc_fbi->alpha_virt_addr0 == NULL ||
550                             mxc_fbi->alpha_virt_addr1 == NULL) {
551                                 dev_err(fbi->device, "mxcfb: dma alloc for"
552                                         " alpha buffer failed.\n");
553                                 if (mxc_fbi->alpha_virt_addr0)
554                                         dma_free_coherent(fbi->device,
555                                                   mxc_fbi->alpha_mem_len,
556                                                   mxc_fbi->alpha_virt_addr0,
557                                                   mxc_fbi->alpha_phy_addr0);
558                                 if (mxc_fbi->alpha_virt_addr1)
559                                         dma_free_coherent(fbi->device,
560                                                   mxc_fbi->alpha_mem_len,
561                                                   mxc_fbi->alpha_virt_addr1,
562                                                   mxc_fbi->alpha_phy_addr1);
563                                 return -ENOMEM;
564                         }
565                         mxc_fbi->alpha_mem_len = alpha_mem_len;
566                 }
567         }
568
569         if (mxc_fbi->next_blank != FB_BLANK_UNBLANK)
570                 return retval;
571
572         if (mxc_fbi->dispdrv && mxc_fbi->dispdrv->drv->setup) {
573                 retval = mxc_fbi->dispdrv->drv->setup(mxc_fbi->dispdrv, fbi);
574                 if (retval < 0) {
575                         dev_err(fbi->device, "setup error, dispdrv: %s (%d)\n",
576                                 mxc_fbi->dispdrv->drv->name, retval);
577                         return -EINVAL;
578                 }
579         }
580
581         _setup_disp_channel1(fbi);
582         if (ovfbi_enable)
583                 _setup_disp_channel1(mxc_fbi->ovfbi);
584
585         if (!mxc_fbi->overlay) {
586                 uint32_t out_pixel_fmt;
587
588                 memset(&sig_cfg, 0, sizeof(sig_cfg));
589                 if (fbi->var.vmode & FB_VMODE_INTERLACED)
590                         sig_cfg.interlaced = true;
591                 out_pixel_fmt = mxc_fbi->ipu_di_pix_fmt;
592                 if (fbi->var.vmode & FB_VMODE_ODD_FLD_FIRST) /* PAL */
593                         sig_cfg.odd_field_first = true;
594                 if (mxc_fbi->ipu_int_clk)
595                         sig_cfg.int_clk = true;
596                 if (fbi->var.sync & FB_SYNC_HOR_HIGH_ACT)
597                         sig_cfg.Hsync_pol = true;
598                 if (fbi->var.sync & FB_SYNC_VERT_HIGH_ACT)
599                         sig_cfg.Vsync_pol = true;
600                 if (mxc_fbi->disp_flags & DISPLAY_FLAGS_PIXDATA_NEGEDGE)
601                         sig_cfg.clk_pol = true;
602                 if (fbi->var.sync & FB_SYNC_DATA_INVERT)
603                         sig_cfg.data_pol = true;
604                 if (!(fbi->var.sync & FB_SYNC_OE_LOW_ACT))
605                         sig_cfg.enable_pol = true;
606                 if (fbi->var.sync & FB_SYNC_CLK_IDLE_EN)
607                         sig_cfg.clkidle_en = true;
608
609                 dev_dbg(fbi->device, "pixclock = %ul Hz\n",
610                         (u32) (PICOS2KHZ(fbi->var.pixclock) * 1000UL));
611
612                 if (ipu_init_sync_panel(mxc_fbi->ipu, mxc_fbi->ipu_di,
613                                         (PICOS2KHZ(fbi->var.pixclock)) * 1000UL,
614                                         fbi->var.xres, fbi->var.yres,
615                                         out_pixel_fmt,
616                                         fbi->var.left_margin,
617                                         fbi->var.hsync_len,
618                                         fbi->var.right_margin,
619                                         fbi->var.upper_margin,
620                                         fbi->var.vsync_len,
621                                         fbi->var.lower_margin,
622                                         0, sig_cfg) != 0) {
623                         dev_err(fbi->device,
624                                 "mxcfb: Error initializing panel.\n");
625                         return -EINVAL;
626                 }
627
628                 fbi->mode =
629                     (struct fb_videomode *)fb_match_mode(&fbi->var,
630                                                          &fbi->modelist);
631
632                 ipu_disp_set_window_pos(mxc_fbi->ipu, mxc_fbi->ipu_ch, 0, 0);
633         }
634
635         retval = _setup_disp_channel2(fbi);
636         if (retval) {
637                 ipu_uninit_channel(mxc_fbi->ipu, mxc_fbi->ipu_ch);
638                 return retval;
639         }
640
641         if (ovfbi_enable) {
642                 if (ov_pos_ret >= 0)
643                         ipu_disp_set_window_pos(
644                                         mxc_fbi_fg->ipu, mxc_fbi_fg->ipu_ch,
645                                         ov_pos_x, ov_pos_y);
646                 retval = _setup_disp_channel2(mxc_fbi->ovfbi);
647                 if (retval) {
648                         ipu_uninit_channel(mxc_fbi_fg->ipu, mxc_fbi_fg->ipu_ch);
649                         ipu_uninit_channel(mxc_fbi->ipu, mxc_fbi->ipu_ch);
650                         return retval;
651                 }
652         }
653
654         ipu_enable_channel(mxc_fbi->ipu, mxc_fbi->ipu_ch);
655         if (ovfbi_enable)
656                 ipu_enable_channel(mxc_fbi_fg->ipu, mxc_fbi_fg->ipu_ch);
657
658         if (mxc_fbi->dispdrv && mxc_fbi->dispdrv->drv->enable) {
659                 retval = mxc_fbi->dispdrv->drv->enable(mxc_fbi->dispdrv);
660                 if (retval < 0) {
661                         dev_err(fbi->device, "enable error, dispdrv: %s (%d)\n",
662                                 mxc_fbi->dispdrv->drv->name, retval);
663                         return -EINVAL;
664                 }
665         }
666
667         mxc_fbi->cur_var = fbi->var;
668
669         return retval;
670 }
671
672 static int _swap_channels(struct fb_info *fbi_from,
673                           struct fb_info *fbi_to, bool both_on)
674 {
675         int retval, tmp;
676         ipu_channel_t old_ch;
677         struct fb_info *ovfbi;
678         struct mxcfb_info *mxc_fbi_from = fbi_from->par;
679         struct mxcfb_info *mxc_fbi_to = fbi_to->par;
680
681         if (both_on) {
682                 ipu_disable_channel(mxc_fbi_to->ipu, mxc_fbi_to->ipu_ch, true);
683                 ipu_uninit_channel(mxc_fbi_to->ipu, mxc_fbi_to->ipu_ch);
684         }
685
686         /* switch the mxc fbi parameters */
687         old_ch = mxc_fbi_from->ipu_ch;
688         mxc_fbi_from->ipu_ch = mxc_fbi_to->ipu_ch;
689         mxc_fbi_to->ipu_ch = old_ch;
690         tmp = mxc_fbi_from->ipu_ch_irq;
691         mxc_fbi_from->ipu_ch_irq = mxc_fbi_to->ipu_ch_irq;
692         mxc_fbi_to->ipu_ch_irq = tmp;
693         tmp = mxc_fbi_from->ipu_ch_nf_irq;
694         mxc_fbi_from->ipu_ch_nf_irq = mxc_fbi_to->ipu_ch_nf_irq;
695         mxc_fbi_to->ipu_ch_nf_irq = tmp;
696         ovfbi = mxc_fbi_from->ovfbi;
697         mxc_fbi_from->ovfbi = mxc_fbi_to->ovfbi;
698         mxc_fbi_to->ovfbi = ovfbi;
699
700         _setup_disp_channel1(fbi_from);
701         retval = _setup_disp_channel2(fbi_from);
702         if (retval)
703                 return retval;
704
705         /* switch between dp and dc, disable old idmac, enable new idmac */
706         retval = ipu_swap_channel(mxc_fbi_from->ipu, old_ch, mxc_fbi_from->ipu_ch);
707         ipu_uninit_channel(mxc_fbi_from->ipu, old_ch);
708
709         if (both_on) {
710                 _setup_disp_channel1(fbi_to);
711                 retval = _setup_disp_channel2(fbi_to);
712                 if (retval)
713                         return retval;
714                 ipu_enable_channel(mxc_fbi_to->ipu, mxc_fbi_to->ipu_ch);
715         }
716
717         return retval;
718 }
719
720 static int swap_channels(struct fb_info *fbi_from)
721 {
722         int i;
723         int swap_mode;
724         ipu_channel_t ch_to;
725         struct mxcfb_info *mxc_fbi_from = fbi_from->par;
726         struct fb_info *fbi_to = NULL;
727         struct mxcfb_info *mxc_fbi_to;
728
729         /* what's the target channel? */
730         if (mxc_fbi_from->ipu_ch == MEM_BG_SYNC)
731                 ch_to = MEM_DC_SYNC;
732         else
733                 ch_to = MEM_BG_SYNC;
734
735         fbi_to = found_registered_fb(ch_to, mxc_fbi_from->ipu_id);
736         if (!fbi_to)
737                 return -1;
738         mxc_fbi_to = fbi_to->par;
739
740         ipu_clear_irq(mxc_fbi_from->ipu, mxc_fbi_from->ipu_ch_irq);
741         ipu_clear_irq(mxc_fbi_to->ipu, mxc_fbi_to->ipu_ch_irq);
742         ipu_free_irq(mxc_fbi_from->ipu, mxc_fbi_from->ipu_ch_irq, fbi_from);
743         ipu_free_irq(mxc_fbi_to->ipu, mxc_fbi_to->ipu_ch_irq, fbi_to);
744         ipu_clear_irq(mxc_fbi_from->ipu, mxc_fbi_from->ipu_ch_nf_irq);
745         ipu_clear_irq(mxc_fbi_to->ipu, mxc_fbi_to->ipu_ch_nf_irq);
746         ipu_free_irq(mxc_fbi_from->ipu, mxc_fbi_from->ipu_ch_nf_irq, fbi_from);
747         ipu_free_irq(mxc_fbi_to->ipu, mxc_fbi_to->ipu_ch_nf_irq, fbi_to);
748
749         if (mxc_fbi_from->cur_blank == FB_BLANK_UNBLANK) {
750                 if (mxc_fbi_to->cur_blank == FB_BLANK_UNBLANK)
751                         swap_mode = BOTH_ON;
752                 else
753                         swap_mode = SRC_ON;
754         } else {
755                 if (mxc_fbi_to->cur_blank == FB_BLANK_UNBLANK)
756                         swap_mode = TGT_ON;
757                 else
758                         swap_mode = BOTH_OFF;
759         }
760
761         switch (swap_mode) {
762         case BOTH_ON:
763                 /* disable target->switch src->enable target */
764                 _swap_channels(fbi_from, fbi_to, true);
765                 break;
766         case SRC_ON:
767                 /* just switch src */
768                 _swap_channels(fbi_from, fbi_to, false);
769                 break;
770         case TGT_ON:
771                 /* just switch target */
772                 _swap_channels(fbi_to, fbi_from, false);
773                 break;
774         case BOTH_OFF:
775                 /* switch directly, no more need to do */
776                 mxc_fbi_to->ipu_ch = mxc_fbi_from->ipu_ch;
777                 mxc_fbi_from->ipu_ch = ch_to;
778                 i = mxc_fbi_from->ipu_ch_irq;
779                 mxc_fbi_from->ipu_ch_irq = mxc_fbi_to->ipu_ch_irq;
780                 mxc_fbi_to->ipu_ch_irq = i;
781                 i = mxc_fbi_from->ipu_ch_nf_irq;
782                 mxc_fbi_from->ipu_ch_nf_irq = mxc_fbi_to->ipu_ch_nf_irq;
783                 mxc_fbi_to->ipu_ch_nf_irq = i;
784                 break;
785         default:
786                 break;
787         }
788
789         if (ipu_request_irq(mxc_fbi_from->ipu, mxc_fbi_from->ipu_ch_irq,
790                 mxcfb_irq_handler, IPU_IRQF_ONESHOT,
791                 MXCFB_NAME, fbi_from) != 0) {
792                 dev_err(fbi_from->device, "Error registering irq %d\n",
793                         mxc_fbi_from->ipu_ch_irq);
794                 return -EBUSY;
795         }
796         ipu_disable_irq(mxc_fbi_from->ipu, mxc_fbi_from->ipu_ch_irq);
797         if (ipu_request_irq(mxc_fbi_to->ipu, mxc_fbi_to->ipu_ch_irq,
798                 mxcfb_irq_handler, IPU_IRQF_ONESHOT,
799                 MXCFB_NAME, fbi_to) != 0) {
800                 dev_err(fbi_to->device, "Error registering irq %d\n",
801                         mxc_fbi_to->ipu_ch_irq);
802                 return -EBUSY;
803         }
804         ipu_disable_irq(mxc_fbi_to->ipu, mxc_fbi_to->ipu_ch_irq);
805         if (ipu_request_irq(mxc_fbi_from->ipu, mxc_fbi_from->ipu_ch_nf_irq,
806                 mxcfb_nf_irq_handler, IPU_IRQF_ONESHOT,
807                 MXCFB_NAME, fbi_from) != 0) {
808                 dev_err(fbi_from->device, "Error registering irq %d\n",
809                         mxc_fbi_from->ipu_ch_nf_irq);
810                 return -EBUSY;
811         }
812         ipu_disable_irq(mxc_fbi_from->ipu, mxc_fbi_from->ipu_ch_nf_irq);
813         if (ipu_request_irq(mxc_fbi_to->ipu, mxc_fbi_to->ipu_ch_nf_irq,
814                 mxcfb_nf_irq_handler, IPU_IRQF_ONESHOT,
815                 MXCFB_NAME, fbi_to) != 0) {
816                 dev_err(fbi_to->device, "Error registering irq %d\n",
817                         mxc_fbi_to->ipu_ch_nf_irq);
818                 return -EBUSY;
819         }
820         ipu_disable_irq(mxc_fbi_to->ipu, mxc_fbi_to->ipu_ch_nf_irq);
821
822         return 0;
823 }
824
825 /*
826  * Check framebuffer variable parameters and adjust to valid values.
827  *
828  * @param       var      framebuffer variable parameters
829  *
830  * @param       info     framebuffer information pointer
831  */
832 static int mxcfb_check_var(struct fb_var_screeninfo *var, struct fb_info *info)
833 {
834         u32 vtotal;
835         u32 htotal;
836         struct mxcfb_info *mxc_fbi = info->par;
837
838
839         if (var->xres == 0 || var->yres == 0)
840                 return 0;
841
842         /* fg should not bigger than bg */
843         if (mxc_fbi->ipu_ch == MEM_FG_SYNC) {
844                 struct fb_info *fbi_tmp;
845                 int bg_xres = 0, bg_yres = 0;
846                 int16_t pos_x, pos_y;
847
848                 bg_xres = var->xres;
849                 bg_yres = var->yres;
850
851                 fbi_tmp = found_registered_fb(MEM_BG_SYNC, mxc_fbi->ipu_id);
852                 if (fbi_tmp) {
853                         bg_xres = fbi_tmp->var.xres;
854                         bg_yres = fbi_tmp->var.yres;
855                 }
856
857                 ipu_disp_get_window_pos(mxc_fbi->ipu, mxc_fbi->ipu_ch, &pos_x, &pos_y);
858
859                 if ((var->xres + pos_x) > bg_xres)
860                         var->xres = bg_xres - pos_x;
861                 if ((var->yres + pos_y) > bg_yres)
862                         var->yres = bg_yres - pos_y;
863         }
864
865         if (var->rotate > IPU_ROTATE_VERT_FLIP)
866                 var->rotate = IPU_ROTATE_NONE;
867
868         if (var->xres_virtual < var->xres)
869                 var->xres_virtual = var->xres;
870
871         if (var->yres_virtual < var->yres)
872                 var->yres_virtual = var->yres * 3;
873
874         if ((var->bits_per_pixel != 32) && (var->bits_per_pixel != 24) &&
875             (var->bits_per_pixel != 16) && (var->bits_per_pixel != 12) &&
876             (var->bits_per_pixel != 8))
877                 var->bits_per_pixel = 16;
878
879         if (check_var_pixfmt(var))
880                 /* Fall back to default */
881                 bpp_to_var(var->bits_per_pixel, var);
882
883         if (var->pixclock < 1000) {
884                 htotal = var->xres + var->right_margin + var->hsync_len +
885                     var->left_margin;
886                 vtotal = var->yres + var->lower_margin + var->vsync_len +
887                     var->upper_margin;
888                 var->pixclock = (vtotal * htotal * 6UL) / 100UL;
889                 var->pixclock = KHZ2PICOS(var->pixclock);
890                 dev_dbg(info->device,
891                         "pixclock set for 60Hz refresh = %u ps\n",
892                         var->pixclock);
893         }
894
895         var->height = -1;
896         var->width = -1;
897         var->grayscale = 0;
898
899         return 0;
900 }
901
902 static inline u_int _chan_to_field(u_int chan, struct fb_bitfield *bf)
903 {
904         chan &= 0xffff;
905         chan >>= 16 - bf->length;
906         return chan << bf->offset;
907 }
908
909 static int mxcfb_setcolreg(u_int regno, u_int red, u_int green, u_int blue,
910                            u_int trans, struct fb_info *fbi)
911 {
912         unsigned int val;
913         int ret = 1;
914
915         /*
916          * If greyscale is true, then we convert the RGB value
917          * to greyscale no matter what visual we are using.
918          */
919         if (fbi->var.grayscale)
920                 red = green = blue = (19595 * red + 38470 * green +
921                                       7471 * blue) >> 16;
922         switch (fbi->fix.visual) {
923         case FB_VISUAL_TRUECOLOR:
924                 /*
925                  * 16-bit True Colour.  We encode the RGB value
926                  * according to the RGB bitfield information.
927                  */
928                 if (regno < 16) {
929                         u32 *pal = fbi->pseudo_palette;
930
931                         val = _chan_to_field(red, &fbi->var.red);
932                         val |= _chan_to_field(green, &fbi->var.green);
933                         val |= _chan_to_field(blue, &fbi->var.blue);
934
935                         pal[regno] = val;
936                         ret = 0;
937                 }
938                 break;
939
940         case FB_VISUAL_STATIC_PSEUDOCOLOR:
941         case FB_VISUAL_PSEUDOCOLOR:
942                 break;
943         }
944
945         return ret;
946 }
947
948 /*
949  * Function to handle custom ioctls for MXC framebuffer.
950  *
951  * @param       inode   inode struct
952  *
953  * @param       file    file struct
954  *
955  * @param       cmd     Ioctl command to handle
956  *
957  * @param       arg     User pointer to command arguments
958  *
959  * @param       fbi     framebuffer information pointer
960  */
961 static int mxcfb_ioctl(struct fb_info *fbi, unsigned int cmd, unsigned long arg)
962 {
963         int retval = 0;
964         int __user *argp = (void __user *)arg;
965         struct mxcfb_info *mxc_fbi = fbi->par;
966
967         switch (cmd) {
968         case MXCFB_SET_GBL_ALPHA:
969                 {
970                         struct mxcfb_gbl_alpha ga;
971
972                         if (copy_from_user(&ga, argp, sizeof(ga))) {
973                                 retval = -EFAULT;
974                                 break;
975                         }
976
977                         if (ipu_disp_set_global_alpha(mxc_fbi->ipu,
978                                                       mxc_fbi->ipu_ch,
979                                                       (bool)ga.enable,
980                                                       ga.alpha)) {
981                                 retval = -EINVAL;
982                                 break;
983                         }
984
985                         if (ga.enable)
986                                 mxc_fbi->alpha_chan_en = false;
987
988                         if (ga.enable)
989                                 dev_dbg(fbi->device,
990                                         "Set global alpha of %s to %d\n",
991                                         fbi->fix.id, ga.alpha);
992                         break;
993                 }
994         case MXCFB_SET_LOC_ALPHA:
995                 {
996                         struct mxcfb_loc_alpha la;
997                         bool bad_pixfmt =
998                                 ipu_ch_param_bad_alpha_pos(fbi_to_pixfmt(fbi));
999
1000                         if (copy_from_user(&la, argp, sizeof(la))) {
1001                                 retval = -EFAULT;
1002                                 break;
1003                         }
1004
1005                         if (la.enable && !la.alpha_in_pixel) {
1006                                 struct fb_info *fbi_tmp;
1007                                 ipu_channel_t ipu_ch;
1008
1009                                 if (bad_pixfmt) {
1010                                         dev_err(fbi->device, "Bad pixel format "
1011                                                 "for graphics plane fb\n");
1012                                         retval = -EINVAL;
1013                                         break;
1014                                 }
1015
1016                                 mxc_fbi->alpha_chan_en = true;
1017
1018                                 if (mxc_fbi->ipu_ch == MEM_FG_SYNC)
1019                                         ipu_ch = MEM_BG_SYNC;
1020                                 else if (mxc_fbi->ipu_ch == MEM_BG_SYNC)
1021                                         ipu_ch = MEM_FG_SYNC;
1022                                 else {
1023                                         retval = -EINVAL;
1024                                         break;
1025                                 }
1026
1027                                 fbi_tmp = found_registered_fb(ipu_ch, mxc_fbi->ipu_id);
1028                                 if (fbi_tmp)
1029                                         ((struct mxcfb_info *)(fbi_tmp->par))->alpha_chan_en = false;
1030                         } else
1031                                 mxc_fbi->alpha_chan_en = false;
1032
1033                         if (ipu_disp_set_global_alpha(mxc_fbi->ipu,
1034                                                       mxc_fbi->ipu_ch,
1035                                                       !(bool)la.enable, 0)) {
1036                                 retval = -EINVAL;
1037                                 break;
1038                         }
1039
1040                         fbi->var.activate = (fbi->var.activate & ~FB_ACTIVATE_MASK) |
1041                                                 FB_ACTIVATE_NOW | FB_ACTIVATE_FORCE;
1042                         mxcfb_set_par(fbi);
1043
1044                         la.alpha_phy_addr0 = mxc_fbi->alpha_phy_addr0;
1045                         la.alpha_phy_addr1 = mxc_fbi->alpha_phy_addr1;
1046                         if (copy_to_user(argp, &la, sizeof(la))) {
1047                                 retval = -EFAULT;
1048                                 break;
1049                         }
1050
1051                         if (la.enable)
1052                                 dev_dbg(fbi->device,
1053                                         "Enable DP local alpha for %s\n",
1054                                         fbi->fix.id);
1055                         break;
1056                 }
1057         case MXCFB_SET_LOC_ALP_BUF:
1058                 {
1059                         unsigned long base;
1060                         uint32_t ipu_alp_ch_irq;
1061
1062                         if (!(((mxc_fbi->ipu_ch == MEM_FG_SYNC) ||
1063                              (mxc_fbi->ipu_ch == MEM_BG_SYNC)) &&
1064                              (mxc_fbi->alpha_chan_en))) {
1065                                 dev_err(fbi->device,
1066                                         "Should use background or overlay "
1067                                         "framebuffer to set the alpha buffer "
1068                                         "number\n");
1069                                 return -EINVAL;
1070                         }
1071
1072                         if (get_user(base, argp))
1073                                 return -EFAULT;
1074
1075                         if (base != mxc_fbi->alpha_phy_addr0 &&
1076                             base != mxc_fbi->alpha_phy_addr1) {
1077                                 dev_err(fbi->device,
1078                                         "Wrong alpha buffer physical address "
1079                                         "%lu\n", base);
1080                                 return -EINVAL;
1081                         }
1082
1083                         if (mxc_fbi->ipu_ch == MEM_FG_SYNC)
1084                                 ipu_alp_ch_irq = IPU_IRQ_FG_ALPHA_SYNC_EOF;
1085                         else
1086                                 ipu_alp_ch_irq = IPU_IRQ_BG_ALPHA_SYNC_EOF;
1087
1088                         retval = wait_for_completion_timeout(
1089                                 &mxc_fbi->alpha_flip_complete, HZ/2);
1090                         if (retval == 0) {
1091                                 dev_err(fbi->device, "timeout when waiting for alpha flip irq\n");
1092                                 retval = -ETIMEDOUT;
1093                                 break;
1094                         }
1095
1096                         mxc_fbi->cur_ipu_alpha_buf =
1097                                                 !mxc_fbi->cur_ipu_alpha_buf;
1098                         if (ipu_update_channel_buffer(mxc_fbi->ipu, mxc_fbi->ipu_ch,
1099                                                       IPU_ALPHA_IN_BUFFER,
1100                                                       mxc_fbi->
1101                                                         cur_ipu_alpha_buf,
1102                                                       base) == 0) {
1103                                 ipu_select_buffer(mxc_fbi->ipu, mxc_fbi->ipu_ch,
1104                                                   IPU_ALPHA_IN_BUFFER,
1105                                                   mxc_fbi->cur_ipu_alpha_buf);
1106                                 ipu_clear_irq(mxc_fbi->ipu, ipu_alp_ch_irq);
1107                                 ipu_enable_irq(mxc_fbi->ipu, ipu_alp_ch_irq);
1108                         } else {
1109                                 dev_err(fbi->device,
1110                                         "Error updating %s SDC alpha buf %d "
1111                                         "to address=0x%08lX\n",
1112                                         fbi->fix.id,
1113                                         mxc_fbi->cur_ipu_alpha_buf, base);
1114                         }
1115                         break;
1116                 }
1117         case MXCFB_SET_CLR_KEY:
1118                 {
1119                         struct mxcfb_color_key key;
1120                         if (copy_from_user(&key, argp, sizeof(key))) {
1121                                 retval = -EFAULT;
1122                                 break;
1123                         }
1124                         retval = ipu_disp_set_color_key(mxc_fbi->ipu, mxc_fbi->ipu_ch,
1125                                                         key.enable,
1126                                                         key.color_key);
1127                         dev_dbg(fbi->device, "Set color key to 0x%08X\n",
1128                                 key.color_key);
1129                         break;
1130                 }
1131         case MXCFB_SET_GAMMA:
1132                 {
1133                         struct mxcfb_gamma gamma;
1134                         if (copy_from_user(&gamma, argp, sizeof(gamma))) {
1135                                 retval = -EFAULT;
1136                                 break;
1137                         }
1138                         retval = ipu_disp_set_gamma_correction(mxc_fbi->ipu,
1139                                                         mxc_fbi->ipu_ch,
1140                                                         gamma.enable,
1141                                                         gamma.constk,
1142                                                         gamma.slopek);
1143                         break;
1144                 }
1145         case MXCFB_WAIT_FOR_VSYNC:
1146                 {
1147                         if (mxc_fbi->ipu_ch == MEM_FG_SYNC) {
1148                                 /* BG should poweron */
1149                                 struct mxcfb_info *bg_mxcfbi = NULL;
1150                                 struct fb_info *fbi_tmp;
1151
1152                                 fbi_tmp = found_registered_fb(MEM_BG_SYNC, mxc_fbi->ipu_id);
1153                                 if (fbi_tmp)
1154                                         bg_mxcfbi = ((struct mxcfb_info *)(fbi_tmp->par));
1155
1156                                 if (!bg_mxcfbi) {
1157                                         retval = -EINVAL;
1158                                         break;
1159                                 }
1160                                 if (bg_mxcfbi->cur_blank != FB_BLANK_UNBLANK) {
1161                                         retval = -EINVAL;
1162                                         break;
1163                                 }
1164                         }
1165                         if (mxc_fbi->cur_blank != FB_BLANK_UNBLANK) {
1166                                 retval = -EINVAL;
1167                                 break;
1168                         }
1169
1170                         init_completion(&mxc_fbi->vsync_complete);
1171                         ipu_clear_irq(mxc_fbi->ipu, mxc_fbi->ipu_ch_nf_irq);
1172                         ipu_enable_irq(mxc_fbi->ipu, mxc_fbi->ipu_ch_nf_irq);
1173                         retval = wait_for_completion_interruptible_timeout(
1174                                 &mxc_fbi->vsync_complete, 1 * HZ);
1175                         if (retval == 0) {
1176                                 dev_err(fbi->device,
1177                                         "MXCFB_WAIT_FOR_VSYNC: timeout %d\n",
1178                                         retval);
1179                                 retval = -ETIME;
1180                         } else if (retval > 0) {
1181                                 retval = 0;
1182                         }
1183                         break;
1184                 }
1185         case FBIO_ALLOC:
1186                 {
1187                         int size;
1188                         struct mxcfb_alloc_list *mem;
1189
1190                         mem = kzalloc(sizeof(*mem), GFP_KERNEL);
1191                         if (mem == NULL)
1192                                 return -ENOMEM;
1193
1194                         if (get_user(size, argp))
1195                                 return -EFAULT;
1196
1197                         mem->size = PAGE_ALIGN(size);
1198
1199                         mem->cpu_addr = dma_alloc_coherent(fbi->device, size,
1200                                                            &mem->phy_addr,
1201                                                            GFP_KERNEL);
1202                         if (mem->cpu_addr == NULL) {
1203                                 kfree(mem);
1204                                 return -ENOMEM;
1205                         }
1206
1207                         list_add(&mem->list, &fb_alloc_list);
1208
1209                         dev_dbg(fbi->device, "allocated %d bytes @ 0x%08X\n",
1210                                 mem->size, mem->phy_addr);
1211
1212                         if (put_user(mem->phy_addr, argp))
1213                                 return -EFAULT;
1214
1215                         break;
1216                 }
1217         case FBIO_FREE:
1218                 {
1219                         unsigned long offset;
1220                         struct mxcfb_alloc_list *mem;
1221
1222                         if (get_user(offset, argp))
1223                                 return -EFAULT;
1224
1225                         retval = -EINVAL;
1226                         list_for_each_entry(mem, &fb_alloc_list, list) {
1227                                 if (mem->phy_addr == offset) {
1228                                         list_del(&mem->list);
1229                                         dma_free_coherent(fbi->device,
1230                                                           mem->size,
1231                                                           mem->cpu_addr,
1232                                                           mem->phy_addr);
1233                                         kfree(mem);
1234                                         retval = 0;
1235                                         break;
1236                                 }
1237                         }
1238
1239                         break;
1240                 }
1241         case MXCFB_SET_OVERLAY_POS:
1242                 {
1243                         struct mxcfb_pos pos;
1244                         struct fb_info *bg_fbi = NULL;
1245                         struct mxcfb_info *bg_mxcfbi = NULL;
1246
1247                         if (mxc_fbi->ipu_ch != MEM_FG_SYNC) {
1248                                 dev_err(fbi->device, "Should use the overlay "
1249                                         "framebuffer to set the position of "
1250                                         "the overlay window\n");
1251                                 retval = -EINVAL;
1252                                 break;
1253                         }
1254
1255                         if (copy_from_user(&pos, argp, sizeof(pos))) {
1256                                 retval = -EFAULT;
1257                                 break;
1258                         }
1259
1260                         bg_fbi = found_registered_fb(MEM_BG_SYNC, mxc_fbi->ipu_id);
1261                         if (bg_fbi)
1262                                 bg_mxcfbi = ((struct mxcfb_info *)(bg_fbi->par));
1263
1264                         if (bg_fbi == NULL) {
1265                                 dev_err(fbi->device, "Cannot find the "
1266                                         "background framebuffer\n");
1267                                 retval = -ENOENT;
1268                                 break;
1269                         }
1270
1271                         /* if fb is unblank, check if the pos fit the display */
1272                         if (mxc_fbi->cur_blank == FB_BLANK_UNBLANK) {
1273                                 if (fbi->var.xres + pos.x > bg_fbi->var.xres) {
1274                                         if (bg_fbi->var.xres < fbi->var.xres)
1275                                                 pos.x = 0;
1276                                         else
1277                                                 pos.x = bg_fbi->var.xres - fbi->var.xres;
1278                                 }
1279                                 if (fbi->var.yres + pos.y > bg_fbi->var.yres) {
1280                                         if (bg_fbi->var.yres < fbi->var.yres)
1281                                                 pos.y = 0;
1282                                         else
1283                                                 pos.y = bg_fbi->var.yres - fbi->var.yres;
1284                                 }
1285                         }
1286
1287                         retval = ipu_disp_set_window_pos(mxc_fbi->ipu, mxc_fbi->ipu_ch,
1288                                                          pos.x, pos.y);
1289
1290                         if (copy_to_user(argp, &pos, sizeof(pos))) {
1291                                 retval = -EFAULT;
1292                                 break;
1293                         }
1294                         break;
1295                 }
1296         case MXCFB_GET_FB_IPU_CHAN:
1297                 {
1298                         struct mxcfb_info *mxc_fbi =
1299                                 (struct mxcfb_info *)fbi->par;
1300
1301                         if (put_user(mxc_fbi->ipu_ch, argp))
1302                                 return -EFAULT;
1303                         break;
1304                 }
1305         case MXCFB_GET_DIFMT:
1306                 {
1307                         struct mxcfb_info *mxc_fbi =
1308                                 (struct mxcfb_info *)fbi->par;
1309
1310                         if (put_user(mxc_fbi->ipu_di_pix_fmt, argp))
1311                                 return -EFAULT;
1312                         break;
1313                 }
1314         case MXCFB_GET_FB_IPU_DI:
1315                 {
1316                         struct mxcfb_info *mxc_fbi =
1317                                 (struct mxcfb_info *)fbi->par;
1318
1319                         if (put_user(mxc_fbi->ipu_di, argp))
1320                                 return -EFAULT;
1321                         break;
1322                 }
1323         case MXCFB_GET_FB_BLANK:
1324                 {
1325                         struct mxcfb_info *mxc_fbi =
1326                                 (struct mxcfb_info *)fbi->par;
1327
1328                         if (put_user(mxc_fbi->cur_blank, argp))
1329                                 return -EFAULT;
1330                         break;
1331                 }
1332         case MXCFB_SET_DIFMT:
1333                 {
1334                         struct mxcfb_info *mxc_fbi =
1335                                 (struct mxcfb_info *)fbi->par;
1336
1337                         if (get_user(mxc_fbi->ipu_di_pix_fmt, argp))
1338                                 return -EFAULT;
1339
1340                         break;
1341                 }
1342         case MXCFB_CSC_UPDATE:
1343                 {
1344                         struct mxcfb_csc_matrix csc;
1345
1346                         if (copy_from_user(&csc, argp, sizeof(csc)))
1347                                 return -EFAULT;
1348
1349                         if ((mxc_fbi->ipu_ch != MEM_FG_SYNC) &&
1350                                 (mxc_fbi->ipu_ch != MEM_BG_SYNC) &&
1351                                 (mxc_fbi->ipu_ch != MEM_BG_ASYNC0))
1352                                 return -EFAULT;
1353                         ipu_set_csc_coefficients(mxc_fbi->ipu, mxc_fbi->ipu_ch,
1354                                                 csc.param);
1355                 }
1356         default:
1357                 retval = -EINVAL;
1358         }
1359         return retval;
1360 }
1361
1362 /*
1363  * mxcfb_blank():
1364  *      Blank the display.
1365  */
1366 static int mxcfb_blank(int blank, struct fb_info *info)
1367 {
1368         struct mxcfb_info *mxc_fbi = (struct mxcfb_info *)info->par;
1369         int ret = 0;
1370
1371         dev_dbg(info->device, "blank = %d\n", blank);
1372
1373         if (mxc_fbi->cur_blank == blank)
1374                 return 0;
1375
1376         mxc_fbi->next_blank = blank;
1377
1378         switch (blank) {
1379         case FB_BLANK_POWERDOWN:
1380         case FB_BLANK_VSYNC_SUSPEND:
1381         case FB_BLANK_HSYNC_SUSPEND:
1382         case FB_BLANK_NORMAL:
1383                 if (mxc_fbi->dispdrv && mxc_fbi->dispdrv->drv->disable)
1384                         mxc_fbi->dispdrv->drv->disable(mxc_fbi->dispdrv);
1385                 ipu_disable_channel(mxc_fbi->ipu, mxc_fbi->ipu_ch, true);
1386                 if (mxc_fbi->ipu_di >= 0)
1387                         ipu_uninit_sync_panel(mxc_fbi->ipu, mxc_fbi->ipu_di);
1388                 ipu_uninit_channel(mxc_fbi->ipu, mxc_fbi->ipu_ch);
1389                 break;
1390         case FB_BLANK_UNBLANK:
1391                 info->var.activate = (info->var.activate & ~FB_ACTIVATE_MASK) |
1392                                 FB_ACTIVATE_NOW | FB_ACTIVATE_FORCE;
1393                 ret = mxcfb_set_par(info);
1394                 break;
1395         }
1396         if (!ret)
1397                 mxc_fbi->cur_blank = blank;
1398         return ret;
1399 }
1400
1401 /*
1402  * Pan or Wrap the Display
1403  *
1404  * This call looks only at xoffset, yoffset and the FB_VMODE_YWRAP flag
1405  *
1406  * @param               var     Variable screen buffer information
1407  * @param               info    Framebuffer information pointer
1408  */
1409 static int
1410 mxcfb_pan_display(struct fb_var_screeninfo *var, struct fb_info *info)
1411 {
1412         struct mxcfb_info *mxc_fbi = (struct mxcfb_info *)info->par,
1413                           *mxc_graphic_fbi = NULL;
1414         u_int y_bottom;
1415         unsigned int fr_xoff, fr_yoff, fr_w, fr_h;
1416         unsigned long base, active_alpha_phy_addr = 0;
1417         bool loc_alpha_en = false;
1418         int fb_stride;
1419         int i;
1420         int ret;
1421
1422         /* no pan display during fb blank */
1423         if (mxc_fbi->ipu_ch == MEM_FG_SYNC) {
1424                 struct mxcfb_info *bg_mxcfbi = NULL;
1425                 struct fb_info *fbi_tmp;
1426
1427                 fbi_tmp = found_registered_fb(MEM_BG_SYNC, mxc_fbi->ipu_id);
1428                 if (fbi_tmp)
1429                         bg_mxcfbi = ((struct mxcfb_info *)(fbi_tmp->par));
1430                 if (!bg_mxcfbi)
1431                         return -EINVAL;
1432                 if (bg_mxcfbi->cur_blank != FB_BLANK_UNBLANK)
1433                         return -EINVAL;
1434         }
1435         if (mxc_fbi->cur_blank != FB_BLANK_UNBLANK)
1436                 return -EINVAL;
1437
1438         y_bottom = var->yoffset;
1439
1440         if (y_bottom > info->var.yres_virtual)
1441                 return -EINVAL;
1442
1443         switch (fbi_to_pixfmt(info)) {
1444         case IPU_PIX_FMT_YUV420P2:
1445         case IPU_PIX_FMT_YVU420P:
1446         case IPU_PIX_FMT_NV12:
1447         case IPU_PIX_FMT_YUV422P:
1448         case IPU_PIX_FMT_YVU422P:
1449         case IPU_PIX_FMT_YUV420P:
1450         case IPU_PIX_FMT_YUV444P:
1451                 fb_stride = info->var.xres_virtual;
1452                 break;
1453         default:
1454                 fb_stride = info->fix.line_length;
1455         }
1456
1457         base = info->fix.smem_start;
1458         fr_xoff = var->xoffset;
1459         fr_w = info->var.xres_virtual;
1460         if (!(var->vmode & FB_VMODE_YWRAP)) {
1461                 dev_dbg(info->device, "Y wrap disabled\n");
1462                 fr_yoff = var->yoffset % info->var.yres;
1463                 fr_h = info->var.yres;
1464                 base += info->fix.line_length * info->var.yres *
1465                         (var->yoffset / info->var.yres);
1466         } else {
1467                 dev_dbg(info->device, "Y wrap enabled\n");
1468                 fr_yoff = var->yoffset;
1469                 fr_h = info->var.yres_virtual;
1470         }
1471         base += fr_yoff * fb_stride + fr_xoff;
1472
1473         /* Check if DP local alpha is enabled and find the graphic fb */
1474         if (mxc_fbi->ipu_ch == MEM_BG_SYNC || mxc_fbi->ipu_ch == MEM_FG_SYNC) {
1475                 for (i = 0; i < num_registered_fb; i++) {
1476                         char bg_id[] = "DISP3 BG";
1477                         char fg_id[] = "DISP3 FG";
1478                         char *idstr = registered_fb[i]->fix.id;
1479                         bg_id[4] += mxc_fbi->ipu_id;
1480                         fg_id[4] += mxc_fbi->ipu_id;
1481                         if ((strcmp(idstr, bg_id) == 0 ||
1482                              strcmp(idstr, fg_id) == 0) &&
1483                             ((struct mxcfb_info *)
1484                               (registered_fb[i]->par))->alpha_chan_en) {
1485                                 loc_alpha_en = true;
1486                                 mxc_graphic_fbi = (struct mxcfb_info *)
1487                                                 (registered_fb[i]->par);
1488                                 active_alpha_phy_addr =
1489                                         mxc_fbi->cur_ipu_alpha_buf ?
1490                                         mxc_graphic_fbi->alpha_phy_addr1 :
1491                                         mxc_graphic_fbi->alpha_phy_addr0;
1492                                 dev_dbg(info->device, "Updating SDC alpha "
1493                                         "buf %d address=0x%08lX\n",
1494                                         !mxc_fbi->cur_ipu_alpha_buf,
1495                                         active_alpha_phy_addr);
1496                                 break;
1497                         }
1498                 }
1499         }
1500
1501         ret = wait_for_completion_timeout(&mxc_fbi->flip_complete, HZ/2);
1502         if (ret == 0) {
1503                 dev_err(info->device, "timeout when waiting for flip irq\n");
1504                 return -ETIMEDOUT;
1505         }
1506
1507         ++mxc_fbi->cur_ipu_buf;
1508         mxc_fbi->cur_ipu_buf %= 3;
1509         mxc_fbi->cur_ipu_alpha_buf = !mxc_fbi->cur_ipu_alpha_buf;
1510
1511         dev_dbg(info->device, "Updating SDC %s buf %d address=0x%08lX\n",
1512                 info->fix.id, mxc_fbi->cur_ipu_buf, base);
1513
1514         if (ipu_update_channel_buffer(mxc_fbi->ipu, mxc_fbi->ipu_ch, IPU_INPUT_BUFFER,
1515                                       mxc_fbi->cur_ipu_buf, base) == 0) {
1516                 /* Update the DP local alpha buffer only for graphic plane */
1517                 if (loc_alpha_en && mxc_graphic_fbi == mxc_fbi &&
1518                     ipu_update_channel_buffer(mxc_graphic_fbi->ipu, mxc_graphic_fbi->ipu_ch,
1519                                               IPU_ALPHA_IN_BUFFER,
1520                                               mxc_fbi->cur_ipu_alpha_buf,
1521                                               active_alpha_phy_addr) == 0) {
1522                         ipu_select_buffer(mxc_graphic_fbi->ipu, mxc_graphic_fbi->ipu_ch,
1523                                           IPU_ALPHA_IN_BUFFER,
1524                                           mxc_fbi->cur_ipu_alpha_buf);
1525                 }
1526
1527                 /* update u/v offset */
1528                 ipu_update_channel_offset(mxc_fbi->ipu, mxc_fbi->ipu_ch,
1529                                 IPU_INPUT_BUFFER,
1530                                 fbi_to_pixfmt(info),
1531                                 fr_w,
1532                                 fr_h,
1533                                 fr_w,
1534                                 0, 0,
1535                                 fr_yoff,
1536                                 fr_xoff);
1537
1538                 ipu_select_buffer(mxc_fbi->ipu, mxc_fbi->ipu_ch, IPU_INPUT_BUFFER,
1539                                   mxc_fbi->cur_ipu_buf);
1540                 ipu_clear_irq(mxc_fbi->ipu, mxc_fbi->ipu_ch_irq);
1541                 ipu_enable_irq(mxc_fbi->ipu, mxc_fbi->ipu_ch_irq);
1542         } else {
1543                 dev_err(info->device,
1544                         "Error updating SDC buf %d to address=0x%08lX, "
1545                         "current buf %d, buf0 ready %d, buf1 ready %d, "
1546                         "buf2 ready %d\n", mxc_fbi->cur_ipu_buf, base,
1547                         ipu_get_cur_buffer_idx(mxc_fbi->ipu, mxc_fbi->ipu_ch,
1548                                                IPU_INPUT_BUFFER),
1549                         ipu_check_buffer_ready(mxc_fbi->ipu, mxc_fbi->ipu_ch,
1550                                                IPU_INPUT_BUFFER, 0),
1551                         ipu_check_buffer_ready(mxc_fbi->ipu, mxc_fbi->ipu_ch,
1552                                                IPU_INPUT_BUFFER, 1),
1553                         ipu_check_buffer_ready(mxc_fbi->ipu, mxc_fbi->ipu_ch,
1554                                                IPU_INPUT_BUFFER, 2));
1555                 ++mxc_fbi->cur_ipu_buf;
1556                 mxc_fbi->cur_ipu_buf %= 3;
1557                 ++mxc_fbi->cur_ipu_buf;
1558                 mxc_fbi->cur_ipu_buf %= 3;
1559                 mxc_fbi->cur_ipu_alpha_buf = !mxc_fbi->cur_ipu_alpha_buf;
1560                 ipu_clear_irq(mxc_fbi->ipu, mxc_fbi->ipu_ch_irq);
1561                 ipu_enable_irq(mxc_fbi->ipu, mxc_fbi->ipu_ch_irq);
1562                 return -EBUSY;
1563         }
1564
1565         dev_dbg(info->device, "Update complete\n");
1566
1567         info->var.yoffset = var->yoffset;
1568
1569         return 0;
1570 }
1571
1572 /*
1573  * Function to handle custom mmap for MXC framebuffer.
1574  *
1575  * @param       fbi     framebuffer information pointer
1576  *
1577  * @param       vma     Pointer to vm_area_struct
1578  */
1579 static int mxcfb_mmap(struct fb_info *fbi, struct vm_area_struct *vma)
1580 {
1581         bool found = false;
1582         u32 len;
1583         unsigned long offset = vma->vm_pgoff << PAGE_SHIFT;
1584         struct mxcfb_alloc_list *mem;
1585         struct mxcfb_info *mxc_fbi = (struct mxcfb_info *)fbi->par;
1586
1587         if (offset < fbi->fix.smem_len) {
1588                 /* mapping framebuffer memory */
1589                 len = fbi->fix.smem_len - offset;
1590                 vma->vm_pgoff = (fbi->fix.smem_start + offset) >> PAGE_SHIFT;
1591         } else if ((vma->vm_pgoff ==
1592                         (mxc_fbi->alpha_phy_addr0 >> PAGE_SHIFT)) ||
1593                    (vma->vm_pgoff ==
1594                         (mxc_fbi->alpha_phy_addr1 >> PAGE_SHIFT))) {
1595                 len = mxc_fbi->alpha_mem_len;
1596         } else {
1597                 list_for_each_entry(mem, &fb_alloc_list, list) {
1598                         if (offset == mem->phy_addr) {
1599                                 found = true;
1600                                 len = mem->size;
1601                                 break;
1602                         }
1603                 }
1604                 if (!found)
1605                         return -EINVAL;
1606         }
1607
1608         len = PAGE_ALIGN(len);
1609         if (vma->vm_end - vma->vm_start > len)
1610                 return -EINVAL;
1611
1612         /* make buffers bufferable */
1613         vma->vm_page_prot = pgprot_writecombine(vma->vm_page_prot);
1614
1615         vma->vm_flags |= VM_IO;
1616
1617         if (remap_pfn_range(vma, vma->vm_start, vma->vm_pgoff,
1618                             vma->vm_end - vma->vm_start, vma->vm_page_prot)) {
1619                 dev_dbg(fbi->device, "mmap remap_pfn_range failed\n");
1620                 return -ENOBUFS;
1621         }
1622
1623         return 0;
1624 }
1625
1626 /*!
1627  * This structure contains the pointers to the control functions that are
1628  * invoked by the core framebuffer driver to perform operations like
1629  * blitting, rectangle filling, copy regions and cursor definition.
1630  */
1631 static struct fb_ops mxcfb_ops = {
1632         .owner = THIS_MODULE,
1633         .fb_set_par = mxcfb_set_par,
1634         .fb_check_var = mxcfb_check_var,
1635         .fb_setcolreg = mxcfb_setcolreg,
1636         .fb_pan_display = mxcfb_pan_display,
1637         .fb_ioctl = mxcfb_ioctl,
1638         .fb_mmap = mxcfb_mmap,
1639         .fb_fillrect = cfb_fillrect,
1640         .fb_copyarea = cfb_copyarea,
1641         .fb_imageblit = cfb_imageblit,
1642         .fb_blank = mxcfb_blank,
1643 };
1644
1645 static irqreturn_t mxcfb_irq_handler(int irq, void *dev_id)
1646 {
1647         struct fb_info *fbi = dev_id;
1648         struct mxcfb_info *mxc_fbi = fbi->par;
1649
1650         complete(&mxc_fbi->flip_complete);
1651         return IRQ_HANDLED;
1652 }
1653
1654 static irqreturn_t mxcfb_nf_irq_handler(int irq, void *dev_id)
1655 {
1656         struct fb_info *fbi = dev_id;
1657         struct mxcfb_info *mxc_fbi = fbi->par;
1658
1659         complete(&mxc_fbi->vsync_complete);
1660         return IRQ_HANDLED;
1661 }
1662
1663 static irqreturn_t mxcfb_alpha_irq_handler(int irq, void *dev_id)
1664 {
1665         struct fb_info *fbi = dev_id;
1666         struct mxcfb_info *mxc_fbi = fbi->par;
1667
1668         complete(&mxc_fbi->alpha_flip_complete);
1669         return IRQ_HANDLED;
1670 }
1671
1672 /*
1673  * Suspends the framebuffer and blanks the screen. Power management support
1674  */
1675 static int mxcfb_suspend(struct platform_device *pdev, pm_message_t state)
1676 {
1677         struct fb_info *fbi = platform_get_drvdata(pdev);
1678         struct mxcfb_info *mxc_fbi = (struct mxcfb_info *)fbi->par;
1679         int saved_blank;
1680 #ifdef CONFIG_FB_MXC_LOW_PWR_DISPLAY
1681         void *fbmem;
1682 #endif
1683
1684         if (mxc_fbi->ovfbi) {
1685                 struct mxcfb_info *mxc_fbi_fg =
1686                         (struct mxcfb_info *)mxc_fbi->ovfbi->par;
1687
1688                 console_lock();
1689                 fb_set_suspend(mxc_fbi->ovfbi, 1);
1690                 saved_blank = mxc_fbi_fg->cur_blank;
1691                 mxcfb_blank(FB_BLANK_POWERDOWN, mxc_fbi->ovfbi);
1692                 mxc_fbi_fg->next_blank = saved_blank;
1693                 console_unlock();
1694         }
1695
1696         console_lock();
1697         fb_set_suspend(fbi, 1);
1698         saved_blank = mxc_fbi->cur_blank;
1699         mxcfb_blank(FB_BLANK_POWERDOWN, fbi);
1700         mxc_fbi->next_blank = saved_blank;
1701         console_unlock();
1702
1703         return 0;
1704 }
1705
1706 /*
1707  * Resumes the framebuffer and unblanks the screen. Power management support
1708  */
1709 static int mxcfb_resume(struct platform_device *pdev)
1710 {
1711         struct fb_info *fbi = platform_get_drvdata(pdev);
1712         struct mxcfb_info *mxc_fbi = (struct mxcfb_info *)fbi->par;
1713
1714         console_lock();
1715         mxcfb_blank(mxc_fbi->next_blank, fbi);
1716         fb_set_suspend(fbi, 0);
1717         console_unlock();
1718
1719         if (mxc_fbi->ovfbi) {
1720                 struct mxcfb_info *mxc_fbi_fg =
1721                         (struct mxcfb_info *)mxc_fbi->ovfbi->par;
1722                 console_lock();
1723                 mxcfb_blank(mxc_fbi_fg->next_blank, mxc_fbi->ovfbi);
1724                 fb_set_suspend(mxc_fbi->ovfbi, 0);
1725                 console_unlock();
1726         }
1727
1728         return 0;
1729 }
1730
1731 /*
1732  * Main framebuffer functions
1733  */
1734
1735 /*!
1736  * Allocates the DRAM memory for the frame buffer.      This buffer is remapped
1737  * into a non-cached, non-buffered, memory region to allow palette and pixel
1738  * writes to occur without flushing the cache.  Once this area is remapped,
1739  * all virtual memory access to the video memory should occur at the new region.
1740  *
1741  * @param       fbi     framebuffer information pointer
1742  *
1743  * @return      Error code indicating success or failure
1744  */
1745 static int mxcfb_map_video_memory(struct fb_info *fbi)
1746 {
1747         if (fbi->fix.smem_len < fbi->var.yres_virtual * fbi->fix.line_length)
1748                 fbi->fix.smem_len = fbi->var.yres_virtual *
1749                                     fbi->fix.line_length;
1750
1751         fbi->screen_base = dma_alloc_writecombine(fbi->device,
1752                                 fbi->fix.smem_len,
1753                                 (dma_addr_t *)&fbi->fix.smem_start,
1754                                 GFP_DMA | GFP_KERNEL);
1755         if (fbi->screen_base == 0) {
1756                 dev_err(fbi->device, "Unable to allocate framebuffer memory\n");
1757                 fbi->fix.smem_len = 0;
1758                 fbi->fix.smem_start = 0;
1759                 return -EBUSY;
1760         }
1761
1762         dev_dbg(fbi->device, "allocated fb @ paddr=0x%08X, size=%d.\n",
1763                 (uint32_t) fbi->fix.smem_start, fbi->fix.smem_len);
1764
1765         fbi->screen_size = fbi->fix.smem_len;
1766
1767         /* Clear the screen */
1768         memset((char *)fbi->screen_base, 0, fbi->fix.smem_len);
1769
1770         return 0;
1771 }
1772
1773 /*!
1774  * De-allocates the DRAM memory for the frame buffer.
1775  *
1776  * @param       fbi     framebuffer information pointer
1777  *
1778  * @return      Error code indicating success or failure
1779  */
1780 static int mxcfb_unmap_video_memory(struct fb_info *fbi)
1781 {
1782         dma_free_writecombine(fbi->device, fbi->fix.smem_len,
1783                               fbi->screen_base, fbi->fix.smem_start);
1784         fbi->screen_base = 0;
1785         fbi->fix.smem_start = 0;
1786         fbi->fix.smem_len = 0;
1787         return 0;
1788 }
1789
1790 /*!
1791  * Initializes the framebuffer information pointer. After allocating
1792  * sufficient memory for the framebuffer structure, the fields are
1793  * filled with custom information passed in from the configurable
1794  * structures.  This includes information such as bits per pixel,
1795  * color maps, screen width/height and RGBA offsets.
1796  *
1797  * @return      Framebuffer structure initialized with our information
1798  */
1799 static struct fb_info *mxcfb_init_fbinfo(struct device *dev, struct fb_ops *ops)
1800 {
1801         struct fb_info *fbi;
1802         struct mxcfb_info *mxcfbi;
1803
1804         /*
1805          * Allocate sufficient memory for the fb structure
1806          */
1807         fbi = framebuffer_alloc(sizeof(struct mxcfb_info), dev);
1808         if (!fbi)
1809                 return NULL;
1810
1811         mxcfbi = (struct mxcfb_info *)fbi->par;
1812
1813         fbi->var.activate = FB_ACTIVATE_NOW;
1814
1815         fbi->fbops = ops;
1816         fbi->flags = FBINFO_FLAG_DEFAULT;
1817         fbi->pseudo_palette = mxcfbi->pseudo_palette;
1818
1819         /*
1820          * Allocate colormap
1821          */
1822         fb_alloc_cmap(&fbi->cmap, 16, 0);
1823
1824         return fbi;
1825 }
1826
1827 static ssize_t show_disp_chan(struct device *dev,
1828                               struct device_attribute *attr, char *buf)
1829 {
1830         struct fb_info *info = dev_get_drvdata(dev);
1831         struct mxcfb_info *mxcfbi = (struct mxcfb_info *)info->par;
1832
1833         if (mxcfbi->ipu_ch == MEM_BG_SYNC)
1834                 return sprintf(buf, "2-layer-fb-bg\n");
1835         else if (mxcfbi->ipu_ch == MEM_FG_SYNC)
1836                 return sprintf(buf, "2-layer-fb-fg\n");
1837         else if (mxcfbi->ipu_ch == MEM_DC_SYNC)
1838                 return sprintf(buf, "1-layer-fb\n");
1839         else
1840                 return sprintf(buf, "err: no display chan\n");
1841 }
1842
1843 static ssize_t swap_disp_chan(struct device *dev,
1844                               struct device_attribute *attr,
1845                               const char *buf, size_t count)
1846 {
1847         struct fb_info *info = dev_get_drvdata(dev);
1848         struct mxcfb_info *mxcfbi = (struct mxcfb_info *)info->par;
1849         struct mxcfb_info *fg_mxcfbi = NULL;
1850
1851         console_lock();
1852         /* swap only happen between DP-BG and DC, while DP-FG disable */
1853         if (((mxcfbi->ipu_ch == MEM_BG_SYNC) &&
1854              (strstr(buf, "1-layer-fb") != NULL)) ||
1855             ((mxcfbi->ipu_ch == MEM_DC_SYNC) &&
1856              (strstr(buf, "2-layer-fb-bg") != NULL))) {
1857                 struct fb_info *fbi_fg;
1858
1859                 fbi_fg = found_registered_fb(MEM_FG_SYNC, mxcfbi->ipu_id);
1860                 if (fbi_fg)
1861                         fg_mxcfbi = (struct mxcfb_info *)fbi_fg->par;
1862
1863                 if (!fg_mxcfbi ||
1864                         fg_mxcfbi->cur_blank == FB_BLANK_UNBLANK) {
1865                         dev_err(dev,
1866                                 "Can not switch while fb2(fb-fg) is on.\n");
1867                         console_unlock();
1868                         return count;
1869                 }
1870
1871                 if (swap_channels(info) < 0)
1872                         dev_err(dev, "Swap display channel failed.\n");
1873         }
1874
1875         console_unlock();
1876         return count;
1877 }
1878 static DEVICE_ATTR(fsl_disp_property, S_IWUSR | S_IRUGO,
1879                    show_disp_chan, swap_disp_chan);
1880
1881 static ssize_t show_disp_dev(struct device *dev,
1882                              struct device_attribute *attr, char *buf)
1883 {
1884         struct fb_info *info = dev_get_drvdata(dev);
1885         struct mxcfb_info *mxcfbi = (struct mxcfb_info *)info->par;
1886
1887         if (mxcfbi->ipu_ch == MEM_FG_SYNC)
1888                 return sprintf(buf, "overlay\n");
1889         else
1890                 return sprintf(buf, "%s\n", mxcfbi->dispdrv->drv->name);
1891 }
1892 static DEVICE_ATTR(fsl_disp_dev_property, S_IRUGO, show_disp_dev, NULL);
1893
1894 static int mxcfb_dispdrv_init(struct platform_device *pdev,
1895                 struct fb_info *fbi)
1896 {
1897         struct ipuv3_fb_platform_data *plat_data = pdev->dev.platform_data;
1898         struct device_node *np = pdev->dev.of_node;
1899         struct mxcfb_info *mxcfbi = fbi->par;
1900         struct mxc_dispdrv_setting setting = {};
1901         char disp_dev[32], *default_dev = "lcd";
1902         int ret = 0;
1903
1904         setting.if_fmt = plat_data->interface_pix_fmt;
1905         setting.dft_mode_str = plat_data->mode_str;
1906         setting.default_bpp = plat_data->default_bpp;
1907         if (!setting.default_bpp)
1908                 setting.default_bpp = 16;
1909         setting.fbi = fbi;
1910         if (!strlen(plat_data->disp_dev))
1911                 strlcpy(disp_dev, default_dev, sizeof(disp_dev));
1912         else
1913                 strlcpy(disp_dev, plat_data->disp_dev, sizeof(disp_dev));
1914
1915         if (of_display_timings_exist(np) == 1) {
1916                 struct videomode vm = { };
1917
1918                 setting.fbmode = kzalloc(sizeof(*setting.fbmode), GFP_KERNEL);
1919                 if (setting.fbmode == NULL)
1920                         return -ENOMEM;
1921
1922                 ret = of_get_videomode(np, &vm, OF_USE_NATIVE_MODE);
1923                 if (ret)
1924                         goto err;
1925
1926                 fb_videomode_from_videomode(&vm, setting.fbmode);
1927                 setting.disp_flags = vm.flags;
1928                 dev_dbg(&pdev->dev, "using video mode from DTB\n");
1929         }
1930
1931         dev_info(&pdev->dev, "register mxc display driver %s\n", disp_dev);
1932
1933         mxcfbi->dispdrv = mxc_dispdrv_gethandle(disp_dev, &setting);
1934         if (IS_ERR(mxcfbi->dispdrv)) {
1935                 ret = PTR_ERR(mxcfbi->dispdrv);
1936                 dev_err(&pdev->dev, "NO mxc display driver found!\n");
1937                 goto err;
1938         } else {
1939                 /* fix-up  */
1940                 mxcfbi->ipu_di_pix_fmt = setting.if_fmt;
1941                 mxcfbi->default_bpp = setting.default_bpp;
1942
1943                 /* setting */
1944                 mxcfbi->ipu_id = setting.dev_id;
1945                 mxcfbi->ipu_di = setting.disp_id;
1946                 mxcfbi->disp_flags = setting.disp_flags;
1947                 dev_dbg(&pdev->dev, "di_pixfmt:0x%x, bpp:0x%x, di:%d, ipu:%d\n",
1948                                 setting.if_fmt, setting.default_bpp,
1949                                 setting.disp_id, setting.dev_id);
1950         }
1951
1952 err:
1953         kfree(setting.fbmode);
1954         return ret;
1955 }
1956
1957 /*
1958  * Parse user specified options (`video=trident:')
1959  * example:
1960  *      video=mxcfb0:dev=lcd,800x480M-16@55,if=RGB565,bpp=16,noaccel
1961  *      video=mxcfb0:dev=lcd,800x480M-16@55,if=RGB565,fbpix=RGB565
1962  */
1963 static int mxcfb_option_setup(struct platform_device *pdev, struct fb_info *fbi)
1964 {
1965         struct ipuv3_fb_platform_data *pdata = pdev->dev.platform_data;
1966         char *options, *opt, *fb_mode_str = NULL;
1967         char name[] = "mxcfb0";
1968         uint32_t fb_pix_fmt = 0;
1969
1970         name[5] += pdev->id;
1971         if (fb_get_options(name, &options)) {
1972                 dev_err(&pdev->dev, "Can't get fb option for %s!\n", name);
1973                 return -ENODEV;
1974         }
1975
1976         if (!options || !*options)
1977                 return 0;
1978
1979         while ((opt = strsep(&options, ",")) != NULL) {
1980                 if (!*opt)
1981                         continue;
1982
1983                 if (!strncmp(opt, "dev=", 4)) {
1984                         strlcpy(pdata->disp_dev, opt + 4, sizeof(pdata->disp_dev));
1985                 } else if (!strncmp(opt, "if=", 3)) {
1986                         if (!strncmp(opt+3, "RGB24", 5))
1987                                 pdata->interface_pix_fmt = IPU_PIX_FMT_RGB24;
1988                         else if (!strncmp(opt+3, "BGR24", 5))
1989                                 pdata->interface_pix_fmt = IPU_PIX_FMT_BGR24;
1990                         else if (!strncmp(opt+3, "GBR24", 5))
1991                                 pdata->interface_pix_fmt = IPU_PIX_FMT_GBR24;
1992                         else if (!strncmp(opt+3, "RGB565", 6))
1993                                 pdata->interface_pix_fmt = IPU_PIX_FMT_RGB565;
1994                         else if (!strncmp(opt+3, "RGB666", 6))
1995                                 pdata->interface_pix_fmt = IPU_PIX_FMT_RGB666;
1996                         else if (!strncmp(opt+3, "YUV444", 6))
1997                                 pdata->interface_pix_fmt = IPU_PIX_FMT_YUV444;
1998                         else if (!strncmp(opt+3, "LVDS666", 7))
1999                                 pdata->interface_pix_fmt = IPU_PIX_FMT_LVDS666;
2000                         else if (!strncmp(opt+3, "YUYV16", 6))
2001                                 pdata->interface_pix_fmt = IPU_PIX_FMT_YUYV;
2002                         else if (!strncmp(opt+3, "UYVY16", 6))
2003                                 pdata->interface_pix_fmt = IPU_PIX_FMT_UYVY;
2004                         else if (!strncmp(opt+3, "YVYU16", 6))
2005                                 pdata->interface_pix_fmt = IPU_PIX_FMT_YVYU;
2006                         else if (!strncmp(opt+3, "VYUY16", 6))
2007                                 pdata->interface_pix_fmt = IPU_PIX_FMT_VYUY;
2008                 } else if (!strncmp(opt, "fbpix=", 6)) {
2009                         if (!strncmp(opt+6, "RGB24", 5))
2010                                 fb_pix_fmt = IPU_PIX_FMT_RGB24;
2011                         else if (!strncmp(opt+6, "BGR24", 5))
2012                                 fb_pix_fmt = IPU_PIX_FMT_BGR24;
2013                         else if (!strncmp(opt+6, "RGB32", 5))
2014                                 fb_pix_fmt = IPU_PIX_FMT_RGB32;
2015                         else if (!strncmp(opt+6, "BGR32", 5))
2016                                 fb_pix_fmt = IPU_PIX_FMT_BGR32;
2017                         else if (!strncmp(opt+6, "ABGR32", 6))
2018                                 fb_pix_fmt = IPU_PIX_FMT_ABGR32;
2019                         else if (!strncmp(opt+6, "RGB565", 6))
2020                                 fb_pix_fmt = IPU_PIX_FMT_RGB565;
2021
2022                         if (fb_pix_fmt) {
2023                                 pixfmt_to_var(fb_pix_fmt, &fbi->var);
2024                                 pdata->default_bpp =
2025                                         fbi->var.bits_per_pixel;
2026                         }
2027                 } else if (!strncmp(opt, "int_clk", 7)) {
2028                         pdata->int_clk = true;
2029                         continue;
2030                 } else if (!strncmp(opt, "bpp=", 4)) {
2031                         /* bpp setting cannot overwrite fbpix setting */
2032                         if (fb_pix_fmt)
2033                                 continue;
2034
2035                         pdata->default_bpp =
2036                                 simple_strtoul(opt + 4, NULL, 0);
2037
2038                         fb_pix_fmt = bpp_to_pixfmt(pdata->default_bpp);
2039                         if (fb_pix_fmt)
2040                                 pixfmt_to_var(fb_pix_fmt, &fbi->var);
2041                 } else
2042                         fb_mode_str = opt;
2043         }
2044
2045         if (fb_mode_str)
2046                 pdata->mode_str = fb_mode_str;
2047
2048         return 0;
2049 }
2050
2051 static int mxcfb_register(struct fb_info *fbi)
2052 {
2053         struct mxcfb_info *mxcfbi = (struct mxcfb_info *)fbi->par;
2054         struct fb_videomode m;
2055         int ret = 0;
2056         char bg0_id[] = "DISP3 BG";
2057         char bg1_id[] = "DISP3 BG - DI1";
2058         char fg_id[] = "DISP3 FG";
2059
2060         if (mxcfbi->ipu_di == 0) {
2061                 bg0_id[4] += mxcfbi->ipu_id;
2062                 strcpy(fbi->fix.id, bg0_id);
2063         } else if (mxcfbi->ipu_di == 1) {
2064                 bg1_id[4] += mxcfbi->ipu_id;
2065                 strcpy(fbi->fix.id, bg1_id);
2066         } else { /* Overlay */
2067                 fg_id[4] += mxcfbi->ipu_id;
2068                 strcpy(fbi->fix.id, fg_id);
2069         }
2070
2071         mxcfb_check_var(&fbi->var, fbi);
2072
2073         mxcfb_set_fix(fbi);
2074
2075         /* Added first mode to fbi modelist. */
2076         if (!fbi->modelist.next || !fbi->modelist.prev)
2077                 INIT_LIST_HEAD(&fbi->modelist);
2078         fb_var_to_videomode(&m, &fbi->var);
2079         fb_add_videomode(&m, &fbi->modelist);
2080
2081         if (ipu_request_irq(mxcfbi->ipu, mxcfbi->ipu_ch_irq,
2082                 mxcfb_irq_handler, IPU_IRQF_ONESHOT, MXCFB_NAME, fbi) != 0) {
2083                 dev_err(fbi->device, "Error registering EOF irq handler.\n");
2084                 ret = -EBUSY;
2085                 goto err0;
2086         }
2087         ipu_disable_irq(mxcfbi->ipu, mxcfbi->ipu_ch_irq);
2088         if (ipu_request_irq(mxcfbi->ipu, mxcfbi->ipu_ch_nf_irq,
2089                 mxcfb_nf_irq_handler, IPU_IRQF_ONESHOT, MXCFB_NAME, fbi) != 0) {
2090                 dev_err(fbi->device, "Error registering NFACK irq handler.\n");
2091                 ret = -EBUSY;
2092                 goto err1;
2093         }
2094         ipu_disable_irq(mxcfbi->ipu, mxcfbi->ipu_ch_nf_irq);
2095
2096         if (mxcfbi->ipu_alp_ch_irq != -1)
2097                 if (ipu_request_irq(mxcfbi->ipu, mxcfbi->ipu_alp_ch_irq,
2098                                 mxcfb_alpha_irq_handler, IPU_IRQF_ONESHOT,
2099                                         MXCFB_NAME, fbi) != 0) {
2100                         dev_err(fbi->device, "Error registering alpha irq "
2101                                         "handler.\n");
2102                         ret = -EBUSY;
2103                         goto err2;
2104                 }
2105
2106         if (!mxcfbi->late_init) {
2107                 fbi->var.activate |= FB_ACTIVATE_FORCE;
2108                 console_lock();
2109                 fbi->flags |= FBINFO_MISC_USEREVENT;
2110                 ret = fb_set_var(fbi, &fbi->var);
2111                 fbi->flags &= ~FBINFO_MISC_USEREVENT;
2112                 console_unlock();
2113                 if (ret < 0) {
2114                         dev_err(fbi->device, "Error fb_set_var ret:%d\n", ret);
2115                         goto err3;
2116                 }
2117
2118                 if (mxcfbi->next_blank == FB_BLANK_UNBLANK) {
2119                         console_lock();
2120                         ret = fb_blank(fbi, FB_BLANK_UNBLANK);
2121                         console_unlock();
2122                         if (ret < 0) {
2123                                 dev_err(fbi->device,
2124                                         "Error fb_blank ret:%d\n", ret);
2125                                 goto err4;
2126                         }
2127                 }
2128         } else {
2129                 /*
2130                  * Setup the channel again though bootloader
2131                  * has done this, then set_par() can stop the
2132                  * channel neatly and re-initialize it .
2133                  */
2134                 if (mxcfbi->next_blank == FB_BLANK_UNBLANK) {
2135                         console_lock();
2136                         _setup_disp_channel1(fbi);
2137                         ipu_enable_channel(mxcfbi->ipu, mxcfbi->ipu_ch);
2138                         console_unlock();
2139                 }
2140         }
2141
2142
2143         ret = register_framebuffer(fbi);
2144         if (ret < 0)
2145                 goto err5;
2146
2147         return ret;
2148 err5:
2149         if (mxcfbi->next_blank == FB_BLANK_UNBLANK) {
2150                 console_lock();
2151                 if (!mxcfbi->late_init)
2152                         fb_blank(fbi, FB_BLANK_POWERDOWN);
2153                 else {
2154                         ipu_disable_channel(mxcfbi->ipu, mxcfbi->ipu_ch,
2155                                             true);
2156                         ipu_uninit_channel(mxcfbi->ipu, mxcfbi->ipu_ch);
2157                 }
2158                 console_unlock();
2159         }
2160 err4:
2161 err3:
2162         if (mxcfbi->ipu_alp_ch_irq != -1)
2163                 ipu_free_irq(mxcfbi->ipu, mxcfbi->ipu_alp_ch_irq, fbi);
2164 err2:
2165         ipu_free_irq(mxcfbi->ipu, mxcfbi->ipu_ch_nf_irq, fbi);
2166 err1:
2167         ipu_free_irq(mxcfbi->ipu, mxcfbi->ipu_ch_irq, fbi);
2168 err0:
2169         return ret;
2170 }
2171
2172 static void mxcfb_unregister(struct fb_info *fbi)
2173 {
2174         struct mxcfb_info *mxcfbi = (struct mxcfb_info *)fbi->par;
2175
2176         if (mxcfbi->ipu_alp_ch_irq != -1)
2177                 ipu_free_irq(mxcfbi->ipu, mxcfbi->ipu_alp_ch_irq, fbi);
2178         if (mxcfbi->ipu_ch_irq)
2179                 ipu_free_irq(mxcfbi->ipu, mxcfbi->ipu_ch_irq, fbi);
2180         if (mxcfbi->ipu_ch_nf_irq)
2181                 ipu_free_irq(mxcfbi->ipu, mxcfbi->ipu_ch_nf_irq, fbi);
2182
2183         unregister_framebuffer(fbi);
2184 }
2185
2186 static int mxcfb_setup_overlay(struct platform_device *pdev,
2187                 struct fb_info *fbi_bg, struct resource *res)
2188 {
2189         struct fb_info *ovfbi;
2190         struct mxcfb_info *mxcfbi_bg = (struct mxcfb_info *)fbi_bg->par;
2191         struct mxcfb_info *mxcfbi_fg;
2192         int ret = 0;
2193
2194         ovfbi = mxcfb_init_fbinfo(&pdev->dev, &mxcfb_ops);
2195         if (!ovfbi) {
2196                 ret = -ENOMEM;
2197                 goto init_ovfbinfo_failed;
2198         }
2199         mxcfbi_fg = ovfbi->par;
2200
2201         mxcfbi_fg->ipu = ipu_get_soc(mxcfbi_bg->ipu_id);
2202         if (IS_ERR(mxcfbi_fg->ipu)) {
2203                 ret = PTR_ERR(mxcfbi_fg->ipu);
2204                 goto get_ipu_failed;
2205         }
2206         mxcfbi_fg->ipu_id = mxcfbi_bg->ipu_id;
2207         mxcfbi_fg->ipu_ch_irq = IPU_IRQ_FG_SYNC_EOF;
2208         mxcfbi_fg->ipu_ch_nf_irq = IPU_IRQ_FG_SYNC_NFACK;
2209         mxcfbi_fg->ipu_alp_ch_irq = IPU_IRQ_FG_ALPHA_SYNC_EOF;
2210         mxcfbi_fg->ipu_ch = MEM_FG_SYNC;
2211         mxcfbi_fg->ipu_di = -1;
2212         mxcfbi_fg->ipu_di_pix_fmt = mxcfbi_bg->ipu_di_pix_fmt;
2213         mxcfbi_fg->overlay = true;
2214         mxcfbi_fg->cur_blank = mxcfbi_fg->next_blank = FB_BLANK_POWERDOWN;
2215
2216         /* Need dummy values until real panel is configured */
2217         ovfbi->var.xres = 240;
2218         ovfbi->var.yres = 320;
2219
2220         if (res && res->start && res->end) {
2221                 ovfbi->fix.smem_len = res->end - res->start + 1;
2222                 ovfbi->fix.smem_start = res->start;
2223                 ovfbi->screen_base = ioremap(
2224                                         ovfbi->fix.smem_start,
2225                                         ovfbi->fix.smem_len);
2226         }
2227
2228         ret = mxcfb_register(ovfbi);
2229         if (ret < 0)
2230                 goto register_ov_failed;
2231
2232         mxcfbi_bg->ovfbi = ovfbi;
2233
2234         return ret;
2235
2236 register_ov_failed:
2237 get_ipu_failed:
2238         fb_dealloc_cmap(&ovfbi->cmap);
2239         framebuffer_release(ovfbi);
2240 init_ovfbinfo_failed:
2241         return ret;
2242 }
2243
2244 static void mxcfb_unsetup_overlay(struct fb_info *fbi_bg)
2245 {
2246         struct mxcfb_info *mxcfbi_bg = fbi_bg->par;
2247         struct fb_info *ovfbi = mxcfbi_bg->ovfbi;
2248
2249         mxcfb_unregister(ovfbi);
2250
2251         if (&ovfbi->cmap)
2252                 fb_dealloc_cmap(&ovfbi->cmap);
2253         framebuffer_release(ovfbi);
2254 }
2255
2256 static bool ipu_usage[2][2];
2257 static int ipu_test_set_usage(int ipu, int di)
2258 {
2259         if (ipu_usage[ipu][di])
2260                 return -EBUSY;
2261         else
2262                 ipu_usage[ipu][di] = true;
2263         return 0;
2264 }
2265
2266 static void ipu_clear_usage(int ipu, int di)
2267 {
2268         ipu_usage[ipu][di] = false;
2269 }
2270
2271 static int mxcfb_get_of_property(struct platform_device *pdev,
2272                                 struct ipuv3_fb_platform_data *plat_data)
2273 {
2274         struct device_node *np = pdev->dev.of_node;
2275         const char *disp_dev;
2276         const char *mode_str;
2277         const char *pixfmt;
2278         int err;
2279         u32 bpp, int_clk;
2280         u32 late_init;
2281
2282         err = of_property_read_string(np, "disp_dev", &disp_dev);
2283         if (err < 0) {
2284                 dev_err(&pdev->dev, "get of property disp_dev fail\n");
2285                 return err;
2286         }
2287         err = of_property_read_string(np, "mode_str", &mode_str);
2288         if (err < 0) {
2289                 dev_err(&pdev->dev, "get of property mode_str fail\n");
2290                 return err;
2291         }
2292         err = of_property_read_string(np, "interface_pix_fmt", &pixfmt);
2293         if (err) {
2294                 dev_err(&pdev->dev, "get of property pix fmt fail\n");
2295                 return err;
2296         }
2297         err = of_property_read_u32(np, "default_bpp", &bpp);
2298         if (err) {
2299                 dev_err(&pdev->dev, "get of property bpp fail\n");
2300                 return err;
2301         }
2302         err = of_property_read_u32(np, "int_clk", &int_clk);
2303         if (err) {
2304                 dev_err(&pdev->dev, "get of property int_clk fail\n");
2305                 return err;
2306         }
2307         err = of_property_read_u32(np, "late_init", &late_init);
2308         if (err) {
2309                 dev_err(&pdev->dev, "get of property late_init fail\n");
2310                 return err;
2311         }
2312
2313         if (!strncmp(pixfmt, "RGB24", 5))
2314                 plat_data->interface_pix_fmt = IPU_PIX_FMT_RGB24;
2315         else if (!strncmp(pixfmt, "BGR24", 5))
2316                 plat_data->interface_pix_fmt = IPU_PIX_FMT_BGR24;
2317         else if (!strncmp(pixfmt, "GBR24", 5))
2318                 plat_data->interface_pix_fmt = IPU_PIX_FMT_GBR24;
2319         else if (!strncmp(pixfmt, "RGB565", 6))
2320                 plat_data->interface_pix_fmt = IPU_PIX_FMT_RGB565;
2321         else if (!strncmp(pixfmt, "RGB666", 6))
2322                 plat_data->interface_pix_fmt = IPU_PIX_FMT_RGB666;
2323         else if (!strncmp(pixfmt, "YUV444", 6))
2324                 plat_data->interface_pix_fmt = IPU_PIX_FMT_YUV444;
2325         else if (!strncmp(pixfmt, "LVDS666", 7))
2326                 plat_data->interface_pix_fmt = IPU_PIX_FMT_LVDS666;
2327         else if (!strncmp(pixfmt, "YUYV16", 6))
2328                 plat_data->interface_pix_fmt = IPU_PIX_FMT_YUYV;
2329         else if (!strncmp(pixfmt, "UYVY16", 6))
2330                 plat_data->interface_pix_fmt = IPU_PIX_FMT_UYVY;
2331         else if (!strncmp(pixfmt, "YVYU16", 6))
2332                 plat_data->interface_pix_fmt = IPU_PIX_FMT_YVYU;
2333         else if (!strncmp(pixfmt, "VYUY16", 6))
2334                                 plat_data->interface_pix_fmt = IPU_PIX_FMT_VYUY;
2335         else {
2336                 dev_err(&pdev->dev, "err interface_pix_fmt!\n");
2337                 return -ENOENT;
2338         }
2339
2340         strlcpy(plat_data->disp_dev, disp_dev, sizeof(plat_data->disp_dev));
2341         plat_data->mode_str = (char *)mode_str;
2342         plat_data->default_bpp = bpp;
2343         plat_data->int_clk = (bool)int_clk;
2344         plat_data->late_init = (bool)late_init;
2345         return err;
2346 }
2347
2348 /*!
2349  * Probe routine for the framebuffer driver. It is called during the
2350  * driver binding process.      The following functions are performed in
2351  * this routine: Framebuffer initialization, Memory allocation and
2352  * mapping, Framebuffer registration, IPU initialization.
2353  *
2354  * @return      Appropriate error code to the kernel common code
2355  */
2356 static int mxcfb_probe(struct platform_device *pdev)
2357 {
2358         struct ipuv3_fb_platform_data *plat_data;
2359         struct fb_info *fbi;
2360         struct mxcfb_info *mxcfbi;
2361         struct resource *res;
2362         int ret = 0;
2363
2364         dev_dbg(&pdev->dev, "%s enter\n", __func__);
2365         pdev->id = of_alias_get_id(pdev->dev.of_node, "mxcfb");
2366         if (pdev->id < 0) {
2367                 dev_err(&pdev->dev, "can not get alias id\n");
2368                 return pdev->id;
2369         }
2370
2371         plat_data = devm_kzalloc(&pdev->dev, sizeof(struct
2372                                         ipuv3_fb_platform_data), GFP_KERNEL);
2373         if (!plat_data)
2374                 return -ENOMEM;
2375         pdev->dev.platform_data = plat_data;
2376
2377         ret = mxcfb_get_of_property(pdev, plat_data);
2378         if (ret < 0) {
2379                 dev_err(&pdev->dev, "get mxcfb of property failed: %d\n", ret);
2380                 return ret;
2381         }
2382
2383         /* Initialize FB structures */
2384         fbi = mxcfb_init_fbinfo(&pdev->dev, &mxcfb_ops);
2385         if (!fbi) {
2386                 ret = -ENOMEM;
2387                 goto init_fbinfo_failed;
2388         }
2389
2390         ret = mxcfb_option_setup(pdev, fbi);
2391         if (ret)
2392                 goto get_fb_option_failed;
2393
2394         mxcfbi = fbi->par;
2395         mxcfbi->ipu_int_clk = plat_data->int_clk;
2396         mxcfbi->late_init = plat_data->late_init;
2397         mxcfbi->first_set_par = true;
2398         ret = mxcfb_dispdrv_init(pdev, fbi);
2399         if (ret < 0)
2400                 goto init_dispdrv_failed;
2401
2402         ret = ipu_test_set_usage(mxcfbi->ipu_id, mxcfbi->ipu_di);
2403         if (ret < 0) {
2404                 dev_err(&pdev->dev, "ipu%d-di%d already in use\n",
2405                                 mxcfbi->ipu_id, mxcfbi->ipu_di);
2406                 goto ipu_in_busy;
2407         }
2408
2409         if (mxcfbi->dispdrv->drv->post_init) {
2410                 ret = mxcfbi->dispdrv->drv->post_init(mxcfbi->dispdrv,
2411                                                 mxcfbi->ipu_id,
2412                                                 mxcfbi->ipu_di);
2413                 if (ret < 0) {
2414                         dev_err(&pdev->dev, "post init failed\n");
2415                         goto post_init_failed;
2416                 }
2417         }
2418
2419         res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
2420         if (res && res->start && res->end) {
2421                 fbi->fix.smem_len = res->end - res->start + 1;
2422                 fbi->fix.smem_start = res->start;
2423                 fbi->screen_base = ioremap(fbi->fix.smem_start, fbi->fix.smem_len);
2424                 /* Do not clear the fb content drawn in bootloader. */
2425                 if (!mxcfbi->late_init)
2426                         memset(fbi->screen_base, 0, fbi->fix.smem_len);
2427         }
2428
2429         mxcfbi->ipu = ipu_get_soc(mxcfbi->ipu_id);
2430         if (IS_ERR(mxcfbi->ipu)) {
2431                 dev_err(&pdev->dev, "Failed to get IPU %d\n", mxcfbi->ipu_id);
2432                 ret = PTR_ERR(mxcfbi->ipu);
2433                 goto get_ipu_failed;
2434         }
2435
2436         /* first user uses DP with alpha feature */
2437         if (!g_dp_in_use[mxcfbi->ipu_id]) {
2438                 mxcfbi->ipu_ch_irq = IPU_IRQ_BG_SYNC_EOF;
2439                 mxcfbi->ipu_ch_nf_irq = IPU_IRQ_BG_SYNC_NFACK;
2440                 mxcfbi->ipu_alp_ch_irq = IPU_IRQ_BG_ALPHA_SYNC_EOF;
2441                 mxcfbi->ipu_ch = MEM_BG_SYNC;
2442                 /* Unblank the primary fb only by default */
2443                 if (pdev->id == 0)
2444                         mxcfbi->cur_blank = mxcfbi->next_blank = FB_BLANK_UNBLANK;
2445                 else
2446                         mxcfbi->cur_blank = mxcfbi->next_blank = FB_BLANK_POWERDOWN;
2447
2448                 ret = mxcfb_register(fbi);
2449                 if (ret < 0)
2450                         goto mxcfb_register_failed;
2451
2452                 ipu_disp_set_global_alpha(mxcfbi->ipu, mxcfbi->ipu_ch,
2453                                           true, 0x80);
2454                 ipu_disp_set_color_key(mxcfbi->ipu, mxcfbi->ipu_ch, false, 0);
2455
2456                 res = platform_get_resource(pdev, IORESOURCE_MEM, 1);
2457                 ret = mxcfb_setup_overlay(pdev, fbi, res);
2458
2459                 if (ret < 0) {
2460                         mxcfb_unregister(fbi);
2461                         goto mxcfb_setupoverlay_failed;
2462                 }
2463
2464                 g_dp_in_use[mxcfbi->ipu_id] = true;
2465
2466                 ret = device_create_file(mxcfbi->ovfbi->dev,
2467                                          &dev_attr_fsl_disp_property);
2468                 if (ret)
2469                         dev_err(mxcfbi->ovfbi->dev, "Error %d on creating "
2470                                                     "file for disp property\n",
2471                                                     ret);
2472
2473                 ret = device_create_file(mxcfbi->ovfbi->dev,
2474                                          &dev_attr_fsl_disp_dev_property);
2475                 if (ret)
2476                         dev_err(mxcfbi->ovfbi->dev, "Error %d on creating "
2477                                                     "file for disp device "
2478                                                     "propety\n", ret);
2479         } else {
2480                 mxcfbi->ipu_ch_irq = IPU_IRQ_DC_SYNC_EOF;
2481                 mxcfbi->ipu_ch_nf_irq = IPU_IRQ_DC_SYNC_NFACK;
2482                 mxcfbi->ipu_alp_ch_irq = -1;
2483                 mxcfbi->ipu_ch = MEM_DC_SYNC;
2484                 mxcfbi->cur_blank = mxcfbi->next_blank = FB_BLANK_POWERDOWN;
2485
2486                 ret = mxcfb_register(fbi);
2487                 if (ret < 0)
2488                         goto mxcfb_register_failed;
2489         }
2490
2491         platform_set_drvdata(pdev, fbi);
2492
2493         ret = device_create_file(fbi->dev, &dev_attr_fsl_disp_property);
2494         if (ret)
2495                 dev_err(&pdev->dev, "Error %d on creating file for disp "
2496                                     "property\n", ret);
2497
2498         ret = device_create_file(fbi->dev, &dev_attr_fsl_disp_dev_property);
2499         if (ret)
2500                 dev_err(&pdev->dev, "Error %d on creating file for disp "
2501                                     " device propety\n", ret);
2502
2503         return 0;
2504
2505 mxcfb_setupoverlay_failed:
2506 mxcfb_register_failed:
2507 get_ipu_failed:
2508 post_init_failed:
2509         ipu_clear_usage(mxcfbi->ipu_id, mxcfbi->ipu_di);
2510 ipu_in_busy:
2511 init_dispdrv_failed:
2512         fb_dealloc_cmap(&fbi->cmap);
2513         framebuffer_release(fbi);
2514 get_fb_option_failed:
2515 init_fbinfo_failed:
2516         return ret;
2517 }
2518
2519 static int mxcfb_remove(struct platform_device *pdev)
2520 {
2521         struct fb_info *fbi = platform_get_drvdata(pdev);
2522         struct mxcfb_info *mxc_fbi = fbi->par;
2523
2524         if (!fbi)
2525                 return 0;
2526
2527         device_remove_file(fbi->dev, &dev_attr_fsl_disp_dev_property);
2528         device_remove_file(fbi->dev, &dev_attr_fsl_disp_property);
2529         mxcfb_blank(FB_BLANK_POWERDOWN, fbi);
2530         mxcfb_unregister(fbi);
2531         mxcfb_unmap_video_memory(fbi);
2532
2533         if (mxc_fbi->ovfbi) {
2534                 device_remove_file(mxc_fbi->ovfbi->dev,
2535                                    &dev_attr_fsl_disp_dev_property);
2536                 device_remove_file(mxc_fbi->ovfbi->dev,
2537                                    &dev_attr_fsl_disp_property);
2538                 mxcfb_blank(FB_BLANK_POWERDOWN, mxc_fbi->ovfbi);
2539                 mxcfb_unsetup_overlay(fbi);
2540                 mxcfb_unmap_video_memory(mxc_fbi->ovfbi);
2541         }
2542
2543         ipu_clear_usage(mxc_fbi->ipu_id, mxc_fbi->ipu_di);
2544         if (&fbi->cmap)
2545                 fb_dealloc_cmap(&fbi->cmap);
2546         framebuffer_release(fbi);
2547         return 0;
2548 }
2549
2550 static const struct of_device_id imx_mxcfb_dt_ids[] = {
2551         { .compatible = "fsl,mxc_sdc_fb"},
2552         { /* sentinel */ }
2553 };
2554
2555 /*!
2556  * This structure contains pointers to the power management callback functions.
2557  */
2558 static struct platform_driver mxcfb_driver = {
2559         .driver = {
2560                 .name = MXCFB_NAME,
2561                 .of_match_table = imx_mxcfb_dt_ids,
2562         },
2563         .probe = mxcfb_probe,
2564         .remove = mxcfb_remove,
2565         .suspend = mxcfb_suspend,
2566         .resume = mxcfb_resume,
2567 };
2568
2569 /*!
2570  * Main entry function for the framebuffer. The function registers the power
2571  * management callback functions with the kernel and also registers the MXCFB
2572  * callback functions with the core Linux framebuffer driver \b fbmem.c
2573  *
2574  * @return      Error code indicating success or failure
2575  */
2576 int __init mxcfb_init(void)
2577 {
2578         return platform_driver_register(&mxcfb_driver);
2579 }
2580
2581 void mxcfb_exit(void)
2582 {
2583         platform_driver_unregister(&mxcfb_driver);
2584 }
2585
2586 module_init(mxcfb_init);
2587 module_exit(mxcfb_exit);
2588
2589 MODULE_AUTHOR("Freescale Semiconductor, Inc.");
2590 MODULE_DESCRIPTION("MXC framebuffer driver");
2591 MODULE_LICENSE("GPL");
2592 MODULE_SUPPORTED_DEVICE("fb");