linux/drivers/video/fbdev/omap/lcdc.c
<<
>>
Prefs
   1// SPDX-License-Identifier: GPL-2.0-or-later
   2/*
   3 * OMAP1 internal LCD controller
   4 *
   5 * Copyright (C) 2004 Nokia Corporation
   6 * Author: Imre Deak <imre.deak@nokia.com>
   7 */
   8#include <linux/module.h>
   9#include <linux/device.h>
  10#include <linux/interrupt.h>
  11#include <linux/spinlock.h>
  12#include <linux/err.h>
  13#include <linux/mm.h>
  14#include <linux/fb.h>
  15#include <linux/dma-mapping.h>
  16#include <linux/vmalloc.h>
  17#include <linux/clk.h>
  18#include <linux/gfp.h>
  19
  20#include <mach/lcdc.h>
  21#include <linux/omap-dma.h>
  22
  23#include <asm/mach-types.h>
  24
  25#include "omapfb.h"
  26
  27#include "lcdc.h"
  28
  29#define MODULE_NAME                     "lcdc"
  30
  31#define MAX_PALETTE_SIZE                PAGE_SIZE
  32
  33enum lcdc_load_mode {
  34        OMAP_LCDC_LOAD_PALETTE,
  35        OMAP_LCDC_LOAD_FRAME,
  36        OMAP_LCDC_LOAD_PALETTE_AND_FRAME
  37};
  38
  39static struct omap_lcd_controller {
  40        enum omapfb_update_mode update_mode;
  41        int                     ext_mode;
  42
  43        unsigned long           frame_offset;
  44        int                     screen_width;
  45        int                     xres;
  46        int                     yres;
  47
  48        enum omapfb_color_format        color_mode;
  49        int                     bpp;
  50        void                    *palette_virt;
  51        dma_addr_t              palette_phys;
  52        int                     palette_code;
  53        int                     palette_size;
  54
  55        unsigned int            irq_mask;
  56        struct completion       last_frame_complete;
  57        struct completion       palette_load_complete;
  58        struct clk              *lcd_ck;
  59        struct omapfb_device    *fbdev;
  60
  61        void                    (*dma_callback)(void *data);
  62        void                    *dma_callback_data;
  63
  64        dma_addr_t              vram_phys;
  65        void                    *vram_virt;
  66        unsigned long           vram_size;
  67} lcdc;
  68
  69static inline void enable_irqs(int mask)
  70{
  71        lcdc.irq_mask |= mask;
  72}
  73
  74static inline void disable_irqs(int mask)
  75{
  76        lcdc.irq_mask &= ~mask;
  77}
  78
  79static void set_load_mode(enum lcdc_load_mode mode)
  80{
  81        u32 l;
  82
  83        l = omap_readl(OMAP_LCDC_CONTROL);
  84        l &= ~(3 << 20);
  85        switch (mode) {
  86        case OMAP_LCDC_LOAD_PALETTE:
  87                l |= 1 << 20;
  88                break;
  89        case OMAP_LCDC_LOAD_FRAME:
  90                l |= 2 << 20;
  91                break;
  92        case OMAP_LCDC_LOAD_PALETTE_AND_FRAME:
  93                break;
  94        default:
  95                BUG();
  96        }
  97        omap_writel(l, OMAP_LCDC_CONTROL);
  98}
  99
 100static void enable_controller(void)
 101{
 102        u32 l;
 103
 104        l = omap_readl(OMAP_LCDC_CONTROL);
 105        l |= OMAP_LCDC_CTRL_LCD_EN;
 106        l &= ~OMAP_LCDC_IRQ_MASK;
 107        l |= lcdc.irq_mask | OMAP_LCDC_IRQ_DONE;        /* enabled IRQs */
 108        omap_writel(l, OMAP_LCDC_CONTROL);
 109}
 110
 111static void disable_controller_async(void)
 112{
 113        u32 l;
 114        u32 mask;
 115
 116        l = omap_readl(OMAP_LCDC_CONTROL);
 117        mask = OMAP_LCDC_CTRL_LCD_EN | OMAP_LCDC_IRQ_MASK;
 118        /*
 119         * Preserve the DONE mask, since we still want to get the
 120         * final DONE irq. It will be disabled in the IRQ handler.
 121         */
 122        mask &= ~OMAP_LCDC_IRQ_DONE;
 123        l &= ~mask;
 124        omap_writel(l, OMAP_LCDC_CONTROL);
 125}
 126
 127static void disable_controller(void)
 128{
 129        init_completion(&lcdc.last_frame_complete);
 130        disable_controller_async();
 131        if (!wait_for_completion_timeout(&lcdc.last_frame_complete,
 132                                msecs_to_jiffies(500)))
 133                dev_err(lcdc.fbdev->dev, "timeout waiting for FRAME DONE\n");
 134}
 135
 136static void reset_controller(u32 status)
 137{
 138        static unsigned long reset_count;
 139        static unsigned long last_jiffies;
 140
 141        disable_controller_async();
 142        reset_count++;
 143        if (reset_count == 1 || time_after(jiffies, last_jiffies + HZ)) {
 144                dev_err(lcdc.fbdev->dev,
 145                          "resetting (status %#010x,reset count %lu)\n",
 146                          status, reset_count);
 147                last_jiffies = jiffies;
 148        }
 149        if (reset_count < 100) {
 150                enable_controller();
 151        } else {
 152                reset_count = 0;
 153                dev_err(lcdc.fbdev->dev,
 154                        "too many reset attempts, giving up.\n");
 155        }
 156}
 157
 158/*
 159 * Configure the LCD DMA according to the current mode specified by parameters
 160 * in lcdc.fbdev and fbdev->var.
 161 */
 162static void setup_lcd_dma(void)
 163{
 164        static const int dma_elem_type[] = {
 165                0,
 166                OMAP_DMA_DATA_TYPE_S8,
 167                OMAP_DMA_DATA_TYPE_S16,
 168                0,
 169                OMAP_DMA_DATA_TYPE_S32,
 170        };
 171        struct omapfb_plane_struct *plane = lcdc.fbdev->fb_info[0]->par;
 172        struct fb_var_screeninfo *var = &lcdc.fbdev->fb_info[0]->var;
 173        unsigned long   src;
 174        int             esize, xelem, yelem;
 175
 176        src = lcdc.vram_phys + lcdc.frame_offset;
 177
 178        switch (var->rotate) {
 179        case 0:
 180                if (plane->info.mirror || (src & 3) ||
 181                    lcdc.color_mode == OMAPFB_COLOR_YUV420 ||
 182                    (lcdc.xres & 1))
 183                        esize = 2;
 184                else
 185                        esize = 4;
 186                xelem = lcdc.xres * lcdc.bpp / 8 / esize;
 187                yelem = lcdc.yres;
 188                break;
 189        case 90:
 190        case 180:
 191        case 270:
 192                if (cpu_is_omap15xx()) {
 193                        BUG();
 194                }
 195                esize = 2;
 196                xelem = lcdc.yres * lcdc.bpp / 16;
 197                yelem = lcdc.xres;
 198                break;
 199        default:
 200                BUG();
 201                return;
 202        }
 203#ifdef VERBOSE
 204        dev_dbg(lcdc.fbdev->dev,
 205                 "setup_dma: src %#010lx esize %d xelem %d yelem %d\n",
 206                 src, esize, xelem, yelem);
 207#endif
 208        omap_set_lcd_dma_b1(src, xelem, yelem, dma_elem_type[esize]);
 209        if (!cpu_is_omap15xx()) {
 210                int bpp = lcdc.bpp;
 211
 212                /*
 213                 * YUV support is only for external mode when we have the
 214                 * YUV window embedded in a 16bpp frame buffer.
 215                 */
 216                if (lcdc.color_mode == OMAPFB_COLOR_YUV420)
 217                        bpp = 16;
 218                /* Set virtual xres elem size */
 219                omap_set_lcd_dma_b1_vxres(
 220                        lcdc.screen_width * bpp / 8 / esize);
 221                /* Setup transformations */
 222                omap_set_lcd_dma_b1_rotation(var->rotate);
 223                omap_set_lcd_dma_b1_mirror(plane->info.mirror);
 224        }
 225        omap_setup_lcd_dma();
 226}
 227
 228static irqreturn_t lcdc_irq_handler(int irq, void *dev_id)
 229{
 230        u32 status;
 231
 232        status = omap_readl(OMAP_LCDC_STATUS);
 233
 234        if (status & (OMAP_LCDC_STAT_FUF | OMAP_LCDC_STAT_SYNC_LOST))
 235                reset_controller(status);
 236        else {
 237                if (status & OMAP_LCDC_STAT_DONE) {
 238                        u32 l;
 239
 240                        /*
 241                         * Disable IRQ_DONE. The status bit will be cleared
 242                         * only when the controller is reenabled and we don't
 243                         * want to get more interrupts.
 244                         */
 245                        l = omap_readl(OMAP_LCDC_CONTROL);
 246                        l &= ~OMAP_LCDC_IRQ_DONE;
 247                        omap_writel(l, OMAP_LCDC_CONTROL);
 248                        complete(&lcdc.last_frame_complete);
 249                }
 250                if (status & OMAP_LCDC_STAT_LOADED_PALETTE) {
 251                        disable_controller_async();
 252                        complete(&lcdc.palette_load_complete);
 253                }
 254        }
 255
 256        /*
 257         * Clear these interrupt status bits.
 258         * Sync_lost, FUF bits were cleared by disabling the LCD controller
 259         * LOADED_PALETTE can be cleared this way only in palette only
 260         * load mode. In other load modes it's cleared by disabling the
 261         * controller.
 262         */
 263        status &= ~(OMAP_LCDC_STAT_VSYNC |
 264                    OMAP_LCDC_STAT_LOADED_PALETTE |
 265                    OMAP_LCDC_STAT_ABC |
 266                    OMAP_LCDC_STAT_LINE_INT);
 267        omap_writel(status, OMAP_LCDC_STATUS);
 268        return IRQ_HANDLED;
 269}
 270
 271/*
 272 * Change to a new video mode. We defer this to a later time to avoid any
 273 * flicker and not to mess up the current LCD DMA context. For this we disable
 274 * the LCD controller, which will generate a DONE irq after the last frame has
 275 * been transferred. Then it'll be safe to reconfigure both the LCD controller
 276 * as well as the LCD DMA.
 277 */
 278static int omap_lcdc_setup_plane(int plane, int channel_out,
 279                                 unsigned long offset, int screen_width,
 280                                 int pos_x, int pos_y, int width, int height,
 281                                 int color_mode)
 282{
 283        struct fb_var_screeninfo *var = &lcdc.fbdev->fb_info[0]->var;
 284        struct lcd_panel *panel = lcdc.fbdev->panel;
 285        int rot_x, rot_y;
 286
 287        if (var->rotate == 0) {
 288                rot_x = panel->x_res;
 289                rot_y = panel->y_res;
 290        } else {
 291                rot_x = panel->y_res;
 292                rot_y = panel->x_res;
 293        }
 294        if (plane != 0 || channel_out != 0 || pos_x != 0 || pos_y != 0 ||
 295            width > rot_x || height > rot_y) {
 296#ifdef VERBOSE
 297                dev_dbg(lcdc.fbdev->dev,
 298                        "invalid plane params plane %d pos_x %d pos_y %d "
 299                        "w %d h %d\n", plane, pos_x, pos_y, width, height);
 300#endif
 301                return -EINVAL;
 302        }
 303
 304        lcdc.frame_offset = offset;
 305        lcdc.xres = width;
 306        lcdc.yres = height;
 307        lcdc.screen_width = screen_width;
 308        lcdc.color_mode = color_mode;
 309
 310        switch (color_mode) {
 311        case OMAPFB_COLOR_CLUT_8BPP:
 312                lcdc.bpp = 8;
 313                lcdc.palette_code = 0x3000;
 314                lcdc.palette_size = 512;
 315                break;
 316        case OMAPFB_COLOR_RGB565:
 317                lcdc.bpp = 16;
 318                lcdc.palette_code = 0x4000;
 319                lcdc.palette_size = 32;
 320                break;
 321        case OMAPFB_COLOR_RGB444:
 322                lcdc.bpp = 16;
 323                lcdc.palette_code = 0x4000;
 324                lcdc.palette_size = 32;
 325                break;
 326        case OMAPFB_COLOR_YUV420:
 327                if (lcdc.ext_mode) {
 328                        lcdc.bpp = 12;
 329                        break;
 330                }
 331                fallthrough;
 332        case OMAPFB_COLOR_YUV422:
 333                if (lcdc.ext_mode) {
 334                        lcdc.bpp = 16;
 335                        break;
 336                }
 337                fallthrough;
 338        default:
 339                /* FIXME: other BPPs.
 340                 * bpp1: code  0,     size 256
 341                 * bpp2: code  0x1000 size 256
 342                 * bpp4: code  0x2000 size 256
 343                 * bpp12: code 0x4000 size 32
 344                 */
 345                dev_dbg(lcdc.fbdev->dev, "invalid color mode %d\n", color_mode);
 346                BUG();
 347                return -1;
 348        }
 349
 350        if (lcdc.ext_mode) {
 351                setup_lcd_dma();
 352                return 0;
 353        }
 354
 355        if (lcdc.update_mode == OMAPFB_AUTO_UPDATE) {
 356                disable_controller();
 357                omap_stop_lcd_dma();
 358                setup_lcd_dma();
 359                enable_controller();
 360        }
 361
 362        return 0;
 363}
 364
 365static int omap_lcdc_enable_plane(int plane, int enable)
 366{
 367        dev_dbg(lcdc.fbdev->dev,
 368                "plane %d enable %d update_mode %d ext_mode %d\n",
 369                plane, enable, lcdc.update_mode, lcdc.ext_mode);
 370        if (plane != OMAPFB_PLANE_GFX)
 371                return -EINVAL;
 372
 373        return 0;
 374}
 375
 376/*
 377 * Configure the LCD DMA for a palette load operation and do the palette
 378 * downloading synchronously. We don't use the frame+palette load mode of
 379 * the controller, since the palette can always be downloaded separately.
 380 */
 381static void load_palette(void)
 382{
 383        u16     *palette;
 384
 385        palette = (u16 *)lcdc.palette_virt;
 386
 387        *(u16 *)palette &= 0x0fff;
 388        *(u16 *)palette |= lcdc.palette_code;
 389
 390        omap_set_lcd_dma_b1(lcdc.palette_phys,
 391                lcdc.palette_size / 4 + 1, 1, OMAP_DMA_DATA_TYPE_S32);
 392
 393        omap_set_lcd_dma_single_transfer(1);
 394        omap_setup_lcd_dma();
 395
 396        init_completion(&lcdc.palette_load_complete);
 397        enable_irqs(OMAP_LCDC_IRQ_LOADED_PALETTE);
 398        set_load_mode(OMAP_LCDC_LOAD_PALETTE);
 399        enable_controller();
 400        if (!wait_for_completion_timeout(&lcdc.palette_load_complete,
 401                                msecs_to_jiffies(500)))
 402                dev_err(lcdc.fbdev->dev, "timeout waiting for FRAME DONE\n");
 403        /* The controller gets disabled in the irq handler */
 404        disable_irqs(OMAP_LCDC_IRQ_LOADED_PALETTE);
 405        omap_stop_lcd_dma();
 406
 407        omap_set_lcd_dma_single_transfer(lcdc.ext_mode);
 408}
 409
 410/* Used only in internal controller mode */
 411static int omap_lcdc_setcolreg(u_int regno, u16 red, u16 green, u16 blue,
 412                               u16 transp, int update_hw_pal)
 413{
 414        u16 *palette;
 415
 416        if (lcdc.color_mode != OMAPFB_COLOR_CLUT_8BPP || regno > 255)
 417                return -EINVAL;
 418
 419        palette = (u16 *)lcdc.palette_virt;
 420
 421        palette[regno] &= ~0x0fff;
 422        palette[regno] |= ((red >> 12) << 8) | ((green >> 12) << 4 ) |
 423                           (blue >> 12);
 424
 425        if (update_hw_pal) {
 426                disable_controller();
 427                omap_stop_lcd_dma();
 428                load_palette();
 429                setup_lcd_dma();
 430                set_load_mode(OMAP_LCDC_LOAD_FRAME);
 431                enable_controller();
 432        }
 433
 434        return 0;
 435}
 436
 437static void calc_ck_div(int is_tft, int pck, int *pck_div)
 438{
 439        unsigned long lck;
 440
 441        pck = max(1, pck);
 442        lck = clk_get_rate(lcdc.lcd_ck);
 443        *pck_div = (lck + pck - 1) / pck;
 444        if (is_tft)
 445                *pck_div = max(2, *pck_div);
 446        else
 447                *pck_div = max(3, *pck_div);
 448        if (*pck_div > 255) {
 449                /* FIXME: try to adjust logic clock divider as well */
 450                *pck_div = 255;
 451                dev_warn(lcdc.fbdev->dev, "pixclock %d kHz too low.\n",
 452                         pck / 1000);
 453        }
 454}
 455
 456static inline void setup_regs(void)
 457{
 458        u32 l;
 459        struct lcd_panel *panel = lcdc.fbdev->panel;
 460        int is_tft = panel->config & OMAP_LCDC_PANEL_TFT;
 461        unsigned long lck;
 462        int pcd;
 463
 464        l = omap_readl(OMAP_LCDC_CONTROL);
 465        l &= ~OMAP_LCDC_CTRL_LCD_TFT;
 466        l |= is_tft ? OMAP_LCDC_CTRL_LCD_TFT : 0;
 467#ifdef CONFIG_MACH_OMAP_PALMTE
 468/* FIXME:if (machine_is_omap_palmte()) { */
 469                /* PalmTE uses alternate TFT setting in 8BPP mode */
 470                l |= (is_tft && panel->bpp == 8) ? 0x810000 : 0;
 471/*      } */
 472#endif
 473        omap_writel(l, OMAP_LCDC_CONTROL);
 474
 475        l = omap_readl(OMAP_LCDC_TIMING2);
 476        l &= ~(((1 << 6) - 1) << 20);
 477        l |= (panel->config & OMAP_LCDC_SIGNAL_MASK) << 20;
 478        omap_writel(l, OMAP_LCDC_TIMING2);
 479
 480        l = panel->x_res - 1;
 481        l |= (panel->hsw - 1) << 10;
 482        l |= (panel->hfp - 1) << 16;
 483        l |= (panel->hbp - 1) << 24;
 484        omap_writel(l, OMAP_LCDC_TIMING0);
 485
 486        l = panel->y_res - 1;
 487        l |= (panel->vsw - 1) << 10;
 488        l |= panel->vfp << 16;
 489        l |= panel->vbp << 24;
 490        omap_writel(l, OMAP_LCDC_TIMING1);
 491
 492        l = omap_readl(OMAP_LCDC_TIMING2);
 493        l &= ~0xff;
 494
 495        lck = clk_get_rate(lcdc.lcd_ck);
 496
 497        if (!panel->pcd)
 498                calc_ck_div(is_tft, panel->pixel_clock * 1000, &pcd);
 499        else {
 500                dev_warn(lcdc.fbdev->dev,
 501                    "Pixel clock divider value is obsolete.\n"
 502                    "Try to set pixel_clock to %lu and pcd to 0 "
 503                    "in drivers/video/omap/lcd_%s.c and submit a patch.\n",
 504                        lck / panel->pcd / 1000, panel->name);
 505
 506                pcd = panel->pcd;
 507        }
 508        l |= pcd & 0xff;
 509        l |= panel->acb << 8;
 510        omap_writel(l, OMAP_LCDC_TIMING2);
 511
 512        /* update panel info with the exact clock */
 513        panel->pixel_clock = lck / pcd / 1000;
 514}
 515
 516/*
 517 * Configure the LCD controller, download the color palette and start a looped
 518 * DMA transfer of the frame image data. Called only in internal
 519 * controller mode.
 520 */
 521static int omap_lcdc_set_update_mode(enum omapfb_update_mode mode)
 522{
 523        int r = 0;
 524
 525        if (mode != lcdc.update_mode) {
 526                switch (mode) {
 527                case OMAPFB_AUTO_UPDATE:
 528                        setup_regs();
 529                        load_palette();
 530
 531                        /* Setup and start LCD DMA */
 532                        setup_lcd_dma();
 533
 534                        set_load_mode(OMAP_LCDC_LOAD_FRAME);
 535                        enable_irqs(OMAP_LCDC_IRQ_DONE);
 536                        /* This will start the actual DMA transfer */
 537                        enable_controller();
 538                        lcdc.update_mode = mode;
 539                        break;
 540                case OMAPFB_UPDATE_DISABLED:
 541                        disable_controller();
 542                        omap_stop_lcd_dma();
 543                        lcdc.update_mode = mode;
 544                        break;
 545                default:
 546                        r = -EINVAL;
 547                }
 548        }
 549
 550        return r;
 551}
 552
 553static enum omapfb_update_mode omap_lcdc_get_update_mode(void)
 554{
 555        return lcdc.update_mode;
 556}
 557
 558/* PM code called only in internal controller mode */
 559static void omap_lcdc_suspend(void)
 560{
 561        omap_lcdc_set_update_mode(OMAPFB_UPDATE_DISABLED);
 562}
 563
 564static void omap_lcdc_resume(void)
 565{
 566        omap_lcdc_set_update_mode(OMAPFB_AUTO_UPDATE);
 567}
 568
 569static void omap_lcdc_get_caps(int plane, struct omapfb_caps *caps)
 570{
 571        return;
 572}
 573
 574int omap_lcdc_set_dma_callback(void (*callback)(void *data), void *data)
 575{
 576        BUG_ON(callback == NULL);
 577
 578        if (lcdc.dma_callback)
 579                return -EBUSY;
 580        else {
 581                lcdc.dma_callback = callback;
 582                lcdc.dma_callback_data = data;
 583        }
 584        return 0;
 585}
 586EXPORT_SYMBOL(omap_lcdc_set_dma_callback);
 587
 588void omap_lcdc_free_dma_callback(void)
 589{
 590        lcdc.dma_callback = NULL;
 591}
 592EXPORT_SYMBOL(omap_lcdc_free_dma_callback);
 593
 594static void lcdc_dma_handler(u16 status, void *data)
 595{
 596        if (lcdc.dma_callback)
 597                lcdc.dma_callback(lcdc.dma_callback_data);
 598}
 599
 600static int alloc_palette_ram(void)
 601{
 602        lcdc.palette_virt = dma_alloc_wc(lcdc.fbdev->dev, MAX_PALETTE_SIZE,
 603                                         &lcdc.palette_phys, GFP_KERNEL);
 604        if (lcdc.palette_virt == NULL) {
 605                dev_err(lcdc.fbdev->dev, "failed to alloc palette memory\n");
 606                return -ENOMEM;
 607        }
 608        memset(lcdc.palette_virt, 0, MAX_PALETTE_SIZE);
 609
 610        return 0;
 611}
 612
 613static void free_palette_ram(void)
 614{
 615        dma_free_wc(lcdc.fbdev->dev, MAX_PALETTE_SIZE, lcdc.palette_virt,
 616                    lcdc.palette_phys);
 617}
 618
 619static int alloc_fbmem(struct omapfb_mem_region *region)
 620{
 621        int bpp;
 622        int frame_size;
 623        struct lcd_panel *panel = lcdc.fbdev->panel;
 624
 625        bpp = panel->bpp;
 626        if (bpp == 12)
 627                bpp = 16;
 628        frame_size = PAGE_ALIGN(panel->x_res * bpp / 8 * panel->y_res);
 629        if (region->size > frame_size)
 630                frame_size = region->size;
 631        lcdc.vram_size = frame_size;
 632        lcdc.vram_virt = dma_alloc_wc(lcdc.fbdev->dev, lcdc.vram_size,
 633                                      &lcdc.vram_phys, GFP_KERNEL);
 634        if (lcdc.vram_virt == NULL) {
 635                dev_err(lcdc.fbdev->dev, "unable to allocate FB DMA memory\n");
 636                return -ENOMEM;
 637        }
 638        region->size = frame_size;
 639        region->paddr = lcdc.vram_phys;
 640        region->vaddr = lcdc.vram_virt;
 641        region->alloc = 1;
 642
 643        memset(lcdc.vram_virt, 0, lcdc.vram_size);
 644
 645        return 0;
 646}
 647
 648static void free_fbmem(void)
 649{
 650        dma_free_wc(lcdc.fbdev->dev, lcdc.vram_size, lcdc.vram_virt,
 651                    lcdc.vram_phys);
 652}
 653
 654static int setup_fbmem(struct omapfb_mem_desc *req_md)
 655{
 656        if (!req_md->region_cnt) {
 657                dev_err(lcdc.fbdev->dev, "no memory regions defined\n");
 658                return -EINVAL;
 659        }
 660
 661        if (req_md->region_cnt > 1) {
 662                dev_err(lcdc.fbdev->dev, "only one plane is supported\n");
 663                req_md->region_cnt = 1;
 664        }
 665
 666        return alloc_fbmem(&req_md->region[0]);
 667}
 668
 669static int omap_lcdc_init(struct omapfb_device *fbdev, int ext_mode,
 670                          struct omapfb_mem_desc *req_vram)
 671{
 672        int r;
 673        u32 l;
 674        int rate;
 675        struct clk *tc_ck;
 676
 677        lcdc.irq_mask = 0;
 678
 679        lcdc.fbdev = fbdev;
 680        lcdc.ext_mode = ext_mode;
 681
 682        l = 0;
 683        omap_writel(l, OMAP_LCDC_CONTROL);
 684
 685        /* FIXME:
 686         * According to errata some platforms have a clock rate limitiation
 687         */
 688        lcdc.lcd_ck = clk_get(fbdev->dev, "lcd_ck");
 689        if (IS_ERR(lcdc.lcd_ck)) {
 690                dev_err(fbdev->dev, "unable to access LCD clock\n");
 691                r = PTR_ERR(lcdc.lcd_ck);
 692                goto fail0;
 693        }
 694
 695        tc_ck = clk_get(fbdev->dev, "tc_ck");
 696        if (IS_ERR(tc_ck)) {
 697                dev_err(fbdev->dev, "unable to access TC clock\n");
 698                r = PTR_ERR(tc_ck);
 699                goto fail1;
 700        }
 701
 702        rate = clk_get_rate(tc_ck);
 703        clk_put(tc_ck);
 704
 705        if (machine_is_ams_delta())
 706                rate /= 4;
 707        if (machine_is_omap_h3())
 708                rate /= 3;
 709        r = clk_set_rate(lcdc.lcd_ck, rate);
 710        if (r) {
 711                dev_err(fbdev->dev, "failed to adjust LCD rate\n");
 712                goto fail1;
 713        }
 714        clk_enable(lcdc.lcd_ck);
 715
 716        r = request_irq(OMAP_LCDC_IRQ, lcdc_irq_handler, 0, MODULE_NAME, fbdev);
 717        if (r) {
 718                dev_err(fbdev->dev, "unable to get IRQ\n");
 719                goto fail2;
 720        }
 721
 722        r = omap_request_lcd_dma(lcdc_dma_handler, NULL);
 723        if (r) {
 724                dev_err(fbdev->dev, "unable to get LCD DMA\n");
 725                goto fail3;
 726        }
 727
 728        omap_set_lcd_dma_single_transfer(ext_mode);
 729        omap_set_lcd_dma_ext_controller(ext_mode);
 730
 731        if (!ext_mode)
 732                if ((r = alloc_palette_ram()) < 0)
 733                        goto fail4;
 734
 735        if ((r = setup_fbmem(req_vram)) < 0)
 736                goto fail5;
 737
 738        pr_info("omapfb: LCDC initialized\n");
 739
 740        return 0;
 741fail5:
 742        if (!ext_mode)
 743                free_palette_ram();
 744fail4:
 745        omap_free_lcd_dma();
 746fail3:
 747        free_irq(OMAP_LCDC_IRQ, lcdc.fbdev);
 748fail2:
 749        clk_disable(lcdc.lcd_ck);
 750fail1:
 751        clk_put(lcdc.lcd_ck);
 752fail0:
 753        return r;
 754}
 755
 756static void omap_lcdc_cleanup(void)
 757{
 758        if (!lcdc.ext_mode)
 759                free_palette_ram();
 760        free_fbmem();
 761        omap_free_lcd_dma();
 762        free_irq(OMAP_LCDC_IRQ, lcdc.fbdev);
 763        clk_disable(lcdc.lcd_ck);
 764        clk_put(lcdc.lcd_ck);
 765}
 766
 767const struct lcd_ctrl omap1_int_ctrl = {
 768        .name                   = "internal",
 769        .init                   = omap_lcdc_init,
 770        .cleanup                = omap_lcdc_cleanup,
 771        .get_caps               = omap_lcdc_get_caps,
 772        .set_update_mode        = omap_lcdc_set_update_mode,
 773        .get_update_mode        = omap_lcdc_get_update_mode,
 774        .update_window          = NULL,
 775        .suspend                = omap_lcdc_suspend,
 776        .resume                 = omap_lcdc_resume,
 777        .setup_plane            = omap_lcdc_setup_plane,
 778        .enable_plane           = omap_lcdc_enable_plane,
 779        .setcolreg              = omap_lcdc_setcolreg,
 780};
 781