diff options
| author | Arnd Bergmann <arnd@arndb.de> | 2014-11-20 11:13:55 -0500 |
|---|---|---|
| committer | Arnd Bergmann <arnd@arndb.de> | 2014-11-20 11:13:55 -0500 |
| commit | 4eca459bc10d8400407d0fc04e90dac45b571c87 (patch) | |
| tree | 02dac5128653db41bc732c3649402b99d70d4c41 | |
| parent | d686ce4204c5dc131396f1fca81beebc46cb8cdb (diff) | |
| parent | f956a785a282f6b5a3e7d59937548f8b7c04d1ac (diff) | |
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>
| -rw-r--r-- | arch/arm/boot/dts/integrator.dtsi | 48 | ||||
| -rw-r--r-- | arch/arm/mach-integrator/Kconfig | 5 | ||||
| -rw-r--r-- | arch/arm/mach-integrator/Makefile | 2 | ||||
| -rw-r--r-- | arch/arm/mach-integrator/cm.h | 1 | ||||
| -rw-r--r-- | arch/arm/mach-integrator/common.h | 2 | ||||
| -rw-r--r-- | arch/arm/mach-integrator/core.c | 103 | ||||
| -rw-r--r-- | arch/arm/mach-integrator/integrator_ap.c | 218 | ||||
| -rw-r--r-- | arch/arm/mach-integrator/integrator_cp.c | 28 | ||||
| -rw-r--r-- | arch/arm/mach-integrator/leds.c | 124 | ||||
| -rw-r--r-- | drivers/clocksource/Makefile | 1 | ||||
| -rw-r--r-- | drivers/clocksource/timer-integrator-ap.c | 210 | ||||
| -rw-r--r-- | drivers/soc/versatile/Kconfig | 9 | ||||
| -rw-r--r-- | drivers/soc/versatile/Makefile | 1 | ||||
| -rw-r--r-- | drivers/soc/versatile/soc-integrator.c | 154 |
14 files changed, 428 insertions, 478 deletions
diff --git a/arch/arm/boot/dts/integrator.dtsi b/arch/arm/boot/dts/integrator.dtsi index 88e3d477bf16..28e38f8c6b0f 100644 --- a/arch/arm/boot/dts/integrator.dtsi +++ b/arch/arm/boot/dts/integrator.dtsi | |||
| @@ -6,8 +6,18 @@ | |||
| 6 | 6 | ||
| 7 | / { | 7 | / { |
| 8 | core-module@10000000 { | 8 | core-module@10000000 { |
| 9 | compatible = "arm,core-module-integrator"; | 9 | compatible = "arm,core-module-integrator", "syscon"; |
| 10 | reg = <0x10000000 0x200>; | 10 | reg = <0x10000000 0x200>; |
| 11 | |||
| 12 | /* Use core module LED to indicate CPU load */ | ||
| 13 | led@0c.0 { | ||
| 14 | compatible = "register-bit-led"; | ||
| 15 | offset = <0x0c>; | ||
| 16 | mask = <0x01>; | ||
| 17 | label = "integrator:core_module"; | ||
| 18 | linux,default-trigger = "cpu0"; | ||
| 19 | default-state = "on"; | ||
| 20 | }; | ||
| 11 | }; | 21 | }; |
| 12 | 22 | ||
| 13 | ebi@12000000 { | 23 | ebi@12000000 { |
| @@ -82,5 +92,41 @@ | |||
| 82 | reg = <0x19000000 0x1000>; | 92 | reg = <0x19000000 0x1000>; |
| 83 | interrupts = <4>; | 93 | interrupts = <4>; |
| 84 | }; | 94 | }; |
| 95 | |||
| 96 | syscon { | ||
| 97 | /* Debug registers mapped as syscon */ | ||
| 98 | compatible = "syscon"; | ||
| 99 | reg = <0x1a000000 0x10>; | ||
| 100 | |||
| 101 | led@04.0 { | ||
| 102 | compatible = "register-bit-led"; | ||
| 103 | offset = <0x04>; | ||
| 104 | mask = <0x01>; | ||
| 105 | label = "integrator:green0"; | ||
| 106 | linux,default-trigger = "heartbeat"; | ||
| 107 | default-state = "on"; | ||
| 108 | }; | ||
| 109 | led@04.1 { | ||
| 110 | compatible = "register-bit-led"; | ||
| 111 | offset = <0x04>; | ||
| 112 | mask = <0x02>; | ||
| 113 | label = "integrator:yellow"; | ||
| 114 | default-state = "off"; | ||
| 115 | }; | ||
| 116 | led@04.2 { | ||
| 117 | compatible = "register-bit-led"; | ||
| 118 | offset = <0x04>; | ||
| 119 | mask = <0x04>; | ||
| 120 | label = "integrator:red"; | ||
| 121 | default-state = "off"; | ||
| 122 | }; | ||
| 123 | led@04.3 { | ||
| 124 | compatible = "register-bit-led"; | ||
| 125 | offset = <0x04>; | ||
| 126 | mask = <0x08>; | ||
| 127 | label = "integrator:green1"; | ||
| 128 | default-state = "off"; | ||
| 129 | }; | ||
| 130 | }; | ||
| 85 | }; | 131 | }; |
| 86 | }; | 132 | }; |
diff --git a/arch/arm/mach-integrator/Kconfig b/arch/arm/mach-integrator/Kconfig index aa7eb272e602..02d083489a26 100644 --- a/arch/arm/mach-integrator/Kconfig +++ b/arch/arm/mach-integrator/Kconfig | |||
| @@ -8,8 +8,13 @@ config ARCH_INTEGRATOR | |||
| 8 | select GENERIC_CLOCKEVENTS | 8 | select GENERIC_CLOCKEVENTS |
| 9 | select HAVE_TCM | 9 | select HAVE_TCM |
| 10 | select ICST | 10 | select ICST |
| 11 | select MFD_SYSCON | ||
| 11 | select MULTI_IRQ_HANDLER | 12 | select MULTI_IRQ_HANDLER |
| 12 | select PLAT_VERSATILE | 13 | select PLAT_VERSATILE |
| 14 | select POWER_RESET | ||
| 15 | select POWER_RESET_VERSATILE | ||
| 16 | select POWER_SUPPLY | ||
| 17 | select SOC_INTEGRATOR_CM | ||
| 13 | select SPARSE_IRQ | 18 | select SPARSE_IRQ |
| 14 | select USE_OF | 19 | select USE_OF |
| 15 | select VERSATILE_FPGA_IRQ | 20 | select VERSATILE_FPGA_IRQ |
diff --git a/arch/arm/mach-integrator/Makefile b/arch/arm/mach-integrator/Makefile index ec759ded7b60..1ebe45356b09 100644 --- a/arch/arm/mach-integrator/Makefile +++ b/arch/arm/mach-integrator/Makefile | |||
| @@ -4,7 +4,7 @@ | |||
| 4 | 4 | ||
| 5 | # Object file lists. | 5 | # Object file lists. |
| 6 | 6 | ||
| 7 | obj-y := core.o lm.o leds.o | 7 | obj-y := core.o lm.o |
| 8 | obj-$(CONFIG_ARCH_INTEGRATOR_AP) += integrator_ap.o | 8 | obj-$(CONFIG_ARCH_INTEGRATOR_AP) += integrator_ap.o |
| 9 | obj-$(CONFIG_ARCH_INTEGRATOR_CP) += integrator_cp.o | 9 | obj-$(CONFIG_ARCH_INTEGRATOR_CP) += integrator_cp.o |
| 10 | 10 | ||
diff --git a/arch/arm/mach-integrator/cm.h b/arch/arm/mach-integrator/cm.h index 4ecff7bff482..5b8ba8247f45 100644 --- a/arch/arm/mach-integrator/cm.h +++ b/arch/arm/mach-integrator/cm.h | |||
| @@ -11,7 +11,6 @@ void cm_clear_irqs(void); | |||
| 11 | #define CM_CTRL_LED (1 << 0) | 11 | #define CM_CTRL_LED (1 << 0) |
| 12 | #define CM_CTRL_nMBDET (1 << 1) | 12 | #define CM_CTRL_nMBDET (1 << 1) |
| 13 | #define CM_CTRL_REMAP (1 << 2) | 13 | #define CM_CTRL_REMAP (1 << 2) |
| 14 | #define CM_CTRL_RESET (1 << 3) | ||
| 15 | 14 | ||
| 16 | /* | 15 | /* |
| 17 | * Integrator/AP,PP2 specific | 16 | * Integrator/AP,PP2 specific |
diff --git a/arch/arm/mach-integrator/common.h b/arch/arm/mach-integrator/common.h index ad0ac5547b2c..96c9dc56cabf 100644 --- a/arch/arm/mach-integrator/common.h +++ b/arch/arm/mach-integrator/common.h | |||
| @@ -4,5 +4,3 @@ extern struct amba_pl010_data ap_uart_data; | |||
| 4 | void integrator_init_early(void); | 4 | void integrator_init_early(void); |
| 5 | int integrator_init(bool is_cp); | 5 | int integrator_init(bool is_cp); |
| 6 | void integrator_reserve(void); | 6 | void integrator_reserve(void); |
| 7 | void integrator_restart(enum reboot_mode, const char *); | ||
| 8 | void integrator_init_sysfs(struct device *parent, u32 id); | ||
diff --git a/arch/arm/mach-integrator/core.c b/arch/arm/mach-integrator/core.c index e3f3aca43efb..948872a419c1 100644 --- a/arch/arm/mach-integrator/core.c +++ b/arch/arm/mach-integrator/core.c | |||
| @@ -60,40 +60,6 @@ void cm_control(u32 mask, u32 set) | |||
| 60 | raw_spin_unlock_irqrestore(&cm_lock, flags); | 60 | raw_spin_unlock_irqrestore(&cm_lock, flags); |
| 61 | } | 61 | } |
| 62 | 62 | ||
| 63 | static const char *integrator_arch_str(u32 id) | ||
| 64 | { | ||
| 65 | switch ((id >> 16) & 0xff) { | ||
| 66 | case 0x00: | ||
| 67 | return "ASB little-endian"; | ||
| 68 | case 0x01: | ||
| 69 | return "AHB little-endian"; | ||
| 70 | case 0x03: | ||
| 71 | return "AHB-Lite system bus, bi-endian"; | ||
| 72 | case 0x04: | ||
| 73 | return "AHB"; | ||
| 74 | case 0x08: | ||
| 75 | return "AHB system bus, ASB processor bus"; | ||
| 76 | default: | ||
| 77 | return "Unknown"; | ||
| 78 | } | ||
| 79 | } | ||
| 80 | |||
| 81 | static const char *integrator_fpga_str(u32 id) | ||
| 82 | { | ||
| 83 | switch ((id >> 12) & 0xf) { | ||
| 84 | case 0x01: | ||
| 85 | return "XC4062"; | ||
| 86 | case 0x02: | ||
| 87 | return "XC4085"; | ||
| 88 | case 0x03: | ||
| 89 | return "XVC600"; | ||
| 90 | case 0x04: | ||
| 91 | return "EPM7256AE (Altera PLD)"; | ||
| 92 | default: | ||
| 93 | return "Unknown"; | ||
| 94 | } | ||
| 95 | } | ||
| 96 | |||
| 97 | void cm_clear_irqs(void) | 63 | void cm_clear_irqs(void) |
| 98 | { | 64 | { |
| 99 | /* disable core module IRQs */ | 65 | /* disable core module IRQs */ |
| @@ -109,7 +75,6 @@ static const struct of_device_id cm_match[] = { | |||
| 109 | void cm_init(void) | 75 | void cm_init(void) |
| 110 | { | 76 | { |
| 111 | struct device_node *cm = of_find_matching_node(NULL, cm_match); | 77 | struct device_node *cm = of_find_matching_node(NULL, cm_match); |
| 112 | u32 val; | ||
| 113 | 78 | ||
| 114 | if (!cm) { | 79 | if (!cm) { |
| 115 | pr_crit("no core module node found in device tree\n"); | 80 | pr_crit("no core module node found in device tree\n"); |
| @@ -121,13 +86,6 @@ void cm_init(void) | |||
| 121 | return; | 86 | return; |
| 122 | } | 87 | } |
| 123 | cm_clear_irqs(); | 88 | cm_clear_irqs(); |
| 124 | val = readl(cm_base + INTEGRATOR_HDR_ID_OFFSET); | ||
| 125 | pr_info("Detected ARM core module:\n"); | ||
| 126 | pr_info(" Manufacturer: %02x\n", (val >> 24)); | ||
| 127 | pr_info(" Architecture: %s\n", integrator_arch_str(val)); | ||
| 128 | pr_info(" FPGA: %s\n", integrator_fpga_str(val)); | ||
| 129 | pr_info(" Build: %02x\n", (val >> 4) & 0xFF); | ||
| 130 | pr_info(" Rev: %c\n", ('A' + (val & 0x03))); | ||
| 131 | } | 89 | } |
| 132 | 90 | ||
| 133 | /* | 91 | /* |
| @@ -139,64 +97,3 @@ void __init integrator_reserve(void) | |||
| 139 | { | 97 | { |
| 140 | memblock_reserve(PHYS_OFFSET, __pa(swapper_pg_dir) - PHYS_OFFSET); | 98 | memblock_reserve(PHYS_OFFSET, __pa(swapper_pg_dir) - PHYS_OFFSET); |
| 141 | } | 99 | } |
| 142 | |||
| 143 | /* | ||
| 144 | * To reset, we hit the on-board reset register in the system FPGA | ||
| 145 | */ | ||
| 146 | void integrator_restart(enum reboot_mode mode, const char *cmd) | ||
| 147 | { | ||
| 148 | cm_control(CM_CTRL_RESET, CM_CTRL_RESET); | ||
| 149 | } | ||
| 150 | |||
| 151 | static u32 integrator_id; | ||
| 152 | |||
| 153 | static ssize_t intcp_get_manf(struct device *dev, | ||
| 154 | struct device_attribute *attr, | ||
| 155 | char *buf) | ||
| 156 | { | ||
| 157 | return sprintf(buf, "%02x\n", integrator_id >> 24); | ||
| 158 | } | ||
| 159 | |||
| 160 | static struct device_attribute intcp_manf_attr = | ||
| 161 | __ATTR(manufacturer, S_IRUGO, intcp_get_manf, NULL); | ||
| 162 | |||
| 163 | static ssize_t intcp_get_arch(struct device *dev, | ||
| 164 | struct device_attribute *attr, | ||
| 165 | char *buf) | ||
| 166 | { | ||
| 167 | return sprintf(buf, "%s\n", integrator_arch_str(integrator_id)); | ||
| 168 | } | ||
| 169 | |||
| 170 | static struct device_attribute intcp_arch_attr = | ||
| 171 | __ATTR(architecture, S_IRUGO, intcp_get_arch, NULL); | ||
| 172 | |||
| 173 | static ssize_t intcp_get_fpga(struct device *dev, | ||
| 174 | struct device_attribute *attr, | ||
| 175 | char *buf) | ||
| 176 | { | ||
| 177 | return sprintf(buf, "%s\n", integrator_fpga_str(integrator_id)); | ||
| 178 | } | ||
| 179 | |||
| 180 | static struct device_attribute intcp_fpga_attr = | ||
| 181 | __ATTR(fpga, S_IRUGO, intcp_get_fpga, NULL); | ||
| 182 | |||
| 183 | static ssize_t intcp_get_build(struct device *dev, | ||
| 184 | struct device_attribute *attr, | ||
| 185 | char *buf) | ||
| 186 | { | ||
| 187 | return sprintf(buf, "%02x\n", (integrator_id >> 4) & 0xFF); | ||
| 188 | } | ||
| 189 | |||
| 190 | static struct device_attribute intcp_build_attr = | ||
| 191 | __ATTR(build, S_IRUGO, intcp_get_build, NULL); | ||
| 192 | |||
| 193 | |||
| 194 | |||
| 195 | void integrator_init_sysfs(struct device *parent, u32 id) | ||
| 196 | { | ||
| 197 | integrator_id = id; | ||
| 198 | device_create_file(parent, &intcp_manf_attr); | ||
| 199 | device_create_file(parent, &intcp_arch_attr); | ||
| 200 | device_create_file(parent, &intcp_fpga_attr); | ||
| 201 | device_create_file(parent, &intcp_build_attr); | ||
| 202 | } | ||
diff --git a/arch/arm/mach-integrator/integrator_ap.c b/arch/arm/mach-integrator/integrator_ap.c index 8ca290b479b1..30003ba447a5 100644 --- a/arch/arm/mach-integrator/integrator_ap.c +++ b/arch/arm/mach-integrator/integrator_ap.c | |||
| @@ -27,22 +27,15 @@ | |||
| 27 | #include <linux/syscore_ops.h> | 27 | #include <linux/syscore_ops.h> |
| 28 | #include <linux/amba/bus.h> | 28 | #include <linux/amba/bus.h> |
| 29 | #include <linux/amba/kmi.h> | 29 | #include <linux/amba/kmi.h> |
| 30 | #include <linux/clocksource.h> | ||
| 31 | #include <linux/clockchips.h> | ||
| 32 | #include <linux/interrupt.h> | ||
| 33 | #include <linux/io.h> | 30 | #include <linux/io.h> |
| 34 | #include <linux/irqchip.h> | 31 | #include <linux/irqchip.h> |
| 35 | #include <linux/mtd/physmap.h> | 32 | #include <linux/mtd/physmap.h> |
| 36 | #include <linux/clk.h> | ||
| 37 | #include <linux/platform_data/clk-integrator.h> | 33 | #include <linux/platform_data/clk-integrator.h> |
| 38 | #include <linux/of_irq.h> | 34 | #include <linux/of_irq.h> |
| 39 | #include <linux/of_address.h> | 35 | #include <linux/of_address.h> |
| 40 | #include <linux/of_platform.h> | 36 | #include <linux/of_platform.h> |
| 41 | #include <linux/stat.h> | 37 | #include <linux/stat.h> |
| 42 | #include <linux/sys_soc.h> | ||
| 43 | #include <linux/termios.h> | 38 | #include <linux/termios.h> |
| 44 | #include <linux/sched_clock.h> | ||
| 45 | #include <linux/clk-provider.h> | ||
| 46 | 39 | ||
| 47 | #include <asm/hardware/arm_timer.h> | 40 | #include <asm/hardware/arm_timer.h> |
| 48 | #include <asm/setup.h> | 41 | #include <asm/setup.h> |
| @@ -89,11 +82,6 @@ static void __iomem *ebi_base; | |||
| 89 | 82 | ||
| 90 | static struct map_desc ap_io_desc[] __initdata __maybe_unused = { | 83 | static struct map_desc ap_io_desc[] __initdata __maybe_unused = { |
| 91 | { | 84 | { |
| 92 | .virtual = IO_ADDRESS(INTEGRATOR_CT_BASE), | ||
| 93 | .pfn = __phys_to_pfn(INTEGRATOR_CT_BASE), | ||
| 94 | .length = SZ_4K, | ||
| 95 | .type = MT_DEVICE | ||
| 96 | }, { | ||
| 97 | .virtual = IO_ADDRESS(INTEGRATOR_IC_BASE), | 85 | .virtual = IO_ADDRESS(INTEGRATOR_IC_BASE), |
| 98 | .pfn = __phys_to_pfn(INTEGRATOR_IC_BASE), | 86 | .pfn = __phys_to_pfn(INTEGRATOR_IC_BASE), |
| 99 | .length = SZ_4K, | 87 | .length = SZ_4K, |
| @@ -257,188 +245,10 @@ struct amba_pl010_data ap_uart_data = { | |||
| 257 | .set_mctrl = integrator_uart_set_mctrl, | 245 | .set_mctrl = integrator_uart_set_mctrl, |
| 258 | }; | 246 | }; |
| 259 | 247 | ||
| 260 | /* | ||
| 261 | * Where is the timer (VA)? | ||
| 262 | */ | ||
| 263 | #define TIMER0_VA_BASE __io_address(INTEGRATOR_TIMER0_BASE) | ||
| 264 | #define TIMER1_VA_BASE __io_address(INTEGRATOR_TIMER1_BASE) | ||
| 265 | #define TIMER2_VA_BASE __io_address(INTEGRATOR_TIMER2_BASE) | ||
| 266 | |||
| 267 | static unsigned long timer_reload; | ||
| 268 | |||
| 269 | static u64 notrace integrator_read_sched_clock(void) | ||
| 270 | { | ||
| 271 | return -readl((void __iomem *) TIMER2_VA_BASE + TIMER_VALUE); | ||
| 272 | } | ||
| 273 | |||
| 274 | static void integrator_clocksource_init(unsigned long inrate, | ||
| 275 | void __iomem *base) | ||
| 276 | { | ||
| 277 | u32 ctrl = TIMER_CTRL_ENABLE | TIMER_CTRL_PERIODIC; | ||
| 278 | unsigned long rate = inrate; | ||
| 279 | |||
| 280 | if (rate >= 1500000) { | ||
| 281 | rate /= 16; | ||
| 282 | ctrl |= TIMER_CTRL_DIV16; | ||
| 283 | } | ||
| 284 | |||
| 285 | writel(0xffff, base + TIMER_LOAD); | ||
| 286 | writel(ctrl, base + TIMER_CTRL); | ||
| 287 | |||
| 288 | clocksource_mmio_init(base + TIMER_VALUE, "timer2", | ||
| 289 | rate, 200, 16, clocksource_mmio_readl_down); | ||
| 290 | sched_clock_register(integrator_read_sched_clock, 16, rate); | ||
| 291 | } | ||
| 292 | |||
| 293 | static void __iomem * clkevt_base; | ||
| 294 | |||
| 295 | /* | ||
| 296 | * IRQ handler for the timer | ||
| 297 | */ | ||
| 298 | static irqreturn_t integrator_timer_interrupt(int irq, void *dev_id) | ||
| 299 | { | ||
| 300 | struct clock_event_device *evt = dev_id; | ||
| 301 | |||
| 302 | /* clear the interrupt */ | ||
| 303 | writel(1, clkevt_base + TIMER_INTCLR); | ||
| 304 | |||
| 305 | evt->event_handler(evt); | ||
| 306 | |||
| 307 | return IRQ_HANDLED; | ||
| 308 | } | ||
| 309 | |||
| 310 | static void clkevt_set_mode(enum clock_event_mode mode, struct clock_event_device *evt) | ||
| 311 | { | ||
| 312 | u32 ctrl = readl(clkevt_base + TIMER_CTRL) & ~TIMER_CTRL_ENABLE; | ||
| 313 | |||
| 314 | /* Disable timer */ | ||
| 315 | writel(ctrl, clkevt_base + TIMER_CTRL); | ||
| 316 | |||
| 317 | switch (mode) { | ||
| 318 | case CLOCK_EVT_MODE_PERIODIC: | ||
| 319 | /* Enable the timer and start the periodic tick */ | ||
| 320 | writel(timer_reload, clkevt_base + TIMER_LOAD); | ||
| 321 | ctrl |= TIMER_CTRL_PERIODIC | TIMER_CTRL_ENABLE; | ||
| 322 | writel(ctrl, clkevt_base + TIMER_CTRL); | ||
| 323 | break; | ||
| 324 | case CLOCK_EVT_MODE_ONESHOT: | ||
| 325 | /* Leave the timer disabled, .set_next_event will enable it */ | ||
| 326 | ctrl &= ~TIMER_CTRL_PERIODIC; | ||
| 327 | writel(ctrl, clkevt_base + TIMER_CTRL); | ||
| 328 | break; | ||
| 329 | case CLOCK_EVT_MODE_UNUSED: | ||
| 330 | case CLOCK_EVT_MODE_SHUTDOWN: | ||
| 331 | case CLOCK_EVT_MODE_RESUME: | ||
| 332 | default: | ||
| 333 | /* Just leave in disabled state */ | ||
| 334 | break; | ||
| 335 | } | ||
| 336 | |||
| 337 | } | ||
| 338 | |||
| 339 | static int clkevt_set_next_event(unsigned long next, struct clock_event_device *evt) | ||
| 340 | { | ||
| 341 | unsigned long ctrl = readl(clkevt_base + TIMER_CTRL); | ||
| 342 | |||
| 343 | writel(ctrl & ~TIMER_CTRL_ENABLE, clkevt_base + TIMER_CTRL); | ||
| 344 | writel(next, clkevt_base + TIMER_LOAD); | ||
| 345 | writel(ctrl | TIMER_CTRL_ENABLE, clkevt_base + TIMER_CTRL); | ||
| 346 | |||
| 347 | return 0; | ||
| 348 | } | ||
| 349 | |||
| 350 | static struct clock_event_device integrator_clockevent = { | ||
| 351 | .name = "timer1", | ||
| 352 | .features = CLOCK_EVT_FEAT_PERIODIC | CLOCK_EVT_FEAT_ONESHOT, | ||
| 353 | .set_mode = clkevt_set_mode, | ||
| 354 | .set_next_event = clkevt_set_next_event, | ||
| 355 | .rating = 300, | ||
| 356 | }; | ||
| 357 | |||
| 358 | static struct irqaction integrator_timer_irq = { | ||
| 359 | .name = "timer", | ||
| 360 | .flags = IRQF_TIMER | IRQF_IRQPOLL, | ||
| 361 | .handler = integrator_timer_interrupt, | ||
| 362 | .dev_id = &integrator_clockevent, | ||
| 363 | }; | ||
| 364 | |||
| 365 | static void integrator_clockevent_init(unsigned long inrate, | ||
| 366 | void __iomem *base, int irq) | ||
| 367 | { | ||
| 368 | unsigned long rate = inrate; | ||
| 369 | unsigned int ctrl = 0; | ||
| 370 | |||
| 371 | clkevt_base = base; | ||
| 372 | /* Calculate and program a divisor */ | ||
| 373 | if (rate > 0x100000 * HZ) { | ||
| 374 | rate /= 256; | ||
| 375 | ctrl |= TIMER_CTRL_DIV256; | ||
| 376 | } else if (rate > 0x10000 * HZ) { | ||
| 377 | rate /= 16; | ||
| 378 | ctrl |= TIMER_CTRL_DIV16; | ||
| 379 | } | ||
| 380 | timer_reload = rate / HZ; | ||
| 381 | writel(ctrl, clkevt_base + TIMER_CTRL); | ||
| 382 | |||
| 383 | setup_irq(irq, &integrator_timer_irq); | ||
| 384 | clockevents_config_and_register(&integrator_clockevent, | ||
| 385 | rate, | ||
| 386 | 1, | ||
| 387 | 0xffffU); | ||
| 388 | } | ||
| 389 | |||
| 390 | void __init ap_init_early(void) | 248 | void __init ap_init_early(void) |
| 391 | { | 249 | { |
| 392 | } | 250 | } |
| 393 | 251 | ||
| 394 | static void __init ap_of_timer_init(void) | ||
| 395 | { | ||
| 396 | struct device_node *node; | ||
| 397 | const char *path; | ||
| 398 | void __iomem *base; | ||
| 399 | int err; | ||
| 400 | int irq; | ||
| 401 | struct clk *clk; | ||
| 402 | unsigned long rate; | ||
| 403 | |||
| 404 | of_clk_init(NULL); | ||
| 405 | |||
| 406 | err = of_property_read_string(of_aliases, | ||
| 407 | "arm,timer-primary", &path); | ||
| 408 | if (WARN_ON(err)) | ||
| 409 | return; | ||
| 410 | node = of_find_node_by_path(path); | ||
| 411 | base = of_iomap(node, 0); | ||
| 412 | if (WARN_ON(!base)) | ||
| 413 | return; | ||
| 414 | |||
| 415 | clk = of_clk_get(node, 0); | ||
| 416 | BUG_ON(IS_ERR(clk)); | ||
| 417 | clk_prepare_enable(clk); | ||
| 418 | rate = clk_get_rate(clk); | ||
| 419 | |||
| 420 | writel(0, base + TIMER_CTRL); | ||
| 421 | integrator_clocksource_init(rate, base); | ||
| 422 | |||
| 423 | err = of_property_read_string(of_aliases, | ||
| 424 | "arm,timer-secondary", &path); | ||
| 425 | if (WARN_ON(err)) | ||
| 426 | return; | ||
| 427 | node = of_find_node_by_path(path); | ||
| 428 | base = of_iomap(node, 0); | ||
| 429 | if (WARN_ON(!base)) | ||
| 430 | return; | ||
| 431 | irq = irq_of_parse_and_map(node, 0); | ||
| 432 | |||
| 433 | clk = of_clk_get(node, 0); | ||
| 434 | BUG_ON(IS_ERR(clk)); | ||
| 435 | clk_prepare_enable(clk); | ||
| 436 | rate = clk_get_rate(clk); | ||
| 437 | |||
| 438 | writel(0, base + TIMER_CTRL); | ||
| 439 | integrator_clockevent_init(rate, base, irq); | ||
| 440 | } | ||
| 441 | |||
| 442 | static void __init ap_init_irq_of(void) | 252 | static void __init ap_init_irq_of(void) |
| 443 | { | 253 | { |
| 444 | cm_init(); | 254 | cm_init(); |
| @@ -477,10 +287,6 @@ static void __init ap_init_of(void) | |||
| 477 | unsigned long sc_dec; | 287 | unsigned long sc_dec; |
| 478 | struct device_node *syscon; | 288 | struct device_node *syscon; |
| 479 | struct device_node *ebi; | 289 | struct device_node *ebi; |
| 480 | struct device *parent; | ||
| 481 | struct soc_device *soc_dev; | ||
| 482 | struct soc_device_attribute *soc_dev_attr; | ||
| 483 | u32 ap_sc_id; | ||
| 484 | int i; | 290 | int i; |
| 485 | 291 | ||
| 486 | syscon = of_find_matching_node(NULL, ap_syscon_match); | 292 | syscon = of_find_matching_node(NULL, ap_syscon_match); |
| @@ -500,28 +306,6 @@ static void __init ap_init_of(void) | |||
| 500 | of_platform_populate(NULL, of_default_bus_match_table, | 306 | of_platform_populate(NULL, of_default_bus_match_table, |
| 501 | ap_auxdata_lookup, NULL); | 307 | ap_auxdata_lookup, NULL); |
| 502 | 308 | ||
| 503 | ap_sc_id = readl(ap_syscon_base); | ||
| 504 | |||
| 505 | soc_dev_attr = kzalloc(sizeof(*soc_dev_attr), GFP_KERNEL); | ||
| 506 | if (!soc_dev_attr) | ||
| 507 | return; | ||
| 508 | |||
| 509 | soc_dev_attr->soc_id = "XVC"; | ||
| 510 | soc_dev_attr->machine = "Integrator/AP"; | ||
| 511 | soc_dev_attr->family = "Integrator"; | ||
| 512 | soc_dev_attr->revision = kasprintf(GFP_KERNEL, "%c", | ||
| 513 | 'A' + (ap_sc_id & 0x0f)); | ||
| 514 | |||
| 515 | soc_dev = soc_device_register(soc_dev_attr); | ||
| 516 | if (IS_ERR(soc_dev)) { | ||
| 517 | kfree(soc_dev_attr->revision); | ||
| 518 | kfree(soc_dev_attr); | ||
| 519 | return; | ||
| 520 | } | ||
| 521 | |||
| 522 | parent = soc_device_to_device(soc_dev); | ||
| 523 | integrator_init_sysfs(parent, ap_sc_id); | ||
| 524 | |||
| 525 | sc_dec = readl(ap_syscon_base + INTEGRATOR_SC_DEC_OFFSET); | 309 | sc_dec = readl(ap_syscon_base + INTEGRATOR_SC_DEC_OFFSET); |
| 526 | for (i = 0; i < 4; i++) { | 310 | for (i = 0; i < 4; i++) { |
| 527 | struct lm_device *lmdev; | 311 | struct lm_device *lmdev; |
| @@ -553,8 +337,6 @@ DT_MACHINE_START(INTEGRATOR_AP_DT, "ARM Integrator/AP (Device Tree)") | |||
| 553 | .map_io = ap_map_io, | 337 | .map_io = ap_map_io, |
| 554 | .init_early = ap_init_early, | 338 | .init_early = ap_init_early, |
| 555 | .init_irq = ap_init_irq_of, | 339 | .init_irq = ap_init_irq_of, |
| 556 | .init_time = ap_of_timer_init, | ||
| 557 | .init_machine = ap_init_of, | 340 | .init_machine = ap_init_of, |
| 558 | .restart = integrator_restart, | ||
| 559 | .dt_compat = ap_dt_board_compat, | 341 | .dt_compat = ap_dt_board_compat, |
| 560 | MACHINE_END | 342 | MACHINE_END |
diff --git a/arch/arm/mach-integrator/integrator_cp.c b/arch/arm/mach-integrator/integrator_cp.c index cca02eb75eb5..b5fb71a36ee6 100644 --- a/arch/arm/mach-integrator/integrator_cp.c +++ b/arch/arm/mach-integrator/integrator_cp.c | |||
| @@ -27,7 +27,6 @@ | |||
| 27 | #include <linux/of_irq.h> | 27 | #include <linux/of_irq.h> |
| 28 | #include <linux/of_address.h> | 28 | #include <linux/of_address.h> |
| 29 | #include <linux/of_platform.h> | 29 | #include <linux/of_platform.h> |
| 30 | #include <linux/sys_soc.h> | ||
| 31 | #include <linux/sched_clock.h> | 30 | #include <linux/sched_clock.h> |
| 32 | 31 | ||
| 33 | #include <asm/setup.h> | 32 | #include <asm/setup.h> |
| @@ -274,10 +273,6 @@ static const struct of_device_id intcp_syscon_match[] = { | |||
| 274 | static void __init intcp_init_of(void) | 273 | static void __init intcp_init_of(void) |
| 275 | { | 274 | { |
| 276 | struct device_node *cpcon; | 275 | struct device_node *cpcon; |
| 277 | struct device *parent; | ||
| 278 | struct soc_device *soc_dev; | ||
| 279 | struct soc_device_attribute *soc_dev_attr; | ||
| 280 | u32 intcp_sc_id; | ||
| 281 | 276 | ||
| 282 | cpcon = of_find_matching_node(NULL, intcp_syscon_match); | 277 | cpcon = of_find_matching_node(NULL, intcp_syscon_match); |
| 283 | if (!cpcon) | 278 | if (!cpcon) |
| @@ -289,28 +284,6 @@ static void __init intcp_init_of(void) | |||
| 289 | 284 | ||
| 290 | of_platform_populate(NULL, of_default_bus_match_table, | 285 | of_platform_populate(NULL, of_default_bus_match_table, |
| 291 | intcp_auxdata_lookup, NULL); | 286 | intcp_auxdata_lookup, NULL); |
| 292 | |||
| 293 | intcp_sc_id = readl(intcp_con_base); | ||
| 294 | |||
| 295 | soc_dev_attr = kzalloc(sizeof(*soc_dev_attr), GFP_KERNEL); | ||
| 296 | if (!soc_dev_attr) | ||
| 297 | return; | ||
| 298 | |||
| 299 | soc_dev_attr->soc_id = "XCV"; | ||
| 300 | soc_dev_attr->machine = "Integrator/CP"; | ||
| 301 | soc_dev_attr->family = "Integrator"; | ||
| 302 | soc_dev_attr->revision = kasprintf(GFP_KERNEL, "%c", | ||
| 303 | 'A' + (intcp_sc_id & 0x0f)); | ||
| 304 | |||
| 305 | soc_dev = soc_device_register(soc_dev_attr); | ||
| 306 | if (IS_ERR(soc_dev)) { | ||
| 307 | kfree(soc_dev_attr->revision); | ||
| 308 | kfree(soc_dev_attr); | ||
| 309 | return; | ||
| 310 | } | ||
| 311 | |||
| 312 | parent = soc_device_to_device(soc_dev); | ||
| 313 | integrator_init_sysfs(parent, intcp_sc_id); | ||
| 314 | } | 287 | } |
| 315 | 288 | ||
| 316 | static const char * intcp_dt_board_compat[] = { | 289 | static const char * intcp_dt_board_compat[] = { |
| @@ -324,6 +297,5 @@ DT_MACHINE_START(INTEGRATOR_CP_DT, "ARM Integrator/CP (Device Tree)") | |||
| 324 | .init_early = intcp_init_early, | 297 | .init_early = intcp_init_early, |
| 325 | .init_irq = intcp_init_irq_of, | 298 | .init_irq = intcp_init_irq_of, |
| 326 | .init_machine = intcp_init_of, | 299 | .init_machine = intcp_init_of, |
| 327 | .restart = integrator_restart, | ||
| 328 | .dt_compat = intcp_dt_board_compat, | 300 | .dt_compat = intcp_dt_board_compat, |
| 329 | MACHINE_END | 301 | MACHINE_END |
diff --git a/arch/arm/mach-integrator/leds.c b/arch/arm/mach-integrator/leds.c deleted file mode 100644 index f1dcb57a59e2..000000000000 --- a/arch/arm/mach-integrator/leds.c +++ /dev/null | |||
| @@ -1,124 +0,0 @@ | |||
| 1 | /* | ||
| 2 | * Driver for the 4 user LEDs found on the Integrator AP/CP baseboard | ||
| 3 | * Based on Versatile and RealView machine LED code | ||
| 4 | * | ||
| 5 | * License terms: GNU General Public License (GPL) version 2 | ||
| 6 | * Author: Bryan Wu <bryan.wu@canonical.com> | ||
| 7 | */ | ||
| 8 | #include <linux/kernel.h> | ||
| 9 | #include <linux/init.h> | ||
| 10 | #include <linux/io.h> | ||
| 11 | #include <linux/slab.h> | ||
| 12 | #include <linux/leds.h> | ||
| 13 | |||
| 14 | #include "hardware.h" | ||
| 15 | #include "cm.h" | ||
| 16 | |||
| 17 | #if defined(CONFIG_NEW_LEDS) && defined(CONFIG_LEDS_CLASS) | ||
| 18 | |||
| 19 | #define ALPHA_REG __io_address(INTEGRATOR_DBG_BASE) | ||
| 20 | #define LEDREG (__io_address(INTEGRATOR_DBG_BASE) + INTEGRATOR_DBG_LEDS_OFFSET) | ||
| 21 | |||
| 22 | struct integrator_led { | ||
| 23 | struct led_classdev cdev; | ||
| 24 | u8 mask; | ||
| 25 | }; | ||
| 26 | |||
| 27 | /* | ||
| 28 | * The triggers lines up below will only be used if the | ||
| 29 | * LED triggers are compiled in. | ||
| 30 | */ | ||
| 31 | static const struct { | ||
| 32 | const char *name; | ||
| 33 | const char *trigger; | ||
| 34 | } integrator_leds[] = { | ||
| 35 | { "integrator:green0", "heartbeat", }, | ||
| 36 | { "integrator:yellow", }, | ||
| 37 | { "integrator:red", }, | ||
| 38 | { "integrator:green1", }, | ||
| 39 | { "integrator:core_module", "cpu0", }, | ||
| 40 | }; | ||
| 41 | |||
| 42 | static void integrator_led_set(struct led_classdev *cdev, | ||
| 43 | enum led_brightness b) | ||
| 44 | { | ||
| 45 | struct integrator_led *led = container_of(cdev, | ||
| 46 | struct integrator_led, cdev); | ||
| 47 | u32 reg = __raw_readl(LEDREG); | ||
| 48 | |||
| 49 | if (b != LED_OFF) | ||
| 50 | reg |= led->mask; | ||
| 51 | else | ||
| 52 | reg &= ~led->mask; | ||
| 53 | |||
| 54 | while (__raw_readl(ALPHA_REG) & 1) | ||
| 55 | cpu_relax(); | ||
| 56 | |||
| 57 | __raw_writel(reg, LEDREG); | ||
| 58 | } | ||
| 59 | |||
| 60 | static enum led_brightness integrator_led_get(struct led_classdev *cdev) | ||
| 61 | { | ||
| 62 | struct integrator_led *led = container_of(cdev, | ||
| 63 | struct integrator_led, cdev); | ||
| 64 | u32 reg = __raw_readl(LEDREG); | ||
| 65 | |||
| 66 | return (reg & led->mask) ? LED_FULL : LED_OFF; | ||
| 67 | } | ||
| 68 | |||
| 69 | static void cm_led_set(struct led_classdev *cdev, | ||
| 70 | enum led_brightness b) | ||
| 71 | { | ||
| 72 | if (b != LED_OFF) | ||
| 73 | cm_control(CM_CTRL_LED, CM_CTRL_LED); | ||
| 74 | else | ||
| 75 | cm_control(CM_CTRL_LED, 0); | ||
| 76 | } | ||
| 77 | |||
| 78 | static enum led_brightness cm_led_get(struct led_classdev *cdev) | ||
| 79 | { | ||
| 80 | u32 reg = cm_get(); | ||
| 81 | |||
| 82 | return (reg & CM_CTRL_LED) ? LED_FULL : LED_OFF; | ||
| 83 | } | ||
| 84 | |||
| 85 | static int __init integrator_leds_init(void) | ||
| 86 | { | ||
| 87 | int i; | ||
| 88 | |||
| 89 | for (i = 0; i < ARRAY_SIZE(integrator_leds); i++) { | ||
| 90 | struct integrator_led *led; | ||
| 91 | |||
| 92 | led = kzalloc(sizeof(*led), GFP_KERNEL); | ||
| 93 | if (!led) | ||
| 94 | break; | ||
| 95 | |||
| 96 | |||
| 97 | led->cdev.name = integrator_leds[i].name; | ||
| 98 | |||
| 99 | if (i == 4) { /* Setting for LED in core module */ | ||
| 100 | led->cdev.brightness_set = cm_led_set; | ||
| 101 | led->cdev.brightness_get = cm_led_get; | ||
| 102 | } else { | ||
| 103 | led->cdev.brightness_set = integrator_led_set; | ||
| 104 | led->cdev.brightness_get = integrator_led_get; | ||
| 105 | } | ||
| 106 | |||
| 107 | led->cdev.default_trigger = integrator_leds[i].trigger; | ||
| 108 | led->mask = BIT(i); | ||
| 109 | |||
| 110 | if (led_classdev_register(NULL, &led->cdev) < 0) { | ||
| 111 | kfree(led); | ||
| 112 | break; | ||
| 113 | } | ||
| 114 | } | ||
| 115 | |||
| 116 | return 0; | ||
| 117 | } | ||
| 118 | |||
| 119 | /* | ||
| 120 | * Since we may have triggers on any subsystem, defer registration | ||
| 121 | * until after subsystem_init. | ||
| 122 | */ | ||
| 123 | fs_initcall(integrator_leds_init); | ||
| 124 | #endif | ||
diff --git a/drivers/clocksource/Makefile b/drivers/clocksource/Makefile index 756f6f10efa0..fae0435cc23d 100644 --- a/drivers/clocksource/Makefile +++ b/drivers/clocksource/Makefile | |||
| @@ -45,4 +45,5 @@ obj-$(CONFIG_ARM_GLOBAL_TIMER) += arm_global_timer.o | |||
| 45 | obj-$(CONFIG_CLKSRC_METAG_GENERIC) += metag_generic.o | 45 | obj-$(CONFIG_CLKSRC_METAG_GENERIC) += metag_generic.o |
| 46 | obj-$(CONFIG_ARCH_HAS_TICK_BROADCAST) += dummy_timer.o | 46 | obj-$(CONFIG_ARCH_HAS_TICK_BROADCAST) += dummy_timer.o |
| 47 | obj-$(CONFIG_ARCH_KEYSTONE) += timer-keystone.o | 47 | obj-$(CONFIG_ARCH_KEYSTONE) += timer-keystone.o |
| 48 | obj-$(CONFIG_ARCH_INTEGRATOR_AP) += timer-integrator-ap.o | ||
| 48 | obj-$(CONFIG_CLKSRC_VERSATILE) += versatile.o | 49 | 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 index 000000000000..b9efd30513d5 --- /dev/null +++ b/drivers/clocksource/timer-integrator-ap.c | |||
| @@ -0,0 +1,210 @@ | |||
| 1 | /* | ||
| 2 | * Integrator/AP timer driver | ||
| 3 | * Copyright (C) 2000-2003 Deep Blue Solutions Ltd | ||
| 4 | * Copyright (c) 2014, Linaro Limited | ||
| 5 | * | ||
| 6 | * This program is free software; you can redistribute it and/or modify | ||
| 7 | * it under the terms of the GNU General Public License as published by | ||
| 8 | * the Free Software Foundation; either version 2 of the License, or | ||
| 9 | * (at your option) any later version. | ||
| 10 | * | ||
| 11 | * This program is distributed in the hope that it will be useful, | ||
| 12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
| 13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
| 14 | * GNU General Public License for more details. | ||
| 15 | * | ||
| 16 | * You should have received a copy of the GNU General Public License | ||
| 17 | * along with this program; if not, write to the Free Software | ||
| 18 | * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA | ||
| 19 | */ | ||
| 20 | |||
| 21 | #include <linux/clk.h> | ||
| 22 | #include <linux/clocksource.h> | ||
| 23 | #include <linux/of_irq.h> | ||
| 24 | #include <linux/of_address.h> | ||
| 25 | #include <linux/of_platform.h> | ||
| 26 | #include <linux/clockchips.h> | ||
| 27 | #include <linux/interrupt.h> | ||
| 28 | #include <linux/sched_clock.h> | ||
| 29 | #include <asm/hardware/arm_timer.h> | ||
| 30 | |||
| 31 | static void __iomem * sched_clk_base; | ||
| 32 | |||
| 33 | static u64 notrace integrator_read_sched_clock(void) | ||
| 34 | { | ||
| 35 | return -readl(sched_clk_base + TIMER_VALUE); | ||
| 36 | } | ||
| 37 | |||
| 38 | static void integrator_clocksource_init(unsigned long inrate, | ||
| 39 | void __iomem *base) | ||
| 40 | { | ||
| 41 | u32 ctrl = TIMER_CTRL_ENABLE | TIMER_CTRL_PERIODIC; | ||
| 42 | unsigned long rate = inrate; | ||
| 43 | |||
| 44 | if (rate >= 1500000) { | ||
| 45 | rate /= 16; | ||
| 46 | ctrl |= TIMER_CTRL_DIV16; | ||
| 47 | } | ||
| 48 | |||
| 49 | writel(0xffff, base + TIMER_LOAD); | ||
| 50 | writel(ctrl, base + TIMER_CTRL); | ||
| 51 | |||
| 52 | clocksource_mmio_init(base + TIMER_VALUE, "timer2", | ||
| 53 | rate, 200, 16, clocksource_mmio_readl_down); | ||
| 54 | |||
| 55 | sched_clk_base = base; | ||
| 56 | sched_clock_register(integrator_read_sched_clock, 16, rate); | ||
| 57 | } | ||
| 58 | |||
| 59 | static unsigned long timer_reload; | ||
| 60 | static void __iomem * clkevt_base; | ||
| 61 | |||
| 62 | /* | ||
| 63 | * IRQ handler for the timer | ||
| 64 | */ | ||
| 65 | static irqreturn_t integrator_timer_interrupt(int irq, void *dev_id) | ||
| 66 | { | ||
| 67 | struct clock_event_device *evt = dev_id; | ||
| 68 | |||
| 69 | /* clear the interrupt */ | ||
| 70 | writel(1, clkevt_base + TIMER_INTCLR); | ||
| 71 | |||
| 72 | evt->event_handler(evt); | ||
| 73 | |||
| 74 | return IRQ_HANDLED; | ||
| 75 | } | ||
| 76 | |||
| 77 | static void clkevt_set_mode(enum clock_event_mode mode, struct clock_event_device *evt) | ||
| 78 | { | ||
| 79 | u32 ctrl = readl(clkevt_base + TIMER_CTRL) & ~TIMER_CTRL_ENABLE; | ||
| 80 | |||
| 81 | /* Disable timer */ | ||
| 82 | writel(ctrl, clkevt_base + TIMER_CTRL); | ||
| 83 | |||
| 84 | switch (mode) { | ||
| 85 | case CLOCK_EVT_MODE_PERIODIC: | ||
| 86 | /* Enable the timer and start the periodic tick */ | ||
| 87 | writel(timer_reload, clkevt_base + TIMER_LOAD); | ||
| 88 | ctrl |= TIMER_CTRL_PERIODIC | TIMER_CTRL_ENABLE; | ||
| 89 | writel(ctrl, clkevt_base + TIMER_CTRL); | ||
| 90 | break; | ||
| 91 | case CLOCK_EVT_MODE_ONESHOT: | ||
| 92 | /* Leave the timer disabled, .set_next_event will enable it */ | ||
| 93 | ctrl &= ~TIMER_CTRL_PERIODIC; | ||
| 94 | writel(ctrl, clkevt_base + TIMER_CTRL); | ||
| 95 | break; | ||
| 96 | case CLOCK_EVT_MODE_UNUSED: | ||
| 97 | case CLOCK_EVT_MODE_SHUTDOWN: | ||
| 98 | case CLOCK_EVT_MODE_RESUME: | ||
| 99 | default: | ||
| 100 | /* Just leave in disabled state */ | ||
| 101 | break; | ||
| 102 | } | ||
| 103 | |||
| 104 | } | ||
| 105 | |||
| 106 | static int clkevt_set_next_event(unsigned long next, struct clock_event_device *evt) | ||
| 107 | { | ||
| 108 | unsigned long ctrl = readl(clkevt_base + TIMER_CTRL); | ||
| 109 | |||
| 110 | writel(ctrl & ~TIMER_CTRL_ENABLE, clkevt_base + TIMER_CTRL); | ||
| 111 | writel(next, clkevt_base + TIMER_LOAD); | ||
| 112 | writel(ctrl | TIMER_CTRL_ENABLE, clkevt_base + TIMER_CTRL); | ||
| 113 | |||
| 114 | return 0; | ||
| 115 | } | ||
| 116 | |||
| 117 | static struct clock_event_device integrator_clockevent = { | ||
| 118 | .name = "timer1", | ||
| 119 | .features = CLOCK_EVT_FEAT_PERIODIC | CLOCK_EVT_FEAT_ONESHOT, | ||
| 120 | .set_mode = clkevt_set_mode, | ||
| 121 | .set_next_event = clkevt_set_next_event, | ||
| 122 | .rating = 300, | ||
| 123 | }; | ||
| 124 | |||
| 125 | static struct irqaction integrator_timer_irq = { | ||
| 126 | .name = "timer", | ||
| 127 | .flags = IRQF_TIMER | IRQF_IRQPOLL, | ||
| 128 | .handler = integrator_timer_interrupt, | ||
| 129 | .dev_id = &integrator_clockevent, | ||
| 130 | }; | ||
| 131 | |||
| 132 | static void integrator_clockevent_init(unsigned long inrate, | ||
| 133 | void __iomem *base, int irq) | ||
| 134 | { | ||
| 135 | unsigned long rate = inrate; | ||
| 136 | unsigned int ctrl = 0; | ||
| 137 | |||
| 138 | clkevt_base = base; | ||
| 139 | /* Calculate and program a divisor */ | ||
| 140 | if (rate > 0x100000 * HZ) { | ||
| 141 | rate /= 256; | ||
| 142 | ctrl |= TIMER_CTRL_DIV256; | ||
| 143 | } else if (rate > 0x10000 * HZ) { | ||
| 144 | rate /= 16; | ||
| 145 | ctrl |= TIMER_CTRL_DIV16; | ||
| 146 | } | ||
| 147 | timer_reload = rate / HZ; | ||
| 148 | writel(ctrl, clkevt_base + TIMER_CTRL); | ||
| 149 | |||
| 150 | setup_irq(irq, &integrator_timer_irq); | ||
| 151 | clockevents_config_and_register(&integrator_clockevent, | ||
| 152 | rate, | ||
| 153 | 1, | ||
| 154 | 0xffffU); | ||
| 155 | } | ||
| 156 | |||
| 157 | static void __init integrator_ap_timer_init_of(struct device_node *node) | ||
| 158 | { | ||
| 159 | const char *path; | ||
| 160 | void __iomem *base; | ||
| 161 | int err; | ||
| 162 | int irq; | ||
| 163 | struct clk *clk; | ||
| 164 | unsigned long rate; | ||
| 165 | struct device_node *pri_node; | ||
| 166 | struct device_node *sec_node; | ||
| 167 | |||
| 168 | base = of_io_request_and_map(node, 0, "integrator-timer"); | ||
| 169 | if (!base) | ||
| 170 | return; | ||
| 171 | |||
| 172 | clk = of_clk_get(node, 0); | ||
| 173 | if (IS_ERR(clk)) { | ||
| 174 | pr_err("No clock for %s\n", node->name); | ||
| 175 | return; | ||
| 176 | } | ||
| 177 | clk_prepare_enable(clk); | ||
| 178 | rate = clk_get_rate(clk); | ||
| 179 | writel(0, base + TIMER_CTRL); | ||
| 180 | |||
| 181 | err = of_property_read_string(of_aliases, | ||
| 182 | "arm,timer-primary", &path); | ||
| 183 | if (WARN_ON(err)) | ||
| 184 | return; | ||
| 185 | pri_node = of_find_node_by_path(path); | ||
| 186 | err = of_property_read_string(of_aliases, | ||
| 187 | "arm,timer-secondary", &path); | ||
| 188 | if (WARN_ON(err)) | ||
| 189 | return; | ||
| 190 | sec_node = of_find_node_by_path(path); | ||
| 191 | |||
| 192 | if (node == pri_node) { | ||
| 193 | /* The primary timer lacks IRQ, use as clocksource */ | ||
| 194 | integrator_clocksource_init(rate, base); | ||
| 195 | return; | ||
| 196 | } | ||
| 197 | |||
| 198 | if (node == sec_node) { | ||
| 199 | /* The secondary timer will drive the clock event */ | ||
| 200 | irq = irq_of_parse_and_map(node, 0); | ||
| 201 | integrator_clockevent_init(rate, base, irq); | ||
| 202 | return; | ||
| 203 | } | ||
| 204 | |||
| 205 | pr_info("Timer @%p unused\n", base); | ||
| 206 | clk_disable_unprepare(clk); | ||
| 207 | } | ||
| 208 | |||
| 209 | CLOCKSOURCE_OF_DECLARE(integrator_ap_timer, "arm,integrator-timer", | ||
| 210 | integrator_ap_timer_init_of); | ||
diff --git a/drivers/soc/versatile/Kconfig b/drivers/soc/versatile/Kconfig index bf5ee9c85330..a928a7fc6be4 100644 --- a/drivers/soc/versatile/Kconfig +++ b/drivers/soc/versatile/Kconfig | |||
| @@ -1,6 +1,15 @@ | |||
| 1 | # | 1 | # |
| 2 | # ARM Versatile SoC drivers | 2 | # ARM Versatile SoC drivers |
| 3 | # | 3 | # |
| 4 | config SOC_INTEGRATOR_CM | ||
| 5 | bool "SoC bus device for the ARM Integrator platform core modules" | ||
| 6 | depends on ARCH_INTEGRATOR | ||
| 7 | select SOC_BUS | ||
| 8 | help | ||
| 9 | Include support for the SoC bus on the ARM Integrator platform | ||
| 10 | core modules providing some sysfs information about the ASIC | ||
| 11 | variant. | ||
| 12 | |||
| 4 | config SOC_REALVIEW | 13 | config SOC_REALVIEW |
| 5 | bool "SoC bus device for the ARM RealView platforms" | 14 | bool "SoC bus device for the ARM RealView platforms" |
| 6 | depends on ARCH_REALVIEW | 15 | depends on ARCH_REALVIEW |
diff --git a/drivers/soc/versatile/Makefile b/drivers/soc/versatile/Makefile index ad547435648e..cf612fe3a659 100644 --- a/drivers/soc/versatile/Makefile +++ b/drivers/soc/versatile/Makefile | |||
| @@ -1 +1,2 @@ | |||
| 1 | obj-$(CONFIG_SOC_INTEGRATOR_CM) += soc-integrator.o | ||
| 1 | obj-$(CONFIG_SOC_REALVIEW) += soc-realview.o | 2 | 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 index 000000000000..ccaa53739ab4 --- /dev/null +++ b/drivers/soc/versatile/soc-integrator.c | |||
| @@ -0,0 +1,154 @@ | |||
| 1 | /* | ||
| 2 | * Copyright (C) 2014 Linaro Ltd. | ||
| 3 | * | ||
| 4 | * Author: Linus Walleij <linus.walleij@linaro.org> | ||
| 5 | * | ||
| 6 | * This program is free software; you can redistribute it and/or modify | ||
| 7 | * it under the terms of the GNU General Public License version 2, as | ||
| 8 | * published by the Free Software Foundation. | ||
| 9 | * | ||
| 10 | */ | ||
| 11 | #include <linux/init.h> | ||
| 12 | #include <linux/io.h> | ||
| 13 | #include <linux/slab.h> | ||
| 14 | #include <linux/sys_soc.h> | ||
| 15 | #include <linux/platform_device.h> | ||
| 16 | #include <linux/mfd/syscon.h> | ||
| 17 | #include <linux/regmap.h> | ||
| 18 | #include <linux/of.h> | ||
| 19 | |||
| 20 | #define INTEGRATOR_HDR_ID_OFFSET 0x00 | ||
| 21 | |||
| 22 | static u32 integrator_coreid; | ||
| 23 | |||
| 24 | static const struct of_device_id integrator_cm_match[] = { | ||
| 25 | { .compatible = "arm,core-module-integrator", }, | ||
| 26 | }; | ||
| 27 | |||
| 28 | static const char *integrator_arch_str(u32 id) | ||
| 29 | { | ||
| 30 | switch ((id >> 16) & 0xff) { | ||
| 31 | case 0x00: | ||
| 32 | return "ASB little-endian"; | ||
| 33 | case 0x01: | ||
| 34 | return "AHB little-endian"; | ||
| 35 | case 0x03: | ||
| 36 | return "AHB-Lite system bus, bi-endian"; | ||
| 37 | case 0x04: | ||
| 38 | return "AHB"; | ||
| 39 | case 0x08: | ||
| 40 | return "AHB system bus, ASB processor bus"; | ||
| 41 | default: | ||
| 42 | return "Unknown"; | ||
| 43 | } | ||
| 44 | } | ||
| 45 | |||
| 46 | static const char *integrator_fpga_str(u32 id) | ||
| 47 | { | ||
| 48 | switch ((id >> 12) & 0xf) { | ||
| 49 | case 0x01: | ||
| 50 | return "XC4062"; | ||
| 51 | case 0x02: | ||
| 52 | return "XC4085"; | ||
| 53 | case 0x03: | ||
| 54 | return "XVC600"; | ||
| 55 | case 0x04: | ||
| 56 | return "EPM7256AE (Altera PLD)"; | ||
| 57 | default: | ||
| 58 | return "Unknown"; | ||
| 59 | } | ||
| 60 | } | ||
| 61 | |||
| 62 | static ssize_t integrator_get_manf(struct device *dev, | ||
| 63 | struct device_attribute *attr, | ||
| 64 | char *buf) | ||
| 65 | { | ||
| 66 | return sprintf(buf, "%02x\n", integrator_coreid >> 24); | ||
| 67 | } | ||
| 68 | |||
| 69 | static struct device_attribute integrator_manf_attr = | ||
| 70 | __ATTR(manufacturer, S_IRUGO, integrator_get_manf, NULL); | ||
| 71 | |||
| 72 | static ssize_t integrator_get_arch(struct device *dev, | ||
| 73 | struct device_attribute *attr, | ||
| 74 | char *buf) | ||
| 75 | { | ||
| 76 | return sprintf(buf, "%s\n", integrator_arch_str(integrator_coreid)); | ||
| 77 | } | ||
| 78 | |||
| 79 | static struct device_attribute integrator_arch_attr = | ||
| 80 | __ATTR(arch, S_IRUGO, integrator_get_arch, NULL); | ||
| 81 | |||
| 82 | static ssize_t integrator_get_fpga(struct device *dev, | ||
| 83 | struct device_attribute *attr, | ||
| 84 | char *buf) | ||
| 85 | { | ||
| 86 | return sprintf(buf, "%s\n", integrator_fpga_str(integrator_coreid)); | ||
| 87 | } | ||
| 88 | |||
| 89 | static struct device_attribute integrator_fpga_attr = | ||
| 90 | __ATTR(fpga, S_IRUGO, integrator_get_fpga, NULL); | ||
| 91 | |||
| 92 | static ssize_t integrator_get_build(struct device *dev, | ||
| 93 | struct device_attribute *attr, | ||
| 94 | char *buf) | ||
| 95 | { | ||
| 96 | return sprintf(buf, "%02x\n", (integrator_coreid >> 4) & 0xFF); | ||
| 97 | } | ||
| 98 | |||
| 99 | static struct device_attribute integrator_build_attr = | ||
| 100 | __ATTR(build, S_IRUGO, integrator_get_build, NULL); | ||
| 101 | |||
| 102 | static int __init integrator_soc_init(void) | ||
| 103 | { | ||
| 104 | static struct regmap *syscon_regmap; | ||
| 105 | struct soc_device *soc_dev; | ||
| 106 | struct soc_device_attribute *soc_dev_attr; | ||
| 107 | struct device_node *np; | ||
| 108 | struct device *dev; | ||
| 109 | u32 val; | ||
| 110 | int ret; | ||
| 111 | |||
| 112 | np = of_find_matching_node(NULL, integrator_cm_match); | ||
| 113 | if (!np) | ||
| 114 | return -ENODEV; | ||
| 115 | |||
| 116 | syscon_regmap = syscon_node_to_regmap(np); | ||
| 117 | if (IS_ERR(syscon_regmap)) | ||
| 118 | return PTR_ERR(syscon_regmap); | ||
| 119 | |||
| 120 | ret = regmap_read(syscon_regmap, INTEGRATOR_HDR_ID_OFFSET, | ||
| 121 | &val); | ||
| 122 | if (ret) | ||
| 123 | return -ENODEV; | ||
| 124 | integrator_coreid = val; | ||
| 125 | |||
| 126 | soc_dev_attr = kzalloc(sizeof(*soc_dev_attr), GFP_KERNEL); | ||
| 127 | if (!soc_dev_attr) | ||
| 128 | return -ENOMEM; | ||
| 129 | |||
| 130 | soc_dev_attr->soc_id = "Integrator"; | ||
| 131 | soc_dev_attr->machine = "Integrator"; | ||
| 132 | soc_dev_attr->family = "Versatile"; | ||
| 133 | soc_dev = soc_device_register(soc_dev_attr); | ||
| 134 | if (IS_ERR(soc_dev)) { | ||
| 135 | kfree(soc_dev_attr); | ||
| 136 | return -ENODEV; | ||
| 137 | } | ||
| 138 | dev = soc_device_to_device(soc_dev); | ||
| 139 | |||
| 140 | device_create_file(dev, &integrator_manf_attr); | ||
| 141 | device_create_file(dev, &integrator_arch_attr); | ||
| 142 | device_create_file(dev, &integrator_fpga_attr); | ||
| 143 | device_create_file(dev, &integrator_build_attr); | ||
| 144 | |||
| 145 | dev_info(dev, "Detected ARM core module:\n"); | ||
| 146 | dev_info(dev, " Manufacturer: %02x\n", (val >> 24)); | ||
| 147 | dev_info(dev, " Architecture: %s\n", integrator_arch_str(val)); | ||
| 148 | dev_info(dev, " FPGA: %s\n", integrator_fpga_str(val)); | ||
| 149 | dev_info(dev, " Build: %02x\n", (val >> 4) & 0xFF); | ||
| 150 | dev_info(dev, " Rev: %c\n", ('A' + (val & 0x03))); | ||
| 151 | |||
| 152 | return 0; | ||
| 153 | } | ||
| 154 | device_initcall(integrator_soc_init); | ||
