2 * Copyright 2004-2013 Freescale Semiconductor, Inc. All Rights Reserved.
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:
10 * http://www.opensource.org/licenses/gpl-license.html
11 * http://www.gnu.org/copyleft/gpl.html
15 * @defgroup Framebuffer Framebuffer Driver for SDC and ADC.
21 * @brief MXC Frame buffer driver for SDC
23 * @ingroup Framebuffer
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>
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>
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"
56 #define MXCFB_NAME "mxc_sdc_fb"
58 /* Display port number */
59 #define MXCFB_PORT_NUM 2
61 * Structure containing the MXC specific framebuffer information.
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;
82 uint32_t ipu_ch_nf_irq;
83 uint32_t ipu_alp_ch_irq;
85 uint32_t cur_ipu_alpha_buf;
87 u32 pseudo_palette[16];
90 struct completion flip_complete;
91 struct completion alpha_flip_complete;
92 struct completion vsync_complete;
95 struct fb_info *ovfbi;
97 struct mxc_dispdrv_handle *dispdrv;
99 struct fb_var_screeninfo cur_var;
105 struct fb_bitfield red;
106 struct fb_bitfield green;
107 struct fb_bitfield blue;
108 struct fb_bitfield transp;
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} },
121 struct mxcfb_alloc_list {
122 struct list_head list;
135 static bool g_dp_in_use[2];
136 LIST_HEAD(fb_alloc_list);
138 /* Return default standard(RGB) pixel format */
139 static uint32_t bpp_to_pixfmt(int bpp)
145 pixfmt = IPU_PIX_FMT_BGR24;
148 pixfmt = IPU_PIX_FMT_BGR32;
151 pixfmt = IPU_PIX_FMT_RGB565;
157 static inline int bitfield_is_equal(struct fb_bitfield f1,
158 struct fb_bitfield f2)
160 return !memcmp(&f1, &f2, sizeof(f1));
163 static int pixfmt_to_var(uint32_t pixfmt, struct fb_var_screeninfo *var)
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;
181 static int bpp_to_var(int bpp, struct fb_var_screeninfo *var)
185 pixfmt = bpp_to_pixfmt(bpp);
187 return pixfmt_to_var(pixfmt, var);
192 static int check_var_pixfmt(struct fb_var_screeninfo *var)
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) {
209 static uint32_t fbi_to_pixfmt(struct fb_info *fbi)
215 return fbi->var.nonstd;
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;
228 dev_err(fbi->device, "cannot get pixel format\n");
233 static struct fb_info *found_registered_fb(ipu_channel_t ipu_ch, int ipu_id)
236 struct mxcfb_info *mxc_fbi;
237 struct fb_info *fbi = NULL;
239 for (i = 0; i < num_registered_fb; i++) {
241 ((struct mxcfb_info *)(registered_fb[i]->par));
243 if ((mxc_fbi->ipu_ch == ipu_ch) &&
244 (mxc_fbi->ipu_id == ipu_id)) {
245 fbi = registered_fb[i];
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);
259 * Set fixed framebuffer parameters based on variable settings.
261 * @param info framebuffer information pointer
263 static int mxcfb_set_fix(struct fb_info *info)
265 struct fb_fix_screeninfo *fix = &info->fix;
266 struct fb_var_screeninfo *var = &info->var;
268 fix->line_length = var->xres_virtual * var->bits_per_pixel / 8;
270 fix->type = FB_TYPE_PACKED_PIXELS;
271 fix->accel = FB_ACCEL_NONE;
272 fix->visual = FB_VISUAL_TRUECOLOR;
280 static int _setup_disp_channel1(struct fb_info *fbi)
282 ipu_channel_params_t params;
283 struct mxcfb_info *mxc_fbi = (struct mxcfb_info *)fbi->par;
285 memset(¶ms, 0, sizeof(params));
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);
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;
302 ipu_init_channel(mxc_fbi->ipu, mxc_fbi->ipu_ch, ¶ms);
307 static int _setup_disp_channel2(struct fb_info *fbi)
310 struct mxcfb_info *mxc_fbi = (struct mxcfb_info *)fbi->par;
313 unsigned int fr_xoff, fr_yoff, fr_w, fr_h;
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;
326 fb_stride = fbi->fix.line_length;
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);
339 dev_dbg(fbi->device, "Y wrap enabled\n");
340 fr_yoff = fbi->var.yoffset;
341 fr_h = fbi->var.yres_virtual;
343 base += fr_yoff * fb_stride + fr_xoff;
345 mxc_fbi->cur_ipu_buf = 2;
346 init_completion(&mxc_fbi->flip_complete);
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.
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);
361 retval = ipu_init_channel_buffer(mxc_fbi->ipu,
362 mxc_fbi->ipu_ch, IPU_INPUT_BUFFER,
364 fbi->var.xres, fbi->var.yres,
369 fbi->var.accel_flags &
370 FB_ACCEL_DOUBLE_FLAG ? 0 : base,
374 "ipu_init_channel_buffer error %d\n", retval);
378 /* update u/v offset */
379 ipu_update_channel_offset(mxc_fbi->ipu, mxc_fbi->ipu_ch,
389 if (mxc_fbi->alpha_chan_en) {
390 retval = ipu_init_channel_buffer(mxc_fbi->ipu,
394 fbi->var.xres, fbi->var.yres,
397 mxc_fbi->alpha_phy_addr1,
398 mxc_fbi->alpha_phy_addr0,
403 "ipu_init_channel_buffer error %d\n", retval);
411 static bool mxcfb_need_to_set_par(struct fb_info *fbi)
413 struct mxcfb_info *mxc_fbi = fbi->par;
415 if ((fbi->var.activate & FB_ACTIVATE_FORCE) &&
416 (fbi->var.activate & FB_ACTIVATE_MASK) == FB_ACTIVATE_NOW)
420 * Ignore xoffset and yoffset update,
421 * because pan display handles this case.
423 mxc_fbi->cur_var.xoffset = fbi->var.xoffset;
424 mxc_fbi->cur_var.yoffset = fbi->var.yoffset;
426 return !!memcmp(&mxc_fbi->cur_var, &fbi->var,
427 sizeof(struct fb_var_screeninfo));
431 * Set framebuffer parameters and change the operating mode.
433 * @param info framebuffer information pointer
435 static int mxcfb_set_par(struct fb_info *fbi)
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;
442 int16_t ov_pos_x = 0, ov_pos_y = 0;
444 struct mxcfb_info *mxc_fbi_fg = NULL;
445 bool ovfbi_enable = false;
448 mxc_fbi_fg = (struct mxcfb_info *)mxc_fbi->ovfbi->par;
450 if (mxc_fbi->ovfbi && mxc_fbi_fg)
451 if (mxc_fbi_fg->next_blank == FB_BLANK_UNBLANK)
454 if (!mxcfb_need_to_set_par(fbi))
457 dev_dbg(fbi->device, "Reconfiguring framebuffer\n");
459 if (fbi->var.xres == 0 || fbi->var.yres == 0)
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);
467 dev_err(fbi->device, "Get overlay pos failed, dispdrv:%s.\n",
468 mxc_fbi->dispdrv->drv->name);
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);
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);
486 * Disable IPU hsp clock if it is enabled for an
487 * additional time in ipu common driver.
489 if (mxc_fbi->first_set_par && mxc_fbi->late_init)
490 ipu_disable_hsp_clk(mxc_fbi->ipu);
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);
499 if (mxcfb_map_video_memory(fbi) < 0)
503 if (mxc_fbi->first_set_par) {
505 * Clear the screen in case uboot fb pixel format is not
506 * the same to kernel fb pixel format.
508 if (mxc_fbi->late_init)
509 memset((char *)fbi->screen_base, 0, fbi->fix.smem_len);
511 mxc_fbi->first_set_par = false;
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);
529 mxc_fbi->alpha_virt_addr0 =
530 dma_alloc_coherent(fbi->device,
532 &mxc_fbi->alpha_phy_addr0,
533 GFP_DMA | GFP_KERNEL);
535 mxc_fbi->alpha_virt_addr1 =
536 dma_alloc_coherent(fbi->device,
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);
556 mxc_fbi->alpha_mem_len = alpha_mem_len;
560 if (mxc_fbi->next_blank != FB_BLANK_UNBLANK)
563 if (mxc_fbi->dispdrv && mxc_fbi->dispdrv->drv->setup) {
564 retval = mxc_fbi->dispdrv->drv->setup(mxc_fbi->dispdrv, fbi);
566 dev_err(fbi->device, "setup error, dispdrv:%s.\n",
567 mxc_fbi->dispdrv->drv->name);
572 _setup_disp_channel1(fbi);
574 _setup_disp_channel1(mxc_fbi->ovfbi);
576 if (!mxc_fbi->overlay) {
577 uint32_t out_pixel_fmt;
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;
600 dev_dbg(fbi->device, "pixclock = %ul Hz\n",
601 (u32) (PICOS2KHZ(fbi->var.pixclock) * 1000UL));
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,
607 fbi->var.left_margin,
609 fbi->var.right_margin,
610 fbi->var.upper_margin,
612 fbi->var.lower_margin,
615 "mxcfb: Error initializing panel.\n");
620 (struct fb_videomode *)fb_match_mode(&fbi->var,
623 ipu_disp_set_window_pos(mxc_fbi->ipu, mxc_fbi->ipu_ch, 0, 0);
626 retval = _setup_disp_channel2(fbi);
628 ipu_uninit_channel(mxc_fbi->ipu, mxc_fbi->ipu_ch);
634 ipu_disp_set_window_pos(
635 mxc_fbi_fg->ipu, mxc_fbi_fg->ipu_ch,
637 retval = _setup_disp_channel2(mxc_fbi->ovfbi);
639 ipu_uninit_channel(mxc_fbi_fg->ipu, mxc_fbi_fg->ipu_ch);
640 ipu_uninit_channel(mxc_fbi->ipu, mxc_fbi->ipu_ch);
645 ipu_enable_channel(mxc_fbi->ipu, mxc_fbi->ipu_ch);
647 ipu_enable_channel(mxc_fbi_fg->ipu, mxc_fbi_fg->ipu_ch);
649 if (mxc_fbi->dispdrv && mxc_fbi->dispdrv->drv->enable) {
650 retval = mxc_fbi->dispdrv->drv->enable(mxc_fbi->dispdrv);
652 dev_err(fbi->device, "enable error, dispdrv:%s.\n",
653 mxc_fbi->dispdrv->drv->name);
658 mxc_fbi->cur_var = fbi->var;
663 static int _swap_channels(struct fb_info *fbi_from,
664 struct fb_info *fbi_to, bool both_on)
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;
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);
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;
691 _setup_disp_channel1(fbi_from);
692 retval = _setup_disp_channel2(fbi_from);
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);
701 _setup_disp_channel1(fbi_to);
702 retval = _setup_disp_channel2(fbi_to);
705 ipu_enable_channel(mxc_fbi_to->ipu, mxc_fbi_to->ipu_ch);
711 static int swap_channels(struct fb_info *fbi_from)
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;
720 /* what's the target channel? */
721 if (mxc_fbi_from->ipu_ch == MEM_BG_SYNC)
726 fbi_to = found_registered_fb(ch_to, mxc_fbi_from->ipu_id);
729 mxc_fbi_to = (struct mxcfb_info *)fbi_to->par;
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);
740 if (mxc_fbi_from->cur_blank == FB_BLANK_UNBLANK) {
741 if (mxc_fbi_to->cur_blank == FB_BLANK_UNBLANK)
746 if (mxc_fbi_to->cur_blank == FB_BLANK_UNBLANK)
749 swap_mode = BOTH_OFF;
754 /* disable target->switch src->enable target */
755 _swap_channels(fbi_from, fbi_to, true);
758 /* just switch src */
759 _swap_channels(fbi_from, fbi_to, false);
762 /* just switch target */
763 _swap_channels(fbi_to, fbi_from, false);
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;
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);
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);
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);
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);
811 ipu_disable_irq(mxc_fbi_to->ipu, mxc_fbi_to->ipu_ch_nf_irq);
817 * Check framebuffer variable parameters and adjust to valid values.
819 * @param var framebuffer variable parameters
821 * @param info framebuffer information pointer
823 static int mxcfb_check_var(struct fb_var_screeninfo *var, struct fb_info *info)
827 struct mxcfb_info *mxc_fbi = (struct mxcfb_info *)info->par;
830 if (var->xres == 0 || var->yres == 0)
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;
842 fbi_tmp = found_registered_fb(MEM_BG_SYNC, mxc_fbi->ipu_id);
844 bg_xres = fbi_tmp->var.xres;
845 bg_yres = fbi_tmp->var.yres;
848 ipu_disp_get_window_pos(mxc_fbi->ipu, mxc_fbi->ipu_ch, &pos_x, &pos_y);
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;
856 if (var->rotate > IPU_ROTATE_VERT_FLIP)
857 var->rotate = IPU_ROTATE_NONE;
859 if (var->xres_virtual < var->xres)
860 var->xres_virtual = var->xres;
862 if (var->yres_virtual < var->yres)
863 var->yres_virtual = var->yres * 3;
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;
870 if (check_var_pixfmt(var))
871 /* Fall back to default */
872 bpp_to_var(var->bits_per_pixel, var);
874 if (var->pixclock < 1000) {
875 htotal = var->xres + var->right_margin + var->hsync_len +
877 vtotal = var->yres + var->lower_margin + var->vsync_len +
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",
893 static inline u_int _chan_to_field(u_int chan, struct fb_bitfield *bf)
896 chan >>= 16 - bf->length;
897 return chan << bf->offset;
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)
907 * If greyscale is true, then we convert the RGB value
908 * to greyscale no matter what visual we are using.
910 if (fbi->var.grayscale)
911 red = green = blue = (19595 * red + 38470 * green +
913 switch (fbi->fix.visual) {
914 case FB_VISUAL_TRUECOLOR:
916 * 16-bit True Colour. We encode the RGB value
917 * according to the RGB bitfield information.
920 u32 *pal = fbi->pseudo_palette;
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);
931 case FB_VISUAL_STATIC_PSEUDOCOLOR:
932 case FB_VISUAL_PSEUDOCOLOR:
940 * Function to handle custom ioctls for MXC framebuffer.
942 * @param inode inode struct
944 * @param file file struct
946 * @param cmd Ioctl command to handle
948 * @param arg User pointer to command arguments
950 * @param fbi framebuffer information pointer
952 static int mxcfb_ioctl(struct fb_info *fbi, unsigned int cmd, unsigned long arg)
955 int __user *argp = (void __user *)arg;
956 struct mxcfb_info *mxc_fbi = (struct mxcfb_info *)fbi->par;
959 case MXCFB_SET_GBL_ALPHA:
961 struct mxcfb_gbl_alpha ga;
963 if (copy_from_user(&ga, (void *)arg, sizeof(ga))) {
968 if (ipu_disp_set_global_alpha(mxc_fbi->ipu,
977 mxc_fbi->alpha_chan_en = false;
981 "Set global alpha of %s to %d\n",
982 fbi->fix.id, ga.alpha);
985 case MXCFB_SET_LOC_ALPHA:
987 struct mxcfb_loc_alpha la;
989 if (copy_from_user(&la, (void *)arg, sizeof(la))) {
994 if (ipu_disp_set_global_alpha(mxc_fbi->ipu, mxc_fbi->ipu_ch,
995 !(bool)la.enable, 0)) {
1000 if (la.enable && !la.alpha_in_pixel) {
1001 struct fb_info *fbi_tmp;
1002 ipu_channel_t ipu_ch;
1004 mxc_fbi->alpha_chan_en = true;
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;
1015 fbi_tmp = found_registered_fb(ipu_ch, mxc_fbi->ipu_id);
1017 ((struct mxcfb_info *)(fbi_tmp->par))->alpha_chan_en = false;
1019 mxc_fbi->alpha_chan_en = false;
1021 fbi->var.activate = (fbi->var.activate & ~FB_ACTIVATE_MASK) |
1022 FB_ACTIVATE_NOW | FB_ACTIVATE_FORCE;
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))) {
1033 dev_dbg(fbi->device,
1034 "Enable DP local alpha for %s\n",
1038 case MXCFB_SET_LOC_ALP_BUF:
1041 uint32_t ipu_alp_ch_irq;
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 "
1053 if (get_user(base, argp))
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 "
1064 if (mxc_fbi->ipu_ch == MEM_FG_SYNC)
1065 ipu_alp_ch_irq = IPU_IRQ_FG_ALPHA_SYNC_EOF;
1067 ipu_alp_ch_irq = IPU_IRQ_BG_ALPHA_SYNC_EOF;
1069 retval = wait_for_completion_timeout(
1070 &mxc_fbi->alpha_flip_complete, HZ/2);
1072 dev_err(fbi->device, "timeout when waiting for alpha flip irq\n");
1073 retval = -ETIMEDOUT;
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,
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);
1090 dev_err(fbi->device,
1091 "Error updating %s SDC alpha buf %d "
1092 "to address=0x%08lX\n",
1094 mxc_fbi->cur_ipu_alpha_buf, base);
1098 case MXCFB_SET_CLR_KEY:
1100 struct mxcfb_color_key key;
1101 if (copy_from_user(&key, (void *)arg, sizeof(key))) {
1105 retval = ipu_disp_set_color_key(mxc_fbi->ipu, mxc_fbi->ipu_ch,
1108 dev_dbg(fbi->device, "Set color key to 0x%08X\n",
1112 case MXCFB_SET_GAMMA:
1114 struct mxcfb_gamma gamma;
1115 if (copy_from_user(&gamma, (void *)arg, sizeof(gamma))) {
1119 retval = ipu_disp_set_gamma_correction(mxc_fbi->ipu,
1126 case MXCFB_WAIT_FOR_VSYNC:
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;
1133 fbi_tmp = found_registered_fb(MEM_BG_SYNC, mxc_fbi->ipu_id);
1135 bg_mxcfbi = ((struct mxcfb_info *)(fbi_tmp->par));
1141 if (bg_mxcfbi->cur_blank != FB_BLANK_UNBLANK) {
1146 if (mxc_fbi->cur_blank != FB_BLANK_UNBLANK) {
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);
1157 dev_err(fbi->device,
1158 "MXCFB_WAIT_FOR_VSYNC: timeout %d\n",
1161 } else if (retval > 0) {
1169 struct mxcfb_alloc_list *mem;
1171 mem = kzalloc(sizeof(*mem), GFP_KERNEL);
1175 if (get_user(size, argp))
1178 mem->size = PAGE_ALIGN(size);
1180 mem->cpu_addr = dma_alloc_coherent(fbi->device, size,
1183 if (mem->cpu_addr == NULL) {
1188 list_add(&mem->list, &fb_alloc_list);
1190 dev_dbg(fbi->device, "allocated %d bytes @ 0x%08X\n",
1191 mem->size, mem->phy_addr);
1193 if (put_user(mem->phy_addr, argp))
1200 unsigned long offset;
1201 struct mxcfb_alloc_list *mem;
1203 if (get_user(offset, argp))
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,
1222 case MXCFB_SET_OVERLAY_POS:
1224 struct mxcfb_pos pos;
1225 struct fb_info *bg_fbi = NULL;
1226 struct mxcfb_info *bg_mxcfbi = NULL;
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");
1236 if (copy_from_user(&pos, (void *)arg, sizeof(pos))) {
1241 bg_fbi = found_registered_fb(MEM_BG_SYNC, mxc_fbi->ipu_id);
1243 bg_mxcfbi = ((struct mxcfb_info *)(bg_fbi->par));
1245 if (bg_fbi == NULL) {
1246 dev_err(fbi->device, "Cannot find the "
1247 "background framebuffer\n");
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)
1258 pos.x = bg_fbi->var.xres - fbi->var.xres;
1260 if (fbi->var.yres + pos.y > bg_fbi->var.yres) {
1261 if (bg_fbi->var.yres < fbi->var.yres)
1264 pos.y = bg_fbi->var.yres - fbi->var.yres;
1268 retval = ipu_disp_set_window_pos(mxc_fbi->ipu, mxc_fbi->ipu_ch,
1271 if (copy_to_user((void *)arg, &pos, sizeof(pos))) {
1277 case MXCFB_GET_FB_IPU_CHAN:
1279 struct mxcfb_info *mxc_fbi =
1280 (struct mxcfb_info *)fbi->par;
1282 if (put_user(mxc_fbi->ipu_ch, argp))
1286 case MXCFB_GET_DIFMT:
1288 struct mxcfb_info *mxc_fbi =
1289 (struct mxcfb_info *)fbi->par;
1291 if (put_user(mxc_fbi->ipu_di_pix_fmt, argp))
1295 case MXCFB_GET_FB_IPU_DI:
1297 struct mxcfb_info *mxc_fbi =
1298 (struct mxcfb_info *)fbi->par;
1300 if (put_user(mxc_fbi->ipu_di, argp))
1304 case MXCFB_GET_FB_BLANK:
1306 struct mxcfb_info *mxc_fbi =
1307 (struct mxcfb_info *)fbi->par;
1309 if (put_user(mxc_fbi->cur_blank, argp))
1313 case MXCFB_SET_DIFMT:
1315 struct mxcfb_info *mxc_fbi =
1316 (struct mxcfb_info *)fbi->par;
1318 if (get_user(mxc_fbi->ipu_di_pix_fmt, argp))
1323 case MXCFB_CSC_UPDATE:
1325 struct mxcfb_csc_matrix csc;
1327 if (copy_from_user(&csc, (void *) arg, sizeof(csc)))
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))
1334 ipu_set_csc_coefficients(mxc_fbi->ipu, mxc_fbi->ipu_ch,
1345 * Blank the display.
1347 static int mxcfb_blank(int blank, struct fb_info *info)
1349 struct mxcfb_info *mxc_fbi = (struct mxcfb_info *)info->par;
1352 dev_dbg(info->device, "blank = %d\n", blank);
1354 if (mxc_fbi->cur_blank == blank)
1357 mxc_fbi->next_blank = 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);
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);
1378 mxc_fbi->cur_blank = blank;
1383 * Pan or Wrap the Display
1385 * This call looks only at xoffset, yoffset and the FB_VMODE_YWRAP flag
1387 * @param var Variable screen buffer information
1388 * @param info Framebuffer information pointer
1391 mxcfb_pan_display(struct fb_var_screeninfo *var, struct fb_info *info)
1393 struct mxcfb_info *mxc_fbi = (struct mxcfb_info *)info->par,
1394 *mxc_graphic_fbi = NULL;
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;
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;
1408 fbi_tmp = found_registered_fb(MEM_BG_SYNC, mxc_fbi->ipu_id);
1410 bg_mxcfbi = ((struct mxcfb_info *)(fbi_tmp->par));
1413 if (bg_mxcfbi->cur_blank != FB_BLANK_UNBLANK)
1416 if (mxc_fbi->cur_blank != FB_BLANK_UNBLANK)
1419 y_bottom = var->yoffset;
1421 if (y_bottom > info->var.yres_virtual)
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;
1435 fb_stride = info->fix.line_length;
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);
1448 dev_dbg(info->device, "Y wrap enabled\n");
1449 fr_yoff = var->yoffset;
1450 fr_h = info->var.yres_virtual;
1452 base += fr_yoff * fb_stride + fr_xoff;
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);
1482 ret = wait_for_completion_timeout(&mxc_fbi->flip_complete, HZ/2);
1484 dev_err(info->device, "timeout when waiting for flip irq\n");
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;
1492 dev_dbg(info->device, "Updating SDC %s buf %d address=0x%08lX\n",
1493 info->fix.id, mxc_fbi->cur_ipu_buf, base);
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);
1508 /* update u/v offset */
1509 ipu_update_channel_offset(mxc_fbi->ipu, mxc_fbi->ipu_ch,
1511 fbi_to_pixfmt(info),
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);
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,
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);
1546 dev_dbg(info->device, "Update complete\n");
1548 info->var.yoffset = var->yoffset;
1554 * Function to handle custom mmap for MXC framebuffer.
1556 * @param fbi framebuffer information pointer
1558 * @param vma Pointer to vm_area_struct
1560 static int mxcfb_mmap(struct fb_info *fbi, struct vm_area_struct *vma)
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;
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)) ||
1575 (mxc_fbi->alpha_phy_addr1 >> PAGE_SHIFT))) {
1576 len = mxc_fbi->alpha_mem_len;
1578 list_for_each_entry(mem, &fb_alloc_list, list) {
1579 if (offset == mem->phy_addr) {
1589 len = PAGE_ALIGN(len);
1590 if (vma->vm_end - vma->vm_start > len)
1593 /* make buffers bufferable */
1594 vma->vm_page_prot = pgprot_writecombine(vma->vm_page_prot);
1596 vma->vm_flags |= VM_IO | VM_RESERVED;
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");
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.
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,
1626 static irqreturn_t mxcfb_irq_handler(int irq, void *dev_id)
1628 struct fb_info *fbi = dev_id;
1629 struct mxcfb_info *mxc_fbi = fbi->par;
1631 complete(&mxc_fbi->flip_complete);
1635 static irqreturn_t mxcfb_nf_irq_handler(int irq, void *dev_id)
1637 struct fb_info *fbi = dev_id;
1638 struct mxcfb_info *mxc_fbi = fbi->par;
1640 complete(&mxc_fbi->vsync_complete);
1644 static irqreturn_t mxcfb_alpha_irq_handler(int irq, void *dev_id)
1646 struct fb_info *fbi = dev_id;
1647 struct mxcfb_info *mxc_fbi = fbi->par;
1649 complete(&mxc_fbi->alpha_flip_complete);
1654 * Suspends the framebuffer and blanks the screen. Power management support
1656 static int mxcfb_suspend(struct platform_device *pdev, pm_message_t state)
1658 struct fb_info *fbi = platform_get_drvdata(pdev);
1659 struct mxcfb_info *mxc_fbi = (struct mxcfb_info *)fbi->par;
1661 #ifdef CONFIG_FB_MXC_LOW_PWR_DISPLAY
1665 if (mxc_fbi->ovfbi) {
1666 struct mxcfb_info *mxc_fbi_fg =
1667 (struct mxcfb_info *)mxc_fbi->ovfbi->par;
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;
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;
1688 * Resumes the framebuffer and unblanks the screen. Power management support
1690 static int mxcfb_resume(struct platform_device *pdev)
1692 struct fb_info *fbi = platform_get_drvdata(pdev);
1693 struct mxcfb_info *mxc_fbi = (struct mxcfb_info *)fbi->par;
1696 mxcfb_blank(mxc_fbi->next_blank, fbi);
1697 fb_set_suspend(fbi, 0);
1700 if (mxc_fbi->ovfbi) {
1701 struct mxcfb_info *mxc_fbi_fg =
1702 (struct mxcfb_info *)mxc_fbi->ovfbi->par;
1704 mxcfb_blank(mxc_fbi_fg->next_blank, mxc_fbi->ovfbi);
1705 fb_set_suspend(mxc_fbi->ovfbi, 0);
1713 * Main framebuffer functions
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.
1722 * @param fbi framebuffer information pointer
1724 * @return Error code indicating success or failure
1726 static int mxcfb_map_video_memory(struct fb_info *fbi)
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;
1732 fbi->screen_base = dma_alloc_writecombine(fbi->device,
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;
1743 dev_dbg(fbi->device, "allocated fb @ paddr=0x%08X, size=%d.\n",
1744 (uint32_t) fbi->fix.smem_start, fbi->fix.smem_len);
1746 fbi->screen_size = fbi->fix.smem_len;
1748 /* Clear the screen */
1749 memset((char *)fbi->screen_base, 0, fbi->fix.smem_len);
1755 * De-allocates the DRAM memory for the frame buffer.
1757 * @param fbi framebuffer information pointer
1759 * @return Error code indicating success or failure
1761 static int mxcfb_unmap_video_memory(struct fb_info *fbi)
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;
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.
1778 * @return Framebuffer structure initialized with our information
1780 static struct fb_info *mxcfb_init_fbinfo(struct device *dev, struct fb_ops *ops)
1782 struct fb_info *fbi;
1783 struct mxcfb_info *mxcfbi;
1786 * Allocate sufficient memory for the fb structure
1788 fbi = framebuffer_alloc(sizeof(struct mxcfb_info), dev);
1792 mxcfbi = (struct mxcfb_info *)fbi->par;
1794 fbi->var.activate = FB_ACTIVATE_NOW;
1797 fbi->flags = FBINFO_FLAG_DEFAULT;
1798 fbi->pseudo_palette = mxcfbi->pseudo_palette;
1803 fb_alloc_cmap(&fbi->cmap, 16, 0);
1808 static ssize_t show_disp_chan(struct device *dev,
1809 struct device_attribute *attr, char *buf)
1811 struct fb_info *info = dev_get_drvdata(dev);
1812 struct mxcfb_info *mxcfbi = (struct mxcfb_info *)info->par;
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");
1821 return sprintf(buf, "err: no display chan\n");
1824 static ssize_t swap_disp_chan(struct device *dev,
1825 struct device_attribute *attr,
1826 const char *buf, size_t count)
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;
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;
1840 fbi_fg = found_registered_fb(MEM_FG_SYNC, mxcfbi->ipu_id);
1842 fg_mxcfbi = (struct mxcfb_info *)fbi_fg->par;
1845 fg_mxcfbi->cur_blank == FB_BLANK_UNBLANK) {
1847 "Can not switch while fb2(fb-fg) is on.\n");
1852 if (swap_channels(info) < 0)
1853 dev_err(dev, "Swap display channel failed.\n");
1859 static DEVICE_ATTR(fsl_disp_property, 644, show_disp_chan, swap_disp_chan);
1861 static ssize_t show_disp_dev(struct device *dev,
1862 struct device_attribute *attr, char *buf)
1864 struct fb_info *info = dev_get_drvdata(dev);
1865 struct mxcfb_info *mxcfbi = (struct mxcfb_info *)info->par;
1867 if (mxcfbi->ipu_ch == MEM_FG_SYNC)
1868 return sprintf(buf, "overlay\n");
1870 return sprintf(buf, "%s\n", mxcfbi->dispdrv->drv->name);
1872 static DEVICE_ATTR(fsl_disp_dev_property, S_IRUGO, show_disp_dev, NULL);
1874 static int mxcfb_dispdrv_init(struct platform_device *pdev,
1875 struct fb_info *fbi)
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";
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;
1889 if (!strlen(plat_data->disp_dev)) {
1890 memcpy(disp_dev, default_dev, strlen(default_dev));
1891 disp_dev[strlen(default_dev)] = '\0';
1893 memcpy(disp_dev, plat_data->disp_dev,
1894 strlen(plat_data->disp_dev));
1895 disp_dev[strlen(plat_data->disp_dev)] = '\0';
1898 dev_info(&pdev->dev, "register mxc display driver %s\n", disp_dev);
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");
1907 mxcfbi->ipu_di_pix_fmt = setting.if_fmt;
1908 mxcfbi->default_bpp = setting.default_bpp;
1911 mxcfbi->ipu_id = setting.dev_id;
1912 mxcfbi->ipu_di = setting.disp_id;
1919 * Parse user specified options (`video=trident:')
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
1924 static int mxcfb_option_setup(struct platform_device *pdev, struct fb_info *fbi)
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;
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);
1937 if (!options || !*options)
1940 while ((opt = strsep(&options, ",")) != NULL) {
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;
1985 pixfmt_to_var(fb_pix_fmt, &fbi->var);
1986 pdata->default_bpp =
1987 fbi->var.bits_per_pixel;
1989 } else if (!strncmp(opt, "int_clk", 7)) {
1990 pdata->int_clk = true;
1992 } else if (!strncmp(opt, "bpp=", 4)) {
1993 /* bpp setting cannot overwirte fbpix setting */
1997 pdata->default_bpp =
1998 simple_strtoul(opt + 4, NULL, 0);
2000 fb_pix_fmt = bpp_to_pixfmt(pdata->default_bpp);
2002 pixfmt_to_var(fb_pix_fmt, &fbi->var);
2008 pdata->mode_str = fb_mode_str;
2013 static int mxcfb_register(struct fb_info *fbi)
2015 struct mxcfb_info *mxcfbi = (struct mxcfb_info *)fbi->par;
2016 struct fb_videomode m;
2018 char bg0_id[] = "DISP3 BG";
2019 char bg1_id[] = "DISP3 BG - DI1";
2020 char fg_id[] = "DISP3 FG";
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);
2033 mxcfb_check_var(&fbi->var, fbi);
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);
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");
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");
2056 ipu_disable_irq(mxcfbi->ipu, mxcfbi->ipu_ch_nf_irq);
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 "
2068 if (!mxcfbi->late_init) {
2069 fbi->var.activate |= FB_ACTIVATE_FORCE;
2071 fbi->flags |= FBINFO_MISC_USEREVENT;
2072 ret = fb_set_var(fbi, &fbi->var);
2073 fbi->flags &= ~FBINFO_MISC_USEREVENT;
2076 dev_err(fbi->device, "Error fb_set_var ret:%d\n", ret);
2080 if (mxcfbi->next_blank == FB_BLANK_UNBLANK) {
2082 ret = fb_blank(fbi, FB_BLANK_UNBLANK);
2085 dev_err(fbi->device,
2086 "Error fb_blank ret:%d\n", ret);
2092 * Setup the channel again though bootloader
2093 * has done this, then set_par() can stop the
2094 * channel neatly and re-initialize it .
2096 if (mxcfbi->next_blank == FB_BLANK_UNBLANK) {
2098 _setup_disp_channel1(fbi);
2099 ipu_enable_channel(mxcfbi->ipu, mxcfbi->ipu_ch);
2105 ret = register_framebuffer(fbi);
2111 if (mxcfbi->next_blank == FB_BLANK_UNBLANK) {
2113 if (!mxcfbi->late_init)
2114 fb_blank(fbi, FB_BLANK_POWERDOWN);
2116 ipu_disable_channel(mxcfbi->ipu, mxcfbi->ipu_ch,
2118 ipu_uninit_channel(mxcfbi->ipu, mxcfbi->ipu_ch);
2124 if (mxcfbi->ipu_alp_ch_irq != -1)
2125 ipu_free_irq(mxcfbi->ipu, mxcfbi->ipu_alp_ch_irq, fbi);
2127 ipu_free_irq(mxcfbi->ipu, mxcfbi->ipu_ch_nf_irq, fbi);
2129 ipu_free_irq(mxcfbi->ipu, mxcfbi->ipu_ch_irq, fbi);
2134 static void mxcfb_unregister(struct fb_info *fbi)
2136 struct mxcfb_info *mxcfbi = (struct mxcfb_info *)fbi->par;
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);
2145 unregister_framebuffer(fbi);
2148 static int mxcfb_setup_overlay(struct platform_device *pdev,
2149 struct fb_info *fbi_bg, struct resource *res)
2151 struct fb_info *ovfbi;
2152 struct mxcfb_info *mxcfbi_bg = (struct mxcfb_info *)fbi_bg->par;
2153 struct mxcfb_info *mxcfbi_fg;
2156 ovfbi = mxcfb_init_fbinfo(&pdev->dev, &mxcfb_ops);
2159 goto init_ovfbinfo_failed;
2161 mxcfbi_fg = (struct mxcfb_info *)ovfbi->par;
2163 mxcfbi_fg->ipu = ipu_get_soc(mxcfbi_bg->ipu_id);
2164 if (IS_ERR(mxcfbi_fg->ipu)) {
2166 goto get_ipu_failed;
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;
2178 /* Need dummy values until real panel is configured */
2179 ovfbi->var.xres = 240;
2180 ovfbi->var.yres = 320;
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);
2190 ret = mxcfb_register(ovfbi);
2192 goto register_ov_failed;
2194 mxcfbi_bg->ovfbi = ovfbi;
2200 fb_dealloc_cmap(&ovfbi->cmap);
2201 framebuffer_release(ovfbi);
2202 init_ovfbinfo_failed:
2206 static void mxcfb_unsetup_overlay(struct fb_info *fbi_bg)
2208 struct mxcfb_info *mxcfbi_bg = (struct mxcfb_info *)fbi_bg->par;
2209 struct fb_info *ovfbi = mxcfbi_bg->ovfbi;
2211 mxcfb_unregister(ovfbi);
2214 fb_dealloc_cmap(&ovfbi->cmap);
2215 framebuffer_release(ovfbi);
2218 static bool ipu_usage[2][2];
2219 static int ipu_test_set_usage(int ipu, int di)
2221 if (ipu_usage[ipu][di])
2224 ipu_usage[ipu][di] = true;
2228 static void ipu_clear_usage(int ipu, int di)
2230 ipu_usage[ipu][di] = false;
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.
2239 * @return Appropriate error code to the kernel common code
2241 static int mxcfb_probe(struct platform_device *pdev)
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;
2249 /* Initialize FB structures */
2250 fbi = mxcfb_init_fbinfo(&pdev->dev, &mxcfb_ops);
2253 goto init_fbinfo_failed;
2256 ret = mxcfb_option_setup(pdev, fbi);
2258 goto get_fb_option_failed;
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);
2266 goto init_dispdrv_failed;
2268 ret = ipu_test_set_usage(mxcfbi->ipu_id, mxcfbi->ipu_di);
2270 dev_err(&pdev->dev, "ipu%d-di%d already in use\n",
2271 mxcfbi->ipu_id, mxcfbi->ipu_di);
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);
2285 mxcfbi->ipu = ipu_get_soc(mxcfbi->ipu_id);
2286 if (IS_ERR(mxcfbi->ipu)) {
2288 goto get_ipu_failed;
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 */
2299 mxcfbi->cur_blank = mxcfbi->next_blank = FB_BLANK_UNBLANK;
2301 mxcfbi->cur_blank = mxcfbi->next_blank = FB_BLANK_POWERDOWN;
2303 ret = mxcfb_register(fbi);
2305 goto mxcfb_register_failed;
2307 ipu_disp_set_global_alpha(mxcfbi->ipu, mxcfbi->ipu_ch,
2309 ipu_disp_set_color_key(mxcfbi->ipu, mxcfbi->ipu_ch, false, 0);
2311 res = platform_get_resource(pdev, IORESOURCE_MEM, 1);
2312 ret = mxcfb_setup_overlay(pdev, fbi, res);
2315 mxcfb_unregister(fbi);
2316 goto mxcfb_setupoverlay_failed;
2319 g_dp_in_use[mxcfbi->ipu_id] = true;
2321 ret = device_create_file(mxcfbi->ovfbi->dev,
2322 &dev_attr_fsl_disp_property);
2324 dev_err(mxcfbi->ovfbi->dev, "Error %d on creating "
2325 "file for disp property\n",
2328 ret = device_create_file(mxcfbi->ovfbi->dev,
2329 &dev_attr_fsl_disp_dev_property);
2331 dev_err(mxcfbi->ovfbi->dev, "Error %d on creating "
2332 "file for disp device "
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;
2341 ret = mxcfb_register(fbi);
2343 goto mxcfb_register_failed;
2346 platform_set_drvdata(pdev, fbi);
2348 ret = device_create_file(fbi->dev, &dev_attr_fsl_disp_property);
2350 dev_err(&pdev->dev, "Error %d on creating file for disp "
2353 ret = device_create_file(fbi->dev, &dev_attr_fsl_disp_dev_property);
2355 dev_err(&pdev->dev, "Error %d on creating file for disp "
2356 " device propety\n", ret);
2359 fb_prepare_logo(fbi, 0);
2360 fb_show_logo(fbi, 0);
2365 mxcfb_setupoverlay_failed:
2366 mxcfb_register_failed:
2368 ipu_clear_usage(mxcfbi->ipu_id, mxcfbi->ipu_di);
2370 init_dispdrv_failed:
2371 fb_dealloc_cmap(&fbi->cmap);
2372 framebuffer_release(fbi);
2373 get_fb_option_failed:
2378 static int mxcfb_remove(struct platform_device *pdev)
2380 struct fb_info *fbi = platform_get_drvdata(pdev);
2381 struct mxcfb_info *mxc_fbi = fbi->par;
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);
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);
2402 ipu_clear_usage(mxc_fbi->ipu_id, mxc_fbi->ipu_di);
2404 fb_dealloc_cmap(&fbi->cmap);
2405 framebuffer_release(fbi);
2410 * This structure contains pointers to the power management callback functions.
2412 static struct platform_driver mxcfb_driver = {
2416 .probe = mxcfb_probe,
2417 .remove = mxcfb_remove,
2418 .suspend = mxcfb_suspend,
2419 .resume = mxcfb_resume,
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
2427 * @return Error code indicating success or failure
2429 int __init mxcfb_init(void)
2431 return platform_driver_register(&mxcfb_driver);
2434 void mxcfb_exit(void)
2436 platform_driver_unregister(&mxcfb_driver);
2439 module_init(mxcfb_init);
2440 module_exit(mxcfb_exit);
2442 MODULE_AUTHOR("Freescale Semiconductor, Inc.");
2443 MODULE_DESCRIPTION("MXC framebuffer driver");
2444 MODULE_LICENSE("GPL");
2445 MODULE_SUPPORTED_DEVICE("fb");