root/drivers/video/fbdev/omap/lcdc.c

/* [<][>][^][v][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. enable_irqs
  2. disable_irqs
  3. set_load_mode
  4. enable_controller
  5. disable_controller_async
  6. disable_controller
  7. reset_controller
  8. setup_lcd_dma
  9. lcdc_irq_handler
  10. omap_lcdc_setup_plane
  11. omap_lcdc_enable_plane
  12. load_palette
  13. omap_lcdc_setcolreg
  14. calc_ck_div
  15. setup_regs
  16. omap_lcdc_set_update_mode
  17. omap_lcdc_get_update_mode
  18. omap_lcdc_suspend
  19. omap_lcdc_resume
  20. omap_lcdc_get_caps
  21. omap_lcdc_set_dma_callback
  22. omap_lcdc_free_dma_callback
  23. lcdc_dma_handler
  24. alloc_palette_ram
  25. free_palette_ram
  26. alloc_fbmem
  27. free_fbmem
  28. setup_fbmem
  29. omap_lcdc_init
  30. omap_lcdc_cleanup

   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 
  33 enum lcdc_load_mode {
  34         OMAP_LCDC_LOAD_PALETTE,
  35         OMAP_LCDC_LOAD_FRAME,
  36         OMAP_LCDC_LOAD_PALETTE_AND_FRAME
  37 };
  38 
  39 static 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 
  69 static inline void enable_irqs(int mask)
  70 {
  71         lcdc.irq_mask |= mask;
  72 }
  73 
  74 static inline void disable_irqs(int mask)
  75 {
  76         lcdc.irq_mask &= ~mask;
  77 }
  78 
  79 static 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 
 100 static 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 
 111 static 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 
 127 static 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 
 136 static 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  */
 162 static 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 
 228 static 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  */
 278 static 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 
 365 static 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  */
 381 static 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 */
 411 static 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 
 437 static 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 
 456 static 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  */
 521 static 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 
 553 static 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 */
 559 static void omap_lcdc_suspend(void)
 560 {
 561         omap_lcdc_set_update_mode(OMAPFB_UPDATE_DISABLED);
 562 }
 563 
 564 static void omap_lcdc_resume(void)
 565 {
 566         omap_lcdc_set_update_mode(OMAPFB_AUTO_UPDATE);
 567 }
 568 
 569 static void omap_lcdc_get_caps(int plane, struct omapfb_caps *caps)
 570 {
 571         return;
 572 }
 573 
 574 int 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 }
 586 EXPORT_SYMBOL(omap_lcdc_set_dma_callback);
 587 
 588 void omap_lcdc_free_dma_callback(void)
 589 {
 590         lcdc.dma_callback = NULL;
 591 }
 592 EXPORT_SYMBOL(omap_lcdc_free_dma_callback);
 593 
 594 static void lcdc_dma_handler(u16 status, void *data)
 595 {
 596         if (lcdc.dma_callback)
 597                 lcdc.dma_callback(lcdc.dma_callback_data);
 598 }
 599 
 600 static 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 
 613 static 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 
 619 static 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 
 648 static void free_fbmem(void)
 649 {
 650         dma_free_wc(lcdc.fbdev->dev, lcdc.vram_size, lcdc.vram_virt,
 651                     lcdc.vram_phys);
 652 }
 653 
 654 static 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 
 669 static 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;
 741 fail5:
 742         if (!ext_mode)
 743                 free_palette_ram();
 744 fail4:
 745         omap_free_lcd_dma();
 746 fail3:
 747         free_irq(OMAP_LCDC_IRQ, lcdc.fbdev);
 748 fail2:
 749         clk_disable(lcdc.lcd_ck);
 750 fail1:
 751         clk_put(lcdc.lcd_ck);
 752 fail0:
 753         return r;
 754 }
 755 
 756 static 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 
 767 const 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 };

/* [<][>][^][v][top][bottom][index][help] */