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