diff options
author | Arnd Bergmann <arnd@arndb.de> | 2012-03-16 19:51:30 +0000 |
---|---|---|
committer | Arnd Bergmann <arnd@arndb.de> | 2012-03-16 19:51:30 +0000 |
commit | d4ef467aea0fdcd5e75a4bbfaf97e579bbe532f3 (patch) | |
tree | 5b91923fb5031c6963a60ee33ee7671d178f26b2 /arch | |
parent | 4acf18232f80c29906356f0f35b2d5f800b5953d (diff) | |
parent | 71de5c46e0600b72df58269e80da343e354ddbd7 (diff) |
Merge branch 'ux500/dt' into next/dt2
* ux500/dt:
ARM: ux500: Provide local timer support for Device Tree
ARM: ux500: Enable PL022 SSP Controller in Device Tree
ARM: ux500: Enable PL310 Level 2 Cache Controller in Device Tree
ARM: ux500: Enable PL011 AMBA UART Controller for Device Tree
ARM: ux500: Enable Cortex-A9 GIC (Generic Interrupt Controller) in Device Tree
ARM: ux500: db8500: list most devices in the snowball device tree
ARM: ux500: split dts file for snowball into generic part
ARM: ux500: combine the board init functions for DT boot
ARM: ux500: Initial Device Tree support for Snowball
ARM: ux500: CONFIG: Enable Device Tree support for future endeavours
ARM: ux500: fix compilation after local timer rework
(adds dependency on localtimer branch, irqdomain branch and ux500/soc
branch)
Conflicts:
arch/arm/mach-ux500/devices-common.c
This adds patches from Lee Jones, Niklas Hernaeus and myself to provide
initial device tree support on the ux500 platform. The pull request from
Lee contained some other changes, so I rebased the patches on top of
the branches that are actually dependencies for this.
Signed-off-by: Arnd Bergmann <arnd@arndb.de>
Diffstat (limited to 'arch')
73 files changed, 1543 insertions, 785 deletions
diff --git a/arch/arm/boot/dts/db8500.dtsi b/arch/arm/boot/dts/db8500.dtsi new file mode 100644 index 00000000000..d73dce64566 --- /dev/null +++ b/arch/arm/boot/dts/db8500.dtsi @@ -0,0 +1,275 @@ +/* + * Copyright 2012 Linaro Ltd + * + * The code contained herein is licensed under the GNU General Public + * License. You may obtain a copy of the GNU General Public License + * Version 2 or later at the following locations: + * + * http://www.opensource.org/licenses/gpl-license.html + * http://www.gnu.org/copyleft/gpl.html + */ + +/include/ "skeleton.dtsi" + +/ { + soc-u9500 { + #address-cells = <1>; + #size-cells = <1>; + compatible = "stericsson,db8500"; + interrupt-parent = <&intc>; + ranges; + + intc: interrupt-controller@a0411000 { + compatible = "arm,cortex-a9-gic"; + #interrupt-cells = <3>; + #address-cells = <1>; + interrupt-controller; + interrupt-parent; + reg = <0xa0411000 0x1000>, + <0xa0410100 0x100>; + }; + + L2: l2-cache { + compatible = "arm,pl310-cache"; + reg = <0xa0412000 0x1000>; + interrupts = <0 13 4>; + cache-unified; + cache-level = <2>; + }; + + pmu { + compatible = "arm,cortex-a9-pmu"; + interrupts = <0 7 0x4>; + }; + + timer@a0410600 { + compatible = "arm,cortex-a9-twd-timer"; + reg = <0xa0410600 0x20>; + interrupts = <1 13 0x304>; + }; + + rtc@80154000 { + compatible = "stericsson,db8500-rtc"; + reg = <0x80154000 0x1000>; + interrupts = <0 18 0x4>; + }; + + gpio0: gpio@8012e000 { + compatible = "stericsson,db8500-gpio", + "stmicroelectronics,nomadik-gpio"; + reg = <0x8012e000 0x80>; + interrupts = <0 119 0x4>; + supports-sleepmode; + gpio-controller; + }; + + gpio1: gpio@8012e080 { + compatible = "stericsson,db8500-gpio", + "stmicroelectronics,nomadik-gpio"; + reg = <0x8012e080 0x80>; + interrupts = <0 120 0x4>; + supports-sleepmode; + gpio-controller; + }; + + gpio2: gpio@8000e000 { + compatible = "stericsson,db8500-gpio", + "stmicroelectronics,nomadik-gpio"; + reg = <0x8000e000 0x80>; + interrupts = <0 121 0x4>; + supports-sleepmode; + gpio-controller; + }; + + gpio3: gpio@8000e080 { + compatible = "stericsson,db8500-gpio", + "stmicroelectronics,nomadik-gpio"; + reg = <0x8000e080 0x80>; + interrupts = <0 122 0x4>; + supports-sleepmode; + gpio-controller; + }; + + gpio4: gpio@8000e100 { + compatible = "stericsson,db8500-gpio", + "stmicroelectronics,nomadik-gpio"; + reg = <0x8000e100 0x80>; + interrupts = <0 123 0x4>; + supports-sleepmode; + gpio-controller; + }; + + gpio5: gpio@8000e180 { + compatible = "stericsson,db8500-gpio", + "stmicroelectronics,nomadik-gpio"; + reg = <0x8000e180 0x80>; + interrupts = <0 124 0x4>; + supports-sleepmode; + gpio-controller; + }; + + gpio6: gpio@8011e000 { + compatible = "stericsson,db8500-gpio", + "stmicroelectronics,nomadik-gpio"; + reg = <0x8011e000 0x80>; + interrupts = <0 125 0x4>; + supports-sleepmode; + gpio-controller; + }; + + gpio7: gpio@8011e080 { + compatible = "stericsson,db8500-gpio", + "stmicroelectronics,nomadik-gpio"; + reg = <0x8011e080 0x80>; + interrupts = <0 126 0x4>; + supports-sleepmode; + gpio-controller; + }; + + gpio8: gpio@a03fe000 { + compatible = "stericsson,db8500-gpio", + "stmicroelectronics,nomadik-gpio"; + reg = <0xa03fe000 0x80>; + interrupts = <0 127 0x4>; + supports-sleepmode; + gpio-controller; + }; + + usb@a03e0000 { + compatible = "stericsson,db8500-musb", + "mentor,musb"; + reg = <0xa03e0000 0x10000>; + interrupts = <0 23 0x4>; + }; + + dma-controller@801C0000 { + compatible = "stericsson,db8500-dma40", + "stericsson,dma40"; + reg = <0x801C0000 0x1000 0x40010000 0x800>; + interrupts = <0 25 0x4>; + }; + + prcmu@80157000 { + compatible = "stericsson,db8500-prcmu"; + reg = <0x80157000 0x1000>; + interrupts = <46 47>; + #address-cells = <1>; + #size-cells = <0>; + + ab8500@5 { + compatible = "stericsson,ab8500"; + reg = <5>; /* mailbox 5 is i2c */ + interrupts = <0 40 0x4>; + }; + }; + + i2c@80004000 { + compatible = "stericsson,db8500-i2c", "stmicroelectronics,nomadik-i2c"; + reg = <0x80004000 0x1000>; + interrupts = <0 21 0x4>; + #address-cells = <1>; + #size-cells = <0>; + }; + + i2c@80122000 { + compatible = "stericsson,db8500-i2c", "stmicroelectronics,nomadik-i2c"; + reg = <0x80122000 0x1000>; + interrupts = <0 22 0x4>; + #address-cells = <1>; + #size-cells = <0>; + }; + + i2c@80128000 { + compatible = "stericsson,db8500-i2c", "stmicroelectronics,nomadik-i2c"; + reg = <0x80128000 0x1000>; + interrupts = <0 55 0x4>; + #address-cells = <1>; + #size-cells = <0>; + }; + + i2c@80110000 { + compatible = "stericsson,db8500-i2c", "stmicroelectronics,nomadik-i2c"; + reg = <0x80110000 0x1000>; + interrupts = <0 12 0x4>; + #address-cells = <1>; + #size-cells = <0>; + }; + + i2c@8012a000 { + compatible = "stericsson,db8500-i2c", "stmicroelectronics,nomadik-i2c"; + reg = <0x8012a000 0x1000>; + interrupts = <0 51 0x4>; + #address-cells = <1>; + #size-cells = <0>; + }; + + ssp@80002000 { + compatible = "arm,pl022", "arm,primecell"; + reg = <80002000 0x1000>; + interrupts = <0 14 0x4>; + #address-cells = <1>; + #size-cells = <0>; + status = "disabled"; + + // Add one of these for each child device + cs-gpios = <&gpio0 31 &gpio4 14 &gpio4 16 &gpio6 22 &gpio7 0>; + + }; + + uart@80120000 { + compatible = "arm,pl011", "arm,primecell"; + reg = <0x80120000 0x1000>; + interrupts = <0 11 0x4>; + status = "disabled"; + }; + uart@80121000 { + compatible = "arm,pl011", "arm,primecell"; + reg = <0x80121000 0x1000>; + interrupts = <0 19 0x4>; + status = "disabled"; + }; + uart@80007000 { + compatible = "arm,pl011", "arm,primecell"; + reg = <0x80007000 0x1000>; + interrupts = <0 26 0x4>; + status = "disabled"; + }; + + sdi@80126000 { + compatible = "arm,pl18x", "arm,primecell"; + reg = <0x80126000 0x1000>; + interrupts = <0 60 0x4>; + status = "disabled"; + }; + sdi@80118000 { + compatible = "arm,pl18x", "arm,primecell"; + reg = <0x80118000 0x1000>; + interrupts = <0 50 0x4>; + status = "disabled"; + }; + sdi@80005000 { + compatible = "arm,pl18x", "arm,primecell"; + reg = <0x80005000 0x1000>; + interrupts = <0 41 0x4>; + status = "disabled"; + }; + sdi@80119000 { + compatible = "arm,pl18x", "arm,primecell"; + reg = <0x80119000 0x1000>; + interrupts = <0 59 0x4>; + status = "disabled"; + }; + sdi@80114000 { + compatible = "arm,pl18x", "arm,primecell"; + reg = <0x80114000 0x1000>; + interrupts = <0 99 0x4>; + status = "disabled"; + }; + sdi@80008000 { + compatible = "arm,pl18x", "arm,primecell"; + reg = <0x80114000 0x1000>; + interrupts = <0 100 0x4>; + status = "disabled"; + }; + }; +}; diff --git a/arch/arm/boot/dts/highbank.dts b/arch/arm/boot/dts/highbank.dts index 305635bd45c..37c0ff9c8b9 100644 --- a/arch/arm/boot/dts/highbank.dts +++ b/arch/arm/boot/dts/highbank.dts @@ -72,15 +72,15 @@ ranges; timer@fff10600 { - compatible = "arm,smp-twd"; + compatible = "arm,cortex-a9-twd-timer"; reg = <0xfff10600 0x20>; - interrupts = <1 13 0xf04>; + interrupts = <1 13 0xf01>; }; watchdog@fff10620 { - compatible = "arm,cortex-a9-wdt"; + compatible = "arm,cortex-a9-twd-wdt"; reg = <0xfff10620 0x20>; - interrupts = <1 14 0xf04>; + interrupts = <1 14 0xf01>; }; intc: interrupt-controller@fff11000 { diff --git a/arch/arm/boot/dts/imx6q.dtsi b/arch/arm/boot/dts/imx6q.dtsi index 263e8f3664b..4905f51a106 100644 --- a/arch/arm/boot/dts/imx6q.dtsi +++ b/arch/arm/boot/dts/imx6q.dtsi @@ -88,9 +88,9 @@ ranges; timer@00a00600 { - compatible = "arm,smp-twd"; - reg = <0x00a00600 0x100>; - interrupts = <1 13 0xf4>; + compatible = "arm,cortex-a9-twd-timer"; + reg = <0x00a00600 0x20>; + interrupts = <1 13 0xf01>; }; L2: l2-cache@00a02000 { diff --git a/arch/arm/boot/dts/snowball.dts b/arch/arm/boot/dts/snowball.dts new file mode 100644 index 00000000000..359c6d67915 --- /dev/null +++ b/arch/arm/boot/dts/snowball.dts @@ -0,0 +1,139 @@ +/* + * Copyright 2011 ST-Ericsson AB + * + * The code contained herein is licensed under the GNU General Public + * License. You may obtain a copy of the GNU General Public License + * Version 2 or later at the following locations: + * + * http://www.opensource.org/licenses/gpl-license.html + * http://www.gnu.org/copyleft/gpl.html + */ + +/dts-v1/; +/include/ "db8500.dtsi" + +/ { + model = "Calao Systems Snowball platform with device tree"; + compatible = "calaosystems,snowball-a9500"; + + memory { + reg = <0x00000000 0x20000000>; + }; + + gpio_keys { + compatible = "gpio-keys"; + #address-cells = <1>; + #size-cells = <0>; + + button@1 { + debounce_interval = <50>; + wakeup = <1>; + linux,code = <2>; + label = "userpb"; + gpios = <&gpio1 0>; + }; + button@2 { + debounce_interval = <50>; + wakeup = <1>; + linux,code = <3>; + label = "userpb"; + gpios = <&gpio4 23>; + }; + button@3 { + debounce_interval = <50>; + wakeup = <1>; + linux,code = <4>; + label = "userpb"; + gpios = <&gpio4 23>; + }; + button@4 { + debounce_interval = <50>; + wakeup = <1>; + linux,code = <5>; + label = "userpb"; + gpios = <&gpio5 1>; + }; + button@5 { + debounce_interval = <50>; + wakeup = <1>; + linux,code = <6>; + label = "userpb"; + gpios = <&gpio5 2>; + }; + }; + + leds { + compatible = "gpio-leds"; + used-led { + label = "user_led"; + gpios = <&gpio4 14>; + }; + }; + + soc-u9500 { + + external-bus@50000000 { + compatible = "simple-bus"; + reg = <0x50000000 0x10000000>; + #address-cells = <1>; + #size-cells = <1>; + ranges; + + ethernet@50000000 { + compatible = "smsc,9111"; + reg = <0x50000000 0x10000>; + interrupts = <12>; + interrupt-parent = <&gpio4>; + }; + }; + + sdi@80126000 { + status = "enabled"; + cd-gpios = <&gpio6 26>; + }; + + sdi@80114000 { + status = "enabled"; + }; + + uart@80120000 { + status = "okay"; + }; + + uart@80121000 { + status = "okay"; + }; + + uart@80007000 { + status = "okay"; + }; + + i2c@80004000 { + tc3589x@42 { + //compatible = "tc3589x"; + reg = <0x42>; + interrupts = <25>; + interrupt-parent = <&gpio6>; + }; + tps61052@33 { + //compatible = "tps61052"; + reg = <0x33>; + }; + }; + + i2c@80128000 { + lp5521@0x33 { + // compatible = "lp5521"; + reg = <0x33>; + }; + lp5521@0x34 { + // compatible = "lp5521"; + reg = <0x34>; + }; + bh1780@0x29 { + // compatible = "rohm,bh1780gli"; + reg = <0x33>; + }; + }; + }; +}; diff --git a/arch/arm/configs/u8500_defconfig b/arch/arm/configs/u8500_defconfig index 2d7b6e7b727..889d73ac1ae 100644 --- a/arch/arm/configs/u8500_defconfig +++ b/arch/arm/configs/u8500_defconfig @@ -13,6 +13,7 @@ CONFIG_UX500_SOC_DB8500=y CONFIG_MACH_HREFV60=y CONFIG_MACH_SNOWBALL=y CONFIG_MACH_U5500=y +CONFIG_MACH_UX500_DT=y CONFIG_NO_HZ=y CONFIG_HIGH_RES_TIMERS=y CONFIG_SMP=y diff --git a/arch/arm/include/asm/localtimer.h b/arch/arm/include/asm/localtimer.h index c6a18424888..f77ffc1eb0c 100644 --- a/arch/arm/include/asm/localtimer.h +++ b/arch/arm/include/asm/localtimer.h @@ -11,47 +11,24 @@ #define __ASM_ARM_LOCALTIMER_H #include <linux/errno.h> -#include <linux/interrupt.h> struct clock_event_device; -/* - * Setup a per-cpu timer, whether it be a local timer or dummy broadcast - */ -void percpu_timer_setup(void); +struct local_timer_ops { + int (*setup)(struct clock_event_device *); + void (*stop)(struct clock_event_device *); +}; #ifdef CONFIG_LOCAL_TIMERS - -#ifdef CONFIG_HAVE_ARM_TWD - -#include "smp_twd.h" - -#define local_timer_stop(c) twd_timer_stop((c)) - -#else - -/* - * Stop the local timer - */ -void local_timer_stop(struct clock_event_device *); - -#endif - /* - * Setup a local timer interrupt for a CPU. + * Register a local timer driver */ -int local_timer_setup(struct clock_event_device *); - +int local_timer_register(struct local_timer_ops *); #else - -static inline int local_timer_setup(struct clock_event_device *evt) +static inline int local_timer_register(struct local_timer_ops *ops) { return -ENXIO; } - -static inline void local_timer_stop(struct clock_event_device *evt) -{ -} #endif #endif diff --git a/arch/arm/include/asm/smp_twd.h b/arch/arm/include/asm/smp_twd.h index ef9ffba97ad..0f01f4677bd 100644 --- a/arch/arm/include/asm/smp_twd.h +++ b/arch/arm/include/asm/smp_twd.h @@ -18,11 +18,28 @@ #define TWD_TIMER_CONTROL_PERIODIC (1 << 1) #define TWD_TIMER_CONTROL_IT_ENABLE (1 << 2) -struct clock_event_device; +#include <linux/ioport.h> -extern void __iomem *twd_base; +struct twd_local_timer { + struct resource res[2]; +}; -void twd_timer_setup(struct clock_event_device *); -void twd_timer_stop(struct clock_event_device *); +#define DEFINE_TWD_LOCAL_TIMER(name,base,irq) \ +struct twd_local_timer name __initdata = { \ + .res = { \ + DEFINE_RES_MEM(base, 0x10), \ + DEFINE_RES_IRQ(irq), \ + }, \ +}; + +int twd_local_timer_register(struct twd_local_timer *); + +#ifdef CONFIG_HAVE_ARM_TWD +void twd_local_timer_of_register(void); +#else +static inline void twd_local_timer_of_register(void) +{ +} +#endif #endif diff --git a/arch/arm/kernel/smp.c b/arch/arm/kernel/smp.c index cdeb727527d..1ad84a6c9bf 100644 --- a/arch/arm/kernel/smp.c +++ b/arch/arm/kernel/smp.c @@ -246,6 +246,8 @@ static void __cpuinit smp_store_cpu_info(unsigned int cpuid) store_cpu_topology(cpuid); } +static void percpu_timer_setup(void); + /* * This is the secondary CPU boot entry. We're using this CPUs * idle thread stack, but a set of temporary page tables. @@ -459,7 +461,20 @@ static void __cpuinit broadcast_timer_setup(struct clock_event_device *evt) clockevents_register_device(evt); } -void __cpuinit percpu_timer_setup(void) +static struct local_timer_ops *lt_ops; + +#ifdef CONFIG_LOCAL_TIMERS +int local_timer_register(struct local_timer_ops *ops) +{ + if (lt_ops) + return -EBUSY; + + lt_ops = ops; + return 0; +} +#endif + +static void __cpuinit percpu_timer_setup(void) { unsigned int cpu = smp_processor_id(); struct clock_event_device *evt = &per_cpu(percpu_clockevent, cpu); @@ -467,7 +482,7 @@ void __cpuinit percpu_timer_setup(void) evt->cpumask = cpumask_of(cpu); evt->broadcast = smp_timer_broadcast; - if (local_timer_setup(evt)) + if (!lt_ops || lt_ops->setup(evt)) broadcast_timer_setup(evt); } @@ -482,7 +497,8 @@ static void percpu_timer_stop(void) unsigned int cpu = smp_processor_id(); struct clock_event_device *evt = &per_cpu(percpu_clockevent, cpu); - local_timer_stop(evt); + if (lt_ops) + lt_ops->stop(evt); } #endif diff --git a/arch/arm/kernel/smp_twd.c b/arch/arm/kernel/smp_twd.c index 7a79b24597b..fef42b21cec 100644 --- a/arch/arm/kernel/smp_twd.c +++ b/arch/arm/kernel/smp_twd.c @@ -18,20 +18,23 @@ #include <linux/smp.h> #include <linux/jiffies.h> #include <linux/clockchips.h> -#include <linux/irq.h> +#include <linux/interrupt.h> #include <linux/io.h> +#include <linux/of_irq.h> +#include <linux/of_address.h> #include <asm/smp_twd.h> #include <asm/localtimer.h> #include <asm/hardware/gic.h> /* set up by the platform code */ -void __iomem *twd_base; +static void __iomem *twd_base; static struct clk *twd_clk; static unsigned long twd_timer_rate; static struct clock_event_device __percpu **twd_evt; +static int twd_ppi; static void twd_set_mode(enum clock_event_mode mode, struct clock_event_device *clk) @@ -77,7 +80,7 @@ static int twd_set_next_event(unsigned long evt, * If a local timer interrupt has occurred, acknowledge and return 1. * Otherwise, return 0. */ -int twd_timer_ack(void) +static int twd_timer_ack(void) { if (__raw_readl(twd_base + TWD_TIMER_INTSTAT)) { __raw_writel(1, twd_base + TWD_TIMER_INTSTAT); @@ -87,7 +90,7 @@ int twd_timer_ack(void) return 0; } -void twd_timer_stop(struct clock_event_device *clk) +static void twd_timer_stop(struct clock_event_device *clk) { twd_set_mode(CLOCK_EVT_MODE_UNUSED, clk); disable_percpu_irq(clk->irq); @@ -222,28 +225,10 @@ static struct clk *twd_get_clock(void) /* * Setup the local clock events for a CPU. */ -void __cpuinit twd_timer_setup(struct clock_event_device *clk) +static int __cpuinit twd_timer_setup(struct clock_event_device *clk) { struct clock_event_device **this_cpu_clk; - if (!twd_evt) { - int err; - - twd_evt = alloc_percpu(struct clock_event_device *); - if (!twd_evt) { - pr_err("twd: can't allocate memory\n"); - return; - } - - err = request_percpu_irq(clk->irq, twd_handler, - "twd", twd_evt); - if (err) { - pr_err("twd: can't register interrupt %d (%d)\n", - clk->irq, err); - return; - } - } - if (!twd_clk) twd_clk = twd_get_clock(); @@ -260,6 +245,7 @@ void __cpuinit twd_timer_setup(struct clock_event_device *clk) clk->rating = 350; clk->set_mode = twd_set_mode; clk->set_next_event = twd_set_next_event; + clk->irq = twd_ppi; this_cpu_clk = __this_cpu_ptr(twd_evt); *this_cpu_clk = clk; @@ -267,4 +253,95 @@ void __cpuinit twd_timer_setup(struct clock_event_device *clk) clockevents_config_and_register(clk, twd_timer_rate, 0xf, 0xffffffff); enable_percpu_irq(clk->irq, 0); + + return 0; +} + +static struct local_timer_ops twd_lt_ops __cpuinitdata = { + .setup = twd_timer_setup, + .stop = twd_timer_stop, +}; + +static int __init twd_local_timer_common_register(void) +{ + int err; + + twd_evt = alloc_percpu(struct clock_event_device *); + if (!twd_evt) { + err = -ENOMEM; + goto out_free; + } + + err = request_percpu_irq(twd_ppi, twd_handler, "twd", twd_evt); + if (err) { + pr_err("twd: can't register interrupt %d (%d)\n", twd_ppi, err); + goto out_free; + } + + err = local_timer_register(&twd_lt_ops); + if (err) + goto out_irq; + + return 0; + +out_irq: + free_percpu_irq(twd_ppi, twd_evt); +out_free: + iounmap(twd_base); + twd_base = NULL; + free_percpu(twd_evt); + + return err; } + +int __init twd_local_timer_register(struct twd_local_timer *tlt) +{ + if (twd_base || twd_evt) + return -EBUSY; + + twd_ppi = tlt->res[1].start; + + twd_base = ioremap(tlt->res[0].start, resource_size(&tlt->res[0])); + if (!twd_base) + return -ENOMEM; + + return twd_local_timer_common_register(); +} + +#ifdef CONFIG_OF +const static struct of_device_id twd_of_match[] __initconst = { + { .compatible = "arm,cortex-a9-twd-timer", }, + { .compatible = "arm,cortex-a5-twd-timer", }, + { .compatible = "arm,arm11mp-twd-timer", }, + { }, +}; + +void __init twd_local_timer_of_register(void) +{ + struct device_node *np; + int err; + + np = of_find_matching_node(NULL, twd_of_match); + if (!np) { + err = -ENODEV; + goto out; + } + + twd_ppi = irq_of_parse_and_map(np, 0); + if (!twd_ppi) { + err = -EINVAL; + goto out; + } + + twd_base = of_iomap(np, 0); + if (!twd_base) { + err = -ENOMEM; + goto out; + } + + err = twd_local_timer_common_register(); + +out: + WARN(err, "twd_local_timer_of_register failed (%d)\n", err); +} +#endif diff --git a/arch/arm/mach-exynos/mct.c b/arch/arm/mach-exynos/mct.c index 85b5527d091..edc4b9488f2 100644 --- a/arch/arm/mach-exynos/mct.c +++ b/arch/arm/mach-exynos/mct.c @@ -21,6 +21,7 @@ #include <linux/percpu.h> #include <asm/hardware/gic.h> +#include <asm/localtimer.h> #include <plat/cpu.h> @@ -375,7 +376,7 @@ static struct irqaction mct_tick1_event_irq = { .handler = exynos4_mct_tick_isr, }; -static void exynos4_mct_tick_init(struct clock_event_device *evt) +static int __cpuinit exynos4_local_timer_setup(struct clock_event_device *evt) { struct mct_clock_event_device *mevt; unsigned int cpu = smp_processor_id(); @@ -417,17 +418,11 @@ static void exynos4_mct_tick_init(struct clock_event_device *evt) } else { enable_percpu_irq(IRQ_MCT_LOCALTIMER, 0); } -} - -/* Setup the local clock events for a CPU */ -int __cpuinit local_timer_setup(struct clock_event_device *evt) -{ - exynos4_mct_tick_init(evt); return 0; } -void local_timer_stop(struct clock_event_device *evt) +static void exynos4_local_timer_stop(struct clock_event_device *evt) { unsigned int cpu = smp_processor_id(); evt->set_mode(CLOCK_EVT_MODE_UNUSED, evt); @@ -439,6 +434,11 @@ void local_timer_stop(struct clock_event_device *evt) else disable_percpu_irq(IRQ_MCT_LOCALTIMER); } + +static struct local_timer_ops exynos4_mct_tick_ops __cpuinitdata = { + .setup = exynos4_local_timer_setup, + .stop = exynos4_local_timer_stop, +}; #endif /* CONFIG_LOCAL_TIMERS */ static void __init exynos4_timer_resources(void) @@ -458,6 +458,8 @@ static void __init exynos4_timer_resources(void) WARN(err, "MCT: can't request IRQ %d (%d)\n", IRQ_MCT_LOCALTIMER, err); } + + local_timer_register(&exynos4_mct_tick_ops); #endif /* CONFIG_LOCAL_TIMERS */ } diff --git a/arch/arm/mach-highbank/Makefile b/arch/arm/mach-highbank/Makefile index 986958a5a72..f8437dd238c 100644 --- a/arch/arm/mach-highbank/Makefile +++ b/arch/arm/mach-highbank/Makefile @@ -1,6 +1,5 @@ obj-y := clock.o highbank.o system.o obj-$(CONFIG_DEBUG_HIGHBANK_UART) += lluart.o obj-$(CONFIG_SMP) += platsmp.o -obj-$(CONFIG_LOCAL_TIMERS) += localtimer.o obj-$(CONFIG_HOTPLUG_CPU) += hotplug.o obj-$(CONFIG_PM_SLEEP) += pm.o diff --git a/arch/arm/mach-highbank/highbank.c b/arch/arm/mach-highbank/highbank.c index 8394d512a40..bb1684f9b68 100644 --- a/arch/arm/mach-highbank/highbank.c +++ b/arch/arm/mach-highbank/highbank.c @@ -27,6 +27,7 @@ #include <asm/cacheflush.h> #include <asm/smp_plat.h> #include <asm/smp_scu.h> +#include <asm/smp_twd.h> #include <asm/hardware/arm_timer.h> #include <asm/hardware/timer-sp.h> #include <asm/hardware/gic.h> @@ -111,6 +112,8 @@ static void __init highbank_timer_init(void) sp804_clocksource_init(timer_base + 0x20, "timer1"); sp804_clockevents_init(timer_base, irq, "timer0"); + + twd_local_timer_of_register(); } static struct sys_timer highbank_timer = { diff --git a/arch/arm/mach-highbank/localtimer.c b/arch/arm/mach-highbank/localtimer.c deleted file mode 100644 index 5a00e7945fd..00000000000 --- a/arch/arm/mach-highbank/localtimer.c +++ /dev/null @@ -1,40 +0,0 @@ -/* - * Copyright 2010-2011 Calxeda, Inc. - * Based on localtimer.c, Copyright (C) 2002 ARM Ltd. - * - * This program is free software; you can redistribute it and/or modify it - * under the terms and conditions of the GNU General Public License, - * version 2, as published by the Free Software Foundation. - * - * This program is distributed in the hope it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for - * more details. - * - * You should have received a copy of the GNU General Public License along with - * this program. If not, see <http://www.gnu.org/licenses/>. - */ -#include <linux/init.h> -#include <linux/clockchips.h> -#include <linux/of.h> -#include <linux/of_address.h> -#include <linux/of_irq.h> - -#include <asm/smp_twd.h> - -/* - * Setup the local clock events for a CPU. - */ -int __cpuinit local_timer_setup(struct clock_event_device *evt) -{ - struct device_node *np; - - np = of_find_compatible_node(NULL, NULL, "arm,smp-twd"); - if (!twd_base) { - twd_base = of_iomap(np, 0); - WARN_ON(!twd_base); - } - evt->irq = irq_of_parse_and_map(np, 0); - twd_timer_setup(evt); - return 0; -} diff --git a/arch/arm/mach-imx/Makefile b/arch/arm/mach-imx/Makefile index 4ffeca7ee25..8f57daf5e79 100644 --- a/arch/arm/mach-imx/Makefile +++ b/arch/arm/mach-imx/Makefile @@ -72,7 +72,6 @@ obj-$(CONFIG_CPU_V7) += head-v7.o AFLAGS_head-v7.o :=-Wa,-march=armv7-a obj-$(CONFIG_SMP) += platsmp.o obj-$(CONFIG_HOTPLUG_CPU) += hotplug.o -obj-$(CONFIG_LOCAL_TIMERS) += localtimer.o obj-$(CONFIG_SOC_IMX6Q) += clock-imx6q.o mach-imx6q.o ifeq ($(CONFIG_PM),y) diff --git a/arch/arm/mach-imx/localtimer.c b/arch/arm/mach-imx/localtimer.c deleted file mode 100644 index 3a163515d41..00000000000 --- a/arch/arm/mach-imx/localtimer.c +++ /dev/null @@ -1,35 +0,0 @@ -/* - * Copyright 2011 Freescale Semiconductor, Inc. - * Copyright 2011 Linaro Ltd. - * - * The code contained herein is licensed under the GNU General Public - * License. You may obtain a copy of the GNU General Public License - * Version 2 or later at the following locations: - * - * http://www.opensource.org/licenses/gpl-license.html - * http://www.gnu.org/copyleft/gpl.html - */ - -#include <linux/init.h> -#include <linux/clockchips.h> -#include <linux/of_address.h> -#include <linux/of_irq.h> -#include <asm/smp_twd.h> - -/* - * Setup the local clock events for a CPU. - */ -int __cpuinit local_timer_setup(struct clock_event_device *evt) -{ - struct device_node *np; - - np = of_find_compatible_node(NULL, NULL, "arm,smp-twd"); - if (!twd_base) { - twd_base = of_iomap(np, 0); - WARN_ON(!twd_base); - } - evt->irq = irq_of_parse_and_map(np, 0); - twd_timer_setup(evt); - - return 0; -} diff --git a/arch/arm/mach-imx/mach-imx6q.c b/arch/arm/mach-imx/mach-imx6q.c index 379b1a9cd22..7696dfa2bdb 100644 --- a/arch/arm/mach-imx/mach-imx6q.c +++ b/arch/arm/mach-imx/mach-imx6q.c @@ -21,6 +21,7 @@ #include <linux/of_platform.h> #include <linux/phy.h> #include <linux/micrel_phy.h> +#include <asm/smp_twd.h> #include <asm/hardware/cache-l2x0.h> #include <asm/hardware/gic.h> #include <asm/mach/arch.h> @@ -120,6 +121,7 @@ static void __init imx6q_init_irq(void) static void __init imx6q_timer_init(void) { mx6q_clocks_init(); + twd_local_timer_of_register(); } static struct sys_timer imx6q_timer = { diff --git a/arch/arm/mach-msm/timer.c b/arch/arm/mach-msm/timer.c index 11d0d8f2656..75f4be40b3e 100644 --- a/arch/arm/mach-msm/timer.c +++ b/arch/arm/mach-msm/timer.c @@ -127,6 +127,45 @@ static struct clocksource msm_clocksource = { .flags = CLOCK_SOURCE_IS_CONTINUOUS, }; +#ifdef CONFIG_LOCAL_TIMERS +static int __cpuinit msm_local_timer_setup(struct clock_event_device *evt) +{ + /* Use existing clock_event for cpu 0 */ + if (!smp_processor_id()) + return 0; + + writel_relaxed(0, event_base + TIMER_ENABLE); + writel_relaxed(0, event_base + TIMER_CLEAR); + writel_relaxed(~0, event_base + TIMER_MATCH_VAL); + evt->irq = msm_clockevent.irq; + evt->name = "local_timer"; + evt->features = msm_clockevent.features; + evt->rating = msm_clockevent.rating; + evt->set_mode = msm_timer_set_mode; + evt->set_next_event = msm_timer_set_next_event; + evt->shift = msm_clockevent.shift; + evt->mult = div_sc(GPT_HZ, NSEC_PER_SEC, evt->shift); + evt->max_delta_ns = clockevent_delta2ns(0xf0000000, evt); + evt->min_delta_ns = clockevent_delta2ns(4, evt); + + *__this_cpu_ptr(msm_evt.percpu_evt) = evt; + clockevents_register_device(evt); + enable_percpu_irq(evt->irq, 0); + return 0; +} + +static void msm_local_timer_stop(struct clock_event_device *evt) +{ + evt->set_mode(CLOCK_EVT_MODE_UNUSED, evt); + disable_percpu_irq(evt->irq); +} + +static struct local_timer_ops msm_local_timer_ops __cpuinitdata = { + .setup = msm_local_timer_setup, + .stop = msm_local_timer_stop, +}; +#endif /* CONFIG_LOCAL_TIMERS */ + static void __init msm_timer_init(void) { struct clock_event_device *ce = &msm_clockevent; @@ -173,8 +212,12 @@ static void __init msm_timer_init(void) *__this_cpu_ptr(msm_evt.percpu_evt) = ce; res = request_percpu_irq(ce->irq, msm_timer_interrupt, ce->name, msm_evt.percpu_evt); - if (!res) + if (!res) { enable_percpu_irq(ce->irq, 0); +#ifdef CONFIG_LOCAL_TIMERS + local_timer_register(&msm_local_timer_ops); +#endif + } } else { msm_evt.evt = ce; res = request_irq(ce->irq, msm_timer_interrupt, @@ -191,40 +234,6 @@ err: pr_err("clocksource_register failed\n"); } -#ifdef CONFIG_LOCAL_TIMERS -int __cpuinit local_timer_setup(struct clock_event_device *evt) -{ - /* Use existing clock_event for cpu 0 */ - if (!smp_processor_id()) - return 0; - - writel_relaxed(0, event_base + TIMER_ENABLE); - writel_relaxed(0, event_base + TIMER_CLEAR); - writel_relaxed(~0, event_base + TIMER_MATCH_VAL); - evt->irq = msm_clockevent.irq; - evt->name = "local_timer"; - evt->features = msm_clockevent.features; - evt->rating = msm_clockevent.rating; - evt->set_mode = msm_timer_set_mode; - evt->set_next_event = msm_timer_set_next_event; - evt->shift = msm_clockevent.shift; - evt->mult = div_sc(GPT_HZ, NSEC_PER_SEC, evt->shift); - evt->max_delta_ns = clockevent_delta2ns(0xf0000000, evt); - evt->min_delta_ns = clockevent_delta2ns(4, evt); - - *__this_cpu_ptr(msm_evt.percpu_evt) = evt; - clockevents_register_device(evt); - enable_percpu_irq(evt->irq, 0); - return 0; -} - -void local_timer_stop(struct clock_event_device *evt) -{ - evt->set_mode(CLOCK_EVT_MODE_UNUSED, evt); - disable_percpu_irq(evt->irq); -} -#endif /* CONFIG_LOCAL_TIMERS */ - struct sys_timer msm_timer = { .init = msm_timer_init }; diff --git a/arch/arm/mach-nomadik/board-nhk8815.c b/arch/arm/mach-nomadik/board-nhk8815.c index f6f74adbe8c..58cacafcf66 100644 --- a/arch/arm/mach-nomadik/board-nhk8815.c +++ b/arch/arm/mach-nomadik/board-nhk8815.c @@ -27,11 +27,11 @@ #include <asm/mach/arch.h> #include <asm/mach/irq.h> #include <asm/mach/flash.h> +#include <asm/mach/time.h> #include <plat/gpio-nomadik.h> #include <plat/mtu.h> -#include <mach/setup.h> #include <mach/nand.h> #include <mach/fsmc.h> @@ -246,10 +246,7 @@ static void __init nomadik_timer_init(void) src_cr |= SRC_CR_INIT_VAL; writel(src_cr, io_p2v(NOMADIK_SRC_BASE)); - /* Save global pointer to mtu, used by platform timer code */ - mtu_base = io_p2v(NOMADIK_MTU0_BASE); - - nmdk_timer_init(); + nmdk_timer_init(io_p2v(NOMADIK_MTU0_BASE)); } static struct sys_timer nomadik_timer = { diff --git a/arch/arm/mach-nomadik/include/mach/setup.h b/arch/arm/mach-nomadik/include/mach/setup.h deleted file mode 100644 index bcaeaf41c05..00000000000 --- a/arch/arm/mach-nomadik/include/mach/setup.h +++ /dev/null @@ -1,19 +0,0 @@ - -/* - * These symbols are needed for board-specific files to call their - * own cpu-specific files - */ - -#ifndef __ASM_ARCH_SETUP_H -#define __ASM_ARCH_SETUP_H - -#include <asm/mach/time.h> -#include <linux/init.h> - -#ifdef CONFIG_NOMADIK_8815 - -extern void nmdk_timer_init(void); - -#endif /* NOMADIK_8815 */ - -#endif /* __ASM_ARCH_SETUP_H */ diff --git a/arch/arm/mach-omap2/Makefile b/arch/arm/mach-omap2/Makefile index bd76394ccaf..05c2ffc1030 100644 --- a/arch/arm/mach-omap2/Makefile +++ b/arch/arm/mach-omap2/Makefile @@ -23,7 +23,6 @@ obj-$(CONFIG_TWL4030_CORE) += omap_twl.o # SMP support ONLY available for OMAP4 obj-$(CONFIG_SMP) += omap-smp.o omap-headsmp.o -obj-$(CONFIG_LOCAL_TIMERS) += timer-mpu.o obj-$(CONFIG_HOTPLUG_CPU) += omap-hotplug.o obj-$(CONFIG_ARCH_OMAP4) += omap4-common.o omap-wakeupgen.o \ sleep44xx.o diff --git a/arch/arm/mach-omap2/timer-mpu.c b/arch/arm/mach-omap2/timer-mpu.c deleted file mode 100644 index 31c0ac4cd66..00000000000 --- a/arch/arm/mach-omap2/timer-mpu.c +++ /dev/null @@ -1,39 +0,0 @@ -/* - * The MPU local timer source file. In OMAP4, both cortex-a9 cores have - * own timer in it's MPU domain. These timers will be driving the - * linux kernel SMP tick framework when active. These timers are not - * part of the wake up domain. - * - * Copyright (C) 2009 Texas Instruments, Inc. - * - * Author: - * Santosh Shilimkar <santosh.shilimkar@ti.com> - * - * This file is based on arm realview smp platform file. - * Copyright (C) 2002 ARM Ltd. - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. - */ -#include <linux/init.h> -#include <linux/smp.h> -#include <linux/clockchips.h> -#include <asm/irq.h> -#include <asm/smp_twd.h> -#include <asm/localtimer.h> - -/* - * Setup the local clock events for a CPU. - */ -int __cpuinit local_timer_setup(struct clock_event_device *evt) -{ - /* Local timers are not supprted on OMAP4430 ES1.0 */ - if (omap_rev() == OMAP4430_REV_ES1_0) - return -ENXIO; - - evt->irq = OMAP44XX_IRQ_LOCALTIMER; - twd_timer_setup(evt); - return 0; -} - diff --git a/arch/arm/mach-omap2/timer.c b/arch/arm/mach-omap2/timer.c index 5c9acea9576..c512bac69ec 100644 --- a/arch/arm/mach-omap2/timer.c +++ b/arch/arm/mach-omap2/timer.c @@ -39,7 +39,7 @@ #include <asm/mach/time.h> #include <plat/dmtimer.h> -#include <asm/localtimer.h> +#include <asm/smp_twd.h> #include <asm/sched_clock.h> #include "common.h" #include <plat/omap_hwmod.h> @@ -324,14 +324,26 @@ OMAP_SYS_TIMER(3_secure) #endif #ifdef CONFIG_ARCH_OMAP4 -static void __init omap4_timer_init(void) -{ #ifdef CONFIG_LOCAL_TIMERS - twd_base = ioremap(OMAP44XX_LOCAL_TWD_BASE, SZ_256); - BUG_ON(!twd_base); +static DEFINE_TWD_LOCAL_TIMER(twd_local_timer, + OMAP44XX_LOCAL_TWD_BASE, + OMAP44XX_IRQ_LOCALTIMER); #endif + +static void __init omap4_timer_init(void) +{ omap2_gp_clockevent_init(1, OMAP4_CLKEV_SOURCE); omap2_gp_clocksource_init(2, OMAP4_MPU_SOURCE); +#ifdef CONFIG_LOCAL_TIMERS + /* Local timers are not supprted on OMAP4430 ES1.0 */ + if (omap_rev() != OMAP4430_REV_ES1_0) { + int err; + + err = twd_local_timer_register(&twd_local_timer); + if (err) + pr_err("twd_local_timer_register failed %d\n", err); + } +#endif } OMAP_SYS_TIMER(4) #endif diff --git a/arch/arm/mach-realview/realview_eb.c b/arch/arm/mach-realview/realview_eb.c index 157e1bc6e83..baf382c5e77 100644 --- a/arch/arm/mach-realview/realview_eb.c +++ b/arch/arm/mach-realview/realview_eb.c @@ -36,7 +36,7 @@ #include <asm/pgtable.h> #include <asm/hardware/gic.h> #include <asm/hardware/cache-l2x0.h> -#include <asm/localtimer.h> +#include <asm/smp_twd.h> #include <asm/mach/arch.h> #include <asm/mach/map.h> @@ -383,6 +383,23 @@ static void realview_eb11mp_fixup(void) realview_eb_isp1761_resources[1].end = IRQ_EB11MP_USB; } +#ifdef CONFIG_HAVE_ARM_TWD +static DEFINE_TWD_LOCAL_TIMER(twd_local_timer, + REALVIEW_EB11MP_TWD_BASE, + IRQ_LOCALTIMER); + +static void __init realview_eb_twd_init(void) +{ + if (core_tile_eb11mp() || core_tile_a9mp()) { + int err = twd_local_timer_register(&twd_local_timer); + if (err) + pr_err("twd_local_timer_register failed %d\n", err); + } +} +#else +#define realview_eb_twd_init() do { } while(0) +#endif + static void __init realview_eb_timer_init(void) { unsigned int timer_irq; @@ -392,15 +409,13 @@ static void __init realview_eb_timer_init(void) timer2_va_base = __io_address(REALVIEW_EB_TIMER2_3_BASE); timer3_va_base = __io_address(REALVIEW_EB_TIMER2_3_BASE) + 0x20; - if (core_tile_eb11mp() || core_tile_a9mp()) { -#ifdef CONFIG_LOCAL_TIMERS - twd_base = __io_address(REALVIEW_EB11MP_TWD_BASE); -#endif + if (core_tile_eb11mp() || core_tile_a9mp()) timer_irq = IRQ_EB11MP_TIMER0_1; - } else + else timer_irq = IRQ_EB_TIMER0_1; realview_timer_init(timer_irq); + realview_eb_twd_init(); } static struct sys_timer realview_eb_timer = { diff --git a/arch/arm/mach-realview/realview_pb11mp.c b/arch/arm/mach-realview/realview_pb11mp.c index ae7fe54f6eb..a98c536e332 100644 --- a/arch/arm/mach-realview/realview_pb11mp.c +++ b/arch/arm/mach-realview/realview_pb11mp.c @@ -36,7 +36,7 @@ #include <asm/pgtable.h> #include <asm/hardware/gic.h> #include <asm/hardware/cache-l2x0.h> -#include <asm/localtimer.h> +#include <asm/smp_twd.h> #include <asm/mach/arch.h> #include <asm/mach/flash.h> @@ -290,6 +290,21 @@ static void __init gic_init_irq(void) gic_cascade_irq(1, IRQ_TC11MP_PB_IRQ1); } +#ifdef CONFIG_HAVE_ARM_TWD +static DEFINE_TWD_LOCAL_TIMER(twd_local_timer, + REALVIEW_TC11MP_TWD_BASE, + IRQ_LOCALTIMER); + +static void __init realview_pb11mp_twd_init(void) +{ + int err = twd_local_timer_register(&twd_local_timer); + if (err) + pr_err("twd_local_timer_register failed %d\n", err); +} +#else +#define realview_pb11mp_twd_init() do {} while(0) +#endif + static void __init realview_pb11mp_timer_init(void) { timer0_va_base = __io_address(REALVIEW_PB11MP_TIMER0_1_BASE); @@ -297,10 +312,8 @@ static void __init realview_pb11mp_timer_init(void) timer2_va_base = __io_address(REALVIEW_PB11MP_TIMER2_3_BASE); timer3_va_base = __io_address(REALVIEW_PB11MP_TIMER2_3_BASE) + 0x20; -#ifdef CONFIG_LOCAL_TIMERS - twd_base = __io_address(REALVIEW_TC11MP_TWD_BASE); -#endif realview_timer_init(IRQ_TC11MP_TIMER0_1); + realview_pb11mp_twd_init(); } static struct sys_timer realview_pb11mp_timer = { diff --git a/arch/arm/mach-realview/realview_pbx.c b/arch/arm/mach-realview/realview_pbx.c index 1cd9956f587..3f2f605624e 100644 --- a/arch/arm/mach-realview/realview_pbx.c +++ b/arch/arm/mach-realview/realview_pbx.c @@ -298,6 +298,21 @@ static void __init gic_init_irq(void) } } +#ifdef CONFIG_HAVE_ARM_TWD +static DEFINE_TWD_LOCAL_TIMER(twd_local_timer, + REALVIEW_PBX_TILE_TWD_BASE, + IRQ_LOCALTIMER); + +static void __init realview_pbx_twd_init(void) +{ + int err = twd_local_timer_register(&twd_local_timer); + if (err) + pr_err("twd_local_timer_register failed %d\n", err); +} +#else +#define realview_pbx_twd_init() do { } while(0) +#endif + static void __init realview_pbx_timer_init(void) { timer0_va_base = __io_address(REALVIEW_PBX_TIMER0_1_BASE); @@ -305,11 +320,8 @@ static void __init realview_pbx_timer_init(void) timer2_va_base = __io_address(REALVIEW_PBX_TIMER2_3_BASE); timer3_va_base = __io_address(REALVIEW_PBX_TIMER2_3_BASE) + 0x20; -#ifdef CONFIG_LOCAL_TIMERS - if (core_tile_pbx11mp() || core_tile_pbxa9mp()) - twd_base = __io_address(REALVIEW_PBX_TILE_TWD_BASE); -#endif realview_timer_init(IRQ_PBX_TIMER0_1); + realview_pbx_twd_init(); } static struct sys_timer realview_pbx_timer = { diff --git a/arch/arm/mach-shmobile/Makefile b/arch/arm/mach-shmobile/Makefile index 7ad6954c46c..e7c2590b75d 100644 --- a/arch/arm/mach-shmobile/Makefile +++ b/arch/arm/mach-shmobile/Makefile @@ -16,7 +16,6 @@ obj-$(CONFIG_ARCH_R8A7779) += setup-r8a7779.o clock-r8a7779.o intc-r8a7779.o # SMP objects smp-y := platsmp.o headsmp.o smp-$(CONFIG_HOTPLUG_CPU) += hotplug.o -smp-$(CONFIG_LOCAL_TIMERS) += localtimer.o smp-$(CONFIG_ARCH_SH73A0) += smp-sh73a0.o smp-$(CONFIG_ARCH_R8A7779) += smp-r8a7779.o diff --git a/arch/arm/mach-shmobile/include/mach/common.h b/arch/arm/mach-shmobile/include/mach/common.h index e4b945e271e..9fde3eb686a 100644 --- a/arch/arm/mach-shmobile/include/mach/common.h +++ b/arch/arm/mach-shmobile/include/mach/common.h @@ -2,6 +2,8 @@ #define __ARCH_MACH_COMMON_H extern struct sys_timer shmobile_timer; +struct twd_local_timer; +void shmobile_twd_init(struct twd_local_timer *twd_local_timer); extern void shmobile_setup_console(void); extern void shmobile_secondary_vector(void); extern int shmobile_platform_cpu_kill(unsigned int cpu); diff --git a/arch/arm/mach-shmobile/localtimer.c b/arch/arm/mach-shmobile/localtimer.c deleted file mode 100644 index ad9ccc9900c..00000000000 --- a/arch/arm/mach-shmobile/localtimer.c +++ /dev/null @@ -1,26 +0,0 @@ -/* - * SMP support for R-Mobile / SH-Mobile - local timer portion - * - * Copyright (C) 2010 Magnus Damm - * - * Based on vexpress, Copyright (C) 2002 ARM Ltd, All Rights Reserved - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. - */ -#include <linux/init.h> -#include <linux/smp.h> -#include <linux/clockchips.h> -#include <asm/smp_twd.h> -#include <asm/localtimer.h> - -/* - * Setup the local clock events for a CPU. - */ -int __cpuinit local_timer_setup(struct clock_event_device *evt) -{ - evt->irq = 29; - twd_timer_setup(evt); - return 0; -} diff --git a/arch/arm/mach-shmobile/platsmp.c b/arch/arm/mach-shmobile/platsmp.c index 993381257f6..45fa3924c6a 100644 --- a/arch/arm/mach-shmobile/platsmp.c +++ b/arch/arm/mach-shmobile/platsmp.c @@ -17,7 +17,6 @@ #include <linux/smp.h> #include <linux/io.h> #include <asm/hardware/gic.h> -#include <asm/localtimer.h> #include <asm/mach-types.h> #include <mach/common.h> diff --git a/arch/arm/mach-shmobile/smp-r8a7779.c b/arch/arm/mach-shmobile/smp-r8a7779.c index 4fe2e9eaf50..9bb7b8575a1 100644 --- a/arch/arm/mach-shmobile/smp-r8a7779.c +++ b/arch/arm/mach-shmobile/smp-r8a7779.c @@ -64,6 +64,8 @@ static void __iomem *scu_base_addr(void) static DEFINE_SPINLOCK(scu_lock); static unsigned long tmp; +static DEFINE_TWD_LOCAL_TIMER(twd_local_timer, 0xf0000600, 29); + static void modify_scu_cpu_psr(unsigned long set, unsigned long clr) { void __iomem *scu_base = scu_base_addr(); @@ -82,11 +84,7 @@ unsigned int __init r8a7779_get_core_count(void) { void __iomem *scu_base = scu_base_addr(); -#ifdef CONFIG_HAVE_ARM_TWD - /* twd_base needs to be initialized before percpu_timer_setup() */ - twd_base = (void __iomem *)0xf0000600; -#endif - + shmobile_twd_init(&twd_local_timer); return scu_get_core_count(scu_base); } diff --git a/arch/arm/mach-shmobile/smp-sh73a0.c b/arch/arm/mach-shmobile/smp-sh73a0.c index 2d0d4212be4..c0a9093ba3a 100644 --- a/arch/arm/mach-shmobile/smp-sh73a0.c +++ b/arch/arm/mach-shmobile/smp-sh73a0.c @@ -42,6 +42,8 @@ static void __iomem *scu_base_addr(void) static DEFINE_SPINLOCK(scu_lock); static unsigned long tmp; +static DEFINE_TWD_LOCAL_TIMER(twd_local_timer, 0xf0000600, 29); + static void modify_scu_cpu_psr(unsigned long set, unsigned long clr) { void __iomem *scu_base = scu_base_addr(); @@ -60,11 +62,7 @@ unsigned int __init sh73a0_get_core_count(void) { void __iomem *scu_base = scu_base_addr(); -#ifdef CONFIG_HAVE_ARM_TWD - /* twd_base needs to be initialized before percpu_timer_setup() */ - twd_base = (void __iomem *)0xf0000600; -#endif - + shmobile_twd_init(&twd_local_timer); return scu_get_core_count(scu_base); } diff --git a/arch/arm/mach-shmobile/timer.c b/arch/arm/mach-shmobile/timer.c index 895794b543c..be16231e86f 100644 --- a/arch/arm/mach-shmobile/timer.c +++ b/arch/arm/mach-shmobile/timer.c @@ -20,6 +20,7 @@ */ #include <linux/platform_device.h> #include <asm/mach/time.h> +#include <asm/smp_twd.h> static void __init shmobile_late_time_init(void) { @@ -41,6 +42,15 @@ static void __init shmobile_timer_init(void) late_time_init = shmobile_late_time_init; } +void __init shmobile_twd_init(struct twd_local_timer *twd_local_timer) +{ +#ifdef CONFIG_HAVE_ARM_TWD + int err = twd_local_timer_register(twd_local_timer); + if (err) + pr_err("twd_local_timer_register failed %d\n", err); +#endif +} + struct sys_timer shmobile_timer = { .init = shmobile_timer_init, }; diff --git a/arch/arm/mach-tegra/Makefile b/arch/arm/mach-tegra/Makefile index e120ff54f66..f7d044369ed 100644 --- a/arch/arm/mach-tegra/Makefile +++ b/arch/arm/mach-tegra/Makefile @@ -13,7 +13,7 @@ obj-$(CONFIG_ARCH_TEGRA_2x_SOC) += tegra2_emc.o obj-$(CONFIG_ARCH_TEGRA_2x_SOC) += pinmux-tegra20-tables.o obj-$(CONFIG_ARCH_TEGRA_3x_SOC) += pinmux-tegra30-tables.o obj-$(CONFIG_ARCH_TEGRA_3x_SOC) += board-dt-tegra30.o -obj-$(CONFIG_SMP) += platsmp.o localtimer.o headsmp.o +obj-$(CONFIG_SMP) += platsmp.o headsmp.o obj-$(CONFIG_HOTPLUG_CPU) += hotplug.o obj-$(CONFIG_TEGRA_SYSTEM_DMA) += dma.o obj-$(CONFIG_CPU_FREQ) += cpu-tegra.o diff --git a/arch/arm/mach-tegra/localtimer.c b/arch/arm/mach-tegra/localtimer.c deleted file mode 100644 index e91d681d45a..00000000000 --- a/arch/arm/mach-tegra/localtimer.c +++ /dev/null @@ -1,26 +0,0 @@ -/* - * arch/arm/mach-tegra/localtimer.c - * - * Copyright (C) 2002 ARM Ltd. - * All Rights Reserved - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. - */ -#include <linux/init.h> -#include <linux/smp.h> -#include <linux/clockchips.h> -#include <asm/irq.h> -#include <asm/smp_twd.h> -#include <asm/localtimer.h> - -/* - * Setup the local clock events for a CPU. - */ -int __cpuinit local_timer_setup(struct clock_event_device *evt) -{ - evt->irq = IRQ_LOCALTIMER; - twd_timer_setup(evt); - return 0; -} diff --git a/arch/arm/mach-tegra/timer.c b/arch/arm/mach-tegra/timer.c index 1d1acda4f3e..1eed8d4a80e 100644 --- a/arch/arm/mach-tegra/timer.c +++ b/arch/arm/mach-tegra/timer.c @@ -28,7 +28,7 @@ #include <linux/io.h> #include <asm/mach/time.h> -#include <asm/localtimer.h> +#include <asm/smp_twd.h> #include <asm/sched_clock.h> #include <mach/iomap.h> @@ -162,6 +162,21 @@ static struct irqaction tegra_timer_irq = { .irq = INT_TMR3, }; +#ifdef CONFIG_HAVE_ARM_TWD +static DEFINE_TWD_LOCAL_TIMER(twd_local_timer, + TEGRA_ARM_PERIF_BASE + 0x600, + IRQ_LOCALTIMER); + +static void __init tegra_twd_init(void) +{ + int err = twd_local_timer_register(&twd_local_timer); + if (err) + pr_err("twd_local_timer_register failed %d\n", err); +} +#else +#define tegra_twd_init() do {} while(0) +#endif + static void __init tegra_init_timer(void) { struct clk *clk; @@ -188,10 +203,6 @@ static void __init tegra_init_timer(void) else clk_enable(clk); -#ifdef CONFIG_HAVE_ARM_TWD - twd_base = IO_ADDRESS(TEGRA_ARM_PERIF_BASE + 0x600); -#endif - switch (rate) { case 12000000: timer_writel(0x000b, TIMERUS_USEC_CFG); @@ -231,6 +242,7 @@ static void __init tegra_init_timer(void) tegra_clockevent.cpumask = cpu_all_mask; tegra_clockevent.irq = tegra_timer_irq.irq; clockevents_register_device(&tegra_clockevent); + tegra_twd_init(); } struct sys_timer tegra_timer = { diff --git a/arch/arm/mach-ux500/Kconfig b/arch/arm/mach-ux500/Kconfig index 52af00446a6..afb3706bab2 100644 --- a/arch/arm/mach-ux500/Kconfig +++ b/arch/arm/mach-ux500/Kconfig @@ -28,6 +28,7 @@ config MACH_U8500 bool "U8500 Development platform" depends on UX500_SOC_DB8500 select TPS6105X + select SOC_BUS help Include support for the mop500 development platform. @@ -49,6 +50,12 @@ config MACH_U5500 depends on UX500_SOC_DB5500 help Include support for the U5500 development platform. + +config MACH_UX500_DT + bool "Generic U8500 support using device tree" + depends on MACH_U8500 + select USE_OF + endmenu config UX500_DEBUG_UART diff --git a/arch/arm/mach-ux500/Makefile b/arch/arm/mach-ux500/Makefile index 6bd2f451c18..35b389442af 100644 --- a/arch/arm/mach-ux500/Makefile +++ b/arch/arm/mach-ux500/Makefile @@ -15,7 +15,6 @@ obj-$(CONFIG_MACH_U8500) += board-mop500.o board-mop500-sdi.o \ obj-$(CONFIG_MACH_U5500) += board-u5500.o board-u5500-sdi.o obj-$(CONFIG_SMP) += platsmp.o headsmp.o obj-$(CONFIG_HOTPLUG_CPU) += hotplug.o -obj-$(CONFIG_LOCAL_TIMERS) += localtimer.o obj-$(CONFIG_U5500_MODEM_IRQ) += modem-irq-db5500.o obj-$(CONFIG_U5500_MBOX) += mbox-db5500.o diff --git a/arch/arm/mach-ux500/Makefile.boot b/arch/arm/mach-ux500/Makefile.boot index ff0a4b5b0a8..dd5cd00e255 100644 --- a/arch/arm/mach-ux500/Makefile.boot +++ b/arch/arm/mach-ux500/Makefile.boot @@ -2,3 +2,4 @@ params_phys-y := 0x00000100 initrd_phys-y := 0x00800000 +dtb-$(CONFIG_MACH_SNOWBALL) += snowball.dtb diff --git a/arch/arm/mach-ux500/board-mop500-sdi.c b/arch/arm/mach-ux500/board-mop500-sdi.c index 5dde4d4ebe8..479ebe04cf9 100644 --- a/arch/arm/mach-ux500/board-mop500-sdi.c +++ b/arch/arm/mach-ux500/board-mop500-sdi.c @@ -104,7 +104,7 @@ static struct mmci_platform_data mop500_sdi0_data = { #endif }; -static void sdi0_configure(void) +static void sdi0_configure(struct device *parent) { int ret; @@ -123,15 +123,15 @@ static void sdi0_configure(void) gpio_direction_output(sdi0_en, 1); /* Add the device, force v2 to subrevision 1 */ - db8500_add_sdi0(&mop500_sdi0_data, U8500_SDI_V2_PERIPHID); + db8500_add_sdi0(parent, &mop500_sdi0_data, U8500_SDI_V2_PERIPHID); } -void mop500_sdi_tc35892_init(void) +void mop500_sdi_tc35892_init(struct device *parent) { mop500_sdi0_data.gpio_cd = GPIO_SDMMC_CD; sdi0_en = GPIO_SDMMC_EN; sdi0_vsel = GPIO_SDMMC_1V8_3V_SEL; - sdi0_configure(); + sdi0_configure(parent); } /* @@ -246,12 +246,13 @@ static struct mmci_platform_data mop500_sdi4_data = { #endif }; -void __init mop500_sdi_init(void) +void __init mop500_sdi_init(struct device *parent) { /* PoP:ed eMMC */ - db8500_add_sdi2(&mop500_sdi2_data, U8500_SDI_V2_PERIPHID); + db8500_add_sdi2(parent, &mop500_sdi2_data, U8500_SDI_V2_PERIPHID); /* On-board eMMC */ - db8500_add_sdi4(&mop500_sdi4_data, U8500_SDI_V2_PERIPHID); + db8500_add_sdi4(parent, &mop500_sdi4_data, U8500_SDI_V2_PERIPHID); + /* * On boards with the TC35892 GPIO expander, sdi0 will finally * be added when the TC35892 initializes and calls @@ -259,31 +260,31 @@ void __init mop500_sdi_init(void) */ } -void __init snowball_sdi_init(void) +void __init snowball_sdi_init(struct device *parent) { /* On Snowball MMC_CAP_SD_HIGHSPEED isn't supported (Hardware issue?) */ mop500_sdi0_data.capabilities &= ~MMC_CAP_SD_HIGHSPEED; /* On-board eMMC */ - db8500_add_sdi4(&mop500_sdi4_data, U8500_SDI_V2_PERIPHID); + db8500_add_sdi4(parent, &mop500_sdi4_data, U8500_SDI_V2_PERIPHID); /* External Micro SD slot */ mop500_sdi0_data.gpio_cd = SNOWBALL_SDMMC_CD_GPIO; mop500_sdi0_data.cd_invert = true; sdi0_en = SNOWBALL_SDMMC_EN_GPIO; sdi0_vsel = SNOWBALL_SDMMC_1V8_3V_GPIO; - sdi0_configure(); + sdi0_configure(parent); } -void __init hrefv60_sdi_init(void) +void __init hrefv60_sdi_init(struct device *parent) { /* PoP:ed eMMC */ - db8500_add_sdi2(&mop500_sdi2_data, U8500_SDI_V2_PERIPHID); + db8500_add_sdi2(parent, &mop500_sdi2_data, U8500_SDI_V2_PERIPHID); /* On-board eMMC */ - db8500_add_sdi4(&mop500_sdi4_data, U8500_SDI_V2_PERIPHID); + db8500_add_sdi4(parent, &mop500_sdi4_data, U8500_SDI_V2_PERIPHID); /* External Micro SD slot */ mop500_sdi0_data.gpio_cd = HREFV60_SDMMC_CD_GPIO; sdi0_en = HREFV60_SDMMC_EN_GPIO; sdi0_vsel = HREFV60_SDMMC_1V8_3V_GPIO; - sdi0_configure(); + sdi0_configure(parent); /* WLAN SDIO channel */ - db8500_add_sdi1(&mop500_sdi1_data, U8500_SDI_V2_PERIPHID); + db8500_add_sdi1(parent, &mop500_sdi1_data, U8500_SDI_V2_PERIPHID); } diff --git a/arch/arm/mach-ux500/board-mop500.c b/arch/arm/mach-ux500/board-mop500.c index 5c00712907d..d0799d59221 100644 --- a/arch/arm/mach-ux500/board-mop500.c +++ b/arch/arm/mach-ux500/board-mop500.c @@ -30,6 +30,9 @@ #include <linux/gpio_keys.h> #include <linux/delay.h> +#include <linux/of.h> +#include <linux/of_platform.h> + #include <linux/leds.h> #include <asm/mach-types.h> #include <asm/mach/arch.h> @@ -226,7 +229,12 @@ static struct tps6105x_platform_data mop500_tps61052_data = { static void mop500_tc35892_init(struct tc3589x *tc3589x, unsigned int base) { - mop500_sdi_tc35892_init(); + struct device *parent = NULL; +#if 0 + /* FIXME: Is the sdi actually part of tc3589x? */ + parent = tc3589x->dev; +#endif + mop500_sdi_tc35892_init(parent); } static struct tc3589x_gpio_platform_data mop500_tc35892_gpio_data = { @@ -353,12 +361,12 @@ U8500_I2C_CONTROLLER(1, 0xe, 1, 8, 100000, 200, I2C_FREQ_MODE_FAST); U8500_I2C_CONTROLLER(2, 0xe, 1, 8, 100000, 200, I2C_FREQ_MODE_FAST); U8500_I2C_CONTROLLER(3, 0xe, 1, 8, 100000, 200, I2C_FREQ_MODE_FAST); -static void __init mop500_i2c_init(void) +static void __init mop500_i2c_init(struct device *parent) { - db8500_add_i2c0(&u8500_i2c0_data); - db8500_add_i2c1(&u8500_i2c1_data); - db8500_add_i2c2(&u8500_i2c2_data); - db8500_add_i2c3(&u8500_i2c3_data); + db8500_add_i2c0(parent, &u8500_i2c0_data); + db8500_add_i2c1(parent, &u8500_i2c1_data); + db8500_add_i2c2(parent, &u8500_i2c2_data); + db8500_add_i2c3(parent, &u8500_i2c3_data); } static struct gpio_keys_button mop500_gpio_keys[] = { @@ -435,7 +443,7 @@ static struct stedma40_chan_cfg ssp0_dma_cfg_tx = { }; #endif -static struct pl022_ssp_controller ssp0_platform_data = { +static struct pl022_ssp_controller ssp0_plat = { .bus_id = 0, #ifdef CONFIG_STE_DMA40 .enable_dma = 1, @@ -451,9 +459,9 @@ static struct pl022_ssp_controller ssp0_platform_data = { .num_chipselect = 5, }; -static void __init mop500_spi_init(void) +static void __init mop500_spi_init(struct device *parent) { - db8500_add_ssp0(&ssp0_platform_data); + db8500_add_ssp0(parent, &ssp0_plat); } #ifdef CONFIG_STE_DMA40 @@ -587,11 +595,11 @@ static struct amba_pl011_data uart2_plat = { #endif }; -static void __init mop500_uart_init(void) +static void __init mop500_uart_init(struct device *parent) { - db8500_add_uart0(&uart0_plat); - db8500_add_uart1(&uart1_plat); - db8500_add_uart2(&uart2_plat); + db8500_add_uart0(parent, &uart0_plat); + db8500_add_uart1(parent, &uart1_plat); + db8500_add_uart2(parent, &uart2_plat); } static struct platform_device *snowball_platform_devs[] __initdata = { @@ -603,21 +611,27 @@ static struct platform_device *snowball_platform_devs[] __initdata = { static void __init mop500_init_machine(void) { + struct device *parent = NULL; int i2c0_devs; + int i; mop500_gpio_keys[0].gpio = GPIO_PROX_SENSOR; - u8500_init_devices(); + parent = u8500_init_devices(); mop500_pins_init(); + /* FIXME: parent of ab8500 should be prcmu */ + for (i = 0; i < ARRAY_SIZE(mop500_platform_devs); i++) + mop500_platform_devs[i]->dev.parent = parent; + platform_add_devices(mop500_platform_devs, ARRAY_SIZE(mop500_platform_devs)); - mop500_i2c_init(); - mop500_sdi_init(); - mop500_spi_init(); - mop500_uart_init(); + mop500_i2c_init(parent); + mop500_sdi_init(parent); + mop500_spi_init(parent); + mop500_uart_init(parent); i2c0_devs = ARRAY_SIZE(mop500_i2c0_devices); @@ -631,19 +645,24 @@ static void __init mop500_init_machine(void) static void __init snowball_init_machine(void) { + struct device *parent = NULL; int i2c0_devs; + int i; - u8500_init_devices(); + parent = u8500_init_devices(); snowball_pins_init(); + for (i = 0; i < ARRAY_SIZE(snowball_platform_devs); i++) + snowball_platform_devs[i]->dev.parent = parent; + platform_add_devices(snowball_platform_devs, ARRAY_SIZE(snowball_platform_devs)); - mop500_i2c_init(); - snowball_sdi_init(); - mop500_spi_init(); - mop500_uart_init(); + mop500_i2c_init(parent); + snowball_sdi_init(parent); + mop500_spi_init(parent); + mop500_uart_init(parent); i2c0_devs = ARRAY_SIZE(mop500_i2c0_devices); i2c_register_board_info(0, mop500_i2c0_devices, i2c0_devs); @@ -656,7 +675,9 @@ static void __init snowball_init_machine(void) static void __init hrefv60_init_machine(void) { + struct device *parent = NULL; int i2c0_devs; + int i; /* * The HREFv60 board removed a GPIO expander and routed @@ -665,17 +686,20 @@ static void __init hrefv60_init_machine(void) */ mop500_gpio_keys[0].gpio = HREFV60_PROX_SENSE_GPIO; - u8500_init_devices(); + parent = u8500_init_devices(); hrefv60_pins_init(); + for (i = 0; i < ARRAY_SIZE(mop500_platform_devs); i++) + mop500_platform_devs[i]->dev.parent = parent; + platform_add_devices(mop500_platform_devs, ARRAY_SIZE(mop500_platform_devs)); - mop500_i2c_init(); - hrefv60_sdi_init(); - mop500_spi_init(); - mop500_uart_init(); + mop500_i2c_init(parent); + hrefv60_sdi_init(parent); + mop500_spi_init(parent); + mop500_uart_init(parent); i2c0_devs = ARRAY_SIZE(mop500_i2c0_devices); @@ -718,3 +742,94 @@ MACHINE_START(SNOWBALL, "Calao Systems Snowball platform") .handle_irq = gic_handle_irq, .init_machine = snowball_init_machine, MACHINE_END + +#ifdef CONFIG_MACH_UX500_DT + +struct of_dev_auxdata u8500_auxdata_lookup[] __initdata = { + OF_DEV_AUXDATA("arm,pl011", 0x80120000, "uart0", &uart0_plat), + OF_DEV_AUXDATA("arm,pl011", 0x80121000, "uart1", &uart1_plat), + OF_DEV_AUXDATA("arm,pl011", 0x80007000, "uart2", &uart2_plat), + OF_DEV_AUXDATA("arm,pl022", 0x80002000, "ssp0", &ssp0_plat), + {}, +}; + +static const struct of_device_id u8500_soc_node[] = { + /* only create devices below soc node */ + { .compatible = "stericsson,db8500", }, + { }, +}; + +static void __init u8500_init_machine(void) +{ + struct device *parent = NULL; + int i2c0_devs; + int i; + + parent = u8500_init_devices(); + i2c0_devs = ARRAY_SIZE(mop500_i2c0_devices); + + for (i = 0; i < ARRAY_SIZE(mop500_platform_devs); i++) + mop500_platform_devs[i]->dev.parent = parent; + for (i = 0; i < ARRAY_SIZE(snowball_platform_devs); i++) + snowball_platform_devs[i]->dev.parent = parent; + + /* automatically probe child nodes of db8500 device */ + of_platform_populate(NULL, u8500_soc_node, u8500_auxdata_lookup, parent); + + if (of_machine_is_compatible("st-ericsson,mop500")) { + mop500_gpio_keys[0].gpio = GPIO_PROX_SENSOR; + mop500_pins_init(); + + platform_add_devices(mop500_platform_devs, + ARRAY_SIZE(mop500_platform_devs)); + + mop500_sdi_init(parent); + } else if (of_machine_is_compatible("calaosystems,snowball-a9500")) { + snowball_pins_init(); + platform_add_devices(snowball_platform_devs, + ARRAY_SIZE(snowball_platform_devs)); + + snowball_sdi_init(parent); + } else if (of_machine_is_compatible("st-ericsson,hrefv60+")) { + /* + * The HREFv60 board removed a GPIO expander and routed + * all these GPIO pins to the internal GPIO controller + * instead. + */ + mop500_gpio_keys[0].gpio = HREFV60_PROX_SENSE_GPIO; + i2c0_devs -= NUM_PRE_V60_I2C0_DEVICES; + hrefv60_pins_init(); + platform_add_devices(mop500_platform_devs, + ARRAY_SIZE(mop500_platform_devs)); + + hrefv60_sdi_init(parent); + } + mop500_i2c_init(parent); + + i2c_register_board_info(0, mop500_i2c0_devices, i2c0_devs); + i2c_register_board_info(2, mop500_i2c2_devices, + ARRAY_SIZE(mop500_i2c2_devices)); + + /* This board has full regulator constraints */ + regulator_has_full_constraints(); +} + +static const char * u8500_dt_board_compat[] = { + "calaosystems,snowball-a9500", + "st-ericsson,hrefv60+", + "st-ericsson,u8500", + "st-ericsson,mop500", + NULL, +}; + + +DT_MACHINE_START(U8500_DT, "ST-Ericsson U8500 platform (Device Tree Support)") + .map_io = u8500_map_io, + .init_irq = ux500_init_irq, + /* we re-use nomadik timer here */ + .timer = &ux500_timer, + .handle_irq = gic_handle_irq, + .init_machine = u8500_init_machine, + .dt_compat = u8500_dt_board_compat, +MACHINE_END +#endif diff --git a/arch/arm/mach-ux500/board-mop500.h b/arch/arm/mach-ux500/board-mop500.h index f926d3db620..3d594c24bfe 100644 --- a/arch/arm/mach-ux500/board-mop500.h +++ b/arch/arm/mach-ux500/board-mop500.h @@ -75,10 +75,10 @@ struct i2c_board_info; -extern void mop500_sdi_init(void); -extern void snowball_sdi_init(void); -extern void hrefv60_sdi_init(void); -extern void mop500_sdi_tc35892_init(void); +extern void mop500_sdi_init(struct device *parent); +extern void snowball_sdi_init(struct device *parent); +extern void hrefv60_sdi_init(struct device *parent); +extern void mop500_sdi_tc35892_init(struct device *parent); void __init mop500_u8500uib_init(void); void __init mop500_stuib_init(void); void __init mop500_pins_init(void); diff --git a/arch/arm/mach-ux500/board-u5500-sdi.c b/arch/arm/mach-ux500/board-u5500-sdi.c index 63c3f8058ff..836112eedde 100644 --- a/arch/arm/mach-ux500/board-u5500-sdi.c +++ b/arch/arm/mach-ux500/board-u5500-sdi.c @@ -66,9 +66,9 @@ static struct mmci_platform_data u5500_sdi0_data = { #endif }; -void __init u5500_sdi_init(void) +void __init u5500_sdi_init(struct device *parent) { nmk_config_pins(u5500_sdi_pins, ARRAY_SIZE(u5500_sdi_pins)); - db5500_add_sdi0(&u5500_sdi0_data); + db5500_add_sdi0(parent, &u5500_sdi0_data); } diff --git a/arch/arm/mach-ux500/board-u5500.c b/arch/arm/mach-ux500/board-u5500.c index 9de9e9c4dbb..0ff4be72a80 100644 --- a/arch/arm/mach-ux500/board-u5500.c +++ b/arch/arm/mach-ux500/board-u5500.c @@ -97,9 +97,9 @@ static struct i2c_board_info __initdata u5500_i2c2_devices[] = { }, }; -static void __init u5500_i2c_init(void) +static void __init u5500_i2c_init(struct device *parent) { - db5500_add_i2c2(&u5500_i2c2_data); + db5500_add_i2c2(parent, &u5500_i2c2_data); i2c_register_board_info(2, ARRAY_AND_SIZE(u5500_i2c2_devices)); } @@ -126,20 +126,27 @@ static struct platform_device *u5500_platform_devices[] __initdata = { &ab5500_device, }; -static void __init u5500_uart_init(void) +static void __init u5500_uart_init(struct device *parent) { - db5500_add_uart0(NULL); - db5500_add_uart1(NULL); - db5500_add_uart2(NULL); + db5500_add_uart0(parent, NULL); + db5500_add_uart1(parent, NULL); + db5500_add_uart2(parent, NULL); } static void __init u5500_init_machine(void) { - u5500_init_devices(); + struct device *parent = NULL; + int i; + + parent = u5500_init_devices(); nmk_config_pins(u5500_pins, ARRAY_SIZE(u5500_pins)); - u5500_i2c_init(); - u5500_sdi_init(); - u5500_uart_init(); + + u5500_i2c_init(parent); + u5500_sdi_init(parent); + u5500_uart_init(parent); + + for (i = 0; i < ARRAY_SIZE(u5500_platform_devices); i++) + u5500_platform_devices[i]->dev.parent = parent; platform_add_devices(u5500_platform_devices, ARRAY_SIZE(u5500_platform_devices)); diff --git a/arch/arm/mach-ux500/cache-l2x0.c b/arch/arm/mach-ux500/cache-l2x0.c index da5569d83d5..77a75ed0df6 100644 --- a/arch/arm/mach-ux500/cache-l2x0.c +++ b/arch/arm/mach-ux500/cache-l2x0.c @@ -5,6 +5,8 @@ */ #include <linux/io.h> +#include <linux/of.h> + #include <asm/cacheflush.h> #include <asm/hardware/cache-l2x0.h> #include <mach/hardware.h> @@ -45,7 +47,10 @@ static int __init ux500_l2x0_init(void) ux500_l2x0_unlock(); /* 64KB way size, 8 way associativity, force WA */ - l2x0_init(l2x0_base, 0x3e060000, 0xc0000fff); + if (of_have_populated_dt()) + l2x0_of_init(0x3e060000, 0xc0000fff); + else + l2x0_init(l2x0_base, 0x3e060000, 0xc0000fff); /* * We can't disable l2 as we are in non secure mode, currently diff --git a/arch/arm/mach-ux500/cpu-db5500.c b/arch/arm/mach-ux500/cpu-db5500.c index 18aa5c05c69..bca47f32082 100644 --- a/arch/arm/mach-ux500/cpu-db5500.c +++ b/arch/arm/mach-ux500/cpu-db5500.c @@ -147,13 +147,13 @@ static resource_size_t __initdata db5500_gpio_base[] = { U5500_GPIOBANK7_BASE, }; -static void __init db5500_add_gpios(void) +static void __init db5500_add_gpios(struct device *parent) { struct nmk_gpio_platform_data pdata = { /* No custom data yet */ }; - dbx500_add_gpios(ARRAY_AND_SIZE(db5500_gpio_base), + dbx500_add_gpios(parent, ARRAY_AND_SIZE(db5500_gpio_base), IRQ_DB5500_GPIO0, &pdata); } @@ -212,14 +212,36 @@ static int usb_db5500_tx_dma_cfg[] = { DB5500_DMA_DEV38_USB_OTG_OEP_8 }; -void __init u5500_init_devices(void) +static const char *db5500_read_soc_id(void) { - db5500_add_gpios(); + return kasprintf(GFP_KERNEL, "u5500 currently unsupported\n"); +} + +static struct device * __init db5500_soc_device_init(void) +{ + const char *soc_id = db5500_read_soc_id(); + + return ux500_soc_device_init(soc_id); +} + +struct device * __init u5500_init_devices(void) +{ + struct device *parent; + int i; + + parent = db5500_soc_device_init(); + + db5500_add_gpios(parent); db5500_pmu_init(); - db5500_dma_init(); - db5500_add_rtc(); - db5500_add_usb(usb_db5500_rx_dma_cfg, usb_db5500_tx_dma_cfg); + db5500_dma_init(parent); + db5500_add_rtc(parent); + db5500_add_usb(parent, usb_db5500_rx_dma_cfg, usb_db5500_tx_dma_cfg); + + for (i = 0; i < ARRAY_SIZE(db5500_platform_devs); i++) + db5500_platform_devs[i]->dev.parent = parent; platform_add_devices(db5500_platform_devs, ARRAY_SIZE(db5500_platform_devs)); + + return parent; } diff --git a/arch/arm/mach-ux500/cpu-db8500.c b/arch/arm/mach-ux500/cpu-db8500.c index 7176ee7491a..9bd8163896c 100644 --- a/arch/arm/mach-ux500/cpu-db8500.c +++ b/arch/arm/mach-ux500/cpu-db8500.c @@ -24,6 +24,7 @@ #include <mach/setup.h> #include <mach/devices.h> #include <mach/usb.h> +#include <mach/db8500-regs.h> #include "devices-db8500.h" #include "ste-dma40-db8500.h" @@ -132,13 +133,13 @@ static resource_size_t __initdata db8500_gpio_base[] = { U8500_GPIOBANK8_BASE, }; -static void __init db8500_add_gpios(void) +static void __init db8500_add_gpios(struct device *parent) { struct nmk_gpio_platform_data pdata = { .supports_sleepmode = true, }; - dbx500_add_gpios(ARRAY_AND_SIZE(db8500_gpio_base), + dbx500_add_gpios(parent, ARRAY_AND_SIZE(db8500_gpio_base), IRQ_DB8500_GPIO0, &pdata); } @@ -164,17 +165,44 @@ static int usb_db8500_tx_dma_cfg[] = { DB8500_DMA_DEV39_USB_OTG_OEP_8 }; +static const char *db8500_read_soc_id(void) +{ + void __iomem *uid = __io_address(U8500_BB_UID_BASE); + + return kasprintf(GFP_KERNEL, "%08x%08x%08x%08x%08x", + readl((u32 *)uid+1), + readl((u32 *)uid+1), readl((u32 *)uid+2), + readl((u32 *)uid+3), readl((u32 *)uid+4)); +} + +static struct device * __init db8500_soc_device_init(void) +{ + const char *soc_id = db8500_read_soc_id(); + + return ux500_soc_device_init(soc_id); +} + /* * This function is called from the board init */ -void __init u8500_init_devices(void) +struct device * __init u8500_init_devices(void) { - db8500_add_rtc(); - db8500_add_gpios(); - db8500_add_usb(usb_db8500_rx_dma_cfg, usb_db8500_tx_dma_cfg); + struct device *parent; + int i; + + parent = db8500_soc_device_init(); + + db8500_add_rtc(parent); + db8500_add_gpios(parent); + db8500_add_usb(parent, usb_db8500_rx_dma_cfg, usb_db8500_tx_dma_cfg); + + platform_device_register_data(parent, + "cpufreq-u8500", -1, NULL, 0); + + for (i = 0; i < ARRAY_SIZE(platform_devs); i++) + platform_devs[i]->dev.parent = parent; - platform_device_register_simple("cpufreq-u8500", -1, NULL, 0); platform_add_devices(platform_devs, ARRAY_SIZE(platform_devs)); - return ; + return parent; } diff --git a/arch/arm/mach-ux500/cpu.c b/arch/arm/mach-ux500/cpu.c index f4185749437..d11f3892a27 100644 --- a/arch/arm/mach-ux500/cpu.c +++ b/arch/arm/mach-ux500/cpu.c @@ -2,6 +2,7 @@ * Copyright (C) ST-Ericsson SA 2010 * * Author: Rabin Vincent <rabin.vincent@stericsson.com> for ST-Ericsson + * Author: Lee Jones <lee.jones@linaro.org> for ST-Ericsson * License terms: GNU General Public License (GPL) version 2 */ @@ -11,10 +12,15 @@ #include <linux/mfd/db8500-prcmu.h> #include <linux/mfd/db5500-prcmu.h> #include <linux/clksrc-dbx500-prcmu.h> +#include <linux/sys_soc.h> +#include <linux/err.h> +#include <linux/slab.h> +#include <linux/stat.h> +#include <linux/of.h> +#include <linux/of_irq.h> #include <asm/hardware/gic.h> #include <asm/mach/map.h> -#include <asm/localtimer.h> #include <mach/hardware.h> #include <mach/setup.h> @@ -24,6 +30,11 @@ void __iomem *_PRCMU_BASE; +static const struct of_device_id ux500_dt_irq_match[] = { + { .compatible = "arm,cortex-a9-gic", .data = gic_of_init, }, + {}, +}; + void __init ux500_init_irq(void) { void __iomem *dist_base; @@ -38,7 +49,12 @@ void __init ux500_init_irq(void) } else ux500_unknown_soc(); - gic_init(0, 29, dist_base, cpu_base); +#ifdef CONFIG_OF + if (of_have_populated_dt()) + of_irq_init(ux500_dt_irq_match); + else +#endif + gic_init(0, 29, dist_base, cpu_base); /* * Init clocks here so that they are available for system timer @@ -50,3 +66,73 @@ void __init ux500_init_irq(void) db8500_prcmu_early_init(); clk_init(); } + +static const char * __init ux500_get_machine(void) +{ + return kasprintf(GFP_KERNEL, "DB%4x", dbx500_partnumber()); +} + +static const char * __init ux500_get_family(void) +{ + return kasprintf(GFP_KERNEL, "ux500"); +} + +static const char * __init ux500_get_revision(void) +{ + unsigned int rev = dbx500_revision(); + + if (rev == 0x01) + return kasprintf(GFP_KERNEL, "%s", "ED"); + else if (rev >= 0xA0) + return kasprintf(GFP_KERNEL, "%d.%d", + (rev >> 4) - 0xA + 1, rev & 0xf); + + return kasprintf(GFP_KERNEL, "%s", "Unknown"); +} + +static ssize_t ux500_get_process(struct device *dev, + struct device_attribute *attr, + char *buf) +{ + if (dbx500_id.process == 0x00) + return sprintf(buf, "Standard\n"); + + return sprintf(buf, "%02xnm\n", dbx500_id.process); +} + +static void __init soc_info_populate(struct soc_device_attribute *soc_dev_attr, + const char *soc_id) +{ + soc_dev_attr->soc_id = soc_id; + soc_dev_attr->machine = ux500_get_machine(); + soc_dev_attr->family = ux500_get_family(); + soc_dev_attr->revision = ux500_get_revision(); +} + +struct device_attribute ux500_soc_attr = + __ATTR(process, S_IRUGO, ux500_get_process, NULL); + +struct device * __init ux500_soc_device_init(const char *soc_id) +{ + struct device *parent; + struct soc_device *soc_dev; + struct soc_device_attribute *soc_dev_attr; + + soc_dev_attr = kzalloc(sizeof(*soc_dev_attr), GFP_KERNEL); + if (!soc_dev_attr) + return ERR_PTR(-ENOMEM); + + soc_info_populate(soc_dev_attr, soc_id); + + soc_dev = soc_device_register(soc_dev_attr); + if (IS_ERR_OR_NULL(soc_dev)) { + kfree(soc_dev_attr); + return NULL; + } + + parent = soc_device_to_device(soc_dev); + if (!IS_ERR_OR_NULL(parent)) + device_create_file(parent, &ux500_soc_attr); + + return parent; +} diff --git a/arch/arm/mach-ux500/devices-common.c b/arch/arm/mach-ux500/devices-common.c index 898a64517b0..c5312a4b49f 100644 --- a/arch/arm/mach-ux500/devices-common.c +++ b/arch/arm/mach-ux500/devices-common.c @@ -20,8 +20,9 @@ #include "devices-common.h" struct amba_device * -dbx500_add_amba_device(const char *name, resource_size_t base, - int irq, void *pdata, unsigned int periphid) +dbx500_add_amba_device(struct device *parent, const char *name, + resource_size_t base, int irq, void *pdata, + unsigned int periphid) { struct amba_device *dev; int ret; @@ -39,6 +40,8 @@ dbx500_add_amba_device(const char *name, resource_size_t base, dev->dev.platform_data = pdata; + dev->dev.parent = parent; + ret = amba_device_add(dev, &iomem_resource); if (ret) { amba_device_put(dev); @@ -49,60 +52,7 @@ dbx500_add_amba_device(const char *name, resource_size_t base, } static struct platform_device * -dbx500_add_platform_device(const char *name, int id, void *pdata, - struct resource *res, int resnum) -{ - struct platform_device *dev; - int ret; - - dev = platform_device_alloc(name, id); - if (!dev) - return ERR_PTR(-ENOMEM); - - dev->dev.coherent_dma_mask = DMA_BIT_MASK(32); - dev->dev.dma_mask = &dev->dev.coherent_dma_mask; - - ret = platform_device_add_resources(dev, res, resnum); - if (ret) - goto out_free; - - dev->dev.platform_data = pdata; - - ret = platform_device_add(dev); - if (ret) - goto out_free; - - return dev; - -out_free: - platform_device_put(dev); - return ERR_PTR(ret); -} - -struct platform_device * -dbx500_add_platform_device_4k1irq(const char *name, int id, - resource_size_t base, - int irq, void *pdata) -{ - struct resource resources[] = { - [0] = { - .start = base, - .end = base + SZ_4K - 1, - .flags = IORESOURCE_MEM, - }, - [1] = { - .start = irq, - .end = irq, - .flags = IORESOURCE_IRQ, - } - }; - - return dbx500_add_platform_device(name, id, pdata, resources, - ARRAY_SIZE(resources)); -} - -static struct platform_device * -dbx500_add_gpio(int id, resource_size_t addr, int irq, +dbx500_add_gpio(struct device *parent, int id, resource_size_t addr, int irq, struct nmk_gpio_platform_data *pdata) { struct resource resources[] = { @@ -118,13 +68,18 @@ dbx500_add_gpio(int id, resource_size_t addr, int irq, } }; - return platform_device_register_resndata(NULL, "gpio", id, - resources, ARRAY_SIZE(resources), - pdata, sizeof(*pdata)); + return platform_device_register_resndata( + parent, + "gpio", + id, + resources, + ARRAY_SIZE(resources), + pdata, + sizeof(*pdata)); } -void dbx500_add_gpios(resource_size_t *base, int num, int irq, - struct nmk_gpio_platform_data *pdata) +void dbx500_add_gpios(struct device *parent, resource_size_t *base, int num, + int irq, struct nmk_gpio_platform_data *pdata) { int first = 0; int i; @@ -134,6 +89,6 @@ void dbx500_add_gpios(resource_size_t *base, int num, int irq, pdata->first_irq = NOMADIK_GPIO_TO_IRQ(first); pdata->num_gpio = 32; - dbx500_add_gpio(i, base[i], irq, pdata); + dbx500_add_gpio(parent, i, base[i], irq, pdata); } } diff --git a/arch/arm/mach-ux500/devices-common.h b/arch/arm/mach-ux500/devices-common.h index 7825705033b..39c74ec82ad 100644 --- a/arch/arm/mach-ux500/devices-common.h +++ b/arch/arm/mach-ux500/devices-common.h @@ -8,80 +8,89 @@ #ifndef __DEVICES_COMMON_H #define __DEVICES_COMMON_H -extern struct amba_device * -dbx500_add_amba_device(const char *name, resource_size_t base, - int irq, void *pdata, unsigned int periphid); +#include <linux/platform_device.h> +#include <linux/dma-mapping.h> +#include <linux/sys_soc.h> +#include <plat/i2c.h> -extern struct platform_device * -dbx500_add_platform_device_4k1irq(const char *name, int id, - resource_size_t base, - int irq, void *pdata); +extern struct amba_device * +dbx500_add_amba_device(struct device *parent, const char *name, + resource_size_t base, int irq, void *pdata, + unsigned int periphid); struct spi_master_cntlr; static inline struct amba_device * -dbx500_add_msp_spi(const char *name, resource_size_t base, int irq, +dbx500_add_msp_spi(struct device *parent, const char *name, + resource_size_t base, int irq, struct spi_master_cntlr *pdata) { - return dbx500_add_amba_device(name, base, irq, pdata, 0); + return dbx500_add_amba_device(parent, name, base, irq, + pdata, 0); } static inline struct amba_device * -dbx500_add_spi(const char *name, resource_size_t base, int irq, - struct spi_master_cntlr *pdata, +dbx500_add_spi(struct device *parent, const char *name, resource_size_t base, + int irq, struct spi_master_cntlr *pdata, u32 periphid) { - return dbx500_add_amba_device(name, base, irq, pdata, periphid); + return dbx500_add_amba_device(parent, name, base, irq, + pdata, periphid); } struct mmci_platform_data; static inline struct amba_device * -dbx500_add_sdi(const char *name, resource_size_t base, int irq, - struct mmci_platform_data *pdata, - u32 periphid) +dbx500_add_sdi(struct device *parent, const char *name, resource_size_t base, + int irq, struct mmci_platform_data *pdata, u32 periphid) { - return dbx500_add_amba_device(name, base, irq, pdata, periphid); + return dbx500_add_amba_device(parent, name, base, irq, + pdata, periphid); } struct amba_pl011_data; static inline struct amba_device * -dbx500_add_uart(const char *name, resource_size_t base, int irq, - struct amba_pl011_data *pdata) +dbx500_add_uart(struct device *parent, const char *name, resource_size_t base, + int irq, struct amba_pl011_data *pdata) { - return dbx500_add_amba_device(name, base, irq, pdata, 0); + return dbx500_add_amba_device(parent, name, base, irq, pdata, 0); } struct nmk_i2c_controller; static inline struct platform_device * -dbx500_add_i2c(int id, resource_size_t base, int irq, - struct nmk_i2c_controller *pdata) -{ - return dbx500_add_platform_device_4k1irq("nmk-i2c", id, base, irq, - pdata); -} - -struct msp_i2s_platform_data; - -static inline struct platform_device * -dbx500_add_msp_i2s(int id, resource_size_t base, int irq, - struct msp_i2s_platform_data *pdata) +dbx500_add_i2c(struct device *parent, int id, resource_size_t base, int irq, + struct nmk_i2c_controller *data) { - return dbx500_add_platform_device_4k1irq("MSP_I2S", id, base, irq, - pdata); + struct resource res[] = { + DEFINE_RES_MEM(base, SZ_4K), + DEFINE_RES_IRQ(irq), + }; + + struct platform_device_info pdevinfo = { + .parent = parent, + .name = "nmk-i2c", + .id = id, + .res = res, + .num_res = ARRAY_SIZE(res), + .data = data, + .size_data = sizeof(*data), + .dma_mask = DMA_BIT_MASK(32), + }; + + return platform_device_register_full(&pdevinfo); } static inline struct amba_device * -dbx500_add_rtc(resource_size_t base, int irq) +dbx500_add_rtc(struct device *parent, resource_size_t base, int irq) { - return dbx500_add_amba_device("rtc-pl031", base, irq, NULL, 0); + return dbx500_add_amba_device(parent, "rtc-pl031", base, irq, NULL, 0); } struct nmk_gpio_platform_data; -void dbx500_add_gpios(resource_size_t *base, int num, int irq, - struct nmk_gpio_platform_data *pdata); +void dbx500_add_gpios(struct device *parent, resource_size_t *base, int num, + int irq, struct nmk_gpio_platform_data *pdata); #endif diff --git a/arch/arm/mach-ux500/devices-db5500.h b/arch/arm/mach-ux500/devices-db5500.h index 0c4bccd02b9..e70955502c3 100644 --- a/arch/arm/mach-ux500/devices-db5500.h +++ b/arch/arm/mach-ux500/devices-db5500.h @@ -10,70 +10,90 @@ #include "devices-common.h" -#define db5500_add_i2c1(pdata) \ - dbx500_add_i2c(1, U5500_I2C1_BASE, IRQ_DB5500_I2C1, pdata) -#define db5500_add_i2c2(pdata) \ - dbx500_add_i2c(2, U5500_I2C2_BASE, IRQ_DB5500_I2C2, pdata) -#define db5500_add_i2c3(pdata) \ - dbx500_add_i2c(3, U5500_I2C3_BASE, IRQ_DB5500_I2C3, pdata) +#define db5500_add_i2c1(parent, pdata) \ + dbx500_add_i2c(parent, 1, U5500_I2C1_BASE, IRQ_DB5500_I2C1, pdata) +#define db5500_add_i2c2(parent, pdata) \ + dbx500_add_i2c(parent, 2, U5500_I2C2_BASE, IRQ_DB5500_I2C2, pdata) +#define db5500_add_i2c3(parent, pdata) \ + dbx500_add_i2c(parent, 3, U5500_I2C3_BASE, IRQ_DB5500_I2C3, pdata) -#define db5500_add_msp0_i2s(pdata) \ - dbx500_add_msp_i2s(0, U5500_MSP0_BASE, IRQ_DB5500_MSP0, pdata) -#define db5500_add_msp1_i2s(pdata) \ - dbx500_add_msp_i2s(1, U5500_MSP1_BASE, IRQ_DB5500_MSP1, pdata) -#define db5500_add_msp2_i2s(pdata) \ - dbx500_add_msp_i2s(2, U5500_MSP2_BASE, IRQ_DB5500_MSP2, pdata) +#define db5500_add_msp0_spi(parent, pdata) \ + dbx500_add_msp_spi(parent, "msp0", U5500_MSP0_BASE, \ + IRQ_DB5500_MSP0, pdata) +#define db5500_add_msp1_spi(parent, pdata) \ + dbx500_add_msp_spi(parent, "msp1", U5500_MSP1_BASE, \ + IRQ_DB5500_MSP1, pdata) +#define db5500_add_msp2_spi(parent, pdata) \ + dbx500_add_msp_spi(parent, "msp2", U5500_MSP2_BASE, \ + IRQ_DB5500_MSP2, pdata) -#define db5500_add_msp0_spi(pdata) \ - dbx500_add_msp_spi("msp0", U5500_MSP0_BASE, IRQ_DB5500_MSP0, pdata) -#define db5500_add_msp1_spi(pdata) \ - dbx500_add_msp_spi("msp1", U5500_MSP1_BASE, IRQ_DB5500_MSP1, pdata) -#define db5500_add_msp2_spi(pdata) \ - dbx500_add_msp_spi("msp2", U5500_MSP2_BASE, IRQ_DB5500_MSP2, pdata) +#define db5500_add_msp0_spi(parent, pdata) \ + dbx500_add_msp_spi(parent, "msp0", U5500_MSP0_BASE, \ + IRQ_DB5500_MSP0, pdata) +#define db5500_add_msp1_spi(parent, pdata) \ + dbx500_add_msp_spi(parent, "msp1", U5500_MSP1_BASE, \ + IRQ_DB5500_MSP1, pdata) +#define db5500_add_msp2_spi(parent, pdata) \ + dbx500_add_msp_spi(parent, "msp2", U5500_MSP2_BASE, \ + IRQ_DB5500_MSP2, pdata) -#define db5500_add_rtc() \ - dbx500_add_rtc(U5500_RTC_BASE, IRQ_DB5500_RTC); +#define db5500_add_rtc(parent) \ + dbx500_add_rtc(parent, U5500_RTC_BASE, IRQ_DB5500_RTC); -#define db5500_add_usb(rx_cfg, tx_cfg) \ - ux500_add_usb(U5500_USBOTG_BASE, IRQ_DB5500_USBOTG, rx_cfg, tx_cfg) +#define db5500_add_usb(parent, rx_cfg, tx_cfg) \ + ux500_add_usb(parent, U5500_USBOTG_BASE, \ + IRQ_DB5500_USBOTG, rx_cfg, tx_cfg) -#define db5500_add_sdi0(pdata) \ - dbx500_add_sdi("sdi0", U5500_SDI0_BASE, IRQ_DB5500_SDMMC0, pdata, \ +#define db5500_add_sdi0(parent, pdata) \ + dbx500_add_sdi(parent, "sdi0", U5500_SDI0_BASE, \ + IRQ_DB5500_SDMMC0, pdata, \ 0x10480180) -#define db5500_add_sdi1(pdata) \ - dbx500_add_sdi("sdi1", U5500_SDI1_BASE, IRQ_DB5500_SDMMC1, pdata, \ +#define db5500_add_sdi1(parent, pdata) \ + dbx500_add_sdi(parent, "sdi1", U5500_SDI1_BASE, \ + IRQ_DB5500_SDMMC1, pdata, \ 0x10480180) -#define db5500_add_sdi2(pdata) \ - dbx500_add_sdi("sdi2", U5500_SDI2_BASE, IRQ_DB5500_SDMMC2, pdata \ +#define db5500_add_sdi2(parent, pdata) \ + dbx500_add_sdi(parent, "sdi2", U5500_SDI2_BASE, \ + IRQ_DB5500_SDMMC2, pdata \ 0x10480180) -#define db5500_add_sdi3(pdata) \ - dbx500_add_sdi("sdi3", U5500_SDI3_BASE, IRQ_DB5500_SDMMC3, pdata \ +#define db5500_add_sdi3(parent, pdata) \ + dbx500_add_sdi(parent, "sdi3", U5500_SDI3_BASE, \ + IRQ_DB5500_SDMMC3, pdata \ 0x10480180) -#define db5500_add_sdi4(pdata) \ - dbx500_add_sdi("sdi4", U5500_SDI4_BASE, IRQ_DB5500_SDMMC4, pdata \ +#define db5500_add_sdi4(parent, pdata) \ + dbx500_add_sdi(parent, "sdi4", U5500_SDI4_BASE, \ + IRQ_DB5500_SDMMC4, pdata \ 0x10480180) /* This one has a bad peripheral ID in the U5500 silicon */ -#define db5500_add_spi0(pdata) \ - dbx500_add_spi("spi0", U5500_SPI0_BASE, IRQ_DB5500_SPI0, pdata, \ +#define db5500_add_spi0(parent, pdata) \ + dbx500_add_spi(parent, "spi0", U5500_SPI0_BASE, \ + IRQ_DB5500_SPI0, pdata, \ 0x10080023) -#define db5500_add_spi1(pdata) \ - dbx500_add_spi("spi1", U5500_SPI1_BASE, IRQ_DB5500_SPI1, pdata, \ +#define db5500_add_spi1(parent, pdata) \ + dbx500_add_spi(parent, "spi1", U5500_SPI1_BASE, \ + IRQ_DB5500_SPI1, pdata, \ 0x10080023) -#define db5500_add_spi2(pdata) \ - dbx500_add_spi("spi2", U5500_SPI2_BASE, IRQ_DB5500_SPI2, pdata \ +#define db5500_add_spi2(parent, pdata) \ + dbx500_add_spi(parent, "spi2", U5500_SPI2_BASE, \ + IRQ_DB5500_SPI2, pdata \ 0x10080023) -#define db5500_add_spi3(pdata) \ - dbx500_add_spi("spi3", U5500_SPI3_BASE, IRQ_DB5500_SPI3, pdata \ +#define db5500_add_spi3(parent, pdata) \ + dbx500_add_spi(parent, "spi3", U5500_SPI3_BASE, \ + IRQ_DB5500_SPI3, pdata \ 0x10080023) -#define db5500_add_uart0(plat) \ - dbx500_add_uart("uart0", U5500_UART0_BASE, IRQ_DB5500_UART0, plat) -#define db5500_add_uart1(plat) \ - dbx500_add_uart("uart1", U5500_UART1_BASE, IRQ_DB5500_UART1, plat) -#define db5500_add_uart2(plat) \ - dbx500_add_uart("uart2", U5500_UART2_BASE, IRQ_DB5500_UART2, plat) -#define db5500_add_uart3(plat) \ - dbx500_add_uart("uart3", U5500_UART3_BASE, IRQ_DB5500_UART3, plat) +#define db5500_add_uart0(parent, plat) \ + dbx500_add_uart(parent, "uart0", U5500_UART0_BASE, \ + IRQ_DB5500_UART0, plat) +#define db5500_add_uart1(parent, plat) \ + dbx500_add_uart(parent, "uart1", U5500_UART1_BASE, \ + IRQ_DB5500_UART1, plat) +#define db5500_add_uart2(parent, plat) \ + dbx500_add_uart(parent, "uart2", U5500_UART2_BASE, \ + IRQ_DB5500_UART2, plat) +#define db5500_add_uart3(parent, plat) \ + dbx500_add_uart(parent, "uart3", U5500_UART3_BASE, \ + IRQ_DB5500_UART3, plat) #endif diff --git a/arch/arm/mach-ux500/devices-db8500.h b/arch/arm/mach-ux500/devices-db8500.h index cbd4a9ae810..9fd93e9da52 100644 --- a/arch/arm/mach-ux500/devices-db8500.h +++ b/arch/arm/mach-ux500/devices-db8500.h @@ -14,88 +14,114 @@ struct ske_keypad_platform_data; struct pl022_ssp_controller; static inline struct platform_device * -db8500_add_ske_keypad(struct ske_keypad_platform_data *pdata) +db8500_add_ske_keypad(struct device *parent, + struct ske_keypad_platform_data *pdata, + size_t size) { - return dbx500_add_platform_device_4k1irq("nmk-ske-keypad", -1, - U8500_SKE_BASE, - IRQ_DB8500_KB, pdata); + struct resource resources[] = { + DEFINE_RES_MEM(U8500_SKE_BASE, SZ_4K), + DEFINE_RES_IRQ(IRQ_DB8500_KB), + }; + + return platform_device_register_resndata(parent, "nmk-ske-keypad", -1, + resources, 2, pdata, size); } static inline struct amba_device * -db8500_add_ssp(const char *name, resource_size_t base, int irq, - struct pl022_ssp_controller *pdata) +db8500_add_ssp(struct device *parent, const char *name, resource_size_t base, + int irq, struct pl022_ssp_controller *pdata) { - return dbx500_add_amba_device(name, base, irq, pdata, 0); + return dbx500_add_amba_device(parent, name, base, irq, pdata, 0); } -#define db8500_add_i2c0(pdata) \ - dbx500_add_i2c(0, U8500_I2C0_BASE, IRQ_DB8500_I2C0, pdata) -#define db8500_add_i2c1(pdata) \ - dbx500_add_i2c(1, U8500_I2C1_BASE, IRQ_DB8500_I2C1, pdata) -#define db8500_add_i2c2(pdata) \ - dbx500_add_i2c(2, U8500_I2C2_BASE, IRQ_DB8500_I2C2, pdata) -#define db8500_add_i2c3(pdata) \ - dbx500_add_i2c(3, U8500_I2C3_BASE, IRQ_DB8500_I2C3, pdata) -#define db8500_add_i2c4(pdata) \ - dbx500_add_i2c(4, U8500_I2C4_BASE, IRQ_DB8500_I2C4, pdata) - -#define db8500_add_msp0_i2s(pdata) \ - dbx500_add_msp_i2s(0, U8500_MSP0_BASE, IRQ_DB8500_MSP0, pdata) -#define db8500_add_msp1_i2s(pdata) \ - dbx500_add_msp_i2s(1, U8500_MSP1_BASE, IRQ_DB8500_MSP1, pdata) -#define db8500_add_msp2_i2s(pdata) \ - dbx500_add_msp_i2s(2, U8500_MSP2_BASE, IRQ_DB8500_MSP2, pdata) -#define db8500_add_msp3_i2s(pdata) \ - dbx500_add_msp_i2s(3, U8500_MSP3_BASE, IRQ_DB8500_MSP1, pdata) - -#define db8500_add_msp0_spi(pdata) \ - dbx500_add_msp_spi("msp0", U8500_MSP0_BASE, IRQ_DB8500_MSP0, pdata) -#define db8500_add_msp1_spi(pdata) \ - dbx500_add_msp_spi("msp1", U8500_MSP1_BASE, IRQ_DB8500_MSP1, pdata) -#define db8500_add_msp2_spi(pdata) \ - dbx500_add_msp_spi("msp2", U8500_MSP2_BASE, IRQ_DB8500_MSP2, pdata) -#define db8500_add_msp3_spi(pdata) \ - dbx500_add_msp_spi("msp3", U8500_MSP3_BASE, IRQ_DB8500_MSP1, pdata) - -#define db8500_add_rtc() \ - dbx500_add_rtc(U8500_RTC_BASE, IRQ_DB8500_RTC); - -#define db8500_add_usb(rx_cfg, tx_cfg) \ - ux500_add_usb(U8500_USBOTG_BASE, IRQ_DB8500_USBOTG, rx_cfg, tx_cfg) - -#define db8500_add_sdi0(pdata, pid) \ - dbx500_add_sdi("sdi0", U8500_SDI0_BASE, IRQ_DB8500_SDMMC0, pdata, pid) -#define db8500_add_sdi1(pdata, pid) \ - dbx500_add_sdi("sdi1", U8500_SDI1_BASE, IRQ_DB8500_SDMMC1, pdata, pid) -#define db8500_add_sdi2(pdata, pid) \ - dbx500_add_sdi("sdi2", U8500_SDI2_BASE, IRQ_DB8500_SDMMC2, pdata, pid) -#define db8500_add_sdi3(pdata, pid) \ - dbx500_add_sdi("sdi3", U8500_SDI3_BASE, IRQ_DB8500_SDMMC3, pdata, pid) -#define db8500_add_sdi4(pdata, pid) \ - dbx500_add_sdi("sdi4", U8500_SDI4_BASE, IRQ_DB8500_SDMMC4, pdata, pid) -#define db8500_add_sdi5(pdata, pid) \ - dbx500_add_sdi("sdi5", U8500_SDI5_BASE, IRQ_DB8500_SDMMC5, pdata, pid) - -#define db8500_add_ssp0(pdata) \ - db8500_add_ssp("ssp0", U8500_SSP0_BASE, IRQ_DB8500_SSP0, pdata) -#define db8500_add_ssp1(pdata) \ - db8500_add_ssp("ssp1", U8500_SSP1_BASE, IRQ_DB8500_SSP1, pdata) - -#define db8500_add_spi0(pdata) \ - dbx500_add_spi("spi0", U8500_SPI0_BASE, IRQ_DB8500_SPI0, pdata, 0) -#define db8500_add_spi1(pdata) \ - dbx500_add_spi("spi1", U8500_SPI1_BASE, IRQ_DB8500_SPI1, pdata, 0) -#define db8500_add_spi2(pdata) \ - dbx500_add_spi("spi2", U8500_SPI2_BASE, IRQ_DB8500_SPI2, pdata, 0) -#define db8500_add_spi3(pdata) \ - dbx500_add_spi("spi3", U8500_SPI3_BASE, IRQ_DB8500_SPI3, pdata, 0) - -#define db8500_add_uart0(pdata) \ - dbx500_add_uart("uart0", U8500_UART0_BASE, IRQ_DB8500_UART0, pdata) -#define db8500_add_uart1(pdata) \ - dbx500_add_uart("uart1", U8500_UART1_BASE, IRQ_DB8500_UART1, pdata) -#define db8500_add_uart2(pdata) \ - dbx500_add_uart("uart2", U8500_UART2_BASE, IRQ_DB8500_UART2, pdata) +#define db8500_add_i2c0(parent, pdata) \ + dbx500_add_i2c(parent, 0, U8500_I2C0_BASE, IRQ_DB8500_I2C0, pdata) +#define db8500_add_i2c1(parent, pdata) \ + dbx500_add_i2c(parent, 1, U8500_I2C1_BASE, IRQ_DB8500_I2C1, pdata) +#define db8500_add_i2c2(parent, pdata) \ + dbx500_add_i2c(parent, 2, U8500_I2C2_BASE, IRQ_DB8500_I2C2, pdata) +#define db8500_add_i2c3(parent, pdata) \ + dbx500_add_i2c(parent, 3, U8500_I2C3_BASE, IRQ_DB8500_I2C3, pdata) +#define db8500_add_i2c4(parent, pdata) \ + dbx500_add_i2c(parent, 4, U8500_I2C4_BASE, IRQ_DB8500_I2C4, pdata) + +#define db8500_add_msp0_i2s(parent, pdata) \ + dbx500_add_msp_i2s(parent, 0, U8500_MSP0_BASE, IRQ_DB8500_MSP0, pdata) +#define db8500_add_msp1_i2s(parent, pdata) \ + dbx500_add_msp_i2s(parent, 1, U8500_MSP1_BASE, IRQ_DB8500_MSP1, pdata) +#define db8500_add_msp2_i2s(parent, pdata) \ + dbx500_add_msp_i2s(parent, 2, U8500_MSP2_BASE, IRQ_DB8500_MSP2, pdata) +#define db8500_add_msp3_i2s(parent, pdata) \ + dbx500_add_msp_i2s(parent, 3, U8500_MSP3_BASE, IRQ_DB8500_MSP1, pdata) + +#define db8500_add_msp0_spi(parent, pdata) \ + dbx500_add_msp_spi(parent, "msp0", U8500_MSP0_BASE, \ + IRQ_DB8500_MSP0, pdata) +#define db8500_add_msp1_spi(parent, pdata) \ + dbx500_add_msp_spi(parent, "msp1", U8500_MSP1_BASE, \ + IRQ_DB8500_MSP1, pdata) +#define db8500_add_msp2_spi(parent, pdata) \ + dbx500_add_msp_spi(parent, "msp2", U8500_MSP2_BASE, \ + IRQ_DB8500_MSP2, pdata) +#define db8500_add_msp3_spi(parent, pdata) \ + dbx500_add_msp_spi(parent, "msp3", U8500_MSP3_BASE, \ + IRQ_DB8500_MSP1, pdata) + +#define db8500_add_rtc(parent) \ + dbx500_add_rtc(parent, U8500_RTC_BASE, IRQ_DB8500_RTC); + +#define db8500_add_usb(parent, rx_cfg, tx_cfg) \ + ux500_add_usb(parent, U8500_USBOTG_BASE, \ + IRQ_DB8500_USBOTG, rx_cfg, tx_cfg) + +#define db8500_add_sdi0(parent, pdata, pid) \ + dbx500_add_sdi(parent, "sdi0", U8500_SDI0_BASE, \ + IRQ_DB8500_SDMMC0, pdata, pid) +#define db8500_add_sdi1(parent, pdata, pid) \ + dbx500_add_sdi(parent, "sdi1", U8500_SDI1_BASE, \ + IRQ_DB8500_SDMMC1, pdata, pid) +#define db8500_add_sdi2(parent, pdata, pid) \ + dbx500_add_sdi(parent, "sdi2", U8500_SDI2_BASE, \ + IRQ_DB8500_SDMMC2, pdata, pid) +#define db8500_add_sdi3(parent, pdata, pid) \ + dbx500_add_sdi(parent, "sdi3", U8500_SDI3_BASE, \ + IRQ_DB8500_SDMMC3, pdata, pid) +#define db8500_add_sdi4(parent, pdata, pid) \ + dbx500_add_sdi(parent, "sdi4", U8500_SDI4_BASE, \ + IRQ_DB8500_SDMMC4, pdata, pid) +#define db8500_add_sdi5(parent, pdata, pid) \ + dbx500_add_sdi(parent, "sdi5", U8500_SDI5_BASE, \ + IRQ_DB8500_SDMMC5, pdata, pid) + +#define db8500_add_ssp0(parent, pdata) \ + db8500_add_ssp(parent, "ssp0", U8500_SSP0_BASE, \ + IRQ_DB8500_SSP0, pdata) +#define db8500_add_ssp1(parent, pdata) \ + db8500_add_ssp(parent, "ssp1", U8500_SSP1_BASE, \ + IRQ_DB8500_SSP1, pdata) + +#define db8500_add_spi0(parent, pdata) \ + dbx500_add_spi(parent, "spi0", U8500_SPI0_BASE, \ + IRQ_DB8500_SPI0, pdata, 0) +#define db8500_add_spi1(parent, pdata) \ + dbx500_add_spi(parent, "spi1", U8500_SPI1_BASE, \ + IRQ_DB8500_SPI1, pdata, 0) +#define db8500_add_spi2(parent, pdata) \ + dbx500_add_spi(parent, "spi2", U8500_SPI2_BASE, \ + IRQ_DB8500_SPI2, pdata, 0) +#define db8500_add_spi3(parent, pdata) \ + dbx500_add_spi(parent, "spi3", U8500_SPI3_BASE, \ + IRQ_DB8500_SPI3, pdata, 0) + +#define db8500_add_uart0(parent, pdata) \ + dbx500_add_uart(parent, "uart0", U8500_UART0_BASE, \ + IRQ_DB8500_UART0, pdata) +#define db8500_add_uart1(parent, pdata) \ + dbx500_add_uart(parent, "uart1", U8500_UART1_BASE, \ + IRQ_DB8500_UART1, pdata) +#define db8500_add_uart2(parent, pdata) \ + dbx500_add_uart(parent, "uart2", U8500_UART2_BASE, \ + IRQ_DB8500_UART2, pdata) #endif diff --git a/arch/arm/mach-ux500/dma-db5500.c b/arch/arm/mach-ux500/dma-db5500.c index 1cfab68ae41..41e9470fa0e 100644 --- a/arch/arm/mach-ux500/dma-db5500.c +++ b/arch/arm/mach-ux500/dma-db5500.c @@ -125,10 +125,11 @@ static struct platform_device dma40_device = { .resource = dma40_resources }; -void __init db5500_dma_init(void) +void __init db5500_dma_init(struct device *parent) { int ret; + dma40_device.dev.parent = parent; ret = platform_device_register(&dma40_device); if (ret) dev_err(&dma40_device.dev, "unable to register device: %d\n", ret); diff --git a/arch/arm/mach-ux500/include/mach/db8500-regs.h b/arch/arm/mach-ux500/include/mach/db8500-regs.h index 80e10f50282..9ec20b96d8f 100644 --- a/arch/arm/mach-ux500/include/mach/db8500-regs.h +++ b/arch/arm/mach-ux500/include/mach/db8500-regs.h @@ -161,4 +161,7 @@ #define U8500_MODEM_BASE 0xe000000 #define U8500_APE_BASE 0x6000000 +/* SoC identification number information */ +#define U8500_BB_UID_BASE (U8500_BACKUPRAM1_BASE + 0xFC0) + #endif diff --git a/arch/arm/mach-ux500/include/mach/setup.h b/arch/arm/mach-ux500/include/mach/setup.h index a7d363fdb4c..3dc00ffa7bf 100644 --- a/arch/arm/mach-ux500/include/mach/setup.h +++ b/arch/arm/mach-ux500/include/mach/setup.h @@ -18,17 +18,16 @@ void __init ux500_map_io(void); extern void __init u5500_map_io(void); extern void __init u8500_map_io(void); -extern void __init u5500_init_devices(void); -extern void __init u8500_init_devices(void); +extern struct device * __init u5500_init_devices(void); +extern struct device * __init u8500_init_devices(void); extern void __init ux500_init_irq(void); -extern void __init u5500_sdi_init(void); +extern void __init u5500_sdi_init(struct device *parent); -extern void __init db5500_dma_init(void); +extern void __init db5500_dma_init(struct device *parent); -/* We re-use nomadik_timer for this platform */ -extern void nmdk_timer_init(void); +extern struct device *ux500_soc_device_init(const char *soc_id); struct amba_device; extern void __init amba_add_devices(struct amba_device *devs[], int num); diff --git a/arch/arm/mach-ux500/include/mach/usb.h b/arch/arm/mach-ux500/include/mach/usb.h index d3739d41881..4c1cc50a595 100644 --- a/arch/arm/mach-ux500/include/mach/usb.h +++ b/arch/arm/mach-ux500/include/mach/usb.h @@ -20,6 +20,6 @@ struct ux500_musb_board_data { bool (*dma_filter)(struct dma_chan *chan, void *filter_param); }; -void ux500_add_usb(resource_size_t base, int irq, int *dma_rx_cfg, - int *dma_tx_cfg); +void ux500_add_usb(struct device *parent, resource_size_t base, + int irq, int *dma_rx_cfg, int *dma_tx_cfg); #endif diff --git a/arch/arm/mach-ux500/localtimer.c b/arch/arm/mach-ux500/localtimer.c deleted file mode 100644 index 5ba113309a0..00000000000 --- a/arch/arm/mach-ux500/localtimer.c +++ /dev/null @@ -1,29 +0,0 @@ -/* - * Copyright (C) 2008-2009 ST-Ericsson - * Srinidhi Kasagar <srinidhi.kasagar@stericsson.com> - * - * This file is heavily based on relaview platform, almost a copy. - * - * Copyright (C) 2002 ARM Ltd. - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. - */ -#include <linux/init.h> -#include <linux/smp.h> -#include <linux/clockchips.h> - -#include <asm/irq.h> -#include <asm/smp_twd.h> -#include <asm/localtimer.h> - -/* - * Setup the local clock events for a CPU. - */ -int __cpuinit local_timer_setup(struct clock_event_device *evt) -{ - evt->irq = IRQ_LOCALTIMER; - twd_timer_setup(evt); - return 0; -} diff --git a/arch/arm/mach-ux500/timer.c b/arch/arm/mach-ux500/timer.c index aea467d04ff..d37df98b5c3 100644 --- a/arch/arm/mach-ux500/timer.c +++ b/arch/arm/mach-ux500/timer.c @@ -7,29 +7,52 @@ #include <linux/io.h> #include <linux/errno.h> #include <linux/clksrc-dbx500-prcmu.h> +#include <linux/of.h> -#include <asm/localtimer.h> +#include <asm/smp_twd.h> #include <plat/mtu.h> #include <mach/setup.h> #include <mach/hardware.h> +#include <mach/irqs.h> + +#ifdef CONFIG_HAVE_ARM_TWD +static DEFINE_TWD_LOCAL_TIMER(u5500_twd_local_timer, + U5500_TWD_BASE, IRQ_LOCALTIMER); +static DEFINE_TWD_LOCAL_TIMER(u8500_twd_local_timer, + U8500_TWD_BASE, IRQ_LOCALTIMER); + +static void __init ux500_twd_init(void) +{ + struct twd_local_timer *twd_local_timer; + int err; + + twd_local_timer = cpu_is_u5500() ? &u5500_twd_local_timer : + &u8500_twd_local_timer; + + if (of_have_populated_dt()) + twd_local_timer_of_register(); + else { + err = twd_local_timer_register(twd_local_timer); + if (err) + pr_err("twd_local_timer_register failed %d\n", err); + } +} +#else +#define ux500_twd_init() do { } while(0) +#endif static void __init ux500_timer_init(void) { + void __iomem *mtu_timer_base; void __iomem *prcmu_timer_base; if (cpu_is_u5500()) { -#ifdef CONFIG_LOCAL_TIMERS - twd_base = __io_address(U5500_TWD_BASE); -#endif - mtu_base = __io_address(U5500_MTU0_BASE); + mtu_timer_base = __io_address(U5500_MTU0_BASE); prcmu_timer_base = __io_address(U5500_PRCMU_TIMER_3_BASE); } else if (cpu_is_u8500()) { -#ifdef CONFIG_LOCAL_TIMERS - twd_base = __io_address(U8500_TWD_BASE); -#endif - mtu_base = __io_address(U8500_MTU0_BASE); + mtu_timer_base = __io_address(U8500_MTU0_BASE); prcmu_timer_base = __io_address(U8500_PRCMU_TIMER_4_BASE); } else { ux500_unknown_soc(); @@ -52,8 +75,9 @@ static void __init ux500_timer_init(void) * */ - nmdk_timer_init(); + nmdk_timer_init(mtu_timer_base); clksrc_dbx500_prcmu_init(prcmu_timer_base); + ux500_twd_init(); } static void ux500_timer_reset(void) diff --git a/arch/arm/mach-ux500/usb.c b/arch/arm/mach-ux500/usb.c index 9f9e1c20306..a74af389bc6 100644 --- a/arch/arm/mach-ux500/usb.c +++ b/arch/arm/mach-ux500/usb.c @@ -7,6 +7,7 @@ #include <linux/platform_device.h> #include <linux/usb/musb.h> #include <linux/dma-mapping.h> + #include <plat/ste_dma40.h> #include <mach/hardware.h> #include <mach/usb.h> @@ -140,8 +141,8 @@ static inline void ux500_usb_dma_update_tx_ch_config(int *dst_dev_type) musb_dma_tx_ch[idx].dst_dev_type = dst_dev_type[idx]; } -void ux500_add_usb(resource_size_t base, int irq, int *dma_rx_cfg, - int *dma_tx_cfg) +void ux500_add_usb(struct device *parent, resource_size_t base, int irq, + int *dma_rx_cfg, int *dma_tx_cfg) { ux500_musb_device.resource[0].start = base; ux500_musb_device.resource[0].end = base + SZ_64K - 1; @@ -151,5 +152,7 @@ void ux500_add_usb(resource_size_t base, int irq, int *dma_rx_cfg, ux500_usb_dma_update_rx_ch_config(dma_rx_cfg); ux500_usb_dma_update_tx_ch_config(dma_tx_cfg); + ux500_musb_device.dev.parent = parent; + platform_device_register(&ux500_musb_device); } diff --git a/arch/arm/mach-vexpress/ct-ca9x4.c b/arch/arm/mach-vexpress/ct-ca9x4.c index 73791f01029..c65cc3b462a 100644 --- a/arch/arm/mach-vexpress/ct-ca9x4.c +++ b/arch/arm/mach-vexpress/ct-ca9x4.c @@ -42,15 +42,26 @@ static struct map_desc ct_ca9x4_io_desc[] __initdata = { static void __init ct_ca9x4_map_io(void) { iotable_init(ct_ca9x4_io_desc, ARRAY_SIZE(ct_ca9x4_io_desc)); -#ifdef CONFIG_LOCAL_TIMERS - twd_base = ioremap(A9_MPCORE_TWD, SZ_32); -#endif } +#ifdef CONFIG_HAVE_ARM_TWD +static DEFINE_TWD_LOCAL_TIMER(twd_local_timer, A9_MPCORE_TWD, IRQ_LOCALTIMER); + +static void __init ca9x4_twd_init(void) +{ + int err = twd_local_timer_register(&twd_local_timer); + if (err) + pr_err("twd_local_timer_register failed %d\n", err); +} +#else +#define ca9x4_twd_init() do {} while(0) +#endif + static void __init ct_ca9x4_init_irq(void) { gic_init(0, 29, ioremap(A9_MPCORE_GIC_DIST, SZ_4K), ioremap(A9_MPCORE_GIC_CPU, SZ_256)); + ca9x4_twd_init(); } static void ct_ca9x4_clcd_enable(struct clcd_fb *fb) diff --git a/arch/arm/plat-nomadik/include/plat/mtu.h b/arch/arm/plat-nomadik/include/plat/mtu.h index 6508e7694a4..582641f3dc0 100644 --- a/arch/arm/plat-nomadik/include/plat/mtu.h +++ b/arch/arm/plat-nomadik/include/plat/mtu.h @@ -1,9 +1,7 @@ #ifndef __PLAT_MTU_H #define __PLAT_MTU_H -/* should be set by the platform code */ -extern void __iomem *mtu_base; - +void nmdk_timer_init(void __iomem *base); void nmdk_clkevt_reset(void); void nmdk_clksrc_reset(void); diff --git a/arch/arm/plat-nomadik/timer.c b/arch/arm/plat-nomadik/timer.c index ad1b45b605a..9222e5522a4 100644 --- a/arch/arm/plat-nomadik/timer.c +++ b/arch/arm/plat-nomadik/timer.c @@ -21,12 +21,6 @@ #include <asm/sched_clock.h> /* - * Guaranteed runtime conversion range in seconds for - * the clocksource and clockevent. - */ -#define MTU_MIN_RANGE 4 - -/* * The MTU device hosts four different counters, with 4 set of * registers. These are register names. */ @@ -66,12 +60,11 @@ #define MTU_PCELL2 0xff8 #define MTU_PCELL3 0xffC +static void __iomem *mtu_base; static bool clkevt_periodic; static u32 clk_prescale; static u32 nmdk_cycle; /* write-once */ -void __iomem *mtu_base; /* Assigned by machine code */ - #ifdef CONFIG_NOMADIK_MTU_SCHED_CLOCK /* * Override the global weak sched_clock symbol with this @@ -103,7 +96,6 @@ static int nmdk_clkevt_next(unsigned long evt, struct clock_event_device *ev) void nmdk_clkevt_reset(void) { if (clkevt_periodic) { - /* Timer: configure load and background-load, and fire it up */ writel(nmdk_cycle, mtu_base + MTU_LR(1)); writel(nmdk_cycle, mtu_base + MTU_BGLR(1)); @@ -121,7 +113,6 @@ void nmdk_clkevt_reset(void) static void nmdk_clkevt_mode(enum clock_event_mode mode, struct clock_event_device *dev) { - switch (mode) { case CLOCK_EVT_MODE_PERIODIC: clkevt_periodic = true; @@ -183,15 +174,16 @@ void nmdk_clksrc_reset(void) mtu_base + MTU_CR(0)); } -void __init nmdk_timer_init(void) +void __init nmdk_timer_init(void __iomem *base) { unsigned long rate; struct clk *clk0; + mtu_base = base; clk0 = clk_get_sys("mtu0", NULL); BUG_ON(IS_ERR(clk0)); - - clk_enable(clk0); + BUG_ON(clk_prepare(clk0) < 0); + BUG_ON(clk_enable(clk0) < 0); /* * Tick rate is 2.4MHz for Nomadik and 2.4Mhz, 100MHz or 133 MHz @@ -224,17 +216,8 @@ void __init nmdk_timer_init(void) setup_sched_clock(nomadik_read_sched_clock, 32, rate); #endif - /* Timer 1 is used for events */ - - clockevents_calc_mult_shift(&nmdk_clkevt, rate, MTU_MIN_RANGE); - - nmdk_clkevt.max_delta_ns = - clockevent_delta2ns(0xffffffff, &nmdk_clkevt); - nmdk_clkevt.min_delta_ns = - clockevent_delta2ns(0x00000002, &nmdk_clkevt); - nmdk_clkevt.cpumask = cpumask_of(0); - - /* Register irq and clockevents */ + /* Timer 1 is used for events, register irq and clockevents */ setup_irq(IRQ_MTU0, &nmdk_timer_irq); - clockevents_register_device(&nmdk_clkevt); + nmdk_clkevt.cpumask = cpumask_of(0); + clockevents_config_and_register(&nmdk_clkevt, rate, 2, 0xffffffffU); } diff --git a/arch/arm/plat-versatile/Makefile b/arch/arm/plat-versatile/Makefile index 69714db47c3..a5cb1945bdc 100644 --- a/arch/arm/plat-versatile/Makefile +++ b/arch/arm/plat-versatile/Makefile @@ -1,5 +1,4 @@ obj-y := clock.o -obj-$(CONFIG_LOCAL_TIMERS) += localtimer.o obj-$(CONFIG_PLAT_VERSATILE_CLCD) += clcd.o obj-$(CONFIG_PLAT_VERSATILE_FPGA_IRQ) += fpga-irq.o obj-$(CONFIG_PLAT_VERSATILE_LEDS) += leds.o diff --git a/arch/arm/plat-versatile/localtimer.c b/arch/arm/plat-versatile/localtimer.c deleted file mode 100644 index e1566879315..00000000000 --- a/arch/arm/plat-versatile/localtimer.c +++ /dev/null @@ -1,53 +0,0 @@ -/* - * linux/arch/arm/plat-versatile/localtimer.c - * - * Copyright (C) 2002 ARM Ltd. - * All Rights Reserved - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. - */ -#include <linux/init.h> -#include <linux/smp.h> -#include <linux/clockchips.h> -#include <linux/of.h> -#include <linux/of_address.h> - -#include <asm/smp_twd.h> -#include <asm/localtimer.h> -#include <mach/irqs.h> - -const static struct of_device_id twd_of_match[] __initconst = { - { .compatible = "arm,cortex-a9-twd-timer", }, - { .compatible = "arm,cortex-a5-twd-timer", }, - { .compatible = "arm,arm11mp-twd-timer", }, - { }, -}; - -/* - * Setup the local clock events for a CPU. - */ -int __cpuinit local_timer_setup(struct clock_event_device *evt) -{ -#if defined(CONFIG_OF) - static int dt_node_probed; - - /* Look for TWD node only once */ - if (!dt_node_probed) { - struct device_node *node = of_find_matching_node(NULL, - twd_of_match); - - if (node) - twd_base = of_iomap(node, 0); - - dt_node_probed = 1; - } -#endif - if (!twd_base) - return -ENXIO; - - evt->irq = IRQ_LOCALTIMER; - twd_timer_setup(evt); - return 0; -} diff --git a/arch/x86/Kconfig b/arch/x86/Kconfig index e0829a6a466..ab39bb20a42 100644 --- a/arch/x86/Kconfig +++ b/arch/x86/Kconfig @@ -179,6 +179,9 @@ config ARCH_HAS_DEFAULT_IDLE config ARCH_HAS_CACHE_LINE_SIZE def_bool y +config ARCH_HAS_CPU_AUTOPROBE + def_bool y + config HAVE_SETUP_PER_CPU_AREA def_bool y diff --git a/arch/x86/crypto/aesni-intel_glue.c b/arch/x86/crypto/aesni-intel_glue.c index 545d0ce5981..b3350bd32c6 100644 --- a/arch/x86/crypto/aesni-intel_glue.c +++ b/arch/x86/crypto/aesni-intel_glue.c @@ -28,6 +28,7 @@ #include <crypto/aes.h> #include <crypto/cryptd.h> #include <crypto/ctr.h> +#include <asm/cpu_device_id.h> #include <asm/i387.h> #include <asm/aes.h> #include <crypto/scatterwalk.h> @@ -1253,14 +1254,19 @@ static struct crypto_alg __rfc4106_alg = { }; #endif + +static const struct x86_cpu_id aesni_cpu_id[] = { + X86_FEATURE_MATCH(X86_FEATURE_AES), + {} +}; +MODULE_DEVICE_TABLE(x86cpu, aesni_cpu_id); + static int __init aesni_init(void) { int err; - if (!cpu_has_aes) { - printk(KERN_INFO "Intel AES-NI instructions are not detected.\n"); + if (!x86_match_cpu(aesni_cpu_id)) return -ENODEV; - } if ((err = crypto_fpu_init())) goto fpu_err; diff --git a/arch/x86/crypto/crc32c-intel.c b/arch/x86/crypto/crc32c-intel.c index b9d00261703..493f959261f 100644 --- a/arch/x86/crypto/crc32c-intel.c +++ b/arch/x86/crypto/crc32c-intel.c @@ -31,6 +31,7 @@ #include <crypto/internal/hash.h> #include <asm/cpufeature.h> +#include <asm/cpu_device_id.h> #define CHKSUM_BLOCK_SIZE 1 #define CHKSUM_DIGEST_SIZE 4 @@ -173,13 +174,17 @@ static struct shash_alg alg = { } }; +static const struct x86_cpu_id crc32c_cpu_id[] = { + X86_FEATURE_MATCH(X86_FEATURE_XMM4_2), + {} +}; +MODULE_DEVICE_TABLE(x86cpu, crc32c_cpu_id); static int __init crc32c_intel_mod_init(void) { - if (cpu_has_xmm4_2) - return crypto_register_shash(&alg); - else + if (!x86_match_cpu(crc32c_cpu_id)) return -ENODEV; + return crypto_register_shash(&alg); } static void __exit crc32c_intel_mod_fini(void) diff --git a/arch/x86/crypto/ghash-clmulni-intel_glue.c b/arch/x86/crypto/ghash-clmulni-intel_glue.c index 976aa64d9a2..b4bf0a63b52 100644 --- a/arch/x86/crypto/ghash-clmulni-intel_glue.c +++ b/arch/x86/crypto/ghash-clmulni-intel_glue.c @@ -20,6 +20,7 @@ #include <crypto/gf128mul.h> #include <crypto/internal/hash.h> #include <asm/i387.h> +#include <asm/cpu_device_id.h> #define GHASH_BLOCK_SIZE 16 #define GHASH_DIGEST_SIZE 16 @@ -294,15 +295,18 @@ static struct ahash_alg ghash_async_alg = { }, }; +static const struct x86_cpu_id pcmul_cpu_id[] = { + X86_FEATURE_MATCH(X86_FEATURE_PCLMULQDQ), /* Pickle-Mickle-Duck */ + {} +}; +MODULE_DEVICE_TABLE(x86cpu, pcmul_cpu_id); + static int __init ghash_pclmulqdqni_mod_init(void) { int err; - if (!cpu_has_pclmulqdq) { - printk(KERN_INFO "Intel PCLMULQDQ-NI instructions are not" - " detected.\n"); + if (!x86_match_cpu(pcmul_cpu_id)) return -ENODEV; - } err = crypto_register_shash(&ghash_alg); if (err) diff --git a/arch/x86/include/asm/cpu_device_id.h b/arch/x86/include/asm/cpu_device_id.h new file mode 100644 index 00000000000..ff501e511d9 --- /dev/null +++ b/arch/x86/include/asm/cpu_device_id.h @@ -0,0 +1,13 @@ +#ifndef _CPU_DEVICE_ID +#define _CPU_DEVICE_ID 1 + +/* + * Declare drivers belonging to specific x86 CPUs + * Similar in spirit to pci_device_id and related PCI functions + */ + +#include <linux/mod_devicetable.h> + +extern const struct x86_cpu_id *x86_match_cpu(const struct x86_cpu_id *match); + +#endif diff --git a/arch/x86/include/asm/cpufeature.h b/arch/x86/include/asm/cpufeature.h index 8d67d428b0f..dcb839eebc7 100644 --- a/arch/x86/include/asm/cpufeature.h +++ b/arch/x86/include/asm/cpufeature.h @@ -177,6 +177,7 @@ #define X86_FEATURE_PLN (7*32+ 5) /* Intel Power Limit Notification */ #define X86_FEATURE_PTS (7*32+ 6) /* Intel Package Thermal Status */ #define X86_FEATURE_DTS (7*32+ 7) /* Digital Thermal Sensor */ +#define X86_FEATURE_HW_PSTATE (7*32+ 8) /* AMD HW-PState */ /* Virtualization flags: Linux defined, word 8 */ #define X86_FEATURE_TPR_SHADOW (8*32+ 0) /* Intel TPR Shadow */ diff --git a/arch/x86/kernel/cpu/Makefile b/arch/x86/kernel/cpu/Makefile index 25f24dccdcf..6ab6aa2fdfd 100644 --- a/arch/x86/kernel/cpu/Makefile +++ b/arch/x86/kernel/cpu/Makefile @@ -16,6 +16,7 @@ obj-y := intel_cacheinfo.o scattered.o topology.o obj-y += proc.o capflags.o powerflags.o common.o obj-y += vmware.o hypervisor.o sched.o mshyperv.o obj-y += rdrand.o +obj-y += match.o obj-$(CONFIG_X86_32) += bugs.o obj-$(CONFIG_X86_64) += bugs_64.o diff --git a/arch/x86/kernel/cpu/match.c b/arch/x86/kernel/cpu/match.c new file mode 100644 index 00000000000..940e2d48307 --- /dev/null +++ b/arch/x86/kernel/cpu/match.c @@ -0,0 +1,92 @@ +#include <asm/cpu_device_id.h> +#include <asm/processor.h> +#include <linux/cpu.h> +#include <linux/module.h> +#include <linux/slab.h> + +/** + * x86_match_cpu - match current CPU again an array of x86_cpu_ids + * @match: Pointer to array of x86_cpu_ids. Last entry terminated with + * {}. + * + * Return the entry if the current CPU matches the entries in the + * passed x86_cpu_id match table. Otherwise NULL. The match table + * contains vendor (X86_VENDOR_*), family, model and feature bits or + * respective wildcard entries. + * + * A typical table entry would be to match a specific CPU + * { X86_VENDOR_INTEL, 6, 0x12 } + * or to match a specific CPU feature + * { X86_FEATURE_MATCH(X86_FEATURE_FOOBAR) } + * + * Fields can be wildcarded with %X86_VENDOR_ANY, %X86_FAMILY_ANY, + * %X86_MODEL_ANY, %X86_FEATURE_ANY or 0 (except for vendor) + * + * Arrays used to match for this should also be declared using + * MODULE_DEVICE_TABLE(x86_cpu, ...) + * + * This always matches against the boot cpu, assuming models and features are + * consistent over all CPUs. + */ +const struct x86_cpu_id *x86_match_cpu(const struct x86_cpu_id *match) +{ + const struct x86_cpu_id *m; + struct cpuinfo_x86 *c = &boot_cpu_data; + + for (m = match; m->vendor | m->family | m->model | m->feature; m++) { + if (m->vendor != X86_VENDOR_ANY && c->x86_vendor != m->vendor) + continue; + if (m->family != X86_FAMILY_ANY && c->x86 != m->family) + continue; + if (m->model != X86_MODEL_ANY && c->x86_model != m->model) + continue; + if (m->feature != X86_FEATURE_ANY && !cpu_has(c, m->feature)) + continue; + return m; + } + return NULL; +} +EXPORT_SYMBOL(x86_match_cpu); + +ssize_t arch_print_cpu_modalias(struct device *dev, + struct device_attribute *attr, + char *bufptr) +{ + int size = PAGE_SIZE; + int i, n; + char *buf = bufptr; + + n = snprintf(buf, size, "x86cpu:vendor:%04X:family:%04X:" + "model:%04X:feature:", + boot_cpu_data.x86_vendor, + boot_cpu_data.x86, + boot_cpu_data.x86_model); + size -= n; + buf += n; + size -= 2; + for (i = 0; i < NCAPINTS*32; i++) { + if (boot_cpu_has(i)) { + n = snprintf(buf, size, ",%04X", i); + if (n < 0) { + WARN(1, "x86 features overflow page\n"); + break; + } + size -= n; + buf += n; + } + } + *buf++ = ','; + *buf++ = '\n'; + return buf - bufptr; +} + +int arch_cpu_uevent(struct device *dev, struct kobj_uevent_env *env) +{ + char *buf = kzalloc(PAGE_SIZE, GFP_KERNEL); + if (buf) { + arch_print_cpu_modalias(NULL, NULL, buf); + add_uevent_var(env, "MODALIAS=%s", buf); + kfree(buf); + } + return 0; +} diff --git a/arch/x86/kernel/cpu/scattered.c b/arch/x86/kernel/cpu/scattered.c index c7f64e6f537..addf9e82a7f 100644 --- a/arch/x86/kernel/cpu/scattered.c +++ b/arch/x86/kernel/cpu/scattered.c @@ -40,6 +40,7 @@ void __cpuinit init_scattered_cpuid_features(struct cpuinfo_x86 *c) { X86_FEATURE_EPB, CR_ECX, 3, 0x00000006, 0 }, { X86_FEATURE_XSAVEOPT, CR_EAX, 0, 0x0000000d, 1 }, { X86_FEATURE_CPB, CR_EDX, 9, 0x80000007, 0 }, + { X86_FEATURE_HW_PSTATE, CR_EDX, 7, 0x80000007, 0 }, { X86_FEATURE_NPT, CR_EDX, 0, 0x8000000a, 0 }, { X86_FEATURE_LBRV, CR_EDX, 1, 0x8000000a, 0 }, { X86_FEATURE_SVML, CR_EDX, 2, 0x8000000a, 0 }, diff --git a/arch/x86/kernel/microcode_core.c b/arch/x86/kernel/microcode_core.c index fda91c30710..87a0f868830 100644 --- a/arch/x86/kernel/microcode_core.c +++ b/arch/x86/kernel/microcode_core.c @@ -86,6 +86,7 @@ #include <asm/microcode.h> #include <asm/processor.h> +#include <asm/cpu_device_id.h> MODULE_DESCRIPTION("Microcode Update Driver"); MODULE_AUTHOR("Tigran Aivazian <tigran@aivazian.fsnet.co.uk>"); @@ -504,6 +505,20 @@ static struct notifier_block __refdata mc_cpu_notifier = { .notifier_call = mc_cpu_callback, }; +#ifdef MODULE +/* Autoload on Intel and AMD systems */ +static const struct x86_cpu_id microcode_id[] = { +#ifdef CONFIG_MICROCODE_INTEL + { X86_VENDOR_INTEL, X86_FAMILY_ANY, X86_MODEL_ANY, }, +#endif +#ifdef CONFIG_MICROCODE_AMD + { X86_VENDOR_AMD, X86_FAMILY_ANY, X86_MODEL_ANY, }, +#endif + {} +}; +MODULE_DEVICE_TABLE(x86cpu, microcode_id); +#endif + static int __init microcode_init(void) { struct cpuinfo_x86 *c = &cpu_data(0); |