Integrator updates for the v3.19 merge cycle on
top of the multiplatform patches, this moves out some drivers and reduced the amount of code carried in arch/arm/mach-integrator. - Move the Integrator/AP timer to drivers/clocksource - Move the restart functionality to the device tree, patches to enable restart for the Integrator have been merged to the reset tree (orthogonal) - Move debug LEDs to device tree (using the syscon LED driver merged for v3.18) - Move core module LEDs to device tree (using the syscon LED driver merged for v3.18) - Move the SoC driver (chip ID etc) to drivers/soc/versatile/soc-integrator.c -----BEGIN PGP SIGNATURE----- Version: GnuPG v1 iQIcBAABAgAGBQJUavcgAAoJEEEQszewGV1zxHgP/3i1LxdQ+B1ztOpZRZ+Bi4iQ 5KU9j93eMMTlZ3nASvRBIx4MgnUVItuUQ5idnmATCDfoP2lhj/JWPw7G5vyEvRoj 2yuTB9IoutGoTPm58UeglPPedwcv2Lc9p7Boz/cnZVc4KfLldU66yoIV+s1vlijN OAhgOyShIjLUv5ikwNPRAjEXw7fJZc6ixhTt/EJrPbiMhjkXMKJs/SXovzhOw25a UVmMu36rwnVyQllfoS4yd+wpHa+Jg6ZhxH3nIveQpEVt8MOukOPiYa5ePmglXpkF B0u0vaACrZfiPCeQL3RD4LN8Z9QLR9Mt1VDbFkWnTRTKdNA034dhIoD0ZxsoGepb cV9QfA1n1Q6hKUqg59PfZv4MKwPXA1TmF5J3ZBNL1xK+bsRBHZmBq1dKg4rww1bu tyxJfg3LmUCQe5PkcT7HZJFv1yXnEXduXUX0TYclPhp+GnAyudwNkw4/7mmz2gPT XEhd64xjB+yVyzN8zu34KIrsDvv/Z7CyKzYAsaR+yY4DbUuh2p2sNupCnci4Hs/k PO09w76mxRulFBVw5ZuLBzevPpa3hasny05bqnku6/VTp1RfOM+5i60B/gGnIWFo KLxaDcvbyuP+nAdQIl+/X8Zv0tQ0KAqlZFvgroxCeUtF5JwXlbdYbbVEO0FVmMB/ TjfE+8xCchI2cZPci9J2 =rplU -----END PGP SIGNATURE----- Merge tag 'integrator-v3.19-arm-soc-2' of git://git.kernel.org/pub/scm/linux/kernel/git/linusw/linux-integrator into next/soc Pull "ARM SoC Integrator updates for v3.19" from Linus Walleij: Integrator updates for the v3.19 merge cycle on top of the multiplatform patches, this moves out some drivers and reduced the amount of code carried in arch/arm/mach-integrator. - Move the Integrator/AP timer to drivers/clocksource - Move the restart functionality to the device tree, patches to enable restart for the Integrator have been merged to the reset tree (orthogonal) - Move debug LEDs to device tree (using the syscon LED driver merged for v3.18) - Move core module LEDs to device tree (using the syscon LED driver merged for v3.18) - Move the SoC driver (chip ID etc) to drivers/soc/versatile/soc-integrator.c * tag 'integrator-v3.19-arm-soc-2' of git://git.kernel.org/pub/scm/linux/kernel/git/linusw/linux-integrator: soc: move SoC driver for the ARM Integrator ARM: integrator: move core module LED to device tree ARM: integrator: move debug LEDs to syscon LED driver ARM: integrator: move restart to the device tree ARM: integrator: move AP timer to clocksource Signed-off-by: Arnd Bergmann <arnd@arndb.de>
This commit is contained in:
commit
4eca459bc1
@ -6,8 +6,18 @@
|
|||||||
|
|
||||||
/ {
|
/ {
|
||||||
core-module@10000000 {
|
core-module@10000000 {
|
||||||
compatible = "arm,core-module-integrator";
|
compatible = "arm,core-module-integrator", "syscon";
|
||||||
reg = <0x10000000 0x200>;
|
reg = <0x10000000 0x200>;
|
||||||
|
|
||||||
|
/* Use core module LED to indicate CPU load */
|
||||||
|
led@0c.0 {
|
||||||
|
compatible = "register-bit-led";
|
||||||
|
offset = <0x0c>;
|
||||||
|
mask = <0x01>;
|
||||||
|
label = "integrator:core_module";
|
||||||
|
linux,default-trigger = "cpu0";
|
||||||
|
default-state = "on";
|
||||||
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
ebi@12000000 {
|
ebi@12000000 {
|
||||||
@ -82,5 +92,41 @@
|
|||||||
reg = <0x19000000 0x1000>;
|
reg = <0x19000000 0x1000>;
|
||||||
interrupts = <4>;
|
interrupts = <4>;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
syscon {
|
||||||
|
/* Debug registers mapped as syscon */
|
||||||
|
compatible = "syscon";
|
||||||
|
reg = <0x1a000000 0x10>;
|
||||||
|
|
||||||
|
led@04.0 {
|
||||||
|
compatible = "register-bit-led";
|
||||||
|
offset = <0x04>;
|
||||||
|
mask = <0x01>;
|
||||||
|
label = "integrator:green0";
|
||||||
|
linux,default-trigger = "heartbeat";
|
||||||
|
default-state = "on";
|
||||||
|
};
|
||||||
|
led@04.1 {
|
||||||
|
compatible = "register-bit-led";
|
||||||
|
offset = <0x04>;
|
||||||
|
mask = <0x02>;
|
||||||
|
label = "integrator:yellow";
|
||||||
|
default-state = "off";
|
||||||
|
};
|
||||||
|
led@04.2 {
|
||||||
|
compatible = "register-bit-led";
|
||||||
|
offset = <0x04>;
|
||||||
|
mask = <0x04>;
|
||||||
|
label = "integrator:red";
|
||||||
|
default-state = "off";
|
||||||
|
};
|
||||||
|
led@04.3 {
|
||||||
|
compatible = "register-bit-led";
|
||||||
|
offset = <0x04>;
|
||||||
|
mask = <0x08>;
|
||||||
|
label = "integrator:green1";
|
||||||
|
default-state = "off";
|
||||||
|
};
|
||||||
|
};
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
@ -8,8 +8,13 @@ config ARCH_INTEGRATOR
|
|||||||
select GENERIC_CLOCKEVENTS
|
select GENERIC_CLOCKEVENTS
|
||||||
select HAVE_TCM
|
select HAVE_TCM
|
||||||
select ICST
|
select ICST
|
||||||
|
select MFD_SYSCON
|
||||||
select MULTI_IRQ_HANDLER
|
select MULTI_IRQ_HANDLER
|
||||||
select PLAT_VERSATILE
|
select PLAT_VERSATILE
|
||||||
|
select POWER_RESET
|
||||||
|
select POWER_RESET_VERSATILE
|
||||||
|
select POWER_SUPPLY
|
||||||
|
select SOC_INTEGRATOR_CM
|
||||||
select SPARSE_IRQ
|
select SPARSE_IRQ
|
||||||
select USE_OF
|
select USE_OF
|
||||||
select VERSATILE_FPGA_IRQ
|
select VERSATILE_FPGA_IRQ
|
||||||
|
@ -4,7 +4,7 @@
|
|||||||
|
|
||||||
# Object file lists.
|
# Object file lists.
|
||||||
|
|
||||||
obj-y := core.o lm.o leds.o
|
obj-y := core.o lm.o
|
||||||
obj-$(CONFIG_ARCH_INTEGRATOR_AP) += integrator_ap.o
|
obj-$(CONFIG_ARCH_INTEGRATOR_AP) += integrator_ap.o
|
||||||
obj-$(CONFIG_ARCH_INTEGRATOR_CP) += integrator_cp.o
|
obj-$(CONFIG_ARCH_INTEGRATOR_CP) += integrator_cp.o
|
||||||
|
|
||||||
|
@ -11,7 +11,6 @@ void cm_clear_irqs(void);
|
|||||||
#define CM_CTRL_LED (1 << 0)
|
#define CM_CTRL_LED (1 << 0)
|
||||||
#define CM_CTRL_nMBDET (1 << 1)
|
#define CM_CTRL_nMBDET (1 << 1)
|
||||||
#define CM_CTRL_REMAP (1 << 2)
|
#define CM_CTRL_REMAP (1 << 2)
|
||||||
#define CM_CTRL_RESET (1 << 3)
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Integrator/AP,PP2 specific
|
* Integrator/AP,PP2 specific
|
||||||
|
@ -4,5 +4,3 @@ extern struct amba_pl010_data ap_uart_data;
|
|||||||
void integrator_init_early(void);
|
void integrator_init_early(void);
|
||||||
int integrator_init(bool is_cp);
|
int integrator_init(bool is_cp);
|
||||||
void integrator_reserve(void);
|
void integrator_reserve(void);
|
||||||
void integrator_restart(enum reboot_mode, const char *);
|
|
||||||
void integrator_init_sysfs(struct device *parent, u32 id);
|
|
||||||
|
@ -60,40 +60,6 @@ void cm_control(u32 mask, u32 set)
|
|||||||
raw_spin_unlock_irqrestore(&cm_lock, flags);
|
raw_spin_unlock_irqrestore(&cm_lock, flags);
|
||||||
}
|
}
|
||||||
|
|
||||||
static const char *integrator_arch_str(u32 id)
|
|
||||||
{
|
|
||||||
switch ((id >> 16) & 0xff) {
|
|
||||||
case 0x00:
|
|
||||||
return "ASB little-endian";
|
|
||||||
case 0x01:
|
|
||||||
return "AHB little-endian";
|
|
||||||
case 0x03:
|
|
||||||
return "AHB-Lite system bus, bi-endian";
|
|
||||||
case 0x04:
|
|
||||||
return "AHB";
|
|
||||||
case 0x08:
|
|
||||||
return "AHB system bus, ASB processor bus";
|
|
||||||
default:
|
|
||||||
return "Unknown";
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
static const char *integrator_fpga_str(u32 id)
|
|
||||||
{
|
|
||||||
switch ((id >> 12) & 0xf) {
|
|
||||||
case 0x01:
|
|
||||||
return "XC4062";
|
|
||||||
case 0x02:
|
|
||||||
return "XC4085";
|
|
||||||
case 0x03:
|
|
||||||
return "XVC600";
|
|
||||||
case 0x04:
|
|
||||||
return "EPM7256AE (Altera PLD)";
|
|
||||||
default:
|
|
||||||
return "Unknown";
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void cm_clear_irqs(void)
|
void cm_clear_irqs(void)
|
||||||
{
|
{
|
||||||
/* disable core module IRQs */
|
/* disable core module IRQs */
|
||||||
@ -109,7 +75,6 @@ static const struct of_device_id cm_match[] = {
|
|||||||
void cm_init(void)
|
void cm_init(void)
|
||||||
{
|
{
|
||||||
struct device_node *cm = of_find_matching_node(NULL, cm_match);
|
struct device_node *cm = of_find_matching_node(NULL, cm_match);
|
||||||
u32 val;
|
|
||||||
|
|
||||||
if (!cm) {
|
if (!cm) {
|
||||||
pr_crit("no core module node found in device tree\n");
|
pr_crit("no core module node found in device tree\n");
|
||||||
@ -121,13 +86,6 @@ void cm_init(void)
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
cm_clear_irqs();
|
cm_clear_irqs();
|
||||||
val = readl(cm_base + INTEGRATOR_HDR_ID_OFFSET);
|
|
||||||
pr_info("Detected ARM core module:\n");
|
|
||||||
pr_info(" Manufacturer: %02x\n", (val >> 24));
|
|
||||||
pr_info(" Architecture: %s\n", integrator_arch_str(val));
|
|
||||||
pr_info(" FPGA: %s\n", integrator_fpga_str(val));
|
|
||||||
pr_info(" Build: %02x\n", (val >> 4) & 0xFF);
|
|
||||||
pr_info(" Rev: %c\n", ('A' + (val & 0x03)));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@ -139,64 +97,3 @@ void __init integrator_reserve(void)
|
|||||||
{
|
{
|
||||||
memblock_reserve(PHYS_OFFSET, __pa(swapper_pg_dir) - PHYS_OFFSET);
|
memblock_reserve(PHYS_OFFSET, __pa(swapper_pg_dir) - PHYS_OFFSET);
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
|
||||||
* To reset, we hit the on-board reset register in the system FPGA
|
|
||||||
*/
|
|
||||||
void integrator_restart(enum reboot_mode mode, const char *cmd)
|
|
||||||
{
|
|
||||||
cm_control(CM_CTRL_RESET, CM_CTRL_RESET);
|
|
||||||
}
|
|
||||||
|
|
||||||
static u32 integrator_id;
|
|
||||||
|
|
||||||
static ssize_t intcp_get_manf(struct device *dev,
|
|
||||||
struct device_attribute *attr,
|
|
||||||
char *buf)
|
|
||||||
{
|
|
||||||
return sprintf(buf, "%02x\n", integrator_id >> 24);
|
|
||||||
}
|
|
||||||
|
|
||||||
static struct device_attribute intcp_manf_attr =
|
|
||||||
__ATTR(manufacturer, S_IRUGO, intcp_get_manf, NULL);
|
|
||||||
|
|
||||||
static ssize_t intcp_get_arch(struct device *dev,
|
|
||||||
struct device_attribute *attr,
|
|
||||||
char *buf)
|
|
||||||
{
|
|
||||||
return sprintf(buf, "%s\n", integrator_arch_str(integrator_id));
|
|
||||||
}
|
|
||||||
|
|
||||||
static struct device_attribute intcp_arch_attr =
|
|
||||||
__ATTR(architecture, S_IRUGO, intcp_get_arch, NULL);
|
|
||||||
|
|
||||||
static ssize_t intcp_get_fpga(struct device *dev,
|
|
||||||
struct device_attribute *attr,
|
|
||||||
char *buf)
|
|
||||||
{
|
|
||||||
return sprintf(buf, "%s\n", integrator_fpga_str(integrator_id));
|
|
||||||
}
|
|
||||||
|
|
||||||
static struct device_attribute intcp_fpga_attr =
|
|
||||||
__ATTR(fpga, S_IRUGO, intcp_get_fpga, NULL);
|
|
||||||
|
|
||||||
static ssize_t intcp_get_build(struct device *dev,
|
|
||||||
struct device_attribute *attr,
|
|
||||||
char *buf)
|
|
||||||
{
|
|
||||||
return sprintf(buf, "%02x\n", (integrator_id >> 4) & 0xFF);
|
|
||||||
}
|
|
||||||
|
|
||||||
static struct device_attribute intcp_build_attr =
|
|
||||||
__ATTR(build, S_IRUGO, intcp_get_build, NULL);
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
void integrator_init_sysfs(struct device *parent, u32 id)
|
|
||||||
{
|
|
||||||
integrator_id = id;
|
|
||||||
device_create_file(parent, &intcp_manf_attr);
|
|
||||||
device_create_file(parent, &intcp_arch_attr);
|
|
||||||
device_create_file(parent, &intcp_fpga_attr);
|
|
||||||
device_create_file(parent, &intcp_build_attr);
|
|
||||||
}
|
|
||||||
|
@ -27,22 +27,15 @@
|
|||||||
#include <linux/syscore_ops.h>
|
#include <linux/syscore_ops.h>
|
||||||
#include <linux/amba/bus.h>
|
#include <linux/amba/bus.h>
|
||||||
#include <linux/amba/kmi.h>
|
#include <linux/amba/kmi.h>
|
||||||
#include <linux/clocksource.h>
|
|
||||||
#include <linux/clockchips.h>
|
|
||||||
#include <linux/interrupt.h>
|
|
||||||
#include <linux/io.h>
|
#include <linux/io.h>
|
||||||
#include <linux/irqchip.h>
|
#include <linux/irqchip.h>
|
||||||
#include <linux/mtd/physmap.h>
|
#include <linux/mtd/physmap.h>
|
||||||
#include <linux/clk.h>
|
|
||||||
#include <linux/platform_data/clk-integrator.h>
|
#include <linux/platform_data/clk-integrator.h>
|
||||||
#include <linux/of_irq.h>
|
#include <linux/of_irq.h>
|
||||||
#include <linux/of_address.h>
|
#include <linux/of_address.h>
|
||||||
#include <linux/of_platform.h>
|
#include <linux/of_platform.h>
|
||||||
#include <linux/stat.h>
|
#include <linux/stat.h>
|
||||||
#include <linux/sys_soc.h>
|
|
||||||
#include <linux/termios.h>
|
#include <linux/termios.h>
|
||||||
#include <linux/sched_clock.h>
|
|
||||||
#include <linux/clk-provider.h>
|
|
||||||
|
|
||||||
#include <asm/hardware/arm_timer.h>
|
#include <asm/hardware/arm_timer.h>
|
||||||
#include <asm/setup.h>
|
#include <asm/setup.h>
|
||||||
@ -89,11 +82,6 @@ static void __iomem *ebi_base;
|
|||||||
|
|
||||||
static struct map_desc ap_io_desc[] __initdata __maybe_unused = {
|
static struct map_desc ap_io_desc[] __initdata __maybe_unused = {
|
||||||
{
|
{
|
||||||
.virtual = IO_ADDRESS(INTEGRATOR_CT_BASE),
|
|
||||||
.pfn = __phys_to_pfn(INTEGRATOR_CT_BASE),
|
|
||||||
.length = SZ_4K,
|
|
||||||
.type = MT_DEVICE
|
|
||||||
}, {
|
|
||||||
.virtual = IO_ADDRESS(INTEGRATOR_IC_BASE),
|
.virtual = IO_ADDRESS(INTEGRATOR_IC_BASE),
|
||||||
.pfn = __phys_to_pfn(INTEGRATOR_IC_BASE),
|
.pfn = __phys_to_pfn(INTEGRATOR_IC_BASE),
|
||||||
.length = SZ_4K,
|
.length = SZ_4K,
|
||||||
@ -257,188 +245,10 @@ struct amba_pl010_data ap_uart_data = {
|
|||||||
.set_mctrl = integrator_uart_set_mctrl,
|
.set_mctrl = integrator_uart_set_mctrl,
|
||||||
};
|
};
|
||||||
|
|
||||||
/*
|
|
||||||
* Where is the timer (VA)?
|
|
||||||
*/
|
|
||||||
#define TIMER0_VA_BASE __io_address(INTEGRATOR_TIMER0_BASE)
|
|
||||||
#define TIMER1_VA_BASE __io_address(INTEGRATOR_TIMER1_BASE)
|
|
||||||
#define TIMER2_VA_BASE __io_address(INTEGRATOR_TIMER2_BASE)
|
|
||||||
|
|
||||||
static unsigned long timer_reload;
|
|
||||||
|
|
||||||
static u64 notrace integrator_read_sched_clock(void)
|
|
||||||
{
|
|
||||||
return -readl((void __iomem *) TIMER2_VA_BASE + TIMER_VALUE);
|
|
||||||
}
|
|
||||||
|
|
||||||
static void integrator_clocksource_init(unsigned long inrate,
|
|
||||||
void __iomem *base)
|
|
||||||
{
|
|
||||||
u32 ctrl = TIMER_CTRL_ENABLE | TIMER_CTRL_PERIODIC;
|
|
||||||
unsigned long rate = inrate;
|
|
||||||
|
|
||||||
if (rate >= 1500000) {
|
|
||||||
rate /= 16;
|
|
||||||
ctrl |= TIMER_CTRL_DIV16;
|
|
||||||
}
|
|
||||||
|
|
||||||
writel(0xffff, base + TIMER_LOAD);
|
|
||||||
writel(ctrl, base + TIMER_CTRL);
|
|
||||||
|
|
||||||
clocksource_mmio_init(base + TIMER_VALUE, "timer2",
|
|
||||||
rate, 200, 16, clocksource_mmio_readl_down);
|
|
||||||
sched_clock_register(integrator_read_sched_clock, 16, rate);
|
|
||||||
}
|
|
||||||
|
|
||||||
static void __iomem * clkevt_base;
|
|
||||||
|
|
||||||
/*
|
|
||||||
* IRQ handler for the timer
|
|
||||||
*/
|
|
||||||
static irqreturn_t integrator_timer_interrupt(int irq, void *dev_id)
|
|
||||||
{
|
|
||||||
struct clock_event_device *evt = dev_id;
|
|
||||||
|
|
||||||
/* clear the interrupt */
|
|
||||||
writel(1, clkevt_base + TIMER_INTCLR);
|
|
||||||
|
|
||||||
evt->event_handler(evt);
|
|
||||||
|
|
||||||
return IRQ_HANDLED;
|
|
||||||
}
|
|
||||||
|
|
||||||
static void clkevt_set_mode(enum clock_event_mode mode, struct clock_event_device *evt)
|
|
||||||
{
|
|
||||||
u32 ctrl = readl(clkevt_base + TIMER_CTRL) & ~TIMER_CTRL_ENABLE;
|
|
||||||
|
|
||||||
/* Disable timer */
|
|
||||||
writel(ctrl, clkevt_base + TIMER_CTRL);
|
|
||||||
|
|
||||||
switch (mode) {
|
|
||||||
case CLOCK_EVT_MODE_PERIODIC:
|
|
||||||
/* Enable the timer and start the periodic tick */
|
|
||||||
writel(timer_reload, clkevt_base + TIMER_LOAD);
|
|
||||||
ctrl |= TIMER_CTRL_PERIODIC | TIMER_CTRL_ENABLE;
|
|
||||||
writel(ctrl, clkevt_base + TIMER_CTRL);
|
|
||||||
break;
|
|
||||||
case CLOCK_EVT_MODE_ONESHOT:
|
|
||||||
/* Leave the timer disabled, .set_next_event will enable it */
|
|
||||||
ctrl &= ~TIMER_CTRL_PERIODIC;
|
|
||||||
writel(ctrl, clkevt_base + TIMER_CTRL);
|
|
||||||
break;
|
|
||||||
case CLOCK_EVT_MODE_UNUSED:
|
|
||||||
case CLOCK_EVT_MODE_SHUTDOWN:
|
|
||||||
case CLOCK_EVT_MODE_RESUME:
|
|
||||||
default:
|
|
||||||
/* Just leave in disabled state */
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
static int clkevt_set_next_event(unsigned long next, struct clock_event_device *evt)
|
|
||||||
{
|
|
||||||
unsigned long ctrl = readl(clkevt_base + TIMER_CTRL);
|
|
||||||
|
|
||||||
writel(ctrl & ~TIMER_CTRL_ENABLE, clkevt_base + TIMER_CTRL);
|
|
||||||
writel(next, clkevt_base + TIMER_LOAD);
|
|
||||||
writel(ctrl | TIMER_CTRL_ENABLE, clkevt_base + TIMER_CTRL);
|
|
||||||
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
static struct clock_event_device integrator_clockevent = {
|
|
||||||
.name = "timer1",
|
|
||||||
.features = CLOCK_EVT_FEAT_PERIODIC | CLOCK_EVT_FEAT_ONESHOT,
|
|
||||||
.set_mode = clkevt_set_mode,
|
|
||||||
.set_next_event = clkevt_set_next_event,
|
|
||||||
.rating = 300,
|
|
||||||
};
|
|
||||||
|
|
||||||
static struct irqaction integrator_timer_irq = {
|
|
||||||
.name = "timer",
|
|
||||||
.flags = IRQF_TIMER | IRQF_IRQPOLL,
|
|
||||||
.handler = integrator_timer_interrupt,
|
|
||||||
.dev_id = &integrator_clockevent,
|
|
||||||
};
|
|
||||||
|
|
||||||
static void integrator_clockevent_init(unsigned long inrate,
|
|
||||||
void __iomem *base, int irq)
|
|
||||||
{
|
|
||||||
unsigned long rate = inrate;
|
|
||||||
unsigned int ctrl = 0;
|
|
||||||
|
|
||||||
clkevt_base = base;
|
|
||||||
/* Calculate and program a divisor */
|
|
||||||
if (rate > 0x100000 * HZ) {
|
|
||||||
rate /= 256;
|
|
||||||
ctrl |= TIMER_CTRL_DIV256;
|
|
||||||
} else if (rate > 0x10000 * HZ) {
|
|
||||||
rate /= 16;
|
|
||||||
ctrl |= TIMER_CTRL_DIV16;
|
|
||||||
}
|
|
||||||
timer_reload = rate / HZ;
|
|
||||||
writel(ctrl, clkevt_base + TIMER_CTRL);
|
|
||||||
|
|
||||||
setup_irq(irq, &integrator_timer_irq);
|
|
||||||
clockevents_config_and_register(&integrator_clockevent,
|
|
||||||
rate,
|
|
||||||
1,
|
|
||||||
0xffffU);
|
|
||||||
}
|
|
||||||
|
|
||||||
void __init ap_init_early(void)
|
void __init ap_init_early(void)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
static void __init ap_of_timer_init(void)
|
|
||||||
{
|
|
||||||
struct device_node *node;
|
|
||||||
const char *path;
|
|
||||||
void __iomem *base;
|
|
||||||
int err;
|
|
||||||
int irq;
|
|
||||||
struct clk *clk;
|
|
||||||
unsigned long rate;
|
|
||||||
|
|
||||||
of_clk_init(NULL);
|
|
||||||
|
|
||||||
err = of_property_read_string(of_aliases,
|
|
||||||
"arm,timer-primary", &path);
|
|
||||||
if (WARN_ON(err))
|
|
||||||
return;
|
|
||||||
node = of_find_node_by_path(path);
|
|
||||||
base = of_iomap(node, 0);
|
|
||||||
if (WARN_ON(!base))
|
|
||||||
return;
|
|
||||||
|
|
||||||
clk = of_clk_get(node, 0);
|
|
||||||
BUG_ON(IS_ERR(clk));
|
|
||||||
clk_prepare_enable(clk);
|
|
||||||
rate = clk_get_rate(clk);
|
|
||||||
|
|
||||||
writel(0, base + TIMER_CTRL);
|
|
||||||
integrator_clocksource_init(rate, base);
|
|
||||||
|
|
||||||
err = of_property_read_string(of_aliases,
|
|
||||||
"arm,timer-secondary", &path);
|
|
||||||
if (WARN_ON(err))
|
|
||||||
return;
|
|
||||||
node = of_find_node_by_path(path);
|
|
||||||
base = of_iomap(node, 0);
|
|
||||||
if (WARN_ON(!base))
|
|
||||||
return;
|
|
||||||
irq = irq_of_parse_and_map(node, 0);
|
|
||||||
|
|
||||||
clk = of_clk_get(node, 0);
|
|
||||||
BUG_ON(IS_ERR(clk));
|
|
||||||
clk_prepare_enable(clk);
|
|
||||||
rate = clk_get_rate(clk);
|
|
||||||
|
|
||||||
writel(0, base + TIMER_CTRL);
|
|
||||||
integrator_clockevent_init(rate, base, irq);
|
|
||||||
}
|
|
||||||
|
|
||||||
static void __init ap_init_irq_of(void)
|
static void __init ap_init_irq_of(void)
|
||||||
{
|
{
|
||||||
cm_init();
|
cm_init();
|
||||||
@ -477,10 +287,6 @@ static void __init ap_init_of(void)
|
|||||||
unsigned long sc_dec;
|
unsigned long sc_dec;
|
||||||
struct device_node *syscon;
|
struct device_node *syscon;
|
||||||
struct device_node *ebi;
|
struct device_node *ebi;
|
||||||
struct device *parent;
|
|
||||||
struct soc_device *soc_dev;
|
|
||||||
struct soc_device_attribute *soc_dev_attr;
|
|
||||||
u32 ap_sc_id;
|
|
||||||
int i;
|
int i;
|
||||||
|
|
||||||
syscon = of_find_matching_node(NULL, ap_syscon_match);
|
syscon = of_find_matching_node(NULL, ap_syscon_match);
|
||||||
@ -500,28 +306,6 @@ static void __init ap_init_of(void)
|
|||||||
of_platform_populate(NULL, of_default_bus_match_table,
|
of_platform_populate(NULL, of_default_bus_match_table,
|
||||||
ap_auxdata_lookup, NULL);
|
ap_auxdata_lookup, NULL);
|
||||||
|
|
||||||
ap_sc_id = readl(ap_syscon_base);
|
|
||||||
|
|
||||||
soc_dev_attr = kzalloc(sizeof(*soc_dev_attr), GFP_KERNEL);
|
|
||||||
if (!soc_dev_attr)
|
|
||||||
return;
|
|
||||||
|
|
||||||
soc_dev_attr->soc_id = "XVC";
|
|
||||||
soc_dev_attr->machine = "Integrator/AP";
|
|
||||||
soc_dev_attr->family = "Integrator";
|
|
||||||
soc_dev_attr->revision = kasprintf(GFP_KERNEL, "%c",
|
|
||||||
'A' + (ap_sc_id & 0x0f));
|
|
||||||
|
|
||||||
soc_dev = soc_device_register(soc_dev_attr);
|
|
||||||
if (IS_ERR(soc_dev)) {
|
|
||||||
kfree(soc_dev_attr->revision);
|
|
||||||
kfree(soc_dev_attr);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
parent = soc_device_to_device(soc_dev);
|
|
||||||
integrator_init_sysfs(parent, ap_sc_id);
|
|
||||||
|
|
||||||
sc_dec = readl(ap_syscon_base + INTEGRATOR_SC_DEC_OFFSET);
|
sc_dec = readl(ap_syscon_base + INTEGRATOR_SC_DEC_OFFSET);
|
||||||
for (i = 0; i < 4; i++) {
|
for (i = 0; i < 4; i++) {
|
||||||
struct lm_device *lmdev;
|
struct lm_device *lmdev;
|
||||||
@ -553,8 +337,6 @@ DT_MACHINE_START(INTEGRATOR_AP_DT, "ARM Integrator/AP (Device Tree)")
|
|||||||
.map_io = ap_map_io,
|
.map_io = ap_map_io,
|
||||||
.init_early = ap_init_early,
|
.init_early = ap_init_early,
|
||||||
.init_irq = ap_init_irq_of,
|
.init_irq = ap_init_irq_of,
|
||||||
.init_time = ap_of_timer_init,
|
|
||||||
.init_machine = ap_init_of,
|
.init_machine = ap_init_of,
|
||||||
.restart = integrator_restart,
|
|
||||||
.dt_compat = ap_dt_board_compat,
|
.dt_compat = ap_dt_board_compat,
|
||||||
MACHINE_END
|
MACHINE_END
|
||||||
|
@ -27,7 +27,6 @@
|
|||||||
#include <linux/of_irq.h>
|
#include <linux/of_irq.h>
|
||||||
#include <linux/of_address.h>
|
#include <linux/of_address.h>
|
||||||
#include <linux/of_platform.h>
|
#include <linux/of_platform.h>
|
||||||
#include <linux/sys_soc.h>
|
|
||||||
#include <linux/sched_clock.h>
|
#include <linux/sched_clock.h>
|
||||||
|
|
||||||
#include <asm/setup.h>
|
#include <asm/setup.h>
|
||||||
@ -274,10 +273,6 @@ static const struct of_device_id intcp_syscon_match[] = {
|
|||||||
static void __init intcp_init_of(void)
|
static void __init intcp_init_of(void)
|
||||||
{
|
{
|
||||||
struct device_node *cpcon;
|
struct device_node *cpcon;
|
||||||
struct device *parent;
|
|
||||||
struct soc_device *soc_dev;
|
|
||||||
struct soc_device_attribute *soc_dev_attr;
|
|
||||||
u32 intcp_sc_id;
|
|
||||||
|
|
||||||
cpcon = of_find_matching_node(NULL, intcp_syscon_match);
|
cpcon = of_find_matching_node(NULL, intcp_syscon_match);
|
||||||
if (!cpcon)
|
if (!cpcon)
|
||||||
@ -289,28 +284,6 @@ static void __init intcp_init_of(void)
|
|||||||
|
|
||||||
of_platform_populate(NULL, of_default_bus_match_table,
|
of_platform_populate(NULL, of_default_bus_match_table,
|
||||||
intcp_auxdata_lookup, NULL);
|
intcp_auxdata_lookup, NULL);
|
||||||
|
|
||||||
intcp_sc_id = readl(intcp_con_base);
|
|
||||||
|
|
||||||
soc_dev_attr = kzalloc(sizeof(*soc_dev_attr), GFP_KERNEL);
|
|
||||||
if (!soc_dev_attr)
|
|
||||||
return;
|
|
||||||
|
|
||||||
soc_dev_attr->soc_id = "XCV";
|
|
||||||
soc_dev_attr->machine = "Integrator/CP";
|
|
||||||
soc_dev_attr->family = "Integrator";
|
|
||||||
soc_dev_attr->revision = kasprintf(GFP_KERNEL, "%c",
|
|
||||||
'A' + (intcp_sc_id & 0x0f));
|
|
||||||
|
|
||||||
soc_dev = soc_device_register(soc_dev_attr);
|
|
||||||
if (IS_ERR(soc_dev)) {
|
|
||||||
kfree(soc_dev_attr->revision);
|
|
||||||
kfree(soc_dev_attr);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
parent = soc_device_to_device(soc_dev);
|
|
||||||
integrator_init_sysfs(parent, intcp_sc_id);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static const char * intcp_dt_board_compat[] = {
|
static const char * intcp_dt_board_compat[] = {
|
||||||
@ -324,6 +297,5 @@ DT_MACHINE_START(INTEGRATOR_CP_DT, "ARM Integrator/CP (Device Tree)")
|
|||||||
.init_early = intcp_init_early,
|
.init_early = intcp_init_early,
|
||||||
.init_irq = intcp_init_irq_of,
|
.init_irq = intcp_init_irq_of,
|
||||||
.init_machine = intcp_init_of,
|
.init_machine = intcp_init_of,
|
||||||
.restart = integrator_restart,
|
|
||||||
.dt_compat = intcp_dt_board_compat,
|
.dt_compat = intcp_dt_board_compat,
|
||||||
MACHINE_END
|
MACHINE_END
|
||||||
|
@ -1,124 +0,0 @@
|
|||||||
/*
|
|
||||||
* Driver for the 4 user LEDs found on the Integrator AP/CP baseboard
|
|
||||||
* Based on Versatile and RealView machine LED code
|
|
||||||
*
|
|
||||||
* License terms: GNU General Public License (GPL) version 2
|
|
||||||
* Author: Bryan Wu <bryan.wu@canonical.com>
|
|
||||||
*/
|
|
||||||
#include <linux/kernel.h>
|
|
||||||
#include <linux/init.h>
|
|
||||||
#include <linux/io.h>
|
|
||||||
#include <linux/slab.h>
|
|
||||||
#include <linux/leds.h>
|
|
||||||
|
|
||||||
#include "hardware.h"
|
|
||||||
#include "cm.h"
|
|
||||||
|
|
||||||
#if defined(CONFIG_NEW_LEDS) && defined(CONFIG_LEDS_CLASS)
|
|
||||||
|
|
||||||
#define ALPHA_REG __io_address(INTEGRATOR_DBG_BASE)
|
|
||||||
#define LEDREG (__io_address(INTEGRATOR_DBG_BASE) + INTEGRATOR_DBG_LEDS_OFFSET)
|
|
||||||
|
|
||||||
struct integrator_led {
|
|
||||||
struct led_classdev cdev;
|
|
||||||
u8 mask;
|
|
||||||
};
|
|
||||||
|
|
||||||
/*
|
|
||||||
* The triggers lines up below will only be used if the
|
|
||||||
* LED triggers are compiled in.
|
|
||||||
*/
|
|
||||||
static const struct {
|
|
||||||
const char *name;
|
|
||||||
const char *trigger;
|
|
||||||
} integrator_leds[] = {
|
|
||||||
{ "integrator:green0", "heartbeat", },
|
|
||||||
{ "integrator:yellow", },
|
|
||||||
{ "integrator:red", },
|
|
||||||
{ "integrator:green1", },
|
|
||||||
{ "integrator:core_module", "cpu0", },
|
|
||||||
};
|
|
||||||
|
|
||||||
static void integrator_led_set(struct led_classdev *cdev,
|
|
||||||
enum led_brightness b)
|
|
||||||
{
|
|
||||||
struct integrator_led *led = container_of(cdev,
|
|
||||||
struct integrator_led, cdev);
|
|
||||||
u32 reg = __raw_readl(LEDREG);
|
|
||||||
|
|
||||||
if (b != LED_OFF)
|
|
||||||
reg |= led->mask;
|
|
||||||
else
|
|
||||||
reg &= ~led->mask;
|
|
||||||
|
|
||||||
while (__raw_readl(ALPHA_REG) & 1)
|
|
||||||
cpu_relax();
|
|
||||||
|
|
||||||
__raw_writel(reg, LEDREG);
|
|
||||||
}
|
|
||||||
|
|
||||||
static enum led_brightness integrator_led_get(struct led_classdev *cdev)
|
|
||||||
{
|
|
||||||
struct integrator_led *led = container_of(cdev,
|
|
||||||
struct integrator_led, cdev);
|
|
||||||
u32 reg = __raw_readl(LEDREG);
|
|
||||||
|
|
||||||
return (reg & led->mask) ? LED_FULL : LED_OFF;
|
|
||||||
}
|
|
||||||
|
|
||||||
static void cm_led_set(struct led_classdev *cdev,
|
|
||||||
enum led_brightness b)
|
|
||||||
{
|
|
||||||
if (b != LED_OFF)
|
|
||||||
cm_control(CM_CTRL_LED, CM_CTRL_LED);
|
|
||||||
else
|
|
||||||
cm_control(CM_CTRL_LED, 0);
|
|
||||||
}
|
|
||||||
|
|
||||||
static enum led_brightness cm_led_get(struct led_classdev *cdev)
|
|
||||||
{
|
|
||||||
u32 reg = cm_get();
|
|
||||||
|
|
||||||
return (reg & CM_CTRL_LED) ? LED_FULL : LED_OFF;
|
|
||||||
}
|
|
||||||
|
|
||||||
static int __init integrator_leds_init(void)
|
|
||||||
{
|
|
||||||
int i;
|
|
||||||
|
|
||||||
for (i = 0; i < ARRAY_SIZE(integrator_leds); i++) {
|
|
||||||
struct integrator_led *led;
|
|
||||||
|
|
||||||
led = kzalloc(sizeof(*led), GFP_KERNEL);
|
|
||||||
if (!led)
|
|
||||||
break;
|
|
||||||
|
|
||||||
|
|
||||||
led->cdev.name = integrator_leds[i].name;
|
|
||||||
|
|
||||||
if (i == 4) { /* Setting for LED in core module */
|
|
||||||
led->cdev.brightness_set = cm_led_set;
|
|
||||||
led->cdev.brightness_get = cm_led_get;
|
|
||||||
} else {
|
|
||||||
led->cdev.brightness_set = integrator_led_set;
|
|
||||||
led->cdev.brightness_get = integrator_led_get;
|
|
||||||
}
|
|
||||||
|
|
||||||
led->cdev.default_trigger = integrator_leds[i].trigger;
|
|
||||||
led->mask = BIT(i);
|
|
||||||
|
|
||||||
if (led_classdev_register(NULL, &led->cdev) < 0) {
|
|
||||||
kfree(led);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Since we may have triggers on any subsystem, defer registration
|
|
||||||
* until after subsystem_init.
|
|
||||||
*/
|
|
||||||
fs_initcall(integrator_leds_init);
|
|
||||||
#endif
|
|
@ -45,4 +45,5 @@ obj-$(CONFIG_ARM_GLOBAL_TIMER) += arm_global_timer.o
|
|||||||
obj-$(CONFIG_CLKSRC_METAG_GENERIC) += metag_generic.o
|
obj-$(CONFIG_CLKSRC_METAG_GENERIC) += metag_generic.o
|
||||||
obj-$(CONFIG_ARCH_HAS_TICK_BROADCAST) += dummy_timer.o
|
obj-$(CONFIG_ARCH_HAS_TICK_BROADCAST) += dummy_timer.o
|
||||||
obj-$(CONFIG_ARCH_KEYSTONE) += timer-keystone.o
|
obj-$(CONFIG_ARCH_KEYSTONE) += timer-keystone.o
|
||||||
|
obj-$(CONFIG_ARCH_INTEGRATOR_AP) += timer-integrator-ap.o
|
||||||
obj-$(CONFIG_CLKSRC_VERSATILE) += versatile.o
|
obj-$(CONFIG_CLKSRC_VERSATILE) += versatile.o
|
||||||
|
210
drivers/clocksource/timer-integrator-ap.c
Normal file
210
drivers/clocksource/timer-integrator-ap.c
Normal file
@ -0,0 +1,210 @@
|
|||||||
|
/*
|
||||||
|
* Integrator/AP timer driver
|
||||||
|
* Copyright (C) 2000-2003 Deep Blue Solutions Ltd
|
||||||
|
* Copyright (c) 2014, Linaro Limited
|
||||||
|
*
|
||||||
|
* This program is free software; you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU General Public License as published by
|
||||||
|
* the Free Software Foundation; either version 2 of the License, or
|
||||||
|
* (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that 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, write to the Free Software
|
||||||
|
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <linux/clk.h>
|
||||||
|
#include <linux/clocksource.h>
|
||||||
|
#include <linux/of_irq.h>
|
||||||
|
#include <linux/of_address.h>
|
||||||
|
#include <linux/of_platform.h>
|
||||||
|
#include <linux/clockchips.h>
|
||||||
|
#include <linux/interrupt.h>
|
||||||
|
#include <linux/sched_clock.h>
|
||||||
|
#include <asm/hardware/arm_timer.h>
|
||||||
|
|
||||||
|
static void __iomem * sched_clk_base;
|
||||||
|
|
||||||
|
static u64 notrace integrator_read_sched_clock(void)
|
||||||
|
{
|
||||||
|
return -readl(sched_clk_base + TIMER_VALUE);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void integrator_clocksource_init(unsigned long inrate,
|
||||||
|
void __iomem *base)
|
||||||
|
{
|
||||||
|
u32 ctrl = TIMER_CTRL_ENABLE | TIMER_CTRL_PERIODIC;
|
||||||
|
unsigned long rate = inrate;
|
||||||
|
|
||||||
|
if (rate >= 1500000) {
|
||||||
|
rate /= 16;
|
||||||
|
ctrl |= TIMER_CTRL_DIV16;
|
||||||
|
}
|
||||||
|
|
||||||
|
writel(0xffff, base + TIMER_LOAD);
|
||||||
|
writel(ctrl, base + TIMER_CTRL);
|
||||||
|
|
||||||
|
clocksource_mmio_init(base + TIMER_VALUE, "timer2",
|
||||||
|
rate, 200, 16, clocksource_mmio_readl_down);
|
||||||
|
|
||||||
|
sched_clk_base = base;
|
||||||
|
sched_clock_register(integrator_read_sched_clock, 16, rate);
|
||||||
|
}
|
||||||
|
|
||||||
|
static unsigned long timer_reload;
|
||||||
|
static void __iomem * clkevt_base;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* IRQ handler for the timer
|
||||||
|
*/
|
||||||
|
static irqreturn_t integrator_timer_interrupt(int irq, void *dev_id)
|
||||||
|
{
|
||||||
|
struct clock_event_device *evt = dev_id;
|
||||||
|
|
||||||
|
/* clear the interrupt */
|
||||||
|
writel(1, clkevt_base + TIMER_INTCLR);
|
||||||
|
|
||||||
|
evt->event_handler(evt);
|
||||||
|
|
||||||
|
return IRQ_HANDLED;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void clkevt_set_mode(enum clock_event_mode mode, struct clock_event_device *evt)
|
||||||
|
{
|
||||||
|
u32 ctrl = readl(clkevt_base + TIMER_CTRL) & ~TIMER_CTRL_ENABLE;
|
||||||
|
|
||||||
|
/* Disable timer */
|
||||||
|
writel(ctrl, clkevt_base + TIMER_CTRL);
|
||||||
|
|
||||||
|
switch (mode) {
|
||||||
|
case CLOCK_EVT_MODE_PERIODIC:
|
||||||
|
/* Enable the timer and start the periodic tick */
|
||||||
|
writel(timer_reload, clkevt_base + TIMER_LOAD);
|
||||||
|
ctrl |= TIMER_CTRL_PERIODIC | TIMER_CTRL_ENABLE;
|
||||||
|
writel(ctrl, clkevt_base + TIMER_CTRL);
|
||||||
|
break;
|
||||||
|
case CLOCK_EVT_MODE_ONESHOT:
|
||||||
|
/* Leave the timer disabled, .set_next_event will enable it */
|
||||||
|
ctrl &= ~TIMER_CTRL_PERIODIC;
|
||||||
|
writel(ctrl, clkevt_base + TIMER_CTRL);
|
||||||
|
break;
|
||||||
|
case CLOCK_EVT_MODE_UNUSED:
|
||||||
|
case CLOCK_EVT_MODE_SHUTDOWN:
|
||||||
|
case CLOCK_EVT_MODE_RESUME:
|
||||||
|
default:
|
||||||
|
/* Just leave in disabled state */
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
static int clkevt_set_next_event(unsigned long next, struct clock_event_device *evt)
|
||||||
|
{
|
||||||
|
unsigned long ctrl = readl(clkevt_base + TIMER_CTRL);
|
||||||
|
|
||||||
|
writel(ctrl & ~TIMER_CTRL_ENABLE, clkevt_base + TIMER_CTRL);
|
||||||
|
writel(next, clkevt_base + TIMER_LOAD);
|
||||||
|
writel(ctrl | TIMER_CTRL_ENABLE, clkevt_base + TIMER_CTRL);
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static struct clock_event_device integrator_clockevent = {
|
||||||
|
.name = "timer1",
|
||||||
|
.features = CLOCK_EVT_FEAT_PERIODIC | CLOCK_EVT_FEAT_ONESHOT,
|
||||||
|
.set_mode = clkevt_set_mode,
|
||||||
|
.set_next_event = clkevt_set_next_event,
|
||||||
|
.rating = 300,
|
||||||
|
};
|
||||||
|
|
||||||
|
static struct irqaction integrator_timer_irq = {
|
||||||
|
.name = "timer",
|
||||||
|
.flags = IRQF_TIMER | IRQF_IRQPOLL,
|
||||||
|
.handler = integrator_timer_interrupt,
|
||||||
|
.dev_id = &integrator_clockevent,
|
||||||
|
};
|
||||||
|
|
||||||
|
static void integrator_clockevent_init(unsigned long inrate,
|
||||||
|
void __iomem *base, int irq)
|
||||||
|
{
|
||||||
|
unsigned long rate = inrate;
|
||||||
|
unsigned int ctrl = 0;
|
||||||
|
|
||||||
|
clkevt_base = base;
|
||||||
|
/* Calculate and program a divisor */
|
||||||
|
if (rate > 0x100000 * HZ) {
|
||||||
|
rate /= 256;
|
||||||
|
ctrl |= TIMER_CTRL_DIV256;
|
||||||
|
} else if (rate > 0x10000 * HZ) {
|
||||||
|
rate /= 16;
|
||||||
|
ctrl |= TIMER_CTRL_DIV16;
|
||||||
|
}
|
||||||
|
timer_reload = rate / HZ;
|
||||||
|
writel(ctrl, clkevt_base + TIMER_CTRL);
|
||||||
|
|
||||||
|
setup_irq(irq, &integrator_timer_irq);
|
||||||
|
clockevents_config_and_register(&integrator_clockevent,
|
||||||
|
rate,
|
||||||
|
1,
|
||||||
|
0xffffU);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void __init integrator_ap_timer_init_of(struct device_node *node)
|
||||||
|
{
|
||||||
|
const char *path;
|
||||||
|
void __iomem *base;
|
||||||
|
int err;
|
||||||
|
int irq;
|
||||||
|
struct clk *clk;
|
||||||
|
unsigned long rate;
|
||||||
|
struct device_node *pri_node;
|
||||||
|
struct device_node *sec_node;
|
||||||
|
|
||||||
|
base = of_io_request_and_map(node, 0, "integrator-timer");
|
||||||
|
if (!base)
|
||||||
|
return;
|
||||||
|
|
||||||
|
clk = of_clk_get(node, 0);
|
||||||
|
if (IS_ERR(clk)) {
|
||||||
|
pr_err("No clock for %s\n", node->name);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
clk_prepare_enable(clk);
|
||||||
|
rate = clk_get_rate(clk);
|
||||||
|
writel(0, base + TIMER_CTRL);
|
||||||
|
|
||||||
|
err = of_property_read_string(of_aliases,
|
||||||
|
"arm,timer-primary", &path);
|
||||||
|
if (WARN_ON(err))
|
||||||
|
return;
|
||||||
|
pri_node = of_find_node_by_path(path);
|
||||||
|
err = of_property_read_string(of_aliases,
|
||||||
|
"arm,timer-secondary", &path);
|
||||||
|
if (WARN_ON(err))
|
||||||
|
return;
|
||||||
|
sec_node = of_find_node_by_path(path);
|
||||||
|
|
||||||
|
if (node == pri_node) {
|
||||||
|
/* The primary timer lacks IRQ, use as clocksource */
|
||||||
|
integrator_clocksource_init(rate, base);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (node == sec_node) {
|
||||||
|
/* The secondary timer will drive the clock event */
|
||||||
|
irq = irq_of_parse_and_map(node, 0);
|
||||||
|
integrator_clockevent_init(rate, base, irq);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
pr_info("Timer @%p unused\n", base);
|
||||||
|
clk_disable_unprepare(clk);
|
||||||
|
}
|
||||||
|
|
||||||
|
CLOCKSOURCE_OF_DECLARE(integrator_ap_timer, "arm,integrator-timer",
|
||||||
|
integrator_ap_timer_init_of);
|
@ -1,6 +1,15 @@
|
|||||||
#
|
#
|
||||||
# ARM Versatile SoC drivers
|
# ARM Versatile SoC drivers
|
||||||
#
|
#
|
||||||
|
config SOC_INTEGRATOR_CM
|
||||||
|
bool "SoC bus device for the ARM Integrator platform core modules"
|
||||||
|
depends on ARCH_INTEGRATOR
|
||||||
|
select SOC_BUS
|
||||||
|
help
|
||||||
|
Include support for the SoC bus on the ARM Integrator platform
|
||||||
|
core modules providing some sysfs information about the ASIC
|
||||||
|
variant.
|
||||||
|
|
||||||
config SOC_REALVIEW
|
config SOC_REALVIEW
|
||||||
bool "SoC bus device for the ARM RealView platforms"
|
bool "SoC bus device for the ARM RealView platforms"
|
||||||
depends on ARCH_REALVIEW
|
depends on ARCH_REALVIEW
|
||||||
|
@ -1 +1,2 @@
|
|||||||
|
obj-$(CONFIG_SOC_INTEGRATOR_CM) += soc-integrator.o
|
||||||
obj-$(CONFIG_SOC_REALVIEW) += soc-realview.o
|
obj-$(CONFIG_SOC_REALVIEW) += soc-realview.o
|
||||||
|
154
drivers/soc/versatile/soc-integrator.c
Normal file
154
drivers/soc/versatile/soc-integrator.c
Normal file
@ -0,0 +1,154 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (C) 2014 Linaro Ltd.
|
||||||
|
*
|
||||||
|
* Author: Linus Walleij <linus.walleij@linaro.org>
|
||||||
|
*
|
||||||
|
* 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/io.h>
|
||||||
|
#include <linux/slab.h>
|
||||||
|
#include <linux/sys_soc.h>
|
||||||
|
#include <linux/platform_device.h>
|
||||||
|
#include <linux/mfd/syscon.h>
|
||||||
|
#include <linux/regmap.h>
|
||||||
|
#include <linux/of.h>
|
||||||
|
|
||||||
|
#define INTEGRATOR_HDR_ID_OFFSET 0x00
|
||||||
|
|
||||||
|
static u32 integrator_coreid;
|
||||||
|
|
||||||
|
static const struct of_device_id integrator_cm_match[] = {
|
||||||
|
{ .compatible = "arm,core-module-integrator", },
|
||||||
|
};
|
||||||
|
|
||||||
|
static const char *integrator_arch_str(u32 id)
|
||||||
|
{
|
||||||
|
switch ((id >> 16) & 0xff) {
|
||||||
|
case 0x00:
|
||||||
|
return "ASB little-endian";
|
||||||
|
case 0x01:
|
||||||
|
return "AHB little-endian";
|
||||||
|
case 0x03:
|
||||||
|
return "AHB-Lite system bus, bi-endian";
|
||||||
|
case 0x04:
|
||||||
|
return "AHB";
|
||||||
|
case 0x08:
|
||||||
|
return "AHB system bus, ASB processor bus";
|
||||||
|
default:
|
||||||
|
return "Unknown";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static const char *integrator_fpga_str(u32 id)
|
||||||
|
{
|
||||||
|
switch ((id >> 12) & 0xf) {
|
||||||
|
case 0x01:
|
||||||
|
return "XC4062";
|
||||||
|
case 0x02:
|
||||||
|
return "XC4085";
|
||||||
|
case 0x03:
|
||||||
|
return "XVC600";
|
||||||
|
case 0x04:
|
||||||
|
return "EPM7256AE (Altera PLD)";
|
||||||
|
default:
|
||||||
|
return "Unknown";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static ssize_t integrator_get_manf(struct device *dev,
|
||||||
|
struct device_attribute *attr,
|
||||||
|
char *buf)
|
||||||
|
{
|
||||||
|
return sprintf(buf, "%02x\n", integrator_coreid >> 24);
|
||||||
|
}
|
||||||
|
|
||||||
|
static struct device_attribute integrator_manf_attr =
|
||||||
|
__ATTR(manufacturer, S_IRUGO, integrator_get_manf, NULL);
|
||||||
|
|
||||||
|
static ssize_t integrator_get_arch(struct device *dev,
|
||||||
|
struct device_attribute *attr,
|
||||||
|
char *buf)
|
||||||
|
{
|
||||||
|
return sprintf(buf, "%s\n", integrator_arch_str(integrator_coreid));
|
||||||
|
}
|
||||||
|
|
||||||
|
static struct device_attribute integrator_arch_attr =
|
||||||
|
__ATTR(arch, S_IRUGO, integrator_get_arch, NULL);
|
||||||
|
|
||||||
|
static ssize_t integrator_get_fpga(struct device *dev,
|
||||||
|
struct device_attribute *attr,
|
||||||
|
char *buf)
|
||||||
|
{
|
||||||
|
return sprintf(buf, "%s\n", integrator_fpga_str(integrator_coreid));
|
||||||
|
}
|
||||||
|
|
||||||
|
static struct device_attribute integrator_fpga_attr =
|
||||||
|
__ATTR(fpga, S_IRUGO, integrator_get_fpga, NULL);
|
||||||
|
|
||||||
|
static ssize_t integrator_get_build(struct device *dev,
|
||||||
|
struct device_attribute *attr,
|
||||||
|
char *buf)
|
||||||
|
{
|
||||||
|
return sprintf(buf, "%02x\n", (integrator_coreid >> 4) & 0xFF);
|
||||||
|
}
|
||||||
|
|
||||||
|
static struct device_attribute integrator_build_attr =
|
||||||
|
__ATTR(build, S_IRUGO, integrator_get_build, NULL);
|
||||||
|
|
||||||
|
static int __init integrator_soc_init(void)
|
||||||
|
{
|
||||||
|
static struct regmap *syscon_regmap;
|
||||||
|
struct soc_device *soc_dev;
|
||||||
|
struct soc_device_attribute *soc_dev_attr;
|
||||||
|
struct device_node *np;
|
||||||
|
struct device *dev;
|
||||||
|
u32 val;
|
||||||
|
int ret;
|
||||||
|
|
||||||
|
np = of_find_matching_node(NULL, integrator_cm_match);
|
||||||
|
if (!np)
|
||||||
|
return -ENODEV;
|
||||||
|
|
||||||
|
syscon_regmap = syscon_node_to_regmap(np);
|
||||||
|
if (IS_ERR(syscon_regmap))
|
||||||
|
return PTR_ERR(syscon_regmap);
|
||||||
|
|
||||||
|
ret = regmap_read(syscon_regmap, INTEGRATOR_HDR_ID_OFFSET,
|
||||||
|
&val);
|
||||||
|
if (ret)
|
||||||
|
return -ENODEV;
|
||||||
|
integrator_coreid = val;
|
||||||
|
|
||||||
|
soc_dev_attr = kzalloc(sizeof(*soc_dev_attr), GFP_KERNEL);
|
||||||
|
if (!soc_dev_attr)
|
||||||
|
return -ENOMEM;
|
||||||
|
|
||||||
|
soc_dev_attr->soc_id = "Integrator";
|
||||||
|
soc_dev_attr->machine = "Integrator";
|
||||||
|
soc_dev_attr->family = "Versatile";
|
||||||
|
soc_dev = soc_device_register(soc_dev_attr);
|
||||||
|
if (IS_ERR(soc_dev)) {
|
||||||
|
kfree(soc_dev_attr);
|
||||||
|
return -ENODEV;
|
||||||
|
}
|
||||||
|
dev = soc_device_to_device(soc_dev);
|
||||||
|
|
||||||
|
device_create_file(dev, &integrator_manf_attr);
|
||||||
|
device_create_file(dev, &integrator_arch_attr);
|
||||||
|
device_create_file(dev, &integrator_fpga_attr);
|
||||||
|
device_create_file(dev, &integrator_build_attr);
|
||||||
|
|
||||||
|
dev_info(dev, "Detected ARM core module:\n");
|
||||||
|
dev_info(dev, " Manufacturer: %02x\n", (val >> 24));
|
||||||
|
dev_info(dev, " Architecture: %s\n", integrator_arch_str(val));
|
||||||
|
dev_info(dev, " FPGA: %s\n", integrator_fpga_str(val));
|
||||||
|
dev_info(dev, " Build: %02x\n", (val >> 4) & 0xFF);
|
||||||
|
dev_info(dev, " Rev: %c\n", ('A' + (val & 0x03)));
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
device_initcall(integrator_soc_init);
|
Loading…
Reference in New Issue
Block a user