0001
0002
0003
0004
0005
0006
0007
0008 #include <linux/module.h>
0009 #include <linux/device.h>
0010 #include <linux/interrupt.h>
0011 #include <linux/spinlock.h>
0012 #include <linux/err.h>
0013 #include <linux/mm.h>
0014 #include <linux/fb.h>
0015 #include <linux/dma-mapping.h>
0016 #include <linux/vmalloc.h>
0017 #include <linux/clk.h>
0018 #include <linux/gfp.h>
0019
0020 #include <linux/soc/ti/omap1-io.h>
0021 #include <linux/soc/ti/omap1-soc.h>
0022 #include <linux/omap-dma.h>
0023
0024 #include <asm/mach-types.h>
0025
0026 #include "omapfb.h"
0027
0028 #include "lcdc.h"
0029 #include "lcd_dma.h"
0030
0031 #define MODULE_NAME "lcdc"
0032
0033 #define MAX_PALETTE_SIZE PAGE_SIZE
0034
0035 enum lcdc_load_mode {
0036 OMAP_LCDC_LOAD_PALETTE,
0037 OMAP_LCDC_LOAD_FRAME,
0038 OMAP_LCDC_LOAD_PALETTE_AND_FRAME
0039 };
0040
0041 static struct omap_lcd_controller {
0042 enum omapfb_update_mode update_mode;
0043 int ext_mode;
0044
0045 unsigned long frame_offset;
0046 int screen_width;
0047 int xres;
0048 int yres;
0049
0050 enum omapfb_color_format color_mode;
0051 int bpp;
0052 void *palette_virt;
0053 dma_addr_t palette_phys;
0054 int palette_code;
0055 int palette_size;
0056
0057 unsigned int irq_mask;
0058 struct completion last_frame_complete;
0059 struct completion palette_load_complete;
0060 struct clk *lcd_ck;
0061 struct omapfb_device *fbdev;
0062
0063 void (*dma_callback)(void *data);
0064 void *dma_callback_data;
0065
0066 dma_addr_t vram_phys;
0067 void *vram_virt;
0068 unsigned long vram_size;
0069 } lcdc;
0070
0071 static inline void enable_irqs(int mask)
0072 {
0073 lcdc.irq_mask |= mask;
0074 }
0075
0076 static inline void disable_irqs(int mask)
0077 {
0078 lcdc.irq_mask &= ~mask;
0079 }
0080
0081 static void set_load_mode(enum lcdc_load_mode mode)
0082 {
0083 u32 l;
0084
0085 l = omap_readl(OMAP_LCDC_CONTROL);
0086 l &= ~(3 << 20);
0087 switch (mode) {
0088 case OMAP_LCDC_LOAD_PALETTE:
0089 l |= 1 << 20;
0090 break;
0091 case OMAP_LCDC_LOAD_FRAME:
0092 l |= 2 << 20;
0093 break;
0094 case OMAP_LCDC_LOAD_PALETTE_AND_FRAME:
0095 break;
0096 default:
0097 BUG();
0098 }
0099 omap_writel(l, OMAP_LCDC_CONTROL);
0100 }
0101
0102 static void enable_controller(void)
0103 {
0104 u32 l;
0105
0106 l = omap_readl(OMAP_LCDC_CONTROL);
0107 l |= OMAP_LCDC_CTRL_LCD_EN;
0108 l &= ~OMAP_LCDC_IRQ_MASK;
0109 l |= lcdc.irq_mask | OMAP_LCDC_IRQ_DONE;
0110 omap_writel(l, OMAP_LCDC_CONTROL);
0111 }
0112
0113 static void disable_controller_async(void)
0114 {
0115 u32 l;
0116 u32 mask;
0117
0118 l = omap_readl(OMAP_LCDC_CONTROL);
0119 mask = OMAP_LCDC_CTRL_LCD_EN | OMAP_LCDC_IRQ_MASK;
0120
0121
0122
0123
0124 mask &= ~OMAP_LCDC_IRQ_DONE;
0125 l &= ~mask;
0126 omap_writel(l, OMAP_LCDC_CONTROL);
0127 }
0128
0129 static void disable_controller(void)
0130 {
0131 init_completion(&lcdc.last_frame_complete);
0132 disable_controller_async();
0133 if (!wait_for_completion_timeout(&lcdc.last_frame_complete,
0134 msecs_to_jiffies(500)))
0135 dev_err(lcdc.fbdev->dev, "timeout waiting for FRAME DONE\n");
0136 }
0137
0138 static void reset_controller(u32 status)
0139 {
0140 static unsigned long reset_count;
0141 static unsigned long last_jiffies;
0142
0143 disable_controller_async();
0144 reset_count++;
0145 if (reset_count == 1 || time_after(jiffies, last_jiffies + HZ)) {
0146 dev_err(lcdc.fbdev->dev,
0147 "resetting (status %#010x,reset count %lu)\n",
0148 status, reset_count);
0149 last_jiffies = jiffies;
0150 }
0151 if (reset_count < 100) {
0152 enable_controller();
0153 } else {
0154 reset_count = 0;
0155 dev_err(lcdc.fbdev->dev,
0156 "too many reset attempts, giving up.\n");
0157 }
0158 }
0159
0160
0161
0162
0163
0164 static void setup_lcd_dma(void)
0165 {
0166 static const int dma_elem_type[] = {
0167 0,
0168 OMAP_DMA_DATA_TYPE_S8,
0169 OMAP_DMA_DATA_TYPE_S16,
0170 0,
0171 OMAP_DMA_DATA_TYPE_S32,
0172 };
0173 struct omapfb_plane_struct *plane = lcdc.fbdev->fb_info[0]->par;
0174 struct fb_var_screeninfo *var = &lcdc.fbdev->fb_info[0]->var;
0175 unsigned long src;
0176 int esize, xelem, yelem;
0177
0178 src = lcdc.vram_phys + lcdc.frame_offset;
0179
0180 switch (var->rotate) {
0181 case 0:
0182 if (plane->info.mirror || (src & 3) ||
0183 lcdc.color_mode == OMAPFB_COLOR_YUV420 ||
0184 (lcdc.xres & 1))
0185 esize = 2;
0186 else
0187 esize = 4;
0188 xelem = lcdc.xres * lcdc.bpp / 8 / esize;
0189 yelem = lcdc.yres;
0190 break;
0191 case 90:
0192 case 180:
0193 case 270:
0194 if (cpu_is_omap15xx()) {
0195 BUG();
0196 }
0197 esize = 2;
0198 xelem = lcdc.yres * lcdc.bpp / 16;
0199 yelem = lcdc.xres;
0200 break;
0201 default:
0202 BUG();
0203 return;
0204 }
0205 #ifdef VERBOSE
0206 dev_dbg(lcdc.fbdev->dev,
0207 "setup_dma: src %#010lx esize %d xelem %d yelem %d\n",
0208 src, esize, xelem, yelem);
0209 #endif
0210 omap_set_lcd_dma_b1(src, xelem, yelem, dma_elem_type[esize]);
0211 if (!cpu_is_omap15xx()) {
0212 int bpp = lcdc.bpp;
0213
0214
0215
0216
0217
0218 if (lcdc.color_mode == OMAPFB_COLOR_YUV420)
0219 bpp = 16;
0220
0221 omap_set_lcd_dma_b1_vxres(
0222 lcdc.screen_width * bpp / 8 / esize);
0223
0224 omap_set_lcd_dma_b1_rotation(var->rotate);
0225 omap_set_lcd_dma_b1_mirror(plane->info.mirror);
0226 }
0227 omap_setup_lcd_dma();
0228 }
0229
0230 static irqreturn_t lcdc_irq_handler(int irq, void *dev_id)
0231 {
0232 u32 status;
0233
0234 status = omap_readl(OMAP_LCDC_STATUS);
0235
0236 if (status & (OMAP_LCDC_STAT_FUF | OMAP_LCDC_STAT_SYNC_LOST))
0237 reset_controller(status);
0238 else {
0239 if (status & OMAP_LCDC_STAT_DONE) {
0240 u32 l;
0241
0242
0243
0244
0245
0246
0247 l = omap_readl(OMAP_LCDC_CONTROL);
0248 l &= ~OMAP_LCDC_IRQ_DONE;
0249 omap_writel(l, OMAP_LCDC_CONTROL);
0250 complete(&lcdc.last_frame_complete);
0251 }
0252 if (status & OMAP_LCDC_STAT_LOADED_PALETTE) {
0253 disable_controller_async();
0254 complete(&lcdc.palette_load_complete);
0255 }
0256 }
0257
0258
0259
0260
0261
0262
0263
0264
0265 status &= ~(OMAP_LCDC_STAT_VSYNC |
0266 OMAP_LCDC_STAT_LOADED_PALETTE |
0267 OMAP_LCDC_STAT_ABC |
0268 OMAP_LCDC_STAT_LINE_INT);
0269 omap_writel(status, OMAP_LCDC_STATUS);
0270 return IRQ_HANDLED;
0271 }
0272
0273
0274
0275
0276
0277
0278
0279
0280 static int omap_lcdc_setup_plane(int plane, int channel_out,
0281 unsigned long offset, int screen_width,
0282 int pos_x, int pos_y, int width, int height,
0283 int color_mode)
0284 {
0285 struct fb_var_screeninfo *var = &lcdc.fbdev->fb_info[0]->var;
0286 struct lcd_panel *panel = lcdc.fbdev->panel;
0287 int rot_x, rot_y;
0288
0289 if (var->rotate == 0) {
0290 rot_x = panel->x_res;
0291 rot_y = panel->y_res;
0292 } else {
0293 rot_x = panel->y_res;
0294 rot_y = panel->x_res;
0295 }
0296 if (plane != 0 || channel_out != 0 || pos_x != 0 || pos_y != 0 ||
0297 width > rot_x || height > rot_y) {
0298 #ifdef VERBOSE
0299 dev_dbg(lcdc.fbdev->dev,
0300 "invalid plane params plane %d pos_x %d pos_y %d "
0301 "w %d h %d\n", plane, pos_x, pos_y, width, height);
0302 #endif
0303 return -EINVAL;
0304 }
0305
0306 lcdc.frame_offset = offset;
0307 lcdc.xres = width;
0308 lcdc.yres = height;
0309 lcdc.screen_width = screen_width;
0310 lcdc.color_mode = color_mode;
0311
0312 switch (color_mode) {
0313 case OMAPFB_COLOR_CLUT_8BPP:
0314 lcdc.bpp = 8;
0315 lcdc.palette_code = 0x3000;
0316 lcdc.palette_size = 512;
0317 break;
0318 case OMAPFB_COLOR_RGB565:
0319 lcdc.bpp = 16;
0320 lcdc.palette_code = 0x4000;
0321 lcdc.palette_size = 32;
0322 break;
0323 case OMAPFB_COLOR_RGB444:
0324 lcdc.bpp = 16;
0325 lcdc.palette_code = 0x4000;
0326 lcdc.palette_size = 32;
0327 break;
0328 case OMAPFB_COLOR_YUV420:
0329 if (lcdc.ext_mode) {
0330 lcdc.bpp = 12;
0331 break;
0332 }
0333 fallthrough;
0334 case OMAPFB_COLOR_YUV422:
0335 if (lcdc.ext_mode) {
0336 lcdc.bpp = 16;
0337 break;
0338 }
0339 fallthrough;
0340 default:
0341
0342
0343
0344
0345
0346
0347 dev_dbg(lcdc.fbdev->dev, "invalid color mode %d\n", color_mode);
0348 BUG();
0349 return -1;
0350 }
0351
0352 if (lcdc.ext_mode) {
0353 setup_lcd_dma();
0354 return 0;
0355 }
0356
0357 if (lcdc.update_mode == OMAPFB_AUTO_UPDATE) {
0358 disable_controller();
0359 omap_stop_lcd_dma();
0360 setup_lcd_dma();
0361 enable_controller();
0362 }
0363
0364 return 0;
0365 }
0366
0367 static int omap_lcdc_enable_plane(int plane, int enable)
0368 {
0369 dev_dbg(lcdc.fbdev->dev,
0370 "plane %d enable %d update_mode %d ext_mode %d\n",
0371 plane, enable, lcdc.update_mode, lcdc.ext_mode);
0372 if (plane != OMAPFB_PLANE_GFX)
0373 return -EINVAL;
0374
0375 return 0;
0376 }
0377
0378
0379
0380
0381
0382
0383 static void load_palette(void)
0384 {
0385 u16 *palette;
0386
0387 palette = (u16 *)lcdc.palette_virt;
0388
0389 *(u16 *)palette &= 0x0fff;
0390 *(u16 *)palette |= lcdc.palette_code;
0391
0392 omap_set_lcd_dma_b1(lcdc.palette_phys,
0393 lcdc.palette_size / 4 + 1, 1, OMAP_DMA_DATA_TYPE_S32);
0394
0395 omap_set_lcd_dma_single_transfer(1);
0396 omap_setup_lcd_dma();
0397
0398 init_completion(&lcdc.palette_load_complete);
0399 enable_irqs(OMAP_LCDC_IRQ_LOADED_PALETTE);
0400 set_load_mode(OMAP_LCDC_LOAD_PALETTE);
0401 enable_controller();
0402 if (!wait_for_completion_timeout(&lcdc.palette_load_complete,
0403 msecs_to_jiffies(500)))
0404 dev_err(lcdc.fbdev->dev, "timeout waiting for FRAME DONE\n");
0405
0406 disable_irqs(OMAP_LCDC_IRQ_LOADED_PALETTE);
0407 omap_stop_lcd_dma();
0408
0409 omap_set_lcd_dma_single_transfer(lcdc.ext_mode);
0410 }
0411
0412
0413 static int omap_lcdc_setcolreg(u_int regno, u16 red, u16 green, u16 blue,
0414 u16 transp, int update_hw_pal)
0415 {
0416 u16 *palette;
0417
0418 if (lcdc.color_mode != OMAPFB_COLOR_CLUT_8BPP || regno > 255)
0419 return -EINVAL;
0420
0421 palette = (u16 *)lcdc.palette_virt;
0422
0423 palette[regno] &= ~0x0fff;
0424 palette[regno] |= ((red >> 12) << 8) | ((green >> 12) << 4 ) |
0425 (blue >> 12);
0426
0427 if (update_hw_pal) {
0428 disable_controller();
0429 omap_stop_lcd_dma();
0430 load_palette();
0431 setup_lcd_dma();
0432 set_load_mode(OMAP_LCDC_LOAD_FRAME);
0433 enable_controller();
0434 }
0435
0436 return 0;
0437 }
0438
0439 static void calc_ck_div(int is_tft, int pck, int *pck_div)
0440 {
0441 unsigned long lck;
0442
0443 pck = max(1, pck);
0444 lck = clk_get_rate(lcdc.lcd_ck);
0445 *pck_div = (lck + pck - 1) / pck;
0446 if (is_tft)
0447 *pck_div = max(2, *pck_div);
0448 else
0449 *pck_div = max(3, *pck_div);
0450 if (*pck_div > 255) {
0451
0452 *pck_div = 255;
0453 dev_warn(lcdc.fbdev->dev, "pixclock %d kHz too low.\n",
0454 pck / 1000);
0455 }
0456 }
0457
0458 static inline void setup_regs(void)
0459 {
0460 u32 l;
0461 struct lcd_panel *panel = lcdc.fbdev->panel;
0462 int is_tft = panel->config & OMAP_LCDC_PANEL_TFT;
0463 unsigned long lck;
0464 int pcd;
0465
0466 l = omap_readl(OMAP_LCDC_CONTROL);
0467 l &= ~OMAP_LCDC_CTRL_LCD_TFT;
0468 l |= is_tft ? OMAP_LCDC_CTRL_LCD_TFT : 0;
0469 #ifdef CONFIG_MACH_OMAP_PALMTE
0470
0471
0472 l |= (is_tft && panel->bpp == 8) ? 0x810000 : 0;
0473
0474 #endif
0475 omap_writel(l, OMAP_LCDC_CONTROL);
0476
0477 l = omap_readl(OMAP_LCDC_TIMING2);
0478 l &= ~(((1 << 6) - 1) << 20);
0479 l |= (panel->config & OMAP_LCDC_SIGNAL_MASK) << 20;
0480 omap_writel(l, OMAP_LCDC_TIMING2);
0481
0482 l = panel->x_res - 1;
0483 l |= (panel->hsw - 1) << 10;
0484 l |= (panel->hfp - 1) << 16;
0485 l |= (panel->hbp - 1) << 24;
0486 omap_writel(l, OMAP_LCDC_TIMING0);
0487
0488 l = panel->y_res - 1;
0489 l |= (panel->vsw - 1) << 10;
0490 l |= panel->vfp << 16;
0491 l |= panel->vbp << 24;
0492 omap_writel(l, OMAP_LCDC_TIMING1);
0493
0494 l = omap_readl(OMAP_LCDC_TIMING2);
0495 l &= ~0xff;
0496
0497 lck = clk_get_rate(lcdc.lcd_ck);
0498
0499 if (!panel->pcd)
0500 calc_ck_div(is_tft, panel->pixel_clock * 1000, &pcd);
0501 else {
0502 dev_warn(lcdc.fbdev->dev,
0503 "Pixel clock divider value is obsolete.\n"
0504 "Try to set pixel_clock to %lu and pcd to 0 "
0505 "in drivers/video/omap/lcd_%s.c and submit a patch.\n",
0506 lck / panel->pcd / 1000, panel->name);
0507
0508 pcd = panel->pcd;
0509 }
0510 l |= pcd & 0xff;
0511 l |= panel->acb << 8;
0512 omap_writel(l, OMAP_LCDC_TIMING2);
0513
0514
0515 panel->pixel_clock = lck / pcd / 1000;
0516 }
0517
0518
0519
0520
0521
0522
0523 static int omap_lcdc_set_update_mode(enum omapfb_update_mode mode)
0524 {
0525 int r = 0;
0526
0527 if (mode != lcdc.update_mode) {
0528 switch (mode) {
0529 case OMAPFB_AUTO_UPDATE:
0530 setup_regs();
0531 load_palette();
0532
0533
0534 setup_lcd_dma();
0535
0536 set_load_mode(OMAP_LCDC_LOAD_FRAME);
0537 enable_irqs(OMAP_LCDC_IRQ_DONE);
0538
0539 enable_controller();
0540 lcdc.update_mode = mode;
0541 break;
0542 case OMAPFB_UPDATE_DISABLED:
0543 disable_controller();
0544 omap_stop_lcd_dma();
0545 lcdc.update_mode = mode;
0546 break;
0547 default:
0548 r = -EINVAL;
0549 }
0550 }
0551
0552 return r;
0553 }
0554
0555 static enum omapfb_update_mode omap_lcdc_get_update_mode(void)
0556 {
0557 return lcdc.update_mode;
0558 }
0559
0560
0561 static void omap_lcdc_suspend(void)
0562 {
0563 omap_lcdc_set_update_mode(OMAPFB_UPDATE_DISABLED);
0564 }
0565
0566 static void omap_lcdc_resume(void)
0567 {
0568 omap_lcdc_set_update_mode(OMAPFB_AUTO_UPDATE);
0569 }
0570
0571 static void omap_lcdc_get_caps(int plane, struct omapfb_caps *caps)
0572 {
0573 return;
0574 }
0575
0576 int omap_lcdc_set_dma_callback(void (*callback)(void *data), void *data)
0577 {
0578 BUG_ON(callback == NULL);
0579
0580 if (lcdc.dma_callback)
0581 return -EBUSY;
0582 else {
0583 lcdc.dma_callback = callback;
0584 lcdc.dma_callback_data = data;
0585 }
0586 return 0;
0587 }
0588 EXPORT_SYMBOL(omap_lcdc_set_dma_callback);
0589
0590 void omap_lcdc_free_dma_callback(void)
0591 {
0592 lcdc.dma_callback = NULL;
0593 }
0594 EXPORT_SYMBOL(omap_lcdc_free_dma_callback);
0595
0596 static void lcdc_dma_handler(u16 status, void *data)
0597 {
0598 if (lcdc.dma_callback)
0599 lcdc.dma_callback(lcdc.dma_callback_data);
0600 }
0601
0602 static int alloc_palette_ram(void)
0603 {
0604 lcdc.palette_virt = dma_alloc_wc(lcdc.fbdev->dev, MAX_PALETTE_SIZE,
0605 &lcdc.palette_phys, GFP_KERNEL);
0606 if (lcdc.palette_virt == NULL) {
0607 dev_err(lcdc.fbdev->dev, "failed to alloc palette memory\n");
0608 return -ENOMEM;
0609 }
0610 memset(lcdc.palette_virt, 0, MAX_PALETTE_SIZE);
0611
0612 return 0;
0613 }
0614
0615 static void free_palette_ram(void)
0616 {
0617 dma_free_wc(lcdc.fbdev->dev, MAX_PALETTE_SIZE, lcdc.palette_virt,
0618 lcdc.palette_phys);
0619 }
0620
0621 static int alloc_fbmem(struct omapfb_mem_region *region)
0622 {
0623 int bpp;
0624 int frame_size;
0625 struct lcd_panel *panel = lcdc.fbdev->panel;
0626
0627 bpp = panel->bpp;
0628 if (bpp == 12)
0629 bpp = 16;
0630 frame_size = PAGE_ALIGN(panel->x_res * bpp / 8 * panel->y_res);
0631 if (region->size > frame_size)
0632 frame_size = region->size;
0633 lcdc.vram_size = frame_size;
0634 lcdc.vram_virt = dma_alloc_wc(lcdc.fbdev->dev, lcdc.vram_size,
0635 &lcdc.vram_phys, GFP_KERNEL);
0636 if (lcdc.vram_virt == NULL) {
0637 dev_err(lcdc.fbdev->dev, "unable to allocate FB DMA memory\n");
0638 return -ENOMEM;
0639 }
0640 region->size = frame_size;
0641 region->paddr = lcdc.vram_phys;
0642 region->vaddr = lcdc.vram_virt;
0643 region->alloc = 1;
0644
0645 memset(lcdc.vram_virt, 0, lcdc.vram_size);
0646
0647 return 0;
0648 }
0649
0650 static void free_fbmem(void)
0651 {
0652 dma_free_wc(lcdc.fbdev->dev, lcdc.vram_size, lcdc.vram_virt,
0653 lcdc.vram_phys);
0654 }
0655
0656 static int setup_fbmem(struct omapfb_mem_desc *req_md)
0657 {
0658 if (!req_md->region_cnt) {
0659 dev_err(lcdc.fbdev->dev, "no memory regions defined\n");
0660 return -EINVAL;
0661 }
0662
0663 if (req_md->region_cnt > 1) {
0664 dev_err(lcdc.fbdev->dev, "only one plane is supported\n");
0665 req_md->region_cnt = 1;
0666 }
0667
0668 return alloc_fbmem(&req_md->region[0]);
0669 }
0670
0671 static int omap_lcdc_init(struct omapfb_device *fbdev, int ext_mode,
0672 struct omapfb_mem_desc *req_vram)
0673 {
0674 int r;
0675 u32 l;
0676 int rate;
0677 struct clk *tc_ck;
0678
0679 lcdc.irq_mask = 0;
0680
0681 lcdc.fbdev = fbdev;
0682 lcdc.ext_mode = ext_mode;
0683
0684 l = 0;
0685 omap_writel(l, OMAP_LCDC_CONTROL);
0686
0687
0688
0689
0690 lcdc.lcd_ck = clk_get(fbdev->dev, "lcd_ck");
0691 if (IS_ERR(lcdc.lcd_ck)) {
0692 dev_err(fbdev->dev, "unable to access LCD clock\n");
0693 r = PTR_ERR(lcdc.lcd_ck);
0694 goto fail0;
0695 }
0696
0697 tc_ck = clk_get(fbdev->dev, "tc_ck");
0698 if (IS_ERR(tc_ck)) {
0699 dev_err(fbdev->dev, "unable to access TC clock\n");
0700 r = PTR_ERR(tc_ck);
0701 goto fail1;
0702 }
0703
0704 rate = clk_get_rate(tc_ck);
0705 clk_put(tc_ck);
0706
0707 if (machine_is_ams_delta())
0708 rate /= 4;
0709 if (machine_is_omap_h3())
0710 rate /= 3;
0711 r = clk_set_rate(lcdc.lcd_ck, rate);
0712 if (r) {
0713 dev_err(fbdev->dev, "failed to adjust LCD rate\n");
0714 goto fail1;
0715 }
0716 clk_prepare_enable(lcdc.lcd_ck);
0717
0718 r = request_irq(fbdev->int_irq, lcdc_irq_handler, 0, MODULE_NAME, fbdev);
0719 if (r) {
0720 dev_err(fbdev->dev, "unable to get IRQ\n");
0721 goto fail2;
0722 }
0723
0724 r = omap_request_lcd_dma(lcdc_dma_handler, NULL);
0725 if (r) {
0726 dev_err(fbdev->dev, "unable to get LCD DMA\n");
0727 goto fail3;
0728 }
0729
0730 omap_set_lcd_dma_single_transfer(ext_mode);
0731 omap_set_lcd_dma_ext_controller(ext_mode);
0732
0733 if (!ext_mode)
0734 if ((r = alloc_palette_ram()) < 0)
0735 goto fail4;
0736
0737 if ((r = setup_fbmem(req_vram)) < 0)
0738 goto fail5;
0739
0740 pr_info("omapfb: LCDC initialized\n");
0741
0742 return 0;
0743 fail5:
0744 if (!ext_mode)
0745 free_palette_ram();
0746 fail4:
0747 omap_free_lcd_dma();
0748 fail3:
0749 free_irq(fbdev->int_irq, lcdc.fbdev);
0750 fail2:
0751 clk_disable_unprepare(lcdc.lcd_ck);
0752 fail1:
0753 clk_put(lcdc.lcd_ck);
0754 fail0:
0755 return r;
0756 }
0757
0758 static void omap_lcdc_cleanup(void)
0759 {
0760 if (!lcdc.ext_mode)
0761 free_palette_ram();
0762 free_fbmem();
0763 omap_free_lcd_dma();
0764 free_irq(lcdc.fbdev->int_irq, lcdc.fbdev);
0765 clk_disable_unprepare(lcdc.lcd_ck);
0766 clk_put(lcdc.lcd_ck);
0767 }
0768
0769 const struct lcd_ctrl omap1_int_ctrl = {
0770 .name = "internal",
0771 .init = omap_lcdc_init,
0772 .cleanup = omap_lcdc_cleanup,
0773 .get_caps = omap_lcdc_get_caps,
0774 .set_update_mode = omap_lcdc_set_update_mode,
0775 .get_update_mode = omap_lcdc_get_update_mode,
0776 .update_window = NULL,
0777 .suspend = omap_lcdc_suspend,
0778 .resume = omap_lcdc_resume,
0779 .setup_plane = omap_lcdc_setup_plane,
0780 .enable_plane = omap_lcdc_enable_plane,
0781 .setcolreg = omap_lcdc_setcolreg,
0782 };