xref: /openbmc/u-boot/drivers/video/fsl_diu_fb.c (revision 44c6e6591cb451ae606f8bde71dd5fb7b4002544)
1 /*
2  * Copyright 2007, 2010 Freescale Semiconductor, Inc.
3  * York Sun <yorksun@freescale.com>
4  *
5  * FSL DIU Framebuffer driver
6  *
7  * See file CREDITS for list of people who contributed to this
8  * project.
9  *
10  * This program is free software; you can redistribute it and/or
11  * modify it under the terms of the GNU General Public License as
12  * published by the Free Software Foundation; either version 2 of
13  * the License, or (at your option) any later version.
14  *
15  * This program is distributed in the hope that it will be useful,
16  * but WITHOUT ANY WARRANTY; without even the implied warranty of
17  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
18  * GNU General Public License for more details.
19  *
20  * You should have received a copy of the GNU General Public License
21  * along with this program; if not, write to the Free Software
22  * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
23  * MA 02111-1307 USA
24  */
25 
26 #include <common.h>
27 #include <i2c.h>
28 #include <malloc.h>
29 #include <asm/io.h>
30 
31 #include <fsl_diu_fb.h>
32 
33 struct fb_videomode {
34 	const char *name;	/* optional */
35 	unsigned int refresh;		/* optional */
36 	unsigned int xres;
37 	unsigned int yres;
38 	unsigned int pixclock;
39 	unsigned int left_margin;
40 	unsigned int right_margin;
41 	unsigned int upper_margin;
42 	unsigned int lower_margin;
43 	unsigned int hsync_len;
44 	unsigned int vsync_len;
45 	unsigned int sync;
46 	unsigned int vmode;
47 	unsigned int flag;
48 };
49 
50 #define FB_SYNC_VERT_HIGH_ACT	2	/* vertical sync high active	*/
51 #define FB_SYNC_COMP_HIGH_ACT	8	/* composite sync high active   */
52 #define FB_VMODE_NONINTERLACED  0	/* non interlaced */
53 
54 /* This setting is used for the ifm pdm360ng with PRIMEVIEW PM070WL3 */
55 static struct fb_videomode fsl_diu_mode_800 = {
56 	.refresh	= 60,
57 	.xres		= 800,
58 	.yres		= 480,
59 	.pixclock	= 31250,
60 	.left_margin	= 86,
61 	.right_margin	= 42,
62 	.upper_margin	= 33,
63 	.lower_margin	= 10,
64 	.hsync_len	= 128,
65 	.vsync_len	= 2,
66 	.sync		= 0,
67 	.vmode		= FB_VMODE_NONINTERLACED
68 };
69 
70 /*
71  * These parameters give default parameters
72  * for video output 1024x768,
73  * FIXME - change timing to proper amounts
74  * hsync 31.5kHz, vsync 60Hz
75  */
76 static struct fb_videomode fsl_diu_mode_1024 = {
77 	.refresh	= 60,
78 	.xres		= 1024,
79 	.yres		= 768,
80 	.pixclock	= 15385,
81 	.left_margin	= 160,
82 	.right_margin	= 24,
83 	.upper_margin	= 29,
84 	.lower_margin	= 3,
85 	.hsync_len	= 136,
86 	.vsync_len	= 6,
87 	.sync		= FB_SYNC_COMP_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT,
88 	.vmode		= FB_VMODE_NONINTERLACED
89 };
90 
91 static struct fb_videomode fsl_diu_mode_1280 = {
92 	.name		= "1280x1024-60",
93 	.refresh	= 60,
94 	.xres		= 1280,
95 	.yres		= 1024,
96 	.pixclock	= 9375,
97 	.left_margin	= 38,
98 	.right_margin	= 128,
99 	.upper_margin	= 2,
100 	.lower_margin	= 7,
101 	.hsync_len	= 216,
102 	.vsync_len	= 37,
103 	.sync		= FB_SYNC_COMP_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT,
104 	.vmode		= FB_VMODE_NONINTERLACED
105 };
106 
107 /*
108  * These are the fields of area descriptor(in DDR memory) for every plane
109  */
110 struct diu_ad {
111 	/* Word 0(32-bit) in DDR memory */
112 	unsigned int pix_fmt; /* hard coding pixel format */
113 	/* Word 1(32-bit) in DDR memory */
114 	unsigned int addr;
115 	/* Word 2(32-bit) in DDR memory */
116 	unsigned int src_size_g_alpha;
117 	/* Word 3(32-bit) in DDR memory */
118 	unsigned int aoi_size;
119 	/* Word 4(32-bit) in DDR memory */
120 	unsigned int offset_xyi;
121 	/* Word 5(32-bit) in DDR memory */
122 	unsigned int offset_xyd;
123 	/* Word 6(32-bit) in DDR memory */
124 	unsigned int ckmax_r:8;
125 	unsigned int ckmax_g:8;
126 	unsigned int ckmax_b:8;
127 	unsigned int res9:8;
128 	/* Word 7(32-bit) in DDR memory */
129 	unsigned int ckmin_r:8;
130 	unsigned int ckmin_g:8;
131 	unsigned int ckmin_b:8;
132 	unsigned int res10:8;
133 	/* Word 8(32-bit) in DDR memory */
134 	unsigned int next_ad;
135 	/* Word 9(32-bit) in DDR memory, just for 64-bit aligned */
136 	unsigned int res1;
137 	unsigned int res2;
138 	unsigned int res3;
139 }__attribute__ ((packed));
140 
141 /*
142  * DIU register map
143  */
144 struct diu {
145 	unsigned int desc[3];
146 	unsigned int gamma;
147 	unsigned int pallete;
148 	unsigned int cursor;
149 	unsigned int curs_pos;
150 	unsigned int diu_mode;
151 	unsigned int bgnd;
152 	unsigned int bgnd_wb;
153 	unsigned int disp_size;
154 	unsigned int wb_size;
155 	unsigned int wb_mem_addr;
156 	unsigned int hsyn_para;
157 	unsigned int vsyn_para;
158 	unsigned int syn_pol;
159 	unsigned int thresholds;
160 	unsigned int int_status;
161 	unsigned int int_mask;
162 	unsigned int colorbar[8];
163 	unsigned int filling;
164 	unsigned int plut;
165 } __attribute__ ((packed));
166 
167 struct diu_hw {
168 	struct diu *diu_reg;
169 	volatile unsigned int mode;		/* DIU operation mode */
170 };
171 
172 struct diu_addr {
173 	unsigned char  *  paddr;	/* Virtual address */
174 	unsigned int	   offset;
175 };
176 
177 /*
178  * Modes of operation of DIU
179  */
180 #define MFB_MODE0	0	/* DIU off */
181 #define MFB_MODE1	1	/* All three planes output to display */
182 #define MFB_MODE2	2	/* Plane 1 to display,
183 				 * planes 2+3 written back to memory */
184 #define MFB_MODE3	3	/* All three planes written back to memory */
185 #define MFB_MODE4	4	/* Color bar generation */
186 
187 #define MAX_CURS		32
188 
189 static struct fb_info fsl_fb_info;
190 static struct diu_addr gamma, cursor;
191 static struct diu_ad fsl_diu_fb_ad __attribute__ ((aligned(32)));
192 static struct diu_ad dummy_ad __attribute__ ((aligned(32)));
193 static unsigned char *dummy_fb;
194 static struct diu_hw dr = {
195 	.mode = MFB_MODE1,
196 };
197 
198 int fb_enabled = 0;
199 int fb_initialized = 0;
200 const int default_xres = 1280;
201 const int default_pixel_format = 0x88882317;
202 
203 static int map_video_memory(struct fb_info *info, unsigned long bytes_align);
204 static void enable_lcdc(void);
205 static void disable_lcdc(void);
206 static int fsl_diu_enable_panel(struct fb_info *info);
207 static int fsl_diu_disable_panel(struct fb_info *info);
208 static int allocate_buf(struct diu_addr *buf, u32 size, u32 bytes_align);
209 void diu_set_pixel_clock(unsigned int pixclock);
210 
211 int fsl_diu_init(int xres, unsigned int pixel_format, int gamma_fix)
212 {
213 	struct fb_videomode *fsl_diu_mode_db;
214 	struct diu_ad *ad = &fsl_diu_fb_ad;
215 	struct diu *hw;
216 	struct fb_info *info = &fsl_fb_info;
217 	struct fb_var_screeninfo *var = &info->var;
218 	unsigned char *gamma_table_base;
219 	unsigned int i, j;
220 
221 	debug("Enter fsl_diu_init\n");
222 	dr.diu_reg = (struct diu *) (CONFIG_SYS_DIU_ADDR);
223 	hw = (struct diu *) dr.diu_reg;
224 
225 	disable_lcdc();
226 
227 	switch (xres) {
228 	case 800:
229 		fsl_diu_mode_db = &fsl_diu_mode_800;
230 		break;
231 	case 1280:
232 		fsl_diu_mode_db = &fsl_diu_mode_1280;
233 		break;
234 	default:
235 		fsl_diu_mode_db = &fsl_diu_mode_1024;
236 	}
237 
238 	if (0 == fb_initialized) {
239 		allocate_buf(&gamma, 768, 32);
240 		debug("gamma is allocated @ 0x%x\n",
241 			(unsigned int)gamma.paddr);
242 		allocate_buf(&cursor, MAX_CURS * MAX_CURS * 2, 32);
243 		debug("curosr is allocated @ 0x%x\n",
244 			(unsigned int)cursor.paddr);
245 
246 		/* create a dummy fb and dummy ad */
247 		dummy_fb = malloc(64);
248 		if (NULL == dummy_fb) {
249 			printf("Cannot allocate dummy fb\n");
250 			return -1;
251 		}
252 		dummy_ad.addr = cpu_to_le32((unsigned int)dummy_fb);
253 		dummy_ad.pix_fmt = 0x88882317;
254 		dummy_ad.src_size_g_alpha = 0x04400000;	/* alpha = 0 */
255 		dummy_ad.aoi_size = 0x02000400;
256 		dummy_ad.offset_xyi = 0;
257 		dummy_ad.offset_xyd = 0;
258 		dummy_ad.next_ad = 0;
259 		/* Memory allocation for framebuffer */
260 		if (map_video_memory(info, 32)) {
261 			printf("Unable to allocate fb memory 1\n");
262 			return -1;
263 		}
264 	}
265 
266 	memset(info->screen_base, 0, info->smem_len);
267 
268 	out_be32(&dr.diu_reg->desc[0], (int)&dummy_ad);
269 	out_be32(&dr.diu_reg->desc[1], (int)&dummy_ad);
270 	out_be32(&dr.diu_reg->desc[2], (int)&dummy_ad);
271 	debug("dummy dr.diu_reg->desc[0] = 0x%x\n", dr.diu_reg->desc[0]);
272 	debug("dummy desc[0] = 0x%x\n", hw->desc[0]);
273 
274 	/* read mode info */
275 	var->xres = fsl_diu_mode_db->xres;
276 	var->yres = fsl_diu_mode_db->yres;
277 	var->bits_per_pixel = 32;
278 	var->pixclock = fsl_diu_mode_db->pixclock;
279 	var->left_margin = fsl_diu_mode_db->left_margin;
280 	var->right_margin = fsl_diu_mode_db->right_margin;
281 	var->upper_margin = fsl_diu_mode_db->upper_margin;
282 	var->lower_margin = fsl_diu_mode_db->lower_margin;
283 	var->hsync_len = fsl_diu_mode_db->hsync_len;
284 	var->vsync_len = fsl_diu_mode_db->vsync_len;
285 	var->sync = fsl_diu_mode_db->sync;
286 	var->vmode = fsl_diu_mode_db->vmode;
287 	info->line_length = var->xres * var->bits_per_pixel / 8;
288 
289 	ad->pix_fmt = pixel_format;
290 	ad->addr    = cpu_to_le32((unsigned int)info->screen_base);
291 	ad->src_size_g_alpha
292 			= cpu_to_le32((var->yres << 12) | var->xres);
293 	/* fix me. AOI should not be greater than display size */
294 	ad->aoi_size	= cpu_to_le32(( var->yres << 16) |  var->xres);
295 	ad->offset_xyi = 0;
296 	ad->offset_xyd = 0;
297 
298 	/* Disable chroma keying function */
299 	ad->ckmax_r = 0;
300 	ad->ckmax_g = 0;
301 	ad->ckmax_b = 0;
302 
303 	ad->ckmin_r = 255;
304 	ad->ckmin_g = 255;
305 	ad->ckmin_b = 255;
306 
307 	gamma_table_base = gamma.paddr;
308 	debug("gamma_table_base is allocated @ 0x%x\n",
309 		(unsigned int)gamma_table_base);
310 
311 	/* Prep for DIU init  - gamma table */
312 
313 	for (i = 0; i <= 2; i++)
314 		for (j = 0; j <= 255; j++)
315 			*gamma_table_base++ = j;
316 
317 	if (gamma_fix == 1) {	/* fix the gamma */
318 		debug("Fix gamma table\n");
319 		gamma_table_base = gamma.paddr;
320 		for (i = 0; i < 256*3; i++) {
321 			gamma_table_base[i] = (gamma_table_base[i] << 2)
322 				| ((gamma_table_base[i] >> 6) & 0x03);
323 		}
324 	}
325 
326 	debug("update-lcdc: HW - %p\n Disabling DIU\n", hw);
327 
328 	/* Program DIU registers */
329 
330 	out_be32(&hw->gamma, (int)gamma.paddr);
331 	out_be32(&hw->cursor, (int)cursor.paddr);
332 	out_be32(&hw->bgnd, 0x007F7F7F);
333 	out_be32(&hw->bgnd_wb, 0);				/* BGND_WB */
334 	out_be32(&hw->disp_size, var->yres << 16 | var->xres);	/* DISP SIZE */
335 	out_be32(&hw->wb_size, 0);				/* WB SIZE */
336 	out_be32(&hw->wb_mem_addr, 0);				/* WB MEM ADDR */
337 	out_be32(&hw->hsyn_para, var->left_margin << 22 |	/* BP_H */
338 			var->hsync_len << 11   |	/* PW_H */
339 			var->right_margin);		/* FP_H */
340 
341 	out_be32(&hw->vsyn_para, var->upper_margin << 22 |	/* BP_V */
342 			var->vsync_len << 11    |	/* PW_V  */
343 			var->lower_margin);		/* FP_V  */
344 
345 	out_be32(&hw->syn_pol, 0);			/* SYNC SIGNALS POLARITY */
346 	out_be32(&hw->thresholds, 0x00037800);		/* The Thresholds */
347 	out_be32(&hw->int_status, 0);			/* INTERRUPT STATUS */
348 	out_be32(&hw->int_mask, 0);			/* INT MASK */
349 	out_be32(&hw->plut, 0x01F5F666);
350 	/* Pixel Clock configuration */
351 	debug("DIU pixclock in ps - %d\n", var->pixclock);
352 	diu_set_pixel_clock(var->pixclock);
353 
354 	fb_initialized = 1;
355 
356 	/* Enable the DIU */
357 	fsl_diu_enable_panel(info);
358 	enable_lcdc();
359 
360 	return 0;
361 }
362 
363 char *fsl_fb_open(struct fb_info **info)
364 {
365 	*info = &fsl_fb_info;
366 	return fsl_fb_info.screen_base;
367 }
368 
369 void fsl_diu_close(void)
370 {
371 	struct fb_info *info = &fsl_fb_info;
372 	fsl_diu_disable_panel(info);
373 }
374 
375 static int fsl_diu_enable_panel(struct fb_info *info)
376 {
377 	struct diu *hw = dr.diu_reg;
378 	struct diu_ad *ad = &fsl_diu_fb_ad;
379 
380 	debug("Entered: enable_panel\n");
381 	if (in_be32(&hw->desc[0]) != (unsigned)ad)
382 		out_be32(&hw->desc[0], (unsigned)ad);
383 	debug("desc[0] = 0x%x\n", hw->desc[0]);
384 	return 0;
385 }
386 
387 static int fsl_diu_disable_panel(struct fb_info *info)
388 {
389 	struct diu *hw = dr.diu_reg;
390 
391 	debug("Entered: disable_panel\n");
392 	if (in_be32(&hw->desc[0]) != (unsigned)&dummy_ad)
393 		out_be32(&hw->desc[0], (unsigned)&dummy_ad);
394 	return 0;
395 }
396 
397 static int map_video_memory(struct fb_info *info, unsigned long bytes_align)
398 {
399 	unsigned long offset;
400 	unsigned long mask;
401 
402 	debug("Entered: map_video_memory\n");
403 	/* allocate maximum 1280*1024 with 32bpp */
404 	info->smem_len = 1280 * 4 *1024 + bytes_align;
405 	debug("MAP_VIDEO_MEMORY: smem_len = %d\n", info->smem_len);
406 	info->screen_base = malloc(info->smem_len);
407 	if (info->screen_base == NULL) {
408 		printf("Unable to allocate fb memory\n");
409 		return -1;
410 	}
411 	info->smem_start = (unsigned int) info->screen_base;
412 	mask = bytes_align - 1;
413 	offset = (unsigned long)info->screen_base & mask;
414 	if (offset) {
415 		info->screen_base += (bytes_align - offset);
416 		info->smem_len = info->smem_len - (bytes_align - offset);
417 	} else
418 		info->smem_len = info->smem_len - bytes_align;
419 
420 	info->screen_size = info->smem_len;
421 
422 	debug("Allocated fb @ 0x%08lx, size=%d.\n",
423 		info->smem_start, info->smem_len);
424 
425 	return 0;
426 }
427 
428 static void enable_lcdc(void)
429 {
430 	struct diu *hw = dr.diu_reg;
431 
432 	debug("Entered: enable_lcdc, fb_enabled = %d\n", fb_enabled);
433 	if (!fb_enabled) {
434 		out_be32(&hw->diu_mode, dr.mode);
435 		fb_enabled++;
436 	}
437 	debug("diu_mode = %d\n", hw->diu_mode);
438 }
439 
440 static void disable_lcdc(void)
441 {
442 	struct diu *hw = dr.diu_reg;
443 
444 	debug("Entered: disable_lcdc, fb_enabled = %d\n", fb_enabled);
445 	if (fb_enabled) {
446 		out_be32(&hw->diu_mode, 0);
447 		fb_enabled = 0;
448 	}
449 }
450 
451 /*
452  * Align to 64-bit(8-byte), 32-byte, etc.
453  */
454 static int allocate_buf(struct diu_addr *buf, u32 size, u32 bytes_align)
455 {
456 	u32 offset, ssize;
457 	u32 mask;
458 
459 	debug("Entered: allocate_buf\n");
460 	ssize = size + bytes_align;
461 	buf->paddr = malloc(ssize);
462 	if (!buf->paddr)
463 		return -1;
464 
465 	memset(buf->paddr, 0, ssize);
466 	mask = bytes_align - 1;
467 	offset = (u32)buf->paddr & mask;
468 	if (offset) {
469 		buf->offset = bytes_align - offset;
470 		buf->paddr = (unsigned char *) ((u32)buf->paddr + offset);
471 	} else
472 		buf->offset = 0;
473 	return 0;
474 }
475 
476 #if defined(CONFIG_VIDEO) || defined(CONFIG_CFB_CONSOLE)
477 #include <stdio_dev.h>
478 #include <video_fb.h>
479 /*
480  * The Graphic Device
481  */
482 static GraphicDevice ctfb;
483 
484 void *video_hw_init(void)
485 {
486 	struct fb_info *info;
487 
488 	if (platform_diu_init(&ctfb.winSizeX, &ctfb.winSizeY) < 0)
489 		return NULL;
490 
491 	/* fill in Graphic device struct */
492 	sprintf(ctfb.modeIdent, "%ix%ix%i %ikHz %iHz",
493 		ctfb.winSizeX, ctfb.winSizeY, 32, 64, 60);
494 
495 	ctfb.frameAdrs = (unsigned int)fsl_fb_open(&info);
496 	ctfb.plnSizeX = ctfb.winSizeX;
497 	ctfb.plnSizeY = ctfb.winSizeY;
498 
499 	ctfb.gdfBytesPP = 4;
500 	ctfb.gdfIndex = GDF_32BIT_X888RGB;
501 
502 	ctfb.isaBase = 0;
503 	ctfb.pciBase = 0;
504 	ctfb.memSize = info->screen_size;
505 
506 	/* Cursor Start Address */
507 	ctfb.dprBase = 0;
508 	ctfb.vprBase = 0;
509 	ctfb.cprBase = 0;
510 
511 	return &ctfb;
512 }
513 #endif /* defined(CONFIG_VIDEO) || defined(CONFIG_CFB_CONSOLE) */
514