root/drivers/video/fbdev/pxa168fb.c

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

DEFINITIONS

This source file includes following definitions.
  1. determine_best_pix_fmt
  2. set_pix_fmt
  3. set_mode
  4. pxa168fb_check_var
  5. set_clock_divider
  6. set_dma_control0
  7. set_dma_control1
  8. set_graphics_start
  9. set_dumb_panel_control
  10. set_dumb_screen_dimensions
  11. pxa168fb_set_par
  12. chan_to_field
  13. to_rgb
  14. pxa168fb_setcolreg
  15. pxa168fb_blank
  16. pxa168fb_pan_display
  17. pxa168fb_handle_irq
  18. pxa168fb_init_mode
  19. pxa168fb_probe
  20. pxa168fb_remove

   1 /*
   2  * linux/drivers/video/pxa168fb.c -- Marvell PXA168 LCD Controller
   3  *
   4  *  Copyright (C) 2008 Marvell International Ltd.
   5  *  All rights reserved.
   6  *
   7  *  2009-02-16  adapted from original version for PXA168/910
   8  *              Jun Nie <njun@marvell.com>
   9  *
  10  * This file is subject to the terms and conditions of the GNU General Public
  11  * License. See the file COPYING in the main directory of this archive for
  12  * more details.
  13  */
  14 
  15 #include <linux/module.h>
  16 #include <linux/kernel.h>
  17 #include <linux/sched.h>
  18 #include <linux/string.h>
  19 #include <linux/interrupt.h>
  20 #include <linux/slab.h>
  21 #include <linux/fb.h>
  22 #include <linux/delay.h>
  23 #include <linux/init.h>
  24 #include <linux/io.h>
  25 #include <linux/ioport.h>
  26 #include <linux/platform_device.h>
  27 #include <linux/dma-mapping.h>
  28 #include <linux/clk.h>
  29 #include <linux/err.h>
  30 #include <linux/uaccess.h>
  31 #include <video/pxa168fb.h>
  32 
  33 #include "pxa168fb.h"
  34 
  35 #define DEFAULT_REFRESH         60      /* Hz */
  36 
  37 static int determine_best_pix_fmt(struct fb_var_screeninfo *var)
  38 {
  39         /*
  40          * Pseudocolor mode?
  41          */
  42         if (var->bits_per_pixel == 8)
  43                 return PIX_FMT_PSEUDOCOLOR;
  44 
  45         /*
  46          * Check for 565/1555.
  47          */
  48         if (var->bits_per_pixel == 16 && var->red.length <= 5 &&
  49             var->green.length <= 6 && var->blue.length <= 5) {
  50                 if (var->transp.length == 0) {
  51                         if (var->red.offset >= var->blue.offset)
  52                                 return PIX_FMT_RGB565;
  53                         else
  54                                 return PIX_FMT_BGR565;
  55                 }
  56 
  57                 if (var->transp.length == 1 && var->green.length <= 5) {
  58                         if (var->red.offset >= var->blue.offset)
  59                                 return PIX_FMT_RGB1555;
  60                         else
  61                                 return PIX_FMT_BGR1555;
  62                 }
  63 
  64                 /* fall through */
  65         }
  66 
  67         /*
  68          * Check for 888/A888.
  69          */
  70         if (var->bits_per_pixel <= 32 && var->red.length <= 8 &&
  71             var->green.length <= 8 && var->blue.length <= 8) {
  72                 if (var->bits_per_pixel == 24 && var->transp.length == 0) {
  73                         if (var->red.offset >= var->blue.offset)
  74                                 return PIX_FMT_RGB888PACK;
  75                         else
  76                                 return PIX_FMT_BGR888PACK;
  77                 }
  78 
  79                 if (var->bits_per_pixel == 32 && var->transp.length == 8) {
  80                         if (var->red.offset >= var->blue.offset)
  81                                 return PIX_FMT_RGBA888;
  82                         else
  83                                 return PIX_FMT_BGRA888;
  84                 } else {
  85                         if (var->red.offset >= var->blue.offset)
  86                                 return PIX_FMT_RGB888UNPACK;
  87                         else
  88                                 return PIX_FMT_BGR888UNPACK;
  89                 }
  90 
  91                 /* fall through */
  92         }
  93 
  94         return -EINVAL;
  95 }
  96 
  97 static void set_pix_fmt(struct fb_var_screeninfo *var, int pix_fmt)
  98 {
  99         switch (pix_fmt) {
 100         case PIX_FMT_RGB565:
 101                 var->bits_per_pixel = 16;
 102                 var->red.offset = 11;    var->red.length = 5;
 103                 var->green.offset = 5;   var->green.length = 6;
 104                 var->blue.offset = 0;    var->blue.length = 5;
 105                 var->transp.offset = 0;  var->transp.length = 0;
 106                 break;
 107         case PIX_FMT_BGR565:
 108                 var->bits_per_pixel = 16;
 109                 var->red.offset = 0;     var->red.length = 5;
 110                 var->green.offset = 5;   var->green.length = 6;
 111                 var->blue.offset = 11;   var->blue.length = 5;
 112                 var->transp.offset = 0;  var->transp.length = 0;
 113                 break;
 114         case PIX_FMT_RGB1555:
 115                 var->bits_per_pixel = 16;
 116                 var->red.offset = 10;    var->red.length = 5;
 117                 var->green.offset = 5;   var->green.length = 5;
 118                 var->blue.offset = 0;    var->blue.length = 5;
 119                 var->transp.offset = 15; var->transp.length = 1;
 120                 break;
 121         case PIX_FMT_BGR1555:
 122                 var->bits_per_pixel = 16;
 123                 var->red.offset = 0;     var->red.length = 5;
 124                 var->green.offset = 5;   var->green.length = 5;
 125                 var->blue.offset = 10;   var->blue.length = 5;
 126                 var->transp.offset = 15; var->transp.length = 1;
 127                 break;
 128         case PIX_FMT_RGB888PACK:
 129                 var->bits_per_pixel = 24;
 130                 var->red.offset = 16;    var->red.length = 8;
 131                 var->green.offset = 8;   var->green.length = 8;
 132                 var->blue.offset = 0;    var->blue.length = 8;
 133                 var->transp.offset = 0;  var->transp.length = 0;
 134                 break;
 135         case PIX_FMT_BGR888PACK:
 136                 var->bits_per_pixel = 24;
 137                 var->red.offset = 0;     var->red.length = 8;
 138                 var->green.offset = 8;   var->green.length = 8;
 139                 var->blue.offset = 16;   var->blue.length = 8;
 140                 var->transp.offset = 0;  var->transp.length = 0;
 141                 break;
 142         case PIX_FMT_RGBA888:
 143                 var->bits_per_pixel = 32;
 144                 var->red.offset = 16;    var->red.length = 8;
 145                 var->green.offset = 8;   var->green.length = 8;
 146                 var->blue.offset = 0;    var->blue.length = 8;
 147                 var->transp.offset = 24; var->transp.length = 8;
 148                 break;
 149         case PIX_FMT_BGRA888:
 150                 var->bits_per_pixel = 32;
 151                 var->red.offset = 0;     var->red.length = 8;
 152                 var->green.offset = 8;   var->green.length = 8;
 153                 var->blue.offset = 16;   var->blue.length = 8;
 154                 var->transp.offset = 24; var->transp.length = 8;
 155                 break;
 156         case PIX_FMT_PSEUDOCOLOR:
 157                 var->bits_per_pixel = 8;
 158                 var->red.offset = 0;     var->red.length = 8;
 159                 var->green.offset = 0;   var->green.length = 8;
 160                 var->blue.offset = 0;    var->blue.length = 8;
 161                 var->transp.offset = 0;  var->transp.length = 0;
 162                 break;
 163         }
 164 }
 165 
 166 static void set_mode(struct pxa168fb_info *fbi, struct fb_var_screeninfo *var,
 167                      struct fb_videomode *mode, int pix_fmt, int ystretch)
 168 {
 169         struct fb_info *info = fbi->info;
 170 
 171         set_pix_fmt(var, pix_fmt);
 172 
 173         var->xres = mode->xres;
 174         var->yres = mode->yres;
 175         var->xres_virtual = max(var->xres, var->xres_virtual);
 176         if (ystretch)
 177                 var->yres_virtual = info->fix.smem_len /
 178                         (var->xres_virtual * (var->bits_per_pixel >> 3));
 179         else
 180                 var->yres_virtual = max(var->yres, var->yres_virtual);
 181         var->grayscale = 0;
 182         var->accel_flags = FB_ACCEL_NONE;
 183         var->pixclock = mode->pixclock;
 184         var->left_margin = mode->left_margin;
 185         var->right_margin = mode->right_margin;
 186         var->upper_margin = mode->upper_margin;
 187         var->lower_margin = mode->lower_margin;
 188         var->hsync_len = mode->hsync_len;
 189         var->vsync_len = mode->vsync_len;
 190         var->sync = mode->sync;
 191         var->vmode = FB_VMODE_NONINTERLACED;
 192         var->rotate = FB_ROTATE_UR;
 193 }
 194 
 195 static int pxa168fb_check_var(struct fb_var_screeninfo *var,
 196                               struct fb_info *info)
 197 {
 198         struct pxa168fb_info *fbi = info->par;
 199         int pix_fmt;
 200 
 201         /*
 202          * Determine which pixel format we're going to use.
 203          */
 204         pix_fmt = determine_best_pix_fmt(var);
 205         if (pix_fmt < 0)
 206                 return pix_fmt;
 207         set_pix_fmt(var, pix_fmt);
 208         fbi->pix_fmt = pix_fmt;
 209 
 210         /*
 211          * Basic geometry sanity checks.
 212          */
 213         if (var->xoffset + var->xres > var->xres_virtual)
 214                 return -EINVAL;
 215         if (var->yoffset + var->yres > var->yres_virtual)
 216                 return -EINVAL;
 217         if (var->xres + var->right_margin +
 218             var->hsync_len + var->left_margin > 2048)
 219                 return -EINVAL;
 220         if (var->yres + var->lower_margin +
 221             var->vsync_len + var->upper_margin > 2048)
 222                 return -EINVAL;
 223 
 224         /*
 225          * Check size of framebuffer.
 226          */
 227         if (var->xres_virtual * var->yres_virtual *
 228             (var->bits_per_pixel >> 3) > info->fix.smem_len)
 229                 return -EINVAL;
 230 
 231         return 0;
 232 }
 233 
 234 /*
 235  * The hardware clock divider has an integer and a fractional
 236  * stage:
 237  *
 238  *      clk2 = clk_in / integer_divider
 239  *      clk_out = clk2 * (1 - (fractional_divider >> 12))
 240  *
 241  * Calculate integer and fractional divider for given clk_in
 242  * and clk_out.
 243  */
 244 static void set_clock_divider(struct pxa168fb_info *fbi,
 245                               const struct fb_videomode *m)
 246 {
 247         int divider_int;
 248         int needed_pixclk;
 249         u64 div_result;
 250         u32 x = 0;
 251 
 252         /*
 253          * Notice: The field pixclock is used by linux fb
 254          * is in pixel second. E.g. struct fb_videomode &
 255          * struct fb_var_screeninfo
 256          */
 257 
 258         /*
 259          * Check input values.
 260          */
 261         if (!m || !m->pixclock || !m->refresh) {
 262                 dev_err(fbi->dev, "Input refresh or pixclock is wrong.\n");
 263                 return;
 264         }
 265 
 266         /*
 267          * Using PLL/AXI clock.
 268          */
 269         x = 0x80000000;
 270 
 271         /*
 272          * Calc divider according to refresh rate.
 273          */
 274         div_result = 1000000000000ll;
 275         do_div(div_result, m->pixclock);
 276         needed_pixclk = (u32)div_result;
 277 
 278         divider_int = clk_get_rate(fbi->clk) / needed_pixclk;
 279 
 280         /* check whether divisor is too small. */
 281         if (divider_int < 2) {
 282                 dev_warn(fbi->dev, "Warning: clock source is too slow. "
 283                                 "Try smaller resolution\n");
 284                 divider_int = 2;
 285         }
 286 
 287         /*
 288          * Set setting to reg.
 289          */
 290         x |= divider_int;
 291         writel(x, fbi->reg_base + LCD_CFG_SCLK_DIV);
 292 }
 293 
 294 static void set_dma_control0(struct pxa168fb_info *fbi)
 295 {
 296         u32 x;
 297 
 298         /*
 299          * Set bit to enable graphics DMA.
 300          */
 301         x = readl(fbi->reg_base + LCD_SPU_DMA_CTRL0);
 302         x &= ~CFG_GRA_ENA_MASK;
 303         x |= fbi->active ? CFG_GRA_ENA(1) : CFG_GRA_ENA(0);
 304 
 305         /*
 306          * If we are in a pseudo-color mode, we need to enable
 307          * palette lookup.
 308          */
 309         if (fbi->pix_fmt == PIX_FMT_PSEUDOCOLOR)
 310                 x |= 0x10000000;
 311 
 312         /*
 313          * Configure hardware pixel format.
 314          */
 315         x &= ~(0xF << 16);
 316         x |= (fbi->pix_fmt >> 1) << 16;
 317 
 318         /*
 319          * Check red and blue pixel swap.
 320          * 1. source data swap
 321          * 2. panel output data swap
 322          */
 323         x &= ~(1 << 12);
 324         x |= ((fbi->pix_fmt & 1) ^ (fbi->panel_rbswap)) << 12;
 325 
 326         writel(x, fbi->reg_base + LCD_SPU_DMA_CTRL0);
 327 }
 328 
 329 static void set_dma_control1(struct pxa168fb_info *fbi, int sync)
 330 {
 331         u32 x;
 332 
 333         /*
 334          * Configure default bits: vsync triggers DMA, gated clock
 335          * enable, power save enable, configure alpha registers to
 336          * display 100% graphics, and set pixel command.
 337          */
 338         x = readl(fbi->reg_base + LCD_SPU_DMA_CTRL1);
 339         x |= 0x2032ff81;
 340 
 341         /*
 342          * We trigger DMA on the falling edge of vsync if vsync is
 343          * active low, or on the rising edge if vsync is active high.
 344          */
 345         if (!(sync & FB_SYNC_VERT_HIGH_ACT))
 346                 x |= 0x08000000;
 347 
 348         writel(x, fbi->reg_base + LCD_SPU_DMA_CTRL1);
 349 }
 350 
 351 static void set_graphics_start(struct fb_info *info, int xoffset, int yoffset)
 352 {
 353         struct pxa168fb_info *fbi = info->par;
 354         struct fb_var_screeninfo *var = &info->var;
 355         int pixel_offset;
 356         unsigned long addr;
 357 
 358         pixel_offset = (yoffset * var->xres_virtual) + xoffset;
 359 
 360         addr = fbi->fb_start_dma + (pixel_offset * (var->bits_per_pixel >> 3));
 361         writel(addr, fbi->reg_base + LCD_CFG_GRA_START_ADDR0);
 362 }
 363 
 364 static void set_dumb_panel_control(struct fb_info *info)
 365 {
 366         struct pxa168fb_info *fbi = info->par;
 367         struct pxa168fb_mach_info *mi = dev_get_platdata(fbi->dev);
 368         u32 x;
 369 
 370         /*
 371          * Preserve enable flag.
 372          */
 373         x = readl(fbi->reg_base + LCD_SPU_DUMB_CTRL) & 0x00000001;
 374 
 375         x |= (fbi->is_blanked ? 0x7 : mi->dumb_mode) << 28;
 376         x |= mi->gpio_output_data << 20;
 377         x |= mi->gpio_output_mask << 12;
 378         x |= mi->panel_rgb_reverse_lanes ? 0x00000080 : 0;
 379         x |= mi->invert_composite_blank ? 0x00000040 : 0;
 380         x |= (info->var.sync & FB_SYNC_COMP_HIGH_ACT) ? 0x00000020 : 0;
 381         x |= mi->invert_pix_val_ena ? 0x00000010 : 0;
 382         x |= (info->var.sync & FB_SYNC_VERT_HIGH_ACT) ? 0 : 0x00000008;
 383         x |= (info->var.sync & FB_SYNC_HOR_HIGH_ACT) ? 0 : 0x00000004;
 384         x |= mi->invert_pixclock ? 0x00000002 : 0;
 385 
 386         writel(x, fbi->reg_base + LCD_SPU_DUMB_CTRL);
 387 }
 388 
 389 static void set_dumb_screen_dimensions(struct fb_info *info)
 390 {
 391         struct pxa168fb_info *fbi = info->par;
 392         struct fb_var_screeninfo *v = &info->var;
 393         int x;
 394         int y;
 395 
 396         x = v->xres + v->right_margin + v->hsync_len + v->left_margin;
 397         y = v->yres + v->lower_margin + v->vsync_len + v->upper_margin;
 398 
 399         writel((y << 16) | x, fbi->reg_base + LCD_SPUT_V_H_TOTAL);
 400 }
 401 
 402 static int pxa168fb_set_par(struct fb_info *info)
 403 {
 404         struct pxa168fb_info *fbi = info->par;
 405         struct fb_var_screeninfo *var = &info->var;
 406         struct fb_videomode mode;
 407         u32 x;
 408 
 409         /*
 410          * Set additional mode info.
 411          */
 412         if (fbi->pix_fmt == PIX_FMT_PSEUDOCOLOR)
 413                 info->fix.visual = FB_VISUAL_PSEUDOCOLOR;
 414         else
 415                 info->fix.visual = FB_VISUAL_TRUECOLOR;
 416         info->fix.line_length = var->xres_virtual * var->bits_per_pixel / 8;
 417         info->fix.ypanstep = var->yres;
 418 
 419         /*
 420          * Disable panel output while we setup the display.
 421          */
 422         x = readl(fbi->reg_base + LCD_SPU_DUMB_CTRL);
 423         writel(x & ~1, fbi->reg_base + LCD_SPU_DUMB_CTRL);
 424 
 425         /*
 426          * Configure global panel parameters.
 427          */
 428         writel((var->yres << 16) | var->xres,
 429                 fbi->reg_base + LCD_SPU_V_H_ACTIVE);
 430 
 431         /*
 432          * convet var to video mode
 433          */
 434         fb_var_to_videomode(&mode, &info->var);
 435 
 436         /* Calculate clock divisor. */
 437         set_clock_divider(fbi, &mode);
 438 
 439         /* Configure dma ctrl regs. */
 440         set_dma_control0(fbi);
 441         set_dma_control1(fbi, info->var.sync);
 442 
 443         /*
 444          * Configure graphics DMA parameters.
 445          */
 446         x = readl(fbi->reg_base + LCD_CFG_GRA_PITCH);
 447         x = (x & ~0xFFFF) | ((var->xres_virtual * var->bits_per_pixel) >> 3);
 448         writel(x, fbi->reg_base + LCD_CFG_GRA_PITCH);
 449         writel((var->yres << 16) | var->xres,
 450                 fbi->reg_base + LCD_SPU_GRA_HPXL_VLN);
 451         writel((var->yres << 16) | var->xres,
 452                 fbi->reg_base + LCD_SPU_GZM_HPXL_VLN);
 453 
 454         /*
 455          * Configure dumb panel ctrl regs & timings.
 456          */
 457         set_dumb_panel_control(info);
 458         set_dumb_screen_dimensions(info);
 459 
 460         writel((var->left_margin << 16) | var->right_margin,
 461                         fbi->reg_base + LCD_SPU_H_PORCH);
 462         writel((var->upper_margin << 16) | var->lower_margin,
 463                         fbi->reg_base + LCD_SPU_V_PORCH);
 464 
 465         /*
 466          * Re-enable panel output.
 467          */
 468         x = readl(fbi->reg_base + LCD_SPU_DUMB_CTRL);
 469         writel(x | 1, fbi->reg_base + LCD_SPU_DUMB_CTRL);
 470 
 471         return 0;
 472 }
 473 
 474 static unsigned int chan_to_field(unsigned int chan, struct fb_bitfield *bf)
 475 {
 476         return ((chan & 0xffff) >> (16 - bf->length)) << bf->offset;
 477 }
 478 
 479 static u32 to_rgb(u16 red, u16 green, u16 blue)
 480 {
 481         red >>= 8;
 482         green >>= 8;
 483         blue >>= 8;
 484 
 485         return (red << 16) | (green << 8) | blue;
 486 }
 487 
 488 static int
 489 pxa168fb_setcolreg(unsigned int regno, unsigned int red, unsigned int green,
 490                  unsigned int blue, unsigned int trans, struct fb_info *info)
 491 {
 492         struct pxa168fb_info *fbi = info->par;
 493         u32 val;
 494 
 495         if (info->var.grayscale)
 496                 red = green = blue = (19595 * red + 38470 * green +
 497                                         7471 * blue) >> 16;
 498 
 499         if (info->fix.visual == FB_VISUAL_TRUECOLOR && regno < 16) {
 500                 val =  chan_to_field(red,   &info->var.red);
 501                 val |= chan_to_field(green, &info->var.green);
 502                 val |= chan_to_field(blue , &info->var.blue);
 503                 fbi->pseudo_palette[regno] = val;
 504         }
 505 
 506         if (info->fix.visual == FB_VISUAL_PSEUDOCOLOR && regno < 256) {
 507                 val = to_rgb(red, green, blue);
 508                 writel(val, fbi->reg_base + LCD_SPU_SRAM_WRDAT);
 509                 writel(0x8300 | regno, fbi->reg_base + LCD_SPU_SRAM_CTRL);
 510         }
 511 
 512         return 0;
 513 }
 514 
 515 static int pxa168fb_blank(int blank, struct fb_info *info)
 516 {
 517         struct pxa168fb_info *fbi = info->par;
 518 
 519         fbi->is_blanked = (blank == FB_BLANK_UNBLANK) ? 0 : 1;
 520         set_dumb_panel_control(info);
 521 
 522         return 0;
 523 }
 524 
 525 static int pxa168fb_pan_display(struct fb_var_screeninfo *var,
 526                                 struct fb_info *info)
 527 {
 528         set_graphics_start(info, var->xoffset, var->yoffset);
 529 
 530         return 0;
 531 }
 532 
 533 static irqreturn_t pxa168fb_handle_irq(int irq, void *dev_id)
 534 {
 535         struct pxa168fb_info *fbi = dev_id;
 536         u32 isr = readl(fbi->reg_base + SPU_IRQ_ISR);
 537 
 538         if ((isr & GRA_FRAME_IRQ0_ENA_MASK)) {
 539 
 540                 writel(isr & (~GRA_FRAME_IRQ0_ENA_MASK),
 541                         fbi->reg_base + SPU_IRQ_ISR);
 542 
 543                 return IRQ_HANDLED;
 544         }
 545         return IRQ_NONE;
 546 }
 547 
 548 static struct fb_ops pxa168fb_ops = {
 549         .owner          = THIS_MODULE,
 550         .fb_check_var   = pxa168fb_check_var,
 551         .fb_set_par     = pxa168fb_set_par,
 552         .fb_setcolreg   = pxa168fb_setcolreg,
 553         .fb_blank       = pxa168fb_blank,
 554         .fb_pan_display = pxa168fb_pan_display,
 555         .fb_fillrect    = cfb_fillrect,
 556         .fb_copyarea    = cfb_copyarea,
 557         .fb_imageblit   = cfb_imageblit,
 558 };
 559 
 560 static int pxa168fb_init_mode(struct fb_info *info,
 561                               struct pxa168fb_mach_info *mi)
 562 {
 563         struct pxa168fb_info *fbi = info->par;
 564         struct fb_var_screeninfo *var = &info->var;
 565         int ret = 0;
 566         u32 total_w, total_h, refresh;
 567         u64 div_result;
 568         const struct fb_videomode *m;
 569 
 570         /*
 571          * Set default value
 572          */
 573         refresh = DEFAULT_REFRESH;
 574 
 575         /* try to find best video mode. */
 576         m = fb_find_best_mode(&info->var, &info->modelist);
 577         if (m)
 578                 fb_videomode_to_var(&info->var, m);
 579 
 580         /* Init settings. */
 581         var->xres_virtual = var->xres;
 582         var->yres_virtual = info->fix.smem_len /
 583                 (var->xres_virtual * (var->bits_per_pixel >> 3));
 584         dev_dbg(fbi->dev, "pxa168fb: find best mode: res = %dx%d\n",
 585                                 var->xres, var->yres);
 586 
 587         /* correct pixclock. */
 588         total_w = var->xres + var->left_margin + var->right_margin +
 589                   var->hsync_len;
 590         total_h = var->yres + var->upper_margin + var->lower_margin +
 591                   var->vsync_len;
 592 
 593         div_result = 1000000000000ll;
 594         do_div(div_result, total_w * total_h * refresh);
 595         var->pixclock = (u32)div_result;
 596 
 597         return ret;
 598 }
 599 
 600 static int pxa168fb_probe(struct platform_device *pdev)
 601 {
 602         struct pxa168fb_mach_info *mi;
 603         struct fb_info *info = 0;
 604         struct pxa168fb_info *fbi = 0;
 605         struct resource *res;
 606         struct clk *clk;
 607         int irq, ret;
 608 
 609         mi = dev_get_platdata(&pdev->dev);
 610         if (mi == NULL) {
 611                 dev_err(&pdev->dev, "no platform data defined\n");
 612                 return -EINVAL;
 613         }
 614 
 615         clk = devm_clk_get(&pdev->dev, "LCDCLK");
 616         if (IS_ERR(clk)) {
 617                 dev_err(&pdev->dev, "unable to get LCDCLK");
 618                 return PTR_ERR(clk);
 619         }
 620 
 621         res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
 622         if (res == NULL) {
 623                 dev_err(&pdev->dev, "no IO memory defined\n");
 624                 return -ENOENT;
 625         }
 626 
 627         irq = platform_get_irq(pdev, 0);
 628         if (irq < 0) {
 629                 dev_err(&pdev->dev, "no IRQ defined\n");
 630                 return -ENOENT;
 631         }
 632 
 633         info = framebuffer_alloc(sizeof(struct pxa168fb_info), &pdev->dev);
 634         if (info == NULL) {
 635                 return -ENOMEM;
 636         }
 637 
 638         /* Initialize private data */
 639         fbi = info->par;
 640         fbi->info = info;
 641         fbi->clk = clk;
 642         fbi->dev = info->dev = &pdev->dev;
 643         fbi->panel_rbswap = mi->panel_rbswap;
 644         fbi->is_blanked = 0;
 645         fbi->active = mi->active;
 646 
 647         /*
 648          * Initialise static fb parameters.
 649          */
 650         info->flags = FBINFO_DEFAULT | FBINFO_PARTIAL_PAN_OK |
 651                       FBINFO_HWACCEL_XPAN | FBINFO_HWACCEL_YPAN;
 652         info->node = -1;
 653         strlcpy(info->fix.id, mi->id, 16);
 654         info->fix.type = FB_TYPE_PACKED_PIXELS;
 655         info->fix.type_aux = 0;
 656         info->fix.xpanstep = 0;
 657         info->fix.ypanstep = 0;
 658         info->fix.ywrapstep = 0;
 659         info->fix.mmio_start = res->start;
 660         info->fix.mmio_len = resource_size(res);
 661         info->fix.accel = FB_ACCEL_NONE;
 662         info->fbops = &pxa168fb_ops;
 663         info->pseudo_palette = fbi->pseudo_palette;
 664 
 665         /*
 666          * Map LCD controller registers.
 667          */
 668         fbi->reg_base = devm_ioremap_nocache(&pdev->dev, res->start,
 669                                              resource_size(res));
 670         if (fbi->reg_base == NULL) {
 671                 ret = -ENOMEM;
 672                 goto failed_free_info;
 673         }
 674 
 675         /*
 676          * Allocate framebuffer memory.
 677          */
 678         info->fix.smem_len = PAGE_ALIGN(DEFAULT_FB_SIZE);
 679 
 680         info->screen_base = dma_alloc_wc(fbi->dev, info->fix.smem_len,
 681                                          &fbi->fb_start_dma, GFP_KERNEL);
 682         if (info->screen_base == NULL) {
 683                 ret = -ENOMEM;
 684                 goto failed_free_info;
 685         }
 686 
 687         info->fix.smem_start = (unsigned long)fbi->fb_start_dma;
 688         set_graphics_start(info, 0, 0);
 689 
 690         /*
 691          * Set video mode according to platform data.
 692          */
 693         set_mode(fbi, &info->var, mi->modes, mi->pix_fmt, 1);
 694 
 695         fb_videomode_to_modelist(mi->modes, mi->num_modes, &info->modelist);
 696 
 697         /*
 698          * init video mode data.
 699          */
 700         pxa168fb_init_mode(info, mi);
 701 
 702         /*
 703          * Fill in sane defaults.
 704          */
 705         ret = pxa168fb_check_var(&info->var, info);
 706         if (ret)
 707                 goto failed_free_fbmem;
 708 
 709         /*
 710          * enable controller clock
 711          */
 712         clk_prepare_enable(fbi->clk);
 713 
 714         pxa168fb_set_par(info);
 715 
 716         /*
 717          * Configure default register values.
 718          */
 719         writel(0, fbi->reg_base + LCD_SPU_BLANKCOLOR);
 720         writel(mi->io_pin_allocation_mode, fbi->reg_base + SPU_IOPAD_CONTROL);
 721         writel(0, fbi->reg_base + LCD_CFG_GRA_START_ADDR1);
 722         writel(0, fbi->reg_base + LCD_SPU_GRA_OVSA_HPXL_VLN);
 723         writel(0, fbi->reg_base + LCD_SPU_SRAM_PARA0);
 724         writel(CFG_CSB_256x32(0x1)|CFG_CSB_256x24(0x1)|CFG_CSB_256x8(0x1),
 725                 fbi->reg_base + LCD_SPU_SRAM_PARA1);
 726 
 727         /*
 728          * Allocate color map.
 729          */
 730         if (fb_alloc_cmap(&info->cmap, 256, 0) < 0) {
 731                 ret = -ENOMEM;
 732                 goto failed_free_clk;
 733         }
 734 
 735         /*
 736          * Register irq handler.
 737          */
 738         ret = devm_request_irq(&pdev->dev, irq, pxa168fb_handle_irq,
 739                                IRQF_SHARED, info->fix.id, fbi);
 740         if (ret < 0) {
 741                 dev_err(&pdev->dev, "unable to request IRQ\n");
 742                 ret = -ENXIO;
 743                 goto failed_free_cmap;
 744         }
 745 
 746         /*
 747          * Enable GFX interrupt
 748          */
 749         writel(GRA_FRAME_IRQ0_ENA(0x1), fbi->reg_base + SPU_IRQ_ENA);
 750 
 751         /*
 752          * Register framebuffer.
 753          */
 754         ret = register_framebuffer(info);
 755         if (ret < 0) {
 756                 dev_err(&pdev->dev, "Failed to register pxa168-fb: %d\n", ret);
 757                 ret = -ENXIO;
 758                 goto failed_free_cmap;
 759         }
 760 
 761         platform_set_drvdata(pdev, fbi);
 762         return 0;
 763 
 764 failed_free_cmap:
 765         fb_dealloc_cmap(&info->cmap);
 766 failed_free_clk:
 767         clk_disable_unprepare(fbi->clk);
 768 failed_free_fbmem:
 769         dma_free_wc(fbi->dev, info->fix.smem_len,
 770                     info->screen_base, fbi->fb_start_dma);
 771 failed_free_info:
 772         kfree(info);
 773 
 774         dev_err(&pdev->dev, "frame buffer device init failed with %d\n", ret);
 775         return ret;
 776 }
 777 
 778 static int pxa168fb_remove(struct platform_device *pdev)
 779 {
 780         struct pxa168fb_info *fbi = platform_get_drvdata(pdev);
 781         struct fb_info *info;
 782         int irq;
 783         unsigned int data;
 784 
 785         if (!fbi)
 786                 return 0;
 787 
 788         /* disable DMA transfer */
 789         data = readl(fbi->reg_base + LCD_SPU_DMA_CTRL0);
 790         data &= ~CFG_GRA_ENA_MASK;
 791         writel(data, fbi->reg_base + LCD_SPU_DMA_CTRL0);
 792 
 793         info = fbi->info;
 794 
 795         unregister_framebuffer(info);
 796 
 797         writel(GRA_FRAME_IRQ0_ENA(0x0), fbi->reg_base + SPU_IRQ_ENA);
 798 
 799         if (info->cmap.len)
 800                 fb_dealloc_cmap(&info->cmap);
 801 
 802         irq = platform_get_irq(pdev, 0);
 803 
 804         dma_free_wc(fbi->dev, info->fix.smem_len,
 805                     info->screen_base, info->fix.smem_start);
 806 
 807         clk_disable_unprepare(fbi->clk);
 808 
 809         framebuffer_release(info);
 810 
 811         return 0;
 812 }
 813 
 814 static struct platform_driver pxa168fb_driver = {
 815         .driver         = {
 816                 .name   = "pxa168-fb",
 817         },
 818         .probe          = pxa168fb_probe,
 819         .remove         = pxa168fb_remove,
 820 };
 821 
 822 module_platform_driver(pxa168fb_driver);
 823 
 824 MODULE_AUTHOR("Lennert Buytenhek <buytenh@marvell.com> "
 825               "Green Wan <gwan@marvell.com>");
 826 MODULE_DESCRIPTION("Framebuffer driver for PXA168/910");
 827 MODULE_LICENSE("GPL");

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