]> git.openfabrics.org - ~emulex/infiniband.git/commitdiff
powerpc: rename powermac files to remove pmac_ prefix
authorPaul Mackerras <paulus@samba.org>
Mon, 10 Oct 2005 12:13:53 +0000 (22:13 +1000)
committerPaul Mackerras <paulus@samba.org>
Mon, 10 Oct 2005 12:13:53 +0000 (22:13 +1000)
Since the files are now in arch/powerpc/platforms/powermac, the
pmac_ prefix that they had is redundant.

Signed-off-by: Paul Mackerras <paulus@samba.org>
27 files changed:
arch/powerpc/platforms/powermac/Makefile
arch/powerpc/platforms/powermac/backlight.c [new file with mode: 0644]
arch/powerpc/platforms/powermac/cache.S [new file with mode: 0644]
arch/powerpc/platforms/powermac/cpufreq.c [new file with mode: 0644]
arch/powerpc/platforms/powermac/feature.c [new file with mode: 0644]
arch/powerpc/platforms/powermac/low_i2c.c [new file with mode: 0644]
arch/powerpc/platforms/powermac/nvram.c [new file with mode: 0644]
arch/powerpc/platforms/powermac/pci.c [new file with mode: 0644]
arch/powerpc/platforms/powermac/pic.c [new file with mode: 0644]
arch/powerpc/platforms/powermac/pic.h [new file with mode: 0644]
arch/powerpc/platforms/powermac/pmac_backlight.c [deleted file]
arch/powerpc/platforms/powermac/pmac_cache.S [deleted file]
arch/powerpc/platforms/powermac/pmac_cpufreq.c [deleted file]
arch/powerpc/platforms/powermac/pmac_feature.c [deleted file]
arch/powerpc/platforms/powermac/pmac_low_i2c.c [deleted file]
arch/powerpc/platforms/powermac/pmac_nvram.c [deleted file]
arch/powerpc/platforms/powermac/pmac_pci.c [deleted file]
arch/powerpc/platforms/powermac/pmac_pic.c [deleted file]
arch/powerpc/platforms/powermac/pmac_pic.h [deleted file]
arch/powerpc/platforms/powermac/pmac_setup.c [deleted file]
arch/powerpc/platforms/powermac/pmac_sleep.S [deleted file]
arch/powerpc/platforms/powermac/pmac_smp.c [deleted file]
arch/powerpc/platforms/powermac/pmac_time.c [deleted file]
arch/powerpc/platforms/powermac/setup.c [new file with mode: 0644]
arch/powerpc/platforms/powermac/sleep.S [new file with mode: 0644]
arch/powerpc/platforms/powermac/smp.c [new file with mode: 0644]
arch/powerpc/platforms/powermac/time.c [new file with mode: 0644]

index 37b7341396e49850768dfb5a37d7ebb3cacdf1de..74712ede16dfa6cf78e51a31ddf4ba419145a1e4 100644 (file)
@@ -1,9 +1,8 @@
-obj-$(CONFIG_PPC_PMAC)         += pmac_pic.o pmac_setup.o pmac_time.o \
-                                  pmac_feature.o pmac_pci.o pmac_sleep.o \
-                                  pmac_low_i2c.o pmac_cache.o
-obj-$(CONFIG_PMAC_BACKLIGHT)   += pmac_backlight.o
-obj-$(CONFIG_CPU_FREQ_PMAC)    += pmac_cpufreq.o
+obj-$(CONFIG_PPC_PMAC)         += pic.o setup.o time.o feature.o pci.o \
+                                  sleep.o low_i2c.o cache.o
+obj-$(CONFIG_PMAC_BACKLIGHT)   += backlight.o
+obj-$(CONFIG_CPU_FREQ_PMAC)    += cpufreq.o
 ifeq ($(CONFIG_PPC_PMAC),y)
-obj-$(CONFIG_NVRAM)            += pmac_nvram.o
-obj-$(CONFIG_SMP)              += pmac_smp.o
+obj-$(CONFIG_NVRAM)            += nvram.o
+obj-$(CONFIG_SMP)              += smp.o
 endif
diff --git a/arch/powerpc/platforms/powermac/backlight.c b/arch/powerpc/platforms/powermac/backlight.c
new file mode 100644 (file)
index 0000000..8be2f7d
--- /dev/null
@@ -0,0 +1,202 @@
+/*
+ * Miscellaneous procedures for dealing with the PowerMac hardware.
+ * Contains support for the backlight.
+ *
+ *   Copyright (C) 2000 Benjamin Herrenschmidt
+ *
+ */
+
+#include <linux/config.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/stddef.h>
+#include <linux/reboot.h>
+#include <linux/nvram.h>
+#include <linux/console.h>
+#include <asm/sections.h>
+#include <asm/ptrace.h>
+#include <asm/io.h>
+#include <asm/pgtable.h>
+#include <asm/system.h>
+#include <asm/prom.h>
+#include <asm/machdep.h>
+#include <asm/nvram.h>
+#include <asm/backlight.h>
+
+#include <linux/adb.h>
+#include <linux/pmu.h>
+
+static struct backlight_controller *backlighter;
+static void* backlighter_data;
+static int backlight_autosave;
+static int backlight_level = BACKLIGHT_MAX;
+static int backlight_enabled = 1;
+static int backlight_req_level = -1;
+static int backlight_req_enable = -1;
+
+static void backlight_callback(void *);
+static DECLARE_WORK(backlight_work, backlight_callback, NULL);
+
+void register_backlight_controller(struct backlight_controller *ctrler,
+                                         void *data, char *type)
+{
+       struct device_node* bk_node;
+       char *prop;
+       int valid = 0;
+
+       /* There's already a matching controller, bail out */
+       if (backlighter != NULL)
+               return;
+
+       bk_node = find_devices("backlight");
+
+#ifdef CONFIG_ADB_PMU
+       /* Special case for the old PowerBook since I can't test on it */
+       backlight_autosave = machine_is_compatible("AAPL,3400/2400")
+               || machine_is_compatible("AAPL,3500");
+       if ((backlight_autosave
+            || machine_is_compatible("AAPL,PowerBook1998")
+            || machine_is_compatible("PowerBook1,1"))
+           && !strcmp(type, "pmu"))
+               valid = 1;
+#endif
+       if (bk_node) {
+               prop = get_property(bk_node, "backlight-control", NULL);
+               if (prop && !strncmp(prop, type, strlen(type)))
+                       valid = 1;
+       }
+       if (!valid)
+               return;
+       backlighter = ctrler;
+       backlighter_data = data;
+
+       if (bk_node && !backlight_autosave)
+               prop = get_property(bk_node, "bklt", NULL);
+       else
+               prop = NULL;
+       if (prop) {
+               backlight_level = ((*prop)+1) >> 1;
+               if (backlight_level > BACKLIGHT_MAX)
+                       backlight_level = BACKLIGHT_MAX;
+       }
+
+#ifdef CONFIG_ADB_PMU
+       if (backlight_autosave) {
+               struct adb_request req;
+               pmu_request(&req, NULL, 2, 0xd9, 0);
+               while (!req.complete)
+                       pmu_poll();
+               backlight_level = req.reply[0] >> 4;
+       }
+#endif
+       acquire_console_sem();
+       if (!backlighter->set_enable(1, backlight_level, data))
+               backlight_enabled = 1;
+       release_console_sem();
+
+       printk(KERN_INFO "Registered \"%s\" backlight controller,"
+              "level: %d/15\n", type, backlight_level);
+}
+EXPORT_SYMBOL(register_backlight_controller);
+
+void unregister_backlight_controller(struct backlight_controller
+                                           *ctrler, void *data)
+{
+       /* We keep the current backlight level (for now) */
+       if (ctrler == backlighter && data == backlighter_data)
+               backlighter = NULL;
+}
+EXPORT_SYMBOL(unregister_backlight_controller);
+
+static int __set_backlight_enable(int enable)
+{
+       int rc;
+
+       if (!backlighter)
+               return -ENODEV;
+       acquire_console_sem();
+       rc = backlighter->set_enable(enable, backlight_level,
+                                    backlighter_data);
+       if (!rc)
+               backlight_enabled = enable;
+       release_console_sem();
+       return rc;
+}
+int set_backlight_enable(int enable)
+{
+       if (!backlighter)
+               return -ENODEV;
+       backlight_req_enable = enable;
+       schedule_work(&backlight_work);
+       return 0;
+}
+
+EXPORT_SYMBOL(set_backlight_enable);
+
+int get_backlight_enable(void)
+{
+       if (!backlighter)
+               return -ENODEV;
+       return backlight_enabled;
+}
+EXPORT_SYMBOL(get_backlight_enable);
+
+static int __set_backlight_level(int level)
+{
+       int rc = 0;
+
+       if (!backlighter)
+               return -ENODEV;
+       if (level < BACKLIGHT_MIN)
+               level = BACKLIGHT_OFF;
+       if (level > BACKLIGHT_MAX)
+               level = BACKLIGHT_MAX;
+       acquire_console_sem();
+       if (backlight_enabled)
+               rc = backlighter->set_level(level, backlighter_data);
+       if (!rc)
+               backlight_level = level;
+       release_console_sem();
+       if (!rc && !backlight_autosave) {
+               level <<=1;
+               if (level & 0x10)
+                       level |= 0x01;
+               // -- todo: save to property "bklt"
+       }
+       return rc;
+}
+int set_backlight_level(int level)
+{
+       if (!backlighter)
+               return -ENODEV;
+       backlight_req_level = level;
+       schedule_work(&backlight_work);
+       return 0;
+}
+
+EXPORT_SYMBOL(set_backlight_level);
+
+int get_backlight_level(void)
+{
+       if (!backlighter)
+               return -ENODEV;
+       return backlight_level;
+}
+EXPORT_SYMBOL(get_backlight_level);
+
+static void backlight_callback(void *dummy)
+{
+       int level, enable;
+
+       do {
+               level = backlight_req_level;
+               enable = backlight_req_enable;
+               mb();
+
+               if (level >= 0)
+                       __set_backlight_level(level);
+               if (enable >= 0)
+                       __set_backlight_enable(enable);
+       } while(cmpxchg(&backlight_req_level, level, -1) != level ||
+               cmpxchg(&backlight_req_enable, enable, -1) != enable);
+}
diff --git a/arch/powerpc/platforms/powermac/cache.S b/arch/powerpc/platforms/powermac/cache.S
new file mode 100644 (file)
index 0000000..fb977de
--- /dev/null
@@ -0,0 +1,359 @@
+/*
+ * This file contains low-level cache management functions
+ * used for sleep and CPU speed changes on Apple machines.
+ * (In fact the only thing that is Apple-specific is that we assume
+ * that we can read from ROM at physical address 0xfff00000.)
+ *
+ *    Copyright (C) 2004 Paul Mackerras (paulus@samba.org) and
+ *                       Benjamin Herrenschmidt (benh@kernel.crashing.org)
+ *
+ * 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.
+ *
+ */
+
+#include <linux/config.h>
+#include <asm/processor.h>
+#include <asm/ppc_asm.h>
+#include <asm/cputable.h>
+
+/*
+ * Flush and disable all data caches (dL1, L2, L3). This is used
+ * when going to sleep, when doing a PMU based cpufreq transition,
+ * or when "offlining" a CPU on SMP machines. This code is over
+ * paranoid, but I've had enough issues with various CPU revs and
+ * bugs that I decided it was worth beeing over cautious
+ */
+
+_GLOBAL(flush_disable_caches)
+#ifndef CONFIG_6xx
+       blr
+#else
+BEGIN_FTR_SECTION
+       b       flush_disable_745x
+END_FTR_SECTION_IFSET(CPU_FTR_SPEC7450)
+BEGIN_FTR_SECTION
+       b       flush_disable_75x
+END_FTR_SECTION_IFSET(CPU_FTR_L2CR)
+       b       __flush_disable_L1
+
+/* This is the code for G3 and 74[01]0 */
+flush_disable_75x:
+       mflr    r10
+
+       /* Turn off EE and DR in MSR */
+       mfmsr   r11
+       rlwinm  r0,r11,0,~MSR_EE
+       rlwinm  r0,r0,0,~MSR_DR
+       sync
+       mtmsr   r0
+       isync
+
+       /* Stop DST streams */
+BEGIN_FTR_SECTION
+       DSSALL
+       sync
+END_FTR_SECTION_IFSET(CPU_FTR_ALTIVEC)
+
+       /* Stop DPM */
+       mfspr   r8,SPRN_HID0            /* Save SPRN_HID0 in r8 */
+       rlwinm  r4,r8,0,12,10           /* Turn off HID0[DPM] */
+       sync
+       mtspr   SPRN_HID0,r4            /* Disable DPM */
+       sync
+
+       /* Disp-flush L1. We have a weird problem here that I never
+        * totally figured out. On 750FX, using the ROM for the flush
+        * results in a non-working flush. We use that workaround for
+        * now until I finally understand what's going on. --BenH
+        */
+
+       /* ROM base by default */
+       lis     r4,0xfff0
+       mfpvr   r3
+       srwi    r3,r3,16
+       cmplwi  cr0,r3,0x7000
+       bne+    1f
+       /* RAM base on 750FX */
+       li      r4,0
+1:     li      r4,0x4000
+       mtctr   r4
+1:     lwz     r0,0(r4)
+       addi    r4,r4,32
+       bdnz    1b
+       sync
+       isync
+
+       /* Disable / invalidate / enable L1 data */
+       mfspr   r3,SPRN_HID0
+       rlwinm  r3,r3,0,~(HID0_DCE | HID0_ICE)
+       mtspr   SPRN_HID0,r3
+       sync
+       isync
+       ori     r3,r3,(HID0_DCE|HID0_DCI|HID0_ICE|HID0_ICFI)
+       sync
+       isync
+       mtspr   SPRN_HID0,r3
+       xori    r3,r3,(HID0_DCI|HID0_ICFI)
+       mtspr   SPRN_HID0,r3
+       sync
+
+       /* Get the current enable bit of the L2CR into r4 */
+       mfspr   r5,SPRN_L2CR
+       /* Set to data-only (pre-745x bit) */
+       oris    r3,r5,L2CR_L2DO@h
+       b       2f
+       /* When disabling L2, code must be in L1 */
+       .balign 32
+1:     mtspr   SPRN_L2CR,r3
+3:     sync
+       isync
+       b       1f
+2:     b       3f
+3:     sync
+       isync
+       b       1b
+1:     /* disp-flush L2. The interesting thing here is that the L2 can be
+        * up to 2Mb ... so using the ROM, we'll end up wrapping back to memory
+        * but that is probbaly fine. We disp-flush over 4Mb to be safe
+        */
+       lis     r4,2
+       mtctr   r4
+       lis     r4,0xfff0
+1:     lwz     r0,0(r4)
+       addi    r4,r4,32
+       bdnz    1b
+       sync
+       isync
+       lis     r4,2
+       mtctr   r4
+       lis     r4,0xfff0
+1:     dcbf    0,r4
+       addi    r4,r4,32
+       bdnz    1b
+       sync
+       isync
+
+       /* now disable L2 */
+       rlwinm  r5,r5,0,~L2CR_L2E
+       b       2f
+       /* When disabling L2, code must be in L1 */
+       .balign 32
+1:     mtspr   SPRN_L2CR,r5
+3:     sync
+       isync
+       b       1f
+2:     b       3f
+3:     sync
+       isync
+       b       1b
+1:     sync
+       isync
+       /* Invalidate L2. This is pre-745x, we clear the L2I bit ourselves */
+       oris    r4,r5,L2CR_L2I@h
+       mtspr   SPRN_L2CR,r4
+       sync
+       isync
+
+       /* Wait for the invalidation to complete */
+1:     mfspr   r3,SPRN_L2CR
+       rlwinm. r0,r3,0,31,31
+       bne     1b
+
+       /* Clear L2I */
+       xoris   r4,r4,L2CR_L2I@h
+       sync
+       mtspr   SPRN_L2CR,r4
+       sync
+
+       /* now disable the L1 data cache */
+       mfspr   r0,SPRN_HID0
+       rlwinm  r0,r0,0,~(HID0_DCE|HID0_ICE)
+       mtspr   SPRN_HID0,r0
+       sync
+       isync
+
+       /* Restore HID0[DPM] to whatever it was before */
+       sync
+       mfspr   r0,SPRN_HID0
+       rlwimi  r0,r8,0,11,11           /* Turn back HID0[DPM] */
+       mtspr   SPRN_HID0,r0
+       sync
+
+       /* restore DR and EE */
+       sync
+       mtmsr   r11
+       isync
+
+       mtlr    r10
+       blr
+
+/* This code is for 745x processors */
+flush_disable_745x:
+       /* Turn off EE and DR in MSR */
+       mfmsr   r11
+       rlwinm  r0,r11,0,~MSR_EE
+       rlwinm  r0,r0,0,~MSR_DR
+       sync
+       mtmsr   r0
+       isync
+
+       /* Stop prefetch streams */
+       DSSALL
+       sync
+
+       /* Disable L2 prefetching */
+       mfspr   r0,SPRN_MSSCR0
+       rlwinm  r0,r0,0,0,29
+       mtspr   SPRN_MSSCR0,r0
+       sync
+       isync
+       lis     r4,0
+       dcbf    0,r4
+       dcbf    0,r4
+       dcbf    0,r4
+       dcbf    0,r4
+       dcbf    0,r4
+       dcbf    0,r4
+       dcbf    0,r4
+       dcbf    0,r4
+
+       /* Due to a bug with the HW flush on some CPU revs, we occasionally
+        * experience data corruption. I'm adding a displacement flush along
+        * with a dcbf loop over a few Mb to "help". The problem isn't totally
+        * fixed by this in theory, but at least, in practice, I couldn't reproduce
+        * it even with a big hammer...
+        */
+
+        lis     r4,0x0002
+        mtctr   r4
+       li      r4,0
+1:
+        lwz     r0,0(r4)
+        addi    r4,r4,32                /* Go to start of next cache line */
+        bdnz    1b
+        isync
+
+        /* Now, flush the first 4MB of memory */
+        lis     r4,0x0002
+        mtctr   r4
+       li      r4,0
+        sync
+1:
+        dcbf    0,r4
+        addi    r4,r4,32                /* Go to start of next cache line */
+        bdnz    1b
+
+       /* Flush and disable the L1 data cache */
+       mfspr   r6,SPRN_LDSTCR
+       lis     r3,0xfff0       /* read from ROM for displacement flush */
+       li      r4,0xfe         /* start with only way 0 unlocked */
+       li      r5,128          /* 128 lines in each way */
+1:     mtctr   r5
+       rlwimi  r6,r4,0,24,31
+       mtspr   SPRN_LDSTCR,r6
+       sync
+       isync
+2:     lwz     r0,0(r3)        /* touch each cache line */
+       addi    r3,r3,32
+       bdnz    2b
+       rlwinm  r4,r4,1,24,30   /* move on to the next way */
+       ori     r4,r4,1
+       cmpwi   r4,0xff         /* all done? */
+       bne     1b
+       /* now unlock the L1 data cache */
+       li      r4,0
+       rlwimi  r6,r4,0,24,31
+       sync
+       mtspr   SPRN_LDSTCR,r6
+       sync
+       isync
+
+       /* Flush the L2 cache using the hardware assist */
+       mfspr   r3,SPRN_L2CR
+       cmpwi   r3,0            /* check if it is enabled first */
+       bge     4f
+       oris    r0,r3,(L2CR_L2IO_745x|L2CR_L2DO_745x)@h
+       b       2f
+       /* When disabling/locking L2, code must be in L1 */
+       .balign 32
+1:     mtspr   SPRN_L2CR,r0    /* lock the L2 cache */
+3:     sync
+       isync
+       b       1f
+2:     b       3f
+3:     sync
+       isync
+       b       1b
+1:     sync
+       isync
+       ori     r0,r3,L2CR_L2HWF_745x
+       sync
+       mtspr   SPRN_L2CR,r0    /* set the hardware flush bit */
+3:     mfspr   r0,SPRN_L2CR    /* wait for it to go to 0 */
+       andi.   r0,r0,L2CR_L2HWF_745x
+       bne     3b
+       sync
+       rlwinm  r3,r3,0,~L2CR_L2E
+       b       2f
+       /* When disabling L2, code must be in L1 */
+       .balign 32
+1:     mtspr   SPRN_L2CR,r3    /* disable the L2 cache */
+3:     sync
+       isync
+       b       1f
+2:     b       3f
+3:     sync
+       isync
+       b       1b
+1:     sync
+       isync
+       oris    r4,r3,L2CR_L2I@h
+       mtspr   SPRN_L2CR,r4
+       sync
+       isync
+1:     mfspr   r4,SPRN_L2CR
+       andis.  r0,r4,L2CR_L2I@h
+       bne     1b
+       sync
+
+BEGIN_FTR_SECTION
+       /* Flush the L3 cache using the hardware assist */
+4:     mfspr   r3,SPRN_L3CR
+       cmpwi   r3,0            /* check if it is enabled */
+       bge     6f
+       oris    r0,r3,L3CR_L3IO@h
+       ori     r0,r0,L3CR_L3DO
+       sync
+       mtspr   SPRN_L3CR,r0    /* lock the L3 cache */
+       sync
+       isync
+       ori     r0,r0,L3CR_L3HWF
+       sync
+       mtspr   SPRN_L3CR,r0    /* set the hardware flush bit */
+5:     mfspr   r0,SPRN_L3CR    /* wait for it to go to zero */
+       andi.   r0,r0,L3CR_L3HWF
+       bne     5b
+       rlwinm  r3,r3,0,~L3CR_L3E
+       sync
+       mtspr   SPRN_L3CR,r3    /* disable the L3 cache */
+       sync
+       ori     r4,r3,L3CR_L3I
+       mtspr   SPRN_L3CR,r4
+1:     mfspr   r4,SPRN_L3CR
+       andi.   r0,r4,L3CR_L3I
+       bne     1b
+       sync
+END_FTR_SECTION_IFSET(CPU_FTR_L3CR)
+
+6:     mfspr   r0,SPRN_HID0    /* now disable the L1 data cache */
+       rlwinm  r0,r0,0,~HID0_DCE
+       mtspr   SPRN_HID0,r0
+       sync
+       isync
+       mtmsr   r11             /* restore DR and EE */
+       isync
+       blr
+#endif /* CONFIG_6xx */
diff --git a/arch/powerpc/platforms/powermac/cpufreq.c b/arch/powerpc/platforms/powermac/cpufreq.c
new file mode 100644 (file)
index 0000000..6d32d99
--- /dev/null
@@ -0,0 +1,728 @@
+/*
+ *  arch/ppc/platforms/pmac_cpufreq.c
+ *
+ *  Copyright (C) 2002 - 2005 Benjamin Herrenschmidt <benh@kernel.crashing.org>
+ *  Copyright (C) 2004        John Steele Scott <toojays@toojays.net>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * TODO: Need a big cleanup here. Basically, we need to have different
+ * cpufreq_driver structures for the different type of HW instead of the
+ * current mess. We also need to better deal with the detection of the
+ * type of machine.
+ *
+ */
+
+#include <linux/config.h>
+#include <linux/module.h>
+#include <linux/types.h>
+#include <linux/errno.h>
+#include <linux/kernel.h>
+#include <linux/delay.h>
+#include <linux/sched.h>
+#include <linux/adb.h>
+#include <linux/pmu.h>
+#include <linux/slab.h>
+#include <linux/cpufreq.h>
+#include <linux/init.h>
+#include <linux/sysdev.h>
+#include <linux/i2c.h>
+#include <linux/hardirq.h>
+#include <asm/prom.h>
+#include <asm/machdep.h>
+#include <asm/irq.h>
+#include <asm/pmac_feature.h>
+#include <asm/mmu_context.h>
+#include <asm/sections.h>
+#include <asm/cputable.h>
+#include <asm/time.h>
+#include <asm/system.h>
+#include <asm/mpic.h>
+#include <asm/keylargo.h>
+
+/* WARNING !!! This will cause calibrate_delay() to be called,
+ * but this is an __init function ! So you MUST go edit
+ * init/main.c to make it non-init before enabling DEBUG_FREQ
+ */
+#undef DEBUG_FREQ
+
+/*
+ * There is a problem with the core cpufreq code on SMP kernels,
+ * it won't recalculate the Bogomips properly
+ */
+#ifdef CONFIG_SMP
+#warning "WARNING, CPUFREQ not recommended on SMP kernels"
+#endif
+
+extern void low_choose_7447a_dfs(int dfs);
+extern void low_choose_750fx_pll(int pll);
+extern void low_sleep_handler(void);
+
+/*
+ * Currently, PowerMac cpufreq supports only high & low frequencies
+ * that are set by the firmware
+ */
+static unsigned int low_freq;
+static unsigned int hi_freq;
+static unsigned int cur_freq;
+static unsigned int sleep_freq;
+
+/*
+ * Different models uses different mecanisms to switch the frequency
+ */
+static int (*set_speed_proc)(int low_speed);
+static unsigned int (*get_speed_proc)(void);
+
+/*
+ * Some definitions used by the various speedprocs
+ */
+static u32 voltage_gpio;
+static u32 frequency_gpio;
+static u32 slew_done_gpio;
+static int no_schedule;
+static int has_cpu_l2lve;
+static int is_pmu_based;
+
+/* There are only two frequency states for each processor. Values
+ * are in kHz for the time being.
+ */
+#define CPUFREQ_HIGH                  0
+#define CPUFREQ_LOW                   1
+
+static struct cpufreq_frequency_table pmac_cpu_freqs[] = {
+       {CPUFREQ_HIGH,          0},
+       {CPUFREQ_LOW,           0},
+       {0,                     CPUFREQ_TABLE_END},
+};
+
+static struct freq_attr* pmac_cpu_freqs_attr[] = {
+       &cpufreq_freq_attr_scaling_available_freqs,
+       NULL,
+};
+
+static inline void local_delay(unsigned long ms)
+{
+       if (no_schedule)
+               mdelay(ms);
+       else
+               msleep(ms);
+}
+
+static inline void wakeup_decrementer(void)
+{
+       set_dec(tb_ticks_per_jiffy);
+       /* No currently-supported powerbook has a 601,
+        * so use get_tbl, not native
+        */
+       last_jiffy_stamp(0) = tb_last_stamp = get_tbl();
+}
+
+#ifdef DEBUG_FREQ
+static inline void debug_calc_bogomips(void)
+{
+       /* This will cause a recalc of bogomips and display the
+        * result. We backup/restore the value to avoid affecting the
+        * core cpufreq framework's own calculation.
+        */
+       extern void calibrate_delay(void);
+
+       unsigned long save_lpj = loops_per_jiffy;
+       calibrate_delay();
+       loops_per_jiffy = save_lpj;
+}
+#endif /* DEBUG_FREQ */
+
+/* Switch CPU speed under 750FX CPU control
+ */
+static int cpu_750fx_cpu_speed(int low_speed)
+{
+       u32 hid2;
+
+       if (low_speed == 0) {
+               /* ramping up, set voltage first */
+               pmac_call_feature(PMAC_FTR_WRITE_GPIO, NULL, voltage_gpio, 0x05);
+               /* Make sure we sleep for at least 1ms */
+               local_delay(10);
+
+               /* tweak L2 for high voltage */
+               if (has_cpu_l2lve) {
+                       hid2 = mfspr(SPRN_HID2);
+                       hid2 &= ~0x2000;
+                       mtspr(SPRN_HID2, hid2);
+               }
+       }
+#ifdef CONFIG_6xx
+       low_choose_750fx_pll(low_speed);
+#endif
+       if (low_speed == 1) {
+               /* tweak L2 for low voltage */
+               if (has_cpu_l2lve) {
+                       hid2 = mfspr(SPRN_HID2);
+                       hid2 |= 0x2000;
+                       mtspr(SPRN_HID2, hid2);
+               }
+
+               /* ramping down, set voltage last */
+               pmac_call_feature(PMAC_FTR_WRITE_GPIO, NULL, voltage_gpio, 0x04);
+               local_delay(10);
+       }
+
+       return 0;
+}
+
+static unsigned int cpu_750fx_get_cpu_speed(void)
+{
+       if (mfspr(SPRN_HID1) & HID1_PS)
+               return low_freq;
+       else
+               return hi_freq;
+}
+
+/* Switch CPU speed using DFS */
+static int dfs_set_cpu_speed(int low_speed)
+{
+       if (low_speed == 0) {
+               /* ramping up, set voltage first */
+               pmac_call_feature(PMAC_FTR_WRITE_GPIO, NULL, voltage_gpio, 0x05);
+               /* Make sure we sleep for at least 1ms */
+               local_delay(1);
+       }
+
+       /* set frequency */
+#ifdef CONFIG_6xx
+       low_choose_7447a_dfs(low_speed);
+#endif
+       udelay(100);
+
+       if (low_speed == 1) {
+               /* ramping down, set voltage last */
+               pmac_call_feature(PMAC_FTR_WRITE_GPIO, NULL, voltage_gpio, 0x04);
+               local_delay(1);
+       }
+
+       return 0;
+}
+
+static unsigned int dfs_get_cpu_speed(void)
+{
+       if (mfspr(SPRN_HID1) & HID1_DFS)
+               return low_freq;
+       else
+               return hi_freq;
+}
+
+
+/* Switch CPU speed using slewing GPIOs
+ */
+static int gpios_set_cpu_speed(int low_speed)
+{
+       int gpio, timeout = 0;
+
+       /* If ramping up, set voltage first */
+       if (low_speed == 0) {
+               pmac_call_feature(PMAC_FTR_WRITE_GPIO, NULL, voltage_gpio, 0x05);
+               /* Delay is way too big but it's ok, we schedule */
+               local_delay(10);
+       }
+
+       /* Set frequency */
+       gpio =  pmac_call_feature(PMAC_FTR_READ_GPIO, NULL, frequency_gpio, 0);
+       if (low_speed == ((gpio & 0x01) == 0))
+               goto skip;
+
+       pmac_call_feature(PMAC_FTR_WRITE_GPIO, NULL, frequency_gpio,
+                         low_speed ? 0x04 : 0x05);
+       udelay(200);
+       do {
+               if (++timeout > 100)
+                       break;
+               local_delay(1);
+               gpio = pmac_call_feature(PMAC_FTR_READ_GPIO, NULL, slew_done_gpio, 0);
+       } while((gpio & 0x02) == 0);
+ skip:
+       /* If ramping down, set voltage last */
+       if (low_speed == 1) {
+               pmac_call_feature(PMAC_FTR_WRITE_GPIO, NULL, voltage_gpio, 0x04);
+               /* Delay is way too big but it's ok, we schedule */
+               local_delay(10);
+       }
+
+#ifdef DEBUG_FREQ
+       debug_calc_bogomips();
+#endif
+
+       return 0;
+}
+
+/* Switch CPU speed under PMU control
+ */
+static int pmu_set_cpu_speed(int low_speed)
+{
+       struct adb_request req;
+       unsigned long save_l2cr;
+       unsigned long save_l3cr;
+       unsigned int pic_prio;
+       unsigned long flags;
+
+       preempt_disable();
+
+#ifdef DEBUG_FREQ
+       printk(KERN_DEBUG "HID1, before: %x\n", mfspr(SPRN_HID1));
+#endif
+       pmu_suspend();
+
+       /* Disable all interrupt sources on openpic */
+       pic_prio = mpic_cpu_get_priority();
+       mpic_cpu_set_priority(0xf);
+
+       /* Make sure the decrementer won't interrupt us */
+       asm volatile("mtdec %0" : : "r" (0x7fffffff));
+       /* Make sure any pending DEC interrupt occuring while we did
+        * the above didn't re-enable the DEC */
+       mb();
+       asm volatile("mtdec %0" : : "r" (0x7fffffff));
+
+       /* We can now disable MSR_EE */
+       local_irq_save(flags);
+
+       /* Giveup the FPU & vec */
+       enable_kernel_fp();
+
+#ifdef CONFIG_ALTIVEC
+       if (cpu_has_feature(CPU_FTR_ALTIVEC))
+               enable_kernel_altivec();
+#endif /* CONFIG_ALTIVEC */
+
+       /* Save & disable L2 and L3 caches */
+       save_l3cr = _get_L3CR();        /* (returns -1 if not available) */
+       save_l2cr = _get_L2CR();        /* (returns -1 if not available) */
+
+       /* Send the new speed command. My assumption is that this command
+        * will cause PLL_CFG[0..3] to be changed next time CPU goes to sleep
+        */
+       pmu_request(&req, NULL, 6, PMU_CPU_SPEED, 'W', 'O', 'O', 'F', low_speed);
+       while (!req.complete)
+               pmu_poll();
+
+       /* Prepare the northbridge for the speed transition */
+       pmac_call_feature(PMAC_FTR_SLEEP_STATE,NULL,1,1);
+
+       /* Call low level code to backup CPU state and recover from
+        * hardware reset
+        */
+       low_sleep_handler();
+
+       /* Restore the northbridge */
+       pmac_call_feature(PMAC_FTR_SLEEP_STATE,NULL,1,0);
+
+       /* Restore L2 cache */
+       if (save_l2cr != 0xffffffff && (save_l2cr & L2CR_L2E) != 0)
+               _set_L2CR(save_l2cr);
+       /* Restore L3 cache */
+       if (save_l3cr != 0xffffffff && (save_l3cr & L3CR_L3E) != 0)
+               _set_L3CR(save_l3cr);
+
+       /* Restore userland MMU context */
+       set_context(current->active_mm->context, current->active_mm->pgd);
+
+#ifdef DEBUG_FREQ
+       printk(KERN_DEBUG "HID1, after: %x\n", mfspr(SPRN_HID1));
+#endif
+
+       /* Restore low level PMU operations */
+       pmu_unlock();
+
+       /* Restore decrementer */
+       wakeup_decrementer();
+
+       /* Restore interrupts */
+       mpic_cpu_set_priority(pic_prio);
+
+       /* Let interrupts flow again ... */
+       local_irq_restore(flags);
+
+#ifdef DEBUG_FREQ
+       debug_calc_bogomips();
+#endif
+
+       pmu_resume();
+
+       preempt_enable();
+
+       return 0;
+}
+
+static int do_set_cpu_speed(int speed_mode, int notify)
+{
+       struct cpufreq_freqs freqs;
+       unsigned long l3cr;
+       static unsigned long prev_l3cr;
+
+       freqs.old = cur_freq;
+       freqs.new = (speed_mode == CPUFREQ_HIGH) ? hi_freq : low_freq;
+       freqs.cpu = smp_processor_id();
+
+       if (freqs.old == freqs.new)
+               return 0;
+
+       if (notify)
+               cpufreq_notify_transition(&freqs, CPUFREQ_PRECHANGE);
+       if (speed_mode == CPUFREQ_LOW &&
+           cpu_has_feature(CPU_FTR_L3CR)) {
+               l3cr = _get_L3CR();
+               if (l3cr & L3CR_L3E) {
+                       prev_l3cr = l3cr;
+                       _set_L3CR(0);
+               }
+       }
+       set_speed_proc(speed_mode == CPUFREQ_LOW);
+       if (speed_mode == CPUFREQ_HIGH &&
+           cpu_has_feature(CPU_FTR_L3CR)) {
+               l3cr = _get_L3CR();
+               if ((prev_l3cr & L3CR_L3E) && l3cr != prev_l3cr)
+                       _set_L3CR(prev_l3cr);
+       }
+       if (notify)
+               cpufreq_notify_transition(&freqs, CPUFREQ_POSTCHANGE);
+       cur_freq = (speed_mode == CPUFREQ_HIGH) ? hi_freq : low_freq;
+
+       return 0;
+}
+
+static unsigned int pmac_cpufreq_get_speed(unsigned int cpu)
+{
+       return cur_freq;
+}
+
+static int pmac_cpufreq_verify(struct cpufreq_policy *policy)
+{
+       return cpufreq_frequency_table_verify(policy, pmac_cpu_freqs);
+}
+
+static int pmac_cpufreq_target(        struct cpufreq_policy *policy,
+                                       unsigned int target_freq,
+                                       unsigned int relation)
+{
+       unsigned int    newstate = 0;
+
+       if (cpufreq_frequency_table_target(policy, pmac_cpu_freqs,
+                       target_freq, relation, &newstate))
+               return -EINVAL;
+
+       return do_set_cpu_speed(newstate, 1);
+}
+
+unsigned int pmac_get_one_cpufreq(int i)
+{
+       /* Supports only one CPU for now */
+       return (i == 0) ? cur_freq : 0;
+}
+
+static int pmac_cpufreq_cpu_init(struct cpufreq_policy *policy)
+{
+       if (policy->cpu != 0)
+               return -ENODEV;
+
+       policy->governor = CPUFREQ_DEFAULT_GOVERNOR;
+       policy->cpuinfo.transition_latency      = CPUFREQ_ETERNAL;
+       policy->cur = cur_freq;
+
+       cpufreq_frequency_table_get_attr(pmac_cpu_freqs, policy->cpu);
+       return cpufreq_frequency_table_cpuinfo(policy, pmac_cpu_freqs);
+}
+
+static u32 read_gpio(struct device_node *np)
+{
+       u32 *reg = (u32 *)get_property(np, "reg", NULL);
+       u32 offset;
+
+       if (reg == NULL)
+               return 0;
+       /* That works for all keylargos but shall be fixed properly
+        * some day... The problem is that it seems we can't rely
+        * on the "reg" property of the GPIO nodes, they are either
+        * relative to the base of KeyLargo or to the base of the
+        * GPIO space, and the device-tree doesn't help.
+        */
+       offset = *reg;
+       if (offset < KEYLARGO_GPIO_LEVELS0)
+               offset += KEYLARGO_GPIO_LEVELS0;
+       return offset;
+}
+
+static int pmac_cpufreq_suspend(struct cpufreq_policy *policy, pm_message_t pmsg)
+{
+       /* Ok, this could be made a bit smarter, but let's be robust for now. We
+        * always force a speed change to high speed before sleep, to make sure
+        * we have appropriate voltage and/or bus speed for the wakeup process,
+        * and to make sure our loops_per_jiffies are "good enough", that is will
+        * not cause too short delays if we sleep in low speed and wake in high
+        * speed..
+        */
+       no_schedule = 1;
+       sleep_freq = cur_freq;
+       if (cur_freq == low_freq && !is_pmu_based)
+               do_set_cpu_speed(CPUFREQ_HIGH, 0);
+       return 0;
+}
+
+static int pmac_cpufreq_resume(struct cpufreq_policy *policy)
+{
+       /* If we resume, first check if we have a get() function */
+       if (get_speed_proc)
+               cur_freq = get_speed_proc();
+       else
+               cur_freq = 0;
+
+       /* We don't, hrm... we don't really know our speed here, best
+        * is that we force a switch to whatever it was, which is
+        * probably high speed due to our suspend() routine
+        */
+       do_set_cpu_speed(sleep_freq == low_freq ?
+                        CPUFREQ_LOW : CPUFREQ_HIGH, 0);
+
+       no_schedule = 0;
+       return 0;
+}
+
+static struct cpufreq_driver pmac_cpufreq_driver = {
+       .verify         = pmac_cpufreq_verify,
+       .target         = pmac_cpufreq_target,
+       .get            = pmac_cpufreq_get_speed,
+       .init           = pmac_cpufreq_cpu_init,
+       .suspend        = pmac_cpufreq_suspend,
+       .resume         = pmac_cpufreq_resume,
+       .flags          = CPUFREQ_PM_NO_WARN,
+       .attr           = pmac_cpu_freqs_attr,
+       .name           = "powermac",
+       .owner          = THIS_MODULE,
+};
+
+
+static int pmac_cpufreq_init_MacRISC3(struct device_node *cpunode)
+{
+       struct device_node *volt_gpio_np = of_find_node_by_name(NULL,
+                                                               "voltage-gpio");
+       struct device_node *freq_gpio_np = of_find_node_by_name(NULL,
+                                                               "frequency-gpio");
+       struct device_node *slew_done_gpio_np = of_find_node_by_name(NULL,
+                                                                    "slewing-done");
+       u32 *value;
+
+       /*
+        * Check to see if it's GPIO driven or PMU only
+        *
+        * The way we extract the GPIO address is slightly hackish, but it
+        * works well enough for now. We need to abstract the whole GPIO
+        * stuff sooner or later anyway
+        */
+
+       if (volt_gpio_np)
+               voltage_gpio = read_gpio(volt_gpio_np);
+       if (freq_gpio_np)
+               frequency_gpio = read_gpio(freq_gpio_np);
+       if (slew_done_gpio_np)
+               slew_done_gpio = read_gpio(slew_done_gpio_np);
+
+       /* If we use the frequency GPIOs, calculate the min/max speeds based
+        * on the bus frequencies
+        */
+       if (frequency_gpio && slew_done_gpio) {
+               int lenp, rc;
+               u32 *freqs, *ratio;
+
+               freqs = (u32 *)get_property(cpunode, "bus-frequencies", &lenp);
+               lenp /= sizeof(u32);
+               if (freqs == NULL || lenp != 2) {
+                       printk(KERN_ERR "cpufreq: bus-frequencies incorrect or missing\n");
+                       return 1;
+               }
+               ratio = (u32 *)get_property(cpunode, "processor-to-bus-ratio*2", NULL);
+               if (ratio == NULL) {
+                       printk(KERN_ERR "cpufreq: processor-to-bus-ratio*2 missing\n");
+                       return 1;
+               }
+
+               /* Get the min/max bus frequencies */
+               low_freq = min(freqs[0], freqs[1]);
+               hi_freq = max(freqs[0], freqs[1]);
+
+               /* Grrrr.. It _seems_ that the device-tree is lying on the low bus
+                * frequency, it claims it to be around 84Mhz on some models while
+                * it appears to be approx. 101Mhz on all. Let's hack around here...
+                * fortunately, we don't need to be too precise
+                */
+               if (low_freq < 98000000)
+                       low_freq = 101000000;
+                       
+               /* Convert those to CPU core clocks */
+               low_freq = (low_freq * (*ratio)) / 2000;
+               hi_freq = (hi_freq * (*ratio)) / 2000;
+
+               /* Now we get the frequencies, we read the GPIO to see what is out current
+                * speed
+                */
+               rc = pmac_call_feature(PMAC_FTR_READ_GPIO, NULL, frequency_gpio, 0);
+               cur_freq = (rc & 0x01) ? hi_freq : low_freq;
+
+               set_speed_proc = gpios_set_cpu_speed;
+               return 1;
+       }
+
+       /* If we use the PMU, look for the min & max frequencies in the
+        * device-tree
+        */
+       value = (u32 *)get_property(cpunode, "min-clock-frequency", NULL);
+       if (!value)
+               return 1;
+       low_freq = (*value) / 1000;
+       /* The PowerBook G4 12" (PowerBook6,1) has an error in the device-tree
+        * here */
+       if (low_freq < 100000)
+               low_freq *= 10;
+
+       value = (u32 *)get_property(cpunode, "max-clock-frequency", NULL);
+       if (!value)
+               return 1;
+       hi_freq = (*value) / 1000;
+       set_speed_proc = pmu_set_cpu_speed;
+       is_pmu_based = 1;
+
+       return 0;
+}
+
+static int pmac_cpufreq_init_7447A(struct device_node *cpunode)
+{
+       struct device_node *volt_gpio_np;
+
+       if (get_property(cpunode, "dynamic-power-step", NULL) == NULL)
+               return 1;
+
+       volt_gpio_np = of_find_node_by_name(NULL, "cpu-vcore-select");
+       if (volt_gpio_np)
+               voltage_gpio = read_gpio(volt_gpio_np);
+       if (!voltage_gpio){
+               printk(KERN_ERR "cpufreq: missing cpu-vcore-select gpio\n");
+               return 1;
+       }
+
+       /* OF only reports the high frequency */
+       hi_freq = cur_freq;
+       low_freq = cur_freq/2;
+
+       /* Read actual frequency from CPU */
+       cur_freq = dfs_get_cpu_speed();
+       set_speed_proc = dfs_set_cpu_speed;
+       get_speed_proc = dfs_get_cpu_speed;
+
+       return 0;
+}
+
+static int pmac_cpufreq_init_750FX(struct device_node *cpunode)
+{
+       struct device_node *volt_gpio_np;
+       u32 pvr, *value;
+
+       if (get_property(cpunode, "dynamic-power-step", NULL) == NULL)
+               return 1;
+
+       hi_freq = cur_freq;
+       value = (u32 *)get_property(cpunode, "reduced-clock-frequency", NULL);
+       if (!value)
+               return 1;
+       low_freq = (*value) / 1000;
+
+       volt_gpio_np = of_find_node_by_name(NULL, "cpu-vcore-select");
+       if (volt_gpio_np)
+               voltage_gpio = read_gpio(volt_gpio_np);
+
+       pvr = mfspr(SPRN_PVR);
+       has_cpu_l2lve = !((pvr & 0xf00) == 0x100);
+
+       set_speed_proc = cpu_750fx_cpu_speed;
+       get_speed_proc = cpu_750fx_get_cpu_speed;
+       cur_freq = cpu_750fx_get_cpu_speed();
+
+       return 0;
+}
+
+/* Currently, we support the following machines:
+ *
+ *  - Titanium PowerBook 1Ghz (PMU based, 667Mhz & 1Ghz)
+ *  - Titanium PowerBook 800 (PMU based, 667Mhz & 800Mhz)
+ *  - Titanium PowerBook 400 (PMU based, 300Mhz & 400Mhz)
+ *  - Titanium PowerBook 500 (PMU based, 300Mhz & 500Mhz)
+ *  - iBook2 500/600 (PMU based, 400Mhz & 500/600Mhz)
+ *  - iBook2 700 (CPU based, 400Mhz & 700Mhz, support low voltage)
+ *  - Recent MacRISC3 laptops
+ *  - All new machines with 7447A CPUs
+ */
+static int __init pmac_cpufreq_setup(void)
+{
+       struct device_node      *cpunode;
+       u32                     *value;
+
+       if (strstr(cmd_line, "nocpufreq"))
+               return 0;
+
+       /* Assume only one CPU */
+       cpunode = find_type_devices("cpu");
+       if (!cpunode)
+               goto out;
+
+       /* Get current cpu clock freq */
+       value = (u32 *)get_property(cpunode, "clock-frequency", NULL);
+       if (!value)
+               goto out;
+       cur_freq = (*value) / 1000;
+
+       /*  Check for 7447A based MacRISC3 */
+       if (machine_is_compatible("MacRISC3") &&
+           get_property(cpunode, "dynamic-power-step", NULL) &&
+           PVR_VER(mfspr(SPRN_PVR)) == 0x8003) {
+               pmac_cpufreq_init_7447A(cpunode);
+       /* Check for other MacRISC3 machines */
+       } else if (machine_is_compatible("PowerBook3,4") ||
+                  machine_is_compatible("PowerBook3,5") ||
+                  machine_is_compatible("MacRISC3")) {
+               pmac_cpufreq_init_MacRISC3(cpunode);
+       /* Else check for iBook2 500/600 */
+       } else if (machine_is_compatible("PowerBook4,1")) {
+               hi_freq = cur_freq;
+               low_freq = 400000;
+               set_speed_proc = pmu_set_cpu_speed;
+               is_pmu_based = 1;
+       }
+       /* Else check for TiPb 400 & 500 */
+       else if (machine_is_compatible("PowerBook3,2")) {
+               /* We only know about the 400 MHz and the 500Mhz model
+                * they both have 300 MHz as low frequency
+                */
+               if (cur_freq < 350000 || cur_freq > 550000)
+                       goto out;
+               hi_freq = cur_freq;
+               low_freq = 300000;
+               set_speed_proc = pmu_set_cpu_speed;
+               is_pmu_based = 1;
+       }
+       /* Else check for 750FX */
+       else if (PVR_VER(mfspr(SPRN_PVR)) == 0x7000)
+               pmac_cpufreq_init_750FX(cpunode);
+out:
+       if (set_speed_proc == NULL)
+               return -ENODEV;
+
+       pmac_cpu_freqs[CPUFREQ_LOW].frequency = low_freq;
+       pmac_cpu_freqs[CPUFREQ_HIGH].frequency = hi_freq;
+
+       printk(KERN_INFO "Registering PowerMac CPU frequency driver\n");
+       printk(KERN_INFO "Low: %d Mhz, High: %d Mhz, Boot: %d Mhz\n",
+              low_freq/1000, hi_freq/1000, cur_freq/1000);
+
+       return cpufreq_register_driver(&pmac_cpufreq_driver);
+}
+
+module_init(pmac_cpufreq_setup);
+
diff --git a/arch/powerpc/platforms/powermac/feature.c b/arch/powerpc/platforms/powermac/feature.c
new file mode 100644 (file)
index 0000000..2cba670
--- /dev/null
@@ -0,0 +1,3062 @@
+/*
+ *  arch/ppc/platforms/pmac_feature.c
+ *
+ *  Copyright (C) 1996-2001 Paul Mackerras (paulus@cs.anu.edu.au)
+ *                          Ben. Herrenschmidt (benh@kernel.crashing.org)
+ *
+ *  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.
+ *
+ *  TODO:
+ *
+ *   - Replace mdelay with some schedule loop if possible
+ *   - Shorten some obfuscated delays on some routines (like modem
+ *     power)
+ *   - Refcount some clocks (see darwin)
+ *   - Split split split...
+ *
+ */
+#include <linux/config.h>
+#include <linux/types.h>
+#include <linux/init.h>
+#include <linux/delay.h>
+#include <linux/kernel.h>
+#include <linux/sched.h>
+#include <linux/spinlock.h>
+#include <linux/adb.h>
+#include <linux/pmu.h>
+#include <linux/ioport.h>
+#include <linux/pci.h>
+#include <asm/sections.h>
+#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/machdep.h>
+#include <asm/pmac_feature.h>
+#include <asm/dbdma.h>
+#include <asm/pci-bridge.h>
+#include <asm/pmac_low_i2c.h>
+
+#undef DEBUG_FEATURE
+
+#ifdef DEBUG_FEATURE
+#define DBG(fmt...) printk(KERN_DEBUG fmt)
+#else
+#define DBG(fmt...)
+#endif
+
+#ifdef CONFIG_6xx
+extern int powersave_lowspeed;
+#endif
+
+extern int powersave_nap;
+extern struct device_node *k2_skiplist[2];
+
+
+/*
+ * We use a single global lock to protect accesses. Each driver has
+ * to take care of its own locking
+ */
+static DEFINE_SPINLOCK(feature_lock);
+
+#define LOCK(flags)    spin_lock_irqsave(&feature_lock, flags);
+#define UNLOCK(flags)  spin_unlock_irqrestore(&feature_lock, flags);
+
+
+/*
+ * Instance of some macio stuffs
+ */
+struct macio_chip macio_chips[MAX_MACIO_CHIPS];
+
+struct macio_chip *macio_find(struct device_node *child, int type)
+{
+       while(child) {
+               int     i;
+
+               for (i=0; i < MAX_MACIO_CHIPS && macio_chips[i].of_node; i++)
+                       if (child == macio_chips[i].of_node &&
+                           (!type || macio_chips[i].type == type))
+                               return &macio_chips[i];
+               child = child->parent;
+       }
+       return NULL;
+}
+EXPORT_SYMBOL_GPL(macio_find);
+
+static const char *macio_names[] =
+{
+       "Unknown",
+       "Grand Central",
+       "OHare",
+       "OHareII",
+       "Heathrow",
+       "Gatwick",
+       "Paddington",
+       "Keylargo",
+       "Pangea",
+       "Intrepid",
+       "K2"
+};
+
+
+
+/*
+ * Uninorth 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)))
+
+static struct device_node *uninorth_node;
+static u32 __iomem *uninorth_base;
+static u32 uninorth_rev;
+static int uninorth_u3;
+static void __iomem *u3_ht;
+
+/*
+ * For each motherboard family, we have a table of functions pointers
+ * that handle the various features.
+ */
+
+typedef long (*feature_call)(struct device_node *node, long param, long value);
+
+struct feature_table_entry {
+       unsigned int    selector;
+       feature_call    function;
+};
+
+struct pmac_mb_def
+{
+       const char*                     model_string;
+       const char*                     model_name;
+       int                             model_id;
+       struct feature_table_entry*     features;
+       unsigned long                   board_flags;
+};
+static struct pmac_mb_def pmac_mb;
+
+/*
+ * Here are the chip specific feature functions
+ */
+
+static inline int simple_feature_tweak(struct device_node *node, int type,
+                                      int reg, u32 mask, int value)
+{
+       struct macio_chip*      macio;
+       unsigned long           flags;
+
+       macio = macio_find(node, type);
+       if (!macio)
+               return -ENODEV;
+       LOCK(flags);
+       if (value)
+               MACIO_BIS(reg, mask);
+       else
+               MACIO_BIC(reg, mask);
+       (void)MACIO_IN32(reg);
+       UNLOCK(flags);
+
+       return 0;
+}
+
+#ifndef CONFIG_POWER4
+
+static long ohare_htw_scc_enable(struct device_node *node, long param,
+                                long value)
+{
+       struct macio_chip*      macio;
+       unsigned long           chan_mask;
+       unsigned long           fcr;
+       unsigned long           flags;
+       int                     htw, trans;
+       unsigned long           rmask;
+
+       macio = macio_find(node, 0);
+       if (!macio)
+               return -ENODEV;
+       if (!strcmp(node->name, "ch-a"))
+               chan_mask = MACIO_FLAG_SCCA_ON;
+       else if (!strcmp(node->name, "ch-b"))
+               chan_mask = MACIO_FLAG_SCCB_ON;
+       else
+               return -ENODEV;
+
+       htw = (macio->type == macio_heathrow || macio->type == macio_paddington
+               || macio->type == macio_gatwick);
+       /* On these machines, the HRW_SCC_TRANS_EN_N bit mustn't be touched */
+       trans = (pmac_mb.model_id != PMAC_TYPE_YOSEMITE &&
+                pmac_mb.model_id != PMAC_TYPE_YIKES);
+       if (value) {
+#ifdef CONFIG_ADB_PMU
+               if ((param & 0xfff) == PMAC_SCC_IRDA)
+                       pmu_enable_irled(1);
+#endif /* CONFIG_ADB_PMU */
+               LOCK(flags);
+               fcr = MACIO_IN32(OHARE_FCR);
+               /* Check if scc cell need enabling */
+               if (!(fcr & OH_SCC_ENABLE)) {
+                       fcr |= OH_SCC_ENABLE;
+                       if (htw) {
+                               /* Side effect: this will also power up the
+                                * modem, but it's too messy to figure out on which
+                                * ports this controls the tranceiver and on which
+                                * it controls the modem
+                                */
+                               if (trans)
+                                       fcr &= ~HRW_SCC_TRANS_EN_N;
+                               MACIO_OUT32(OHARE_FCR, fcr);
+                               fcr |= (rmask = HRW_RESET_SCC);
+                               MACIO_OUT32(OHARE_FCR, fcr);
+                       } else {
+                               fcr |= (rmask = OH_SCC_RESET);
+                               MACIO_OUT32(OHARE_FCR, fcr);
+                       }
+                       UNLOCK(flags);
+                       (void)MACIO_IN32(OHARE_FCR);
+                       mdelay(15);
+                       LOCK(flags);
+                       fcr &= ~rmask;
+                       MACIO_OUT32(OHARE_FCR, fcr);
+               }
+               if (chan_mask & MACIO_FLAG_SCCA_ON)
+                       fcr |= OH_SCCA_IO;
+               if (chan_mask & MACIO_FLAG_SCCB_ON)
+                       fcr |= OH_SCCB_IO;
+               MACIO_OUT32(OHARE_FCR, fcr);
+               macio->flags |= chan_mask;
+               UNLOCK(flags);
+               if (param & PMAC_SCC_FLAG_XMON)
+                       macio->flags |= MACIO_FLAG_SCC_LOCKED;
+       } else {
+               if (macio->flags & MACIO_FLAG_SCC_LOCKED)
+                       return -EPERM;
+               LOCK(flags);
+               fcr = MACIO_IN32(OHARE_FCR);
+               if (chan_mask & MACIO_FLAG_SCCA_ON)
+                       fcr &= ~OH_SCCA_IO;
+               if (chan_mask & MACIO_FLAG_SCCB_ON)
+                       fcr &= ~OH_SCCB_IO;
+               MACIO_OUT32(OHARE_FCR, fcr);
+               if ((fcr & (OH_SCCA_IO | OH_SCCB_IO)) == 0) {
+                       fcr &= ~OH_SCC_ENABLE;
+                       if (htw && trans)
+                               fcr |= HRW_SCC_TRANS_EN_N;
+                       MACIO_OUT32(OHARE_FCR, fcr);
+               }
+               macio->flags &= ~(chan_mask);
+               UNLOCK(flags);
+               mdelay(10);
+#ifdef CONFIG_ADB_PMU
+               if ((param & 0xfff) == PMAC_SCC_IRDA)
+                       pmu_enable_irled(0);
+#endif /* CONFIG_ADB_PMU */
+       }
+       return 0;
+}
+
+static long ohare_floppy_enable(struct device_node *node, long param,
+                               long value)
+{
+       return simple_feature_tweak(node, macio_ohare,
+               OHARE_FCR, OH_FLOPPY_ENABLE, value);
+}
+
+static long ohare_mesh_enable(struct device_node *node, long param, long value)
+{
+       return simple_feature_tweak(node, macio_ohare,
+               OHARE_FCR, OH_MESH_ENABLE, value);
+}
+
+static long ohare_ide_enable(struct device_node *node, long param, long value)
+{
+       switch(param) {
+       case 0:
+               /* For some reason, setting the bit in set_initial_features()
+                * doesn't stick. I'm still investigating... --BenH.
+                */
+               if (value)
+                       simple_feature_tweak(node, macio_ohare,
+                               OHARE_FCR, OH_IOBUS_ENABLE, 1);
+               return simple_feature_tweak(node, macio_ohare,
+                       OHARE_FCR, OH_IDE0_ENABLE, value);
+       case 1:
+               return simple_feature_tweak(node, macio_ohare,
+                       OHARE_FCR, OH_BAY_IDE_ENABLE, value);
+       default:
+               return -ENODEV;
+       }
+}
+
+static long ohare_ide_reset(struct device_node *node, long param, long value)
+{
+       switch(param) {
+       case 0:
+               return simple_feature_tweak(node, macio_ohare,
+                       OHARE_FCR, OH_IDE0_RESET_N, !value);
+       case 1:
+               return simple_feature_tweak(node, macio_ohare,
+                       OHARE_FCR, OH_IDE1_RESET_N, !value);
+       default:
+               return -ENODEV;
+       }
+}
+
+static long ohare_sleep_state(struct device_node *node, long param, long value)
+{
+       struct macio_chip*      macio = &macio_chips[0];
+
+       if ((pmac_mb.board_flags & PMAC_MB_CAN_SLEEP) == 0)
+               return -EPERM;
+       if (value == 1) {
+               MACIO_BIC(OHARE_FCR, OH_IOBUS_ENABLE);
+       } else if (value == 0) {
+               MACIO_BIS(OHARE_FCR, OH_IOBUS_ENABLE);
+       }
+
+       return 0;
+}
+
+static long heathrow_modem_enable(struct device_node *node, long param,
+                                 long value)
+{
+       struct macio_chip*      macio;
+       u8                      gpio;
+       unsigned long           flags;
+
+       macio = macio_find(node, macio_unknown);
+       if (!macio)
+               return -ENODEV;
+       gpio = MACIO_IN8(HRW_GPIO_MODEM_RESET) & ~1;
+       if (!value) {
+               LOCK(flags);
+               MACIO_OUT8(HRW_GPIO_MODEM_RESET, gpio);
+               UNLOCK(flags);
+               (void)MACIO_IN8(HRW_GPIO_MODEM_RESET);
+               mdelay(250);
+       }
+       if (pmac_mb.model_id != PMAC_TYPE_YOSEMITE &&
+           pmac_mb.model_id != PMAC_TYPE_YIKES) {
+               LOCK(flags);
+               if (value)
+                       MACIO_BIC(HEATHROW_FCR, HRW_SCC_TRANS_EN_N);
+               else
+                       MACIO_BIS(HEATHROW_FCR, HRW_SCC_TRANS_EN_N);
+               UNLOCK(flags);
+               (void)MACIO_IN32(HEATHROW_FCR);
+               mdelay(250);
+       }
+       if (value) {
+               LOCK(flags);
+               MACIO_OUT8(HRW_GPIO_MODEM_RESET, gpio | 1);
+               (void)MACIO_IN8(HRW_GPIO_MODEM_RESET);
+               UNLOCK(flags); mdelay(250); LOCK(flags);
+               MACIO_OUT8(HRW_GPIO_MODEM_RESET, gpio);
+               (void)MACIO_IN8(HRW_GPIO_MODEM_RESET);
+               UNLOCK(flags); mdelay(250); LOCK(flags);
+               MACIO_OUT8(HRW_GPIO_MODEM_RESET, gpio | 1);
+               (void)MACIO_IN8(HRW_GPIO_MODEM_RESET);
+               UNLOCK(flags); mdelay(250);
+       }
+       return 0;
+}
+
+static long heathrow_floppy_enable(struct device_node *node, long param,
+                                  long value)
+{
+       return simple_feature_tweak(node, macio_unknown,
+               HEATHROW_FCR,
+               HRW_SWIM_ENABLE|HRW_BAY_FLOPPY_ENABLE,
+               value);
+}
+
+static long heathrow_mesh_enable(struct device_node *node, long param,
+                                long value)
+{
+       struct macio_chip*      macio;
+       unsigned long           flags;
+
+       macio = macio_find(node, macio_unknown);
+       if (!macio)
+               return -ENODEV;
+       LOCK(flags);
+       /* Set clear mesh cell enable */
+       if (value)
+               MACIO_BIS(HEATHROW_FCR, HRW_MESH_ENABLE);
+       else
+               MACIO_BIC(HEATHROW_FCR, HRW_MESH_ENABLE);
+       (void)MACIO_IN32(HEATHROW_FCR);
+       udelay(10);
+       /* Set/Clear termination power */
+       if (value)
+               MACIO_BIC(HEATHROW_MBCR, 0x04000000);
+       else
+               MACIO_BIS(HEATHROW_MBCR, 0x04000000);
+       (void)MACIO_IN32(HEATHROW_MBCR);
+       udelay(10);
+       UNLOCK(flags);
+
+       return 0;
+}
+
+static long heathrow_ide_enable(struct device_node *node, long param,
+                               long value)
+{
+       switch(param) {
+       case 0:
+               return simple_feature_tweak(node, macio_unknown,
+                       HEATHROW_FCR, HRW_IDE0_ENABLE, value);
+       case 1:
+               return simple_feature_tweak(node, macio_unknown,
+                       HEATHROW_FCR, HRW_BAY_IDE_ENABLE, value);
+       default:
+               return -ENODEV;
+       }
+}
+
+static long heathrow_ide_reset(struct device_node *node, long param,
+                              long value)
+{
+       switch(param) {
+       case 0:
+               return simple_feature_tweak(node, macio_unknown,
+                       HEATHROW_FCR, HRW_IDE0_RESET_N, !value);
+       case 1:
+               return simple_feature_tweak(node, macio_unknown,
+                       HEATHROW_FCR, HRW_IDE1_RESET_N, !value);
+       default:
+               return -ENODEV;
+       }
+}
+
+static long heathrow_bmac_enable(struct device_node *node, long param,
+                                long value)
+{
+       struct macio_chip*      macio;
+       unsigned long           flags;
+
+       macio = macio_find(node, 0);
+       if (!macio)
+               return -ENODEV;
+       if (value) {
+               LOCK(flags);
+               MACIO_BIS(HEATHROW_FCR, HRW_BMAC_IO_ENABLE);
+               MACIO_BIS(HEATHROW_FCR, HRW_BMAC_RESET);
+               UNLOCK(flags);
+               (void)MACIO_IN32(HEATHROW_FCR);
+               mdelay(10);
+               LOCK(flags);
+               MACIO_BIC(HEATHROW_FCR, HRW_BMAC_RESET);
+               UNLOCK(flags);
+               (void)MACIO_IN32(HEATHROW_FCR);
+               mdelay(10);
+       } else {
+               LOCK(flags);
+               MACIO_BIC(HEATHROW_FCR, HRW_BMAC_IO_ENABLE);
+               UNLOCK(flags);
+       }
+       return 0;
+}
+
+static long heathrow_sound_enable(struct device_node *node, long param,
+                                 long value)
+{
+       struct macio_chip*      macio;
+       unsigned long           flags;
+
+       /* B&W G3 and Yikes don't support that properly (the
+        * sound appear to never come back after beeing shut down).
+        */
+       if (pmac_mb.model_id == PMAC_TYPE_YOSEMITE ||
+           pmac_mb.model_id == PMAC_TYPE_YIKES)
+               return 0;
+
+       macio = macio_find(node, 0);
+       if (!macio)
+               return -ENODEV;
+       if (value) {
+               LOCK(flags);
+               MACIO_BIS(HEATHROW_FCR, HRW_SOUND_CLK_ENABLE);
+               MACIO_BIC(HEATHROW_FCR, HRW_SOUND_POWER_N);
+               UNLOCK(flags);
+               (void)MACIO_IN32(HEATHROW_FCR);
+       } else {
+               LOCK(flags);
+               MACIO_BIS(HEATHROW_FCR, HRW_SOUND_POWER_N);
+               MACIO_BIC(HEATHROW_FCR, HRW_SOUND_CLK_ENABLE);
+               UNLOCK(flags);
+       }
+       return 0;
+}
+
+static u32 save_fcr[6];
+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 u32 save_unin_clock_ctl;
+static struct dbdma_regs save_dbdma[13];
+static struct dbdma_regs save_alt_dbdma[13];
+
+static void dbdma_save(struct macio_chip *macio, struct dbdma_regs *save)
+{
+       int i;
+
+       /* Save state & config of DBDMA channels */
+       for (i = 0; i < 13; i++) {
+               volatile struct dbdma_regs __iomem * chan = (void __iomem *)
+                       (macio->base + ((0x8000+i*0x100)>>2));
+               save[i].cmdptr_hi = in_le32(&chan->cmdptr_hi);
+               save[i].cmdptr = in_le32(&chan->cmdptr);
+               save[i].intr_sel = in_le32(&chan->intr_sel);
+               save[i].br_sel = in_le32(&chan->br_sel);
+               save[i].wait_sel = in_le32(&chan->wait_sel);
+       }
+}
+
+static void dbdma_restore(struct macio_chip *macio, struct dbdma_regs *save)
+{
+       int i;
+
+       /* Save state & config of DBDMA channels */
+       for (i = 0; i < 13; i++) {
+               volatile struct dbdma_regs __iomem * chan = (void __iomem *)
+                       (macio->base + ((0x8000+i*0x100)>>2));
+               out_le32(&chan->control, (ACTIVE|DEAD|WAKE|FLUSH|PAUSE|RUN)<<16);
+               while (in_le32(&chan->status) & ACTIVE)
+                       mb();
+               out_le32(&chan->cmdptr_hi, save[i].cmdptr_hi);
+               out_le32(&chan->cmdptr, save[i].cmdptr);
+               out_le32(&chan->intr_sel, save[i].intr_sel);
+               out_le32(&chan->br_sel, save[i].br_sel);
+               out_le32(&chan->wait_sel, save[i].wait_sel);
+       }
+}
+
+static void heathrow_sleep(struct macio_chip *macio, int secondary)
+{
+       if (secondary) {
+               dbdma_save(macio, save_alt_dbdma);
+               save_fcr[2] = MACIO_IN32(0x38);
+               save_fcr[3] = MACIO_IN32(0x3c);
+       } else {
+               dbdma_save(macio, save_dbdma);
+               save_fcr[0] = MACIO_IN32(0x38);
+               save_fcr[1] = MACIO_IN32(0x3c);
+               save_mbcr = MACIO_IN32(0x34);
+               /* Make sure sound is shut down */
+               MACIO_BIS(HEATHROW_FCR, HRW_SOUND_POWER_N);
+               MACIO_BIC(HEATHROW_FCR, HRW_SOUND_CLK_ENABLE);
+               /* This seems to be necessary as well or the fan
+                * keeps coming up and battery drains fast */
+               MACIO_BIC(HEATHROW_FCR, HRW_IOBUS_ENABLE);
+               MACIO_BIC(HEATHROW_FCR, HRW_IDE0_RESET_N);
+               /* Make sure eth is down even if module or sleep
+                * won't work properly */
+               MACIO_BIC(HEATHROW_FCR, HRW_BMAC_IO_ENABLE | HRW_BMAC_RESET);
+       }
+       /* Make sure modem is shut down */
+       MACIO_OUT8(HRW_GPIO_MODEM_RESET,
+               MACIO_IN8(HRW_GPIO_MODEM_RESET) & ~1);
+       MACIO_BIS(HEATHROW_FCR, HRW_SCC_TRANS_EN_N);
+       MACIO_BIC(HEATHROW_FCR, OH_SCCA_IO|OH_SCCB_IO|HRW_SCC_ENABLE);
+
+       /* Let things settle */
+       (void)MACIO_IN32(HEATHROW_FCR);
+}
+
+static void heathrow_wakeup(struct macio_chip *macio, int secondary)
+{
+       if (secondary) {
+               MACIO_OUT32(0x38, save_fcr[2]);
+               (void)MACIO_IN32(0x38);
+               mdelay(1);
+               MACIO_OUT32(0x3c, save_fcr[3]);
+               (void)MACIO_IN32(0x38);
+               mdelay(10);
+               dbdma_restore(macio, save_alt_dbdma);
+       } else {
+               MACIO_OUT32(0x38, save_fcr[0] | HRW_IOBUS_ENABLE);
+               (void)MACIO_IN32(0x38);
+               mdelay(1);
+               MACIO_OUT32(0x3c, save_fcr[1]);
+               (void)MACIO_IN32(0x38);
+               mdelay(1);
+               MACIO_OUT32(0x34, save_mbcr);
+               (void)MACIO_IN32(0x38);
+               mdelay(10);
+               dbdma_restore(macio, save_dbdma);
+       }
+}
+
+static long heathrow_sleep_state(struct device_node *node, long param,
+                                long value)
+{
+       if ((pmac_mb.board_flags & PMAC_MB_CAN_SLEEP) == 0)
+               return -EPERM;
+       if (value == 1) {
+               if (macio_chips[1].type == macio_gatwick)
+                       heathrow_sleep(&macio_chips[0], 1);
+               heathrow_sleep(&macio_chips[0], 0);
+       } else if (value == 0) {
+               heathrow_wakeup(&macio_chips[0], 0);
+               if (macio_chips[1].type == macio_gatwick)
+                       heathrow_wakeup(&macio_chips[0], 1);
+       }
+       return 0;
+}
+
+static long core99_scc_enable(struct device_node *node, long param, long value)
+{
+       struct macio_chip*      macio;
+       unsigned long           flags;
+       unsigned long           chan_mask;
+       u32                     fcr;
+
+       macio = macio_find(node, 0);
+       if (!macio)
+               return -ENODEV;
+       if (!strcmp(node->name, "ch-a"))
+               chan_mask = MACIO_FLAG_SCCA_ON;
+       else if (!strcmp(node->name, "ch-b"))
+               chan_mask = MACIO_FLAG_SCCB_ON;
+       else
+               return -ENODEV;
+
+       if (value) {
+               int need_reset_scc = 0;
+               int need_reset_irda = 0;
+
+               LOCK(flags);
+               fcr = MACIO_IN32(KEYLARGO_FCR0);
+               /* Check if scc cell need enabling */
+               if (!(fcr & KL0_SCC_CELL_ENABLE)) {
+                       fcr |= KL0_SCC_CELL_ENABLE;
+                       need_reset_scc = 1;
+               }
+               if (chan_mask & MACIO_FLAG_SCCA_ON) {
+                       fcr |= KL0_SCCA_ENABLE;
+                       /* Don't enable line drivers for I2S modem */
+                       if ((param & 0xfff) == PMAC_SCC_I2S1)
+                               fcr &= ~KL0_SCC_A_INTF_ENABLE;
+                       else
+                               fcr |= KL0_SCC_A_INTF_ENABLE;
+               }
+               if (chan_mask & MACIO_FLAG_SCCB_ON) {
+                       fcr |= KL0_SCCB_ENABLE;
+                       /* Perform irda specific inits */
+                       if ((param & 0xfff) == PMAC_SCC_IRDA) {
+                               fcr &= ~KL0_SCC_B_INTF_ENABLE;
+                               fcr |= KL0_IRDA_ENABLE;
+                               fcr |= KL0_IRDA_CLK32_ENABLE | KL0_IRDA_CLK19_ENABLE;
+                               fcr |= KL0_IRDA_SOURCE1_SEL;
+                               fcr &= ~(KL0_IRDA_FAST_CONNECT|KL0_IRDA_DEFAULT1|KL0_IRDA_DEFAULT0);
+                               fcr &= ~(KL0_IRDA_SOURCE2_SEL|KL0_IRDA_HIGH_BAND);
+                               need_reset_irda = 1;
+                       } else
+                               fcr |= KL0_SCC_B_INTF_ENABLE;
+               }
+               MACIO_OUT32(KEYLARGO_FCR0, fcr);
+               macio->flags |= chan_mask;
+               if (need_reset_scc)  {
+                       MACIO_BIS(KEYLARGO_FCR0, KL0_SCC_RESET);
+                       (void)MACIO_IN32(KEYLARGO_FCR0);
+                       UNLOCK(flags);
+                       mdelay(15);
+                       LOCK(flags);
+                       MACIO_BIC(KEYLARGO_FCR0, KL0_SCC_RESET);
+               }
+               if (need_reset_irda)  {
+                       MACIO_BIS(KEYLARGO_FCR0, KL0_IRDA_RESET);
+                       (void)MACIO_IN32(KEYLARGO_FCR0);
+                       UNLOCK(flags);
+                       mdelay(15);
+                       LOCK(flags);
+                       MACIO_BIC(KEYLARGO_FCR0, KL0_IRDA_RESET);
+               }
+               UNLOCK(flags);
+               if (param & PMAC_SCC_FLAG_XMON)
+                       macio->flags |= MACIO_FLAG_SCC_LOCKED;
+       } else {
+               if (macio->flags & MACIO_FLAG_SCC_LOCKED)
+                       return -EPERM;
+               LOCK(flags);
+               fcr = MACIO_IN32(KEYLARGO_FCR0);
+               if (chan_mask & MACIO_FLAG_SCCA_ON)
+                       fcr &= ~KL0_SCCA_ENABLE;
+               if (chan_mask & MACIO_FLAG_SCCB_ON) {
+                       fcr &= ~KL0_SCCB_ENABLE;
+                       /* Perform irda specific clears */
+                       if ((param & 0xfff) == PMAC_SCC_IRDA) {
+                               fcr &= ~KL0_IRDA_ENABLE;
+                               fcr &= ~(KL0_IRDA_CLK32_ENABLE | KL0_IRDA_CLK19_ENABLE);
+                               fcr &= ~(KL0_IRDA_FAST_CONNECT|KL0_IRDA_DEFAULT1|KL0_IRDA_DEFAULT0);
+                               fcr &= ~(KL0_IRDA_SOURCE1_SEL|KL0_IRDA_SOURCE2_SEL|KL0_IRDA_HIGH_BAND);
+                       }
+               }
+               MACIO_OUT32(KEYLARGO_FCR0, fcr);
+               if ((fcr & (KL0_SCCA_ENABLE | KL0_SCCB_ENABLE)) == 0) {
+                       fcr &= ~KL0_SCC_CELL_ENABLE;
+                       MACIO_OUT32(KEYLARGO_FCR0, fcr);
+               }
+               macio->flags &= ~(chan_mask);
+               UNLOCK(flags);
+               mdelay(10);
+       }
+       return 0;
+}
+
+static long
+core99_modem_enable(struct device_node *node, long param, long value)
+{
+       struct macio_chip*      macio;
+       u8                      gpio;
+       unsigned long           flags;
+
+       /* Hack for internal USB modem */
+       if (node == NULL) {
+               if (macio_chips[0].type != macio_keylargo)
+                       return -ENODEV;
+               node = macio_chips[0].of_node;
+       }
+       macio = macio_find(node, 0);
+       if (!macio)
+               return -ENODEV;
+       gpio = MACIO_IN8(KL_GPIO_MODEM_RESET);
+       gpio |= KEYLARGO_GPIO_OUTPUT_ENABLE;
+       gpio &= ~KEYLARGO_GPIO_OUTOUT_DATA;
+
+       if (!value) {
+               LOCK(flags);
+               MACIO_OUT8(KL_GPIO_MODEM_RESET, gpio);
+               UNLOCK(flags);
+               (void)MACIO_IN8(KL_GPIO_MODEM_RESET);
+               mdelay(250);
+       }
+       LOCK(flags);
+       if (value) {
+               MACIO_BIC(KEYLARGO_FCR2, KL2_ALT_DATA_OUT);
+               UNLOCK(flags);
+               (void)MACIO_IN32(KEYLARGO_FCR2);
+               mdelay(250);
+       } else {
+               MACIO_BIS(KEYLARGO_FCR2, KL2_ALT_DATA_OUT);
+               UNLOCK(flags);
+       }
+       if (value) {
+               LOCK(flags);
+               MACIO_OUT8(KL_GPIO_MODEM_RESET, gpio | KEYLARGO_GPIO_OUTOUT_DATA);
+               (void)MACIO_IN8(KL_GPIO_MODEM_RESET);
+               UNLOCK(flags); mdelay(250); LOCK(flags);
+               MACIO_OUT8(KL_GPIO_MODEM_RESET, gpio);
+               (void)MACIO_IN8(KL_GPIO_MODEM_RESET);
+               UNLOCK(flags); mdelay(250); LOCK(flags);
+               MACIO_OUT8(KL_GPIO_MODEM_RESET, gpio | KEYLARGO_GPIO_OUTOUT_DATA);
+               (void)MACIO_IN8(KL_GPIO_MODEM_RESET);
+               UNLOCK(flags); mdelay(250);
+       }
+       return 0;
+}
+
+static long
+pangea_modem_enable(struct device_node *node, long param, long value)
+{
+       struct macio_chip*      macio;
+       u8                      gpio;
+       unsigned long           flags;
+
+       /* Hack for internal USB modem */
+       if (node == NULL) {
+               if (macio_chips[0].type != macio_pangea &&
+                   macio_chips[0].type != macio_intrepid)
+                       return -ENODEV;
+               node = macio_chips[0].of_node;
+       }
+       macio = macio_find(node, 0);
+       if (!macio)
+               return -ENODEV;
+       gpio = MACIO_IN8(KL_GPIO_MODEM_RESET);
+       gpio |= KEYLARGO_GPIO_OUTPUT_ENABLE;
+       gpio &= ~KEYLARGO_GPIO_OUTOUT_DATA;
+
+       if (!value) {
+               LOCK(flags);
+               MACIO_OUT8(KL_GPIO_MODEM_RESET, gpio);
+               UNLOCK(flags);
+               (void)MACIO_IN8(KL_GPIO_MODEM_RESET);
+               mdelay(250);
+       }
+       LOCK(flags);
+       if (value) {
+               MACIO_OUT8(KL_GPIO_MODEM_POWER,
+                       KEYLARGO_GPIO_OUTPUT_ENABLE);
+               UNLOCK(flags);
+               (void)MACIO_IN32(KEYLARGO_FCR2);
+               mdelay(250);
+       } else {
+               MACIO_OUT8(KL_GPIO_MODEM_POWER,
+                       KEYLARGO_GPIO_OUTPUT_ENABLE | KEYLARGO_GPIO_OUTOUT_DATA);
+               UNLOCK(flags);
+       }
+       if (value) {
+               LOCK(flags);
+               MACIO_OUT8(KL_GPIO_MODEM_RESET, gpio | KEYLARGO_GPIO_OUTOUT_DATA);
+               (void)MACIO_IN8(KL_GPIO_MODEM_RESET);
+               UNLOCK(flags); mdelay(250); LOCK(flags);
+               MACIO_OUT8(KL_GPIO_MODEM_RESET, gpio);
+               (void)MACIO_IN8(KL_GPIO_MODEM_RESET);
+               UNLOCK(flags); mdelay(250); LOCK(flags);
+               MACIO_OUT8(KL_GPIO_MODEM_RESET, gpio | KEYLARGO_GPIO_OUTOUT_DATA);
+               (void)MACIO_IN8(KL_GPIO_MODEM_RESET);
+               UNLOCK(flags); mdelay(250);
+       }
+       return 0;
+}
+
+static long
+core99_ata100_enable(struct device_node *node, long value)
+{
+       unsigned long flags;
+       struct pci_dev *pdev = NULL;
+       u8 pbus, pid;
+
+       if (uninorth_rev < 0x24)
+               return -ENODEV;
+
+       LOCK(flags);
+       if (value)
+               UN_BIS(UNI_N_CLOCK_CNTL, UNI_N_CLOCK_CNTL_ATA100);
+       else
+               UN_BIC(UNI_N_CLOCK_CNTL, UNI_N_CLOCK_CNTL_ATA100);
+       (void)UN_IN(UNI_N_CLOCK_CNTL);
+       UNLOCK(flags);
+       udelay(20);
+
+       if (value) {
+               if (pci_device_from_OF_node(node, &pbus, &pid) == 0)
+                       pdev = pci_find_slot(pbus, pid);
+               if (pdev == NULL)
+                       return 0;
+               pci_enable_device(pdev);
+               pci_set_master(pdev);
+       }
+       return 0;
+}
+
+static long
+core99_ide_enable(struct device_node *node, long param, long value)
+{
+       /* Bus ID 0 to 2 are KeyLargo based IDE, busID 3 is U2
+        * based ata-100
+        */
+       switch(param) {
+           case 0:
+               return simple_feature_tweak(node, macio_unknown,
+                       KEYLARGO_FCR1, KL1_EIDE0_ENABLE, value);
+           case 1:
+               return simple_feature_tweak(node, macio_unknown,
+                       KEYLARGO_FCR1, KL1_EIDE1_ENABLE, value);
+           case 2:
+               return simple_feature_tweak(node, macio_unknown,
+                       KEYLARGO_FCR1, KL1_UIDE_ENABLE, value);
+           case 3:
+               return core99_ata100_enable(node, value);
+           default:
+               return -ENODEV;
+       }
+}
+
+static long
+core99_ide_reset(struct device_node *node, long param, long value)
+{
+       switch(param) {
+           case 0:
+               return simple_feature_tweak(node, macio_unknown,
+                       KEYLARGO_FCR1, KL1_EIDE0_RESET_N, !value);
+           case 1:
+               return simple_feature_tweak(node, macio_unknown,
+                       KEYLARGO_FCR1, KL1_EIDE1_RESET_N, !value);
+           case 2:
+               return simple_feature_tweak(node, macio_unknown,
+                       KEYLARGO_FCR1, KL1_UIDE_RESET_N, !value);
+           default:
+               return -ENODEV;
+       }
+}
+
+static long
+core99_gmac_enable(struct device_node *node, long param, long value)
+{
+       unsigned long flags;
+
+       LOCK(flags);
+       if (value)
+               UN_BIS(UNI_N_CLOCK_CNTL, UNI_N_CLOCK_CNTL_GMAC);
+       else
+               UN_BIC(UNI_N_CLOCK_CNTL, UNI_N_CLOCK_CNTL_GMAC);
+       (void)UN_IN(UNI_N_CLOCK_CNTL);
+       UNLOCK(flags);
+       udelay(20);
+
+       return 0;
+}
+
+static long
+core99_gmac_phy_reset(struct device_node *node, long param, long value)
+{
+       unsigned long flags;
+       struct macio_chip *macio;
+
+       macio = &macio_chips[0];
+       if (macio->type != macio_keylargo && macio->type != macio_pangea &&
+           macio->type != macio_intrepid)
+               return -ENODEV;
+
+       LOCK(flags);
+       MACIO_OUT8(KL_GPIO_ETH_PHY_RESET, KEYLARGO_GPIO_OUTPUT_ENABLE);
+       (void)MACIO_IN8(KL_GPIO_ETH_PHY_RESET);
+       UNLOCK(flags);
+       mdelay(10);
+       LOCK(flags);
+       MACIO_OUT8(KL_GPIO_ETH_PHY_RESET, /*KEYLARGO_GPIO_OUTPUT_ENABLE | */
+               KEYLARGO_GPIO_OUTOUT_DATA);
+       UNLOCK(flags);
+       mdelay(10);
+
+       return 0;
+}
+
+static long
+core99_sound_chip_enable(struct device_node *node, long param, long value)
+{
+       struct macio_chip*      macio;
+       unsigned long           flags;
+
+       macio = macio_find(node, 0);
+       if (!macio)
+               return -ENODEV;
+
+       /* Do a better probe code, screamer G4 desktops &
+        * iMacs can do that too, add a recalibrate  in
+        * the driver as well
+        */
+       if (pmac_mb.model_id == PMAC_TYPE_PISMO ||
+           pmac_mb.model_id == PMAC_TYPE_TITANIUM) {
+               LOCK(flags);
+               if (value)
+                       MACIO_OUT8(KL_GPIO_SOUND_POWER,
+                               KEYLARGO_GPIO_OUTPUT_ENABLE |
+                               KEYLARGO_GPIO_OUTOUT_DATA);
+               else
+                       MACIO_OUT8(KL_GPIO_SOUND_POWER,
+                               KEYLARGO_GPIO_OUTPUT_ENABLE);
+               (void)MACIO_IN8(KL_GPIO_SOUND_POWER);
+               UNLOCK(flags);
+       }
+       return 0;
+}
+
+static long
+core99_airport_enable(struct device_node *node, long param, long value)
+{
+       struct macio_chip*      macio;
+       unsigned long           flags;
+       int                     state;
+
+       macio = macio_find(node, 0);
+       if (!macio)
+               return -ENODEV;
+
+       /* Hint: we allow passing of macio itself for the sake of the
+        * sleep code
+        */
+       if (node != macio->of_node &&
+           (!node->parent || node->parent != macio->of_node))
+               return -ENODEV;
+       state = (macio->flags & MACIO_FLAG_AIRPORT_ON) != 0;
+       if (value == state)
+               return 0;
+       if (value) {
+               /* This code is a reproduction of OF enable-cardslot
+                * and init-wireless methods, slightly hacked until
+                * I got it working.
+                */
+               LOCK(flags);
+               MACIO_OUT8(KEYLARGO_GPIO_0+0xf, 5);
+               (void)MACIO_IN8(KEYLARGO_GPIO_0+0xf);
+               UNLOCK(flags);
+               mdelay(10);
+               LOCK(flags);
+               MACIO_OUT8(KEYLARGO_GPIO_0+0xf, 4);
+               (void)MACIO_IN8(KEYLARGO_GPIO_0+0xf);
+               UNLOCK(flags);
+
+               mdelay(10);
+
+               LOCK(flags);
+               MACIO_BIC(KEYLARGO_FCR2, KL2_CARDSEL_16);
+               (void)MACIO_IN32(KEYLARGO_FCR2);
+               udelay(10);
+               MACIO_OUT8(KEYLARGO_GPIO_EXTINT_0+0xb, 0);
+               (void)MACIO_IN8(KEYLARGO_GPIO_EXTINT_0+0xb);
+               udelay(10);
+               MACIO_OUT8(KEYLARGO_GPIO_EXTINT_0+0xa, 0x28);
+               (void)MACIO_IN8(KEYLARGO_GPIO_EXTINT_0+0xa);
+               udelay(10);
+               MACIO_OUT8(KEYLARGO_GPIO_EXTINT_0+0xd, 0x28);
+               (void)MACIO_IN8(KEYLARGO_GPIO_EXTINT_0+0xd);
+               udelay(10);
+               MACIO_OUT8(KEYLARGO_GPIO_0+0xd, 0x28);
+               (void)MACIO_IN8(KEYLARGO_GPIO_0+0xd);
+               udelay(10);
+               MACIO_OUT8(KEYLARGO_GPIO_0+0xe, 0x28);
+               (void)MACIO_IN8(KEYLARGO_GPIO_0+0xe);
+               UNLOCK(flags);
+               udelay(10);
+               MACIO_OUT32(0x1c000, 0);
+               mdelay(1);
+               MACIO_OUT8(0x1a3e0, 0x41);
+               (void)MACIO_IN8(0x1a3e0);
+               udelay(10);
+               LOCK(flags);
+               MACIO_BIS(KEYLARGO_FCR2, KL2_CARDSEL_16);
+               (void)MACIO_IN32(KEYLARGO_FCR2);
+               UNLOCK(flags);
+               mdelay(100);
+
+               macio->flags |= MACIO_FLAG_AIRPORT_ON;
+       } else {
+               LOCK(flags);
+               MACIO_BIC(KEYLARGO_FCR2, KL2_CARDSEL_16);
+               (void)MACIO_IN32(KEYLARGO_FCR2);
+               MACIO_OUT8(KL_GPIO_AIRPORT_0, 0);
+               MACIO_OUT8(KL_GPIO_AIRPORT_1, 0);
+               MACIO_OUT8(KL_GPIO_AIRPORT_2, 0);
+               MACIO_OUT8(KL_GPIO_AIRPORT_3, 0);
+               MACIO_OUT8(KL_GPIO_AIRPORT_4, 0);
+               (void)MACIO_IN8(KL_GPIO_AIRPORT_4);
+               UNLOCK(flags);
+
+               macio->flags &= ~MACIO_FLAG_AIRPORT_ON;
+       }
+       return 0;
+}
+
+#ifdef CONFIG_SMP
+static long
+core99_reset_cpu(struct device_node *node, long param, long value)
+{
+       unsigned int reset_io = 0;
+       unsigned long flags;
+       struct macio_chip *macio;
+       struct device_node *np;
+       const int dflt_reset_lines[] = {        KL_GPIO_RESET_CPU0,
+                                               KL_GPIO_RESET_CPU1,
+                                               KL_GPIO_RESET_CPU2,
+                                               KL_GPIO_RESET_CPU3 };
+
+       macio = &macio_chips[0];
+       if (macio->type != macio_keylargo)
+               return -ENODEV;
+
+       np = find_path_device("/cpus");
+       if (np == NULL)
+               return -ENODEV;
+       for (np = np->child; np != NULL; np = np->sibling) {
+               u32 *num = (u32 *)get_property(np, "reg", NULL);
+               u32 *rst = (u32 *)get_property(np, "soft-reset", NULL);
+               if (num == NULL || rst == NULL)
+                       continue;
+               if (param == *num) {
+                       reset_io = *rst;
+                       break;
+               }
+       }
+       if (np == NULL || reset_io == 0)
+               reset_io = dflt_reset_lines[param];
+
+       LOCK(flags);
+       MACIO_OUT8(reset_io, KEYLARGO_GPIO_OUTPUT_ENABLE);
+       (void)MACIO_IN8(reset_io);
+       udelay(1);
+       MACIO_OUT8(reset_io, 0);
+       (void)MACIO_IN8(reset_io);
+       UNLOCK(flags);
+
+       return 0;
+}
+#endif /* CONFIG_SMP */
+
+static long
+core99_usb_enable(struct device_node *node, long param, long value)
+{
+       struct macio_chip *macio;
+       unsigned long flags;
+       char *prop;
+       int number;
+       u32 reg;
+
+       macio = &macio_chips[0];
+       if (macio->type != macio_keylargo && macio->type != macio_pangea &&
+           macio->type != macio_intrepid)
+               return -ENODEV;
+
+       prop = (char *)get_property(node, "AAPL,clock-id", NULL);
+       if (!prop)
+               return -ENODEV;
+       if (strncmp(prop, "usb0u048", 8) == 0)
+               number = 0;
+       else if (strncmp(prop, "usb1u148", 8) == 0)
+               number = 2;
+       else if (strncmp(prop, "usb2u248", 8) == 0)
+               number = 4;
+       else
+               return -ENODEV;
+
+       /* Sorry for the brute-force locking, but this is only used during
+        * sleep and the timing seem to be critical
+        */
+       LOCK(flags);
+       if (value) {
+               /* Turn ON */
+               if (number == 0) {
+                       MACIO_BIC(KEYLARGO_FCR0, (KL0_USB0_PAD_SUSPEND0 | KL0_USB0_PAD_SUSPEND1));
+                       (void)MACIO_IN32(KEYLARGO_FCR0);
+                       UNLOCK(flags);
+                       mdelay(1);
+                       LOCK(flags);
+                       MACIO_BIS(KEYLARGO_FCR0, KL0_USB0_CELL_ENABLE);
+               } else if (number == 2) {
+                       MACIO_BIC(KEYLARGO_FCR0, (KL0_USB1_PAD_SUSPEND0 | KL0_USB1_PAD_SUSPEND1));
+                       UNLOCK(flags);
+                       (void)MACIO_IN32(KEYLARGO_FCR0);
+                       mdelay(1);
+                       LOCK(flags);
+                       MACIO_BIS(KEYLARGO_FCR0, KL0_USB1_CELL_ENABLE);
+               } else if (number == 4) {
+                       MACIO_BIC(KEYLARGO_FCR1, (KL1_USB2_PAD_SUSPEND0 | KL1_USB2_PAD_SUSPEND1));
+                       UNLOCK(flags);
+                       (void)MACIO_IN32(KEYLARGO_FCR1);
+                       mdelay(1);
+                       LOCK(flags);
+                       MACIO_BIS(KEYLARGO_FCR1, KL1_USB2_CELL_ENABLE);
+               }
+               if (number < 4) {
+                       reg = MACIO_IN32(KEYLARGO_FCR4);
+                       reg &=  ~(KL4_PORT_WAKEUP_ENABLE(number) | KL4_PORT_RESUME_WAKE_EN(number) |
+                               KL4_PORT_CONNECT_WAKE_EN(number) | KL4_PORT_DISCONNECT_WAKE_EN(number));
+                       reg &=  ~(KL4_PORT_WAKEUP_ENABLE(number+1) | KL4_PORT_RESUME_WAKE_EN(number+1) |
+                               KL4_PORT_CONNECT_WAKE_EN(number+1) | KL4_PORT_DISCONNECT_WAKE_EN(number+1));
+                       MACIO_OUT32(KEYLARGO_FCR4, reg);
+                       (void)MACIO_IN32(KEYLARGO_FCR4);
+                       udelay(10);
+               } else {
+                       reg = MACIO_IN32(KEYLARGO_FCR3);
+                       reg &=  ~(KL3_IT_PORT_WAKEUP_ENABLE(0) | KL3_IT_PORT_RESUME_WAKE_EN(0) |
+                               KL3_IT_PORT_CONNECT_WAKE_EN(0) | KL3_IT_PORT_DISCONNECT_WAKE_EN(0));
+                       reg &=  ~(KL3_IT_PORT_WAKEUP_ENABLE(1) | KL3_IT_PORT_RESUME_WAKE_EN(1) |
+                               KL3_IT_PORT_CONNECT_WAKE_EN(1) | KL3_IT_PORT_DISCONNECT_WAKE_EN(1));
+                       MACIO_OUT32(KEYLARGO_FCR3, reg);
+                       (void)MACIO_IN32(KEYLARGO_FCR3);
+                       udelay(10);
+               }
+               if (macio->type == macio_intrepid) {
+                       /* wait for clock stopped bits to clear */
+                       u32 test0 = 0, test1 = 0;
+                       u32 status0, status1;
+                       int timeout = 1000;
+
+                       UNLOCK(flags);
+                       switch (number) {
+                       case 0:
+                               test0 = UNI_N_CLOCK_STOPPED_USB0;
+                               test1 = UNI_N_CLOCK_STOPPED_USB0PCI;
+                               break;
+                       case 2:
+                               test0 = UNI_N_CLOCK_STOPPED_USB1;
+                               test1 = UNI_N_CLOCK_STOPPED_USB1PCI;
+                               break;
+                       case 4:
+                               test0 = UNI_N_CLOCK_STOPPED_USB2;
+                               test1 = UNI_N_CLOCK_STOPPED_USB2PCI;
+                               break;
+                       }
+                       do {
+                               if (--timeout <= 0) {
+                                       printk(KERN_ERR "core99_usb_enable: "
+                                              "Timeout waiting for clocks\n");
+                                       break;
+                               }
+                               mdelay(1);
+                               status0 = UN_IN(UNI_N_CLOCK_STOP_STATUS0);
+                               status1 = UN_IN(UNI_N_CLOCK_STOP_STATUS1);
+                       } while ((status0 & test0) | (status1 & test1));
+                       LOCK(flags);
+               }
+       } else {
+               /* Turn OFF */
+               if (number < 4) {
+                       reg = MACIO_IN32(KEYLARGO_FCR4);
+                       reg |=  KL4_PORT_WAKEUP_ENABLE(number) | KL4_PORT_RESUME_WAKE_EN(number) |
+                               KL4_PORT_CONNECT_WAKE_EN(number) | KL4_PORT_DISCONNECT_WAKE_EN(number);
+                       reg |=  KL4_PORT_WAKEUP_ENABLE(number+1) | KL4_PORT_RESUME_WAKE_EN(number+1) |
+                               KL4_PORT_CONNECT_WAKE_EN(number+1) | KL4_PORT_DISCONNECT_WAKE_EN(number+1);
+                       MACIO_OUT32(KEYLARGO_FCR4, reg);
+                       (void)MACIO_IN32(KEYLARGO_FCR4);
+                       udelay(1);
+               } else {
+                       reg = MACIO_IN32(KEYLARGO_FCR3);
+                       reg |=  KL3_IT_PORT_WAKEUP_ENABLE(0) | KL3_IT_PORT_RESUME_WAKE_EN(0) |
+                               KL3_IT_PORT_CONNECT_WAKE_EN(0) | KL3_IT_PORT_DISCONNECT_WAKE_EN(0);
+                       reg |=  KL3_IT_PORT_WAKEUP_ENABLE(1) | KL3_IT_PORT_RESUME_WAKE_EN(1) |
+                               KL3_IT_PORT_CONNECT_WAKE_EN(1) | KL3_IT_PORT_DISCONNECT_WAKE_EN(1);
+                       MACIO_OUT32(KEYLARGO_FCR3, reg);
+                       (void)MACIO_IN32(KEYLARGO_FCR3);
+                       udelay(1);
+               }
+               if (number == 0) {
+                       if (macio->type != macio_intrepid)
+                               MACIO_BIC(KEYLARGO_FCR0, KL0_USB0_CELL_ENABLE);
+                       (void)MACIO_IN32(KEYLARGO_FCR0);
+                       udelay(1);
+                       MACIO_BIS(KEYLARGO_FCR0, (KL0_USB0_PAD_SUSPEND0 | KL0_USB0_PAD_SUSPEND1));
+                       (void)MACIO_IN32(KEYLARGO_FCR0);
+               } else if (number == 2) {
+                       if (macio->type != macio_intrepid)
+                               MACIO_BIC(KEYLARGO_FCR0, KL0_USB1_CELL_ENABLE);
+                       (void)MACIO_IN32(KEYLARGO_FCR0);
+                       udelay(1);
+                       MACIO_BIS(KEYLARGO_FCR0, (KL0_USB1_PAD_SUSPEND0 | KL0_USB1_PAD_SUSPEND1));
+                       (void)MACIO_IN32(KEYLARGO_FCR0);
+               } else if (number == 4) {
+                       udelay(1);
+                       MACIO_BIS(KEYLARGO_FCR1, (KL1_USB2_PAD_SUSPEND0 | KL1_USB2_PAD_SUSPEND1));
+                       (void)MACIO_IN32(KEYLARGO_FCR1);
+               }
+               udelay(1);
+       }
+       UNLOCK(flags);
+
+       return 0;
+}
+
+static long
+core99_firewire_enable(struct device_node *node, long param, long value)
+{
+       unsigned long flags;
+       struct macio_chip *macio;
+
+       macio = &macio_chips[0];
+       if (macio->type != macio_keylargo && macio->type != macio_pangea &&
+           macio->type != macio_intrepid)
+               return -ENODEV;
+       if (!(macio->flags & MACIO_FLAG_FW_SUPPORTED))
+               return -ENODEV;
+
+       LOCK(flags);
+       if (value) {
+               UN_BIS(UNI_N_CLOCK_CNTL, UNI_N_CLOCK_CNTL_FW);
+               (void)UN_IN(UNI_N_CLOCK_CNTL);
+       } else {
+               UN_BIC(UNI_N_CLOCK_CNTL, UNI_N_CLOCK_CNTL_FW);
+               (void)UN_IN(UNI_N_CLOCK_CNTL);
+       }
+       UNLOCK(flags);
+       mdelay(1);
+
+       return 0;
+}
+
+static long
+core99_firewire_cable_power(struct device_node *node, long param, long value)
+{
+       unsigned long flags;
+       struct macio_chip *macio;
+
+       /* Trick: we allow NULL node */
+       if ((pmac_mb.board_flags & PMAC_MB_HAS_FW_POWER) == 0)
+               return -ENODEV;
+       macio = &macio_chips[0];
+       if (macio->type != macio_keylargo && macio->type != macio_pangea &&
+           macio->type != macio_intrepid)
+               return -ENODEV;
+       if (!(macio->flags & MACIO_FLAG_FW_SUPPORTED))
+               return -ENODEV;
+
+       LOCK(flags);
+       if (value) {
+               MACIO_OUT8(KL_GPIO_FW_CABLE_POWER , 0);
+               MACIO_IN8(KL_GPIO_FW_CABLE_POWER);
+               udelay(10);
+       } else {
+               MACIO_OUT8(KL_GPIO_FW_CABLE_POWER , 4);
+               MACIO_IN8(KL_GPIO_FW_CABLE_POWER); udelay(10);
+       }
+       UNLOCK(flags);
+       mdelay(1);
+
+       return 0;
+}
+
+static long
+intrepid_aack_delay_enable(struct device_node *node, long param, long value)
+{
+       unsigned long flags;
+
+       if (uninorth_rev < 0xd2)
+               return -ENODEV;
+
+       LOCK(flags);
+       if (param)
+               UN_BIS(UNI_N_AACK_DELAY, UNI_N_AACK_DELAY_ENABLE);
+       else
+               UN_BIC(UNI_N_AACK_DELAY, UNI_N_AACK_DELAY_ENABLE);
+       UNLOCK(flags);
+
+       return 0;
+}
+
+
+#endif /* CONFIG_POWER4 */
+
+static long
+core99_read_gpio(struct device_node *node, long param, long value)
+{
+       struct macio_chip *macio = &macio_chips[0];
+
+       return MACIO_IN8(param);
+}
+
+
+static long
+core99_write_gpio(struct device_node *node, long param, long value)
+{
+       struct macio_chip *macio = &macio_chips[0];
+
+       MACIO_OUT8(param, (u8)(value & 0xff));
+       return 0;
+}
+
+#ifdef CONFIG_POWER4
+static long g5_gmac_enable(struct device_node *node, long param, long value)
+{
+       struct macio_chip *macio = &macio_chips[0];
+       unsigned long flags;
+
+       if (node == NULL)
+               return -ENODEV;
+
+       LOCK(flags);
+       if (value) {
+               MACIO_BIS(KEYLARGO_FCR1, K2_FCR1_GMAC_CLK_ENABLE);
+               mb();
+               k2_skiplist[0] = NULL;
+       } else {
+               k2_skiplist[0] = node;
+               mb();
+               MACIO_BIC(KEYLARGO_FCR1, K2_FCR1_GMAC_CLK_ENABLE);
+       }
+       
+       UNLOCK(flags);
+       mdelay(1);
+
+       return 0;
+}
+
+static long g5_fw_enable(struct device_node *node, long param, long value)
+{
+       struct macio_chip *macio = &macio_chips[0];
+       unsigned long flags;
+
+       if (node == NULL)
+               return -ENODEV;
+
+       LOCK(flags);
+       if (value) {
+               MACIO_BIS(KEYLARGO_FCR1, K2_FCR1_FW_CLK_ENABLE);
+               mb();
+               k2_skiplist[1] = NULL;
+       } else {
+               k2_skiplist[1] = node;
+               mb();
+               MACIO_BIC(KEYLARGO_FCR1, K2_FCR1_FW_CLK_ENABLE);
+       }
+       
+       UNLOCK(flags);
+       mdelay(1);
+
+       return 0;
+}
+
+static long g5_mpic_enable(struct device_node *node, long param, long value)
+{
+       unsigned long flags;
+
+       if (node->parent == NULL || strcmp(node->parent->name, "u3"))
+               return 0;
+
+       LOCK(flags);
+       UN_BIS(U3_TOGGLE_REG, U3_MPIC_RESET | U3_MPIC_OUTPUT_ENABLE);
+       UNLOCK(flags);
+
+       return 0;
+}
+
+static long g5_eth_phy_reset(struct device_node *node, long param, long value)
+{
+       struct macio_chip *macio = &macio_chips[0];
+       struct device_node *phy;
+       int need_reset;
+
+       /*
+        * We must not reset the combo PHYs, only the BCM5221 found in
+        * the iMac G5.
+        */
+       phy = of_get_next_child(node, NULL);
+       if (!phy)
+               return -ENODEV;
+       need_reset = device_is_compatible(phy, "B5221");
+       of_node_put(phy);
+       if (!need_reset)
+               return 0;
+
+       /* PHY reset is GPIO 29, not in device-tree unfortunately */
+       MACIO_OUT8(K2_GPIO_EXTINT_0 + 29,
+                  KEYLARGO_GPIO_OUTPUT_ENABLE | KEYLARGO_GPIO_OUTOUT_DATA);
+       /* Thankfully, this is now always called at a time when we can
+        * schedule by sungem.
+        */
+       msleep(10);
+       MACIO_OUT8(K2_GPIO_EXTINT_0 + 29, 0);
+
+       return 0;
+}
+
+static long g5_i2s_enable(struct device_node *node, long param, long value)
+{
+       /* Very crude implementation for now */
+       struct macio_chip *macio = &macio_chips[0];
+       unsigned long flags;
+
+       if (value == 0)
+               return 0; /* don't disable yet */
+
+       LOCK(flags);
+       MACIO_BIS(KEYLARGO_FCR3, KL3_CLK45_ENABLE | KL3_CLK49_ENABLE |
+                 KL3_I2S0_CLK18_ENABLE);
+       udelay(10);
+       MACIO_BIS(KEYLARGO_FCR1, K2_FCR1_I2S0_CELL_ENABLE |
+                 K2_FCR1_I2S0_CLK_ENABLE_BIT | K2_FCR1_I2S0_ENABLE);
+       udelay(10);
+       MACIO_BIC(KEYLARGO_FCR1, K2_FCR1_I2S0_RESET);
+       UNLOCK(flags);
+       udelay(10);
+
+       return 0;
+}
+
+
+#ifdef CONFIG_SMP
+static long g5_reset_cpu(struct device_node *node, long param, long value)
+{
+       unsigned int reset_io = 0;
+       unsigned long flags;
+       struct macio_chip *macio;
+       struct device_node *np;
+
+       macio = &macio_chips[0];
+       if (macio->type != macio_keylargo2)
+               return -ENODEV;
+
+       np = find_path_device("/cpus");
+       if (np == NULL)
+               return -ENODEV;
+       for (np = np->child; np != NULL; np = np->sibling) {
+               u32 *num = (u32 *)get_property(np, "reg", NULL);
+               u32 *rst = (u32 *)get_property(np, "soft-reset", NULL);
+               if (num == NULL || rst == NULL)
+                       continue;
+               if (param == *num) {
+                       reset_io = *rst;
+                       break;
+               }
+       }
+       if (np == NULL || reset_io == 0)
+               return -ENODEV;
+
+       LOCK(flags);
+       MACIO_OUT8(reset_io, KEYLARGO_GPIO_OUTPUT_ENABLE);
+       (void)MACIO_IN8(reset_io);
+       udelay(1);
+       MACIO_OUT8(reset_io, 0);
+       (void)MACIO_IN8(reset_io);
+       UNLOCK(flags);
+
+       return 0;
+}
+#endif /* CONFIG_SMP */
+
+/*
+ * This can be called from pmac_smp so isn't static
+ *
+ * This takes the second CPU off the bus on dual CPU machines
+ * running UP
+ */
+void g5_phy_disable_cpu1(void)
+{
+       UN_OUT(U3_API_PHY_CONFIG_1, 0);
+}
+#endif /* CONFIG_POWER4 */
+
+#ifndef CONFIG_POWER4
+
+static void
+keylargo_shutdown(struct macio_chip *macio, int sleep_mode)
+{
+       u32 temp;
+
+       if (sleep_mode) {
+               mdelay(1);
+               MACIO_BIS(KEYLARGO_FCR0, KL0_USB_REF_SUSPEND);
+               (void)MACIO_IN32(KEYLARGO_FCR0);
+               mdelay(1);
+       }
+
+       MACIO_BIC(KEYLARGO_FCR0,KL0_SCCA_ENABLE | KL0_SCCB_ENABLE |
+                               KL0_SCC_CELL_ENABLE |
+                               KL0_IRDA_ENABLE | KL0_IRDA_CLK32_ENABLE |
+                               KL0_IRDA_CLK19_ENABLE);
+
+       MACIO_BIC(KEYLARGO_MBCR, KL_MBCR_MB0_DEV_MASK);
+       MACIO_BIS(KEYLARGO_MBCR, KL_MBCR_MB0_IDE_ENABLE);
+
+       MACIO_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);
+
+       MACIO_BIS(KEYLARGO_FCR2, KL2_ALT_DATA_OUT);
+       MACIO_BIC(KEYLARGO_FCR2, KL2_IOBUS_ENABLE);
+
+       temp = MACIO_IN32(KEYLARGO_FCR3);
+       if (macio->rev >= 2) {
+               temp |= KL3_SHUTDOWN_PLL2X;
+               if (sleep_mode)
+                       temp |= KL3_SHUTDOWN_PLL_TOTAL;
+       }
+
+       temp |= KL3_SHUTDOWN_PLLKW6 | KL3_SHUTDOWN_PLLKW4 |
+               KL3_SHUTDOWN_PLLKW35;
+       if (sleep_mode)
+               temp |= KL3_SHUTDOWN_PLLKW12;
+       temp &= ~(KL3_CLK66_ENABLE | KL3_CLK49_ENABLE | KL3_CLK45_ENABLE
+               | KL3_CLK31_ENABLE | KL3_I2S1_CLK18_ENABLE | KL3_I2S0_CLK18_ENABLE);
+       if (sleep_mode)
+               temp &= ~(KL3_TIMER_CLK18_ENABLE | KL3_VIA_CLK16_ENABLE);
+       MACIO_OUT32(KEYLARGO_FCR3, temp);
+
+       /* Flush posted writes & wait a bit */
+       (void)MACIO_IN32(KEYLARGO_FCR0); mdelay(1);
+}
+
+static void
+pangea_shutdown(struct macio_chip *macio, int sleep_mode)
+{
+       u32 temp;
+
+       MACIO_BIC(KEYLARGO_FCR0,KL0_SCCA_ENABLE | KL0_SCCB_ENABLE |
+                               KL0_SCC_CELL_ENABLE |
+                               KL0_USB0_CELL_ENABLE | KL0_USB1_CELL_ENABLE);
+
+       MACIO_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_UIDE_ENABLE);
+       if (pmac_mb.board_flags & PMAC_MB_MOBILE)
+               MACIO_BIC(KEYLARGO_FCR1, KL1_UIDE_RESET_N);
+
+       MACIO_BIS(KEYLARGO_FCR2, KL2_ALT_DATA_OUT);
+
+       temp = MACIO_IN32(KEYLARGO_FCR3);
+       temp |= KL3_SHUTDOWN_PLLKW6 | KL3_SHUTDOWN_PLLKW4 |
+               KL3_SHUTDOWN_PLLKW35;
+       temp &= ~(KL3_CLK49_ENABLE | KL3_CLK45_ENABLE | KL3_CLK31_ENABLE
+               | KL3_I2S0_CLK18_ENABLE | KL3_I2S1_CLK18_ENABLE);
+       if (sleep_mode)
+               temp &= ~(KL3_VIA_CLK16_ENABLE | KL3_TIMER_CLK18_ENABLE);
+       MACIO_OUT32(KEYLARGO_FCR3, temp);
+
+       /* Flush posted writes & wait a bit */
+       (void)MACIO_IN32(KEYLARGO_FCR0); mdelay(1);
+}
+
+static void
+intrepid_shutdown(struct macio_chip *macio, int sleep_mode)
+{
+       u32 temp;
+
+       MACIO_BIC(KEYLARGO_FCR0,KL0_SCCA_ENABLE | KL0_SCCB_ENABLE |
+                 KL0_SCC_CELL_ENABLE);
+
+       MACIO_BIC(KEYLARGO_FCR1,
+                 /*KL1_USB2_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);
+       if (pmac_mb.board_flags & PMAC_MB_MOBILE)
+               MACIO_BIC(KEYLARGO_FCR1, KL1_UIDE_RESET_N);
+
+       temp = MACIO_IN32(KEYLARGO_FCR3);
+       temp &= ~(KL3_CLK49_ENABLE | KL3_CLK45_ENABLE |
+                 KL3_I2S1_CLK18_ENABLE | KL3_I2S0_CLK18_ENABLE);
+       if (sleep_mode)
+               temp &= ~(KL3_TIMER_CLK18_ENABLE | KL3_IT_VIA_CLK32_ENABLE);
+       MACIO_OUT32(KEYLARGO_FCR3, temp);
+
+       /* Flush posted writes & wait a bit */
+       (void)MACIO_IN32(KEYLARGO_FCR0);
+       mdelay(10);
+}
+
+
+void pmac_tweak_clock_spreading(int enable)
+{
+       struct macio_chip *macio = &macio_chips[0];
+
+       /* Hack for doing clock spreading on some machines PowerBooks and
+        * iBooks. This implements the "platform-do-clockspreading" OF
+        * property as decoded manually on various models. For safety, we also
+        * check the product ID in the device-tree in cases we'll whack the i2c
+        * chip to make reasonably sure we won't set wrong values in there
+        *
+        * Of course, ultimately, we have to implement a real parser for
+        * the platform-do-* stuff...
+        */
+
+       if (macio->type == macio_intrepid) {
+               if (enable)
+                       UN_OUT(UNI_N_CLOCK_SPREADING, 2);
+               else
+                       UN_OUT(UNI_N_CLOCK_SPREADING, 0);
+               mdelay(40);
+       }
+
+       while (machine_is_compatible("PowerBook5,2") ||
+              machine_is_compatible("PowerBook5,3") ||
+              machine_is_compatible("PowerBook6,2") ||
+              machine_is_compatible("PowerBook6,3")) {
+               struct device_node *ui2c = of_find_node_by_type(NULL, "i2c");
+               struct device_node *dt = of_find_node_by_name(NULL, "device-tree");
+               u8 buffer[9];
+               u32 *productID;
+               int i, rc, changed = 0;
+
+               if (dt == NULL)
+                       break;
+               productID = (u32 *)get_property(dt, "pid#", NULL);
+               if (productID == NULL)
+                       break;
+               while(ui2c) {
+                       struct device_node *p = of_get_parent(ui2c);
+                       if (p && !strcmp(p->name, "uni-n"))
+                               break;
+                       ui2c = of_find_node_by_type(ui2c, "i2c");
+               }
+               if (ui2c == NULL)
+                       break;
+               DBG("Trying to bump clock speed for PID: %08x...\n", *productID);
+               rc = pmac_low_i2c_open(ui2c, 1);
+               if (rc != 0)
+                       break;
+               pmac_low_i2c_setmode(ui2c, pmac_low_i2c_mode_combined);
+               rc = pmac_low_i2c_xfer(ui2c, 0xd2 | pmac_low_i2c_read, 0x80, buffer, 9);
+               DBG("read result: %d,", rc);
+               if (rc != 0) {
+                       pmac_low_i2c_close(ui2c);
+                       break;
+               }
+               for (i=0; i<9; i++)
+                       DBG(" %02x", buffer[i]);
+               DBG("\n");
+
+               switch(*productID) {
+               case 0x1182:    /* AlBook 12" rev 2 */
+               case 0x1183:    /* iBook G4 12" */
+                       buffer[0] = (buffer[0] & 0x8f) | 0x70;
+                       buffer[2] = (buffer[2] & 0x7f) | 0x00;
+                       buffer[5] = (buffer[5] & 0x80) | 0x31;
+                       buffer[6] = (buffer[6] & 0x40) | 0xb0;
+                       buffer[7] = (buffer[7] & 0x00) | (enable ? 0xc0 : 0xba);
+                       buffer[8] = (buffer[8] & 0x00) | 0x30;
+                       changed = 1;
+                       break;
+               case 0x3142:    /* AlBook 15" (ATI M10) */
+               case 0x3143:    /* AlBook 17" (ATI M10) */
+                       buffer[0] = (buffer[0] & 0xaf) | 0x50;
+                       buffer[2] = (buffer[2] & 0x7f) | 0x00;
+                       buffer[5] = (buffer[5] & 0x80) | 0x31;
+                       buffer[6] = (buffer[6] & 0x40) | 0xb0;
+                       buffer[7] = (buffer[7] & 0x00) | (enable ? 0xd0 : 0xc0);
+                       buffer[8] = (buffer[8] & 0x00) | 0x30;
+                       changed = 1;
+                       break;
+               default:
+                       DBG("i2c-hwclock: Machine model not handled\n");
+                       break;
+               }
+               if (!changed) {
+                       pmac_low_i2c_close(ui2c);
+                       break;
+               }
+               pmac_low_i2c_setmode(ui2c, pmac_low_i2c_mode_stdsub);
+               rc = pmac_low_i2c_xfer(ui2c, 0xd2 | pmac_low_i2c_write, 0x80, buffer, 9);
+               DBG("write result: %d,", rc);
+               pmac_low_i2c_setmode(ui2c, pmac_low_i2c_mode_combined);
+               rc = pmac_low_i2c_xfer(ui2c, 0xd2 | pmac_low_i2c_read, 0x80, buffer, 9);
+               DBG("read result: %d,", rc);
+               if (rc != 0) {
+                       pmac_low_i2c_close(ui2c);
+                       break;
+               }
+               for (i=0; i<9; i++)
+                       DBG(" %02x", buffer[i]);
+               pmac_low_i2c_close(ui2c);
+               break;
+       }
+}
+
+
+static int
+core99_sleep(void)
+{
+       struct macio_chip *macio;
+       int i;
+
+       macio = &macio_chips[0];
+       if (macio->type != macio_keylargo && macio->type != macio_pangea &&
+           macio->type != macio_intrepid)
+               return -ENODEV;
+
+       /* We power off the wireless slot in case it was not done
+        * by the driver. We don't power it on automatically however
+        */
+       if (macio->flags & MACIO_FLAG_AIRPORT_ON)
+               core99_airport_enable(macio->of_node, 0, 0);
+
+       /* We power off the FW cable. Should be done by the driver... */
+       if (macio->flags & MACIO_FLAG_FW_SUPPORTED) {
+               core99_firewire_enable(NULL, 0, 0);
+               core99_firewire_cable_power(NULL, 0, 0);
+       }
+
+       /* We make sure int. modem is off (in case driver lost it) */
+       if (macio->type == macio_keylargo)
+               core99_modem_enable(macio->of_node, 0, 0);
+       else
+               pangea_modem_enable(macio->of_node, 0, 0);
+
+       /* We make sure the sound is off as well */
+       core99_sound_chip_enable(macio->of_node, 0, 0);
+
+       /*
+        * Save various bits of KeyLargo
+        */
+
+       /* Save the state of the various GPIOs */
+       save_gpio_levels[0] = MACIO_IN32(KEYLARGO_GPIO_LEVELS0);
+       save_gpio_levels[1] = MACIO_IN32(KEYLARGO_GPIO_LEVELS1);
+       for (i=0; i<KEYLARGO_GPIO_EXTINT_CNT; i++)
+               save_gpio_extint[i] = MACIO_IN8(KEYLARGO_GPIO_EXTINT_0+i);
+       for (i=0; i<KEYLARGO_GPIO_CNT; i++)
+               save_gpio_normal[i] = MACIO_IN8(KEYLARGO_GPIO_0+i);
+
+       /* Save the FCRs */
+       if (macio->type == macio_keylargo)
+               save_mbcr = MACIO_IN32(KEYLARGO_MBCR);
+       save_fcr[0] = MACIO_IN32(KEYLARGO_FCR0);
+       save_fcr[1] = MACIO_IN32(KEYLARGO_FCR1);
+       save_fcr[2] = MACIO_IN32(KEYLARGO_FCR2);
+       save_fcr[3] = MACIO_IN32(KEYLARGO_FCR3);
+       save_fcr[4] = MACIO_IN32(KEYLARGO_FCR4);
+       if (macio->type == macio_pangea || macio->type == macio_intrepid)
+               save_fcr[5] = MACIO_IN32(KEYLARGO_FCR5);
+
+       /* Save state & config of DBDMA channels */
+       dbdma_save(macio, save_dbdma);
+
+       /*
+        * Turn off as much as we can
+        */
+       if (macio->type == macio_pangea)
+               pangea_shutdown(macio, 1);
+       else if (macio->type == macio_intrepid)
+               intrepid_shutdown(macio, 1);
+       else if (macio->type == macio_keylargo)
+               keylargo_shutdown(macio, 1);
+
+       /*
+        * Put the host bridge to sleep
+        */
+
+       save_unin_clock_ctl = UN_IN(UNI_N_CLOCK_CNTL);
+       /* Note: do not switch GMAC off, driver does it when necessary, WOL must keep it
+        * enabled !
+        */
+       UN_OUT(UNI_N_CLOCK_CNTL, save_unin_clock_ctl &
+              ~(/*UNI_N_CLOCK_CNTL_GMAC|*/UNI_N_CLOCK_CNTL_FW/*|UNI_N_CLOCK_CNTL_PCI*/));
+       udelay(100);
+       UN_OUT(UNI_N_HWINIT_STATE, UNI_N_HWINIT_STATE_SLEEPING);
+       UN_OUT(UNI_N_POWER_MGT, UNI_N_POWER_MGT_SLEEP);
+       mdelay(10);
+
+       /*
+        * FIXME: A bit of black magic with OpenPIC (don't ask me why)
+        */
+       if (pmac_mb.model_id == PMAC_TYPE_SAWTOOTH) {
+               MACIO_BIS(0x506e0, 0x00400000);
+               MACIO_BIS(0x506e0, 0x80000000);
+       }
+       return 0;
+}
+
+static int
+core99_wake_up(void)
+{
+       struct macio_chip *macio;
+       int i;
+
+       macio = &macio_chips[0];
+       if (macio->type != macio_keylargo && macio->type != macio_pangea &&
+           macio->type != macio_intrepid)
+               return -ENODEV;
+
+       /*
+        * Wakeup the host bridge
+        */
+       UN_OUT(UNI_N_POWER_MGT, UNI_N_POWER_MGT_NORMAL);
+       udelay(10);
+       UN_OUT(UNI_N_HWINIT_STATE, UNI_N_HWINIT_STATE_RUNNING);
+       udelay(10);
+
+       /*
+        * Restore KeyLargo
+        */
+
+       if (macio->type == macio_keylargo) {
+               MACIO_OUT32(KEYLARGO_MBCR, save_mbcr);
+               (void)MACIO_IN32(KEYLARGO_MBCR); udelay(10);
+       }
+       MACIO_OUT32(KEYLARGO_FCR0, save_fcr[0]);
+       (void)MACIO_IN32(KEYLARGO_FCR0); udelay(10);
+       MACIO_OUT32(KEYLARGO_FCR1, save_fcr[1]);
+       (void)MACIO_IN32(KEYLARGO_FCR1); udelay(10);
+       MACIO_OUT32(KEYLARGO_FCR2, save_fcr[2]);
+       (void)MACIO_IN32(KEYLARGO_FCR2); udelay(10);
+       MACIO_OUT32(KEYLARGO_FCR3, save_fcr[3]);
+       (void)MACIO_IN32(KEYLARGO_FCR3); udelay(10);
+       MACIO_OUT32(KEYLARGO_FCR4, save_fcr[4]);
+       (void)MACIO_IN32(KEYLARGO_FCR4); udelay(10);
+       if (macio->type == macio_pangea || macio->type == macio_intrepid) {
+               MACIO_OUT32(KEYLARGO_FCR5, save_fcr[5]);
+               (void)MACIO_IN32(KEYLARGO_FCR5); udelay(10);
+       }
+
+       dbdma_restore(macio, save_dbdma);
+
+       MACIO_OUT32(KEYLARGO_GPIO_LEVELS0, save_gpio_levels[0]);
+       MACIO_OUT32(KEYLARGO_GPIO_LEVELS1, save_gpio_levels[1]);
+       for (i=0; i<KEYLARGO_GPIO_EXTINT_CNT; i++)
+               MACIO_OUT8(KEYLARGO_GPIO_EXTINT_0+i, save_gpio_extint[i]);
+       for (i=0; i<KEYLARGO_GPIO_CNT; i++)
+               MACIO_OUT8(KEYLARGO_GPIO_0+i, save_gpio_normal[i]);
+
+       /* FIXME more black magic with OpenPIC ... */
+       if (pmac_mb.model_id == PMAC_TYPE_SAWTOOTH) {
+               MACIO_BIC(0x506e0, 0x00400000);
+               MACIO_BIC(0x506e0, 0x80000000);
+       }
+
+       UN_OUT(UNI_N_CLOCK_CNTL, save_unin_clock_ctl);
+       udelay(100);
+
+       return 0;
+}
+
+static long
+core99_sleep_state(struct device_node *node, long param, long value)
+{
+       /* Param == 1 means to enter the "fake sleep" mode that is
+        * used for CPU speed switch
+        */
+       if (param == 1) {
+               if (value == 1) {
+                       UN_OUT(UNI_N_HWINIT_STATE, UNI_N_HWINIT_STATE_SLEEPING);
+                       UN_OUT(UNI_N_POWER_MGT, UNI_N_POWER_MGT_IDLE2);
+               } else {
+                       UN_OUT(UNI_N_POWER_MGT, UNI_N_POWER_MGT_NORMAL);
+                       udelay(10);
+                       UN_OUT(UNI_N_HWINIT_STATE, UNI_N_HWINIT_STATE_RUNNING);
+                       udelay(10);
+               }
+               return 0;
+       }
+       if ((pmac_mb.board_flags & PMAC_MB_CAN_SLEEP) == 0)
+               return -EPERM;
+
+       if (value == 1)
+               return core99_sleep();
+       else if (value == 0)
+               return core99_wake_up();
+       return 0;
+}
+
+#endif /* CONFIG_POWER4 */
+
+static long
+generic_dev_can_wake(struct device_node *node, long param, long value)
+{
+       /* Todo: eventually check we are really dealing with on-board
+        * video device ...
+        */
+
+       if (pmac_mb.board_flags & PMAC_MB_MAY_SLEEP)
+               pmac_mb.board_flags |= PMAC_MB_CAN_SLEEP;
+       return 0;
+}
+
+static long generic_get_mb_info(struct device_node *node, long param, long value)
+{
+       switch(param) {
+               case PMAC_MB_INFO_MODEL:
+                       return pmac_mb.model_id;
+               case PMAC_MB_INFO_FLAGS:
+                       return pmac_mb.board_flags;
+               case PMAC_MB_INFO_NAME:
+                       /* hack hack hack... but should work */
+                       *((const char **)value) = pmac_mb.model_name;
+                       return 0;
+       }
+       return -EINVAL;
+}
+
+
+/*
+ * Table definitions
+ */
+
+/* Used on any machine
+ */
+static struct feature_table_entry any_features[] = {
+       { PMAC_FTR_GET_MB_INFO,         generic_get_mb_info },
+       { PMAC_FTR_DEVICE_CAN_WAKE,     generic_dev_can_wake },
+       { 0, NULL }
+};
+
+#ifndef CONFIG_POWER4
+
+/* OHare based motherboards. Currently, we only use these on the
+ * 2400,3400 and 3500 series powerbooks. Some older desktops seem
+ * to have issues with turning on/off those asic cells
+ */
+static struct feature_table_entry ohare_features[] = {
+       { PMAC_FTR_SCC_ENABLE,          ohare_htw_scc_enable },
+       { PMAC_FTR_SWIM3_ENABLE,        ohare_floppy_enable },
+       { PMAC_FTR_MESH_ENABLE,         ohare_mesh_enable },
+       { PMAC_FTR_IDE_ENABLE,          ohare_ide_enable},
+       { PMAC_FTR_IDE_RESET,           ohare_ide_reset},
+       { PMAC_FTR_SLEEP_STATE,         ohare_sleep_state },
+       { 0, NULL }
+};
+
+/* Heathrow desktop machines (Beige G3).
+ * Separated as some features couldn't be properly tested
+ * and the serial port control bits appear to confuse it.
+ */
+static struct feature_table_entry heathrow_desktop_features[] = {
+       { PMAC_FTR_SWIM3_ENABLE,        heathrow_floppy_enable },
+       { PMAC_FTR_MESH_ENABLE,         heathrow_mesh_enable },
+       { PMAC_FTR_IDE_ENABLE,          heathrow_ide_enable },
+       { PMAC_FTR_IDE_RESET,           heathrow_ide_reset },
+       { PMAC_FTR_BMAC_ENABLE,         heathrow_bmac_enable },
+       { 0, NULL }
+};
+
+/* Heathrow based laptop, that is the Wallstreet and mainstreet
+ * powerbooks.
+ */
+static struct feature_table_entry heathrow_laptop_features[] = {
+       { PMAC_FTR_SCC_ENABLE,          ohare_htw_scc_enable },
+       { PMAC_FTR_MODEM_ENABLE,        heathrow_modem_enable },
+       { PMAC_FTR_SWIM3_ENABLE,        heathrow_floppy_enable },
+       { PMAC_FTR_MESH_ENABLE,         heathrow_mesh_enable },
+       { PMAC_FTR_IDE_ENABLE,          heathrow_ide_enable },
+       { PMAC_FTR_IDE_RESET,           heathrow_ide_reset },
+       { PMAC_FTR_BMAC_ENABLE,         heathrow_bmac_enable },
+       { PMAC_FTR_SOUND_CHIP_ENABLE,   heathrow_sound_enable },
+       { PMAC_FTR_SLEEP_STATE,         heathrow_sleep_state },
+       { 0, NULL }
+};
+
+/* Paddington based machines
+ * The lombard (101) powerbook, first iMac models, B&W G3 and Yikes G4.
+ */
+static struct feature_table_entry paddington_features[] = {
+       { PMAC_FTR_SCC_ENABLE,          ohare_htw_scc_enable },
+       { PMAC_FTR_MODEM_ENABLE,        heathrow_modem_enable },
+       { PMAC_FTR_SWIM3_ENABLE,        heathrow_floppy_enable },
+       { PMAC_FTR_MESH_ENABLE,         heathrow_mesh_enable },
+       { PMAC_FTR_IDE_ENABLE,          heathrow_ide_enable },
+       { PMAC_FTR_IDE_RESET,           heathrow_ide_reset },
+       { PMAC_FTR_BMAC_ENABLE,         heathrow_bmac_enable },
+       { PMAC_FTR_SOUND_CHIP_ENABLE,   heathrow_sound_enable },
+       { PMAC_FTR_SLEEP_STATE,         heathrow_sleep_state },
+       { 0, NULL }
+};
+
+/* Core99 & MacRISC 2 machines (all machines released since the
+ * iBook (included), that is all AGP machines, except pangea
+ * chipset. The pangea chipset is the "combo" UniNorth/KeyLargo
+ * used on iBook2 & iMac "flow power".
+ */
+static struct feature_table_entry core99_features[] = {
+       { PMAC_FTR_SCC_ENABLE,          core99_scc_enable },
+       { PMAC_FTR_MODEM_ENABLE,        core99_modem_enable },
+       { PMAC_FTR_IDE_ENABLE,          core99_ide_enable },
+       { PMAC_FTR_IDE_RESET,           core99_ide_reset },
+       { PMAC_FTR_GMAC_ENABLE,         core99_gmac_enable },
+       { PMAC_FTR_GMAC_PHY_RESET,      core99_gmac_phy_reset },
+       { PMAC_FTR_SOUND_CHIP_ENABLE,   core99_sound_chip_enable },
+       { PMAC_FTR_AIRPORT_ENABLE,      core99_airport_enable },
+       { PMAC_FTR_USB_ENABLE,          core99_usb_enable },
+       { PMAC_FTR_1394_ENABLE,         core99_firewire_enable },
+       { PMAC_FTR_1394_CABLE_POWER,    core99_firewire_cable_power },
+       { PMAC_FTR_SLEEP_STATE,         core99_sleep_state },
+#ifdef CONFIG_SMP
+       { PMAC_FTR_RESET_CPU,           core99_reset_cpu },
+#endif /* CONFIG_SMP */
+       { PMAC_FTR_READ_GPIO,           core99_read_gpio },
+       { PMAC_FTR_WRITE_GPIO,          core99_write_gpio },
+       { 0, NULL }
+};
+
+/* RackMac
+ */
+static struct feature_table_entry rackmac_features[] = {
+       { PMAC_FTR_SCC_ENABLE,          core99_scc_enable },
+       { PMAC_FTR_IDE_ENABLE,          core99_ide_enable },
+       { PMAC_FTR_IDE_RESET,           core99_ide_reset },
+       { PMAC_FTR_GMAC_ENABLE,         core99_gmac_enable },
+       { PMAC_FTR_GMAC_PHY_RESET,      core99_gmac_phy_reset },
+       { PMAC_FTR_USB_ENABLE,          core99_usb_enable },
+       { PMAC_FTR_1394_ENABLE,         core99_firewire_enable },
+       { PMAC_FTR_1394_CABLE_POWER,    core99_firewire_cable_power },
+       { PMAC_FTR_SLEEP_STATE,         core99_sleep_state },
+#ifdef CONFIG_SMP
+       { PMAC_FTR_RESET_CPU,           core99_reset_cpu },
+#endif /* CONFIG_SMP */
+       { PMAC_FTR_READ_GPIO,           core99_read_gpio },
+       { PMAC_FTR_WRITE_GPIO,          core99_write_gpio },
+       { 0, NULL }
+};
+
+/* Pangea features
+ */
+static struct feature_table_entry pangea_features[] = {
+       { PMAC_FTR_SCC_ENABLE,          core99_scc_enable },
+       { PMAC_FTR_MODEM_ENABLE,        pangea_modem_enable },
+       { PMAC_FTR_IDE_ENABLE,          core99_ide_enable },
+       { PMAC_FTR_IDE_RESET,           core99_ide_reset },
+       { PMAC_FTR_GMAC_ENABLE,         core99_gmac_enable },
+       { PMAC_FTR_GMAC_PHY_RESET,      core99_gmac_phy_reset },
+       { PMAC_FTR_SOUND_CHIP_ENABLE,   core99_sound_chip_enable },
+       { PMAC_FTR_AIRPORT_ENABLE,      core99_airport_enable },
+       { PMAC_FTR_USB_ENABLE,          core99_usb_enable },
+       { PMAC_FTR_1394_ENABLE,         core99_firewire_enable },
+       { PMAC_FTR_1394_CABLE_POWER,    core99_firewire_cable_power },
+       { PMAC_FTR_SLEEP_STATE,         core99_sleep_state },
+       { PMAC_FTR_READ_GPIO,           core99_read_gpio },
+       { PMAC_FTR_WRITE_GPIO,          core99_write_gpio },
+       { 0, NULL }
+};
+
+/* Intrepid features
+ */
+static struct feature_table_entry intrepid_features[] = {
+       { PMAC_FTR_SCC_ENABLE,          core99_scc_enable },
+       { PMAC_FTR_MODEM_ENABLE,        pangea_modem_enable },
+       { PMAC_FTR_IDE_ENABLE,          core99_ide_enable },
+       { PMAC_FTR_IDE_RESET,           core99_ide_reset },
+       { PMAC_FTR_GMAC_ENABLE,         core99_gmac_enable },
+       { PMAC_FTR_GMAC_PHY_RESET,      core99_gmac_phy_reset },
+       { PMAC_FTR_SOUND_CHIP_ENABLE,   core99_sound_chip_enable },
+       { PMAC_FTR_AIRPORT_ENABLE,      core99_airport_enable },
+       { PMAC_FTR_USB_ENABLE,          core99_usb_enable },
+       { PMAC_FTR_1394_ENABLE,         core99_firewire_enable },
+       { PMAC_FTR_1394_CABLE_POWER,    core99_firewire_cable_power },
+       { PMAC_FTR_SLEEP_STATE,         core99_sleep_state },
+       { PMAC_FTR_READ_GPIO,           core99_read_gpio },
+       { PMAC_FTR_WRITE_GPIO,          core99_write_gpio },
+       { PMAC_FTR_AACK_DELAY_ENABLE,   intrepid_aack_delay_enable },
+       { 0, NULL }
+};
+
+#else /* CONFIG_POWER4 */
+
+/* G5 features
+ */
+static struct feature_table_entry g5_features[] = {
+       { PMAC_FTR_GMAC_ENABLE,         g5_gmac_enable },
+       { PMAC_FTR_1394_ENABLE,         g5_fw_enable },
+       { PMAC_FTR_ENABLE_MPIC,         g5_mpic_enable },
+       { PMAC_FTR_GMAC_PHY_RESET,      g5_eth_phy_reset },
+       { PMAC_FTR_SOUND_CHIP_ENABLE,   g5_i2s_enable },
+#ifdef CONFIG_SMP
+       { PMAC_FTR_RESET_CPU,           g5_reset_cpu },
+#endif /* CONFIG_SMP */
+       { PMAC_FTR_READ_GPIO,           core99_read_gpio },
+       { PMAC_FTR_WRITE_GPIO,          core99_write_gpio },
+       { 0, NULL }
+};
+
+#endif /* CONFIG_POWER4 */
+
+static struct pmac_mb_def pmac_mb_defs[] = {
+#ifndef CONFIG_POWER4
+       /*
+        * Desktops
+        */
+
+       {       "AAPL,8500",                    "PowerMac 8500/8600",
+               PMAC_TYPE_PSURGE,               NULL,
+               0
+       },
+       {       "AAPL,9500",                    "PowerMac 9500/9600",
+               PMAC_TYPE_PSURGE,               NULL,
+               0
+       },
+       {       "AAPL,7200",                    "PowerMac 7200",
+               PMAC_TYPE_PSURGE,               NULL,
+               0
+       },
+       {       "AAPL,7300",                    "PowerMac 7200/7300",
+               PMAC_TYPE_PSURGE,               NULL,
+               0
+       },
+       {       "AAPL,7500",                    "PowerMac 7500",
+               PMAC_TYPE_PSURGE,               NULL,
+               0
+       },
+       {       "AAPL,ShinerESB",               "Apple Network Server",
+               PMAC_TYPE_ANS,                  NULL,
+               0
+       },
+       {       "AAPL,e407",                    "Alchemy",
+               PMAC_TYPE_ALCHEMY,              NULL,
+               0
+       },
+       {       "AAPL,e411",                    "Gazelle",
+               PMAC_TYPE_GAZELLE,              NULL,
+               0
+       },
+       {       "AAPL,Gossamer",                "PowerMac G3 (Gossamer)",
+               PMAC_TYPE_GOSSAMER,             heathrow_desktop_features,
+               0
+       },
+       {       "AAPL,PowerMac G3",             "PowerMac G3 (Silk)",
+               PMAC_TYPE_SILK,                 heathrow_desktop_features,
+               0
+       },
+       {       "PowerMac1,1",                  "Blue&White G3",
+               PMAC_TYPE_YOSEMITE,             paddington_features,
+               0
+       },
+       {       "PowerMac1,2",                  "PowerMac G4 PCI Graphics",
+               PMAC_TYPE_YIKES,                paddington_features,
+               0
+       },
+       {       "PowerMac2,1",                  "iMac FireWire",
+               PMAC_TYPE_FW_IMAC,              core99_features,
+               PMAC_MB_MAY_SLEEP | PMAC_MB_OLD_CORE99
+       },
+       {       "PowerMac2,2",                  "iMac FireWire",
+               PMAC_TYPE_FW_IMAC,              core99_features,
+               PMAC_MB_MAY_SLEEP | PMAC_MB_OLD_CORE99
+       },
+       {       "PowerMac3,1",                  "PowerMac G4 AGP Graphics",
+               PMAC_TYPE_SAWTOOTH,             core99_features,
+               PMAC_MB_OLD_CORE99
+       },
+       {       "PowerMac3,2",                  "PowerMac G4 AGP Graphics",
+               PMAC_TYPE_SAWTOOTH,             core99_features,
+               PMAC_MB_MAY_SLEEP | PMAC_MB_OLD_CORE99
+       },
+       {       "PowerMac3,3",                  "PowerMac G4 AGP Graphics",
+               PMAC_TYPE_SAWTOOTH,             core99_features,
+               PMAC_MB_MAY_SLEEP | PMAC_MB_OLD_CORE99
+       },
+       {       "PowerMac3,4",                  "PowerMac G4 Silver",
+               PMAC_TYPE_QUICKSILVER,          core99_features,
+               PMAC_MB_MAY_SLEEP
+       },
+       {       "PowerMac3,5",                  "PowerMac G4 Silver",
+               PMAC_TYPE_QUICKSILVER,          core99_features,
+               PMAC_MB_MAY_SLEEP
+       },
+       {       "PowerMac3,6",                  "PowerMac G4 Windtunnel",
+               PMAC_TYPE_WINDTUNNEL,           core99_features,
+               PMAC_MB_MAY_SLEEP,
+       },
+       {       "PowerMac4,1",                  "iMac \"Flower Power\"",
+               PMAC_TYPE_PANGEA_IMAC,          pangea_features,
+               PMAC_MB_MAY_SLEEP
+       },
+       {       "PowerMac4,2",                  "Flat panel iMac",
+               PMAC_TYPE_FLAT_PANEL_IMAC,      pangea_features,
+               PMAC_MB_CAN_SLEEP
+       },
+       {       "PowerMac4,4",                  "eMac",
+               PMAC_TYPE_EMAC,                 core99_features,
+               PMAC_MB_MAY_SLEEP
+       },
+       {       "PowerMac5,1",                  "PowerMac G4 Cube",
+               PMAC_TYPE_CUBE,                 core99_features,
+               PMAC_MB_MAY_SLEEP | PMAC_MB_OLD_CORE99
+       },
+       {       "PowerMac6,1",                  "Flat panel iMac",
+               PMAC_TYPE_UNKNOWN_INTREPID,     intrepid_features,
+               PMAC_MB_MAY_SLEEP,
+       },
+       {       "PowerMac6,3",                  "Flat panel iMac",
+               PMAC_TYPE_UNKNOWN_INTREPID,     intrepid_features,
+               PMAC_MB_MAY_SLEEP,
+       },
+       {       "PowerMac6,4",                  "eMac",
+               PMAC_TYPE_UNKNOWN_INTREPID,     intrepid_features,
+               PMAC_MB_MAY_SLEEP,
+       },
+       {       "PowerMac10,1",                 "Mac mini",
+               PMAC_TYPE_UNKNOWN_INTREPID,     intrepid_features,
+               PMAC_MB_MAY_SLEEP | PMAC_MB_HAS_FW_POWER,
+       },
+       {       "iMac,1",                       "iMac (first generation)",
+               PMAC_TYPE_ORIG_IMAC,            paddington_features,
+               0
+       },
+
+       /*
+        * Xserve's
+        */
+
+       {       "RackMac1,1",                   "XServe",
+               PMAC_TYPE_RACKMAC,              rackmac_features,
+               0,
+       },
+       {       "RackMac1,2",                   "XServe rev. 2",
+               PMAC_TYPE_RACKMAC,              rackmac_features,
+               0,
+       },
+
+       /*
+        * Laptops
+        */
+
+       {       "AAPL,3400/2400",               "PowerBook 3400",
+               PMAC_TYPE_HOOPER,               ohare_features,
+               PMAC_MB_CAN_SLEEP | PMAC_MB_MOBILE
+       },
+       {       "AAPL,3500",                    "PowerBook 3500",
+               PMAC_TYPE_KANGA,                ohare_features,
+               PMAC_MB_CAN_SLEEP | PMAC_MB_MOBILE
+       },
+       {       "AAPL,PowerBook1998",           "PowerBook Wallstreet",
+               PMAC_TYPE_WALLSTREET,           heathrow_laptop_features,
+               PMAC_MB_CAN_SLEEP | PMAC_MB_MOBILE
+       },
+       {       "PowerBook1,1",                 "PowerBook 101 (Lombard)",
+               PMAC_TYPE_101_PBOOK,            paddington_features,
+               PMAC_MB_CAN_SLEEP | PMAC_MB_MOBILE
+       },
+       {       "PowerBook2,1",                 "iBook (first generation)",
+               PMAC_TYPE_ORIG_IBOOK,           core99_features,
+               PMAC_MB_CAN_SLEEP | PMAC_MB_OLD_CORE99 | PMAC_MB_MOBILE
+       },
+       {       "PowerBook2,2",                 "iBook FireWire",
+               PMAC_TYPE_FW_IBOOK,             core99_features,
+               PMAC_MB_MAY_SLEEP | PMAC_MB_HAS_FW_POWER |
+               PMAC_MB_OLD_CORE99 | PMAC_MB_MOBILE
+       },
+       {       "PowerBook3,1",                 "PowerBook Pismo",
+               PMAC_TYPE_PISMO,                core99_features,
+               PMAC_MB_MAY_SLEEP | PMAC_MB_HAS_FW_POWER |
+               PMAC_MB_OLD_CORE99 | PMAC_MB_MOBILE
+       },
+       {       "PowerBook3,2",                 "PowerBook Titanium",
+               PMAC_TYPE_TITANIUM,             core99_features,
+               PMAC_MB_MAY_SLEEP | PMAC_MB_HAS_FW_POWER | PMAC_MB_MOBILE
+       },
+       {       "PowerBook3,3",                 "PowerBook Titanium II",
+               PMAC_TYPE_TITANIUM2,            core99_features,
+               PMAC_MB_MAY_SLEEP | PMAC_MB_HAS_FW_POWER | PMAC_MB_MOBILE
+       },
+       {       "PowerBook3,4",                 "PowerBook Titanium III",
+               PMAC_TYPE_TITANIUM3,            core99_features,
+               PMAC_MB_MAY_SLEEP | PMAC_MB_HAS_FW_POWER | PMAC_MB_MOBILE
+       },
+       {       "PowerBook3,5",                 "PowerBook Titanium IV",
+               PMAC_TYPE_TITANIUM4,            core99_features,
+               PMAC_MB_MAY_SLEEP | PMAC_MB_HAS_FW_POWER | PMAC_MB_MOBILE
+       },
+       {       "PowerBook4,1",                 "iBook 2",
+               PMAC_TYPE_IBOOK2,               pangea_features,
+               PMAC_MB_MAY_SLEEP | PMAC_MB_HAS_FW_POWER | PMAC_MB_MOBILE
+       },
+       {       "PowerBook4,2",                 "iBook 2",
+               PMAC_TYPE_IBOOK2,               pangea_features,
+               PMAC_MB_MAY_SLEEP | PMAC_MB_HAS_FW_POWER | PMAC_MB_MOBILE
+       },
+       {       "PowerBook4,3",                 "iBook 2 rev. 2",
+               PMAC_TYPE_IBOOK2,               pangea_features,
+               PMAC_MB_MAY_SLEEP | PMAC_MB_HAS_FW_POWER | PMAC_MB_MOBILE
+       },
+       {       "PowerBook5,1",                 "PowerBook G4 17\"",
+               PMAC_TYPE_UNKNOWN_INTREPID,     intrepid_features,
+               PMAC_MB_HAS_FW_POWER | PMAC_MB_MOBILE,
+       },
+       {       "PowerBook5,2",                 "PowerBook G4 15\"",
+               PMAC_TYPE_UNKNOWN_INTREPID,     intrepid_features,
+               PMAC_MB_MAY_SLEEP | PMAC_MB_HAS_FW_POWER | PMAC_MB_MOBILE,
+       },
+       {       "PowerBook5,3",                 "PowerBook G4 17\"",
+               PMAC_TYPE_UNKNOWN_INTREPID,     intrepid_features,
+               PMAC_MB_MAY_SLEEP | PMAC_MB_HAS_FW_POWER | PMAC_MB_MOBILE,
+       },
+       {       "PowerBook5,4",                 "PowerBook G4 15\"",
+               PMAC_TYPE_UNKNOWN_INTREPID,     intrepid_features,
+               PMAC_MB_MAY_SLEEP | PMAC_MB_HAS_FW_POWER | PMAC_MB_MOBILE,
+       },
+       {       "PowerBook5,5",                 "PowerBook G4 17\"",
+               PMAC_TYPE_UNKNOWN_INTREPID,     intrepid_features,
+               PMAC_MB_MAY_SLEEP | PMAC_MB_HAS_FW_POWER | PMAC_MB_MOBILE,
+       },
+       {       "PowerBook5,6",                 "PowerBook G4 15\"",
+               PMAC_TYPE_UNKNOWN_INTREPID,     intrepid_features,
+               PMAC_MB_MAY_SLEEP | PMAC_MB_HAS_FW_POWER | PMAC_MB_MOBILE,
+       },
+       {       "PowerBook5,7",                 "PowerBook G4 17\"",
+               PMAC_TYPE_UNKNOWN_INTREPID,     intrepid_features,
+               PMAC_MB_MAY_SLEEP | PMAC_MB_HAS_FW_POWER | PMAC_MB_MOBILE,
+       },
+       {       "PowerBook6,1",                 "PowerBook G4 12\"",
+               PMAC_TYPE_UNKNOWN_INTREPID,     intrepid_features,
+               PMAC_MB_MAY_SLEEP | PMAC_MB_HAS_FW_POWER | PMAC_MB_MOBILE,
+       },
+       {       "PowerBook6,2",                 "PowerBook G4",
+               PMAC_TYPE_UNKNOWN_INTREPID,     intrepid_features,
+               PMAC_MB_MAY_SLEEP | PMAC_MB_HAS_FW_POWER | PMAC_MB_MOBILE,
+       },
+       {       "PowerBook6,3",                 "iBook G4",
+               PMAC_TYPE_UNKNOWN_INTREPID,     intrepid_features,
+               PMAC_MB_MAY_SLEEP | PMAC_MB_HAS_FW_POWER | PMAC_MB_MOBILE,
+       },
+       {       "PowerBook6,4",                 "PowerBook G4 12\"",
+               PMAC_TYPE_UNKNOWN_INTREPID,     intrepid_features,
+               PMAC_MB_MAY_SLEEP | PMAC_MB_HAS_FW_POWER | PMAC_MB_MOBILE,
+       },
+       {       "PowerBook6,5",                 "iBook G4",
+               PMAC_TYPE_UNKNOWN_INTREPID,     intrepid_features,
+               PMAC_MB_MAY_SLEEP | PMAC_MB_HAS_FW_POWER | PMAC_MB_MOBILE,
+       },
+       {       "PowerBook6,8",                 "PowerBook G4 12\"",
+               PMAC_TYPE_UNKNOWN_INTREPID,     intrepid_features,
+               PMAC_MB_MAY_SLEEP | PMAC_MB_HAS_FW_POWER | PMAC_MB_MOBILE,
+       },
+#else /* CONFIG_POWER4 */
+       {       "PowerMac7,2",                  "PowerMac G5",
+               PMAC_TYPE_POWERMAC_G5,          g5_features,
+               0,
+       },
+#ifdef CONFIG_PPC64
+       {       "PowerMac7,3",                  "PowerMac G5",
+               PMAC_TYPE_POWERMAC_G5,          g5_features,
+               0,
+       },
+       {       "PowerMac8,1",                  "iMac G5",
+               PMAC_TYPE_IMAC_G5,              g5_features,
+               0,
+       },
+       {       "PowerMac9,1",                  "PowerMac G5",
+               PMAC_TYPE_POWERMAC_G5_U3L,      g5_features,
+               0,
+       },
+       {       "RackMac3,1",                   "XServe G5",
+               PMAC_TYPE_XSERVE_G5,            g5_features,
+               0,
+       },
+#endif /* CONFIG_PPC64 */
+#endif /* CONFIG_POWER4 */
+};
+
+/*
+ * The toplevel feature_call callback
+ */
+long pmac_do_feature_call(unsigned int selector, ...)
+{
+       struct device_node *node;
+       long param, value;
+       int i;
+       feature_call func = NULL;
+       va_list args;
+
+       if (pmac_mb.features)
+               for (i=0; pmac_mb.features[i].function; i++)
+                       if (pmac_mb.features[i].selector == selector) {
+                               func = pmac_mb.features[i].function;
+                               break;
+                       }
+       if (!func)
+               for (i=0; any_features[i].function; i++)
+                       if (any_features[i].selector == selector) {
+                               func = any_features[i].function;
+                               break;
+                       }
+       if (!func)
+               return -ENODEV;
+
+       va_start(args, selector);
+       node = (struct device_node*)va_arg(args, void*);
+       param = va_arg(args, long);
+       value = va_arg(args, long);
+       va_end(args);
+
+       return func(node, param, value);
+}
+
+static int __init probe_motherboard(void)
+{
+       int i;
+       struct macio_chip *macio = &macio_chips[0];
+       const char *model = NULL;
+       struct device_node *dt;
+
+       /* Lookup known motherboard type in device-tree. First try an
+        * exact match on the "model" property, then try a "compatible"
+        * match is none is found.
+        */
+       dt = find_devices("device-tree");
+       if (dt != NULL)
+               model = (const char *) get_property(dt, "model", NULL);
+       for(i=0; model && i<(sizeof(pmac_mb_defs)/sizeof(struct pmac_mb_def)); i++) {
+           if (strcmp(model, pmac_mb_defs[i].model_string) == 0) {
+               pmac_mb = pmac_mb_defs[i];
+               goto found;
+           }
+       }
+       for(i=0; i<(sizeof(pmac_mb_defs)/sizeof(struct pmac_mb_def)); i++) {
+           if (machine_is_compatible(pmac_mb_defs[i].model_string)) {
+               pmac_mb = pmac_mb_defs[i];
+               goto found;
+           }
+       }
+
+       /* Fallback to selection depending on mac-io chip type */
+       switch(macio->type) {
+#ifndef CONFIG_POWER4
+           case macio_grand_central:
+               pmac_mb.model_id = PMAC_TYPE_PSURGE;
+               pmac_mb.model_name = "Unknown PowerSurge";
+               break;
+           case macio_ohare:
+               pmac_mb.model_id = PMAC_TYPE_UNKNOWN_OHARE;
+               pmac_mb.model_name = "Unknown OHare-based";
+               break;
+           case macio_heathrow:
+               pmac_mb.model_id = PMAC_TYPE_UNKNOWN_HEATHROW;
+               pmac_mb.model_name = "Unknown Heathrow-based";
+               pmac_mb.features = heathrow_desktop_features;
+               break;
+           case macio_paddington:
+               pmac_mb.model_id = PMAC_TYPE_UNKNOWN_PADDINGTON;
+               pmac_mb.model_name = "Unknown Paddington-based";
+               pmac_mb.features = paddington_features;
+               break;
+           case macio_keylargo:
+               pmac_mb.model_id = PMAC_TYPE_UNKNOWN_CORE99;
+               pmac_mb.model_name = "Unknown Keylargo-based";
+               pmac_mb.features = core99_features;
+               break;
+           case macio_pangea:
+               pmac_mb.model_id = PMAC_TYPE_UNKNOWN_PANGEA;
+               pmac_mb.model_name = "Unknown Pangea-based";
+               pmac_mb.features = pangea_features;
+               break;
+           case macio_intrepid:
+               pmac_mb.model_id = PMAC_TYPE_UNKNOWN_INTREPID;
+               pmac_mb.model_name = "Unknown Intrepid-based";
+               pmac_mb.features = intrepid_features;
+               break;
+#else /* CONFIG_POWER4 */
+       case macio_keylargo2:
+               pmac_mb.model_id = PMAC_TYPE_UNKNOWN_K2;
+               pmac_mb.model_name = "Unknown K2-based";
+               pmac_mb.features = g5_features;
+               break;
+#endif /* CONFIG_POWER4 */
+       default:
+               return -ENODEV;
+       }
+found:
+#ifndef CONFIG_POWER4
+       /* Fixup Hooper vs. Comet */
+       if (pmac_mb.model_id == PMAC_TYPE_HOOPER) {
+               u32 __iomem * mach_id_ptr = ioremap(0xf3000034, 4);
+               if (!mach_id_ptr)
+                       return -ENODEV;
+               /* Here, I used to disable the media-bay on comet. It
+                * appears this is wrong, the floppy connector is actually
+                * a kind of media-bay and works with the current driver.
+                */
+               if (__raw_readl(mach_id_ptr) & 0x20000000UL)
+                       pmac_mb.model_id = PMAC_TYPE_COMET;
+               iounmap(mach_id_ptr);
+       }
+#endif /* CONFIG_POWER4 */
+
+#ifdef CONFIG_6xx
+       /* Set default value of powersave_nap on machines that support it.
+        * It appears that uninorth rev 3 has a problem with it, we don't
+        * enable it on those. In theory, the flush-on-lock property is
+        * supposed to be set when not supported, but I'm not very confident
+        * that all Apple OF revs did it properly, I do it the paranoid way.
+        */
+       while (uninorth_base && uninorth_rev > 3) {
+               struct device_node *np = find_path_device("/cpus");
+               if (!np || !np->child) {
+                       printk(KERN_WARNING "Can't find CPU(s) in device tree !\n");
+                       break;
+               }
+               np = np->child;
+               /* Nap mode not supported on SMP */
+               if (np->sibling)
+                       break;
+               /* Nap mode not supported if flush-on-lock property is present */
+               if (get_property(np, "flush-on-lock", NULL))
+                       break;
+               powersave_nap = 1;
+               printk(KERN_INFO "Processor NAP mode on idle enabled.\n");
+               break;
+       }
+
+       /* On CPUs that support it (750FX), lowspeed by default during
+        * NAP mode
+        */
+       powersave_lowspeed = 1;
+#endif /* CONFIG_6xx */
+#ifdef CONFIG_POWER4
+       powersave_nap = 1;
+#endif
+       /* Check for "mobile" machine */
+       if (model && (strncmp(model, "PowerBook", 9) == 0
+                  || strncmp(model, "iBook", 5) == 0))
+               pmac_mb.board_flags |= PMAC_MB_MOBILE;
+
+
+       printk(KERN_INFO "PowerMac motherboard: %s\n", pmac_mb.model_name);
+       return 0;
+}
+
+/* Initialize the Core99 UniNorth host bridge and memory controller
+ */
+static void __init probe_uninorth(void)
+{
+       unsigned long actrl;
+
+       /* Locate core99 Uni-N */
+       uninorth_node = of_find_node_by_name(NULL, "uni-n");
+       /* Locate G5 u3 */
+       if (uninorth_node == NULL) {
+               uninorth_node = of_find_node_by_name(NULL, "u3");
+               uninorth_u3 = 1;
+       }
+       if (uninorth_node && uninorth_node->n_addrs > 0) {
+               unsigned long address = uninorth_node->addrs[0].address;
+               uninorth_base = ioremap(address, 0x40000);
+               uninorth_rev = in_be32(UN_REG(UNI_N_VERSION));
+               if (uninorth_u3)
+                       u3_ht = ioremap(address + U3_HT_CONFIG_BASE, 0x1000);
+       } else
+               uninorth_node = NULL;
+
+       if (!uninorth_node)
+               return;
+
+       printk(KERN_INFO "Found %s memory controller & host bridge, revision: %d\n",
+              uninorth_u3 ? "U3" : "UniNorth", uninorth_rev);
+       printk(KERN_INFO "Mapped at 0x%08lx\n", (unsigned long)uninorth_base);
+
+       /* Set the arbitrer QAck delay according to what Apple does
+        */
+       if (uninorth_rev < 0x11) {
+               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);
+       }
+
+       /* Some more magic as done by them in recent MacOS X on UniNorth
+        * revs 1.5 to 2.O and Pangea. Seem to toggle the UniN Maxbus/PCI
+        * memory timeout
+        */
+       if ((uninorth_rev >= 0x11 && uninorth_rev <= 0x24) || uninorth_rev == 0xc0)
+               UN_OUT(0x2160, UN_IN(0x2160) & 0x00ffffff);
+}
+
+static void __init probe_one_macio(const char *name, const char *compat, int type)
+{
+       struct device_node*     node;
+       int                     i;
+       volatile u32 __iomem *  base;
+       u32*                    revp;
+
+       node = find_devices(name);
+       if (!node || !node->n_addrs)
+               return;
+       if (compat)
+               do {
+                       if (device_is_compatible(node, compat))
+                               break;
+                       node = node->next;
+               } while (node);
+       if (!node)
+               return;
+       for(i=0; i<MAX_MACIO_CHIPS; i++) {
+               if (!macio_chips[i].of_node)
+                       break;
+               if (macio_chips[i].of_node == node)
+                       return;
+       }
+       if (i >= MAX_MACIO_CHIPS) {
+               printk(KERN_ERR "pmac_feature: Please increase MAX_MACIO_CHIPS !\n");
+               printk(KERN_ERR "pmac_feature: %s skipped\n", node->full_name);
+               return;
+       }
+       base = ioremap(node->addrs[0].address, node->addrs[0].size);
+       if (!base) {
+               printk(KERN_ERR "pmac_feature: Can't map mac-io chip !\n");
+               return;
+       }
+       if (type == macio_keylargo) {
+               u32 *did = (u32 *)get_property(node, "device-id", NULL);
+               if (*did == 0x00000025)
+                       type = macio_pangea;
+               if (*did == 0x0000003e)
+                       type = macio_intrepid;
+       }
+       macio_chips[i].of_node  = node;
+       macio_chips[i].type     = type;
+       macio_chips[i].base     = base;
+       macio_chips[i].flags    = MACIO_FLAG_SCCB_ON | MACIO_FLAG_SCCB_ON;
+       macio_chips[i].name     = macio_names[type];
+       revp = (u32 *)get_property(node, "revision-id", NULL);
+       if (revp)
+               macio_chips[i].rev = *revp;
+       printk(KERN_INFO "Found a %s mac-io controller, rev: %d, mapped at 0x%p\n",
+               macio_names[type], macio_chips[i].rev, macio_chips[i].base);
+}
+
+static int __init
+probe_macios(void)
+{
+       /* Warning, ordering is important */
+       probe_one_macio("gc", NULL, macio_grand_central);
+       probe_one_macio("ohare", NULL, macio_ohare);
+       probe_one_macio("pci106b,7", NULL, macio_ohareII);
+       probe_one_macio("mac-io", "keylargo", macio_keylargo);
+       probe_one_macio("mac-io", "paddington", macio_paddington);
+       probe_one_macio("mac-io", "gatwick", macio_gatwick);
+       probe_one_macio("mac-io", "heathrow", macio_heathrow);
+       probe_one_macio("mac-io", "K2-Keylargo", macio_keylargo2);
+
+       /* Make sure the "main" macio chip appear first */
+       if (macio_chips[0].type == macio_gatwick
+           && macio_chips[1].type == macio_heathrow) {
+               struct macio_chip temp = macio_chips[0];
+               macio_chips[0] = macio_chips[1];
+               macio_chips[1] = temp;
+       }
+       if (macio_chips[0].type == macio_ohareII
+           && macio_chips[1].type == macio_ohare) {
+               struct macio_chip temp = macio_chips[0];
+               macio_chips[0] = macio_chips[1];
+               macio_chips[1] = temp;
+       }
+       macio_chips[0].lbus.index = 0;
+       macio_chips[1].lbus.index = 1;
+
+       return (macio_chips[0].of_node == NULL) ? -ENODEV : 0;
+}
+
+static void __init
+initial_serial_shutdown(struct device_node *np)
+{
+       int len;
+       struct slot_names_prop {
+               int     count;
+               char    name[1];
+       } *slots;
+       char *conn;
+       int port_type = PMAC_SCC_ASYNC;
+       int modem = 0;
+
+       slots = (struct slot_names_prop *)get_property(np, "slot-names", &len);
+       conn = get_property(np, "AAPL,connector", &len);
+       if (conn && (strcmp(conn, "infrared") == 0))
+               port_type = PMAC_SCC_IRDA;
+       else if (device_is_compatible(np, "cobalt"))
+               modem = 1;
+       else if (slots && slots->count > 0) {
+               if (strcmp(slots->name, "IrDA") == 0)
+                       port_type = PMAC_SCC_IRDA;
+               else if (strcmp(slots->name, "Modem") == 0)
+                       modem = 1;
+       }
+       if (modem)
+               pmac_call_feature(PMAC_FTR_MODEM_ENABLE, np, 0, 0);
+       pmac_call_feature(PMAC_FTR_SCC_ENABLE, np, port_type, 0);
+}
+
+static void __init
+set_initial_features(void)
+{
+       struct device_node *np;
+
+       /* That hack appears to be necessary for some StarMax motherboards
+        * but I'm not too sure it was audited for side-effects on other
+        * ohare based machines...
+        * Since I still have difficulties figuring the right way to
+        * differenciate them all and since that hack was there for a long
+        * time, I'll keep it around
+        */
+       if (macio_chips[0].type == macio_ohare && !find_devices("via-pmu")) {
+               struct macio_chip *macio = &macio_chips[0];
+               MACIO_OUT32(OHARE_FCR, STARMAX_FEATURES);
+       } else if (macio_chips[0].type == macio_ohare) {
+               struct macio_chip *macio = &macio_chips[0];
+               MACIO_BIS(OHARE_FCR, OH_IOBUS_ENABLE);
+       } else if (macio_chips[1].type == macio_ohare) {
+               struct macio_chip *macio = &macio_chips[1];
+               MACIO_BIS(OHARE_FCR, OH_IOBUS_ENABLE);
+       }
+
+#ifdef CONFIG_POWER4
+       if (macio_chips[0].type == macio_keylargo2) {
+#ifndef CONFIG_SMP
+               /* On SMP machines running UP, we have the second CPU eating
+                * bus cycles. We need to take it off the bus. This is done
+                * from pmac_smp for SMP kernels running on one CPU
+                */
+               np = of_find_node_by_type(NULL, "cpu");
+               if (np != NULL)
+                       np = of_find_node_by_type(np, "cpu");
+               if (np != NULL) {
+                       g5_phy_disable_cpu1();
+                       of_node_put(np);
+               }
+#endif /* CONFIG_SMP */
+               /* Enable GMAC for now for PCI probing. It will be disabled
+                * later on after PCI probe
+                */
+               np = of_find_node_by_name(NULL, "ethernet");
+               while(np) {
+                       if (device_is_compatible(np, "K2-GMAC"))
+                               g5_gmac_enable(np, 0, 1);
+                       np = of_find_node_by_name(np, "ethernet");
+               }
+
+               /* Enable FW before PCI probe. Will be disabled later on
+                * Note: We should have a batter way to check that we are
+                * dealing with uninorth internal cell and not a PCI cell
+                * on the external PCI. The code below works though.
+                */
+               np = of_find_node_by_name(NULL, "firewire");
+               while(np) {
+                       if (device_is_compatible(np, "pci106b,5811")) {
+                               macio_chips[0].flags |= MACIO_FLAG_FW_SUPPORTED;
+                               g5_fw_enable(np, 0, 1);
+                       }
+                       np = of_find_node_by_name(np, "firewire");
+               }
+       }
+#else /* CONFIG_POWER4 */
+
+       if (macio_chips[0].type == macio_keylargo ||
+           macio_chips[0].type == macio_pangea ||
+           macio_chips[0].type == macio_intrepid) {
+               /* Enable GMAC for now for PCI probing. It will be disabled
+                * later on after PCI probe
+                */
+               np = of_find_node_by_name(NULL, "ethernet");
+               while(np) {
+                       if (np->parent
+                           && device_is_compatible(np->parent, "uni-north")
+                           && device_is_compatible(np, "gmac"))
+                               core99_gmac_enable(np, 0, 1);
+                       np = of_find_node_by_name(np, "ethernet");
+               }
+
+               /* Enable FW before PCI probe. Will be disabled later on
+                * Note: We should have a batter way to check that we are
+                * dealing with uninorth internal cell and not a PCI cell
+                * on the external PCI. The code below works though.
+                */
+               np = of_find_node_by_name(NULL, "firewire");
+               while(np) {
+                       if (np->parent
+                           && device_is_compatible(np->parent, "uni-north")
+                           && (device_is_compatible(np, "pci106b,18") ||
+                               device_is_compatible(np, "pci106b,30") ||
+                               device_is_compatible(np, "pci11c1,5811"))) {
+                               macio_chips[0].flags |= MACIO_FLAG_FW_SUPPORTED;
+                               core99_firewire_enable(np, 0, 1);
+                       }
+                       np = of_find_node_by_name(np, "firewire");
+               }
+
+               /* Enable ATA-100 before PCI probe. */
+               np = of_find_node_by_name(NULL, "ata-6");
+               while(np) {
+                       if (np->parent
+                           && device_is_compatible(np->parent, "uni-north")
+                           && device_is_compatible(np, "kauai-ata")) {
+                               core99_ata100_enable(np, 1);
+                       }
+                       np = of_find_node_by_name(np, "ata-6");
+               }
+
+               /* Switch airport off */
+               np = find_devices("radio");
+               while(np) {
+                       if (np && np->parent == macio_chips[0].of_node) {
+                               macio_chips[0].flags |= MACIO_FLAG_AIRPORT_ON;
+                               core99_airport_enable(np, 0, 0);
+                       }
+                       np = np->next;
+               }
+       }
+
+       /* On all machines that support sound PM, switch sound off */
+       if (macio_chips[0].of_node)
+               pmac_do_feature_call(PMAC_FTR_SOUND_CHIP_ENABLE,
+                       macio_chips[0].of_node, 0, 0);
+
+       /* While on some desktop G3s, we turn it back on */
+       if (macio_chips[0].of_node && macio_chips[0].type == macio_heathrow
+               && (pmac_mb.model_id == PMAC_TYPE_GOSSAMER ||
+                   pmac_mb.model_id == PMAC_TYPE_SILK)) {
+               struct macio_chip *macio = &macio_chips[0];
+               MACIO_BIS(HEATHROW_FCR, HRW_SOUND_CLK_ENABLE);
+               MACIO_BIC(HEATHROW_FCR, HRW_SOUND_POWER_N);
+       }
+
+       /* Some machine models need the clock chip to be properly setup for
+        * clock spreading now. This should be a platform function but we
+        * don't do these at the moment
+        */
+       pmac_tweak_clock_spreading(1);
+
+#endif /* CONFIG_POWER4 */
+
+       /* On all machines, switch modem & serial ports off */
+       np = find_devices("ch-a");
+       while(np) {
+               initial_serial_shutdown(np);
+               np = np->next;
+       }
+       np = find_devices("ch-b");
+       while(np) {
+               initial_serial_shutdown(np);
+               np = np->next;
+       }
+}
+
+void __init
+pmac_feature_init(void)
+{
+       /* Detect the UniNorth memory controller */
+       probe_uninorth();
+
+       /* Probe mac-io controllers */
+       if (probe_macios()) {
+               printk(KERN_WARNING "No mac-io chip found\n");
+               return;
+       }
+
+       /* Setup low-level i2c stuffs */
+       pmac_init_low_i2c();
+
+       /* Probe machine type */
+       if (probe_motherboard())
+               printk(KERN_WARNING "Unknown PowerMac !\n");
+
+       /* Set some initial features (turn off some chips that will
+        * be later turned on)
+        */
+       set_initial_features();
+}
+
+int __init pmac_feature_late_init(void)
+{
+#if 0
+       struct device_node *np;
+
+       /* Request some resources late */
+       if (uninorth_node)
+               request_OF_resource(uninorth_node, 0, NULL);
+       np = find_devices("hammerhead");
+       if (np)
+               request_OF_resource(np, 0, NULL);
+       np = find_devices("interrupt-controller");
+       if (np)
+               request_OF_resource(np, 0, NULL);
+#endif
+       return 0;
+}
+
+device_initcall(pmac_feature_late_init);
+
+#if 0
+static void dump_HT_speeds(char *name, u32 cfg, u32 frq)
+{
+       int     freqs[16] = { 200,300,400,500,600,800,1000,0,0,0,0,0,0,0,0,0 };
+       int     bits[8] = { 8,16,0,32,2,4,0,0 };
+       int     freq = (frq >> 8) & 0xf;
+
+       if (freqs[freq] == 0)
+               printk("%s: Unknown HT link frequency %x\n", name, freq);
+       else
+               printk("%s: %d MHz on main link, (%d in / %d out) bits width\n",
+                      name, freqs[freq],
+                      bits[(cfg >> 28) & 0x7], bits[(cfg >> 24) & 0x7]);
+}
+
+void __init pmac_check_ht_link(void)
+{
+#if 0 /* Disabled for now */
+       u32     ufreq, freq, ucfg, cfg;
+       struct device_node *pcix_node;
+       u8      px_bus, px_devfn;
+       struct pci_controller *px_hose;
+
+       (void)in_be32(u3_ht + U3_HT_LINK_COMMAND);
+       ucfg = cfg = in_be32(u3_ht + U3_HT_LINK_CONFIG);
+       ufreq = freq = in_be32(u3_ht + U3_HT_LINK_FREQ);
+       dump_HT_speeds("U3 HyperTransport", cfg, freq);
+
+       pcix_node = of_find_compatible_node(NULL, "pci", "pci-x");
+       if (pcix_node == NULL) {
+               printk("No PCI-X bridge found\n");
+               return;
+       }
+       if (pci_device_from_OF_node(pcix_node, &px_bus, &px_devfn) != 0) {
+               printk("PCI-X bridge found but not matched to pci\n");
+               return;
+       }
+       px_hose = pci_find_hose_for_OF_device(pcix_node);
+       if (px_hose == NULL) {
+               printk("PCI-X bridge found but not matched to host\n");
+               return;
+       }       
+       early_read_config_dword(px_hose, px_bus, px_devfn, 0xc4, &cfg);
+       early_read_config_dword(px_hose, px_bus, px_devfn, 0xcc, &freq);
+       dump_HT_speeds("PCI-X HT Uplink", cfg, freq);
+       early_read_config_dword(px_hose, px_bus, px_devfn, 0xc8, &cfg);
+       early_read_config_dword(px_hose, px_bus, px_devfn, 0xd0, &freq);
+       dump_HT_speeds("PCI-X HT Downlink", cfg, freq);
+#endif
+}
+
+#endif /* CONFIG_POWER4 */
+
+/*
+ * Early video resume hook
+ */
+
+static void (*pmac_early_vresume_proc)(void *data);
+static void *pmac_early_vresume_data;
+
+void pmac_set_early_video_resume(void (*proc)(void *data), void *data)
+{
+       if (_machine != _MACH_Pmac)
+               return;
+       preempt_disable();
+       pmac_early_vresume_proc = proc;
+       pmac_early_vresume_data = data;
+       preempt_enable();
+}
+EXPORT_SYMBOL(pmac_set_early_video_resume);
+
+void pmac_call_early_video_resume(void)
+{
+       if (pmac_early_vresume_proc)
+               pmac_early_vresume_proc(pmac_early_vresume_data);
+}
+
+/*
+ * AGP related suspend/resume code
+ */
+
+static struct pci_dev *pmac_agp_bridge;
+static int (*pmac_agp_suspend)(struct pci_dev *bridge);
+static int (*pmac_agp_resume)(struct pci_dev *bridge);
+
+void pmac_register_agp_pm(struct pci_dev *bridge,
+                                int (*suspend)(struct pci_dev *bridge),
+                                int (*resume)(struct pci_dev *bridge))
+{
+       if (suspend || resume) {
+               pmac_agp_bridge = bridge;
+               pmac_agp_suspend = suspend;
+               pmac_agp_resume = resume;
+               return;
+       }
+       if (bridge != pmac_agp_bridge)
+               return;
+       pmac_agp_suspend = pmac_agp_resume = NULL;
+       return;
+}
+EXPORT_SYMBOL(pmac_register_agp_pm);
+
+void pmac_suspend_agp_for_card(struct pci_dev *dev)
+{
+       if (pmac_agp_bridge == NULL || pmac_agp_suspend == NULL)
+               return;
+       if (pmac_agp_bridge->bus != dev->bus)
+               return;
+       pmac_agp_suspend(pmac_agp_bridge);
+}
+EXPORT_SYMBOL(pmac_suspend_agp_for_card);
+
+void pmac_resume_agp_for_card(struct pci_dev *dev)
+{
+       if (pmac_agp_bridge == NULL || pmac_agp_resume == NULL)
+               return;
+       if (pmac_agp_bridge->bus != dev->bus)
+               return;
+       pmac_agp_resume(pmac_agp_bridge);
+}
+EXPORT_SYMBOL(pmac_resume_agp_for_card);
diff --git a/arch/powerpc/platforms/powermac/low_i2c.c b/arch/powerpc/platforms/powermac/low_i2c.c
new file mode 100644 (file)
index 0000000..f3f39e8
--- /dev/null
@@ -0,0 +1,523 @@
+/*
+ *  arch/ppc/platforms/pmac_low_i2c.c
+ *
+ *  Copyright (C) 2003 Ben. Herrenschmidt (benh@kernel.crashing.org)
+ *
+ *  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.
+ *
+ *  This file contains some low-level i2c access routines that
+ *  need to be used by various bits of the PowerMac platform code
+ *  at times where the real asynchronous & interrupt driven driver
+ *  cannot be used. The API borrows some semantics from the darwin
+ *  driver in order to ease the implementation of the platform
+ *  properties parser
+ */
+
+#undef DEBUG
+
+#include <linux/config.h>
+#include <linux/types.h>
+#include <linux/sched.h>
+#include <linux/init.h>
+#include <linux/module.h>
+#include <linux/adb.h>
+#include <linux/pmu.h>
+#include <asm/keylargo.h>
+#include <asm/uninorth.h>
+#include <asm/io.h>
+#include <asm/prom.h>
+#include <asm/machdep.h>
+#include <asm/pmac_low_i2c.h>
+
+#define MAX_LOW_I2C_HOST       4
+
+#ifdef DEBUG
+#define DBG(x...) do {\
+               printk(KERN_DEBUG "KW:" x);     \
+       } while(0)
+#else
+#define DBG(x...)
+#endif
+
+struct low_i2c_host;
+
+typedef int (*low_i2c_func_t)(struct low_i2c_host *host, u8 addr, u8 sub, u8 *data, int len);
+
+struct low_i2c_host
+{
+       struct device_node      *np;            /* OF device node */
+       struct semaphore        mutex;          /* Access mutex for use by i2c-keywest */
+       low_i2c_func_t          func;           /* Access function */
+       unsigned int            is_open : 1;    /* Poor man's access control */
+       int                     mode;           /* Current mode */
+       int                     channel;        /* Current channel */
+       int                     num_channels;   /* Number of channels */
+       void __iomem            *base;          /* For keywest-i2c, base address */
+       int                     bsteps;         /* And register stepping */
+       int                     speed;          /* And speed */
+};
+
+static struct low_i2c_host     low_i2c_hosts[MAX_LOW_I2C_HOST];
+
+/* No locking is necessary on allocation, we are running way before
+ * anything can race with us
+ */
+static struct low_i2c_host *find_low_i2c_host(struct device_node *np)
+{
+       int i;
+
+       for (i = 0; i < MAX_LOW_I2C_HOST; i++)
+               if (low_i2c_hosts[i].np == np)
+                       return &low_i2c_hosts[i];
+       return NULL;
+}
+
+/*
+ *
+ * i2c-keywest implementation (UniNorth, U2, U3, Keylargo's)
+ *
+ */
+
+/*
+ * Keywest i2c definitions borrowed from drivers/i2c/i2c-keywest.h,
+ * should be moved somewhere in include/asm-ppc/
+ */
+/* Register indices */
+typedef enum {
+       reg_mode = 0,
+       reg_control,
+       reg_status,
+       reg_isr,
+       reg_ier,
+       reg_addr,
+       reg_subaddr,
+       reg_data
+} reg_t;
+
+
+/* Mode register */
+#define KW_I2C_MODE_100KHZ     0x00
+#define KW_I2C_MODE_50KHZ      0x01
+#define KW_I2C_MODE_25KHZ      0x02
+#define KW_I2C_MODE_DUMB       0x00
+#define KW_I2C_MODE_STANDARD   0x04
+#define KW_I2C_MODE_STANDARDSUB        0x08
+#define KW_I2C_MODE_COMBINED   0x0C
+#define KW_I2C_MODE_MODE_MASK  0x0C
+#define KW_I2C_MODE_CHAN_MASK  0xF0
+
+/* Control register */
+#define KW_I2C_CTL_AAK         0x01
+#define KW_I2C_CTL_XADDR       0x02
+#define KW_I2C_CTL_STOP                0x04
+#define KW_I2C_CTL_START       0x08
+
+/* Status register */
+#define KW_I2C_STAT_BUSY       0x01
+#define KW_I2C_STAT_LAST_AAK   0x02
+#define KW_I2C_STAT_LAST_RW    0x04
+#define KW_I2C_STAT_SDA                0x08
+#define KW_I2C_STAT_SCL                0x10
+
+/* IER & ISR registers */
+#define KW_I2C_IRQ_DATA                0x01
+#define KW_I2C_IRQ_ADDR                0x02
+#define KW_I2C_IRQ_STOP                0x04
+#define KW_I2C_IRQ_START       0x08
+#define KW_I2C_IRQ_MASK                0x0F
+
+/* State machine states */
+enum {
+       state_idle,
+       state_addr,
+       state_read,
+       state_write,
+       state_stop,
+       state_dead
+};
+
+#define WRONG_STATE(name) do {\
+               printk(KERN_DEBUG "KW: wrong state. Got %s, state: %s (isr: %02x)\n", \
+                      name, __kw_state_names[state], isr); \
+       } while(0)
+
+static const char *__kw_state_names[] = {
+       "state_idle",
+       "state_addr",
+       "state_read",
+       "state_write",
+       "state_stop",
+       "state_dead"
+};
+
+static inline u8 __kw_read_reg(struct low_i2c_host *host, reg_t reg)
+{
+       return readb(host->base + (((unsigned int)reg) << host->bsteps));
+}
+
+static inline void __kw_write_reg(struct low_i2c_host *host, reg_t reg, u8 val)
+{
+       writeb(val, host->base + (((unsigned)reg) << host->bsteps));
+       (void)__kw_read_reg(host, reg_subaddr);
+}
+
+#define kw_write_reg(reg, val) __kw_write_reg(host, reg, val) 
+#define kw_read_reg(reg)       __kw_read_reg(host, reg) 
+
+
+/* Don't schedule, the g5 fan controller is too
+ * timing sensitive
+ */
+static u8 kw_wait_interrupt(struct low_i2c_host* host)
+{
+       int i, j;
+       u8 isr;
+       
+       for (i = 0; i < 100000; i++) {
+               isr = kw_read_reg(reg_isr) & KW_I2C_IRQ_MASK;
+               if (isr != 0)
+                       return isr;
+
+               /* This code is used with the timebase frozen, we cannot rely
+                * on udelay ! For now, just use a bogus loop
+                */
+               for (j = 1; j < 10000; j++)
+                       mb();
+       }
+       return isr;
+}
+
+static int kw_handle_interrupt(struct low_i2c_host *host, int state, int rw, int *rc, u8 **data, int *len, u8 isr)
+{
+       u8 ack;
+
+       DBG("kw_handle_interrupt(%s, isr: %x)\n", __kw_state_names[state], isr);
+
+       if (isr == 0) {
+               if (state != state_stop) {
+                       DBG("KW: Timeout !\n");
+                       *rc = -EIO;
+                       goto stop;
+               }
+               if (state == state_stop) {
+                       ack = kw_read_reg(reg_status);
+                       if (!(ack & KW_I2C_STAT_BUSY)) {
+                               state = state_idle;
+                               kw_write_reg(reg_ier, 0x00);
+                       }
+               }
+               return state;
+       }
+
+       if (isr & KW_I2C_IRQ_ADDR) {
+               ack = kw_read_reg(reg_status);
+               if (state != state_addr) {
+                       kw_write_reg(reg_isr, KW_I2C_IRQ_ADDR);
+                       WRONG_STATE("KW_I2C_IRQ_ADDR"); 
+                       *rc = -EIO;
+                       goto stop;
+               }
+               if ((ack & KW_I2C_STAT_LAST_AAK) == 0) {                        
+                       *rc = -ENODEV;
+                       DBG("KW: NAK on address\n");
+                       return state_stop;                   
+               } else {
+                       if (rw) {
+                               state = state_read;
+                               if (*len > 1)
+                                       kw_write_reg(reg_control, KW_I2C_CTL_AAK);
+                       } else {
+                               state = state_write;
+                               kw_write_reg(reg_data, **data);
+                               (*data)++; (*len)--;
+                       }
+               }
+               kw_write_reg(reg_isr, KW_I2C_IRQ_ADDR);
+       }
+
+       if (isr & KW_I2C_IRQ_DATA) {
+               if (state == state_read) {
+                       **data = kw_read_reg(reg_data);
+                       (*data)++; (*len)--;
+                       kw_write_reg(reg_isr, KW_I2C_IRQ_DATA);
+                       if ((*len) == 0)
+                               state = state_stop;
+                       else if ((*len) == 1)
+                               kw_write_reg(reg_control, 0);
+               } else if (state == state_write) {
+                       ack = kw_read_reg(reg_status);
+                       if ((ack & KW_I2C_STAT_LAST_AAK) == 0) {
+                               DBG("KW: nack on data write\n");
+                               *rc = -EIO;
+                               goto stop;
+                       } else if (*len) {
+                               kw_write_reg(reg_data, **data);
+                               (*data)++; (*len)--;
+                       } else {
+                               kw_write_reg(reg_control, KW_I2C_CTL_STOP);
+                               state = state_stop;
+                               *rc = 0;
+                       }
+                       kw_write_reg(reg_isr, KW_I2C_IRQ_DATA);
+               } else {
+                       kw_write_reg(reg_isr, KW_I2C_IRQ_DATA);
+                       WRONG_STATE("KW_I2C_IRQ_DATA"); 
+                       if (state != state_stop) {
+                               *rc = -EIO;
+                               goto stop;
+                       }
+               }
+       }
+
+       if (isr & KW_I2C_IRQ_STOP) {
+               kw_write_reg(reg_isr, KW_I2C_IRQ_STOP);
+               if (state != state_stop) {
+                       WRONG_STATE("KW_I2C_IRQ_STOP");
+                       *rc = -EIO;
+               }
+               return state_idle;
+       }
+
+       if (isr & KW_I2C_IRQ_START)
+               kw_write_reg(reg_isr, KW_I2C_IRQ_START);
+
+       return state;
+
+ stop:
+       kw_write_reg(reg_control, KW_I2C_CTL_STOP);     
+       return state_stop;
+}
+
+static int keywest_low_i2c_func(struct low_i2c_host *host, u8 addr, u8 subaddr, u8 *data, int len)
+{
+       u8 mode_reg = host->speed;
+       int state = state_addr;
+       int rc = 0;
+
+       /* Setup mode & subaddress if any */
+       switch(host->mode) {
+       case pmac_low_i2c_mode_dumb:
+               printk(KERN_ERR "low_i2c: Dumb mode not supported !\n");
+               return -EINVAL;
+       case pmac_low_i2c_mode_std:
+               mode_reg |= KW_I2C_MODE_STANDARD;
+               break;
+       case pmac_low_i2c_mode_stdsub:
+               mode_reg |= KW_I2C_MODE_STANDARDSUB;
+               break;
+       case pmac_low_i2c_mode_combined:
+               mode_reg |= KW_I2C_MODE_COMBINED;
+               break;
+       }
+
+       /* Setup channel & clear pending irqs */
+       kw_write_reg(reg_isr, kw_read_reg(reg_isr));
+       kw_write_reg(reg_mode, mode_reg | (host->channel << 4));
+       kw_write_reg(reg_status, 0);
+
+       /* Set up address and r/w bit */
+       kw_write_reg(reg_addr, addr);
+
+       /* Set up the sub address */
+       if ((mode_reg & KW_I2C_MODE_MODE_MASK) == KW_I2C_MODE_STANDARDSUB
+           || (mode_reg & KW_I2C_MODE_MODE_MASK) == KW_I2C_MODE_COMBINED)
+               kw_write_reg(reg_subaddr, subaddr);
+
+       /* Start sending address & disable interrupt*/
+       kw_write_reg(reg_ier, 0 /*KW_I2C_IRQ_MASK*/);
+       kw_write_reg(reg_control, KW_I2C_CTL_XADDR);
+
+       /* State machine, to turn into an interrupt handler */
+       while(state != state_idle) {
+               u8 isr = kw_wait_interrupt(host);
+               state = kw_handle_interrupt(host, state, addr & 1, &rc, &data, &len, isr);
+       }
+
+       return rc;
+}
+
+static void keywest_low_i2c_add(struct device_node *np)
+{
+       struct low_i2c_host     *host = find_low_i2c_host(NULL);
+       u32                     *psteps, *prate, steps, aoffset = 0;
+       struct device_node      *parent;
+
+       if (host == NULL) {
+               printk(KERN_ERR "low_i2c: Can't allocate host for %s\n",
+                      np->full_name);
+               return;
+       }
+       memset(host, 0, sizeof(*host));
+
+       init_MUTEX(&host->mutex);
+       host->np = of_node_get(np);     
+       psteps = (u32 *)get_property(np, "AAPL,address-step", NULL);
+       steps = psteps ? (*psteps) : 0x10;
+       for (host->bsteps = 0; (steps & 0x01) == 0; host->bsteps++)
+               steps >>= 1;
+       parent = of_get_parent(np);
+       host->num_channels = 1;
+       if (parent && parent->name[0] == 'u') {
+               host->num_channels = 2;
+               aoffset = 3;
+       }
+       /* Select interface rate */
+       host->speed = KW_I2C_MODE_100KHZ;
+       prate = (u32 *)get_property(np, "AAPL,i2c-rate", NULL);
+       if (prate) switch(*prate) {
+       case 100:
+               host->speed = KW_I2C_MODE_100KHZ;
+               break;
+       case 50:
+               host->speed = KW_I2C_MODE_50KHZ;
+               break;
+       case 25:
+               host->speed = KW_I2C_MODE_25KHZ;
+               break;
+       }       
+
+       host->mode = pmac_low_i2c_mode_std;
+       host->base = ioremap(np->addrs[0].address + aoffset,
+                                               np->addrs[0].size);
+       host->func = keywest_low_i2c_func;
+}
+
+/*
+ *
+ * PMU implementation
+ *
+ */
+
+
+#ifdef CONFIG_ADB_PMU
+
+static int pmu_low_i2c_func(struct low_i2c_host *host, u8 addr, u8 sub, u8 *data, int len)
+{
+       // TODO
+       return -ENODEV;
+}
+
+static void pmu_low_i2c_add(struct device_node *np)
+{
+       struct low_i2c_host     *host = find_low_i2c_host(NULL);
+
+       if (host == NULL) {
+               printk(KERN_ERR "low_i2c: Can't allocate host for %s\n",
+                      np->full_name);
+               return;
+       }
+       memset(host, 0, sizeof(*host));
+
+       init_MUTEX(&host->mutex);
+       host->np = of_node_get(np);     
+       host->num_channels = 3;
+       host->mode = pmac_low_i2c_mode_std;
+       host->func = pmu_low_i2c_func;
+}
+
+#endif /* CONFIG_ADB_PMU */
+
+void __init pmac_init_low_i2c(void)
+{
+       struct device_node *np;
+
+       /* Probe keywest-i2c busses */
+       np = of_find_compatible_node(NULL, "i2c", "keywest-i2c");
+       while(np) {
+               keywest_low_i2c_add(np);
+               np = of_find_compatible_node(np, "i2c", "keywest-i2c");
+       }
+
+#ifdef CONFIG_ADB_PMU
+       /* Probe PMU busses */
+       np = of_find_node_by_name(NULL, "via-pmu");
+       if (np)
+               pmu_low_i2c_add(np);
+#endif /* CONFIG_ADB_PMU */
+
+       /* TODO: Add CUDA support as well */
+}
+
+int pmac_low_i2c_lock(struct device_node *np)
+{
+       struct low_i2c_host *host = find_low_i2c_host(np);
+
+       if (!host)
+               return -ENODEV;
+       down(&host->mutex);
+       return 0;
+}
+EXPORT_SYMBOL(pmac_low_i2c_lock);
+
+int pmac_low_i2c_unlock(struct device_node *np)
+{
+       struct low_i2c_host *host = find_low_i2c_host(np);
+
+       if (!host)
+               return -ENODEV;
+       up(&host->mutex);
+       return 0;
+}
+EXPORT_SYMBOL(pmac_low_i2c_unlock);
+
+
+int pmac_low_i2c_open(struct device_node *np, int channel)
+{
+       struct low_i2c_host *host = find_low_i2c_host(np);
+
+       if (!host)
+               return -ENODEV;
+
+       if (channel >= host->num_channels)
+               return -EINVAL;
+
+       down(&host->mutex);
+       host->is_open = 1;
+       host->channel = channel;
+
+       return 0;
+}
+EXPORT_SYMBOL(pmac_low_i2c_open);
+
+int pmac_low_i2c_close(struct device_node *np)
+{
+       struct low_i2c_host *host = find_low_i2c_host(np);
+
+       if (!host)
+               return -ENODEV;
+
+       host->is_open = 0;
+       up(&host->mutex);
+
+       return 0;
+}
+EXPORT_SYMBOL(pmac_low_i2c_close);
+
+int pmac_low_i2c_setmode(struct device_node *np, int mode)
+{
+       struct low_i2c_host *host = find_low_i2c_host(np);
+
+       if (!host)
+               return -ENODEV;
+       WARN_ON(!host->is_open);
+       host->mode = mode;
+
+       return 0;
+}
+EXPORT_SYMBOL(pmac_low_i2c_setmode);
+
+int pmac_low_i2c_xfer(struct device_node *np, u8 addrdir, u8 subaddr, u8 *data, int len)
+{
+       struct low_i2c_host *host = find_low_i2c_host(np);
+
+       if (!host)
+               return -ENODEV;
+       WARN_ON(!host->is_open);
+
+       return host->func(host, addrdir, subaddr, data, len);
+}
+EXPORT_SYMBOL(pmac_low_i2c_xfer);
+
diff --git a/arch/powerpc/platforms/powermac/nvram.c b/arch/powerpc/platforms/powermac/nvram.c
new file mode 100644 (file)
index 0000000..8c9b008
--- /dev/null
@@ -0,0 +1,584 @@
+/*
+ *  arch/ppc/platforms/pmac_nvram.c
+ *
+ *  Copyright (C) 2002 Benjamin Herrenschmidt (benh@kernel.crashing.org)
+ *
+ *  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.
+ *
+ *  Todo: - add support for the OF persistent properties
+ */
+#include <linux/config.h>
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/stddef.h>
+#include <linux/string.h>
+#include <linux/nvram.h>
+#include <linux/init.h>
+#include <linux/slab.h>
+#include <linux/delay.h>
+#include <linux/errno.h>
+#include <linux/adb.h>
+#include <linux/pmu.h>
+#include <linux/bootmem.h>
+#include <linux/completion.h>
+#include <linux/spinlock.h>
+#include <asm/sections.h>
+#include <asm/io.h>
+#include <asm/system.h>
+#include <asm/prom.h>
+#include <asm/machdep.h>
+#include <asm/nvram.h>
+
+#define DEBUG
+
+#ifdef DEBUG
+#define DBG(x...) printk(x)
+#else
+#define DBG(x...)
+#endif
+
+#define NVRAM_SIZE             0x2000  /* 8kB of non-volatile RAM */
+
+#define CORE99_SIGNATURE       0x5a
+#define CORE99_ADLER_START     0x14
+
+/* On Core99, nvram is either a sharp, a micron or an AMD flash */
+#define SM_FLASH_STATUS_DONE   0x80
+#define SM_FLASH_STATUS_ERR            0x38
+#define SM_FLASH_CMD_ERASE_CONFIRM     0xd0
+#define SM_FLASH_CMD_ERASE_SETUP       0x20
+#define SM_FLASH_CMD_RESET             0xff
+#define SM_FLASH_CMD_WRITE_SETUP       0x40
+#define SM_FLASH_CMD_CLEAR_STATUS      0x50
+#define SM_FLASH_CMD_READ_STATUS       0x70
+
+/* CHRP NVRAM header */
+struct chrp_header {
+  u8           signature;
+  u8           cksum;
+  u16          len;
+  char          name[12];
+  u8           data[0];
+};
+
+struct core99_header {
+  struct chrp_header   hdr;
+  u32                  adler;
+  u32                  generation;
+  u32                  reserved[2];
+};
+
+/*
+ * Read and write the non-volatile RAM on PowerMacs and CHRP machines.
+ */
+static int nvram_naddrs;
+static volatile unsigned char *nvram_addr;
+static volatile unsigned char *nvram_data;
+static int nvram_mult, is_core_99;
+static int core99_bank = 0;
+static int nvram_partitions[3];
+static DEFINE_SPINLOCK(nv_lock);
+
+extern int pmac_newworld;
+extern int system_running;
+
+static int (*core99_write_bank)(int bank, u8* datas);
+static int (*core99_erase_bank)(int bank);
+
+static char *nvram_image;
+
+
+static unsigned char core99_nvram_read_byte(int addr)
+{
+       if (nvram_image == NULL)
+               return 0xff;
+       return nvram_image[addr];
+}
+
+static void core99_nvram_write_byte(int addr, unsigned char val)
+{
+       if (nvram_image == NULL)
+               return;
+       nvram_image[addr] = val;
+}
+
+
+static unsigned char direct_nvram_read_byte(int addr)
+{
+       return in_8(&nvram_data[(addr & (NVRAM_SIZE - 1)) * nvram_mult]);
+}
+
+static void direct_nvram_write_byte(int addr, unsigned char val)
+{
+       out_8(&nvram_data[(addr & (NVRAM_SIZE - 1)) * nvram_mult], val);
+}
+
+
+static unsigned char indirect_nvram_read_byte(int addr)
+{
+       unsigned char val;
+       unsigned long flags;
+
+       spin_lock_irqsave(&nv_lock, flags);
+       out_8(nvram_addr, addr >> 5);
+       val = in_8(&nvram_data[(addr & 0x1f) << 4]);
+       spin_unlock_irqrestore(&nv_lock, flags);
+
+       return val;
+}
+
+static void indirect_nvram_write_byte(int addr, unsigned char val)
+{
+       unsigned long flags;
+
+       spin_lock_irqsave(&nv_lock, flags);
+       out_8(nvram_addr, addr >> 5);
+       out_8(&nvram_data[(addr & 0x1f) << 4], val);
+       spin_unlock_irqrestore(&nv_lock, flags);
+}
+
+
+#ifdef CONFIG_ADB_PMU
+
+static void pmu_nvram_complete(struct adb_request *req)
+{
+       if (req->arg)
+               complete((struct completion *)req->arg);
+}
+
+static unsigned char pmu_nvram_read_byte(int addr)
+{
+       struct adb_request req;
+       DECLARE_COMPLETION(req_complete); 
+       
+       req.arg = system_state == SYSTEM_RUNNING ? &req_complete : NULL;
+       if (pmu_request(&req, pmu_nvram_complete, 3, PMU_READ_NVRAM,
+                       (addr >> 8) & 0xff, addr & 0xff))
+               return 0xff;
+       if (system_state == SYSTEM_RUNNING)
+               wait_for_completion(&req_complete);
+       while (!req.complete)
+               pmu_poll();
+       return req.reply[0];
+}
+
+static void pmu_nvram_write_byte(int addr, unsigned char val)
+{
+       struct adb_request req;
+       DECLARE_COMPLETION(req_complete); 
+       
+       req.arg = system_state == SYSTEM_RUNNING ? &req_complete : NULL;
+       if (pmu_request(&req, pmu_nvram_complete, 4, PMU_WRITE_NVRAM,
+                       (addr >> 8) & 0xff, addr & 0xff, val))
+               return;
+       if (system_state == SYSTEM_RUNNING)
+               wait_for_completion(&req_complete);
+       while (!req.complete)
+               pmu_poll();
+}
+
+#endif /* CONFIG_ADB_PMU */
+
+
+static u8 chrp_checksum(struct chrp_header* hdr)
+{
+       u8 *ptr;
+       u16 sum = hdr->signature;
+       for (ptr = (u8 *)&hdr->len; ptr < hdr->data; ptr++)
+               sum += *ptr;
+       while (sum > 0xFF)
+               sum = (sum & 0xFF) + (sum>>8);
+       return sum;
+}
+
+static u32 core99_calc_adler(u8 *buffer)
+{
+       int cnt;
+       u32 low, high;
+
+       buffer += CORE99_ADLER_START;
+       low = 1;
+       high = 0;
+       for (cnt=0; cnt<(NVRAM_SIZE-CORE99_ADLER_START); cnt++) {
+               if ((cnt % 5000) == 0) {
+                       high  %= 65521UL;
+                       high %= 65521UL;
+               }
+               low += buffer[cnt];
+               high += low;
+       }
+       low  %= 65521UL;
+       high %= 65521UL;
+
+       return (high << 16) | low;
+}
+
+static u32 core99_check(u8* datas)
+{
+       struct core99_header* hdr99 = (struct core99_header*)datas;
+
+       if (hdr99->hdr.signature != CORE99_SIGNATURE) {
+               DBG("Invalid signature\n");
+               return 0;
+       }
+       if (hdr99->hdr.cksum != chrp_checksum(&hdr99->hdr)) {
+               DBG("Invalid checksum\n");
+               return 0;
+       }
+       if (hdr99->adler != core99_calc_adler(datas)) {
+               DBG("Invalid adler\n");
+               return 0;
+       }
+       return hdr99->generation;
+}
+
+static int sm_erase_bank(int bank)
+{
+       int stat, i;
+       unsigned long timeout;
+
+       u8* base = (u8 *)nvram_data + core99_bank*NVRAM_SIZE;
+
+               DBG("nvram: Sharp/Micron Erasing bank %d...\n", bank);
+
+       out_8(base, SM_FLASH_CMD_ERASE_SETUP);
+       out_8(base, SM_FLASH_CMD_ERASE_CONFIRM);
+       timeout = 0;
+       do {
+               if (++timeout > 1000000) {
+                       printk(KERN_ERR "nvram: Sharp/Miron flash erase timeout !\n");
+                       break;
+               }
+               out_8(base, SM_FLASH_CMD_READ_STATUS);
+               stat = in_8(base);
+       } while (!(stat & SM_FLASH_STATUS_DONE));
+
+       out_8(base, SM_FLASH_CMD_CLEAR_STATUS);
+       out_8(base, SM_FLASH_CMD_RESET);
+
+       for (i=0; i<NVRAM_SIZE; i++)
+               if (base[i] != 0xff) {
+                       printk(KERN_ERR "nvram: Sharp/Micron flash erase failed !\n");
+                       return -ENXIO;
+               }
+       return 0;
+}
+
+static int sm_write_bank(int bank, u8* datas)
+{
+       int i, stat = 0;
+       unsigned long timeout;
+
+       u8* base = (u8 *)nvram_data + core99_bank*NVRAM_SIZE;
+
+               DBG("nvram: Sharp/Micron Writing bank %d...\n", bank);
+
+       for (i=0; i<NVRAM_SIZE; i++) {
+               out_8(base+i, SM_FLASH_CMD_WRITE_SETUP);
+               udelay(1);
+               out_8(base+i, datas[i]);
+               timeout = 0;
+               do {
+                       if (++timeout > 1000000) {
+                               printk(KERN_ERR "nvram: Sharp/Micron flash write timeout !\n");
+                               break;
+                       }
+                       out_8(base, SM_FLASH_CMD_READ_STATUS);
+                       stat = in_8(base);
+               } while (!(stat & SM_FLASH_STATUS_DONE));
+               if (!(stat & SM_FLASH_STATUS_DONE))
+                       break;
+       }
+       out_8(base, SM_FLASH_CMD_CLEAR_STATUS);
+       out_8(base, SM_FLASH_CMD_RESET);
+       for (i=0; i<NVRAM_SIZE; i++)
+               if (base[i] != datas[i]) {
+                       printk(KERN_ERR "nvram: Sharp/Micron flash write failed !\n");
+                       return -ENXIO;
+               }
+       return 0;
+}
+
+static int amd_erase_bank(int bank)
+{
+       int i, stat = 0;
+       unsigned long timeout;
+
+       u8* base = (u8 *)nvram_data + core99_bank*NVRAM_SIZE;
+
+               DBG("nvram: AMD Erasing bank %d...\n", bank);
+
+       /* Unlock 1 */
+       out_8(base+0x555, 0xaa);
+       udelay(1);
+       /* Unlock 2 */
+       out_8(base+0x2aa, 0x55);
+       udelay(1);
+
+       /* Sector-Erase */
+       out_8(base+0x555, 0x80);
+       udelay(1);
+       out_8(base+0x555, 0xaa);
+       udelay(1);
+       out_8(base+0x2aa, 0x55);
+       udelay(1);
+       out_8(base, 0x30);
+       udelay(1);
+
+       timeout = 0;
+       do {
+               if (++timeout > 1000000) {
+                       printk(KERN_ERR "nvram: AMD flash erase timeout !\n");
+                       break;
+               }
+               stat = in_8(base) ^ in_8(base);
+       } while (stat != 0);
+       
+       /* Reset */
+       out_8(base, 0xf0);
+       udelay(1);
+       
+       for (i=0; i<NVRAM_SIZE; i++)
+               if (base[i] != 0xff) {
+                       printk(KERN_ERR "nvram: AMD flash erase failed !\n");
+                       return -ENXIO;
+               }
+       return 0;
+}
+
+static int amd_write_bank(int bank, u8* datas)
+{
+       int i, stat = 0;
+       unsigned long timeout;
+
+       u8* base = (u8 *)nvram_data + core99_bank*NVRAM_SIZE;
+
+               DBG("nvram: AMD Writing bank %d...\n", bank);
+
+       for (i=0; i<NVRAM_SIZE; i++) {
+               /* Unlock 1 */
+               out_8(base+0x555, 0xaa);
+               udelay(1);
+               /* Unlock 2 */
+               out_8(base+0x2aa, 0x55);
+               udelay(1);
+
+               /* Write single word */
+               out_8(base+0x555, 0xa0);
+               udelay(1);
+               out_8(base+i, datas[i]);
+               
+               timeout = 0;
+               do {
+                       if (++timeout > 1000000) {
+                               printk(KERN_ERR "nvram: AMD flash write timeout !\n");
+                               break;
+                       }
+                       stat = in_8(base) ^ in_8(base);
+               } while (stat != 0);
+               if (stat != 0)
+                       break;
+       }
+
+       /* Reset */
+       out_8(base, 0xf0);
+       udelay(1);
+
+       for (i=0; i<NVRAM_SIZE; i++)
+               if (base[i] != datas[i]) {
+                       printk(KERN_ERR "nvram: AMD flash write failed !\n");
+                       return -ENXIO;
+               }
+       return 0;
+}
+
+static void __init lookup_partitions(void)
+{
+       u8 buffer[17];
+       int i, offset;
+       struct chrp_header* hdr;
+
+       if (pmac_newworld) {
+               nvram_partitions[pmac_nvram_OF] = -1;
+               nvram_partitions[pmac_nvram_XPRAM] = -1;
+               nvram_partitions[pmac_nvram_NR] = -1;
+               hdr = (struct chrp_header *)buffer;
+
+               offset = 0;
+               buffer[16] = 0;
+               do {
+                       for (i=0;i<16;i++)
+                               buffer[i] = nvram_read_byte(offset+i);
+                       if (!strcmp(hdr->name, "common"))
+                               nvram_partitions[pmac_nvram_OF] = offset + 0x10;
+                       if (!strcmp(hdr->name, "APL,MacOS75")) {
+                               nvram_partitions[pmac_nvram_XPRAM] = offset + 0x10;
+                               nvram_partitions[pmac_nvram_NR] = offset + 0x110;
+                       }
+                       offset += (hdr->len * 0x10);
+               } while(offset < NVRAM_SIZE);
+       } else {
+               nvram_partitions[pmac_nvram_OF] = 0x1800;
+               nvram_partitions[pmac_nvram_XPRAM] = 0x1300;
+               nvram_partitions[pmac_nvram_NR] = 0x1400;
+       }
+       DBG("nvram: OF partition at 0x%x\n", nvram_partitions[pmac_nvram_OF]);
+       DBG("nvram: XP partition at 0x%x\n", nvram_partitions[pmac_nvram_XPRAM]);
+       DBG("nvram: NR partition at 0x%x\n", nvram_partitions[pmac_nvram_NR]);
+}
+
+static void core99_nvram_sync(void)
+{
+       struct core99_header* hdr99;
+       unsigned long flags;
+
+       if (!is_core_99 || !nvram_data || !nvram_image)
+               return;
+
+       spin_lock_irqsave(&nv_lock, flags);
+       if (!memcmp(nvram_image, (u8*)nvram_data + core99_bank*NVRAM_SIZE,
+               NVRAM_SIZE))
+               goto bail;
+
+       DBG("Updating nvram...\n");
+
+       hdr99 = (struct core99_header*)nvram_image;
+       hdr99->generation++;
+       hdr99->hdr.signature = CORE99_SIGNATURE;
+       hdr99->hdr.cksum = chrp_checksum(&hdr99->hdr);
+       hdr99->adler = core99_calc_adler(nvram_image);
+       core99_bank = core99_bank ? 0 : 1;
+       if (core99_erase_bank)
+               if (core99_erase_bank(core99_bank)) {
+                       printk("nvram: Error erasing bank %d\n", core99_bank);
+                       goto bail;
+               }
+       if (core99_write_bank)
+               if (core99_write_bank(core99_bank, nvram_image))
+                       printk("nvram: Error writing bank %d\n", core99_bank);
+ bail:
+       spin_unlock_irqrestore(&nv_lock, flags);
+
+#ifdef DEBUG
+               mdelay(2000);
+#endif
+}
+
+void __init pmac_nvram_init(void)
+{
+       struct device_node *dp;
+
+       nvram_naddrs = 0;
+
+       dp = find_devices("nvram");
+       if (dp == NULL) {
+               printk(KERN_ERR "Can't find NVRAM device\n");
+               return;
+       }
+       nvram_naddrs = dp->n_addrs;
+       is_core_99 = device_is_compatible(dp, "nvram,flash");
+       if (is_core_99) {
+               int i;
+               u32 gen_bank0, gen_bank1;
+
+               if (nvram_naddrs < 1) {
+                       printk(KERN_ERR "nvram: no address\n");
+                       return;
+               }
+               nvram_image = alloc_bootmem(NVRAM_SIZE);
+               if (nvram_image == NULL) {
+                       printk(KERN_ERR "nvram: can't allocate ram image\n");
+                       return;
+               }
+               nvram_data = ioremap(dp->addrs[0].address, NVRAM_SIZE*2);
+               nvram_naddrs = 1; /* Make sure we get the correct case */
+
+               DBG("nvram: Checking bank 0...\n");
+
+               gen_bank0 = core99_check((u8 *)nvram_data);
+               gen_bank1 = core99_check((u8 *)nvram_data + NVRAM_SIZE);
+               core99_bank = (gen_bank0 < gen_bank1) ? 1 : 0;
+
+               DBG("nvram: gen0=%d, gen1=%d\n", gen_bank0, gen_bank1);
+               DBG("nvram: Active bank is: %d\n", core99_bank);
+
+               for (i=0; i<NVRAM_SIZE; i++)
+                       nvram_image[i] = nvram_data[i + core99_bank*NVRAM_SIZE];
+
+               ppc_md.nvram_read_val   = core99_nvram_read_byte;
+               ppc_md.nvram_write_val  = core99_nvram_write_byte;
+               ppc_md.nvram_sync       = core99_nvram_sync;
+               /* 
+                * Maybe we could be smarter here though making an exclusive list
+                * of known flash chips is a bit nasty as older OF didn't provide us
+                * with a useful "compatible" entry. A solution would be to really
+                * identify the chip using flash id commands and base ourselves on
+                * a list of known chips IDs
+                */
+               if (device_is_compatible(dp, "amd-0137")) {
+                       core99_erase_bank = amd_erase_bank;
+                       core99_write_bank = amd_write_bank;
+               } else {
+                       core99_erase_bank = sm_erase_bank;
+                       core99_write_bank = sm_write_bank;
+               }
+       } else if (_machine == _MACH_chrp && nvram_naddrs == 1) {
+               nvram_data = ioremap(dp->addrs[0].address + isa_mem_base,
+                                    dp->addrs[0].size);
+               nvram_mult = 1;
+               ppc_md.nvram_read_val   = direct_nvram_read_byte;
+               ppc_md.nvram_write_val  = direct_nvram_write_byte;
+       } else if (nvram_naddrs == 1) {
+               nvram_data = ioremap(dp->addrs[0].address, dp->addrs[0].size);
+               nvram_mult = (dp->addrs[0].size + NVRAM_SIZE - 1) / NVRAM_SIZE;
+               ppc_md.nvram_read_val   = direct_nvram_read_byte;
+               ppc_md.nvram_write_val  = direct_nvram_write_byte;
+       } else if (nvram_naddrs == 2) {
+               nvram_addr = ioremap(dp->addrs[0].address, dp->addrs[0].size);
+               nvram_data = ioremap(dp->addrs[1].address, dp->addrs[1].size);
+               ppc_md.nvram_read_val   = indirect_nvram_read_byte;
+               ppc_md.nvram_write_val  = indirect_nvram_write_byte;
+       } else if (nvram_naddrs == 0 && sys_ctrler == SYS_CTRLER_PMU) {
+#ifdef CONFIG_ADB_PMU
+               nvram_naddrs = -1;
+               ppc_md.nvram_read_val   = pmu_nvram_read_byte;
+               ppc_md.nvram_write_val  = pmu_nvram_write_byte;
+#endif /* CONFIG_ADB_PMU */
+       } else {
+               printk(KERN_ERR "Don't know how to access NVRAM with %d addresses\n",
+                      nvram_naddrs);
+       }
+       lookup_partitions();
+}
+
+int pmac_get_partition(int partition)
+{
+       return nvram_partitions[partition];
+}
+
+u8 pmac_xpram_read(int xpaddr)
+{
+       int offset = nvram_partitions[pmac_nvram_XPRAM];
+
+       if (offset < 0)
+               return 0xff;
+
+       return ppc_md.nvram_read_val(xpaddr + offset);
+}
+
+void pmac_xpram_write(int xpaddr, u8 data)
+{
+       int offset = nvram_partitions[pmac_nvram_XPRAM];
+
+       if (offset < 0)
+               return;
+
+       ppc_md.nvram_write_val(xpaddr + offset, data);
+}
+
+EXPORT_SYMBOL(pmac_get_partition);
+EXPORT_SYMBOL(pmac_xpram_read);
+EXPORT_SYMBOL(pmac_xpram_write);
diff --git a/arch/powerpc/platforms/powermac/pci.c b/arch/powerpc/platforms/powermac/pci.c
new file mode 100644 (file)
index 0000000..40bcd3e
--- /dev/null
@@ -0,0 +1,1341 @@
+/*
+ * Support for PCI bridges found on Power Macintoshes.
+ * At present the "bandit" and "chaos" bridges are supported.
+ * Fortunately you access configuration space in the same
+ * way with either bridge.
+ *
+ * Copyright (C) 2003 Benjamin Herrenschmuidt (benh@kernel.crashing.org)
+ * Copyright (C) 1997 Paul Mackerras (paulus@samba.org)
+ *
+ * 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.
+ */
+
+#include <linux/kernel.h>
+#include <linux/pci.h>
+#include <linux/delay.h>
+#include <linux/string.h>
+#include <linux/init.h>
+#include <linux/bootmem.h>
+
+#include <asm/sections.h>
+#include <asm/io.h>
+#include <asm/prom.h>
+#include <asm/pci-bridge.h>
+#include <asm/machdep.h>
+#include <asm/pmac_feature.h>
+
+#undef DEBUG
+
+#ifdef DEBUG
+#define DBG(x...) printk(x)
+#else
+#define DBG(x...)
+#endif
+
+static int add_bridge(struct device_node *dev);
+extern void pmac_check_ht_link(void);
+
+/* XXX Could be per-controller, but I don't think we risk anything by
+ * assuming we won't have both UniNorth and Bandit */
+static int has_uninorth;
+#ifdef CONFIG_POWER4
+static struct pci_controller *u3_agp;
+#endif /* CONFIG_POWER4 */
+
+extern u8 pci_cache_line_size;
+extern int pcibios_assign_bus_offset;
+
+struct device_node *k2_skiplist[2];
+
+/*
+ * Magic constants for enabling cache coherency in the bandit/PSX bridge.
+ */
+#define BANDIT_DEVID_2 8
+#define BANDIT_REVID   3
+
+#define BANDIT_DEVNUM  11
+#define BANDIT_MAGIC   0x50
+#define BANDIT_COHERENT        0x40
+
+static int __init fixup_one_level_bus_range(struct device_node *node, int higher)
+{
+       for (; node != 0;node = node->sibling) {
+               int * bus_range;
+               unsigned int *class_code;
+               int len;
+
+               /* For PCI<->PCI bridges or CardBus bridges, we go down */
+               class_code = (unsigned int *) get_property(node, "class-code", NULL);
+               if (!class_code || ((*class_code >> 8) != PCI_CLASS_BRIDGE_PCI &&
+                       (*class_code >> 8) != PCI_CLASS_BRIDGE_CARDBUS))
+                       continue;
+               bus_range = (int *) get_property(node, "bus-range", &len);
+               if (bus_range != NULL && len > 2 * sizeof(int)) {
+                       if (bus_range[1] > higher)
+                               higher = bus_range[1];
+               }
+               higher = fixup_one_level_bus_range(node->child, higher);
+       }
+       return higher;
+}
+
+/* This routine fixes the "bus-range" property of all bridges in the
+ * system since they tend to have their "last" member wrong on macs
+ *
+ * Note that the bus numbers manipulated here are OF bus numbers, they
+ * are not Linux bus numbers.
+ */
+static void __init fixup_bus_range(struct device_node *bridge)
+{
+       int * bus_range;
+       int len;
+
+       /* Lookup the "bus-range" property for the hose */
+       bus_range = (int *) get_property(bridge, "bus-range", &len);
+       if (bus_range == NULL || len < 2 * sizeof(int)) {
+               printk(KERN_WARNING "Can't get bus-range for %s\n",
+                              bridge->full_name);
+               return;
+       }
+       bus_range[1] = fixup_one_level_bus_range(bridge->child, bus_range[1]);
+}
+
+/*
+ * Apple MacRISC (U3, UniNorth, Bandit, Chaos) PCI controllers.
+ *
+ * The "Bandit" version is present in all early PCI PowerMacs,
+ * and up to the first ones using Grackle. Some machines may
+ * have 2 bandit controllers (2 PCI busses).
+ *
+ * "Chaos" is used in some "Bandit"-type machines as a bridge
+ * for the separate display bus. It is accessed the same
+ * way as bandit, but cannot be probed for devices. It therefore
+ * has its own config access functions.
+ *
+ * The "UniNorth" version is present in all Core99 machines
+ * (iBook, G4, new IMacs, and all the recent Apple machines).
+ * It contains 3 controllers in one ASIC.
+ *
+ * The U3 is the bridge used on G5 machines. It contains an
+ * AGP bus which is dealt with the old UniNorth access routines
+ * and a HyperTransport bus which uses its own set of access
+ * functions.
+ */
+
+#define MACRISC_CFA0(devfn, off)       \
+       ((1 << (unsigned long)PCI_SLOT(dev_fn)) \
+       | (((unsigned long)PCI_FUNC(dev_fn)) << 8) \
+       | (((unsigned long)(off)) & 0xFCUL))
+
+#define MACRISC_CFA1(bus, devfn, off)  \
+       ((((unsigned long)(bus)) << 16) \
+       |(((unsigned long)(devfn)) << 8) \
+       |(((unsigned long)(off)) & 0xFCUL) \
+       |1UL)
+
+static unsigned long macrisc_cfg_access(struct pci_controller* hose,
+                                              u8 bus, u8 dev_fn, u8 offset)
+{
+       unsigned int caddr;
+
+       if (bus == hose->first_busno) {
+               if (dev_fn < (11 << 3))
+                       return 0;
+               caddr = MACRISC_CFA0(dev_fn, offset);
+       } else
+               caddr = MACRISC_CFA1(bus, dev_fn, offset);
+
+       /* Uninorth will return garbage if we don't read back the value ! */
+       do {
+               out_le32(hose->cfg_addr, caddr);
+       } while (in_le32(hose->cfg_addr) != caddr);
+
+       offset &= has_uninorth ? 0x07 : 0x03;
+       return ((unsigned long)hose->cfg_data) + offset;
+}
+
+static int macrisc_read_config(struct pci_bus *bus, unsigned int devfn,
+                                     int offset, int len, u32 *val)
+{
+       struct pci_controller *hose = bus->sysdata;
+       unsigned long addr;
+
+       addr = macrisc_cfg_access(hose, bus->number, devfn, offset);
+       if (!addr)
+               return PCIBIOS_DEVICE_NOT_FOUND;
+       /*
+        * Note: the caller has already checked that offset is
+        * suitably aligned and that len is 1, 2 or 4.
+        */
+       switch (len) {
+       case 1:
+               *val = in_8((u8 *)addr);
+               break;
+       case 2:
+               *val = in_le16((u16 *)addr);
+               break;
+       default:
+               *val = in_le32((u32 *)addr);
+               break;
+       }
+       return PCIBIOS_SUCCESSFUL;
+}
+
+static int macrisc_write_config(struct pci_bus *bus, unsigned int devfn,
+                                      int offset, int len, u32 val)
+{
+       struct pci_controller *hose = bus->sysdata;
+       unsigned long addr;
+
+       addr = macrisc_cfg_access(hose, bus->number, devfn, offset);
+       if (!addr)
+               return PCIBIOS_DEVICE_NOT_FOUND;
+       /*
+        * Note: the caller has already checked that offset is
+        * suitably aligned and that len is 1, 2 or 4.
+        */
+       switch (len) {
+       case 1:
+               out_8((u8 *)addr, val);
+               (void) in_8((u8 *)addr);
+               break;
+       case 2:
+               out_le16((u16 *)addr, val);
+               (void) in_le16((u16 *)addr);
+               break;
+       default:
+               out_le32((u32 *)addr, val);
+               (void) in_le32((u32 *)addr);
+               break;
+       }
+       return PCIBIOS_SUCCESSFUL;
+}
+
+static struct pci_ops macrisc_pci_ops =
+{
+       macrisc_read_config,
+       macrisc_write_config
+};
+
+/*
+ * Verifiy that a specific (bus, dev_fn) exists on chaos
+ */
+static int
+chaos_validate_dev(struct pci_bus *bus, int devfn, int offset)
+{
+       struct device_node *np;
+       u32 *vendor, *device;
+
+       np = pci_busdev_to_OF_node(bus, devfn);
+       if (np == NULL)
+               return PCIBIOS_DEVICE_NOT_FOUND;
+
+       vendor = (u32 *)get_property(np, "vendor-id", NULL);
+       device = (u32 *)get_property(np, "device-id", NULL);
+       if (vendor == NULL || device == NULL)
+               return PCIBIOS_DEVICE_NOT_FOUND;
+
+       if ((*vendor == 0x106b) && (*device == 3) && (offset >= 0x10)
+           && (offset != 0x14) && (offset != 0x18) && (offset <= 0x24))
+               return PCIBIOS_BAD_REGISTER_NUMBER;
+
+       return PCIBIOS_SUCCESSFUL;
+}
+
+static int
+chaos_read_config(struct pci_bus *bus, unsigned int devfn, int offset,
+                 int len, u32 *val)
+{
+       int result = chaos_validate_dev(bus, devfn, offset);
+       if (result == PCIBIOS_BAD_REGISTER_NUMBER)
+               *val = ~0U;
+       if (result != PCIBIOS_SUCCESSFUL)
+               return result;
+       return macrisc_read_config(bus, devfn, offset, len, val);
+}
+
+static int
+chaos_write_config(struct pci_bus *bus, unsigned int devfn, int offset,
+                  int len, u32 val)
+{
+       int result = chaos_validate_dev(bus, devfn, offset);
+       if (result != PCIBIOS_SUCCESSFUL)
+               return result;
+       return macrisc_write_config(bus, devfn, offset, len, val);
+}
+
+static struct pci_ops chaos_pci_ops =
+{
+       chaos_read_config,
+       chaos_write_config
+};
+
+#ifdef CONFIG_POWER4
+
+/*
+ * These versions of U3 HyperTransport config space access ops do not
+ * implement self-view of the HT host yet
+ */
+
+/*
+ * This function deals with some "special cases" devices.
+ *
+ *  0 -> No special case
+ *  1 -> Skip the device but act as if the access was successfull
+ *       (return 0xff's on reads, eventually, cache config space
+ *       accesses in a later version)
+ * -1 -> Hide the device (unsuccessful acess)
+ */
+static int u3_ht_skip_device(struct pci_controller *hose,
+                            struct pci_bus *bus, unsigned int devfn)
+{
+       struct device_node *busdn, *dn;
+       int i;
+
+       /* We only allow config cycles to devices that are in OF device-tree
+        * as we are apparently having some weird things going on with some
+        * revs of K2 on recent G5s
+        */
+       if (bus->self)
+               busdn = pci_device_to_OF_node(bus->self);
+       else
+               busdn = hose->arch_data;
+       for (dn = busdn->child; dn; dn = dn->sibling)
+               if (dn->data && PCI_DN(dn)->devfn == devfn)
+                       break;
+       if (dn == NULL)
+               return -1;
+
+       /*
+        * When a device in K2 is powered down, we die on config
+        * cycle accesses. Fix that here.
+        */
+       for (i=0; i<2; i++)
+               if (k2_skiplist[i] == dn)
+                       return 1;
+
+       return 0;
+}
+
+#define U3_HT_CFA0(devfn, off)         \
+               ((((unsigned long)devfn) << 8) | offset)
+#define U3_HT_CFA1(bus, devfn, off)    \
+               (U3_HT_CFA0(devfn, off) \
+               + (((unsigned long)bus) << 16) \
+               + 0x01000000UL)
+
+static unsigned long u3_ht_cfg_access(struct pci_controller* hose,
+                                            u8 bus, u8 devfn, u8 offset)
+{
+       if (bus == hose->first_busno) {
+               /* For now, we don't self probe U3 HT bridge */
+               if (PCI_SLOT(devfn) == 0)
+                       return 0;
+               return ((unsigned long)hose->cfg_data) + U3_HT_CFA0(devfn, offset);
+       } else
+               return ((unsigned long)hose->cfg_data) + U3_HT_CFA1(bus, devfn, offset);
+}
+
+static int u3_ht_read_config(struct pci_bus *bus, unsigned int devfn,
+                                   int offset, int len, u32 *val)
+{
+       struct pci_controller *hose = bus->sysdata;
+       unsigned long addr;
+
+       struct device_node *np = pci_busdev_to_OF_node(bus, devfn);
+       if (np == NULL)
+               return PCIBIOS_DEVICE_NOT_FOUND;
+
+       addr = u3_ht_cfg_access(hose, bus->number, devfn, offset);
+       if (!addr)
+               return PCIBIOS_DEVICE_NOT_FOUND;
+
+       switch (u3_ht_skip_device(hose, bus, devfn)) {
+       case 0:
+               break;
+       case 1:
+                       switch (len) {
+                       case 1:
+                               *val = 0xff; break;
+                       case 2:
+                               *val = 0xffff; break;
+                       default:
+                               *val = 0xfffffffful; break;
+                       }
+                       return PCIBIOS_SUCCESSFUL;
+       default:
+               return PCIBIOS_DEVICE_NOT_FOUND;
+               }
+           
+       /*
+        * Note: the caller has already checked that offset is
+        * suitably aligned and that len is 1, 2 or 4.
+        */
+       switch (len) {
+       case 1:
+               *val = in_8((u8 *)addr);
+               break;
+       case 2:
+               *val = in_le16((u16 *)addr);
+               break;
+       default:
+               *val = in_le32((u32 *)addr);
+               break;
+       }
+       return PCIBIOS_SUCCESSFUL;
+}
+
+static int u3_ht_write_config(struct pci_bus *bus, unsigned int devfn,
+                                    int offset, int len, u32 val)
+{
+       struct pci_controller *hose = bus->sysdata;
+       unsigned long addr;
+
+       struct device_node *np = pci_busdev_to_OF_node(bus, devfn);
+       if (np == NULL)
+               return PCIBIOS_DEVICE_NOT_FOUND;
+
+       addr = u3_ht_cfg_access(hose, bus->number, devfn, offset);
+       if (!addr)
+               return PCIBIOS_DEVICE_NOT_FOUND;
+
+       switch (u3_ht_skip_device(hose, bus, devfn)) {
+       case 0:
+               break;
+       case 1:
+               return PCIBIOS_SUCCESSFUL;
+       default:
+               return PCIBIOS_DEVICE_NOT_FOUND;
+       }
+
+       /*
+        * Note: the caller has already checked that offset is
+        * suitably aligned and that len is 1, 2 or 4.
+        */
+       switch (len) {
+       case 1:
+               out_8((u8 *)addr, val);
+               (void) in_8((u8 *)addr);
+               break;
+       case 2:
+               out_le16((u16 *)addr, val);
+               (void) in_le16((u16 *)addr);
+               break;
+       default:
+               out_le32((u32 *)addr, val);
+               (void) in_le32((u32 *)addr);
+               break;
+       }
+       return PCIBIOS_SUCCESSFUL;
+}
+
+static struct pci_ops u3_ht_pci_ops =
+{
+       u3_ht_read_config,
+       u3_ht_write_config
+};
+
+#endif /* CONFIG_POWER4 */
+
+/*
+ * For a bandit bridge, turn on cache coherency if necessary.
+ * N.B. we could clean this up using the hose ops directly.
+ */
+static void __init
+init_bandit(struct pci_controller *bp)
+{
+       unsigned int vendev, magic;
+       int rev;
+
+       /* read the word at offset 0 in config space for device 11 */
+       out_le32(bp->cfg_addr, (1UL << BANDIT_DEVNUM) + PCI_VENDOR_ID);
+       udelay(2);
+       vendev = in_le32(bp->cfg_data);
+       if (vendev == (PCI_DEVICE_ID_APPLE_BANDIT << 16) +
+                       PCI_VENDOR_ID_APPLE) {
+               /* read the revision id */
+               out_le32(bp->cfg_addr,
+                        (1UL << BANDIT_DEVNUM) + PCI_REVISION_ID);
+               udelay(2);
+               rev = in_8(bp->cfg_data);
+               if (rev != BANDIT_REVID)
+                       printk(KERN_WARNING
+                              "Unknown revision %d for bandit\n", rev);
+       } else if (vendev != (BANDIT_DEVID_2 << 16) + PCI_VENDOR_ID_APPLE) {
+               printk(KERN_WARNING "bandit isn't? (%x)\n", vendev);
+               return;
+       }
+
+       /* read the word at offset 0x50 */
+       out_le32(bp->cfg_addr, (1UL << BANDIT_DEVNUM) + BANDIT_MAGIC);
+       udelay(2);
+       magic = in_le32(bp->cfg_data);
+       if ((magic & BANDIT_COHERENT) != 0)
+               return;
+       magic |= BANDIT_COHERENT;
+       udelay(2);
+       out_le32(bp->cfg_data, magic);
+       printk(KERN_INFO "Cache coherency enabled for bandit/PSX\n");
+}
+
+
+/*
+ * Tweak the PCI-PCI bridge chip on the blue & white G3s.
+ */
+static void __init
+init_p2pbridge(void)
+{
+       struct device_node *p2pbridge;
+       struct pci_controller* hose;
+       u8 bus, devfn;
+       u16 val;
+
+       /* XXX it would be better here to identify the specific
+          PCI-PCI bridge chip we have. */
+       if ((p2pbridge = find_devices("pci-bridge")) == 0
+           || p2pbridge->parent == NULL
+           || strcmp(p2pbridge->parent->name, "pci") != 0)
+               return;
+       if (pci_device_from_OF_node(p2pbridge, &bus, &devfn) < 0) {
+               DBG("Can't find PCI infos for PCI<->PCI bridge\n");
+               return;
+       }
+       /* Warning: At this point, we have not yet renumbered all busses.
+        * So we must use OF walking to find out hose
+        */
+       hose = pci_find_hose_for_OF_device(p2pbridge);
+       if (!hose) {
+               DBG("Can't find hose for PCI<->PCI bridge\n");
+               return;
+       }
+       if (early_read_config_word(hose, bus, devfn,
+                                  PCI_BRIDGE_CONTROL, &val) < 0) {
+               printk(KERN_ERR "init_p2pbridge: couldn't read bridge control\n");
+               return;
+       }
+       val &= ~PCI_BRIDGE_CTL_MASTER_ABORT;
+       early_write_config_word(hose, bus, devfn, PCI_BRIDGE_CONTROL, val);
+}
+
+/*
+ * Some Apple desktop machines have a NEC PD720100A USB2 controller
+ * on the motherboard. Open Firmware, on these, will disable the
+ * EHCI part of it so it behaves like a pair of OHCI's. This fixup
+ * code re-enables it ;)
+ */
+static void __init
+fixup_nec_usb2(void)
+{
+       struct device_node *nec;
+
+       for (nec = NULL; (nec = of_find_node_by_name(nec, "usb")) != NULL;) {
+               struct pci_controller *hose;
+               u32 data, *prop;
+               u8 bus, devfn;
+               
+               prop = (u32 *)get_property(nec, "vendor-id", NULL);
+               if (prop == NULL)
+                       continue;
+               if (0x1033 != *prop)
+                       continue;
+               prop = (u32 *)get_property(nec, "device-id", NULL);
+               if (prop == NULL)
+                       continue;
+               if (0x0035 != *prop)
+                       continue;
+               prop = (u32 *)get_property(nec, "reg", NULL);
+               if (prop == NULL)
+                       continue;
+               devfn = (prop[0] >> 8) & 0xff;
+               bus = (prop[0] >> 16) & 0xff;
+               if (PCI_FUNC(devfn) != 0)
+                       continue;
+               hose = pci_find_hose_for_OF_device(nec);
+               if (!hose)
+                       continue;
+               early_read_config_dword(hose, bus, devfn, 0xe4, &data);
+               if (data & 1UL) {
+                       printk("Found NEC PD720100A USB2 chip with disabled EHCI, fixing up...\n");
+                       data &= ~1UL;
+                       early_write_config_dword(hose, bus, devfn, 0xe4, data);
+                       early_write_config_byte(hose, bus, devfn | 2, PCI_INTERRUPT_LINE,
+                               nec->intrs[0].line);
+               }
+       }
+}
+
+void __init
+pmac_find_bridges(void)
+{
+       struct device_node *np, *root;
+       struct device_node *ht = NULL;
+
+       root = of_find_node_by_path("/");
+       if (root == NULL) {
+               printk(KERN_CRIT "pmac_find_bridges: can't find root of device tree\n");
+               return;
+       }
+       for (np = NULL; (np = of_get_next_child(root, np)) != NULL;) {
+               if (np->name == NULL)
+                       continue;
+               if (strcmp(np->name, "bandit") == 0
+                   || strcmp(np->name, "chaos") == 0
+                   || strcmp(np->name, "pci") == 0) {
+                       if (add_bridge(np) == 0)
+                               of_node_get(np);
+               }
+               if (strcmp(np->name, "ht") == 0) {
+                       of_node_get(np);
+                       ht = np;
+               }
+       }
+       of_node_put(root);
+
+       /* Probe HT last as it relies on the agp resources to be already
+        * setup
+        */
+       if (ht && add_bridge(ht) != 0)
+               of_node_put(ht);
+
+       init_p2pbridge();
+       fixup_nec_usb2();
+       
+       /* We are still having some issues with the Xserve G4, enabling
+        * some offset between bus number and domains for now when we
+        * assign all busses should help for now
+        */
+       if (pci_assign_all_busses)
+               pcibios_assign_bus_offset = 0x10;
+
+#ifdef CONFIG_POWER4 
+       /* There is something wrong with DMA on U3/HT. I haven't figured out
+        * the details yet, but if I set the cache line size to 128 bytes like
+        * it should, I'm getting memory corruption caused by devices like
+        * sungem (even without the MWI bit set, but maybe sungem doesn't
+        * care). Right now, it appears that setting up a 64 bytes line size
+        * works properly, 64 bytes beeing the max transfer size of HT, I
+        * suppose this is related the way HT/PCI are hooked together. I still
+        * need to dive into more specs though to be really sure of what's
+        * going on. --BenH.
+        *
+        * Ok, apparently, it's just that HT can't do more than 64 bytes
+        * transactions. MWI seem to be meaningless there as well, it may
+        * be worth nop'ing out pci_set_mwi too though I haven't done that
+        * yet.
+        *
+        * Note that it's a bit different for whatever is in the AGP slot.
+        * For now, I don't care, but this can become a real issue, we
+        * should probably hook pci_set_mwi anyway to make sure it sets
+        * the real cache line size in there.
+        */
+       if (machine_is_compatible("MacRISC4"))
+               pci_cache_line_size = 16; /* 64 bytes */
+
+       pmac_check_ht_link();
+#endif /* CONFIG_POWER4 */
+}
+
+#define GRACKLE_CFA(b, d, o)   (0x80 | ((b) << 8) | ((d) << 16) \
+                                | (((o) & ~3) << 24))
+
+#define GRACKLE_PICR1_STG              0x00000040
+#define GRACKLE_PICR1_LOOPSNOOP                0x00000010
+
+/* N.B. this is called before bridges is initialized, so we can't
+   use grackle_pcibios_{read,write}_config_dword. */
+static inline void grackle_set_stg(struct pci_controller* bp, int enable)
+{
+       unsigned int val;
+
+       out_be32(bp->cfg_addr, GRACKLE_CFA(0, 0, 0xa8));
+       val = in_le32(bp->cfg_data);
+       val = enable? (val | GRACKLE_PICR1_STG) :
+               (val & ~GRACKLE_PICR1_STG);
+       out_be32(bp->cfg_addr, GRACKLE_CFA(0, 0, 0xa8));
+       out_le32(bp->cfg_data, val);
+       (void)in_le32(bp->cfg_data);
+}
+
+static inline void grackle_set_loop_snoop(struct pci_controller *bp, int enable)
+{
+       unsigned int val;
+
+       out_be32(bp->cfg_addr, GRACKLE_CFA(0, 0, 0xa8));
+       val = in_le32(bp->cfg_data);
+       val = enable? (val | GRACKLE_PICR1_LOOPSNOOP) :
+               (val & ~GRACKLE_PICR1_LOOPSNOOP);
+       out_be32(bp->cfg_addr, GRACKLE_CFA(0, 0, 0xa8));
+       out_le32(bp->cfg_data, val);
+       (void)in_le32(bp->cfg_data);
+}
+
+static int __init
+setup_uninorth(struct pci_controller* hose, struct reg_property* addr)
+{
+       pci_assign_all_busses = 1;
+       has_uninorth = 1;
+       hose->ops = &macrisc_pci_ops;
+       hose->cfg_addr = ioremap(addr->address + 0x800000, 0x1000);
+       hose->cfg_data = ioremap(addr->address + 0xc00000, 0x1000);
+       /* We "know" that the bridge at f2000000 has the PCI slots. */
+       return addr->address == 0xf2000000;
+}
+
+static void __init
+setup_bandit(struct pci_controller* hose, struct reg_property* addr)
+{
+       hose->ops = &macrisc_pci_ops;
+       hose->cfg_addr = ioremap(addr->address + 0x800000, 0x1000);
+       hose->cfg_data = ioremap(addr->address + 0xc00000, 0x1000);
+       init_bandit(hose);
+}
+
+static void __init
+setup_chaos(struct pci_controller* hose, struct reg_property* addr)
+{
+       /* assume a `chaos' bridge */
+       hose->ops = &chaos_pci_ops;
+       hose->cfg_addr = ioremap(addr->address + 0x800000, 0x1000);
+       hose->cfg_data = ioremap(addr->address + 0xc00000, 0x1000);
+}
+
+#ifdef CONFIG_POWER4
+
+static void __init setup_u3_agp(struct pci_controller* hose)
+{
+       /* On G5, we move AGP up to high bus number so we don't need
+        * to reassign bus numbers for HT. If we ever have P2P bridges
+        * on AGP, we'll have to move pci_assign_all_busses to the
+        * pci_controller structure so we enable it for AGP and not for
+        * HT childs.
+        * We hard code the address because of the different size of
+        * the reg address cell, we shall fix that by killing struct
+        * reg_property and using some accessor functions instead
+        */
+               hose->first_busno = 0xf0;
+       hose->last_busno = 0xff;
+       has_uninorth = 1;
+       hose->ops = &macrisc_pci_ops;
+       hose->cfg_addr = ioremap(0xf0000000 + 0x800000, 0x1000);
+       hose->cfg_data = ioremap(0xf0000000 + 0xc00000, 0x1000);
+
+       u3_agp = hose;
+}
+
+static void __init setup_u3_ht(struct pci_controller* hose)
+{
+       struct device_node *np = (struct device_node *)hose->arch_data;
+       int i, cur;
+
+       hose->ops = &u3_ht_pci_ops;
+
+       /* We hard code the address because of the different size of
+        * the reg address cell, we shall fix that by killing struct
+        * reg_property and using some accessor functions instead
+        */
+       hose->cfg_data = (volatile unsigned char *)ioremap(0xf2000000, 0x02000000);
+
+       /*
+        * /ht node doesn't expose a "ranges" property, so we "remove" regions that
+        * have been allocated to AGP. So far, this version of the code doesn't assign
+        * any of the 0xfxxxxxxx "fine" memory regions to /ht.
+        * We need to fix that sooner or later by either parsing all child "ranges"
+        * properties or figuring out the U3 address space decoding logic and
+        * then read its configuration register (if any).
+        */
+       hose->io_base_phys = 0xf4000000;
+       hose->io_base_virt = ioremap(hose->io_base_phys, 0x00400000);
+       isa_io_base = (unsigned long) hose->io_base_virt;
+       hose->io_resource.name = np->full_name;
+       hose->io_resource.start = 0;
+       hose->io_resource.end = 0x003fffff;
+       hose->io_resource.flags = IORESOURCE_IO;
+       hose->pci_mem_offset = 0;
+       hose->first_busno = 0;
+       hose->last_busno = 0xef;
+       hose->mem_resources[0].name = np->full_name;
+       hose->mem_resources[0].start = 0x80000000;
+       hose->mem_resources[0].end = 0xefffffff;
+       hose->mem_resources[0].flags = IORESOURCE_MEM;
+
+       if (u3_agp == NULL) {
+               DBG("U3 has no AGP, using full resource range\n");
+               return;
+       }
+
+       /* We "remove" the AGP resources from the resources allocated to HT, that
+        * is we create "holes". However, that code does assumptions that so far
+        * happen to be true (cross fingers...), typically that resources in the
+        * AGP node are properly ordered
+        */
+       cur = 0;
+       for (i=0; i<3; i++) {
+               struct resource *res = &u3_agp->mem_resources[i];
+               if (res->flags != IORESOURCE_MEM)
+                       continue;
+               /* We don't care about "fine" resources */
+               if (res->start >= 0xf0000000)
+                       continue;
+               /* Check if it's just a matter of "shrinking" us in one direction */
+               if (hose->mem_resources[cur].start == res->start) {
+                       DBG("U3/HT: shrink start of %d, %08lx -> %08lx\n",
+                           cur, hose->mem_resources[cur].start, res->end + 1);
+                       hose->mem_resources[cur].start = res->end + 1;
+                       continue;
+               }
+               if (hose->mem_resources[cur].end == res->end) {
+                       DBG("U3/HT: shrink end of %d, %08lx -> %08lx\n",
+                           cur, hose->mem_resources[cur].end, res->start - 1);
+                       hose->mem_resources[cur].end = res->start - 1;
+                       continue;
+               }
+               /* No, it's not the case, we need a hole */
+               if (cur == 2) {
+                       /* not enough resources to make a hole, we drop part of the range */
+                       printk(KERN_WARNING "Running out of resources for /ht host !\n");
+                       hose->mem_resources[cur].end = res->start - 1;
+                       continue;
+               }               
+               cur++;
+                       DBG("U3/HT: hole, %d end at %08lx, %d start at %08lx\n",
+                   cur-1, res->start - 1, cur, res->end + 1);
+               hose->mem_resources[cur].name = np->full_name;
+               hose->mem_resources[cur].flags = IORESOURCE_MEM;
+               hose->mem_resources[cur].start = res->end + 1;
+               hose->mem_resources[cur].end = hose->mem_resources[cur-1].end;
+               hose->mem_resources[cur-1].end = res->start - 1;
+       }
+}
+
+#endif /* CONFIG_POWER4 */
+
+void __init
+setup_grackle(struct pci_controller *hose)
+{
+       setup_indirect_pci(hose, 0xfec00000, 0xfee00000);
+       if (machine_is_compatible("AAPL,PowerBook1998"))
+               grackle_set_loop_snoop(hose, 1);
+#if 0  /* Disabled for now, HW problems ??? */
+       grackle_set_stg(hose, 1);
+#endif
+}
+
+static void __init pmac_process_bridge_OF_ranges(struct pci_controller *hose,
+                          struct device_node *dev, int primary)
+{
+       static unsigned int static_lc_ranges[2024];
+       unsigned int *dt_ranges, *lc_ranges, *ranges, *prev;
+       unsigned int size;
+       int rlen = 0, orig_rlen;
+       int memno = 0;
+       struct resource *res;
+       int np, na = prom_n_addr_cells(dev);
+
+       np = na + 5;
+
+       /* First we try to merge ranges to fix a problem with some pmacs
+        * that can have more than 3 ranges, fortunately using contiguous
+        * addresses -- BenH
+        */
+       dt_ranges = (unsigned int *) get_property(dev, "ranges", &rlen);
+       if (!dt_ranges)
+               return;
+       /*      lc_ranges = alloc_bootmem(rlen);*/
+       lc_ranges = static_lc_ranges;
+       if (!lc_ranges)
+               return; /* what can we do here ? */
+       memcpy(lc_ranges, dt_ranges, rlen);
+       orig_rlen = rlen;
+
+       /* Let's work on a copy of the "ranges" property instead of damaging
+        * the device-tree image in memory
+        */
+       ranges = lc_ranges;
+       prev = NULL;
+       while ((rlen -= np * sizeof(unsigned int)) >= 0) {
+               if (prev) {
+                       if (prev[0] == ranges[0] && prev[1] == ranges[1] &&
+                               (prev[2] + prev[na+4]) == ranges[2] &&
+                               (prev[na+2] + prev[na+4]) == ranges[na+2]) {
+                               prev[na+4] += ranges[na+4];
+                               ranges[0] = 0;
+                               ranges += np;
+                               continue;
+                       }
+               }
+               prev = ranges;
+               ranges += np;
+       }
+
+       /*
+        * The ranges property is laid out as an array of elements,
+        * each of which comprises:
+        *   cells 0 - 2:       a PCI address
+        *   cells 3 or 3+4:    a CPU physical address
+        *                      (size depending on dev->n_addr_cells)
+        *   cells 4+5 or 5+6:  the size of the range
+        */
+       ranges = lc_ranges;
+       rlen = orig_rlen;
+       while (ranges && (rlen -= np * sizeof(unsigned int)) >= 0) {
+               res = NULL;
+               size = ranges[na+4];
+               switch (ranges[0] >> 24) {
+               case 1:         /* I/O space */
+                       if (ranges[2] != 0)
+                               break;
+                       hose->io_base_phys = ranges[na+2];
+                       /* limit I/O space to 16MB */
+                       if (size > 0x01000000)
+                               size = 0x01000000;
+                       hose->io_base_virt = ioremap(ranges[na+2], size);
+                       if (primary)
+                               isa_io_base = (unsigned long) hose->io_base_virt;
+                       res = &hose->io_resource;
+                       res->flags = IORESOURCE_IO;
+                       res->start = ranges[2];
+                       break;
+               case 2:         /* memory space */
+                       memno = 0;
+                       if (ranges[1] == 0 && ranges[2] == 0
+                           && ranges[na+4] <= (16 << 20)) {
+                               /* 1st 16MB, i.e. ISA memory area */
+#if 0
+                               if (primary)
+                                       isa_mem_base = ranges[na+2];
+#endif
+                               memno = 1;
+                       }
+                       while (memno < 3 && hose->mem_resources[memno].flags)
+                               ++memno;
+                       if (memno == 0)
+                               hose->pci_mem_offset = ranges[na+2] - ranges[2];
+                       if (memno < 3) {
+                               res = &hose->mem_resources[memno];
+                               res->flags = IORESOURCE_MEM;
+                               res->start = ranges[na+2];
+                       }
+                       break;
+               }
+               if (res != NULL) {
+                       res->name = dev->full_name;
+                       res->end = res->start + size - 1;
+                       res->parent = NULL;
+                       res->sibling = NULL;
+                       res->child = NULL;
+               }
+               ranges += np;
+       }
+}
+
+/*
+ * We assume that if we have a G3 powermac, we have one bridge called
+ * "pci" (a MPC106) and no bandit or chaos bridges, and contrariwise,
+ * if we have one or more bandit or chaos bridges, we don't have a MPC106.
+ */
+static int __init add_bridge(struct device_node *dev)
+{
+       int len;
+       struct pci_controller *hose;
+       struct reg_property *addr;
+       char* disp_name;
+       int *bus_range;
+       int primary = 1;
+
+       DBG("Adding PCI host bridge %s\n", dev->full_name);
+
+               addr = (struct reg_property *) get_property(dev, "reg", &len);
+               if (addr == NULL || len < sizeof(*addr)) {
+                       printk(KERN_WARNING "Can't use %s: no address\n",
+                              dev->full_name);
+                       return -ENODEV;
+               }
+               bus_range = (int *) get_property(dev, "bus-range", &len);
+               if (bus_range == NULL || len < 2 * sizeof(int)) {
+                       printk(KERN_WARNING "Can't get bus-range for %s, assume bus 0\n",
+                                      dev->full_name);
+               }
+
+               hose = pcibios_alloc_controller();
+               if (!hose)
+                       return -ENOMEM;
+               hose->arch_data = dev;
+               hose->first_busno = bus_range ? bus_range[0] : 0;
+               hose->last_busno = bus_range ? bus_range[1] : 0xff;
+
+       disp_name = NULL;
+#ifdef CONFIG_POWER4
+               if (device_is_compatible(dev, "u3-agp")) {
+                       setup_u3_agp(hose, addr);
+                       disp_name = "U3-AGP";
+                       primary = 0;
+               } else if (device_is_compatible(dev, "u3-ht")) {
+                       setup_u3_ht(hose, addr);
+                       disp_name = "U3-HT";
+                       primary = 1;
+               } else
+#endif /* CONFIG_POWER4 */
+       if (device_is_compatible(dev, "uni-north")) {
+                       primary = setup_uninorth(hose, addr);
+                       disp_name = "UniNorth";
+               } else if (strcmp(dev->name, "pci") == 0) {
+                       /* XXX assume this is a mpc106 (grackle) */
+                       setup_grackle(hose);
+                       disp_name = "Grackle (MPC106)";
+               } else if (strcmp(dev->name, "bandit") == 0) {
+                       setup_bandit(hose, addr);
+                       disp_name = "Bandit";
+               } else if (strcmp(dev->name, "chaos") == 0) {
+                       setup_chaos(hose, addr);
+                       disp_name = "Chaos";
+                       primary = 0;
+               }
+               printk(KERN_INFO "Found %s PCI host bridge at 0x%08x. Firmware bus number: %d->%d\n",
+                       disp_name, addr->address, hose->first_busno, hose->last_busno);
+               DBG(" ->Hose at 0x%p, cfg_addr=0x%p,cfg_data=0x%p\n",
+                       hose, hose->cfg_addr, hose->cfg_data);
+
+               /* Interpret the "ranges" property */
+               /* This also maps the I/O region and sets isa_io/mem_base */
+               pci_process_bridge_OF_ranges(hose, dev, primary);
+
+               /* Fixup "bus-range" OF property */
+               fixup_bus_range(dev);
+
+       return 0;
+}
+
+static void __init
+pcibios_fixup_OF_interrupts(void)
+{
+       struct pci_dev* dev = NULL;
+
+       /*
+        * Open Firmware often doesn't initialize the
+        * PCI_INTERRUPT_LINE config register properly, so we
+        * should find the device node and apply the interrupt
+        * obtained from the OF device-tree
+        */
+       for_each_pci_dev(dev) {
+               struct device_node *node;
+               node = pci_device_to_OF_node(dev);
+               /* this is the node, see if it has interrupts */
+               if (node && node->n_intrs > 0)
+                       dev->irq = node->intrs[0].line;
+               pci_write_config_byte(dev, PCI_INTERRUPT_LINE, dev->irq);
+       }
+}
+
+void __init
+pmac_pcibios_fixup(void)
+{
+       /* Fixup interrupts according to OF tree */
+       pcibios_fixup_OF_interrupts();
+}
+
+int
+pmac_pci_enable_device_hook(struct pci_dev *dev, int initial)
+{
+       struct device_node* node;
+       int updatecfg = 0;
+       int uninorth_child;
+
+       node = pci_device_to_OF_node(dev);
+
+       /* We don't want to enable USB controllers absent from the OF tree
+        * (iBook second controller)
+        */
+       if (dev->vendor == PCI_VENDOR_ID_APPLE
+           && (dev->class == ((PCI_CLASS_SERIAL_USB << 8) | 0x10))
+           && !node) {
+               printk(KERN_INFO "Apple USB OHCI %s disabled by firmware\n",
+                      pci_name(dev));
+               return -EINVAL;
+       }
+
+       if (!node)
+               return 0;
+
+       uninorth_child = node->parent &&
+               device_is_compatible(node->parent, "uni-north");
+       
+       /* Firewire & GMAC were disabled after PCI probe, the driver is
+        * claiming them, we must re-enable them now.
+        */
+       if (uninorth_child && !strcmp(node->name, "firewire") &&
+           (device_is_compatible(node, "pci106b,18") ||
+            device_is_compatible(node, "pci106b,30") ||
+            device_is_compatible(node, "pci11c1,5811"))) {
+               pmac_call_feature(PMAC_FTR_1394_CABLE_POWER, node, 0, 1);
+               pmac_call_feature(PMAC_FTR_1394_ENABLE, node, 0, 1);
+               updatecfg = 1;
+       }
+       if (uninorth_child && !strcmp(node->name, "ethernet") &&
+           device_is_compatible(node, "gmac")) {
+               pmac_call_feature(PMAC_FTR_GMAC_ENABLE, node, 0, 1);
+               updatecfg = 1;
+       }
+
+       if (updatecfg) {
+               u16 cmd;
+       
+               /*
+                * Make sure PCI is correctly configured
+                *
+                * We use old pci_bios versions of the function since, by
+                * default, gmac is not powered up, and so will be absent
+                * from the kernel initial PCI lookup.
+                *
+                * Should be replaced by 2.4 new PCI mechanisms and really
+                * register the device.
+                */
+               pci_read_config_word(dev, PCI_COMMAND, &cmd);
+               cmd |= PCI_COMMAND_MEMORY | PCI_COMMAND_MASTER | PCI_COMMAND_INVALIDATE;
+               pci_write_config_word(dev, PCI_COMMAND, cmd);
+               pci_write_config_byte(dev, PCI_LATENCY_TIMER, 16);
+               pci_write_config_byte(dev, PCI_CACHE_LINE_SIZE, pci_cache_line_size);
+       }
+
+       return 0;
+}
+
+/* We power down some devices after they have been probed. They'll
+ * be powered back on later on
+ */
+void __init
+pmac_pcibios_after_init(void)
+{
+       struct device_node* nd;
+
+#ifdef CONFIG_BLK_DEV_IDE
+       struct pci_dev *dev = NULL;
+
+       /* OF fails to initialize IDE controllers on macs
+        * (and maybe other machines)
+        *
+        * Ideally, this should be moved to the IDE layer, but we need
+        * to check specifically with Andre Hedrick how to do it cleanly
+        * since the common IDE code seem to care about the fact that the
+        * BIOS may have disabled a controller.
+        *
+        * -- BenH
+        */
+       for_each_pci_dev(dev) {
+               if ((dev->class >> 16) == PCI_BASE_CLASS_STORAGE)
+                       pci_enable_device(dev);
+       }
+#endif /* CONFIG_BLK_DEV_IDE */
+
+       nd = find_devices("firewire");
+       while (nd) {
+               if (nd->parent && (device_is_compatible(nd, "pci106b,18") ||
+                                  device_is_compatible(nd, "pci106b,30") ||
+                                  device_is_compatible(nd, "pci11c1,5811"))
+                   && device_is_compatible(nd->parent, "uni-north")) {
+                       pmac_call_feature(PMAC_FTR_1394_ENABLE, nd, 0, 0);
+                       pmac_call_feature(PMAC_FTR_1394_CABLE_POWER, nd, 0, 0);
+               }
+               nd = nd->next;
+       }
+       nd = find_devices("ethernet");
+       while (nd) {
+               if (nd->parent && device_is_compatible(nd, "gmac")
+                   && device_is_compatible(nd->parent, "uni-north"))
+                       pmac_call_feature(PMAC_FTR_GMAC_ENABLE, nd, 0, 0);
+               nd = nd->next;
+       }
+}
+
+#ifdef CONFIG_PPC64
+static void __init pmac_fixup_phb_resources(void)
+{
+       struct pci_controller *hose, *tmp;
+       
+       list_for_each_entry_safe(hose, tmp, &hose_list, list_node) {
+               unsigned long offset = (unsigned long)hose->io_base_virt - pci_io_base;
+               hose->io_resource.start += offset;
+               hose->io_resource.end += offset;
+               printk(KERN_INFO "PCI Host %d, io start: %lx; io end: %lx\n",
+                      hose->global_number,
+                      hose->io_resource.start, hose->io_resource.end);
+       }
+}
+
+void __init pmac_pci_init(void)
+{
+       struct device_node *np, *root;
+       struct device_node *ht = NULL;
+
+       /* Probe root PCI hosts, that is on U3 the AGP host and the
+        * HyperTransport host. That one is actually "kept" around
+        * and actually added last as it's resource management relies
+        * on the AGP resources to have been setup first
+        */
+       root = of_find_node_by_path("/");
+       if (root == NULL) {
+               printk(KERN_CRIT "pmac_find_bridges: can't find root of device tree\n");
+               return;
+       }
+       for (np = NULL; (np = of_get_next_child(root, np)) != NULL;) {
+               if (np->name == NULL)
+                       continue;
+               if (strcmp(np->name, "pci") == 0) {
+                       if (add_bridge(np) == 0)
+                               of_node_get(np);
+               }
+               if (strcmp(np->name, "ht") == 0) {
+                       of_node_get(np);
+                       ht = np;
+               }
+       }
+       of_node_put(root);
+
+       /* Now setup the HyperTransport host if we found any
+        */
+       if (ht && add_bridge(ht) != 0)
+               of_node_put(ht);
+
+       /* Fixup the IO resources on our host bridges as the common code
+        * does it only for childs of the host bridges
+        */
+       pmac_fixup_phb_resources();
+
+       /* Setup the linkage between OF nodes and PHBs */ 
+       pci_devs_phb_init();
+
+       /* Fixup the PCI<->OF mapping for U3 AGP due to bus renumbering. We
+        * assume there is no P2P bridge on the AGP bus, which should be a
+        * safe assumptions hopefully.
+        */
+       if (u3_agp) {
+               struct device_node *np = u3_agp->arch_data;
+               PCI_DN(np)->busno = 0xf0;
+               for (np = np->child; np; np = np->sibling)
+                       PCI_DN(np)->busno = 0xf0;
+       }
+
+       pmac_check_ht_link();
+
+       /* Tell pci.c to not use the common resource allocation mecanism */
+       pci_probe_only = 1;
+       
+       /* Allow all IO */
+       io_page_mask = -1;
+}
+#endif
+
+#ifdef CONFIG_PPC32
+void pmac_pci_fixup_cardbus(struct pci_dev* dev)
+{
+       if (_machine != _MACH_Pmac)
+               return;
+       /*
+        * Fix the interrupt routing on the various cardbus bridges
+        * used on powerbooks
+        */
+       if (dev->vendor != PCI_VENDOR_ID_TI)
+               return;
+       if (dev->device == PCI_DEVICE_ID_TI_1130 ||
+           dev->device == PCI_DEVICE_ID_TI_1131) {
+               u8 val;
+               /* Enable PCI interrupt */
+               if (pci_read_config_byte(dev, 0x91, &val) == 0)
+                       pci_write_config_byte(dev, 0x91, val | 0x30);
+               /* Disable ISA interrupt mode */
+               if (pci_read_config_byte(dev, 0x92, &val) == 0)
+                       pci_write_config_byte(dev, 0x92, val & ~0x06);
+       }
+       if (dev->device == PCI_DEVICE_ID_TI_1210 ||
+           dev->device == PCI_DEVICE_ID_TI_1211 ||
+           dev->device == PCI_DEVICE_ID_TI_1410 ||
+           dev->device == PCI_DEVICE_ID_TI_1510) {
+               u8 val;
+               /* 0x8c == TI122X_IRQMUX, 2 says to route the INTA
+                  signal out the MFUNC0 pin */
+               if (pci_read_config_byte(dev, 0x8c, &val) == 0)
+                       pci_write_config_byte(dev, 0x8c, (val & ~0x0f) | 2);
+               /* Disable ISA interrupt mode */
+               if (pci_read_config_byte(dev, 0x92, &val) == 0)
+                       pci_write_config_byte(dev, 0x92, val & ~0x06);
+       }
+}
+
+DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_TI, PCI_ANY_ID, pmac_pci_fixup_cardbus);
+
+void pmac_pci_fixup_pciata(struct pci_dev* dev)
+{
+       u8 progif = 0;
+
+       /*
+        * On PowerMacs, we try to switch any PCI ATA controller to
+       * fully native mode
+        */
+       if (_machine != _MACH_Pmac)
+               return;
+       /* Some controllers don't have the class IDE */
+       if (dev->vendor == PCI_VENDOR_ID_PROMISE)
+               switch(dev->device) {
+               case PCI_DEVICE_ID_PROMISE_20246:
+               case PCI_DEVICE_ID_PROMISE_20262:
+               case PCI_DEVICE_ID_PROMISE_20263:
+               case PCI_DEVICE_ID_PROMISE_20265:
+               case PCI_DEVICE_ID_PROMISE_20267:
+               case PCI_DEVICE_ID_PROMISE_20268:
+               case PCI_DEVICE_ID_PROMISE_20269:
+               case PCI_DEVICE_ID_PROMISE_20270:
+               case PCI_DEVICE_ID_PROMISE_20271:
+               case PCI_DEVICE_ID_PROMISE_20275:
+               case PCI_DEVICE_ID_PROMISE_20276:
+               case PCI_DEVICE_ID_PROMISE_20277:
+                       goto good;
+               }
+       /* Others, check PCI class */
+       if ((dev->class >> 8) != PCI_CLASS_STORAGE_IDE)
+               return;
+ good:
+       pci_read_config_byte(dev, PCI_CLASS_PROG, &progif);
+       if ((progif & 5) != 5) {
+               printk(KERN_INFO "Forcing PCI IDE into native mode: %s\n", pci_name(dev));
+               (void) pci_write_config_byte(dev, PCI_CLASS_PROG, progif|5);
+               if (pci_read_config_byte(dev, PCI_CLASS_PROG, &progif) ||
+                   (progif & 5) != 5)
+                       printk(KERN_ERR "Rewrite of PROGIF failed !\n");
+       }
+}
+DECLARE_PCI_FIXUP_FINAL(PCI_ANY_ID, PCI_ANY_ID, pmac_pci_fixup_pciata);
+#endif
+
+/*
+ * Disable second function on K2-SATA, it's broken
+ * and disable IO BARs on first one
+ */
+static void fixup_k2_sata(struct pci_dev* dev)
+{
+       int i;
+       u16 cmd;
+
+       if (PCI_FUNC(dev->devfn) > 0) {
+               pci_read_config_word(dev, PCI_COMMAND, &cmd);
+               cmd &= ~(PCI_COMMAND_IO | PCI_COMMAND_MEMORY);
+               pci_write_config_word(dev, PCI_COMMAND, cmd);
+               for (i = 0; i < 6; i++) {
+                       dev->resource[i].start = dev->resource[i].end = 0;
+                       dev->resource[i].flags = 0;
+                       pci_write_config_dword(dev, PCI_BASE_ADDRESS_0 + 4 * i, 0);
+               }
+       } else {
+               pci_read_config_word(dev, PCI_COMMAND, &cmd);
+               cmd &= ~PCI_COMMAND_IO;
+               pci_write_config_word(dev, PCI_COMMAND, cmd);
+               for (i = 0; i < 5; i++) {
+                       dev->resource[i].start = dev->resource[i].end = 0;
+                       dev->resource[i].flags = 0;
+                       pci_write_config_dword(dev, PCI_BASE_ADDRESS_0 + 4 * i, 0);
+               }
+       }
+}
+DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_SERVERWORKS, 0x0240, fixup_k2_sata);
+
diff --git a/arch/powerpc/platforms/powermac/pic.c b/arch/powerpc/platforms/powermac/pic.c
new file mode 100644 (file)
index 0000000..7ddd526
--- /dev/null
@@ -0,0 +1,673 @@
+/*
+ *  Support for the interrupt controllers found on Power Macintosh,
+ *  currently Apple's "Grand Central" interrupt controller in all
+ *  it's incarnations. OpenPIC support used on newer machines is
+ *  in a separate file
+ *
+ *  Copyright (C) 1997 Paul Mackerras (paulus@samba.org)
+ *
+ *  Maintained by Benjamin Herrenschmidt (benh@kernel.crashing.org)
+ *
+ *  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.
+ *
+ */
+
+#include <linux/config.h>
+#include <linux/stddef.h>
+#include <linux/init.h>
+#include <linux/sched.h>
+#include <linux/signal.h>
+#include <linux/pci.h>
+#include <linux/interrupt.h>
+#include <linux/sysdev.h>
+#include <linux/adb.h>
+#include <linux/pmu.h>
+
+#include <asm/sections.h>
+#include <asm/io.h>
+#include <asm/smp.h>
+#include <asm/prom.h>
+#include <asm/pci-bridge.h>
+#include <asm/time.h>
+#include <asm/open_pic.h>
+#include <asm/xmon.h>
+#include <asm/pmac_feature.h>
+#include <asm/mpic.h>
+
+#include "pmac_pic.h"
+
+/*
+ * XXX this should be in xmon.h, but putting it there means xmon.h
+ * has to include <linux/interrupt.h> (to get irqreturn_t), which
+ * causes all sorts of problems.  -- paulus
+ */
+extern irqreturn_t xmon_irq(int, void *, struct pt_regs *);
+
+struct pmac_irq_hw {
+        unsigned int    event;
+        unsigned int    enable;
+        unsigned int    ack;
+        unsigned int    level;
+};
+
+/* Default addresses */
+static volatile struct pmac_irq_hw *pmac_irq_hw[4] = {
+        (struct pmac_irq_hw *) 0xf3000020,
+        (struct pmac_irq_hw *) 0xf3000010,
+        (struct pmac_irq_hw *) 0xf4000020,
+        (struct pmac_irq_hw *) 0xf4000010,
+};
+
+#define GC_LEVEL_MASK          0x3ff00000
+#define OHARE_LEVEL_MASK       0x1ff00000
+#define HEATHROW_LEVEL_MASK    0x1ff00000
+
+static int max_irqs;
+static int max_real_irqs;
+static u32 level_mask[4];
+
+static DEFINE_SPINLOCK(pmac_pic_lock);
+
+
+#define GATWICK_IRQ_POOL_SIZE        10
+static struct interrupt_info gatwick_int_pool[GATWICK_IRQ_POOL_SIZE];
+
+/*
+ * Mark an irq as "lost".  This is only used on the pmac
+ * since it can lose interrupts (see pmac_set_irq_mask).
+ * -- Cort
+ */
+void
+__set_lost(unsigned long irq_nr, int nokick)
+{
+       if (!test_and_set_bit(irq_nr, ppc_lost_interrupts)) {
+               atomic_inc(&ppc_n_lost_interrupts);
+               if (!nokick)
+                       set_dec(1);
+       }
+}
+
+static void
+pmac_mask_and_ack_irq(unsigned int irq_nr)
+{
+        unsigned long bit = 1UL << (irq_nr & 0x1f);
+        int i = irq_nr >> 5;
+        unsigned long flags;
+
+        if ((unsigned)irq_nr >= max_irqs)
+                return;
+
+        clear_bit(irq_nr, ppc_cached_irq_mask);
+        if (test_and_clear_bit(irq_nr, ppc_lost_interrupts))
+                atomic_dec(&ppc_n_lost_interrupts);
+       spin_lock_irqsave(&pmac_pic_lock, flags);
+        out_le32(&pmac_irq_hw[i]->enable, ppc_cached_irq_mask[i]);
+        out_le32(&pmac_irq_hw[i]->ack, bit);
+        do {
+                /* make sure ack gets to controller before we enable
+                   interrupts */
+                mb();
+        } while((in_le32(&pmac_irq_hw[i]->enable) & bit)
+                != (ppc_cached_irq_mask[i] & bit));
+       spin_unlock_irqrestore(&pmac_pic_lock, flags);
+}
+
+static void pmac_set_irq_mask(unsigned int irq_nr, int nokicklost)
+{
+        unsigned long bit = 1UL << (irq_nr & 0x1f);
+        int i = irq_nr >> 5;
+        unsigned long flags;
+
+        if ((unsigned)irq_nr >= max_irqs)
+                return;
+
+       spin_lock_irqsave(&pmac_pic_lock, flags);
+        /* enable unmasked interrupts */
+        out_le32(&pmac_irq_hw[i]->enable, ppc_cached_irq_mask[i]);
+
+        do {
+                /* make sure mask gets to controller before we
+                   return to user */
+                mb();
+        } while((in_le32(&pmac_irq_hw[i]->enable) & bit)
+                != (ppc_cached_irq_mask[i] & bit));
+
+        /*
+         * Unfortunately, setting the bit in the enable register
+         * when the device interrupt is already on *doesn't* set
+         * the bit in the flag register or request another interrupt.
+         */
+        if (bit & ppc_cached_irq_mask[i] & in_le32(&pmac_irq_hw[i]->level))
+               __set_lost((ulong)irq_nr, nokicklost);
+       spin_unlock_irqrestore(&pmac_pic_lock, flags);
+}
+
+/* When an irq gets requested for the first client, if it's an
+ * edge interrupt, we clear any previous one on the controller
+ */
+static unsigned int pmac_startup_irq(unsigned int irq_nr)
+{
+        unsigned long bit = 1UL << (irq_nr & 0x1f);
+        int i = irq_nr >> 5;
+
+       if ((irq_desc[irq_nr].status & IRQ_LEVEL) == 0)
+               out_le32(&pmac_irq_hw[i]->ack, bit);
+        set_bit(irq_nr, ppc_cached_irq_mask);
+        pmac_set_irq_mask(irq_nr, 0);
+
+       return 0;
+}
+
+static void pmac_mask_irq(unsigned int irq_nr)
+{
+        clear_bit(irq_nr, ppc_cached_irq_mask);
+        pmac_set_irq_mask(irq_nr, 0);
+        mb();
+}
+
+static void pmac_unmask_irq(unsigned int irq_nr)
+{
+        set_bit(irq_nr, ppc_cached_irq_mask);
+        pmac_set_irq_mask(irq_nr, 0);
+}
+
+static void pmac_end_irq(unsigned int irq_nr)
+{
+       if (!(irq_desc[irq_nr].status & (IRQ_DISABLED|IRQ_INPROGRESS))
+           && irq_desc[irq_nr].action) {
+               set_bit(irq_nr, ppc_cached_irq_mask);
+               pmac_set_irq_mask(irq_nr, 1);
+       }
+}
+
+
+struct hw_interrupt_type pmac_pic = {
+       .typename       = " PMAC-PIC ",
+       .startup        = pmac_startup_irq,
+       .enable         = pmac_unmask_irq,
+       .disable        = pmac_mask_irq,
+       .ack            = pmac_mask_and_ack_irq,
+       .end            = pmac_end_irq,
+};
+
+struct hw_interrupt_type gatwick_pic = {
+       .typename       = " GATWICK  ",
+       .startup        = pmac_startup_irq,
+       .enable         = pmac_unmask_irq,
+       .disable        = pmac_mask_irq,
+       .ack            = pmac_mask_and_ack_irq,
+       .end            = pmac_end_irq,
+};
+
+static irqreturn_t gatwick_action(int cpl, void *dev_id, struct pt_regs *regs)
+{
+       int irq, bits;
+
+       for (irq = max_irqs; (irq -= 32) >= max_real_irqs; ) {
+               int i = irq >> 5;
+               bits = in_le32(&pmac_irq_hw[i]->event) | ppc_lost_interrupts[i];
+               /* We must read level interrupts from the level register */
+               bits |= (in_le32(&pmac_irq_hw[i]->level) & level_mask[i]);
+               bits &= ppc_cached_irq_mask[i];
+               if (bits == 0)
+                       continue;
+               irq += __ilog2(bits);
+               __do_IRQ(irq, regs);
+               return IRQ_HANDLED;
+       }
+       printk("gatwick irq not from gatwick pic\n");
+       return IRQ_NONE;
+}
+
+int
+pmac_get_irq(struct pt_regs *regs)
+{
+       int irq;
+       unsigned long bits = 0;
+
+#ifdef CONFIG_SMP
+       void psurge_smp_message_recv(struct pt_regs *);
+
+               /* IPI's are a hack on the powersurge -- Cort */
+               if ( smp_processor_id() != 0 ) {
+               psurge_smp_message_recv(regs);
+               return -2;      /* ignore, already handled */
+        }
+#endif /* CONFIG_SMP */
+       for (irq = max_real_irqs; (irq -= 32) >= 0; ) {
+               int i = irq >> 5;
+               bits = in_le32(&pmac_irq_hw[i]->event) | ppc_lost_interrupts[i];
+               /* We must read level interrupts from the level register */
+               bits |= (in_le32(&pmac_irq_hw[i]->level) & level_mask[i]);
+               bits &= ppc_cached_irq_mask[i];
+               if (bits == 0)
+                       continue;
+               irq += __ilog2(bits);
+               break;
+       }
+
+       return irq;
+}
+
+/* This routine will fix some missing interrupt values in the device tree
+ * on the gatwick mac-io controller used by some PowerBooks
+ */
+static void __init
+pmac_fix_gatwick_interrupts(struct device_node *gw, int irq_base)
+{
+       struct device_node *node;
+       int count;
+
+       memset(gatwick_int_pool, 0, sizeof(gatwick_int_pool));
+       node = gw->child;
+       count = 0;
+       while(node)
+       {
+               /* Fix SCC */
+               if (strcasecmp(node->name, "escc") == 0)
+                       if (node->child) {
+                               if (node->child->n_intrs < 3) {
+                                       node->child->intrs = &gatwick_int_pool[count];
+                                       count += 3;
+                               }
+                               node->child->n_intrs = 3;
+                               node->child->intrs[0].line = 15+irq_base;
+                               node->child->intrs[1].line =  4+irq_base;
+                               node->child->intrs[2].line =  5+irq_base;
+                               printk(KERN_INFO "irq: fixed SCC on second controller (%d,%d,%d)\n",
+                                       node->child->intrs[0].line,
+                                       node->child->intrs[1].line,
+                                       node->child->intrs[2].line);
+                       }
+               /* Fix media-bay & left SWIM */
+               if (strcasecmp(node->name, "media-bay") == 0) {
+                       struct device_node* ya_node;
+
+                       if (node->n_intrs == 0)
+                               node->intrs = &gatwick_int_pool[count++];
+                       node->n_intrs = 1;
+                       node->intrs[0].line = 29+irq_base;
+                       printk(KERN_INFO "irq: fixed media-bay on second controller (%d)\n",
+                                       node->intrs[0].line);
+
+                       ya_node = node->child;
+                       while(ya_node)
+                       {
+                               if (strcasecmp(ya_node->name, "floppy") == 0) {
+                                       if (ya_node->n_intrs < 2) {
+                                               ya_node->intrs = &gatwick_int_pool[count];
+                                               count += 2;
+                                       }
+                                       ya_node->n_intrs = 2;
+                                       ya_node->intrs[0].line = 19+irq_base;
+                                       ya_node->intrs[1].line =  1+irq_base;
+                                       printk(KERN_INFO "irq: fixed floppy on second controller (%d,%d)\n",
+                                               ya_node->intrs[0].line, ya_node->intrs[1].line);
+                               }
+                               if (strcasecmp(ya_node->name, "ata4") == 0) {
+                                       if (ya_node->n_intrs < 2) {
+                                               ya_node->intrs = &gatwick_int_pool[count];
+                                               count += 2;
+                                       }
+                                       ya_node->n_intrs = 2;
+                                       ya_node->intrs[0].line = 14+irq_base;
+                                       ya_node->intrs[1].line =  3+irq_base;
+                                       printk(KERN_INFO "irq: fixed ide on second controller (%d,%d)\n",
+                                               ya_node->intrs[0].line, ya_node->intrs[1].line);
+                               }
+                               ya_node = ya_node->sibling;
+                       }
+               }
+               node = node->sibling;
+       }
+       if (count > 10) {
+               printk("WARNING !! Gatwick interrupt pool overflow\n");
+               printk("  GATWICK_IRQ_POOL_SIZE = %d\n", GATWICK_IRQ_POOL_SIZE);
+               printk("              requested = %d\n", count);
+       }
+}
+
+/*
+ * The PowerBook 3400/2400/3500 can have a combo ethernet/modem
+ * card which includes an ohare chip that acts as a second interrupt
+ * controller.  If we find this second ohare, set it up and fix the
+ * interrupt value in the device tree for the ethernet chip.
+ */
+static int __init enable_second_ohare(void)
+{
+       unsigned char bus, devfn;
+       unsigned short cmd;
+        unsigned long addr;
+       struct device_node *irqctrler = find_devices("pci106b,7");
+       struct device_node *ether;
+
+       if (irqctrler == NULL || irqctrler->n_addrs <= 0)
+               return -1;
+       addr = (unsigned long) ioremap(irqctrler->addrs[0].address, 0x40);
+       pmac_irq_hw[1] = (volatile struct pmac_irq_hw *)(addr + 0x20);
+       max_irqs = 64;
+       if (pci_device_from_OF_node(irqctrler, &bus, &devfn) == 0) {
+               struct pci_controller* hose = pci_find_hose_for_OF_device(irqctrler);
+               if (!hose)
+                   printk(KERN_ERR "Can't find PCI hose for OHare2 !\n");
+               else {
+                   early_read_config_word(hose, bus, devfn, PCI_COMMAND, &cmd);
+                   cmd |= PCI_COMMAND_MEMORY | PCI_COMMAND_MASTER;
+                   cmd &= ~PCI_COMMAND_IO;
+                   early_write_config_word(hose, bus, devfn, PCI_COMMAND, cmd);
+               }
+       }
+
+       /* Fix interrupt for the modem/ethernet combo controller. The number
+          in the device tree (27) is bogus (correct for the ethernet-only
+          board but not the combo ethernet/modem board).
+          The real interrupt is 28 on the second controller -> 28+32 = 60.
+       */
+       ether = find_devices("pci1011,14");
+       if (ether && ether->n_intrs > 0) {
+               ether->intrs[0].line = 60;
+               printk(KERN_INFO "irq: Fixed ethernet IRQ to %d\n",
+                      ether->intrs[0].line);
+       }
+
+       /* Return the interrupt number of the cascade */
+       return irqctrler->intrs[0].line;
+}
+
+static int pmac_u3_cascade(struct pt_regs *regs, void *data)
+{
+       return mpic_get_one_irq((struct mpic *)data, regs);
+}
+
+#ifdef CONFIG_XMON
+static struct irqaction xmon_action = {
+       .handler        = xmon_irq,
+       .flags          = 0,
+       .mask           = CPU_MASK_NONE,
+       .name           = "NMI - XMON"
+};
+#endif
+
+static struct irqaction gatwick_cascade_action = {
+       .handler        = gatwick_action,
+       .flags          = SA_INTERRUPT,
+       .mask           = CPU_MASK_NONE,
+       .name           = "cascade",
+};
+
+void __init pmac_pic_init(void)
+{
+        int i;
+        struct device_node *irqctrler  = NULL;
+        struct device_node *irqctrler2 = NULL;
+       struct device_node *np;
+        unsigned long addr;
+       int irq_cascade = -1;
+       struct mpic *mpic1, *mpic2;
+
+       /* We first try to detect Apple's new Core99 chipset, since mac-io
+        * is quite different on those machines and contains an IBM MPIC2.
+        */
+       np = find_type_devices("open-pic");
+       while (np) {
+               if (np->parent && !strcmp(np->parent->name, "u3"))
+                       irqctrler2 = np;
+               else
+                       irqctrler = np;
+               np = np->next;
+       }
+       if (irqctrler != NULL && irqctrler->n_addrs > 0) {
+               unsigned char senses[128];
+
+               printk(KERN_INFO "PowerMac using OpenPIC irq controller at 0x%08x\n",
+                      (unsigned int)irqctrler->addrs[0].address);
+               ppc_md.get_irq = mpic_get_irq;
+               pmac_call_feature(PMAC_FTR_ENABLE_MPIC, irqctrler, 0, 0);
+
+               prom_get_irq_senses(senses, 0, 128);
+               mpic1 = mpic_alloc(irqctrler->addrs[0].address,
+                                  MPIC_PRIMARY | MPIC_WANTS_RESET,
+                                  0, 0, 128, 252, senses, 128, " OpenPIC  ");
+               BUG_ON(mpic1 == NULL);
+               mpic_init(mpic1);               
+
+               if (irqctrler2 != NULL && irqctrler2->n_intrs > 0 &&
+                   irqctrler2->n_addrs > 0) {
+                       printk(KERN_INFO "Slave OpenPIC at 0x%08x hooked on IRQ %d\n",
+                              (u32)irqctrler2->addrs[0].address,
+                              irqctrler2->intrs[0].line);
+
+                       pmac_call_feature(PMAC_FTR_ENABLE_MPIC, irqctrler2, 0, 0);
+                       prom_get_irq_senses(senses, 128, 128 + 124);
+
+                       /* We don't need to set MPIC_BROKEN_U3 here since we don't have
+                        * hypertransport interrupts routed to it
+                        */
+                       mpic2 = mpic_alloc(irqctrler2->addrs[0].address,
+                                          MPIC_BIG_ENDIAN | MPIC_WANTS_RESET,
+                                          0, 128, 124, 0, senses, 124,
+                                          " U3-MPIC  ");
+                       BUG_ON(mpic2 == NULL);
+                       mpic_init(mpic2);
+                       mpic_setup_cascade(irqctrler2->intrs[0].line,
+                                          pmac_u3_cascade, mpic2);
+               }
+#ifdef CONFIG_XMON
+               {
+                       struct device_node* pswitch;
+                       int nmi_irq;
+
+                       pswitch = find_devices("programmer-switch");
+                       if (pswitch && pswitch->n_intrs) {
+                               nmi_irq = pswitch->intrs[0].line;
+                               openpic_init_nmi_irq(nmi_irq);
+                               setup_irq(nmi_irq, &xmon_action);
+                       }
+               }
+#endif /* CONFIG_XMON */
+               return;
+       }
+       irqctrler = NULL;
+
+       /* Get the level/edge settings, assume if it's not
+        * a Grand Central nor an OHare, then it's an Heathrow
+        * (or Paddington).
+        */
+       if (find_devices("gc"))
+               level_mask[0] = GC_LEVEL_MASK;
+       else if (find_devices("ohare")) {
+               level_mask[0] = OHARE_LEVEL_MASK;
+               /* We might have a second cascaded ohare */
+               level_mask[1] = OHARE_LEVEL_MASK;
+       } else {
+               level_mask[0] = HEATHROW_LEVEL_MASK;
+               level_mask[1] = 0;
+               /* We might have a second cascaded heathrow */
+               level_mask[2] = HEATHROW_LEVEL_MASK;
+               level_mask[3] = 0;
+       }
+
+       /*
+        * G3 powermacs and 1999 G3 PowerBooks have 64 interrupts,
+        * 1998 G3 Series PowerBooks have 128,
+        * other powermacs have 32.
+        * The combo ethernet/modem card for the Powerstar powerbooks
+        * (2400/3400/3500, ohare based) has a second ohare chip
+        * effectively making a total of 64.
+        */
+       max_irqs = max_real_irqs = 32;
+       irqctrler = find_devices("mac-io");
+       if (irqctrler)
+       {
+               max_real_irqs = 64;
+               if (irqctrler->next)
+                       max_irqs = 128;
+               else
+                       max_irqs = 64;
+       }
+       for ( i = 0; i < max_real_irqs ; i++ )
+               irq_desc[i].handler = &pmac_pic;
+
+       /* get addresses of first controller */
+       if (irqctrler) {
+               if  (irqctrler->n_addrs > 0) {
+                       addr = (unsigned long)
+                               ioremap(irqctrler->addrs[0].address, 0x40);
+                       for (i = 0; i < 2; ++i)
+                               pmac_irq_hw[i] = (volatile struct pmac_irq_hw*)
+                                       (addr + (2 - i) * 0x10);
+               }
+
+               /* get addresses of second controller */
+               irqctrler = irqctrler->next;
+               if (irqctrler && irqctrler->n_addrs > 0) {
+                       addr = (unsigned long)
+                               ioremap(irqctrler->addrs[0].address, 0x40);
+                       for (i = 2; i < 4; ++i)
+                               pmac_irq_hw[i] = (volatile struct pmac_irq_hw*)
+                                       (addr + (4 - i) * 0x10);
+                       irq_cascade = irqctrler->intrs[0].line;
+                       if (device_is_compatible(irqctrler, "gatwick"))
+                               pmac_fix_gatwick_interrupts(irqctrler, max_real_irqs);
+               }
+       } else {
+               /* older powermacs have a GC (grand central) or ohare at
+                  f3000000, with interrupt control registers at f3000020. */
+               addr = (unsigned long) ioremap(0xf3000000, 0x40);
+               pmac_irq_hw[0] = (volatile struct pmac_irq_hw *) (addr + 0x20);
+       }
+
+       /* PowerBooks 3400 and 3500 can have a second controller in a second
+          ohare chip, on the combo ethernet/modem card */
+       if (machine_is_compatible("AAPL,3400/2400")
+            || machine_is_compatible("AAPL,3500"))
+               irq_cascade = enable_second_ohare();
+
+       /* disable all interrupts in all controllers */
+       for (i = 0; i * 32 < max_irqs; ++i)
+               out_le32(&pmac_irq_hw[i]->enable, 0);
+       /* mark level interrupts */
+       for (i = 0; i < max_irqs; i++)
+               if (level_mask[i >> 5] & (1UL << (i & 0x1f)))
+                       irq_desc[i].status = IRQ_LEVEL;
+
+       /* get interrupt line of secondary interrupt controller */
+       if (irq_cascade >= 0) {
+               printk(KERN_INFO "irq: secondary controller on irq %d\n",
+                       (int)irq_cascade);
+               for ( i = max_real_irqs ; i < max_irqs ; i++ )
+                       irq_desc[i].handler = &gatwick_pic;
+               setup_irq(irq_cascade, &gatwick_cascade_action);
+       }
+       printk("System has %d possible interrupts\n", max_irqs);
+       if (max_irqs != max_real_irqs)
+               printk(KERN_DEBUG "%d interrupts on main controller\n",
+                       max_real_irqs);
+
+#ifdef CONFIG_XMON
+       setup_irq(20, &xmon_action);
+#endif /* CONFIG_XMON */
+}
+
+#ifdef CONFIG_PM
+/*
+ * These procedures are used in implementing sleep on the powerbooks.
+ * sleep_save_intrs() saves the states of all interrupt enables
+ * and disables all interrupts except for the nominated one.
+ * sleep_restore_intrs() restores the states of all interrupt enables.
+ */
+unsigned long sleep_save_mask[2];
+
+/* This used to be passed by the PMU driver but that link got
+ * broken with the new driver model. We use this tweak for now...
+ */
+static int pmacpic_find_viaint(void)
+{
+       int viaint = -1;
+
+#ifdef CONFIG_ADB_PMU
+       struct device_node *np;
+
+       if (pmu_get_model() != PMU_OHARE_BASED)
+               goto not_found;
+       np = of_find_node_by_name(NULL, "via-pmu");
+       if (np == NULL)
+               goto not_found;
+       viaint = np->intrs[0].line;
+#endif /* CONFIG_ADB_PMU */
+
+not_found:
+       return viaint;
+}
+
+static int pmacpic_suspend(struct sys_device *sysdev, pm_message_t state)
+{
+       int viaint = pmacpic_find_viaint();
+
+       sleep_save_mask[0] = ppc_cached_irq_mask[0];
+       sleep_save_mask[1] = ppc_cached_irq_mask[1];
+       ppc_cached_irq_mask[0] = 0;
+       ppc_cached_irq_mask[1] = 0;
+       if (viaint > 0)
+               set_bit(viaint, ppc_cached_irq_mask);
+       out_le32(&pmac_irq_hw[0]->enable, ppc_cached_irq_mask[0]);
+       if (max_real_irqs > 32)
+               out_le32(&pmac_irq_hw[1]->enable, ppc_cached_irq_mask[1]);
+       (void)in_le32(&pmac_irq_hw[0]->event);
+       /* make sure mask gets to controller before we return to caller */
+       mb();
+        (void)in_le32(&pmac_irq_hw[0]->enable);
+
+        return 0;
+}
+
+static int pmacpic_resume(struct sys_device *sysdev)
+{
+       int i;
+
+       out_le32(&pmac_irq_hw[0]->enable, 0);
+       if (max_real_irqs > 32)
+               out_le32(&pmac_irq_hw[1]->enable, 0);
+       mb();
+       for (i = 0; i < max_real_irqs; ++i)
+               if (test_bit(i, sleep_save_mask))
+                       pmac_unmask_irq(i);
+
+       return 0;
+}
+
+#endif /* CONFIG_PM */
+
+static struct sysdev_class pmacpic_sysclass = {
+       set_kset_name("pmac_pic"),
+};
+
+static struct sys_device device_pmacpic = {
+       .id             = 0,
+       .cls            = &pmacpic_sysclass,
+};
+
+static struct sysdev_driver driver_pmacpic = {
+#ifdef CONFIG_PM
+       .suspend        = &pmacpic_suspend,
+       .resume         = &pmacpic_resume,
+#endif /* CONFIG_PM */
+};
+
+static int __init init_pmacpic_sysfs(void)
+{
+       if (max_irqs == 0)
+               return -ENODEV;
+
+       printk(KERN_DEBUG "Registering pmac pic with sysfs...\n");
+       sysdev_class_register(&pmacpic_sysclass);
+       sysdev_register(&device_pmacpic);
+       sysdev_driver_register(&pmacpic_sysclass, &driver_pmacpic);
+       return 0;
+}
+
+subsys_initcall(init_pmacpic_sysfs);
+
diff --git a/arch/powerpc/platforms/powermac/pic.h b/arch/powerpc/platforms/powermac/pic.h
new file mode 100644 (file)
index 0000000..664103d
--- /dev/null
@@ -0,0 +1,11 @@
+#ifndef __PPC_PLATFORMS_PMAC_PIC_H
+#define __PPC_PLATFORMS_PMAC_PIC_H
+
+#include <linux/irq.h>
+
+extern struct hw_interrupt_type pmac_pic;
+
+void pmac_pic_init(void);
+int pmac_get_irq(struct pt_regs *regs);
+
+#endif /* __PPC_PLATFORMS_PMAC_PIC_H */
diff --git a/arch/powerpc/platforms/powermac/pmac_backlight.c b/arch/powerpc/platforms/powermac/pmac_backlight.c
deleted file mode 100644 (file)
index 8be2f7d..0000000
+++ /dev/null
@@ -1,202 +0,0 @@
-/*
- * Miscellaneous procedures for dealing with the PowerMac hardware.
- * Contains support for the backlight.
- *
- *   Copyright (C) 2000 Benjamin Herrenschmidt
- *
- */
-
-#include <linux/config.h>
-#include <linux/kernel.h>
-#include <linux/module.h>
-#include <linux/stddef.h>
-#include <linux/reboot.h>
-#include <linux/nvram.h>
-#include <linux/console.h>
-#include <asm/sections.h>
-#include <asm/ptrace.h>
-#include <asm/io.h>
-#include <asm/pgtable.h>
-#include <asm/system.h>
-#include <asm/prom.h>
-#include <asm/machdep.h>
-#include <asm/nvram.h>
-#include <asm/backlight.h>
-
-#include <linux/adb.h>
-#include <linux/pmu.h>
-
-static struct backlight_controller *backlighter;
-static void* backlighter_data;
-static int backlight_autosave;
-static int backlight_level = BACKLIGHT_MAX;
-static int backlight_enabled = 1;
-static int backlight_req_level = -1;
-static int backlight_req_enable = -1;
-
-static void backlight_callback(void *);
-static DECLARE_WORK(backlight_work, backlight_callback, NULL);
-
-void register_backlight_controller(struct backlight_controller *ctrler,
-                                         void *data, char *type)
-{
-       struct device_node* bk_node;
-       char *prop;
-       int valid = 0;
-
-       /* There's already a matching controller, bail out */
-       if (backlighter != NULL)
-               return;
-
-       bk_node = find_devices("backlight");
-
-#ifdef CONFIG_ADB_PMU
-       /* Special case for the old PowerBook since I can't test on it */
-       backlight_autosave = machine_is_compatible("AAPL,3400/2400")
-               || machine_is_compatible("AAPL,3500");
-       if ((backlight_autosave
-            || machine_is_compatible("AAPL,PowerBook1998")
-            || machine_is_compatible("PowerBook1,1"))
-           && !strcmp(type, "pmu"))
-               valid = 1;
-#endif
-       if (bk_node) {
-               prop = get_property(bk_node, "backlight-control", NULL);
-               if (prop && !strncmp(prop, type, strlen(type)))
-                       valid = 1;
-       }
-       if (!valid)
-               return;
-       backlighter = ctrler;
-       backlighter_data = data;
-
-       if (bk_node && !backlight_autosave)
-               prop = get_property(bk_node, "bklt", NULL);
-       else
-               prop = NULL;
-       if (prop) {
-               backlight_level = ((*prop)+1) >> 1;
-               if (backlight_level > BACKLIGHT_MAX)
-                       backlight_level = BACKLIGHT_MAX;
-       }
-
-#ifdef CONFIG_ADB_PMU
-       if (backlight_autosave) {
-               struct adb_request req;
-               pmu_request(&req, NULL, 2, 0xd9, 0);
-               while (!req.complete)
-                       pmu_poll();
-               backlight_level = req.reply[0] >> 4;
-       }
-#endif
-       acquire_console_sem();
-       if (!backlighter->set_enable(1, backlight_level, data))
-               backlight_enabled = 1;
-       release_console_sem();
-
-       printk(KERN_INFO "Registered \"%s\" backlight controller,"
-              "level: %d/15\n", type, backlight_level);
-}
-EXPORT_SYMBOL(register_backlight_controller);
-
-void unregister_backlight_controller(struct backlight_controller
-                                           *ctrler, void *data)
-{
-       /* We keep the current backlight level (for now) */
-       if (ctrler == backlighter && data == backlighter_data)
-               backlighter = NULL;
-}
-EXPORT_SYMBOL(unregister_backlight_controller);
-
-static int __set_backlight_enable(int enable)
-{
-       int rc;
-
-       if (!backlighter)
-               return -ENODEV;
-       acquire_console_sem();
-       rc = backlighter->set_enable(enable, backlight_level,
-                                    backlighter_data);
-       if (!rc)
-               backlight_enabled = enable;
-       release_console_sem();
-       return rc;
-}
-int set_backlight_enable(int enable)
-{
-       if (!backlighter)
-               return -ENODEV;
-       backlight_req_enable = enable;
-       schedule_work(&backlight_work);
-       return 0;
-}
-
-EXPORT_SYMBOL(set_backlight_enable);
-
-int get_backlight_enable(void)
-{
-       if (!backlighter)
-               return -ENODEV;
-       return backlight_enabled;
-}
-EXPORT_SYMBOL(get_backlight_enable);
-
-static int __set_backlight_level(int level)
-{
-       int rc = 0;
-
-       if (!backlighter)
-               return -ENODEV;
-       if (level < BACKLIGHT_MIN)
-               level = BACKLIGHT_OFF;
-       if (level > BACKLIGHT_MAX)
-               level = BACKLIGHT_MAX;
-       acquire_console_sem();
-       if (backlight_enabled)
-               rc = backlighter->set_level(level, backlighter_data);
-       if (!rc)
-               backlight_level = level;
-       release_console_sem();
-       if (!rc && !backlight_autosave) {
-               level <<=1;
-               if (level & 0x10)
-                       level |= 0x01;
-               // -- todo: save to property "bklt"
-       }
-       return rc;
-}
-int set_backlight_level(int level)
-{
-       if (!backlighter)
-               return -ENODEV;
-       backlight_req_level = level;
-       schedule_work(&backlight_work);
-       return 0;
-}
-
-EXPORT_SYMBOL(set_backlight_level);
-
-int get_backlight_level(void)
-{
-       if (!backlighter)
-               return -ENODEV;
-       return backlight_level;
-}
-EXPORT_SYMBOL(get_backlight_level);
-
-static void backlight_callback(void *dummy)
-{
-       int level, enable;
-
-       do {
-               level = backlight_req_level;
-               enable = backlight_req_enable;
-               mb();
-
-               if (level >= 0)
-                       __set_backlight_level(level);
-               if (enable >= 0)
-                       __set_backlight_enable(enable);
-       } while(cmpxchg(&backlight_req_level, level, -1) != level ||
-               cmpxchg(&backlight_req_enable, enable, -1) != enable);
-}
diff --git a/arch/powerpc/platforms/powermac/pmac_cache.S b/arch/powerpc/platforms/powermac/pmac_cache.S
deleted file mode 100644 (file)
index fb977de..0000000
+++ /dev/null
@@ -1,359 +0,0 @@
-/*
- * This file contains low-level cache management functions
- * used for sleep and CPU speed changes on Apple machines.
- * (In fact the only thing that is Apple-specific is that we assume
- * that we can read from ROM at physical address 0xfff00000.)
- *
- *    Copyright (C) 2004 Paul Mackerras (paulus@samba.org) and
- *                       Benjamin Herrenschmidt (benh@kernel.crashing.org)
- *
- * 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.
- *
- */
-
-#include <linux/config.h>
-#include <asm/processor.h>
-#include <asm/ppc_asm.h>
-#include <asm/cputable.h>
-
-/*
- * Flush and disable all data caches (dL1, L2, L3). This is used
- * when going to sleep, when doing a PMU based cpufreq transition,
- * or when "offlining" a CPU on SMP machines. This code is over
- * paranoid, but I've had enough issues with various CPU revs and
- * bugs that I decided it was worth beeing over cautious
- */
-
-_GLOBAL(flush_disable_caches)
-#ifndef CONFIG_6xx
-       blr
-#else
-BEGIN_FTR_SECTION
-       b       flush_disable_745x
-END_FTR_SECTION_IFSET(CPU_FTR_SPEC7450)
-BEGIN_FTR_SECTION
-       b       flush_disable_75x
-END_FTR_SECTION_IFSET(CPU_FTR_L2CR)
-       b       __flush_disable_L1
-
-/* This is the code for G3 and 74[01]0 */
-flush_disable_75x:
-       mflr    r10
-
-       /* Turn off EE and DR in MSR */
-       mfmsr   r11
-       rlwinm  r0,r11,0,~MSR_EE
-       rlwinm  r0,r0,0,~MSR_DR
-       sync
-       mtmsr   r0
-       isync
-
-       /* Stop DST streams */
-BEGIN_FTR_SECTION
-       DSSALL
-       sync
-END_FTR_SECTION_IFSET(CPU_FTR_ALTIVEC)
-
-       /* Stop DPM */
-       mfspr   r8,SPRN_HID0            /* Save SPRN_HID0 in r8 */
-       rlwinm  r4,r8,0,12,10           /* Turn off HID0[DPM] */
-       sync
-       mtspr   SPRN_HID0,r4            /* Disable DPM */
-       sync
-
-       /* Disp-flush L1. We have a weird problem here that I never
-        * totally figured out. On 750FX, using the ROM for the flush
-        * results in a non-working flush. We use that workaround for
-        * now until I finally understand what's going on. --BenH
-        */
-
-       /* ROM base by default */
-       lis     r4,0xfff0
-       mfpvr   r3
-       srwi    r3,r3,16
-       cmplwi  cr0,r3,0x7000
-       bne+    1f
-       /* RAM base on 750FX */
-       li      r4,0
-1:     li      r4,0x4000
-       mtctr   r4
-1:     lwz     r0,0(r4)
-       addi    r4,r4,32
-       bdnz    1b
-       sync
-       isync
-
-       /* Disable / invalidate / enable L1 data */
-       mfspr   r3,SPRN_HID0
-       rlwinm  r3,r3,0,~(HID0_DCE | HID0_ICE)
-       mtspr   SPRN_HID0,r3
-       sync
-       isync
-       ori     r3,r3,(HID0_DCE|HID0_DCI|HID0_ICE|HID0_ICFI)
-       sync
-       isync
-       mtspr   SPRN_HID0,r3
-       xori    r3,r3,(HID0_DCI|HID0_ICFI)
-       mtspr   SPRN_HID0,r3
-       sync
-
-       /* Get the current enable bit of the L2CR into r4 */
-       mfspr   r5,SPRN_L2CR
-       /* Set to data-only (pre-745x bit) */
-       oris    r3,r5,L2CR_L2DO@h
-       b       2f
-       /* When disabling L2, code must be in L1 */
-       .balign 32
-1:     mtspr   SPRN_L2CR,r3
-3:     sync
-       isync
-       b       1f
-2:     b       3f
-3:     sync
-       isync
-       b       1b
-1:     /* disp-flush L2. The interesting thing here is that the L2 can be
-        * up to 2Mb ... so using the ROM, we'll end up wrapping back to memory
-        * but that is probbaly fine. We disp-flush over 4Mb to be safe
-        */
-       lis     r4,2
-       mtctr   r4
-       lis     r4,0xfff0
-1:     lwz     r0,0(r4)
-       addi    r4,r4,32
-       bdnz    1b
-       sync
-       isync
-       lis     r4,2
-       mtctr   r4
-       lis     r4,0xfff0
-1:     dcbf    0,r4
-       addi    r4,r4,32
-       bdnz    1b
-       sync
-       isync
-
-       /* now disable L2 */
-       rlwinm  r5,r5,0,~L2CR_L2E
-       b       2f
-       /* When disabling L2, code must be in L1 */
-       .balign 32
-1:     mtspr   SPRN_L2CR,r5
-3:     sync
-       isync
-       b       1f
-2:     b       3f
-3:     sync
-       isync
-       b       1b
-1:     sync
-       isync
-       /* Invalidate L2. This is pre-745x, we clear the L2I bit ourselves */
-       oris    r4,r5,L2CR_L2I@h
-       mtspr   SPRN_L2CR,r4
-       sync
-       isync
-
-       /* Wait for the invalidation to complete */
-1:     mfspr   r3,SPRN_L2CR
-       rlwinm. r0,r3,0,31,31
-       bne     1b
-
-       /* Clear L2I */
-       xoris   r4,r4,L2CR_L2I@h
-       sync
-       mtspr   SPRN_L2CR,r4
-       sync
-
-       /* now disable the L1 data cache */
-       mfspr   r0,SPRN_HID0
-       rlwinm  r0,r0,0,~(HID0_DCE|HID0_ICE)
-       mtspr   SPRN_HID0,r0
-       sync
-       isync
-
-       /* Restore HID0[DPM] to whatever it was before */
-       sync
-       mfspr   r0,SPRN_HID0
-       rlwimi  r0,r8,0,11,11           /* Turn back HID0[DPM] */
-       mtspr   SPRN_HID0,r0
-       sync
-
-       /* restore DR and EE */
-       sync
-       mtmsr   r11
-       isync
-
-       mtlr    r10
-       blr
-
-/* This code is for 745x processors */
-flush_disable_745x:
-       /* Turn off EE and DR in MSR */
-       mfmsr   r11
-       rlwinm  r0,r11,0,~MSR_EE
-       rlwinm  r0,r0,0,~MSR_DR
-       sync
-       mtmsr   r0
-       isync
-
-       /* Stop prefetch streams */
-       DSSALL
-       sync
-
-       /* Disable L2 prefetching */
-       mfspr   r0,SPRN_MSSCR0
-       rlwinm  r0,r0,0,0,29
-       mtspr   SPRN_MSSCR0,r0
-       sync
-       isync
-       lis     r4,0
-       dcbf    0,r4
-       dcbf    0,r4
-       dcbf    0,r4
-       dcbf    0,r4
-       dcbf    0,r4
-       dcbf    0,r4
-       dcbf    0,r4
-       dcbf    0,r4
-
-       /* Due to a bug with the HW flush on some CPU revs, we occasionally
-        * experience data corruption. I'm adding a displacement flush along
-        * with a dcbf loop over a few Mb to "help". The problem isn't totally
-        * fixed by this in theory, but at least, in practice, I couldn't reproduce
-        * it even with a big hammer...
-        */
-
-        lis     r4,0x0002
-        mtctr   r4
-       li      r4,0
-1:
-        lwz     r0,0(r4)
-        addi    r4,r4,32                /* Go to start of next cache line */
-        bdnz    1b
-        isync
-
-        /* Now, flush the first 4MB of memory */
-        lis     r4,0x0002
-        mtctr   r4
-       li      r4,0
-        sync
-1:
-        dcbf    0,r4
-        addi    r4,r4,32                /* Go to start of next cache line */
-        bdnz    1b
-
-       /* Flush and disable the L1 data cache */
-       mfspr   r6,SPRN_LDSTCR
-       lis     r3,0xfff0       /* read from ROM for displacement flush */
-       li      r4,0xfe         /* start with only way 0 unlocked */
-       li      r5,128          /* 128 lines in each way */
-1:     mtctr   r5
-       rlwimi  r6,r4,0,24,31
-       mtspr   SPRN_LDSTCR,r6
-       sync
-       isync
-2:     lwz     r0,0(r3)        /* touch each cache line */
-       addi    r3,r3,32
-       bdnz    2b
-       rlwinm  r4,r4,1,24,30   /* move on to the next way */
-       ori     r4,r4,1
-       cmpwi   r4,0xff         /* all done? */
-       bne     1b
-       /* now unlock the L1 data cache */
-       li      r4,0
-       rlwimi  r6,r4,0,24,31
-       sync
-       mtspr   SPRN_LDSTCR,r6
-       sync
-       isync
-
-       /* Flush the L2 cache using the hardware assist */
-       mfspr   r3,SPRN_L2CR
-       cmpwi   r3,0            /* check if it is enabled first */
-       bge     4f
-       oris    r0,r3,(L2CR_L2IO_745x|L2CR_L2DO_745x)@h
-       b       2f
-       /* When disabling/locking L2, code must be in L1 */
-       .balign 32
-1:     mtspr   SPRN_L2CR,r0    /* lock the L2 cache */
-3:     sync
-       isync
-       b       1f
-2:     b       3f
-3:     sync
-       isync
-       b       1b
-1:     sync
-       isync
-       ori     r0,r3,L2CR_L2HWF_745x
-       sync
-       mtspr   SPRN_L2CR,r0    /* set the hardware flush bit */
-3:     mfspr   r0,SPRN_L2CR    /* wait for it to go to 0 */
-       andi.   r0,r0,L2CR_L2HWF_745x
-       bne     3b
-       sync
-       rlwinm  r3,r3,0,~L2CR_L2E
-       b       2f
-       /* When disabling L2, code must be in L1 */
-       .balign 32
-1:     mtspr   SPRN_L2CR,r3    /* disable the L2 cache */
-3:     sync
-       isync
-       b       1f
-2:     b       3f
-3:     sync
-       isync
-       b       1b
-1:     sync
-       isync
-       oris    r4,r3,L2CR_L2I@h
-       mtspr   SPRN_L2CR,r4
-       sync
-       isync
-1:     mfspr   r4,SPRN_L2CR
-       andis.  r0,r4,L2CR_L2I@h
-       bne     1b
-       sync
-
-BEGIN_FTR_SECTION
-       /* Flush the L3 cache using the hardware assist */
-4:     mfspr   r3,SPRN_L3CR
-       cmpwi   r3,0            /* check if it is enabled */
-       bge     6f
-       oris    r0,r3,L3CR_L3IO@h
-       ori     r0,r0,L3CR_L3DO
-       sync
-       mtspr   SPRN_L3CR,r0    /* lock the L3 cache */
-       sync
-       isync
-       ori     r0,r0,L3CR_L3HWF
-       sync
-       mtspr   SPRN_L3CR,r0    /* set the hardware flush bit */
-5:     mfspr   r0,SPRN_L3CR    /* wait for it to go to zero */
-       andi.   r0,r0,L3CR_L3HWF
-       bne     5b
-       rlwinm  r3,r3,0,~L3CR_L3E
-       sync
-       mtspr   SPRN_L3CR,r3    /* disable the L3 cache */
-       sync
-       ori     r4,r3,L3CR_L3I
-       mtspr   SPRN_L3CR,r4
-1:     mfspr   r4,SPRN_L3CR
-       andi.   r0,r4,L3CR_L3I
-       bne     1b
-       sync
-END_FTR_SECTION_IFSET(CPU_FTR_L3CR)
-
-6:     mfspr   r0,SPRN_HID0    /* now disable the L1 data cache */
-       rlwinm  r0,r0,0,~HID0_DCE
-       mtspr   SPRN_HID0,r0
-       sync
-       isync
-       mtmsr   r11             /* restore DR and EE */
-       isync
-       blr
-#endif /* CONFIG_6xx */
diff --git a/arch/powerpc/platforms/powermac/pmac_cpufreq.c b/arch/powerpc/platforms/powermac/pmac_cpufreq.c
deleted file mode 100644 (file)
index 6d32d99..0000000
+++ /dev/null
@@ -1,728 +0,0 @@
-/*
- *  arch/ppc/platforms/pmac_cpufreq.c
- *
- *  Copyright (C) 2002 - 2005 Benjamin Herrenschmidt <benh@kernel.crashing.org>
- *  Copyright (C) 2004        John Steele Scott <toojays@toojays.net>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
- *
- * TODO: Need a big cleanup here. Basically, we need to have different
- * cpufreq_driver structures for the different type of HW instead of the
- * current mess. We also need to better deal with the detection of the
- * type of machine.
- *
- */
-
-#include <linux/config.h>
-#include <linux/module.h>
-#include <linux/types.h>
-#include <linux/errno.h>
-#include <linux/kernel.h>
-#include <linux/delay.h>
-#include <linux/sched.h>
-#include <linux/adb.h>
-#include <linux/pmu.h>
-#include <linux/slab.h>
-#include <linux/cpufreq.h>
-#include <linux/init.h>
-#include <linux/sysdev.h>
-#include <linux/i2c.h>
-#include <linux/hardirq.h>
-#include <asm/prom.h>
-#include <asm/machdep.h>
-#include <asm/irq.h>
-#include <asm/pmac_feature.h>
-#include <asm/mmu_context.h>
-#include <asm/sections.h>
-#include <asm/cputable.h>
-#include <asm/time.h>
-#include <asm/system.h>
-#include <asm/mpic.h>
-#include <asm/keylargo.h>
-
-/* WARNING !!! This will cause calibrate_delay() to be called,
- * but this is an __init function ! So you MUST go edit
- * init/main.c to make it non-init before enabling DEBUG_FREQ
- */
-#undef DEBUG_FREQ
-
-/*
- * There is a problem with the core cpufreq code on SMP kernels,
- * it won't recalculate the Bogomips properly
- */
-#ifdef CONFIG_SMP
-#warning "WARNING, CPUFREQ not recommended on SMP kernels"
-#endif
-
-extern void low_choose_7447a_dfs(int dfs);
-extern void low_choose_750fx_pll(int pll);
-extern void low_sleep_handler(void);
-
-/*
- * Currently, PowerMac cpufreq supports only high & low frequencies
- * that are set by the firmware
- */
-static unsigned int low_freq;
-static unsigned int hi_freq;
-static unsigned int cur_freq;
-static unsigned int sleep_freq;
-
-/*
- * Different models uses different mecanisms to switch the frequency
- */
-static int (*set_speed_proc)(int low_speed);
-static unsigned int (*get_speed_proc)(void);
-
-/*
- * Some definitions used by the various speedprocs
- */
-static u32 voltage_gpio;
-static u32 frequency_gpio;
-static u32 slew_done_gpio;
-static int no_schedule;
-static int has_cpu_l2lve;
-static int is_pmu_based;
-
-/* There are only two frequency states for each processor. Values
- * are in kHz for the time being.
- */
-#define CPUFREQ_HIGH                  0
-#define CPUFREQ_LOW                   1
-
-static struct cpufreq_frequency_table pmac_cpu_freqs[] = {
-       {CPUFREQ_HIGH,          0},
-       {CPUFREQ_LOW,           0},
-       {0,                     CPUFREQ_TABLE_END},
-};
-
-static struct freq_attr* pmac_cpu_freqs_attr[] = {
-       &cpufreq_freq_attr_scaling_available_freqs,
-       NULL,
-};
-
-static inline void local_delay(unsigned long ms)
-{
-       if (no_schedule)
-               mdelay(ms);
-       else
-               msleep(ms);
-}
-
-static inline void wakeup_decrementer(void)
-{
-       set_dec(tb_ticks_per_jiffy);
-       /* No currently-supported powerbook has a 601,
-        * so use get_tbl, not native
-        */
-       last_jiffy_stamp(0) = tb_last_stamp = get_tbl();
-}
-
-#ifdef DEBUG_FREQ
-static inline void debug_calc_bogomips(void)
-{
-       /* This will cause a recalc of bogomips and display the
-        * result. We backup/restore the value to avoid affecting the
-        * core cpufreq framework's own calculation.
-        */
-       extern void calibrate_delay(void);
-
-       unsigned long save_lpj = loops_per_jiffy;
-       calibrate_delay();
-       loops_per_jiffy = save_lpj;
-}
-#endif /* DEBUG_FREQ */
-
-/* Switch CPU speed under 750FX CPU control
- */
-static int cpu_750fx_cpu_speed(int low_speed)
-{
-       u32 hid2;
-
-       if (low_speed == 0) {
-               /* ramping up, set voltage first */
-               pmac_call_feature(PMAC_FTR_WRITE_GPIO, NULL, voltage_gpio, 0x05);
-               /* Make sure we sleep for at least 1ms */
-               local_delay(10);
-
-               /* tweak L2 for high voltage */
-               if (has_cpu_l2lve) {
-                       hid2 = mfspr(SPRN_HID2);
-                       hid2 &= ~0x2000;
-                       mtspr(SPRN_HID2, hid2);
-               }
-       }
-#ifdef CONFIG_6xx
-       low_choose_750fx_pll(low_speed);
-#endif
-       if (low_speed == 1) {
-               /* tweak L2 for low voltage */
-               if (has_cpu_l2lve) {
-                       hid2 = mfspr(SPRN_HID2);
-                       hid2 |= 0x2000;
-                       mtspr(SPRN_HID2, hid2);
-               }
-
-               /* ramping down, set voltage last */
-               pmac_call_feature(PMAC_FTR_WRITE_GPIO, NULL, voltage_gpio, 0x04);
-               local_delay(10);
-       }
-
-       return 0;
-}
-
-static unsigned int cpu_750fx_get_cpu_speed(void)
-{
-       if (mfspr(SPRN_HID1) & HID1_PS)
-               return low_freq;
-       else
-               return hi_freq;
-}
-
-/* Switch CPU speed using DFS */
-static int dfs_set_cpu_speed(int low_speed)
-{
-       if (low_speed == 0) {
-               /* ramping up, set voltage first */
-               pmac_call_feature(PMAC_FTR_WRITE_GPIO, NULL, voltage_gpio, 0x05);
-               /* Make sure we sleep for at least 1ms */
-               local_delay(1);
-       }
-
-       /* set frequency */
-#ifdef CONFIG_6xx
-       low_choose_7447a_dfs(low_speed);
-#endif
-       udelay(100);
-
-       if (low_speed == 1) {
-               /* ramping down, set voltage last */
-               pmac_call_feature(PMAC_FTR_WRITE_GPIO, NULL, voltage_gpio, 0x04);
-               local_delay(1);
-       }
-
-       return 0;
-}
-
-static unsigned int dfs_get_cpu_speed(void)
-{
-       if (mfspr(SPRN_HID1) & HID1_DFS)
-               return low_freq;
-       else
-               return hi_freq;
-}
-
-
-/* Switch CPU speed using slewing GPIOs
- */
-static int gpios_set_cpu_speed(int low_speed)
-{
-       int gpio, timeout = 0;
-
-       /* If ramping up, set voltage first */
-       if (low_speed == 0) {
-               pmac_call_feature(PMAC_FTR_WRITE_GPIO, NULL, voltage_gpio, 0x05);
-               /* Delay is way too big but it's ok, we schedule */
-               local_delay(10);
-       }
-
-       /* Set frequency */
-       gpio =  pmac_call_feature(PMAC_FTR_READ_GPIO, NULL, frequency_gpio, 0);
-       if (low_speed == ((gpio & 0x01) == 0))
-               goto skip;
-
-       pmac_call_feature(PMAC_FTR_WRITE_GPIO, NULL, frequency_gpio,
-                         low_speed ? 0x04 : 0x05);
-       udelay(200);
-       do {
-               if (++timeout > 100)
-                       break;
-               local_delay(1);
-               gpio = pmac_call_feature(PMAC_FTR_READ_GPIO, NULL, slew_done_gpio, 0);
-       } while((gpio & 0x02) == 0);
- skip:
-       /* If ramping down, set voltage last */
-       if (low_speed == 1) {
-               pmac_call_feature(PMAC_FTR_WRITE_GPIO, NULL, voltage_gpio, 0x04);
-               /* Delay is way too big but it's ok, we schedule */
-               local_delay(10);
-       }
-
-#ifdef DEBUG_FREQ
-       debug_calc_bogomips();
-#endif
-
-       return 0;
-}
-
-/* Switch CPU speed under PMU control
- */
-static int pmu_set_cpu_speed(int low_speed)
-{
-       struct adb_request req;
-       unsigned long save_l2cr;
-       unsigned long save_l3cr;
-       unsigned int pic_prio;
-       unsigned long flags;
-
-       preempt_disable();
-
-#ifdef DEBUG_FREQ
-       printk(KERN_DEBUG "HID1, before: %x\n", mfspr(SPRN_HID1));
-#endif
-       pmu_suspend();
-
-       /* Disable all interrupt sources on openpic */
-       pic_prio = mpic_cpu_get_priority();
-       mpic_cpu_set_priority(0xf);
-
-       /* Make sure the decrementer won't interrupt us */
-       asm volatile("mtdec %0" : : "r" (0x7fffffff));
-       /* Make sure any pending DEC interrupt occuring while we did
-        * the above didn't re-enable the DEC */
-       mb();
-       asm volatile("mtdec %0" : : "r" (0x7fffffff));
-
-       /* We can now disable MSR_EE */
-       local_irq_save(flags);
-
-       /* Giveup the FPU & vec */
-       enable_kernel_fp();
-
-#ifdef CONFIG_ALTIVEC
-       if (cpu_has_feature(CPU_FTR_ALTIVEC))
-               enable_kernel_altivec();
-#endif /* CONFIG_ALTIVEC */
-
-       /* Save & disable L2 and L3 caches */
-       save_l3cr = _get_L3CR();        /* (returns -1 if not available) */
-       save_l2cr = _get_L2CR();        /* (returns -1 if not available) */
-
-       /* Send the new speed command. My assumption is that this command
-        * will cause PLL_CFG[0..3] to be changed next time CPU goes to sleep
-        */
-       pmu_request(&req, NULL, 6, PMU_CPU_SPEED, 'W', 'O', 'O', 'F', low_speed);
-       while (!req.complete)
-               pmu_poll();
-
-       /* Prepare the northbridge for the speed transition */
-       pmac_call_feature(PMAC_FTR_SLEEP_STATE,NULL,1,1);
-
-       /* Call low level code to backup CPU state and recover from
-        * hardware reset
-        */
-       low_sleep_handler();
-
-       /* Restore the northbridge */
-       pmac_call_feature(PMAC_FTR_SLEEP_STATE,NULL,1,0);
-
-       /* Restore L2 cache */
-       if (save_l2cr != 0xffffffff && (save_l2cr & L2CR_L2E) != 0)
-               _set_L2CR(save_l2cr);
-       /* Restore L3 cache */
-       if (save_l3cr != 0xffffffff && (save_l3cr & L3CR_L3E) != 0)
-               _set_L3CR(save_l3cr);
-
-       /* Restore userland MMU context */
-       set_context(current->active_mm->context, current->active_mm->pgd);
-
-#ifdef DEBUG_FREQ
-       printk(KERN_DEBUG "HID1, after: %x\n", mfspr(SPRN_HID1));
-#endif
-
-       /* Restore low level PMU operations */
-       pmu_unlock();
-
-       /* Restore decrementer */
-       wakeup_decrementer();
-
-       /* Restore interrupts */
-       mpic_cpu_set_priority(pic_prio);
-
-       /* Let interrupts flow again ... */
-       local_irq_restore(flags);
-
-#ifdef DEBUG_FREQ
-       debug_calc_bogomips();
-#endif
-
-       pmu_resume();
-
-       preempt_enable();
-
-       return 0;
-}
-
-static int do_set_cpu_speed(int speed_mode, int notify)
-{
-       struct cpufreq_freqs freqs;
-       unsigned long l3cr;
-       static unsigned long prev_l3cr;
-
-       freqs.old = cur_freq;
-       freqs.new = (speed_mode == CPUFREQ_HIGH) ? hi_freq : low_freq;
-       freqs.cpu = smp_processor_id();
-
-       if (freqs.old == freqs.new)
-               return 0;
-
-       if (notify)
-               cpufreq_notify_transition(&freqs, CPUFREQ_PRECHANGE);
-       if (speed_mode == CPUFREQ_LOW &&
-           cpu_has_feature(CPU_FTR_L3CR)) {
-               l3cr = _get_L3CR();
-               if (l3cr & L3CR_L3E) {
-                       prev_l3cr = l3cr;
-                       _set_L3CR(0);
-               }
-       }
-       set_speed_proc(speed_mode == CPUFREQ_LOW);
-       if (speed_mode == CPUFREQ_HIGH &&
-           cpu_has_feature(CPU_FTR_L3CR)) {
-               l3cr = _get_L3CR();
-               if ((prev_l3cr & L3CR_L3E) && l3cr != prev_l3cr)
-                       _set_L3CR(prev_l3cr);
-       }
-       if (notify)
-               cpufreq_notify_transition(&freqs, CPUFREQ_POSTCHANGE);
-       cur_freq = (speed_mode == CPUFREQ_HIGH) ? hi_freq : low_freq;
-
-       return 0;
-}
-
-static unsigned int pmac_cpufreq_get_speed(unsigned int cpu)
-{
-       return cur_freq;
-}
-
-static int pmac_cpufreq_verify(struct cpufreq_policy *policy)
-{
-       return cpufreq_frequency_table_verify(policy, pmac_cpu_freqs);
-}
-
-static int pmac_cpufreq_target(        struct cpufreq_policy *policy,
-                                       unsigned int target_freq,
-                                       unsigned int relation)
-{
-       unsigned int    newstate = 0;
-
-       if (cpufreq_frequency_table_target(policy, pmac_cpu_freqs,
-                       target_freq, relation, &newstate))
-               return -EINVAL;
-
-       return do_set_cpu_speed(newstate, 1);
-}
-
-unsigned int pmac_get_one_cpufreq(int i)
-{
-       /* Supports only one CPU for now */
-       return (i == 0) ? cur_freq : 0;
-}
-
-static int pmac_cpufreq_cpu_init(struct cpufreq_policy *policy)
-{
-       if (policy->cpu != 0)
-               return -ENODEV;
-
-       policy->governor = CPUFREQ_DEFAULT_GOVERNOR;
-       policy->cpuinfo.transition_latency      = CPUFREQ_ETERNAL;
-       policy->cur = cur_freq;
-
-       cpufreq_frequency_table_get_attr(pmac_cpu_freqs, policy->cpu);
-       return cpufreq_frequency_table_cpuinfo(policy, pmac_cpu_freqs);
-}
-
-static u32 read_gpio(struct device_node *np)
-{
-       u32 *reg = (u32 *)get_property(np, "reg", NULL);
-       u32 offset;
-
-       if (reg == NULL)
-               return 0;
-       /* That works for all keylargos but shall be fixed properly
-        * some day... The problem is that it seems we can't rely
-        * on the "reg" property of the GPIO nodes, they are either
-        * relative to the base of KeyLargo or to the base of the
-        * GPIO space, and the device-tree doesn't help.
-        */
-       offset = *reg;
-       if (offset < KEYLARGO_GPIO_LEVELS0)
-               offset += KEYLARGO_GPIO_LEVELS0;
-       return offset;
-}
-
-static int pmac_cpufreq_suspend(struct cpufreq_policy *policy, pm_message_t pmsg)
-{
-       /* Ok, this could be made a bit smarter, but let's be robust for now. We
-        * always force a speed change to high speed before sleep, to make sure
-        * we have appropriate voltage and/or bus speed for the wakeup process,
-        * and to make sure our loops_per_jiffies are "good enough", that is will
-        * not cause too short delays if we sleep in low speed and wake in high
-        * speed..
-        */
-       no_schedule = 1;
-       sleep_freq = cur_freq;
-       if (cur_freq == low_freq && !is_pmu_based)
-               do_set_cpu_speed(CPUFREQ_HIGH, 0);
-       return 0;
-}
-
-static int pmac_cpufreq_resume(struct cpufreq_policy *policy)
-{
-       /* If we resume, first check if we have a get() function */
-       if (get_speed_proc)
-               cur_freq = get_speed_proc();
-       else
-               cur_freq = 0;
-
-       /* We don't, hrm... we don't really know our speed here, best
-        * is that we force a switch to whatever it was, which is
-        * probably high speed due to our suspend() routine
-        */
-       do_set_cpu_speed(sleep_freq == low_freq ?
-                        CPUFREQ_LOW : CPUFREQ_HIGH, 0);
-
-       no_schedule = 0;
-       return 0;
-}
-
-static struct cpufreq_driver pmac_cpufreq_driver = {
-       .verify         = pmac_cpufreq_verify,
-       .target         = pmac_cpufreq_target,
-       .get            = pmac_cpufreq_get_speed,
-       .init           = pmac_cpufreq_cpu_init,
-       .suspend        = pmac_cpufreq_suspend,
-       .resume         = pmac_cpufreq_resume,
-       .flags          = CPUFREQ_PM_NO_WARN,
-       .attr           = pmac_cpu_freqs_attr,
-       .name           = "powermac",
-       .owner          = THIS_MODULE,
-};
-
-
-static int pmac_cpufreq_init_MacRISC3(struct device_node *cpunode)
-{
-       struct device_node *volt_gpio_np = of_find_node_by_name(NULL,
-                                                               "voltage-gpio");
-       struct device_node *freq_gpio_np = of_find_node_by_name(NULL,
-                                                               "frequency-gpio");
-       struct device_node *slew_done_gpio_np = of_find_node_by_name(NULL,
-                                                                    "slewing-done");
-       u32 *value;
-
-       /*
-        * Check to see if it's GPIO driven or PMU only
-        *
-        * The way we extract the GPIO address is slightly hackish, but it
-        * works well enough for now. We need to abstract the whole GPIO
-        * stuff sooner or later anyway
-        */
-
-       if (volt_gpio_np)
-               voltage_gpio = read_gpio(volt_gpio_np);
-       if (freq_gpio_np)
-               frequency_gpio = read_gpio(freq_gpio_np);
-       if (slew_done_gpio_np)
-               slew_done_gpio = read_gpio(slew_done_gpio_np);
-
-       /* If we use the frequency GPIOs, calculate the min/max speeds based
-        * on the bus frequencies
-        */
-       if (frequency_gpio && slew_done_gpio) {
-               int lenp, rc;
-               u32 *freqs, *ratio;
-
-               freqs = (u32 *)get_property(cpunode, "bus-frequencies", &lenp);
-               lenp /= sizeof(u32);
-               if (freqs == NULL || lenp != 2) {
-                       printk(KERN_ERR "cpufreq: bus-frequencies incorrect or missing\n");
-                       return 1;
-               }
-               ratio = (u32 *)get_property(cpunode, "processor-to-bus-ratio*2", NULL);
-               if (ratio == NULL) {
-                       printk(KERN_ERR "cpufreq: processor-to-bus-ratio*2 missing\n");
-                       return 1;
-               }
-
-               /* Get the min/max bus frequencies */
-               low_freq = min(freqs[0], freqs[1]);
-               hi_freq = max(freqs[0], freqs[1]);
-
-               /* Grrrr.. It _seems_ that the device-tree is lying on the low bus
-                * frequency, it claims it to be around 84Mhz on some models while
-                * it appears to be approx. 101Mhz on all. Let's hack around here...
-                * fortunately, we don't need to be too precise
-                */
-               if (low_freq < 98000000)
-                       low_freq = 101000000;
-                       
-               /* Convert those to CPU core clocks */
-               low_freq = (low_freq * (*ratio)) / 2000;
-               hi_freq = (hi_freq * (*ratio)) / 2000;
-
-               /* Now we get the frequencies, we read the GPIO to see what is out current
-                * speed
-                */
-               rc = pmac_call_feature(PMAC_FTR_READ_GPIO, NULL, frequency_gpio, 0);
-               cur_freq = (rc & 0x01) ? hi_freq : low_freq;
-
-               set_speed_proc = gpios_set_cpu_speed;
-               return 1;
-       }
-
-       /* If we use the PMU, look for the min & max frequencies in the
-        * device-tree
-        */
-       value = (u32 *)get_property(cpunode, "min-clock-frequency", NULL);
-       if (!value)
-               return 1;
-       low_freq = (*value) / 1000;
-       /* The PowerBook G4 12" (PowerBook6,1) has an error in the device-tree
-        * here */
-       if (low_freq < 100000)
-               low_freq *= 10;
-
-       value = (u32 *)get_property(cpunode, "max-clock-frequency", NULL);
-       if (!value)
-               return 1;
-       hi_freq = (*value) / 1000;
-       set_speed_proc = pmu_set_cpu_speed;
-       is_pmu_based = 1;
-
-       return 0;
-}
-
-static int pmac_cpufreq_init_7447A(struct device_node *cpunode)
-{
-       struct device_node *volt_gpio_np;
-
-       if (get_property(cpunode, "dynamic-power-step", NULL) == NULL)
-               return 1;
-
-       volt_gpio_np = of_find_node_by_name(NULL, "cpu-vcore-select");
-       if (volt_gpio_np)
-               voltage_gpio = read_gpio(volt_gpio_np);
-       if (!voltage_gpio){
-               printk(KERN_ERR "cpufreq: missing cpu-vcore-select gpio\n");
-               return 1;
-       }
-
-       /* OF only reports the high frequency */
-       hi_freq = cur_freq;
-       low_freq = cur_freq/2;
-
-       /* Read actual frequency from CPU */
-       cur_freq = dfs_get_cpu_speed();
-       set_speed_proc = dfs_set_cpu_speed;
-       get_speed_proc = dfs_get_cpu_speed;
-
-       return 0;
-}
-
-static int pmac_cpufreq_init_750FX(struct device_node *cpunode)
-{
-       struct device_node *volt_gpio_np;
-       u32 pvr, *value;
-
-       if (get_property(cpunode, "dynamic-power-step", NULL) == NULL)
-               return 1;
-
-       hi_freq = cur_freq;
-       value = (u32 *)get_property(cpunode, "reduced-clock-frequency", NULL);
-       if (!value)
-               return 1;
-       low_freq = (*value) / 1000;
-
-       volt_gpio_np = of_find_node_by_name(NULL, "cpu-vcore-select");
-       if (volt_gpio_np)
-               voltage_gpio = read_gpio(volt_gpio_np);
-
-       pvr = mfspr(SPRN_PVR);
-       has_cpu_l2lve = !((pvr & 0xf00) == 0x100);
-
-       set_speed_proc = cpu_750fx_cpu_speed;
-       get_speed_proc = cpu_750fx_get_cpu_speed;
-       cur_freq = cpu_750fx_get_cpu_speed();
-
-       return 0;
-}
-
-/* Currently, we support the following machines:
- *
- *  - Titanium PowerBook 1Ghz (PMU based, 667Mhz & 1Ghz)
- *  - Titanium PowerBook 800 (PMU based, 667Mhz & 800Mhz)
- *  - Titanium PowerBook 400 (PMU based, 300Mhz & 400Mhz)
- *  - Titanium PowerBook 500 (PMU based, 300Mhz & 500Mhz)
- *  - iBook2 500/600 (PMU based, 400Mhz & 500/600Mhz)
- *  - iBook2 700 (CPU based, 400Mhz & 700Mhz, support low voltage)
- *  - Recent MacRISC3 laptops
- *  - All new machines with 7447A CPUs
- */
-static int __init pmac_cpufreq_setup(void)
-{
-       struct device_node      *cpunode;
-       u32                     *value;
-
-       if (strstr(cmd_line, "nocpufreq"))
-               return 0;
-
-       /* Assume only one CPU */
-       cpunode = find_type_devices("cpu");
-       if (!cpunode)
-               goto out;
-
-       /* Get current cpu clock freq */
-       value = (u32 *)get_property(cpunode, "clock-frequency", NULL);
-       if (!value)
-               goto out;
-       cur_freq = (*value) / 1000;
-
-       /*  Check for 7447A based MacRISC3 */
-       if (machine_is_compatible("MacRISC3") &&
-           get_property(cpunode, "dynamic-power-step", NULL) &&
-           PVR_VER(mfspr(SPRN_PVR)) == 0x8003) {
-               pmac_cpufreq_init_7447A(cpunode);
-       /* Check for other MacRISC3 machines */
-       } else if (machine_is_compatible("PowerBook3,4") ||
-                  machine_is_compatible("PowerBook3,5") ||
-                  machine_is_compatible("MacRISC3")) {
-               pmac_cpufreq_init_MacRISC3(cpunode);
-       /* Else check for iBook2 500/600 */
-       } else if (machine_is_compatible("PowerBook4,1")) {
-               hi_freq = cur_freq;
-               low_freq = 400000;
-               set_speed_proc = pmu_set_cpu_speed;
-               is_pmu_based = 1;
-       }
-       /* Else check for TiPb 400 & 500 */
-       else if (machine_is_compatible("PowerBook3,2")) {
-               /* We only know about the 400 MHz and the 500Mhz model
-                * they both have 300 MHz as low frequency
-                */
-               if (cur_freq < 350000 || cur_freq > 550000)
-                       goto out;
-               hi_freq = cur_freq;
-               low_freq = 300000;
-               set_speed_proc = pmu_set_cpu_speed;
-               is_pmu_based = 1;
-       }
-       /* Else check for 750FX */
-       else if (PVR_VER(mfspr(SPRN_PVR)) == 0x7000)
-               pmac_cpufreq_init_750FX(cpunode);
-out:
-       if (set_speed_proc == NULL)
-               return -ENODEV;
-
-       pmac_cpu_freqs[CPUFREQ_LOW].frequency = low_freq;
-       pmac_cpu_freqs[CPUFREQ_HIGH].frequency = hi_freq;
-
-       printk(KERN_INFO "Registering PowerMac CPU frequency driver\n");
-       printk(KERN_INFO "Low: %d Mhz, High: %d Mhz, Boot: %d Mhz\n",
-              low_freq/1000, hi_freq/1000, cur_freq/1000);
-
-       return cpufreq_register_driver(&pmac_cpufreq_driver);
-}
-
-module_init(pmac_cpufreq_setup);
-
diff --git a/arch/powerpc/platforms/powermac/pmac_feature.c b/arch/powerpc/platforms/powermac/pmac_feature.c
deleted file mode 100644 (file)
index 2cba670..0000000
+++ /dev/null
@@ -1,3062 +0,0 @@
-/*
- *  arch/ppc/platforms/pmac_feature.c
- *
- *  Copyright (C) 1996-2001 Paul Mackerras (paulus@cs.anu.edu.au)
- *                          Ben. Herrenschmidt (benh@kernel.crashing.org)
- *
- *  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.
- *
- *  TODO:
- *
- *   - Replace mdelay with some schedule loop if possible
- *   - Shorten some obfuscated delays on some routines (like modem
- *     power)
- *   - Refcount some clocks (see darwin)
- *   - Split split split...
- *
- */
-#include <linux/config.h>
-#include <linux/types.h>
-#include <linux/init.h>
-#include <linux/delay.h>
-#include <linux/kernel.h>
-#include <linux/sched.h>
-#include <linux/spinlock.h>
-#include <linux/adb.h>
-#include <linux/pmu.h>
-#include <linux/ioport.h>
-#include <linux/pci.h>
-#include <asm/sections.h>
-#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/machdep.h>
-#include <asm/pmac_feature.h>
-#include <asm/dbdma.h>
-#include <asm/pci-bridge.h>
-#include <asm/pmac_low_i2c.h>
-
-#undef DEBUG_FEATURE
-
-#ifdef DEBUG_FEATURE
-#define DBG(fmt...) printk(KERN_DEBUG fmt)
-#else
-#define DBG(fmt...)
-#endif
-
-#ifdef CONFIG_6xx
-extern int powersave_lowspeed;
-#endif
-
-extern int powersave_nap;
-extern struct device_node *k2_skiplist[2];
-
-
-/*
- * We use a single global lock to protect accesses. Each driver has
- * to take care of its own locking
- */
-static DEFINE_SPINLOCK(feature_lock);
-
-#define LOCK(flags)    spin_lock_irqsave(&feature_lock, flags);
-#define UNLOCK(flags)  spin_unlock_irqrestore(&feature_lock, flags);
-
-
-/*
- * Instance of some macio stuffs
- */
-struct macio_chip macio_chips[MAX_MACIO_CHIPS];
-
-struct macio_chip *macio_find(struct device_node *child, int type)
-{
-       while(child) {
-               int     i;
-
-               for (i=0; i < MAX_MACIO_CHIPS && macio_chips[i].of_node; i++)
-                       if (child == macio_chips[i].of_node &&
-                           (!type || macio_chips[i].type == type))
-                               return &macio_chips[i];
-               child = child->parent;
-       }
-       return NULL;
-}
-EXPORT_SYMBOL_GPL(macio_find);
-
-static const char *macio_names[] =
-{
-       "Unknown",
-       "Grand Central",
-       "OHare",
-       "OHareII",
-       "Heathrow",
-       "Gatwick",
-       "Paddington",
-       "Keylargo",
-       "Pangea",
-       "Intrepid",
-       "K2"
-};
-
-
-
-/*
- * Uninorth 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)))
-
-static struct device_node *uninorth_node;
-static u32 __iomem *uninorth_base;
-static u32 uninorth_rev;
-static int uninorth_u3;
-static void __iomem *u3_ht;
-
-/*
- * For each motherboard family, we have a table of functions pointers
- * that handle the various features.
- */
-
-typedef long (*feature_call)(struct device_node *node, long param, long value);
-
-struct feature_table_entry {
-       unsigned int    selector;
-       feature_call    function;
-};
-
-struct pmac_mb_def
-{
-       const char*                     model_string;
-       const char*                     model_name;
-       int                             model_id;
-       struct feature_table_entry*     features;
-       unsigned long                   board_flags;
-};
-static struct pmac_mb_def pmac_mb;
-
-/*
- * Here are the chip specific feature functions
- */
-
-static inline int simple_feature_tweak(struct device_node *node, int type,
-                                      int reg, u32 mask, int value)
-{
-       struct macio_chip*      macio;
-       unsigned long           flags;
-
-       macio = macio_find(node, type);
-       if (!macio)
-               return -ENODEV;
-       LOCK(flags);
-       if (value)
-               MACIO_BIS(reg, mask);
-       else
-               MACIO_BIC(reg, mask);
-       (void)MACIO_IN32(reg);
-       UNLOCK(flags);
-
-       return 0;
-}
-
-#ifndef CONFIG_POWER4
-
-static long ohare_htw_scc_enable(struct device_node *node, long param,
-                                long value)
-{
-       struct macio_chip*      macio;
-       unsigned long           chan_mask;
-       unsigned long           fcr;
-       unsigned long           flags;
-       int                     htw, trans;
-       unsigned long           rmask;
-
-       macio = macio_find(node, 0);
-       if (!macio)
-               return -ENODEV;
-       if (!strcmp(node->name, "ch-a"))
-               chan_mask = MACIO_FLAG_SCCA_ON;
-       else if (!strcmp(node->name, "ch-b"))
-               chan_mask = MACIO_FLAG_SCCB_ON;
-       else
-               return -ENODEV;
-
-       htw = (macio->type == macio_heathrow || macio->type == macio_paddington
-               || macio->type == macio_gatwick);
-       /* On these machines, the HRW_SCC_TRANS_EN_N bit mustn't be touched */
-       trans = (pmac_mb.model_id != PMAC_TYPE_YOSEMITE &&
-                pmac_mb.model_id != PMAC_TYPE_YIKES);
-       if (value) {
-#ifdef CONFIG_ADB_PMU
-               if ((param & 0xfff) == PMAC_SCC_IRDA)
-                       pmu_enable_irled(1);
-#endif /* CONFIG_ADB_PMU */
-               LOCK(flags);
-               fcr = MACIO_IN32(OHARE_FCR);
-               /* Check if scc cell need enabling */
-               if (!(fcr & OH_SCC_ENABLE)) {
-                       fcr |= OH_SCC_ENABLE;
-                       if (htw) {
-                               /* Side effect: this will also power up the
-                                * modem, but it's too messy to figure out on which
-                                * ports this controls the tranceiver and on which
-                                * it controls the modem
-                                */
-                               if (trans)
-                                       fcr &= ~HRW_SCC_TRANS_EN_N;
-                               MACIO_OUT32(OHARE_FCR, fcr);
-                               fcr |= (rmask = HRW_RESET_SCC);
-                               MACIO_OUT32(OHARE_FCR, fcr);
-                       } else {
-                               fcr |= (rmask = OH_SCC_RESET);
-                               MACIO_OUT32(OHARE_FCR, fcr);
-                       }
-                       UNLOCK(flags);
-                       (void)MACIO_IN32(OHARE_FCR);
-                       mdelay(15);
-                       LOCK(flags);
-                       fcr &= ~rmask;
-                       MACIO_OUT32(OHARE_FCR, fcr);
-               }
-               if (chan_mask & MACIO_FLAG_SCCA_ON)
-                       fcr |= OH_SCCA_IO;
-               if (chan_mask & MACIO_FLAG_SCCB_ON)
-                       fcr |= OH_SCCB_IO;
-               MACIO_OUT32(OHARE_FCR, fcr);
-               macio->flags |= chan_mask;
-               UNLOCK(flags);
-               if (param & PMAC_SCC_FLAG_XMON)
-                       macio->flags |= MACIO_FLAG_SCC_LOCKED;
-       } else {
-               if (macio->flags & MACIO_FLAG_SCC_LOCKED)
-                       return -EPERM;
-               LOCK(flags);
-               fcr = MACIO_IN32(OHARE_FCR);
-               if (chan_mask & MACIO_FLAG_SCCA_ON)
-                       fcr &= ~OH_SCCA_IO;
-               if (chan_mask & MACIO_FLAG_SCCB_ON)
-                       fcr &= ~OH_SCCB_IO;
-               MACIO_OUT32(OHARE_FCR, fcr);
-               if ((fcr & (OH_SCCA_IO | OH_SCCB_IO)) == 0) {
-                       fcr &= ~OH_SCC_ENABLE;
-                       if (htw && trans)
-                               fcr |= HRW_SCC_TRANS_EN_N;
-                       MACIO_OUT32(OHARE_FCR, fcr);
-               }
-               macio->flags &= ~(chan_mask);
-               UNLOCK(flags);
-               mdelay(10);
-#ifdef CONFIG_ADB_PMU
-               if ((param & 0xfff) == PMAC_SCC_IRDA)
-                       pmu_enable_irled(0);
-#endif /* CONFIG_ADB_PMU */
-       }
-       return 0;
-}
-
-static long ohare_floppy_enable(struct device_node *node, long param,
-                               long value)
-{
-       return simple_feature_tweak(node, macio_ohare,
-               OHARE_FCR, OH_FLOPPY_ENABLE, value);
-}
-
-static long ohare_mesh_enable(struct device_node *node, long param, long value)
-{
-       return simple_feature_tweak(node, macio_ohare,
-               OHARE_FCR, OH_MESH_ENABLE, value);
-}
-
-static long ohare_ide_enable(struct device_node *node, long param, long value)
-{
-       switch(param) {
-       case 0:
-               /* For some reason, setting the bit in set_initial_features()
-                * doesn't stick. I'm still investigating... --BenH.
-                */
-               if (value)
-                       simple_feature_tweak(node, macio_ohare,
-                               OHARE_FCR, OH_IOBUS_ENABLE, 1);
-               return simple_feature_tweak(node, macio_ohare,
-                       OHARE_FCR, OH_IDE0_ENABLE, value);
-       case 1:
-               return simple_feature_tweak(node, macio_ohare,
-                       OHARE_FCR, OH_BAY_IDE_ENABLE, value);
-       default:
-               return -ENODEV;
-       }
-}
-
-static long ohare_ide_reset(struct device_node *node, long param, long value)
-{
-       switch(param) {
-       case 0:
-               return simple_feature_tweak(node, macio_ohare,
-                       OHARE_FCR, OH_IDE0_RESET_N, !value);
-       case 1:
-               return simple_feature_tweak(node, macio_ohare,
-                       OHARE_FCR, OH_IDE1_RESET_N, !value);
-       default:
-               return -ENODEV;
-       }
-}
-
-static long ohare_sleep_state(struct device_node *node, long param, long value)
-{
-       struct macio_chip*      macio = &macio_chips[0];
-
-       if ((pmac_mb.board_flags & PMAC_MB_CAN_SLEEP) == 0)
-               return -EPERM;
-       if (value == 1) {
-               MACIO_BIC(OHARE_FCR, OH_IOBUS_ENABLE);
-       } else if (value == 0) {
-               MACIO_BIS(OHARE_FCR, OH_IOBUS_ENABLE);
-       }
-
-       return 0;
-}
-
-static long heathrow_modem_enable(struct device_node *node, long param,
-                                 long value)
-{
-       struct macio_chip*      macio;
-       u8                      gpio;
-       unsigned long           flags;
-
-       macio = macio_find(node, macio_unknown);
-       if (!macio)
-               return -ENODEV;
-       gpio = MACIO_IN8(HRW_GPIO_MODEM_RESET) & ~1;
-       if (!value) {
-               LOCK(flags);
-               MACIO_OUT8(HRW_GPIO_MODEM_RESET, gpio);
-               UNLOCK(flags);
-               (void)MACIO_IN8(HRW_GPIO_MODEM_RESET);
-               mdelay(250);
-       }
-       if (pmac_mb.model_id != PMAC_TYPE_YOSEMITE &&
-           pmac_mb.model_id != PMAC_TYPE_YIKES) {
-               LOCK(flags);
-               if (value)
-                       MACIO_BIC(HEATHROW_FCR, HRW_SCC_TRANS_EN_N);
-               else
-                       MACIO_BIS(HEATHROW_FCR, HRW_SCC_TRANS_EN_N);
-               UNLOCK(flags);
-               (void)MACIO_IN32(HEATHROW_FCR);
-               mdelay(250);
-       }
-       if (value) {
-               LOCK(flags);
-               MACIO_OUT8(HRW_GPIO_MODEM_RESET, gpio | 1);
-               (void)MACIO_IN8(HRW_GPIO_MODEM_RESET);
-               UNLOCK(flags); mdelay(250); LOCK(flags);
-               MACIO_OUT8(HRW_GPIO_MODEM_RESET, gpio);
-               (void)MACIO_IN8(HRW_GPIO_MODEM_RESET);
-               UNLOCK(flags); mdelay(250); LOCK(flags);
-               MACIO_OUT8(HRW_GPIO_MODEM_RESET, gpio | 1);
-               (void)MACIO_IN8(HRW_GPIO_MODEM_RESET);
-               UNLOCK(flags); mdelay(250);
-       }
-       return 0;
-}
-
-static long heathrow_floppy_enable(struct device_node *node, long param,
-                                  long value)
-{
-       return simple_feature_tweak(node, macio_unknown,
-               HEATHROW_FCR,
-               HRW_SWIM_ENABLE|HRW_BAY_FLOPPY_ENABLE,
-               value);
-}
-
-static long heathrow_mesh_enable(struct device_node *node, long param,
-                                long value)
-{
-       struct macio_chip*      macio;
-       unsigned long           flags;
-
-       macio = macio_find(node, macio_unknown);
-       if (!macio)
-               return -ENODEV;
-       LOCK(flags);
-       /* Set clear mesh cell enable */
-       if (value)
-               MACIO_BIS(HEATHROW_FCR, HRW_MESH_ENABLE);
-       else
-               MACIO_BIC(HEATHROW_FCR, HRW_MESH_ENABLE);
-       (void)MACIO_IN32(HEATHROW_FCR);
-       udelay(10);
-       /* Set/Clear termination power */
-       if (value)
-               MACIO_BIC(HEATHROW_MBCR, 0x04000000);
-       else
-               MACIO_BIS(HEATHROW_MBCR, 0x04000000);
-       (void)MACIO_IN32(HEATHROW_MBCR);
-       udelay(10);
-       UNLOCK(flags);
-
-       return 0;
-}
-
-static long heathrow_ide_enable(struct device_node *node, long param,
-                               long value)
-{
-       switch(param) {
-       case 0:
-               return simple_feature_tweak(node, macio_unknown,
-                       HEATHROW_FCR, HRW_IDE0_ENABLE, value);
-       case 1:
-               return simple_feature_tweak(node, macio_unknown,
-                       HEATHROW_FCR, HRW_BAY_IDE_ENABLE, value);
-       default:
-               return -ENODEV;
-       }
-}
-
-static long heathrow_ide_reset(struct device_node *node, long param,
-                              long value)
-{
-       switch(param) {
-       case 0:
-               return simple_feature_tweak(node, macio_unknown,
-                       HEATHROW_FCR, HRW_IDE0_RESET_N, !value);
-       case 1:
-               return simple_feature_tweak(node, macio_unknown,
-                       HEATHROW_FCR, HRW_IDE1_RESET_N, !value);
-       default:
-               return -ENODEV;
-       }
-}
-
-static long heathrow_bmac_enable(struct device_node *node, long param,
-                                long value)
-{
-       struct macio_chip*      macio;
-       unsigned long           flags;
-
-       macio = macio_find(node, 0);
-       if (!macio)
-               return -ENODEV;
-       if (value) {
-               LOCK(flags);
-               MACIO_BIS(HEATHROW_FCR, HRW_BMAC_IO_ENABLE);
-               MACIO_BIS(HEATHROW_FCR, HRW_BMAC_RESET);
-               UNLOCK(flags);
-               (void)MACIO_IN32(HEATHROW_FCR);
-               mdelay(10);
-               LOCK(flags);
-               MACIO_BIC(HEATHROW_FCR, HRW_BMAC_RESET);
-               UNLOCK(flags);
-               (void)MACIO_IN32(HEATHROW_FCR);
-               mdelay(10);
-       } else {
-               LOCK(flags);
-               MACIO_BIC(HEATHROW_FCR, HRW_BMAC_IO_ENABLE);
-               UNLOCK(flags);
-       }
-       return 0;
-}
-
-static long heathrow_sound_enable(struct device_node *node, long param,
-                                 long value)
-{
-       struct macio_chip*      macio;
-       unsigned long           flags;
-
-       /* B&W G3 and Yikes don't support that properly (the
-        * sound appear to never come back after beeing shut down).
-        */
-       if (pmac_mb.model_id == PMAC_TYPE_YOSEMITE ||
-           pmac_mb.model_id == PMAC_TYPE_YIKES)
-               return 0;
-
-       macio = macio_find(node, 0);
-       if (!macio)
-               return -ENODEV;
-       if (value) {
-               LOCK(flags);
-               MACIO_BIS(HEATHROW_FCR, HRW_SOUND_CLK_ENABLE);
-               MACIO_BIC(HEATHROW_FCR, HRW_SOUND_POWER_N);
-               UNLOCK(flags);
-               (void)MACIO_IN32(HEATHROW_FCR);
-       } else {
-               LOCK(flags);
-               MACIO_BIS(HEATHROW_FCR, HRW_SOUND_POWER_N);
-               MACIO_BIC(HEATHROW_FCR, HRW_SOUND_CLK_ENABLE);
-               UNLOCK(flags);
-       }
-       return 0;
-}
-
-static u32 save_fcr[6];
-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 u32 save_unin_clock_ctl;
-static struct dbdma_regs save_dbdma[13];
-static struct dbdma_regs save_alt_dbdma[13];
-
-static void dbdma_save(struct macio_chip *macio, struct dbdma_regs *save)
-{
-       int i;
-
-       /* Save state & config of DBDMA channels */
-       for (i = 0; i < 13; i++) {
-               volatile struct dbdma_regs __iomem * chan = (void __iomem *)
-                       (macio->base + ((0x8000+i*0x100)>>2));
-               save[i].cmdptr_hi = in_le32(&chan->cmdptr_hi);
-               save[i].cmdptr = in_le32(&chan->cmdptr);
-               save[i].intr_sel = in_le32(&chan->intr_sel);
-               save[i].br_sel = in_le32(&chan->br_sel);
-               save[i].wait_sel = in_le32(&chan->wait_sel);
-       }
-}
-
-static void dbdma_restore(struct macio_chip *macio, struct dbdma_regs *save)
-{
-       int i;
-
-       /* Save state & config of DBDMA channels */
-       for (i = 0; i < 13; i++) {
-               volatile struct dbdma_regs __iomem * chan = (void __iomem *)
-                       (macio->base + ((0x8000+i*0x100)>>2));
-               out_le32(&chan->control, (ACTIVE|DEAD|WAKE|FLUSH|PAUSE|RUN)<<16);
-               while (in_le32(&chan->status) & ACTIVE)
-                       mb();
-               out_le32(&chan->cmdptr_hi, save[i].cmdptr_hi);
-               out_le32(&chan->cmdptr, save[i].cmdptr);
-               out_le32(&chan->intr_sel, save[i].intr_sel);
-               out_le32(&chan->br_sel, save[i].br_sel);
-               out_le32(&chan->wait_sel, save[i].wait_sel);
-       }
-}
-
-static void heathrow_sleep(struct macio_chip *macio, int secondary)
-{
-       if (secondary) {
-               dbdma_save(macio, save_alt_dbdma);
-               save_fcr[2] = MACIO_IN32(0x38);
-               save_fcr[3] = MACIO_IN32(0x3c);
-       } else {
-               dbdma_save(macio, save_dbdma);
-               save_fcr[0] = MACIO_IN32(0x38);
-               save_fcr[1] = MACIO_IN32(0x3c);
-               save_mbcr = MACIO_IN32(0x34);
-               /* Make sure sound is shut down */
-               MACIO_BIS(HEATHROW_FCR, HRW_SOUND_POWER_N);
-               MACIO_BIC(HEATHROW_FCR, HRW_SOUND_CLK_ENABLE);
-               /* This seems to be necessary as well or the fan
-                * keeps coming up and battery drains fast */
-               MACIO_BIC(HEATHROW_FCR, HRW_IOBUS_ENABLE);
-               MACIO_BIC(HEATHROW_FCR, HRW_IDE0_RESET_N);
-               /* Make sure eth is down even if module or sleep
-                * won't work properly */
-               MACIO_BIC(HEATHROW_FCR, HRW_BMAC_IO_ENABLE | HRW_BMAC_RESET);
-       }
-       /* Make sure modem is shut down */
-       MACIO_OUT8(HRW_GPIO_MODEM_RESET,
-               MACIO_IN8(HRW_GPIO_MODEM_RESET) & ~1);
-       MACIO_BIS(HEATHROW_FCR, HRW_SCC_TRANS_EN_N);
-       MACIO_BIC(HEATHROW_FCR, OH_SCCA_IO|OH_SCCB_IO|HRW_SCC_ENABLE);
-
-       /* Let things settle */
-       (void)MACIO_IN32(HEATHROW_FCR);
-}
-
-static void heathrow_wakeup(struct macio_chip *macio, int secondary)
-{
-       if (secondary) {
-               MACIO_OUT32(0x38, save_fcr[2]);
-               (void)MACIO_IN32(0x38);
-               mdelay(1);
-               MACIO_OUT32(0x3c, save_fcr[3]);
-               (void)MACIO_IN32(0x38);
-               mdelay(10);
-               dbdma_restore(macio, save_alt_dbdma);
-       } else {
-               MACIO_OUT32(0x38, save_fcr[0] | HRW_IOBUS_ENABLE);
-               (void)MACIO_IN32(0x38);
-               mdelay(1);
-               MACIO_OUT32(0x3c, save_fcr[1]);
-               (void)MACIO_IN32(0x38);
-               mdelay(1);
-               MACIO_OUT32(0x34, save_mbcr);
-               (void)MACIO_IN32(0x38);
-               mdelay(10);
-               dbdma_restore(macio, save_dbdma);
-       }
-}
-
-static long heathrow_sleep_state(struct device_node *node, long param,
-                                long value)
-{
-       if ((pmac_mb.board_flags & PMAC_MB_CAN_SLEEP) == 0)
-               return -EPERM;
-       if (value == 1) {
-               if (macio_chips[1].type == macio_gatwick)
-                       heathrow_sleep(&macio_chips[0], 1);
-               heathrow_sleep(&macio_chips[0], 0);
-       } else if (value == 0) {
-               heathrow_wakeup(&macio_chips[0], 0);
-               if (macio_chips[1].type == macio_gatwick)
-                       heathrow_wakeup(&macio_chips[0], 1);
-       }
-       return 0;
-}
-
-static long core99_scc_enable(struct device_node *node, long param, long value)
-{
-       struct macio_chip*      macio;
-       unsigned long           flags;
-       unsigned long           chan_mask;
-       u32                     fcr;
-
-       macio = macio_find(node, 0);
-       if (!macio)
-               return -ENODEV;
-       if (!strcmp(node->name, "ch-a"))
-               chan_mask = MACIO_FLAG_SCCA_ON;
-       else if (!strcmp(node->name, "ch-b"))
-               chan_mask = MACIO_FLAG_SCCB_ON;
-       else
-               return -ENODEV;
-
-       if (value) {
-               int need_reset_scc = 0;
-               int need_reset_irda = 0;
-
-               LOCK(flags);
-               fcr = MACIO_IN32(KEYLARGO_FCR0);
-               /* Check if scc cell need enabling */
-               if (!(fcr & KL0_SCC_CELL_ENABLE)) {
-                       fcr |= KL0_SCC_CELL_ENABLE;
-                       need_reset_scc = 1;
-               }
-               if (chan_mask & MACIO_FLAG_SCCA_ON) {
-                       fcr |= KL0_SCCA_ENABLE;
-                       /* Don't enable line drivers for I2S modem */
-                       if ((param & 0xfff) == PMAC_SCC_I2S1)
-                               fcr &= ~KL0_SCC_A_INTF_ENABLE;
-                       else
-                               fcr |= KL0_SCC_A_INTF_ENABLE;
-               }
-               if (chan_mask & MACIO_FLAG_SCCB_ON) {
-                       fcr |= KL0_SCCB_ENABLE;
-                       /* Perform irda specific inits */
-                       if ((param & 0xfff) == PMAC_SCC_IRDA) {
-                               fcr &= ~KL0_SCC_B_INTF_ENABLE;
-                               fcr |= KL0_IRDA_ENABLE;
-                               fcr |= KL0_IRDA_CLK32_ENABLE | KL0_IRDA_CLK19_ENABLE;
-                               fcr |= KL0_IRDA_SOURCE1_SEL;
-                               fcr &= ~(KL0_IRDA_FAST_CONNECT|KL0_IRDA_DEFAULT1|KL0_IRDA_DEFAULT0);
-                               fcr &= ~(KL0_IRDA_SOURCE2_SEL|KL0_IRDA_HIGH_BAND);
-                               need_reset_irda = 1;
-                       } else
-                               fcr |= KL0_SCC_B_INTF_ENABLE;
-               }
-               MACIO_OUT32(KEYLARGO_FCR0, fcr);
-               macio->flags |= chan_mask;
-               if (need_reset_scc)  {
-                       MACIO_BIS(KEYLARGO_FCR0, KL0_SCC_RESET);
-                       (void)MACIO_IN32(KEYLARGO_FCR0);
-                       UNLOCK(flags);
-                       mdelay(15);
-                       LOCK(flags);
-                       MACIO_BIC(KEYLARGO_FCR0, KL0_SCC_RESET);
-               }
-               if (need_reset_irda)  {
-                       MACIO_BIS(KEYLARGO_FCR0, KL0_IRDA_RESET);
-                       (void)MACIO_IN32(KEYLARGO_FCR0);
-                       UNLOCK(flags);
-                       mdelay(15);
-                       LOCK(flags);
-                       MACIO_BIC(KEYLARGO_FCR0, KL0_IRDA_RESET);
-               }
-               UNLOCK(flags);
-               if (param & PMAC_SCC_FLAG_XMON)
-                       macio->flags |= MACIO_FLAG_SCC_LOCKED;
-       } else {
-               if (macio->flags & MACIO_FLAG_SCC_LOCKED)
-                       return -EPERM;
-               LOCK(flags);
-               fcr = MACIO_IN32(KEYLARGO_FCR0);
-               if (chan_mask & MACIO_FLAG_SCCA_ON)
-                       fcr &= ~KL0_SCCA_ENABLE;
-               if (chan_mask & MACIO_FLAG_SCCB_ON) {
-                       fcr &= ~KL0_SCCB_ENABLE;
-                       /* Perform irda specific clears */
-                       if ((param & 0xfff) == PMAC_SCC_IRDA) {
-                               fcr &= ~KL0_IRDA_ENABLE;
-                               fcr &= ~(KL0_IRDA_CLK32_ENABLE | KL0_IRDA_CLK19_ENABLE);
-                               fcr &= ~(KL0_IRDA_FAST_CONNECT|KL0_IRDA_DEFAULT1|KL0_IRDA_DEFAULT0);
-                               fcr &= ~(KL0_IRDA_SOURCE1_SEL|KL0_IRDA_SOURCE2_SEL|KL0_IRDA_HIGH_BAND);
-                       }
-               }
-               MACIO_OUT32(KEYLARGO_FCR0, fcr);
-               if ((fcr & (KL0_SCCA_ENABLE | KL0_SCCB_ENABLE)) == 0) {
-                       fcr &= ~KL0_SCC_CELL_ENABLE;
-                       MACIO_OUT32(KEYLARGO_FCR0, fcr);
-               }
-               macio->flags &= ~(chan_mask);
-               UNLOCK(flags);
-               mdelay(10);
-       }
-       return 0;
-}
-
-static long
-core99_modem_enable(struct device_node *node, long param, long value)
-{
-       struct macio_chip*      macio;
-       u8                      gpio;
-       unsigned long           flags;
-
-       /* Hack for internal USB modem */
-       if (node == NULL) {
-               if (macio_chips[0].type != macio_keylargo)
-                       return -ENODEV;
-               node = macio_chips[0].of_node;
-       }
-       macio = macio_find(node, 0);
-       if (!macio)
-               return -ENODEV;
-       gpio = MACIO_IN8(KL_GPIO_MODEM_RESET);
-       gpio |= KEYLARGO_GPIO_OUTPUT_ENABLE;
-       gpio &= ~KEYLARGO_GPIO_OUTOUT_DATA;
-
-       if (!value) {
-               LOCK(flags);
-               MACIO_OUT8(KL_GPIO_MODEM_RESET, gpio);
-               UNLOCK(flags);
-               (void)MACIO_IN8(KL_GPIO_MODEM_RESET);
-               mdelay(250);
-       }
-       LOCK(flags);
-       if (value) {
-               MACIO_BIC(KEYLARGO_FCR2, KL2_ALT_DATA_OUT);
-               UNLOCK(flags);
-               (void)MACIO_IN32(KEYLARGO_FCR2);
-               mdelay(250);
-       } else {
-               MACIO_BIS(KEYLARGO_FCR2, KL2_ALT_DATA_OUT);
-               UNLOCK(flags);
-       }
-       if (value) {
-               LOCK(flags);
-               MACIO_OUT8(KL_GPIO_MODEM_RESET, gpio | KEYLARGO_GPIO_OUTOUT_DATA);
-               (void)MACIO_IN8(KL_GPIO_MODEM_RESET);
-               UNLOCK(flags); mdelay(250); LOCK(flags);
-               MACIO_OUT8(KL_GPIO_MODEM_RESET, gpio);
-               (void)MACIO_IN8(KL_GPIO_MODEM_RESET);
-               UNLOCK(flags); mdelay(250); LOCK(flags);
-               MACIO_OUT8(KL_GPIO_MODEM_RESET, gpio | KEYLARGO_GPIO_OUTOUT_DATA);
-               (void)MACIO_IN8(KL_GPIO_MODEM_RESET);
-               UNLOCK(flags); mdelay(250);
-       }
-       return 0;
-}
-
-static long
-pangea_modem_enable(struct device_node *node, long param, long value)
-{
-       struct macio_chip*      macio;
-       u8                      gpio;
-       unsigned long           flags;
-
-       /* Hack for internal USB modem */
-       if (node == NULL) {
-               if (macio_chips[0].type != macio_pangea &&
-                   macio_chips[0].type != macio_intrepid)
-                       return -ENODEV;
-               node = macio_chips[0].of_node;
-       }
-       macio = macio_find(node, 0);
-       if (!macio)
-               return -ENODEV;
-       gpio = MACIO_IN8(KL_GPIO_MODEM_RESET);
-       gpio |= KEYLARGO_GPIO_OUTPUT_ENABLE;
-       gpio &= ~KEYLARGO_GPIO_OUTOUT_DATA;
-
-       if (!value) {
-               LOCK(flags);
-               MACIO_OUT8(KL_GPIO_MODEM_RESET, gpio);
-               UNLOCK(flags);
-               (void)MACIO_IN8(KL_GPIO_MODEM_RESET);
-               mdelay(250);
-       }
-       LOCK(flags);
-       if (value) {
-               MACIO_OUT8(KL_GPIO_MODEM_POWER,
-                       KEYLARGO_GPIO_OUTPUT_ENABLE);
-               UNLOCK(flags);
-               (void)MACIO_IN32(KEYLARGO_FCR2);
-               mdelay(250);
-       } else {
-               MACIO_OUT8(KL_GPIO_MODEM_POWER,
-                       KEYLARGO_GPIO_OUTPUT_ENABLE | KEYLARGO_GPIO_OUTOUT_DATA);
-               UNLOCK(flags);
-       }
-       if (value) {
-               LOCK(flags);
-               MACIO_OUT8(KL_GPIO_MODEM_RESET, gpio | KEYLARGO_GPIO_OUTOUT_DATA);
-               (void)MACIO_IN8(KL_GPIO_MODEM_RESET);
-               UNLOCK(flags); mdelay(250); LOCK(flags);
-               MACIO_OUT8(KL_GPIO_MODEM_RESET, gpio);
-               (void)MACIO_IN8(KL_GPIO_MODEM_RESET);
-               UNLOCK(flags); mdelay(250); LOCK(flags);
-               MACIO_OUT8(KL_GPIO_MODEM_RESET, gpio | KEYLARGO_GPIO_OUTOUT_DATA);
-               (void)MACIO_IN8(KL_GPIO_MODEM_RESET);
-               UNLOCK(flags); mdelay(250);
-       }
-       return 0;
-}
-
-static long
-core99_ata100_enable(struct device_node *node, long value)
-{
-       unsigned long flags;
-       struct pci_dev *pdev = NULL;
-       u8 pbus, pid;
-
-       if (uninorth_rev < 0x24)
-               return -ENODEV;
-
-       LOCK(flags);
-       if (value)
-               UN_BIS(UNI_N_CLOCK_CNTL, UNI_N_CLOCK_CNTL_ATA100);
-       else
-               UN_BIC(UNI_N_CLOCK_CNTL, UNI_N_CLOCK_CNTL_ATA100);
-       (void)UN_IN(UNI_N_CLOCK_CNTL);
-       UNLOCK(flags);
-       udelay(20);
-
-       if (value) {
-               if (pci_device_from_OF_node(node, &pbus, &pid) == 0)
-                       pdev = pci_find_slot(pbus, pid);
-               if (pdev == NULL)
-                       return 0;
-               pci_enable_device(pdev);
-               pci_set_master(pdev);
-       }
-       return 0;
-}
-
-static long
-core99_ide_enable(struct device_node *node, long param, long value)
-{
-       /* Bus ID 0 to 2 are KeyLargo based IDE, busID 3 is U2
-        * based ata-100
-        */
-       switch(param) {
-           case 0:
-               return simple_feature_tweak(node, macio_unknown,
-                       KEYLARGO_FCR1, KL1_EIDE0_ENABLE, value);
-           case 1:
-               return simple_feature_tweak(node, macio_unknown,
-                       KEYLARGO_FCR1, KL1_EIDE1_ENABLE, value);
-           case 2:
-               return simple_feature_tweak(node, macio_unknown,
-                       KEYLARGO_FCR1, KL1_UIDE_ENABLE, value);
-           case 3:
-               return core99_ata100_enable(node, value);
-           default:
-               return -ENODEV;
-       }
-}
-
-static long
-core99_ide_reset(struct device_node *node, long param, long value)
-{
-       switch(param) {
-           case 0:
-               return simple_feature_tweak(node, macio_unknown,
-                       KEYLARGO_FCR1, KL1_EIDE0_RESET_N, !value);
-           case 1:
-               return simple_feature_tweak(node, macio_unknown,
-                       KEYLARGO_FCR1, KL1_EIDE1_RESET_N, !value);
-           case 2:
-               return simple_feature_tweak(node, macio_unknown,
-                       KEYLARGO_FCR1, KL1_UIDE_RESET_N, !value);
-           default:
-               return -ENODEV;
-       }
-}
-
-static long
-core99_gmac_enable(struct device_node *node, long param, long value)
-{
-       unsigned long flags;
-
-       LOCK(flags);
-       if (value)
-               UN_BIS(UNI_N_CLOCK_CNTL, UNI_N_CLOCK_CNTL_GMAC);
-       else
-               UN_BIC(UNI_N_CLOCK_CNTL, UNI_N_CLOCK_CNTL_GMAC);
-       (void)UN_IN(UNI_N_CLOCK_CNTL);
-       UNLOCK(flags);
-       udelay(20);
-
-       return 0;
-}
-
-static long
-core99_gmac_phy_reset(struct device_node *node, long param, long value)
-{
-       unsigned long flags;
-       struct macio_chip *macio;
-
-       macio = &macio_chips[0];
-       if (macio->type != macio_keylargo && macio->type != macio_pangea &&
-           macio->type != macio_intrepid)
-               return -ENODEV;
-
-       LOCK(flags);
-       MACIO_OUT8(KL_GPIO_ETH_PHY_RESET, KEYLARGO_GPIO_OUTPUT_ENABLE);
-       (void)MACIO_IN8(KL_GPIO_ETH_PHY_RESET);
-       UNLOCK(flags);
-       mdelay(10);
-       LOCK(flags);
-       MACIO_OUT8(KL_GPIO_ETH_PHY_RESET, /*KEYLARGO_GPIO_OUTPUT_ENABLE | */
-               KEYLARGO_GPIO_OUTOUT_DATA);
-       UNLOCK(flags);
-       mdelay(10);
-
-       return 0;
-}
-
-static long
-core99_sound_chip_enable(struct device_node *node, long param, long value)
-{
-       struct macio_chip*      macio;
-       unsigned long           flags;
-
-       macio = macio_find(node, 0);
-       if (!macio)
-               return -ENODEV;
-
-       /* Do a better probe code, screamer G4 desktops &
-        * iMacs can do that too, add a recalibrate  in
-        * the driver as well
-        */
-       if (pmac_mb.model_id == PMAC_TYPE_PISMO ||
-           pmac_mb.model_id == PMAC_TYPE_TITANIUM) {
-               LOCK(flags);
-               if (value)
-                       MACIO_OUT8(KL_GPIO_SOUND_POWER,
-                               KEYLARGO_GPIO_OUTPUT_ENABLE |
-                               KEYLARGO_GPIO_OUTOUT_DATA);
-               else
-                       MACIO_OUT8(KL_GPIO_SOUND_POWER,
-                               KEYLARGO_GPIO_OUTPUT_ENABLE);
-               (void)MACIO_IN8(KL_GPIO_SOUND_POWER);
-               UNLOCK(flags);
-       }
-       return 0;
-}
-
-static long
-core99_airport_enable(struct device_node *node, long param, long value)
-{
-       struct macio_chip*      macio;
-       unsigned long           flags;
-       int                     state;
-
-       macio = macio_find(node, 0);
-       if (!macio)
-               return -ENODEV;
-
-       /* Hint: we allow passing of macio itself for the sake of the
-        * sleep code
-        */
-       if (node != macio->of_node &&
-           (!node->parent || node->parent != macio->of_node))
-               return -ENODEV;
-       state = (macio->flags & MACIO_FLAG_AIRPORT_ON) != 0;
-       if (value == state)
-               return 0;
-       if (value) {
-               /* This code is a reproduction of OF enable-cardslot
-                * and init-wireless methods, slightly hacked until
-                * I got it working.
-                */
-               LOCK(flags);
-               MACIO_OUT8(KEYLARGO_GPIO_0+0xf, 5);
-               (void)MACIO_IN8(KEYLARGO_GPIO_0+0xf);
-               UNLOCK(flags);
-               mdelay(10);
-               LOCK(flags);
-               MACIO_OUT8(KEYLARGO_GPIO_0+0xf, 4);
-               (void)MACIO_IN8(KEYLARGO_GPIO_0+0xf);
-               UNLOCK(flags);
-
-               mdelay(10);
-
-               LOCK(flags);
-               MACIO_BIC(KEYLARGO_FCR2, KL2_CARDSEL_16);
-               (void)MACIO_IN32(KEYLARGO_FCR2);
-               udelay(10);
-               MACIO_OUT8(KEYLARGO_GPIO_EXTINT_0+0xb, 0);
-               (void)MACIO_IN8(KEYLARGO_GPIO_EXTINT_0+0xb);
-               udelay(10);
-               MACIO_OUT8(KEYLARGO_GPIO_EXTINT_0+0xa, 0x28);
-               (void)MACIO_IN8(KEYLARGO_GPIO_EXTINT_0+0xa);
-               udelay(10);
-               MACIO_OUT8(KEYLARGO_GPIO_EXTINT_0+0xd, 0x28);
-               (void)MACIO_IN8(KEYLARGO_GPIO_EXTINT_0+0xd);
-               udelay(10);
-               MACIO_OUT8(KEYLARGO_GPIO_0+0xd, 0x28);
-               (void)MACIO_IN8(KEYLARGO_GPIO_0+0xd);
-               udelay(10);
-               MACIO_OUT8(KEYLARGO_GPIO_0+0xe, 0x28);
-               (void)MACIO_IN8(KEYLARGO_GPIO_0+0xe);
-               UNLOCK(flags);
-               udelay(10);
-               MACIO_OUT32(0x1c000, 0);
-               mdelay(1);
-               MACIO_OUT8(0x1a3e0, 0x41);
-               (void)MACIO_IN8(0x1a3e0);
-               udelay(10);
-               LOCK(flags);
-               MACIO_BIS(KEYLARGO_FCR2, KL2_CARDSEL_16);
-               (void)MACIO_IN32(KEYLARGO_FCR2);
-               UNLOCK(flags);
-               mdelay(100);
-
-               macio->flags |= MACIO_FLAG_AIRPORT_ON;
-       } else {
-               LOCK(flags);
-               MACIO_BIC(KEYLARGO_FCR2, KL2_CARDSEL_16);
-               (void)MACIO_IN32(KEYLARGO_FCR2);
-               MACIO_OUT8(KL_GPIO_AIRPORT_0, 0);
-               MACIO_OUT8(KL_GPIO_AIRPORT_1, 0);
-               MACIO_OUT8(KL_GPIO_AIRPORT_2, 0);
-               MACIO_OUT8(KL_GPIO_AIRPORT_3, 0);
-               MACIO_OUT8(KL_GPIO_AIRPORT_4, 0);
-               (void)MACIO_IN8(KL_GPIO_AIRPORT_4);
-               UNLOCK(flags);
-
-               macio->flags &= ~MACIO_FLAG_AIRPORT_ON;
-       }
-       return 0;
-}
-
-#ifdef CONFIG_SMP
-static long
-core99_reset_cpu(struct device_node *node, long param, long value)
-{
-       unsigned int reset_io = 0;
-       unsigned long flags;
-       struct macio_chip *macio;
-       struct device_node *np;
-       const int dflt_reset_lines[] = {        KL_GPIO_RESET_CPU0,
-                                               KL_GPIO_RESET_CPU1,
-                                               KL_GPIO_RESET_CPU2,
-                                               KL_GPIO_RESET_CPU3 };
-
-       macio = &macio_chips[0];
-       if (macio->type != macio_keylargo)
-               return -ENODEV;
-
-       np = find_path_device("/cpus");
-       if (np == NULL)
-               return -ENODEV;
-       for (np = np->child; np != NULL; np = np->sibling) {
-               u32 *num = (u32 *)get_property(np, "reg", NULL);
-               u32 *rst = (u32 *)get_property(np, "soft-reset", NULL);
-               if (num == NULL || rst == NULL)
-                       continue;
-               if (param == *num) {
-                       reset_io = *rst;
-                       break;
-               }
-       }
-       if (np == NULL || reset_io == 0)
-               reset_io = dflt_reset_lines[param];
-
-       LOCK(flags);
-       MACIO_OUT8(reset_io, KEYLARGO_GPIO_OUTPUT_ENABLE);
-       (void)MACIO_IN8(reset_io);
-       udelay(1);
-       MACIO_OUT8(reset_io, 0);
-       (void)MACIO_IN8(reset_io);
-       UNLOCK(flags);
-
-       return 0;
-}
-#endif /* CONFIG_SMP */
-
-static long
-core99_usb_enable(struct device_node *node, long param, long value)
-{
-       struct macio_chip *macio;
-       unsigned long flags;
-       char *prop;
-       int number;
-       u32 reg;
-
-       macio = &macio_chips[0];
-       if (macio->type != macio_keylargo && macio->type != macio_pangea &&
-           macio->type != macio_intrepid)
-               return -ENODEV;
-
-       prop = (char *)get_property(node, "AAPL,clock-id", NULL);
-       if (!prop)
-               return -ENODEV;
-       if (strncmp(prop, "usb0u048", 8) == 0)
-               number = 0;
-       else if (strncmp(prop, "usb1u148", 8) == 0)
-               number = 2;
-       else if (strncmp(prop, "usb2u248", 8) == 0)
-               number = 4;
-       else
-               return -ENODEV;
-
-       /* Sorry for the brute-force locking, but this is only used during
-        * sleep and the timing seem to be critical
-        */
-       LOCK(flags);
-       if (value) {
-               /* Turn ON */
-               if (number == 0) {
-                       MACIO_BIC(KEYLARGO_FCR0, (KL0_USB0_PAD_SUSPEND0 | KL0_USB0_PAD_SUSPEND1));
-                       (void)MACIO_IN32(KEYLARGO_FCR0);
-                       UNLOCK(flags);
-                       mdelay(1);
-                       LOCK(flags);
-                       MACIO_BIS(KEYLARGO_FCR0, KL0_USB0_CELL_ENABLE);
-               } else if (number == 2) {
-                       MACIO_BIC(KEYLARGO_FCR0, (KL0_USB1_PAD_SUSPEND0 | KL0_USB1_PAD_SUSPEND1));
-                       UNLOCK(flags);
-                       (void)MACIO_IN32(KEYLARGO_FCR0);
-                       mdelay(1);
-                       LOCK(flags);
-                       MACIO_BIS(KEYLARGO_FCR0, KL0_USB1_CELL_ENABLE);
-               } else if (number == 4) {
-                       MACIO_BIC(KEYLARGO_FCR1, (KL1_USB2_PAD_SUSPEND0 | KL1_USB2_PAD_SUSPEND1));
-                       UNLOCK(flags);
-                       (void)MACIO_IN32(KEYLARGO_FCR1);
-                       mdelay(1);
-                       LOCK(flags);
-                       MACIO_BIS(KEYLARGO_FCR1, KL1_USB2_CELL_ENABLE);
-               }
-               if (number < 4) {
-                       reg = MACIO_IN32(KEYLARGO_FCR4);
-                       reg &=  ~(KL4_PORT_WAKEUP_ENABLE(number) | KL4_PORT_RESUME_WAKE_EN(number) |
-                               KL4_PORT_CONNECT_WAKE_EN(number) | KL4_PORT_DISCONNECT_WAKE_EN(number));
-                       reg &=  ~(KL4_PORT_WAKEUP_ENABLE(number+1) | KL4_PORT_RESUME_WAKE_EN(number+1) |
-                               KL4_PORT_CONNECT_WAKE_EN(number+1) | KL4_PORT_DISCONNECT_WAKE_EN(number+1));
-                       MACIO_OUT32(KEYLARGO_FCR4, reg);
-                       (void)MACIO_IN32(KEYLARGO_FCR4);
-                       udelay(10);
-               } else {
-                       reg = MACIO_IN32(KEYLARGO_FCR3);
-                       reg &=  ~(KL3_IT_PORT_WAKEUP_ENABLE(0) | KL3_IT_PORT_RESUME_WAKE_EN(0) |
-                               KL3_IT_PORT_CONNECT_WAKE_EN(0) | KL3_IT_PORT_DISCONNECT_WAKE_EN(0));
-                       reg &=  ~(KL3_IT_PORT_WAKEUP_ENABLE(1) | KL3_IT_PORT_RESUME_WAKE_EN(1) |
-                               KL3_IT_PORT_CONNECT_WAKE_EN(1) | KL3_IT_PORT_DISCONNECT_WAKE_EN(1));
-                       MACIO_OUT32(KEYLARGO_FCR3, reg);
-                       (void)MACIO_IN32(KEYLARGO_FCR3);
-                       udelay(10);
-               }
-               if (macio->type == macio_intrepid) {
-                       /* wait for clock stopped bits to clear */
-                       u32 test0 = 0, test1 = 0;
-                       u32 status0, status1;
-                       int timeout = 1000;
-
-                       UNLOCK(flags);
-                       switch (number) {
-                       case 0:
-                               test0 = UNI_N_CLOCK_STOPPED_USB0;
-                               test1 = UNI_N_CLOCK_STOPPED_USB0PCI;
-                               break;
-                       case 2:
-                               test0 = UNI_N_CLOCK_STOPPED_USB1;
-                               test1 = UNI_N_CLOCK_STOPPED_USB1PCI;
-                               break;
-                       case 4:
-                               test0 = UNI_N_CLOCK_STOPPED_USB2;
-                               test1 = UNI_N_CLOCK_STOPPED_USB2PCI;
-                               break;
-                       }
-                       do {
-                               if (--timeout <= 0) {
-                                       printk(KERN_ERR "core99_usb_enable: "
-                                              "Timeout waiting for clocks\n");
-                                       break;
-                               }
-                               mdelay(1);
-                               status0 = UN_IN(UNI_N_CLOCK_STOP_STATUS0);
-                               status1 = UN_IN(UNI_N_CLOCK_STOP_STATUS1);
-                       } while ((status0 & test0) | (status1 & test1));
-                       LOCK(flags);
-               }
-       } else {
-               /* Turn OFF */
-               if (number < 4) {
-                       reg = MACIO_IN32(KEYLARGO_FCR4);
-                       reg |=  KL4_PORT_WAKEUP_ENABLE(number) | KL4_PORT_RESUME_WAKE_EN(number) |
-                               KL4_PORT_CONNECT_WAKE_EN(number) | KL4_PORT_DISCONNECT_WAKE_EN(number);
-                       reg |=  KL4_PORT_WAKEUP_ENABLE(number+1) | KL4_PORT_RESUME_WAKE_EN(number+1) |
-                               KL4_PORT_CONNECT_WAKE_EN(number+1) | KL4_PORT_DISCONNECT_WAKE_EN(number+1);
-                       MACIO_OUT32(KEYLARGO_FCR4, reg);
-                       (void)MACIO_IN32(KEYLARGO_FCR4);
-                       udelay(1);
-               } else {
-                       reg = MACIO_IN32(KEYLARGO_FCR3);
-                       reg |=  KL3_IT_PORT_WAKEUP_ENABLE(0) | KL3_IT_PORT_RESUME_WAKE_EN(0) |
-                               KL3_IT_PORT_CONNECT_WAKE_EN(0) | KL3_IT_PORT_DISCONNECT_WAKE_EN(0);
-                       reg |=  KL3_IT_PORT_WAKEUP_ENABLE(1) | KL3_IT_PORT_RESUME_WAKE_EN(1) |
-                               KL3_IT_PORT_CONNECT_WAKE_EN(1) | KL3_IT_PORT_DISCONNECT_WAKE_EN(1);
-                       MACIO_OUT32(KEYLARGO_FCR3, reg);
-                       (void)MACIO_IN32(KEYLARGO_FCR3);
-                       udelay(1);
-               }
-               if (number == 0) {
-                       if (macio->type != macio_intrepid)
-                               MACIO_BIC(KEYLARGO_FCR0, KL0_USB0_CELL_ENABLE);
-                       (void)MACIO_IN32(KEYLARGO_FCR0);
-                       udelay(1);
-                       MACIO_BIS(KEYLARGO_FCR0, (KL0_USB0_PAD_SUSPEND0 | KL0_USB0_PAD_SUSPEND1));
-                       (void)MACIO_IN32(KEYLARGO_FCR0);
-               } else if (number == 2) {
-                       if (macio->type != macio_intrepid)
-                               MACIO_BIC(KEYLARGO_FCR0, KL0_USB1_CELL_ENABLE);
-                       (void)MACIO_IN32(KEYLARGO_FCR0);
-                       udelay(1);
-                       MACIO_BIS(KEYLARGO_FCR0, (KL0_USB1_PAD_SUSPEND0 | KL0_USB1_PAD_SUSPEND1));
-                       (void)MACIO_IN32(KEYLARGO_FCR0);
-               } else if (number == 4) {
-                       udelay(1);
-                       MACIO_BIS(KEYLARGO_FCR1, (KL1_USB2_PAD_SUSPEND0 | KL1_USB2_PAD_SUSPEND1));
-                       (void)MACIO_IN32(KEYLARGO_FCR1);
-               }
-               udelay(1);
-       }
-       UNLOCK(flags);
-
-       return 0;
-}
-
-static long
-core99_firewire_enable(struct device_node *node, long param, long value)
-{
-       unsigned long flags;
-       struct macio_chip *macio;
-
-       macio = &macio_chips[0];
-       if (macio->type != macio_keylargo && macio->type != macio_pangea &&
-           macio->type != macio_intrepid)
-               return -ENODEV;
-       if (!(macio->flags & MACIO_FLAG_FW_SUPPORTED))
-               return -ENODEV;
-
-       LOCK(flags);
-       if (value) {
-               UN_BIS(UNI_N_CLOCK_CNTL, UNI_N_CLOCK_CNTL_FW);
-               (void)UN_IN(UNI_N_CLOCK_CNTL);
-       } else {
-               UN_BIC(UNI_N_CLOCK_CNTL, UNI_N_CLOCK_CNTL_FW);
-               (void)UN_IN(UNI_N_CLOCK_CNTL);
-       }
-       UNLOCK(flags);
-       mdelay(1);
-
-       return 0;
-}
-
-static long
-core99_firewire_cable_power(struct device_node *node, long param, long value)
-{
-       unsigned long flags;
-       struct macio_chip *macio;
-
-       /* Trick: we allow NULL node */
-       if ((pmac_mb.board_flags & PMAC_MB_HAS_FW_POWER) == 0)
-               return -ENODEV;
-       macio = &macio_chips[0];
-       if (macio->type != macio_keylargo && macio->type != macio_pangea &&
-           macio->type != macio_intrepid)
-               return -ENODEV;
-       if (!(macio->flags & MACIO_FLAG_FW_SUPPORTED))
-               return -ENODEV;
-
-       LOCK(flags);
-       if (value) {
-               MACIO_OUT8(KL_GPIO_FW_CABLE_POWER , 0);
-               MACIO_IN8(KL_GPIO_FW_CABLE_POWER);
-               udelay(10);
-       } else {
-               MACIO_OUT8(KL_GPIO_FW_CABLE_POWER , 4);
-               MACIO_IN8(KL_GPIO_FW_CABLE_POWER); udelay(10);
-       }
-       UNLOCK(flags);
-       mdelay(1);
-
-       return 0;
-}
-
-static long
-intrepid_aack_delay_enable(struct device_node *node, long param, long value)
-{
-       unsigned long flags;
-
-       if (uninorth_rev < 0xd2)
-               return -ENODEV;
-
-       LOCK(flags);
-       if (param)
-               UN_BIS(UNI_N_AACK_DELAY, UNI_N_AACK_DELAY_ENABLE);
-       else
-               UN_BIC(UNI_N_AACK_DELAY, UNI_N_AACK_DELAY_ENABLE);
-       UNLOCK(flags);
-
-       return 0;
-}
-
-
-#endif /* CONFIG_POWER4 */
-
-static long
-core99_read_gpio(struct device_node *node, long param, long value)
-{
-       struct macio_chip *macio = &macio_chips[0];
-
-       return MACIO_IN8(param);
-}
-
-
-static long
-core99_write_gpio(struct device_node *node, long param, long value)
-{
-       struct macio_chip *macio = &macio_chips[0];
-
-       MACIO_OUT8(param, (u8)(value & 0xff));
-       return 0;
-}
-
-#ifdef CONFIG_POWER4
-static long g5_gmac_enable(struct device_node *node, long param, long value)
-{
-       struct macio_chip *macio = &macio_chips[0];
-       unsigned long flags;
-
-       if (node == NULL)
-               return -ENODEV;
-
-       LOCK(flags);
-       if (value) {
-               MACIO_BIS(KEYLARGO_FCR1, K2_FCR1_GMAC_CLK_ENABLE);
-               mb();
-               k2_skiplist[0] = NULL;
-       } else {
-               k2_skiplist[0] = node;
-               mb();
-               MACIO_BIC(KEYLARGO_FCR1, K2_FCR1_GMAC_CLK_ENABLE);
-       }
-       
-       UNLOCK(flags);
-       mdelay(1);
-
-       return 0;
-}
-
-static long g5_fw_enable(struct device_node *node, long param, long value)
-{
-       struct macio_chip *macio = &macio_chips[0];
-       unsigned long flags;
-
-       if (node == NULL)
-               return -ENODEV;
-
-       LOCK(flags);
-       if (value) {
-               MACIO_BIS(KEYLARGO_FCR1, K2_FCR1_FW_CLK_ENABLE);
-               mb();
-               k2_skiplist[1] = NULL;
-       } else {
-               k2_skiplist[1] = node;
-               mb();
-               MACIO_BIC(KEYLARGO_FCR1, K2_FCR1_FW_CLK_ENABLE);
-       }
-       
-       UNLOCK(flags);
-       mdelay(1);
-
-       return 0;
-}
-
-static long g5_mpic_enable(struct device_node *node, long param, long value)
-{
-       unsigned long flags;
-
-       if (node->parent == NULL || strcmp(node->parent->name, "u3"))
-               return 0;
-
-       LOCK(flags);
-       UN_BIS(U3_TOGGLE_REG, U3_MPIC_RESET | U3_MPIC_OUTPUT_ENABLE);
-       UNLOCK(flags);
-
-       return 0;
-}
-
-static long g5_eth_phy_reset(struct device_node *node, long param, long value)
-{
-       struct macio_chip *macio = &macio_chips[0];
-       struct device_node *phy;
-       int need_reset;
-
-       /*
-        * We must not reset the combo PHYs, only the BCM5221 found in
-        * the iMac G5.
-        */
-       phy = of_get_next_child(node, NULL);
-       if (!phy)
-               return -ENODEV;
-       need_reset = device_is_compatible(phy, "B5221");
-       of_node_put(phy);
-       if (!need_reset)
-               return 0;
-
-       /* PHY reset is GPIO 29, not in device-tree unfortunately */
-       MACIO_OUT8(K2_GPIO_EXTINT_0 + 29,
-                  KEYLARGO_GPIO_OUTPUT_ENABLE | KEYLARGO_GPIO_OUTOUT_DATA);
-       /* Thankfully, this is now always called at a time when we can
-        * schedule by sungem.
-        */
-       msleep(10);
-       MACIO_OUT8(K2_GPIO_EXTINT_0 + 29, 0);
-
-       return 0;
-}
-
-static long g5_i2s_enable(struct device_node *node, long param, long value)
-{
-       /* Very crude implementation for now */
-       struct macio_chip *macio = &macio_chips[0];
-       unsigned long flags;
-
-       if (value == 0)
-               return 0; /* don't disable yet */
-
-       LOCK(flags);
-       MACIO_BIS(KEYLARGO_FCR3, KL3_CLK45_ENABLE | KL3_CLK49_ENABLE |
-                 KL3_I2S0_CLK18_ENABLE);
-       udelay(10);
-       MACIO_BIS(KEYLARGO_FCR1, K2_FCR1_I2S0_CELL_ENABLE |
-                 K2_FCR1_I2S0_CLK_ENABLE_BIT | K2_FCR1_I2S0_ENABLE);
-       udelay(10);
-       MACIO_BIC(KEYLARGO_FCR1, K2_FCR1_I2S0_RESET);
-       UNLOCK(flags);
-       udelay(10);
-
-       return 0;
-}
-
-
-#ifdef CONFIG_SMP
-static long g5_reset_cpu(struct device_node *node, long param, long value)
-{
-       unsigned int reset_io = 0;
-       unsigned long flags;
-       struct macio_chip *macio;
-       struct device_node *np;
-
-       macio = &macio_chips[0];
-       if (macio->type != macio_keylargo2)
-               return -ENODEV;
-
-       np = find_path_device("/cpus");
-       if (np == NULL)
-               return -ENODEV;
-       for (np = np->child; np != NULL; np = np->sibling) {
-               u32 *num = (u32 *)get_property(np, "reg", NULL);
-               u32 *rst = (u32 *)get_property(np, "soft-reset", NULL);
-               if (num == NULL || rst == NULL)
-                       continue;
-               if (param == *num) {
-                       reset_io = *rst;
-                       break;
-               }
-       }
-       if (np == NULL || reset_io == 0)
-               return -ENODEV;
-
-       LOCK(flags);
-       MACIO_OUT8(reset_io, KEYLARGO_GPIO_OUTPUT_ENABLE);
-       (void)MACIO_IN8(reset_io);
-       udelay(1);
-       MACIO_OUT8(reset_io, 0);
-       (void)MACIO_IN8(reset_io);
-       UNLOCK(flags);
-
-       return 0;
-}
-#endif /* CONFIG_SMP */
-
-/*
- * This can be called from pmac_smp so isn't static
- *
- * This takes the second CPU off the bus on dual CPU machines
- * running UP
- */
-void g5_phy_disable_cpu1(void)
-{
-       UN_OUT(U3_API_PHY_CONFIG_1, 0);
-}
-#endif /* CONFIG_POWER4 */
-
-#ifndef CONFIG_POWER4
-
-static void
-keylargo_shutdown(struct macio_chip *macio, int sleep_mode)
-{
-       u32 temp;
-
-       if (sleep_mode) {
-               mdelay(1);
-               MACIO_BIS(KEYLARGO_FCR0, KL0_USB_REF_SUSPEND);
-               (void)MACIO_IN32(KEYLARGO_FCR0);
-               mdelay(1);
-       }
-
-       MACIO_BIC(KEYLARGO_FCR0,KL0_SCCA_ENABLE | KL0_SCCB_ENABLE |
-                               KL0_SCC_CELL_ENABLE |
-                               KL0_IRDA_ENABLE | KL0_IRDA_CLK32_ENABLE |
-                               KL0_IRDA_CLK19_ENABLE);
-
-       MACIO_BIC(KEYLARGO_MBCR, KL_MBCR_MB0_DEV_MASK);
-       MACIO_BIS(KEYLARGO_MBCR, KL_MBCR_MB0_IDE_ENABLE);
-
-       MACIO_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);
-
-       MACIO_BIS(KEYLARGO_FCR2, KL2_ALT_DATA_OUT);
-       MACIO_BIC(KEYLARGO_FCR2, KL2_IOBUS_ENABLE);
-
-       temp = MACIO_IN32(KEYLARGO_FCR3);
-       if (macio->rev >= 2) {
-               temp |= KL3_SHUTDOWN_PLL2X;
-               if (sleep_mode)
-                       temp |= KL3_SHUTDOWN_PLL_TOTAL;
-       }
-
-       temp |= KL3_SHUTDOWN_PLLKW6 | KL3_SHUTDOWN_PLLKW4 |
-               KL3_SHUTDOWN_PLLKW35;
-       if (sleep_mode)
-               temp |= KL3_SHUTDOWN_PLLKW12;
-       temp &= ~(KL3_CLK66_ENABLE | KL3_CLK49_ENABLE | KL3_CLK45_ENABLE
-               | KL3_CLK31_ENABLE | KL3_I2S1_CLK18_ENABLE | KL3_I2S0_CLK18_ENABLE);
-       if (sleep_mode)
-               temp &= ~(KL3_TIMER_CLK18_ENABLE | KL3_VIA_CLK16_ENABLE);
-       MACIO_OUT32(KEYLARGO_FCR3, temp);
-
-       /* Flush posted writes & wait a bit */
-       (void)MACIO_IN32(KEYLARGO_FCR0); mdelay(1);
-}
-
-static void
-pangea_shutdown(struct macio_chip *macio, int sleep_mode)
-{
-       u32 temp;
-
-       MACIO_BIC(KEYLARGO_FCR0,KL0_SCCA_ENABLE | KL0_SCCB_ENABLE |
-                               KL0_SCC_CELL_ENABLE |
-                               KL0_USB0_CELL_ENABLE | KL0_USB1_CELL_ENABLE);
-
-       MACIO_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_UIDE_ENABLE);
-       if (pmac_mb.board_flags & PMAC_MB_MOBILE)
-               MACIO_BIC(KEYLARGO_FCR1, KL1_UIDE_RESET_N);
-
-       MACIO_BIS(KEYLARGO_FCR2, KL2_ALT_DATA_OUT);
-
-       temp = MACIO_IN32(KEYLARGO_FCR3);
-       temp |= KL3_SHUTDOWN_PLLKW6 | KL3_SHUTDOWN_PLLKW4 |
-               KL3_SHUTDOWN_PLLKW35;
-       temp &= ~(KL3_CLK49_ENABLE | KL3_CLK45_ENABLE | KL3_CLK31_ENABLE
-               | KL3_I2S0_CLK18_ENABLE | KL3_I2S1_CLK18_ENABLE);
-       if (sleep_mode)
-               temp &= ~(KL3_VIA_CLK16_ENABLE | KL3_TIMER_CLK18_ENABLE);
-       MACIO_OUT32(KEYLARGO_FCR3, temp);
-
-       /* Flush posted writes & wait a bit */
-       (void)MACIO_IN32(KEYLARGO_FCR0); mdelay(1);
-}
-
-static void
-intrepid_shutdown(struct macio_chip *macio, int sleep_mode)
-{
-       u32 temp;
-
-       MACIO_BIC(KEYLARGO_FCR0,KL0_SCCA_ENABLE | KL0_SCCB_ENABLE |
-                 KL0_SCC_CELL_ENABLE);
-
-       MACIO_BIC(KEYLARGO_FCR1,
-                 /*KL1_USB2_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);
-       if (pmac_mb.board_flags & PMAC_MB_MOBILE)
-               MACIO_BIC(KEYLARGO_FCR1, KL1_UIDE_RESET_N);
-
-       temp = MACIO_IN32(KEYLARGO_FCR3);
-       temp &= ~(KL3_CLK49_ENABLE | KL3_CLK45_ENABLE |
-                 KL3_I2S1_CLK18_ENABLE | KL3_I2S0_CLK18_ENABLE);
-       if (sleep_mode)
-               temp &= ~(KL3_TIMER_CLK18_ENABLE | KL3_IT_VIA_CLK32_ENABLE);
-       MACIO_OUT32(KEYLARGO_FCR3, temp);
-
-       /* Flush posted writes & wait a bit */
-       (void)MACIO_IN32(KEYLARGO_FCR0);
-       mdelay(10);
-}
-
-
-void pmac_tweak_clock_spreading(int enable)
-{
-       struct macio_chip *macio = &macio_chips[0];
-
-       /* Hack for doing clock spreading on some machines PowerBooks and
-        * iBooks. This implements the "platform-do-clockspreading" OF
-        * property as decoded manually on various models. For safety, we also
-        * check the product ID in the device-tree in cases we'll whack the i2c
-        * chip to make reasonably sure we won't set wrong values in there
-        *
-        * Of course, ultimately, we have to implement a real parser for
-        * the platform-do-* stuff...
-        */
-
-       if (macio->type == macio_intrepid) {
-               if (enable)
-                       UN_OUT(UNI_N_CLOCK_SPREADING, 2);
-               else
-                       UN_OUT(UNI_N_CLOCK_SPREADING, 0);
-               mdelay(40);
-       }
-
-       while (machine_is_compatible("PowerBook5,2") ||
-              machine_is_compatible("PowerBook5,3") ||
-              machine_is_compatible("PowerBook6,2") ||
-              machine_is_compatible("PowerBook6,3")) {
-               struct device_node *ui2c = of_find_node_by_type(NULL, "i2c");
-               struct device_node *dt = of_find_node_by_name(NULL, "device-tree");
-               u8 buffer[9];
-               u32 *productID;
-               int i, rc, changed = 0;
-
-               if (dt == NULL)
-                       break;
-               productID = (u32 *)get_property(dt, "pid#", NULL);
-               if (productID == NULL)
-                       break;
-               while(ui2c) {
-                       struct device_node *p = of_get_parent(ui2c);
-                       if (p && !strcmp(p->name, "uni-n"))
-                               break;
-                       ui2c = of_find_node_by_type(ui2c, "i2c");
-               }
-               if (ui2c == NULL)
-                       break;
-               DBG("Trying to bump clock speed for PID: %08x...\n", *productID);
-               rc = pmac_low_i2c_open(ui2c, 1);
-               if (rc != 0)
-                       break;
-               pmac_low_i2c_setmode(ui2c, pmac_low_i2c_mode_combined);
-               rc = pmac_low_i2c_xfer(ui2c, 0xd2 | pmac_low_i2c_read, 0x80, buffer, 9);
-               DBG("read result: %d,", rc);
-               if (rc != 0) {
-                       pmac_low_i2c_close(ui2c);
-                       break;
-               }
-               for (i=0; i<9; i++)
-                       DBG(" %02x", buffer[i]);
-               DBG("\n");
-
-               switch(*productID) {
-               case 0x1182:    /* AlBook 12" rev 2 */
-               case 0x1183:    /* iBook G4 12" */
-                       buffer[0] = (buffer[0] & 0x8f) | 0x70;
-                       buffer[2] = (buffer[2] & 0x7f) | 0x00;
-                       buffer[5] = (buffer[5] & 0x80) | 0x31;
-                       buffer[6] = (buffer[6] & 0x40) | 0xb0;
-                       buffer[7] = (buffer[7] & 0x00) | (enable ? 0xc0 : 0xba);
-                       buffer[8] = (buffer[8] & 0x00) | 0x30;
-                       changed = 1;
-                       break;
-               case 0x3142:    /* AlBook 15" (ATI M10) */
-               case 0x3143:    /* AlBook 17" (ATI M10) */
-                       buffer[0] = (buffer[0] & 0xaf) | 0x50;
-                       buffer[2] = (buffer[2] & 0x7f) | 0x00;
-                       buffer[5] = (buffer[5] & 0x80) | 0x31;
-                       buffer[6] = (buffer[6] & 0x40) | 0xb0;
-                       buffer[7] = (buffer[7] & 0x00) | (enable ? 0xd0 : 0xc0);
-                       buffer[8] = (buffer[8] & 0x00) | 0x30;
-                       changed = 1;
-                       break;
-               default:
-                       DBG("i2c-hwclock: Machine model not handled\n");
-                       break;
-               }
-               if (!changed) {
-                       pmac_low_i2c_close(ui2c);
-                       break;
-               }
-               pmac_low_i2c_setmode(ui2c, pmac_low_i2c_mode_stdsub);
-               rc = pmac_low_i2c_xfer(ui2c, 0xd2 | pmac_low_i2c_write, 0x80, buffer, 9);
-               DBG("write result: %d,", rc);
-               pmac_low_i2c_setmode(ui2c, pmac_low_i2c_mode_combined);
-               rc = pmac_low_i2c_xfer(ui2c, 0xd2 | pmac_low_i2c_read, 0x80, buffer, 9);
-               DBG("read result: %d,", rc);
-               if (rc != 0) {
-                       pmac_low_i2c_close(ui2c);
-                       break;
-               }
-               for (i=0; i<9; i++)
-                       DBG(" %02x", buffer[i]);
-               pmac_low_i2c_close(ui2c);
-               break;
-       }
-}
-
-
-static int
-core99_sleep(void)
-{
-       struct macio_chip *macio;
-       int i;
-
-       macio = &macio_chips[0];
-       if (macio->type != macio_keylargo && macio->type != macio_pangea &&
-           macio->type != macio_intrepid)
-               return -ENODEV;
-
-       /* We power off the wireless slot in case it was not done
-        * by the driver. We don't power it on automatically however
-        */
-       if (macio->flags & MACIO_FLAG_AIRPORT_ON)
-               core99_airport_enable(macio->of_node, 0, 0);
-
-       /* We power off the FW cable. Should be done by the driver... */
-       if (macio->flags & MACIO_FLAG_FW_SUPPORTED) {
-               core99_firewire_enable(NULL, 0, 0);
-               core99_firewire_cable_power(NULL, 0, 0);
-       }
-
-       /* We make sure int. modem is off (in case driver lost it) */
-       if (macio->type == macio_keylargo)
-               core99_modem_enable(macio->of_node, 0, 0);
-       else
-               pangea_modem_enable(macio->of_node, 0, 0);
-
-       /* We make sure the sound is off as well */
-       core99_sound_chip_enable(macio->of_node, 0, 0);
-
-       /*
-        * Save various bits of KeyLargo
-        */
-
-       /* Save the state of the various GPIOs */
-       save_gpio_levels[0] = MACIO_IN32(KEYLARGO_GPIO_LEVELS0);
-       save_gpio_levels[1] = MACIO_IN32(KEYLARGO_GPIO_LEVELS1);
-       for (i=0; i<KEYLARGO_GPIO_EXTINT_CNT; i++)
-               save_gpio_extint[i] = MACIO_IN8(KEYLARGO_GPIO_EXTINT_0+i);
-       for (i=0; i<KEYLARGO_GPIO_CNT; i++)
-               save_gpio_normal[i] = MACIO_IN8(KEYLARGO_GPIO_0+i);
-
-       /* Save the FCRs */
-       if (macio->type == macio_keylargo)
-               save_mbcr = MACIO_IN32(KEYLARGO_MBCR);
-       save_fcr[0] = MACIO_IN32(KEYLARGO_FCR0);
-       save_fcr[1] = MACIO_IN32(KEYLARGO_FCR1);
-       save_fcr[2] = MACIO_IN32(KEYLARGO_FCR2);
-       save_fcr[3] = MACIO_IN32(KEYLARGO_FCR3);
-       save_fcr[4] = MACIO_IN32(KEYLARGO_FCR4);
-       if (macio->type == macio_pangea || macio->type == macio_intrepid)
-               save_fcr[5] = MACIO_IN32(KEYLARGO_FCR5);
-
-       /* Save state & config of DBDMA channels */
-       dbdma_save(macio, save_dbdma);
-
-       /*
-        * Turn off as much as we can
-        */
-       if (macio->type == macio_pangea)
-               pangea_shutdown(macio, 1);
-       else if (macio->type == macio_intrepid)
-               intrepid_shutdown(macio, 1);
-       else if (macio->type == macio_keylargo)
-               keylargo_shutdown(macio, 1);
-
-       /*
-        * Put the host bridge to sleep
-        */
-
-       save_unin_clock_ctl = UN_IN(UNI_N_CLOCK_CNTL);
-       /* Note: do not switch GMAC off, driver does it when necessary, WOL must keep it
-        * enabled !
-        */
-       UN_OUT(UNI_N_CLOCK_CNTL, save_unin_clock_ctl &
-              ~(/*UNI_N_CLOCK_CNTL_GMAC|*/UNI_N_CLOCK_CNTL_FW/*|UNI_N_CLOCK_CNTL_PCI*/));
-       udelay(100);
-       UN_OUT(UNI_N_HWINIT_STATE, UNI_N_HWINIT_STATE_SLEEPING);
-       UN_OUT(UNI_N_POWER_MGT, UNI_N_POWER_MGT_SLEEP);
-       mdelay(10);
-
-       /*
-        * FIXME: A bit of black magic with OpenPIC (don't ask me why)
-        */
-       if (pmac_mb.model_id == PMAC_TYPE_SAWTOOTH) {
-               MACIO_BIS(0x506e0, 0x00400000);
-               MACIO_BIS(0x506e0, 0x80000000);
-       }
-       return 0;
-}
-
-static int
-core99_wake_up(void)
-{
-       struct macio_chip *macio;
-       int i;
-
-       macio = &macio_chips[0];
-       if (macio->type != macio_keylargo && macio->type != macio_pangea &&
-           macio->type != macio_intrepid)
-               return -ENODEV;
-
-       /*
-        * Wakeup the host bridge
-        */
-       UN_OUT(UNI_N_POWER_MGT, UNI_N_POWER_MGT_NORMAL);
-       udelay(10);
-       UN_OUT(UNI_N_HWINIT_STATE, UNI_N_HWINIT_STATE_RUNNING);
-       udelay(10);
-
-       /*
-        * Restore KeyLargo
-        */
-
-       if (macio->type == macio_keylargo) {
-               MACIO_OUT32(KEYLARGO_MBCR, save_mbcr);
-               (void)MACIO_IN32(KEYLARGO_MBCR); udelay(10);
-       }
-       MACIO_OUT32(KEYLARGO_FCR0, save_fcr[0]);
-       (void)MACIO_IN32(KEYLARGO_FCR0); udelay(10);
-       MACIO_OUT32(KEYLARGO_FCR1, save_fcr[1]);
-       (void)MACIO_IN32(KEYLARGO_FCR1); udelay(10);
-       MACIO_OUT32(KEYLARGO_FCR2, save_fcr[2]);
-       (void)MACIO_IN32(KEYLARGO_FCR2); udelay(10);
-       MACIO_OUT32(KEYLARGO_FCR3, save_fcr[3]);
-       (void)MACIO_IN32(KEYLARGO_FCR3); udelay(10);
-       MACIO_OUT32(KEYLARGO_FCR4, save_fcr[4]);
-       (void)MACIO_IN32(KEYLARGO_FCR4); udelay(10);
-       if (macio->type == macio_pangea || macio->type == macio_intrepid) {
-               MACIO_OUT32(KEYLARGO_FCR5, save_fcr[5]);
-               (void)MACIO_IN32(KEYLARGO_FCR5); udelay(10);
-       }
-
-       dbdma_restore(macio, save_dbdma);
-
-       MACIO_OUT32(KEYLARGO_GPIO_LEVELS0, save_gpio_levels[0]);
-       MACIO_OUT32(KEYLARGO_GPIO_LEVELS1, save_gpio_levels[1]);
-       for (i=0; i<KEYLARGO_GPIO_EXTINT_CNT; i++)
-               MACIO_OUT8(KEYLARGO_GPIO_EXTINT_0+i, save_gpio_extint[i]);
-       for (i=0; i<KEYLARGO_GPIO_CNT; i++)
-               MACIO_OUT8(KEYLARGO_GPIO_0+i, save_gpio_normal[i]);
-
-       /* FIXME more black magic with OpenPIC ... */
-       if (pmac_mb.model_id == PMAC_TYPE_SAWTOOTH) {
-               MACIO_BIC(0x506e0, 0x00400000);
-               MACIO_BIC(0x506e0, 0x80000000);
-       }
-
-       UN_OUT(UNI_N_CLOCK_CNTL, save_unin_clock_ctl);
-       udelay(100);
-
-       return 0;
-}
-
-static long
-core99_sleep_state(struct device_node *node, long param, long value)
-{
-       /* Param == 1 means to enter the "fake sleep" mode that is
-        * used for CPU speed switch
-        */
-       if (param == 1) {
-               if (value == 1) {
-                       UN_OUT(UNI_N_HWINIT_STATE, UNI_N_HWINIT_STATE_SLEEPING);
-                       UN_OUT(UNI_N_POWER_MGT, UNI_N_POWER_MGT_IDLE2);
-               } else {
-                       UN_OUT(UNI_N_POWER_MGT, UNI_N_POWER_MGT_NORMAL);
-                       udelay(10);
-                       UN_OUT(UNI_N_HWINIT_STATE, UNI_N_HWINIT_STATE_RUNNING);
-                       udelay(10);
-               }
-               return 0;
-       }
-       if ((pmac_mb.board_flags & PMAC_MB_CAN_SLEEP) == 0)
-               return -EPERM;
-
-       if (value == 1)
-               return core99_sleep();
-       else if (value == 0)
-               return core99_wake_up();
-       return 0;
-}
-
-#endif /* CONFIG_POWER4 */
-
-static long
-generic_dev_can_wake(struct device_node *node, long param, long value)
-{
-       /* Todo: eventually check we are really dealing with on-board
-        * video device ...
-        */
-
-       if (pmac_mb.board_flags & PMAC_MB_MAY_SLEEP)
-               pmac_mb.board_flags |= PMAC_MB_CAN_SLEEP;
-       return 0;
-}
-
-static long generic_get_mb_info(struct device_node *node, long param, long value)
-{
-       switch(param) {
-               case PMAC_MB_INFO_MODEL:
-                       return pmac_mb.model_id;
-               case PMAC_MB_INFO_FLAGS:
-                       return pmac_mb.board_flags;
-               case PMAC_MB_INFO_NAME:
-                       /* hack hack hack... but should work */
-                       *((const char **)value) = pmac_mb.model_name;
-                       return 0;
-       }
-       return -EINVAL;
-}
-
-
-/*
- * Table definitions
- */
-
-/* Used on any machine
- */
-static struct feature_table_entry any_features[] = {
-       { PMAC_FTR_GET_MB_INFO,         generic_get_mb_info },
-       { PMAC_FTR_DEVICE_CAN_WAKE,     generic_dev_can_wake },
-       { 0, NULL }
-};
-
-#ifndef CONFIG_POWER4
-
-/* OHare based motherboards. Currently, we only use these on the
- * 2400,3400 and 3500 series powerbooks. Some older desktops seem
- * to have issues with turning on/off those asic cells
- */
-static struct feature_table_entry ohare_features[] = {
-       { PMAC_FTR_SCC_ENABLE,          ohare_htw_scc_enable },
-       { PMAC_FTR_SWIM3_ENABLE,        ohare_floppy_enable },
-       { PMAC_FTR_MESH_ENABLE,         ohare_mesh_enable },
-       { PMAC_FTR_IDE_ENABLE,          ohare_ide_enable},
-       { PMAC_FTR_IDE_RESET,           ohare_ide_reset},
-       { PMAC_FTR_SLEEP_STATE,         ohare_sleep_state },
-       { 0, NULL }
-};
-
-/* Heathrow desktop machines (Beige G3).
- * Separated as some features couldn't be properly tested
- * and the serial port control bits appear to confuse it.
- */
-static struct feature_table_entry heathrow_desktop_features[] = {
-       { PMAC_FTR_SWIM3_ENABLE,        heathrow_floppy_enable },
-       { PMAC_FTR_MESH_ENABLE,         heathrow_mesh_enable },
-       { PMAC_FTR_IDE_ENABLE,          heathrow_ide_enable },
-       { PMAC_FTR_IDE_RESET,           heathrow_ide_reset },
-       { PMAC_FTR_BMAC_ENABLE,         heathrow_bmac_enable },
-       { 0, NULL }
-};
-
-/* Heathrow based laptop, that is the Wallstreet and mainstreet
- * powerbooks.
- */
-static struct feature_table_entry heathrow_laptop_features[] = {
-       { PMAC_FTR_SCC_ENABLE,          ohare_htw_scc_enable },
-       { PMAC_FTR_MODEM_ENABLE,        heathrow_modem_enable },
-       { PMAC_FTR_SWIM3_ENABLE,        heathrow_floppy_enable },
-       { PMAC_FTR_MESH_ENABLE,         heathrow_mesh_enable },
-       { PMAC_FTR_IDE_ENABLE,          heathrow_ide_enable },
-       { PMAC_FTR_IDE_RESET,           heathrow_ide_reset },
-       { PMAC_FTR_BMAC_ENABLE,         heathrow_bmac_enable },
-       { PMAC_FTR_SOUND_CHIP_ENABLE,   heathrow_sound_enable },
-       { PMAC_FTR_SLEEP_STATE,         heathrow_sleep_state },
-       { 0, NULL }
-};
-
-/* Paddington based machines
- * The lombard (101) powerbook, first iMac models, B&W G3 and Yikes G4.
- */
-static struct feature_table_entry paddington_features[] = {
-       { PMAC_FTR_SCC_ENABLE,          ohare_htw_scc_enable },
-       { PMAC_FTR_MODEM_ENABLE,        heathrow_modem_enable },
-       { PMAC_FTR_SWIM3_ENABLE,        heathrow_floppy_enable },
-       { PMAC_FTR_MESH_ENABLE,         heathrow_mesh_enable },
-       { PMAC_FTR_IDE_ENABLE,          heathrow_ide_enable },
-       { PMAC_FTR_IDE_RESET,           heathrow_ide_reset },
-       { PMAC_FTR_BMAC_ENABLE,         heathrow_bmac_enable },
-       { PMAC_FTR_SOUND_CHIP_ENABLE,   heathrow_sound_enable },
-       { PMAC_FTR_SLEEP_STATE,         heathrow_sleep_state },
-       { 0, NULL }
-};
-
-/* Core99 & MacRISC 2 machines (all machines released since the
- * iBook (included), that is all AGP machines, except pangea
- * chipset. The pangea chipset is the "combo" UniNorth/KeyLargo
- * used on iBook2 & iMac "flow power".
- */
-static struct feature_table_entry core99_features[] = {
-       { PMAC_FTR_SCC_ENABLE,          core99_scc_enable },
-       { PMAC_FTR_MODEM_ENABLE,        core99_modem_enable },
-       { PMAC_FTR_IDE_ENABLE,          core99_ide_enable },
-       { PMAC_FTR_IDE_RESET,           core99_ide_reset },
-       { PMAC_FTR_GMAC_ENABLE,         core99_gmac_enable },
-       { PMAC_FTR_GMAC_PHY_RESET,      core99_gmac_phy_reset },
-       { PMAC_FTR_SOUND_CHIP_ENABLE,   core99_sound_chip_enable },
-       { PMAC_FTR_AIRPORT_ENABLE,      core99_airport_enable },
-       { PMAC_FTR_USB_ENABLE,          core99_usb_enable },
-       { PMAC_FTR_1394_ENABLE,         core99_firewire_enable },
-       { PMAC_FTR_1394_CABLE_POWER,    core99_firewire_cable_power },
-       { PMAC_FTR_SLEEP_STATE,         core99_sleep_state },
-#ifdef CONFIG_SMP
-       { PMAC_FTR_RESET_CPU,           core99_reset_cpu },
-#endif /* CONFIG_SMP */
-       { PMAC_FTR_READ_GPIO,           core99_read_gpio },
-       { PMAC_FTR_WRITE_GPIO,          core99_write_gpio },
-       { 0, NULL }
-};
-
-/* RackMac
- */
-static struct feature_table_entry rackmac_features[] = {
-       { PMAC_FTR_SCC_ENABLE,          core99_scc_enable },
-       { PMAC_FTR_IDE_ENABLE,          core99_ide_enable },
-       { PMAC_FTR_IDE_RESET,           core99_ide_reset },
-       { PMAC_FTR_GMAC_ENABLE,         core99_gmac_enable },
-       { PMAC_FTR_GMAC_PHY_RESET,      core99_gmac_phy_reset },
-       { PMAC_FTR_USB_ENABLE,          core99_usb_enable },
-       { PMAC_FTR_1394_ENABLE,         core99_firewire_enable },
-       { PMAC_FTR_1394_CABLE_POWER,    core99_firewire_cable_power },
-       { PMAC_FTR_SLEEP_STATE,         core99_sleep_state },
-#ifdef CONFIG_SMP
-       { PMAC_FTR_RESET_CPU,           core99_reset_cpu },
-#endif /* CONFIG_SMP */
-       { PMAC_FTR_READ_GPIO,           core99_read_gpio },
-       { PMAC_FTR_WRITE_GPIO,          core99_write_gpio },
-       { 0, NULL }
-};
-
-/* Pangea features
- */
-static struct feature_table_entry pangea_features[] = {
-       { PMAC_FTR_SCC_ENABLE,          core99_scc_enable },
-       { PMAC_FTR_MODEM_ENABLE,        pangea_modem_enable },
-       { PMAC_FTR_IDE_ENABLE,          core99_ide_enable },
-       { PMAC_FTR_IDE_RESET,           core99_ide_reset },
-       { PMAC_FTR_GMAC_ENABLE,         core99_gmac_enable },
-       { PMAC_FTR_GMAC_PHY_RESET,      core99_gmac_phy_reset },
-       { PMAC_FTR_SOUND_CHIP_ENABLE,   core99_sound_chip_enable },
-       { PMAC_FTR_AIRPORT_ENABLE,      core99_airport_enable },
-       { PMAC_FTR_USB_ENABLE,          core99_usb_enable },
-       { PMAC_FTR_1394_ENABLE,         core99_firewire_enable },
-       { PMAC_FTR_1394_CABLE_POWER,    core99_firewire_cable_power },
-       { PMAC_FTR_SLEEP_STATE,         core99_sleep_state },
-       { PMAC_FTR_READ_GPIO,           core99_read_gpio },
-       { PMAC_FTR_WRITE_GPIO,          core99_write_gpio },
-       { 0, NULL }
-};
-
-/* Intrepid features
- */
-static struct feature_table_entry intrepid_features[] = {
-       { PMAC_FTR_SCC_ENABLE,          core99_scc_enable },
-       { PMAC_FTR_MODEM_ENABLE,        pangea_modem_enable },
-       { PMAC_FTR_IDE_ENABLE,          core99_ide_enable },
-       { PMAC_FTR_IDE_RESET,           core99_ide_reset },
-       { PMAC_FTR_GMAC_ENABLE,         core99_gmac_enable },
-       { PMAC_FTR_GMAC_PHY_RESET,      core99_gmac_phy_reset },
-       { PMAC_FTR_SOUND_CHIP_ENABLE,   core99_sound_chip_enable },
-       { PMAC_FTR_AIRPORT_ENABLE,      core99_airport_enable },
-       { PMAC_FTR_USB_ENABLE,          core99_usb_enable },
-       { PMAC_FTR_1394_ENABLE,         core99_firewire_enable },
-       { PMAC_FTR_1394_CABLE_POWER,    core99_firewire_cable_power },
-       { PMAC_FTR_SLEEP_STATE,         core99_sleep_state },
-       { PMAC_FTR_READ_GPIO,           core99_read_gpio },
-       { PMAC_FTR_WRITE_GPIO,          core99_write_gpio },
-       { PMAC_FTR_AACK_DELAY_ENABLE,   intrepid_aack_delay_enable },
-       { 0, NULL }
-};
-
-#else /* CONFIG_POWER4 */
-
-/* G5 features
- */
-static struct feature_table_entry g5_features[] = {
-       { PMAC_FTR_GMAC_ENABLE,         g5_gmac_enable },
-       { PMAC_FTR_1394_ENABLE,         g5_fw_enable },
-       { PMAC_FTR_ENABLE_MPIC,         g5_mpic_enable },
-       { PMAC_FTR_GMAC_PHY_RESET,      g5_eth_phy_reset },
-       { PMAC_FTR_SOUND_CHIP_ENABLE,   g5_i2s_enable },
-#ifdef CONFIG_SMP
-       { PMAC_FTR_RESET_CPU,           g5_reset_cpu },
-#endif /* CONFIG_SMP */
-       { PMAC_FTR_READ_GPIO,           core99_read_gpio },
-       { PMAC_FTR_WRITE_GPIO,          core99_write_gpio },
-       { 0, NULL }
-};
-
-#endif /* CONFIG_POWER4 */
-
-static struct pmac_mb_def pmac_mb_defs[] = {
-#ifndef CONFIG_POWER4
-       /*
-        * Desktops
-        */
-
-       {       "AAPL,8500",                    "PowerMac 8500/8600",
-               PMAC_TYPE_PSURGE,               NULL,
-               0
-       },
-       {       "AAPL,9500",                    "PowerMac 9500/9600",
-               PMAC_TYPE_PSURGE,               NULL,
-               0
-       },
-       {       "AAPL,7200",                    "PowerMac 7200",
-               PMAC_TYPE_PSURGE,               NULL,
-               0
-       },
-       {       "AAPL,7300",                    "PowerMac 7200/7300",
-               PMAC_TYPE_PSURGE,               NULL,
-               0
-       },
-       {       "AAPL,7500",                    "PowerMac 7500",
-               PMAC_TYPE_PSURGE,               NULL,
-               0
-       },
-       {       "AAPL,ShinerESB",               "Apple Network Server",
-               PMAC_TYPE_ANS,                  NULL,
-               0
-       },
-       {       "AAPL,e407",                    "Alchemy",
-               PMAC_TYPE_ALCHEMY,              NULL,
-               0
-       },
-       {       "AAPL,e411",                    "Gazelle",
-               PMAC_TYPE_GAZELLE,              NULL,
-               0
-       },
-       {       "AAPL,Gossamer",                "PowerMac G3 (Gossamer)",
-               PMAC_TYPE_GOSSAMER,             heathrow_desktop_features,
-               0
-       },
-       {       "AAPL,PowerMac G3",             "PowerMac G3 (Silk)",
-               PMAC_TYPE_SILK,                 heathrow_desktop_features,
-               0
-       },
-       {       "PowerMac1,1",                  "Blue&White G3",
-               PMAC_TYPE_YOSEMITE,             paddington_features,
-               0
-       },
-       {       "PowerMac1,2",                  "PowerMac G4 PCI Graphics",
-               PMAC_TYPE_YIKES,                paddington_features,
-               0
-       },
-       {       "PowerMac2,1",                  "iMac FireWire",
-               PMAC_TYPE_FW_IMAC,              core99_features,
-               PMAC_MB_MAY_SLEEP | PMAC_MB_OLD_CORE99
-       },
-       {       "PowerMac2,2",                  "iMac FireWire",
-               PMAC_TYPE_FW_IMAC,              core99_features,
-               PMAC_MB_MAY_SLEEP | PMAC_MB_OLD_CORE99
-       },
-       {       "PowerMac3,1",                  "PowerMac G4 AGP Graphics",
-               PMAC_TYPE_SAWTOOTH,             core99_features,
-               PMAC_MB_OLD_CORE99
-       },
-       {       "PowerMac3,2",                  "PowerMac G4 AGP Graphics",
-               PMAC_TYPE_SAWTOOTH,             core99_features,
-               PMAC_MB_MAY_SLEEP | PMAC_MB_OLD_CORE99
-       },
-       {       "PowerMac3,3",                  "PowerMac G4 AGP Graphics",
-               PMAC_TYPE_SAWTOOTH,             core99_features,
-               PMAC_MB_MAY_SLEEP | PMAC_MB_OLD_CORE99
-       },
-       {       "PowerMac3,4",                  "PowerMac G4 Silver",
-               PMAC_TYPE_QUICKSILVER,          core99_features,
-               PMAC_MB_MAY_SLEEP
-       },
-       {       "PowerMac3,5",                  "PowerMac G4 Silver",
-               PMAC_TYPE_QUICKSILVER,          core99_features,
-               PMAC_MB_MAY_SLEEP
-       },
-       {       "PowerMac3,6",                  "PowerMac G4 Windtunnel",
-               PMAC_TYPE_WINDTUNNEL,           core99_features,
-               PMAC_MB_MAY_SLEEP,
-       },
-       {       "PowerMac4,1",                  "iMac \"Flower Power\"",
-               PMAC_TYPE_PANGEA_IMAC,          pangea_features,
-               PMAC_MB_MAY_SLEEP
-       },
-       {       "PowerMac4,2",                  "Flat panel iMac",
-               PMAC_TYPE_FLAT_PANEL_IMAC,      pangea_features,
-               PMAC_MB_CAN_SLEEP
-       },
-       {       "PowerMac4,4",                  "eMac",
-               PMAC_TYPE_EMAC,                 core99_features,
-               PMAC_MB_MAY_SLEEP
-       },
-       {       "PowerMac5,1",                  "PowerMac G4 Cube",
-               PMAC_TYPE_CUBE,                 core99_features,
-               PMAC_MB_MAY_SLEEP | PMAC_MB_OLD_CORE99
-       },
-       {       "PowerMac6,1",                  "Flat panel iMac",
-               PMAC_TYPE_UNKNOWN_INTREPID,     intrepid_features,
-               PMAC_MB_MAY_SLEEP,
-       },
-       {       "PowerMac6,3",                  "Flat panel iMac",
-               PMAC_TYPE_UNKNOWN_INTREPID,     intrepid_features,
-               PMAC_MB_MAY_SLEEP,
-       },
-       {       "PowerMac6,4",                  "eMac",
-               PMAC_TYPE_UNKNOWN_INTREPID,     intrepid_features,
-               PMAC_MB_MAY_SLEEP,
-       },
-       {       "PowerMac10,1",                 "Mac mini",
-               PMAC_TYPE_UNKNOWN_INTREPID,     intrepid_features,
-               PMAC_MB_MAY_SLEEP | PMAC_MB_HAS_FW_POWER,
-       },
-       {       "iMac,1",                       "iMac (first generation)",
-               PMAC_TYPE_ORIG_IMAC,            paddington_features,
-               0
-       },
-
-       /*
-        * Xserve's
-        */
-
-       {       "RackMac1,1",                   "XServe",
-               PMAC_TYPE_RACKMAC,              rackmac_features,
-               0,
-       },
-       {       "RackMac1,2",                   "XServe rev. 2",
-               PMAC_TYPE_RACKMAC,              rackmac_features,
-               0,
-       },
-
-       /*
-        * Laptops
-        */
-
-       {       "AAPL,3400/2400",               "PowerBook 3400",
-               PMAC_TYPE_HOOPER,               ohare_features,
-               PMAC_MB_CAN_SLEEP | PMAC_MB_MOBILE
-       },
-       {       "AAPL,3500",                    "PowerBook 3500",
-               PMAC_TYPE_KANGA,                ohare_features,
-               PMAC_MB_CAN_SLEEP | PMAC_MB_MOBILE
-       },
-       {       "AAPL,PowerBook1998",           "PowerBook Wallstreet",
-               PMAC_TYPE_WALLSTREET,           heathrow_laptop_features,
-               PMAC_MB_CAN_SLEEP | PMAC_MB_MOBILE
-       },
-       {       "PowerBook1,1",                 "PowerBook 101 (Lombard)",
-               PMAC_TYPE_101_PBOOK,            paddington_features,
-               PMAC_MB_CAN_SLEEP | PMAC_MB_MOBILE
-       },
-       {       "PowerBook2,1",                 "iBook (first generation)",
-               PMAC_TYPE_ORIG_IBOOK,           core99_features,
-               PMAC_MB_CAN_SLEEP | PMAC_MB_OLD_CORE99 | PMAC_MB_MOBILE
-       },
-       {       "PowerBook2,2",                 "iBook FireWire",
-               PMAC_TYPE_FW_IBOOK,             core99_features,
-               PMAC_MB_MAY_SLEEP | PMAC_MB_HAS_FW_POWER |
-               PMAC_MB_OLD_CORE99 | PMAC_MB_MOBILE
-       },
-       {       "PowerBook3,1",                 "PowerBook Pismo",
-               PMAC_TYPE_PISMO,                core99_features,
-               PMAC_MB_MAY_SLEEP | PMAC_MB_HAS_FW_POWER |
-               PMAC_MB_OLD_CORE99 | PMAC_MB_MOBILE
-       },
-       {       "PowerBook3,2",                 "PowerBook Titanium",
-               PMAC_TYPE_TITANIUM,             core99_features,
-               PMAC_MB_MAY_SLEEP | PMAC_MB_HAS_FW_POWER | PMAC_MB_MOBILE
-       },
-       {       "PowerBook3,3",                 "PowerBook Titanium II",
-               PMAC_TYPE_TITANIUM2,            core99_features,
-               PMAC_MB_MAY_SLEEP | PMAC_MB_HAS_FW_POWER | PMAC_MB_MOBILE
-       },
-       {       "PowerBook3,4",                 "PowerBook Titanium III",
-               PMAC_TYPE_TITANIUM3,            core99_features,
-               PMAC_MB_MAY_SLEEP | PMAC_MB_HAS_FW_POWER | PMAC_MB_MOBILE
-       },
-       {       "PowerBook3,5",                 "PowerBook Titanium IV",
-               PMAC_TYPE_TITANIUM4,            core99_features,
-               PMAC_MB_MAY_SLEEP | PMAC_MB_HAS_FW_POWER | PMAC_MB_MOBILE
-       },
-       {       "PowerBook4,1",                 "iBook 2",
-               PMAC_TYPE_IBOOK2,               pangea_features,
-               PMAC_MB_MAY_SLEEP | PMAC_MB_HAS_FW_POWER | PMAC_MB_MOBILE
-       },
-       {       "PowerBook4,2",                 "iBook 2",
-               PMAC_TYPE_IBOOK2,               pangea_features,
-               PMAC_MB_MAY_SLEEP | PMAC_MB_HAS_FW_POWER | PMAC_MB_MOBILE
-       },
-       {       "PowerBook4,3",                 "iBook 2 rev. 2",
-               PMAC_TYPE_IBOOK2,               pangea_features,
-               PMAC_MB_MAY_SLEEP | PMAC_MB_HAS_FW_POWER | PMAC_MB_MOBILE
-       },
-       {       "PowerBook5,1",                 "PowerBook G4 17\"",
-               PMAC_TYPE_UNKNOWN_INTREPID,     intrepid_features,
-               PMAC_MB_HAS_FW_POWER | PMAC_MB_MOBILE,
-       },
-       {       "PowerBook5,2",                 "PowerBook G4 15\"",
-               PMAC_TYPE_UNKNOWN_INTREPID,     intrepid_features,
-               PMAC_MB_MAY_SLEEP | PMAC_MB_HAS_FW_POWER | PMAC_MB_MOBILE,
-       },
-       {       "PowerBook5,3",                 "PowerBook G4 17\"",
-               PMAC_TYPE_UNKNOWN_INTREPID,     intrepid_features,
-               PMAC_MB_MAY_SLEEP | PMAC_MB_HAS_FW_POWER | PMAC_MB_MOBILE,
-       },
-       {       "PowerBook5,4",                 "PowerBook G4 15\"",
-               PMAC_TYPE_UNKNOWN_INTREPID,     intrepid_features,
-               PMAC_MB_MAY_SLEEP | PMAC_MB_HAS_FW_POWER | PMAC_MB_MOBILE,
-       },
-       {       "PowerBook5,5",                 "PowerBook G4 17\"",
-               PMAC_TYPE_UNKNOWN_INTREPID,     intrepid_features,
-               PMAC_MB_MAY_SLEEP | PMAC_MB_HAS_FW_POWER | PMAC_MB_MOBILE,
-       },
-       {       "PowerBook5,6",                 "PowerBook G4 15\"",
-               PMAC_TYPE_UNKNOWN_INTREPID,     intrepid_features,
-               PMAC_MB_MAY_SLEEP | PMAC_MB_HAS_FW_POWER | PMAC_MB_MOBILE,
-       },
-       {       "PowerBook5,7",                 "PowerBook G4 17\"",
-               PMAC_TYPE_UNKNOWN_INTREPID,     intrepid_features,
-               PMAC_MB_MAY_SLEEP | PMAC_MB_HAS_FW_POWER | PMAC_MB_MOBILE,
-       },
-       {       "PowerBook6,1",                 "PowerBook G4 12\"",
-               PMAC_TYPE_UNKNOWN_INTREPID,     intrepid_features,
-               PMAC_MB_MAY_SLEEP | PMAC_MB_HAS_FW_POWER | PMAC_MB_MOBILE,
-       },
-       {       "PowerBook6,2",                 "PowerBook G4",
-               PMAC_TYPE_UNKNOWN_INTREPID,     intrepid_features,
-               PMAC_MB_MAY_SLEEP | PMAC_MB_HAS_FW_POWER | PMAC_MB_MOBILE,
-       },
-       {       "PowerBook6,3",                 "iBook G4",
-               PMAC_TYPE_UNKNOWN_INTREPID,     intrepid_features,
-               PMAC_MB_MAY_SLEEP | PMAC_MB_HAS_FW_POWER | PMAC_MB_MOBILE,
-       },
-       {       "PowerBook6,4",                 "PowerBook G4 12\"",
-               PMAC_TYPE_UNKNOWN_INTREPID,     intrepid_features,
-               PMAC_MB_MAY_SLEEP | PMAC_MB_HAS_FW_POWER | PMAC_MB_MOBILE,
-       },
-       {       "PowerBook6,5",                 "iBook G4",
-               PMAC_TYPE_UNKNOWN_INTREPID,     intrepid_features,
-               PMAC_MB_MAY_SLEEP | PMAC_MB_HAS_FW_POWER | PMAC_MB_MOBILE,
-       },
-       {       "PowerBook6,8",                 "PowerBook G4 12\"",
-               PMAC_TYPE_UNKNOWN_INTREPID,     intrepid_features,
-               PMAC_MB_MAY_SLEEP | PMAC_MB_HAS_FW_POWER | PMAC_MB_MOBILE,
-       },
-#else /* CONFIG_POWER4 */
-       {       "PowerMac7,2",                  "PowerMac G5",
-               PMAC_TYPE_POWERMAC_G5,          g5_features,
-               0,
-       },
-#ifdef CONFIG_PPC64
-       {       "PowerMac7,3",                  "PowerMac G5",
-               PMAC_TYPE_POWERMAC_G5,          g5_features,
-               0,
-       },
-       {       "PowerMac8,1",                  "iMac G5",
-               PMAC_TYPE_IMAC_G5,              g5_features,
-               0,
-       },
-       {       "PowerMac9,1",                  "PowerMac G5",
-               PMAC_TYPE_POWERMAC_G5_U3L,      g5_features,
-               0,
-       },
-       {       "RackMac3,1",                   "XServe G5",
-               PMAC_TYPE_XSERVE_G5,            g5_features,
-               0,
-       },
-#endif /* CONFIG_PPC64 */
-#endif /* CONFIG_POWER4 */
-};
-
-/*
- * The toplevel feature_call callback
- */
-long pmac_do_feature_call(unsigned int selector, ...)
-{
-       struct device_node *node;
-       long param, value;
-       int i;
-       feature_call func = NULL;
-       va_list args;
-
-       if (pmac_mb.features)
-               for (i=0; pmac_mb.features[i].function; i++)
-                       if (pmac_mb.features[i].selector == selector) {
-                               func = pmac_mb.features[i].function;
-                               break;
-                       }
-       if (!func)
-               for (i=0; any_features[i].function; i++)
-                       if (any_features[i].selector == selector) {
-                               func = any_features[i].function;
-                               break;
-                       }
-       if (!func)
-               return -ENODEV;
-
-       va_start(args, selector);
-       node = (struct device_node*)va_arg(args, void*);
-       param = va_arg(args, long);
-       value = va_arg(args, long);
-       va_end(args);
-
-       return func(node, param, value);
-}
-
-static int __init probe_motherboard(void)
-{
-       int i;
-       struct macio_chip *macio = &macio_chips[0];
-       const char *model = NULL;
-       struct device_node *dt;
-
-       /* Lookup known motherboard type in device-tree. First try an
-        * exact match on the "model" property, then try a "compatible"
-        * match is none is found.
-        */
-       dt = find_devices("device-tree");
-       if (dt != NULL)
-               model = (const char *) get_property(dt, "model", NULL);
-       for(i=0; model && i<(sizeof(pmac_mb_defs)/sizeof(struct pmac_mb_def)); i++) {
-           if (strcmp(model, pmac_mb_defs[i].model_string) == 0) {
-               pmac_mb = pmac_mb_defs[i];
-               goto found;
-           }
-       }
-       for(i=0; i<(sizeof(pmac_mb_defs)/sizeof(struct pmac_mb_def)); i++) {
-           if (machine_is_compatible(pmac_mb_defs[i].model_string)) {
-               pmac_mb = pmac_mb_defs[i];
-               goto found;
-           }
-       }
-
-       /* Fallback to selection depending on mac-io chip type */
-       switch(macio->type) {
-#ifndef CONFIG_POWER4
-           case macio_grand_central:
-               pmac_mb.model_id = PMAC_TYPE_PSURGE;
-               pmac_mb.model_name = "Unknown PowerSurge";
-               break;
-           case macio_ohare:
-               pmac_mb.model_id = PMAC_TYPE_UNKNOWN_OHARE;
-               pmac_mb.model_name = "Unknown OHare-based";
-               break;
-           case macio_heathrow:
-               pmac_mb.model_id = PMAC_TYPE_UNKNOWN_HEATHROW;
-               pmac_mb.model_name = "Unknown Heathrow-based";
-               pmac_mb.features = heathrow_desktop_features;
-               break;
-           case macio_paddington:
-               pmac_mb.model_id = PMAC_TYPE_UNKNOWN_PADDINGTON;
-               pmac_mb.model_name = "Unknown Paddington-based";
-               pmac_mb.features = paddington_features;
-               break;
-           case macio_keylargo:
-               pmac_mb.model_id = PMAC_TYPE_UNKNOWN_CORE99;
-               pmac_mb.model_name = "Unknown Keylargo-based";
-               pmac_mb.features = core99_features;
-               break;
-           case macio_pangea:
-               pmac_mb.model_id = PMAC_TYPE_UNKNOWN_PANGEA;
-               pmac_mb.model_name = "Unknown Pangea-based";
-               pmac_mb.features = pangea_features;
-               break;
-           case macio_intrepid:
-               pmac_mb.model_id = PMAC_TYPE_UNKNOWN_INTREPID;
-               pmac_mb.model_name = "Unknown Intrepid-based";
-               pmac_mb.features = intrepid_features;
-               break;
-#else /* CONFIG_POWER4 */
-       case macio_keylargo2:
-               pmac_mb.model_id = PMAC_TYPE_UNKNOWN_K2;
-               pmac_mb.model_name = "Unknown K2-based";
-               pmac_mb.features = g5_features;
-               break;
-#endif /* CONFIG_POWER4 */
-       default:
-               return -ENODEV;
-       }
-found:
-#ifndef CONFIG_POWER4
-       /* Fixup Hooper vs. Comet */
-       if (pmac_mb.model_id == PMAC_TYPE_HOOPER) {
-               u32 __iomem * mach_id_ptr = ioremap(0xf3000034, 4);
-               if (!mach_id_ptr)
-                       return -ENODEV;
-               /* Here, I used to disable the media-bay on comet. It
-                * appears this is wrong, the floppy connector is actually
-                * a kind of media-bay and works with the current driver.
-                */
-               if (__raw_readl(mach_id_ptr) & 0x20000000UL)
-                       pmac_mb.model_id = PMAC_TYPE_COMET;
-               iounmap(mach_id_ptr);
-       }
-#endif /* CONFIG_POWER4 */
-
-#ifdef CONFIG_6xx
-       /* Set default value of powersave_nap on machines that support it.
-        * It appears that uninorth rev 3 has a problem with it, we don't
-        * enable it on those. In theory, the flush-on-lock property is
-        * supposed to be set when not supported, but I'm not very confident
-        * that all Apple OF revs did it properly, I do it the paranoid way.
-        */
-       while (uninorth_base && uninorth_rev > 3) {
-               struct device_node *np = find_path_device("/cpus");
-               if (!np || !np->child) {
-                       printk(KERN_WARNING "Can't find CPU(s) in device tree !\n");
-                       break;
-               }
-               np = np->child;
-               /* Nap mode not supported on SMP */
-               if (np->sibling)
-                       break;
-               /* Nap mode not supported if flush-on-lock property is present */
-               if (get_property(np, "flush-on-lock", NULL))
-                       break;
-               powersave_nap = 1;
-               printk(KERN_INFO "Processor NAP mode on idle enabled.\n");
-               break;
-       }
-
-       /* On CPUs that support it (750FX), lowspeed by default during
-        * NAP mode
-        */
-       powersave_lowspeed = 1;
-#endif /* CONFIG_6xx */
-#ifdef CONFIG_POWER4
-       powersave_nap = 1;
-#endif
-       /* Check for "mobile" machine */
-       if (model && (strncmp(model, "PowerBook", 9) == 0
-                  || strncmp(model, "iBook", 5) == 0))
-               pmac_mb.board_flags |= PMAC_MB_MOBILE;
-
-
-       printk(KERN_INFO "PowerMac motherboard: %s\n", pmac_mb.model_name);
-       return 0;
-}
-
-/* Initialize the Core99 UniNorth host bridge and memory controller
- */
-static void __init probe_uninorth(void)
-{
-       unsigned long actrl;
-
-       /* Locate core99 Uni-N */
-       uninorth_node = of_find_node_by_name(NULL, "uni-n");
-       /* Locate G5 u3 */
-       if (uninorth_node == NULL) {
-               uninorth_node = of_find_node_by_name(NULL, "u3");
-               uninorth_u3 = 1;
-       }
-       if (uninorth_node && uninorth_node->n_addrs > 0) {
-               unsigned long address = uninorth_node->addrs[0].address;
-               uninorth_base = ioremap(address, 0x40000);
-               uninorth_rev = in_be32(UN_REG(UNI_N_VERSION));
-               if (uninorth_u3)
-                       u3_ht = ioremap(address + U3_HT_CONFIG_BASE, 0x1000);
-       } else
-               uninorth_node = NULL;
-
-       if (!uninorth_node)
-               return;
-
-       printk(KERN_INFO "Found %s memory controller & host bridge, revision: %d\n",
-              uninorth_u3 ? "U3" : "UniNorth", uninorth_rev);
-       printk(KERN_INFO "Mapped at 0x%08lx\n", (unsigned long)uninorth_base);
-
-       /* Set the arbitrer QAck delay according to what Apple does
-        */
-       if (uninorth_rev < 0x11) {
-               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);
-       }
-
-       /* Some more magic as done by them in recent MacOS X on UniNorth
-        * revs 1.5 to 2.O and Pangea. Seem to toggle the UniN Maxbus/PCI
-        * memory timeout
-        */
-       if ((uninorth_rev >= 0x11 && uninorth_rev <= 0x24) || uninorth_rev == 0xc0)
-               UN_OUT(0x2160, UN_IN(0x2160) & 0x00ffffff);
-}
-
-static void __init probe_one_macio(const char *name, const char *compat, int type)
-{
-       struct device_node*     node;
-       int                     i;
-       volatile u32 __iomem *  base;
-       u32*                    revp;
-
-       node = find_devices(name);
-       if (!node || !node->n_addrs)
-               return;
-       if (compat)
-               do {
-                       if (device_is_compatible(node, compat))
-                               break;
-                       node = node->next;
-               } while (node);
-       if (!node)
-               return;
-       for(i=0; i<MAX_MACIO_CHIPS; i++) {
-               if (!macio_chips[i].of_node)
-                       break;
-               if (macio_chips[i].of_node == node)
-                       return;
-       }
-       if (i >= MAX_MACIO_CHIPS) {
-               printk(KERN_ERR "pmac_feature: Please increase MAX_MACIO_CHIPS !\n");
-               printk(KERN_ERR "pmac_feature: %s skipped\n", node->full_name);
-               return;
-       }
-       base = ioremap(node->addrs[0].address, node->addrs[0].size);
-       if (!base) {
-               printk(KERN_ERR "pmac_feature: Can't map mac-io chip !\n");
-               return;
-       }
-       if (type == macio_keylargo) {
-               u32 *did = (u32 *)get_property(node, "device-id", NULL);
-               if (*did == 0x00000025)
-                       type = macio_pangea;
-               if (*did == 0x0000003e)
-                       type = macio_intrepid;
-       }
-       macio_chips[i].of_node  = node;
-       macio_chips[i].type     = type;
-       macio_chips[i].base     = base;
-       macio_chips[i].flags    = MACIO_FLAG_SCCB_ON | MACIO_FLAG_SCCB_ON;
-       macio_chips[i].name     = macio_names[type];
-       revp = (u32 *)get_property(node, "revision-id", NULL);
-       if (revp)
-               macio_chips[i].rev = *revp;
-       printk(KERN_INFO "Found a %s mac-io controller, rev: %d, mapped at 0x%p\n",
-               macio_names[type], macio_chips[i].rev, macio_chips[i].base);
-}
-
-static int __init
-probe_macios(void)
-{
-       /* Warning, ordering is important */
-       probe_one_macio("gc", NULL, macio_grand_central);
-       probe_one_macio("ohare", NULL, macio_ohare);
-       probe_one_macio("pci106b,7", NULL, macio_ohareII);
-       probe_one_macio("mac-io", "keylargo", macio_keylargo);
-       probe_one_macio("mac-io", "paddington", macio_paddington);
-       probe_one_macio("mac-io", "gatwick", macio_gatwick);
-       probe_one_macio("mac-io", "heathrow", macio_heathrow);
-       probe_one_macio("mac-io", "K2-Keylargo", macio_keylargo2);
-
-       /* Make sure the "main" macio chip appear first */
-       if (macio_chips[0].type == macio_gatwick
-           && macio_chips[1].type == macio_heathrow) {
-               struct macio_chip temp = macio_chips[0];
-               macio_chips[0] = macio_chips[1];
-               macio_chips[1] = temp;
-       }
-       if (macio_chips[0].type == macio_ohareII
-           && macio_chips[1].type == macio_ohare) {
-               struct macio_chip temp = macio_chips[0];
-               macio_chips[0] = macio_chips[1];
-               macio_chips[1] = temp;
-       }
-       macio_chips[0].lbus.index = 0;
-       macio_chips[1].lbus.index = 1;
-
-       return (macio_chips[0].of_node == NULL) ? -ENODEV : 0;
-}
-
-static void __init
-initial_serial_shutdown(struct device_node *np)
-{
-       int len;
-       struct slot_names_prop {
-               int     count;
-               char    name[1];
-       } *slots;
-       char *conn;
-       int port_type = PMAC_SCC_ASYNC;
-       int modem = 0;
-
-       slots = (struct slot_names_prop *)get_property(np, "slot-names", &len);
-       conn = get_property(np, "AAPL,connector", &len);
-       if (conn && (strcmp(conn, "infrared") == 0))
-               port_type = PMAC_SCC_IRDA;
-       else if (device_is_compatible(np, "cobalt"))
-               modem = 1;
-       else if (slots && slots->count > 0) {
-               if (strcmp(slots->name, "IrDA") == 0)
-                       port_type = PMAC_SCC_IRDA;
-               else if (strcmp(slots->name, "Modem") == 0)
-                       modem = 1;
-       }
-       if (modem)
-               pmac_call_feature(PMAC_FTR_MODEM_ENABLE, np, 0, 0);
-       pmac_call_feature(PMAC_FTR_SCC_ENABLE, np, port_type, 0);
-}
-
-static void __init
-set_initial_features(void)
-{
-       struct device_node *np;
-
-       /* That hack appears to be necessary for some StarMax motherboards
-        * but I'm not too sure it was audited for side-effects on other
-        * ohare based machines...
-        * Since I still have difficulties figuring the right way to
-        * differenciate them all and since that hack was there for a long
-        * time, I'll keep it around
-        */
-       if (macio_chips[0].type == macio_ohare && !find_devices("via-pmu")) {
-               struct macio_chip *macio = &macio_chips[0];
-               MACIO_OUT32(OHARE_FCR, STARMAX_FEATURES);
-       } else if (macio_chips[0].type == macio_ohare) {
-               struct macio_chip *macio = &macio_chips[0];
-               MACIO_BIS(OHARE_FCR, OH_IOBUS_ENABLE);
-       } else if (macio_chips[1].type == macio_ohare) {
-               struct macio_chip *macio = &macio_chips[1];
-               MACIO_BIS(OHARE_FCR, OH_IOBUS_ENABLE);
-       }
-
-#ifdef CONFIG_POWER4
-       if (macio_chips[0].type == macio_keylargo2) {
-#ifndef CONFIG_SMP
-               /* On SMP machines running UP, we have the second CPU eating
-                * bus cycles. We need to take it off the bus. This is done
-                * from pmac_smp for SMP kernels running on one CPU
-                */
-               np = of_find_node_by_type(NULL, "cpu");
-               if (np != NULL)
-                       np = of_find_node_by_type(np, "cpu");
-               if (np != NULL) {
-                       g5_phy_disable_cpu1();
-                       of_node_put(np);
-               }
-#endif /* CONFIG_SMP */
-               /* Enable GMAC for now for PCI probing. It will be disabled
-                * later on after PCI probe
-                */
-               np = of_find_node_by_name(NULL, "ethernet");
-               while(np) {
-                       if (device_is_compatible(np, "K2-GMAC"))
-                               g5_gmac_enable(np, 0, 1);
-                       np = of_find_node_by_name(np, "ethernet");
-               }
-
-               /* Enable FW before PCI probe. Will be disabled later on
-                * Note: We should have a batter way to check that we are
-                * dealing with uninorth internal cell and not a PCI cell
-                * on the external PCI. The code below works though.
-                */
-               np = of_find_node_by_name(NULL, "firewire");
-               while(np) {
-                       if (device_is_compatible(np, "pci106b,5811")) {
-                               macio_chips[0].flags |= MACIO_FLAG_FW_SUPPORTED;
-                               g5_fw_enable(np, 0, 1);
-                       }
-                       np = of_find_node_by_name(np, "firewire");
-               }
-       }
-#else /* CONFIG_POWER4 */
-
-       if (macio_chips[0].type == macio_keylargo ||
-           macio_chips[0].type == macio_pangea ||
-           macio_chips[0].type == macio_intrepid) {
-               /* Enable GMAC for now for PCI probing. It will be disabled
-                * later on after PCI probe
-                */
-               np = of_find_node_by_name(NULL, "ethernet");
-               while(np) {
-                       if (np->parent
-                           && device_is_compatible(np->parent, "uni-north")
-                           && device_is_compatible(np, "gmac"))
-                               core99_gmac_enable(np, 0, 1);
-                       np = of_find_node_by_name(np, "ethernet");
-               }
-
-               /* Enable FW before PCI probe. Will be disabled later on
-                * Note: We should have a batter way to check that we are
-                * dealing with uninorth internal cell and not a PCI cell
-                * on the external PCI. The code below works though.
-                */
-               np = of_find_node_by_name(NULL, "firewire");
-               while(np) {
-                       if (np->parent
-                           && device_is_compatible(np->parent, "uni-north")
-                           && (device_is_compatible(np, "pci106b,18") ||
-                               device_is_compatible(np, "pci106b,30") ||
-                               device_is_compatible(np, "pci11c1,5811"))) {
-                               macio_chips[0].flags |= MACIO_FLAG_FW_SUPPORTED;
-                               core99_firewire_enable(np, 0, 1);
-                       }
-                       np = of_find_node_by_name(np, "firewire");
-               }
-
-               /* Enable ATA-100 before PCI probe. */
-               np = of_find_node_by_name(NULL, "ata-6");
-               while(np) {
-                       if (np->parent
-                           && device_is_compatible(np->parent, "uni-north")
-                           && device_is_compatible(np, "kauai-ata")) {
-                               core99_ata100_enable(np, 1);
-                       }
-                       np = of_find_node_by_name(np, "ata-6");
-               }
-
-               /* Switch airport off */
-               np = find_devices("radio");
-               while(np) {
-                       if (np && np->parent == macio_chips[0].of_node) {
-                               macio_chips[0].flags |= MACIO_FLAG_AIRPORT_ON;
-                               core99_airport_enable(np, 0, 0);
-                       }
-                       np = np->next;
-               }
-       }
-
-       /* On all machines that support sound PM, switch sound off */
-       if (macio_chips[0].of_node)
-               pmac_do_feature_call(PMAC_FTR_SOUND_CHIP_ENABLE,
-                       macio_chips[0].of_node, 0, 0);
-
-       /* While on some desktop G3s, we turn it back on */
-       if (macio_chips[0].of_node && macio_chips[0].type == macio_heathrow
-               && (pmac_mb.model_id == PMAC_TYPE_GOSSAMER ||
-                   pmac_mb.model_id == PMAC_TYPE_SILK)) {
-               struct macio_chip *macio = &macio_chips[0];
-               MACIO_BIS(HEATHROW_FCR, HRW_SOUND_CLK_ENABLE);
-               MACIO_BIC(HEATHROW_FCR, HRW_SOUND_POWER_N);
-       }
-
-       /* Some machine models need the clock chip to be properly setup for
-        * clock spreading now. This should be a platform function but we
-        * don't do these at the moment
-        */
-       pmac_tweak_clock_spreading(1);
-
-#endif /* CONFIG_POWER4 */
-
-       /* On all machines, switch modem & serial ports off */
-       np = find_devices("ch-a");
-       while(np) {
-               initial_serial_shutdown(np);
-               np = np->next;
-       }
-       np = find_devices("ch-b");
-       while(np) {
-               initial_serial_shutdown(np);
-               np = np->next;
-       }
-}
-
-void __init
-pmac_feature_init(void)
-{
-       /* Detect the UniNorth memory controller */
-       probe_uninorth();
-
-       /* Probe mac-io controllers */
-       if (probe_macios()) {
-               printk(KERN_WARNING "No mac-io chip found\n");
-               return;
-       }
-
-       /* Setup low-level i2c stuffs */
-       pmac_init_low_i2c();
-
-       /* Probe machine type */
-       if (probe_motherboard())
-               printk(KERN_WARNING "Unknown PowerMac !\n");
-
-       /* Set some initial features (turn off some chips that will
-        * be later turned on)
-        */
-       set_initial_features();
-}
-
-int __init pmac_feature_late_init(void)
-{
-#if 0
-       struct device_node *np;
-
-       /* Request some resources late */
-       if (uninorth_node)
-               request_OF_resource(uninorth_node, 0, NULL);
-       np = find_devices("hammerhead");
-       if (np)
-               request_OF_resource(np, 0, NULL);
-       np = find_devices("interrupt-controller");
-       if (np)
-               request_OF_resource(np, 0, NULL);
-#endif
-       return 0;
-}
-
-device_initcall(pmac_feature_late_init);
-
-#if 0
-static void dump_HT_speeds(char *name, u32 cfg, u32 frq)
-{
-       int     freqs[16] = { 200,300,400,500,600,800,1000,0,0,0,0,0,0,0,0,0 };
-       int     bits[8] = { 8,16,0,32,2,4,0,0 };
-       int     freq = (frq >> 8) & 0xf;
-
-       if (freqs[freq] == 0)
-               printk("%s: Unknown HT link frequency %x\n", name, freq);
-       else
-               printk("%s: %d MHz on main link, (%d in / %d out) bits width\n",
-                      name, freqs[freq],
-                      bits[(cfg >> 28) & 0x7], bits[(cfg >> 24) & 0x7]);
-}
-
-void __init pmac_check_ht_link(void)
-{
-#if 0 /* Disabled for now */
-       u32     ufreq, freq, ucfg, cfg;
-       struct device_node *pcix_node;
-       u8      px_bus, px_devfn;
-       struct pci_controller *px_hose;
-
-       (void)in_be32(u3_ht + U3_HT_LINK_COMMAND);
-       ucfg = cfg = in_be32(u3_ht + U3_HT_LINK_CONFIG);
-       ufreq = freq = in_be32(u3_ht + U3_HT_LINK_FREQ);
-       dump_HT_speeds("U3 HyperTransport", cfg, freq);
-
-       pcix_node = of_find_compatible_node(NULL, "pci", "pci-x");
-       if (pcix_node == NULL) {
-               printk("No PCI-X bridge found\n");
-               return;
-       }
-       if (pci_device_from_OF_node(pcix_node, &px_bus, &px_devfn) != 0) {
-               printk("PCI-X bridge found but not matched to pci\n");
-               return;
-       }
-       px_hose = pci_find_hose_for_OF_device(pcix_node);
-       if (px_hose == NULL) {
-               printk("PCI-X bridge found but not matched to host\n");
-               return;
-       }       
-       early_read_config_dword(px_hose, px_bus, px_devfn, 0xc4, &cfg);
-       early_read_config_dword(px_hose, px_bus, px_devfn, 0xcc, &freq);
-       dump_HT_speeds("PCI-X HT Uplink", cfg, freq);
-       early_read_config_dword(px_hose, px_bus, px_devfn, 0xc8, &cfg);
-       early_read_config_dword(px_hose, px_bus, px_devfn, 0xd0, &freq);
-       dump_HT_speeds("PCI-X HT Downlink", cfg, freq);
-#endif
-}
-
-#endif /* CONFIG_POWER4 */
-
-/*
- * Early video resume hook
- */
-
-static void (*pmac_early_vresume_proc)(void *data);
-static void *pmac_early_vresume_data;
-
-void pmac_set_early_video_resume(void (*proc)(void *data), void *data)
-{
-       if (_machine != _MACH_Pmac)
-               return;
-       preempt_disable();
-       pmac_early_vresume_proc = proc;
-       pmac_early_vresume_data = data;
-       preempt_enable();
-}
-EXPORT_SYMBOL(pmac_set_early_video_resume);
-
-void pmac_call_early_video_resume(void)
-{
-       if (pmac_early_vresume_proc)
-               pmac_early_vresume_proc(pmac_early_vresume_data);
-}
-
-/*
- * AGP related suspend/resume code
- */
-
-static struct pci_dev *pmac_agp_bridge;
-static int (*pmac_agp_suspend)(struct pci_dev *bridge);
-static int (*pmac_agp_resume)(struct pci_dev *bridge);
-
-void pmac_register_agp_pm(struct pci_dev *bridge,
-                                int (*suspend)(struct pci_dev *bridge),
-                                int (*resume)(struct pci_dev *bridge))
-{
-       if (suspend || resume) {
-               pmac_agp_bridge = bridge;
-               pmac_agp_suspend = suspend;
-               pmac_agp_resume = resume;
-               return;
-       }
-       if (bridge != pmac_agp_bridge)
-               return;
-       pmac_agp_suspend = pmac_agp_resume = NULL;
-       return;
-}
-EXPORT_SYMBOL(pmac_register_agp_pm);
-
-void pmac_suspend_agp_for_card(struct pci_dev *dev)
-{
-       if (pmac_agp_bridge == NULL || pmac_agp_suspend == NULL)
-               return;
-       if (pmac_agp_bridge->bus != dev->bus)
-               return;
-       pmac_agp_suspend(pmac_agp_bridge);
-}
-EXPORT_SYMBOL(pmac_suspend_agp_for_card);
-
-void pmac_resume_agp_for_card(struct pci_dev *dev)
-{
-       if (pmac_agp_bridge == NULL || pmac_agp_resume == NULL)
-               return;
-       if (pmac_agp_bridge->bus != dev->bus)
-               return;
-       pmac_agp_resume(pmac_agp_bridge);
-}
-EXPORT_SYMBOL(pmac_resume_agp_for_card);
diff --git a/arch/powerpc/platforms/powermac/pmac_low_i2c.c b/arch/powerpc/platforms/powermac/pmac_low_i2c.c
deleted file mode 100644 (file)
index f3f39e8..0000000
+++ /dev/null
@@ -1,523 +0,0 @@
-/*
- *  arch/ppc/platforms/pmac_low_i2c.c
- *
- *  Copyright (C) 2003 Ben. Herrenschmidt (benh@kernel.crashing.org)
- *
- *  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.
- *
- *  This file contains some low-level i2c access routines that
- *  need to be used by various bits of the PowerMac platform code
- *  at times where the real asynchronous & interrupt driven driver
- *  cannot be used. The API borrows some semantics from the darwin
- *  driver in order to ease the implementation of the platform
- *  properties parser
- */
-
-#undef DEBUG
-
-#include <linux/config.h>
-#include <linux/types.h>
-#include <linux/sched.h>
-#include <linux/init.h>
-#include <linux/module.h>
-#include <linux/adb.h>
-#include <linux/pmu.h>
-#include <asm/keylargo.h>
-#include <asm/uninorth.h>
-#include <asm/io.h>
-#include <asm/prom.h>
-#include <asm/machdep.h>
-#include <asm/pmac_low_i2c.h>
-
-#define MAX_LOW_I2C_HOST       4
-
-#ifdef DEBUG
-#define DBG(x...) do {\
-               printk(KERN_DEBUG "KW:" x);     \
-       } while(0)
-#else
-#define DBG(x...)
-#endif
-
-struct low_i2c_host;
-
-typedef int (*low_i2c_func_t)(struct low_i2c_host *host, u8 addr, u8 sub, u8 *data, int len);
-
-struct low_i2c_host
-{
-       struct device_node      *np;            /* OF device node */
-       struct semaphore        mutex;          /* Access mutex for use by i2c-keywest */
-       low_i2c_func_t          func;           /* Access function */
-       unsigned int            is_open : 1;    /* Poor man's access control */
-       int                     mode;           /* Current mode */
-       int                     channel;        /* Current channel */
-       int                     num_channels;   /* Number of channels */
-       void __iomem            *base;          /* For keywest-i2c, base address */
-       int                     bsteps;         /* And register stepping */
-       int                     speed;          /* And speed */
-};
-
-static struct low_i2c_host     low_i2c_hosts[MAX_LOW_I2C_HOST];
-
-/* No locking is necessary on allocation, we are running way before
- * anything can race with us
- */
-static struct low_i2c_host *find_low_i2c_host(struct device_node *np)
-{
-       int i;
-
-       for (i = 0; i < MAX_LOW_I2C_HOST; i++)
-               if (low_i2c_hosts[i].np == np)
-                       return &low_i2c_hosts[i];
-       return NULL;
-}
-
-/*
- *
- * i2c-keywest implementation (UniNorth, U2, U3, Keylargo's)
- *
- */
-
-/*
- * Keywest i2c definitions borrowed from drivers/i2c/i2c-keywest.h,
- * should be moved somewhere in include/asm-ppc/
- */
-/* Register indices */
-typedef enum {
-       reg_mode = 0,
-       reg_control,
-       reg_status,
-       reg_isr,
-       reg_ier,
-       reg_addr,
-       reg_subaddr,
-       reg_data
-} reg_t;
-
-
-/* Mode register */
-#define KW_I2C_MODE_100KHZ     0x00
-#define KW_I2C_MODE_50KHZ      0x01
-#define KW_I2C_MODE_25KHZ      0x02
-#define KW_I2C_MODE_DUMB       0x00
-#define KW_I2C_MODE_STANDARD   0x04
-#define KW_I2C_MODE_STANDARDSUB        0x08
-#define KW_I2C_MODE_COMBINED   0x0C
-#define KW_I2C_MODE_MODE_MASK  0x0C
-#define KW_I2C_MODE_CHAN_MASK  0xF0
-
-/* Control register */
-#define KW_I2C_CTL_AAK         0x01
-#define KW_I2C_CTL_XADDR       0x02
-#define KW_I2C_CTL_STOP                0x04
-#define KW_I2C_CTL_START       0x08
-
-/* Status register */
-#define KW_I2C_STAT_BUSY       0x01
-#define KW_I2C_STAT_LAST_AAK   0x02
-#define KW_I2C_STAT_LAST_RW    0x04
-#define KW_I2C_STAT_SDA                0x08
-#define KW_I2C_STAT_SCL                0x10
-
-/* IER & ISR registers */
-#define KW_I2C_IRQ_DATA                0x01
-#define KW_I2C_IRQ_ADDR                0x02
-#define KW_I2C_IRQ_STOP                0x04
-#define KW_I2C_IRQ_START       0x08
-#define KW_I2C_IRQ_MASK                0x0F
-
-/* State machine states */
-enum {
-       state_idle,
-       state_addr,
-       state_read,
-       state_write,
-       state_stop,
-       state_dead
-};
-
-#define WRONG_STATE(name) do {\
-               printk(KERN_DEBUG "KW: wrong state. Got %s, state: %s (isr: %02x)\n", \
-                      name, __kw_state_names[state], isr); \
-       } while(0)
-
-static const char *__kw_state_names[] = {
-       "state_idle",
-       "state_addr",
-       "state_read",
-       "state_write",
-       "state_stop",
-       "state_dead"
-};
-
-static inline u8 __kw_read_reg(struct low_i2c_host *host, reg_t reg)
-{
-       return readb(host->base + (((unsigned int)reg) << host->bsteps));
-}
-
-static inline void __kw_write_reg(struct low_i2c_host *host, reg_t reg, u8 val)
-{
-       writeb(val, host->base + (((unsigned)reg) << host->bsteps));
-       (void)__kw_read_reg(host, reg_subaddr);
-}
-
-#define kw_write_reg(reg, val) __kw_write_reg(host, reg, val) 
-#define kw_read_reg(reg)       __kw_read_reg(host, reg) 
-
-
-/* Don't schedule, the g5 fan controller is too
- * timing sensitive
- */
-static u8 kw_wait_interrupt(struct low_i2c_host* host)
-{
-       int i, j;
-       u8 isr;
-       
-       for (i = 0; i < 100000; i++) {
-               isr = kw_read_reg(reg_isr) & KW_I2C_IRQ_MASK;
-               if (isr != 0)
-                       return isr;
-
-               /* This code is used with the timebase frozen, we cannot rely
-                * on udelay ! For now, just use a bogus loop
-                */
-               for (j = 1; j < 10000; j++)
-                       mb();
-       }
-       return isr;
-}
-
-static int kw_handle_interrupt(struct low_i2c_host *host, int state, int rw, int *rc, u8 **data, int *len, u8 isr)
-{
-       u8 ack;
-
-       DBG("kw_handle_interrupt(%s, isr: %x)\n", __kw_state_names[state], isr);
-
-       if (isr == 0) {
-               if (state != state_stop) {
-                       DBG("KW: Timeout !\n");
-                       *rc = -EIO;
-                       goto stop;
-               }
-               if (state == state_stop) {
-                       ack = kw_read_reg(reg_status);
-                       if (!(ack & KW_I2C_STAT_BUSY)) {
-                               state = state_idle;
-                               kw_write_reg(reg_ier, 0x00);
-                       }
-               }
-               return state;
-       }
-
-       if (isr & KW_I2C_IRQ_ADDR) {
-               ack = kw_read_reg(reg_status);
-               if (state != state_addr) {
-                       kw_write_reg(reg_isr, KW_I2C_IRQ_ADDR);
-                       WRONG_STATE("KW_I2C_IRQ_ADDR"); 
-                       *rc = -EIO;
-                       goto stop;
-               }
-               if ((ack & KW_I2C_STAT_LAST_AAK) == 0) {                        
-                       *rc = -ENODEV;
-                       DBG("KW: NAK on address\n");
-                       return state_stop;                   
-               } else {
-                       if (rw) {
-                               state = state_read;
-                               if (*len > 1)
-                                       kw_write_reg(reg_control, KW_I2C_CTL_AAK);
-                       } else {
-                               state = state_write;
-                               kw_write_reg(reg_data, **data);
-                               (*data)++; (*len)--;
-                       }
-               }
-               kw_write_reg(reg_isr, KW_I2C_IRQ_ADDR);
-       }
-
-       if (isr & KW_I2C_IRQ_DATA) {
-               if (state == state_read) {
-                       **data = kw_read_reg(reg_data);
-                       (*data)++; (*len)--;
-                       kw_write_reg(reg_isr, KW_I2C_IRQ_DATA);
-                       if ((*len) == 0)
-                               state = state_stop;
-                       else if ((*len) == 1)
-                               kw_write_reg(reg_control, 0);
-               } else if (state == state_write) {
-                       ack = kw_read_reg(reg_status);
-                       if ((ack & KW_I2C_STAT_LAST_AAK) == 0) {
-                               DBG("KW: nack on data write\n");
-                               *rc = -EIO;
-                               goto stop;
-                       } else if (*len) {
-                               kw_write_reg(reg_data, **data);
-                               (*data)++; (*len)--;
-                       } else {
-                               kw_write_reg(reg_control, KW_I2C_CTL_STOP);
-                               state = state_stop;
-                               *rc = 0;
-                       }
-                       kw_write_reg(reg_isr, KW_I2C_IRQ_DATA);
-               } else {
-                       kw_write_reg(reg_isr, KW_I2C_IRQ_DATA);
-                       WRONG_STATE("KW_I2C_IRQ_DATA"); 
-                       if (state != state_stop) {
-                               *rc = -EIO;
-                               goto stop;
-                       }
-               }
-       }
-
-       if (isr & KW_I2C_IRQ_STOP) {
-               kw_write_reg(reg_isr, KW_I2C_IRQ_STOP);
-               if (state != state_stop) {
-                       WRONG_STATE("KW_I2C_IRQ_STOP");
-                       *rc = -EIO;
-               }
-               return state_idle;
-       }
-
-       if (isr & KW_I2C_IRQ_START)
-               kw_write_reg(reg_isr, KW_I2C_IRQ_START);
-
-       return state;
-
- stop:
-       kw_write_reg(reg_control, KW_I2C_CTL_STOP);     
-       return state_stop;
-}
-
-static int keywest_low_i2c_func(struct low_i2c_host *host, u8 addr, u8 subaddr, u8 *data, int len)
-{
-       u8 mode_reg = host->speed;
-       int state = state_addr;
-       int rc = 0;
-
-       /* Setup mode & subaddress if any */
-       switch(host->mode) {
-       case pmac_low_i2c_mode_dumb:
-               printk(KERN_ERR "low_i2c: Dumb mode not supported !\n");
-               return -EINVAL;
-       case pmac_low_i2c_mode_std:
-               mode_reg |= KW_I2C_MODE_STANDARD;
-               break;
-       case pmac_low_i2c_mode_stdsub:
-               mode_reg |= KW_I2C_MODE_STANDARDSUB;
-               break;
-       case pmac_low_i2c_mode_combined:
-               mode_reg |= KW_I2C_MODE_COMBINED;
-               break;
-       }
-
-       /* Setup channel & clear pending irqs */
-       kw_write_reg(reg_isr, kw_read_reg(reg_isr));
-       kw_write_reg(reg_mode, mode_reg | (host->channel << 4));
-       kw_write_reg(reg_status, 0);
-
-       /* Set up address and r/w bit */
-       kw_write_reg(reg_addr, addr);
-
-       /* Set up the sub address */
-       if ((mode_reg & KW_I2C_MODE_MODE_MASK) == KW_I2C_MODE_STANDARDSUB
-           || (mode_reg & KW_I2C_MODE_MODE_MASK) == KW_I2C_MODE_COMBINED)
-               kw_write_reg(reg_subaddr, subaddr);
-
-       /* Start sending address & disable interrupt*/
-       kw_write_reg(reg_ier, 0 /*KW_I2C_IRQ_MASK*/);
-       kw_write_reg(reg_control, KW_I2C_CTL_XADDR);
-
-       /* State machine, to turn into an interrupt handler */
-       while(state != state_idle) {
-               u8 isr = kw_wait_interrupt(host);
-               state = kw_handle_interrupt(host, state, addr & 1, &rc, &data, &len, isr);
-       }
-
-       return rc;
-}
-
-static void keywest_low_i2c_add(struct device_node *np)
-{
-       struct low_i2c_host     *host = find_low_i2c_host(NULL);
-       u32                     *psteps, *prate, steps, aoffset = 0;
-       struct device_node      *parent;
-
-       if (host == NULL) {
-               printk(KERN_ERR "low_i2c: Can't allocate host for %s\n",
-                      np->full_name);
-               return;
-       }
-       memset(host, 0, sizeof(*host));
-
-       init_MUTEX(&host->mutex);
-       host->np = of_node_get(np);     
-       psteps = (u32 *)get_property(np, "AAPL,address-step", NULL);
-       steps = psteps ? (*psteps) : 0x10;
-       for (host->bsteps = 0; (steps & 0x01) == 0; host->bsteps++)
-               steps >>= 1;
-       parent = of_get_parent(np);
-       host->num_channels = 1;
-       if (parent && parent->name[0] == 'u') {
-               host->num_channels = 2;
-               aoffset = 3;
-       }
-       /* Select interface rate */
-       host->speed = KW_I2C_MODE_100KHZ;
-       prate = (u32 *)get_property(np, "AAPL,i2c-rate", NULL);
-       if (prate) switch(*prate) {
-       case 100:
-               host->speed = KW_I2C_MODE_100KHZ;
-               break;
-       case 50:
-               host->speed = KW_I2C_MODE_50KHZ;
-               break;
-       case 25:
-               host->speed = KW_I2C_MODE_25KHZ;
-               break;
-       }       
-
-       host->mode = pmac_low_i2c_mode_std;
-       host->base = ioremap(np->addrs[0].address + aoffset,
-                                               np->addrs[0].size);
-       host->func = keywest_low_i2c_func;
-}
-
-/*
- *
- * PMU implementation
- *
- */
-
-
-#ifdef CONFIG_ADB_PMU
-
-static int pmu_low_i2c_func(struct low_i2c_host *host, u8 addr, u8 sub, u8 *data, int len)
-{
-       // TODO
-       return -ENODEV;
-}
-
-static void pmu_low_i2c_add(struct device_node *np)
-{
-       struct low_i2c_host     *host = find_low_i2c_host(NULL);
-
-       if (host == NULL) {
-               printk(KERN_ERR "low_i2c: Can't allocate host for %s\n",
-                      np->full_name);
-               return;
-       }
-       memset(host, 0, sizeof(*host));
-
-       init_MUTEX(&host->mutex);
-       host->np = of_node_get(np);     
-       host->num_channels = 3;
-       host->mode = pmac_low_i2c_mode_std;
-       host->func = pmu_low_i2c_func;
-}
-
-#endif /* CONFIG_ADB_PMU */
-
-void __init pmac_init_low_i2c(void)
-{
-       struct device_node *np;
-
-       /* Probe keywest-i2c busses */
-       np = of_find_compatible_node(NULL, "i2c", "keywest-i2c");
-       while(np) {
-               keywest_low_i2c_add(np);
-               np = of_find_compatible_node(np, "i2c", "keywest-i2c");
-       }
-
-#ifdef CONFIG_ADB_PMU
-       /* Probe PMU busses */
-       np = of_find_node_by_name(NULL, "via-pmu");
-       if (np)
-               pmu_low_i2c_add(np);
-#endif /* CONFIG_ADB_PMU */
-
-       /* TODO: Add CUDA support as well */
-}
-
-int pmac_low_i2c_lock(struct device_node *np)
-{
-       struct low_i2c_host *host = find_low_i2c_host(np);
-
-       if (!host)
-               return -ENODEV;
-       down(&host->mutex);
-       return 0;
-}
-EXPORT_SYMBOL(pmac_low_i2c_lock);
-
-int pmac_low_i2c_unlock(struct device_node *np)
-{
-       struct low_i2c_host *host = find_low_i2c_host(np);
-
-       if (!host)
-               return -ENODEV;
-       up(&host->mutex);
-       return 0;
-}
-EXPORT_SYMBOL(pmac_low_i2c_unlock);
-
-
-int pmac_low_i2c_open(struct device_node *np, int channel)
-{
-       struct low_i2c_host *host = find_low_i2c_host(np);
-
-       if (!host)
-               return -ENODEV;
-
-       if (channel >= host->num_channels)
-               return -EINVAL;
-
-       down(&host->mutex);
-       host->is_open = 1;
-       host->channel = channel;
-
-       return 0;
-}
-EXPORT_SYMBOL(pmac_low_i2c_open);
-
-int pmac_low_i2c_close(struct device_node *np)
-{
-       struct low_i2c_host *host = find_low_i2c_host(np);
-
-       if (!host)
-               return -ENODEV;
-
-       host->is_open = 0;
-       up(&host->mutex);
-
-       return 0;
-}
-EXPORT_SYMBOL(pmac_low_i2c_close);
-
-int pmac_low_i2c_setmode(struct device_node *np, int mode)
-{
-       struct low_i2c_host *host = find_low_i2c_host(np);
-
-       if (!host)
-               return -ENODEV;
-       WARN_ON(!host->is_open);
-       host->mode = mode;
-
-       return 0;
-}
-EXPORT_SYMBOL(pmac_low_i2c_setmode);
-
-int pmac_low_i2c_xfer(struct device_node *np, u8 addrdir, u8 subaddr, u8 *data, int len)
-{
-       struct low_i2c_host *host = find_low_i2c_host(np);
-
-       if (!host)
-               return -ENODEV;
-       WARN_ON(!host->is_open);
-
-       return host->func(host, addrdir, subaddr, data, len);
-}
-EXPORT_SYMBOL(pmac_low_i2c_xfer);
-
diff --git a/arch/powerpc/platforms/powermac/pmac_nvram.c b/arch/powerpc/platforms/powermac/pmac_nvram.c
deleted file mode 100644 (file)
index 8c9b008..0000000
+++ /dev/null
@@ -1,584 +0,0 @@
-/*
- *  arch/ppc/platforms/pmac_nvram.c
- *
- *  Copyright (C) 2002 Benjamin Herrenschmidt (benh@kernel.crashing.org)
- *
- *  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.
- *
- *  Todo: - add support for the OF persistent properties
- */
-#include <linux/config.h>
-#include <linux/module.h>
-#include <linux/kernel.h>
-#include <linux/stddef.h>
-#include <linux/string.h>
-#include <linux/nvram.h>
-#include <linux/init.h>
-#include <linux/slab.h>
-#include <linux/delay.h>
-#include <linux/errno.h>
-#include <linux/adb.h>
-#include <linux/pmu.h>
-#include <linux/bootmem.h>
-#include <linux/completion.h>
-#include <linux/spinlock.h>
-#include <asm/sections.h>
-#include <asm/io.h>
-#include <asm/system.h>
-#include <asm/prom.h>
-#include <asm/machdep.h>
-#include <asm/nvram.h>
-
-#define DEBUG
-
-#ifdef DEBUG
-#define DBG(x...) printk(x)
-#else
-#define DBG(x...)
-#endif
-
-#define NVRAM_SIZE             0x2000  /* 8kB of non-volatile RAM */
-
-#define CORE99_SIGNATURE       0x5a
-#define CORE99_ADLER_START     0x14
-
-/* On Core99, nvram is either a sharp, a micron or an AMD flash */
-#define SM_FLASH_STATUS_DONE   0x80
-#define SM_FLASH_STATUS_ERR            0x38
-#define SM_FLASH_CMD_ERASE_CONFIRM     0xd0
-#define SM_FLASH_CMD_ERASE_SETUP       0x20
-#define SM_FLASH_CMD_RESET             0xff
-#define SM_FLASH_CMD_WRITE_SETUP       0x40
-#define SM_FLASH_CMD_CLEAR_STATUS      0x50
-#define SM_FLASH_CMD_READ_STATUS       0x70
-
-/* CHRP NVRAM header */
-struct chrp_header {
-  u8           signature;
-  u8           cksum;
-  u16          len;
-  char          name[12];
-  u8           data[0];
-};
-
-struct core99_header {
-  struct chrp_header   hdr;
-  u32                  adler;
-  u32                  generation;
-  u32                  reserved[2];
-};
-
-/*
- * Read and write the non-volatile RAM on PowerMacs and CHRP machines.
- */
-static int nvram_naddrs;
-static volatile unsigned char *nvram_addr;
-static volatile unsigned char *nvram_data;
-static int nvram_mult, is_core_99;
-static int core99_bank = 0;
-static int nvram_partitions[3];
-static DEFINE_SPINLOCK(nv_lock);
-
-extern int pmac_newworld;
-extern int system_running;
-
-static int (*core99_write_bank)(int bank, u8* datas);
-static int (*core99_erase_bank)(int bank);
-
-static char *nvram_image;
-
-
-static unsigned char core99_nvram_read_byte(int addr)
-{
-       if (nvram_image == NULL)
-               return 0xff;
-       return nvram_image[addr];
-}
-
-static void core99_nvram_write_byte(int addr, unsigned char val)
-{
-       if (nvram_image == NULL)
-               return;
-       nvram_image[addr] = val;
-}
-
-
-static unsigned char direct_nvram_read_byte(int addr)
-{
-       return in_8(&nvram_data[(addr & (NVRAM_SIZE - 1)) * nvram_mult]);
-}
-
-static void direct_nvram_write_byte(int addr, unsigned char val)
-{
-       out_8(&nvram_data[(addr & (NVRAM_SIZE - 1)) * nvram_mult], val);
-}
-
-
-static unsigned char indirect_nvram_read_byte(int addr)
-{
-       unsigned char val;
-       unsigned long flags;
-
-       spin_lock_irqsave(&nv_lock, flags);
-       out_8(nvram_addr, addr >> 5);
-       val = in_8(&nvram_data[(addr & 0x1f) << 4]);
-       spin_unlock_irqrestore(&nv_lock, flags);
-
-       return val;
-}
-
-static void indirect_nvram_write_byte(int addr, unsigned char val)
-{
-       unsigned long flags;
-
-       spin_lock_irqsave(&nv_lock, flags);
-       out_8(nvram_addr, addr >> 5);
-       out_8(&nvram_data[(addr & 0x1f) << 4], val);
-       spin_unlock_irqrestore(&nv_lock, flags);
-}
-
-
-#ifdef CONFIG_ADB_PMU
-
-static void pmu_nvram_complete(struct adb_request *req)
-{
-       if (req->arg)
-               complete((struct completion *)req->arg);
-}
-
-static unsigned char pmu_nvram_read_byte(int addr)
-{
-       struct adb_request req;
-       DECLARE_COMPLETION(req_complete); 
-       
-       req.arg = system_state == SYSTEM_RUNNING ? &req_complete : NULL;
-       if (pmu_request(&req, pmu_nvram_complete, 3, PMU_READ_NVRAM,
-                       (addr >> 8) & 0xff, addr & 0xff))
-               return 0xff;
-       if (system_state == SYSTEM_RUNNING)
-               wait_for_completion(&req_complete);
-       while (!req.complete)
-               pmu_poll();
-       return req.reply[0];
-}
-
-static void pmu_nvram_write_byte(int addr, unsigned char val)
-{
-       struct adb_request req;
-       DECLARE_COMPLETION(req_complete); 
-       
-       req.arg = system_state == SYSTEM_RUNNING ? &req_complete : NULL;
-       if (pmu_request(&req, pmu_nvram_complete, 4, PMU_WRITE_NVRAM,
-                       (addr >> 8) & 0xff, addr & 0xff, val))
-               return;
-       if (system_state == SYSTEM_RUNNING)
-               wait_for_completion(&req_complete);
-       while (!req.complete)
-               pmu_poll();
-}
-
-#endif /* CONFIG_ADB_PMU */
-
-
-static u8 chrp_checksum(struct chrp_header* hdr)
-{
-       u8 *ptr;
-       u16 sum = hdr->signature;
-       for (ptr = (u8 *)&hdr->len; ptr < hdr->data; ptr++)
-               sum += *ptr;
-       while (sum > 0xFF)
-               sum = (sum & 0xFF) + (sum>>8);
-       return sum;
-}
-
-static u32 core99_calc_adler(u8 *buffer)
-{
-       int cnt;
-       u32 low, high;
-
-       buffer += CORE99_ADLER_START;
-       low = 1;
-       high = 0;
-       for (cnt=0; cnt<(NVRAM_SIZE-CORE99_ADLER_START); cnt++) {
-               if ((cnt % 5000) == 0) {
-                       high  %= 65521UL;
-                       high %= 65521UL;
-               }
-               low += buffer[cnt];
-               high += low;
-       }
-       low  %= 65521UL;
-       high %= 65521UL;
-
-       return (high << 16) | low;
-}
-
-static u32 core99_check(u8* datas)
-{
-       struct core99_header* hdr99 = (struct core99_header*)datas;
-
-       if (hdr99->hdr.signature != CORE99_SIGNATURE) {
-               DBG("Invalid signature\n");
-               return 0;
-       }
-       if (hdr99->hdr.cksum != chrp_checksum(&hdr99->hdr)) {
-               DBG("Invalid checksum\n");
-               return 0;
-       }
-       if (hdr99->adler != core99_calc_adler(datas)) {
-               DBG("Invalid adler\n");
-               return 0;
-       }
-       return hdr99->generation;
-}
-
-static int sm_erase_bank(int bank)
-{
-       int stat, i;
-       unsigned long timeout;
-
-       u8* base = (u8 *)nvram_data + core99_bank*NVRAM_SIZE;
-
-               DBG("nvram: Sharp/Micron Erasing bank %d...\n", bank);
-
-       out_8(base, SM_FLASH_CMD_ERASE_SETUP);
-       out_8(base, SM_FLASH_CMD_ERASE_CONFIRM);
-       timeout = 0;
-       do {
-               if (++timeout > 1000000) {
-                       printk(KERN_ERR "nvram: Sharp/Miron flash erase timeout !\n");
-                       break;
-               }
-               out_8(base, SM_FLASH_CMD_READ_STATUS);
-               stat = in_8(base);
-       } while (!(stat & SM_FLASH_STATUS_DONE));
-
-       out_8(base, SM_FLASH_CMD_CLEAR_STATUS);
-       out_8(base, SM_FLASH_CMD_RESET);
-
-       for (i=0; i<NVRAM_SIZE; i++)
-               if (base[i] != 0xff) {
-                       printk(KERN_ERR "nvram: Sharp/Micron flash erase failed !\n");
-                       return -ENXIO;
-               }
-       return 0;
-}
-
-static int sm_write_bank(int bank, u8* datas)
-{
-       int i, stat = 0;
-       unsigned long timeout;
-
-       u8* base = (u8 *)nvram_data + core99_bank*NVRAM_SIZE;
-
-               DBG("nvram: Sharp/Micron Writing bank %d...\n", bank);
-
-       for (i=0; i<NVRAM_SIZE; i++) {
-               out_8(base+i, SM_FLASH_CMD_WRITE_SETUP);
-               udelay(1);
-               out_8(base+i, datas[i]);
-               timeout = 0;
-               do {
-                       if (++timeout > 1000000) {
-                               printk(KERN_ERR "nvram: Sharp/Micron flash write timeout !\n");
-                               break;
-                       }
-                       out_8(base, SM_FLASH_CMD_READ_STATUS);
-                       stat = in_8(base);
-               } while (!(stat & SM_FLASH_STATUS_DONE));
-               if (!(stat & SM_FLASH_STATUS_DONE))
-                       break;
-       }
-       out_8(base, SM_FLASH_CMD_CLEAR_STATUS);
-       out_8(base, SM_FLASH_CMD_RESET);
-       for (i=0; i<NVRAM_SIZE; i++)
-               if (base[i] != datas[i]) {
-                       printk(KERN_ERR "nvram: Sharp/Micron flash write failed !\n");
-                       return -ENXIO;
-               }
-       return 0;
-}
-
-static int amd_erase_bank(int bank)
-{
-       int i, stat = 0;
-       unsigned long timeout;
-
-       u8* base = (u8 *)nvram_data + core99_bank*NVRAM_SIZE;
-
-               DBG("nvram: AMD Erasing bank %d...\n", bank);
-
-       /* Unlock 1 */
-       out_8(base+0x555, 0xaa);
-       udelay(1);
-       /* Unlock 2 */
-       out_8(base+0x2aa, 0x55);
-       udelay(1);
-
-       /* Sector-Erase */
-       out_8(base+0x555, 0x80);
-       udelay(1);
-       out_8(base+0x555, 0xaa);
-       udelay(1);
-       out_8(base+0x2aa, 0x55);
-       udelay(1);
-       out_8(base, 0x30);
-       udelay(1);
-
-       timeout = 0;
-       do {
-               if (++timeout > 1000000) {
-                       printk(KERN_ERR "nvram: AMD flash erase timeout !\n");
-                       break;
-               }
-               stat = in_8(base) ^ in_8(base);
-       } while (stat != 0);
-       
-       /* Reset */
-       out_8(base, 0xf0);
-       udelay(1);
-       
-       for (i=0; i<NVRAM_SIZE; i++)
-               if (base[i] != 0xff) {
-                       printk(KERN_ERR "nvram: AMD flash erase failed !\n");
-                       return -ENXIO;
-               }
-       return 0;
-}
-
-static int amd_write_bank(int bank, u8* datas)
-{
-       int i, stat = 0;
-       unsigned long timeout;
-
-       u8* base = (u8 *)nvram_data + core99_bank*NVRAM_SIZE;
-
-               DBG("nvram: AMD Writing bank %d...\n", bank);
-
-       for (i=0; i<NVRAM_SIZE; i++) {
-               /* Unlock 1 */
-               out_8(base+0x555, 0xaa);
-               udelay(1);
-               /* Unlock 2 */
-               out_8(base+0x2aa, 0x55);
-               udelay(1);
-
-               /* Write single word */
-               out_8(base+0x555, 0xa0);
-               udelay(1);
-               out_8(base+i, datas[i]);
-               
-               timeout = 0;
-               do {
-                       if (++timeout > 1000000) {
-                               printk(KERN_ERR "nvram: AMD flash write timeout !\n");
-                               break;
-                       }
-                       stat = in_8(base) ^ in_8(base);
-               } while (stat != 0);
-               if (stat != 0)
-                       break;
-       }
-
-       /* Reset */
-       out_8(base, 0xf0);
-       udelay(1);
-
-       for (i=0; i<NVRAM_SIZE; i++)
-               if (base[i] != datas[i]) {
-                       printk(KERN_ERR "nvram: AMD flash write failed !\n");
-                       return -ENXIO;
-               }
-       return 0;
-}
-
-static void __init lookup_partitions(void)
-{
-       u8 buffer[17];
-       int i, offset;
-       struct chrp_header* hdr;
-
-       if (pmac_newworld) {
-               nvram_partitions[pmac_nvram_OF] = -1;
-               nvram_partitions[pmac_nvram_XPRAM] = -1;
-               nvram_partitions[pmac_nvram_NR] = -1;
-               hdr = (struct chrp_header *)buffer;
-
-               offset = 0;
-               buffer[16] = 0;
-               do {
-                       for (i=0;i<16;i++)
-                               buffer[i] = nvram_read_byte(offset+i);
-                       if (!strcmp(hdr->name, "common"))
-                               nvram_partitions[pmac_nvram_OF] = offset + 0x10;
-                       if (!strcmp(hdr->name, "APL,MacOS75")) {
-                               nvram_partitions[pmac_nvram_XPRAM] = offset + 0x10;
-                               nvram_partitions[pmac_nvram_NR] = offset + 0x110;
-                       }
-                       offset += (hdr->len * 0x10);
-               } while(offset < NVRAM_SIZE);
-       } else {
-               nvram_partitions[pmac_nvram_OF] = 0x1800;
-               nvram_partitions[pmac_nvram_XPRAM] = 0x1300;
-               nvram_partitions[pmac_nvram_NR] = 0x1400;
-       }
-       DBG("nvram: OF partition at 0x%x\n", nvram_partitions[pmac_nvram_OF]);
-       DBG("nvram: XP partition at 0x%x\n", nvram_partitions[pmac_nvram_XPRAM]);
-       DBG("nvram: NR partition at 0x%x\n", nvram_partitions[pmac_nvram_NR]);
-}
-
-static void core99_nvram_sync(void)
-{
-       struct core99_header* hdr99;
-       unsigned long flags;
-
-       if (!is_core_99 || !nvram_data || !nvram_image)
-               return;
-
-       spin_lock_irqsave(&nv_lock, flags);
-       if (!memcmp(nvram_image, (u8*)nvram_data + core99_bank*NVRAM_SIZE,
-               NVRAM_SIZE))
-               goto bail;
-
-       DBG("Updating nvram...\n");
-
-       hdr99 = (struct core99_header*)nvram_image;
-       hdr99->generation++;
-       hdr99->hdr.signature = CORE99_SIGNATURE;
-       hdr99->hdr.cksum = chrp_checksum(&hdr99->hdr);
-       hdr99->adler = core99_calc_adler(nvram_image);
-       core99_bank = core99_bank ? 0 : 1;
-       if (core99_erase_bank)
-               if (core99_erase_bank(core99_bank)) {
-                       printk("nvram: Error erasing bank %d\n", core99_bank);
-                       goto bail;
-               }
-       if (core99_write_bank)
-               if (core99_write_bank(core99_bank, nvram_image))
-                       printk("nvram: Error writing bank %d\n", core99_bank);
- bail:
-       spin_unlock_irqrestore(&nv_lock, flags);
-
-#ifdef DEBUG
-               mdelay(2000);
-#endif
-}
-
-void __init pmac_nvram_init(void)
-{
-       struct device_node *dp;
-
-       nvram_naddrs = 0;
-
-       dp = find_devices("nvram");
-       if (dp == NULL) {
-               printk(KERN_ERR "Can't find NVRAM device\n");
-               return;
-       }
-       nvram_naddrs = dp->n_addrs;
-       is_core_99 = device_is_compatible(dp, "nvram,flash");
-       if (is_core_99) {
-               int i;
-               u32 gen_bank0, gen_bank1;
-
-               if (nvram_naddrs < 1) {
-                       printk(KERN_ERR "nvram: no address\n");
-                       return;
-               }
-               nvram_image = alloc_bootmem(NVRAM_SIZE);
-               if (nvram_image == NULL) {
-                       printk(KERN_ERR "nvram: can't allocate ram image\n");
-                       return;
-               }
-               nvram_data = ioremap(dp->addrs[0].address, NVRAM_SIZE*2);
-               nvram_naddrs = 1; /* Make sure we get the correct case */
-
-               DBG("nvram: Checking bank 0...\n");
-
-               gen_bank0 = core99_check((u8 *)nvram_data);
-               gen_bank1 = core99_check((u8 *)nvram_data + NVRAM_SIZE);
-               core99_bank = (gen_bank0 < gen_bank1) ? 1 : 0;
-
-               DBG("nvram: gen0=%d, gen1=%d\n", gen_bank0, gen_bank1);
-               DBG("nvram: Active bank is: %d\n", core99_bank);
-
-               for (i=0; i<NVRAM_SIZE; i++)
-                       nvram_image[i] = nvram_data[i + core99_bank*NVRAM_SIZE];
-
-               ppc_md.nvram_read_val   = core99_nvram_read_byte;
-               ppc_md.nvram_write_val  = core99_nvram_write_byte;
-               ppc_md.nvram_sync       = core99_nvram_sync;
-               /* 
-                * Maybe we could be smarter here though making an exclusive list
-                * of known flash chips is a bit nasty as older OF didn't provide us
-                * with a useful "compatible" entry. A solution would be to really
-                * identify the chip using flash id commands and base ourselves on
-                * a list of known chips IDs
-                */
-               if (device_is_compatible(dp, "amd-0137")) {
-                       core99_erase_bank = amd_erase_bank;
-                       core99_write_bank = amd_write_bank;
-               } else {
-                       core99_erase_bank = sm_erase_bank;
-                       core99_write_bank = sm_write_bank;
-               }
-       } else if (_machine == _MACH_chrp && nvram_naddrs == 1) {
-               nvram_data = ioremap(dp->addrs[0].address + isa_mem_base,
-                                    dp->addrs[0].size);
-               nvram_mult = 1;
-               ppc_md.nvram_read_val   = direct_nvram_read_byte;
-               ppc_md.nvram_write_val  = direct_nvram_write_byte;
-       } else if (nvram_naddrs == 1) {
-               nvram_data = ioremap(dp->addrs[0].address, dp->addrs[0].size);
-               nvram_mult = (dp->addrs[0].size + NVRAM_SIZE - 1) / NVRAM_SIZE;
-               ppc_md.nvram_read_val   = direct_nvram_read_byte;
-               ppc_md.nvram_write_val  = direct_nvram_write_byte;
-       } else if (nvram_naddrs == 2) {
-               nvram_addr = ioremap(dp->addrs[0].address, dp->addrs[0].size);
-               nvram_data = ioremap(dp->addrs[1].address, dp->addrs[1].size);
-               ppc_md.nvram_read_val   = indirect_nvram_read_byte;
-               ppc_md.nvram_write_val  = indirect_nvram_write_byte;
-       } else if (nvram_naddrs == 0 && sys_ctrler == SYS_CTRLER_PMU) {
-#ifdef CONFIG_ADB_PMU
-               nvram_naddrs = -1;
-               ppc_md.nvram_read_val   = pmu_nvram_read_byte;
-               ppc_md.nvram_write_val  = pmu_nvram_write_byte;
-#endif /* CONFIG_ADB_PMU */
-       } else {
-               printk(KERN_ERR "Don't know how to access NVRAM with %d addresses\n",
-                      nvram_naddrs);
-       }
-       lookup_partitions();
-}
-
-int pmac_get_partition(int partition)
-{
-       return nvram_partitions[partition];
-}
-
-u8 pmac_xpram_read(int xpaddr)
-{
-       int offset = nvram_partitions[pmac_nvram_XPRAM];
-
-       if (offset < 0)
-               return 0xff;
-
-       return ppc_md.nvram_read_val(xpaddr + offset);
-}
-
-void pmac_xpram_write(int xpaddr, u8 data)
-{
-       int offset = nvram_partitions[pmac_nvram_XPRAM];
-
-       if (offset < 0)
-               return;
-
-       ppc_md.nvram_write_val(xpaddr + offset, data);
-}
-
-EXPORT_SYMBOL(pmac_get_partition);
-EXPORT_SYMBOL(pmac_xpram_read);
-EXPORT_SYMBOL(pmac_xpram_write);
diff --git a/arch/powerpc/platforms/powermac/pmac_pci.c b/arch/powerpc/platforms/powermac/pmac_pci.c
deleted file mode 100644 (file)
index 40bcd3e..0000000
+++ /dev/null
@@ -1,1341 +0,0 @@
-/*
- * Support for PCI bridges found on Power Macintoshes.
- * At present the "bandit" and "chaos" bridges are supported.
- * Fortunately you access configuration space in the same
- * way with either bridge.
- *
- * Copyright (C) 2003 Benjamin Herrenschmuidt (benh@kernel.crashing.org)
- * Copyright (C) 1997 Paul Mackerras (paulus@samba.org)
- *
- * 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.
- */
-
-#include <linux/kernel.h>
-#include <linux/pci.h>
-#include <linux/delay.h>
-#include <linux/string.h>
-#include <linux/init.h>
-#include <linux/bootmem.h>
-
-#include <asm/sections.h>
-#include <asm/io.h>
-#include <asm/prom.h>
-#include <asm/pci-bridge.h>
-#include <asm/machdep.h>
-#include <asm/pmac_feature.h>
-
-#undef DEBUG
-
-#ifdef DEBUG
-#define DBG(x...) printk(x)
-#else
-#define DBG(x...)
-#endif
-
-static int add_bridge(struct device_node *dev);
-extern void pmac_check_ht_link(void);
-
-/* XXX Could be per-controller, but I don't think we risk anything by
- * assuming we won't have both UniNorth and Bandit */
-static int has_uninorth;
-#ifdef CONFIG_POWER4
-static struct pci_controller *u3_agp;
-#endif /* CONFIG_POWER4 */
-
-extern u8 pci_cache_line_size;
-extern int pcibios_assign_bus_offset;
-
-struct device_node *k2_skiplist[2];
-
-/*
- * Magic constants for enabling cache coherency in the bandit/PSX bridge.
- */
-#define BANDIT_DEVID_2 8
-#define BANDIT_REVID   3
-
-#define BANDIT_DEVNUM  11
-#define BANDIT_MAGIC   0x50
-#define BANDIT_COHERENT        0x40
-
-static int __init fixup_one_level_bus_range(struct device_node *node, int higher)
-{
-       for (; node != 0;node = node->sibling) {
-               int * bus_range;
-               unsigned int *class_code;
-               int len;
-
-               /* For PCI<->PCI bridges or CardBus bridges, we go down */
-               class_code = (unsigned int *) get_property(node, "class-code", NULL);
-               if (!class_code || ((*class_code >> 8) != PCI_CLASS_BRIDGE_PCI &&
-                       (*class_code >> 8) != PCI_CLASS_BRIDGE_CARDBUS))
-                       continue;
-               bus_range = (int *) get_property(node, "bus-range", &len);
-               if (bus_range != NULL && len > 2 * sizeof(int)) {
-                       if (bus_range[1] > higher)
-                               higher = bus_range[1];
-               }
-               higher = fixup_one_level_bus_range(node->child, higher);
-       }
-       return higher;
-}
-
-/* This routine fixes the "bus-range" property of all bridges in the
- * system since they tend to have their "last" member wrong on macs
- *
- * Note that the bus numbers manipulated here are OF bus numbers, they
- * are not Linux bus numbers.
- */
-static void __init fixup_bus_range(struct device_node *bridge)
-{
-       int * bus_range;
-       int len;
-
-       /* Lookup the "bus-range" property for the hose */
-       bus_range = (int *) get_property(bridge, "bus-range", &len);
-       if (bus_range == NULL || len < 2 * sizeof(int)) {
-               printk(KERN_WARNING "Can't get bus-range for %s\n",
-                              bridge->full_name);
-               return;
-       }
-       bus_range[1] = fixup_one_level_bus_range(bridge->child, bus_range[1]);
-}
-
-/*
- * Apple MacRISC (U3, UniNorth, Bandit, Chaos) PCI controllers.
- *
- * The "Bandit" version is present in all early PCI PowerMacs,
- * and up to the first ones using Grackle. Some machines may
- * have 2 bandit controllers (2 PCI busses).
- *
- * "Chaos" is used in some "Bandit"-type machines as a bridge
- * for the separate display bus. It is accessed the same
- * way as bandit, but cannot be probed for devices. It therefore
- * has its own config access functions.
- *
- * The "UniNorth" version is present in all Core99 machines
- * (iBook, G4, new IMacs, and all the recent Apple machines).
- * It contains 3 controllers in one ASIC.
- *
- * The U3 is the bridge used on G5 machines. It contains an
- * AGP bus which is dealt with the old UniNorth access routines
- * and a HyperTransport bus which uses its own set of access
- * functions.
- */
-
-#define MACRISC_CFA0(devfn, off)       \
-       ((1 << (unsigned long)PCI_SLOT(dev_fn)) \
-       | (((unsigned long)PCI_FUNC(dev_fn)) << 8) \
-       | (((unsigned long)(off)) & 0xFCUL))
-
-#define MACRISC_CFA1(bus, devfn, off)  \
-       ((((unsigned long)(bus)) << 16) \
-       |(((unsigned long)(devfn)) << 8) \
-       |(((unsigned long)(off)) & 0xFCUL) \
-       |1UL)
-
-static unsigned long macrisc_cfg_access(struct pci_controller* hose,
-                                              u8 bus, u8 dev_fn, u8 offset)
-{
-       unsigned int caddr;
-
-       if (bus == hose->first_busno) {
-               if (dev_fn < (11 << 3))
-                       return 0;
-               caddr = MACRISC_CFA0(dev_fn, offset);
-       } else
-               caddr = MACRISC_CFA1(bus, dev_fn, offset);
-
-       /* Uninorth will return garbage if we don't read back the value ! */
-       do {
-               out_le32(hose->cfg_addr, caddr);
-       } while (in_le32(hose->cfg_addr) != caddr);
-
-       offset &= has_uninorth ? 0x07 : 0x03;
-       return ((unsigned long)hose->cfg_data) + offset;
-}
-
-static int macrisc_read_config(struct pci_bus *bus, unsigned int devfn,
-                                     int offset, int len, u32 *val)
-{
-       struct pci_controller *hose = bus->sysdata;
-       unsigned long addr;
-
-       addr = macrisc_cfg_access(hose, bus->number, devfn, offset);
-       if (!addr)
-               return PCIBIOS_DEVICE_NOT_FOUND;
-       /*
-        * Note: the caller has already checked that offset is
-        * suitably aligned and that len is 1, 2 or 4.
-        */
-       switch (len) {
-       case 1:
-               *val = in_8((u8 *)addr);
-               break;
-       case 2:
-               *val = in_le16((u16 *)addr);
-               break;
-       default:
-               *val = in_le32((u32 *)addr);
-               break;
-       }
-       return PCIBIOS_SUCCESSFUL;
-}
-
-static int macrisc_write_config(struct pci_bus *bus, unsigned int devfn,
-                                      int offset, int len, u32 val)
-{
-       struct pci_controller *hose = bus->sysdata;
-       unsigned long addr;
-
-       addr = macrisc_cfg_access(hose, bus->number, devfn, offset);
-       if (!addr)
-               return PCIBIOS_DEVICE_NOT_FOUND;
-       /*
-        * Note: the caller has already checked that offset is
-        * suitably aligned and that len is 1, 2 or 4.
-        */
-       switch (len) {
-       case 1:
-               out_8((u8 *)addr, val);
-               (void) in_8((u8 *)addr);
-               break;
-       case 2:
-               out_le16((u16 *)addr, val);
-               (void) in_le16((u16 *)addr);
-               break;
-       default:
-               out_le32((u32 *)addr, val);
-               (void) in_le32((u32 *)addr);
-               break;
-       }
-       return PCIBIOS_SUCCESSFUL;
-}
-
-static struct pci_ops macrisc_pci_ops =
-{
-       macrisc_read_config,
-       macrisc_write_config
-};
-
-/*
- * Verifiy that a specific (bus, dev_fn) exists on chaos
- */
-static int
-chaos_validate_dev(struct pci_bus *bus, int devfn, int offset)
-{
-       struct device_node *np;
-       u32 *vendor, *device;
-
-       np = pci_busdev_to_OF_node(bus, devfn);
-       if (np == NULL)
-               return PCIBIOS_DEVICE_NOT_FOUND;
-
-       vendor = (u32 *)get_property(np, "vendor-id", NULL);
-       device = (u32 *)get_property(np, "device-id", NULL);
-       if (vendor == NULL || device == NULL)
-               return PCIBIOS_DEVICE_NOT_FOUND;
-
-       if ((*vendor == 0x106b) && (*device == 3) && (offset >= 0x10)
-           && (offset != 0x14) && (offset != 0x18) && (offset <= 0x24))
-               return PCIBIOS_BAD_REGISTER_NUMBER;
-
-       return PCIBIOS_SUCCESSFUL;
-}
-
-static int
-chaos_read_config(struct pci_bus *bus, unsigned int devfn, int offset,
-                 int len, u32 *val)
-{
-       int result = chaos_validate_dev(bus, devfn, offset);
-       if (result == PCIBIOS_BAD_REGISTER_NUMBER)
-               *val = ~0U;
-       if (result != PCIBIOS_SUCCESSFUL)
-               return result;
-       return macrisc_read_config(bus, devfn, offset, len, val);
-}
-
-static int
-chaos_write_config(struct pci_bus *bus, unsigned int devfn, int offset,
-                  int len, u32 val)
-{
-       int result = chaos_validate_dev(bus, devfn, offset);
-       if (result != PCIBIOS_SUCCESSFUL)
-               return result;
-       return macrisc_write_config(bus, devfn, offset, len, val);
-}
-
-static struct pci_ops chaos_pci_ops =
-{
-       chaos_read_config,
-       chaos_write_config
-};
-
-#ifdef CONFIG_POWER4
-
-/*
- * These versions of U3 HyperTransport config space access ops do not
- * implement self-view of the HT host yet
- */
-
-/*
- * This function deals with some "special cases" devices.
- *
- *  0 -> No special case
- *  1 -> Skip the device but act as if the access was successfull
- *       (return 0xff's on reads, eventually, cache config space
- *       accesses in a later version)
- * -1 -> Hide the device (unsuccessful acess)
- */
-static int u3_ht_skip_device(struct pci_controller *hose,
-                            struct pci_bus *bus, unsigned int devfn)
-{
-       struct device_node *busdn, *dn;
-       int i;
-
-       /* We only allow config cycles to devices that are in OF device-tree
-        * as we are apparently having some weird things going on with some
-        * revs of K2 on recent G5s
-        */
-       if (bus->self)
-               busdn = pci_device_to_OF_node(bus->self);
-       else
-               busdn = hose->arch_data;
-       for (dn = busdn->child; dn; dn = dn->sibling)
-               if (dn->data && PCI_DN(dn)->devfn == devfn)
-                       break;
-       if (dn == NULL)
-               return -1;
-
-       /*
-        * When a device in K2 is powered down, we die on config
-        * cycle accesses. Fix that here.
-        */
-       for (i=0; i<2; i++)
-               if (k2_skiplist[i] == dn)
-                       return 1;
-
-       return 0;
-}
-
-#define U3_HT_CFA0(devfn, off)         \
-               ((((unsigned long)devfn) << 8) | offset)
-#define U3_HT_CFA1(bus, devfn, off)    \
-               (U3_HT_CFA0(devfn, off) \
-               + (((unsigned long)bus) << 16) \
-               + 0x01000000UL)
-
-static unsigned long u3_ht_cfg_access(struct pci_controller* hose,
-                                            u8 bus, u8 devfn, u8 offset)
-{
-       if (bus == hose->first_busno) {
-               /* For now, we don't self probe U3 HT bridge */
-               if (PCI_SLOT(devfn) == 0)
-                       return 0;
-               return ((unsigned long)hose->cfg_data) + U3_HT_CFA0(devfn, offset);
-       } else
-               return ((unsigned long)hose->cfg_data) + U3_HT_CFA1(bus, devfn, offset);
-}
-
-static int u3_ht_read_config(struct pci_bus *bus, unsigned int devfn,
-                                   int offset, int len, u32 *val)
-{
-       struct pci_controller *hose = bus->sysdata;
-       unsigned long addr;
-
-       struct device_node *np = pci_busdev_to_OF_node(bus, devfn);
-       if (np == NULL)
-               return PCIBIOS_DEVICE_NOT_FOUND;
-
-       addr = u3_ht_cfg_access(hose, bus->number, devfn, offset);
-       if (!addr)
-               return PCIBIOS_DEVICE_NOT_FOUND;
-
-       switch (u3_ht_skip_device(hose, bus, devfn)) {
-       case 0:
-               break;
-       case 1:
-                       switch (len) {
-                       case 1:
-                               *val = 0xff; break;
-                       case 2:
-                               *val = 0xffff; break;
-                       default:
-                               *val = 0xfffffffful; break;
-                       }
-                       return PCIBIOS_SUCCESSFUL;
-       default:
-               return PCIBIOS_DEVICE_NOT_FOUND;
-               }
-           
-       /*
-        * Note: the caller has already checked that offset is
-        * suitably aligned and that len is 1, 2 or 4.
-        */
-       switch (len) {
-       case 1:
-               *val = in_8((u8 *)addr);
-               break;
-       case 2:
-               *val = in_le16((u16 *)addr);
-               break;
-       default:
-               *val = in_le32((u32 *)addr);
-               break;
-       }
-       return PCIBIOS_SUCCESSFUL;
-}
-
-static int u3_ht_write_config(struct pci_bus *bus, unsigned int devfn,
-                                    int offset, int len, u32 val)
-{
-       struct pci_controller *hose = bus->sysdata;
-       unsigned long addr;
-
-       struct device_node *np = pci_busdev_to_OF_node(bus, devfn);
-       if (np == NULL)
-               return PCIBIOS_DEVICE_NOT_FOUND;
-
-       addr = u3_ht_cfg_access(hose, bus->number, devfn, offset);
-       if (!addr)
-               return PCIBIOS_DEVICE_NOT_FOUND;
-
-       switch (u3_ht_skip_device(hose, bus, devfn)) {
-       case 0:
-               break;
-       case 1:
-               return PCIBIOS_SUCCESSFUL;
-       default:
-               return PCIBIOS_DEVICE_NOT_FOUND;
-       }
-
-       /*
-        * Note: the caller has already checked that offset is
-        * suitably aligned and that len is 1, 2 or 4.
-        */
-       switch (len) {
-       case 1:
-               out_8((u8 *)addr, val);
-               (void) in_8((u8 *)addr);
-               break;
-       case 2:
-               out_le16((u16 *)addr, val);
-               (void) in_le16((u16 *)addr);
-               break;
-       default:
-               out_le32((u32 *)addr, val);
-               (void) in_le32((u32 *)addr);
-               break;
-       }
-       return PCIBIOS_SUCCESSFUL;
-}
-
-static struct pci_ops u3_ht_pci_ops =
-{
-       u3_ht_read_config,
-       u3_ht_write_config
-};
-
-#endif /* CONFIG_POWER4 */
-
-/*
- * For a bandit bridge, turn on cache coherency if necessary.
- * N.B. we could clean this up using the hose ops directly.
- */
-static void __init
-init_bandit(struct pci_controller *bp)
-{
-       unsigned int vendev, magic;
-       int rev;
-
-       /* read the word at offset 0 in config space for device 11 */
-       out_le32(bp->cfg_addr, (1UL << BANDIT_DEVNUM) + PCI_VENDOR_ID);
-       udelay(2);
-       vendev = in_le32(bp->cfg_data);
-       if (vendev == (PCI_DEVICE_ID_APPLE_BANDIT << 16) +
-                       PCI_VENDOR_ID_APPLE) {
-               /* read the revision id */
-               out_le32(bp->cfg_addr,
-                        (1UL << BANDIT_DEVNUM) + PCI_REVISION_ID);
-               udelay(2);
-               rev = in_8(bp->cfg_data);
-               if (rev != BANDIT_REVID)
-                       printk(KERN_WARNING
-                              "Unknown revision %d for bandit\n", rev);
-       } else if (vendev != (BANDIT_DEVID_2 << 16) + PCI_VENDOR_ID_APPLE) {
-               printk(KERN_WARNING "bandit isn't? (%x)\n", vendev);
-               return;
-       }
-
-       /* read the word at offset 0x50 */
-       out_le32(bp->cfg_addr, (1UL << BANDIT_DEVNUM) + BANDIT_MAGIC);
-       udelay(2);
-       magic = in_le32(bp->cfg_data);
-       if ((magic & BANDIT_COHERENT) != 0)
-               return;
-       magic |= BANDIT_COHERENT;
-       udelay(2);
-       out_le32(bp->cfg_data, magic);
-       printk(KERN_INFO "Cache coherency enabled for bandit/PSX\n");
-}
-
-
-/*
- * Tweak the PCI-PCI bridge chip on the blue & white G3s.
- */
-static void __init
-init_p2pbridge(void)
-{
-       struct device_node *p2pbridge;
-       struct pci_controller* hose;
-       u8 bus, devfn;
-       u16 val;
-
-       /* XXX it would be better here to identify the specific
-          PCI-PCI bridge chip we have. */
-       if ((p2pbridge = find_devices("pci-bridge")) == 0
-           || p2pbridge->parent == NULL
-           || strcmp(p2pbridge->parent->name, "pci") != 0)
-               return;
-       if (pci_device_from_OF_node(p2pbridge, &bus, &devfn) < 0) {
-               DBG("Can't find PCI infos for PCI<->PCI bridge\n");
-               return;
-       }
-       /* Warning: At this point, we have not yet renumbered all busses.
-        * So we must use OF walking to find out hose
-        */
-       hose = pci_find_hose_for_OF_device(p2pbridge);
-       if (!hose) {
-               DBG("Can't find hose for PCI<->PCI bridge\n");
-               return;
-       }
-       if (early_read_config_word(hose, bus, devfn,
-                                  PCI_BRIDGE_CONTROL, &val) < 0) {
-               printk(KERN_ERR "init_p2pbridge: couldn't read bridge control\n");
-               return;
-       }
-       val &= ~PCI_BRIDGE_CTL_MASTER_ABORT;
-       early_write_config_word(hose, bus, devfn, PCI_BRIDGE_CONTROL, val);
-}
-
-/*
- * Some Apple desktop machines have a NEC PD720100A USB2 controller
- * on the motherboard. Open Firmware, on these, will disable the
- * EHCI part of it so it behaves like a pair of OHCI's. This fixup
- * code re-enables it ;)
- */
-static void __init
-fixup_nec_usb2(void)
-{
-       struct device_node *nec;
-
-       for (nec = NULL; (nec = of_find_node_by_name(nec, "usb")) != NULL;) {
-               struct pci_controller *hose;
-               u32 data, *prop;
-               u8 bus, devfn;
-               
-               prop = (u32 *)get_property(nec, "vendor-id", NULL);
-               if (prop == NULL)
-                       continue;
-               if (0x1033 != *prop)
-                       continue;
-               prop = (u32 *)get_property(nec, "device-id", NULL);
-               if (prop == NULL)
-                       continue;
-               if (0x0035 != *prop)
-                       continue;
-               prop = (u32 *)get_property(nec, "reg", NULL);
-               if (prop == NULL)
-                       continue;
-               devfn = (prop[0] >> 8) & 0xff;
-               bus = (prop[0] >> 16) & 0xff;
-               if (PCI_FUNC(devfn) != 0)
-                       continue;
-               hose = pci_find_hose_for_OF_device(nec);
-               if (!hose)
-                       continue;
-               early_read_config_dword(hose, bus, devfn, 0xe4, &data);
-               if (data & 1UL) {
-                       printk("Found NEC PD720100A USB2 chip with disabled EHCI, fixing up...\n");
-                       data &= ~1UL;
-                       early_write_config_dword(hose, bus, devfn, 0xe4, data);
-                       early_write_config_byte(hose, bus, devfn | 2, PCI_INTERRUPT_LINE,
-                               nec->intrs[0].line);
-               }
-       }
-}
-
-void __init
-pmac_find_bridges(void)
-{
-       struct device_node *np, *root;
-       struct device_node *ht = NULL;
-
-       root = of_find_node_by_path("/");
-       if (root == NULL) {
-               printk(KERN_CRIT "pmac_find_bridges: can't find root of device tree\n");
-               return;
-       }
-       for (np = NULL; (np = of_get_next_child(root, np)) != NULL;) {
-               if (np->name == NULL)
-                       continue;
-               if (strcmp(np->name, "bandit") == 0
-                   || strcmp(np->name, "chaos") == 0
-                   || strcmp(np->name, "pci") == 0) {
-                       if (add_bridge(np) == 0)
-                               of_node_get(np);
-               }
-               if (strcmp(np->name, "ht") == 0) {
-                       of_node_get(np);
-                       ht = np;
-               }
-       }
-       of_node_put(root);
-
-       /* Probe HT last as it relies on the agp resources to be already
-        * setup
-        */
-       if (ht && add_bridge(ht) != 0)
-               of_node_put(ht);
-
-       init_p2pbridge();
-       fixup_nec_usb2();
-       
-       /* We are still having some issues with the Xserve G4, enabling
-        * some offset between bus number and domains for now when we
-        * assign all busses should help for now
-        */
-       if (pci_assign_all_busses)
-               pcibios_assign_bus_offset = 0x10;
-
-#ifdef CONFIG_POWER4 
-       /* There is something wrong with DMA on U3/HT. I haven't figured out
-        * the details yet, but if I set the cache line size to 128 bytes like
-        * it should, I'm getting memory corruption caused by devices like
-        * sungem (even without the MWI bit set, but maybe sungem doesn't
-        * care). Right now, it appears that setting up a 64 bytes line size
-        * works properly, 64 bytes beeing the max transfer size of HT, I
-        * suppose this is related the way HT/PCI are hooked together. I still
-        * need to dive into more specs though to be really sure of what's
-        * going on. --BenH.
-        *
-        * Ok, apparently, it's just that HT can't do more than 64 bytes
-        * transactions. MWI seem to be meaningless there as well, it may
-        * be worth nop'ing out pci_set_mwi too though I haven't done that
-        * yet.
-        *
-        * Note that it's a bit different for whatever is in the AGP slot.
-        * For now, I don't care, but this can become a real issue, we
-        * should probably hook pci_set_mwi anyway to make sure it sets
-        * the real cache line size in there.
-        */
-       if (machine_is_compatible("MacRISC4"))
-               pci_cache_line_size = 16; /* 64 bytes */
-
-       pmac_check_ht_link();
-#endif /* CONFIG_POWER4 */
-}
-
-#define GRACKLE_CFA(b, d, o)   (0x80 | ((b) << 8) | ((d) << 16) \
-                                | (((o) & ~3) << 24))
-
-#define GRACKLE_PICR1_STG              0x00000040
-#define GRACKLE_PICR1_LOOPSNOOP                0x00000010
-
-/* N.B. this is called before bridges is initialized, so we can't
-   use grackle_pcibios_{read,write}_config_dword. */
-static inline void grackle_set_stg(struct pci_controller* bp, int enable)
-{
-       unsigned int val;
-
-       out_be32(bp->cfg_addr, GRACKLE_CFA(0, 0, 0xa8));
-       val = in_le32(bp->cfg_data);
-       val = enable? (val | GRACKLE_PICR1_STG) :
-               (val & ~GRACKLE_PICR1_STG);
-       out_be32(bp->cfg_addr, GRACKLE_CFA(0, 0, 0xa8));
-       out_le32(bp->cfg_data, val);
-       (void)in_le32(bp->cfg_data);
-}
-
-static inline void grackle_set_loop_snoop(struct pci_controller *bp, int enable)
-{
-       unsigned int val;
-
-       out_be32(bp->cfg_addr, GRACKLE_CFA(0, 0, 0xa8));
-       val = in_le32(bp->cfg_data);
-       val = enable? (val | GRACKLE_PICR1_LOOPSNOOP) :
-               (val & ~GRACKLE_PICR1_LOOPSNOOP);
-       out_be32(bp->cfg_addr, GRACKLE_CFA(0, 0, 0xa8));
-       out_le32(bp->cfg_data, val);
-       (void)in_le32(bp->cfg_data);
-}
-
-static int __init
-setup_uninorth(struct pci_controller* hose, struct reg_property* addr)
-{
-       pci_assign_all_busses = 1;
-       has_uninorth = 1;
-       hose->ops = &macrisc_pci_ops;
-       hose->cfg_addr = ioremap(addr->address + 0x800000, 0x1000);
-       hose->cfg_data = ioremap(addr->address + 0xc00000, 0x1000);
-       /* We "know" that the bridge at f2000000 has the PCI slots. */
-       return addr->address == 0xf2000000;
-}
-
-static void __init
-setup_bandit(struct pci_controller* hose, struct reg_property* addr)
-{
-       hose->ops = &macrisc_pci_ops;
-       hose->cfg_addr = ioremap(addr->address + 0x800000, 0x1000);
-       hose->cfg_data = ioremap(addr->address + 0xc00000, 0x1000);
-       init_bandit(hose);
-}
-
-static void __init
-setup_chaos(struct pci_controller* hose, struct reg_property* addr)
-{
-       /* assume a `chaos' bridge */
-       hose->ops = &chaos_pci_ops;
-       hose->cfg_addr = ioremap(addr->address + 0x800000, 0x1000);
-       hose->cfg_data = ioremap(addr->address + 0xc00000, 0x1000);
-}
-
-#ifdef CONFIG_POWER4
-
-static void __init setup_u3_agp(struct pci_controller* hose)
-{
-       /* On G5, we move AGP up to high bus number so we don't need
-        * to reassign bus numbers for HT. If we ever have P2P bridges
-        * on AGP, we'll have to move pci_assign_all_busses to the
-        * pci_controller structure so we enable it for AGP and not for
-        * HT childs.
-        * We hard code the address because of the different size of
-        * the reg address cell, we shall fix that by killing struct
-        * reg_property and using some accessor functions instead
-        */
-               hose->first_busno = 0xf0;
-       hose->last_busno = 0xff;
-       has_uninorth = 1;
-       hose->ops = &macrisc_pci_ops;
-       hose->cfg_addr = ioremap(0xf0000000 + 0x800000, 0x1000);
-       hose->cfg_data = ioremap(0xf0000000 + 0xc00000, 0x1000);
-
-       u3_agp = hose;
-}
-
-static void __init setup_u3_ht(struct pci_controller* hose)
-{
-       struct device_node *np = (struct device_node *)hose->arch_data;
-       int i, cur;
-
-       hose->ops = &u3_ht_pci_ops;
-
-       /* We hard code the address because of the different size of
-        * the reg address cell, we shall fix that by killing struct
-        * reg_property and using some accessor functions instead
-        */
-       hose->cfg_data = (volatile unsigned char *)ioremap(0xf2000000, 0x02000000);
-
-       /*
-        * /ht node doesn't expose a "ranges" property, so we "remove" regions that
-        * have been allocated to AGP. So far, this version of the code doesn't assign
-        * any of the 0xfxxxxxxx "fine" memory regions to /ht.
-        * We need to fix that sooner or later by either parsing all child "ranges"
-        * properties or figuring out the U3 address space decoding logic and
-        * then read its configuration register (if any).
-        */
-       hose->io_base_phys = 0xf4000000;
-       hose->io_base_virt = ioremap(hose->io_base_phys, 0x00400000);
-       isa_io_base = (unsigned long) hose->io_base_virt;
-       hose->io_resource.name = np->full_name;
-       hose->io_resource.start = 0;
-       hose->io_resource.end = 0x003fffff;
-       hose->io_resource.flags = IORESOURCE_IO;
-       hose->pci_mem_offset = 0;
-       hose->first_busno = 0;
-       hose->last_busno = 0xef;
-       hose->mem_resources[0].name = np->full_name;
-       hose->mem_resources[0].start = 0x80000000;
-       hose->mem_resources[0].end = 0xefffffff;
-       hose->mem_resources[0].flags = IORESOURCE_MEM;
-
-       if (u3_agp == NULL) {
-               DBG("U3 has no AGP, using full resource range\n");
-               return;
-       }
-
-       /* We "remove" the AGP resources from the resources allocated to HT, that
-        * is we create "holes". However, that code does assumptions that so far
-        * happen to be true (cross fingers...), typically that resources in the
-        * AGP node are properly ordered
-        */
-       cur = 0;
-       for (i=0; i<3; i++) {
-               struct resource *res = &u3_agp->mem_resources[i];
-               if (res->flags != IORESOURCE_MEM)
-                       continue;
-               /* We don't care about "fine" resources */
-               if (res->start >= 0xf0000000)
-                       continue;
-               /* Check if it's just a matter of "shrinking" us in one direction */
-               if (hose->mem_resources[cur].start == res->start) {
-                       DBG("U3/HT: shrink start of %d, %08lx -> %08lx\n",
-                           cur, hose->mem_resources[cur].start, res->end + 1);
-                       hose->mem_resources[cur].start = res->end + 1;
-                       continue;
-               }
-               if (hose->mem_resources[cur].end == res->end) {
-                       DBG("U3/HT: shrink end of %d, %08lx -> %08lx\n",
-                           cur, hose->mem_resources[cur].end, res->start - 1);
-                       hose->mem_resources[cur].end = res->start - 1;
-                       continue;
-               }
-               /* No, it's not the case, we need a hole */
-               if (cur == 2) {
-                       /* not enough resources to make a hole, we drop part of the range */
-                       printk(KERN_WARNING "Running out of resources for /ht host !\n");
-                       hose->mem_resources[cur].end = res->start - 1;
-                       continue;
-               }               
-               cur++;
-                       DBG("U3/HT: hole, %d end at %08lx, %d start at %08lx\n",
-                   cur-1, res->start - 1, cur, res->end + 1);
-               hose->mem_resources[cur].name = np->full_name;
-               hose->mem_resources[cur].flags = IORESOURCE_MEM;
-               hose->mem_resources[cur].start = res->end + 1;
-               hose->mem_resources[cur].end = hose->mem_resources[cur-1].end;
-               hose->mem_resources[cur-1].end = res->start - 1;
-       }
-}
-
-#endif /* CONFIG_POWER4 */
-
-void __init
-setup_grackle(struct pci_controller *hose)
-{
-       setup_indirect_pci(hose, 0xfec00000, 0xfee00000);
-       if (machine_is_compatible("AAPL,PowerBook1998"))
-               grackle_set_loop_snoop(hose, 1);
-#if 0  /* Disabled for now, HW problems ??? */
-       grackle_set_stg(hose, 1);
-#endif
-}
-
-static void __init pmac_process_bridge_OF_ranges(struct pci_controller *hose,
-                          struct device_node *dev, int primary)
-{
-       static unsigned int static_lc_ranges[2024];
-       unsigned int *dt_ranges, *lc_ranges, *ranges, *prev;
-       unsigned int size;
-       int rlen = 0, orig_rlen;
-       int memno = 0;
-       struct resource *res;
-       int np, na = prom_n_addr_cells(dev);
-
-       np = na + 5;
-
-       /* First we try to merge ranges to fix a problem with some pmacs
-        * that can have more than 3 ranges, fortunately using contiguous
-        * addresses -- BenH
-        */
-       dt_ranges = (unsigned int *) get_property(dev, "ranges", &rlen);
-       if (!dt_ranges)
-               return;
-       /*      lc_ranges = alloc_bootmem(rlen);*/
-       lc_ranges = static_lc_ranges;
-       if (!lc_ranges)
-               return; /* what can we do here ? */
-       memcpy(lc_ranges, dt_ranges, rlen);
-       orig_rlen = rlen;
-
-       /* Let's work on a copy of the "ranges" property instead of damaging
-        * the device-tree image in memory
-        */
-       ranges = lc_ranges;
-       prev = NULL;
-       while ((rlen -= np * sizeof(unsigned int)) >= 0) {
-               if (prev) {
-                       if (prev[0] == ranges[0] && prev[1] == ranges[1] &&
-                               (prev[2] + prev[na+4]) == ranges[2] &&
-                               (prev[na+2] + prev[na+4]) == ranges[na+2]) {
-                               prev[na+4] += ranges[na+4];
-                               ranges[0] = 0;
-                               ranges += np;
-                               continue;
-                       }
-               }
-               prev = ranges;
-               ranges += np;
-       }
-
-       /*
-        * The ranges property is laid out as an array of elements,
-        * each of which comprises:
-        *   cells 0 - 2:       a PCI address
-        *   cells 3 or 3+4:    a CPU physical address
-        *                      (size depending on dev->n_addr_cells)
-        *   cells 4+5 or 5+6:  the size of the range
-        */
-       ranges = lc_ranges;
-       rlen = orig_rlen;
-       while (ranges && (rlen -= np * sizeof(unsigned int)) >= 0) {
-               res = NULL;
-               size = ranges[na+4];
-               switch (ranges[0] >> 24) {
-               case 1:         /* I/O space */
-                       if (ranges[2] != 0)
-                               break;
-                       hose->io_base_phys = ranges[na+2];
-                       /* limit I/O space to 16MB */
-                       if (size > 0x01000000)
-                               size = 0x01000000;
-                       hose->io_base_virt = ioremap(ranges[na+2], size);
-                       if (primary)
-                               isa_io_base = (unsigned long) hose->io_base_virt;
-                       res = &hose->io_resource;
-                       res->flags = IORESOURCE_IO;
-                       res->start = ranges[2];
-                       break;
-               case 2:         /* memory space */
-                       memno = 0;
-                       if (ranges[1] == 0 && ranges[2] == 0
-                           && ranges[na+4] <= (16 << 20)) {
-                               /* 1st 16MB, i.e. ISA memory area */
-#if 0
-                               if (primary)
-                                       isa_mem_base = ranges[na+2];
-#endif
-                               memno = 1;
-                       }
-                       while (memno < 3 && hose->mem_resources[memno].flags)
-                               ++memno;
-                       if (memno == 0)
-                               hose->pci_mem_offset = ranges[na+2] - ranges[2];
-                       if (memno < 3) {
-                               res = &hose->mem_resources[memno];
-                               res->flags = IORESOURCE_MEM;
-                               res->start = ranges[na+2];
-                       }
-                       break;
-               }
-               if (res != NULL) {
-                       res->name = dev->full_name;
-                       res->end = res->start + size - 1;
-                       res->parent = NULL;
-                       res->sibling = NULL;
-                       res->child = NULL;
-               }
-               ranges += np;
-       }
-}
-
-/*
- * We assume that if we have a G3 powermac, we have one bridge called
- * "pci" (a MPC106) and no bandit or chaos bridges, and contrariwise,
- * if we have one or more bandit or chaos bridges, we don't have a MPC106.
- */
-static int __init add_bridge(struct device_node *dev)
-{
-       int len;
-       struct pci_controller *hose;
-       struct reg_property *addr;
-       char* disp_name;
-       int *bus_range;
-       int primary = 1;
-
-       DBG("Adding PCI host bridge %s\n", dev->full_name);
-
-               addr = (struct reg_property *) get_property(dev, "reg", &len);
-               if (addr == NULL || len < sizeof(*addr)) {
-                       printk(KERN_WARNING "Can't use %s: no address\n",
-                              dev->full_name);
-                       return -ENODEV;
-               }
-               bus_range = (int *) get_property(dev, "bus-range", &len);
-               if (bus_range == NULL || len < 2 * sizeof(int)) {
-                       printk(KERN_WARNING "Can't get bus-range for %s, assume bus 0\n",
-                                      dev->full_name);
-               }
-
-               hose = pcibios_alloc_controller();
-               if (!hose)
-                       return -ENOMEM;
-               hose->arch_data = dev;
-               hose->first_busno = bus_range ? bus_range[0] : 0;
-               hose->last_busno = bus_range ? bus_range[1] : 0xff;
-
-       disp_name = NULL;
-#ifdef CONFIG_POWER4
-               if (device_is_compatible(dev, "u3-agp")) {
-                       setup_u3_agp(hose, addr);
-                       disp_name = "U3-AGP";
-                       primary = 0;
-               } else if (device_is_compatible(dev, "u3-ht")) {
-                       setup_u3_ht(hose, addr);
-                       disp_name = "U3-HT";
-                       primary = 1;
-               } else
-#endif /* CONFIG_POWER4 */
-       if (device_is_compatible(dev, "uni-north")) {
-                       primary = setup_uninorth(hose, addr);
-                       disp_name = "UniNorth";
-               } else if (strcmp(dev->name, "pci") == 0) {
-                       /* XXX assume this is a mpc106 (grackle) */
-                       setup_grackle(hose);
-                       disp_name = "Grackle (MPC106)";
-               } else if (strcmp(dev->name, "bandit") == 0) {
-                       setup_bandit(hose, addr);
-                       disp_name = "Bandit";
-               } else if (strcmp(dev->name, "chaos") == 0) {
-                       setup_chaos(hose, addr);
-                       disp_name = "Chaos";
-                       primary = 0;
-               }
-               printk(KERN_INFO "Found %s PCI host bridge at 0x%08x. Firmware bus number: %d->%d\n",
-                       disp_name, addr->address, hose->first_busno, hose->last_busno);
-               DBG(" ->Hose at 0x%p, cfg_addr=0x%p,cfg_data=0x%p\n",
-                       hose, hose->cfg_addr, hose->cfg_data);
-
-               /* Interpret the "ranges" property */
-               /* This also maps the I/O region and sets isa_io/mem_base */
-               pci_process_bridge_OF_ranges(hose, dev, primary);
-
-               /* Fixup "bus-range" OF property */
-               fixup_bus_range(dev);
-
-       return 0;
-}
-
-static void __init
-pcibios_fixup_OF_interrupts(void)
-{
-       struct pci_dev* dev = NULL;
-
-       /*
-        * Open Firmware often doesn't initialize the
-        * PCI_INTERRUPT_LINE config register properly, so we
-        * should find the device node and apply the interrupt
-        * obtained from the OF device-tree
-        */
-       for_each_pci_dev(dev) {
-               struct device_node *node;
-               node = pci_device_to_OF_node(dev);
-               /* this is the node, see if it has interrupts */
-               if (node && node->n_intrs > 0)
-                       dev->irq = node->intrs[0].line;
-               pci_write_config_byte(dev, PCI_INTERRUPT_LINE, dev->irq);
-       }
-}
-
-void __init
-pmac_pcibios_fixup(void)
-{
-       /* Fixup interrupts according to OF tree */
-       pcibios_fixup_OF_interrupts();
-}
-
-int
-pmac_pci_enable_device_hook(struct pci_dev *dev, int initial)
-{
-       struct device_node* node;
-       int updatecfg = 0;
-       int uninorth_child;
-
-       node = pci_device_to_OF_node(dev);
-
-       /* We don't want to enable USB controllers absent from the OF tree
-        * (iBook second controller)
-        */
-       if (dev->vendor == PCI_VENDOR_ID_APPLE
-           && (dev->class == ((PCI_CLASS_SERIAL_USB << 8) | 0x10))
-           && !node) {
-               printk(KERN_INFO "Apple USB OHCI %s disabled by firmware\n",
-                      pci_name(dev));
-               return -EINVAL;
-       }
-
-       if (!node)
-               return 0;
-
-       uninorth_child = node->parent &&
-               device_is_compatible(node->parent, "uni-north");
-       
-       /* Firewire & GMAC were disabled after PCI probe, the driver is
-        * claiming them, we must re-enable them now.
-        */
-       if (uninorth_child && !strcmp(node->name, "firewire") &&
-           (device_is_compatible(node, "pci106b,18") ||
-            device_is_compatible(node, "pci106b,30") ||
-            device_is_compatible(node, "pci11c1,5811"))) {
-               pmac_call_feature(PMAC_FTR_1394_CABLE_POWER, node, 0, 1);
-               pmac_call_feature(PMAC_FTR_1394_ENABLE, node, 0, 1);
-               updatecfg = 1;
-       }
-       if (uninorth_child && !strcmp(node->name, "ethernet") &&
-           device_is_compatible(node, "gmac")) {
-               pmac_call_feature(PMAC_FTR_GMAC_ENABLE, node, 0, 1);
-               updatecfg = 1;
-       }
-
-       if (updatecfg) {
-               u16 cmd;
-       
-               /*
-                * Make sure PCI is correctly configured
-                *
-                * We use old pci_bios versions of the function since, by
-                * default, gmac is not powered up, and so will be absent
-                * from the kernel initial PCI lookup.
-                *
-                * Should be replaced by 2.4 new PCI mechanisms and really
-                * register the device.
-                */
-               pci_read_config_word(dev, PCI_COMMAND, &cmd);
-               cmd |= PCI_COMMAND_MEMORY | PCI_COMMAND_MASTER | PCI_COMMAND_INVALIDATE;
-               pci_write_config_word(dev, PCI_COMMAND, cmd);
-               pci_write_config_byte(dev, PCI_LATENCY_TIMER, 16);
-               pci_write_config_byte(dev, PCI_CACHE_LINE_SIZE, pci_cache_line_size);
-       }
-
-       return 0;
-}
-
-/* We power down some devices after they have been probed. They'll
- * be powered back on later on
- */
-void __init
-pmac_pcibios_after_init(void)
-{
-       struct device_node* nd;
-
-#ifdef CONFIG_BLK_DEV_IDE
-       struct pci_dev *dev = NULL;
-
-       /* OF fails to initialize IDE controllers on macs
-        * (and maybe other machines)
-        *
-        * Ideally, this should be moved to the IDE layer, but we need
-        * to check specifically with Andre Hedrick how to do it cleanly
-        * since the common IDE code seem to care about the fact that the
-        * BIOS may have disabled a controller.
-        *
-        * -- BenH
-        */
-       for_each_pci_dev(dev) {
-               if ((dev->class >> 16) == PCI_BASE_CLASS_STORAGE)
-                       pci_enable_device(dev);
-       }
-#endif /* CONFIG_BLK_DEV_IDE */
-
-       nd = find_devices("firewire");
-       while (nd) {
-               if (nd->parent && (device_is_compatible(nd, "pci106b,18") ||
-                                  device_is_compatible(nd, "pci106b,30") ||
-                                  device_is_compatible(nd, "pci11c1,5811"))
-                   && device_is_compatible(nd->parent, "uni-north")) {
-                       pmac_call_feature(PMAC_FTR_1394_ENABLE, nd, 0, 0);
-                       pmac_call_feature(PMAC_FTR_1394_CABLE_POWER, nd, 0, 0);
-               }
-               nd = nd->next;
-       }
-       nd = find_devices("ethernet");
-       while (nd) {
-               if (nd->parent && device_is_compatible(nd, "gmac")
-                   && device_is_compatible(nd->parent, "uni-north"))
-                       pmac_call_feature(PMAC_FTR_GMAC_ENABLE, nd, 0, 0);
-               nd = nd->next;
-       }
-}
-
-#ifdef CONFIG_PPC64
-static void __init pmac_fixup_phb_resources(void)
-{
-       struct pci_controller *hose, *tmp;
-       
-       list_for_each_entry_safe(hose, tmp, &hose_list, list_node) {
-               unsigned long offset = (unsigned long)hose->io_base_virt - pci_io_base;
-               hose->io_resource.start += offset;
-               hose->io_resource.end += offset;
-               printk(KERN_INFO "PCI Host %d, io start: %lx; io end: %lx\n",
-                      hose->global_number,
-                      hose->io_resource.start, hose->io_resource.end);
-       }
-}
-
-void __init pmac_pci_init(void)
-{
-       struct device_node *np, *root;
-       struct device_node *ht = NULL;
-
-       /* Probe root PCI hosts, that is on U3 the AGP host and the
-        * HyperTransport host. That one is actually "kept" around
-        * and actually added last as it's resource management relies
-        * on the AGP resources to have been setup first
-        */
-       root = of_find_node_by_path("/");
-       if (root == NULL) {
-               printk(KERN_CRIT "pmac_find_bridges: can't find root of device tree\n");
-               return;
-       }
-       for (np = NULL; (np = of_get_next_child(root, np)) != NULL;) {
-               if (np->name == NULL)
-                       continue;
-               if (strcmp(np->name, "pci") == 0) {
-                       if (add_bridge(np) == 0)
-                               of_node_get(np);
-               }
-               if (strcmp(np->name, "ht") == 0) {
-                       of_node_get(np);
-                       ht = np;
-               }
-       }
-       of_node_put(root);
-
-       /* Now setup the HyperTransport host if we found any
-        */
-       if (ht && add_bridge(ht) != 0)
-               of_node_put(ht);
-
-       /* Fixup the IO resources on our host bridges as the common code
-        * does it only for childs of the host bridges
-        */
-       pmac_fixup_phb_resources();
-
-       /* Setup the linkage between OF nodes and PHBs */ 
-       pci_devs_phb_init();
-
-       /* Fixup the PCI<->OF mapping for U3 AGP due to bus renumbering. We
-        * assume there is no P2P bridge on the AGP bus, which should be a
-        * safe assumptions hopefully.
-        */
-       if (u3_agp) {
-               struct device_node *np = u3_agp->arch_data;
-               PCI_DN(np)->busno = 0xf0;
-               for (np = np->child; np; np = np->sibling)
-                       PCI_DN(np)->busno = 0xf0;
-       }
-
-       pmac_check_ht_link();
-
-       /* Tell pci.c to not use the common resource allocation mecanism */
-       pci_probe_only = 1;
-       
-       /* Allow all IO */
-       io_page_mask = -1;
-}
-#endif
-
-#ifdef CONFIG_PPC32
-void pmac_pci_fixup_cardbus(struct pci_dev* dev)
-{
-       if (_machine != _MACH_Pmac)
-               return;
-       /*
-        * Fix the interrupt routing on the various cardbus bridges
-        * used on powerbooks
-        */
-       if (dev->vendor != PCI_VENDOR_ID_TI)
-               return;
-       if (dev->device == PCI_DEVICE_ID_TI_1130 ||
-           dev->device == PCI_DEVICE_ID_TI_1131) {
-               u8 val;
-               /* Enable PCI interrupt */
-               if (pci_read_config_byte(dev, 0x91, &val) == 0)
-                       pci_write_config_byte(dev, 0x91, val | 0x30);
-               /* Disable ISA interrupt mode */
-               if (pci_read_config_byte(dev, 0x92, &val) == 0)
-                       pci_write_config_byte(dev, 0x92, val & ~0x06);
-       }
-       if (dev->device == PCI_DEVICE_ID_TI_1210 ||
-           dev->device == PCI_DEVICE_ID_TI_1211 ||
-           dev->device == PCI_DEVICE_ID_TI_1410 ||
-           dev->device == PCI_DEVICE_ID_TI_1510) {
-               u8 val;
-               /* 0x8c == TI122X_IRQMUX, 2 says to route the INTA
-                  signal out the MFUNC0 pin */
-               if (pci_read_config_byte(dev, 0x8c, &val) == 0)
-                       pci_write_config_byte(dev, 0x8c, (val & ~0x0f) | 2);
-               /* Disable ISA interrupt mode */
-               if (pci_read_config_byte(dev, 0x92, &val) == 0)
-                       pci_write_config_byte(dev, 0x92, val & ~0x06);
-       }
-}
-
-DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_TI, PCI_ANY_ID, pmac_pci_fixup_cardbus);
-
-void pmac_pci_fixup_pciata(struct pci_dev* dev)
-{
-       u8 progif = 0;
-
-       /*
-        * On PowerMacs, we try to switch any PCI ATA controller to
-       * fully native mode
-        */
-       if (_machine != _MACH_Pmac)
-               return;
-       /* Some controllers don't have the class IDE */
-       if (dev->vendor == PCI_VENDOR_ID_PROMISE)
-               switch(dev->device) {
-               case PCI_DEVICE_ID_PROMISE_20246:
-               case PCI_DEVICE_ID_PROMISE_20262:
-               case PCI_DEVICE_ID_PROMISE_20263:
-               case PCI_DEVICE_ID_PROMISE_20265:
-               case PCI_DEVICE_ID_PROMISE_20267:
-               case PCI_DEVICE_ID_PROMISE_20268:
-               case PCI_DEVICE_ID_PROMISE_20269:
-               case PCI_DEVICE_ID_PROMISE_20270:
-               case PCI_DEVICE_ID_PROMISE_20271:
-               case PCI_DEVICE_ID_PROMISE_20275:
-               case PCI_DEVICE_ID_PROMISE_20276:
-               case PCI_DEVICE_ID_PROMISE_20277:
-                       goto good;
-               }
-       /* Others, check PCI class */
-       if ((dev->class >> 8) != PCI_CLASS_STORAGE_IDE)
-               return;
- good:
-       pci_read_config_byte(dev, PCI_CLASS_PROG, &progif);
-       if ((progif & 5) != 5) {
-               printk(KERN_INFO "Forcing PCI IDE into native mode: %s\n", pci_name(dev));
-               (void) pci_write_config_byte(dev, PCI_CLASS_PROG, progif|5);
-               if (pci_read_config_byte(dev, PCI_CLASS_PROG, &progif) ||
-                   (progif & 5) != 5)
-                       printk(KERN_ERR "Rewrite of PROGIF failed !\n");
-       }
-}
-DECLARE_PCI_FIXUP_FINAL(PCI_ANY_ID, PCI_ANY_ID, pmac_pci_fixup_pciata);
-#endif
-
-/*
- * Disable second function on K2-SATA, it's broken
- * and disable IO BARs on first one
- */
-static void fixup_k2_sata(struct pci_dev* dev)
-{
-       int i;
-       u16 cmd;
-
-       if (PCI_FUNC(dev->devfn) > 0) {
-               pci_read_config_word(dev, PCI_COMMAND, &cmd);
-               cmd &= ~(PCI_COMMAND_IO | PCI_COMMAND_MEMORY);
-               pci_write_config_word(dev, PCI_COMMAND, cmd);
-               for (i = 0; i < 6; i++) {
-                       dev->resource[i].start = dev->resource[i].end = 0;
-                       dev->resource[i].flags = 0;
-                       pci_write_config_dword(dev, PCI_BASE_ADDRESS_0 + 4 * i, 0);
-               }
-       } else {
-               pci_read_config_word(dev, PCI_COMMAND, &cmd);
-               cmd &= ~PCI_COMMAND_IO;
-               pci_write_config_word(dev, PCI_COMMAND, cmd);
-               for (i = 0; i < 5; i++) {
-                       dev->resource[i].start = dev->resource[i].end = 0;
-                       dev->resource[i].flags = 0;
-                       pci_write_config_dword(dev, PCI_BASE_ADDRESS_0 + 4 * i, 0);
-               }
-       }
-}
-DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_SERVERWORKS, 0x0240, fixup_k2_sata);
-
diff --git a/arch/powerpc/platforms/powermac/pmac_pic.c b/arch/powerpc/platforms/powermac/pmac_pic.c
deleted file mode 100644 (file)
index 7ddd526..0000000
+++ /dev/null
@@ -1,673 +0,0 @@
-/*
- *  Support for the interrupt controllers found on Power Macintosh,
- *  currently Apple's "Grand Central" interrupt controller in all
- *  it's incarnations. OpenPIC support used on newer machines is
- *  in a separate file
- *
- *  Copyright (C) 1997 Paul Mackerras (paulus@samba.org)
- *
- *  Maintained by Benjamin Herrenschmidt (benh@kernel.crashing.org)
- *
- *  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.
- *
- */
-
-#include <linux/config.h>
-#include <linux/stddef.h>
-#include <linux/init.h>
-#include <linux/sched.h>
-#include <linux/signal.h>
-#include <linux/pci.h>
-#include <linux/interrupt.h>
-#include <linux/sysdev.h>
-#include <linux/adb.h>
-#include <linux/pmu.h>
-
-#include <asm/sections.h>
-#include <asm/io.h>
-#include <asm/smp.h>
-#include <asm/prom.h>
-#include <asm/pci-bridge.h>
-#include <asm/time.h>
-#include <asm/open_pic.h>
-#include <asm/xmon.h>
-#include <asm/pmac_feature.h>
-#include <asm/mpic.h>
-
-#include "pmac_pic.h"
-
-/*
- * XXX this should be in xmon.h, but putting it there means xmon.h
- * has to include <linux/interrupt.h> (to get irqreturn_t), which
- * causes all sorts of problems.  -- paulus
- */
-extern irqreturn_t xmon_irq(int, void *, struct pt_regs *);
-
-struct pmac_irq_hw {
-        unsigned int    event;
-        unsigned int    enable;
-        unsigned int    ack;
-        unsigned int    level;
-};
-
-/* Default addresses */
-static volatile struct pmac_irq_hw *pmac_irq_hw[4] = {
-        (struct pmac_irq_hw *) 0xf3000020,
-        (struct pmac_irq_hw *) 0xf3000010,
-        (struct pmac_irq_hw *) 0xf4000020,
-        (struct pmac_irq_hw *) 0xf4000010,
-};
-
-#define GC_LEVEL_MASK          0x3ff00000
-#define OHARE_LEVEL_MASK       0x1ff00000
-#define HEATHROW_LEVEL_MASK    0x1ff00000
-
-static int max_irqs;
-static int max_real_irqs;
-static u32 level_mask[4];
-
-static DEFINE_SPINLOCK(pmac_pic_lock);
-
-
-#define GATWICK_IRQ_POOL_SIZE        10
-static struct interrupt_info gatwick_int_pool[GATWICK_IRQ_POOL_SIZE];
-
-/*
- * Mark an irq as "lost".  This is only used on the pmac
- * since it can lose interrupts (see pmac_set_irq_mask).
- * -- Cort
- */
-void
-__set_lost(unsigned long irq_nr, int nokick)
-{
-       if (!test_and_set_bit(irq_nr, ppc_lost_interrupts)) {
-               atomic_inc(&ppc_n_lost_interrupts);
-               if (!nokick)
-                       set_dec(1);
-       }
-}
-
-static void
-pmac_mask_and_ack_irq(unsigned int irq_nr)
-{
-        unsigned long bit = 1UL << (irq_nr & 0x1f);
-        int i = irq_nr >> 5;
-        unsigned long flags;
-
-        if ((unsigned)irq_nr >= max_irqs)
-                return;
-
-        clear_bit(irq_nr, ppc_cached_irq_mask);
-        if (test_and_clear_bit(irq_nr, ppc_lost_interrupts))
-                atomic_dec(&ppc_n_lost_interrupts);
-       spin_lock_irqsave(&pmac_pic_lock, flags);
-        out_le32(&pmac_irq_hw[i]->enable, ppc_cached_irq_mask[i]);
-        out_le32(&pmac_irq_hw[i]->ack, bit);
-        do {
-                /* make sure ack gets to controller before we enable
-                   interrupts */
-                mb();
-        } while((in_le32(&pmac_irq_hw[i]->enable) & bit)
-                != (ppc_cached_irq_mask[i] & bit));
-       spin_unlock_irqrestore(&pmac_pic_lock, flags);
-}
-
-static void pmac_set_irq_mask(unsigned int irq_nr, int nokicklost)
-{
-        unsigned long bit = 1UL << (irq_nr & 0x1f);
-        int i = irq_nr >> 5;
-        unsigned long flags;
-
-        if ((unsigned)irq_nr >= max_irqs)
-                return;
-
-       spin_lock_irqsave(&pmac_pic_lock, flags);
-        /* enable unmasked interrupts */
-        out_le32(&pmac_irq_hw[i]->enable, ppc_cached_irq_mask[i]);
-
-        do {
-                /* make sure mask gets to controller before we
-                   return to user */
-                mb();
-        } while((in_le32(&pmac_irq_hw[i]->enable) & bit)
-                != (ppc_cached_irq_mask[i] & bit));
-
-        /*
-         * Unfortunately, setting the bit in the enable register
-         * when the device interrupt is already on *doesn't* set
-         * the bit in the flag register or request another interrupt.
-         */
-        if (bit & ppc_cached_irq_mask[i] & in_le32(&pmac_irq_hw[i]->level))
-               __set_lost((ulong)irq_nr, nokicklost);
-       spin_unlock_irqrestore(&pmac_pic_lock, flags);
-}
-
-/* When an irq gets requested for the first client, if it's an
- * edge interrupt, we clear any previous one on the controller
- */
-static unsigned int pmac_startup_irq(unsigned int irq_nr)
-{
-        unsigned long bit = 1UL << (irq_nr & 0x1f);
-        int i = irq_nr >> 5;
-
-       if ((irq_desc[irq_nr].status & IRQ_LEVEL) == 0)
-               out_le32(&pmac_irq_hw[i]->ack, bit);
-        set_bit(irq_nr, ppc_cached_irq_mask);
-        pmac_set_irq_mask(irq_nr, 0);
-
-       return 0;
-}
-
-static void pmac_mask_irq(unsigned int irq_nr)
-{
-        clear_bit(irq_nr, ppc_cached_irq_mask);
-        pmac_set_irq_mask(irq_nr, 0);
-        mb();
-}
-
-static void pmac_unmask_irq(unsigned int irq_nr)
-{
-        set_bit(irq_nr, ppc_cached_irq_mask);
-        pmac_set_irq_mask(irq_nr, 0);
-}
-
-static void pmac_end_irq(unsigned int irq_nr)
-{
-       if (!(irq_desc[irq_nr].status & (IRQ_DISABLED|IRQ_INPROGRESS))
-           && irq_desc[irq_nr].action) {
-               set_bit(irq_nr, ppc_cached_irq_mask);
-               pmac_set_irq_mask(irq_nr, 1);
-       }
-}
-
-
-struct hw_interrupt_type pmac_pic = {
-       .typename       = " PMAC-PIC ",
-       .startup        = pmac_startup_irq,
-       .enable         = pmac_unmask_irq,
-       .disable        = pmac_mask_irq,
-       .ack            = pmac_mask_and_ack_irq,
-       .end            = pmac_end_irq,
-};
-
-struct hw_interrupt_type gatwick_pic = {
-       .typename       = " GATWICK  ",
-       .startup        = pmac_startup_irq,
-       .enable         = pmac_unmask_irq,
-       .disable        = pmac_mask_irq,
-       .ack            = pmac_mask_and_ack_irq,
-       .end            = pmac_end_irq,
-};
-
-static irqreturn_t gatwick_action(int cpl, void *dev_id, struct pt_regs *regs)
-{
-       int irq, bits;
-
-       for (irq = max_irqs; (irq -= 32) >= max_real_irqs; ) {
-               int i = irq >> 5;
-               bits = in_le32(&pmac_irq_hw[i]->event) | ppc_lost_interrupts[i];
-               /* We must read level interrupts from the level register */
-               bits |= (in_le32(&pmac_irq_hw[i]->level) & level_mask[i]);
-               bits &= ppc_cached_irq_mask[i];
-               if (bits == 0)
-                       continue;
-               irq += __ilog2(bits);
-               __do_IRQ(irq, regs);
-               return IRQ_HANDLED;
-       }
-       printk("gatwick irq not from gatwick pic\n");
-       return IRQ_NONE;
-}
-
-int
-pmac_get_irq(struct pt_regs *regs)
-{
-       int irq;
-       unsigned long bits = 0;
-
-#ifdef CONFIG_SMP
-       void psurge_smp_message_recv(struct pt_regs *);
-
-               /* IPI's are a hack on the powersurge -- Cort */
-               if ( smp_processor_id() != 0 ) {
-               psurge_smp_message_recv(regs);
-               return -2;      /* ignore, already handled */
-        }
-#endif /* CONFIG_SMP */
-       for (irq = max_real_irqs; (irq -= 32) >= 0; ) {
-               int i = irq >> 5;
-               bits = in_le32(&pmac_irq_hw[i]->event) | ppc_lost_interrupts[i];
-               /* We must read level interrupts from the level register */
-               bits |= (in_le32(&pmac_irq_hw[i]->level) & level_mask[i]);
-               bits &= ppc_cached_irq_mask[i];
-               if (bits == 0)
-                       continue;
-               irq += __ilog2(bits);
-               break;
-       }
-
-       return irq;
-}
-
-/* This routine will fix some missing interrupt values in the device tree
- * on the gatwick mac-io controller used by some PowerBooks
- */
-static void __init
-pmac_fix_gatwick_interrupts(struct device_node *gw, int irq_base)
-{
-       struct device_node *node;
-       int count;
-
-       memset(gatwick_int_pool, 0, sizeof(gatwick_int_pool));
-       node = gw->child;
-       count = 0;
-       while(node)
-       {
-               /* Fix SCC */
-               if (strcasecmp(node->name, "escc") == 0)
-                       if (node->child) {
-                               if (node->child->n_intrs < 3) {
-                                       node->child->intrs = &gatwick_int_pool[count];
-                                       count += 3;
-                               }
-                               node->child->n_intrs = 3;
-                               node->child->intrs[0].line = 15+irq_base;
-                               node->child->intrs[1].line =  4+irq_base;
-                               node->child->intrs[2].line =  5+irq_base;
-                               printk(KERN_INFO "irq: fixed SCC on second controller (%d,%d,%d)\n",
-                                       node->child->intrs[0].line,
-                                       node->child->intrs[1].line,
-                                       node->child->intrs[2].line);
-                       }
-               /* Fix media-bay & left SWIM */
-               if (strcasecmp(node->name, "media-bay") == 0) {
-                       struct device_node* ya_node;
-
-                       if (node->n_intrs == 0)
-                               node->intrs = &gatwick_int_pool[count++];
-                       node->n_intrs = 1;
-                       node->intrs[0].line = 29+irq_base;
-                       printk(KERN_INFO "irq: fixed media-bay on second controller (%d)\n",
-                                       node->intrs[0].line);
-
-                       ya_node = node->child;
-                       while(ya_node)
-                       {
-                               if (strcasecmp(ya_node->name, "floppy") == 0) {
-                                       if (ya_node->n_intrs < 2) {
-                                               ya_node->intrs = &gatwick_int_pool[count];
-                                               count += 2;
-                                       }
-                                       ya_node->n_intrs = 2;
-                                       ya_node->intrs[0].line = 19+irq_base;
-                                       ya_node->intrs[1].line =  1+irq_base;
-                                       printk(KERN_INFO "irq: fixed floppy on second controller (%d,%d)\n",
-                                               ya_node->intrs[0].line, ya_node->intrs[1].line);
-                               }
-                               if (strcasecmp(ya_node->name, "ata4") == 0) {
-                                       if (ya_node->n_intrs < 2) {
-                                               ya_node->intrs = &gatwick_int_pool[count];
-                                               count += 2;
-                                       }
-                                       ya_node->n_intrs = 2;
-                                       ya_node->intrs[0].line = 14+irq_base;
-                                       ya_node->intrs[1].line =  3+irq_base;
-                                       printk(KERN_INFO "irq: fixed ide on second controller (%d,%d)\n",
-                                               ya_node->intrs[0].line, ya_node->intrs[1].line);
-                               }
-                               ya_node = ya_node->sibling;
-                       }
-               }
-               node = node->sibling;
-       }
-       if (count > 10) {
-               printk("WARNING !! Gatwick interrupt pool overflow\n");
-               printk("  GATWICK_IRQ_POOL_SIZE = %d\n", GATWICK_IRQ_POOL_SIZE);
-               printk("              requested = %d\n", count);
-       }
-}
-
-/*
- * The PowerBook 3400/2400/3500 can have a combo ethernet/modem
- * card which includes an ohare chip that acts as a second interrupt
- * controller.  If we find this second ohare, set it up and fix the
- * interrupt value in the device tree for the ethernet chip.
- */
-static int __init enable_second_ohare(void)
-{
-       unsigned char bus, devfn;
-       unsigned short cmd;
-        unsigned long addr;
-       struct device_node *irqctrler = find_devices("pci106b,7");
-       struct device_node *ether;
-
-       if (irqctrler == NULL || irqctrler->n_addrs <= 0)
-               return -1;
-       addr = (unsigned long) ioremap(irqctrler->addrs[0].address, 0x40);
-       pmac_irq_hw[1] = (volatile struct pmac_irq_hw *)(addr + 0x20);
-       max_irqs = 64;
-       if (pci_device_from_OF_node(irqctrler, &bus, &devfn) == 0) {
-               struct pci_controller* hose = pci_find_hose_for_OF_device(irqctrler);
-               if (!hose)
-                   printk(KERN_ERR "Can't find PCI hose for OHare2 !\n");
-               else {
-                   early_read_config_word(hose, bus, devfn, PCI_COMMAND, &cmd);
-                   cmd |= PCI_COMMAND_MEMORY | PCI_COMMAND_MASTER;
-                   cmd &= ~PCI_COMMAND_IO;
-                   early_write_config_word(hose, bus, devfn, PCI_COMMAND, cmd);
-               }
-       }
-
-       /* Fix interrupt for the modem/ethernet combo controller. The number
-          in the device tree (27) is bogus (correct for the ethernet-only
-          board but not the combo ethernet/modem board).
-          The real interrupt is 28 on the second controller -> 28+32 = 60.
-       */
-       ether = find_devices("pci1011,14");
-       if (ether && ether->n_intrs > 0) {
-               ether->intrs[0].line = 60;
-               printk(KERN_INFO "irq: Fixed ethernet IRQ to %d\n",
-                      ether->intrs[0].line);
-       }
-
-       /* Return the interrupt number of the cascade */
-       return irqctrler->intrs[0].line;
-}
-
-static int pmac_u3_cascade(struct pt_regs *regs, void *data)
-{
-       return mpic_get_one_irq((struct mpic *)data, regs);
-}
-
-#ifdef CONFIG_XMON
-static struct irqaction xmon_action = {
-       .handler        = xmon_irq,
-       .flags          = 0,
-       .mask           = CPU_MASK_NONE,
-       .name           = "NMI - XMON"
-};
-#endif
-
-static struct irqaction gatwick_cascade_action = {
-       .handler        = gatwick_action,
-       .flags          = SA_INTERRUPT,
-       .mask           = CPU_MASK_NONE,
-       .name           = "cascade",
-};
-
-void __init pmac_pic_init(void)
-{
-        int i;
-        struct device_node *irqctrler  = NULL;
-        struct device_node *irqctrler2 = NULL;
-       struct device_node *np;
-        unsigned long addr;
-       int irq_cascade = -1;
-       struct mpic *mpic1, *mpic2;
-
-       /* We first try to detect Apple's new Core99 chipset, since mac-io
-        * is quite different on those machines and contains an IBM MPIC2.
-        */
-       np = find_type_devices("open-pic");
-       while (np) {
-               if (np->parent && !strcmp(np->parent->name, "u3"))
-                       irqctrler2 = np;
-               else
-                       irqctrler = np;
-               np = np->next;
-       }
-       if (irqctrler != NULL && irqctrler->n_addrs > 0) {
-               unsigned char senses[128];
-
-               printk(KERN_INFO "PowerMac using OpenPIC irq controller at 0x%08x\n",
-                      (unsigned int)irqctrler->addrs[0].address);
-               ppc_md.get_irq = mpic_get_irq;
-               pmac_call_feature(PMAC_FTR_ENABLE_MPIC, irqctrler, 0, 0);
-
-               prom_get_irq_senses(senses, 0, 128);
-               mpic1 = mpic_alloc(irqctrler->addrs[0].address,
-                                  MPIC_PRIMARY | MPIC_WANTS_RESET,
-                                  0, 0, 128, 252, senses, 128, " OpenPIC  ");
-               BUG_ON(mpic1 == NULL);
-               mpic_init(mpic1);               
-
-               if (irqctrler2 != NULL && irqctrler2->n_intrs > 0 &&
-                   irqctrler2->n_addrs > 0) {
-                       printk(KERN_INFO "Slave OpenPIC at 0x%08x hooked on IRQ %d\n",
-                              (u32)irqctrler2->addrs[0].address,
-                              irqctrler2->intrs[0].line);
-
-                       pmac_call_feature(PMAC_FTR_ENABLE_MPIC, irqctrler2, 0, 0);
-                       prom_get_irq_senses(senses, 128, 128 + 124);
-
-                       /* We don't need to set MPIC_BROKEN_U3 here since we don't have
-                        * hypertransport interrupts routed to it
-                        */
-                       mpic2 = mpic_alloc(irqctrler2->addrs[0].address,
-                                          MPIC_BIG_ENDIAN | MPIC_WANTS_RESET,
-                                          0, 128, 124, 0, senses, 124,
-                                          " U3-MPIC  ");
-                       BUG_ON(mpic2 == NULL);
-                       mpic_init(mpic2);
-                       mpic_setup_cascade(irqctrler2->intrs[0].line,
-                                          pmac_u3_cascade, mpic2);
-               }
-#ifdef CONFIG_XMON
-               {
-                       struct device_node* pswitch;
-                       int nmi_irq;
-
-                       pswitch = find_devices("programmer-switch");
-                       if (pswitch && pswitch->n_intrs) {
-                               nmi_irq = pswitch->intrs[0].line;
-                               openpic_init_nmi_irq(nmi_irq);
-                               setup_irq(nmi_irq, &xmon_action);
-                       }
-               }
-#endif /* CONFIG_XMON */
-               return;
-       }
-       irqctrler = NULL;
-
-       /* Get the level/edge settings, assume if it's not
-        * a Grand Central nor an OHare, then it's an Heathrow
-        * (or Paddington).
-        */
-       if (find_devices("gc"))
-               level_mask[0] = GC_LEVEL_MASK;
-       else if (find_devices("ohare")) {
-               level_mask[0] = OHARE_LEVEL_MASK;
-               /* We might have a second cascaded ohare */
-               level_mask[1] = OHARE_LEVEL_MASK;
-       } else {
-               level_mask[0] = HEATHROW_LEVEL_MASK;
-               level_mask[1] = 0;
-               /* We might have a second cascaded heathrow */
-               level_mask[2] = HEATHROW_LEVEL_MASK;
-               level_mask[3] = 0;
-       }
-
-       /*
-        * G3 powermacs and 1999 G3 PowerBooks have 64 interrupts,
-        * 1998 G3 Series PowerBooks have 128,
-        * other powermacs have 32.
-        * The combo ethernet/modem card for the Powerstar powerbooks
-        * (2400/3400/3500, ohare based) has a second ohare chip
-        * effectively making a total of 64.
-        */
-       max_irqs = max_real_irqs = 32;
-       irqctrler = find_devices("mac-io");
-       if (irqctrler)
-       {
-               max_real_irqs = 64;
-               if (irqctrler->next)
-                       max_irqs = 128;
-               else
-                       max_irqs = 64;
-       }
-       for ( i = 0; i < max_real_irqs ; i++ )
-               irq_desc[i].handler = &pmac_pic;
-
-       /* get addresses of first controller */
-       if (irqctrler) {
-               if  (irqctrler->n_addrs > 0) {
-                       addr = (unsigned long)
-                               ioremap(irqctrler->addrs[0].address, 0x40);
-                       for (i = 0; i < 2; ++i)
-                               pmac_irq_hw[i] = (volatile struct pmac_irq_hw*)
-                                       (addr + (2 - i) * 0x10);
-               }
-
-               /* get addresses of second controller */
-               irqctrler = irqctrler->next;
-               if (irqctrler && irqctrler->n_addrs > 0) {
-                       addr = (unsigned long)
-                               ioremap(irqctrler->addrs[0].address, 0x40);
-                       for (i = 2; i < 4; ++i)
-                               pmac_irq_hw[i] = (volatile struct pmac_irq_hw*)
-                                       (addr + (4 - i) * 0x10);
-                       irq_cascade = irqctrler->intrs[0].line;
-                       if (device_is_compatible(irqctrler, "gatwick"))
-                               pmac_fix_gatwick_interrupts(irqctrler, max_real_irqs);
-               }
-       } else {
-               /* older powermacs have a GC (grand central) or ohare at
-                  f3000000, with interrupt control registers at f3000020. */
-               addr = (unsigned long) ioremap(0xf3000000, 0x40);
-               pmac_irq_hw[0] = (volatile struct pmac_irq_hw *) (addr + 0x20);
-       }
-
-       /* PowerBooks 3400 and 3500 can have a second controller in a second
-          ohare chip, on the combo ethernet/modem card */
-       if (machine_is_compatible("AAPL,3400/2400")
-            || machine_is_compatible("AAPL,3500"))
-               irq_cascade = enable_second_ohare();
-
-       /* disable all interrupts in all controllers */
-       for (i = 0; i * 32 < max_irqs; ++i)
-               out_le32(&pmac_irq_hw[i]->enable, 0);
-       /* mark level interrupts */
-       for (i = 0; i < max_irqs; i++)
-               if (level_mask[i >> 5] & (1UL << (i & 0x1f)))
-                       irq_desc[i].status = IRQ_LEVEL;
-
-       /* get interrupt line of secondary interrupt controller */
-       if (irq_cascade >= 0) {
-               printk(KERN_INFO "irq: secondary controller on irq %d\n",
-                       (int)irq_cascade);
-               for ( i = max_real_irqs ; i < max_irqs ; i++ )
-                       irq_desc[i].handler = &gatwick_pic;
-               setup_irq(irq_cascade, &gatwick_cascade_action);
-       }
-       printk("System has %d possible interrupts\n", max_irqs);
-       if (max_irqs != max_real_irqs)
-               printk(KERN_DEBUG "%d interrupts on main controller\n",
-                       max_real_irqs);
-
-#ifdef CONFIG_XMON
-       setup_irq(20, &xmon_action);
-#endif /* CONFIG_XMON */
-}
-
-#ifdef CONFIG_PM
-/*
- * These procedures are used in implementing sleep on the powerbooks.
- * sleep_save_intrs() saves the states of all interrupt enables
- * and disables all interrupts except for the nominated one.
- * sleep_restore_intrs() restores the states of all interrupt enables.
- */
-unsigned long sleep_save_mask[2];
-
-/* This used to be passed by the PMU driver but that link got
- * broken with the new driver model. We use this tweak for now...
- */
-static int pmacpic_find_viaint(void)
-{
-       int viaint = -1;
-
-#ifdef CONFIG_ADB_PMU
-       struct device_node *np;
-
-       if (pmu_get_model() != PMU_OHARE_BASED)
-               goto not_found;
-       np = of_find_node_by_name(NULL, "via-pmu");
-       if (np == NULL)
-               goto not_found;
-       viaint = np->intrs[0].line;
-#endif /* CONFIG_ADB_PMU */
-
-not_found:
-       return viaint;
-}
-
-static int pmacpic_suspend(struct sys_device *sysdev, pm_message_t state)
-{
-       int viaint = pmacpic_find_viaint();
-
-       sleep_save_mask[0] = ppc_cached_irq_mask[0];
-       sleep_save_mask[1] = ppc_cached_irq_mask[1];
-       ppc_cached_irq_mask[0] = 0;
-       ppc_cached_irq_mask[1] = 0;
-       if (viaint > 0)
-               set_bit(viaint, ppc_cached_irq_mask);
-       out_le32(&pmac_irq_hw[0]->enable, ppc_cached_irq_mask[0]);
-       if (max_real_irqs > 32)
-               out_le32(&pmac_irq_hw[1]->enable, ppc_cached_irq_mask[1]);
-       (void)in_le32(&pmac_irq_hw[0]->event);
-       /* make sure mask gets to controller before we return to caller */
-       mb();
-        (void)in_le32(&pmac_irq_hw[0]->enable);
-
-        return 0;
-}
-
-static int pmacpic_resume(struct sys_device *sysdev)
-{
-       int i;
-
-       out_le32(&pmac_irq_hw[0]->enable, 0);
-       if (max_real_irqs > 32)
-               out_le32(&pmac_irq_hw[1]->enable, 0);
-       mb();
-       for (i = 0; i < max_real_irqs; ++i)
-               if (test_bit(i, sleep_save_mask))
-                       pmac_unmask_irq(i);
-
-       return 0;
-}
-
-#endif /* CONFIG_PM */
-
-static struct sysdev_class pmacpic_sysclass = {
-       set_kset_name("pmac_pic"),
-};
-
-static struct sys_device device_pmacpic = {
-       .id             = 0,
-       .cls            = &pmacpic_sysclass,
-};
-
-static struct sysdev_driver driver_pmacpic = {
-#ifdef CONFIG_PM
-       .suspend        = &pmacpic_suspend,
-       .resume         = &pmacpic_resume,
-#endif /* CONFIG_PM */
-};
-
-static int __init init_pmacpic_sysfs(void)
-{
-       if (max_irqs == 0)
-               return -ENODEV;
-
-       printk(KERN_DEBUG "Registering pmac pic with sysfs...\n");
-       sysdev_class_register(&pmacpic_sysclass);
-       sysdev_register(&device_pmacpic);
-       sysdev_driver_register(&pmacpic_sysclass, &driver_pmacpic);
-       return 0;
-}
-
-subsys_initcall(init_pmacpic_sysfs);
-
diff --git a/arch/powerpc/platforms/powermac/pmac_pic.h b/arch/powerpc/platforms/powermac/pmac_pic.h
deleted file mode 100644 (file)
index 664103d..0000000
+++ /dev/null
@@ -1,11 +0,0 @@
-#ifndef __PPC_PLATFORMS_PMAC_PIC_H
-#define __PPC_PLATFORMS_PMAC_PIC_H
-
-#include <linux/irq.h>
-
-extern struct hw_interrupt_type pmac_pic;
-
-void pmac_pic_init(void);
-int pmac_get_irq(struct pt_regs *regs);
-
-#endif /* __PPC_PLATFORMS_PMAC_PIC_H */
diff --git a/arch/powerpc/platforms/powermac/pmac_setup.c b/arch/powerpc/platforms/powermac/pmac_setup.c
deleted file mode 100644 (file)
index 1b12bf9..0000000
+++ /dev/null
@@ -1,663 +0,0 @@
-/*
- *  arch/ppc/platforms/setup.c
- *
- *  PowerPC version
- *    Copyright (C) 1995-1996 Gary Thomas (gdt@linuxppc.org)
- *
- *  Adapted for Power Macintosh by Paul Mackerras
- *    Copyright (C) 1996 Paul Mackerras (paulus@cs.anu.edu.au)
- *
- *  Derived from "arch/alpha/kernel/setup.c"
- *    Copyright (C) 1995 Linus Torvalds
- *
- *  Maintained by Benjamin Herrenschmidt (benh@kernel.crashing.org)
- *
- *  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.
- *
- */
-
-/*
- * bootup setup stuff..
- */
-
-#include <linux/config.h>
-#include <linux/init.h>
-#include <linux/errno.h>
-#include <linux/sched.h>
-#include <linux/kernel.h>
-#include <linux/mm.h>
-#include <linux/stddef.h>
-#include <linux/unistd.h>
-#include <linux/ptrace.h>
-#include <linux/slab.h>
-#include <linux/user.h>
-#include <linux/a.out.h>
-#include <linux/tty.h>
-#include <linux/string.h>
-#include <linux/delay.h>
-#include <linux/ioport.h>
-#include <linux/major.h>
-#include <linux/initrd.h>
-#include <linux/vt_kern.h>
-#include <linux/console.h>
-#include <linux/ide.h>
-#include <linux/pci.h>
-#include <linux/adb.h>
-#include <linux/cuda.h>
-#include <linux/pmu.h>
-#include <linux/irq.h>
-#include <linux/seq_file.h>
-#include <linux/root_dev.h>
-#include <linux/bitops.h>
-#include <linux/suspend.h>
-
-#include <asm/reg.h>
-#include <asm/sections.h>
-#include <asm/prom.h>
-#include <asm/system.h>
-#include <asm/pgtable.h>
-#include <asm/io.h>
-#include <asm/pci-bridge.h>
-#include <asm/ohare.h>
-#include <asm/mediabay.h>
-#include <asm/machdep.h>
-#include <asm/dma.h>
-#include <asm/bootx.h>
-#include <asm/cputable.h>
-#include <asm/btext.h>
-#include <asm/pmac_feature.h>
-#include <asm/time.h>
-#include <asm/of_device.h>
-#include <asm/mmu_context.h>
-
-#include "pmac_pic.h"
-
-#undef SHOW_GATWICK_IRQS
-
-extern long pmac_time_init(void);
-extern unsigned long pmac_get_rtc_time(void);
-extern int pmac_set_rtc_time(unsigned long nowtime);
-extern void pmac_read_rtc_time(void);
-extern void pmac_calibrate_decr(void);
-extern void pmac_pcibios_fixup(void);
-extern void pmac_find_bridges(void);
-extern unsigned long pmac_ide_get_base(int index);
-extern void pmac_ide_init_hwif_ports(hw_regs_t *hw,
-       unsigned long data_port, unsigned long ctrl_port, int *irq);
-
-extern void pmac_nvram_update(void);
-extern unsigned char pmac_nvram_read_byte(int addr);
-extern void pmac_nvram_write_byte(int addr, unsigned char val);
-extern int pmac_pci_enable_device_hook(struct pci_dev *dev, int initial);
-extern void pmac_pcibios_after_init(void);
-extern int of_show_percpuinfo(struct seq_file *m, int i);
-
-unsigned char drive_info;
-
-int ppc_override_l2cr = 0;
-int ppc_override_l2cr_value;
-int has_l2cache = 0;
-
-int pmac_newworld = 1;
-
-static int current_root_goodness = -1;
-
-extern int pmac_newworld;
-
-#define DEFAULT_ROOT_DEVICE Root_SDA1  /* sda1 - slightly silly choice */
-
-extern void zs_kgdb_hook(int tty_num);
-static void ohare_init(void);
-#ifdef CONFIG_BOOTX_TEXT
-static void pmac_progress(char *s, unsigned short hex);
-#endif
-
-sys_ctrler_t sys_ctrler = SYS_CTRLER_UNKNOWN;
-
-#ifdef CONFIG_SMP
-extern struct smp_ops_t psurge_smp_ops;
-extern struct smp_ops_t core99_smp_ops;
-#endif /* CONFIG_SMP */
-
-static int
-pmac_show_cpuinfo(struct seq_file *m)
-{
-       struct device_node *np;
-       char *pp;
-       int plen;
-       int mbmodel = pmac_call_feature(PMAC_FTR_GET_MB_INFO,
-               NULL, PMAC_MB_INFO_MODEL, 0);
-       unsigned int mbflags = (unsigned int)pmac_call_feature(PMAC_FTR_GET_MB_INFO,
-               NULL, PMAC_MB_INFO_FLAGS, 0);
-       char* mbname;
-
-       if (pmac_call_feature(PMAC_FTR_GET_MB_INFO, NULL, PMAC_MB_INFO_NAME, (int)&mbname) != 0)
-               mbname = "Unknown";
-
-       /* find motherboard type */
-       seq_printf(m, "machine\t\t: ");
-       np = find_devices("device-tree");
-       if (np != NULL) {
-               pp = (char *) get_property(np, "model", NULL);
-               if (pp != NULL)
-                       seq_printf(m, "%s\n", pp);
-               else
-                       seq_printf(m, "PowerMac\n");
-               pp = (char *) get_property(np, "compatible", &plen);
-               if (pp != NULL) {
-                       seq_printf(m, "motherboard\t:");
-                       while (plen > 0) {
-                               int l = strlen(pp) + 1;
-                               seq_printf(m, " %s", pp);
-                               plen -= l;
-                               pp += l;
-                       }
-                       seq_printf(m, "\n");
-               }
-       } else
-               seq_printf(m, "PowerMac\n");
-
-       /* print parsed model */
-       seq_printf(m, "detected as\t: %d (%s)\n", mbmodel, mbname);
-       seq_printf(m, "pmac flags\t: %08x\n", mbflags);
-
-       /* find l2 cache info */
-       np = find_devices("l2-cache");
-       if (np == 0)
-               np = find_type_devices("cache");
-       if (np != 0) {
-               unsigned int *ic = (unsigned int *)
-                       get_property(np, "i-cache-size", NULL);
-               unsigned int *dc = (unsigned int *)
-                       get_property(np, "d-cache-size", NULL);
-               seq_printf(m, "L2 cache\t:");
-               has_l2cache = 1;
-               if (get_property(np, "cache-unified", NULL) != 0 && dc) {
-                       seq_printf(m, " %dK unified", *dc / 1024);
-               } else {
-                       if (ic)
-                               seq_printf(m, " %dK instruction", *ic / 1024);
-                       if (dc)
-                               seq_printf(m, "%s %dK data",
-                                          (ic? " +": ""), *dc / 1024);
-               }
-               pp = get_property(np, "ram-type", NULL);
-               if (pp)
-                       seq_printf(m, " %s", pp);
-               seq_printf(m, "\n");
-       }
-
-       /* find ram info */
-       np = find_devices("memory");
-       if (np != 0) {
-               int n;
-               struct reg_property *reg = (struct reg_property *)
-                       get_property(np, "reg", &n);
-
-               if (reg != 0) {
-                       unsigned long total = 0;
-
-                       for (n /= sizeof(struct reg_property); n > 0; --n)
-                               total += (reg++)->size;
-                       seq_printf(m, "memory\t\t: %luMB\n", total >> 20);
-               }
-       }
-
-       /* Checks "l2cr-value" property in the registry */
-       np = find_devices("cpus");
-       if (np == 0)
-               np = find_type_devices("cpu");
-       if (np != 0) {
-               unsigned int *l2cr = (unsigned int *)
-                       get_property(np, "l2cr-value", NULL);
-               if (l2cr != 0) {
-                       seq_printf(m, "l2cr override\t: 0x%x\n", *l2cr);
-               }
-       }
-
-       /* Indicate newworld/oldworld */
-       seq_printf(m, "pmac-generation\t: %s\n",
-                  pmac_newworld ? "NewWorld" : "OldWorld");
-
-
-       return 0;
-}
-
-static int
-pmac_show_percpuinfo(struct seq_file *m, int i)
-{
-#ifdef CONFIG_CPU_FREQ_PMAC
-       extern unsigned int pmac_get_one_cpufreq(int i);
-       unsigned int freq = pmac_get_one_cpufreq(i);
-       if (freq != 0) {
-               seq_printf(m, "clock\t\t: %dMHz\n", freq/1000);
-               return 0;
-       }
-#endif /* CONFIG_CPU_FREQ_PMAC */
-       return of_show_percpuinfo(m, i);
-}
-
-static volatile u32 *sysctrl_regs;
-
-void __init
-pmac_setup_arch(void)
-{
-       struct device_node *cpu;
-       int *fp;
-       unsigned long pvr;
-
-       pvr = PVR_VER(mfspr(SPRN_PVR));
-
-       /* Set loops_per_jiffy to a half-way reasonable value,
-          for use until calibrate_delay gets called. */
-       cpu = find_type_devices("cpu");
-       if (cpu != 0) {
-               fp = (int *) get_property(cpu, "clock-frequency", NULL);
-               if (fp != 0) {
-                       if (pvr == 4 || pvr >= 8)
-                               /* 604, G3, G4 etc. */
-                               loops_per_jiffy = *fp / HZ;
-                       else
-                               /* 601, 603, etc. */
-                               loops_per_jiffy = *fp / (2*HZ);
-               } else
-                       loops_per_jiffy = 50000000 / HZ;
-       }
-
-       /* this area has the CPU identification register
-          and some registers used by smp boards */
-       sysctrl_regs = (volatile u32 *) ioremap(0xf8000000, 0x1000);
-       ohare_init();
-
-       /* Lookup PCI hosts */
-       pmac_find_bridges();
-
-       /* Checks "l2cr-value" property in the registry */
-       if (cpu_has_feature(CPU_FTR_L2CR)) {
-               struct device_node *np = find_devices("cpus");
-               if (np == 0)
-                       np = find_type_devices("cpu");
-               if (np != 0) {
-                       unsigned int *l2cr = (unsigned int *)
-                               get_property(np, "l2cr-value", NULL);
-                       if (l2cr != 0) {
-                               ppc_override_l2cr = 1;
-                               ppc_override_l2cr_value = *l2cr;
-                               _set_L2CR(0);
-                               _set_L2CR(ppc_override_l2cr_value);
-                       }
-               }
-       }
-
-       if (ppc_override_l2cr)
-               printk(KERN_INFO "L2CR overriden (0x%x), backside cache is %s\n",
-                       ppc_override_l2cr_value, (ppc_override_l2cr_value & 0x80000000)
-                               ? "enabled" : "disabled");
-
-#ifdef CONFIG_KGDB
-       zs_kgdb_hook(0);
-#endif
-
-#ifdef CONFIG_ADB_CUDA
-       find_via_cuda();
-#else
-       if (find_devices("via-cuda")) {
-               printk("WARNING ! Your machine is Cuda based but your kernel\n");
-               printk("          wasn't compiled with CONFIG_ADB_CUDA option !\n");
-       }
-#endif
-#ifdef CONFIG_ADB_PMU
-       find_via_pmu();
-#else
-       if (find_devices("via-pmu")) {
-               printk("WARNING ! Your machine is PMU based but your kernel\n");
-               printk("          wasn't compiled with CONFIG_ADB_PMU option !\n");
-       }
-#endif
-#ifdef CONFIG_NVRAM
-       pmac_nvram_init();
-#endif
-#ifdef CONFIG_BLK_DEV_INITRD
-       if (initrd_start)
-               ROOT_DEV = Root_RAM0;
-       else
-#endif
-               ROOT_DEV = DEFAULT_ROOT_DEVICE;
-
-#ifdef CONFIG_SMP
-       /* Check for Core99 */
-       if (find_devices("uni-n") || find_devices("u3"))
-               ppc_md.smp_ops = &core99_smp_ops;
-       else
-               ppc_md.smp_ops = &psurge_smp_ops;
-#endif /* CONFIG_SMP */
-
-       pci_create_OF_bus_map();
-}
-
-static void __init ohare_init(void)
-{
-       /*
-        * Turn on the L2 cache.
-        * We assume that we have a PSX memory controller iff
-        * we have an ohare I/O controller.
-        */
-       if (find_devices("ohare") != NULL) {
-               if (((sysctrl_regs[2] >> 24) & 0xf) >= 3) {
-                       if (sysctrl_regs[4] & 0x10)
-                               sysctrl_regs[4] |= 0x04000020;
-                       else
-                               sysctrl_regs[4] |= 0x04000000;
-                       if(has_l2cache)
-                               printk(KERN_INFO "Level 2 cache enabled\n");
-               }
-       }
-}
-
-char *bootpath;
-char *bootdevice;
-void *boot_host;
-int boot_target;
-int boot_part;
-extern dev_t boot_dev;
-
-#ifdef CONFIG_SCSI
-void __init
-note_scsi_host(struct device_node *node, void *host)
-{
-       int l;
-       char *p;
-
-       l = strlen(node->full_name);
-       if (bootpath != NULL && bootdevice != NULL
-           && strncmp(node->full_name, bootdevice, l) == 0
-           && (bootdevice[l] == '/' || bootdevice[l] == 0)) {
-               boot_host = host;
-               /*
-                * There's a bug in OF 1.0.5.  (Why am I not surprised.)
-                * If you pass a path like scsi/sd@1:0 to canon, it returns
-                * something like /bandit@F2000000/gc@10/53c94@10000/sd@0,0
-                * That is, the scsi target number doesn't get preserved.
-                * So we pick the target number out of bootpath and use that.
-                */
-               p = strstr(bootpath, "/sd@");
-               if (p != NULL) {
-                       p += 4;
-                       boot_target = simple_strtoul(p, NULL, 10);
-                       p = strchr(p, ':');
-                       if (p != NULL)
-                               boot_part = simple_strtoul(p + 1, NULL, 10);
-               }
-       }
-}
-EXPORT_SYMBOL(note_scsi_host);
-#endif
-
-#if defined(CONFIG_BLK_DEV_IDE) && defined(CONFIG_BLK_DEV_IDE_PMAC)
-static dev_t __init
-find_ide_boot(void)
-{
-       char *p;
-       int n;
-       dev_t __init pmac_find_ide_boot(char *bootdevice, int n);
-
-       if (bootdevice == NULL)
-               return 0;
-       p = strrchr(bootdevice, '/');
-       if (p == NULL)
-               return 0;
-       n = p - bootdevice;
-
-       return pmac_find_ide_boot(bootdevice, n);
-}
-#endif /* CONFIG_BLK_DEV_IDE && CONFIG_BLK_DEV_IDE_PMAC */
-
-static void __init
-find_boot_device(void)
-{
-#if defined(CONFIG_BLK_DEV_IDE) && defined(CONFIG_BLK_DEV_IDE_PMAC)
-       boot_dev = find_ide_boot();
-#endif
-}
-
-static int initializing = 1;
-/* TODO: Merge the suspend-to-ram with the common code !!!
- * currently, this is a stub implementation for suspend-to-disk
- * only
- */
-
-#ifdef CONFIG_SOFTWARE_SUSPEND
-
-static int pmac_pm_prepare(suspend_state_t state)
-{
-       printk(KERN_DEBUG "%s(%d)\n", __FUNCTION__, state);
-
-       return 0;
-}
-
-static int pmac_pm_enter(suspend_state_t state)
-{
-       printk(KERN_DEBUG "%s(%d)\n", __FUNCTION__, state);
-
-       /* Giveup the lazy FPU & vec so we don't have to back them
-        * up from the low level code
-        */
-       enable_kernel_fp();
-
-#ifdef CONFIG_ALTIVEC
-       if (cur_cpu_spec->cpu_features & CPU_FTR_ALTIVEC)
-               enable_kernel_altivec();
-#endif /* CONFIG_ALTIVEC */
-
-       return 0;
-}
-
-static int pmac_pm_finish(suspend_state_t state)
-{
-       printk(KERN_DEBUG "%s(%d)\n", __FUNCTION__, state);
-
-       /* Restore userland MMU context */
-       set_context(current->active_mm->context, current->active_mm->pgd);
-
-       return 0;
-}
-
-static struct pm_ops pmac_pm_ops = {
-       .pm_disk_mode   = PM_DISK_SHUTDOWN,
-       .prepare        = pmac_pm_prepare,
-       .enter          = pmac_pm_enter,
-       .finish         = pmac_pm_finish,
-};
-
-#endif /* CONFIG_SOFTWARE_SUSPEND */
-
-static int pmac_late_init(void)
-{
-       initializing = 0;
-#ifdef CONFIG_SOFTWARE_SUSPEND
-       pm_set_ops(&pmac_pm_ops);
-#endif /* CONFIG_SOFTWARE_SUSPEND */
-       return 0;
-}
-
-late_initcall(pmac_late_init);
-
-/* can't be __init - can be called whenever a disk is first accessed */
-void
-note_bootable_part(dev_t dev, int part, int goodness)
-{
-       static int found_boot = 0;
-       char *p;
-
-       if (!initializing)
-               return;
-       if ((goodness <= current_root_goodness) &&
-           ROOT_DEV != DEFAULT_ROOT_DEVICE)
-               return;
-       p = strstr(saved_command_line, "root=");
-       if (p != NULL && (p == saved_command_line || p[-1] == ' '))
-               return;
-
-       if (!found_boot) {
-               find_boot_device();
-               found_boot = 1;
-       }
-       if (!boot_dev || dev == boot_dev) {
-               ROOT_DEV = dev + part;
-               boot_dev = 0;
-               current_root_goodness = goodness;
-       }
-}
-
-static void
-pmac_restart(char *cmd)
-{
-#ifdef CONFIG_ADB_CUDA
-       struct adb_request req;
-#endif /* CONFIG_ADB_CUDA */
-
-       switch (sys_ctrler) {
-#ifdef CONFIG_ADB_CUDA
-       case SYS_CTRLER_CUDA:
-               cuda_request(&req, NULL, 2, CUDA_PACKET,
-                            CUDA_RESET_SYSTEM);
-               for (;;)
-                       cuda_poll();
-               break;
-#endif /* CONFIG_ADB_CUDA */
-#ifdef CONFIG_ADB_PMU
-       case SYS_CTRLER_PMU:
-               pmu_restart();
-               break;
-#endif /* CONFIG_ADB_PMU */
-       default: ;
-       }
-}
-
-static void
-pmac_power_off(void)
-{
-#ifdef CONFIG_ADB_CUDA
-       struct adb_request req;
-#endif /* CONFIG_ADB_CUDA */
-
-       switch (sys_ctrler) {
-#ifdef CONFIG_ADB_CUDA
-       case SYS_CTRLER_CUDA:
-               cuda_request(&req, NULL, 2, CUDA_PACKET,
-                            CUDA_POWERDOWN);
-               for (;;)
-                       cuda_poll();
-               break;
-#endif /* CONFIG_ADB_CUDA */
-#ifdef CONFIG_ADB_PMU
-       case SYS_CTRLER_PMU:
-               pmu_shutdown();
-               break;
-#endif /* CONFIG_ADB_PMU */
-       default: ;
-       }
-}
-
-static void
-pmac_halt(void)
-{
-       pmac_power_off();
-}
-
-void __init pmac_init(void)
-{
-       /* isa_io_base gets set in pmac_find_bridges */
-       isa_mem_base = PMAC_ISA_MEM_BASE;
-       pci_dram_offset = PMAC_PCI_DRAM_OFFSET;
-       ISA_DMA_THRESHOLD = ~0L;
-       DMA_MODE_READ = 1;
-       DMA_MODE_WRITE = 2;
-
-       ppc_md.setup_arch     = pmac_setup_arch;
-       ppc_md.show_cpuinfo   = pmac_show_cpuinfo;
-       ppc_md.show_percpuinfo = pmac_show_percpuinfo;
-       ppc_md.irq_canonicalize = NULL;
-       ppc_md.init_IRQ       = pmac_pic_init;
-       ppc_md.get_irq        = pmac_get_irq; /* Changed later on ... */
-
-       ppc_md.pcibios_fixup  = pmac_pcibios_fixup;
-       ppc_md.pcibios_enable_device_hook = pmac_pci_enable_device_hook;
-       ppc_md.pcibios_after_init = pmac_pcibios_after_init;
-       ppc_md.phys_mem_access_prot = pci_phys_mem_access_prot;
-
-       ppc_md.restart        = pmac_restart;
-       ppc_md.power_off      = pmac_power_off;
-       ppc_md.halt           = pmac_halt;
-
-       ppc_md.time_init      = pmac_time_init;
-       ppc_md.set_rtc_time   = pmac_set_rtc_time;
-       ppc_md.get_rtc_time   = pmac_get_rtc_time;
-       ppc_md.calibrate_decr = pmac_calibrate_decr;
-
-       ppc_md.feature_call   = pmac_do_feature_call;
-
-#if defined(CONFIG_BLK_DEV_IDE) || defined(CONFIG_BLK_DEV_IDE_MODULE)
-#ifdef CONFIG_BLK_DEV_IDE_PMAC
-        ppc_ide_md.ide_init_hwif       = pmac_ide_init_hwif_ports;
-        ppc_ide_md.default_io_base     = pmac_ide_get_base;
-#endif /* CONFIG_BLK_DEV_IDE_PMAC */
-#endif /* defined(CONFIG_BLK_DEV_IDE) || defined(CONFIG_BLK_DEV_IDE_MODULE) */
-
-#ifdef CONFIG_BOOTX_TEXT
-       ppc_md.progress = pmac_progress;
-#endif /* CONFIG_BOOTX_TEXT */
-
-       if (ppc_md.progress) ppc_md.progress("pmac_init(): exit", 0);
-
-}
-
-#ifdef CONFIG_BOOTX_TEXT
-static void __init
-pmac_progress(char *s, unsigned short hex)
-{
-       if (boot_text_mapped) {
-               btext_drawstring(s);
-               btext_drawchar('\n');
-       }
-}
-#endif /* CONFIG_BOOTX_TEXT */
-
-static int __init
-pmac_declare_of_platform_devices(void)
-{
-       struct device_node *np;
-
-       np = find_devices("uni-n");
-       if (np) {
-               for (np = np->child; np != NULL; np = np->sibling)
-                       if (strncmp(np->name, "i2c", 3) == 0) {
-                               of_platform_device_create(np, "uni-n-i2c",
-                                                         NULL);
-                               break;
-                       }
-       }
-       np = find_devices("u3");
-       if (np) {
-               for (np = np->child; np != NULL; np = np->sibling)
-                       if (strncmp(np->name, "i2c", 3) == 0) {
-                               of_platform_device_create(np, "u3-i2c",
-                                                         NULL);
-                               break;
-                       }
-       }
-
-       np = find_devices("valkyrie");
-       if (np)
-               of_platform_device_create(np, "valkyrie", NULL);
-       np = find_devices("platinum");
-       if (np)
-               of_platform_device_create(np, "platinum", NULL);
-
-       return 0;
-}
-
-device_initcall(pmac_declare_of_platform_devices);
diff --git a/arch/powerpc/platforms/powermac/pmac_sleep.S b/arch/powerpc/platforms/powermac/pmac_sleep.S
deleted file mode 100644 (file)
index 88419c7..0000000
+++ /dev/null
@@ -1,396 +0,0 @@
-/*
- * This file contains sleep low-level functions for PowerBook G3.
- *    Copyright (C) 1999 Benjamin Herrenschmidt (benh@kernel.crashing.org)
- *    and Paul Mackerras (paulus@samba.org).
- *
- * 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.
- *
- */
-
-#include <linux/config.h>
-#include <asm/processor.h>
-#include <asm/page.h>
-#include <asm/ppc_asm.h>
-#include <asm/cputable.h>
-#include <asm/cache.h>
-#include <asm/thread_info.h>
-#include <asm/asm-offsets.h>
-
-#define MAGIC  0x4c617273      /* 'Lars' */
-
-/*
- * Structure for storing CPU registers on the stack.
- */
-#define SL_SP          0
-#define SL_PC          4
-#define SL_MSR         8
-#define SL_SDR1                0xc
-#define SL_SPRG0       0x10    /* 4 sprg's */
-#define SL_DBAT0       0x20
-#define SL_IBAT0       0x28
-#define SL_DBAT1       0x30
-#define SL_IBAT1       0x38
-#define SL_DBAT2       0x40
-#define SL_IBAT2       0x48
-#define SL_DBAT3       0x50
-#define SL_IBAT3       0x58
-#define SL_TB          0x60
-#define SL_R2          0x68
-#define SL_CR          0x6c
-#define SL_R12         0x70    /* r12 to r31 */
-#define SL_SIZE                (SL_R12 + 80)
-
-       .section .text
-       .align  5
-
-#if defined(CONFIG_PM) || defined(CONFIG_CPU_FREQ_PMAC)
-
-/* This gets called by via-pmu.c late during the sleep process.
- * The PMU was already send the sleep command and will shut us down
- * soon. We need to save all that is needed and setup the wakeup
- * vector that will be called by the ROM on wakeup
- */
-_GLOBAL(low_sleep_handler)
-#ifndef CONFIG_6xx
-       blr
-#else
-       mflr    r0
-       stw     r0,4(r1)
-       stwu    r1,-SL_SIZE(r1)
-       mfcr    r0
-       stw     r0,SL_CR(r1)
-       stw     r2,SL_R2(r1)
-       stmw    r12,SL_R12(r1)
-
-       /* Save MSR & SDR1 */
-       mfmsr   r4
-       stw     r4,SL_MSR(r1)
-       mfsdr1  r4
-       stw     r4,SL_SDR1(r1)
-
-       /* Get a stable timebase and save it */
-1:     mftbu   r4
-       stw     r4,SL_TB(r1)
-       mftb    r5
-       stw     r5,SL_TB+4(r1)
-       mftbu   r3
-       cmpw    r3,r4
-       bne     1b
-
-       /* Save SPRGs */
-       mfsprg  r4,0
-       stw     r4,SL_SPRG0(r1)
-       mfsprg  r4,1
-       stw     r4,SL_SPRG0+4(r1)
-       mfsprg  r4,2
-       stw     r4,SL_SPRG0+8(r1)
-       mfsprg  r4,3
-       stw     r4,SL_SPRG0+12(r1)
-
-       /* Save BATs */
-       mfdbatu r4,0
-       stw     r4,SL_DBAT0(r1)
-       mfdbatl r4,0
-       stw     r4,SL_DBAT0+4(r1)
-       mfdbatu r4,1
-       stw     r4,SL_DBAT1(r1)
-       mfdbatl r4,1
-       stw     r4,SL_DBAT1+4(r1)
-       mfdbatu r4,2
-       stw     r4,SL_DBAT2(r1)
-       mfdbatl r4,2
-       stw     r4,SL_DBAT2+4(r1)
-       mfdbatu r4,3
-       stw     r4,SL_DBAT3(r1)
-       mfdbatl r4,3
-       stw     r4,SL_DBAT3+4(r1)
-       mfibatu r4,0
-       stw     r4,SL_IBAT0(r1)
-       mfibatl r4,0
-       stw     r4,SL_IBAT0+4(r1)
-       mfibatu r4,1
-       stw     r4,SL_IBAT1(r1)
-       mfibatl r4,1
-       stw     r4,SL_IBAT1+4(r1)
-       mfibatu r4,2
-       stw     r4,SL_IBAT2(r1)
-       mfibatl r4,2
-       stw     r4,SL_IBAT2+4(r1)
-       mfibatu r4,3
-       stw     r4,SL_IBAT3(r1)
-       mfibatl r4,3
-       stw     r4,SL_IBAT3+4(r1)
-
-       /* Backup various CPU config stuffs */
-       bl      __save_cpu_setup
-
-       /* The ROM can wake us up via 2 different vectors:
-        *  - On wallstreet & lombard, we must write a magic
-        *    value 'Lars' at address 4 and a pointer to a
-        *    memory location containing the PC to resume from
-        *    at address 0.
-        *  - On Core99, we must store the wakeup vector at
-        *    address 0x80 and eventually it's parameters
-        *    at address 0x84. I've have some trouble with those
-        *    parameters however and I no longer use them.
-        */
-       lis     r5,grackle_wake_up@ha
-       addi    r5,r5,grackle_wake_up@l
-       tophys(r5,r5)
-       stw     r5,SL_PC(r1)
-       lis     r4,KERNELBASE@h
-       tophys(r5,r1)
-       addi    r5,r5,SL_PC
-       lis     r6,MAGIC@ha
-       addi    r6,r6,MAGIC@l
-       stw     r5,0(r4)
-       stw     r6,4(r4)
-       /* Setup stuffs at 0x80-0x84 for Core99 */
-       lis     r3,core99_wake_up@ha
-       addi    r3,r3,core99_wake_up@l
-       tophys(r3,r3)
-       stw     r3,0x80(r4)
-       stw     r5,0x84(r4)
-       /* Store a pointer to our backup storage into
-        * a kernel global
-        */
-       lis r3,sleep_storage@ha
-       addi r3,r3,sleep_storage@l
-       stw r5,0(r3)
-
-       .globl  low_cpu_die
-low_cpu_die:
-       /* Flush & disable all caches */
-       bl      flush_disable_caches
-
-       /* Turn off data relocation. */
-       mfmsr   r3              /* Save MSR in r7 */
-       rlwinm  r3,r3,0,28,26   /* Turn off DR bit */
-       sync
-       mtmsr   r3
-       isync
-
-BEGIN_FTR_SECTION
-       /* Flush any pending L2 data prefetches to work around HW bug */
-       sync
-       lis     r3,0xfff0
-       lwz     r0,0(r3)        /* perform cache-inhibited load to ROM */
-       sync                    /* (caches are disabled at this point) */
-END_FTR_SECTION_IFSET(CPU_FTR_SPEC7450)
-
-/*
- * Set the HID0 and MSR for sleep.
- */
-       mfspr   r2,SPRN_HID0
-       rlwinm  r2,r2,0,10,7    /* clear doze, nap */
-       oris    r2,r2,HID0_SLEEP@h
-       sync
-       isync
-       mtspr   SPRN_HID0,r2
-       sync
-
-/* This loop puts us back to sleep in case we have a spurrious
- * wakeup so that the host bridge properly stays asleep. The
- * CPU will be turned off, either after a known time (about 1
- * second) on wallstreet & lombard, or as soon as the CPU enters
- * SLEEP mode on core99
- */
-       mfmsr   r2
-       oris    r2,r2,MSR_POW@h
-1:     sync
-       mtmsr   r2
-       isync
-       b       1b
-
-/*
- * Here is the resume code.
- */
-
-
-/*
- * Core99 machines resume here
- * r4 has the physical address of SL_PC(sp) (unused)
- */
-_GLOBAL(core99_wake_up)
-       /* Make sure HID0 no longer contains any sleep bit and that data cache
-        * is disabled
-        */
-       mfspr   r3,SPRN_HID0
-       rlwinm  r3,r3,0,11,7            /* clear SLEEP, NAP, DOZE bits */
-       rlwinm  3,r3,0,18,15            /* clear DCE, ICE */
-       mtspr   SPRN_HID0,r3
-       sync
-       isync
-
-       /* sanitize MSR */
-       mfmsr   r3
-       ori     r3,r3,MSR_EE|MSR_IP
-       xori    r3,r3,MSR_EE|MSR_IP
-       sync
-       isync
-       mtmsr   r3
-       sync
-       isync
-
-       /* Recover sleep storage */
-       lis     r3,sleep_storage@ha
-       addi    r3,r3,sleep_storage@l
-       tophys(r3,r3)
-       lwz     r1,0(r3)
-
-       /* Pass thru to older resume code ... */
-/*
- * Here is the resume code for older machines.
- * r1 has the physical address of SL_PC(sp).
- */
-
-grackle_wake_up:
-
-       /* Restore the kernel's segment registers before
-        * we do any r1 memory access as we are not sure they
-        * are in a sane state above the first 256Mb region
-        */
-       li      r0,16           /* load up segment register values */
-       mtctr   r0              /* for context 0 */
-       lis     r3,0x2000       /* Ku = 1, VSID = 0 */
-       li      r4,0
-3:     mtsrin  r3,r4
-       addi    r3,r3,0x111     /* increment VSID */
-       addis   r4,r4,0x1000    /* address of next segment */
-       bdnz    3b
-       sync
-       isync
-
-       subi    r1,r1,SL_PC
-
-       /* Restore various CPU config stuffs */
-       bl      __restore_cpu_setup
-
-       /* Make sure all FPRs have been initialized */
-       bl      reloc_offset
-       bl      __init_fpu_registers
-
-       /* Invalidate & enable L1 cache, we don't care about
-        * whatever the ROM may have tried to write to memory
-        */
-       bl      __inval_enable_L1
-
-       /* Restore the BATs, and SDR1.  Then we can turn on the MMU. */
-       lwz     r4,SL_SDR1(r1)
-       mtsdr1  r4
-       lwz     r4,SL_SPRG0(r1)
-       mtsprg  0,r4
-       lwz     r4,SL_SPRG0+4(r1)
-       mtsprg  1,r4
-       lwz     r4,SL_SPRG0+8(r1)
-       mtsprg  2,r4
-       lwz     r4,SL_SPRG0+12(r1)
-       mtsprg  3,r4
-
-       lwz     r4,SL_DBAT0(r1)
-       mtdbatu 0,r4
-       lwz     r4,SL_DBAT0+4(r1)
-       mtdbatl 0,r4
-       lwz     r4,SL_DBAT1(r1)
-       mtdbatu 1,r4
-       lwz     r4,SL_DBAT1+4(r1)
-       mtdbatl 1,r4
-       lwz     r4,SL_DBAT2(r1)
-       mtdbatu 2,r4
-       lwz     r4,SL_DBAT2+4(r1)
-       mtdbatl 2,r4
-       lwz     r4,SL_DBAT3(r1)
-       mtdbatu 3,r4
-       lwz     r4,SL_DBAT3+4(r1)
-       mtdbatl 3,r4
-       lwz     r4,SL_IBAT0(r1)
-       mtibatu 0,r4
-       lwz     r4,SL_IBAT0+4(r1)
-       mtibatl 0,r4
-       lwz     r4,SL_IBAT1(r1)
-       mtibatu 1,r4
-       lwz     r4,SL_IBAT1+4(r1)
-       mtibatl 1,r4
-       lwz     r4,SL_IBAT2(r1)
-       mtibatu 2,r4
-       lwz     r4,SL_IBAT2+4(r1)
-       mtibatl 2,r4
-       lwz     r4,SL_IBAT3(r1)
-       mtibatu 3,r4
-       lwz     r4,SL_IBAT3+4(r1)
-       mtibatl 3,r4
-
-BEGIN_FTR_SECTION
-       li      r4,0
-       mtspr   SPRN_DBAT4U,r4
-       mtspr   SPRN_DBAT4L,r4
-       mtspr   SPRN_DBAT5U,r4
-       mtspr   SPRN_DBAT5L,r4
-       mtspr   SPRN_DBAT6U,r4
-       mtspr   SPRN_DBAT6L,r4
-       mtspr   SPRN_DBAT7U,r4
-       mtspr   SPRN_DBAT7L,r4
-       mtspr   SPRN_IBAT4U,r4
-       mtspr   SPRN_IBAT4L,r4
-       mtspr   SPRN_IBAT5U,r4
-       mtspr   SPRN_IBAT5L,r4
-       mtspr   SPRN_IBAT6U,r4
-       mtspr   SPRN_IBAT6L,r4
-       mtspr   SPRN_IBAT7U,r4
-       mtspr   SPRN_IBAT7L,r4
-END_FTR_SECTION_IFSET(CPU_FTR_HAS_HIGH_BATS)
-
-       /* Flush all TLBs */
-       lis     r4,0x1000
-1:     addic.  r4,r4,-0x1000
-       tlbie   r4
-       blt     1b
-       sync
-
-       /* restore the MSR and turn on the MMU */
-       lwz     r3,SL_MSR(r1)
-       bl      turn_on_mmu
-
-       /* get back the stack pointer */
-       tovirt(r1,r1)
-
-       /* Restore TB */
-       li      r3,0
-       mttbl   r3
-       lwz     r3,SL_TB(r1)
-       lwz     r4,SL_TB+4(r1)
-       mttbu   r3
-       mttbl   r4
-
-       /* Restore the callee-saved registers and return */
-       lwz     r0,SL_CR(r1)
-       mtcr    r0
-       lwz     r2,SL_R2(r1)
-       lmw     r12,SL_R12(r1)
-       addi    r1,r1,SL_SIZE
-       lwz     r0,4(r1)
-       mtlr    r0
-       blr
-
-turn_on_mmu:
-       mflr    r4
-       tovirt(r4,r4)
-       mtsrr0  r4
-       mtsrr1  r3
-       sync
-       isync
-       rfi
-
-#endif /* defined(CONFIG_PM) || defined(CONFIG_CPU_FREQ) */
-
-       .section .data
-       .balign L1_CACHE_LINE_SIZE
-sleep_storage:
-       .long 0
-       .balign L1_CACHE_LINE_SIZE, 0
-
-#endif /* CONFIG_6xx */
-       .section .text
diff --git a/arch/powerpc/platforms/powermac/pmac_smp.c b/arch/powerpc/platforms/powermac/pmac_smp.c
deleted file mode 100644 (file)
index fb99633..0000000
+++ /dev/null
@@ -1,716 +0,0 @@
-/*
- * SMP support for power macintosh.
- *
- * We support both the old "powersurge" SMP architecture
- * and the current Core99 (G4 PowerMac) machines.
- *
- * Note that we don't support the very first rev. of
- * Apple/DayStar 2 CPUs board, the one with the funky
- * watchdog. Hopefully, none of these should be there except
- * maybe internally to Apple. I should probably still add some
- * code to detect this card though and disable SMP. --BenH.
- *
- * Support Macintosh G4 SMP by Troy Benjegerdes (hozer@drgw.net)
- * and Ben Herrenschmidt <benh@kernel.crashing.org>.
- *
- * Support for DayStar quad CPU cards
- * Copyright (C) XLR8, Inc. 1994-2000
- *
- *  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.
- */
-#include <linux/config.h>
-#include <linux/kernel.h>
-#include <linux/sched.h>
-#include <linux/smp.h>
-#include <linux/smp_lock.h>
-#include <linux/interrupt.h>
-#include <linux/kernel_stat.h>
-#include <linux/delay.h>
-#include <linux/init.h>
-#include <linux/spinlock.h>
-#include <linux/errno.h>
-#include <linux/hardirq.h>
-#include <linux/cpu.h>
-
-#include <asm/ptrace.h>
-#include <asm/atomic.h>
-#include <asm/irq.h>
-#include <asm/page.h>
-#include <asm/pgtable.h>
-#include <asm/sections.h>
-#include <asm/io.h>
-#include <asm/prom.h>
-#include <asm/smp.h>
-#include <asm/residual.h>
-#include <asm/machdep.h>
-#include <asm/pmac_feature.h>
-#include <asm/time.h>
-#include <asm/mpic.h>
-#include <asm/cacheflush.h>
-#include <asm/keylargo.h>
-
-/*
- * Powersurge (old powermac SMP) support.
- */
-
-extern void __secondary_start_pmac_0(void);
-
-/* Addresses for powersurge registers */
-#define HAMMERHEAD_BASE                0xf8000000
-#define HHEAD_CONFIG           0x90
-#define HHEAD_SEC_INTR         0xc0
-
-/* register for interrupting the primary processor on the powersurge */
-/* N.B. this is actually the ethernet ROM! */
-#define PSURGE_PRI_INTR                0xf3019000
-
-/* register for storing the start address for the secondary processor */
-/* N.B. this is the PCI config space address register for the 1st bridge */
-#define PSURGE_START           0xf2800000
-
-/* Daystar/XLR8 4-CPU card */
-#define PSURGE_QUAD_REG_ADDR   0xf8800000
-
-#define PSURGE_QUAD_IRQ_SET    0
-#define PSURGE_QUAD_IRQ_CLR    1
-#define PSURGE_QUAD_IRQ_PRIMARY        2
-#define PSURGE_QUAD_CKSTOP_CTL 3
-#define PSURGE_QUAD_PRIMARY_ARB        4
-#define PSURGE_QUAD_BOARD_ID   6
-#define PSURGE_QUAD_WHICH_CPU  7
-#define PSURGE_QUAD_CKSTOP_RDBK        8
-#define PSURGE_QUAD_RESET_CTL  11
-
-#define PSURGE_QUAD_OUT(r, v)  (out_8(quad_base + ((r) << 4) + 4, (v)))
-#define PSURGE_QUAD_IN(r)      (in_8(quad_base + ((r) << 4) + 4) & 0x0f)
-#define PSURGE_QUAD_BIS(r, v)  (PSURGE_QUAD_OUT((r), PSURGE_QUAD_IN(r) | (v)))
-#define PSURGE_QUAD_BIC(r, v)  (PSURGE_QUAD_OUT((r), PSURGE_QUAD_IN(r) & ~(v)))
-
-/* virtual addresses for the above */
-static volatile u8 __iomem *hhead_base;
-static volatile u8 __iomem *quad_base;
-static volatile u32 __iomem *psurge_pri_intr;
-static volatile u8 __iomem *psurge_sec_intr;
-static volatile u32 __iomem *psurge_start;
-
-/* values for psurge_type */
-#define PSURGE_NONE            -1
-#define PSURGE_DUAL            0
-#define PSURGE_QUAD_OKEE       1
-#define PSURGE_QUAD_COTTON     2
-#define PSURGE_QUAD_ICEGRASS   3
-
-/* what sort of powersurge board we have */
-static int psurge_type = PSURGE_NONE;
-
-/* L2 and L3 cache settings to pass from CPU0 to CPU1 */
-volatile static long int core99_l2_cache;
-volatile static long int core99_l3_cache;
-
-/* Timebase freeze GPIO */
-static unsigned int core99_tb_gpio;
-
-/* Sync flag for HW tb sync */
-static volatile int sec_tb_reset = 0;
-static unsigned int pri_tb_hi, pri_tb_lo;
-static unsigned int pri_tb_stamp;
-
-static void __devinit core99_init_caches(int cpu)
-{
-       if (!cpu_has_feature(CPU_FTR_L2CR))
-               return;
-
-       if (cpu == 0) {
-               core99_l2_cache = _get_L2CR();
-               printk("CPU0: L2CR is %lx\n", core99_l2_cache);
-       } else {
-               printk("CPU%d: L2CR was %lx\n", cpu, _get_L2CR());
-               _set_L2CR(0);
-               _set_L2CR(core99_l2_cache);
-               printk("CPU%d: L2CR set to %lx\n", cpu, core99_l2_cache);
-       }
-
-       if (!cpu_has_feature(CPU_FTR_L3CR))
-               return;
-
-       if (cpu == 0){
-               core99_l3_cache = _get_L3CR();
-               printk("CPU0: L3CR is %lx\n", core99_l3_cache);
-       } else {
-               printk("CPU%d: L3CR was %lx\n", cpu, _get_L3CR());
-               _set_L3CR(0);
-               _set_L3CR(core99_l3_cache);
-               printk("CPU%d: L3CR set to %lx\n", cpu, core99_l3_cache);
-       }
-}
-
-/*
- * Set and clear IPIs for powersurge.
- */
-static inline void psurge_set_ipi(int cpu)
-{
-       if (psurge_type == PSURGE_NONE)
-               return;
-       if (cpu == 0)
-               in_be32(psurge_pri_intr);
-       else if (psurge_type == PSURGE_DUAL)
-               out_8(psurge_sec_intr, 0);
-       else
-               PSURGE_QUAD_OUT(PSURGE_QUAD_IRQ_SET, 1 << cpu);
-}
-
-static inline void psurge_clr_ipi(int cpu)
-{
-       if (cpu > 0) {
-               switch(psurge_type) {
-               case PSURGE_DUAL:
-                       out_8(psurge_sec_intr, ~0);
-               case PSURGE_NONE:
-                       break;
-               default:
-                       PSURGE_QUAD_OUT(PSURGE_QUAD_IRQ_CLR, 1 << cpu);
-               }
-       }
-}
-
-/*
- * On powersurge (old SMP powermac architecture) we don't have
- * separate IPIs for separate messages like openpic does.  Instead
- * we have a bitmap for each processor, where a 1 bit means that
- * the corresponding message is pending for that processor.
- * Ideally each cpu's entry would be in a different cache line.
- *  -- paulus.
- */
-static unsigned long psurge_smp_message[NR_CPUS];
-
-void psurge_smp_message_recv(struct pt_regs *regs)
-{
-       int cpu = smp_processor_id();
-       int msg;
-
-       /* clear interrupt */
-       psurge_clr_ipi(cpu);
-
-       if (num_online_cpus() < 2)
-               return;
-
-       /* make sure there is a message there */
-       for (msg = 0; msg < 4; msg++)
-               if (test_and_clear_bit(msg, &psurge_smp_message[cpu]))
-                       smp_message_recv(msg, regs);
-}
-
-irqreturn_t psurge_primary_intr(int irq, void *d, struct pt_regs *regs)
-{
-       psurge_smp_message_recv(regs);
-       return IRQ_HANDLED;
-}
-
-static void smp_psurge_message_pass(int target, int msg, unsigned long data,
-                                          int wait)
-{
-       int i;
-
-       if (num_online_cpus() < 2)
-               return;
-
-       for (i = 0; i < NR_CPUS; i++) {
-               if (!cpu_online(i))
-                       continue;
-               if (target == MSG_ALL
-                   || (target == MSG_ALL_BUT_SELF && i != smp_processor_id())
-                   || target == i) {
-                       set_bit(msg, &psurge_smp_message[i]);
-                       psurge_set_ipi(i);
-               }
-       }
-}
-
-/*
- * Determine a quad card presence. We read the board ID register, we
- * force the data bus to change to something else, and we read it again.
- * It it's stable, then the register probably exist (ugh !)
- */
-static int __init psurge_quad_probe(void)
-{
-       int type;
-       unsigned int i;
-
-       type = PSURGE_QUAD_IN(PSURGE_QUAD_BOARD_ID);
-       if (type < PSURGE_QUAD_OKEE || type > PSURGE_QUAD_ICEGRASS
-           || type != PSURGE_QUAD_IN(PSURGE_QUAD_BOARD_ID))
-               return PSURGE_DUAL;
-
-       /* looks OK, try a slightly more rigorous test */
-       /* bogus is not necessarily cacheline-aligned,
-          though I don't suppose that really matters.  -- paulus */
-       for (i = 0; i < 100; i++) {
-               volatile u32 bogus[8];
-               bogus[(0+i)%8] = 0x00000000;
-               bogus[(1+i)%8] = 0x55555555;
-               bogus[(2+i)%8] = 0xFFFFFFFF;
-               bogus[(3+i)%8] = 0xAAAAAAAA;
-               bogus[(4+i)%8] = 0x33333333;
-               bogus[(5+i)%8] = 0xCCCCCCCC;
-               bogus[(6+i)%8] = 0xCCCCCCCC;
-               bogus[(7+i)%8] = 0x33333333;
-               wmb();
-               asm volatile("dcbf 0,%0" : : "r" (bogus) : "memory");
-               mb();
-               if (type != PSURGE_QUAD_IN(PSURGE_QUAD_BOARD_ID))
-                       return PSURGE_DUAL;
-       }
-       return type;
-}
-
-static void __init psurge_quad_init(void)
-{
-       int procbits;
-
-       if (ppc_md.progress) ppc_md.progress("psurge_quad_init", 0x351);
-       procbits = ~PSURGE_QUAD_IN(PSURGE_QUAD_WHICH_CPU);
-       if (psurge_type == PSURGE_QUAD_ICEGRASS)
-               PSURGE_QUAD_BIS(PSURGE_QUAD_RESET_CTL, procbits);
-       else
-               PSURGE_QUAD_BIC(PSURGE_QUAD_CKSTOP_CTL, procbits);
-       mdelay(33);
-       out_8(psurge_sec_intr, ~0);
-       PSURGE_QUAD_OUT(PSURGE_QUAD_IRQ_CLR, procbits);
-       PSURGE_QUAD_BIS(PSURGE_QUAD_RESET_CTL, procbits);
-       if (psurge_type != PSURGE_QUAD_ICEGRASS)
-               PSURGE_QUAD_BIS(PSURGE_QUAD_CKSTOP_CTL, procbits);
-       PSURGE_QUAD_BIC(PSURGE_QUAD_PRIMARY_ARB, procbits);
-       mdelay(33);
-       PSURGE_QUAD_BIC(PSURGE_QUAD_RESET_CTL, procbits);
-       mdelay(33);
-       PSURGE_QUAD_BIS(PSURGE_QUAD_PRIMARY_ARB, procbits);
-       mdelay(33);
-}
-
-static int __init smp_psurge_probe(void)
-{
-       int i, ncpus;
-
-       /* We don't do SMP on the PPC601 -- paulus */
-       if (PVR_VER(mfspr(SPRN_PVR)) == 1)
-               return 1;
-
-       /*
-        * The powersurge cpu board can be used in the generation
-        * of powermacs that have a socket for an upgradeable cpu card,
-        * including the 7500, 8500, 9500, 9600.
-        * The device tree doesn't tell you if you have 2 cpus because
-        * OF doesn't know anything about the 2nd processor.
-        * Instead we look for magic bits in magic registers,
-        * in the hammerhead memory controller in the case of the
-        * dual-cpu powersurge board.  -- paulus.
-        */
-       if (find_devices("hammerhead") == NULL)
-               return 1;
-
-       hhead_base = ioremap(HAMMERHEAD_BASE, 0x800);
-       quad_base = ioremap(PSURGE_QUAD_REG_ADDR, 1024);
-       psurge_sec_intr = hhead_base + HHEAD_SEC_INTR;
-
-       psurge_type = psurge_quad_probe();
-       if (psurge_type != PSURGE_DUAL) {
-               psurge_quad_init();
-               /* All released cards using this HW design have 4 CPUs */
-               ncpus = 4;
-       } else {
-               iounmap(quad_base);
-               if ((in_8(hhead_base + HHEAD_CONFIG) & 0x02) == 0) {
-                       /* not a dual-cpu card */
-                       iounmap(hhead_base);
-                       psurge_type = PSURGE_NONE;
-                       return 1;
-               }
-               ncpus = 2;
-       }
-
-       psurge_start = ioremap(PSURGE_START, 4);
-       psurge_pri_intr = ioremap(PSURGE_PRI_INTR, 4);
-
-       /* this is not actually strictly necessary -- paulus. */
-       for (i = 1; i < ncpus; ++i)
-               smp_hw_index[i] = i;
-
-       if (ppc_md.progress) ppc_md.progress("smp_psurge_probe - done", 0x352);
-
-       return ncpus;
-}
-
-static void __init smp_psurge_kick_cpu(int nr)
-{
-       unsigned long start = __pa(__secondary_start_pmac_0) + nr * 8;
-       unsigned long a;
-
-       /* may need to flush here if secondary bats aren't setup */
-       for (a = KERNELBASE; a < KERNELBASE + 0x800000; a += 32)
-               asm volatile("dcbf 0,%0" : : "r" (a) : "memory");
-       asm volatile("sync");
-
-       if (ppc_md.progress) ppc_md.progress("smp_psurge_kick_cpu", 0x353);
-
-       out_be32(psurge_start, start);
-       mb();
-
-       psurge_set_ipi(nr);
-       udelay(10);
-       psurge_clr_ipi(nr);
-
-       if (ppc_md.progress) ppc_md.progress("smp_psurge_kick_cpu - done", 0x354);
-}
-
-/*
- * With the dual-cpu powersurge board, the decrementers and timebases
- * of both cpus are frozen after the secondary cpu is started up,
- * until we give the secondary cpu another interrupt.  This routine
- * uses this to get the timebases synchronized.
- *  -- paulus.
- */
-static void __init psurge_dual_sync_tb(int cpu_nr)
-{
-       int t;
-
-       set_dec(tb_ticks_per_jiffy);
-       set_tb(0, 0);
-       last_jiffy_stamp(cpu_nr) = 0;
-
-       if (cpu_nr > 0) {
-               mb();
-               sec_tb_reset = 1;
-               return;
-       }
-
-       /* wait for the secondary to have reset its TB before proceeding */
-       for (t = 10000000; t > 0 && !sec_tb_reset; --t)
-               ;
-
-       /* now interrupt the secondary, starting both TBs */
-       psurge_set_ipi(1);
-
-       smp_tb_synchronized = 1;
-}
-
-static struct irqaction psurge_irqaction = {
-       .handler = psurge_primary_intr,
-       .flags = SA_INTERRUPT,
-       .mask = CPU_MASK_NONE,
-       .name = "primary IPI",
-};
-
-static void __init smp_psurge_setup_cpu(int cpu_nr)
-{
-
-       if (cpu_nr == 0) {
-               /* If we failed to start the second CPU, we should still
-                * send it an IPI to start the timebase & DEC or we might
-                * have them stuck.
-                */
-               if (num_online_cpus() < 2) {
-                       if (psurge_type == PSURGE_DUAL)
-                               psurge_set_ipi(1);
-                       return;
-               }
-               /* reset the entry point so if we get another intr we won't
-                * try to startup again */
-               out_be32(psurge_start, 0x100);
-               if (setup_irq(30, &psurge_irqaction))
-                       printk(KERN_ERR "Couldn't get primary IPI interrupt");
-       }
-
-       if (psurge_type == PSURGE_DUAL)
-               psurge_dual_sync_tb(cpu_nr);
-}
-
-void __init smp_psurge_take_timebase(void)
-{
-       /* Dummy implementation */
-}
-
-void __init smp_psurge_give_timebase(void)
-{
-       /* Dummy implementation */
-}
-
-static int __init smp_core99_probe(void)
-{
-#ifdef CONFIG_6xx
-       extern int powersave_nap;
-#endif
-       struct device_node *cpus, *firstcpu;
-       int i, ncpus = 0, boot_cpu = -1;
-       u32 *tbprop = NULL;
-
-       if (ppc_md.progress) ppc_md.progress("smp_core99_probe", 0x345);
-       cpus = firstcpu = find_type_devices("cpu");
-       while(cpus != NULL) {
-               u32 *regprop = (u32 *)get_property(cpus, "reg", NULL);
-               char *stateprop = (char *)get_property(cpus, "state", NULL);
-               if (regprop != NULL && stateprop != NULL &&
-                   !strncmp(stateprop, "running", 7))
-                       boot_cpu = *regprop;
-               ++ncpus;
-               cpus = cpus->next;
-       }
-       if (boot_cpu == -1)
-               printk(KERN_WARNING "Couldn't detect boot CPU !\n");
-       if (boot_cpu != 0)
-               printk(KERN_WARNING "Boot CPU is %d, unsupported setup !\n", boot_cpu);
-
-       if (machine_is_compatible("MacRISC4")) {
-               extern struct smp_ops_t core99_smp_ops;
-
-               core99_smp_ops.take_timebase = smp_generic_take_timebase;
-               core99_smp_ops.give_timebase = smp_generic_give_timebase;
-       } else {
-               if (firstcpu != NULL)
-                       tbprop = (u32 *)get_property(firstcpu, "timebase-enable", NULL);
-               if (tbprop)
-                       core99_tb_gpio = *tbprop;
-               else
-                       core99_tb_gpio = KL_GPIO_TB_ENABLE;
-       }
-
-       if (ncpus > 1) {
-               mpic_request_ipis();
-               for (i = 1; i < ncpus; ++i)
-                       smp_hw_index[i] = i;
-#ifdef CONFIG_6xx
-               powersave_nap = 0;
-#endif
-               core99_init_caches(0);
-       }
-
-       return ncpus;
-}
-
-static void __devinit smp_core99_kick_cpu(int nr)
-{
-       unsigned long save_vector, new_vector;
-       unsigned long flags;
-
-       volatile unsigned long *vector
-                = ((volatile unsigned long *)(KERNELBASE+0x100));
-       if (nr < 0 || nr > 3)
-               return;
-       if (ppc_md.progress) ppc_md.progress("smp_core99_kick_cpu", 0x346);
-
-       local_irq_save(flags);
-       local_irq_disable();
-
-       /* Save reset vector */
-       save_vector = *vector;
-
-       /* Setup fake reset vector that does    
-        *   b __secondary_start_pmac_0 + nr*8 - KERNELBASE
-        */
-       new_vector = (unsigned long) __secondary_start_pmac_0 + nr * 8;
-       *vector = 0x48000002 + new_vector - KERNELBASE;
-
-       /* flush data cache and inval instruction cache */
-       flush_icache_range((unsigned long) vector, (unsigned long) vector + 4);
-
-       /* Put some life in our friend */
-       pmac_call_feature(PMAC_FTR_RESET_CPU, NULL, nr, 0);
-
-       /* FIXME: We wait a bit for the CPU to take the exception, I should
-        * instead wait for the entry code to set something for me. Well,
-        * ideally, all that crap will be done in prom.c and the CPU left
-        * in a RAM-based wait loop like CHRP.
-        */
-       mdelay(1);
-
-       /* Restore our exception vector */
-       *vector = save_vector;
-       flush_icache_range((unsigned long) vector, (unsigned long) vector + 4);
-
-       local_irq_restore(flags);
-       if (ppc_md.progress) ppc_md.progress("smp_core99_kick_cpu done", 0x347);
-}
-
-static void __devinit smp_core99_setup_cpu(int cpu_nr)
-{
-       /* Setup L2/L3 */
-       if (cpu_nr != 0)
-               core99_init_caches(cpu_nr);
-
-       /* Setup openpic */
-       mpic_setup_this_cpu();
-
-       if (cpu_nr == 0) {
-#ifdef CONFIG_POWER4
-               extern void g5_phy_disable_cpu1(void);
-
-               /* If we didn't start the second CPU, we must take
-                * it off the bus
-                */
-               if (machine_is_compatible("MacRISC4") &&
-                   num_online_cpus() < 2)              
-                       g5_phy_disable_cpu1();
-#endif /* CONFIG_POWER4 */
-               if (ppc_md.progress) ppc_md.progress("core99_setup_cpu 0 done", 0x349);
-       }
-}
-
-/* not __init, called in sleep/wakeup code */
-void smp_core99_take_timebase(void)
-{
-       unsigned long flags;
-
-       /* tell the primary we're here */
-       sec_tb_reset = 1;
-       mb();
-
-       /* wait for the primary to set pri_tb_hi/lo */
-       while (sec_tb_reset < 2)
-               mb();
-
-       /* set our stuff the same as the primary */
-       local_irq_save(flags);
-       set_dec(1);
-       set_tb(pri_tb_hi, pri_tb_lo);
-       last_jiffy_stamp(smp_processor_id()) = pri_tb_stamp;
-       mb();
-
-       /* tell the primary we're done */
-               sec_tb_reset = 0;
-       mb();
-       local_irq_restore(flags);
-}
-
-/* not __init, called in sleep/wakeup code */
-void smp_core99_give_timebase(void)
-{
-       unsigned long flags;
-       unsigned int t;
-
-       /* wait for the secondary to be in take_timebase */
-       for (t = 100000; t > 0 && !sec_tb_reset; --t)
-               udelay(10);
-       if (!sec_tb_reset) {
-               printk(KERN_WARNING "Timeout waiting sync on second CPU\n");
-               return;
-       }
-
-       /* freeze the timebase and read it */
-       /* disable interrupts so the timebase is disabled for the
-          shortest possible time */
-       local_irq_save(flags);
-       pmac_call_feature(PMAC_FTR_WRITE_GPIO, NULL, core99_tb_gpio, 4);
-       pmac_call_feature(PMAC_FTR_READ_GPIO, NULL, core99_tb_gpio, 0);
-       mb();
-       pri_tb_hi = get_tbu();
-       pri_tb_lo = get_tbl();
-       pri_tb_stamp = last_jiffy_stamp(smp_processor_id());
-       mb();
-
-       /* tell the secondary we're ready */
-       sec_tb_reset = 2;
-       mb();
-
-       /* wait for the secondary to have taken it */
-       for (t = 100000; t > 0 && sec_tb_reset; --t)
-               udelay(10);
-       if (sec_tb_reset)
-               printk(KERN_WARNING "Timeout waiting sync(2) on second CPU\n");
-       else
-               smp_tb_synchronized = 1;
-
-       /* Now, restart the timebase by leaving the GPIO to an open collector */
-               pmac_call_feature(PMAC_FTR_WRITE_GPIO, NULL, core99_tb_gpio, 0);
-        pmac_call_feature(PMAC_FTR_READ_GPIO, NULL, core99_tb_gpio, 0);
-       local_irq_restore(flags);
-}
-
-void smp_core99_message_pass(int target, int msg, unsigned long data, int wait)
-{
-       cpumask_t mask = CPU_MASK_ALL;
-       /* make sure we're sending something that translates to an IPI */
-       if (msg > 0x3) {
-               printk("SMP %d: smp_message_pass: unknown msg %d\n",
-                      smp_processor_id(), msg);
-               return;
-       }
-       switch (target) {
-       case MSG_ALL:
-               mpic_send_ipi(msg, cpus_addr(mask)[0]);
-               break;
-       case MSG_ALL_BUT_SELF:
-               cpu_clear(smp_processor_id(), mask);
-               mpic_send_ipi(msg, cpus_addr(mask)[0]);
-               break;
-       default:
-               mpic_send_ipi(msg, 1 << target);
-               break;
-       }
-}
-
-
-/* PowerSurge-style Macs */
-struct smp_ops_t psurge_smp_ops = {
-       .message_pass   = smp_psurge_message_pass,
-       .probe          = smp_psurge_probe,
-       .kick_cpu       = smp_psurge_kick_cpu,
-       .setup_cpu      = smp_psurge_setup_cpu,
-       .give_timebase  = smp_psurge_give_timebase,
-       .take_timebase  = smp_psurge_take_timebase,
-};
-
-/* Core99 Macs (dual G4s) */
-struct smp_ops_t core99_smp_ops = {
-       .message_pass   = smp_core99_message_pass,
-       .probe          = smp_core99_probe,
-       .kick_cpu       = smp_core99_kick_cpu,
-       .setup_cpu      = smp_core99_setup_cpu,
-       .give_timebase  = smp_core99_give_timebase,
-       .take_timebase  = smp_core99_take_timebase,
-};
-
-#ifdef CONFIG_HOTPLUG_CPU
-
-int __cpu_disable(void)
-{
-       cpu_clear(smp_processor_id(), cpu_online_map);
-
-       /* XXX reset cpu affinity here */
-       mpic_cpu_set_priority(0xf);
-       asm volatile("mtdec %0" : : "r" (0x7fffffff));
-       mb();
-       udelay(20);
-       asm volatile("mtdec %0" : : "r" (0x7fffffff));
-       return 0;
-}
-
-extern void low_cpu_die(void) __attribute__((noreturn)); /* in pmac_sleep.S */
-static int cpu_dead[NR_CPUS];
-
-void cpu_die(void)
-{
-       local_irq_disable();
-       cpu_dead[smp_processor_id()] = 1;
-       mb();
-       low_cpu_die();
-}
-
-void __cpu_die(unsigned int cpu)
-{
-       int timeout;
-
-       timeout = 1000;
-       while (!cpu_dead[cpu]) {
-               if (--timeout == 0) {
-                       printk("CPU %u refused to die!\n", cpu);
-                       break;
-               }
-               msleep(1);
-       }
-       cpu_callin_map[cpu] = 0;
-       cpu_dead[cpu] = 0;
-}
-
-#endif
diff --git a/arch/powerpc/platforms/powermac/pmac_time.c b/arch/powerpc/platforms/powermac/pmac_time.c
deleted file mode 100644 (file)
index ff6adff..0000000
+++ /dev/null
@@ -1,291 +0,0 @@
-/*
- * Support for periodic interrupts (100 per second) and for getting
- * the current time from the RTC on Power Macintoshes.
- *
- * We use the decrementer register for our periodic interrupts.
- *
- * Paul Mackerras      August 1996.
- * Copyright (C) 1996 Paul Mackerras.
- */
-#include <linux/config.h>
-#include <linux/errno.h>
-#include <linux/sched.h>
-#include <linux/kernel.h>
-#include <linux/param.h>
-#include <linux/string.h>
-#include <linux/mm.h>
-#include <linux/init.h>
-#include <linux/time.h>
-#include <linux/adb.h>
-#include <linux/cuda.h>
-#include <linux/pmu.h>
-#include <linux/hardirq.h>
-
-#include <asm/sections.h>
-#include <asm/prom.h>
-#include <asm/system.h>
-#include <asm/io.h>
-#include <asm/pgtable.h>
-#include <asm/machdep.h>
-#include <asm/time.h>
-#include <asm/nvram.h>
-
-/* Apparently the RTC stores seconds since 1 Jan 1904 */
-#define RTC_OFFSET     2082844800
-
-/*
- * Calibrate the decrementer frequency with the VIA timer 1.
- */
-#define VIA_TIMER_FREQ_6       4700000 /* time 1 frequency * 6 */
-
-/* VIA registers */
-#define RS             0x200           /* skip between registers */
-#define T1CL           (4*RS)          /* Timer 1 ctr/latch (low 8 bits) */
-#define T1CH           (5*RS)          /* Timer 1 counter (high 8 bits) */
-#define T1LL           (6*RS)          /* Timer 1 latch (low 8 bits) */
-#define T1LH           (7*RS)          /* Timer 1 latch (high 8 bits) */
-#define ACR            (11*RS)         /* Auxiliary control register */
-#define IFR            (13*RS)         /* Interrupt flag register */
-
-/* Bits in ACR */
-#define T1MODE         0xc0            /* Timer 1 mode */
-#define T1MODE_CONT    0x40            /*  continuous interrupts */
-
-/* Bits in IFR and IER */
-#define T1_INT         0x40            /* Timer 1 interrupt */
-
-extern struct timezone sys_tz;
-
-long __init
-pmac_time_init(void)
-{
-#ifdef CONFIG_NVRAM
-       s32 delta = 0;
-       int dst;
-       
-       delta = ((s32)pmac_xpram_read(PMAC_XPRAM_MACHINE_LOC + 0x9)) << 16;
-       delta |= ((s32)pmac_xpram_read(PMAC_XPRAM_MACHINE_LOC + 0xa)) << 8;
-       delta |= pmac_xpram_read(PMAC_XPRAM_MACHINE_LOC + 0xb);
-       if (delta & 0x00800000UL)
-               delta |= 0xFF000000UL;
-       dst = ((pmac_xpram_read(PMAC_XPRAM_MACHINE_LOC + 0x8) & 0x80) != 0);
-       printk("GMT Delta read from XPRAM: %d minutes, DST: %s\n", delta/60,
-               dst ? "on" : "off");
-       return delta;
-#else
-       return 0;
-#endif
-}
-
-unsigned long
-pmac_get_rtc_time(void)
-{
-#if defined(CONFIG_ADB_CUDA) || defined(CONFIG_ADB_PMU)
-       struct adb_request req;
-       unsigned long now;
-#endif
-
-       /* Get the time from the RTC */
-       switch (sys_ctrler) {
-#ifdef CONFIG_ADB_CUDA
-       case SYS_CTRLER_CUDA:
-               if (cuda_request(&req, NULL, 2, CUDA_PACKET, CUDA_GET_TIME) < 0)
-                       return 0;
-               while (!req.complete)
-                       cuda_poll();
-               if (req.reply_len != 7)
-                       printk(KERN_ERR "pmac_get_rtc_time: got %d byte reply\n",
-                              req.reply_len);
-               now = (req.reply[3] << 24) + (req.reply[4] << 16)
-                       + (req.reply[5] << 8) + req.reply[6];
-               return now - RTC_OFFSET;
-#endif /* CONFIG_ADB_CUDA */
-#ifdef CONFIG_ADB_PMU
-       case SYS_CTRLER_PMU:
-               if (pmu_request(&req, NULL, 1, PMU_READ_RTC) < 0)
-                       return 0;
-               while (!req.complete)
-                       pmu_poll();
-               if (req.reply_len != 4)
-                       printk(KERN_ERR "pmac_get_rtc_time: got %d byte reply\n",
-                              req.reply_len);
-               now = (req.reply[0] << 24) + (req.reply[1] << 16)
-                       + (req.reply[2] << 8) + req.reply[3];
-               return now - RTC_OFFSET;
-#endif /* CONFIG_ADB_PMU */
-       default: ;
-       }
-       return 0;
-}
-
-int
-pmac_set_rtc_time(unsigned long nowtime)
-{
-#if defined(CONFIG_ADB_CUDA) || defined(CONFIG_ADB_PMU)
-       struct adb_request req;
-#endif
-
-       nowtime += RTC_OFFSET;
-
-       switch (sys_ctrler) {
-#ifdef CONFIG_ADB_CUDA
-       case SYS_CTRLER_CUDA:
-               if (cuda_request(&req, NULL, 6, CUDA_PACKET, CUDA_SET_TIME,
-                                nowtime >> 24, nowtime >> 16, nowtime >> 8, nowtime) < 0)
-                       return 0;
-               while (!req.complete)
-                       cuda_poll();
-               if ((req.reply_len != 3) && (req.reply_len != 7))
-                       printk(KERN_ERR "pmac_set_rtc_time: got %d byte reply\n",
-                              req.reply_len);
-               return 1;
-#endif /* CONFIG_ADB_CUDA */
-#ifdef CONFIG_ADB_PMU
-       case SYS_CTRLER_PMU:
-               if (pmu_request(&req, NULL, 5, PMU_SET_RTC,
-                               nowtime >> 24, nowtime >> 16, nowtime >> 8, nowtime) < 0)
-                       return 0;
-               while (!req.complete)
-                       pmu_poll();
-               if (req.reply_len != 0)
-                       printk(KERN_ERR "pmac_set_rtc_time: got %d byte reply\n",
-                              req.reply_len);
-               return 1;
-#endif /* CONFIG_ADB_PMU */
-       default:
-               return 0;
-       }
-}
-
-/*
- * Calibrate the decrementer register using VIA timer 1.
- * This is used both on powermacs and CHRP machines.
- */
-int __init
-via_calibrate_decr(void)
-{
-       struct device_node *vias;
-       volatile unsigned char __iomem *via;
-       int count = VIA_TIMER_FREQ_6 / 100;
-       unsigned int dstart, dend;
-
-       vias = find_devices("via-cuda");
-       if (vias == 0)
-               vias = find_devices("via-pmu");
-       if (vias == 0)
-               vias = find_devices("via");
-       if (vias == 0 || vias->n_addrs == 0)
-               return 0;
-       via = ioremap(vias->addrs[0].address, vias->addrs[0].size);
-
-       /* set timer 1 for continuous interrupts */
-       out_8(&via[ACR], (via[ACR] & ~T1MODE) | T1MODE_CONT);
-       /* set the counter to a small value */
-       out_8(&via[T1CH], 2);
-       /* set the latch to `count' */
-       out_8(&via[T1LL], count);
-       out_8(&via[T1LH], count >> 8);
-       /* wait until it hits 0 */
-       while ((in_8(&via[IFR]) & T1_INT) == 0)
-               ;
-       dstart = get_dec();
-       /* clear the interrupt & wait until it hits 0 again */
-       in_8(&via[T1CL]);
-       while ((in_8(&via[IFR]) & T1_INT) == 0)
-               ;
-       dend = get_dec();
-
-       tb_ticks_per_jiffy = (dstart - dend) / (6 * (HZ/100));
-       tb_to_us = mulhwu_scale_factor(dstart - dend, 60000);
-
-       printk(KERN_INFO "via_calibrate_decr: ticks per jiffy = %u (%u ticks)\n",
-              tb_ticks_per_jiffy, dstart - dend);
-
-       iounmap(via);
-       
-       return 1;
-}
-
-#ifdef CONFIG_PM
-/*
- * Reset the time after a sleep.
- */
-static int
-time_sleep_notify(struct pmu_sleep_notifier *self, int when)
-{
-       static unsigned long time_diff;
-       unsigned long flags;
-       unsigned long seq;
-
-       switch (when) {
-       case PBOOK_SLEEP_NOW:
-               do {
-                       seq = read_seqbegin_irqsave(&xtime_lock, flags);
-                       time_diff = xtime.tv_sec - pmac_get_rtc_time();
-               } while (read_seqretry_irqrestore(&xtime_lock, seq, flags));
-               break;
-       case PBOOK_WAKE:
-               write_seqlock_irqsave(&xtime_lock, flags);
-               xtime.tv_sec = pmac_get_rtc_time() + time_diff;
-               xtime.tv_nsec = 0;
-               last_rtc_update = xtime.tv_sec;
-               write_sequnlock_irqrestore(&xtime_lock, flags);
-               break;
-       }
-       return PBOOK_SLEEP_OK;
-}
-
-static struct pmu_sleep_notifier time_sleep_notifier = {
-       time_sleep_notify, SLEEP_LEVEL_MISC,
-};
-#endif /* CONFIG_PM */
-
-/*
- * Query the OF and get the decr frequency.
- * This was taken from the pmac time_init() when merging the prep/pmac
- * time functions.
- */
-void __init
-pmac_calibrate_decr(void)
-{
-       struct device_node *cpu;
-       unsigned int freq, *fp;
-
-#ifdef CONFIG_PM
-       pmu_register_sleep_notifier(&time_sleep_notifier);
-#endif /* CONFIG_PM */
-
-       /* We assume MacRISC2 machines have correct device-tree
-        * calibration. That's better since the VIA itself seems
-        * to be slightly off. --BenH
-        */
-       if (!machine_is_compatible("MacRISC2") &&
-           !machine_is_compatible("MacRISC3") &&
-           !machine_is_compatible("MacRISC4"))
-               if (via_calibrate_decr())
-                       return;
-
-       /* Special case: QuickSilver G4s seem to have a badly calibrated
-        * timebase-frequency in OF, VIA is much better on these. We should
-        * probably implement calibration based on the KL timer on these
-        * machines anyway... -BenH
-        */
-       if (machine_is_compatible("PowerMac3,5"))
-               if (via_calibrate_decr())
-                       return;
-       /*
-        * The cpu node should have a timebase-frequency property
-        * to tell us the rate at which the decrementer counts.
-        */
-       cpu = find_type_devices("cpu");
-       if (cpu == 0)
-               panic("can't find cpu node in time_init");
-       fp = (unsigned int *) get_property(cpu, "timebase-frequency", NULL);
-       if (fp == 0)
-               panic("can't get cpu timebase frequency");
-       freq = *fp;
-       printk("time_init: decrementer frequency = %u.%.6u MHz\n",
-              freq/1000000, freq%1000000);
-       tb_ticks_per_jiffy = freq / HZ;
-       tb_to_us = mulhwu_scale_factor(freq, 1000000);
-}
diff --git a/arch/powerpc/platforms/powermac/setup.c b/arch/powerpc/platforms/powermac/setup.c
new file mode 100644 (file)
index 0000000..1b12bf9
--- /dev/null
@@ -0,0 +1,663 @@
+/*
+ *  arch/ppc/platforms/setup.c
+ *
+ *  PowerPC version
+ *    Copyright (C) 1995-1996 Gary Thomas (gdt@linuxppc.org)
+ *
+ *  Adapted for Power Macintosh by Paul Mackerras
+ *    Copyright (C) 1996 Paul Mackerras (paulus@cs.anu.edu.au)
+ *
+ *  Derived from "arch/alpha/kernel/setup.c"
+ *    Copyright (C) 1995 Linus Torvalds
+ *
+ *  Maintained by Benjamin Herrenschmidt (benh@kernel.crashing.org)
+ *
+ *  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.
+ *
+ */
+
+/*
+ * bootup setup stuff..
+ */
+
+#include <linux/config.h>
+#include <linux/init.h>
+#include <linux/errno.h>
+#include <linux/sched.h>
+#include <linux/kernel.h>
+#include <linux/mm.h>
+#include <linux/stddef.h>
+#include <linux/unistd.h>
+#include <linux/ptrace.h>
+#include <linux/slab.h>
+#include <linux/user.h>
+#include <linux/a.out.h>
+#include <linux/tty.h>
+#include <linux/string.h>
+#include <linux/delay.h>
+#include <linux/ioport.h>
+#include <linux/major.h>
+#include <linux/initrd.h>
+#include <linux/vt_kern.h>
+#include <linux/console.h>
+#include <linux/ide.h>
+#include <linux/pci.h>
+#include <linux/adb.h>
+#include <linux/cuda.h>
+#include <linux/pmu.h>
+#include <linux/irq.h>
+#include <linux/seq_file.h>
+#include <linux/root_dev.h>
+#include <linux/bitops.h>
+#include <linux/suspend.h>
+
+#include <asm/reg.h>
+#include <asm/sections.h>
+#include <asm/prom.h>
+#include <asm/system.h>
+#include <asm/pgtable.h>
+#include <asm/io.h>
+#include <asm/pci-bridge.h>
+#include <asm/ohare.h>
+#include <asm/mediabay.h>
+#include <asm/machdep.h>
+#include <asm/dma.h>
+#include <asm/bootx.h>
+#include <asm/cputable.h>
+#include <asm/btext.h>
+#include <asm/pmac_feature.h>
+#include <asm/time.h>
+#include <asm/of_device.h>
+#include <asm/mmu_context.h>
+
+#include "pmac_pic.h"
+
+#undef SHOW_GATWICK_IRQS
+
+extern long pmac_time_init(void);
+extern unsigned long pmac_get_rtc_time(void);
+extern int pmac_set_rtc_time(unsigned long nowtime);
+extern void pmac_read_rtc_time(void);
+extern void pmac_calibrate_decr(void);
+extern void pmac_pcibios_fixup(void);
+extern void pmac_find_bridges(void);
+extern unsigned long pmac_ide_get_base(int index);
+extern void pmac_ide_init_hwif_ports(hw_regs_t *hw,
+       unsigned long data_port, unsigned long ctrl_port, int *irq);
+
+extern void pmac_nvram_update(void);
+extern unsigned char pmac_nvram_read_byte(int addr);
+extern void pmac_nvram_write_byte(int addr, unsigned char val);
+extern int pmac_pci_enable_device_hook(struct pci_dev *dev, int initial);
+extern void pmac_pcibios_after_init(void);
+extern int of_show_percpuinfo(struct seq_file *m, int i);
+
+unsigned char drive_info;
+
+int ppc_override_l2cr = 0;
+int ppc_override_l2cr_value;
+int has_l2cache = 0;
+
+int pmac_newworld = 1;
+
+static int current_root_goodness = -1;
+
+extern int pmac_newworld;
+
+#define DEFAULT_ROOT_DEVICE Root_SDA1  /* sda1 - slightly silly choice */
+
+extern void zs_kgdb_hook(int tty_num);
+static void ohare_init(void);
+#ifdef CONFIG_BOOTX_TEXT
+static void pmac_progress(char *s, unsigned short hex);
+#endif
+
+sys_ctrler_t sys_ctrler = SYS_CTRLER_UNKNOWN;
+
+#ifdef CONFIG_SMP
+extern struct smp_ops_t psurge_smp_ops;
+extern struct smp_ops_t core99_smp_ops;
+#endif /* CONFIG_SMP */
+
+static int
+pmac_show_cpuinfo(struct seq_file *m)
+{
+       struct device_node *np;
+       char *pp;
+       int plen;
+       int mbmodel = pmac_call_feature(PMAC_FTR_GET_MB_INFO,
+               NULL, PMAC_MB_INFO_MODEL, 0);
+       unsigned int mbflags = (unsigned int)pmac_call_feature(PMAC_FTR_GET_MB_INFO,
+               NULL, PMAC_MB_INFO_FLAGS, 0);
+       char* mbname;
+
+       if (pmac_call_feature(PMAC_FTR_GET_MB_INFO, NULL, PMAC_MB_INFO_NAME, (int)&mbname) != 0)
+               mbname = "Unknown";
+
+       /* find motherboard type */
+       seq_printf(m, "machine\t\t: ");
+       np = find_devices("device-tree");
+       if (np != NULL) {
+               pp = (char *) get_property(np, "model", NULL);
+               if (pp != NULL)
+                       seq_printf(m, "%s\n", pp);
+               else
+                       seq_printf(m, "PowerMac\n");
+               pp = (char *) get_property(np, "compatible", &plen);
+               if (pp != NULL) {
+                       seq_printf(m, "motherboard\t:");
+                       while (plen > 0) {
+                               int l = strlen(pp) + 1;
+                               seq_printf(m, " %s", pp);
+                               plen -= l;
+                               pp += l;
+                       }
+                       seq_printf(m, "\n");
+               }
+       } else
+               seq_printf(m, "PowerMac\n");
+
+       /* print parsed model */
+       seq_printf(m, "detected as\t: %d (%s)\n", mbmodel, mbname);
+       seq_printf(m, "pmac flags\t: %08x\n", mbflags);
+
+       /* find l2 cache info */
+       np = find_devices("l2-cache");
+       if (np == 0)
+               np = find_type_devices("cache");
+       if (np != 0) {
+               unsigned int *ic = (unsigned int *)
+                       get_property(np, "i-cache-size", NULL);
+               unsigned int *dc = (unsigned int *)
+                       get_property(np, "d-cache-size", NULL);
+               seq_printf(m, "L2 cache\t:");
+               has_l2cache = 1;
+               if (get_property(np, "cache-unified", NULL) != 0 && dc) {
+                       seq_printf(m, " %dK unified", *dc / 1024);
+               } else {
+                       if (ic)
+                               seq_printf(m, " %dK instruction", *ic / 1024);
+                       if (dc)
+                               seq_printf(m, "%s %dK data",
+                                          (ic? " +": ""), *dc / 1024);
+               }
+               pp = get_property(np, "ram-type", NULL);
+               if (pp)
+                       seq_printf(m, " %s", pp);
+               seq_printf(m, "\n");
+       }
+
+       /* find ram info */
+       np = find_devices("memory");
+       if (np != 0) {
+               int n;
+               struct reg_property *reg = (struct reg_property *)
+                       get_property(np, "reg", &n);
+
+               if (reg != 0) {
+                       unsigned long total = 0;
+
+                       for (n /= sizeof(struct reg_property); n > 0; --n)
+                               total += (reg++)->size;
+                       seq_printf(m, "memory\t\t: %luMB\n", total >> 20);
+               }
+       }
+
+       /* Checks "l2cr-value" property in the registry */
+       np = find_devices("cpus");
+       if (np == 0)
+               np = find_type_devices("cpu");
+       if (np != 0) {
+               unsigned int *l2cr = (unsigned int *)
+                       get_property(np, "l2cr-value", NULL);
+               if (l2cr != 0) {
+                       seq_printf(m, "l2cr override\t: 0x%x\n", *l2cr);
+               }
+       }
+
+       /* Indicate newworld/oldworld */
+       seq_printf(m, "pmac-generation\t: %s\n",
+                  pmac_newworld ? "NewWorld" : "OldWorld");
+
+
+       return 0;
+}
+
+static int
+pmac_show_percpuinfo(struct seq_file *m, int i)
+{
+#ifdef CONFIG_CPU_FREQ_PMAC
+       extern unsigned int pmac_get_one_cpufreq(int i);
+       unsigned int freq = pmac_get_one_cpufreq(i);
+       if (freq != 0) {
+               seq_printf(m, "clock\t\t: %dMHz\n", freq/1000);
+               return 0;
+       }
+#endif /* CONFIG_CPU_FREQ_PMAC */
+       return of_show_percpuinfo(m, i);
+}
+
+static volatile u32 *sysctrl_regs;
+
+void __init
+pmac_setup_arch(void)
+{
+       struct device_node *cpu;
+       int *fp;
+       unsigned long pvr;
+
+       pvr = PVR_VER(mfspr(SPRN_PVR));
+
+       /* Set loops_per_jiffy to a half-way reasonable value,
+          for use until calibrate_delay gets called. */
+       cpu = find_type_devices("cpu");
+       if (cpu != 0) {
+               fp = (int *) get_property(cpu, "clock-frequency", NULL);
+               if (fp != 0) {
+                       if (pvr == 4 || pvr >= 8)
+                               /* 604, G3, G4 etc. */
+                               loops_per_jiffy = *fp / HZ;
+                       else
+                               /* 601, 603, etc. */
+                               loops_per_jiffy = *fp / (2*HZ);
+               } else
+                       loops_per_jiffy = 50000000 / HZ;
+       }
+
+       /* this area has the CPU identification register
+          and some registers used by smp boards */
+       sysctrl_regs = (volatile u32 *) ioremap(0xf8000000, 0x1000);
+       ohare_init();
+
+       /* Lookup PCI hosts */
+       pmac_find_bridges();
+
+       /* Checks "l2cr-value" property in the registry */
+       if (cpu_has_feature(CPU_FTR_L2CR)) {
+               struct device_node *np = find_devices("cpus");
+               if (np == 0)
+                       np = find_type_devices("cpu");
+               if (np != 0) {
+                       unsigned int *l2cr = (unsigned int *)
+                               get_property(np, "l2cr-value", NULL);
+                       if (l2cr != 0) {
+                               ppc_override_l2cr = 1;
+                               ppc_override_l2cr_value = *l2cr;
+                               _set_L2CR(0);
+                               _set_L2CR(ppc_override_l2cr_value);
+                       }
+               }
+       }
+
+       if (ppc_override_l2cr)
+               printk(KERN_INFO "L2CR overriden (0x%x), backside cache is %s\n",
+                       ppc_override_l2cr_value, (ppc_override_l2cr_value & 0x80000000)
+                               ? "enabled" : "disabled");
+
+#ifdef CONFIG_KGDB
+       zs_kgdb_hook(0);
+#endif
+
+#ifdef CONFIG_ADB_CUDA
+       find_via_cuda();
+#else
+       if (find_devices("via-cuda")) {
+               printk("WARNING ! Your machine is Cuda based but your kernel\n");
+               printk("          wasn't compiled with CONFIG_ADB_CUDA option !\n");
+       }
+#endif
+#ifdef CONFIG_ADB_PMU
+       find_via_pmu();
+#else
+       if (find_devices("via-pmu")) {
+               printk("WARNING ! Your machine is PMU based but your kernel\n");
+               printk("          wasn't compiled with CONFIG_ADB_PMU option !\n");
+       }
+#endif
+#ifdef CONFIG_NVRAM
+       pmac_nvram_init();
+#endif
+#ifdef CONFIG_BLK_DEV_INITRD
+       if (initrd_start)
+               ROOT_DEV = Root_RAM0;
+       else
+#endif
+               ROOT_DEV = DEFAULT_ROOT_DEVICE;
+
+#ifdef CONFIG_SMP
+       /* Check for Core99 */
+       if (find_devices("uni-n") || find_devices("u3"))
+               ppc_md.smp_ops = &core99_smp_ops;
+       else
+               ppc_md.smp_ops = &psurge_smp_ops;
+#endif /* CONFIG_SMP */
+
+       pci_create_OF_bus_map();
+}
+
+static void __init ohare_init(void)
+{
+       /*
+        * Turn on the L2 cache.
+        * We assume that we have a PSX memory controller iff
+        * we have an ohare I/O controller.
+        */
+       if (find_devices("ohare") != NULL) {
+               if (((sysctrl_regs[2] >> 24) & 0xf) >= 3) {
+                       if (sysctrl_regs[4] & 0x10)
+                               sysctrl_regs[4] |= 0x04000020;
+                       else
+                               sysctrl_regs[4] |= 0x04000000;
+                       if(has_l2cache)
+                               printk(KERN_INFO "Level 2 cache enabled\n");
+               }
+       }
+}
+
+char *bootpath;
+char *bootdevice;
+void *boot_host;
+int boot_target;
+int boot_part;
+extern dev_t boot_dev;
+
+#ifdef CONFIG_SCSI
+void __init
+note_scsi_host(struct device_node *node, void *host)
+{
+       int l;
+       char *p;
+
+       l = strlen(node->full_name);
+       if (bootpath != NULL && bootdevice != NULL
+           && strncmp(node->full_name, bootdevice, l) == 0
+           && (bootdevice[l] == '/' || bootdevice[l] == 0)) {
+               boot_host = host;
+               /*
+                * There's a bug in OF 1.0.5.  (Why am I not surprised.)
+                * If you pass a path like scsi/sd@1:0 to canon, it returns
+                * something like /bandit@F2000000/gc@10/53c94@10000/sd@0,0
+                * That is, the scsi target number doesn't get preserved.
+                * So we pick the target number out of bootpath and use that.
+                */
+               p = strstr(bootpath, "/sd@");
+               if (p != NULL) {
+                       p += 4;
+                       boot_target = simple_strtoul(p, NULL, 10);
+                       p = strchr(p, ':');
+                       if (p != NULL)
+                               boot_part = simple_strtoul(p + 1, NULL, 10);
+               }
+       }
+}
+EXPORT_SYMBOL(note_scsi_host);
+#endif
+
+#if defined(CONFIG_BLK_DEV_IDE) && defined(CONFIG_BLK_DEV_IDE_PMAC)
+static dev_t __init
+find_ide_boot(void)
+{
+       char *p;
+       int n;
+       dev_t __init pmac_find_ide_boot(char *bootdevice, int n);
+
+       if (bootdevice == NULL)
+               return 0;
+       p = strrchr(bootdevice, '/');
+       if (p == NULL)
+               return 0;
+       n = p - bootdevice;
+
+       return pmac_find_ide_boot(bootdevice, n);
+}
+#endif /* CONFIG_BLK_DEV_IDE && CONFIG_BLK_DEV_IDE_PMAC */
+
+static void __init
+find_boot_device(void)
+{
+#if defined(CONFIG_BLK_DEV_IDE) && defined(CONFIG_BLK_DEV_IDE_PMAC)
+       boot_dev = find_ide_boot();
+#endif
+}
+
+static int initializing = 1;
+/* TODO: Merge the suspend-to-ram with the common code !!!
+ * currently, this is a stub implementation for suspend-to-disk
+ * only
+ */
+
+#ifdef CONFIG_SOFTWARE_SUSPEND
+
+static int pmac_pm_prepare(suspend_state_t state)
+{
+       printk(KERN_DEBUG "%s(%d)\n", __FUNCTION__, state);
+
+       return 0;
+}
+
+static int pmac_pm_enter(suspend_state_t state)
+{
+       printk(KERN_DEBUG "%s(%d)\n", __FUNCTION__, state);
+
+       /* Giveup the lazy FPU & vec so we don't have to back them
+        * up from the low level code
+        */
+       enable_kernel_fp();
+
+#ifdef CONFIG_ALTIVEC
+       if (cur_cpu_spec->cpu_features & CPU_FTR_ALTIVEC)
+               enable_kernel_altivec();
+#endif /* CONFIG_ALTIVEC */
+
+       return 0;
+}
+
+static int pmac_pm_finish(suspend_state_t state)
+{
+       printk(KERN_DEBUG "%s(%d)\n", __FUNCTION__, state);
+
+       /* Restore userland MMU context */
+       set_context(current->active_mm->context, current->active_mm->pgd);
+
+       return 0;
+}
+
+static struct pm_ops pmac_pm_ops = {
+       .pm_disk_mode   = PM_DISK_SHUTDOWN,
+       .prepare        = pmac_pm_prepare,
+       .enter          = pmac_pm_enter,
+       .finish         = pmac_pm_finish,
+};
+
+#endif /* CONFIG_SOFTWARE_SUSPEND */
+
+static int pmac_late_init(void)
+{
+       initializing = 0;
+#ifdef CONFIG_SOFTWARE_SUSPEND
+       pm_set_ops(&pmac_pm_ops);
+#endif /* CONFIG_SOFTWARE_SUSPEND */
+       return 0;
+}
+
+late_initcall(pmac_late_init);
+
+/* can't be __init - can be called whenever a disk is first accessed */
+void
+note_bootable_part(dev_t dev, int part, int goodness)
+{
+       static int found_boot = 0;
+       char *p;
+
+       if (!initializing)
+               return;
+       if ((goodness <= current_root_goodness) &&
+           ROOT_DEV != DEFAULT_ROOT_DEVICE)
+               return;
+       p = strstr(saved_command_line, "root=");
+       if (p != NULL && (p == saved_command_line || p[-1] == ' '))
+               return;
+
+       if (!found_boot) {
+               find_boot_device();
+               found_boot = 1;
+       }
+       if (!boot_dev || dev == boot_dev) {
+               ROOT_DEV = dev + part;
+               boot_dev = 0;
+               current_root_goodness = goodness;
+       }
+}
+
+static void
+pmac_restart(char *cmd)
+{
+#ifdef CONFIG_ADB_CUDA
+       struct adb_request req;
+#endif /* CONFIG_ADB_CUDA */
+
+       switch (sys_ctrler) {
+#ifdef CONFIG_ADB_CUDA
+       case SYS_CTRLER_CUDA:
+               cuda_request(&req, NULL, 2, CUDA_PACKET,
+                            CUDA_RESET_SYSTEM);
+               for (;;)
+                       cuda_poll();
+               break;
+#endif /* CONFIG_ADB_CUDA */
+#ifdef CONFIG_ADB_PMU
+       case SYS_CTRLER_PMU:
+               pmu_restart();
+               break;
+#endif /* CONFIG_ADB_PMU */
+       default: ;
+       }
+}
+
+static void
+pmac_power_off(void)
+{
+#ifdef CONFIG_ADB_CUDA
+       struct adb_request req;
+#endif /* CONFIG_ADB_CUDA */
+
+       switch (sys_ctrler) {
+#ifdef CONFIG_ADB_CUDA
+       case SYS_CTRLER_CUDA:
+               cuda_request(&req, NULL, 2, CUDA_PACKET,
+                            CUDA_POWERDOWN);
+               for (;;)
+                       cuda_poll();
+               break;
+#endif /* CONFIG_ADB_CUDA */
+#ifdef CONFIG_ADB_PMU
+       case SYS_CTRLER_PMU:
+               pmu_shutdown();
+               break;
+#endif /* CONFIG_ADB_PMU */
+       default: ;
+       }
+}
+
+static void
+pmac_halt(void)
+{
+       pmac_power_off();
+}
+
+void __init pmac_init(void)
+{
+       /* isa_io_base gets set in pmac_find_bridges */
+       isa_mem_base = PMAC_ISA_MEM_BASE;
+       pci_dram_offset = PMAC_PCI_DRAM_OFFSET;
+       ISA_DMA_THRESHOLD = ~0L;
+       DMA_MODE_READ = 1;
+       DMA_MODE_WRITE = 2;
+
+       ppc_md.setup_arch     = pmac_setup_arch;
+       ppc_md.show_cpuinfo   = pmac_show_cpuinfo;
+       ppc_md.show_percpuinfo = pmac_show_percpuinfo;
+       ppc_md.irq_canonicalize = NULL;
+       ppc_md.init_IRQ       = pmac_pic_init;
+       ppc_md.get_irq        = pmac_get_irq; /* Changed later on ... */
+
+       ppc_md.pcibios_fixup  = pmac_pcibios_fixup;
+       ppc_md.pcibios_enable_device_hook = pmac_pci_enable_device_hook;
+       ppc_md.pcibios_after_init = pmac_pcibios_after_init;
+       ppc_md.phys_mem_access_prot = pci_phys_mem_access_prot;
+
+       ppc_md.restart        = pmac_restart;
+       ppc_md.power_off      = pmac_power_off;
+       ppc_md.halt           = pmac_halt;
+
+       ppc_md.time_init      = pmac_time_init;
+       ppc_md.set_rtc_time   = pmac_set_rtc_time;
+       ppc_md.get_rtc_time   = pmac_get_rtc_time;
+       ppc_md.calibrate_decr = pmac_calibrate_decr;
+
+       ppc_md.feature_call   = pmac_do_feature_call;
+
+#if defined(CONFIG_BLK_DEV_IDE) || defined(CONFIG_BLK_DEV_IDE_MODULE)
+#ifdef CONFIG_BLK_DEV_IDE_PMAC
+        ppc_ide_md.ide_init_hwif       = pmac_ide_init_hwif_ports;
+        ppc_ide_md.default_io_base     = pmac_ide_get_base;
+#endif /* CONFIG_BLK_DEV_IDE_PMAC */
+#endif /* defined(CONFIG_BLK_DEV_IDE) || defined(CONFIG_BLK_DEV_IDE_MODULE) */
+
+#ifdef CONFIG_BOOTX_TEXT
+       ppc_md.progress = pmac_progress;
+#endif /* CONFIG_BOOTX_TEXT */
+
+       if (ppc_md.progress) ppc_md.progress("pmac_init(): exit", 0);
+
+}
+
+#ifdef CONFIG_BOOTX_TEXT
+static void __init
+pmac_progress(char *s, unsigned short hex)
+{
+       if (boot_text_mapped) {
+               btext_drawstring(s);
+               btext_drawchar('\n');
+       }
+}
+#endif /* CONFIG_BOOTX_TEXT */
+
+static int __init
+pmac_declare_of_platform_devices(void)
+{
+       struct device_node *np;
+
+       np = find_devices("uni-n");
+       if (np) {
+               for (np = np->child; np != NULL; np = np->sibling)
+                       if (strncmp(np->name, "i2c", 3) == 0) {
+                               of_platform_device_create(np, "uni-n-i2c",
+                                                         NULL);
+                               break;
+                       }
+       }
+       np = find_devices("u3");
+       if (np) {
+               for (np = np->child; np != NULL; np = np->sibling)
+                       if (strncmp(np->name, "i2c", 3) == 0) {
+                               of_platform_device_create(np, "u3-i2c",
+                                                         NULL);
+                               break;
+                       }
+       }
+
+       np = find_devices("valkyrie");
+       if (np)
+               of_platform_device_create(np, "valkyrie", NULL);
+       np = find_devices("platinum");
+       if (np)
+               of_platform_device_create(np, "platinum", NULL);
+
+       return 0;
+}
+
+device_initcall(pmac_declare_of_platform_devices);
diff --git a/arch/powerpc/platforms/powermac/sleep.S b/arch/powerpc/platforms/powermac/sleep.S
new file mode 100644 (file)
index 0000000..88419c7
--- /dev/null
@@ -0,0 +1,396 @@
+/*
+ * This file contains sleep low-level functions for PowerBook G3.
+ *    Copyright (C) 1999 Benjamin Herrenschmidt (benh@kernel.crashing.org)
+ *    and Paul Mackerras (paulus@samba.org).
+ *
+ * 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.
+ *
+ */
+
+#include <linux/config.h>
+#include <asm/processor.h>
+#include <asm/page.h>
+#include <asm/ppc_asm.h>
+#include <asm/cputable.h>
+#include <asm/cache.h>
+#include <asm/thread_info.h>
+#include <asm/asm-offsets.h>
+
+#define MAGIC  0x4c617273      /* 'Lars' */
+
+/*
+ * Structure for storing CPU registers on the stack.
+ */
+#define SL_SP          0
+#define SL_PC          4
+#define SL_MSR         8
+#define SL_SDR1                0xc
+#define SL_SPRG0       0x10    /* 4 sprg's */
+#define SL_DBAT0       0x20
+#define SL_IBAT0       0x28
+#define SL_DBAT1       0x30
+#define SL_IBAT1       0x38
+#define SL_DBAT2       0x40
+#define SL_IBAT2       0x48
+#define SL_DBAT3       0x50
+#define SL_IBAT3       0x58
+#define SL_TB          0x60
+#define SL_R2          0x68
+#define SL_CR          0x6c
+#define SL_R12         0x70    /* r12 to r31 */
+#define SL_SIZE                (SL_R12 + 80)
+
+       .section .text
+       .align  5
+
+#if defined(CONFIG_PM) || defined(CONFIG_CPU_FREQ_PMAC)
+
+/* This gets called by via-pmu.c late during the sleep process.
+ * The PMU was already send the sleep command and will shut us down
+ * soon. We need to save all that is needed and setup the wakeup
+ * vector that will be called by the ROM on wakeup
+ */
+_GLOBAL(low_sleep_handler)
+#ifndef CONFIG_6xx
+       blr
+#else
+       mflr    r0
+       stw     r0,4(r1)
+       stwu    r1,-SL_SIZE(r1)
+       mfcr    r0
+       stw     r0,SL_CR(r1)
+       stw     r2,SL_R2(r1)
+       stmw    r12,SL_R12(r1)
+
+       /* Save MSR & SDR1 */
+       mfmsr   r4
+       stw     r4,SL_MSR(r1)
+       mfsdr1  r4
+       stw     r4,SL_SDR1(r1)
+
+       /* Get a stable timebase and save it */
+1:     mftbu   r4
+       stw     r4,SL_TB(r1)
+       mftb    r5
+       stw     r5,SL_TB+4(r1)
+       mftbu   r3
+       cmpw    r3,r4
+       bne     1b
+
+       /* Save SPRGs */
+       mfsprg  r4,0
+       stw     r4,SL_SPRG0(r1)
+       mfsprg  r4,1
+       stw     r4,SL_SPRG0+4(r1)
+       mfsprg  r4,2
+       stw     r4,SL_SPRG0+8(r1)
+       mfsprg  r4,3
+       stw     r4,SL_SPRG0+12(r1)
+
+       /* Save BATs */
+       mfdbatu r4,0
+       stw     r4,SL_DBAT0(r1)
+       mfdbatl r4,0
+       stw     r4,SL_DBAT0+4(r1)
+       mfdbatu r4,1
+       stw     r4,SL_DBAT1(r1)
+       mfdbatl r4,1
+       stw     r4,SL_DBAT1+4(r1)
+       mfdbatu r4,2
+       stw     r4,SL_DBAT2(r1)
+       mfdbatl r4,2
+       stw     r4,SL_DBAT2+4(r1)
+       mfdbatu r4,3
+       stw     r4,SL_DBAT3(r1)
+       mfdbatl r4,3
+       stw     r4,SL_DBAT3+4(r1)
+       mfibatu r4,0
+       stw     r4,SL_IBAT0(r1)
+       mfibatl r4,0
+       stw     r4,SL_IBAT0+4(r1)
+       mfibatu r4,1
+       stw     r4,SL_IBAT1(r1)
+       mfibatl r4,1
+       stw     r4,SL_IBAT1+4(r1)
+       mfibatu r4,2
+       stw     r4,SL_IBAT2(r1)
+       mfibatl r4,2
+       stw     r4,SL_IBAT2+4(r1)
+       mfibatu r4,3
+       stw     r4,SL_IBAT3(r1)
+       mfibatl r4,3
+       stw     r4,SL_IBAT3+4(r1)
+
+       /* Backup various CPU config stuffs */
+       bl      __save_cpu_setup
+
+       /* The ROM can wake us up via 2 different vectors:
+        *  - On wallstreet & lombard, we must write a magic
+        *    value 'Lars' at address 4 and a pointer to a
+        *    memory location containing the PC to resume from
+        *    at address 0.
+        *  - On Core99, we must store the wakeup vector at
+        *    address 0x80 and eventually it's parameters
+        *    at address 0x84. I've have some trouble with those
+        *    parameters however and I no longer use them.
+        */
+       lis     r5,grackle_wake_up@ha
+       addi    r5,r5,grackle_wake_up@l
+       tophys(r5,r5)
+       stw     r5,SL_PC(r1)
+       lis     r4,KERNELBASE@h
+       tophys(r5,r1)
+       addi    r5,r5,SL_PC
+       lis     r6,MAGIC@ha
+       addi    r6,r6,MAGIC@l
+       stw     r5,0(r4)
+       stw     r6,4(r4)
+       /* Setup stuffs at 0x80-0x84 for Core99 */
+       lis     r3,core99_wake_up@ha
+       addi    r3,r3,core99_wake_up@l
+       tophys(r3,r3)
+       stw     r3,0x80(r4)
+       stw     r5,0x84(r4)
+       /* Store a pointer to our backup storage into
+        * a kernel global
+        */
+       lis r3,sleep_storage@ha
+       addi r3,r3,sleep_storage@l
+       stw r5,0(r3)
+
+       .globl  low_cpu_die
+low_cpu_die:
+       /* Flush & disable all caches */
+       bl      flush_disable_caches
+
+       /* Turn off data relocation. */
+       mfmsr   r3              /* Save MSR in r7 */
+       rlwinm  r3,r3,0,28,26   /* Turn off DR bit */
+       sync
+       mtmsr   r3
+       isync
+
+BEGIN_FTR_SECTION
+       /* Flush any pending L2 data prefetches to work around HW bug */
+       sync
+       lis     r3,0xfff0
+       lwz     r0,0(r3)        /* perform cache-inhibited load to ROM */
+       sync                    /* (caches are disabled at this point) */
+END_FTR_SECTION_IFSET(CPU_FTR_SPEC7450)
+
+/*
+ * Set the HID0 and MSR for sleep.
+ */
+       mfspr   r2,SPRN_HID0
+       rlwinm  r2,r2,0,10,7    /* clear doze, nap */
+       oris    r2,r2,HID0_SLEEP@h
+       sync
+       isync
+       mtspr   SPRN_HID0,r2
+       sync
+
+/* This loop puts us back to sleep in case we have a spurrious
+ * wakeup so that the host bridge properly stays asleep. The
+ * CPU will be turned off, either after a known time (about 1
+ * second) on wallstreet & lombard, or as soon as the CPU enters
+ * SLEEP mode on core99
+ */
+       mfmsr   r2
+       oris    r2,r2,MSR_POW@h
+1:     sync
+       mtmsr   r2
+       isync
+       b       1b
+
+/*
+ * Here is the resume code.
+ */
+
+
+/*
+ * Core99 machines resume here
+ * r4 has the physical address of SL_PC(sp) (unused)
+ */
+_GLOBAL(core99_wake_up)
+       /* Make sure HID0 no longer contains any sleep bit and that data cache
+        * is disabled
+        */
+       mfspr   r3,SPRN_HID0
+       rlwinm  r3,r3,0,11,7            /* clear SLEEP, NAP, DOZE bits */
+       rlwinm  3,r3,0,18,15            /* clear DCE, ICE */
+       mtspr   SPRN_HID0,r3
+       sync
+       isync
+
+       /* sanitize MSR */
+       mfmsr   r3
+       ori     r3,r3,MSR_EE|MSR_IP
+       xori    r3,r3,MSR_EE|MSR_IP
+       sync
+       isync
+       mtmsr   r3
+       sync
+       isync
+
+       /* Recover sleep storage */
+       lis     r3,sleep_storage@ha
+       addi    r3,r3,sleep_storage@l
+       tophys(r3,r3)
+       lwz     r1,0(r3)
+
+       /* Pass thru to older resume code ... */
+/*
+ * Here is the resume code for older machines.
+ * r1 has the physical address of SL_PC(sp).
+ */
+
+grackle_wake_up:
+
+       /* Restore the kernel's segment registers before
+        * we do any r1 memory access as we are not sure they
+        * are in a sane state above the first 256Mb region
+        */
+       li      r0,16           /* load up segment register values */
+       mtctr   r0              /* for context 0 */
+       lis     r3,0x2000       /* Ku = 1, VSID = 0 */
+       li      r4,0
+3:     mtsrin  r3,r4
+       addi    r3,r3,0x111     /* increment VSID */
+       addis   r4,r4,0x1000    /* address of next segment */
+       bdnz    3b
+       sync
+       isync
+
+       subi    r1,r1,SL_PC
+
+       /* Restore various CPU config stuffs */
+       bl      __restore_cpu_setup
+
+       /* Make sure all FPRs have been initialized */
+       bl      reloc_offset
+       bl      __init_fpu_registers
+
+       /* Invalidate & enable L1 cache, we don't care about
+        * whatever the ROM may have tried to write to memory
+        */
+       bl      __inval_enable_L1
+
+       /* Restore the BATs, and SDR1.  Then we can turn on the MMU. */
+       lwz     r4,SL_SDR1(r1)
+       mtsdr1  r4
+       lwz     r4,SL_SPRG0(r1)
+       mtsprg  0,r4
+       lwz     r4,SL_SPRG0+4(r1)
+       mtsprg  1,r4
+       lwz     r4,SL_SPRG0+8(r1)
+       mtsprg  2,r4
+       lwz     r4,SL_SPRG0+12(r1)
+       mtsprg  3,r4
+
+       lwz     r4,SL_DBAT0(r1)
+       mtdbatu 0,r4
+       lwz     r4,SL_DBAT0+4(r1)
+       mtdbatl 0,r4
+       lwz     r4,SL_DBAT1(r1)
+       mtdbatu 1,r4
+       lwz     r4,SL_DBAT1+4(r1)
+       mtdbatl 1,r4
+       lwz     r4,SL_DBAT2(r1)
+       mtdbatu 2,r4
+       lwz     r4,SL_DBAT2+4(r1)
+       mtdbatl 2,r4
+       lwz     r4,SL_DBAT3(r1)
+       mtdbatu 3,r4
+       lwz     r4,SL_DBAT3+4(r1)
+       mtdbatl 3,r4
+       lwz     r4,SL_IBAT0(r1)
+       mtibatu 0,r4
+       lwz     r4,SL_IBAT0+4(r1)
+       mtibatl 0,r4
+       lwz     r4,SL_IBAT1(r1)
+       mtibatu 1,r4
+       lwz     r4,SL_IBAT1+4(r1)
+       mtibatl 1,r4
+       lwz     r4,SL_IBAT2(r1)
+       mtibatu 2,r4
+       lwz     r4,SL_IBAT2+4(r1)
+       mtibatl 2,r4
+       lwz     r4,SL_IBAT3(r1)
+       mtibatu 3,r4
+       lwz     r4,SL_IBAT3+4(r1)
+       mtibatl 3,r4
+
+BEGIN_FTR_SECTION
+       li      r4,0
+       mtspr   SPRN_DBAT4U,r4
+       mtspr   SPRN_DBAT4L,r4
+       mtspr   SPRN_DBAT5U,r4
+       mtspr   SPRN_DBAT5L,r4
+       mtspr   SPRN_DBAT6U,r4
+       mtspr   SPRN_DBAT6L,r4
+       mtspr   SPRN_DBAT7U,r4
+       mtspr   SPRN_DBAT7L,r4
+       mtspr   SPRN_IBAT4U,r4
+       mtspr   SPRN_IBAT4L,r4
+       mtspr   SPRN_IBAT5U,r4
+       mtspr   SPRN_IBAT5L,r4
+       mtspr   SPRN_IBAT6U,r4
+       mtspr   SPRN_IBAT6L,r4
+       mtspr   SPRN_IBAT7U,r4
+       mtspr   SPRN_IBAT7L,r4
+END_FTR_SECTION_IFSET(CPU_FTR_HAS_HIGH_BATS)
+
+       /* Flush all TLBs */
+       lis     r4,0x1000
+1:     addic.  r4,r4,-0x1000
+       tlbie   r4
+       blt     1b
+       sync
+
+       /* restore the MSR and turn on the MMU */
+       lwz     r3,SL_MSR(r1)
+       bl      turn_on_mmu
+
+       /* get back the stack pointer */
+       tovirt(r1,r1)
+
+       /* Restore TB */
+       li      r3,0
+       mttbl   r3
+       lwz     r3,SL_TB(r1)
+       lwz     r4,SL_TB+4(r1)
+       mttbu   r3
+       mttbl   r4
+
+       /* Restore the callee-saved registers and return */
+       lwz     r0,SL_CR(r1)
+       mtcr    r0
+       lwz     r2,SL_R2(r1)
+       lmw     r12,SL_R12(r1)
+       addi    r1,r1,SL_SIZE
+       lwz     r0,4(r1)
+       mtlr    r0
+       blr
+
+turn_on_mmu:
+       mflr    r4
+       tovirt(r4,r4)
+       mtsrr0  r4
+       mtsrr1  r3
+       sync
+       isync
+       rfi
+
+#endif /* defined(CONFIG_PM) || defined(CONFIG_CPU_FREQ) */
+
+       .section .data
+       .balign L1_CACHE_LINE_SIZE
+sleep_storage:
+       .long 0
+       .balign L1_CACHE_LINE_SIZE, 0
+
+#endif /* CONFIG_6xx */
+       .section .text
diff --git a/arch/powerpc/platforms/powermac/smp.c b/arch/powerpc/platforms/powermac/smp.c
new file mode 100644 (file)
index 0000000..fb99633
--- /dev/null
@@ -0,0 +1,716 @@
+/*
+ * SMP support for power macintosh.
+ *
+ * We support both the old "powersurge" SMP architecture
+ * and the current Core99 (G4 PowerMac) machines.
+ *
+ * Note that we don't support the very first rev. of
+ * Apple/DayStar 2 CPUs board, the one with the funky
+ * watchdog. Hopefully, none of these should be there except
+ * maybe internally to Apple. I should probably still add some
+ * code to detect this card though and disable SMP. --BenH.
+ *
+ * Support Macintosh G4 SMP by Troy Benjegerdes (hozer@drgw.net)
+ * and Ben Herrenschmidt <benh@kernel.crashing.org>.
+ *
+ * Support for DayStar quad CPU cards
+ * Copyright (C) XLR8, Inc. 1994-2000
+ *
+ *  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.
+ */
+#include <linux/config.h>
+#include <linux/kernel.h>
+#include <linux/sched.h>
+#include <linux/smp.h>
+#include <linux/smp_lock.h>
+#include <linux/interrupt.h>
+#include <linux/kernel_stat.h>
+#include <linux/delay.h>
+#include <linux/init.h>
+#include <linux/spinlock.h>
+#include <linux/errno.h>
+#include <linux/hardirq.h>
+#include <linux/cpu.h>
+
+#include <asm/ptrace.h>
+#include <asm/atomic.h>
+#include <asm/irq.h>
+#include <asm/page.h>
+#include <asm/pgtable.h>
+#include <asm/sections.h>
+#include <asm/io.h>
+#include <asm/prom.h>
+#include <asm/smp.h>
+#include <asm/residual.h>
+#include <asm/machdep.h>
+#include <asm/pmac_feature.h>
+#include <asm/time.h>
+#include <asm/mpic.h>
+#include <asm/cacheflush.h>
+#include <asm/keylargo.h>
+
+/*
+ * Powersurge (old powermac SMP) support.
+ */
+
+extern void __secondary_start_pmac_0(void);
+
+/* Addresses for powersurge registers */
+#define HAMMERHEAD_BASE                0xf8000000
+#define HHEAD_CONFIG           0x90
+#define HHEAD_SEC_INTR         0xc0
+
+/* register for interrupting the primary processor on the powersurge */
+/* N.B. this is actually the ethernet ROM! */
+#define PSURGE_PRI_INTR                0xf3019000
+
+/* register for storing the start address for the secondary processor */
+/* N.B. this is the PCI config space address register for the 1st bridge */
+#define PSURGE_START           0xf2800000
+
+/* Daystar/XLR8 4-CPU card */
+#define PSURGE_QUAD_REG_ADDR   0xf8800000
+
+#define PSURGE_QUAD_IRQ_SET    0
+#define PSURGE_QUAD_IRQ_CLR    1
+#define PSURGE_QUAD_IRQ_PRIMARY        2
+#define PSURGE_QUAD_CKSTOP_CTL 3
+#define PSURGE_QUAD_PRIMARY_ARB        4
+#define PSURGE_QUAD_BOARD_ID   6
+#define PSURGE_QUAD_WHICH_CPU  7
+#define PSURGE_QUAD_CKSTOP_RDBK        8
+#define PSURGE_QUAD_RESET_CTL  11
+
+#define PSURGE_QUAD_OUT(r, v)  (out_8(quad_base + ((r) << 4) + 4, (v)))
+#define PSURGE_QUAD_IN(r)      (in_8(quad_base + ((r) << 4) + 4) & 0x0f)
+#define PSURGE_QUAD_BIS(r, v)  (PSURGE_QUAD_OUT((r), PSURGE_QUAD_IN(r) | (v)))
+#define PSURGE_QUAD_BIC(r, v)  (PSURGE_QUAD_OUT((r), PSURGE_QUAD_IN(r) & ~(v)))
+
+/* virtual addresses for the above */
+static volatile u8 __iomem *hhead_base;
+static volatile u8 __iomem *quad_base;
+static volatile u32 __iomem *psurge_pri_intr;
+static volatile u8 __iomem *psurge_sec_intr;
+static volatile u32 __iomem *psurge_start;
+
+/* values for psurge_type */
+#define PSURGE_NONE            -1
+#define PSURGE_DUAL            0
+#define PSURGE_QUAD_OKEE       1
+#define PSURGE_QUAD_COTTON     2
+#define PSURGE_QUAD_ICEGRASS   3
+
+/* what sort of powersurge board we have */
+static int psurge_type = PSURGE_NONE;
+
+/* L2 and L3 cache settings to pass from CPU0 to CPU1 */
+volatile static long int core99_l2_cache;
+volatile static long int core99_l3_cache;
+
+/* Timebase freeze GPIO */
+static unsigned int core99_tb_gpio;
+
+/* Sync flag for HW tb sync */
+static volatile int sec_tb_reset = 0;
+static unsigned int pri_tb_hi, pri_tb_lo;
+static unsigned int pri_tb_stamp;
+
+static void __devinit core99_init_caches(int cpu)
+{
+       if (!cpu_has_feature(CPU_FTR_L2CR))
+               return;
+
+       if (cpu == 0) {
+               core99_l2_cache = _get_L2CR();
+               printk("CPU0: L2CR is %lx\n", core99_l2_cache);
+       } else {
+               printk("CPU%d: L2CR was %lx\n", cpu, _get_L2CR());
+               _set_L2CR(0);
+               _set_L2CR(core99_l2_cache);
+               printk("CPU%d: L2CR set to %lx\n", cpu, core99_l2_cache);
+       }
+
+       if (!cpu_has_feature(CPU_FTR_L3CR))
+               return;
+
+       if (cpu == 0){
+               core99_l3_cache = _get_L3CR();
+               printk("CPU0: L3CR is %lx\n", core99_l3_cache);
+       } else {
+               printk("CPU%d: L3CR was %lx\n", cpu, _get_L3CR());
+               _set_L3CR(0);
+               _set_L3CR(core99_l3_cache);
+               printk("CPU%d: L3CR set to %lx\n", cpu, core99_l3_cache);
+       }
+}
+
+/*
+ * Set and clear IPIs for powersurge.
+ */
+static inline void psurge_set_ipi(int cpu)
+{
+       if (psurge_type == PSURGE_NONE)
+               return;
+       if (cpu == 0)
+               in_be32(psurge_pri_intr);
+       else if (psurge_type == PSURGE_DUAL)
+               out_8(psurge_sec_intr, 0);
+       else
+               PSURGE_QUAD_OUT(PSURGE_QUAD_IRQ_SET, 1 << cpu);
+}
+
+static inline void psurge_clr_ipi(int cpu)
+{
+       if (cpu > 0) {
+               switch(psurge_type) {
+               case PSURGE_DUAL:
+                       out_8(psurge_sec_intr, ~0);
+               case PSURGE_NONE:
+                       break;
+               default:
+                       PSURGE_QUAD_OUT(PSURGE_QUAD_IRQ_CLR, 1 << cpu);
+               }
+       }
+}
+
+/*
+ * On powersurge (old SMP powermac architecture) we don't have
+ * separate IPIs for separate messages like openpic does.  Instead
+ * we have a bitmap for each processor, where a 1 bit means that
+ * the corresponding message is pending for that processor.
+ * Ideally each cpu's entry would be in a different cache line.
+ *  -- paulus.
+ */
+static unsigned long psurge_smp_message[NR_CPUS];
+
+void psurge_smp_message_recv(struct pt_regs *regs)
+{
+       int cpu = smp_processor_id();
+       int msg;
+
+       /* clear interrupt */
+       psurge_clr_ipi(cpu);
+
+       if (num_online_cpus() < 2)
+               return;
+
+       /* make sure there is a message there */
+       for (msg = 0; msg < 4; msg++)
+               if (test_and_clear_bit(msg, &psurge_smp_message[cpu]))
+                       smp_message_recv(msg, regs);
+}
+
+irqreturn_t psurge_primary_intr(int irq, void *d, struct pt_regs *regs)
+{
+       psurge_smp_message_recv(regs);
+       return IRQ_HANDLED;
+}
+
+static void smp_psurge_message_pass(int target, int msg, unsigned long data,
+                                          int wait)
+{
+       int i;
+
+       if (num_online_cpus() < 2)
+               return;
+
+       for (i = 0; i < NR_CPUS; i++) {
+               if (!cpu_online(i))
+                       continue;
+               if (target == MSG_ALL
+                   || (target == MSG_ALL_BUT_SELF && i != smp_processor_id())
+                   || target == i) {
+                       set_bit(msg, &psurge_smp_message[i]);
+                       psurge_set_ipi(i);
+               }
+       }
+}
+
+/*
+ * Determine a quad card presence. We read the board ID register, we
+ * force the data bus to change to something else, and we read it again.
+ * It it's stable, then the register probably exist (ugh !)
+ */
+static int __init psurge_quad_probe(void)
+{
+       int type;
+       unsigned int i;
+
+       type = PSURGE_QUAD_IN(PSURGE_QUAD_BOARD_ID);
+       if (type < PSURGE_QUAD_OKEE || type > PSURGE_QUAD_ICEGRASS
+           || type != PSURGE_QUAD_IN(PSURGE_QUAD_BOARD_ID))
+               return PSURGE_DUAL;
+
+       /* looks OK, try a slightly more rigorous test */
+       /* bogus is not necessarily cacheline-aligned,
+          though I don't suppose that really matters.  -- paulus */
+       for (i = 0; i < 100; i++) {
+               volatile u32 bogus[8];
+               bogus[(0+i)%8] = 0x00000000;
+               bogus[(1+i)%8] = 0x55555555;
+               bogus[(2+i)%8] = 0xFFFFFFFF;
+               bogus[(3+i)%8] = 0xAAAAAAAA;
+               bogus[(4+i)%8] = 0x33333333;
+               bogus[(5+i)%8] = 0xCCCCCCCC;
+               bogus[(6+i)%8] = 0xCCCCCCCC;
+               bogus[(7+i)%8] = 0x33333333;
+               wmb();
+               asm volatile("dcbf 0,%0" : : "r" (bogus) : "memory");
+               mb();
+               if (type != PSURGE_QUAD_IN(PSURGE_QUAD_BOARD_ID))
+                       return PSURGE_DUAL;
+       }
+       return type;
+}
+
+static void __init psurge_quad_init(void)
+{
+       int procbits;
+
+       if (ppc_md.progress) ppc_md.progress("psurge_quad_init", 0x351);
+       procbits = ~PSURGE_QUAD_IN(PSURGE_QUAD_WHICH_CPU);
+       if (psurge_type == PSURGE_QUAD_ICEGRASS)
+               PSURGE_QUAD_BIS(PSURGE_QUAD_RESET_CTL, procbits);
+       else
+               PSURGE_QUAD_BIC(PSURGE_QUAD_CKSTOP_CTL, procbits);
+       mdelay(33);
+       out_8(psurge_sec_intr, ~0);
+       PSURGE_QUAD_OUT(PSURGE_QUAD_IRQ_CLR, procbits);
+       PSURGE_QUAD_BIS(PSURGE_QUAD_RESET_CTL, procbits);
+       if (psurge_type != PSURGE_QUAD_ICEGRASS)
+               PSURGE_QUAD_BIS(PSURGE_QUAD_CKSTOP_CTL, procbits);
+       PSURGE_QUAD_BIC(PSURGE_QUAD_PRIMARY_ARB, procbits);
+       mdelay(33);
+       PSURGE_QUAD_BIC(PSURGE_QUAD_RESET_CTL, procbits);
+       mdelay(33);
+       PSURGE_QUAD_BIS(PSURGE_QUAD_PRIMARY_ARB, procbits);
+       mdelay(33);
+}
+
+static int __init smp_psurge_probe(void)
+{
+       int i, ncpus;
+
+       /* We don't do SMP on the PPC601 -- paulus */
+       if (PVR_VER(mfspr(SPRN_PVR)) == 1)
+               return 1;
+
+       /*
+        * The powersurge cpu board can be used in the generation
+        * of powermacs that have a socket for an upgradeable cpu card,
+        * including the 7500, 8500, 9500, 9600.
+        * The device tree doesn't tell you if you have 2 cpus because
+        * OF doesn't know anything about the 2nd processor.
+        * Instead we look for magic bits in magic registers,
+        * in the hammerhead memory controller in the case of the
+        * dual-cpu powersurge board.  -- paulus.
+        */
+       if (find_devices("hammerhead") == NULL)
+               return 1;
+
+       hhead_base = ioremap(HAMMERHEAD_BASE, 0x800);
+       quad_base = ioremap(PSURGE_QUAD_REG_ADDR, 1024);
+       psurge_sec_intr = hhead_base + HHEAD_SEC_INTR;
+
+       psurge_type = psurge_quad_probe();
+       if (psurge_type != PSURGE_DUAL) {
+               psurge_quad_init();
+               /* All released cards using this HW design have 4 CPUs */
+               ncpus = 4;
+       } else {
+               iounmap(quad_base);
+               if ((in_8(hhead_base + HHEAD_CONFIG) & 0x02) == 0) {
+                       /* not a dual-cpu card */
+                       iounmap(hhead_base);
+                       psurge_type = PSURGE_NONE;
+                       return 1;
+               }
+               ncpus = 2;
+       }
+
+       psurge_start = ioremap(PSURGE_START, 4);
+       psurge_pri_intr = ioremap(PSURGE_PRI_INTR, 4);
+
+       /* this is not actually strictly necessary -- paulus. */
+       for (i = 1; i < ncpus; ++i)
+               smp_hw_index[i] = i;
+
+       if (ppc_md.progress) ppc_md.progress("smp_psurge_probe - done", 0x352);
+
+       return ncpus;
+}
+
+static void __init smp_psurge_kick_cpu(int nr)
+{
+       unsigned long start = __pa(__secondary_start_pmac_0) + nr * 8;
+       unsigned long a;
+
+       /* may need to flush here if secondary bats aren't setup */
+       for (a = KERNELBASE; a < KERNELBASE + 0x800000; a += 32)
+               asm volatile("dcbf 0,%0" : : "r" (a) : "memory");
+       asm volatile("sync");
+
+       if (ppc_md.progress) ppc_md.progress("smp_psurge_kick_cpu", 0x353);
+
+       out_be32(psurge_start, start);
+       mb();
+
+       psurge_set_ipi(nr);
+       udelay(10);
+       psurge_clr_ipi(nr);
+
+       if (ppc_md.progress) ppc_md.progress("smp_psurge_kick_cpu - done", 0x354);
+}
+
+/*
+ * With the dual-cpu powersurge board, the decrementers and timebases
+ * of both cpus are frozen after the secondary cpu is started up,
+ * until we give the secondary cpu another interrupt.  This routine
+ * uses this to get the timebases synchronized.
+ *  -- paulus.
+ */
+static void __init psurge_dual_sync_tb(int cpu_nr)
+{
+       int t;
+
+       set_dec(tb_ticks_per_jiffy);
+       set_tb(0, 0);
+       last_jiffy_stamp(cpu_nr) = 0;
+
+       if (cpu_nr > 0) {
+               mb();
+               sec_tb_reset = 1;
+               return;
+       }
+
+       /* wait for the secondary to have reset its TB before proceeding */
+       for (t = 10000000; t > 0 && !sec_tb_reset; --t)
+               ;
+
+       /* now interrupt the secondary, starting both TBs */
+       psurge_set_ipi(1);
+
+       smp_tb_synchronized = 1;
+}
+
+static struct irqaction psurge_irqaction = {
+       .handler = psurge_primary_intr,
+       .flags = SA_INTERRUPT,
+       .mask = CPU_MASK_NONE,
+       .name = "primary IPI",
+};
+
+static void __init smp_psurge_setup_cpu(int cpu_nr)
+{
+
+       if (cpu_nr == 0) {
+               /* If we failed to start the second CPU, we should still
+                * send it an IPI to start the timebase & DEC or we might
+                * have them stuck.
+                */
+               if (num_online_cpus() < 2) {
+                       if (psurge_type == PSURGE_DUAL)
+                               psurge_set_ipi(1);
+                       return;
+               }
+               /* reset the entry point so if we get another intr we won't
+                * try to startup again */
+               out_be32(psurge_start, 0x100);
+               if (setup_irq(30, &psurge_irqaction))
+                       printk(KERN_ERR "Couldn't get primary IPI interrupt");
+       }
+
+       if (psurge_type == PSURGE_DUAL)
+               psurge_dual_sync_tb(cpu_nr);
+}
+
+void __init smp_psurge_take_timebase(void)
+{
+       /* Dummy implementation */
+}
+
+void __init smp_psurge_give_timebase(void)
+{
+       /* Dummy implementation */
+}
+
+static int __init smp_core99_probe(void)
+{
+#ifdef CONFIG_6xx
+       extern int powersave_nap;
+#endif
+       struct device_node *cpus, *firstcpu;
+       int i, ncpus = 0, boot_cpu = -1;
+       u32 *tbprop = NULL;
+
+       if (ppc_md.progress) ppc_md.progress("smp_core99_probe", 0x345);
+       cpus = firstcpu = find_type_devices("cpu");
+       while(cpus != NULL) {
+               u32 *regprop = (u32 *)get_property(cpus, "reg", NULL);
+               char *stateprop = (char *)get_property(cpus, "state", NULL);
+               if (regprop != NULL && stateprop != NULL &&
+                   !strncmp(stateprop, "running", 7))
+                       boot_cpu = *regprop;
+               ++ncpus;
+               cpus = cpus->next;
+       }
+       if (boot_cpu == -1)
+               printk(KERN_WARNING "Couldn't detect boot CPU !\n");
+       if (boot_cpu != 0)
+               printk(KERN_WARNING "Boot CPU is %d, unsupported setup !\n", boot_cpu);
+
+       if (machine_is_compatible("MacRISC4")) {
+               extern struct smp_ops_t core99_smp_ops;
+
+               core99_smp_ops.take_timebase = smp_generic_take_timebase;
+               core99_smp_ops.give_timebase = smp_generic_give_timebase;
+       } else {
+               if (firstcpu != NULL)
+                       tbprop = (u32 *)get_property(firstcpu, "timebase-enable", NULL);
+               if (tbprop)
+                       core99_tb_gpio = *tbprop;
+               else
+                       core99_tb_gpio = KL_GPIO_TB_ENABLE;
+       }
+
+       if (ncpus > 1) {
+               mpic_request_ipis();
+               for (i = 1; i < ncpus; ++i)
+                       smp_hw_index[i] = i;
+#ifdef CONFIG_6xx
+               powersave_nap = 0;
+#endif
+               core99_init_caches(0);
+       }
+
+       return ncpus;
+}
+
+static void __devinit smp_core99_kick_cpu(int nr)
+{
+       unsigned long save_vector, new_vector;
+       unsigned long flags;
+
+       volatile unsigned long *vector
+                = ((volatile unsigned long *)(KERNELBASE+0x100));
+       if (nr < 0 || nr > 3)
+               return;
+       if (ppc_md.progress) ppc_md.progress("smp_core99_kick_cpu", 0x346);
+
+       local_irq_save(flags);
+       local_irq_disable();
+
+       /* Save reset vector */
+       save_vector = *vector;
+
+       /* Setup fake reset vector that does    
+        *   b __secondary_start_pmac_0 + nr*8 - KERNELBASE
+        */
+       new_vector = (unsigned long) __secondary_start_pmac_0 + nr * 8;
+       *vector = 0x48000002 + new_vector - KERNELBASE;
+
+       /* flush data cache and inval instruction cache */
+       flush_icache_range((unsigned long) vector, (unsigned long) vector + 4);
+
+       /* Put some life in our friend */
+       pmac_call_feature(PMAC_FTR_RESET_CPU, NULL, nr, 0);
+
+       /* FIXME: We wait a bit for the CPU to take the exception, I should
+        * instead wait for the entry code to set something for me. Well,
+        * ideally, all that crap will be done in prom.c and the CPU left
+        * in a RAM-based wait loop like CHRP.
+        */
+       mdelay(1);
+
+       /* Restore our exception vector */
+       *vector = save_vector;
+       flush_icache_range((unsigned long) vector, (unsigned long) vector + 4);
+
+       local_irq_restore(flags);
+       if (ppc_md.progress) ppc_md.progress("smp_core99_kick_cpu done", 0x347);
+}
+
+static void __devinit smp_core99_setup_cpu(int cpu_nr)
+{
+       /* Setup L2/L3 */
+       if (cpu_nr != 0)
+               core99_init_caches(cpu_nr);
+
+       /* Setup openpic */
+       mpic_setup_this_cpu();
+
+       if (cpu_nr == 0) {
+#ifdef CONFIG_POWER4
+               extern void g5_phy_disable_cpu1(void);
+
+               /* If we didn't start the second CPU, we must take
+                * it off the bus
+                */
+               if (machine_is_compatible("MacRISC4") &&
+                   num_online_cpus() < 2)              
+                       g5_phy_disable_cpu1();
+#endif /* CONFIG_POWER4 */
+               if (ppc_md.progress) ppc_md.progress("core99_setup_cpu 0 done", 0x349);
+       }
+}
+
+/* not __init, called in sleep/wakeup code */
+void smp_core99_take_timebase(void)
+{
+       unsigned long flags;
+
+       /* tell the primary we're here */
+       sec_tb_reset = 1;
+       mb();
+
+       /* wait for the primary to set pri_tb_hi/lo */
+       while (sec_tb_reset < 2)
+               mb();
+
+       /* set our stuff the same as the primary */
+       local_irq_save(flags);
+       set_dec(1);
+       set_tb(pri_tb_hi, pri_tb_lo);
+       last_jiffy_stamp(smp_processor_id()) = pri_tb_stamp;
+       mb();
+
+       /* tell the primary we're done */
+               sec_tb_reset = 0;
+       mb();
+       local_irq_restore(flags);
+}
+
+/* not __init, called in sleep/wakeup code */
+void smp_core99_give_timebase(void)
+{
+       unsigned long flags;
+       unsigned int t;
+
+       /* wait for the secondary to be in take_timebase */
+       for (t = 100000; t > 0 && !sec_tb_reset; --t)
+               udelay(10);
+       if (!sec_tb_reset) {
+               printk(KERN_WARNING "Timeout waiting sync on second CPU\n");
+               return;
+       }
+
+       /* freeze the timebase and read it */
+       /* disable interrupts so the timebase is disabled for the
+          shortest possible time */
+       local_irq_save(flags);
+       pmac_call_feature(PMAC_FTR_WRITE_GPIO, NULL, core99_tb_gpio, 4);
+       pmac_call_feature(PMAC_FTR_READ_GPIO, NULL, core99_tb_gpio, 0);
+       mb();
+       pri_tb_hi = get_tbu();
+       pri_tb_lo = get_tbl();
+       pri_tb_stamp = last_jiffy_stamp(smp_processor_id());
+       mb();
+
+       /* tell the secondary we're ready */
+       sec_tb_reset = 2;
+       mb();
+
+       /* wait for the secondary to have taken it */
+       for (t = 100000; t > 0 && sec_tb_reset; --t)
+               udelay(10);
+       if (sec_tb_reset)
+               printk(KERN_WARNING "Timeout waiting sync(2) on second CPU\n");
+       else
+               smp_tb_synchronized = 1;
+
+       /* Now, restart the timebase by leaving the GPIO to an open collector */
+               pmac_call_feature(PMAC_FTR_WRITE_GPIO, NULL, core99_tb_gpio, 0);
+        pmac_call_feature(PMAC_FTR_READ_GPIO, NULL, core99_tb_gpio, 0);
+       local_irq_restore(flags);
+}
+
+void smp_core99_message_pass(int target, int msg, unsigned long data, int wait)
+{
+       cpumask_t mask = CPU_MASK_ALL;
+       /* make sure we're sending something that translates to an IPI */
+       if (msg > 0x3) {
+               printk("SMP %d: smp_message_pass: unknown msg %d\n",
+                      smp_processor_id(), msg);
+               return;
+       }
+       switch (target) {
+       case MSG_ALL:
+               mpic_send_ipi(msg, cpus_addr(mask)[0]);
+               break;
+       case MSG_ALL_BUT_SELF:
+               cpu_clear(smp_processor_id(), mask);
+               mpic_send_ipi(msg, cpus_addr(mask)[0]);
+               break;
+       default:
+               mpic_send_ipi(msg, 1 << target);
+               break;
+       }
+}
+
+
+/* PowerSurge-style Macs */
+struct smp_ops_t psurge_smp_ops = {
+       .message_pass   = smp_psurge_message_pass,
+       .probe          = smp_psurge_probe,
+       .kick_cpu       = smp_psurge_kick_cpu,
+       .setup_cpu      = smp_psurge_setup_cpu,
+       .give_timebase  = smp_psurge_give_timebase,
+       .take_timebase  = smp_psurge_take_timebase,
+};
+
+/* Core99 Macs (dual G4s) */
+struct smp_ops_t core99_smp_ops = {
+       .message_pass   = smp_core99_message_pass,
+       .probe          = smp_core99_probe,
+       .kick_cpu       = smp_core99_kick_cpu,
+       .setup_cpu      = smp_core99_setup_cpu,
+       .give_timebase  = smp_core99_give_timebase,
+       .take_timebase  = smp_core99_take_timebase,
+};
+
+#ifdef CONFIG_HOTPLUG_CPU
+
+int __cpu_disable(void)
+{
+       cpu_clear(smp_processor_id(), cpu_online_map);
+
+       /* XXX reset cpu affinity here */
+       mpic_cpu_set_priority(0xf);
+       asm volatile("mtdec %0" : : "r" (0x7fffffff));
+       mb();
+       udelay(20);
+       asm volatile("mtdec %0" : : "r" (0x7fffffff));
+       return 0;
+}
+
+extern void low_cpu_die(void) __attribute__((noreturn)); /* in pmac_sleep.S */
+static int cpu_dead[NR_CPUS];
+
+void cpu_die(void)
+{
+       local_irq_disable();
+       cpu_dead[smp_processor_id()] = 1;
+       mb();
+       low_cpu_die();
+}
+
+void __cpu_die(unsigned int cpu)
+{
+       int timeout;
+
+       timeout = 1000;
+       while (!cpu_dead[cpu]) {
+               if (--timeout == 0) {
+                       printk("CPU %u refused to die!\n", cpu);
+                       break;
+               }
+               msleep(1);
+       }
+       cpu_callin_map[cpu] = 0;
+       cpu_dead[cpu] = 0;
+}
+
+#endif
diff --git a/arch/powerpc/platforms/powermac/time.c b/arch/powerpc/platforms/powermac/time.c
new file mode 100644 (file)
index 0000000..ff6adff
--- /dev/null
@@ -0,0 +1,291 @@
+/*
+ * Support for periodic interrupts (100 per second) and for getting
+ * the current time from the RTC on Power Macintoshes.
+ *
+ * We use the decrementer register for our periodic interrupts.
+ *
+ * Paul Mackerras      August 1996.
+ * Copyright (C) 1996 Paul Mackerras.
+ */
+#include <linux/config.h>
+#include <linux/errno.h>
+#include <linux/sched.h>
+#include <linux/kernel.h>
+#include <linux/param.h>
+#include <linux/string.h>
+#include <linux/mm.h>
+#include <linux/init.h>
+#include <linux/time.h>
+#include <linux/adb.h>
+#include <linux/cuda.h>
+#include <linux/pmu.h>
+#include <linux/hardirq.h>
+
+#include <asm/sections.h>
+#include <asm/prom.h>
+#include <asm/system.h>
+#include <asm/io.h>
+#include <asm/pgtable.h>
+#include <asm/machdep.h>
+#include <asm/time.h>
+#include <asm/nvram.h>
+
+/* Apparently the RTC stores seconds since 1 Jan 1904 */
+#define RTC_OFFSET     2082844800
+
+/*
+ * Calibrate the decrementer frequency with the VIA timer 1.
+ */
+#define VIA_TIMER_FREQ_6       4700000 /* time 1 frequency * 6 */
+
+/* VIA registers */
+#define RS             0x200           /* skip between registers */
+#define T1CL           (4*RS)          /* Timer 1 ctr/latch (low 8 bits) */
+#define T1CH           (5*RS)          /* Timer 1 counter (high 8 bits) */
+#define T1LL           (6*RS)          /* Timer 1 latch (low 8 bits) */
+#define T1LH           (7*RS)          /* Timer 1 latch (high 8 bits) */
+#define ACR            (11*RS)         /* Auxiliary control register */
+#define IFR            (13*RS)         /* Interrupt flag register */
+
+/* Bits in ACR */
+#define T1MODE         0xc0            /* Timer 1 mode */
+#define T1MODE_CONT    0x40            /*  continuous interrupts */
+
+/* Bits in IFR and IER */
+#define T1_INT         0x40            /* Timer 1 interrupt */
+
+extern struct timezone sys_tz;
+
+long __init
+pmac_time_init(void)
+{
+#ifdef CONFIG_NVRAM
+       s32 delta = 0;
+       int dst;
+       
+       delta = ((s32)pmac_xpram_read(PMAC_XPRAM_MACHINE_LOC + 0x9)) << 16;
+       delta |= ((s32)pmac_xpram_read(PMAC_XPRAM_MACHINE_LOC + 0xa)) << 8;
+       delta |= pmac_xpram_read(PMAC_XPRAM_MACHINE_LOC + 0xb);
+       if (delta & 0x00800000UL)
+               delta |= 0xFF000000UL;
+       dst = ((pmac_xpram_read(PMAC_XPRAM_MACHINE_LOC + 0x8) & 0x80) != 0);
+       printk("GMT Delta read from XPRAM: %d minutes, DST: %s\n", delta/60,
+               dst ? "on" : "off");
+       return delta;
+#else
+       return 0;
+#endif
+}
+
+unsigned long
+pmac_get_rtc_time(void)
+{
+#if defined(CONFIG_ADB_CUDA) || defined(CONFIG_ADB_PMU)
+       struct adb_request req;
+       unsigned long now;
+#endif
+
+       /* Get the time from the RTC */
+       switch (sys_ctrler) {
+#ifdef CONFIG_ADB_CUDA
+       case SYS_CTRLER_CUDA:
+               if (cuda_request(&req, NULL, 2, CUDA_PACKET, CUDA_GET_TIME) < 0)
+                       return 0;
+               while (!req.complete)
+                       cuda_poll();
+               if (req.reply_len != 7)
+                       printk(KERN_ERR "pmac_get_rtc_time: got %d byte reply\n",
+                              req.reply_len);
+               now = (req.reply[3] << 24) + (req.reply[4] << 16)
+                       + (req.reply[5] << 8) + req.reply[6];
+               return now - RTC_OFFSET;
+#endif /* CONFIG_ADB_CUDA */
+#ifdef CONFIG_ADB_PMU
+       case SYS_CTRLER_PMU:
+               if (pmu_request(&req, NULL, 1, PMU_READ_RTC) < 0)
+                       return 0;
+               while (!req.complete)
+                       pmu_poll();
+               if (req.reply_len != 4)
+                       printk(KERN_ERR "pmac_get_rtc_time: got %d byte reply\n",
+                              req.reply_len);
+               now = (req.reply[0] << 24) + (req.reply[1] << 16)
+                       + (req.reply[2] << 8) + req.reply[3];
+               return now - RTC_OFFSET;
+#endif /* CONFIG_ADB_PMU */
+       default: ;
+       }
+       return 0;
+}
+
+int
+pmac_set_rtc_time(unsigned long nowtime)
+{
+#if defined(CONFIG_ADB_CUDA) || defined(CONFIG_ADB_PMU)
+       struct adb_request req;
+#endif
+
+       nowtime += RTC_OFFSET;
+
+       switch (sys_ctrler) {
+#ifdef CONFIG_ADB_CUDA
+       case SYS_CTRLER_CUDA:
+               if (cuda_request(&req, NULL, 6, CUDA_PACKET, CUDA_SET_TIME,
+                                nowtime >> 24, nowtime >> 16, nowtime >> 8, nowtime) < 0)
+                       return 0;
+               while (!req.complete)
+                       cuda_poll();
+               if ((req.reply_len != 3) && (req.reply_len != 7))
+                       printk(KERN_ERR "pmac_set_rtc_time: got %d byte reply\n",
+                              req.reply_len);
+               return 1;
+#endif /* CONFIG_ADB_CUDA */
+#ifdef CONFIG_ADB_PMU
+       case SYS_CTRLER_PMU:
+               if (pmu_request(&req, NULL, 5, PMU_SET_RTC,
+                               nowtime >> 24, nowtime >> 16, nowtime >> 8, nowtime) < 0)
+                       return 0;
+               while (!req.complete)
+                       pmu_poll();
+               if (req.reply_len != 0)
+                       printk(KERN_ERR "pmac_set_rtc_time: got %d byte reply\n",
+                              req.reply_len);
+               return 1;
+#endif /* CONFIG_ADB_PMU */
+       default:
+               return 0;
+       }
+}
+
+/*
+ * Calibrate the decrementer register using VIA timer 1.
+ * This is used both on powermacs and CHRP machines.
+ */
+int __init
+via_calibrate_decr(void)
+{
+       struct device_node *vias;
+       volatile unsigned char __iomem *via;
+       int count = VIA_TIMER_FREQ_6 / 100;
+       unsigned int dstart, dend;
+
+       vias = find_devices("via-cuda");
+       if (vias == 0)
+               vias = find_devices("via-pmu");
+       if (vias == 0)
+               vias = find_devices("via");
+       if (vias == 0 || vias->n_addrs == 0)
+               return 0;
+       via = ioremap(vias->addrs[0].address, vias->addrs[0].size);
+
+       /* set timer 1 for continuous interrupts */
+       out_8(&via[ACR], (via[ACR] & ~T1MODE) | T1MODE_CONT);
+       /* set the counter to a small value */
+       out_8(&via[T1CH], 2);
+       /* set the latch to `count' */
+       out_8(&via[T1LL], count);
+       out_8(&via[T1LH], count >> 8);
+       /* wait until it hits 0 */
+       while ((in_8(&via[IFR]) & T1_INT) == 0)
+               ;
+       dstart = get_dec();
+       /* clear the interrupt & wait until it hits 0 again */
+       in_8(&via[T1CL]);
+       while ((in_8(&via[IFR]) & T1_INT) == 0)
+               ;
+       dend = get_dec();
+
+       tb_ticks_per_jiffy = (dstart - dend) / (6 * (HZ/100));
+       tb_to_us = mulhwu_scale_factor(dstart - dend, 60000);
+
+       printk(KERN_INFO "via_calibrate_decr: ticks per jiffy = %u (%u ticks)\n",
+              tb_ticks_per_jiffy, dstart - dend);
+
+       iounmap(via);
+       
+       return 1;
+}
+
+#ifdef CONFIG_PM
+/*
+ * Reset the time after a sleep.
+ */
+static int
+time_sleep_notify(struct pmu_sleep_notifier *self, int when)
+{
+       static unsigned long time_diff;
+       unsigned long flags;
+       unsigned long seq;
+
+       switch (when) {
+       case PBOOK_SLEEP_NOW:
+               do {
+                       seq = read_seqbegin_irqsave(&xtime_lock, flags);
+                       time_diff = xtime.tv_sec - pmac_get_rtc_time();
+               } while (read_seqretry_irqrestore(&xtime_lock, seq, flags));
+               break;
+       case PBOOK_WAKE:
+               write_seqlock_irqsave(&xtime_lock, flags);
+               xtime.tv_sec = pmac_get_rtc_time() + time_diff;
+               xtime.tv_nsec = 0;
+               last_rtc_update = xtime.tv_sec;
+               write_sequnlock_irqrestore(&xtime_lock, flags);
+               break;
+       }
+       return PBOOK_SLEEP_OK;
+}
+
+static struct pmu_sleep_notifier time_sleep_notifier = {
+       time_sleep_notify, SLEEP_LEVEL_MISC,
+};
+#endif /* CONFIG_PM */
+
+/*
+ * Query the OF and get the decr frequency.
+ * This was taken from the pmac time_init() when merging the prep/pmac
+ * time functions.
+ */
+void __init
+pmac_calibrate_decr(void)
+{
+       struct device_node *cpu;
+       unsigned int freq, *fp;
+
+#ifdef CONFIG_PM
+       pmu_register_sleep_notifier(&time_sleep_notifier);
+#endif /* CONFIG_PM */
+
+       /* We assume MacRISC2 machines have correct device-tree
+        * calibration. That's better since the VIA itself seems
+        * to be slightly off. --BenH
+        */
+       if (!machine_is_compatible("MacRISC2") &&
+           !machine_is_compatible("MacRISC3") &&
+           !machine_is_compatible("MacRISC4"))
+               if (via_calibrate_decr())
+                       return;
+
+       /* Special case: QuickSilver G4s seem to have a badly calibrated
+        * timebase-frequency in OF, VIA is much better on these. We should
+        * probably implement calibration based on the KL timer on these
+        * machines anyway... -BenH
+        */
+       if (machine_is_compatible("PowerMac3,5"))
+               if (via_calibrate_decr())
+                       return;
+       /*
+        * The cpu node should have a timebase-frequency property
+        * to tell us the rate at which the decrementer counts.
+        */
+       cpu = find_type_devices("cpu");
+       if (cpu == 0)
+               panic("can't find cpu node in time_init");
+       fp = (unsigned int *) get_property(cpu, "timebase-frequency", NULL);
+       if (fp == 0)
+               panic("can't get cpu timebase frequency");
+       freq = *fp;
+       printk("time_init: decrementer frequency = %u.%.6u MHz\n",
+              freq/1000000, freq%1000000);
+       tb_ticks_per_jiffy = freq / HZ;
+       tb_to_us = mulhwu_scale_factor(freq, 1000000);
+}