15dda7945SStefano Babic /*
25dda7945SStefano Babic * Porting to u-boot:
35dda7945SStefano Babic *
45dda7945SStefano Babic * (C) Copyright 2010
55dda7945SStefano Babic * Stefano Babic, DENX Software Engineering, sbabic@denx.de
65dda7945SStefano Babic *
75dda7945SStefano Babic * MX51 Linux framebuffer:
85dda7945SStefano Babic *
95dda7945SStefano Babic * (C) Copyright 2004-2010 Freescale Semiconductor, Inc.
105dda7945SStefano Babic *
111a459660SWolfgang Denk * SPDX-License-Identifier: GPL-2.0+
125dda7945SStefano Babic */
135dda7945SStefano Babic
145dda7945SStefano Babic #include <common.h>
151221ce45SMasahiro Yamada #include <linux/errno.h>
16a69214dcSEric Nelson #include <asm/global_data.h>
175dda7945SStefano Babic #include <linux/string.h>
185dda7945SStefano Babic #include <linux/list.h>
195dda7945SStefano Babic #include <linux/fb.h>
205dda7945SStefano Babic #include <asm/io.h>
215dda7945SStefano Babic #include <malloc.h>
22e9934f0bSStefano Babic #include <video_fb.h>
235dda7945SStefano Babic #include "videomodes.h"
245dda7945SStefano Babic #include "ipu.h"
255dda7945SStefano Babic #include "mxcfb.h"
265f8e17ceSEric Nelson #include "ipu_regs.h"
275dda7945SStefano Babic
28a69214dcSEric Nelson DECLARE_GLOBAL_DATA_PTR;
29a69214dcSEric Nelson
305dda7945SStefano Babic static int mxcfb_map_video_memory(struct fb_info *fbi);
315dda7945SStefano Babic static int mxcfb_unmap_video_memory(struct fb_info *fbi);
325dda7945SStefano Babic
33e9934f0bSStefano Babic /* graphics setup */
34e9934f0bSStefano Babic static GraphicDevice panel;
3509c8bb26SEric Nelson static struct fb_videomode const *gmode;
3602ae1a18SMarek Vasut static uint8_t gdisp;
3702ae1a18SMarek Vasut static uint32_t gpixfmt;
385dda7945SStefano Babic
fb_videomode_to_var(struct fb_var_screeninfo * var,const struct fb_videomode * mode)39c5fe2532SJeroen Hofstee static void fb_videomode_to_var(struct fb_var_screeninfo *var,
405dda7945SStefano Babic const struct fb_videomode *mode)
415dda7945SStefano Babic {
425dda7945SStefano Babic var->xres = mode->xres;
435dda7945SStefano Babic var->yres = mode->yres;
445dda7945SStefano Babic var->xres_virtual = mode->xres;
455dda7945SStefano Babic var->yres_virtual = mode->yres;
465dda7945SStefano Babic var->xoffset = 0;
475dda7945SStefano Babic var->yoffset = 0;
485dda7945SStefano Babic var->pixclock = mode->pixclock;
495dda7945SStefano Babic var->left_margin = mode->left_margin;
505dda7945SStefano Babic var->right_margin = mode->right_margin;
515dda7945SStefano Babic var->upper_margin = mode->upper_margin;
525dda7945SStefano Babic var->lower_margin = mode->lower_margin;
535dda7945SStefano Babic var->hsync_len = mode->hsync_len;
545dda7945SStefano Babic var->vsync_len = mode->vsync_len;
555dda7945SStefano Babic var->sync = mode->sync;
565dda7945SStefano Babic var->vmode = mode->vmode & FB_VMODE_MASK;
575dda7945SStefano Babic }
585dda7945SStefano Babic
595dda7945SStefano Babic /*
605dda7945SStefano Babic * Structure containing the MXC specific framebuffer information.
615dda7945SStefano Babic */
625dda7945SStefano Babic struct mxcfb_info {
635dda7945SStefano Babic int blank;
645dda7945SStefano Babic ipu_channel_t ipu_ch;
655dda7945SStefano Babic int ipu_di;
665dda7945SStefano Babic u32 ipu_di_pix_fmt;
675dda7945SStefano Babic unsigned char overlay;
685dda7945SStefano Babic unsigned char alpha_chan_en;
695dda7945SStefano Babic dma_addr_t alpha_phy_addr0;
705dda7945SStefano Babic dma_addr_t alpha_phy_addr1;
715dda7945SStefano Babic void *alpha_virt_addr0;
725dda7945SStefano Babic void *alpha_virt_addr1;
735dda7945SStefano Babic uint32_t alpha_mem_len;
745dda7945SStefano Babic uint32_t cur_ipu_buf;
755dda7945SStefano Babic uint32_t cur_ipu_alpha_buf;
765dda7945SStefano Babic
775dda7945SStefano Babic u32 pseudo_palette[16];
785dda7945SStefano Babic };
795dda7945SStefano Babic
805dda7945SStefano Babic enum {
815dda7945SStefano Babic BOTH_ON,
825dda7945SStefano Babic SRC_ON,
835dda7945SStefano Babic TGT_ON,
845dda7945SStefano Babic BOTH_OFF
855dda7945SStefano Babic };
865dda7945SStefano Babic
875dda7945SStefano Babic static unsigned long default_bpp = 16;
885dda7945SStefano Babic static unsigned char g_dp_in_use;
895dda7945SStefano Babic static struct fb_info *mxcfb_info[3];
905dda7945SStefano Babic static int ext_clk_used;
915dda7945SStefano Babic
bpp_to_pixfmt(struct fb_info * fbi)925dda7945SStefano Babic static uint32_t bpp_to_pixfmt(struct fb_info *fbi)
935dda7945SStefano Babic {
945dda7945SStefano Babic uint32_t pixfmt = 0;
955dda7945SStefano Babic
965dda7945SStefano Babic debug("bpp_to_pixfmt: %d\n", fbi->var.bits_per_pixel);
975dda7945SStefano Babic
985dda7945SStefano Babic if (fbi->var.nonstd)
995dda7945SStefano Babic return fbi->var.nonstd;
1005dda7945SStefano Babic
1015dda7945SStefano Babic switch (fbi->var.bits_per_pixel) {
1025dda7945SStefano Babic case 24:
1035dda7945SStefano Babic pixfmt = IPU_PIX_FMT_BGR24;
1045dda7945SStefano Babic break;
1055dda7945SStefano Babic case 32:
1065dda7945SStefano Babic pixfmt = IPU_PIX_FMT_BGR32;
1075dda7945SStefano Babic break;
1085dda7945SStefano Babic case 16:
1095dda7945SStefano Babic pixfmt = IPU_PIX_FMT_RGB565;
1105dda7945SStefano Babic break;
1115dda7945SStefano Babic }
1125dda7945SStefano Babic return pixfmt;
1135dda7945SStefano Babic }
1145dda7945SStefano Babic
1155dda7945SStefano Babic /*
1165dda7945SStefano Babic * Set fixed framebuffer parameters based on variable settings.
1175dda7945SStefano Babic *
1185dda7945SStefano Babic * @param info framebuffer information pointer
1195dda7945SStefano Babic */
mxcfb_set_fix(struct fb_info * info)1205dda7945SStefano Babic static int mxcfb_set_fix(struct fb_info *info)
1215dda7945SStefano Babic {
1225dda7945SStefano Babic struct fb_fix_screeninfo *fix = &info->fix;
1235dda7945SStefano Babic struct fb_var_screeninfo *var = &info->var;
1245dda7945SStefano Babic
1255dda7945SStefano Babic fix->line_length = var->xres_virtual * var->bits_per_pixel / 8;
1265dda7945SStefano Babic
1275dda7945SStefano Babic fix->type = FB_TYPE_PACKED_PIXELS;
1285dda7945SStefano Babic fix->accel = FB_ACCEL_NONE;
1295dda7945SStefano Babic fix->visual = FB_VISUAL_TRUECOLOR;
1305dda7945SStefano Babic fix->xpanstep = 1;
1315dda7945SStefano Babic fix->ypanstep = 1;
1325dda7945SStefano Babic
1335dda7945SStefano Babic return 0;
1345dda7945SStefano Babic }
1355dda7945SStefano Babic
setup_disp_channel1(struct fb_info * fbi)1365dda7945SStefano Babic static int setup_disp_channel1(struct fb_info *fbi)
1375dda7945SStefano Babic {
1385dda7945SStefano Babic ipu_channel_params_t params;
1395dda7945SStefano Babic struct mxcfb_info *mxc_fbi = (struct mxcfb_info *)fbi->par;
1405dda7945SStefano Babic
1415dda7945SStefano Babic memset(¶ms, 0, sizeof(params));
1425dda7945SStefano Babic params.mem_dp_bg_sync.di = mxc_fbi->ipu_di;
1435dda7945SStefano Babic
1445dda7945SStefano Babic debug("%s called\n", __func__);
1455dda7945SStefano Babic /*
1465dda7945SStefano Babic * Assuming interlaced means yuv output, below setting also
1475dda7945SStefano Babic * valid for mem_dc_sync. FG should have the same vmode as BG.
1485dda7945SStefano Babic */
1495dda7945SStefano Babic if (fbi->var.vmode & FB_VMODE_INTERLACED) {
1505dda7945SStefano Babic params.mem_dp_bg_sync.interlaced = 1;
1515dda7945SStefano Babic params.mem_dp_bg_sync.out_pixel_fmt =
1525dda7945SStefano Babic IPU_PIX_FMT_YUV444;
1535dda7945SStefano Babic } else {
1545dda7945SStefano Babic if (mxc_fbi->ipu_di_pix_fmt) {
1555dda7945SStefano Babic params.mem_dp_bg_sync.out_pixel_fmt =
1565dda7945SStefano Babic mxc_fbi->ipu_di_pix_fmt;
1575dda7945SStefano Babic } else {
1585dda7945SStefano Babic params.mem_dp_bg_sync.out_pixel_fmt =
1595dda7945SStefano Babic IPU_PIX_FMT_RGB666;
1605dda7945SStefano Babic }
1615dda7945SStefano Babic }
1625dda7945SStefano Babic params.mem_dp_bg_sync.in_pixel_fmt = bpp_to_pixfmt(fbi);
1635dda7945SStefano Babic if (mxc_fbi->alpha_chan_en)
1645dda7945SStefano Babic params.mem_dp_bg_sync.alpha_chan_en = 1;
1655dda7945SStefano Babic
1665dda7945SStefano Babic ipu_init_channel(mxc_fbi->ipu_ch, ¶ms);
1675dda7945SStefano Babic
1685dda7945SStefano Babic return 0;
1695dda7945SStefano Babic }
1705dda7945SStefano Babic
setup_disp_channel2(struct fb_info * fbi)1715dda7945SStefano Babic static int setup_disp_channel2(struct fb_info *fbi)
1725dda7945SStefano Babic {
1735dda7945SStefano Babic int retval = 0;
1745dda7945SStefano Babic struct mxcfb_info *mxc_fbi = (struct mxcfb_info *)fbi->par;
1755dda7945SStefano Babic
1765dda7945SStefano Babic mxc_fbi->cur_ipu_buf = 1;
1775dda7945SStefano Babic if (mxc_fbi->alpha_chan_en)
1785dda7945SStefano Babic mxc_fbi->cur_ipu_alpha_buf = 1;
1795dda7945SStefano Babic
1805dda7945SStefano Babic fbi->var.xoffset = fbi->var.yoffset = 0;
1815dda7945SStefano Babic
1825dda7945SStefano Babic debug("%s: %x %d %d %d %lx %lx\n",
1835dda7945SStefano Babic __func__,
1845dda7945SStefano Babic mxc_fbi->ipu_ch,
1855dda7945SStefano Babic fbi->var.xres,
1865dda7945SStefano Babic fbi->var.yres,
1875dda7945SStefano Babic fbi->fix.line_length,
1885dda7945SStefano Babic fbi->fix.smem_start,
1895dda7945SStefano Babic fbi->fix.smem_start +
1905dda7945SStefano Babic (fbi->fix.line_length * fbi->var.yres));
1915dda7945SStefano Babic
1925dda7945SStefano Babic retval = ipu_init_channel_buffer(mxc_fbi->ipu_ch, IPU_INPUT_BUFFER,
1935dda7945SStefano Babic bpp_to_pixfmt(fbi),
1945dda7945SStefano Babic fbi->var.xres, fbi->var.yres,
1955dda7945SStefano Babic fbi->fix.line_length,
1965dda7945SStefano Babic fbi->fix.smem_start +
1975dda7945SStefano Babic (fbi->fix.line_length * fbi->var.yres),
1985dda7945SStefano Babic fbi->fix.smem_start,
1995dda7945SStefano Babic 0, 0);
2005dda7945SStefano Babic if (retval)
2015dda7945SStefano Babic printf("ipu_init_channel_buffer error %d\n", retval);
2025dda7945SStefano Babic
2035dda7945SStefano Babic return retval;
2045dda7945SStefano Babic }
2055dda7945SStefano Babic
2065dda7945SStefano Babic /*
2075dda7945SStefano Babic * Set framebuffer parameters and change the operating mode.
2085dda7945SStefano Babic *
2095dda7945SStefano Babic * @param info framebuffer information pointer
2105dda7945SStefano Babic */
mxcfb_set_par(struct fb_info * fbi)2115dda7945SStefano Babic static int mxcfb_set_par(struct fb_info *fbi)
2125dda7945SStefano Babic {
2135dda7945SStefano Babic int retval = 0;
2145dda7945SStefano Babic u32 mem_len;
2155dda7945SStefano Babic ipu_di_signal_cfg_t sig_cfg;
2165dda7945SStefano Babic struct mxcfb_info *mxc_fbi = (struct mxcfb_info *)fbi->par;
2175dda7945SStefano Babic uint32_t out_pixel_fmt;
2185dda7945SStefano Babic
2195dda7945SStefano Babic ipu_disable_channel(mxc_fbi->ipu_ch);
2205dda7945SStefano Babic ipu_uninit_channel(mxc_fbi->ipu_ch);
2215dda7945SStefano Babic mxcfb_set_fix(fbi);
2225dda7945SStefano Babic
2235dda7945SStefano Babic mem_len = fbi->var.yres_virtual * fbi->fix.line_length;
2245dda7945SStefano Babic if (!fbi->fix.smem_start || (mem_len > fbi->fix.smem_len)) {
2255dda7945SStefano Babic if (fbi->fix.smem_start)
2265dda7945SStefano Babic mxcfb_unmap_video_memory(fbi);
2275dda7945SStefano Babic
2285dda7945SStefano Babic if (mxcfb_map_video_memory(fbi) < 0)
2295dda7945SStefano Babic return -ENOMEM;
2305dda7945SStefano Babic }
2315dda7945SStefano Babic
2325dda7945SStefano Babic setup_disp_channel1(fbi);
2335dda7945SStefano Babic
2345dda7945SStefano Babic memset(&sig_cfg, 0, sizeof(sig_cfg));
2355dda7945SStefano Babic if (fbi->var.vmode & FB_VMODE_INTERLACED) {
2365dda7945SStefano Babic sig_cfg.interlaced = 1;
2375dda7945SStefano Babic out_pixel_fmt = IPU_PIX_FMT_YUV444;
2385dda7945SStefano Babic } else {
2395dda7945SStefano Babic if (mxc_fbi->ipu_di_pix_fmt)
2405dda7945SStefano Babic out_pixel_fmt = mxc_fbi->ipu_di_pix_fmt;
2415dda7945SStefano Babic else
2425dda7945SStefano Babic out_pixel_fmt = IPU_PIX_FMT_RGB666;
2435dda7945SStefano Babic }
2445dda7945SStefano Babic if (fbi->var.vmode & FB_VMODE_ODD_FLD_FIRST) /* PAL */
2455dda7945SStefano Babic sig_cfg.odd_field_first = 1;
2465dda7945SStefano Babic if ((fbi->var.sync & FB_SYNC_EXT) || ext_clk_used)
2475dda7945SStefano Babic sig_cfg.ext_clk = 1;
2485dda7945SStefano Babic if (fbi->var.sync & FB_SYNC_HOR_HIGH_ACT)
2495dda7945SStefano Babic sig_cfg.Hsync_pol = 1;
2505dda7945SStefano Babic if (fbi->var.sync & FB_SYNC_VERT_HIGH_ACT)
2515dda7945SStefano Babic sig_cfg.Vsync_pol = 1;
2525dda7945SStefano Babic if (!(fbi->var.sync & FB_SYNC_CLK_LAT_FALL))
2535dda7945SStefano Babic sig_cfg.clk_pol = 1;
2545dda7945SStefano Babic if (fbi->var.sync & FB_SYNC_DATA_INVERT)
2555dda7945SStefano Babic sig_cfg.data_pol = 1;
2565dda7945SStefano Babic if (!(fbi->var.sync & FB_SYNC_OE_LOW_ACT))
2575dda7945SStefano Babic sig_cfg.enable_pol = 1;
2585dda7945SStefano Babic if (fbi->var.sync & FB_SYNC_CLK_IDLE_EN)
2595dda7945SStefano Babic sig_cfg.clkidle_en = 1;
2605dda7945SStefano Babic
261c1420328SJeroen Hofstee debug("pixclock = %lu Hz\n", PICOS2KHZ(fbi->var.pixclock) * 1000UL);
2625dda7945SStefano Babic
2635dda7945SStefano Babic if (ipu_init_sync_panel(mxc_fbi->ipu_di,
2645dda7945SStefano Babic (PICOS2KHZ(fbi->var.pixclock)) * 1000UL,
2655dda7945SStefano Babic fbi->var.xres, fbi->var.yres,
2665dda7945SStefano Babic out_pixel_fmt,
2675dda7945SStefano Babic fbi->var.left_margin,
2685dda7945SStefano Babic fbi->var.hsync_len,
2695dda7945SStefano Babic fbi->var.right_margin,
2705dda7945SStefano Babic fbi->var.upper_margin,
2715dda7945SStefano Babic fbi->var.vsync_len,
2725dda7945SStefano Babic fbi->var.lower_margin,
2735dda7945SStefano Babic 0, sig_cfg) != 0) {
2745dda7945SStefano Babic puts("mxcfb: Error initializing panel.\n");
2755dda7945SStefano Babic return -EINVAL;
2765dda7945SStefano Babic }
2775dda7945SStefano Babic
2785dda7945SStefano Babic retval = setup_disp_channel2(fbi);
2795dda7945SStefano Babic if (retval)
2805dda7945SStefano Babic return retval;
2815dda7945SStefano Babic
2825dda7945SStefano Babic if (mxc_fbi->blank == FB_BLANK_UNBLANK)
2835dda7945SStefano Babic ipu_enable_channel(mxc_fbi->ipu_ch);
2845dda7945SStefano Babic
2855dda7945SStefano Babic return retval;
2865dda7945SStefano Babic }
2875dda7945SStefano Babic
2885dda7945SStefano Babic /*
2895dda7945SStefano Babic * Check framebuffer variable parameters and adjust to valid values.
2905dda7945SStefano Babic *
2915dda7945SStefano Babic * @param var framebuffer variable parameters
2925dda7945SStefano Babic *
2935dda7945SStefano Babic * @param info framebuffer information pointer
2945dda7945SStefano Babic */
mxcfb_check_var(struct fb_var_screeninfo * var,struct fb_info * info)2955dda7945SStefano Babic static int mxcfb_check_var(struct fb_var_screeninfo *var, struct fb_info *info)
2965dda7945SStefano Babic {
2975dda7945SStefano Babic u32 vtotal;
2985dda7945SStefano Babic u32 htotal;
2995dda7945SStefano Babic
3005dda7945SStefano Babic if (var->xres_virtual < var->xres)
3015dda7945SStefano Babic var->xres_virtual = var->xres;
3025dda7945SStefano Babic if (var->yres_virtual < var->yres)
3035dda7945SStefano Babic var->yres_virtual = var->yres;
3045dda7945SStefano Babic
3055dda7945SStefano Babic if ((var->bits_per_pixel != 32) && (var->bits_per_pixel != 24) &&
3065dda7945SStefano Babic (var->bits_per_pixel != 16) && (var->bits_per_pixel != 8))
3075dda7945SStefano Babic var->bits_per_pixel = default_bpp;
3085dda7945SStefano Babic
3095dda7945SStefano Babic switch (var->bits_per_pixel) {
3105dda7945SStefano Babic case 8:
3115dda7945SStefano Babic var->red.length = 3;
3125dda7945SStefano Babic var->red.offset = 5;
3135dda7945SStefano Babic var->red.msb_right = 0;
3145dda7945SStefano Babic
3155dda7945SStefano Babic var->green.length = 3;
3165dda7945SStefano Babic var->green.offset = 2;
3175dda7945SStefano Babic var->green.msb_right = 0;
3185dda7945SStefano Babic
3195dda7945SStefano Babic var->blue.length = 2;
3205dda7945SStefano Babic var->blue.offset = 0;
3215dda7945SStefano Babic var->blue.msb_right = 0;
3225dda7945SStefano Babic
3235dda7945SStefano Babic var->transp.length = 0;
3245dda7945SStefano Babic var->transp.offset = 0;
3255dda7945SStefano Babic var->transp.msb_right = 0;
3265dda7945SStefano Babic break;
3275dda7945SStefano Babic case 16:
3285dda7945SStefano Babic var->red.length = 5;
3295dda7945SStefano Babic var->red.offset = 11;
3305dda7945SStefano Babic var->red.msb_right = 0;
3315dda7945SStefano Babic
3325dda7945SStefano Babic var->green.length = 6;
3335dda7945SStefano Babic var->green.offset = 5;
3345dda7945SStefano Babic var->green.msb_right = 0;
3355dda7945SStefano Babic
3365dda7945SStefano Babic var->blue.length = 5;
3375dda7945SStefano Babic var->blue.offset = 0;
3385dda7945SStefano Babic var->blue.msb_right = 0;
3395dda7945SStefano Babic
3405dda7945SStefano Babic var->transp.length = 0;
3415dda7945SStefano Babic var->transp.offset = 0;
3425dda7945SStefano Babic var->transp.msb_right = 0;
3435dda7945SStefano Babic break;
3445dda7945SStefano Babic case 24:
3455dda7945SStefano Babic var->red.length = 8;
3465dda7945SStefano Babic var->red.offset = 16;
3475dda7945SStefano Babic var->red.msb_right = 0;
3485dda7945SStefano Babic
3495dda7945SStefano Babic var->green.length = 8;
3505dda7945SStefano Babic var->green.offset = 8;
3515dda7945SStefano Babic var->green.msb_right = 0;
3525dda7945SStefano Babic
3535dda7945SStefano Babic var->blue.length = 8;
3545dda7945SStefano Babic var->blue.offset = 0;
3555dda7945SStefano Babic var->blue.msb_right = 0;
3565dda7945SStefano Babic
3575dda7945SStefano Babic var->transp.length = 0;
3585dda7945SStefano Babic var->transp.offset = 0;
3595dda7945SStefano Babic var->transp.msb_right = 0;
3605dda7945SStefano Babic break;
3615dda7945SStefano Babic case 32:
3625dda7945SStefano Babic var->red.length = 8;
3635dda7945SStefano Babic var->red.offset = 16;
3645dda7945SStefano Babic var->red.msb_right = 0;
3655dda7945SStefano Babic
3665dda7945SStefano Babic var->green.length = 8;
3675dda7945SStefano Babic var->green.offset = 8;
3685dda7945SStefano Babic var->green.msb_right = 0;
3695dda7945SStefano Babic
3705dda7945SStefano Babic var->blue.length = 8;
3715dda7945SStefano Babic var->blue.offset = 0;
3725dda7945SStefano Babic var->blue.msb_right = 0;
3735dda7945SStefano Babic
3745dda7945SStefano Babic var->transp.length = 8;
3755dda7945SStefano Babic var->transp.offset = 24;
3765dda7945SStefano Babic var->transp.msb_right = 0;
3775dda7945SStefano Babic break;
3785dda7945SStefano Babic }
3795dda7945SStefano Babic
3805dda7945SStefano Babic if (var->pixclock < 1000) {
3815dda7945SStefano Babic htotal = var->xres + var->right_margin + var->hsync_len +
3825dda7945SStefano Babic var->left_margin;
3835dda7945SStefano Babic vtotal = var->yres + var->lower_margin + var->vsync_len +
3845dda7945SStefano Babic var->upper_margin;
3855dda7945SStefano Babic var->pixclock = (vtotal * htotal * 6UL) / 100UL;
3865dda7945SStefano Babic var->pixclock = KHZ2PICOS(var->pixclock);
3875dda7945SStefano Babic printf("pixclock set for 60Hz refresh = %u ps\n",
3885dda7945SStefano Babic var->pixclock);
3895dda7945SStefano Babic }
3905dda7945SStefano Babic
3915dda7945SStefano Babic var->height = -1;
3925dda7945SStefano Babic var->width = -1;
3935dda7945SStefano Babic var->grayscale = 0;
3945dda7945SStefano Babic
3955dda7945SStefano Babic return 0;
3965dda7945SStefano Babic }
3975dda7945SStefano Babic
mxcfb_map_video_memory(struct fb_info * fbi)3985dda7945SStefano Babic static int mxcfb_map_video_memory(struct fb_info *fbi)
3995dda7945SStefano Babic {
4005dda7945SStefano Babic if (fbi->fix.smem_len < fbi->var.yres_virtual * fbi->fix.line_length) {
4015dda7945SStefano Babic fbi->fix.smem_len = fbi->var.yres_virtual *
4025dda7945SStefano Babic fbi->fix.line_length;
4035dda7945SStefano Babic }
4044acb4d39SEric Nelson fbi->fix.smem_len = roundup(fbi->fix.smem_len, ARCH_DMA_MINALIGN);
4054acb4d39SEric Nelson fbi->screen_base = (char *)memalign(ARCH_DMA_MINALIGN,
4064acb4d39SEric Nelson fbi->fix.smem_len);
407e9934f0bSStefano Babic fbi->fix.smem_start = (unsigned long)fbi->screen_base;
4085dda7945SStefano Babic if (fbi->screen_base == 0) {
4095dda7945SStefano Babic puts("Unable to allocate framebuffer memory\n");
4105dda7945SStefano Babic fbi->fix.smem_len = 0;
4115dda7945SStefano Babic fbi->fix.smem_start = 0;
4125dda7945SStefano Babic return -EBUSY;
4135dda7945SStefano Babic }
4145dda7945SStefano Babic
4155dda7945SStefano Babic debug("allocated fb @ paddr=0x%08X, size=%d.\n",
4165dda7945SStefano Babic (uint32_t) fbi->fix.smem_start, fbi->fix.smem_len);
4175dda7945SStefano Babic
4185dda7945SStefano Babic fbi->screen_size = fbi->fix.smem_len;
4195dda7945SStefano Babic
420a69214dcSEric Nelson gd->fb_base = fbi->fix.smem_start;
421a69214dcSEric Nelson
4225dda7945SStefano Babic /* Clear the screen */
4235dda7945SStefano Babic memset((char *)fbi->screen_base, 0, fbi->fix.smem_len);
4245dda7945SStefano Babic
4255dda7945SStefano Babic return 0;
4265dda7945SStefano Babic }
4275dda7945SStefano Babic
mxcfb_unmap_video_memory(struct fb_info * fbi)4285dda7945SStefano Babic static int mxcfb_unmap_video_memory(struct fb_info *fbi)
4295dda7945SStefano Babic {
4305dda7945SStefano Babic fbi->screen_base = 0;
4315dda7945SStefano Babic fbi->fix.smem_start = 0;
4325dda7945SStefano Babic fbi->fix.smem_len = 0;
4335dda7945SStefano Babic return 0;
4345dda7945SStefano Babic }
4355dda7945SStefano Babic
4365dda7945SStefano Babic /*
4375dda7945SStefano Babic * Initializes the framebuffer information pointer. After allocating
4385dda7945SStefano Babic * sufficient memory for the framebuffer structure, the fields are
4395dda7945SStefano Babic * filled with custom information passed in from the configurable
4405dda7945SStefano Babic * structures. This includes information such as bits per pixel,
4415dda7945SStefano Babic * color maps, screen width/height and RGBA offsets.
4425dda7945SStefano Babic *
4435dda7945SStefano Babic * @return Framebuffer structure initialized with our information
4445dda7945SStefano Babic */
mxcfb_init_fbinfo(void)4455dda7945SStefano Babic static struct fb_info *mxcfb_init_fbinfo(void)
4465dda7945SStefano Babic {
4475dda7945SStefano Babic #define BYTES_PER_LONG 4
4485dda7945SStefano Babic #define PADDING (BYTES_PER_LONG - (sizeof(struct fb_info) % BYTES_PER_LONG))
4495dda7945SStefano Babic struct fb_info *fbi;
4505dda7945SStefano Babic struct mxcfb_info *mxcfbi;
4515dda7945SStefano Babic char *p;
4525dda7945SStefano Babic int size = sizeof(struct mxcfb_info) + PADDING +
4535dda7945SStefano Babic sizeof(struct fb_info);
4545dda7945SStefano Babic
4555dda7945SStefano Babic debug("%s: %d %d %d %d\n",
4565dda7945SStefano Babic __func__,
4575dda7945SStefano Babic PADDING,
4585dda7945SStefano Babic size,
4595dda7945SStefano Babic sizeof(struct mxcfb_info),
4605dda7945SStefano Babic sizeof(struct fb_info));
4615dda7945SStefano Babic /*
4625dda7945SStefano Babic * Allocate sufficient memory for the fb structure
4635dda7945SStefano Babic */
4645dda7945SStefano Babic
4655dda7945SStefano Babic p = malloc(size);
4665dda7945SStefano Babic if (!p)
4675dda7945SStefano Babic return NULL;
4685dda7945SStefano Babic
4695dda7945SStefano Babic memset(p, 0, size);
4705dda7945SStefano Babic
4715dda7945SStefano Babic fbi = (struct fb_info *)p;
4725dda7945SStefano Babic fbi->par = p + sizeof(struct fb_info) + PADDING;
4735dda7945SStefano Babic
4745dda7945SStefano Babic mxcfbi = (struct mxcfb_info *)fbi->par;
4755dda7945SStefano Babic debug("Framebuffer structures at: fbi=0x%x mxcfbi=0x%x\n",
4765dda7945SStefano Babic (unsigned int)fbi, (unsigned int)mxcfbi);
4775dda7945SStefano Babic
4785dda7945SStefano Babic fbi->var.activate = FB_ACTIVATE_NOW;
4795dda7945SStefano Babic
4805dda7945SStefano Babic fbi->flags = FBINFO_FLAG_DEFAULT;
4815dda7945SStefano Babic fbi->pseudo_palette = mxcfbi->pseudo_palette;
4825dda7945SStefano Babic
4835dda7945SStefano Babic return fbi;
4845dda7945SStefano Babic }
4855dda7945SStefano Babic
4865dda7945SStefano Babic /*
4875dda7945SStefano Babic * Probe routine for the framebuffer driver. It is called during the
4885dda7945SStefano Babic * driver binding process. The following functions are performed in
4895dda7945SStefano Babic * this routine: Framebuffer initialization, Memory allocation and
4905dda7945SStefano Babic * mapping, Framebuffer registration, IPU initialization.
4915dda7945SStefano Babic *
4925dda7945SStefano Babic * @return Appropriate error code to the kernel common code
4935dda7945SStefano Babic */
mxcfb_probe(u32 interface_pix_fmt,uint8_t disp,struct fb_videomode const * mode)49402ae1a18SMarek Vasut static int mxcfb_probe(u32 interface_pix_fmt, uint8_t disp,
49509c8bb26SEric Nelson struct fb_videomode const *mode)
4965dda7945SStefano Babic {
4975dda7945SStefano Babic struct fb_info *fbi;
4985dda7945SStefano Babic struct mxcfb_info *mxcfbi;
4995dda7945SStefano Babic int ret = 0;
5005dda7945SStefano Babic
5015dda7945SStefano Babic /*
5025dda7945SStefano Babic * Initialize FB structures
5035dda7945SStefano Babic */
5045dda7945SStefano Babic fbi = mxcfb_init_fbinfo();
5055dda7945SStefano Babic if (!fbi) {
5065dda7945SStefano Babic ret = -ENOMEM;
5075dda7945SStefano Babic goto err0;
5085dda7945SStefano Babic }
5095dda7945SStefano Babic mxcfbi = (struct mxcfb_info *)fbi->par;
5105dda7945SStefano Babic
5115dda7945SStefano Babic if (!g_dp_in_use) {
5125dda7945SStefano Babic mxcfbi->ipu_ch = MEM_BG_SYNC;
5135dda7945SStefano Babic mxcfbi->blank = FB_BLANK_UNBLANK;
5145dda7945SStefano Babic } else {
5155dda7945SStefano Babic mxcfbi->ipu_ch = MEM_DC_SYNC;
5165dda7945SStefano Babic mxcfbi->blank = FB_BLANK_POWERDOWN;
5175dda7945SStefano Babic }
5185dda7945SStefano Babic
51902ae1a18SMarek Vasut mxcfbi->ipu_di = disp;
5205dda7945SStefano Babic
5215dda7945SStefano Babic ipu_disp_set_global_alpha(mxcfbi->ipu_ch, 1, 0x80);
5225dda7945SStefano Babic ipu_disp_set_color_key(mxcfbi->ipu_ch, 0, 0);
5235dda7945SStefano Babic strcpy(fbi->fix.id, "DISP3 BG");
5245dda7945SStefano Babic
5255dda7945SStefano Babic g_dp_in_use = 1;
5265dda7945SStefano Babic
5275dda7945SStefano Babic mxcfb_info[mxcfbi->ipu_di] = fbi;
5285dda7945SStefano Babic
5295dda7945SStefano Babic /* Need dummy values until real panel is configured */
5305dda7945SStefano Babic
5315dda7945SStefano Babic mxcfbi->ipu_di_pix_fmt = interface_pix_fmt;
5325dda7945SStefano Babic fb_videomode_to_var(&fbi->var, mode);
533e9934f0bSStefano Babic fbi->var.bits_per_pixel = 16;
534e9934f0bSStefano Babic fbi->fix.line_length = fbi->var.xres * (fbi->var.bits_per_pixel / 8);
535e9934f0bSStefano Babic fbi->fix.smem_len = fbi->var.yres_virtual * fbi->fix.line_length;
5365dda7945SStefano Babic
5375dda7945SStefano Babic mxcfb_check_var(&fbi->var, fbi);
5385dda7945SStefano Babic
5395dda7945SStefano Babic /* Default Y virtual size is 2x panel size */
5405dda7945SStefano Babic fbi->var.yres_virtual = fbi->var.yres * 2;
5415dda7945SStefano Babic
5425dda7945SStefano Babic mxcfb_set_fix(fbi);
5435dda7945SStefano Babic
544c1420328SJeroen Hofstee /* allocate fb first */
5455dda7945SStefano Babic if (mxcfb_map_video_memory(fbi) < 0)
5465dda7945SStefano Babic return -ENOMEM;
5475dda7945SStefano Babic
5485dda7945SStefano Babic mxcfb_set_par(fbi);
5495dda7945SStefano Babic
550e9934f0bSStefano Babic panel.winSizeX = mode->xres;
551e9934f0bSStefano Babic panel.winSizeY = mode->yres;
552e9934f0bSStefano Babic panel.plnSizeX = mode->xres;
553e9934f0bSStefano Babic panel.plnSizeY = mode->yres;
5545dda7945SStefano Babic
555e9934f0bSStefano Babic panel.frameAdrs = (u32)fbi->screen_base;
556e9934f0bSStefano Babic panel.memSize = fbi->screen_size;
5575dda7945SStefano Babic
558e9934f0bSStefano Babic panel.gdfBytesPP = 2;
559e9934f0bSStefano Babic panel.gdfIndex = GDF_16BIT_565RGB;
5605dda7945SStefano Babic
5615dda7945SStefano Babic ipu_dump_registers();
5625dda7945SStefano Babic
5635dda7945SStefano Babic return 0;
5645dda7945SStefano Babic
5655dda7945SStefano Babic err0:
5665dda7945SStefano Babic return ret;
5675dda7945SStefano Babic }
5685dda7945SStefano Babic
ipuv3_fb_shutdown(void)5695f8e17ceSEric Nelson void ipuv3_fb_shutdown(void)
5705f8e17ceSEric Nelson {
5710d1ae97cSAnatolij Gustschin int i;
5729493d05aSTom Rini struct ipu_stat *stat = (struct ipu_stat *)IPU_STAT;
5735f8e17ceSEric Nelson
574*f8ba7f27SAnatolij Gustschin if (!ipu_clk_enabled())
575*f8ba7f27SAnatolij Gustschin return;
576*f8ba7f27SAnatolij Gustschin
5775f8e17ceSEric Nelson for (i = 0; i < ARRAY_SIZE(mxcfb_info); i++) {
5785f8e17ceSEric Nelson struct fb_info *fbi = mxcfb_info[i];
5795f8e17ceSEric Nelson if (fbi) {
5805f8e17ceSEric Nelson struct mxcfb_info *mxc_fbi = fbi->par;
5815f8e17ceSEric Nelson ipu_disable_channel(mxc_fbi->ipu_ch);
5825f8e17ceSEric Nelson ipu_uninit_channel(mxc_fbi->ipu_ch);
5835f8e17ceSEric Nelson }
5845f8e17ceSEric Nelson }
5855f8e17ceSEric Nelson for (i = 0; i < ARRAY_SIZE(stat->int_stat); i++) {
5865f8e17ceSEric Nelson __raw_writel(__raw_readl(&stat->int_stat[i]),
5875f8e17ceSEric Nelson &stat->int_stat[i]);
5885f8e17ceSEric Nelson }
5895f8e17ceSEric Nelson }
5905f8e17ceSEric Nelson
video_hw_init(void)591e9934f0bSStefano Babic void *video_hw_init(void)
5925dda7945SStefano Babic {
5935dda7945SStefano Babic int ret;
5945dda7945SStefano Babic
5955dda7945SStefano Babic ret = ipu_probe();
5965dda7945SStefano Babic if (ret)
5975dda7945SStefano Babic puts("Error initializing IPU\n");
5985dda7945SStefano Babic
59902ae1a18SMarek Vasut ret = mxcfb_probe(gpixfmt, gdisp, gmode);
600e9934f0bSStefano Babic debug("Framebuffer at 0x%x\n", (unsigned int)panel.frameAdrs);
6015dda7945SStefano Babic
602e9934f0bSStefano Babic return (void *)&panel;
603e9934f0bSStefano Babic }
6045dda7945SStefano Babic
ipuv3_fb_init(struct fb_videomode const * mode,uint8_t disp,uint32_t pixfmt)60509c8bb26SEric Nelson int ipuv3_fb_init(struct fb_videomode const *mode,
60609c8bb26SEric Nelson uint8_t disp,
60709c8bb26SEric Nelson uint32_t pixfmt)
608e9934f0bSStefano Babic {
609e9934f0bSStefano Babic gmode = mode;
61002ae1a18SMarek Vasut gdisp = disp;
61102ae1a18SMarek Vasut gpixfmt = pixfmt;
612e9934f0bSStefano Babic
613e9934f0bSStefano Babic return 0;
6145dda7945SStefano Babic }
615