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