aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/char/agp/uninorth-agp.c
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 /drivers/char/agp/uninorth-agp.c
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>
Diffstat (limited to 'drivers/char/agp/uninorth-agp.c')
-rw-r--r--drivers/char/agp/uninorth-agp.c52
1 files changed, 44 insertions, 8 deletions
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)