* Re: [PATCH] powerpc: Add FSL SOC library and setup code
From: Olof Johansson @ 2006-01-14 19:21 UTC (permalink / raw)
To: Kumar Gala; +Cc: linuxppc-dev, linuxppc-embedded
In-Reply-To: <Pine.LNX.4.44.0601131118350.19371-100000@gate.crashing.org>
Hi,
On Fri, Jan 13, 2006 at 11:19:13AM -0600, Kumar Gala wrote:
> Parse the flat device tree for devices on Freescale SOC's that we know
> about (gianfar, gianfar_mdio, i2c, mpc83xx_wdt). We need to setup
> platform devices and platform data for these devices to match arch/ppc
> usage.
>
> Also add a helper function (get_immrbase) that reports the base
> address of the MMIO registers on the SOC.
Besides the specific comments below, you have long lines in some
places. Can you break them at 78-80 columns? I know it's awkward when
a function name is 30 characters, but still.
Thanks,
Olof
>
> Signed-off-by: Kumar Gala <galak@kernel.crashing.org>
>
> ---
> commit 8699b259e5432c100d06ea406616453a2ccc1989
> tree ad1a3444ab98051bf6e88a10ca3d6aa27e6ec822
> parent 461d4edf6f4a1950a94a190f1fc3a4b9e692453e
> author Kumar Gala <galak@kernel.crashing.org> Fri, 13 Jan 2006 11:20:44 -0600
> committer Kumar Gala <galak@kernel.crashing.org> Fri, 13 Jan 2006 11:20:44 -0600
>
> arch/powerpc/sysdev/Makefile | 1
> arch/powerpc/sysdev/fsl_soc.c | 317 +++++++++++++++++++++++++++++++++++++++++
> arch/powerpc/sysdev/fsl_soc.h | 8 +
> 3 files changed, 326 insertions(+), 0 deletions(-)
>
> diff --git a/arch/powerpc/sysdev/Makefile b/arch/powerpc/sysdev/Makefile
> index 0ae8413..4c2b356 100644
> --- a/arch/powerpc/sysdev/Makefile
> +++ b/arch/powerpc/sysdev/Makefile
> @@ -7,3 +7,4 @@ obj-$(CONFIG_40x) += dcr.o
> obj-$(CONFIG_U3_DART) += dart_iommu.o
> obj-$(CONFIG_MMIO_NVRAM) += mmio_nvram.o
> obj-$(CONFIG_PPC_83xx) += ipic.o
> +obj-$(CONFIG_FSL_SOC) += fsl_soc.o
> diff --git a/arch/powerpc/sysdev/fsl_soc.c b/arch/powerpc/sysdev/fsl_soc.c
> new file mode 100644
> index 0000000..064c9de
> --- /dev/null
> +++ b/arch/powerpc/sysdev/fsl_soc.c
> @@ -0,0 +1,317 @@
> +/*
> + * FSL SoC setup code
Maybe explain that FSL is Freescale?
> + *
> + * Maintained by Kumar Gala (see MAINTAINERS for contact information)
> + *
> + * This program is free software; you can redistribute it and/or modify it
> + * under the terms of the GNU General Public License as published by the
> + * Free Software Foundation; either version 2 of the License, or (at your
> + * option) any later version.
> + */
> +
> +#include <linux/config.h>
> +#include <linux/stddef.h>
> +#include <linux/kernel.h>
> +#include <linux/init.h>
> +#include <linux/errno.h>
> +#include <linux/major.h>
> +#include <linux/delay.h>
> +#include <linux/irq.h>
> +#include <linux/module.h>
> +#include <linux/device.h>
> +#include <linux/platform_device.h>
> +#include <linux/fsl_devices.h>
> +
> +#include <asm/system.h>
> +#include <asm/atomic.h>
> +#include <asm/io.h>
> +#include <asm/irq.h>
> +#include <asm/prom.h>
> +#include <sysdev/fsl_soc.h>
> +#include <mm/mmu_decl.h>
> +
> +static phys_addr_t immrbase = -1;
What does immr mean? Maybe a short comment would be good.
> +
> +phys_addr_t get_immrbase(void)
> +{
> + struct device_node *soc;
> +
> + if (immrbase != -1)
> + return immrbase;
> +
> + soc = of_find_node_by_type(NULL, "soc");
> + if (soc != 0) {
Compare with NULL instead, since it's a pointer? (or just if (soc))
> + unsigned int size;
> + void *prop = get_property(soc, "reg", &size);
> + immrbase = of_translate_address(soc, prop);
> + of_node_put(soc);
> + };
> +
> + return immrbase;
> +}
> +EXPORT_SYMBOL(get_immrbase);
> +
> +static const char * gfar_tx_intr = "tx";
> +static const char * gfar_rx_intr = "rx";
> +static const char * gfar_err_intr = "error";
> +
> +static int __init gfar_of_init(void)
> +{
> + struct device_node *np;
> + unsigned int i;
> + struct platform_device *mdio_dev, *gfar_dev;
> + struct resource res;
> + int ret;
> +
> + for (np = NULL, i = 0; (np = of_find_compatible_node(np, "mdio", "gianfar")) != NULL; i++) {
Long line, please try to keep them 78-80 characters max.
Maybe a primitive for iterating over compatible nodes would be useful in
other places too.
> + int k;
> + struct device_node *child = NULL;
> + struct gianfar_mdio_data mdio_data;
> +
> + memset(&res, 0, sizeof(res));
> + memset(&mdio_data, 0, sizeof(mdio_data));
> +
> + ret = of_address_to_resource(np, 0, &res);
> + if (ret)
> + goto mdio_err;
> +
> + mdio_dev = platform_device_register_simple("fsl-gianfar_mdio", res.start, &res, 1);
> + if (IS_ERR(mdio_dev)) {
> + ret = PTR_ERR(mdio_dev);
> + goto mdio_err;
> + }
> +
> + for (k = 0; k < 32; k++)
> + mdio_data.irq[k] = -1;
> +
> + while ((child = of_get_next_child(np, child)) != NULL) {
> + if (child->n_intrs) {
> + u32 *id = (u32 *) get_property(child, "reg", NULL);
> + mdio_data.irq[*id] = child->intrs[0].line;
> + }
> + }
> +
> + ret = platform_device_add_data(mdio_dev, &mdio_data, sizeof(struct gianfar_mdio_data));
> + if (ret)
> + goto mdio_unreg;
> + }
> +
> + for (np = NULL, i = 0; (np = of_find_compatible_node(np, "network", "gianfar")) != NULL; i++) {
> + struct resource r[4];
> + struct device_node *phy, *mdio;
> + struct gianfar_platform_data gfar_data;
> + unsigned int *id;
> + char *model;
> + void *mac_addr;
> + phandle *ph;
> +
> + memset(r, 0, sizeof(r));
> + memset(&gfar_data, 0, sizeof(gfar_data));
> +
> + ret = of_address_to_resource(np, 0, &r[0]);
> + if (ret)
> + goto gfar_err;
> +
> + r[1].start = np->intrs[0].line;
> + r[1].end = np->intrs[0].line;
> + r[1].flags = IORESOURCE_IRQ;
> +
> + model = get_property(np, "model", NULL);
> +
> + /* If we aren't the FEC we have multiple interrupts */
> + if (model && strcasecmp(model, "FEC")) {
> + r[1].name = gfar_tx_intr;
> +
> + r[2].name = gfar_rx_intr;
> + r[2].start = np->intrs[1].line;
> + r[2].end = np->intrs[1].line;
> + r[2].flags = IORESOURCE_IRQ;
> +
> + r[3].name = gfar_err_intr;
> + r[3].start = np->intrs[2].line;
> + r[3].end = np->intrs[2].line;
> + r[3].flags = IORESOURCE_IRQ;
> + }
> +
> + gfar_dev = platform_device_register_simple("fsl-gianfar", i, &r[0], np->n_intrs + 1);
> +
> + if (IS_ERR(gfar_dev)) {
> + ret = PTR_ERR(gfar_dev);
> + goto gfar_err;
> + }
> +
> + mac_addr = get_property(np, "address", NULL);
> + memcpy(gfar_data.mac_addr, mac_addr, 6);
> +
> + if (model && !strcasecmp(model, "TSEC"))
> + gfar_data.device_flags =
> + FSL_GIANFAR_DEV_HAS_GIGABIT |
> + FSL_GIANFAR_DEV_HAS_COALESCE |
> + FSL_GIANFAR_DEV_HAS_RMON |
> + FSL_GIANFAR_DEV_HAS_MULTI_INTR;
> + if (model && !strcasecmp(model, "eTSEC"))
> + gfar_data.device_flags =
> + FSL_GIANFAR_DEV_HAS_GIGABIT |
> + FSL_GIANFAR_DEV_HAS_COALESCE |
> + FSL_GIANFAR_DEV_HAS_RMON |
> + FSL_GIANFAR_DEV_HAS_MULTI_INTR |
> + FSL_GIANFAR_DEV_HAS_CSUM |
> + FSL_GIANFAR_DEV_HAS_VLAN |
> + FSL_GIANFAR_DEV_HAS_EXTENDED_HASH;
> +
> + ph = (phandle *) get_property(np, "phy-handle", NULL);
> + phy = of_find_node_by_phandle(*ph);
> +
> + if (phy == NULL) {
> + ret = -ENODEV;
> + goto gfar_unreg;
> + }
> +
> + mdio = of_get_parent(phy);
> +
> + id = (u32 *) get_property(phy, "reg", NULL);
> + ret = of_address_to_resource(mdio, 0, &res);
> + if (ret) {
> + of_node_put(phy);
> + of_node_put(mdio);
> + goto gfar_unreg;
> + }
> +
> + gfar_data.phy_id = *id;
> + gfar_data.bus_id = res.start;
> +
> + of_node_put(phy);
> + of_node_put(mdio);
> +
> + ret = platform_device_add_data(gfar_dev, &gfar_data, sizeof(struct gianfar_platform_data));
> + if (ret)
> + goto gfar_unreg;
> + }
> +
> + return 0;
> +
> +mdio_unreg:
> + platform_device_unregister(mdio_dev);
> +mdio_err:
> + return ret;
> +
> +gfar_unreg:
> + platform_device_unregister(gfar_dev);
> +gfar_err:
> + return ret;
> +}
If you have two completely separate exit paths for error, and two
separate loops for setup, shouldn't the setup for the two cases be in
separate functions in the first place?
That way, there's no need to prefix the unreg and err exit labels
either.
> +arch_initcall(gfar_of_init);
> +
> +static int __init fsl_i2c_of_init(void)
> +{
> + struct device_node *np;
> + unsigned int i;
> + struct platform_device *i2c_dev;
> + int ret;
> +
> + for (np = NULL, i = 0; (np = of_find_compatible_node(np, "i2c", "fsl-i2c")) != NULL; i++) {
> + struct resource r[2];
> + struct fsl_i2c_platform_data i2c_data;
> + unsigned char * flags = NULL;
> +
> + memset(&r, 0, sizeof(r));
> + memset(&i2c_data, 0, sizeof(i2c_data));
> +
> + ret = of_address_to_resource(np, 0, &r[0]);
> + if (ret)
> + goto i2c_err;
> +
> + r[1].start = np->intrs[0].line;
> + r[1].end = np->intrs[0].line;
> + r[1].flags = IORESOURCE_IRQ;
> +
> + i2c_dev = platform_device_register_simple("fsl-i2c", i, r, 2);
> + if (IS_ERR(i2c_dev)) {
> + ret = PTR_ERR(i2c_dev);
> + goto i2c_err;
> + }
> +
> + i2c_data.device_flags = 0;
> + flags = get_property(np, "dfsrr", NULL);
> + if (flags)
> + i2c_data.device_flags |= FSL_I2C_DEV_SEPARATE_DFSRR;
> +
> + flags = get_property(np, "fsl5200-clocking", NULL);
> + if (flags)
> + i2c_data.device_flags |= FSL_I2C_DEV_CLOCK_5200;
> +
> + ret = platform_device_add_data(i2c_dev, &i2c_data, sizeof(struct fsl_i2c_platform_data));
> + if (ret)
> + goto i2c_unreg;
> + }
> +
> + return 0;
> +
> +i2c_unreg:
> + platform_device_unregister(i2c_dev);
> +i2c_err:
> + return ret;
No need to prefix the labels, scope is just function
> +}
> +arch_initcall(fsl_i2c_of_init);
> +
> +#ifdef CONFIG_PPC_83xx
> +static int __init mpc83xx_wdt_init(void)
> +{
> + struct resource r;
> + struct device_node *soc, *np;
> + struct platform_device *dev;
> + unsigned int *freq;
> + int ret;
> +
> + np = of_find_compatible_node(NULL, "watchdog", "mpc83xx_wdt");
> +
> + if (!np) {
> + ret = -ENODEV;
> + goto mpc83xx_wdt_nodev;
> + }
> +
> + soc = of_find_node_by_type(NULL, "soc");
> +
> + if (!soc) {
> + ret = -ENODEV;
> + goto mpc83xx_wdt_nosoc;
> + }
> +
> + freq = (unsigned int *)get_property(soc, "bus-frequency", NULL);
> + if (!freq) {
> + ret = -ENODEV;
> + goto mpc83xx_wdt_err;
> + }
> +
> + memset(&r, 0, sizeof(r));
> +
> + ret = of_address_to_resource(np, 0, &r);
> + if (ret)
> + goto mpc83xx_wdt_err;
> +
> + dev = platform_device_register_simple("mpc83xx_wdt", 0, &r, 1);
> + if (IS_ERR(dev)) {
> + ret = PTR_ERR(dev);
> + goto mpc83xx_wdt_err;
> + }
> +
> + ret = platform_device_add_data(dev, freq, sizeof(int));
> + if (ret)
> + goto mpc83xx_wdt_unreg;
> +
> + of_node_put(soc);
> + of_node_put(np);
> +
> + return 0;
> +
> +mpc83xx_wdt_unreg:
> + platform_device_unregister(dev);
> +mpc83xx_wdt_err:
> + of_node_put(soc);
> +mpc83xx_wdt_nosoc:
> + of_node_put(np);
> +mpc83xx_wdt_nodev:
> + return ret;
Same thing about labels as before
> +}
> +arch_initcall(mpc83xx_wdt_init);
> +#endif
> diff --git a/arch/powerpc/sysdev/fsl_soc.h b/arch/powerpc/sysdev/fsl_soc.h
> new file mode 100644
> index 0000000..c433d3f
> --- /dev/null
> +++ b/arch/powerpc/sysdev/fsl_soc.h
> @@ -0,0 +1,8 @@
> +#ifndef __PPC_FSL_SOC_H
> +#define __PPC_FSL_SOC_H
> +#ifdef __KERNEL__
> +
> +extern phys_addr_t get_immrbase(void);
> +
> +#endif
> +#endif
>
> _______________________________________________
> Linuxppc-dev mailing list
> Linuxppc-dev@ozlabs.org
> https://ozlabs.org/mailman/listinfo/linuxppc-dev
^ permalink raw reply
* Re: [PATCH] Remove powermac support from ARCH=ppc
From: Brad Boyer @ 2006-01-14 19:31 UTC (permalink / raw)
To: Paul Mackerras; +Cc: linuxppc-dev
In-Reply-To: <17352.57423.119068.737164@cargo.ozlabs.ibm.com>
On Sat, Jan 14, 2006 at 10:28:15PM +1100, Paul Mackerras wrote:
> This means, BTW, that it will no longer be possible to build 32-bit
> kernels for Apple G5 machines. Also, miboot users (are there any
> still?) are out of luck until I move the miboot stuff over to
> arch/powerpc/boot.
If nothing else, miboot is used to make install floppies for oldworld
boxes for the Debian installer. I doubt very many people are using it
for normal boot, but this is the simplest way to boot from a floppy
disk on oldworld models.
Brad Boyer
flar@allandria.com
^ permalink raw reply
* Re: [PATCH] Remove powermac support from ARCH=ppc
From: Benjamin Herrenschmidt @ 2006-01-14 20:56 UTC (permalink / raw)
To: Paul Mackerras; +Cc: linuxppc-dev
In-Reply-To: <17352.57423.119068.737164@cargo.ozlabs.ibm.com>
On Sat, 2006-01-14 at 22:28 +1100, Paul Mackerras wrote:
> This patch makes it possible to build kernels for PReP and/or CHRP
> with ARCH=ppc by removing the (non-building) powermac support.
> It's now also possible to select PReP and CHRP independently.
> Powermac users should now build with ARCH=powerpc instead of
> ARCH=ppc.
Any reason not to remove CHRP too ?
> This patch doesn't actually remove all the powermac files under
> arch/ppc, but they could go.
OK, we can do that in a second step.
> This means, BTW, that it will no longer be possible to build 32-bit
> kernels for Apple G5 machines. Also, miboot users (are there any
> still?) are out of luck until I move the miboot stuff over to
> arch/powerpc/boot.
32 bits kernel on g5 were unuspported for ages and I announced the death
of that support long enough in advance. miboot works with plain vmlinux,
the only thing those miboot images are useful for is if you need a
compressed image due to lack of space and/or if you need an embedded
initrd. Hopefully, that should be trivial to add back though.
Ben.
^ permalink raw reply
* Re: [PATCH] powerpc: Better machine descriptions and kill magic numbers
From: Benjamin Herrenschmidt @ 2006-01-14 21:04 UTC (permalink / raw)
To: Olof Johansson; +Cc: linuxppc-dev list, linuxppc64-dev
In-Reply-To: <20060114184040.GR2491@pb15.lixom.net>
> Because of this, I suggest keeping the mach_ part in the syntax, i.e,
> to use:
>
> machine_is(mach_powermac) instead, and not do preprocessor mangling of
> the label name. The same would go for define_machine().
>
> It would seem to make some sense to keep the platform types looking
> like defines (i.e. MACH_POWERMAC instead of mach_powermac) to keep it
> consistent with the CPU and firmware feature testing, but the way it's
> implemented that doesn't make much sense. That's a bit of a shame.
I'm not sure about these ... I'm definitely not fan of going uppercase (and
it makes no sense vs. the implementation as it's not macros). I also don't
get your problem with grep... the "mach_" construct is totally invisible,
so people wouldn't grep for it, but for "powermac" alone.
Or do you mean a grep on "powermac" might return too many things unrelated ?
It should be easy enough in this case to grep for machine_is(powermac) instead
then, after all, that's the only possible use...
> In the probe loop, ppc_md is copied over for each probe, that seems
> wasteful.
I changed that from the old way indeed to allow the probe() function to
override things in ppc_md.
> Shouldn't the probe routines use and modify their own
> machdep_calls instead of ppc_md, so the copying can be done only once,
> after a match is found?
I don't like modifying their own machdep calls because the name of the
structure is hidden. In general, I prefer that things continue to only
access ppc_md. and not their own machine structure that goes away. That
means that the code "patching" it can be moved away etc... without
special case instead of having a special case in probe() that has to
reference the machine specific copy...
I doubt the memcpy per machine at boot will cause any kind of
significant performance issue ...
Ben.
^ permalink raw reply
* [PATCH] Updated Initial MPC8540 ADS port with OF Flat Dev
From: Becky Bruce @ 2006-01-14 22:57 UTC (permalink / raw)
To: linuxppc-dev; +Cc: jdl
Updated patch for support for mpc8540_ads in arch/powerpc with a
flat OF device tree. This patch does not yet support PCI or I2C.
Signed-off-by: Becky Bruce <becky.bruce@freescale.com>
Signed-off-by: Jon Loeliger <jdl@freescale.com>
Signed-off-by: Kumar Gala <galak@kernel.crashing.org>
---
commit baeb15eb1ee0ffb52cdecfdeced8d286d1d89331
tree 0da2dbad749fde0f364b1eecb75e9eefb7eabf01
parent 87530db5ec7d519c7ba334e414307c5130ae2da8
author Becky Bruce <becky.bruce@freescale.com> Sat, 14 Jan 2006 16:21:28 -0600
committer Becky Bruce <becky.bruce@freescale.com> Sat, 14 Jan 2006 16:21:28 -0600
arch/powerpc/Kconfig | 23 +
arch/powerpc/configs/mpc8540_ads_defconfig | 721 ++++++++++++++++++++++++++++
arch/powerpc/kernel/head_booke.h | 363 ++++++++++++++
arch/powerpc/platforms/85xx/Kconfig | 74 ---
arch/powerpc/platforms/85xx/Makefile | 5
arch/powerpc/platforms/85xx/mpc8540_ads.h | 60 ++
arch/powerpc/platforms/85xx/mpc85xx.c | 31 +
arch/powerpc/platforms/85xx/mpc85xx.h | 17 +
arch/powerpc/platforms/85xx/mpc85xx_ads.c | 208 ++++++++
arch/powerpc/platforms/Makefile | 2
10 files changed, 1431 insertions(+), 73 deletions(-)
diff --git a/arch/powerpc/Kconfig b/arch/powerpc/Kconfig
index 01feed0..c870865 100644
--- a/arch/powerpc/Kconfig
+++ b/arch/powerpc/Kconfig
@@ -132,6 +132,12 @@ config PPC_83xx
select 83xx
select PPC_FPU
+config PPC_85xx
+ bool "Freescale 85xx"
+ select E500
+ select FSL_SOC
+ select 85xx
+
config 40x
bool "AMCC 40x"
@@ -144,8 +150,6 @@ config 8xx
config E200
bool "Freescale e200"
-config E500
- bool "Freescale e500"
endchoice
config POWER4_ONLY
@@ -173,6 +177,13 @@ config 6xx
config 83xx
bool
+# this is temp to handle compat with arch=ppc
+config 85xx
+ bool
+
+config E500
+ bool
+
config PPC_FPU
bool
default y if PPC64
@@ -222,6 +233,7 @@ config ALTIVEC
config SPE
bool "SPE Support"
depends on E200 || E500
+ default y
---help---
This option enables kernel support for the Signal Processing
Extensions (SPE) to the PowerPC processor. The kernel currently
@@ -729,13 +741,12 @@ config GENERIC_ISA_DMA
config PPC_I8259
bool
- default y if 85xx
default n
config PPC_INDIRECT_PCI
bool
depends on PCI
- default y if 40x || 44x || 85xx
+ default y if 40x || 44x
default n
config EISA
@@ -752,8 +763,8 @@ config MCA
bool
config PCI
- bool "PCI support" if 40x || CPM2 || PPC_83xx || 85xx || PPC_MPC52xx || (EMBEDDED && PPC_ISERIES)
- default y if !40x && !CPM2 && !8xx && !APUS && !PPC_83xx && !85xx
+ bool "PCI support" if 40x || CPM2 || PPC_83xx || PPC_85xx || PPC_MPC52xx || (EMBEDDED && PPC_ISERIES)
+ default y if !40x && !CPM2 && !8xx && !APUS && !PPC_83xx && !PPC_85xx
default PCI_PERMEDIA if !4xx && !CPM2 && !8xx && APUS
default PCI_QSPAN if !4xx && !CPM2 && 8xx
help
diff --git a/arch/powerpc/configs/mpc8540_ads_defconfig b/arch/powerpc/configs/mpc8540_ads_defconfig
new file mode 100644
index 0000000..2a8290e
--- /dev/null
+++ b/arch/powerpc/configs/mpc8540_ads_defconfig
@@ -0,0 +1,721 @@
+#
+# Automatically generated make config: don't edit
+# Linux kernel version:
+# Sat Jan 14 15:57:54 2006
+#
+# CONFIG_PPC64 is not set
+CONFIG_PPC32=y
+CONFIG_PPC_MERGE=y
+CONFIG_MMU=y
+CONFIG_GENERIC_HARDIRQS=y
+CONFIG_RWSEM_XCHGADD_ALGORITHM=y
+CONFIG_GENERIC_CALIBRATE_DELAY=y
+CONFIG_PPC=y
+CONFIG_EARLY_PRINTK=y
+CONFIG_GENERIC_NVRAM=y
+CONFIG_SCHED_NO_NO_OMIT_FRAME_POINTER=y
+CONFIG_ARCH_MAY_HAVE_PC_FDC=y
+CONFIG_PPC_OF=y
+CONFIG_PPC_UDBG_16550=y
+# CONFIG_GENERIC_TBSYNC is not set
+
+#
+# Processor support
+#
+# CONFIG_CLASSIC32 is not set
+# CONFIG_PPC_52xx is not set
+# CONFIG_PPC_82xx is not set
+# CONFIG_PPC_83xx is not set
+CONFIG_PPC_85xx=y
+# CONFIG_40x is not set
+# CONFIG_44x is not set
+# CONFIG_8xx is not set
+# CONFIG_E200 is not set
+CONFIG_85xx=y
+CONFIG_E500=y
+CONFIG_BOOKE=y
+CONFIG_FSL_BOOKE=y
+# CONFIG_PHYS_64BIT is not set
+CONFIG_SPE=y
+
+#
+# Code maturity level options
+#
+CONFIG_EXPERIMENTAL=y
+CONFIG_CLEAN_COMPILE=y
+CONFIG_BROKEN_ON_SMP=y
+CONFIG_INIT_ENV_ARG_LIMIT=32
+
+#
+# General setup
+#
+CONFIG_LOCALVERSION=""
+CONFIG_LOCALVERSION_AUTO=y
+CONFIG_SWAP=y
+CONFIG_SYSVIPC=y
+# CONFIG_POSIX_MQUEUE is not set
+# CONFIG_BSD_PROCESS_ACCT is not set
+CONFIG_SYSCTL=y
+# CONFIG_AUDIT is not set
+# CONFIG_IKCONFIG is not set
+CONFIG_INITRAMFS_SOURCE=""
+# CONFIG_CC_OPTIMIZE_FOR_SIZE is not set
+CONFIG_EMBEDDED=y
+CONFIG_KALLSYMS=y
+# CONFIG_KALLSYMS_ALL is not set
+# CONFIG_KALLSYMS_EXTRA_PASS is not set
+CONFIG_HOTPLUG=y
+CONFIG_PRINTK=y
+CONFIG_BUG=y
+CONFIG_ELF_CORE=y
+CONFIG_BASE_FULL=y
+CONFIG_FUTEX=y
+CONFIG_EPOLL=y
+CONFIG_SHMEM=y
+CONFIG_CC_ALIGN_FUNCTIONS=0
+CONFIG_CC_ALIGN_LABELS=0
+CONFIG_CC_ALIGN_LOOPS=0
+CONFIG_CC_ALIGN_JUMPS=0
+CONFIG_SLAB=y
+# CONFIG_TINY_SHMEM is not set
+CONFIG_BASE_SMALL=0
+# CONFIG_SLOB is not set
+
+#
+# Loadable module support
+#
+# CONFIG_MODULES is not set
+
+#
+# Block layer
+#
+# CONFIG_LBD is not set
+
+#
+# IO Schedulers
+#
+CONFIG_IOSCHED_NOOP=y
+CONFIG_IOSCHED_AS=y
+CONFIG_IOSCHED_DEADLINE=y
+CONFIG_IOSCHED_CFQ=y
+CONFIG_DEFAULT_AS=y
+# CONFIG_DEFAULT_DEADLINE is not set
+# CONFIG_DEFAULT_CFQ is not set
+# CONFIG_DEFAULT_NOOP is not set
+CONFIG_DEFAULT_IOSCHED="anticipatory"
+CONFIG_MPIC=y
+# CONFIG_WANT_EARLY_SERIAL is not set
+
+#
+# Platform support
+#
+CONFIG_MPC8540_ADS=y
+CONFIG_MPC8540=y
+CONFIG_PPC_INDIRECT_PCI_BE=y
+
+#
+# Kernel options
+#
+# CONFIG_HIGHMEM is not set
+# CONFIG_HZ_100 is not set
+CONFIG_HZ_250=y
+# CONFIG_HZ_1000 is not set
+CONFIG_HZ=250
+CONFIG_PREEMPT_NONE=y
+# CONFIG_PREEMPT_VOLUNTARY is not set
+# CONFIG_PREEMPT is not set
+CONFIG_BINFMT_ELF=y
+CONFIG_BINFMT_MISC=y
+CONFIG_MATH_EMULATION=y
+CONFIG_ARCH_FLATMEM_ENABLE=y
+CONFIG_SELECT_MEMORY_MODEL=y
+CONFIG_FLATMEM_MANUAL=y
+# CONFIG_DISCONTIGMEM_MANUAL is not set
+# CONFIG_SPARSEMEM_MANUAL is not set
+CONFIG_FLATMEM=y
+CONFIG_FLAT_NODE_MEM_MAP=y
+# CONFIG_SPARSEMEM_STATIC is not set
+CONFIG_SPLIT_PTLOCK_CPUS=4
+CONFIG_PROC_DEVICETREE=y
+# CONFIG_CMDLINE_BOOL is not set
+# CONFIG_PM is not set
+# CONFIG_SOFTWARE_SUSPEND is not set
+# CONFIG_SECCOMP is not set
+CONFIG_ISA_DMA_API=y
+
+#
+# Bus options
+#
+# CONFIG_PPC_I8259 is not set
+CONFIG_PPC_INDIRECT_PCI=y
+CONFIG_FSL_SOC=y
+# CONFIG_PCI is not set
+# CONFIG_PCI_DOMAINS is not set
+
+#
+# PCCARD (PCMCIA/CardBus) support
+#
+# CONFIG_PCCARD is not set
+
+#
+# PCI Hotplug Support
+#
+
+#
+# Advanced setup
+#
+# CONFIG_ADVANCED_OPTIONS is not set
+
+#
+# Default settings for advanced configuration options are used
+#
+CONFIG_HIGHMEM_START=0xfe000000
+CONFIG_LOWMEM_SIZE=0x30000000
+CONFIG_KERNEL_START=0xc0000000
+CONFIG_TASK_SIZE=0x80000000
+CONFIG_BOOT_LOAD=0x00800000
+
+#
+# Networking
+#
+CONFIG_NET=y
+
+#
+# Networking options
+#
+CONFIG_PACKET=y
+# CONFIG_PACKET_MMAP is not set
+CONFIG_UNIX=y
+# CONFIG_NET_KEY is not set
+CONFIG_INET=y
+CONFIG_IP_MULTICAST=y
+# CONFIG_IP_ADVANCED_ROUTER is not set
+CONFIG_IP_FIB_HASH=y
+CONFIG_IP_PNP=y
+CONFIG_IP_PNP_DHCP=y
+CONFIG_IP_PNP_BOOTP=y
+# CONFIG_IP_PNP_RARP is not set
+# CONFIG_NET_IPIP is not set
+# CONFIG_NET_IPGRE is not set
+# CONFIG_IP_MROUTE is not set
+# CONFIG_ARPD is not set
+CONFIG_SYN_COOKIES=y
+# CONFIG_INET_AH is not set
+# CONFIG_INET_ESP is not set
+# CONFIG_INET_IPCOMP is not set
+# CONFIG_INET_TUNNEL is not set
+CONFIG_INET_DIAG=y
+CONFIG_INET_TCP_DIAG=y
+# CONFIG_TCP_CONG_ADVANCED is not set
+CONFIG_TCP_CONG_BIC=y
+# CONFIG_IPV6 is not set
+# CONFIG_NETFILTER is not set
+
+#
+# DCCP Configuration (EXPERIMENTAL)
+#
+# CONFIG_IP_DCCP is not set
+
+#
+# SCTP Configuration (EXPERIMENTAL)
+#
+# CONFIG_IP_SCTP is not set
+# CONFIG_ATM is not set
+# CONFIG_BRIDGE is not set
+# CONFIG_VLAN_8021Q is not set
+# CONFIG_DECNET is not set
+# CONFIG_LLC2 is not set
+# CONFIG_IPX is not set
+# CONFIG_ATALK is not set
+# CONFIG_X25 is not set
+# CONFIG_LAPB is not set
+
+#
+# TIPC Configuration (EXPERIMENTAL)
+#
+# CONFIG_TIPC is not set
+# CONFIG_NET_DIVERT is not set
+# CONFIG_ECONET is not set
+# CONFIG_WAN_ROUTER is not set
+
+#
+# QoS and/or fair queueing
+#
+# CONFIG_NET_SCHED is not set
+
+#
+# Network testing
+#
+# CONFIG_NET_PKTGEN is not set
+# CONFIG_HAMRADIO is not set
+# CONFIG_IRDA is not set
+# CONFIG_BT is not set
+# CONFIG_IEEE80211 is not set
+
+#
+# Device Drivers
+#
+
+#
+# Generic Driver Options
+#
+CONFIG_STANDALONE=y
+CONFIG_PREVENT_FIRMWARE_BUILD=y
+# CONFIG_FW_LOADER is not set
+# CONFIG_DEBUG_DRIVER is not set
+
+#
+# Connector - unified userspace <-> kernelspace linker
+#
+# CONFIG_CONNECTOR is not set
+
+#
+# Memory Technology Devices (MTD)
+#
+# CONFIG_MTD is not set
+
+#
+# Parallel port support
+#
+# CONFIG_PARPORT is not set
+
+#
+# Plug and Play support
+#
+
+#
+# Block devices
+#
+# CONFIG_BLK_DEV_FD is not set
+# CONFIG_BLK_DEV_COW_COMMON is not set
+CONFIG_BLK_DEV_LOOP=y
+# CONFIG_BLK_DEV_CRYPTOLOOP is not set
+# CONFIG_BLK_DEV_NBD is not set
+CONFIG_BLK_DEV_RAM=y
+CONFIG_BLK_DEV_RAM_COUNT=16
+CONFIG_BLK_DEV_RAM_SIZE=32768
+CONFIG_BLK_DEV_INITRD=y
+# CONFIG_CDROM_PKTCDVD is not set
+# CONFIG_ATA_OVER_ETH is not set
+
+#
+# ATA/ATAPI/MFM/RLL support
+#
+# CONFIG_IDE is not set
+
+#
+# SCSI device support
+#
+# CONFIG_RAID_ATTRS is not set
+# CONFIG_SCSI is not set
+
+#
+# Multi-device support (RAID and LVM)
+#
+# CONFIG_MD is not set
+
+#
+# Fusion MPT device support
+#
+# CONFIG_FUSION is not set
+
+#
+# IEEE 1394 (FireWire) support
+#
+
+#
+# I2O device support
+#
+
+#
+# Macintosh device drivers
+#
+# CONFIG_WINDFARM is not set
+
+#
+# Network device support
+#
+CONFIG_NETDEVICES=y
+# CONFIG_DUMMY is not set
+# CONFIG_BONDING is not set
+# CONFIG_EQUALIZER is not set
+# CONFIG_TUN is not set
+
+#
+# PHY device support
+#
+CONFIG_PHYLIB=y
+
+#
+# MII PHY device drivers
+#
+# CONFIG_MARVELL_PHY is not set
+# CONFIG_DAVICOM_PHY is not set
+# CONFIG_QSEMI_PHY is not set
+# CONFIG_LXT_PHY is not set
+# CONFIG_CICADA_PHY is not set
+
+#
+# Ethernet (10 or 100Mbit)
+#
+CONFIG_NET_ETHERNET=y
+CONFIG_MII=y
+
+#
+# Ethernet (1000 Mbit)
+#
+CONFIG_GIANFAR=y
+CONFIG_GFAR_NAPI=y
+
+#
+# Ethernet (10000 Mbit)
+#
+
+#
+# Token Ring devices
+#
+
+#
+# Wireless LAN (non-hamradio)
+#
+# CONFIG_NET_RADIO is not set
+
+#
+# Wan interfaces
+#
+# CONFIG_WAN is not set
+# CONFIG_PPP is not set
+# CONFIG_SLIP is not set
+# CONFIG_SHAPER is not set
+# CONFIG_NETCONSOLE is not set
+# CONFIG_NETPOLL is not set
+# CONFIG_NET_POLL_CONTROLLER is not set
+
+#
+# ISDN subsystem
+#
+# CONFIG_ISDN is not set
+
+#
+# Telephony Support
+#
+# CONFIG_PHONE is not set
+
+#
+# Input device support
+#
+CONFIG_INPUT=y
+
+#
+# Userland interfaces
+#
+# CONFIG_INPUT_MOUSEDEV is not set
+# CONFIG_INPUT_JOYDEV is not set
+# CONFIG_INPUT_TSDEV is not set
+# CONFIG_INPUT_EVDEV is not set
+# CONFIG_INPUT_EVBUG is not set
+
+#
+# Input Device Drivers
+#
+# CONFIG_INPUT_KEYBOARD is not set
+# CONFIG_INPUT_MOUSE is not set
+# CONFIG_INPUT_JOYSTICK is not set
+# CONFIG_INPUT_TOUCHSCREEN is not set
+# CONFIG_INPUT_MISC is not set
+
+#
+# Hardware I/O ports
+#
+# CONFIG_SERIO is not set
+# CONFIG_GAMEPORT is not set
+
+#
+# Character devices
+#
+# CONFIG_VT is not set
+# CONFIG_SERIAL_NONSTANDARD is not set
+
+#
+# Serial drivers
+#
+CONFIG_SERIAL_8250=y
+CONFIG_SERIAL_8250_CONSOLE=y
+CONFIG_SERIAL_8250_NR_UARTS=4
+CONFIG_SERIAL_8250_RUNTIME_UARTS=4
+# CONFIG_SERIAL_8250_EXTENDED is not set
+
+#
+# Non-8250 serial port support
+#
+CONFIG_SERIAL_CORE=y
+CONFIG_SERIAL_CORE_CONSOLE=y
+CONFIG_UNIX98_PTYS=y
+CONFIG_LEGACY_PTYS=y
+CONFIG_LEGACY_PTY_COUNT=256
+
+#
+# IPMI
+#
+# CONFIG_IPMI_HANDLER is not set
+
+#
+# Watchdog Cards
+#
+# CONFIG_WATCHDOG is not set
+# CONFIG_NVRAM is not set
+CONFIG_GEN_RTC=y
+# CONFIG_GEN_RTC_X is not set
+# CONFIG_DTLK is not set
+# CONFIG_R3964 is not set
+
+#
+# Ftape, the floppy tape device driver
+#
+# CONFIG_AGP is not set
+# CONFIG_RAW_DRIVER is not set
+
+#
+# TPM devices
+#
+# CONFIG_TCG_TPM is not set
+# CONFIG_TELCLOCK is not set
+
+#
+# I2C support
+#
+# CONFIG_I2C is not set
+
+#
+# Dallas's 1-wire bus
+#
+# CONFIG_W1 is not set
+
+#
+# Hardware Monitoring support
+#
+CONFIG_HWMON=y
+# CONFIG_HWMON_VID is not set
+# CONFIG_HWMON_DEBUG_CHIP is not set
+
+#
+# Misc devices
+#
+
+#
+# Multimedia Capabilities Port drivers
+#
+
+#
+# Multimedia devices
+#
+# CONFIG_VIDEO_DEV is not set
+
+#
+# Digital Video Broadcasting Devices
+#
+# CONFIG_DVB is not set
+
+#
+# Graphics support
+#
+# CONFIG_FB is not set
+
+#
+# Sound
+#
+# CONFIG_SOUND is not set
+
+#
+# USB support
+#
+# CONFIG_USB_ARCH_HAS_HCD is not set
+# CONFIG_USB_ARCH_HAS_OHCI is not set
+
+#
+# NOTE: USB_STORAGE enables SCSI, and 'SCSI disk support'
+#
+
+#
+# USB Gadget Support
+#
+# CONFIG_USB_GADGET is not set
+
+#
+# MMC/SD Card support
+#
+# CONFIG_MMC is not set
+
+#
+# InfiniBand support
+#
+
+#
+# SN Devices
+#
+
+#
+# File systems
+#
+CONFIG_EXT2_FS=y
+# CONFIG_EXT2_FS_XATTR is not set
+# CONFIG_EXT2_FS_XIP is not set
+CONFIG_EXT3_FS=y
+CONFIG_EXT3_FS_XATTR=y
+# CONFIG_EXT3_FS_POSIX_ACL is not set
+# CONFIG_EXT3_FS_SECURITY is not set
+CONFIG_JBD=y
+# CONFIG_JBD_DEBUG is not set
+CONFIG_FS_MBCACHE=y
+# CONFIG_REISERFS_FS is not set
+# CONFIG_JFS_FS is not set
+# CONFIG_FS_POSIX_ACL is not set
+# CONFIG_XFS_FS is not set
+# CONFIG_OCFS2_FS is not set
+# CONFIG_MINIX_FS is not set
+# CONFIG_ROMFS_FS is not set
+CONFIG_INOTIFY=y
+# CONFIG_QUOTA is not set
+CONFIG_DNOTIFY=y
+# CONFIG_AUTOFS_FS is not set
+# CONFIG_AUTOFS4_FS is not set
+# CONFIG_FUSE_FS is not set
+
+#
+# CD-ROM/DVD Filesystems
+#
+# CONFIG_ISO9660_FS is not set
+# CONFIG_UDF_FS is not set
+
+#
+# DOS/FAT/NT Filesystems
+#
+# CONFIG_MSDOS_FS is not set
+# CONFIG_VFAT_FS is not set
+# CONFIG_NTFS_FS is not set
+
+#
+# Pseudo filesystems
+#
+CONFIG_PROC_FS=y
+CONFIG_PROC_KCORE=y
+CONFIG_SYSFS=y
+CONFIG_TMPFS=y
+# CONFIG_HUGETLB_PAGE is not set
+CONFIG_RAMFS=y
+# CONFIG_RELAYFS_FS is not set
+# CONFIG_CONFIGFS_FS is not set
+
+#
+# Miscellaneous filesystems
+#
+# CONFIG_ADFS_FS is not set
+# CONFIG_AFFS_FS is not set
+# CONFIG_HFS_FS is not set
+# CONFIG_HFSPLUS_FS is not set
+# CONFIG_BEFS_FS is not set
+# CONFIG_BFS_FS is not set
+# CONFIG_EFS_FS is not set
+# CONFIG_CRAMFS is not set
+# CONFIG_VXFS_FS is not set
+# CONFIG_HPFS_FS is not set
+# CONFIG_QNX4FS_FS is not set
+# CONFIG_SYSV_FS is not set
+# CONFIG_UFS_FS is not set
+
+#
+# Network File Systems
+#
+CONFIG_NFS_FS=y
+# CONFIG_NFS_V3 is not set
+# CONFIG_NFS_V4 is not set
+# CONFIG_NFS_DIRECTIO is not set
+# CONFIG_NFSD is not set
+CONFIG_ROOT_NFS=y
+CONFIG_LOCKD=y
+CONFIG_NFS_COMMON=y
+CONFIG_SUNRPC=y
+# CONFIG_RPCSEC_GSS_KRB5 is not set
+# CONFIG_RPCSEC_GSS_SPKM3 is not set
+# CONFIG_SMB_FS is not set
+# CONFIG_CIFS is not set
+# CONFIG_NCP_FS is not set
+# CONFIG_CODA_FS is not set
+# CONFIG_AFS_FS is not set
+# CONFIG_9P_FS is not set
+
+#
+# Partition Types
+#
+CONFIG_PARTITION_ADVANCED=y
+# CONFIG_ACORN_PARTITION is not set
+# CONFIG_OSF_PARTITION is not set
+# CONFIG_AMIGA_PARTITION is not set
+# CONFIG_ATARI_PARTITION is not set
+# CONFIG_MAC_PARTITION is not set
+# CONFIG_MSDOS_PARTITION is not set
+# CONFIG_LDM_PARTITION is not set
+# CONFIG_SGI_PARTITION is not set
+# CONFIG_ULTRIX_PARTITION is not set
+# CONFIG_SUN_PARTITION is not set
+# CONFIG_EFI_PARTITION is not set
+
+#
+# Native Language Support
+#
+# CONFIG_NLS is not set
+
+#
+# Library routines
+#
+# CONFIG_CRC_CCITT is not set
+# CONFIG_CRC16 is not set
+CONFIG_CRC32=y
+# CONFIG_LIBCRC32C is not set
+
+#
+# Instrumentation Support
+#
+# CONFIG_PROFILING is not set
+
+#
+# Kernel hacking
+#
+# CONFIG_PRINTK_TIME is not set
+# CONFIG_MAGIC_SYSRQ is not set
+CONFIG_DEBUG_KERNEL=y
+CONFIG_LOG_BUF_SHIFT=14
+CONFIG_DETECT_SOFTLOCKUP=y
+# CONFIG_SCHEDSTATS is not set
+# CONFIG_DEBUG_SLAB is not set
+CONFIG_DEBUG_MUTEXES=y
+# CONFIG_DEBUG_SPINLOCK is not set
+# CONFIG_DEBUG_SPINLOCK_SLEEP is not set
+# CONFIG_DEBUG_KOBJECT is not set
+# CONFIG_DEBUG_INFO is not set
+# CONFIG_DEBUG_FS is not set
+# CONFIG_DEBUG_VM is not set
+# CONFIG_RCU_TORTURE_TEST is not set
+# CONFIG_DEBUGGER is not set
+# CONFIG_BDI_SWITCH is not set
+# CONFIG_BOOTX_TEXT is not set
+# CONFIG_PPC_EARLY_DEBUG_LPAR is not set
+# CONFIG_PPC_EARLY_DEBUG_G5 is not set
+# CONFIG_PPC_EARLY_DEBUG_RTAS is not set
+# CONFIG_PPC_EARLY_DEBUG_MAPLE is not set
+# CONFIG_PPC_EARLY_DEBUG_ISERIES is not set
+
+#
+# Security options
+#
+# CONFIG_KEYS is not set
+# CONFIG_SECURITY is not set
+
+#
+# Cryptographic options
+#
+# CONFIG_CRYPTO is not set
+
+#
+# Hardware crypto devices
+#
diff --git a/arch/powerpc/kernel/head_booke.h b/arch/powerpc/kernel/head_booke.h
new file mode 100644
index 0000000..5827c27
--- /dev/null
+++ b/arch/powerpc/kernel/head_booke.h
@@ -0,0 +1,363 @@
+#ifndef __HEAD_BOOKE_H__
+#define __HEAD_BOOKE_H__
+
+/*
+ * Macros used for common Book-e exception handling
+ */
+
+#define SET_IVOR(vector_number, vector_label) \
+ li r26,vector_label@l; \
+ mtspr SPRN_IVOR##vector_number,r26; \
+ sync
+
+#define NORMAL_EXCEPTION_PROLOG \
+ mtspr SPRN_SPRG0,r10; /* save two registers to work with */\
+ mtspr SPRN_SPRG1,r11; \
+ mtspr SPRN_SPRG4W,r1; \
+ mfcr r10; /* save CR in r10 for now */\
+ mfspr r11,SPRN_SRR1; /* check whether user or kernel */\
+ andi. r11,r11,MSR_PR; \
+ beq 1f; \
+ mfspr r1,SPRN_SPRG3; /* if from user, start at top of */\
+ lwz r1,THREAD_INFO-THREAD(r1); /* this thread's kernel stack */\
+ addi r1,r1,THREAD_SIZE; \
+1: subi r1,r1,INT_FRAME_SIZE; /* Allocate an exception frame */\
+ mr r11,r1; \
+ stw r10,_CCR(r11); /* save various registers */\
+ stw r12,GPR12(r11); \
+ stw r9,GPR9(r11); \
+ mfspr r10,SPRN_SPRG0; \
+ stw r10,GPR10(r11); \
+ mfspr r12,SPRN_SPRG1; \
+ stw r12,GPR11(r11); \
+ mflr r10; \
+ stw r10,_LINK(r11); \
+ mfspr r10,SPRN_SPRG4R; \
+ mfspr r12,SPRN_SRR0; \
+ stw r10,GPR1(r11); \
+ mfspr r9,SPRN_SRR1; \
+ stw r10,0(r11); \
+ rlwinm r9,r9,0,14,12; /* clear MSR_WE (necessary?) */\
+ stw r0,GPR0(r11); \
+ SAVE_4GPRS(3, r11); \
+ SAVE_2GPRS(7, r11)
+
+/* To handle the additional exception priority levels on 40x and Book-E
+ * processors we allocate a 4k stack per additional priority level. The various
+ * head_xxx.S files allocate space (exception_stack_top) for each priority's
+ * stack times the number of CPUs
+ *
+ * On 40x critical is the only additional level
+ * On 44x/e500 we have critical and machine check
+ * On e200 we have critical and debug (machine check occurs via critical)
+ *
+ * Additionally we reserve a SPRG for each priority level so we can free up a
+ * GPR to use as the base for indirect access to the exception stacks. This
+ * is necessary since the MMU is always on, for Book-E parts, and the stacks
+ * are offset from KERNELBASE.
+ *
+ */
+#define BOOKE_EXCEPTION_STACK_SIZE (8192)
+
+/* CRIT_SPRG only used in critical exception handling */
+#define CRIT_SPRG SPRN_SPRG2
+/* MCHECK_SPRG only used in machine check exception handling */
+#define MCHECK_SPRG SPRN_SPRG6W
+
+#define MCHECK_STACK_TOP (exception_stack_top - 4096)
+#define CRIT_STACK_TOP (exception_stack_top)
+
+/* only on e200 for now */
+#define DEBUG_STACK_TOP (exception_stack_top - 4096)
+#define DEBUG_SPRG SPRN_SPRG6W
+
+#ifdef CONFIG_SMP
+#define BOOKE_LOAD_EXC_LEVEL_STACK(level) \
+ mfspr r8,SPRN_PIR; \
+ mulli r8,r8,BOOKE_EXCEPTION_STACK_SIZE; \
+ neg r8,r8; \
+ addis r8,r8,level##_STACK_TOP@ha; \
+ addi r8,r8,level##_STACK_TOP@l
+#else
+#define BOOKE_LOAD_EXC_LEVEL_STACK(level) \
+ lis r8,level##_STACK_TOP@h; \
+ ori r8,r8,level##_STACK_TOP@l
+#endif
+
+/*
+ * Exception prolog for critical/machine check exceptions. This is a
+ * little different from the normal exception prolog above since a
+ * critical/machine check exception can potentially occur at any point
+ * during normal exception processing. Thus we cannot use the same SPRG
+ * registers as the normal prolog above. Instead we use a portion of the
+ * critical/machine check exception stack at low physical addresses.
+ */
+#define EXC_LEVEL_EXCEPTION_PROLOG(exc_level, exc_level_srr0, exc_level_srr1) \
+ mtspr exc_level##_SPRG,r8; \
+ BOOKE_LOAD_EXC_LEVEL_STACK(exc_level);/* r8 points to the exc_level stack*/ \
+ stw r10,GPR10-INT_FRAME_SIZE(r8); \
+ stw r11,GPR11-INT_FRAME_SIZE(r8); \
+ mfcr r10; /* save CR in r10 for now */\
+ mfspr r11,exc_level_srr1; /* check whether user or kernel */\
+ andi. r11,r11,MSR_PR; \
+ mr r11,r8; \
+ mfspr r8,exc_level##_SPRG; \
+ beq 1f; \
+ /* COMING FROM USER MODE */ \
+ mfspr r11,SPRN_SPRG3; /* if from user, start at top of */\
+ lwz r11,THREAD_INFO-THREAD(r11); /* this thread's kernel stack */\
+ addi r11,r11,THREAD_SIZE; \
+1: subi r11,r11,INT_FRAME_SIZE; /* Allocate an exception frame */\
+ stw r10,_CCR(r11); /* save various registers */\
+ stw r12,GPR12(r11); \
+ stw r9,GPR9(r11); \
+ mflr r10; \
+ stw r10,_LINK(r11); \
+ mfspr r12,SPRN_DEAR; /* save DEAR and ESR in the frame */\
+ stw r12,_DEAR(r11); /* since they may have had stuff */\
+ mfspr r9,SPRN_ESR; /* in them at the point where the */\
+ stw r9,_ESR(r11); /* exception was taken */\
+ mfspr r12,exc_level_srr0; \
+ stw r1,GPR1(r11); \
+ mfspr r9,exc_level_srr1; \
+ stw r1,0(r11); \
+ mr r1,r11; \
+ rlwinm r9,r9,0,14,12; /* clear MSR_WE (necessary?) */\
+ stw r0,GPR0(r11); \
+ SAVE_4GPRS(3, r11); \
+ SAVE_2GPRS(7, r11)
+
+#define CRITICAL_EXCEPTION_PROLOG \
+ EXC_LEVEL_EXCEPTION_PROLOG(CRIT, SPRN_CSRR0, SPRN_CSRR1)
+#define DEBUG_EXCEPTION_PROLOG \
+ EXC_LEVEL_EXCEPTION_PROLOG(DEBUG, SPRN_DSRR0, SPRN_DSRR1)
+#define MCHECK_EXCEPTION_PROLOG \
+ EXC_LEVEL_EXCEPTION_PROLOG(MCHECK, SPRN_MCSRR0, SPRN_MCSRR1)
+
+/*
+ * Exception vectors.
+ */
+#define START_EXCEPTION(label) \
+ .align 5; \
+label:
+
+#define FINISH_EXCEPTION(func) \
+ bl transfer_to_handler_full; \
+ .long func; \
+ .long ret_from_except_full
+
+#define EXCEPTION(n, label, hdlr, xfer) \
+ START_EXCEPTION(label); \
+ NORMAL_EXCEPTION_PROLOG; \
+ addi r3,r1,STACK_FRAME_OVERHEAD; \
+ xfer(n, hdlr)
+
+#define CRITICAL_EXCEPTION(n, label, hdlr) \
+ START_EXCEPTION(label); \
+ CRITICAL_EXCEPTION_PROLOG; \
+ addi r3,r1,STACK_FRAME_OVERHEAD; \
+ EXC_XFER_TEMPLATE(hdlr, n+2, (MSR_KERNEL & ~(MSR_ME|MSR_DE|MSR_CE)), \
+ NOCOPY, crit_transfer_to_handler, \
+ ret_from_crit_exc)
+
+#define MCHECK_EXCEPTION(n, label, hdlr) \
+ START_EXCEPTION(label); \
+ MCHECK_EXCEPTION_PROLOG; \
+ mfspr r5,SPRN_ESR; \
+ stw r5,_ESR(r11); \
+ addi r3,r1,STACK_FRAME_OVERHEAD; \
+ EXC_XFER_TEMPLATE(hdlr, n+2, (MSR_KERNEL & ~(MSR_ME|MSR_DE|MSR_CE)), \
+ NOCOPY, mcheck_transfer_to_handler, \
+ ret_from_mcheck_exc)
+
+#define EXC_XFER_TEMPLATE(hdlr, trap, msr, copyee, tfer, ret) \
+ li r10,trap; \
+ stw r10,_TRAP(r11); \
+ lis r10,msr@h; \
+ ori r10,r10,msr@l; \
+ copyee(r10, r9); \
+ bl tfer; \
+ .long hdlr; \
+ .long ret
+
+#define COPY_EE(d, s) rlwimi d,s,0,16,16
+#define NOCOPY(d, s)
+
+#define EXC_XFER_STD(n, hdlr) \
+ EXC_XFER_TEMPLATE(hdlr, n, MSR_KERNEL, NOCOPY, transfer_to_handler_full, \
+ ret_from_except_full)
+
+#define EXC_XFER_LITE(n, hdlr) \
+ EXC_XFER_TEMPLATE(hdlr, n+1, MSR_KERNEL, NOCOPY, transfer_to_handler, \
+ ret_from_except)
+
+#define EXC_XFER_EE(n, hdlr) \
+ EXC_XFER_TEMPLATE(hdlr, n, MSR_KERNEL, COPY_EE, transfer_to_handler_full, \
+ ret_from_except_full)
+
+#define EXC_XFER_EE_LITE(n, hdlr) \
+ EXC_XFER_TEMPLATE(hdlr, n+1, MSR_KERNEL, COPY_EE, transfer_to_handler, \
+ ret_from_except)
+
+/* Check for a single step debug exception while in an exception
+ * handler before state has been saved. This is to catch the case
+ * where an instruction that we are trying to single step causes
+ * an exception (eg ITLB/DTLB miss) and thus the first instruction of
+ * the exception handler generates a single step debug exception.
+ *
+ * If we get a debug trap on the first instruction of an exception handler,
+ * we reset the MSR_DE in the _exception handler's_ MSR (the debug trap is
+ * a critical exception, so we are using SPRN_CSRR1 to manipulate the MSR).
+ * The exception handler was handling a non-critical interrupt, so it will
+ * save (and later restore) the MSR via SPRN_CSRR1, which will still have
+ * the MSR_DE bit set.
+ */
+#ifdef CONFIG_E200
+#define DEBUG_EXCEPTION \
+ START_EXCEPTION(Debug); \
+ DEBUG_EXCEPTION_PROLOG; \
+ \
+ /* \
+ * If there is a single step or branch-taken exception in an \
+ * exception entry sequence, it was probably meant to apply to \
+ * the code where the exception occurred (since exception entry \
+ * doesn't turn off DE automatically). We simulate the effect \
+ * of turning off DE on entry to an exception handler by turning \
+ * off DE in the CSRR1 value and clearing the debug status. \
+ */ \
+ mfspr r10,SPRN_DBSR; /* check single-step/branch taken */ \
+ andis. r10,r10,DBSR_IC@h; \
+ beq+ 2f; \
+ \
+ lis r10,KERNELBASE@h; /* check if exception in vectors */ \
+ ori r10,r10,KERNELBASE@l; \
+ cmplw r12,r10; \
+ blt+ 2f; /* addr below exception vectors */ \
+ \
+ lis r10,Debug@h; \
+ ori r10,r10,Debug@l; \
+ cmplw r12,r10; \
+ bgt+ 2f; /* addr above exception vectors */ \
+ \
+ /* here it looks like we got an inappropriate debug exception. */ \
+1: rlwinm r9,r9,0,~MSR_DE; /* clear DE in the CDRR1 value */ \
+ lis r10,DBSR_IC@h; /* clear the IC event */ \
+ mtspr SPRN_DBSR,r10; \
+ /* restore state and get out */ \
+ lwz r10,_CCR(r11); \
+ lwz r0,GPR0(r11); \
+ lwz r1,GPR1(r11); \
+ mtcrf 0x80,r10; \
+ mtspr SPRN_DSRR0,r12; \
+ mtspr SPRN_DSRR1,r9; \
+ lwz r9,GPR9(r11); \
+ lwz r12,GPR12(r11); \
+ mtspr DEBUG_SPRG,r8; \
+ BOOKE_LOAD_EXC_LEVEL_STACK(DEBUG); /* r8 points to the debug stack */ \
+ lwz r10,GPR10-INT_FRAME_SIZE(r8); \
+ lwz r11,GPR11-INT_FRAME_SIZE(r8); \
+ mfspr r8,DEBUG_SPRG; \
+ \
+ RFDI; \
+ b .; \
+ \
+ /* continue normal handling for a critical exception... */ \
+2: mfspr r4,SPRN_DBSR; \
+ addi r3,r1,STACK_FRAME_OVERHEAD; \
+ EXC_XFER_TEMPLATE(DebugException, 0x2002, (MSR_KERNEL & ~(MSR_ME|MSR_DE|MSR_CE)), NOCOPY, debug_transfer_to_handler, ret_from_debug_exc)
+#else
+#define DEBUG_EXCEPTION \
+ START_EXCEPTION(Debug); \
+ CRITICAL_EXCEPTION_PROLOG; \
+ \
+ /* \
+ * If there is a single step or branch-taken exception in an \
+ * exception entry sequence, it was probably meant to apply to \
+ * the code where the exception occurred (since exception entry \
+ * doesn't turn off DE automatically). We simulate the effect \
+ * of turning off DE on entry to an exception handler by turning \
+ * off DE in the CSRR1 value and clearing the debug status. \
+ */ \
+ mfspr r10,SPRN_DBSR; /* check single-step/branch taken */ \
+ andis. r10,r10,DBSR_IC@h; \
+ beq+ 2f; \
+ \
+ lis r10,KERNELBASE@h; /* check if exception in vectors */ \
+ ori r10,r10,KERNELBASE@l; \
+ cmplw r12,r10; \
+ blt+ 2f; /* addr below exception vectors */ \
+ \
+ lis r10,Debug@h; \
+ ori r10,r10,Debug@l; \
+ cmplw r12,r10; \
+ bgt+ 2f; /* addr above exception vectors */ \
+ \
+ /* here it looks like we got an inappropriate debug exception. */ \
+1: rlwinm r9,r9,0,~MSR_DE; /* clear DE in the CSRR1 value */ \
+ lis r10,DBSR_IC@h; /* clear the IC event */ \
+ mtspr SPRN_DBSR,r10; \
+ /* restore state and get out */ \
+ lwz r10,_CCR(r11); \
+ lwz r0,GPR0(r11); \
+ lwz r1,GPR1(r11); \
+ mtcrf 0x80,r10; \
+ mtspr SPRN_CSRR0,r12; \
+ mtspr SPRN_CSRR1,r9; \
+ lwz r9,GPR9(r11); \
+ lwz r12,GPR12(r11); \
+ mtspr CRIT_SPRG,r8; \
+ BOOKE_LOAD_EXC_LEVEL_STACK(CRIT); /* r8 points to the debug stack */ \
+ lwz r10,GPR10-INT_FRAME_SIZE(r8); \
+ lwz r11,GPR11-INT_FRAME_SIZE(r8); \
+ mfspr r8,CRIT_SPRG; \
+ \
+ rfci; \
+ b .; \
+ \
+ /* continue normal handling for a critical exception... */ \
+2: mfspr r4,SPRN_DBSR; \
+ addi r3,r1,STACK_FRAME_OVERHEAD; \
+ EXC_XFER_TEMPLATE(DebugException, 0x2002, (MSR_KERNEL & ~(MSR_ME|MSR_DE|MSR_CE)), NOCOPY, crit_transfer_to_handler, ret_from_crit_exc)
+#endif
+
+#define INSTRUCTION_STORAGE_EXCEPTION \
+ START_EXCEPTION(InstructionStorage) \
+ NORMAL_EXCEPTION_PROLOG; \
+ mfspr r5,SPRN_ESR; /* Grab the ESR and save it */ \
+ stw r5,_ESR(r11); \
+ mr r4,r12; /* Pass SRR0 as arg2 */ \
+ li r5,0; /* Pass zero as arg3 */ \
+ EXC_XFER_EE_LITE(0x0400, handle_page_fault)
+
+#define ALIGNMENT_EXCEPTION \
+ START_EXCEPTION(Alignment) \
+ NORMAL_EXCEPTION_PROLOG; \
+ mfspr r4,SPRN_DEAR; /* Grab the DEAR and save it */ \
+ stw r4,_DEAR(r11); \
+ addi r3,r1,STACK_FRAME_OVERHEAD; \
+ EXC_XFER_EE(0x0600, alignment_exception)
+
+#define PROGRAM_EXCEPTION \
+ START_EXCEPTION(Program) \
+ NORMAL_EXCEPTION_PROLOG; \
+ mfspr r4,SPRN_ESR; /* Grab the ESR and save it */ \
+ stw r4,_ESR(r11); \
+ addi r3,r1,STACK_FRAME_OVERHEAD; \
+ EXC_XFER_STD(0x0700, program_check_exception)
+
+#define DECREMENTER_EXCEPTION \
+ START_EXCEPTION(Decrementer) \
+ NORMAL_EXCEPTION_PROLOG; \
+ lis r0,TSR_DIS@h; /* Setup the DEC interrupt mask */ \
+ mtspr SPRN_TSR,r0; /* Clear the DEC interrupt */ \
+ addi r3,r1,STACK_FRAME_OVERHEAD; \
+ EXC_XFER_LITE(0x0900, timer_interrupt)
+
+#define FP_UNAVAILABLE_EXCEPTION \
+ START_EXCEPTION(FloatingPointUnavailable) \
+ NORMAL_EXCEPTION_PROLOG; \
+ bne load_up_fpu; /* if from user, just load it up */ \
+ addi r3,r1,STACK_FRAME_OVERHEAD; \
+ EXC_XFER_EE_LITE(0x800, KernelFP)
+
+#endif /* __HEAD_BOOKE_H__ */
diff --git a/arch/powerpc/platforms/85xx/Kconfig b/arch/powerpc/platforms/85xx/Kconfig
index c5bc282..d3d0ff7 100644
--- a/arch/powerpc/platforms/85xx/Kconfig
+++ b/arch/powerpc/platforms/85xx/Kconfig
@@ -1,86 +1,30 @@
-config 85xx
- bool
- depends on E500
- default y
-
-config PPC_INDIRECT_PCI_BE
- bool
- depends on 85xx
- default y
-
-menu "Freescale 85xx options"
- depends on E500
+menu "Platform support"
+ depends on PPC_85xx
choice
prompt "Machine Type"
- depends on 85xx
default MPC8540_ADS
config MPC8540_ADS
bool "Freescale MPC8540 ADS"
help
- This option enables support for the MPC 8540 ADS evaluation board.
-
-config MPC8548_CDS
- bool "Freescale MPC8548 CDS"
- help
- This option enablese support for the MPC8548 CDS evaluation board.
-
-config MPC8555_CDS
- bool "Freescale MPC8555 CDS"
- help
- This option enablese support for the MPC8555 CDS evaluation board.
-
-config MPC8560_ADS
- bool "Freescale MPC8560 ADS"
- help
- This option enables support for the MPC 8560 ADS evaluation board.
-
-config SBC8560
- bool "WindRiver PowerQUICC III SBC8560"
- help
- This option enables support for the WindRiver PowerQUICC III
- SBC8560 board.
-
-config STX_GP3
- bool "Silicon Turnkey Express GP3"
- help
- This option enables support for the Silicon Turnkey Express GP3
- board.
+ This option enables support for the MPC 8540 ADS board
endchoice
-# It's often necessary to know the specific 85xx processor type.
-# Fortunately, it is implied (so far) from the board type, so we
-# don't need to ask more redundant questions.
config MPC8540
bool
- depends on MPC8540_ADS
- default y
-
-config MPC8548
- bool
- depends on MPC8548_CDS
- default y
+ select PPC_UDBG_16550
+ select PPC_INDIRECT_PCI
+ default y if MPC8540_ADS
-config MPC8555
- bool
- depends on MPC8555_CDS
- default y
-
-config MPC8560
+config PPC_INDIRECT_PCI_BE
bool
- depends on SBC8560 || MPC8560_ADS || STX_GP3
- default y
-
-config 85xx_PCI2
- bool "Supprt for 2nd PCI host controller"
- depends on MPC8555_CDS
+ depends on PPC_85xx
default y
-config PPC_GEN550
+config MPIC
bool
- depends on MPC8540 || SBC8560 || MPC8555
default y
endmenu
diff --git a/arch/powerpc/platforms/85xx/Makefile b/arch/powerpc/platforms/85xx/Makefile
index 6407197..b443206 100644
--- a/arch/powerpc/platforms/85xx/Makefile
+++ b/arch/powerpc/platforms/85xx/Makefile
@@ -1 +1,4 @@
-# empty makefile so make clean works
+#
+# Makefile for the PowerPC 85xx linux kernel.
+#
+obj-$(CONFIG_PPC_85xx) += mpc85xx.o mpc85xx_ads.o
diff --git a/arch/powerpc/platforms/85xx/mpc8540_ads.h b/arch/powerpc/platforms/85xx/mpc8540_ads.h
new file mode 100644
index 0000000..47609c9
--- /dev/null
+++ b/arch/powerpc/platforms/85xx/mpc8540_ads.h
@@ -0,0 +1,60 @@
+/*
+ * arch/ppc/platforms/85xx/mpc8540_ads.h
+ *
+ * MPC8540ADS board definitions
+ *
+ * Maintainer: Kumar Gala <kumar.gala@freescale.com>
+ *
+ * Copyright 2004 Freescale Semiconductor Inc.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version.
+ *
+ */
+
+#ifndef __MACH_MPC8540ADS_H__
+#define __MACH_MPC8540ADS_H__
+
+#include <linux/config.h>
+#include <linux/initrd.h>
+
+#define BOARD_CCSRBAR ((uint)0xe0000000)
+#define BCSR_ADDR ((uint)0xf8000000)
+#define BCSR_SIZE ((uint)(32 * 1024))
+
+/* PCI interrupt controller */
+#define PIRQA MPC85xx_IRQ_EXT1
+#define PIRQB MPC85xx_IRQ_EXT2
+#define PIRQC MPC85xx_IRQ_EXT3
+#define PIRQD MPC85xx_IRQ_EXT4
+
+#define MPC85XX_PCI1_LOWER_IO 0x00000000
+#define MPC85XX_PCI1_UPPER_IO 0x00ffffff
+
+#define MPC85XX_PCI1_LOWER_MEM 0x80000000
+#define MPC85XX_PCI1_UPPER_MEM 0x9fffffff
+
+#define MPC85XX_PCI1_IO_BASE 0xe2000000
+#define MPC85XX_PCI1_MEM_OFFSET 0x00000000
+
+#define MPC85XX_PCI1_IO_SIZE 0x01000000
+
+/* PCI config */
+#define PCI1_CFG_ADDR_OFFSET (0x8000)
+#define PCI1_CFG_DATA_OFFSET (0x8004)
+
+#define PCI2_CFG_ADDR_OFFSET (0x9000)
+#define PCI2_CFG_DATA_OFFSET (0x9004)
+
+/* Additional register for PCI-X configuration */
+#define PCIX_NEXT_CAP 0x60
+#define PCIX_CAP_ID 0x61
+#define PCIX_COMMAND 0x62
+#define PCIX_STATUS 0x64
+
+/* Offset of CPM register space */
+#define CPM_MAP_ADDR (CCSRBAR + MPC85xx_CPM_OFFSET)
+
+#endif /* __MACH_MPC8540ADS_H__ */
diff --git a/arch/powerpc/platforms/85xx/mpc85xx.c b/arch/powerpc/platforms/85xx/mpc85xx.c
new file mode 100644
index 0000000..8251038
--- /dev/null
+++ b/arch/powerpc/platforms/85xx/mpc85xx.c
@@ -0,0 +1,31 @@
+/*
+ * MPC85xx generic code.
+ *
+ * Maintained by Kumar Gala (see MAINTAINERS for contact information)
+ *
+ * Copyright 2005 Freescale Semiconductor Inc.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version.
+ */
+#include <linux/irq.h>
+#include <linux/module.h>
+#include <asm/irq.h>
+
+extern void abort(void);
+
+void
+mpc85xx_restart(char *cmd)
+{
+ local_irq_disable();
+ abort();
+}
+
+/* For now this is a pass through */
+phys_addr_t fixup_bigphys_addr(phys_addr_t addr, phys_addr_t size)
+{
+ return addr;
+};
+EXPORT_SYMBOL(fixup_bigphys_addr);
diff --git a/arch/powerpc/platforms/85xx/mpc85xx.h b/arch/powerpc/platforms/85xx/mpc85xx.h
new file mode 100644
index 0000000..be75abb
--- /dev/null
+++ b/arch/powerpc/platforms/85xx/mpc85xx.h
@@ -0,0 +1,17 @@
+/*
+ * arch/ppc/platforms/85xx/mpc85xx.h
+ *
+ * MPC85xx soc definitions/function decls
+ *
+ * Maintainer: Kumar Gala <kumar.gala@freescale.com>
+ *
+ * Copyright 2005 Freescale Semiconductor Inc.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version.
+ *
+ */
+
+extern void mpc85xx_restart(char *);
diff --git a/arch/powerpc/platforms/85xx/mpc85xx_ads.c b/arch/powerpc/platforms/85xx/mpc85xx_ads.c
new file mode 100644
index 0000000..41191e9
--- /dev/null
+++ b/arch/powerpc/platforms/85xx/mpc85xx_ads.c
@@ -0,0 +1,208 @@
+/*
+ * MPC85xx setup and early boot code plus other random bits.
+ *
+ * Maintained by Kumar Gala (see MAINTAINERS for contact information)
+ *
+ * Copyright 2005 Freescale Semiconductor Inc.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version.
+ */
+
+#include <linux/config.h>
+#include <linux/stddef.h>
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/errno.h>
+#include <linux/reboot.h>
+#include <linux/pci.h>
+#include <linux/kdev_t.h>
+#include <linux/major.h>
+#include <linux/console.h>
+#include <linux/delay.h>
+#include <linux/irq.h>
+#include <linux/seq_file.h>
+#include <linux/root_dev.h>
+#include <linux/serial.h>
+#include <linux/tty.h> /* for linux/serial_core.h */
+#include <linux/serial_core.h>
+#include <linux/initrd.h>
+#include <linux/module.h>
+#include <linux/fsl_devices.h>
+#include <linux/serial_core.h>
+#include <linux/serial_8250.h>
+
+#include <asm/system.h>
+#include <asm/pgtable.h>
+#include <asm/page.h>
+#include <asm/atomic.h>
+#include <asm/time.h>
+#include <asm/io.h>
+#include <asm/machdep.h>
+#include <asm/bootinfo.h>
+#include <asm/pci-bridge.h>
+#include <asm/mpc85xx.h>
+#include <asm/irq.h>
+#include <asm/immap_85xx.h>
+#include <asm/prom.h>
+#include <asm/mpic.h>
+#include <mm/mmu_decl.h>
+#include <asm/udbg.h>
+
+#include <sysdev/fsl_soc.h>
+#include "mpc85xx.h"
+
+#ifndef CONFIG_PCI
+unsigned long isa_io_base = 0;
+unsigned long isa_mem_base = 0;
+#endif
+
+
+/*
+ * Internal interrupts are all Level Sensitive, and Positive Polarity
+ *
+ * Note: Likely, this table and the following function should be
+ * obtained and derived from the OF Device Tree.
+ */
+static u_char mpc85xx_ads_openpic_initsenses[] __initdata = {
+ MPC85XX_INTERNAL_IRQ_SENSES,
+ 0x0, /* External 0: */
+#if defined(CONFIG_PCI)
+ (IRQ_SENSE_LEVEL | IRQ_POLARITY_NEGATIVE), /* Ext 1: PCI slot 0 */
+ (IRQ_SENSE_LEVEL | IRQ_POLARITY_NEGATIVE), /* Ext 2: PCI slot 1 */
+ (IRQ_SENSE_LEVEL | IRQ_POLARITY_NEGATIVE), /* Ext 3: PCI slot 2 */
+ (IRQ_SENSE_LEVEL | IRQ_POLARITY_NEGATIVE), /* Ext 4: PCI slot 3 */
+#else
+ 0x0, /* External 1: */
+ 0x0, /* External 2: */
+ 0x0, /* External 3: */
+ 0x0, /* External 4: */
+#endif
+ (IRQ_SENSE_LEVEL | IRQ_POLARITY_NEGATIVE), /* External 5: PHY */
+ 0x0, /* External 6: */
+ (IRQ_SENSE_LEVEL | IRQ_POLARITY_NEGATIVE), /* External 7: PHY */
+ 0x0, /* External 8: */
+ 0x0, /* External 9: */
+ 0x0, /* External 10: */
+ 0x0, /* External 11: */
+};
+
+
+void __init mpc85xx_ads_pic_init(void)
+{
+ struct mpic *mpic1;
+ phys_addr_t OpenPIC_PAddr;
+
+ /* Determine the Physical Address of the OpenPIC regs */
+ OpenPIC_PAddr = get_immrbase() + MPC85xx_OPENPIC_OFFSET;
+
+ mpic1 = mpic_alloc(OpenPIC_PAddr,
+ MPIC_PRIMARY | MPIC_WANTS_RESET | MPIC_BIG_ENDIAN,
+ 4, MPC85xx_OPENPIC_IRQ_OFFSET, 0, 250,
+ mpc85xx_ads_openpic_initsenses,
+ sizeof(mpc85xx_ads_openpic_initsenses), " OpenPIC ");
+ BUG_ON(mpic1 == NULL);
+ mpic_assign_isu(mpic1, 0, OpenPIC_PAddr + 0x10200);
+ mpic_assign_isu(mpic1, 1, OpenPIC_PAddr + 0x10280);
+ mpic_assign_isu(mpic1, 2, OpenPIC_PAddr + 0x10300);
+ mpic_assign_isu(mpic1, 3, OpenPIC_PAddr + 0x10380);
+ mpic_assign_isu(mpic1, 4, OpenPIC_PAddr + 0x10400);
+ mpic_assign_isu(mpic1, 5, OpenPIC_PAddr + 0x10480);
+ mpic_assign_isu(mpic1, 6, OpenPIC_PAddr + 0x10500);
+ mpic_assign_isu(mpic1, 7, OpenPIC_PAddr + 0x10580);
+
+ /* dummy mappings to get to 48 */
+ mpic_assign_isu(mpic1, 8, OpenPIC_PAddr + 0x10600);
+ mpic_assign_isu(mpic1, 9, OpenPIC_PAddr + 0x10680);
+ mpic_assign_isu(mpic1, 10, OpenPIC_PAddr + 0x10700);
+ mpic_assign_isu(mpic1, 11, OpenPIC_PAddr + 0x10780);
+
+ /* External ints */
+ mpic_assign_isu(mpic1, 12, OpenPIC_PAddr + 0x10000);
+ mpic_assign_isu(mpic1, 13, OpenPIC_PAddr + 0x10080);
+ mpic_assign_isu(mpic1, 14, OpenPIC_PAddr + 0x10100);
+ mpic_init(mpic1);
+}
+
+
+/*
+ * Setup the architecture
+ */
+static void __init
+mpc85xx_ads_setup_arch(void)
+{
+ struct device_node *cpu;
+
+ if (ppc_md.progress)
+ ppc_md.progress("mpc85xx_ads_setup_arch()", 0);
+
+ cpu = of_find_node_by_type(NULL, "cpu");
+ if (cpu != 0) {
+ unsigned int *fp;
+
+ fp = (int *)get_property(cpu, "clock-frequency", NULL);
+ if (fp != 0)
+ loops_per_jiffy = *fp / HZ;
+ else
+ loops_per_jiffy = 50000000 / HZ;
+ of_node_put(cpu);
+ }
+
+#ifdef CONFIG_ROOT_NFS
+ ROOT_DEV = Root_NFS;
+#else
+ ROOT_DEV = Root_HDA1;
+#endif
+}
+
+
+void
+mpc85xx_ads_show_cpuinfo(struct seq_file *m)
+{
+ uint pvid, svid, phid1;
+ uint memsize = total_memory;
+
+ pvid = mfspr(SPRN_PVR);
+ svid = mfspr(SPRN_SVR);
+
+ seq_printf(m, "Vendor\t\t: Freescale Semiconductor\n");
+ seq_printf(m, "Machine\t\t: mpc85xx\n");
+ seq_printf(m, "PVR\t\t: 0x%x\n", pvid);
+ seq_printf(m, "SVR\t\t: 0x%x\n", svid);
+
+ /* Display cpu Pll setting */
+ phid1 = mfspr(SPRN_HID1);
+ seq_printf(m, "PLL setting\t: 0x%x\n", ((phid1 >> 24) & 0x3f));
+
+ /* Display the amount of memory */
+ seq_printf(m, "Memory\t\t: %d MB\n", memsize / (1024 * 1024));
+}
+
+
+void __init
+platform_init(void)
+{
+ ppc_md.setup_arch = mpc85xx_ads_setup_arch;
+ ppc_md.show_cpuinfo = mpc85xx_ads_show_cpuinfo;
+
+ ppc_md.init_IRQ = mpc85xx_ads_pic_init;
+ ppc_md.get_irq = mpic_get_irq;
+
+ ppc_md.restart = mpc85xx_restart;
+ ppc_md.power_off = NULL;
+ ppc_md.halt = NULL;
+
+ ppc_md.time_init = NULL;
+ ppc_md.set_rtc_time = NULL;
+ ppc_md.get_rtc_time = NULL;
+ ppc_md.calibrate_decr = generic_calibrate_decr;
+
+ ppc_md.progress = udbg_progress;
+
+ if (ppc_md.progress)
+ ppc_md.progress("mpc85xx_ads platform_init(): exit", 0);
+}
+
+
diff --git a/arch/powerpc/platforms/Makefile b/arch/powerpc/platforms/Makefile
index 04073fd..c4f6b0d 100644
--- a/arch/powerpc/platforms/Makefile
+++ b/arch/powerpc/platforms/Makefile
@@ -8,7 +8,7 @@ endif
obj-$(CONFIG_PPC_CHRP) += chrp/
obj-$(CONFIG_4xx) += 4xx/
obj-$(CONFIG_PPC_83xx) += 83xx/
-obj-$(CONFIG_85xx) += 85xx/
+obj-$(CONFIG_PPC_85xx) += 85xx/
obj-$(CONFIG_PPC_PSERIES) += pseries/
obj-$(CONFIG_PPC_ISERIES) += iseries/
obj-$(CONFIG_PPC_MAPLE) += maple/
^ permalink raw reply related
* Re: [PATCH] powerpc: Add FSL SOC library and setup code
From: Eugene Surovegin @ 2006-01-14 23:47 UTC (permalink / raw)
To: Olof Johansson; +Cc: Kumar Gala, linuxppc-embedded, linuxppc-dev
In-Reply-To: <20060114192158.GS2491@pb15.lixom.net>
On Sat, Jan 14, 2006 at 01:21:58PM -0600, Olof Johansson wrote:
> > +
> > +static phys_addr_t immrbase = -1;
>
> What does immr mean? Maybe a short comment would be good.
IMHO, this is not needed because _everybody_ who is working
with these chips know what IMMR means. And there cannot be _any_
confusion about it. Let's not add useless comments.
We don't add comments describing what MMU, PTE, PCI and IOMMU means,
do we? Any chip specific code has tons of strange abbreviations
which might be puzzling for anybody who isn't familiar with this chip
but are quite clear for anybody who are.
--
Eugene
^ permalink raw reply
* Re: [PATCH] powerpc: Better machine descriptions and kill magic numbers
From: Olof Johansson @ 2006-01-15 0:42 UTC (permalink / raw)
To: Benjamin Herrenschmidt; +Cc: linuxppc-dev list, linuxppc64-dev
In-Reply-To: <1137272686.4855.17.camel@localhost.localdomain>
On Sun, Jan 15, 2006 at 08:04:46AM +1100, Benjamin Herrenschmidt wrote:
>
> > Because of this, I suggest keeping the mach_ part in the syntax, i.e,
> > to use:
> >
> > machine_is(mach_powermac) instead, and not do preprocessor mangling of
> > the label name. The same would go for define_machine().
> >
> > It would seem to make some sense to keep the platform types looking
> > like defines (i.e. MACH_POWERMAC instead of mach_powermac) to keep it
> > consistent with the CPU and firmware feature testing, but the way it's
> > implemented that doesn't make much sense. That's a bit of a shame.
>
> I'm not sure about these ... I'm definitely not fan of going uppercase (and
> it makes no sense vs. the implementation as it's not macros). I also don't
Yeah, that's what I meant with doesn't make sense in this case. I was
just thinking out loud.
> get your problem with grep... the "mach_" construct is totally invisible,
> so people wouldn't grep for it, but for "powermac" alone.
>
> Or do you mean a grep on "powermac" might return too many things unrelated ?
>
> It should be easy enough in this case to grep for machine_is(powermac) instead
> then, after all, that's the only possible use...
One drawback is that source navigation tools like tags and cscope probably
won't find it, and the base strings are quite generic (powermac, cbe/cell,
etc). A stringbased grep will, sure.
> > In the probe loop, ppc_md is copied over for each probe, that seems
> > wasteful.
>
> I changed that from the old way indeed to allow the probe() function to
> override things in ppc_md.
>
> > Shouldn't the probe routines use and modify their own
> > machdep_calls instead of ppc_md, so the copying can be done only once,
> > after a match is found?
>
> I don't like modifying their own machdep calls because the name of the
> structure is hidden. In general, I prefer that things continue to only
> access ppc_md. and not their own machine structure that goes away. That
> means that the code "patching" it can be moved away etc... without
> special case instead of having a special case in probe() that has to
> reference the machine specific copy...
Ok.
> I doubt the memcpy per machine at boot will cause any kind of
> significant performance issue ...
Yeah, that's why I said it seemed wasteful, not that it'd be a
performance issue.
^ permalink raw reply
* [PATCH 001/001] subsystem: Themperature monitoring for ibook 2.2
From: Cedric Pradalier @ 2006-01-15 1:43 UTC (permalink / raw)
To: linuxppc-dev
From: Cedric Pradalier <cedric.pradalier@free.fr>
This driver provides some thermostat monitoring for ibook2,
equipped with a adm103x fan control chip. It also provides
and sysfs access to the adm103x fan control parameters. For
instance
#cat /sys/device/temperature/info?
T:51*C S:56*C R:10*C <-- sensor 0
T:48*C S:76*C R:10*C <-- sensor 1
#echo "56 10" > /sys/device/temperature/info0
make the fan starts at 56 degrees and accelerate
progressively till max at 66 degrees (56 + 10), on the
sensor 0.
The drivers also provides a ioctl access to the fan
parameters. This can be enabled/disabled at compile time.
major/minor number are 63 200, in the experimental range.
Developer's Certificate of Origin
By making a contribution to this project, I certify that:
(a) The contribution was created in whole or in part by me and I
have the right to submit it under the open source license
indicated in the file; or
(b) The contribution is based upon previous work that, to the best
of my knowledge, is covered under an appropriate open source
license and I have the right under that license to submit that
work with modifications, whether created in whole or in part
by me, under the same open source license (unless I am
permitted to submit under a different license), as indicated
in the file; or
(c) I understand and agree that this project and the contribution
are public and that a record of the contribution (including all
personal information I submit with it, including my sign-off) is
maintained indefinitely and may be redistributed consistent with
this project or the open source license(s) involved.
Signed-off-by: Cedric Pradalier <cedric.pradalier@free.fr>
---
diff -Naurp -X linux-2.6.15/Documentation/dontdiff linux-2.6.15/Documentation/therm_adm103x.txt linux-2.6.15-adm/Documentation/therm_adm103x.txt
--- linux-2.6.15/Documentation/therm_adm103x.txt 1970-01-01 10:00:00.000000000 +1000
+++ linux-2.6.15-adm/Documentation/therm_adm103x.txt 2006-01-15 11:27:58.000000000 +1000
@@ -0,0 +1,94 @@
+
+Therm ADM103X Version 1.2.3
+--------------------------------------------------------------
+Authors...: Cedric Pradalier (cedric.pradalier@free.fr)
+
+
+Description
+--------------------------------------------------------------
+ This driver provides some thermostat monitoring for ibook2, equipped
+ with a adm1030 or adm1031 fan control chip. It also provides a sysfs
+ access to the adm103x fan control parameters. For instance
+ * #cat /sys/device/temperature/info?
+ * T:51*C S:56*C R:10*C <-- sensor 0
+ * T:48*C S:76*C R:10*C <-- sensor 1
+ * #echo "56 10" > /sys/device/temperature/info0
+ make the fan starts at 56 degrees and accelerate progressively till max
+ at 66 degrees (56 + 10), on the sensor 0.
+
+ Reading /sys/device/temperatures/minpwm0 shows the minimum speed of the fan.
+ Writing an integer value between 0 and 100 set this value. Low speed make
+ lower noise, but high speed lower temperature faster... Default is 33%.
+ * #echo "45" > /sys/device/temperature/minpwm0
+
+ You can also access the driver with ioctl commands. You need to include
+ /usr/include/linux/therm_adm103x.h in sources. Then, nearly all commands
+ expect a struct IOC_Adm103x argument.
+
+ typedef struct _IOC_Adm103x_ {
+ unsigned char id; /* sensor or fan id */
+ unsigned char mintemp; /* fan starting temp (deg)*/
+ unsigned char rangetemp; /* fan speeding range (deg)*/
+ unsigned char minpwm; /* min fan speed (percent)*/
+ signed long int millitemp; /* current temp (millideg)*/
+ unsigned char hysteresis;/* current histeresis (deg)*/
+ unsigned char reg; /* accessed register */
+ unsigned char value; /* value get/set into reg */
+ } IOC_Adm103x;
+
+ Nine commands are available :
+
+ ADM103X_IOC_GETTEMP
+ Argument : struct IOC_Adm103x * arg.
+ Action : put temperature in milli-degrees in arg->millitemp
+
+ ADM103X_IOC_GETLIMITS
+ Argument : struct IOC_Adm103x * arg.
+ Action : read fan starting temperature and fan speeding range and
+ write them in arg->mintemp and arg->rangetemp.
+ arg->id is used to select which sensor is concerned.
+
+ ADM103X_IOC_SETLIMITS
+ Argument : struct IOC_Adm103x * arg.
+ Action : set fan starting temperature and fan speeding range
+ from arg->mintemp and arg->rangetemp.
+ arg->id is used to select which sensor is concerned.
+
+ ADM103X_IOC_GETMINPWM
+ Argument : struct IOC_Adm103x * arg.
+ Action : read fan minimal speed and write it in arg->minpwm
+ arg->id is used to select which fan is concerned.
+
+ ADM103X_IOC_SETMINPWM
+ Argument : struct IOC_Adm103x * arg.
+ Action : set fan minimal speed and from arg->minpwm
+ arg->id is used to select which fan is concerned.
+
+ ADM103X_IOC_CHECK_IF_FAN_IS_NEEDED
+ Argument : None
+ Action : Compare current temperature to current limits minus hysteresis
+ and switch the fan off is needed.
+
+ ADM103X_IOC_SETHYSTERESIS
+ Argument : struct IOC_Adm103x * arg.
+ Action : Set hysteresis for the ADM103X_IOC_CHECK_IF_FAN_IS_NEEDED
+ command. Default value is 2 degrees.
+
+ ADM103X_IOC_GETHYSTERESIS
+ Argument : struct IOC_Adm103x * arg.
+ Action : Get hysteresis for the ADM103X_IOC_CHECK_IF_FAN_IS_NEEDED
+ command. Value is written in arg->hysteresis. arg->id is used
+ to select which sensor is concerned.
+
+ ADM103X_IOC_GETREGISTER
+ Argument : struct IOC_Adm103x * arg.
+ Action : Read a chip register. Register is selected with arg->reg and
+ written in arg->value.
+
+Copyright
+--------------------------------------------------------------
+From my point of view this is freeware - I don't know what
+others think but...
+Read the COPYING file for the complete GNU license.
+
+
diff -Naurp -X linux-2.6.15/Documentation/dontdiff linux-2.6.15/drivers/macintosh/Kconfig linux-2.6.15-adm/drivers/macintosh/Kconfig
--- linux-2.6.15/drivers/macintosh/Kconfig 2006-01-03 13:21:10.000000000 +1000
+++ linux-2.6.15-adm/drivers/macintosh/Kconfig 2006-01-12 21:26:22.000000000 +1000
@@ -154,6 +154,20 @@ config THERM_WINDTUNNEL
This driver provides some thermostat and fan control for the desktop
G4 "Windtunnel"
+config THERM_ADM103X
+ tristate "Support for thermal monitoring on ibook2"
+ depends on I2C && I2C_KEYWEST && PPC_PMAC && !PPC_PMAC64
+ help
+ This driver provides some thermostat monitoring for ibook2, equipped
+ with a adm103x fan control chip. It also provides and sysfs
+ access to the adm103x fan control parameters. For instance
+ #cat /sys/device/temperature/info?
+ T:51*C S:56*C R:10*C <-- sensor 0
+ T:48*C S:76*C R:10*C <-- sensor 1
+ #echo "56 10" > /sys/device/temperature/info0
+ make the fan starts at 56 degrees and accelerate progressively till max
+ at 66 degrees (56 + 10), on the sensor 0.
+
config THERM_ADT746X
tristate "Support for thermal mgmnt on laptops with ADT 746x chipset"
depends on I2C && I2C_KEYWEST && PPC_PMAC && !PPC_PMAC64
diff -Naurp -X linux-2.6.15/Documentation/dontdiff linux-2.6.15/drivers/macintosh/Makefile linux-2.6.15-adm/drivers/macintosh/Makefile
--- linux-2.6.15/drivers/macintosh/Makefile 2006-01-03 13:21:10.000000000 +1000
+++ linux-2.6.15-adm/drivers/macintosh/Makefile 2006-01-12 21:26:22.000000000 +1000
@@ -25,6 +25,7 @@ obj-$(CONFIG_ADB_MACIO) += macio-adb.o
obj-$(CONFIG_THERM_PM72) += therm_pm72.o
obj-$(CONFIG_THERM_WINDTUNNEL) += therm_windtunnel.o
+obj-$(CONFIG_THERM_ADM103X) += therm_adm103x.o
obj-$(CONFIG_THERM_ADT746X) += therm_adt746x.o
obj-$(CONFIG_WINDFARM) += windfarm_core.o
obj-$(CONFIG_WINDFARM_PM81) += windfarm_smu_controls.o \
diff -Naurp -X linux-2.6.15/Documentation/dontdiff linux-2.6.15/drivers/macintosh/therm_adm103x.c linux-2.6.15-adm/drivers/macintosh/therm_adm103x.c
--- linux-2.6.15/drivers/macintosh/therm_adm103x.c 1970-01-01 10:00:00.000000000 +1000
+++ linux-2.6.15-adm/drivers/macintosh/therm_adm103x.c 2006-01-15 11:38:36.000000000 +1000
@@ -0,0 +1,895 @@
+/*
+ * Device driver for the i2c thermostat found on some iBook G3 (for intance
+ * ibook 2.2) : Namely the adm1030 or adm1031 chip.
+ *
+ * Copyright (C) 2003, 2004 Cedric Pradalier, Colin Leroy,
+ * Rasmus Rohde, Benjamin Herrenschmidt
+ *
+ * Documentation from
+ * http://www.analog.com/UploadedFiles/Data_Sheets/27250527ADM1031_a.pdf
+ * http://www.analog.com/UploadedFiles/Data_Sheets/878926113ADM1030_a.pdf
+ *
+ */
+
+#include <linux/config.h>
+#include <linux/types.h>
+#include <linux/module.h>
+#include <linux/errno.h>
+#include <linux/kernel.h>
+#include <linux/delay.h>
+#include <linux/sched.h>
+#include <linux/i2c.h>
+#include <linux/slab.h>
+#include <linux/init.h>
+#include <linux/spinlock.h>
+#include <linux/smp_lock.h>
+#include <linux/wait.h>
+#include <linux/miscdevice.h>
+#include <linux/syscalls.h>
+#include <linux/poll.h>
+#include <linux/devfs_fs_kernel.h>
+#include <asm/prom.h>
+#include <asm/machdep.h>
+#include <asm/io.h>
+#include <asm/system.h>
+#include <asm/sections.h>
+#include <asm/of_device.h>
+#include <asm/uaccess.h>
+
+
+#define ADM103X_USE_IOCTL
+
+
+#ifdef ADM103X_USE_IOCTL
+#include "linux/therm_adm103x.h"
+#endif
+
+
+/* Choose for display which caracter to use. The degree symbol is */
+/* not supported in all fonts. */
+#define DEGREE_CHARACTER '*'
+
+/* ADM Part */
+static uint8_t ADM_LIMIT_REG[3] = { 0x24, 0x25, 0x26 }; /* local, remote, remote */
+static uint8_t ADM_OFFSET_REG[3] = { 0x0D, 0x0E, 0x0F }; /* local, remote, remote */
+static uint8_t ADM_TEMP_REG[3] = { 0x0a, 0x0b, 0x0c }; /* local, remote, remote */
+#define ADM_RESOL_REG 0x06
+#define ADM_MINPWM_REG 0x22
+
+/* Regs marked with 1 are used on adm1030 and adm1031
+ * regs marked with 2 are used only on adm1031 */
+static uint8_t ADM_USED_REG[0x40] =
+{
+ /* 0 1 2 3 4 5 6 7 8 9 A B C D E F */
+/*0*/ 1,1,1,1,0,0,1,0,1,2,1,1,2,1,1,2,
+/*1*/ 1,2,0,0,1,1,1,0,1,1,1,0,2,2,2,0,
+/*2*/ 1,2,1,1,1,1,2,0,0,0,0,0,0,0,0,0,
+/*3*/ 0,0,0,0,0,0,0,0,0,0,0,0,0,1,1,1
+};
+
+#define DRIVER_NAME "adm103x"
+#define DRIVER_VERSION "2004 May 25"
+#define DRIVER_DESC "Driver for ADM103x thermostat in iBook G3"
+#define DRIVER_INFO DRIVER_VERSION " " DRIVER_DESC
+MODULE_AUTHOR ("Cedric Pradalier <cedric.pradalier@free.fr>");
+MODULE_DESCRIPTION (DRIVER_INFO);
+MODULE_LICENSE ("GPL");
+MODULE_VERSION ("1:2.3");
+
+static int debug = 0;
+
+MODULE_PARM(debug, "i");
+MODULE_PARM_DESC(debug, "If != 0, activates debug output. If > 1, activates monitoring thread.");
+#define DPRINTK if (debug) printk
+
+
+#ifdef ADM103X_USE_IOCTL
+static int useioctl = 0;
+MODULE_PARM(useioctl, "i");
+MODULE_PARM_DESC(useioctl, "if non-zero, activates ioctl interface in /dev/adm103x (10,200)");
+#endif
+
+struct thermostat
+{
+ struct i2c_client clt;
+ uint8_t startfan[3];
+ uint8_t ranges[3];
+ uint8_t regtoread;
+ uint8_t hysteresis[3];
+};
+
+static enum { ADM1030, ADM1031 } therm_type;
+static int therm_bus, therm_address;
+static struct of_device *of_dev;
+static struct thermostat *thermostat;
+
+static pid_t monitor_thread_id;
+static int monitor_running;
+static struct completion monitor_task_compl;
+
+static int attach_one_thermostat (struct i2c_adapter *adapter, int addr,
+ int busno);
+
+/** Encoding of limit in adm103x registers :
+ * Bits 7:3 : min : fan starting temperature divided by 4
+ * Bits 2:0 : range :temperature at which fan motors is running at full speed
+ * |
+ * max| oooooooooooo
+ * | oo
+ *fan | ooo
+ *speed | ooo
+ * | ooo
+ * | oo
+ * min| o
+ * | o
+ * | o<----range--->| Temperature
+ * 0+ooooooooo--------------|--------> in Celcius
+ * min
+ *
+ * */
+static void
+adm_reg2minrange (uint8_t reg, uint8_t * min, uint8_t * range)
+{
+ *min = (reg & 0xF8) >> 1;
+ if ((reg&0x07)>4)
+ printk (KERN_INFO "adm103x: invalid limit temp register %02x\n", reg);
+ *range = 5 * (1<<(reg&0x07));
+}
+
+static uint8_t
+adm_minrange2reg (uint8_t min, uint8_t range)
+{
+ /* Rounding to nearest 4 degree */
+ if (min & 0x2) min += 4;
+ min = (min & 0xFC) << 1;
+ switch (range) {
+ case 5: return min;
+ case 10: return min | 0x01;
+ case 20: return min | 0x02;
+ case 40: return min | 0x03;
+ case 80: return min | 0x04;
+ default:
+ printk (KERN_INFO "adm103x: invalid limit temp range %d-%d\n", min, range);
+ return min;
+ }
+}
+
+static char *
+therm_name (int therm_type)
+{
+ switch (therm_type) {
+ case ADM1030:
+ return "adm1030";
+ case ADM1031:
+ return "adm1031";
+ }
+ return "unknown";
+}
+
+/*****************************************************
+ *
+ * I2C Bus Management
+ *
+ *****************************************************/
+static int
+write_reg (struct thermostat *th, int reg, uint8_t data)
+{
+ uint8_t tmp[2];
+ int rc;
+
+ tmp[0] = reg;
+ tmp[1] = data;
+ rc = i2c_master_send (&th->clt, (const char *) tmp, 2);
+ if (rc < 0)
+ return rc;
+ if (rc != 2)
+ return -ENODEV;
+ return 0;
+}
+
+static int
+read_reg (struct thermostat *th, int reg)
+{
+ uint8_t reg_addr, data;
+ int rc;
+
+ reg_addr = (uint8_t) reg;
+ rc = i2c_master_send (&th->clt, (const char*)®_addr, 1);
+ if (rc < 0)
+ return rc;
+ if (rc != 1)
+ return -ENODEV;
+ rc = i2c_master_recv (&th->clt, (char *) &data, 1);
+ if (rc < 0)
+ return rc;
+ return data;
+}
+
+static int
+attach_thermostat (struct i2c_adapter *adapter)
+{
+ unsigned long bus_no;
+ DPRINTK (KERN_INFO "adm103x: attach_thermostat\n");
+
+
+ if (strncmp (adapter->name, "uni-n", 5))
+ return -ENODEV;
+ bus_no = simple_strtoul (adapter->name + 6, NULL, 10);
+ if (bus_no != therm_bus)
+ return -ENODEV;
+ return attach_one_thermostat (adapter, therm_address, bus_no);
+}
+
+static int
+detach_thermostat (struct i2c_adapter *adapter)
+{
+ struct thermostat *th;
+ DPRINTK (KERN_INFO "adm103x: deattach_thermostat\n");
+
+ if (thermostat == NULL)
+ return 0;
+
+ th = thermostat;
+
+ if (debug>1) {
+ if (monitor_running) {
+ monitor_running = 0;
+ wait_for_completion (&monitor_task_compl);
+ }
+ }
+
+ i2c_detach_client (&th->clt);
+
+ thermostat = NULL;
+
+ kfree (th);
+
+ return 0;
+}
+
+static struct i2c_driver thermostat_driver = {
+ .name = "Apple Thermostat ADM103x",
+ .id = 0xDEAD1030,
+ .flags = I2C_DF_NOTIFY,
+ .attach_adapter = &attach_thermostat,
+ .detach_adapter = &detach_thermostat
+};
+
+static int
+monitor_task (void *arg)
+{
+ /**
+ * Monitoring thread. Only useful in debug. Otherwise, you can
+ * access chip state in sysfs
+ * **/
+ struct thermostat *th = arg;
+ uint8_t temps[3], start[3], range[3];
+ uint8_t nbsensor, reg;
+ int i;
+ start[2] = range[2] = temps[2] = 0;
+
+ lock_kernel ();
+ daemonize ("kfand");
+ unlock_kernel ();
+ strcpy (current->comm, "thermostat");
+ monitor_running = 1;
+
+ while (monitor_running) {
+ set_task_state (current, TASK_UNINTERRUPTIBLE);
+ schedule_timeout (1 * HZ);
+
+ /* Read status */
+ /* local : chip */
+ /* remote 1: CPU ? */
+ /* remote 2: GPU ? */
+ nbsensor = (therm_type == ADM1030) ? 2 : 3;
+ for (i = 0; i < nbsensor; i++) {
+ temps[i] = read_reg (th, ADM_TEMP_REG[i]);
+ reg = read_reg (th, ADM_LIMIT_REG[i]);
+ adm_reg2minrange (reg, &start[i], &range[i]);
+ }
+
+ printk (KERN_INFO "adm103x: Temperature infos: %d,%d,%d%cC\n",
+ temps[0], temps[1], temps[2],DEGREE_CHARACTER);
+ printk (KERN_INFO "adm103x: FanCtrl infos: %d,%d,%d%cC\n",
+ start[0], start[1], start[2],DEGREE_CHARACTER);
+ printk (KERN_INFO "adm103x: FanCtrl infos: %d,%d,%d%cC\n",
+ range[0], range[1], range[2],DEGREE_CHARACTER);
+ }
+
+ complete_and_exit (&monitor_task_compl, 0);
+ return 0;
+}
+
+
+static int attach_one_thermostat (struct i2c_adapter *adapter, int addr, int busno)
+{
+ struct thermostat *th;
+ int rc;
+ int i;
+ uint8_t reg;
+
+ DPRINTK (KERN_INFO "adm103x: attach_one_thermostat\n");
+ if (thermostat)
+ return 0;
+ th = (struct thermostat *) kmalloc (sizeof (struct thermostat), GFP_KERNEL);
+ if (!th)
+ return -ENOMEM;
+ memset (th, 0, sizeof (*th));
+ th->clt.addr = addr;
+ th->clt.adapter = adapter;
+ th->clt.driver = &thermostat_driver;
+ /*th->clt.id = 0xDEAD1030;*/
+ strcpy (th->clt.name, "thermostat");
+
+ rc = read_reg (th, 0);
+ if (rc < 0) {
+ printk (KERN_ERR
+ "adm103x: Thermostat failed to read config from bus %d !\n",
+ busno);
+ kfree (th);
+ return -ENODEV;
+ }
+
+ printk (KERN_INFO "adm103x: %s initializing\n", therm_name (therm_type));
+
+ /* Initializing thermostat structure from chip registers */
+ for (i = 0; i < ((therm_type == ADM1030) ? 2 : 3); i++) {
+ uint8_t min, range, off;
+ reg = read_reg (th, ADM_LIMIT_REG[i]);
+ off = read_reg (th, ADM_OFFSET_REG[i]);
+ adm_reg2minrange (reg, &min, &range);
+ printk (KERN_INFO "adm103x: %s initializing %d:%d+%d%cC\n",
+ therm_name (therm_type), i,
+ (off&0x80)?(min+(off&0x0F)):(min-(off&0x0F)), range,
+ DEGREE_CHARACTER);
+ th->startfan[i] = min;
+ th->ranges[i] = range;
+ th->hysteresis[i] = 2;
+ }
+ th->regtoread = 0;
+ /* activate automatic control and set analog speed input */
+ reg = read_reg (th, 0x00);
+ write_reg (th, 0x00, reg | 0x84);
+
+ thermostat = th;
+
+ if (i2c_attach_client (&th->clt)) {
+ printk ("adm103x: Thermostat failed to attach client !\n");
+ thermostat = NULL;
+ kfree (th);
+ return -ENODEV;
+ }
+
+ if (debug > 1) {
+ /* In debug we launch a monitoring thread which output
+ * chip state in syslog */
+ init_completion (&monitor_task_compl);
+
+ monitor_thread_id = kernel_thread (monitor_task, th,
+ SIGCHLD | CLONE_KERNEL);
+ }
+
+ return 0;
+}
+
+
+/*****************************************************
+ *
+ * ADM103X Data Manipulation
+ *
+ *****************************************************/
+
+
+
+static int set_limit (struct thermostat *th, int i, int min, int range)
+{
+ int error;
+ uint8_t offset = min % 4;
+ uint8_t limit = adm_minrange2reg ((offset==0)?min:(min-offset+4), range);
+ th->startfan[i] = min;
+ th->ranges[i] = range;
+ printk (KERN_INFO "adm103x: Setting FanCtrl infos: %d : %d+%d%cC\n",
+ i, th->startfan[i], th->ranges[i],DEGREE_CHARACTER);
+ error = write_reg (th, ADM_OFFSET_REG[i], (offset==0)?0x00:(4-offset));
+ if (error) return error;
+ error = write_reg (th, ADM_LIMIT_REG[i], limit);
+ return error;
+}
+
+static int get_limit (struct thermostat *th, int i, uint8_t * min, uint8_t * range)
+{
+ uint8_t lim;
+ uint8_t o = read_reg(th, ADM_OFFSET_REG[i]);
+ uint8_t l = read_reg(th, ADM_LIMIT_REG[i]);
+ adm_reg2minrange(l,&lim,range);
+ *min = (o&0x80)?(lim+(o&0x0F)):(lim-(o&0x0F));
+ return 0;
+}
+
+static int get_temp(struct thermostat * th, int i, int32_t * millitemp)
+{
+ uint16_t resol=0;
+ uint8_t o = read_reg(th, ADM_OFFSET_REG[i]);
+ uint8_t t = read_reg(th, ADM_TEMP_REG[i]);
+ uint8_t p = read_reg(th, ADM_RESOL_REG);
+ switch(i){
+ case 0: resol = ((((uint16_t)p)&0xC0)>>6)*250; break;
+ case 1: resol = (((uint16_t)p)&0x07)*125; break;
+ case 2: resol = ((((uint16_t)p)&0x38)>>3)*125; break;
+ }
+ t = (o&0x80)?(t+(o&0x0F)):(t-(o&0x0F));
+ *millitemp = (((int32_t)t)*1000)+resol;
+ return 0;
+}
+
+static uint8_t show_minPWM(struct thermostat * th, uint8_t index)
+{
+ static uint8_t s[16]={0,7,14,20, 27,33,40,47, 53,60,67,73, 80,87,93,100};
+ uint8_t minpwm = read_reg(th, ADM_MINPWM_REG);
+ uint8_t val=0;
+ switch (index) {
+ case 0 : val = s[minpwm&0x0F]; break;
+ case 1 : val = s[(minpwm&0xF0)>>4]; break;
+ }
+ return val;
+}
+
+static int set_minPWM(struct thermostat * th, int newpwm, uint8_t index)
+{
+ static uint8_t s[16]={0,7,14,20, 27,33,40,47, 53,60,67,73, 80,87,93,100};
+ uint8_t i,minpwm;
+ int d;
+ for (i=0;i<16;i++) {
+ d=s[i]-newpwm;
+ if ((d<=3)&&(d>-3))
+ break;
+ }
+ minpwm = read_reg(th, ADM_MINPWM_REG);
+ switch(index) {
+ case 0 : minpwm = (minpwm&0xF0) | i; break;
+ case 1 : minpwm = (minpwm&0x0F) | (i<<4); break;
+ }
+ return write_reg(th,ADM_MINPWM_REG,minpwm);
+}
+
+#ifdef ADM103X_USE_IOCTL
+static int checkIfFanIsNeeded(struct thermostat * th)
+{
+ int i,nbsensors;
+ uint8_t lim,rge;
+ int32_t millitemp;
+ uint8_t fanIsNeeded = 0;
+ nbsensors = (therm_type==ADM1030)?2:3;
+ DPRINTK (KERN_INFO "adm103x: check if fan is needed \n");
+ for (i=0;i<nbsensors;i++) {
+ get_limit(th,i,&lim,&rge);
+ get_temp(th,i,&millitemp);
+ DPRINTK (KERN_INFO "adm103x: sensor %d : %d.%d <? %d - %d \n",i,
+ millitemp/1000, millitemp%1000, lim,th->hysteresis[i] );
+ if (millitemp > 1000*((int32_t)lim - th->hysteresis[i]))
+ fanIsNeeded = 1;
+ }
+ if (!fanIsNeeded) {
+ uint8_t lim[3],rge[3];
+ DPRINTK (KERN_INFO "adm103x: fan is not needed \n");
+ for (i=0;i<nbsensors;i++) {
+ /* The following hack stop the fan is no-longer needed. */
+ /* Hard coded adm1030/1 hysteresis is 5 degrees. */
+ get_limit(th,i,&lim[i],&rge[i]);
+ set_limit(th,i,lim[i]+6,rge[i]);
+ }
+ set_task_state (current, TASK_UNINTERRUPTIBLE);
+ schedule_timeout (1 * HZ);
+ for (i=0;i<nbsensors;i++) {
+ set_limit(th,i,lim[i],rge[i]);
+ }
+ }
+ else
+ {
+ DPRINTK (KERN_INFO "adm103x: fan is needed \n");
+ }
+ return 0;
+}
+#endif
+
+
+/*****************************************************
+ *
+ * SYSFS Access
+ *
+ *****************************************************/
+
+
+/*
+ * Now, unfortunately, sysfs doesn't give us a nice void * we could
+ * pass around to the attribute functions, so we don't really have
+ * choice but implement a bunch of them...
+ *
+ */
+#define BUILD_SHOWPWM_FUNC(index) \
+static ssize_t show_minPWM##index(struct device *dev, struct device_attribute *attr, char *buf)\
+{ uint8_t minpwm = 0; \
+ minpwm = show_minPWM(thermostat,index); \
+ return sprintf(buf, "%3d%%\n", minpwm); }
+
+#define BUILD_SETPWM_FUNC(index) \
+static ssize_t set_minPWM##index(struct device *dev, struct device_attribute *attr, const char *buf, size_t count)\
+{ \
+ int newpwm; \
+ if (sscanf (buf, "%d", &newpwm) != 1)\
+ return -EINVAL;\
+ if ((newpwm < 0) || (newpwm > 100))\
+ return -EINVAL;\
+ set_minPWM(thermostat,newpwm,index); \
+ return count; \
+}
+
+
+static ssize_t show_regtoread(struct device *dev, struct device_attribute *attr, char *buf)
+{
+ return sprintf(buf, "%02X\n", thermostat->regtoread);
+}
+
+static ssize_t show_reg(struct device *dev, struct device_attribute *attr, char *buf)
+{
+ uint8_t reg = 0;
+ reg = read_reg(thermostat, thermostat->regtoread);
+ return sprintf(buf, "%02X\n", reg);
+}
+
+static ssize_t set_regtoread(struct device *dev, struct device_attribute *attr, const char *buf, size_t count)
+{
+ unsigned int r2r;
+ thermostat->regtoread=0;
+ if (sscanf (buf, "%X", &r2r) != 1)
+ return -EINVAL;
+ if ((r2r > 0x3F)||(ADM_USED_REG[r2r]==0)){
+ printk (KERN_INFO
+ "adm103x: invalid register %02X \n", r2r);
+ return -EINVAL;
+ }
+
+ if ((therm_type==ADM1030)&&(ADM_USED_REG[r2r]==2)) {
+ printk (KERN_INFO
+ "adm103x: invalid register %02X on device adm1030\n", r2r);
+ return -EINVAL;
+ }
+ DPRINTK (KERN_INFO "adm103x: register to read : %02X \n", r2r);
+ thermostat->regtoread=r2r;
+ return count;
+}
+
+
+
+#define BUILD_SHOW_FUNC(index) \
+static ssize_t show_info##index(struct device *dev, struct device_attribute *attr, char *buf) \
+{ \
+ uint8_t lim,rge; int32_t millitemp; \
+ get_limit(thermostat,index,&lim,&rge); \
+ get_temp(thermostat,index,&millitemp); \
+ return sprintf(buf, "T:%d.%03u%cC S:%d%cC R:%d%cC H:%d%cC\n", \
+ millitemp/1000, millitemp%1000, DEGREE_CHARACTER, \
+ lim, DEGREE_CHARACTER, \
+ rge, DEGREE_CHARACTER, \
+ thermostat->hysteresis[index],DEGREE_CHARACTER); \
+}
+
+#define BUILD_SET_FUNC(index) \
+static ssize_t set_info##index(struct device *dev, struct device_attribute *attr, const char *buf, size_t count) \
+{ \
+ int start,range,hyst,narg; \
+ narg = sscanf (buf, " %u %u %u", &start, &range, &hyst); \
+ if ((narg != 2) && (narg != 3))return -EINVAL; \
+ if (narg == 2) hyst = 2; \
+ if (start > 124) return -EINVAL; \
+ if ((range!=5)&&(range!=10)&&(range!=20)&&(range!=40)) \
+ return -EINVAL; \
+ if ((hyst < 0) || (hyst > 100)) hyst = 2; \
+ set_limit(thermostat,index,start,range); \
+ thermostat->hysteresis[index] = hyst; \
+ return count; \
+}
+
+
+BUILD_SHOWPWM_FUNC (0)
+BUILD_SETPWM_FUNC (0)
+BUILD_SHOWPWM_FUNC (1)
+BUILD_SETPWM_FUNC (1)
+
+BUILD_SHOW_FUNC (0)
+BUILD_SET_FUNC (0)
+BUILD_SHOW_FUNC (1)
+BUILD_SET_FUNC (1)
+BUILD_SHOW_FUNC (2)
+BUILD_SET_FUNC (2)
+
+static DEVICE_ATTR (info0, S_IRUGO | S_IWUSR, show_info0, set_info0);
+static DEVICE_ATTR (info1, S_IRUGO | S_IWUSR, show_info1, set_info1);
+static DEVICE_ATTR (info2, S_IRUGO | S_IWUSR, show_info2, set_info2);
+static DEVICE_ATTR (minpwm0, S_IRUGO | S_IWUSR, show_minPWM0, set_minPWM0);
+static DEVICE_ATTR (minpwm1, S_IRUGO | S_IWUSR, show_minPWM1, set_minPWM1);
+static DEVICE_ATTR (regtoread, S_IRUGO | S_IWOTH , show_regtoread, set_regtoread);
+static DEVICE_ATTR (register, S_IRUGO | S_IWUSR , show_reg, NULL);
+
+/*****************************************************
+ *
+ * IOCTL Access
+ *
+ *****************************************************/
+#ifdef ADM103X_USE_IOCTL
+static int adm103x_open(struct inode *inode, struct file *file)
+{
+ file->private_data = 0;
+ return 0;
+}
+
+static int adm103x_release(struct inode *inode, struct file *file)
+{
+ return 0;
+}
+
+static int adm103x_ioctl(struct inode * inode, struct file *filp,
+ u_int cmd, u_long arg)
+{
+ int error = 0;
+ IOC_Adm103x data;
+
+ switch (cmd) {
+ case ADM103X_IOC_SETLIMITS:
+ /* arg : struct {?id, ?tmin, ?trange} */
+ if (!capable(CAP_SYS_ADMIN))
+ return -EACCES;
+ if (copy_from_user(&data,(void*)arg,sizeof(IOC_Adm103x)))
+ return -EFAULT;
+ if (data.id >= 3) return -EINVAL;
+ if ((data.id >= 2) && (therm_type != ADM1031)) return -EINVAL;
+ if (data.mintemp > 124)
+ return -EINVAL;
+ if ((data.rangetemp!=5)&&(data.rangetemp!=10)&&
+ (data.rangetemp!=20)&&(data.rangetemp!=40))
+ return -EINVAL;
+ set_limit(thermostat,data.id,data.mintemp,data.rangetemp);
+ return 0;
+ case ADM103X_IOC_GETLIMITS:
+ /* arg : struct {?id, !tmin, !trange} */
+ if (copy_from_user(&data,(void*)arg,sizeof(IOC_Adm103x)))
+ return -EFAULT;
+ if (data.id >= 3) return -EINVAL;
+ if ((data.id >= 2) && (therm_type != ADM1031)) return -EINVAL;
+ {
+ uint8_t mt,rt;
+ get_limit(thermostat,data.id,&mt,&rt);
+ data.mintemp = mt;
+ data.rangetemp = rt;
+ }
+ if (copy_to_user((void*)arg,&data,sizeof(IOC_Adm103x)))
+ return -EFAULT;
+ return 0;
+ case ADM103X_IOC_GETTEMP:
+ /* arg : struct {?id, !temp} */
+ if (copy_from_user(&data,(void*)arg,sizeof(IOC_Adm103x)))
+ return -EFAULT;
+ if (data.id >= 3) return -EINVAL;
+ if ((data.id >= 2) && (therm_type != ADM1031)) return -EINVAL;
+ {
+ int32_t millitemp;
+ get_temp(thermostat,data.id,&millitemp);
+ data.millitemp = millitemp;
+ }
+ if (copy_to_user((void*)arg,&data,sizeof(IOC_Adm103x)))
+ return -EFAULT;
+ return 0;
+ case ADM103X_IOC_SETMINPWM:
+ /* arg : struct {?id, ?minpwm} */
+ if (copy_from_user(&data,(void*)arg,sizeof(IOC_Adm103x)))
+ return -EFAULT;
+ if (!capable(CAP_SYS_ADMIN))
+ return -EACCES;
+ if (data.id >= 2) return -EINVAL;
+ if ((data.id >= 1) && (therm_type != ADM1031)) return -EINVAL;
+ if (data.minpwm > 100)
+ return -EINVAL;
+ set_minPWM(thermostat,data.minpwm,data.id);
+ return 0;
+ case ADM103X_IOC_GETMINPWM:
+ /* arg : struct {?id, !minpwm} */
+ if (copy_from_user(&data,(void*)arg,sizeof(IOC_Adm103x)))
+ return -EFAULT;
+ if (data.id >= 2) return -EINVAL;
+ if ((data.id >= 1) && (therm_type != ADM1031)) return -EINVAL;
+ data.minpwm = show_minPWM(thermostat,data.id);
+ if (copy_to_user((void*)arg,&data,sizeof(IOC_Adm103x)))
+ return -EFAULT;
+ return 0;
+ case ADM103X_IOC_CHECK_IF_FAN_IS_NEEDED:
+ /* arg : void */
+ error = checkIfFanIsNeeded(thermostat);
+ return error;
+ case ADM103X_IOC_GETHYSTERESIS:
+ /* arg : struct {?id, !hysteresis} */
+ if (copy_from_user(&data,(void*)arg,sizeof(IOC_Adm103x)))
+ return -EFAULT;
+ if (data.id >= 3) return -EINVAL;
+ if ((data.id >= 2) && (therm_type != ADM1031)) return -EINVAL;
+ data.hysteresis = thermostat->hysteresis[data.id];
+ if (copy_to_user((void*)arg,&data,sizeof(IOC_Adm103x)))
+ return -EFAULT;
+ return 0;
+ case ADM103X_IOC_SETHYSTERESIS:
+ /* arg : struct {?id, ?hysteresis} */
+ if (copy_from_user(&data,(void*)arg,sizeof(IOC_Adm103x)))
+ return -EFAULT;
+ if (!capable(CAP_SYS_ADMIN))
+ return -EACCES;
+ if (data.id >= 3) return -EINVAL;
+ if ((data.id >= 2) && (therm_type != ADM1031)) return -EINVAL;
+ thermostat->hysteresis[data.id] = data.hysteresis;
+ return 0;
+ case ADM103X_IOC_GETREGISTER:
+ /* arg : struct {?id, ?register, !value} */
+ if (copy_from_user(&data,(void*)arg,sizeof(IOC_Adm103x)))
+ return -EFAULT;
+ if ((data.reg > 0x3F)||(ADM_USED_REG[data.reg]==0)){
+ printk (KERN_INFO "adm103x: invalid register %02X \n", data.reg);
+ return -EINVAL;
+ }
+ if ((therm_type==ADM1030)&&(ADM_USED_REG[data.reg]==2)) {
+ printk (KERN_INFO "adm103x: invalid register %02X on device adm1030\n", data.reg);
+ return -EINVAL;
+ }
+ data.value = read_reg(thermostat, data.reg);
+ if (copy_to_user((void*)arg,&data,sizeof(IOC_Adm103x)))
+ return -EFAULT;
+ return 0;
+ }
+ return -EINVAL;
+}
+
+
+static ssize_t adm103x_read(struct file *file, char __user *buf,
+ size_t count, loff_t *ppos)
+{
+ return -EINVAL;
+}
+
+static ssize_t adm103x_write(struct file *file, const char __user *buf,
+ size_t count, loff_t *ppos)
+{
+ return -EINVAL;
+}
+
+static unsigned int adm103x_fpoll(struct file *filp, poll_table *wait)
+{
+ return -EINVAL;
+}
+
+static struct file_operations adm103x_device_fops = {
+ .read = adm103x_read,
+ .write = adm103x_write,
+ .poll = adm103x_fpoll,
+ .ioctl = adm103x_ioctl,
+ .open = adm103x_open,
+ .release = adm103x_release,
+};
+
+
+#endif
+
+/*****************************************************
+ *
+ * Module management
+ *
+ *****************************************************/
+
+
+static int __init
+thermostat_init (void)
+{
+ int error;
+ struct device_node *np;
+ uint32_t *prop;
+
+
+ /* Currently, we only deal with the iBook G3, rev 2.2
+ */
+ np = of_find_node_by_name (NULL, "fan");
+ if (!np)
+ return -ENODEV;
+ if (device_is_compatible (np, "adm1030")) {
+ therm_type = ADM1030;
+ } else if (device_is_compatible (np, "adm1031")) {
+ therm_type = ADM1031;
+ }
+ else
+ return -ENODEV;
+
+ prop = (uint32_t *) get_property (np, "reg", NULL);
+ if (!prop)
+ return -ENODEV;
+ therm_bus = ((*prop) >> 8) & 0x0f;
+ therm_address = ((*prop) & 0xff) >> 1;
+
+ printk (KERN_INFO "adm103x: Thermostat bus: %d, address: 0x%02x\n",
+ therm_bus, therm_address);
+
+#ifndef CONFIG_I2C_KEYWEST
+ request_module ("i2c-keywest");
+#endif
+
+#ifdef ADM103X_USE_IOCTL
+ if (useioctl) {
+ /*
+ * * try to register device major number against driver entry points.
+ * */
+ if (register_chrdev(ADM103X_MAJOR,DRIVER_NAME,&adm103x_device_fops)) {
+ if (devfs_mk_cdev(MKDEV(ADM103X_MAJOR, ADM103X_MINOR) ,
+ S_IFCHR | S_IRUSR | S_IWUSR, DRIVER_NAME)!=0) {
+ printk(KERN_ERR "adm103x: cannot create device.\n");
+ useioctl = 0;
+ }
+ printk(KERN_ERR "adm103x: cannot register major %d device.\n",ADM103X_MAJOR);
+ useioctl = 0;
+ } else
+ printk(KERN_INFO "adm103x: device registered.\n");
+ }
+#endif
+ of_dev = of_platform_device_create (np, "temperatures",NULL);
+
+ if (of_dev == NULL) {
+ printk (KERN_ERR "Can't register temperatures device !\n");
+ return -ENODEV;
+ }
+
+ device_create_file (&of_dev->dev, &dev_attr_register);
+ device_create_file (&of_dev->dev, &dev_attr_regtoread);
+ device_create_file (&of_dev->dev, &dev_attr_info0);
+ device_create_file (&of_dev->dev, &dev_attr_info1);
+ device_create_file (&of_dev->dev, &dev_attr_minpwm0);
+ if (therm_type == ADM1031) {
+ device_create_file (&of_dev->dev, &dev_attr_minpwm1);
+ device_create_file (&of_dev->dev, &dev_attr_info2);
+ }
+
+ error = i2c_add_driver (&thermostat_driver);
+
+ DPRINTK(KERN_INFO "Driver initialized %d\n",error);
+
+ return error;
+}
+
+static void __exit
+thermostat_exit (void)
+{
+ if (of_dev) {
+ device_remove_file (&of_dev->dev, &dev_attr_register);
+ device_remove_file (&of_dev->dev, &dev_attr_regtoread);
+ device_remove_file (&of_dev->dev, &dev_attr_info0);
+ device_remove_file (&of_dev->dev, &dev_attr_info1);
+ device_remove_file (&of_dev->dev, &dev_attr_minpwm0);
+ if (therm_type == ADM1031) {
+ device_remove_file (&of_dev->dev, &dev_attr_minpwm1);
+ device_remove_file (&of_dev->dev, &dev_attr_info2);
+ }
+
+ of_device_unregister (of_dev);
+ }
+#ifdef ADM103X_USE_IOCTL
+ if (useioctl) {
+ devfs_remove(DRIVER_NAME);
+ if (unregister_chrdev(ADM103X_MAJOR,DRIVER_NAME)<0)
+ printk(KERN_ERR "adm103x: cannot deregister %d device.\n",ADM103X_MAJOR);
+ else
+ printk(KERN_INFO "adm103x: driver deregistered.\n");
+ }
+#endif
+ i2c_del_driver (&thermostat_driver);
+}
+
+module_init (thermostat_init);
+module_exit (thermostat_exit);
+
+
+
+
+
diff -Naurp -X linux-2.6.15/Documentation/dontdiff linux-2.6.15/include/linux/therm_adm103x.h linux-2.6.15-adm/include/linux/therm_adm103x.h
--- linux-2.6.15/include/linux/therm_adm103x.h 1970-01-01 10:00:00.000000000 +1000
+++ linux-2.6.15-adm/include/linux/therm_adm103x.h 2006-01-12 21:27:51.000000000 +1000
@@ -0,0 +1,30 @@
+#ifndef THERM_ADM103X_H
+#define THERM_ADM103X_H
+
+#define ADM103X_MINOR 200
+#define ADM103X_MAJOR 63 // Experimental
+
+typedef struct _IOC_Adm103x_ {
+ unsigned char id; /* sensor or fan id */
+ unsigned char mintemp; /* fan starting temp (deg)*/
+ unsigned char rangetemp; /* fan speeding range (deg)*/
+ unsigned char minpwm; /* min fan speed (percent)*/
+ signed long int millitemp; /* current temp (millideg)*/
+ unsigned char hysteresis;/* current histeresis (deg)*/
+ unsigned char reg; /* accessed register */
+ unsigned char value; /* value get/set into reg */
+} IOC_Adm103x;
+
+#define ADM103X_IOC_GETTEMP 1
+#define ADM103X_IOC_GETLIMITS 2
+#define ADM103X_IOC_SETLIMITS 3
+#define ADM103X_IOC_SETMINPWM 4
+#define ADM103X_IOC_GETMINPWM 5
+#define ADM103X_IOC_CHECK_IF_FAN_IS_NEEDED 6
+#define ADM103X_IOC_SETHYSTERESIS 7
+#define ADM103X_IOC_GETHYSTERESIS 8
+#define ADM103X_IOC_GETREGISTER 9
+
+
+
+#endif // THERM_ADM103X_H
--
Cedric
^ permalink raw reply
* Re: powerpc.git tree
From: Stephen Rothwell @ 2006-01-15 5:53 UTC (permalink / raw)
To: will schmidt; +Cc: linuxppc-dev, linuxppc64-dev
In-Reply-To: <43C55852.2060703@vnet.ibm.com>
[-- Attachment #1: Type: text/plain, Size: 646 bytes --]
Hi Will,
On Wed, 11 Jan 2006 13:11:14 -0600 will schmidt <will_schmidt@vnet.ibm.com> wrote:
>
> Paul Mackerras wrote:
> >
> > That means that anyone who is following the powerpc.git tree by doing
> > pulls periodically will need to reset their tree too. Otherwise each
> > pull will do an unnecessary merge.
>
> By reset, do you mean to delete the local tree and pull a fresh one, or something fancier?
I just did a "git fetch -f powerpc" where my .git/remotes/powerpc points
at the powerpc.git tree on kernel.org.
--
Cheers,
Stephen Rothwell sfr@canb.auug.org.au
http://www.canb.auug.org.au/~sfr/
[-- Attachment #2: Type: application/pgp-signature, Size: 189 bytes --]
^ permalink raw reply
* Re: powerpc.git tree
From: Paul Mackerras @ 2006-01-15 6:07 UTC (permalink / raw)
To: will schmidt; +Cc: linuxppc-dev, linuxppc64-dev
In-Reply-To: <43C55852.2060703@vnet.ibm.com>
will schmidt writes:
> Paul Mackerras wrote:
> >
> > That means that anyone who is following the powerpc.git tree by doing
> > pulls periodically will need to reset their tree too. Otherwise each
> > pull will do an unnecessary merge.
>
> Hi Paul,
>
> By reset, do you mean to delete the local tree and pull a fresh
> one, or something fancier?
The powerpc.git tree is now identical to Linus' tree as of a day or so
ago. There are several ways you can reset your tree:
- make a fresh clone of Linus' tree, and make its .git/remotes/powerpc
point at the powerpc.git tree on kernel.org, or
- do "git fetch -f powerpc" (substitute whatever remote name you use
for the powerpc.git tree) (according to Stephen Rothwell), or
- do a pull as you would normally do, then throw away the merge and
the extra objects by doing:
git reset --hard FETCH_HEAD
git prune
- or you can delete the local tree and do a fresh clone.
I will start putting stuff in powerpc.git in the next day or so.
Paul.
^ permalink raw reply
* Re: [PATCH] powerpc: Add FSL SOC library and setup code
From: Olof Johansson @ 2006-01-15 7:15 UTC (permalink / raw)
To: Eugene Surovegin; +Cc: Kumar Gala, linuxppc-embedded, linuxppc-dev
In-Reply-To: <20060114234754.GB29766@gate.ebshome.net>
On Sat, Jan 14, 2006 at 03:47:54PM -0800, Eugene Surovegin wrote:
> On Sat, Jan 14, 2006 at 01:21:58PM -0600, Olof Johansson wrote:
> > > +
> > > +static phys_addr_t immrbase = -1;
> >
> > What does immr mean? Maybe a short comment would be good.
>
> IMHO, this is not needed because _everybody_ who is working
> with these chips know what IMMR means. And there cannot be _any_
> confusion about it. Let's not add useless comments.
I haven't been exposed much yet to embedded 32-bit PPC, I thought at
first that it was something chip-specific, not an architected feature
common across the families. I agree, it doesn't really need further
explanation in this case.
-Olof
^ permalink raw reply
* Re: [PATCH] powerpc: Add FSL SOC library and setup code
From: Kumar Gala @ 2006-01-15 7:31 UTC (permalink / raw)
To: Olof Johansson; +Cc: Kumar Gala, linuxppc-embedded, linuxppc-dev
In-Reply-To: <20060115071533.GA932@pb15.lixom.net>
On Jan 15, 2006, at 1:15 AM, Olof Johansson wrote:
> On Sat, Jan 14, 2006 at 03:47:54PM -0800, Eugene Surovegin wrote:
>> On Sat, Jan 14, 2006 at 01:21:58PM -0600, Olof Johansson wrote:
>>>> +
>>>> +static phys_addr_t immrbase = -1;
>>>
>>> What does immr mean? Maybe a short comment would be good.
>>
>> IMHO, this is not needed because _everybody_ who is working
>> with these chips know what IMMR means. And there cannot be _any_
>> confusion about it. Let's not add useless comments.
>
> I haven't been exposed much yet to embedded 32-bit PPC, I thought at
> first that it was something chip-specific, not an architected feature
> common across the families. I agree, it doesn't really need further
> explanation in this case.
To be clear its a system level architecture feature on Freescale
SOCs. It goes by a few different names (immrbar, ccsrbar, eumbar),
but the purpose is the same.
- kumar
^ permalink raw reply
* Re: Problems starting /sbin/init
From: David H. Lynch Jr. @ 2006-01-15 9:13 UTC (permalink / raw)
To: srideep.devireddy; +Cc: linuxppc-embedded
In-Reply-To: <6AD9F6A5F6E096408F0B703773355A070E705B@CHN-SNR-MBX01.wipro.com>
srideep.devireddy@wipro.com wrote:
> Hello David ,
>
> I am bringing up Montavista Linux on mpc8272 custom board .But as we completed almost all the configurations and linux is booting well till the NFS or Ramdisk file system is mounted . then it hangs .. when i tried to debug i saw the /sbin/init in the init/main.c is not getting executed . i had printk and checked all the printks are executed but not the /sbin/init and the printks after the init is also executed .so this /sbin/init is not getting excecuting and i am not getting any messages .
>
> Thanks & Regards
> Srideep Reddy D
> Wipro Technologies
>
>
Srideep;
I was eventually able to resolve my problem. My serial console driver
was inadvertently using the physical address of the uart and not the
virtual address. When the TLB entry created in head_4xx.S for that
physical address eventually got overwritten - which coincidentally
occured after loading /init (or /bin/sh or ....) but prior to their
outputting anything.
It is possible but unlikely you are having a similar problem.
Regardless, you can isolate your problem further. You can sprinkle
prink's inside init/main.c to figure out exactly how far you are getting.
If you are actually getting to attempting to start /init, you can
change main.c to start the program of your choice instead of init.
I started with "Hello World" in ppc assmebler with no library dependencies.
You can enable SHOW_SYSCALLS and find out what system calls are
occuring immeditely prior to your system running off the rails.
And I am sure others may have even more and better ideas.
Dave
^ permalink raw reply
* Download Eldk4.0
From: Chinafeng @ 2006-01-15 9:48 UTC (permalink / raw)
To: Linuxppc-embedded
SGk6DQoNCiAgICAgICBXaHkgbm90IGRvd25sb2FkIGVsZGs0LjA/Pz8NCg0KICAgICAgIGZ0cCBo
YXMgc29tZSBlcnJvcnMgIHdoZW4gSSBkb3dubG9hZCBlbGRrNC4wICBieSBmdHAuLi4NCg0KICAg
ICAgIFNwZWVkIGlzIHZlcnkgdmVyeSAgc2xvdy4uLi4uDQoJDQogICAgICAgICAgICAgICAgICAg
ICBXSFk/DQqhoaGhoaGhoaGhoaGhoSAJCQkJDQoNCqGhoaGhoaGhoaGhoaGhoaENCqGhoaGhoaGh
oaGhoaGhoaFjaGluYWZlbmcyMDA4QDE2My5jb20NCqGhoaGhoaGhoaGhoaGhoaGhoaGhMjAwNi0w
MS0xNQ0K
^ permalink raw reply
* Re: PPC440EP/Yosemite PCI misbehavior
From: Stefan Roese @ 2006-01-15 9:21 UTC (permalink / raw)
To: linuxppc-embedded
In-Reply-To: <43C88013.40800@ovro.caltech.edu>
Hi David,
On Saturday 14 January 2006 05:37, David Hawkins wrote:
> I'll go and play with the 440EP DMA controller and see if I can get
> that to burst to the PCI bus.
>
> > access to PCI I/O space causes a machine check exception.
>
> I still get this in 2.6.15, but Wolfgang Denx indicated that
> they'd tested PCI I/O pretty thoroughly, so I'm inclined to
> believe that its my driver that is at fault. I'll do a little
> more digging on that one.
I have to admit, that PCI I/O can't have worked until now on
Yosemite/Yellowstone. I just found a bug in
arch/ppc/platforms/4xx/yosemite.h:
-#define YOSEMITE_PCI_IO_BASE 0x00000000e0000000ULL
+#define YOSEMITE_PCI_IO_BASE 0x00000000e8000000ULL
Please give it a try and let me know if the problem is fixed.
Best regards,
Stefan
^ permalink raw reply
* Re: Download Eldk4.0
From: Wolfgang Denk @ 2006-01-15 14:39 UTC (permalink / raw)
To: Chinafeng; +Cc: Linuxppc-embedded
In-Reply-To: <43CA24BB.1EE448.29192>
In message <43CA24BB.1EE448.29192> you wrote:
> Why not download eldk4.0???
Because it's not released yet?
Best regards,
Wolfgang Denk
--
Software Engineering: Embedded and Realtime Systems, Embedded Linux
Phone: (+49)-8142-66989-10 Fax: (+49)-8142-66989-80 Email: wd@denx.de
Business is like a wheelbarrow. Nothing ever happens until you start
pushing.
^ permalink raw reply
* How to check which CPU we are using? PPC?
From: jeanwelly @ 2006-01-15 15:07 UTC (permalink / raw)
To: Linuxppc-embedded
SG93IHRvIGNoZWNrIHdoaWNoIENQVSB3ZSBhcmUgdXNpbmc/IEFueSBtZXRob2RzPw0KDQoJDQpU
aGFua3MhDQoNCqGhoaGhoaGhoaGhoaGhoaFqZWFud2VsbHkNCqGhoaGhoaGhoaGhoaGhoaFqZWFu
d2VsbHlAMTI2LmNvbQ0KoaGhoaGhoaGhoaGhoaGhoaGhoaEyMDA2LTAxLTE1DQo=
^ permalink raw reply
* [PATCH] PPC32 CPM_UART: update to utilize the new TTY flip API
From: Vitaly Bordug @ 2006-01-15 15:44 UTC (permalink / raw)
To: Paul Mackerras; +Cc: linuxppc-embedded
This replaces old direct usage of tty->flip stuff with relative flip API
calls.
---
drivers/serial/cpm_uart/cpm_uart_core.c | 13 ++++---------
1 files changed, 4 insertions(+), 9 deletions(-)
diff --git a/drivers/serial/cpm_uart/cpm_uart_core.c b/drivers/serial/cpm_uart/cpm_uart_core.c
index 16af562..5e25c2d 100644
--- a/drivers/serial/cpm_uart/cpm_uart_core.c
+++ b/drivers/serial/cpm_uart/cpm_uart_core.c
@@ -252,12 +252,9 @@ static void cpm_uart_int_rx(struct uart_
/* If we have not enough room in tty flip buffer, then we try
* later, which will be the next rx-interrupt or a timeout
*/
- if ((tty->flip.count + i) >= TTY_FLIPBUF_SIZE) {
- tty->flip.work.func((void *)tty);
- if ((tty->flip.count + i) >= TTY_FLIPBUF_SIZE) {
- printk(KERN_WARNING "TTY_DONT_FLIP set\n");
- return;
- }
+ if(tty_buffer_request_room(tty, i) < i) {
+ printk(KERN_WARNING "No room in flip buffer\n");
+ return;
}
/* get pointer */
@@ -276,9 +273,7 @@ static void cpm_uart_int_rx(struct uart_
continue;
error_return:
- *tty->flip.char_buf_ptr++ = ch;
- *tty->flip.flag_buf_ptr++ = flg;
- tty->flip.count++;
+ tty_insert_flip_char(tty, ch, flg);
} /* End while (i--) */
^ permalink raw reply related
* Re: [linux-usb-devel] Re: [2.6 patch] remove unused tmp_buf_sem's
From: Alan Cox @ 2006-01-15 15:46 UTC (permalink / raw)
To: Greg KH
Cc: akpm, Jes Sorensen, tony.luck, linux-ia64, linux-usb-devel,
linux-kernel, Adrian Bunk, linuxppc-dev, torvalds, R.E.Wolff
In-Reply-To: <20060114034903.GA23074@suse.de>
On Gwe, 2006-01-13 at 19:49 -0800, Greg KH wrote:
> On Sat, Jan 14, 2006 at 03:08:16AM +0100, Adrian Bunk wrote:
> > <-- snip -->
> >
> >
> > tmp_buf_sem sems to be a common name for something completely unused...
That would be correct. The old tty driver layer used to call ->write
from both kernel and user contexts according to a flag. Drivers then all
ended up with the same code copying it into a tmp buffer and using a
locking semaphore.
Linus took out that code and arranged that ->write always got a kernel
buffer so the remainders should indeed go.
Alan
^ permalink raw reply
* Re: How to check which CPU we are using? PPC?
From: Wolfgang Denk @ 2006-01-15 17:19 UTC (permalink / raw)
To: jeanwelly; +Cc: Linuxppc-embedded
In-Reply-To: <43CA7AF1.11609B.03655>
In message <43CA7AF1.11609B.03655> you wrote:
> SG93IHRvIGNoZWNrIHdoaWNoIENQVSB3ZSBhcmUgdXNpbmc/IEFueSBtZXRob2RzPw0KDQoJDQpU
> aGFua3MhDQoNCqGhoaGhoaGhoaGhoaGhoaFqZWFud2VsbHkNCqGhoaGhoaGhoaGhoaGhoaFqZWFu
> d2VsbHlAMTI2LmNvbQ0KoaGhoaGhoaGhoaGhoaGhoaGhoaEyMDA2LTAxLTE1DQpfX19fX19fX19f
> X19fX19fX19fX19fX19fX19fX19fX19fX19fX19fX19fX19fXwpMaW51eHBwYy1lbWJlZGRlZCBt
> YWlsaW5nIGxpc3QKTGludXhwcGMtZW1iZWRkZWRAb3psYWJzLm9yZwpodHRwczovL296bGFicy5v
> cmcvbWFpbG1hbi9saXN0aW5mby9saW51eHBwYy1lbWJlZGRlZA==
Please fix your mailer. Don't use base64 encsding. Post plain text,
please.
> How to check which CPU we are using? Any methods?
Check the print on the processor? Check the documentation? Check the
schematics?
Best regards,
Wolfgang Denk
--
Software Engineering: Embedded and Realtime Systems, Embedded Linux
Phone: (+49)-8142-66989-10 Fax: (+49)-8142-66989-80 Email: wd@denx.de
Use C++ to confuse your enemies; use C to produce stable code.
^ permalink raw reply
* Re: AGPGART driver for ArticiaS - ioremap() problem
From: Benjamin Herrenschmidt @ 2006-01-15 21:48 UTC (permalink / raw)
To: Gerhard Pircher; +Cc: linuxppc-dev, debian-powerpc
In-Reply-To: <19351.1137053713@www55.gmx.net>
> Please take a look at the end of my previous mail, where I included the
> debug messages of the driver and the driver code itself. The log shows that
> the physical address is mapped (IMHO) to the PCI memory range (>
> 0x0c0000000). Is this correct? Shouldn't it be mapped to the system memory
> address range?
I don't understand. I would need to now more about what the bridge
actually does to get any sense out of that.
> The aperture size is 4MB, page_order should be 1 and num_entries = 1024.
>
> Hope this helps!? :-)
>
> Thanks!
>
> Regards,
>
> Gerhard
>
> --
> DSL-Aktion wegen großer Nachfrage bis 28.2.2006 verlängert:
> GMX DSL-Flatrate 1 Jahr kostenlos* http://www.gmx.net/de/go/dsl
>
>
^ permalink raw reply
* Re: AGPGART driver for ArticiaS - ioremap() problem
From: Gerhard Pircher @ 2006-01-15 23:10 UTC (permalink / raw)
To: Benjamin Herrenschmidt; +Cc: linuxppc-dev, debian-powerpc
[-- Attachment #1: Type: text/plain, Size: 4215 bytes --]
> --- Ursprüngliche Nachricht ---
> Von: Benjamin Herrenschmidt <benh@kernel.crashing.org>
> An: Gerhard Pircher <gerhard_pircher@gmx.net>
> Kopie: linuxppc-dev@ozlabs.org, debian-powerpc@lists.debian.org
> Betreff: Re: AGPGART driver for ArticiaS - ioremap() problem
> Datum: Mon, 16 Jan 2006 08:48:28 +1100
>
> I don't understand. I would need to now more about what
> the bridge actually does to get any sense out of that.
Thanks for answering! It's hard to explain for me what the code does, but I
will try.
I included a cleaned-up version of the AGPGART driver code for the ArticiaS
(AmigaOne/Pegasos1). As mentioned, the driver is based on the VIA AGPGART
driver and uses the agp_generic_create_gatt_table() and
agp_generic_free_gatt_table() functions (well, I copied and renamed this
functions to insert debug code).
Actually at least the bridge does everthing right until now (IMHO :-). The
bridge is detected and also the aperture size is read out correctly from the
registers. After that, the agp_backend_initialize() function in
drivers/cahr/agp/backend.c calls the create_gatt_table() function of the
driver (articias_create_gatt_table). Based on the detected aperture size and
its definitions, this function allocates pages for the GATT table
(alloc_gatt_pages). The function then tries to map this pages with
ioremap_nocache(virt_to_gatt(table, (PAGE_SIZE * (1 << page_order))). But
ioremap_nocache() cannot remap the pages, because the following code snipped
in __ioremap (arch/ppc/mm/pgtable.c) is trigged:
/*
* Don't allow anybody to remap normal RAM that we're using.
* mem_init() sets high_memory so only do the check after that.
*/
if ( mem_init_done && (p < virt_to_phys(high_memory)) )
{
printk("__ioremap(): phys addr "PHYS_FMT" is RAM lr %p\n", p,
__builtin_return_address(0));
return NULL;
}
As it can be seen in the following log, the table address (0xde200000 ->
virt_to_gart(table) = 0x1e200000) is lower than the maximum amount of memory
0x20000000 (512MB) and therefore __ioremap() does not remap the pages.
Debuglog:
agpgart: [ARTICIAS] articias_fetch_size()
agpgart: [ARTICIAS] * non masked temp = 0x6
agpgart: [ARTICIAS] * aperature size loop index #0
agpgart: [ARTICIAS] * values[0].size_value = 1
agpgart: [ARTICIAS] * aperature size loop index #1
agpgart: [ARTICIAS] * values[1].size_value = 2
agpgart: [ARTICIAS] * aperature size loop index #2
agpgart: [ARTICIAS] * values[2].size_value = 3
agpgart: [ARTICIAS] * aperature size loop index #3
agpgart: [ARTICIAS] * values[3].size_value = 4
agpgart: [ARTICIAS] * aperature size loop index #4
agpgart: [ARTICIAS] * values[4].size_value = 5
agpgart: [ARTICIAS] * aperature size loop index #5
agpgart: [ARTICIAS] * values[5].size_value = 6
agpgart: [ARTICIAS] * masked temp = 0x6
agpgart: [ARTICIAS] * values[5].size = 128 (128MB aperture size)
agpgart: [ARTICIAS] * current_size->size = 128
agpgart: [ARTICIAS] * current_size->page_order = 5
agpgart: [ARTICIAS] * current_size->num_entries = 32768
agpgart: [ARTICIAS] * current_size->size_value = 6
agpgart: [ARTICIAS] articias_create_gatt_table()
agpgart: [ARTICIAS] * table address = 0xde200000
agpgart: [ARTICIAS] * table end address = 0xde21ffff
agpgart: [ARTICIAS] * page = 0xc09c4400
agpgart: [ARTICIAS] * gatt_table_real = 0xde200000
agpgart: [ARTICIAS] * agp_gatt_table = 0xde200000
agpgart: [ARTICIAS] * virt_to_gart(table) = 0x1e200000
__ioremap() debug: addr = 0x1e200000
__ioremap() debug: phys addr = 0x1e200000
__ioremap() debug: size = 0x20000
__ioremap() debug: Highmem check
__ioremap() debug: high_memory = 0xe0000000
__ioremap() debug: virt_to_phys(high_memory) = 0x20000000
__ioremap(): phys addr 1e200000 is RAM lr c000f210
agpgart: [ARTICIAS] * gatt_table_real = 0x0
agpgart: unable to get memory for graphics translation table.
agpgart: agp_backend_initialize() failed.
agpgart-articias: probe of 0000:00:00.0 failed with error -12
How can I achieve it that ioremap_nocache() can map the pages or that
alloc_gatt_pages() returns valid pages for the GATT table?
Thanks again!
Regards,
Gerhard
--
Lust, ein paar Euro nebenbei zu verdienen? Ohne Kosten, ohne Risiko!
Satte Provisionen für GMX Partner: http://www.gmx.net/de/go/partner
[-- Warning: decoded text below may be mangled, UTF-8 assumed --]
[-- Attachment #2: articias-agp.c --]
[-- Type: text/x-csrc; name="articias-agp.c", Size: 11419 bytes --]
/*
* ArticiaS AGPGART routines.
*/
#include <linux/types.h>
#include <linux/module.h>
#include <linux/pagemap.h>
#include <linux/pci.h>
#include <asm/pci-bridge.h>
#include <linux/init.h>
#include <linux/agp_backend.h>
#include "agp.h"
static struct pci_device_id agp_articias_pci_table[];
__u32 *agp_gatt_table;
#define ARTICIAS_AGP_EN 0x49 /* bit 0 -> AGP enable */
#define ARTICIAS_GART_EN 0x58 /* bit 6 -> GART enable */
#define ARTICIAS_APSIZE 0x59 /* bits 2:0 set size */
#define ARTICIAS_APBASE 0x59 /* TLB address Base [31:12]*/
#define ARTICIAS_GATTBASE 0x10 /* GART base address register */
#define ARTICIAS_TLB_BASE 0x5A /* bits 16:31 of TLB base address */
#define ARTICIAS_GATT_MASK 0xFFFFF000
#define ARTICIAS_SIZE_MASK 0x07 /* Mask aperture size bits. */
static int articias_fetch_size(void)
{
int i;
u8 temp;
struct aper_size_info_8 *values;
values = A_SIZE_8(agp_bridge->driver->aperture_sizes);
pci_read_config_byte(agp_bridge->dev, ARTICIAS_APSIZE, &temp);
/* Mask the GART/Aperture size selection bits. */
temp = temp & ARTICIAS_SIZE_MASK;
for (i = 0; i < agp_bridge->driver->num_aperture_sizes; i++) {
if (temp == values[i].size_value) {
agp_bridge->previous_size =
agp_bridge->current_size = (void *) (values + i);
/* Geri: Was <(void *) (values)> before, but that
* didn't make sense to me!? Otherwise it would always
* point to the same value!
*/
agp_bridge->aperture_size_idx = i;
return values[i].size;
}
}
printk(KERN_ERR PFX "Unknown aperture size from AGP bridge (0x%x)\n", temp);
return 0;
}
static int articias_configure(void)
{
u32 temp = 0;
u16 shift16 = 0;
u8 shift8 = 0;
struct aper_size_info_8 *current_size;
/* Get current aperture size */
current_size = A_SIZE_8(agp_bridge->current_size);
temp = (u32) agp_bridge->gatt_table_real;
/* Get upper word from dword. Note that the ArticiaS should have 20
* bits for the TLB base address. Otherwise the PCI write config code
* for the aperture size below doesn't make sense!?
*/
shift16 = (u16) (temp>>16);
pci_write_config_word(agp_bridge->dev, ARTICIAS_TLB_BASE, shift16);
/* Get the byte 1 from dword and mask it out with the aperture size. */
shift8 = (u8) (temp>>8);
shift8 &= ~(ARTICIAS_SIZE_MASK);
shift8 |= current_size->size_value;
pci_write_config_byte(agp_bridge->dev, ARTICIAS_APBASE, shift8);
/* Get address to map too */
pci_read_config_dword(agp_bridge->dev, ARTICIAS_GATTBASE, (void *)&temp);
temp = temp & ARTICIAS_GATT_MASK;
agp_bridge->gart_bus_addr = temp;
/* GART control register */
/* Enable GART and bus concurrency */
pci_write_config_byte(agp_bridge->dev, ARTICIAS_GART_EN, 0x41);
/* Enable AGP operation */
pci_write_config_byte(agp_bridge->dev, ARTICIAS_AGP_EN, 0x01);
return 0;
}
int articias_create_gatt_table(struct agp_bridge_data *bridge)
{
char *table;
char *table_end;
int size;
int page_order;
int num_entries;
int i;
void *temp;
struct page *page;
/* The generic routines can't handle 2 level gatt's */
if (bridge->driver->size_type == LVL2_APER_SIZE)
return -EINVAL;
table = NULL;
i = bridge->aperture_size_idx;
temp = bridge->current_size;
size = page_order = num_entries = 0;
if (bridge->driver->size_type != FIXED_APER_SIZE) {
do {
switch (bridge->driver->size_type) {
case U8_APER_SIZE:
size = A_SIZE_8(temp)->size;
page_order =
A_SIZE_8(temp)->page_order;
num_entries =
A_SIZE_8(temp)->num_entries;
break;
case U16_APER_SIZE:
size = A_SIZE_16(temp)->size;
page_order = A_SIZE_16(temp)->page_order;
num_entries = A_SIZE_16(temp)->num_entries;
break;
case U32_APER_SIZE:
size = A_SIZE_32(temp)->size;
page_order = A_SIZE_32(temp)->page_order;
num_entries = A_SIZE_32(temp)->num_entries;
break;
/* This case will never really happen. */
case FIXED_APER_SIZE:
case LVL2_APER_SIZE:
default:
size = page_order = num_entries = 0;
break;
}
table = alloc_gatt_pages(page_order);
if (table == NULL) {
i++;
switch (bridge->driver->size_type) {
case U8_APER_SIZE:
bridge->current_size = A_IDX8(bridge);
break;
case U16_APER_SIZE:
bridge->current_size = A_IDX16(bridge);
break;
case U32_APER_SIZE:
bridge->current_size = A_IDX32(bridge);
break;
/* This case will never really happen. */
case FIXED_APER_SIZE:
case LVL2_APER_SIZE:
default:
bridge->current_size =
bridge->current_size;
break;
}
temp = bridge->current_size;
} else {
bridge->aperture_size_idx = i;
}
} while (!table && (i < bridge->driver->num_aperture_sizes));
} else {
size = ((struct aper_size_info_fixed *) temp)->size;
page_order = ((struct aper_size_info_fixed *) temp)->page_order;
num_entries = ((struct aper_size_info_fixed *) temp)->num_entries;
table = alloc_gatt_pages(page_order);
}
if (table == NULL)
return -ENOMEM;
table_end = table + ((PAGE_SIZE * (1 << page_order)) - 1);
for (page = virt_to_page(table); page <= virt_to_page(table_end); page++)
SetPageReserved(page);
bridge->gatt_table_real = (u32 *) table;
agp_gatt_table = (void *) table;
bridge->driver->cache_flush();
bridge->gatt_table = ioremap_nocache(virt_to_gart(table),
(PAGE_SIZE * (1 << page_order)));
bridge->driver->cache_flush();
if (bridge->gatt_table == NULL) {
for (page = virt_to_page(table); page <= virt_to_page(table_end); page++)
ClearPageReserved(page);
free_gatt_pages(table, page_order);
return -ENOMEM;
}
bridge->gatt_bus_addr = virt_to_gart(bridge->gatt_table_real);
/* AK: bogus, should encode addresses > 4GB */
for (i = 0; i < num_entries; i++) {
writel(bridge->scratch_page, bridge->gatt_table+i);
readl(bridge->gatt_table+i); /* PCI Posting. */
}
return 0;
}
int articias_free_gatt_table(struct agp_bridge_data *bridge)
{
int page_order;
char *table, *table_end;
void *temp;
struct page *page;
temp = bridge->current_size;
switch (bridge->driver->size_type) {
case U8_APER_SIZE:
page_order = A_SIZE_8(temp)->page_order;
break;
case U16_APER_SIZE:
page_order = A_SIZE_16(temp)->page_order;
break;
case U32_APER_SIZE:
page_order = A_SIZE_32(temp)->page_order;
break;
case FIXED_APER_SIZE:
page_order = A_SIZE_FIX(temp)->page_order;
break;
case LVL2_APER_SIZE:
/* The generic routines can't deal with 2 level gatt's */
return -EINVAL;
break;
default:
page_order = 0;
break;
}
/* Do not worry about freeing memory, because if this is
* called, then all agp memory is deallocated and removed
* from the table. */
iounmap(bridge->gatt_table);
table = (char *) bridge->gatt_table_real;
table_end = table + ((PAGE_SIZE * (1 << page_order)) - 1);
for (page = virt_to_page(table); page <= virt_to_page(table_end); page++)
ClearPageReserved(page);
free_gatt_pages(bridge->gatt_table_real, page_order);
agp_gatt_table = NULL;
bridge->gatt_table = NULL;
bridge->gatt_table_real = NULL;
bridge->gatt_bus_addr = 0;
return 0;
}
#endif
static void articias_cleanup(void)
{
struct aper_size_info_8 *previous_size;
previous_size = A_SIZE_8(agp_bridge->previous_size);
pci_write_config_byte(agp_bridge->dev, ARTICIAS_APSIZE,
previous_size->size_value);
}
static void articias_tlbflush(struct agp_memory *mem)
{
u8 temp;
pci_read_config_byte(agp_bridge->dev, ARTICIAS_GART_EN, &temp);
pci_write_config_byte(agp_bridge->dev, ARTICIAS_GART_EN, (temp | 0x80));
pci_write_config_byte(agp_bridge->dev, ARTICIAS_GART_EN, (temp & 0x7F));
return;
}
static struct aper_size_info_8 articias_generic_sizes[7] =
{
/* size, num_entries, page_order, size_value */
{4, 1024, 1, 1},
{8, 2048, 1, 2},
{16, 4096, 2, 3},
{32, 8192, 3, 4},
{64, 16384, 4, 5},
{128, 32768, 5, 6},
{256, 65536, 6, 7},
};
static struct agp_bridge_driver articias_driver = {
.owner = THIS_MODULE,
.aperture_sizes = articias_generic_sizes,
.size_type = U8_APER_SIZE,
.num_aperture_sizes = 7,
.configure = articias_configure,
.fetch_size = articias_fetch_size,
.cleanup = articias_cleanup,
.tlb_flush = articias_tlbflush,
.mask_memory = agp_generic_mask_memory,
.masks = NULL,
.agp_enable = agp_generic_enable,
.cache_flush = global_cache_flush,
.create_gatt_table = articias_create_gatt_table,
.free_gatt_table = articias_free_gatt_table,
.insert_memory = agp_generic_insert_memory,
.remove_memory = agp_generic_remove_memory,
.alloc_by_type = agp_generic_alloc_by_type,
.free_by_type = agp_generic_free_by_type,
.agp_alloc_page = agp_generic_alloc_page,
.agp_destroy_page = agp_generic_destroy_page,
};
static struct agp_device_ids articias_agp_device_ids[] __devinitdata =
{
{
.device_id = PCI_DEVICE_ID_MAI_ARTICIAS,
.chipset_name = "ArticiaS",
},
{ }, /* dummy final entry, always present */
};
static int __devinit agp_articias_probe(struct pci_dev *pdev,
const struct pci_device_id *ent)
{
struct agp_device_ids *devs = articias_agp_device_ids;
struct agp_bridge_data *bridge;
int j = 0;
u8 cap_ptr;
cap_ptr = pci_find_capability(pdev, PCI_CAP_ID_AGP);
if (!cap_ptr)
return -ENODEV;
j = ent - agp_articias_pci_table;
printk (KERN_INFO PFX "Detected MAI %s chipset\n", devs[j].chipset_name);
bridge = agp_alloc_bridge();
if (!bridge)
return -ENOMEM;
#ifdef ARTICIAS_DEBUG
/* Geri: Print all AGP relevant registers of the ArticiaS. */
articias_print_agp_register(pdev);
#endif
bridge->dev = pdev;
bridge->capndx = cap_ptr;
bridge->driver = &articias_driver;
/* Set a higher aperture size! Now it should be 128MB. */
pci_write_config_byte(pdev, ARTICIAS_APSIZE, 0x06);
return agp_add_bridge(bridge);
}
static void __devexit agp_articias_remove(struct pci_dev *pdev)
{
struct agp_bridge_data *bridge = pci_get_drvdata(pdev);
agp_remove_bridge(bridge);
agp_put_bridge(bridge);
}
#ifdef CONFIG_PM
static int agp_articias_suspend(struct pci_dev *pdev, pm_message_t state)
{
pci_save_state (pdev);
pci_set_power_state (pdev, PCI_D3hot);
return 0;
}
static int agp_articias_resume(struct pci_dev *pdev)
{
struct agp_bridge_data *bridge = pci_get_drvdata(pdev);
pci_set_power_state (pdev, PCI_D0);
pci_restore_state(pdev);
if (bridge->driver == &articias_driver)
return articias_configure();
return 0;
}
#endif /* CONFIG_PM */
/* must be the same order as name table above */
static struct pci_device_id agp_articias_pci_table[] = {
#define ID(x) \
{ \
.class = (PCI_CLASS_BRIDGE_HOST << 8), \
.class_mask = ~0, \
.vendor = PCI_VENDOR_ID_MAI, \
.device = x, \
.subvendor = PCI_ANY_ID, \
.subdevice = PCI_ANY_ID, \
}
ID(PCI_DEVICE_ID_MAI_ARTICIAS),
{ }
};
MODULE_DEVICE_TABLE(pci, agp_articias_pci_table);
static struct pci_driver agp_articias_pci_driver = {
.name = "agpgart-articias",
.id_table = agp_articias_pci_table,
.probe = agp_articias_probe,
.remove = agp_articias_remove,
#ifdef CONFIG_PM
.suspend = agp_articias_suspend,
.resume = agp_articias_resume,
#endif
};
static int __init agp_articias_init(void)
{
if (agp_off)
{
return -EINVAL;
}
return pci_register_driver(&agp_articias_pci_driver);
}
static void __exit agp_articias_cleanup(void)
{
pci_unregister_driver(&agp_articias_pci_driver);
}
module_init(agp_articias_init);
module_exit(agp_articias_cleanup);
MODULE_LICENSE("GPL");
MODULE_AUTHOR("Dave Jones <davej@codemonkey.org.uk>");
^ permalink raw reply
* Re: AGPGART driver for ArticiaS - ioremap() problem
From: Benjamin Herrenschmidt @ 2006-01-15 23:25 UTC (permalink / raw)
To: Gerhard Pircher; +Cc: linuxppc-dev, debian-powerpc
In-Reply-To: <13039.1137366615@www38.gmx.net>
> Actually at least the bridge does everthing right until now (IMHO :-). The
> bridge is detected and also the aperture size is read out correctly from the
> registers. After that, the agp_backend_initialize() function in
> drivers/cahr/agp/backend.c calls the create_gatt_table() function of the
> driver (articias_create_gatt_table). Based on the detected aperture size and
> its definitions, this function allocates pages for the GATT table
> (alloc_gatt_pages). The function then tries to map this pages with
> ioremap_nocache(virt_to_gatt(table, (PAGE_SIZE * (1 << page_order))). But
> ioremap_nocache() cannot remap the pages, because the following code snipped
> in __ioremap (arch/ppc/mm/pgtable.c) is trigged:
Yes, you are not allowed to ioremap RAM on ppc at least not with
CONFIG_6xx. You should leave it cacheable and use explicit cache flush
like the UniNorth driver.
> As it can be seen in the following log, the table address (0xde200000 ->
> virt_to_gart(table) = 0x1e200000) is lower than the maximum amount of memory
> 0x20000000 (512MB) and therefore __ioremap() does not remap the pages.
^ permalink raw reply
* Re: [PATCH 00/10] Xilinx Virtex-* updates
From: David H. Lynch Jr. @ 2006-01-16 5:27 UTC (permalink / raw)
To: linuxppc-embedded
In-Reply-To: <87u0c8q9f4.fsf@48ers.dk>
I merged your ml403 changes into my copy of the kernel.org linux-2.6 git
repository, and I am working to adapt my Pico E12-Virtex-4 port to work
with them. I have mostly succeeded, but I am still working through a few
rough spots.
Peter Korsgaard wrote:
>>>>>>"grant" == grant likely <grant.likely@secretlab.ca> writes:
>
>
> grant> Here's a repost of my Xilinx ML300 and ML403 patches with a few
> grant> cleanups, a bit of patch reordering, and rebased to 2.6.15.
>
> Nice, ..
>
> grant> I've tested on an ML403
> grant> Can someone test on an ML300? (I no longer have one)
>
> Works fine here on a ML300-alike board.
>
^ permalink raw reply
* Re: [PATCH 00/10] Xilinx Virtex-* updates
From: Grant Likely @ 2006-01-16 7:30 UTC (permalink / raw)
To: David H. Lynch Jr.; +Cc: linuxppc-embedded
In-Reply-To: <43CB2EAB.7080307@dlasys.net>
David H. Lynch Jr. wrote:
> I merged your ml403 changes into my copy of the kernel.org linux-2.6 git
> repository, and I am working to adapt my Pico E12-Virtex-4 port to work
> with them. I have mostly succeeded, but I am still working through a few
> rough spots.
Cool, thanks! Let me know about anything you've got issues with.
It looks like I missed the merge window for 2.6.16, so this stuff
probably won't get in until 2.6.17. OTOH, that give us some time to get
the weeds out.
Cheers,
g.
--
Grant Likely, B.Sc. P.Eng.
Secret Lab Technologies Ltd.
(403) 663-0761
^ permalink raw reply
page: next (older) | prev (newer) | latest
- recent:[subjects (threaded)|topics (new)|topics (active)]
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox