162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-or-later
262306a36Sopenharmony_ci/*
362306a36Sopenharmony_ci *  Copyright (C) 1996-2001 Paul Mackerras (paulus@cs.anu.edu.au)
462306a36Sopenharmony_ci *                          Ben. Herrenschmidt (benh@kernel.crashing.org)
562306a36Sopenharmony_ci *
662306a36Sopenharmony_ci *  TODO:
762306a36Sopenharmony_ci *
862306a36Sopenharmony_ci *   - Replace mdelay with some schedule loop if possible
962306a36Sopenharmony_ci *   - Shorten some obfuscated delays on some routines (like modem
1062306a36Sopenharmony_ci *     power)
1162306a36Sopenharmony_ci *   - Refcount some clocks (see darwin)
1262306a36Sopenharmony_ci *   - Split split split...
1362306a36Sopenharmony_ci */
1462306a36Sopenharmony_ci#include <linux/types.h>
1562306a36Sopenharmony_ci#include <linux/init.h>
1662306a36Sopenharmony_ci#include <linux/delay.h>
1762306a36Sopenharmony_ci#include <linux/kernel.h>
1862306a36Sopenharmony_ci#include <linux/sched.h>
1962306a36Sopenharmony_ci#include <linux/of.h>
2062306a36Sopenharmony_ci#include <linux/of_address.h>
2162306a36Sopenharmony_ci#include <linux/spinlock.h>
2262306a36Sopenharmony_ci#include <linux/adb.h>
2362306a36Sopenharmony_ci#include <linux/pmu.h>
2462306a36Sopenharmony_ci#include <linux/ioport.h>
2562306a36Sopenharmony_ci#include <linux/export.h>
2662306a36Sopenharmony_ci#include <linux/pci.h>
2762306a36Sopenharmony_ci#include <asm/sections.h>
2862306a36Sopenharmony_ci#include <asm/errno.h>
2962306a36Sopenharmony_ci#include <asm/ohare.h>
3062306a36Sopenharmony_ci#include <asm/heathrow.h>
3162306a36Sopenharmony_ci#include <asm/keylargo.h>
3262306a36Sopenharmony_ci#include <asm/uninorth.h>
3362306a36Sopenharmony_ci#include <asm/io.h>
3462306a36Sopenharmony_ci#include <asm/machdep.h>
3562306a36Sopenharmony_ci#include <asm/pmac_feature.h>
3662306a36Sopenharmony_ci#include <asm/dbdma.h>
3762306a36Sopenharmony_ci#include <asm/pci-bridge.h>
3862306a36Sopenharmony_ci#include <asm/pmac_low_i2c.h>
3962306a36Sopenharmony_ci
4062306a36Sopenharmony_ci#include "pmac.h"
4162306a36Sopenharmony_ci
4262306a36Sopenharmony_ci#undef DEBUG_FEATURE
4362306a36Sopenharmony_ci
4462306a36Sopenharmony_ci#ifdef DEBUG_FEATURE
4562306a36Sopenharmony_ci#define DBG(fmt...) printk(KERN_DEBUG fmt)
4662306a36Sopenharmony_ci#else
4762306a36Sopenharmony_ci#define DBG(fmt...)
4862306a36Sopenharmony_ci#endif
4962306a36Sopenharmony_ci
5062306a36Sopenharmony_ci#ifdef CONFIG_PPC_BOOK3S_32
5162306a36Sopenharmony_ciextern int powersave_lowspeed;
5262306a36Sopenharmony_ci#endif
5362306a36Sopenharmony_ci
5462306a36Sopenharmony_ciextern int powersave_nap;
5562306a36Sopenharmony_ciextern struct device_node *k2_skiplist[2];
5662306a36Sopenharmony_ci
5762306a36Sopenharmony_ci/*
5862306a36Sopenharmony_ci * We use a single global lock to protect accesses. Each driver has
5962306a36Sopenharmony_ci * to take care of its own locking
6062306a36Sopenharmony_ci */
6162306a36Sopenharmony_ciDEFINE_RAW_SPINLOCK(feature_lock);
6262306a36Sopenharmony_ci
6362306a36Sopenharmony_ci#define LOCK(flags)	raw_spin_lock_irqsave(&feature_lock, flags);
6462306a36Sopenharmony_ci#define UNLOCK(flags)	raw_spin_unlock_irqrestore(&feature_lock, flags);
6562306a36Sopenharmony_ci
6662306a36Sopenharmony_ci
6762306a36Sopenharmony_ci/*
6862306a36Sopenharmony_ci * Instance of some macio stuffs
6962306a36Sopenharmony_ci */
7062306a36Sopenharmony_cistruct macio_chip macio_chips[MAX_MACIO_CHIPS];
7162306a36Sopenharmony_ci
7262306a36Sopenharmony_cistruct macio_chip *macio_find(struct device_node *child, int type)
7362306a36Sopenharmony_ci{
7462306a36Sopenharmony_ci	while(child) {
7562306a36Sopenharmony_ci		int	i;
7662306a36Sopenharmony_ci
7762306a36Sopenharmony_ci		for (i=0; i < MAX_MACIO_CHIPS && macio_chips[i].of_node; i++)
7862306a36Sopenharmony_ci			if (child == macio_chips[i].of_node &&
7962306a36Sopenharmony_ci			    (!type || macio_chips[i].type == type))
8062306a36Sopenharmony_ci				return &macio_chips[i];
8162306a36Sopenharmony_ci		child = child->parent;
8262306a36Sopenharmony_ci	}
8362306a36Sopenharmony_ci	return NULL;
8462306a36Sopenharmony_ci}
8562306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(macio_find);
8662306a36Sopenharmony_ci
8762306a36Sopenharmony_cistatic const char *macio_names[] =
8862306a36Sopenharmony_ci{
8962306a36Sopenharmony_ci	"Unknown",
9062306a36Sopenharmony_ci	"Grand Central",
9162306a36Sopenharmony_ci	"OHare",
9262306a36Sopenharmony_ci	"OHareII",
9362306a36Sopenharmony_ci	"Heathrow",
9462306a36Sopenharmony_ci	"Gatwick",
9562306a36Sopenharmony_ci	"Paddington",
9662306a36Sopenharmony_ci	"Keylargo",
9762306a36Sopenharmony_ci	"Pangea",
9862306a36Sopenharmony_ci	"Intrepid",
9962306a36Sopenharmony_ci	"K2",
10062306a36Sopenharmony_ci	"Shasta",
10162306a36Sopenharmony_ci};
10262306a36Sopenharmony_ci
10362306a36Sopenharmony_ci
10462306a36Sopenharmony_cistruct device_node *uninorth_node;
10562306a36Sopenharmony_ciu32 __iomem *uninorth_base;
10662306a36Sopenharmony_ci
10762306a36Sopenharmony_cistatic u32 uninorth_rev;
10862306a36Sopenharmony_cistatic int uninorth_maj;
10962306a36Sopenharmony_cistatic void __iomem *u3_ht_base;
11062306a36Sopenharmony_ci
11162306a36Sopenharmony_ci/*
11262306a36Sopenharmony_ci * For each motherboard family, we have a table of functions pointers
11362306a36Sopenharmony_ci * that handle the various features.
11462306a36Sopenharmony_ci */
11562306a36Sopenharmony_ci
11662306a36Sopenharmony_citypedef long (*feature_call)(struct device_node *node, long param, long value);
11762306a36Sopenharmony_ci
11862306a36Sopenharmony_cistruct feature_table_entry {
11962306a36Sopenharmony_ci	unsigned int	selector;
12062306a36Sopenharmony_ci	feature_call	function;
12162306a36Sopenharmony_ci};
12262306a36Sopenharmony_ci
12362306a36Sopenharmony_cistruct pmac_mb_def
12462306a36Sopenharmony_ci{
12562306a36Sopenharmony_ci	const char*			model_string;
12662306a36Sopenharmony_ci	const char*			model_name;
12762306a36Sopenharmony_ci	int				model_id;
12862306a36Sopenharmony_ci	struct feature_table_entry*	features;
12962306a36Sopenharmony_ci	unsigned long			board_flags;
13062306a36Sopenharmony_ci};
13162306a36Sopenharmony_cistatic struct pmac_mb_def pmac_mb;
13262306a36Sopenharmony_ci
13362306a36Sopenharmony_ci/*
13462306a36Sopenharmony_ci * Here are the chip specific feature functions
13562306a36Sopenharmony_ci */
13662306a36Sopenharmony_ci
13762306a36Sopenharmony_ci#ifndef CONFIG_PPC64
13862306a36Sopenharmony_ci
13962306a36Sopenharmony_cistatic int simple_feature_tweak(struct device_node *node, int type, int reg,
14062306a36Sopenharmony_ci				u32 mask, int value)
14162306a36Sopenharmony_ci{
14262306a36Sopenharmony_ci	struct macio_chip*	macio;
14362306a36Sopenharmony_ci	unsigned long		flags;
14462306a36Sopenharmony_ci
14562306a36Sopenharmony_ci	macio = macio_find(node, type);
14662306a36Sopenharmony_ci	if (!macio)
14762306a36Sopenharmony_ci		return -ENODEV;
14862306a36Sopenharmony_ci	LOCK(flags);
14962306a36Sopenharmony_ci	if (value)
15062306a36Sopenharmony_ci		MACIO_BIS(reg, mask);
15162306a36Sopenharmony_ci	else
15262306a36Sopenharmony_ci		MACIO_BIC(reg, mask);
15362306a36Sopenharmony_ci	(void)MACIO_IN32(reg);
15462306a36Sopenharmony_ci	UNLOCK(flags);
15562306a36Sopenharmony_ci
15662306a36Sopenharmony_ci	return 0;
15762306a36Sopenharmony_ci}
15862306a36Sopenharmony_ci
15962306a36Sopenharmony_cistatic long ohare_htw_scc_enable(struct device_node *node, long param,
16062306a36Sopenharmony_ci				 long value)
16162306a36Sopenharmony_ci{
16262306a36Sopenharmony_ci	struct macio_chip*	macio;
16362306a36Sopenharmony_ci	unsigned long		chan_mask;
16462306a36Sopenharmony_ci	unsigned long		fcr;
16562306a36Sopenharmony_ci	unsigned long		flags;
16662306a36Sopenharmony_ci	int			htw, trans;
16762306a36Sopenharmony_ci	unsigned long		rmask;
16862306a36Sopenharmony_ci
16962306a36Sopenharmony_ci	macio = macio_find(node, 0);
17062306a36Sopenharmony_ci	if (!macio)
17162306a36Sopenharmony_ci		return -ENODEV;
17262306a36Sopenharmony_ci	if (of_node_name_eq(node, "ch-a"))
17362306a36Sopenharmony_ci		chan_mask = MACIO_FLAG_SCCA_ON;
17462306a36Sopenharmony_ci	else if (of_node_name_eq(node, "ch-b"))
17562306a36Sopenharmony_ci		chan_mask = MACIO_FLAG_SCCB_ON;
17662306a36Sopenharmony_ci	else
17762306a36Sopenharmony_ci		return -ENODEV;
17862306a36Sopenharmony_ci
17962306a36Sopenharmony_ci	htw = (macio->type == macio_heathrow || macio->type == macio_paddington
18062306a36Sopenharmony_ci		|| macio->type == macio_gatwick);
18162306a36Sopenharmony_ci	/* On these machines, the HRW_SCC_TRANS_EN_N bit mustn't be touched */
18262306a36Sopenharmony_ci	trans = (pmac_mb.model_id != PMAC_TYPE_YOSEMITE &&
18362306a36Sopenharmony_ci		 pmac_mb.model_id != PMAC_TYPE_YIKES);
18462306a36Sopenharmony_ci	if (value) {
18562306a36Sopenharmony_ci#ifdef CONFIG_ADB_PMU
18662306a36Sopenharmony_ci		if ((param & 0xfff) == PMAC_SCC_IRDA)
18762306a36Sopenharmony_ci			pmu_enable_irled(1);
18862306a36Sopenharmony_ci#endif /* CONFIG_ADB_PMU */
18962306a36Sopenharmony_ci		LOCK(flags);
19062306a36Sopenharmony_ci		fcr = MACIO_IN32(OHARE_FCR);
19162306a36Sopenharmony_ci		/* Check if scc cell need enabling */
19262306a36Sopenharmony_ci		if (!(fcr & OH_SCC_ENABLE)) {
19362306a36Sopenharmony_ci			fcr |= OH_SCC_ENABLE;
19462306a36Sopenharmony_ci			if (htw) {
19562306a36Sopenharmony_ci				/* Side effect: this will also power up the
19662306a36Sopenharmony_ci				 * modem, but it's too messy to figure out on which
19762306a36Sopenharmony_ci				 * ports this controls the transceiver and on which
19862306a36Sopenharmony_ci				 * it controls the modem
19962306a36Sopenharmony_ci				 */
20062306a36Sopenharmony_ci				if (trans)
20162306a36Sopenharmony_ci					fcr &= ~HRW_SCC_TRANS_EN_N;
20262306a36Sopenharmony_ci				MACIO_OUT32(OHARE_FCR, fcr);
20362306a36Sopenharmony_ci				fcr |= (rmask = HRW_RESET_SCC);
20462306a36Sopenharmony_ci				MACIO_OUT32(OHARE_FCR, fcr);
20562306a36Sopenharmony_ci			} else {
20662306a36Sopenharmony_ci				fcr |= (rmask = OH_SCC_RESET);
20762306a36Sopenharmony_ci				MACIO_OUT32(OHARE_FCR, fcr);
20862306a36Sopenharmony_ci			}
20962306a36Sopenharmony_ci			UNLOCK(flags);
21062306a36Sopenharmony_ci			(void)MACIO_IN32(OHARE_FCR);
21162306a36Sopenharmony_ci			mdelay(15);
21262306a36Sopenharmony_ci			LOCK(flags);
21362306a36Sopenharmony_ci			fcr &= ~rmask;
21462306a36Sopenharmony_ci			MACIO_OUT32(OHARE_FCR, fcr);
21562306a36Sopenharmony_ci		}
21662306a36Sopenharmony_ci		if (chan_mask & MACIO_FLAG_SCCA_ON)
21762306a36Sopenharmony_ci			fcr |= OH_SCCA_IO;
21862306a36Sopenharmony_ci		if (chan_mask & MACIO_FLAG_SCCB_ON)
21962306a36Sopenharmony_ci			fcr |= OH_SCCB_IO;
22062306a36Sopenharmony_ci		MACIO_OUT32(OHARE_FCR, fcr);
22162306a36Sopenharmony_ci		macio->flags |= chan_mask;
22262306a36Sopenharmony_ci		UNLOCK(flags);
22362306a36Sopenharmony_ci		if (param & PMAC_SCC_FLAG_XMON)
22462306a36Sopenharmony_ci			macio->flags |= MACIO_FLAG_SCC_LOCKED;
22562306a36Sopenharmony_ci	} else {
22662306a36Sopenharmony_ci		if (macio->flags & MACIO_FLAG_SCC_LOCKED)
22762306a36Sopenharmony_ci			return -EPERM;
22862306a36Sopenharmony_ci		LOCK(flags);
22962306a36Sopenharmony_ci		fcr = MACIO_IN32(OHARE_FCR);
23062306a36Sopenharmony_ci		if (chan_mask & MACIO_FLAG_SCCA_ON)
23162306a36Sopenharmony_ci			fcr &= ~OH_SCCA_IO;
23262306a36Sopenharmony_ci		if (chan_mask & MACIO_FLAG_SCCB_ON)
23362306a36Sopenharmony_ci			fcr &= ~OH_SCCB_IO;
23462306a36Sopenharmony_ci		MACIO_OUT32(OHARE_FCR, fcr);
23562306a36Sopenharmony_ci		if ((fcr & (OH_SCCA_IO | OH_SCCB_IO)) == 0) {
23662306a36Sopenharmony_ci			fcr &= ~OH_SCC_ENABLE;
23762306a36Sopenharmony_ci			if (htw && trans)
23862306a36Sopenharmony_ci				fcr |= HRW_SCC_TRANS_EN_N;
23962306a36Sopenharmony_ci			MACIO_OUT32(OHARE_FCR, fcr);
24062306a36Sopenharmony_ci		}
24162306a36Sopenharmony_ci		macio->flags &= ~(chan_mask);
24262306a36Sopenharmony_ci		UNLOCK(flags);
24362306a36Sopenharmony_ci		mdelay(10);
24462306a36Sopenharmony_ci#ifdef CONFIG_ADB_PMU
24562306a36Sopenharmony_ci		if ((param & 0xfff) == PMAC_SCC_IRDA)
24662306a36Sopenharmony_ci			pmu_enable_irled(0);
24762306a36Sopenharmony_ci#endif /* CONFIG_ADB_PMU */
24862306a36Sopenharmony_ci	}
24962306a36Sopenharmony_ci	return 0;
25062306a36Sopenharmony_ci}
25162306a36Sopenharmony_ci
25262306a36Sopenharmony_cistatic long ohare_floppy_enable(struct device_node *node, long param,
25362306a36Sopenharmony_ci				long value)
25462306a36Sopenharmony_ci{
25562306a36Sopenharmony_ci	return simple_feature_tweak(node, macio_ohare,
25662306a36Sopenharmony_ci		OHARE_FCR, OH_FLOPPY_ENABLE, value);
25762306a36Sopenharmony_ci}
25862306a36Sopenharmony_ci
25962306a36Sopenharmony_cistatic long ohare_mesh_enable(struct device_node *node, long param, long value)
26062306a36Sopenharmony_ci{
26162306a36Sopenharmony_ci	return simple_feature_tweak(node, macio_ohare,
26262306a36Sopenharmony_ci		OHARE_FCR, OH_MESH_ENABLE, value);
26362306a36Sopenharmony_ci}
26462306a36Sopenharmony_ci
26562306a36Sopenharmony_cistatic long ohare_ide_enable(struct device_node *node, long param, long value)
26662306a36Sopenharmony_ci{
26762306a36Sopenharmony_ci	switch(param) {
26862306a36Sopenharmony_ci	case 0:
26962306a36Sopenharmony_ci		/* For some reason, setting the bit in set_initial_features()
27062306a36Sopenharmony_ci		 * doesn't stick. I'm still investigating... --BenH.
27162306a36Sopenharmony_ci		 */
27262306a36Sopenharmony_ci		if (value)
27362306a36Sopenharmony_ci			simple_feature_tweak(node, macio_ohare,
27462306a36Sopenharmony_ci				OHARE_FCR, OH_IOBUS_ENABLE, 1);
27562306a36Sopenharmony_ci		return simple_feature_tweak(node, macio_ohare,
27662306a36Sopenharmony_ci			OHARE_FCR, OH_IDE0_ENABLE, value);
27762306a36Sopenharmony_ci	case 1:
27862306a36Sopenharmony_ci		return simple_feature_tweak(node, macio_ohare,
27962306a36Sopenharmony_ci			OHARE_FCR, OH_BAY_IDE_ENABLE, value);
28062306a36Sopenharmony_ci	default:
28162306a36Sopenharmony_ci		return -ENODEV;
28262306a36Sopenharmony_ci	}
28362306a36Sopenharmony_ci}
28462306a36Sopenharmony_ci
28562306a36Sopenharmony_cistatic long ohare_ide_reset(struct device_node *node, long param, long value)
28662306a36Sopenharmony_ci{
28762306a36Sopenharmony_ci	switch(param) {
28862306a36Sopenharmony_ci	case 0:
28962306a36Sopenharmony_ci		return simple_feature_tweak(node, macio_ohare,
29062306a36Sopenharmony_ci			OHARE_FCR, OH_IDE0_RESET_N, !value);
29162306a36Sopenharmony_ci	case 1:
29262306a36Sopenharmony_ci		return simple_feature_tweak(node, macio_ohare,
29362306a36Sopenharmony_ci			OHARE_FCR, OH_IDE1_RESET_N, !value);
29462306a36Sopenharmony_ci	default:
29562306a36Sopenharmony_ci		return -ENODEV;
29662306a36Sopenharmony_ci	}
29762306a36Sopenharmony_ci}
29862306a36Sopenharmony_ci
29962306a36Sopenharmony_cistatic long ohare_sleep_state(struct device_node *node, long param, long value)
30062306a36Sopenharmony_ci{
30162306a36Sopenharmony_ci	struct macio_chip*	macio = &macio_chips[0];
30262306a36Sopenharmony_ci
30362306a36Sopenharmony_ci	if ((pmac_mb.board_flags & PMAC_MB_CAN_SLEEP) == 0)
30462306a36Sopenharmony_ci		return -EPERM;
30562306a36Sopenharmony_ci	if (value == 1) {
30662306a36Sopenharmony_ci		MACIO_BIC(OHARE_FCR, OH_IOBUS_ENABLE);
30762306a36Sopenharmony_ci	} else if (value == 0) {
30862306a36Sopenharmony_ci		MACIO_BIS(OHARE_FCR, OH_IOBUS_ENABLE);
30962306a36Sopenharmony_ci	}
31062306a36Sopenharmony_ci
31162306a36Sopenharmony_ci	return 0;
31262306a36Sopenharmony_ci}
31362306a36Sopenharmony_ci
31462306a36Sopenharmony_cistatic long heathrow_modem_enable(struct device_node *node, long param,
31562306a36Sopenharmony_ci				  long value)
31662306a36Sopenharmony_ci{
31762306a36Sopenharmony_ci	struct macio_chip*	macio;
31862306a36Sopenharmony_ci	u8			gpio;
31962306a36Sopenharmony_ci	unsigned long		flags;
32062306a36Sopenharmony_ci
32162306a36Sopenharmony_ci	macio = macio_find(node, macio_unknown);
32262306a36Sopenharmony_ci	if (!macio)
32362306a36Sopenharmony_ci		return -ENODEV;
32462306a36Sopenharmony_ci	gpio = MACIO_IN8(HRW_GPIO_MODEM_RESET) & ~1;
32562306a36Sopenharmony_ci	if (!value) {
32662306a36Sopenharmony_ci		LOCK(flags);
32762306a36Sopenharmony_ci		MACIO_OUT8(HRW_GPIO_MODEM_RESET, gpio);
32862306a36Sopenharmony_ci		UNLOCK(flags);
32962306a36Sopenharmony_ci		(void)MACIO_IN8(HRW_GPIO_MODEM_RESET);
33062306a36Sopenharmony_ci		mdelay(250);
33162306a36Sopenharmony_ci	}
33262306a36Sopenharmony_ci	if (pmac_mb.model_id != PMAC_TYPE_YOSEMITE &&
33362306a36Sopenharmony_ci	    pmac_mb.model_id != PMAC_TYPE_YIKES) {
33462306a36Sopenharmony_ci		LOCK(flags);
33562306a36Sopenharmony_ci		if (value)
33662306a36Sopenharmony_ci			MACIO_BIC(HEATHROW_FCR, HRW_SCC_TRANS_EN_N);
33762306a36Sopenharmony_ci		else
33862306a36Sopenharmony_ci			MACIO_BIS(HEATHROW_FCR, HRW_SCC_TRANS_EN_N);
33962306a36Sopenharmony_ci		UNLOCK(flags);
34062306a36Sopenharmony_ci		(void)MACIO_IN32(HEATHROW_FCR);
34162306a36Sopenharmony_ci		mdelay(250);
34262306a36Sopenharmony_ci	}
34362306a36Sopenharmony_ci	if (value) {
34462306a36Sopenharmony_ci		LOCK(flags);
34562306a36Sopenharmony_ci		MACIO_OUT8(HRW_GPIO_MODEM_RESET, gpio | 1);
34662306a36Sopenharmony_ci		(void)MACIO_IN8(HRW_GPIO_MODEM_RESET);
34762306a36Sopenharmony_ci		UNLOCK(flags); mdelay(250); LOCK(flags);
34862306a36Sopenharmony_ci		MACIO_OUT8(HRW_GPIO_MODEM_RESET, gpio);
34962306a36Sopenharmony_ci		(void)MACIO_IN8(HRW_GPIO_MODEM_RESET);
35062306a36Sopenharmony_ci		UNLOCK(flags); mdelay(250); LOCK(flags);
35162306a36Sopenharmony_ci		MACIO_OUT8(HRW_GPIO_MODEM_RESET, gpio | 1);
35262306a36Sopenharmony_ci		(void)MACIO_IN8(HRW_GPIO_MODEM_RESET);
35362306a36Sopenharmony_ci		UNLOCK(flags); mdelay(250);
35462306a36Sopenharmony_ci	}
35562306a36Sopenharmony_ci	return 0;
35662306a36Sopenharmony_ci}
35762306a36Sopenharmony_ci
35862306a36Sopenharmony_cistatic long heathrow_floppy_enable(struct device_node *node, long param,
35962306a36Sopenharmony_ci				   long value)
36062306a36Sopenharmony_ci{
36162306a36Sopenharmony_ci	return simple_feature_tweak(node, macio_unknown,
36262306a36Sopenharmony_ci		HEATHROW_FCR,
36362306a36Sopenharmony_ci		HRW_SWIM_ENABLE|HRW_BAY_FLOPPY_ENABLE,
36462306a36Sopenharmony_ci		value);
36562306a36Sopenharmony_ci}
36662306a36Sopenharmony_ci
36762306a36Sopenharmony_cistatic long heathrow_mesh_enable(struct device_node *node, long param,
36862306a36Sopenharmony_ci				 long value)
36962306a36Sopenharmony_ci{
37062306a36Sopenharmony_ci	struct macio_chip*	macio;
37162306a36Sopenharmony_ci	unsigned long		flags;
37262306a36Sopenharmony_ci
37362306a36Sopenharmony_ci	macio = macio_find(node, macio_unknown);
37462306a36Sopenharmony_ci	if (!macio)
37562306a36Sopenharmony_ci		return -ENODEV;
37662306a36Sopenharmony_ci	LOCK(flags);
37762306a36Sopenharmony_ci	/* Set clear mesh cell enable */
37862306a36Sopenharmony_ci	if (value)
37962306a36Sopenharmony_ci		MACIO_BIS(HEATHROW_FCR, HRW_MESH_ENABLE);
38062306a36Sopenharmony_ci	else
38162306a36Sopenharmony_ci		MACIO_BIC(HEATHROW_FCR, HRW_MESH_ENABLE);
38262306a36Sopenharmony_ci	(void)MACIO_IN32(HEATHROW_FCR);
38362306a36Sopenharmony_ci	udelay(10);
38462306a36Sopenharmony_ci	/* Set/Clear termination power */
38562306a36Sopenharmony_ci	if (value)
38662306a36Sopenharmony_ci		MACIO_BIC(HEATHROW_MBCR, 0x04000000);
38762306a36Sopenharmony_ci	else
38862306a36Sopenharmony_ci		MACIO_BIS(HEATHROW_MBCR, 0x04000000);
38962306a36Sopenharmony_ci	(void)MACIO_IN32(HEATHROW_MBCR);
39062306a36Sopenharmony_ci	udelay(10);
39162306a36Sopenharmony_ci	UNLOCK(flags);
39262306a36Sopenharmony_ci
39362306a36Sopenharmony_ci	return 0;
39462306a36Sopenharmony_ci}
39562306a36Sopenharmony_ci
39662306a36Sopenharmony_cistatic long heathrow_ide_enable(struct device_node *node, long param,
39762306a36Sopenharmony_ci				long value)
39862306a36Sopenharmony_ci{
39962306a36Sopenharmony_ci	switch(param) {
40062306a36Sopenharmony_ci	case 0:
40162306a36Sopenharmony_ci		return simple_feature_tweak(node, macio_unknown,
40262306a36Sopenharmony_ci			HEATHROW_FCR, HRW_IDE0_ENABLE, value);
40362306a36Sopenharmony_ci	case 1:
40462306a36Sopenharmony_ci		return simple_feature_tweak(node, macio_unknown,
40562306a36Sopenharmony_ci			HEATHROW_FCR, HRW_BAY_IDE_ENABLE, value);
40662306a36Sopenharmony_ci	default:
40762306a36Sopenharmony_ci		return -ENODEV;
40862306a36Sopenharmony_ci	}
40962306a36Sopenharmony_ci}
41062306a36Sopenharmony_ci
41162306a36Sopenharmony_cistatic long heathrow_ide_reset(struct device_node *node, long param,
41262306a36Sopenharmony_ci			       long value)
41362306a36Sopenharmony_ci{
41462306a36Sopenharmony_ci	switch(param) {
41562306a36Sopenharmony_ci	case 0:
41662306a36Sopenharmony_ci		return simple_feature_tweak(node, macio_unknown,
41762306a36Sopenharmony_ci			HEATHROW_FCR, HRW_IDE0_RESET_N, !value);
41862306a36Sopenharmony_ci	case 1:
41962306a36Sopenharmony_ci		return simple_feature_tweak(node, macio_unknown,
42062306a36Sopenharmony_ci			HEATHROW_FCR, HRW_IDE1_RESET_N, !value);
42162306a36Sopenharmony_ci	default:
42262306a36Sopenharmony_ci		return -ENODEV;
42362306a36Sopenharmony_ci	}
42462306a36Sopenharmony_ci}
42562306a36Sopenharmony_ci
42662306a36Sopenharmony_cistatic long heathrow_bmac_enable(struct device_node *node, long param,
42762306a36Sopenharmony_ci				 long value)
42862306a36Sopenharmony_ci{
42962306a36Sopenharmony_ci	struct macio_chip*	macio;
43062306a36Sopenharmony_ci	unsigned long		flags;
43162306a36Sopenharmony_ci
43262306a36Sopenharmony_ci	macio = macio_find(node, 0);
43362306a36Sopenharmony_ci	if (!macio)
43462306a36Sopenharmony_ci		return -ENODEV;
43562306a36Sopenharmony_ci	if (value) {
43662306a36Sopenharmony_ci		LOCK(flags);
43762306a36Sopenharmony_ci		MACIO_BIS(HEATHROW_FCR, HRW_BMAC_IO_ENABLE);
43862306a36Sopenharmony_ci		MACIO_BIS(HEATHROW_FCR, HRW_BMAC_RESET);
43962306a36Sopenharmony_ci		UNLOCK(flags);
44062306a36Sopenharmony_ci		(void)MACIO_IN32(HEATHROW_FCR);
44162306a36Sopenharmony_ci		mdelay(10);
44262306a36Sopenharmony_ci		LOCK(flags);
44362306a36Sopenharmony_ci		MACIO_BIC(HEATHROW_FCR, HRW_BMAC_RESET);
44462306a36Sopenharmony_ci		UNLOCK(flags);
44562306a36Sopenharmony_ci		(void)MACIO_IN32(HEATHROW_FCR);
44662306a36Sopenharmony_ci		mdelay(10);
44762306a36Sopenharmony_ci	} else {
44862306a36Sopenharmony_ci		LOCK(flags);
44962306a36Sopenharmony_ci		MACIO_BIC(HEATHROW_FCR, HRW_BMAC_IO_ENABLE);
45062306a36Sopenharmony_ci		UNLOCK(flags);
45162306a36Sopenharmony_ci	}
45262306a36Sopenharmony_ci	return 0;
45362306a36Sopenharmony_ci}
45462306a36Sopenharmony_ci
45562306a36Sopenharmony_cistatic long heathrow_sound_enable(struct device_node *node, long param,
45662306a36Sopenharmony_ci				  long value)
45762306a36Sopenharmony_ci{
45862306a36Sopenharmony_ci	struct macio_chip*	macio;
45962306a36Sopenharmony_ci	unsigned long		flags;
46062306a36Sopenharmony_ci
46162306a36Sopenharmony_ci	/* B&W G3 and Yikes don't support that properly (the
46262306a36Sopenharmony_ci	 * sound appear to never come back after being shut down).
46362306a36Sopenharmony_ci	 */
46462306a36Sopenharmony_ci	if (pmac_mb.model_id == PMAC_TYPE_YOSEMITE ||
46562306a36Sopenharmony_ci	    pmac_mb.model_id == PMAC_TYPE_YIKES)
46662306a36Sopenharmony_ci		return 0;
46762306a36Sopenharmony_ci
46862306a36Sopenharmony_ci	macio = macio_find(node, 0);
46962306a36Sopenharmony_ci	if (!macio)
47062306a36Sopenharmony_ci		return -ENODEV;
47162306a36Sopenharmony_ci	if (value) {
47262306a36Sopenharmony_ci		LOCK(flags);
47362306a36Sopenharmony_ci		MACIO_BIS(HEATHROW_FCR, HRW_SOUND_CLK_ENABLE);
47462306a36Sopenharmony_ci		MACIO_BIC(HEATHROW_FCR, HRW_SOUND_POWER_N);
47562306a36Sopenharmony_ci		UNLOCK(flags);
47662306a36Sopenharmony_ci		(void)MACIO_IN32(HEATHROW_FCR);
47762306a36Sopenharmony_ci	} else {
47862306a36Sopenharmony_ci		LOCK(flags);
47962306a36Sopenharmony_ci		MACIO_BIS(HEATHROW_FCR, HRW_SOUND_POWER_N);
48062306a36Sopenharmony_ci		MACIO_BIC(HEATHROW_FCR, HRW_SOUND_CLK_ENABLE);
48162306a36Sopenharmony_ci		UNLOCK(flags);
48262306a36Sopenharmony_ci	}
48362306a36Sopenharmony_ci	return 0;
48462306a36Sopenharmony_ci}
48562306a36Sopenharmony_ci
48662306a36Sopenharmony_cistatic u32 save_fcr[6];
48762306a36Sopenharmony_cistatic u32 save_mbcr;
48862306a36Sopenharmony_cistatic struct dbdma_regs save_dbdma[13];
48962306a36Sopenharmony_cistatic struct dbdma_regs save_alt_dbdma[13];
49062306a36Sopenharmony_ci
49162306a36Sopenharmony_cistatic void dbdma_save(struct macio_chip *macio, struct dbdma_regs *save)
49262306a36Sopenharmony_ci{
49362306a36Sopenharmony_ci	int i;
49462306a36Sopenharmony_ci
49562306a36Sopenharmony_ci	/* Save state & config of DBDMA channels */
49662306a36Sopenharmony_ci	for (i = 0; i < 13; i++) {
49762306a36Sopenharmony_ci		volatile struct dbdma_regs __iomem * chan = (void __iomem *)
49862306a36Sopenharmony_ci			(macio->base + ((0x8000+i*0x100)>>2));
49962306a36Sopenharmony_ci		save[i].cmdptr_hi = in_le32(&chan->cmdptr_hi);
50062306a36Sopenharmony_ci		save[i].cmdptr = in_le32(&chan->cmdptr);
50162306a36Sopenharmony_ci		save[i].intr_sel = in_le32(&chan->intr_sel);
50262306a36Sopenharmony_ci		save[i].br_sel = in_le32(&chan->br_sel);
50362306a36Sopenharmony_ci		save[i].wait_sel = in_le32(&chan->wait_sel);
50462306a36Sopenharmony_ci	}
50562306a36Sopenharmony_ci}
50662306a36Sopenharmony_ci
50762306a36Sopenharmony_cistatic void dbdma_restore(struct macio_chip *macio, struct dbdma_regs *save)
50862306a36Sopenharmony_ci{
50962306a36Sopenharmony_ci	int i;
51062306a36Sopenharmony_ci
51162306a36Sopenharmony_ci	/* Save state & config of DBDMA channels */
51262306a36Sopenharmony_ci	for (i = 0; i < 13; i++) {
51362306a36Sopenharmony_ci		volatile struct dbdma_regs __iomem * chan = (void __iomem *)
51462306a36Sopenharmony_ci			(macio->base + ((0x8000+i*0x100)>>2));
51562306a36Sopenharmony_ci		out_le32(&chan->control, (ACTIVE|DEAD|WAKE|FLUSH|PAUSE|RUN)<<16);
51662306a36Sopenharmony_ci		while (in_le32(&chan->status) & ACTIVE)
51762306a36Sopenharmony_ci			mb();
51862306a36Sopenharmony_ci		out_le32(&chan->cmdptr_hi, save[i].cmdptr_hi);
51962306a36Sopenharmony_ci		out_le32(&chan->cmdptr, save[i].cmdptr);
52062306a36Sopenharmony_ci		out_le32(&chan->intr_sel, save[i].intr_sel);
52162306a36Sopenharmony_ci		out_le32(&chan->br_sel, save[i].br_sel);
52262306a36Sopenharmony_ci		out_le32(&chan->wait_sel, save[i].wait_sel);
52362306a36Sopenharmony_ci	}
52462306a36Sopenharmony_ci}
52562306a36Sopenharmony_ci
52662306a36Sopenharmony_cistatic void heathrow_sleep(struct macio_chip *macio, int secondary)
52762306a36Sopenharmony_ci{
52862306a36Sopenharmony_ci	if (secondary) {
52962306a36Sopenharmony_ci		dbdma_save(macio, save_alt_dbdma);
53062306a36Sopenharmony_ci		save_fcr[2] = MACIO_IN32(0x38);
53162306a36Sopenharmony_ci		save_fcr[3] = MACIO_IN32(0x3c);
53262306a36Sopenharmony_ci	} else {
53362306a36Sopenharmony_ci		dbdma_save(macio, save_dbdma);
53462306a36Sopenharmony_ci		save_fcr[0] = MACIO_IN32(0x38);
53562306a36Sopenharmony_ci		save_fcr[1] = MACIO_IN32(0x3c);
53662306a36Sopenharmony_ci		save_mbcr = MACIO_IN32(0x34);
53762306a36Sopenharmony_ci		/* Make sure sound is shut down */
53862306a36Sopenharmony_ci		MACIO_BIS(HEATHROW_FCR, HRW_SOUND_POWER_N);
53962306a36Sopenharmony_ci		MACIO_BIC(HEATHROW_FCR, HRW_SOUND_CLK_ENABLE);
54062306a36Sopenharmony_ci		/* This seems to be necessary as well or the fan
54162306a36Sopenharmony_ci		 * keeps coming up and battery drains fast */
54262306a36Sopenharmony_ci		MACIO_BIC(HEATHROW_FCR, HRW_IOBUS_ENABLE);
54362306a36Sopenharmony_ci		MACIO_BIC(HEATHROW_FCR, HRW_IDE0_RESET_N);
54462306a36Sopenharmony_ci		/* Make sure eth is down even if module or sleep
54562306a36Sopenharmony_ci		 * won't work properly */
54662306a36Sopenharmony_ci		MACIO_BIC(HEATHROW_FCR, HRW_BMAC_IO_ENABLE | HRW_BMAC_RESET);
54762306a36Sopenharmony_ci	}
54862306a36Sopenharmony_ci	/* Make sure modem is shut down */
54962306a36Sopenharmony_ci	MACIO_OUT8(HRW_GPIO_MODEM_RESET,
55062306a36Sopenharmony_ci		MACIO_IN8(HRW_GPIO_MODEM_RESET) & ~1);
55162306a36Sopenharmony_ci	MACIO_BIS(HEATHROW_FCR, HRW_SCC_TRANS_EN_N);
55262306a36Sopenharmony_ci	MACIO_BIC(HEATHROW_FCR, OH_SCCA_IO|OH_SCCB_IO|HRW_SCC_ENABLE);
55362306a36Sopenharmony_ci
55462306a36Sopenharmony_ci	/* Let things settle */
55562306a36Sopenharmony_ci	(void)MACIO_IN32(HEATHROW_FCR);
55662306a36Sopenharmony_ci}
55762306a36Sopenharmony_ci
55862306a36Sopenharmony_cistatic void heathrow_wakeup(struct macio_chip *macio, int secondary)
55962306a36Sopenharmony_ci{
56062306a36Sopenharmony_ci	if (secondary) {
56162306a36Sopenharmony_ci		MACIO_OUT32(0x38, save_fcr[2]);
56262306a36Sopenharmony_ci		(void)MACIO_IN32(0x38);
56362306a36Sopenharmony_ci		mdelay(1);
56462306a36Sopenharmony_ci		MACIO_OUT32(0x3c, save_fcr[3]);
56562306a36Sopenharmony_ci		(void)MACIO_IN32(0x38);
56662306a36Sopenharmony_ci		mdelay(10);
56762306a36Sopenharmony_ci		dbdma_restore(macio, save_alt_dbdma);
56862306a36Sopenharmony_ci	} else {
56962306a36Sopenharmony_ci		MACIO_OUT32(0x38, save_fcr[0] | HRW_IOBUS_ENABLE);
57062306a36Sopenharmony_ci		(void)MACIO_IN32(0x38);
57162306a36Sopenharmony_ci		mdelay(1);
57262306a36Sopenharmony_ci		MACIO_OUT32(0x3c, save_fcr[1]);
57362306a36Sopenharmony_ci		(void)MACIO_IN32(0x38);
57462306a36Sopenharmony_ci		mdelay(1);
57562306a36Sopenharmony_ci		MACIO_OUT32(0x34, save_mbcr);
57662306a36Sopenharmony_ci		(void)MACIO_IN32(0x38);
57762306a36Sopenharmony_ci		mdelay(10);
57862306a36Sopenharmony_ci		dbdma_restore(macio, save_dbdma);
57962306a36Sopenharmony_ci	}
58062306a36Sopenharmony_ci}
58162306a36Sopenharmony_ci
58262306a36Sopenharmony_cistatic long heathrow_sleep_state(struct device_node *node, long param,
58362306a36Sopenharmony_ci				 long value)
58462306a36Sopenharmony_ci{
58562306a36Sopenharmony_ci	if ((pmac_mb.board_flags & PMAC_MB_CAN_SLEEP) == 0)
58662306a36Sopenharmony_ci		return -EPERM;
58762306a36Sopenharmony_ci	if (value == 1) {
58862306a36Sopenharmony_ci		if (macio_chips[1].type == macio_gatwick)
58962306a36Sopenharmony_ci			heathrow_sleep(&macio_chips[0], 1);
59062306a36Sopenharmony_ci		heathrow_sleep(&macio_chips[0], 0);
59162306a36Sopenharmony_ci	} else if (value == 0) {
59262306a36Sopenharmony_ci		heathrow_wakeup(&macio_chips[0], 0);
59362306a36Sopenharmony_ci		if (macio_chips[1].type == macio_gatwick)
59462306a36Sopenharmony_ci			heathrow_wakeup(&macio_chips[0], 1);
59562306a36Sopenharmony_ci	}
59662306a36Sopenharmony_ci	return 0;
59762306a36Sopenharmony_ci}
59862306a36Sopenharmony_ci
59962306a36Sopenharmony_cistatic long core99_scc_enable(struct device_node *node, long param, long value)
60062306a36Sopenharmony_ci{
60162306a36Sopenharmony_ci	struct macio_chip*	macio;
60262306a36Sopenharmony_ci	unsigned long		flags;
60362306a36Sopenharmony_ci	unsigned long		chan_mask;
60462306a36Sopenharmony_ci	u32			fcr;
60562306a36Sopenharmony_ci
60662306a36Sopenharmony_ci	macio = macio_find(node, 0);
60762306a36Sopenharmony_ci	if (!macio)
60862306a36Sopenharmony_ci		return -ENODEV;
60962306a36Sopenharmony_ci	if (of_node_name_eq(node, "ch-a"))
61062306a36Sopenharmony_ci		chan_mask = MACIO_FLAG_SCCA_ON;
61162306a36Sopenharmony_ci	else if (of_node_name_eq(node, "ch-b"))
61262306a36Sopenharmony_ci		chan_mask = MACIO_FLAG_SCCB_ON;
61362306a36Sopenharmony_ci	else
61462306a36Sopenharmony_ci		return -ENODEV;
61562306a36Sopenharmony_ci
61662306a36Sopenharmony_ci	if (value) {
61762306a36Sopenharmony_ci		int need_reset_scc = 0;
61862306a36Sopenharmony_ci		int need_reset_irda = 0;
61962306a36Sopenharmony_ci
62062306a36Sopenharmony_ci		LOCK(flags);
62162306a36Sopenharmony_ci		fcr = MACIO_IN32(KEYLARGO_FCR0);
62262306a36Sopenharmony_ci		/* Check if scc cell need enabling */
62362306a36Sopenharmony_ci		if (!(fcr & KL0_SCC_CELL_ENABLE)) {
62462306a36Sopenharmony_ci			fcr |= KL0_SCC_CELL_ENABLE;
62562306a36Sopenharmony_ci			need_reset_scc = 1;
62662306a36Sopenharmony_ci		}
62762306a36Sopenharmony_ci		if (chan_mask & MACIO_FLAG_SCCA_ON) {
62862306a36Sopenharmony_ci			fcr |= KL0_SCCA_ENABLE;
62962306a36Sopenharmony_ci			/* Don't enable line drivers for I2S modem */
63062306a36Sopenharmony_ci			if ((param & 0xfff) == PMAC_SCC_I2S1)
63162306a36Sopenharmony_ci				fcr &= ~KL0_SCC_A_INTF_ENABLE;
63262306a36Sopenharmony_ci			else
63362306a36Sopenharmony_ci				fcr |= KL0_SCC_A_INTF_ENABLE;
63462306a36Sopenharmony_ci		}
63562306a36Sopenharmony_ci		if (chan_mask & MACIO_FLAG_SCCB_ON) {
63662306a36Sopenharmony_ci			fcr |= KL0_SCCB_ENABLE;
63762306a36Sopenharmony_ci			/* Perform irda specific inits */
63862306a36Sopenharmony_ci			if ((param & 0xfff) == PMAC_SCC_IRDA) {
63962306a36Sopenharmony_ci				fcr &= ~KL0_SCC_B_INTF_ENABLE;
64062306a36Sopenharmony_ci				fcr |= KL0_IRDA_ENABLE;
64162306a36Sopenharmony_ci				fcr |= KL0_IRDA_CLK32_ENABLE | KL0_IRDA_CLK19_ENABLE;
64262306a36Sopenharmony_ci				fcr |= KL0_IRDA_SOURCE1_SEL;
64362306a36Sopenharmony_ci				fcr &= ~(KL0_IRDA_FAST_CONNECT|KL0_IRDA_DEFAULT1|KL0_IRDA_DEFAULT0);
64462306a36Sopenharmony_ci				fcr &= ~(KL0_IRDA_SOURCE2_SEL|KL0_IRDA_HIGH_BAND);
64562306a36Sopenharmony_ci				need_reset_irda = 1;
64662306a36Sopenharmony_ci			} else
64762306a36Sopenharmony_ci				fcr |= KL0_SCC_B_INTF_ENABLE;
64862306a36Sopenharmony_ci		}
64962306a36Sopenharmony_ci		MACIO_OUT32(KEYLARGO_FCR0, fcr);
65062306a36Sopenharmony_ci		macio->flags |= chan_mask;
65162306a36Sopenharmony_ci		if (need_reset_scc)  {
65262306a36Sopenharmony_ci			MACIO_BIS(KEYLARGO_FCR0, KL0_SCC_RESET);
65362306a36Sopenharmony_ci			(void)MACIO_IN32(KEYLARGO_FCR0);
65462306a36Sopenharmony_ci			UNLOCK(flags);
65562306a36Sopenharmony_ci			mdelay(15);
65662306a36Sopenharmony_ci			LOCK(flags);
65762306a36Sopenharmony_ci			MACIO_BIC(KEYLARGO_FCR0, KL0_SCC_RESET);
65862306a36Sopenharmony_ci		}
65962306a36Sopenharmony_ci		if (need_reset_irda)  {
66062306a36Sopenharmony_ci			MACIO_BIS(KEYLARGO_FCR0, KL0_IRDA_RESET);
66162306a36Sopenharmony_ci			(void)MACIO_IN32(KEYLARGO_FCR0);
66262306a36Sopenharmony_ci			UNLOCK(flags);
66362306a36Sopenharmony_ci			mdelay(15);
66462306a36Sopenharmony_ci			LOCK(flags);
66562306a36Sopenharmony_ci			MACIO_BIC(KEYLARGO_FCR0, KL0_IRDA_RESET);
66662306a36Sopenharmony_ci		}
66762306a36Sopenharmony_ci		UNLOCK(flags);
66862306a36Sopenharmony_ci		if (param & PMAC_SCC_FLAG_XMON)
66962306a36Sopenharmony_ci			macio->flags |= MACIO_FLAG_SCC_LOCKED;
67062306a36Sopenharmony_ci	} else {
67162306a36Sopenharmony_ci		if (macio->flags & MACIO_FLAG_SCC_LOCKED)
67262306a36Sopenharmony_ci			return -EPERM;
67362306a36Sopenharmony_ci		LOCK(flags);
67462306a36Sopenharmony_ci		fcr = MACIO_IN32(KEYLARGO_FCR0);
67562306a36Sopenharmony_ci		if (chan_mask & MACIO_FLAG_SCCA_ON)
67662306a36Sopenharmony_ci			fcr &= ~KL0_SCCA_ENABLE;
67762306a36Sopenharmony_ci		if (chan_mask & MACIO_FLAG_SCCB_ON) {
67862306a36Sopenharmony_ci			fcr &= ~KL0_SCCB_ENABLE;
67962306a36Sopenharmony_ci			/* Perform irda specific clears */
68062306a36Sopenharmony_ci			if ((param & 0xfff) == PMAC_SCC_IRDA) {
68162306a36Sopenharmony_ci				fcr &= ~KL0_IRDA_ENABLE;
68262306a36Sopenharmony_ci				fcr &= ~(KL0_IRDA_CLK32_ENABLE | KL0_IRDA_CLK19_ENABLE);
68362306a36Sopenharmony_ci				fcr &= ~(KL0_IRDA_FAST_CONNECT|KL0_IRDA_DEFAULT1|KL0_IRDA_DEFAULT0);
68462306a36Sopenharmony_ci				fcr &= ~(KL0_IRDA_SOURCE1_SEL|KL0_IRDA_SOURCE2_SEL|KL0_IRDA_HIGH_BAND);
68562306a36Sopenharmony_ci			}
68662306a36Sopenharmony_ci		}
68762306a36Sopenharmony_ci		MACIO_OUT32(KEYLARGO_FCR0, fcr);
68862306a36Sopenharmony_ci		if ((fcr & (KL0_SCCA_ENABLE | KL0_SCCB_ENABLE)) == 0) {
68962306a36Sopenharmony_ci			fcr &= ~KL0_SCC_CELL_ENABLE;
69062306a36Sopenharmony_ci			MACIO_OUT32(KEYLARGO_FCR0, fcr);
69162306a36Sopenharmony_ci		}
69262306a36Sopenharmony_ci		macio->flags &= ~(chan_mask);
69362306a36Sopenharmony_ci		UNLOCK(flags);
69462306a36Sopenharmony_ci		mdelay(10);
69562306a36Sopenharmony_ci	}
69662306a36Sopenharmony_ci	return 0;
69762306a36Sopenharmony_ci}
69862306a36Sopenharmony_ci
69962306a36Sopenharmony_cistatic long
70062306a36Sopenharmony_cicore99_modem_enable(struct device_node *node, long param, long value)
70162306a36Sopenharmony_ci{
70262306a36Sopenharmony_ci	struct macio_chip*	macio;
70362306a36Sopenharmony_ci	u8			gpio;
70462306a36Sopenharmony_ci	unsigned long		flags;
70562306a36Sopenharmony_ci
70662306a36Sopenharmony_ci	/* Hack for internal USB modem */
70762306a36Sopenharmony_ci	if (node == NULL) {
70862306a36Sopenharmony_ci		if (macio_chips[0].type != macio_keylargo)
70962306a36Sopenharmony_ci			return -ENODEV;
71062306a36Sopenharmony_ci		node = macio_chips[0].of_node;
71162306a36Sopenharmony_ci	}
71262306a36Sopenharmony_ci	macio = macio_find(node, 0);
71362306a36Sopenharmony_ci	if (!macio)
71462306a36Sopenharmony_ci		return -ENODEV;
71562306a36Sopenharmony_ci	gpio = MACIO_IN8(KL_GPIO_MODEM_RESET);
71662306a36Sopenharmony_ci	gpio |= KEYLARGO_GPIO_OUTPUT_ENABLE;
71762306a36Sopenharmony_ci	gpio &= ~KEYLARGO_GPIO_OUTOUT_DATA;
71862306a36Sopenharmony_ci
71962306a36Sopenharmony_ci	if (!value) {
72062306a36Sopenharmony_ci		LOCK(flags);
72162306a36Sopenharmony_ci		MACIO_OUT8(KL_GPIO_MODEM_RESET, gpio);
72262306a36Sopenharmony_ci		UNLOCK(flags);
72362306a36Sopenharmony_ci		(void)MACIO_IN8(KL_GPIO_MODEM_RESET);
72462306a36Sopenharmony_ci		mdelay(250);
72562306a36Sopenharmony_ci	}
72662306a36Sopenharmony_ci	LOCK(flags);
72762306a36Sopenharmony_ci	if (value) {
72862306a36Sopenharmony_ci		MACIO_BIC(KEYLARGO_FCR2, KL2_ALT_DATA_OUT);
72962306a36Sopenharmony_ci		UNLOCK(flags);
73062306a36Sopenharmony_ci		(void)MACIO_IN32(KEYLARGO_FCR2);
73162306a36Sopenharmony_ci		mdelay(250);
73262306a36Sopenharmony_ci	} else {
73362306a36Sopenharmony_ci		MACIO_BIS(KEYLARGO_FCR2, KL2_ALT_DATA_OUT);
73462306a36Sopenharmony_ci		UNLOCK(flags);
73562306a36Sopenharmony_ci	}
73662306a36Sopenharmony_ci	if (value) {
73762306a36Sopenharmony_ci		LOCK(flags);
73862306a36Sopenharmony_ci		MACIO_OUT8(KL_GPIO_MODEM_RESET, gpio | KEYLARGO_GPIO_OUTOUT_DATA);
73962306a36Sopenharmony_ci		(void)MACIO_IN8(KL_GPIO_MODEM_RESET);
74062306a36Sopenharmony_ci		UNLOCK(flags); mdelay(250); LOCK(flags);
74162306a36Sopenharmony_ci		MACIO_OUT8(KL_GPIO_MODEM_RESET, gpio);
74262306a36Sopenharmony_ci		(void)MACIO_IN8(KL_GPIO_MODEM_RESET);
74362306a36Sopenharmony_ci		UNLOCK(flags); mdelay(250); LOCK(flags);
74462306a36Sopenharmony_ci		MACIO_OUT8(KL_GPIO_MODEM_RESET, gpio | KEYLARGO_GPIO_OUTOUT_DATA);
74562306a36Sopenharmony_ci		(void)MACIO_IN8(KL_GPIO_MODEM_RESET);
74662306a36Sopenharmony_ci		UNLOCK(flags); mdelay(250);
74762306a36Sopenharmony_ci	}
74862306a36Sopenharmony_ci	return 0;
74962306a36Sopenharmony_ci}
75062306a36Sopenharmony_ci
75162306a36Sopenharmony_cistatic long
75262306a36Sopenharmony_cipangea_modem_enable(struct device_node *node, long param, long value)
75362306a36Sopenharmony_ci{
75462306a36Sopenharmony_ci	struct macio_chip*	macio;
75562306a36Sopenharmony_ci	u8			gpio;
75662306a36Sopenharmony_ci	unsigned long		flags;
75762306a36Sopenharmony_ci
75862306a36Sopenharmony_ci	/* Hack for internal USB modem */
75962306a36Sopenharmony_ci	if (node == NULL) {
76062306a36Sopenharmony_ci		if (macio_chips[0].type != macio_pangea &&
76162306a36Sopenharmony_ci		    macio_chips[0].type != macio_intrepid)
76262306a36Sopenharmony_ci			return -ENODEV;
76362306a36Sopenharmony_ci		node = macio_chips[0].of_node;
76462306a36Sopenharmony_ci	}
76562306a36Sopenharmony_ci	macio = macio_find(node, 0);
76662306a36Sopenharmony_ci	if (!macio)
76762306a36Sopenharmony_ci		return -ENODEV;
76862306a36Sopenharmony_ci	gpio = MACIO_IN8(KL_GPIO_MODEM_RESET);
76962306a36Sopenharmony_ci	gpio |= KEYLARGO_GPIO_OUTPUT_ENABLE;
77062306a36Sopenharmony_ci	gpio &= ~KEYLARGO_GPIO_OUTOUT_DATA;
77162306a36Sopenharmony_ci
77262306a36Sopenharmony_ci	if (!value) {
77362306a36Sopenharmony_ci		LOCK(flags);
77462306a36Sopenharmony_ci		MACIO_OUT8(KL_GPIO_MODEM_RESET, gpio);
77562306a36Sopenharmony_ci		UNLOCK(flags);
77662306a36Sopenharmony_ci		(void)MACIO_IN8(KL_GPIO_MODEM_RESET);
77762306a36Sopenharmony_ci		mdelay(250);
77862306a36Sopenharmony_ci	}
77962306a36Sopenharmony_ci	LOCK(flags);
78062306a36Sopenharmony_ci	if (value) {
78162306a36Sopenharmony_ci		MACIO_OUT8(KL_GPIO_MODEM_POWER,
78262306a36Sopenharmony_ci			KEYLARGO_GPIO_OUTPUT_ENABLE);
78362306a36Sopenharmony_ci		UNLOCK(flags);
78462306a36Sopenharmony_ci		(void)MACIO_IN32(KEYLARGO_FCR2);
78562306a36Sopenharmony_ci		mdelay(250);
78662306a36Sopenharmony_ci	} else {
78762306a36Sopenharmony_ci		MACIO_OUT8(KL_GPIO_MODEM_POWER,
78862306a36Sopenharmony_ci			KEYLARGO_GPIO_OUTPUT_ENABLE | KEYLARGO_GPIO_OUTOUT_DATA);
78962306a36Sopenharmony_ci		UNLOCK(flags);
79062306a36Sopenharmony_ci	}
79162306a36Sopenharmony_ci	if (value) {
79262306a36Sopenharmony_ci		LOCK(flags);
79362306a36Sopenharmony_ci		MACIO_OUT8(KL_GPIO_MODEM_RESET, gpio | KEYLARGO_GPIO_OUTOUT_DATA);
79462306a36Sopenharmony_ci		(void)MACIO_IN8(KL_GPIO_MODEM_RESET);
79562306a36Sopenharmony_ci		UNLOCK(flags); mdelay(250); LOCK(flags);
79662306a36Sopenharmony_ci		MACIO_OUT8(KL_GPIO_MODEM_RESET, gpio);
79762306a36Sopenharmony_ci		(void)MACIO_IN8(KL_GPIO_MODEM_RESET);
79862306a36Sopenharmony_ci		UNLOCK(flags); mdelay(250); LOCK(flags);
79962306a36Sopenharmony_ci		MACIO_OUT8(KL_GPIO_MODEM_RESET, gpio | KEYLARGO_GPIO_OUTOUT_DATA);
80062306a36Sopenharmony_ci		(void)MACIO_IN8(KL_GPIO_MODEM_RESET);
80162306a36Sopenharmony_ci		UNLOCK(flags); mdelay(250);
80262306a36Sopenharmony_ci	}
80362306a36Sopenharmony_ci	return 0;
80462306a36Sopenharmony_ci}
80562306a36Sopenharmony_ci
80662306a36Sopenharmony_cistatic long
80762306a36Sopenharmony_cicore99_ata100_enable(struct device_node *node, long value)
80862306a36Sopenharmony_ci{
80962306a36Sopenharmony_ci	unsigned long flags;
81062306a36Sopenharmony_ci	struct pci_dev *pdev = NULL;
81162306a36Sopenharmony_ci	u8 pbus, pid;
81262306a36Sopenharmony_ci	int rc;
81362306a36Sopenharmony_ci
81462306a36Sopenharmony_ci	if (uninorth_rev < 0x24)
81562306a36Sopenharmony_ci		return -ENODEV;
81662306a36Sopenharmony_ci
81762306a36Sopenharmony_ci	LOCK(flags);
81862306a36Sopenharmony_ci	if (value)
81962306a36Sopenharmony_ci		UN_BIS(UNI_N_CLOCK_CNTL, UNI_N_CLOCK_CNTL_ATA100);
82062306a36Sopenharmony_ci	else
82162306a36Sopenharmony_ci		UN_BIC(UNI_N_CLOCK_CNTL, UNI_N_CLOCK_CNTL_ATA100);
82262306a36Sopenharmony_ci	(void)UN_IN(UNI_N_CLOCK_CNTL);
82362306a36Sopenharmony_ci	UNLOCK(flags);
82462306a36Sopenharmony_ci	udelay(20);
82562306a36Sopenharmony_ci
82662306a36Sopenharmony_ci	if (value) {
82762306a36Sopenharmony_ci		if (pci_device_from_OF_node(node, &pbus, &pid) == 0)
82862306a36Sopenharmony_ci			pdev = pci_get_domain_bus_and_slot(0, pbus, pid);
82962306a36Sopenharmony_ci		if (pdev == NULL)
83062306a36Sopenharmony_ci			return 0;
83162306a36Sopenharmony_ci		rc = pci_enable_device(pdev);
83262306a36Sopenharmony_ci		if (rc == 0)
83362306a36Sopenharmony_ci			pci_set_master(pdev);
83462306a36Sopenharmony_ci		pci_dev_put(pdev);
83562306a36Sopenharmony_ci		if (rc)
83662306a36Sopenharmony_ci			return rc;
83762306a36Sopenharmony_ci	}
83862306a36Sopenharmony_ci	return 0;
83962306a36Sopenharmony_ci}
84062306a36Sopenharmony_ci
84162306a36Sopenharmony_cistatic long
84262306a36Sopenharmony_cicore99_ide_enable(struct device_node *node, long param, long value)
84362306a36Sopenharmony_ci{
84462306a36Sopenharmony_ci	/* Bus ID 0 to 2 are KeyLargo based IDE, busID 3 is U2
84562306a36Sopenharmony_ci	 * based ata-100
84662306a36Sopenharmony_ci	 */
84762306a36Sopenharmony_ci	switch(param) {
84862306a36Sopenharmony_ci	    case 0:
84962306a36Sopenharmony_ci		return simple_feature_tweak(node, macio_unknown,
85062306a36Sopenharmony_ci			KEYLARGO_FCR1, KL1_EIDE0_ENABLE, value);
85162306a36Sopenharmony_ci	    case 1:
85262306a36Sopenharmony_ci		return simple_feature_tweak(node, macio_unknown,
85362306a36Sopenharmony_ci			KEYLARGO_FCR1, KL1_EIDE1_ENABLE, value);
85462306a36Sopenharmony_ci	    case 2:
85562306a36Sopenharmony_ci		return simple_feature_tweak(node, macio_unknown,
85662306a36Sopenharmony_ci			KEYLARGO_FCR1, KL1_UIDE_ENABLE, value);
85762306a36Sopenharmony_ci	    case 3:
85862306a36Sopenharmony_ci		return core99_ata100_enable(node, value);
85962306a36Sopenharmony_ci	    default:
86062306a36Sopenharmony_ci		return -ENODEV;
86162306a36Sopenharmony_ci	}
86262306a36Sopenharmony_ci}
86362306a36Sopenharmony_ci
86462306a36Sopenharmony_cistatic long
86562306a36Sopenharmony_cicore99_ide_reset(struct device_node *node, long param, long value)
86662306a36Sopenharmony_ci{
86762306a36Sopenharmony_ci	switch(param) {
86862306a36Sopenharmony_ci	    case 0:
86962306a36Sopenharmony_ci		return simple_feature_tweak(node, macio_unknown,
87062306a36Sopenharmony_ci			KEYLARGO_FCR1, KL1_EIDE0_RESET_N, !value);
87162306a36Sopenharmony_ci	    case 1:
87262306a36Sopenharmony_ci		return simple_feature_tweak(node, macio_unknown,
87362306a36Sopenharmony_ci			KEYLARGO_FCR1, KL1_EIDE1_RESET_N, !value);
87462306a36Sopenharmony_ci	    case 2:
87562306a36Sopenharmony_ci		return simple_feature_tweak(node, macio_unknown,
87662306a36Sopenharmony_ci			KEYLARGO_FCR1, KL1_UIDE_RESET_N, !value);
87762306a36Sopenharmony_ci	    default:
87862306a36Sopenharmony_ci		return -ENODEV;
87962306a36Sopenharmony_ci	}
88062306a36Sopenharmony_ci}
88162306a36Sopenharmony_ci
88262306a36Sopenharmony_cistatic long
88362306a36Sopenharmony_cicore99_gmac_enable(struct device_node *node, long param, long value)
88462306a36Sopenharmony_ci{
88562306a36Sopenharmony_ci	unsigned long flags;
88662306a36Sopenharmony_ci
88762306a36Sopenharmony_ci	LOCK(flags);
88862306a36Sopenharmony_ci	if (value)
88962306a36Sopenharmony_ci		UN_BIS(UNI_N_CLOCK_CNTL, UNI_N_CLOCK_CNTL_GMAC);
89062306a36Sopenharmony_ci	else
89162306a36Sopenharmony_ci		UN_BIC(UNI_N_CLOCK_CNTL, UNI_N_CLOCK_CNTL_GMAC);
89262306a36Sopenharmony_ci	(void)UN_IN(UNI_N_CLOCK_CNTL);
89362306a36Sopenharmony_ci	UNLOCK(flags);
89462306a36Sopenharmony_ci	udelay(20);
89562306a36Sopenharmony_ci
89662306a36Sopenharmony_ci	return 0;
89762306a36Sopenharmony_ci}
89862306a36Sopenharmony_ci
89962306a36Sopenharmony_cistatic long
90062306a36Sopenharmony_cicore99_gmac_phy_reset(struct device_node *node, long param, long value)
90162306a36Sopenharmony_ci{
90262306a36Sopenharmony_ci	unsigned long flags;
90362306a36Sopenharmony_ci	struct macio_chip *macio;
90462306a36Sopenharmony_ci
90562306a36Sopenharmony_ci	macio = &macio_chips[0];
90662306a36Sopenharmony_ci	if (macio->type != macio_keylargo && macio->type != macio_pangea &&
90762306a36Sopenharmony_ci	    macio->type != macio_intrepid)
90862306a36Sopenharmony_ci		return -ENODEV;
90962306a36Sopenharmony_ci
91062306a36Sopenharmony_ci	LOCK(flags);
91162306a36Sopenharmony_ci	MACIO_OUT8(KL_GPIO_ETH_PHY_RESET, KEYLARGO_GPIO_OUTPUT_ENABLE);
91262306a36Sopenharmony_ci	(void)MACIO_IN8(KL_GPIO_ETH_PHY_RESET);
91362306a36Sopenharmony_ci	UNLOCK(flags);
91462306a36Sopenharmony_ci	mdelay(10);
91562306a36Sopenharmony_ci	LOCK(flags);
91662306a36Sopenharmony_ci	MACIO_OUT8(KL_GPIO_ETH_PHY_RESET, /*KEYLARGO_GPIO_OUTPUT_ENABLE | */
91762306a36Sopenharmony_ci		KEYLARGO_GPIO_OUTOUT_DATA);
91862306a36Sopenharmony_ci	UNLOCK(flags);
91962306a36Sopenharmony_ci	mdelay(10);
92062306a36Sopenharmony_ci
92162306a36Sopenharmony_ci	return 0;
92262306a36Sopenharmony_ci}
92362306a36Sopenharmony_ci
92462306a36Sopenharmony_cistatic long
92562306a36Sopenharmony_cicore99_sound_chip_enable(struct device_node *node, long param, long value)
92662306a36Sopenharmony_ci{
92762306a36Sopenharmony_ci	struct macio_chip*	macio;
92862306a36Sopenharmony_ci	unsigned long		flags;
92962306a36Sopenharmony_ci
93062306a36Sopenharmony_ci	macio = macio_find(node, 0);
93162306a36Sopenharmony_ci	if (!macio)
93262306a36Sopenharmony_ci		return -ENODEV;
93362306a36Sopenharmony_ci
93462306a36Sopenharmony_ci	/* Do a better probe code, screamer G4 desktops &
93562306a36Sopenharmony_ci	 * iMacs can do that too, add a recalibrate  in
93662306a36Sopenharmony_ci	 * the driver as well
93762306a36Sopenharmony_ci	 */
93862306a36Sopenharmony_ci	if (pmac_mb.model_id == PMAC_TYPE_PISMO ||
93962306a36Sopenharmony_ci	    pmac_mb.model_id == PMAC_TYPE_TITANIUM) {
94062306a36Sopenharmony_ci		LOCK(flags);
94162306a36Sopenharmony_ci		if (value)
94262306a36Sopenharmony_ci			MACIO_OUT8(KL_GPIO_SOUND_POWER,
94362306a36Sopenharmony_ci				KEYLARGO_GPIO_OUTPUT_ENABLE |
94462306a36Sopenharmony_ci				KEYLARGO_GPIO_OUTOUT_DATA);
94562306a36Sopenharmony_ci		else
94662306a36Sopenharmony_ci			MACIO_OUT8(KL_GPIO_SOUND_POWER,
94762306a36Sopenharmony_ci				KEYLARGO_GPIO_OUTPUT_ENABLE);
94862306a36Sopenharmony_ci		(void)MACIO_IN8(KL_GPIO_SOUND_POWER);
94962306a36Sopenharmony_ci		UNLOCK(flags);
95062306a36Sopenharmony_ci	}
95162306a36Sopenharmony_ci	return 0;
95262306a36Sopenharmony_ci}
95362306a36Sopenharmony_ci
95462306a36Sopenharmony_cistatic long
95562306a36Sopenharmony_cicore99_airport_enable(struct device_node *node, long param, long value)
95662306a36Sopenharmony_ci{
95762306a36Sopenharmony_ci	struct macio_chip*	macio;
95862306a36Sopenharmony_ci	unsigned long		flags;
95962306a36Sopenharmony_ci	int			state;
96062306a36Sopenharmony_ci
96162306a36Sopenharmony_ci	macio = macio_find(node, 0);
96262306a36Sopenharmony_ci	if (!macio)
96362306a36Sopenharmony_ci		return -ENODEV;
96462306a36Sopenharmony_ci
96562306a36Sopenharmony_ci	/* Hint: we allow passing of macio itself for the sake of the
96662306a36Sopenharmony_ci	 * sleep code
96762306a36Sopenharmony_ci	 */
96862306a36Sopenharmony_ci	if (node != macio->of_node &&
96962306a36Sopenharmony_ci	    (!node->parent || node->parent != macio->of_node))
97062306a36Sopenharmony_ci		return -ENODEV;
97162306a36Sopenharmony_ci	state = (macio->flags & MACIO_FLAG_AIRPORT_ON) != 0;
97262306a36Sopenharmony_ci	if (value == state)
97362306a36Sopenharmony_ci		return 0;
97462306a36Sopenharmony_ci	if (value) {
97562306a36Sopenharmony_ci		/* This code is a reproduction of OF enable-cardslot
97662306a36Sopenharmony_ci		 * and init-wireless methods, slightly hacked until
97762306a36Sopenharmony_ci		 * I got it working.
97862306a36Sopenharmony_ci		 */
97962306a36Sopenharmony_ci		LOCK(flags);
98062306a36Sopenharmony_ci		MACIO_OUT8(KEYLARGO_GPIO_0+0xf, 5);
98162306a36Sopenharmony_ci		(void)MACIO_IN8(KEYLARGO_GPIO_0+0xf);
98262306a36Sopenharmony_ci		UNLOCK(flags);
98362306a36Sopenharmony_ci		mdelay(10);
98462306a36Sopenharmony_ci		LOCK(flags);
98562306a36Sopenharmony_ci		MACIO_OUT8(KEYLARGO_GPIO_0+0xf, 4);
98662306a36Sopenharmony_ci		(void)MACIO_IN8(KEYLARGO_GPIO_0+0xf);
98762306a36Sopenharmony_ci		UNLOCK(flags);
98862306a36Sopenharmony_ci
98962306a36Sopenharmony_ci		mdelay(10);
99062306a36Sopenharmony_ci
99162306a36Sopenharmony_ci		LOCK(flags);
99262306a36Sopenharmony_ci		MACIO_BIC(KEYLARGO_FCR2, KL2_CARDSEL_16);
99362306a36Sopenharmony_ci		(void)MACIO_IN32(KEYLARGO_FCR2);
99462306a36Sopenharmony_ci		udelay(10);
99562306a36Sopenharmony_ci		MACIO_OUT8(KEYLARGO_GPIO_EXTINT_0+0xb, 0);
99662306a36Sopenharmony_ci		(void)MACIO_IN8(KEYLARGO_GPIO_EXTINT_0+0xb);
99762306a36Sopenharmony_ci		udelay(10);
99862306a36Sopenharmony_ci		MACIO_OUT8(KEYLARGO_GPIO_EXTINT_0+0xa, 0x28);
99962306a36Sopenharmony_ci		(void)MACIO_IN8(KEYLARGO_GPIO_EXTINT_0+0xa);
100062306a36Sopenharmony_ci		udelay(10);
100162306a36Sopenharmony_ci		MACIO_OUT8(KEYLARGO_GPIO_EXTINT_0+0xd, 0x28);
100262306a36Sopenharmony_ci		(void)MACIO_IN8(KEYLARGO_GPIO_EXTINT_0+0xd);
100362306a36Sopenharmony_ci		udelay(10);
100462306a36Sopenharmony_ci		MACIO_OUT8(KEYLARGO_GPIO_0+0xd, 0x28);
100562306a36Sopenharmony_ci		(void)MACIO_IN8(KEYLARGO_GPIO_0+0xd);
100662306a36Sopenharmony_ci		udelay(10);
100762306a36Sopenharmony_ci		MACIO_OUT8(KEYLARGO_GPIO_0+0xe, 0x28);
100862306a36Sopenharmony_ci		(void)MACIO_IN8(KEYLARGO_GPIO_0+0xe);
100962306a36Sopenharmony_ci		UNLOCK(flags);
101062306a36Sopenharmony_ci		udelay(10);
101162306a36Sopenharmony_ci		MACIO_OUT32(0x1c000, 0);
101262306a36Sopenharmony_ci		mdelay(1);
101362306a36Sopenharmony_ci		MACIO_OUT8(0x1a3e0, 0x41);
101462306a36Sopenharmony_ci		(void)MACIO_IN8(0x1a3e0);
101562306a36Sopenharmony_ci		udelay(10);
101662306a36Sopenharmony_ci		LOCK(flags);
101762306a36Sopenharmony_ci		MACIO_BIS(KEYLARGO_FCR2, KL2_CARDSEL_16);
101862306a36Sopenharmony_ci		(void)MACIO_IN32(KEYLARGO_FCR2);
101962306a36Sopenharmony_ci		UNLOCK(flags);
102062306a36Sopenharmony_ci		mdelay(100);
102162306a36Sopenharmony_ci
102262306a36Sopenharmony_ci		macio->flags |= MACIO_FLAG_AIRPORT_ON;
102362306a36Sopenharmony_ci	} else {
102462306a36Sopenharmony_ci		LOCK(flags);
102562306a36Sopenharmony_ci		MACIO_BIC(KEYLARGO_FCR2, KL2_CARDSEL_16);
102662306a36Sopenharmony_ci		(void)MACIO_IN32(KEYLARGO_FCR2);
102762306a36Sopenharmony_ci		MACIO_OUT8(KL_GPIO_AIRPORT_0, 0);
102862306a36Sopenharmony_ci		MACIO_OUT8(KL_GPIO_AIRPORT_1, 0);
102962306a36Sopenharmony_ci		MACIO_OUT8(KL_GPIO_AIRPORT_2, 0);
103062306a36Sopenharmony_ci		MACIO_OUT8(KL_GPIO_AIRPORT_3, 0);
103162306a36Sopenharmony_ci		MACIO_OUT8(KL_GPIO_AIRPORT_4, 0);
103262306a36Sopenharmony_ci		(void)MACIO_IN8(KL_GPIO_AIRPORT_4);
103362306a36Sopenharmony_ci		UNLOCK(flags);
103462306a36Sopenharmony_ci
103562306a36Sopenharmony_ci		macio->flags &= ~MACIO_FLAG_AIRPORT_ON;
103662306a36Sopenharmony_ci	}
103762306a36Sopenharmony_ci	return 0;
103862306a36Sopenharmony_ci}
103962306a36Sopenharmony_ci
104062306a36Sopenharmony_ci#ifdef CONFIG_SMP
104162306a36Sopenharmony_cistatic long
104262306a36Sopenharmony_cicore99_reset_cpu(struct device_node *node, long param, long value)
104362306a36Sopenharmony_ci{
104462306a36Sopenharmony_ci	unsigned int reset_io = 0;
104562306a36Sopenharmony_ci	unsigned long flags;
104662306a36Sopenharmony_ci	struct macio_chip *macio;
104762306a36Sopenharmony_ci	struct device_node *np;
104862306a36Sopenharmony_ci	const int dflt_reset_lines[] = {	KL_GPIO_RESET_CPU0,
104962306a36Sopenharmony_ci						KL_GPIO_RESET_CPU1,
105062306a36Sopenharmony_ci						KL_GPIO_RESET_CPU2,
105162306a36Sopenharmony_ci						KL_GPIO_RESET_CPU3 };
105262306a36Sopenharmony_ci
105362306a36Sopenharmony_ci	macio = &macio_chips[0];
105462306a36Sopenharmony_ci	if (macio->type != macio_keylargo)
105562306a36Sopenharmony_ci		return -ENODEV;
105662306a36Sopenharmony_ci
105762306a36Sopenharmony_ci	for_each_of_cpu_node(np) {
105862306a36Sopenharmony_ci		const u32 *rst = of_get_property(np, "soft-reset", NULL);
105962306a36Sopenharmony_ci		if (!rst)
106062306a36Sopenharmony_ci			continue;
106162306a36Sopenharmony_ci		if (param == of_get_cpu_hwid(np, 0)) {
106262306a36Sopenharmony_ci			of_node_put(np);
106362306a36Sopenharmony_ci			reset_io = *rst;
106462306a36Sopenharmony_ci			break;
106562306a36Sopenharmony_ci		}
106662306a36Sopenharmony_ci	}
106762306a36Sopenharmony_ci	if (np == NULL || reset_io == 0)
106862306a36Sopenharmony_ci		reset_io = dflt_reset_lines[param];
106962306a36Sopenharmony_ci
107062306a36Sopenharmony_ci	LOCK(flags);
107162306a36Sopenharmony_ci	MACIO_OUT8(reset_io, KEYLARGO_GPIO_OUTPUT_ENABLE);
107262306a36Sopenharmony_ci	(void)MACIO_IN8(reset_io);
107362306a36Sopenharmony_ci	udelay(1);
107462306a36Sopenharmony_ci	MACIO_OUT8(reset_io, 0);
107562306a36Sopenharmony_ci	(void)MACIO_IN8(reset_io);
107662306a36Sopenharmony_ci	UNLOCK(flags);
107762306a36Sopenharmony_ci
107862306a36Sopenharmony_ci	return 0;
107962306a36Sopenharmony_ci}
108062306a36Sopenharmony_ci#endif /* CONFIG_SMP */
108162306a36Sopenharmony_ci
108262306a36Sopenharmony_cistatic long
108362306a36Sopenharmony_cicore99_usb_enable(struct device_node *node, long param, long value)
108462306a36Sopenharmony_ci{
108562306a36Sopenharmony_ci	struct macio_chip *macio;
108662306a36Sopenharmony_ci	unsigned long flags;
108762306a36Sopenharmony_ci	const char *prop;
108862306a36Sopenharmony_ci	int number;
108962306a36Sopenharmony_ci	u32 reg;
109062306a36Sopenharmony_ci
109162306a36Sopenharmony_ci	macio = &macio_chips[0];
109262306a36Sopenharmony_ci	if (macio->type != macio_keylargo && macio->type != macio_pangea &&
109362306a36Sopenharmony_ci	    macio->type != macio_intrepid)
109462306a36Sopenharmony_ci		return -ENODEV;
109562306a36Sopenharmony_ci
109662306a36Sopenharmony_ci	prop = of_get_property(node, "AAPL,clock-id", NULL);
109762306a36Sopenharmony_ci	if (!prop)
109862306a36Sopenharmony_ci		return -ENODEV;
109962306a36Sopenharmony_ci	if (strncmp(prop, "usb0u048", 8) == 0)
110062306a36Sopenharmony_ci		number = 0;
110162306a36Sopenharmony_ci	else if (strncmp(prop, "usb1u148", 8) == 0)
110262306a36Sopenharmony_ci		number = 2;
110362306a36Sopenharmony_ci	else if (strncmp(prop, "usb2u248", 8) == 0)
110462306a36Sopenharmony_ci		number = 4;
110562306a36Sopenharmony_ci	else
110662306a36Sopenharmony_ci		return -ENODEV;
110762306a36Sopenharmony_ci
110862306a36Sopenharmony_ci	/* Sorry for the brute-force locking, but this is only used during
110962306a36Sopenharmony_ci	 * sleep and the timing seem to be critical
111062306a36Sopenharmony_ci	 */
111162306a36Sopenharmony_ci	LOCK(flags);
111262306a36Sopenharmony_ci	if (value) {
111362306a36Sopenharmony_ci		/* Turn ON */
111462306a36Sopenharmony_ci		if (number == 0) {
111562306a36Sopenharmony_ci			MACIO_BIC(KEYLARGO_FCR0, (KL0_USB0_PAD_SUSPEND0 | KL0_USB0_PAD_SUSPEND1));
111662306a36Sopenharmony_ci			(void)MACIO_IN32(KEYLARGO_FCR0);
111762306a36Sopenharmony_ci			UNLOCK(flags);
111862306a36Sopenharmony_ci			mdelay(1);
111962306a36Sopenharmony_ci			LOCK(flags);
112062306a36Sopenharmony_ci			MACIO_BIS(KEYLARGO_FCR0, KL0_USB0_CELL_ENABLE);
112162306a36Sopenharmony_ci		} else if (number == 2) {
112262306a36Sopenharmony_ci			MACIO_BIC(KEYLARGO_FCR0, (KL0_USB1_PAD_SUSPEND0 | KL0_USB1_PAD_SUSPEND1));
112362306a36Sopenharmony_ci			UNLOCK(flags);
112462306a36Sopenharmony_ci			(void)MACIO_IN32(KEYLARGO_FCR0);
112562306a36Sopenharmony_ci			mdelay(1);
112662306a36Sopenharmony_ci			LOCK(flags);
112762306a36Sopenharmony_ci			MACIO_BIS(KEYLARGO_FCR0, KL0_USB1_CELL_ENABLE);
112862306a36Sopenharmony_ci		} else if (number == 4) {
112962306a36Sopenharmony_ci			MACIO_BIC(KEYLARGO_FCR1, (KL1_USB2_PAD_SUSPEND0 | KL1_USB2_PAD_SUSPEND1));
113062306a36Sopenharmony_ci			UNLOCK(flags);
113162306a36Sopenharmony_ci			(void)MACIO_IN32(KEYLARGO_FCR1);
113262306a36Sopenharmony_ci			mdelay(1);
113362306a36Sopenharmony_ci			LOCK(flags);
113462306a36Sopenharmony_ci			MACIO_BIS(KEYLARGO_FCR1, KL1_USB2_CELL_ENABLE);
113562306a36Sopenharmony_ci		}
113662306a36Sopenharmony_ci		if (number < 4) {
113762306a36Sopenharmony_ci			reg = MACIO_IN32(KEYLARGO_FCR4);
113862306a36Sopenharmony_ci			reg &=	~(KL4_PORT_WAKEUP_ENABLE(number) | KL4_PORT_RESUME_WAKE_EN(number) |
113962306a36Sopenharmony_ci				KL4_PORT_CONNECT_WAKE_EN(number) | KL4_PORT_DISCONNECT_WAKE_EN(number));
114062306a36Sopenharmony_ci			reg &=	~(KL4_PORT_WAKEUP_ENABLE(number+1) | KL4_PORT_RESUME_WAKE_EN(number+1) |
114162306a36Sopenharmony_ci				KL4_PORT_CONNECT_WAKE_EN(number+1) | KL4_PORT_DISCONNECT_WAKE_EN(number+1));
114262306a36Sopenharmony_ci			MACIO_OUT32(KEYLARGO_FCR4, reg);
114362306a36Sopenharmony_ci			(void)MACIO_IN32(KEYLARGO_FCR4);
114462306a36Sopenharmony_ci			udelay(10);
114562306a36Sopenharmony_ci		} else {
114662306a36Sopenharmony_ci			reg = MACIO_IN32(KEYLARGO_FCR3);
114762306a36Sopenharmony_ci			reg &=	~(KL3_IT_PORT_WAKEUP_ENABLE(0) | KL3_IT_PORT_RESUME_WAKE_EN(0) |
114862306a36Sopenharmony_ci				KL3_IT_PORT_CONNECT_WAKE_EN(0) | KL3_IT_PORT_DISCONNECT_WAKE_EN(0));
114962306a36Sopenharmony_ci			reg &=	~(KL3_IT_PORT_WAKEUP_ENABLE(1) | KL3_IT_PORT_RESUME_WAKE_EN(1) |
115062306a36Sopenharmony_ci				KL3_IT_PORT_CONNECT_WAKE_EN(1) | KL3_IT_PORT_DISCONNECT_WAKE_EN(1));
115162306a36Sopenharmony_ci			MACIO_OUT32(KEYLARGO_FCR3, reg);
115262306a36Sopenharmony_ci			(void)MACIO_IN32(KEYLARGO_FCR3);
115362306a36Sopenharmony_ci			udelay(10);
115462306a36Sopenharmony_ci		}
115562306a36Sopenharmony_ci		if (macio->type == macio_intrepid) {
115662306a36Sopenharmony_ci			/* wait for clock stopped bits to clear */
115762306a36Sopenharmony_ci			u32 test0 = 0, test1 = 0;
115862306a36Sopenharmony_ci			u32 status0, status1;
115962306a36Sopenharmony_ci			int timeout = 1000;
116062306a36Sopenharmony_ci
116162306a36Sopenharmony_ci			UNLOCK(flags);
116262306a36Sopenharmony_ci			switch (number) {
116362306a36Sopenharmony_ci			case 0:
116462306a36Sopenharmony_ci				test0 = UNI_N_CLOCK_STOPPED_USB0;
116562306a36Sopenharmony_ci				test1 = UNI_N_CLOCK_STOPPED_USB0PCI;
116662306a36Sopenharmony_ci				break;
116762306a36Sopenharmony_ci			case 2:
116862306a36Sopenharmony_ci				test0 = UNI_N_CLOCK_STOPPED_USB1;
116962306a36Sopenharmony_ci				test1 = UNI_N_CLOCK_STOPPED_USB1PCI;
117062306a36Sopenharmony_ci				break;
117162306a36Sopenharmony_ci			case 4:
117262306a36Sopenharmony_ci				test0 = UNI_N_CLOCK_STOPPED_USB2;
117362306a36Sopenharmony_ci				test1 = UNI_N_CLOCK_STOPPED_USB2PCI;
117462306a36Sopenharmony_ci				break;
117562306a36Sopenharmony_ci			}
117662306a36Sopenharmony_ci			do {
117762306a36Sopenharmony_ci				if (--timeout <= 0) {
117862306a36Sopenharmony_ci					printk(KERN_ERR "core99_usb_enable: "
117962306a36Sopenharmony_ci					       "Timeout waiting for clocks\n");
118062306a36Sopenharmony_ci					break;
118162306a36Sopenharmony_ci				}
118262306a36Sopenharmony_ci				mdelay(1);
118362306a36Sopenharmony_ci				status0 = UN_IN(UNI_N_CLOCK_STOP_STATUS0);
118462306a36Sopenharmony_ci				status1 = UN_IN(UNI_N_CLOCK_STOP_STATUS1);
118562306a36Sopenharmony_ci			} while ((status0 & test0) | (status1 & test1));
118662306a36Sopenharmony_ci			LOCK(flags);
118762306a36Sopenharmony_ci		}
118862306a36Sopenharmony_ci	} else {
118962306a36Sopenharmony_ci		/* Turn OFF */
119062306a36Sopenharmony_ci		if (number < 4) {
119162306a36Sopenharmony_ci			reg = MACIO_IN32(KEYLARGO_FCR4);
119262306a36Sopenharmony_ci			reg |=	KL4_PORT_WAKEUP_ENABLE(number) | KL4_PORT_RESUME_WAKE_EN(number) |
119362306a36Sopenharmony_ci				KL4_PORT_CONNECT_WAKE_EN(number) | KL4_PORT_DISCONNECT_WAKE_EN(number);
119462306a36Sopenharmony_ci			reg |=	KL4_PORT_WAKEUP_ENABLE(number+1) | KL4_PORT_RESUME_WAKE_EN(number+1) |
119562306a36Sopenharmony_ci				KL4_PORT_CONNECT_WAKE_EN(number+1) | KL4_PORT_DISCONNECT_WAKE_EN(number+1);
119662306a36Sopenharmony_ci			MACIO_OUT32(KEYLARGO_FCR4, reg);
119762306a36Sopenharmony_ci			(void)MACIO_IN32(KEYLARGO_FCR4);
119862306a36Sopenharmony_ci			udelay(1);
119962306a36Sopenharmony_ci		} else {
120062306a36Sopenharmony_ci			reg = MACIO_IN32(KEYLARGO_FCR3);
120162306a36Sopenharmony_ci			reg |=	KL3_IT_PORT_WAKEUP_ENABLE(0) | KL3_IT_PORT_RESUME_WAKE_EN(0) |
120262306a36Sopenharmony_ci				KL3_IT_PORT_CONNECT_WAKE_EN(0) | KL3_IT_PORT_DISCONNECT_WAKE_EN(0);
120362306a36Sopenharmony_ci			reg |=	KL3_IT_PORT_WAKEUP_ENABLE(1) | KL3_IT_PORT_RESUME_WAKE_EN(1) |
120462306a36Sopenharmony_ci				KL3_IT_PORT_CONNECT_WAKE_EN(1) | KL3_IT_PORT_DISCONNECT_WAKE_EN(1);
120562306a36Sopenharmony_ci			MACIO_OUT32(KEYLARGO_FCR3, reg);
120662306a36Sopenharmony_ci			(void)MACIO_IN32(KEYLARGO_FCR3);
120762306a36Sopenharmony_ci			udelay(1);
120862306a36Sopenharmony_ci		}
120962306a36Sopenharmony_ci		if (number == 0) {
121062306a36Sopenharmony_ci			if (macio->type != macio_intrepid)
121162306a36Sopenharmony_ci				MACIO_BIC(KEYLARGO_FCR0, KL0_USB0_CELL_ENABLE);
121262306a36Sopenharmony_ci			(void)MACIO_IN32(KEYLARGO_FCR0);
121362306a36Sopenharmony_ci			udelay(1);
121462306a36Sopenharmony_ci			MACIO_BIS(KEYLARGO_FCR0, (KL0_USB0_PAD_SUSPEND0 | KL0_USB0_PAD_SUSPEND1));
121562306a36Sopenharmony_ci			(void)MACIO_IN32(KEYLARGO_FCR0);
121662306a36Sopenharmony_ci		} else if (number == 2) {
121762306a36Sopenharmony_ci			if (macio->type != macio_intrepid)
121862306a36Sopenharmony_ci				MACIO_BIC(KEYLARGO_FCR0, KL0_USB1_CELL_ENABLE);
121962306a36Sopenharmony_ci			(void)MACIO_IN32(KEYLARGO_FCR0);
122062306a36Sopenharmony_ci			udelay(1);
122162306a36Sopenharmony_ci			MACIO_BIS(KEYLARGO_FCR0, (KL0_USB1_PAD_SUSPEND0 | KL0_USB1_PAD_SUSPEND1));
122262306a36Sopenharmony_ci			(void)MACIO_IN32(KEYLARGO_FCR0);
122362306a36Sopenharmony_ci		} else if (number == 4) {
122462306a36Sopenharmony_ci			udelay(1);
122562306a36Sopenharmony_ci			MACIO_BIS(KEYLARGO_FCR1, (KL1_USB2_PAD_SUSPEND0 | KL1_USB2_PAD_SUSPEND1));
122662306a36Sopenharmony_ci			(void)MACIO_IN32(KEYLARGO_FCR1);
122762306a36Sopenharmony_ci		}
122862306a36Sopenharmony_ci		udelay(1);
122962306a36Sopenharmony_ci	}
123062306a36Sopenharmony_ci	UNLOCK(flags);
123162306a36Sopenharmony_ci
123262306a36Sopenharmony_ci	return 0;
123362306a36Sopenharmony_ci}
123462306a36Sopenharmony_ci
123562306a36Sopenharmony_cistatic long
123662306a36Sopenharmony_cicore99_firewire_enable(struct device_node *node, long param, long value)
123762306a36Sopenharmony_ci{
123862306a36Sopenharmony_ci	unsigned long flags;
123962306a36Sopenharmony_ci	struct macio_chip *macio;
124062306a36Sopenharmony_ci
124162306a36Sopenharmony_ci	macio = &macio_chips[0];
124262306a36Sopenharmony_ci	if (macio->type != macio_keylargo && macio->type != macio_pangea &&
124362306a36Sopenharmony_ci	    macio->type != macio_intrepid)
124462306a36Sopenharmony_ci		return -ENODEV;
124562306a36Sopenharmony_ci	if (!(macio->flags & MACIO_FLAG_FW_SUPPORTED))
124662306a36Sopenharmony_ci		return -ENODEV;
124762306a36Sopenharmony_ci
124862306a36Sopenharmony_ci	LOCK(flags);
124962306a36Sopenharmony_ci	if (value) {
125062306a36Sopenharmony_ci		UN_BIS(UNI_N_CLOCK_CNTL, UNI_N_CLOCK_CNTL_FW);
125162306a36Sopenharmony_ci		(void)UN_IN(UNI_N_CLOCK_CNTL);
125262306a36Sopenharmony_ci	} else {
125362306a36Sopenharmony_ci		UN_BIC(UNI_N_CLOCK_CNTL, UNI_N_CLOCK_CNTL_FW);
125462306a36Sopenharmony_ci		(void)UN_IN(UNI_N_CLOCK_CNTL);
125562306a36Sopenharmony_ci	}
125662306a36Sopenharmony_ci	UNLOCK(flags);
125762306a36Sopenharmony_ci	mdelay(1);
125862306a36Sopenharmony_ci
125962306a36Sopenharmony_ci	return 0;
126062306a36Sopenharmony_ci}
126162306a36Sopenharmony_ci
126262306a36Sopenharmony_cistatic long
126362306a36Sopenharmony_cicore99_firewire_cable_power(struct device_node *node, long param, long value)
126462306a36Sopenharmony_ci{
126562306a36Sopenharmony_ci	unsigned long flags;
126662306a36Sopenharmony_ci	struct macio_chip *macio;
126762306a36Sopenharmony_ci
126862306a36Sopenharmony_ci	/* Trick: we allow NULL node */
126962306a36Sopenharmony_ci	if ((pmac_mb.board_flags & PMAC_MB_HAS_FW_POWER) == 0)
127062306a36Sopenharmony_ci		return -ENODEV;
127162306a36Sopenharmony_ci	macio = &macio_chips[0];
127262306a36Sopenharmony_ci	if (macio->type != macio_keylargo && macio->type != macio_pangea &&
127362306a36Sopenharmony_ci	    macio->type != macio_intrepid)
127462306a36Sopenharmony_ci		return -ENODEV;
127562306a36Sopenharmony_ci	if (!(macio->flags & MACIO_FLAG_FW_SUPPORTED))
127662306a36Sopenharmony_ci		return -ENODEV;
127762306a36Sopenharmony_ci
127862306a36Sopenharmony_ci	LOCK(flags);
127962306a36Sopenharmony_ci	if (value) {
128062306a36Sopenharmony_ci		MACIO_OUT8(KL_GPIO_FW_CABLE_POWER , 0);
128162306a36Sopenharmony_ci		MACIO_IN8(KL_GPIO_FW_CABLE_POWER);
128262306a36Sopenharmony_ci		udelay(10);
128362306a36Sopenharmony_ci	} else {
128462306a36Sopenharmony_ci		MACIO_OUT8(KL_GPIO_FW_CABLE_POWER , 4);
128562306a36Sopenharmony_ci		MACIO_IN8(KL_GPIO_FW_CABLE_POWER); udelay(10);
128662306a36Sopenharmony_ci	}
128762306a36Sopenharmony_ci	UNLOCK(flags);
128862306a36Sopenharmony_ci	mdelay(1);
128962306a36Sopenharmony_ci
129062306a36Sopenharmony_ci	return 0;
129162306a36Sopenharmony_ci}
129262306a36Sopenharmony_ci
129362306a36Sopenharmony_cistatic long
129462306a36Sopenharmony_ciintrepid_aack_delay_enable(struct device_node *node, long param, long value)
129562306a36Sopenharmony_ci{
129662306a36Sopenharmony_ci	unsigned long flags;
129762306a36Sopenharmony_ci
129862306a36Sopenharmony_ci	if (uninorth_rev < 0xd2)
129962306a36Sopenharmony_ci		return -ENODEV;
130062306a36Sopenharmony_ci
130162306a36Sopenharmony_ci	LOCK(flags);
130262306a36Sopenharmony_ci	if (param)
130362306a36Sopenharmony_ci		UN_BIS(UNI_N_AACK_DELAY, UNI_N_AACK_DELAY_ENABLE);
130462306a36Sopenharmony_ci	else
130562306a36Sopenharmony_ci		UN_BIC(UNI_N_AACK_DELAY, UNI_N_AACK_DELAY_ENABLE);
130662306a36Sopenharmony_ci	UNLOCK(flags);
130762306a36Sopenharmony_ci
130862306a36Sopenharmony_ci	return 0;
130962306a36Sopenharmony_ci}
131062306a36Sopenharmony_ci
131162306a36Sopenharmony_ci
131262306a36Sopenharmony_ci#endif /* CONFIG_PPC64 */
131362306a36Sopenharmony_ci
131462306a36Sopenharmony_cistatic long
131562306a36Sopenharmony_cicore99_read_gpio(struct device_node *node, long param, long value)
131662306a36Sopenharmony_ci{
131762306a36Sopenharmony_ci	struct macio_chip *macio = &macio_chips[0];
131862306a36Sopenharmony_ci
131962306a36Sopenharmony_ci	return MACIO_IN8(param);
132062306a36Sopenharmony_ci}
132162306a36Sopenharmony_ci
132262306a36Sopenharmony_ci
132362306a36Sopenharmony_cistatic long
132462306a36Sopenharmony_cicore99_write_gpio(struct device_node *node, long param, long value)
132562306a36Sopenharmony_ci{
132662306a36Sopenharmony_ci	struct macio_chip *macio = &macio_chips[0];
132762306a36Sopenharmony_ci
132862306a36Sopenharmony_ci	MACIO_OUT8(param, (u8)(value & 0xff));
132962306a36Sopenharmony_ci	return 0;
133062306a36Sopenharmony_ci}
133162306a36Sopenharmony_ci
133262306a36Sopenharmony_ci#ifdef CONFIG_PPC64
133362306a36Sopenharmony_cistatic long g5_gmac_enable(struct device_node *node, long param, long value)
133462306a36Sopenharmony_ci{
133562306a36Sopenharmony_ci	struct macio_chip *macio = &macio_chips[0];
133662306a36Sopenharmony_ci	unsigned long flags;
133762306a36Sopenharmony_ci
133862306a36Sopenharmony_ci	if (node == NULL)
133962306a36Sopenharmony_ci		return -ENODEV;
134062306a36Sopenharmony_ci
134162306a36Sopenharmony_ci	LOCK(flags);
134262306a36Sopenharmony_ci	if (value) {
134362306a36Sopenharmony_ci		MACIO_BIS(KEYLARGO_FCR1, K2_FCR1_GMAC_CLK_ENABLE);
134462306a36Sopenharmony_ci		mb();
134562306a36Sopenharmony_ci		k2_skiplist[0] = NULL;
134662306a36Sopenharmony_ci	} else {
134762306a36Sopenharmony_ci		k2_skiplist[0] = node;
134862306a36Sopenharmony_ci		mb();
134962306a36Sopenharmony_ci		MACIO_BIC(KEYLARGO_FCR1, K2_FCR1_GMAC_CLK_ENABLE);
135062306a36Sopenharmony_ci	}
135162306a36Sopenharmony_ci
135262306a36Sopenharmony_ci	UNLOCK(flags);
135362306a36Sopenharmony_ci	mdelay(1);
135462306a36Sopenharmony_ci
135562306a36Sopenharmony_ci	return 0;
135662306a36Sopenharmony_ci}
135762306a36Sopenharmony_ci
135862306a36Sopenharmony_cistatic long g5_fw_enable(struct device_node *node, long param, long value)
135962306a36Sopenharmony_ci{
136062306a36Sopenharmony_ci	struct macio_chip *macio = &macio_chips[0];
136162306a36Sopenharmony_ci	unsigned long flags;
136262306a36Sopenharmony_ci
136362306a36Sopenharmony_ci	if (node == NULL)
136462306a36Sopenharmony_ci		return -ENODEV;
136562306a36Sopenharmony_ci
136662306a36Sopenharmony_ci	LOCK(flags);
136762306a36Sopenharmony_ci	if (value) {
136862306a36Sopenharmony_ci		MACIO_BIS(KEYLARGO_FCR1, K2_FCR1_FW_CLK_ENABLE);
136962306a36Sopenharmony_ci		mb();
137062306a36Sopenharmony_ci		k2_skiplist[1] = NULL;
137162306a36Sopenharmony_ci	} else {
137262306a36Sopenharmony_ci		k2_skiplist[1] = node;
137362306a36Sopenharmony_ci		mb();
137462306a36Sopenharmony_ci		MACIO_BIC(KEYLARGO_FCR1, K2_FCR1_FW_CLK_ENABLE);
137562306a36Sopenharmony_ci	}
137662306a36Sopenharmony_ci
137762306a36Sopenharmony_ci	UNLOCK(flags);
137862306a36Sopenharmony_ci	mdelay(1);
137962306a36Sopenharmony_ci
138062306a36Sopenharmony_ci	return 0;
138162306a36Sopenharmony_ci}
138262306a36Sopenharmony_ci
138362306a36Sopenharmony_cistatic long g5_mpic_enable(struct device_node *node, long param, long value)
138462306a36Sopenharmony_ci{
138562306a36Sopenharmony_ci	unsigned long flags;
138662306a36Sopenharmony_ci	struct device_node *parent = of_get_parent(node);
138762306a36Sopenharmony_ci	int is_u3;
138862306a36Sopenharmony_ci
138962306a36Sopenharmony_ci	if (parent == NULL)
139062306a36Sopenharmony_ci		return 0;
139162306a36Sopenharmony_ci	is_u3 = of_node_name_eq(parent, "u3") || of_node_name_eq(parent, "u4");
139262306a36Sopenharmony_ci	of_node_put(parent);
139362306a36Sopenharmony_ci	if (!is_u3)
139462306a36Sopenharmony_ci		return 0;
139562306a36Sopenharmony_ci
139662306a36Sopenharmony_ci	LOCK(flags);
139762306a36Sopenharmony_ci	UN_BIS(U3_TOGGLE_REG, U3_MPIC_RESET | U3_MPIC_OUTPUT_ENABLE);
139862306a36Sopenharmony_ci	UNLOCK(flags);
139962306a36Sopenharmony_ci
140062306a36Sopenharmony_ci	return 0;
140162306a36Sopenharmony_ci}
140262306a36Sopenharmony_ci
140362306a36Sopenharmony_cistatic long g5_eth_phy_reset(struct device_node *node, long param, long value)
140462306a36Sopenharmony_ci{
140562306a36Sopenharmony_ci	struct macio_chip *macio = &macio_chips[0];
140662306a36Sopenharmony_ci	struct device_node *phy;
140762306a36Sopenharmony_ci	int need_reset;
140862306a36Sopenharmony_ci
140962306a36Sopenharmony_ci	/*
141062306a36Sopenharmony_ci	 * We must not reset the combo PHYs, only the BCM5221 found in
141162306a36Sopenharmony_ci	 * the iMac G5.
141262306a36Sopenharmony_ci	 */
141362306a36Sopenharmony_ci	phy = of_get_next_child(node, NULL);
141462306a36Sopenharmony_ci	if (!phy)
141562306a36Sopenharmony_ci		return -ENODEV;
141662306a36Sopenharmony_ci	need_reset = of_device_is_compatible(phy, "B5221");
141762306a36Sopenharmony_ci	of_node_put(phy);
141862306a36Sopenharmony_ci	if (!need_reset)
141962306a36Sopenharmony_ci		return 0;
142062306a36Sopenharmony_ci
142162306a36Sopenharmony_ci	/* PHY reset is GPIO 29, not in device-tree unfortunately */
142262306a36Sopenharmony_ci	MACIO_OUT8(K2_GPIO_EXTINT_0 + 29,
142362306a36Sopenharmony_ci		   KEYLARGO_GPIO_OUTPUT_ENABLE | KEYLARGO_GPIO_OUTOUT_DATA);
142462306a36Sopenharmony_ci	/* Thankfully, this is now always called at a time when we can
142562306a36Sopenharmony_ci	 * schedule by sungem.
142662306a36Sopenharmony_ci	 */
142762306a36Sopenharmony_ci	msleep(10);
142862306a36Sopenharmony_ci	MACIO_OUT8(K2_GPIO_EXTINT_0 + 29, 0);
142962306a36Sopenharmony_ci
143062306a36Sopenharmony_ci	return 0;
143162306a36Sopenharmony_ci}
143262306a36Sopenharmony_ci
143362306a36Sopenharmony_cistatic long g5_i2s_enable(struct device_node *node, long param, long value)
143462306a36Sopenharmony_ci{
143562306a36Sopenharmony_ci	/* Very crude implementation for now */
143662306a36Sopenharmony_ci	struct macio_chip *macio = &macio_chips[0];
143762306a36Sopenharmony_ci	unsigned long flags;
143862306a36Sopenharmony_ci	int cell;
143962306a36Sopenharmony_ci	u32 fcrs[3][3] = {
144062306a36Sopenharmony_ci		{ 0,
144162306a36Sopenharmony_ci		  K2_FCR1_I2S0_CELL_ENABLE |
144262306a36Sopenharmony_ci		  K2_FCR1_I2S0_CLK_ENABLE_BIT | K2_FCR1_I2S0_ENABLE,
144362306a36Sopenharmony_ci		  KL3_I2S0_CLK18_ENABLE
144462306a36Sopenharmony_ci		},
144562306a36Sopenharmony_ci		{ KL0_SCC_A_INTF_ENABLE,
144662306a36Sopenharmony_ci		  K2_FCR1_I2S1_CELL_ENABLE |
144762306a36Sopenharmony_ci		  K2_FCR1_I2S1_CLK_ENABLE_BIT | K2_FCR1_I2S1_ENABLE,
144862306a36Sopenharmony_ci		  KL3_I2S1_CLK18_ENABLE
144962306a36Sopenharmony_ci		},
145062306a36Sopenharmony_ci		{ KL0_SCC_B_INTF_ENABLE,
145162306a36Sopenharmony_ci		  SH_FCR1_I2S2_CELL_ENABLE |
145262306a36Sopenharmony_ci		  SH_FCR1_I2S2_CLK_ENABLE_BIT | SH_FCR1_I2S2_ENABLE,
145362306a36Sopenharmony_ci		  SH_FCR3_I2S2_CLK18_ENABLE
145462306a36Sopenharmony_ci		},
145562306a36Sopenharmony_ci	};
145662306a36Sopenharmony_ci
145762306a36Sopenharmony_ci	if (macio->type != macio_keylargo2 && macio->type != macio_shasta)
145862306a36Sopenharmony_ci		return -ENODEV;
145962306a36Sopenharmony_ci	if (strncmp(node->name, "i2s-", 4))
146062306a36Sopenharmony_ci		return -ENODEV;
146162306a36Sopenharmony_ci	cell = node->name[4] - 'a';
146262306a36Sopenharmony_ci	switch(cell) {
146362306a36Sopenharmony_ci	case 0:
146462306a36Sopenharmony_ci	case 1:
146562306a36Sopenharmony_ci		break;
146662306a36Sopenharmony_ci	case 2:
146762306a36Sopenharmony_ci		if (macio->type == macio_shasta)
146862306a36Sopenharmony_ci			break;
146962306a36Sopenharmony_ci		fallthrough;
147062306a36Sopenharmony_ci	default:
147162306a36Sopenharmony_ci		return -ENODEV;
147262306a36Sopenharmony_ci	}
147362306a36Sopenharmony_ci
147462306a36Sopenharmony_ci	LOCK(flags);
147562306a36Sopenharmony_ci	if (value) {
147662306a36Sopenharmony_ci		MACIO_BIC(KEYLARGO_FCR0, fcrs[cell][0]);
147762306a36Sopenharmony_ci		MACIO_BIS(KEYLARGO_FCR1, fcrs[cell][1]);
147862306a36Sopenharmony_ci		MACIO_BIS(KEYLARGO_FCR3, fcrs[cell][2]);
147962306a36Sopenharmony_ci	} else {
148062306a36Sopenharmony_ci		MACIO_BIC(KEYLARGO_FCR3, fcrs[cell][2]);
148162306a36Sopenharmony_ci		MACIO_BIC(KEYLARGO_FCR1, fcrs[cell][1]);
148262306a36Sopenharmony_ci		MACIO_BIS(KEYLARGO_FCR0, fcrs[cell][0]);
148362306a36Sopenharmony_ci	}
148462306a36Sopenharmony_ci	udelay(10);
148562306a36Sopenharmony_ci	UNLOCK(flags);
148662306a36Sopenharmony_ci
148762306a36Sopenharmony_ci	return 0;
148862306a36Sopenharmony_ci}
148962306a36Sopenharmony_ci
149062306a36Sopenharmony_ci
149162306a36Sopenharmony_ci#ifdef CONFIG_SMP
149262306a36Sopenharmony_cistatic long g5_reset_cpu(struct device_node *node, long param, long value)
149362306a36Sopenharmony_ci{
149462306a36Sopenharmony_ci	unsigned int reset_io = 0;
149562306a36Sopenharmony_ci	unsigned long flags;
149662306a36Sopenharmony_ci	struct macio_chip *macio;
149762306a36Sopenharmony_ci	struct device_node *np;
149862306a36Sopenharmony_ci
149962306a36Sopenharmony_ci	macio = &macio_chips[0];
150062306a36Sopenharmony_ci	if (macio->type != macio_keylargo2 && macio->type != macio_shasta)
150162306a36Sopenharmony_ci		return -ENODEV;
150262306a36Sopenharmony_ci
150362306a36Sopenharmony_ci	for_each_of_cpu_node(np) {
150462306a36Sopenharmony_ci		const u32 *rst = of_get_property(np, "soft-reset", NULL);
150562306a36Sopenharmony_ci		if (!rst)
150662306a36Sopenharmony_ci			continue;
150762306a36Sopenharmony_ci		if (param == of_get_cpu_hwid(np, 0)) {
150862306a36Sopenharmony_ci			of_node_put(np);
150962306a36Sopenharmony_ci			reset_io = *rst;
151062306a36Sopenharmony_ci			break;
151162306a36Sopenharmony_ci		}
151262306a36Sopenharmony_ci	}
151362306a36Sopenharmony_ci	if (np == NULL || reset_io == 0)
151462306a36Sopenharmony_ci		return -ENODEV;
151562306a36Sopenharmony_ci
151662306a36Sopenharmony_ci	LOCK(flags);
151762306a36Sopenharmony_ci	MACIO_OUT8(reset_io, KEYLARGO_GPIO_OUTPUT_ENABLE);
151862306a36Sopenharmony_ci	(void)MACIO_IN8(reset_io);
151962306a36Sopenharmony_ci	udelay(1);
152062306a36Sopenharmony_ci	MACIO_OUT8(reset_io, 0);
152162306a36Sopenharmony_ci	(void)MACIO_IN8(reset_io);
152262306a36Sopenharmony_ci	UNLOCK(flags);
152362306a36Sopenharmony_ci
152462306a36Sopenharmony_ci	return 0;
152562306a36Sopenharmony_ci}
152662306a36Sopenharmony_ci#endif /* CONFIG_SMP */
152762306a36Sopenharmony_ci
152862306a36Sopenharmony_ci/*
152962306a36Sopenharmony_ci * This can be called from pmac_smp so isn't static
153062306a36Sopenharmony_ci *
153162306a36Sopenharmony_ci * This takes the second CPU off the bus on dual CPU machines
153262306a36Sopenharmony_ci * running UP
153362306a36Sopenharmony_ci */
153462306a36Sopenharmony_civoid __init g5_phy_disable_cpu1(void)
153562306a36Sopenharmony_ci{
153662306a36Sopenharmony_ci	if (uninorth_maj == 3)
153762306a36Sopenharmony_ci		UN_OUT(U3_API_PHY_CONFIG_1, 0);
153862306a36Sopenharmony_ci}
153962306a36Sopenharmony_ci#endif /* CONFIG_PPC64 */
154062306a36Sopenharmony_ci
154162306a36Sopenharmony_ci#ifndef CONFIG_PPC64
154262306a36Sopenharmony_ci
154362306a36Sopenharmony_ci
154462306a36Sopenharmony_ci#ifdef CONFIG_PM
154562306a36Sopenharmony_cistatic u32 save_gpio_levels[2];
154662306a36Sopenharmony_cistatic u8 save_gpio_extint[KEYLARGO_GPIO_EXTINT_CNT];
154762306a36Sopenharmony_cistatic u8 save_gpio_normal[KEYLARGO_GPIO_CNT];
154862306a36Sopenharmony_cistatic u32 save_unin_clock_ctl;
154962306a36Sopenharmony_ci
155062306a36Sopenharmony_cistatic void keylargo_shutdown(struct macio_chip *macio, int sleep_mode)
155162306a36Sopenharmony_ci{
155262306a36Sopenharmony_ci	u32 temp;
155362306a36Sopenharmony_ci
155462306a36Sopenharmony_ci	if (sleep_mode) {
155562306a36Sopenharmony_ci		mdelay(1);
155662306a36Sopenharmony_ci		MACIO_BIS(KEYLARGO_FCR0, KL0_USB_REF_SUSPEND);
155762306a36Sopenharmony_ci		(void)MACIO_IN32(KEYLARGO_FCR0);
155862306a36Sopenharmony_ci		mdelay(1);
155962306a36Sopenharmony_ci	}
156062306a36Sopenharmony_ci
156162306a36Sopenharmony_ci	MACIO_BIC(KEYLARGO_FCR0,KL0_SCCA_ENABLE | KL0_SCCB_ENABLE |
156262306a36Sopenharmony_ci				KL0_SCC_CELL_ENABLE |
156362306a36Sopenharmony_ci				KL0_IRDA_ENABLE | KL0_IRDA_CLK32_ENABLE |
156462306a36Sopenharmony_ci				KL0_IRDA_CLK19_ENABLE);
156562306a36Sopenharmony_ci
156662306a36Sopenharmony_ci	MACIO_BIC(KEYLARGO_MBCR, KL_MBCR_MB0_DEV_MASK);
156762306a36Sopenharmony_ci	MACIO_BIS(KEYLARGO_MBCR, KL_MBCR_MB0_IDE_ENABLE);
156862306a36Sopenharmony_ci
156962306a36Sopenharmony_ci	MACIO_BIC(KEYLARGO_FCR1,
157062306a36Sopenharmony_ci		KL1_AUDIO_SEL_22MCLK | KL1_AUDIO_CLK_ENABLE_BIT |
157162306a36Sopenharmony_ci		KL1_AUDIO_CLK_OUT_ENABLE | KL1_AUDIO_CELL_ENABLE |
157262306a36Sopenharmony_ci		KL1_I2S0_CELL_ENABLE | KL1_I2S0_CLK_ENABLE_BIT |
157362306a36Sopenharmony_ci		KL1_I2S0_ENABLE | KL1_I2S1_CELL_ENABLE |
157462306a36Sopenharmony_ci		KL1_I2S1_CLK_ENABLE_BIT | KL1_I2S1_ENABLE |
157562306a36Sopenharmony_ci		KL1_EIDE0_ENABLE | KL1_EIDE0_RESET_N |
157662306a36Sopenharmony_ci		KL1_EIDE1_ENABLE | KL1_EIDE1_RESET_N |
157762306a36Sopenharmony_ci		KL1_UIDE_ENABLE);
157862306a36Sopenharmony_ci
157962306a36Sopenharmony_ci	MACIO_BIS(KEYLARGO_FCR2, KL2_ALT_DATA_OUT);
158062306a36Sopenharmony_ci	MACIO_BIC(KEYLARGO_FCR2, KL2_IOBUS_ENABLE);
158162306a36Sopenharmony_ci
158262306a36Sopenharmony_ci	temp = MACIO_IN32(KEYLARGO_FCR3);
158362306a36Sopenharmony_ci	if (macio->rev >= 2) {
158462306a36Sopenharmony_ci		temp |= KL3_SHUTDOWN_PLL2X;
158562306a36Sopenharmony_ci		if (sleep_mode)
158662306a36Sopenharmony_ci			temp |= KL3_SHUTDOWN_PLL_TOTAL;
158762306a36Sopenharmony_ci	}
158862306a36Sopenharmony_ci
158962306a36Sopenharmony_ci	temp |= KL3_SHUTDOWN_PLLKW6 | KL3_SHUTDOWN_PLLKW4 |
159062306a36Sopenharmony_ci		KL3_SHUTDOWN_PLLKW35;
159162306a36Sopenharmony_ci	if (sleep_mode)
159262306a36Sopenharmony_ci		temp |= KL3_SHUTDOWN_PLLKW12;
159362306a36Sopenharmony_ci	temp &= ~(KL3_CLK66_ENABLE | KL3_CLK49_ENABLE | KL3_CLK45_ENABLE
159462306a36Sopenharmony_ci		| KL3_CLK31_ENABLE | KL3_I2S1_CLK18_ENABLE | KL3_I2S0_CLK18_ENABLE);
159562306a36Sopenharmony_ci	if (sleep_mode)
159662306a36Sopenharmony_ci		temp &= ~(KL3_TIMER_CLK18_ENABLE | KL3_VIA_CLK16_ENABLE);
159762306a36Sopenharmony_ci	MACIO_OUT32(KEYLARGO_FCR3, temp);
159862306a36Sopenharmony_ci
159962306a36Sopenharmony_ci	/* Flush posted writes & wait a bit */
160062306a36Sopenharmony_ci	(void)MACIO_IN32(KEYLARGO_FCR0); mdelay(1);
160162306a36Sopenharmony_ci}
160262306a36Sopenharmony_ci
160362306a36Sopenharmony_cistatic void pangea_shutdown(struct macio_chip *macio, int sleep_mode)
160462306a36Sopenharmony_ci{
160562306a36Sopenharmony_ci	u32 temp;
160662306a36Sopenharmony_ci
160762306a36Sopenharmony_ci	MACIO_BIC(KEYLARGO_FCR0,KL0_SCCA_ENABLE | KL0_SCCB_ENABLE |
160862306a36Sopenharmony_ci				KL0_SCC_CELL_ENABLE |
160962306a36Sopenharmony_ci				KL0_USB0_CELL_ENABLE | KL0_USB1_CELL_ENABLE);
161062306a36Sopenharmony_ci
161162306a36Sopenharmony_ci	MACIO_BIC(KEYLARGO_FCR1,
161262306a36Sopenharmony_ci		KL1_AUDIO_SEL_22MCLK | KL1_AUDIO_CLK_ENABLE_BIT |
161362306a36Sopenharmony_ci		KL1_AUDIO_CLK_OUT_ENABLE | KL1_AUDIO_CELL_ENABLE |
161462306a36Sopenharmony_ci		KL1_I2S0_CELL_ENABLE | KL1_I2S0_CLK_ENABLE_BIT |
161562306a36Sopenharmony_ci		KL1_I2S0_ENABLE | KL1_I2S1_CELL_ENABLE |
161662306a36Sopenharmony_ci		KL1_I2S1_CLK_ENABLE_BIT | KL1_I2S1_ENABLE |
161762306a36Sopenharmony_ci		KL1_UIDE_ENABLE);
161862306a36Sopenharmony_ci	if (pmac_mb.board_flags & PMAC_MB_MOBILE)
161962306a36Sopenharmony_ci		MACIO_BIC(KEYLARGO_FCR1, KL1_UIDE_RESET_N);
162062306a36Sopenharmony_ci
162162306a36Sopenharmony_ci	MACIO_BIS(KEYLARGO_FCR2, KL2_ALT_DATA_OUT);
162262306a36Sopenharmony_ci
162362306a36Sopenharmony_ci	temp = MACIO_IN32(KEYLARGO_FCR3);
162462306a36Sopenharmony_ci	temp |= KL3_SHUTDOWN_PLLKW6 | KL3_SHUTDOWN_PLLKW4 |
162562306a36Sopenharmony_ci		KL3_SHUTDOWN_PLLKW35;
162662306a36Sopenharmony_ci	temp &= ~(KL3_CLK49_ENABLE | KL3_CLK45_ENABLE | KL3_CLK31_ENABLE
162762306a36Sopenharmony_ci		| KL3_I2S0_CLK18_ENABLE | KL3_I2S1_CLK18_ENABLE);
162862306a36Sopenharmony_ci	if (sleep_mode)
162962306a36Sopenharmony_ci		temp &= ~(KL3_VIA_CLK16_ENABLE | KL3_TIMER_CLK18_ENABLE);
163062306a36Sopenharmony_ci	MACIO_OUT32(KEYLARGO_FCR3, temp);
163162306a36Sopenharmony_ci
163262306a36Sopenharmony_ci	/* Flush posted writes & wait a bit */
163362306a36Sopenharmony_ci	(void)MACIO_IN32(KEYLARGO_FCR0); mdelay(1);
163462306a36Sopenharmony_ci}
163562306a36Sopenharmony_ci
163662306a36Sopenharmony_cistatic void intrepid_shutdown(struct macio_chip *macio, int sleep_mode)
163762306a36Sopenharmony_ci{
163862306a36Sopenharmony_ci	u32 temp;
163962306a36Sopenharmony_ci
164062306a36Sopenharmony_ci	MACIO_BIC(KEYLARGO_FCR0,KL0_SCCA_ENABLE | KL0_SCCB_ENABLE |
164162306a36Sopenharmony_ci		  KL0_SCC_CELL_ENABLE);
164262306a36Sopenharmony_ci
164362306a36Sopenharmony_ci	MACIO_BIC(KEYLARGO_FCR1,
164462306a36Sopenharmony_ci		KL1_I2S0_CELL_ENABLE | KL1_I2S0_CLK_ENABLE_BIT |
164562306a36Sopenharmony_ci		KL1_I2S0_ENABLE | KL1_I2S1_CELL_ENABLE |
164662306a36Sopenharmony_ci		KL1_I2S1_CLK_ENABLE_BIT | KL1_I2S1_ENABLE |
164762306a36Sopenharmony_ci		KL1_EIDE0_ENABLE);
164862306a36Sopenharmony_ci	if (pmac_mb.board_flags & PMAC_MB_MOBILE)
164962306a36Sopenharmony_ci		MACIO_BIC(KEYLARGO_FCR1, KL1_UIDE_RESET_N);
165062306a36Sopenharmony_ci
165162306a36Sopenharmony_ci	temp = MACIO_IN32(KEYLARGO_FCR3);
165262306a36Sopenharmony_ci	temp &= ~(KL3_CLK49_ENABLE | KL3_CLK45_ENABLE |
165362306a36Sopenharmony_ci		  KL3_I2S1_CLK18_ENABLE | KL3_I2S0_CLK18_ENABLE);
165462306a36Sopenharmony_ci	if (sleep_mode)
165562306a36Sopenharmony_ci		temp &= ~(KL3_TIMER_CLK18_ENABLE | KL3_IT_VIA_CLK32_ENABLE);
165662306a36Sopenharmony_ci	MACIO_OUT32(KEYLARGO_FCR3, temp);
165762306a36Sopenharmony_ci
165862306a36Sopenharmony_ci	/* Flush posted writes & wait a bit */
165962306a36Sopenharmony_ci	(void)MACIO_IN32(KEYLARGO_FCR0);
166062306a36Sopenharmony_ci	mdelay(10);
166162306a36Sopenharmony_ci}
166262306a36Sopenharmony_ci
166362306a36Sopenharmony_ci
166462306a36Sopenharmony_cistatic int
166562306a36Sopenharmony_cicore99_sleep(void)
166662306a36Sopenharmony_ci{
166762306a36Sopenharmony_ci	struct macio_chip *macio;
166862306a36Sopenharmony_ci	int i;
166962306a36Sopenharmony_ci
167062306a36Sopenharmony_ci	macio = &macio_chips[0];
167162306a36Sopenharmony_ci	if (macio->type != macio_keylargo && macio->type != macio_pangea &&
167262306a36Sopenharmony_ci	    macio->type != macio_intrepid)
167362306a36Sopenharmony_ci		return -ENODEV;
167462306a36Sopenharmony_ci
167562306a36Sopenharmony_ci	/* We power off the wireless slot in case it was not done
167662306a36Sopenharmony_ci	 * by the driver. We don't power it on automatically however
167762306a36Sopenharmony_ci	 */
167862306a36Sopenharmony_ci	if (macio->flags & MACIO_FLAG_AIRPORT_ON)
167962306a36Sopenharmony_ci		core99_airport_enable(macio->of_node, 0, 0);
168062306a36Sopenharmony_ci
168162306a36Sopenharmony_ci	/* We power off the FW cable. Should be done by the driver... */
168262306a36Sopenharmony_ci	if (macio->flags & MACIO_FLAG_FW_SUPPORTED) {
168362306a36Sopenharmony_ci		core99_firewire_enable(NULL, 0, 0);
168462306a36Sopenharmony_ci		core99_firewire_cable_power(NULL, 0, 0);
168562306a36Sopenharmony_ci	}
168662306a36Sopenharmony_ci
168762306a36Sopenharmony_ci	/* We make sure int. modem is off (in case driver lost it) */
168862306a36Sopenharmony_ci	if (macio->type == macio_keylargo)
168962306a36Sopenharmony_ci		core99_modem_enable(macio->of_node, 0, 0);
169062306a36Sopenharmony_ci	else
169162306a36Sopenharmony_ci		pangea_modem_enable(macio->of_node, 0, 0);
169262306a36Sopenharmony_ci
169362306a36Sopenharmony_ci	/* We make sure the sound is off as well */
169462306a36Sopenharmony_ci	core99_sound_chip_enable(macio->of_node, 0, 0);
169562306a36Sopenharmony_ci
169662306a36Sopenharmony_ci	/*
169762306a36Sopenharmony_ci	 * Save various bits of KeyLargo
169862306a36Sopenharmony_ci	 */
169962306a36Sopenharmony_ci
170062306a36Sopenharmony_ci	/* Save the state of the various GPIOs */
170162306a36Sopenharmony_ci	save_gpio_levels[0] = MACIO_IN32(KEYLARGO_GPIO_LEVELS0);
170262306a36Sopenharmony_ci	save_gpio_levels[1] = MACIO_IN32(KEYLARGO_GPIO_LEVELS1);
170362306a36Sopenharmony_ci	for (i=0; i<KEYLARGO_GPIO_EXTINT_CNT; i++)
170462306a36Sopenharmony_ci		save_gpio_extint[i] = MACIO_IN8(KEYLARGO_GPIO_EXTINT_0+i);
170562306a36Sopenharmony_ci	for (i=0; i<KEYLARGO_GPIO_CNT; i++)
170662306a36Sopenharmony_ci		save_gpio_normal[i] = MACIO_IN8(KEYLARGO_GPIO_0+i);
170762306a36Sopenharmony_ci
170862306a36Sopenharmony_ci	/* Save the FCRs */
170962306a36Sopenharmony_ci	if (macio->type == macio_keylargo)
171062306a36Sopenharmony_ci		save_mbcr = MACIO_IN32(KEYLARGO_MBCR);
171162306a36Sopenharmony_ci	save_fcr[0] = MACIO_IN32(KEYLARGO_FCR0);
171262306a36Sopenharmony_ci	save_fcr[1] = MACIO_IN32(KEYLARGO_FCR1);
171362306a36Sopenharmony_ci	save_fcr[2] = MACIO_IN32(KEYLARGO_FCR2);
171462306a36Sopenharmony_ci	save_fcr[3] = MACIO_IN32(KEYLARGO_FCR3);
171562306a36Sopenharmony_ci	save_fcr[4] = MACIO_IN32(KEYLARGO_FCR4);
171662306a36Sopenharmony_ci	if (macio->type == macio_pangea || macio->type == macio_intrepid)
171762306a36Sopenharmony_ci		save_fcr[5] = MACIO_IN32(KEYLARGO_FCR5);
171862306a36Sopenharmony_ci
171962306a36Sopenharmony_ci	/* Save state & config of DBDMA channels */
172062306a36Sopenharmony_ci	dbdma_save(macio, save_dbdma);
172162306a36Sopenharmony_ci
172262306a36Sopenharmony_ci	/*
172362306a36Sopenharmony_ci	 * Turn off as much as we can
172462306a36Sopenharmony_ci	 */
172562306a36Sopenharmony_ci	if (macio->type == macio_pangea)
172662306a36Sopenharmony_ci		pangea_shutdown(macio, 1);
172762306a36Sopenharmony_ci	else if (macio->type == macio_intrepid)
172862306a36Sopenharmony_ci		intrepid_shutdown(macio, 1);
172962306a36Sopenharmony_ci	else if (macio->type == macio_keylargo)
173062306a36Sopenharmony_ci		keylargo_shutdown(macio, 1);
173162306a36Sopenharmony_ci
173262306a36Sopenharmony_ci	/*
173362306a36Sopenharmony_ci	 * Put the host bridge to sleep
173462306a36Sopenharmony_ci	 */
173562306a36Sopenharmony_ci
173662306a36Sopenharmony_ci	save_unin_clock_ctl = UN_IN(UNI_N_CLOCK_CNTL);
173762306a36Sopenharmony_ci	/* Note: do not switch GMAC off, driver does it when necessary, WOL must keep it
173862306a36Sopenharmony_ci	 * enabled !
173962306a36Sopenharmony_ci	 */
174062306a36Sopenharmony_ci	UN_OUT(UNI_N_CLOCK_CNTL, save_unin_clock_ctl &
174162306a36Sopenharmony_ci	       ~(/*UNI_N_CLOCK_CNTL_GMAC|*/UNI_N_CLOCK_CNTL_FW/*|UNI_N_CLOCK_CNTL_PCI*/));
174262306a36Sopenharmony_ci	udelay(100);
174362306a36Sopenharmony_ci	UN_OUT(UNI_N_HWINIT_STATE, UNI_N_HWINIT_STATE_SLEEPING);
174462306a36Sopenharmony_ci	UN_OUT(UNI_N_POWER_MGT, UNI_N_POWER_MGT_SLEEP);
174562306a36Sopenharmony_ci	mdelay(10);
174662306a36Sopenharmony_ci
174762306a36Sopenharmony_ci	/*
174862306a36Sopenharmony_ci	 * FIXME: A bit of black magic with OpenPIC (don't ask me why)
174962306a36Sopenharmony_ci	 */
175062306a36Sopenharmony_ci	if (pmac_mb.model_id == PMAC_TYPE_SAWTOOTH) {
175162306a36Sopenharmony_ci		MACIO_BIS(0x506e0, 0x00400000);
175262306a36Sopenharmony_ci		MACIO_BIS(0x506e0, 0x80000000);
175362306a36Sopenharmony_ci	}
175462306a36Sopenharmony_ci	return 0;
175562306a36Sopenharmony_ci}
175662306a36Sopenharmony_ci
175762306a36Sopenharmony_cistatic int
175862306a36Sopenharmony_cicore99_wake_up(void)
175962306a36Sopenharmony_ci{
176062306a36Sopenharmony_ci	struct macio_chip *macio;
176162306a36Sopenharmony_ci	int i;
176262306a36Sopenharmony_ci
176362306a36Sopenharmony_ci	macio = &macio_chips[0];
176462306a36Sopenharmony_ci	if (macio->type != macio_keylargo && macio->type != macio_pangea &&
176562306a36Sopenharmony_ci	    macio->type != macio_intrepid)
176662306a36Sopenharmony_ci		return -ENODEV;
176762306a36Sopenharmony_ci
176862306a36Sopenharmony_ci	/*
176962306a36Sopenharmony_ci	 * Wakeup the host bridge
177062306a36Sopenharmony_ci	 */
177162306a36Sopenharmony_ci	UN_OUT(UNI_N_POWER_MGT, UNI_N_POWER_MGT_NORMAL);
177262306a36Sopenharmony_ci	udelay(10);
177362306a36Sopenharmony_ci	UN_OUT(UNI_N_HWINIT_STATE, UNI_N_HWINIT_STATE_RUNNING);
177462306a36Sopenharmony_ci	udelay(10);
177562306a36Sopenharmony_ci
177662306a36Sopenharmony_ci	/*
177762306a36Sopenharmony_ci	 * Restore KeyLargo
177862306a36Sopenharmony_ci	 */
177962306a36Sopenharmony_ci
178062306a36Sopenharmony_ci	if (macio->type == macio_keylargo) {
178162306a36Sopenharmony_ci		MACIO_OUT32(KEYLARGO_MBCR, save_mbcr);
178262306a36Sopenharmony_ci		(void)MACIO_IN32(KEYLARGO_MBCR); udelay(10);
178362306a36Sopenharmony_ci	}
178462306a36Sopenharmony_ci	MACIO_OUT32(KEYLARGO_FCR0, save_fcr[0]);
178562306a36Sopenharmony_ci	(void)MACIO_IN32(KEYLARGO_FCR0); udelay(10);
178662306a36Sopenharmony_ci	MACIO_OUT32(KEYLARGO_FCR1, save_fcr[1]);
178762306a36Sopenharmony_ci	(void)MACIO_IN32(KEYLARGO_FCR1); udelay(10);
178862306a36Sopenharmony_ci	MACIO_OUT32(KEYLARGO_FCR2, save_fcr[2]);
178962306a36Sopenharmony_ci	(void)MACIO_IN32(KEYLARGO_FCR2); udelay(10);
179062306a36Sopenharmony_ci	MACIO_OUT32(KEYLARGO_FCR3, save_fcr[3]);
179162306a36Sopenharmony_ci	(void)MACIO_IN32(KEYLARGO_FCR3); udelay(10);
179262306a36Sopenharmony_ci	MACIO_OUT32(KEYLARGO_FCR4, save_fcr[4]);
179362306a36Sopenharmony_ci	(void)MACIO_IN32(KEYLARGO_FCR4); udelay(10);
179462306a36Sopenharmony_ci	if (macio->type == macio_pangea || macio->type == macio_intrepid) {
179562306a36Sopenharmony_ci		MACIO_OUT32(KEYLARGO_FCR5, save_fcr[5]);
179662306a36Sopenharmony_ci		(void)MACIO_IN32(KEYLARGO_FCR5); udelay(10);
179762306a36Sopenharmony_ci	}
179862306a36Sopenharmony_ci
179962306a36Sopenharmony_ci	dbdma_restore(macio, save_dbdma);
180062306a36Sopenharmony_ci
180162306a36Sopenharmony_ci	MACIO_OUT32(KEYLARGO_GPIO_LEVELS0, save_gpio_levels[0]);
180262306a36Sopenharmony_ci	MACIO_OUT32(KEYLARGO_GPIO_LEVELS1, save_gpio_levels[1]);
180362306a36Sopenharmony_ci	for (i=0; i<KEYLARGO_GPIO_EXTINT_CNT; i++)
180462306a36Sopenharmony_ci		MACIO_OUT8(KEYLARGO_GPIO_EXTINT_0+i, save_gpio_extint[i]);
180562306a36Sopenharmony_ci	for (i=0; i<KEYLARGO_GPIO_CNT; i++)
180662306a36Sopenharmony_ci		MACIO_OUT8(KEYLARGO_GPIO_0+i, save_gpio_normal[i]);
180762306a36Sopenharmony_ci
180862306a36Sopenharmony_ci	/* FIXME more black magic with OpenPIC ... */
180962306a36Sopenharmony_ci	if (pmac_mb.model_id == PMAC_TYPE_SAWTOOTH) {
181062306a36Sopenharmony_ci		MACIO_BIC(0x506e0, 0x00400000);
181162306a36Sopenharmony_ci		MACIO_BIC(0x506e0, 0x80000000);
181262306a36Sopenharmony_ci	}
181362306a36Sopenharmony_ci
181462306a36Sopenharmony_ci	UN_OUT(UNI_N_CLOCK_CNTL, save_unin_clock_ctl);
181562306a36Sopenharmony_ci	udelay(100);
181662306a36Sopenharmony_ci
181762306a36Sopenharmony_ci	return 0;
181862306a36Sopenharmony_ci}
181962306a36Sopenharmony_ci
182062306a36Sopenharmony_ci#endif /* CONFIG_PM */
182162306a36Sopenharmony_ci
182262306a36Sopenharmony_cistatic long
182362306a36Sopenharmony_cicore99_sleep_state(struct device_node *node, long param, long value)
182462306a36Sopenharmony_ci{
182562306a36Sopenharmony_ci	/* Param == 1 means to enter the "fake sleep" mode that is
182662306a36Sopenharmony_ci	 * used for CPU speed switch
182762306a36Sopenharmony_ci	 */
182862306a36Sopenharmony_ci	if (param == 1) {
182962306a36Sopenharmony_ci		if (value == 1) {
183062306a36Sopenharmony_ci			UN_OUT(UNI_N_HWINIT_STATE, UNI_N_HWINIT_STATE_SLEEPING);
183162306a36Sopenharmony_ci			UN_OUT(UNI_N_POWER_MGT, UNI_N_POWER_MGT_IDLE2);
183262306a36Sopenharmony_ci		} else {
183362306a36Sopenharmony_ci			UN_OUT(UNI_N_POWER_MGT, UNI_N_POWER_MGT_NORMAL);
183462306a36Sopenharmony_ci			udelay(10);
183562306a36Sopenharmony_ci			UN_OUT(UNI_N_HWINIT_STATE, UNI_N_HWINIT_STATE_RUNNING);
183662306a36Sopenharmony_ci			udelay(10);
183762306a36Sopenharmony_ci		}
183862306a36Sopenharmony_ci		return 0;
183962306a36Sopenharmony_ci	}
184062306a36Sopenharmony_ci	if ((pmac_mb.board_flags & PMAC_MB_CAN_SLEEP) == 0)
184162306a36Sopenharmony_ci		return -EPERM;
184262306a36Sopenharmony_ci
184362306a36Sopenharmony_ci#ifdef CONFIG_PM
184462306a36Sopenharmony_ci	if (value == 1)
184562306a36Sopenharmony_ci		return core99_sleep();
184662306a36Sopenharmony_ci	else if (value == 0)
184762306a36Sopenharmony_ci		return core99_wake_up();
184862306a36Sopenharmony_ci
184962306a36Sopenharmony_ci#endif /* CONFIG_PM */
185062306a36Sopenharmony_ci	return 0;
185162306a36Sopenharmony_ci}
185262306a36Sopenharmony_ci
185362306a36Sopenharmony_ci#endif /* CONFIG_PPC64 */
185462306a36Sopenharmony_ci
185562306a36Sopenharmony_cistatic long
185662306a36Sopenharmony_cigeneric_dev_can_wake(struct device_node *node, long param, long value)
185762306a36Sopenharmony_ci{
185862306a36Sopenharmony_ci	/* Todo: eventually check we are really dealing with on-board
185962306a36Sopenharmony_ci	 * video device ...
186062306a36Sopenharmony_ci	 */
186162306a36Sopenharmony_ci
186262306a36Sopenharmony_ci	if (pmac_mb.board_flags & PMAC_MB_MAY_SLEEP)
186362306a36Sopenharmony_ci		pmac_mb.board_flags |= PMAC_MB_CAN_SLEEP;
186462306a36Sopenharmony_ci	return 0;
186562306a36Sopenharmony_ci}
186662306a36Sopenharmony_ci
186762306a36Sopenharmony_cistatic long generic_get_mb_info(struct device_node *node, long param, long value)
186862306a36Sopenharmony_ci{
186962306a36Sopenharmony_ci	switch(param) {
187062306a36Sopenharmony_ci		case PMAC_MB_INFO_MODEL:
187162306a36Sopenharmony_ci			return pmac_mb.model_id;
187262306a36Sopenharmony_ci		case PMAC_MB_INFO_FLAGS:
187362306a36Sopenharmony_ci			return pmac_mb.board_flags;
187462306a36Sopenharmony_ci		case PMAC_MB_INFO_NAME:
187562306a36Sopenharmony_ci			/* hack hack hack... but should work */
187662306a36Sopenharmony_ci			*((const char **)value) = pmac_mb.model_name;
187762306a36Sopenharmony_ci			return 0;
187862306a36Sopenharmony_ci	}
187962306a36Sopenharmony_ci	return -EINVAL;
188062306a36Sopenharmony_ci}
188162306a36Sopenharmony_ci
188262306a36Sopenharmony_ci
188362306a36Sopenharmony_ci/*
188462306a36Sopenharmony_ci * Table definitions
188562306a36Sopenharmony_ci */
188662306a36Sopenharmony_ci
188762306a36Sopenharmony_ci/* Used on any machine
188862306a36Sopenharmony_ci */
188962306a36Sopenharmony_cistatic struct feature_table_entry any_features[] = {
189062306a36Sopenharmony_ci	{ PMAC_FTR_GET_MB_INFO,		generic_get_mb_info },
189162306a36Sopenharmony_ci	{ PMAC_FTR_DEVICE_CAN_WAKE,	generic_dev_can_wake },
189262306a36Sopenharmony_ci	{ 0, NULL }
189362306a36Sopenharmony_ci};
189462306a36Sopenharmony_ci
189562306a36Sopenharmony_ci#ifndef CONFIG_PPC64
189662306a36Sopenharmony_ci
189762306a36Sopenharmony_ci/* OHare based motherboards. Currently, we only use these on the
189862306a36Sopenharmony_ci * 2400,3400 and 3500 series powerbooks. Some older desktops seem
189962306a36Sopenharmony_ci * to have issues with turning on/off those asic cells
190062306a36Sopenharmony_ci */
190162306a36Sopenharmony_cistatic struct feature_table_entry ohare_features[] = {
190262306a36Sopenharmony_ci	{ PMAC_FTR_SCC_ENABLE,		ohare_htw_scc_enable },
190362306a36Sopenharmony_ci	{ PMAC_FTR_SWIM3_ENABLE,	ohare_floppy_enable },
190462306a36Sopenharmony_ci	{ PMAC_FTR_MESH_ENABLE,		ohare_mesh_enable },
190562306a36Sopenharmony_ci	{ PMAC_FTR_IDE_ENABLE,		ohare_ide_enable},
190662306a36Sopenharmony_ci	{ PMAC_FTR_IDE_RESET,		ohare_ide_reset},
190762306a36Sopenharmony_ci	{ PMAC_FTR_SLEEP_STATE,		ohare_sleep_state },
190862306a36Sopenharmony_ci	{ 0, NULL }
190962306a36Sopenharmony_ci};
191062306a36Sopenharmony_ci
191162306a36Sopenharmony_ci/* Heathrow desktop machines (Beige G3).
191262306a36Sopenharmony_ci * Separated as some features couldn't be properly tested
191362306a36Sopenharmony_ci * and the serial port control bits appear to confuse it.
191462306a36Sopenharmony_ci */
191562306a36Sopenharmony_cistatic struct feature_table_entry heathrow_desktop_features[] = {
191662306a36Sopenharmony_ci	{ PMAC_FTR_SWIM3_ENABLE,	heathrow_floppy_enable },
191762306a36Sopenharmony_ci	{ PMAC_FTR_MESH_ENABLE,		heathrow_mesh_enable },
191862306a36Sopenharmony_ci	{ PMAC_FTR_IDE_ENABLE,		heathrow_ide_enable },
191962306a36Sopenharmony_ci	{ PMAC_FTR_IDE_RESET,		heathrow_ide_reset },
192062306a36Sopenharmony_ci	{ PMAC_FTR_BMAC_ENABLE,		heathrow_bmac_enable },
192162306a36Sopenharmony_ci	{ 0, NULL }
192262306a36Sopenharmony_ci};
192362306a36Sopenharmony_ci
192462306a36Sopenharmony_ci/* Heathrow based laptop, that is the Wallstreet and mainstreet
192562306a36Sopenharmony_ci * powerbooks.
192662306a36Sopenharmony_ci */
192762306a36Sopenharmony_cistatic struct feature_table_entry heathrow_laptop_features[] = {
192862306a36Sopenharmony_ci	{ PMAC_FTR_SCC_ENABLE,		ohare_htw_scc_enable },
192962306a36Sopenharmony_ci	{ PMAC_FTR_MODEM_ENABLE,	heathrow_modem_enable },
193062306a36Sopenharmony_ci	{ PMAC_FTR_SWIM3_ENABLE,	heathrow_floppy_enable },
193162306a36Sopenharmony_ci	{ PMAC_FTR_MESH_ENABLE,		heathrow_mesh_enable },
193262306a36Sopenharmony_ci	{ PMAC_FTR_IDE_ENABLE,		heathrow_ide_enable },
193362306a36Sopenharmony_ci	{ PMAC_FTR_IDE_RESET,		heathrow_ide_reset },
193462306a36Sopenharmony_ci	{ PMAC_FTR_BMAC_ENABLE,		heathrow_bmac_enable },
193562306a36Sopenharmony_ci	{ PMAC_FTR_SOUND_CHIP_ENABLE,	heathrow_sound_enable },
193662306a36Sopenharmony_ci	{ PMAC_FTR_SLEEP_STATE,		heathrow_sleep_state },
193762306a36Sopenharmony_ci	{ 0, NULL }
193862306a36Sopenharmony_ci};
193962306a36Sopenharmony_ci
194062306a36Sopenharmony_ci/* Paddington based machines
194162306a36Sopenharmony_ci * The lombard (101) powerbook, first iMac models, B&W G3 and Yikes G4.
194262306a36Sopenharmony_ci */
194362306a36Sopenharmony_cistatic struct feature_table_entry paddington_features[] = {
194462306a36Sopenharmony_ci	{ PMAC_FTR_SCC_ENABLE,		ohare_htw_scc_enable },
194562306a36Sopenharmony_ci	{ PMAC_FTR_MODEM_ENABLE,	heathrow_modem_enable },
194662306a36Sopenharmony_ci	{ PMAC_FTR_SWIM3_ENABLE,	heathrow_floppy_enable },
194762306a36Sopenharmony_ci	{ PMAC_FTR_MESH_ENABLE,		heathrow_mesh_enable },
194862306a36Sopenharmony_ci	{ PMAC_FTR_IDE_ENABLE,		heathrow_ide_enable },
194962306a36Sopenharmony_ci	{ PMAC_FTR_IDE_RESET,		heathrow_ide_reset },
195062306a36Sopenharmony_ci	{ PMAC_FTR_BMAC_ENABLE,		heathrow_bmac_enable },
195162306a36Sopenharmony_ci	{ PMAC_FTR_SOUND_CHIP_ENABLE,	heathrow_sound_enable },
195262306a36Sopenharmony_ci	{ PMAC_FTR_SLEEP_STATE,		heathrow_sleep_state },
195362306a36Sopenharmony_ci	{ 0, NULL }
195462306a36Sopenharmony_ci};
195562306a36Sopenharmony_ci
195662306a36Sopenharmony_ci/* Core99 & MacRISC 2 machines (all machines released since the
195762306a36Sopenharmony_ci * iBook (included), that is all AGP machines, except pangea
195862306a36Sopenharmony_ci * chipset. The pangea chipset is the "combo" UniNorth/KeyLargo
195962306a36Sopenharmony_ci * used on iBook2 & iMac "flow power".
196062306a36Sopenharmony_ci */
196162306a36Sopenharmony_cistatic struct feature_table_entry core99_features[] = {
196262306a36Sopenharmony_ci	{ PMAC_FTR_SCC_ENABLE,		core99_scc_enable },
196362306a36Sopenharmony_ci	{ PMAC_FTR_MODEM_ENABLE,	core99_modem_enable },
196462306a36Sopenharmony_ci	{ PMAC_FTR_IDE_ENABLE,		core99_ide_enable },
196562306a36Sopenharmony_ci	{ PMAC_FTR_IDE_RESET,		core99_ide_reset },
196662306a36Sopenharmony_ci	{ PMAC_FTR_GMAC_ENABLE,		core99_gmac_enable },
196762306a36Sopenharmony_ci	{ PMAC_FTR_GMAC_PHY_RESET,	core99_gmac_phy_reset },
196862306a36Sopenharmony_ci	{ PMAC_FTR_SOUND_CHIP_ENABLE,	core99_sound_chip_enable },
196962306a36Sopenharmony_ci	{ PMAC_FTR_AIRPORT_ENABLE,	core99_airport_enable },
197062306a36Sopenharmony_ci	{ PMAC_FTR_USB_ENABLE,		core99_usb_enable },
197162306a36Sopenharmony_ci	{ PMAC_FTR_1394_ENABLE,		core99_firewire_enable },
197262306a36Sopenharmony_ci	{ PMAC_FTR_1394_CABLE_POWER,	core99_firewire_cable_power },
197362306a36Sopenharmony_ci#ifdef CONFIG_PM
197462306a36Sopenharmony_ci	{ PMAC_FTR_SLEEP_STATE,		core99_sleep_state },
197562306a36Sopenharmony_ci#endif
197662306a36Sopenharmony_ci#ifdef CONFIG_SMP
197762306a36Sopenharmony_ci	{ PMAC_FTR_RESET_CPU,		core99_reset_cpu },
197862306a36Sopenharmony_ci#endif /* CONFIG_SMP */
197962306a36Sopenharmony_ci	{ PMAC_FTR_READ_GPIO,		core99_read_gpio },
198062306a36Sopenharmony_ci	{ PMAC_FTR_WRITE_GPIO,		core99_write_gpio },
198162306a36Sopenharmony_ci	{ 0, NULL }
198262306a36Sopenharmony_ci};
198362306a36Sopenharmony_ci
198462306a36Sopenharmony_ci/* RackMac
198562306a36Sopenharmony_ci */
198662306a36Sopenharmony_cistatic struct feature_table_entry rackmac_features[] = {
198762306a36Sopenharmony_ci	{ PMAC_FTR_SCC_ENABLE,		core99_scc_enable },
198862306a36Sopenharmony_ci	{ PMAC_FTR_IDE_ENABLE,		core99_ide_enable },
198962306a36Sopenharmony_ci	{ PMAC_FTR_IDE_RESET,		core99_ide_reset },
199062306a36Sopenharmony_ci	{ PMAC_FTR_GMAC_ENABLE,		core99_gmac_enable },
199162306a36Sopenharmony_ci	{ PMAC_FTR_GMAC_PHY_RESET,	core99_gmac_phy_reset },
199262306a36Sopenharmony_ci	{ PMAC_FTR_USB_ENABLE,		core99_usb_enable },
199362306a36Sopenharmony_ci	{ PMAC_FTR_1394_ENABLE,		core99_firewire_enable },
199462306a36Sopenharmony_ci	{ PMAC_FTR_1394_CABLE_POWER,	core99_firewire_cable_power },
199562306a36Sopenharmony_ci	{ PMAC_FTR_SLEEP_STATE,		core99_sleep_state },
199662306a36Sopenharmony_ci#ifdef CONFIG_SMP
199762306a36Sopenharmony_ci	{ PMAC_FTR_RESET_CPU,		core99_reset_cpu },
199862306a36Sopenharmony_ci#endif /* CONFIG_SMP */
199962306a36Sopenharmony_ci	{ PMAC_FTR_READ_GPIO,		core99_read_gpio },
200062306a36Sopenharmony_ci	{ PMAC_FTR_WRITE_GPIO,		core99_write_gpio },
200162306a36Sopenharmony_ci	{ 0, NULL }
200262306a36Sopenharmony_ci};
200362306a36Sopenharmony_ci
200462306a36Sopenharmony_ci/* Pangea features
200562306a36Sopenharmony_ci */
200662306a36Sopenharmony_cistatic struct feature_table_entry pangea_features[] = {
200762306a36Sopenharmony_ci	{ PMAC_FTR_SCC_ENABLE,		core99_scc_enable },
200862306a36Sopenharmony_ci	{ PMAC_FTR_MODEM_ENABLE,	pangea_modem_enable },
200962306a36Sopenharmony_ci	{ PMAC_FTR_IDE_ENABLE,		core99_ide_enable },
201062306a36Sopenharmony_ci	{ PMAC_FTR_IDE_RESET,		core99_ide_reset },
201162306a36Sopenharmony_ci	{ PMAC_FTR_GMAC_ENABLE,		core99_gmac_enable },
201262306a36Sopenharmony_ci	{ PMAC_FTR_GMAC_PHY_RESET,	core99_gmac_phy_reset },
201362306a36Sopenharmony_ci	{ PMAC_FTR_SOUND_CHIP_ENABLE,	core99_sound_chip_enable },
201462306a36Sopenharmony_ci	{ PMAC_FTR_AIRPORT_ENABLE,	core99_airport_enable },
201562306a36Sopenharmony_ci	{ PMAC_FTR_USB_ENABLE,		core99_usb_enable },
201662306a36Sopenharmony_ci	{ PMAC_FTR_1394_ENABLE,		core99_firewire_enable },
201762306a36Sopenharmony_ci	{ PMAC_FTR_1394_CABLE_POWER,	core99_firewire_cable_power },
201862306a36Sopenharmony_ci	{ PMAC_FTR_SLEEP_STATE,		core99_sleep_state },
201962306a36Sopenharmony_ci	{ PMAC_FTR_READ_GPIO,		core99_read_gpio },
202062306a36Sopenharmony_ci	{ PMAC_FTR_WRITE_GPIO,		core99_write_gpio },
202162306a36Sopenharmony_ci	{ 0, NULL }
202262306a36Sopenharmony_ci};
202362306a36Sopenharmony_ci
202462306a36Sopenharmony_ci/* Intrepid features
202562306a36Sopenharmony_ci */
202662306a36Sopenharmony_cistatic struct feature_table_entry intrepid_features[] = {
202762306a36Sopenharmony_ci	{ PMAC_FTR_SCC_ENABLE,		core99_scc_enable },
202862306a36Sopenharmony_ci	{ PMAC_FTR_MODEM_ENABLE,	pangea_modem_enable },
202962306a36Sopenharmony_ci	{ PMAC_FTR_IDE_ENABLE,		core99_ide_enable },
203062306a36Sopenharmony_ci	{ PMAC_FTR_IDE_RESET,		core99_ide_reset },
203162306a36Sopenharmony_ci	{ PMAC_FTR_GMAC_ENABLE,		core99_gmac_enable },
203262306a36Sopenharmony_ci	{ PMAC_FTR_GMAC_PHY_RESET,	core99_gmac_phy_reset },
203362306a36Sopenharmony_ci	{ PMAC_FTR_SOUND_CHIP_ENABLE,	core99_sound_chip_enable },
203462306a36Sopenharmony_ci	{ PMAC_FTR_AIRPORT_ENABLE,	core99_airport_enable },
203562306a36Sopenharmony_ci	{ PMAC_FTR_USB_ENABLE,		core99_usb_enable },
203662306a36Sopenharmony_ci	{ PMAC_FTR_1394_ENABLE,		core99_firewire_enable },
203762306a36Sopenharmony_ci	{ PMAC_FTR_1394_CABLE_POWER,	core99_firewire_cable_power },
203862306a36Sopenharmony_ci	{ PMAC_FTR_SLEEP_STATE,		core99_sleep_state },
203962306a36Sopenharmony_ci	{ PMAC_FTR_READ_GPIO,		core99_read_gpio },
204062306a36Sopenharmony_ci	{ PMAC_FTR_WRITE_GPIO,		core99_write_gpio },
204162306a36Sopenharmony_ci	{ PMAC_FTR_AACK_DELAY_ENABLE,	intrepid_aack_delay_enable },
204262306a36Sopenharmony_ci	{ 0, NULL }
204362306a36Sopenharmony_ci};
204462306a36Sopenharmony_ci
204562306a36Sopenharmony_ci#else /* CONFIG_PPC64 */
204662306a36Sopenharmony_ci
204762306a36Sopenharmony_ci/* G5 features
204862306a36Sopenharmony_ci */
204962306a36Sopenharmony_cistatic struct feature_table_entry g5_features[] = {
205062306a36Sopenharmony_ci	{ PMAC_FTR_GMAC_ENABLE,		g5_gmac_enable },
205162306a36Sopenharmony_ci	{ PMAC_FTR_1394_ENABLE,		g5_fw_enable },
205262306a36Sopenharmony_ci	{ PMAC_FTR_ENABLE_MPIC,		g5_mpic_enable },
205362306a36Sopenharmony_ci	{ PMAC_FTR_GMAC_PHY_RESET,	g5_eth_phy_reset },
205462306a36Sopenharmony_ci	{ PMAC_FTR_SOUND_CHIP_ENABLE,	g5_i2s_enable },
205562306a36Sopenharmony_ci#ifdef CONFIG_SMP
205662306a36Sopenharmony_ci	{ PMAC_FTR_RESET_CPU,		g5_reset_cpu },
205762306a36Sopenharmony_ci#endif /* CONFIG_SMP */
205862306a36Sopenharmony_ci	{ PMAC_FTR_READ_GPIO,		core99_read_gpio },
205962306a36Sopenharmony_ci	{ PMAC_FTR_WRITE_GPIO,		core99_write_gpio },
206062306a36Sopenharmony_ci	{ 0, NULL }
206162306a36Sopenharmony_ci};
206262306a36Sopenharmony_ci
206362306a36Sopenharmony_ci#endif /* CONFIG_PPC64 */
206462306a36Sopenharmony_ci
206562306a36Sopenharmony_cistatic struct pmac_mb_def pmac_mb_defs[] = {
206662306a36Sopenharmony_ci#ifndef CONFIG_PPC64
206762306a36Sopenharmony_ci	/*
206862306a36Sopenharmony_ci	 * Desktops
206962306a36Sopenharmony_ci	 */
207062306a36Sopenharmony_ci
207162306a36Sopenharmony_ci	{	"AAPL,8500",			"PowerMac 8500/8600",
207262306a36Sopenharmony_ci		PMAC_TYPE_PSURGE,		NULL,
207362306a36Sopenharmony_ci		0
207462306a36Sopenharmony_ci	},
207562306a36Sopenharmony_ci	{	"AAPL,9500",			"PowerMac 9500/9600",
207662306a36Sopenharmony_ci		PMAC_TYPE_PSURGE,		NULL,
207762306a36Sopenharmony_ci		0
207862306a36Sopenharmony_ci	},
207962306a36Sopenharmony_ci	{	"AAPL,7200",			"PowerMac 7200",
208062306a36Sopenharmony_ci		PMAC_TYPE_PSURGE,		NULL,
208162306a36Sopenharmony_ci		0
208262306a36Sopenharmony_ci	},
208362306a36Sopenharmony_ci	{	"AAPL,7300",			"PowerMac 7200/7300",
208462306a36Sopenharmony_ci		PMAC_TYPE_PSURGE,		NULL,
208562306a36Sopenharmony_ci		0
208662306a36Sopenharmony_ci	},
208762306a36Sopenharmony_ci	{	"AAPL,7500",			"PowerMac 7500",
208862306a36Sopenharmony_ci		PMAC_TYPE_PSURGE,		NULL,
208962306a36Sopenharmony_ci		0
209062306a36Sopenharmony_ci	},
209162306a36Sopenharmony_ci	{	"AAPL,ShinerESB",		"Apple Network Server",
209262306a36Sopenharmony_ci		PMAC_TYPE_ANS,			NULL,
209362306a36Sopenharmony_ci		0
209462306a36Sopenharmony_ci	},
209562306a36Sopenharmony_ci	{	"AAPL,e407",			"Alchemy",
209662306a36Sopenharmony_ci		PMAC_TYPE_ALCHEMY,		NULL,
209762306a36Sopenharmony_ci		0
209862306a36Sopenharmony_ci	},
209962306a36Sopenharmony_ci	{	"AAPL,e411",			"Gazelle",
210062306a36Sopenharmony_ci		PMAC_TYPE_GAZELLE,		NULL,
210162306a36Sopenharmony_ci		0
210262306a36Sopenharmony_ci	},
210362306a36Sopenharmony_ci	{	"AAPL,Gossamer",		"PowerMac G3 (Gossamer)",
210462306a36Sopenharmony_ci		PMAC_TYPE_GOSSAMER,		heathrow_desktop_features,
210562306a36Sopenharmony_ci		0
210662306a36Sopenharmony_ci	},
210762306a36Sopenharmony_ci	{	"AAPL,PowerMac G3",		"PowerMac G3 (Silk)",
210862306a36Sopenharmony_ci		PMAC_TYPE_SILK,			heathrow_desktop_features,
210962306a36Sopenharmony_ci		0
211062306a36Sopenharmony_ci	},
211162306a36Sopenharmony_ci	{	"PowerMac1,1",			"Blue&White G3",
211262306a36Sopenharmony_ci		PMAC_TYPE_YOSEMITE,		paddington_features,
211362306a36Sopenharmony_ci		0
211462306a36Sopenharmony_ci	},
211562306a36Sopenharmony_ci	{	"PowerMac1,2",			"PowerMac G4 PCI Graphics",
211662306a36Sopenharmony_ci		PMAC_TYPE_YIKES,		paddington_features,
211762306a36Sopenharmony_ci		0
211862306a36Sopenharmony_ci	},
211962306a36Sopenharmony_ci	{	"PowerMac2,1",			"iMac FireWire",
212062306a36Sopenharmony_ci		PMAC_TYPE_FW_IMAC,		core99_features,
212162306a36Sopenharmony_ci		PMAC_MB_MAY_SLEEP | PMAC_MB_OLD_CORE99
212262306a36Sopenharmony_ci	},
212362306a36Sopenharmony_ci	{	"PowerMac2,2",			"iMac FireWire",
212462306a36Sopenharmony_ci		PMAC_TYPE_FW_IMAC,		core99_features,
212562306a36Sopenharmony_ci		PMAC_MB_MAY_SLEEP | PMAC_MB_OLD_CORE99
212662306a36Sopenharmony_ci	},
212762306a36Sopenharmony_ci	{	"PowerMac3,1",			"PowerMac G4 AGP Graphics",
212862306a36Sopenharmony_ci		PMAC_TYPE_SAWTOOTH,		core99_features,
212962306a36Sopenharmony_ci		PMAC_MB_OLD_CORE99
213062306a36Sopenharmony_ci	},
213162306a36Sopenharmony_ci	{	"PowerMac3,2",			"PowerMac G4 AGP Graphics",
213262306a36Sopenharmony_ci		PMAC_TYPE_SAWTOOTH,		core99_features,
213362306a36Sopenharmony_ci		PMAC_MB_MAY_SLEEP | PMAC_MB_OLD_CORE99
213462306a36Sopenharmony_ci	},
213562306a36Sopenharmony_ci	{	"PowerMac3,3",			"PowerMac G4 AGP Graphics",
213662306a36Sopenharmony_ci		PMAC_TYPE_SAWTOOTH,		core99_features,
213762306a36Sopenharmony_ci		PMAC_MB_MAY_SLEEP | PMAC_MB_OLD_CORE99
213862306a36Sopenharmony_ci	},
213962306a36Sopenharmony_ci	{	"PowerMac3,4",			"PowerMac G4 Silver",
214062306a36Sopenharmony_ci		PMAC_TYPE_QUICKSILVER,		core99_features,
214162306a36Sopenharmony_ci		PMAC_MB_MAY_SLEEP
214262306a36Sopenharmony_ci	},
214362306a36Sopenharmony_ci	{	"PowerMac3,5",			"PowerMac G4 Silver",
214462306a36Sopenharmony_ci		PMAC_TYPE_QUICKSILVER,		core99_features,
214562306a36Sopenharmony_ci		PMAC_MB_MAY_SLEEP
214662306a36Sopenharmony_ci	},
214762306a36Sopenharmony_ci	{	"PowerMac3,6",			"PowerMac G4 Windtunnel",
214862306a36Sopenharmony_ci		PMAC_TYPE_WINDTUNNEL,		core99_features,
214962306a36Sopenharmony_ci		PMAC_MB_MAY_SLEEP,
215062306a36Sopenharmony_ci	},
215162306a36Sopenharmony_ci	{	"PowerMac4,1",			"iMac \"Flower Power\"",
215262306a36Sopenharmony_ci		PMAC_TYPE_PANGEA_IMAC,		pangea_features,
215362306a36Sopenharmony_ci		PMAC_MB_MAY_SLEEP
215462306a36Sopenharmony_ci	},
215562306a36Sopenharmony_ci	{	"PowerMac4,2",			"Flat panel iMac",
215662306a36Sopenharmony_ci		PMAC_TYPE_FLAT_PANEL_IMAC,	pangea_features,
215762306a36Sopenharmony_ci		PMAC_MB_CAN_SLEEP
215862306a36Sopenharmony_ci	},
215962306a36Sopenharmony_ci	{	"PowerMac4,4",			"eMac",
216062306a36Sopenharmony_ci		PMAC_TYPE_EMAC,			core99_features,
216162306a36Sopenharmony_ci		PMAC_MB_MAY_SLEEP
216262306a36Sopenharmony_ci	},
216362306a36Sopenharmony_ci	{	"PowerMac5,1",			"PowerMac G4 Cube",
216462306a36Sopenharmony_ci		PMAC_TYPE_CUBE,			core99_features,
216562306a36Sopenharmony_ci		PMAC_MB_MAY_SLEEP | PMAC_MB_OLD_CORE99
216662306a36Sopenharmony_ci	},
216762306a36Sopenharmony_ci	{	"PowerMac6,1",			"Flat panel iMac",
216862306a36Sopenharmony_ci		PMAC_TYPE_UNKNOWN_INTREPID,	intrepid_features,
216962306a36Sopenharmony_ci		PMAC_MB_MAY_SLEEP,
217062306a36Sopenharmony_ci	},
217162306a36Sopenharmony_ci	{	"PowerMac6,3",			"Flat panel iMac",
217262306a36Sopenharmony_ci		PMAC_TYPE_UNKNOWN_INTREPID,	intrepid_features,
217362306a36Sopenharmony_ci		PMAC_MB_MAY_SLEEP,
217462306a36Sopenharmony_ci	},
217562306a36Sopenharmony_ci	{	"PowerMac6,4",			"eMac",
217662306a36Sopenharmony_ci		PMAC_TYPE_UNKNOWN_INTREPID,	intrepid_features,
217762306a36Sopenharmony_ci		PMAC_MB_MAY_SLEEP,
217862306a36Sopenharmony_ci	},
217962306a36Sopenharmony_ci	{	"PowerMac10,1",			"Mac mini",
218062306a36Sopenharmony_ci		PMAC_TYPE_UNKNOWN_INTREPID,	intrepid_features,
218162306a36Sopenharmony_ci		PMAC_MB_MAY_SLEEP,
218262306a36Sopenharmony_ci	},
218362306a36Sopenharmony_ci	{       "PowerMac10,2",                 "Mac mini (Late 2005)",
218462306a36Sopenharmony_ci		PMAC_TYPE_UNKNOWN_INTREPID,     intrepid_features,
218562306a36Sopenharmony_ci		PMAC_MB_MAY_SLEEP,
218662306a36Sopenharmony_ci	},
218762306a36Sopenharmony_ci 	{	"iMac,1",			"iMac (first generation)",
218862306a36Sopenharmony_ci		PMAC_TYPE_ORIG_IMAC,		paddington_features,
218962306a36Sopenharmony_ci		0
219062306a36Sopenharmony_ci	},
219162306a36Sopenharmony_ci
219262306a36Sopenharmony_ci	/*
219362306a36Sopenharmony_ci	 * Xserve's
219462306a36Sopenharmony_ci	 */
219562306a36Sopenharmony_ci
219662306a36Sopenharmony_ci	{	"RackMac1,1",			"XServe",
219762306a36Sopenharmony_ci		PMAC_TYPE_RACKMAC,		rackmac_features,
219862306a36Sopenharmony_ci		0,
219962306a36Sopenharmony_ci	},
220062306a36Sopenharmony_ci	{	"RackMac1,2",			"XServe rev. 2",
220162306a36Sopenharmony_ci		PMAC_TYPE_RACKMAC,		rackmac_features,
220262306a36Sopenharmony_ci		0,
220362306a36Sopenharmony_ci	},
220462306a36Sopenharmony_ci
220562306a36Sopenharmony_ci	/*
220662306a36Sopenharmony_ci	 * Laptops
220762306a36Sopenharmony_ci	 */
220862306a36Sopenharmony_ci
220962306a36Sopenharmony_ci	{	"AAPL,3400/2400",		"PowerBook 3400",
221062306a36Sopenharmony_ci		PMAC_TYPE_HOOPER,		ohare_features,
221162306a36Sopenharmony_ci		PMAC_MB_CAN_SLEEP | PMAC_MB_MOBILE
221262306a36Sopenharmony_ci	},
221362306a36Sopenharmony_ci	{	"AAPL,3500",			"PowerBook 3500",
221462306a36Sopenharmony_ci		PMAC_TYPE_KANGA,		ohare_features,
221562306a36Sopenharmony_ci		PMAC_MB_CAN_SLEEP | PMAC_MB_MOBILE
221662306a36Sopenharmony_ci	},
221762306a36Sopenharmony_ci	{	"AAPL,PowerBook1998",		"PowerBook Wallstreet",
221862306a36Sopenharmony_ci		PMAC_TYPE_WALLSTREET,		heathrow_laptop_features,
221962306a36Sopenharmony_ci		PMAC_MB_CAN_SLEEP | PMAC_MB_MOBILE
222062306a36Sopenharmony_ci	},
222162306a36Sopenharmony_ci	{	"PowerBook1,1",			"PowerBook 101 (Lombard)",
222262306a36Sopenharmony_ci		PMAC_TYPE_101_PBOOK,		paddington_features,
222362306a36Sopenharmony_ci		PMAC_MB_CAN_SLEEP | PMAC_MB_MOBILE
222462306a36Sopenharmony_ci	},
222562306a36Sopenharmony_ci	{	"PowerBook2,1",			"iBook (first generation)",
222662306a36Sopenharmony_ci		PMAC_TYPE_ORIG_IBOOK,		core99_features,
222762306a36Sopenharmony_ci		PMAC_MB_CAN_SLEEP | PMAC_MB_OLD_CORE99 | PMAC_MB_MOBILE
222862306a36Sopenharmony_ci	},
222962306a36Sopenharmony_ci	{	"PowerBook2,2",			"iBook FireWire",
223062306a36Sopenharmony_ci		PMAC_TYPE_FW_IBOOK,		core99_features,
223162306a36Sopenharmony_ci		PMAC_MB_MAY_SLEEP | PMAC_MB_HAS_FW_POWER |
223262306a36Sopenharmony_ci		PMAC_MB_OLD_CORE99 | PMAC_MB_MOBILE
223362306a36Sopenharmony_ci	},
223462306a36Sopenharmony_ci	{	"PowerBook3,1",			"PowerBook Pismo",
223562306a36Sopenharmony_ci		PMAC_TYPE_PISMO,		core99_features,
223662306a36Sopenharmony_ci		PMAC_MB_MAY_SLEEP | PMAC_MB_HAS_FW_POWER |
223762306a36Sopenharmony_ci		PMAC_MB_OLD_CORE99 | PMAC_MB_MOBILE
223862306a36Sopenharmony_ci	},
223962306a36Sopenharmony_ci	{	"PowerBook3,2",			"PowerBook Titanium",
224062306a36Sopenharmony_ci		PMAC_TYPE_TITANIUM,		core99_features,
224162306a36Sopenharmony_ci		PMAC_MB_MAY_SLEEP | PMAC_MB_HAS_FW_POWER | PMAC_MB_MOBILE
224262306a36Sopenharmony_ci	},
224362306a36Sopenharmony_ci	{	"PowerBook3,3",			"PowerBook Titanium II",
224462306a36Sopenharmony_ci		PMAC_TYPE_TITANIUM2,		core99_features,
224562306a36Sopenharmony_ci		PMAC_MB_MAY_SLEEP | PMAC_MB_HAS_FW_POWER | PMAC_MB_MOBILE
224662306a36Sopenharmony_ci	},
224762306a36Sopenharmony_ci	{	"PowerBook3,4",			"PowerBook Titanium III",
224862306a36Sopenharmony_ci		PMAC_TYPE_TITANIUM3,		core99_features,
224962306a36Sopenharmony_ci		PMAC_MB_MAY_SLEEP | PMAC_MB_HAS_FW_POWER | PMAC_MB_MOBILE
225062306a36Sopenharmony_ci	},
225162306a36Sopenharmony_ci	{	"PowerBook3,5",			"PowerBook Titanium IV",
225262306a36Sopenharmony_ci		PMAC_TYPE_TITANIUM4,		core99_features,
225362306a36Sopenharmony_ci		PMAC_MB_MAY_SLEEP | PMAC_MB_HAS_FW_POWER | PMAC_MB_MOBILE
225462306a36Sopenharmony_ci	},
225562306a36Sopenharmony_ci	{	"PowerBook4,1",			"iBook 2",
225662306a36Sopenharmony_ci		PMAC_TYPE_IBOOK2,		pangea_features,
225762306a36Sopenharmony_ci		PMAC_MB_MAY_SLEEP | PMAC_MB_HAS_FW_POWER | PMAC_MB_MOBILE
225862306a36Sopenharmony_ci	},
225962306a36Sopenharmony_ci	{	"PowerBook4,2",			"iBook 2",
226062306a36Sopenharmony_ci		PMAC_TYPE_IBOOK2,		pangea_features,
226162306a36Sopenharmony_ci		PMAC_MB_MAY_SLEEP | PMAC_MB_HAS_FW_POWER | PMAC_MB_MOBILE
226262306a36Sopenharmony_ci	},
226362306a36Sopenharmony_ci	{	"PowerBook4,3",			"iBook 2 rev. 2",
226462306a36Sopenharmony_ci		PMAC_TYPE_IBOOK2,		pangea_features,
226562306a36Sopenharmony_ci		PMAC_MB_MAY_SLEEP | PMAC_MB_HAS_FW_POWER | PMAC_MB_MOBILE
226662306a36Sopenharmony_ci	},
226762306a36Sopenharmony_ci	{	"PowerBook5,1",			"PowerBook G4 17\"",
226862306a36Sopenharmony_ci		PMAC_TYPE_UNKNOWN_INTREPID,	intrepid_features,
226962306a36Sopenharmony_ci		PMAC_MB_HAS_FW_POWER | PMAC_MB_MOBILE,
227062306a36Sopenharmony_ci	},
227162306a36Sopenharmony_ci	{	"PowerBook5,2",			"PowerBook G4 15\"",
227262306a36Sopenharmony_ci		PMAC_TYPE_UNKNOWN_INTREPID,	intrepid_features,
227362306a36Sopenharmony_ci		PMAC_MB_MAY_SLEEP | PMAC_MB_HAS_FW_POWER | PMAC_MB_MOBILE,
227462306a36Sopenharmony_ci	},
227562306a36Sopenharmony_ci	{	"PowerBook5,3",			"PowerBook G4 17\"",
227662306a36Sopenharmony_ci		PMAC_TYPE_UNKNOWN_INTREPID,	intrepid_features,
227762306a36Sopenharmony_ci		PMAC_MB_MAY_SLEEP | PMAC_MB_HAS_FW_POWER | PMAC_MB_MOBILE,
227862306a36Sopenharmony_ci	},
227962306a36Sopenharmony_ci	{	"PowerBook5,4",			"PowerBook G4 15\"",
228062306a36Sopenharmony_ci		PMAC_TYPE_UNKNOWN_INTREPID,	intrepid_features,
228162306a36Sopenharmony_ci		PMAC_MB_MAY_SLEEP | PMAC_MB_HAS_FW_POWER | PMAC_MB_MOBILE,
228262306a36Sopenharmony_ci	},
228362306a36Sopenharmony_ci	{	"PowerBook5,5",			"PowerBook G4 17\"",
228462306a36Sopenharmony_ci		PMAC_TYPE_UNKNOWN_INTREPID,	intrepid_features,
228562306a36Sopenharmony_ci		PMAC_MB_MAY_SLEEP | PMAC_MB_HAS_FW_POWER | PMAC_MB_MOBILE,
228662306a36Sopenharmony_ci	},
228762306a36Sopenharmony_ci	{	"PowerBook5,6",			"PowerBook G4 15\"",
228862306a36Sopenharmony_ci		PMAC_TYPE_UNKNOWN_INTREPID,	intrepid_features,
228962306a36Sopenharmony_ci		PMAC_MB_MAY_SLEEP | PMAC_MB_HAS_FW_POWER | PMAC_MB_MOBILE,
229062306a36Sopenharmony_ci	},
229162306a36Sopenharmony_ci	{	"PowerBook5,7",			"PowerBook G4 17\"",
229262306a36Sopenharmony_ci		PMAC_TYPE_UNKNOWN_INTREPID,	intrepid_features,
229362306a36Sopenharmony_ci		PMAC_MB_MAY_SLEEP | PMAC_MB_HAS_FW_POWER | PMAC_MB_MOBILE,
229462306a36Sopenharmony_ci	},
229562306a36Sopenharmony_ci	{	"PowerBook5,8",			"PowerBook G4 15\"",
229662306a36Sopenharmony_ci		PMAC_TYPE_UNKNOWN_INTREPID,	intrepid_features,
229762306a36Sopenharmony_ci		PMAC_MB_MAY_SLEEP  | PMAC_MB_MOBILE,
229862306a36Sopenharmony_ci	},
229962306a36Sopenharmony_ci	{	"PowerBook5,9",			"PowerBook G4 17\"",
230062306a36Sopenharmony_ci		PMAC_TYPE_UNKNOWN_INTREPID,	intrepid_features,
230162306a36Sopenharmony_ci		PMAC_MB_MAY_SLEEP | PMAC_MB_MOBILE,
230262306a36Sopenharmony_ci	},
230362306a36Sopenharmony_ci	{	"PowerBook6,1",			"PowerBook G4 12\"",
230462306a36Sopenharmony_ci		PMAC_TYPE_UNKNOWN_INTREPID,	intrepid_features,
230562306a36Sopenharmony_ci		PMAC_MB_MAY_SLEEP | PMAC_MB_HAS_FW_POWER | PMAC_MB_MOBILE,
230662306a36Sopenharmony_ci	},
230762306a36Sopenharmony_ci	{	"PowerBook6,2",			"PowerBook G4",
230862306a36Sopenharmony_ci		PMAC_TYPE_UNKNOWN_INTREPID,	intrepid_features,
230962306a36Sopenharmony_ci		PMAC_MB_MAY_SLEEP | PMAC_MB_HAS_FW_POWER | PMAC_MB_MOBILE,
231062306a36Sopenharmony_ci	},
231162306a36Sopenharmony_ci	{	"PowerBook6,3",			"iBook G4",
231262306a36Sopenharmony_ci		PMAC_TYPE_UNKNOWN_INTREPID,	intrepid_features,
231362306a36Sopenharmony_ci		PMAC_MB_MAY_SLEEP | PMAC_MB_HAS_FW_POWER | PMAC_MB_MOBILE,
231462306a36Sopenharmony_ci	},
231562306a36Sopenharmony_ci	{	"PowerBook6,4",			"PowerBook G4 12\"",
231662306a36Sopenharmony_ci		PMAC_TYPE_UNKNOWN_INTREPID,	intrepid_features,
231762306a36Sopenharmony_ci		PMAC_MB_MAY_SLEEP | PMAC_MB_HAS_FW_POWER | PMAC_MB_MOBILE,
231862306a36Sopenharmony_ci	},
231962306a36Sopenharmony_ci	{	"PowerBook6,5",			"iBook G4",
232062306a36Sopenharmony_ci		PMAC_TYPE_UNKNOWN_INTREPID,	intrepid_features,
232162306a36Sopenharmony_ci		PMAC_MB_MAY_SLEEP | PMAC_MB_HAS_FW_POWER | PMAC_MB_MOBILE,
232262306a36Sopenharmony_ci	},
232362306a36Sopenharmony_ci	{	"PowerBook6,7",			"iBook G4",
232462306a36Sopenharmony_ci		PMAC_TYPE_UNKNOWN_INTREPID,	intrepid_features,
232562306a36Sopenharmony_ci		PMAC_MB_MAY_SLEEP | PMAC_MB_HAS_FW_POWER | PMAC_MB_MOBILE,
232662306a36Sopenharmony_ci	},
232762306a36Sopenharmony_ci	{	"PowerBook6,8",			"PowerBook G4 12\"",
232862306a36Sopenharmony_ci		PMAC_TYPE_UNKNOWN_INTREPID,	intrepid_features,
232962306a36Sopenharmony_ci		PMAC_MB_MAY_SLEEP | PMAC_MB_HAS_FW_POWER | PMAC_MB_MOBILE,
233062306a36Sopenharmony_ci	},
233162306a36Sopenharmony_ci#else /* CONFIG_PPC64 */
233262306a36Sopenharmony_ci	{	"PowerMac7,2",			"PowerMac G5",
233362306a36Sopenharmony_ci		PMAC_TYPE_POWERMAC_G5,		g5_features,
233462306a36Sopenharmony_ci		0,
233562306a36Sopenharmony_ci	},
233662306a36Sopenharmony_ci#ifdef CONFIG_PPC64
233762306a36Sopenharmony_ci	{	"PowerMac7,3",			"PowerMac G5",
233862306a36Sopenharmony_ci		PMAC_TYPE_POWERMAC_G5,		g5_features,
233962306a36Sopenharmony_ci		0,
234062306a36Sopenharmony_ci	},
234162306a36Sopenharmony_ci	{	"PowerMac8,1",			"iMac G5",
234262306a36Sopenharmony_ci		PMAC_TYPE_IMAC_G5,		g5_features,
234362306a36Sopenharmony_ci		0,
234462306a36Sopenharmony_ci	},
234562306a36Sopenharmony_ci	{	"PowerMac9,1",			"PowerMac G5",
234662306a36Sopenharmony_ci		PMAC_TYPE_POWERMAC_G5_U3L,	g5_features,
234762306a36Sopenharmony_ci		0,
234862306a36Sopenharmony_ci	},
234962306a36Sopenharmony_ci	{	"PowerMac11,2",			"PowerMac G5 Dual Core",
235062306a36Sopenharmony_ci		PMAC_TYPE_POWERMAC_G5_U3L,	g5_features,
235162306a36Sopenharmony_ci		0,
235262306a36Sopenharmony_ci	},
235362306a36Sopenharmony_ci	{	"PowerMac12,1",			"iMac G5 (iSight)",
235462306a36Sopenharmony_ci		PMAC_TYPE_POWERMAC_G5_U3L,	g5_features,
235562306a36Sopenharmony_ci		0,
235662306a36Sopenharmony_ci	},
235762306a36Sopenharmony_ci	{       "RackMac3,1",                   "XServe G5",
235862306a36Sopenharmony_ci		PMAC_TYPE_XSERVE_G5,		g5_features,
235962306a36Sopenharmony_ci		0,
236062306a36Sopenharmony_ci	},
236162306a36Sopenharmony_ci#endif /* CONFIG_PPC64 */
236262306a36Sopenharmony_ci#endif /* CONFIG_PPC64 */
236362306a36Sopenharmony_ci};
236462306a36Sopenharmony_ci
236562306a36Sopenharmony_ci/*
236662306a36Sopenharmony_ci * The toplevel feature_call callback
236762306a36Sopenharmony_ci */
236862306a36Sopenharmony_cilong pmac_do_feature_call(unsigned int selector, ...)
236962306a36Sopenharmony_ci{
237062306a36Sopenharmony_ci	struct device_node *node;
237162306a36Sopenharmony_ci	long param, value;
237262306a36Sopenharmony_ci	int i;
237362306a36Sopenharmony_ci	feature_call func = NULL;
237462306a36Sopenharmony_ci	va_list args;
237562306a36Sopenharmony_ci
237662306a36Sopenharmony_ci	if (pmac_mb.features)
237762306a36Sopenharmony_ci		for (i=0; pmac_mb.features[i].function; i++)
237862306a36Sopenharmony_ci			if (pmac_mb.features[i].selector == selector) {
237962306a36Sopenharmony_ci				func = pmac_mb.features[i].function;
238062306a36Sopenharmony_ci				break;
238162306a36Sopenharmony_ci			}
238262306a36Sopenharmony_ci	if (!func)
238362306a36Sopenharmony_ci		for (i=0; any_features[i].function; i++)
238462306a36Sopenharmony_ci			if (any_features[i].selector == selector) {
238562306a36Sopenharmony_ci				func = any_features[i].function;
238662306a36Sopenharmony_ci				break;
238762306a36Sopenharmony_ci			}
238862306a36Sopenharmony_ci	if (!func)
238962306a36Sopenharmony_ci		return -ENODEV;
239062306a36Sopenharmony_ci
239162306a36Sopenharmony_ci	va_start(args, selector);
239262306a36Sopenharmony_ci	node = (struct device_node*)va_arg(args, void*);
239362306a36Sopenharmony_ci	param = va_arg(args, long);
239462306a36Sopenharmony_ci	value = va_arg(args, long);
239562306a36Sopenharmony_ci	va_end(args);
239662306a36Sopenharmony_ci
239762306a36Sopenharmony_ci	return func(node, param, value);
239862306a36Sopenharmony_ci}
239962306a36Sopenharmony_ci
240062306a36Sopenharmony_cistatic int __init probe_motherboard(void)
240162306a36Sopenharmony_ci{
240262306a36Sopenharmony_ci	int i;
240362306a36Sopenharmony_ci	struct macio_chip *macio = &macio_chips[0];
240462306a36Sopenharmony_ci	const char *model = NULL;
240562306a36Sopenharmony_ci	struct device_node *dt;
240662306a36Sopenharmony_ci	int ret = 0;
240762306a36Sopenharmony_ci
240862306a36Sopenharmony_ci	/* Lookup known motherboard type in device-tree. First try an
240962306a36Sopenharmony_ci	 * exact match on the "model" property, then try a "compatible"
241062306a36Sopenharmony_ci	 * match is none is found.
241162306a36Sopenharmony_ci	 */
241262306a36Sopenharmony_ci	dt = of_find_node_by_name(NULL, "device-tree");
241362306a36Sopenharmony_ci	if (dt != NULL)
241462306a36Sopenharmony_ci		model = of_get_property(dt, "model", NULL);
241562306a36Sopenharmony_ci	for(i=0; model && i<ARRAY_SIZE(pmac_mb_defs); i++) {
241662306a36Sopenharmony_ci	    if (strcmp(model, pmac_mb_defs[i].model_string) == 0) {
241762306a36Sopenharmony_ci		pmac_mb = pmac_mb_defs[i];
241862306a36Sopenharmony_ci		goto found;
241962306a36Sopenharmony_ci	    }
242062306a36Sopenharmony_ci	}
242162306a36Sopenharmony_ci	for(i=0; i<ARRAY_SIZE(pmac_mb_defs); i++) {
242262306a36Sopenharmony_ci	    if (of_machine_is_compatible(pmac_mb_defs[i].model_string)) {
242362306a36Sopenharmony_ci		pmac_mb = pmac_mb_defs[i];
242462306a36Sopenharmony_ci		goto found;
242562306a36Sopenharmony_ci	    }
242662306a36Sopenharmony_ci	}
242762306a36Sopenharmony_ci
242862306a36Sopenharmony_ci	/* Fallback to selection depending on mac-io chip type */
242962306a36Sopenharmony_ci	switch(macio->type) {
243062306a36Sopenharmony_ci#ifndef CONFIG_PPC64
243162306a36Sopenharmony_ci	    case macio_grand_central:
243262306a36Sopenharmony_ci		pmac_mb.model_id = PMAC_TYPE_PSURGE;
243362306a36Sopenharmony_ci		pmac_mb.model_name = "Unknown PowerSurge";
243462306a36Sopenharmony_ci		break;
243562306a36Sopenharmony_ci	    case macio_ohare:
243662306a36Sopenharmony_ci		pmac_mb.model_id = PMAC_TYPE_UNKNOWN_OHARE;
243762306a36Sopenharmony_ci		pmac_mb.model_name = "Unknown OHare-based";
243862306a36Sopenharmony_ci		break;
243962306a36Sopenharmony_ci	    case macio_heathrow:
244062306a36Sopenharmony_ci		pmac_mb.model_id = PMAC_TYPE_UNKNOWN_HEATHROW;
244162306a36Sopenharmony_ci		pmac_mb.model_name = "Unknown Heathrow-based";
244262306a36Sopenharmony_ci		pmac_mb.features = heathrow_desktop_features;
244362306a36Sopenharmony_ci		break;
244462306a36Sopenharmony_ci	    case macio_paddington:
244562306a36Sopenharmony_ci		pmac_mb.model_id = PMAC_TYPE_UNKNOWN_PADDINGTON;
244662306a36Sopenharmony_ci		pmac_mb.model_name = "Unknown Paddington-based";
244762306a36Sopenharmony_ci		pmac_mb.features = paddington_features;
244862306a36Sopenharmony_ci		break;
244962306a36Sopenharmony_ci	    case macio_keylargo:
245062306a36Sopenharmony_ci		pmac_mb.model_id = PMAC_TYPE_UNKNOWN_CORE99;
245162306a36Sopenharmony_ci		pmac_mb.model_name = "Unknown Keylargo-based";
245262306a36Sopenharmony_ci		pmac_mb.features = core99_features;
245362306a36Sopenharmony_ci		break;
245462306a36Sopenharmony_ci	    case macio_pangea:
245562306a36Sopenharmony_ci		pmac_mb.model_id = PMAC_TYPE_UNKNOWN_PANGEA;
245662306a36Sopenharmony_ci		pmac_mb.model_name = "Unknown Pangea-based";
245762306a36Sopenharmony_ci		pmac_mb.features = pangea_features;
245862306a36Sopenharmony_ci		break;
245962306a36Sopenharmony_ci	    case macio_intrepid:
246062306a36Sopenharmony_ci		pmac_mb.model_id = PMAC_TYPE_UNKNOWN_INTREPID;
246162306a36Sopenharmony_ci		pmac_mb.model_name = "Unknown Intrepid-based";
246262306a36Sopenharmony_ci		pmac_mb.features = intrepid_features;
246362306a36Sopenharmony_ci		break;
246462306a36Sopenharmony_ci#else /* CONFIG_PPC64 */
246562306a36Sopenharmony_ci	case macio_keylargo2:
246662306a36Sopenharmony_ci		pmac_mb.model_id = PMAC_TYPE_UNKNOWN_K2;
246762306a36Sopenharmony_ci		pmac_mb.model_name = "Unknown K2-based";
246862306a36Sopenharmony_ci		pmac_mb.features = g5_features;
246962306a36Sopenharmony_ci		break;
247062306a36Sopenharmony_ci	case macio_shasta:
247162306a36Sopenharmony_ci		pmac_mb.model_id = PMAC_TYPE_UNKNOWN_SHASTA;
247262306a36Sopenharmony_ci		pmac_mb.model_name = "Unknown Shasta-based";
247362306a36Sopenharmony_ci		pmac_mb.features = g5_features;
247462306a36Sopenharmony_ci		break;
247562306a36Sopenharmony_ci#endif /* CONFIG_PPC64 */
247662306a36Sopenharmony_ci	default:
247762306a36Sopenharmony_ci		ret = -ENODEV;
247862306a36Sopenharmony_ci		goto done;
247962306a36Sopenharmony_ci	}
248062306a36Sopenharmony_cifound:
248162306a36Sopenharmony_ci#ifndef CONFIG_PPC64
248262306a36Sopenharmony_ci	/* Fixup Hooper vs. Comet */
248362306a36Sopenharmony_ci	if (pmac_mb.model_id == PMAC_TYPE_HOOPER) {
248462306a36Sopenharmony_ci		u32 __iomem * mach_id_ptr = ioremap(0xf3000034, 4);
248562306a36Sopenharmony_ci		if (!mach_id_ptr) {
248662306a36Sopenharmony_ci			ret = -ENODEV;
248762306a36Sopenharmony_ci			goto done;
248862306a36Sopenharmony_ci		}
248962306a36Sopenharmony_ci		/* Here, I used to disable the media-bay on comet. It
249062306a36Sopenharmony_ci		 * appears this is wrong, the floppy connector is actually
249162306a36Sopenharmony_ci		 * a kind of media-bay and works with the current driver.
249262306a36Sopenharmony_ci		 */
249362306a36Sopenharmony_ci		if (__raw_readl(mach_id_ptr) & 0x20000000UL)
249462306a36Sopenharmony_ci			pmac_mb.model_id = PMAC_TYPE_COMET;
249562306a36Sopenharmony_ci		iounmap(mach_id_ptr);
249662306a36Sopenharmony_ci	}
249762306a36Sopenharmony_ci
249862306a36Sopenharmony_ci	/* Set default value of powersave_nap on machines that support it.
249962306a36Sopenharmony_ci	 * It appears that uninorth rev 3 has a problem with it, we don't
250062306a36Sopenharmony_ci	 * enable it on those. In theory, the flush-on-lock property is
250162306a36Sopenharmony_ci	 * supposed to be set when not supported, but I'm not very confident
250262306a36Sopenharmony_ci	 * that all Apple OF revs did it properly, I do it the paranoid way.
250362306a36Sopenharmony_ci	 */
250462306a36Sopenharmony_ci	if (uninorth_base && uninorth_rev > 3) {
250562306a36Sopenharmony_ci		struct device_node *np;
250662306a36Sopenharmony_ci
250762306a36Sopenharmony_ci		for_each_of_cpu_node(np) {
250862306a36Sopenharmony_ci			int cpu_count = 1;
250962306a36Sopenharmony_ci
251062306a36Sopenharmony_ci			/* Nap mode not supported on SMP */
251162306a36Sopenharmony_ci			if (of_property_read_bool(np, "flush-on-lock") ||
251262306a36Sopenharmony_ci			    (cpu_count > 1)) {
251362306a36Sopenharmony_ci				powersave_nap = 0;
251462306a36Sopenharmony_ci				of_node_put(np);
251562306a36Sopenharmony_ci				break;
251662306a36Sopenharmony_ci			}
251762306a36Sopenharmony_ci
251862306a36Sopenharmony_ci			cpu_count++;
251962306a36Sopenharmony_ci			powersave_nap = 1;
252062306a36Sopenharmony_ci		}
252162306a36Sopenharmony_ci	}
252262306a36Sopenharmony_ci	if (powersave_nap)
252362306a36Sopenharmony_ci		printk(KERN_DEBUG "Processor NAP mode on idle enabled.\n");
252462306a36Sopenharmony_ci
252562306a36Sopenharmony_ci	/* On CPUs that support it (750FX), lowspeed by default during
252662306a36Sopenharmony_ci	 * NAP mode
252762306a36Sopenharmony_ci	 */
252862306a36Sopenharmony_ci	powersave_lowspeed = 1;
252962306a36Sopenharmony_ci
253062306a36Sopenharmony_ci#else /* CONFIG_PPC64 */
253162306a36Sopenharmony_ci	powersave_nap = 1;
253262306a36Sopenharmony_ci#endif  /* CONFIG_PPC64 */
253362306a36Sopenharmony_ci
253462306a36Sopenharmony_ci	/* Check for "mobile" machine */
253562306a36Sopenharmony_ci	if (model && (strncmp(model, "PowerBook", 9) == 0
253662306a36Sopenharmony_ci		   || strncmp(model, "iBook", 5) == 0))
253762306a36Sopenharmony_ci		pmac_mb.board_flags |= PMAC_MB_MOBILE;
253862306a36Sopenharmony_ci
253962306a36Sopenharmony_ci
254062306a36Sopenharmony_ci	printk(KERN_INFO "PowerMac motherboard: %s\n", pmac_mb.model_name);
254162306a36Sopenharmony_cidone:
254262306a36Sopenharmony_ci	of_node_put(dt);
254362306a36Sopenharmony_ci	return ret;
254462306a36Sopenharmony_ci}
254562306a36Sopenharmony_ci
254662306a36Sopenharmony_ci/* Initialize the Core99 UniNorth host bridge and memory controller
254762306a36Sopenharmony_ci */
254862306a36Sopenharmony_cistatic void __init probe_uninorth(void)
254962306a36Sopenharmony_ci{
255062306a36Sopenharmony_ci	struct resource res;
255162306a36Sopenharmony_ci	unsigned long actrl;
255262306a36Sopenharmony_ci
255362306a36Sopenharmony_ci	/* Locate core99 Uni-N */
255462306a36Sopenharmony_ci	uninorth_node = of_find_node_by_name(NULL, "uni-n");
255562306a36Sopenharmony_ci	uninorth_maj = 1;
255662306a36Sopenharmony_ci
255762306a36Sopenharmony_ci	/* Locate G5 u3 */
255862306a36Sopenharmony_ci	if (uninorth_node == NULL) {
255962306a36Sopenharmony_ci		uninorth_node = of_find_node_by_name(NULL, "u3");
256062306a36Sopenharmony_ci		uninorth_maj = 3;
256162306a36Sopenharmony_ci	}
256262306a36Sopenharmony_ci	/* Locate G5 u4 */
256362306a36Sopenharmony_ci	if (uninorth_node == NULL) {
256462306a36Sopenharmony_ci		uninorth_node = of_find_node_by_name(NULL, "u4");
256562306a36Sopenharmony_ci		uninorth_maj = 4;
256662306a36Sopenharmony_ci	}
256762306a36Sopenharmony_ci	if (uninorth_node == NULL) {
256862306a36Sopenharmony_ci		uninorth_maj = 0;
256962306a36Sopenharmony_ci		return;
257062306a36Sopenharmony_ci	}
257162306a36Sopenharmony_ci
257262306a36Sopenharmony_ci	if (of_address_to_resource(uninorth_node, 0, &res))
257362306a36Sopenharmony_ci		return;
257462306a36Sopenharmony_ci
257562306a36Sopenharmony_ci	uninorth_base = ioremap(res.start, 0x40000);
257662306a36Sopenharmony_ci	if (uninorth_base == NULL)
257762306a36Sopenharmony_ci		return;
257862306a36Sopenharmony_ci	uninorth_rev = in_be32(UN_REG(UNI_N_VERSION));
257962306a36Sopenharmony_ci	if (uninorth_maj == 3 || uninorth_maj == 4) {
258062306a36Sopenharmony_ci		u3_ht_base = ioremap(res.start + U3_HT_CONFIG_BASE, 0x1000);
258162306a36Sopenharmony_ci		if (u3_ht_base == NULL) {
258262306a36Sopenharmony_ci			iounmap(uninorth_base);
258362306a36Sopenharmony_ci			return;
258462306a36Sopenharmony_ci		}
258562306a36Sopenharmony_ci	}
258662306a36Sopenharmony_ci
258762306a36Sopenharmony_ci	printk(KERN_INFO "Found %s memory controller & host bridge"
258862306a36Sopenharmony_ci	       " @ 0x%08x revision: 0x%02x\n", uninorth_maj == 3 ? "U3" :
258962306a36Sopenharmony_ci	       uninorth_maj == 4 ? "U4" : "UniNorth",
259062306a36Sopenharmony_ci	       (unsigned int)res.start, uninorth_rev);
259162306a36Sopenharmony_ci	printk(KERN_INFO "Mapped at 0x%08lx\n", (unsigned long)uninorth_base);
259262306a36Sopenharmony_ci
259362306a36Sopenharmony_ci	/* Set the arbitrer QAck delay according to what Apple does
259462306a36Sopenharmony_ci	 */
259562306a36Sopenharmony_ci	if (uninorth_rev < 0x11) {
259662306a36Sopenharmony_ci		actrl = UN_IN(UNI_N_ARB_CTRL) & ~UNI_N_ARB_CTRL_QACK_DELAY_MASK;
259762306a36Sopenharmony_ci		actrl |= ((uninorth_rev < 3) ? UNI_N_ARB_CTRL_QACK_DELAY105 :
259862306a36Sopenharmony_ci			UNI_N_ARB_CTRL_QACK_DELAY) <<
259962306a36Sopenharmony_ci			UNI_N_ARB_CTRL_QACK_DELAY_SHIFT;
260062306a36Sopenharmony_ci		UN_OUT(UNI_N_ARB_CTRL, actrl);
260162306a36Sopenharmony_ci	}
260262306a36Sopenharmony_ci
260362306a36Sopenharmony_ci	/* Some more magic as done by them in recent MacOS X on UniNorth
260462306a36Sopenharmony_ci	 * revs 1.5 to 2.O and Pangea. Seem to toggle the UniN Maxbus/PCI
260562306a36Sopenharmony_ci	 * memory timeout
260662306a36Sopenharmony_ci	 */
260762306a36Sopenharmony_ci	if ((uninorth_rev >= 0x11 && uninorth_rev <= 0x24) ||
260862306a36Sopenharmony_ci	    uninorth_rev == 0xc0)
260962306a36Sopenharmony_ci		UN_OUT(0x2160, UN_IN(0x2160) & 0x00ffffff);
261062306a36Sopenharmony_ci}
261162306a36Sopenharmony_ci
261262306a36Sopenharmony_cistatic void __init probe_one_macio(const char *name, const char *compat, int type)
261362306a36Sopenharmony_ci{
261462306a36Sopenharmony_ci	struct device_node*	node;
261562306a36Sopenharmony_ci	int			i;
261662306a36Sopenharmony_ci	volatile u32 __iomem	*base;
261762306a36Sopenharmony_ci	const u32		*addrp, *revp;
261862306a36Sopenharmony_ci	phys_addr_t		addr;
261962306a36Sopenharmony_ci	u64			size;
262062306a36Sopenharmony_ci
262162306a36Sopenharmony_ci	for_each_node_by_name(node, name) {
262262306a36Sopenharmony_ci		if (!compat)
262362306a36Sopenharmony_ci			break;
262462306a36Sopenharmony_ci		if (of_device_is_compatible(node, compat))
262562306a36Sopenharmony_ci			break;
262662306a36Sopenharmony_ci	}
262762306a36Sopenharmony_ci	if (!node)
262862306a36Sopenharmony_ci		return;
262962306a36Sopenharmony_ci	for(i=0; i<MAX_MACIO_CHIPS; i++) {
263062306a36Sopenharmony_ci		if (!macio_chips[i].of_node)
263162306a36Sopenharmony_ci			break;
263262306a36Sopenharmony_ci		if (macio_chips[i].of_node == node)
263362306a36Sopenharmony_ci			goto out_put;
263462306a36Sopenharmony_ci	}
263562306a36Sopenharmony_ci
263662306a36Sopenharmony_ci	if (i >= MAX_MACIO_CHIPS) {
263762306a36Sopenharmony_ci		printk(KERN_ERR "pmac_feature: Please increase MAX_MACIO_CHIPS !\n");
263862306a36Sopenharmony_ci		printk(KERN_ERR "pmac_feature: %pOF skipped\n", node);
263962306a36Sopenharmony_ci		goto out_put;
264062306a36Sopenharmony_ci	}
264162306a36Sopenharmony_ci	addrp = of_get_pci_address(node, 0, &size, NULL);
264262306a36Sopenharmony_ci	if (addrp == NULL) {
264362306a36Sopenharmony_ci		printk(KERN_ERR "pmac_feature: %pOF: can't find base !\n",
264462306a36Sopenharmony_ci		       node);
264562306a36Sopenharmony_ci		goto out_put;
264662306a36Sopenharmony_ci	}
264762306a36Sopenharmony_ci	addr = of_translate_address(node, addrp);
264862306a36Sopenharmony_ci	if (addr == 0) {
264962306a36Sopenharmony_ci		printk(KERN_ERR "pmac_feature: %pOF, can't translate base !\n",
265062306a36Sopenharmony_ci		       node);
265162306a36Sopenharmony_ci		goto out_put;
265262306a36Sopenharmony_ci	}
265362306a36Sopenharmony_ci	base = ioremap(addr, (unsigned long)size);
265462306a36Sopenharmony_ci	if (!base) {
265562306a36Sopenharmony_ci		printk(KERN_ERR "pmac_feature: %pOF, can't map mac-io chip !\n",
265662306a36Sopenharmony_ci		       node);
265762306a36Sopenharmony_ci		goto out_put;
265862306a36Sopenharmony_ci	}
265962306a36Sopenharmony_ci	if (type == macio_keylargo || type == macio_keylargo2) {
266062306a36Sopenharmony_ci		const u32 *did = of_get_property(node, "device-id", NULL);
266162306a36Sopenharmony_ci		if (*did == 0x00000025)
266262306a36Sopenharmony_ci			type = macio_pangea;
266362306a36Sopenharmony_ci		if (*did == 0x0000003e)
266462306a36Sopenharmony_ci			type = macio_intrepid;
266562306a36Sopenharmony_ci		if (*did == 0x0000004f)
266662306a36Sopenharmony_ci			type = macio_shasta;
266762306a36Sopenharmony_ci	}
266862306a36Sopenharmony_ci	macio_chips[i].of_node	= node;
266962306a36Sopenharmony_ci	macio_chips[i].type	= type;
267062306a36Sopenharmony_ci	macio_chips[i].base	= base;
267162306a36Sopenharmony_ci	macio_chips[i].flags	= MACIO_FLAG_SCCA_ON | MACIO_FLAG_SCCB_ON;
267262306a36Sopenharmony_ci	macio_chips[i].name	= macio_names[type];
267362306a36Sopenharmony_ci	revp = of_get_property(node, "revision-id", NULL);
267462306a36Sopenharmony_ci	if (revp)
267562306a36Sopenharmony_ci		macio_chips[i].rev = *revp;
267662306a36Sopenharmony_ci	printk(KERN_INFO "Found a %s mac-io controller, rev: %d, mapped at 0x%p\n",
267762306a36Sopenharmony_ci		macio_names[type], macio_chips[i].rev, macio_chips[i].base);
267862306a36Sopenharmony_ci
267962306a36Sopenharmony_ci	return;
268062306a36Sopenharmony_ci
268162306a36Sopenharmony_ciout_put:
268262306a36Sopenharmony_ci	of_node_put(node);
268362306a36Sopenharmony_ci}
268462306a36Sopenharmony_ci
268562306a36Sopenharmony_cistatic int __init
268662306a36Sopenharmony_ciprobe_macios(void)
268762306a36Sopenharmony_ci{
268862306a36Sopenharmony_ci	/* Warning, ordering is important */
268962306a36Sopenharmony_ci	probe_one_macio("gc", NULL, macio_grand_central);
269062306a36Sopenharmony_ci	probe_one_macio("ohare", NULL, macio_ohare);
269162306a36Sopenharmony_ci	probe_one_macio("pci106b,7", NULL, macio_ohareII);
269262306a36Sopenharmony_ci	probe_one_macio("mac-io", "keylargo", macio_keylargo);
269362306a36Sopenharmony_ci	probe_one_macio("mac-io", "paddington", macio_paddington);
269462306a36Sopenharmony_ci	probe_one_macio("mac-io", "gatwick", macio_gatwick);
269562306a36Sopenharmony_ci	probe_one_macio("mac-io", "heathrow", macio_heathrow);
269662306a36Sopenharmony_ci	probe_one_macio("mac-io", "K2-Keylargo", macio_keylargo2);
269762306a36Sopenharmony_ci
269862306a36Sopenharmony_ci	/* Make sure the "main" macio chip appear first */
269962306a36Sopenharmony_ci	if (macio_chips[0].type == macio_gatwick
270062306a36Sopenharmony_ci	    && macio_chips[1].type == macio_heathrow) {
270162306a36Sopenharmony_ci		struct macio_chip temp = macio_chips[0];
270262306a36Sopenharmony_ci		macio_chips[0] = macio_chips[1];
270362306a36Sopenharmony_ci		macio_chips[1] = temp;
270462306a36Sopenharmony_ci	}
270562306a36Sopenharmony_ci	if (macio_chips[0].type == macio_ohareII
270662306a36Sopenharmony_ci	    && macio_chips[1].type == macio_ohare) {
270762306a36Sopenharmony_ci		struct macio_chip temp = macio_chips[0];
270862306a36Sopenharmony_ci		macio_chips[0] = macio_chips[1];
270962306a36Sopenharmony_ci		macio_chips[1] = temp;
271062306a36Sopenharmony_ci	}
271162306a36Sopenharmony_ci	macio_chips[0].lbus.index = 0;
271262306a36Sopenharmony_ci	macio_chips[1].lbus.index = 1;
271362306a36Sopenharmony_ci
271462306a36Sopenharmony_ci	return (macio_chips[0].of_node == NULL) ? -ENODEV : 0;
271562306a36Sopenharmony_ci}
271662306a36Sopenharmony_ci
271762306a36Sopenharmony_cistatic void __init
271862306a36Sopenharmony_ciinitial_serial_shutdown(struct device_node *np)
271962306a36Sopenharmony_ci{
272062306a36Sopenharmony_ci	int len;
272162306a36Sopenharmony_ci	const struct slot_names_prop {
272262306a36Sopenharmony_ci		int	count;
272362306a36Sopenharmony_ci		char	name[1];
272462306a36Sopenharmony_ci	} *slots;
272562306a36Sopenharmony_ci	const char *conn;
272662306a36Sopenharmony_ci	int port_type = PMAC_SCC_ASYNC;
272762306a36Sopenharmony_ci	int modem = 0;
272862306a36Sopenharmony_ci
272962306a36Sopenharmony_ci	slots = of_get_property(np, "slot-names", &len);
273062306a36Sopenharmony_ci	conn = of_get_property(np, "AAPL,connector", &len);
273162306a36Sopenharmony_ci	if (conn && (strcmp(conn, "infrared") == 0))
273262306a36Sopenharmony_ci		port_type = PMAC_SCC_IRDA;
273362306a36Sopenharmony_ci	else if (of_device_is_compatible(np, "cobalt"))
273462306a36Sopenharmony_ci		modem = 1;
273562306a36Sopenharmony_ci	else if (slots && slots->count > 0) {
273662306a36Sopenharmony_ci		if (strcmp(slots->name, "IrDA") == 0)
273762306a36Sopenharmony_ci			port_type = PMAC_SCC_IRDA;
273862306a36Sopenharmony_ci		else if (strcmp(slots->name, "Modem") == 0)
273962306a36Sopenharmony_ci			modem = 1;
274062306a36Sopenharmony_ci	}
274162306a36Sopenharmony_ci	if (modem)
274262306a36Sopenharmony_ci		pmac_call_feature(PMAC_FTR_MODEM_ENABLE, np, 0, 0);
274362306a36Sopenharmony_ci	pmac_call_feature(PMAC_FTR_SCC_ENABLE, np, port_type, 0);
274462306a36Sopenharmony_ci}
274562306a36Sopenharmony_ci
274662306a36Sopenharmony_cistatic void __init
274762306a36Sopenharmony_ciset_initial_features(void)
274862306a36Sopenharmony_ci{
274962306a36Sopenharmony_ci	struct device_node *np;
275062306a36Sopenharmony_ci
275162306a36Sopenharmony_ci	/* That hack appears to be necessary for some StarMax motherboards
275262306a36Sopenharmony_ci	 * but I'm not too sure it was audited for side-effects on other
275362306a36Sopenharmony_ci	 * ohare based machines...
275462306a36Sopenharmony_ci	 * Since I still have difficulties figuring the right way to
275562306a36Sopenharmony_ci	 * differentiate them all and since that hack was there for a long
275662306a36Sopenharmony_ci	 * time, I'll keep it around
275762306a36Sopenharmony_ci	 */
275862306a36Sopenharmony_ci	if (macio_chips[0].type == macio_ohare) {
275962306a36Sopenharmony_ci		struct macio_chip *macio = &macio_chips[0];
276062306a36Sopenharmony_ci		np = of_find_node_by_name(NULL, "via-pmu");
276162306a36Sopenharmony_ci		if (np)
276262306a36Sopenharmony_ci			MACIO_BIS(OHARE_FCR, OH_IOBUS_ENABLE);
276362306a36Sopenharmony_ci		else
276462306a36Sopenharmony_ci			MACIO_OUT32(OHARE_FCR, STARMAX_FEATURES);
276562306a36Sopenharmony_ci		of_node_put(np);
276662306a36Sopenharmony_ci	} else if (macio_chips[1].type == macio_ohare) {
276762306a36Sopenharmony_ci		struct macio_chip *macio = &macio_chips[1];
276862306a36Sopenharmony_ci		MACIO_BIS(OHARE_FCR, OH_IOBUS_ENABLE);
276962306a36Sopenharmony_ci	}
277062306a36Sopenharmony_ci
277162306a36Sopenharmony_ci#ifdef CONFIG_PPC64
277262306a36Sopenharmony_ci	if (macio_chips[0].type == macio_keylargo2 ||
277362306a36Sopenharmony_ci	    macio_chips[0].type == macio_shasta) {
277462306a36Sopenharmony_ci#ifndef CONFIG_SMP
277562306a36Sopenharmony_ci		/* On SMP machines running UP, we have the second CPU eating
277662306a36Sopenharmony_ci		 * bus cycles. We need to take it off the bus. This is done
277762306a36Sopenharmony_ci		 * from pmac_smp for SMP kernels running on one CPU
277862306a36Sopenharmony_ci		 */
277962306a36Sopenharmony_ci		np = of_find_node_by_type(NULL, "cpu");
278062306a36Sopenharmony_ci		if (np != NULL)
278162306a36Sopenharmony_ci			np = of_find_node_by_type(np, "cpu");
278262306a36Sopenharmony_ci		if (np != NULL) {
278362306a36Sopenharmony_ci			g5_phy_disable_cpu1();
278462306a36Sopenharmony_ci			of_node_put(np);
278562306a36Sopenharmony_ci		}
278662306a36Sopenharmony_ci#endif /* CONFIG_SMP */
278762306a36Sopenharmony_ci		/* Enable GMAC for now for PCI probing. It will be disabled
278862306a36Sopenharmony_ci		 * later on after PCI probe
278962306a36Sopenharmony_ci		 */
279062306a36Sopenharmony_ci		for_each_node_by_name(np, "ethernet")
279162306a36Sopenharmony_ci			if (of_device_is_compatible(np, "K2-GMAC"))
279262306a36Sopenharmony_ci				g5_gmac_enable(np, 0, 1);
279362306a36Sopenharmony_ci
279462306a36Sopenharmony_ci		/* Enable FW before PCI probe. Will be disabled later on
279562306a36Sopenharmony_ci		 * Note: We should have a batter way to check that we are
279662306a36Sopenharmony_ci		 * dealing with uninorth internal cell and not a PCI cell
279762306a36Sopenharmony_ci		 * on the external PCI. The code below works though.
279862306a36Sopenharmony_ci		 */
279962306a36Sopenharmony_ci		for_each_node_by_name(np, "firewire") {
280062306a36Sopenharmony_ci			if (of_device_is_compatible(np, "pci106b,5811")) {
280162306a36Sopenharmony_ci				macio_chips[0].flags |= MACIO_FLAG_FW_SUPPORTED;
280262306a36Sopenharmony_ci				g5_fw_enable(np, 0, 1);
280362306a36Sopenharmony_ci			}
280462306a36Sopenharmony_ci		}
280562306a36Sopenharmony_ci	}
280662306a36Sopenharmony_ci#else /* CONFIG_PPC64 */
280762306a36Sopenharmony_ci
280862306a36Sopenharmony_ci	if (macio_chips[0].type == macio_keylargo ||
280962306a36Sopenharmony_ci	    macio_chips[0].type == macio_pangea ||
281062306a36Sopenharmony_ci	    macio_chips[0].type == macio_intrepid) {
281162306a36Sopenharmony_ci		/* Enable GMAC for now for PCI probing. It will be disabled
281262306a36Sopenharmony_ci		 * later on after PCI probe
281362306a36Sopenharmony_ci		 */
281462306a36Sopenharmony_ci		for_each_node_by_name(np, "ethernet") {
281562306a36Sopenharmony_ci			if (np->parent
281662306a36Sopenharmony_ci			    && of_device_is_compatible(np->parent, "uni-north")
281762306a36Sopenharmony_ci			    && of_device_is_compatible(np, "gmac"))
281862306a36Sopenharmony_ci				core99_gmac_enable(np, 0, 1);
281962306a36Sopenharmony_ci		}
282062306a36Sopenharmony_ci
282162306a36Sopenharmony_ci		/* Enable FW before PCI probe. Will be disabled later on
282262306a36Sopenharmony_ci		 * Note: We should have a batter way to check that we are
282362306a36Sopenharmony_ci		 * dealing with uninorth internal cell and not a PCI cell
282462306a36Sopenharmony_ci		 * on the external PCI. The code below works though.
282562306a36Sopenharmony_ci		 */
282662306a36Sopenharmony_ci		for_each_node_by_name(np, "firewire") {
282762306a36Sopenharmony_ci			if (np->parent
282862306a36Sopenharmony_ci			    && of_device_is_compatible(np->parent, "uni-north")
282962306a36Sopenharmony_ci			    && (of_device_is_compatible(np, "pci106b,18") ||
283062306a36Sopenharmony_ci			        of_device_is_compatible(np, "pci106b,30") ||
283162306a36Sopenharmony_ci			        of_device_is_compatible(np, "pci11c1,5811"))) {
283262306a36Sopenharmony_ci				macio_chips[0].flags |= MACIO_FLAG_FW_SUPPORTED;
283362306a36Sopenharmony_ci				core99_firewire_enable(np, 0, 1);
283462306a36Sopenharmony_ci			}
283562306a36Sopenharmony_ci		}
283662306a36Sopenharmony_ci
283762306a36Sopenharmony_ci		/* Enable ATA-100 before PCI probe. */
283862306a36Sopenharmony_ci		for_each_node_by_name(np, "ata-6") {
283962306a36Sopenharmony_ci			if (np->parent
284062306a36Sopenharmony_ci			    && of_device_is_compatible(np->parent, "uni-north")
284162306a36Sopenharmony_ci			    && of_device_is_compatible(np, "kauai-ata")) {
284262306a36Sopenharmony_ci				core99_ata100_enable(np, 1);
284362306a36Sopenharmony_ci			}
284462306a36Sopenharmony_ci		}
284562306a36Sopenharmony_ci
284662306a36Sopenharmony_ci		/* Switch airport off */
284762306a36Sopenharmony_ci		for_each_node_by_name(np, "radio") {
284862306a36Sopenharmony_ci			if (np->parent == macio_chips[0].of_node) {
284962306a36Sopenharmony_ci				macio_chips[0].flags |= MACIO_FLAG_AIRPORT_ON;
285062306a36Sopenharmony_ci				core99_airport_enable(np, 0, 0);
285162306a36Sopenharmony_ci			}
285262306a36Sopenharmony_ci		}
285362306a36Sopenharmony_ci	}
285462306a36Sopenharmony_ci
285562306a36Sopenharmony_ci	/* On all machines that support sound PM, switch sound off */
285662306a36Sopenharmony_ci	if (macio_chips[0].of_node)
285762306a36Sopenharmony_ci		pmac_do_feature_call(PMAC_FTR_SOUND_CHIP_ENABLE,
285862306a36Sopenharmony_ci			macio_chips[0].of_node, 0, 0);
285962306a36Sopenharmony_ci
286062306a36Sopenharmony_ci	/* While on some desktop G3s, we turn it back on */
286162306a36Sopenharmony_ci	if (macio_chips[0].of_node && macio_chips[0].type == macio_heathrow
286262306a36Sopenharmony_ci		&& (pmac_mb.model_id == PMAC_TYPE_GOSSAMER ||
286362306a36Sopenharmony_ci		    pmac_mb.model_id == PMAC_TYPE_SILK)) {
286462306a36Sopenharmony_ci		struct macio_chip *macio = &macio_chips[0];
286562306a36Sopenharmony_ci		MACIO_BIS(HEATHROW_FCR, HRW_SOUND_CLK_ENABLE);
286662306a36Sopenharmony_ci		MACIO_BIC(HEATHROW_FCR, HRW_SOUND_POWER_N);
286762306a36Sopenharmony_ci	}
286862306a36Sopenharmony_ci
286962306a36Sopenharmony_ci#endif /* CONFIG_PPC64 */
287062306a36Sopenharmony_ci
287162306a36Sopenharmony_ci	/* On all machines, switch modem & serial ports off */
287262306a36Sopenharmony_ci	for_each_node_by_name(np, "ch-a")
287362306a36Sopenharmony_ci		initial_serial_shutdown(np);
287462306a36Sopenharmony_ci	for_each_node_by_name(np, "ch-b")
287562306a36Sopenharmony_ci		initial_serial_shutdown(np);
287662306a36Sopenharmony_ci}
287762306a36Sopenharmony_ci
287862306a36Sopenharmony_civoid __init
287962306a36Sopenharmony_cipmac_feature_init(void)
288062306a36Sopenharmony_ci{
288162306a36Sopenharmony_ci	/* Detect the UniNorth memory controller */
288262306a36Sopenharmony_ci	probe_uninorth();
288362306a36Sopenharmony_ci
288462306a36Sopenharmony_ci	/* Probe mac-io controllers */
288562306a36Sopenharmony_ci	if (probe_macios()) {
288662306a36Sopenharmony_ci		printk(KERN_WARNING "No mac-io chip found\n");
288762306a36Sopenharmony_ci		return;
288862306a36Sopenharmony_ci	}
288962306a36Sopenharmony_ci
289062306a36Sopenharmony_ci	/* Probe machine type */
289162306a36Sopenharmony_ci	if (probe_motherboard())
289262306a36Sopenharmony_ci		printk(KERN_WARNING "Unknown PowerMac !\n");
289362306a36Sopenharmony_ci
289462306a36Sopenharmony_ci	/* Set some initial features (turn off some chips that will
289562306a36Sopenharmony_ci	 * be later turned on)
289662306a36Sopenharmony_ci	 */
289762306a36Sopenharmony_ci	set_initial_features();
289862306a36Sopenharmony_ci}
289962306a36Sopenharmony_ci
290062306a36Sopenharmony_ci#if 0
290162306a36Sopenharmony_cistatic void dump_HT_speeds(char *name, u32 cfg, u32 frq)
290262306a36Sopenharmony_ci{
290362306a36Sopenharmony_ci	int	freqs[16] = { 200,300,400,500,600,800,1000,0,0,0,0,0,0,0,0,0 };
290462306a36Sopenharmony_ci	int	bits[8] = { 8,16,0,32,2,4,0,0 };
290562306a36Sopenharmony_ci	int	freq = (frq >> 8) & 0xf;
290662306a36Sopenharmony_ci
290762306a36Sopenharmony_ci	if (freqs[freq] == 0)
290862306a36Sopenharmony_ci		printk("%s: Unknown HT link frequency %x\n", name, freq);
290962306a36Sopenharmony_ci	else
291062306a36Sopenharmony_ci		printk("%s: %d MHz on main link, (%d in / %d out) bits width\n",
291162306a36Sopenharmony_ci		       name, freqs[freq],
291262306a36Sopenharmony_ci		       bits[(cfg >> 28) & 0x7], bits[(cfg >> 24) & 0x7]);
291362306a36Sopenharmony_ci}
291462306a36Sopenharmony_ci
291562306a36Sopenharmony_civoid __init pmac_check_ht_link(void)
291662306a36Sopenharmony_ci{
291762306a36Sopenharmony_ci	u32	ufreq, freq, ucfg, cfg;
291862306a36Sopenharmony_ci	struct device_node *pcix_node;
291962306a36Sopenharmony_ci	u8	px_bus, px_devfn;
292062306a36Sopenharmony_ci	struct pci_controller *px_hose;
292162306a36Sopenharmony_ci
292262306a36Sopenharmony_ci	(void)in_be32(u3_ht_base + U3_HT_LINK_COMMAND);
292362306a36Sopenharmony_ci	ucfg = cfg = in_be32(u3_ht_base + U3_HT_LINK_CONFIG);
292462306a36Sopenharmony_ci	ufreq = freq = in_be32(u3_ht_base + U3_HT_LINK_FREQ);
292562306a36Sopenharmony_ci	dump_HT_speeds("U3 HyperTransport", cfg, freq);
292662306a36Sopenharmony_ci
292762306a36Sopenharmony_ci	pcix_node = of_find_compatible_node(NULL, "pci", "pci-x");
292862306a36Sopenharmony_ci	if (pcix_node == NULL) {
292962306a36Sopenharmony_ci		printk("No PCI-X bridge found\n");
293062306a36Sopenharmony_ci		return;
293162306a36Sopenharmony_ci	}
293262306a36Sopenharmony_ci	if (pci_device_from_OF_node(pcix_node, &px_bus, &px_devfn) != 0) {
293362306a36Sopenharmony_ci		printk("PCI-X bridge found but not matched to pci\n");
293462306a36Sopenharmony_ci		return;
293562306a36Sopenharmony_ci	}
293662306a36Sopenharmony_ci	px_hose = pci_find_hose_for_OF_device(pcix_node);
293762306a36Sopenharmony_ci	if (px_hose == NULL) {
293862306a36Sopenharmony_ci		printk("PCI-X bridge found but not matched to host\n");
293962306a36Sopenharmony_ci		return;
294062306a36Sopenharmony_ci	}
294162306a36Sopenharmony_ci	early_read_config_dword(px_hose, px_bus, px_devfn, 0xc4, &cfg);
294262306a36Sopenharmony_ci	early_read_config_dword(px_hose, px_bus, px_devfn, 0xcc, &freq);
294362306a36Sopenharmony_ci	dump_HT_speeds("PCI-X HT Uplink", cfg, freq);
294462306a36Sopenharmony_ci	early_read_config_dword(px_hose, px_bus, px_devfn, 0xc8, &cfg);
294562306a36Sopenharmony_ci	early_read_config_dword(px_hose, px_bus, px_devfn, 0xd0, &freq);
294662306a36Sopenharmony_ci	dump_HT_speeds("PCI-X HT Downlink", cfg, freq);
294762306a36Sopenharmony_ci}
294862306a36Sopenharmony_ci#endif /* 0 */
294962306a36Sopenharmony_ci
295062306a36Sopenharmony_ci/*
295162306a36Sopenharmony_ci * Early video resume hook
295262306a36Sopenharmony_ci */
295362306a36Sopenharmony_ci
295462306a36Sopenharmony_cistatic void (*pmac_early_vresume_proc)(void *data);
295562306a36Sopenharmony_cistatic void *pmac_early_vresume_data;
295662306a36Sopenharmony_ci
295762306a36Sopenharmony_civoid pmac_set_early_video_resume(void (*proc)(void *data), void *data)
295862306a36Sopenharmony_ci{
295962306a36Sopenharmony_ci	if (!machine_is(powermac))
296062306a36Sopenharmony_ci		return;
296162306a36Sopenharmony_ci	preempt_disable();
296262306a36Sopenharmony_ci	pmac_early_vresume_proc = proc;
296362306a36Sopenharmony_ci	pmac_early_vresume_data = data;
296462306a36Sopenharmony_ci	preempt_enable();
296562306a36Sopenharmony_ci}
296662306a36Sopenharmony_ciEXPORT_SYMBOL(pmac_set_early_video_resume);
296762306a36Sopenharmony_ci
296862306a36Sopenharmony_civoid pmac_call_early_video_resume(void)
296962306a36Sopenharmony_ci{
297062306a36Sopenharmony_ci	if (pmac_early_vresume_proc)
297162306a36Sopenharmony_ci		pmac_early_vresume_proc(pmac_early_vresume_data);
297262306a36Sopenharmony_ci}
297362306a36Sopenharmony_ci
297462306a36Sopenharmony_ci/*
297562306a36Sopenharmony_ci * AGP related suspend/resume code
297662306a36Sopenharmony_ci */
297762306a36Sopenharmony_ci
297862306a36Sopenharmony_cistatic struct pci_dev *pmac_agp_bridge;
297962306a36Sopenharmony_cistatic int (*pmac_agp_suspend)(struct pci_dev *bridge);
298062306a36Sopenharmony_cistatic int (*pmac_agp_resume)(struct pci_dev *bridge);
298162306a36Sopenharmony_ci
298262306a36Sopenharmony_civoid pmac_register_agp_pm(struct pci_dev *bridge,
298362306a36Sopenharmony_ci				 int (*suspend)(struct pci_dev *bridge),
298462306a36Sopenharmony_ci				 int (*resume)(struct pci_dev *bridge))
298562306a36Sopenharmony_ci{
298662306a36Sopenharmony_ci	if (suspend || resume) {
298762306a36Sopenharmony_ci		pmac_agp_bridge = bridge;
298862306a36Sopenharmony_ci		pmac_agp_suspend = suspend;
298962306a36Sopenharmony_ci		pmac_agp_resume = resume;
299062306a36Sopenharmony_ci		return;
299162306a36Sopenharmony_ci	}
299262306a36Sopenharmony_ci	if (bridge != pmac_agp_bridge)
299362306a36Sopenharmony_ci		return;
299462306a36Sopenharmony_ci	pmac_agp_suspend = pmac_agp_resume = NULL;
299562306a36Sopenharmony_ci	return;
299662306a36Sopenharmony_ci}
299762306a36Sopenharmony_ciEXPORT_SYMBOL(pmac_register_agp_pm);
299862306a36Sopenharmony_ci
299962306a36Sopenharmony_civoid pmac_suspend_agp_for_card(struct pci_dev *dev)
300062306a36Sopenharmony_ci{
300162306a36Sopenharmony_ci	if (pmac_agp_bridge == NULL || pmac_agp_suspend == NULL)
300262306a36Sopenharmony_ci		return;
300362306a36Sopenharmony_ci	if (pmac_agp_bridge->bus != dev->bus)
300462306a36Sopenharmony_ci		return;
300562306a36Sopenharmony_ci	pmac_agp_suspend(pmac_agp_bridge);
300662306a36Sopenharmony_ci}
300762306a36Sopenharmony_ciEXPORT_SYMBOL(pmac_suspend_agp_for_card);
300862306a36Sopenharmony_ci
300962306a36Sopenharmony_civoid pmac_resume_agp_for_card(struct pci_dev *dev)
301062306a36Sopenharmony_ci{
301162306a36Sopenharmony_ci	if (pmac_agp_bridge == NULL || pmac_agp_resume == NULL)
301262306a36Sopenharmony_ci		return;
301362306a36Sopenharmony_ci	if (pmac_agp_bridge->bus != dev->bus)
301462306a36Sopenharmony_ci		return;
301562306a36Sopenharmony_ci	pmac_agp_resume(pmac_agp_bridge);
301662306a36Sopenharmony_ci}
301762306a36Sopenharmony_ciEXPORT_SYMBOL(pmac_resume_agp_for_card);
301862306a36Sopenharmony_ci
301962306a36Sopenharmony_ciint pmac_get_uninorth_variant(void)
302062306a36Sopenharmony_ci{
302162306a36Sopenharmony_ci	return uninorth_maj;
302262306a36Sopenharmony_ci}
3023