2 * linux/arch/arm/mach-omap/omap_lcdc.c
4 * OMAP internal LCD controller
6 * Copyright (C) 2004 Nokia Corporation
7 * Author: Imre Deak <imre.deak@nokia.com>
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.
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.
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.
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>
33 #include <asm/arch/dma.h>
34 #include <asm/mach-types.h>
35 #include <asm/hardware/clock.h>
40 #define OMAP_LCDC_BASE 0xfffec000
41 #define OMAP_LCDC_SIZE 256
42 #define OMAP_LCDC_IRQ INT_LCD_CTRL
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)
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)
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)
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)
72 #define MAX_PALETTE_SIZE PAGE_SIZE
75 OMAP_LCDC_LOAD_PALETTE,
77 OMAP_LCDC_LOAD_PALETTE_AND_FRAME
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;
88 static void inline enable_irqs(int mask)
90 omap_lcdc.irq_mask |= mask;
93 static void inline disable_irqs(int mask)
95 omap_lcdc.irq_mask &= ~mask;
98 static void set_load_mode(enum lcdc_load_mode mode)
102 l = omap_readl(OMAP_LCDC_CONTROL);
105 case OMAP_LCDC_LOAD_PALETTE:
108 case OMAP_LCDC_LOAD_FRAME:
111 case OMAP_LCDC_LOAD_PALETTE_AND_FRAME:
116 omap_writel(l, OMAP_LCDC_CONTROL);
119 static void enable_controller(void)
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);
130 static void disable_controller_async(void)
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.
141 mask &= ~OMAP_LCDC_IRQ_DONE;
143 omap_writel(l, OMAP_LCDC_CONTROL);
146 static void last_frame_timeout(unsigned long data)
148 printk(KERN_ERR "omap_lcdc: timeout waiting for DONE flag\n");
149 complete(&omap_lcdc.last_frame_complete);
152 static void inline wait_for_frame_done(void)
154 struct timer_list timeout;
156 init_timer(&timeout);
157 timeout.function = last_frame_timeout;
158 timeout.expires = jiffies + msecs_to_jiffies(500);
160 wait_for_completion(&omap_lcdc.last_frame_complete);
161 del_timer_sync(&timeout);
164 static void disable_controller(void)
166 disable_controller_async();
167 wait_for_frame_done();
170 static void reset_controller(u32 status)
172 static unsigned long reset_count = 0;
173 static unsigned long last_jiffies = 0;
175 disable_controller_async();
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;
184 if (reset_count < 100) {
188 printk(KERN_ERR "omap_lcdc: too many reset attempts, "
193 /* Configure the LCD DMA according to the current mode specified by parameters
194 * in fbdev and fbdev->var.
196 static void setup_lcd_dma(struct omapfb_device *fbdev)
198 static const int dma_elem_type[] = {
200 OMAP_DMA_DATA_TYPE_S8,
201 OMAP_DMA_DATA_TYPE_S16,
203 OMAP_DMA_DATA_TYPE_S32,
205 struct fb_var_screeninfo *var = &fbdev->fb_info->var;
207 int esize, xelem, yelem;
209 src = fbdev->lcddma_handle + fbdev->vis_frame_org + fbdev->view_org;
210 switch (var->rotate) {
212 esize = fbdev->mirror || (src & 3) ? 2 : 4;
213 xelem = var->xres * var->bits_per_pixel / 8 / esize;
220 xelem = var->xres * var->bits_per_pixel / 16;
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);
240 omap_setup_lcd_dma();
243 static irqreturn_t lcdc_irq_handler(int irq, void *dev_id,
248 status = omap_readl(OMAP_LCDC_STATUS);
250 if (status & (OMAP_LCDC_STAT_FUF | OMAP_LCDC_STAT_SYNC_LOST))
251 reset_controller(status);
253 if (status & OMAP_LCDC_STAT_DONE) {
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.
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);
265 if (status & OMAP_LCDC_STAT_LOADED_PALETTE) {
266 disable_controller_async();
267 complete(&omap_lcdc.palette_load_complete);
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
277 status &= ~(OMAP_LCDC_STAT_VSYNC |
278 OMAP_LCDC_STAT_LOADED_PALETTE |
280 OMAP_LCDC_STAT_LINE_INT);
281 omap_writel(status, OMAP_LCDC_STATUS);
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.
291 static void omap_lcdc_change_mode(struct omapfb_device *fbdev)
296 disable_controller();
297 setup_lcd_dma(fbdev);
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.
307 static void load_palette(struct omapfb_device *fbdev)
312 unsigned long palette_org;
316 switch (fbdev->panel->video_mode->bpp) {
318 /* 0 is already set */
343 palette_org = MAX_PALETTE_SIZE - size;
344 palette = fbdev->lcddma_base + palette_org;
345 memset(palette, 0, size);
346 *(u32 *)palette = code;
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();
353 init_completion(&omap_lcdc.palette_load_complete);
354 enable_irqs(OMAP_LCDC_IRQ_LOADED_PALETTE);
355 set_load_mode(OMAP_LCDC_LOAD_PALETTE);
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);
365 static void inline setup_regs(struct omapfb_device *fbdev)
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;
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);
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);
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);
389 l |= (mode->vsw - 1) << 10;
390 l |= mode->vfp << 16;
391 l |= mode->vbp << 24;
392 omap_writel(l, OMAP_LCDC_TIMING1);
394 l = omap_readl(OMAP_LCDC_TIMING2);
397 if (!cpu_is_omap730())
400 if (machine_is_omap_perseus2()) {
404 clock1 = mode->pixel_clock * 1000;
405 clock2 = clk_get_rate(omap_lcdc.lcd_ck);
408 pcd = clock2 / clock1;
420 // printk("%% ck1: %d ck2: %d pcd: %d %%\n",clock1, clock2, pcd);
424 if (mode->flags & OMAP_LCDC_INV_PIX_CLOCK)
426 omap_writel(l, OMAP_LCDC_TIMING2);
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)
438 if (mode != omap_lcdc.update_mode) {
444 /* Setup and start LCD DMA */
445 setup_lcd_dma(fbdev);
447 set_load_mode(OMAP_LCDC_LOAD_FRAME);
448 enable_irqs(OMAP_LCDC_IRQ_DONE);
449 /* This will start the actual DMA transfer */
451 omap_lcdc.update_mode = mode;
453 case FB_UPDATE_DISABLED:
454 disable_controller();
456 omap_lcdc.update_mode = mode;
467 static enum fb_update_mode omap_lcdc_get_update_mode(struct omapfb_device *fbdev)
469 return omap_lcdc.update_mode;
472 static void omap_lcdc_suspend(struct omapfb_device *fbdev)
474 if (omap_lcdc.update_mode == FB_AUTO_UPDATE) {
475 disable_controller();
480 static void omap_lcdc_resume(struct omapfb_device *fbdev)
482 if (omap_lcdc.update_mode == FB_AUTO_UPDATE) {
485 setup_lcd_dma(fbdev);
486 set_load_mode(OMAP_LCDC_LOAD_FRAME);
487 enable_irqs(OMAP_LCDC_IRQ_DONE);
492 static int omap_lcdc_init(struct omapfb_device *fbdev)
501 omap_lcdc.irq_mask = 0;
504 omap_writel(l, OMAP_LCDC_CONTROL);
507 * According to errata some platforms have a clock rate limitiation
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);
516 tc_ck = clk_get(NULL, "tc_ck");
518 printk(KERN_ERR "omap_lcdc: unable to access TC clock\n");
523 rate = clk_get_rate(tc_ck);
526 if (machine_is_omap_h3())
528 r = clk_set_rate(omap_lcdc.lcd_ck, rate);
530 printk(KERN_ERR "omap_lcdc: failed to adjust LCD rate\n");
533 clk_use(omap_lcdc.lcd_ck);
535 r = request_irq(OMAP_LCDC_IRQ, lcdc_irq_handler, 0, "omap-lcdc", fbdev);
537 printk(KERN_ERR "omap_lcdc: unable to get IRQ\n");
541 r = omap_request_lcd_dma(NULL, NULL);
543 printk(KERN_ERR "omap_lcdc: unable to get LCD DMA\n");
547 printk(KERN_INFO "OMAP LCD controller initialized.\n");
551 free_irq(OMAP_LCDC_IRQ, fbdev);
553 clk_unuse(omap_lcdc.lcd_ck);
555 clk_put(omap_lcdc.lcd_ck);
561 static void omap_lcdc_cleanup(struct omapfb_device *fbdev)
564 free_irq(OMAP_LCDC_IRQ, fbdev);
565 clk_unuse(omap_lcdc.lcd_ck);
566 clk_put(omap_lcdc.lcd_ck);
569 static void omap_lcdc_get_mem_layout(struct omapfb_device *fbdev,
570 unsigned long *size, unsigned long *fb_org)
572 struct lcdc_video_mode *mode = fbdev->panel->video_mode;
574 *size = MAX_PALETTE_SIZE;
576 *size += mode->x_res * mode->bpp / 8 * mode->y_res;
579 static unsigned long omap_lcdc_get_caps(struct omapfb_device *fbdev)
584 struct lcd_ctrl omapfb_lcdc_ctrl = {
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,
598 MODULE_DESCRIPTION("TI OMAP LCDC controller");
599 MODULE_LICENSE("GPL");