2 * File: drivers/video/omap/omap1/lcdc.c
4 * OMAP1 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>
32 #include <linux/dma-mapping.h>
33 #include <linux/vmalloc.h>
34 #include <linux/clk.h>
36 #include <asm/arch/dma.h>
37 #include <asm/arch/omapfb.h>
39 #include <asm/mach-types.h>
41 /* #define OMAPFB_DBG 1 */
45 #define MODULE_NAME "omapfb-lcdc"
47 #define OMAP_LCDC_BASE 0xfffec000
48 #define OMAP_LCDC_SIZE 256
49 #define OMAP_LCDC_IRQ INT_LCD_CTRL
51 #define OMAP_LCDC_CONTROL (OMAP_LCDC_BASE + 0x00)
52 #define OMAP_LCDC_TIMING0 (OMAP_LCDC_BASE + 0x04)
53 #define OMAP_LCDC_TIMING1 (OMAP_LCDC_BASE + 0x08)
54 #define OMAP_LCDC_TIMING2 (OMAP_LCDC_BASE + 0x0c)
55 #define OMAP_LCDC_STATUS (OMAP_LCDC_BASE + 0x10)
56 #define OMAP_LCDC_SUBPANEL (OMAP_LCDC_BASE + 0x14)
57 #define OMAP_LCDC_LINE_INT (OMAP_LCDC_BASE + 0x18)
58 #define OMAP_LCDC_DISPLAY_STATUS (OMAP_LCDC_BASE + 0x1c)
60 #define OMAP_LCDC_STAT_DONE (1 << 0)
61 #define OMAP_LCDC_STAT_VSYNC (1 << 1)
62 #define OMAP_LCDC_STAT_SYNC_LOST (1 << 2)
63 #define OMAP_LCDC_STAT_ABC (1 << 3)
64 #define OMAP_LCDC_STAT_LINE_INT (1 << 4)
65 #define OMAP_LCDC_STAT_FUF (1 << 5)
66 #define OMAP_LCDC_STAT_LOADED_PALETTE (1 << 6)
68 #define OMAP_LCDC_CTRL_LCD_EN (1 << 0)
69 #define OMAP_LCDC_CTRL_LCD_TFT (1 << 7)
70 #define OMAP_LCDC_CTRL_LINE_IRQ_CLR_SEL (1 << 10)
72 #define OMAP_LCDC_IRQ_VSYNC (1 << 2)
73 #define OMAP_LCDC_IRQ_DONE (1 << 3)
74 #define OMAP_LCDC_IRQ_LOADED_PALETTE (1 << 4)
75 #define OMAP_LCDC_IRQ_LINE_NIRQ (1 << 5)
76 #define OMAP_LCDC_IRQ_LINE (1 << 6)
77 #define OMAP_LCDC_IRQ_MASK (((1 << 5) - 1) << 2)
79 #define MAX_PALETTE_SIZE PAGE_SIZE
81 #define pr_err(fmt, args...) printk(KERN_ERR MODULE_NAME ": " fmt, ## args)
84 OMAP_LCDC_LOAD_PALETTE,
86 OMAP_LCDC_LOAD_PALETTE_AND_FRAME
89 static struct omap_lcd_controller {
90 enum omapfb_update_mode update_mode;
93 unsigned long frame_offset;
98 enum omapfb_color_format color_mode;
101 dma_addr_t palette_phys;
105 unsigned int irq_mask;
106 struct completion last_frame_complete;
107 struct completion palette_load_complete;
109 struct omapfb_device *fbdev;
111 void (*dma_callback)(void *data);
112 void *dma_callback_data;
115 dma_addr_t vram_phys;
117 unsigned long vram_size;
120 static void inline enable_irqs(int mask)
122 omap_lcdc.irq_mask |= mask;
125 static void inline disable_irqs(int mask)
127 omap_lcdc.irq_mask &= ~mask;
130 static void set_load_mode(enum lcdc_load_mode mode)
134 l = omap_readl(OMAP_LCDC_CONTROL);
137 case OMAP_LCDC_LOAD_PALETTE:
140 case OMAP_LCDC_LOAD_FRAME:
143 case OMAP_LCDC_LOAD_PALETTE_AND_FRAME:
148 omap_writel(l, OMAP_LCDC_CONTROL);
151 static void enable_controller(void)
155 l = omap_readl(OMAP_LCDC_CONTROL);
156 l |= OMAP_LCDC_CTRL_LCD_EN;
157 l &= ~OMAP_LCDC_IRQ_MASK;
158 l |= omap_lcdc.irq_mask | OMAP_LCDC_IRQ_DONE; /* enabled IRQs */
159 omap_writel(l, OMAP_LCDC_CONTROL);
162 static void disable_controller_async(void)
167 l = omap_readl(OMAP_LCDC_CONTROL);
168 mask = OMAP_LCDC_CTRL_LCD_EN | OMAP_LCDC_IRQ_MASK;
169 /* Preserve the DONE mask, since we still want to get the
170 * final DONE irq. It will be disabled in the IRQ handler.
172 mask &= ~OMAP_LCDC_IRQ_DONE;
174 omap_writel(l, OMAP_LCDC_CONTROL);
177 static void disable_controller(void)
179 init_completion(&omap_lcdc.last_frame_complete);
180 disable_controller_async();
181 if (!wait_for_completion_timeout(&omap_lcdc.last_frame_complete,
182 msecs_to_jiffies(500)))
183 pr_err("timeout waiting for FRAME DONE\n");
186 static void reset_controller(u32 status)
188 static unsigned long reset_count = 0;
189 static unsigned long last_jiffies = 0;
191 disable_controller_async();
193 if (reset_count == 1 || time_after(jiffies, last_jiffies + HZ)) {
194 pr_err("resetting (status %#010x,reset count %lu)\n",
195 status, reset_count);
196 last_jiffies = jiffies;
198 if (reset_count < 100) {
202 pr_err("too many reset attempts, giving up.\n");
206 /* Configure the LCD DMA according to the current mode specified by parameters
207 * in omap_lcdc.fbdev and fbdev->var.
209 static void setup_lcd_dma(void)
211 static const int dma_elem_type[] = {
213 OMAP_DMA_DATA_TYPE_S8,
214 OMAP_DMA_DATA_TYPE_S16,
216 OMAP_DMA_DATA_TYPE_S32,
218 struct fb_var_screeninfo *var = &omap_lcdc.fbdev->fb_info->var;
220 int esize, xelem, yelem;
222 src = omap_lcdc.vram_phys + omap_lcdc.frame_offset;
224 switch (var->rotate) {
226 if (omap_lcdc.fbdev->mirror || (src & 3) ||
227 omap_lcdc.color_mode == OMAPFB_COLOR_YUV420 ||
228 (omap_lcdc.xres & 1))
232 xelem = omap_lcdc.xres * omap_lcdc.bpp / 8 / esize;
233 yelem = omap_lcdc.yres;
238 if (cpu_is_omap15xx()) {
242 xelem = omap_lcdc.yres * omap_lcdc.bpp / 16;
243 yelem = omap_lcdc.xres;
249 DBGPRINT(2, "setup_dma: src %#010lx esize %d xelem %d yelem %d\n",
250 src, esize, xelem, yelem);
251 omap_set_lcd_dma_b1(src, xelem, yelem, dma_elem_type[esize]);
252 if (!cpu_is_omap15xx()) {
253 int bpp = omap_lcdc.bpp;
255 /* YUV support is only for external mode when we have the
256 * YUV window embedded in a 16bpp frame buffer.
258 if (omap_lcdc.color_mode == OMAPFB_COLOR_YUV420)
260 /* Set virtual xres elem size */
261 omap_set_lcd_dma_b1_vxres(
262 omap_lcdc.screen_width * bpp / 8 / esize);
263 /* Setup transformations */
264 omap_set_lcd_dma_b1_rotation(var->rotate);
265 omap_set_lcd_dma_b1_mirror(omap_lcdc.fbdev->mirror);
267 omap_setup_lcd_dma();
270 static irqreturn_t lcdc_irq_handler(int irq, void *dev_id, struct pt_regs *fp)
274 status = omap_readl(OMAP_LCDC_STATUS);
276 if (status & (OMAP_LCDC_STAT_FUF | OMAP_LCDC_STAT_SYNC_LOST))
277 reset_controller(status);
279 if (status & OMAP_LCDC_STAT_DONE) {
282 /* Disable IRQ_DONE. The status bit will be cleared
283 * only when the controller is reenabled and we don't
284 * want to get more interrupts.
286 l = omap_readl(OMAP_LCDC_CONTROL);
287 l &= ~OMAP_LCDC_IRQ_DONE;
288 omap_writel(l, OMAP_LCDC_CONTROL);
289 complete(&omap_lcdc.last_frame_complete);
291 if (status & OMAP_LCDC_STAT_LOADED_PALETTE) {
292 disable_controller_async();
293 complete(&omap_lcdc.palette_load_complete);
297 /* Clear these interrupt status bits.
298 * Sync_lost, FUF bits were cleared by disabling the LCD controller
299 * LOADED_PALETTE can be cleared this way only in palette only
300 * load mode. In other load modes it's cleared by disabling the
303 status &= ~(OMAP_LCDC_STAT_VSYNC |
304 OMAP_LCDC_STAT_LOADED_PALETTE |
306 OMAP_LCDC_STAT_LINE_INT);
307 omap_writel(status, OMAP_LCDC_STATUS);
311 /* Change to a new video mode. We defer this to a later time to avoid any
312 * flicker and not to mess up the current LCD DMA context. For this we disable
313 * the LCD controler, which will generate a DONE irq after the last frame has
314 * been transferred. Then it'll be safe to reconfigure both the LCD controller
315 * as well as the LCD DMA.
317 static int omap_lcdc_setup_plane(int plane, int channel_out,
318 unsigned long offset, int screen_width,
319 int pos_x, int pos_y, int width, int height,
322 struct fb_var_screeninfo *var = &omap_lcdc.fbdev->fb_info->var;
323 struct lcd_panel *panel = omap_lcdc.fbdev->panel;
328 if (var->rotate == 0) {
329 rot_x = panel->x_res;
330 rot_y = panel->y_res;
332 rot_x = panel->y_res;
333 rot_y = panel->x_res;
335 if (plane != 0 || channel_out != 0 || pos_x != 0 || pos_y != 0 ||
336 width > rot_x || height > rot_y) {
337 DBGPRINT(1, "invalid plane params plane %d pos_x %d "
338 "pos_y %d w %d h %d\n", plane, pos_x, pos_y,
343 omap_lcdc.frame_offset = offset;
344 omap_lcdc.xres = width;
345 omap_lcdc.yres = height;
346 omap_lcdc.screen_width = screen_width;
347 omap_lcdc.color_mode = color_mode;
349 switch (color_mode) {
350 case OMAPFB_COLOR_CLUT_8BPP:
352 omap_lcdc.palette_code = 0x3000;
353 omap_lcdc.palette_size = 512;
355 case OMAPFB_COLOR_RGB565:
357 omap_lcdc.palette_code = 0x4000;
358 omap_lcdc.palette_size = 32;
360 case OMAPFB_COLOR_YUV420:
361 if (omap_lcdc.ext_mode) {
366 case OMAPFB_COLOR_YUV422:
367 if (omap_lcdc.ext_mode) {
373 /* FIXME: other BPPs.
374 * bpp1: code 0, size 256
375 * bpp2: code 0x1000 size 256
376 * bpp4: code 0x2000 size 256
377 * bpp12: code 0x4000 size 32
379 DBGPRINT(1, "invalid color mode %d\n", color_mode);
383 if (omap_lcdc.ext_mode) {
388 if (omap_lcdc.update_mode == OMAPFB_AUTO_UPDATE) {
389 disable_controller();
400 static int omap_lcdc_enable_plane(int plane, int enable)
402 DBGPRINT(2, "plane %d enable %d update_mode %d ext_mode %d\n",
403 plane, enable, omap_lcdc.update_mode,
405 if (plane != OMAPFB_PLANE_GFX)
411 /* Configure the LCD DMA for a palette load operation and do the palette
412 * downloading synchronously. We don't use the frame+palette load mode of
413 * the controller, since the palette can always be downloaded seperately.
415 static void load_palette(void)
421 palette = (u16 *)omap_lcdc.palette_virt;
423 *(u16 *)palette &= 0x0fff;
424 *(u16 *)palette |= omap_lcdc.palette_code;
426 omap_set_lcd_dma_b1(omap_lcdc.palette_phys,
427 omap_lcdc.palette_size / 4 + 1, 1, OMAP_DMA_DATA_TYPE_S32);
429 omap_set_lcd_dma_single_transfer(1);
430 omap_setup_lcd_dma();
432 init_completion(&omap_lcdc.palette_load_complete);
433 enable_irqs(OMAP_LCDC_IRQ_LOADED_PALETTE);
434 set_load_mode(OMAP_LCDC_LOAD_PALETTE);
436 if (!wait_for_completion_timeout(&omap_lcdc.palette_load_complete,
437 msecs_to_jiffies(500)))
438 pr_err("timeout waiting for FRAME DONE\n");
439 /* The controller gets disabled in the irq handler */
440 disable_irqs(OMAP_LCDC_IRQ_LOADED_PALETTE);
443 omap_set_lcd_dma_single_transfer(omap_lcdc.ext_mode);
448 /* Used only in internal controller mode */
449 static int omap_lcdc_setcolreg(u_int regno, u16 red, u16 green, u16 blue,
450 u16 transp, int update_hw_pal)
454 if (omap_lcdc.color_mode != OMAPFB_COLOR_CLUT_8BPP || regno > 255)
457 palette = (u16 *)omap_lcdc.palette_virt;
459 palette[regno] &= ~0x0fff;
460 palette[regno] |= ((red >> 12) << 8) | ((green >> 12) << 4 ) |
464 disable_controller();
468 set_load_mode(OMAP_LCDC_LOAD_FRAME);
475 static void calc_ck_div(int is_tft, int pck, int *pck_div)
480 lck = clk_get_rate(omap_lcdc.lcd_ck);
481 *pck_div = (lck + pck - 1) / pck;
483 *pck_div = max(2, *pck_div);
485 *pck_div = max(3, *pck_div);
486 if (*pck_div > 255) {
487 /* FIXME: try to adjust logic clock divider as well */
489 printk(KERN_WARNING MODULE_NAME ": pixclock %d kHz too low.\n",
494 static void inline setup_regs(void)
497 struct lcd_panel *panel = omap_lcdc.fbdev->panel;
498 int is_tft = panel->config & OMAP_LCDC_PANEL_TFT;
502 l = omap_readl(OMAP_LCDC_CONTROL);
503 l &= ~OMAP_LCDC_CTRL_LCD_TFT;
504 l |= is_tft ? OMAP_LCDC_CTRL_LCD_TFT : 0;
505 #ifdef CONFIG_MACH_OMAP_PALMTE
506 /* FIXME:if (machine_is_omap_palmte()) { */
507 /* PalmTE uses alternate TFT setting in 8BPP mode */
508 l |= (is_tft && panel->bpp == 8) ? 0x810000 : 0;
511 omap_writel(l, OMAP_LCDC_CONTROL);
513 l = omap_readl(OMAP_LCDC_TIMING2);
514 l &= ~(((1 << 6) - 1) << 20);
515 l |= (panel->config & OMAP_LCDC_SIGNAL_MASK) << 20;
516 omap_writel(l, OMAP_LCDC_TIMING2);
518 l = panel->x_res - 1;
519 l |= (panel->hsw - 1) << 10;
520 l |= (panel->hfp - 1) << 16;
521 l |= (panel->hbp - 1) << 24;
522 omap_writel(l, OMAP_LCDC_TIMING0);
524 l = panel->y_res - 1;
525 l |= (panel->vsw - 1) << 10;
526 l |= panel->vfp << 16;
527 l |= panel->vbp << 24;
528 omap_writel(l, OMAP_LCDC_TIMING1);
530 l = omap_readl(OMAP_LCDC_TIMING2);
533 lck = clk_get_rate(omap_lcdc.lcd_ck);
536 calc_ck_div(is_tft, panel->pixel_clock * 1000, &pcd);
539 MODULE_NAME ": Pixel clock divider value is obsolete.\n"
540 MODULE_NAME ": Try to set pixel_clock to %lu and pcd to 0 "
541 "in drivers/video/omap/lcd_%s.c and submit a patch.\n",
542 lck / panel->pcd / 1000, panel->name);
547 l |= panel->acb << 8;
548 omap_writel(l, OMAP_LCDC_TIMING2);
550 /* update panel info with the exact clock */
551 panel->pixel_clock = lck / pcd / 1000;
554 /* Configure the LCD controller, download the color palette and start a looped
555 * DMA transfer of the frame image data. Called only in internal
558 static int omap_lcdc_set_update_mode(enum omapfb_update_mode mode)
564 if (mode != omap_lcdc.update_mode) {
566 case OMAPFB_AUTO_UPDATE:
570 /* Setup and start LCD DMA */
573 set_load_mode(OMAP_LCDC_LOAD_FRAME);
574 enable_irqs(OMAP_LCDC_IRQ_DONE);
575 /* This will start the actual DMA transfer */
577 omap_lcdc.update_mode = mode;
579 case OMAPFB_UPDATE_DISABLED:
580 disable_controller();
582 omap_lcdc.update_mode = mode;
593 static enum omapfb_update_mode omap_lcdc_get_update_mode(void)
595 return omap_lcdc.update_mode;
598 /* PM code called only in internal controller mode */
599 static void omap_lcdc_suspend(void)
601 if (omap_lcdc.update_mode == OMAPFB_AUTO_UPDATE) {
602 disable_controller();
607 static void omap_lcdc_resume(void)
609 if (omap_lcdc.update_mode == OMAPFB_AUTO_UPDATE) {
613 set_load_mode(OMAP_LCDC_LOAD_FRAME);
614 enable_irqs(OMAP_LCDC_IRQ_DONE);
619 static unsigned long omap_lcdc_get_caps(void)
624 static void omap_lcdc_get_vram_layout(unsigned long *size, void **virt,
627 *size = omap_lcdc.vram_size;
628 *virt = (u8 *)omap_lcdc.vram_virt;
629 *phys = omap_lcdc.vram_phys;
632 int omap_lcdc_set_dma_callback(void (*callback)(void *data), void *data)
634 BUG_ON(callback == NULL);
636 if (omap_lcdc.dma_callback)
639 omap_lcdc.dma_callback = callback;
640 omap_lcdc.dma_callback_data = data;
644 EXPORT_SYMBOL(omap_lcdc_set_dma_callback);
646 void omap_lcdc_free_dma_callback(void)
648 omap_lcdc.dma_callback = NULL;
650 EXPORT_SYMBOL(omap_lcdc_free_dma_callback);
652 static void lcdc_dma_handler(u16 status, void *data)
655 if (omap_lcdc.dma_callback)
656 omap_lcdc.dma_callback(omap_lcdc.dma_callback_data);
659 static int mmap_kern(void)
661 struct vm_struct *kvma;
662 struct vm_area_struct vma;
668 kvma = get_vm_area(omap_lcdc.vram_size, VM_IOREMAP);
670 pr_err("can't get kernel vm area\n");
673 vma.vm_mm = &init_mm;
675 vaddr = (unsigned long)kvma->addr;
676 vma.vm_start = vaddr;
677 vma.vm_end = vaddr + omap_lcdc.vram_size;
679 pgprot = pgprot_writecombine(pgprot_kernel);
680 if (io_remap_pfn_range(&vma, vaddr,
681 omap_lcdc.vram_phys >> PAGE_SHIFT,
682 omap_lcdc.vram_size, pgprot) < 0) {
683 pr_err("kernel mmap for FB memory failed\n");
687 omap_lcdc.vram_virt = (void *)vaddr;
694 static void unmap_kern(void)
696 vunmap(omap_lcdc.vram_virt);
699 static int alloc_palette_ram(void)
701 omap_lcdc.palette_virt = dma_alloc_writecombine(omap_lcdc.fbdev->dev,
702 MAX_PALETTE_SIZE, &omap_lcdc.palette_phys, GFP_KERNEL);
703 if (omap_lcdc.palette_virt == NULL) {
704 pr_err("failed to alloc palette memory\n");
707 memset(omap_lcdc.palette_virt, 0, MAX_PALETTE_SIZE);
712 static void free_palette_ram(void)
714 dma_free_writecombine(omap_lcdc.fbdev->dev, MAX_PALETTE_SIZE,
715 omap_lcdc.palette_virt, omap_lcdc.palette_phys);
718 static int alloc_fbmem(int req_size)
721 struct lcd_panel *panel = omap_lcdc.fbdev->panel;
723 frame_size = PAGE_ALIGN(panel->x_res * panel->bpp / 8 * panel->y_res);
724 if (req_size > frame_size)
725 frame_size = req_size;
726 omap_lcdc.vram_size = frame_size;
727 omap_lcdc.vram_virt = dma_alloc_writecombine(omap_lcdc.fbdev->dev,
728 omap_lcdc.vram_size, &omap_lcdc.vram_phys, GFP_KERNEL);
730 if (omap_lcdc.vram_virt == NULL) {
731 pr_err("unable to allocate FB DMA memory\n");
735 memset(omap_lcdc.vram_virt, 0, omap_lcdc.vram_size);
740 static void free_fbmem(void)
742 dma_free_writecombine(omap_lcdc.fbdev->dev, omap_lcdc.vram_size,
743 omap_lcdc.vram_virt, omap_lcdc.vram_phys);
746 static int setup_fbmem(int req_size)
748 struct lcd_panel *panel = omap_lcdc.fbdev->panel;
749 struct omapfb_platform_data *conf;
753 conf = omap_lcdc.fbdev->dev->platform_data;
755 if (conf->fbmem.fb_sram_size) {
756 pr_err("can't use FB SRAM in OMAP1\n");
760 if (conf->fbmem.fb_sdram_size == 0) {
761 omap_lcdc.fbmem_allocated = 1;
762 if ((r = alloc_fbmem(req_size)) < 0)
767 frame_size = PAGE_ALIGN(panel->x_res * panel->bpp / 8 * panel->y_res);
769 if (conf->fbmem.fb_sdram_size < frame_size) {
770 pr_err("invalid FB memory configuration\n");
774 if (conf->fbmem.fb_sdram_size < req_size) {
775 pr_err("%d vram was requested, but only %u is available\n",
776 req_size, conf->fbmem.fb_sdram_size);
779 omap_lcdc.vram_phys = conf->fbmem.fb_sdram_start;
780 omap_lcdc.vram_size = conf->fbmem.fb_sdram_size;
782 if ((r = mmap_kern()) < 0)
785 DBGPRINT(1, "vram at %08x size %08lx mapped to 0x%p\n",
786 omap_lcdc.vram_phys, omap_lcdc.vram_size, omap_lcdc.vram_virt);
791 static void cleanup_fbmem(void)
793 if (omap_lcdc.fbmem_allocated)
799 static int omap_lcdc_init(struct omapfb_device *fbdev, int ext_mode,
809 omap_lcdc.irq_mask = 0;
811 omap_lcdc.fbdev = fbdev;
812 omap_lcdc.ext_mode = ext_mode;
814 pr_info(MODULE_NAME ": init\n");
817 omap_writel(l, OMAP_LCDC_CONTROL);
820 * According to errata some platforms have a clock rate limitiation
822 omap_lcdc.lcd_ck = clk_get(NULL, "lcd_ck");
823 if (IS_ERR(omap_lcdc.lcd_ck)) {
824 pr_err("unable to access LCD clock\n");
825 r = PTR_ERR(omap_lcdc.lcd_ck);
829 tc_ck = clk_get(NULL, "tc_ck");
831 pr_err("unable to access TC clock\n");
836 rate = clk_get_rate(tc_ck);
839 if (machine_is_omap_h3())
841 r = clk_set_rate(omap_lcdc.lcd_ck, rate);
843 pr_err("failed to adjust LCD rate\n");
846 clk_enable(omap_lcdc.lcd_ck);
848 r = request_irq(OMAP_LCDC_IRQ, lcdc_irq_handler, 0, "omap-lcdc",
851 pr_err("unable to get IRQ\n");
855 r = omap_request_lcd_dma(lcdc_dma_handler, NULL);
857 pr_err("unable to get LCD DMA\n");
861 omap_set_lcd_dma_single_transfer(ext_mode);
862 omap_set_lcd_dma_ext_controller(ext_mode);
865 if ((r = alloc_palette_ram()) < 0)
868 req_vram_size = 1024 * 1024;
869 if ((r = setup_fbmem(req_vram_size)) < 0)
881 free_irq(OMAP_LCDC_IRQ, omap_lcdc.fbdev);
883 clk_disable(omap_lcdc.lcd_ck);
885 clk_put(omap_lcdc.lcd_ck);
891 static void omap_lcdc_cleanup(void)
893 if (!omap_lcdc.ext_mode)
897 free_irq(OMAP_LCDC_IRQ, omap_lcdc.fbdev);
898 clk_disable(omap_lcdc.lcd_ck);
899 clk_put(omap_lcdc.lcd_ck);
902 struct lcd_ctrl omap1_int_ctrl = {
904 .init = omap_lcdc_init,
905 .cleanup = omap_lcdc_cleanup,
906 .get_vram_layout = omap_lcdc_get_vram_layout,
907 .get_caps = omap_lcdc_get_caps,
908 .set_update_mode = omap_lcdc_set_update_mode,
909 .get_update_mode = omap_lcdc_get_update_mode,
910 .update_window = NULL,
911 .suspend = omap_lcdc_suspend,
912 .resume = omap_lcdc_resume,
913 .setup_plane = omap_lcdc_setup_plane,
914 .enable_plane = omap_lcdc_enable_plane,
915 .setcolreg = omap_lcdc_setcolreg,
918 MODULE_DESCRIPTION("TI OMAP LCDC controller");
919 MODULE_LICENSE("GPL");