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/mm.h> 21 #include <linux/fb.h> 22 #include <linux/init.h> 23 #include <linux/ioport.h> 24 #include <linux/list.h> 25 #include <linux/amba/bus.h> 26 #include <linux/amba/clcd.h> 27 #include <linux/clk.h> 28 #include <linux/hardirq.h> 29 30 #include <asm/sizes.h> 31 32 #define to_clcd(info) container_of(info, struct clcd_fb, fb) 33 34 /* This is limited to 16 characters when displayed by X startup */ 35 static const char *clcd_name = "CLCD FB"; 36 37 /* 38 * Unfortunately, the enable/disable functions may be called either from 39 * process or IRQ context, and we _need_ to delay. This is _not_ good. 40 */ 41 static inline void clcdfb_sleep(unsigned int ms) 42 { 43 if (in_atomic()) { 44 mdelay(ms); 45 } else { 46 msleep(ms); 47 } 48 } 49 50 static inline void clcdfb_set_start(struct clcd_fb *fb) 51 { 52 unsigned long ustart = fb->fb.fix.smem_start; 53 unsigned long lstart; 54 55 ustart += fb->fb.var.yoffset * fb->fb.fix.line_length; 56 lstart = ustart + fb->fb.var.yres * fb->fb.fix.line_length / 2; 57 58 writel(ustart, fb->regs + CLCD_UBAS); 59 writel(lstart, fb->regs + CLCD_LBAS); 60 } 61 62 static void clcdfb_disable(struct clcd_fb *fb) 63 { 64 u32 val; 65 66 if (fb->board->disable) 67 fb->board->disable(fb); 68 69 val = readl(fb->regs + fb->off_cntl); 70 if (val & CNTL_LCDPWR) { 71 val &= ~CNTL_LCDPWR; 72 writel(val, fb->regs + fb->off_cntl); 73 74 clcdfb_sleep(20); 75 } 76 if (val & CNTL_LCDEN) { 77 val &= ~CNTL_LCDEN; 78 writel(val, fb->regs + fb->off_cntl); 79 } 80 81 /* 82 * Disable CLCD clock source. 83 */ 84 if (fb->clk_enabled) { 85 fb->clk_enabled = false; 86 clk_disable(fb->clk); 87 } 88 } 89 90 static void clcdfb_enable(struct clcd_fb *fb, u32 cntl) 91 { 92 /* 93 * Enable the CLCD clock source. 94 */ 95 if (!fb->clk_enabled) { 96 fb->clk_enabled = true; 97 clk_enable(fb->clk); 98 } 99 100 /* 101 * Bring up by first enabling.. 102 */ 103 cntl |= CNTL_LCDEN; 104 writel(cntl, fb->regs + fb->off_cntl); 105 106 clcdfb_sleep(20); 107 108 /* 109 * and now apply power. 110 */ 111 cntl |= CNTL_LCDPWR; 112 writel(cntl, fb->regs + fb->off_cntl); 113 114 /* 115 * finally, enable the interface. 116 */ 117 if (fb->board->enable) 118 fb->board->enable(fb); 119 } 120 121 static int 122 clcdfb_set_bitfields(struct clcd_fb *fb, struct fb_var_screeninfo *var) 123 { 124 u32 caps; 125 int ret = 0; 126 127 if (fb->panel->caps && fb->board->caps) 128 caps = fb->panel->caps & fb->board->caps; 129 else { 130 /* Old way of specifying what can be used */ 131 caps = fb->panel->cntl & CNTL_BGR ? 132 CLCD_CAP_BGR : CLCD_CAP_RGB; 133 /* But mask out 444 modes as they weren't supported */ 134 caps &= ~CLCD_CAP_444; 135 } 136 137 /* Only TFT panels can do RGB888/BGR888 */ 138 if (!(fb->panel->cntl & CNTL_LCDTFT)) 139 caps &= ~CLCD_CAP_888; 140 141 memset(&var->transp, 0, sizeof(var->transp)); 142 143 var->red.msb_right = 0; 144 var->green.msb_right = 0; 145 var->blue.msb_right = 0; 146 147 switch (var->bits_per_pixel) { 148 case 1: 149 case 2: 150 case 4: 151 case 8: 152 /* If we can't do 5551, reject */ 153 caps &= CLCD_CAP_5551; 154 if (!caps) { 155 ret = -EINVAL; 156 break; 157 } 158 159 var->red.length = var->bits_per_pixel; 160 var->red.offset = 0; 161 var->green.length = var->bits_per_pixel; 162 var->green.offset = 0; 163 var->blue.length = var->bits_per_pixel; 164 var->blue.offset = 0; 165 break; 166 167 case 16: 168 /* If we can't do 444, 5551 or 565, reject */ 169 if (!(caps & (CLCD_CAP_444 | CLCD_CAP_5551 | CLCD_CAP_565))) { 170 ret = -EINVAL; 171 break; 172 } 173 174 /* 175 * Green length can be 4, 5 or 6 depending whether 176 * we're operating in 444, 5551 or 565 mode. 177 */ 178 if (var->green.length == 4 && caps & CLCD_CAP_444) 179 caps &= CLCD_CAP_444; 180 if (var->green.length == 5 && caps & CLCD_CAP_5551) 181 caps &= CLCD_CAP_5551; 182 else if (var->green.length == 6 && caps & CLCD_CAP_565) 183 caps &= CLCD_CAP_565; 184 else { 185 /* 186 * PL110 officially only supports RGB555, 187 * but may be wired up to allow RGB565. 188 */ 189 if (caps & CLCD_CAP_565) { 190 var->green.length = 6; 191 caps &= CLCD_CAP_565; 192 } else if (caps & CLCD_CAP_5551) { 193 var->green.length = 5; 194 caps &= CLCD_CAP_5551; 195 } else { 196 var->green.length = 4; 197 caps &= CLCD_CAP_444; 198 } 199 } 200 201 if (var->green.length >= 5) { 202 var->red.length = 5; 203 var->blue.length = 5; 204 } else { 205 var->red.length = 4; 206 var->blue.length = 4; 207 } 208 break; 209 case 32: 210 /* If we can't do 888, reject */ 211 caps &= CLCD_CAP_888; 212 if (!caps) { 213 ret = -EINVAL; 214 break; 215 } 216 217 var->red.length = 8; 218 var->green.length = 8; 219 var->blue.length = 8; 220 break; 221 default: 222 ret = -EINVAL; 223 break; 224 } 225 226 /* 227 * >= 16bpp displays have separate colour component bitfields 228 * encoded in the pixel data. Calculate their position from 229 * the bitfield length defined above. 230 */ 231 if (ret == 0 && var->bits_per_pixel >= 16) { 232 bool bgr, rgb; 233 234 bgr = caps & CLCD_CAP_BGR && var->blue.offset == 0; 235 rgb = caps & CLCD_CAP_RGB && var->red.offset == 0; 236 237 if (!bgr && !rgb) 238 /* 239 * The requested format was not possible, try just 240 * our capabilities. One of BGR or RGB must be 241 * supported. 242 */ 243 bgr = caps & CLCD_CAP_BGR; 244 245 if (bgr) { 246 var->blue.offset = 0; 247 var->green.offset = var->blue.offset + var->blue.length; 248 var->red.offset = var->green.offset + var->green.length; 249 } else { 250 var->red.offset = 0; 251 var->green.offset = var->red.offset + var->red.length; 252 var->blue.offset = var->green.offset + var->green.length; 253 } 254 } 255 256 return ret; 257 } 258 259 static int clcdfb_check_var(struct fb_var_screeninfo *var, struct fb_info *info) 260 { 261 struct clcd_fb *fb = to_clcd(info); 262 int ret = -EINVAL; 263 264 if (fb->board->check) 265 ret = fb->board->check(fb, var); 266 267 if (ret == 0 && 268 var->xres_virtual * var->bits_per_pixel / 8 * 269 var->yres_virtual > fb->fb.fix.smem_len) 270 ret = -EINVAL; 271 272 if (ret == 0) 273 ret = clcdfb_set_bitfields(fb, var); 274 275 return ret; 276 } 277 278 static int clcdfb_set_par(struct fb_info *info) 279 { 280 struct clcd_fb *fb = to_clcd(info); 281 struct clcd_regs regs; 282 283 fb->fb.fix.line_length = fb->fb.var.xres_virtual * 284 fb->fb.var.bits_per_pixel / 8; 285 286 if (fb->fb.var.bits_per_pixel <= 8) 287 fb->fb.fix.visual = FB_VISUAL_PSEUDOCOLOR; 288 else 289 fb->fb.fix.visual = FB_VISUAL_TRUECOLOR; 290 291 fb->board->decode(fb, ®s); 292 293 clcdfb_disable(fb); 294 295 writel(regs.tim0, fb->regs + CLCD_TIM0); 296 writel(regs.tim1, fb->regs + CLCD_TIM1); 297 writel(regs.tim2, fb->regs + CLCD_TIM2); 298 writel(regs.tim3, fb->regs + CLCD_TIM3); 299 300 clcdfb_set_start(fb); 301 302 clk_set_rate(fb->clk, (1000000000 / regs.pixclock) * 1000); 303 304 fb->clcd_cntl = regs.cntl; 305 306 clcdfb_enable(fb, regs.cntl); 307 308 #ifdef DEBUG 309 printk(KERN_INFO 310 "CLCD: Registers set to\n" 311 " %08x %08x %08x %08x\n" 312 " %08x %08x %08x %08x\n", 313 readl(fb->regs + CLCD_TIM0), readl(fb->regs + CLCD_TIM1), 314 readl(fb->regs + CLCD_TIM2), readl(fb->regs + CLCD_TIM3), 315 readl(fb->regs + CLCD_UBAS), readl(fb->regs + CLCD_LBAS), 316 readl(fb->regs + fb->off_ienb), readl(fb->regs + fb->off_cntl)); 317 #endif 318 319 return 0; 320 } 321 322 static inline u32 convert_bitfield(int val, struct fb_bitfield *bf) 323 { 324 unsigned int mask = (1 << bf->length) - 1; 325 326 return (val >> (16 - bf->length) & mask) << bf->offset; 327 } 328 329 /* 330 * Set a single color register. The values supplied have a 16 bit 331 * magnitude. Return != 0 for invalid regno. 332 */ 333 static int 334 clcdfb_setcolreg(unsigned int regno, unsigned int red, unsigned int green, 335 unsigned int blue, unsigned int transp, struct fb_info *info) 336 { 337 struct clcd_fb *fb = to_clcd(info); 338 339 if (regno < 16) 340 fb->cmap[regno] = convert_bitfield(transp, &fb->fb.var.transp) | 341 convert_bitfield(blue, &fb->fb.var.blue) | 342 convert_bitfield(green, &fb->fb.var.green) | 343 convert_bitfield(red, &fb->fb.var.red); 344 345 if (fb->fb.fix.visual == FB_VISUAL_PSEUDOCOLOR && regno < 256) { 346 int hw_reg = CLCD_PALETTE + ((regno * 2) & ~3); 347 u32 val, mask, newval; 348 349 newval = (red >> 11) & 0x001f; 350 newval |= (green >> 6) & 0x03e0; 351 newval |= (blue >> 1) & 0x7c00; 352 353 /* 354 * 3.2.11: if we're configured for big endian 355 * byte order, the palette entries are swapped. 356 */ 357 if (fb->clcd_cntl & CNTL_BEBO) 358 regno ^= 1; 359 360 if (regno & 1) { 361 newval <<= 16; 362 mask = 0x0000ffff; 363 } else { 364 mask = 0xffff0000; 365 } 366 367 val = readl(fb->regs + hw_reg) & mask; 368 writel(val | newval, fb->regs + hw_reg); 369 } 370 371 return regno > 255; 372 } 373 374 /* 375 * Blank the screen if blank_mode != 0, else unblank. If blank == NULL 376 * then the caller blanks by setting the CLUT (Color Look Up Table) to all 377 * black. Return 0 if blanking succeeded, != 0 if un-/blanking failed due 378 * to e.g. a video mode which doesn't support it. Implements VESA suspend 379 * and powerdown modes on hardware that supports disabling hsync/vsync: 380 * blank_mode == 2: suspend vsync 381 * blank_mode == 3: suspend hsync 382 * blank_mode == 4: powerdown 383 */ 384 static int clcdfb_blank(int blank_mode, struct fb_info *info) 385 { 386 struct clcd_fb *fb = to_clcd(info); 387 388 if (blank_mode != 0) { 389 clcdfb_disable(fb); 390 } else { 391 clcdfb_enable(fb, fb->clcd_cntl); 392 } 393 return 0; 394 } 395 396 static int clcdfb_mmap(struct fb_info *info, 397 struct vm_area_struct *vma) 398 { 399 struct clcd_fb *fb = to_clcd(info); 400 unsigned long len, off = vma->vm_pgoff << PAGE_SHIFT; 401 int ret = -EINVAL; 402 403 len = info->fix.smem_len; 404 405 if (off <= len && vma->vm_end - vma->vm_start <= len - off && 406 fb->board->mmap) 407 ret = fb->board->mmap(fb, vma); 408 409 return ret; 410 } 411 412 static struct fb_ops clcdfb_ops = { 413 .owner = THIS_MODULE, 414 .fb_check_var = clcdfb_check_var, 415 .fb_set_par = clcdfb_set_par, 416 .fb_setcolreg = clcdfb_setcolreg, 417 .fb_blank = clcdfb_blank, 418 .fb_fillrect = cfb_fillrect, 419 .fb_copyarea = cfb_copyarea, 420 .fb_imageblit = cfb_imageblit, 421 .fb_mmap = clcdfb_mmap, 422 }; 423 424 static int clcdfb_register(struct clcd_fb *fb) 425 { 426 int ret; 427 428 /* 429 * ARM PL111 always has IENB at 0x1c; it's only PL110 430 * which is reversed on some platforms. 431 */ 432 if (amba_manf(fb->dev) == 0x41 && amba_part(fb->dev) == 0x111) { 433 fb->off_ienb = CLCD_PL111_IENB; 434 fb->off_cntl = CLCD_PL111_CNTL; 435 } else { 436 #ifdef CONFIG_ARCH_VERSATILE 437 fb->off_ienb = CLCD_PL111_IENB; 438 fb->off_cntl = CLCD_PL111_CNTL; 439 #else 440 fb->off_ienb = CLCD_PL110_IENB; 441 fb->off_cntl = CLCD_PL110_CNTL; 442 #endif 443 } 444 445 fb->clk = clk_get(&fb->dev->dev, NULL); 446 if (IS_ERR(fb->clk)) { 447 ret = PTR_ERR(fb->clk); 448 goto out; 449 } 450 451 ret = clk_prepare(fb->clk); 452 if (ret) 453 goto free_clk; 454 455 fb->fb.device = &fb->dev->dev; 456 457 fb->fb.fix.mmio_start = fb->dev->res.start; 458 fb->fb.fix.mmio_len = resource_size(&fb->dev->res); 459 460 fb->regs = ioremap(fb->fb.fix.mmio_start, fb->fb.fix.mmio_len); 461 if (!fb->regs) { 462 printk(KERN_ERR "CLCD: unable to remap registers\n"); 463 ret = -ENOMEM; 464 goto clk_unprep; 465 } 466 467 fb->fb.fbops = &clcdfb_ops; 468 fb->fb.flags = FBINFO_FLAG_DEFAULT; 469 fb->fb.pseudo_palette = fb->cmap; 470 471 strncpy(fb->fb.fix.id, clcd_name, sizeof(fb->fb.fix.id)); 472 fb->fb.fix.type = FB_TYPE_PACKED_PIXELS; 473 fb->fb.fix.type_aux = 0; 474 fb->fb.fix.xpanstep = 0; 475 fb->fb.fix.ypanstep = 0; 476 fb->fb.fix.ywrapstep = 0; 477 fb->fb.fix.accel = FB_ACCEL_NONE; 478 479 fb->fb.var.xres = fb->panel->mode.xres; 480 fb->fb.var.yres = fb->panel->mode.yres; 481 fb->fb.var.xres_virtual = fb->panel->mode.xres; 482 fb->fb.var.yres_virtual = fb->panel->mode.yres; 483 fb->fb.var.bits_per_pixel = fb->panel->bpp; 484 fb->fb.var.grayscale = fb->panel->grayscale; 485 fb->fb.var.pixclock = fb->panel->mode.pixclock; 486 fb->fb.var.left_margin = fb->panel->mode.left_margin; 487 fb->fb.var.right_margin = fb->panel->mode.right_margin; 488 fb->fb.var.upper_margin = fb->panel->mode.upper_margin; 489 fb->fb.var.lower_margin = fb->panel->mode.lower_margin; 490 fb->fb.var.hsync_len = fb->panel->mode.hsync_len; 491 fb->fb.var.vsync_len = fb->panel->mode.vsync_len; 492 fb->fb.var.sync = fb->panel->mode.sync; 493 fb->fb.var.vmode = fb->panel->mode.vmode; 494 fb->fb.var.activate = FB_ACTIVATE_NOW; 495 fb->fb.var.nonstd = 0; 496 fb->fb.var.height = fb->panel->height; 497 fb->fb.var.width = fb->panel->width; 498 fb->fb.var.accel_flags = 0; 499 500 fb->fb.monspecs.hfmin = 0; 501 fb->fb.monspecs.hfmax = 100000; 502 fb->fb.monspecs.vfmin = 0; 503 fb->fb.monspecs.vfmax = 400; 504 fb->fb.monspecs.dclkmin = 1000000; 505 fb->fb.monspecs.dclkmax = 100000000; 506 507 /* 508 * Make sure that the bitfields are set appropriately. 509 */ 510 clcdfb_set_bitfields(fb, &fb->fb.var); 511 512 /* 513 * Allocate colourmap. 514 */ 515 ret = fb_alloc_cmap(&fb->fb.cmap, 256, 0); 516 if (ret) 517 goto unmap; 518 519 /* 520 * Ensure interrupts are disabled. 521 */ 522 writel(0, fb->regs + fb->off_ienb); 523 524 fb_set_var(&fb->fb, &fb->fb.var); 525 526 dev_info(&fb->dev->dev, "%s hardware, %s display\n", 527 fb->board->name, fb->panel->mode.name); 528 529 ret = register_framebuffer(&fb->fb); 530 if (ret == 0) 531 goto out; 532 533 printk(KERN_ERR "CLCD: cannot register framebuffer (%d)\n", ret); 534 535 fb_dealloc_cmap(&fb->fb.cmap); 536 unmap: 537 iounmap(fb->regs); 538 clk_unprep: 539 clk_unprepare(fb->clk); 540 free_clk: 541 clk_put(fb->clk); 542 out: 543 return ret; 544 } 545 546 static int clcdfb_probe(struct amba_device *dev, const struct amba_id *id) 547 { 548 struct clcd_board *board = dev_get_platdata(&dev->dev); 549 struct clcd_fb *fb; 550 int ret; 551 552 if (!board) 553 return -EINVAL; 554 555 ret = dma_set_mask_and_coherent(&dev->dev, DMA_BIT_MASK(32)); 556 if (ret) 557 goto out; 558 559 ret = amba_request_regions(dev, NULL); 560 if (ret) { 561 printk(KERN_ERR "CLCD: unable to reserve regs region\n"); 562 goto out; 563 } 564 565 fb = kzalloc(sizeof(struct clcd_fb), GFP_KERNEL); 566 if (!fb) { 567 printk(KERN_INFO "CLCD: could not allocate new clcd_fb struct\n"); 568 ret = -ENOMEM; 569 goto free_region; 570 } 571 572 fb->dev = dev; 573 fb->board = board; 574 575 dev_info(&fb->dev->dev, "PL%03x rev%u at 0x%08llx\n", 576 amba_part(dev), amba_rev(dev), 577 (unsigned long long)dev->res.start); 578 579 ret = fb->board->setup(fb); 580 if (ret) 581 goto free_fb; 582 583 ret = clcdfb_register(fb); 584 if (ret == 0) { 585 amba_set_drvdata(dev, fb); 586 goto out; 587 } 588 589 fb->board->remove(fb); 590 free_fb: 591 kfree(fb); 592 free_region: 593 amba_release_regions(dev); 594 out: 595 return ret; 596 } 597 598 static int clcdfb_remove(struct amba_device *dev) 599 { 600 struct clcd_fb *fb = amba_get_drvdata(dev); 601 602 clcdfb_disable(fb); 603 unregister_framebuffer(&fb->fb); 604 if (fb->fb.cmap.len) 605 fb_dealloc_cmap(&fb->fb.cmap); 606 iounmap(fb->regs); 607 clk_unprepare(fb->clk); 608 clk_put(fb->clk); 609 610 fb->board->remove(fb); 611 612 kfree(fb); 613 614 amba_release_regions(dev); 615 616 return 0; 617 } 618 619 static struct amba_id clcdfb_id_table[] = { 620 { 621 .id = 0x00041110, 622 .mask = 0x000ffffe, 623 }, 624 { 0, 0 }, 625 }; 626 627 MODULE_DEVICE_TABLE(amba, clcdfb_id_table); 628 629 static struct amba_driver clcd_driver = { 630 .drv = { 631 .name = "clcd-pl11x", 632 }, 633 .probe = clcdfb_probe, 634 .remove = clcdfb_remove, 635 .id_table = clcdfb_id_table, 636 }; 637 638 static int __init amba_clcdfb_init(void) 639 { 640 if (fb_get_options("ambafb", NULL)) 641 return -ENODEV; 642 643 return amba_driver_register(&clcd_driver); 644 } 645 646 module_init(amba_clcdfb_init); 647 648 static void __exit amba_clcdfb_exit(void) 649 { 650 amba_driver_unregister(&clcd_driver); 651 } 652 653 module_exit(amba_clcdfb_exit); 654 655 MODULE_DESCRIPTION("ARM PrimeCell PL110 CLCD core driver"); 656 MODULE_LICENSE("GPL"); 657