Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

video: fbdev: amba-clcd: Retire elder CLCD driver

All the functionality in this driver has been reimplemented
in the new DRM driver in drivers/gpu/drm/pl111/* and all
the boards using it have been migrated to use the DRM driver
with all configuration coming from the device tree.

I started the work to migrate the CLCD driver to DRM in
april 2017 and it took a little more than 3 years to do this
properly without leaving any platforms behind.

Reviewed-by: Eric Anholt <eric@anholt.net>
Signed-off-by: Linus Walleij <linus.walleij@linaro.org>
Cc: Russell King <linux@armlinux.org.uk>
Link: https://patchwork.freedesktop.org/patch/msgid/20200609200446.153209-2-linus.walleij@linaro.org

-1302
-5
MAINTAINERS
··· 1448 1448 F: drivers/amba/ 1449 1449 F: include/linux/amba/bus.h 1450 1450 1451 - ARM PRIMECELL CLCD PL110 DRIVER 1452 - M: Russell King <linux@armlinux.org.uk> 1453 - S: Odd Fixes 1454 - F: drivers/video/fbdev/amba-clcd.* 1455 - 1456 1451 ARM PRIMECELL KMI PL050 DRIVER 1457 1452 M: Russell King <linux@armlinux.org.uk> 1458 1453 S: Odd Fixes
-20
drivers/video/fbdev/Kconfig
··· 272 272 help 273 273 Support the Permedia2 FIFO disconnect feature. 274 274 275 - config FB_ARMCLCD 276 - tristate "ARM PrimeCell PL110 support" 277 - depends on ARM || ARM64 || COMPILE_TEST 278 - depends on FB && ARM_AMBA && HAS_IOMEM 279 - select FB_CFB_FILLRECT 280 - select FB_CFB_COPYAREA 281 - select FB_CFB_IMAGEBLIT 282 - select FB_MODE_HELPERS if OF 283 - select VIDEOMODE_HELPERS if OF 284 - select BACKLIGHT_CLASS_DEVICE if OF 285 - help 286 - This framebuffer device driver is for the ARM PrimeCell PL110 287 - Colour LCD controller. ARM PrimeCells provide the building 288 - blocks for System on a Chip devices. 289 - 290 - If you want to compile this as a module (=code which can be 291 - inserted into and removed from the running kernel), say M 292 - here and read <file:Documentation/kbuild/modules.rst>. The module 293 - will be called amba-clcd. 294 - 295 275 config FB_ACORN 296 276 bool "Acorn VIDC support" 297 277 depends on (FB = y) && ARM && ARCH_ACORN
-1
drivers/video/fbdev/Makefile
··· 75 75 obj-$(CONFIG_FB_ATMEL) += atmel_lcdfb.o 76 76 obj-$(CONFIG_FB_PVR2) += pvr2fb.o 77 77 obj-$(CONFIG_FB_VOODOO1) += sstfb.o 78 - obj-$(CONFIG_FB_ARMCLCD) += amba-clcd.o 79 78 obj-$(CONFIG_FB_GOLDFISH) += goldfishfb.o 80 79 obj-$(CONFIG_FB_68328) += 68328fb.o 81 80 obj-$(CONFIG_FB_GBE) += gbefb.o
-986
drivers/video/fbdev/amba-clcd.c
··· 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/amba/bus.h> 14 - #include <linux/amba/clcd.h> 15 - #include <linux/backlight.h> 16 - #include <linux/clk.h> 17 - #include <linux/delay.h> 18 - #include <linux/dma-mapping.h> 19 - #include <linux/fb.h> 20 - #include <linux/init.h> 21 - #include <linux/ioport.h> 22 - #include <linux/list.h> 23 - #include <linux/mm.h> 24 - #include <linux/module.h> 25 - #include <linux/of_address.h> 26 - #include <linux/of_graph.h> 27 - #include <linux/slab.h> 28 - #include <linux/string.h> 29 - #include <video/display_timing.h> 30 - #include <video/of_display_timing.h> 31 - #include <video/videomode.h> 32 - 33 - #define to_clcd(info) container_of(info, struct clcd_fb, fb) 34 - 35 - /* This is limited to 16 characters when displayed by X startup */ 36 - static const char *clcd_name = "CLCD FB"; 37 - 38 - /* 39 - * Unfortunately, the enable/disable functions may be called either from 40 - * process or IRQ context, and we _need_ to delay. This is _not_ good. 41 - */ 42 - static inline void clcdfb_sleep(unsigned int ms) 43 - { 44 - if (in_atomic()) { 45 - mdelay(ms); 46 - } else { 47 - msleep(ms); 48 - } 49 - } 50 - 51 - static inline void clcdfb_set_start(struct clcd_fb *fb) 52 - { 53 - unsigned long ustart = fb->fb.fix.smem_start; 54 - unsigned long lstart; 55 - 56 - ustart += fb->fb.var.yoffset * fb->fb.fix.line_length; 57 - lstart = ustart + fb->fb.var.yres * fb->fb.fix.line_length / 2; 58 - 59 - writel(ustart, fb->regs + CLCD_UBAS); 60 - writel(lstart, fb->regs + CLCD_LBAS); 61 - } 62 - 63 - static void clcdfb_disable(struct clcd_fb *fb) 64 - { 65 - u32 val; 66 - 67 - if (fb->board->disable) 68 - fb->board->disable(fb); 69 - 70 - if (fb->panel->backlight) { 71 - fb->panel->backlight->props.power = FB_BLANK_POWERDOWN; 72 - backlight_update_status(fb->panel->backlight); 73 - } 74 - 75 - val = readl(fb->regs + fb->off_cntl); 76 - if (val & CNTL_LCDPWR) { 77 - val &= ~CNTL_LCDPWR; 78 - writel(val, fb->regs + fb->off_cntl); 79 - 80 - clcdfb_sleep(20); 81 - } 82 - if (val & CNTL_LCDEN) { 83 - val &= ~CNTL_LCDEN; 84 - writel(val, fb->regs + fb->off_cntl); 85 - } 86 - 87 - /* 88 - * Disable CLCD clock source. 89 - */ 90 - if (fb->clk_enabled) { 91 - fb->clk_enabled = false; 92 - clk_disable(fb->clk); 93 - } 94 - } 95 - 96 - static void clcdfb_enable(struct clcd_fb *fb, u32 cntl) 97 - { 98 - /* 99 - * Enable the CLCD clock source. 100 - */ 101 - if (!fb->clk_enabled) { 102 - fb->clk_enabled = true; 103 - clk_enable(fb->clk); 104 - } 105 - 106 - /* 107 - * Bring up by first enabling.. 108 - */ 109 - cntl |= CNTL_LCDEN; 110 - writel(cntl, fb->regs + fb->off_cntl); 111 - 112 - clcdfb_sleep(20); 113 - 114 - /* 115 - * and now apply power. 116 - */ 117 - cntl |= CNTL_LCDPWR; 118 - writel(cntl, fb->regs + fb->off_cntl); 119 - 120 - /* 121 - * Turn on backlight 122 - */ 123 - if (fb->panel->backlight) { 124 - fb->panel->backlight->props.power = FB_BLANK_UNBLANK; 125 - backlight_update_status(fb->panel->backlight); 126 - } 127 - 128 - /* 129 - * finally, enable the interface. 130 - */ 131 - if (fb->board->enable) 132 - fb->board->enable(fb); 133 - } 134 - 135 - static int 136 - clcdfb_set_bitfields(struct clcd_fb *fb, struct fb_var_screeninfo *var) 137 - { 138 - u32 caps; 139 - int ret = 0; 140 - 141 - if (fb->panel->caps && fb->board->caps) 142 - caps = fb->panel->caps & fb->board->caps; 143 - else { 144 - /* Old way of specifying what can be used */ 145 - caps = fb->panel->cntl & CNTL_BGR ? 146 - CLCD_CAP_BGR : CLCD_CAP_RGB; 147 - /* But mask out 444 modes as they weren't supported */ 148 - caps &= ~CLCD_CAP_444; 149 - } 150 - 151 - /* Only TFT panels can do RGB888/BGR888 */ 152 - if (!(fb->panel->cntl & CNTL_LCDTFT)) 153 - caps &= ~CLCD_CAP_888; 154 - 155 - memset(&var->transp, 0, sizeof(var->transp)); 156 - 157 - var->red.msb_right = 0; 158 - var->green.msb_right = 0; 159 - var->blue.msb_right = 0; 160 - 161 - switch (var->bits_per_pixel) { 162 - case 1: 163 - case 2: 164 - case 4: 165 - case 8: 166 - /* If we can't do 5551, reject */ 167 - caps &= CLCD_CAP_5551; 168 - if (!caps) { 169 - ret = -EINVAL; 170 - break; 171 - } 172 - 173 - var->red.length = var->bits_per_pixel; 174 - var->red.offset = 0; 175 - var->green.length = var->bits_per_pixel; 176 - var->green.offset = 0; 177 - var->blue.length = var->bits_per_pixel; 178 - var->blue.offset = 0; 179 - break; 180 - 181 - case 16: 182 - /* If we can't do 444, 5551 or 565, reject */ 183 - if (!(caps & (CLCD_CAP_444 | CLCD_CAP_5551 | CLCD_CAP_565))) { 184 - ret = -EINVAL; 185 - break; 186 - } 187 - 188 - /* 189 - * Green length can be 4, 5 or 6 depending whether 190 - * we're operating in 444, 5551 or 565 mode. 191 - */ 192 - if (var->green.length == 4 && caps & CLCD_CAP_444) 193 - caps &= CLCD_CAP_444; 194 - if (var->green.length == 5 && caps & CLCD_CAP_5551) 195 - caps &= CLCD_CAP_5551; 196 - else if (var->green.length == 6 && caps & CLCD_CAP_565) 197 - caps &= CLCD_CAP_565; 198 - else { 199 - /* 200 - * PL110 officially only supports RGB555, 201 - * but may be wired up to allow RGB565. 202 - */ 203 - if (caps & CLCD_CAP_565) { 204 - var->green.length = 6; 205 - caps &= CLCD_CAP_565; 206 - } else if (caps & CLCD_CAP_5551) { 207 - var->green.length = 5; 208 - caps &= CLCD_CAP_5551; 209 - } else { 210 - var->green.length = 4; 211 - caps &= CLCD_CAP_444; 212 - } 213 - } 214 - 215 - if (var->green.length >= 5) { 216 - var->red.length = 5; 217 - var->blue.length = 5; 218 - } else { 219 - var->red.length = 4; 220 - var->blue.length = 4; 221 - } 222 - break; 223 - case 32: 224 - /* If we can't do 888, reject */ 225 - caps &= CLCD_CAP_888; 226 - if (!caps) { 227 - ret = -EINVAL; 228 - break; 229 - } 230 - 231 - var->red.length = 8; 232 - var->green.length = 8; 233 - var->blue.length = 8; 234 - break; 235 - default: 236 - ret = -EINVAL; 237 - break; 238 - } 239 - 240 - /* 241 - * >= 16bpp displays have separate colour component bitfields 242 - * encoded in the pixel data. Calculate their position from 243 - * the bitfield length defined above. 244 - */ 245 - if (ret == 0 && var->bits_per_pixel >= 16) { 246 - bool bgr, rgb; 247 - 248 - bgr = caps & CLCD_CAP_BGR && var->blue.offset == 0; 249 - rgb = caps & CLCD_CAP_RGB && var->red.offset == 0; 250 - 251 - if (!bgr && !rgb) 252 - /* 253 - * The requested format was not possible, try just 254 - * our capabilities. One of BGR or RGB must be 255 - * supported. 256 - */ 257 - bgr = caps & CLCD_CAP_BGR; 258 - 259 - if (bgr) { 260 - var->blue.offset = 0; 261 - var->green.offset = var->blue.offset + var->blue.length; 262 - var->red.offset = var->green.offset + var->green.length; 263 - } else { 264 - var->red.offset = 0; 265 - var->green.offset = var->red.offset + var->red.length; 266 - var->blue.offset = var->green.offset + var->green.length; 267 - } 268 - } 269 - 270 - return ret; 271 - } 272 - 273 - static int clcdfb_check_var(struct fb_var_screeninfo *var, struct fb_info *info) 274 - { 275 - struct clcd_fb *fb = to_clcd(info); 276 - int ret = -EINVAL; 277 - 278 - if (fb->board->check) 279 - ret = fb->board->check(fb, var); 280 - 281 - if (ret == 0 && 282 - var->xres_virtual * var->bits_per_pixel / 8 * 283 - var->yres_virtual > fb->fb.fix.smem_len) 284 - ret = -EINVAL; 285 - 286 - if (ret == 0) 287 - ret = clcdfb_set_bitfields(fb, var); 288 - 289 - return ret; 290 - } 291 - 292 - static int clcdfb_set_par(struct fb_info *info) 293 - { 294 - struct clcd_fb *fb = to_clcd(info); 295 - struct clcd_regs regs; 296 - 297 - fb->fb.fix.line_length = fb->fb.var.xres_virtual * 298 - fb->fb.var.bits_per_pixel / 8; 299 - 300 - if (fb->fb.var.bits_per_pixel <= 8) 301 - fb->fb.fix.visual = FB_VISUAL_PSEUDOCOLOR; 302 - else 303 - fb->fb.fix.visual = FB_VISUAL_TRUECOLOR; 304 - 305 - fb->board->decode(fb, &regs); 306 - 307 - clcdfb_disable(fb); 308 - 309 - writel(regs.tim0, fb->regs + CLCD_TIM0); 310 - writel(regs.tim1, fb->regs + CLCD_TIM1); 311 - writel(regs.tim2, fb->regs + CLCD_TIM2); 312 - writel(regs.tim3, fb->regs + CLCD_TIM3); 313 - 314 - clcdfb_set_start(fb); 315 - 316 - clk_set_rate(fb->clk, (1000000000 / regs.pixclock) * 1000); 317 - 318 - fb->clcd_cntl = regs.cntl; 319 - 320 - clcdfb_enable(fb, regs.cntl); 321 - 322 - #ifdef DEBUG 323 - printk(KERN_INFO 324 - "CLCD: Registers set to\n" 325 - " %08x %08x %08x %08x\n" 326 - " %08x %08x %08x %08x\n", 327 - readl(fb->regs + CLCD_TIM0), readl(fb->regs + CLCD_TIM1), 328 - readl(fb->regs + CLCD_TIM2), readl(fb->regs + CLCD_TIM3), 329 - readl(fb->regs + CLCD_UBAS), readl(fb->regs + CLCD_LBAS), 330 - readl(fb->regs + fb->off_ienb), readl(fb->regs + fb->off_cntl)); 331 - #endif 332 - 333 - return 0; 334 - } 335 - 336 - static inline u32 convert_bitfield(int val, struct fb_bitfield *bf) 337 - { 338 - unsigned int mask = (1 << bf->length) - 1; 339 - 340 - return (val >> (16 - bf->length) & mask) << bf->offset; 341 - } 342 - 343 - /* 344 - * Set a single color register. The values supplied have a 16 bit 345 - * magnitude. Return != 0 for invalid regno. 346 - */ 347 - static int 348 - clcdfb_setcolreg(unsigned int regno, unsigned int red, unsigned int green, 349 - unsigned int blue, unsigned int transp, struct fb_info *info) 350 - { 351 - struct clcd_fb *fb = to_clcd(info); 352 - 353 - if (regno < 16) 354 - fb->cmap[regno] = convert_bitfield(transp, &fb->fb.var.transp) | 355 - convert_bitfield(blue, &fb->fb.var.blue) | 356 - convert_bitfield(green, &fb->fb.var.green) | 357 - convert_bitfield(red, &fb->fb.var.red); 358 - 359 - if (fb->fb.fix.visual == FB_VISUAL_PSEUDOCOLOR && regno < 256) { 360 - int hw_reg = CLCD_PALETTE + ((regno * 2) & ~3); 361 - u32 val, mask, newval; 362 - 363 - newval = (red >> 11) & 0x001f; 364 - newval |= (green >> 6) & 0x03e0; 365 - newval |= (blue >> 1) & 0x7c00; 366 - 367 - /* 368 - * 3.2.11: if we're configured for big endian 369 - * byte order, the palette entries are swapped. 370 - */ 371 - if (fb->clcd_cntl & CNTL_BEBO) 372 - regno ^= 1; 373 - 374 - if (regno & 1) { 375 - newval <<= 16; 376 - mask = 0x0000ffff; 377 - } else { 378 - mask = 0xffff0000; 379 - } 380 - 381 - val = readl(fb->regs + hw_reg) & mask; 382 - writel(val | newval, fb->regs + hw_reg); 383 - } 384 - 385 - return regno > 255; 386 - } 387 - 388 - /* 389 - * Blank the screen if blank_mode != 0, else unblank. If blank == NULL 390 - * then the caller blanks by setting the CLUT (Color Look Up Table) to all 391 - * black. Return 0 if blanking succeeded, != 0 if un-/blanking failed due 392 - * to e.g. a video mode which doesn't support it. Implements VESA suspend 393 - * and powerdown modes on hardware that supports disabling hsync/vsync: 394 - * blank_mode == 2: suspend vsync 395 - * blank_mode == 3: suspend hsync 396 - * blank_mode == 4: powerdown 397 - */ 398 - static int clcdfb_blank(int blank_mode, struct fb_info *info) 399 - { 400 - struct clcd_fb *fb = to_clcd(info); 401 - 402 - if (blank_mode != 0) { 403 - clcdfb_disable(fb); 404 - } else { 405 - clcdfb_enable(fb, fb->clcd_cntl); 406 - } 407 - return 0; 408 - } 409 - 410 - static int clcdfb_mmap(struct fb_info *info, 411 - struct vm_area_struct *vma) 412 - { 413 - struct clcd_fb *fb = to_clcd(info); 414 - unsigned long len, off = vma->vm_pgoff << PAGE_SHIFT; 415 - int ret = -EINVAL; 416 - 417 - len = info->fix.smem_len; 418 - 419 - if (off <= len && vma->vm_end - vma->vm_start <= len - off && 420 - fb->board->mmap) 421 - ret = fb->board->mmap(fb, vma); 422 - 423 - return ret; 424 - } 425 - 426 - static const struct fb_ops clcdfb_ops = { 427 - .owner = THIS_MODULE, 428 - .fb_check_var = clcdfb_check_var, 429 - .fb_set_par = clcdfb_set_par, 430 - .fb_setcolreg = clcdfb_setcolreg, 431 - .fb_blank = clcdfb_blank, 432 - .fb_fillrect = cfb_fillrect, 433 - .fb_copyarea = cfb_copyarea, 434 - .fb_imageblit = cfb_imageblit, 435 - .fb_mmap = clcdfb_mmap, 436 - }; 437 - 438 - static int clcdfb_register(struct clcd_fb *fb) 439 - { 440 - int ret; 441 - 442 - /* 443 - * ARM PL111 always has IENB at 0x1c; it's only PL110 444 - * which is reversed on some platforms. 445 - */ 446 - if (amba_manf(fb->dev) == 0x41 && amba_part(fb->dev) == 0x111) { 447 - fb->off_ienb = CLCD_PL111_IENB; 448 - fb->off_cntl = CLCD_PL111_CNTL; 449 - } else { 450 - fb->off_ienb = CLCD_PL110_IENB; 451 - fb->off_cntl = CLCD_PL110_CNTL; 452 - } 453 - 454 - fb->clk = clk_get(&fb->dev->dev, NULL); 455 - if (IS_ERR(fb->clk)) { 456 - ret = PTR_ERR(fb->clk); 457 - goto out; 458 - } 459 - 460 - ret = clk_prepare(fb->clk); 461 - if (ret) 462 - goto free_clk; 463 - 464 - fb->fb.device = &fb->dev->dev; 465 - 466 - fb->fb.fix.mmio_start = fb->dev->res.start; 467 - fb->fb.fix.mmio_len = resource_size(&fb->dev->res); 468 - 469 - fb->regs = ioremap(fb->fb.fix.mmio_start, fb->fb.fix.mmio_len); 470 - if (!fb->regs) { 471 - printk(KERN_ERR "CLCD: unable to remap registers\n"); 472 - ret = -ENOMEM; 473 - goto clk_unprep; 474 - } 475 - 476 - fb->fb.fbops = &clcdfb_ops; 477 - fb->fb.flags = FBINFO_FLAG_DEFAULT; 478 - fb->fb.pseudo_palette = fb->cmap; 479 - 480 - strncpy(fb->fb.fix.id, clcd_name, sizeof(fb->fb.fix.id)); 481 - fb->fb.fix.type = FB_TYPE_PACKED_PIXELS; 482 - fb->fb.fix.type_aux = 0; 483 - fb->fb.fix.xpanstep = 0; 484 - fb->fb.fix.ypanstep = 0; 485 - fb->fb.fix.ywrapstep = 0; 486 - fb->fb.fix.accel = FB_ACCEL_NONE; 487 - 488 - fb->fb.var.xres = fb->panel->mode.xres; 489 - fb->fb.var.yres = fb->panel->mode.yres; 490 - fb->fb.var.xres_virtual = fb->panel->mode.xres; 491 - fb->fb.var.yres_virtual = fb->panel->mode.yres; 492 - fb->fb.var.bits_per_pixel = fb->panel->bpp; 493 - fb->fb.var.grayscale = fb->panel->grayscale; 494 - fb->fb.var.pixclock = fb->panel->mode.pixclock; 495 - fb->fb.var.left_margin = fb->panel->mode.left_margin; 496 - fb->fb.var.right_margin = fb->panel->mode.right_margin; 497 - fb->fb.var.upper_margin = fb->panel->mode.upper_margin; 498 - fb->fb.var.lower_margin = fb->panel->mode.lower_margin; 499 - fb->fb.var.hsync_len = fb->panel->mode.hsync_len; 500 - fb->fb.var.vsync_len = fb->panel->mode.vsync_len; 501 - fb->fb.var.sync = fb->panel->mode.sync; 502 - fb->fb.var.vmode = fb->panel->mode.vmode; 503 - fb->fb.var.activate = FB_ACTIVATE_NOW; 504 - fb->fb.var.nonstd = 0; 505 - fb->fb.var.height = fb->panel->height; 506 - fb->fb.var.width = fb->panel->width; 507 - fb->fb.var.accel_flags = 0; 508 - 509 - fb->fb.monspecs.hfmin = 0; 510 - fb->fb.monspecs.hfmax = 100000; 511 - fb->fb.monspecs.vfmin = 0; 512 - fb->fb.monspecs.vfmax = 400; 513 - fb->fb.monspecs.dclkmin = 1000000; 514 - fb->fb.monspecs.dclkmax = 100000000; 515 - 516 - /* 517 - * Make sure that the bitfields are set appropriately. 518 - */ 519 - clcdfb_set_bitfields(fb, &fb->fb.var); 520 - 521 - /* 522 - * Allocate colourmap. 523 - */ 524 - ret = fb_alloc_cmap(&fb->fb.cmap, 256, 0); 525 - if (ret) 526 - goto unmap; 527 - 528 - /* 529 - * Ensure interrupts are disabled. 530 - */ 531 - writel(0, fb->regs + fb->off_ienb); 532 - 533 - fb_set_var(&fb->fb, &fb->fb.var); 534 - 535 - dev_info(&fb->dev->dev, "%s hardware, %s display\n", 536 - fb->board->name, fb->panel->mode.name); 537 - 538 - ret = register_framebuffer(&fb->fb); 539 - if (ret == 0) 540 - goto out; 541 - 542 - printk(KERN_ERR "CLCD: cannot register framebuffer (%d)\n", ret); 543 - 544 - fb_dealloc_cmap(&fb->fb.cmap); 545 - unmap: 546 - iounmap(fb->regs); 547 - clk_unprep: 548 - clk_unprepare(fb->clk); 549 - free_clk: 550 - clk_put(fb->clk); 551 - out: 552 - return ret; 553 - } 554 - 555 - #ifdef CONFIG_OF 556 - static int clcdfb_of_get_dpi_panel_mode(struct device_node *node, 557 - struct clcd_panel *clcd_panel) 558 - { 559 - int err; 560 - struct display_timing timing; 561 - struct videomode video; 562 - 563 - err = of_get_display_timing(node, "panel-timing", &timing); 564 - if (err) { 565 - pr_err("%pOF: problems parsing panel-timing (%d)\n", node, err); 566 - return err; 567 - } 568 - 569 - videomode_from_timing(&timing, &video); 570 - 571 - err = fb_videomode_from_videomode(&video, &clcd_panel->mode); 572 - if (err) 573 - return err; 574 - 575 - /* Set up some inversion flags */ 576 - if (timing.flags & DISPLAY_FLAGS_PIXDATA_NEGEDGE) 577 - clcd_panel->tim2 |= TIM2_IPC; 578 - else if (!(timing.flags & DISPLAY_FLAGS_PIXDATA_POSEDGE)) 579 - /* 580 - * To preserve backwards compatibility, the IPC (inverted 581 - * pixel clock) flag needs to be set on any display that 582 - * doesn't explicitly specify that the pixel clock is 583 - * active on the negative or positive edge. 584 - */ 585 - clcd_panel->tim2 |= TIM2_IPC; 586 - 587 - if (timing.flags & DISPLAY_FLAGS_HSYNC_LOW) 588 - clcd_panel->tim2 |= TIM2_IHS; 589 - 590 - if (timing.flags & DISPLAY_FLAGS_VSYNC_LOW) 591 - clcd_panel->tim2 |= TIM2_IVS; 592 - 593 - if (timing.flags & DISPLAY_FLAGS_DE_LOW) 594 - clcd_panel->tim2 |= TIM2_IOE; 595 - 596 - return 0; 597 - } 598 - 599 - static int clcdfb_snprintf_mode(char *buf, int size, struct fb_videomode *mode) 600 - { 601 - return snprintf(buf, size, "%ux%u@%u", mode->xres, mode->yres, 602 - mode->refresh); 603 - } 604 - 605 - static int clcdfb_of_get_backlight(struct device *dev, 606 - struct clcd_panel *clcd_panel) 607 - { 608 - struct backlight_device *backlight; 609 - 610 - /* Look up the optional backlight device */ 611 - backlight = devm_of_find_backlight(dev); 612 - if (IS_ERR(backlight)) 613 - return PTR_ERR(backlight); 614 - 615 - clcd_panel->backlight = backlight; 616 - return 0; 617 - } 618 - 619 - static int clcdfb_of_get_mode(struct device *dev, struct device_node *panel, 620 - struct clcd_panel *clcd_panel) 621 - { 622 - int err; 623 - struct fb_videomode *mode; 624 - char *name; 625 - int len; 626 - 627 - /* Only directly connected DPI panels supported for now */ 628 - if (of_device_is_compatible(panel, "panel-dpi")) 629 - err = clcdfb_of_get_dpi_panel_mode(panel, clcd_panel); 630 - else 631 - err = -ENOENT; 632 - if (err) 633 - return err; 634 - mode = &clcd_panel->mode; 635 - 636 - len = clcdfb_snprintf_mode(NULL, 0, mode); 637 - name = devm_kzalloc(dev, len + 1, GFP_KERNEL); 638 - if (!name) 639 - return -ENOMEM; 640 - 641 - clcdfb_snprintf_mode(name, len + 1, mode); 642 - mode->name = name; 643 - 644 - return 0; 645 - } 646 - 647 - static int clcdfb_of_init_tft_panel(struct clcd_fb *fb, u32 r0, u32 g0, u32 b0) 648 - { 649 - static struct { 650 - unsigned int part; 651 - u32 r0, g0, b0; 652 - u32 caps; 653 - } panels[] = { 654 - { 0x110, 1, 7, 13, CLCD_CAP_5551 }, 655 - { 0x110, 0, 8, 16, CLCD_CAP_888 }, 656 - { 0x110, 16, 8, 0, CLCD_CAP_888 }, 657 - { 0x111, 4, 14, 20, CLCD_CAP_444 }, 658 - { 0x111, 3, 11, 19, CLCD_CAP_444 | CLCD_CAP_5551 }, 659 - { 0x111, 3, 10, 19, CLCD_CAP_444 | CLCD_CAP_5551 | 660 - CLCD_CAP_565 }, 661 - { 0x111, 0, 8, 16, CLCD_CAP_444 | CLCD_CAP_5551 | 662 - CLCD_CAP_565 | CLCD_CAP_888 }, 663 - }; 664 - int i; 665 - 666 - /* Bypass pixel clock divider */ 667 - fb->panel->tim2 |= TIM2_BCD; 668 - 669 - /* TFT display, vert. comp. interrupt at the start of the back porch */ 670 - fb->panel->cntl |= CNTL_LCDTFT | CNTL_LCDVCOMP(1); 671 - 672 - fb->panel->caps = 0; 673 - 674 - /* Match the setup with known variants */ 675 - for (i = 0; i < ARRAY_SIZE(panels) && !fb->panel->caps; i++) { 676 - if (amba_part(fb->dev) != panels[i].part) 677 - continue; 678 - if (g0 != panels[i].g0) 679 - continue; 680 - if (r0 == panels[i].r0 && b0 == panels[i].b0) 681 - fb->panel->caps = panels[i].caps; 682 - } 683 - 684 - /* 685 - * If we actually physically connected the R lines to B and 686 - * vice versa 687 - */ 688 - if (r0 != 0 && b0 == 0) 689 - fb->panel->bgr_connection = true; 690 - 691 - return fb->panel->caps ? 0 : -EINVAL; 692 - } 693 - 694 - static int clcdfb_of_init_display(struct clcd_fb *fb) 695 - { 696 - struct device_node *endpoint, *panel; 697 - int err; 698 - unsigned int bpp; 699 - u32 max_bandwidth; 700 - u32 tft_r0b0g0[3]; 701 - 702 - fb->panel = devm_kzalloc(&fb->dev->dev, sizeof(*fb->panel), GFP_KERNEL); 703 - if (!fb->panel) 704 - return -ENOMEM; 705 - 706 - /* 707 - * Fetch the panel endpoint. 708 - */ 709 - endpoint = of_graph_get_next_endpoint(fb->dev->dev.of_node, NULL); 710 - if (!endpoint) 711 - return -ENODEV; 712 - 713 - panel = of_graph_get_remote_port_parent(endpoint); 714 - if (!panel) 715 - return -ENODEV; 716 - 717 - err = clcdfb_of_get_backlight(&fb->dev->dev, fb->panel); 718 - if (err) 719 - return err; 720 - 721 - err = clcdfb_of_get_mode(&fb->dev->dev, panel, fb->panel); 722 - if (err) 723 - return err; 724 - 725 - err = of_property_read_u32(fb->dev->dev.of_node, "max-memory-bandwidth", 726 - &max_bandwidth); 727 - if (!err) { 728 - /* 729 - * max_bandwidth is in bytes per second and pixclock in 730 - * pico-seconds, so the maximum allowed bits per pixel is 731 - * 8 * max_bandwidth / (PICOS2KHZ(pixclock) * 1000) 732 - * Rearrange this calculation to avoid overflow and then ensure 733 - * result is a valid format. 734 - */ 735 - bpp = max_bandwidth / (1000 / 8) 736 - / PICOS2KHZ(fb->panel->mode.pixclock); 737 - bpp = rounddown_pow_of_two(bpp); 738 - if (bpp > 32) 739 - bpp = 32; 740 - } else 741 - bpp = 32; 742 - fb->panel->bpp = bpp; 743 - 744 - #ifdef CONFIG_CPU_BIG_ENDIAN 745 - fb->panel->cntl |= CNTL_BEBO; 746 - #endif 747 - fb->panel->width = -1; 748 - fb->panel->height = -1; 749 - 750 - if (of_property_read_u32_array(endpoint, 751 - "arm,pl11x,tft-r0g0b0-pads", 752 - tft_r0b0g0, ARRAY_SIZE(tft_r0b0g0)) != 0) 753 - return -ENOENT; 754 - 755 - return clcdfb_of_init_tft_panel(fb, tft_r0b0g0[0], 756 - tft_r0b0g0[1], tft_r0b0g0[2]); 757 - } 758 - 759 - static int clcdfb_of_vram_setup(struct clcd_fb *fb) 760 - { 761 - int err; 762 - struct device_node *memory; 763 - u64 size; 764 - 765 - err = clcdfb_of_init_display(fb); 766 - if (err) 767 - return err; 768 - 769 - memory = of_parse_phandle(fb->dev->dev.of_node, "memory-region", 0); 770 - if (!memory) 771 - return -ENODEV; 772 - 773 - fb->fb.screen_base = of_iomap(memory, 0); 774 - if (!fb->fb.screen_base) 775 - return -ENOMEM; 776 - 777 - fb->fb.fix.smem_start = of_translate_address(memory, 778 - of_get_address(memory, 0, &size, NULL)); 779 - fb->fb.fix.smem_len = size; 780 - 781 - return 0; 782 - } 783 - 784 - static int clcdfb_of_vram_mmap(struct clcd_fb *fb, struct vm_area_struct *vma) 785 - { 786 - unsigned long off, user_size, kernel_size; 787 - 788 - 789 - off = vma->vm_pgoff << PAGE_SHIFT; 790 - user_size = vma->vm_end - vma->vm_start; 791 - kernel_size = fb->fb.fix.smem_len; 792 - 793 - if (off >= kernel_size || user_size > (kernel_size - off)) 794 - return -ENXIO; 795 - 796 - return remap_pfn_range(vma, vma->vm_start, 797 - __phys_to_pfn(fb->fb.fix.smem_start) + vma->vm_pgoff, 798 - user_size, 799 - pgprot_writecombine(vma->vm_page_prot)); 800 - } 801 - 802 - static void clcdfb_of_vram_remove(struct clcd_fb *fb) 803 - { 804 - iounmap(fb->fb.screen_base); 805 - } 806 - 807 - static int clcdfb_of_dma_setup(struct clcd_fb *fb) 808 - { 809 - unsigned long framesize; 810 - dma_addr_t dma; 811 - int err; 812 - 813 - err = clcdfb_of_init_display(fb); 814 - if (err) 815 - return err; 816 - 817 - framesize = PAGE_ALIGN(fb->panel->mode.xres * fb->panel->mode.yres * 818 - fb->panel->bpp / 8); 819 - fb->fb.screen_base = dma_alloc_coherent(&fb->dev->dev, framesize, 820 - &dma, GFP_KERNEL); 821 - if (!fb->fb.screen_base) 822 - return -ENOMEM; 823 - 824 - fb->fb.fix.smem_start = dma; 825 - fb->fb.fix.smem_len = framesize; 826 - 827 - return 0; 828 - } 829 - 830 - static int clcdfb_of_dma_mmap(struct clcd_fb *fb, struct vm_area_struct *vma) 831 - { 832 - return dma_mmap_wc(&fb->dev->dev, vma, fb->fb.screen_base, 833 - fb->fb.fix.smem_start, fb->fb.fix.smem_len); 834 - } 835 - 836 - static void clcdfb_of_dma_remove(struct clcd_fb *fb) 837 - { 838 - dma_free_coherent(&fb->dev->dev, fb->fb.fix.smem_len, 839 - fb->fb.screen_base, fb->fb.fix.smem_start); 840 - } 841 - 842 - static struct clcd_board *clcdfb_of_get_board(struct amba_device *dev) 843 - { 844 - struct clcd_board *board = devm_kzalloc(&dev->dev, sizeof(*board), 845 - GFP_KERNEL); 846 - struct device_node *node = dev->dev.of_node; 847 - 848 - if (!board) 849 - return NULL; 850 - 851 - board->name = of_node_full_name(node); 852 - board->caps = CLCD_CAP_ALL; 853 - board->check = clcdfb_check; 854 - board->decode = clcdfb_decode; 855 - if (of_find_property(node, "memory-region", NULL)) { 856 - board->setup = clcdfb_of_vram_setup; 857 - board->mmap = clcdfb_of_vram_mmap; 858 - board->remove = clcdfb_of_vram_remove; 859 - } else { 860 - board->setup = clcdfb_of_dma_setup; 861 - board->mmap = clcdfb_of_dma_mmap; 862 - board->remove = clcdfb_of_dma_remove; 863 - } 864 - 865 - return board; 866 - } 867 - #else 868 - static struct clcd_board *clcdfb_of_get_board(struct amba_device *dev) 869 - { 870 - return NULL; 871 - } 872 - #endif 873 - 874 - static int clcdfb_probe(struct amba_device *dev, const struct amba_id *id) 875 - { 876 - struct clcd_board *board = dev_get_platdata(&dev->dev); 877 - struct clcd_fb *fb; 878 - int ret; 879 - 880 - if (!board) 881 - board = clcdfb_of_get_board(dev); 882 - 883 - if (!board) 884 - return -EINVAL; 885 - 886 - ret = dma_set_mask_and_coherent(&dev->dev, DMA_BIT_MASK(32)); 887 - if (ret) 888 - goto out; 889 - 890 - ret = amba_request_regions(dev, NULL); 891 - if (ret) { 892 - printk(KERN_ERR "CLCD: unable to reserve regs region\n"); 893 - goto out; 894 - } 895 - 896 - fb = kzalloc(sizeof(*fb), GFP_KERNEL); 897 - if (!fb) { 898 - ret = -ENOMEM; 899 - goto free_region; 900 - } 901 - 902 - fb->dev = dev; 903 - fb->board = board; 904 - 905 - dev_info(&fb->dev->dev, "PL%03x designer %02x rev%u at 0x%08llx\n", 906 - amba_part(dev), amba_manf(dev), amba_rev(dev), 907 - (unsigned long long)dev->res.start); 908 - 909 - ret = fb->board->setup(fb); 910 - if (ret) 911 - goto free_fb; 912 - 913 - ret = clcdfb_register(fb); 914 - if (ret == 0) { 915 - amba_set_drvdata(dev, fb); 916 - goto out; 917 - } 918 - 919 - fb->board->remove(fb); 920 - free_fb: 921 - kfree(fb); 922 - free_region: 923 - amba_release_regions(dev); 924 - out: 925 - return ret; 926 - } 927 - 928 - static int clcdfb_remove(struct amba_device *dev) 929 - { 930 - struct clcd_fb *fb = amba_get_drvdata(dev); 931 - 932 - clcdfb_disable(fb); 933 - unregister_framebuffer(&fb->fb); 934 - if (fb->fb.cmap.len) 935 - fb_dealloc_cmap(&fb->fb.cmap); 936 - iounmap(fb->regs); 937 - clk_unprepare(fb->clk); 938 - clk_put(fb->clk); 939 - 940 - fb->board->remove(fb); 941 - 942 - kfree(fb); 943 - 944 - amba_release_regions(dev); 945 - 946 - return 0; 947 - } 948 - 949 - static const struct amba_id clcdfb_id_table[] = { 950 - { 951 - .id = 0x00041110, 952 - .mask = 0x000ffffe, 953 - }, 954 - { 0, 0 }, 955 - }; 956 - 957 - MODULE_DEVICE_TABLE(amba, clcdfb_id_table); 958 - 959 - static struct amba_driver clcd_driver = { 960 - .drv = { 961 - .name = "clcd-pl11x", 962 - }, 963 - .probe = clcdfb_probe, 964 - .remove = clcdfb_remove, 965 - .id_table = clcdfb_id_table, 966 - }; 967 - 968 - static int __init amba_clcdfb_init(void) 969 - { 970 - if (fb_get_options("ambafb", NULL)) 971 - return -ENODEV; 972 - 973 - return amba_driver_register(&clcd_driver); 974 - } 975 - 976 - module_init(amba_clcdfb_init); 977 - 978 - static void __exit amba_clcdfb_exit(void) 979 - { 980 - amba_driver_unregister(&clcd_driver); 981 - } 982 - 983 - module_exit(amba_clcdfb_exit); 984 - 985 - MODULE_DESCRIPTION("ARM PrimeCell PL110 CLCD core driver"); 986 - MODULE_LICENSE("GPL");
-290
include/linux/amba/clcd.h
··· 1 - /* 2 - * linux/include/asm-arm/hardware/amba_clcd.h -- Integrator LCD panel. 3 - * 4 - * David A Rusling 5 - * 6 - * Copyright (C) 2001 ARM Limited 7 - * 8 - * This file is subject to the terms and conditions of the GNU General Public 9 - * License. See the file COPYING in the main directory of this archive 10 - * for more details. 11 - */ 12 - #include <linux/fb.h> 13 - #include <linux/amba/clcd-regs.h> 14 - 15 - enum { 16 - /* individual formats */ 17 - CLCD_CAP_RGB444 = (1 << 0), 18 - CLCD_CAP_RGB5551 = (1 << 1), 19 - CLCD_CAP_RGB565 = (1 << 2), 20 - CLCD_CAP_RGB888 = (1 << 3), 21 - CLCD_CAP_BGR444 = (1 << 4), 22 - CLCD_CAP_BGR5551 = (1 << 5), 23 - CLCD_CAP_BGR565 = (1 << 6), 24 - CLCD_CAP_BGR888 = (1 << 7), 25 - 26 - /* connection layouts */ 27 - CLCD_CAP_444 = CLCD_CAP_RGB444 | CLCD_CAP_BGR444, 28 - CLCD_CAP_5551 = CLCD_CAP_RGB5551 | CLCD_CAP_BGR5551, 29 - CLCD_CAP_565 = CLCD_CAP_RGB565 | CLCD_CAP_BGR565, 30 - CLCD_CAP_888 = CLCD_CAP_RGB888 | CLCD_CAP_BGR888, 31 - 32 - /* red/blue ordering */ 33 - CLCD_CAP_RGB = CLCD_CAP_RGB444 | CLCD_CAP_RGB5551 | 34 - CLCD_CAP_RGB565 | CLCD_CAP_RGB888, 35 - CLCD_CAP_BGR = CLCD_CAP_BGR444 | CLCD_CAP_BGR5551 | 36 - CLCD_CAP_BGR565 | CLCD_CAP_BGR888, 37 - 38 - CLCD_CAP_ALL = CLCD_CAP_BGR | CLCD_CAP_RGB, 39 - }; 40 - 41 - struct backlight_device; 42 - 43 - struct clcd_panel { 44 - struct fb_videomode mode; 45 - signed short width; /* width in mm */ 46 - signed short height; /* height in mm */ 47 - u32 tim2; 48 - u32 tim3; 49 - u32 cntl; 50 - u32 caps; 51 - unsigned int bpp:8, 52 - fixedtimings:1, 53 - grayscale:1; 54 - unsigned int connector; 55 - struct backlight_device *backlight; 56 - /* 57 - * If the B/R lines are switched between the CLCD 58 - * and the panel we need to know this and not try to 59 - * compensate with the BGR bit in the control register. 60 - */ 61 - bool bgr_connection; 62 - }; 63 - 64 - struct clcd_regs { 65 - u32 tim0; 66 - u32 tim1; 67 - u32 tim2; 68 - u32 tim3; 69 - u32 cntl; 70 - unsigned long pixclock; 71 - }; 72 - 73 - struct clcd_fb; 74 - 75 - /* 76 - * the board-type specific routines 77 - */ 78 - struct clcd_board { 79 - const char *name; 80 - 81 - /* 82 - * Optional. Hardware capability flags. 83 - */ 84 - u32 caps; 85 - 86 - /* 87 - * Optional. Check whether the var structure is acceptable 88 - * for this display. 89 - */ 90 - int (*check)(struct clcd_fb *fb, struct fb_var_screeninfo *var); 91 - 92 - /* 93 - * Compulsory. Decode fb->fb.var into regs->*. In the case of 94 - * fixed timing, set regs->* to the register values required. 95 - */ 96 - void (*decode)(struct clcd_fb *fb, struct clcd_regs *regs); 97 - 98 - /* 99 - * Optional. Disable any extra display hardware. 100 - */ 101 - void (*disable)(struct clcd_fb *); 102 - 103 - /* 104 - * Optional. Enable any extra display hardware. 105 - */ 106 - void (*enable)(struct clcd_fb *); 107 - 108 - /* 109 - * Setup platform specific parts of CLCD driver 110 - */ 111 - int (*setup)(struct clcd_fb *); 112 - 113 - /* 114 - * mmap the framebuffer memory 115 - */ 116 - int (*mmap)(struct clcd_fb *, struct vm_area_struct *); 117 - 118 - /* 119 - * Remove platform specific parts of CLCD driver 120 - */ 121 - void (*remove)(struct clcd_fb *); 122 - }; 123 - 124 - struct amba_device; 125 - struct clk; 126 - 127 - /* this data structure describes each frame buffer device we find */ 128 - struct clcd_fb { 129 - struct fb_info fb; 130 - struct amba_device *dev; 131 - struct clk *clk; 132 - struct clcd_panel *panel; 133 - struct clcd_board *board; 134 - void *board_data; 135 - void __iomem *regs; 136 - u16 off_ienb; 137 - u16 off_cntl; 138 - u32 clcd_cntl; 139 - u32 cmap[16]; 140 - bool clk_enabled; 141 - }; 142 - 143 - static inline void clcdfb_decode(struct clcd_fb *fb, struct clcd_regs *regs) 144 - { 145 - struct fb_var_screeninfo *var = &fb->fb.var; 146 - u32 val, cpl; 147 - 148 - /* 149 - * Program the CLCD controller registers and start the CLCD 150 - */ 151 - val = ((var->xres / 16) - 1) << 2; 152 - val |= (var->hsync_len - 1) << 8; 153 - val |= (var->right_margin - 1) << 16; 154 - val |= (var->left_margin - 1) << 24; 155 - regs->tim0 = val; 156 - 157 - val = var->yres; 158 - if (fb->panel->cntl & CNTL_LCDDUAL) 159 - val /= 2; 160 - val -= 1; 161 - val |= (var->vsync_len - 1) << 10; 162 - val |= var->lower_margin << 16; 163 - val |= var->upper_margin << 24; 164 - regs->tim1 = val; 165 - 166 - val = fb->panel->tim2; 167 - val |= var->sync & FB_SYNC_HOR_HIGH_ACT ? 0 : TIM2_IHS; 168 - val |= var->sync & FB_SYNC_VERT_HIGH_ACT ? 0 : TIM2_IVS; 169 - 170 - cpl = var->xres_virtual; 171 - if (fb->panel->cntl & CNTL_LCDTFT) /* TFT */ 172 - /* / 1 */; 173 - else if (!var->grayscale) /* STN color */ 174 - cpl = cpl * 8 / 3; 175 - else if (fb->panel->cntl & CNTL_LCDMONO8) /* STN monochrome, 8bit */ 176 - cpl /= 8; 177 - else /* STN monochrome, 4bit */ 178 - cpl /= 4; 179 - 180 - regs->tim2 = val | ((cpl - 1) << 16); 181 - 182 - regs->tim3 = fb->panel->tim3; 183 - 184 - val = fb->panel->cntl; 185 - if (var->grayscale) 186 - val |= CNTL_LCDBW; 187 - 188 - if (fb->panel->caps && fb->board->caps && var->bits_per_pixel >= 16) { 189 - /* 190 - * if board and panel supply capabilities, we can support 191 - * changing BGR/RGB depending on supplied parameters. Here 192 - * we switch to what the framebuffer is providing if need 193 - * be, so if the framebuffer is BGR but the display connection 194 - * is RGB (first case) we switch it around. Vice versa mutatis 195 - * mutandis if the framebuffer is RGB but the display connection 196 - * is BGR, we flip it around. 197 - */ 198 - if (var->red.offset == 0) 199 - val &= ~CNTL_BGR; 200 - else 201 - val |= CNTL_BGR; 202 - if (fb->panel->bgr_connection) 203 - val ^= CNTL_BGR; 204 - } 205 - 206 - switch (var->bits_per_pixel) { 207 - case 1: 208 - val |= CNTL_LCDBPP1; 209 - break; 210 - case 2: 211 - val |= CNTL_LCDBPP2; 212 - break; 213 - case 4: 214 - val |= CNTL_LCDBPP4; 215 - break; 216 - case 8: 217 - val |= CNTL_LCDBPP8; 218 - break; 219 - case 16: 220 - /* 221 - * PL110 cannot choose between 5551 and 565 modes in its 222 - * control register. It is possible to use 565 with 223 - * custom external wiring. 224 - */ 225 - if (amba_part(fb->dev) == 0x110 || 226 - var->green.length == 5) 227 - val |= CNTL_LCDBPP16; 228 - else if (var->green.length == 6) 229 - val |= CNTL_LCDBPP16_565; 230 - else 231 - val |= CNTL_LCDBPP16_444; 232 - break; 233 - case 32: 234 - val |= CNTL_LCDBPP24; 235 - break; 236 - } 237 - 238 - regs->cntl = val; 239 - regs->pixclock = var->pixclock; 240 - } 241 - 242 - static inline int clcdfb_check(struct clcd_fb *fb, struct fb_var_screeninfo *var) 243 - { 244 - var->xres_virtual = var->xres = (var->xres + 15) & ~15; 245 - var->yres_virtual = var->yres = (var->yres + 1) & ~1; 246 - 247 - #define CHECK(e,l,h) (var->e < l || var->e > h) 248 - if (CHECK(right_margin, (5+1), 256) || /* back porch */ 249 - CHECK(left_margin, (5+1), 256) || /* front porch */ 250 - CHECK(hsync_len, (5+1), 256) || 251 - var->xres > 4096 || 252 - var->lower_margin > 255 || /* back porch */ 253 - var->upper_margin > 255 || /* front porch */ 254 - var->vsync_len > 32 || 255 - var->yres > 1024) 256 - return -EINVAL; 257 - #undef CHECK 258 - 259 - /* single panel mode: PCD = max(PCD, 1) */ 260 - /* dual panel mode: PCD = max(PCD, 5) */ 261 - 262 - /* 263 - * You can't change the grayscale setting, and 264 - * we can only do non-interlaced video. 265 - */ 266 - if (var->grayscale != fb->fb.var.grayscale || 267 - (var->vmode & FB_VMODE_MASK) != FB_VMODE_NONINTERLACED) 268 - return -EINVAL; 269 - 270 - #define CHECK(e) (var->e != fb->fb.var.e) 271 - if (fb->panel->fixedtimings && 272 - (CHECK(xres) || 273 - CHECK(yres) || 274 - CHECK(bits_per_pixel) || 275 - CHECK(pixclock) || 276 - CHECK(left_margin) || 277 - CHECK(right_margin) || 278 - CHECK(upper_margin) || 279 - CHECK(lower_margin) || 280 - CHECK(hsync_len) || 281 - CHECK(vsync_len) || 282 - CHECK(sync))) 283 - return -EINVAL; 284 - #undef CHECK 285 - 286 - var->nonstd = 0; 287 - var->accel_flags = 0; 288 - 289 - return 0; 290 - }