xref: /openbmc/u-boot/drivers/video/mxc_ipuv3_fb.c (revision e8f80a5a)
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(&params, 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, &params);
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