]> www.pilppa.org Git - linux-2.6-omap-h63xx.git/blob - drivers/video/omap/omap_lcdc.c
fdc3af2cdadc7213829012fabc1d7e7422860932
[linux-2.6-omap-h63xx.git] / drivers / video / omap / omap_lcdc.c
1 /*
2  * linux/arch/arm/mach-omap/omap_lcdc.c
3  *
4  * OMAP internal LCD controller
5  *
6  * Copyright (C) 2004 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/config.h>
25 #include <linux/module.h>
26 #include <linux/device.h>
27 #include <linux/interrupt.h>
28 #include <linux/spinlock.h>
29 #include <linux/err.h>
30 #include <linux/mm.h>
31 #include <linux/fb.h>
32
33 #include <asm/arch/dma.h>
34 #include <asm/mach-types.h>
35 #include <asm/hardware/clock.h>
36
37 #include "omapfb.h"
38 #include "debug.h"
39
40 #define OMAP_LCDC_BASE                  0xfffec000
41 #define OMAP_LCDC_SIZE                  256
42 #define OMAP_LCDC_IRQ                   INT_LCD_CTRL
43
44 #define OMAP_LCDC_CONTROL               (OMAP_LCDC_BASE + 0x00)
45 #define OMAP_LCDC_TIMING0               (OMAP_LCDC_BASE + 0x04)
46 #define OMAP_LCDC_TIMING1               (OMAP_LCDC_BASE + 0x08)
47 #define OMAP_LCDC_TIMING2               (OMAP_LCDC_BASE + 0x0c)
48 #define OMAP_LCDC_STATUS                (OMAP_LCDC_BASE + 0x10)
49 #define OMAP_LCDC_SUBPANEL              (OMAP_LCDC_BASE + 0x14)
50 #define OMAP_LCDC_LINE_INT              (OMAP_LCDC_BASE + 0x18)
51 #define OMAP_LCDC_DISPLAY_STATUS        (OMAP_LCDC_BASE + 0x1c)
52
53 #define OMAP_LCDC_STAT_DONE             (1 << 0)
54 #define OMAP_LCDC_STAT_VSYNC            (1 << 1)
55 #define OMAP_LCDC_STAT_SYNC_LOST        (1 << 2)
56 #define OMAP_LCDC_STAT_ABC              (1 << 3)
57 #define OMAP_LCDC_STAT_LINE_INT         (1 << 4)
58 #define OMAP_LCDC_STAT_FUF              (1 << 5)
59 #define OMAP_LCDC_STAT_LOADED_PALETTE   (1 << 6)
60
61 #define OMAP_LCDC_CTRL_LCD_EN           (1 << 0)
62 #define OMAP_LCDC_CTRL_LCD_TFT          (1 << 7)
63 #define OMAP_LCDC_CTRL_LINE_IRQ_CLR_SEL (1 << 10)
64
65 #define OMAP_LCDC_IRQ_VSYNC             (1 << 2)
66 #define OMAP_LCDC_IRQ_DONE              (1 << 3)
67 #define OMAP_LCDC_IRQ_LOADED_PALETTE    (1 << 4)
68 #define OMAP_LCDC_IRQ_LINE_NIRQ         (1 << 5)
69 #define OMAP_LCDC_IRQ_LINE              (1 << 6)
70 #define OMAP_LCDC_IRQ_MASK              (((1 << 5) - 1) << 2)
71
72 #define MAX_PALETTE_SIZE                PAGE_SIZE
73
74 enum lcdc_load_mode {
75         OMAP_LCDC_LOAD_PALETTE,
76         OMAP_LCDC_LOAD_FRAME,
77         OMAP_LCDC_LOAD_PALETTE_AND_FRAME
78 };
79
80 static struct omap_lcd_controller {
81         enum fb_update_mode     update_mode;
82         unsigned int            irq_mask;
83         struct completion       last_frame_complete;
84         struct completion       palette_load_complete;
85         struct clk              *lcd_ck;
86 } omap_lcdc;
87
88 static void inline enable_irqs(int mask)
89 {
90         omap_lcdc.irq_mask |= mask;
91 }
92
93 static void inline disable_irqs(int mask)
94 {
95         omap_lcdc.irq_mask &= ~mask;
96 }
97
98 static void set_load_mode(enum lcdc_load_mode mode)
99 {
100         u32 l;
101
102         l = omap_readl(OMAP_LCDC_CONTROL);
103         l &= ~(3 << 20);
104         switch (mode) {
105         case OMAP_LCDC_LOAD_PALETTE:
106                 l |= 1 << 20;
107                 break;
108         case OMAP_LCDC_LOAD_FRAME:
109                 l |= 2 << 20;
110                 break;
111         case OMAP_LCDC_LOAD_PALETTE_AND_FRAME:
112                 break;
113         default:
114                 BUG();
115         }
116         omap_writel(l, OMAP_LCDC_CONTROL);
117 }
118
119 static void enable_controller(void)
120 {
121         u32 l;
122
123         l = omap_readl(OMAP_LCDC_CONTROL);
124         l |= OMAP_LCDC_CTRL_LCD_EN;
125         l &= ~OMAP_LCDC_IRQ_MASK;
126         l |= omap_lcdc.irq_mask | OMAP_LCDC_IRQ_DONE;   /* enabled IRQs */
127         omap_writel(l, OMAP_LCDC_CONTROL);
128 }
129
130 static void disable_controller_async(void)
131 {
132         u32 l;
133         u32 mask;
134
135         init_completion(&omap_lcdc.last_frame_complete);
136         l = omap_readl(OMAP_LCDC_CONTROL);
137         mask = OMAP_LCDC_CTRL_LCD_EN | OMAP_LCDC_IRQ_MASK;
138         /* Preserve the DONE mask, since we still want to get the
139          * final DONE irq. It will be disabled in the IRQ handler.
140          */
141         mask &= ~OMAP_LCDC_IRQ_DONE;
142         l &= ~mask;
143         omap_writel(l, OMAP_LCDC_CONTROL);
144 }
145
146 static void last_frame_timeout(unsigned long data)
147 {
148         printk(KERN_ERR "omap_lcdc: timeout waiting for DONE flag\n");
149         complete(&omap_lcdc.last_frame_complete);
150 }
151
152 static void inline wait_for_frame_done(void)
153 {
154         struct timer_list timeout;
155
156         init_timer(&timeout);
157         timeout.function = last_frame_timeout;
158         timeout.expires = jiffies + msecs_to_jiffies(500);
159         add_timer(&timeout);
160         wait_for_completion(&omap_lcdc.last_frame_complete);
161         del_timer_sync(&timeout);
162 }
163
164 static void disable_controller(void)
165 {
166         disable_controller_async();
167         wait_for_frame_done();
168 }
169
170 static void reset_controller(u32 status)
171 {
172         static unsigned long reset_count = 0;
173         static unsigned long last_jiffies = 0;
174
175         disable_controller_async();
176         reset_count++;
177         if (reset_count == 1 ||
178             time_after(jiffies, last_jiffies + HZ)) {
179                 printk(KERN_ERR "omap_lcdc: resetting "
180                                  "(status %#010x,reset count %lu)\n",
181                                   status, reset_count);
182                 last_jiffies = jiffies;
183         }
184         if (reset_count < 100) {
185                 enable_controller();
186         } else {
187                 reset_count = 0;
188                 printk(KERN_ERR "omap_lcdc: too many reset attempts, "
189                                 "giving up.\n");
190         }
191 }
192
193 /* Configure the LCD DMA according to the current mode specified by parameters
194  * in fbdev and fbdev->var.
195  */
196 static void setup_lcd_dma(struct omapfb_device *fbdev)
197 {
198         static const int dma_elem_type[] = {
199                 0,
200                 OMAP_DMA_DATA_TYPE_S8,
201                 OMAP_DMA_DATA_TYPE_S16,
202                 0,
203                 OMAP_DMA_DATA_TYPE_S32,
204         };
205         struct fb_var_screeninfo *var = &fbdev->fb_info->var;
206         unsigned long   src;
207         int             esize, xelem, yelem;
208
209         src = fbdev->lcddma_handle + fbdev->vis_frame_org + fbdev->view_org;
210         switch (var->rotate) {
211         case 0:
212                 esize = fbdev->mirror || (src & 3) ? 2 : 4;
213                 xelem = var->xres * var->bits_per_pixel / 8 / esize;
214                 yelem = var->yres;
215                 break;
216         case 90:
217         case 180:
218         case 270:
219                 esize = 2;
220                 xelem = var->xres * var->bits_per_pixel / 16;
221                 yelem = var->yres;
222                 break;
223         default:
224                 BUG();
225                 return;
226         }
227         DBGPRINT(1, "setup_dma: src=%#010x esize=%d xelem=%d yelem=%d\n",
228                  src, esize, xelem, yelem);
229         omap_set_lcd_dma_b1(src, xelem, yelem, dma_elem_type[esize]);
230         omap_set_lcd_dma_single_transfer(0);
231         if (!cpu_is_omap1510()) {
232                 /* Set virtual xres elem size */
233                 omap_set_lcd_dma_b1_vxres(
234                         fbdev->fb_info->fix.line_length / esize);
235                 /* Setup transformations */
236                 omap_set_lcd_dma_b1_rotation(var->rotate);
237                 omap_set_lcd_dma_b1_mirror(fbdev->mirror);
238                 omap_set_lcd_dma_b1_scale(fbdev->xscale, fbdev->yscale);
239         }
240         omap_setup_lcd_dma();
241 }
242
243 static irqreturn_t lcdc_irq_handler(int irq, void *dev_id,
244                                          struct pt_regs *fp)
245 {
246         u32 status;
247
248         status = omap_readl(OMAP_LCDC_STATUS);
249
250         if (status & (OMAP_LCDC_STAT_FUF | OMAP_LCDC_STAT_SYNC_LOST))
251                 reset_controller(status);
252         else {
253                 if (status & OMAP_LCDC_STAT_DONE) {
254                         u32 l;
255
256                         /* Disable IRQ_DONE. The status bit will be cleared
257                          * only when the controller is reenabled and we don't
258                          * want to get more interrupts.
259                          */
260                         l = omap_readl(OMAP_LCDC_CONTROL);
261                         l &= ~OMAP_LCDC_IRQ_DONE;
262                         omap_writel(l, OMAP_LCDC_CONTROL);
263                         complete(&omap_lcdc.last_frame_complete);
264                 }
265                 if (status & OMAP_LCDC_STAT_LOADED_PALETTE) {
266                         disable_controller_async();
267                         complete(&omap_lcdc.palette_load_complete);
268                 }
269         }
270
271         /* Clear these interrupt status bits.
272          * Sync_lost, FUF bits were cleared by disabling the LCD controller
273          * LOADED_PALETTE can be cleared this way only in palette only
274          * load mode. In other load modes it's cleared by disabling the
275          * controller.
276          */
277         status &= ~(OMAP_LCDC_STAT_VSYNC |
278                     OMAP_LCDC_STAT_LOADED_PALETTE |
279                     OMAP_LCDC_STAT_ABC |
280                     OMAP_LCDC_STAT_LINE_INT);
281         omap_writel(status, OMAP_LCDC_STATUS);
282         return IRQ_HANDLED;
283 }
284
285 /* Change to a new video mode. We defer this to a later time to avoid any
286  * flicker and not to mess up the current LCD DMA context. For this we disable
287  * the LCD controler, which will generate a DONE irq after the last frame has
288  * been transferred. Then it'll be safe to reconfigure both the LCD controller
289  * as well as the LCD DMA.
290  */
291 static void omap_lcdc_change_mode(struct omapfb_device *fbdev)
292 {
293         DBGENTER(1);
294
295         omap_stop_lcd_dma();
296         disable_controller();
297         setup_lcd_dma(fbdev);
298         enable_controller();
299
300         DBGLEAVE(1);
301 }
302
303 /* Configure the LCD DMA for a palette load operation and do the palette
304  * downloading synchronously. We don't use the frame+palette load mode of
305  * the controller, since the palette can always be downloaded seperately.
306  */
307 static void load_palette(struct omapfb_device *fbdev)
308 {
309         u8              *palette;
310         u32             code;
311         unsigned long   size;
312         unsigned long   palette_org;
313
314         DBGENTER(1);
315
316         switch (fbdev->panel->video_mode->bpp) {
317         case 1:
318                 /* 0 is already set */
319                 code = 0;
320                 size = 256;
321                 break;
322         case 2:
323                 code = 0x1000;
324                 size = 256;
325                 break;
326         case 4:
327                 code = 0x2000;
328                 size = 256;
329                 break;
330         case 8:
331                 code = 0x3000;
332                 size = 256;
333                 break;
334         case 12:
335         case 16:
336                 code = 0x4000;
337                 size = 32;
338                 break;
339         default:
340                 BUG();
341                 return;
342         }
343         palette_org = MAX_PALETTE_SIZE - size;
344         palette = fbdev->lcddma_base + palette_org;
345         memset(palette, 0, size);
346         *(u32 *)palette = code;
347
348         omap_set_lcd_dma_b1(fbdev->lcddma_handle + palette_org,
349                             size / 4 + 1, 1, OMAP_DMA_DATA_TYPE_S32);
350         omap_set_lcd_dma_single_transfer(1);
351         omap_setup_lcd_dma();
352
353         init_completion(&omap_lcdc.palette_load_complete);
354         enable_irqs(OMAP_LCDC_IRQ_LOADED_PALETTE);
355         set_load_mode(OMAP_LCDC_LOAD_PALETTE);
356         enable_controller();
357         wait_for_completion(&omap_lcdc.palette_load_complete);
358         /* The controller gets disabled in the irq handler */
359         disable_irqs(OMAP_LCDC_IRQ_LOADED_PALETTE);
360         omap_stop_lcd_dma();
361
362         DBGLEAVE(1);
363 }
364
365 static void inline setup_regs(struct omapfb_device *fbdev)
366 {
367         u32 l;
368         struct lcdc_video_mode *mode = fbdev->panel->video_mode;
369         int tft = fbdev->panel->config & LCD_PANEL_TFT;
370         int signal_levels = fbdev->panel->signals;
371
372         l = omap_readl(OMAP_LCDC_CONTROL);
373         l &= ~OMAP_LCDC_CTRL_LCD_TFT;
374         l |= tft ? OMAP_LCDC_CTRL_LCD_TFT : 0;
375         omap_writel(l, OMAP_LCDC_CONTROL);
376
377         l = omap_readl(OMAP_LCDC_TIMING2);
378         l &= ~(((1 << 6) - 1) << 20);
379         l |= signal_levels << 20;
380         omap_writel(l, OMAP_LCDC_TIMING2);
381
382         l = mode->x_res - 1;
383         l |= (mode->hsw - 1) << 10;
384         l |= (mode->hfp - 1) << 16;
385         l |= (mode->hbp - 1) << 24;
386         omap_writel(l, OMAP_LCDC_TIMING0);
387
388         l = mode->y_res - 1;
389         l |= (mode->vsw - 1) << 10;
390         l |= mode->vfp << 16;
391         l |= mode->vbp << 24;
392         omap_writel(l, OMAP_LCDC_TIMING1);
393
394         l = omap_readl(OMAP_LCDC_TIMING2);
395         l &= ~0xff;
396
397         if (!cpu_is_omap730())
398                 l |= mode->pcd;
399
400         if (machine_is_omap_perseus2()) {
401                 u32 clock1, clock2;
402                 int pcd;
403
404                 clock1 = mode->pixel_clock * 1000;
405                 clock2 = clk_get_rate(omap_lcdc.lcd_ck);
406
407                 if (clock1 != 0) {
408                         pcd = clock2 / clock1;
409                         if (pcd > 255)
410                                 pcd = 0;
411                 } else {
412                         pcd = 0;
413                 }
414                 
415                 if (pcd == 0)
416                         l |= mode->pcd;
417                 else
418                         l |= pcd;
419
420 //              printk("%% ck1: %d  ck2: %d  pcd: %d %%\n",clock1, clock2, pcd);        
421         }
422
423         l |= mode->acb << 8;
424         if (mode->flags & OMAP_LCDC_INV_PIX_CLOCK)
425                 l |= 1 << 22;
426         omap_writel(l, OMAP_LCDC_TIMING2);
427 }
428
429 /* Configure the LCD controller, download the color palette and start a looped
430  * DMA transfer of the frame image data. */
431 static int omap_lcdc_set_update_mode(struct omapfb_device *fbdev,
432                                      enum fb_update_mode mode)
433 {
434         int r = 0;
435
436         DBGENTER(1);
437
438         if (mode != omap_lcdc.update_mode) {
439                 switch (mode) {
440                 case FB_AUTO_UPDATE:
441                         setup_regs(fbdev);
442                         load_palette(fbdev);
443
444                         /* Setup and start LCD DMA */
445                         setup_lcd_dma(fbdev);
446
447                         set_load_mode(OMAP_LCDC_LOAD_FRAME);
448                         enable_irqs(OMAP_LCDC_IRQ_DONE);
449                         /* This will start the actual DMA transfer */
450                         enable_controller();
451                         omap_lcdc.update_mode = mode;
452                         break;
453                 case FB_UPDATE_DISABLED:
454                         disable_controller();
455                         omap_stop_lcd_dma();
456                         omap_lcdc.update_mode = mode;
457                         break;
458                 default:
459                         r = -EINVAL;
460                 }
461         }       
462
463         DBGLEAVE(1);
464         return r;
465 }
466
467 static enum fb_update_mode omap_lcdc_get_update_mode(struct omapfb_device *fbdev)
468 {
469         return omap_lcdc.update_mode;
470 }
471
472 static void omap_lcdc_suspend(struct omapfb_device *fbdev)
473 {
474         if (omap_lcdc.update_mode == FB_AUTO_UPDATE) {
475                 disable_controller();
476                 omap_stop_lcd_dma();
477         }
478 }
479
480 static void omap_lcdc_resume(struct omapfb_device *fbdev)
481 {
482         if (omap_lcdc.update_mode == FB_AUTO_UPDATE) {
483                 setup_regs(fbdev);
484                 load_palette(fbdev);
485                 setup_lcd_dma(fbdev);
486                 set_load_mode(OMAP_LCDC_LOAD_FRAME);
487                 enable_irqs(OMAP_LCDC_IRQ_DONE);
488                 enable_controller();
489         }
490 }
491
492 static int omap_lcdc_init(struct omapfb_device *fbdev)
493 {
494         int r;
495         u32 l;
496         int rate;
497         struct clk *tc_ck;
498
499         DBGENTER(1);
500
501         omap_lcdc.irq_mask = 0;
502
503         l = 0;
504         omap_writel(l, OMAP_LCDC_CONTROL);
505
506         /* FIXME:
507          * According to errata some platforms have a clock rate limitiation
508          */
509         omap_lcdc.lcd_ck = clk_get(NULL, "lcd_ck");
510         if (IS_ERR(omap_lcdc.lcd_ck)) {
511                 printk(KERN_ERR "omap_lcdc: unable to access LCD clock\n");
512                 r = PTR_ERR(omap_lcdc.lcd_ck);
513                 goto fail0;
514         }
515
516         tc_ck = clk_get(NULL, "tc_ck");
517         if (IS_ERR(tc_ck)) {
518                 printk(KERN_ERR "omap_lcdc: unable to access TC clock\n");
519                 r = PTR_ERR(tc_ck);
520                 goto fail1;
521         }
522
523         rate = clk_get_rate(tc_ck);
524         clk_put(tc_ck);
525
526         if (machine_is_omap_h3())
527                 rate /= 3;
528         r = clk_set_rate(omap_lcdc.lcd_ck, rate);
529         if (r) {
530                 printk(KERN_ERR "omap_lcdc: failed to adjust LCD rate\n");
531                 goto fail1;
532         }
533         clk_use(omap_lcdc.lcd_ck);
534
535         r = request_irq(OMAP_LCDC_IRQ, lcdc_irq_handler, 0, "omap-lcdc", fbdev);
536         if (r) {
537                 printk(KERN_ERR "omap_lcdc: unable to get IRQ\n");
538                 goto fail2;
539         }
540
541         r = omap_request_lcd_dma(NULL, NULL);
542         if (r) {
543                 printk(KERN_ERR "omap_lcdc: unable to get LCD DMA\n");
544                 goto fail3;
545         }
546
547         printk(KERN_INFO "OMAP LCD controller initialized.\n");
548         DBGLEAVE(1);
549         return 0;
550 fail3:
551         free_irq(OMAP_LCDC_IRQ, fbdev);
552 fail2:
553         clk_unuse(omap_lcdc.lcd_ck);
554 fail1:
555         clk_put(omap_lcdc.lcd_ck);
556 fail0:
557         DBGLEAVE(1);
558         return r;
559 }
560
561 static void omap_lcdc_cleanup(struct omapfb_device *fbdev)
562 {
563         omap_free_lcd_dma();
564         free_irq(OMAP_LCDC_IRQ, fbdev);
565         clk_unuse(omap_lcdc.lcd_ck);
566         clk_put(omap_lcdc.lcd_ck);
567 }
568
569 static void omap_lcdc_get_mem_layout(struct omapfb_device *fbdev,
570                                      unsigned long *size, unsigned long *fb_org)
571 {
572         struct lcdc_video_mode *mode = fbdev->panel->video_mode;
573
574         *size = MAX_PALETTE_SIZE;
575         *fb_org = *size;
576         *size += mode->x_res * mode->bpp / 8 * mode->y_res;
577 }
578
579 static unsigned long omap_lcdc_get_caps(struct omapfb_device *fbdev)
580 {
581         return 0;
582 }
583
584 struct lcd_ctrl omapfb_lcdc_ctrl = {
585         .name                   = "internal",
586         .init                   = omap_lcdc_init,
587         .cleanup                = omap_lcdc_cleanup,
588         .get_mem_layout         = omap_lcdc_get_mem_layout,
589         .get_caps               = omap_lcdc_get_caps,
590         .set_update_mode        = omap_lcdc_set_update_mode,
591         .get_update_mode        = omap_lcdc_get_update_mode,
592         .update_window          = NULL,
593         .suspend                = omap_lcdc_suspend, 
594         .resume                 = omap_lcdc_resume,
595         .change_mode            = omap_lcdc_change_mode,
596 };
597
598 MODULE_DESCRIPTION("TI OMAP LCDC controller");
599 MODULE_LICENSE("GPL");