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