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