]> git.karo-electronics.de Git - karo-tx-uboot.git/blob - drivers/video/fsl_diu_fb.c
Merge branch 'master' of git://git.denx.de/u-boot-imx
[karo-tx-uboot.git] / drivers / video / fsl_diu_fb.c
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) */