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