[PATCH] ppc64: very basic desktop g5 sound support
[linux-2.6.git] / arch / ppc64 / kernel / pmac_feature.c
1 /*
2  *  arch/ppc/platforms/pmac_feature.c
3  *
4  *  Copyright (C) 1996-2001 Paul Mackerras (paulus@cs.anu.edu.au)
5  *                          Ben. Herrenschmidt (benh@kernel.crashing.org)
6  *
7  *  This program is free software; you can redistribute it and/or
8  *  modify it under the terms of the GNU General Public License
9  *  as published by the Free Software Foundation; either version
10  *  2 of the License, or (at your option) any later version.
11  *
12  *  TODO:
13  *
14  *   - Replace mdelay with some schedule loop if possible
15  *   - Shorten some obfuscated delays on some routines (like modem
16  *     power)
17  *   - Refcount some clocks (see darwin)
18  *   - Split split split...
19  *
20  */
21 #include <linux/config.h>
22 #include <linux/types.h>
23 #include <linux/init.h>
24 #include <linux/delay.h>
25 #include <linux/kernel.h>
26 #include <linux/sched.h>
27 #include <linux/spinlock.h>
28 #include <linux/adb.h>
29 #include <linux/pmu.h>
30 #include <linux/ioport.h>
31 #include <linux/pci.h>
32 #include <asm/sections.h>
33 #include <asm/errno.h>
34 #include <asm/keylargo.h>
35 #include <asm/uninorth.h>
36 #include <asm/io.h>
37 #include <asm/prom.h>
38 #include <asm/machdep.h>
39 #include <asm/pmac_feature.h>
40 #include <asm/dbdma.h>
41 #include <asm/pci-bridge.h>
42 #include <asm/pmac_low_i2c.h>
43
44 #undef DEBUG_FEATURE
45
46 #ifdef DEBUG_FEATURE
47 #define DBG(fmt...) printk(KERN_DEBUG fmt)
48 #else
49 #define DBG(fmt...)
50 #endif
51
52 /*
53  * We use a single global lock to protect accesses. Each driver has
54  * to take care of its own locking
55  */
56 static DEFINE_SPINLOCK(feature_lock  __pmacdata);
57
58 #define LOCK(flags)     spin_lock_irqsave(&feature_lock, flags);
59 #define UNLOCK(flags)   spin_unlock_irqrestore(&feature_lock, flags);
60
61
62 /*
63  * Instance of some macio stuffs
64  */
65 struct macio_chip macio_chips[MAX_MACIO_CHIPS]  __pmacdata;
66
67 struct macio_chip* __pmac macio_find(struct device_node* child, int type)
68 {
69         while(child) {
70                 int     i;
71
72                 for (i=0; i < MAX_MACIO_CHIPS && macio_chips[i].of_node; i++)
73                         if (child == macio_chips[i].of_node &&
74                             (!type || macio_chips[i].type == type))
75                                 return &macio_chips[i];
76                 child = child->parent;
77         }
78         return NULL;
79 }
80 EXPORT_SYMBOL_GPL(macio_find);
81
82 static const char* macio_names[] __pmacdata =
83 {
84         "Unknown",
85         "Grand Central",
86         "OHare",
87         "OHareII",
88         "Heathrow",
89         "Gatwick",
90         "Paddington",
91         "Keylargo",
92         "Pangea",
93         "Intrepid",
94         "K2"
95 };
96
97
98
99 /*
100  * Uninorth reg. access. Note that Uni-N regs are big endian
101  */
102
103 #define UN_REG(r)       (uninorth_base + ((r) >> 2))
104 #define UN_IN(r)        (in_be32(UN_REG(r)))
105 #define UN_OUT(r,v)     (out_be32(UN_REG(r), (v)))
106 #define UN_BIS(r,v)     (UN_OUT((r), UN_IN(r) | (v)))
107 #define UN_BIC(r,v)     (UN_OUT((r), UN_IN(r) & ~(v)))
108
109 static struct device_node* uninorth_node __pmacdata;
110 static u32* uninorth_base __pmacdata;
111 static u32 uninorth_rev __pmacdata;
112 static void *u3_ht;
113
114 extern struct device_node *k2_skiplist[2];
115
116 /*
117  * For each motherboard family, we have a table of functions pointers
118  * that handle the various features.
119  */
120
121 typedef long (*feature_call)(struct device_node* node, long param, long value);
122
123 struct feature_table_entry {
124         unsigned int    selector;
125         feature_call    function;
126 };
127
128 struct pmac_mb_def
129 {
130         const char*                     model_string;
131         const char*                     model_name;
132         int                             model_id;
133         struct feature_table_entry*     features;
134         unsigned long                   board_flags;
135 };
136 static struct pmac_mb_def pmac_mb __pmacdata;
137
138 /*
139  * Here are the chip specific feature functions
140  */
141
142
143 static long __pmac g5_read_gpio(struct device_node* node, long param, long value)
144 {
145         struct macio_chip* macio = &macio_chips[0];
146
147         return MACIO_IN8(param);
148 }
149
150
151 static long __pmac g5_write_gpio(struct device_node* node, long param, long value)
152 {
153         struct macio_chip* macio = &macio_chips[0];
154
155         MACIO_OUT8(param, (u8)(value & 0xff));
156         return 0;
157 }
158
159 static long __pmac g5_gmac_enable(struct device_node* node, long param, long value)
160 {
161         struct macio_chip* macio = &macio_chips[0];
162         unsigned long flags;
163
164         if (node == NULL)
165                 return -ENODEV;
166
167         LOCK(flags);
168         if (value) {
169                 MACIO_BIS(KEYLARGO_FCR1, K2_FCR1_GMAC_CLK_ENABLE);
170                 mb();
171                 k2_skiplist[0] = NULL;
172         } else {
173                 k2_skiplist[0] = node;
174                 mb();
175                 MACIO_BIC(KEYLARGO_FCR1, K2_FCR1_GMAC_CLK_ENABLE);
176         }
177         
178         UNLOCK(flags);
179         mdelay(1);
180
181         return 0;
182 }
183
184 static long __pmac g5_fw_enable(struct device_node* node, long param, long value)
185 {
186         struct macio_chip* macio = &macio_chips[0];
187         unsigned long flags;
188
189         if (node == NULL)
190                 return -ENODEV;
191
192         LOCK(flags);
193         if (value) {
194                 MACIO_BIS(KEYLARGO_FCR1, K2_FCR1_FW_CLK_ENABLE);
195                 mb();
196                 k2_skiplist[1] = NULL;
197         } else {
198                 k2_skiplist[1] = node;
199                 mb();
200                 MACIO_BIC(KEYLARGO_FCR1, K2_FCR1_FW_CLK_ENABLE);
201         }
202         
203         UNLOCK(flags);
204         mdelay(1);
205
206         return 0;
207 }
208
209 static long __pmac g5_mpic_enable(struct device_node* node, long param, long value)
210 {
211         unsigned long flags;
212
213         if (node->parent == NULL || strcmp(node->parent->name, "u3"))
214                 return 0;
215
216         LOCK(flags);
217         UN_BIS(U3_TOGGLE_REG, U3_MPIC_RESET | U3_MPIC_OUTPUT_ENABLE);
218         UNLOCK(flags);
219
220         return 0;
221 }
222
223 static long __pmac g5_eth_phy_reset(struct device_node* node, long param, long value)
224 {
225         struct macio_chip* macio = &macio_chips[0];
226         struct device_node *phy;
227         int need_reset;
228
229         /*
230          * We must not reset the combo PHYs, only the BCM5221 found in
231          * the iMac G5.
232          */
233         phy = of_get_next_child(node, NULL);
234         if (!phy)
235                 return -ENODEV;
236         need_reset = device_is_compatible(phy, "B5221");
237         of_node_put(phy);
238         if (!need_reset)
239                 return 0;
240
241         /* PHY reset is GPIO 29, not in device-tree unfortunately */
242         MACIO_OUT8(K2_GPIO_EXTINT_0 + 29,
243                    KEYLARGO_GPIO_OUTPUT_ENABLE | KEYLARGO_GPIO_OUTOUT_DATA);
244         /* Thankfully, this is now always called at a time when we can
245          * schedule by sungem.
246          */
247         msleep(10);
248         MACIO_OUT8(K2_GPIO_EXTINT_0 + 29, 0);
249
250         return 0;
251 }
252
253 static long __pmac g5_i2s_enable(struct device_node *node, long param, long value)
254 {
255         /* Very crude implementation for now */
256         struct macio_chip* macio = &macio_chips[0];
257         unsigned long flags;
258
259         if (value == 0)
260                 return 0; /* don't disable yet */
261
262         LOCK(flags);
263         MACIO_BIS(KEYLARGO_FCR3, KL3_CLK45_ENABLE | KL3_CLK49_ENABLE |
264                   KL3_I2S0_CLK18_ENABLE);
265         udelay(10);
266         MACIO_BIS(KEYLARGO_FCR1, K2_FCR1_I2S0_CELL_ENABLE |
267                   K2_FCR1_I2S0_CLK_ENABLE_BIT | K2_FCR1_I2S0_ENABLE);
268         udelay(10);
269         MACIO_BIC(KEYLARGO_FCR1, K2_FCR1_I2S0_RESET);
270         UNLOCK(flags);
271         udelay(10);
272
273         return 0;
274 }
275
276
277 #ifdef CONFIG_SMP
278 static long __pmac g5_reset_cpu(struct device_node* node, long param, long value)
279 {
280         unsigned int reset_io = 0;
281         unsigned long flags;
282         struct macio_chip* macio;
283         struct device_node* np;
284
285         macio = &macio_chips[0];
286         if (macio->type != macio_keylargo2)
287                 return -ENODEV;
288
289         np = find_path_device("/cpus");
290         if (np == NULL)
291                 return -ENODEV;
292         for (np = np->child; np != NULL; np = np->sibling) {
293                 u32* num = (u32 *)get_property(np, "reg", NULL);
294                 u32* rst = (u32 *)get_property(np, "soft-reset", NULL);
295                 if (num == NULL || rst == NULL)
296                         continue;
297                 if (param == *num) {
298                         reset_io = *rst;
299                         break;
300                 }
301         }
302         if (np == NULL || reset_io == 0)
303                 return -ENODEV;
304
305         LOCK(flags);
306         MACIO_OUT8(reset_io, KEYLARGO_GPIO_OUTPUT_ENABLE);
307         (void)MACIO_IN8(reset_io);
308         udelay(1);
309         MACIO_OUT8(reset_io, 0);
310         (void)MACIO_IN8(reset_io);
311         UNLOCK(flags);
312
313         return 0;
314 }
315 #endif /* CONFIG_SMP */
316
317 /*
318  * This can be called from pmac_smp so isn't static
319  *
320  * This takes the second CPU off the bus on dual CPU machines
321  * running UP
322  */
323 void __pmac g5_phy_disable_cpu1(void)
324 {
325         UN_OUT(U3_API_PHY_CONFIG_1, 0);
326 }
327
328 static long __pmac generic_get_mb_info(struct device_node* node, long param, long value)
329 {
330         switch(param) {
331                 case PMAC_MB_INFO_MODEL:
332                         return pmac_mb.model_id;
333                 case PMAC_MB_INFO_FLAGS:
334                         return pmac_mb.board_flags;
335                 case PMAC_MB_INFO_NAME:                 
336                         /* hack hack hack... but should work */
337                         *((const char **)value) = pmac_mb.model_name;
338                         return 0;
339         }
340         return -EINVAL;
341 }
342
343
344 /*
345  * Table definitions
346  */
347
348 /* Used on any machine
349  */
350 static struct feature_table_entry any_features[]  __pmacdata = {
351         { PMAC_FTR_GET_MB_INFO,         generic_get_mb_info },
352         { 0, NULL }
353 };
354
355 /* G5 features
356  */
357 static struct feature_table_entry g5_features[]  __pmacdata = {
358         { PMAC_FTR_GMAC_ENABLE,         g5_gmac_enable },
359         { PMAC_FTR_1394_ENABLE,         g5_fw_enable },
360         { PMAC_FTR_ENABLE_MPIC,         g5_mpic_enable },
361         { PMAC_FTR_READ_GPIO,           g5_read_gpio },
362         { PMAC_FTR_WRITE_GPIO,          g5_write_gpio },
363         { PMAC_FTR_GMAC_PHY_RESET,      g5_eth_phy_reset },
364         { PMAC_FTR_SOUND_CHIP_ENABLE,   g5_i2s_enable },
365 #ifdef CONFIG_SMP
366         { PMAC_FTR_RESET_CPU,           g5_reset_cpu },
367 #endif /* CONFIG_SMP */
368         { 0, NULL }
369 };
370
371 static struct pmac_mb_def pmac_mb_defs[] __pmacdata = {
372         {       "PowerMac7,2",                  "PowerMac G5",
373                 PMAC_TYPE_POWERMAC_G5,          g5_features,
374                 0,
375         },
376         {       "PowerMac7,3",                  "PowerMac G5",
377                 PMAC_TYPE_POWERMAC_G5,          g5_features,
378                 0,
379         },
380         {       "PowerMac8,1",                  "iMac G5",
381                 PMAC_TYPE_IMAC_G5,              g5_features,
382                 0,
383         },
384         {       "PowerMac9,1",                  "PowerMac G5",
385                 PMAC_TYPE_POWERMAC_G5_U3L,      g5_features,
386                 0,
387         },
388         {       "RackMac3,1",                   "XServe G5",
389                 PMAC_TYPE_XSERVE_G5,            g5_features,
390                 0,
391         },
392 };
393
394 /*
395  * The toplevel feature_call callback
396  */
397 long __pmac pmac_do_feature_call(unsigned int selector, ...)
398 {
399         struct device_node* node;
400         long param, value;
401         int i;
402         feature_call func = NULL;
403         va_list args;
404
405         if (pmac_mb.features)
406                 for (i=0; pmac_mb.features[i].function; i++)
407                         if (pmac_mb.features[i].selector == selector) {
408                                 func = pmac_mb.features[i].function;
409                                 break;
410                         }
411         if (!func)
412                 for (i=0; any_features[i].function; i++)
413                         if (any_features[i].selector == selector) {
414                                 func = any_features[i].function;
415                                 break;
416                         }
417         if (!func)
418                 return -ENODEV;
419
420         va_start(args, selector);
421         node = (struct device_node*)va_arg(args, void*);
422         param = va_arg(args, long);
423         value = va_arg(args, long);
424         va_end(args);
425
426         return func(node, param, value);
427 }
428
429 static int __init probe_motherboard(void)
430 {
431         int i;
432         struct macio_chip* macio = &macio_chips[0];
433         const char* model = NULL;
434         struct device_node *dt;
435
436         /* Lookup known motherboard type in device-tree. First try an
437          * exact match on the "model" property, then try a "compatible"
438          * match is none is found.
439          */
440         dt = find_devices("device-tree");
441         if (dt != NULL)
442                 model = (const char *) get_property(dt, "model", NULL);
443         for(i=0; model && i<(sizeof(pmac_mb_defs)/sizeof(struct pmac_mb_def)); i++) {
444             if (strcmp(model, pmac_mb_defs[i].model_string) == 0) {
445                 pmac_mb = pmac_mb_defs[i];
446                 goto found;
447             }
448         }
449         for(i=0; i<(sizeof(pmac_mb_defs)/sizeof(struct pmac_mb_def)); i++) {
450             if (machine_is_compatible(pmac_mb_defs[i].model_string)) {
451                 pmac_mb = pmac_mb_defs[i];
452                 goto found;
453             }
454         }
455
456         /* Fallback to selection depending on mac-io chip type */
457         switch(macio->type) {
458         case macio_keylargo2:
459                 pmac_mb.model_id = PMAC_TYPE_UNKNOWN_K2;
460                 pmac_mb.model_name = "Unknown K2-based";
461                 pmac_mb.features = g5_features;
462                 
463         default:
464                 return -ENODEV;
465         }
466 found:
467         /* Check for "mobile" machine */
468         if (model && (strncmp(model, "PowerBook", 9) == 0
469                    || strncmp(model, "iBook", 5) == 0))
470                 pmac_mb.board_flags |= PMAC_MB_MOBILE;
471
472
473         printk(KERN_INFO "PowerMac motherboard: %s\n", pmac_mb.model_name);
474         return 0;
475 }
476
477 /* Initialize the Core99 UniNorth host bridge and memory controller
478  */
479 static void __init probe_uninorth(void)
480 {
481         uninorth_node = of_find_node_by_name(NULL, "u3");
482         if (uninorth_node && uninorth_node->n_addrs > 0) {
483                 /* Small hack until I figure out if parsing in prom.c is correct. I should
484                  * get rid of those pre-parsed junk anyway
485                  */
486                 unsigned long address = uninorth_node->addrs[0].address;
487                 uninorth_base = ioremap(address, 0x40000);
488                 uninorth_rev = in_be32(UN_REG(UNI_N_VERSION));
489                 u3_ht = ioremap(address + U3_HT_CONFIG_BASE, 0x1000);
490         } else
491                 uninorth_node = NULL;
492
493         if (!uninorth_node)
494                 return;
495
496         printk(KERN_INFO "Found U3 memory controller & host bridge, revision: %d\n",
497                uninorth_rev);
498         printk(KERN_INFO "Mapped at 0x%08lx\n", (unsigned long)uninorth_base);
499
500 }
501
502 static void __init probe_one_macio(const char* name, const char* compat, int type)
503 {
504         struct device_node*     node;
505         int                     i;
506         volatile u32*           base;
507         u32*                    revp;
508
509         node = find_devices(name);
510         if (!node || !node->n_addrs)
511                 return;
512         if (compat)
513                 do {
514                         if (device_is_compatible(node, compat))
515                                 break;
516                         node = node->next;
517                 } while (node);
518         if (!node)
519                 return;
520         for(i=0; i<MAX_MACIO_CHIPS; i++) {
521                 if (!macio_chips[i].of_node)
522                         break;
523                 if (macio_chips[i].of_node == node)
524                         return;
525         }
526         if (i >= MAX_MACIO_CHIPS) {
527                 printk(KERN_ERR "pmac_feature: Please increase MAX_MACIO_CHIPS !\n");
528                 printk(KERN_ERR "pmac_feature: %s skipped\n", node->full_name);
529                 return;
530         }
531         base = (volatile u32*)ioremap(node->addrs[0].address, node->addrs[0].size);
532         if (!base) {
533                 printk(KERN_ERR "pmac_feature: Can't map mac-io chip !\n");
534                 return;
535         }
536         if (type == macio_keylargo) {
537                 u32* did = (u32 *)get_property(node, "device-id", NULL);
538                 if (*did == 0x00000025)
539                         type = macio_pangea;
540                 if (*did == 0x0000003e)
541                         type = macio_intrepid;
542         }
543         macio_chips[i].of_node  = node;
544         macio_chips[i].type     = type;
545         macio_chips[i].base     = base;
546         macio_chips[i].flags    = MACIO_FLAG_SCCB_ON | MACIO_FLAG_SCCB_ON;
547         macio_chips[i].name     = macio_names[type];
548         revp = (u32 *)get_property(node, "revision-id", NULL);
549         if (revp)
550                 macio_chips[i].rev = *revp;
551         printk(KERN_INFO "Found a %s mac-io controller, rev: %d, mapped at 0x%p\n",
552                 macio_names[type], macio_chips[i].rev, macio_chips[i].base);
553 }
554
555 static int __init
556 probe_macios(void)
557 {
558         probe_one_macio("mac-io", "K2-Keylargo", macio_keylargo2);
559
560         macio_chips[0].lbus.index = 0;
561         macio_chips[1].lbus.index = 1;
562
563         return (macio_chips[0].of_node == NULL) ? -ENODEV : 0;
564 }
565
566 static void __init
567 set_initial_features(void)
568 {
569         struct device_node *np;
570
571         if (macio_chips[0].type == macio_keylargo2) {
572 #ifndef CONFIG_SMP
573                 /* On SMP machines running UP, we have the second CPU eating
574                  * bus cycles. We need to take it off the bus. This is done
575                  * from pmac_smp for SMP kernels running on one CPU
576                  */
577                 np = of_find_node_by_type(NULL, "cpu");
578                 if (np != NULL)
579                         np = of_find_node_by_type(np, "cpu");
580                 if (np != NULL) {
581                         g5_phy_disable_cpu1();
582                         of_node_put(np);
583                 }
584 #endif /* CONFIG_SMP */
585                 /* Enable GMAC for now for PCI probing. It will be disabled
586                  * later on after PCI probe
587                  */
588                 np = of_find_node_by_name(NULL, "ethernet");
589                 while(np) {
590                         if (device_is_compatible(np, "K2-GMAC"))
591                                 g5_gmac_enable(np, 0, 1);
592                         np = of_find_node_by_name(np, "ethernet");
593                 }
594
595                 /* Enable FW before PCI probe. Will be disabled later on
596                  * Note: We should have a batter way to check that we are
597                  * dealing with uninorth internal cell and not a PCI cell
598                  * on the external PCI. The code below works though.
599                  */
600                 np = of_find_node_by_name(NULL, "firewire");
601                 while(np) {
602                         if (device_is_compatible(np, "pci106b,5811")) {
603                                 macio_chips[0].flags |= MACIO_FLAG_FW_SUPPORTED;
604                                 g5_fw_enable(np, 0, 1);
605                         }
606                         np = of_find_node_by_name(np, "firewire");
607                 }
608         }
609 }
610
611 void __init
612 pmac_feature_init(void)
613 {
614         /* Detect the UniNorth memory controller */
615         probe_uninorth();
616
617         /* Probe mac-io controllers */
618         if (probe_macios()) {
619                 printk(KERN_WARNING "No mac-io chip found\n");
620                 return;
621         }
622
623         /* Setup low-level i2c stuffs */
624         pmac_init_low_i2c();
625
626         /* Probe machine type */
627         if (probe_motherboard())
628                 printk(KERN_WARNING "Unknown PowerMac !\n");
629
630         /* Set some initial features (turn off some chips that will
631          * be later turned on)
632          */
633         set_initial_features();
634 }
635
636 int __init pmac_feature_late_init(void)
637 {
638 #if 0
639         struct device_node* np;
640
641         /* Request some resources late */
642         if (uninorth_node)
643                 request_OF_resource(uninorth_node, 0, NULL);
644         np = find_devices("hammerhead");
645         if (np)
646                 request_OF_resource(np, 0, NULL);
647         np = find_devices("interrupt-controller");
648         if (np)
649                 request_OF_resource(np, 0, NULL);
650 #endif
651         return 0;
652 }
653
654 device_initcall(pmac_feature_late_init);
655
656 #if 0
657 static void dump_HT_speeds(char *name, u32 cfg, u32 frq)
658 {
659         int     freqs[16] = { 200,300,400,500,600,800,1000,0,0,0,0,0,0,0,0,0 };
660         int     bits[8] = { 8,16,0,32,2,4,0,0 };
661         int     freq = (frq >> 8) & 0xf;
662
663         if (freqs[freq] == 0)
664                 printk("%s: Unknown HT link frequency %x\n", name, freq);
665         else
666                 printk("%s: %d MHz on main link, (%d in / %d out) bits width\n",
667                        name, freqs[freq],
668                        bits[(cfg >> 28) & 0x7], bits[(cfg >> 24) & 0x7]);
669 }
670 #endif
671
672 void __init pmac_check_ht_link(void)
673 {
674 #if 0 /* Disabled for now */
675         u32     ufreq, freq, ucfg, cfg;
676         struct device_node *pcix_node;
677         u8      px_bus, px_devfn;
678         struct pci_controller *px_hose;
679
680         (void)in_be32(u3_ht + U3_HT_LINK_COMMAND);
681         ucfg = cfg = in_be32(u3_ht + U3_HT_LINK_CONFIG);
682         ufreq = freq = in_be32(u3_ht + U3_HT_LINK_FREQ);
683         dump_HT_speeds("U3 HyperTransport", cfg, freq);
684
685         pcix_node = of_find_compatible_node(NULL, "pci", "pci-x");
686         if (pcix_node == NULL) {
687                 printk("No PCI-X bridge found\n");
688                 return;
689         }
690         px_hose = pcix_node->phb;
691         px_bus = pcix_node->busno;
692         px_devfn = pcix_node->devfn;
693         
694         early_read_config_dword(px_hose, px_bus, px_devfn, 0xc4, &cfg);
695         early_read_config_dword(px_hose, px_bus, px_devfn, 0xcc, &freq);
696         dump_HT_speeds("PCI-X HT Uplink", cfg, freq);
697         early_read_config_dword(px_hose, px_bus, px_devfn, 0xc8, &cfg);
698         early_read_config_dword(px_hose, px_bus, px_devfn, 0xd0, &freq);
699         dump_HT_speeds("PCI-X HT Downlink", cfg, freq);
700 #endif
701 }
702
703 /*
704  * Early video resume hook
705  */
706
707 static void (*pmac_early_vresume_proc)(void *data) __pmacdata;
708 static void *pmac_early_vresume_data __pmacdata;
709
710 void pmac_set_early_video_resume(void (*proc)(void *data), void *data)
711 {
712         if (_machine != _MACH_Pmac)
713                 return;
714         preempt_disable();
715         pmac_early_vresume_proc = proc;
716         pmac_early_vresume_data = data;
717         preempt_enable();
718 }
719 EXPORT_SYMBOL(pmac_set_early_video_resume);
720
721
722 /*
723  * AGP related suspend/resume code
724  */
725
726 static struct pci_dev *pmac_agp_bridge __pmacdata;
727 static int (*pmac_agp_suspend)(struct pci_dev *bridge) __pmacdata;
728 static int (*pmac_agp_resume)(struct pci_dev *bridge) __pmacdata;
729
730 void __pmac pmac_register_agp_pm(struct pci_dev *bridge,
731                                  int (*suspend)(struct pci_dev *bridge),
732                                  int (*resume)(struct pci_dev *bridge))
733 {
734         if (suspend || resume) {
735                 pmac_agp_bridge = bridge;
736                 pmac_agp_suspend = suspend;
737                 pmac_agp_resume = resume;
738                 return;
739         }
740         if (bridge != pmac_agp_bridge)
741                 return;
742         pmac_agp_suspend = pmac_agp_resume = NULL;
743         return;
744 }
745 EXPORT_SYMBOL(pmac_register_agp_pm);
746
747 void __pmac pmac_suspend_agp_for_card(struct pci_dev *dev)
748 {
749         if (pmac_agp_bridge == NULL || pmac_agp_suspend == NULL)
750                 return;
751         if (pmac_agp_bridge->bus != dev->bus)
752                 return;
753         pmac_agp_suspend(pmac_agp_bridge);
754 }
755 EXPORT_SYMBOL(pmac_suspend_agp_for_card);
756
757 void __pmac pmac_resume_agp_for_card(struct pci_dev *dev)
758 {
759         if (pmac_agp_bridge == NULL || pmac_agp_resume == NULL)
760                 return;
761         if (pmac_agp_bridge->bus != dev->bus)
762                 return;
763         pmac_agp_resume(pmac_agp_bridge);
764 }
765 EXPORT_SYMBOL(pmac_resume_agp_for_card);