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