]> git.kernelconcepts.de Git - karo-tx-uboot.git/blob - drivers/video/fsl_diu_fb.c
Merge branch 'master' of git://git.denx.de/u-boot-mmc
[karo-tx-uboot.git] / drivers / video / fsl_diu_fb.c
1 /*
2  * Copyright 2007, 2010-2011 Freescale Semiconductor, Inc.
3  * Authors: York Sun <yorksun@freescale.com>
4  *          Timur Tabi <timur@freescale.com>
5  *
6  * FSL DIU Framebuffer driver
7  *
8  * See file CREDITS for list of people who contributed to this
9  * project.
10  *
11  * This program is free software; you can redistribute it and/or
12  * modify it under the terms of the GNU General Public License as
13  * published by the Free Software Foundation; either version 2 of
14  * the License, or (at your option) any later version.
15  *
16  * This program is distributed in the hope that it will be useful,
17  * but WITHOUT ANY WARRANTY; without even the implied warranty of
18  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
19  * GNU General Public License for more details.
20  *
21  * You should have received a copy of the GNU General Public License
22  * along with this program; if not, write to the Free Software
23  * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
24  * MA 02111-1307 USA
25  */
26
27 #include <common.h>
28 #include <malloc.h>
29 #include <asm/io.h>
30
31 #include "videomodes.h"
32 #include <video_fb.h>
33 #include <fsl_diu_fb.h>
34
35 struct fb_var_screeninfo {
36         unsigned int xres;              /* visible resolution           */
37         unsigned int yres;
38
39         unsigned int bits_per_pixel;    /* guess what                   */
40
41         /* Timing: All values in pixclocks, except pixclock (of course) */
42         unsigned int pixclock;          /* pixel clock in ps (pico seconds) */
43         unsigned int left_margin;       /* time from sync to picture    */
44         unsigned int right_margin;      /* time from picture to sync    */
45         unsigned int upper_margin;      /* time from sync to picture    */
46         unsigned int lower_margin;
47         unsigned int hsync_len;         /* length of horizontal sync    */
48         unsigned int vsync_len;         /* length of vertical sync      */
49         unsigned int sync;              /* see FB_SYNC_*                */
50         unsigned int vmode;             /* see FB_VMODE_*               */
51         unsigned int rotate;            /* angle we rotate counter clockwise */
52 };
53
54 struct fb_info {
55         struct fb_var_screeninfo var;   /* Current var */
56         unsigned int smem_len;          /* Length of frame buffer mem */
57         unsigned int type;              /* see FB_TYPE_*                */
58         unsigned int line_length;       /* length of a line in bytes    */
59
60         void *screen_base;
61         unsigned long screen_size;
62 };
63
64 struct fb_videomode {
65         const char *name;       /* optional */
66         unsigned int refresh;           /* optional */
67         unsigned int xres;
68         unsigned int yres;
69         unsigned int pixclock;
70         unsigned int left_margin;
71         unsigned int right_margin;
72         unsigned int upper_margin;
73         unsigned int lower_margin;
74         unsigned int hsync_len;
75         unsigned int vsync_len;
76         unsigned int sync;
77         unsigned int vmode;
78         unsigned int flag;
79 };
80
81 #define FB_SYNC_VERT_HIGH_ACT   2       /* vertical sync high active    */
82 #define FB_SYNC_COMP_HIGH_ACT   8       /* composite sync high active   */
83 #define FB_VMODE_NONINTERLACED  0       /* non interlaced */
84
85 /* This setting is used for the ifm pdm360ng with PRIMEVIEW PM070WL3 */
86 static struct fb_videomode fsl_diu_mode_800 = {
87         .name           = "800x600-60",
88         .refresh        = 60,
89         .xres           = 800,
90         .yres           = 480,
91         .pixclock       = 31250,
92         .left_margin    = 86,
93         .right_margin   = 42,
94         .upper_margin   = 33,
95         .lower_margin   = 10,
96         .hsync_len      = 128,
97         .vsync_len      = 2,
98         .sync           = 0,
99         .vmode          = FB_VMODE_NONINTERLACED
100 };
101
102 /*
103  * These parameters give default parameters
104  * for video output 1024x768,
105  * FIXME - change timing to proper amounts
106  * hsync 31.5kHz, vsync 60Hz
107  */
108 static struct fb_videomode fsl_diu_mode_1024 = {
109         .name           = "1024x768-60",
110         .refresh        = 60,
111         .xres           = 1024,
112         .yres           = 768,
113         .pixclock       = 15385,
114         .left_margin    = 160,
115         .right_margin   = 24,
116         .upper_margin   = 29,
117         .lower_margin   = 3,
118         .hsync_len      = 136,
119         .vsync_len      = 6,
120         .sync           = FB_SYNC_COMP_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT,
121         .vmode          = FB_VMODE_NONINTERLACED
122 };
123
124 static struct fb_videomode fsl_diu_mode_1280 = {
125         .name           = "1280x1024-60",
126         .refresh        = 60,
127         .xres           = 1280,
128         .yres           = 1024,
129         .pixclock       = 9375,
130         .left_margin    = 38,
131         .right_margin   = 128,
132         .upper_margin   = 2,
133         .lower_margin   = 7,
134         .hsync_len      = 216,
135         .vsync_len      = 37,
136         .sync           = FB_SYNC_COMP_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT,
137         .vmode          = FB_VMODE_NONINTERLACED
138 };
139
140 /*
141  * These are the fields of area descriptor(in DDR memory) for every plane
142  */
143 struct diu_ad {
144         /* Word 0(32-bit) in DDR memory */
145         __le32 pix_fmt; /* hard coding pixel format */
146         /* Word 1(32-bit) in DDR memory */
147         __le32 addr;
148         /* Word 2(32-bit) in DDR memory */
149         __le32 src_size_g_alpha;
150         /* Word 3(32-bit) in DDR memory */
151         __le32 aoi_size;
152         /* Word 4(32-bit) in DDR memory */
153         __le32 offset_xyi;
154         /* Word 5(32-bit) in DDR memory */
155         __le32 offset_xyd;
156         /* Word 6(32-bit) in DDR memory */
157         __le32 ckmax_r:8;
158         __le32 ckmax_g:8;
159         __le32 ckmax_b:8;
160         __le32 res9:8;
161         /* Word 7(32-bit) in DDR memory */
162         __le32 ckmin_r:8;
163         __le32 ckmin_g:8;
164         __le32 ckmin_b:8;
165         __le32 res10:8;
166         /* Word 8(32-bit) in DDR memory */
167         __le32 next_ad;
168         /* Word 9(32-bit) in DDR memory, just for 64-bit aligned */
169         __le32 res[3];
170 } __attribute__ ((packed));
171
172 /*
173  * DIU register map
174  */
175 struct diu {
176         __be32 desc[3];
177         __be32 gamma;
178         __be32 pallete;
179         __be32 cursor;
180         __be32 curs_pos;
181         __be32 diu_mode;
182         __be32 bgnd;
183         __be32 bgnd_wb;
184         __be32 disp_size;
185         __be32 wb_size;
186         __be32 wb_mem_addr;
187         __be32 hsyn_para;
188         __be32 vsyn_para;
189         __be32 syn_pol;
190         __be32 thresholds;
191         __be32 int_status;
192         __be32 int_mask;
193         __be32 colorbar[8];
194         __be32 filling;
195         __be32 plut;
196 } __attribute__ ((packed));
197
198 struct diu_addr {
199         void *vaddr;            /* Virtual address */
200         u32 paddr;              /* 32-bit physical address */
201         unsigned int offset;    /* Alignment offset */
202 };
203
204 static struct fb_info info;
205
206 /*
207  * Align to 64-bit(8-byte), 32-byte, etc.
208  */
209 static int allocate_buf(struct diu_addr *buf, u32 size, u32 bytes_align)
210 {
211         u32 offset, ssize;
212         u32 mask;
213
214         ssize = size + bytes_align;
215         buf->vaddr = malloc(ssize);
216         if (!buf->vaddr)
217                 return -1;
218
219         memset(buf->vaddr, 0, ssize);
220         mask = bytes_align - 1;
221         offset = (u32)buf->vaddr & mask;
222         if (offset) {
223                 buf->offset = bytes_align - offset;
224                 buf->vaddr += offset;
225         } else
226                 buf->offset = 0;
227
228         buf->paddr = virt_to_phys(buf->vaddr);
229         return 0;
230 }
231
232 /*
233  * Allocate a framebuffer and an Area Descriptor that points to it.  Both
234  * are created in the same memory block.  The Area Descriptor is updated to
235  * point to the framebuffer memory. Memory is aligned as needed.
236  */
237 static struct diu_ad *allocate_fb(unsigned int xres, unsigned int yres,
238                                   unsigned int depth, void **fb)
239 {
240         unsigned long size = xres * yres * depth;
241         struct diu_addr addr;
242         struct diu_ad *ad;
243         size_t ad_size = roundup(sizeof(struct diu_ad), 32);
244
245         /*
246          * Allocate a memory block that holds the Area Descriptor and the
247          * frame buffer right behind it.  To keep the code simple, everything
248          * is aligned on a 32-byte address.
249          */
250         if (allocate_buf(&addr, ad_size + size, 32) < 0)
251                 return NULL;
252
253         ad = addr.vaddr;
254         ad->addr = cpu_to_le32(addr.paddr + ad_size);
255         ad->aoi_size = cpu_to_le32((yres << 16) | xres);
256         ad->src_size_g_alpha = cpu_to_le32((yres << 12) | xres);
257         ad->offset_xyi = 0;
258         ad->offset_xyd = 0;
259
260         if (fb)
261                 *fb = addr.vaddr + ad_size;
262
263         return ad;
264 }
265
266 int fsl_diu_init(int xres, u32 pixel_format, int gamma_fix)
267 {
268         struct fb_videomode *fsl_diu_mode_db;
269         struct diu_ad *ad;
270         struct diu *hw = (struct diu *)CONFIG_SYS_DIU_ADDR;
271         u8 *gamma_table_base;
272         unsigned int i, j;
273         struct diu_ad *dummy_ad;
274         struct diu_addr gamma;
275         struct diu_addr cursor;
276
277         switch (xres) {
278         case 800:
279                 fsl_diu_mode_db = &fsl_diu_mode_800;
280                 break;
281         case 1280:
282                 fsl_diu_mode_db = &fsl_diu_mode_1280;
283                 break;
284         default:
285                 fsl_diu_mode_db = &fsl_diu_mode_1024;
286         }
287
288         /* The AD struct for the dummy framebuffer and the FB itself */
289         dummy_ad = allocate_fb(2, 4, 4, NULL);
290         if (!dummy_ad) {
291                 printf("DIU:   Out of memory\n");
292                 return -1;
293         }
294         dummy_ad->pix_fmt = 0x88883316;
295
296         /* read mode info */
297         info.var.xres = fsl_diu_mode_db->xres;
298         info.var.yres = fsl_diu_mode_db->yres;
299         info.var.bits_per_pixel = 32;
300         info.var.pixclock = fsl_diu_mode_db->pixclock;
301         info.var.left_margin = fsl_diu_mode_db->left_margin;
302         info.var.right_margin = fsl_diu_mode_db->right_margin;
303         info.var.upper_margin = fsl_diu_mode_db->upper_margin;
304         info.var.lower_margin = fsl_diu_mode_db->lower_margin;
305         info.var.hsync_len = fsl_diu_mode_db->hsync_len;
306         info.var.vsync_len = fsl_diu_mode_db->vsync_len;
307         info.var.sync = fsl_diu_mode_db->sync;
308         info.var.vmode = fsl_diu_mode_db->vmode;
309         info.line_length = info.var.xres * info.var.bits_per_pixel / 8;
310
311         /* Memory allocation for framebuffer */
312         info.smem_len =
313                 info.var.xres * info.var.yres * (info.var.bits_per_pixel / 8);
314         ad = allocate_fb(info.var.xres, info.var.yres,
315                          info.var.bits_per_pixel / 8, &info.screen_base);
316         if (!ad) {
317                 printf("DIU:   Out of memory\n");
318                 return -1;
319         }
320
321         ad->pix_fmt = pixel_format;
322
323         /* Disable chroma keying function */
324         ad->ckmax_r = 0;
325         ad->ckmax_g = 0;
326         ad->ckmax_b = 0;
327
328         ad->ckmin_r = 255;
329         ad->ckmin_g = 255;
330         ad->ckmin_b = 255;
331
332         /* Initialize the gamma table */
333         if (allocate_buf(&gamma, 256 * 3, 32) < 0) {
334                 printf("DIU:   Out of memory\n");
335                 return -1;
336         }
337         gamma_table_base = gamma.vaddr;
338         for (i = 0; i <= 2; i++)
339                 for (j = 0; j < 256; j++)
340                         *gamma_table_base++ = j;
341
342         if (gamma_fix == 1) {   /* fix the gamma */
343                 gamma_table_base = gamma.vaddr;
344                 for (i = 0; i < 256 * 3; i++) {
345                         gamma_table_base[i] = (gamma_table_base[i] << 2)
346                                 | ((gamma_table_base[i] >> 6) & 0x03);
347                 }
348         }
349
350         /* Initialize the cursor */
351         if (allocate_buf(&cursor, 32 * 32 * 2, 32) < 0) {
352                 printf("DIU:   Can't alloc cursor data\n");
353                 return -1;
354         }
355
356         /* Program DIU registers */
357         out_be32(&hw->diu_mode, 0);     /* Temporarily disable the DIU */
358
359         out_be32(&hw->gamma, gamma.paddr);
360         out_be32(&hw->cursor, cursor.paddr);
361         out_be32(&hw->bgnd, 0x007F7F7F);
362         out_be32(&hw->bgnd_wb, 0);
363         out_be32(&hw->disp_size, info.var.yres << 16 | info.var.xres);
364         out_be32(&hw->wb_size, 0);
365         out_be32(&hw->wb_mem_addr, 0);
366         out_be32(&hw->hsyn_para, info.var.left_margin << 22 |
367                         info.var.hsync_len << 11 |
368                         info.var.right_margin);
369
370         out_be32(&hw->vsyn_para, info.var.upper_margin << 22 |
371                         info.var.vsync_len << 11 |
372                         info.var.lower_margin);
373
374         out_be32(&hw->syn_pol, 0);
375         out_be32(&hw->thresholds, 0x00037800);
376         out_be32(&hw->int_status, 0);
377         out_be32(&hw->int_mask, 0);
378         out_be32(&hw->plut, 0x01F5F666);
379         /* Pixel Clock configuration */
380         diu_set_pixel_clock(info.var.pixclock);
381
382         /* Set the frame buffers */
383         out_be32(&hw->desc[0], virt_to_phys(ad));
384         out_be32(&hw->desc[1], virt_to_phys(dummy_ad));
385         out_be32(&hw->desc[2], virt_to_phys(dummy_ad));
386
387         /* Enable the DIU, set display to all three planes */
388         out_be32(&hw->diu_mode, 1);
389
390         return 0;
391 }
392
393 void *video_hw_init(void)
394 {
395         static GraphicDevice ctfb;
396         const char *options;
397         unsigned int depth = 0, freq = 0;
398
399         if (!video_get_video_mode(&ctfb.winSizeX, &ctfb.winSizeY, &depth, &freq,
400                                   &options))
401                 return NULL;
402
403         /* Find the monitor port, which is a required option */
404         if (!options)
405                 return NULL;
406         if (strncmp(options, "monitor=", 8) != 0)
407                 return NULL;
408
409         if (platform_diu_init(ctfb.winSizeX, ctfb.winSizeY, options + 8) < 0)
410                 return NULL;
411
412         /* fill in Graphic device struct */
413         sprintf(ctfb.modeIdent, "%ix%ix%i %ikHz %iHz",
414                 ctfb.winSizeX, ctfb.winSizeY, depth, 64, freq);
415
416         ctfb.frameAdrs = (unsigned int)info.screen_base;
417         ctfb.plnSizeX = ctfb.winSizeX;
418         ctfb.plnSizeY = ctfb.winSizeY;
419
420         ctfb.gdfBytesPP = 4;
421         ctfb.gdfIndex = GDF_32BIT_X888RGB;
422
423         ctfb.isaBase = 0;
424         ctfb.pciBase = 0;
425         ctfb.memSize = info.screen_size;
426
427         /* Cursor Start Address */
428         ctfb.dprBase = 0;
429         ctfb.vprBase = 0;
430         ctfb.cprBase = 0;
431
432         return &ctfb;
433 }