aboutsummaryrefslogtreecommitdiff
path: root/arch/powerpc/platforms/powermac
diff options
context:
space:
mode:
Diffstat (limited to 'arch/powerpc/platforms/powermac')
-rw-r--r--arch/powerpc/platforms/powermac/Kconfig30
-rw-r--r--arch/powerpc/platforms/powermac/Makefile15
-rw-r--r--arch/powerpc/platforms/powermac/backlight.c332
-rw-r--r--arch/powerpc/platforms/powermac/bootx_init.c84
-rw-r--r--arch/powerpc/platforms/powermac/cache.S1
-rw-r--r--arch/powerpc/platforms/powermac/cpufreq_32.c727
-rw-r--r--arch/powerpc/platforms/powermac/cpufreq_64.c725
-rw-r--r--arch/powerpc/platforms/powermac/feature.c226
-rw-r--r--arch/powerpc/platforms/powermac/low_i2c.c222
-rw-r--r--arch/powerpc/platforms/powermac/nvram.c94
-rw-r--r--arch/powerpc/platforms/powermac/pci.c659
-rw-r--r--arch/powerpc/platforms/powermac/pfunc_base.c55
-rw-r--r--arch/powerpc/platforms/powermac/pfunc_core.c63
-rw-r--r--arch/powerpc/platforms/powermac/pic.c585
-rw-r--r--arch/powerpc/platforms/powermac/pic.h11
-rw-r--r--arch/powerpc/platforms/powermac/pmac.h17
-rw-r--r--arch/powerpc/platforms/powermac/setup.c434
-rw-r--r--arch/powerpc/platforms/powermac/sleep.S9
-rw-r--r--arch/powerpc/platforms/powermac/smp.c471
-rw-r--r--arch/powerpc/platforms/powermac/time.c66
-rw-r--r--arch/powerpc/platforms/powermac/udbg_adb.c6
-rw-r--r--arch/powerpc/platforms/powermac/udbg_scc.c39
22 files changed, 1782 insertions, 3089 deletions
diff --git a/arch/powerpc/platforms/powermac/Kconfig b/arch/powerpc/platforms/powermac/Kconfig
new file mode 100644
index 00000000000..1afd10f6785
--- /dev/null
+++ b/arch/powerpc/platforms/powermac/Kconfig
@@ -0,0 +1,30 @@
+config PPC_PMAC
+ bool "Apple PowerMac based machines"
+ depends on PPC_BOOK3S
+ select MPIC
+ select PCI
+ select PPC_INDIRECT_PCI if PPC32
+ select PPC_MPC106 if PPC32
+ select PPC_NATIVE
+ default y
+
+config PPC_PMAC64
+ bool
+ depends on PPC_PMAC && POWER4
+ select MPIC
+ select U3_DART
+ select MPIC_U3_HT_IRQS
+ select GENERIC_TBSYNC
+ select PPC_970_NAP
+ default y
+
+config PPC_PMAC32_PSURGE
+ bool "Support for powersurge upgrade cards" if EXPERT
+ depends on SMP && PPC32 && PPC_PMAC
+ select PPC_SMP_MUXED_IPI
+ default y
+ help
+ The powersurge cpu boards can be used in the generation
+ of powermacs that have a socket for an upgradeable cpu card,
+ including the 7500, 8500, 9500, 9600. Support exists for
+ both dual and quad socket upgrade cards.
diff --git a/arch/powerpc/platforms/powermac/Makefile b/arch/powerpc/platforms/powermac/Makefile
index 78093d7f97a..52c6ce1cc98 100644
--- a/arch/powerpc/platforms/powermac/Makefile
+++ b/arch/powerpc/platforms/powermac/Makefile
@@ -1,14 +1,19 @@
CFLAGS_bootx_init.o += -fPIC
+ifdef CONFIG_FUNCTION_TRACER
+# Do not trace early boot code
+CFLAGS_REMOVE_bootx_init.o = -pg -mno-sched-epilog
+endif
+
obj-y += pic.o setup.o time.o feature.o pci.o \
sleep.o low_i2c.o cache.o pfunc_core.o \
- pfunc_base.o
+ pfunc_base.o udbg_scc.o udbg_adb.o
obj-$(CONFIG_PMAC_BACKLIGHT) += backlight.o
-obj-$(CONFIG_CPU_FREQ_PMAC) += cpufreq_32.o
-obj-$(CONFIG_CPU_FREQ_PMAC64) += cpufreq_64.o
-obj-$(CONFIG_NVRAM) += nvram.o
+# CONFIG_NVRAM is an arch. independent tristate symbol, for pmac32 we really
+# need this to be a bool. Cheat here and pretend CONFIG_NVRAM=m is really
+# CONFIG_NVRAM=y
+obj-$(CONFIG_NVRAM:m=y) += nvram.o
# ppc64 pmac doesn't define CONFIG_NVRAM but needs nvram stuff
obj-$(CONFIG_PPC64) += nvram.o
obj-$(CONFIG_PPC32) += bootx_init.o
obj-$(CONFIG_SMP) += smp.o
-obj-$(CONFIG_PPC_MERGE) += udbg_scc.o udbg_adb.o
diff --git a/arch/powerpc/platforms/powermac/backlight.c b/arch/powerpc/platforms/powermac/backlight.c
index 8be2f7d071f..a00096b1c71 100644
--- a/arch/powerpc/platforms/powermac/backlight.c
+++ b/arch/powerpc/platforms/powermac/backlight.c
@@ -3,200 +3,218 @@
* Contains support for the backlight.
*
* Copyright (C) 2000 Benjamin Herrenschmidt
+ * Copyright (C) 2006 Michael Hanselmann <linux-kernel@hansmi.ch>
*
*/
-#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 <linux/fb.h>
+#include <linux/backlight.h>
+#include <linux/adb.h>
+#include <linux/pmu.h>
+#include <linux/atomic.h>
+#include <linux/export.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>
+#define OLD_BACKLIGHT_MAX 15
-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 pmac_backlight_key_worker(struct work_struct *work);
+static void pmac_backlight_set_legacy_worker(struct work_struct *work);
-static void backlight_callback(void *);
-static DECLARE_WORK(backlight_work, backlight_callback, NULL);
+static DECLARE_WORK(pmac_backlight_key_work, pmac_backlight_key_worker);
+static DECLARE_WORK(pmac_backlight_set_legacy_work, pmac_backlight_set_legacy_worker);
-void register_backlight_controller(struct backlight_controller *ctrler,
- void *data, char *type)
-{
- struct device_node* bk_node;
- char *prop;
- int valid = 0;
+/* Although these variables are used in interrupt context, it makes no sense to
+ * protect them. No user is able to produce enough key events per second and
+ * notice the errors that might happen.
+ */
+static int pmac_backlight_key_queued;
+static int pmac_backlight_set_legacy_queued;
- /* There's already a matching controller, bail out */
- if (backlighter != NULL)
- return;
+/* The via-pmu code allows the backlight to be grabbed, in which case the
+ * in-kernel control of the brightness needs to be disabled. This should
+ * only be used by really old PowerBooks.
+ */
+static atomic_t kernel_backlight_disabled = ATOMIC_INIT(0);
+
+/* Protect the pmac_backlight variable below.
+ You should hold this lock when using the pmac_backlight pointer to
+ prevent its potential removal. */
+DEFINE_MUTEX(pmac_backlight_mutex);
+
+/* Main backlight storage
+ *
+ * Backlight drivers in this variable are required to have the "ops"
+ * attribute set and to have an update_status function.
+ *
+ * We can only store one backlight here, but since Apple laptops have only one
+ * internal display, it doesn't matter. Other backlight drivers can be used
+ * independently.
+ *
+ */
+struct backlight_device *pmac_backlight;
+
+int pmac_has_backlight_type(const char *type)
+{
+ struct device_node* bk_node = of_find_node_by_name(NULL, "backlight");
- 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;
+ const char *prop = of_get_property(bk_node,
+ "backlight-control", NULL);
+ if (prop && strncmp(prop, type, strlen(type)) == 0) {
+ of_node_put(bk_node);
+ return 1;
+ }
+ of_node_put(bk_node);
}
- 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;
+
+ return 0;
+}
+
+int pmac_backlight_curve_lookup(struct fb_info *info, int value)
+{
+ int level = (FB_BACKLIGHT_LEVELS - 1);
+
+ if (info && info->bl_dev) {
+ int i, max = 0;
+
+ /* Look for biggest value */
+ for (i = 0; i < FB_BACKLIGHT_LEVELS; i++)
+ max = max((int)info->bl_curve[i], max);
+
+ /* Look for nearest value */
+ for (i = 0; i < FB_BACKLIGHT_LEVELS; i++) {
+ int diff = abs(info->bl_curve[i] - value);
+ if (diff < max) {
+ max = diff;
+ level = i;
+ }
+ }
+
}
-#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;
+ return level;
+}
+
+static void pmac_backlight_key_worker(struct work_struct *work)
+{
+ if (atomic_read(&kernel_backlight_disabled))
+ return;
+
+ mutex_lock(&pmac_backlight_mutex);
+ if (pmac_backlight) {
+ struct backlight_properties *props;
+ int brightness;
+
+ props = &pmac_backlight->props;
+
+ brightness = props->brightness +
+ ((pmac_backlight_key_queued?-1:1) *
+ (props->max_brightness / 15));
+
+ if (brightness < 0)
+ brightness = 0;
+ else if (brightness > props->max_brightness)
+ brightness = props->max_brightness;
+
+ props->brightness = brightness;
+ backlight_update_status(pmac_backlight);
}
-#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);
+ mutex_unlock(&pmac_backlight_mutex);
}
-EXPORT_SYMBOL(register_backlight_controller);
-void unregister_backlight_controller(struct backlight_controller
- *ctrler, void *data)
+/* This function is called in interrupt context */
+void pmac_backlight_key(int direction)
{
- /* We keep the current backlight level (for now) */
- if (ctrler == backlighter && data == backlighter_data)
- backlighter = NULL;
+ if (atomic_read(&kernel_backlight_disabled))
+ return;
+
+ /* we can receive multiple interrupts here, but the scheduled work
+ * will run only once, with the last value
+ */
+ pmac_backlight_key_queued = direction;
+ schedule_work(&pmac_backlight_key_work);
}
-EXPORT_SYMBOL(unregister_backlight_controller);
-static int __set_backlight_enable(int enable)
+static int __pmac_backlight_set_legacy_brightness(int brightness)
{
- 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 error = -ENXIO;
+
+ mutex_lock(&pmac_backlight_mutex);
+ if (pmac_backlight) {
+ struct backlight_properties *props;
+
+ props = &pmac_backlight->props;
+ props->brightness = brightness *
+ (props->max_brightness + 1) /
+ (OLD_BACKLIGHT_MAX + 1);
+
+ if (props->brightness > props->max_brightness)
+ props->brightness = props->max_brightness;
+ else if (props->brightness < 0)
+ props->brightness = 0;
+
+ backlight_update_status(pmac_backlight);
+
+ error = 0;
+ }
+ mutex_unlock(&pmac_backlight_mutex);
+
+ return error;
}
-int set_backlight_enable(int enable)
+
+static void pmac_backlight_set_legacy_worker(struct work_struct *work)
{
- if (!backlighter)
- return -ENODEV;
- backlight_req_enable = enable;
- schedule_work(&backlight_work);
- return 0;
+ if (atomic_read(&kernel_backlight_disabled))
+ return;
+
+ __pmac_backlight_set_legacy_brightness(pmac_backlight_set_legacy_queued);
}
-EXPORT_SYMBOL(set_backlight_enable);
+/* This function is called in interrupt context */
+void pmac_backlight_set_legacy_brightness_pmu(int brightness) {
+ if (atomic_read(&kernel_backlight_disabled))
+ return;
-int get_backlight_enable(void)
-{
- if (!backlighter)
- return -ENODEV;
- return backlight_enabled;
+ pmac_backlight_set_legacy_queued = brightness;
+ schedule_work(&pmac_backlight_set_legacy_work);
}
-EXPORT_SYMBOL(get_backlight_enable);
-static int __set_backlight_level(int level)
+int pmac_backlight_set_legacy_brightness(int brightness)
{
- 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;
+ return __pmac_backlight_set_legacy_brightness(brightness);
}
-int set_backlight_level(int level)
+
+int pmac_backlight_get_legacy_brightness()
{
- if (!backlighter)
- return -ENODEV;
- backlight_req_level = level;
- schedule_work(&backlight_work);
- return 0;
-}
+ int result = -ENXIO;
+
+ mutex_lock(&pmac_backlight_mutex);
+ if (pmac_backlight) {
+ struct backlight_properties *props;
-EXPORT_SYMBOL(set_backlight_level);
+ props = &pmac_backlight->props;
+
+ result = props->brightness *
+ (OLD_BACKLIGHT_MAX + 1) /
+ (props->max_brightness + 1);
+ }
+ mutex_unlock(&pmac_backlight_mutex);
-int get_backlight_level(void)
+ return result;
+}
+
+void pmac_backlight_disable()
{
- if (!backlighter)
- return -ENODEV;
- return backlight_level;
+ atomic_inc(&kernel_backlight_disabled);
}
-EXPORT_SYMBOL(get_backlight_level);
-static void backlight_callback(void *dummy)
+void pmac_backlight_enable()
{
- 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);
+ atomic_dec(&kernel_backlight_disabled);
}
+
+EXPORT_SYMBOL_GPL(pmac_backlight);
+EXPORT_SYMBOL_GPL(pmac_backlight_mutex);
+EXPORT_SYMBOL_GPL(pmac_has_backlight_type);
diff --git a/arch/powerpc/platforms/powermac/bootx_init.c b/arch/powerpc/platforms/powermac/bootx_init.c
index fa8b4d7b5de..3e91ef53811 100644
--- a/arch/powerpc/platforms/powermac/bootx_init.c
+++ b/arch/powerpc/platforms/powermac/bootx_init.c
@@ -9,18 +9,17 @@
* 2 of the License, or (at your option) any later version.
*/
-#include <linux/config.h>
#include <linux/kernel.h>
#include <linux/string.h>
#include <linux/init.h>
-#include <linux/version.h>
+#include <generated/utsrelease.h>
#include <asm/sections.h>
#include <asm/prom.h>
#include <asm/page.h>
#include <asm/bootx.h>
-#include <asm/bootinfo.h>
#include <asm/btext.h>
#include <asm/io.h>
+#include <asm/setup.h>
#undef DEBUG
#define SET_BOOT_BAT
@@ -161,9 +160,9 @@ static void __init bootx_dt_add_prop(char *name, void *data, int size,
static void __init bootx_add_chosen_props(unsigned long base,
unsigned long *mem_end)
{
- u32 val = _MACH_Pmac;
+ u32 val;
- bootx_dt_add_prop("linux,platform", &val, 4, mem_end);
+ bootx_dt_add_prop("linux,bootx", NULL, 0, mem_end);
if (bootx_info->kernelParamsOffset) {
char *args = (char *)((unsigned long)bootx_info) +
@@ -182,10 +181,32 @@ static void __init bootx_add_chosen_props(unsigned long base,
}
static void __init bootx_add_display_props(unsigned long base,
- unsigned long *mem_end)
+ unsigned long *mem_end,
+ int has_real_node)
{
- bootx_dt_add_prop("linux,boot-display", NULL, 0, mem_end);
- bootx_dt_add_prop("linux,opened", NULL, 0, mem_end);
+ boot_infos_t *bi = bootx_info;
+ u32 tmp;
+
+ if (has_real_node) {
+ bootx_dt_add_prop("linux,boot-display", NULL, 0, mem_end);
+ bootx_dt_add_prop("linux,opened", NULL, 0, mem_end);
+ } else
+ bootx_dt_add_prop("linux,bootx-noscreen", NULL, 0, mem_end);
+
+ tmp = bi->dispDeviceDepth;
+ bootx_dt_add_prop("linux,bootx-depth", &tmp, 4, mem_end);
+ tmp = bi->dispDeviceRect[2] - bi->dispDeviceRect[0];
+ bootx_dt_add_prop("linux,bootx-width", &tmp, 4, mem_end);
+ tmp = bi->dispDeviceRect[3] - bi->dispDeviceRect[1];
+ bootx_dt_add_prop("linux,bootx-height", &tmp, 4, mem_end);
+ tmp = bi->dispDeviceRowBytes;
+ bootx_dt_add_prop("linux,bootx-linebytes", &tmp, 4, mem_end);
+ tmp = (u32)bi->dispDeviceBase;
+ if (tmp == 0)
+ tmp = (u32)bi->logicalDisplayBase;
+ tmp += bi->dispDeviceRect[1] * bi->dispDeviceRowBytes;
+ tmp += bi->dispDeviceRect[0] * ((bi->dispDeviceDepth + 7) / 8);
+ bootx_dt_add_prop("linux,bootx-addr", &tmp, 4, mem_end);
}
static void __init bootx_dt_add_string(char *s, unsigned long *mem_end)
@@ -214,7 +235,7 @@ static void __init bootx_scan_dt_build_strings(unsigned long base,
if (!strcmp(namep, "/chosen")) {
DBG(" detected /chosen ! adding properties names !\n");
- bootx_dt_add_string("linux,platform", mem_end);
+ bootx_dt_add_string("linux,bootx", mem_end);
bootx_dt_add_string("linux,stdout-path", mem_end);
bootx_dt_add_string("linux,initrd-start", mem_end);
bootx_dt_add_string("linux,initrd-end", mem_end);
@@ -308,10 +329,13 @@ static void __init bootx_scan_dt_build_struct(unsigned long base,
ppp = &pp->next;
}
- if (node == bootx_node_chosen)
+ if (node == bootx_node_chosen) {
bootx_add_chosen_props(base, mem_end);
- if (node == bootx_info->dispDeviceRegEntryOffset)
- bootx_add_display_props(base, mem_end);
+ if (bootx_info->dispDeviceRegEntryOffset == 0)
+ bootx_add_display_props(base, mem_end, 0);
+ }
+ else if (node == bootx_info->dispDeviceRegEntryOffset)
+ bootx_add_display_props(base, mem_end, 1);
/* do all our children */
cpp = &np->child;
@@ -353,6 +377,14 @@ static unsigned long __init bootx_flatten_dt(unsigned long start)
mem_end += 4;
bootx_dt_strend = mem_end;
bootx_scan_dt_build_strings(base, 4, &mem_end);
+ /* Add some strings */
+ bootx_dt_add_string("linux,bootx-noscreen", &mem_end);
+ bootx_dt_add_string("linux,bootx-depth", &mem_end);
+ bootx_dt_add_string("linux,bootx-width", &mem_end);
+ bootx_dt_add_string("linux,bootx-height", &mem_end);
+ bootx_dt_add_string("linux,bootx-linebytes", &mem_end);
+ bootx_dt_add_string("linux,bootx-addr", &mem_end);
+ /* Wrap up strings */
hdr->off_dt_strings = bootx_dt_strbase - mem_start;
hdr->dt_strings_size = bootx_dt_strend - bootx_dt_strbase;
@@ -379,8 +411,15 @@ static unsigned long __init bootx_flatten_dt(unsigned long start)
DBG("End of boot params: %x\n", mem_end);
rsvmap[0] = mem_start;
rsvmap[1] = mem_end;
- rsvmap[2] = 0;
- rsvmap[3] = 0;
+ if (bootx_info->ramDisk) {
+ rsvmap[2] = ((unsigned long)bootx_info) + bootx_info->ramDisk;
+ rsvmap[3] = rsvmap[2] + bootx_info->ramDiskSize;
+ rsvmap[4] = 0;
+ rsvmap[5] = 0;
+ } else {
+ rsvmap[2] = 0;
+ rsvmap[3] = 0;
+ }
return (unsigned long)hdr;
}
@@ -446,7 +485,15 @@ void __init bootx_init(unsigned long r3, unsigned long r4)
if (!BOOT_INFO_IS_V2_COMPATIBLE(bi))
bi->logicalDisplayBase = bi->dispDeviceBase;
+ /* Fixup depth 16 -> 15 as that's what MacOS calls 16bpp */
+ if (bi->dispDeviceDepth == 16)
+ bi->dispDeviceDepth = 15;
+
+
#ifdef CONFIG_BOOTX_TEXT
+ ptr = (unsigned long)bi->logicalDisplayBase;
+ ptr += bi->dispDeviceRect[1] * bi->dispDeviceRowBytes;
+ ptr += bi->dispDeviceRect[0] * ((bi->dispDeviceDepth + 7) / 8);
btext_setup_display(bi->dispDeviceRect[2] - bi->dispDeviceRect[0],
bi->dispDeviceRect[3] - bi->dispDeviceRect[1],
bi->dispDeviceDepth, bi->dispDeviceRowBytes,
@@ -480,6 +527,7 @@ void __init bootx_init(unsigned long r3, unsigned long r4)
#ifdef CONFIG_BOOTX_TEXT
btext_welcome(bi);
#endif
+
/* New BootX enters kernel with MMU off, i/os are not allowed
* here. This hack will have been done by the boostrap anyway.
*/
@@ -492,8 +540,8 @@ void __init bootx_init(unsigned long r3, unsigned long r4)
if (model
&& (strcmp(model, "iMac,1") == 0
|| strcmp(model, "PowerMac1,1") == 0)) {
- bootx_printf("iMac,1 detected, shutting down USB \n");
- out_le32((unsigned *)0x80880008, 1); /* XXX */
+ bootx_printf("iMac,1 detected, shutting down USB\n");
+ out_le32((unsigned __iomem *)0x80880008, 1); /* XXX */
}
}
@@ -502,12 +550,12 @@ void __init bootx_init(unsigned long r3, unsigned long r4)
*/
if (bi->version < 5) {
space = bi->deviceTreeOffset + bi->deviceTreeSize;
- if (bi->ramDisk)
+ if (bi->ramDisk >= space)
space = bi->ramDisk + bi->ramDiskSize;
} else
space = bi->totalParamsSize;
- bootx_printf("Total space used by parameters & ramdisk: %x \n", space);
+ bootx_printf("Total space used by parameters & ramdisk: 0x%x\n", space);
/* New BootX will have flushed all TLBs and enters kernel with
* MMU switched OFF, so this should not be useful anymore.
diff --git a/arch/powerpc/platforms/powermac/cache.S b/arch/powerpc/platforms/powermac/cache.S
index fb977de6b70..6be1a4af335 100644
--- a/arch/powerpc/platforms/powermac/cache.S
+++ b/arch/powerpc/platforms/powermac/cache.S
@@ -14,7 +14,6 @@
*
*/
-#include <linux/config.h>
#include <asm/processor.h>
#include <asm/ppc_asm.h>
#include <asm/cputable.h>
diff --git a/arch/powerpc/platforms/powermac/cpufreq_32.c b/arch/powerpc/platforms/powermac/cpufreq_32.c
deleted file mode 100644
index 56fd4e05fed..00000000000
--- a/arch/powerpc/platforms/powermac/cpufreq_32.c
+++ /dev/null
@@ -1,727 +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);
-}
-
-#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;
- int rc;
-
- if (cpufreq_frequency_table_target(policy, pmac_cpu_freqs,
- target_freq, relation, &newstate))
- return -EINVAL;
-
- rc = do_set_cpu_speed(newstate, 1);
-
- ppc_proc_freq = cur_freq * 1000ul;
- return rc;
-}
-
-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);
-
- ppc_proc_freq = cur_freq * 1000ul;
-
- 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 550 */
- else if (machine_is_compatible("PowerBook3,3") && cur_freq == 550000) {
- hi_freq = cur_freq;
- low_freq = 500000;
- 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;
- ppc_proc_freq = cur_freq * 1000ul;
-
- 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/cpufreq_64.c b/arch/powerpc/platforms/powermac/cpufreq_64.c
deleted file mode 100644
index a415e8d2f7a..00000000000
--- a/arch/powerpc/platforms/powermac/cpufreq_64.c
+++ /dev/null
@@ -1,725 +0,0 @@
-/*
- * Copyright (C) 2002 - 2005 Benjamin Herrenschmidt <benh@kernel.crashing.org>
- * and Markus Demleitner <msdemlei@cl.uni-heidelberg.de>
- *
- * 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.
- *
- * This driver adds basic cpufreq support for SMU & 970FX based G5 Macs,
- * that is iMac G5 and latest single CPU desktop.
- */
-
-#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/slab.h>
-#include <linux/cpufreq.h>
-#include <linux/init.h>
-#include <linux/completion.h>
-#include <asm/prom.h>
-#include <asm/machdep.h>
-#include <asm/irq.h>
-#include <asm/sections.h>
-#include <asm/cputable.h>
-#include <asm/time.h>
-#include <asm/smu.h>
-#include <asm/pmac_pfunc.h>
-
-#undef DEBUG
-
-#ifdef DEBUG
-#define DBG(fmt...) printk(fmt)
-#else
-#define DBG(fmt...)
-#endif
-
-/* see 970FX user manual */
-
-#define SCOM_PCR 0x0aa001 /* PCR scom addr */
-
-#define PCR_HILO_SELECT 0x80000000U /* 1 = PCR, 0 = PCRH */
-#define PCR_SPEED_FULL 0x00000000U /* 1:1 speed value */
-#define PCR_SPEED_HALF 0x00020000U /* 1:2 speed value */
-#define PCR_SPEED_QUARTER 0x00040000U /* 1:4 speed value */
-#define PCR_SPEED_MASK 0x000e0000U /* speed mask */
-#define PCR_SPEED_SHIFT 17
-#define PCR_FREQ_REQ_VALID 0x00010000U /* freq request valid */
-#define PCR_VOLT_REQ_VALID 0x00008000U /* volt request valid */
-#define PCR_TARGET_TIME_MASK 0x00006000U /* target time */
-#define PCR_STATLAT_MASK 0x00001f00U /* STATLAT value */
-#define PCR_SNOOPLAT_MASK 0x000000f0U /* SNOOPLAT value */
-#define PCR_SNOOPACC_MASK 0x0000000fU /* SNOOPACC value */
-
-#define SCOM_PSR 0x408001 /* PSR scom addr */
-/* warning: PSR is a 64 bits register */
-#define PSR_CMD_RECEIVED 0x2000000000000000U /* command received */
-#define PSR_CMD_COMPLETED 0x1000000000000000U /* command completed */
-#define PSR_CUR_SPEED_MASK 0x0300000000000000U /* current speed */
-#define PSR_CUR_SPEED_SHIFT (56)
-
-/*
- * The G5 only supports two frequencies (Quarter speed is not supported)
- */
-#define CPUFREQ_HIGH 0
-#define CPUFREQ_LOW 1
-
-static struct cpufreq_frequency_table g5_cpu_freqs[] = {
- {CPUFREQ_HIGH, 0},
- {CPUFREQ_LOW, 0},
- {0, CPUFREQ_TABLE_END},
-};
-
-static struct freq_attr* g5_cpu_freqs_attr[] = {
- &cpufreq_freq_attr_scaling_available_freqs,
- NULL,
-};
-
-/* Power mode data is an array of the 32 bits PCR values to use for
- * the various frequencies, retrieved from the device-tree
- */
-static u32 *g5_pmode_data;
-static int g5_pmode_max;
-static int g5_pmode_cur;
-
-static void (*g5_switch_volt)(int speed_mode);
-static int (*g5_switch_freq)(int speed_mode);
-static int (*g5_query_freq)(void);
-
-static DECLARE_MUTEX(g5_switch_mutex);
-
-
-static struct smu_sdbp_fvt *g5_fvt_table; /* table of op. points */
-static int g5_fvt_count; /* number of op. points */
-static int g5_fvt_cur; /* current op. point */
-
-/*
- * SMU based voltage switching for Neo2 platforms
- */
-
-static void g5_smu_switch_volt(int speed_mode)
-{
- struct smu_simple_cmd cmd;
-
- DECLARE_COMPLETION(comp);
- smu_queue_simple(&cmd, SMU_CMD_POWER_COMMAND, 8, smu_done_complete,
- &comp, 'V', 'S', 'L', 'E', 'W',
- 0xff, g5_fvt_cur+1, speed_mode);
- wait_for_completion(&comp);
-}
-
-/*
- * Platform function based voltage/vdnap switching for Neo2
- */
-
-static struct pmf_function *pfunc_set_vdnap0;
-static struct pmf_function *pfunc_vdnap0_complete;
-
-static void g5_vdnap_switch_volt(int speed_mode)
-{
- struct pmf_args args;
- u32 slew, done = 0;
- unsigned long timeout;
-
- slew = (speed_mode == CPUFREQ_LOW) ? 1 : 0;
- args.count = 1;
- args.u[0].p = &slew;
-
- pmf_call_one(pfunc_set_vdnap0, &args);
-
- /* It's an irq GPIO so we should be able to just block here,
- * I'll do that later after I've properly tested the IRQ code for
- * platform functions
- */
- timeout = jiffies + HZ/10;
- while(!time_after(jiffies, timeout)) {
- args.count = 1;
- args.u[0].p = &done;
- pmf_call_one(pfunc_vdnap0_complete, &args);
- if (done)
- break;
- msleep(1);
- }
- if (done == 0)
- printk(KERN_WARNING "cpufreq: Timeout in clock slewing !\n");
-}
-
-
-/*
- * SCOM based frequency switching for 970FX rev3
- */
-static int g5_scom_switch_freq(int speed_mode)
-{
- unsigned long flags;
- int to;
-
- /* If frequency is going up, first ramp up the voltage */
- if (speed_mode < g5_pmode_cur)
- g5_switch_volt(speed_mode);
-
- local_irq_save(flags);
-
- /* Clear PCR high */
- scom970_write(SCOM_PCR, 0);
- /* Clear PCR low */
- scom970_write(SCOM_PCR, PCR_HILO_SELECT | 0);
- /* Set PCR low */
- scom970_write(SCOM_PCR, PCR_HILO_SELECT |
- g5_pmode_data[speed_mode]);
-
- /* Wait for completion */
- for (to = 0; to < 10; to++) {
- unsigned long psr = scom970_read(SCOM_PSR);
-
- if ((psr & PSR_CMD_RECEIVED) == 0 &&
- (((psr >> PSR_CUR_SPEED_SHIFT) ^
- (g5_pmode_data[speed_mode] >> PCR_SPEED_SHIFT)) & 0x3)
- == 0)
- break;
- if (psr & PSR_CMD_COMPLETED)
- break;
- udelay(100);
- }
-
- local_irq_restore(flags);
-
- /* If frequency is going down, last ramp the voltage */
- if (speed_mode > g5_pmode_cur)
- g5_switch_volt(speed_mode);
-
- g5_pmode_cur = speed_mode;
- ppc_proc_freq = g5_cpu_freqs[speed_mode].frequency * 1000ul;
-
- return 0;
-}
-
-static int g5_scom_query_freq(void)
-{
- unsigned long psr = scom970_read(SCOM_PSR);
- int i;
-
- for (i = 0; i <= g5_pmode_max; i++)
- if ((((psr >> PSR_CUR_SPEED_SHIFT) ^
- (g5_pmode_data[i] >> PCR_SPEED_SHIFT)) & 0x3) == 0)
- break;
- return i;
-}
-
-/*
- * Platform function based voltage switching for PowerMac7,2 & 7,3
- */
-
-static struct pmf_function *pfunc_cpu0_volt_high;
-static struct pmf_function *pfunc_cpu0_volt_low;
-static struct pmf_function *pfunc_cpu1_volt_high;
-static struct pmf_function *pfunc_cpu1_volt_low;
-
-static void g5_pfunc_switch_volt(int speed_mode)
-{
- if (speed_mode == CPUFREQ_HIGH) {
- if (pfunc_cpu0_volt_high)
- pmf_call_one(pfunc_cpu0_volt_high, NULL);
- if (pfunc_cpu1_volt_high)
- pmf_call_one(pfunc_cpu1_volt_high, NULL);
- } else {
- if (pfunc_cpu0_volt_low)
- pmf_call_one(pfunc_cpu0_volt_low, NULL);
- if (pfunc_cpu1_volt_low)
- pmf_call_one(pfunc_cpu1_volt_low, NULL);
- }
- msleep(10); /* should be faster , to fix */
-}
-
-/*
- * Platform function based frequency switching for PowerMac7,2 & 7,3
- */
-
-static struct pmf_function *pfunc_cpu_setfreq_high;
-static struct pmf_function *pfunc_cpu_setfreq_low;
-static struct pmf_function *pfunc_cpu_getfreq;
-static struct pmf_function *pfunc_slewing_done;;
-
-static int g5_pfunc_switch_freq(int speed_mode)
-{
- struct pmf_args args;
- u32 done = 0;
- unsigned long timeout;
-
- /* If frequency is going up, first ramp up the voltage */
- if (speed_mode < g5_pmode_cur)
- g5_switch_volt(speed_mode);
-
- /* Do it */
- if (speed_mode == CPUFREQ_HIGH)
- pmf_call_one(pfunc_cpu_setfreq_high, NULL);
- else
- pmf_call_one(pfunc_cpu_setfreq_low, NULL);
-
- /* It's an irq GPIO so we should be able to just block here,
- * I'll do that later after I've properly tested the IRQ code for
- * platform functions
- */
- timeout = jiffies + HZ/10;
- while(!time_after(jiffies, timeout)) {
- args.count = 1;
- args.u[0].p = &done;
- pmf_call_one(pfunc_slewing_done, &args);
- if (done)
- break;
- msleep(1);
- }
- if (done == 0)
- printk(KERN_WARNING "cpufreq: Timeout in clock slewing !\n");
-
- /* If frequency is going down, last ramp the voltage */
- if (speed_mode > g5_pmode_cur)
- g5_switch_volt(speed_mode);
-
- g5_pmode_cur = speed_mode;
- ppc_proc_freq = g5_cpu_freqs[speed_mode].frequency * 1000ul;
-
- return 0;
-}
-
-static int g5_pfunc_query_freq(void)
-{
- struct pmf_args args;
- u32 val = 0;
-
- args.count = 1;
- args.u[0].p = &val;
- pmf_call_one(pfunc_cpu_getfreq, &args);
- return val ? CPUFREQ_HIGH : CPUFREQ_LOW;
-}
-
-/*
- * Fake voltage switching for platforms with missing support
- */
-
-static void g5_dummy_switch_volt(int speed_mode)
-{
-}
-
-/*
- * Common interface to the cpufreq core
- */
-
-static int g5_cpufreq_verify(struct cpufreq_policy *policy)
-{
- return cpufreq_frequency_table_verify(policy, g5_cpu_freqs);
-}
-
-static int g5_cpufreq_target(struct cpufreq_policy *policy,
- unsigned int target_freq, unsigned int relation)
-{
- unsigned int newstate = 0;
- struct cpufreq_freqs freqs;
- int rc;
-
- if (cpufreq_frequency_table_target(policy, g5_cpu_freqs,
- target_freq, relation, &newstate))
- return -EINVAL;
-
- if (g5_pmode_cur == newstate)
- return 0;
-
- down(&g5_switch_mutex);
-
- freqs.old = g5_cpu_freqs[g5_pmode_cur].frequency;
- freqs.new = g5_cpu_freqs[newstate].frequency;
- freqs.cpu = 0;
-
- cpufreq_notify_transition(&freqs, CPUFREQ_PRECHANGE);
- rc = g5_switch_freq(newstate);
- cpufreq_notify_transition(&freqs, CPUFREQ_POSTCHANGE);
-
- up(&g5_switch_mutex);
-
- return rc;
-}
-
-static unsigned int g5_cpufreq_get_speed(unsigned int cpu)
-{
- return g5_cpu_freqs[g5_pmode_cur].frequency;
-}
-
-static int g5_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 = g5_cpu_freqs[g5_query_freq()].frequency;
- policy->cpus = cpu_possible_map;
- cpufreq_frequency_table_get_attr(g5_cpu_freqs, policy->cpu);
-
- return cpufreq_frequency_table_cpuinfo(policy,
- g5_cpu_freqs);
-}
-
-
-static struct cpufreq_driver g5_cpufreq_driver = {
- .name = "powermac",
- .owner = THIS_MODULE,
- .flags = CPUFREQ_CONST_LOOPS,
- .init = g5_cpufreq_cpu_init,
- .verify = g5_cpufreq_verify,
- .target = g5_cpufreq_target,
- .get = g5_cpufreq_get_speed,
- .attr = g5_cpu_freqs_attr,
-};
-
-
-static int __init g5_neo2_cpufreq_init(struct device_node *cpus)
-{
- struct device_node *cpunode;
- unsigned int psize, ssize;
- unsigned long max_freq;
- char *freq_method, *volt_method;
- u32 *valp, pvr_hi;
- int use_volts_vdnap = 0;
- int use_volts_smu = 0;
- int rc = -ENODEV;
-
- /* Check supported platforms */
- if (machine_is_compatible("PowerMac8,1") ||
- machine_is_compatible("PowerMac8,2") ||
- machine_is_compatible("PowerMac9,1"))
- use_volts_smu = 1;
- else if (machine_is_compatible("PowerMac11,2"))
- use_volts_vdnap = 1;
- else
- return -ENODEV;
-
- /* Get first CPU node */
- for (cpunode = NULL;
- (cpunode = of_get_next_child(cpus, cpunode)) != NULL;) {
- u32 *reg =
- (u32 *)get_property(cpunode, "reg", NULL);
- if (reg == NULL || (*reg) != 0)
- continue;
- if (!strcmp(cpunode->type, "cpu"))
- break;
- }
- if (cpunode == NULL) {
- printk(KERN_ERR "cpufreq: Can't find any CPU 0 node\n");
- return -ENODEV;
- }
-
- /* Check 970FX for now */
- valp = (u32 *)get_property(cpunode, "cpu-version", NULL);
- if (!valp) {
- DBG("No cpu-version property !\n");
- goto bail_noprops;
- }
- pvr_hi = (*valp) >> 16;
- if (pvr_hi != 0x3c && pvr_hi != 0x44) {
- printk(KERN_ERR "cpufreq: Unsupported CPU version\n");
- goto bail_noprops;
- }
-
- /* Look for the powertune data in the device-tree */
- g5_pmode_data = (u32 *)get_property(cpunode, "power-mode-data",&psize);
- if (!g5_pmode_data) {
- DBG("No power-mode-data !\n");
- goto bail_noprops;
- }
- g5_pmode_max = psize / sizeof(u32) - 1;
-
- if (use_volts_smu) {
- struct smu_sdbp_header *shdr;
-
- /* Look for the FVT table */
- shdr = smu_get_sdb_partition(SMU_SDB_FVT_ID, NULL);
- if (!shdr)
- goto bail_noprops;
- g5_fvt_table = (struct smu_sdbp_fvt *)&shdr[1];
- ssize = (shdr->len * sizeof(u32)) -
- sizeof(struct smu_sdbp_header);
- g5_fvt_count = ssize / sizeof(struct smu_sdbp_fvt);
- g5_fvt_cur = 0;
-
- /* Sanity checking */
- if (g5_fvt_count < 1 || g5_pmode_max < 1)
- goto bail_noprops;
-
- g5_switch_volt = g5_smu_switch_volt;
- volt_method = "SMU";
- } else if (use_volts_vdnap) {
- struct device_node *root;
-
- root = of_find_node_by_path("/");
- if (root == NULL) {
- printk(KERN_ERR "cpufreq: Can't find root of "
- "device tree\n");
- goto bail_noprops;
- }
- pfunc_set_vdnap0 = pmf_find_function(root, "set-vdnap0");
- pfunc_vdnap0_complete =
- pmf_find_function(root, "slewing-done");
- if (pfunc_set_vdnap0 == NULL ||
- pfunc_vdnap0_complete == NULL) {
- printk(KERN_ERR "cpufreq: Can't find required "
- "platform function\n");
- goto bail_noprops;
- }
-
- g5_switch_volt = g5_vdnap_switch_volt;
- volt_method = "GPIO";
- } else {
- g5_switch_volt = g5_dummy_switch_volt;
- volt_method = "none";
- }
-
- /*
- * From what I see, clock-frequency is always the maximal frequency.
- * The current driver can not slew sysclk yet, so we really only deal
- * with powertune steps for now. We also only implement full freq and
- * half freq in this version. So far, I haven't yet seen a machine
- * supporting anything else.
- */
- valp = (u32 *)get_property(cpunode, "clock-frequency", NULL);
- if (!valp)
- return -ENODEV;
- max_freq = (*valp)/1000;
- g5_cpu_freqs[0].frequency = max_freq;
- g5_cpu_freqs[1].frequency = max_freq/2;
-
- /* Set callbacks */
- g5_switch_freq = g5_scom_switch_freq;
- g5_query_freq = g5_scom_query_freq;
- freq_method = "SCOM";
-
- /* Force apply current frequency to make sure everything is in
- * sync (voltage is right for example). Firmware may leave us with
- * a strange setting ...
- */
- g5_switch_volt(CPUFREQ_HIGH);
- msleep(10);
- g5_pmode_cur = -1;
- g5_switch_freq(g5_query_freq());
-
- printk(KERN_INFO "Registering G5 CPU frequency driver\n");
- printk(KERN_INFO "Frequency method: %s, Voltage method: %s\n",
- freq_method, volt_method);
- printk(KERN_INFO "Low: %d Mhz, High: %d Mhz, Cur: %d MHz\n",
- g5_cpu_freqs[1].frequency/1000,
- g5_cpu_freqs[0].frequency/1000,
- g5_cpu_freqs[g5_pmode_cur].frequency/1000);
-
- rc = cpufreq_register_driver(&g5_cpufreq_driver);
-
- /* We keep the CPU node on hold... hopefully, Apple G5 don't have
- * hotplug CPU with a dynamic device-tree ...
- */
- return rc;
-
- bail_noprops:
- of_node_put(cpunode);
-
- return rc;
-}
-
-static int __init g5_pm72_cpufreq_init(struct device_node *cpus)
-{
- struct device_node *cpuid = NULL, *hwclock = NULL, *cpunode = NULL;
- u8 *eeprom = NULL;
- u32 *valp;
- u64 max_freq, min_freq, ih, il;
- int has_volt = 1, rc = 0;
-
- /* Get first CPU node */
- for (cpunode = NULL;
- (cpunode = of_get_next_child(cpus, cpunode)) != NULL;) {
- if (!strcmp(cpunode->type, "cpu"))
- break;
- }
- if (cpunode == NULL) {
- printk(KERN_ERR "cpufreq: Can't find any CPU node\n");
- return -ENODEV;
- }
-
- /* Lookup the cpuid eeprom node */
- cpuid = of_find_node_by_path("/u3@0,f8000000/i2c@f8001000/cpuid@a0");
- if (cpuid != NULL)
- eeprom = (u8 *)get_property(cpuid, "cpuid", NULL);
- if (eeprom == NULL) {
- printk(KERN_ERR "cpufreq: Can't find cpuid EEPROM !\n");
- rc = -ENODEV;
- goto bail;
- }
-
- /* Lookup the i2c hwclock */
- for (hwclock = NULL;
- (hwclock = of_find_node_by_name(hwclock, "i2c-hwclock")) != NULL;){
- char *loc = get_property(hwclock, "hwctrl-location", NULL);
- if (loc == NULL)
- continue;
- if (strcmp(loc, "CPU CLOCK"))
- continue;
- if (!get_property(hwclock, "platform-get-frequency", NULL))
- continue;
- break;
- }
- if (hwclock == NULL) {
- printk(KERN_ERR "cpufreq: Can't find i2c clock chip !\n");
- rc = -ENODEV;
- goto bail;
- }
-
- DBG("cpufreq: i2c clock chip found: %s\n", hwclock->full_name);
-
- /* Now get all the platform functions */
- pfunc_cpu_getfreq =
- pmf_find_function(hwclock, "get-frequency");
- pfunc_cpu_setfreq_high =
- pmf_find_function(hwclock, "set-frequency-high");
- pfunc_cpu_setfreq_low =
- pmf_find_function(hwclock, "set-frequency-low");
- pfunc_slewing_done =
- pmf_find_function(hwclock, "slewing-done");
- pfunc_cpu0_volt_high =
- pmf_find_function(hwclock, "set-voltage-high-0");
- pfunc_cpu0_volt_low =
- pmf_find_function(hwclock, "set-voltage-low-0");
- pfunc_cpu1_volt_high =
- pmf_find_function(hwclock, "set-voltage-high-1");
- pfunc_cpu1_volt_low =
- pmf_find_function(hwclock, "set-voltage-low-1");
-
- /* Check we have minimum requirements */
- if (pfunc_cpu_getfreq == NULL || pfunc_cpu_setfreq_high == NULL ||
- pfunc_cpu_setfreq_low == NULL || pfunc_slewing_done == NULL) {
- printk(KERN_ERR "cpufreq: Can't find platform functions !\n");
- rc = -ENODEV;
- goto bail;
- }
-
- /* Check that we have complete sets */
- if (pfunc_cpu0_volt_high == NULL || pfunc_cpu0_volt_low == NULL) {
- pmf_put_function(pfunc_cpu0_volt_high);
- pmf_put_function(pfunc_cpu0_volt_low);
- pfunc_cpu0_volt_high = pfunc_cpu0_volt_low = NULL;
- has_volt = 0;
- }
- if (!has_volt ||
- pfunc_cpu1_volt_high == NULL || pfunc_cpu1_volt_low == NULL) {
- pmf_put_function(pfunc_cpu1_volt_high);
- pmf_put_function(pfunc_cpu1_volt_low);
- pfunc_cpu1_volt_high = pfunc_cpu1_volt_low = NULL;
- }
-
- /* Note: The device tree also contains a "platform-set-values"
- * function for which I haven't quite figured out the usage. It
- * might have to be called on init and/or wakeup, I'm not too sure
- * but things seem to work fine without it so far ...
- */
-
- /* Get max frequency from device-tree */
- valp = (u32 *)get_property(cpunode, "clock-frequency", NULL);
- if (!valp) {
- printk(KERN_ERR "cpufreq: Can't find CPU frequency !\n");
- rc = -ENODEV;
- goto bail;
- }
-
- max_freq = (*valp)/1000;
-
- /* Now calculate reduced frequency by using the cpuid input freq
- * ratio. This requires 64 bits math unless we are willing to lose
- * some precision
- */
- ih = *((u32 *)(eeprom + 0x10));
- il = *((u32 *)(eeprom + 0x20));
- min_freq = 0;
- if (ih != 0 && il != 0)
- min_freq = (max_freq * il) / ih;
-
- /* Sanity check */
- if (min_freq >= max_freq || min_freq < 1000) {
- printk(KERN_ERR "cpufreq: Can't calculate low frequency !\n");
- rc = -ENODEV;
- goto bail;
- }
- g5_cpu_freqs[0].frequency = max_freq;
- g5_cpu_freqs[1].frequency = min_freq;
-
- /* Set callbacks */
- g5_switch_volt = g5_pfunc_switch_volt;
- g5_switch_freq = g5_pfunc_switch_freq;
- g5_query_freq = g5_pfunc_query_freq;
-
- /* Force apply current frequency to make sure everything is in
- * sync (voltage is right for example). Firmware may leave us with
- * a strange setting ...
- */
- g5_switch_volt(CPUFREQ_HIGH);
- msleep(10);
- g5_pmode_cur = -1;
- g5_switch_freq(g5_query_freq());
-
- printk(KERN_INFO "Registering G5 CPU frequency driver\n");
- printk(KERN_INFO "Frequency method: i2c/pfunc, "
- "Voltage method: %s\n", has_volt ? "i2c/pfunc" : "none");
- printk(KERN_INFO "Low: %d Mhz, High: %d Mhz, Cur: %d MHz\n",
- g5_cpu_freqs[1].frequency/1000,
- g5_cpu_freqs[0].frequency/1000,
- g5_cpu_freqs[g5_pmode_cur].frequency/1000);
-
- rc = cpufreq_register_driver(&g5_cpufreq_driver);
- bail:
- if (rc != 0) {
- pmf_put_function(pfunc_cpu_getfreq);
- pmf_put_function(pfunc_cpu_setfreq_high);
- pmf_put_function(pfunc_cpu_setfreq_low);
- pmf_put_function(pfunc_slewing_done);
- pmf_put_function(pfunc_cpu0_volt_high);
- pmf_put_function(pfunc_cpu0_volt_low);
- pmf_put_function(pfunc_cpu1_volt_high);
- pmf_put_function(pfunc_cpu1_volt_low);
- }
- of_node_put(hwclock);
- of_node_put(cpuid);
- of_node_put(cpunode);
-
- return rc;
-}
-
-static int __init g5_rm31_cpufreq_init(struct device_node *cpus)
-{
- /* NYI */
- return 0;
-}
-
-static int __init g5_cpufreq_init(void)
-{
- struct device_node *cpus;
- int rc;
-
- cpus = of_find_node_by_path("/cpus");
- if (cpus == NULL) {
- DBG("No /cpus node !\n");
- return -ENODEV;
- }
-
- if (machine_is_compatible("PowerMac7,2") ||
- machine_is_compatible("PowerMac7,3"))
- rc = g5_pm72_cpufreq_init(cpus);
- else if (machine_is_compatible("RackMac3,1"))
- rc = g5_rm31_cpufreq_init(cpus);
- else
- rc = g5_neo2_cpufreq_init(cpus);
-
- of_node_put(cpus);
- return rc;
-}
-
-module_init(g5_cpufreq_init);
-
-
-MODULE_LICENSE("GPL");
diff --git a/arch/powerpc/platforms/powermac/feature.c b/arch/powerpc/platforms/powermac/feature.c
index 558dd069209..63d82bbc05e 100644
--- a/arch/powerpc/platforms/powermac/feature.c
+++ b/arch/powerpc/platforms/powermac/feature.c
@@ -1,6 +1,4 @@
/*
- * arch/ppc/platforms/pmac_feature.c
- *
* Copyright (C) 1996-2001 Paul Mackerras (paulus@cs.anu.edu.au)
* Ben. Herrenschmidt (benh@kernel.crashing.org)
*
@@ -18,16 +16,18 @@
* - 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/of.h>
+#include <linux/of_address.h>
#include <linux/spinlock.h>
#include <linux/adb.h>
#include <linux/pmu.h>
#include <linux/ioport.h>
+#include <linux/export.h>
#include <linux/pci.h>
#include <asm/sections.h>
#include <asm/errno.h>
@@ -62,10 +62,10 @@ 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
*/
-DEFINE_SPINLOCK(feature_lock);
+DEFINE_RAW_SPINLOCK(feature_lock);
-#define LOCK(flags) spin_lock_irqsave(&feature_lock, flags);
-#define UNLOCK(flags) spin_unlock_irqrestore(&feature_lock, flags);
+#define LOCK(flags) raw_spin_lock_irqsave(&feature_lock, flags);
+#define UNLOCK(flags) raw_spin_unlock_irqrestore(&feature_lock, flags);
/*
@@ -489,10 +489,6 @@ static long heathrow_sound_enable(struct device_node *node, long param,
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];
@@ -817,6 +813,7 @@ core99_ata100_enable(struct device_node *node, long value)
unsigned long flags;
struct pci_dev *pdev = NULL;
u8 pbus, pid;
+ int rc;
if (uninorth_rev < 0x24)
return -ENODEV;
@@ -832,11 +829,15 @@ core99_ata100_enable(struct device_node *node, long value)
if (value) {
if (pci_device_from_OF_node(node, &pbus, &pid) == 0)
- pdev = pci_find_slot(pbus, pid);
+ pdev = pci_get_bus_and_slot(pbus, pid);
if (pdev == NULL)
return 0;
- pci_enable_device(pdev);
- pci_set_master(pdev);
+ rc = pci_enable_device(pdev);
+ if (rc == 0)
+ pci_set_master(pdev);
+ pci_dev_put(pdev);
+ if (rc)
+ return rc;
}
return 0;
}
@@ -1048,6 +1049,7 @@ core99_reset_cpu(struct device_node *node, long param, long value)
unsigned long flags;
struct macio_chip *macio;
struct device_node *np;
+ struct device_node *cpus;
const int dflt_reset_lines[] = { KL_GPIO_RESET_CPU0,
KL_GPIO_RESET_CPU1,
KL_GPIO_RESET_CPU2,
@@ -1057,12 +1059,12 @@ core99_reset_cpu(struct device_node *node, long param, long value)
if (macio->type != macio_keylargo)
return -ENODEV;
- np = find_path_device("/cpus");
- if (np == NULL)
+ cpus = of_find_node_by_path("/cpus");
+ if (cpus == 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);
+ for (np = cpus->child; np != NULL; np = np->sibling) {
+ const u32 *num = of_get_property(np, "reg", NULL);
+ const u32 *rst = of_get_property(np, "soft-reset", NULL);
if (num == NULL || rst == NULL)
continue;
if (param == *num) {
@@ -1070,6 +1072,7 @@ core99_reset_cpu(struct device_node *node, long param, long value)
break;
}
}
+ of_node_put(cpus);
if (np == NULL || reset_io == 0)
reset_io = dflt_reset_lines[param];
@@ -1090,7 +1093,7 @@ core99_usb_enable(struct device_node *node, long param, long value)
{
struct macio_chip *macio;
unsigned long flags;
- char *prop;
+ const char *prop;
int number;
u32 reg;
@@ -1099,7 +1102,7 @@ core99_usb_enable(struct device_node *node, long param, long value)
macio->type != macio_intrepid)
return -ENODEV;
- prop = (char *)get_property(node, "AAPL,clock-id", NULL);
+ prop = of_get_property(node, "AAPL,clock-id", NULL);
if (!prop)
return -ENODEV;
if (strncmp(prop, "usb0u048", 8) == 0)
@@ -1420,7 +1423,7 @@ static long g5_eth_phy_reset(struct device_node *node, long param, long value)
phy = of_get_next_child(node, NULL);
if (!phy)
return -ENODEV;
- need_reset = device_is_compatible(phy, "B5221");
+ need_reset = of_device_is_compatible(phy, "B5221");
of_node_put(phy);
if (!need_reset)
return 0;
@@ -1501,17 +1504,18 @@ static long g5_reset_cpu(struct device_node *node, long param, long value)
unsigned long flags;
struct macio_chip *macio;
struct device_node *np;
+ struct device_node *cpus;
macio = &macio_chips[0];
if (macio->type != macio_keylargo2 && macio->type != macio_shasta)
return -ENODEV;
- np = find_path_device("/cpus");
- if (np == NULL)
+ cpus = of_find_node_by_path("/cpus");
+ if (cpus == 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);
+ for (np = cpus->child; np != NULL; np = np->sibling) {
+ const u32 *num = of_get_property(np, "reg", NULL);
+ const u32 *rst = of_get_property(np, "soft-reset", NULL);
if (num == NULL || rst == NULL)
continue;
if (param == *num) {
@@ -1519,6 +1523,7 @@ static long g5_reset_cpu(struct device_node *node, long param, long value)
break;
}
}
+ of_node_put(cpus);
if (np == NULL || reset_io == 0)
return -ENODEV;
@@ -1551,6 +1556,10 @@ void g5_phy_disable_cpu1(void)
#ifdef CONFIG_PM
+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 void keylargo_shutdown(struct macio_chip *macio, int sleep_mode)
{
@@ -1646,10 +1655,10 @@ static void intrepid_shutdown(struct macio_chip *macio, int sleep_mode)
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);
+ KL1_I2S1_CLK_ENABLE_BIT | KL1_I2S1_ENABLE |
+ KL1_EIDE0_ENABLE);
if (pmac_mb.board_flags & PMAC_MB_MOBILE)
MACIO_BIC(KEYLARGO_FCR1, KL1_UIDE_RESET_N);
@@ -2183,9 +2192,13 @@ static struct pmac_mb_def pmac_mb_defs[] = {
},
{ "PowerMac10,1", "Mac mini",
PMAC_TYPE_UNKNOWN_INTREPID, intrepid_features,
- PMAC_MB_MAY_SLEEP | PMAC_MB_HAS_FW_POWER,
+ PMAC_MB_MAY_SLEEP,
},
- { "iMac,1", "iMac (first generation)",
+ { "PowerMac10,2", "Mac mini (Late 2005)",
+ PMAC_TYPE_UNKNOWN_INTREPID, intrepid_features,
+ PMAC_MB_MAY_SLEEP,
+ },
+ { "iMac,1", "iMac (first generation)",
PMAC_TYPE_ORIG_IMAC, paddington_features,
0
},
@@ -2295,11 +2308,11 @@ static struct pmac_mb_def pmac_mb_defs[] = {
},
{ "PowerBook5,8", "PowerBook G4 15\"",
PMAC_TYPE_UNKNOWN_INTREPID, intrepid_features,
- PMAC_MB_MAY_SLEEP | PMAC_MB_HAS_FW_POWER | PMAC_MB_MOBILE,
+ PMAC_MB_MAY_SLEEP | PMAC_MB_MOBILE,
},
{ "PowerBook5,9", "PowerBook G4 17\"",
PMAC_TYPE_UNKNOWN_INTREPID, intrepid_features,
- PMAC_MB_MAY_SLEEP | PMAC_MB_HAS_FW_POWER | PMAC_MB_MOBILE,
+ PMAC_MB_MAY_SLEEP | PMAC_MB_MOBILE,
},
{ "PowerBook6,1", "PowerBook G4 12\"",
PMAC_TYPE_UNKNOWN_INTREPID, intrepid_features,
@@ -2404,22 +2417,23 @@ static int __init probe_motherboard(void)
struct macio_chip *macio = &macio_chips[0];
const char *model = NULL;
struct device_node *dt;
+ int ret = 0;
/* 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");
+ dt = of_find_node_by_name(NULL, "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++) {
+ model = of_get_property(dt, "model", NULL);
+ for(i=0; model && i<ARRAY_SIZE(pmac_mb_defs); 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)) {
+ for(i=0; i<ARRAY_SIZE(pmac_mb_defs); i++) {
+ if (of_machine_is_compatible(pmac_mb_defs[i].model_string)) {
pmac_mb = pmac_mb_defs[i];
goto found;
}
@@ -2474,15 +2488,18 @@ static int __init probe_motherboard(void)
break;
#endif /* CONFIG_POWER4 */
default:
- return -ENODEV;
+ ret = -ENODEV;
+ goto done;
}
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;
+ if (!mach_id_ptr) {
+ ret = -ENODEV;
+ goto done;
+ }
/* 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.
@@ -2491,9 +2508,7 @@ found:
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
@@ -2501,20 +2516,28 @@ found:
* 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) {
+ struct device_node *cpus = of_find_node_by_path("/cpus");
+ struct device_node *np;
+
+ if (!cpus || !cpus->child) {
printk(KERN_WARNING "Can't find CPU(s) in device tree !\n");
+ of_node_put(cpus);
break;
}
- np = np->child;
+ np = cpus->child;
/* Nap mode not supported on SMP */
- if (np->sibling)
+ if (np->sibling) {
+ of_node_put(cpus);
break;
+ }
/* Nap mode not supported if flush-on-lock property is present */
- if (get_property(np, "flush-on-lock", NULL))
+ if (of_get_property(np, "flush-on-lock", NULL)) {
+ of_node_put(cpus);
break;
+ }
+ of_node_put(cpus);
powersave_nap = 1;
- printk(KERN_INFO "Processor NAP mode on idle enabled.\n");
+ printk(KERN_DEBUG "Processor NAP mode on idle enabled.\n");
break;
}
@@ -2522,10 +2545,11 @@ found:
* NAP mode
*/
powersave_lowspeed = 1;
-#endif /* CONFIG_6xx */
-#ifdef CONFIG_POWER4
+
+#else /* CONFIG_POWER4 */
powersave_nap = 1;
-#endif
+#endif /* CONFIG_POWER4 */
+
/* Check for "mobile" machine */
if (model && (strncmp(model, "PowerBook", 9) == 0
|| strncmp(model, "iBook", 5) == 0))
@@ -2533,19 +2557,23 @@ found:
printk(KERN_INFO "PowerMac motherboard: %s\n", pmac_mb.model_name);
- return 0;
+done:
+ of_node_put(dt);
+ return ret;
}
/* Initialize the Core99 UniNorth host bridge and memory controller
*/
static void __init probe_uninorth(void)
{
- u32 *addrp;
+ const u32 *addrp;
phys_addr_t address;
unsigned long actrl;
/* Locate core99 Uni-N */
uninorth_node = of_find_node_by_name(NULL, "uni-n");
+ uninorth_maj = 1;
+
/* Locate G5 u3 */
if (uninorth_node == NULL) {
uninorth_node = of_find_node_by_name(NULL, "u3");
@@ -2556,19 +2584,28 @@ static void __init probe_uninorth(void)
uninorth_node = of_find_node_by_name(NULL, "u4");
uninorth_maj = 4;
}
- if (uninorth_node == NULL)
+ if (uninorth_node == NULL) {
+ uninorth_maj = 0;
return;
+ }
- addrp = (u32 *)get_property(uninorth_node, "reg", NULL);
+ addrp = of_get_property(uninorth_node, "reg", NULL);
if (addrp == NULL)
return;
address = of_translate_address(uninorth_node, addrp);
if (address == 0)
return;
uninorth_base = ioremap(address, 0x40000);
+ if (uninorth_base == NULL)
+ return;
uninorth_rev = in_be32(UN_REG(UNI_N_VERSION));
- if (uninorth_maj == 3 || uninorth_maj == 4)
+ if (uninorth_maj == 3 || uninorth_maj == 4) {
u3_ht_base = ioremap(address + U3_HT_CONFIG_BASE, 0x1000);
+ if (u3_ht_base == NULL) {
+ iounmap(uninorth_base);
+ return;
+ }
+ }
printk(KERN_INFO "Found %s memory controller & host bridge"
" @ 0x%08x revision: 0x%02x\n", uninorth_maj == 3 ? "U3" :
@@ -2600,14 +2637,14 @@ static void __init probe_one_macio(const char *name, const char *compat, int typ
struct device_node* node;
int i;
volatile u32 __iomem *base;
- u32 *addrp, *revp;
+ const u32 *addrp, *revp;
phys_addr_t addr;
u64 size;
for (node = NULL; (node = of_find_node_by_name(node, name)) != NULL;) {
if (!compat)
break;
- if (device_is_compatible(node, compat))
+ if (of_device_is_compatible(node, compat))
break;
}
if (!node)
@@ -2643,7 +2680,7 @@ static void __init probe_one_macio(const char *name, const char *compat, int typ
return;
}
if (type == macio_keylargo || type == macio_keylargo2) {
- u32 *did = (u32 *)get_property(node, "device-id", NULL);
+ const u32 *did = of_get_property(node, "device-id", NULL);
if (*did == 0x00000025)
type = macio_pangea;
if (*did == 0x0000003e)
@@ -2654,9 +2691,9 @@ static void __init probe_one_macio(const char *name, const char *compat, int typ
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].flags = MACIO_FLAG_SCCA_ON | MACIO_FLAG_SCCB_ON;
macio_chips[i].name = macio_names[type];
- revp = (u32 *)get_property(node, "revision-id", NULL);
+ revp = of_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",
@@ -2699,19 +2736,19 @@ static void __init
initial_serial_shutdown(struct device_node *np)
{
int len;
- struct slot_names_prop {
+ const struct slot_names_prop {
int count;
char name[1];
} *slots;
- char *conn;
+ const 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);
+ slots = of_get_property(np, "slot-names", &len);
+ conn = of_get_property(np, "AAPL,connector", &len);
if (conn && (strcmp(conn, "infrared") == 0))
port_type = PMAC_SCC_IRDA;
- else if (device_is_compatible(np, "cobalt"))
+ else if (of_device_is_compatible(np, "cobalt"))
modem = 1;
else if (slots && slots->count > 0) {
if (strcmp(slots->name, "IrDA") == 0)
@@ -2736,12 +2773,14 @@ set_initial_features(void)
* 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) {
+ if (macio_chips[0].type == macio_ohare) {
struct macio_chip *macio = &macio_chips[0];
- MACIO_BIS(OHARE_FCR, OH_IOBUS_ENABLE);
+ np = of_find_node_by_name(NULL, "via-pmu");
+ if (np)
+ MACIO_BIS(OHARE_FCR, OH_IOBUS_ENABLE);
+ else
+ MACIO_OUT32(OHARE_FCR, STARMAX_FEATURES);
+ of_node_put(np);
} else if (macio_chips[1].type == macio_ohare) {
struct macio_chip *macio = &macio_chips[1];
MACIO_BIS(OHARE_FCR, OH_IOBUS_ENABLE);
@@ -2768,7 +2807,7 @@ set_initial_features(void)
*/
np = of_find_node_by_name(NULL, "ethernet");
while(np) {
- if (device_is_compatible(np, "K2-GMAC"))
+ if (of_device_is_compatible(np, "K2-GMAC"))
g5_gmac_enable(np, 0, 1);
np = of_find_node_by_name(np, "ethernet");
}
@@ -2780,7 +2819,7 @@ set_initial_features(void)
*/
np = of_find_node_by_name(NULL, "firewire");
while(np) {
- if (device_is_compatible(np, "pci106b,5811")) {
+ if (of_device_is_compatible(np, "pci106b,5811")) {
macio_chips[0].flags |= MACIO_FLAG_FW_SUPPORTED;
g5_fw_enable(np, 0, 1);
}
@@ -2798,8 +2837,8 @@ set_initial_features(void)
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"))
+ && of_device_is_compatible(np->parent, "uni-north")
+ && of_device_is_compatible(np, "gmac"))
core99_gmac_enable(np, 0, 1);
np = of_find_node_by_name(np, "ethernet");
}
@@ -2812,10 +2851,10 @@ set_initial_features(void)
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"))) {
+ && of_device_is_compatible(np->parent, "uni-north")
+ && (of_device_is_compatible(np, "pci106b,18") ||
+ of_device_is_compatible(np, "pci106b,30") ||
+ of_device_is_compatible(np, "pci11c1,5811"))) {
macio_chips[0].flags |= MACIO_FLAG_FW_SUPPORTED;
core99_firewire_enable(np, 0, 1);
}
@@ -2826,21 +2865,19 @@ set_initial_features(void)
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")) {
+ && of_device_is_compatible(np->parent, "uni-north")
+ && of_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) {
+ for_each_node_by_name(np, "radio") {
+ if (np->parent == macio_chips[0].of_node) {
macio_chips[0].flags |= MACIO_FLAG_AIRPORT_ON;
core99_airport_enable(np, 0, 0);
}
- np = np->next;
}
}
@@ -2861,16 +2898,12 @@ set_initial_features(void)
#endif /* CONFIG_POWER4 */
/* On all machines, switch modem & serial ports off */
- np = find_devices("ch-a");
- while(np) {
+ for_each_node_by_name(np, "ch-a")
initial_serial_shutdown(np);
- np = np->next;
- }
- np = find_devices("ch-b");
- while(np) {
+ of_node_put(np);
+ for_each_node_by_name(np, "ch-b")
initial_serial_shutdown(np);
- np = np->next;
- }
+ of_node_put(np);
}
void __init
@@ -2954,7 +2987,7 @@ static void *pmac_early_vresume_data;
void pmac_set_early_video_resume(void (*proc)(void *data), void *data)
{
- if (_machine != _MACH_Pmac)
+ if (!machine_is(powermac))
return;
preempt_disable();
pmac_early_vresume_proc = proc;
@@ -3013,3 +3046,8 @@ void pmac_resume_agp_for_card(struct pci_dev *dev)
pmac_agp_resume(pmac_agp_bridge);
}
EXPORT_SYMBOL(pmac_resume_agp_for_card);
+
+int pmac_get_uninorth_variant(void)
+{
+ return uninorth_maj;
+}
diff --git a/arch/powerpc/platforms/powermac/low_i2c.c b/arch/powerpc/platforms/powermac/low_i2c.c
index 535c802b369..7553b6a77c6 100644
--- a/arch/powerpc/platforms/powermac/low_i2c.c
+++ b/arch/powerpc/platforms/powermac/low_i2c.c
@@ -30,19 +30,20 @@
#undef DEBUG
#undef DEBUG_LOW
-#include <linux/config.h>
#include <linux/types.h>
#include <linux/sched.h>
#include <linux/init.h>
-#include <linux/module.h>
+#include <linux/export.h>
#include <linux/adb.h>
#include <linux/pmu.h>
#include <linux/delay.h>
#include <linux/completion.h>
#include <linux/platform_device.h>
#include <linux/interrupt.h>
-#include <linux/completion.h>
#include <linux/timer.h>
+#include <linux/mutex.h>
+#include <linux/i2c.h>
+#include <linux/slab.h>
#include <asm/keylargo.h>
#include <asm/uninorth.h>
#include <asm/io.h>
@@ -81,11 +82,11 @@ struct pmac_i2c_bus
struct device_node *busnode;
int type;
int flags;
- struct i2c_adapter *adapter;
+ struct i2c_adapter adapter;
void *hostdata;
int channel; /* some hosts have multiple */
int mode; /* current mode */
- struct semaphore sem;
+ struct mutex mutex;
int opened;
int polled; /* open mode */
struct platform_device *platform_dev;
@@ -105,7 +106,7 @@ static LIST_HEAD(pmac_i2c_busses);
struct pmac_i2c_host_kw
{
- struct semaphore mutex; /* Access mutex for use by
+ struct mutex mutex; /* Access mutex for use by
* i2c-keywest */
void __iomem *base; /* register base address */
int bsteps; /* register stepping */
@@ -231,6 +232,14 @@ static u8 kw_i2c_wait_interrupt(struct pmac_i2c_host_kw *host)
return isr;
}
+static void kw_i2c_do_stop(struct pmac_i2c_host_kw *host, int result)
+{
+ kw_write_reg(reg_control, KW_I2C_CTL_STOP);
+ host->state = state_stop;
+ host->result = result;
+}
+
+
static void kw_i2c_handle_interrupt(struct pmac_i2c_host_kw *host, u8 isr)
{
u8 ack;
@@ -246,42 +255,36 @@ static void kw_i2c_handle_interrupt(struct pmac_i2c_host_kw *host, u8 isr)
}
if (isr == 0) {
+ printk(KERN_WARNING "low_i2c: Timeout in i2c transfer"
+ " on keywest !\n");
if (host->state != state_stop) {
- DBG_LOW("KW: Timeout !\n");
- host->result = -EIO;
- goto stop;
- }
- if (host->state == state_stop) {
- ack = kw_read_reg(reg_status);
- if (ack & KW_I2C_STAT_BUSY)
- kw_write_reg(reg_status, 0);
- host->state = state_idle;
- kw_write_reg(reg_ier, 0x00);
- if (!host->polled)
- complete(&host->complete);
+ kw_i2c_do_stop(host, -EIO);
+ return;
}
+ ack = kw_read_reg(reg_status);
+ if (ack & KW_I2C_STAT_BUSY)
+ kw_write_reg(reg_status, 0);
+ host->state = state_idle;
+ kw_write_reg(reg_ier, 0x00);
+ if (!host->polled)
+ complete(&host->complete);
return;
}
if (isr & KW_I2C_IRQ_ADDR) {
ack = kw_read_reg(reg_status);
if (host->state != state_addr) {
- kw_write_reg(reg_isr, KW_I2C_IRQ_ADDR);
WRONG_STATE("KW_I2C_IRQ_ADDR");
- host->result = -EIO;
- goto stop;
+ kw_i2c_do_stop(host, -EIO);
}
if ((ack & KW_I2C_STAT_LAST_AAK) == 0) {
- host->result = -ENODEV;
- DBG_LOW("KW: NAK on address\n");
+ host->result = -ENXIO;
host->state = state_stop;
- return;
+ DBG_LOW("KW: NAK on address\n");
} else {
- if (host->len == 0) {
- kw_write_reg(reg_isr, KW_I2C_IRQ_ADDR);
- goto stop;
- }
- if (host->rw) {
+ if (host->len == 0)
+ kw_i2c_do_stop(host, 0);
+ else if (host->rw) {
host->state = state_read;
if (host->len > 1)
kw_write_reg(reg_control,
@@ -308,25 +311,19 @@ static void kw_i2c_handle_interrupt(struct pmac_i2c_host_kw *host, u8 isr)
ack = kw_read_reg(reg_status);
if ((ack & KW_I2C_STAT_LAST_AAK) == 0) {
DBG_LOW("KW: nack on data write\n");
- host->result = -EIO;
- goto stop;
+ host->result = -EFBIG;
+ host->state = state_stop;
} else if (host->len) {
kw_write_reg(reg_data, *(host->data++));
host->len--;
- } else {
- kw_write_reg(reg_control, KW_I2C_CTL_STOP);
- host->state = state_stop;
- host->result = 0;
- }
- kw_write_reg(reg_isr, KW_I2C_IRQ_DATA);
+ } else
+ kw_i2c_do_stop(host, 0);
} else {
- kw_write_reg(reg_isr, KW_I2C_IRQ_DATA);
WRONG_STATE("KW_I2C_IRQ_DATA");
- if (host->state != state_stop) {
- host->result = -EIO;
- goto stop;
- }
+ if (host->state != state_stop)
+ kw_i2c_do_stop(host, -EIO);
}
+ kw_write_reg(reg_isr, KW_I2C_IRQ_DATA);
}
if (isr & KW_I2C_IRQ_STOP) {
@@ -340,18 +337,14 @@ static void kw_i2c_handle_interrupt(struct pmac_i2c_host_kw *host, u8 isr)
complete(&host->complete);
}
+ /* Below should only happen in manual mode which we don't use ... */
if (isr & KW_I2C_IRQ_START)
kw_write_reg(reg_isr, KW_I2C_IRQ_START);
- return;
- stop:
- kw_write_reg(reg_control, KW_I2C_CTL_STOP);
- host->state = state_stop;
- return;
}
/* Interrupt handler */
-static irqreturn_t kw_i2c_irq(int irq, void *dev_id, struct pt_regs *regs)
+static irqreturn_t kw_i2c_irq(int irq, void *dev_id)
{
struct pmac_i2c_host_kw *host = dev_id;
unsigned long flags;
@@ -373,25 +366,34 @@ static void kw_i2c_timeout(unsigned long data)
unsigned long flags;
spin_lock_irqsave(&host->lock, flags);
+
+ /*
+ * If the timer is pending, that means we raced with the
+ * irq, in which case we just return
+ */
+ if (timer_pending(&host->timeout_timer))
+ goto skip;
+
kw_i2c_handle_interrupt(host, kw_read_reg(reg_isr));
if (host->state != state_idle) {
host->timeout_timer.expires = jiffies + KW_POLL_TIMEOUT;
add_timer(&host->timeout_timer);
}
+ skip:
spin_unlock_irqrestore(&host->lock, flags);
}
static int kw_i2c_open(struct pmac_i2c_bus *bus)
{
struct pmac_i2c_host_kw *host = bus->hostdata;
- down(&host->mutex);
+ mutex_lock(&host->mutex);
return 0;
}
static void kw_i2c_close(struct pmac_i2c_bus *bus)
{
struct pmac_i2c_host_kw *host = bus->hostdata;
- up(&host->mutex);
+ mutex_unlock(&host->mutex);
}
static int kw_i2c_xfer(struct pmac_i2c_bus *bus, u8 addrdir, int subsize,
@@ -450,7 +452,7 @@ static int kw_i2c_xfer(struct pmac_i2c_bus *bus, u8 addrdir, int subsize,
*/
if (use_irq) {
/* Clear completion */
- INIT_COMPLETION(host->complete);
+ reinit_completion(&host->complete);
/* Ack stale interrupts */
kw_write_reg(reg_isr, kw_read_reg(reg_isr));
/* Arm timeout */
@@ -486,7 +488,8 @@ static int kw_i2c_xfer(struct pmac_i2c_bus *bus, u8 addrdir, int subsize,
static struct pmac_i2c_host_kw *__init kw_i2c_host_init(struct device_node *np)
{
struct pmac_i2c_host_kw *host;
- u32 *psteps, *prate, *addrp, steps;
+ const u32 *psteps, *prate, *addrp;
+ u32 steps;
host = kzalloc(sizeof(struct pmac_i2c_host_kw), GFP_KERNEL);
if (host == NULL) {
@@ -499,27 +502,27 @@ static struct pmac_i2c_host_kw *__init kw_i2c_host_init(struct device_node *np)
* on all i2c keywest nodes so far ... we would have to fallback
* to macio parsing if that wasn't the case
*/
- addrp = (u32 *)get_property(np, "AAPL,address", NULL);
+ addrp = of_get_property(np, "AAPL,address", NULL);
if (addrp == NULL) {
printk(KERN_ERR "low_i2c: Can't find address for %s\n",
np->full_name);
kfree(host);
return NULL;
}
- init_MUTEX(&host->mutex);
+ mutex_init(&host->mutex);
init_completion(&host->complete);
spin_lock_init(&host->lock);
init_timer(&host->timeout_timer);
host->timeout_timer.function = kw_i2c_timeout;
host->timeout_timer.data = (unsigned long)host;
- psteps = (u32 *)get_property(np, "AAPL,address-step", NULL);
+ psteps = of_get_property(np, "AAPL,address-step", NULL);
steps = psteps ? (*psteps) : 0x10;
for (host->bsteps = 0; (steps & 0x01) == 0; host->bsteps++)
steps >>= 1;
/* Select interface rate */
host->speed = KW_I2C_MODE_25KHZ;
- prate = (u32 *)get_property(np, "AAPL,i2c-rate", NULL);
+ prate = of_get_property(np, "AAPL,i2c-rate", NULL);
if (prate) switch(*prate) {
case 100:
host->speed = KW_I2C_MODE_100KHZ;
@@ -531,10 +534,11 @@ static struct pmac_i2c_host_kw *__init kw_i2c_host_init(struct device_node *np)
host->speed = KW_I2C_MODE_25KHZ;
break;
}
- if (np->n_intrs > 0)
- host->irq = np->intrs[0].line;
- else
- host->irq = NO_IRQ;
+ host->irq = irq_of_parse_and_map(np, 0);
+ if (host->irq == NO_IRQ)
+ printk(KERN_WARNING
+ "low_i2c: Failed to map interrupt for %s\n",
+ np->full_name);
host->base = ioremap((*addrp), 0x1000);
if (host->base == NULL) {
@@ -544,11 +548,15 @@ static struct pmac_i2c_host_kw *__init kw_i2c_host_init(struct device_node *np)
return NULL;
}
- /* Make sure IRA is disabled */
+ /* Make sure IRQ is disabled */
kw_write_reg(reg_ier, 0);
- /* Request chip interrupt */
- if (request_irq(host->irq, kw_i2c_irq, SA_SHIRQ, "keywest i2c", host))
+ /* Request chip interrupt. We set IRQF_NO_SUSPEND because we don't
+ * want that interrupt disabled between the 2 passes of driver
+ * suspend or we'll have issues running the pfuncs
+ */
+ if (request_irq(host->irq, kw_i2c_irq, IRQF_NO_SUSPEND,
+ "keywest i2c", host))
host->irq = NO_IRQ;
printk(KERN_INFO "KeyWest i2c @0x%08x irq %d %s\n",
@@ -578,7 +586,7 @@ static void __init kw_i2c_add(struct pmac_i2c_host_kw *host,
bus->open = kw_i2c_open;
bus->close = kw_i2c_close;
bus->xfer = kw_i2c_xfer;
- init_MUTEX(&bus->sem);
+ mutex_init(&bus->mutex);
if (controller == busnode)
bus->flags = pmac_i2c_multibus;
list_add(&bus->link, &pmac_i2c_busses);
@@ -592,10 +600,9 @@ static void __init kw_i2c_probe(void)
struct device_node *np, *child, *parent;
/* Probe keywest-i2c busses */
- for (np = NULL;
- (np = of_find_compatible_node(np, "i2c","keywest-i2c")) != NULL;){
+ for_each_compatible_node(np, "i2c","keywest-i2c") {
struct pmac_i2c_host_kw *host;
- int multibus, chans, i;
+ int multibus;
/* Found one, init a host structure */
host = kw_i2c_host_init(np);
@@ -617,6 +624,8 @@ static void __init kw_i2c_probe(void)
* parent type
*/
if (multibus) {
+ int chans, i;
+
parent = of_get_parent(np);
if (parent == NULL)
continue;
@@ -626,8 +635,8 @@ static void __init kw_i2c_probe(void)
} else {
for (child = NULL;
(child = of_get_next_child(np, child)) != NULL;) {
- u32 *reg =
- (u32 *)get_property(child, "reg", NULL);
+ const u32 *reg = of_get_property(child,
+ "reg", NULL);
if (reg == NULL)
continue;
kw_i2c_add(host, np, child, *reg);
@@ -708,7 +717,7 @@ static int pmu_i2c_xfer(struct pmac_i2c_bus *bus, u8 addrdir, int subsize,
return -EINVAL;
}
- INIT_COMPLETION(comp);
+ reinit_completion(&comp);
req->data[0] = PMU_I2C_CMD;
req->reply[0] = 0xff;
req->nbytes = sizeof(struct pmu_i2c_hdr) + 1;
@@ -739,7 +748,7 @@ static int pmu_i2c_xfer(struct pmac_i2c_bus *bus, u8 addrdir, int subsize,
hdr->bus = PMU_I2C_BUS_STATUS;
- INIT_COMPLETION(comp);
+ reinit_completion(&comp);
req->data[0] = PMU_I2C_CMD;
req->reply[0] = 0xff;
req->nbytes = 2;
@@ -805,7 +814,7 @@ static void __init pmu_i2c_probe(void)
bus->mode = pmac_i2c_mode_std;
bus->hostdata = bus + 1;
bus->xfer = pmu_i2c_xfer;
- init_MUTEX(&bus->sem);
+ mutex_init(&bus->mutex);
bus->flags = pmac_i2c_multibus;
list_add(&bus->link, &pmac_i2c_busses);
@@ -889,7 +898,7 @@ static void __init smu_i2c_probe(void)
{
struct device_node *controller, *busnode;
struct pmac_i2c_bus *bus;
- u32 *reg;
+ const u32 *reg;
int sz;
if (!smu_present())
@@ -904,7 +913,7 @@ static void __init smu_i2c_probe(void)
printk(KERN_INFO "SMU i2c %s\n", controller->full_name);
/* Look for childs, note that they might not be of the right
- * type as older device trees mix i2c busses and other thigns
+ * type as older device trees mix i2c busses and other things
* at the same level
*/
for (busnode = NULL;
@@ -912,7 +921,7 @@ static void __init smu_i2c_probe(void)
if (strcmp(busnode->type, "i2c") &&
strcmp(busnode->type, "i2c-bus"))
continue;
- reg = (u32 *)get_property(busnode, "reg", NULL);
+ reg = of_get_property(busnode, "reg", NULL);
if (reg == NULL)
continue;
@@ -928,7 +937,7 @@ static void __init smu_i2c_probe(void)
bus->mode = pmac_i2c_mode_std;
bus->hostdata = bus + 1;
bus->xfer = smu_i2c_xfer;
- init_MUTEX(&bus->sem);
+ mutex_init(&bus->mutex);
bus->flags = 0;
list_add(&bus->link, &pmac_i2c_busses);
@@ -956,9 +965,9 @@ struct pmac_i2c_bus *pmac_i2c_find_bus(struct device_node *node)
list_for_each_entry(bus, &pmac_i2c_busses, link) {
if (p == bus->busnode) {
if (prev && bus->flags & pmac_i2c_multibus) {
- u32 *reg;
- reg = (u32 *)get_property(prev, "reg",
- NULL);
+ const u32 *reg;
+ reg = of_get_property(prev, "reg",
+ NULL);
if (!reg)
continue;
if (((*reg) >> 8) != bus->channel)
@@ -979,7 +988,7 @@ EXPORT_SYMBOL_GPL(pmac_i2c_find_bus);
u8 pmac_i2c_get_dev_addr(struct device_node *device)
{
- u32 *reg = (u32 *)get_property(device, "reg", NULL);
+ const u32 *reg = of_get_property(device, "reg", NULL);
if (reg == NULL)
return 0;
@@ -1019,25 +1028,9 @@ int pmac_i2c_get_channel(struct pmac_i2c_bus *bus)
EXPORT_SYMBOL_GPL(pmac_i2c_get_channel);
-void pmac_i2c_attach_adapter(struct pmac_i2c_bus *bus,
- struct i2c_adapter *adapter)
-{
- WARN_ON(bus->adapter != NULL);
- bus->adapter = adapter;
-}
-EXPORT_SYMBOL_GPL(pmac_i2c_attach_adapter);
-
-void pmac_i2c_detach_adapter(struct pmac_i2c_bus *bus,
- struct i2c_adapter *adapter)
-{
- WARN_ON(bus->adapter != adapter);
- bus->adapter = NULL;
-}
-EXPORT_SYMBOL_GPL(pmac_i2c_detach_adapter);
-
struct i2c_adapter *pmac_i2c_get_adapter(struct pmac_i2c_bus *bus)
{
- return bus->adapter;
+ return &bus->adapter;
}
EXPORT_SYMBOL_GPL(pmac_i2c_get_adapter);
@@ -1046,20 +1039,19 @@ struct pmac_i2c_bus *pmac_i2c_adapter_to_bus(struct i2c_adapter *adapter)
struct pmac_i2c_bus *bus;
list_for_each_entry(bus, &pmac_i2c_busses, link)
- if (bus->adapter == adapter)
+ if (&bus->adapter == adapter)
return bus;
return NULL;
}
EXPORT_SYMBOL_GPL(pmac_i2c_adapter_to_bus);
-extern int pmac_i2c_match_adapter(struct device_node *dev,
- struct i2c_adapter *adapter)
+int pmac_i2c_match_adapter(struct device_node *dev, struct i2c_adapter *adapter)
{
struct pmac_i2c_bus *bus = pmac_i2c_find_bus(dev);
if (bus == NULL)
return 0;
- return (bus->adapter == adapter);
+ return (&bus->adapter == adapter);
}
EXPORT_SYMBOL_GPL(pmac_i2c_match_adapter);
@@ -1101,13 +1093,13 @@ int pmac_i2c_open(struct pmac_i2c_bus *bus, int polled)
{
int rc;
- down(&bus->sem);
+ mutex_lock(&bus->mutex);
bus->polled = polled || pmac_i2c_force_poll;
bus->opened = 1;
bus->mode = pmac_i2c_mode_std;
if (bus->open && (rc = bus->open(bus)) != 0) {
bus->opened = 0;
- up(&bus->sem);
+ mutex_unlock(&bus->mutex);
return rc;
}
return 0;
@@ -1120,7 +1112,7 @@ void pmac_i2c_close(struct pmac_i2c_bus *bus)
if (bus->close)
bus->close(bus);
bus->opened = 0;
- up(&bus->sem);
+ mutex_unlock(&bus->mutex);
}
EXPORT_SYMBOL_GPL(pmac_i2c_close);
@@ -1166,6 +1158,7 @@ EXPORT_SYMBOL_GPL(pmac_i2c_xfer);
/* some quirks for platform function decoding */
enum {
pmac_i2c_quirk_invmask = 0x00000001u,
+ pmac_i2c_quirk_skip = 0x00000002u,
};
static void pmac_i2c_devscan(void (*callback)(struct device_node *dev,
@@ -1181,6 +1174,15 @@ static void pmac_i2c_devscan(void (*callback)(struct device_node *dev,
/* XXX Study device-tree's & apple drivers are get the quirks
* right !
*/
+ /* Workaround: It seems that running the clockspreading
+ * properties on the eMac will cause lockups during boot.
+ * The machine seems to work fine without that. So for now,
+ * let's make sure i2c-hwclock doesn't match about "imic"
+ * clocks and we'll figure out if we really need to do
+ * something special about those later.
+ */
+ { "i2c-hwclock", "imic5002", pmac_i2c_quirk_skip },
+ { "i2c-hwclock", "imic5003", pmac_i2c_quirk_skip },
{ "i2c-hwclock", NULL, pmac_i2c_quirk_invmask },
{ "i2c-cpu-voltage", NULL, 0},
{ "temp-monitor", NULL, 0 },
@@ -1205,8 +1207,10 @@ static void pmac_i2c_devscan(void (*callback)(struct device_node *dev,
if (strcmp(np->name, p->name))
continue;
if (p->compatible &&
- !device_is_compatible(np, p->compatible))
+ !of_device_is_compatible(np, p->compatible))
continue;
+ if (p->quirks & pmac_i2c_quirk_skip)
+ break;
callback(np, p->quirks);
break;
}
@@ -1266,8 +1270,7 @@ static void pmac_i2c_do_end(struct pmf_function *func, void *instdata)
if (inst == NULL)
return;
pmac_i2c_close(inst->bus);
- if (inst)
- kfree(inst);
+ kfree(inst);
}
static int pmac_i2c_do_read(PMF_STD_ARGS, u32 len)
@@ -1476,7 +1479,7 @@ int __init pmac_i2c_init(void)
return 0;
}
-arch_initcall(pmac_i2c_init);
+machine_arch_initcall(powermac, pmac_i2c_init);
/* Since pmac_i2c_init can be called too early for the platform device
* registration, we need to do it at a later time. In our case, subsys
@@ -1500,6 +1503,7 @@ static int __init pmac_i2c_create_platform_devices(void)
if (bus->platform_dev == NULL)
return -ENOMEM;
bus->platform_dev->dev.platform_data = bus;
+ bus->platform_dev->dev.of_node = bus->busnode;
platform_device_add(bus->platform_dev);
}
@@ -1508,4 +1512,4 @@ static int __init pmac_i2c_create_platform_devices(void)
return 0;
}
-subsys_initcall(pmac_i2c_create_platform_devices);
+machine_subsys_initcall(powermac, pmac_i2c_create_platform_devices);
diff --git a/arch/powerpc/platforms/powermac/nvram.c b/arch/powerpc/platforms/powermac/nvram.c
index 3ebd045a335..014d06e6d46 100644
--- a/arch/powerpc/platforms/powermac/nvram.c
+++ b/arch/powerpc/platforms/powermac/nvram.c
@@ -1,6 +1,4 @@
/*
- * 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
@@ -10,14 +8,12 @@
*
* Todo: - add support for the OF persistent properties
*/
-#include <linux/config.h>
-#include <linux/module.h>
+#include <linux/export.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>
@@ -27,11 +23,12 @@
#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>
+#include "pmac.h"
+
#define DEBUG
#ifdef DEBUG
@@ -76,15 +73,12 @@ struct core99_header {
* Read and write the non-volatile RAM on PowerMacs and CHRP machines.
*/
static int nvram_naddrs;
-static volatile unsigned char *nvram_data;
+static volatile unsigned char __iomem *nvram_data;
static int is_core_99;
static int core99_bank = 0;
static int nvram_partitions[3];
// XXX Turn that into a sem
-static DEFINE_SPINLOCK(nv_lock);
-
-extern int pmac_newworld;
-extern int system_running;
+static DEFINE_RAW_SPINLOCK(nv_lock);
static int (*core99_write_bank)(int bank, u8* datas);
static int (*core99_erase_bank)(int bank);
@@ -150,7 +144,7 @@ static ssize_t core99_nvram_size(void)
}
#ifdef CONFIG_PPC32
-static volatile unsigned char *nvram_addr;
+static volatile unsigned char __iomem *nvram_addr;
static int nvram_mult;
static unsigned char direct_nvram_read_byte(int addr)
@@ -169,10 +163,10 @@ static unsigned char indirect_nvram_read_byte(int addr)
unsigned char val;
unsigned long flags;
- spin_lock_irqsave(&nv_lock, flags);
+ raw_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);
+ raw_spin_unlock_irqrestore(&nv_lock, flags);
return val;
}
@@ -181,10 +175,10 @@ static void indirect_nvram_write_byte(int addr, unsigned char val)
{
unsigned long flags;
- spin_lock_irqsave(&nv_lock, flags);
+ raw_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);
+ raw_spin_unlock_irqrestore(&nv_lock, flags);
}
@@ -199,7 +193,7 @@ static void pmu_nvram_complete(struct adb_request *req)
static unsigned char pmu_nvram_read_byte(int addr)
{
struct adb_request req;
- DECLARE_COMPLETION(req_complete);
+ DECLARE_COMPLETION_ONSTACK(req_complete);
req.arg = system_state == SYSTEM_RUNNING ? &req_complete : NULL;
if (pmu_request(&req, pmu_nvram_complete, 3, PMU_READ_NVRAM,
@@ -215,7 +209,7 @@ static unsigned char pmu_nvram_read_byte(int addr)
static void pmu_nvram_write_byte(int addr, unsigned char val)
{
struct adb_request req;
- DECLARE_COMPLETION(req_complete);
+ DECLARE_COMPLETION_ONSTACK(req_complete);
req.arg = system_state == SYSTEM_RUNNING ? &req_complete : NULL;
if (pmu_request(&req, pmu_nvram_complete, 4, PMU_WRITE_NVRAM,
@@ -284,10 +278,10 @@ static u32 core99_check(u8* datas)
static int sm_erase_bank(int bank)
{
- int stat, i;
+ int stat;
unsigned long timeout;
- u8* base = (u8 *)nvram_data + core99_bank*NVRAM_SIZE;
+ u8 __iomem *base = (u8 __iomem *)nvram_data + core99_bank*NVRAM_SIZE;
DBG("nvram: Sharp/Micron Erasing bank %d...\n", bank);
@@ -306,11 +300,10 @@ static int sm_erase_bank(int bank)
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;
- }
+ if (memchr_inv(base, 0xff, NVRAM_SIZE)) {
+ printk(KERN_ERR "nvram: Sharp/Micron flash erase failed !\n");
+ return -ENXIO;
+ }
return 0;
}
@@ -319,7 +312,7 @@ 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;
+ u8 __iomem *base = (u8 __iomem *)nvram_data + core99_bank*NVRAM_SIZE;
DBG("nvram: Sharp/Micron Writing bank %d...\n", bank);
@@ -341,20 +334,19 @@ static int sm_write_bank(int bank, u8* datas)
}
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;
- }
+ if (memcmp(base, datas, NVRAM_SIZE)) {
+ 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;
+ int stat = 0;
unsigned long timeout;
- u8* base = (u8 *)nvram_data + core99_bank*NVRAM_SIZE;
+ u8 __iomem *base = (u8 __iomem *)nvram_data + core99_bank*NVRAM_SIZE;
DBG("nvram: AMD Erasing bank %d...\n", bank);
@@ -387,12 +379,11 @@ static int amd_erase_bank(int bank)
/* 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;
- }
+
+ if (memchr_inv(base, 0xff, NVRAM_SIZE)) {
+ printk(KERN_ERR "nvram: AMD flash erase failed !\n");
+ return -ENXIO;
+ }
return 0;
}
@@ -401,7 +392,7 @@ 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;
+ u8 __iomem *base = (u8 __iomem *)nvram_data + core99_bank*NVRAM_SIZE;
DBG("nvram: AMD Writing bank %d...\n", bank);
@@ -434,11 +425,10 @@ static int amd_write_bank(int bank, u8* datas)
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;
- }
+ if (memcmp(base, datas, NVRAM_SIZE)) {
+ printk(KERN_ERR "nvram: AMD flash write failed !\n");
+ return -ENXIO;
+ }
return 0;
}
@@ -485,7 +475,7 @@ static void core99_nvram_sync(void)
if (!is_core_99 || !nvram_data || !nvram_image)
return;
- spin_lock_irqsave(&nv_lock, flags);
+ raw_spin_lock_irqsave(&nv_lock, flags);
if (!memcmp(nvram_image, (u8*)nvram_data + core99_bank*NVRAM_SIZE,
NVRAM_SIZE))
goto bail;
@@ -507,7 +497,7 @@ static void core99_nvram_sync(void)
if (core99_write_bank(core99_bank, nvram_image))
printk("nvram: Error writing bank %d\n", core99_bank);
bail:
- spin_unlock_irqrestore(&nv_lock, flags);
+ raw_spin_unlock_irqrestore(&nv_lock, flags);
#ifdef DEBUG
mdelay(2000);
@@ -557,7 +547,7 @@ static int __init core99_nvram_setup(struct device_node *dp, unsigned long addr)
* identify the chip using flash id commands and base ourselves on
* a list of known chips IDs
*/
- if (device_is_compatible(dp, "amd-0137")) {
+ if (of_device_is_compatible(dp, "amd-0137")) {
core99_erase_bank = amd_erase_bank;
core99_write_bank = amd_write_bank;
} else {
@@ -585,21 +575,21 @@ int __init pmac_nvram_init(void)
/* Try to obtain an address */
if (of_address_to_resource(dp, 0, &r1) == 0) {
nvram_naddrs = 1;
- s1 = (r1.end - r1.start) + 1;
+ s1 = resource_size(&r1);
if (of_address_to_resource(dp, 1, &r2) == 0) {
nvram_naddrs = 2;
- s2 = (r2.end - r2.start) + 1;
+ s2 = resource_size(&r2);
}
}
- is_core_99 = device_is_compatible(dp, "nvram,flash");
+ is_core_99 = of_device_is_compatible(dp, "nvram,flash");
if (is_core_99) {
err = core99_nvram_setup(dp, r1.start);
goto bail;
}
#ifdef CONFIG_PPC32
- if (_machine == _MACH_chrp && nvram_naddrs == 1) {
+ if (machine_is(chrp) && nvram_naddrs == 1) {
nvram_data = ioremap(r1.start, s1);
nvram_mult = 1;
ppc_md.nvram_read_val = direct_nvram_read_byte;
diff --git a/arch/powerpc/platforms/powermac/pci.c b/arch/powerpc/platforms/powermac/pci.c
index f671ed25390..cf7009b8c7b 100644
--- a/arch/powerpc/platforms/powermac/pci.c
+++ b/arch/powerpc/platforms/powermac/pci.c
@@ -16,6 +16,8 @@
#include <linux/string.h>
#include <linux/init.h>
#include <linux/bootmem.h>
+#include <linux/irq.h>
+#include <linux/of_pci.h>
#include <asm/sections.h>
#include <asm/io.h>
@@ -24,10 +26,7 @@
#include <asm/machdep.h>
#include <asm/pmac_feature.h>
#include <asm/grackle.h>
-#ifdef CONFIG_PPC64
-//#include <asm/iommu.h>
#include <asm/ppc-pci.h>
-#endif
#undef DEBUG
@@ -37,18 +36,15 @@
#define DBG(x...)
#endif
-static int add_bridge(struct device_node *dev);
-
/* 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_PPC64
static struct pci_controller *u3_agp;
-static struct pci_controller *u4_pcie;
-static struct pci_controller *u3_ht;
+#else
+static int has_second_ohare;
#endif /* CONFIG_PPC64 */
-extern u8 pci_cache_line_size;
extern int pcibios_assign_bus_offset;
struct device_node *k2_skiplist[2];
@@ -66,16 +62,16 @@ struct device_node *k2_skiplist[2];
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;
+ const int * bus_range;
+ const 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);
+ class_code = of_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);
+ bus_range = of_get_property(node, "bus-range", &len);
if (bus_range != NULL && len > 2 * sizeof(int)) {
if (bus_range[1] > higher)
higher = bus_range[1];
@@ -93,13 +89,15 @@ static int __init fixup_one_level_bus_range(struct device_node *node, int higher
*/
static void __init fixup_bus_range(struct device_node *bridge)
{
- int * bus_range;
- int len;
+ int *bus_range, len;
+ struct property *prop;
/* 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))
+ prop = of_find_property(bridge, "bus-range", &len);
+ if (prop == NULL || prop->length < 2 * sizeof(int))
return;
+
+ bus_range = prop->value;
bus_range[1] = fixup_one_level_bus_range(bridge->child, bus_range[1]);
}
@@ -136,14 +134,14 @@ static void __init fixup_bus_range(struct device_node *bridge)
|(((unsigned int)(off)) & 0xFCUL) \
|1UL)
-static unsigned long macrisc_cfg_access(struct pci_controller* hose,
+static volatile void __iomem *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;
+ return NULL;
caddr = MACRISC_CFA0(dev_fn, offset);
} else
caddr = MACRISC_CFA1(bus, dev_fn, offset);
@@ -154,14 +152,14 @@ static unsigned long macrisc_cfg_access(struct pci_controller* hose,
} while (in_le32(hose->cfg_addr) != caddr);
offset &= has_uninorth ? 0x07 : 0x03;
- return ((unsigned long)hose->cfg_data) + offset;
+ return 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;
- unsigned long addr;
+ volatile void __iomem *addr;
hose = pci_bus_to_host(bus);
if (hose == NULL)
@@ -177,13 +175,13 @@ static int macrisc_read_config(struct pci_bus *bus, unsigned int devfn,
*/
switch (len) {
case 1:
- *val = in_8((u8 *)addr);
+ *val = in_8(addr);
break;
case 2:
- *val = in_le16((u16 *)addr);
+ *val = in_le16(addr);
break;
default:
- *val = in_le32((u32 *)addr);
+ *val = in_le32(addr);
break;
}
return PCIBIOS_SUCCESSFUL;
@@ -193,7 +191,7 @@ static int macrisc_write_config(struct pci_bus *bus, unsigned int devfn,
int offset, int len, u32 val)
{
struct pci_controller *hose;
- unsigned long addr;
+ volatile void __iomem *addr;
hose = pci_bus_to_host(bus);
if (hose == NULL)
@@ -209,16 +207,13 @@ static int macrisc_write_config(struct pci_bus *bus, unsigned int devfn,
*/
switch (len) {
case 1:
- out_8((u8 *)addr, val);
- (void) in_8((u8 *)addr);
+ out_8(addr, val);
break;
case 2:
- out_le16((u16 *)addr, val);
- (void) in_le16((u16 *)addr);
+ out_le16(addr, val);
break;
default:
- out_le32((u32 *)addr, val);
- (void) in_le32((u32 *)addr);
+ out_le32(addr, val);
break;
}
return PCIBIOS_SUCCESSFUL;
@@ -226,8 +221,8 @@ static int macrisc_write_config(struct pci_bus *bus, unsigned int devfn,
static struct pci_ops macrisc_pci_ops =
{
- macrisc_read_config,
- macrisc_write_config
+ .read = macrisc_read_config,
+ .write = macrisc_write_config,
};
#ifdef CONFIG_PPC32
@@ -237,16 +232,16 @@ static struct pci_ops macrisc_pci_ops =
static int chaos_validate_dev(struct pci_bus *bus, int devfn, int offset)
{
struct device_node *np;
- u32 *vendor, *device;
+ const u32 *vendor, *device;
if (offset >= 0x100)
return PCIBIOS_BAD_REGISTER_NUMBER;
- np = pci_busdev_to_OF_node(bus, devfn);
+ np = of_pci_find_child_device(bus->dev.of_node, 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);
+ vendor = of_get_property(np, "vendor-id", NULL);
+ device = of_get_property(np, "device-id", NULL);
if (vendor == NULL || device == NULL)
return PCIBIOS_DEVICE_NOT_FOUND;
@@ -281,8 +276,8 @@ chaos_write_config(struct pci_bus *bus, unsigned int devfn, int offset,
static struct pci_ops chaos_pci_ops =
{
- chaos_read_config,
- chaos_write_config
+ .read = chaos_read_config,
+ .write = chaos_write_config,
};
static void __init setup_chaos(struct pci_controller *hose,
@@ -305,10 +300,10 @@ static void __init setup_chaos(struct pci_controller *hose,
* This function deals with some "special cases" devices.
*
* 0 -> No special case
- * 1 -> Skip the device but act as if the access was successfull
+ * 1 -> Skip the device but act as if the access was successful
* (return 0xff's on reads, eventually, cache config space
* accesses in a later version)
- * -1 -> Hide the device (unsuccessful acess)
+ * -1 -> Hide the device (unsuccessful access)
*/
static int u3_ht_skip_device(struct pci_controller *hose,
struct pci_bus *bus, unsigned int devfn)
@@ -318,12 +313,15 @@ static int u3_ht_skip_device(struct pci_controller *hose,
/* 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
+ * revs of K2 on recent G5s, except for the host bridge itself, which
+ * is missing from the tree but we know we can probe.
*/
if (bus->self)
busdn = pci_device_to_OF_node(bus->self);
+ else if (devfn == 0)
+ return 0;
else
- busdn = hose->arch_data;
+ busdn = hose->dn;
for (dn = busdn->child; dn; dn = dn->sibling)
if (PCI_DN(dn) && PCI_DN(dn)->devfn == devfn)
break;
@@ -348,32 +346,32 @@ static int u3_ht_skip_device(struct pci_controller *hose,
+ (((unsigned int)bus) << 16) \
+ 0x01000000UL)
-static unsigned long u3_ht_cfg_access(struct pci_controller* hose,
- u8 bus, u8 devfn, u8 offset)
+static void __iomem *u3_ht_cfg_access(struct pci_controller *hose, u8 bus,
+ u8 devfn, u8 offset, int *swap)
{
+ *swap = 1;
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);
+ if (devfn != 0)
+ return hose->cfg_data + U3_HT_CFA0(devfn, offset);
+ *swap = 0;
+ return ((void __iomem *)hose->cfg_addr) + (offset << 2);
} else
- return ((unsigned long)hose->cfg_data) +
- U3_HT_CFA1(bus, devfn, offset);
+ return 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;
- unsigned long addr;
+ void __iomem *addr;
+ int swap;
hose = pci_bus_to_host(bus);
if (hose == NULL)
return PCIBIOS_DEVICE_NOT_FOUND;
if (offset >= 0x100)
return PCIBIOS_BAD_REGISTER_NUMBER;
- addr = u3_ht_cfg_access(hose, bus->number, devfn, offset);
+ addr = u3_ht_cfg_access(hose, bus->number, devfn, offset, &swap);
if (!addr)
return PCIBIOS_DEVICE_NOT_FOUND;
@@ -400,13 +398,13 @@ static int u3_ht_read_config(struct pci_bus *bus, unsigned int devfn,
*/
switch (len) {
case 1:
- *val = in_8((u8 *)addr);
+ *val = in_8(addr);
break;
case 2:
- *val = in_le16((u16 *)addr);
+ *val = swap ? in_le16(addr) : in_be16(addr);
break;
default:
- *val = in_le32((u32 *)addr);
+ *val = swap ? in_le32(addr) : in_be32(addr);
break;
}
return PCIBIOS_SUCCESSFUL;
@@ -416,14 +414,15 @@ static int u3_ht_write_config(struct pci_bus *bus, unsigned int devfn,
int offset, int len, u32 val)
{
struct pci_controller *hose;
- unsigned long addr;
+ void __iomem *addr;
+ int swap;
hose = pci_bus_to_host(bus);
if (hose == NULL)
return PCIBIOS_DEVICE_NOT_FOUND;
if (offset >= 0x100)
return PCIBIOS_BAD_REGISTER_NUMBER;
- addr = u3_ht_cfg_access(hose, bus->number, devfn, offset);
+ addr = u3_ht_cfg_access(hose, bus->number, devfn, offset, &swap);
if (!addr)
return PCIBIOS_DEVICE_NOT_FOUND;
@@ -442,16 +441,13 @@ static int u3_ht_write_config(struct pci_bus *bus, unsigned int devfn,
*/
switch (len) {
case 1:
- out_8((u8 *)addr, val);
- (void) in_8((u8 *)addr);
+ out_8(addr, val);
break;
case 2:
- out_le16((u16 *)addr, val);
- (void) in_le16((u16 *)addr);
+ swap ? out_le16(addr, val) : out_be16(addr, val);
break;
default:
- out_le32((u32 *)addr, val);
- (void) in_le32((u32 *)addr);
+ swap ? out_le32(addr, val) : out_be32(addr, val);
break;
}
return PCIBIOS_SUCCESSFUL;
@@ -459,8 +455,8 @@ static int u3_ht_write_config(struct pci_bus *bus, unsigned int devfn,
static struct pci_ops u3_ht_pci_ops =
{
- u3_ht_read_config,
- u3_ht_write_config
+ .read = u3_ht_read_config,
+ .write = u3_ht_write_config,
};
#define U4_PCIE_CFA0(devfn, off) \
@@ -476,7 +472,7 @@ static struct pci_ops u3_ht_pci_ops =
|(((unsigned int)(off)) & 0xfcU) \
|1UL)
-static unsigned long u4_pcie_cfg_access(struct pci_controller* hose,
+static volatile void __iomem *u4_pcie_cfg_access(struct pci_controller* hose,
u8 bus, u8 dev_fn, int offset)
{
unsigned int caddr;
@@ -492,14 +488,14 @@ static unsigned long u4_pcie_cfg_access(struct pci_controller* hose,
} while (in_le32(hose->cfg_addr) != caddr);
offset &= 0x03;
- return ((unsigned long)hose->cfg_data) + offset;
+ return hose->cfg_data + offset;
}
static int u4_pcie_read_config(struct pci_bus *bus, unsigned int devfn,
int offset, int len, u32 *val)
{
struct pci_controller *hose;
- unsigned long addr;
+ volatile void __iomem *addr;
hose = pci_bus_to_host(bus);
if (hose == NULL)
@@ -515,13 +511,13 @@ static int u4_pcie_read_config(struct pci_bus *bus, unsigned int devfn,
*/
switch (len) {
case 1:
- *val = in_8((u8 *)addr);
+ *val = in_8(addr);
break;
case 2:
- *val = in_le16((u16 *)addr);
+ *val = in_le16(addr);
break;
default:
- *val = in_le32((u32 *)addr);
+ *val = in_le32(addr);
break;
}
return PCIBIOS_SUCCESSFUL;
@@ -531,7 +527,7 @@ static int u4_pcie_write_config(struct pci_bus *bus, unsigned int devfn,
int offset, int len, u32 val)
{
struct pci_controller *hose;
- unsigned long addr;
+ volatile void __iomem *addr;
hose = pci_bus_to_host(bus);
if (hose == NULL)
@@ -547,16 +543,13 @@ static int u4_pcie_write_config(struct pci_bus *bus, unsigned int devfn,
*/
switch (len) {
case 1:
- out_8((u8 *)addr, val);
- (void) in_8((u8 *)addr);
+ out_8(addr, val);
break;
case 2:
- out_le16((u16 *)addr, val);
- (void) in_le16((u16 *)addr);
+ out_le16(addr, val);
break;
default:
- out_le32((u32 *)addr, val);
- (void) in_le32((u32 *)addr);
+ out_le32(addr, val);
break;
}
return PCIBIOS_SUCCESSFUL;
@@ -564,10 +557,24 @@ static int u4_pcie_write_config(struct pci_bus *bus, unsigned int devfn,
static struct pci_ops u4_pcie_pci_ops =
{
- u4_pcie_read_config,
- u4_pcie_write_config
+ .read = u4_pcie_read_config,
+ .write = u4_pcie_write_config,
};
+static void pmac_pci_fixup_u4_of_node(struct pci_dev *dev)
+{
+ /* Apple's device-tree "hides" the root complex virtual P2P bridge
+ * on U4. However, Linux sees it, causing the PCI <-> OF matching
+ * code to fail to properly match devices below it. This works around
+ * it by setting the node of the bridge to point to the PHB node,
+ * which is not entirely correct but fixes the matching code and
+ * doesn't break anything else. It's also the simplest possible fix.
+ */
+ if (dev->dev.of_node == NULL)
+ dev->dev.of_node = pcibios_get_phb_of_node(dev->bus);
+}
+DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_APPLE, 0x5b, pmac_pci_fixup_u4_of_node);
+
#endif /* CONFIG_PPC64 */
#ifdef CONFIG_PPC32
@@ -623,13 +630,14 @@ static void __init init_p2pbridge(void)
/* XXX it would be better here to identify the specific
PCI-PCI bridge chip we have. */
- if ((p2pbridge = find_devices("pci-bridge")) == 0
+ p2pbridge = of_find_node_by_name(NULL, "pci-bridge");
+ if (p2pbridge == NULL
|| p2pbridge->parent == NULL
|| strcmp(p2pbridge->parent->name, "pci") != 0)
- return;
+ goto done;
if (pci_device_from_OF_node(p2pbridge, &bus, &devfn) < 0) {
DBG("Can't find PCI infos for PCI<->PCI bridge\n");
- return;
+ goto done;
}
/* Warning: At this point, we have not yet renumbered all busses.
* So we must use OF walking to find out hose
@@ -637,16 +645,47 @@ static void __init init_p2pbridge(void)
hose = pci_find_hose_for_OF_device(p2pbridge);
if (!hose) {
DBG("Can't find hose for PCI<->PCI bridge\n");
- return;
+ goto done;
}
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;
+ goto done;
}
val &= ~PCI_BRIDGE_CTL_MASTER_ABORT;
early_write_config_word(hose, bus, devfn, PCI_BRIDGE_CONTROL, val);
+done:
+ of_node_put(p2pbridge);
+}
+
+static void __init init_second_ohare(void)
+{
+ struct device_node *np = of_find_node_by_name(NULL, "pci106b,7");
+ unsigned char bus, devfn;
+ unsigned short cmd;
+
+ if (np == NULL)
+ return;
+
+ /* This must run before we initialize the PICs since the second
+ * ohare hosts a PIC that will be accessed there.
+ */
+ if (pci_device_from_OF_node(np, &bus, &devfn) == 0) {
+ struct pci_controller* hose =
+ pci_find_hose_for_OF_device(np);
+ if (!hose) {
+ printk(KERN_ERR "Can't find PCI hose for OHare2 !\n");
+ of_node_put(np);
+ return;
+ }
+ 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);
+ }
+ has_second_ohare = 1;
+ of_node_put(np);
}
/*
@@ -661,20 +700,21 @@ static void __init fixup_nec_usb2(void)
for (nec = NULL; (nec = of_find_node_by_name(nec, "usb")) != NULL;) {
struct pci_controller *hose;
- u32 data, *prop;
+ u32 data;
+ const u32 *prop;
u8 bus, devfn;
- prop = (u32 *)get_property(nec, "vendor-id", NULL);
+ prop = of_get_property(nec, "vendor-id", NULL);
if (prop == NULL)
continue;
if (0x1033 != *prop)
continue;
- prop = (u32 *)get_property(nec, "device-id", NULL);
+ prop = of_get_property(nec, "device-id", NULL);
if (prop == NULL)
continue;
if (0x0035 != *prop)
continue;
- prop = (u32 *)get_property(nec, "reg", NULL);
+ prop = of_get_property(nec, "reg", NULL);
if (prop == NULL)
continue;
devfn = (prop[0] >> 8) & 0xff;
@@ -690,9 +730,6 @@ static void __init fixup_nec_usb2(void)
" 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);
}
}
}
@@ -709,7 +746,7 @@ static void __init setup_bandit(struct pci_controller *hose,
static int __init setup_uninorth(struct pci_controller *hose,
struct resource *addr)
{
- pci_assign_all_buses = 1;
+ pci_add_flags(PCI_REASSIGN_ALL_BUS);
has_uninorth = 1;
hose->ops = &macrisc_pci_ops;
hose->cfg_addr = ioremap(addr->start + 0x800000, 0x1000);
@@ -757,32 +794,72 @@ static void __init setup_u4_pcie(struct pci_controller* hose)
*/
hose->first_busno = 0x00;
hose->last_busno = 0xff;
- u4_pcie = hose;
}
-static void __init setup_u3_ht(struct pci_controller* hose)
+static void __init parse_region_decode(struct pci_controller *hose,
+ u32 decode)
{
- struct device_node *np = (struct device_node *)hose->arch_data;
- struct pci_controller *other = NULL;
- int i, cur;
+ unsigned long base, end, next = -1;
+ int i, cur = -1;
+ /* Iterate through all bits. We ignore the last bit as this region is
+ * reserved for the ROM among other niceties
+ */
+ for (i = 0; i < 31; i++) {
+ if ((decode & (0x80000000 >> i)) == 0)
+ continue;
+ if (i < 16) {
+ base = 0xf0000000 | (((u32)i) << 24);
+ end = base + 0x00ffffff;
+ } else {
+ base = ((u32)i-16) << 28;
+ end = base + 0x0fffffff;
+ }
+ if (base != next) {
+ if (++cur >= 3) {
+ printk(KERN_WARNING "PCI: Too many ranges !\n");
+ break;
+ }
+ hose->mem_resources[cur].flags = IORESOURCE_MEM;
+ hose->mem_resources[cur].name = hose->dn->full_name;
+ hose->mem_resources[cur].start = base;
+ hose->mem_resources[cur].end = end;
+ hose->mem_offset[cur] = 0;
+ DBG(" %d: 0x%08lx-0x%08lx\n", cur, base, end);
+ } else {
+ DBG(" : -0x%08lx\n", end);
+ hose->mem_resources[cur].end = end;
+ }
+ next = end + 1;
+ }
+}
+
+static void __init setup_u3_ht(struct pci_controller* hose)
+{
+ struct device_node *np = hose->dn;
+ struct resource cfg_res, self_res;
+ u32 decode;
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
+ /* Get base addresses from OF tree
+ */
+ if (of_address_to_resource(np, 0, &cfg_res) ||
+ of_address_to_resource(np, 1, &self_res)) {
+ printk(KERN_ERR "PCI: Failed to get U3/U4 HT resources !\n");
+ return;
+ }
+
+ /* Map external cfg space access into cfg_data and self registers
+ * into cfg_addr
*/
- hose->cfg_data = (volatile unsigned char *)ioremap(0xf2000000,
- 0x02000000);
+ hose->cfg_data = ioremap(cfg_res.start, 0x02000000);
+ hose->cfg_addr = ioremap(self_res.start, resource_size(&self_res));
/*
- * /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).
+ * /ht node doesn't expose a "ranges" property, we read the register
+ * that controls the decoding logic and use that for memory regions.
+ * The IO region is hard coded since it is fixed in HW as well.
*/
hose->io_base_phys = 0xf4000000;
hose->pci_io_size = 0x00400000;
@@ -790,79 +867,35 @@ static void __init setup_u3_ht(struct pci_controller* hose)
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;
-
- u3_ht = hose;
-
- if (u3_agp != NULL)
- other = u3_agp;
- else if (u4_pcie != NULL)
- other = u4_pcie;
- if (other == NULL) {
- DBG("U3/4 has no AGP/PCIE, using full resource range\n");
- return;
- }
+ /* Note: fix offset when cfg_addr becomes a void * */
+ decode = in_be32(hose->cfg_addr + 0x80);
- /* Fixup bus range vs. PCIE */
- if (u4_pcie)
- hose->last_busno = u4_pcie->first_busno - 1;
+ DBG("PCI: Apple HT bridge decode register: 0x%08x\n", decode);
- /* 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
+ /* NOTE: The decode register setup is a bit weird... region
+ * 0xf8000000 for example is marked as enabled in there while it's
+ & actually the memory controller registers.
+ * That means that we are incorrectly attributing it to HT.
+ *
+ * In a similar vein, region 0xf4000000 is actually the HT IO space but
+ * also marked as enabled in here and 0xf9000000 is used by some other
+ * internal bits of the northbridge.
+ *
+ * Unfortunately, we can't just mask out those bit as we would end
+ * up with more regions than we can cope (linux can only cope with
+ * 3 memory regions for a PHB at this stage).
+ *
+ * So for now, we just do a little hack. We happen to -know- that
+ * Apple firmware doesn't assign things below 0xfa000000 for that
+ * bridge anyway so we mask out all bits we don't want.
*/
- cur = 0;
- for (i=0; i<3; i++) {
- struct resource *res = &other->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 for 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;
- }
+ decode &= 0x003fffff;
+
+ /* Now parse the resulting bits and build resources */
+ parse_region_decode(hose, decode);
}
#endif /* CONFIG_PPC64 */
@@ -871,13 +904,13 @@ static void __init setup_u3_ht(struct pci_controller* hose)
* "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)
+static int __init pmac_add_bridge(struct device_node *dev)
{
int len;
struct pci_controller *hose;
struct resource rsrc;
char *disp_name;
- int *bus_range;
+ const int *bus_range;
int primary = 1, has_address = 0;
DBG("Adding PCI host bridge %s\n", dev->full_name);
@@ -886,21 +919,15 @@ static int __init add_bridge(struct device_node *dev)
has_address = (of_address_to_resource(dev, 0, &rsrc) == 0);
/* Get bus range if any */
- bus_range = (int *) get_property(dev, "bus-range", &len);
+ bus_range = of_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);
}
- /* XXX Different prototypes, to be merged */
-#ifdef CONFIG_PPC64
hose = pcibios_alloc_controller(dev);
-#else
- hose = pcibios_alloc_controller();
-#endif
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;
@@ -908,15 +935,15 @@ static int __init add_bridge(struct device_node *dev)
/* 64 bits only bridges */
#ifdef CONFIG_PPC64
- if (device_is_compatible(dev, "u3-agp")) {
+ if (of_device_is_compatible(dev, "u3-agp")) {
setup_u3_agp(hose);
disp_name = "U3-AGP";
primary = 0;
- } else if (device_is_compatible(dev, "u3-ht")) {
+ } else if (of_device_is_compatible(dev, "u3-ht")) {
setup_u3_ht(hose);
disp_name = "U3-HT";
primary = 1;
- } else if (device_is_compatible(dev, "u4-pcie")) {
+ } else if (of_device_is_compatible(dev, "u4-pcie")) {
setup_u4_pcie(hose);
disp_name = "U4-PCIE";
primary = 0;
@@ -927,7 +954,7 @@ static int __init add_bridge(struct device_node *dev)
/* 32 bits only bridges */
#ifdef CONFIG_PPC32
- if (device_is_compatible(dev, "uni-north")) {
+ if (of_device_is_compatible(dev, "uni-north")) {
primary = setup_uninorth(hose, &rsrc);
disp_name = "UniNorth";
} else if (strcmp(dev->name, "pci") == 0) {
@@ -942,9 +969,10 @@ static int __init add_bridge(struct device_node *dev)
disp_name = "Chaos";
primary = 0;
}
- printk(KERN_INFO "Found %s PCI host bridge at 0x%08lx. "
+ printk(KERN_INFO "Found %s PCI host bridge at 0x%016llx. "
"Firmware bus number: %d->%d\n",
- disp_name, rsrc.start, hose->first_busno, hose->last_busno);
+ disp_name, (unsigned long long)rsrc.start, hose->first_busno,
+ hose->last_busno);
#endif /* CONFIG_PPC32 */
DBG(" ->Hose at 0x%p, cfg_addr=0x%p,cfg_data=0x%p\n",
@@ -960,50 +988,32 @@ static int __init add_bridge(struct device_node *dev)
return 0;
}
-static void __init pcibios_fixup_OF_interrupts(void)
+void pmac_pci_irq_fixup(struct pci_dev *dev)
{
- 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
+#ifdef CONFIG_PPC32
+ /* Fixup interrupt for the modem/ethernet combo controller.
+ * on machines with a second ohare chip.
+ * 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.
*/
- 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();
-}
-
-#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) {
- printk(KERN_INFO "PCI Host %d, io start: %lx; io end: %lx\n",
- hose->global_number,
- hose->io_resource.start, hose->io_resource.end);
+ if (has_second_ohare &&
+ dev->vendor == PCI_VENDOR_ID_DEC &&
+ dev->device == PCI_DEVICE_ID_DEC_TULIP_PLUS) {
+ dev->irq = irq_create_mapping(NULL, 60);
+ irq_set_irq_type(dev->irq, IRQ_TYPE_LEVEL_LOW);
}
+#endif /* CONFIG_PPC32 */
}
-#endif
void __init pmac_pci_init(void)
{
struct device_node *np, *root;
struct device_node *ht = NULL;
+ pci_set_flags(PCI_CAN_SKIP_ISA_ALIGN);
+
root = of_find_node_by_path("/");
if (root == NULL) {
printk(KERN_CRIT "pmac_pci_init: can't find root "
@@ -1016,7 +1026,7 @@ void __init pmac_pci_init(void)
if (strcmp(np->name, "bandit") == 0
|| strcmp(np->name, "chaos") == 0
|| strcmp(np->name, "pci") == 0) {
- if (add_bridge(np) == 0)
+ if (pmac_add_bridge(np) == 0)
of_node_get(np);
}
if (strcmp(np->name, "ht") == 0) {
@@ -1030,28 +1040,9 @@ void __init pmac_pci_init(void)
/* Probe HT last as it relies on the agp resources to be already
* setup
*/
- if (ht && add_bridge(ht) != 0)
+ if (ht && pmac_add_bridge(ht) != 0)
of_node_put(ht);
- /*
- * We need to call pci_setup_phb_io for the HT bridge first
- * so it gets the I/O port numbers starting at 0, and we
- * need to call it for the AGP bridge after that so it gets
- * small positive I/O port numbers.
- */
- if (u3_ht)
- pci_setup_phb_io(u3_ht, 1);
- if (u3_agp)
- pci_setup_phb_io(u3_agp, 0);
- if (u4_pcie)
- pci_setup_phb_io(u4_pcie, 0);
-
- /*
- * On ppc64, fixup the IO resources on our host bridges as
- * the common code does it only for children of the host bridges
- */
- pmac_fixup_phb_resources();
-
/* Setup the linkage between OF nodes and PHBs */
pci_devs_phb_init();
@@ -1061,34 +1052,29 @@ void __init pmac_pci_init(void)
* future though
*/
if (u3_agp) {
- struct device_node *np = u3_agp->arch_data;
+ struct device_node *np = u3_agp->dn;
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 mechanism */
- pci_probe_only = 1;
-
- /* Allow all IO */
- io_page_mask = -1;
-
#else /* CONFIG_PPC64 */
init_p2pbridge();
+ init_second_ohare();
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_buses)
+ if (pci_has_flag(PCI_REASSIGN_ALL_BUS))
pcibios_assign_bus_offset = 0x10;
#endif
}
-int
-pmac_pci_enable_device_hook(struct pci_dev *dev, int initial)
+#ifdef CONFIG_PPC32
+int pmac_pci_enable_device_hook(struct pci_dev *dev)
{
struct device_node* node;
int updatecfg = 0;
@@ -1100,7 +1086,7 @@ pmac_pci_enable_device_hook(struct pci_dev *dev, int initial)
* (iBook second controller)
*/
if (dev->vendor == PCI_VENDOR_ID_APPLE
- && (dev->class == ((PCI_CLASS_SERIAL_USB << 8) | 0x10))
+ && dev->class == PCI_CLASS_SERIAL_USB_OHCI
&& !node) {
printk(KERN_INFO "Apple USB OHCI %s disabled by firmware\n",
pci_name(dev));
@@ -1111,43 +1097,40 @@ pmac_pci_enable_device_hook(struct pci_dev *dev, int initial)
return 0;
uninorth_child = node->parent &&
- device_is_compatible(node->parent, "uni-north");
+ of_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"))) {
+ (of_device_is_compatible(node, "pci106b,18") ||
+ of_device_is_compatible(node, "pci106b,30") ||
+ of_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")) {
+ of_device_is_compatible(node, "gmac")) {
pmac_call_feature(PMAC_FTR_GMAC_ENABLE, node, 0, 1);
updatecfg = 1;
}
+ /*
+ * Fixup various header fields on 32 bits. We don't do that on
+ * 64 bits as some of these have strange values behind the HT
+ * bridge and we must not, for example, enable MWI or set the
+ * cache line size on them.
+ */
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,
L1_CACHE_BYTES >> 2);
}
@@ -1155,6 +1138,18 @@ pmac_pci_enable_device_hook(struct pci_dev *dev, int initial)
return 0;
}
+void pmac_pci_fixup_ohci(struct pci_dev *dev)
+{
+ struct device_node *node = pci_device_to_OF_node(dev);
+
+ /* We don't want to assign resources to USB controllers
+ * absent from the OF tree (iBook second controller)
+ */
+ if (dev->class == PCI_CLASS_SERIAL_USB_OHCI && !node)
+ dev->resource[0].flags = 0;
+}
+DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_APPLE, PCI_ANY_ID, pmac_pci_fixup_ohci);
+
/* We power down some devices after they have been probed. They'll
* be powered back on later on
*/
@@ -1162,49 +1157,25 @@ 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")) {
+ for_each_node_by_name(nd, "firewire") {
+ if (nd->parent && (of_device_is_compatible(nd, "pci106b,18") ||
+ of_device_is_compatible(nd, "pci106b,30") ||
+ of_device_is_compatible(nd, "pci11c1,5811"))
+ && of_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"))
+ for_each_node_by_name(nd, "ethernet") {
+ if (nd->parent && of_device_is_compatible(nd, "gmac")
+ && of_device_is_compatible(nd->parent, "uni-north"))
pmac_call_feature(PMAC_FTR_GMAC_ENABLE, nd, 0, 0);
- nd = nd->next;
}
}
-#ifdef CONFIG_PPC32
void pmac_pci_fixup_cardbus(struct pci_dev* dev)
{
- if (_machine != _MACH_Pmac)
+ if (!machine_is(powermac))
return;
/*
* Fix the interrupt routing on the various cardbus bridges
@@ -1247,8 +1218,9 @@ void pmac_pci_fixup_pciata(struct pci_dev* dev)
* On PowerMacs, we try to switch any PCI ATA controller to
* fully native mode
*/
- if (_machine != _MACH_Pmac)
+ if (!machine_is(powermac))
return;
+
/* Some controllers don't have the class IDE */
if (dev->vendor == PCI_VENDOR_ID_PROMISE)
switch(dev->device) {
@@ -1272,16 +1244,23 @@ void pmac_pci_fixup_pciata(struct pci_dev* dev)
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",
+ printk(KERN_INFO "PCI: %s Forcing PCI IDE into native mode\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");
+ else {
+ /* Clear IO BARs, they will be reassigned */
+ pci_write_config_dword(dev, PCI_BASE_ADDRESS_0, 0);
+ pci_write_config_dword(dev, PCI_BASE_ADDRESS_1, 0);
+ pci_write_config_dword(dev, PCI_BASE_ADDRESS_2, 0);
+ pci_write_config_dword(dev, PCI_BASE_ADDRESS_3, 0);
+ }
}
}
-DECLARE_PCI_FIXUP_FINAL(PCI_ANY_ID, PCI_ANY_ID, pmac_pci_fixup_pciata);
-#endif
+DECLARE_PCI_FIXUP_EARLY(PCI_ANY_ID, PCI_ANY_ID, pmac_pci_fixup_pciata);
+#endif /* CONFIG_PPC32 */
/*
* Disable second function on K2-SATA, it's broken
@@ -1316,3 +1295,63 @@ static void fixup_k2_sata(struct pci_dev* dev)
}
DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_SERVERWORKS, 0x0240, fixup_k2_sata);
+/*
+ * On U4 (aka CPC945) the PCIe root complex "P2P" bridge resource ranges aren't
+ * configured by the firmware. The bridge itself seems to ignore them but it
+ * causes problems with Linux which then re-assigns devices below the bridge,
+ * thus changing addresses of those devices from what was in the device-tree,
+ * which sucks when those are video cards using offb
+ *
+ * We could just mark it transparent but I prefer fixing up the resources to
+ * properly show what's going on here, as I have some doubts about having them
+ * badly configured potentially being an issue for DMA.
+ *
+ * We leave PIO alone, it seems to be fine
+ *
+ * Oh and there's another funny bug. The OF properties advertize the region
+ * 0xf1000000..0xf1ffffff as being forwarded as memory space. But that's
+ * actually not true, this region is the memory mapped config space. So we
+ * also need to filter it out or we'll map things in the wrong place.
+ */
+static void fixup_u4_pcie(struct pci_dev* dev)
+{
+ struct pci_controller *host = pci_bus_to_host(dev->bus);
+ struct resource *region = NULL;
+ u32 reg;
+ int i;
+
+ /* Only do that on PowerMac */
+ if (!machine_is(powermac))
+ return;
+
+ /* Find the largest MMIO region */
+ for (i = 0; i < 3; i++) {
+ struct resource *r = &host->mem_resources[i];
+ if (!(r->flags & IORESOURCE_MEM))
+ continue;
+ /* Skip the 0xf0xxxxxx..f2xxxxxx regions, we know they
+ * are reserved by HW for other things
+ */
+ if (r->start >= 0xf0000000 && r->start < 0xf3000000)
+ continue;
+ if (!region || resource_size(r) > resource_size(region))
+ region = r;
+ }
+ /* Nothing found, bail */
+ if (region == 0)
+ return;
+
+ /* Print things out */
+ printk(KERN_INFO "PCI: Fixup U4 PCIe bridge range: %pR\n", region);
+
+ /* Fixup bridge config space. We know it's a Mac, resource aren't
+ * offset so let's just blast them as-is. We also know that they
+ * fit in 32 bits
+ */
+ reg = ((region->start >> 16) & 0xfff0) | (region->end & 0xfff00000);
+ pci_write_config_dword(dev, PCI_MEMORY_BASE, reg);
+ pci_write_config_dword(dev, PCI_PREF_BASE_UPPER32, 0);
+ pci_write_config_dword(dev, PCI_PREF_LIMIT_UPPER32, 0);
+ pci_write_config_dword(dev, PCI_PREF_MEMORY_BASE, 0);
+}
+DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_APPLE, PCI_DEVICE_ID_APPLE_U4_PCIE, fixup_u4_pcie);
diff --git a/arch/powerpc/platforms/powermac/pfunc_base.c b/arch/powerpc/platforms/powermac/pfunc_base.c
index 4ffd2a9832a..e49d07f3d54 100644
--- a/arch/powerpc/platforms/powermac/pfunc_base.c
+++ b/arch/powerpc/platforms/powermac/pfunc_base.c
@@ -1,17 +1,22 @@
-#include <linux/config.h>
#include <linux/types.h>
#include <linux/init.h>
#include <linux/delay.h>
#include <linux/kernel.h>
#include <linux/interrupt.h>
#include <linux/spinlock.h>
+#include <linux/of_irq.h>
#include <asm/pmac_feature.h>
#include <asm/pmac_pfunc.h>
+#undef DEBUG
+#ifdef DEBUG
#define DBG(fmt...) printk(fmt)
+#else
+#define DBG(fmt...)
+#endif
-static irqreturn_t macio_gpio_irq(int irq, void *data, struct pt_regs *regs)
+static irqreturn_t macio_gpio_irq(int irq, void *data)
{
pmf_do_irq(data);
@@ -20,19 +25,18 @@ static irqreturn_t macio_gpio_irq(int irq, void *data, struct pt_regs *regs)
static int macio_do_gpio_irq_enable(struct pmf_function *func)
{
- if (func->node->n_intrs < 1)
+ unsigned int irq = irq_of_parse_and_map(func->node, 0);
+ if (irq == NO_IRQ)
return -EINVAL;
-
- return request_irq(func->node->intrs[0].line, macio_gpio_irq, 0,
- func->node->name, func);
+ return request_irq(irq, macio_gpio_irq, 0, func->node->name, func);
}
static int macio_do_gpio_irq_disable(struct pmf_function *func)
{
- if (func->node->n_intrs < 1)
+ unsigned int irq = irq_of_parse_and_map(func->node, 0);
+ if (irq == NO_IRQ)
return -EINVAL;
-
- free_irq(func->node->intrs[0].line, func);
+ free_irq(irq, func);
return 0;
}
@@ -47,13 +51,13 @@ static int macio_do_gpio_write(PMF_STD_ARGS, u8 value, u8 mask)
value = ~value;
/* Toggle the GPIO */
- spin_lock_irqsave(&feature_lock, flags);
+ raw_spin_lock_irqsave(&feature_lock, flags);
tmp = readb(addr);
tmp = (tmp & ~mask) | (value & mask);
DBG("Do write 0x%02x to GPIO %s (%p)\n",
tmp, func->node->full_name, addr);
writeb(tmp, addr);
- spin_unlock_irqrestore(&feature_lock, flags);
+ raw_spin_unlock_irqrestore(&feature_lock, flags);
return 0;
}
@@ -111,7 +115,7 @@ static void macio_gpio_init_one(struct macio_chip *macio)
* we just create them all
*/
for (gp = NULL; (gp = of_get_next_child(gparent, gp)) != NULL;) {
- u32 *reg = (u32 *)get_property(gp, "reg", NULL);
+ const u32 *reg = of_get_property(gp, "reg", NULL);
unsigned long offset;
if (reg == NULL)
continue;
@@ -142,9 +146,9 @@ static int macio_do_write_reg32(PMF_STD_ARGS, u32 offset, u32 value, u32 mask)
struct macio_chip *macio = func->driver_data;
unsigned long flags;
- spin_lock_irqsave(&feature_lock, flags);
+ raw_spin_lock_irqsave(&feature_lock, flags);
MACIO_OUT32(offset, (MACIO_IN32(offset) & ~mask) | (value & mask));
- spin_unlock_irqrestore(&feature_lock, flags);
+ raw_spin_unlock_irqrestore(&feature_lock, flags);
return 0;
}
@@ -165,9 +169,9 @@ static int macio_do_write_reg8(PMF_STD_ARGS, u32 offset, u8 value, u8 mask)
struct macio_chip *macio = func->driver_data;
unsigned long flags;
- spin_lock_irqsave(&feature_lock, flags);
+ raw_spin_lock_irqsave(&feature_lock, flags);
MACIO_OUT8(offset, (MACIO_IN8(offset) & ~mask) | (value & mask));
- spin_unlock_irqrestore(&feature_lock, flags);
+ raw_spin_unlock_irqrestore(&feature_lock, flags);
return 0;
}
@@ -220,12 +224,12 @@ static int macio_do_write_reg32_slm(PMF_STD_ARGS, u32 offset, u32 shift,
if (args == NULL || args->count == 0)
return -EINVAL;
- spin_lock_irqsave(&feature_lock, flags);
+ raw_spin_lock_irqsave(&feature_lock, flags);
tmp = MACIO_IN32(offset);
val = args->u[0].v << shift;
tmp = (tmp & ~mask) | (val & mask);
MACIO_OUT32(offset, tmp);
- spin_unlock_irqrestore(&feature_lock, flags);
+ raw_spin_unlock_irqrestore(&feature_lock, flags);
return 0;
}
@@ -240,12 +244,12 @@ static int macio_do_write_reg8_slm(PMF_STD_ARGS, u32 offset, u32 shift,
if (args == NULL || args->count == 0)
return -EINVAL;
- spin_lock_irqsave(&feature_lock, flags);
+ raw_spin_lock_irqsave(&feature_lock, flags);
tmp = MACIO_IN8(offset);
val = args->u[0].v << shift;
tmp = (tmp & ~mask) | (val & mask);
MACIO_OUT8(offset, tmp);
- spin_unlock_irqrestore(&feature_lock, flags);
+ raw_spin_unlock_irqrestore(&feature_lock, flags);
return 0;
}
@@ -253,7 +257,7 @@ static struct pmf_handlers macio_mmio_handlers = {
.write_reg32 = macio_do_write_reg32,
.read_reg32 = macio_do_read_reg32,
.write_reg8 = macio_do_write_reg8,
- .read_reg32 = macio_do_read_reg8,
+ .read_reg8 = macio_do_read_reg8,
.read_reg32_msrx = macio_do_read_reg32_msrx,
.read_reg8_msrx = macio_do_read_reg8_msrx,
.write_reg32_slm = macio_do_write_reg32_slm,
@@ -275,12 +279,12 @@ static int unin_do_write_reg32(PMF_STD_ARGS, u32 offset, u32 value, u32 mask)
{
unsigned long flags;
- spin_lock_irqsave(&feature_lock, flags);
+ raw_spin_lock_irqsave(&feature_lock, flags);
/* This is fairly bogus in darwin, but it should work for our needs
* implemeted that way:
*/
UN_OUT(offset, (UN_IN(offset) & ~mask) | (value & mask));
- spin_unlock_irqrestore(&feature_lock, flags);
+ raw_spin_unlock_irqrestore(&feature_lock, flags);
return 0;
}
@@ -331,6 +335,8 @@ int __init pmac_pfunc_base_install(void)
return 0;
pfbase_inited = 1;
+ if (!machine_is(powermac))
+ return 0;
DBG("Installing base platform functions...\n");
@@ -358,8 +364,7 @@ int __init pmac_pfunc_base_install(void)
return 0;
}
-
-arch_initcall(pmac_pfunc_base_install);
+machine_arch_initcall(powermac, pmac_pfunc_base_install);
#ifdef CONFIG_PM
diff --git a/arch/powerpc/platforms/powermac/pfunc_core.c b/arch/powerpc/platforms/powermac/pfunc_core.c
index 356a739e52b..43075081721 100644
--- a/arch/powerpc/platforms/powermac/pfunc_core.c
+++ b/arch/powerpc/platforms/powermac/pfunc_core.c
@@ -5,14 +5,13 @@
* FIXME: LOCKING !!!
*/
-#include <linux/config.h>
-#include <linux/init.h>
#include <linux/delay.h>
#include <linux/kernel.h>
#include <linux/spinlock.h>
+#include <linux/slab.h>
#include <linux/module.h>
+#include <linux/mutex.h>
-#include <asm/semaphore.h>
#include <asm/prom.h>
#include <asm/pmac_pfunc.h>
@@ -20,7 +19,13 @@
#define LOG_PARSE(fmt...)
#define LOG_ERROR(fmt...) printk(fmt)
#define LOG_BLOB(t,b,c)
+
+#undef DEBUG
+#ifdef DEBUG
#define DBG(fmt...) printk(fmt)
+#else
+#define DBG(fmt...)
+#endif
/* Command numbers */
#define PMF_CMD_LIST 0
@@ -539,7 +544,8 @@ struct pmf_device {
};
static LIST_HEAD(pmf_devices);
-static spinlock_t pmf_lock = SPIN_LOCK_UNLOCKED;
+static DEFINE_SPINLOCK(pmf_lock);
+static DEFINE_MUTEX(pmf_irq_mutex);
static void pmf_release_device(struct kref *kref)
{
@@ -679,14 +685,13 @@ static int pmf_add_functions(struct pmf_device *dev, void *driverdata)
int count = 0;
for (pp = dev->node->properties; pp != 0; pp = pp->next) {
- char *name;
+ const char *name;
if (strncmp(pp->name, PP_PREFIX, plen) != 0)
continue;
name = pp->name + plen;
if (strlen(name) && pp->length >= 12)
count += pmf_add_function_prop(dev, driverdata, name,
- (u32 *)pp->value,
- pp->length);
+ pp->value, pp->length);
}
return count;
}
@@ -806,14 +811,15 @@ struct pmf_function *__pmf_find_function(struct device_node *target,
struct pmf_device *dev;
struct pmf_function *func, *result = NULL;
char fname[64];
- u32 *prop, ph;
+ const u32 *prop;
+ u32 ph;
/*
* Look for a "platform-*" function reference. If we can't find
* one, then we fallback to a direct call attempt
*/
snprintf(fname, 63, "platform-%s", name);
- prop = (u32 *)get_property(target, fname, NULL);
+ prop = of_get_property(target, fname, NULL);
if (prop == NULL)
goto find_it;
ph = *prop;
@@ -830,21 +836,24 @@ struct pmf_function *__pmf_find_function(struct device_node *target,
return NULL;
find_it:
dev = pmf_find_device(actor);
- if (dev == NULL)
- return NULL;
+ if (dev == NULL) {
+ result = NULL;
+ goto out;
+ }
list_for_each_entry(func, &dev->functions, link) {
if (name && strcmp(name, func->name))
continue;
- if (func->phandle && target->node != func->phandle)
+ if (func->phandle && target->phandle != func->phandle)
continue;
if ((func->flags & flags) == 0)
continue;
result = func;
break;
}
- of_node_put(actor);
pmf_put_device(dev);
+out:
+ of_node_put(actor);
return result;
}
@@ -858,16 +867,25 @@ int pmf_register_irq_client(struct device_node *target,
spin_lock_irqsave(&pmf_lock, flags);
func = __pmf_find_function(target, name, PMF_FLAGS_INT_GEN);
- if (func == NULL) {
- spin_unlock_irqrestore(&pmf_lock, flags);
+ if (func)
+ func = pmf_get_function(func);
+ spin_unlock_irqrestore(&pmf_lock, flags);
+ if (func == NULL)
return -ENODEV;
- }
+
+ /* guard against manipulations of list */
+ mutex_lock(&pmf_irq_mutex);
if (list_empty(&func->irq_clients))
func->dev->handlers->irq_enable(func);
+
+ /* guard against pmf_do_irq while changing list */
+ spin_lock_irqsave(&pmf_lock, flags);
list_add(&client->link, &func->irq_clients);
- client->func = func;
spin_unlock_irqrestore(&pmf_lock, flags);
+ client->func = func;
+ mutex_unlock(&pmf_irq_mutex);
+
return 0;
}
EXPORT_SYMBOL_GPL(pmf_register_irq_client);
@@ -879,12 +897,19 @@ void pmf_unregister_irq_client(struct pmf_irq_client *client)
BUG_ON(func == NULL);
- spin_lock_irqsave(&pmf_lock, flags);
+ /* guard against manipulations of list */
+ mutex_lock(&pmf_irq_mutex);
client->func = NULL;
+
+ /* guard against pmf_do_irq while changing list */
+ spin_lock_irqsave(&pmf_lock, flags);
list_del(&client->link);
+ spin_unlock_irqrestore(&pmf_lock, flags);
+
if (list_empty(&func->irq_clients))
func->dev->handlers->irq_disable(func);
- spin_unlock_irqrestore(&pmf_lock, flags);
+ mutex_unlock(&pmf_irq_mutex);
+ pmf_put_function(func);
}
EXPORT_SYMBOL_GPL(pmf_unregister_irq_client);
diff --git a/arch/powerpc/platforms/powermac/pic.c b/arch/powerpc/platforms/powermac/pic.c
index 18bf3011d1e..4c24bf60d39 100644
--- a/arch/powerpc/platforms/powermac/pic.c
+++ b/arch/powerpc/platforms/powermac/pic.c
@@ -15,17 +15,15 @@
*
*/
-#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/syscore_ops.h>
#include <linux/adb.h>
#include <linux/pmu.h>
-#include <linux/module.h>
#include <asm/sections.h>
#include <asm/io.h>
@@ -35,16 +33,10 @@
#include <asm/time.h>
#include <asm/pmac_feature.h>
#include <asm/mpic.h>
+#include <asm/xmon.h>
#include "pmac.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 *);
-
#ifdef CONFIG_PPC32
struct pmac_irq_hw {
unsigned int event;
@@ -53,52 +45,48 @@ struct pmac_irq_hw {
unsigned int level;
};
+/* Workaround flags for 32bit powermac machines */
+unsigned int of_irq_workarounds;
+struct device_node *of_irq_dflt_pic;
+
/* Default addresses */
static volatile struct pmac_irq_hw __iomem *pmac_irq_hw[4];
-#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];
+static DEFINE_RAW_SPINLOCK(pmac_pic_lock);
-#define NR_MASK_WORDS ((NR_IRQS + 31) / 32)
-static unsigned long ppc_lost_interrupts[NR_MASK_WORDS];
+/* The max irq number this driver deals with is 128; see max_irqs */
+static DECLARE_BITMAP(ppc_lost_interrupts, 128);
+static DECLARE_BITMAP(ppc_cached_irq_mask, 128);
+static int pmac_irq_cascade = -1;
+static struct irq_domain *pmac_pic_host;
-/*
- * 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)
+static void __pmac_retrigger(unsigned int irq_nr)
{
- if (!test_and_set_bit(irq_nr, ppc_lost_interrupts)) {
+ if (irq_nr >= max_real_irqs && pmac_irq_cascade > 0) {
+ __set_bit(irq_nr, ppc_lost_interrupts);
+ irq_nr = pmac_irq_cascade;
+ mb();
+ }
+ if (!__test_and_set_bit(irq_nr, ppc_lost_interrupts)) {
atomic_inc(&ppc_n_lost_interrupts);
- if (!nokick)
- set_dec(1);
+ set_dec(1);
}
}
-static void pmac_mask_and_ack_irq(unsigned int irq_nr)
+static void pmac_mask_and_ack_irq(struct irq_data *d)
{
- unsigned long bit = 1UL << (irq_nr & 0x1f);
- int i = irq_nr >> 5;
+ unsigned int src = irqd_to_hwirq(d);
+ unsigned long bit = 1UL << (src & 0x1f);
+ int i = src >> 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))
+ raw_spin_lock_irqsave(&pmac_pic_lock, flags);
+ __clear_bit(src, ppc_cached_irq_mask);
+ if (__test_and_clear_bit(src, 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 {
@@ -107,19 +95,32 @@ static void pmac_mask_and_ack_irq(unsigned int irq_nr)
mb();
} while((in_le32(&pmac_irq_hw[i]->enable) & bit)
!= (ppc_cached_irq_mask[i] & bit));
- spin_unlock_irqrestore(&pmac_pic_lock, flags);
+ raw_spin_unlock_irqrestore(&pmac_pic_lock, flags);
+}
+
+static void pmac_ack_irq(struct irq_data *d)
+{
+ unsigned int src = irqd_to_hwirq(d);
+ unsigned long bit = 1UL << (src & 0x1f);
+ int i = src >> 5;
+ unsigned long flags;
+
+ raw_spin_lock_irqsave(&pmac_pic_lock, flags);
+ if (__test_and_clear_bit(src, ppc_lost_interrupts))
+ atomic_dec(&ppc_n_lost_interrupts);
+ out_le32(&pmac_irq_hw[i]->ack, bit);
+ (void)in_le32(&pmac_irq_hw[i]->ack);
+ raw_spin_unlock_irqrestore(&pmac_pic_lock, flags);
}
-static void pmac_set_irq_mask(unsigned int irq_nr, int nokicklost)
+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]);
@@ -136,268 +137,173 @@ static void pmac_set_irq_mask(unsigned int irq_nr, int nokicklost)
* 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);
+ __pmac_retrigger(irq_nr);
}
/* 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)
+static unsigned int pmac_startup_irq(struct irq_data *d)
{
- unsigned long bit = 1UL << (irq_nr & 0x1f);
- int i = irq_nr >> 5;
+ unsigned long flags;
+ unsigned int src = irqd_to_hwirq(d);
+ unsigned long bit = 1UL << (src & 0x1f);
+ int i = src >> 5;
- if ((irq_desc[irq_nr].status & IRQ_LEVEL) == 0)
+ raw_spin_lock_irqsave(&pmac_pic_lock, flags);
+ if (!irqd_is_level_type(d))
out_le32(&pmac_irq_hw[i]->ack, bit);
- set_bit(irq_nr, ppc_cached_irq_mask);
- pmac_set_irq_mask(irq_nr, 0);
+ __set_bit(src, ppc_cached_irq_mask);
+ __pmac_set_irq_mask(src, 0);
+ raw_spin_unlock_irqrestore(&pmac_pic_lock, flags);
return 0;
}
-static void pmac_mask_irq(unsigned int irq_nr)
+static void pmac_mask_irq(struct irq_data *d)
{
- clear_bit(irq_nr, ppc_cached_irq_mask);
- pmac_set_irq_mask(irq_nr, 0);
- mb();
-}
+ unsigned long flags;
+ unsigned int src = irqd_to_hwirq(d);
-static void pmac_unmask_irq(unsigned int irq_nr)
-{
- set_bit(irq_nr, ppc_cached_irq_mask);
- pmac_set_irq_mask(irq_nr, 0);
+ raw_spin_lock_irqsave(&pmac_pic_lock, flags);
+ __clear_bit(src, ppc_cached_irq_mask);
+ __pmac_set_irq_mask(src, 1);
+ raw_spin_unlock_irqrestore(&pmac_pic_lock, flags);
}
-static void pmac_end_irq(unsigned int irq_nr)
+static void pmac_unmask_irq(struct irq_data *d)
{
- 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);
- }
+ unsigned long flags;
+ unsigned int src = irqd_to_hwirq(d);
+
+ raw_spin_lock_irqsave(&pmac_pic_lock, flags);
+ __set_bit(src, ppc_cached_irq_mask);
+ __pmac_set_irq_mask(src, 0);
+ raw_spin_unlock_irqrestore(&pmac_pic_lock, flags);
}
+static int pmac_retrigger(struct irq_data *d)
+{
+ unsigned long flags;
-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,
-};
+ raw_spin_lock_irqsave(&pmac_pic_lock, flags);
+ __pmac_retrigger(irqd_to_hwirq(d));
+ raw_spin_unlock_irqrestore(&pmac_pic_lock, flags);
+ return 1;
+}
-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 struct irq_chip pmac_pic = {
+ .name = "PMAC-PIC",
+ .irq_startup = pmac_startup_irq,
+ .irq_mask = pmac_mask_irq,
+ .irq_ack = pmac_ack_irq,
+ .irq_mask_ack = pmac_mask_and_ack_irq,
+ .irq_unmask = pmac_unmask_irq,
+ .irq_retrigger = pmac_retrigger,
};
-static irqreturn_t gatwick_action(int cpl, void *dev_id, struct pt_regs *regs)
+static irqreturn_t gatwick_action(int cpl, void *dev_id)
{
+ unsigned long flags;
int irq, bits;
+ int rc = IRQ_NONE;
+ raw_spin_lock_irqsave(&pmac_pic_lock, flags);
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 |= in_le32(&pmac_irq_hw[i]->level);
bits &= ppc_cached_irq_mask[i];
if (bits == 0)
continue;
irq += __ilog2(bits);
- __do_IRQ(irq, regs);
- return IRQ_HANDLED;
+ raw_spin_unlock_irqrestore(&pmac_pic_lock, flags);
+ generic_handle_irq(irq);
+ raw_spin_lock_irqsave(&pmac_pic_lock, flags);
+ rc = IRQ_HANDLED;
}
- printk("gatwick irq not from gatwick pic\n");
- return IRQ_NONE;
+ raw_spin_unlock_irqrestore(&pmac_pic_lock, flags);
+ return rc;
}
-static int pmac_get_irq(struct pt_regs *regs)
+static unsigned int pmac_pic_get_irq(void)
{
int irq;
unsigned long bits = 0;
+ unsigned long flags;
-#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 */
+#ifdef CONFIG_PPC_PMAC32_PSURGE
+ /* IPI's are a hack on the powersurge -- Cort */
+ if (smp_processor_id() != 0) {
+ return psurge_secondary_virq;
}
-#endif /* CONFIG_SMP */
+#endif /* CONFIG_PPC_PMAC32_PSURGE */
+ raw_spin_lock_irqsave(&pmac_pic_lock, flags);
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 |= in_le32(&pmac_irq_hw[i]->level);
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
- *
- * Walking of OF nodes could use a bit more fixing up here, but it's not
- * very important as this is all boot time code on static portions of the
- * device-tree.
- *
- * However, the modifications done to "intrs" will have to be removed and
- * replaced with proper updates of the "interrupts" properties or
- * AAPL,interrupts, yet to be decided, once the dynamic parsing is there.
- */
-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));
- count = 0;
- for (node = NULL; (node = of_get_next_child(gw, node)) != NULL;) {
- /* Fix SCC */
- if ((strcasecmp(node->name, "escc") == 0) && 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 gatwick"
- " (%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 gatwick"
- " (%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;
- }
- }
- }
- 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 void __init enable_second_ohare(struct device_node *np)
-{
- unsigned char bus, devfn;
- unsigned short cmd;
- struct device_node *ether;
-
- /* This code doesn't strictly belong here, it could be part of
- * either the PCI initialisation or the feature code. It's kept
- * here for historical reasons.
- */
- if (pci_device_from_OF_node(np, &bus, &devfn) == 0) {
- struct pci_controller* hose =
- pci_find_hose_for_OF_device(np);
- if (!hose) {
- printk(KERN_ERR "Can't find PCI hose for OHare2 !\n");
- return;
- }
- 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 = of_find_node_by_name(NULL, "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);
- }
- of_node_put(ether);
+ raw_spin_unlock_irqrestore(&pmac_pic_lock, flags);
+ if (unlikely(irq < 0))
+ return NO_IRQ;
+ return irq_linear_revmap(pmac_pic_host, irq);
}
#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",
};
+static int pmac_pic_host_match(struct irq_domain *h, struct device_node *node)
+{
+ /* We match all, we don't always have a node anyway */
+ return 1;
+}
+
+static int pmac_pic_host_map(struct irq_domain *h, unsigned int virq,
+ irq_hw_number_t hw)
+{
+ if (hw >= max_irqs)
+ return -EINVAL;
+
+ /* Mark level interrupts, set delayed disable for edge ones and set
+ * handlers
+ */
+ irq_set_status_flags(virq, IRQ_LEVEL);
+ irq_set_chip_and_handler(virq, &pmac_pic, handle_level_irq);
+ return 0;
+}
+
+static const struct irq_domain_ops pmac_pic_host_ops = {
+ .match = pmac_pic_host_match,
+ .map = pmac_pic_host_map,
+ .xlate = irq_domain_xlate_onecell,
+};
+
static void __init pmac_pic_probe_oldstyle(void)
{
int i;
- int irq_cascade = -1;
struct device_node *master = NULL;
struct device_node *slave = NULL;
u8 __iomem *addr;
struct resource r;
/* Set our get_irq function */
- ppc_md.get_irq = pmac_get_irq;
+ ppc_md.get_irq = pmac_pic_get_irq;
/*
* Find the interrupt controller type & node
@@ -405,28 +311,20 @@ static void __init pmac_pic_probe_oldstyle(void)
if ((master = of_find_node_by_name(NULL, "gc")) != NULL) {
max_irqs = max_real_irqs = 32;
- level_mask[0] = GC_LEVEL_MASK;
} else if ((master = of_find_node_by_name(NULL, "ohare")) != NULL) {
max_irqs = max_real_irqs = 32;
- level_mask[0] = OHARE_LEVEL_MASK;
-
/* We might have a second cascaded ohare */
slave = of_find_node_by_name(NULL, "pci106b,7");
- if (slave) {
+ if (slave)
max_irqs = 64;
- level_mask[1] = OHARE_LEVEL_MASK;
- enable_second_ohare(slave);
- }
} else if ((master = of_find_node_by_name(NULL, "mac-io")) != NULL) {
max_irqs = max_real_irqs = 64;
- level_mask[0] = HEATHROW_LEVEL_MASK;
- level_mask[1] = 0;
/* We might have a second cascaded heathrow */
slave = of_find_node_by_name(master, "mac-io");
/* Check ordering of master & slave */
- if (device_is_compatible(master, "gatwick")) {
+ if (of_device_is_compatible(master, "gatwick")) {
struct device_node *tmp;
BUG_ON(slave == NULL);
tmp = master;
@@ -435,18 +333,18 @@ static void __init pmac_pic_probe_oldstyle(void)
}
/* We found a slave */
- if (slave) {
+ if (slave)
max_irqs = 128;
- level_mask[2] = HEATHROW_LEVEL_MASK;
- level_mask[3] = 0;
- pmac_fix_gatwick_interrupts(slave, max_real_irqs);
- }
}
BUG_ON(master == NULL);
- /* Set the handler for the main PIC */
- for ( i = 0; i < max_real_irqs ; i++ )
- irq_desc[i].handler = &pmac_pic;
+ /*
+ * Allocate an irq host
+ */
+ pmac_pic_host = irq_domain_add_linear(master, max_irqs,
+ &pmac_pic_host_ops, NULL);
+ BUG_ON(pmac_pic_host == NULL);
+ irq_set_default_host(pmac_pic_host);
/* Get addresses of first controller if we have a node for it */
BUG_ON(of_address_to_resource(master, 0, &r));
@@ -473,40 +371,64 @@ static void __init pmac_pic_probe_oldstyle(void)
pmac_irq_hw[i++] =
(volatile struct pmac_irq_hw __iomem *)
(addr + 0x10);
- irq_cascade = slave->intrs[0].line;
+ pmac_irq_cascade = irq_of_parse_and_map(slave, 0);
printk(KERN_INFO "irq: Found slave Apple PIC %s for %d irqs"
" cascade: %d\n", slave->full_name,
- max_irqs - max_real_irqs, irq_cascade);
+ max_irqs - max_real_irqs, pmac_irq_cascade);
}
of_node_put(slave);
- /* disable all interrupts in all controllers */
+ /* 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;
+ /* Hookup cascade irq */
+ if (slave && pmac_irq_cascade != NO_IRQ)
+ setup_irq(pmac_irq_cascade, &gatwick_cascade_action);
- /* Setup handlers for secondary controller and hook cascade irq*/
- if (slave) {
- for ( i = max_real_irqs ; i < max_irqs ; i++ )
- irq_desc[i].handler = &gatwick_pic;
- setup_irq(irq_cascade, &gatwick_cascade_action);
- }
printk(KERN_INFO "irq: System has %d possible interrupts\n", max_irqs);
#ifdef CONFIG_XMON
- setup_irq(20, &xmon_action);
+ setup_irq(irq_create_mapping(NULL, 20), &xmon_action);
#endif
}
-#endif /* CONFIG_PPC32 */
-static int pmac_u3_cascade(struct pt_regs *regs, void *data)
+int of_irq_parse_oldworld(struct device_node *device, int index,
+ struct of_phandle_args *out_irq)
{
- return mpic_get_one_irq((struct mpic *)data, regs);
+ const u32 *ints = NULL;
+ int intlen;
+
+ /*
+ * Old machines just have a list of interrupt numbers
+ * and no interrupt-controller nodes. We also have dodgy
+ * cases where the APPL,interrupts property is completely
+ * missing behind pci-pci bridges and we have to get it
+ * from the parent (the bridge itself, as apple just wired
+ * everything together on these)
+ */
+ while (device) {
+ ints = of_get_property(device, "AAPL,interrupts", &intlen);
+ if (ints != NULL)
+ break;
+ device = device->parent;
+ if (device && strcmp(device->type, "pci") != 0)
+ break;
+ }
+ if (ints == NULL)
+ return -EINVAL;
+ intlen /= sizeof(u32);
+
+ if (index >= intlen)
+ return -EINVAL;
+
+ out_irq->np = NULL;
+ out_irq->args[0] = ints[index];
+ out_irq->args_count = 1;
+
+ return 0;
}
+#endif /* CONFIG_PPC32 */
static void __init pmac_pic_setup_mpic_nmi(struct mpic *mpic)
{
@@ -515,47 +437,36 @@ static void __init pmac_pic_setup_mpic_nmi(struct mpic *mpic)
int nmi_irq;
pswitch = of_find_node_by_name(NULL, "programmer-switch");
- if (pswitch && pswitch->n_intrs) {
- nmi_irq = pswitch->intrs[0].line;
- mpic_irq_set_priority(nmi_irq, 9);
- setup_irq(nmi_irq, &xmon_action);
+ if (pswitch) {
+ nmi_irq = irq_of_parse_and_map(pswitch, 0);
+ if (nmi_irq != NO_IRQ) {
+ mpic_irq_set_priority(nmi_irq, 9);
+ setup_irq(nmi_irq, &xmon_action);
+ }
+ of_node_put(pswitch);
}
- of_node_put(pswitch);
#endif /* defined(CONFIG_XMON) && defined(CONFIG_PPC32) */
}
static struct mpic * __init pmac_setup_one_mpic(struct device_node *np,
int master)
{
- unsigned char senses[128];
- int offset = master ? 0 : 128;
- int count = master ? 128 : 124;
const char *name = master ? " MPIC 1 " : " MPIC 2 ";
- struct resource r;
struct mpic *mpic;
- unsigned int flags = master ? MPIC_PRIMARY : 0;
- int rc;
-
- rc = of_address_to_resource(np, 0, &r);
- if (rc)
- return NULL;
+ unsigned int flags = master ? 0 : MPIC_SECONDARY;
pmac_call_feature(PMAC_FTR_ENABLE_MPIC, np, 0, 0);
- prom_get_irq_senses(senses, offset, offset + count);
-
- flags |= MPIC_WANTS_RESET;
- if (get_property(np, "big-endian", NULL))
+ if (of_get_property(np, "big-endian", NULL))
flags |= MPIC_BIG_ENDIAN;
/* Primary Big Endian means HT interrupts. This is quite dodgy
* but works until I find a better way
*/
if (master && (flags & MPIC_BIG_ENDIAN))
- flags |= MPIC_BROKEN_U3;
+ flags |= MPIC_U3_HT_IRQS;
- mpic = mpic_alloc(r.start, flags, 0, offset, count, master ? 252 : 0,
- senses, count, name);
+ mpic = mpic_alloc(np, 0, flags, 0, 0, name);
if (mpic == NULL)
return NULL;
@@ -573,7 +484,7 @@ static int __init pmac_pic_probe_mpic(void)
for (np = NULL; (np = of_find_node_by_type(np, "open-pic"))
!= NULL;) {
if (master == NULL &&
- get_property(np, "interrupts", NULL) == NULL)
+ of_get_property(np, "interrupts", NULL) == NULL)
master = of_node_get(np);
else if (slave == NULL)
slave = of_node_get(np);
@@ -603,25 +514,54 @@ static int __init pmac_pic_probe_mpic(void)
of_node_put(master);
- /* No slave, let's go out */
- if (slave == NULL || slave->n_intrs < 1)
- return 0;
-
- mpic2 = pmac_setup_one_mpic(slave, 0);
- if (mpic2 == NULL) {
- printk(KERN_ERR "Failed to setup slave MPIC\n");
+ /* Set up a cascaded controller, if present */
+ if (slave) {
+ mpic2 = pmac_setup_one_mpic(slave, 0);
+ if (mpic2 == NULL)
+ printk(KERN_ERR "Failed to setup slave MPIC\n");
of_node_put(slave);
- return 0;
}
- mpic_setup_cascade(slave->intrs[0].line, pmac_u3_cascade, mpic2);
- of_node_put(slave);
return 0;
}
void __init pmac_pic_init(void)
{
+ /* We configure the OF parsing based on our oldworld vs. newworld
+ * platform type and whether we were booted by BootX.
+ */
+#ifdef CONFIG_PPC32
+ if (!pmac_newworld)
+ of_irq_workarounds |= OF_IMAP_OLDWORLD_MAC;
+ if (of_get_property(of_chosen, "linux,bootx", NULL) != NULL)
+ of_irq_workarounds |= OF_IMAP_NO_PHANDLE;
+
+ /* If we don't have phandles on a newworld, then try to locate a
+ * default interrupt controller (happens when booting with BootX).
+ * We do a first match here, hopefully, that only ever happens on
+ * machines with one controller.
+ */
+ if (pmac_newworld && (of_irq_workarounds & OF_IMAP_NO_PHANDLE)) {
+ struct device_node *np;
+
+ for_each_node_with_property(np, "interrupt-controller") {
+ /* Skip /chosen/interrupt-controller */
+ if (strcmp(np->name, "chosen") == 0)
+ continue;
+ /* It seems like at least one person wants
+ * to use BootX on a machine with an AppleKiwi
+ * controller which happens to pretend to be an
+ * interrupt controller too. */
+ if (strcmp(np->name, "AppleKiwi") == 0)
+ continue;
+ /* I think we found one ! */
+ of_irq_dflt_pic = np;
+ break;
+ }
+ }
+#endif /* CONFIG_PPC32 */
+
/* We first try to detect Apple's new Core99 chipset, since mac-io
* is quite different on those machines and contains an IBM MPIC2.
*/
@@ -644,6 +584,7 @@ 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...
+ * We really want to do things differently though...
*/
static int pmacpic_find_viaint(void)
{
@@ -657,14 +598,14 @@ static int pmacpic_find_viaint(void)
np = of_find_node_by_name(NULL, "via-pmu");
if (np == NULL)
goto not_found;
- viaint = np->intrs[0].line;
-#endif /* CONFIG_ADB_PMU */
+ viaint = irq_of_parse_and_map(np, 0);
not_found:
+#endif /* CONFIG_ADB_PMU */
return viaint;
}
-static int pmacpic_suspend(struct sys_device *sysdev, pm_message_t state)
+static int pmacpic_suspend(void)
{
int viaint = pmacpic_find_viaint();
@@ -685,7 +626,7 @@ static int pmacpic_suspend(struct sys_device *sysdev, pm_message_t state)
return 0;
}
-static int pmacpic_resume(struct sys_device *sysdev)
+static void pmacpic_resume(void)
{
int i;
@@ -695,41 +636,21 @@ static int pmacpic_resume(struct sys_device *sysdev)
mb();
for (i = 0; i < max_real_irqs; ++i)
if (test_bit(i, sleep_save_mask))
- pmac_unmask_irq(i);
-
- return 0;
+ pmac_unmask_irq(irq_get_irq_data(i));
}
-#endif /* CONFIG_PM && CONFIG_PPC32 */
-
-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 = {
-#if defined(CONFIG_PM) && defined(CONFIG_PPC32)
- .suspend = &pmacpic_suspend,
- .resume = &pmacpic_resume,
-#endif /* CONFIG_PM && CONFIG_PPC32 */
+static struct syscore_ops pmacpic_syscore_ops = {
+ .suspend = pmacpic_suspend,
+ .resume = pmacpic_resume,
};
-static int __init init_pmacpic_sysfs(void)
+static int __init init_pmacpic_syscore(void)
{
-#ifdef CONFIG_PPC32
- if (max_irqs == 0)
- return -ENODEV;
-#endif
- 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);
+ if (pmac_irq_hw[0])
+ register_syscore_ops(&pmacpic_syscore_ops);
return 0;
}
-subsys_initcall(init_pmacpic_sysfs);
+machine_subsys_initcall(powermac, init_pmacpic_syscore);
+#endif /* CONFIG_PM && CONFIG_PPC32 */
diff --git a/arch/powerpc/platforms/powermac/pic.h b/arch/powerpc/platforms/powermac/pic.h
deleted file mode 100644
index 664103dfeef..00000000000
--- a/arch/powerpc/platforms/powermac/pic.h
+++ /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.h b/arch/powerpc/platforms/powermac/pmac.h
index 21c7b0f8f32..8327cce2bdb 100644
--- a/arch/powerpc/platforms/powermac/pmac.h
+++ b/arch/powerpc/platforms/powermac/pmac.h
@@ -2,7 +2,6 @@
#define __PMAC_H__
#include <linux/pci.h>
-#include <linux/ide.h>
#include <linux/irq.h>
/*
@@ -12,34 +11,30 @@
struct rtc_time;
+extern int pmac_newworld;
+
extern long pmac_time_init(void);
extern unsigned long pmac_get_boot_time(void);
extern void pmac_get_rtc_time(struct rtc_time *);
extern int pmac_set_rtc_time(struct rtc_time *);
extern void pmac_read_rtc_time(void);
extern void pmac_calibrate_decr(void);
-extern void pmac_pcibios_fixup(void);
+extern void pmac_pci_irq_fixup(struct pci_dev *);
extern void pmac_pci_init(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 int pmac_pci_enable_device_hook(struct pci_dev *dev);
extern void pmac_pcibios_after_init(void);
extern int of_show_percpuinfo(struct seq_file *m, int i);
-extern void pmac_pci_init(void);
extern void pmac_setup_pci_dma(void);
extern void pmac_check_ht_link(void);
extern void pmac_setup_smp(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 int psurge_secondary_virq;
+extern void low_cpu_die(void) __attribute__((noreturn));
extern int pmac_nvram_init(void);
extern void pmac_pic_init(void);
diff --git a/arch/powerpc/platforms/powermac/setup.c b/arch/powerpc/platforms/powermac/setup.c
index 89c4c363616..141f8899a63 100644
--- a/arch/powerpc/platforms/powermac/setup.c
+++ b/arch/powerpc/platforms/powermac/setup.c
@@ -23,7 +23,6 @@
* bootup setup stuff..
*/
-#include <linux/config.h>
#include <linux/init.h>
#include <linux/errno.h>
#include <linux/sched.h>
@@ -32,9 +31,8 @@
#include <linux/stddef.h>
#include <linux/unistd.h>
#include <linux/ptrace.h>
-#include <linux/slab.h>
+#include <linux/export.h>
#include <linux/user.h>
-#include <linux/a.out.h>
#include <linux/tty.h>
#include <linux/string.h>
#include <linux/delay.h>
@@ -43,7 +41,6 @@
#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>
@@ -53,14 +50,15 @@
#include <linux/root_dev.h>
#include <linux/bitops.h>
#include <linux/suspend.h>
+#include <linux/of_device.h>
+#include <linux/of_platform.h>
+#include <linux/memblock.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/kexec.h>
#include <asm/pci-bridge.h>
#include <asm/ohare.h>
#include <asm/mediabay.h>
@@ -70,40 +68,32 @@
#include <asm/btext.h>
#include <asm/pmac_feature.h>
#include <asm/time.h>
-#include <asm/of_device.h>
#include <asm/mmu_context.h>
#include <asm/iommu.h>
#include <asm/smu.h>
#include <asm/pmc.h>
-#include <asm/lmb.h>
#include <asm/udbg.h>
#include "pmac.h"
#undef SHOW_GATWICK_IRQS
-unsigned char drive_info;
-
int ppc_override_l2cr = 0;
int ppc_override_l2cr_value;
int has_l2cache = 0;
-int pmac_newworld = 1;
+int pmac_newworld;
static int current_root_goodness = -1;
-extern int pmac_newworld;
extern struct machdep_calls pmac_md;
#define DEFAULT_ROOT_DEVICE Root_SDA1 /* sda1 - slightly silly choice */
#ifdef CONFIG_PPC64
-#include <asm/udbg.h>
int sccdbg;
#endif
-extern void zs_kgdb_hook(int tty_num);
-
sys_ctrler_t sys_ctrler = SYS_CTRLER_UNKNOWN;
EXPORT_SYMBOL(sys_ctrler);
@@ -112,15 +102,10 @@ unsigned long smu_cmdbuf_abs;
EXPORT_SYMBOL(smu_cmdbuf_abs);
#endif
-#ifdef CONFIG_SMP
-extern struct smp_ops_t psurge_smp_ops;
-extern struct smp_ops_t core99_smp_ops;
-#endif /* CONFIG_SMP */
-
static void pmac_show_cpuinfo(struct seq_file *m)
{
struct device_node *np;
- char *pp;
+ const char *pp;
int plen;
int mbmodel;
unsigned int mbflags;
@@ -138,12 +123,12 @@ static void pmac_show_cpuinfo(struct seq_file *m)
seq_printf(m, "machine\t\t: ");
np = of_find_node_by_path("/");
if (np != NULL) {
- pp = (char *) get_property(np, "model", NULL);
+ pp = of_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);
+ pp = of_get_property(np, "compatible", &plen);
if (pp != NULL) {
seq_printf(m, "motherboard\t:");
while (plen > 0) {
@@ -167,13 +152,13 @@ static void pmac_show_cpuinfo(struct seq_file *m)
if (np == NULL)
np = of_find_node_by_type(NULL, "cache");
if (np != NULL) {
- unsigned int *ic = (unsigned int *)
- get_property(np, "i-cache-size", NULL);
- unsigned int *dc = (unsigned int *)
- get_property(np, "d-cache-size", NULL);
+ const unsigned int *ic =
+ of_get_property(np, "i-cache-size", NULL);
+ const unsigned int *dc =
+ of_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) {
+ if (of_get_property(np, "cache-unified", NULL) != 0 && dc) {
seq_printf(m, " %dK unified", *dc / 1024);
} else {
if (ic)
@@ -182,7 +167,7 @@ static void pmac_show_cpuinfo(struct seq_file *m)
seq_printf(m, "%s %dK data",
(ic? " +": ""), *dc / 1024);
}
- pp = get_property(np, "ram-type", NULL);
+ pp = of_get_property(np, "ram-type", NULL);
if (pp)
seq_printf(m, " %s", pp);
seq_printf(m, "\n");
@@ -197,8 +182,11 @@ static void pmac_show_cpuinfo(struct seq_file *m)
#ifndef CONFIG_ADB_CUDA
int find_via_cuda(void)
{
- if (!find_devices("via-cuda"))
+ struct device_node *dn = of_find_node_by_name(NULL, "via-cuda");
+
+ if (!dn)
return 0;
+ of_node_put(dn);
printk("WARNING ! Your machine is CUDA-based but your kernel\n");
printk(" wasn't compiled with CONFIG_ADB_CUDA option !\n");
return 0;
@@ -208,8 +196,11 @@ int find_via_cuda(void)
#ifndef CONFIG_ADB_PMU
int find_via_pmu(void)
{
- if (!find_devices("via-pmu"))
+ struct device_node *dn = of_find_node_by_name(NULL, "via-pmu");
+
+ if (!dn)
return 0;
+ of_node_put(dn);
printk("WARNING ! Your machine is PMU-based but your kernel\n");
printk(" wasn't compiled with CONFIG_ADB_PMU option !\n");
return 0;
@@ -229,6 +220,8 @@ static volatile u32 *sysctrl_regs;
static void __init ohare_init(void)
{
+ struct device_node *dn;
+
/* this area has the CPU identification register
and some registers used by smp boards */
sysctrl_regs = (volatile u32 *) ioremap(0xf8000000, 0x1000);
@@ -238,7 +231,9 @@ static void __init ohare_init(void)
* We assume that we have a PSX memory controller iff
* we have an ohare I/O controller.
*/
- if (find_devices("ohare") != NULL) {
+ dn = of_find_node_by_name(NULL, "ohare");
+ if (dn) {
+ of_node_put(dn);
if (((sysctrl_regs[2] >> 24) & 0xf) >= 3) {
if (sysctrl_regs[4] & 0x10)
sysctrl_regs[4] |= 0x04000020;
@@ -254,18 +249,19 @@ static void __init l2cr_init(void)
{
/* Checks "l2cr-value" property in the registry */
if (cpu_has_feature(CPU_FTR_L2CR)) {
- struct device_node *np = find_devices("cpus");
+ struct device_node *np = of_find_node_by_name(NULL, "cpus");
if (np == 0)
- np = find_type_devices("cpu");
+ np = of_find_node_by_type(NULL, "cpu");
if (np != 0) {
- unsigned int *l2cr = (unsigned int *)
- get_property(np, "l2cr-value", NULL);
+ const unsigned int *l2cr =
+ of_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);
}
+ of_node_put(np);
}
}
@@ -281,7 +277,7 @@ static void __init l2cr_init(void)
static void __init pmac_setup_arch(void)
{
struct device_node *cpu, *ic;
- int *fp;
+ const int *fp;
unsigned long pvr;
pvr = PVR_VER(mfspr(SPRN_PVR));
@@ -291,7 +287,7 @@ static void __init pmac_setup_arch(void)
loops_per_jiffy = 50000000 / HZ;
cpu = of_find_node_by_type(NULL, "cpu");
if (cpu != NULL) {
- fp = (int *) get_property(cpu, "clock-frequency", NULL);
+ fp = of_get_property(cpu, "clock-frequency", NULL);
if (fp != NULL) {
if (pvr >= 0x30 && pvr < 0x80)
/* PPC970 etc. */
@@ -307,12 +303,11 @@ static void __init pmac_setup_arch(void)
}
/* See if newworld or oldworld */
- for (ic = NULL; (ic = of_find_all_nodes(ic)) != NULL; )
- if (get_property(ic, "interrupt-controller", NULL))
- break;
- pmac_newworld = (ic != NULL);
- if (ic)
+ ic = of_find_node_with_property(NULL, "interrupt-controller");
+ if (ic) {
+ pmac_newworld = 1;
of_node_put(ic);
+ }
/* Lookup PCI hosts */
pmac_pci_init();
@@ -322,15 +317,12 @@ static void __init pmac_setup_arch(void)
l2cr_init();
#endif /* CONFIG_PPC32 */
-#ifdef CONFIG_KGDB
- zs_kgdb_hook(0);
-#endif
-
find_via_cuda();
find_via_pmu();
smu_init();
-#if defined(CONFIG_NVRAM) || defined(CONFIG_PPC64)
+#if defined(CONFIG_NVRAM) || defined(CONFIG_NVRAM_MODULE) || \
+ defined(CONFIG_PPC64)
pmac_nvram_init();
#endif
@@ -343,147 +335,38 @@ static void __init pmac_setup_arch(void)
ROOT_DEV = DEFAULT_ROOT_DEVICE;
#endif
-#ifdef CONFIG_SMP
- /* Check for Core99 */
- if (find_devices("uni-n") || find_devices("u3") || find_devices("u4"))
- smp_ops = &core99_smp_ops;
-#ifdef CONFIG_PPC32
- else
- smp_ops = &psurge_smp_ops;
-#endif
-#endif /* CONFIG_SMP */
+#ifdef CONFIG_ADB
+ if (strstr(cmd_line, "adb_sync")) {
+ extern int __adb_probe_sync;
+ __adb_probe_sync = 1;
+ }
+#endif /* CONFIG_ADB */
}
-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)
+void 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
-}
-
-/* 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 initializing = 1;
static int pmac_late_init(void)
{
initializing = 0;
-#ifdef CONFIG_SOFTWARE_SUSPEND
- pm_set_ops(&pmac_pm_ops);
-#endif /* CONFIG_SOFTWARE_SUSPEND */
return 0;
}
+machine_late_initcall(powermac, pmac_late_init);
-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)
+/*
+ * This is __init_refok because we check for "initializing" before
+ * touching any of the __init sensitive things and "initializing"
+ * will be false after __init time. This can't be __init because it
+ * can be called whenever a disk is first accessed.
+ */
+void __init_refok note_bootable_part(dev_t dev, int part, int goodness)
{
- static int found_boot = 0;
char *p;
if (!initializing)
@@ -491,19 +374,12 @@ void note_bootable_part(dev_t dev, int part, int goodness)
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] == ' '))
+ p = strstr(boot_command_line, "root=");
+ if (p != NULL && (p == boot_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;
- }
+ ROOT_DEV = dev + part;
+ current_root_goodness = goodness;
}
#ifdef CONFIG_ADB_CUDA
@@ -578,42 +454,11 @@ pmac_halt(void)
pmac_power_off();
}
-#ifdef CONFIG_PPC32
-void __init pmac_init(void)
-{
- /* isa_io_base gets set in pmac_pci_init */
- 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 = pmac_md;
-
-#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) */
-
- if (ppc_md.progress) ppc_md.progress("pmac_init(): exit", 0);
-
-}
-#endif
-
/*
* Early initialization.
*/
static void __init pmac_init_early(void)
{
-#ifdef CONFIG_PPC64
- /* Initialize hash table, from now on, we can take hash faults
- * and call ioremap
- */
- hpte_init_native();
-#endif
-
/* Enable early btext debug if requested */
if (strstr(cmd_line, "btextdbg")) {
udbg_adb_init_early();
@@ -623,61 +468,143 @@ static void __init pmac_init_early(void)
/* Probe motherboard chipset */
pmac_feature_init();
- /* We can NAP */
- powersave_nap = 1;
- printk(KERN_INFO "Using native/NAP idle loop\n");
-
/* Initialize debug stuff */
udbg_scc_init(!!strstr(cmd_line, "sccdbg"));
udbg_adb_init(!!strstr(cmd_line, "btextdbg"));
#ifdef CONFIG_PPC64
- /* Setup interrupt mapping options */
- ppc64_interrupt_controller = IC_OPEN_PIC;
-
iommu_init_early_dart();
#endif
-}
-/*
- * pmac has no legacy IO, anything calling this function has to
- * fail or bad things will happen
- */
-static int pmac_check_legacy_ioport(unsigned int baseport)
-{
- return -ENODEV;
+ /* SMP Init has to be done early as we need to patch up
+ * cpu_possible_mask before interrupt stacks are allocated
+ * or kaboom...
+ */
+#ifdef CONFIG_SMP
+ pmac_setup_smp();
+#endif
}
static int __init pmac_declare_of_platform_devices(void)
{
struct device_node *np;
+ if (machine_is(chrp))
+ return -1;
+
np = of_find_node_by_name(NULL, "valkyrie");
- if (np)
+ if (np) {
of_platform_device_create(np, "valkyrie", NULL);
+ of_node_put(np);
+ }
np = of_find_node_by_name(NULL, "platinum");
- if (np)
+ if (np) {
of_platform_device_create(np, "platinum", NULL);
+ of_node_put(np);
+ }
np = of_find_node_by_type(NULL, "smu");
if (np) {
of_platform_device_create(np, "smu", NULL);
of_node_put(np);
}
+ np = of_find_node_by_type(NULL, "fcu");
+ if (np == NULL) {
+ /* Some machines have strangely broken device-tree */
+ np = of_find_node_by_path("/u3@0,f8000000/i2c@f8001000/fan@15e");
+ }
+ if (np) {
+ of_platform_device_create(np, "temperature", NULL);
+ of_node_put(np);
+ }
return 0;
}
+machine_device_initcall(powermac, pmac_declare_of_platform_devices);
-device_initcall(pmac_declare_of_platform_devices);
+#ifdef CONFIG_SERIAL_PMACZILOG_CONSOLE
+/*
+ * This is called very early, as part of console_init() (typically just after
+ * time_init()). This function is respondible for trying to find a good
+ * default console on serial ports. It tries to match the open firmware
+ * default output with one of the available serial console drivers.
+ */
+static int __init check_pmac_serial_console(void)
+{
+ struct device_node *prom_stdout = NULL;
+ int offset = 0;
+ const char *name;
+#ifdef CONFIG_SERIAL_PMACZILOG_TTYS
+ char *devname = "ttyS";
+#else
+ char *devname = "ttyPZ";
+#endif
+
+ pr_debug(" -> check_pmac_serial_console()\n");
+
+ /* The user has requested a console so this is already set up. */
+ if (strstr(boot_command_line, "console=")) {
+ pr_debug(" console was specified !\n");
+ return -EBUSY;
+ }
+
+ if (!of_chosen) {
+ pr_debug(" of_chosen is NULL !\n");
+ return -ENODEV;
+ }
+
+ /* We are getting a weird phandle from OF ... */
+ /* ... So use the full path instead */
+ name = of_get_property(of_chosen, "linux,stdout-path", NULL);
+ if (name == NULL) {
+ pr_debug(" no linux,stdout-path !\n");
+ return -ENODEV;
+ }
+ prom_stdout = of_find_node_by_path(name);
+ if (!prom_stdout) {
+ pr_debug(" can't find stdout package %s !\n", name);
+ return -ENODEV;
+ }
+ pr_debug("stdout is %s\n", prom_stdout->full_name);
+
+ name = of_get_property(prom_stdout, "name", NULL);
+ if (!name) {
+ pr_debug(" stdout package has no name !\n");
+ goto not_found;
+ }
+
+ if (strcmp(name, "ch-a") == 0)
+ offset = 0;
+ else if (strcmp(name, "ch-b") == 0)
+ offset = 1;
+ else
+ goto not_found;
+ of_node_put(prom_stdout);
+
+ pr_debug("Found serial console at %s%d\n", devname, offset);
+
+ return add_preferred_console(devname, offset, NULL);
+
+ not_found:
+ pr_debug("No preferred console found !\n");
+ of_node_put(prom_stdout);
+ return -ENODEV;
+}
+console_initcall(check_pmac_serial_console);
+
+#endif /* CONFIG_SERIAL_PMACZILOG_CONSOLE */
/*
* Called very early, MMU is off, device-tree isn't unflattened
*/
-static int __init pmac_probe(int platform)
+static int __init pmac_probe(void)
{
-#ifdef CONFIG_PPC64
- if (platform != PLATFORM_POWERMAC)
+ unsigned long root = of_get_flat_dt_root();
+
+ if (!of_flat_dt_is_compatible(root, "Power Macintosh") &&
+ !of_flat_dt_is_compatible(root, "MacRISC"))
return 0;
+#ifdef CONFIG_PPC64
/*
* On U3, the DART (iommu) must be allocated now since it
* has an impact on htab_initialize (due to the large page it
@@ -685,15 +612,24 @@ static int __init pmac_probe(int platform)
* part of the cacheable linar mapping
*/
alloc_dart_table();
+
+ hpte_init_native();
#endif
+#ifdef CONFIG_PPC32
+ /* isa_io_base gets set in pmac_pci_init */
+ ISA_DMA_THRESHOLD = ~0L;
+ DMA_MODE_READ = 1;
+ DMA_MODE_WRITE = 2;
+#endif /* CONFIG_PPC32 */
+
#ifdef CONFIG_PMAC_SMU
/*
* SMU based G5s need some memory below 2Gb, at least the current
* driver needs that. We have to allocate it now. We allocate 4k
* (1 small page) for now.
*/
- smu_cmdbuf_abs = lmb_alloc_base(4096, 4096, 0x80000000UL);
+ smu_cmdbuf_abs = memblock_alloc_base(4096, 4096, 0x80000000UL);
#endif /* CONFIG_PMAC_SMU */
return 1;
@@ -703,29 +639,29 @@ static int __init pmac_probe(int platform)
/* Move that to pci.c */
static int pmac_pci_probe_mode(struct pci_bus *bus)
{
- struct device_node *node = bus->sysdata;
+ struct device_node *node = pci_bus_to_OF_node(bus);
/* We need to use normal PCI probing for the AGP bus,
* since the device for the AGP bridge isn't in the tree.
+ * Same for the PCIe host on U4 and the HT host bridge.
*/
- if (bus->self == NULL && (device_is_compatible(node, "u3-agp") ||
- device_is_compatible(node, "u4-pcie")))
+ if (bus->self == NULL && (of_device_is_compatible(node, "u3-agp") ||
+ of_device_is_compatible(node, "u4-pcie") ||
+ of_device_is_compatible(node, "u3-ht")))
return PCI_PROBE_NORMAL;
return PCI_PROBE_DEVTREE;
}
-#endif
+#endif /* CONFIG_PPC64 */
-struct machdep_calls __initdata pmac_md = {
-#if defined(CONFIG_HOTPLUG_CPU) && defined(CONFIG_PPC64)
- .cpu_die = generic_mach_cpu_die,
-#endif
+define_machine(powermac) {
+ .name = "PowerMac",
.probe = pmac_probe,
.setup_arch = pmac_setup_arch,
.init_early = pmac_init_early,
.show_cpuinfo = pmac_show_cpuinfo,
.init_IRQ = pmac_pic_init,
.get_irq = NULL, /* changed later */
- .pcibios_fixup = pmac_pcibios_fixup,
+ .pci_irq_fixup = pmac_pci_irq_fixup,
.restart = pmac_restart,
.power_off = pmac_power_off,
.halt = pmac_halt,
@@ -735,17 +671,11 @@ struct machdep_calls __initdata pmac_md = {
.get_rtc_time = pmac_get_rtc_time,
.calibrate_decr = pmac_calibrate_decr,
.feature_call = pmac_do_feature_call,
- .check_legacy_ioport = pmac_check_legacy_ioport,
.progress = udbg_progress,
#ifdef CONFIG_PPC64
.pci_probe_mode = pmac_pci_probe_mode,
- .idle_loop = native_idle,
+ .power_save = power4_idle,
.enable_pmcs = power4_enable_pmcs,
-#ifdef CONFIG_KEXEC
- .machine_kexec = default_machine_kexec,
- .machine_kexec_prepare = default_machine_kexec_prepare,
- .machine_crash_shutdown = default_machine_crash_shutdown,
-#endif
#endif /* CONFIG_PPC64 */
#ifdef CONFIG_PPC32
.pcibios_enable_device_hook = pmac_pci_enable_device_hook,
diff --git a/arch/powerpc/platforms/powermac/sleep.S b/arch/powerpc/platforms/powermac/sleep.S
index 22b113d19b2..1c2802fabd5 100644
--- a/arch/powerpc/platforms/powermac/sleep.S
+++ b/arch/powerpc/platforms/powermac/sleep.S
@@ -10,7 +10,6 @@
*
*/
-#include <linux/config.h>
#include <asm/processor.h>
#include <asm/page.h>
#include <asm/ppc_asm.h>
@@ -18,6 +17,7 @@
#include <asm/cache.h>
#include <asm/thread_info.h>
#include <asm/asm-offsets.h>
+#include <asm/mmu.h>
#define MAGIC 0x4c617273 /* 'Lars' */
@@ -46,7 +46,8 @@
.section .text
.align 5
-#if defined(CONFIG_PM) || defined(CONFIG_CPU_FREQ_PMAC)
+#if defined(CONFIG_PM) || defined(CONFIG_CPU_FREQ_PMAC) || \
+ (defined(CONFIG_HOTPLUG_CPU) && defined(CONFIG_PPC32))
/* 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
@@ -323,7 +324,7 @@ grackle_wake_up:
lwz r4,SL_IBAT3+4(r1)
mtibatl 3,r4
-BEGIN_FTR_SECTION
+BEGIN_MMU_FTR_SECTION
li r4,0
mtspr SPRN_DBAT4U,r4
mtspr SPRN_DBAT4L,r4
@@ -341,7 +342,7 @@ BEGIN_FTR_SECTION
mtspr SPRN_IBAT6L,r4
mtspr SPRN_IBAT7U,r4
mtspr SPRN_IBAT7L,r4
-END_FTR_SECTION_IFSET(CPU_FTR_HAS_HIGH_BATS)
+END_MMU_FTR_SECTION_IFSET(MMU_FTR_USE_HIGH_BATS)
/* Flush all TLBs */
lis r4,0x1000
diff --git a/arch/powerpc/platforms/powermac/smp.c b/arch/powerpc/platforms/powermac/smp.c
index 0df2cdcd805..5cbd4d67d5c 100644
--- a/arch/powerpc/platforms/powermac/smp.c
+++ b/arch/powerpc/platforms/powermac/smp.c
@@ -21,11 +21,9 @@
* 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>
@@ -37,7 +35,8 @@
#include <linux/compiler.h>
#include <asm/ptrace.h>
-#include <asm/atomic.h>
+#include <linux/atomic.h>
+#include <asm/code-patching.h>
#include <asm/irq.h>
#include <asm/page.h>
#include <asm/pgtable.h>
@@ -54,7 +53,9 @@
#include <asm/pmac_low_i2c.h>
#include <asm/pmac_pfunc.h>
-#define DEBUG
+#include "pmac.h"
+
+#undef DEBUG
#ifdef DEBUG
#define DBG(fmt...) udbg_printf(fmt)
@@ -65,10 +66,11 @@
extern void __secondary_start_pmac_0(void);
extern int pmac_pfunc_base_install(void);
-#ifdef CONFIG_PPC32
+static void (*pmac_tb_freeze)(int freeze);
+static u64 timebase;
+static int tb_req;
-/* Sync flag for HW tb sync */
-static volatile int sec_tb_reset = 0;
+#ifdef CONFIG_PPC_PMAC32_PSURGE
/*
* Powersurge (old powermac SMP) support.
@@ -122,6 +124,10 @@ static volatile u32 __iomem *psurge_start;
/* what sort of powersurge board we have */
static int psurge_type = PSURGE_NONE;
+/* irq for secondary cpus to report */
+static struct irq_domain *psurge_host;
+int psurge_secondary_virq;
+
/*
* Set and clear IPIs for powersurge.
*/
@@ -154,53 +160,51 @@ static inline void psurge_clr_ipi(int 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.
+ * use the generic demux helpers
* -- paulus.
*/
-static unsigned long psurge_smp_message[NR_CPUS];
-
-void psurge_smp_message_recv(struct pt_regs *regs)
+static irqreturn_t psurge_ipi_intr(int irq, void *d)
{
- int cpu = smp_processor_id();
- int msg;
+ psurge_clr_ipi(smp_processor_id());
+ smp_ipi_demux();
- /* clear interrupt */
- psurge_clr_ipi(cpu);
-
- if (num_online_cpus() < 2)
- return;
+ return IRQ_HANDLED;
+}
- /* 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);
+static void smp_psurge_cause_ipi(int cpu, unsigned long data)
+{
+ psurge_set_ipi(cpu);
}
-irqreturn_t psurge_primary_intr(int irq, void *d, struct pt_regs *regs)
+static int psurge_host_map(struct irq_domain *h, unsigned int virq,
+ irq_hw_number_t hw)
{
- psurge_smp_message_recv(regs);
- return IRQ_HANDLED;
+ irq_set_chip_and_handler(virq, &dummy_irq_chip, handle_percpu_irq);
+
+ return 0;
}
-static void smp_psurge_message_pass(int target, int msg)
+static const struct irq_domain_ops psurge_host_ops = {
+ .map = psurge_host_map,
+};
+
+static int psurge_secondary_ipi_init(void)
{
- int i;
+ int rc = -ENOMEM;
- if (num_online_cpus() < 2)
- return;
+ psurge_host = irq_domain_add_nomap(NULL, ~0, &psurge_host_ops, NULL);
- 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);
- }
- }
+ if (psurge_host)
+ psurge_secondary_virq = irq_create_direct_mapping(psurge_host);
+
+ if (psurge_secondary_virq)
+ rc = request_irq(psurge_secondary_virq, psurge_ipi_intr,
+ IRQF_PERCPU | IRQF_NO_THREAD, "IPI", NULL);
+
+ if (rc)
+ pr_err("Failed to setup secondary cpu IPI\n");
+
+ return rc;
}
/*
@@ -267,6 +271,7 @@ static void __init psurge_quad_init(void)
static int __init smp_psurge_probe(void)
{
int i, ncpus;
+ struct device_node *dn;
/* We don't do SMP on the PPC601 -- paulus */
if (PVR_VER(mfspr(SPRN_PVR)) == 1)
@@ -282,8 +287,10 @@ static int __init smp_psurge_probe(void)
* in the hammerhead memory controller in the case of the
* dual-cpu powersurge board. -- paulus.
*/
- if (find_devices("hammerhead") == NULL)
+ dn = of_find_node_by_name(NULL, "hammerhead");
+ if (dn == NULL)
return 1;
+ of_node_put(dn);
hhead_base = ioremap(HAMMERHEAD_BASE, 0x800);
quad_base = ioremap(PSURGE_QUAD_REG_ADDR, 1024);
@@ -294,6 +301,9 @@ static int __init smp_psurge_probe(void)
psurge_quad_init();
/* All released cards using this HW design have 4 CPUs */
ncpus = 4;
+ /* No sure how timebase sync works on those, let's use SW */
+ smp_ops->give_timebase = smp_generic_give_timebase;
+ smp_ops->take_timebase = smp_generic_take_timebase;
} else {
iounmap(quad_base);
if ((in_8(hhead_base + HHEAD_CONFIG) & 0x02) == 0) {
@@ -305,32 +315,38 @@ static int __init smp_psurge_probe(void)
ncpus = 2;
}
+ if (psurge_secondary_ipi_init())
+ return 1;
+
psurge_start = ioremap(PSURGE_START, 4);
psurge_pri_intr = ioremap(PSURGE_PRI_INTR, 4);
- /*
- * This is necessary because OF doesn't know about the
+ /* This is necessary because OF doesn't know about the
* secondary cpu(s), and thus there aren't nodes in the
* device tree for them, and smp_setup_cpu_maps hasn't
- * set their bits in cpu_possible_map and cpu_present_map.
+ * set their bits in cpu_present_mask.
*/
if (ncpus > NR_CPUS)
ncpus = NR_CPUS;
- for (i = 1; i < ncpus ; ++i) {
- cpu_set(i, cpu_present_map);
- cpu_set(i, cpu_possible_map);
- set_hard_smp_processor_id(i, i);
- }
+ for (i = 1; i < ncpus ; ++i)
+ set_cpu_present(i, true);
if (ppc_md.progress) ppc_md.progress("smp_psurge_probe - done", 0x352);
return ncpus;
}
-static void __init smp_psurge_kick_cpu(int nr)
+static int __init smp_psurge_kick_cpu(int nr)
{
unsigned long start = __pa(__secondary_start_pmac_0) + nr * 8;
- unsigned long a;
+ unsigned long a, flags;
+ int i, j;
+
+ /* Defining this here is evil ... but I prefer hiding that
+ * crap to avoid giving people ideas that they can do the
+ * same.
+ */
+ extern volatile unsigned int cpu_callin_map[NR_CPUS];
/* may need to flush here if secondary bats aren't setup */
for (a = KERNELBASE; a < KERNELBASE + 0x800000; a += 32)
@@ -339,104 +355,111 @@ static void __init smp_psurge_kick_cpu(int nr)
if (ppc_md.progress) ppc_md.progress("smp_psurge_kick_cpu", 0x353);
+ /* This is going to freeze the timeebase, we disable interrupts */
+ local_irq_save(flags);
+
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);
- /* XXX fixme */
- set_tb(0, 0);
+ /*
+ * We can't use udelay here because the timebase is now frozen.
+ */
+ for (i = 0; i < 2000; ++i)
+ asm volatile("nop" : : : "memory");
+ psurge_clr_ipi(nr);
- if (cpu_nr > 0) {
+ /*
+ * Also, because the timebase is frozen, we must not return to the
+ * caller which will try to do udelay's etc... Instead, we wait -here-
+ * for the CPU to callin.
+ */
+ for (i = 0; i < 100000 && !cpu_callin_map[nr]; ++i) {
+ for (j = 1; j < 10000; j++)
+ asm volatile("nop" : : : "memory");
+ asm volatile("sync" : : : "memory");
+ }
+ if (!cpu_callin_map[nr])
+ goto stuck;
+
+ /* And we do the TB sync here too for standard dual CPU cards */
+ if (psurge_type == PSURGE_DUAL) {
+ while(!tb_req)
+ barrier();
+ tb_req = 0;
+ mb();
+ timebase = get_tb();
+ mb();
+ while (timebase)
+ barrier();
mb();
- sec_tb_reset = 1;
- return;
}
+ stuck:
+ /* now interrupt the secondary, restarting both TBs */
+ if (psurge_type == PSURGE_DUAL)
+ psurge_set_ipi(1);
- /* wait for the secondary to have reset its TB before proceeding */
- for (t = 10000000; t > 0 && !sec_tb_reset; --t)
- ;
+ if (ppc_md.progress) ppc_md.progress("smp_psurge_kick_cpu - done", 0x354);
- /* now interrupt the secondary, starting both TBs */
- psurge_set_ipi(1);
+ return 0;
}
static struct irqaction psurge_irqaction = {
- .handler = psurge_primary_intr,
- .flags = SA_INTERRUPT,
- .mask = CPU_MASK_NONE,
+ .handler = psurge_ipi_intr,
+ .flags = IRQF_PERCPU | IRQF_NO_THREAD,
.name = "primary IPI",
};
static void __init smp_psurge_setup_cpu(int cpu_nr)
{
+ if (cpu_nr != 0 || !psurge_start)
+ return;
- 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);
+ /* 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(irq_create_mapping(NULL, 30), &psurge_irqaction))
+ printk(KERN_ERR "Couldn't get primary IPI interrupt");
}
void __init smp_psurge_take_timebase(void)
{
- /* Dummy implementation */
+ if (psurge_type != PSURGE_DUAL)
+ return;
+
+ tb_req = 1;
+ mb();
+ while (!timebase)
+ barrier();
+ mb();
+ set_tb(timebase >> 32, timebase & 0xffffffff);
+ timebase = 0;
+ mb();
+ set_dec(tb_ticks_per_jiffy/2);
}
void __init smp_psurge_give_timebase(void)
{
- /* Dummy implementation */
+ /* Nothing to do here */
}
/* PowerSurge-style Macs */
struct smp_ops_t psurge_smp_ops = {
- .message_pass = smp_psurge_message_pass,
+ .message_pass = NULL, /* Use smp_muxed_ipi_message_pass */
+ .cause_ipi = smp_psurge_cause_ipi,
.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,
};
-#endif /* CONFIG_PPC32 - actually powersurge support */
+#endif /* CONFIG_PPC_PMAC32_PSURGE */
/*
* Core 99 and later support
*/
-static void (*pmac_tb_freeze)(int freeze);
-static unsigned long timebase;
-static int tb_req;
static void smp_core99_give_timebase(void)
{
@@ -461,7 +484,7 @@ static void smp_core99_give_timebase(void)
}
-static void __devinit smp_core99_take_timebase(void)
+static void smp_core99_take_timebase(void)
{
unsigned long flags;
@@ -475,7 +498,6 @@ static void __devinit smp_core99_take_timebase(void)
set_tb(timebase >> 32, timebase & 0xffffffff);
timebase = 0;
mb();
- set_dec(tb_ticks_per_jiffy/2);
local_irq_restore(flags);
}
@@ -551,13 +573,13 @@ static void __init smp_core99_setup_i2c_hwsync(int ncpus)
struct device_node *cc = NULL;
struct device_node *p;
const char *name = NULL;
- u32 *reg;
+ const u32 *reg;
int ok;
/* Look for the clock chip */
while ((cc = of_find_node_by_name(cc, "i2c-hwclock")) != NULL) {
p = of_get_parent(cc);
- ok = p && device_is_compatible(p, "uni-n-i2c");
+ ok = p && of_device_is_compatible(p, "uni-n-i2c");
of_node_put(p);
if (!ok)
continue;
@@ -565,16 +587,16 @@ static void __init smp_core99_setup_i2c_hwsync(int ncpus)
pmac_tb_clock_chip_host = pmac_i2c_find_bus(cc);
if (pmac_tb_clock_chip_host == NULL)
continue;
- reg = (u32 *)get_property(cc, "reg", NULL);
+ reg = of_get_property(cc, "reg", NULL);
if (reg == NULL)
continue;
switch (*reg) {
case 0xd2:
- if (device_is_compatible(cc,"pulsar-legacy-slewing")) {
+ if (of_device_is_compatible(cc,"pulsar-legacy-slewing")) {
pmac_tb_freeze = smp_core99_pulsar_tb_freeze;
pmac_tb_pulsar_addr = 0xd2;
name = "Pulsar";
- } else if (device_is_compatible(cc, "cy28508")) {
+ } else if (of_device_is_compatible(cc, "cy28508")) {
pmac_tb_freeze = smp_core99_cypress_tb_freeze;
name = "Cypress";
}
@@ -647,7 +669,7 @@ static void smp_core99_gpio_tb_freeze(int freeze)
volatile static long int core99_l2_cache;
volatile static long int core99_l3_cache;
-static void __devinit core99_init_caches(int cpu)
+static void core99_init_caches(int cpu)
{
#ifndef CONFIG_PPC64
if (!cpu_has_feature(CPU_FTR_L2CR))
@@ -683,9 +705,9 @@ static void __init smp_core99_setup(int ncpus)
#ifdef CONFIG_PPC64
/* i2c based HW sync on some G5s */
- if (machine_is_compatible("PowerMac7,2") ||
- machine_is_compatible("PowerMac7,3") ||
- machine_is_compatible("RackMac3,1"))
+ if (of_machine_is_compatible("PowerMac7,2") ||
+ of_machine_is_compatible("PowerMac7,3") ||
+ of_machine_is_compatible("RackMac3,1"))
smp_core99_setup_i2c_hwsync(ncpus);
/* pfunc based HW sync on recent G5s */
@@ -693,7 +715,7 @@ static void __init smp_core99_setup(int ncpus)
struct device_node *cpus =
of_find_node_by_path("/cpus");
if (cpus &&
- get_property(cpus, "platform-cpu-timebase", NULL)) {
+ of_get_property(cpus, "platform-cpu-timebase", NULL)) {
pmac_tb_freeze = smp_core99_pfunc_tb_freeze;
printk(KERN_INFO "Processor timebase sync using"
" platform function\n");
@@ -703,15 +725,14 @@ static void __init smp_core99_setup(int ncpus)
#else /* CONFIG_PPC64 */
/* GPIO based HW sync on ppc32 Core99 */
- if (pmac_tb_freeze == NULL && !machine_is_compatible("MacRISC4")) {
+ if (pmac_tb_freeze == NULL && !of_machine_is_compatible("MacRISC4")) {
struct device_node *cpu;
- u32 *tbprop = NULL;
+ const u32 *tbprop = NULL;
core99_tb_gpio = KL_GPIO_TB_ENABLE; /* default value */
cpu = of_find_node_by_type(NULL, "cpu");
if (cpu != NULL) {
- tbprop = (u32 *)get_property(cpu, "timebase-enable",
- NULL);
+ tbprop = of_get_property(cpu, "timebase-enable", NULL);
if (tbprop)
core99_tb_gpio = *tbprop;
of_node_put(cpu);
@@ -736,12 +757,12 @@ static void __init smp_core99_setup(int ncpus)
/* XXX should get this from reg properties */
for (i = 1; i < ncpus; ++i)
- smp_hw_index[i] = i;
+ set_hard_smp_processor_id(i, i);
}
#endif
/* 32 bits SMP can't NAP */
- if (!machine_is_compatible("MacRISC4"))
+ if (!of_machine_is_compatible("MacRISC4"))
powersave_nap = 0;
}
@@ -780,30 +801,28 @@ static int __init smp_core99_probe(void)
return ncpus;
}
-static void __devinit smp_core99_kick_cpu(int nr)
+static int smp_core99_kick_cpu(int nr)
{
unsigned int save_vector;
unsigned long target, flags;
- volatile unsigned int *vector
- = ((volatile unsigned int *)(KERNELBASE+0x100));
+ unsigned int *vector = (unsigned int *)(PAGE_OFFSET+0x100);
if (nr < 0 || nr > 3)
- return;
+ return -ENOENT;
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
+ * b __secondary_start_pmac_0 + nr*8
*/
target = (unsigned long) __secondary_start_pmac_0 + nr * 8;
- create_branch((unsigned long)vector, target, BRANCH_SET_LINK);
+ patch_branch(vector, target, BRANCH_SET_LINK);
/* Put some life in our friend */
pmac_call_feature(PMAC_FTR_RESET_CPU, NULL, nr, 0);
@@ -821,9 +840,11 @@ static void __devinit smp_core99_kick_cpu(int nr)
local_irq_restore(flags);
if (ppc_md.progress) ppc_md.progress("smp_core99_kick_cpu done", 0x347);
+
+ return 0;
}
-static void __devinit smp_core99_setup_cpu(int cpu_nr)
+static void smp_core99_setup_cpu(int cpu_nr)
{
/* Setup L2/L3 */
if (cpu_nr != 0)
@@ -831,84 +852,186 @@ static void __devinit smp_core99_setup_cpu(int cpu_nr)
/* Setup openpic */
mpic_setup_this_cpu();
+}
- if (cpu_nr == 0) {
#ifdef CONFIG_PPC64
- extern void g5_phy_disable_cpu1(void);
+#ifdef CONFIG_HOTPLUG_CPU
+static int smp_core99_cpu_notify(struct notifier_block *self,
+ unsigned long action, void *hcpu)
+{
+ int rc;
- /* Close i2c bus if it was used for tb sync */
+ switch(action) {
+ case CPU_UP_PREPARE:
+ case CPU_UP_PREPARE_FROZEN:
+ /* Open i2c bus if it was used for tb sync */
if (pmac_tb_clock_chip_host) {
- pmac_i2c_close(pmac_tb_clock_chip_host);
- pmac_tb_clock_chip_host = NULL;
+ rc = pmac_i2c_open(pmac_tb_clock_chip_host, 1);
+ if (rc) {
+ pr_err("Failed to open i2c bus for time sync\n");
+ return notifier_from_errno(rc);
+ }
}
+ break;
+ case CPU_ONLINE:
+ case CPU_UP_CANCELED:
+ /* Close i2c bus if it was used for tb sync */
+ if (pmac_tb_clock_chip_host)
+ pmac_i2c_close(pmac_tb_clock_chip_host);
+ break;
+ default:
+ break;
+ }
+ return NOTIFY_OK;
+}
- /* 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_PPC64 */
+static struct notifier_block smp_core99_cpu_nb = {
+ .notifier_call = smp_core99_cpu_notify,
+};
+#endif /* CONFIG_HOTPLUG_CPU */
- if (ppc_md.progress)
- ppc_md.progress("core99_setup_cpu 0 done", 0x349);
+static void __init smp_core99_bringup_done(void)
+{
+ extern void g5_phy_disable_cpu1(void);
+
+ /* Close i2c bus if it was used for tb sync */
+ if (pmac_tb_clock_chip_host)
+ pmac_i2c_close(pmac_tb_clock_chip_host);
+
+ /* If we didn't start the second CPU, we must take
+ * it off the bus.
+ */
+ if (of_machine_is_compatible("MacRISC4") &&
+ num_online_cpus() < 2) {
+ set_cpu_present(1, false);
+ g5_phy_disable_cpu1();
}
-}
+#ifdef CONFIG_HOTPLUG_CPU
+ register_cpu_notifier(&smp_core99_cpu_nb);
+#endif
+ if (ppc_md.progress)
+ ppc_md.progress("smp_core99_bringup_done", 0x349);
+}
+#endif /* CONFIG_PPC64 */
-#if defined(CONFIG_HOTPLUG_CPU) && defined(CONFIG_PPC32)
+#ifdef CONFIG_HOTPLUG_CPU
-int smp_core99_cpu_disable(void)
+static int smp_core99_cpu_disable(void)
{
- cpu_clear(smp_processor_id(), cpu_online_map);
+ int rc = generic_cpu_disable();
+ if (rc)
+ return rc;
- /* 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 sleep.S */
-static int cpu_dead[NR_CPUS];
+#ifdef CONFIG_PPC32
-void cpu_die(void)
+static void pmac_cpu_die(void)
{
+ int cpu = smp_processor_id();
+
local_irq_disable();
- cpu_dead[smp_processor_id()] = 1;
+ idle_task_exit();
+ pr_debug("CPU%d offline\n", cpu);
+ generic_set_cpu_dead(cpu);
+ smp_wmb();
mb();
low_cpu_die();
}
-void smp_core99_cpu_die(unsigned int cpu)
+#else /* CONFIG_PPC32 */
+
+static void pmac_cpu_die(void)
{
- int timeout;
+ int cpu = smp_processor_id();
- timeout = 1000;
- while (!cpu_dead[cpu]) {
- if (--timeout == 0) {
- printk("CPU %u refused to die!\n", cpu);
- break;
- }
- msleep(1);
+ local_irq_disable();
+ idle_task_exit();
+
+ /*
+ * turn off as much as possible, we'll be
+ * kicked out as this will only be invoked
+ * on core99 platforms for now ...
+ */
+
+ printk(KERN_INFO "CPU#%d offline\n", cpu);
+ generic_set_cpu_dead(cpu);
+ smp_wmb();
+
+ /*
+ * Re-enable interrupts. The NAP code needs to enable them
+ * anyways, do it now so we deal with the case where one already
+ * happened while soft-disabled.
+ * We shouldn't get any external interrupts, only decrementer, and the
+ * decrementer handler is safe for use on offline CPUs
+ */
+ local_irq_enable();
+
+ while (1) {
+ /* let's not take timer interrupts too often ... */
+ set_dec(0x7fffffff);
+
+ /* Enter NAP mode */
+ power4_idle();
}
- cpu_dead[cpu] = 0;
}
-#endif
+#endif /* else CONFIG_PPC32 */
+#endif /* CONFIG_HOTPLUG_CPU */
/* Core99 Macs (dual G4s and G5s) */
struct smp_ops_t core99_smp_ops = {
.message_pass = smp_mpic_message_pass,
.probe = smp_core99_probe,
+#ifdef CONFIG_PPC64
+ .bringup_done = smp_core99_bringup_done,
+#endif
.kick_cpu = smp_core99_kick_cpu,
.setup_cpu = smp_core99_setup_cpu,
.give_timebase = smp_core99_give_timebase,
.take_timebase = smp_core99_take_timebase,
-#if defined(CONFIG_HOTPLUG_CPU) && defined(CONFIG_PPC32)
+#if defined(CONFIG_HOTPLUG_CPU)
.cpu_disable = smp_core99_cpu_disable,
- .cpu_die = smp_core99_cpu_die,
+ .cpu_die = generic_cpu_die,
#endif
};
+
+void __init pmac_setup_smp(void)
+{
+ struct device_node *np;
+
+ /* Check for Core99 */
+ np = of_find_node_by_name(NULL, "uni-n");
+ if (!np)
+ np = of_find_node_by_name(NULL, "u3");
+ if (!np)
+ np = of_find_node_by_name(NULL, "u4");
+ if (np) {
+ of_node_put(np);
+ smp_ops = &core99_smp_ops;
+ }
+#ifdef CONFIG_PPC_PMAC32_PSURGE
+ else {
+ /* We have to set bits in cpu_possible_mask here since the
+ * secondary CPU(s) aren't in the device tree. Various
+ * things won't be initialized for CPUs not in the possible
+ * map, so we really need to fix it up here.
+ */
+ int cpu;
+
+ for (cpu = 1; cpu < 4 && cpu < NR_CPUS; ++cpu)
+ set_cpu_possible(cpu, true);
+ smp_ops = &psurge_smp_ops;
+ }
+#endif /* CONFIG_PPC_PMAC32_PSURGE */
+
+#ifdef CONFIG_HOTPLUG_CPU
+ ppc_md.cpu_die = pmac_cpu_die;
+#endif
+}
+
+
diff --git a/arch/powerpc/platforms/powermac/time.c b/arch/powerpc/platforms/powermac/time.c
index 5d9afa1fa02..8680bb69795 100644
--- a/arch/powerpc/platforms/powermac/time.c
+++ b/arch/powerpc/platforms/powermac/time.c
@@ -9,7 +9,6 @@
* Copyright (C) 2003-2005 Benjamin Herrenschmidt.
*
*/
-#include <linux/config.h>
#include <linux/errno.h>
#include <linux/sched.h>
#include <linux/kernel.h>
@@ -27,7 +26,6 @@
#include <asm/sections.h>
#include <asm/prom.h>
-#include <asm/system.h>
#include <asm/io.h>
#include <asm/pgtable.h>
#include <asm/machdep.h>
@@ -85,18 +83,23 @@ long __init pmac_time_init(void)
return delta;
}
+#if defined(CONFIG_ADB_CUDA) || defined(CONFIG_ADB_PMU)
static void to_rtc_time(unsigned long now, struct rtc_time *tm)
{
to_tm(now, tm);
tm->tm_year -= 1900;
tm->tm_mon -= 1;
}
+#endif
+#if defined(CONFIG_ADB_CUDA) || defined(CONFIG_ADB_PMU) || \
+ defined(CONFIG_PMAC_SMU)
static unsigned long from_rtc_time(struct rtc_time *tm)
{
return mktime(tm->tm_year+1900, tm->tm_mon+1, tm->tm_mday,
tm->tm_hour, tm->tm_min, tm->tm_sec);
}
+#endif
#ifdef CONFIG_ADB_CUDA
static unsigned long cuda_get_time(void)
@@ -261,13 +264,16 @@ int __init via_calibrate_decr(void)
struct resource rsrc;
vias = of_find_node_by_name(NULL, "via-cuda");
- if (vias == 0)
+ if (vias == NULL)
vias = of_find_node_by_name(NULL, "via-pmu");
- if (vias == 0)
+ if (vias == NULL)
vias = of_find_node_by_name(NULL, "via");
- if (vias == 0 || of_address_to_resource(vias, 0, &rsrc))
+ if (vias == NULL || of_address_to_resource(vias, 0, &rsrc)) {
+ of_node_put(vias);
return 0;
- via = ioremap(rsrc.start, rsrc.end - rsrc.start + 1);
+ }
+ of_node_put(vias);
+ via = ioremap(rsrc.start, resource_size(&rsrc));
if (via == NULL) {
printk(KERN_ERR "Failed to map VIA for timer calibration !\n");
return 0;
@@ -293,54 +299,16 @@ int __init via_calibrate_decr(void)
ppc_tb_freq = (dstart - dend) * 100 / 6;
iounmap(via);
-
+
return 1;
}
#endif
-#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;
- struct timespec tv;
-
- switch (when) {
- case PBOOK_SLEEP_NOW:
- do {
- seq = read_seqbegin_irqsave(&xtime_lock, flags);
- time_diff = xtime.tv_sec - pmac_get_boot_time();
- } while (read_seqretry_irqrestore(&xtime_lock, seq, flags));
- break;
- case PBOOK_WAKE:
- tv.tv_sec = pmac_get_boot_time() + time_diff;
- tv.tv_nsec = 0;
- do_settimeofday(&tv);
- 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.
*/
void __init pmac_calibrate_decr(void)
{
-#ifdef CONFIG_PM
- /* XXX why here? */
- pmu_register_sleep_notifier(&time_sleep_notifier);
-#endif /* CONFIG_PM */
-
generic_calibrate_decr();
#ifdef CONFIG_PPC32
@@ -348,9 +316,9 @@ void __init pmac_calibrate_decr(void)
* 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 (!of_machine_is_compatible("MacRISC2") &&
+ !of_machine_is_compatible("MacRISC3") &&
+ !of_machine_is_compatible("MacRISC4"))
if (via_calibrate_decr())
return;
@@ -359,7 +327,7 @@ void __init pmac_calibrate_decr(void)
* probably implement calibration based on the KL timer on these
* machines anyway... -BenH
*/
- if (machine_is_compatible("PowerMac3,5"))
+ if (of_machine_is_compatible("PowerMac3,5"))
if (via_calibrate_decr())
return;
#endif
diff --git a/arch/powerpc/platforms/powermac/udbg_adb.c b/arch/powerpc/platforms/powermac/udbg_adb.c
index 06c8265c2ba..44e0b55a2a0 100644
--- a/arch/powerpc/platforms/powermac/udbg_adb.c
+++ b/arch/powerpc/platforms/powermac/udbg_adb.c
@@ -1,4 +1,3 @@
-#include <linux/config.h>
#include <linux/string.h>
#include <linux/kernel.h>
#include <linux/errno.h>
@@ -13,7 +12,6 @@
#include <asm/xmon.h>
#include <asm/prom.h>
#include <asm/bootx.h>
-#include <asm/machdep.h>
#include <asm/errno.h>
#include <asm/pmac_feature.h>
#include <asm/processor.h>
@@ -151,7 +149,7 @@ static void udbg_adb_putc(char c)
return udbg_adb_old_putc(c);
}
-void udbg_adb_init_early(void)
+void __init udbg_adb_init_early(void)
{
#ifdef CONFIG_BOOTX_TEXT
if (btext_find_display(1) == 0) {
@@ -161,7 +159,7 @@ void udbg_adb_init_early(void)
#endif
}
-int udbg_adb_init(int force_btext)
+int __init udbg_adb_init(int force_btext)
{
struct device_node *np;
diff --git a/arch/powerpc/platforms/powermac/udbg_scc.c b/arch/powerpc/platforms/powermac/udbg_scc.c
index c4352a8db64..d83135a9830 100644
--- a/arch/powerpc/platforms/powermac/udbg_scc.c
+++ b/arch/powerpc/platforms/powermac/udbg_scc.c
@@ -1,5 +1,5 @@
/*
- * udbg for for zilog scc ports as found on Apple PowerMacs
+ * udbg for zilog scc ports as found on Apple PowerMacs
*
* Copyright (C) 2001-2005 PPC 64 Team, IBM Corp
*
@@ -8,7 +8,6 @@
* 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/types.h>
#include <asm/udbg.h>
#include <asm/processor.h>
@@ -69,11 +68,11 @@ static unsigned char scc_inittab[] = {
void udbg_scc_init(int force_scc)
{
- u32 *reg;
+ const u32 *reg;
unsigned long addr;
struct device_node *stdout = NULL, *escc = NULL, *macio = NULL;
struct device_node *ch, *ch_def = NULL, *ch_a = NULL;
- char *path;
+ const char *path;
int i, x;
escc = of_find_node_by_name(NULL, "escc");
@@ -82,7 +81,7 @@ void udbg_scc_init(int force_scc)
macio = of_get_parent(escc);
if (macio == NULL)
goto bail;
- path = (char *)get_property(of_chosen, "linux,stdout-path", NULL);
+ path = of_get_property(of_chosen, "linux,stdout-path", NULL);
if (path != NULL)
stdout = of_find_node_by_path(path);
for (ch = NULL; (ch = of_get_next_child(escc, ch)) != NULL;) {
@@ -97,13 +96,13 @@ void udbg_scc_init(int force_scc)
ch = ch_def ? ch_def : ch_a;
/* Get address within mac-io ASIC */
- reg = (u32 *)get_property(escc, "reg", NULL);
+ reg = of_get_property(escc, "reg", NULL);
if (reg == NULL)
goto bail;
addr = reg[0];
/* Get address of mac-io PCI itself */
- reg = (u32 *)get_property(macio, "assigned-addresses", NULL);
+ reg = of_get_property(macio, "assigned-addresses", NULL);
if (reg == NULL)
goto bail;
addr += reg[2];
@@ -112,11 +111,9 @@ void udbg_scc_init(int force_scc)
pmac_call_feature(PMAC_FTR_SCC_ENABLE, ch,
PMAC_SCC_ASYNC | PMAC_SCC_FLAG_XMON, 1);
-
- /* Setup for 57600 8N1 */
if (ch == ch_a)
addr += 0x20;
- sccc = (volatile u8 * __iomem) ioremap(addr & PAGE_MASK, PAGE_SIZE) ;
+ sccc = ioremap(addr & PAGE_MASK, PAGE_SIZE) ;
sccc += addr & ~PAGE_MASK;
sccd = sccc + 0x10;
@@ -126,9 +123,31 @@ void udbg_scc_init(int force_scc)
x = in_8(sccc);
out_8(sccc, 0x09); /* reset A or B side */
out_8(sccc, 0xc0);
+
+ /* If SCC was the OF output port, read the BRG value, else
+ * Setup for 38400 or 57600 8N1 depending on the machine
+ */
+ if (ch_def != NULL) {
+ out_8(sccc, 13);
+ scc_inittab[1] = in_8(sccc);
+ out_8(sccc, 12);
+ scc_inittab[3] = in_8(sccc);
+ } else if (of_machine_is_compatible("RackMac1,1")
+ || of_machine_is_compatible("RackMac1,2")
+ || of_machine_is_compatible("MacRISC4")) {
+ /* Xserves and G5s default to 57600 */
+ scc_inittab[1] = 0;
+ scc_inittab[3] = 0;
+ } else {
+ /* Others default to 38400 */
+ scc_inittab[1] = 0;
+ scc_inittab[3] = 1;
+ }
+
for (i = 0; i < sizeof(scc_inittab); ++i)
out_8(sccc, scc_inittab[i]);
+
udbg_putc = udbg_scc_putc;
udbg_getc = udbg_scc_getc;
udbg_getc_poll = udbg_scc_getc_poll;