1 #include <linux/kernel.h> 2 #include <linux/module.h> 3 #include <linux/errno.h> 4 #include <linux/string.h> 5 #include <linux/mm.h> 6 #include <linux/slab.h> 7 #include <linux/delay.h> 8 #include <linux/fb.h> 9 #include <linux/ioport.h> 10 #include <linux/init.h> 11 #include <linux/pci.h> 12 #include <linux/mm_types.h> 13 #include <linux/vmalloc.h> 14 #include <linux/pagemap.h> 15 #include <linux/screen_info.h> 16 #include <linux/console.h> 17 #include <asm/fb.h> 18 #include "sm750.h" 19 #include "sm750_accel.h" 20 #include "sm750_cursor.h" 21 22 /* 23 * #ifdef __BIG_ENDIAN 24 * ssize_t lynxfb_ops_write(struct fb_info *info, const char __user *buf, 25 * size_t count, loff_t *ppos); 26 * ssize_t lynxfb_ops_read(struct fb_info *info, char __user *buf, 27 * size_t count, loff_t *ppos); 28 * #endif 29 */ 30 31 /* common var for all device */ 32 static int g_hwcursor = 1; 33 static int g_noaccel; 34 static int g_nomtrr; 35 static const char *g_fbmode[] = {NULL, NULL}; 36 static const char *g_def_fbmode = "1024x768-32@60"; 37 static char *g_settings; 38 static int g_dualview; 39 static char *g_option; 40 41 static const struct fb_videomode lynx750_ext[] = { 42 /* 1024x600-60 VESA [1.71:1] */ 43 {NULL, 60, 1024, 600, 20423, 144, 40, 18, 1, 104, 3, 44 FB_SYNC_HOR_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT, 45 FB_VMODE_NONINTERLACED}, 46 47 /* 1024x600-70 VESA */ 48 {NULL, 70, 1024, 600, 17211, 152, 48, 21, 1, 104, 3, 49 FB_SYNC_HOR_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT, 50 FB_VMODE_NONINTERLACED}, 51 52 /* 1024x600-75 VESA */ 53 {NULL, 75, 1024, 600, 15822, 160, 56, 23, 1, 104, 3, 54 FB_SYNC_HOR_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT, 55 FB_VMODE_NONINTERLACED}, 56 57 /* 1024x600-85 VESA */ 58 {NULL, 85, 1024, 600, 13730, 168, 56, 26, 1, 112, 3, 59 FB_SYNC_HOR_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT, 60 FB_VMODE_NONINTERLACED}, 61 62 /* 720x480 */ 63 {NULL, 60, 720, 480, 37427, 88, 16, 13, 1, 72, 3, 64 FB_SYNC_HOR_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT, 65 FB_VMODE_NONINTERLACED}, 66 67 /* 1280x720 [1.78:1] */ 68 {NULL, 60, 1280, 720, 13426, 162, 86, 22, 1, 136, 3, 69 FB_SYNC_HOR_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT, 70 FB_VMODE_NONINTERLACED}, 71 72 /* 1280x768@60 */ 73 {NULL, 60, 1280, 768, 12579, 192, 64, 20, 3, 128, 7, 74 FB_SYNC_HOR_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT, 75 FB_VMODE_NONINTERLACED}, 76 77 /* 1360 x 768 [1.77083:1] */ 78 {NULL, 60, 1360, 768, 11804, 208, 64, 23, 1, 144, 3, 79 FB_SYNC_HOR_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT, 80 FB_VMODE_NONINTERLACED}, 81 82 /* 1368 x 768 [1.78:1] */ 83 {NULL, 60, 1368, 768, 11647, 216, 72, 23, 1, 144, 3, 84 FB_SYNC_HOR_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT, 85 FB_VMODE_NONINTERLACED}, 86 87 /* 1440 x 900 [16:10] */ 88 {NULL, 60, 1440, 900, 9392, 232, 80, 28, 1, 152, 3, 89 FB_SYNC_VERT_HIGH_ACT, 90 FB_VMODE_NONINTERLACED}, 91 92 /* 1440x960 [15:10] */ 93 {NULL, 60, 1440, 960, 8733, 240, 88, 30, 1, 152, 3, 94 FB_SYNC_HOR_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT, 95 FB_VMODE_NONINTERLACED}, 96 97 /* 1920x1080 [16:9] */ 98 {NULL, 60, 1920, 1080, 6734, 148, 88, 41, 1, 44, 3, 99 FB_SYNC_VERT_HIGH_ACT, 100 FB_VMODE_NONINTERLACED}, 101 }; 102 103 /* no hardware cursor supported under version 2.6.10, kernel bug */ 104 static int lynxfb_ops_cursor(struct fb_info *info, struct fb_cursor *fbcursor) 105 { 106 struct lynxfb_par *par; 107 struct lynxfb_crtc *crtc; 108 struct lynx_cursor *cursor; 109 110 par = info->par; 111 crtc = &par->crtc; 112 cursor = &crtc->cursor; 113 114 if (fbcursor->image.width > cursor->maxW || 115 fbcursor->image.height > cursor->maxH || 116 fbcursor->image.depth > 1) { 117 return -ENXIO; 118 } 119 120 sm750_hw_cursor_disable(cursor); 121 if (fbcursor->set & FB_CUR_SETSIZE) 122 sm750_hw_cursor_setSize(cursor, 123 fbcursor->image.width, 124 fbcursor->image.height); 125 126 if (fbcursor->set & FB_CUR_SETPOS) 127 sm750_hw_cursor_setPos(cursor, 128 fbcursor->image.dx - info->var.xoffset, 129 fbcursor->image.dy - info->var.yoffset); 130 131 if (fbcursor->set & FB_CUR_SETCMAP) { 132 /* get the 16bit color of kernel means */ 133 u16 fg, bg; 134 135 fg = ((info->cmap.red[fbcursor->image.fg_color] & 0xf800)) | 136 ((info->cmap.green[fbcursor->image.fg_color] & 0xfc00) >> 5) | 137 ((info->cmap.blue[fbcursor->image.fg_color] & 0xf800) >> 11); 138 139 bg = ((info->cmap.red[fbcursor->image.bg_color] & 0xf800)) | 140 ((info->cmap.green[fbcursor->image.bg_color] & 0xfc00) >> 5) | 141 ((info->cmap.blue[fbcursor->image.bg_color] & 0xf800) >> 11); 142 143 sm750_hw_cursor_setColor(cursor, fg, bg); 144 } 145 146 if (fbcursor->set & (FB_CUR_SETSHAPE | FB_CUR_SETIMAGE)) { 147 sm750_hw_cursor_setData(cursor, 148 fbcursor->rop, 149 fbcursor->image.data, 150 fbcursor->mask); 151 } 152 153 if (fbcursor->enable) 154 sm750_hw_cursor_enable(cursor); 155 156 return 0; 157 } 158 159 static void lynxfb_ops_fillrect(struct fb_info *info, 160 const struct fb_fillrect *region) 161 { 162 struct lynxfb_par *par; 163 struct sm750_dev *sm750_dev; 164 unsigned int base, pitch, Bpp, rop; 165 u32 color; 166 167 if (info->state != FBINFO_STATE_RUNNING) 168 return; 169 170 par = info->par; 171 sm750_dev = par->dev; 172 173 /* 174 * each time 2d function begin to work,below three variable always need 175 * be set, seems we can put them together in some place 176 */ 177 base = par->crtc.oScreen; 178 pitch = info->fix.line_length; 179 Bpp = info->var.bits_per_pixel >> 3; 180 181 color = (Bpp == 1) ? region->color : 182 ((u32 *)info->pseudo_palette)[region->color]; 183 rop = (region->rop != ROP_COPY) ? HW_ROP2_XOR : HW_ROP2_COPY; 184 185 /* 186 * If not use spin_lock, system will die if user load driver 187 * and immediately unload driver frequently (dual) 188 * since they fb_count could change during the lifetime of 189 * this lock, we are holding it for all cases. 190 */ 191 spin_lock(&sm750_dev->slock); 192 193 sm750_dev->accel.de_fillrect(&sm750_dev->accel, 194 base, pitch, Bpp, 195 region->dx, region->dy, 196 region->width, region->height, 197 color, rop); 198 spin_unlock(&sm750_dev->slock); 199 } 200 201 static void lynxfb_ops_copyarea(struct fb_info *info, 202 const struct fb_copyarea *region) 203 { 204 struct lynxfb_par *par; 205 struct sm750_dev *sm750_dev; 206 unsigned int base, pitch, Bpp; 207 208 par = info->par; 209 sm750_dev = par->dev; 210 211 /* 212 * each time 2d function begin to work,below three variable always need 213 * be set, seems we can put them together in some place 214 */ 215 base = par->crtc.oScreen; 216 pitch = info->fix.line_length; 217 Bpp = info->var.bits_per_pixel >> 3; 218 219 /* 220 * If not use spin_lock, system will die if user load driver 221 * and immediately unload driver frequently (dual) 222 * since they fb_count could change during the lifetime of 223 * this lock, we are holding it for all cases. 224 */ 225 spin_lock(&sm750_dev->slock); 226 227 sm750_dev->accel.de_copyarea(&sm750_dev->accel, 228 base, pitch, region->sx, region->sy, 229 base, pitch, Bpp, region->dx, region->dy, 230 region->width, region->height, 231 HW_ROP2_COPY); 232 spin_unlock(&sm750_dev->slock); 233 } 234 235 static void lynxfb_ops_imageblit(struct fb_info *info, 236 const struct fb_image *image) 237 { 238 unsigned int base, pitch, Bpp; 239 unsigned int fgcol, bgcol; 240 struct lynxfb_par *par; 241 struct sm750_dev *sm750_dev; 242 243 par = info->par; 244 sm750_dev = par->dev; 245 /* 246 * each time 2d function begin to work,below three variable always need 247 * be set, seems we can put them together in some place 248 */ 249 base = par->crtc.oScreen; 250 pitch = info->fix.line_length; 251 Bpp = info->var.bits_per_pixel >> 3; 252 253 /* TODO: Implement hardware acceleration for image->depth > 1 */ 254 if (image->depth != 1) { 255 cfb_imageblit(info, image); 256 return; 257 } 258 259 if (info->fix.visual == FB_VISUAL_TRUECOLOR || 260 info->fix.visual == FB_VISUAL_DIRECTCOLOR) { 261 fgcol = ((u32 *)info->pseudo_palette)[image->fg_color]; 262 bgcol = ((u32 *)info->pseudo_palette)[image->bg_color]; 263 } else { 264 fgcol = image->fg_color; 265 bgcol = image->bg_color; 266 } 267 268 /* 269 * If not use spin_lock, system will die if user load driver 270 * and immediately unload driver frequently (dual) 271 * since they fb_count could change during the lifetime of 272 * this lock, we are holding it for all cases. 273 */ 274 spin_lock(&sm750_dev->slock); 275 276 sm750_dev->accel.de_imageblit(&sm750_dev->accel, 277 image->data, image->width >> 3, 0, 278 base, pitch, Bpp, 279 image->dx, image->dy, 280 image->width, image->height, 281 fgcol, bgcol, HW_ROP2_COPY); 282 spin_unlock(&sm750_dev->slock); 283 } 284 285 static int lynxfb_ops_pan_display(struct fb_var_screeninfo *var, 286 struct fb_info *info) 287 { 288 struct lynxfb_par *par; 289 struct lynxfb_crtc *crtc; 290 291 if (!info) 292 return -EINVAL; 293 294 par = info->par; 295 crtc = &par->crtc; 296 return hw_sm750_pan_display(crtc, var, info); 297 } 298 299 static int lynxfb_ops_set_par(struct fb_info *info) 300 { 301 struct lynxfb_par *par; 302 struct lynxfb_crtc *crtc; 303 struct lynxfb_output *output; 304 struct fb_var_screeninfo *var; 305 struct fb_fix_screeninfo *fix; 306 int ret; 307 unsigned int line_length; 308 309 if (!info) 310 return -EINVAL; 311 312 ret = 0; 313 par = info->par; 314 crtc = &par->crtc; 315 output = &par->output; 316 var = &info->var; 317 fix = &info->fix; 318 319 /* fix structure is not so FIX ... */ 320 line_length = var->xres_virtual * var->bits_per_pixel / 8; 321 line_length = ALIGN(line_length, crtc->line_pad); 322 fix->line_length = line_length; 323 pr_info("fix->line_length = %d\n", fix->line_length); 324 325 /* 326 * var->red,green,blue,transp are need to be set by driver 327 * and these data should be set before setcolreg routine 328 */ 329 330 switch (var->bits_per_pixel) { 331 case 8: 332 fix->visual = FB_VISUAL_PSEUDOCOLOR; 333 var->red.offset = 0; 334 var->red.length = 8; 335 var->green.offset = 0; 336 var->green.length = 8; 337 var->blue.offset = 0; 338 var->blue.length = 8; 339 var->transp.length = 0; 340 var->transp.offset = 0; 341 break; 342 case 16: 343 var->red.offset = 11; 344 var->red.length = 5; 345 var->green.offset = 5; 346 var->green.length = 6; 347 var->blue.offset = 0; 348 var->blue.length = 5; 349 var->transp.length = 0; 350 var->transp.offset = 0; 351 fix->visual = FB_VISUAL_TRUECOLOR; 352 break; 353 case 24: 354 case 32: 355 var->red.offset = 16; 356 var->red.length = 8; 357 var->green.offset = 8; 358 var->green.length = 8; 359 var->blue.offset = 0; 360 var->blue.length = 8; 361 fix->visual = FB_VISUAL_TRUECOLOR; 362 break; 363 default: 364 ret = -EINVAL; 365 break; 366 } 367 var->height = var->width = -1; 368 var->accel_flags = 0;/*FB_ACCELF_TEXT;*/ 369 370 if (ret) { 371 pr_err("pixel bpp format not satisfied\n."); 372 return ret; 373 } 374 ret = hw_sm750_crtc_setMode(crtc, var, fix); 375 if (!ret) 376 ret = hw_sm750_output_setMode(output, var, fix); 377 return ret; 378 } 379 380 static inline unsigned int chan_to_field(unsigned int chan, 381 struct fb_bitfield *bf) 382 { 383 chan &= 0xffff; 384 chan >>= 16 - bf->length; 385 return chan << bf->offset; 386 } 387 388 #ifdef CONFIG_PM 389 static int lynxfb_suspend(struct pci_dev *pdev, pm_message_t mesg) 390 { 391 struct fb_info *info; 392 struct sm750_dev *sm750_dev; 393 int ret; 394 395 if (mesg.event == pdev->dev.power.power_state.event) 396 return 0; 397 398 ret = 0; 399 sm750_dev = pci_get_drvdata(pdev); 400 switch (mesg.event) { 401 case PM_EVENT_FREEZE: 402 case PM_EVENT_PRETHAW: 403 pdev->dev.power.power_state = mesg; 404 return 0; 405 } 406 407 console_lock(); 408 if (mesg.event & PM_EVENT_SLEEP) { 409 info = sm750_dev->fbinfo[0]; 410 if (info) 411 /* 1 means do suspend */ 412 fb_set_suspend(info, 1); 413 info = sm750_dev->fbinfo[1]; 414 if (info) 415 /* 1 means do suspend */ 416 fb_set_suspend(info, 1); 417 418 ret = pci_save_state(pdev); 419 if (ret) { 420 dev_err(&pdev->dev, 421 "error:%d occurred in pci_save_state\n", ret); 422 goto lynxfb_suspend_err; 423 } 424 425 ret = pci_set_power_state(pdev, pci_choose_state(pdev, mesg)); 426 if (ret) { 427 dev_err(&pdev->dev, 428 "error:%d occurred in pci_set_power_state\n", 429 ret); 430 goto lynxfb_suspend_err; 431 } 432 } 433 434 pdev->dev.power.power_state = mesg; 435 436 lynxfb_suspend_err: 437 console_unlock(); 438 return ret; 439 } 440 441 static int lynxfb_resume(struct pci_dev *pdev) 442 { 443 struct fb_info *info; 444 struct sm750_dev *sm750_dev; 445 446 struct lynxfb_par *par; 447 struct lynxfb_crtc *crtc; 448 struct lynx_cursor *cursor; 449 450 int ret; 451 452 ret = 0; 453 sm750_dev = pci_get_drvdata(pdev); 454 455 console_lock(); 456 457 ret = pci_set_power_state(pdev, PCI_D0); 458 if (ret) { 459 dev_err(&pdev->dev, 460 "error:%d occurred in pci_set_power_state\n", ret); 461 goto lynxfb_resume_err; 462 } 463 464 if (pdev->dev.power.power_state.event != PM_EVENT_FREEZE) { 465 pci_restore_state(pdev); 466 ret = pci_enable_device(pdev); 467 if (ret) { 468 dev_err(&pdev->dev, 469 "error:%d occurred in pci_enable_device\n", 470 ret); 471 goto lynxfb_resume_err; 472 } 473 pci_set_master(pdev); 474 } 475 476 hw_sm750_inithw(sm750_dev, pdev); 477 478 info = sm750_dev->fbinfo[0]; 479 480 if (info) { 481 par = info->par; 482 crtc = &par->crtc; 483 cursor = &crtc->cursor; 484 memset_io(cursor->vstart, 0x0, cursor->size); 485 memset_io(crtc->vScreen, 0x0, crtc->vidmem_size); 486 lynxfb_ops_set_par(info); 487 fb_set_suspend(info, 0); 488 } 489 490 info = sm750_dev->fbinfo[1]; 491 492 if (info) { 493 par = info->par; 494 crtc = &par->crtc; 495 cursor = &crtc->cursor; 496 memset_io(cursor->vstart, 0x0, cursor->size); 497 memset_io(crtc->vScreen, 0x0, crtc->vidmem_size); 498 lynxfb_ops_set_par(info); 499 fb_set_suspend(info, 0); 500 } 501 502 pdev->dev.power.power_state.event = PM_EVENT_RESUME; 503 504 lynxfb_resume_err: 505 console_unlock(); 506 return ret; 507 } 508 #endif 509 510 static int lynxfb_ops_check_var(struct fb_var_screeninfo *var, 511 struct fb_info *info) 512 { 513 struct lynxfb_par *par; 514 struct lynxfb_crtc *crtc; 515 resource_size_t request; 516 517 par = info->par; 518 crtc = &par->crtc; 519 520 pr_debug("check var:%dx%d-%d\n", 521 var->xres, 522 var->yres, 523 var->bits_per_pixel); 524 525 switch (var->bits_per_pixel) { 526 case 8: 527 info->fix.visual = FB_VISUAL_PSEUDOCOLOR; 528 var->red.offset = 0; 529 var->red.length = 8; 530 var->green.offset = 0; 531 var->green.length = 8; 532 var->blue.offset = 0; 533 var->blue.length = 8; 534 var->transp.length = 0; 535 var->transp.offset = 0; 536 break; 537 case 16: 538 var->red.offset = 11; 539 var->red.length = 5; 540 var->green.offset = 5; 541 var->green.length = 6; 542 var->blue.offset = 0; 543 var->blue.length = 5; 544 var->transp.length = 0; 545 var->transp.offset = 0; 546 info->fix.visual = FB_VISUAL_TRUECOLOR; 547 break; 548 case 24: 549 case 32: 550 var->red.offset = 16; 551 var->red.length = 8; 552 var->green.offset = 8; 553 var->green.length = 8; 554 var->blue.offset = 0; 555 var->blue.length = 8; 556 info->fix.visual = FB_VISUAL_TRUECOLOR; 557 break; 558 default: 559 pr_err("bpp %d not supported\n", var->bits_per_pixel); 560 return -EINVAL; 561 } 562 var->height = var->width = -1; 563 var->accel_flags = 0;/* FB_ACCELF_TEXT; */ 564 565 /* check if current fb's video memory big enought to hold the onscreen*/ 566 request = var->xres_virtual * (var->bits_per_pixel >> 3); 567 /* defaulty crtc->channel go with par->index */ 568 569 request = ALIGN(request, crtc->line_pad); 570 request = request * var->yres_virtual; 571 if (crtc->vidmem_size < request) { 572 pr_err("not enough video memory for mode\n"); 573 return -ENOMEM; 574 } 575 576 return hw_sm750_crtc_checkMode(crtc, var); 577 } 578 579 static int lynxfb_ops_setcolreg(unsigned int regno, 580 unsigned int red, 581 unsigned int green, 582 unsigned int blue, 583 unsigned int transp, 584 struct fb_info *info) 585 { 586 struct lynxfb_par *par; 587 struct lynxfb_crtc *crtc; 588 struct fb_var_screeninfo *var; 589 int ret; 590 591 par = info->par; 592 crtc = &par->crtc; 593 var = &info->var; 594 ret = 0; 595 596 if (regno > 256) { 597 pr_err("regno = %d\n", regno); 598 return -EINVAL; 599 } 600 601 if (info->var.grayscale) 602 red = green = blue = (red * 77 + green * 151 + blue * 28) >> 8; 603 604 if (var->bits_per_pixel == 8 && 605 info->fix.visual == FB_VISUAL_PSEUDOCOLOR) { 606 red >>= 8; 607 green >>= 8; 608 blue >>= 8; 609 ret = hw_sm750_setColReg(crtc, regno, red, green, blue); 610 goto exit; 611 } 612 613 if (info->fix.visual == FB_VISUAL_TRUECOLOR && regno < 256) { 614 u32 val; 615 616 if (var->bits_per_pixel == 16 || 617 var->bits_per_pixel == 32 || 618 var->bits_per_pixel == 24) { 619 val = chan_to_field(red, &var->red); 620 val |= chan_to_field(green, &var->green); 621 val |= chan_to_field(blue, &var->blue); 622 par->pseudo_palette[regno] = val; 623 goto exit; 624 } 625 } 626 627 ret = -EINVAL; 628 629 exit: 630 return ret; 631 } 632 633 static int lynxfb_ops_blank(int blank, struct fb_info *info) 634 { 635 struct lynxfb_par *par; 636 struct lynxfb_output *output; 637 638 pr_debug("blank = %d.\n", blank); 639 par = info->par; 640 output = &par->output; 641 return output->proc_setBLANK(output, blank); 642 } 643 644 static int sm750fb_set_drv(struct lynxfb_par *par) 645 { 646 int ret; 647 struct sm750_dev *sm750_dev; 648 struct lynxfb_output *output; 649 struct lynxfb_crtc *crtc; 650 651 ret = 0; 652 653 sm750_dev = par->dev; 654 output = &par->output; 655 crtc = &par->crtc; 656 657 crtc->vidmem_size = sm750_dev->vidmem_size; 658 if (sm750_dev->fb_count > 1) 659 crtc->vidmem_size >>= 1; 660 661 /* setup crtc and output member */ 662 sm750_dev->hwCursor = g_hwcursor; 663 664 crtc->line_pad = 16; 665 crtc->xpanstep = 8; 666 crtc->ypanstep = 1; 667 crtc->ywrapstep = 0; 668 669 output->proc_setBLANK = (sm750_dev->revid == SM750LE_REVISION_ID) ? 670 hw_sm750le_setBLANK : hw_sm750_setBLANK; 671 /* chip specific phase */ 672 sm750_dev->accel.de_wait = (sm750_dev->revid == SM750LE_REVISION_ID) ? 673 hw_sm750le_deWait : hw_sm750_deWait; 674 switch (sm750_dev->dataflow) { 675 case sm750_simul_pri: 676 output->paths = sm750_pnc; 677 crtc->channel = sm750_primary; 678 crtc->oScreen = 0; 679 crtc->vScreen = sm750_dev->pvMem; 680 pr_info("use simul primary mode\n"); 681 break; 682 case sm750_simul_sec: 683 output->paths = sm750_pnc; 684 crtc->channel = sm750_secondary; 685 crtc->oScreen = 0; 686 crtc->vScreen = sm750_dev->pvMem; 687 break; 688 case sm750_dual_normal: 689 if (par->index == 0) { 690 output->paths = sm750_panel; 691 crtc->channel = sm750_primary; 692 crtc->oScreen = 0; 693 crtc->vScreen = sm750_dev->pvMem; 694 } else { 695 output->paths = sm750_crt; 696 crtc->channel = sm750_secondary; 697 /* not consider of padding stuffs for oScreen,need fix */ 698 crtc->oScreen = (sm750_dev->vidmem_size >> 1); 699 crtc->vScreen = sm750_dev->pvMem + crtc->oScreen; 700 } 701 break; 702 case sm750_dual_swap: 703 if (par->index == 0) { 704 output->paths = sm750_panel; 705 crtc->channel = sm750_secondary; 706 crtc->oScreen = 0; 707 crtc->vScreen = sm750_dev->pvMem; 708 } else { 709 output->paths = sm750_crt; 710 crtc->channel = sm750_primary; 711 /* not consider of padding stuffs for oScreen,need fix */ 712 crtc->oScreen = (sm750_dev->vidmem_size >> 1); 713 crtc->vScreen = sm750_dev->pvMem + crtc->oScreen; 714 } 715 break; 716 default: 717 ret = -EINVAL; 718 } 719 720 return ret; 721 } 722 723 static struct fb_ops lynxfb_ops = { 724 .owner = THIS_MODULE, 725 .fb_check_var = lynxfb_ops_check_var, 726 .fb_set_par = lynxfb_ops_set_par, 727 .fb_setcolreg = lynxfb_ops_setcolreg, 728 .fb_blank = lynxfb_ops_blank, 729 .fb_fillrect = cfb_fillrect, 730 .fb_imageblit = cfb_imageblit, 731 .fb_copyarea = cfb_copyarea, 732 /* cursor */ 733 .fb_cursor = lynxfb_ops_cursor, 734 }; 735 736 static int lynxfb_set_fbinfo(struct fb_info *info, int index) 737 { 738 int i; 739 struct lynxfb_par *par; 740 struct sm750_dev *sm750_dev; 741 struct lynxfb_crtc *crtc; 742 struct lynxfb_output *output; 743 struct fb_var_screeninfo *var; 744 struct fb_fix_screeninfo *fix; 745 746 const struct fb_videomode *pdb[] = { 747 lynx750_ext, NULL, vesa_modes, 748 }; 749 int cdb[] = {ARRAY_SIZE(lynx750_ext), 0, VESA_MODEDB_SIZE}; 750 static const char *mdb_desc[] = { 751 "driver prepared modes", 752 "kernel prepared default modedb", 753 "kernel HELPERS prepared vesa_modes", 754 }; 755 756 static const char *fixId[2] = { 757 "sm750_fb1", "sm750_fb2", 758 }; 759 760 int ret, line_length; 761 762 ret = 0; 763 par = (struct lynxfb_par *)info->par; 764 sm750_dev = par->dev; 765 crtc = &par->crtc; 766 output = &par->output; 767 var = &info->var; 768 fix = &info->fix; 769 770 /* set index */ 771 par->index = index; 772 output->channel = &crtc->channel; 773 sm750fb_set_drv(par); 774 lynxfb_ops.fb_pan_display = lynxfb_ops_pan_display; 775 776 /* 777 * set current cursor variable and proc pointer, 778 * must be set after crtc member initialized 779 */ 780 crtc->cursor.offset = crtc->oScreen + crtc->vidmem_size - 1024; 781 crtc->cursor.mmio = sm750_dev->pvReg + 782 0x800f0 + (int)crtc->channel * 0x140; 783 784 pr_info("crtc->cursor.mmio = %p\n", crtc->cursor.mmio); 785 crtc->cursor.maxH = crtc->cursor.maxW = 64; 786 crtc->cursor.size = crtc->cursor.maxH * crtc->cursor.maxW * 2 / 8; 787 crtc->cursor.vstart = sm750_dev->pvMem + crtc->cursor.offset; 788 789 memset_io(crtc->cursor.vstart, 0, crtc->cursor.size); 790 if (!g_hwcursor) { 791 lynxfb_ops.fb_cursor = NULL; 792 sm750_hw_cursor_disable(&crtc->cursor); 793 } 794 795 /* set info->fbops, must be set before fb_find_mode */ 796 if (!sm750_dev->accel_off) { 797 /* use 2d acceleration */ 798 lynxfb_ops.fb_fillrect = lynxfb_ops_fillrect; 799 lynxfb_ops.fb_copyarea = lynxfb_ops_copyarea; 800 lynxfb_ops.fb_imageblit = lynxfb_ops_imageblit; 801 } 802 info->fbops = &lynxfb_ops; 803 804 if (!g_fbmode[index]) { 805 g_fbmode[index] = g_def_fbmode; 806 if (index) 807 g_fbmode[index] = g_fbmode[0]; 808 } 809 810 for (i = 0; i < 3; i++) { 811 ret = fb_find_mode(var, info, g_fbmode[index], 812 pdb[i], cdb[i], NULL, 8); 813 814 if (ret == 1) { 815 pr_info("success! use specified mode:%s in %s\n", 816 g_fbmode[index], 817 mdb_desc[i]); 818 break; 819 } else if (ret == 2) { 820 pr_warn("use specified mode:%s in %s,with an ignored refresh rate\n", 821 g_fbmode[index], 822 mdb_desc[i]); 823 break; 824 } else if (ret == 3) { 825 pr_warn("wanna use default mode\n"); 826 /*break;*/ 827 } else if (ret == 4) { 828 pr_warn("fall back to any valid mode\n"); 829 } else { 830 pr_warn("ret = %d,fb_find_mode failed,with %s\n", 831 ret, 832 mdb_desc[i]); 833 } 834 } 835 836 /* some member of info->var had been set by fb_find_mode */ 837 838 pr_info("Member of info->var is :\n" 839 "xres=%d\n" 840 "yres=%d\n" 841 "xres_virtual=%d\n" 842 "yres_virtual=%d\n" 843 "xoffset=%d\n" 844 "yoffset=%d\n" 845 "bits_per_pixel=%d\n" 846 " ...\n", 847 var->xres, 848 var->yres, 849 var->xres_virtual, 850 var->yres_virtual, 851 var->xoffset, 852 var->yoffset, 853 var->bits_per_pixel); 854 855 /* set par */ 856 par->info = info; 857 858 /* set info */ 859 line_length = ALIGN((var->xres_virtual * var->bits_per_pixel / 8), 860 crtc->line_pad); 861 862 info->pseudo_palette = &par->pseudo_palette[0]; 863 info->screen_base = crtc->vScreen; 864 pr_debug("screen_base vaddr = %p\n", info->screen_base); 865 info->screen_size = line_length * var->yres_virtual; 866 info->flags = FBINFO_FLAG_DEFAULT | 0; 867 868 /* set info->fix */ 869 fix->type = FB_TYPE_PACKED_PIXELS; 870 fix->type_aux = 0; 871 fix->xpanstep = crtc->xpanstep; 872 fix->ypanstep = crtc->ypanstep; 873 fix->ywrapstep = crtc->ywrapstep; 874 fix->accel = FB_ACCEL_SMI; 875 876 strlcpy(fix->id, fixId[index], sizeof(fix->id)); 877 878 fix->smem_start = crtc->oScreen + sm750_dev->vidmem_start; 879 pr_info("fix->smem_start = %lx\n", fix->smem_start); 880 /* 881 * according to mmap experiment from user space application, 882 * fix->mmio_len should not larger than virtual size 883 * (xres_virtual x yres_virtual x ByPP) 884 * Below line maybe buggy when user mmap fb dev node and write 885 * data into the bound over virtual size 886 */ 887 fix->smem_len = crtc->vidmem_size; 888 pr_info("fix->smem_len = %x\n", fix->smem_len); 889 info->screen_size = fix->smem_len; 890 fix->line_length = line_length; 891 fix->mmio_start = sm750_dev->vidreg_start; 892 pr_info("fix->mmio_start = %lx\n", fix->mmio_start); 893 fix->mmio_len = sm750_dev->vidreg_size; 894 pr_info("fix->mmio_len = %x\n", fix->mmio_len); 895 switch (var->bits_per_pixel) { 896 case 8: 897 fix->visual = FB_VISUAL_PSEUDOCOLOR; 898 break; 899 case 16: 900 case 32: 901 fix->visual = FB_VISUAL_TRUECOLOR; 902 break; 903 } 904 905 /* set var */ 906 var->activate = FB_ACTIVATE_NOW; 907 var->accel_flags = 0; 908 var->vmode = FB_VMODE_NONINTERLACED; 909 910 pr_debug("#1 show info->cmap :\nstart=%d,len=%d,red=%p,green=%p,blue=%p,transp=%p\n", 911 info->cmap.start, info->cmap.len, 912 info->cmap.red, info->cmap.green, info->cmap.blue, 913 info->cmap.transp); 914 915 ret = fb_alloc_cmap(&info->cmap, 256, 0); 916 if (ret < 0) { 917 pr_err("Could not allocate memory for cmap.\n"); 918 goto exit; 919 } 920 921 pr_debug("#2 show info->cmap :\nstart=%d,len=%d,red=%p,green=%p,blue=%p,transp=%p\n", 922 info->cmap.start, info->cmap.len, 923 info->cmap.red, info->cmap.green, info->cmap.blue, 924 info->cmap.transp); 925 926 exit: 927 lynxfb_ops_check_var(var, info); 928 return ret; 929 } 930 931 /* chip specific g_option configuration routine */ 932 static void sm750fb_setup(struct sm750_dev *sm750_dev, char *src) 933 { 934 char *opt; 935 int swap; 936 937 swap = 0; 938 939 sm750_dev->initParm.chip_clk = 0; 940 sm750_dev->initParm.mem_clk = 0; 941 sm750_dev->initParm.master_clk = 0; 942 sm750_dev->initParm.powerMode = 0; 943 sm750_dev->initParm.setAllEngOff = 0; 944 sm750_dev->initParm.resetMemory = 1; 945 946 /* defaultly turn g_hwcursor on for both view */ 947 g_hwcursor = 3; 948 949 if (!src || !*src) { 950 dev_warn(&sm750_dev->pdev->dev, "no specific g_option.\n"); 951 goto NO_PARAM; 952 } 953 954 while ((opt = strsep(&src, ":")) != NULL && *opt != 0) { 955 dev_info(&sm750_dev->pdev->dev, "opt=%s\n", opt); 956 dev_info(&sm750_dev->pdev->dev, "src=%s\n", src); 957 958 if (!strncmp(opt, "swap", strlen("swap"))) { 959 swap = 1; 960 } else if (!strncmp(opt, "nocrt", strlen("nocrt"))) { 961 sm750_dev->nocrt = 1; 962 } else if (!strncmp(opt, "36bit", strlen("36bit"))) { 963 sm750_dev->pnltype = sm750_doubleTFT; 964 } else if (!strncmp(opt, "18bit", strlen("18bit"))) { 965 sm750_dev->pnltype = sm750_dualTFT; 966 } else if (!strncmp(opt, "24bit", strlen("24bit"))) { 967 sm750_dev->pnltype = sm750_24TFT; 968 } else if (!strncmp(opt, "nohwc0", strlen("nohwc0"))) { 969 g_hwcursor &= ~0x1; 970 } else if (!strncmp(opt, "nohwc1", strlen("nohwc1"))) { 971 g_hwcursor &= ~0x2; 972 } else if (!strncmp(opt, "nohwc", strlen("nohwc"))) { 973 g_hwcursor = 0; 974 } else { 975 if (!g_fbmode[0]) { 976 g_fbmode[0] = opt; 977 dev_info(&sm750_dev->pdev->dev, 978 "find fbmode0 : %s\n", g_fbmode[0]); 979 } else if (!g_fbmode[1]) { 980 g_fbmode[1] = opt; 981 dev_info(&sm750_dev->pdev->dev, 982 "find fbmode1 : %s\n", g_fbmode[1]); 983 } else { 984 dev_warn(&sm750_dev->pdev->dev, "How many view you wann set?\n"); 985 } 986 } 987 } 988 989 NO_PARAM: 990 if (sm750_dev->revid != SM750LE_REVISION_ID) { 991 if (sm750_dev->fb_count > 1) { 992 if (swap) 993 sm750_dev->dataflow = sm750_dual_swap; 994 else 995 sm750_dev->dataflow = sm750_dual_normal; 996 } else { 997 if (swap) 998 sm750_dev->dataflow = sm750_simul_sec; 999 else 1000 sm750_dev->dataflow = sm750_simul_pri; 1001 } 1002 } else { 1003 /* SM750LE only have one crt channel */ 1004 sm750_dev->dataflow = sm750_simul_sec; 1005 /* sm750le do not have complex attributes */ 1006 sm750_dev->nocrt = 0; 1007 } 1008 } 1009 1010 static void sm750fb_frambuffer_release(struct sm750_dev *sm750_dev) 1011 { 1012 struct fb_info *fb_info; 1013 1014 while (sm750_dev->fb_count) { 1015 fb_info = sm750_dev->fbinfo[sm750_dev->fb_count - 1]; 1016 unregister_framebuffer(fb_info); 1017 framebuffer_release(fb_info); 1018 sm750_dev->fb_count--; 1019 } 1020 } 1021 1022 static int sm750fb_frambuffer_alloc(struct sm750_dev *sm750_dev, int fbidx) 1023 { 1024 struct fb_info *fb_info; 1025 struct lynxfb_par *par; 1026 int err; 1027 1028 fb_info = framebuffer_alloc(sizeof(struct lynxfb_par), 1029 &sm750_dev->pdev->dev); 1030 if (!fb_info) 1031 return -ENOMEM; 1032 1033 sm750_dev->fbinfo[fbidx] = fb_info; 1034 par = fb_info->par; 1035 par->dev = sm750_dev; 1036 1037 err = lynxfb_set_fbinfo(fb_info, fbidx); 1038 if (err) 1039 goto release_fb; 1040 1041 err = register_framebuffer(fb_info); 1042 if (err < 0) 1043 goto release_fb; 1044 1045 sm750_dev->fb_count++; 1046 1047 return 0; 1048 1049 release_fb: 1050 framebuffer_release(fb_info); 1051 return err; 1052 } 1053 1054 static int lynxfb_kick_out_firmware_fb(struct pci_dev *pdev) 1055 { 1056 struct apertures_struct *ap; 1057 bool primary = false; 1058 1059 ap = alloc_apertures(1); 1060 if (!ap) 1061 return -ENOMEM; 1062 1063 ap->ranges[0].base = pci_resource_start(pdev, 0); 1064 ap->ranges[0].size = pci_resource_len(pdev, 0); 1065 #ifdef CONFIG_X86 1066 primary = pdev->resource[PCI_ROM_RESOURCE].flags & 1067 IORESOURCE_ROM_SHADOW; 1068 #endif 1069 remove_conflicting_framebuffers(ap, "sm750_fb1", primary); 1070 kfree(ap); 1071 return 0; 1072 } 1073 1074 static int lynxfb_pci_probe(struct pci_dev *pdev, 1075 const struct pci_device_id *ent) 1076 { 1077 struct sm750_dev *sm750_dev = NULL; 1078 int max_fb; 1079 int fbidx; 1080 int err; 1081 1082 err = lynxfb_kick_out_firmware_fb(pdev); 1083 if (err) 1084 return err; 1085 1086 /* enable device */ 1087 err = pcim_enable_device(pdev); 1088 if (err) 1089 return err; 1090 1091 err = -ENOMEM; 1092 sm750_dev = devm_kzalloc(&pdev->dev, sizeof(*sm750_dev), GFP_KERNEL); 1093 if (!sm750_dev) 1094 return err; 1095 1096 sm750_dev->fbinfo[0] = sm750_dev->fbinfo[1] = NULL; 1097 sm750_dev->devid = pdev->device; 1098 sm750_dev->revid = pdev->revision; 1099 sm750_dev->pdev = pdev; 1100 sm750_dev->mtrr_off = g_nomtrr; 1101 sm750_dev->mtrr.vram = 0; 1102 sm750_dev->accel_off = g_noaccel; 1103 spin_lock_init(&sm750_dev->slock); 1104 1105 if (!sm750_dev->accel_off) { 1106 /* 1107 * hook deInit and 2d routines, notes that below hw_xxx 1108 * routine can work on most of lynx chips 1109 * if some chip need specific function, 1110 * please hook it in smXXX_set_drv routine 1111 */ 1112 sm750_dev->accel.de_init = sm750_hw_de_init; 1113 sm750_dev->accel.de_fillrect = sm750_hw_fillrect; 1114 sm750_dev->accel.de_copyarea = sm750_hw_copyarea; 1115 sm750_dev->accel.de_imageblit = sm750_hw_imageblit; 1116 } 1117 1118 /* call chip specific setup routine */ 1119 sm750fb_setup(sm750_dev, g_settings); 1120 1121 /* call chip specific mmap routine */ 1122 err = hw_sm750_map(sm750_dev, pdev); 1123 if (err) 1124 return err; 1125 1126 if (!sm750_dev->mtrr_off) 1127 sm750_dev->mtrr.vram = arch_phys_wc_add(sm750_dev->vidmem_start, 1128 sm750_dev->vidmem_size); 1129 1130 memset_io(sm750_dev->pvMem, 0, sm750_dev->vidmem_size); 1131 1132 pci_set_drvdata(pdev, sm750_dev); 1133 1134 /* call chipInit routine */ 1135 hw_sm750_inithw(sm750_dev, pdev); 1136 1137 /* allocate frame buffer info structures according to g_dualview */ 1138 max_fb = g_dualview ? 2 : 1; 1139 for (fbidx = 0; fbidx < max_fb; fbidx++) { 1140 err = sm750fb_frambuffer_alloc(sm750_dev, fbidx); 1141 if (err) 1142 goto release_fb; 1143 } 1144 1145 return 0; 1146 1147 release_fb: 1148 sm750fb_frambuffer_release(sm750_dev); 1149 return err; 1150 } 1151 1152 static void lynxfb_pci_remove(struct pci_dev *pdev) 1153 { 1154 struct sm750_dev *sm750_dev; 1155 1156 sm750_dev = pci_get_drvdata(pdev); 1157 1158 sm750fb_frambuffer_release(sm750_dev); 1159 arch_phys_wc_del(sm750_dev->mtrr.vram); 1160 1161 iounmap(sm750_dev->pvReg); 1162 iounmap(sm750_dev->pvMem); 1163 kfree(g_settings); 1164 } 1165 1166 static int __init lynxfb_setup(char *options) 1167 { 1168 int len; 1169 char *opt, *tmp; 1170 1171 if (!options || !*options) { 1172 pr_warn("no options.\n"); 1173 return 0; 1174 } 1175 1176 pr_info("options:%s\n", options); 1177 1178 len = strlen(options) + 1; 1179 g_settings = kzalloc(len, GFP_KERNEL); 1180 if (!g_settings) 1181 return -ENOMEM; 1182 1183 tmp = g_settings; 1184 1185 /* 1186 * Notes: 1187 * char * strsep(char **s,const char * ct); 1188 * @s: the string to be searched 1189 * @ct :the characters to search for 1190 * 1191 * strsep() updates @options to pointer after the first found token 1192 * it also returns the pointer ahead the token. 1193 */ 1194 while ((opt = strsep(&options, ":")) != NULL) { 1195 /* options that mean for any lynx chips are configured here */ 1196 if (!strncmp(opt, "noaccel", strlen("noaccel"))) { 1197 g_noaccel = 1; 1198 } else if (!strncmp(opt, "nomtrr", strlen("nomtrr"))) { 1199 g_nomtrr = 1; 1200 } else if (!strncmp(opt, "dual", strlen("dual"))) { 1201 g_dualview = 1; 1202 } else { 1203 strcat(tmp, opt); 1204 tmp += strlen(opt); 1205 if (options) 1206 *tmp++ = ':'; 1207 else 1208 *tmp++ = 0; 1209 } 1210 } 1211 1212 /* misc g_settings are transport to chip specific routines */ 1213 pr_info("parameter left for chip specific analysis:%s\n", g_settings); 1214 return 0; 1215 } 1216 1217 static const struct pci_device_id smi_pci_table[] = { 1218 { PCI_DEVICE(0x126f, 0x0750), }, 1219 {0,} 1220 }; 1221 1222 MODULE_DEVICE_TABLE(pci, smi_pci_table); 1223 1224 static struct pci_driver lynxfb_driver = { 1225 .name = "sm750fb", 1226 .id_table = smi_pci_table, 1227 .probe = lynxfb_pci_probe, 1228 .remove = lynxfb_pci_remove, 1229 #ifdef CONFIG_PM 1230 .suspend = lynxfb_suspend, 1231 .resume = lynxfb_resume, 1232 #endif 1233 }; 1234 1235 static int __init lynxfb_init(void) 1236 { 1237 char *option; 1238 1239 #ifdef MODULE 1240 option = g_option; 1241 #else 1242 if (fb_get_options("sm750fb", &option)) 1243 return -ENODEV; 1244 #endif 1245 1246 lynxfb_setup(option); 1247 return pci_register_driver(&lynxfb_driver); 1248 } 1249 module_init(lynxfb_init); 1250 1251 static void __exit lynxfb_exit(void) 1252 { 1253 pci_unregister_driver(&lynxfb_driver); 1254 } 1255 module_exit(lynxfb_exit); 1256 1257 module_param(g_option, charp, 0444); 1258 1259 MODULE_PARM_DESC(g_option, 1260 "\n\t\tCommon options:\n" 1261 "\t\tnoaccel:disable 2d capabilities\n" 1262 "\t\tnomtrr:disable MTRR attribute for video memory\n" 1263 "\t\tdualview:dual frame buffer feature enabled\n" 1264 "\t\tnohwc:disable hardware cursor\n" 1265 "\t\tUsual example:\n" 1266 "\t\tinsmod ./sm750fb.ko g_option=\"noaccel,nohwc,1280x1024-8@60\"\n" 1267 ); 1268 1269 MODULE_AUTHOR("monk liu <monk.liu@siliconmotion.com>"); 1270 MODULE_AUTHOR("Sudip Mukherjee <sudip@vectorindia.org>"); 1271 MODULE_DESCRIPTION("Frame buffer driver for SM750 chipset"); 1272 MODULE_LICENSE("Dual BSD/GPL"); 1273