LCOV - code coverage report
Current view: top level - drivers/video - amba-clcd.c (source / functions) Hit Total Coverage
Test: coverage.info Lines: 0 361 0.0 %
Date: 2014-04-16 Functions: 0 23 0.0 %
Branches: 0 194 0.0 %

           Branch data     Line data    Source code
       1                 :            : /*
       2                 :            :  *  linux/drivers/video/amba-clcd.c
       3                 :            :  *
       4                 :            :  * Copyright (C) 2001 ARM Limited, by David A Rusling
       5                 :            :  * Updated to 2.5, Deep Blue Solutions Ltd.
       6                 :            :  *
       7                 :            :  * This file is subject to the terms and conditions of the GNU General Public
       8                 :            :  * License.  See the file COPYING in the main directory of this archive
       9                 :            :  * for more details.
      10                 :            :  *
      11                 :            :  *  ARM PrimeCell PL110 Color LCD Controller
      12                 :            :  */
      13                 :            : #include <linux/dma-mapping.h>
      14                 :            : #include <linux/module.h>
      15                 :            : #include <linux/kernel.h>
      16                 :            : #include <linux/errno.h>
      17                 :            : #include <linux/string.h>
      18                 :            : #include <linux/slab.h>
      19                 :            : #include <linux/delay.h>
      20                 :            : #include <linux/dma-mapping.h>
      21                 :            : #include <linux/memblock.h>
      22                 :            : #include <linux/mm.h>
      23                 :            : #include <linux/of.h>
      24                 :            : #include <linux/fb.h>
      25                 :            : #include <linux/init.h>
      26                 :            : #include <linux/ioport.h>
      27                 :            : #include <linux/list.h>
      28                 :            : #include <linux/amba/bus.h>
      29                 :            : #include <linux/amba/clcd.h>
      30                 :            : #include <linux/clk.h>
      31                 :            : #include <linux/hardirq.h>
      32                 :            : 
      33                 :            : #include <asm/sizes.h>
      34                 :            : 
      35                 :            : #define to_clcd(info)   container_of(info, struct clcd_fb, fb)
      36                 :            : 
      37                 :            : #ifdef CONFIG_ARM
      38                 :            : #define clcdfb_dma_alloc        dma_alloc_writecombine
      39                 :            : #define clcdfb_dma_free         dma_free_writecombine
      40                 :            : #define clcdfb_dma_mmap         dma_mmap_writecombine
      41                 :            : #else
      42                 :            : #define clcdfb_dma_alloc        dma_alloc_coherent
      43                 :            : #define clcdfb_dma_free         dma_free_coherent
      44                 :            : #define clcdfb_dma_mmap         dma_mmap_coherent
      45                 :            : #endif
      46                 :            : 
      47                 :            : /* This is limited to 16 characters when displayed by X startup */
      48                 :            : static const char *clcd_name = "CLCD FB";
      49                 :            : static char *def_mode;
      50                 :            : module_param_named(mode, def_mode, charp, 0);
      51                 :            : 
      52                 :            : /*
      53                 :            :  * Unfortunately, the enable/disable functions may be called either from
      54                 :            :  * process or IRQ context, and we _need_ to delay.  This is _not_ good.
      55                 :            :  */
      56                 :            : static inline void clcdfb_sleep(unsigned int ms)
      57                 :            : {
      58 [ #  # ][ #  # ]:          0 :         if (in_atomic()) {
      59 [ #  # ][ #  # ]:          0 :                 mdelay(ms);
      60                 :            :         } else {
      61                 :          0 :                 msleep(ms);
      62                 :            :         }
      63                 :            : }
      64                 :            : 
      65                 :            : static inline void clcdfb_set_start(struct clcd_fb *fb)
      66                 :            : {
      67                 :          0 :         unsigned long ustart = fb->fb.fix.smem_start;
      68                 :            :         unsigned long lstart;
      69                 :            : 
      70                 :          0 :         ustart += fb->fb.var.yoffset * fb->fb.fix.line_length;
      71                 :          0 :         lstart = ustart + fb->fb.var.yres * fb->fb.fix.line_length / 2;
      72                 :            : 
      73                 :          0 :         writel(ustart, fb->regs + CLCD_UBAS);
      74                 :          0 :         writel(lstart, fb->regs + CLCD_LBAS);
      75                 :            : }
      76                 :            : 
      77                 :          0 : static void clcdfb_disable(struct clcd_fb *fb)
      78                 :            : {
      79                 :            :         u32 val;
      80                 :            : 
      81         [ #  # ]:          0 :         if (fb->board->disable)
      82                 :          0 :                 fb->board->disable(fb);
      83                 :            : 
      84                 :          0 :         val = readl(fb->regs + fb->off_cntl);
      85         [ #  # ]:          0 :         if (val & CNTL_LCDPWR) {
      86                 :          0 :                 val &= ~CNTL_LCDPWR;
      87                 :          0 :                 writel(val, fb->regs + fb->off_cntl);
      88                 :            : 
      89                 :            :                 clcdfb_sleep(20);
      90                 :            :         }
      91         [ #  # ]:          0 :         if (val & CNTL_LCDEN) {
      92                 :          0 :                 val &= ~CNTL_LCDEN;
      93                 :          0 :                 writel(val, fb->regs + fb->off_cntl);
      94                 :            :         }
      95                 :            : 
      96                 :            :         /*
      97                 :            :          * Disable CLCD clock source.
      98                 :            :          */
      99         [ #  # ]:          0 :         if (fb->clk_enabled) {
     100                 :          0 :                 fb->clk_enabled = false;
     101                 :          0 :                 clk_disable(fb->clk);
     102                 :            :         }
     103                 :          0 : }
     104                 :            : 
     105                 :          0 : static void clcdfb_enable(struct clcd_fb *fb, u32 cntl)
     106                 :            : {
     107                 :            :         /*
     108                 :            :          * Enable the CLCD clock source.
     109                 :            :          */
     110         [ #  # ]:          0 :         if (!fb->clk_enabled) {
     111                 :          0 :                 fb->clk_enabled = true;
     112                 :          0 :                 clk_enable(fb->clk);
     113                 :            :         }
     114                 :            : 
     115                 :            :         /*
     116                 :            :          * Bring up by first enabling..
     117                 :            :          */
     118                 :          0 :         cntl |= CNTL_LCDEN;
     119                 :          0 :         writel(cntl, fb->regs + fb->off_cntl);
     120                 :            : 
     121                 :            :         clcdfb_sleep(20);
     122                 :            : 
     123                 :            :         /*
     124                 :            :          * and now apply power.
     125                 :            :          */
     126                 :          0 :         cntl |= CNTL_LCDPWR;
     127                 :          0 :         writel(cntl, fb->regs + fb->off_cntl);
     128                 :            : 
     129                 :            :         /*
     130                 :            :          * finally, enable the interface.
     131                 :            :          */
     132         [ #  # ]:          0 :         if (fb->board->enable)
     133                 :          0 :                 fb->board->enable(fb);
     134                 :          0 : }
     135                 :            : 
     136                 :            : static int
     137                 :          0 : clcdfb_set_bitfields(struct clcd_fb *fb, struct fb_var_screeninfo *var)
     138                 :            : {
     139                 :            :         u32 caps;
     140                 :            :         int ret = 0;
     141                 :            : 
     142 [ #  # ][ #  # ]:          0 :         if (fb->panel->caps && fb->board->caps)
     143                 :          0 :                 caps = fb->panel->caps & fb->board->caps;
     144                 :            :         else {
     145                 :            :                 /* Old way of specifying what can be used */
     146         [ #  # ]:          0 :                 caps = fb->panel->cntl & CNTL_BGR ?
     147                 :            :                         CLCD_CAP_BGR : CLCD_CAP_RGB;
     148                 :            :                 /* But mask out 444 modes as they weren't supported */
     149                 :          0 :                 caps &= ~CLCD_CAP_444;
     150                 :            :         }
     151                 :            : 
     152                 :            :         /* Only TFT panels can do RGB888/BGR888 */
     153         [ #  # ]:          0 :         if (!(fb->panel->cntl & CNTL_LCDTFT))
     154                 :          0 :                 caps &= ~CLCD_CAP_888;
     155                 :            : 
     156                 :          0 :         memset(&var->transp, 0, sizeof(var->transp));
     157                 :            : 
     158                 :          0 :         var->red.msb_right = 0;
     159                 :          0 :         var->green.msb_right = 0;
     160                 :          0 :         var->blue.msb_right = 0;
     161                 :            : 
     162 [ #  # ][ #  # ]:          0 :         switch (var->bits_per_pixel) {
         [ #  # ][ #  # ]
     163                 :            :         case 1:
     164                 :            :         case 2:
     165                 :            :         case 4:
     166                 :            :         case 8:
     167                 :            :                 /* If we can't do 5551, reject */
     168                 :          0 :                 caps &= CLCD_CAP_5551;
     169         [ #  # ]:          0 :                 if (!caps) {
     170                 :            :                         ret = -EINVAL;
     171                 :            :                         break;
     172                 :            :                 }
     173                 :            : 
     174                 :          0 :                 var->red.length              = var->bits_per_pixel;
     175                 :          0 :                 var->red.offset              = 0;
     176                 :          0 :                 var->green.length    = var->bits_per_pixel;
     177                 :          0 :                 var->green.offset    = 0;
     178                 :          0 :                 var->blue.length     = var->bits_per_pixel;
     179                 :          0 :                 var->blue.offset     = 0;
     180                 :            :                 break;
     181                 :            : 
     182                 :            :         case 16:
     183                 :            :                 /* If we can't do 444, 5551 or 565, reject */
     184         [ #  # ]:          0 :                 if (!(caps & (CLCD_CAP_444 | CLCD_CAP_5551 | CLCD_CAP_565))) {
     185                 :            :                         ret = -EINVAL;
     186                 :            :                         break;
     187                 :            :                 }
     188                 :            : 
     189                 :            :                 /*
     190                 :            :                  * Green length can be 4, 5 or 6 depending whether
     191                 :            :                  * we're operating in 444, 5551 or 565 mode.
     192                 :            :                  */
     193 [ #  # ][ #  # ]:          0 :                 if (var->green.length == 4 && caps & CLCD_CAP_444)
     194                 :            :                         caps &= CLCD_CAP_444;
     195 [ #  # ][ #  # ]:          0 :                 if (var->green.length == 5 && caps & CLCD_CAP_5551)
     196                 :            :                         caps &= CLCD_CAP_5551;
     197 [ #  # ][ #  # ]:          0 :                 else if (var->green.length == 6 && caps & CLCD_CAP_565)
     198                 :            :                         caps &= CLCD_CAP_565;
     199                 :            :                 else {
     200                 :            :                         /*
     201                 :            :                          * PL110 officially only supports RGB555,
     202                 :            :                          * but may be wired up to allow RGB565.
     203                 :            :                          */
     204         [ #  # ]:          0 :                         if (caps & CLCD_CAP_565) {
     205                 :          0 :                                 var->green.length = 6;
     206                 :            :                                 caps &= CLCD_CAP_565;
     207         [ #  # ]:          0 :                         } else if (caps & CLCD_CAP_5551) {
     208                 :          0 :                                 var->green.length = 5;
     209                 :            :                                 caps &= CLCD_CAP_5551;
     210                 :            :                         } else {
     211                 :          0 :                                 var->green.length = 4;
     212                 :          0 :                                 caps &= CLCD_CAP_444;
     213                 :            :                         }
     214                 :            :                 }
     215                 :            : 
     216         [ #  # ]:          0 :                 if (var->green.length >= 5) {
     217                 :          0 :                         var->red.length = 5;
     218                 :          0 :                         var->blue.length = 5;
     219                 :            :                 } else {
     220                 :          0 :                         var->red.length = 4;
     221                 :          0 :                         var->blue.length = 4;
     222                 :            :                 }
     223                 :            :                 break;
     224                 :            :         case 32:
     225                 :            :                 /* If we can't do 888, reject */
     226                 :          0 :                 caps &= CLCD_CAP_888;
     227         [ #  # ]:          0 :                 if (!caps) {
     228                 :            :                         ret = -EINVAL;
     229                 :            :                         break;
     230                 :            :                 }
     231                 :            : 
     232                 :          0 :                 var->red.length = 8;
     233                 :          0 :                 var->green.length = 8;
     234                 :          0 :                 var->blue.length = 8;
     235                 :            :                 break;
     236                 :            :         default:
     237                 :            :                 ret = -EINVAL;
     238                 :            :                 break;
     239                 :            :         }
     240                 :            : 
     241                 :            :         /*
     242                 :            :          * >= 16bpp displays have separate colour component bitfields
     243                 :            :          * encoded in the pixel data.  Calculate their position from
     244                 :            :          * the bitfield length defined above.
     245                 :            :          */
     246 [ #  # ][ #  # ]:          0 :         if (ret == 0 && var->bits_per_pixel >= 16) {
     247                 :            :                 bool bgr, rgb;
     248                 :            : 
     249 [ #  # ][ #  # ]:          0 :                 bgr = caps & CLCD_CAP_BGR && var->blue.offset == 0;
     250 [ #  # ][ #  # ]:          0 :                 rgb = caps & CLCD_CAP_RGB && var->red.offset == 0;
     251                 :            : 
     252                 :            :                 /*
     253                 :            :                  * Seems that for 32-bit mode there is confusion about RGB
     254                 :            :                  * ordering somewhere between user-side, kernel and hardware.
     255                 :            :                  * The following hack seems get things working, at least on
     256                 :            :                  * vexpress hardware and models...
     257                 :            :                  */
     258         [ #  # ]:          0 :                 if (var->bits_per_pixel == 32) {
     259                 :            :                         bgr = false;
     260                 :            :                         rgb = true;
     261                 :            :                 }
     262                 :            : 
     263         [ #  # ]:          0 :                 if (!bgr && !rgb)
     264                 :            :                         /*
     265                 :            :                          * The requested format was not possible, try just
     266                 :            :                          * our capabilities.  One of BGR or RGB must be
     267                 :            :                          * supported.
     268                 :            :                          */
     269                 :          0 :                         bgr = caps & CLCD_CAP_BGR;
     270                 :            : 
     271         [ #  # ]:          0 :                 if (bgr) {
     272                 :          0 :                         var->blue.offset = 0;
     273                 :          0 :                         var->green.offset = var->blue.offset + var->blue.length;
     274                 :          0 :                         var->red.offset = var->green.offset + var->green.length;
     275                 :            :                 } else {
     276                 :          0 :                         var->red.offset = 0;
     277                 :          0 :                         var->green.offset = var->red.offset + var->red.length;
     278                 :          0 :                         var->blue.offset = var->green.offset + var->green.length;
     279                 :            :                 }
     280                 :            :         }
     281                 :            : 
     282                 :          0 :         return ret;
     283                 :            : }
     284                 :            : 
     285                 :          0 : static int clcdfb_check_var(struct fb_var_screeninfo *var, struct fb_info *info)
     286                 :            : {
     287                 :          0 :         struct clcd_fb *fb = to_clcd(info);
     288                 :            :         int ret = -EINVAL;
     289                 :            : 
     290         [ #  # ]:          0 :         if (fb->board->check)
     291                 :          0 :                 ret = fb->board->check(fb, var);
     292                 :            : 
     293 [ #  # ][ #  # ]:          0 :         if (ret == 0 &&
     294                 :          0 :             var->xres_virtual * var->bits_per_pixel / 8 *
     295                 :          0 :             var->yres_virtual > fb->fb.fix.smem_len)
     296                 :            :                 ret = -EINVAL;
     297                 :            : 
     298         [ #  # ]:          0 :         if (ret == 0)
     299                 :          0 :                 ret = clcdfb_set_bitfields(fb, var);
     300                 :            : 
     301                 :          0 :         return ret;
     302                 :            : }
     303                 :            : 
     304                 :          0 : static int clcdfb_set_par(struct fb_info *info)
     305                 :            : {
     306                 :            :         struct clcd_fb *fb = to_clcd(info);
     307                 :            :         struct clcd_regs regs;
     308                 :            : 
     309                 :          0 :         fb->fb.fix.line_length = fb->fb.var.xres_virtual *
     310                 :          0 :                                  fb->fb.var.bits_per_pixel / 8;
     311                 :            : 
     312         [ #  # ]:          0 :         if (fb->fb.var.bits_per_pixel <= 8)
     313                 :          0 :                 fb->fb.fix.visual = FB_VISUAL_PSEUDOCOLOR;
     314                 :            :         else
     315                 :          0 :                 fb->fb.fix.visual = FB_VISUAL_TRUECOLOR;
     316                 :            : 
     317                 :          0 :         fb->board->decode(fb, &regs);
     318                 :            : 
     319                 :          0 :         clcdfb_disable(fb);
     320                 :            : 
     321                 :          0 :         writel(regs.tim0, fb->regs + CLCD_TIM0);
     322                 :          0 :         writel(regs.tim1, fb->regs + CLCD_TIM1);
     323                 :          0 :         writel(regs.tim2, fb->regs + CLCD_TIM2);
     324                 :          0 :         writel(regs.tim3, fb->regs + CLCD_TIM3);
     325                 :            : 
     326                 :            :         clcdfb_set_start(fb);
     327                 :            : 
     328                 :          0 :         clk_set_rate(fb->clk, (1000000000 / regs.pixclock) * 1000);
     329                 :            : 
     330                 :          0 :         fb->clcd_cntl = regs.cntl;
     331                 :            : 
     332                 :          0 :         clcdfb_enable(fb, regs.cntl);
     333                 :            : 
     334                 :            : #ifdef DEBUG
     335                 :            :         printk(KERN_INFO
     336                 :            :                "CLCD: Registers set to\n"
     337                 :            :                "  %08x %08x %08x %08x\n"
     338                 :            :                "  %08x %08x %08x %08x\n",
     339                 :            :                 readl(fb->regs + CLCD_TIM0), readl(fb->regs + CLCD_TIM1),
     340                 :            :                 readl(fb->regs + CLCD_TIM2), readl(fb->regs + CLCD_TIM3),
     341                 :            :                 readl(fb->regs + CLCD_UBAS), readl(fb->regs + CLCD_LBAS),
     342                 :            :                 readl(fb->regs + fb->off_ienb), readl(fb->regs + fb->off_cntl));
     343                 :            : #endif
     344                 :            : 
     345                 :          0 :         return 0;
     346                 :            : }
     347                 :            : 
     348                 :            : static inline u32 convert_bitfield(int val, struct fb_bitfield *bf)
     349                 :            : {
     350                 :          0 :         unsigned int mask = (1 << bf->length) - 1;
     351                 :            : 
     352                 :          0 :         return (val >> (16 - bf->length) & mask) << bf->offset;
     353                 :            : }
     354                 :            : 
     355                 :            : /*
     356                 :            :  *  Set a single color register. The values supplied have a 16 bit
     357                 :            :  *  magnitude.  Return != 0 for invalid regno.
     358                 :            :  */
     359                 :            : static int
     360                 :          0 : clcdfb_setcolreg(unsigned int regno, unsigned int red, unsigned int green,
     361                 :            :                  unsigned int blue, unsigned int transp, struct fb_info *info)
     362                 :            : {
     363                 :            :         struct clcd_fb *fb = to_clcd(info);
     364                 :            : 
     365         [ #  # ]:          0 :         if (regno < 16)
     366                 :          0 :                 fb->cmap[regno] = convert_bitfield(transp, &fb->fb.var.transp) |
     367                 :          0 :                                   convert_bitfield(blue, &fb->fb.var.blue) |
     368                 :          0 :                                   convert_bitfield(green, &fb->fb.var.green) |
     369                 :          0 :                                   convert_bitfield(red, &fb->fb.var.red);
     370                 :            : 
     371 [ #  # ][ #  # ]:          0 :         if (fb->fb.fix.visual == FB_VISUAL_PSEUDOCOLOR && regno < 256) {
     372                 :          0 :                 int hw_reg = CLCD_PALETTE + ((regno * 2) & ~3);
     373                 :            :                 u32 val, mask, newval;
     374                 :            : 
     375                 :          0 :                 newval  = (red >> 11)  & 0x001f;
     376                 :          0 :                 newval |= (green >> 6) & 0x03e0;
     377                 :          0 :                 newval |= (blue >> 1)  & 0x7c00;
     378                 :            : 
     379                 :            :                 /*
     380                 :            :                  * 3.2.11: if we're configured for big endian
     381                 :            :                  * byte order, the palette entries are swapped.
     382                 :            :                  */
     383         [ #  # ]:          0 :                 if (fb->clcd_cntl & CNTL_BEBO)
     384                 :          0 :                         regno ^= 1;
     385                 :            : 
     386         [ #  # ]:          0 :                 if (regno & 1) {
     387                 :          0 :                         newval <<= 16;
     388                 :            :                         mask = 0x0000ffff;
     389                 :            :                 } else {
     390                 :            :                         mask = 0xffff0000;
     391                 :            :                 }
     392                 :            : 
     393                 :          0 :                 val = readl(fb->regs + hw_reg) & mask;
     394                 :          0 :                 writel(val | newval, fb->regs + hw_reg);
     395                 :            :         }
     396                 :            : 
     397                 :          0 :         return regno > 255;
     398                 :            : }
     399                 :            : 
     400                 :            : /*
     401                 :            :  *  Blank the screen if blank_mode != 0, else unblank. If blank == NULL
     402                 :            :  *  then the caller blanks by setting the CLUT (Color Look Up Table) to all
     403                 :            :  *  black. Return 0 if blanking succeeded, != 0 if un-/blanking failed due
     404                 :            :  *  to e.g. a video mode which doesn't support it. Implements VESA suspend
     405                 :            :  *  and powerdown modes on hardware that supports disabling hsync/vsync:
     406                 :            :  *    blank_mode == 2: suspend vsync
     407                 :            :  *    blank_mode == 3: suspend hsync
     408                 :            :  *    blank_mode == 4: powerdown
     409                 :            :  */
     410                 :          0 : static int clcdfb_blank(int blank_mode, struct fb_info *info)
     411                 :            : {
     412                 :            :         struct clcd_fb *fb = to_clcd(info);
     413                 :            : 
     414         [ #  # ]:          0 :         if (blank_mode != 0) {
     415                 :          0 :                 clcdfb_disable(fb);
     416                 :            :         } else {
     417                 :          0 :                 clcdfb_enable(fb, fb->clcd_cntl);
     418                 :            :         }
     419                 :          0 :         return 0;
     420                 :            : }
     421                 :            : 
     422                 :          0 : int clcdfb_mmap_dma(struct clcd_fb *fb, struct vm_area_struct *vma)
     423                 :            : {
     424                 :          0 :         return clcdfb_dma_mmap(&fb->dev->dev, vma,
     425                 :          0 :                                fb->fb.screen_base,
     426                 :          0 :                                fb->fb.fix.smem_start,
     427                 :            :                                fb->fb.fix.smem_len);
     428                 :            : }
     429                 :            : 
     430                 :          0 : int clcdfb_mmap_io(struct clcd_fb *fb, struct vm_area_struct *vma)
     431                 :            : {
     432                 :            :         unsigned long user_count, count, pfn, off;
     433                 :            : 
     434                 :          0 :         user_count      = (vma->vm_end - vma->vm_start) >> PAGE_SHIFT;
     435                 :          0 :         count           = PAGE_ALIGN(fb->fb.fix.smem_len) >> PAGE_SHIFT;
     436                 :          0 :         pfn             = fb->fb.fix.smem_start >> PAGE_SHIFT;
     437                 :          0 :         off             = vma->vm_pgoff;
     438                 :            : 
     439                 :          0 :         vma->vm_page_prot = pgprot_noncached(vma->vm_page_prot);
     440                 :            : 
     441 [ #  # ][ #  # ]:          0 :         if (off < count && user_count <= (count - off))
     442                 :          0 :                 return remap_pfn_range(vma, vma->vm_start, pfn + off,
     443                 :            :                                        user_count << PAGE_SHIFT,
     444                 :            :                                        vma->vm_page_prot);
     445                 :            : 
     446                 :            :         return -ENXIO;
     447                 :            : }
     448                 :            : 
     449                 :          0 : void clcdfb_remove_dma(struct clcd_fb *fb)
     450                 :            : {
     451                 :          0 :         clcdfb_dma_free(&fb->dev->dev, fb->fb.fix.smem_len,
     452                 :          0 :                         fb->fb.screen_base, fb->fb.fix.smem_start);
     453                 :          0 : }
     454                 :            : 
     455                 :          0 : void clcdfb_remove_io(struct clcd_fb *fb)
     456                 :            : {
     457                 :          0 :         iounmap(fb->fb.screen_base);
     458                 :          0 : }
     459                 :            : 
     460                 :          0 : static int clcdfb_mmap(struct fb_info *info,
     461                 :            :                        struct vm_area_struct *vma)
     462                 :            : {
     463                 :            :         struct clcd_fb *fb = to_clcd(info);
     464                 :          0 :         unsigned long len, off = vma->vm_pgoff << PAGE_SHIFT;
     465                 :            :         int ret = -EINVAL;
     466                 :            : 
     467                 :          0 :         len = info->fix.smem_len;
     468                 :            : 
     469 [ #  # ][ #  # ]:          0 :         if (off <= len && vma->vm_end - vma->vm_start <= len - off &&
                 [ #  # ]
     470                 :          0 :             fb->board->mmap)
     471                 :          0 :                 ret = fb->board->mmap(fb, vma);
     472                 :            : 
     473                 :          0 :         return ret;
     474                 :            : }
     475                 :            : 
     476                 :            : static struct fb_ops clcdfb_ops = {
     477                 :            :         .owner          = THIS_MODULE,
     478                 :            :         .fb_check_var   = clcdfb_check_var,
     479                 :            :         .fb_set_par     = clcdfb_set_par,
     480                 :            :         .fb_setcolreg   = clcdfb_setcolreg,
     481                 :            :         .fb_blank       = clcdfb_blank,
     482                 :            :         .fb_fillrect    = cfb_fillrect,
     483                 :            :         .fb_copyarea    = cfb_copyarea,
     484                 :            :         .fb_imageblit   = cfb_imageblit,
     485                 :            :         .fb_mmap        = clcdfb_mmap,
     486                 :            : };
     487                 :            : 
     488                 :          0 : static int clcdfb_register(struct clcd_fb *fb)
     489                 :            : {
     490                 :            :         int ret;
     491                 :            : 
     492                 :            :         /*
     493                 :            :          * ARM PL111 always has IENB at 0x1c; it's only PL110
     494                 :            :          * which is reversed on some platforms.
     495                 :            :          */
     496 [ #  # ][ #  # ]:          0 :         if (amba_manf(fb->dev) == 0x41 && amba_part(fb->dev) == 0x111) {
     497                 :          0 :                 fb->off_ienb = CLCD_PL111_IENB;
     498                 :          0 :                 fb->off_cntl = CLCD_PL111_CNTL;
     499                 :            :         } else {
     500                 :            : #ifdef CONFIG_ARCH_VERSATILE
     501                 :            :                 fb->off_ienb = CLCD_PL111_IENB;
     502                 :            :                 fb->off_cntl = CLCD_PL111_CNTL;
     503                 :            : #else
     504                 :          0 :                 fb->off_ienb = CLCD_PL110_IENB;
     505                 :          0 :                 fb->off_cntl = CLCD_PL110_CNTL;
     506                 :            : #endif
     507                 :            :         }
     508                 :            : 
     509                 :          0 :         fb->clk = clk_get(&fb->dev->dev, NULL);
     510         [ #  # ]:          0 :         if (IS_ERR(fb->clk)) {
     511                 :            :                 ret = PTR_ERR(fb->clk);
     512                 :          0 :                 goto out;
     513                 :            :         }
     514                 :            : 
     515                 :          0 :         ret = clk_prepare(fb->clk);
     516         [ #  # ]:          0 :         if (ret)
     517                 :            :                 goto free_clk;
     518                 :            : 
     519                 :          0 :         fb->fb.device                = &fb->dev->dev;
     520                 :            : 
     521                 :          0 :         fb->fb.fix.mmio_start        = fb->dev->res.start;
     522                 :          0 :         fb->fb.fix.mmio_len  = resource_size(&fb->dev->res);
     523                 :            : 
     524                 :          0 :         fb->regs = ioremap(fb->fb.fix.mmio_start, fb->fb.fix.mmio_len);
     525         [ #  # ]:          0 :         if (!fb->regs) {
     526                 :          0 :                 printk(KERN_ERR "CLCD: unable to remap registers\n");
     527                 :            :                 ret = -ENOMEM;
     528                 :          0 :                 goto clk_unprep;
     529                 :            :         }
     530                 :            : 
     531                 :          0 :         fb->fb.fbops         = &clcdfb_ops;
     532                 :          0 :         fb->fb.flags         = FBINFO_FLAG_DEFAULT;
     533                 :          0 :         fb->fb.pseudo_palette        = fb->cmap;
     534                 :            : 
     535                 :          0 :         strncpy(fb->fb.fix.id, clcd_name, sizeof(fb->fb.fix.id));
     536                 :          0 :         fb->fb.fix.type              = FB_TYPE_PACKED_PIXELS;
     537                 :          0 :         fb->fb.fix.type_aux  = 0;
     538                 :          0 :         fb->fb.fix.xpanstep  = 0;
     539                 :          0 :         fb->fb.fix.ypanstep  = 0;
     540                 :          0 :         fb->fb.fix.ywrapstep = 0;
     541                 :          0 :         fb->fb.fix.accel     = FB_ACCEL_NONE;
     542                 :            : 
     543                 :          0 :         fb->fb.var.xres              = fb->panel->mode.xres;
     544                 :          0 :         fb->fb.var.yres              = fb->panel->mode.yres;
     545                 :          0 :         fb->fb.var.xres_virtual      = fb->panel->mode.xres;
     546                 :          0 :         fb->fb.var.yres_virtual      = fb->panel->mode.yres;
     547                 :          0 :         fb->fb.var.bits_per_pixel = fb->panel->bpp;
     548                 :          0 :         fb->fb.var.grayscale = fb->panel->grayscale;
     549                 :          0 :         fb->fb.var.pixclock  = fb->panel->mode.pixclock;
     550                 :          0 :         fb->fb.var.left_margin       = fb->panel->mode.left_margin;
     551                 :          0 :         fb->fb.var.right_margin      = fb->panel->mode.right_margin;
     552                 :          0 :         fb->fb.var.upper_margin      = fb->panel->mode.upper_margin;
     553                 :          0 :         fb->fb.var.lower_margin      = fb->panel->mode.lower_margin;
     554                 :          0 :         fb->fb.var.hsync_len = fb->panel->mode.hsync_len;
     555                 :          0 :         fb->fb.var.vsync_len = fb->panel->mode.vsync_len;
     556                 :          0 :         fb->fb.var.sync              = fb->panel->mode.sync;
     557                 :          0 :         fb->fb.var.vmode     = fb->panel->mode.vmode;
     558                 :          0 :         fb->fb.var.activate  = FB_ACTIVATE_NOW;
     559                 :          0 :         fb->fb.var.nonstd    = 0;
     560                 :          0 :         fb->fb.var.height    = fb->panel->height;
     561                 :          0 :         fb->fb.var.width     = fb->panel->width;
     562                 :          0 :         fb->fb.var.accel_flags       = 0;
     563                 :            : 
     564                 :          0 :         fb->fb.monspecs.hfmin        = 0;
     565                 :          0 :         fb->fb.monspecs.hfmax   = 100000;
     566                 :          0 :         fb->fb.monspecs.vfmin        = 0;
     567                 :          0 :         fb->fb.monspecs.vfmax        = 400;
     568                 :          0 :         fb->fb.monspecs.dclkmin = 1000000;
     569                 :          0 :         fb->fb.monspecs.dclkmax      = 100000000;
     570                 :            : 
     571                 :            :         /*
     572                 :            :          * Make sure that the bitfields are set appropriately.
     573                 :            :          */
     574                 :          0 :         clcdfb_set_bitfields(fb, &fb->fb.var);
     575                 :            : 
     576                 :            :         /*
     577                 :            :          * Allocate colourmap.
     578                 :            :          */
     579                 :          0 :         ret = fb_alloc_cmap(&fb->fb.cmap, 256, 0);
     580         [ #  # ]:          0 :         if (ret)
     581                 :            :                 goto unmap;
     582                 :            : 
     583                 :            :         /*
     584                 :            :          * Ensure interrupts are disabled.
     585                 :            :          */
     586                 :          0 :         writel(0, fb->regs + fb->off_ienb);
     587                 :            : 
     588                 :          0 :         fb_set_var(&fb->fb, &fb->fb.var);
     589                 :            : 
     590                 :          0 :         dev_info(&fb->dev->dev, "%s hardware, %s display\n",
     591                 :            :                  fb->board->name, fb->panel->mode.name);
     592                 :            : 
     593                 :          0 :         ret = register_framebuffer(&fb->fb);
     594         [ #  # ]:          0 :         if (ret == 0)
     595                 :            :                 goto out;
     596                 :            : 
     597                 :          0 :         printk(KERN_ERR "CLCD: cannot register framebuffer (%d)\n", ret);
     598                 :            : 
     599                 :          0 :         fb_dealloc_cmap(&fb->fb.cmap);
     600                 :            :  unmap:
     601                 :          0 :         iounmap(fb->regs);
     602                 :            :  clk_unprep:
     603                 :          0 :         clk_unprepare(fb->clk);
     604                 :            :  free_clk:
     605                 :          0 :         clk_put(fb->clk);
     606                 :            :  out:
     607                 :          0 :         return ret;
     608                 :            : }
     609                 :            : 
     610                 :            : struct string_lookup {
     611                 :            :         const char *string;
     612                 :            :         const u32       val;
     613                 :            : };
     614                 :            : 
     615                 :            : static struct string_lookup vmode_lookups[] = {
     616                 :            :         { "FB_VMODE_NONINTERLACED", FB_VMODE_NONINTERLACED},
     617                 :            :         { "FB_VMODE_INTERLACED",    FB_VMODE_INTERLACED},
     618                 :            :         { "FB_VMODE_DOUBLE",        FB_VMODE_DOUBLE},
     619                 :            :         { "FB_VMODE_ODD_FLD_FIRST", FB_VMODE_ODD_FLD_FIRST},
     620                 :            :         { NULL, 0 },
     621                 :            : };
     622                 :            : 
     623                 :            : static struct string_lookup tim2_lookups[] = {
     624                 :            :         { "TIM2_CLKSEL", TIM2_CLKSEL},
     625                 :            :         { "TIM2_IVS",    TIM2_IVS},
     626                 :            :         { "TIM2_IHS",    TIM2_IHS},
     627                 :            :         { "TIM2_IPC",    TIM2_IPC},
     628                 :            :         { "TIM2_IOE",    TIM2_IOE},
     629                 :            :         { "TIM2_BCD",    TIM2_BCD},
     630                 :            :         { NULL, 0},
     631                 :            : };
     632                 :            : static struct string_lookup cntl_lookups[] = {
     633                 :            :         {"CNTL_LCDEN",        CNTL_LCDEN},
     634                 :            :         {"CNTL_LCDBPP1",      CNTL_LCDBPP1},
     635                 :            :         {"CNTL_LCDBPP2",      CNTL_LCDBPP2},
     636                 :            :         {"CNTL_LCDBPP4",      CNTL_LCDBPP4},
     637                 :            :         {"CNTL_LCDBPP8",      CNTL_LCDBPP8},
     638                 :            :         {"CNTL_LCDBPP16",     CNTL_LCDBPP16},
     639                 :            :         {"CNTL_LCDBPP16_565", CNTL_LCDBPP16_565},
     640                 :            :         {"CNTL_LCDBPP16_444", CNTL_LCDBPP16_444},
     641                 :            :         {"CNTL_LCDBPP24",     CNTL_LCDBPP24},
     642                 :            :         {"CNTL_LCDBW",        CNTL_LCDBW},
     643                 :            :         {"CNTL_LCDTFT",       CNTL_LCDTFT},
     644                 :            :         {"CNTL_LCDMONO8",     CNTL_LCDMONO8},
     645                 :            :         {"CNTL_LCDDUAL",      CNTL_LCDDUAL},
     646                 :            :         {"CNTL_BGR",          CNTL_BGR},
     647                 :            :         {"CNTL_BEBO",         CNTL_BEBO},
     648                 :            :         {"CNTL_BEPO",         CNTL_BEPO},
     649                 :            :         {"CNTL_LCDPWR",       CNTL_LCDPWR},
     650                 :            :         {"CNTL_LCDVCOMP(1)",  CNTL_LCDVCOMP(1)},
     651                 :            :         {"CNTL_LCDVCOMP(2)",  CNTL_LCDVCOMP(2)},
     652                 :            :         {"CNTL_LCDVCOMP(3)",  CNTL_LCDVCOMP(3)},
     653                 :            :         {"CNTL_LCDVCOMP(4)",  CNTL_LCDVCOMP(4)},
     654                 :            :         {"CNTL_LCDVCOMP(5)",  CNTL_LCDVCOMP(5)},
     655                 :            :         {"CNTL_LCDVCOMP(6)",  CNTL_LCDVCOMP(6)},
     656                 :            :         {"CNTL_LCDVCOMP(7)",  CNTL_LCDVCOMP(7)},
     657                 :            :         {"CNTL_LDMAFIFOTIME", CNTL_LDMAFIFOTIME},
     658                 :            :         {"CNTL_WATERMARK",    CNTL_WATERMARK},
     659                 :            :         { NULL, 0},
     660                 :            : };
     661                 :            : static struct string_lookup caps_lookups[] = {
     662                 :            :         {"CLCD_CAP_RGB444",  CLCD_CAP_RGB444},
     663                 :            :         {"CLCD_CAP_RGB5551", CLCD_CAP_RGB5551},
     664                 :            :         {"CLCD_CAP_RGB565",  CLCD_CAP_RGB565},
     665                 :            :         {"CLCD_CAP_RGB888",  CLCD_CAP_RGB888},
     666                 :            :         {"CLCD_CAP_BGR444",  CLCD_CAP_BGR444},
     667                 :            :         {"CLCD_CAP_BGR5551", CLCD_CAP_BGR5551},
     668                 :            :         {"CLCD_CAP_BGR565",  CLCD_CAP_BGR565},
     669                 :            :         {"CLCD_CAP_BGR888",  CLCD_CAP_BGR888},
     670                 :            :         {"CLCD_CAP_444",     CLCD_CAP_444},
     671                 :            :         {"CLCD_CAP_5551",    CLCD_CAP_5551},
     672                 :            :         {"CLCD_CAP_565",     CLCD_CAP_565},
     673                 :            :         {"CLCD_CAP_888",     CLCD_CAP_888},
     674                 :            :         {"CLCD_CAP_RGB",     CLCD_CAP_RGB},
     675                 :            :         {"CLCD_CAP_BGR",     CLCD_CAP_BGR},
     676                 :            :         {"CLCD_CAP_ALL",     CLCD_CAP_ALL},
     677                 :            :         { NULL, 0},
     678                 :            : };
     679                 :            : 
     680                 :          0 : u32 parse_setting(struct string_lookup *lookup, const char *name)
     681                 :            : {
     682                 :            :         int i = 0;
     683         [ #  # ]:          0 :         while (lookup[i].string != NULL) {
     684         [ #  # ]:          0 :                 if (strcmp(lookup[i].string, name) == 0)
     685                 :          0 :                         return lookup[i].val;
     686                 :          0 :                 ++i;
     687                 :            :         }
     688                 :            :         return -EINVAL;
     689                 :            : }
     690                 :            : 
     691                 :          0 : u32 get_string_lookup(struct device_node *node, const char *name,
     692                 :            :                       struct string_lookup *lookup)
     693                 :            : {
     694                 :            :         const char *string;
     695                 :            :         int count, i, ret = 0;
     696                 :            : 
     697                 :          0 :         count = of_property_count_strings(node, name);
     698         [ #  # ]:          0 :         if (count >= 0)
     699         [ #  # ]:          0 :                 for (i = 0; i < count; i++)
     700         [ #  # ]:          0 :                         if (of_property_read_string_index(node, name, i,
     701                 :            :                                         &string) == 0)
     702                 :          0 :                                 ret |= parse_setting(lookup, string);
     703                 :          0 :         return ret;
     704                 :            : }
     705                 :            : 
     706                 :          0 : int get_val(struct device_node *node, const char *string)
     707                 :            : {
     708                 :          0 :         u32 ret = 0;
     709                 :            : 
     710         [ #  # ]:          0 :         if (of_property_read_u32(node, string, &ret))
     711                 :          0 :                 ret = -1;
     712                 :          0 :         return ret;
     713                 :            : }
     714                 :            : 
     715                 :          0 : struct clcd_panel *getPanel(struct device_node *node)
     716                 :            : {
     717                 :            :         static struct clcd_panel panel;
     718                 :            : 
     719                 :          0 :         panel.mode.refresh      = get_val(node, "refresh");
     720                 :          0 :         panel.mode.xres         = get_val(node, "xres");
     721                 :          0 :         panel.mode.yres         = get_val(node, "yres");
     722                 :          0 :         panel.mode.pixclock     = get_val(node, "pixclock");
     723                 :          0 :         panel.mode.left_margin  = get_val(node, "left_margin");
     724                 :          0 :         panel.mode.right_margin = get_val(node, "right_margin");
     725                 :          0 :         panel.mode.upper_margin = get_val(node, "upper_margin");
     726                 :          0 :         panel.mode.lower_margin = get_val(node, "lower_margin");
     727                 :          0 :         panel.mode.hsync_len    = get_val(node, "hsync_len");
     728                 :          0 :         panel.mode.vsync_len    = get_val(node, "vsync_len");
     729                 :          0 :         panel.mode.sync         = get_val(node, "sync");
     730                 :          0 :         panel.bpp               = get_val(node, "bpp");
     731                 :          0 :         panel.width             = (signed short) get_val(node, "width");
     732                 :          0 :         panel.height            = (signed short) get_val(node, "height");
     733                 :            : 
     734                 :          0 :         panel.mode.vmode = get_string_lookup(node, "vmode", vmode_lookups);
     735                 :          0 :         panel.tim2       = get_string_lookup(node, "tim2",  tim2_lookups);
     736                 :          0 :         panel.cntl       = get_string_lookup(node, "cntl",  cntl_lookups);
     737                 :          0 :         panel.caps       = get_string_lookup(node, "caps",  caps_lookups);
     738                 :            : 
     739                 :          0 :         return &panel;
     740                 :            : }
     741                 :            : 
     742                 :          0 : struct clcd_panel *clcdfb_get_panel(const char *name)
     743                 :            : {
     744                 :            :         struct device_node *node = NULL;
     745                 :            :         const char *mode;
     746                 :            :         struct clcd_panel *panel = NULL;
     747                 :            : 
     748                 :            :         do {
     749                 :          0 :                 node = of_find_compatible_node(node, NULL, "panel");
     750         [ #  # ]:          0 :                 if (node)
     751         [ #  # ]:          0 :                         if (of_property_read_string(node, "mode", &mode) == 0)
     752         [ #  # ]:          0 :                                 if (strcmp(mode, name) == 0) {
     753                 :          0 :                                         panel = getPanel(node);
     754                 :          0 :                                         panel->mode.name = name;
     755                 :            :                                 }
     756         [ #  # ]:          0 :         } while (node != NULL);
     757                 :            : 
     758                 :          0 :         return panel;
     759                 :            : }
     760                 :            : 
     761                 :            : #ifdef CONFIG_OF
     762                 :          0 : static int clcdfb_dt_init(struct clcd_fb *fb)
     763                 :            : {
     764                 :            :         int err = 0;
     765                 :            :         struct device_node *node;
     766                 :            :         const char *mode;
     767                 :            :         dma_addr_t dma;
     768                 :            :         u32 use_dma;
     769                 :            :         const __be32 *prop;
     770                 :            :         int len, na, ns;
     771                 :            :         phys_addr_t fb_base, fb_size;
     772                 :            : 
     773                 :          0 :         node = fb->dev->dev.of_node;
     774         [ #  # ]:          0 :         if (!node)
     775                 :            :                 return -ENODEV;
     776                 :            : 
     777                 :          0 :         na = of_n_addr_cells(node);
     778                 :          0 :         ns = of_n_size_cells(node);
     779                 :            : 
     780 [ #  # ][ #  # ]:          0 :         if (def_mode && strlen(def_mode) > 0) {
     781                 :          0 :                 fb->panel = clcdfb_get_panel(def_mode);
     782         [ #  # ]:          0 :                 if (!fb->panel)
     783                 :          0 :                         printk(KERN_ERR "CLCD: invalid mode specified on the command line (%s)\n", def_mode);
     784                 :            :         }
     785                 :            : 
     786         [ #  # ]:          0 :         if (!fb->panel) {
     787 [ #  # ][ #  # ]:          0 :                 if (WARN_ON(of_property_read_string(node, "mode", &mode)))
     788                 :            :                         return -ENODEV;
     789                 :          0 :                 fb->panel = clcdfb_get_panel(mode);
     790                 :            :         }
     791                 :            : 
     792         [ #  # ]:          0 :         if (!fb->panel)
     793                 :            :                 return -EINVAL;
     794                 :          0 :         fb->fb.fix.smem_len = fb->panel->mode.xres * fb->panel->mode.yres * 4;
     795                 :            : 
     796                 :          0 :         fb->board->name           = "Device Tree CLCD PL111";
     797                 :          0 :         fb->board->caps           = CLCD_CAP_5551 | CLCD_CAP_565 | CLCD_CAP_888;
     798                 :          0 :         fb->board->check  = clcdfb_check;
     799                 :          0 :         fb->board->decode = clcdfb_decode;
     800                 :            : 
     801         [ #  # ]:          0 :         if (of_property_read_u32(node, "use_dma", &use_dma))
     802                 :          0 :                 use_dma = 0;
     803                 :            : 
     804         [ #  # ]:          0 :         if (use_dma) {
     805                 :          0 :                 fb->fb.screen_base = clcdfb_dma_alloc(&fb->dev->dev,
     806                 :            :                                                       fb->fb.fix.smem_len,
     807                 :            :                                                       &dma, GFP_KERNEL);
     808         [ #  # ]:          0 :                 if (!fb->fb.screen_base) {
     809                 :          0 :                         pr_err("CLCD: unable to map framebuffer\n");
     810                 :          0 :                         return -ENOMEM;
     811                 :            :                 }
     812                 :            : 
     813                 :          0 :                 fb->fb.fix.smem_start        = dma;
     814                 :          0 :                 fb->board->mmap           = clcdfb_mmap_dma;
     815                 :          0 :                 fb->board->remove = clcdfb_remove_dma;
     816                 :            :         } else {
     817                 :          0 :                 prop = of_get_property(node, "framebuffer", &len);
     818 [ #  # ][ #  # ]:          0 :                 if (WARN_ON(!prop || len < (na + ns) * sizeof(*prop)))
         [ #  # ][ #  # ]
     819                 :            :                         return -EINVAL;
     820                 :            : 
     821                 :          0 :                 fb_base = of_read_number(prop, na);
     822                 :          0 :                 fb_size = of_read_number(prop + na, ns);
     823                 :            : 
     824                 :          0 :                 fb->fb.fix.smem_start        = fb_base;
     825                 :          0 :                 fb->fb.screen_base   = ioremap_wc(fb_base, fb_size);
     826                 :          0 :                 fb->board->mmap           = clcdfb_mmap_io;
     827                 :          0 :                 fb->board->remove = clcdfb_remove_io;
     828                 :            :         }
     829                 :            : 
     830                 :            :         return err;
     831                 :            : }
     832                 :            : #endif /* CONFIG_OF */
     833                 :            : 
     834                 :          0 : static int clcdfb_probe(struct amba_device *dev, const struct amba_id *id)
     835                 :            : {
     836                 :          0 :         struct clcd_board *board = dev_get_platdata(&dev->dev);
     837                 :            :         struct clcd_fb *fb;
     838                 :            :         int ret;
     839                 :            : 
     840         [ #  # ]:          0 :         if (!board) {
     841                 :            : #ifdef CONFIG_OF
     842         [ #  # ]:          0 :                 if (dev->dev.of_node) {
     843                 :            :                         board = kzalloc(sizeof(struct clcd_board), GFP_KERNEL);
     844         [ #  # ]:          0 :                         if (!board)
     845                 :            :                                 return -ENOMEM;
     846                 :          0 :                         board->setup   = clcdfb_dt_init;
     847                 :            :                 } else
     848                 :            : #endif
     849                 :            :                         return -EINVAL;
     850                 :            :         }
     851                 :            : 
     852                 :          0 :         ret = dma_set_mask_and_coherent(&dev->dev, DMA_BIT_MASK(32));
     853         [ #  # ]:          0 :         if (ret)
     854                 :            :                 goto out;
     855                 :            : 
     856                 :          0 :         ret = amba_request_regions(dev, NULL);
     857         [ #  # ]:          0 :         if (ret) {
     858                 :          0 :                 printk(KERN_ERR "CLCD: unable to reserve regs region\n");
     859                 :          0 :                 goto out;
     860                 :            :         }
     861                 :            : 
     862                 :            :         fb = kzalloc(sizeof(struct clcd_fb), GFP_KERNEL);
     863         [ #  # ]:          0 :         if (!fb) {
     864                 :          0 :                 printk(KERN_INFO "CLCD: could not allocate new clcd_fb struct\n");
     865                 :            :                 ret = -ENOMEM;
     866                 :          0 :                 goto free_region;
     867                 :            :         }
     868                 :            : 
     869                 :          0 :         fb->dev = dev;
     870                 :          0 :         fb->board = board;
     871                 :            : 
     872                 :          0 :         dev_info(&fb->dev->dev, "PL%03x rev%u at 0x%08llx\n",
     873                 :            :                 amba_part(dev), amba_rev(dev),
     874                 :            :                 (unsigned long long)dev->res.start);
     875                 :            : 
     876                 :          0 :         ret = fb->board->setup(fb);
     877         [ #  # ]:          0 :         if (ret)
     878                 :            :                 goto free_fb;
     879                 :            : 
     880                 :          0 :         ret = clcdfb_register(fb); 
     881         [ #  # ]:          0 :         if (ret == 0) {
     882                 :          0 :                 amba_set_drvdata(dev, fb);
     883                 :          0 :                 goto out;
     884                 :            :         }
     885                 :            : 
     886                 :          0 :         fb->board->remove(fb);
     887                 :            :  free_fb:
     888                 :          0 :         kfree(fb);
     889                 :            :  free_region:
     890                 :          0 :         amba_release_regions(dev);
     891                 :            :  out:
     892                 :          0 :         return ret;
     893                 :            : }
     894                 :            : 
     895                 :          0 : static int clcdfb_remove(struct amba_device *dev)
     896                 :            : {
     897                 :          0 :         struct clcd_fb *fb = amba_get_drvdata(dev);
     898                 :            : 
     899                 :          0 :         clcdfb_disable(fb);
     900                 :          0 :         unregister_framebuffer(&fb->fb);
     901         [ #  # ]:          0 :         if (fb->fb.cmap.len)
     902                 :          0 :                 fb_dealloc_cmap(&fb->fb.cmap);
     903                 :          0 :         iounmap(fb->regs);
     904                 :          0 :         clk_unprepare(fb->clk);
     905                 :          0 :         clk_put(fb->clk);
     906                 :            : 
     907                 :          0 :         fb->board->remove(fb);
     908                 :            : 
     909                 :          0 :         kfree(fb);
     910                 :            : 
     911                 :          0 :         amba_release_regions(dev);
     912                 :            : 
     913                 :          0 :         return 0;
     914                 :            : }
     915                 :            : 
     916                 :            : static struct amba_id clcdfb_id_table[] = {
     917                 :            :         {
     918                 :            :                 .id     = 0x00041110,
     919                 :            :                 .mask   = 0x000ffffe,
     920                 :            :         },
     921                 :            :         { 0, 0 },
     922                 :            : };
     923                 :            : 
     924                 :            : MODULE_DEVICE_TABLE(amba, clcdfb_id_table);
     925                 :            : 
     926                 :            : static struct amba_driver clcd_driver = {
     927                 :            :         .drv            = {
     928                 :            :                 .name   = "clcd-pl11x",
     929                 :            :         },
     930                 :            :         .probe          = clcdfb_probe,
     931                 :            :         .remove         = clcdfb_remove,
     932                 :            :         .id_table       = clcdfb_id_table,
     933                 :            : };
     934                 :            : 
     935                 :          0 : static int __init amba_clcdfb_init(void)
     936                 :            : {
     937         [ #  # ]:          0 :         if (fb_get_options("ambafb", NULL))
     938                 :            :                 return -ENODEV;
     939                 :            : 
     940                 :          0 :         return amba_driver_register(&clcd_driver);
     941                 :            : }
     942                 :            : 
     943                 :            : module_init(amba_clcdfb_init);
     944                 :            : 
     945                 :          0 : static void __exit amba_clcdfb_exit(void)
     946                 :            : {
     947                 :          0 :         amba_driver_unregister(&clcd_driver);
     948                 :          0 : }
     949                 :            : 
     950                 :            : module_exit(amba_clcdfb_exit);
     951                 :            : 
     952                 :            : MODULE_DESCRIPTION("ARM PrimeCell PL110 CLCD core driver");
     953                 :            : MODULE_LICENSE("GPL");

Generated by: LCOV version 1.9