aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorBenjamin Herrenschmidt <benh@kernel.crashing.org>2005-04-16 18:24:19 -0400
committerLinus Torvalds <torvalds@ppc970.osdl.org>2005-04-16 18:24:19 -0400
commit0c541b4406a68e74d94ddb667c69d9e03bce8681 (patch)
tree869506b6c3f7c00ac13f2aa80c35fb5e229cc329
parent7a648b9ec09f32606fe0f27fb9d095311cf968ca (diff)
[PATCH] ppc32: Fix AGP and sleep again
My previous patch that added sleep support for uninorth-agp and some AGP "off" stuff in radeonfb and aty128fb is breaking some configs. More specifically, it has problems with rage128 setups since the DRI code for these in X doesn't properly re-enable AGP on wakeup or console switch (unlike the radeon DRM). This patch fixes the problem for pmac once for all by using a different approach. The AGP driver "registers" special suspend/resume callbacks with some arch code that the fbdev's can later on call to suspend and resume AGP, making sure it's resumed back in the same state it was when suspended. This is platform specific for now. It would be too complicated to try to do a generic implementation of this at this point due to all sort of weird things going on with AGP on other architectures. We'll re-work that whole problem cleanly once we finally merge fbdev's and DRI. In the meantime, please apply this patch which brings back some r128 based laptops into working condition as far as system sleep is concerned. Signed-off-by: Benjamin Herrenschmidt <benh@kernel.crashing.org> Signed-off-by: Andrew Morton <akpm@osdl.org> Signed-off-by: Linus Torvalds <torvalds@osdl.org>
-rw-r--r--arch/ppc/platforms/pmac_feature.c45
-rw-r--r--arch/ppc64/kernel/pmac_feature.c64
-rw-r--r--drivers/char/agp/uninorth-agp.c52
-rw-r--r--drivers/video/aty/aty128fb.c34
-rw-r--r--drivers/video/aty/radeon_pm.c43
-rw-r--r--include/asm-ppc/pmac_feature.h11
6 files changed, 193 insertions, 56 deletions
diff --git a/arch/ppc/platforms/pmac_feature.c b/arch/ppc/platforms/pmac_feature.c
index eda9c80746a4..24b42fd9e014 100644
--- a/arch/ppc/platforms/pmac_feature.c
+++ b/arch/ppc/platforms/pmac_feature.c
@@ -2944,3 +2944,48 @@ void __pmac pmac_call_early_video_resume(void)
2944 if (pmac_early_vresume_proc) 2944 if (pmac_early_vresume_proc)
2945 pmac_early_vresume_proc(pmac_early_vresume_data); 2945 pmac_early_vresume_proc(pmac_early_vresume_data);
2946} 2946}
2947
2948/*
2949 * AGP related suspend/resume code
2950 */
2951
2952static struct pci_dev *pmac_agp_bridge __pmacdata;
2953static int (*pmac_agp_suspend)(struct pci_dev *bridge) __pmacdata;
2954static int (*pmac_agp_resume)(struct pci_dev *bridge) __pmacdata;
2955
2956void __pmac pmac_register_agp_pm(struct pci_dev *bridge,
2957 int (*suspend)(struct pci_dev *bridge),
2958 int (*resume)(struct pci_dev *bridge))
2959{
2960 if (suspend || resume) {
2961 pmac_agp_bridge = bridge;
2962 pmac_agp_suspend = suspend;
2963 pmac_agp_resume = resume;
2964 return;
2965 }
2966 if (bridge != pmac_agp_bridge)
2967 return;
2968 pmac_agp_suspend = pmac_agp_resume = NULL;
2969 return;
2970}
2971EXPORT_SYMBOL(pmac_register_agp_pm);
2972
2973void __pmac pmac_suspend_agp_for_card(struct pci_dev *dev)
2974{
2975 if (pmac_agp_bridge == NULL || pmac_agp_suspend == NULL)
2976 return;
2977 if (pmac_agp_bridge->bus != dev->bus)
2978 return;
2979 pmac_agp_suspend(pmac_agp_bridge);
2980}
2981EXPORT_SYMBOL(pmac_suspend_agp_for_card);
2982
2983void __pmac pmac_resume_agp_for_card(struct pci_dev *dev)
2984{
2985 if (pmac_agp_bridge == NULL || pmac_agp_resume == NULL)
2986 return;
2987 if (pmac_agp_bridge->bus != dev->bus)
2988 return;
2989 pmac_agp_resume(pmac_agp_bridge);
2990}
2991EXPORT_SYMBOL(pmac_resume_agp_for_card);
diff --git a/arch/ppc64/kernel/pmac_feature.c b/arch/ppc64/kernel/pmac_feature.c
index 7f1062d222c9..086abc1bcca1 100644
--- a/arch/ppc64/kernel/pmac_feature.c
+++ b/arch/ppc64/kernel/pmac_feature.c
@@ -674,3 +674,67 @@ void __init pmac_check_ht_link(void)
674 dump_HT_speeds("PCI-X HT Downlink", cfg, freq); 674 dump_HT_speeds("PCI-X HT Downlink", cfg, freq);
675#endif 675#endif
676} 676}
677
678/*
679 * Early video resume hook
680 */
681
682static void (*pmac_early_vresume_proc)(void *data) __pmacdata;
683static void *pmac_early_vresume_data __pmacdata;
684
685void pmac_set_early_video_resume(void (*proc)(void *data), void *data)
686{
687 if (_machine != _MACH_Pmac)
688 return;
689 preempt_disable();
690 pmac_early_vresume_proc = proc;
691 pmac_early_vresume_data = data;
692 preempt_enable();
693}
694EXPORT_SYMBOL(pmac_set_early_video_resume);
695
696
697/*
698 * AGP related suspend/resume code
699 */
700
701static struct pci_dev *pmac_agp_bridge __pmacdata;
702static int (*pmac_agp_suspend)(struct pci_dev *bridge) __pmacdata;
703static int (*pmac_agp_resume)(struct pci_dev *bridge) __pmacdata;
704
705void __pmac pmac_register_agp_pm(struct pci_dev *bridge,
706 int (*suspend)(struct pci_dev *bridge),
707 int (*resume)(struct pci_dev *bridge))
708{
709 if (suspend || resume) {
710 pmac_agp_bridge = bridge;
711 pmac_agp_suspend = suspend;
712 pmac_agp_resume = resume;
713 return;
714 }
715 if (bridge != pmac_agp_bridge)
716 return;
717 pmac_agp_suspend = pmac_agp_resume = NULL;
718 return;
719}
720EXPORT_SYMBOL(pmac_register_agp_pm);
721
722void __pmac pmac_suspend_agp_for_card(struct pci_dev *dev)
723{
724 if (pmac_agp_bridge == NULL || pmac_agp_suspend == NULL)
725 return;
726 if (pmac_agp_bridge->bus != dev->bus)
727 return;
728 pmac_agp_suspend(pmac_agp_bridge);
729}
730EXPORT_SYMBOL(pmac_suspend_agp_for_card);
731
732void __pmac pmac_resume_agp_for_card(struct pci_dev *dev)
733{
734 if (pmac_agp_bridge == NULL || pmac_agp_resume == NULL)
735 return;
736 if (pmac_agp_bridge->bus != dev->bus)
737 return;
738 pmac_agp_resume(pmac_agp_bridge);
739}
740EXPORT_SYMBOL(pmac_resume_agp_for_card);
diff --git a/drivers/char/agp/uninorth-agp.c b/drivers/char/agp/uninorth-agp.c
index 0f248239b4ba..a673971f2a90 100644
--- a/drivers/char/agp/uninorth-agp.c
+++ b/drivers/char/agp/uninorth-agp.c
@@ -10,6 +10,7 @@
10#include <asm/uninorth.h> 10#include <asm/uninorth.h>
11#include <asm/pci-bridge.h> 11#include <asm/pci-bridge.h>
12#include <asm/prom.h> 12#include <asm/prom.h>
13#include <asm/pmac_feature.h>
13#include "agp.h" 14#include "agp.h"
14 15
15/* 16/*
@@ -26,6 +27,7 @@
26static int uninorth_rev; 27static int uninorth_rev;
27static int is_u3; 28static int is_u3;
28 29
30
29static int uninorth_fetch_size(void) 31static int uninorth_fetch_size(void)
30{ 32{
31 int i; 33 int i;
@@ -264,7 +266,8 @@ static void uninorth_agp_enable(struct agp_bridge_data *bridge, u32 mode)
264 &scratch); 266 &scratch);
265 } while ((scratch & PCI_AGP_COMMAND_AGP) == 0 && ++timeout < 1000); 267 } while ((scratch & PCI_AGP_COMMAND_AGP) == 0 && ++timeout < 1000);
266 if ((scratch & PCI_AGP_COMMAND_AGP) == 0) 268 if ((scratch & PCI_AGP_COMMAND_AGP) == 0)
267 printk(KERN_ERR PFX "failed to write UniNorth AGP command reg\n"); 269 printk(KERN_ERR PFX "failed to write UniNorth AGP"
270 " command register\n");
268 271
269 if (uninorth_rev >= 0x30) { 272 if (uninorth_rev >= 0x30) {
270 /* This is an AGP V3 */ 273 /* This is an AGP V3 */
@@ -278,13 +281,24 @@ static void uninorth_agp_enable(struct agp_bridge_data *bridge, u32 mode)
278} 281}
279 282
280#ifdef CONFIG_PM 283#ifdef CONFIG_PM
281static int agp_uninorth_suspend(struct pci_dev *pdev, pm_message_t state) 284/*
285 * These Power Management routines are _not_ called by the normal PCI PM layer,
286 * but directly by the video driver through function pointers in the device
287 * tree.
288 */
289static int agp_uninorth_suspend(struct pci_dev *pdev)
282{ 290{
291 struct agp_bridge_data *bridge;
283 u32 cmd; 292 u32 cmd;
284 u8 agp; 293 u8 agp;
285 struct pci_dev *device = NULL; 294 struct pci_dev *device = NULL;
286 295
287 if (state != PMSG_SUSPEND) 296 bridge = agp_find_bridge(pdev);
297 if (bridge == NULL)
298 return -ENODEV;
299
300 /* Only one suspend supported */
301 if (bridge->dev_private_data)
288 return 0; 302 return 0;
289 303
290 /* turn off AGP on the video chip, if it was enabled */ 304 /* turn off AGP on the video chip, if it was enabled */
@@ -315,6 +329,7 @@ static int agp_uninorth_suspend(struct pci_dev *pdev, pm_message_t state)
315 /* turn off AGP on the bridge */ 329 /* turn off AGP on the bridge */
316 agp = pci_find_capability(pdev, PCI_CAP_ID_AGP); 330 agp = pci_find_capability(pdev, PCI_CAP_ID_AGP);
317 pci_read_config_dword(pdev, agp + PCI_AGP_COMMAND, &cmd); 331 pci_read_config_dword(pdev, agp + PCI_AGP_COMMAND, &cmd);
332 bridge->dev_private_data = (void *)cmd;
318 if (cmd & PCI_AGP_COMMAND_AGP) { 333 if (cmd & PCI_AGP_COMMAND_AGP) {
319 printk("uninorth-agp: disabling AGP on bridge %s\n", 334 printk("uninorth-agp: disabling AGP on bridge %s\n",
320 pci_name(pdev)); 335 pci_name(pdev));
@@ -329,9 +344,23 @@ static int agp_uninorth_suspend(struct pci_dev *pdev, pm_message_t state)
329 344
330static int agp_uninorth_resume(struct pci_dev *pdev) 345static int agp_uninorth_resume(struct pci_dev *pdev)
331{ 346{
347 struct agp_bridge_data *bridge;
348 u32 command;
349
350 bridge = agp_find_bridge(pdev);
351 if (bridge == NULL)
352 return -ENODEV;
353
354 command = (u32)bridge->dev_private_data;
355 bridge->dev_private_data = NULL;
356 if (!(command & PCI_AGP_COMMAND_AGP))
357 return 0;
358
359 uninorth_agp_enable(bridge, command);
360
332 return 0; 361 return 0;
333} 362}
334#endif 363#endif /* CONFIG_PM */
335 364
336static int uninorth_create_gatt_table(struct agp_bridge_data *bridge) 365static int uninorth_create_gatt_table(struct agp_bridge_data *bridge)
337{ 366{
@@ -575,6 +604,12 @@ static int __devinit agp_uninorth_probe(struct pci_dev *pdev,
575 of_node_put(uninorth_node); 604 of_node_put(uninorth_node);
576 } 605 }
577 606
607#ifdef CONFIG_PM
608 /* Inform platform of our suspend/resume caps */
609 pmac_register_agp_pm(pdev, agp_uninorth_suspend, agp_uninorth_resume);
610#endif
611
612 /* Allocate & setup our driver */
578 bridge = agp_alloc_bridge(); 613 bridge = agp_alloc_bridge();
579 if (!bridge) 614 if (!bridge)
580 return -ENOMEM; 615 return -ENOMEM;
@@ -599,6 +634,11 @@ static void __devexit agp_uninorth_remove(struct pci_dev *pdev)
599{ 634{
600 struct agp_bridge_data *bridge = pci_get_drvdata(pdev); 635 struct agp_bridge_data *bridge = pci_get_drvdata(pdev);
601 636
637#ifdef CONFIG_PM
638 /* Inform platform of our suspend/resume caps */
639 pmac_register_agp_pm(pdev, NULL, NULL);
640#endif
641
602 agp_remove_bridge(bridge); 642 agp_remove_bridge(bridge);
603 agp_put_bridge(bridge); 643 agp_put_bridge(bridge);
604} 644}
@@ -622,10 +662,6 @@ static struct pci_driver agp_uninorth_pci_driver = {
622 .id_table = agp_uninorth_pci_table, 662 .id_table = agp_uninorth_pci_table,
623 .probe = agp_uninorth_probe, 663 .probe = agp_uninorth_probe,
624 .remove = agp_uninorth_remove, 664 .remove = agp_uninorth_remove,
625#ifdef CONFIG_PM
626 .suspend = agp_uninorth_suspend,
627 .resume = agp_uninorth_resume,
628#endif
629}; 665};
630 666
631static int __init agp_uninorth_init(void) 667static int __init agp_uninorth_init(void)
diff --git a/drivers/video/aty/aty128fb.c b/drivers/video/aty/aty128fb.c
index 8a4ba3bb9872..9789115980a5 100644
--- a/drivers/video/aty/aty128fb.c
+++ b/drivers/video/aty/aty128fb.c
@@ -2331,7 +2331,6 @@ static int aty128_pci_suspend(struct pci_dev *pdev, pm_message_t state)
2331{ 2331{
2332 struct fb_info *info = pci_get_drvdata(pdev); 2332 struct fb_info *info = pci_get_drvdata(pdev);
2333 struct aty128fb_par *par = info->par; 2333 struct aty128fb_par *par = info->par;
2334 u8 agp;
2335 2334
2336 /* We don't do anything but D2, for now we return 0, but 2335 /* We don't do anything but D2, for now we return 0, but
2337 * we may want to change that. How do we know if the BIOS 2336 * we may want to change that. How do we know if the BIOS
@@ -2369,26 +2368,13 @@ static int aty128_pci_suspend(struct pci_dev *pdev, pm_message_t state)
2369 par->asleep = 1; 2368 par->asleep = 1;
2370 par->lock_blank = 1; 2369 par->lock_blank = 1;
2371 2370
2372 /* Disable AGP. The AGP host should have done it, but since ordering 2371#ifdef CONFIG_PPC_PMAC
2373 * isn't always properly guaranteed in this specific case, let's make 2372 /* On powermac, we have hooks to properly suspend/resume AGP now,
2374 * sure it's disabled on card side now. Ultimately, when merging fbdev 2373 * use them here. We'll ultimately need some generic support here,
2375 * and dri into some common infrastructure, this will be handled 2374 * but the generic code isn't quite ready for that yet
2376 * more nicely. The host bridge side will (or will not) be dealt with
2377 * by the bridge AGP driver, we don't attempt to touch it here.
2378 */ 2375 */
2379 agp = pci_find_capability(pdev, PCI_CAP_ID_AGP); 2376 pmac_suspend_agp_for_card(pdev);
2380 if (agp) { 2377#endif /* CONFIG_PPC_PMAC */
2381 u32 cmd;
2382
2383 pci_read_config_dword(pdev, agp + PCI_AGP_COMMAND, &cmd);
2384 if (cmd & PCI_AGP_COMMAND_AGP) {
2385 printk(KERN_INFO "aty128fb: AGP was enabled, "
2386 "disabling ...\n");
2387 cmd &= ~PCI_AGP_COMMAND_AGP;
2388 pci_write_config_dword(pdev, agp + PCI_AGP_COMMAND,
2389 cmd);
2390 }
2391 }
2392 2378
2393 /* We need a way to make sure the fbdev layer will _not_ touch the 2379 /* We need a way to make sure the fbdev layer will _not_ touch the
2394 * framebuffer before we put the chip to suspend state. On 2.4, I 2380 * framebuffer before we put the chip to suspend state. On 2.4, I
@@ -2432,6 +2418,14 @@ static int aty128_do_resume(struct pci_dev *pdev)
2432 par->lock_blank = 0; 2418 par->lock_blank = 0;
2433 aty128fb_blank(0, info); 2419 aty128fb_blank(0, info);
2434 2420
2421#ifdef CONFIG_PPC_PMAC
2422 /* On powermac, we have hooks to properly suspend/resume AGP now,
2423 * use them here. We'll ultimately need some generic support here,
2424 * but the generic code isn't quite ready for that yet
2425 */
2426 pmac_resume_agp_for_card(pdev);
2427#endif /* CONFIG_PPC_PMAC */
2428
2435 pdev->dev.power.power_state = PMSG_ON; 2429 pdev->dev.power.power_state = PMSG_ON;
2436 2430
2437 printk(KERN_DEBUG "aty128fb: resumed !\n"); 2431 printk(KERN_DEBUG "aty128fb: resumed !\n");
diff --git a/drivers/video/aty/radeon_pm.c b/drivers/video/aty/radeon_pm.c
index 23c677e5093f..98352af39325 100644
--- a/drivers/video/aty/radeon_pm.c
+++ b/drivers/video/aty/radeon_pm.c
@@ -2520,13 +2520,10 @@ static int radeon_restore_pci_cfg(struct radeonfb_info *rinfo)
2520} 2520}
2521 2521
2522 2522
2523static/*extern*/ int susdisking = 0;
2524
2525int radeonfb_pci_suspend(struct pci_dev *pdev, pm_message_t state) 2523int radeonfb_pci_suspend(struct pci_dev *pdev, pm_message_t state)
2526{ 2524{
2527 struct fb_info *info = pci_get_drvdata(pdev); 2525 struct fb_info *info = pci_get_drvdata(pdev);
2528 struct radeonfb_info *rinfo = info->par; 2526 struct radeonfb_info *rinfo = info->par;
2529 u8 agp;
2530 int i; 2527 int i;
2531 2528
2532 if (state == pdev->dev.power.power_state) 2529 if (state == pdev->dev.power.power_state)
@@ -2542,11 +2539,6 @@ int radeonfb_pci_suspend(struct pci_dev *pdev, pm_message_t state)
2542 */ 2539 */
2543 if (state != PM_SUSPEND_MEM) 2540 if (state != PM_SUSPEND_MEM)
2544 goto done; 2541 goto done;
2545 if (susdisking) {
2546 printk("radeonfb (%s): suspending to disk but state = %d\n",
2547 pci_name(pdev), state);
2548 goto done;
2549 }
2550 2542
2551 acquire_console_sem(); 2543 acquire_console_sem();
2552 2544
@@ -2567,27 +2559,13 @@ int radeonfb_pci_suspend(struct pci_dev *pdev, pm_message_t state)
2567 rinfo->lock_blank = 1; 2559 rinfo->lock_blank = 1;
2568 del_timer_sync(&rinfo->lvds_timer); 2560 del_timer_sync(&rinfo->lvds_timer);
2569 2561
2570 /* Disable AGP. The AGP host should have done it, but since ordering 2562#ifdef CONFIG_PPC_PMAC
2571 * isn't always properly guaranteed in this specific case, let's make 2563 /* On powermac, we have hooks to properly suspend/resume AGP now,
2572 * sure it's disabled on card side now. Ultimately, when merging fbdev 2564 * use them here. We'll ultimately need some generic support here,
2573 * and dri into some common infrastructure, this will be handled 2565 * but the generic code isn't quite ready for that yet
2574 * more nicely. The host bridge side will (or will not) be dealt with
2575 * by the bridge AGP driver, we don't attempt to touch it here.
2576 */ 2566 */
2577 agp = pci_find_capability(pdev, PCI_CAP_ID_AGP); 2567 pmac_suspend_agp_for_card(pdev);
2578 if (agp) { 2568#endif /* CONFIG_PPC_PMAC */
2579 u32 cmd;
2580
2581 pci_read_config_dword(pdev, agp + PCI_AGP_COMMAND, &cmd);
2582 if (cmd & PCI_AGP_COMMAND_AGP) {
2583 printk(KERN_INFO "radeonfb (%s): AGP was enabled, "
2584 "disabling ...\n",
2585 pci_name(pdev));
2586 cmd &= ~PCI_AGP_COMMAND_AGP;
2587 pci_write_config_dword(pdev, agp + PCI_AGP_COMMAND,
2588 cmd);
2589 }
2590 }
2591 2569
2592 /* If we support wakeup from poweroff, we save all regs we can including cfg 2570 /* If we support wakeup from poweroff, we save all regs we can including cfg
2593 * space 2571 * space
@@ -2699,6 +2677,15 @@ int radeonfb_pci_resume(struct pci_dev *pdev)
2699 rinfo->lock_blank = 0; 2677 rinfo->lock_blank = 0;
2700 radeon_screen_blank(rinfo, FB_BLANK_UNBLANK, 1); 2678 radeon_screen_blank(rinfo, FB_BLANK_UNBLANK, 1);
2701 2679
2680#ifdef CONFIG_PPC_PMAC
2681 /* On powermac, we have hooks to properly suspend/resume AGP now,
2682 * use them here. We'll ultimately need some generic support here,
2683 * but the generic code isn't quite ready for that yet
2684 */
2685 pmac_resume_agp_for_card(pdev);
2686#endif /* CONFIG_PPC_PMAC */
2687
2688
2702 /* Check status of dynclk */ 2689 /* Check status of dynclk */
2703 if (rinfo->dynclk == 1) 2690 if (rinfo->dynclk == 1)
2704 radeon_pm_enable_dynamic_mode(rinfo); 2691 radeon_pm_enable_dynamic_mode(rinfo);
diff --git a/include/asm-ppc/pmac_feature.h b/include/asm-ppc/pmac_feature.h
index 98c206d8c024..639b690ce6f7 100644
--- a/include/asm-ppc/pmac_feature.h
+++ b/include/asm-ppc/pmac_feature.h
@@ -305,6 +305,17 @@ extern void pmac_call_early_video_resume(void);
305 305
306#define PMAC_FTR_DEF(x) ((_MACH_Pmac << 16) | (x)) 306#define PMAC_FTR_DEF(x) ((_MACH_Pmac << 16) | (x))
307 307
308/* The AGP driver registers itself here */
309extern void pmac_register_agp_pm(struct pci_dev *bridge,
310 int (*suspend)(struct pci_dev *bridge),
311 int (*resume)(struct pci_dev *bridge));
312
313/* Those are meant to be used by video drivers to deal with AGP
314 * suspend resume properly
315 */
316extern void pmac_suspend_agp_for_card(struct pci_dev *dev);
317extern void pmac_resume_agp_for_card(struct pci_dev *dev);
318
308 319
309/* 320/*
310 * The part below is for use by macio_asic.c only, do not rely 321 * The part below is for use by macio_asic.c only, do not rely