xref: /openbmc/linux/arch/powerpc/platforms/powermac/feature.c (revision cc5d0189b9ba95260857a5018a1c2fef90008507)
1f6d57916SPaul Mackerras /*
2f6d57916SPaul Mackerras  *  arch/ppc/platforms/pmac_feature.c
3f6d57916SPaul Mackerras  *
4f6d57916SPaul Mackerras  *  Copyright (C) 1996-2001 Paul Mackerras (paulus@cs.anu.edu.au)
5f6d57916SPaul Mackerras  *                          Ben. Herrenschmidt (benh@kernel.crashing.org)
6f6d57916SPaul Mackerras  *
7f6d57916SPaul Mackerras  *  This program is free software; you can redistribute it and/or
8f6d57916SPaul Mackerras  *  modify it under the terms of the GNU General Public License
9f6d57916SPaul Mackerras  *  as published by the Free Software Foundation; either version
10f6d57916SPaul Mackerras  *  2 of the License, or (at your option) any later version.
11f6d57916SPaul Mackerras  *
12f6d57916SPaul Mackerras  *  TODO:
13f6d57916SPaul Mackerras  *
14f6d57916SPaul Mackerras  *   - Replace mdelay with some schedule loop if possible
15f6d57916SPaul Mackerras  *   - Shorten some obfuscated delays on some routines (like modem
16f6d57916SPaul Mackerras  *     power)
17f6d57916SPaul Mackerras  *   - Refcount some clocks (see darwin)
18f6d57916SPaul Mackerras  *   - Split split split...
19f6d57916SPaul Mackerras  *
20f6d57916SPaul Mackerras  */
21f6d57916SPaul Mackerras #include <linux/config.h>
22f6d57916SPaul Mackerras #include <linux/types.h>
23f6d57916SPaul Mackerras #include <linux/init.h>
24f6d57916SPaul Mackerras #include <linux/delay.h>
25f6d57916SPaul Mackerras #include <linux/kernel.h>
26f6d57916SPaul Mackerras #include <linux/sched.h>
27f6d57916SPaul Mackerras #include <linux/spinlock.h>
28f6d57916SPaul Mackerras #include <linux/adb.h>
29f6d57916SPaul Mackerras #include <linux/pmu.h>
30f6d57916SPaul Mackerras #include <linux/ioport.h>
31f6d57916SPaul Mackerras #include <linux/pci.h>
32f6d57916SPaul Mackerras #include <asm/sections.h>
33f6d57916SPaul Mackerras #include <asm/errno.h>
34f6d57916SPaul Mackerras #include <asm/ohare.h>
35f6d57916SPaul Mackerras #include <asm/heathrow.h>
36f6d57916SPaul Mackerras #include <asm/keylargo.h>
37f6d57916SPaul Mackerras #include <asm/uninorth.h>
38f6d57916SPaul Mackerras #include <asm/io.h>
39f6d57916SPaul Mackerras #include <asm/prom.h>
40f6d57916SPaul Mackerras #include <asm/machdep.h>
41f6d57916SPaul Mackerras #include <asm/pmac_feature.h>
42f6d57916SPaul Mackerras #include <asm/dbdma.h>
43f6d57916SPaul Mackerras #include <asm/pci-bridge.h>
44f6d57916SPaul Mackerras #include <asm/pmac_low_i2c.h>
45f6d57916SPaul Mackerras 
46f6d57916SPaul Mackerras #undef DEBUG_FEATURE
47f6d57916SPaul Mackerras 
48f6d57916SPaul Mackerras #ifdef DEBUG_FEATURE
49f6d57916SPaul Mackerras #define DBG(fmt...) printk(KERN_DEBUG fmt)
50f6d57916SPaul Mackerras #else
51f6d57916SPaul Mackerras #define DBG(fmt...)
52f6d57916SPaul Mackerras #endif
53f6d57916SPaul Mackerras 
54f6d57916SPaul Mackerras #ifdef CONFIG_6xx
55f6d57916SPaul Mackerras extern int powersave_lowspeed;
56f6d57916SPaul Mackerras #endif
57f6d57916SPaul Mackerras 
58f6d57916SPaul Mackerras extern int powersave_nap;
59f6d57916SPaul Mackerras extern struct device_node *k2_skiplist[2];
60f6d57916SPaul Mackerras 
61f6d57916SPaul Mackerras 
62f6d57916SPaul Mackerras /*
63f6d57916SPaul Mackerras  * We use a single global lock to protect accesses. Each driver has
64f6d57916SPaul Mackerras  * to take care of its own locking
65f6d57916SPaul Mackerras  */
66f6d57916SPaul Mackerras static DEFINE_SPINLOCK(feature_lock);
67f6d57916SPaul Mackerras 
68f6d57916SPaul Mackerras #define LOCK(flags)	spin_lock_irqsave(&feature_lock, flags);
69f6d57916SPaul Mackerras #define UNLOCK(flags)	spin_unlock_irqrestore(&feature_lock, flags);
70f6d57916SPaul Mackerras 
71f6d57916SPaul Mackerras 
72f6d57916SPaul Mackerras /*
73f6d57916SPaul Mackerras  * Instance of some macio stuffs
74f6d57916SPaul Mackerras  */
75f6d57916SPaul Mackerras struct macio_chip macio_chips[MAX_MACIO_CHIPS];
76f6d57916SPaul Mackerras 
77f6d57916SPaul Mackerras struct macio_chip *macio_find(struct device_node *child, int type)
78f6d57916SPaul Mackerras {
79f6d57916SPaul Mackerras 	while(child) {
80f6d57916SPaul Mackerras 		int	i;
81f6d57916SPaul Mackerras 
82f6d57916SPaul Mackerras 		for (i=0; i < MAX_MACIO_CHIPS && macio_chips[i].of_node; i++)
83f6d57916SPaul Mackerras 			if (child == macio_chips[i].of_node &&
84f6d57916SPaul Mackerras 			    (!type || macio_chips[i].type == type))
85f6d57916SPaul Mackerras 				return &macio_chips[i];
86f6d57916SPaul Mackerras 		child = child->parent;
87f6d57916SPaul Mackerras 	}
88f6d57916SPaul Mackerras 	return NULL;
89f6d57916SPaul Mackerras }
90f6d57916SPaul Mackerras EXPORT_SYMBOL_GPL(macio_find);
91f6d57916SPaul Mackerras 
92f6d57916SPaul Mackerras static const char *macio_names[] =
93f6d57916SPaul Mackerras {
94f6d57916SPaul Mackerras 	"Unknown",
95f6d57916SPaul Mackerras 	"Grand Central",
96f6d57916SPaul Mackerras 	"OHare",
97f6d57916SPaul Mackerras 	"OHareII",
98f6d57916SPaul Mackerras 	"Heathrow",
99f6d57916SPaul Mackerras 	"Gatwick",
100f6d57916SPaul Mackerras 	"Paddington",
101f6d57916SPaul Mackerras 	"Keylargo",
102f6d57916SPaul Mackerras 	"Pangea",
103f6d57916SPaul Mackerras 	"Intrepid",
104f6d57916SPaul Mackerras 	"K2"
105f6d57916SPaul Mackerras };
106f6d57916SPaul Mackerras 
107f6d57916SPaul Mackerras 
108f6d57916SPaul Mackerras 
109f6d57916SPaul Mackerras /*
110f6d57916SPaul Mackerras  * Uninorth reg. access. Note that Uni-N regs are big endian
111f6d57916SPaul Mackerras  */
112f6d57916SPaul Mackerras 
113f6d57916SPaul Mackerras #define UN_REG(r)	(uninorth_base + ((r) >> 2))
114f6d57916SPaul Mackerras #define UN_IN(r)	(in_be32(UN_REG(r)))
115f6d57916SPaul Mackerras #define UN_OUT(r,v)	(out_be32(UN_REG(r), (v)))
116f6d57916SPaul Mackerras #define UN_BIS(r,v)	(UN_OUT((r), UN_IN(r) | (v)))
117f6d57916SPaul Mackerras #define UN_BIC(r,v)	(UN_OUT((r), UN_IN(r) & ~(v)))
118f6d57916SPaul Mackerras 
119f6d57916SPaul Mackerras static struct device_node *uninorth_node;
120f6d57916SPaul Mackerras static u32 __iomem *uninorth_base;
121f6d57916SPaul Mackerras static u32 uninorth_rev;
122f6d57916SPaul Mackerras static int uninorth_u3;
123f6d57916SPaul Mackerras static void __iomem *u3_ht;
124f6d57916SPaul Mackerras 
125f6d57916SPaul Mackerras /*
126f6d57916SPaul Mackerras  * For each motherboard family, we have a table of functions pointers
127f6d57916SPaul Mackerras  * that handle the various features.
128f6d57916SPaul Mackerras  */
129f6d57916SPaul Mackerras 
130f6d57916SPaul Mackerras typedef long (*feature_call)(struct device_node *node, long param, long value);
131f6d57916SPaul Mackerras 
132f6d57916SPaul Mackerras struct feature_table_entry {
133f6d57916SPaul Mackerras 	unsigned int	selector;
134f6d57916SPaul Mackerras 	feature_call	function;
135f6d57916SPaul Mackerras };
136f6d57916SPaul Mackerras 
137f6d57916SPaul Mackerras struct pmac_mb_def
138f6d57916SPaul Mackerras {
139f6d57916SPaul Mackerras 	const char*			model_string;
140f6d57916SPaul Mackerras 	const char*			model_name;
141f6d57916SPaul Mackerras 	int				model_id;
142f6d57916SPaul Mackerras 	struct feature_table_entry*	features;
143f6d57916SPaul Mackerras 	unsigned long			board_flags;
144f6d57916SPaul Mackerras };
145f6d57916SPaul Mackerras static struct pmac_mb_def pmac_mb;
146f6d57916SPaul Mackerras 
147f6d57916SPaul Mackerras /*
148f6d57916SPaul Mackerras  * Here are the chip specific feature functions
149f6d57916SPaul Mackerras  */
150f6d57916SPaul Mackerras 
151f6d57916SPaul Mackerras static inline int simple_feature_tweak(struct device_node *node, int type,
152f6d57916SPaul Mackerras 				       int reg, u32 mask, int value)
153f6d57916SPaul Mackerras {
154f6d57916SPaul Mackerras 	struct macio_chip*	macio;
155f6d57916SPaul Mackerras 	unsigned long		flags;
156f6d57916SPaul Mackerras 
157f6d57916SPaul Mackerras 	macio = macio_find(node, type);
158f6d57916SPaul Mackerras 	if (!macio)
159f6d57916SPaul Mackerras 		return -ENODEV;
160f6d57916SPaul Mackerras 	LOCK(flags);
161f6d57916SPaul Mackerras 	if (value)
162f6d57916SPaul Mackerras 		MACIO_BIS(reg, mask);
163f6d57916SPaul Mackerras 	else
164f6d57916SPaul Mackerras 		MACIO_BIC(reg, mask);
165f6d57916SPaul Mackerras 	(void)MACIO_IN32(reg);
166f6d57916SPaul Mackerras 	UNLOCK(flags);
167f6d57916SPaul Mackerras 
168f6d57916SPaul Mackerras 	return 0;
169f6d57916SPaul Mackerras }
170f6d57916SPaul Mackerras 
171f6d57916SPaul Mackerras #ifndef CONFIG_POWER4
172f6d57916SPaul Mackerras 
173f6d57916SPaul Mackerras static long ohare_htw_scc_enable(struct device_node *node, long param,
174f6d57916SPaul Mackerras 				 long value)
175f6d57916SPaul Mackerras {
176f6d57916SPaul Mackerras 	struct macio_chip*	macio;
177f6d57916SPaul Mackerras 	unsigned long		chan_mask;
178f6d57916SPaul Mackerras 	unsigned long		fcr;
179f6d57916SPaul Mackerras 	unsigned long		flags;
180f6d57916SPaul Mackerras 	int			htw, trans;
181f6d57916SPaul Mackerras 	unsigned long		rmask;
182f6d57916SPaul Mackerras 
183f6d57916SPaul Mackerras 	macio = macio_find(node, 0);
184f6d57916SPaul Mackerras 	if (!macio)
185f6d57916SPaul Mackerras 		return -ENODEV;
186f6d57916SPaul Mackerras 	if (!strcmp(node->name, "ch-a"))
187f6d57916SPaul Mackerras 		chan_mask = MACIO_FLAG_SCCA_ON;
188f6d57916SPaul Mackerras 	else if (!strcmp(node->name, "ch-b"))
189f6d57916SPaul Mackerras 		chan_mask = MACIO_FLAG_SCCB_ON;
190f6d57916SPaul Mackerras 	else
191f6d57916SPaul Mackerras 		return -ENODEV;
192f6d57916SPaul Mackerras 
193f6d57916SPaul Mackerras 	htw = (macio->type == macio_heathrow || macio->type == macio_paddington
194f6d57916SPaul Mackerras 		|| macio->type == macio_gatwick);
195f6d57916SPaul Mackerras 	/* On these machines, the HRW_SCC_TRANS_EN_N bit mustn't be touched */
196f6d57916SPaul Mackerras 	trans = (pmac_mb.model_id != PMAC_TYPE_YOSEMITE &&
197f6d57916SPaul Mackerras 		 pmac_mb.model_id != PMAC_TYPE_YIKES);
198f6d57916SPaul Mackerras 	if (value) {
199f6d57916SPaul Mackerras #ifdef CONFIG_ADB_PMU
200f6d57916SPaul Mackerras 		if ((param & 0xfff) == PMAC_SCC_IRDA)
201f6d57916SPaul Mackerras 			pmu_enable_irled(1);
202f6d57916SPaul Mackerras #endif /* CONFIG_ADB_PMU */
203f6d57916SPaul Mackerras 		LOCK(flags);
204f6d57916SPaul Mackerras 		fcr = MACIO_IN32(OHARE_FCR);
205f6d57916SPaul Mackerras 		/* Check if scc cell need enabling */
206f6d57916SPaul Mackerras 		if (!(fcr & OH_SCC_ENABLE)) {
207f6d57916SPaul Mackerras 			fcr |= OH_SCC_ENABLE;
208f6d57916SPaul Mackerras 			if (htw) {
209f6d57916SPaul Mackerras 				/* Side effect: this will also power up the
210f6d57916SPaul Mackerras 				 * modem, but it's too messy to figure out on which
211f6d57916SPaul Mackerras 				 * ports this controls the tranceiver and on which
212f6d57916SPaul Mackerras 				 * it controls the modem
213f6d57916SPaul Mackerras 				 */
214f6d57916SPaul Mackerras 				if (trans)
215f6d57916SPaul Mackerras 					fcr &= ~HRW_SCC_TRANS_EN_N;
216f6d57916SPaul Mackerras 				MACIO_OUT32(OHARE_FCR, fcr);
217f6d57916SPaul Mackerras 				fcr |= (rmask = HRW_RESET_SCC);
218f6d57916SPaul Mackerras 				MACIO_OUT32(OHARE_FCR, fcr);
219f6d57916SPaul Mackerras 			} else {
220f6d57916SPaul Mackerras 				fcr |= (rmask = OH_SCC_RESET);
221f6d57916SPaul Mackerras 				MACIO_OUT32(OHARE_FCR, fcr);
222f6d57916SPaul Mackerras 			}
223f6d57916SPaul Mackerras 			UNLOCK(flags);
224f6d57916SPaul Mackerras 			(void)MACIO_IN32(OHARE_FCR);
225f6d57916SPaul Mackerras 			mdelay(15);
226f6d57916SPaul Mackerras 			LOCK(flags);
227f6d57916SPaul Mackerras 			fcr &= ~rmask;
228f6d57916SPaul Mackerras 			MACIO_OUT32(OHARE_FCR, fcr);
229f6d57916SPaul Mackerras 		}
230f6d57916SPaul Mackerras 		if (chan_mask & MACIO_FLAG_SCCA_ON)
231f6d57916SPaul Mackerras 			fcr |= OH_SCCA_IO;
232f6d57916SPaul Mackerras 		if (chan_mask & MACIO_FLAG_SCCB_ON)
233f6d57916SPaul Mackerras 			fcr |= OH_SCCB_IO;
234f6d57916SPaul Mackerras 		MACIO_OUT32(OHARE_FCR, fcr);
235f6d57916SPaul Mackerras 		macio->flags |= chan_mask;
236f6d57916SPaul Mackerras 		UNLOCK(flags);
237f6d57916SPaul Mackerras 		if (param & PMAC_SCC_FLAG_XMON)
238f6d57916SPaul Mackerras 			macio->flags |= MACIO_FLAG_SCC_LOCKED;
239f6d57916SPaul Mackerras 	} else {
240f6d57916SPaul Mackerras 		if (macio->flags & MACIO_FLAG_SCC_LOCKED)
241f6d57916SPaul Mackerras 			return -EPERM;
242f6d57916SPaul Mackerras 		LOCK(flags);
243f6d57916SPaul Mackerras 		fcr = MACIO_IN32(OHARE_FCR);
244f6d57916SPaul Mackerras 		if (chan_mask & MACIO_FLAG_SCCA_ON)
245f6d57916SPaul Mackerras 			fcr &= ~OH_SCCA_IO;
246f6d57916SPaul Mackerras 		if (chan_mask & MACIO_FLAG_SCCB_ON)
247f6d57916SPaul Mackerras 			fcr &= ~OH_SCCB_IO;
248f6d57916SPaul Mackerras 		MACIO_OUT32(OHARE_FCR, fcr);
249f6d57916SPaul Mackerras 		if ((fcr & (OH_SCCA_IO | OH_SCCB_IO)) == 0) {
250f6d57916SPaul Mackerras 			fcr &= ~OH_SCC_ENABLE;
251f6d57916SPaul Mackerras 			if (htw && trans)
252f6d57916SPaul Mackerras 				fcr |= HRW_SCC_TRANS_EN_N;
253f6d57916SPaul Mackerras 			MACIO_OUT32(OHARE_FCR, fcr);
254f6d57916SPaul Mackerras 		}
255f6d57916SPaul Mackerras 		macio->flags &= ~(chan_mask);
256f6d57916SPaul Mackerras 		UNLOCK(flags);
257f6d57916SPaul Mackerras 		mdelay(10);
258f6d57916SPaul Mackerras #ifdef CONFIG_ADB_PMU
259f6d57916SPaul Mackerras 		if ((param & 0xfff) == PMAC_SCC_IRDA)
260f6d57916SPaul Mackerras 			pmu_enable_irled(0);
261f6d57916SPaul Mackerras #endif /* CONFIG_ADB_PMU */
262f6d57916SPaul Mackerras 	}
263f6d57916SPaul Mackerras 	return 0;
264f6d57916SPaul Mackerras }
265f6d57916SPaul Mackerras 
266f6d57916SPaul Mackerras static long ohare_floppy_enable(struct device_node *node, long param,
267f6d57916SPaul Mackerras 				long value)
268f6d57916SPaul Mackerras {
269f6d57916SPaul Mackerras 	return simple_feature_tweak(node, macio_ohare,
270f6d57916SPaul Mackerras 		OHARE_FCR, OH_FLOPPY_ENABLE, value);
271f6d57916SPaul Mackerras }
272f6d57916SPaul Mackerras 
273f6d57916SPaul Mackerras static long ohare_mesh_enable(struct device_node *node, long param, long value)
274f6d57916SPaul Mackerras {
275f6d57916SPaul Mackerras 	return simple_feature_tweak(node, macio_ohare,
276f6d57916SPaul Mackerras 		OHARE_FCR, OH_MESH_ENABLE, value);
277f6d57916SPaul Mackerras }
278f6d57916SPaul Mackerras 
279f6d57916SPaul Mackerras static long ohare_ide_enable(struct device_node *node, long param, long value)
280f6d57916SPaul Mackerras {
281f6d57916SPaul Mackerras 	switch(param) {
282f6d57916SPaul Mackerras 	case 0:
283f6d57916SPaul Mackerras 		/* For some reason, setting the bit in set_initial_features()
284f6d57916SPaul Mackerras 		 * doesn't stick. I'm still investigating... --BenH.
285f6d57916SPaul Mackerras 		 */
286f6d57916SPaul Mackerras 		if (value)
287f6d57916SPaul Mackerras 			simple_feature_tweak(node, macio_ohare,
288f6d57916SPaul Mackerras 				OHARE_FCR, OH_IOBUS_ENABLE, 1);
289f6d57916SPaul Mackerras 		return simple_feature_tweak(node, macio_ohare,
290f6d57916SPaul Mackerras 			OHARE_FCR, OH_IDE0_ENABLE, value);
291f6d57916SPaul Mackerras 	case 1:
292f6d57916SPaul Mackerras 		return simple_feature_tweak(node, macio_ohare,
293f6d57916SPaul Mackerras 			OHARE_FCR, OH_BAY_IDE_ENABLE, value);
294f6d57916SPaul Mackerras 	default:
295f6d57916SPaul Mackerras 		return -ENODEV;
296f6d57916SPaul Mackerras 	}
297f6d57916SPaul Mackerras }
298f6d57916SPaul Mackerras 
299f6d57916SPaul Mackerras static long ohare_ide_reset(struct device_node *node, long param, long value)
300f6d57916SPaul Mackerras {
301f6d57916SPaul Mackerras 	switch(param) {
302f6d57916SPaul Mackerras 	case 0:
303f6d57916SPaul Mackerras 		return simple_feature_tweak(node, macio_ohare,
304f6d57916SPaul Mackerras 			OHARE_FCR, OH_IDE0_RESET_N, !value);
305f6d57916SPaul Mackerras 	case 1:
306f6d57916SPaul Mackerras 		return simple_feature_tweak(node, macio_ohare,
307f6d57916SPaul Mackerras 			OHARE_FCR, OH_IDE1_RESET_N, !value);
308f6d57916SPaul Mackerras 	default:
309f6d57916SPaul Mackerras 		return -ENODEV;
310f6d57916SPaul Mackerras 	}
311f6d57916SPaul Mackerras }
312f6d57916SPaul Mackerras 
313f6d57916SPaul Mackerras static long ohare_sleep_state(struct device_node *node, long param, long value)
314f6d57916SPaul Mackerras {
315f6d57916SPaul Mackerras 	struct macio_chip*	macio = &macio_chips[0];
316f6d57916SPaul Mackerras 
317f6d57916SPaul Mackerras 	if ((pmac_mb.board_flags & PMAC_MB_CAN_SLEEP) == 0)
318f6d57916SPaul Mackerras 		return -EPERM;
319f6d57916SPaul Mackerras 	if (value == 1) {
320f6d57916SPaul Mackerras 		MACIO_BIC(OHARE_FCR, OH_IOBUS_ENABLE);
321f6d57916SPaul Mackerras 	} else if (value == 0) {
322f6d57916SPaul Mackerras 		MACIO_BIS(OHARE_FCR, OH_IOBUS_ENABLE);
323f6d57916SPaul Mackerras 	}
324f6d57916SPaul Mackerras 
325f6d57916SPaul Mackerras 	return 0;
326f6d57916SPaul Mackerras }
327f6d57916SPaul Mackerras 
328f6d57916SPaul Mackerras static long heathrow_modem_enable(struct device_node *node, long param,
329f6d57916SPaul Mackerras 				  long value)
330f6d57916SPaul Mackerras {
331f6d57916SPaul Mackerras 	struct macio_chip*	macio;
332f6d57916SPaul Mackerras 	u8			gpio;
333f6d57916SPaul Mackerras 	unsigned long		flags;
334f6d57916SPaul Mackerras 
335f6d57916SPaul Mackerras 	macio = macio_find(node, macio_unknown);
336f6d57916SPaul Mackerras 	if (!macio)
337f6d57916SPaul Mackerras 		return -ENODEV;
338f6d57916SPaul Mackerras 	gpio = MACIO_IN8(HRW_GPIO_MODEM_RESET) & ~1;
339f6d57916SPaul Mackerras 	if (!value) {
340f6d57916SPaul Mackerras 		LOCK(flags);
341f6d57916SPaul Mackerras 		MACIO_OUT8(HRW_GPIO_MODEM_RESET, gpio);
342f6d57916SPaul Mackerras 		UNLOCK(flags);
343f6d57916SPaul Mackerras 		(void)MACIO_IN8(HRW_GPIO_MODEM_RESET);
344f6d57916SPaul Mackerras 		mdelay(250);
345f6d57916SPaul Mackerras 	}
346f6d57916SPaul Mackerras 	if (pmac_mb.model_id != PMAC_TYPE_YOSEMITE &&
347f6d57916SPaul Mackerras 	    pmac_mb.model_id != PMAC_TYPE_YIKES) {
348f6d57916SPaul Mackerras 		LOCK(flags);
349f6d57916SPaul Mackerras 		if (value)
350f6d57916SPaul Mackerras 			MACIO_BIC(HEATHROW_FCR, HRW_SCC_TRANS_EN_N);
351f6d57916SPaul Mackerras 		else
352f6d57916SPaul Mackerras 			MACIO_BIS(HEATHROW_FCR, HRW_SCC_TRANS_EN_N);
353f6d57916SPaul Mackerras 		UNLOCK(flags);
354f6d57916SPaul Mackerras 		(void)MACIO_IN32(HEATHROW_FCR);
355f6d57916SPaul Mackerras 		mdelay(250);
356f6d57916SPaul Mackerras 	}
357f6d57916SPaul Mackerras 	if (value) {
358f6d57916SPaul Mackerras 		LOCK(flags);
359f6d57916SPaul Mackerras 		MACIO_OUT8(HRW_GPIO_MODEM_RESET, gpio | 1);
360f6d57916SPaul Mackerras 		(void)MACIO_IN8(HRW_GPIO_MODEM_RESET);
361f6d57916SPaul Mackerras 		UNLOCK(flags); mdelay(250); LOCK(flags);
362f6d57916SPaul Mackerras 		MACIO_OUT8(HRW_GPIO_MODEM_RESET, gpio);
363f6d57916SPaul Mackerras 		(void)MACIO_IN8(HRW_GPIO_MODEM_RESET);
364f6d57916SPaul Mackerras 		UNLOCK(flags); mdelay(250); LOCK(flags);
365f6d57916SPaul Mackerras 		MACIO_OUT8(HRW_GPIO_MODEM_RESET, gpio | 1);
366f6d57916SPaul Mackerras 		(void)MACIO_IN8(HRW_GPIO_MODEM_RESET);
367f6d57916SPaul Mackerras 		UNLOCK(flags); mdelay(250);
368f6d57916SPaul Mackerras 	}
369f6d57916SPaul Mackerras 	return 0;
370f6d57916SPaul Mackerras }
371f6d57916SPaul Mackerras 
372f6d57916SPaul Mackerras static long heathrow_floppy_enable(struct device_node *node, long param,
373f6d57916SPaul Mackerras 				   long value)
374f6d57916SPaul Mackerras {
375f6d57916SPaul Mackerras 	return simple_feature_tweak(node, macio_unknown,
376f6d57916SPaul Mackerras 		HEATHROW_FCR,
377f6d57916SPaul Mackerras 		HRW_SWIM_ENABLE|HRW_BAY_FLOPPY_ENABLE,
378f6d57916SPaul Mackerras 		value);
379f6d57916SPaul Mackerras }
380f6d57916SPaul Mackerras 
381f6d57916SPaul Mackerras static long heathrow_mesh_enable(struct device_node *node, long param,
382f6d57916SPaul Mackerras 				 long value)
383f6d57916SPaul Mackerras {
384f6d57916SPaul Mackerras 	struct macio_chip*	macio;
385f6d57916SPaul Mackerras 	unsigned long		flags;
386f6d57916SPaul Mackerras 
387f6d57916SPaul Mackerras 	macio = macio_find(node, macio_unknown);
388f6d57916SPaul Mackerras 	if (!macio)
389f6d57916SPaul Mackerras 		return -ENODEV;
390f6d57916SPaul Mackerras 	LOCK(flags);
391f6d57916SPaul Mackerras 	/* Set clear mesh cell enable */
392f6d57916SPaul Mackerras 	if (value)
393f6d57916SPaul Mackerras 		MACIO_BIS(HEATHROW_FCR, HRW_MESH_ENABLE);
394f6d57916SPaul Mackerras 	else
395f6d57916SPaul Mackerras 		MACIO_BIC(HEATHROW_FCR, HRW_MESH_ENABLE);
396f6d57916SPaul Mackerras 	(void)MACIO_IN32(HEATHROW_FCR);
397f6d57916SPaul Mackerras 	udelay(10);
398f6d57916SPaul Mackerras 	/* Set/Clear termination power */
399f6d57916SPaul Mackerras 	if (value)
400f6d57916SPaul Mackerras 		MACIO_BIC(HEATHROW_MBCR, 0x04000000);
401f6d57916SPaul Mackerras 	else
402f6d57916SPaul Mackerras 		MACIO_BIS(HEATHROW_MBCR, 0x04000000);
403f6d57916SPaul Mackerras 	(void)MACIO_IN32(HEATHROW_MBCR);
404f6d57916SPaul Mackerras 	udelay(10);
405f6d57916SPaul Mackerras 	UNLOCK(flags);
406f6d57916SPaul Mackerras 
407f6d57916SPaul Mackerras 	return 0;
408f6d57916SPaul Mackerras }
409f6d57916SPaul Mackerras 
410f6d57916SPaul Mackerras static long heathrow_ide_enable(struct device_node *node, long param,
411f6d57916SPaul Mackerras 				long value)
412f6d57916SPaul Mackerras {
413f6d57916SPaul Mackerras 	switch(param) {
414f6d57916SPaul Mackerras 	case 0:
415f6d57916SPaul Mackerras 		return simple_feature_tweak(node, macio_unknown,
416f6d57916SPaul Mackerras 			HEATHROW_FCR, HRW_IDE0_ENABLE, value);
417f6d57916SPaul Mackerras 	case 1:
418f6d57916SPaul Mackerras 		return simple_feature_tweak(node, macio_unknown,
419f6d57916SPaul Mackerras 			HEATHROW_FCR, HRW_BAY_IDE_ENABLE, value);
420f6d57916SPaul Mackerras 	default:
421f6d57916SPaul Mackerras 		return -ENODEV;
422f6d57916SPaul Mackerras 	}
423f6d57916SPaul Mackerras }
424f6d57916SPaul Mackerras 
425f6d57916SPaul Mackerras static long heathrow_ide_reset(struct device_node *node, long param,
426f6d57916SPaul Mackerras 			       long value)
427f6d57916SPaul Mackerras {
428f6d57916SPaul Mackerras 	switch(param) {
429f6d57916SPaul Mackerras 	case 0:
430f6d57916SPaul Mackerras 		return simple_feature_tweak(node, macio_unknown,
431f6d57916SPaul Mackerras 			HEATHROW_FCR, HRW_IDE0_RESET_N, !value);
432f6d57916SPaul Mackerras 	case 1:
433f6d57916SPaul Mackerras 		return simple_feature_tweak(node, macio_unknown,
434f6d57916SPaul Mackerras 			HEATHROW_FCR, HRW_IDE1_RESET_N, !value);
435f6d57916SPaul Mackerras 	default:
436f6d57916SPaul Mackerras 		return -ENODEV;
437f6d57916SPaul Mackerras 	}
438f6d57916SPaul Mackerras }
439f6d57916SPaul Mackerras 
440f6d57916SPaul Mackerras static long heathrow_bmac_enable(struct device_node *node, long param,
441f6d57916SPaul Mackerras 				 long value)
442f6d57916SPaul Mackerras {
443f6d57916SPaul Mackerras 	struct macio_chip*	macio;
444f6d57916SPaul Mackerras 	unsigned long		flags;
445f6d57916SPaul Mackerras 
446f6d57916SPaul Mackerras 	macio = macio_find(node, 0);
447f6d57916SPaul Mackerras 	if (!macio)
448f6d57916SPaul Mackerras 		return -ENODEV;
449f6d57916SPaul Mackerras 	if (value) {
450f6d57916SPaul Mackerras 		LOCK(flags);
451f6d57916SPaul Mackerras 		MACIO_BIS(HEATHROW_FCR, HRW_BMAC_IO_ENABLE);
452f6d57916SPaul Mackerras 		MACIO_BIS(HEATHROW_FCR, HRW_BMAC_RESET);
453f6d57916SPaul Mackerras 		UNLOCK(flags);
454f6d57916SPaul Mackerras 		(void)MACIO_IN32(HEATHROW_FCR);
455f6d57916SPaul Mackerras 		mdelay(10);
456f6d57916SPaul Mackerras 		LOCK(flags);
457f6d57916SPaul Mackerras 		MACIO_BIC(HEATHROW_FCR, HRW_BMAC_RESET);
458f6d57916SPaul Mackerras 		UNLOCK(flags);
459f6d57916SPaul Mackerras 		(void)MACIO_IN32(HEATHROW_FCR);
460f6d57916SPaul Mackerras 		mdelay(10);
461f6d57916SPaul Mackerras 	} else {
462f6d57916SPaul Mackerras 		LOCK(flags);
463f6d57916SPaul Mackerras 		MACIO_BIC(HEATHROW_FCR, HRW_BMAC_IO_ENABLE);
464f6d57916SPaul Mackerras 		UNLOCK(flags);
465f6d57916SPaul Mackerras 	}
466f6d57916SPaul Mackerras 	return 0;
467f6d57916SPaul Mackerras }
468f6d57916SPaul Mackerras 
469f6d57916SPaul Mackerras static long heathrow_sound_enable(struct device_node *node, long param,
470f6d57916SPaul Mackerras 				  long value)
471f6d57916SPaul Mackerras {
472f6d57916SPaul Mackerras 	struct macio_chip*	macio;
473f6d57916SPaul Mackerras 	unsigned long		flags;
474f6d57916SPaul Mackerras 
475f6d57916SPaul Mackerras 	/* B&W G3 and Yikes don't support that properly (the
476f6d57916SPaul Mackerras 	 * sound appear to never come back after beeing shut down).
477f6d57916SPaul Mackerras 	 */
478f6d57916SPaul Mackerras 	if (pmac_mb.model_id == PMAC_TYPE_YOSEMITE ||
479f6d57916SPaul Mackerras 	    pmac_mb.model_id == PMAC_TYPE_YIKES)
480f6d57916SPaul Mackerras 		return 0;
481f6d57916SPaul Mackerras 
482f6d57916SPaul Mackerras 	macio = macio_find(node, 0);
483f6d57916SPaul Mackerras 	if (!macio)
484f6d57916SPaul Mackerras 		return -ENODEV;
485f6d57916SPaul Mackerras 	if (value) {
486f6d57916SPaul Mackerras 		LOCK(flags);
487f6d57916SPaul Mackerras 		MACIO_BIS(HEATHROW_FCR, HRW_SOUND_CLK_ENABLE);
488f6d57916SPaul Mackerras 		MACIO_BIC(HEATHROW_FCR, HRW_SOUND_POWER_N);
489f6d57916SPaul Mackerras 		UNLOCK(flags);
490f6d57916SPaul Mackerras 		(void)MACIO_IN32(HEATHROW_FCR);
491f6d57916SPaul Mackerras 	} else {
492f6d57916SPaul Mackerras 		LOCK(flags);
493f6d57916SPaul Mackerras 		MACIO_BIS(HEATHROW_FCR, HRW_SOUND_POWER_N);
494f6d57916SPaul Mackerras 		MACIO_BIC(HEATHROW_FCR, HRW_SOUND_CLK_ENABLE);
495f6d57916SPaul Mackerras 		UNLOCK(flags);
496f6d57916SPaul Mackerras 	}
497f6d57916SPaul Mackerras 	return 0;
498f6d57916SPaul Mackerras }
499f6d57916SPaul Mackerras 
500f6d57916SPaul Mackerras static u32 save_fcr[6];
501f6d57916SPaul Mackerras static u32 save_mbcr;
502f6d57916SPaul Mackerras static u32 save_gpio_levels[2];
503f6d57916SPaul Mackerras static u8 save_gpio_extint[KEYLARGO_GPIO_EXTINT_CNT];
504f6d57916SPaul Mackerras static u8 save_gpio_normal[KEYLARGO_GPIO_CNT];
505f6d57916SPaul Mackerras static u32 save_unin_clock_ctl;
506f6d57916SPaul Mackerras static struct dbdma_regs save_dbdma[13];
507f6d57916SPaul Mackerras static struct dbdma_regs save_alt_dbdma[13];
508f6d57916SPaul Mackerras 
509f6d57916SPaul Mackerras static void dbdma_save(struct macio_chip *macio, struct dbdma_regs *save)
510f6d57916SPaul Mackerras {
511f6d57916SPaul Mackerras 	int i;
512f6d57916SPaul Mackerras 
513f6d57916SPaul Mackerras 	/* Save state & config of DBDMA channels */
514f6d57916SPaul Mackerras 	for (i = 0; i < 13; i++) {
515f6d57916SPaul Mackerras 		volatile struct dbdma_regs __iomem * chan = (void __iomem *)
516f6d57916SPaul Mackerras 			(macio->base + ((0x8000+i*0x100)>>2));
517f6d57916SPaul Mackerras 		save[i].cmdptr_hi = in_le32(&chan->cmdptr_hi);
518f6d57916SPaul Mackerras 		save[i].cmdptr = in_le32(&chan->cmdptr);
519f6d57916SPaul Mackerras 		save[i].intr_sel = in_le32(&chan->intr_sel);
520f6d57916SPaul Mackerras 		save[i].br_sel = in_le32(&chan->br_sel);
521f6d57916SPaul Mackerras 		save[i].wait_sel = in_le32(&chan->wait_sel);
522f6d57916SPaul Mackerras 	}
523f6d57916SPaul Mackerras }
524f6d57916SPaul Mackerras 
525f6d57916SPaul Mackerras static void dbdma_restore(struct macio_chip *macio, struct dbdma_regs *save)
526f6d57916SPaul Mackerras {
527f6d57916SPaul Mackerras 	int i;
528f6d57916SPaul Mackerras 
529f6d57916SPaul Mackerras 	/* Save state & config of DBDMA channels */
530f6d57916SPaul Mackerras 	for (i = 0; i < 13; i++) {
531f6d57916SPaul Mackerras 		volatile struct dbdma_regs __iomem * chan = (void __iomem *)
532f6d57916SPaul Mackerras 			(macio->base + ((0x8000+i*0x100)>>2));
533f6d57916SPaul Mackerras 		out_le32(&chan->control, (ACTIVE|DEAD|WAKE|FLUSH|PAUSE|RUN)<<16);
534f6d57916SPaul Mackerras 		while (in_le32(&chan->status) & ACTIVE)
535f6d57916SPaul Mackerras 			mb();
536f6d57916SPaul Mackerras 		out_le32(&chan->cmdptr_hi, save[i].cmdptr_hi);
537f6d57916SPaul Mackerras 		out_le32(&chan->cmdptr, save[i].cmdptr);
538f6d57916SPaul Mackerras 		out_le32(&chan->intr_sel, save[i].intr_sel);
539f6d57916SPaul Mackerras 		out_le32(&chan->br_sel, save[i].br_sel);
540f6d57916SPaul Mackerras 		out_le32(&chan->wait_sel, save[i].wait_sel);
541f6d57916SPaul Mackerras 	}
542f6d57916SPaul Mackerras }
543f6d57916SPaul Mackerras 
544f6d57916SPaul Mackerras static void heathrow_sleep(struct macio_chip *macio, int secondary)
545f6d57916SPaul Mackerras {
546f6d57916SPaul Mackerras 	if (secondary) {
547f6d57916SPaul Mackerras 		dbdma_save(macio, save_alt_dbdma);
548f6d57916SPaul Mackerras 		save_fcr[2] = MACIO_IN32(0x38);
549f6d57916SPaul Mackerras 		save_fcr[3] = MACIO_IN32(0x3c);
550f6d57916SPaul Mackerras 	} else {
551f6d57916SPaul Mackerras 		dbdma_save(macio, save_dbdma);
552f6d57916SPaul Mackerras 		save_fcr[0] = MACIO_IN32(0x38);
553f6d57916SPaul Mackerras 		save_fcr[1] = MACIO_IN32(0x3c);
554f6d57916SPaul Mackerras 		save_mbcr = MACIO_IN32(0x34);
555f6d57916SPaul Mackerras 		/* Make sure sound is shut down */
556f6d57916SPaul Mackerras 		MACIO_BIS(HEATHROW_FCR, HRW_SOUND_POWER_N);
557f6d57916SPaul Mackerras 		MACIO_BIC(HEATHROW_FCR, HRW_SOUND_CLK_ENABLE);
558f6d57916SPaul Mackerras 		/* This seems to be necessary as well or the fan
559f6d57916SPaul Mackerras 		 * keeps coming up and battery drains fast */
560f6d57916SPaul Mackerras 		MACIO_BIC(HEATHROW_FCR, HRW_IOBUS_ENABLE);
561f6d57916SPaul Mackerras 		MACIO_BIC(HEATHROW_FCR, HRW_IDE0_RESET_N);
562f6d57916SPaul Mackerras 		/* Make sure eth is down even if module or sleep
563f6d57916SPaul Mackerras 		 * won't work properly */
564f6d57916SPaul Mackerras 		MACIO_BIC(HEATHROW_FCR, HRW_BMAC_IO_ENABLE | HRW_BMAC_RESET);
565f6d57916SPaul Mackerras 	}
566f6d57916SPaul Mackerras 	/* Make sure modem is shut down */
567f6d57916SPaul Mackerras 	MACIO_OUT8(HRW_GPIO_MODEM_RESET,
568f6d57916SPaul Mackerras 		MACIO_IN8(HRW_GPIO_MODEM_RESET) & ~1);
569f6d57916SPaul Mackerras 	MACIO_BIS(HEATHROW_FCR, HRW_SCC_TRANS_EN_N);
570f6d57916SPaul Mackerras 	MACIO_BIC(HEATHROW_FCR, OH_SCCA_IO|OH_SCCB_IO|HRW_SCC_ENABLE);
571f6d57916SPaul Mackerras 
572f6d57916SPaul Mackerras 	/* Let things settle */
573f6d57916SPaul Mackerras 	(void)MACIO_IN32(HEATHROW_FCR);
574f6d57916SPaul Mackerras }
575f6d57916SPaul Mackerras 
576f6d57916SPaul Mackerras static void heathrow_wakeup(struct macio_chip *macio, int secondary)
577f6d57916SPaul Mackerras {
578f6d57916SPaul Mackerras 	if (secondary) {
579f6d57916SPaul Mackerras 		MACIO_OUT32(0x38, save_fcr[2]);
580f6d57916SPaul Mackerras 		(void)MACIO_IN32(0x38);
581f6d57916SPaul Mackerras 		mdelay(1);
582f6d57916SPaul Mackerras 		MACIO_OUT32(0x3c, save_fcr[3]);
583f6d57916SPaul Mackerras 		(void)MACIO_IN32(0x38);
584f6d57916SPaul Mackerras 		mdelay(10);
585f6d57916SPaul Mackerras 		dbdma_restore(macio, save_alt_dbdma);
586f6d57916SPaul Mackerras 	} else {
587f6d57916SPaul Mackerras 		MACIO_OUT32(0x38, save_fcr[0] | HRW_IOBUS_ENABLE);
588f6d57916SPaul Mackerras 		(void)MACIO_IN32(0x38);
589f6d57916SPaul Mackerras 		mdelay(1);
590f6d57916SPaul Mackerras 		MACIO_OUT32(0x3c, save_fcr[1]);
591f6d57916SPaul Mackerras 		(void)MACIO_IN32(0x38);
592f6d57916SPaul Mackerras 		mdelay(1);
593f6d57916SPaul Mackerras 		MACIO_OUT32(0x34, save_mbcr);
594f6d57916SPaul Mackerras 		(void)MACIO_IN32(0x38);
595f6d57916SPaul Mackerras 		mdelay(10);
596f6d57916SPaul Mackerras 		dbdma_restore(macio, save_dbdma);
597f6d57916SPaul Mackerras 	}
598f6d57916SPaul Mackerras }
599f6d57916SPaul Mackerras 
600f6d57916SPaul Mackerras static long heathrow_sleep_state(struct device_node *node, long param,
601f6d57916SPaul Mackerras 				 long value)
602f6d57916SPaul Mackerras {
603f6d57916SPaul Mackerras 	if ((pmac_mb.board_flags & PMAC_MB_CAN_SLEEP) == 0)
604f6d57916SPaul Mackerras 		return -EPERM;
605f6d57916SPaul Mackerras 	if (value == 1) {
606f6d57916SPaul Mackerras 		if (macio_chips[1].type == macio_gatwick)
607f6d57916SPaul Mackerras 			heathrow_sleep(&macio_chips[0], 1);
608f6d57916SPaul Mackerras 		heathrow_sleep(&macio_chips[0], 0);
609f6d57916SPaul Mackerras 	} else if (value == 0) {
610f6d57916SPaul Mackerras 		heathrow_wakeup(&macio_chips[0], 0);
611f6d57916SPaul Mackerras 		if (macio_chips[1].type == macio_gatwick)
612f6d57916SPaul Mackerras 			heathrow_wakeup(&macio_chips[0], 1);
613f6d57916SPaul Mackerras 	}
614f6d57916SPaul Mackerras 	return 0;
615f6d57916SPaul Mackerras }
616f6d57916SPaul Mackerras 
617f6d57916SPaul Mackerras static long core99_scc_enable(struct device_node *node, long param, long value)
618f6d57916SPaul Mackerras {
619f6d57916SPaul Mackerras 	struct macio_chip*	macio;
620f6d57916SPaul Mackerras 	unsigned long		flags;
621f6d57916SPaul Mackerras 	unsigned long		chan_mask;
622f6d57916SPaul Mackerras 	u32			fcr;
623f6d57916SPaul Mackerras 
624f6d57916SPaul Mackerras 	macio = macio_find(node, 0);
625f6d57916SPaul Mackerras 	if (!macio)
626f6d57916SPaul Mackerras 		return -ENODEV;
627f6d57916SPaul Mackerras 	if (!strcmp(node->name, "ch-a"))
628f6d57916SPaul Mackerras 		chan_mask = MACIO_FLAG_SCCA_ON;
629f6d57916SPaul Mackerras 	else if (!strcmp(node->name, "ch-b"))
630f6d57916SPaul Mackerras 		chan_mask = MACIO_FLAG_SCCB_ON;
631f6d57916SPaul Mackerras 	else
632f6d57916SPaul Mackerras 		return -ENODEV;
633f6d57916SPaul Mackerras 
634f6d57916SPaul Mackerras 	if (value) {
635f6d57916SPaul Mackerras 		int need_reset_scc = 0;
636f6d57916SPaul Mackerras 		int need_reset_irda = 0;
637f6d57916SPaul Mackerras 
638f6d57916SPaul Mackerras 		LOCK(flags);
639f6d57916SPaul Mackerras 		fcr = MACIO_IN32(KEYLARGO_FCR0);
640f6d57916SPaul Mackerras 		/* Check if scc cell need enabling */
641f6d57916SPaul Mackerras 		if (!(fcr & KL0_SCC_CELL_ENABLE)) {
642f6d57916SPaul Mackerras 			fcr |= KL0_SCC_CELL_ENABLE;
643f6d57916SPaul Mackerras 			need_reset_scc = 1;
644f6d57916SPaul Mackerras 		}
645f6d57916SPaul Mackerras 		if (chan_mask & MACIO_FLAG_SCCA_ON) {
646f6d57916SPaul Mackerras 			fcr |= KL0_SCCA_ENABLE;
647f6d57916SPaul Mackerras 			/* Don't enable line drivers for I2S modem */
648f6d57916SPaul Mackerras 			if ((param & 0xfff) == PMAC_SCC_I2S1)
649f6d57916SPaul Mackerras 				fcr &= ~KL0_SCC_A_INTF_ENABLE;
650f6d57916SPaul Mackerras 			else
651f6d57916SPaul Mackerras 				fcr |= KL0_SCC_A_INTF_ENABLE;
652f6d57916SPaul Mackerras 		}
653f6d57916SPaul Mackerras 		if (chan_mask & MACIO_FLAG_SCCB_ON) {
654f6d57916SPaul Mackerras 			fcr |= KL0_SCCB_ENABLE;
655f6d57916SPaul Mackerras 			/* Perform irda specific inits */
656f6d57916SPaul Mackerras 			if ((param & 0xfff) == PMAC_SCC_IRDA) {
657f6d57916SPaul Mackerras 				fcr &= ~KL0_SCC_B_INTF_ENABLE;
658f6d57916SPaul Mackerras 				fcr |= KL0_IRDA_ENABLE;
659f6d57916SPaul Mackerras 				fcr |= KL0_IRDA_CLK32_ENABLE | KL0_IRDA_CLK19_ENABLE;
660f6d57916SPaul Mackerras 				fcr |= KL0_IRDA_SOURCE1_SEL;
661f6d57916SPaul Mackerras 				fcr &= ~(KL0_IRDA_FAST_CONNECT|KL0_IRDA_DEFAULT1|KL0_IRDA_DEFAULT0);
662f6d57916SPaul Mackerras 				fcr &= ~(KL0_IRDA_SOURCE2_SEL|KL0_IRDA_HIGH_BAND);
663f6d57916SPaul Mackerras 				need_reset_irda = 1;
664f6d57916SPaul Mackerras 			} else
665f6d57916SPaul Mackerras 				fcr |= KL0_SCC_B_INTF_ENABLE;
666f6d57916SPaul Mackerras 		}
667f6d57916SPaul Mackerras 		MACIO_OUT32(KEYLARGO_FCR0, fcr);
668f6d57916SPaul Mackerras 		macio->flags |= chan_mask;
669f6d57916SPaul Mackerras 		if (need_reset_scc)  {
670f6d57916SPaul Mackerras 			MACIO_BIS(KEYLARGO_FCR0, KL0_SCC_RESET);
671f6d57916SPaul Mackerras 			(void)MACIO_IN32(KEYLARGO_FCR0);
672f6d57916SPaul Mackerras 			UNLOCK(flags);
673f6d57916SPaul Mackerras 			mdelay(15);
674f6d57916SPaul Mackerras 			LOCK(flags);
675f6d57916SPaul Mackerras 			MACIO_BIC(KEYLARGO_FCR0, KL0_SCC_RESET);
676f6d57916SPaul Mackerras 		}
677f6d57916SPaul Mackerras 		if (need_reset_irda)  {
678f6d57916SPaul Mackerras 			MACIO_BIS(KEYLARGO_FCR0, KL0_IRDA_RESET);
679f6d57916SPaul Mackerras 			(void)MACIO_IN32(KEYLARGO_FCR0);
680f6d57916SPaul Mackerras 			UNLOCK(flags);
681f6d57916SPaul Mackerras 			mdelay(15);
682f6d57916SPaul Mackerras 			LOCK(flags);
683f6d57916SPaul Mackerras 			MACIO_BIC(KEYLARGO_FCR0, KL0_IRDA_RESET);
684f6d57916SPaul Mackerras 		}
685f6d57916SPaul Mackerras 		UNLOCK(flags);
686f6d57916SPaul Mackerras 		if (param & PMAC_SCC_FLAG_XMON)
687f6d57916SPaul Mackerras 			macio->flags |= MACIO_FLAG_SCC_LOCKED;
688f6d57916SPaul Mackerras 	} else {
689f6d57916SPaul Mackerras 		if (macio->flags & MACIO_FLAG_SCC_LOCKED)
690f6d57916SPaul Mackerras 			return -EPERM;
691f6d57916SPaul Mackerras 		LOCK(flags);
692f6d57916SPaul Mackerras 		fcr = MACIO_IN32(KEYLARGO_FCR0);
693f6d57916SPaul Mackerras 		if (chan_mask & MACIO_FLAG_SCCA_ON)
694f6d57916SPaul Mackerras 			fcr &= ~KL0_SCCA_ENABLE;
695f6d57916SPaul Mackerras 		if (chan_mask & MACIO_FLAG_SCCB_ON) {
696f6d57916SPaul Mackerras 			fcr &= ~KL0_SCCB_ENABLE;
697f6d57916SPaul Mackerras 			/* Perform irda specific clears */
698f6d57916SPaul Mackerras 			if ((param & 0xfff) == PMAC_SCC_IRDA) {
699f6d57916SPaul Mackerras 				fcr &= ~KL0_IRDA_ENABLE;
700f6d57916SPaul Mackerras 				fcr &= ~(KL0_IRDA_CLK32_ENABLE | KL0_IRDA_CLK19_ENABLE);
701f6d57916SPaul Mackerras 				fcr &= ~(KL0_IRDA_FAST_CONNECT|KL0_IRDA_DEFAULT1|KL0_IRDA_DEFAULT0);
702f6d57916SPaul Mackerras 				fcr &= ~(KL0_IRDA_SOURCE1_SEL|KL0_IRDA_SOURCE2_SEL|KL0_IRDA_HIGH_BAND);
703f6d57916SPaul Mackerras 			}
704f6d57916SPaul Mackerras 		}
705f6d57916SPaul Mackerras 		MACIO_OUT32(KEYLARGO_FCR0, fcr);
706f6d57916SPaul Mackerras 		if ((fcr & (KL0_SCCA_ENABLE | KL0_SCCB_ENABLE)) == 0) {
707f6d57916SPaul Mackerras 			fcr &= ~KL0_SCC_CELL_ENABLE;
708f6d57916SPaul Mackerras 			MACIO_OUT32(KEYLARGO_FCR0, fcr);
709f6d57916SPaul Mackerras 		}
710f6d57916SPaul Mackerras 		macio->flags &= ~(chan_mask);
711f6d57916SPaul Mackerras 		UNLOCK(flags);
712f6d57916SPaul Mackerras 		mdelay(10);
713f6d57916SPaul Mackerras 	}
714f6d57916SPaul Mackerras 	return 0;
715f6d57916SPaul Mackerras }
716f6d57916SPaul Mackerras 
717f6d57916SPaul Mackerras static long
718f6d57916SPaul Mackerras core99_modem_enable(struct device_node *node, long param, long value)
719f6d57916SPaul Mackerras {
720f6d57916SPaul Mackerras 	struct macio_chip*	macio;
721f6d57916SPaul Mackerras 	u8			gpio;
722f6d57916SPaul Mackerras 	unsigned long		flags;
723f6d57916SPaul Mackerras 
724f6d57916SPaul Mackerras 	/* Hack for internal USB modem */
725f6d57916SPaul Mackerras 	if (node == NULL) {
726f6d57916SPaul Mackerras 		if (macio_chips[0].type != macio_keylargo)
727f6d57916SPaul Mackerras 			return -ENODEV;
728f6d57916SPaul Mackerras 		node = macio_chips[0].of_node;
729f6d57916SPaul Mackerras 	}
730f6d57916SPaul Mackerras 	macio = macio_find(node, 0);
731f6d57916SPaul Mackerras 	if (!macio)
732f6d57916SPaul Mackerras 		return -ENODEV;
733f6d57916SPaul Mackerras 	gpio = MACIO_IN8(KL_GPIO_MODEM_RESET);
734f6d57916SPaul Mackerras 	gpio |= KEYLARGO_GPIO_OUTPUT_ENABLE;
735f6d57916SPaul Mackerras 	gpio &= ~KEYLARGO_GPIO_OUTOUT_DATA;
736f6d57916SPaul Mackerras 
737f6d57916SPaul Mackerras 	if (!value) {
738f6d57916SPaul Mackerras 		LOCK(flags);
739f6d57916SPaul Mackerras 		MACIO_OUT8(KL_GPIO_MODEM_RESET, gpio);
740f6d57916SPaul Mackerras 		UNLOCK(flags);
741f6d57916SPaul Mackerras 		(void)MACIO_IN8(KL_GPIO_MODEM_RESET);
742f6d57916SPaul Mackerras 		mdelay(250);
743f6d57916SPaul Mackerras 	}
744f6d57916SPaul Mackerras 	LOCK(flags);
745f6d57916SPaul Mackerras 	if (value) {
746f6d57916SPaul Mackerras 		MACIO_BIC(KEYLARGO_FCR2, KL2_ALT_DATA_OUT);
747f6d57916SPaul Mackerras 		UNLOCK(flags);
748f6d57916SPaul Mackerras 		(void)MACIO_IN32(KEYLARGO_FCR2);
749f6d57916SPaul Mackerras 		mdelay(250);
750f6d57916SPaul Mackerras 	} else {
751f6d57916SPaul Mackerras 		MACIO_BIS(KEYLARGO_FCR2, KL2_ALT_DATA_OUT);
752f6d57916SPaul Mackerras 		UNLOCK(flags);
753f6d57916SPaul Mackerras 	}
754f6d57916SPaul Mackerras 	if (value) {
755f6d57916SPaul Mackerras 		LOCK(flags);
756f6d57916SPaul Mackerras 		MACIO_OUT8(KL_GPIO_MODEM_RESET, gpio | KEYLARGO_GPIO_OUTOUT_DATA);
757f6d57916SPaul Mackerras 		(void)MACIO_IN8(KL_GPIO_MODEM_RESET);
758f6d57916SPaul Mackerras 		UNLOCK(flags); mdelay(250); LOCK(flags);
759f6d57916SPaul Mackerras 		MACIO_OUT8(KL_GPIO_MODEM_RESET, gpio);
760f6d57916SPaul Mackerras 		(void)MACIO_IN8(KL_GPIO_MODEM_RESET);
761f6d57916SPaul Mackerras 		UNLOCK(flags); mdelay(250); LOCK(flags);
762f6d57916SPaul Mackerras 		MACIO_OUT8(KL_GPIO_MODEM_RESET, gpio | KEYLARGO_GPIO_OUTOUT_DATA);
763f6d57916SPaul Mackerras 		(void)MACIO_IN8(KL_GPIO_MODEM_RESET);
764f6d57916SPaul Mackerras 		UNLOCK(flags); mdelay(250);
765f6d57916SPaul Mackerras 	}
766f6d57916SPaul Mackerras 	return 0;
767f6d57916SPaul Mackerras }
768f6d57916SPaul Mackerras 
769f6d57916SPaul Mackerras static long
770f6d57916SPaul Mackerras pangea_modem_enable(struct device_node *node, long param, long value)
771f6d57916SPaul Mackerras {
772f6d57916SPaul Mackerras 	struct macio_chip*	macio;
773f6d57916SPaul Mackerras 	u8			gpio;
774f6d57916SPaul Mackerras 	unsigned long		flags;
775f6d57916SPaul Mackerras 
776f6d57916SPaul Mackerras 	/* Hack for internal USB modem */
777f6d57916SPaul Mackerras 	if (node == NULL) {
778f6d57916SPaul Mackerras 		if (macio_chips[0].type != macio_pangea &&
779f6d57916SPaul Mackerras 		    macio_chips[0].type != macio_intrepid)
780f6d57916SPaul Mackerras 			return -ENODEV;
781f6d57916SPaul Mackerras 		node = macio_chips[0].of_node;
782f6d57916SPaul Mackerras 	}
783f6d57916SPaul Mackerras 	macio = macio_find(node, 0);
784f6d57916SPaul Mackerras 	if (!macio)
785f6d57916SPaul Mackerras 		return -ENODEV;
786f6d57916SPaul Mackerras 	gpio = MACIO_IN8(KL_GPIO_MODEM_RESET);
787f6d57916SPaul Mackerras 	gpio |= KEYLARGO_GPIO_OUTPUT_ENABLE;
788f6d57916SPaul Mackerras 	gpio &= ~KEYLARGO_GPIO_OUTOUT_DATA;
789f6d57916SPaul Mackerras 
790f6d57916SPaul Mackerras 	if (!value) {
791f6d57916SPaul Mackerras 		LOCK(flags);
792f6d57916SPaul Mackerras 		MACIO_OUT8(KL_GPIO_MODEM_RESET, gpio);
793f6d57916SPaul Mackerras 		UNLOCK(flags);
794f6d57916SPaul Mackerras 		(void)MACIO_IN8(KL_GPIO_MODEM_RESET);
795f6d57916SPaul Mackerras 		mdelay(250);
796f6d57916SPaul Mackerras 	}
797f6d57916SPaul Mackerras 	LOCK(flags);
798f6d57916SPaul Mackerras 	if (value) {
799f6d57916SPaul Mackerras 		MACIO_OUT8(KL_GPIO_MODEM_POWER,
800f6d57916SPaul Mackerras 			KEYLARGO_GPIO_OUTPUT_ENABLE);
801f6d57916SPaul Mackerras 		UNLOCK(flags);
802f6d57916SPaul Mackerras 		(void)MACIO_IN32(KEYLARGO_FCR2);
803f6d57916SPaul Mackerras 		mdelay(250);
804f6d57916SPaul Mackerras 	} else {
805f6d57916SPaul Mackerras 		MACIO_OUT8(KL_GPIO_MODEM_POWER,
806f6d57916SPaul Mackerras 			KEYLARGO_GPIO_OUTPUT_ENABLE | KEYLARGO_GPIO_OUTOUT_DATA);
807f6d57916SPaul Mackerras 		UNLOCK(flags);
808f6d57916SPaul Mackerras 	}
809f6d57916SPaul Mackerras 	if (value) {
810f6d57916SPaul Mackerras 		LOCK(flags);
811f6d57916SPaul Mackerras 		MACIO_OUT8(KL_GPIO_MODEM_RESET, gpio | KEYLARGO_GPIO_OUTOUT_DATA);
812f6d57916SPaul Mackerras 		(void)MACIO_IN8(KL_GPIO_MODEM_RESET);
813f6d57916SPaul Mackerras 		UNLOCK(flags); mdelay(250); LOCK(flags);
814f6d57916SPaul Mackerras 		MACIO_OUT8(KL_GPIO_MODEM_RESET, gpio);
815f6d57916SPaul Mackerras 		(void)MACIO_IN8(KL_GPIO_MODEM_RESET);
816f6d57916SPaul Mackerras 		UNLOCK(flags); mdelay(250); LOCK(flags);
817f6d57916SPaul Mackerras 		MACIO_OUT8(KL_GPIO_MODEM_RESET, gpio | KEYLARGO_GPIO_OUTOUT_DATA);
818f6d57916SPaul Mackerras 		(void)MACIO_IN8(KL_GPIO_MODEM_RESET);
819f6d57916SPaul Mackerras 		UNLOCK(flags); mdelay(250);
820f6d57916SPaul Mackerras 	}
821f6d57916SPaul Mackerras 	return 0;
822f6d57916SPaul Mackerras }
823f6d57916SPaul Mackerras 
824f6d57916SPaul Mackerras static long
825f6d57916SPaul Mackerras core99_ata100_enable(struct device_node *node, long value)
826f6d57916SPaul Mackerras {
827f6d57916SPaul Mackerras 	unsigned long flags;
828f6d57916SPaul Mackerras 	struct pci_dev *pdev = NULL;
829f6d57916SPaul Mackerras 	u8 pbus, pid;
830f6d57916SPaul Mackerras 
831f6d57916SPaul Mackerras 	if (uninorth_rev < 0x24)
832f6d57916SPaul Mackerras 		return -ENODEV;
833f6d57916SPaul Mackerras 
834f6d57916SPaul Mackerras 	LOCK(flags);
835f6d57916SPaul Mackerras 	if (value)
836f6d57916SPaul Mackerras 		UN_BIS(UNI_N_CLOCK_CNTL, UNI_N_CLOCK_CNTL_ATA100);
837f6d57916SPaul Mackerras 	else
838f6d57916SPaul Mackerras 		UN_BIC(UNI_N_CLOCK_CNTL, UNI_N_CLOCK_CNTL_ATA100);
839f6d57916SPaul Mackerras 	(void)UN_IN(UNI_N_CLOCK_CNTL);
840f6d57916SPaul Mackerras 	UNLOCK(flags);
841f6d57916SPaul Mackerras 	udelay(20);
842f6d57916SPaul Mackerras 
843f6d57916SPaul Mackerras 	if (value) {
844f6d57916SPaul Mackerras 		if (pci_device_from_OF_node(node, &pbus, &pid) == 0)
845f6d57916SPaul Mackerras 			pdev = pci_find_slot(pbus, pid);
846f6d57916SPaul Mackerras 		if (pdev == NULL)
847f6d57916SPaul Mackerras 			return 0;
848f6d57916SPaul Mackerras 		pci_enable_device(pdev);
849f6d57916SPaul Mackerras 		pci_set_master(pdev);
850f6d57916SPaul Mackerras 	}
851f6d57916SPaul Mackerras 	return 0;
852f6d57916SPaul Mackerras }
853f6d57916SPaul Mackerras 
854f6d57916SPaul Mackerras static long
855f6d57916SPaul Mackerras core99_ide_enable(struct device_node *node, long param, long value)
856f6d57916SPaul Mackerras {
857f6d57916SPaul Mackerras 	/* Bus ID 0 to 2 are KeyLargo based IDE, busID 3 is U2
858f6d57916SPaul Mackerras 	 * based ata-100
859f6d57916SPaul Mackerras 	 */
860f6d57916SPaul Mackerras 	switch(param) {
861f6d57916SPaul Mackerras 	    case 0:
862f6d57916SPaul Mackerras 		return simple_feature_tweak(node, macio_unknown,
863f6d57916SPaul Mackerras 			KEYLARGO_FCR1, KL1_EIDE0_ENABLE, value);
864f6d57916SPaul Mackerras 	    case 1:
865f6d57916SPaul Mackerras 		return simple_feature_tweak(node, macio_unknown,
866f6d57916SPaul Mackerras 			KEYLARGO_FCR1, KL1_EIDE1_ENABLE, value);
867f6d57916SPaul Mackerras 	    case 2:
868f6d57916SPaul Mackerras 		return simple_feature_tweak(node, macio_unknown,
869f6d57916SPaul Mackerras 			KEYLARGO_FCR1, KL1_UIDE_ENABLE, value);
870f6d57916SPaul Mackerras 	    case 3:
871f6d57916SPaul Mackerras 		return core99_ata100_enable(node, value);
872f6d57916SPaul Mackerras 	    default:
873f6d57916SPaul Mackerras 		return -ENODEV;
874f6d57916SPaul Mackerras 	}
875f6d57916SPaul Mackerras }
876f6d57916SPaul Mackerras 
877f6d57916SPaul Mackerras static long
878f6d57916SPaul Mackerras core99_ide_reset(struct device_node *node, long param, long value)
879f6d57916SPaul Mackerras {
880f6d57916SPaul Mackerras 	switch(param) {
881f6d57916SPaul Mackerras 	    case 0:
882f6d57916SPaul Mackerras 		return simple_feature_tweak(node, macio_unknown,
883f6d57916SPaul Mackerras 			KEYLARGO_FCR1, KL1_EIDE0_RESET_N, !value);
884f6d57916SPaul Mackerras 	    case 1:
885f6d57916SPaul Mackerras 		return simple_feature_tweak(node, macio_unknown,
886f6d57916SPaul Mackerras 			KEYLARGO_FCR1, KL1_EIDE1_RESET_N, !value);
887f6d57916SPaul Mackerras 	    case 2:
888f6d57916SPaul Mackerras 		return simple_feature_tweak(node, macio_unknown,
889f6d57916SPaul Mackerras 			KEYLARGO_FCR1, KL1_UIDE_RESET_N, !value);
890f6d57916SPaul Mackerras 	    default:
891f6d57916SPaul Mackerras 		return -ENODEV;
892f6d57916SPaul Mackerras 	}
893f6d57916SPaul Mackerras }
894f6d57916SPaul Mackerras 
895f6d57916SPaul Mackerras static long
896f6d57916SPaul Mackerras core99_gmac_enable(struct device_node *node, long param, long value)
897f6d57916SPaul Mackerras {
898f6d57916SPaul Mackerras 	unsigned long flags;
899f6d57916SPaul Mackerras 
900f6d57916SPaul Mackerras 	LOCK(flags);
901f6d57916SPaul Mackerras 	if (value)
902f6d57916SPaul Mackerras 		UN_BIS(UNI_N_CLOCK_CNTL, UNI_N_CLOCK_CNTL_GMAC);
903f6d57916SPaul Mackerras 	else
904f6d57916SPaul Mackerras 		UN_BIC(UNI_N_CLOCK_CNTL, UNI_N_CLOCK_CNTL_GMAC);
905f6d57916SPaul Mackerras 	(void)UN_IN(UNI_N_CLOCK_CNTL);
906f6d57916SPaul Mackerras 	UNLOCK(flags);
907f6d57916SPaul Mackerras 	udelay(20);
908f6d57916SPaul Mackerras 
909f6d57916SPaul Mackerras 	return 0;
910f6d57916SPaul Mackerras }
911f6d57916SPaul Mackerras 
912f6d57916SPaul Mackerras static long
913f6d57916SPaul Mackerras core99_gmac_phy_reset(struct device_node *node, long param, long value)
914f6d57916SPaul Mackerras {
915f6d57916SPaul Mackerras 	unsigned long flags;
916f6d57916SPaul Mackerras 	struct macio_chip *macio;
917f6d57916SPaul Mackerras 
918f6d57916SPaul Mackerras 	macio = &macio_chips[0];
919f6d57916SPaul Mackerras 	if (macio->type != macio_keylargo && macio->type != macio_pangea &&
920f6d57916SPaul Mackerras 	    macio->type != macio_intrepid)
921f6d57916SPaul Mackerras 		return -ENODEV;
922f6d57916SPaul Mackerras 
923f6d57916SPaul Mackerras 	LOCK(flags);
924f6d57916SPaul Mackerras 	MACIO_OUT8(KL_GPIO_ETH_PHY_RESET, KEYLARGO_GPIO_OUTPUT_ENABLE);
925f6d57916SPaul Mackerras 	(void)MACIO_IN8(KL_GPIO_ETH_PHY_RESET);
926f6d57916SPaul Mackerras 	UNLOCK(flags);
927f6d57916SPaul Mackerras 	mdelay(10);
928f6d57916SPaul Mackerras 	LOCK(flags);
929f6d57916SPaul Mackerras 	MACIO_OUT8(KL_GPIO_ETH_PHY_RESET, /*KEYLARGO_GPIO_OUTPUT_ENABLE | */
930f6d57916SPaul Mackerras 		KEYLARGO_GPIO_OUTOUT_DATA);
931f6d57916SPaul Mackerras 	UNLOCK(flags);
932f6d57916SPaul Mackerras 	mdelay(10);
933f6d57916SPaul Mackerras 
934f6d57916SPaul Mackerras 	return 0;
935f6d57916SPaul Mackerras }
936f6d57916SPaul Mackerras 
937f6d57916SPaul Mackerras static long
938f6d57916SPaul Mackerras core99_sound_chip_enable(struct device_node *node, long param, long value)
939f6d57916SPaul Mackerras {
940f6d57916SPaul Mackerras 	struct macio_chip*	macio;
941f6d57916SPaul Mackerras 	unsigned long		flags;
942f6d57916SPaul Mackerras 
943f6d57916SPaul Mackerras 	macio = macio_find(node, 0);
944f6d57916SPaul Mackerras 	if (!macio)
945f6d57916SPaul Mackerras 		return -ENODEV;
946f6d57916SPaul Mackerras 
947f6d57916SPaul Mackerras 	/* Do a better probe code, screamer G4 desktops &
948f6d57916SPaul Mackerras 	 * iMacs can do that too, add a recalibrate  in
949f6d57916SPaul Mackerras 	 * the driver as well
950f6d57916SPaul Mackerras 	 */
951f6d57916SPaul Mackerras 	if (pmac_mb.model_id == PMAC_TYPE_PISMO ||
952f6d57916SPaul Mackerras 	    pmac_mb.model_id == PMAC_TYPE_TITANIUM) {
953f6d57916SPaul Mackerras 		LOCK(flags);
954f6d57916SPaul Mackerras 		if (value)
955f6d57916SPaul Mackerras 			MACIO_OUT8(KL_GPIO_SOUND_POWER,
956f6d57916SPaul Mackerras 				KEYLARGO_GPIO_OUTPUT_ENABLE |
957f6d57916SPaul Mackerras 				KEYLARGO_GPIO_OUTOUT_DATA);
958f6d57916SPaul Mackerras 		else
959f6d57916SPaul Mackerras 			MACIO_OUT8(KL_GPIO_SOUND_POWER,
960f6d57916SPaul Mackerras 				KEYLARGO_GPIO_OUTPUT_ENABLE);
961f6d57916SPaul Mackerras 		(void)MACIO_IN8(KL_GPIO_SOUND_POWER);
962f6d57916SPaul Mackerras 		UNLOCK(flags);
963f6d57916SPaul Mackerras 	}
964f6d57916SPaul Mackerras 	return 0;
965f6d57916SPaul Mackerras }
966f6d57916SPaul Mackerras 
967f6d57916SPaul Mackerras static long
968f6d57916SPaul Mackerras core99_airport_enable(struct device_node *node, long param, long value)
969f6d57916SPaul Mackerras {
970f6d57916SPaul Mackerras 	struct macio_chip*	macio;
971f6d57916SPaul Mackerras 	unsigned long		flags;
972f6d57916SPaul Mackerras 	int			state;
973f6d57916SPaul Mackerras 
974f6d57916SPaul Mackerras 	macio = macio_find(node, 0);
975f6d57916SPaul Mackerras 	if (!macio)
976f6d57916SPaul Mackerras 		return -ENODEV;
977f6d57916SPaul Mackerras 
978f6d57916SPaul Mackerras 	/* Hint: we allow passing of macio itself for the sake of the
979f6d57916SPaul Mackerras 	 * sleep code
980f6d57916SPaul Mackerras 	 */
981f6d57916SPaul Mackerras 	if (node != macio->of_node &&
982f6d57916SPaul Mackerras 	    (!node->parent || node->parent != macio->of_node))
983f6d57916SPaul Mackerras 		return -ENODEV;
984f6d57916SPaul Mackerras 	state = (macio->flags & MACIO_FLAG_AIRPORT_ON) != 0;
985f6d57916SPaul Mackerras 	if (value == state)
986f6d57916SPaul Mackerras 		return 0;
987f6d57916SPaul Mackerras 	if (value) {
988f6d57916SPaul Mackerras 		/* This code is a reproduction of OF enable-cardslot
989f6d57916SPaul Mackerras 		 * and init-wireless methods, slightly hacked until
990f6d57916SPaul Mackerras 		 * I got it working.
991f6d57916SPaul Mackerras 		 */
992f6d57916SPaul Mackerras 		LOCK(flags);
993f6d57916SPaul Mackerras 		MACIO_OUT8(KEYLARGO_GPIO_0+0xf, 5);
994f6d57916SPaul Mackerras 		(void)MACIO_IN8(KEYLARGO_GPIO_0+0xf);
995f6d57916SPaul Mackerras 		UNLOCK(flags);
996f6d57916SPaul Mackerras 		mdelay(10);
997f6d57916SPaul Mackerras 		LOCK(flags);
998f6d57916SPaul Mackerras 		MACIO_OUT8(KEYLARGO_GPIO_0+0xf, 4);
999f6d57916SPaul Mackerras 		(void)MACIO_IN8(KEYLARGO_GPIO_0+0xf);
1000f6d57916SPaul Mackerras 		UNLOCK(flags);
1001f6d57916SPaul Mackerras 
1002f6d57916SPaul Mackerras 		mdelay(10);
1003f6d57916SPaul Mackerras 
1004f6d57916SPaul Mackerras 		LOCK(flags);
1005f6d57916SPaul Mackerras 		MACIO_BIC(KEYLARGO_FCR2, KL2_CARDSEL_16);
1006f6d57916SPaul Mackerras 		(void)MACIO_IN32(KEYLARGO_FCR2);
1007f6d57916SPaul Mackerras 		udelay(10);
1008f6d57916SPaul Mackerras 		MACIO_OUT8(KEYLARGO_GPIO_EXTINT_0+0xb, 0);
1009f6d57916SPaul Mackerras 		(void)MACIO_IN8(KEYLARGO_GPIO_EXTINT_0+0xb);
1010f6d57916SPaul Mackerras 		udelay(10);
1011f6d57916SPaul Mackerras 		MACIO_OUT8(KEYLARGO_GPIO_EXTINT_0+0xa, 0x28);
1012f6d57916SPaul Mackerras 		(void)MACIO_IN8(KEYLARGO_GPIO_EXTINT_0+0xa);
1013f6d57916SPaul Mackerras 		udelay(10);
1014f6d57916SPaul Mackerras 		MACIO_OUT8(KEYLARGO_GPIO_EXTINT_0+0xd, 0x28);
1015f6d57916SPaul Mackerras 		(void)MACIO_IN8(KEYLARGO_GPIO_EXTINT_0+0xd);
1016f6d57916SPaul Mackerras 		udelay(10);
1017f6d57916SPaul Mackerras 		MACIO_OUT8(KEYLARGO_GPIO_0+0xd, 0x28);
1018f6d57916SPaul Mackerras 		(void)MACIO_IN8(KEYLARGO_GPIO_0+0xd);
1019f6d57916SPaul Mackerras 		udelay(10);
1020f6d57916SPaul Mackerras 		MACIO_OUT8(KEYLARGO_GPIO_0+0xe, 0x28);
1021f6d57916SPaul Mackerras 		(void)MACIO_IN8(KEYLARGO_GPIO_0+0xe);
1022f6d57916SPaul Mackerras 		UNLOCK(flags);
1023f6d57916SPaul Mackerras 		udelay(10);
1024f6d57916SPaul Mackerras 		MACIO_OUT32(0x1c000, 0);
1025f6d57916SPaul Mackerras 		mdelay(1);
1026f6d57916SPaul Mackerras 		MACIO_OUT8(0x1a3e0, 0x41);
1027f6d57916SPaul Mackerras 		(void)MACIO_IN8(0x1a3e0);
1028f6d57916SPaul Mackerras 		udelay(10);
1029f6d57916SPaul Mackerras 		LOCK(flags);
1030f6d57916SPaul Mackerras 		MACIO_BIS(KEYLARGO_FCR2, KL2_CARDSEL_16);
1031f6d57916SPaul Mackerras 		(void)MACIO_IN32(KEYLARGO_FCR2);
1032f6d57916SPaul Mackerras 		UNLOCK(flags);
1033f6d57916SPaul Mackerras 		mdelay(100);
1034f6d57916SPaul Mackerras 
1035f6d57916SPaul Mackerras 		macio->flags |= MACIO_FLAG_AIRPORT_ON;
1036f6d57916SPaul Mackerras 	} else {
1037f6d57916SPaul Mackerras 		LOCK(flags);
1038f6d57916SPaul Mackerras 		MACIO_BIC(KEYLARGO_FCR2, KL2_CARDSEL_16);
1039f6d57916SPaul Mackerras 		(void)MACIO_IN32(KEYLARGO_FCR2);
1040f6d57916SPaul Mackerras 		MACIO_OUT8(KL_GPIO_AIRPORT_0, 0);
1041f6d57916SPaul Mackerras 		MACIO_OUT8(KL_GPIO_AIRPORT_1, 0);
1042f6d57916SPaul Mackerras 		MACIO_OUT8(KL_GPIO_AIRPORT_2, 0);
1043f6d57916SPaul Mackerras 		MACIO_OUT8(KL_GPIO_AIRPORT_3, 0);
1044f6d57916SPaul Mackerras 		MACIO_OUT8(KL_GPIO_AIRPORT_4, 0);
1045f6d57916SPaul Mackerras 		(void)MACIO_IN8(KL_GPIO_AIRPORT_4);
1046f6d57916SPaul Mackerras 		UNLOCK(flags);
1047f6d57916SPaul Mackerras 
1048f6d57916SPaul Mackerras 		macio->flags &= ~MACIO_FLAG_AIRPORT_ON;
1049f6d57916SPaul Mackerras 	}
1050f6d57916SPaul Mackerras 	return 0;
1051f6d57916SPaul Mackerras }
1052f6d57916SPaul Mackerras 
1053f6d57916SPaul Mackerras #ifdef CONFIG_SMP
1054f6d57916SPaul Mackerras static long
1055f6d57916SPaul Mackerras core99_reset_cpu(struct device_node *node, long param, long value)
1056f6d57916SPaul Mackerras {
1057f6d57916SPaul Mackerras 	unsigned int reset_io = 0;
1058f6d57916SPaul Mackerras 	unsigned long flags;
1059f6d57916SPaul Mackerras 	struct macio_chip *macio;
1060f6d57916SPaul Mackerras 	struct device_node *np;
1061f6d57916SPaul Mackerras 	const int dflt_reset_lines[] = {	KL_GPIO_RESET_CPU0,
1062f6d57916SPaul Mackerras 						KL_GPIO_RESET_CPU1,
1063f6d57916SPaul Mackerras 						KL_GPIO_RESET_CPU2,
1064f6d57916SPaul Mackerras 						KL_GPIO_RESET_CPU3 };
1065f6d57916SPaul Mackerras 
1066f6d57916SPaul Mackerras 	macio = &macio_chips[0];
1067f6d57916SPaul Mackerras 	if (macio->type != macio_keylargo)
1068f6d57916SPaul Mackerras 		return -ENODEV;
1069f6d57916SPaul Mackerras 
1070f6d57916SPaul Mackerras 	np = find_path_device("/cpus");
1071f6d57916SPaul Mackerras 	if (np == NULL)
1072f6d57916SPaul Mackerras 		return -ENODEV;
1073f6d57916SPaul Mackerras 	for (np = np->child; np != NULL; np = np->sibling) {
1074f6d57916SPaul Mackerras 		u32 *num = (u32 *)get_property(np, "reg", NULL);
1075f6d57916SPaul Mackerras 		u32 *rst = (u32 *)get_property(np, "soft-reset", NULL);
1076f6d57916SPaul Mackerras 		if (num == NULL || rst == NULL)
1077f6d57916SPaul Mackerras 			continue;
1078f6d57916SPaul Mackerras 		if (param == *num) {
1079f6d57916SPaul Mackerras 			reset_io = *rst;
1080f6d57916SPaul Mackerras 			break;
1081f6d57916SPaul Mackerras 		}
1082f6d57916SPaul Mackerras 	}
1083f6d57916SPaul Mackerras 	if (np == NULL || reset_io == 0)
1084f6d57916SPaul Mackerras 		reset_io = dflt_reset_lines[param];
1085f6d57916SPaul Mackerras 
1086f6d57916SPaul Mackerras 	LOCK(flags);
1087f6d57916SPaul Mackerras 	MACIO_OUT8(reset_io, KEYLARGO_GPIO_OUTPUT_ENABLE);
1088f6d57916SPaul Mackerras 	(void)MACIO_IN8(reset_io);
1089f6d57916SPaul Mackerras 	udelay(1);
1090f6d57916SPaul Mackerras 	MACIO_OUT8(reset_io, 0);
1091f6d57916SPaul Mackerras 	(void)MACIO_IN8(reset_io);
1092f6d57916SPaul Mackerras 	UNLOCK(flags);
1093f6d57916SPaul Mackerras 
1094f6d57916SPaul Mackerras 	return 0;
1095f6d57916SPaul Mackerras }
1096f6d57916SPaul Mackerras #endif /* CONFIG_SMP */
1097f6d57916SPaul Mackerras 
1098f6d57916SPaul Mackerras static long
1099f6d57916SPaul Mackerras core99_usb_enable(struct device_node *node, long param, long value)
1100f6d57916SPaul Mackerras {
1101f6d57916SPaul Mackerras 	struct macio_chip *macio;
1102f6d57916SPaul Mackerras 	unsigned long flags;
1103f6d57916SPaul Mackerras 	char *prop;
1104f6d57916SPaul Mackerras 	int number;
1105f6d57916SPaul Mackerras 	u32 reg;
1106f6d57916SPaul Mackerras 
1107f6d57916SPaul Mackerras 	macio = &macio_chips[0];
1108f6d57916SPaul Mackerras 	if (macio->type != macio_keylargo && macio->type != macio_pangea &&
1109f6d57916SPaul Mackerras 	    macio->type != macio_intrepid)
1110f6d57916SPaul Mackerras 		return -ENODEV;
1111f6d57916SPaul Mackerras 
1112f6d57916SPaul Mackerras 	prop = (char *)get_property(node, "AAPL,clock-id", NULL);
1113f6d57916SPaul Mackerras 	if (!prop)
1114f6d57916SPaul Mackerras 		return -ENODEV;
1115f6d57916SPaul Mackerras 	if (strncmp(prop, "usb0u048", 8) == 0)
1116f6d57916SPaul Mackerras 		number = 0;
1117f6d57916SPaul Mackerras 	else if (strncmp(prop, "usb1u148", 8) == 0)
1118f6d57916SPaul Mackerras 		number = 2;
1119f6d57916SPaul Mackerras 	else if (strncmp(prop, "usb2u248", 8) == 0)
1120f6d57916SPaul Mackerras 		number = 4;
1121f6d57916SPaul Mackerras 	else
1122f6d57916SPaul Mackerras 		return -ENODEV;
1123f6d57916SPaul Mackerras 
1124f6d57916SPaul Mackerras 	/* Sorry for the brute-force locking, but this is only used during
1125f6d57916SPaul Mackerras 	 * sleep and the timing seem to be critical
1126f6d57916SPaul Mackerras 	 */
1127f6d57916SPaul Mackerras 	LOCK(flags);
1128f6d57916SPaul Mackerras 	if (value) {
1129f6d57916SPaul Mackerras 		/* Turn ON */
1130f6d57916SPaul Mackerras 		if (number == 0) {
1131f6d57916SPaul Mackerras 			MACIO_BIC(KEYLARGO_FCR0, (KL0_USB0_PAD_SUSPEND0 | KL0_USB0_PAD_SUSPEND1));
1132f6d57916SPaul Mackerras 			(void)MACIO_IN32(KEYLARGO_FCR0);
1133f6d57916SPaul Mackerras 			UNLOCK(flags);
1134f6d57916SPaul Mackerras 			mdelay(1);
1135f6d57916SPaul Mackerras 			LOCK(flags);
1136f6d57916SPaul Mackerras 			MACIO_BIS(KEYLARGO_FCR0, KL0_USB0_CELL_ENABLE);
1137f6d57916SPaul Mackerras 		} else if (number == 2) {
1138f6d57916SPaul Mackerras 			MACIO_BIC(KEYLARGO_FCR0, (KL0_USB1_PAD_SUSPEND0 | KL0_USB1_PAD_SUSPEND1));
1139f6d57916SPaul Mackerras 			UNLOCK(flags);
1140f6d57916SPaul Mackerras 			(void)MACIO_IN32(KEYLARGO_FCR0);
1141f6d57916SPaul Mackerras 			mdelay(1);
1142f6d57916SPaul Mackerras 			LOCK(flags);
1143f6d57916SPaul Mackerras 			MACIO_BIS(KEYLARGO_FCR0, KL0_USB1_CELL_ENABLE);
1144f6d57916SPaul Mackerras 		} else if (number == 4) {
1145f6d57916SPaul Mackerras 			MACIO_BIC(KEYLARGO_FCR1, (KL1_USB2_PAD_SUSPEND0 | KL1_USB2_PAD_SUSPEND1));
1146f6d57916SPaul Mackerras 			UNLOCK(flags);
1147f6d57916SPaul Mackerras 			(void)MACIO_IN32(KEYLARGO_FCR1);
1148f6d57916SPaul Mackerras 			mdelay(1);
1149f6d57916SPaul Mackerras 			LOCK(flags);
1150f6d57916SPaul Mackerras 			MACIO_BIS(KEYLARGO_FCR1, KL1_USB2_CELL_ENABLE);
1151f6d57916SPaul Mackerras 		}
1152f6d57916SPaul Mackerras 		if (number < 4) {
1153f6d57916SPaul Mackerras 			reg = MACIO_IN32(KEYLARGO_FCR4);
1154f6d57916SPaul Mackerras 			reg &=	~(KL4_PORT_WAKEUP_ENABLE(number) | KL4_PORT_RESUME_WAKE_EN(number) |
1155f6d57916SPaul Mackerras 				KL4_PORT_CONNECT_WAKE_EN(number) | KL4_PORT_DISCONNECT_WAKE_EN(number));
1156f6d57916SPaul Mackerras 			reg &=	~(KL4_PORT_WAKEUP_ENABLE(number+1) | KL4_PORT_RESUME_WAKE_EN(number+1) |
1157f6d57916SPaul Mackerras 				KL4_PORT_CONNECT_WAKE_EN(number+1) | KL4_PORT_DISCONNECT_WAKE_EN(number+1));
1158f6d57916SPaul Mackerras 			MACIO_OUT32(KEYLARGO_FCR4, reg);
1159f6d57916SPaul Mackerras 			(void)MACIO_IN32(KEYLARGO_FCR4);
1160f6d57916SPaul Mackerras 			udelay(10);
1161f6d57916SPaul Mackerras 		} else {
1162f6d57916SPaul Mackerras 			reg = MACIO_IN32(KEYLARGO_FCR3);
1163f6d57916SPaul Mackerras 			reg &=	~(KL3_IT_PORT_WAKEUP_ENABLE(0) | KL3_IT_PORT_RESUME_WAKE_EN(0) |
1164f6d57916SPaul Mackerras 				KL3_IT_PORT_CONNECT_WAKE_EN(0) | KL3_IT_PORT_DISCONNECT_WAKE_EN(0));
1165f6d57916SPaul Mackerras 			reg &=	~(KL3_IT_PORT_WAKEUP_ENABLE(1) | KL3_IT_PORT_RESUME_WAKE_EN(1) |
1166f6d57916SPaul Mackerras 				KL3_IT_PORT_CONNECT_WAKE_EN(1) | KL3_IT_PORT_DISCONNECT_WAKE_EN(1));
1167f6d57916SPaul Mackerras 			MACIO_OUT32(KEYLARGO_FCR3, reg);
1168f6d57916SPaul Mackerras 			(void)MACIO_IN32(KEYLARGO_FCR3);
1169f6d57916SPaul Mackerras 			udelay(10);
1170f6d57916SPaul Mackerras 		}
1171f6d57916SPaul Mackerras 		if (macio->type == macio_intrepid) {
1172f6d57916SPaul Mackerras 			/* wait for clock stopped bits to clear */
1173f6d57916SPaul Mackerras 			u32 test0 = 0, test1 = 0;
1174f6d57916SPaul Mackerras 			u32 status0, status1;
1175f6d57916SPaul Mackerras 			int timeout = 1000;
1176f6d57916SPaul Mackerras 
1177f6d57916SPaul Mackerras 			UNLOCK(flags);
1178f6d57916SPaul Mackerras 			switch (number) {
1179f6d57916SPaul Mackerras 			case 0:
1180f6d57916SPaul Mackerras 				test0 = UNI_N_CLOCK_STOPPED_USB0;
1181f6d57916SPaul Mackerras 				test1 = UNI_N_CLOCK_STOPPED_USB0PCI;
1182f6d57916SPaul Mackerras 				break;
1183f6d57916SPaul Mackerras 			case 2:
1184f6d57916SPaul Mackerras 				test0 = UNI_N_CLOCK_STOPPED_USB1;
1185f6d57916SPaul Mackerras 				test1 = UNI_N_CLOCK_STOPPED_USB1PCI;
1186f6d57916SPaul Mackerras 				break;
1187f6d57916SPaul Mackerras 			case 4:
1188f6d57916SPaul Mackerras 				test0 = UNI_N_CLOCK_STOPPED_USB2;
1189f6d57916SPaul Mackerras 				test1 = UNI_N_CLOCK_STOPPED_USB2PCI;
1190f6d57916SPaul Mackerras 				break;
1191f6d57916SPaul Mackerras 			}
1192f6d57916SPaul Mackerras 			do {
1193f6d57916SPaul Mackerras 				if (--timeout <= 0) {
1194f6d57916SPaul Mackerras 					printk(KERN_ERR "core99_usb_enable: "
1195f6d57916SPaul Mackerras 					       "Timeout waiting for clocks\n");
1196f6d57916SPaul Mackerras 					break;
1197f6d57916SPaul Mackerras 				}
1198f6d57916SPaul Mackerras 				mdelay(1);
1199f6d57916SPaul Mackerras 				status0 = UN_IN(UNI_N_CLOCK_STOP_STATUS0);
1200f6d57916SPaul Mackerras 				status1 = UN_IN(UNI_N_CLOCK_STOP_STATUS1);
1201f6d57916SPaul Mackerras 			} while ((status0 & test0) | (status1 & test1));
1202f6d57916SPaul Mackerras 			LOCK(flags);
1203f6d57916SPaul Mackerras 		}
1204f6d57916SPaul Mackerras 	} else {
1205f6d57916SPaul Mackerras 		/* Turn OFF */
1206f6d57916SPaul Mackerras 		if (number < 4) {
1207f6d57916SPaul Mackerras 			reg = MACIO_IN32(KEYLARGO_FCR4);
1208f6d57916SPaul Mackerras 			reg |=	KL4_PORT_WAKEUP_ENABLE(number) | KL4_PORT_RESUME_WAKE_EN(number) |
1209f6d57916SPaul Mackerras 				KL4_PORT_CONNECT_WAKE_EN(number) | KL4_PORT_DISCONNECT_WAKE_EN(number);
1210f6d57916SPaul Mackerras 			reg |=	KL4_PORT_WAKEUP_ENABLE(number+1) | KL4_PORT_RESUME_WAKE_EN(number+1) |
1211f6d57916SPaul Mackerras 				KL4_PORT_CONNECT_WAKE_EN(number+1) | KL4_PORT_DISCONNECT_WAKE_EN(number+1);
1212f6d57916SPaul Mackerras 			MACIO_OUT32(KEYLARGO_FCR4, reg);
1213f6d57916SPaul Mackerras 			(void)MACIO_IN32(KEYLARGO_FCR4);
1214f6d57916SPaul Mackerras 			udelay(1);
1215f6d57916SPaul Mackerras 		} else {
1216f6d57916SPaul Mackerras 			reg = MACIO_IN32(KEYLARGO_FCR3);
1217f6d57916SPaul Mackerras 			reg |=	KL3_IT_PORT_WAKEUP_ENABLE(0) | KL3_IT_PORT_RESUME_WAKE_EN(0) |
1218f6d57916SPaul Mackerras 				KL3_IT_PORT_CONNECT_WAKE_EN(0) | KL3_IT_PORT_DISCONNECT_WAKE_EN(0);
1219f6d57916SPaul Mackerras 			reg |=	KL3_IT_PORT_WAKEUP_ENABLE(1) | KL3_IT_PORT_RESUME_WAKE_EN(1) |
1220f6d57916SPaul Mackerras 				KL3_IT_PORT_CONNECT_WAKE_EN(1) | KL3_IT_PORT_DISCONNECT_WAKE_EN(1);
1221f6d57916SPaul Mackerras 			MACIO_OUT32(KEYLARGO_FCR3, reg);
1222f6d57916SPaul Mackerras 			(void)MACIO_IN32(KEYLARGO_FCR3);
1223f6d57916SPaul Mackerras 			udelay(1);
1224f6d57916SPaul Mackerras 		}
1225f6d57916SPaul Mackerras 		if (number == 0) {
1226f6d57916SPaul Mackerras 			if (macio->type != macio_intrepid)
1227f6d57916SPaul Mackerras 				MACIO_BIC(KEYLARGO_FCR0, KL0_USB0_CELL_ENABLE);
1228f6d57916SPaul Mackerras 			(void)MACIO_IN32(KEYLARGO_FCR0);
1229f6d57916SPaul Mackerras 			udelay(1);
1230f6d57916SPaul Mackerras 			MACIO_BIS(KEYLARGO_FCR0, (KL0_USB0_PAD_SUSPEND0 | KL0_USB0_PAD_SUSPEND1));
1231f6d57916SPaul Mackerras 			(void)MACIO_IN32(KEYLARGO_FCR0);
1232f6d57916SPaul Mackerras 		} else if (number == 2) {
1233f6d57916SPaul Mackerras 			if (macio->type != macio_intrepid)
1234f6d57916SPaul Mackerras 				MACIO_BIC(KEYLARGO_FCR0, KL0_USB1_CELL_ENABLE);
1235f6d57916SPaul Mackerras 			(void)MACIO_IN32(KEYLARGO_FCR0);
1236f6d57916SPaul Mackerras 			udelay(1);
1237f6d57916SPaul Mackerras 			MACIO_BIS(KEYLARGO_FCR0, (KL0_USB1_PAD_SUSPEND0 | KL0_USB1_PAD_SUSPEND1));
1238f6d57916SPaul Mackerras 			(void)MACIO_IN32(KEYLARGO_FCR0);
1239f6d57916SPaul Mackerras 		} else if (number == 4) {
1240f6d57916SPaul Mackerras 			udelay(1);
1241f6d57916SPaul Mackerras 			MACIO_BIS(KEYLARGO_FCR1, (KL1_USB2_PAD_SUSPEND0 | KL1_USB2_PAD_SUSPEND1));
1242f6d57916SPaul Mackerras 			(void)MACIO_IN32(KEYLARGO_FCR1);
1243f6d57916SPaul Mackerras 		}
1244f6d57916SPaul Mackerras 		udelay(1);
1245f6d57916SPaul Mackerras 	}
1246f6d57916SPaul Mackerras 	UNLOCK(flags);
1247f6d57916SPaul Mackerras 
1248f6d57916SPaul Mackerras 	return 0;
1249f6d57916SPaul Mackerras }
1250f6d57916SPaul Mackerras 
1251f6d57916SPaul Mackerras static long
1252f6d57916SPaul Mackerras core99_firewire_enable(struct device_node *node, long param, long value)
1253f6d57916SPaul Mackerras {
1254f6d57916SPaul Mackerras 	unsigned long flags;
1255f6d57916SPaul Mackerras 	struct macio_chip *macio;
1256f6d57916SPaul Mackerras 
1257f6d57916SPaul Mackerras 	macio = &macio_chips[0];
1258f6d57916SPaul Mackerras 	if (macio->type != macio_keylargo && macio->type != macio_pangea &&
1259f6d57916SPaul Mackerras 	    macio->type != macio_intrepid)
1260f6d57916SPaul Mackerras 		return -ENODEV;
1261f6d57916SPaul Mackerras 	if (!(macio->flags & MACIO_FLAG_FW_SUPPORTED))
1262f6d57916SPaul Mackerras 		return -ENODEV;
1263f6d57916SPaul Mackerras 
1264f6d57916SPaul Mackerras 	LOCK(flags);
1265f6d57916SPaul Mackerras 	if (value) {
1266f6d57916SPaul Mackerras 		UN_BIS(UNI_N_CLOCK_CNTL, UNI_N_CLOCK_CNTL_FW);
1267f6d57916SPaul Mackerras 		(void)UN_IN(UNI_N_CLOCK_CNTL);
1268f6d57916SPaul Mackerras 	} else {
1269f6d57916SPaul Mackerras 		UN_BIC(UNI_N_CLOCK_CNTL, UNI_N_CLOCK_CNTL_FW);
1270f6d57916SPaul Mackerras 		(void)UN_IN(UNI_N_CLOCK_CNTL);
1271f6d57916SPaul Mackerras 	}
1272f6d57916SPaul Mackerras 	UNLOCK(flags);
1273f6d57916SPaul Mackerras 	mdelay(1);
1274f6d57916SPaul Mackerras 
1275f6d57916SPaul Mackerras 	return 0;
1276f6d57916SPaul Mackerras }
1277f6d57916SPaul Mackerras 
1278f6d57916SPaul Mackerras static long
1279f6d57916SPaul Mackerras core99_firewire_cable_power(struct device_node *node, long param, long value)
1280f6d57916SPaul Mackerras {
1281f6d57916SPaul Mackerras 	unsigned long flags;
1282f6d57916SPaul Mackerras 	struct macio_chip *macio;
1283f6d57916SPaul Mackerras 
1284f6d57916SPaul Mackerras 	/* Trick: we allow NULL node */
1285f6d57916SPaul Mackerras 	if ((pmac_mb.board_flags & PMAC_MB_HAS_FW_POWER) == 0)
1286f6d57916SPaul Mackerras 		return -ENODEV;
1287f6d57916SPaul Mackerras 	macio = &macio_chips[0];
1288f6d57916SPaul Mackerras 	if (macio->type != macio_keylargo && macio->type != macio_pangea &&
1289f6d57916SPaul Mackerras 	    macio->type != macio_intrepid)
1290f6d57916SPaul Mackerras 		return -ENODEV;
1291f6d57916SPaul Mackerras 	if (!(macio->flags & MACIO_FLAG_FW_SUPPORTED))
1292f6d57916SPaul Mackerras 		return -ENODEV;
1293f6d57916SPaul Mackerras 
1294f6d57916SPaul Mackerras 	LOCK(flags);
1295f6d57916SPaul Mackerras 	if (value) {
1296f6d57916SPaul Mackerras 		MACIO_OUT8(KL_GPIO_FW_CABLE_POWER , 0);
1297f6d57916SPaul Mackerras 		MACIO_IN8(KL_GPIO_FW_CABLE_POWER);
1298f6d57916SPaul Mackerras 		udelay(10);
1299f6d57916SPaul Mackerras 	} else {
1300f6d57916SPaul Mackerras 		MACIO_OUT8(KL_GPIO_FW_CABLE_POWER , 4);
1301f6d57916SPaul Mackerras 		MACIO_IN8(KL_GPIO_FW_CABLE_POWER); udelay(10);
1302f6d57916SPaul Mackerras 	}
1303f6d57916SPaul Mackerras 	UNLOCK(flags);
1304f6d57916SPaul Mackerras 	mdelay(1);
1305f6d57916SPaul Mackerras 
1306f6d57916SPaul Mackerras 	return 0;
1307f6d57916SPaul Mackerras }
1308f6d57916SPaul Mackerras 
1309f6d57916SPaul Mackerras static long
1310f6d57916SPaul Mackerras intrepid_aack_delay_enable(struct device_node *node, long param, long value)
1311f6d57916SPaul Mackerras {
1312f6d57916SPaul Mackerras 	unsigned long flags;
1313f6d57916SPaul Mackerras 
1314f6d57916SPaul Mackerras 	if (uninorth_rev < 0xd2)
1315f6d57916SPaul Mackerras 		return -ENODEV;
1316f6d57916SPaul Mackerras 
1317f6d57916SPaul Mackerras 	LOCK(flags);
1318f6d57916SPaul Mackerras 	if (param)
1319f6d57916SPaul Mackerras 		UN_BIS(UNI_N_AACK_DELAY, UNI_N_AACK_DELAY_ENABLE);
1320f6d57916SPaul Mackerras 	else
1321f6d57916SPaul Mackerras 		UN_BIC(UNI_N_AACK_DELAY, UNI_N_AACK_DELAY_ENABLE);
1322f6d57916SPaul Mackerras 	UNLOCK(flags);
1323f6d57916SPaul Mackerras 
1324f6d57916SPaul Mackerras 	return 0;
1325f6d57916SPaul Mackerras }
1326f6d57916SPaul Mackerras 
1327f6d57916SPaul Mackerras 
1328f6d57916SPaul Mackerras #endif /* CONFIG_POWER4 */
1329f6d57916SPaul Mackerras 
1330f6d57916SPaul Mackerras static long
1331f6d57916SPaul Mackerras core99_read_gpio(struct device_node *node, long param, long value)
1332f6d57916SPaul Mackerras {
1333f6d57916SPaul Mackerras 	struct macio_chip *macio = &macio_chips[0];
1334f6d57916SPaul Mackerras 
1335f6d57916SPaul Mackerras 	return MACIO_IN8(param);
1336f6d57916SPaul Mackerras }
1337f6d57916SPaul Mackerras 
1338f6d57916SPaul Mackerras 
1339f6d57916SPaul Mackerras static long
1340f6d57916SPaul Mackerras core99_write_gpio(struct device_node *node, long param, long value)
1341f6d57916SPaul Mackerras {
1342f6d57916SPaul Mackerras 	struct macio_chip *macio = &macio_chips[0];
1343f6d57916SPaul Mackerras 
1344f6d57916SPaul Mackerras 	MACIO_OUT8(param, (u8)(value & 0xff));
1345f6d57916SPaul Mackerras 	return 0;
1346f6d57916SPaul Mackerras }
1347f6d57916SPaul Mackerras 
1348f6d57916SPaul Mackerras #ifdef CONFIG_POWER4
1349f6d57916SPaul Mackerras static long g5_gmac_enable(struct device_node *node, long param, long value)
1350f6d57916SPaul Mackerras {
1351f6d57916SPaul Mackerras 	struct macio_chip *macio = &macio_chips[0];
1352f6d57916SPaul Mackerras 	unsigned long flags;
1353f6d57916SPaul Mackerras 
1354f6d57916SPaul Mackerras 	if (node == NULL)
1355f6d57916SPaul Mackerras 		return -ENODEV;
1356f6d57916SPaul Mackerras 
1357f6d57916SPaul Mackerras 	LOCK(flags);
1358f6d57916SPaul Mackerras 	if (value) {
1359f6d57916SPaul Mackerras 		MACIO_BIS(KEYLARGO_FCR1, K2_FCR1_GMAC_CLK_ENABLE);
1360f6d57916SPaul Mackerras 		mb();
1361f6d57916SPaul Mackerras 		k2_skiplist[0] = NULL;
1362f6d57916SPaul Mackerras 	} else {
1363f6d57916SPaul Mackerras 		k2_skiplist[0] = node;
1364f6d57916SPaul Mackerras 		mb();
1365f6d57916SPaul Mackerras 		MACIO_BIC(KEYLARGO_FCR1, K2_FCR1_GMAC_CLK_ENABLE);
1366f6d57916SPaul Mackerras 	}
1367f6d57916SPaul Mackerras 
1368f6d57916SPaul Mackerras 	UNLOCK(flags);
1369f6d57916SPaul Mackerras 	mdelay(1);
1370f6d57916SPaul Mackerras 
1371f6d57916SPaul Mackerras 	return 0;
1372f6d57916SPaul Mackerras }
1373f6d57916SPaul Mackerras 
1374f6d57916SPaul Mackerras static long g5_fw_enable(struct device_node *node, long param, long value)
1375f6d57916SPaul Mackerras {
1376f6d57916SPaul Mackerras 	struct macio_chip *macio = &macio_chips[0];
1377f6d57916SPaul Mackerras 	unsigned long flags;
1378f6d57916SPaul Mackerras 
1379f6d57916SPaul Mackerras 	if (node == NULL)
1380f6d57916SPaul Mackerras 		return -ENODEV;
1381f6d57916SPaul Mackerras 
1382f6d57916SPaul Mackerras 	LOCK(flags);
1383f6d57916SPaul Mackerras 	if (value) {
1384f6d57916SPaul Mackerras 		MACIO_BIS(KEYLARGO_FCR1, K2_FCR1_FW_CLK_ENABLE);
1385f6d57916SPaul Mackerras 		mb();
1386f6d57916SPaul Mackerras 		k2_skiplist[1] = NULL;
1387f6d57916SPaul Mackerras 	} else {
1388f6d57916SPaul Mackerras 		k2_skiplist[1] = node;
1389f6d57916SPaul Mackerras 		mb();
1390f6d57916SPaul Mackerras 		MACIO_BIC(KEYLARGO_FCR1, K2_FCR1_FW_CLK_ENABLE);
1391f6d57916SPaul Mackerras 	}
1392f6d57916SPaul Mackerras 
1393f6d57916SPaul Mackerras 	UNLOCK(flags);
1394f6d57916SPaul Mackerras 	mdelay(1);
1395f6d57916SPaul Mackerras 
1396f6d57916SPaul Mackerras 	return 0;
1397f6d57916SPaul Mackerras }
1398f6d57916SPaul Mackerras 
1399f6d57916SPaul Mackerras static long g5_mpic_enable(struct device_node *node, long param, long value)
1400f6d57916SPaul Mackerras {
1401f6d57916SPaul Mackerras 	unsigned long flags;
1402f6d57916SPaul Mackerras 
1403f6d57916SPaul Mackerras 	if (node->parent == NULL || strcmp(node->parent->name, "u3"))
1404f6d57916SPaul Mackerras 		return 0;
1405f6d57916SPaul Mackerras 
1406f6d57916SPaul Mackerras 	LOCK(flags);
1407f6d57916SPaul Mackerras 	UN_BIS(U3_TOGGLE_REG, U3_MPIC_RESET | U3_MPIC_OUTPUT_ENABLE);
1408f6d57916SPaul Mackerras 	UNLOCK(flags);
1409f6d57916SPaul Mackerras 
1410f6d57916SPaul Mackerras 	return 0;
1411f6d57916SPaul Mackerras }
1412f6d57916SPaul Mackerras 
1413f6d57916SPaul Mackerras static long g5_eth_phy_reset(struct device_node *node, long param, long value)
1414f6d57916SPaul Mackerras {
1415f6d57916SPaul Mackerras 	struct macio_chip *macio = &macio_chips[0];
1416f6d57916SPaul Mackerras 	struct device_node *phy;
1417f6d57916SPaul Mackerras 	int need_reset;
1418f6d57916SPaul Mackerras 
1419f6d57916SPaul Mackerras 	/*
1420f6d57916SPaul Mackerras 	 * We must not reset the combo PHYs, only the BCM5221 found in
1421f6d57916SPaul Mackerras 	 * the iMac G5.
1422f6d57916SPaul Mackerras 	 */
1423f6d57916SPaul Mackerras 	phy = of_get_next_child(node, NULL);
1424f6d57916SPaul Mackerras 	if (!phy)
1425f6d57916SPaul Mackerras 		return -ENODEV;
1426f6d57916SPaul Mackerras 	need_reset = device_is_compatible(phy, "B5221");
1427f6d57916SPaul Mackerras 	of_node_put(phy);
1428f6d57916SPaul Mackerras 	if (!need_reset)
1429f6d57916SPaul Mackerras 		return 0;
1430f6d57916SPaul Mackerras 
1431f6d57916SPaul Mackerras 	/* PHY reset is GPIO 29, not in device-tree unfortunately */
1432f6d57916SPaul Mackerras 	MACIO_OUT8(K2_GPIO_EXTINT_0 + 29,
1433f6d57916SPaul Mackerras 		   KEYLARGO_GPIO_OUTPUT_ENABLE | KEYLARGO_GPIO_OUTOUT_DATA);
1434f6d57916SPaul Mackerras 	/* Thankfully, this is now always called at a time when we can
1435f6d57916SPaul Mackerras 	 * schedule by sungem.
1436f6d57916SPaul Mackerras 	 */
1437f6d57916SPaul Mackerras 	msleep(10);
1438f6d57916SPaul Mackerras 	MACIO_OUT8(K2_GPIO_EXTINT_0 + 29, 0);
1439f6d57916SPaul Mackerras 
1440f6d57916SPaul Mackerras 	return 0;
1441f6d57916SPaul Mackerras }
1442f6d57916SPaul Mackerras 
1443f6d57916SPaul Mackerras static long g5_i2s_enable(struct device_node *node, long param, long value)
1444f6d57916SPaul Mackerras {
1445f6d57916SPaul Mackerras 	/* Very crude implementation for now */
1446f6d57916SPaul Mackerras 	struct macio_chip *macio = &macio_chips[0];
1447f6d57916SPaul Mackerras 	unsigned long flags;
1448*cc5d0189SBenjamin Herrenschmidt 	int cell;
1449*cc5d0189SBenjamin Herrenschmidt 	u32 fcrs[3][3] = {
1450*cc5d0189SBenjamin Herrenschmidt 		{ 0,
1451*cc5d0189SBenjamin Herrenschmidt 		  K2_FCR1_I2S0_CELL_ENABLE |
1452*cc5d0189SBenjamin Herrenschmidt 		  K2_FCR1_I2S0_CLK_ENABLE_BIT | K2_FCR1_I2S0_ENABLE,
1453*cc5d0189SBenjamin Herrenschmidt 		  KL3_I2S0_CLK18_ENABLE
1454*cc5d0189SBenjamin Herrenschmidt 		},
1455*cc5d0189SBenjamin Herrenschmidt 		{ KL0_SCC_A_INTF_ENABLE,
1456*cc5d0189SBenjamin Herrenschmidt 		  K2_FCR1_I2S1_CELL_ENABLE |
1457*cc5d0189SBenjamin Herrenschmidt 		  K2_FCR1_I2S1_CLK_ENABLE_BIT | K2_FCR1_I2S1_ENABLE,
1458*cc5d0189SBenjamin Herrenschmidt 		  KL3_I2S1_CLK18_ENABLE
1459*cc5d0189SBenjamin Herrenschmidt 		},
1460*cc5d0189SBenjamin Herrenschmidt 		{ KL0_SCC_B_INTF_ENABLE,
1461*cc5d0189SBenjamin Herrenschmidt 		  SH_FCR1_I2S2_CELL_ENABLE |
1462*cc5d0189SBenjamin Herrenschmidt 		  SH_FCR1_I2S2_CLK_ENABLE_BIT | SH_FCR1_I2S2_ENABLE,
1463*cc5d0189SBenjamin Herrenschmidt 		  SH_FCR3_I2S2_CLK18_ENABLE
1464*cc5d0189SBenjamin Herrenschmidt 		},
1465*cc5d0189SBenjamin Herrenschmidt 	};
1466f6d57916SPaul Mackerras 
1467*cc5d0189SBenjamin Herrenschmidt 	if (macio->type != macio_keylargo2 /* && macio->type != macio_shasta*/)
1468*cc5d0189SBenjamin Herrenschmidt 		return -ENODEV;
1469*cc5d0189SBenjamin Herrenschmidt 	if (strncmp(node->name, "i2s-", 4))
1470*cc5d0189SBenjamin Herrenschmidt 		return -ENODEV;
1471*cc5d0189SBenjamin Herrenschmidt 	cell = node->name[4] - 'a';
1472*cc5d0189SBenjamin Herrenschmidt 	switch(cell) {
1473*cc5d0189SBenjamin Herrenschmidt 	case 0:
1474*cc5d0189SBenjamin Herrenschmidt 	case 1:
1475*cc5d0189SBenjamin Herrenschmidt 		break;
1476*cc5d0189SBenjamin Herrenschmidt #if 0
1477*cc5d0189SBenjamin Herrenschmidt 	case 2:
1478*cc5d0189SBenjamin Herrenschmidt 		if (macio->type == macio_shasta)
1479*cc5d0189SBenjamin Herrenschmidt 			break;
1480*cc5d0189SBenjamin Herrenschmidt #endif
1481*cc5d0189SBenjamin Herrenschmidt 	default:
1482*cc5d0189SBenjamin Herrenschmidt 		return -ENODEV;
1483*cc5d0189SBenjamin Herrenschmidt 	}
1484f6d57916SPaul Mackerras 
1485f6d57916SPaul Mackerras 	LOCK(flags);
1486*cc5d0189SBenjamin Herrenschmidt 	if (value) {
1487*cc5d0189SBenjamin Herrenschmidt 		MACIO_BIC(KEYLARGO_FCR0, fcrs[cell][0]);
1488*cc5d0189SBenjamin Herrenschmidt 		MACIO_BIS(KEYLARGO_FCR1, fcrs[cell][1]);
1489*cc5d0189SBenjamin Herrenschmidt 		MACIO_BIS(KEYLARGO_FCR3, fcrs[cell][2]);
1490*cc5d0189SBenjamin Herrenschmidt 	} else {
1491*cc5d0189SBenjamin Herrenschmidt 		MACIO_BIC(KEYLARGO_FCR3, fcrs[cell][2]);
1492*cc5d0189SBenjamin Herrenschmidt 		MACIO_BIC(KEYLARGO_FCR1, fcrs[cell][1]);
1493*cc5d0189SBenjamin Herrenschmidt 		MACIO_BIS(KEYLARGO_FCR0, fcrs[cell][0]);
1494*cc5d0189SBenjamin Herrenschmidt 	}
1495f6d57916SPaul Mackerras 	udelay(10);
1496f6d57916SPaul Mackerras 	UNLOCK(flags);
1497f6d57916SPaul Mackerras 
1498f6d57916SPaul Mackerras 	return 0;
1499f6d57916SPaul Mackerras }
1500f6d57916SPaul Mackerras 
1501f6d57916SPaul Mackerras 
1502f6d57916SPaul Mackerras #ifdef CONFIG_SMP
1503f6d57916SPaul Mackerras static long g5_reset_cpu(struct device_node *node, long param, long value)
1504f6d57916SPaul Mackerras {
1505f6d57916SPaul Mackerras 	unsigned int reset_io = 0;
1506f6d57916SPaul Mackerras 	unsigned long flags;
1507f6d57916SPaul Mackerras 	struct macio_chip *macio;
1508f6d57916SPaul Mackerras 	struct device_node *np;
1509f6d57916SPaul Mackerras 
1510f6d57916SPaul Mackerras 	macio = &macio_chips[0];
1511f6d57916SPaul Mackerras 	if (macio->type != macio_keylargo2)
1512f6d57916SPaul Mackerras 		return -ENODEV;
1513f6d57916SPaul Mackerras 
1514f6d57916SPaul Mackerras 	np = find_path_device("/cpus");
1515f6d57916SPaul Mackerras 	if (np == NULL)
1516f6d57916SPaul Mackerras 		return -ENODEV;
1517f6d57916SPaul Mackerras 	for (np = np->child; np != NULL; np = np->sibling) {
1518f6d57916SPaul Mackerras 		u32 *num = (u32 *)get_property(np, "reg", NULL);
1519f6d57916SPaul Mackerras 		u32 *rst = (u32 *)get_property(np, "soft-reset", NULL);
1520f6d57916SPaul Mackerras 		if (num == NULL || rst == NULL)
1521f6d57916SPaul Mackerras 			continue;
1522f6d57916SPaul Mackerras 		if (param == *num) {
1523f6d57916SPaul Mackerras 			reset_io = *rst;
1524f6d57916SPaul Mackerras 			break;
1525f6d57916SPaul Mackerras 		}
1526f6d57916SPaul Mackerras 	}
1527f6d57916SPaul Mackerras 	if (np == NULL || reset_io == 0)
1528f6d57916SPaul Mackerras 		return -ENODEV;
1529f6d57916SPaul Mackerras 
1530f6d57916SPaul Mackerras 	LOCK(flags);
1531f6d57916SPaul Mackerras 	MACIO_OUT8(reset_io, KEYLARGO_GPIO_OUTPUT_ENABLE);
1532f6d57916SPaul Mackerras 	(void)MACIO_IN8(reset_io);
1533f6d57916SPaul Mackerras 	udelay(1);
1534f6d57916SPaul Mackerras 	MACIO_OUT8(reset_io, 0);
1535f6d57916SPaul Mackerras 	(void)MACIO_IN8(reset_io);
1536f6d57916SPaul Mackerras 	UNLOCK(flags);
1537f6d57916SPaul Mackerras 
1538f6d57916SPaul Mackerras 	return 0;
1539f6d57916SPaul Mackerras }
1540f6d57916SPaul Mackerras #endif /* CONFIG_SMP */
1541f6d57916SPaul Mackerras 
1542f6d57916SPaul Mackerras /*
1543f6d57916SPaul Mackerras  * This can be called from pmac_smp so isn't static
1544f6d57916SPaul Mackerras  *
1545f6d57916SPaul Mackerras  * This takes the second CPU off the bus on dual CPU machines
1546f6d57916SPaul Mackerras  * running UP
1547f6d57916SPaul Mackerras  */
1548f6d57916SPaul Mackerras void g5_phy_disable_cpu1(void)
1549f6d57916SPaul Mackerras {
1550f6d57916SPaul Mackerras 	UN_OUT(U3_API_PHY_CONFIG_1, 0);
1551f6d57916SPaul Mackerras }
1552f6d57916SPaul Mackerras #endif /* CONFIG_POWER4 */
1553f6d57916SPaul Mackerras 
1554f6d57916SPaul Mackerras #ifndef CONFIG_POWER4
1555f6d57916SPaul Mackerras 
1556f6d57916SPaul Mackerras static void
1557f6d57916SPaul Mackerras keylargo_shutdown(struct macio_chip *macio, int sleep_mode)
1558f6d57916SPaul Mackerras {
1559f6d57916SPaul Mackerras 	u32 temp;
1560f6d57916SPaul Mackerras 
1561f6d57916SPaul Mackerras 	if (sleep_mode) {
1562f6d57916SPaul Mackerras 		mdelay(1);
1563f6d57916SPaul Mackerras 		MACIO_BIS(KEYLARGO_FCR0, KL0_USB_REF_SUSPEND);
1564f6d57916SPaul Mackerras 		(void)MACIO_IN32(KEYLARGO_FCR0);
1565f6d57916SPaul Mackerras 		mdelay(1);
1566f6d57916SPaul Mackerras 	}
1567f6d57916SPaul Mackerras 
1568f6d57916SPaul Mackerras 	MACIO_BIC(KEYLARGO_FCR0,KL0_SCCA_ENABLE | KL0_SCCB_ENABLE |
1569f6d57916SPaul Mackerras 				KL0_SCC_CELL_ENABLE |
1570f6d57916SPaul Mackerras 				KL0_IRDA_ENABLE | KL0_IRDA_CLK32_ENABLE |
1571f6d57916SPaul Mackerras 				KL0_IRDA_CLK19_ENABLE);
1572f6d57916SPaul Mackerras 
1573f6d57916SPaul Mackerras 	MACIO_BIC(KEYLARGO_MBCR, KL_MBCR_MB0_DEV_MASK);
1574f6d57916SPaul Mackerras 	MACIO_BIS(KEYLARGO_MBCR, KL_MBCR_MB0_IDE_ENABLE);
1575f6d57916SPaul Mackerras 
1576f6d57916SPaul Mackerras 	MACIO_BIC(KEYLARGO_FCR1,
1577f6d57916SPaul Mackerras 		KL1_AUDIO_SEL_22MCLK | KL1_AUDIO_CLK_ENABLE_BIT |
1578f6d57916SPaul Mackerras 		KL1_AUDIO_CLK_OUT_ENABLE | KL1_AUDIO_CELL_ENABLE |
1579f6d57916SPaul Mackerras 		KL1_I2S0_CELL_ENABLE | KL1_I2S0_CLK_ENABLE_BIT |
1580f6d57916SPaul Mackerras 		KL1_I2S0_ENABLE | KL1_I2S1_CELL_ENABLE |
1581f6d57916SPaul Mackerras 		KL1_I2S1_CLK_ENABLE_BIT | KL1_I2S1_ENABLE |
1582f6d57916SPaul Mackerras 		KL1_EIDE0_ENABLE | KL1_EIDE0_RESET_N |
1583f6d57916SPaul Mackerras 		KL1_EIDE1_ENABLE | KL1_EIDE1_RESET_N |
1584f6d57916SPaul Mackerras 		KL1_UIDE_ENABLE);
1585f6d57916SPaul Mackerras 
1586f6d57916SPaul Mackerras 	MACIO_BIS(KEYLARGO_FCR2, KL2_ALT_DATA_OUT);
1587f6d57916SPaul Mackerras 	MACIO_BIC(KEYLARGO_FCR2, KL2_IOBUS_ENABLE);
1588f6d57916SPaul Mackerras 
1589f6d57916SPaul Mackerras 	temp = MACIO_IN32(KEYLARGO_FCR3);
1590f6d57916SPaul Mackerras 	if (macio->rev >= 2) {
1591f6d57916SPaul Mackerras 		temp |= KL3_SHUTDOWN_PLL2X;
1592f6d57916SPaul Mackerras 		if (sleep_mode)
1593f6d57916SPaul Mackerras 			temp |= KL3_SHUTDOWN_PLL_TOTAL;
1594f6d57916SPaul Mackerras 	}
1595f6d57916SPaul Mackerras 
1596f6d57916SPaul Mackerras 	temp |= KL3_SHUTDOWN_PLLKW6 | KL3_SHUTDOWN_PLLKW4 |
1597f6d57916SPaul Mackerras 		KL3_SHUTDOWN_PLLKW35;
1598f6d57916SPaul Mackerras 	if (sleep_mode)
1599f6d57916SPaul Mackerras 		temp |= KL3_SHUTDOWN_PLLKW12;
1600f6d57916SPaul Mackerras 	temp &= ~(KL3_CLK66_ENABLE | KL3_CLK49_ENABLE | KL3_CLK45_ENABLE
1601f6d57916SPaul Mackerras 		| KL3_CLK31_ENABLE | KL3_I2S1_CLK18_ENABLE | KL3_I2S0_CLK18_ENABLE);
1602f6d57916SPaul Mackerras 	if (sleep_mode)
1603f6d57916SPaul Mackerras 		temp &= ~(KL3_TIMER_CLK18_ENABLE | KL3_VIA_CLK16_ENABLE);
1604f6d57916SPaul Mackerras 	MACIO_OUT32(KEYLARGO_FCR3, temp);
1605f6d57916SPaul Mackerras 
1606f6d57916SPaul Mackerras 	/* Flush posted writes & wait a bit */
1607f6d57916SPaul Mackerras 	(void)MACIO_IN32(KEYLARGO_FCR0); mdelay(1);
1608f6d57916SPaul Mackerras }
1609f6d57916SPaul Mackerras 
1610f6d57916SPaul Mackerras static void
1611f6d57916SPaul Mackerras pangea_shutdown(struct macio_chip *macio, int sleep_mode)
1612f6d57916SPaul Mackerras {
1613f6d57916SPaul Mackerras 	u32 temp;
1614f6d57916SPaul Mackerras 
1615f6d57916SPaul Mackerras 	MACIO_BIC(KEYLARGO_FCR0,KL0_SCCA_ENABLE | KL0_SCCB_ENABLE |
1616f6d57916SPaul Mackerras 				KL0_SCC_CELL_ENABLE |
1617f6d57916SPaul Mackerras 				KL0_USB0_CELL_ENABLE | KL0_USB1_CELL_ENABLE);
1618f6d57916SPaul Mackerras 
1619f6d57916SPaul Mackerras 	MACIO_BIC(KEYLARGO_FCR1,
1620f6d57916SPaul Mackerras 		KL1_AUDIO_SEL_22MCLK | KL1_AUDIO_CLK_ENABLE_BIT |
1621f6d57916SPaul Mackerras 		KL1_AUDIO_CLK_OUT_ENABLE | KL1_AUDIO_CELL_ENABLE |
1622f6d57916SPaul Mackerras 		KL1_I2S0_CELL_ENABLE | KL1_I2S0_CLK_ENABLE_BIT |
1623f6d57916SPaul Mackerras 		KL1_I2S0_ENABLE | KL1_I2S1_CELL_ENABLE |
1624f6d57916SPaul Mackerras 		KL1_I2S1_CLK_ENABLE_BIT | KL1_I2S1_ENABLE |
1625f6d57916SPaul Mackerras 		KL1_UIDE_ENABLE);
1626f6d57916SPaul Mackerras 	if (pmac_mb.board_flags & PMAC_MB_MOBILE)
1627f6d57916SPaul Mackerras 		MACIO_BIC(KEYLARGO_FCR1, KL1_UIDE_RESET_N);
1628f6d57916SPaul Mackerras 
1629f6d57916SPaul Mackerras 	MACIO_BIS(KEYLARGO_FCR2, KL2_ALT_DATA_OUT);
1630f6d57916SPaul Mackerras 
1631f6d57916SPaul Mackerras 	temp = MACIO_IN32(KEYLARGO_FCR3);
1632f6d57916SPaul Mackerras 	temp |= KL3_SHUTDOWN_PLLKW6 | KL3_SHUTDOWN_PLLKW4 |
1633f6d57916SPaul Mackerras 		KL3_SHUTDOWN_PLLKW35;
1634f6d57916SPaul Mackerras 	temp &= ~(KL3_CLK49_ENABLE | KL3_CLK45_ENABLE | KL3_CLK31_ENABLE
1635f6d57916SPaul Mackerras 		| KL3_I2S0_CLK18_ENABLE | KL3_I2S1_CLK18_ENABLE);
1636f6d57916SPaul Mackerras 	if (sleep_mode)
1637f6d57916SPaul Mackerras 		temp &= ~(KL3_VIA_CLK16_ENABLE | KL3_TIMER_CLK18_ENABLE);
1638f6d57916SPaul Mackerras 	MACIO_OUT32(KEYLARGO_FCR3, temp);
1639f6d57916SPaul Mackerras 
1640f6d57916SPaul Mackerras 	/* Flush posted writes & wait a bit */
1641f6d57916SPaul Mackerras 	(void)MACIO_IN32(KEYLARGO_FCR0); mdelay(1);
1642f6d57916SPaul Mackerras }
1643f6d57916SPaul Mackerras 
1644f6d57916SPaul Mackerras static void
1645f6d57916SPaul Mackerras intrepid_shutdown(struct macio_chip *macio, int sleep_mode)
1646f6d57916SPaul Mackerras {
1647f6d57916SPaul Mackerras 	u32 temp;
1648f6d57916SPaul Mackerras 
1649f6d57916SPaul Mackerras 	MACIO_BIC(KEYLARGO_FCR0,KL0_SCCA_ENABLE | KL0_SCCB_ENABLE |
1650f6d57916SPaul Mackerras 		  KL0_SCC_CELL_ENABLE);
1651f6d57916SPaul Mackerras 
1652f6d57916SPaul Mackerras 	MACIO_BIC(KEYLARGO_FCR1,
1653f6d57916SPaul Mackerras 		  /*KL1_USB2_CELL_ENABLE |*/
1654f6d57916SPaul Mackerras 		KL1_I2S0_CELL_ENABLE | KL1_I2S0_CLK_ENABLE_BIT |
1655f6d57916SPaul Mackerras 		KL1_I2S0_ENABLE | KL1_I2S1_CELL_ENABLE |
1656f6d57916SPaul Mackerras 		KL1_I2S1_CLK_ENABLE_BIT | KL1_I2S1_ENABLE);
1657f6d57916SPaul Mackerras 	if (pmac_mb.board_flags & PMAC_MB_MOBILE)
1658f6d57916SPaul Mackerras 		MACIO_BIC(KEYLARGO_FCR1, KL1_UIDE_RESET_N);
1659f6d57916SPaul Mackerras 
1660f6d57916SPaul Mackerras 	temp = MACIO_IN32(KEYLARGO_FCR3);
1661f6d57916SPaul Mackerras 	temp &= ~(KL3_CLK49_ENABLE | KL3_CLK45_ENABLE |
1662f6d57916SPaul Mackerras 		  KL3_I2S1_CLK18_ENABLE | KL3_I2S0_CLK18_ENABLE);
1663f6d57916SPaul Mackerras 	if (sleep_mode)
1664f6d57916SPaul Mackerras 		temp &= ~(KL3_TIMER_CLK18_ENABLE | KL3_IT_VIA_CLK32_ENABLE);
1665f6d57916SPaul Mackerras 	MACIO_OUT32(KEYLARGO_FCR3, temp);
1666f6d57916SPaul Mackerras 
1667f6d57916SPaul Mackerras 	/* Flush posted writes & wait a bit */
1668f6d57916SPaul Mackerras 	(void)MACIO_IN32(KEYLARGO_FCR0);
1669f6d57916SPaul Mackerras 	mdelay(10);
1670f6d57916SPaul Mackerras }
1671f6d57916SPaul Mackerras 
1672f6d57916SPaul Mackerras 
1673f6d57916SPaul Mackerras void pmac_tweak_clock_spreading(int enable)
1674f6d57916SPaul Mackerras {
1675f6d57916SPaul Mackerras 	struct macio_chip *macio = &macio_chips[0];
1676f6d57916SPaul Mackerras 
1677f6d57916SPaul Mackerras 	/* Hack for doing clock spreading on some machines PowerBooks and
1678f6d57916SPaul Mackerras 	 * iBooks. This implements the "platform-do-clockspreading" OF
1679f6d57916SPaul Mackerras 	 * property as decoded manually on various models. For safety, we also
1680f6d57916SPaul Mackerras 	 * check the product ID in the device-tree in cases we'll whack the i2c
1681f6d57916SPaul Mackerras 	 * chip to make reasonably sure we won't set wrong values in there
1682f6d57916SPaul Mackerras 	 *
1683f6d57916SPaul Mackerras 	 * Of course, ultimately, we have to implement a real parser for
1684f6d57916SPaul Mackerras 	 * the platform-do-* stuff...
1685f6d57916SPaul Mackerras 	 */
1686f6d57916SPaul Mackerras 
1687f6d57916SPaul Mackerras 	if (macio->type == macio_intrepid) {
1688b39f9485SBenjamin Herrenschmidt 		struct device_node *clock =
1689b39f9485SBenjamin Herrenschmidt 			of_find_node_by_path("/uni-n@f8000000/hw-clock");
1690b39f9485SBenjamin Herrenschmidt 		if (clock && get_property(clock, "platform-do-clockspreading",
1691b39f9485SBenjamin Herrenschmidt 					  NULL)) {
1692b39f9485SBenjamin Herrenschmidt 			printk(KERN_INFO "%sabling clock spreading on Intrepid"
1693b39f9485SBenjamin Herrenschmidt 			       " ASIC\n", enable ? "En" : "Dis");
1694f6d57916SPaul Mackerras 			if (enable)
1695f6d57916SPaul Mackerras 				UN_OUT(UNI_N_CLOCK_SPREADING, 2);
1696f6d57916SPaul Mackerras 			else
1697f6d57916SPaul Mackerras 				UN_OUT(UNI_N_CLOCK_SPREADING, 0);
1698f6d57916SPaul Mackerras 			mdelay(40);
1699f6d57916SPaul Mackerras 		}
1700b39f9485SBenjamin Herrenschmidt 		of_node_put(clock);
1701b39f9485SBenjamin Herrenschmidt 	}
1702f6d57916SPaul Mackerras 
1703f6d57916SPaul Mackerras 	while (machine_is_compatible("PowerBook5,2") ||
1704f6d57916SPaul Mackerras 	       machine_is_compatible("PowerBook5,3") ||
1705f6d57916SPaul Mackerras 	       machine_is_compatible("PowerBook6,2") ||
1706f6d57916SPaul Mackerras 	       machine_is_compatible("PowerBook6,3")) {
1707f6d57916SPaul Mackerras 		struct device_node *ui2c = of_find_node_by_type(NULL, "i2c");
1708f6d57916SPaul Mackerras 		struct device_node *dt = of_find_node_by_name(NULL, "device-tree");
1709f6d57916SPaul Mackerras 		u8 buffer[9];
1710f6d57916SPaul Mackerras 		u32 *productID;
1711f6d57916SPaul Mackerras 		int i, rc, changed = 0;
1712f6d57916SPaul Mackerras 
1713f6d57916SPaul Mackerras 		if (dt == NULL)
1714f6d57916SPaul Mackerras 			break;
1715f6d57916SPaul Mackerras 		productID = (u32 *)get_property(dt, "pid#", NULL);
1716f6d57916SPaul Mackerras 		if (productID == NULL)
1717f6d57916SPaul Mackerras 			break;
1718f6d57916SPaul Mackerras 		while(ui2c) {
1719f6d57916SPaul Mackerras 			struct device_node *p = of_get_parent(ui2c);
1720f6d57916SPaul Mackerras 			if (p && !strcmp(p->name, "uni-n"))
1721f6d57916SPaul Mackerras 				break;
1722f6d57916SPaul Mackerras 			ui2c = of_find_node_by_type(ui2c, "i2c");
1723f6d57916SPaul Mackerras 		}
1724f6d57916SPaul Mackerras 		if (ui2c == NULL)
1725f6d57916SPaul Mackerras 			break;
1726f6d57916SPaul Mackerras 		DBG("Trying to bump clock speed for PID: %08x...\n", *productID);
1727f6d57916SPaul Mackerras 		rc = pmac_low_i2c_open(ui2c, 1);
1728f6d57916SPaul Mackerras 		if (rc != 0)
1729f6d57916SPaul Mackerras 			break;
1730f6d57916SPaul Mackerras 		pmac_low_i2c_setmode(ui2c, pmac_low_i2c_mode_combined);
1731f6d57916SPaul Mackerras 		rc = pmac_low_i2c_xfer(ui2c, 0xd2 | pmac_low_i2c_read, 0x80, buffer, 9);
1732f6d57916SPaul Mackerras 		DBG("read result: %d,", rc);
1733f6d57916SPaul Mackerras 		if (rc != 0) {
1734f6d57916SPaul Mackerras 			pmac_low_i2c_close(ui2c);
1735f6d57916SPaul Mackerras 			break;
1736f6d57916SPaul Mackerras 		}
1737f6d57916SPaul Mackerras 		for (i=0; i<9; i++)
1738f6d57916SPaul Mackerras 			DBG(" %02x", buffer[i]);
1739f6d57916SPaul Mackerras 		DBG("\n");
1740f6d57916SPaul Mackerras 
1741f6d57916SPaul Mackerras 		switch(*productID) {
1742f6d57916SPaul Mackerras 		case 0x1182:	/* AlBook 12" rev 2 */
1743f6d57916SPaul Mackerras 		case 0x1183:	/* iBook G4 12" */
1744f6d57916SPaul Mackerras 			buffer[0] = (buffer[0] & 0x8f) | 0x70;
1745f6d57916SPaul Mackerras 			buffer[2] = (buffer[2] & 0x7f) | 0x00;
1746f6d57916SPaul Mackerras 			buffer[5] = (buffer[5] & 0x80) | 0x31;
1747f6d57916SPaul Mackerras 			buffer[6] = (buffer[6] & 0x40) | 0xb0;
1748f6d57916SPaul Mackerras 			buffer[7] = (buffer[7] & 0x00) | (enable ? 0xc0 : 0xba);
1749f6d57916SPaul Mackerras 			buffer[8] = (buffer[8] & 0x00) | 0x30;
1750f6d57916SPaul Mackerras 			changed = 1;
1751f6d57916SPaul Mackerras 			break;
1752f6d57916SPaul Mackerras 		case 0x3142:	/* AlBook 15" (ATI M10) */
1753f6d57916SPaul Mackerras 		case 0x3143:	/* AlBook 17" (ATI M10) */
1754f6d57916SPaul Mackerras 			buffer[0] = (buffer[0] & 0xaf) | 0x50;
1755f6d57916SPaul Mackerras 			buffer[2] = (buffer[2] & 0x7f) | 0x00;
1756f6d57916SPaul Mackerras 			buffer[5] = (buffer[5] & 0x80) | 0x31;
1757f6d57916SPaul Mackerras 			buffer[6] = (buffer[6] & 0x40) | 0xb0;
1758f6d57916SPaul Mackerras 			buffer[7] = (buffer[7] & 0x00) | (enable ? 0xd0 : 0xc0);
1759f6d57916SPaul Mackerras 			buffer[8] = (buffer[8] & 0x00) | 0x30;
1760f6d57916SPaul Mackerras 			changed = 1;
1761f6d57916SPaul Mackerras 			break;
1762f6d57916SPaul Mackerras 		default:
1763f6d57916SPaul Mackerras 			DBG("i2c-hwclock: Machine model not handled\n");
1764f6d57916SPaul Mackerras 			break;
1765f6d57916SPaul Mackerras 		}
1766f6d57916SPaul Mackerras 		if (!changed) {
1767f6d57916SPaul Mackerras 			pmac_low_i2c_close(ui2c);
1768f6d57916SPaul Mackerras 			break;
1769f6d57916SPaul Mackerras 		}
1770b39f9485SBenjamin Herrenschmidt 		printk(KERN_INFO "%sabling clock spreading on i2c clock chip\n",
1771b39f9485SBenjamin Herrenschmidt 		       enable ? "En" : "Dis");
1772b39f9485SBenjamin Herrenschmidt 
1773f6d57916SPaul Mackerras 		pmac_low_i2c_setmode(ui2c, pmac_low_i2c_mode_stdsub);
1774f6d57916SPaul Mackerras 		rc = pmac_low_i2c_xfer(ui2c, 0xd2 | pmac_low_i2c_write, 0x80, buffer, 9);
1775f6d57916SPaul Mackerras 		DBG("write result: %d,", rc);
1776f6d57916SPaul Mackerras 		pmac_low_i2c_setmode(ui2c, pmac_low_i2c_mode_combined);
1777f6d57916SPaul Mackerras 		rc = pmac_low_i2c_xfer(ui2c, 0xd2 | pmac_low_i2c_read, 0x80, buffer, 9);
1778f6d57916SPaul Mackerras 		DBG("read result: %d,", rc);
1779f6d57916SPaul Mackerras 		if (rc != 0) {
1780f6d57916SPaul Mackerras 			pmac_low_i2c_close(ui2c);
1781f6d57916SPaul Mackerras 			break;
1782f6d57916SPaul Mackerras 		}
1783f6d57916SPaul Mackerras 		for (i=0; i<9; i++)
1784f6d57916SPaul Mackerras 			DBG(" %02x", buffer[i]);
1785f6d57916SPaul Mackerras 		pmac_low_i2c_close(ui2c);
1786f6d57916SPaul Mackerras 		break;
1787f6d57916SPaul Mackerras 	}
1788f6d57916SPaul Mackerras }
1789f6d57916SPaul Mackerras 
1790f6d57916SPaul Mackerras 
1791f6d57916SPaul Mackerras static int
1792f6d57916SPaul Mackerras core99_sleep(void)
1793f6d57916SPaul Mackerras {
1794f6d57916SPaul Mackerras 	struct macio_chip *macio;
1795f6d57916SPaul Mackerras 	int i;
1796f6d57916SPaul Mackerras 
1797f6d57916SPaul Mackerras 	macio = &macio_chips[0];
1798f6d57916SPaul Mackerras 	if (macio->type != macio_keylargo && macio->type != macio_pangea &&
1799f6d57916SPaul Mackerras 	    macio->type != macio_intrepid)
1800f6d57916SPaul Mackerras 		return -ENODEV;
1801f6d57916SPaul Mackerras 
1802f6d57916SPaul Mackerras 	/* We power off the wireless slot in case it was not done
1803f6d57916SPaul Mackerras 	 * by the driver. We don't power it on automatically however
1804f6d57916SPaul Mackerras 	 */
1805f6d57916SPaul Mackerras 	if (macio->flags & MACIO_FLAG_AIRPORT_ON)
1806f6d57916SPaul Mackerras 		core99_airport_enable(macio->of_node, 0, 0);
1807f6d57916SPaul Mackerras 
1808f6d57916SPaul Mackerras 	/* We power off the FW cable. Should be done by the driver... */
1809f6d57916SPaul Mackerras 	if (macio->flags & MACIO_FLAG_FW_SUPPORTED) {
1810f6d57916SPaul Mackerras 		core99_firewire_enable(NULL, 0, 0);
1811f6d57916SPaul Mackerras 		core99_firewire_cable_power(NULL, 0, 0);
1812f6d57916SPaul Mackerras 	}
1813f6d57916SPaul Mackerras 
1814f6d57916SPaul Mackerras 	/* We make sure int. modem is off (in case driver lost it) */
1815f6d57916SPaul Mackerras 	if (macio->type == macio_keylargo)
1816f6d57916SPaul Mackerras 		core99_modem_enable(macio->of_node, 0, 0);
1817f6d57916SPaul Mackerras 	else
1818f6d57916SPaul Mackerras 		pangea_modem_enable(macio->of_node, 0, 0);
1819f6d57916SPaul Mackerras 
1820f6d57916SPaul Mackerras 	/* We make sure the sound is off as well */
1821f6d57916SPaul Mackerras 	core99_sound_chip_enable(macio->of_node, 0, 0);
1822f6d57916SPaul Mackerras 
1823f6d57916SPaul Mackerras 	/*
1824f6d57916SPaul Mackerras 	 * Save various bits of KeyLargo
1825f6d57916SPaul Mackerras 	 */
1826f6d57916SPaul Mackerras 
1827f6d57916SPaul Mackerras 	/* Save the state of the various GPIOs */
1828f6d57916SPaul Mackerras 	save_gpio_levels[0] = MACIO_IN32(KEYLARGO_GPIO_LEVELS0);
1829f6d57916SPaul Mackerras 	save_gpio_levels[1] = MACIO_IN32(KEYLARGO_GPIO_LEVELS1);
1830f6d57916SPaul Mackerras 	for (i=0; i<KEYLARGO_GPIO_EXTINT_CNT; i++)
1831f6d57916SPaul Mackerras 		save_gpio_extint[i] = MACIO_IN8(KEYLARGO_GPIO_EXTINT_0+i);
1832f6d57916SPaul Mackerras 	for (i=0; i<KEYLARGO_GPIO_CNT; i++)
1833f6d57916SPaul Mackerras 		save_gpio_normal[i] = MACIO_IN8(KEYLARGO_GPIO_0+i);
1834f6d57916SPaul Mackerras 
1835f6d57916SPaul Mackerras 	/* Save the FCRs */
1836f6d57916SPaul Mackerras 	if (macio->type == macio_keylargo)
1837f6d57916SPaul Mackerras 		save_mbcr = MACIO_IN32(KEYLARGO_MBCR);
1838f6d57916SPaul Mackerras 	save_fcr[0] = MACIO_IN32(KEYLARGO_FCR0);
1839f6d57916SPaul Mackerras 	save_fcr[1] = MACIO_IN32(KEYLARGO_FCR1);
1840f6d57916SPaul Mackerras 	save_fcr[2] = MACIO_IN32(KEYLARGO_FCR2);
1841f6d57916SPaul Mackerras 	save_fcr[3] = MACIO_IN32(KEYLARGO_FCR3);
1842f6d57916SPaul Mackerras 	save_fcr[4] = MACIO_IN32(KEYLARGO_FCR4);
1843f6d57916SPaul Mackerras 	if (macio->type == macio_pangea || macio->type == macio_intrepid)
1844f6d57916SPaul Mackerras 		save_fcr[5] = MACIO_IN32(KEYLARGO_FCR5);
1845f6d57916SPaul Mackerras 
1846f6d57916SPaul Mackerras 	/* Save state & config of DBDMA channels */
1847f6d57916SPaul Mackerras 	dbdma_save(macio, save_dbdma);
1848f6d57916SPaul Mackerras 
1849f6d57916SPaul Mackerras 	/*
1850f6d57916SPaul Mackerras 	 * Turn off as much as we can
1851f6d57916SPaul Mackerras 	 */
1852f6d57916SPaul Mackerras 	if (macio->type == macio_pangea)
1853f6d57916SPaul Mackerras 		pangea_shutdown(macio, 1);
1854f6d57916SPaul Mackerras 	else if (macio->type == macio_intrepid)
1855f6d57916SPaul Mackerras 		intrepid_shutdown(macio, 1);
1856f6d57916SPaul Mackerras 	else if (macio->type == macio_keylargo)
1857f6d57916SPaul Mackerras 		keylargo_shutdown(macio, 1);
1858f6d57916SPaul Mackerras 
1859f6d57916SPaul Mackerras 	/*
1860f6d57916SPaul Mackerras 	 * Put the host bridge to sleep
1861f6d57916SPaul Mackerras 	 */
1862f6d57916SPaul Mackerras 
1863f6d57916SPaul Mackerras 	save_unin_clock_ctl = UN_IN(UNI_N_CLOCK_CNTL);
1864f6d57916SPaul Mackerras 	/* Note: do not switch GMAC off, driver does it when necessary, WOL must keep it
1865f6d57916SPaul Mackerras 	 * enabled !
1866f6d57916SPaul Mackerras 	 */
1867f6d57916SPaul Mackerras 	UN_OUT(UNI_N_CLOCK_CNTL, save_unin_clock_ctl &
1868f6d57916SPaul Mackerras 	       ~(/*UNI_N_CLOCK_CNTL_GMAC|*/UNI_N_CLOCK_CNTL_FW/*|UNI_N_CLOCK_CNTL_PCI*/));
1869f6d57916SPaul Mackerras 	udelay(100);
1870f6d57916SPaul Mackerras 	UN_OUT(UNI_N_HWINIT_STATE, UNI_N_HWINIT_STATE_SLEEPING);
1871f6d57916SPaul Mackerras 	UN_OUT(UNI_N_POWER_MGT, UNI_N_POWER_MGT_SLEEP);
1872f6d57916SPaul Mackerras 	mdelay(10);
1873f6d57916SPaul Mackerras 
1874f6d57916SPaul Mackerras 	/*
1875f6d57916SPaul Mackerras 	 * FIXME: A bit of black magic with OpenPIC (don't ask me why)
1876f6d57916SPaul Mackerras 	 */
1877f6d57916SPaul Mackerras 	if (pmac_mb.model_id == PMAC_TYPE_SAWTOOTH) {
1878f6d57916SPaul Mackerras 		MACIO_BIS(0x506e0, 0x00400000);
1879f6d57916SPaul Mackerras 		MACIO_BIS(0x506e0, 0x80000000);
1880f6d57916SPaul Mackerras 	}
1881f6d57916SPaul Mackerras 	return 0;
1882f6d57916SPaul Mackerras }
1883f6d57916SPaul Mackerras 
1884f6d57916SPaul Mackerras static int
1885f6d57916SPaul Mackerras core99_wake_up(void)
1886f6d57916SPaul Mackerras {
1887f6d57916SPaul Mackerras 	struct macio_chip *macio;
1888f6d57916SPaul Mackerras 	int i;
1889f6d57916SPaul Mackerras 
1890f6d57916SPaul Mackerras 	macio = &macio_chips[0];
1891f6d57916SPaul Mackerras 	if (macio->type != macio_keylargo && macio->type != macio_pangea &&
1892f6d57916SPaul Mackerras 	    macio->type != macio_intrepid)
1893f6d57916SPaul Mackerras 		return -ENODEV;
1894f6d57916SPaul Mackerras 
1895f6d57916SPaul Mackerras 	/*
1896f6d57916SPaul Mackerras 	 * Wakeup the host bridge
1897f6d57916SPaul Mackerras 	 */
1898f6d57916SPaul Mackerras 	UN_OUT(UNI_N_POWER_MGT, UNI_N_POWER_MGT_NORMAL);
1899f6d57916SPaul Mackerras 	udelay(10);
1900f6d57916SPaul Mackerras 	UN_OUT(UNI_N_HWINIT_STATE, UNI_N_HWINIT_STATE_RUNNING);
1901f6d57916SPaul Mackerras 	udelay(10);
1902f6d57916SPaul Mackerras 
1903f6d57916SPaul Mackerras 	/*
1904f6d57916SPaul Mackerras 	 * Restore KeyLargo
1905f6d57916SPaul Mackerras 	 */
1906f6d57916SPaul Mackerras 
1907f6d57916SPaul Mackerras 	if (macio->type == macio_keylargo) {
1908f6d57916SPaul Mackerras 		MACIO_OUT32(KEYLARGO_MBCR, save_mbcr);
1909f6d57916SPaul Mackerras 		(void)MACIO_IN32(KEYLARGO_MBCR); udelay(10);
1910f6d57916SPaul Mackerras 	}
1911f6d57916SPaul Mackerras 	MACIO_OUT32(KEYLARGO_FCR0, save_fcr[0]);
1912f6d57916SPaul Mackerras 	(void)MACIO_IN32(KEYLARGO_FCR0); udelay(10);
1913f6d57916SPaul Mackerras 	MACIO_OUT32(KEYLARGO_FCR1, save_fcr[1]);
1914f6d57916SPaul Mackerras 	(void)MACIO_IN32(KEYLARGO_FCR1); udelay(10);
1915f6d57916SPaul Mackerras 	MACIO_OUT32(KEYLARGO_FCR2, save_fcr[2]);
1916f6d57916SPaul Mackerras 	(void)MACIO_IN32(KEYLARGO_FCR2); udelay(10);
1917f6d57916SPaul Mackerras 	MACIO_OUT32(KEYLARGO_FCR3, save_fcr[3]);
1918f6d57916SPaul Mackerras 	(void)MACIO_IN32(KEYLARGO_FCR3); udelay(10);
1919f6d57916SPaul Mackerras 	MACIO_OUT32(KEYLARGO_FCR4, save_fcr[4]);
1920f6d57916SPaul Mackerras 	(void)MACIO_IN32(KEYLARGO_FCR4); udelay(10);
1921f6d57916SPaul Mackerras 	if (macio->type == macio_pangea || macio->type == macio_intrepid) {
1922f6d57916SPaul Mackerras 		MACIO_OUT32(KEYLARGO_FCR5, save_fcr[5]);
1923f6d57916SPaul Mackerras 		(void)MACIO_IN32(KEYLARGO_FCR5); udelay(10);
1924f6d57916SPaul Mackerras 	}
1925f6d57916SPaul Mackerras 
1926f6d57916SPaul Mackerras 	dbdma_restore(macio, save_dbdma);
1927f6d57916SPaul Mackerras 
1928f6d57916SPaul Mackerras 	MACIO_OUT32(KEYLARGO_GPIO_LEVELS0, save_gpio_levels[0]);
1929f6d57916SPaul Mackerras 	MACIO_OUT32(KEYLARGO_GPIO_LEVELS1, save_gpio_levels[1]);
1930f6d57916SPaul Mackerras 	for (i=0; i<KEYLARGO_GPIO_EXTINT_CNT; i++)
1931f6d57916SPaul Mackerras 		MACIO_OUT8(KEYLARGO_GPIO_EXTINT_0+i, save_gpio_extint[i]);
1932f6d57916SPaul Mackerras 	for (i=0; i<KEYLARGO_GPIO_CNT; i++)
1933f6d57916SPaul Mackerras 		MACIO_OUT8(KEYLARGO_GPIO_0+i, save_gpio_normal[i]);
1934f6d57916SPaul Mackerras 
1935f6d57916SPaul Mackerras 	/* FIXME more black magic with OpenPIC ... */
1936f6d57916SPaul Mackerras 	if (pmac_mb.model_id == PMAC_TYPE_SAWTOOTH) {
1937f6d57916SPaul Mackerras 		MACIO_BIC(0x506e0, 0x00400000);
1938f6d57916SPaul Mackerras 		MACIO_BIC(0x506e0, 0x80000000);
1939f6d57916SPaul Mackerras 	}
1940f6d57916SPaul Mackerras 
1941f6d57916SPaul Mackerras 	UN_OUT(UNI_N_CLOCK_CNTL, save_unin_clock_ctl);
1942f6d57916SPaul Mackerras 	udelay(100);
1943f6d57916SPaul Mackerras 
1944f6d57916SPaul Mackerras 	return 0;
1945f6d57916SPaul Mackerras }
1946f6d57916SPaul Mackerras 
1947f6d57916SPaul Mackerras static long
1948f6d57916SPaul Mackerras core99_sleep_state(struct device_node *node, long param, long value)
1949f6d57916SPaul Mackerras {
1950f6d57916SPaul Mackerras 	/* Param == 1 means to enter the "fake sleep" mode that is
1951f6d57916SPaul Mackerras 	 * used for CPU speed switch
1952f6d57916SPaul Mackerras 	 */
1953f6d57916SPaul Mackerras 	if (param == 1) {
1954f6d57916SPaul Mackerras 		if (value == 1) {
1955f6d57916SPaul Mackerras 			UN_OUT(UNI_N_HWINIT_STATE, UNI_N_HWINIT_STATE_SLEEPING);
1956f6d57916SPaul Mackerras 			UN_OUT(UNI_N_POWER_MGT, UNI_N_POWER_MGT_IDLE2);
1957f6d57916SPaul Mackerras 		} else {
1958f6d57916SPaul Mackerras 			UN_OUT(UNI_N_POWER_MGT, UNI_N_POWER_MGT_NORMAL);
1959f6d57916SPaul Mackerras 			udelay(10);
1960f6d57916SPaul Mackerras 			UN_OUT(UNI_N_HWINIT_STATE, UNI_N_HWINIT_STATE_RUNNING);
1961f6d57916SPaul Mackerras 			udelay(10);
1962f6d57916SPaul Mackerras 		}
1963f6d57916SPaul Mackerras 		return 0;
1964f6d57916SPaul Mackerras 	}
1965f6d57916SPaul Mackerras 	if ((pmac_mb.board_flags & PMAC_MB_CAN_SLEEP) == 0)
1966f6d57916SPaul Mackerras 		return -EPERM;
1967f6d57916SPaul Mackerras 
1968f6d57916SPaul Mackerras 	if (value == 1)
1969f6d57916SPaul Mackerras 		return core99_sleep();
1970f6d57916SPaul Mackerras 	else if (value == 0)
1971f6d57916SPaul Mackerras 		return core99_wake_up();
1972f6d57916SPaul Mackerras 	return 0;
1973f6d57916SPaul Mackerras }
1974f6d57916SPaul Mackerras 
1975f6d57916SPaul Mackerras #endif /* CONFIG_POWER4 */
1976f6d57916SPaul Mackerras 
1977f6d57916SPaul Mackerras static long
1978f6d57916SPaul Mackerras generic_dev_can_wake(struct device_node *node, long param, long value)
1979f6d57916SPaul Mackerras {
1980f6d57916SPaul Mackerras 	/* Todo: eventually check we are really dealing with on-board
1981f6d57916SPaul Mackerras 	 * video device ...
1982f6d57916SPaul Mackerras 	 */
1983f6d57916SPaul Mackerras 
1984f6d57916SPaul Mackerras 	if (pmac_mb.board_flags & PMAC_MB_MAY_SLEEP)
1985f6d57916SPaul Mackerras 		pmac_mb.board_flags |= PMAC_MB_CAN_SLEEP;
1986f6d57916SPaul Mackerras 	return 0;
1987f6d57916SPaul Mackerras }
1988f6d57916SPaul Mackerras 
1989f6d57916SPaul Mackerras static long generic_get_mb_info(struct device_node *node, long param, long value)
1990f6d57916SPaul Mackerras {
1991f6d57916SPaul Mackerras 	switch(param) {
1992f6d57916SPaul Mackerras 		case PMAC_MB_INFO_MODEL:
1993f6d57916SPaul Mackerras 			return pmac_mb.model_id;
1994f6d57916SPaul Mackerras 		case PMAC_MB_INFO_FLAGS:
1995f6d57916SPaul Mackerras 			return pmac_mb.board_flags;
1996f6d57916SPaul Mackerras 		case PMAC_MB_INFO_NAME:
1997f6d57916SPaul Mackerras 			/* hack hack hack... but should work */
1998f6d57916SPaul Mackerras 			*((const char **)value) = pmac_mb.model_name;
1999f6d57916SPaul Mackerras 			return 0;
2000f6d57916SPaul Mackerras 	}
2001f6d57916SPaul Mackerras 	return -EINVAL;
2002f6d57916SPaul Mackerras }
2003f6d57916SPaul Mackerras 
2004f6d57916SPaul Mackerras 
2005f6d57916SPaul Mackerras /*
2006f6d57916SPaul Mackerras  * Table definitions
2007f6d57916SPaul Mackerras  */
2008f6d57916SPaul Mackerras 
2009f6d57916SPaul Mackerras /* Used on any machine
2010f6d57916SPaul Mackerras  */
2011f6d57916SPaul Mackerras static struct feature_table_entry any_features[] = {
2012f6d57916SPaul Mackerras 	{ PMAC_FTR_GET_MB_INFO,		generic_get_mb_info },
2013f6d57916SPaul Mackerras 	{ PMAC_FTR_DEVICE_CAN_WAKE,	generic_dev_can_wake },
2014f6d57916SPaul Mackerras 	{ 0, NULL }
2015f6d57916SPaul Mackerras };
2016f6d57916SPaul Mackerras 
2017f6d57916SPaul Mackerras #ifndef CONFIG_POWER4
2018f6d57916SPaul Mackerras 
2019f6d57916SPaul Mackerras /* OHare based motherboards. Currently, we only use these on the
2020f6d57916SPaul Mackerras  * 2400,3400 and 3500 series powerbooks. Some older desktops seem
2021f6d57916SPaul Mackerras  * to have issues with turning on/off those asic cells
2022f6d57916SPaul Mackerras  */
2023f6d57916SPaul Mackerras static struct feature_table_entry ohare_features[] = {
2024f6d57916SPaul Mackerras 	{ PMAC_FTR_SCC_ENABLE,		ohare_htw_scc_enable },
2025f6d57916SPaul Mackerras 	{ PMAC_FTR_SWIM3_ENABLE,	ohare_floppy_enable },
2026f6d57916SPaul Mackerras 	{ PMAC_FTR_MESH_ENABLE,		ohare_mesh_enable },
2027f6d57916SPaul Mackerras 	{ PMAC_FTR_IDE_ENABLE,		ohare_ide_enable},
2028f6d57916SPaul Mackerras 	{ PMAC_FTR_IDE_RESET,		ohare_ide_reset},
2029f6d57916SPaul Mackerras 	{ PMAC_FTR_SLEEP_STATE,		ohare_sleep_state },
2030f6d57916SPaul Mackerras 	{ 0, NULL }
2031f6d57916SPaul Mackerras };
2032f6d57916SPaul Mackerras 
2033f6d57916SPaul Mackerras /* Heathrow desktop machines (Beige G3).
2034f6d57916SPaul Mackerras  * Separated as some features couldn't be properly tested
2035f6d57916SPaul Mackerras  * and the serial port control bits appear to confuse it.
2036f6d57916SPaul Mackerras  */
2037f6d57916SPaul Mackerras static struct feature_table_entry heathrow_desktop_features[] = {
2038f6d57916SPaul Mackerras 	{ PMAC_FTR_SWIM3_ENABLE,	heathrow_floppy_enable },
2039f6d57916SPaul Mackerras 	{ PMAC_FTR_MESH_ENABLE,		heathrow_mesh_enable },
2040f6d57916SPaul Mackerras 	{ PMAC_FTR_IDE_ENABLE,		heathrow_ide_enable },
2041f6d57916SPaul Mackerras 	{ PMAC_FTR_IDE_RESET,		heathrow_ide_reset },
2042f6d57916SPaul Mackerras 	{ PMAC_FTR_BMAC_ENABLE,		heathrow_bmac_enable },
2043f6d57916SPaul Mackerras 	{ 0, NULL }
2044f6d57916SPaul Mackerras };
2045f6d57916SPaul Mackerras 
2046f6d57916SPaul Mackerras /* Heathrow based laptop, that is the Wallstreet and mainstreet
2047f6d57916SPaul Mackerras  * powerbooks.
2048f6d57916SPaul Mackerras  */
2049f6d57916SPaul Mackerras static struct feature_table_entry heathrow_laptop_features[] = {
2050f6d57916SPaul Mackerras 	{ PMAC_FTR_SCC_ENABLE,		ohare_htw_scc_enable },
2051f6d57916SPaul Mackerras 	{ PMAC_FTR_MODEM_ENABLE,	heathrow_modem_enable },
2052f6d57916SPaul Mackerras 	{ PMAC_FTR_SWIM3_ENABLE,	heathrow_floppy_enable },
2053f6d57916SPaul Mackerras 	{ PMAC_FTR_MESH_ENABLE,		heathrow_mesh_enable },
2054f6d57916SPaul Mackerras 	{ PMAC_FTR_IDE_ENABLE,		heathrow_ide_enable },
2055f6d57916SPaul Mackerras 	{ PMAC_FTR_IDE_RESET,		heathrow_ide_reset },
2056f6d57916SPaul Mackerras 	{ PMAC_FTR_BMAC_ENABLE,		heathrow_bmac_enable },
2057f6d57916SPaul Mackerras 	{ PMAC_FTR_SOUND_CHIP_ENABLE,	heathrow_sound_enable },
2058f6d57916SPaul Mackerras 	{ PMAC_FTR_SLEEP_STATE,		heathrow_sleep_state },
2059f6d57916SPaul Mackerras 	{ 0, NULL }
2060f6d57916SPaul Mackerras };
2061f6d57916SPaul Mackerras 
2062f6d57916SPaul Mackerras /* Paddington based machines
2063f6d57916SPaul Mackerras  * The lombard (101) powerbook, first iMac models, B&W G3 and Yikes G4.
2064f6d57916SPaul Mackerras  */
2065f6d57916SPaul Mackerras static struct feature_table_entry paddington_features[] = {
2066f6d57916SPaul Mackerras 	{ PMAC_FTR_SCC_ENABLE,		ohare_htw_scc_enable },
2067f6d57916SPaul Mackerras 	{ PMAC_FTR_MODEM_ENABLE,	heathrow_modem_enable },
2068f6d57916SPaul Mackerras 	{ PMAC_FTR_SWIM3_ENABLE,	heathrow_floppy_enable },
2069f6d57916SPaul Mackerras 	{ PMAC_FTR_MESH_ENABLE,		heathrow_mesh_enable },
2070f6d57916SPaul Mackerras 	{ PMAC_FTR_IDE_ENABLE,		heathrow_ide_enable },
2071f6d57916SPaul Mackerras 	{ PMAC_FTR_IDE_RESET,		heathrow_ide_reset },
2072f6d57916SPaul Mackerras 	{ PMAC_FTR_BMAC_ENABLE,		heathrow_bmac_enable },
2073f6d57916SPaul Mackerras 	{ PMAC_FTR_SOUND_CHIP_ENABLE,	heathrow_sound_enable },
2074f6d57916SPaul Mackerras 	{ PMAC_FTR_SLEEP_STATE,		heathrow_sleep_state },
2075f6d57916SPaul Mackerras 	{ 0, NULL }
2076f6d57916SPaul Mackerras };
2077f6d57916SPaul Mackerras 
2078f6d57916SPaul Mackerras /* Core99 & MacRISC 2 machines (all machines released since the
2079f6d57916SPaul Mackerras  * iBook (included), that is all AGP machines, except pangea
2080f6d57916SPaul Mackerras  * chipset. The pangea chipset is the "combo" UniNorth/KeyLargo
2081f6d57916SPaul Mackerras  * used on iBook2 & iMac "flow power".
2082f6d57916SPaul Mackerras  */
2083f6d57916SPaul Mackerras static struct feature_table_entry core99_features[] = {
2084f6d57916SPaul Mackerras 	{ PMAC_FTR_SCC_ENABLE,		core99_scc_enable },
2085f6d57916SPaul Mackerras 	{ PMAC_FTR_MODEM_ENABLE,	core99_modem_enable },
2086f6d57916SPaul Mackerras 	{ PMAC_FTR_IDE_ENABLE,		core99_ide_enable },
2087f6d57916SPaul Mackerras 	{ PMAC_FTR_IDE_RESET,		core99_ide_reset },
2088f6d57916SPaul Mackerras 	{ PMAC_FTR_GMAC_ENABLE,		core99_gmac_enable },
2089f6d57916SPaul Mackerras 	{ PMAC_FTR_GMAC_PHY_RESET,	core99_gmac_phy_reset },
2090f6d57916SPaul Mackerras 	{ PMAC_FTR_SOUND_CHIP_ENABLE,	core99_sound_chip_enable },
2091f6d57916SPaul Mackerras 	{ PMAC_FTR_AIRPORT_ENABLE,	core99_airport_enable },
2092f6d57916SPaul Mackerras 	{ PMAC_FTR_USB_ENABLE,		core99_usb_enable },
2093f6d57916SPaul Mackerras 	{ PMAC_FTR_1394_ENABLE,		core99_firewire_enable },
2094f6d57916SPaul Mackerras 	{ PMAC_FTR_1394_CABLE_POWER,	core99_firewire_cable_power },
2095f6d57916SPaul Mackerras 	{ PMAC_FTR_SLEEP_STATE,		core99_sleep_state },
2096f6d57916SPaul Mackerras #ifdef CONFIG_SMP
2097f6d57916SPaul Mackerras 	{ PMAC_FTR_RESET_CPU,		core99_reset_cpu },
2098f6d57916SPaul Mackerras #endif /* CONFIG_SMP */
2099f6d57916SPaul Mackerras 	{ PMAC_FTR_READ_GPIO,		core99_read_gpio },
2100f6d57916SPaul Mackerras 	{ PMAC_FTR_WRITE_GPIO,		core99_write_gpio },
2101f6d57916SPaul Mackerras 	{ 0, NULL }
2102f6d57916SPaul Mackerras };
2103f6d57916SPaul Mackerras 
2104f6d57916SPaul Mackerras /* RackMac
2105f6d57916SPaul Mackerras  */
2106f6d57916SPaul Mackerras static struct feature_table_entry rackmac_features[] = {
2107f6d57916SPaul Mackerras 	{ PMAC_FTR_SCC_ENABLE,		core99_scc_enable },
2108f6d57916SPaul Mackerras 	{ PMAC_FTR_IDE_ENABLE,		core99_ide_enable },
2109f6d57916SPaul Mackerras 	{ PMAC_FTR_IDE_RESET,		core99_ide_reset },
2110f6d57916SPaul Mackerras 	{ PMAC_FTR_GMAC_ENABLE,		core99_gmac_enable },
2111f6d57916SPaul Mackerras 	{ PMAC_FTR_GMAC_PHY_RESET,	core99_gmac_phy_reset },
2112f6d57916SPaul Mackerras 	{ PMAC_FTR_USB_ENABLE,		core99_usb_enable },
2113f6d57916SPaul Mackerras 	{ PMAC_FTR_1394_ENABLE,		core99_firewire_enable },
2114f6d57916SPaul Mackerras 	{ PMAC_FTR_1394_CABLE_POWER,	core99_firewire_cable_power },
2115f6d57916SPaul Mackerras 	{ PMAC_FTR_SLEEP_STATE,		core99_sleep_state },
2116f6d57916SPaul Mackerras #ifdef CONFIG_SMP
2117f6d57916SPaul Mackerras 	{ PMAC_FTR_RESET_CPU,		core99_reset_cpu },
2118f6d57916SPaul Mackerras #endif /* CONFIG_SMP */
2119f6d57916SPaul Mackerras 	{ PMAC_FTR_READ_GPIO,		core99_read_gpio },
2120f6d57916SPaul Mackerras 	{ PMAC_FTR_WRITE_GPIO,		core99_write_gpio },
2121f6d57916SPaul Mackerras 	{ 0, NULL }
2122f6d57916SPaul Mackerras };
2123f6d57916SPaul Mackerras 
2124f6d57916SPaul Mackerras /* Pangea features
2125f6d57916SPaul Mackerras  */
2126f6d57916SPaul Mackerras static struct feature_table_entry pangea_features[] = {
2127f6d57916SPaul Mackerras 	{ PMAC_FTR_SCC_ENABLE,		core99_scc_enable },
2128f6d57916SPaul Mackerras 	{ PMAC_FTR_MODEM_ENABLE,	pangea_modem_enable },
2129f6d57916SPaul Mackerras 	{ PMAC_FTR_IDE_ENABLE,		core99_ide_enable },
2130f6d57916SPaul Mackerras 	{ PMAC_FTR_IDE_RESET,		core99_ide_reset },
2131f6d57916SPaul Mackerras 	{ PMAC_FTR_GMAC_ENABLE,		core99_gmac_enable },
2132f6d57916SPaul Mackerras 	{ PMAC_FTR_GMAC_PHY_RESET,	core99_gmac_phy_reset },
2133f6d57916SPaul Mackerras 	{ PMAC_FTR_SOUND_CHIP_ENABLE,	core99_sound_chip_enable },
2134f6d57916SPaul Mackerras 	{ PMAC_FTR_AIRPORT_ENABLE,	core99_airport_enable },
2135f6d57916SPaul Mackerras 	{ PMAC_FTR_USB_ENABLE,		core99_usb_enable },
2136f6d57916SPaul Mackerras 	{ PMAC_FTR_1394_ENABLE,		core99_firewire_enable },
2137f6d57916SPaul Mackerras 	{ PMAC_FTR_1394_CABLE_POWER,	core99_firewire_cable_power },
2138f6d57916SPaul Mackerras 	{ PMAC_FTR_SLEEP_STATE,		core99_sleep_state },
2139f6d57916SPaul Mackerras 	{ PMAC_FTR_READ_GPIO,		core99_read_gpio },
2140f6d57916SPaul Mackerras 	{ PMAC_FTR_WRITE_GPIO,		core99_write_gpio },
2141f6d57916SPaul Mackerras 	{ 0, NULL }
2142f6d57916SPaul Mackerras };
2143f6d57916SPaul Mackerras 
2144f6d57916SPaul Mackerras /* Intrepid features
2145f6d57916SPaul Mackerras  */
2146f6d57916SPaul Mackerras static struct feature_table_entry intrepid_features[] = {
2147f6d57916SPaul Mackerras 	{ PMAC_FTR_SCC_ENABLE,		core99_scc_enable },
2148f6d57916SPaul Mackerras 	{ PMAC_FTR_MODEM_ENABLE,	pangea_modem_enable },
2149f6d57916SPaul Mackerras 	{ PMAC_FTR_IDE_ENABLE,		core99_ide_enable },
2150f6d57916SPaul Mackerras 	{ PMAC_FTR_IDE_RESET,		core99_ide_reset },
2151f6d57916SPaul Mackerras 	{ PMAC_FTR_GMAC_ENABLE,		core99_gmac_enable },
2152f6d57916SPaul Mackerras 	{ PMAC_FTR_GMAC_PHY_RESET,	core99_gmac_phy_reset },
2153f6d57916SPaul Mackerras 	{ PMAC_FTR_SOUND_CHIP_ENABLE,	core99_sound_chip_enable },
2154f6d57916SPaul Mackerras 	{ PMAC_FTR_AIRPORT_ENABLE,	core99_airport_enable },
2155f6d57916SPaul Mackerras 	{ PMAC_FTR_USB_ENABLE,		core99_usb_enable },
2156f6d57916SPaul Mackerras 	{ PMAC_FTR_1394_ENABLE,		core99_firewire_enable },
2157f6d57916SPaul Mackerras 	{ PMAC_FTR_1394_CABLE_POWER,	core99_firewire_cable_power },
2158f6d57916SPaul Mackerras 	{ PMAC_FTR_SLEEP_STATE,		core99_sleep_state },
2159f6d57916SPaul Mackerras 	{ PMAC_FTR_READ_GPIO,		core99_read_gpio },
2160f6d57916SPaul Mackerras 	{ PMAC_FTR_WRITE_GPIO,		core99_write_gpio },
2161f6d57916SPaul Mackerras 	{ PMAC_FTR_AACK_DELAY_ENABLE,	intrepid_aack_delay_enable },
2162f6d57916SPaul Mackerras 	{ 0, NULL }
2163f6d57916SPaul Mackerras };
2164f6d57916SPaul Mackerras 
2165f6d57916SPaul Mackerras #else /* CONFIG_POWER4 */
2166f6d57916SPaul Mackerras 
2167f6d57916SPaul Mackerras /* G5 features
2168f6d57916SPaul Mackerras  */
2169f6d57916SPaul Mackerras static struct feature_table_entry g5_features[] = {
2170f6d57916SPaul Mackerras 	{ PMAC_FTR_GMAC_ENABLE,		g5_gmac_enable },
2171f6d57916SPaul Mackerras 	{ PMAC_FTR_1394_ENABLE,		g5_fw_enable },
2172f6d57916SPaul Mackerras 	{ PMAC_FTR_ENABLE_MPIC,		g5_mpic_enable },
2173f6d57916SPaul Mackerras 	{ PMAC_FTR_GMAC_PHY_RESET,	g5_eth_phy_reset },
2174f6d57916SPaul Mackerras 	{ PMAC_FTR_SOUND_CHIP_ENABLE,	g5_i2s_enable },
2175f6d57916SPaul Mackerras #ifdef CONFIG_SMP
2176f6d57916SPaul Mackerras 	{ PMAC_FTR_RESET_CPU,		g5_reset_cpu },
2177f6d57916SPaul Mackerras #endif /* CONFIG_SMP */
2178f6d57916SPaul Mackerras 	{ PMAC_FTR_READ_GPIO,		core99_read_gpio },
2179f6d57916SPaul Mackerras 	{ PMAC_FTR_WRITE_GPIO,		core99_write_gpio },
2180f6d57916SPaul Mackerras 	{ 0, NULL }
2181f6d57916SPaul Mackerras };
2182f6d57916SPaul Mackerras 
2183f6d57916SPaul Mackerras #endif /* CONFIG_POWER4 */
2184f6d57916SPaul Mackerras 
2185f6d57916SPaul Mackerras static struct pmac_mb_def pmac_mb_defs[] = {
2186f6d57916SPaul Mackerras #ifndef CONFIG_POWER4
2187f6d57916SPaul Mackerras 	/*
2188f6d57916SPaul Mackerras 	 * Desktops
2189f6d57916SPaul Mackerras 	 */
2190f6d57916SPaul Mackerras 
2191f6d57916SPaul Mackerras 	{	"AAPL,8500",			"PowerMac 8500/8600",
2192f6d57916SPaul Mackerras 		PMAC_TYPE_PSURGE,		NULL,
2193f6d57916SPaul Mackerras 		0
2194f6d57916SPaul Mackerras 	},
2195f6d57916SPaul Mackerras 	{	"AAPL,9500",			"PowerMac 9500/9600",
2196f6d57916SPaul Mackerras 		PMAC_TYPE_PSURGE,		NULL,
2197f6d57916SPaul Mackerras 		0
2198f6d57916SPaul Mackerras 	},
2199f6d57916SPaul Mackerras 	{	"AAPL,7200",			"PowerMac 7200",
2200f6d57916SPaul Mackerras 		PMAC_TYPE_PSURGE,		NULL,
2201f6d57916SPaul Mackerras 		0
2202f6d57916SPaul Mackerras 	},
2203f6d57916SPaul Mackerras 	{	"AAPL,7300",			"PowerMac 7200/7300",
2204f6d57916SPaul Mackerras 		PMAC_TYPE_PSURGE,		NULL,
2205f6d57916SPaul Mackerras 		0
2206f6d57916SPaul Mackerras 	},
2207f6d57916SPaul Mackerras 	{	"AAPL,7500",			"PowerMac 7500",
2208f6d57916SPaul Mackerras 		PMAC_TYPE_PSURGE,		NULL,
2209f6d57916SPaul Mackerras 		0
2210f6d57916SPaul Mackerras 	},
2211f6d57916SPaul Mackerras 	{	"AAPL,ShinerESB",		"Apple Network Server",
2212f6d57916SPaul Mackerras 		PMAC_TYPE_ANS,			NULL,
2213f6d57916SPaul Mackerras 		0
2214f6d57916SPaul Mackerras 	},
2215f6d57916SPaul Mackerras 	{	"AAPL,e407",			"Alchemy",
2216f6d57916SPaul Mackerras 		PMAC_TYPE_ALCHEMY,		NULL,
2217f6d57916SPaul Mackerras 		0
2218f6d57916SPaul Mackerras 	},
2219f6d57916SPaul Mackerras 	{	"AAPL,e411",			"Gazelle",
2220f6d57916SPaul Mackerras 		PMAC_TYPE_GAZELLE,		NULL,
2221f6d57916SPaul Mackerras 		0
2222f6d57916SPaul Mackerras 	},
2223f6d57916SPaul Mackerras 	{	"AAPL,Gossamer",		"PowerMac G3 (Gossamer)",
2224f6d57916SPaul Mackerras 		PMAC_TYPE_GOSSAMER,		heathrow_desktop_features,
2225f6d57916SPaul Mackerras 		0
2226f6d57916SPaul Mackerras 	},
2227f6d57916SPaul Mackerras 	{	"AAPL,PowerMac G3",		"PowerMac G3 (Silk)",
2228f6d57916SPaul Mackerras 		PMAC_TYPE_SILK,			heathrow_desktop_features,
2229f6d57916SPaul Mackerras 		0
2230f6d57916SPaul Mackerras 	},
2231f6d57916SPaul Mackerras 	{	"PowerMac1,1",			"Blue&White G3",
2232f6d57916SPaul Mackerras 		PMAC_TYPE_YOSEMITE,		paddington_features,
2233f6d57916SPaul Mackerras 		0
2234f6d57916SPaul Mackerras 	},
2235f6d57916SPaul Mackerras 	{	"PowerMac1,2",			"PowerMac G4 PCI Graphics",
2236f6d57916SPaul Mackerras 		PMAC_TYPE_YIKES,		paddington_features,
2237f6d57916SPaul Mackerras 		0
2238f6d57916SPaul Mackerras 	},
2239f6d57916SPaul Mackerras 	{	"PowerMac2,1",			"iMac FireWire",
2240f6d57916SPaul Mackerras 		PMAC_TYPE_FW_IMAC,		core99_features,
2241f6d57916SPaul Mackerras 		PMAC_MB_MAY_SLEEP | PMAC_MB_OLD_CORE99
2242f6d57916SPaul Mackerras 	},
2243f6d57916SPaul Mackerras 	{	"PowerMac2,2",			"iMac FireWire",
2244f6d57916SPaul Mackerras 		PMAC_TYPE_FW_IMAC,		core99_features,
2245f6d57916SPaul Mackerras 		PMAC_MB_MAY_SLEEP | PMAC_MB_OLD_CORE99
2246f6d57916SPaul Mackerras 	},
2247f6d57916SPaul Mackerras 	{	"PowerMac3,1",			"PowerMac G4 AGP Graphics",
2248f6d57916SPaul Mackerras 		PMAC_TYPE_SAWTOOTH,		core99_features,
2249f6d57916SPaul Mackerras 		PMAC_MB_OLD_CORE99
2250f6d57916SPaul Mackerras 	},
2251f6d57916SPaul Mackerras 	{	"PowerMac3,2",			"PowerMac G4 AGP Graphics",
2252f6d57916SPaul Mackerras 		PMAC_TYPE_SAWTOOTH,		core99_features,
2253f6d57916SPaul Mackerras 		PMAC_MB_MAY_SLEEP | PMAC_MB_OLD_CORE99
2254f6d57916SPaul Mackerras 	},
2255f6d57916SPaul Mackerras 	{	"PowerMac3,3",			"PowerMac G4 AGP Graphics",
2256f6d57916SPaul Mackerras 		PMAC_TYPE_SAWTOOTH,		core99_features,
2257f6d57916SPaul Mackerras 		PMAC_MB_MAY_SLEEP | PMAC_MB_OLD_CORE99
2258f6d57916SPaul Mackerras 	},
2259f6d57916SPaul Mackerras 	{	"PowerMac3,4",			"PowerMac G4 Silver",
2260f6d57916SPaul Mackerras 		PMAC_TYPE_QUICKSILVER,		core99_features,
2261f6d57916SPaul Mackerras 		PMAC_MB_MAY_SLEEP
2262f6d57916SPaul Mackerras 	},
2263f6d57916SPaul Mackerras 	{	"PowerMac3,5",			"PowerMac G4 Silver",
2264f6d57916SPaul Mackerras 		PMAC_TYPE_QUICKSILVER,		core99_features,
2265f6d57916SPaul Mackerras 		PMAC_MB_MAY_SLEEP
2266f6d57916SPaul Mackerras 	},
2267f6d57916SPaul Mackerras 	{	"PowerMac3,6",			"PowerMac G4 Windtunnel",
2268f6d57916SPaul Mackerras 		PMAC_TYPE_WINDTUNNEL,		core99_features,
2269f6d57916SPaul Mackerras 		PMAC_MB_MAY_SLEEP,
2270f6d57916SPaul Mackerras 	},
2271f6d57916SPaul Mackerras 	{	"PowerMac4,1",			"iMac \"Flower Power\"",
2272f6d57916SPaul Mackerras 		PMAC_TYPE_PANGEA_IMAC,		pangea_features,
2273f6d57916SPaul Mackerras 		PMAC_MB_MAY_SLEEP
2274f6d57916SPaul Mackerras 	},
2275f6d57916SPaul Mackerras 	{	"PowerMac4,2",			"Flat panel iMac",
2276f6d57916SPaul Mackerras 		PMAC_TYPE_FLAT_PANEL_IMAC,	pangea_features,
2277f6d57916SPaul Mackerras 		PMAC_MB_CAN_SLEEP
2278f6d57916SPaul Mackerras 	},
2279f6d57916SPaul Mackerras 	{	"PowerMac4,4",			"eMac",
2280f6d57916SPaul Mackerras 		PMAC_TYPE_EMAC,			core99_features,
2281f6d57916SPaul Mackerras 		PMAC_MB_MAY_SLEEP
2282f6d57916SPaul Mackerras 	},
2283f6d57916SPaul Mackerras 	{	"PowerMac5,1",			"PowerMac G4 Cube",
2284f6d57916SPaul Mackerras 		PMAC_TYPE_CUBE,			core99_features,
2285f6d57916SPaul Mackerras 		PMAC_MB_MAY_SLEEP | PMAC_MB_OLD_CORE99
2286f6d57916SPaul Mackerras 	},
2287f6d57916SPaul Mackerras 	{	"PowerMac6,1",			"Flat panel iMac",
2288f6d57916SPaul Mackerras 		PMAC_TYPE_UNKNOWN_INTREPID,	intrepid_features,
2289f6d57916SPaul Mackerras 		PMAC_MB_MAY_SLEEP,
2290f6d57916SPaul Mackerras 	},
2291f6d57916SPaul Mackerras 	{	"PowerMac6,3",			"Flat panel iMac",
2292f6d57916SPaul Mackerras 		PMAC_TYPE_UNKNOWN_INTREPID,	intrepid_features,
2293f6d57916SPaul Mackerras 		PMAC_MB_MAY_SLEEP,
2294f6d57916SPaul Mackerras 	},
2295f6d57916SPaul Mackerras 	{	"PowerMac6,4",			"eMac",
2296f6d57916SPaul Mackerras 		PMAC_TYPE_UNKNOWN_INTREPID,	intrepid_features,
2297f6d57916SPaul Mackerras 		PMAC_MB_MAY_SLEEP,
2298f6d57916SPaul Mackerras 	},
2299f6d57916SPaul Mackerras 	{	"PowerMac10,1",			"Mac mini",
2300f6d57916SPaul Mackerras 		PMAC_TYPE_UNKNOWN_INTREPID,	intrepid_features,
2301f6d57916SPaul Mackerras 		PMAC_MB_MAY_SLEEP | PMAC_MB_HAS_FW_POWER,
2302f6d57916SPaul Mackerras 	},
2303f6d57916SPaul Mackerras 	{	"iMac,1",			"iMac (first generation)",
2304f6d57916SPaul Mackerras 		PMAC_TYPE_ORIG_IMAC,		paddington_features,
2305f6d57916SPaul Mackerras 		0
2306f6d57916SPaul Mackerras 	},
2307f6d57916SPaul Mackerras 
2308f6d57916SPaul Mackerras 	/*
2309f6d57916SPaul Mackerras 	 * Xserve's
2310f6d57916SPaul Mackerras 	 */
2311f6d57916SPaul Mackerras 
2312f6d57916SPaul Mackerras 	{	"RackMac1,1",			"XServe",
2313f6d57916SPaul Mackerras 		PMAC_TYPE_RACKMAC,		rackmac_features,
2314f6d57916SPaul Mackerras 		0,
2315f6d57916SPaul Mackerras 	},
2316f6d57916SPaul Mackerras 	{	"RackMac1,2",			"XServe rev. 2",
2317f6d57916SPaul Mackerras 		PMAC_TYPE_RACKMAC,		rackmac_features,
2318f6d57916SPaul Mackerras 		0,
2319f6d57916SPaul Mackerras 	},
2320f6d57916SPaul Mackerras 
2321f6d57916SPaul Mackerras 	/*
2322f6d57916SPaul Mackerras 	 * Laptops
2323f6d57916SPaul Mackerras 	 */
2324f6d57916SPaul Mackerras 
2325f6d57916SPaul Mackerras 	{	"AAPL,3400/2400",		"PowerBook 3400",
2326f6d57916SPaul Mackerras 		PMAC_TYPE_HOOPER,		ohare_features,
2327f6d57916SPaul Mackerras 		PMAC_MB_CAN_SLEEP | PMAC_MB_MOBILE
2328f6d57916SPaul Mackerras 	},
2329f6d57916SPaul Mackerras 	{	"AAPL,3500",			"PowerBook 3500",
2330f6d57916SPaul Mackerras 		PMAC_TYPE_KANGA,		ohare_features,
2331f6d57916SPaul Mackerras 		PMAC_MB_CAN_SLEEP | PMAC_MB_MOBILE
2332f6d57916SPaul Mackerras 	},
2333f6d57916SPaul Mackerras 	{	"AAPL,PowerBook1998",		"PowerBook Wallstreet",
2334f6d57916SPaul Mackerras 		PMAC_TYPE_WALLSTREET,		heathrow_laptop_features,
2335f6d57916SPaul Mackerras 		PMAC_MB_CAN_SLEEP | PMAC_MB_MOBILE
2336f6d57916SPaul Mackerras 	},
2337f6d57916SPaul Mackerras 	{	"PowerBook1,1",			"PowerBook 101 (Lombard)",
2338f6d57916SPaul Mackerras 		PMAC_TYPE_101_PBOOK,		paddington_features,
2339f6d57916SPaul Mackerras 		PMAC_MB_CAN_SLEEP | PMAC_MB_MOBILE
2340f6d57916SPaul Mackerras 	},
2341f6d57916SPaul Mackerras 	{	"PowerBook2,1",			"iBook (first generation)",
2342f6d57916SPaul Mackerras 		PMAC_TYPE_ORIG_IBOOK,		core99_features,
2343f6d57916SPaul Mackerras 		PMAC_MB_CAN_SLEEP | PMAC_MB_OLD_CORE99 | PMAC_MB_MOBILE
2344f6d57916SPaul Mackerras 	},
2345f6d57916SPaul Mackerras 	{	"PowerBook2,2",			"iBook FireWire",
2346f6d57916SPaul Mackerras 		PMAC_TYPE_FW_IBOOK,		core99_features,
2347f6d57916SPaul Mackerras 		PMAC_MB_MAY_SLEEP | PMAC_MB_HAS_FW_POWER |
2348f6d57916SPaul Mackerras 		PMAC_MB_OLD_CORE99 | PMAC_MB_MOBILE
2349f6d57916SPaul Mackerras 	},
2350f6d57916SPaul Mackerras 	{	"PowerBook3,1",			"PowerBook Pismo",
2351f6d57916SPaul Mackerras 		PMAC_TYPE_PISMO,		core99_features,
2352f6d57916SPaul Mackerras 		PMAC_MB_MAY_SLEEP | PMAC_MB_HAS_FW_POWER |
2353f6d57916SPaul Mackerras 		PMAC_MB_OLD_CORE99 | PMAC_MB_MOBILE
2354f6d57916SPaul Mackerras 	},
2355f6d57916SPaul Mackerras 	{	"PowerBook3,2",			"PowerBook Titanium",
2356f6d57916SPaul Mackerras 		PMAC_TYPE_TITANIUM,		core99_features,
2357f6d57916SPaul Mackerras 		PMAC_MB_MAY_SLEEP | PMAC_MB_HAS_FW_POWER | PMAC_MB_MOBILE
2358f6d57916SPaul Mackerras 	},
2359f6d57916SPaul Mackerras 	{	"PowerBook3,3",			"PowerBook Titanium II",
2360f6d57916SPaul Mackerras 		PMAC_TYPE_TITANIUM2,		core99_features,
2361f6d57916SPaul Mackerras 		PMAC_MB_MAY_SLEEP | PMAC_MB_HAS_FW_POWER | PMAC_MB_MOBILE
2362f6d57916SPaul Mackerras 	},
2363f6d57916SPaul Mackerras 	{	"PowerBook3,4",			"PowerBook Titanium III",
2364f6d57916SPaul Mackerras 		PMAC_TYPE_TITANIUM3,		core99_features,
2365f6d57916SPaul Mackerras 		PMAC_MB_MAY_SLEEP | PMAC_MB_HAS_FW_POWER | PMAC_MB_MOBILE
2366f6d57916SPaul Mackerras 	},
2367f6d57916SPaul Mackerras 	{	"PowerBook3,5",			"PowerBook Titanium IV",
2368f6d57916SPaul Mackerras 		PMAC_TYPE_TITANIUM4,		core99_features,
2369f6d57916SPaul Mackerras 		PMAC_MB_MAY_SLEEP | PMAC_MB_HAS_FW_POWER | PMAC_MB_MOBILE
2370f6d57916SPaul Mackerras 	},
2371f6d57916SPaul Mackerras 	{	"PowerBook4,1",			"iBook 2",
2372f6d57916SPaul Mackerras 		PMAC_TYPE_IBOOK2,		pangea_features,
2373f6d57916SPaul Mackerras 		PMAC_MB_MAY_SLEEP | PMAC_MB_HAS_FW_POWER | PMAC_MB_MOBILE
2374f6d57916SPaul Mackerras 	},
2375f6d57916SPaul Mackerras 	{	"PowerBook4,2",			"iBook 2",
2376f6d57916SPaul Mackerras 		PMAC_TYPE_IBOOK2,		pangea_features,
2377f6d57916SPaul Mackerras 		PMAC_MB_MAY_SLEEP | PMAC_MB_HAS_FW_POWER | PMAC_MB_MOBILE
2378f6d57916SPaul Mackerras 	},
2379f6d57916SPaul Mackerras 	{	"PowerBook4,3",			"iBook 2 rev. 2",
2380f6d57916SPaul Mackerras 		PMAC_TYPE_IBOOK2,		pangea_features,
2381f6d57916SPaul Mackerras 		PMAC_MB_MAY_SLEEP | PMAC_MB_HAS_FW_POWER | PMAC_MB_MOBILE
2382f6d57916SPaul Mackerras 	},
2383f6d57916SPaul Mackerras 	{	"PowerBook5,1",			"PowerBook G4 17\"",
2384f6d57916SPaul Mackerras 		PMAC_TYPE_UNKNOWN_INTREPID,	intrepid_features,
2385f6d57916SPaul Mackerras 		PMAC_MB_HAS_FW_POWER | PMAC_MB_MOBILE,
2386f6d57916SPaul Mackerras 	},
2387f6d57916SPaul Mackerras 	{	"PowerBook5,2",			"PowerBook G4 15\"",
2388f6d57916SPaul Mackerras 		PMAC_TYPE_UNKNOWN_INTREPID,	intrepid_features,
2389f6d57916SPaul Mackerras 		PMAC_MB_MAY_SLEEP | PMAC_MB_HAS_FW_POWER | PMAC_MB_MOBILE,
2390f6d57916SPaul Mackerras 	},
2391f6d57916SPaul Mackerras 	{	"PowerBook5,3",			"PowerBook G4 17\"",
2392f6d57916SPaul Mackerras 		PMAC_TYPE_UNKNOWN_INTREPID,	intrepid_features,
2393f6d57916SPaul Mackerras 		PMAC_MB_MAY_SLEEP | PMAC_MB_HAS_FW_POWER | PMAC_MB_MOBILE,
2394f6d57916SPaul Mackerras 	},
2395f6d57916SPaul Mackerras 	{	"PowerBook5,4",			"PowerBook G4 15\"",
2396f6d57916SPaul Mackerras 		PMAC_TYPE_UNKNOWN_INTREPID,	intrepid_features,
2397f6d57916SPaul Mackerras 		PMAC_MB_MAY_SLEEP | PMAC_MB_HAS_FW_POWER | PMAC_MB_MOBILE,
2398f6d57916SPaul Mackerras 	},
2399f6d57916SPaul Mackerras 	{	"PowerBook5,5",			"PowerBook G4 17\"",
2400f6d57916SPaul Mackerras 		PMAC_TYPE_UNKNOWN_INTREPID,	intrepid_features,
2401f6d57916SPaul Mackerras 		PMAC_MB_MAY_SLEEP | PMAC_MB_HAS_FW_POWER | PMAC_MB_MOBILE,
2402f6d57916SPaul Mackerras 	},
2403f6d57916SPaul Mackerras 	{	"PowerBook5,6",			"PowerBook G4 15\"",
2404f6d57916SPaul Mackerras 		PMAC_TYPE_UNKNOWN_INTREPID,	intrepid_features,
2405f6d57916SPaul Mackerras 		PMAC_MB_MAY_SLEEP | PMAC_MB_HAS_FW_POWER | PMAC_MB_MOBILE,
2406f6d57916SPaul Mackerras 	},
2407f6d57916SPaul Mackerras 	{	"PowerBook5,7",			"PowerBook G4 17\"",
2408f6d57916SPaul Mackerras 		PMAC_TYPE_UNKNOWN_INTREPID,	intrepid_features,
2409f6d57916SPaul Mackerras 		PMAC_MB_MAY_SLEEP | PMAC_MB_HAS_FW_POWER | PMAC_MB_MOBILE,
2410f6d57916SPaul Mackerras 	},
2411950fc002SOlof Johansson 	{	"PowerBook5,8",			"PowerBook G4 15\"",
2412950fc002SOlof Johansson 		PMAC_TYPE_UNKNOWN_INTREPID,	intrepid_features,
2413950fc002SOlof Johansson 		PMAC_MB_MAY_SLEEP | PMAC_MB_HAS_FW_POWER | PMAC_MB_MOBILE,
2414950fc002SOlof Johansson 	},
2415950fc002SOlof Johansson 	{	"PowerBook5,9",			"PowerBook G4 17\"",
2416950fc002SOlof Johansson 		PMAC_TYPE_UNKNOWN_INTREPID,	intrepid_features,
2417950fc002SOlof Johansson 		PMAC_MB_MAY_SLEEP | PMAC_MB_HAS_FW_POWER | PMAC_MB_MOBILE,
2418950fc002SOlof Johansson 	},
2419f6d57916SPaul Mackerras 	{	"PowerBook6,1",			"PowerBook G4 12\"",
2420f6d57916SPaul Mackerras 		PMAC_TYPE_UNKNOWN_INTREPID,	intrepid_features,
2421f6d57916SPaul Mackerras 		PMAC_MB_MAY_SLEEP | PMAC_MB_HAS_FW_POWER | PMAC_MB_MOBILE,
2422f6d57916SPaul Mackerras 	},
2423f6d57916SPaul Mackerras 	{	"PowerBook6,2",			"PowerBook G4",
2424f6d57916SPaul Mackerras 		PMAC_TYPE_UNKNOWN_INTREPID,	intrepid_features,
2425f6d57916SPaul Mackerras 		PMAC_MB_MAY_SLEEP | PMAC_MB_HAS_FW_POWER | PMAC_MB_MOBILE,
2426f6d57916SPaul Mackerras 	},
2427f6d57916SPaul Mackerras 	{	"PowerBook6,3",			"iBook G4",
2428f6d57916SPaul Mackerras 		PMAC_TYPE_UNKNOWN_INTREPID,	intrepid_features,
2429f6d57916SPaul Mackerras 		PMAC_MB_MAY_SLEEP | PMAC_MB_HAS_FW_POWER | PMAC_MB_MOBILE,
2430f6d57916SPaul Mackerras 	},
2431f6d57916SPaul Mackerras 	{	"PowerBook6,4",			"PowerBook G4 12\"",
2432f6d57916SPaul Mackerras 		PMAC_TYPE_UNKNOWN_INTREPID,	intrepid_features,
2433f6d57916SPaul Mackerras 		PMAC_MB_MAY_SLEEP | PMAC_MB_HAS_FW_POWER | PMAC_MB_MOBILE,
2434f6d57916SPaul Mackerras 	},
2435f6d57916SPaul Mackerras 	{	"PowerBook6,5",			"iBook G4",
2436f6d57916SPaul Mackerras 		PMAC_TYPE_UNKNOWN_INTREPID,	intrepid_features,
2437f6d57916SPaul Mackerras 		PMAC_MB_MAY_SLEEP | PMAC_MB_HAS_FW_POWER | PMAC_MB_MOBILE,
2438f6d57916SPaul Mackerras 	},
24395629d41dSPaul Mackerras 	{	"PowerBook6,7",			"iBook G4",
24405629d41dSPaul Mackerras 		PMAC_TYPE_UNKNOWN_INTREPID,	intrepid_features,
24415629d41dSPaul Mackerras 		PMAC_MB_MAY_SLEEP | PMAC_MB_HAS_FW_POWER | PMAC_MB_MOBILE,
24425629d41dSPaul Mackerras 	},
2443f6d57916SPaul Mackerras 	{	"PowerBook6,8",			"PowerBook G4 12\"",
2444f6d57916SPaul Mackerras 		PMAC_TYPE_UNKNOWN_INTREPID,	intrepid_features,
2445f6d57916SPaul Mackerras 		PMAC_MB_MAY_SLEEP | PMAC_MB_HAS_FW_POWER | PMAC_MB_MOBILE,
2446f6d57916SPaul Mackerras 	},
2447f6d57916SPaul Mackerras #else /* CONFIG_POWER4 */
2448f6d57916SPaul Mackerras 	{	"PowerMac7,2",			"PowerMac G5",
2449f6d57916SPaul Mackerras 		PMAC_TYPE_POWERMAC_G5,		g5_features,
2450f6d57916SPaul Mackerras 		0,
2451f6d57916SPaul Mackerras 	},
2452f6d57916SPaul Mackerras #ifdef CONFIG_PPC64
2453f6d57916SPaul Mackerras 	{	"PowerMac7,3",			"PowerMac G5",
2454f6d57916SPaul Mackerras 		PMAC_TYPE_POWERMAC_G5,		g5_features,
2455f6d57916SPaul Mackerras 		0,
2456f6d57916SPaul Mackerras 	},
2457f6d57916SPaul Mackerras 	{	"PowerMac8,1",			"iMac G5",
2458f6d57916SPaul Mackerras 		PMAC_TYPE_IMAC_G5,		g5_features,
2459f6d57916SPaul Mackerras 		0,
2460f6d57916SPaul Mackerras 	},
2461f6d57916SPaul Mackerras 	{	"PowerMac9,1",			"PowerMac G5",
2462f6d57916SPaul Mackerras 		PMAC_TYPE_POWERMAC_G5_U3L,	g5_features,
2463f6d57916SPaul Mackerras 		0,
2464f6d57916SPaul Mackerras 	},
2465f6d57916SPaul Mackerras 	{       "RackMac3,1",                   "XServe G5",
2466f6d57916SPaul Mackerras 		PMAC_TYPE_XSERVE_G5,		g5_features,
2467f6d57916SPaul Mackerras 		0,
2468f6d57916SPaul Mackerras 	},
2469f6d57916SPaul Mackerras #endif /* CONFIG_PPC64 */
2470f6d57916SPaul Mackerras #endif /* CONFIG_POWER4 */
2471f6d57916SPaul Mackerras };
2472f6d57916SPaul Mackerras 
2473f6d57916SPaul Mackerras /*
2474f6d57916SPaul Mackerras  * The toplevel feature_call callback
2475f6d57916SPaul Mackerras  */
2476f6d57916SPaul Mackerras long pmac_do_feature_call(unsigned int selector, ...)
2477f6d57916SPaul Mackerras {
2478f6d57916SPaul Mackerras 	struct device_node *node;
2479f6d57916SPaul Mackerras 	long param, value;
2480f6d57916SPaul Mackerras 	int i;
2481f6d57916SPaul Mackerras 	feature_call func = NULL;
2482f6d57916SPaul Mackerras 	va_list args;
2483f6d57916SPaul Mackerras 
2484f6d57916SPaul Mackerras 	if (pmac_mb.features)
2485f6d57916SPaul Mackerras 		for (i=0; pmac_mb.features[i].function; i++)
2486f6d57916SPaul Mackerras 			if (pmac_mb.features[i].selector == selector) {
2487f6d57916SPaul Mackerras 				func = pmac_mb.features[i].function;
2488f6d57916SPaul Mackerras 				break;
2489f6d57916SPaul Mackerras 			}
2490f6d57916SPaul Mackerras 	if (!func)
2491f6d57916SPaul Mackerras 		for (i=0; any_features[i].function; i++)
2492f6d57916SPaul Mackerras 			if (any_features[i].selector == selector) {
2493f6d57916SPaul Mackerras 				func = any_features[i].function;
2494f6d57916SPaul Mackerras 				break;
2495f6d57916SPaul Mackerras 			}
2496f6d57916SPaul Mackerras 	if (!func)
2497f6d57916SPaul Mackerras 		return -ENODEV;
2498f6d57916SPaul Mackerras 
2499f6d57916SPaul Mackerras 	va_start(args, selector);
2500f6d57916SPaul Mackerras 	node = (struct device_node*)va_arg(args, void*);
2501f6d57916SPaul Mackerras 	param = va_arg(args, long);
2502f6d57916SPaul Mackerras 	value = va_arg(args, long);
2503f6d57916SPaul Mackerras 	va_end(args);
2504f6d57916SPaul Mackerras 
2505f6d57916SPaul Mackerras 	return func(node, param, value);
2506f6d57916SPaul Mackerras }
2507f6d57916SPaul Mackerras 
2508f6d57916SPaul Mackerras static int __init probe_motherboard(void)
2509f6d57916SPaul Mackerras {
2510f6d57916SPaul Mackerras 	int i;
2511f6d57916SPaul Mackerras 	struct macio_chip *macio = &macio_chips[0];
2512f6d57916SPaul Mackerras 	const char *model = NULL;
2513f6d57916SPaul Mackerras 	struct device_node *dt;
2514f6d57916SPaul Mackerras 
2515f6d57916SPaul Mackerras 	/* Lookup known motherboard type in device-tree. First try an
2516f6d57916SPaul Mackerras 	 * exact match on the "model" property, then try a "compatible"
2517f6d57916SPaul Mackerras 	 * match is none is found.
2518f6d57916SPaul Mackerras 	 */
2519f6d57916SPaul Mackerras 	dt = find_devices("device-tree");
2520f6d57916SPaul Mackerras 	if (dt != NULL)
2521f6d57916SPaul Mackerras 		model = (const char *) get_property(dt, "model", NULL);
2522f6d57916SPaul Mackerras 	for(i=0; model && i<(sizeof(pmac_mb_defs)/sizeof(struct pmac_mb_def)); i++) {
2523f6d57916SPaul Mackerras 	    if (strcmp(model, pmac_mb_defs[i].model_string) == 0) {
2524f6d57916SPaul Mackerras 		pmac_mb = pmac_mb_defs[i];
2525f6d57916SPaul Mackerras 		goto found;
2526f6d57916SPaul Mackerras 	    }
2527f6d57916SPaul Mackerras 	}
2528f6d57916SPaul Mackerras 	for(i=0; i<(sizeof(pmac_mb_defs)/sizeof(struct pmac_mb_def)); i++) {
2529f6d57916SPaul Mackerras 	    if (machine_is_compatible(pmac_mb_defs[i].model_string)) {
2530f6d57916SPaul Mackerras 		pmac_mb = pmac_mb_defs[i];
2531f6d57916SPaul Mackerras 		goto found;
2532f6d57916SPaul Mackerras 	    }
2533f6d57916SPaul Mackerras 	}
2534f6d57916SPaul Mackerras 
2535f6d57916SPaul Mackerras 	/* Fallback to selection depending on mac-io chip type */
2536f6d57916SPaul Mackerras 	switch(macio->type) {
2537f6d57916SPaul Mackerras #ifndef CONFIG_POWER4
2538f6d57916SPaul Mackerras 	    case macio_grand_central:
2539f6d57916SPaul Mackerras 		pmac_mb.model_id = PMAC_TYPE_PSURGE;
2540f6d57916SPaul Mackerras 		pmac_mb.model_name = "Unknown PowerSurge";
2541f6d57916SPaul Mackerras 		break;
2542f6d57916SPaul Mackerras 	    case macio_ohare:
2543f6d57916SPaul Mackerras 		pmac_mb.model_id = PMAC_TYPE_UNKNOWN_OHARE;
2544f6d57916SPaul Mackerras 		pmac_mb.model_name = "Unknown OHare-based";
2545f6d57916SPaul Mackerras 		break;
2546f6d57916SPaul Mackerras 	    case macio_heathrow:
2547f6d57916SPaul Mackerras 		pmac_mb.model_id = PMAC_TYPE_UNKNOWN_HEATHROW;
2548f6d57916SPaul Mackerras 		pmac_mb.model_name = "Unknown Heathrow-based";
2549f6d57916SPaul Mackerras 		pmac_mb.features = heathrow_desktop_features;
2550f6d57916SPaul Mackerras 		break;
2551f6d57916SPaul Mackerras 	    case macio_paddington:
2552f6d57916SPaul Mackerras 		pmac_mb.model_id = PMAC_TYPE_UNKNOWN_PADDINGTON;
2553f6d57916SPaul Mackerras 		pmac_mb.model_name = "Unknown Paddington-based";
2554f6d57916SPaul Mackerras 		pmac_mb.features = paddington_features;
2555f6d57916SPaul Mackerras 		break;
2556f6d57916SPaul Mackerras 	    case macio_keylargo:
2557f6d57916SPaul Mackerras 		pmac_mb.model_id = PMAC_TYPE_UNKNOWN_CORE99;
2558f6d57916SPaul Mackerras 		pmac_mb.model_name = "Unknown Keylargo-based";
2559f6d57916SPaul Mackerras 		pmac_mb.features = core99_features;
2560f6d57916SPaul Mackerras 		break;
2561f6d57916SPaul Mackerras 	    case macio_pangea:
2562f6d57916SPaul Mackerras 		pmac_mb.model_id = PMAC_TYPE_UNKNOWN_PANGEA;
2563f6d57916SPaul Mackerras 		pmac_mb.model_name = "Unknown Pangea-based";
2564f6d57916SPaul Mackerras 		pmac_mb.features = pangea_features;
2565f6d57916SPaul Mackerras 		break;
2566f6d57916SPaul Mackerras 	    case macio_intrepid:
2567f6d57916SPaul Mackerras 		pmac_mb.model_id = PMAC_TYPE_UNKNOWN_INTREPID;
2568f6d57916SPaul Mackerras 		pmac_mb.model_name = "Unknown Intrepid-based";
2569f6d57916SPaul Mackerras 		pmac_mb.features = intrepid_features;
2570f6d57916SPaul Mackerras 		break;
2571f6d57916SPaul Mackerras #else /* CONFIG_POWER4 */
2572f6d57916SPaul Mackerras 	case macio_keylargo2:
2573f6d57916SPaul Mackerras 		pmac_mb.model_id = PMAC_TYPE_UNKNOWN_K2;
2574f6d57916SPaul Mackerras 		pmac_mb.model_name = "Unknown K2-based";
2575f6d57916SPaul Mackerras 		pmac_mb.features = g5_features;
2576f6d57916SPaul Mackerras 		break;
2577f6d57916SPaul Mackerras #endif /* CONFIG_POWER4 */
2578f6d57916SPaul Mackerras 	default:
2579f6d57916SPaul Mackerras 		return -ENODEV;
2580f6d57916SPaul Mackerras 	}
2581f6d57916SPaul Mackerras found:
2582f6d57916SPaul Mackerras #ifndef CONFIG_POWER4
2583f6d57916SPaul Mackerras 	/* Fixup Hooper vs. Comet */
2584f6d57916SPaul Mackerras 	if (pmac_mb.model_id == PMAC_TYPE_HOOPER) {
2585f6d57916SPaul Mackerras 		u32 __iomem * mach_id_ptr = ioremap(0xf3000034, 4);
2586f6d57916SPaul Mackerras 		if (!mach_id_ptr)
2587f6d57916SPaul Mackerras 			return -ENODEV;
2588f6d57916SPaul Mackerras 		/* Here, I used to disable the media-bay on comet. It
2589f6d57916SPaul Mackerras 		 * appears this is wrong, the floppy connector is actually
2590f6d57916SPaul Mackerras 		 * a kind of media-bay and works with the current driver.
2591f6d57916SPaul Mackerras 		 */
2592f6d57916SPaul Mackerras 		if (__raw_readl(mach_id_ptr) & 0x20000000UL)
2593f6d57916SPaul Mackerras 			pmac_mb.model_id = PMAC_TYPE_COMET;
2594f6d57916SPaul Mackerras 		iounmap(mach_id_ptr);
2595f6d57916SPaul Mackerras 	}
2596f6d57916SPaul Mackerras #endif /* CONFIG_POWER4 */
2597f6d57916SPaul Mackerras 
2598f6d57916SPaul Mackerras #ifdef CONFIG_6xx
2599f6d57916SPaul Mackerras 	/* Set default value of powersave_nap on machines that support it.
2600f6d57916SPaul Mackerras 	 * It appears that uninorth rev 3 has a problem with it, we don't
2601f6d57916SPaul Mackerras 	 * enable it on those. In theory, the flush-on-lock property is
2602f6d57916SPaul Mackerras 	 * supposed to be set when not supported, but I'm not very confident
2603f6d57916SPaul Mackerras 	 * that all Apple OF revs did it properly, I do it the paranoid way.
2604f6d57916SPaul Mackerras 	 */
2605f6d57916SPaul Mackerras 	while (uninorth_base && uninorth_rev > 3) {
2606f6d57916SPaul Mackerras 		struct device_node *np = find_path_device("/cpus");
2607f6d57916SPaul Mackerras 		if (!np || !np->child) {
2608f6d57916SPaul Mackerras 			printk(KERN_WARNING "Can't find CPU(s) in device tree !\n");
2609f6d57916SPaul Mackerras 			break;
2610f6d57916SPaul Mackerras 		}
2611f6d57916SPaul Mackerras 		np = np->child;
2612f6d57916SPaul Mackerras 		/* Nap mode not supported on SMP */
2613f6d57916SPaul Mackerras 		if (np->sibling)
2614f6d57916SPaul Mackerras 			break;
2615f6d57916SPaul Mackerras 		/* Nap mode not supported if flush-on-lock property is present */
2616f6d57916SPaul Mackerras 		if (get_property(np, "flush-on-lock", NULL))
2617f6d57916SPaul Mackerras 			break;
2618f6d57916SPaul Mackerras 		powersave_nap = 1;
2619f6d57916SPaul Mackerras 		printk(KERN_INFO "Processor NAP mode on idle enabled.\n");
2620f6d57916SPaul Mackerras 		break;
2621f6d57916SPaul Mackerras 	}
2622f6d57916SPaul Mackerras 
2623f6d57916SPaul Mackerras 	/* On CPUs that support it (750FX), lowspeed by default during
2624f6d57916SPaul Mackerras 	 * NAP mode
2625f6d57916SPaul Mackerras 	 */
2626f6d57916SPaul Mackerras 	powersave_lowspeed = 1;
2627f6d57916SPaul Mackerras #endif /* CONFIG_6xx */
2628f6d57916SPaul Mackerras #ifdef CONFIG_POWER4
2629f6d57916SPaul Mackerras 	powersave_nap = 1;
2630f6d57916SPaul Mackerras #endif
2631f6d57916SPaul Mackerras 	/* Check for "mobile" machine */
2632f6d57916SPaul Mackerras 	if (model && (strncmp(model, "PowerBook", 9) == 0
2633f6d57916SPaul Mackerras 		   || strncmp(model, "iBook", 5) == 0))
2634f6d57916SPaul Mackerras 		pmac_mb.board_flags |= PMAC_MB_MOBILE;
2635f6d57916SPaul Mackerras 
2636f6d57916SPaul Mackerras 
2637f6d57916SPaul Mackerras 	printk(KERN_INFO "PowerMac motherboard: %s\n", pmac_mb.model_name);
2638f6d57916SPaul Mackerras 	return 0;
2639f6d57916SPaul Mackerras }
2640f6d57916SPaul Mackerras 
2641f6d57916SPaul Mackerras /* Initialize the Core99 UniNorth host bridge and memory controller
2642f6d57916SPaul Mackerras  */
2643f6d57916SPaul Mackerras static void __init probe_uninorth(void)
2644f6d57916SPaul Mackerras {
264551d3082fSBenjamin Herrenschmidt 	u32 *addrp;
264651d3082fSBenjamin Herrenschmidt 	phys_addr_t address;
2647f6d57916SPaul Mackerras 	unsigned long actrl;
2648f6d57916SPaul Mackerras 
2649f6d57916SPaul Mackerras 	/* Locate core99 Uni-N */
2650f6d57916SPaul Mackerras 	uninorth_node = of_find_node_by_name(NULL, "uni-n");
2651f6d57916SPaul Mackerras 	/* Locate G5 u3 */
2652f6d57916SPaul Mackerras 	if (uninorth_node == NULL) {
2653f6d57916SPaul Mackerras 		uninorth_node = of_find_node_by_name(NULL, "u3");
2654f6d57916SPaul Mackerras 		uninorth_u3 = 1;
2655f6d57916SPaul Mackerras 	}
265651d3082fSBenjamin Herrenschmidt 	if (uninorth_node == NULL)
265751d3082fSBenjamin Herrenschmidt 		return;
265851d3082fSBenjamin Herrenschmidt 
265951d3082fSBenjamin Herrenschmidt 	addrp = (u32 *)get_property(uninorth_node, "reg", NULL);
266051d3082fSBenjamin Herrenschmidt 	if (addrp == NULL)
266151d3082fSBenjamin Herrenschmidt 		return;
266251d3082fSBenjamin Herrenschmidt 	address = of_translate_address(uninorth_node, addrp);
266351d3082fSBenjamin Herrenschmidt 	if (address == 0)
266451d3082fSBenjamin Herrenschmidt 		return;
2665f6d57916SPaul Mackerras 	uninorth_base = ioremap(address, 0x40000);
2666f6d57916SPaul Mackerras 	uninorth_rev = in_be32(UN_REG(UNI_N_VERSION));
2667f6d57916SPaul Mackerras 	if (uninorth_u3)
2668f6d57916SPaul Mackerras 		u3_ht = ioremap(address + U3_HT_CONFIG_BASE, 0x1000);
2669f6d57916SPaul Mackerras 
267051d3082fSBenjamin Herrenschmidt 	printk(KERN_INFO "Found %s memory controller & host bridge,"
267151d3082fSBenjamin Herrenschmidt 	       " revision: %d\n", uninorth_u3 ? "U3" : "UniNorth",
267251d3082fSBenjamin Herrenschmidt 	       uninorth_rev);
2673f6d57916SPaul Mackerras 	printk(KERN_INFO "Mapped at 0x%08lx\n", (unsigned long)uninorth_base);
2674f6d57916SPaul Mackerras 
2675f6d57916SPaul Mackerras 	/* Set the arbitrer QAck delay according to what Apple does
2676f6d57916SPaul Mackerras 	 */
2677f6d57916SPaul Mackerras 	if (uninorth_rev < 0x11) {
2678f6d57916SPaul Mackerras 		actrl = UN_IN(UNI_N_ARB_CTRL) & ~UNI_N_ARB_CTRL_QACK_DELAY_MASK;
2679f6d57916SPaul Mackerras 		actrl |= ((uninorth_rev < 3) ? UNI_N_ARB_CTRL_QACK_DELAY105 :
2680f6d57916SPaul Mackerras 			UNI_N_ARB_CTRL_QACK_DELAY) << UNI_N_ARB_CTRL_QACK_DELAY_SHIFT;
2681f6d57916SPaul Mackerras 		UN_OUT(UNI_N_ARB_CTRL, actrl);
2682f6d57916SPaul Mackerras 	}
2683f6d57916SPaul Mackerras 
2684f6d57916SPaul Mackerras 	/* Some more magic as done by them in recent MacOS X on UniNorth
2685f6d57916SPaul Mackerras 	 * revs 1.5 to 2.O and Pangea. Seem to toggle the UniN Maxbus/PCI
2686f6d57916SPaul Mackerras 	 * memory timeout
2687f6d57916SPaul Mackerras 	 */
2688f6d57916SPaul Mackerras 	if ((uninorth_rev >= 0x11 && uninorth_rev <= 0x24) || uninorth_rev == 0xc0)
2689f6d57916SPaul Mackerras 		UN_OUT(0x2160, UN_IN(0x2160) & 0x00ffffff);
2690f6d57916SPaul Mackerras }
2691f6d57916SPaul Mackerras 
2692f6d57916SPaul Mackerras static void __init probe_one_macio(const char *name, const char *compat, int type)
2693f6d57916SPaul Mackerras {
2694f6d57916SPaul Mackerras 	struct device_node*	node;
2695f6d57916SPaul Mackerras 	int			i;
2696f6d57916SPaul Mackerras 	volatile u32 __iomem	*base;
269751d3082fSBenjamin Herrenschmidt 	u32			*addrp, *revp;
269851d3082fSBenjamin Herrenschmidt 	phys_addr_t		addr;
269951d3082fSBenjamin Herrenschmidt 	u64			size;
2700f6d57916SPaul Mackerras 
270151d3082fSBenjamin Herrenschmidt 	for (node = NULL; (node = of_find_node_by_name(node, name)) != NULL;) {
270251d3082fSBenjamin Herrenschmidt 		if (!compat)
270351d3082fSBenjamin Herrenschmidt 			break;
2704f6d57916SPaul Mackerras 		if (device_is_compatible(node, compat))
2705f6d57916SPaul Mackerras 			break;
270651d3082fSBenjamin Herrenschmidt 	}
2707f6d57916SPaul Mackerras 	if (!node)
2708f6d57916SPaul Mackerras 		return;
2709f6d57916SPaul Mackerras 	for(i=0; i<MAX_MACIO_CHIPS; i++) {
2710f6d57916SPaul Mackerras 		if (!macio_chips[i].of_node)
2711f6d57916SPaul Mackerras 			break;
2712f6d57916SPaul Mackerras 		if (macio_chips[i].of_node == node)
2713f6d57916SPaul Mackerras 			return;
2714f6d57916SPaul Mackerras 	}
271551d3082fSBenjamin Herrenschmidt 
2716f6d57916SPaul Mackerras 	if (i >= MAX_MACIO_CHIPS) {
2717f6d57916SPaul Mackerras 		printk(KERN_ERR "pmac_feature: Please increase MAX_MACIO_CHIPS !\n");
2718f6d57916SPaul Mackerras 		printk(KERN_ERR "pmac_feature: %s skipped\n", node->full_name);
2719f6d57916SPaul Mackerras 		return;
2720f6d57916SPaul Mackerras 	}
2721d2dd482bSBenjamin Herrenschmidt 	addrp = of_get_pci_address(node, 0, &size, NULL);
272251d3082fSBenjamin Herrenschmidt 	if (addrp == NULL) {
272351d3082fSBenjamin Herrenschmidt 		printk(KERN_ERR "pmac_feature: %s: can't find base !\n",
272451d3082fSBenjamin Herrenschmidt 		       node->full_name);
272551d3082fSBenjamin Herrenschmidt 		return;
272651d3082fSBenjamin Herrenschmidt 	}
272751d3082fSBenjamin Herrenschmidt 	addr = of_translate_address(node, addrp);
272851d3082fSBenjamin Herrenschmidt 	if (addr == 0) {
272951d3082fSBenjamin Herrenschmidt 		printk(KERN_ERR "pmac_feature: %s, can't translate base !\n",
273051d3082fSBenjamin Herrenschmidt 		       node->full_name);
273151d3082fSBenjamin Herrenschmidt 		return;
273251d3082fSBenjamin Herrenschmidt 	}
273351d3082fSBenjamin Herrenschmidt 	base = ioremap(addr, (unsigned long)size);
2734f6d57916SPaul Mackerras 	if (!base) {
273551d3082fSBenjamin Herrenschmidt 		printk(KERN_ERR "pmac_feature: %s, can't map mac-io chip !\n",
273651d3082fSBenjamin Herrenschmidt 		       node->full_name);
2737f6d57916SPaul Mackerras 		return;
2738f6d57916SPaul Mackerras 	}
2739f6d57916SPaul Mackerras 	if (type == macio_keylargo) {
2740f6d57916SPaul Mackerras 		u32 *did = (u32 *)get_property(node, "device-id", NULL);
2741f6d57916SPaul Mackerras 		if (*did == 0x00000025)
2742f6d57916SPaul Mackerras 			type = macio_pangea;
2743f6d57916SPaul Mackerras 		if (*did == 0x0000003e)
2744f6d57916SPaul Mackerras 			type = macio_intrepid;
2745f6d57916SPaul Mackerras 	}
2746f6d57916SPaul Mackerras 	macio_chips[i].of_node	= node;
2747f6d57916SPaul Mackerras 	macio_chips[i].type	= type;
2748f6d57916SPaul Mackerras 	macio_chips[i].base	= base;
2749f6d57916SPaul Mackerras 	macio_chips[i].flags	= MACIO_FLAG_SCCB_ON | MACIO_FLAG_SCCB_ON;
2750f6d57916SPaul Mackerras 	macio_chips[i].name	= macio_names[type];
2751f6d57916SPaul Mackerras 	revp = (u32 *)get_property(node, "revision-id", NULL);
2752f6d57916SPaul Mackerras 	if (revp)
2753f6d57916SPaul Mackerras 		macio_chips[i].rev = *revp;
2754f6d57916SPaul Mackerras 	printk(KERN_INFO "Found a %s mac-io controller, rev: %d, mapped at 0x%p\n",
2755f6d57916SPaul Mackerras 		macio_names[type], macio_chips[i].rev, macio_chips[i].base);
2756f6d57916SPaul Mackerras }
2757f6d57916SPaul Mackerras 
2758f6d57916SPaul Mackerras static int __init
2759f6d57916SPaul Mackerras probe_macios(void)
2760f6d57916SPaul Mackerras {
2761f6d57916SPaul Mackerras 	/* Warning, ordering is important */
2762f6d57916SPaul Mackerras 	probe_one_macio("gc", NULL, macio_grand_central);
2763f6d57916SPaul Mackerras 	probe_one_macio("ohare", NULL, macio_ohare);
2764f6d57916SPaul Mackerras 	probe_one_macio("pci106b,7", NULL, macio_ohareII);
2765f6d57916SPaul Mackerras 	probe_one_macio("mac-io", "keylargo", macio_keylargo);
2766f6d57916SPaul Mackerras 	probe_one_macio("mac-io", "paddington", macio_paddington);
2767f6d57916SPaul Mackerras 	probe_one_macio("mac-io", "gatwick", macio_gatwick);
2768f6d57916SPaul Mackerras 	probe_one_macio("mac-io", "heathrow", macio_heathrow);
2769f6d57916SPaul Mackerras 	probe_one_macio("mac-io", "K2-Keylargo", macio_keylargo2);
2770f6d57916SPaul Mackerras 
2771f6d57916SPaul Mackerras 	/* Make sure the "main" macio chip appear first */
2772f6d57916SPaul Mackerras 	if (macio_chips[0].type == macio_gatwick
2773f6d57916SPaul Mackerras 	    && macio_chips[1].type == macio_heathrow) {
2774f6d57916SPaul Mackerras 		struct macio_chip temp = macio_chips[0];
2775f6d57916SPaul Mackerras 		macio_chips[0] = macio_chips[1];
2776f6d57916SPaul Mackerras 		macio_chips[1] = temp;
2777f6d57916SPaul Mackerras 	}
2778f6d57916SPaul Mackerras 	if (macio_chips[0].type == macio_ohareII
2779f6d57916SPaul Mackerras 	    && macio_chips[1].type == macio_ohare) {
2780f6d57916SPaul Mackerras 		struct macio_chip temp = macio_chips[0];
2781f6d57916SPaul Mackerras 		macio_chips[0] = macio_chips[1];
2782f6d57916SPaul Mackerras 		macio_chips[1] = temp;
2783f6d57916SPaul Mackerras 	}
2784f6d57916SPaul Mackerras 	macio_chips[0].lbus.index = 0;
2785f6d57916SPaul Mackerras 	macio_chips[1].lbus.index = 1;
2786f6d57916SPaul Mackerras 
2787f6d57916SPaul Mackerras 	return (macio_chips[0].of_node == NULL) ? -ENODEV : 0;
2788f6d57916SPaul Mackerras }
2789f6d57916SPaul Mackerras 
2790f6d57916SPaul Mackerras static void __init
2791f6d57916SPaul Mackerras initial_serial_shutdown(struct device_node *np)
2792f6d57916SPaul Mackerras {
2793f6d57916SPaul Mackerras 	int len;
2794f6d57916SPaul Mackerras 	struct slot_names_prop {
2795f6d57916SPaul Mackerras 		int	count;
2796f6d57916SPaul Mackerras 		char	name[1];
2797f6d57916SPaul Mackerras 	} *slots;
2798f6d57916SPaul Mackerras 	char *conn;
2799f6d57916SPaul Mackerras 	int port_type = PMAC_SCC_ASYNC;
2800f6d57916SPaul Mackerras 	int modem = 0;
2801f6d57916SPaul Mackerras 
2802f6d57916SPaul Mackerras 	slots = (struct slot_names_prop *)get_property(np, "slot-names", &len);
2803f6d57916SPaul Mackerras 	conn = get_property(np, "AAPL,connector", &len);
2804f6d57916SPaul Mackerras 	if (conn && (strcmp(conn, "infrared") == 0))
2805f6d57916SPaul Mackerras 		port_type = PMAC_SCC_IRDA;
2806f6d57916SPaul Mackerras 	else if (device_is_compatible(np, "cobalt"))
2807f6d57916SPaul Mackerras 		modem = 1;
2808f6d57916SPaul Mackerras 	else if (slots && slots->count > 0) {
2809f6d57916SPaul Mackerras 		if (strcmp(slots->name, "IrDA") == 0)
2810f6d57916SPaul Mackerras 			port_type = PMAC_SCC_IRDA;
2811f6d57916SPaul Mackerras 		else if (strcmp(slots->name, "Modem") == 0)
2812f6d57916SPaul Mackerras 			modem = 1;
2813f6d57916SPaul Mackerras 	}
2814f6d57916SPaul Mackerras 	if (modem)
2815f6d57916SPaul Mackerras 		pmac_call_feature(PMAC_FTR_MODEM_ENABLE, np, 0, 0);
2816f6d57916SPaul Mackerras 	pmac_call_feature(PMAC_FTR_SCC_ENABLE, np, port_type, 0);
2817f6d57916SPaul Mackerras }
2818f6d57916SPaul Mackerras 
2819f6d57916SPaul Mackerras static void __init
2820f6d57916SPaul Mackerras set_initial_features(void)
2821f6d57916SPaul Mackerras {
2822f6d57916SPaul Mackerras 	struct device_node *np;
2823f6d57916SPaul Mackerras 
2824f6d57916SPaul Mackerras 	/* That hack appears to be necessary for some StarMax motherboards
2825f6d57916SPaul Mackerras 	 * but I'm not too sure it was audited for side-effects on other
2826f6d57916SPaul Mackerras 	 * ohare based machines...
2827f6d57916SPaul Mackerras 	 * Since I still have difficulties figuring the right way to
2828f6d57916SPaul Mackerras 	 * differenciate them all and since that hack was there for a long
2829f6d57916SPaul Mackerras 	 * time, I'll keep it around
2830f6d57916SPaul Mackerras 	 */
2831f6d57916SPaul Mackerras 	if (macio_chips[0].type == macio_ohare && !find_devices("via-pmu")) {
2832f6d57916SPaul Mackerras 		struct macio_chip *macio = &macio_chips[0];
2833f6d57916SPaul Mackerras 		MACIO_OUT32(OHARE_FCR, STARMAX_FEATURES);
2834f6d57916SPaul Mackerras 	} else if (macio_chips[0].type == macio_ohare) {
2835f6d57916SPaul Mackerras 		struct macio_chip *macio = &macio_chips[0];
2836f6d57916SPaul Mackerras 		MACIO_BIS(OHARE_FCR, OH_IOBUS_ENABLE);
2837f6d57916SPaul Mackerras 	} else if (macio_chips[1].type == macio_ohare) {
2838f6d57916SPaul Mackerras 		struct macio_chip *macio = &macio_chips[1];
2839f6d57916SPaul Mackerras 		MACIO_BIS(OHARE_FCR, OH_IOBUS_ENABLE);
2840f6d57916SPaul Mackerras 	}
2841f6d57916SPaul Mackerras 
2842f6d57916SPaul Mackerras #ifdef CONFIG_POWER4
2843f6d57916SPaul Mackerras 	if (macio_chips[0].type == macio_keylargo2) {
2844f6d57916SPaul Mackerras #ifndef CONFIG_SMP
2845f6d57916SPaul Mackerras 		/* On SMP machines running UP, we have the second CPU eating
2846f6d57916SPaul Mackerras 		 * bus cycles. We need to take it off the bus. This is done
2847f6d57916SPaul Mackerras 		 * from pmac_smp for SMP kernels running on one CPU
2848f6d57916SPaul Mackerras 		 */
2849f6d57916SPaul Mackerras 		np = of_find_node_by_type(NULL, "cpu");
2850f6d57916SPaul Mackerras 		if (np != NULL)
2851f6d57916SPaul Mackerras 			np = of_find_node_by_type(np, "cpu");
2852f6d57916SPaul Mackerras 		if (np != NULL) {
2853f6d57916SPaul Mackerras 			g5_phy_disable_cpu1();
2854f6d57916SPaul Mackerras 			of_node_put(np);
2855f6d57916SPaul Mackerras 		}
2856f6d57916SPaul Mackerras #endif /* CONFIG_SMP */
2857f6d57916SPaul Mackerras 		/* Enable GMAC for now for PCI probing. It will be disabled
2858f6d57916SPaul Mackerras 		 * later on after PCI probe
2859f6d57916SPaul Mackerras 		 */
2860f6d57916SPaul Mackerras 		np = of_find_node_by_name(NULL, "ethernet");
2861f6d57916SPaul Mackerras 		while(np) {
2862f6d57916SPaul Mackerras 			if (device_is_compatible(np, "K2-GMAC"))
2863f6d57916SPaul Mackerras 				g5_gmac_enable(np, 0, 1);
2864f6d57916SPaul Mackerras 			np = of_find_node_by_name(np, "ethernet");
2865f6d57916SPaul Mackerras 		}
2866f6d57916SPaul Mackerras 
2867f6d57916SPaul Mackerras 		/* Enable FW before PCI probe. Will be disabled later on
2868f6d57916SPaul Mackerras 		 * Note: We should have a batter way to check that we are
2869f6d57916SPaul Mackerras 		 * dealing with uninorth internal cell and not a PCI cell
2870f6d57916SPaul Mackerras 		 * on the external PCI. The code below works though.
2871f6d57916SPaul Mackerras 		 */
2872f6d57916SPaul Mackerras 		np = of_find_node_by_name(NULL, "firewire");
2873f6d57916SPaul Mackerras 		while(np) {
2874f6d57916SPaul Mackerras 			if (device_is_compatible(np, "pci106b,5811")) {
2875f6d57916SPaul Mackerras 				macio_chips[0].flags |= MACIO_FLAG_FW_SUPPORTED;
2876f6d57916SPaul Mackerras 				g5_fw_enable(np, 0, 1);
2877f6d57916SPaul Mackerras 			}
2878f6d57916SPaul Mackerras 			np = of_find_node_by_name(np, "firewire");
2879f6d57916SPaul Mackerras 		}
2880f6d57916SPaul Mackerras 	}
2881f6d57916SPaul Mackerras #else /* CONFIG_POWER4 */
2882f6d57916SPaul Mackerras 
2883f6d57916SPaul Mackerras 	if (macio_chips[0].type == macio_keylargo ||
2884f6d57916SPaul Mackerras 	    macio_chips[0].type == macio_pangea ||
2885f6d57916SPaul Mackerras 	    macio_chips[0].type == macio_intrepid) {
2886f6d57916SPaul Mackerras 		/* Enable GMAC for now for PCI probing. It will be disabled
2887f6d57916SPaul Mackerras 		 * later on after PCI probe
2888f6d57916SPaul Mackerras 		 */
2889f6d57916SPaul Mackerras 		np = of_find_node_by_name(NULL, "ethernet");
2890f6d57916SPaul Mackerras 		while(np) {
2891f6d57916SPaul Mackerras 			if (np->parent
2892f6d57916SPaul Mackerras 			    && device_is_compatible(np->parent, "uni-north")
2893f6d57916SPaul Mackerras 			    && device_is_compatible(np, "gmac"))
2894f6d57916SPaul Mackerras 				core99_gmac_enable(np, 0, 1);
2895f6d57916SPaul Mackerras 			np = of_find_node_by_name(np, "ethernet");
2896f6d57916SPaul Mackerras 		}
2897f6d57916SPaul Mackerras 
2898f6d57916SPaul Mackerras 		/* Enable FW before PCI probe. Will be disabled later on
2899f6d57916SPaul Mackerras 		 * Note: We should have a batter way to check that we are
2900f6d57916SPaul Mackerras 		 * dealing with uninorth internal cell and not a PCI cell
2901f6d57916SPaul Mackerras 		 * on the external PCI. The code below works though.
2902f6d57916SPaul Mackerras 		 */
2903f6d57916SPaul Mackerras 		np = of_find_node_by_name(NULL, "firewire");
2904f6d57916SPaul Mackerras 		while(np) {
2905f6d57916SPaul Mackerras 			if (np->parent
2906f6d57916SPaul Mackerras 			    && device_is_compatible(np->parent, "uni-north")
2907f6d57916SPaul Mackerras 			    && (device_is_compatible(np, "pci106b,18") ||
2908f6d57916SPaul Mackerras 			        device_is_compatible(np, "pci106b,30") ||
2909f6d57916SPaul Mackerras 			        device_is_compatible(np, "pci11c1,5811"))) {
2910f6d57916SPaul Mackerras 				macio_chips[0].flags |= MACIO_FLAG_FW_SUPPORTED;
2911f6d57916SPaul Mackerras 				core99_firewire_enable(np, 0, 1);
2912f6d57916SPaul Mackerras 			}
2913f6d57916SPaul Mackerras 			np = of_find_node_by_name(np, "firewire");
2914f6d57916SPaul Mackerras 		}
2915f6d57916SPaul Mackerras 
2916f6d57916SPaul Mackerras 		/* Enable ATA-100 before PCI probe. */
2917f6d57916SPaul Mackerras 		np = of_find_node_by_name(NULL, "ata-6");
2918f6d57916SPaul Mackerras 		while(np) {
2919f6d57916SPaul Mackerras 			if (np->parent
2920f6d57916SPaul Mackerras 			    && device_is_compatible(np->parent, "uni-north")
2921f6d57916SPaul Mackerras 			    && device_is_compatible(np, "kauai-ata")) {
2922f6d57916SPaul Mackerras 				core99_ata100_enable(np, 1);
2923f6d57916SPaul Mackerras 			}
2924f6d57916SPaul Mackerras 			np = of_find_node_by_name(np, "ata-6");
2925f6d57916SPaul Mackerras 		}
2926f6d57916SPaul Mackerras 
2927f6d57916SPaul Mackerras 		/* Switch airport off */
2928f6d57916SPaul Mackerras 		np = find_devices("radio");
2929f6d57916SPaul Mackerras 		while(np) {
2930f6d57916SPaul Mackerras 			if (np && np->parent == macio_chips[0].of_node) {
2931f6d57916SPaul Mackerras 				macio_chips[0].flags |= MACIO_FLAG_AIRPORT_ON;
2932f6d57916SPaul Mackerras 				core99_airport_enable(np, 0, 0);
2933f6d57916SPaul Mackerras 			}
2934f6d57916SPaul Mackerras 			np = np->next;
2935f6d57916SPaul Mackerras 		}
2936f6d57916SPaul Mackerras 	}
2937f6d57916SPaul Mackerras 
2938f6d57916SPaul Mackerras 	/* On all machines that support sound PM, switch sound off */
2939f6d57916SPaul Mackerras 	if (macio_chips[0].of_node)
2940f6d57916SPaul Mackerras 		pmac_do_feature_call(PMAC_FTR_SOUND_CHIP_ENABLE,
2941f6d57916SPaul Mackerras 			macio_chips[0].of_node, 0, 0);
2942f6d57916SPaul Mackerras 
2943f6d57916SPaul Mackerras 	/* While on some desktop G3s, we turn it back on */
2944f6d57916SPaul Mackerras 	if (macio_chips[0].of_node && macio_chips[0].type == macio_heathrow
2945f6d57916SPaul Mackerras 		&& (pmac_mb.model_id == PMAC_TYPE_GOSSAMER ||
2946f6d57916SPaul Mackerras 		    pmac_mb.model_id == PMAC_TYPE_SILK)) {
2947f6d57916SPaul Mackerras 		struct macio_chip *macio = &macio_chips[0];
2948f6d57916SPaul Mackerras 		MACIO_BIS(HEATHROW_FCR, HRW_SOUND_CLK_ENABLE);
2949f6d57916SPaul Mackerras 		MACIO_BIC(HEATHROW_FCR, HRW_SOUND_POWER_N);
2950f6d57916SPaul Mackerras 	}
2951f6d57916SPaul Mackerras 
2952f6d57916SPaul Mackerras 	/* Some machine models need the clock chip to be properly setup for
2953f6d57916SPaul Mackerras 	 * clock spreading now. This should be a platform function but we
2954f6d57916SPaul Mackerras 	 * don't do these at the moment
2955f6d57916SPaul Mackerras 	 */
2956f6d57916SPaul Mackerras 	pmac_tweak_clock_spreading(1);
2957f6d57916SPaul Mackerras 
2958f6d57916SPaul Mackerras #endif /* CONFIG_POWER4 */
2959f6d57916SPaul Mackerras 
2960f6d57916SPaul Mackerras 	/* On all machines, switch modem & serial ports off */
2961f6d57916SPaul Mackerras 	np = find_devices("ch-a");
2962f6d57916SPaul Mackerras 	while(np) {
2963f6d57916SPaul Mackerras 		initial_serial_shutdown(np);
2964f6d57916SPaul Mackerras 		np = np->next;
2965f6d57916SPaul Mackerras 	}
2966f6d57916SPaul Mackerras 	np = find_devices("ch-b");
2967f6d57916SPaul Mackerras 	while(np) {
2968f6d57916SPaul Mackerras 		initial_serial_shutdown(np);
2969f6d57916SPaul Mackerras 		np = np->next;
2970f6d57916SPaul Mackerras 	}
2971f6d57916SPaul Mackerras }
2972f6d57916SPaul Mackerras 
2973f6d57916SPaul Mackerras void __init
2974f6d57916SPaul Mackerras pmac_feature_init(void)
2975f6d57916SPaul Mackerras {
2976f6d57916SPaul Mackerras 	/* Detect the UniNorth memory controller */
2977f6d57916SPaul Mackerras 	probe_uninorth();
2978f6d57916SPaul Mackerras 
2979f6d57916SPaul Mackerras 	/* Probe mac-io controllers */
2980f6d57916SPaul Mackerras 	if (probe_macios()) {
2981f6d57916SPaul Mackerras 		printk(KERN_WARNING "No mac-io chip found\n");
2982f6d57916SPaul Mackerras 		return;
2983f6d57916SPaul Mackerras 	}
2984f6d57916SPaul Mackerras 
2985f6d57916SPaul Mackerras 	/* Setup low-level i2c stuffs */
2986f6d57916SPaul Mackerras 	pmac_init_low_i2c();
2987f6d57916SPaul Mackerras 
2988f6d57916SPaul Mackerras 	/* Probe machine type */
2989f6d57916SPaul Mackerras 	if (probe_motherboard())
2990f6d57916SPaul Mackerras 		printk(KERN_WARNING "Unknown PowerMac !\n");
2991f6d57916SPaul Mackerras 
2992f6d57916SPaul Mackerras 	/* Set some initial features (turn off some chips that will
2993f6d57916SPaul Mackerras 	 * be later turned on)
2994f6d57916SPaul Mackerras 	 */
2995f6d57916SPaul Mackerras 	set_initial_features();
2996f6d57916SPaul Mackerras }
2997f6d57916SPaul Mackerras 
2998f6d57916SPaul Mackerras #if 0
2999f6d57916SPaul Mackerras static void dump_HT_speeds(char *name, u32 cfg, u32 frq)
3000f6d57916SPaul Mackerras {
3001f6d57916SPaul Mackerras 	int	freqs[16] = { 200,300,400,500,600,800,1000,0,0,0,0,0,0,0,0,0 };
3002f6d57916SPaul Mackerras 	int	bits[8] = { 8,16,0,32,2,4,0,0 };
3003f6d57916SPaul Mackerras 	int	freq = (frq >> 8) & 0xf;
3004f6d57916SPaul Mackerras 
3005f6d57916SPaul Mackerras 	if (freqs[freq] == 0)
3006f6d57916SPaul Mackerras 		printk("%s: Unknown HT link frequency %x\n", name, freq);
3007f6d57916SPaul Mackerras 	else
3008f6d57916SPaul Mackerras 		printk("%s: %d MHz on main link, (%d in / %d out) bits width\n",
3009f6d57916SPaul Mackerras 		       name, freqs[freq],
3010f6d57916SPaul Mackerras 		       bits[(cfg >> 28) & 0x7], bits[(cfg >> 24) & 0x7]);
3011f6d57916SPaul Mackerras }
3012f6d57916SPaul Mackerras 
3013f6d57916SPaul Mackerras void __init pmac_check_ht_link(void)
3014f6d57916SPaul Mackerras {
3015f6d57916SPaul Mackerras 	u32	ufreq, freq, ucfg, cfg;
3016f6d57916SPaul Mackerras 	struct device_node *pcix_node;
3017f6d57916SPaul Mackerras 	u8	px_bus, px_devfn;
3018f6d57916SPaul Mackerras 	struct pci_controller *px_hose;
3019f6d57916SPaul Mackerras 
3020f6d57916SPaul Mackerras 	(void)in_be32(u3_ht + U3_HT_LINK_COMMAND);
3021f6d57916SPaul Mackerras 	ucfg = cfg = in_be32(u3_ht + U3_HT_LINK_CONFIG);
3022f6d57916SPaul Mackerras 	ufreq = freq = in_be32(u3_ht + U3_HT_LINK_FREQ);
3023f6d57916SPaul Mackerras 	dump_HT_speeds("U3 HyperTransport", cfg, freq);
3024f6d57916SPaul Mackerras 
3025f6d57916SPaul Mackerras 	pcix_node = of_find_compatible_node(NULL, "pci", "pci-x");
3026f6d57916SPaul Mackerras 	if (pcix_node == NULL) {
3027f6d57916SPaul Mackerras 		printk("No PCI-X bridge found\n");
3028f6d57916SPaul Mackerras 		return;
3029f6d57916SPaul Mackerras 	}
3030f6d57916SPaul Mackerras 	if (pci_device_from_OF_node(pcix_node, &px_bus, &px_devfn) != 0) {
3031f6d57916SPaul Mackerras 		printk("PCI-X bridge found but not matched to pci\n");
3032f6d57916SPaul Mackerras 		return;
3033f6d57916SPaul Mackerras 	}
3034f6d57916SPaul Mackerras 	px_hose = pci_find_hose_for_OF_device(pcix_node);
3035f6d57916SPaul Mackerras 	if (px_hose == NULL) {
3036f6d57916SPaul Mackerras 		printk("PCI-X bridge found but not matched to host\n");
3037f6d57916SPaul Mackerras 		return;
3038f6d57916SPaul Mackerras 	}
3039f6d57916SPaul Mackerras 	early_read_config_dword(px_hose, px_bus, px_devfn, 0xc4, &cfg);
3040f6d57916SPaul Mackerras 	early_read_config_dword(px_hose, px_bus, px_devfn, 0xcc, &freq);
3041f6d57916SPaul Mackerras 	dump_HT_speeds("PCI-X HT Uplink", cfg, freq);
3042f6d57916SPaul Mackerras 	early_read_config_dword(px_hose, px_bus, px_devfn, 0xc8, &cfg);
3043f6d57916SPaul Mackerras 	early_read_config_dword(px_hose, px_bus, px_devfn, 0xd0, &freq);
3044f6d57916SPaul Mackerras 	dump_HT_speeds("PCI-X HT Downlink", cfg, freq);
3045f6d57916SPaul Mackerras }
304635499c01SPaul Mackerras #endif /* 0 */
3047f6d57916SPaul Mackerras 
3048f6d57916SPaul Mackerras /*
3049f6d57916SPaul Mackerras  * Early video resume hook
3050f6d57916SPaul Mackerras  */
3051f6d57916SPaul Mackerras 
3052f6d57916SPaul Mackerras static void (*pmac_early_vresume_proc)(void *data);
3053f6d57916SPaul Mackerras static void *pmac_early_vresume_data;
3054f6d57916SPaul Mackerras 
3055f6d57916SPaul Mackerras void pmac_set_early_video_resume(void (*proc)(void *data), void *data)
3056f6d57916SPaul Mackerras {
3057f6d57916SPaul Mackerras 	if (_machine != _MACH_Pmac)
3058f6d57916SPaul Mackerras 		return;
3059f6d57916SPaul Mackerras 	preempt_disable();
3060f6d57916SPaul Mackerras 	pmac_early_vresume_proc = proc;
3061f6d57916SPaul Mackerras 	pmac_early_vresume_data = data;
3062f6d57916SPaul Mackerras 	preempt_enable();
3063f6d57916SPaul Mackerras }
3064f6d57916SPaul Mackerras EXPORT_SYMBOL(pmac_set_early_video_resume);
3065f6d57916SPaul Mackerras 
3066f6d57916SPaul Mackerras void pmac_call_early_video_resume(void)
3067f6d57916SPaul Mackerras {
3068f6d57916SPaul Mackerras 	if (pmac_early_vresume_proc)
3069f6d57916SPaul Mackerras 		pmac_early_vresume_proc(pmac_early_vresume_data);
3070f6d57916SPaul Mackerras }
3071f6d57916SPaul Mackerras 
3072f6d57916SPaul Mackerras /*
3073f6d57916SPaul Mackerras  * AGP related suspend/resume code
3074f6d57916SPaul Mackerras  */
3075f6d57916SPaul Mackerras 
3076f6d57916SPaul Mackerras static struct pci_dev *pmac_agp_bridge;
3077f6d57916SPaul Mackerras static int (*pmac_agp_suspend)(struct pci_dev *bridge);
3078f6d57916SPaul Mackerras static int (*pmac_agp_resume)(struct pci_dev *bridge);
3079f6d57916SPaul Mackerras 
3080f6d57916SPaul Mackerras void pmac_register_agp_pm(struct pci_dev *bridge,
3081f6d57916SPaul Mackerras 				 int (*suspend)(struct pci_dev *bridge),
3082f6d57916SPaul Mackerras 				 int (*resume)(struct pci_dev *bridge))
3083f6d57916SPaul Mackerras {
3084f6d57916SPaul Mackerras 	if (suspend || resume) {
3085f6d57916SPaul Mackerras 		pmac_agp_bridge = bridge;
3086f6d57916SPaul Mackerras 		pmac_agp_suspend = suspend;
3087f6d57916SPaul Mackerras 		pmac_agp_resume = resume;
3088f6d57916SPaul Mackerras 		return;
3089f6d57916SPaul Mackerras 	}
3090f6d57916SPaul Mackerras 	if (bridge != pmac_agp_bridge)
3091f6d57916SPaul Mackerras 		return;
3092f6d57916SPaul Mackerras 	pmac_agp_suspend = pmac_agp_resume = NULL;
3093f6d57916SPaul Mackerras 	return;
3094f6d57916SPaul Mackerras }
3095f6d57916SPaul Mackerras EXPORT_SYMBOL(pmac_register_agp_pm);
3096f6d57916SPaul Mackerras 
3097f6d57916SPaul Mackerras void pmac_suspend_agp_for_card(struct pci_dev *dev)
3098f6d57916SPaul Mackerras {
3099f6d57916SPaul Mackerras 	if (pmac_agp_bridge == NULL || pmac_agp_suspend == NULL)
3100f6d57916SPaul Mackerras 		return;
3101f6d57916SPaul Mackerras 	if (pmac_agp_bridge->bus != dev->bus)
3102f6d57916SPaul Mackerras 		return;
3103f6d57916SPaul Mackerras 	pmac_agp_suspend(pmac_agp_bridge);
3104f6d57916SPaul Mackerras }
3105f6d57916SPaul Mackerras EXPORT_SYMBOL(pmac_suspend_agp_for_card);
3106f6d57916SPaul Mackerras 
3107f6d57916SPaul Mackerras void pmac_resume_agp_for_card(struct pci_dev *dev)
3108f6d57916SPaul Mackerras {
3109f6d57916SPaul Mackerras 	if (pmac_agp_bridge == NULL || pmac_agp_resume == NULL)
3110f6d57916SPaul Mackerras 		return;
3111f6d57916SPaul Mackerras 	if (pmac_agp_bridge->bus != dev->bus)
3112f6d57916SPaul Mackerras 		return;
3113f6d57916SPaul Mackerras 	pmac_agp_resume(pmac_agp_bridge);
3114f6d57916SPaul Mackerras }
3115f6d57916SPaul Mackerras EXPORT_SYMBOL(pmac_resume_agp_for_card);
3116