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