]> www.pilppa.org Git - linux-2.6-omap-h63xx.git/blob - drivers/video/omap/dispc.c
ARM: OMAP: A whopping FB driver update
[linux-2.6-omap-h63xx.git] / drivers / video / omap / dispc.c
1 /*
2  * File: drivers/video/omap/omap2/dispc.c
3  *
4  * OMAP2 display controller support
5  *
6  * Copyright (C) 2005 Nokia Corporation
7  * Author: Imre Deak <imre.deak@nokia.com>
8  *
9  * This program is free software; you can redistribute it and/or modify it
10  * under the terms of the GNU General Public License as published by the
11  * Free Software Foundation; either version 2 of the License, or (at your
12  * option) any later version.
13  *
14  * This program is distributed in the hope that it will be useful, but
15  * WITHOUT ANY WARRANTY; without even the implied warranty of
16  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
17  * General Public License for more details.
18  *
19  * You should have received a copy of the GNU General Public License along
20  * with this program; if not, write to the Free Software Foundation, Inc.,
21  * 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
22  */
23
24 #include <linux/kernel.h>
25 #include <linux/dma-mapping.h>
26 #include <linux/vmalloc.h>
27 #include <linux/clk.h>
28
29 #include <asm/io.h>
30
31 #include <asm/arch/sram.h>
32 #include <asm/arch/omapfb.h>
33 #include <asm/arch/board.h>
34
35 #include "dispc.h"
36
37 /* #define OMAPFB_DBG   1 */
38
39 #include "debug.h"
40
41 #define MODULE_NAME                     "omapfb-dispc"
42
43 #define DISPC_BASE                      0x48050400
44
45 /* DISPC common */
46 #define DISPC_REVISION                  0x0000
47 #define DISPC_SYSCONFIG                 0x0010
48 #define DISPC_SYSSTATUS                 0x0014
49 #define DISPC_IRQSTATUS                 0x0018
50 #define DISPC_IRQENABLE                 0x001C
51 #define DISPC_CONTROL                   0x0040
52 #define DISPC_CONFIG                    0x0044
53 #define DISPC_CAPABLE                   0x0048
54 #define DISPC_DEFAULT_COLOR0            0x004C
55 #define DISPC_DEFAULT_COLOR1            0x0050
56 #define DISPC_TRANS_COLOR0              0x0054
57 #define DISPC_TRANS_COLOR1              0x0058
58 #define DISPC_LINE_STATUS               0x005C
59 #define DISPC_LINE_NUMBER               0x0060
60 #define DISPC_TIMING_H                  0x0064
61 #define DISPC_TIMING_V                  0x0068
62 #define DISPC_POL_FREQ                  0x006C
63 #define DISPC_DIVISOR                   0x0070
64 #define DISPC_SIZE_DIG                  0x0078
65 #define DISPC_SIZE_LCD                  0x007C
66
67 #define DISPC_DATA_CYCLE1               0x01D4
68 #define DISPC_DATA_CYCLE2               0x01D8
69 #define DISPC_DATA_CYCLE3               0x01DC
70
71 /* DISPC GFX plane */
72 #define DISPC_GFX_BA0                   0x0080
73 #define DISPC_GFX_BA1                   0x0084
74 #define DISPC_GFX_POSITION              0x0088
75 #define DISPC_GFX_SIZE                  0x008C
76 #define DISPC_GFX_ATTRIBUTES            0x00A0
77 #define DISPC_GFX_FIFO_THRESHOLD        0x00A4
78 #define DISPC_GFX_FIFO_SIZE_STATUS      0x00A8
79 #define DISPC_GFX_ROW_INC               0x00AC
80 #define DISPC_GFX_PIXEL_INC             0x00B0
81 #define DISPC_GFX_WINDOW_SKIP           0x00B4
82 #define DISPC_GFX_TABLE_BA              0x00B8
83
84 /* DISPC Video plane 1/2 */
85 #define DISPC_VID1_BASE                 0x00BC
86 #define DISPC_VID2_BASE                 0x014C
87
88 /* Offsets into DISPC_VID1/2_BASE */
89 #define DISPC_VID_BA0                   0x0000
90 #define DISPC_VID_BA1                   0x0004
91 #define DISPC_VID_POSITION              0x0008
92 #define DISPC_VID_SIZE                  0x000C
93 #define DISPC_VID_ATTRIBUTES            0x0010
94 #define DISPC_VID_FIFO_THRESHOLD        0x0014
95 #define DISPC_VID_FIFO_SIZE_STATUS      0x0018
96 #define DISPC_VID_ROW_INC               0x001C
97 #define DISPC_VID_PIXEL_INC             0x0020
98 #define DISPC_VID_FIR                   0x0024
99 #define DISPC_VID_PICTURE_SIZE          0x0028
100 #define DISPC_VID_ACCU0                 0x002C
101 #define DISPC_VID_ACCU1                 0x0030
102
103 /* 8 elements in 8 byte increments */
104 #define DISPC_VID_FIR_COEF_H0           0x0034
105 /* 8 elements in 8 byte increments */
106 #define DISPC_VID_FIR_COEF_HV0          0x0038
107 /* 5 elements in 4 byte increments */
108 #define DISPC_VID_CONV_COEF0            0x0074
109
110 #define DISPC_IRQ_FRAMEMASK             0x0001
111 #define DISPC_IRQ_VSYNC                 0x0002
112 #define DISPC_IRQ_EVSYNC_EVEN           0x0004
113 #define DISPC_IRQ_EVSYNC_ODD            0x0008
114 #define DISPC_IRQ_ACBIAS_COUNT_STAT     0x0010
115 #define DISPC_IRQ_PROG_LINE_NUM         0x0020
116 #define DISPC_IRQ_GFX_FIFO_UNDERFLOW    0x0040
117 #define DISPC_IRQ_GFX_END_WIN           0x0080
118 #define DISPC_IRQ_PAL_GAMMA_MASK        0x0100
119 #define DISPC_IRQ_OCP_ERR               0x0200
120 #define DISPC_IRQ_VID1_FIFO_UNDERFLOW   0x0400
121 #define DISPC_IRQ_VID1_END_WIN          0x0800
122 #define DISPC_IRQ_VID2_FIFO_UNDERFLOW   0x1000
123 #define DISPC_IRQ_VID2_END_WIN          0x2000
124 #define DISPC_IRQ_SYNC_LOST             0x4000
125
126 #define DISPC_IRQ_MASK_ALL              0x7fff
127
128 #define DISPC_IRQ_MASK_ERROR            (DISPC_IRQ_GFX_FIFO_UNDERFLOW | \
129                                              DISPC_IRQ_VID1_FIFO_UNDERFLOW | \
130                                              DISPC_IRQ_VID2_FIFO_UNDERFLOW | \
131                                              DISPC_IRQ_SYNC_LOST)
132
133 #define RFBI_CONTROL                    0x48050040
134
135 #define MAX_PALETTE_SIZE                (256 * 16)
136
137 #define pr_err(fmt, args...) printk(KERN_ERR MODULE_NAME ": " fmt, ## args)
138
139 #define FLD_MASK(pos, len)      (((1 << len) - 1) << pos)
140
141 #define MOD_REG_FLD(reg, mask, val) \
142         dispc_write_reg((reg), (dispc_read_reg(reg) & ~(mask)) | (val));
143
144 static struct {
145         u32             base;
146
147         dma_addr_t      fb_sram_paddr;
148         u32             fb_sram_size;
149         int             fb_sram_lines;
150
151         dma_addr_t      fb_sdram_paddr;
152         void            *fb_sdram_vaddr;
153         u32             fb_sdram_size;
154         int             fb_sdram_lines;
155
156         dma_addr_t      palette_paddr;
157         void            *palette_vaddr;
158
159         void            *fb_kern_vaddr;
160
161         int             multiplane_head;
162
163         int             ext_mode;
164         int             fbmem_allocated;
165
166         unsigned long   enabled_irqs;
167         void            (*irq_callback)(void *);
168         void            *irq_callback_data;
169         struct completion       frame_done;
170
171         struct clk      *dss_ick, *dss1_fck;
172         struct clk      *dss_54m_fck;
173
174         enum omapfb_update_mode update_mode;
175         struct omapfb_device    *fbdev;
176 } dispc;
177
178 static void inline dispc_write_reg(int idx, u32 val)
179 {
180         __raw_writel(val, dispc.base + idx);
181 }
182
183 static u32 inline dispc_read_reg(int idx)
184 {
185         u32 l = __raw_readl(dispc.base + idx);
186         return l;
187 }
188
189 /* Select RFBI or bypass mode */
190 static void enable_rfbi_mode(int enable)
191 {
192         u32 l;
193
194         l = dispc_read_reg(DISPC_CONTROL);
195         /* Enable RFBI, GPIO0/1 */
196         l &= ~((1 << 11) | (1 << 15) | (1 << 16));
197         l |= enable ? (1 << 11) : 0;
198         /* RFBI En: GPIO0/1=10  RFBI Dis: GPIO0/1=11 */
199         l |= 1 << 15;
200         l |= enable ? 0 : (1 << 16);
201         dispc_write_reg(DISPC_CONTROL, l);
202
203         /* Set bypass mode in RFBI module */
204         l = __raw_readl(io_p2v(RFBI_CONTROL));
205         l |= enable ? 0 : (1 << 1);
206         __raw_writel(l, io_p2v(RFBI_CONTROL));
207 }
208
209 static void set_lcd_data_lines(int data_lines)
210 {
211         u32 l;
212         int code = 0;
213
214         switch (data_lines) {
215         case 12:
216                 code = 0;
217                 break;
218         case 16:
219                 code = 1;
220                 break;
221         case 18:
222                 code = 2;
223                 break;
224         case 24:
225                 code = 3;
226                 break;
227         default:
228                 BUG();
229         }
230
231         l = dispc_read_reg(DISPC_CONTROL);
232         l &= ~(0x03 << 8);
233         l |= code << 8;
234         dispc_write_reg(DISPC_CONTROL, l);
235 }
236
237 static void set_load_mode(int mode)
238 {
239         BUG_ON(mode & ~(DISPC_LOAD_CLUT_ONLY | DISPC_LOAD_FRAME_ONLY |
240                         DISPC_LOAD_CLUT_ONCE_FRAME));
241         MOD_REG_FLD(DISPC_CONFIG, 0x03 << 1, mode << 1);
242 }
243
244 void omap_dispc_set_lcd_size(int x, int y)
245 {
246         BUG_ON((x > (1 << 11)) || (y > (1 << 11)));
247         MOD_REG_FLD(DISPC_SIZE_LCD, FLD_MASK(16, 11) | FLD_MASK(0, 11),
248                         ((y - 1) << 16) | (x - 1));
249 }
250 EXPORT_SYMBOL(omap_dispc_set_lcd_size);
251
252 void omap_dispc_set_digit_size(int x, int y)
253 {
254         BUG_ON((x > (1 << 11)) || (y > (1 << 11)));
255         MOD_REG_FLD(DISPC_SIZE_DIG, FLD_MASK(16, 11) | FLD_MASK(0, 11),
256                         ((y - 1) << 16) | (x - 1));
257 }
258 EXPORT_SYMBOL(omap_dispc_set_digit_size);
259
260 static void setup_plane_fifo(int plane)
261 {
262         const u32 ftrs_reg[] = { DISPC_GFX_FIFO_THRESHOLD,
263                                 DISPC_VID1_BASE + DISPC_VID_FIFO_THRESHOLD,
264                                 DISPC_VID2_BASE + DISPC_VID_FIFO_THRESHOLD };
265         const u32 fsz_reg[] = { DISPC_GFX_FIFO_SIZE_STATUS,
266                                 DISPC_VID1_BASE + DISPC_VID_FIFO_SIZE_STATUS,
267                                 DISPC_VID2_BASE + DISPC_VID_FIFO_SIZE_STATUS };
268
269         u32 l;
270
271         BUG_ON(plane > 2);
272
273         l = dispc_read_reg(fsz_reg[plane]);
274         l &= FLD_MASK(0, 9);
275         /* HIGH=3/4 LOW=1/4 */
276         MOD_REG_FLD(ftrs_reg[plane], FLD_MASK(16, 9) | FLD_MASK(0, 9),
277                         ((l * 3 / 4) << 16) | (l / 4));
278 }
279
280 void omap_dispc_enable_lcd_out(int enable)
281 {
282         MOD_REG_FLD(DISPC_CONTROL, 1, enable ? 1 : 0);
283 }
284 EXPORT_SYMBOL(omap_dispc_enable_lcd_out);
285
286 void omap_dispc_enable_digit_out(int enable)
287 {
288         MOD_REG_FLD(DISPC_CONTROL, 1 << 1, enable ? 1 << 1 : 0);
289 }
290 EXPORT_SYMBOL(omap_dispc_enable_digit_out);
291
292 static inline int _setup_plane(int plane, int channel_out,
293                                   u32 paddr, int screen_width,
294                                   int pos_x, int pos_y, int width, int height,
295                                   int color_mode)
296 {
297         const u32 at_reg[] = { DISPC_GFX_ATTRIBUTES,
298                                 DISPC_VID1_BASE + DISPC_VID_ATTRIBUTES,
299                                 DISPC_VID2_BASE + DISPC_VID_ATTRIBUTES };
300         const u32 ba_reg[] = { DISPC_GFX_BA0, DISPC_VID1_BASE + DISPC_VID_BA0,
301                                 DISPC_VID2_BASE + DISPC_VID_BA0 };
302         const u32 ps_reg[] = { DISPC_GFX_POSITION,
303                                 DISPC_VID1_BASE + DISPC_VID_POSITION,
304                                 DISPC_VID2_BASE + DISPC_VID_POSITION };
305         const u32 sz_reg[] = { DISPC_GFX_SIZE, DISPC_VID1_BASE + DISPC_VID_SIZE,
306                                 DISPC_VID2_BASE + DISPC_VID_SIZE };
307         const u32 ri_reg[] = { DISPC_GFX_ROW_INC,
308                                 DISPC_VID1_BASE + DISPC_VID_ROW_INC,
309                                 DISPC_VID2_BASE + DISPC_VID_ROW_INC };
310         int chout_shift, burst_shift;
311         int chout_val;
312         int color_code;
313         int bpp;
314         u32 l;
315
316         DBGPRINT(2, "plane %d channel %d paddr %u scr_width %d pos_x %d pos_y %d "
317                     "width %d height %d color_mode %d\n",
318                     plane, channel_out, paddr, screen_width, pos_x, pos_y,
319                     width, height, color_mode);
320
321         switch (plane) {
322         case OMAPFB_PLANE_GFX:
323                 burst_shift = 6;
324                 chout_shift = 8;
325                 break;
326         case OMAPFB_PLANE_VID1:
327         case OMAPFB_PLANE_VID2:
328                 burst_shift = 14;
329                 chout_shift = 16;
330                 break;
331         default:
332                 return -EINVAL;
333         }
334
335         switch (channel_out) {
336         case OMAPFB_CHANNEL_OUT_LCD:
337                 chout_val = 0;
338                 break;
339         case OMAPFB_CHANNEL_OUT_DIGIT:
340                 chout_val = 1;
341                 break;
342         default:
343                 return -EINVAL;
344         }
345
346         switch (color_mode) {
347         case OMAPFB_COLOR_RGB565:
348                 color_code = DISPC_RGB_16_BPP;
349                 bpp = 16;
350                 break;
351         case OMAPFB_COLOR_YUV422:
352                 if (plane != 0)
353                         return -EINVAL;
354                 color_code = DISPC_UYVY_422;
355                 bpp = 16;
356                 break;
357         case OMAPFB_COLOR_YUV420:
358                 if (plane != 0)
359                         return -EINVAL;
360                 color_code = DISPC_YUV2_422;
361                 bpp = 12;
362                 break;
363         default:
364                 return -EINVAL;
365         }
366
367         l = dispc_read_reg(at_reg[plane]);
368
369         l &= ~(0x0f << 1);
370         l |= color_code << 1;
371
372         l &= ~(0x03 << burst_shift);
373         l |= DISPC_BURST_8x32 << burst_shift;
374
375         l &= ~(1 << chout_shift);
376         l |= chout_val << chout_shift;
377
378         dispc_write_reg(at_reg[plane], l);
379
380         dispc_write_reg(ba_reg[plane], paddr);
381         MOD_REG_FLD(ps_reg[plane],
382                     FLD_MASK(16, 11) | FLD_MASK(0, 11), (pos_y << 16) | pos_x);
383
384         MOD_REG_FLD(sz_reg[plane], FLD_MASK(16, 11) | FLD_MASK(0, 11),
385                         ((height - 1) << 16) | (width - 1));
386
387         dispc_write_reg(ri_reg[plane], (screen_width - width) * bpp / 8 + 1);
388
389         return height * screen_width * bpp / 8;
390 }
391
392 static int omap_dispc_setup_plane(int plane, int channel_out,
393                                   unsigned long offset, int screen_width,
394                                   int pos_x, int pos_y, int width, int height,
395                                   int color_mode)
396 {
397         int yspan;
398         u32 paddr;
399         int mp_head = -1;
400         int r;
401
402         if (offset > dispc.fb_sram_size + dispc.fb_sdram_size)
403                 return -EINVAL;
404
405         if (offset < dispc.fb_sram_size) {
406                 paddr = dispc.fb_sram_paddr + offset;
407                 yspan = min_t(int, height, dispc.fb_sram_lines);
408                 if (yspan) {
409                         if ((r = _setup_plane(plane, channel_out, paddr,
410                                         screen_width, pos_x, pos_y,
411                                         width, height, color_mode)) < 0)
412                                 return r;
413                         offset += r;
414                         height -= yspan;
415                         pos_y += yspan;
416                         mp_head = plane;
417                         if (++plane > 2)
418                                 plane = OMAPFB_PLANE_GFX;
419                 }
420         }
421         if (height) {
422                 offset -= dispc.fb_sram_size;
423                 paddr = dispc.fb_sdram_paddr + offset;
424                 yspan = min_t(int, height, dispc.fb_sdram_lines);
425                 if (yspan) {
426                         if ((r = _setup_plane(plane, channel_out, paddr,
427                                         screen_width, pos_x, pos_y,
428                                         width, height, color_mode)) < 0)
429                                 return r;
430                         if (mp_head != -1)
431                                 dispc.multiplane_head = mp_head;
432                 }
433         }
434
435         return 0;
436 }
437
438 static int omap_dispc_enable_plane(int plane, int enable)
439 {
440         const u32 at_reg[] = { DISPC_GFX_ATTRIBUTES,
441                                 DISPC_VID1_BASE + DISPC_VID_ATTRIBUTES,
442                                 DISPC_VID2_BASE + DISPC_VID_ATTRIBUTES };
443         DBGENTER(2);
444
445         if ((unsigned int)plane > 2)
446                 return -EINVAL;
447         MOD_REG_FLD(at_reg[plane], 1, enable ? 1 : 0);
448         if (plane == dispc.multiplane_head) {
449                 if (++plane > 2)
450                         plane = OMAPFB_PLANE_GFX;
451                 MOD_REG_FLD(at_reg[plane], 1, enable ? 1 : 0);
452         }
453
454         return 0;
455 }
456
457 static int omap_dispc_set_color_key(struct omapfb_color_key *ck)
458 {
459         u32 df_reg, tr_reg;
460         int shift, val;
461
462         switch (ck->channel_out) {
463         case OMAPFB_CHANNEL_OUT_LCD:
464                 df_reg = DISPC_DEFAULT_COLOR0;
465                 tr_reg = DISPC_TRANS_COLOR0;
466                 shift = 10;
467                 break;
468         case OMAPFB_CHANNEL_OUT_DIGIT:
469                 df_reg = DISPC_DEFAULT_COLOR1;
470                 tr_reg = DISPC_TRANS_COLOR1;
471                 shift = 12;
472                 break;
473         default:
474                 return -EINVAL;
475         }
476         switch (ck->key_type) {
477         case OMAPFB_COLOR_KEY_DISABLED:
478                 val = 0;
479                 break;
480         case OMAPFB_COLOR_KEY_GFX_DST:
481                 val = 1;
482                 break;
483         case OMAPFB_COLOR_KEY_VID_SRC:
484                 val = 3;
485                 break;
486         default:
487                 return -EINVAL;
488         }
489         MOD_REG_FLD(DISPC_CONFIG, FLD_MASK(shift, 2), val << shift);
490
491         if (val != 0)
492                 dispc_write_reg(tr_reg, ck->trans_key);
493         dispc_write_reg(df_reg, ck->background);
494
495         return 0;
496 }
497
498 static void load_palette(void)
499 {
500 }
501
502 static int omap_dispc_set_update_mode(enum omapfb_update_mode mode)
503 {
504         int r = 0;
505
506         DBGENTER(1);
507
508         if (mode != dispc.update_mode) {
509                 switch (mode) {
510                 case OMAPFB_AUTO_UPDATE:
511                 case OMAPFB_MANUAL_UPDATE:
512                         omap_dispc_enable_lcd_out(1);
513                         dispc.update_mode = mode;
514                         break;
515                 case OMAPFB_UPDATE_DISABLED:
516                         init_completion(&dispc.frame_done);
517                         omap_dispc_enable_lcd_out(0);
518                         if (!wait_for_completion_timeout(&dispc.frame_done,
519                                         msecs_to_jiffies(500))) {
520                                 pr_err("timeout waiting for FRAME DONE\n");
521                         }
522                         dispc.update_mode = mode;
523                         break;
524                 default:
525                         r = -EINVAL;
526                 }
527         }
528
529         DBGLEAVE(1);
530
531         return r;
532 }
533
534 static enum omapfb_update_mode omap_dispc_get_update_mode(void)
535 {
536         return dispc.update_mode;
537 }
538
539 static void calc_ck_div(int is_tft, int pck, int *lck_div, int *pck_div)
540 {
541         unsigned long fck, lck;
542
543         *lck_div = 1;
544         pck = max(1, pck);
545         fck = clk_get_rate(dispc.dss1_fck);
546         lck = fck;
547         *pck_div = (lck + pck - 1) / pck;
548         if (is_tft)
549                 *pck_div = max(2, *pck_div);
550         else
551                 *pck_div = max(3, *pck_div);
552         if (*pck_div > 255) {
553                 *pck_div = 255;
554                 lck = pck * *pck_div;
555                 *lck_div = fck / lck;
556                 BUG_ON(*lck_div < 1);
557                 if (*lck_div > 255) {
558                         *lck_div = 255;
559                         printk(KERN_WARNING
560                                 MODULE_NAME ": pixclock %d kHz too low.\n",
561                                  pck / 1000);
562                 }
563         }
564 }
565
566 static void set_lcd_tft_mode(int enable)
567 {
568         u32 mask;
569
570         mask = 1 << 3;
571         MOD_REG_FLD(DISPC_CONTROL, mask, enable ? mask : 0);
572 }
573
574 static void set_lcd_timings(void)
575 {
576         u32 l;
577         int lck_div, pck_div;
578         struct lcd_panel *panel = dispc.fbdev->panel;
579         int is_tft = panel->config & OMAP_LCDC_PANEL_TFT;
580         unsigned long fck;
581
582         DBGENTER(1);
583
584         l = dispc_read_reg(DISPC_TIMING_H);
585         l &= ~(FLD_MASK(0, 6) | FLD_MASK(8, 8) | FLD_MASK(20, 8));
586         l |= ( max(1, (min(64,  panel->hsw))) - 1 ) << 0;
587         l |= ( max(1, (min(256, panel->hfp))) - 1 ) << 8;
588         l |= ( max(1, (min(256, panel->hbp))) - 1 ) << 20;
589         dispc_write_reg(DISPC_TIMING_H, l);
590
591         l = dispc_read_reg(DISPC_TIMING_V);
592         l &= ~(FLD_MASK(0, 6) | FLD_MASK(8, 8) | FLD_MASK(20, 8));
593         l |= ( max(1, (min(64,  panel->vsw))) - 1 ) << 0;
594         l |= ( max(0, (min(255, panel->vfp))) - 0 ) << 8;
595         l |= ( max(0, (min(255, panel->vbp))) - 0 ) << 20;
596         dispc_write_reg(DISPC_TIMING_V, l);
597
598         l = dispc_read_reg(DISPC_POL_FREQ);
599         l &= ~FLD_MASK(12, 6);
600         l |= (panel->config & OMAP_LCDC_SIGNAL_MASK) << 12;
601         l |= panel->acb & 0xff;
602         dispc_write_reg(DISPC_POL_FREQ, l);
603
604         calc_ck_div(is_tft, panel->pixel_clock * 1000, &lck_div, &pck_div);
605
606         l = dispc_read_reg(DISPC_DIVISOR);
607         l &= ~(FLD_MASK(16, 8) | FLD_MASK(0, 8));
608         l |= (lck_div << 16) | (pck_div << 0);
609         dispc_write_reg(DISPC_DIVISOR, l);
610
611         /* update panel info with the exact clock */
612         fck = clk_get_rate(dispc.dss1_fck);
613         panel->pixel_clock = fck / lck_div / pck_div / 1000;
614 }
615
616 int omap_dispc_request_irq(void (*callback)(void *data), void *data)
617 {
618         int r = 0;
619
620         BUG_ON(callback == NULL);
621
622         if (dispc.irq_callback)
623                 r = -EBUSY;
624         else {
625                 dispc.irq_callback = callback;
626                 dispc.irq_callback_data = data;
627         }
628
629         return r;
630 }
631 EXPORT_SYMBOL(omap_dispc_request_irq);
632
633 void omap_dispc_enable_irqs(int irq_mask)
634 {
635         dispc.enabled_irqs = irq_mask;
636         irq_mask |= DISPC_IRQ_MASK_ERROR;
637         MOD_REG_FLD(DISPC_IRQENABLE, 0x7fff, irq_mask);
638 }
639 EXPORT_SYMBOL(omap_dispc_enable_irqs);
640
641 void omap_dispc_disable_irqs(int irq_mask)
642 {
643         dispc.enabled_irqs &= ~irq_mask;
644         irq_mask &= ~DISPC_IRQ_MASK_ERROR;
645         MOD_REG_FLD(DISPC_IRQENABLE, 0x7fff, irq_mask);
646 }
647 EXPORT_SYMBOL(omap_dispc_disable_irqs);
648
649 void omap_dispc_free_irq(void)
650 {
651         omap_dispc_disable_irqs(DISPC_IRQ_MASK_ALL);
652         dispc.irq_callback = NULL;
653         dispc.irq_callback_data = NULL;
654 }
655 EXPORT_SYMBOL(omap_dispc_free_irq);
656
657 static irqreturn_t omap_dispc_irq_handler(int irq, void *dev, struct pt_regs *regs)
658 {
659         u32 stat = dispc_read_reg(DISPC_IRQSTATUS);
660         static int jabber;
661
662         DBGENTER(2);
663
664         if (stat & DISPC_IRQ_FRAMEMASK)
665                 complete(&dispc.frame_done);
666
667         if (stat & DISPC_IRQ_MASK_ERROR) {
668                 if (jabber++ < 5) {
669                         pr_err("irq error status %04x\n", stat & 0x7fff);
670                 } else {
671                         pr_err("disable irq\n");
672                         dispc_write_reg(DISPC_IRQENABLE, 0);
673                 }
674         }
675
676         if ((stat & dispc.enabled_irqs) && dispc.irq_callback)
677                 dispc.irq_callback(dispc.irq_callback_data);
678
679         dispc_write_reg(DISPC_IRQSTATUS, stat);
680
681         return IRQ_HANDLED;
682 }
683
684 static int get_dss_clocks(void)
685 {
686         if (IS_ERR((dispc.dss_ick = clk_get(dispc.fbdev->dev, "dss_ick")))) {
687                 pr_err("can't get dss_ick");
688                 return PTR_ERR(dispc.dss_ick);
689         }
690
691         if (IS_ERR((dispc.dss1_fck = clk_get(dispc.fbdev->dev, "dss1_fck")))) {
692                 pr_err("can't get dss1_fck");
693                 clk_put(dispc.dss_ick);
694                 return PTR_ERR(dispc.dss1_fck);
695         }
696
697         if (IS_ERR((dispc.dss_54m_fck =
698                                 clk_get(dispc.fbdev->dev, "dss_54m_fck")))) {
699                 pr_err("can't get dss_54m_fck");
700                 clk_put(dispc.dss_ick);
701                 clk_put(dispc.dss1_fck);
702                 return PTR_ERR(dispc.dss_54m_fck);
703         }
704
705         return 0;
706 }
707
708 static void put_dss_clocks(void)
709 {
710         clk_put(dispc.dss_54m_fck);
711         clk_put(dispc.dss1_fck);
712         clk_put(dispc.dss_ick);
713 }
714
715 static void enable_lcd_clocks(int enable)
716 {
717         if (enable) {
718                 clk_enable(dispc.dss_ick);
719                 clk_enable(dispc.dss1_fck);
720         } else {
721                 clk_disable(dispc.dss1_fck);
722                 clk_disable(dispc.dss_ick);
723         }
724 }
725
726 static void enable_digit_clocks(int enable)
727 {
728         if (enable)
729                 clk_enable(dispc.dss_54m_fck);
730         else
731                 clk_disable(dispc.dss_54m_fck);
732 }
733
734 static void omap_dispc_suspend(void)
735 {
736         DBGENTER(1);
737
738         if (dispc.update_mode == OMAPFB_AUTO_UPDATE) {
739                 init_completion(&dispc.frame_done);
740                 omap_dispc_enable_lcd_out(0);
741                 if (!wait_for_completion_timeout(&dispc.frame_done,
742                                 msecs_to_jiffies(500))) {
743                         pr_err("timeout waiting for FRAME DONE\n");
744                 }
745                 enable_lcd_clocks(0);
746         }
747
748         DBGLEAVE(1);
749 }
750
751 static void omap_dispc_resume(void)
752 {
753         DBGENTER(1);
754
755         if (dispc.update_mode == OMAPFB_AUTO_UPDATE) {
756                 enable_lcd_clocks(1);
757                 set_lcd_timings();
758                 load_palette();
759                 omap_dispc_enable_lcd_out(1);
760         }
761
762         DBGLEAVE(1);
763 }
764
765
766 static int omap_dispc_update_window(struct omapfb_update_window *win,
767                                  void (*complete_callback)(void *arg),
768                                  void *complete_callback_data)
769 {
770         return dispc.update_mode == OMAPFB_UPDATE_DISABLED ? -ENODEV : 0;
771 }
772
773 /* Greatest common divisor */
774 static int calc_gcd(int a, int b)
775 {
776         int tmp;
777
778         if (a < b) {
779                 tmp = a;
780                 a = b;
781                 b = tmp;
782         }
783         for (;;) {
784                 tmp = a % b;
785                 if (tmp != 0) {
786                         a = b;
787                         b = tmp;
788                 } else
789                         break;
790         }
791
792         return b;
793 }
794
795 /* Least common multiple */
796 static int calc_lcm(int a, int b)
797 {
798         return a * b / calc_gcd(a, b);
799 }
800
801 static void omap_dispc_get_vram_layout(unsigned long *size, void **virt,
802                                         dma_addr_t *phys)
803 {
804         *size = dispc.fb_sram_size + dispc.fb_sdram_size;
805         *virt = dispc.fb_kern_vaddr;
806         /* Physical vram might not be contiguous. No one except own mmap
807          * should use this addr.
808          */
809         *phys = 0;
810 }
811
812 static int omap_dispc_mmap_user(struct vm_area_struct *vma)
813 {
814         unsigned long len;
815         unsigned long offset;
816         unsigned long vaddr;
817         int r;
818
819         DBGPRINT(1, "vm_pgoff 0x%08lx vm_start 0x%08lx vm_end 0x%08lx\n",
820                         vma->vm_pgoff, vma->vm_start, vma->vm_end);
821
822         if (vma->vm_pgoff > (~0UL >> PAGE_SHIFT))
823                 return -EINVAL;
824         offset = vma->vm_pgoff << PAGE_SHIFT;
825
826         if (offset >= dispc.fb_sram_size + dispc.fb_sdram_size)
827                 return -EINVAL;
828
829         len = vma->vm_end - vma->vm_start;
830         if (offset + len > dispc.fb_sram_size + dispc.fb_sdram_size)
831                 return -EINVAL;
832
833         vma->vm_page_prot = pgprot_writecombine(vma->vm_page_prot);
834         vma->vm_flags |= VM_PFNMAP;
835
836         vaddr = vma->vm_start;
837
838         if (dispc.fb_sram_size) {
839                 if (offset < dispc.fb_sram_size) {
840                         int chunk = min_t(int, dispc.fb_sram_size - offset, len);
841                         DBGPRINT(1, "map sram va %08lx pa %08lx size %d\n",
842                                  vaddr, dispc.fb_sram_paddr + offset, chunk);
843                         r = io_remap_pfn_range(vma, vaddr,
844                                            (dispc.fb_sram_paddr +
845                                            offset) >> PAGE_SHIFT, chunk,
846                                            vma->vm_page_prot);
847                         if (r == -EINVAL)
848                                 return r;
849                         if (r < 0)
850                                 return -EAGAIN;
851
852                         vaddr += chunk;
853                         len -= chunk;
854                         offset = 0;
855                 } else
856                         offset -= dispc.fb_sram_size;
857         }
858
859         if (len) {
860                 DBGPRINT(1, "map sdram va %08lx pa %08lx size %ld\n",
861                                  vaddr, dispc.fb_sdram_paddr + offset, len);
862                 BUG_ON(offset > dispc.fb_sdram_size ||
863                         offset + len > dispc.fb_sdram_size ||
864                         vma->vm_end - vaddr != len);
865                 r = io_remap_pfn_range(vma, vaddr, (dispc.fb_sdram_paddr +
866                                    offset) >> PAGE_SHIFT, len,
867                                    vma->vm_page_prot);
868                 /* no teardown of the previous mapping here.
869                  * do_mmap_pgoff will take core of that. */
870                 if (r == -EINVAL)
871                         return r;
872                 if (r < 0)
873                         return -EAGAIN;
874         }
875
876         return 0;
877 }
878
879 static int mmap_kern(void)
880 {
881         struct vm_struct        *kvma;
882         struct vm_area_struct   vma;
883         pgprot_t                pgprot;
884         unsigned long           vaddr;
885
886         DBGENTER(1);
887
888         kvma = get_vm_area(dispc.fb_sram_size + dispc.fb_sdram_size, VM_IOREMAP);
889         if (kvma == NULL) {
890                 pr_err("can't get kernel vm area\n");
891                 return -ENOMEM;
892         }
893         vma.vm_mm = &init_mm;
894
895         dispc.fb_kern_vaddr = kvma->addr;
896         vaddr = (unsigned long)kvma->addr;
897
898         pgprot = pgprot_writecombine(pgprot_kernel);
899         if (dispc.fb_sram_size) {
900                 vma.vm_start = vaddr;
901                 vma.vm_end = vaddr + dispc.fb_sram_size;
902                 if (io_remap_pfn_range(&vma, vaddr,
903                                    dispc.fb_sram_paddr >> PAGE_SHIFT,
904                                    dispc.fb_sram_size, pgprot) < 0) {
905                         pr_err("kernel mmap for FBMEM failed\n");
906                         return -EAGAIN;
907                 }
908                 vaddr += dispc.fb_sram_size;
909         }
910         if (dispc.fb_sdram_size) {
911                 vma.vm_start = vaddr;
912                 vma.vm_end = vaddr + dispc.fb_sdram_size;
913                 if (io_remap_pfn_range(&vma, vaddr,
914                                    dispc.fb_sdram_paddr >> PAGE_SHIFT,
915                                    dispc.fb_sdram_size, pgprot) < 0) {
916                         pr_err("kernel mmap for FBMEM failed\n");
917                         return -EAGAIN;
918                 }
919         }
920
921         DBGLEAVE(1);
922
923         return 0;
924 }
925
926 static void unmap_kern(void)
927 {
928         vunmap(dispc.fb_kern_vaddr);
929 }
930
931 static int alloc_palette_ram(void)
932 {
933         dispc.palette_vaddr = dma_alloc_writecombine(dispc.fbdev->dev,
934                 MAX_PALETTE_SIZE, &dispc.palette_paddr, GFP_KERNEL);
935         if (dispc.palette_vaddr == NULL) {
936                 pr_err("failed to alloc palette memory\n");
937                 return -ENOMEM;
938         }
939
940         return 0;
941 }
942
943 static void free_palette_ram(void)
944 {
945         dma_free_writecombine(dispc.fbdev->dev, MAX_PALETTE_SIZE,
946                         dispc.palette_vaddr, dispc.palette_paddr);
947 }
948
949 static int alloc_fbmem(int req_size)
950 {
951         int frame_size;
952         struct lcd_panel *panel = dispc.fbdev->panel;
953
954         frame_size = PAGE_ALIGN(panel->x_res * panel->bpp / 8 * panel->y_res);
955         if (req_size > frame_size)
956                 frame_size = req_size;
957         dispc.fb_sdram_size = PAGE_ALIGN(MAX_PALETTE_SIZE) + frame_size;
958         dispc.fb_kern_vaddr = dma_alloc_writecombine(dispc.fbdev->dev,
959                         dispc.fb_sdram_size, &dispc.fb_sdram_paddr, GFP_KERNEL);
960
961         if (dispc.fb_kern_vaddr == 0) {
962                 pr_err("unable to allocate fb DMA memory\n");
963                 return -ENOMEM;
964         }
965
966         return 0;
967 }
968
969 static void free_fbmem(void)
970 {
971         dma_free_writecombine(dispc.fbdev->dev, dispc.fb_sdram_size,
972                               dispc.fb_kern_vaddr, dispc.fb_sdram_paddr);
973 }
974
975 static int setup_fbmem(int req_size)
976 {
977         struct lcd_panel *panel = dispc.fbdev->panel;
978         struct omapfb_platform_data *conf;
979         unsigned long size_align;
980         int line_size;
981         int frame_size;
982         int lines;
983         int r;
984
985         conf = dispc.fbdev->dev->platform_data;
986
987         if (conf->fbmem.fb_sram_size + conf->fbmem.fb_sdram_size == 0) {
988                 if ((r = alloc_fbmem(req_size)) < 0)
989                         return r;
990                 dispc.fbmem_allocated = 1;
991                 dispc.fb_sdram_lines = panel->y_res;
992                 return 0;
993         }
994
995         dispc.fb_sram_paddr = conf->fbmem.fb_sram_start;
996         dispc.fb_sram_size = conf->fbmem.fb_sram_size;
997         dispc.fb_sdram_paddr = conf->fbmem.fb_sdram_start;
998         dispc.fb_sdram_size = conf->fbmem.fb_sdram_size;
999
1000         line_size = panel->x_res * panel->bpp / 8;
1001         frame_size = PAGE_ALIGN(line_size * panel->y_res);
1002
1003         size_align = calc_lcm(line_size, PAGE_SIZE);
1004
1005         if (dispc.fb_sram_size + dispc.fb_sdram_size < frame_size ||
1006             (dispc.fb_sdram_size && (dispc.fb_sram_size % size_align))) {
1007                 pr_err("Invalid FB memory configuration\n");
1008                 return -EINVAL;
1009         }
1010
1011         if (dispc.fb_sram_size + dispc.fb_sdram_size < req_size) {
1012                 pr_err("%d vram was requested, but only %u is available\n",
1013                         req_size, dispc.fb_sram_size + dispc.fb_sdram_size);
1014         }
1015
1016         lines = dispc.fb_sram_size / line_size;
1017         lines = min_t(int, panel->y_res, lines);
1018         dispc.fb_sram_lines = lines;
1019         lines = panel->y_res - lines;
1020         dispc.fb_sdram_lines = lines;
1021
1022         if ((r = mmap_kern()) < 0)
1023                 return r;
1024
1025         DBGPRINT(1, "fb_sram %08x size %08x fb_sdram %08x size %08x\n",
1026                  dispc.fb_sram_paddr, dispc.fb_sram_size,
1027                  dispc.fb_sdram_paddr, dispc.fb_sdram_size);
1028
1029         return 0;
1030 }
1031
1032 static void cleanup_fbmem(void)
1033 {
1034         if (dispc.fbmem_allocated)
1035                 free_fbmem();
1036         else
1037                 unmap_kern();
1038 }
1039
1040 static int omap_dispc_init(struct omapfb_device *fbdev, int ext_mode,
1041                            int req_vram_size)
1042 {
1043         int r;
1044         u32 l;
1045         struct lcd_panel *panel = fbdev->panel;
1046         int tmo = 10000;
1047         int skip_init = 0;
1048
1049         DBGENTER(1);
1050
1051         memset(&dispc, 0, sizeof(dispc));
1052
1053         dispc.base = io_p2v(DISPC_BASE);
1054         dispc.fbdev = fbdev;
1055         dispc.ext_mode = ext_mode;
1056
1057         dispc.multiplane_head = -1;
1058
1059         if (fbdev->dev->platform_data == NULL) {
1060                 pr_err("missing FB configuration\n");
1061                 return -ENOENT;
1062         }
1063
1064         init_completion(&dispc.frame_done);
1065
1066         if ((r = get_dss_clocks()) < 0)
1067                 return r;
1068
1069         enable_lcd_clocks(1);
1070
1071         l = dispc_read_reg(DISPC_REVISION);
1072         pr_info(MODULE_NAME ": version %d.%d\n", l >> 4 & 0x0f, l & 0x0f);
1073
1074 #ifdef CONFIG_FB_OMAP_BOOTLOADER_INIT
1075         l = dispc_read_reg(DISPC_CONTROL);
1076         /* LCD enabled ? */
1077         if (l & 1) {
1078                 pr_info(MODULE_NAME ": skipping hardware initialization\n");
1079                 skip_init = 1;
1080         }
1081 #endif
1082
1083         if (!skip_init) {
1084                 /* Reset monitoring works only w/ the 54M clk */
1085                 enable_digit_clocks(1);
1086
1087                 /* Soft reset */
1088                 MOD_REG_FLD(DISPC_SYSCONFIG, 1 << 1, 1 << 1);
1089
1090                 while (!(dispc_read_reg(DISPC_SYSSTATUS) & 1)) {
1091                         if (!--tmo) {
1092                                 pr_err("soft reset failed\n");
1093                                 r = -ENODEV;
1094                                 enable_digit_clocks(0);
1095                                 goto fail1;
1096                         }
1097                 }
1098
1099                 enable_digit_clocks(0);
1100         }
1101
1102         l = dispc_read_reg(DISPC_IRQSTATUS);
1103         dispc_write_reg(l, DISPC_IRQSTATUS);
1104
1105         /* Enable those that we handle always */
1106         omap_dispc_enable_irqs(DISPC_IRQ_FRAMEMASK);
1107
1108         if ((r = request_irq(INT_24XX_DSS_IRQ, omap_dispc_irq_handler,
1109                            0, MODULE_NAME, NULL)) < 0) {
1110                 pr_err("can't get DSS IRQ\n");
1111                 goto fail1;
1112         }
1113
1114         /* L3 firewall setting: enable access to OCM RAM */
1115         __raw_writel(0x402000b0, io_p2v(0x680050a0));
1116
1117         if ((r = alloc_palette_ram()) < 0)
1118                 goto fail2;
1119
1120         if ((r = setup_fbmem(req_vram_size)) < 0)
1121                 goto fail3;
1122
1123         if (!skip_init) {
1124                 memset(dispc.fb_kern_vaddr, 0,
1125                         dispc.fb_sram_size + dispc.fb_sdram_size);
1126
1127                 /* Set logic clock to fck, pixel clock to fck/2 for now */
1128                 MOD_REG_FLD(DISPC_DIVISOR, FLD_MASK(16, 8), 1 << 16);
1129                 MOD_REG_FLD(DISPC_DIVISOR, FLD_MASK(0, 8), 2 << 0);
1130
1131                 setup_plane_fifo(0);
1132                 setup_plane_fifo(1);
1133                 setup_plane_fifo(2);
1134
1135                 set_lcd_tft_mode(panel->config & OMAP_LCDC_PANEL_TFT);
1136                 set_lcd_data_lines(panel->data_lines);
1137                 set_load_mode(DISPC_LOAD_FRAME_ONLY);
1138
1139                 if (!ext_mode) {
1140                         omap_dispc_set_lcd_size(panel->x_res, panel->y_res);
1141                         set_lcd_timings();
1142                 }
1143                 enable_rfbi_mode(ext_mode);
1144         }
1145
1146         return 0;
1147 fail3:
1148         free_palette_ram();
1149 fail2:
1150         free_irq(INT_24XX_DSS_IRQ, NULL);
1151 fail1:
1152         enable_lcd_clocks(0);
1153         put_dss_clocks();
1154
1155         return r;
1156 }
1157
1158 static void omap_dispc_cleanup(void)
1159 {
1160         cleanup_fbmem();
1161         free_palette_ram();
1162         free_irq(INT_24XX_DSS_IRQ, NULL);
1163         enable_lcd_clocks(0);
1164         put_dss_clocks();
1165 }
1166
1167 static unsigned long omap_dispc_get_caps(void)
1168 {
1169         return 0;
1170 }
1171
1172 struct lcd_ctrl omap2_int_ctrl = {
1173         .name                   = "internal",
1174         .init                   = omap_dispc_init,
1175         .cleanup                = omap_dispc_cleanup,
1176         .get_vram_layout        = omap_dispc_get_vram_layout,
1177         .mmap                   = omap_dispc_mmap_user,
1178         .get_caps               = omap_dispc_get_caps,
1179         .set_update_mode        = omap_dispc_set_update_mode,
1180         .get_update_mode        = omap_dispc_get_update_mode,
1181         .update_window          = omap_dispc_update_window,
1182         .suspend                = omap_dispc_suspend,
1183         .resume                 = omap_dispc_resume,
1184         .setup_plane            = omap_dispc_setup_plane,
1185         .enable_plane           = omap_dispc_enable_plane,
1186         .set_color_key          = omap_dispc_set_color_key,
1187 };
1188
1189 MODULE_DESCRIPTION("TI OMAP LCDC controller");
1190 MODULE_LICENSE("GPL");