drivers/video: fsl-diu-fb: clean up whitespace and formatting
[pandora-kernel.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 int regno, unsigned int red,
903                              unsigned int green, unsigned int blue,
904                              unsigned int transp, struct fb_info *info)
905 {
906         int ret = 1;
907
908         /*
909          * If greyscale is true, then we convert the RGB value
910          * to greyscale no matter what visual we are using.
911          */
912         if (info->var.grayscale)
913                 red = green = blue = (19595 * red + 38470 * green +
914                                       7471 * blue) >> 16;
915         switch (info->fix.visual) {
916         case FB_VISUAL_TRUECOLOR:
917                 /*
918                  * 16-bit True Colour.  We encode the RGB value
919                  * according to the RGB bitfield information.
920                  */
921                 if (regno < 16) {
922                         u32 *pal = info->pseudo_palette;
923                         u32 v;
924
925                         red = CNVT_TOHW(red, info->var.red.length);
926                         green = CNVT_TOHW(green, info->var.green.length);
927                         blue = CNVT_TOHW(blue, info->var.blue.length);
928                         transp = CNVT_TOHW(transp, info->var.transp.length);
929
930                         v = (red << info->var.red.offset) |
931                             (green << info->var.green.offset) |
932                             (blue << info->var.blue.offset) |
933                             (transp << info->var.transp.offset);
934
935                         pal[regno] = v;
936                         ret = 0;
937                 }
938                 break;
939         case FB_VISUAL_STATIC_PSEUDOCOLOR:
940         case FB_VISUAL_PSEUDOCOLOR:
941                 break;
942         }
943
944         return ret;
945 }
946
947 /*
948  * Pan (or wrap, depending on the `vmode' field) the display using the
949  * 'xoffset' and 'yoffset' fields of the 'var' structure. If the values
950  * don't fit, return -EINVAL.
951  */
952 static int fsl_diu_pan_display(struct fb_var_screeninfo *var,
953                              struct fb_info *info)
954 {
955         if ((info->var.xoffset == var->xoffset) &&
956             (info->var.yoffset == var->yoffset))
957                 return 0;       /* No change, do nothing */
958
959         if (var->xoffset < 0 || var->yoffset < 0
960             || var->xoffset + info->var.xres > info->var.xres_virtual
961             || var->yoffset + info->var.yres > info->var.yres_virtual)
962                 return -EINVAL;
963
964         info->var.xoffset = var->xoffset;
965         info->var.yoffset = var->yoffset;
966
967         if (var->vmode & FB_VMODE_YWRAP)
968                 info->var.vmode |= FB_VMODE_YWRAP;
969         else
970                 info->var.vmode &= ~FB_VMODE_YWRAP;
971
972         fsl_diu_set_aoi(info);
973
974         return 0;
975 }
976
977 /*
978  * Blank the screen if blank_mode != 0, else unblank. Return 0 if blanking
979  * succeeded, != 0 if un-/blanking failed.
980  * blank_mode == 2: suspend vsync
981  * blank_mode == 3: suspend hsync
982  * blank_mode == 4: powerdown
983  */
984 static int fsl_diu_blank(int blank_mode, struct fb_info *info)
985 {
986         struct mfb_info *mfbi = info->par;
987
988         mfbi->blank = blank_mode;
989
990         switch (blank_mode) {
991         case FB_BLANK_VSYNC_SUSPEND:
992         case FB_BLANK_HSYNC_SUSPEND:
993         /* FIXME: fixes to enable_panel and enable lcdc needed */
994         case FB_BLANK_NORMAL:
995         /*      fsl_diu_disable_panel(info);*/
996                 break;
997         case FB_BLANK_POWERDOWN:
998         /*      disable_lcdc(info);     */
999                 break;
1000         case FB_BLANK_UNBLANK:
1001         /*      fsl_diu_enable_panel(info);*/
1002                 break;
1003         }
1004
1005         return 0;
1006 }
1007
1008 static int fsl_diu_ioctl(struct fb_info *info, unsigned int cmd,
1009                        unsigned long arg)
1010 {
1011         struct mfb_info *mfbi = info->par;
1012         struct diu_ad *ad = mfbi->ad;
1013         struct mfb_chroma_key ck;
1014         unsigned char global_alpha;
1015         struct aoi_display_offset aoi_d;
1016         __u32 pix_fmt;
1017         void __user *buf = (void __user *)arg;
1018
1019         if (!arg)
1020                 return -EINVAL;
1021         switch (cmd) {
1022         case MFB_SET_PIXFMT:
1023                 if (copy_from_user(&pix_fmt, buf, sizeof(pix_fmt)))
1024                         return -EFAULT;
1025                 ad->pix_fmt = pix_fmt;
1026                 pr_debug("Set pixel format to 0x%08x\n", ad->pix_fmt);
1027                 break;
1028         case MFB_GET_PIXFMT:
1029                 pix_fmt = ad->pix_fmt;
1030                 if (copy_to_user(buf, &pix_fmt, sizeof(pix_fmt)))
1031                         return -EFAULT;
1032                 pr_debug("get pixel format 0x%08x\n", ad->pix_fmt);
1033                 break;
1034         case MFB_SET_AOID:
1035                 if (copy_from_user(&aoi_d, buf, sizeof(aoi_d)))
1036                         return -EFAULT;
1037                 mfbi->x_aoi_d = aoi_d.x_aoi_d;
1038                 mfbi->y_aoi_d = aoi_d.y_aoi_d;
1039                 pr_debug("set AOI display offset of index %d to (%d,%d)\n",
1040                                  mfbi->index, aoi_d.x_aoi_d, aoi_d.y_aoi_d);
1041                 fsl_diu_check_var(&info->var, info);
1042                 fsl_diu_set_aoi(info);
1043                 break;
1044         case MFB_GET_AOID:
1045                 aoi_d.x_aoi_d = mfbi->x_aoi_d;
1046                 aoi_d.y_aoi_d = mfbi->y_aoi_d;
1047                 if (copy_to_user(buf, &aoi_d, sizeof(aoi_d)))
1048                         return -EFAULT;
1049                 pr_debug("get AOI display offset of index %d (%d,%d)\n",
1050                                 mfbi->index, aoi_d.x_aoi_d, aoi_d.y_aoi_d);
1051                 break;
1052         case MFB_GET_ALPHA:
1053                 global_alpha = mfbi->g_alpha;
1054                 if (copy_to_user(buf, &global_alpha, sizeof(global_alpha)))
1055                         return -EFAULT;
1056                 pr_debug("get global alpha of index %d\n", mfbi->index);
1057                 break;
1058         case MFB_SET_ALPHA:
1059                 /* set panel information */
1060                 if (copy_from_user(&global_alpha, buf, sizeof(global_alpha)))
1061                         return -EFAULT;
1062                 ad->src_size_g_alpha = (ad->src_size_g_alpha & (~0xff)) |
1063                                                         (global_alpha & 0xff);
1064                 mfbi->g_alpha = global_alpha;
1065                 pr_debug("set global alpha for index %d\n", mfbi->index);
1066                 break;
1067         case MFB_SET_CHROMA_KEY:
1068                 /* set panel winformation */
1069                 if (copy_from_user(&ck, buf, sizeof(ck)))
1070                         return -EFAULT;
1071
1072                 if (ck.enable &&
1073                    (ck.red_max < ck.red_min ||
1074                     ck.green_max < ck.green_min ||
1075                     ck.blue_max < ck.blue_min))
1076                         return -EINVAL;
1077
1078                 if (!ck.enable) {
1079                         ad->ckmax_r = 0;
1080                         ad->ckmax_g = 0;
1081                         ad->ckmax_b = 0;
1082                         ad->ckmin_r = 255;
1083                         ad->ckmin_g = 255;
1084                         ad->ckmin_b = 255;
1085                 } else {
1086                         ad->ckmax_r = ck.red_max;
1087                         ad->ckmax_g = ck.green_max;
1088                         ad->ckmax_b = ck.blue_max;
1089                         ad->ckmin_r = ck.red_min;
1090                         ad->ckmin_g = ck.green_min;
1091                         ad->ckmin_b = ck.blue_min;
1092                 }
1093                 pr_debug("set chroma key\n");
1094                 break;
1095         case FBIOGET_GWINFO:
1096                 if (mfbi->type == MFB_TYPE_OFF)
1097                         return -ENODEV;
1098                 /* get graphic window information */
1099                 if (copy_to_user(buf, ad, sizeof(*ad)))
1100                         return -EFAULT;
1101                 break;
1102         case FBIOGET_HWCINFO:
1103                 pr_debug("FBIOGET_HWCINFO:0x%08x\n", FBIOGET_HWCINFO);
1104                 break;
1105         case FBIOPUT_MODEINFO:
1106                 pr_debug("FBIOPUT_MODEINFO:0x%08x\n", FBIOPUT_MODEINFO);
1107                 break;
1108         case FBIOGET_DISPINFO:
1109                 pr_debug("FBIOGET_DISPINFO:0x%08x\n", FBIOGET_DISPINFO);
1110                 break;
1111
1112         default:
1113                 printk(KERN_ERR "Unknown ioctl command (0x%08X)\n", cmd);
1114                 return -ENOIOCTLCMD;
1115         }
1116
1117         return 0;
1118 }
1119
1120 /* turn on fb if count == 1
1121  */
1122 static int fsl_diu_open(struct fb_info *info, int user)
1123 {
1124         struct mfb_info *mfbi = info->par;
1125         int res = 0;
1126
1127         /* free boot splash memory on first /dev/fb0 open */
1128         if (!mfbi->index && diu_ops.release_bootmem)
1129                 diu_ops.release_bootmem();
1130
1131         spin_lock(&diu_lock);
1132         mfbi->count++;
1133         if (mfbi->count == 1) {
1134                 pr_debug("open plane index %d\n", mfbi->index);
1135                 fsl_diu_check_var(&info->var, info);
1136                 res = fsl_diu_set_par(info);
1137                 if (res < 0)
1138                         mfbi->count--;
1139                 else {
1140                         res = fsl_diu_enable_panel(info);
1141                         if (res < 0)
1142                                 mfbi->count--;
1143                 }
1144         }
1145
1146         spin_unlock(&diu_lock);
1147         return res;
1148 }
1149
1150 /* turn off fb if count == 0
1151  */
1152 static int fsl_diu_release(struct fb_info *info, int user)
1153 {
1154         struct mfb_info *mfbi = info->par;
1155         int res = 0;
1156
1157         spin_lock(&diu_lock);
1158         mfbi->count--;
1159         if (mfbi->count == 0) {
1160                 pr_debug("release plane index %d\n", mfbi->index);
1161                 res = fsl_diu_disable_panel(info);
1162                 if (res < 0)
1163                         mfbi->count++;
1164         }
1165         spin_unlock(&diu_lock);
1166         return res;
1167 }
1168
1169 static struct fb_ops fsl_diu_ops = {
1170         .owner = THIS_MODULE,
1171         .fb_check_var = fsl_diu_check_var,
1172         .fb_set_par = fsl_diu_set_par,
1173         .fb_setcolreg = fsl_diu_setcolreg,
1174         .fb_blank = fsl_diu_blank,
1175         .fb_pan_display = fsl_diu_pan_display,
1176         .fb_fillrect = cfb_fillrect,
1177         .fb_copyarea = cfb_copyarea,
1178         .fb_imageblit = cfb_imageblit,
1179         .fb_ioctl = fsl_diu_ioctl,
1180         .fb_open = fsl_diu_open,
1181         .fb_release = fsl_diu_release,
1182 };
1183
1184 static int init_fbinfo(struct fb_info *info)
1185 {
1186         struct mfb_info *mfbi = info->par;
1187
1188         info->device = NULL;
1189         info->var.activate = FB_ACTIVATE_NOW;
1190         info->fbops = &fsl_diu_ops;
1191         info->flags = FBINFO_FLAG_DEFAULT;
1192         info->pseudo_palette = &mfbi->pseudo_palette;
1193
1194         /* Allocate colormap */
1195         fb_alloc_cmap(&info->cmap, 16, 0);
1196         return 0;
1197 }
1198
1199 static int __devinit install_fb(struct fb_info *info)
1200 {
1201         int rc;
1202         struct mfb_info *mfbi = info->par;
1203         const char *aoi_mode, *init_aoi_mode = "320x240";
1204         struct fb_videomode *db = fsl_diu_mode_db;
1205         unsigned int dbsize = ARRAY_SIZE(fsl_diu_mode_db);
1206         int has_default_mode = 1;
1207
1208         if (init_fbinfo(info))
1209                 return -EINVAL;
1210
1211         if (mfbi->index == 0) { /* plane 0 */
1212                 if (mfbi->edid_data) {
1213                         /* Now build modedb from EDID */
1214                         fb_edid_to_monspecs(mfbi->edid_data, &info->monspecs);
1215                         fb_videomode_to_modelist(info->monspecs.modedb,
1216                                                  info->monspecs.modedb_len,
1217                                                  &info->modelist);
1218                         db = info->monspecs.modedb;
1219                         dbsize = info->monspecs.modedb_len;
1220                 }
1221                 aoi_mode = fb_mode;
1222         } else {
1223                 aoi_mode = init_aoi_mode;
1224         }
1225         pr_debug("mode used = %s\n", aoi_mode);
1226         rc = fb_find_mode(&info->var, info, aoi_mode, db, dbsize,
1227                           &fsl_diu_default_mode, default_bpp);
1228         switch (rc) {
1229         case 1:
1230                 pr_debug("using mode specified in @mode\n");
1231                 break;
1232         case 2:
1233                 pr_debug("using mode specified in @mode "
1234                         "with ignored refresh rate\n");
1235                 break;
1236         case 3:
1237                 pr_debug("using mode default mode\n");
1238                 break;
1239         case 4:
1240                 pr_debug("using mode from list\n");
1241                 break;
1242         default:
1243                 pr_debug("rc = %d\n", rc);
1244                 pr_debug("failed to find mode\n");
1245                 /*
1246                  * For plane 0 we continue and look into
1247                  * driver's internal modedb.
1248                  */
1249                 if (mfbi->index == 0 && mfbi->edid_data)
1250                         has_default_mode = 0;
1251                 else
1252                         return -EINVAL;
1253                 break;
1254         }
1255
1256         if (!has_default_mode) {
1257                 rc = fb_find_mode(&info->var, info, aoi_mode, fsl_diu_mode_db,
1258                                   ARRAY_SIZE(fsl_diu_mode_db),
1259                                   &fsl_diu_default_mode,
1260                                   default_bpp);
1261                 if (rc > 0 && rc < 5)
1262                         has_default_mode = 1;
1263         }
1264
1265         /* Still not found, use preferred mode from database if any */
1266         if (!has_default_mode && info->monspecs.modedb) {
1267                 struct fb_monspecs *specs = &info->monspecs;
1268                 struct fb_videomode *modedb = &specs->modedb[0];
1269
1270                 /*
1271                  * Get preferred timing. If not found,
1272                  * first mode in database will be used.
1273                  */
1274                 if (specs->misc & FB_MISC_1ST_DETAIL) {
1275                         int i;
1276
1277                         for (i = 0; i < specs->modedb_len; i++) {
1278                                 if (specs->modedb[i].flag & FB_MODE_IS_FIRST) {
1279                                         modedb = &specs->modedb[i];
1280                                         break;
1281                                 }
1282                         }
1283                 }
1284
1285                 info->var.bits_per_pixel = default_bpp;
1286                 fb_videomode_to_var(&info->var, modedb);
1287         }
1288
1289         pr_debug("xres_virtual %d\n", info->var.xres_virtual);
1290         pr_debug("bits_per_pixel %d\n", info->var.bits_per_pixel);
1291
1292         pr_debug("info->var.yres_virtual = %d\n", info->var.yres_virtual);
1293         pr_debug("info->fix.line_length = %d\n", info->fix.line_length);
1294
1295         if (mfbi->type == MFB_TYPE_OFF)
1296                 mfbi->blank = FB_BLANK_NORMAL;
1297         else
1298                 mfbi->blank = FB_BLANK_UNBLANK;
1299
1300         if (fsl_diu_check_var(&info->var, info)) {
1301                 printk(KERN_ERR "fb_check_var failed");
1302                 fb_dealloc_cmap(&info->cmap);
1303                 return -EINVAL;
1304         }
1305
1306         if (register_framebuffer(info) < 0) {
1307                 printk(KERN_ERR "register_framebuffer failed");
1308                 unmap_video_memory(info);
1309                 fb_dealloc_cmap(&info->cmap);
1310                 return -EINVAL;
1311         }
1312
1313         mfbi->registered = 1;
1314         printk(KERN_INFO "fb%d: %s fb device registered successfully.\n",
1315                  info->node, info->fix.id);
1316
1317         return 0;
1318 }
1319
1320 static void uninstall_fb(struct fb_info *info)
1321 {
1322         struct mfb_info *mfbi = info->par;
1323
1324         if (!mfbi->registered)
1325                 return;
1326
1327         if (mfbi->index == 0)
1328                 kfree(mfbi->edid_data);
1329
1330         unregister_framebuffer(info);
1331         unmap_video_memory(info);
1332         if (&info->cmap)
1333                 fb_dealloc_cmap(&info->cmap);
1334
1335         mfbi->registered = 0;
1336 }
1337
1338 static irqreturn_t fsl_diu_isr(int irq, void *dev_id)
1339 {
1340         struct diu *hw = dr.diu_reg;
1341         unsigned int status = in_be32(&hw->int_status);
1342
1343         if (status) {
1344                 /* This is the workaround for underrun */
1345                 if (status & INT_UNDRUN) {
1346                         out_be32(&hw->diu_mode, 0);
1347                         pr_debug("Err: DIU occurs underrun!\n");
1348                         udelay(1);
1349                         out_be32(&hw->diu_mode, 1);
1350                 }
1351 #if defined(CONFIG_NOT_COHERENT_CACHE)
1352                 else if (status & INT_VSYNC) {
1353                         unsigned int i;
1354
1355                         for (i = 0; i < coherence_data_size;
1356                                 i += d_cache_line_size)
1357                                 __asm__ __volatile__ (
1358                                         "dcbz 0, %[input]"
1359                                 ::[input]"r"(&coherence_data[i]));
1360                 }
1361 #endif
1362                 return IRQ_HANDLED;
1363         }
1364         return IRQ_NONE;
1365 }
1366
1367 static int request_irq_local(int irq)
1368 {
1369         unsigned long status, ints;
1370         struct diu *hw;
1371         int ret;
1372
1373         hw = dr.diu_reg;
1374
1375         /* Read to clear the status */
1376         status = in_be32(&hw->int_status);
1377
1378         ret = request_irq(irq, fsl_diu_isr, 0, "diu", NULL);
1379         if (ret)
1380                 pr_info("Request diu IRQ failed.\n");
1381         else {
1382                 ints = INT_PARERR | INT_LS_BF_VS;
1383 #if !defined(CONFIG_NOT_COHERENT_CACHE)
1384                 ints |= INT_VSYNC;
1385 #endif
1386
1387                 if (dr.mode == MFB_MODE2 || dr.mode == MFB_MODE3)
1388                         ints |= INT_VSYNC_WB;
1389
1390                 /* Read to clear the status */
1391                 status = in_be32(&hw->int_status);
1392                 out_be32(&hw->int_mask, ints);
1393         }
1394
1395         return ret;
1396 }
1397
1398 static void free_irq_local(int irq)
1399 {
1400         struct diu *hw = dr.diu_reg;
1401
1402         /* Disable all LCDC interrupt */
1403         out_be32(&hw->int_mask, 0x1f);
1404
1405         free_irq(irq, NULL);
1406 }
1407
1408 #ifdef CONFIG_PM
1409 /*
1410  * Power management hooks. Note that we won't be called from IRQ context,
1411  * unlike the blank functions above, so we may sleep.
1412  */
1413 static int fsl_diu_suspend(struct platform_device *ofdev, pm_message_t state)
1414 {
1415         struct fsl_diu_data *machine_data;
1416
1417         machine_data = dev_get_drvdata(&ofdev->dev);
1418         disable_lcdc(machine_data->fsl_diu_info[0]);
1419
1420         return 0;
1421 }
1422
1423 static int fsl_diu_resume(struct platform_device *ofdev)
1424 {
1425         struct fsl_diu_data *machine_data;
1426
1427         machine_data = dev_get_drvdata(&ofdev->dev);
1428         enable_lcdc(machine_data->fsl_diu_info[0]);
1429
1430         return 0;
1431 }
1432
1433 #else
1434 #define fsl_diu_suspend NULL
1435 #define fsl_diu_resume NULL
1436 #endif                          /* CONFIG_PM */
1437
1438 /* Align to 64-bit(8-byte), 32-byte, etc. */
1439 static int allocate_buf(struct device *dev, struct diu_addr *buf, u32 size,
1440                         u32 bytes_align)
1441 {
1442         u32 offset, ssize;
1443         u32 mask;
1444         dma_addr_t paddr = 0;
1445
1446         ssize = size + bytes_align;
1447         buf->vaddr = dma_alloc_coherent(dev, ssize, &paddr, GFP_DMA |
1448                                                              __GFP_ZERO);
1449         if (!buf->vaddr)
1450                 return -ENOMEM;
1451
1452         buf->paddr = (__u32) paddr;
1453
1454         mask = bytes_align - 1;
1455         offset = (u32)buf->paddr & mask;
1456         if (offset) {
1457                 buf->offset = bytes_align - offset;
1458                 buf->paddr = (u32)buf->paddr + offset;
1459         } else
1460                 buf->offset = 0;
1461
1462         return 0;
1463 }
1464
1465 static void free_buf(struct device *dev, struct diu_addr *buf, u32 size,
1466                      u32 bytes_align)
1467 {
1468         dma_free_coherent(dev, size + bytes_align, buf->vaddr,
1469                           buf->paddr - buf->offset);
1470 }
1471
1472 static ssize_t store_monitor(struct device *device,
1473         struct device_attribute *attr, const char *buf, size_t count)
1474 {
1475         enum fsl_diu_monitor_port old_monitor_port;
1476         struct fsl_diu_data *machine_data =
1477                 container_of(attr, struct fsl_diu_data, dev_attr);
1478
1479         old_monitor_port = machine_data->monitor_port;
1480         machine_data->monitor_port = fsl_diu_name_to_port(buf);
1481
1482         if (old_monitor_port != machine_data->monitor_port) {
1483                 /* All AOIs need adjust pixel format
1484                  * fsl_diu_set_par only change the pixsel format here
1485                  * unlikely to fail. */
1486                 fsl_diu_set_par(machine_data->fsl_diu_info[0]);
1487                 fsl_diu_set_par(machine_data->fsl_diu_info[1]);
1488                 fsl_diu_set_par(machine_data->fsl_diu_info[2]);
1489                 fsl_diu_set_par(machine_data->fsl_diu_info[3]);
1490                 fsl_diu_set_par(machine_data->fsl_diu_info[4]);
1491         }
1492         return count;
1493 }
1494
1495 static ssize_t show_monitor(struct device *device,
1496         struct device_attribute *attr, char *buf)
1497 {
1498         struct fsl_diu_data *machine_data =
1499                 container_of(attr, struct fsl_diu_data, dev_attr);
1500
1501         switch (machine_data->monitor_port) {
1502         case FSL_DIU_PORT_DVI:
1503                 return sprintf(buf, "DVI\n");
1504         case FSL_DIU_PORT_LVDS:
1505                 return sprintf(buf, "Single-link LVDS\n");
1506         case FSL_DIU_PORT_DLVDS:
1507                 return sprintf(buf, "Dual-link LVDS\n");
1508         }
1509
1510         return 0;
1511 }
1512
1513 static int __devinit fsl_diu_probe(struct platform_device *ofdev)
1514 {
1515         struct device_node *np = ofdev->dev.of_node;
1516         struct mfb_info *mfbi;
1517         phys_addr_t dummy_ad_addr;
1518         int ret, i, error = 0;
1519         struct resource res;
1520         struct fsl_diu_data *machine_data;
1521         int diu_mode;
1522
1523         machine_data = kzalloc(sizeof(struct fsl_diu_data), GFP_KERNEL);
1524         if (!machine_data)
1525                 return -ENOMEM;
1526
1527         for (i = 0; i < ARRAY_SIZE(machine_data->fsl_diu_info); i++) {
1528                 machine_data->fsl_diu_info[i] =
1529                         framebuffer_alloc(sizeof(struct mfb_info), &ofdev->dev);
1530                 if (!machine_data->fsl_diu_info[i]) {
1531                         dev_err(&ofdev->dev, "cannot allocate memory\n");
1532                         ret = -ENOMEM;
1533                         goto error2;
1534                 }
1535                 mfbi = machine_data->fsl_diu_info[i]->par;
1536                 memcpy(mfbi, &mfb_template[i], sizeof(struct mfb_info));
1537                 mfbi->parent = machine_data;
1538
1539                 if (mfbi->index == 0) {
1540                         const u8 *prop;
1541                         int len;
1542
1543                         /* Get EDID */
1544                         prop = of_get_property(np, "edid", &len);
1545                         if (prop && len == EDID_LENGTH)
1546                                 mfbi->edid_data = kmemdup(prop, EDID_LENGTH,
1547                                                           GFP_KERNEL);
1548                 }
1549         }
1550
1551         ret = of_address_to_resource(np, 0, &res);
1552         if (ret) {
1553                 dev_err(&ofdev->dev, "could not obtain DIU address\n");
1554                 goto error;
1555         }
1556         if (!res.start) {
1557                 dev_err(&ofdev->dev, "invalid DIU address\n");
1558                 goto error;
1559         }
1560         dev_dbg(&ofdev->dev, "%s, res.start: 0x%08x\n", __func__, res.start);
1561
1562         dr.diu_reg = ioremap(res.start, sizeof(struct diu));
1563         if (!dr.diu_reg) {
1564                 dev_err(&ofdev->dev, "Err: can't map DIU registers!\n");
1565                 ret = -EFAULT;
1566                 goto error2;
1567         }
1568
1569         diu_mode = in_be32(&dr.diu_reg->diu_mode);
1570         if (diu_mode != MFB_MODE1)
1571                 out_be32(&dr.diu_reg->diu_mode, 0);     /* disable DIU */
1572
1573         /* Get the IRQ of the DIU */
1574         machine_data->irq = irq_of_parse_and_map(np, 0);
1575
1576         if (!machine_data->irq) {
1577                 dev_err(&ofdev->dev, "could not get DIU IRQ\n");
1578                 ret = -EINVAL;
1579                 goto error;
1580         }
1581         machine_data->monitor_port = monitor_port;
1582
1583         /* Area descriptor memory pool aligns to 64-bit boundary */
1584         if (allocate_buf(&ofdev->dev, &pool.ad,
1585                          sizeof(struct diu_ad) * FSL_AOI_NUM, 8))
1586                 return -ENOMEM;
1587
1588         /* Get memory for Gamma Table  - 32-byte aligned memory */
1589         if (allocate_buf(&ofdev->dev, &pool.gamma, 768, 32)) {
1590                 ret = -ENOMEM;
1591                 goto error;
1592         }
1593
1594         /* For performance, cursor bitmap buffer aligns to 32-byte boundary */
1595         if (allocate_buf(&ofdev->dev, &pool.cursor, MAX_CURS * MAX_CURS * 2,
1596                          32)) {
1597                 ret = -ENOMEM;
1598                 goto error;
1599         }
1600
1601         i = ARRAY_SIZE(machine_data->fsl_diu_info);
1602         machine_data->dummy_ad = (struct diu_ad *)
1603                         ((u32)pool.ad.vaddr + pool.ad.offset) + i;
1604         machine_data->dummy_ad->paddr = pool.ad.paddr +
1605                         i * sizeof(struct diu_ad);
1606         machine_data->dummy_aoi_virt = fsl_diu_alloc(64, &dummy_ad_addr);
1607         if (!machine_data->dummy_aoi_virt) {
1608                 ret = -ENOMEM;
1609                 goto error;
1610         }
1611         machine_data->dummy_ad->addr = cpu_to_le32(dummy_ad_addr);
1612         machine_data->dummy_ad->pix_fmt = 0x88882317;
1613         machine_data->dummy_ad->src_size_g_alpha = cpu_to_le32((4 << 12) | 4);
1614         machine_data->dummy_ad->aoi_size = cpu_to_le32((4 << 16) |  2);
1615         machine_data->dummy_ad->offset_xyi = 0;
1616         machine_data->dummy_ad->offset_xyd = 0;
1617         machine_data->dummy_ad->next_ad = 0;
1618
1619         /*
1620          * Let DIU display splash screen if it was pre-initialized
1621          * by the bootloader, set dummy area descriptor otherwise.
1622          */
1623         if (diu_mode != MFB_MODE1)
1624                 out_be32(&dr.diu_reg->desc[0], machine_data->dummy_ad->paddr);
1625
1626         out_be32(&dr.diu_reg->desc[1], machine_data->dummy_ad->paddr);
1627         out_be32(&dr.diu_reg->desc[2], machine_data->dummy_ad->paddr);
1628
1629         for (i = 0; i < ARRAY_SIZE(machine_data->fsl_diu_info); i++) {
1630                 machine_data->fsl_diu_info[i]->fix.smem_start = 0;
1631                 mfbi = machine_data->fsl_diu_info[i]->par;
1632                 mfbi->ad = (struct diu_ad *)((u32)pool.ad.vaddr
1633                                         + pool.ad.offset) + i;
1634                 mfbi->ad->paddr = pool.ad.paddr + i * sizeof(struct diu_ad);
1635                 ret = install_fb(machine_data->fsl_diu_info[i]);
1636                 if (ret) {
1637                         dev_err(&ofdev->dev,
1638                                 "Failed to register framebuffer %d\n",
1639                                 i);
1640                         goto error;
1641                 }
1642         }
1643
1644         if (request_irq_local(machine_data->irq)) {
1645                 dev_err(machine_data->fsl_diu_info[0]->dev,
1646                         "could not request irq for diu.");
1647                 goto error;
1648         }
1649
1650         sysfs_attr_init(&machine_data->dev_attr.attr);
1651         machine_data->dev_attr.attr.name = "monitor";
1652         machine_data->dev_attr.attr.mode = S_IRUGO|S_IWUSR;
1653         machine_data->dev_attr.show = show_monitor;
1654         machine_data->dev_attr.store = store_monitor;
1655         error = device_create_file(machine_data->fsl_diu_info[0]->dev,
1656                                   &machine_data->dev_attr);
1657         if (error) {
1658                 dev_err(machine_data->fsl_diu_info[0]->dev,
1659                         "could not create sysfs %s file\n",
1660                         machine_data->dev_attr.attr.name);
1661         }
1662
1663         dev_set_drvdata(&ofdev->dev, machine_data);
1664         return 0;
1665
1666 error:
1667         for (i = ARRAY_SIZE(machine_data->fsl_diu_info);
1668                 i > 0; i--)
1669                 uninstall_fb(machine_data->fsl_diu_info[i - 1]);
1670         if (pool.ad.vaddr)
1671                 free_buf(&ofdev->dev, &pool.ad,
1672                          sizeof(struct diu_ad) * FSL_AOI_NUM, 8);
1673         if (pool.gamma.vaddr)
1674                 free_buf(&ofdev->dev, &pool.gamma, 768, 32);
1675         if (pool.cursor.vaddr)
1676                 free_buf(&ofdev->dev, &pool.cursor, MAX_CURS * MAX_CURS * 2,
1677                          32);
1678         if (machine_data->dummy_aoi_virt)
1679                 fsl_diu_free(machine_data->dummy_aoi_virt, 64);
1680         iounmap(dr.diu_reg);
1681
1682 error2:
1683         for (i = 0; i < ARRAY_SIZE(machine_data->fsl_diu_info); i++)
1684                 if (machine_data->fsl_diu_info[i])
1685                         framebuffer_release(machine_data->fsl_diu_info[i]);
1686         kfree(machine_data);
1687
1688         return ret;
1689 }
1690
1691
1692 static int fsl_diu_remove(struct platform_device *ofdev)
1693 {
1694         struct fsl_diu_data *machine_data;
1695         int i;
1696
1697         machine_data = dev_get_drvdata(&ofdev->dev);
1698         disable_lcdc(machine_data->fsl_diu_info[0]);
1699         free_irq_local(machine_data->irq);
1700         for (i = ARRAY_SIZE(machine_data->fsl_diu_info); i > 0; i--)
1701                 uninstall_fb(machine_data->fsl_diu_info[i - 1]);
1702         if (pool.ad.vaddr)
1703                 free_buf(&ofdev->dev, &pool.ad,
1704                          sizeof(struct diu_ad) * FSL_AOI_NUM, 8);
1705         if (pool.gamma.vaddr)
1706                 free_buf(&ofdev->dev, &pool.gamma, 768, 32);
1707         if (pool.cursor.vaddr)
1708                 free_buf(&ofdev->dev, &pool.cursor, MAX_CURS * MAX_CURS * 2,
1709                          32);
1710         if (machine_data->dummy_aoi_virt)
1711                 fsl_diu_free(machine_data->dummy_aoi_virt, 64);
1712         iounmap(dr.diu_reg);
1713         for (i = 0; i < ARRAY_SIZE(machine_data->fsl_diu_info); i++)
1714                 if (machine_data->fsl_diu_info[i])
1715                         framebuffer_release(machine_data->fsl_diu_info[i]);
1716         kfree(machine_data);
1717
1718         return 0;
1719 }
1720
1721 #ifndef MODULE
1722 static int __init fsl_diu_setup(char *options)
1723 {
1724         char *opt;
1725         unsigned long val;
1726
1727         if (!options || !*options)
1728                 return 0;
1729
1730         while ((opt = strsep(&options, ",")) != NULL) {
1731                 if (!*opt)
1732                         continue;
1733                 if (!strncmp(opt, "monitor=", 8)) {
1734                         monitor_port = fsl_diu_name_to_port(opt + 8);
1735                 } else if (!strncmp(opt, "bpp=", 4)) {
1736                         if (!strict_strtoul(opt + 4, 10, &val))
1737                                 default_bpp = val;
1738                 } else
1739                         fb_mode = opt;
1740         }
1741
1742         return 0;
1743 }
1744 #endif
1745
1746 static struct of_device_id fsl_diu_match[] = {
1747 #ifdef CONFIG_PPC_MPC512x
1748         {
1749                 .compatible = "fsl,mpc5121-diu",
1750         },
1751 #endif
1752         {
1753                 .compatible = "fsl,diu",
1754         },
1755         {}
1756 };
1757 MODULE_DEVICE_TABLE(of, fsl_diu_match);
1758
1759 static struct platform_driver fsl_diu_driver = {
1760         .driver = {
1761                 .name = "fsl_diu",
1762                 .owner = THIS_MODULE,
1763                 .of_match_table = fsl_diu_match,
1764         },
1765         .probe          = fsl_diu_probe,
1766         .remove         = fsl_diu_remove,
1767         .suspend        = fsl_diu_suspend,
1768         .resume         = fsl_diu_resume,
1769 };
1770
1771 static int __init fsl_diu_init(void)
1772 {
1773 #ifdef CONFIG_NOT_COHERENT_CACHE
1774         struct device_node *np;
1775         const u32 *prop;
1776 #endif
1777         int ret;
1778 #ifndef MODULE
1779         char *option;
1780
1781         /*
1782          * For kernel boot options (in 'video=xxxfb:<options>' format)
1783          */
1784         if (fb_get_options("fslfb", &option))
1785                 return -ENODEV;
1786         fsl_diu_setup(option);
1787 #else
1788         monitor_port = fsl_diu_name_to_port(monitor_string);
1789 #endif
1790         printk(KERN_INFO "Freescale DIU driver\n");
1791
1792 #ifdef CONFIG_NOT_COHERENT_CACHE
1793         np = of_find_node_by_type(NULL, "cpu");
1794         if (!np) {
1795                 printk(KERN_ERR "Err: can't find device node 'cpu'\n");
1796                 return -ENODEV;
1797         }
1798
1799         prop = of_get_property(np, "d-cache-size", NULL);
1800         if (prop == NULL) {
1801                 of_node_put(np);
1802                 return -ENODEV;
1803         }
1804
1805         /*
1806          * Freescale PLRU requires 13/8 times the cache size to do a proper
1807          * displacement flush
1808          */
1809         coherence_data_size = *prop * 13;
1810         coherence_data_size /= 8;
1811
1812         prop = of_get_property(np, "d-cache-line-size", NULL);
1813         if (prop == NULL) {
1814                 of_node_put(np);
1815                 return -ENODEV;
1816         }
1817         d_cache_line_size = *prop;
1818
1819         of_node_put(np);
1820         coherence_data = vmalloc(coherence_data_size);
1821         if (!coherence_data)
1822                 return -ENOMEM;
1823 #endif
1824
1825         ret = platform_driver_register(&fsl_diu_driver);
1826         if (ret) {
1827                 printk(KERN_ERR
1828                         "fsl-diu: failed to register platform driver\n");
1829 #if defined(CONFIG_NOT_COHERENT_CACHE)
1830                 vfree(coherence_data);
1831 #endif
1832                 iounmap(dr.diu_reg);
1833         }
1834         return ret;
1835 }
1836
1837 static void __exit fsl_diu_exit(void)
1838 {
1839         platform_driver_unregister(&fsl_diu_driver);
1840 #if defined(CONFIG_NOT_COHERENT_CACHE)
1841         vfree(coherence_data);
1842 #endif
1843 }
1844
1845 module_init(fsl_diu_init);
1846 module_exit(fsl_diu_exit);
1847
1848 MODULE_AUTHOR("York Sun <yorksun@freescale.com>");
1849 MODULE_DESCRIPTION("Freescale DIU framebuffer driver");
1850 MODULE_LICENSE("GPL");
1851
1852 module_param_named(mode, fb_mode, charp, 0);
1853 MODULE_PARM_DESC(mode,
1854         "Specify resolution as \"<xres>x<yres>[-<bpp>][@<refresh>]\" ");
1855 module_param_named(bpp, default_bpp, ulong, 0);
1856 MODULE_PARM_DESC(bpp, "Specify bit-per-pixel if not specified mode");
1857 module_param_named(monitor, monitor_string, charp, 0);
1858 MODULE_PARM_DESC(monitor, "Specify the monitor port "
1859         "(\"dvi\", \"lvds\", or \"dlvds\") if supported by the platform");
1860