patch-2.2.18 linux/arch/ppc/kernel/feature.c
Next file: linux/arch/ppc/kernel/gemini_setup.c
Previous file: linux/arch/ppc/kernel/chrp_time.c
Back to the patch index
Back to the overall index
- Lines: 723
- Date:
Wed Nov 8 23:00:34 2000
- Orig file:
v2.2.17/arch/ppc/kernel/feature.c
- Orig date:
Sat Sep 9 18:42:33 2000
diff -u --new-file --recursive --exclude-from /usr/src/exclude v2.2.17/arch/ppc/kernel/feature.c linux/arch/ppc/kernel/feature.c
@@ -2,16 +2,13 @@
* arch/ppc/kernel/feature.c
*
* Copyright (C) 1996 Paul Mackerras (paulus@cs.anu.edu.au)
+ * Ben. Herrenschmidt (bh40@calva.net)
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version
* 2 of the License, or (at your option) any later version.
*
- * BenH: Changed implementation to work on multiple registers
- * polarity is also taken into account. Removed delay (now
- * responsibility of the caller). Added spinlocks.
- *
*/
#include <linux/types.h>
#include <linux/init.h>
@@ -22,6 +19,8 @@
#include <asm/errno.h>
#include <asm/ohare.h>
#include <asm/heathrow.h>
+#include <asm/keylargo.h>
+#include <asm/uninorth.h>
#include <asm/io.h>
#include <asm/prom.h>
#include <asm/feature.h>
@@ -29,18 +28,30 @@
#undef DEBUG_FEATURE
#define MAX_FEATURE_CONTROLLERS 2
-#define MAX_FEATURE_OFFSET 0x50
+#define MAX_FEATURE_OFFSET 0x100
#define FREG(c,r) (&(((c)->reg)[(r)>>2]))
+/* Keylargo reg. access. */
+#define KL_FCR(r) (keylargo_base + ((r) >> 2))
+#define KL_IN(r) (in_le32(KL_FCR(r)))
+#define KL_OUT(r,v) (out_le32(KL_FCR(r), (v)))
+#define KL_BIS(r,v) (KL_OUT((r), KL_IN(r) | (v)))
+#define KL_BIC(r,v) (KL_OUT((r), KL_IN(r) & ~(v)))
+
+/* Uni-N reg. access. Note that Uni-N regs are big endian */
+#define UN_REG(r) (uninorth_base + ((r) >> 2))
+#define UN_IN(r) (in_be32(UN_REG(r)))
+#define UN_OUT(r,v) (out_be32(UN_REG(r), (v)))
+#define UN_BIS(r,v) (UN_OUT((r), UN_IN(r) | (v)))
+#define UN_BIC(r,v) (UN_OUT((r), UN_IN(r) & ~(v)))
+
typedef struct feature_bit {
int reg; /* reg. offset from mac-io base */
unsigned int polarity; /* 0 = normal, 1 = inverse */
unsigned int mask; /* bit mask */
} fbit;
-/* I don't have an OHare machine to test with, so I left those as they
- * were. Someone with such a machine chould check out what OF says and
- * try too see if they match the heathrow ones and should be changed too
+/* Those features concern for OHare-based PowerBooks (2400, 3400, 3500)
*/
static fbit feature_bits_ohare_pbook[] = {
{0x38,0,0}, /* FEATURE_null */
@@ -69,13 +80,48 @@
{0x38,0,0}, /* FEATURE_IDE2_reset */
{0x38,0,0}, /* FEATURE_Mediabay_IDE_switch */
{0x38,0,0}, /* FEATURE_Mediabay_content */
+ {0x38,0,0}, /* FEATURE_Airport_reset */
};
-/* Those bits are from a PowerBook. It's possible that desktop machines
- * based on heathrow need a different definition or some bits removed
+/* Those bits concern heathrow-based desktop machines (Beige G3s). We have removed
+ * the SCC related bits and init them once. They have proven to occasionally cause
+ * problems with the desktop units.
*/
static fbit feature_bits_heathrow[] = {
{0x38,0,0}, /* FEATURE_null */
+ {0x38,0,0}, /* FEATURE_Serial_reset */
+ {0x38,0,0}, /* FEATURE_Serial_enable */
+ {0x38,0,0}, /* FEATURE_Serial_IO_A */
+ {0x38,0,0}, /* FEATURE_Serial_IO_B */
+ {0x38,0,HRW_SWIM_ENABLE}, /* FEATURE_SWIM3_enable */
+ {0x38,0,HRW_MESH_ENABLE}, /* FEATURE_MESH_enable */
+ {0x38,0,HRW_IDE0_ENABLE}, /* FEATURE_IDE0_enable */
+ {0x38,1,HRW_IDE0_RESET_N}, /* FEATURE_IDE0_reset */
+ {0x38,0,HRW_IOBUS_ENABLE}, /* FEATURE_IOBUS_enable */
+ {0x38,1,0}, /* FEATURE_Mediabay_reset */
+ {0x38,1,0}, /* FEATURE_Mediabay_power */
+ {0x38,0,0}, /* FEATURE_Mediabay_PCI_enable */
+ {0x38,0,HRW_BAY_IDE_ENABLE}, /* FEATURE_IDE1_enable */
+ {0x38,1,HRW_IDE1_RESET_N}, /* FEATURE_IDE1_reset */
+ {0x38,0,0}, /* FEATURE_Mediabay_floppy_enable */
+ {0x38,0,HRW_BMAC_RESET}, /* FEATURE_BMac_reset */
+ {0x38,0,HRW_BMAC_IO_ENABLE}, /* FEATURE_BMac_IO_enable */
+ {0x38,1,0}, /* FEATURE_Modem_power */
+ {0x38,0,HRW_SLOW_SCC_PCLK}, /* FEATURE_Slow_SCC_PCLK */
+ {0x38,1,0}, /* FEATURE_Sound_Power */
+ {0x38,0,0}, /* FEATURE_Sound_CLK_Enable */
+ {0x38,0,0}, /* FEATURE_IDE2_enable */
+ {0x38,0,0}, /* FEATURE_IDE2_reset */
+ {0x38,0,0}, /* FEATURE_Mediabay_IDE_switch */
+ {0x38,0,0}, /* FEATURE_Mediabay_content */
+ {0x38,0,0}, /* FEATURE_Airport_reset */
+};
+
+/* Those bits concern heathrow-based PowerBooks (wallstreet/mainstreet).
+ * Heathrow-based desktop macs (Beige G3s) are _not_ handled here
+ */
+static fbit feature_bits_wallstreet[] = {
+ {0x38,0,0}, /* FEATURE_null */
{0x38,0,HRW_RESET_SCC}, /* FEATURE_Serial_reset */
{0x38,0,HRW_SCC_ENABLE}, /* FEATURE_Serial_enable */
{0x38,0,HRW_SCCA_IO}, /* FEATURE_Serial_IO_A */
@@ -101,15 +147,17 @@
{0x38,0,0}, /* FEATURE_IDE2_reset */
{0x38,0,0}, /* FEATURE_Mediabay_IDE_switch */
{0x38,0,0}, /* FEATURE_Mediabay_content */
+ {0x38,0,0}, /* FEATURE_Airport_reset */
};
/*
* Those bits are from a 1999 G3 PowerBook, with a paddington chip.
- * Mostly the same as the heathrow.
+ * Mostly the same as the heathrow. They are used on both PowerBooks
+ * and desktop machines using the paddington chip
*/
static fbit feature_bits_paddington[] = {
{0x38,0,0}, /* FEATURE_null */
- {0x38,0,0}, /* FEATURE_Serial_reset */
+ {0x38,0,PADD_RESET_SCC}, /* FEATURE_Serial_reset */
{0x38,0,HRW_SCC_ENABLE}, /* FEATURE_Serial_enable */
{0x38,0,HRW_SCCA_IO}, /* FEATURE_Serial_IO_A */
{0x38,0,HRW_SCCB_IO}, /* FEATURE_Serial_IO_B */
@@ -134,37 +182,40 @@
{0x38,0,0}, /* FEATURE_IDE2_reset */
{0x38,0,0}, /* FEATURE_Mediabay_IDE_switch */
{0x38,0,0}, /* FEATURE_Mediabay_content */
+ {0x38,0,0}, /* FEATURE_Airport_reset */
};
/* Those bits are for Core99 machines (iBook,G4,iMacSL/DV,Pismo,...).
+ * Note: Different sets may be needed for iBook, especially for sound
*/
static fbit feature_bits_keylargo[] = {
{0x38,0,0}, /* FEATURE_null */
- {0x38,0,0}, /* FEATURE_Serial_reset */
- {0x38,0,0x00000054}, /* FEATURE_Serial_enable */
- {0x38,0,0}, /* FEATURE_Serial_IO_A */
- {0x38,0,0}, /* FEATURE_Serial_IO_B */
+ {0x38,0,KL0_SCC_RESET}, /* FEATURE_Serial_reset */
+ {0x38,0,KL0_SERIAL_ENABLE}, /* FEATURE_Serial_enable */
+ {0x38,0,KL0_SCC_A_INTF_ENABLE}, /* FEATURE_Serial_IO_A */
+ {0x38,0,KL0_SCC_B_INTF_ENABLE}, /* FEATURE_Serial_IO_B */
{0x38,0,0}, /* FEATURE_SWIM3_enable */
{0x38,0,0}, /* FEATURE_MESH_enable */
{0x3c,0,0}, /* FEATURE_IDE0_enable */
- {0x3c,1,0x01000000}, /* FEATURE_IDE0_reset */
+ {0x3c,1,KL1_EIDE0_RESET_N}, /* FEATURE_IDE0_reset */
{0x38,0,0}, /* FEATURE_IOBUS_enable */
{0x34,1,0x00000200}, /* FEATURE_Mediabay_reset */
{0x34,1,0x00000400}, /* FEATURE_Mediabay_power */
{0x38,0,0}, /* FEATURE_Mediabay_PCI_enable */
{0x3c,0,0x0}, /* FEATURE_IDE1_enable */
- {0x3c,1,0x08000000}, /* FEATURE_IDE1_reset */
+ {0x3c,1,KL1_EIDE1_RESET_N}, /* FEATURE_IDE1_reset */
{0x38,0,0}, /* FEATURE_Mediabay_floppy_enable */
{0x38,0,0}, /* FEATURE_BMac_reset */
{0x38,0,0}, /* FEATURE_BMac_IO_enable */
- {0x40,1,0x02000000}, /* FEATURE_Modem_power */
+ {0x40,1,KL2_MODEM_POWER_N}, /* FEATURE_Modem_power */
{0x38,0,0}, /* FEATURE_Slow_SCC_PCLK */
{0x38,0,0}, /* FEATURE_Sound_Power */
{0x38,0,0}, /* FEATURE_Sound_CLK_Enable */
{0x38,0,0}, /* FEATURE_IDE2_enable */
- {0x3c,1,0x40000000}, /* FEATURE_IDE2_reset */
- {0x34,0,0x00001000}, /* FEATURE_Mediabay_IDE_switch */
+ {0x3c,1,KL1_UIDE_RESET_N}, /* FEATURE_IDE2_reset */
+ {0x34,0,KL_MBCR_MBDEV_ENABLE}, /* FEATURE_Mediabay_IDE_switch */
{0x34,0,0x00000100}, /* FEATURE_Mediabay_content */
+ {0x40,1,KL2_AIRPORT_RESET_N}, /* FEATURE_Airport_reset */
};
/* definition of a feature controller object */
@@ -176,33 +227,93 @@
};
/* static functions */
-static void
+static struct feature_controller*
feature_add_controller(struct device_node *controller_device, fbit* bits);
static struct feature_controller*
feature_lookup_controller(struct device_node *device);
-/* static varialbles */
+static void uninorth_init(void);
+static void keylargo_init(void);
+#ifdef CONFIG_PMAC_PBOOK
+static void heathrow_prepare_for_sleep(struct feature_controller* ctrler);
+static void heathrow_wakeup(struct feature_controller* ctrler);
+static void core99_prepare_for_sleep(struct feature_controller* ctrler);
+static void core99_wake_up(struct feature_controller* ctrler);
+#endif /* CONFIG_PMAC_PBOOK */
+
+/* static variables */
static struct feature_controller controllers[MAX_FEATURE_CONTROLLERS];
static int controller_count = 0;
+/* Core99 stuffs */
+static volatile u32* uninorth_base;
+static volatile u32* keylargo_base;
+static struct feature_controller* keylargo;
+static int uninorth_rev;
+static int keylargo_rev;
+static u32 board_features;
+
+#define FTR_NEED_OPENPIC_TWEAK 0x00000001
+
+static struct board_features_t {
+ char* compatible;
+ u32 features;
+} board_features_datas[] __init =
+{
+ { "PowerMac2,1", 0 }, /* iMac ? */
+ { "PowerMac2,2", 0 }, /* iMac ? */
+ { "PowerMac3,1", FTR_NEED_OPENPIC_TWEAK }, /* Sawtooth (G4) */
+ { "PowerMac3,3", 0 }, /* Dual G4 or Cube ? */
+ { "PowerMac5,1", 0 }, /* Dual G4 or Cube ? */
+ { "PowerBook2,1", 0 }, /* iBook */
+ { "PowerBook2,2", 0 }, /* iBook FireWire ? */
+ { "PowerBook3,1", 0 }, /* PowerBook 2000 (Pismo) */
+ { NULL, 0 }
+};
void
feature_init(void)
{
struct device_node *np;
+ u32* rev;
+ int i;
+
+ /* Figure out motherboard type & options */
+ for(i=0;board_features_datas[i].compatible;i++)
+ if (machine_is_compatible(board_features_datas[i].compatible)) {
+ board_features = board_features_datas[i].features;
+ break;
+ }
+ /* Track those poor mac-io's */
+
np = find_devices("mac-io");
while (np != NULL) {
/* KeyLargo contains several (5 ?) FCR registers in mac-io,
* plus some gpio's which could eventually be handled here.
*/
if (device_is_compatible(np, "Keylargo")) {
- feature_add_controller(np, feature_bits_keylargo);
+ struct feature_controller* ctrler =
+ feature_add_controller(np, feature_bits_keylargo);
+ if (ctrler) {
+ keylargo = ctrler;
+ keylargo_base = ctrler->reg;
+ rev = (u32 *)get_property(ctrler->device, "revision-id", NULL);
+ if (rev)
+ keylargo_rev = *rev;
+ }
} else if (device_is_compatible(np, "paddington")) {
feature_add_controller(np, feature_bits_paddington);
+ } else if (machine_is_compatible("AAPL,PowerBook1998")) {
+ feature_add_controller(np, feature_bits_wallstreet);
} else {
- feature_add_controller(np, feature_bits_heathrow);
+ struct feature_controller* ctrler =
+ feature_add_controller(np, feature_bits_heathrow);
+ if (ctrler)
+ out_le32(FREG(ctrler,HEATHROW_FEATURE_REG),
+ in_le32(FREG(ctrler,HEATHROW_FEATURE_REG)) | HRW_DEFAULTS);
+
}
np = np->next;
}
@@ -218,6 +329,20 @@
}
}
+ /* Locate core99 Uni-N */
+ np = find_devices("uni-n");
+ if (np && np->n_addrs > 0) {
+ uninorth_base = ioremap(np->addrs[0].address, 0x1000);
+ uninorth_rev = in_be32(UN_REG(UNI_N_VERSION));
+ }
+ if (uninorth_base && keylargo_base)
+ printk("Uni-N revision: %d, KeyLargo revision: %d\n",
+ uninorth_rev, keylargo_rev);
+ if (uninorth_base)
+ uninorth_init();
+ if (keylargo_base)
+ keylargo_init();
+
if (controller_count)
printk(KERN_INFO "Registered %d feature controller(s)\n", controller_count);
@@ -232,7 +357,7 @@
#endif
}
-static void
+static struct feature_controller*
feature_add_controller(struct device_node *controller_device, fbit* bits)
{
struct feature_controller* controller;
@@ -240,7 +365,7 @@
if (controller_count >= MAX_FEATURE_CONTROLLERS) {
printk(KERN_INFO "Feature controller %s skipped(MAX:%d)\n",
controller_device->full_name, MAX_FEATURE_CONTROLLERS);
- return;
+ return NULL;
}
controller = &controllers[controller_count];
@@ -249,21 +374,27 @@
if (controller_device->n_addrs == 0) {
printk(KERN_ERR "No addresses for %s\n",
controller_device->full_name);
- return;
+ return NULL;
}
+ /* We remap the entire mac-io here. Normally, this will just
+ * give us back our already existing BAT mapping
+ */
controller->reg = (volatile u32 *)ioremap(
- controller_device->addrs[0].address, MAX_FEATURE_OFFSET);
+ controller_device->addrs[0].address,
+ controller_device->addrs[0].size);
if (bits == NULL) {
printk(KERN_INFO "Twiddling the magic ohare bits\n");
out_le32(FREG(controller,OHARE_FEATURE_REG), STARMAX_FEATURES);
- return;
+ return NULL;
}
spin_lock_init(&controller->lock);
controller_count++;
+
+ return controller;
}
static struct feature_controller*
@@ -383,5 +514,371 @@
*/
value = (in_le32(FREG(controller, bit->reg)) & bit->mask);
return bit->polarity ? (value == 0) : (value == bit->mask);
+}
+
+/*
+ * Core99 functions
+ *
+ * Note: We currently assume there is _one_ UniN chip and _one_ KeyLargo
+ * chip, which is the case on all Core99 machines so far
+ */
+
+/* Only one GMAC is assumed */
+void
+feature_set_gmac_power(struct device_node* device, int power)
+{
+ unsigned long flags;
+
+ if (!uninorth_base || !keylargo)
+ return;
+
+ spin_lock_irqsave(&keylargo->lock, flags);
+ if (power)
+ UN_BIS(UNI_N_CLOCK_CNTL, UNI_N_CLOCK_CNTL_GMAC);
+ else
+ UN_BIC(UNI_N_CLOCK_CNTL, UNI_N_CLOCK_CNTL_GMAC);
+ spin_unlock_irqrestore(&keylargo->lock, flags);
+ udelay(20);
+}
+
+void
+feature_set_gmac_phy_reset(struct device_node* device, int reset)
+{
+ unsigned long flags;
+
+ if (!keylargo_base || !keylargo)
+ return;
+
+ spin_lock_irqsave(&keylargo->lock, flags);
+ out_8((volatile u8 *)KL_FCR(KL_GPIO_ETH_PHY_RESET), reset);
+ (void)in_8((volatile u8 *)KL_FCR(KL_GPIO_ETH_PHY_RESET));
+ spin_unlock_irqrestore(&keylargo->lock, flags);
+}
+
+/* Pass the node of the correct controller, please */
+void
+feature_set_usb_power(struct device_node* device, int power)
+{
+ char* prop;
+ int number;
+ u32 reg;
+
+ unsigned long flags;
+
+ if (!keylargo_base || !keylargo)
+ return;
+
+ prop = (char *)get_property(device, "AAPL,clock-id", NULL);
+ if (!prop)
+ return;
+ if (strncmp(prop, "usb0u048", strlen("usb0u048")) == 0)
+ number = 0;
+ else if (strncmp(prop, "usb1u148", strlen("usb1u148")) == 0)
+ number = 2;
+ else
+ return;
+
+ spin_lock_irqsave(&keylargo->lock, flags);
+ if (power) {
+ /* Turn ON */
+
+ if (number == 0) {
+ KL_BIC(KEYLARGO_FCR0, (KL0_USB0_PAD_SUSPEND0 | KL0_USB0_PAD_SUSPEND1));
+ mdelay(1);
+ KL_BIS(KEYLARGO_FCR0, KL0_USB0_CELL_ENABLE);
+ } else {
+ KL_BIC(KEYLARGO_FCR0, (KL0_USB1_PAD_SUSPEND0 | KL0_USB1_PAD_SUSPEND1));
+ mdelay(1);
+ KL_BIS(KEYLARGO_FCR0, KL0_USB1_CELL_ENABLE);
+ }
+ reg = KL_IN(KEYLARGO_FCR4);
+ reg &= ~(KL4_SET_PORT_ENABLE(number) | KL4_SET_PORT_RESUME(number) |
+ KL4_SET_PORT_CONNECT(number) | KL4_SET_PORT_DISCONNECT(number));
+ reg &= ~(KL4_SET_PORT_ENABLE(number+1) | KL4_SET_PORT_RESUME(number+1) |
+ KL4_SET_PORT_CONNECT(number+1) | KL4_SET_PORT_DISCONNECT(number+1));
+ KL_OUT(KEYLARGO_FCR4, reg);
+ (void)KL_IN(KEYLARGO_FCR4);
+ udelay(10);
+ } else {
+ /* Turn OFF */
+
+ reg = KL_IN(KEYLARGO_FCR4);
+ reg |= KL4_SET_PORT_ENABLE(number) | KL4_SET_PORT_RESUME(number) |
+ KL4_SET_PORT_CONNECT(number) | KL4_SET_PORT_DISCONNECT(number);
+ reg |= KL4_SET_PORT_ENABLE(number+1) | KL4_SET_PORT_RESUME(number+1) |
+ KL4_SET_PORT_CONNECT(number+1) | KL4_SET_PORT_DISCONNECT(number+1);
+ KL_OUT(KEYLARGO_FCR4, reg);
+ (void)KL_IN(KEYLARGO_FCR4);
+ udelay(1);
+ if (number == 0) {
+ KL_BIC(KEYLARGO_FCR0, KL0_USB0_CELL_ENABLE);
+ (void)KL_IN(KEYLARGO_FCR0);
+ udelay(1);
+ KL_BIS(KEYLARGO_FCR0, (KL0_USB0_PAD_SUSPEND0 | KL0_USB0_PAD_SUSPEND1));
+ (void)KL_IN(KEYLARGO_FCR0);
+ } else {
+ KL_BIC(KEYLARGO_FCR0, KL0_USB1_CELL_ENABLE);
+ (void)KL_IN(KEYLARGO_FCR0);
+ udelay(1);
+ KL_BIS(KEYLARGO_FCR0, (KL0_USB1_PAD_SUSPEND0 | KL0_USB1_PAD_SUSPEND1));
+ (void)KL_IN(KEYLARGO_FCR0);
+ }
+ udelay(1);
+ }
+ spin_unlock_irqrestore(&keylargo->lock, flags);
+}
+
+/* Not yet implemented */
+void
+feature_set_firewire_power(struct device_node* device, int power)
+{
+}
+
+#ifdef CONFIG_SMP
+void
+feature_core99_kick_cpu1(void)
+{
+ out_8((volatile u8 *)KL_FCR(KL_GPIO_EXTINT_CPU1), KL_GPIO_EXTINT_CPU1_ASSERT);
+ udelay(1);
+ out_8((volatile u8 *)KL_FCR(KL_GPIO_EXTINT_CPU1), KL_GPIO_EXTINT_CPU1_RELEASE);
+}
+#endif /* CONFIG_SMP */
+
+#ifdef CONFIG_PMAC_PBOOK
+void
+feature_prepare_for_sleep(void)
+{
+ /* We assume gatwick is second */
+ struct feature_controller* ctrler = &controllers[0];
+
+ if (!ctrler)
+ return;
+ if (controller_count > 1 &&
+ device_is_compatible(ctrler->device, "gatwick"))
+ ctrler = &controllers[1];
+
+ if (ctrler->bits == feature_bits_heathrow ||
+ ctrler->bits == feature_bits_paddington) {
+ heathrow_prepare_for_sleep(ctrler);
+ return;
+ }
+ if (ctrler->bits == feature_bits_keylargo) {
+ core99_prepare_for_sleep(ctrler);
+ return;
+ }
+}
+
+
+void
+feature_wake_up(void)
+{
+ struct feature_controller* ctrler = &controllers[0];
+
+ if (!ctrler)
+ return;
+ if (controller_count > 1 &&
+ device_is_compatible(ctrler->device, "gatwick"))
+ ctrler = &controllers[1];
+
+ if (ctrler->bits == feature_bits_heathrow ||
+ ctrler->bits == feature_bits_paddington) {
+ heathrow_wakeup(ctrler);
+ return;
+ }
+ if (ctrler->bits == feature_bits_keylargo) {
+ core99_wake_up(ctrler);
+ return;
+ }
+}
+
+static u32 save_fcr[5];
+static u32 save_mbcr;
+static u32 save_gpio_levels[2];
+static u8 save_gpio_extint[KEYLARGO_GPIO_EXTINT_CNT];
+static u8 save_gpio_normal[KEYLARGO_GPIO_CNT];
+
+static void
+heathrow_prepare_for_sleep(struct feature_controller* ctrler)
+{
+ save_mbcr = in_le32(FREG(ctrler, 0x34));
+ save_fcr[0] = in_le32(FREG(ctrler, 0x38));
+ save_fcr[1] = in_le32(FREG(ctrler, 0x3c));
+
+ out_le32(FREG(ctrler, 0x38), save_fcr[0] & ~HRW_IOBUS_ENABLE);
+}
+
+static void
+heathrow_wakeup(struct feature_controller* ctrler)
+{
+ out_le32(FREG(ctrler, 0x38), save_fcr[0]);
+ out_le32(FREG(ctrler, 0x3c), save_fcr[1]);
+ out_le32(FREG(ctrler, 0x34), save_mbcr);
+ mdelay(1);
+ out_le32(FREG(ctrler, 0x38), save_fcr[0] | HRW_IOBUS_ENABLE);
+ mdelay(1);
+}
+
+
+static void
+core99_prepare_for_sleep(struct feature_controller* ctrler)
+{
+ u32 temp;
+ int i;
+ u8* base8;
+
+ /*
+ * Save various bits of KeyLargo
+ */
+
+ save_gpio_levels[0] = KL_IN(KEYLARGO_GPIO_LEVELS0);
+ save_gpio_levels[1] = KL_IN(KEYLARGO_GPIO_LEVELS1);
+ base8 = (u8 *)KL_FCR(KEYLARGO_GPIO_EXTINT_0);
+ for (i=0; i<KEYLARGO_GPIO_EXTINT_CNT; i++)
+ save_gpio_extint[i] = in_8(base8+i);
+ base8 = (u8 *)KL_FCR(KEYLARGO_GPIO_0);
+ for (i=0; i<KEYLARGO_GPIO_CNT; i++)
+ save_gpio_normal[i] = in_8(base8+i);
+ save_mbcr = KL_IN(KEYLARGO_MBCR);
+ save_fcr[0] = KL_IN(KEYLARGO_FCR0);
+ save_fcr[1] = KL_IN(KEYLARGO_FCR1);
+ save_fcr[2] = KL_IN(KEYLARGO_FCR2);
+ save_fcr[3] = KL_IN(KEYLARGO_FCR3);
+ save_fcr[4] = KL_IN(KEYLARGO_FCR4);
+
+ /*
+ * Turn off as much as we can
+ */
+
+ KL_BIS(KEYLARGO_FCR0, KL0_USB_REF_SUSPEND);
+ mdelay(1);
+ KL_BIC(KEYLARGO_FCR0, KL0_SCCA_ENABLE | KL0_SCCB_ENABLE | KL0_SCC_CELL_ENABLE);
+ KL_BIC(KEYLARGO_FCR0, KL0_IRDA_ENABLE | KL0_IRDA_CLK32_ENABLE | KL0_IRDA_CLK19_ENABLE);
+
+ KL_BIS(KEYLARGO_MBCR, KL_MBCR_MBDEV_ENABLE);
+
+ KL_BIC(KEYLARGO_FCR1,
+ KL1_AUDIO_SEL_22MCLK | KL1_AUDIO_CLK_ENABLE_BIT |
+ KL1_AUDIO_CLK_OUT_ENABLE | KL1_AUDIO_CELL_ENABLE |
+ KL1_I2S0_CELL_ENABLE | KL1_I2S0_CLK_ENABLE_BIT |
+ KL1_I2S0_ENABLE | KL1_I2S1_CELL_ENABLE |
+ KL1_I2S1_CLK_ENABLE_BIT | KL1_I2S1_ENABLE |
+ KL1_EIDE0_ENABLE | KL1_EIDE0_RESET_N |
+ KL1_EIDE1_ENABLE | KL1_EIDE1_RESET_N |
+ KL1_UIDE_ENABLE);
+
+ KL_BIS(KEYLARGO_FCR2, KL2_MODEM_POWER_N);
+ KL_BIC(KEYLARGO_FCR2, KL2_IOBUS_ENABLE);
+
+ temp = KL_IN(KEYLARGO_FCR3);
+ if (keylargo_rev >= 2)
+ temp |= (KL3_SHUTDOWN_PLL2X | KL3_SHUTDOWN_PLL_TOTAL);
+
+ temp |= KL3_SHUTDOWN_PLLKW6 | KL3_SHUTDOWN_PLLKW4 |
+ KL3_SHUTDOWN_PLLKW35 | KL3_SHUTDOWN_PLLKW12;
+ temp &= ~(KL3_CLK66_ENABLE | KL3_CLK49_ENABLE | KL3_CLK45_ENABLE
+ | KL3_CLK31_ENABLE | KL3_TIMER_CLK18_ENABLE | KL3_I2S1_CLK18_ENABLE
+ | KL3_I2S0_CLK18_ENABLE | KL3_VIA_CLK16_ENABLE);
+ KL_OUT(KEYLARGO_FCR3, temp);
+
+ /*
+ * Put the host bridge to sleep
+ */
+
+ UN_OUT(UNI_N_HWINIT_STATE, UNI_N_HWINIT_STATE_SLEEPING);
+ UN_OUT(UNI_N_POWER_MGT, UNI_N_POWER_MGT_SLEEP);
+
+ /*
+ * FIXME: A bit of black magic with OpenPIC (don't ask me why)
+ */
+ if (board_features & FTR_NEED_OPENPIC_TWEAK) {
+ KL_BIS(0x506e0, 0x00400000);
+ KL_BIS(0x506e0, 0x80000000);
+ }
+}
+
+static void
+core99_wake_up(struct feature_controller* ctrler)
+{
+ int i;
+ u8* base8;
+
+ /*
+ * Wakeup the host bridge
+ */
+ UN_OUT(UNI_N_POWER_MGT, UNI_N_POWER_MGT_NORMAL);
+ UN_OUT(UNI_N_HWINIT_STATE, UNI_N_HWINIT_STATE_RUNNING);
+
+ /*
+ * Restore KeyLargo
+ */
+
+ KL_OUT(KEYLARGO_MBCR, save_mbcr);
+ KL_OUT(KEYLARGO_FCR0, save_fcr[0]);
+ KL_OUT(KEYLARGO_FCR1, save_fcr[1]);
+ KL_OUT(KEYLARGO_FCR2, save_fcr[2]);
+ KL_OUT(KEYLARGO_FCR3, save_fcr[3]);
+ KL_OUT(KEYLARGO_FCR4, save_fcr[4]);
+ mdelay(1);
+ KL_OUT(KEYLARGO_GPIO_LEVELS0, save_gpio_levels[0]);
+ KL_OUT(KEYLARGO_GPIO_LEVELS1, save_gpio_levels[1]);
+ base8 = (u8 *)KL_FCR(KEYLARGO_GPIO_EXTINT_0);
+ for (i=0; i<KEYLARGO_GPIO_EXTINT_CNT; i++)
+ out_8(base8+i, save_gpio_extint[i]);
+ base8 = (u8 *)KL_FCR(KEYLARGO_GPIO_0);
+ for (i=0; i<KEYLARGO_GPIO_CNT; i++)
+ out_8(base8+i, save_gpio_normal[i]);
+
+ /* FIXME more black magic with OpenPIC ... */
+ if (board_features & FTR_NEED_OPENPIC_TWEAK) {
+ KL_BIC(0x506e0, 0x00400000);
+ KL_BIC(0x506e0, 0x80000000);
+ }
+}
+#endif /* CONFIG_PMAC_PBOOK */
+
+/* Initialize the Core99 UniNorth host bridge and memory controller
+ */
+static void
+uninorth_init(void)
+{
+ struct device_node* gmac;
+ unsigned long actrl;
+
+ /* Set the arbitrer QAck delay according to what Apple does
+ */
+ actrl = UN_IN(UNI_N_ARB_CTRL) & ~UNI_N_ARB_CTRL_QACK_DELAY_MASK;
+ actrl |= ((uninorth_rev < 3) ? UNI_N_ARB_CTRL_QACK_DELAY105 : UNI_N_ARB_CTRL_QACK_DELAY)
+ << UNI_N_ARB_CTRL_QACK_DELAY_SHIFT;
+ UN_OUT(UNI_N_ARB_CTRL, actrl);
+
+ /*
+ * Turns OFF the gmac clock. The gmac driver will turn
+ * it back ON when the interface is enabled. This save
+ * power on portables.
+ *
+ * Note: We could also try to turn OFF the PHY. Since this
+ * has to be done by both the gmac driver and this code,
+ * I'll probably end-up moving some of this out of the
+ * modular gmac driver into a non-modular stub containing
+ * some basic PHY management and power management stuffs
+ */
+ gmac = find_devices("ethernet");
+
+ while(gmac) {
+ if (device_is_compatible(gmac, "gmac"))
+ break;
+ gmac = gmac->next;
+ }
+ if (gmac)
+ feature_set_gmac_power(gmac, 0);
+}
+
+/* Initialize the Core99 KeyLargo ASIC. Currently, we just make sure
+ * OpenPIC is enabled
+ */
+static void
+keylargo_init(void)
+{
+ KL_BIS(KEYLARGO_FCR2, KL2_MPIC_ENABLE);
}
FUNET's LINUX-ADM group, linux-adm@nic.funet.fi
TCL-scripts by Sam Shen (who was at: slshen@lbl.gov)