Commit d4ef467a authored by Arnd Bergmann's avatar Arnd Bergmann

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: default avatarArnd Bergmann <arnd@arndb.de>
parents 4acf1823 71de5c46
What: /sys/devices/socX
Date: January 2012
contact: Lee Jones <lee.jones@linaro.org>
Description:
The /sys/devices/ directory contains a sub-directory for each
System-on-Chip (SoC) device on a running platform. Information
regarding each SoC can be obtained by reading sysfs files. This
functionality is only available if implemented by the platform.
The directory created for each SoC will also house information
about devices which are commonly contained in /sys/devices/platform.
It has been agreed that if an SoC device exists, its supported
devices would be better suited to appear as children of that SoC.
What: /sys/devices/socX/machine
Date: January 2012
contact: Lee Jones <lee.jones@linaro.org>
Description:
Read-only attribute common to all SoCs. Contains the SoC machine
name (e.g. Ux500).
What: /sys/devices/socX/family
Date: January 2012
contact: Lee Jones <lee.jones@linaro.org>
Description:
Read-only attribute common to all SoCs. Contains SoC family name
(e.g. DB8500).
What: /sys/devices/socX/soc_id
Date: January 2012
contact: Lee Jones <lee.jones@linaro.org>
Description:
Read-only attribute supported by most SoCs. In the case of
ST-Ericsson's chips this contains the SoC serial number.
What: /sys/devices/socX/revision
Date: January 2012
contact: Lee Jones <lee.jones@linaro.org>
Description:
Read-only attribute supported by most SoCs. Contains the SoC's
manufacturing revision number.
What: /sys/devices/socX/process
Date: January 2012
contact: Lee Jones <lee.jones@linaro.org>
Description:
Read-only attribute supported ST-Ericsson's silicon. Contains the
the process by which the silicon chip was manufactured.
What: /sys/bus/soc
Date: January 2012
contact: Lee Jones <lee.jones@linaro.org>
Description:
The /sys/bus/soc/ directory contains the usual sub-folders
expected under most buses. /sys/bus/soc/devices is of particular
interest, as it contains a symlink for each SoC device found on
the system. Each symlink points back into the aforementioned
/sys/devices/socX devices.
* ARM Timer Watchdog
ARM 11MP, Cortex-A5 and Cortex-A9 are often associated with a per-core
Timer-Watchdog (aka TWD), which provides both a per-cpu local timer
and watchdog.
The TWD is usually attached to a GIC to deliver its two per-processor
interrupts.
** Timer node required properties:
- compatible : Should be one of:
"arm,cortex-a9-twd-timer"
"arm,cortex-a5-twd-timer"
"arm,arm11mp-twd-timer"
- interrupts : One interrupt to each core
- reg : Specify the base address and the size of the TWD timer
register window.
Example:
twd-timer@2c000600 {
compatible = "arm,arm11mp-twd-timer"";
reg = <0x2c000600 0x20>;
interrupts = <1 13 0xf01>;
};
** Watchdog node properties:
- compatible : Should be one of:
"arm,cortex-a9-twd-wdt"
"arm,cortex-a5-twd-wdt"
"arm,arm11mp-twd-wdt"
- interrupts : One interrupt to each core
- reg : Specify the base address and the size of the TWD watchdog
register window.
Example:
twd-watchdog@2c000620 {
compatible = "arm,arm11mp-twd-wdt";
reg = <0x2c000620 0x20>;
interrupts = <1 14 0xf01>;
};
......@@ -12,7 +12,7 @@ dynamically enabled per-callsite.
Dynamic debug has even more useful features:
* Simple query language allows turning on and off debugging statements by
matching any combination of:
matching any combination of 0 or 1 of:
- source filename
- function name
......@@ -79,31 +79,24 @@ Command Language Reference
==========================
At the lexical level, a command comprises a sequence of words separated
by whitespace characters. Note that newlines are treated as word
separators and do *not* end a command or allow multiple commands to
be done together. So these are all equivalent:
by spaces or tabs. So these are all equivalent:
nullarbor:~ # echo -c 'file svcsock.c line 1603 +p' >
<debugfs>/dynamic_debug/control
nullarbor:~ # echo -c ' file svcsock.c line 1603 +p ' >
<debugfs>/dynamic_debug/control
nullarbor:~ # echo -c 'file svcsock.c\nline 1603 +p' >
<debugfs>/dynamic_debug/control
nullarbor:~ # echo -n 'file svcsock.c line 1603 +p' >
<debugfs>/dynamic_debug/control
Commands are bounded by a write() system call. If you want to do
multiple commands you need to do a separate "echo" for each, like:
Command submissions are bounded by a write() system call.
Multiple commands can be written together, separated by ';' or '\n'.
nullarbor:~ # echo 'file svcsock.c line 1603 +p' > /proc/dprintk ;\
> echo 'file svcsock.c line 1563 +p' > /proc/dprintk
~# echo "func pnpacpi_get_resources +p; func pnp_assign_mem +p" \
> <debugfs>/dynamic_debug/control
or even like:
If your query set is big, you can batch them too:
nullarbor:~ # (
> echo 'file svcsock.c line 1603 +p' ;\
> echo 'file svcsock.c line 1563 +p' ;\
> ) > /proc/dprintk
~# cat query-batch-file > <debugfs>/dynamic_debug/control
At the syntactical level, a command comprises a sequence of match
specifications, followed by a flags change specification.
......@@ -144,11 +137,12 @@ func
func svc_tcp_accept
file
The given string is compared against either the full
pathname or the basename of the source file of each
callsite. Examples:
The given string is compared against either the full pathname, the
src-root relative pathname, or the basename of the source file of
each callsite. Examples:
file svcsock.c
file kernel/freezer.c
file /usr/src/packages/BUILD/sgi-enhancednfs-1.4/default/net/sunrpc/svcsock.c
module
......
......@@ -14,7 +14,10 @@ Debugfs is typically mounted with a command like:
mount -t debugfs none /sys/kernel/debug
(Or an equivalent /etc/fstab line).
(Or an equivalent /etc/fstab line).
The debugfs root directory is accessible by anyone by default. To
restrict access to the tree the "uid", "gid" and "mode" mount
options can be used.
Note that the debugfs API is exported GPL-only to modules.
......
/*
* 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";
};
};
};
......@@ -72,15 +72,15 @@ soc {
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 {
......
......@@ -88,9 +88,9 @@ soc {
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 {
......
/*
* 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>;
};
};
};
};
......@@ -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
......
......@@ -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
......@@ -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
......@@ -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
......
......@@ -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
......@@ -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 */
}
......
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
......@@ -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 = {
......
/*
* 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;
}
......@@ -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)
......
/*
* 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;
}
......@@ -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 = {
......
......@@ -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 @@ static void __init msm_timer_init(void)
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
};
......@@ -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 = {
......
/*
* 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 */
......@@ -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
......
/*
* 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;
}
......@@ -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
......
......@@ -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 = {
......
......@@ -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 = {
......
......@@ -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 = {
......
......@@ -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
......
......@@ -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);
......
/*
* 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;
}
......@@ -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>
......
......@@ -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);
}
......
......@@ -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);
}
......
......@@ -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,
};
......@@ -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
......
/*
* 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;
}
......@@ -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 = {
......
......@@ -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
......
......@@ -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
......@@ -2,3 +2,4 @@
params_phys-y := 0x00000100
initrd_phys-y := 0x00800000
dtb-$(CONFIG_MACH_SNOWBALL) += snowball.dtb
......@@ -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);
}
......@@ -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
......@@ -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);
......
......@@ -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);
}
......@@ -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));
......
......@@ -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
......
......@@ -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;
}
......@@ -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;
}
......@@ -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;
}
......@@ -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);
}
}
......@@ -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
......@@ -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
......@@ -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
......@@ -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);
......
......@@ -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
......@@ -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);
......
......@@ -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
/*
* 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;
}
......@@ -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)
......
......@@ -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);
}
......@@ -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)
......
#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);
......
......@@ -20,12 +20,6 @@
#include <asm/mach/time.h>
#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);
}
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
......
/*
* 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;
}
......@@ -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
......
......@@ -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;
......
......@@ -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)
......
......@@ -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)
......
#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
......@@ -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 */
......
......@@ -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
......
#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;
}
......@@ -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 },
......
......@@ -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);
......
......@@ -474,6 +474,7 @@ static __ref int acpi_processor_start(struct acpi_processor *pr)
#ifdef CONFIG_CPU_FREQ
acpi_processor_ppc_has_changed(pr, 0);
acpi_processor_load_module(pr);
#endif
acpi_processor_get_throttling_info(pr);
acpi_processor_get_limit_info(pr);
......
......@@ -240,6 +240,28 @@ void acpi_processor_ppc_exit(void)
acpi_processor_ppc_status &= ~PPC_REGISTERED;
}
/*
* Do a quick check if the systems looks like it should use ACPI
* cpufreq. We look at a _PCT method being available, but don't
* do a whole lot of sanity checks.
*/
void acpi_processor_load_module(struct acpi_processor *pr)
{
static int requested;
acpi_status status = 0;
struct acpi_buffer buffer = { ACPI_ALLOCATE_BUFFER, NULL };
if (!arch_has_acpi_pdc() || requested)
return;
status = acpi_evaluate_object(pr->handle, "_PCT", NULL, &buffer);
if (!ACPI_FAILURE(status)) {
printk(KERN_INFO PREFIX "Requesting acpi_cpufreq\n");
request_module_nowait("acpi_cpufreq");
requested = 1;
}
kfree(buffer.pointer);
}
static int acpi_processor_get_performance_control(struct acpi_processor *pr)
{
int result = 0;
......
......@@ -176,6 +176,9 @@ config GENERIC_CPU_DEVICES
bool
default n
config SOC_BUS
bool
source "drivers/base/regmap/Kconfig"
config DMA_SHARED_BUFFER
......
......@@ -19,6 +19,7 @@ obj-$(CONFIG_MODULES) += module.o
endif
obj-$(CONFIG_SYS_HYPERVISOR) += hypervisor.o
obj-$(CONFIG_REGMAP) += regmap/
obj-$(CONFIG_SOC_BUS) += soc.o
ccflags-$(CONFIG_DEBUG_DRIVER) := -DDEBUG
......@@ -1194,13 +1194,15 @@ EXPORT_SYMBOL_GPL(subsys_interface_register);
void subsys_interface_unregister(struct subsys_interface *sif)
{
struct bus_type *subsys = sif->subsys;
struct bus_type *subsys;
struct subsys_dev_iter iter;
struct device *dev;
if (!sif)
if (!sif || !sif->subsys)
return;
subsys = sif->subsys;
mutex_lock(&subsys->p->mutex);
list_del_init(&sif->node);
if (sif->remove_dev) {
......
......@@ -11,6 +11,7 @@
#include <linux/device.h>
#include <linux/node.h>
#include <linux/gfp.h>
#include <linux/slab.h>
#include <linux/percpu.h>
#include "base.h"
......@@ -244,6 +245,9 @@ int __cpuinit register_cpu(struct cpu *cpu, int num)
cpu->dev.id = num;
cpu->dev.bus = &cpu_subsys;
cpu->dev.release = cpu_device_release;
#ifdef CONFIG_ARCH_HAS_CPU_AUTOPROBE
cpu->dev.bus->uevent = arch_cpu_uevent;
#endif
error = device_register(&cpu->dev);
if (!error && cpu->hotpluggable)
register_cpu_control(cpu);
......@@ -268,6 +272,10 @@ struct device *get_cpu_device(unsigned cpu)
}
EXPORT_SYMBOL_GPL(get_cpu_device);
#ifdef CONFIG_ARCH_HAS_CPU_AUTOPROBE
static DEVICE_ATTR(modalias, 0444, arch_print_cpu_modalias, NULL);
#endif
static struct attribute *cpu_root_attrs[] = {
#ifdef CONFIG_ARCH_CPU_PROBE_RELEASE
&dev_attr_probe.attr,
......@@ -278,6 +286,9 @@ static struct attribute *cpu_root_attrs[] = {
&cpu_attrs[2].attr.attr,
&dev_attr_kernel_max.attr,
&dev_attr_offline.attr,
#ifdef CONFIG_ARCH_HAS_CPU_AUTOPROBE
&dev_attr_modalias.attr,
#endif
NULL
};
......
......@@ -153,34 +153,6 @@ int driver_add_kobj(struct device_driver *drv, struct kobject *kobj,
}
EXPORT_SYMBOL_GPL(driver_add_kobj);
/**
* get_driver - increment driver reference count.
* @drv: driver.
*/
struct device_driver *get_driver(struct device_driver *drv)
{
if (drv) {
struct driver_private *priv;
struct kobject *kobj;
kobj = kobject_get(&drv->p->kobj);
priv = to_driver(kobj);
return priv->driver;
}
return NULL;
}
EXPORT_SYMBOL_GPL(get_driver);
/**
* put_driver - decrement driver's refcount.
* @drv: driver.
*/
void put_driver(struct device_driver *drv)
{
kobject_put(&drv->p->kobj);
}
EXPORT_SYMBOL_GPL(put_driver);
static int driver_add_groups(struct device_driver *drv,
const struct attribute_group **groups)
{
......@@ -234,7 +206,6 @@ int driver_register(struct device_driver *drv)
other = driver_find(drv->name, drv->bus);
if (other) {
put_driver(other);
printk(KERN_ERR "Error: Driver '%s' is already registered, "
"aborting...\n", drv->name);
return -EBUSY;
......@@ -275,7 +246,9 @@ EXPORT_SYMBOL_GPL(driver_unregister);
* Call kset_find_obj() to iterate over list of drivers on
* a bus to find driver by name. Return driver if found.
*
* Note that kset_find_obj increments driver's reference count.
* This routine provides no locking to prevent the driver it returns
* from being unregistered or unloaded while the caller is using it.
* The caller is responsible for preventing this.
*/
struct device_driver *driver_find(const char *name, struct bus_type *bus)
{
......@@ -283,6 +256,8 @@ struct device_driver *driver_find(const char *name, struct bus_type *bus)
struct driver_private *priv;
if (k) {
/* Drop reference added by kset_find_obj() */
kobject_put(k);
priv = to_driver(k);
return priv->driver;
}
......
/*
* Copyright (C) ST-Ericsson SA 2011
*
* Author: Lee Jones <lee.jones@linaro.org> for ST-Ericsson.
* License terms: GNU General Public License (GPL), version 2
*/
#include <linux/sysfs.h>
#include <linux/module.h>
#include <linux/init.h>
#include <linux/stat.h>
#include <linux/slab.h>
#include <linux/idr.h>
#include <linux/spinlock.h>
#include <linux/sys_soc.h>
#include <linux/err.h>
static DEFINE_IDR(soc_ida);
static DEFINE_SPINLOCK(soc_lock);
static ssize_t soc_info_get(struct device *dev,
struct device_attribute *attr,
char *buf);
struct soc_device {
struct device dev;
struct soc_device_attribute *attr;
int soc_dev_num;
};
static struct bus_type soc_bus_type = {
.name = "soc",
};
static DEVICE_ATTR(machine, S_IRUGO, soc_info_get, NULL);
static DEVICE_ATTR(family, S_IRUGO, soc_info_get, NULL);
static DEVICE_ATTR(soc_id, S_IRUGO, soc_info_get, NULL);
static DEVICE_ATTR(revision, S_IRUGO, soc_info_get, NULL);
struct device *soc_device_to_device(struct soc_device *soc_dev)
{
return &soc_dev->dev;
}
static mode_t soc_attribute_mode(struct kobject *kobj,
struct attribute *attr,
int index)
{
struct device *dev = container_of(kobj, struct device, kobj);
struct soc_device *soc_dev = container_of(dev, struct soc_device, dev);
if ((attr == &dev_attr_machine.attr)
&& (soc_dev->attr->machine != NULL))
return attr->mode;
if ((attr == &dev_attr_family.attr)
&& (soc_dev->attr->family != NULL))
return attr->mode;
if ((attr == &dev_attr_revision.attr)
&& (soc_dev->attr->revision != NULL))
return attr->mode;
if ((attr == &dev_attr_soc_id.attr)
&& (soc_dev->attr->soc_id != NULL))
return attr->mode;
/* Unknown or unfilled attribute. */
return 0;
}
static ssize_t soc_info_get(struct device *dev,
struct device_attribute *attr,
char *buf)
{
struct soc_device *soc_dev = container_of(dev, struct soc_device, dev);
if (attr == &dev_attr_machine)
return sprintf(buf, "%s\n", soc_dev->attr->machine);
if (attr == &dev_attr_family)
return sprintf(buf, "%s\n", soc_dev->attr->family);
if (attr == &dev_attr_revision)
return sprintf(buf, "%s\n", soc_dev->attr->revision);
if (attr == &dev_attr_soc_id)
return sprintf(buf, "%s\n", soc_dev->attr->soc_id);
return -EINVAL;
}
static struct attribute *soc_attr[] = {
&dev_attr_machine.attr,
&dev_attr_family.attr,
&dev_attr_soc_id.attr,
&dev_attr_revision.attr,
NULL,
};
static const struct attribute_group soc_attr_group = {
.attrs = soc_attr,
.is_visible = soc_attribute_mode,
};
static const struct attribute_group *soc_attr_groups[] = {
&soc_attr_group,
NULL,
};
static void soc_release(struct device *dev)
{
struct soc_device *soc_dev = container_of(dev, struct soc_device, dev);
kfree(soc_dev);
}
struct soc_device *soc_device_register(struct soc_device_attribute *soc_dev_attr)
{
struct soc_device *soc_dev;
int ret;
soc_dev = kzalloc(sizeof(*soc_dev), GFP_KERNEL);
if (!soc_dev) {
ret = -ENOMEM;
goto out1;
}
/* Fetch a unique (reclaimable) SOC ID. */
do {
if (!ida_pre_get(&soc_ida, GFP_KERNEL)) {
ret = -ENOMEM;
goto out2;
}
spin_lock(&soc_lock);
ret = ida_get_new(&soc_ida, &soc_dev->soc_dev_num);
spin_unlock(&soc_lock);
} while (ret == -EAGAIN);
if (ret)
goto out2;
soc_dev->attr = soc_dev_attr;
soc_dev->dev.bus = &soc_bus_type;
soc_dev->dev.groups = soc_attr_groups;
soc_dev->dev.release = soc_release;
dev_set_name(&soc_dev->dev, "soc%d", soc_dev->soc_dev_num);
ret = device_register(&soc_dev->dev);
if (ret)
goto out3;
return soc_dev;
out3:
ida_remove(&soc_ida, soc_dev->soc_dev_num);
out2:
kfree(soc_dev);
out1:
return ERR_PTR(ret);
}
/* Ensure soc_dev->attr is freed prior to calling soc_device_unregister. */
void soc_device_unregister(struct soc_device *soc_dev)
{
ida_remove(&soc_ida, soc_dev->soc_dev_num);
device_unregister(&soc_dev->dev);
}
static int __init soc_bus_register(void)
{
spin_lock_init(&soc_lock);
return bus_register(&soc_bus_type);
}
core_initcall(soc_bus_register);
static void __exit soc_bus_unregister(void)
{
ida_destroy(&soc_ida);
bus_unregister(&soc_bus_type);
}
module_exit(soc_bus_unregister);
......@@ -385,6 +385,14 @@ static struct cpufreq_driver nforce2_driver = {
.owner = THIS_MODULE,
};
#ifdef MODULE
static DEFINE_PCI_DEVICE_TABLE(nforce2_ids) = {
{ PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_NFORCE2 },
{}
};
MODULE_DEVICE_TABLE(pci, nforce2_ids);
#endif
/**
* nforce2_detect_chipset - detect the Southbridge which contains FSB PLL logic
*
......
......@@ -16,6 +16,7 @@
#include <linux/io.h>
#include <linux/delay.h>
#include <asm/cpu_device_id.h>
#include <asm/msr.h>
#include <asm/tsc.h>
......@@ -437,18 +438,19 @@ static struct cpufreq_driver eps_driver = {
.attr = eps_attr,
};
/* This driver will work only on Centaur C7 processors with
* Enhanced SpeedStep/PowerSaver registers */
static const struct x86_cpu_id eps_cpu_id[] = {
{ X86_VENDOR_CENTAUR, 6, X86_MODEL_ANY, X86_FEATURE_EST },
{}
};
MODULE_DEVICE_TABLE(x86cpu, eps_cpu_id);
static int __init eps_init(void)
{
struct cpuinfo_x86 *c = &cpu_data(0);
/* This driver will work only on Centaur C7 processors with
* Enhanced SpeedStep/PowerSaver registers */
if (c->x86_vendor != X86_VENDOR_CENTAUR
|| c->x86 != 6 || c->x86_model < 10)
return -ENODEV;
if (!cpu_has(c, X86_FEATURE_EST))
if (!x86_match_cpu(eps_cpu_id) || boot_cpu_data.x86_model < 10)
return -ENODEV;
if (cpufreq_register_driver(&eps_driver))
return -EINVAL;
return 0;
......
......@@ -23,6 +23,7 @@
#include <linux/delay.h>
#include <linux/cpufreq.h>
#include <asm/cpu_device_id.h>
#include <asm/msr.h>
#include <linux/timex.h>
#include <linux/io.h>
......@@ -277,17 +278,16 @@ static struct cpufreq_driver elanfreq_driver = {
.attr = elanfreq_attr,
};
static const struct x86_cpu_id elan_id[] = {
{ X86_VENDOR_AMD, 4, 10, },
{}
};
MODULE_DEVICE_TABLE(x86cpu, elan_id);
static int __init elanfreq_init(void)
{
struct cpuinfo_x86 *c = &cpu_data(0);
/* Test if we have the right hardware */
if ((c->x86_vendor != X86_VENDOR_AMD) ||
(c->x86 != 4) || (c->x86_model != 10)) {
printk(KERN_INFO "elanfreq: error: no Elan processor found!\n");
if (!x86_match_cpu(elan_id))
return -ENODEV;
}
return cpufreq_register_driver(&elanfreq_driver);
}
......
......@@ -82,6 +82,7 @@
#include <linux/errno.h>
#include <linux/slab.h>
#include <asm/cpu_device_id.h>
#include <asm/processor-cyrix.h>
/* PCI config registers, all at F0 */
......@@ -171,6 +172,7 @@ static struct pci_device_id gx_chipset_tbl[] __initdata = {
{ PCI_VDEVICE(CYRIX, PCI_DEVICE_ID_CYRIX_5510), },
{ 0, },
};
MODULE_DEVICE_TABLE(pci, gx_chipset_tbl);
static void gx_write_byte(int reg, int value)
{
......@@ -185,13 +187,6 @@ static __init struct pci_dev *gx_detect_chipset(void)
{
struct pci_dev *gx_pci = NULL;
/* check if CPU is a MediaGX or a Geode. */
if ((boot_cpu_data.x86_vendor != X86_VENDOR_NSC) &&
(boot_cpu_data.x86_vendor != X86_VENDOR_CYRIX)) {
pr_debug("error: no MediaGX/Geode processor found!\n");
return NULL;
}
/* detect which companion chip is used */
for_each_pci_dev(gx_pci) {
if ((pci_match_id(gx_chipset_tbl, gx_pci)) != NULL)
......
......@@ -35,6 +35,7 @@
#include <linux/acpi.h>
#include <asm/msr.h>
#include <asm/cpu_device_id.h>
#include <acpi/processor.h>
#include "longhaul.h"
......@@ -951,12 +952,17 @@ static struct cpufreq_driver longhaul_driver = {
.attr = longhaul_attr,
};
static const struct x86_cpu_id longhaul_id[] = {
{ X86_VENDOR_CENTAUR, 6 },
{}
};
MODULE_DEVICE_TABLE(x86cpu, longhaul_id);
static int __init longhaul_init(void)
{
struct cpuinfo_x86 *c = &cpu_data(0);
if (c->x86_vendor != X86_VENDOR_CENTAUR || c->x86 != 6)
if (!x86_match_cpu(longhaul_id))
return -ENODEV;
#ifdef CONFIG_SMP
......
......@@ -14,6 +14,7 @@
#include <asm/msr.h>
#include <asm/processor.h>
#include <asm/cpu_device_id.h>
static struct cpufreq_driver longrun_driver;
......@@ -288,6 +289,12 @@ static struct cpufreq_driver longrun_driver = {
.owner = THIS_MODULE,
};
static const struct x86_cpu_id longrun_ids[] = {
{ X86_VENDOR_TRANSMETA, X86_FAMILY_ANY, X86_MODEL_ANY,
X86_FEATURE_LONGRUN },
{}
};
MODULE_DEVICE_TABLE(x86cpu, longrun_ids);
/**
* longrun_init - initializes the Transmeta Crusoe LongRun CPUFreq driver
......@@ -296,12 +303,8 @@ static struct cpufreq_driver longrun_driver = {
*/
static int __init longrun_init(void)
{
struct cpuinfo_x86 *c = &cpu_data(0);
if (c->x86_vendor != X86_VENDOR_TRANSMETA ||
!cpu_has(c, X86_FEATURE_LONGRUN))
if (!x86_match_cpu(longrun_ids))
return -ENODEV;
return cpufreq_register_driver(&longrun_driver);
}
......
......@@ -31,6 +31,7 @@
#include <asm/processor.h>
#include <asm/msr.h>
#include <asm/timer.h>
#include <asm/cpu_device_id.h>
#include "speedstep-lib.h"
......@@ -289,21 +290,25 @@ static struct cpufreq_driver p4clockmod_driver = {
.attr = p4clockmod_attr,
};
static const struct x86_cpu_id cpufreq_p4_id[] = {
{ X86_VENDOR_INTEL, X86_FAMILY_ANY, X86_MODEL_ANY, X86_FEATURE_ACC },
{}
};
/*
* Intentionally no MODULE_DEVICE_TABLE here: this driver should not
* be auto loaded. Please don't add one.
*/
static int __init cpufreq_p4_init(void)
{
struct cpuinfo_x86 *c = &cpu_data(0);
int ret;
/*
* THERM_CONTROL is architectural for IA32 now, so
* we can rely on the capability checks
*/
if (c->x86_vendor != X86_VENDOR_INTEL)
return -ENODEV;
if (!test_cpu_cap(c, X86_FEATURE_ACPI) ||
!test_cpu_cap(c, X86_FEATURE_ACC))
if (!x86_match_cpu(cpufreq_p4_id) || !boot_cpu_has(X86_FEATURE_ACPI))
return -ENODEV;
ret = cpufreq_register_driver(&p4clockmod_driver);
......
......@@ -16,6 +16,7 @@
#include <linux/timex.h>
#include <linux/io.h>
#include <asm/cpu_device_id.h>
#include <asm/msr.h>
#define POWERNOW_IOPORT 0xfff0 /* it doesn't matter where, as long
......@@ -210,6 +211,12 @@ static struct cpufreq_driver powernow_k6_driver = {
.attr = powernow_k6_attr,
};
static const struct x86_cpu_id powernow_k6_ids[] = {
{ X86_VENDOR_AMD, 5, 12 },
{ X86_VENDOR_AMD, 5, 13 },
{}
};
/**
* powernow_k6_init - initializes the k6 PowerNow! CPUFreq driver
......@@ -220,10 +227,7 @@ static struct cpufreq_driver powernow_k6_driver = {
*/
static int __init powernow_k6_init(void)
{
struct cpuinfo_x86 *c = &cpu_data(0);
if ((c->x86_vendor != X86_VENDOR_AMD) || (c->x86 != 5) ||
((c->x86_model != 12) && (c->x86_model != 13)))
if (!x86_match_cpu(powernow_k6_ids))
return -ENODEV;
if (!request_region(POWERNOW_IOPORT, 16, "PowerNow!")) {
......
......@@ -28,6 +28,7 @@
#include <asm/timer.h> /* Needed for recalibrate_cpu_khz() */
#include <asm/msr.h>
#include <asm/system.h>
#include <asm/cpu_device_id.h>
#ifdef CONFIG_X86_POWERNOW_K7_ACPI
#include <linux/acpi.h>
......@@ -110,18 +111,19 @@ static int check_fsb(unsigned int fsbspeed)
return delta < 5;
}
static const struct x86_cpu_id powernow_k7_cpuids[] = {
{ X86_VENDOR_AMD, 7, },
{}
};
MODULE_DEVICE_TABLE(x86cpu, powernow_k7_cpuids);
static int check_powernow(void)
{
struct cpuinfo_x86 *c = &cpu_data(0);
unsigned int maxei, eax, ebx, ecx, edx;
if ((c->x86_vendor != X86_VENDOR_AMD) || (c->x86 != 6)) {
#ifdef MODULE
printk(KERN_INFO PFX "This module only works with "
"AMD K7 CPUs\n");
#endif
if (!x86_match_cpu(powernow_k7_cpuids))
return 0;
}
/* Get maximum capabilities */
maxei = cpuid_eax(0x80000000);
......
......@@ -40,6 +40,7 @@
#include <linux/delay.h>
#include <asm/msr.h>
#include <asm/cpu_device_id.h>
#include <linux/acpi.h>
#include <linux/mutex.h>
......@@ -520,6 +521,15 @@ static int core_voltage_post_transition(struct powernow_k8_data *data,
return 0;
}
static const struct x86_cpu_id powernow_k8_ids[] = {
/* IO based frequency switching */
{ X86_VENDOR_AMD, 0xf },
/* MSR based frequency switching supported */
X86_FEATURE_MATCH(X86_FEATURE_HW_PSTATE),
{}
};
MODULE_DEVICE_TABLE(x86cpu, powernow_k8_ids);
static void check_supported_cpu(void *_rc)
{
u32 eax, ebx, ecx, edx;
......@@ -527,13 +537,7 @@ static void check_supported_cpu(void *_rc)
*rc = -ENODEV;
if (__this_cpu_read(cpu_info.x86_vendor) != X86_VENDOR_AMD)
return;
eax = cpuid_eax(CPUID_PROCESSOR_SIGNATURE);
if (((eax & CPUID_XFAM) != CPUID_XFAM_K8) &&
((eax & CPUID_XFAM) < CPUID_XFAM_10H))
return;
if ((eax & CPUID_XFAM) == CPUID_XFAM_K8) {
if (((eax & CPUID_USE_XFAM_XMOD) != CPUID_USE_XFAM_XMOD) ||
......@@ -1553,6 +1557,9 @@ static int __cpuinit powernowk8_init(void)
unsigned int i, supported_cpus = 0, cpu;
int rv;
if (!x86_match_cpu(powernow_k8_ids))
return -ENODEV;
for_each_online_cpu(i) {
int rc;
smp_call_function_single(i, check_supported_cpu, &rc, 1);
......
......@@ -22,6 +22,7 @@
#include <linux/timex.h>
#include <linux/io.h>
#include <asm/cpu_device_id.h>
#include <asm/msr.h>
#define MMCR_BASE 0xfffef000 /* The default base address */
......@@ -150,18 +151,19 @@ static struct cpufreq_driver sc520_freq_driver = {
.attr = sc520_freq_attr,
};
static const struct x86_cpu_id sc520_ids[] = {
{ X86_VENDOR_AMD, 4, 9 },
{}
};
MODULE_DEVICE_TABLE(x86cpu, sc520_ids);
static int __init sc520_freq_init(void)
{
struct cpuinfo_x86 *c = &cpu_data(0);
int err;
/* Test if we have the right hardware */
if (c->x86_vendor != X86_VENDOR_AMD ||
c->x86 != 4 || c->x86_model != 9) {
pr_debug("no Elan SC520 processor found!\n");
if (!x86_match_cpu(sc520_ids))
return -ENODEV;
}
cpuctl = ioremap((unsigned long)(MMCR_BASE + OFFS_CPUCTL), 1);
if (!cpuctl) {
printk(KERN_ERR "sc520_freq: error: failed to remap memory\n");
......
......@@ -25,6 +25,7 @@
#include <asm/msr.h>
#include <asm/processor.h>
#include <asm/cpufeature.h>
#include <asm/cpu_device_id.h>
#define PFX "speedstep-centrino: "
#define MAINTAINER "cpufreq@vger.kernel.org"
......@@ -595,6 +596,24 @@ static struct cpufreq_driver centrino_driver = {
.owner = THIS_MODULE,
};
/*
* This doesn't replace the detailed checks above because
* the generic CPU IDs don't have a way to match for steppings
* or ASCII model IDs.
*/
static const struct x86_cpu_id centrino_ids[] = {
{ X86_VENDOR_INTEL, 6, 9, X86_FEATURE_EST },
{ X86_VENDOR_INTEL, 6, 13, X86_FEATURE_EST },
{ X86_VENDOR_INTEL, 6, 13, X86_FEATURE_EST },
{ X86_VENDOR_INTEL, 6, 13, X86_FEATURE_EST },
{ X86_VENDOR_INTEL, 15, 3, X86_FEATURE_EST },
{ X86_VENDOR_INTEL, 15, 4, X86_FEATURE_EST },
{}
};
#if 0
/* Autoload or not? Do not for now. */
MODULE_DEVICE_TABLE(x86cpu, centrino_ids);
#endif
/**
* centrino_init - initializes the Enhanced SpeedStep CPUFreq driver
......@@ -612,11 +631,8 @@ static struct cpufreq_driver centrino_driver = {
*/
static int __init centrino_init(void)
{
struct cpuinfo_x86 *cpu = &cpu_data(0);
if (!cpu_has(cpu, X86_FEATURE_EST))
if (!x86_match_cpu(centrino_ids))
return -ENODEV;
return cpufreq_register_driver(&centrino_driver);
}
......
......@@ -25,6 +25,8 @@
#include <linux/pci.h>
#include <linux/sched.h>
#include <asm/cpu_device_id.h>
#include "speedstep-lib.h"
......@@ -388,6 +390,16 @@ static struct cpufreq_driver speedstep_driver = {
.attr = speedstep_attr,
};
static const struct x86_cpu_id ss_smi_ids[] = {
{ X86_VENDOR_INTEL, 6, 0xb, },
{ X86_VENDOR_INTEL, 6, 0x8, },
{ X86_VENDOR_INTEL, 15, 2 },
{}
};
#if 0
/* Autoload or not? Do not for now. */
MODULE_DEVICE_TABLE(x86cpu, ss_smi_ids);
#endif
/**
* speedstep_init - initializes the SpeedStep CPUFreq driver
......@@ -398,6 +410,9 @@ static struct cpufreq_driver speedstep_driver = {
*/
static int __init speedstep_init(void)
{
if (!x86_match_cpu(ss_smi_ids))
return -ENODEV;
/* detect processor */
speedstep_processor = speedstep_detect_processor();
if (!speedstep_processor) {
......
......@@ -249,6 +249,7 @@ EXPORT_SYMBOL_GPL(speedstep_get_frequency);
* DETECT SPEEDSTEP-CAPABLE PROCESSOR *
*********************************************************************/
/* Keep in sync with the x86_cpu_id tables in the different modules */
unsigned int speedstep_detect_processor(void)
{
struct cpuinfo_x86 *c = &cpu_data(0);
......
......@@ -20,6 +20,7 @@
#include <linux/delay.h>
#include <linux/io.h>
#include <asm/ist.h>
#include <asm/cpu_device_id.h>
#include "speedstep-lib.h"
......@@ -379,6 +380,17 @@ static struct cpufreq_driver speedstep_driver = {
.attr = speedstep_attr,
};
static const struct x86_cpu_id ss_smi_ids[] = {
{ X86_VENDOR_INTEL, 6, 0xb, },
{ X86_VENDOR_INTEL, 6, 0x8, },
{ X86_VENDOR_INTEL, 15, 2 },
{}
};
#if 0
/* Not auto loaded currently */
MODULE_DEVICE_TABLE(x86cpu, ss_smi_ids);
#endif
/**
* speedstep_init - initializes the SpeedStep CPUFreq driver
*
......@@ -388,6 +400,9 @@ static struct cpufreq_driver speedstep_driver = {
*/
static int __init speedstep_init(void)
{
if (!x86_match_cpu(ss_smi_ids))
return -ENODEV;
speedstep_processor = speedstep_detect_processor();
switch (speedstep_processor) {
......
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment