Merge tag 'integrator-v3.19-arm-soc-2' of git://git.kernel.org/pub/scm/linux/kernel...
authorArnd Bergmann <arnd@arndb.de>
Thu, 20 Nov 2014 16:13:55 +0000 (17:13 +0100)
committerArnd Bergmann <arnd@arndb.de>
Thu, 20 Nov 2014 16:13:55 +0000 (17:13 +0100)
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>
14 files changed:
arch/arm/boot/dts/integrator.dtsi
arch/arm/mach-integrator/Kconfig
arch/arm/mach-integrator/Makefile
arch/arm/mach-integrator/cm.h
arch/arm/mach-integrator/common.h
arch/arm/mach-integrator/core.c
arch/arm/mach-integrator/integrator_ap.c
arch/arm/mach-integrator/integrator_cp.c
arch/arm/mach-integrator/leds.c [deleted file]
drivers/clocksource/Makefile
drivers/clocksource/timer-integrator-ap.c [new file with mode: 0644]
drivers/soc/versatile/Kconfig
drivers/soc/versatile/Makefile
drivers/soc/versatile/soc-integrator.c [new file with mode: 0644]

index 88e3d477bf16394b0f789d855cabea0ae6217b9e..28e38f8c6b0fe46c743b75e5e207089e371bdc5e 100644 (file)
@@ -6,8 +6,18 @@
 
 / {
        core-module@10000000 {
-               compatible = "arm,core-module-integrator";
+               compatible = "arm,core-module-integrator", "syscon";
                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 {
                        reg = <0x19000000 0x1000>;
                        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";
+                       };
+               };
        };
 };
index aa7eb272e602f07acd9eb8eb60dfae61bf322f4d..02d083489a2641ac5f9d71ca390e53a4965c1570 100644 (file)
@@ -8,8 +8,13 @@ config ARCH_INTEGRATOR
        select GENERIC_CLOCKEVENTS
        select HAVE_TCM
        select ICST
+       select MFD_SYSCON
        select MULTI_IRQ_HANDLER
        select PLAT_VERSATILE
+       select POWER_RESET
+       select POWER_RESET_VERSATILE
+       select POWER_SUPPLY
+       select SOC_INTEGRATOR_CM
        select SPARSE_IRQ
        select USE_OF
        select VERSATILE_FPGA_IRQ
index ec759ded7b609c541204b9ec72dd5814b8c6dea0..1ebe45356b09ca18b85a7dc1da4b0e012685e885 100644 (file)
@@ -4,7 +4,7 @@
 
 # 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_CP)       += integrator_cp.o
 
index 4ecff7bff482e4b6d2108d5f1ec1d417d884ee3c..5b8ba8247f45404d7d4c6d8f318a9295e9ce6e15 100644 (file)
@@ -11,7 +11,6 @@ void cm_clear_irqs(void);
 #define CM_CTRL_LED                    (1 << 0)
 #define CM_CTRL_nMBDET                 (1 << 1)
 #define CM_CTRL_REMAP                  (1 << 2)
-#define CM_CTRL_RESET                  (1 << 3)
 
 /*
  * Integrator/AP,PP2 specific
index ad0ac5547b2c6284988ffba604cd7dae1d83a9c5..96c9dc56cabfc2644d4cf7c832c26d4e87651574 100644 (file)
@@ -4,5 +4,3 @@ extern struct amba_pl010_data ap_uart_data;
 void integrator_init_early(void);
 int integrator_init(bool is_cp);
 void integrator_reserve(void);
-void integrator_restart(enum reboot_mode, const char *);
-void integrator_init_sysfs(struct device *parent, u32 id);
index e3f3aca43efbe65bc9a05e59aa429359ab56918d..948872a419c192e8c66ab287b7128adcdebe365a 100644 (file)
@@ -60,40 +60,6 @@ void cm_control(u32 mask, u32 set)
        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)
 {
        /* disable core module IRQs */
@@ -109,7 +75,6 @@ static const struct of_device_id cm_match[] = {
 void cm_init(void)
 {
        struct device_node *cm = of_find_matching_node(NULL, cm_match);
-       u32 val;
 
        if (!cm) {
                pr_crit("no core module node found in device tree\n");
@@ -121,13 +86,6 @@ void cm_init(void)
                return;
        }
        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);
 }
