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