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