root/drivers/video/fbdev/ep93xx-fb.c

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

DEFINITIONS

This source file includes following definitions.
  1. ep93xxfb_readl
  2. ep93xxfb_writel
  3. ep93xxfb_out_locked
  4. ep93xxfb_set_video_attribs
  5. ep93xxfb_set_pixelmode
  6. ep93xxfb_set_timing
  7. ep93xxfb_set_par
  8. ep93xxfb_check_var
  9. ep93xxfb_mmap
  10. ep93xxfb_blank
  11. ep93xxfb_convert_color
  12. ep93xxfb_setcolreg
  13. ep93xxfb_alloc_videomem
  14. ep93xxfb_dealloc_videomem
  15. ep93xxfb_probe
  16. ep93xxfb_remove

   1 // SPDX-License-Identifier: GPL-2.0-only
   2 /*
   3  * linux/drivers/video/ep93xx-fb.c
   4  *
   5  * Framebuffer support for the EP93xx series.
   6  *
   7  * Copyright (C) 2007 Bluewater Systems Ltd
   8  * Author: Ryan Mallon
   9  *
  10  * Copyright (c) 2009 H Hartley Sweeten <hsweeten@visionengravers.com>
  11  *
  12  * Based on the Cirrus Logic ep93xxfb driver, and various other ep93xxfb
  13  * drivers.
  14  */
  15 
  16 #include <linux/platform_device.h>
  17 #include <linux/module.h>
  18 #include <linux/dma-mapping.h>
  19 #include <linux/slab.h>
  20 #include <linux/clk.h>
  21 #include <linux/fb.h>
  22 #include <linux/io.h>
  23 
  24 #include <linux/platform_data/video-ep93xx.h>
  25 
  26 /* Vertical Frame Timing Registers */
  27 #define EP93XXFB_VLINES_TOTAL                   0x0000  /* SW locked */
  28 #define EP93XXFB_VSYNC                          0x0004  /* SW locked */
  29 #define EP93XXFB_VACTIVE                        0x0008  /* SW locked */
  30 #define EP93XXFB_VBLANK                         0x0228  /* SW locked */
  31 #define EP93XXFB_VCLK                           0x000c  /* SW locked */
  32 
  33 /* Horizontal Frame Timing Registers */
  34 #define EP93XXFB_HCLKS_TOTAL                    0x0010  /* SW locked */
  35 #define EP93XXFB_HSYNC                          0x0014  /* SW locked */
  36 #define EP93XXFB_HACTIVE                        0x0018  /* SW locked */
  37 #define EP93XXFB_HBLANK                         0x022c  /* SW locked */
  38 #define EP93XXFB_HCLK                           0x001c  /* SW locked */
  39 
  40 /* Frame Buffer Memory Configuration Registers */
  41 #define EP93XXFB_SCREEN_PAGE                    0x0028
  42 #define EP93XXFB_SCREEN_HPAGE                   0x002c
  43 #define EP93XXFB_SCREEN_LINES                   0x0030
  44 #define EP93XXFB_LINE_LENGTH                    0x0034
  45 #define EP93XXFB_VLINE_STEP                     0x0038
  46 #define EP93XXFB_LINE_CARRY                     0x003c  /* SW locked */
  47 #define EP93XXFB_EOL_OFFSET                     0x0230
  48 
  49 /* Other Video Registers */
  50 #define EP93XXFB_BRIGHTNESS                     0x0020
  51 #define EP93XXFB_ATTRIBS                        0x0024  /* SW locked */
  52 #define EP93XXFB_SWLOCK                         0x007c  /* SW locked */
  53 #define EP93XXFB_AC_RATE                        0x0214
  54 #define EP93XXFB_FIFO_LEVEL                     0x0234
  55 #define EP93XXFB_PIXELMODE                      0x0054
  56 #define EP93XXFB_PIXELMODE_32BPP                (0x7 << 0)
  57 #define EP93XXFB_PIXELMODE_24BPP                (0x6 << 0)
  58 #define EP93XXFB_PIXELMODE_16BPP                (0x4 << 0)
  59 #define EP93XXFB_PIXELMODE_8BPP                 (0x2 << 0)
  60 #define EP93XXFB_PIXELMODE_SHIFT_1P_24B         (0x0 << 3)
  61 #define EP93XXFB_PIXELMODE_SHIFT_1P_18B         (0x1 << 3)
  62 #define EP93XXFB_PIXELMODE_COLOR_LUT            (0x0 << 10)
  63 #define EP93XXFB_PIXELMODE_COLOR_888            (0x4 << 10)
  64 #define EP93XXFB_PIXELMODE_COLOR_555            (0x5 << 10)
  65 #define EP93XXFB_PARL_IF_OUT                    0x0058
  66 #define EP93XXFB_PARL_IF_IN                     0x005c
  67 
  68 /* Blink Control Registers */
  69 #define EP93XXFB_BLINK_RATE                     0x0040
  70 #define EP93XXFB_BLINK_MASK                     0x0044
  71 #define EP93XXFB_BLINK_PATTRN                   0x0048
  72 #define EP93XXFB_PATTRN_MASK                    0x004c
  73 #define EP93XXFB_BKGRND_OFFSET                  0x0050
  74 
  75 /* Hardware Cursor Registers */
  76 #define EP93XXFB_CURSOR_ADR_START               0x0060
  77 #define EP93XXFB_CURSOR_ADR_RESET               0x0064
  78 #define EP93XXFB_CURSOR_SIZE                    0x0068
  79 #define EP93XXFB_CURSOR_COLOR1                  0x006c
  80 #define EP93XXFB_CURSOR_COLOR2                  0x0070
  81 #define EP93XXFB_CURSOR_BLINK_COLOR1            0x021c
  82 #define EP93XXFB_CURSOR_BLINK_COLOR2            0x0220
  83 #define EP93XXFB_CURSOR_XY_LOC                  0x0074
  84 #define EP93XXFB_CURSOR_DSCAN_HY_LOC            0x0078
  85 #define EP93XXFB_CURSOR_BLINK_RATE_CTRL         0x0224
  86 
  87 /* LUT Registers */
  88 #define EP93XXFB_GRY_SCL_LUTR                   0x0080
  89 #define EP93XXFB_GRY_SCL_LUTG                   0x0280
  90 #define EP93XXFB_GRY_SCL_LUTB                   0x0300
  91 #define EP93XXFB_LUT_SW_CONTROL                 0x0218
  92 #define EP93XXFB_LUT_SW_CONTROL_SWTCH           (1 << 0)
  93 #define EP93XXFB_LUT_SW_CONTROL_SSTAT           (1 << 1)
  94 #define EP93XXFB_COLOR_LUT                      0x0400
  95 
  96 /* Video Signature Registers */
  97 #define EP93XXFB_VID_SIG_RSLT_VAL               0x0200
  98 #define EP93XXFB_VID_SIG_CTRL                   0x0204
  99 #define EP93XXFB_VSIG                           0x0208
 100 #define EP93XXFB_HSIG                           0x020c
 101 #define EP93XXFB_SIG_CLR_STR                    0x0210
 102 
 103 /* Minimum / Maximum resolutions supported */
 104 #define EP93XXFB_MIN_XRES                       64
 105 #define EP93XXFB_MIN_YRES                       64
 106 #define EP93XXFB_MAX_XRES                       1024
 107 #define EP93XXFB_MAX_YRES                       768
 108 
 109 struct ep93xx_fbi {
 110         struct ep93xxfb_mach_info       *mach_info;
 111         struct clk                      *clk;
 112         struct resource                 *res;
 113         void __iomem                    *mmio_base;
 114         unsigned int                    pseudo_palette[256];
 115 };
 116 
 117 static int check_screenpage_bug = 1;
 118 module_param(check_screenpage_bug, int, 0644);
 119 MODULE_PARM_DESC(check_screenpage_bug,
 120                  "Check for bit 27 screen page bug. Default = 1");
 121 
 122 static inline unsigned int ep93xxfb_readl(struct ep93xx_fbi *fbi,
 123                                           unsigned int off)
 124 {
 125         return __raw_readl(fbi->mmio_base + off);
 126 }
 127 
 128 static inline void ep93xxfb_writel(struct ep93xx_fbi *fbi,
 129                                    unsigned int val, unsigned int off)
 130 {
 131         __raw_writel(val, fbi->mmio_base + off);
 132 }
 133 
 134 /*
 135  * Write to one of the locked raster registers.
 136  */
 137 static inline void ep93xxfb_out_locked(struct ep93xx_fbi *fbi,
 138                                        unsigned int val, unsigned int reg)
 139 {
 140         /*
 141          * We don't need a lock or delay here since the raster register
 142          * block will remain unlocked until the next access.
 143          */
 144         ep93xxfb_writel(fbi, 0xaa, EP93XXFB_SWLOCK);
 145         ep93xxfb_writel(fbi, val, reg);
 146 }
 147 
 148 static void ep93xxfb_set_video_attribs(struct fb_info *info)
 149 {
 150         struct ep93xx_fbi *fbi = info->par;
 151         unsigned int attribs;
 152 
 153         attribs = EP93XXFB_ENABLE;
 154         attribs |= fbi->mach_info->flags;
 155         ep93xxfb_out_locked(fbi, attribs, EP93XXFB_ATTRIBS);
 156 }
 157 
 158 static int ep93xxfb_set_pixelmode(struct fb_info *info)
 159 {
 160         struct ep93xx_fbi *fbi = info->par;
 161         unsigned int val;
 162 
 163         info->var.transp.offset = 0;
 164         info->var.transp.length = 0;
 165 
 166         switch (info->var.bits_per_pixel) {
 167         case 8:
 168                 val = EP93XXFB_PIXELMODE_8BPP | EP93XXFB_PIXELMODE_COLOR_LUT |
 169                         EP93XXFB_PIXELMODE_SHIFT_1P_18B;
 170 
 171                 info->var.red.offset    = 0;
 172                 info->var.red.length    = 8;
 173                 info->var.green.offset  = 0;
 174                 info->var.green.length  = 8;
 175                 info->var.blue.offset   = 0;
 176                 info->var.blue.length   = 8;
 177                 info->fix.visual        = FB_VISUAL_PSEUDOCOLOR;
 178                 break;
 179 
 180         case 16:
 181                 val = EP93XXFB_PIXELMODE_16BPP | EP93XXFB_PIXELMODE_COLOR_555 |
 182                         EP93XXFB_PIXELMODE_SHIFT_1P_18B;
 183 
 184                 info->var.red.offset    = 11;
 185                 info->var.red.length    = 5;
 186                 info->var.green.offset  = 5;
 187                 info->var.green.length  = 6;
 188                 info->var.blue.offset   = 0;
 189                 info->var.blue.length   = 5;
 190                 info->fix.visual        = FB_VISUAL_TRUECOLOR;
 191                 break;
 192 
 193         case 24:
 194                 val = EP93XXFB_PIXELMODE_24BPP | EP93XXFB_PIXELMODE_COLOR_888 |
 195                         EP93XXFB_PIXELMODE_SHIFT_1P_24B;
 196 
 197                 info->var.red.offset    = 16;
 198                 info->var.red.length    = 8;
 199                 info->var.green.offset  = 8;
 200                 info->var.green.length  = 8;
 201                 info->var.blue.offset   = 0;
 202                 info->var.blue.length   = 8;
 203                 info->fix.visual        = FB_VISUAL_TRUECOLOR;
 204                 break;
 205 
 206         case 32:
 207                 val = EP93XXFB_PIXELMODE_32BPP | EP93XXFB_PIXELMODE_COLOR_888 |
 208                         EP93XXFB_PIXELMODE_SHIFT_1P_24B;
 209 
 210                 info->var.red.offset    = 16;
 211                 info->var.red.length    = 8;
 212                 info->var.green.offset  = 8;
 213                 info->var.green.length  = 8;
 214                 info->var.blue.offset   = 0;
 215                 info->var.blue.length   = 8;
 216                 info->fix.visual        = FB_VISUAL_TRUECOLOR;
 217                 break;
 218 
 219         default:
 220                 return -EINVAL;
 221         }
 222 
 223         ep93xxfb_writel(fbi, val, EP93XXFB_PIXELMODE);
 224         return 0;
 225 }
 226 
 227 static void ep93xxfb_set_timing(struct fb_info *info)
 228 {
 229         struct ep93xx_fbi *fbi = info->par;
 230         unsigned int vlines_total, hclks_total, start, stop;
 231 
 232         vlines_total = info->var.yres + info->var.upper_margin +
 233                 info->var.lower_margin + info->var.vsync_len - 1;
 234 
 235         hclks_total = info->var.xres + info->var.left_margin +
 236                 info->var.right_margin + info->var.hsync_len - 1;
 237 
 238         ep93xxfb_out_locked(fbi, vlines_total, EP93XXFB_VLINES_TOTAL);
 239         ep93xxfb_out_locked(fbi, hclks_total, EP93XXFB_HCLKS_TOTAL);
 240 
 241         start = vlines_total;
 242         stop = vlines_total - info->var.vsync_len;
 243         ep93xxfb_out_locked(fbi, start | (stop << 16), EP93XXFB_VSYNC);
 244 
 245         start = vlines_total - info->var.vsync_len - info->var.upper_margin;
 246         stop = info->var.lower_margin - 1;
 247         ep93xxfb_out_locked(fbi, start | (stop << 16), EP93XXFB_VBLANK);
 248         ep93xxfb_out_locked(fbi, start | (stop << 16), EP93XXFB_VACTIVE);
 249 
 250         start = vlines_total;
 251         stop = vlines_total + 1;
 252         ep93xxfb_out_locked(fbi, start | (stop << 16), EP93XXFB_VCLK);
 253 
 254         start = hclks_total;
 255         stop = hclks_total - info->var.hsync_len;
 256         ep93xxfb_out_locked(fbi, start | (stop << 16), EP93XXFB_HSYNC);
 257 
 258         start = hclks_total - info->var.hsync_len - info->var.left_margin;
 259         stop = info->var.right_margin - 1;
 260         ep93xxfb_out_locked(fbi, start | (stop << 16), EP93XXFB_HBLANK);
 261         ep93xxfb_out_locked(fbi, start | (stop << 16), EP93XXFB_HACTIVE);
 262 
 263         start = hclks_total;
 264         stop = hclks_total;
 265         ep93xxfb_out_locked(fbi, start | (stop << 16), EP93XXFB_HCLK);
 266 
 267         ep93xxfb_out_locked(fbi, 0x0, EP93XXFB_LINE_CARRY);
 268 }
 269 
 270 static int ep93xxfb_set_par(struct fb_info *info)
 271 {
 272         struct ep93xx_fbi *fbi = info->par;
 273 
 274         clk_set_rate(fbi->clk, 1000 * PICOS2KHZ(info->var.pixclock));
 275 
 276         ep93xxfb_set_timing(info);
 277 
 278         info->fix.line_length = info->var.xres_virtual *
 279                 info->var.bits_per_pixel / 8;
 280 
 281         ep93xxfb_writel(fbi, info->fix.smem_start, EP93XXFB_SCREEN_PAGE);
 282         ep93xxfb_writel(fbi, info->var.yres - 1, EP93XXFB_SCREEN_LINES);
 283         ep93xxfb_writel(fbi, ((info->var.xres * info->var.bits_per_pixel)
 284                               / 32) - 1, EP93XXFB_LINE_LENGTH);
 285         ep93xxfb_writel(fbi, info->fix.line_length / 4, EP93XXFB_VLINE_STEP);
 286         ep93xxfb_set_video_attribs(info);
 287         return 0;
 288 }
 289 
 290 static int ep93xxfb_check_var(struct fb_var_screeninfo *var,
 291                               struct fb_info *info)
 292 {
 293         int err;
 294 
 295         err = ep93xxfb_set_pixelmode(info);
 296         if (err)
 297                 return err;
 298 
 299         var->xres = max_t(unsigned int, var->xres, EP93XXFB_MIN_XRES);
 300         var->xres = min_t(unsigned int, var->xres, EP93XXFB_MAX_XRES);
 301         var->xres_virtual = max(var->xres_virtual, var->xres);
 302 
 303         var->yres = max_t(unsigned int, var->yres, EP93XXFB_MIN_YRES);
 304         var->yres = min_t(unsigned int, var->yres, EP93XXFB_MAX_YRES);
 305         var->yres_virtual = max(var->yres_virtual, var->yres);
 306 
 307         return 0;
 308 }
 309 
 310 static int ep93xxfb_mmap(struct fb_info *info, struct vm_area_struct *vma)
 311 {
 312         unsigned int offset = vma->vm_pgoff << PAGE_SHIFT;
 313 
 314         if (offset < info->fix.smem_len) {
 315                 return dma_mmap_wc(info->dev, vma, info->screen_base,
 316                                    info->fix.smem_start, info->fix.smem_len);
 317         }
 318 
 319         return -EINVAL;
 320 }
 321 
 322 static int ep93xxfb_blank(int blank_mode, struct fb_info *info)
 323 {
 324         struct ep93xx_fbi *fbi = info->par;
 325         unsigned int attribs = ep93xxfb_readl(fbi, EP93XXFB_ATTRIBS);
 326 
 327         if (blank_mode) {
 328                 if (fbi->mach_info->blank)
 329                         fbi->mach_info->blank(blank_mode, info);
 330                 ep93xxfb_out_locked(fbi, attribs & ~EP93XXFB_ENABLE,
 331                                     EP93XXFB_ATTRIBS);
 332                 clk_disable(fbi->clk);
 333         } else {
 334                 clk_enable(fbi->clk);
 335                 ep93xxfb_out_locked(fbi, attribs | EP93XXFB_ENABLE,
 336                                     EP93XXFB_ATTRIBS);
 337                 if (fbi->mach_info->blank)
 338                         fbi->mach_info->blank(blank_mode, info);
 339         }
 340 
 341         return 0;
 342 }
 343 
 344 static inline int ep93xxfb_convert_color(int val, int width)
 345 {
 346         return ((val << width) + 0x7fff - val) >> 16;
 347 }
 348 
 349 static int ep93xxfb_setcolreg(unsigned int regno, unsigned int red,
 350                               unsigned int green, unsigned int blue,
 351                               unsigned int transp, struct fb_info *info)
 352 {
 353         struct ep93xx_fbi *fbi = info->par;
 354         unsigned int *pal = info->pseudo_palette;
 355         unsigned int ctrl, i, rgb, lut_current, lut_stat;
 356 
 357         switch (info->fix.visual) {
 358         case FB_VISUAL_PSEUDOCOLOR:
 359                 if (regno > 255)
 360                         return 1;
 361                 rgb = ((red & 0xff00) << 8) | (green & 0xff00) |
 362                         ((blue & 0xff00) >> 8);
 363 
 364                 pal[regno] = rgb;
 365                 ep93xxfb_writel(fbi, rgb, (EP93XXFB_COLOR_LUT + (regno << 2)));
 366                 ctrl = ep93xxfb_readl(fbi, EP93XXFB_LUT_SW_CONTROL);
 367                 lut_stat = !!(ctrl & EP93XXFB_LUT_SW_CONTROL_SSTAT);
 368                 lut_current = !!(ctrl & EP93XXFB_LUT_SW_CONTROL_SWTCH);
 369 
 370                 if (lut_stat == lut_current) {
 371                         for (i = 0; i < 256; i++) {
 372                                 ep93xxfb_writel(fbi, pal[i],
 373                                         EP93XXFB_COLOR_LUT + (i << 2));
 374                         }
 375 
 376                         ep93xxfb_writel(fbi,
 377                                         ctrl ^ EP93XXFB_LUT_SW_CONTROL_SWTCH,
 378                                         EP93XXFB_LUT_SW_CONTROL);
 379                 }
 380                 break;
 381 
 382         case FB_VISUAL_TRUECOLOR:
 383                 if (regno > 16)
 384                         return 1;
 385 
 386                 red = ep93xxfb_convert_color(red, info->var.red.length);
 387                 green = ep93xxfb_convert_color(green, info->var.green.length);
 388                 blue = ep93xxfb_convert_color(blue, info->var.blue.length);
 389                 transp = ep93xxfb_convert_color(transp,
 390                                                 info->var.transp.length);
 391 
 392                 pal[regno] = (red << info->var.red.offset) |
 393                         (green << info->var.green.offset) |
 394                         (blue << info->var.blue.offset) |
 395                         (transp << info->var.transp.offset);
 396                 break;
 397 
 398         default:
 399                 return 1;
 400         }
 401 
 402         return 0;
 403 }
 404 
 405 static struct fb_ops ep93xxfb_ops = {
 406         .owner          = THIS_MODULE,
 407         .fb_check_var   = ep93xxfb_check_var,
 408         .fb_set_par     = ep93xxfb_set_par,
 409         .fb_blank       = ep93xxfb_blank,
 410         .fb_fillrect    = cfb_fillrect,
 411         .fb_copyarea    = cfb_copyarea,
 412         .fb_imageblit   = cfb_imageblit,
 413         .fb_setcolreg   = ep93xxfb_setcolreg,
 414         .fb_mmap        = ep93xxfb_mmap,
 415 };
 416 
 417 static int ep93xxfb_alloc_videomem(struct fb_info *info)
 418 {
 419         char __iomem *virt_addr;
 420         dma_addr_t phys_addr;
 421         unsigned int fb_size;
 422 
 423         /* Maximum 16bpp -> used memory is maximum x*y*2 bytes */
 424         fb_size = EP93XXFB_MAX_XRES * EP93XXFB_MAX_YRES * 2;
 425 
 426         virt_addr = dma_alloc_wc(info->dev, fb_size, &phys_addr, GFP_KERNEL);
 427         if (!virt_addr)
 428                 return -ENOMEM;
 429 
 430         /*
 431          * There is a bug in the ep93xx framebuffer which causes problems
 432          * if bit 27 of the physical address is set.
 433          * See: http://marc.info/?l=linux-arm-kernel&m=110061245502000&w=2
 434          * There does not seem to be any official errata for this, but I
 435          * have confirmed the problem exists on my hardware (ep9315) at
 436          * least.
 437          */
 438         if (check_screenpage_bug && phys_addr & (1 << 27)) {
 439                 dev_err(info->dev, "ep93xx framebuffer bug. phys addr (0x%x) "
 440                         "has bit 27 set: cannot init framebuffer\n",
 441                         phys_addr);
 442 
 443                 dma_free_coherent(info->dev, fb_size, virt_addr, phys_addr);
 444                 return -ENOMEM;
 445         }
 446 
 447         info->fix.smem_start = phys_addr;
 448         info->fix.smem_len = fb_size;
 449         info->screen_base = virt_addr;
 450 
 451         return 0;
 452 }
 453 
 454 static void ep93xxfb_dealloc_videomem(struct fb_info *info)
 455 {
 456         if (info->screen_base)
 457                 dma_free_coherent(info->dev, info->fix.smem_len,
 458                                   info->screen_base, info->fix.smem_start);
 459 }
 460 
 461 static int ep93xxfb_probe(struct platform_device *pdev)
 462 {
 463         struct ep93xxfb_mach_info *mach_info = dev_get_platdata(&pdev->dev);
 464         struct fb_info *info;
 465         struct ep93xx_fbi *fbi;
 466         struct resource *res;
 467         char *video_mode;
 468         int err;
 469 
 470         if (!mach_info)
 471                 return -EINVAL;
 472 
 473         info = framebuffer_alloc(sizeof(struct ep93xx_fbi), &pdev->dev);
 474         if (!info)
 475                 return -ENOMEM;
 476 
 477         info->dev = &pdev->dev;
 478         platform_set_drvdata(pdev, info);
 479         fbi = info->par;
 480         fbi->mach_info = mach_info;
 481 
 482         err = fb_alloc_cmap(&info->cmap, 256, 0);
 483         if (err)
 484                 goto failed_cmap;
 485 
 486         err = ep93xxfb_alloc_videomem(info);
 487         if (err)
 488                 goto failed_videomem;
 489 
 490         res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
 491         if (!res) {
 492                 err = -ENXIO;
 493                 goto failed_resource;
 494         }
 495 
 496         /*
 497          * FIXME - We don't do a request_mem_region here because we are
 498          * sharing the register space with the backlight driver (see
 499          * drivers/video/backlight/ep93xx_bl.c) and doing so will cause
 500          * the second loaded driver to return -EBUSY.
 501          *
 502          * NOTE: No locking is required; the backlight does not touch
 503          * any of the framebuffer registers.
 504          */
 505         fbi->res = res;
 506         fbi->mmio_base = devm_ioremap(&pdev->dev, res->start,
 507                                       resource_size(res));
 508         if (!fbi->mmio_base) {
 509                 err = -ENXIO;
 510                 goto failed_resource;
 511         }
 512 
 513         strcpy(info->fix.id, pdev->name);
 514         info->fbops             = &ep93xxfb_ops;
 515         info->fix.type          = FB_TYPE_PACKED_PIXELS;
 516         info->fix.accel         = FB_ACCEL_NONE;
 517         info->var.activate      = FB_ACTIVATE_NOW;
 518         info->var.vmode         = FB_VMODE_NONINTERLACED;
 519         info->flags             = FBINFO_DEFAULT;
 520         info->node              = -1;
 521         info->state             = FBINFO_STATE_RUNNING;
 522         info->pseudo_palette    = &fbi->pseudo_palette;
 523 
 524         fb_get_options("ep93xx-fb", &video_mode);
 525         err = fb_find_mode(&info->var, info, video_mode,
 526                            NULL, 0, NULL, 16);
 527         if (err == 0) {
 528                 dev_err(info->dev, "No suitable video mode found\n");
 529                 err = -EINVAL;
 530                 goto failed_resource;
 531         }
 532 
 533         if (mach_info->setup) {
 534                 err = mach_info->setup(pdev);
 535                 if (err)
 536                         goto failed_resource;
 537         }
 538 
 539         err = ep93xxfb_check_var(&info->var, info);
 540         if (err)
 541                 goto failed_check;
 542 
 543         fbi->clk = devm_clk_get(&pdev->dev, NULL);
 544         if (IS_ERR(fbi->clk)) {
 545                 err = PTR_ERR(fbi->clk);
 546                 fbi->clk = NULL;
 547                 goto failed_check;
 548         }
 549 
 550         ep93xxfb_set_par(info);
 551         clk_enable(fbi->clk);
 552 
 553         err = register_framebuffer(info);
 554         if (err)
 555                 goto failed_check;
 556 
 557         dev_info(info->dev, "registered. Mode = %dx%d-%d\n",
 558                  info->var.xres, info->var.yres, info->var.bits_per_pixel);
 559         return 0;
 560 
 561 failed_check:
 562         if (fbi->mach_info->teardown)
 563                 fbi->mach_info->teardown(pdev);
 564 failed_resource:
 565         ep93xxfb_dealloc_videomem(info);
 566 failed_videomem:
 567         fb_dealloc_cmap(&info->cmap);
 568 failed_cmap:
 569         kfree(info);
 570 
 571         return err;
 572 }
 573 
 574 static int ep93xxfb_remove(struct platform_device *pdev)
 575 {
 576         struct fb_info *info = platform_get_drvdata(pdev);
 577         struct ep93xx_fbi *fbi = info->par;
 578 
 579         unregister_framebuffer(info);
 580         clk_disable(fbi->clk);
 581         ep93xxfb_dealloc_videomem(info);
 582         fb_dealloc_cmap(&info->cmap);
 583 
 584         if (fbi->mach_info->teardown)
 585                 fbi->mach_info->teardown(pdev);
 586 
 587         kfree(info);
 588 
 589         return 0;
 590 }
 591 
 592 static struct platform_driver ep93xxfb_driver = {
 593         .probe          = ep93xxfb_probe,
 594         .remove         = ep93xxfb_remove,
 595         .driver = {
 596                 .name   = "ep93xx-fb",
 597         },
 598 };
 599 module_platform_driver(ep93xxfb_driver);
 600 
 601 MODULE_DESCRIPTION("EP93XX Framebuffer Driver");
 602 MODULE_ALIAS("platform:ep93xx-fb");
 603 MODULE_AUTHOR("Ryan Mallon, "
 604               "H Hartley Sweeten <hsweeten@visionengravers.com");
 605 MODULE_LICENSE("GPL");

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