Merge commit 'kumar/next' into next
[sfrench/cifs-2.6.git] / drivers / video / fsl-diu-fb.c
1 /*
2  * Copyright 2008 Freescale Semiconductor, Inc. All Rights Reserved.
3  *
4  *  Freescale DIU Frame Buffer device driver
5  *
6  *  Authors: Hongjun Chen <hong-jun.chen@freescale.com>
7  *           Paul Widmer <paul.widmer@freescale.com>
8  *           Srikanth Srinivasan <srikanth.srinivasan@freescale.com>
9  *           York Sun <yorksun@freescale.com>
10  *
11  *   Based on imxfb.c Copyright (C) 2004 S.Hauer, Pengutronix
12  *
13  * This program is free software; you can redistribute  it and/or modify it
14  * under  the terms of  the GNU General  Public License as published by the
15  * Free Software Foundation;  either version 2 of the  License, or (at your
16  * option) any later version.
17  *
18  */
19
20 #include <linux/module.h>
21 #include <linux/kernel.h>
22 #include <linux/errno.h>
23 #include <linux/string.h>
24 #include <linux/slab.h>
25 #include <linux/fb.h>
26 #include <linux/init.h>
27 #include <linux/dma-mapping.h>
28 #include <linux/platform_device.h>
29 #include <linux/interrupt.h>
30 #include <linux/clk.h>
31 #include <linux/uaccess.h>
32 #include <linux/vmalloc.h>
33
34 #include <linux/of_platform.h>
35
36 #include <sysdev/fsl_soc.h>
37 #include <linux/fsl-diu-fb.h>
38 #include "edid.h"
39
40 /*
41  * These parameters give default parameters
42  * for video output 1024x768,
43  * FIXME - change timing to proper amounts
44  * hsync 31.5kHz, vsync 60Hz
45  */
46 static struct fb_videomode __devinitdata fsl_diu_default_mode = {
47         .refresh        = 60,
48         .xres           = 1024,
49         .yres           = 768,
50         .pixclock       = 15385,
51         .left_margin    = 160,
52         .right_margin   = 24,
53         .upper_margin   = 29,
54         .lower_margin   = 3,
55         .hsync_len      = 136,
56         .vsync_len      = 6,
57         .sync           = FB_SYNC_COMP_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT,
58         .vmode          = FB_VMODE_NONINTERLACED
59 };
60
61 static struct fb_videomode __devinitdata fsl_diu_mode_db[] = {
62         {
63                 .name           = "1024x768-60",
64                 .refresh        = 60,
65                 .xres           = 1024,
66                 .yres           = 768,
67                 .pixclock       = 15385,
68                 .left_margin    = 160,
69                 .right_margin   = 24,
70                 .upper_margin   = 29,
71                 .lower_margin   = 3,
72                 .hsync_len      = 136,
73                 .vsync_len      = 6,
74                 .sync           = FB_SYNC_COMP_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT,
75                 .vmode          = FB_VMODE_NONINTERLACED
76         },
77         {
78                 .name           = "1024x768-70",
79                 .refresh        = 70,
80                 .xres           = 1024,
81                 .yres           = 768,
82                 .pixclock       = 16886,
83                 .left_margin    = 3,
84                 .right_margin   = 3,
85                 .upper_margin   = 2,
86                 .lower_margin   = 2,
87                 .hsync_len      = 40,
88                 .vsync_len      = 18,
89                 .sync           = FB_SYNC_COMP_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT,
90                 .vmode          = FB_VMODE_NONINTERLACED
91         },
92         {
93                 .name           = "1024x768-75",
94                 .refresh        = 75,
95                 .xres           = 1024,
96                 .yres           = 768,
97                 .pixclock       = 15009,
98                 .left_margin    = 3,
99                 .right_margin   = 3,
100                 .upper_margin   = 2,
101                 .lower_margin   = 2,
102                 .hsync_len      = 80,
103                 .vsync_len      = 32,
104                 .sync           = FB_SYNC_COMP_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT,
105                 .vmode          = FB_VMODE_NONINTERLACED
106         },
107         {
108                 .name           = "1280x1024-60",
109                 .refresh        = 60,
110                 .xres           = 1280,
111                 .yres           = 1024,
112                 .pixclock       = 9375,
113                 .left_margin    = 38,
114                 .right_margin   = 128,
115                 .upper_margin   = 2,
116                 .lower_margin   = 7,
117                 .hsync_len      = 216,
118                 .vsync_len      = 37,
119                 .sync           = FB_SYNC_COMP_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT,
120                 .vmode          = FB_VMODE_NONINTERLACED
121         },
122         {
123                 .name           = "1280x1024-70",
124                 .refresh        = 70,
125                 .xres           = 1280,
126                 .yres           = 1024,
127                 .pixclock       = 9380,
128                 .left_margin    = 6,
129                 .right_margin   = 6,
130                 .upper_margin   = 4,
131                 .lower_margin   = 4,
132                 .hsync_len      = 60,
133                 .vsync_len      = 94,
134                 .sync           = FB_SYNC_COMP_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT,
135                 .vmode          = FB_VMODE_NONINTERLACED
136         },
137         {
138                 .name           = "1280x1024-75",
139                 .refresh        = 75,
140                 .xres           = 1280,
141                 .yres           = 1024,
142                 .pixclock       = 9380,
143                 .left_margin    = 6,
144                 .right_margin   = 6,
145                 .upper_margin   = 4,
146                 .lower_margin   = 4,
147                 .hsync_len      = 60,
148                 .vsync_len      = 15,
149                 .sync           = FB_SYNC_COMP_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT,
150                 .vmode          = FB_VMODE_NONINTERLACED
151         },
152         {
153                 .name           = "320x240",            /* for AOI only */
154                 .refresh        = 60,
155                 .xres           = 320,
156                 .yres           = 240,
157                 .pixclock       = 15385,
158                 .left_margin    = 0,
159                 .right_margin   = 0,
160                 .upper_margin   = 0,
161                 .lower_margin   = 0,
162                 .hsync_len      = 0,
163                 .vsync_len      = 0,
164                 .sync           = FB_SYNC_COMP_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT,
165                 .vmode          = FB_VMODE_NONINTERLACED
166         },
167         {
168                 .name           = "1280x480-60",
169                 .refresh        = 60,
170                 .xres           = 1280,
171                 .yres           = 480,
172                 .pixclock       = 18939,
173                 .left_margin    = 353,
174                 .right_margin   = 47,
175                 .upper_margin   = 39,
176                 .lower_margin   = 4,
177                 .hsync_len      = 8,
178                 .vsync_len      = 2,
179                 .sync           = FB_SYNC_COMP_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT,
180                 .vmode          = FB_VMODE_NONINTERLACED
181         },
182 };
183
184 static char *fb_mode = "1024x768-32@60";
185 static unsigned long default_bpp = 32;
186 static int monitor_port;
187
188 #if defined(CONFIG_NOT_COHERENT_CACHE)
189 static u8 *coherence_data;
190 static size_t coherence_data_size;
191 static unsigned int d_cache_line_size;
192 #endif
193
194 static DEFINE_SPINLOCK(diu_lock);
195
196 struct fsl_diu_data {
197         struct fb_info *fsl_diu_info[FSL_AOI_NUM - 1];
198                                 /*FSL_AOI_NUM has one dummy AOI */
199         struct device_attribute dev_attr;
200         struct diu_ad *dummy_ad;
201         void *dummy_aoi_virt;
202         unsigned int irq;
203         int fb_enabled;
204         int monitor_port;
205 };
206
207 struct mfb_info {
208         int index;
209         int type;
210         char *id;
211         int registered;
212         int blank;
213         unsigned long pseudo_palette[16];
214         struct diu_ad *ad;
215         int cursor_reset;
216         unsigned char g_alpha;
217         unsigned int count;
218         int x_aoi_d;            /* aoi display x offset to physical screen */
219         int y_aoi_d;            /* aoi display y offset to physical screen */
220         struct fsl_diu_data *parent;
221         u8 *edid_data;
222 };
223
224
225 static struct mfb_info mfb_template[] = {
226         {               /* AOI 0 for plane 0 */
227         .index = 0,
228         .type = MFB_TYPE_OUTPUT,
229         .id = "Panel0",
230         .registered = 0,
231         .count = 0,
232         .x_aoi_d = 0,
233         .y_aoi_d = 0,
234         },
235         {               /* AOI 0 for plane 1 */
236         .index = 1,
237         .type = MFB_TYPE_OUTPUT,
238         .id = "Panel1 AOI0",
239         .registered = 0,
240         .g_alpha = 0xff,
241         .count = 0,
242         .x_aoi_d = 0,
243         .y_aoi_d = 0,
244         },
245         {               /* AOI 1 for plane 1 */
246         .index = 2,
247         .type = MFB_TYPE_OUTPUT,
248         .id = "Panel1 AOI1",
249         .registered = 0,
250         .g_alpha = 0xff,
251         .count = 0,
252         .x_aoi_d = 0,
253         .y_aoi_d = 480,
254         },
255         {               /* AOI 0 for plane 2 */
256         .index = 3,
257         .type = MFB_TYPE_OUTPUT,
258         .id = "Panel2 AOI0",
259         .registered = 0,
260         .g_alpha = 0xff,
261         .count = 0,
262         .x_aoi_d = 640,
263         .y_aoi_d = 0,
264         },
265         {               /* AOI 1 for plane 2 */
266         .index = 4,
267         .type = MFB_TYPE_OUTPUT,
268         .id = "Panel2 AOI1",
269         .registered = 0,
270         .g_alpha = 0xff,
271         .count = 0,
272         .x_aoi_d = 640,
273         .y_aoi_d = 480,
274         },
275 };
276
277 static struct diu_hw dr = {
278         .mode = MFB_MODE1,
279         .reg_lock = __SPIN_LOCK_UNLOCKED(diu_hw.reg_lock),
280 };
281
282 static struct diu_pool pool;
283
284 /**
285  * fsl_diu_alloc - allocate memory for the DIU
286  * @size: number of bytes to allocate
287  * @param: returned physical address of memory
288  *
289  * This function allocates a physically-contiguous block of memory.
290  */
291 static void *fsl_diu_alloc(size_t size, phys_addr_t *phys)
292 {
293         void *virt;
294
295         pr_debug("size=%zu\n", size);
296
297         virt = alloc_pages_exact(size, GFP_DMA | __GFP_ZERO);
298         if (virt) {
299                 *phys = virt_to_phys(virt);
300                 pr_debug("virt=%p phys=%llx\n", virt,
301                         (unsigned long long)*phys);
302         }
303
304         return virt;
305 }
306
307 /**
308  * fsl_diu_free - release DIU memory
309  * @virt: pointer returned by fsl_diu_alloc()
310  * @size: number of bytes allocated by fsl_diu_alloc()
311  *
312  * This function releases memory allocated by fsl_diu_alloc().
313  */
314 static void fsl_diu_free(void *virt, size_t size)
315 {
316         pr_debug("virt=%p size=%zu\n", virt, size);
317
318         if (virt && size)
319                 free_pages_exact(virt, size);
320 }
321
322 /*
323  * Workaround for failed writing desc register of planes.
324  * Needed with MPC5121 DIU rev 2.0 silicon.
325  */
326 void wr_reg_wa(u32 *reg, u32 val)
327 {
328         do {
329                 out_be32(reg, val);
330         } while (in_be32(reg) != val);
331 }
332
333 static int fsl_diu_enable_panel(struct fb_info *info)
334 {
335         struct mfb_info *pmfbi, *cmfbi, *mfbi = info->par;
336         struct diu *hw = dr.diu_reg;
337         struct diu_ad *ad = mfbi->ad;
338         struct fsl_diu_data *machine_data = mfbi->parent;
339         int res = 0;
340
341         pr_debug("enable_panel index %d\n", mfbi->index);
342         if (mfbi->type != MFB_TYPE_OFF) {
343                 switch (mfbi->index) {
344                 case 0:                         /* plane 0 */
345                         if (hw->desc[0] != ad->paddr)
346                                 wr_reg_wa(&hw->desc[0], ad->paddr);
347                         break;
348                 case 1:                         /* plane 1 AOI 0 */
349                         cmfbi = machine_data->fsl_diu_info[2]->par;
350                         if (hw->desc[1] != ad->paddr) { /* AOI0 closed */
351                                 if (cmfbi->count > 0)   /* AOI1 open */
352                                         ad->next_ad =
353                                                 cpu_to_le32(cmfbi->ad->paddr);
354                                 else
355                                         ad->next_ad = 0;
356                                 wr_reg_wa(&hw->desc[1], ad->paddr);
357                         }
358                         break;
359                 case 3:                         /* plane 2 AOI 0 */
360                         cmfbi = machine_data->fsl_diu_info[4]->par;
361                         if (hw->desc[2] != ad->paddr) { /* AOI0 closed */
362                                 if (cmfbi->count > 0)   /* AOI1 open */
363                                         ad->next_ad =
364                                                 cpu_to_le32(cmfbi->ad->paddr);
365                                 else
366                                         ad->next_ad = 0;
367                                 wr_reg_wa(&hw->desc[2], ad->paddr);
368                         }
369                         break;
370                 case 2:                         /* plane 1 AOI 1 */
371                         pmfbi = machine_data->fsl_diu_info[1]->par;
372                         ad->next_ad = 0;
373                         if (hw->desc[1] == machine_data->dummy_ad->paddr)
374                                 wr_reg_wa(&hw->desc[1], ad->paddr);
375                         else                                    /* AOI0 open */
376                                 pmfbi->ad->next_ad = cpu_to_le32(ad->paddr);
377                         break;
378                 case 4:                         /* plane 2 AOI 1 */
379                         pmfbi = machine_data->fsl_diu_info[3]->par;
380                         ad->next_ad = 0;
381                         if (hw->desc[2] == machine_data->dummy_ad->paddr)
382                                 wr_reg_wa(&hw->desc[2], ad->paddr);
383                         else                            /* AOI0 was open */
384                                 pmfbi->ad->next_ad = cpu_to_le32(ad->paddr);
385                         break;
386                 default:
387                         res = -EINVAL;
388                         break;
389                 }
390         } else
391                 res = -EINVAL;
392         return res;
393 }
394
395 static int fsl_diu_disable_panel(struct fb_info *info)
396 {
397         struct mfb_info *pmfbi, *cmfbi, *mfbi = info->par;
398         struct diu *hw = dr.diu_reg;
399         struct diu_ad *ad = mfbi->ad;
400         struct fsl_diu_data *machine_data = mfbi->parent;
401         int res = 0;
402
403         switch (mfbi->index) {
404         case 0:                                 /* plane 0 */
405                 if (hw->desc[0] != machine_data->dummy_ad->paddr)
406                         wr_reg_wa(&hw->desc[0], machine_data->dummy_ad->paddr);
407                 break;
408         case 1:                                 /* plane 1 AOI 0 */
409                 cmfbi = machine_data->fsl_diu_info[2]->par;
410                 if (cmfbi->count > 0)   /* AOI1 is open */
411                         wr_reg_wa(&hw->desc[1], cmfbi->ad->paddr);
412                                         /* move AOI1 to the first */
413                 else                    /* AOI1 was closed */
414                         wr_reg_wa(&hw->desc[1], machine_data->dummy_ad->paddr);
415                                         /* close AOI 0 */
416                 break;
417         case 3:                                 /* plane 2 AOI 0 */
418                 cmfbi = machine_data->fsl_diu_info[4]->par;
419                 if (cmfbi->count > 0)   /* AOI1 is open */
420                         wr_reg_wa(&hw->desc[2], cmfbi->ad->paddr);
421                                         /* move AOI1 to the first */
422                 else                    /* AOI1 was closed */
423                         wr_reg_wa(&hw->desc[2], machine_data->dummy_ad->paddr);
424                                         /* close AOI 0 */
425                 break;
426         case 2:                                 /* plane 1 AOI 1 */
427                 pmfbi = machine_data->fsl_diu_info[1]->par;
428                 if (hw->desc[1] != ad->paddr) {
429                                 /* AOI1 is not the first in the chain */
430                         if (pmfbi->count > 0)
431                                         /* AOI0 is open, must be the first */
432                                 pmfbi->ad->next_ad = 0;
433                 } else                  /* AOI1 is the first in the chain */
434                         wr_reg_wa(&hw->desc[1], machine_data->dummy_ad->paddr);
435                                         /* close AOI 1 */
436                 break;
437         case 4:                                 /* plane 2 AOI 1 */
438                 pmfbi = machine_data->fsl_diu_info[3]->par;
439                 if (hw->desc[2] != ad->paddr) {
440                                 /* AOI1 is not the first in the chain */
441                         if (pmfbi->count > 0)
442                                 /* AOI0 is open, must be the first */
443                                 pmfbi->ad->next_ad = 0;
444                 } else          /* AOI1 is the first in the chain */
445                         wr_reg_wa(&hw->desc[2], machine_data->dummy_ad->paddr);
446                                 /* close AOI 1 */
447                 break;
448         default:
449                 res = -EINVAL;
450                 break;
451         }
452
453         return res;
454 }
455
456 static void enable_lcdc(struct fb_info *info)
457 {
458         struct diu *hw = dr.diu_reg;
459         struct mfb_info *mfbi = info->par;
460         struct fsl_diu_data *machine_data = mfbi->parent;
461
462         if (!machine_data->fb_enabled) {
463                 out_be32(&hw->diu_mode, dr.mode);
464                 machine_data->fb_enabled++;
465         }
466 }
467
468 static void disable_lcdc(struct fb_info *info)
469 {
470         struct diu *hw = dr.diu_reg;
471         struct mfb_info *mfbi = info->par;
472         struct fsl_diu_data *machine_data = mfbi->parent;
473
474         if (machine_data->fb_enabled) {
475                 out_be32(&hw->diu_mode, 0);
476                 machine_data->fb_enabled = 0;
477         }
478 }
479
480 static void adjust_aoi_size_position(struct fb_var_screeninfo *var,
481                                 struct fb_info *info)
482 {
483         struct mfb_info *lower_aoi_mfbi, *upper_aoi_mfbi, *mfbi = info->par;
484         struct fsl_diu_data *machine_data = mfbi->parent;
485         int available_height, upper_aoi_bottom, index = mfbi->index;
486         int lower_aoi_is_open, upper_aoi_is_open;
487         __u32 base_plane_width, base_plane_height, upper_aoi_height;
488
489         base_plane_width = machine_data->fsl_diu_info[0]->var.xres;
490         base_plane_height = machine_data->fsl_diu_info[0]->var.yres;
491
492         if (mfbi->x_aoi_d < 0)
493                 mfbi->x_aoi_d = 0;
494         if (mfbi->y_aoi_d < 0)
495                 mfbi->y_aoi_d = 0;
496         switch (index) {
497         case 0:
498                 if (mfbi->x_aoi_d != 0)
499                         mfbi->x_aoi_d = 0;
500                 if (mfbi->y_aoi_d != 0)
501                         mfbi->y_aoi_d = 0;
502                 break;
503         case 1:                 /* AOI 0 */
504         case 3:
505                 lower_aoi_mfbi = machine_data->fsl_diu_info[index+1]->par;
506                 lower_aoi_is_open = lower_aoi_mfbi->count > 0 ? 1 : 0;
507                 if (var->xres > base_plane_width)
508                         var->xres = base_plane_width;
509                 if ((mfbi->x_aoi_d + var->xres) > base_plane_width)
510                         mfbi->x_aoi_d = base_plane_width - var->xres;
511
512                 if (lower_aoi_is_open)
513                         available_height = lower_aoi_mfbi->y_aoi_d;
514                 else
515                         available_height = base_plane_height;
516                 if (var->yres > available_height)
517                         var->yres = available_height;
518                 if ((mfbi->y_aoi_d + var->yres) > available_height)
519                         mfbi->y_aoi_d = available_height - var->yres;
520                 break;
521         case 2:                 /* AOI 1 */
522         case 4:
523                 upper_aoi_mfbi = machine_data->fsl_diu_info[index-1]->par;
524                 upper_aoi_height =
525                                 machine_data->fsl_diu_info[index-1]->var.yres;
526                 upper_aoi_bottom = upper_aoi_mfbi->y_aoi_d + upper_aoi_height;
527                 upper_aoi_is_open = upper_aoi_mfbi->count > 0 ? 1 : 0;
528                 if (var->xres > base_plane_width)
529                         var->xres = base_plane_width;
530                 if ((mfbi->x_aoi_d + var->xres) > base_plane_width)
531                         mfbi->x_aoi_d = base_plane_width - var->xres;
532                 if (mfbi->y_aoi_d < 0)
533                         mfbi->y_aoi_d = 0;
534                 if (upper_aoi_is_open) {
535                         if (mfbi->y_aoi_d < upper_aoi_bottom)
536                                 mfbi->y_aoi_d = upper_aoi_bottom;
537                         available_height = base_plane_height
538                                                 - upper_aoi_bottom;
539                 } else
540                         available_height = base_plane_height;
541                 if (var->yres > available_height)
542                         var->yres = available_height;
543                 if ((mfbi->y_aoi_d + var->yres) > base_plane_height)
544                         mfbi->y_aoi_d = base_plane_height - var->yres;
545                 break;
546         }
547 }
548 /*
549  * Checks to see if the hardware supports the state requested by var passed
550  * in. This function does not alter the hardware state! If the var passed in
551  * is slightly off by what the hardware can support then we alter the var
552  * PASSED in to what we can do. If the hardware doesn't support mode change
553  * a -EINVAL will be returned by the upper layers.
554  */
555 static int fsl_diu_check_var(struct fb_var_screeninfo *var,
556                                 struct fb_info *info)
557 {
558         unsigned long htotal, vtotal;
559
560         pr_debug("check_var xres: %d\n", var->xres);
561         pr_debug("check_var yres: %d\n", var->yres);
562
563         if (var->xres_virtual < var->xres)
564                 var->xres_virtual = var->xres;
565         if (var->yres_virtual < var->yres)
566                 var->yres_virtual = var->yres;
567
568         if (var->xoffset < 0)
569                 var->xoffset = 0;
570
571         if (var->yoffset < 0)
572                 var->yoffset = 0;
573
574         if (var->xoffset + info->var.xres > info->var.xres_virtual)
575                 var->xoffset = info->var.xres_virtual - info->var.xres;
576
577         if (var->yoffset + info->var.yres > info->var.yres_virtual)
578                 var->yoffset = info->var.yres_virtual - info->var.yres;
579
580         if ((var->bits_per_pixel != 32) && (var->bits_per_pixel != 24) &&
581             (var->bits_per_pixel != 16))
582                 var->bits_per_pixel = default_bpp;
583
584         switch (var->bits_per_pixel) {
585         case 16:
586                 var->red.length = 5;
587                 var->red.offset = 11;
588                 var->red.msb_right = 0;
589
590                 var->green.length = 6;
591                 var->green.offset = 5;
592                 var->green.msb_right = 0;
593
594                 var->blue.length = 5;
595                 var->blue.offset = 0;
596                 var->blue.msb_right = 0;
597
598                 var->transp.length = 0;
599                 var->transp.offset = 0;
600                 var->transp.msb_right = 0;
601                 break;
602         case 24:
603                 var->red.length = 8;
604                 var->red.offset = 0;
605                 var->red.msb_right = 0;
606
607                 var->green.length = 8;
608                 var->green.offset = 8;
609                 var->green.msb_right = 0;
610
611                 var->blue.length = 8;
612                 var->blue.offset = 16;
613                 var->blue.msb_right = 0;
614
615                 var->transp.length = 0;
616                 var->transp.offset = 0;
617                 var->transp.msb_right = 0;
618                 break;
619         case 32:
620                 var->red.length = 8;
621                 var->red.offset = 16;
622                 var->red.msb_right = 0;
623
624                 var->green.length = 8;
625                 var->green.offset = 8;
626                 var->green.msb_right = 0;
627
628                 var->blue.length = 8;
629                 var->blue.offset = 0;
630                 var->blue.msb_right = 0;
631
632                 var->transp.length = 8;
633                 var->transp.offset = 24;
634                 var->transp.msb_right = 0;
635
636                 break;
637         }
638         /* If the pixclock is below the minimum spec'd value then set to
639          * refresh rate for 60Hz since this is supported by most monitors.
640          * Refer to Documentation/fb/ for calculations.
641          */
642         if ((var->pixclock < MIN_PIX_CLK) || (var->pixclock > MAX_PIX_CLK)) {
643                 htotal = var->xres + var->right_margin + var->hsync_len +
644                     var->left_margin;
645                 vtotal = var->yres + var->lower_margin + var->vsync_len +
646                     var->upper_margin;
647                 var->pixclock = (vtotal * htotal * 6UL) / 100UL;
648                 var->pixclock = KHZ2PICOS(var->pixclock);
649                 pr_debug("pixclock set for 60Hz refresh = %u ps\n",
650                         var->pixclock);
651         }
652
653         var->height = -1;
654         var->width = -1;
655         var->grayscale = 0;
656
657         /* Copy nonstd field to/from sync for fbset usage */
658         var->sync |= var->nonstd;
659         var->nonstd |= var->sync;
660
661         adjust_aoi_size_position(var, info);
662         return 0;
663 }
664
665 static void set_fix(struct fb_info *info)
666 {
667         struct fb_fix_screeninfo *fix = &info->fix;
668         struct fb_var_screeninfo *var = &info->var;
669         struct mfb_info *mfbi = info->par;
670
671         strncpy(fix->id, mfbi->id, strlen(mfbi->id));
672         fix->line_length = var->xres_virtual * var->bits_per_pixel / 8;
673         fix->type = FB_TYPE_PACKED_PIXELS;
674         fix->accel = FB_ACCEL_NONE;
675         fix->visual = FB_VISUAL_TRUECOLOR;
676         fix->xpanstep = 1;
677         fix->ypanstep = 1;
678 }
679
680 static void update_lcdc(struct fb_info *info)
681 {
682         struct fb_var_screeninfo *var = &info->var;
683         struct mfb_info *mfbi = info->par;
684         struct fsl_diu_data *machine_data = mfbi->parent;
685         struct diu *hw;
686         int i, j;
687         char __iomem *cursor_base, *gamma_table_base;
688
689         u32 temp;
690
691         hw = dr.diu_reg;
692
693         if (mfbi->type == MFB_TYPE_OFF) {
694                 fsl_diu_disable_panel(info);
695                 return;
696         }
697
698         diu_ops.set_monitor_port(machine_data->monitor_port);
699         gamma_table_base = pool.gamma.vaddr;
700         cursor_base = pool.cursor.vaddr;
701         /* Prep for DIU init  - gamma table, cursor table */
702
703         for (i = 0; i <= 2; i++)
704            for (j = 0; j <= 255; j++)
705               *gamma_table_base++ = j;
706
707         diu_ops.set_gamma_table(machine_data->monitor_port, pool.gamma.vaddr);
708
709         pr_debug("update-lcdc: HW - %p\n Disabling DIU\n", hw);
710         disable_lcdc(info);
711
712         /* Program DIU registers */
713
714         out_be32(&hw->gamma, pool.gamma.paddr);
715         out_be32(&hw->cursor, pool.cursor.paddr);
716
717         out_be32(&hw->bgnd, 0x007F7F7F);        /* BGND */
718         out_be32(&hw->bgnd_wb, 0);              /* BGND_WB */
719         out_be32(&hw->disp_size, (var->yres << 16 | var->xres));
720                                                 /* DISP SIZE */
721         pr_debug("DIU xres: %d\n", var->xres);
722         pr_debug("DIU yres: %d\n", var->yres);
723
724         out_be32(&hw->wb_size, 0); /* WB SIZE */
725         out_be32(&hw->wb_mem_addr, 0); /* WB MEM ADDR */
726
727         /* Horizontal and vertical configuration register */
728         temp = var->left_margin << 22 | /* BP_H */
729                var->hsync_len << 11 |   /* PW_H */
730                var->right_margin;       /* FP_H */
731
732         out_be32(&hw->hsyn_para, temp);
733
734         temp = var->upper_margin << 22 | /* BP_V */
735                var->vsync_len << 11 |    /* PW_V  */
736                var->lower_margin;        /* FP_V  */
737
738         out_be32(&hw->vsyn_para, temp);
739
740         pr_debug("DIU right_margin - %d\n", var->right_margin);
741         pr_debug("DIU left_margin - %d\n", var->left_margin);
742         pr_debug("DIU hsync_len - %d\n", var->hsync_len);
743         pr_debug("DIU upper_margin - %d\n", var->upper_margin);
744         pr_debug("DIU lower_margin - %d\n", var->lower_margin);
745         pr_debug("DIU vsync_len - %d\n", var->vsync_len);
746         pr_debug("DIU HSYNC - 0x%08x\n", hw->hsyn_para);
747         pr_debug("DIU VSYNC - 0x%08x\n", hw->vsyn_para);
748
749         diu_ops.set_pixel_clock(var->pixclock);
750
751         out_be32(&hw->syn_pol, 0);      /* SYNC SIGNALS POLARITY */
752         out_be32(&hw->thresholds, 0x00037800); /* The Thresholds */
753         out_be32(&hw->int_status, 0);   /* INTERRUPT STATUS */
754         out_be32(&hw->plut, 0x01F5F666);
755
756         /* Enable the DIU */
757         enable_lcdc(info);
758 }
759
760 static int map_video_memory(struct fb_info *info)
761 {
762         phys_addr_t phys;
763         u32 smem_len = info->fix.line_length * info->var.yres_virtual;
764
765         pr_debug("info->var.xres_virtual = %d\n", info->var.xres_virtual);
766         pr_debug("info->var.yres_virtual = %d\n", info->var.yres_virtual);
767         pr_debug("info->fix.line_length  = %d\n", info->fix.line_length);
768         pr_debug("MAP_VIDEO_MEMORY: smem_len = %u\n", smem_len);
769
770         info->screen_base = fsl_diu_alloc(smem_len, &phys);
771         if (info->screen_base == NULL) {
772                 printk(KERN_ERR "Unable to allocate fb memory\n");
773                 return -ENOMEM;
774         }
775         mutex_lock(&info->mm_lock);
776         info->fix.smem_start = (unsigned long) phys;
777         info->fix.smem_len = smem_len;
778         mutex_unlock(&info->mm_lock);
779         info->screen_size = info->fix.smem_len;
780
781         pr_debug("Allocated fb @ paddr=0x%08lx, size=%d.\n",
782                  info->fix.smem_start, info->fix.smem_len);
783         pr_debug("screen base %p\n", info->screen_base);
784
785         return 0;
786 }
787
788 static void unmap_video_memory(struct fb_info *info)
789 {
790         fsl_diu_free(info->screen_base, info->fix.smem_len);
791         mutex_lock(&info->mm_lock);
792         info->screen_base = NULL;
793         info->fix.smem_start = 0;
794         info->fix.smem_len = 0;
795         mutex_unlock(&info->mm_lock);
796 }
797
798 /*
799  * Using the fb_var_screeninfo in fb_info we set the aoi of this
800  * particular framebuffer. It is a light version of fsl_diu_set_par.
801  */
802 static int fsl_diu_set_aoi(struct fb_info *info)
803 {
804         struct fb_var_screeninfo *var = &info->var;
805         struct mfb_info *mfbi = info->par;
806         struct diu_ad *ad = mfbi->ad;
807
808         /* AOI should not be greater than display size */
809         ad->offset_xyi = cpu_to_le32((var->yoffset << 16) | var->xoffset);
810         ad->offset_xyd = cpu_to_le32((mfbi->y_aoi_d << 16) | mfbi->x_aoi_d);
811         return 0;
812 }
813
814 /*
815  * Using the fb_var_screeninfo in fb_info we set the resolution of this
816  * particular framebuffer. This function alters the fb_fix_screeninfo stored
817  * in fb_info. It does not alter var in fb_info since we are using that
818  * data. This means we depend on the data in var inside fb_info to be
819  * supported by the hardware. fsl_diu_check_var is always called before
820  * fsl_diu_set_par to ensure this.
821  */
822 static int fsl_diu_set_par(struct fb_info *info)
823 {
824         unsigned long len;
825         struct fb_var_screeninfo *var = &info->var;
826         struct mfb_info *mfbi = info->par;
827         struct fsl_diu_data *machine_data = mfbi->parent;
828         struct diu_ad *ad = mfbi->ad;
829         struct diu *hw;
830
831         hw = dr.diu_reg;
832
833         set_fix(info);
834         mfbi->cursor_reset = 1;
835
836         len = info->var.yres_virtual * info->fix.line_length;
837         /* Alloc & dealloc each time resolution/bpp change */
838         if (len != info->fix.smem_len) {
839                 if (info->fix.smem_start)
840                         unmap_video_memory(info);
841                 pr_debug("SET PAR: smem_len = %d\n", info->fix.smem_len);
842
843                 /* Memory allocation for framebuffer */
844                 if (map_video_memory(info)) {
845                         printk(KERN_ERR "Unable to allocate fb memory 1\n");
846                         return -ENOMEM;
847                 }
848         }
849
850         ad->pix_fmt =
851                 diu_ops.get_pixel_format(var->bits_per_pixel,
852                                          machine_data->monitor_port);
853         ad->addr    = cpu_to_le32(info->fix.smem_start);
854         ad->src_size_g_alpha = cpu_to_le32((var->yres_virtual << 12) |
855                                 var->xres_virtual) | mfbi->g_alpha;
856         /* AOI should not be greater than display size */
857         ad->aoi_size    = cpu_to_le32((var->yres << 16) | var->xres);
858         ad->offset_xyi = cpu_to_le32((var->yoffset << 16) | var->xoffset);
859         ad->offset_xyd = cpu_to_le32((mfbi->y_aoi_d << 16) | mfbi->x_aoi_d);
860
861         /* Disable chroma keying function */
862         ad->ckmax_r = 0;
863         ad->ckmax_g = 0;
864         ad->ckmax_b = 0;
865
866         ad->ckmin_r = 255;
867         ad->ckmin_g = 255;
868         ad->ckmin_b = 255;
869
870         if (mfbi->index == 0)
871                 update_lcdc(info);
872         return 0;
873 }
874
875 static inline __u32 CNVT_TOHW(__u32 val, __u32 width)
876 {
877         return ((val<<width) + 0x7FFF - val)>>16;
878 }
879
880 /*
881  * Set a single color register. The values supplied have a 16 bit magnitude
882  * which needs to be scaled in this function for the hardware. Things to take
883  * into consideration are how many color registers, if any, are supported with
884  * the current color visual. With truecolor mode no color palettes are
885  * supported. Here a psuedo palette is created which we store the value in
886  * pseudo_palette in struct fb_info. For pseudocolor mode we have a limited
887  * color palette.
888  */
889 static int fsl_diu_setcolreg(unsigned regno, unsigned red, unsigned green,
890                            unsigned blue, unsigned transp, struct fb_info *info)
891 {
892         int ret = 1;
893
894         /*
895          * If greyscale is true, then we convert the RGB value
896          * to greyscale no matter what visual we are using.
897          */
898         if (info->var.grayscale)
899                 red = green = blue = (19595 * red + 38470 * green +
900                                       7471 * blue) >> 16;
901         switch (info->fix.visual) {
902         case FB_VISUAL_TRUECOLOR:
903                 /*
904                  * 16-bit True Colour.  We encode the RGB value
905                  * according to the RGB bitfield information.
906                  */
907                 if (regno < 16) {
908                         u32 *pal = info->pseudo_palette;
909                         u32 v;
910
911                         red = CNVT_TOHW(red, info->var.red.length);
912                         green = CNVT_TOHW(green, info->var.green.length);
913                         blue = CNVT_TOHW(blue, info->var.blue.length);
914                         transp = CNVT_TOHW(transp, info->var.transp.length);
915
916                         v = (red << info->var.red.offset) |
917                             (green << info->var.green.offset) |
918                             (blue << info->var.blue.offset) |
919                             (transp << info->var.transp.offset);
920
921                         pal[regno] = v;
922                         ret = 0;
923                 }
924                 break;
925         case FB_VISUAL_STATIC_PSEUDOCOLOR:
926         case FB_VISUAL_PSEUDOCOLOR:
927                 break;
928         }
929
930         return ret;
931 }
932
933 /*
934  * Pan (or wrap, depending on the `vmode' field) the display using the
935  * 'xoffset' and 'yoffset' fields of the 'var' structure. If the values
936  * don't fit, return -EINVAL.
937  */
938 static int fsl_diu_pan_display(struct fb_var_screeninfo *var,
939                              struct fb_info *info)
940 {
941         if ((info->var.xoffset == var->xoffset) &&
942             (info->var.yoffset == var->yoffset))
943                 return 0;       /* No change, do nothing */
944
945         if (var->xoffset < 0 || var->yoffset < 0
946             || var->xoffset + info->var.xres > info->var.xres_virtual
947             || var->yoffset + info->var.yres > info->var.yres_virtual)
948                 return -EINVAL;
949
950         info->var.xoffset = var->xoffset;
951         info->var.yoffset = var->yoffset;
952
953         if (var->vmode & FB_VMODE_YWRAP)
954                 info->var.vmode |= FB_VMODE_YWRAP;
955         else
956                 info->var.vmode &= ~FB_VMODE_YWRAP;
957
958         fsl_diu_set_aoi(info);
959
960         return 0;
961 }
962
963 /*
964  * Blank the screen if blank_mode != 0, else unblank. Return 0 if blanking
965  * succeeded, != 0 if un-/blanking failed.
966  * blank_mode == 2: suspend vsync
967  * blank_mode == 3: suspend hsync
968  * blank_mode == 4: powerdown
969  */
970 static int fsl_diu_blank(int blank_mode, struct fb_info *info)
971 {
972         struct mfb_info *mfbi = info->par;
973
974         mfbi->blank = blank_mode;
975
976         switch (blank_mode) {
977         case FB_BLANK_VSYNC_SUSPEND:
978         case FB_BLANK_HSYNC_SUSPEND:
979         /* FIXME: fixes to enable_panel and enable lcdc needed */
980         case FB_BLANK_NORMAL:
981         /*      fsl_diu_disable_panel(info);*/
982                 break;
983         case FB_BLANK_POWERDOWN:
984         /*      disable_lcdc(info);     */
985                 break;
986         case FB_BLANK_UNBLANK:
987         /*      fsl_diu_enable_panel(info);*/
988                 break;
989         }
990
991         return 0;
992 }
993
994 static int fsl_diu_ioctl(struct fb_info *info, unsigned int cmd,
995                        unsigned long arg)
996 {
997         struct mfb_info *mfbi = info->par;
998         struct diu_ad *ad = mfbi->ad;
999         struct mfb_chroma_key ck;
1000         unsigned char global_alpha;
1001         struct aoi_display_offset aoi_d;
1002         __u32 pix_fmt;
1003         void __user *buf = (void __user *)arg;
1004
1005         if (!arg)
1006                 return -EINVAL;
1007         switch (cmd) {
1008         case MFB_SET_PIXFMT:
1009                 if (copy_from_user(&pix_fmt, buf, sizeof(pix_fmt)))
1010                         return -EFAULT;
1011                 ad->pix_fmt = pix_fmt;
1012                 pr_debug("Set pixel format to 0x%08x\n", ad->pix_fmt);
1013                 break;
1014         case MFB_GET_PIXFMT:
1015                 pix_fmt = ad->pix_fmt;
1016                 if (copy_to_user(buf, &pix_fmt, sizeof(pix_fmt)))
1017                         return -EFAULT;
1018                 pr_debug("get pixel format 0x%08x\n", ad->pix_fmt);
1019                 break;
1020         case MFB_SET_AOID:
1021                 if (copy_from_user(&aoi_d, buf, sizeof(aoi_d)))
1022                         return -EFAULT;
1023                 mfbi->x_aoi_d = aoi_d.x_aoi_d;
1024                 mfbi->y_aoi_d = aoi_d.y_aoi_d;
1025                 pr_debug("set AOI display offset of index %d to (%d,%d)\n",
1026                                  mfbi->index, aoi_d.x_aoi_d, aoi_d.y_aoi_d);
1027                 fsl_diu_check_var(&info->var, info);
1028                 fsl_diu_set_aoi(info);
1029                 break;
1030         case MFB_GET_AOID:
1031                 aoi_d.x_aoi_d = mfbi->x_aoi_d;
1032                 aoi_d.y_aoi_d = mfbi->y_aoi_d;
1033                 if (copy_to_user(buf, &aoi_d, sizeof(aoi_d)))
1034                         return -EFAULT;
1035                 pr_debug("get AOI display offset of index %d (%d,%d)\n",
1036                                 mfbi->index, aoi_d.x_aoi_d, aoi_d.y_aoi_d);
1037                 break;
1038         case MFB_GET_ALPHA:
1039                 global_alpha = mfbi->g_alpha;
1040                 if (copy_to_user(buf, &global_alpha, sizeof(global_alpha)))
1041                         return -EFAULT;
1042                 pr_debug("get global alpha of index %d\n", mfbi->index);
1043                 break;
1044         case MFB_SET_ALPHA:
1045                 /* set panel information */
1046                 if (copy_from_user(&global_alpha, buf, sizeof(global_alpha)))
1047                         return -EFAULT;
1048                 ad->src_size_g_alpha = (ad->src_size_g_alpha & (~0xff)) |
1049                                                         (global_alpha & 0xff);
1050                 mfbi->g_alpha = global_alpha;
1051                 pr_debug("set global alpha for index %d\n", mfbi->index);
1052                 break;
1053         case MFB_SET_CHROMA_KEY:
1054                 /* set panel winformation */
1055                 if (copy_from_user(&ck, buf, sizeof(ck)))
1056                         return -EFAULT;
1057
1058                 if (ck.enable &&
1059                    (ck.red_max < ck.red_min ||
1060                     ck.green_max < ck.green_min ||
1061                     ck.blue_max < ck.blue_min))
1062                         return -EINVAL;
1063
1064                 if (!ck.enable) {
1065                         ad->ckmax_r = 0;
1066                         ad->ckmax_g = 0;
1067                         ad->ckmax_b = 0;
1068                         ad->ckmin_r = 255;
1069                         ad->ckmin_g = 255;
1070                         ad->ckmin_b = 255;
1071                 } else {
1072                         ad->ckmax_r = ck.red_max;
1073                         ad->ckmax_g = ck.green_max;
1074                         ad->ckmax_b = ck.blue_max;
1075                         ad->ckmin_r = ck.red_min;
1076                         ad->ckmin_g = ck.green_min;
1077                         ad->ckmin_b = ck.blue_min;
1078                 }
1079                 pr_debug("set chroma key\n");
1080                 break;
1081         case FBIOGET_GWINFO:
1082                 if (mfbi->type == MFB_TYPE_OFF)
1083                         return -ENODEV;
1084                 /* get graphic window information */
1085                 if (copy_to_user(buf, ad, sizeof(*ad)))
1086                         return -EFAULT;
1087                 break;
1088         case FBIOGET_HWCINFO:
1089                 pr_debug("FBIOGET_HWCINFO:0x%08x\n", FBIOGET_HWCINFO);
1090                 break;
1091         case FBIOPUT_MODEINFO:
1092                 pr_debug("FBIOPUT_MODEINFO:0x%08x\n", FBIOPUT_MODEINFO);
1093                 break;
1094         case FBIOGET_DISPINFO:
1095                 pr_debug("FBIOGET_DISPINFO:0x%08x\n", FBIOGET_DISPINFO);
1096                 break;
1097
1098         default:
1099                 printk(KERN_ERR "Unknown ioctl command (0x%08X)\n", cmd);
1100                 return -ENOIOCTLCMD;
1101         }
1102
1103         return 0;
1104 }
1105
1106 /* turn on fb if count == 1
1107  */
1108 static int fsl_diu_open(struct fb_info *info, int user)
1109 {
1110         struct mfb_info *mfbi = info->par;
1111         int res = 0;
1112
1113         /* free boot splash memory on first /dev/fb0 open */
1114         if (!mfbi->index && diu_ops.release_bootmem)
1115                 diu_ops.release_bootmem();
1116
1117         spin_lock(&diu_lock);
1118         mfbi->count++;
1119         if (mfbi->count == 1) {
1120                 pr_debug("open plane index %d\n", mfbi->index);
1121                 fsl_diu_check_var(&info->var, info);
1122                 res = fsl_diu_set_par(info);
1123                 if (res < 0)
1124                         mfbi->count--;
1125                 else {
1126                         res = fsl_diu_enable_panel(info);
1127                         if (res < 0)
1128                                 mfbi->count--;
1129                 }
1130         }
1131
1132         spin_unlock(&diu_lock);
1133         return res;
1134 }
1135
1136 /* turn off fb if count == 0
1137  */
1138 static int fsl_diu_release(struct fb_info *info, int user)
1139 {
1140         struct mfb_info *mfbi = info->par;
1141         int res = 0;
1142
1143         spin_lock(&diu_lock);
1144         mfbi->count--;
1145         if (mfbi->count == 0) {
1146                 pr_debug("release plane index %d\n", mfbi->index);
1147                 res = fsl_diu_disable_panel(info);
1148                 if (res < 0)
1149                         mfbi->count++;
1150         }
1151         spin_unlock(&diu_lock);
1152         return res;
1153 }
1154
1155 static struct fb_ops fsl_diu_ops = {
1156         .owner = THIS_MODULE,
1157         .fb_check_var = fsl_diu_check_var,
1158         .fb_set_par = fsl_diu_set_par,
1159         .fb_setcolreg = fsl_diu_setcolreg,
1160         .fb_blank = fsl_diu_blank,
1161         .fb_pan_display = fsl_diu_pan_display,
1162         .fb_fillrect = cfb_fillrect,
1163         .fb_copyarea = cfb_copyarea,
1164         .fb_imageblit = cfb_imageblit,
1165         .fb_ioctl = fsl_diu_ioctl,
1166         .fb_open = fsl_diu_open,
1167         .fb_release = fsl_diu_release,
1168 };
1169
1170 static int init_fbinfo(struct fb_info *info)
1171 {
1172         struct mfb_info *mfbi = info->par;
1173
1174         info->device = NULL;
1175         info->var.activate = FB_ACTIVATE_NOW;
1176         info->fbops = &fsl_diu_ops;
1177         info->flags = FBINFO_FLAG_DEFAULT;
1178         info->pseudo_palette = &mfbi->pseudo_palette;
1179
1180         /* Allocate colormap */
1181         fb_alloc_cmap(&info->cmap, 16, 0);
1182         return 0;
1183 }
1184
1185 static int __devinit install_fb(struct fb_info *info)
1186 {
1187         int rc;
1188         struct mfb_info *mfbi = info->par;
1189         const char *aoi_mode, *init_aoi_mode = "320x240";
1190         struct fb_videomode *db = fsl_diu_mode_db;
1191         unsigned int dbsize = ARRAY_SIZE(fsl_diu_mode_db);
1192         int has_default_mode = 1;
1193
1194         if (init_fbinfo(info))
1195                 return -EINVAL;
1196
1197         if (mfbi->index == 0) { /* plane 0 */
1198                 if (mfbi->edid_data) {
1199                         /* Now build modedb from EDID */
1200                         fb_edid_to_monspecs(mfbi->edid_data, &info->monspecs);
1201                         fb_videomode_to_modelist(info->monspecs.modedb,
1202                                                  info->monspecs.modedb_len,
1203                                                  &info->modelist);
1204                         db = info->monspecs.modedb;
1205                         dbsize = info->monspecs.modedb_len;
1206                 }
1207                 aoi_mode = fb_mode;
1208         } else {
1209                 aoi_mode = init_aoi_mode;
1210         }
1211         pr_debug("mode used = %s\n", aoi_mode);
1212         rc = fb_find_mode(&info->var, info, aoi_mode, db, dbsize,
1213                           &fsl_diu_default_mode, default_bpp);
1214         switch (rc) {
1215         case 1:
1216                 pr_debug("using mode specified in @mode\n");
1217                 break;
1218         case 2:
1219                 pr_debug("using mode specified in @mode "
1220                         "with ignored refresh rate\n");
1221                 break;
1222         case 3:
1223                 pr_debug("using mode default mode\n");
1224                 break;
1225         case 4:
1226                 pr_debug("using mode from list\n");
1227                 break;
1228         default:
1229                 pr_debug("rc = %d\n", rc);
1230                 pr_debug("failed to find mode\n");
1231                 /*
1232                  * For plane 0 we continue and look into
1233                  * driver's internal modedb.
1234                  */
1235                 if (mfbi->index == 0 && mfbi->edid_data)
1236                         has_default_mode = 0;
1237                 else
1238                         return -EINVAL;
1239                 break;
1240         }
1241
1242         if (!has_default_mode) {
1243                 rc = fb_find_mode(&info->var, info, aoi_mode, fsl_diu_mode_db,
1244                                   ARRAY_SIZE(fsl_diu_mode_db),
1245                                   &fsl_diu_default_mode,
1246                                   default_bpp);
1247                 if (rc > 0 && rc < 5)
1248                         has_default_mode = 1;
1249         }
1250
1251         /* Still not found, use preferred mode from database if any */
1252         if (!has_default_mode && info->monspecs.modedb) {
1253                 struct fb_monspecs *specs = &info->monspecs;
1254                 struct fb_videomode *modedb = &specs->modedb[0];
1255
1256                 /*
1257                  * Get preferred timing. If not found,
1258                  * first mode in database will be used.
1259                  */
1260                 if (specs->misc & FB_MISC_1ST_DETAIL) {
1261                         int i;
1262
1263                         for (i = 0; i < specs->modedb_len; i++) {
1264                                 if (specs->modedb[i].flag & FB_MODE_IS_FIRST) {
1265                                         modedb = &specs->modedb[i];
1266                                         break;
1267                                 }
1268                         }
1269                 }
1270
1271                 info->var.bits_per_pixel = default_bpp;
1272                 fb_videomode_to_var(&info->var, modedb);
1273         }
1274
1275         pr_debug("xres_virtual %d\n", info->var.xres_virtual);
1276         pr_debug("bits_per_pixel %d\n", info->var.bits_per_pixel);
1277
1278         pr_debug("info->var.yres_virtual = %d\n", info->var.yres_virtual);
1279         pr_debug("info->fix.line_length = %d\n", info->fix.line_length);
1280
1281         if (mfbi->type == MFB_TYPE_OFF)
1282                 mfbi->blank = FB_BLANK_NORMAL;
1283         else
1284                 mfbi->blank = FB_BLANK_UNBLANK;
1285
1286         if (fsl_diu_check_var(&info->var, info)) {
1287                 printk(KERN_ERR "fb_check_var failed");
1288                 fb_dealloc_cmap(&info->cmap);
1289                 return -EINVAL;
1290         }
1291
1292         if (register_framebuffer(info) < 0) {
1293                 printk(KERN_ERR "register_framebuffer failed");
1294                 unmap_video_memory(info);
1295                 fb_dealloc_cmap(&info->cmap);
1296                 return -EINVAL;
1297         }
1298
1299         mfbi->registered = 1;
1300         printk(KERN_INFO "fb%d: %s fb device registered successfully.\n",
1301                  info->node, info->fix.id);
1302
1303         return 0;
1304 }
1305
1306 static void uninstall_fb(struct fb_info *info)
1307 {
1308         struct mfb_info *mfbi = info->par;
1309
1310         if (!mfbi->registered)
1311                 return;
1312
1313         if (mfbi->index == 0)
1314                 kfree(mfbi->edid_data);
1315
1316         unregister_framebuffer(info);
1317         unmap_video_memory(info);
1318         if (&info->cmap)
1319                 fb_dealloc_cmap(&info->cmap);
1320
1321         mfbi->registered = 0;
1322 }
1323
1324 static irqreturn_t fsl_diu_isr(int irq, void *dev_id)
1325 {
1326         struct diu *hw = dr.diu_reg;
1327         unsigned int status = in_be32(&hw->int_status);
1328
1329         if (status) {
1330                 /* This is the workaround for underrun */
1331                 if (status & INT_UNDRUN) {
1332                         out_be32(&hw->diu_mode, 0);
1333                         pr_debug("Err: DIU occurs underrun!\n");
1334                         udelay(1);
1335                         out_be32(&hw->diu_mode, 1);
1336                 }
1337 #if defined(CONFIG_NOT_COHERENT_CACHE)
1338                 else if (status & INT_VSYNC) {
1339                         unsigned int i;
1340                         for (i = 0; i < coherence_data_size;
1341                                 i += d_cache_line_size)
1342                                 __asm__ __volatile__ (
1343                                         "dcbz 0, %[input]"
1344                                 ::[input]"r"(&coherence_data[i]));
1345                 }
1346 #endif
1347                 return IRQ_HANDLED;
1348         }
1349         return IRQ_NONE;
1350 }
1351
1352 static int request_irq_local(int irq)
1353 {
1354         unsigned long status, ints;
1355         struct diu *hw;
1356         int ret;
1357
1358         hw = dr.diu_reg;
1359
1360         /* Read to clear the status */
1361         status = in_be32(&hw->int_status);
1362
1363         ret = request_irq(irq, fsl_diu_isr, 0, "diu", NULL);
1364         if (ret)
1365                 pr_info("Request diu IRQ failed.\n");
1366         else {
1367                 ints = INT_PARERR | INT_LS_BF_VS;
1368 #if !defined(CONFIG_NOT_COHERENT_CACHE)
1369                 ints |= INT_VSYNC;
1370 #endif
1371                 if (dr.mode == MFB_MODE2 || dr.mode == MFB_MODE3)
1372                         ints |= INT_VSYNC_WB;
1373
1374                 /* Read to clear the status */
1375                 status = in_be32(&hw->int_status);
1376                 out_be32(&hw->int_mask, ints);
1377         }
1378         return ret;
1379 }
1380
1381 static void free_irq_local(int irq)
1382 {
1383         struct diu *hw = dr.diu_reg;
1384
1385         /* Disable all LCDC interrupt */
1386         out_be32(&hw->int_mask, 0x1f);
1387
1388         free_irq(irq, NULL);
1389 }
1390
1391 #ifdef CONFIG_PM
1392 /*
1393  * Power management hooks. Note that we won't be called from IRQ context,
1394  * unlike the blank functions above, so we may sleep.
1395  */
1396 static int fsl_diu_suspend(struct of_device *ofdev, pm_message_t state)
1397 {
1398         struct fsl_diu_data *machine_data;
1399
1400         machine_data = dev_get_drvdata(&ofdev->dev);
1401         disable_lcdc(machine_data->fsl_diu_info[0]);
1402
1403         return 0;
1404 }
1405
1406 static int fsl_diu_resume(struct of_device *ofdev)
1407 {
1408         struct fsl_diu_data *machine_data;
1409
1410         machine_data = dev_get_drvdata(&ofdev->dev);
1411         enable_lcdc(machine_data->fsl_diu_info[0]);
1412
1413         return 0;
1414 }
1415
1416 #else
1417 #define fsl_diu_suspend NULL
1418 #define fsl_diu_resume NULL
1419 #endif                          /* CONFIG_PM */
1420
1421 /* Align to 64-bit(8-byte), 32-byte, etc. */
1422 static int allocate_buf(struct device *dev, struct diu_addr *buf, u32 size,
1423                         u32 bytes_align)
1424 {
1425         u32 offset, ssize;
1426         u32 mask;
1427         dma_addr_t paddr = 0;
1428
1429         ssize = size + bytes_align;
1430         buf->vaddr = dma_alloc_coherent(dev, ssize, &paddr, GFP_DMA |
1431                                                              __GFP_ZERO);
1432         if (!buf->vaddr)
1433                 return -ENOMEM;
1434
1435         buf->paddr = (__u32) paddr;
1436
1437         mask = bytes_align - 1;
1438         offset = (u32)buf->paddr & mask;
1439         if (offset) {
1440                 buf->offset = bytes_align - offset;
1441                 buf->paddr = (u32)buf->paddr + offset;
1442         } else
1443                 buf->offset = 0;
1444         return 0;
1445 }
1446
1447 static void free_buf(struct device *dev, struct diu_addr *buf, u32 size,
1448                      u32 bytes_align)
1449 {
1450         dma_free_coherent(dev, size + bytes_align,
1451                                 buf->vaddr, (buf->paddr - buf->offset));
1452         return;
1453 }
1454
1455 static ssize_t store_monitor(struct device *device,
1456         struct device_attribute *attr, const char *buf, size_t count)
1457 {
1458         int old_monitor_port;
1459         unsigned long val;
1460         struct fsl_diu_data *machine_data =
1461                 container_of(attr, struct fsl_diu_data, dev_attr);
1462
1463         if (strict_strtoul(buf, 10, &val))
1464                 return 0;
1465
1466         old_monitor_port = machine_data->monitor_port;
1467         machine_data->monitor_port = diu_ops.set_sysfs_monitor_port(val);
1468
1469         if (old_monitor_port != machine_data->monitor_port) {
1470                 /* All AOIs need adjust pixel format
1471                  * fsl_diu_set_par only change the pixsel format here
1472                  * unlikely to fail. */
1473                 fsl_diu_set_par(machine_data->fsl_diu_info[0]);
1474                 fsl_diu_set_par(machine_data->fsl_diu_info[1]);
1475                 fsl_diu_set_par(machine_data->fsl_diu_info[2]);
1476                 fsl_diu_set_par(machine_data->fsl_diu_info[3]);
1477                 fsl_diu_set_par(machine_data->fsl_diu_info[4]);
1478         }
1479         return count;
1480 }
1481
1482 static ssize_t show_monitor(struct device *device,
1483         struct device_attribute *attr, char *buf)
1484 {
1485         struct fsl_diu_data *machine_data =
1486                 container_of(attr, struct fsl_diu_data, dev_attr);
1487         return diu_ops.show_monitor_port(machine_data->monitor_port, buf);
1488 }
1489
1490 static int __devinit fsl_diu_probe(struct of_device *ofdev,
1491         const struct of_device_id *match)
1492 {
1493         struct device_node *np = ofdev->dev.of_node;
1494         struct mfb_info *mfbi;
1495         phys_addr_t dummy_ad_addr;
1496         int ret, i, error = 0;
1497         struct resource res;
1498         struct fsl_diu_data *machine_data;
1499         int diu_mode;
1500
1501         machine_data = kzalloc(sizeof(struct fsl_diu_data), GFP_KERNEL);
1502         if (!machine_data)
1503                 return -ENOMEM;
1504
1505         for (i = 0; i < ARRAY_SIZE(machine_data->fsl_diu_info); i++) {
1506                 machine_data->fsl_diu_info[i] =
1507                         framebuffer_alloc(sizeof(struct mfb_info), &ofdev->dev);
1508                 if (!machine_data->fsl_diu_info[i]) {
1509                         dev_err(&ofdev->dev, "cannot allocate memory\n");
1510                         ret = -ENOMEM;
1511                         goto error2;
1512                 }
1513                 mfbi = machine_data->fsl_diu_info[i]->par;
1514                 memcpy(mfbi, &mfb_template[i], sizeof(struct mfb_info));
1515                 mfbi->parent = machine_data;
1516
1517                 if (mfbi->index == 0) {
1518                         const u8 *prop;
1519                         int len;
1520
1521                         /* Get EDID */
1522                         prop = of_get_property(np, "edid", &len);
1523                         if (prop && len == EDID_LENGTH)
1524                                 mfbi->edid_data = kmemdup(prop, EDID_LENGTH,
1525                                                           GFP_KERNEL);
1526                 }
1527         }
1528
1529         ret = of_address_to_resource(np, 0, &res);
1530         if (ret) {
1531                 dev_err(&ofdev->dev, "could not obtain DIU address\n");
1532                 goto error;
1533         }
1534         if (!res.start) {
1535                 dev_err(&ofdev->dev, "invalid DIU address\n");
1536                 goto error;
1537         }
1538         dev_dbg(&ofdev->dev, "%s, res.start: 0x%08x\n", __func__, res.start);
1539
1540         dr.diu_reg = ioremap(res.start, sizeof(struct diu));
1541         if (!dr.diu_reg) {
1542                 dev_err(&ofdev->dev, "Err: can't map DIU registers!\n");
1543                 ret = -EFAULT;
1544                 goto error2;
1545         }
1546
1547         diu_mode = in_be32(&dr.diu_reg->diu_mode);
1548         if (diu_mode != MFB_MODE1)
1549                 out_be32(&dr.diu_reg->diu_mode, 0);     /* disable DIU */
1550
1551         /* Get the IRQ of the DIU */
1552         machine_data->irq = irq_of_parse_and_map(np, 0);
1553
1554         if (!machine_data->irq) {
1555                 dev_err(&ofdev->dev, "could not get DIU IRQ\n");
1556                 ret = -EINVAL;
1557                 goto error;
1558         }
1559         machine_data->monitor_port = monitor_port;
1560
1561         /* Area descriptor memory pool aligns to 64-bit boundary */
1562         if (allocate_buf(&ofdev->dev, &pool.ad,
1563                          sizeof(struct diu_ad) * FSL_AOI_NUM, 8))
1564                 return -ENOMEM;
1565
1566         /* Get memory for Gamma Table  - 32-byte aligned memory */
1567         if (allocate_buf(&ofdev->dev, &pool.gamma, 768, 32)) {
1568                 ret = -ENOMEM;
1569                 goto error;
1570         }
1571
1572         /* For performance, cursor bitmap buffer aligns to 32-byte boundary */
1573         if (allocate_buf(&ofdev->dev, &pool.cursor, MAX_CURS * MAX_CURS * 2,
1574                          32)) {
1575                 ret = -ENOMEM;
1576                 goto error;
1577         }
1578
1579         i = ARRAY_SIZE(machine_data->fsl_diu_info);
1580         machine_data->dummy_ad = (struct diu_ad *)
1581                         ((u32)pool.ad.vaddr + pool.ad.offset) + i;
1582         machine_data->dummy_ad->paddr = pool.ad.paddr +
1583                         i * sizeof(struct diu_ad);
1584         machine_data->dummy_aoi_virt = fsl_diu_alloc(64, &dummy_ad_addr);
1585         if (!machine_data->dummy_aoi_virt) {
1586                 ret = -ENOMEM;
1587                 goto error;
1588         }
1589         machine_data->dummy_ad->addr = cpu_to_le32(dummy_ad_addr);
1590         machine_data->dummy_ad->pix_fmt = 0x88882317;
1591         machine_data->dummy_ad->src_size_g_alpha = cpu_to_le32((4 << 12) | 4);
1592         machine_data->dummy_ad->aoi_size = cpu_to_le32((4 << 16) |  2);
1593         machine_data->dummy_ad->offset_xyi = 0;
1594         machine_data->dummy_ad->offset_xyd = 0;
1595         machine_data->dummy_ad->next_ad = 0;
1596
1597         /*
1598          * Let DIU display splash screen if it was pre-initialized
1599          * by the bootloader, set dummy area descriptor otherwise.
1600          */
1601         if (diu_mode != MFB_MODE1)
1602                 out_be32(&dr.diu_reg->desc[0], machine_data->dummy_ad->paddr);
1603
1604         out_be32(&dr.diu_reg->desc[1], machine_data->dummy_ad->paddr);
1605         out_be32(&dr.diu_reg->desc[2], machine_data->dummy_ad->paddr);
1606
1607         for (i = 0; i < ARRAY_SIZE(machine_data->fsl_diu_info); i++) {
1608                 machine_data->fsl_diu_info[i]->fix.smem_start = 0;
1609                 mfbi = machine_data->fsl_diu_info[i]->par;
1610                 mfbi->ad = (struct diu_ad *)((u32)pool.ad.vaddr
1611                                         + pool.ad.offset) + i;
1612                 mfbi->ad->paddr = pool.ad.paddr + i * sizeof(struct diu_ad);
1613                 ret = install_fb(machine_data->fsl_diu_info[i]);
1614                 if (ret) {
1615                         dev_err(&ofdev->dev,
1616                                 "Failed to register framebuffer %d\n",
1617                                 i);
1618                         goto error;
1619                 }
1620         }
1621
1622         if (request_irq_local(machine_data->irq)) {
1623                 dev_err(machine_data->fsl_diu_info[0]->dev,
1624                         "could not request irq for diu.");
1625                 goto error;
1626         }
1627
1628         sysfs_attr_init(&machine_data->dev_attr.attr);
1629         machine_data->dev_attr.attr.name = "monitor";
1630         machine_data->dev_attr.attr.mode = S_IRUGO|S_IWUSR;
1631         machine_data->dev_attr.show = show_monitor;
1632         machine_data->dev_attr.store = store_monitor;
1633         error = device_create_file(machine_data->fsl_diu_info[0]->dev,
1634                                   &machine_data->dev_attr);
1635         if (error) {
1636                 dev_err(machine_data->fsl_diu_info[0]->dev,
1637                         "could not create sysfs %s file\n",
1638                         machine_data->dev_attr.attr.name);
1639         }
1640
1641         dev_set_drvdata(&ofdev->dev, machine_data);
1642         return 0;
1643
1644 error:
1645         for (i = ARRAY_SIZE(machine_data->fsl_diu_info);
1646                 i > 0; i--)
1647                 uninstall_fb(machine_data->fsl_diu_info[i - 1]);
1648         if (pool.ad.vaddr)
1649                 free_buf(&ofdev->dev, &pool.ad,
1650                          sizeof(struct diu_ad) * FSL_AOI_NUM, 8);
1651         if (pool.gamma.vaddr)
1652                 free_buf(&ofdev->dev, &pool.gamma, 768, 32);
1653         if (pool.cursor.vaddr)
1654                 free_buf(&ofdev->dev, &pool.cursor, MAX_CURS * MAX_CURS * 2,
1655                          32);
1656         if (machine_data->dummy_aoi_virt)
1657                 fsl_diu_free(machine_data->dummy_aoi_virt, 64);
1658         iounmap(dr.diu_reg);
1659
1660 error2:
1661         for (i = 0; i < ARRAY_SIZE(machine_data->fsl_diu_info); i++)
1662                 if (machine_data->fsl_diu_info[i])
1663                         framebuffer_release(machine_data->fsl_diu_info[i]);
1664         kfree(machine_data);
1665
1666         return ret;
1667 }
1668
1669
1670 static int fsl_diu_remove(struct of_device *ofdev)
1671 {
1672         struct fsl_diu_data *machine_data;
1673         int i;
1674
1675         machine_data = dev_get_drvdata(&ofdev->dev);
1676         disable_lcdc(machine_data->fsl_diu_info[0]);
1677         free_irq_local(machine_data->irq);
1678         for (i = ARRAY_SIZE(machine_data->fsl_diu_info); i > 0; i--)
1679                 uninstall_fb(machine_data->fsl_diu_info[i - 1]);
1680         if (pool.ad.vaddr)
1681                 free_buf(&ofdev->dev, &pool.ad,
1682                          sizeof(struct diu_ad) * FSL_AOI_NUM, 8);
1683         if (pool.gamma.vaddr)
1684                 free_buf(&ofdev->dev, &pool.gamma, 768, 32);
1685         if (pool.cursor.vaddr)
1686                 free_buf(&ofdev->dev, &pool.cursor, MAX_CURS * MAX_CURS * 2,
1687                          32);
1688         if (machine_data->dummy_aoi_virt)
1689                 fsl_diu_free(machine_data->dummy_aoi_virt, 64);
1690         iounmap(dr.diu_reg);
1691         for (i = 0; i < ARRAY_SIZE(machine_data->fsl_diu_info); i++)
1692                 if (machine_data->fsl_diu_info[i])
1693                         framebuffer_release(machine_data->fsl_diu_info[i]);
1694         kfree(machine_data);
1695
1696         return 0;
1697 }
1698
1699 #ifndef MODULE
1700 static int __init fsl_diu_setup(char *options)
1701 {
1702         char *opt;
1703         unsigned long val;
1704
1705         if (!options || !*options)
1706                 return 0;
1707
1708         while ((opt = strsep(&options, ",")) != NULL) {
1709                 if (!*opt)
1710                         continue;
1711                 if (!strncmp(opt, "monitor=", 8)) {
1712                         if (!strict_strtoul(opt + 8, 10, &val) && (val <= 2))
1713                                 monitor_port = val;
1714                 } else if (!strncmp(opt, "bpp=", 4)) {
1715                         if (!strict_strtoul(opt + 4, 10, &val))
1716                                 default_bpp = val;
1717                 } else
1718                         fb_mode = opt;
1719         }
1720
1721         return 0;
1722 }
1723 #endif
1724
1725 static struct of_device_id fsl_diu_match[] = {
1726 #ifdef CONFIG_PPC_MPC512x
1727         {
1728                 .compatible = "fsl,mpc5121-diu",
1729         },
1730 #endif
1731         {
1732                 .compatible = "fsl,diu",
1733         },
1734         {}
1735 };
1736 MODULE_DEVICE_TABLE(of, fsl_diu_match);
1737
1738 static struct of_platform_driver fsl_diu_driver = {
1739         .driver = {
1740                 .name = "fsl_diu",
1741                 .owner = THIS_MODULE,
1742                 .of_match_table = fsl_diu_match,
1743         },
1744         .probe          = fsl_diu_probe,
1745         .remove         = fsl_diu_remove,
1746         .suspend        = fsl_diu_suspend,
1747         .resume         = fsl_diu_resume,
1748 };
1749
1750 static int __init fsl_diu_init(void)
1751 {
1752 #ifdef CONFIG_NOT_COHERENT_CACHE
1753         struct device_node *np;
1754         const u32 *prop;
1755 #endif
1756         int ret;
1757 #ifndef MODULE
1758         char *option;
1759
1760         /*
1761          * For kernel boot options (in 'video=xxxfb:<options>' format)
1762          */
1763         if (fb_get_options("fslfb", &option))
1764                 return -ENODEV;
1765         fsl_diu_setup(option);
1766 #endif
1767         printk(KERN_INFO "Freescale DIU driver\n");
1768
1769 #ifdef CONFIG_NOT_COHERENT_CACHE
1770         np = of_find_node_by_type(NULL, "cpu");
1771         if (!np) {
1772                 printk(KERN_ERR "Err: can't find device node 'cpu'\n");
1773                 return -ENODEV;
1774         }
1775
1776         prop = of_get_property(np, "d-cache-size", NULL);
1777         if (prop == NULL) {
1778                 of_node_put(np);
1779                 return -ENODEV;
1780         }
1781
1782         /* Freescale PLRU requires 13/8 times the cache size to do a proper
1783            displacement flush
1784          */
1785         coherence_data_size = *prop * 13;
1786         coherence_data_size /= 8;
1787
1788         prop = of_get_property(np, "d-cache-line-size", NULL);
1789         if (prop == NULL) {
1790                 of_node_put(np);
1791                 return -ENODEV;
1792         }
1793         d_cache_line_size = *prop;
1794
1795         of_node_put(np);
1796         coherence_data = vmalloc(coherence_data_size);
1797         if (!coherence_data)
1798                 return -ENOMEM;
1799 #endif
1800         ret = of_register_platform_driver(&fsl_diu_driver);
1801         if (ret) {
1802                 printk(KERN_ERR
1803                         "fsl-diu: failed to register platform driver\n");
1804 #if defined(CONFIG_NOT_COHERENT_CACHE)
1805                 vfree(coherence_data);
1806 #endif
1807                 iounmap(dr.diu_reg);
1808         }
1809         return ret;
1810 }
1811
1812 static void __exit fsl_diu_exit(void)
1813 {
1814         of_unregister_platform_driver(&fsl_diu_driver);
1815 #if defined(CONFIG_NOT_COHERENT_CACHE)
1816         vfree(coherence_data);
1817 #endif
1818 }
1819
1820 module_init(fsl_diu_init);
1821 module_exit(fsl_diu_exit);
1822
1823 MODULE_AUTHOR("York Sun <yorksun@freescale.com>");
1824 MODULE_DESCRIPTION("Freescale DIU framebuffer driver");
1825 MODULE_LICENSE("GPL");
1826
1827 module_param_named(mode, fb_mode, charp, 0);
1828 MODULE_PARM_DESC(mode,
1829         "Specify resolution as \"<xres>x<yres>[-<bpp>][@<refresh>]\" ");
1830 module_param_named(bpp, default_bpp, ulong, 0);
1831 MODULE_PARM_DESC(bpp, "Specify bit-per-pixel if not specified mode");
1832 module_param_named(monitor, monitor_port, int, 0);
1833 MODULE_PARM_DESC(monitor,
1834         "Specify the monitor port (0, 1 or 2) if supported by the platform");
1835