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