xref: /rk3399_rockchip-uboot/drivers/video/mxc_ipuv3_fb.c (revision 5dda7945d18077db81eb0cfdc2f9d4525e6b77b1)
1*5dda7945SStefano Babic /*
2*5dda7945SStefano Babic  * Porting to u-boot:
3*5dda7945SStefano Babic  *
4*5dda7945SStefano Babic  * (C) Copyright 2010
5*5dda7945SStefano Babic  * Stefano Babic, DENX Software Engineering, sbabic@denx.de
6*5dda7945SStefano Babic  *
7*5dda7945SStefano Babic  * MX51 Linux framebuffer:
8*5dda7945SStefano Babic  *
9*5dda7945SStefano Babic  * (C) Copyright 2004-2010 Freescale Semiconductor, Inc.
10*5dda7945SStefano Babic  *
11*5dda7945SStefano Babic  * See file CREDITS for list of people who contributed to this
12*5dda7945SStefano Babic  * project.
13*5dda7945SStefano Babic  *
14*5dda7945SStefano Babic  * This program is free software; you can redistribute it and/or
15*5dda7945SStefano Babic  * modify it under the terms of the GNU General Public License as
16*5dda7945SStefano Babic  * published by the Free Software Foundation; either version 2 of
17*5dda7945SStefano Babic  * the License, or (at your option) any later version.
18*5dda7945SStefano Babic  *
19*5dda7945SStefano Babic  * This program is distributed in the hope that it will be useful,
20*5dda7945SStefano Babic  * but WITHOUT ANY WARRANTY; without even the implied warranty of
21*5dda7945SStefano Babic  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
22*5dda7945SStefano Babic  * GNU General Public License for more details.
23*5dda7945SStefano Babic  *
24*5dda7945SStefano Babic  * You should have received a copy of the GNU General Public License
25*5dda7945SStefano Babic  * along with this program; if not, write to the Free Software
26*5dda7945SStefano Babic  * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
27*5dda7945SStefano Babic  * MA 02111-1307 USA
28*5dda7945SStefano Babic  */
29*5dda7945SStefano Babic 
30*5dda7945SStefano Babic /* #define DEBUG */
31*5dda7945SStefano Babic #include <common.h>
32*5dda7945SStefano Babic #include <asm/errno.h>
33*5dda7945SStefano Babic #include <linux/string.h>
34*5dda7945SStefano Babic #include <linux/list.h>
35*5dda7945SStefano Babic #include <linux/fb.h>
36*5dda7945SStefano Babic #include <asm/io.h>
37*5dda7945SStefano Babic #include <malloc.h>
38*5dda7945SStefano Babic #include <lcd.h>
39*5dda7945SStefano Babic #include "videomodes.h"
40*5dda7945SStefano Babic #include "ipu.h"
41*5dda7945SStefano Babic #include "mxcfb.h"
42*5dda7945SStefano Babic 
43*5dda7945SStefano Babic DECLARE_GLOBAL_DATA_PTR;
44*5dda7945SStefano Babic 
45*5dda7945SStefano Babic void *lcd_base;			/* Start of framebuffer memory	*/
46*5dda7945SStefano Babic void *lcd_console_address;	/* Start of console buffer	*/
47*5dda7945SStefano Babic 
48*5dda7945SStefano Babic int lcd_line_length;
49*5dda7945SStefano Babic int lcd_color_fg;
50*5dda7945SStefano Babic int lcd_color_bg;
51*5dda7945SStefano Babic 
52*5dda7945SStefano Babic short console_col;
53*5dda7945SStefano Babic short console_row;
54*5dda7945SStefano Babic 
55*5dda7945SStefano Babic vidinfo_t panel_info;
56*5dda7945SStefano Babic 
57*5dda7945SStefano Babic static int mxcfb_map_video_memory(struct fb_info *fbi);
58*5dda7945SStefano Babic static int mxcfb_unmap_video_memory(struct fb_info *fbi);
59*5dda7945SStefano Babic 
60*5dda7945SStefano Babic void lcd_initcolregs(void)
61*5dda7945SStefano Babic {
62*5dda7945SStefano Babic }
63*5dda7945SStefano Babic 
64*5dda7945SStefano Babic void lcd_setcolreg(ushort regno, ushort red, ushort green, ushort blue)
65*5dda7945SStefano Babic {
66*5dda7945SStefano Babic }
67*5dda7945SStefano Babic 
68*5dda7945SStefano Babic void lcd_disable(void)
69*5dda7945SStefano Babic {
70*5dda7945SStefano Babic }
71*5dda7945SStefano Babic 
72*5dda7945SStefano Babic void lcd_panel_disable(void)
73*5dda7945SStefano Babic {
74*5dda7945SStefano Babic }
75*5dda7945SStefano Babic 
76*5dda7945SStefano Babic void fb_videomode_to_var(struct fb_var_screeninfo *var,
77*5dda7945SStefano Babic 			 const struct fb_videomode *mode)
78*5dda7945SStefano Babic {
79*5dda7945SStefano Babic 	var->xres = mode->xres;
80*5dda7945SStefano Babic 	var->yres = mode->yres;
81*5dda7945SStefano Babic 	var->xres_virtual = mode->xres;
82*5dda7945SStefano Babic 	var->yres_virtual = mode->yres;
83*5dda7945SStefano Babic 	var->xoffset = 0;
84*5dda7945SStefano Babic 	var->yoffset = 0;
85*5dda7945SStefano Babic 	var->pixclock = mode->pixclock;
86*5dda7945SStefano Babic 	var->left_margin = mode->left_margin;
87*5dda7945SStefano Babic 	var->right_margin = mode->right_margin;
88*5dda7945SStefano Babic 	var->upper_margin = mode->upper_margin;
89*5dda7945SStefano Babic 	var->lower_margin = mode->lower_margin;
90*5dda7945SStefano Babic 	var->hsync_len = mode->hsync_len;
91*5dda7945SStefano Babic 	var->vsync_len = mode->vsync_len;
92*5dda7945SStefano Babic 	var->sync = mode->sync;
93*5dda7945SStefano Babic 	var->vmode = mode->vmode & FB_VMODE_MASK;
94*5dda7945SStefano Babic }
95*5dda7945SStefano Babic 
96*5dda7945SStefano Babic /*
97*5dda7945SStefano Babic  * Structure containing the MXC specific framebuffer information.
98*5dda7945SStefano Babic  */
99*5dda7945SStefano Babic struct mxcfb_info {
100*5dda7945SStefano Babic 	int blank;
101*5dda7945SStefano Babic 	ipu_channel_t ipu_ch;
102*5dda7945SStefano Babic 	int ipu_di;
103*5dda7945SStefano Babic 	u32 ipu_di_pix_fmt;
104*5dda7945SStefano Babic 	unsigned char overlay;
105*5dda7945SStefano Babic 	unsigned char alpha_chan_en;
106*5dda7945SStefano Babic 	dma_addr_t alpha_phy_addr0;
107*5dda7945SStefano Babic 	dma_addr_t alpha_phy_addr1;
108*5dda7945SStefano Babic 	void *alpha_virt_addr0;
109*5dda7945SStefano Babic 	void *alpha_virt_addr1;
110*5dda7945SStefano Babic 	uint32_t alpha_mem_len;
111*5dda7945SStefano Babic 	uint32_t cur_ipu_buf;
112*5dda7945SStefano Babic 	uint32_t cur_ipu_alpha_buf;
113*5dda7945SStefano Babic 
114*5dda7945SStefano Babic 	u32 pseudo_palette[16];
115*5dda7945SStefano Babic };
116*5dda7945SStefano Babic 
117*5dda7945SStefano Babic enum {
118*5dda7945SStefano Babic 	BOTH_ON,
119*5dda7945SStefano Babic 	SRC_ON,
120*5dda7945SStefano Babic 	TGT_ON,
121*5dda7945SStefano Babic 	BOTH_OFF
122*5dda7945SStefano Babic };
123*5dda7945SStefano Babic 
124*5dda7945SStefano Babic static unsigned long default_bpp = 16;
125*5dda7945SStefano Babic static unsigned char g_dp_in_use;
126*5dda7945SStefano Babic static struct fb_info *mxcfb_info[3];
127*5dda7945SStefano Babic static int ext_clk_used;
128*5dda7945SStefano Babic 
129*5dda7945SStefano Babic static uint32_t bpp_to_pixfmt(struct fb_info *fbi)
130*5dda7945SStefano Babic {
131*5dda7945SStefano Babic 	uint32_t pixfmt = 0;
132*5dda7945SStefano Babic 
133*5dda7945SStefano Babic 	debug("bpp_to_pixfmt: %d\n", fbi->var.bits_per_pixel);
134*5dda7945SStefano Babic 
135*5dda7945SStefano Babic 	if (fbi->var.nonstd)
136*5dda7945SStefano Babic 		return fbi->var.nonstd;
137*5dda7945SStefano Babic 
138*5dda7945SStefano Babic 	switch (fbi->var.bits_per_pixel) {
139*5dda7945SStefano Babic 	case 24:
140*5dda7945SStefano Babic 		pixfmt = IPU_PIX_FMT_BGR24;
141*5dda7945SStefano Babic 		break;
142*5dda7945SStefano Babic 	case 32:
143*5dda7945SStefano Babic 		pixfmt = IPU_PIX_FMT_BGR32;
144*5dda7945SStefano Babic 		break;
145*5dda7945SStefano Babic 	case 16:
146*5dda7945SStefano Babic 		pixfmt = IPU_PIX_FMT_RGB565;
147*5dda7945SStefano Babic 		break;
148*5dda7945SStefano Babic 	}
149*5dda7945SStefano Babic 	return pixfmt;
150*5dda7945SStefano Babic }
151*5dda7945SStefano Babic 
152*5dda7945SStefano Babic /*
153*5dda7945SStefano Babic  * Set fixed framebuffer parameters based on variable settings.
154*5dda7945SStefano Babic  *
155*5dda7945SStefano Babic  * @param       info     framebuffer information pointer
156*5dda7945SStefano Babic  */
157*5dda7945SStefano Babic static int mxcfb_set_fix(struct fb_info *info)
158*5dda7945SStefano Babic {
159*5dda7945SStefano Babic 	struct fb_fix_screeninfo *fix = &info->fix;
160*5dda7945SStefano Babic 	struct fb_var_screeninfo *var = &info->var;
161*5dda7945SStefano Babic 
162*5dda7945SStefano Babic 	fix->line_length = var->xres_virtual * var->bits_per_pixel / 8;
163*5dda7945SStefano Babic 
164*5dda7945SStefano Babic 	fix->type = FB_TYPE_PACKED_PIXELS;
165*5dda7945SStefano Babic 	fix->accel = FB_ACCEL_NONE;
166*5dda7945SStefano Babic 	fix->visual = FB_VISUAL_TRUECOLOR;
167*5dda7945SStefano Babic 	fix->xpanstep = 1;
168*5dda7945SStefano Babic 	fix->ypanstep = 1;
169*5dda7945SStefano Babic 
170*5dda7945SStefano Babic 	return 0;
171*5dda7945SStefano Babic }
172*5dda7945SStefano Babic 
173*5dda7945SStefano Babic static int setup_disp_channel1(struct fb_info *fbi)
174*5dda7945SStefano Babic {
175*5dda7945SStefano Babic 	ipu_channel_params_t params;
176*5dda7945SStefano Babic 	struct mxcfb_info *mxc_fbi = (struct mxcfb_info *)fbi->par;
177*5dda7945SStefano Babic 
178*5dda7945SStefano Babic 	memset(&params, 0, sizeof(params));
179*5dda7945SStefano Babic 	params.mem_dp_bg_sync.di = mxc_fbi->ipu_di;
180*5dda7945SStefano Babic 
181*5dda7945SStefano Babic 	debug("%s called\n", __func__);
182*5dda7945SStefano Babic 	/*
183*5dda7945SStefano Babic 	 * Assuming interlaced means yuv output, below setting also
184*5dda7945SStefano Babic 	 * valid for mem_dc_sync. FG should have the same vmode as BG.
185*5dda7945SStefano Babic 	 */
186*5dda7945SStefano Babic 	if (fbi->var.vmode & FB_VMODE_INTERLACED) {
187*5dda7945SStefano Babic 		params.mem_dp_bg_sync.interlaced = 1;
188*5dda7945SStefano Babic 		params.mem_dp_bg_sync.out_pixel_fmt =
189*5dda7945SStefano Babic 			IPU_PIX_FMT_YUV444;
190*5dda7945SStefano Babic 	} else {
191*5dda7945SStefano Babic 		if (mxc_fbi->ipu_di_pix_fmt) {
192*5dda7945SStefano Babic 			params.mem_dp_bg_sync.out_pixel_fmt =
193*5dda7945SStefano Babic 				mxc_fbi->ipu_di_pix_fmt;
194*5dda7945SStefano Babic 		} else {
195*5dda7945SStefano Babic 			params.mem_dp_bg_sync.out_pixel_fmt =
196*5dda7945SStefano Babic 				IPU_PIX_FMT_RGB666;
197*5dda7945SStefano Babic 		}
198*5dda7945SStefano Babic 	}
199*5dda7945SStefano Babic 	params.mem_dp_bg_sync.in_pixel_fmt = bpp_to_pixfmt(fbi);
200*5dda7945SStefano Babic 	if (mxc_fbi->alpha_chan_en)
201*5dda7945SStefano Babic 		params.mem_dp_bg_sync.alpha_chan_en = 1;
202*5dda7945SStefano Babic 
203*5dda7945SStefano Babic 	ipu_init_channel(mxc_fbi->ipu_ch, &params);
204*5dda7945SStefano Babic 
205*5dda7945SStefano Babic 	return 0;
206*5dda7945SStefano Babic }
207*5dda7945SStefano Babic 
208*5dda7945SStefano Babic static int setup_disp_channel2(struct fb_info *fbi)
209*5dda7945SStefano Babic {
210*5dda7945SStefano Babic 	int retval = 0;
211*5dda7945SStefano Babic 	struct mxcfb_info *mxc_fbi = (struct mxcfb_info *)fbi->par;
212*5dda7945SStefano Babic 
213*5dda7945SStefano Babic 	mxc_fbi->cur_ipu_buf = 1;
214*5dda7945SStefano Babic 	if (mxc_fbi->alpha_chan_en)
215*5dda7945SStefano Babic 		mxc_fbi->cur_ipu_alpha_buf = 1;
216*5dda7945SStefano Babic 
217*5dda7945SStefano Babic 	fbi->var.xoffset = fbi->var.yoffset = 0;
218*5dda7945SStefano Babic 
219*5dda7945SStefano Babic 	debug("%s: %x %d %d %d %lx %lx\n",
220*5dda7945SStefano Babic 		__func__,
221*5dda7945SStefano Babic 		mxc_fbi->ipu_ch,
222*5dda7945SStefano Babic 		fbi->var.xres,
223*5dda7945SStefano Babic 		fbi->var.yres,
224*5dda7945SStefano Babic 		fbi->fix.line_length,
225*5dda7945SStefano Babic 		fbi->fix.smem_start,
226*5dda7945SStefano Babic 		fbi->fix.smem_start +
227*5dda7945SStefano Babic 		(fbi->fix.line_length * fbi->var.yres));
228*5dda7945SStefano Babic 
229*5dda7945SStefano Babic 	retval = ipu_init_channel_buffer(mxc_fbi->ipu_ch, IPU_INPUT_BUFFER,
230*5dda7945SStefano Babic 					 bpp_to_pixfmt(fbi),
231*5dda7945SStefano Babic 					 fbi->var.xres, fbi->var.yres,
232*5dda7945SStefano Babic 					 fbi->fix.line_length,
233*5dda7945SStefano Babic 					 fbi->fix.smem_start +
234*5dda7945SStefano Babic 					 (fbi->fix.line_length * fbi->var.yres),
235*5dda7945SStefano Babic 					 fbi->fix.smem_start,
236*5dda7945SStefano Babic 					 0, 0);
237*5dda7945SStefano Babic 	if (retval)
238*5dda7945SStefano Babic 		printf("ipu_init_channel_buffer error %d\n", retval);
239*5dda7945SStefano Babic 
240*5dda7945SStefano Babic 	return retval;
241*5dda7945SStefano Babic }
242*5dda7945SStefano Babic 
243*5dda7945SStefano Babic /*
244*5dda7945SStefano Babic  * Set framebuffer parameters and change the operating mode.
245*5dda7945SStefano Babic  *
246*5dda7945SStefano Babic  * @param       info     framebuffer information pointer
247*5dda7945SStefano Babic  */
248*5dda7945SStefano Babic static int mxcfb_set_par(struct fb_info *fbi)
249*5dda7945SStefano Babic {
250*5dda7945SStefano Babic 	int retval = 0;
251*5dda7945SStefano Babic 	u32 mem_len;
252*5dda7945SStefano Babic 	ipu_di_signal_cfg_t sig_cfg;
253*5dda7945SStefano Babic 	struct mxcfb_info *mxc_fbi = (struct mxcfb_info *)fbi->par;
254*5dda7945SStefano Babic 	uint32_t out_pixel_fmt;
255*5dda7945SStefano Babic 
256*5dda7945SStefano Babic 	ipu_disable_channel(mxc_fbi->ipu_ch);
257*5dda7945SStefano Babic 	ipu_uninit_channel(mxc_fbi->ipu_ch);
258*5dda7945SStefano Babic 	mxcfb_set_fix(fbi);
259*5dda7945SStefano Babic 
260*5dda7945SStefano Babic 	mem_len = fbi->var.yres_virtual * fbi->fix.line_length;
261*5dda7945SStefano Babic 	if (!fbi->fix.smem_start || (mem_len > fbi->fix.smem_len)) {
262*5dda7945SStefano Babic 		if (fbi->fix.smem_start)
263*5dda7945SStefano Babic 			mxcfb_unmap_video_memory(fbi);
264*5dda7945SStefano Babic 
265*5dda7945SStefano Babic 		if (mxcfb_map_video_memory(fbi) < 0)
266*5dda7945SStefano Babic 			return -ENOMEM;
267*5dda7945SStefano Babic 	}
268*5dda7945SStefano Babic 
269*5dda7945SStefano Babic 	setup_disp_channel1(fbi);
270*5dda7945SStefano Babic 
271*5dda7945SStefano Babic 	memset(&sig_cfg, 0, sizeof(sig_cfg));
272*5dda7945SStefano Babic 	if (fbi->var.vmode & FB_VMODE_INTERLACED) {
273*5dda7945SStefano Babic 		sig_cfg.interlaced = 1;
274*5dda7945SStefano Babic 		out_pixel_fmt = IPU_PIX_FMT_YUV444;
275*5dda7945SStefano Babic 	} else {
276*5dda7945SStefano Babic 		if (mxc_fbi->ipu_di_pix_fmt)
277*5dda7945SStefano Babic 			out_pixel_fmt = mxc_fbi->ipu_di_pix_fmt;
278*5dda7945SStefano Babic 		else
279*5dda7945SStefano Babic 			out_pixel_fmt = IPU_PIX_FMT_RGB666;
280*5dda7945SStefano Babic 	}
281*5dda7945SStefano Babic 	if (fbi->var.vmode & FB_VMODE_ODD_FLD_FIRST) /* PAL */
282*5dda7945SStefano Babic 		sig_cfg.odd_field_first = 1;
283*5dda7945SStefano Babic 	if ((fbi->var.sync & FB_SYNC_EXT) || ext_clk_used)
284*5dda7945SStefano Babic 		sig_cfg.ext_clk = 1;
285*5dda7945SStefano Babic 	if (fbi->var.sync & FB_SYNC_HOR_HIGH_ACT)
286*5dda7945SStefano Babic 		sig_cfg.Hsync_pol = 1;
287*5dda7945SStefano Babic 	if (fbi->var.sync & FB_SYNC_VERT_HIGH_ACT)
288*5dda7945SStefano Babic 		sig_cfg.Vsync_pol = 1;
289*5dda7945SStefano Babic 	if (!(fbi->var.sync & FB_SYNC_CLK_LAT_FALL))
290*5dda7945SStefano Babic 		sig_cfg.clk_pol = 1;
291*5dda7945SStefano Babic 	if (fbi->var.sync & FB_SYNC_DATA_INVERT)
292*5dda7945SStefano Babic 		sig_cfg.data_pol = 1;
293*5dda7945SStefano Babic 	if (!(fbi->var.sync & FB_SYNC_OE_LOW_ACT))
294*5dda7945SStefano Babic 		sig_cfg.enable_pol = 1;
295*5dda7945SStefano Babic 	if (fbi->var.sync & FB_SYNC_CLK_IDLE_EN)
296*5dda7945SStefano Babic 		sig_cfg.clkidle_en = 1;
297*5dda7945SStefano Babic 
298*5dda7945SStefano Babic 	debug("pixclock = %ul Hz\n",
299*5dda7945SStefano Babic 		(u32) (PICOS2KHZ(fbi->var.pixclock) * 1000UL));
300*5dda7945SStefano Babic 
301*5dda7945SStefano Babic 	if (ipu_init_sync_panel(mxc_fbi->ipu_di,
302*5dda7945SStefano Babic 				(PICOS2KHZ(fbi->var.pixclock)) * 1000UL,
303*5dda7945SStefano Babic 				fbi->var.xres, fbi->var.yres,
304*5dda7945SStefano Babic 				out_pixel_fmt,
305*5dda7945SStefano Babic 				fbi->var.left_margin,
306*5dda7945SStefano Babic 				fbi->var.hsync_len,
307*5dda7945SStefano Babic 				fbi->var.right_margin,
308*5dda7945SStefano Babic 				fbi->var.upper_margin,
309*5dda7945SStefano Babic 				fbi->var.vsync_len,
310*5dda7945SStefano Babic 				fbi->var.lower_margin,
311*5dda7945SStefano Babic 				0, sig_cfg) != 0) {
312*5dda7945SStefano Babic 		puts("mxcfb: Error initializing panel.\n");
313*5dda7945SStefano Babic 		return -EINVAL;
314*5dda7945SStefano Babic 	}
315*5dda7945SStefano Babic 
316*5dda7945SStefano Babic 	retval = setup_disp_channel2(fbi);
317*5dda7945SStefano Babic 	if (retval)
318*5dda7945SStefano Babic 		return retval;
319*5dda7945SStefano Babic 
320*5dda7945SStefano Babic 	if (mxc_fbi->blank == FB_BLANK_UNBLANK)
321*5dda7945SStefano Babic 		ipu_enable_channel(mxc_fbi->ipu_ch);
322*5dda7945SStefano Babic 
323*5dda7945SStefano Babic 	return retval;
324*5dda7945SStefano Babic }
325*5dda7945SStefano Babic 
326*5dda7945SStefano Babic /*
327*5dda7945SStefano Babic  * Check framebuffer variable parameters and adjust to valid values.
328*5dda7945SStefano Babic  *
329*5dda7945SStefano Babic  * @param       var      framebuffer variable parameters
330*5dda7945SStefano Babic  *
331*5dda7945SStefano Babic  * @param       info     framebuffer information pointer
332*5dda7945SStefano Babic  */
333*5dda7945SStefano Babic static int mxcfb_check_var(struct fb_var_screeninfo *var, struct fb_info *info)
334*5dda7945SStefano Babic {
335*5dda7945SStefano Babic 	u32 vtotal;
336*5dda7945SStefano Babic 	u32 htotal;
337*5dda7945SStefano Babic 
338*5dda7945SStefano Babic 	if (var->xres_virtual < var->xres)
339*5dda7945SStefano Babic 		var->xres_virtual = var->xres;
340*5dda7945SStefano Babic 	if (var->yres_virtual < var->yres)
341*5dda7945SStefano Babic 		var->yres_virtual = var->yres;
342*5dda7945SStefano Babic 
343*5dda7945SStefano Babic 	if ((var->bits_per_pixel != 32) && (var->bits_per_pixel != 24) &&
344*5dda7945SStefano Babic 	    (var->bits_per_pixel != 16) && (var->bits_per_pixel != 8))
345*5dda7945SStefano Babic 		var->bits_per_pixel = default_bpp;
346*5dda7945SStefano Babic 
347*5dda7945SStefano Babic 	switch (var->bits_per_pixel) {
348*5dda7945SStefano Babic 	case 8:
349*5dda7945SStefano Babic 		var->red.length = 3;
350*5dda7945SStefano Babic 		var->red.offset = 5;
351*5dda7945SStefano Babic 		var->red.msb_right = 0;
352*5dda7945SStefano Babic 
353*5dda7945SStefano Babic 		var->green.length = 3;
354*5dda7945SStefano Babic 		var->green.offset = 2;
355*5dda7945SStefano Babic 		var->green.msb_right = 0;
356*5dda7945SStefano Babic 
357*5dda7945SStefano Babic 		var->blue.length = 2;
358*5dda7945SStefano Babic 		var->blue.offset = 0;
359*5dda7945SStefano Babic 		var->blue.msb_right = 0;
360*5dda7945SStefano Babic 
361*5dda7945SStefano Babic 		var->transp.length = 0;
362*5dda7945SStefano Babic 		var->transp.offset = 0;
363*5dda7945SStefano Babic 		var->transp.msb_right = 0;
364*5dda7945SStefano Babic 		break;
365*5dda7945SStefano Babic 	case 16:
366*5dda7945SStefano Babic 		var->red.length = 5;
367*5dda7945SStefano Babic 		var->red.offset = 11;
368*5dda7945SStefano Babic 		var->red.msb_right = 0;
369*5dda7945SStefano Babic 
370*5dda7945SStefano Babic 		var->green.length = 6;
371*5dda7945SStefano Babic 		var->green.offset = 5;
372*5dda7945SStefano Babic 		var->green.msb_right = 0;
373*5dda7945SStefano Babic 
374*5dda7945SStefano Babic 		var->blue.length = 5;
375*5dda7945SStefano Babic 		var->blue.offset = 0;
376*5dda7945SStefano Babic 		var->blue.msb_right = 0;
377*5dda7945SStefano Babic 
378*5dda7945SStefano Babic 		var->transp.length = 0;
379*5dda7945SStefano Babic 		var->transp.offset = 0;
380*5dda7945SStefano Babic 		var->transp.msb_right = 0;
381*5dda7945SStefano Babic 		break;
382*5dda7945SStefano Babic 	case 24:
383*5dda7945SStefano Babic 		var->red.length = 8;
384*5dda7945SStefano Babic 		var->red.offset = 16;
385*5dda7945SStefano Babic 		var->red.msb_right = 0;
386*5dda7945SStefano Babic 
387*5dda7945SStefano Babic 		var->green.length = 8;
388*5dda7945SStefano Babic 		var->green.offset = 8;
389*5dda7945SStefano Babic 		var->green.msb_right = 0;
390*5dda7945SStefano Babic 
391*5dda7945SStefano Babic 		var->blue.length = 8;
392*5dda7945SStefano Babic 		var->blue.offset = 0;
393*5dda7945SStefano Babic 		var->blue.msb_right = 0;
394*5dda7945SStefano Babic 
395*5dda7945SStefano Babic 		var->transp.length = 0;
396*5dda7945SStefano Babic 		var->transp.offset = 0;
397*5dda7945SStefano Babic 		var->transp.msb_right = 0;
398*5dda7945SStefano Babic 		break;
399*5dda7945SStefano Babic 	case 32:
400*5dda7945SStefano Babic 		var->red.length = 8;
401*5dda7945SStefano Babic 		var->red.offset = 16;
402*5dda7945SStefano Babic 		var->red.msb_right = 0;
403*5dda7945SStefano Babic 
404*5dda7945SStefano Babic 		var->green.length = 8;
405*5dda7945SStefano Babic 		var->green.offset = 8;
406*5dda7945SStefano Babic 		var->green.msb_right = 0;
407*5dda7945SStefano Babic 
408*5dda7945SStefano Babic 		var->blue.length = 8;
409*5dda7945SStefano Babic 		var->blue.offset = 0;
410*5dda7945SStefano Babic 		var->blue.msb_right = 0;
411*5dda7945SStefano Babic 
412*5dda7945SStefano Babic 		var->transp.length = 8;
413*5dda7945SStefano Babic 		var->transp.offset = 24;
414*5dda7945SStefano Babic 		var->transp.msb_right = 0;
415*5dda7945SStefano Babic 		break;
416*5dda7945SStefano Babic 	}
417*5dda7945SStefano Babic 
418*5dda7945SStefano Babic 	if (var->pixclock < 1000) {
419*5dda7945SStefano Babic 		htotal = var->xres + var->right_margin + var->hsync_len +
420*5dda7945SStefano Babic 		    var->left_margin;
421*5dda7945SStefano Babic 		vtotal = var->yres + var->lower_margin + var->vsync_len +
422*5dda7945SStefano Babic 		    var->upper_margin;
423*5dda7945SStefano Babic 		var->pixclock = (vtotal * htotal * 6UL) / 100UL;
424*5dda7945SStefano Babic 		var->pixclock = KHZ2PICOS(var->pixclock);
425*5dda7945SStefano Babic 		printf("pixclock set for 60Hz refresh = %u ps\n",
426*5dda7945SStefano Babic 			var->pixclock);
427*5dda7945SStefano Babic 	}
428*5dda7945SStefano Babic 
429*5dda7945SStefano Babic 	var->height = -1;
430*5dda7945SStefano Babic 	var->width = -1;
431*5dda7945SStefano Babic 	var->grayscale = 0;
432*5dda7945SStefano Babic 
433*5dda7945SStefano Babic 	return 0;
434*5dda7945SStefano Babic }
435*5dda7945SStefano Babic 
436*5dda7945SStefano Babic static int mxcfb_map_video_memory(struct fb_info *fbi)
437*5dda7945SStefano Babic {
438*5dda7945SStefano Babic 	if (fbi->fix.smem_len < fbi->var.yres_virtual * fbi->fix.line_length) {
439*5dda7945SStefano Babic 		fbi->fix.smem_len = fbi->var.yres_virtual *
440*5dda7945SStefano Babic 				    fbi->fix.line_length;
441*5dda7945SStefano Babic 	}
442*5dda7945SStefano Babic 
443*5dda7945SStefano Babic 	fbi->screen_base = (char *)lcd_base;
444*5dda7945SStefano Babic 	fbi->fix.smem_start = (unsigned long)lcd_base;
445*5dda7945SStefano Babic 	if (fbi->screen_base == 0) {
446*5dda7945SStefano Babic 		puts("Unable to allocate framebuffer memory\n");
447*5dda7945SStefano Babic 		fbi->fix.smem_len = 0;
448*5dda7945SStefano Babic 		fbi->fix.smem_start = 0;
449*5dda7945SStefano Babic 		return -EBUSY;
450*5dda7945SStefano Babic 	}
451*5dda7945SStefano Babic 
452*5dda7945SStefano Babic 	debug("allocated fb @ paddr=0x%08X, size=%d.\n",
453*5dda7945SStefano Babic 		(uint32_t) fbi->fix.smem_start, fbi->fix.smem_len);
454*5dda7945SStefano Babic 
455*5dda7945SStefano Babic 	fbi->screen_size = fbi->fix.smem_len;
456*5dda7945SStefano Babic 
457*5dda7945SStefano Babic 	/* Clear the screen */
458*5dda7945SStefano Babic 	memset((char *)fbi->screen_base, 0, fbi->fix.smem_len);
459*5dda7945SStefano Babic 
460*5dda7945SStefano Babic 	return 0;
461*5dda7945SStefano Babic }
462*5dda7945SStefano Babic 
463*5dda7945SStefano Babic static int mxcfb_unmap_video_memory(struct fb_info *fbi)
464*5dda7945SStefano Babic {
465*5dda7945SStefano Babic 	fbi->screen_base = 0;
466*5dda7945SStefano Babic 	fbi->fix.smem_start = 0;
467*5dda7945SStefano Babic 	fbi->fix.smem_len = 0;
468*5dda7945SStefano Babic 	return 0;
469*5dda7945SStefano Babic }
470*5dda7945SStefano Babic 
471*5dda7945SStefano Babic /*
472*5dda7945SStefano Babic  * Initializes the framebuffer information pointer. After allocating
473*5dda7945SStefano Babic  * sufficient memory for the framebuffer structure, the fields are
474*5dda7945SStefano Babic  * filled with custom information passed in from the configurable
475*5dda7945SStefano Babic  * structures.  This includes information such as bits per pixel,
476*5dda7945SStefano Babic  * color maps, screen width/height and RGBA offsets.
477*5dda7945SStefano Babic  *
478*5dda7945SStefano Babic  * @return      Framebuffer structure initialized with our information
479*5dda7945SStefano Babic  */
480*5dda7945SStefano Babic static struct fb_info *mxcfb_init_fbinfo(void)
481*5dda7945SStefano Babic {
482*5dda7945SStefano Babic #define BYTES_PER_LONG 4
483*5dda7945SStefano Babic #define PADDING (BYTES_PER_LONG - (sizeof(struct fb_info) % BYTES_PER_LONG))
484*5dda7945SStefano Babic 	struct fb_info *fbi;
485*5dda7945SStefano Babic 	struct mxcfb_info *mxcfbi;
486*5dda7945SStefano Babic 	char *p;
487*5dda7945SStefano Babic 	int size = sizeof(struct mxcfb_info) + PADDING +
488*5dda7945SStefano Babic 		sizeof(struct fb_info);
489*5dda7945SStefano Babic 
490*5dda7945SStefano Babic 	debug("%s: %d %d %d %d\n",
491*5dda7945SStefano Babic 		__func__,
492*5dda7945SStefano Babic 		PADDING,
493*5dda7945SStefano Babic 		size,
494*5dda7945SStefano Babic 		sizeof(struct mxcfb_info),
495*5dda7945SStefano Babic 		sizeof(struct fb_info));
496*5dda7945SStefano Babic 	/*
497*5dda7945SStefano Babic 	 * Allocate sufficient memory for the fb structure
498*5dda7945SStefano Babic 	 */
499*5dda7945SStefano Babic 
500*5dda7945SStefano Babic 	p = malloc(size);
501*5dda7945SStefano Babic 	if (!p)
502*5dda7945SStefano Babic 		return NULL;
503*5dda7945SStefano Babic 
504*5dda7945SStefano Babic 	memset(p, 0, size);
505*5dda7945SStefano Babic 
506*5dda7945SStefano Babic 	fbi = (struct fb_info *)p;
507*5dda7945SStefano Babic 	fbi->par = p + sizeof(struct fb_info) + PADDING;
508*5dda7945SStefano Babic 
509*5dda7945SStefano Babic 	mxcfbi = (struct mxcfb_info *)fbi->par;
510*5dda7945SStefano Babic 	debug("Framebuffer structures at: fbi=0x%x mxcfbi=0x%x\n",
511*5dda7945SStefano Babic 		(unsigned int)fbi, (unsigned int)mxcfbi);
512*5dda7945SStefano Babic 
513*5dda7945SStefano Babic 	fbi->var.activate = FB_ACTIVATE_NOW;
514*5dda7945SStefano Babic 
515*5dda7945SStefano Babic 	fbi->flags = FBINFO_FLAG_DEFAULT;
516*5dda7945SStefano Babic 	fbi->pseudo_palette = mxcfbi->pseudo_palette;
517*5dda7945SStefano Babic 
518*5dda7945SStefano Babic 	return fbi;
519*5dda7945SStefano Babic }
520*5dda7945SStefano Babic 
521*5dda7945SStefano Babic /*
522*5dda7945SStefano Babic  * Probe routine for the framebuffer driver. It is called during the
523*5dda7945SStefano Babic  * driver binding process.      The following functions are performed in
524*5dda7945SStefano Babic  * this routine: Framebuffer initialization, Memory allocation and
525*5dda7945SStefano Babic  * mapping, Framebuffer registration, IPU initialization.
526*5dda7945SStefano Babic  *
527*5dda7945SStefano Babic  * @return      Appropriate error code to the kernel common code
528*5dda7945SStefano Babic  */
529*5dda7945SStefano Babic static int mxcfb_probe(u32 interface_pix_fmt, struct fb_videomode *mode)
530*5dda7945SStefano Babic {
531*5dda7945SStefano Babic 	struct fb_info *fbi;
532*5dda7945SStefano Babic 	struct mxcfb_info *mxcfbi;
533*5dda7945SStefano Babic 	int ret = 0;
534*5dda7945SStefano Babic 
535*5dda7945SStefano Babic 	/*
536*5dda7945SStefano Babic 	 * Initialize FB structures
537*5dda7945SStefano Babic 	 */
538*5dda7945SStefano Babic 	fbi = mxcfb_init_fbinfo();
539*5dda7945SStefano Babic 	if (!fbi) {
540*5dda7945SStefano Babic 		ret = -ENOMEM;
541*5dda7945SStefano Babic 		goto err0;
542*5dda7945SStefano Babic 	}
543*5dda7945SStefano Babic 	mxcfbi = (struct mxcfb_info *)fbi->par;
544*5dda7945SStefano Babic 
545*5dda7945SStefano Babic 	if (!g_dp_in_use) {
546*5dda7945SStefano Babic 		mxcfbi->ipu_ch = MEM_BG_SYNC;
547*5dda7945SStefano Babic 		mxcfbi->blank = FB_BLANK_UNBLANK;
548*5dda7945SStefano Babic 	} else {
549*5dda7945SStefano Babic 		mxcfbi->ipu_ch = MEM_DC_SYNC;
550*5dda7945SStefano Babic 		mxcfbi->blank = FB_BLANK_POWERDOWN;
551*5dda7945SStefano Babic 	}
552*5dda7945SStefano Babic 
553*5dda7945SStefano Babic 	mxcfbi->ipu_di = 0;
554*5dda7945SStefano Babic 
555*5dda7945SStefano Babic 	ipu_disp_set_global_alpha(mxcfbi->ipu_ch, 1, 0x80);
556*5dda7945SStefano Babic 	ipu_disp_set_color_key(mxcfbi->ipu_ch, 0, 0);
557*5dda7945SStefano Babic 	strcpy(fbi->fix.id, "DISP3 BG");
558*5dda7945SStefano Babic 
559*5dda7945SStefano Babic 	g_dp_in_use = 1;
560*5dda7945SStefano Babic 
561*5dda7945SStefano Babic 	mxcfb_info[mxcfbi->ipu_di] = fbi;
562*5dda7945SStefano Babic 
563*5dda7945SStefano Babic 	/* Need dummy values until real panel is configured */
564*5dda7945SStefano Babic 	fbi->var.xres = 640;
565*5dda7945SStefano Babic 	fbi->var.yres = 480;
566*5dda7945SStefano Babic 	fbi->var.bits_per_pixel = 16;
567*5dda7945SStefano Babic 
568*5dda7945SStefano Babic 	mxcfbi->ipu_di_pix_fmt = interface_pix_fmt;
569*5dda7945SStefano Babic 	fb_videomode_to_var(&fbi->var, mode);
570*5dda7945SStefano Babic 
571*5dda7945SStefano Babic 	mxcfb_check_var(&fbi->var, fbi);
572*5dda7945SStefano Babic 
573*5dda7945SStefano Babic 	/* Default Y virtual size is 2x panel size */
574*5dda7945SStefano Babic 	fbi->var.yres_virtual = fbi->var.yres * 2;
575*5dda7945SStefano Babic 
576*5dda7945SStefano Babic 	mxcfb_set_fix(fbi);
577*5dda7945SStefano Babic 
578*5dda7945SStefano Babic 	/* alocate fb first */
579*5dda7945SStefano Babic 	if (mxcfb_map_video_memory(fbi) < 0)
580*5dda7945SStefano Babic 		return -ENOMEM;
581*5dda7945SStefano Babic 
582*5dda7945SStefano Babic 	mxcfb_set_par(fbi);
583*5dda7945SStefano Babic 
584*5dda7945SStefano Babic 	/* Setting panel_info for lcd */
585*5dda7945SStefano Babic 	panel_info.cmap = NULL;
586*5dda7945SStefano Babic 	panel_info.vl_col = fbi->var.xres;
587*5dda7945SStefano Babic 	panel_info.vl_row = fbi->var.yres;
588*5dda7945SStefano Babic 	panel_info.vl_bpix = LCD_BPP;
589*5dda7945SStefano Babic 
590*5dda7945SStefano Babic 	lcd_line_length = (panel_info.vl_col * NBITS(panel_info.vl_bpix)) / 8;
591*5dda7945SStefano Babic 
592*5dda7945SStefano Babic 	debug("MXC IPUV3 configured\n"
593*5dda7945SStefano Babic 		"XRES = %d YRES = %d BitsXpixel = %d\n",
594*5dda7945SStefano Babic 		panel_info.vl_col,
595*5dda7945SStefano Babic 		panel_info.vl_row,
596*5dda7945SStefano Babic 		panel_info.vl_bpix);
597*5dda7945SStefano Babic 
598*5dda7945SStefano Babic 	ipu_dump_registers();
599*5dda7945SStefano Babic 
600*5dda7945SStefano Babic 	return 0;
601*5dda7945SStefano Babic 
602*5dda7945SStefano Babic err0:
603*5dda7945SStefano Babic 	return ret;
604*5dda7945SStefano Babic }
605*5dda7945SStefano Babic 
606*5dda7945SStefano Babic int overwrite_console(void)
607*5dda7945SStefano Babic {
608*5dda7945SStefano Babic 	/* Keep stdout / stderr on serial, our LCD is for splashscreen only */
609*5dda7945SStefano Babic 	return 1;
610*5dda7945SStefano Babic }
611*5dda7945SStefano Babic 
612*5dda7945SStefano Babic void lcd_ctrl_init(void *lcdbase)
613*5dda7945SStefano Babic {
614*5dda7945SStefano Babic 	u32 mem_len = panel_info.vl_col *
615*5dda7945SStefano Babic 		panel_info.vl_row *
616*5dda7945SStefano Babic 		NBITS(panel_info.vl_bpix) / 8;
617*5dda7945SStefano Babic 
618*5dda7945SStefano Babic 	/*
619*5dda7945SStefano Babic 	 * We rely on lcdbase being a physical address, i.e., either MMU off,
620*5dda7945SStefano Babic 	 * or 1-to-1 mapping. Might want to add some virt2phys here.
621*5dda7945SStefano Babic 	 */
622*5dda7945SStefano Babic 	if (!lcdbase)
623*5dda7945SStefano Babic 		return;
624*5dda7945SStefano Babic 
625*5dda7945SStefano Babic 	memset(lcdbase, 0, mem_len);
626*5dda7945SStefano Babic }
627*5dda7945SStefano Babic 
628*5dda7945SStefano Babic int mx51_fb_init(struct fb_videomode *mode)
629*5dda7945SStefano Babic {
630*5dda7945SStefano Babic 	int ret;
631*5dda7945SStefano Babic 
632*5dda7945SStefano Babic 	ret = ipu_probe();
633*5dda7945SStefano Babic 	if (ret)
634*5dda7945SStefano Babic 		puts("Error initializing IPU\n");
635*5dda7945SStefano Babic 
636*5dda7945SStefano Babic 	lcd_base += 56;
637*5dda7945SStefano Babic 
638*5dda7945SStefano Babic 	debug("Framebuffer at 0x%x\n", (unsigned int)lcd_base);
639*5dda7945SStefano Babic 	ret = mxcfb_probe(IPU_PIX_FMT_RGB666, mode);
640*5dda7945SStefano Babic 
641*5dda7945SStefano Babic 	return ret;
642*5dda7945SStefano Babic }
643