-
-/*
- * 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);
-}
index 8ca290b479b1ffb04eb931db39183999caa1b7d8..30003ba447a580563428a644ca93d22c9865ea2e 100644 (file)
 #include <linux/syscore_ops.h>
 #include <linux/amba/bus.h>
 #include <linux/amba/kmi.h>
-#include <linux/clocksource.h>
-#include <linux/clockchips.h>
-#include <linux/interrupt.h>
 #include <linux/io.h>
 #include <linux/irqchip.h>
 #include <linux/mtd/physmap.h>
-#include <linux/clk.h>
 #include <linux/platform_data/clk-integrator.h>
 #include <linux/of_irq.h>
 #include <linux/of_address.h>
 #include <linux/of_platform.h>
 #include <linux/stat.h>
-#include <linux/sys_soc.h>
 #include <linux/termios.h>
-#include <linux/sched_clock.h>
-#include <linux/clk-provider.h>
 
 #include <asm/hardware/arm_timer.h>
 #include <asm/setup.h>
@@ -89,11 +82,6 @@ static void __iomem *ebi_base;
 
 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),
                .pfn            = __phys_to_pfn(INTEGRATOR_IC_BASE),
                .length         = SZ_4K,
@@ -257,188 +245,10 @@ struct amba_pl010_data ap_uart_data = {
        .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)
 {
 }
 
-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)
 {
        cm_init();
@@ -477,10 +287,6 @@ static void __init ap_init_of(void)
        unsigned long sc_dec;
        struct device_node *syscon;
        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;
 
        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,
                        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);
        for (i = 0; i < 4; i++) {
                struct lm_device *lmdev;
@@ -553,8 +337,6 @@ DT_MACHINE_START(INTEGRATOR_AP_DT, "ARM Integrator/AP (Device Tree)")
        .map_io         = ap_map_io,
        .init_early     = ap_init_early,
        .init_irq       = ap_init_irq_of,
-       .init_time      = ap_of_timer_init,
        .init_machine   = ap_init_of,
-       .restart        = integrator_restart,
        .dt_compat      = ap_dt_board_compat,
 MACHINE_END
index cca02eb75eb5680674eb05e9728d1bfed9dfd97d..b5fb71a36ee63961899709af0f5332fb7ee0a062 100644 (file)
@@ -27,7 +27,6 @@
 #include <linux/of_irq.h>
 #include <linux/of_address.h>
 #include <linux/of_platform.h>
-#include <linux/sys_soc.h>
 #include <linux/sched_clock.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)
 {
        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);
        if (!cpcon)
@@ -289,28 +284,6 @@ static void __init intcp_init_of(void)
 
        of_platform_populate(NULL, of_default_bus_match_table,
                             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[] = {
@@ -324,6 +297,5 @@ DT_MACHINE_START(INTEGRATOR_CP_DT, "ARM Integrator/CP (Device Tree)")
        .init_early     = intcp_init_early,
        .init_irq       = intcp_init_irq_of,
        .init_machine   = intcp_init_of,
-       .restart        = integrator_restart,
        .dt_compat      = intcp_dt_board_compat,
 MACHINE_END
diff --git a/arch/arm/mach-integrator/leds.c b/arch/arm/mach-integrator/leds.c
deleted file mode 100644 (file)
index f1dcb57..0000000
+++ /dev/null
@@ -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
index 756f6f10efa03de825a9b1ef48edf8315f331161..fae0435cc23d580df6c3e192051a4526cdb08acb 100644 (file)
@@ -45,4 +45,5 @@ obj-$(CONFIG_ARM_GLOBAL_TIMER)                += arm_global_timer.o
 obj-$(CONFIG_CLKSRC_METAG_GENERIC)     += metag_generic.o
 obj-$(CONFIG_ARCH_HAS_TICK_BROADCAST)  += dummy_timer.o
 obj-$(CONFIG_ARCH_KEYSTONE)            += timer-keystone.o
+obj-$(CONFIG_ARCH_INTEGRATOR_AP)       += timer-integrator-ap.o
 obj-$(CONFIG_CLKSRC_VERSATILE)         += versatile.o
diff --git a/drivers/clocksource/timer-integrator-ap.c b/drivers/clocksource/timer-integrator-ap.c
new file mode 100644 (file)
index 0000000..b9efd30
--- /dev/null
@@ -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);
index bf5ee9c8533094592d40a0328d0d5caffeb80fda..a928a7fc6be4b03aab6d3efa2b44d2bdf03dd871 100644 (file)
@@ -1,6 +1,15 @@
 #
 # 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
        bool "SoC bus device for the ARM RealView platforms"
        depends on ARCH_REALVIEW
index ad547435648ebd9638061a5e665cad771da90bef..cf612fe3a659709ab969ffbdcad5e797b9561b7a 100644 (file)
@@ -1 +1,2 @@
+obj-$(CONFIG_SOC_INTEGRATOR_CM)        += soc-integrator.o
 obj-$(CONFIG_SOC_REALVIEW)     += soc-realview.o
diff --git a/drivers/soc/versatile/soc-integrator.c b/drivers/soc/versatile/soc-integrator.c
new file mode 100644 (file)
index 0000000..ccaa537
--- /dev/null
@@ -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);