diff options
Diffstat (limited to 'drivers/video/chipsfb.c')
-rw-r--r-- | drivers/video/chipsfb.c | 176 |
1 files changed, 92 insertions, 84 deletions
diff --git a/drivers/video/chipsfb.c b/drivers/video/chipsfb.c index 95e72550d43f..e75a965ec760 100644 --- a/drivers/video/chipsfb.c +++ b/drivers/video/chipsfb.c | |||
@@ -28,22 +28,17 @@ | |||
28 | #include <linux/fb.h> | 28 | #include <linux/fb.h> |
29 | #include <linux/init.h> | 29 | #include <linux/init.h> |
30 | #include <linux/pci.h> | 30 | #include <linux/pci.h> |
31 | #include <linux/console.h> | ||
31 | #include <asm/io.h> | 32 | #include <asm/io.h> |
32 | 33 | ||
33 | #ifdef CONFIG_PMAC_BACKLIGHT | 34 | #ifdef CONFIG_PMAC_BACKLIGHT |
34 | #include <asm/backlight.h> | 35 | #include <asm/backlight.h> |
35 | #endif | 36 | #endif |
36 | #ifdef CONFIG_PMAC_PBOOK | ||
37 | #include <linux/adb.h> | ||
38 | #include <linux/pmu.h> | ||
39 | #endif | ||
40 | 37 | ||
41 | /* | 38 | /* |
42 | * Since we access the display with inb/outb to fixed port numbers, | 39 | * Since we access the display with inb/outb to fixed port numbers, |
43 | * we can only handle one 6555x chip. -- paulus | 40 | * we can only handle one 6555x chip. -- paulus |
44 | */ | 41 | */ |
45 | static struct fb_info chipsfb_info; | ||
46 | |||
47 | #define write_ind(num, val, ap, dp) do { \ | 42 | #define write_ind(num, val, ap, dp) do { \ |
48 | outb((num), (ap)); outb((val), (dp)); \ | 43 | outb((num), (ap)); outb((val), (dp)); \ |
49 | } while (0) | 44 | } while (0) |
@@ -74,14 +69,6 @@ static struct fb_info chipsfb_info; | |||
74 | inb(0x3da); read_ind(num, var, 0x3c0, 0x3c1); \ | 69 | inb(0x3da); read_ind(num, var, 0x3c0, 0x3c1); \ |
75 | } while (0) | 70 | } while (0) |
76 | 71 | ||
77 | #ifdef CONFIG_PMAC_PBOOK | ||
78 | static unsigned char *save_framebuffer; | ||
79 | int chips_sleep_notify(struct pmu_sleep_notifier *self, int when); | ||
80 | static struct pmu_sleep_notifier chips_sleep_notifier = { | ||
81 | chips_sleep_notify, SLEEP_LEVEL_VIDEO, | ||
82 | }; | ||
83 | #endif | ||
84 | |||
85 | /* | 72 | /* |
86 | * Exported functions | 73 | * Exported functions |
87 | */ | 74 | */ |
@@ -356,6 +343,8 @@ static struct fb_var_screeninfo chipsfb_var __initdata = { | |||
356 | 343 | ||
357 | static void __init init_chips(struct fb_info *p, unsigned long addr) | 344 | static void __init init_chips(struct fb_info *p, unsigned long addr) |
358 | { | 345 | { |
346 | memset(p->screen_base, 0, 0x100000); | ||
347 | |||
359 | p->fix = chipsfb_fix; | 348 | p->fix = chipsfb_fix; |
360 | p->fix.smem_start = addr; | 349 | p->fix.smem_start = addr; |
361 | 350 | ||
@@ -366,34 +355,41 @@ static void __init init_chips(struct fb_info *p, unsigned long addr) | |||
366 | 355 | ||
367 | fb_alloc_cmap(&p->cmap, 256, 0); | 356 | fb_alloc_cmap(&p->cmap, 256, 0); |
368 | 357 | ||
369 | if (register_framebuffer(p) < 0) { | ||
370 | printk(KERN_ERR "C&T 65550 framebuffer failed to register\n"); | ||
371 | return; | ||
372 | } | ||
373 | |||
374 | printk(KERN_INFO "fb%d: Chips 65550 frame buffer (%dK RAM detected)\n", | ||
375 | p->node, p->fix.smem_len / 1024); | ||
376 | |||
377 | chips_hw_init(); | 358 | chips_hw_init(); |
378 | } | 359 | } |
379 | 360 | ||
380 | static int __devinit | 361 | static int __devinit |
381 | chipsfb_pci_init(struct pci_dev *dp, const struct pci_device_id *ent) | 362 | chipsfb_pci_init(struct pci_dev *dp, const struct pci_device_id *ent) |
382 | { | 363 | { |
383 | struct fb_info *p = &chipsfb_info; | 364 | struct fb_info *p; |
384 | unsigned long addr, size; | 365 | unsigned long addr, size; |
385 | unsigned short cmd; | 366 | unsigned short cmd; |
367 | int rc = -ENODEV; | ||
368 | |||
369 | if (pci_enable_device(dp) < 0) { | ||
370 | dev_err(&dp->dev, "Cannot enable PCI device\n"); | ||
371 | goto err_out; | ||
372 | } | ||
386 | 373 | ||
387 | if ((dp->resource[0].flags & IORESOURCE_MEM) == 0) | 374 | if ((dp->resource[0].flags & IORESOURCE_MEM) == 0) |
388 | return -ENODEV; | 375 | goto err_disable; |
389 | addr = pci_resource_start(dp, 0); | 376 | addr = pci_resource_start(dp, 0); |
390 | size = pci_resource_len(dp, 0); | 377 | size = pci_resource_len(dp, 0); |
391 | if (addr == 0) | 378 | if (addr == 0) |
392 | return -ENODEV; | 379 | goto err_disable; |
393 | if (p->screen_base != 0) | 380 | |
394 | return -EBUSY; | 381 | p = framebuffer_alloc(0, &dp->dev); |
395 | if (!request_mem_region(addr, size, "chipsfb")) | 382 | if (p == NULL) { |
396 | return -EBUSY; | 383 | dev_err(&dp->dev, "Cannot allocate framebuffer structure\n"); |
384 | rc = -ENOMEM; | ||
385 | goto err_disable; | ||
386 | } | ||
387 | |||
388 | if (pci_request_region(dp, 0, "chipsfb") != 0) { | ||
389 | dev_err(&dp->dev, "Cannot request framebuffer\n"); | ||
390 | rc = -EBUSY; | ||
391 | goto err_release_fb; | ||
392 | } | ||
397 | 393 | ||
398 | #ifdef __BIG_ENDIAN | 394 | #ifdef __BIG_ENDIAN |
399 | addr += 0x800000; // Use big-endian aperture | 395 | addr += 0x800000; // Use big-endian aperture |
@@ -411,37 +407,89 @@ chipsfb_pci_init(struct pci_dev *dp, const struct pci_device_id *ent) | |||
411 | set_backlight_enable(1); | 407 | set_backlight_enable(1); |
412 | #endif /* CONFIG_PMAC_BACKLIGHT */ | 408 | #endif /* CONFIG_PMAC_BACKLIGHT */ |
413 | 409 | ||
410 | #ifdef CONFIG_PPC | ||
414 | p->screen_base = __ioremap(addr, 0x200000, _PAGE_NO_CACHE); | 411 | p->screen_base = __ioremap(addr, 0x200000, _PAGE_NO_CACHE); |
412 | #else | ||
413 | p->screen_base = ioremap(addr, 0x200000); | ||
414 | #endif | ||
415 | if (p->screen_base == NULL) { | 415 | if (p->screen_base == NULL) { |
416 | release_mem_region(addr, size); | 416 | dev_err(&dp->dev, "Cannot map framebuffer\n"); |
417 | return -ENOMEM; | 417 | rc = -ENOMEM; |
418 | goto err_release_pci; | ||
418 | } | 419 | } |
420 | |||
421 | pci_set_drvdata(dp, p); | ||
419 | p->device = &dp->dev; | 422 | p->device = &dp->dev; |
423 | |||
420 | init_chips(p, addr); | 424 | init_chips(p, addr); |
421 | 425 | ||
422 | #ifdef CONFIG_PMAC_PBOOK | 426 | if (register_framebuffer(p) < 0) { |
423 | pmu_register_sleep_notifier(&chips_sleep_notifier); | 427 | dev_err(&dp->dev,"C&T 65550 framebuffer failed to register\n"); |
424 | #endif /* CONFIG_PMAC_PBOOK */ | 428 | goto err_unmap; |
429 | } | ||
430 | |||
431 | dev_info(&dp->dev,"fb%d: Chips 65550 frame buffer" | ||
432 | " (%dK RAM detected)\n", | ||
433 | p->node, p->fix.smem_len / 1024); | ||
425 | 434 | ||
426 | pci_set_drvdata(dp, p); | ||
427 | return 0; | 435 | return 0; |
436 | |||
437 | err_unmap: | ||
438 | iounmap(p->screen_base); | ||
439 | err_release_pci: | ||
440 | pci_release_region(dp, 0); | ||
441 | err_release_fb: | ||
442 | framebuffer_release(p); | ||
443 | err_disable: | ||
444 | err_out: | ||
445 | return rc; | ||
428 | } | 446 | } |
429 | 447 | ||
430 | static void __devexit chipsfb_remove(struct pci_dev *dp) | 448 | static void __devexit chipsfb_remove(struct pci_dev *dp) |
431 | { | 449 | { |
432 | struct fb_info *p = pci_get_drvdata(dp); | 450 | struct fb_info *p = pci_get_drvdata(dp); |
433 | 451 | ||
434 | if (p != &chipsfb_info || p->screen_base == NULL) | 452 | if (p->screen_base == NULL) |
435 | return; | 453 | return; |
436 | unregister_framebuffer(p); | 454 | unregister_framebuffer(p); |
437 | iounmap(p->screen_base); | 455 | iounmap(p->screen_base); |
438 | p->screen_base = NULL; | 456 | p->screen_base = NULL; |
439 | release_mem_region(pci_resource_start(dp, 0), pci_resource_len(dp, 0)); | 457 | pci_release_region(dp, 0); |
458 | } | ||
459 | |||
460 | #ifdef CONFIG_PM | ||
461 | static int chipsfb_pci_suspend(struct pci_dev *pdev, pm_message_t state) | ||
462 | { | ||
463 | struct fb_info *p = pci_get_drvdata(pdev); | ||
464 | |||
465 | if (state == pdev->dev.power.power_state) | ||
466 | return 0; | ||
467 | if (state != PM_SUSPEND_MEM) | ||
468 | goto done; | ||
469 | |||
470 | acquire_console_sem(); | ||
471 | chipsfb_blank(1, p); | ||
472 | fb_set_suspend(p, 1); | ||
473 | release_console_sem(); | ||
474 | done: | ||
475 | pdev->dev.power.power_state = state; | ||
476 | return 0; | ||
477 | } | ||
478 | |||
479 | static int chipsfb_pci_resume(struct pci_dev *pdev) | ||
480 | { | ||
481 | struct fb_info *p = pci_get_drvdata(pdev); | ||
440 | 482 | ||
441 | #ifdef CONFIG_PMAC_PBOOK | 483 | acquire_console_sem(); |
442 | pmu_unregister_sleep_notifier(&chips_sleep_notifier); | 484 | fb_set_suspend(p, 0); |
443 | #endif /* CONFIG_PMAC_PBOOK */ | 485 | chipsfb_blank(0, p); |
486 | release_console_sem(); | ||
487 | |||
488 | pdev->dev.power.power_state = PMSG_ON; | ||
489 | return 0; | ||
444 | } | 490 | } |
491 | #endif /* CONFIG_PM */ | ||
492 | |||
445 | 493 | ||
446 | static struct pci_device_id chipsfb_pci_tbl[] = { | 494 | static struct pci_device_id chipsfb_pci_tbl[] = { |
447 | { PCI_VENDOR_ID_CT, PCI_DEVICE_ID_CT_65550, PCI_ANY_ID, PCI_ANY_ID }, | 495 | { PCI_VENDOR_ID_CT, PCI_DEVICE_ID_CT_65550, PCI_ANY_ID, PCI_ANY_ID }, |
@@ -455,6 +503,10 @@ static struct pci_driver chipsfb_driver = { | |||
455 | .id_table = chipsfb_pci_tbl, | 503 | .id_table = chipsfb_pci_tbl, |
456 | .probe = chipsfb_pci_init, | 504 | .probe = chipsfb_pci_init, |
457 | .remove = __devexit_p(chipsfb_remove), | 505 | .remove = __devexit_p(chipsfb_remove), |
506 | #ifdef CONFIG_PM | ||
507 | .suspend = chipsfb_pci_suspend, | ||
508 | .resume = chipsfb_pci_resume, | ||
509 | #endif | ||
458 | }; | 510 | }; |
459 | 511 | ||
460 | int __init chips_init(void) | 512 | int __init chips_init(void) |
@@ -472,48 +524,4 @@ static void __exit chipsfb_exit(void) | |||
472 | pci_unregister_driver(&chipsfb_driver); | 524 | pci_unregister_driver(&chipsfb_driver); |
473 | } | 525 | } |
474 | 526 | ||
475 | #ifdef CONFIG_PMAC_PBOOK | ||
476 | /* | ||
477 | * Save the contents of the frame buffer when we go to sleep, | ||
478 | * and restore it when we wake up again. | ||
479 | */ | ||
480 | int | ||
481 | chips_sleep_notify(struct pmu_sleep_notifier *self, int when) | ||
482 | { | ||
483 | struct fb_info *p = &chipsfb_info; | ||
484 | int nb = p->var.yres * p->fix.line_length; | ||
485 | |||
486 | if (p->screen_base == NULL) | ||
487 | return PBOOK_SLEEP_OK; | ||
488 | |||
489 | switch (when) { | ||
490 | case PBOOK_SLEEP_REQUEST: | ||
491 | save_framebuffer = vmalloc(nb); | ||
492 | if (save_framebuffer == NULL) | ||
493 | return PBOOK_SLEEP_REFUSE; | ||
494 | break; | ||
495 | case PBOOK_SLEEP_REJECT: | ||
496 | if (save_framebuffer) { | ||
497 | vfree(save_framebuffer); | ||
498 | save_framebuffer = NULL; | ||
499 | } | ||
500 | break; | ||
501 | case PBOOK_SLEEP_NOW: | ||
502 | chipsfb_blank(1, p); | ||
503 | if (save_framebuffer) | ||
504 | memcpy(save_framebuffer, p->screen_base, nb); | ||
505 | break; | ||
506 | case PBOOK_WAKE: | ||
507 | if (save_framebuffer) { | ||
508 | memcpy(p->screen_base, save_framebuffer, nb); | ||
509 | vfree(save_framebuffer); | ||
510 | save_framebuffer = NULL; | ||
511 | } | ||
512 | chipsfb_blank(0, p); | ||
513 | break; | ||
514 | } | ||
515 | return PBOOK_SLEEP_OK; | ||
516 | } | ||
517 | #endif /* CONFIG_PMAC_PBOOK */ | ||
518 | |||
519 | MODULE_LICENSE("GPL"); | 527 | MODULE_LICENSE("GPL"); |