Back to home page

OSCL-LXR

 
 

    


0001 // SPDX-License-Identifier: GPL-2.0-or-later
0002 /*
0003  * OMAP1 internal LCD controller
0004  *
0005  * Copyright (C) 2004 Nokia Corporation
0006  * Author: Imre Deak <imre.deak@nokia.com>
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;    /* enabled IRQs */
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      * Preserve the DONE mask, since we still want to get the
0122      * final DONE irq. It will be disabled in the IRQ handler.
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  * Configure the LCD DMA according to the current mode specified by parameters
0162  * in lcdc.fbdev and fbdev->var.
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          * YUV support is only for external mode when we have the
0216          * YUV window embedded in a 16bpp frame buffer.
0217          */
0218         if (lcdc.color_mode == OMAPFB_COLOR_YUV420)
0219             bpp = 16;
0220         /* Set virtual xres elem size */
0221         omap_set_lcd_dma_b1_vxres(
0222             lcdc.screen_width * bpp / 8 / esize);
0223         /* Setup transformations */
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              * Disable IRQ_DONE. The status bit will be cleared
0244              * only when the controller is reenabled and we don't
0245              * want to get more interrupts.
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      * Clear these interrupt status bits.
0260      * Sync_lost, FUF bits were cleared by disabling the LCD controller
0261      * LOADED_PALETTE can be cleared this way only in palette only
0262      * load mode. In other load modes it's cleared by disabling the
0263      * controller.
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  * Change to a new video mode. We defer this to a later time to avoid any
0275  * flicker and not to mess up the current LCD DMA context. For this we disable
0276  * the LCD controller, which will generate a DONE irq after the last frame has
0277  * been transferred. Then it'll be safe to reconfigure both the LCD controller
0278  * as well as the LCD DMA.
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         /* FIXME: other BPPs.
0342          * bpp1: code  0,     size 256
0343          * bpp2: code  0x1000 size 256
0344          * bpp4: code  0x2000 size 256
0345          * bpp12: code 0x4000 size 32
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  * Configure the LCD DMA for a palette load operation and do the palette
0380  * downloading synchronously. We don't use the frame+palette load mode of
0381  * the controller, since the palette can always be downloaded separately.
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     /* The controller gets disabled in the irq handler */
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 /* Used only in internal controller mode */
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         /* FIXME: try to adjust logic clock divider as well */
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 /* FIXME:if (machine_is_omap_palmte()) { */
0471         /* PalmTE uses alternate TFT setting in 8BPP mode */
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     /* update panel info with the exact clock */
0515     panel->pixel_clock = lck / pcd / 1000;
0516 }
0517 
0518 /*
0519  * Configure the LCD controller, download the color palette and start a looped
0520  * DMA transfer of the frame image data. Called only in internal
0521  * controller mode.
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             /* Setup and start LCD DMA */
0534             setup_lcd_dma();
0535 
0536             set_load_mode(OMAP_LCDC_LOAD_FRAME);
0537             enable_irqs(OMAP_LCDC_IRQ_DONE);
0538             /* This will start the actual DMA transfer */
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 /* PM code called only in internal controller mode */
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     /* FIXME:
0688      * According to errata some platforms have a clock rate limitiation
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 };