1 // SPDX-License-Identifier: GPL-2.0-only 2 /* linux/drivers/video/sm501fb.c 3 * 4 * Copyright (c) 2006 Simtec Electronics 5 * Vincent Sanders <vince@simtec.co.uk> 6 * Ben Dooks <ben@simtec.co.uk> 7 * 8 * Framebuffer driver for the Silicon Motion SM501 9 */ 10 11 #include <linux/module.h> 12 #include <linux/kernel.h> 13 #include <linux/errno.h> 14 #include <linux/string.h> 15 #include <linux/mm.h> 16 #include <linux/tty.h> 17 #include <linux/slab.h> 18 #include <linux/delay.h> 19 #include <linux/fb.h> 20 #include <linux/init.h> 21 #include <linux/vmalloc.h> 22 #include <linux/dma-mapping.h> 23 #include <linux/interrupt.h> 24 #include <linux/workqueue.h> 25 #include <linux/wait.h> 26 #include <linux/platform_device.h> 27 #include <linux/clk.h> 28 #include <linux/console.h> 29 #include <linux/io.h> 30 #include <linux/string_choices.h> 31 32 #include <linux/uaccess.h> 33 #include <asm/div64.h> 34 35 #ifdef CONFIG_PM 36 #include <linux/pm.h> 37 #endif 38 39 #include <linux/sm501.h> 40 #include <linux/sm501-regs.h> 41 42 #include "edid.h" 43 44 static char *fb_mode = "640x480-16@60"; 45 static unsigned long default_bpp = 16; 46 47 static const struct fb_videomode sm501_default_mode = { 48 .refresh = 60, 49 .xres = 640, 50 .yres = 480, 51 .pixclock = 20833, 52 .left_margin = 142, 53 .right_margin = 13, 54 .upper_margin = 21, 55 .lower_margin = 1, 56 .hsync_len = 69, 57 .vsync_len = 3, 58 .sync = FB_SYNC_HOR_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT, 59 .vmode = FB_VMODE_NONINTERLACED 60 }; 61 62 #define NR_PALETTE 256 63 64 enum sm501_controller { 65 HEAD_CRT = 0, 66 HEAD_PANEL = 1, 67 }; 68 69 /* SM501 memory address. 70 * 71 * This structure is used to track memory usage within the SM501 framebuffer 72 * allocation. The sm_addr field is stored as an offset as it is often used 73 * against both the physical and mapped addresses. 74 */ 75 struct sm501_mem { 76 unsigned long size; 77 unsigned long sm_addr; /* offset from base of sm501 fb. */ 78 void __iomem *k_addr; 79 }; 80 81 /* private data that is shared between all frambuffers* */ 82 struct sm501fb_info { 83 struct device *dev; 84 struct fb_info *fb[2]; /* fb info for both heads */ 85 struct resource *fbmem_res; /* framebuffer resource */ 86 struct resource *regs_res; /* registers resource */ 87 struct resource *regs2d_res; /* 2d registers resource */ 88 struct sm501_platdata_fb *pdata; /* our platform data */ 89 90 unsigned long pm_crt_ctrl; /* pm: crt ctrl save */ 91 92 int irq; 93 int swap_endian; /* set to swap rgb=>bgr */ 94 void __iomem *regs; /* remapped registers */ 95 void __iomem *regs2d; /* 2d remapped registers */ 96 void __iomem *fbmem; /* remapped framebuffer */ 97 size_t fbmem_len; /* length of remapped region */ 98 u8 *edid_data; 99 }; 100 101 /* per-framebuffer private data */ 102 struct sm501fb_par { 103 u32 pseudo_palette[16]; 104 105 enum sm501_controller head; 106 struct sm501_mem cursor; 107 struct sm501_mem screen; 108 struct fb_ops ops; 109 110 void *store_fb; 111 void *store_cursor; 112 void __iomem *cursor_regs; 113 struct sm501fb_info *info; 114 }; 115 116 /* Helper functions */ 117 118 static inline int h_total(struct fb_var_screeninfo *var) 119 { 120 return var->xres + var->left_margin + 121 var->right_margin + var->hsync_len; 122 } 123 124 static inline int v_total(struct fb_var_screeninfo *var) 125 { 126 return var->yres + var->upper_margin + 127 var->lower_margin + var->vsync_len; 128 } 129 130 /* sm501fb_sync_regs() 131 * 132 * This call is mainly for PCI bus systems where we need to 133 * ensure that any writes to the bus are completed before the 134 * next phase, or after completing a function. 135 */ 136 137 static inline void sm501fb_sync_regs(struct sm501fb_info *info) 138 { 139 smc501_readl(info->regs); 140 } 141 142 /* sm501_alloc_mem 143 * 144 * This is an attempt to lay out memory for the two framebuffers and 145 * everything else 146 * 147 * |fbmem_res->start fbmem_res->end| 148 * | | 149 * |fb[0].fix.smem_start | |fb[1].fix.smem_start | 2K | 150 * |-> fb[0].fix.smem_len <-| spare |-> fb[1].fix.smem_len <-|-> cursors <-| 151 * 152 * The "spare" space is for the 2d engine data 153 * the fixed is space for the cursors (2x1Kbyte) 154 * 155 * we need to allocate memory for the 2D acceleration engine 156 * command list and the data for the engine to deal with. 157 * 158 * - all allocations must be 128bit aligned 159 * - cursors are 64x64x2 bits (1Kbyte) 160 * 161 */ 162 163 #define SM501_MEMF_CURSOR (1) 164 #define SM501_MEMF_PANEL (2) 165 #define SM501_MEMF_CRT (4) 166 #define SM501_MEMF_ACCEL (8) 167 168 static int sm501_alloc_mem(struct sm501fb_info *inf, struct sm501_mem *mem, 169 unsigned int why, size_t size, u32 smem_len) 170 { 171 struct sm501fb_par *par; 172 struct fb_info *fbi; 173 unsigned int ptr; 174 unsigned int end; 175 176 switch (why) { 177 case SM501_MEMF_CURSOR: 178 ptr = inf->fbmem_len - size; 179 inf->fbmem_len = ptr; /* adjust available memory. */ 180 break; 181 182 case SM501_MEMF_PANEL: 183 if (size > inf->fbmem_len) 184 return -ENOMEM; 185 186 ptr = inf->fbmem_len - size; 187 fbi = inf->fb[HEAD_CRT]; 188 189 /* round down, some programs such as directfb do not draw 190 * 0,0 correctly unless the start is aligned to a page start. 191 */ 192 193 if (ptr > 0) 194 ptr &= ~(PAGE_SIZE - 1); 195 196 if (fbi && ptr < smem_len) 197 return -ENOMEM; 198 199 break; 200 201 case SM501_MEMF_CRT: 202 ptr = 0; 203 204 /* check to see if we have panel memory allocated 205 * which would put an limit on available memory. */ 206 207 fbi = inf->fb[HEAD_PANEL]; 208 if (fbi) { 209 par = fbi->par; 210 end = par->screen.k_addr ? par->screen.sm_addr : inf->fbmem_len; 211 } else 212 end = inf->fbmem_len; 213 214 if ((ptr + size) > end) 215 return -ENOMEM; 216 217 break; 218 219 case SM501_MEMF_ACCEL: 220 fbi = inf->fb[HEAD_CRT]; 221 ptr = fbi ? smem_len : 0; 222 223 fbi = inf->fb[HEAD_PANEL]; 224 if (fbi) { 225 par = fbi->par; 226 end = par->screen.sm_addr; 227 } else 228 end = inf->fbmem_len; 229 230 if ((ptr + size) > end) 231 return -ENOMEM; 232 233 break; 234 235 default: 236 return -EINVAL; 237 } 238 239 mem->size = size; 240 mem->sm_addr = ptr; 241 mem->k_addr = inf->fbmem + ptr; 242 243 dev_dbg(inf->dev, "%s: result %08lx, %p - %u, %zd\n", 244 __func__, mem->sm_addr, mem->k_addr, why, size); 245 246 return 0; 247 } 248 249 /* sm501fb_ps_to_hz 250 * 251 * Converts a period in picoseconds to Hz. 252 * 253 * Note, we try to keep this in Hz to minimise rounding with 254 * the limited PLL settings on the SM501. 255 */ 256 257 static unsigned long sm501fb_ps_to_hz(unsigned long psvalue) 258 { 259 unsigned long long numerator=1000000000000ULL; 260 261 /* 10^12 / picosecond period gives frequency in Hz */ 262 do_div(numerator, psvalue); 263 return (unsigned long)numerator; 264 } 265 266 /* sm501fb_hz_to_ps is identical to the opposite transform */ 267 268 #define sm501fb_hz_to_ps(x) sm501fb_ps_to_hz(x) 269 270 /* sm501fb_setup_gamma 271 * 272 * Programs a linear 1.0 gamma ramp in case the gamma 273 * correction is enabled without programming anything else. 274 */ 275 276 static void sm501fb_setup_gamma(struct sm501fb_info *fbi, 277 unsigned long palette) 278 { 279 unsigned long value = 0; 280 int offset; 281 282 /* set gamma values */ 283 for (offset = 0; offset < 256 * 4; offset += 4) { 284 smc501_writel(value, fbi->regs + palette + offset); 285 value += 0x010101; /* Advance RGB by 1,1,1.*/ 286 } 287 } 288 289 /* sm501fb_check_var 290 * 291 * check common variables for both panel and crt 292 */ 293 294 static int sm501fb_check_var(struct fb_var_screeninfo *var, 295 struct fb_info *info) 296 { 297 struct sm501fb_par *par = info->par; 298 struct sm501fb_info *sm = par->info; 299 unsigned long tmp; 300 301 /* check we can fit these values into the registers */ 302 303 if (var->hsync_len > 255 || var->vsync_len > 63) 304 return -EINVAL; 305 306 /* hdisplay end and hsync start */ 307 if ((var->xres + var->right_margin) > 4096) 308 return -EINVAL; 309 310 /* vdisplay end and vsync start */ 311 if ((var->yres + var->lower_margin) > 2048) 312 return -EINVAL; 313 314 /* hard limits of device */ 315 316 if (h_total(var) > 4096 || v_total(var) > 2048) 317 return -EINVAL; 318 319 /* check our line length is going to be 128 bit aligned */ 320 321 tmp = (var->xres * var->bits_per_pixel) / 8; 322 if ((tmp & 15) != 0) 323 return -EINVAL; 324 325 /* check the virtual size */ 326 327 if (var->xres_virtual > 4096 || var->yres_virtual > 2048) 328 return -EINVAL; 329 330 /* can cope with 8,16 or 32bpp */ 331 332 if (var->bits_per_pixel <= 8) 333 var->bits_per_pixel = 8; 334 else if (var->bits_per_pixel <= 16) 335 var->bits_per_pixel = 16; 336 else if (var->bits_per_pixel == 24) 337 var->bits_per_pixel = 32; 338 339 /* set r/g/b positions and validate bpp */ 340 switch(var->bits_per_pixel) { 341 case 8: 342 var->red.length = var->bits_per_pixel; 343 var->red.offset = 0; 344 var->green.length = var->bits_per_pixel; 345 var->green.offset = 0; 346 var->blue.length = var->bits_per_pixel; 347 var->blue.offset = 0; 348 var->transp.length = 0; 349 var->transp.offset = 0; 350 351 break; 352 353 case 16: 354 if (sm->pdata->flags & SM501_FBPD_SWAP_FB_ENDIAN) { 355 var->blue.offset = 11; 356 var->green.offset = 5; 357 var->red.offset = 0; 358 } else { 359 var->red.offset = 11; 360 var->green.offset = 5; 361 var->blue.offset = 0; 362 } 363 var->transp.offset = 0; 364 365 var->red.length = 5; 366 var->green.length = 6; 367 var->blue.length = 5; 368 var->transp.length = 0; 369 break; 370 371 case 32: 372 if (sm->pdata->flags & SM501_FBPD_SWAP_FB_ENDIAN) { 373 var->transp.offset = 0; 374 var->red.offset = 8; 375 var->green.offset = 16; 376 var->blue.offset = 24; 377 } else { 378 var->transp.offset = 24; 379 var->red.offset = 16; 380 var->green.offset = 8; 381 var->blue.offset = 0; 382 } 383 384 var->red.length = 8; 385 var->green.length = 8; 386 var->blue.length = 8; 387 var->transp.length = 0; 388 break; 389 390 default: 391 return -EINVAL; 392 } 393 394 return 0; 395 } 396 397 /* 398 * sm501fb_check_var_crt(): 399 * 400 * check the parameters for the CRT head, and either bring them 401 * back into range, or return -EINVAL. 402 */ 403 404 static int sm501fb_check_var_crt(struct fb_var_screeninfo *var, 405 struct fb_info *info) 406 { 407 return sm501fb_check_var(var, info); 408 } 409 410 /* sm501fb_check_var_pnl(): 411 * 412 * check the parameters for the CRT head, and either bring them 413 * back into range, or return -EINVAL. 414 */ 415 416 static int sm501fb_check_var_pnl(struct fb_var_screeninfo *var, 417 struct fb_info *info) 418 { 419 return sm501fb_check_var(var, info); 420 } 421 422 /* sm501fb_set_par_common 423 * 424 * set common registers for framebuffers 425 */ 426 427 static int sm501fb_set_par_common(struct fb_info *info, 428 struct fb_var_screeninfo *var) 429 { 430 struct sm501fb_par *par = info->par; 431 struct sm501fb_info *fbi = par->info; 432 unsigned long pixclock; /* pixelclock in Hz */ 433 unsigned long sm501pixclock; /* pixelclock the 501 can achieve in Hz */ 434 unsigned int mem_type; 435 unsigned int clock_type; 436 unsigned int head_addr; 437 unsigned int smem_len; 438 439 dev_dbg(fbi->dev, "%s: %dx%d, bpp = %d, virtual %dx%d\n", 440 __func__, var->xres, var->yres, var->bits_per_pixel, 441 var->xres_virtual, var->yres_virtual); 442 443 switch (par->head) { 444 case HEAD_CRT: 445 mem_type = SM501_MEMF_CRT; 446 clock_type = SM501_CLOCK_V2XCLK; 447 head_addr = SM501_DC_CRT_FB_ADDR; 448 break; 449 450 case HEAD_PANEL: 451 mem_type = SM501_MEMF_PANEL; 452 clock_type = SM501_CLOCK_P2XCLK; 453 head_addr = SM501_DC_PANEL_FB_ADDR; 454 break; 455 456 default: 457 mem_type = 0; /* stop compiler warnings */ 458 head_addr = 0; 459 clock_type = 0; 460 } 461 462 switch (var->bits_per_pixel) { 463 case 8: 464 info->fix.visual = FB_VISUAL_PSEUDOCOLOR; 465 break; 466 467 case 16: 468 info->fix.visual = FB_VISUAL_TRUECOLOR; 469 break; 470 471 case 32: 472 info->fix.visual = FB_VISUAL_TRUECOLOR; 473 break; 474 } 475 476 /* allocate fb memory within 501 */ 477 info->fix.line_length = (var->xres_virtual * var->bits_per_pixel)/8; 478 smem_len = info->fix.line_length * var->yres_virtual; 479 480 dev_dbg(fbi->dev, "%s: line length = %u\n", __func__, 481 info->fix.line_length); 482 483 if (sm501_alloc_mem(fbi, &par->screen, mem_type, smem_len, smem_len)) { 484 dev_err(fbi->dev, "no memory available\n"); 485 return -ENOMEM; 486 } 487 488 mutex_lock(&info->mm_lock); 489 info->fix.smem_start = fbi->fbmem_res->start + par->screen.sm_addr; 490 info->fix.smem_len = smem_len; 491 mutex_unlock(&info->mm_lock); 492 493 info->screen_base = fbi->fbmem + par->screen.sm_addr; 494 info->screen_size = info->fix.smem_len; 495 496 /* set start of framebuffer to the screen */ 497 498 smc501_writel(par->screen.sm_addr | SM501_ADDR_FLIP, 499 fbi->regs + head_addr); 500 501 /* program CRT clock */ 502 503 pixclock = sm501fb_ps_to_hz(var->pixclock); 504 505 sm501pixclock = sm501_set_clock(fbi->dev->parent, clock_type, 506 pixclock); 507 508 /* update fb layer with actual clock used */ 509 var->pixclock = sm501fb_hz_to_ps(sm501pixclock); 510 511 dev_dbg(fbi->dev, "%s: pixclock(ps) = %u, pixclock(Hz) = %lu, " 512 "sm501pixclock = %lu, error = %ld%%\n", 513 __func__, var->pixclock, pixclock, sm501pixclock, 514 ((pixclock - sm501pixclock)*100)/pixclock); 515 516 return 0; 517 } 518 519 /* sm501fb_set_par_geometry 520 * 521 * set the geometry registers for specified framebuffer. 522 */ 523 524 static void sm501fb_set_par_geometry(struct fb_info *info, 525 struct fb_var_screeninfo *var) 526 { 527 struct sm501fb_par *par = info->par; 528 struct sm501fb_info *fbi = par->info; 529 void __iomem *base = fbi->regs; 530 unsigned long reg; 531 532 if (par->head == HEAD_CRT) 533 base += SM501_DC_CRT_H_TOT; 534 else 535 base += SM501_DC_PANEL_H_TOT; 536 537 /* set framebuffer width and display width */ 538 539 reg = info->fix.line_length; 540 reg |= ((var->xres * var->bits_per_pixel)/8) << 16; 541 542 smc501_writel(reg, fbi->regs + (par->head == HEAD_CRT ? 543 SM501_DC_CRT_FB_OFFSET : SM501_DC_PANEL_FB_OFFSET)); 544 545 /* program horizontal total */ 546 547 reg = (h_total(var) - 1) << 16; 548 reg |= (var->xres - 1); 549 550 smc501_writel(reg, base + SM501_OFF_DC_H_TOT); 551 552 /* program horizontal sync */ 553 554 reg = var->hsync_len << 16; 555 reg |= var->xres + var->right_margin - 1; 556 557 smc501_writel(reg, base + SM501_OFF_DC_H_SYNC); 558 559 /* program vertical total */ 560 561 reg = (v_total(var) - 1) << 16; 562 reg |= (var->yres - 1); 563 564 smc501_writel(reg, base + SM501_OFF_DC_V_TOT); 565 566 /* program vertical sync */ 567 reg = var->vsync_len << 16; 568 reg |= var->yres + var->lower_margin - 1; 569 570 smc501_writel(reg, base + SM501_OFF_DC_V_SYNC); 571 } 572 573 /* sm501fb_pan_crt 574 * 575 * pan the CRT display output within an virtual framebuffer 576 */ 577 578 static int sm501fb_pan_crt(struct fb_var_screeninfo *var, 579 struct fb_info *info) 580 { 581 struct sm501fb_par *par = info->par; 582 struct sm501fb_info *fbi = par->info; 583 unsigned int bytes_pixel = info->var.bits_per_pixel / 8; 584 unsigned long reg; 585 unsigned long xoffs; 586 587 xoffs = var->xoffset * bytes_pixel; 588 589 reg = smc501_readl(fbi->regs + SM501_DC_CRT_CONTROL); 590 591 reg &= ~SM501_DC_CRT_CONTROL_PIXEL_MASK; 592 reg |= ((xoffs & 15) / bytes_pixel) << 4; 593 smc501_writel(reg, fbi->regs + SM501_DC_CRT_CONTROL); 594 595 reg = (par->screen.sm_addr + xoffs + 596 var->yoffset * info->fix.line_length); 597 smc501_writel(reg | SM501_ADDR_FLIP, fbi->regs + SM501_DC_CRT_FB_ADDR); 598 599 sm501fb_sync_regs(fbi); 600 return 0; 601 } 602 603 /* sm501fb_pan_pnl 604 * 605 * pan the panel display output within an virtual framebuffer 606 */ 607 608 static int sm501fb_pan_pnl(struct fb_var_screeninfo *var, 609 struct fb_info *info) 610 { 611 struct sm501fb_par *par = info->par; 612 struct sm501fb_info *fbi = par->info; 613 unsigned long reg; 614 615 reg = var->xoffset | (info->var.xres_virtual << 16); 616 smc501_writel(reg, fbi->regs + SM501_DC_PANEL_FB_WIDTH); 617 618 reg = var->yoffset | (info->var.yres_virtual << 16); 619 smc501_writel(reg, fbi->regs + SM501_DC_PANEL_FB_HEIGHT); 620 621 sm501fb_sync_regs(fbi); 622 return 0; 623 } 624 625 /* sm501fb_set_par_crt 626 * 627 * Set the CRT video mode from the fb_info structure 628 */ 629 630 static int sm501fb_set_par_crt(struct fb_info *info) 631 { 632 struct sm501fb_par *par = info->par; 633 struct sm501fb_info *fbi = par->info; 634 struct fb_var_screeninfo *var = &info->var; 635 unsigned long control; /* control register */ 636 int ret; 637 638 /* activate new configuration */ 639 640 dev_dbg(fbi->dev, "%s(%p)\n", __func__, info); 641 642 /* enable CRT DAC - note 0 is on!*/ 643 sm501_misc_control(fbi->dev->parent, 0, SM501_MISC_DAC_POWER); 644 645 control = smc501_readl(fbi->regs + SM501_DC_CRT_CONTROL); 646 647 control &= (SM501_DC_CRT_CONTROL_PIXEL_MASK | 648 SM501_DC_CRT_CONTROL_GAMMA | 649 SM501_DC_CRT_CONTROL_BLANK | 650 SM501_DC_CRT_CONTROL_SEL | 651 SM501_DC_CRT_CONTROL_CP | 652 SM501_DC_CRT_CONTROL_TVP); 653 654 /* set the sync polarities before we check data source */ 655 656 if ((var->sync & FB_SYNC_HOR_HIGH_ACT) == 0) 657 control |= SM501_DC_CRT_CONTROL_HSP; 658 659 if ((var->sync & FB_SYNC_VERT_HIGH_ACT) == 0) 660 control |= SM501_DC_CRT_CONTROL_VSP; 661 662 if ((control & SM501_DC_CRT_CONTROL_SEL) == 0) { 663 /* the head is displaying panel data... */ 664 665 sm501_alloc_mem(fbi, &par->screen, SM501_MEMF_CRT, 0, 666 info->fix.smem_len); 667 goto out_update; 668 } 669 670 ret = sm501fb_set_par_common(info, var); 671 if (ret) { 672 dev_err(fbi->dev, "failed to set common parameters\n"); 673 return ret; 674 } 675 676 sm501fb_pan_crt(var, info); 677 sm501fb_set_par_geometry(info, var); 678 679 control |= SM501_FIFO_3; /* fill if >3 free slots */ 680 681 switch(var->bits_per_pixel) { 682 case 8: 683 control |= SM501_DC_CRT_CONTROL_8BPP; 684 break; 685 686 case 16: 687 control |= SM501_DC_CRT_CONTROL_16BPP; 688 sm501fb_setup_gamma(fbi, SM501_DC_CRT_PALETTE); 689 break; 690 691 case 32: 692 control |= SM501_DC_CRT_CONTROL_32BPP; 693 sm501fb_setup_gamma(fbi, SM501_DC_CRT_PALETTE); 694 break; 695 696 default: 697 BUG(); 698 } 699 700 control |= SM501_DC_CRT_CONTROL_SEL; /* CRT displays CRT data */ 701 control |= SM501_DC_CRT_CONTROL_TE; /* enable CRT timing */ 702 control |= SM501_DC_CRT_CONTROL_ENABLE; /* enable CRT plane */ 703 704 out_update: 705 dev_dbg(fbi->dev, "new control is %08lx\n", control); 706 707 smc501_writel(control, fbi->regs + SM501_DC_CRT_CONTROL); 708 sm501fb_sync_regs(fbi); 709 710 return 0; 711 } 712 713 static void sm501fb_panel_power(struct sm501fb_info *fbi, int to) 714 { 715 unsigned long control; 716 void __iomem *ctrl_reg = fbi->regs + SM501_DC_PANEL_CONTROL; 717 struct sm501_platdata_fbsub *pd = fbi->pdata->fb_pnl; 718 719 control = smc501_readl(ctrl_reg); 720 721 if (to && (control & SM501_DC_PANEL_CONTROL_VDD) == 0) { 722 /* enable panel power */ 723 724 control |= SM501_DC_PANEL_CONTROL_VDD; /* FPVDDEN */ 725 smc501_writel(control, ctrl_reg); 726 sm501fb_sync_regs(fbi); 727 mdelay(10); 728 729 control |= SM501_DC_PANEL_CONTROL_DATA; /* DATA */ 730 smc501_writel(control, ctrl_reg); 731 sm501fb_sync_regs(fbi); 732 mdelay(10); 733 734 /* VBIASEN */ 735 736 if (!(pd->flags & SM501FB_FLAG_PANEL_NO_VBIASEN)) { 737 if (pd->flags & SM501FB_FLAG_PANEL_INV_VBIASEN) 738 control &= ~SM501_DC_PANEL_CONTROL_BIAS; 739 else 740 control |= SM501_DC_PANEL_CONTROL_BIAS; 741 742 smc501_writel(control, ctrl_reg); 743 sm501fb_sync_regs(fbi); 744 mdelay(10); 745 } 746 747 if (!(pd->flags & SM501FB_FLAG_PANEL_NO_FPEN)) { 748 if (pd->flags & SM501FB_FLAG_PANEL_INV_FPEN) 749 control &= ~SM501_DC_PANEL_CONTROL_FPEN; 750 else 751 control |= SM501_DC_PANEL_CONTROL_FPEN; 752 753 smc501_writel(control, ctrl_reg); 754 sm501fb_sync_regs(fbi); 755 mdelay(10); 756 } 757 } else if (!to && (control & SM501_DC_PANEL_CONTROL_VDD) != 0) { 758 /* disable panel power */ 759 if (!(pd->flags & SM501FB_FLAG_PANEL_NO_FPEN)) { 760 if (pd->flags & SM501FB_FLAG_PANEL_INV_FPEN) 761 control |= SM501_DC_PANEL_CONTROL_FPEN; 762 else 763 control &= ~SM501_DC_PANEL_CONTROL_FPEN; 764 765 smc501_writel(control, ctrl_reg); 766 sm501fb_sync_regs(fbi); 767 mdelay(10); 768 } 769 770 if (!(pd->flags & SM501FB_FLAG_PANEL_NO_VBIASEN)) { 771 if (pd->flags & SM501FB_FLAG_PANEL_INV_VBIASEN) 772 control |= SM501_DC_PANEL_CONTROL_BIAS; 773 else 774 control &= ~SM501_DC_PANEL_CONTROL_BIAS; 775 776 smc501_writel(control, ctrl_reg); 777 sm501fb_sync_regs(fbi); 778 mdelay(10); 779 } 780 781 control &= ~SM501_DC_PANEL_CONTROL_DATA; 782 smc501_writel(control, ctrl_reg); 783 sm501fb_sync_regs(fbi); 784 mdelay(10); 785 786 control &= ~SM501_DC_PANEL_CONTROL_VDD; 787 smc501_writel(control, ctrl_reg); 788 sm501fb_sync_regs(fbi); 789 mdelay(10); 790 } 791 792 sm501fb_sync_regs(fbi); 793 } 794 795 /* sm501fb_set_par_pnl 796 * 797 * Set the panel video mode from the fb_info structure 798 */ 799 800 static int sm501fb_set_par_pnl(struct fb_info *info) 801 { 802 struct sm501fb_par *par = info->par; 803 struct sm501fb_info *fbi = par->info; 804 struct fb_var_screeninfo *var = &info->var; 805 unsigned long control; 806 unsigned long reg; 807 int ret; 808 809 dev_dbg(fbi->dev, "%s(%p)\n", __func__, info); 810 811 /* activate this new configuration */ 812 813 ret = sm501fb_set_par_common(info, var); 814 if (ret) 815 return ret; 816 817 sm501fb_pan_pnl(var, info); 818 sm501fb_set_par_geometry(info, var); 819 820 /* update control register */ 821 822 control = smc501_readl(fbi->regs + SM501_DC_PANEL_CONTROL); 823 control &= (SM501_DC_PANEL_CONTROL_GAMMA | 824 SM501_DC_PANEL_CONTROL_VDD | 825 SM501_DC_PANEL_CONTROL_DATA | 826 SM501_DC_PANEL_CONTROL_BIAS | 827 SM501_DC_PANEL_CONTROL_FPEN | 828 SM501_DC_PANEL_CONTROL_CP | 829 SM501_DC_PANEL_CONTROL_CK | 830 SM501_DC_PANEL_CONTROL_HP | 831 SM501_DC_PANEL_CONTROL_VP | 832 SM501_DC_PANEL_CONTROL_HPD | 833 SM501_DC_PANEL_CONTROL_VPD); 834 835 control |= SM501_FIFO_3; /* fill if >3 free slots */ 836 837 switch(var->bits_per_pixel) { 838 case 8: 839 control |= SM501_DC_PANEL_CONTROL_8BPP; 840 break; 841 842 case 16: 843 control |= SM501_DC_PANEL_CONTROL_16BPP; 844 sm501fb_setup_gamma(fbi, SM501_DC_PANEL_PALETTE); 845 break; 846 847 case 32: 848 control |= SM501_DC_PANEL_CONTROL_32BPP; 849 sm501fb_setup_gamma(fbi, SM501_DC_PANEL_PALETTE); 850 break; 851 852 default: 853 BUG(); 854 } 855 856 smc501_writel(0x0, fbi->regs + SM501_DC_PANEL_PANNING_CONTROL); 857 858 /* panel plane top left and bottom right location */ 859 860 smc501_writel(0x00, fbi->regs + SM501_DC_PANEL_TL_LOC); 861 862 reg = var->xres - 1; 863 reg |= (var->yres - 1) << 16; 864 865 smc501_writel(reg, fbi->regs + SM501_DC_PANEL_BR_LOC); 866 867 /* program panel control register */ 868 869 control |= SM501_DC_PANEL_CONTROL_TE; /* enable PANEL timing */ 870 control |= SM501_DC_PANEL_CONTROL_EN; /* enable PANEL gfx plane */ 871 872 if ((var->sync & FB_SYNC_HOR_HIGH_ACT) == 0) 873 control |= SM501_DC_PANEL_CONTROL_HSP; 874 875 if ((var->sync & FB_SYNC_VERT_HIGH_ACT) == 0) 876 control |= SM501_DC_PANEL_CONTROL_VSP; 877 878 smc501_writel(control, fbi->regs + SM501_DC_PANEL_CONTROL); 879 sm501fb_sync_regs(fbi); 880 881 /* ensure the panel interface is not tristated at this point */ 882 883 sm501_modify_reg(fbi->dev->parent, SM501_SYSTEM_CONTROL, 884 0, SM501_SYSCTRL_PANEL_TRISTATE); 885 886 /* power the panel up */ 887 sm501fb_panel_power(fbi, 1); 888 return 0; 889 } 890 891 892 /* chan_to_field 893 * 894 * convert a colour value into a field position 895 * 896 * from pxafb.c 897 */ 898 899 static inline unsigned int chan_to_field(unsigned int chan, 900 struct fb_bitfield *bf) 901 { 902 chan &= 0xffff; 903 chan >>= 16 - bf->length; 904 return chan << bf->offset; 905 } 906 907 /* sm501fb_setcolreg 908 * 909 * set the colour mapping for modes that support palettised data 910 */ 911 912 static int sm501fb_setcolreg(unsigned regno, 913 unsigned red, unsigned green, unsigned blue, 914 unsigned transp, struct fb_info *info) 915 { 916 struct sm501fb_par *par = info->par; 917 struct sm501fb_info *fbi = par->info; 918 void __iomem *base = fbi->regs; 919 unsigned int val; 920 921 if (par->head == HEAD_CRT) 922 base += SM501_DC_CRT_PALETTE; 923 else 924 base += SM501_DC_PANEL_PALETTE; 925 926 switch (info->fix.visual) { 927 case FB_VISUAL_TRUECOLOR: 928 /* true-colour, use pseuo-palette */ 929 930 if (regno < 16) { 931 u32 *pal = par->pseudo_palette; 932 933 val = chan_to_field(red, &info->var.red); 934 val |= chan_to_field(green, &info->var.green); 935 val |= chan_to_field(blue, &info->var.blue); 936 937 pal[regno] = val; 938 } 939 break; 940 941 case FB_VISUAL_PSEUDOCOLOR: 942 if (regno < 256) { 943 val = (red >> 8) << 16; 944 val |= (green >> 8) << 8; 945 val |= blue >> 8; 946 947 smc501_writel(val, base + (regno * 4)); 948 } 949 950 break; 951 952 default: 953 return 1; /* unknown type */ 954 } 955 956 return 0; 957 } 958 959 /* sm501fb_blank_pnl 960 * 961 * Blank or un-blank the panel interface 962 */ 963 964 static int sm501fb_blank_pnl(int blank_mode, struct fb_info *info) 965 { 966 struct sm501fb_par *par = info->par; 967 struct sm501fb_info *fbi = par->info; 968 969 dev_dbg(fbi->dev, "%s(mode=%d, %p)\n", __func__, blank_mode, info); 970 971 switch (blank_mode) { 972 case FB_BLANK_POWERDOWN: 973 sm501fb_panel_power(fbi, 0); 974 break; 975 976 case FB_BLANK_UNBLANK: 977 sm501fb_panel_power(fbi, 1); 978 break; 979 980 case FB_BLANK_NORMAL: 981 case FB_BLANK_VSYNC_SUSPEND: 982 case FB_BLANK_HSYNC_SUSPEND: 983 default: 984 return 1; 985 } 986 987 return 0; 988 } 989 990 /* sm501fb_blank_crt 991 * 992 * Blank or un-blank the crt interface 993 */ 994 995 static int sm501fb_blank_crt(int blank_mode, struct fb_info *info) 996 { 997 struct sm501fb_par *par = info->par; 998 struct sm501fb_info *fbi = par->info; 999 unsigned long ctrl; 1000 1001 dev_dbg(fbi->dev, "%s(mode=%d, %p)\n", __func__, blank_mode, info); 1002 1003 ctrl = smc501_readl(fbi->regs + SM501_DC_CRT_CONTROL); 1004 1005 switch (blank_mode) { 1006 case FB_BLANK_POWERDOWN: 1007 ctrl &= ~SM501_DC_CRT_CONTROL_ENABLE; 1008 sm501_misc_control(fbi->dev->parent, SM501_MISC_DAC_POWER, 0); 1009 fallthrough; 1010 1011 case FB_BLANK_NORMAL: 1012 ctrl |= SM501_DC_CRT_CONTROL_BLANK; 1013 break; 1014 1015 case FB_BLANK_UNBLANK: 1016 ctrl &= ~SM501_DC_CRT_CONTROL_BLANK; 1017 ctrl |= SM501_DC_CRT_CONTROL_ENABLE; 1018 sm501_misc_control(fbi->dev->parent, 0, SM501_MISC_DAC_POWER); 1019 break; 1020 1021 case FB_BLANK_VSYNC_SUSPEND: 1022 case FB_BLANK_HSYNC_SUSPEND: 1023 default: 1024 return 1; 1025 1026 } 1027 1028 smc501_writel(ctrl, fbi->regs + SM501_DC_CRT_CONTROL); 1029 sm501fb_sync_regs(fbi); 1030 1031 return 0; 1032 } 1033 1034 /* sm501fb_cursor 1035 * 1036 * set or change the hardware cursor parameters 1037 */ 1038 1039 static int sm501fb_cursor(struct fb_info *info, struct fb_cursor *cursor) 1040 { 1041 struct sm501fb_par *par = info->par; 1042 struct sm501fb_info *fbi = par->info; 1043 void __iomem *base = fbi->regs; 1044 unsigned long hwc_addr; 1045 unsigned long fg, bg; 1046 1047 dev_dbg(fbi->dev, "%s(%p,%p)\n", __func__, info, cursor); 1048 1049 if (par->head == HEAD_CRT) 1050 base += SM501_DC_CRT_HWC_BASE; 1051 else 1052 base += SM501_DC_PANEL_HWC_BASE; 1053 1054 /* check not being asked to exceed capabilities */ 1055 1056 if (cursor->image.width > 64) 1057 return -EINVAL; 1058 1059 if (cursor->image.height > 64) 1060 return -EINVAL; 1061 1062 if (cursor->image.depth > 1) 1063 return -EINVAL; 1064 1065 hwc_addr = smc501_readl(base + SM501_OFF_HWC_ADDR); 1066 1067 if (cursor->enable) 1068 smc501_writel(hwc_addr | SM501_HWC_EN, 1069 base + SM501_OFF_HWC_ADDR); 1070 else 1071 smc501_writel(hwc_addr & ~SM501_HWC_EN, 1072 base + SM501_OFF_HWC_ADDR); 1073 1074 /* set data */ 1075 if (cursor->set & FB_CUR_SETPOS) { 1076 unsigned int x = cursor->image.dx; 1077 unsigned int y = cursor->image.dy; 1078 1079 if (x >= 2048 || y >= 2048 ) 1080 return -EINVAL; 1081 1082 dev_dbg(fbi->dev, "set position %d,%d\n", x, y); 1083 1084 //y += cursor->image.height; 1085 1086 smc501_writel(x | (y << 16), base + SM501_OFF_HWC_LOC); 1087 } 1088 1089 if (cursor->set & FB_CUR_SETCMAP) { 1090 unsigned int bg_col = cursor->image.bg_color; 1091 unsigned int fg_col = cursor->image.fg_color; 1092 1093 dev_dbg(fbi->dev, "%s: update cmap (%08x,%08x)\n", 1094 __func__, bg_col, fg_col); 1095 1096 bg = ((info->cmap.red[bg_col] & 0xF8) << 8) | 1097 ((info->cmap.green[bg_col] & 0xFC) << 3) | 1098 ((info->cmap.blue[bg_col] & 0xF8) >> 3); 1099 1100 fg = ((info->cmap.red[fg_col] & 0xF8) << 8) | 1101 ((info->cmap.green[fg_col] & 0xFC) << 3) | 1102 ((info->cmap.blue[fg_col] & 0xF8) >> 3); 1103 1104 dev_dbg(fbi->dev, "fgcol %08lx, bgcol %08lx\n", fg, bg); 1105 1106 smc501_writel(bg, base + SM501_OFF_HWC_COLOR_1_2); 1107 smc501_writel(fg, base + SM501_OFF_HWC_COLOR_3); 1108 } 1109 1110 if (cursor->set & FB_CUR_SETSIZE || 1111 cursor->set & (FB_CUR_SETIMAGE | FB_CUR_SETSHAPE)) { 1112 /* SM501 cursor is a two bpp 64x64 bitmap this routine 1113 * clears it to transparent then combines the cursor 1114 * shape plane with the colour plane to set the 1115 * cursor */ 1116 int x, y; 1117 const unsigned char *pcol = cursor->image.data; 1118 const unsigned char *pmsk = cursor->mask; 1119 void __iomem *dst = par->cursor.k_addr; 1120 unsigned char dcol = 0; 1121 unsigned char dmsk = 0; 1122 unsigned int op; 1123 1124 dev_dbg(fbi->dev, "%s: setting shape (%d,%d)\n", 1125 __func__, cursor->image.width, cursor->image.height); 1126 1127 for (op = 0; op < (64*64*2)/8; op+=4) 1128 smc501_writel(0x0, dst + op); 1129 1130 for (y = 0; y < cursor->image.height; y++) { 1131 for (x = 0; x < cursor->image.width; x++) { 1132 if ((x % 8) == 0) { 1133 dcol = *pcol++; 1134 dmsk = *pmsk++; 1135 } else { 1136 dcol >>= 1; 1137 dmsk >>= 1; 1138 } 1139 1140 if (dmsk & 1) { 1141 op = (dcol & 1) ? 1 : 3; 1142 op <<= ((x % 4) * 2); 1143 1144 op |= readb(dst + (x / 4)); 1145 writeb(op, dst + (x / 4)); 1146 } 1147 } 1148 dst += (64*2)/8; 1149 } 1150 } 1151 1152 sm501fb_sync_regs(fbi); /* ensure cursor data flushed */ 1153 return 0; 1154 } 1155 1156 /* sm501fb_crtsrc_show 1157 * 1158 * device attribute code to show where the crt output is sourced from 1159 */ 1160 1161 static ssize_t sm501fb_crtsrc_show(struct device *dev, 1162 struct device_attribute *attr, char *buf) 1163 { 1164 struct sm501fb_info *info = dev_get_drvdata(dev); 1165 unsigned long ctrl; 1166 1167 ctrl = smc501_readl(info->regs + SM501_DC_CRT_CONTROL); 1168 ctrl &= SM501_DC_CRT_CONTROL_SEL; 1169 1170 return sysfs_emit(buf, "%s\n", ctrl ? "crt" : "panel"); 1171 } 1172 1173 /* sm501fb_crtsrc_show 1174 * 1175 * device attribute code to set where the crt output is sourced from 1176 */ 1177 1178 static ssize_t sm501fb_crtsrc_store(struct device *dev, 1179 struct device_attribute *attr, 1180 const char *buf, size_t len) 1181 { 1182 struct sm501fb_info *info = dev_get_drvdata(dev); 1183 enum sm501_controller head; 1184 unsigned long ctrl; 1185 1186 if (len < 1) 1187 return -EINVAL; 1188 1189 if (strncasecmp(buf, "crt", 3) == 0) 1190 head = HEAD_CRT; 1191 else if (strncasecmp(buf, "panel", 5) == 0) 1192 head = HEAD_PANEL; 1193 else 1194 return -EINVAL; 1195 1196 dev_info(dev, "setting crt source to head %d\n", head); 1197 1198 ctrl = smc501_readl(info->regs + SM501_DC_CRT_CONTROL); 1199 1200 if (head == HEAD_CRT) { 1201 ctrl |= SM501_DC_CRT_CONTROL_SEL; 1202 ctrl |= SM501_DC_CRT_CONTROL_ENABLE; 1203 ctrl |= SM501_DC_CRT_CONTROL_TE; 1204 } else { 1205 ctrl &= ~SM501_DC_CRT_CONTROL_SEL; 1206 ctrl &= ~SM501_DC_CRT_CONTROL_ENABLE; 1207 ctrl &= ~SM501_DC_CRT_CONTROL_TE; 1208 } 1209 1210 smc501_writel(ctrl, info->regs + SM501_DC_CRT_CONTROL); 1211 sm501fb_sync_regs(info); 1212 1213 return len; 1214 } 1215 1216 /* Prepare the device_attr for registration with sysfs later */ 1217 static DEVICE_ATTR(crt_src, 0664, sm501fb_crtsrc_show, sm501fb_crtsrc_store); 1218 1219 /* sm501fb_show_regs 1220 * 1221 * show the primary sm501 registers 1222 */ 1223 static int sm501fb_show_regs(struct sm501fb_info *info, char *ptr, 1224 unsigned int start, unsigned int len) 1225 { 1226 void __iomem *mem = info->regs; 1227 char *buf = ptr; 1228 unsigned int reg; 1229 1230 for (reg = start; reg < (len + start); reg += 4) 1231 ptr += sprintf(ptr, "%08x = %08x\n", reg, 1232 smc501_readl(mem + reg)); 1233 1234 return ptr - buf; 1235 } 1236 1237 /* sm501fb_debug_show_crt 1238 * 1239 * show the crt control and cursor registers 1240 */ 1241 1242 static ssize_t sm501fb_debug_show_crt(struct device *dev, 1243 struct device_attribute *attr, char *buf) 1244 { 1245 struct sm501fb_info *info = dev_get_drvdata(dev); 1246 char *ptr = buf; 1247 1248 ptr += sm501fb_show_regs(info, ptr, SM501_DC_CRT_CONTROL, 0x40); 1249 ptr += sm501fb_show_regs(info, ptr, SM501_DC_CRT_HWC_BASE, 0x10); 1250 1251 return ptr - buf; 1252 } 1253 1254 static DEVICE_ATTR(fbregs_crt, 0444, sm501fb_debug_show_crt, NULL); 1255 1256 /* sm501fb_debug_show_pnl 1257 * 1258 * show the panel control and cursor registers 1259 */ 1260 1261 static ssize_t sm501fb_debug_show_pnl(struct device *dev, 1262 struct device_attribute *attr, char *buf) 1263 { 1264 struct sm501fb_info *info = dev_get_drvdata(dev); 1265 char *ptr = buf; 1266 1267 ptr += sm501fb_show_regs(info, ptr, 0x0, 0x40); 1268 ptr += sm501fb_show_regs(info, ptr, SM501_DC_PANEL_HWC_BASE, 0x10); 1269 1270 return ptr - buf; 1271 } 1272 1273 static DEVICE_ATTR(fbregs_pnl, 0444, sm501fb_debug_show_pnl, NULL); 1274 1275 static struct attribute *sm501fb_attrs[] = { 1276 &dev_attr_crt_src.attr, 1277 &dev_attr_fbregs_pnl.attr, 1278 &dev_attr_fbregs_crt.attr, 1279 NULL, 1280 }; 1281 ATTRIBUTE_GROUPS(sm501fb); 1282 1283 /* acceleration operations */ 1284 static int sm501fb_sync(struct fb_info *info) 1285 { 1286 int count = 1000000; 1287 struct sm501fb_par *par = info->par; 1288 struct sm501fb_info *fbi = par->info; 1289 1290 /* wait for the 2d engine to be ready */ 1291 while ((count > 0) && 1292 (smc501_readl(fbi->regs + SM501_SYSTEM_CONTROL) & 1293 SM501_SYSCTRL_2D_ENGINE_STATUS) != 0) 1294 count--; 1295 1296 if (count <= 0) { 1297 fb_err(info, "Timeout waiting for 2d engine sync\n"); 1298 return 1; 1299 } 1300 return 0; 1301 } 1302 1303 static void sm501fb_copyarea(struct fb_info *info, const struct fb_copyarea *area) 1304 { 1305 struct sm501fb_par *par = info->par; 1306 struct sm501fb_info *fbi = par->info; 1307 int width = area->width; 1308 int height = area->height; 1309 int sx = area->sx; 1310 int sy = area->sy; 1311 int dx = area->dx; 1312 int dy = area->dy; 1313 unsigned long rtl = 0; 1314 1315 /* source clip */ 1316 if ((sx >= info->var.xres_virtual) || 1317 (sy >= info->var.yres_virtual)) 1318 /* source Area not within virtual screen, skipping */ 1319 return; 1320 if ((sx + width) >= info->var.xres_virtual) 1321 width = info->var.xres_virtual - sx - 1; 1322 if ((sy + height) >= info->var.yres_virtual) 1323 height = info->var.yres_virtual - sy - 1; 1324 1325 /* dest clip */ 1326 if ((dx >= info->var.xres_virtual) || 1327 (dy >= info->var.yres_virtual)) 1328 /* Destination Area not within virtual screen, skipping */ 1329 return; 1330 if ((dx + width) >= info->var.xres_virtual) 1331 width = info->var.xres_virtual - dx - 1; 1332 if ((dy + height) >= info->var.yres_virtual) 1333 height = info->var.yres_virtual - dy - 1; 1334 1335 if ((sx < dx) || (sy < dy)) { 1336 rtl = 1 << 27; 1337 sx += width - 1; 1338 dx += width - 1; 1339 sy += height - 1; 1340 dy += height - 1; 1341 } 1342 1343 if (sm501fb_sync(info)) 1344 return; 1345 1346 /* set the base addresses */ 1347 smc501_writel(par->screen.sm_addr, fbi->regs2d + SM501_2D_SOURCE_BASE); 1348 smc501_writel(par->screen.sm_addr, 1349 fbi->regs2d + SM501_2D_DESTINATION_BASE); 1350 1351 /* set the window width */ 1352 smc501_writel((info->var.xres << 16) | info->var.xres, 1353 fbi->regs2d + SM501_2D_WINDOW_WIDTH); 1354 1355 /* set window stride */ 1356 smc501_writel((info->var.xres_virtual << 16) | info->var.xres_virtual, 1357 fbi->regs2d + SM501_2D_PITCH); 1358 1359 /* set data format */ 1360 switch (info->var.bits_per_pixel) { 1361 case 8: 1362 smc501_writel(0, fbi->regs2d + SM501_2D_STRETCH); 1363 break; 1364 case 16: 1365 smc501_writel(0x00100000, fbi->regs2d + SM501_2D_STRETCH); 1366 break; 1367 case 32: 1368 smc501_writel(0x00200000, fbi->regs2d + SM501_2D_STRETCH); 1369 break; 1370 } 1371 1372 /* 2d compare mask */ 1373 smc501_writel(0xffffffff, fbi->regs2d + SM501_2D_COLOR_COMPARE_MASK); 1374 1375 /* 2d mask */ 1376 smc501_writel(0xffffffff, fbi->regs2d + SM501_2D_MASK); 1377 1378 /* source and destination x y */ 1379 smc501_writel((sx << 16) | sy, fbi->regs2d + SM501_2D_SOURCE); 1380 smc501_writel((dx << 16) | dy, fbi->regs2d + SM501_2D_DESTINATION); 1381 1382 /* w/h */ 1383 smc501_writel((width << 16) | height, fbi->regs2d + SM501_2D_DIMENSION); 1384 1385 /* do area move */ 1386 smc501_writel(0x800000cc | rtl, fbi->regs2d + SM501_2D_CONTROL); 1387 } 1388 1389 static void sm501fb_fillrect(struct fb_info *info, const struct fb_fillrect *rect) 1390 { 1391 struct sm501fb_par *par = info->par; 1392 struct sm501fb_info *fbi = par->info; 1393 int width = rect->width, height = rect->height; 1394 1395 if ((rect->dx >= info->var.xres_virtual) || 1396 (rect->dy >= info->var.yres_virtual)) 1397 /* Rectangle not within virtual screen, skipping */ 1398 return; 1399 if ((rect->dx + width) >= info->var.xres_virtual) 1400 width = info->var.xres_virtual - rect->dx - 1; 1401 if ((rect->dy + height) >= info->var.yres_virtual) 1402 height = info->var.yres_virtual - rect->dy - 1; 1403 1404 if (sm501fb_sync(info)) 1405 return; 1406 1407 /* set the base addresses */ 1408 smc501_writel(par->screen.sm_addr, fbi->regs2d + SM501_2D_SOURCE_BASE); 1409 smc501_writel(par->screen.sm_addr, 1410 fbi->regs2d + SM501_2D_DESTINATION_BASE); 1411 1412 /* set the window width */ 1413 smc501_writel((info->var.xres << 16) | info->var.xres, 1414 fbi->regs2d + SM501_2D_WINDOW_WIDTH); 1415 1416 /* set window stride */ 1417 smc501_writel((info->var.xres_virtual << 16) | info->var.xres_virtual, 1418 fbi->regs2d + SM501_2D_PITCH); 1419 1420 /* set data format */ 1421 switch (info->var.bits_per_pixel) { 1422 case 8: 1423 smc501_writel(0, fbi->regs2d + SM501_2D_STRETCH); 1424 break; 1425 case 16: 1426 smc501_writel(0x00100000, fbi->regs2d + SM501_2D_STRETCH); 1427 break; 1428 case 32: 1429 smc501_writel(0x00200000, fbi->regs2d + SM501_2D_STRETCH); 1430 break; 1431 } 1432 1433 /* 2d compare mask */ 1434 smc501_writel(0xffffffff, fbi->regs2d + SM501_2D_COLOR_COMPARE_MASK); 1435 1436 /* 2d mask */ 1437 smc501_writel(0xffffffff, fbi->regs2d + SM501_2D_MASK); 1438 1439 /* colour */ 1440 smc501_writel(rect->color, fbi->regs2d + SM501_2D_FOREGROUND); 1441 1442 /* x y */ 1443 smc501_writel((rect->dx << 16) | rect->dy, 1444 fbi->regs2d + SM501_2D_DESTINATION); 1445 1446 /* w/h */ 1447 smc501_writel((width << 16) | height, fbi->regs2d + SM501_2D_DIMENSION); 1448 1449 /* do rectangle fill */ 1450 smc501_writel(0x800100cc, fbi->regs2d + SM501_2D_CONTROL); 1451 } 1452 1453 1454 static struct fb_ops sm501fb_ops_crt = { 1455 .owner = THIS_MODULE, 1456 __FB_DEFAULT_IOMEM_OPS_RDWR, 1457 .fb_check_var = sm501fb_check_var_crt, 1458 .fb_set_par = sm501fb_set_par_crt, 1459 .fb_blank = sm501fb_blank_crt, 1460 .fb_setcolreg = sm501fb_setcolreg, 1461 .fb_pan_display = sm501fb_pan_crt, 1462 .fb_cursor = sm501fb_cursor, 1463 .fb_fillrect = sm501fb_fillrect, 1464 .fb_copyarea = sm501fb_copyarea, 1465 .fb_imageblit = cfb_imageblit, 1466 .fb_sync = sm501fb_sync, 1467 __FB_DEFAULT_IOMEM_OPS_MMAP, 1468 }; 1469 1470 static struct fb_ops sm501fb_ops_pnl = { 1471 .owner = THIS_MODULE, 1472 __FB_DEFAULT_IOMEM_OPS_RDWR, 1473 .fb_check_var = sm501fb_check_var_pnl, 1474 .fb_set_par = sm501fb_set_par_pnl, 1475 .fb_pan_display = sm501fb_pan_pnl, 1476 .fb_blank = sm501fb_blank_pnl, 1477 .fb_setcolreg = sm501fb_setcolreg, 1478 .fb_cursor = sm501fb_cursor, 1479 .fb_fillrect = sm501fb_fillrect, 1480 .fb_copyarea = sm501fb_copyarea, 1481 .fb_imageblit = cfb_imageblit, 1482 .fb_sync = sm501fb_sync, 1483 __FB_DEFAULT_IOMEM_OPS_MMAP, 1484 }; 1485 1486 /* sm501_init_cursor 1487 * 1488 * initialise hw cursor parameters 1489 */ 1490 1491 static int sm501_init_cursor(struct fb_info *fbi, unsigned int reg_base) 1492 { 1493 struct sm501fb_par *par; 1494 struct sm501fb_info *info; 1495 int ret; 1496 1497 if (fbi == NULL) 1498 return 0; 1499 1500 par = fbi->par; 1501 info = par->info; 1502 1503 par->cursor_regs = info->regs + reg_base; 1504 1505 ret = sm501_alloc_mem(info, &par->cursor, SM501_MEMF_CURSOR, 1024, 1506 fbi->fix.smem_len); 1507 if (ret < 0) 1508 return ret; 1509 1510 /* initialise the colour registers */ 1511 1512 smc501_writel(par->cursor.sm_addr, 1513 par->cursor_regs + SM501_OFF_HWC_ADDR); 1514 1515 smc501_writel(0x00, par->cursor_regs + SM501_OFF_HWC_LOC); 1516 smc501_writel(0x00, par->cursor_regs + SM501_OFF_HWC_COLOR_1_2); 1517 smc501_writel(0x00, par->cursor_regs + SM501_OFF_HWC_COLOR_3); 1518 sm501fb_sync_regs(info); 1519 1520 return 0; 1521 } 1522 1523 /* sm501fb_info_start 1524 * 1525 * fills the par structure claiming resources and remapping etc. 1526 */ 1527 1528 static int sm501fb_start(struct sm501fb_info *info, 1529 struct platform_device *pdev) 1530 { 1531 struct resource *res; 1532 struct device *dev = &pdev->dev; 1533 int k; 1534 int ret; 1535 1536 info->irq = ret = platform_get_irq(pdev, 0); 1537 if (ret < 0) { 1538 /* we currently do not use the IRQ */ 1539 dev_warn(dev, "no irq for device\n"); 1540 } 1541 1542 /* allocate, reserve and remap resources for display 1543 * controller registers */ 1544 res = platform_get_resource(pdev, IORESOURCE_MEM, 0); 1545 if (res == NULL) { 1546 dev_err(dev, "no resource definition for registers\n"); 1547 ret = -ENOENT; 1548 goto err_release; 1549 } 1550 1551 info->regs_res = request_mem_region(res->start, 1552 resource_size(res), 1553 pdev->name); 1554 1555 if (info->regs_res == NULL) { 1556 dev_err(dev, "cannot claim registers\n"); 1557 ret = -ENXIO; 1558 goto err_release; 1559 } 1560 1561 info->regs = ioremap(res->start, resource_size(res)); 1562 if (info->regs == NULL) { 1563 dev_err(dev, "cannot remap registers\n"); 1564 ret = -ENXIO; 1565 goto err_regs_res; 1566 } 1567 1568 /* allocate, reserve and remap resources for 2d 1569 * controller registers */ 1570 res = platform_get_resource(pdev, IORESOURCE_MEM, 1); 1571 if (res == NULL) { 1572 dev_err(dev, "no resource definition for 2d registers\n"); 1573 ret = -ENOENT; 1574 goto err_regs_map; 1575 } 1576 1577 info->regs2d_res = request_mem_region(res->start, 1578 resource_size(res), 1579 pdev->name); 1580 1581 if (info->regs2d_res == NULL) { 1582 dev_err(dev, "cannot claim registers\n"); 1583 ret = -ENXIO; 1584 goto err_regs_map; 1585 } 1586 1587 info->regs2d = ioremap(res->start, resource_size(res)); 1588 if (info->regs2d == NULL) { 1589 dev_err(dev, "cannot remap registers\n"); 1590 ret = -ENXIO; 1591 goto err_regs2d_res; 1592 } 1593 1594 /* allocate, reserve resources for framebuffer */ 1595 res = platform_get_resource(pdev, IORESOURCE_MEM, 2); 1596 if (res == NULL) { 1597 dev_err(dev, "no memory resource defined\n"); 1598 ret = -ENXIO; 1599 goto err_regs2d_map; 1600 } 1601 1602 info->fbmem_res = request_mem_region(res->start, 1603 resource_size(res), 1604 pdev->name); 1605 if (info->fbmem_res == NULL) { 1606 dev_err(dev, "cannot claim framebuffer\n"); 1607 ret = -ENXIO; 1608 goto err_regs2d_map; 1609 } 1610 1611 info->fbmem = ioremap(res->start, resource_size(res)); 1612 if (info->fbmem == NULL) { 1613 dev_err(dev, "cannot remap framebuffer\n"); 1614 ret = -ENXIO; 1615 goto err_mem_res; 1616 } 1617 1618 info->fbmem_len = resource_size(res); 1619 1620 /* clear framebuffer memory - avoids garbage data on unused fb */ 1621 memset_io(info->fbmem, 0, info->fbmem_len); 1622 1623 /* clear palette ram - undefined at power on */ 1624 for (k = 0; k < (256 * 3); k++) 1625 smc501_writel(0, info->regs + SM501_DC_PANEL_PALETTE + (k * 4)); 1626 1627 /* enable display controller */ 1628 sm501_unit_power(dev->parent, SM501_GATE_DISPLAY, 1); 1629 1630 /* enable 2d controller */ 1631 sm501_unit_power(dev->parent, SM501_GATE_2D_ENGINE, 1); 1632 1633 /* setup cursors */ 1634 sm501_init_cursor(info->fb[HEAD_CRT], SM501_DC_CRT_HWC_ADDR); 1635 sm501_init_cursor(info->fb[HEAD_PANEL], SM501_DC_PANEL_HWC_ADDR); 1636 1637 return 0; /* everything is setup */ 1638 1639 err_mem_res: 1640 release_mem_region(info->fbmem_res->start, 1641 resource_size(info->fbmem_res)); 1642 1643 err_regs2d_map: 1644 iounmap(info->regs2d); 1645 1646 err_regs2d_res: 1647 release_mem_region(info->regs2d_res->start, 1648 resource_size(info->regs2d_res)); 1649 1650 err_regs_map: 1651 iounmap(info->regs); 1652 1653 err_regs_res: 1654 release_mem_region(info->regs_res->start, 1655 resource_size(info->regs_res)); 1656 1657 err_release: 1658 return ret; 1659 } 1660 1661 static void sm501fb_stop(struct sm501fb_info *info) 1662 { 1663 /* disable display controller */ 1664 sm501_unit_power(info->dev->parent, SM501_GATE_DISPLAY, 0); 1665 1666 iounmap(info->fbmem); 1667 release_mem_region(info->fbmem_res->start, 1668 resource_size(info->fbmem_res)); 1669 1670 iounmap(info->regs2d); 1671 release_mem_region(info->regs2d_res->start, 1672 resource_size(info->regs2d_res)); 1673 1674 iounmap(info->regs); 1675 release_mem_region(info->regs_res->start, 1676 resource_size(info->regs_res)); 1677 } 1678 1679 static int sm501fb_init_fb(struct fb_info *fb, enum sm501_controller head, 1680 const char *fbname) 1681 { 1682 struct sm501_platdata_fbsub *pd; 1683 struct sm501fb_par *par = fb->par; 1684 struct sm501fb_info *info = par->info; 1685 unsigned long ctrl; 1686 unsigned int enable; 1687 int ret; 1688 1689 switch (head) { 1690 case HEAD_CRT: 1691 pd = info->pdata->fb_crt; 1692 ctrl = smc501_readl(info->regs + SM501_DC_CRT_CONTROL); 1693 enable = (ctrl & SM501_DC_CRT_CONTROL_ENABLE) ? 1 : 0; 1694 1695 /* ensure we set the correct source register */ 1696 if (info->pdata->fb_route != SM501_FB_CRT_PANEL) { 1697 ctrl |= SM501_DC_CRT_CONTROL_SEL; 1698 smc501_writel(ctrl, info->regs + SM501_DC_CRT_CONTROL); 1699 } 1700 1701 break; 1702 1703 case HEAD_PANEL: 1704 pd = info->pdata->fb_pnl; 1705 ctrl = smc501_readl(info->regs + SM501_DC_PANEL_CONTROL); 1706 enable = (ctrl & SM501_DC_PANEL_CONTROL_EN) ? 1 : 0; 1707 break; 1708 1709 default: 1710 pd = NULL; /* stop compiler warnings */ 1711 ctrl = 0; 1712 enable = 0; 1713 BUG(); 1714 } 1715 1716 dev_info(info->dev, "fb %s %s at start\n", 1717 fbname, str_enabled_disabled(enable)); 1718 1719 /* check to see if our routing allows this */ 1720 1721 if (head == HEAD_CRT && info->pdata->fb_route == SM501_FB_CRT_PANEL) { 1722 ctrl &= ~SM501_DC_CRT_CONTROL_SEL; 1723 smc501_writel(ctrl, info->regs + SM501_DC_CRT_CONTROL); 1724 enable = 0; 1725 } 1726 1727 strscpy(fb->fix.id, fbname, sizeof(fb->fix.id)); 1728 1729 memcpy(&par->ops, 1730 (head == HEAD_CRT) ? &sm501fb_ops_crt : &sm501fb_ops_pnl, 1731 sizeof(struct fb_ops)); 1732 1733 /* update ops dependent on what we've been passed */ 1734 1735 if ((pd->flags & SM501FB_FLAG_USE_HWCURSOR) == 0) 1736 par->ops.fb_cursor = NULL; 1737 1738 fb->fbops = &par->ops; 1739 fb->flags = FBINFO_READS_FAST | 1740 FBINFO_HWACCEL_COPYAREA | FBINFO_HWACCEL_FILLRECT | 1741 FBINFO_HWACCEL_XPAN | FBINFO_HWACCEL_YPAN; 1742 1743 #if defined(CONFIG_OF) 1744 #ifdef __BIG_ENDIAN 1745 if (of_property_read_bool(info->dev->parent->of_node, "little-endian")) 1746 fb->flags |= FBINFO_FOREIGN_ENDIAN; 1747 #else 1748 if (of_property_read_bool(info->dev->parent->of_node, "big-endian")) 1749 fb->flags |= FBINFO_FOREIGN_ENDIAN; 1750 #endif 1751 #endif 1752 /* fixed data */ 1753 1754 fb->fix.type = FB_TYPE_PACKED_PIXELS; 1755 fb->fix.type_aux = 0; 1756 fb->fix.xpanstep = 1; 1757 fb->fix.ypanstep = 1; 1758 fb->fix.ywrapstep = 0; 1759 fb->fix.accel = FB_ACCEL_NONE; 1760 1761 /* screenmode */ 1762 1763 fb->var.nonstd = 0; 1764 fb->var.activate = FB_ACTIVATE_NOW; 1765 fb->var.accel_flags = 0; 1766 fb->var.vmode = FB_VMODE_NONINTERLACED; 1767 fb->var.bits_per_pixel = 16; 1768 1769 if (info->edid_data) { 1770 /* Now build modedb from EDID */ 1771 fb_edid_to_monspecs(info->edid_data, &fb->monspecs); 1772 fb_videomode_to_modelist(fb->monspecs.modedb, 1773 fb->monspecs.modedb_len, 1774 &fb->modelist); 1775 } 1776 1777 if (enable && (pd->flags & SM501FB_FLAG_USE_INIT_MODE) && 0) { 1778 /* TODO read the mode from the current display */ 1779 } else { 1780 if (pd->def_mode) { 1781 dev_info(info->dev, "using supplied mode\n"); 1782 fb_videomode_to_var(&fb->var, pd->def_mode); 1783 1784 fb->var.bits_per_pixel = pd->def_bpp ? pd->def_bpp : 8; 1785 fb->var.xres_virtual = fb->var.xres; 1786 fb->var.yres_virtual = fb->var.yres; 1787 } else { 1788 if (info->edid_data) { 1789 ret = fb_find_mode(&fb->var, fb, fb_mode, 1790 fb->monspecs.modedb, 1791 fb->monspecs.modedb_len, 1792 &sm501_default_mode, default_bpp); 1793 /* edid_data is no longer needed, free it */ 1794 kfree(info->edid_data); 1795 } else { 1796 ret = fb_find_mode(&fb->var, fb, 1797 NULL, NULL, 0, NULL, 8); 1798 } 1799 1800 switch (ret) { 1801 case 1: 1802 dev_info(info->dev, "using mode specified in " 1803 "@mode\n"); 1804 break; 1805 case 2: 1806 dev_info(info->dev, "using mode specified in " 1807 "@mode with ignored refresh rate\n"); 1808 break; 1809 case 3: 1810 dev_info(info->dev, "using mode default " 1811 "mode\n"); 1812 break; 1813 case 4: 1814 dev_info(info->dev, "using mode from list\n"); 1815 break; 1816 default: 1817 dev_info(info->dev, "ret = %d\n", ret); 1818 dev_info(info->dev, "failed to find mode\n"); 1819 return -EINVAL; 1820 } 1821 } 1822 } 1823 1824 /* initialise and set the palette */ 1825 if (fb_alloc_cmap(&fb->cmap, NR_PALETTE, 0)) { 1826 dev_err(info->dev, "failed to allocate cmap memory\n"); 1827 return -ENOMEM; 1828 } 1829 fb_set_cmap(&fb->cmap, fb); 1830 1831 ret = (fb->fbops->fb_check_var)(&fb->var, fb); 1832 if (ret) 1833 dev_err(info->dev, "check_var() failed on initial setup?\n"); 1834 1835 return 0; 1836 } 1837 1838 /* default platform data if none is supplied (ie, PCI device) */ 1839 1840 static struct sm501_platdata_fbsub sm501fb_pdata_crt = { 1841 .flags = (SM501FB_FLAG_USE_INIT_MODE | 1842 SM501FB_FLAG_USE_HWCURSOR | 1843 SM501FB_FLAG_USE_HWACCEL | 1844 SM501FB_FLAG_DISABLE_AT_EXIT), 1845 1846 }; 1847 1848 static struct sm501_platdata_fbsub sm501fb_pdata_pnl = { 1849 .flags = (SM501FB_FLAG_USE_INIT_MODE | 1850 SM501FB_FLAG_USE_HWCURSOR | 1851 SM501FB_FLAG_USE_HWACCEL | 1852 SM501FB_FLAG_DISABLE_AT_EXIT), 1853 }; 1854 1855 static struct sm501_platdata_fb sm501fb_def_pdata = { 1856 .fb_route = SM501_FB_OWN, 1857 .fb_crt = &sm501fb_pdata_crt, 1858 .fb_pnl = &sm501fb_pdata_pnl, 1859 }; 1860 1861 static char driver_name_crt[] = "sm501fb-crt"; 1862 static char driver_name_pnl[] = "sm501fb-panel"; 1863 1864 static int sm501fb_probe_one(struct sm501fb_info *info, 1865 enum sm501_controller head) 1866 { 1867 unsigned char *name = (head == HEAD_CRT) ? "crt" : "panel"; 1868 struct sm501_platdata_fbsub *pd; 1869 struct sm501fb_par *par; 1870 struct fb_info *fbi; 1871 1872 pd = (head == HEAD_CRT) ? info->pdata->fb_crt : info->pdata->fb_pnl; 1873 1874 /* Do not initialise if we've not been given any platform data */ 1875 if (pd == NULL) { 1876 dev_info(info->dev, "no data for fb %s (disabled)\n", name); 1877 return 0; 1878 } 1879 1880 fbi = framebuffer_alloc(sizeof(struct sm501fb_par), info->dev); 1881 if (!fbi) 1882 return -ENOMEM; 1883 1884 par = fbi->par; 1885 par->info = info; 1886 par->head = head; 1887 fbi->pseudo_palette = &par->pseudo_palette; 1888 1889 info->fb[head] = fbi; 1890 1891 return 0; 1892 } 1893 1894 /* Free up anything allocated by sm501fb_init_fb */ 1895 1896 static void sm501_free_init_fb(struct sm501fb_info *info, 1897 enum sm501_controller head) 1898 { 1899 struct fb_info *fbi = info->fb[head]; 1900 1901 if (!fbi) 1902 return; 1903 1904 fb_dealloc_cmap(&fbi->cmap); 1905 } 1906 1907 static int sm501fb_start_one(struct sm501fb_info *info, 1908 enum sm501_controller head, const char *drvname) 1909 { 1910 struct fb_info *fbi = info->fb[head]; 1911 int ret; 1912 1913 if (!fbi) 1914 return 0; 1915 1916 mutex_init(&info->fb[head]->mm_lock); 1917 1918 ret = sm501fb_init_fb(info->fb[head], head, drvname); 1919 if (ret) { 1920 dev_err(info->dev, "cannot initialise fb %s\n", drvname); 1921 return ret; 1922 } 1923 1924 ret = register_framebuffer(info->fb[head]); 1925 if (ret) { 1926 dev_err(info->dev, "failed to register fb %s\n", drvname); 1927 sm501_free_init_fb(info, head); 1928 return ret; 1929 } 1930 1931 dev_info(info->dev, "fb%d: %s frame buffer\n", fbi->node, fbi->fix.id); 1932 1933 return 0; 1934 } 1935 1936 static int sm501fb_probe(struct platform_device *pdev) 1937 { 1938 struct sm501fb_info *info; 1939 struct device *dev = &pdev->dev; 1940 int ret; 1941 1942 /* allocate our framebuffers */ 1943 info = kzalloc(sizeof(*info), GFP_KERNEL); 1944 if (!info) { 1945 dev_err(dev, "failed to allocate state\n"); 1946 return -ENOMEM; 1947 } 1948 1949 info->dev = dev = &pdev->dev; 1950 platform_set_drvdata(pdev, info); 1951 1952 if (dev->parent->platform_data) { 1953 struct sm501_platdata *pd = dev->parent->platform_data; 1954 info->pdata = pd->fb; 1955 } 1956 1957 if (info->pdata == NULL) { 1958 int found = 0; 1959 #if defined(CONFIG_OF) 1960 struct device_node *np = pdev->dev.parent->of_node; 1961 const u8 *prop; 1962 const char *cp; 1963 int len; 1964 1965 info->pdata = &sm501fb_def_pdata; 1966 if (np) { 1967 /* Get EDID */ 1968 cp = of_get_property(np, "mode", &len); 1969 if (cp) 1970 strcpy(fb_mode, cp); 1971 prop = of_get_property(np, "edid", &len); 1972 if (prop && len == EDID_LENGTH) { 1973 info->edid_data = kmemdup(prop, EDID_LENGTH, 1974 GFP_KERNEL); 1975 if (info->edid_data) 1976 found = 1; 1977 } 1978 } 1979 #endif 1980 if (!found) { 1981 dev_info(dev, "using default configuration data\n"); 1982 info->pdata = &sm501fb_def_pdata; 1983 } 1984 } 1985 1986 /* probe for the presence of each panel */ 1987 1988 ret = sm501fb_probe_one(info, HEAD_CRT); 1989 if (ret < 0) { 1990 dev_err(dev, "failed to probe CRT\n"); 1991 goto err_alloc; 1992 } 1993 1994 ret = sm501fb_probe_one(info, HEAD_PANEL); 1995 if (ret < 0) { 1996 dev_err(dev, "failed to probe PANEL\n"); 1997 goto err_probed_crt; 1998 } 1999 2000 if (info->fb[HEAD_PANEL] == NULL && 2001 info->fb[HEAD_CRT] == NULL) { 2002 dev_err(dev, "no framebuffers found\n"); 2003 ret = -ENODEV; 2004 goto err_alloc; 2005 } 2006 2007 /* get the resources for both of the framebuffers */ 2008 2009 ret = sm501fb_start(info, pdev); 2010 if (ret) { 2011 dev_err(dev, "cannot initialise SM501\n"); 2012 goto err_probed_panel; 2013 } 2014 2015 ret = sm501fb_start_one(info, HEAD_CRT, driver_name_crt); 2016 if (ret) { 2017 dev_err(dev, "failed to start CRT\n"); 2018 goto err_started; 2019 } 2020 2021 ret = sm501fb_start_one(info, HEAD_PANEL, driver_name_pnl); 2022 if (ret) { 2023 dev_err(dev, "failed to start Panel\n"); 2024 goto err_started_crt; 2025 } 2026 2027 /* we registered, return ok */ 2028 return 0; 2029 2030 err_started_crt: 2031 unregister_framebuffer(info->fb[HEAD_CRT]); 2032 sm501_free_init_fb(info, HEAD_CRT); 2033 2034 err_started: 2035 sm501fb_stop(info); 2036 2037 err_probed_panel: 2038 framebuffer_release(info->fb[HEAD_PANEL]); 2039 2040 err_probed_crt: 2041 framebuffer_release(info->fb[HEAD_CRT]); 2042 2043 err_alloc: 2044 kfree(info); 2045 2046 return ret; 2047 } 2048 2049 2050 /* 2051 * Cleanup 2052 */ 2053 static void sm501fb_remove(struct platform_device *pdev) 2054 { 2055 struct sm501fb_info *info = platform_get_drvdata(pdev); 2056 struct fb_info *fbinfo_crt = info->fb[0]; 2057 struct fb_info *fbinfo_pnl = info->fb[1]; 2058 2059 sm501_free_init_fb(info, HEAD_CRT); 2060 sm501_free_init_fb(info, HEAD_PANEL); 2061 2062 if (fbinfo_crt) 2063 unregister_framebuffer(fbinfo_crt); 2064 if (fbinfo_pnl) 2065 unregister_framebuffer(fbinfo_pnl); 2066 2067 sm501fb_stop(info); 2068 kfree(info); 2069 2070 framebuffer_release(fbinfo_pnl); 2071 framebuffer_release(fbinfo_crt); 2072 } 2073 2074 #ifdef CONFIG_PM 2075 2076 static int sm501fb_suspend_fb(struct sm501fb_info *info, 2077 enum sm501_controller head) 2078 { 2079 struct fb_info *fbi = info->fb[head]; 2080 struct sm501fb_par *par; 2081 2082 if (!fbi) 2083 return 0; 2084 2085 par = fbi->par; 2086 if (par->screen.size == 0) 2087 return 0; 2088 2089 /* blank the relevant interface to ensure unit power minimised */ 2090 (par->ops.fb_blank)(FB_BLANK_POWERDOWN, fbi); 2091 2092 /* tell console/fb driver we are suspending */ 2093 2094 console_lock(); 2095 fb_set_suspend(fbi, 1); 2096 console_unlock(); 2097 2098 /* backup copies in case chip is powered down over suspend */ 2099 2100 par->store_fb = vmalloc(par->screen.size); 2101 if (par->store_fb == NULL) { 2102 dev_err(info->dev, "no memory to store screen\n"); 2103 return -ENOMEM; 2104 } 2105 2106 par->store_cursor = vmalloc(par->cursor.size); 2107 if (par->store_cursor == NULL) { 2108 dev_err(info->dev, "no memory to store cursor\n"); 2109 goto err_nocursor; 2110 } 2111 2112 dev_dbg(info->dev, "suspending screen to %p\n", par->store_fb); 2113 dev_dbg(info->dev, "suspending cursor to %p\n", par->store_cursor); 2114 2115 memcpy_fromio(par->store_fb, par->screen.k_addr, par->screen.size); 2116 memcpy_fromio(par->store_cursor, par->cursor.k_addr, par->cursor.size); 2117 2118 return 0; 2119 2120 err_nocursor: 2121 vfree(par->store_fb); 2122 par->store_fb = NULL; 2123 2124 return -ENOMEM; 2125 } 2126 2127 static void sm501fb_resume_fb(struct sm501fb_info *info, 2128 enum sm501_controller head) 2129 { 2130 struct fb_info *fbi = info->fb[head]; 2131 struct sm501fb_par *par; 2132 2133 if (!fbi) 2134 return; 2135 2136 par = fbi->par; 2137 if (par->screen.size == 0) 2138 return; 2139 2140 /* re-activate the configuration */ 2141 2142 (par->ops.fb_set_par)(fbi); 2143 2144 /* restore the data */ 2145 2146 dev_dbg(info->dev, "restoring screen from %p\n", par->store_fb); 2147 dev_dbg(info->dev, "restoring cursor from %p\n", par->store_cursor); 2148 2149 if (par->store_fb) 2150 memcpy_toio(par->screen.k_addr, par->store_fb, 2151 par->screen.size); 2152 2153 if (par->store_cursor) 2154 memcpy_toio(par->cursor.k_addr, par->store_cursor, 2155 par->cursor.size); 2156 2157 console_lock(); 2158 fb_set_suspend(fbi, 0); 2159 console_unlock(); 2160 2161 vfree(par->store_fb); 2162 vfree(par->store_cursor); 2163 } 2164 2165 2166 /* suspend and resume support */ 2167 2168 static int sm501fb_suspend(struct platform_device *pdev, pm_message_t state) 2169 { 2170 struct sm501fb_info *info = platform_get_drvdata(pdev); 2171 2172 /* store crt control to resume with */ 2173 info->pm_crt_ctrl = smc501_readl(info->regs + SM501_DC_CRT_CONTROL); 2174 2175 sm501fb_suspend_fb(info, HEAD_CRT); 2176 sm501fb_suspend_fb(info, HEAD_PANEL); 2177 2178 /* turn off the clocks, in case the device is not powered down */ 2179 sm501_unit_power(info->dev->parent, SM501_GATE_DISPLAY, 0); 2180 2181 return 0; 2182 } 2183 2184 #define SM501_CRT_CTRL_SAVE (SM501_DC_CRT_CONTROL_TVP | \ 2185 SM501_DC_CRT_CONTROL_SEL) 2186 2187 2188 static int sm501fb_resume(struct platform_device *pdev) 2189 { 2190 struct sm501fb_info *info = platform_get_drvdata(pdev); 2191 unsigned long crt_ctrl; 2192 2193 sm501_unit_power(info->dev->parent, SM501_GATE_DISPLAY, 1); 2194 2195 /* restore the items we want to be saved for crt control */ 2196 2197 crt_ctrl = smc501_readl(info->regs + SM501_DC_CRT_CONTROL); 2198 crt_ctrl &= ~SM501_CRT_CTRL_SAVE; 2199 crt_ctrl |= info->pm_crt_ctrl & SM501_CRT_CTRL_SAVE; 2200 smc501_writel(crt_ctrl, info->regs + SM501_DC_CRT_CONTROL); 2201 2202 sm501fb_resume_fb(info, HEAD_CRT); 2203 sm501fb_resume_fb(info, HEAD_PANEL); 2204 2205 return 0; 2206 } 2207 2208 #else 2209 #define sm501fb_suspend NULL 2210 #define sm501fb_resume NULL 2211 #endif 2212 2213 static struct platform_driver sm501fb_driver = { 2214 .probe = sm501fb_probe, 2215 .remove = sm501fb_remove, 2216 .suspend = sm501fb_suspend, 2217 .resume = sm501fb_resume, 2218 .driver = { 2219 .name = "sm501-fb", 2220 .dev_groups = sm501fb_groups, 2221 }, 2222 }; 2223 2224 module_platform_driver(sm501fb_driver); 2225 2226 module_param_named(mode, fb_mode, charp, 0); 2227 MODULE_PARM_DESC(mode, 2228 "Specify resolution as \"<xres>x<yres>[-<bpp>][@<refresh>]\" "); 2229 module_param_named(bpp, default_bpp, ulong, 0); 2230 MODULE_PARM_DESC(bpp, "Specify bit-per-pixel if not specified mode"); 2231 MODULE_AUTHOR("Ben Dooks, Vincent Sanders"); 2232 MODULE_DESCRIPTION("SM501 Framebuffer driver"); 2233 MODULE_LICENSE("GPL v2"); 2234