diff options
| author | John Stultz <john.stultz@linaro.org> | 2013-09-26 15:05:54 -0400 |
|---|---|---|
| committer | John Stultz <john.stultz@linaro.org> | 2013-09-26 15:05:54 -0400 |
| commit | 17deb9c2db01c7813611291d251d8c7dbdfd3c9d (patch) | |
| tree | 6e023c0be7c64de84dd51a671eb09c5c82b56615 /drivers/clocksource | |
| parent | f4e6e1ea19737077d958f2bc6c196eb579d97544 (diff) | |
| parent | 389e067032fbb96e439abafae848dd447e4cafb4 (diff) | |
Merge remote-tracking branch 'tip/timers/core' into fordlezcano/3.13/sched-clock64-conversion
Update to tip/timers/core and resolve minor conflict.
Conflicts:
drivers/clocksource/samsung_pwm_timer.c
Signed-off-by: John Stultz <john.stultz@linaro.org>
Diffstat (limited to 'drivers/clocksource')
| -rw-r--r-- | drivers/clocksource/Kconfig | 1 | ||||
| -rw-r--r-- | drivers/clocksource/Makefile | 1 | ||||
| -rw-r--r-- | drivers/clocksource/acpi_pm.c | 4 | ||||
| -rw-r--r-- | drivers/clocksource/arm_arch_timer.c | 453 | ||||
| -rw-r--r-- | drivers/clocksource/arm_global_timer.c | 8 | ||||
| -rw-r--r-- | drivers/clocksource/bcm_kona_timer.c | 8 | ||||
| -rw-r--r-- | drivers/clocksource/cadence_ttc_timer.c | 13 | ||||
| -rw-r--r-- | drivers/clocksource/dummy_timer.c | 6 | ||||
| -rw-r--r-- | drivers/clocksource/em_sti.c | 49 | ||||
| -rw-r--r-- | drivers/clocksource/exynos_mct.c | 60 | ||||
| -rw-r--r-- | drivers/clocksource/metag_generic.c | 6 | ||||
| -rw-r--r-- | drivers/clocksource/moxart_timer.c | 165 | ||||
| -rw-r--r-- | drivers/clocksource/nomadik-mtu.c | 3 | ||||
| -rw-r--r-- | drivers/clocksource/samsung_pwm_timer.c | 120 | ||||
| -rw-r--r-- | drivers/clocksource/sh_cmt.c | 50 | ||||
| -rw-r--r-- | drivers/clocksource/sun4i_timer.c | 110 | ||||
| -rw-r--r-- | drivers/clocksource/time-armada-370-xp.c | 225 | ||||
| -rw-r--r-- | drivers/clocksource/time-orion.c | 2 | ||||
| -rw-r--r-- | drivers/clocksource/timer-marco.c | 100 |
19 files changed, 994 insertions, 390 deletions
diff --git a/drivers/clocksource/Kconfig b/drivers/clocksource/Kconfig index b7b9b040a89b..41c69469ce20 100644 --- a/drivers/clocksource/Kconfig +++ b/drivers/clocksource/Kconfig | |||
| @@ -99,7 +99,6 @@ config CLKSRC_EXYNOS_MCT | |||
| 99 | 99 | ||
| 100 | config CLKSRC_SAMSUNG_PWM | 100 | config CLKSRC_SAMSUNG_PWM |
| 101 | bool | 101 | bool |
| 102 | select CLKSRC_MMIO | ||
| 103 | help | 102 | help |
| 104 | This is a new clocksource driver for the PWM timer found in | 103 | This is a new clocksource driver for the PWM timer found in |
| 105 | Samsung S3C, S5P and Exynos SoCs, replacing an earlier driver | 104 | Samsung S3C, S5P and Exynos SoCs, replacing an earlier driver |
diff --git a/drivers/clocksource/Makefile b/drivers/clocksource/Makefile index 8b00c5cebfa4..704d6d342adc 100644 --- a/drivers/clocksource/Makefile +++ b/drivers/clocksource/Makefile | |||
| @@ -18,6 +18,7 @@ obj-$(CONFIG_ARMADA_370_XP_TIMER) += time-armada-370-xp.o | |||
| 18 | obj-$(CONFIG_ORION_TIMER) += time-orion.o | 18 | obj-$(CONFIG_ORION_TIMER) += time-orion.o |
| 19 | obj-$(CONFIG_ARCH_BCM2835) += bcm2835_timer.o | 19 | obj-$(CONFIG_ARCH_BCM2835) += bcm2835_timer.o |
| 20 | obj-$(CONFIG_ARCH_MARCO) += timer-marco.o | 20 | obj-$(CONFIG_ARCH_MARCO) += timer-marco.o |
| 21 | obj-$(CONFIG_ARCH_MOXART) += moxart_timer.o | ||
| 21 | obj-$(CONFIG_ARCH_MXS) += mxs_timer.o | 22 | obj-$(CONFIG_ARCH_MXS) += mxs_timer.o |
| 22 | obj-$(CONFIG_ARCH_PRIMA2) += timer-prima2.o | 23 | obj-$(CONFIG_ARCH_PRIMA2) += timer-prima2.o |
| 23 | obj-$(CONFIG_SUN4I_TIMER) += sun4i_timer.o | 24 | obj-$(CONFIG_SUN4I_TIMER) += sun4i_timer.o |
diff --git a/drivers/clocksource/acpi_pm.c b/drivers/clocksource/acpi_pm.c index 6efe4d1ab3aa..6eab88985670 100644 --- a/drivers/clocksource/acpi_pm.c +++ b/drivers/clocksource/acpi_pm.c | |||
| @@ -200,14 +200,14 @@ static int __init init_acpi_pm_clocksource(void) | |||
| 200 | if ((value2 < value1) && ((value2) < 0xFFF)) | 200 | if ((value2 < value1) && ((value2) < 0xFFF)) |
| 201 | break; | 201 | break; |
| 202 | printk(KERN_INFO "PM-Timer had inconsistent results:" | 202 | printk(KERN_INFO "PM-Timer had inconsistent results:" |
| 203 | " 0x%#llx, 0x%#llx - aborting.\n", | 203 | " %#llx, %#llx - aborting.\n", |
| 204 | value1, value2); | 204 | value1, value2); |
| 205 | pmtmr_ioport = 0; | 205 | pmtmr_ioport = 0; |
| 206 | return -EINVAL; | 206 | return -EINVAL; |
| 207 | } | 207 | } |
| 208 | if (i == ACPI_PM_READ_CHECKS) { | 208 | if (i == ACPI_PM_READ_CHECKS) { |
| 209 | printk(KERN_INFO "PM-Timer failed consistency check " | 209 | printk(KERN_INFO "PM-Timer failed consistency check " |
| 210 | " (0x%#llx) - aborting.\n", value1); | 210 | " (%#llx) - aborting.\n", value1); |
| 211 | pmtmr_ioport = 0; | 211 | pmtmr_ioport = 0; |
| 212 | return -ENODEV; | 212 | return -ENODEV; |
| 213 | } | 213 | } |
diff --git a/drivers/clocksource/arm_arch_timer.c b/drivers/clocksource/arm_arch_timer.c index 053d846ab5b1..fbd9ccd5e114 100644 --- a/drivers/clocksource/arm_arch_timer.c +++ b/drivers/clocksource/arm_arch_timer.c | |||
| @@ -16,13 +16,39 @@ | |||
| 16 | #include <linux/clockchips.h> | 16 | #include <linux/clockchips.h> |
| 17 | #include <linux/interrupt.h> | 17 | #include <linux/interrupt.h> |
| 18 | #include <linux/of_irq.h> | 18 | #include <linux/of_irq.h> |
| 19 | #include <linux/of_address.h> | ||
| 19 | #include <linux/io.h> | 20 | #include <linux/io.h> |
| 21 | #include <linux/slab.h> | ||
| 20 | 22 | ||
| 21 | #include <asm/arch_timer.h> | 23 | #include <asm/arch_timer.h> |
| 22 | #include <asm/virt.h> | 24 | #include <asm/virt.h> |
| 23 | 25 | ||
| 24 | #include <clocksource/arm_arch_timer.h> | 26 | #include <clocksource/arm_arch_timer.h> |
| 25 | 27 | ||
| 28 | #define CNTTIDR 0x08 | ||
| 29 | #define CNTTIDR_VIRT(n) (BIT(1) << ((n) * 4)) | ||
| 30 | |||
| 31 | #define CNTVCT_LO 0x08 | ||
| 32 | #define CNTVCT_HI 0x0c | ||
| 33 | #define CNTFRQ 0x10 | ||
| 34 | #define CNTP_TVAL 0x28 | ||
| 35 | #define CNTP_CTL 0x2c | ||
| 36 | #define CNTV_TVAL 0x38 | ||
| 37 | #define CNTV_CTL 0x3c | ||
| 38 | |||
| 39 | #define ARCH_CP15_TIMER BIT(0) | ||
| 40 | #define ARCH_MEM_TIMER BIT(1) | ||
| 41 | static unsigned arch_timers_present __initdata; | ||
| 42 | |||
| 43 | static void __iomem *arch_counter_base; | ||
| 44 | |||
| 45 | struct arch_timer { | ||
| 46 | void __iomem *base; | ||
| 47 | struct clock_event_device evt; | ||
| 48 | }; | ||
| 49 | |||
| 50 | #define to_arch_timer(e) container_of(e, struct arch_timer, evt) | ||
| 51 | |||
| 26 | static u32 arch_timer_rate; | 52 | static u32 arch_timer_rate; |
| 27 | 53 | ||
| 28 | enum ppi_nr { | 54 | enum ppi_nr { |
| @@ -38,19 +64,83 @@ static int arch_timer_ppi[MAX_TIMER_PPI]; | |||
| 38 | static struct clock_event_device __percpu *arch_timer_evt; | 64 | static struct clock_event_device __percpu *arch_timer_evt; |
| 39 | 65 | ||
| 40 | static bool arch_timer_use_virtual = true; | 66 | static bool arch_timer_use_virtual = true; |
| 67 | static bool arch_timer_mem_use_virtual; | ||
| 41 | 68 | ||
| 42 | /* | 69 | /* |
| 43 | * Architected system timer support. | 70 | * Architected system timer support. |
| 44 | */ | 71 | */ |
| 45 | 72 | ||
| 46 | static inline irqreturn_t timer_handler(const int access, | 73 | static __always_inline |
| 74 | void arch_timer_reg_write(int access, enum arch_timer_reg reg, u32 val, | ||
| 75 | struct clock_event_device *clk) | ||
| 76 | { | ||
| 77 | if (access == ARCH_TIMER_MEM_PHYS_ACCESS) { | ||
| 78 | struct arch_timer *timer = to_arch_timer(clk); | ||
| 79 | switch (reg) { | ||
| 80 | case ARCH_TIMER_REG_CTRL: | ||
| 81 | writel_relaxed(val, timer->base + CNTP_CTL); | ||
| 82 | break; | ||
| 83 | case ARCH_TIMER_REG_TVAL: | ||
| 84 | writel_relaxed(val, timer->base + CNTP_TVAL); | ||
| 85 | break; | ||
| 86 | } | ||
| 87 | } else if (access == ARCH_TIMER_MEM_VIRT_ACCESS) { | ||
| 88 | struct arch_timer *timer = to_arch_timer(clk); | ||
| 89 | switch (reg) { | ||
| 90 | case ARCH_TIMER_REG_CTRL: | ||
| 91 | writel_relaxed(val, timer->base + CNTV_CTL); | ||
| 92 | break; | ||
| 93 | case ARCH_TIMER_REG_TVAL: | ||
| 94 | writel_relaxed(val, timer->base + CNTV_TVAL); | ||
| 95 | break; | ||
| 96 | } | ||
| 97 | } else { | ||
| 98 | arch_timer_reg_write_cp15(access, reg, val); | ||
| 99 | } | ||
| 100 | } | ||
| 101 | |||
| 102 | static __always_inline | ||
| 103 | u32 arch_timer_reg_read(int access, enum arch_timer_reg reg, | ||
| 104 | struct clock_event_device *clk) | ||
| 105 | { | ||
| 106 | u32 val; | ||
| 107 | |||
| 108 | if (access == ARCH_TIMER_MEM_PHYS_ACCESS) { | ||
| 109 | struct arch_timer *timer = to_arch_timer(clk); | ||
| 110 | switch (reg) { | ||
| 111 | case ARCH_TIMER_REG_CTRL: | ||
| 112 | val = readl_relaxed(timer->base + CNTP_CTL); | ||
| 113 | break; | ||
| 114 | case ARCH_TIMER_REG_TVAL: | ||
| 115 | val = readl_relaxed(timer->base + CNTP_TVAL); | ||
| 116 | break; | ||
| 117 | } | ||
| 118 | } else if (access == ARCH_TIMER_MEM_VIRT_ACCESS) { | ||
| 119 | struct arch_timer *timer = to_arch_timer(clk); | ||
| 120 | switch (reg) { | ||
| 121 | case ARCH_TIMER_REG_CTRL: | ||
| 122 | val = readl_relaxed(timer->base + CNTV_CTL); | ||
| 123 | break; | ||
| 124 | case ARCH_TIMER_REG_TVAL: | ||
| 125 | val = readl_relaxed(timer->base + CNTV_TVAL); | ||
| 126 | break; | ||
| 127 | } | ||
| 128 | } else { | ||
| 129 | val = arch_timer_reg_read_cp15(access, reg); | ||
| 130 | } | ||
| 131 | |||
| 132 | return val; | ||
| 133 | } | ||
| 134 | |||
| 135 | static __always_inline irqreturn_t timer_handler(const int access, | ||
| 47 | struct clock_event_device *evt) | 136 | struct clock_event_device *evt) |
| 48 | { | 137 | { |
| 49 | unsigned long ctrl; | 138 | unsigned long ctrl; |
| 50 | ctrl = arch_timer_reg_read(access, ARCH_TIMER_REG_CTRL); | 139 | |
| 140 | ctrl = arch_timer_reg_read(access, ARCH_TIMER_REG_CTRL, evt); | ||
| 51 | if (ctrl & ARCH_TIMER_CTRL_IT_STAT) { | 141 | if (ctrl & ARCH_TIMER_CTRL_IT_STAT) { |
| 52 | ctrl |= ARCH_TIMER_CTRL_IT_MASK; | 142 | ctrl |= ARCH_TIMER_CTRL_IT_MASK; |
| 53 | arch_timer_reg_write(access, ARCH_TIMER_REG_CTRL, ctrl); | 143 | arch_timer_reg_write(access, ARCH_TIMER_REG_CTRL, ctrl, evt); |
| 54 | evt->event_handler(evt); | 144 | evt->event_handler(evt); |
| 55 | return IRQ_HANDLED; | 145 | return IRQ_HANDLED; |
| 56 | } | 146 | } |
| @@ -72,15 +162,30 @@ static irqreturn_t arch_timer_handler_phys(int irq, void *dev_id) | |||
| 72 | return timer_handler(ARCH_TIMER_PHYS_ACCESS, evt); | 162 | return timer_handler(ARCH_TIMER_PHYS_ACCESS, evt); |
| 73 | } | 163 | } |
| 74 | 164 | ||
| 75 | static inline void timer_set_mode(const int access, int mode) | 165 | static irqreturn_t arch_timer_handler_phys_mem(int irq, void *dev_id) |
| 166 | { | ||
| 167 | struct clock_event_device *evt = dev_id; | ||
| 168 | |||
| 169 | return timer_handler(ARCH_TIMER_MEM_PHYS_ACCESS, evt); | ||
| 170 | } | ||
| 171 | |||
| 172 | static irqreturn_t arch_timer_handler_virt_mem(int irq, void *dev_id) | ||
| 173 | { | ||
| 174 | struct clock_event_device *evt = dev_id; | ||
| 175 | |||
| 176 | return timer_handler(ARCH_TIMER_MEM_VIRT_ACCESS, evt); | ||
| 177 | } | ||
| 178 | |||
| 179 | static __always_inline void timer_set_mode(const int access, int mode, | ||
| 180 | struct clock_event_device *clk) | ||
| 76 | { | 181 | { |
| 77 | unsigned long ctrl; | 182 | unsigned long ctrl; |
| 78 | switch (mode) { | 183 | switch (mode) { |
| 79 | case CLOCK_EVT_MODE_UNUSED: | 184 | case CLOCK_EVT_MODE_UNUSED: |
| 80 | case CLOCK_EVT_MODE_SHUTDOWN: | 185 | case CLOCK_EVT_MODE_SHUTDOWN: |
| 81 | ctrl = arch_timer_reg_read(access, ARCH_TIMER_REG_CTRL); | 186 | ctrl = arch_timer_reg_read(access, ARCH_TIMER_REG_CTRL, clk); |
| 82 | ctrl &= ~ARCH_TIMER_CTRL_ENABLE; | 187 | ctrl &= ~ARCH_TIMER_CTRL_ENABLE; |
| 83 | arch_timer_reg_write(access, ARCH_TIMER_REG_CTRL, ctrl); | 188 | arch_timer_reg_write(access, ARCH_TIMER_REG_CTRL, ctrl, clk); |
| 84 | break; | 189 | break; |
| 85 | default: | 190 | default: |
| 86 | break; | 191 | break; |
| @@ -90,60 +195,108 @@ static inline void timer_set_mode(const int access, int mode) | |||
| 90 | static void arch_timer_set_mode_virt(enum clock_event_mode mode, | 195 | static void arch_timer_set_mode_virt(enum clock_event_mode mode, |
| 91 | struct clock_event_device *clk) | 196 | struct clock_event_device *clk) |
| 92 | { | 197 | { |
| 93 | timer_set_mode(ARCH_TIMER_VIRT_ACCESS, mode); | 198 | timer_set_mode(ARCH_TIMER_VIRT_ACCESS, mode, clk); |
| 94 | } | 199 | } |
| 95 | 200 | ||
| 96 | static void arch_timer_set_mode_phys(enum clock_event_mode mode, | 201 | static void arch_timer_set_mode_phys(enum clock_event_mode mode, |
| 97 | struct clock_event_device *clk) | 202 | struct clock_event_device *clk) |
| 98 | { | 203 | { |
| 99 | timer_set_mode(ARCH_TIMER_PHYS_ACCESS, mode); | 204 | timer_set_mode(ARCH_TIMER_PHYS_ACCESS, mode, clk); |
| 205 | } | ||
| 206 | |||
| 207 | static void arch_timer_set_mode_virt_mem(enum clock_event_mode mode, | ||
| 208 | struct clock_event_device *clk) | ||
| 209 | { | ||
| 210 | timer_set_mode(ARCH_TIMER_MEM_VIRT_ACCESS, mode, clk); | ||
| 100 | } | 211 | } |
| 101 | 212 | ||
| 102 | static inline void set_next_event(const int access, unsigned long evt) | 213 | static void arch_timer_set_mode_phys_mem(enum clock_event_mode mode, |
| 214 | struct clock_event_device *clk) | ||
| 215 | { | ||
| 216 | timer_set_mode(ARCH_TIMER_MEM_PHYS_ACCESS, mode, clk); | ||
| 217 | } | ||
| 218 | |||
| 219 | static __always_inline void set_next_event(const int access, unsigned long evt, | ||
| 220 | struct clock_event_device *clk) | ||
| 103 | { | 221 | { |
| 104 | unsigned long ctrl; | 222 | unsigned long ctrl; |
| 105 | ctrl = arch_timer_reg_read(access, ARCH_TIMER_REG_CTRL); | 223 | ctrl = arch_timer_reg_read(access, ARCH_TIMER_REG_CTRL, clk); |
| 106 | ctrl |= ARCH_TIMER_CTRL_ENABLE; | 224 | ctrl |= ARCH_TIMER_CTRL_ENABLE; |
| 107 | ctrl &= ~ARCH_TIMER_CTRL_IT_MASK; | 225 | ctrl &= ~ARCH_TIMER_CTRL_IT_MASK; |
| 108 | arch_timer_reg_write(access, ARCH_TIMER_REG_TVAL, evt); | 226 | arch_timer_reg_write(access, ARCH_TIMER_REG_TVAL, evt, clk); |
| 109 | arch_timer_reg_write(access, ARCH_TIMER_REG_CTRL, ctrl); | 227 | arch_timer_reg_write(access, ARCH_TIMER_REG_CTRL, ctrl, clk); |
| 110 | } | 228 | } |
| 111 | 229 | ||
| 112 | static int arch_timer_set_next_event_virt(unsigned long evt, | 230 | static int arch_timer_set_next_event_virt(unsigned long evt, |
| 113 | struct clock_event_device *unused) | 231 | struct clock_event_device *clk) |
| 114 | { | 232 | { |
| 115 | set_next_event(ARCH_TIMER_VIRT_ACCESS, evt); | 233 | set_next_event(ARCH_TIMER_VIRT_ACCESS, evt, clk); |
| 116 | return 0; | 234 | return 0; |
| 117 | } | 235 | } |
| 118 | 236 | ||
| 119 | static int arch_timer_set_next_event_phys(unsigned long evt, | 237 | static int arch_timer_set_next_event_phys(unsigned long evt, |
| 120 | struct clock_event_device *unused) | 238 | struct clock_event_device *clk) |
| 121 | { | 239 | { |
| 122 | set_next_event(ARCH_TIMER_PHYS_ACCESS, evt); | 240 | set_next_event(ARCH_TIMER_PHYS_ACCESS, evt, clk); |
| 123 | return 0; | 241 | return 0; |
| 124 | } | 242 | } |
| 125 | 243 | ||
| 126 | static int __cpuinit arch_timer_setup(struct clock_event_device *clk) | 244 | static int arch_timer_set_next_event_virt_mem(unsigned long evt, |
| 245 | struct clock_event_device *clk) | ||
| 127 | { | 246 | { |
| 128 | clk->features = CLOCK_EVT_FEAT_ONESHOT | CLOCK_EVT_FEAT_C3STOP; | 247 | set_next_event(ARCH_TIMER_MEM_VIRT_ACCESS, evt, clk); |
| 129 | clk->name = "arch_sys_timer"; | 248 | return 0; |
| 130 | clk->rating = 450; | 249 | } |
| 131 | if (arch_timer_use_virtual) { | 250 | |
| 132 | clk->irq = arch_timer_ppi[VIRT_PPI]; | 251 | static int arch_timer_set_next_event_phys_mem(unsigned long evt, |
| 133 | clk->set_mode = arch_timer_set_mode_virt; | 252 | struct clock_event_device *clk) |
| 134 | clk->set_next_event = arch_timer_set_next_event_virt; | 253 | { |
| 254 | set_next_event(ARCH_TIMER_MEM_PHYS_ACCESS, evt, clk); | ||
| 255 | return 0; | ||
| 256 | } | ||
| 257 | |||
| 258 | static void __arch_timer_setup(unsigned type, | ||
| 259 | struct clock_event_device *clk) | ||
| 260 | { | ||
| 261 | clk->features = CLOCK_EVT_FEAT_ONESHOT; | ||
| 262 | |||
| 263 | if (type == ARCH_CP15_TIMER) { | ||
| 264 | clk->features |= CLOCK_EVT_FEAT_C3STOP; | ||
| 265 | clk->name = "arch_sys_timer"; | ||
| 266 | clk->rating = 450; | ||
| 267 | clk->cpumask = cpumask_of(smp_processor_id()); | ||
| 268 | if (arch_timer_use_virtual) { | ||
| 269 | clk->irq = arch_timer_ppi[VIRT_PPI]; | ||
| 270 | clk->set_mode = arch_timer_set_mode_virt; | ||
| 271 | clk->set_next_event = arch_timer_set_next_event_virt; | ||
| 272 | } else { | ||
| 273 | clk->irq = arch_timer_ppi[PHYS_SECURE_PPI]; | ||
| 274 | clk->set_mode = arch_timer_set_mode_phys; | ||
| 275 | clk->set_next_event = arch_timer_set_next_event_phys; | ||
| 276 | } | ||
| 135 | } else { | 277 | } else { |
| 136 | clk->irq = arch_timer_ppi[PHYS_SECURE_PPI]; | 278 | clk->name = "arch_mem_timer"; |
| 137 | clk->set_mode = arch_timer_set_mode_phys; | 279 | clk->rating = 400; |
| 138 | clk->set_next_event = arch_timer_set_next_event_phys; | 280 | clk->cpumask = cpu_all_mask; |
| 281 | if (arch_timer_mem_use_virtual) { | ||
| 282 | clk->set_mode = arch_timer_set_mode_virt_mem; | ||
| 283 | clk->set_next_event = | ||
| 284 | arch_timer_set_next_event_virt_mem; | ||
| 285 | } else { | ||
| 286 | clk->set_mode = arch_timer_set_mode_phys_mem; | ||
| 287 | clk->set_next_event = | ||
| 288 | arch_timer_set_next_event_phys_mem; | ||
| 289 | } | ||
| 139 | } | 290 | } |
| 140 | 291 | ||
| 141 | clk->cpumask = cpumask_of(smp_processor_id()); | 292 | clk->set_mode(CLOCK_EVT_MODE_SHUTDOWN, clk); |
| 142 | 293 | ||
| 143 | clk->set_mode(CLOCK_EVT_MODE_SHUTDOWN, NULL); | 294 | clockevents_config_and_register(clk, arch_timer_rate, 0xf, 0x7fffffff); |
| 295 | } | ||
| 144 | 296 | ||
| 145 | clockevents_config_and_register(clk, arch_timer_rate, | 297 | static int arch_timer_setup(struct clock_event_device *clk) |
| 146 | 0xf, 0x7fffffff); | 298 | { |
| 299 | __arch_timer_setup(ARCH_CP15_TIMER, clk); | ||
| 147 | 300 | ||
| 148 | if (arch_timer_use_virtual) | 301 | if (arch_timer_use_virtual) |
| 149 | enable_percpu_irq(arch_timer_ppi[VIRT_PPI], 0); | 302 | enable_percpu_irq(arch_timer_ppi[VIRT_PPI], 0); |
| @@ -158,27 +311,41 @@ static int __cpuinit arch_timer_setup(struct clock_event_device *clk) | |||
| 158 | return 0; | 311 | return 0; |
| 159 | } | 312 | } |
| 160 | 313 | ||
| 161 | static int arch_timer_available(void) | 314 | static void |
| 315 | arch_timer_detect_rate(void __iomem *cntbase, struct device_node *np) | ||
| 162 | { | 316 | { |
| 163 | u32 freq; | 317 | /* Who has more than one independent system counter? */ |
| 164 | 318 | if (arch_timer_rate) | |
| 165 | if (arch_timer_rate == 0) { | 319 | return; |
| 166 | freq = arch_timer_get_cntfrq(); | ||
| 167 | |||
| 168 | /* Check the timer frequency. */ | ||
| 169 | if (freq == 0) { | ||
| 170 | pr_warn("Architected timer frequency not available\n"); | ||
| 171 | return -EINVAL; | ||
| 172 | } | ||
| 173 | 320 | ||
| 174 | arch_timer_rate = freq; | 321 | /* Try to determine the frequency from the device tree or CNTFRQ */ |
| 322 | if (of_property_read_u32(np, "clock-frequency", &arch_timer_rate)) { | ||
| 323 | if (cntbase) | ||
| 324 | arch_timer_rate = readl_relaxed(cntbase + CNTFRQ); | ||
| 325 | else | ||
| 326 | arch_timer_rate = arch_timer_get_cntfrq(); | ||
| 175 | } | 327 | } |
| 176 | 328 | ||
| 177 | pr_info_once("Architected local timer running at %lu.%02luMHz (%s).\n", | 329 | /* Check the timer frequency. */ |
| 330 | if (arch_timer_rate == 0) | ||
| 331 | pr_warn("Architected timer frequency not available\n"); | ||
| 332 | } | ||
| 333 | |||
| 334 | static void arch_timer_banner(unsigned type) | ||
| 335 | { | ||
| 336 | pr_info("Architected %s%s%s timer(s) running at %lu.%02luMHz (%s%s%s).\n", | ||
| 337 | type & ARCH_CP15_TIMER ? "cp15" : "", | ||
| 338 | type == (ARCH_CP15_TIMER | ARCH_MEM_TIMER) ? " and " : "", | ||
| 339 | type & ARCH_MEM_TIMER ? "mmio" : "", | ||
| 178 | (unsigned long)arch_timer_rate / 1000000, | 340 | (unsigned long)arch_timer_rate / 1000000, |
| 179 | (unsigned long)(arch_timer_rate / 10000) % 100, | 341 | (unsigned long)(arch_timer_rate / 10000) % 100, |
| 180 | arch_timer_use_virtual ? "virt" : "phys"); | 342 | type & ARCH_CP15_TIMER ? |
| 181 | return 0; | 343 | arch_timer_use_virtual ? "virt" : "phys" : |
| 344 | "", | ||
| 345 | type == (ARCH_CP15_TIMER | ARCH_MEM_TIMER) ? "/" : "", | ||
| 346 | type & ARCH_MEM_TIMER ? | ||
| 347 | arch_timer_mem_use_virtual ? "virt" : "phys" : | ||
| 348 | ""); | ||
| 182 | } | 349 | } |
| 183 | 350 | ||
| 184 | u32 arch_timer_get_rate(void) | 351 | u32 arch_timer_get_rate(void) |
| @@ -186,19 +353,35 @@ u32 arch_timer_get_rate(void) | |||
| 186 | return arch_timer_rate; | 353 | return arch_timer_rate; |
| 187 | } | 354 | } |
| 188 | 355 | ||
| 189 | u64 arch_timer_read_counter(void) | 356 | static u64 arch_counter_get_cntvct_mem(void) |
| 190 | { | 357 | { |
| 191 | return arch_counter_get_cntvct(); | 358 | u32 vct_lo, vct_hi, tmp_hi; |
| 359 | |||
| 360 | do { | ||
| 361 | vct_hi = readl_relaxed(arch_counter_base + CNTVCT_HI); | ||
| 362 | vct_lo = readl_relaxed(arch_counter_base + CNTVCT_LO); | ||
| 363 | tmp_hi = readl_relaxed(arch_counter_base + CNTVCT_HI); | ||
| 364 | } while (vct_hi != tmp_hi); | ||
| 365 | |||
| 366 | return ((u64) vct_hi << 32) | vct_lo; | ||
| 192 | } | 367 | } |
| 193 | 368 | ||
| 369 | /* | ||
| 370 | * Default to cp15 based access because arm64 uses this function for | ||
| 371 | * sched_clock() before DT is probed and the cp15 method is guaranteed | ||
| 372 | * to exist on arm64. arm doesn't use this before DT is probed so even | ||
| 373 | * if we don't have the cp15 accessors we won't have a problem. | ||
| 374 | */ | ||
| 375 | u64 (*arch_timer_read_counter)(void) = arch_counter_get_cntvct; | ||
| 376 | |||
| 194 | static cycle_t arch_counter_read(struct clocksource *cs) | 377 | static cycle_t arch_counter_read(struct clocksource *cs) |
| 195 | { | 378 | { |
| 196 | return arch_counter_get_cntvct(); | 379 | return arch_timer_read_counter(); |
| 197 | } | 380 | } |
| 198 | 381 | ||
| 199 | static cycle_t arch_counter_read_cc(const struct cyclecounter *cc) | 382 | static cycle_t arch_counter_read_cc(const struct cyclecounter *cc) |
| 200 | { | 383 | { |
| 201 | return arch_counter_get_cntvct(); | 384 | return arch_timer_read_counter(); |
| 202 | } | 385 | } |
| 203 | 386 | ||
| 204 | static struct clocksource clocksource_counter = { | 387 | static struct clocksource clocksource_counter = { |
| @@ -221,7 +404,24 @@ struct timecounter *arch_timer_get_timecounter(void) | |||
| 221 | return &timecounter; | 404 | return &timecounter; |
| 222 | } | 405 | } |
| 223 | 406 | ||
| 224 | static void __cpuinit arch_timer_stop(struct clock_event_device *clk) | 407 | static void __init arch_counter_register(unsigned type) |
| 408 | { | ||
| 409 | u64 start_count; | ||
| 410 | |||
| 411 | /* Register the CP15 based counter if we have one */ | ||
| 412 | if (type & ARCH_CP15_TIMER) | ||
| 413 | arch_timer_read_counter = arch_counter_get_cntvct; | ||
| 414 | else | ||
| 415 | arch_timer_read_counter = arch_counter_get_cntvct_mem; | ||
| 416 | |||
| 417 | start_count = arch_timer_read_counter(); | ||
| 418 | clocksource_register_hz(&clocksource_counter, arch_timer_rate); | ||
| 419 | cyclecounter.mult = clocksource_counter.mult; | ||
| 420 | cyclecounter.shift = clocksource_counter.shift; | ||
| 421 | timecounter_init(&timecounter, &cyclecounter, start_count); | ||
| 422 | } | ||
| 423 | |||
| 424 | static void arch_timer_stop(struct clock_event_device *clk) | ||
| 225 | { | 425 | { |
| 226 | pr_debug("arch_timer_teardown disable IRQ%d cpu #%d\n", | 426 | pr_debug("arch_timer_teardown disable IRQ%d cpu #%d\n", |
| 227 | clk->irq, smp_processor_id()); | 427 | clk->irq, smp_processor_id()); |
| @@ -237,7 +437,7 @@ static void __cpuinit arch_timer_stop(struct clock_event_device *clk) | |||
| 237 | clk->set_mode(CLOCK_EVT_MODE_UNUSED, clk); | 437 | clk->set_mode(CLOCK_EVT_MODE_UNUSED, clk); |
| 238 | } | 438 | } |
| 239 | 439 | ||
| 240 | static int __cpuinit arch_timer_cpu_notify(struct notifier_block *self, | 440 | static int arch_timer_cpu_notify(struct notifier_block *self, |
| 241 | unsigned long action, void *hcpu) | 441 | unsigned long action, void *hcpu) |
| 242 | { | 442 | { |
| 243 | /* | 443 | /* |
| @@ -256,7 +456,7 @@ static int __cpuinit arch_timer_cpu_notify(struct notifier_block *self, | |||
| 256 | return NOTIFY_OK; | 456 | return NOTIFY_OK; |
| 257 | } | 457 | } |
| 258 | 458 | ||
| 259 | static struct notifier_block arch_timer_cpu_nb __cpuinitdata = { | 459 | static struct notifier_block arch_timer_cpu_nb = { |
| 260 | .notifier_call = arch_timer_cpu_notify, | 460 | .notifier_call = arch_timer_cpu_notify, |
| 261 | }; | 461 | }; |
| 262 | 462 | ||
| @@ -265,22 +465,12 @@ static int __init arch_timer_register(void) | |||
| 265 | int err; | 465 | int err; |
| 266 | int ppi; | 466 | int ppi; |
| 267 | 467 | ||
| 268 | err = arch_timer_available(); | ||
| 269 | if (err) | ||
| 270 | goto out; | ||
| 271 | |||
| 272 | arch_timer_evt = alloc_percpu(struct clock_event_device); | 468 | arch_timer_evt = alloc_percpu(struct clock_event_device); |
| 273 | if (!arch_timer_evt) { | 469 | if (!arch_timer_evt) { |
| 274 | err = -ENOMEM; | 470 | err = -ENOMEM; |
| 275 | goto out; | 471 | goto out; |
| 276 | } | 472 | } |
| 277 | 473 | ||
| 278 | clocksource_register_hz(&clocksource_counter, arch_timer_rate); | ||
| 279 | cyclecounter.mult = clocksource_counter.mult; | ||
| 280 | cyclecounter.shift = clocksource_counter.shift; | ||
| 281 | timecounter_init(&timecounter, &cyclecounter, | ||
| 282 | arch_counter_get_cntvct()); | ||
| 283 | |||
| 284 | if (arch_timer_use_virtual) { | 474 | if (arch_timer_use_virtual) { |
| 285 | ppi = arch_timer_ppi[VIRT_PPI]; | 475 | ppi = arch_timer_ppi[VIRT_PPI]; |
| 286 | err = request_percpu_irq(ppi, arch_timer_handler_virt, | 476 | err = request_percpu_irq(ppi, arch_timer_handler_virt, |
| @@ -331,24 +521,77 @@ out: | |||
| 331 | return err; | 521 | return err; |
| 332 | } | 522 | } |
| 333 | 523 | ||
| 524 | static int __init arch_timer_mem_register(void __iomem *base, unsigned int irq) | ||
| 525 | { | ||
| 526 | int ret; | ||
| 527 | irq_handler_t func; | ||
| 528 | struct arch_timer *t; | ||
| 529 | |||
| 530 | t = kzalloc(sizeof(*t), GFP_KERNEL); | ||
| 531 | if (!t) | ||
| 532 | return -ENOMEM; | ||
| 533 | |||
| 534 | t->base = base; | ||
| 535 | t->evt.irq = irq; | ||
| 536 | __arch_timer_setup(ARCH_MEM_TIMER, &t->evt); | ||
| 537 | |||
| 538 | if (arch_timer_mem_use_virtual) | ||
| 539 | func = arch_timer_handler_virt_mem; | ||
| 540 | else | ||
| 541 | func = arch_timer_handler_phys_mem; | ||
| 542 | |||
| 543 | ret = request_irq(irq, func, IRQF_TIMER, "arch_mem_timer", &t->evt); | ||
| 544 | if (ret) { | ||
| 545 | pr_err("arch_timer: Failed to request mem timer irq\n"); | ||
| 546 | kfree(t); | ||
| 547 | } | ||
| 548 | |||
| 549 | return ret; | ||
| 550 | } | ||
| 551 | |||
| 552 | static const struct of_device_id arch_timer_of_match[] __initconst = { | ||
| 553 | { .compatible = "arm,armv7-timer", }, | ||
| 554 | { .compatible = "arm,armv8-timer", }, | ||
| 555 | {}, | ||
| 556 | }; | ||
| 557 | |||
| 558 | static const struct of_device_id arch_timer_mem_of_match[] __initconst = { | ||
| 559 | { .compatible = "arm,armv7-timer-mem", }, | ||
| 560 | {}, | ||
| 561 | }; | ||
| 562 | |||
| 563 | static void __init arch_timer_common_init(void) | ||
| 564 | { | ||
| 565 | unsigned mask = ARCH_CP15_TIMER | ARCH_MEM_TIMER; | ||
| 566 | |||
| 567 | /* Wait until both nodes are probed if we have two timers */ | ||
| 568 | if ((arch_timers_present & mask) != mask) { | ||
| 569 | if (of_find_matching_node(NULL, arch_timer_mem_of_match) && | ||
| 570 | !(arch_timers_present & ARCH_MEM_TIMER)) | ||
| 571 | return; | ||
| 572 | if (of_find_matching_node(NULL, arch_timer_of_match) && | ||
| 573 | !(arch_timers_present & ARCH_CP15_TIMER)) | ||
| 574 | return; | ||
| 575 | } | ||
| 576 | |||
| 577 | arch_timer_banner(arch_timers_present); | ||
| 578 | arch_counter_register(arch_timers_present); | ||
| 579 | arch_timer_arch_init(); | ||
| 580 | } | ||
| 581 | |||
| 334 | static void __init arch_timer_init(struct device_node *np) | 582 | static void __init arch_timer_init(struct device_node *np) |
| 335 | { | 583 | { |
| 336 | u32 freq; | ||
| 337 | int i; | 584 | int i; |
| 338 | 585 | ||
| 339 | if (arch_timer_get_rate()) { | 586 | if (arch_timers_present & ARCH_CP15_TIMER) { |
| 340 | pr_warn("arch_timer: multiple nodes in dt, skipping\n"); | 587 | pr_warn("arch_timer: multiple nodes in dt, skipping\n"); |
| 341 | return; | 588 | return; |
| 342 | } | 589 | } |
| 343 | 590 | ||
| 344 | /* Try to determine the frequency from the device tree or CNTFRQ */ | 591 | arch_timers_present |= ARCH_CP15_TIMER; |
| 345 | if (!of_property_read_u32(np, "clock-frequency", &freq)) | ||
| 346 | arch_timer_rate = freq; | ||
| 347 | |||
| 348 | for (i = PHYS_SECURE_PPI; i < MAX_TIMER_PPI; i++) | 592 | for (i = PHYS_SECURE_PPI; i < MAX_TIMER_PPI; i++) |
| 349 | arch_timer_ppi[i] = irq_of_parse_and_map(np, i); | 593 | arch_timer_ppi[i] = irq_of_parse_and_map(np, i); |
| 350 | 594 | arch_timer_detect_rate(NULL, np); | |
| 351 | of_node_put(np); | ||
| 352 | 595 | ||
| 353 | /* | 596 | /* |
| 354 | * If HYP mode is available, we know that the physical timer | 597 | * If HYP mode is available, we know that the physical timer |
| @@ -369,7 +612,73 @@ static void __init arch_timer_init(struct device_node *np) | |||
| 369 | } | 612 | } |
| 370 | 613 | ||
| 371 | arch_timer_register(); | 614 | arch_timer_register(); |
| 372 | arch_timer_arch_init(); | 615 | arch_timer_common_init(); |
| 373 | } | 616 | } |
| 374 | CLOCKSOURCE_OF_DECLARE(armv7_arch_timer, "arm,armv7-timer", arch_timer_init); | 617 | CLOCKSOURCE_OF_DECLARE(armv7_arch_timer, "arm,armv7-timer", arch_timer_init); |
| 375 | CLOCKSOURCE_OF_DECLARE(armv8_arch_timer, "arm,armv8-timer", arch_timer_init); | 618 | CLOCKSOURCE_OF_DECLARE(armv8_arch_timer, "arm,armv8-timer", arch_timer_init); |
| 619 | |||
| 620 | static void __init arch_timer_mem_init(struct device_node *np) | ||
| 621 | { | ||
| 622 | struct device_node *frame, *best_frame = NULL; | ||
| 623 | void __iomem *cntctlbase, *base; | ||
| 624 | unsigned int irq; | ||
| 625 | u32 cnttidr; | ||
| 626 | |||
| 627 | arch_timers_present |= ARCH_MEM_TIMER; | ||
| 628 | cntctlbase = of_iomap(np, 0); | ||
| 629 | if (!cntctlbase) { | ||
| 630 | pr_err("arch_timer: Can't find CNTCTLBase\n"); | ||
| 631 | return; | ||
| 632 | } | ||
| 633 | |||
| 634 | cnttidr = readl_relaxed(cntctlbase + CNTTIDR); | ||
| 635 | iounmap(cntctlbase); | ||
| 636 | |||
| 637 | /* | ||
| 638 | * Try to find a virtual capable frame. Otherwise fall back to a | ||
| 639 | * physical capable frame. | ||
| 640 | */ | ||
| 641 | for_each_available_child_of_node(np, frame) { | ||
| 642 | int n; | ||
| 643 | |||
| 644 | if (of_property_read_u32(frame, "frame-number", &n)) { | ||
| 645 | pr_err("arch_timer: Missing frame-number\n"); | ||
| 646 | of_node_put(best_frame); | ||
| 647 | of_node_put(frame); | ||
| 648 | return; | ||
| 649 | } | ||
| 650 | |||
| 651 | if (cnttidr & CNTTIDR_VIRT(n)) { | ||
| 652 | of_node_put(best_frame); | ||
| 653 | best_frame = frame; | ||
| 654 | arch_timer_mem_use_virtual = true; | ||
| 655 | break; | ||
| 656 | } | ||
| 657 | of_node_put(best_frame); | ||
| 658 | best_frame = of_node_get(frame); | ||
| 659 | } | ||
| 660 | |||
| 661 | base = arch_counter_base = of_iomap(best_frame, 0); | ||
| 662 | if (!base) { | ||
| 663 | pr_err("arch_timer: Can't map frame's registers\n"); | ||
| 664 | of_node_put(best_frame); | ||
| 665 | return; | ||
| 666 | } | ||
| 667 | |||
| 668 | if (arch_timer_mem_use_virtual) | ||
| 669 | irq = irq_of_parse_and_map(best_frame, 1); | ||
| 670 | else | ||
| 671 | irq = irq_of_parse_and_map(best_frame, 0); | ||
| 672 | of_node_put(best_frame); | ||
| 673 | if (!irq) { | ||
| 674 | pr_err("arch_timer: Frame missing %s irq", | ||
| 675 | arch_timer_mem_use_virtual ? "virt" : "phys"); | ||
| 676 | return; | ||
| 677 | } | ||
| 678 | |||
| 679 | arch_timer_detect_rate(base, np); | ||
| 680 | arch_timer_mem_register(base, irq); | ||
| 681 | arch_timer_common_init(); | ||
| 682 | } | ||
| 683 | CLOCKSOURCE_OF_DECLARE(armv7_arch_timer_mem, "arm,armv7-timer-mem", | ||
| 684 | arch_timer_mem_init); | ||
diff --git a/drivers/clocksource/arm_global_timer.c b/drivers/clocksource/arm_global_timer.c index db8afc7427a6..b66c1f36066c 100644 --- a/drivers/clocksource/arm_global_timer.c +++ b/drivers/clocksource/arm_global_timer.c | |||
| @@ -164,7 +164,7 @@ static irqreturn_t gt_clockevent_interrupt(int irq, void *dev_id) | |||
| 164 | return IRQ_HANDLED; | 164 | return IRQ_HANDLED; |
| 165 | } | 165 | } |
| 166 | 166 | ||
| 167 | static int __cpuinit gt_clockevents_init(struct clock_event_device *clk) | 167 | static int gt_clockevents_init(struct clock_event_device *clk) |
| 168 | { | 168 | { |
| 169 | int cpu = smp_processor_id(); | 169 | int cpu = smp_processor_id(); |
| 170 | 170 | ||
| @@ -221,8 +221,8 @@ static void __init gt_clocksource_init(void) | |||
| 221 | clocksource_register_hz(>_clocksource, gt_clk_rate); | 221 | clocksource_register_hz(>_clocksource, gt_clk_rate); |
| 222 | } | 222 | } |
| 223 | 223 | ||
| 224 | static int __cpuinit gt_cpu_notify(struct notifier_block *self, | 224 | static int gt_cpu_notify(struct notifier_block *self, unsigned long action, |
| 225 | unsigned long action, void *hcpu) | 225 | void *hcpu) |
| 226 | { | 226 | { |
| 227 | switch (action & ~CPU_TASKS_FROZEN) { | 227 | switch (action & ~CPU_TASKS_FROZEN) { |
| 228 | case CPU_STARTING: | 228 | case CPU_STARTING: |
| @@ -235,7 +235,7 @@ static int __cpuinit gt_cpu_notify(struct notifier_block *self, | |||
| 235 | 235 | ||
| 236 | return NOTIFY_OK; | 236 | return NOTIFY_OK; |
| 237 | } | 237 | } |
| 238 | static struct notifier_block gt_cpu_nb __cpuinitdata = { | 238 | static struct notifier_block gt_cpu_nb = { |
| 239 | .notifier_call = gt_cpu_notify, | 239 | .notifier_call = gt_cpu_notify, |
| 240 | }; | 240 | }; |
| 241 | 241 | ||
diff --git a/drivers/clocksource/bcm_kona_timer.c b/drivers/clocksource/bcm_kona_timer.c index ba3d85904c9a..0d7d8c3ed6b2 100644 --- a/drivers/clocksource/bcm_kona_timer.c +++ b/drivers/clocksource/bcm_kona_timer.c | |||
| @@ -99,7 +99,8 @@ kona_timer_get_counter(void *timer_base, uint32_t *msw, uint32_t *lsw) | |||
| 99 | } | 99 | } |
| 100 | 100 | ||
| 101 | static const struct of_device_id bcm_timer_ids[] __initconst = { | 101 | static const struct of_device_id bcm_timer_ids[] __initconst = { |
| 102 | {.compatible = "bcm,kona-timer"}, | 102 | {.compatible = "brcm,kona-timer"}, |
| 103 | {.compatible = "bcm,kona-timer"}, /* deprecated name */ | ||
| 103 | {}, | 104 | {}, |
| 104 | }; | 105 | }; |
| 105 | 106 | ||
| @@ -201,4 +202,9 @@ static void __init kona_timer_init(struct device_node *node) | |||
| 201 | kona_timer_set_next_event((arch_timer_rate / HZ), NULL); | 202 | kona_timer_set_next_event((arch_timer_rate / HZ), NULL); |
| 202 | } | 203 | } |
| 203 | 204 | ||
| 205 | CLOCKSOURCE_OF_DECLARE(brcm_kona, "brcm,kona-timer", kona_timer_init); | ||
| 206 | /* | ||
| 207 | * bcm,kona-timer is deprecated by brcm,kona-timer | ||
| 208 | * being kept here for driver compatibility | ||
| 209 | */ | ||
| 204 | CLOCKSOURCE_OF_DECLARE(bcm_kona, "bcm,kona-timer", kona_timer_init); | 210 | CLOCKSOURCE_OF_DECLARE(bcm_kona, "bcm,kona-timer", kona_timer_init); |
diff --git a/drivers/clocksource/cadence_ttc_timer.c b/drivers/clocksource/cadence_ttc_timer.c index 4cbe28c74631..b2bb3a4bc205 100644 --- a/drivers/clocksource/cadence_ttc_timer.c +++ b/drivers/clocksource/cadence_ttc_timer.c | |||
| @@ -21,7 +21,7 @@ | |||
| 21 | #include <linux/of_address.h> | 21 | #include <linux/of_address.h> |
| 22 | #include <linux/of_irq.h> | 22 | #include <linux/of_irq.h> |
| 23 | #include <linux/slab.h> | 23 | #include <linux/slab.h> |
| 24 | #include <linux/clk-provider.h> | 24 | #include <linux/sched_clock.h> |
| 25 | 25 | ||
| 26 | /* | 26 | /* |
| 27 | * This driver configures the 2 16-bit count-up timers as follows: | 27 | * This driver configures the 2 16-bit count-up timers as follows: |
| @@ -95,6 +95,8 @@ struct ttc_timer_clockevent { | |||
| 95 | #define to_ttc_timer_clkevent(x) \ | 95 | #define to_ttc_timer_clkevent(x) \ |
| 96 | container_of(x, struct ttc_timer_clockevent, ce) | 96 | container_of(x, struct ttc_timer_clockevent, ce) |
| 97 | 97 | ||
| 98 | static void __iomem *ttc_sched_clock_val_reg; | ||
| 99 | |||
| 98 | /** | 100 | /** |
| 99 | * ttc_set_interval - Set the timer interval value | 101 | * ttc_set_interval - Set the timer interval value |
| 100 | * | 102 | * |
| @@ -156,6 +158,11 @@ static cycle_t __ttc_clocksource_read(struct clocksource *cs) | |||
| 156 | TTC_COUNT_VAL_OFFSET); | 158 | TTC_COUNT_VAL_OFFSET); |
| 157 | } | 159 | } |
| 158 | 160 | ||
| 161 | static u32 notrace ttc_sched_clock_read(void) | ||
| 162 | { | ||
| 163 | return __raw_readl(ttc_sched_clock_val_reg); | ||
| 164 | } | ||
| 165 | |||
| 159 | /** | 166 | /** |
| 160 | * ttc_set_next_event - Sets the time interval for next event | 167 | * ttc_set_next_event - Sets the time interval for next event |
| 161 | * | 168 | * |
| @@ -297,6 +304,10 @@ static void __init ttc_setup_clocksource(struct clk *clk, void __iomem *base) | |||
| 297 | kfree(ttccs); | 304 | kfree(ttccs); |
| 298 | return; | 305 | return; |
| 299 | } | 306 | } |
| 307 | |||
| 308 | ttc_sched_clock_val_reg = base + TTC_COUNT_VAL_OFFSET; | ||
| 309 | setup_sched_clock(ttc_sched_clock_read, 16, | ||
| 310 | clk_get_rate(ttccs->ttc.clk) / PRESCALE); | ||
| 300 | } | 311 | } |
| 301 | 312 | ||
| 302 | static int ttc_rate_change_clockevent_cb(struct notifier_block *nb, | 313 | static int ttc_rate_change_clockevent_cb(struct notifier_block *nb, |
diff --git a/drivers/clocksource/dummy_timer.c b/drivers/clocksource/dummy_timer.c index 1f55f9620338..b3eb582d6a6f 100644 --- a/drivers/clocksource/dummy_timer.c +++ b/drivers/clocksource/dummy_timer.c | |||
| @@ -25,7 +25,7 @@ static void dummy_timer_set_mode(enum clock_event_mode mode, | |||
| 25 | */ | 25 | */ |
| 26 | } | 26 | } |
| 27 | 27 | ||
| 28 | static void __cpuinit dummy_timer_setup(void) | 28 | static void dummy_timer_setup(void) |
| 29 | { | 29 | { |
| 30 | int cpu = smp_processor_id(); | 30 | int cpu = smp_processor_id(); |
| 31 | struct clock_event_device *evt = __this_cpu_ptr(&dummy_timer_evt); | 31 | struct clock_event_device *evt = __this_cpu_ptr(&dummy_timer_evt); |
| @@ -41,7 +41,7 @@ static void __cpuinit dummy_timer_setup(void) | |||
| 41 | clockevents_register_device(evt); | 41 | clockevents_register_device(evt); |
| 42 | } | 42 | } |
| 43 | 43 | ||
| 44 | static int __cpuinit dummy_timer_cpu_notify(struct notifier_block *self, | 44 | static int dummy_timer_cpu_notify(struct notifier_block *self, |
| 45 | unsigned long action, void *hcpu) | 45 | unsigned long action, void *hcpu) |
| 46 | { | 46 | { |
| 47 | if ((action & ~CPU_TASKS_FROZEN) == CPU_STARTING) | 47 | if ((action & ~CPU_TASKS_FROZEN) == CPU_STARTING) |
| @@ -50,7 +50,7 @@ static int __cpuinit dummy_timer_cpu_notify(struct notifier_block *self, | |||
| 50 | return NOTIFY_OK; | 50 | return NOTIFY_OK; |
| 51 | } | 51 | } |
| 52 | 52 | ||
| 53 | static struct notifier_block dummy_timer_cpu_nb __cpuinitdata = { | 53 | static struct notifier_block dummy_timer_cpu_nb = { |
| 54 | .notifier_call = dummy_timer_cpu_notify, | 54 | .notifier_call = dummy_timer_cpu_notify, |
| 55 | }; | 55 | }; |
| 56 | 56 | ||
diff --git a/drivers/clocksource/em_sti.c b/drivers/clocksource/em_sti.c index 4329a29a5310..b9c81b7c3a3b 100644 --- a/drivers/clocksource/em_sti.c +++ b/drivers/clocksource/em_sti.c | |||
| @@ -315,68 +315,47 @@ static int em_sti_probe(struct platform_device *pdev) | |||
| 315 | { | 315 | { |
| 316 | struct em_sti_priv *p; | 316 | struct em_sti_priv *p; |
| 317 | struct resource *res; | 317 | struct resource *res; |
| 318 | int irq, ret; | 318 | int irq; |
| 319 | 319 | ||
| 320 | p = kzalloc(sizeof(*p), GFP_KERNEL); | 320 | p = devm_kzalloc(&pdev->dev, sizeof(*p), GFP_KERNEL); |
| 321 | if (p == NULL) { | 321 | if (p == NULL) { |
| 322 | dev_err(&pdev->dev, "failed to allocate driver data\n"); | 322 | dev_err(&pdev->dev, "failed to allocate driver data\n"); |
| 323 | ret = -ENOMEM; | 323 | return -ENOMEM; |
| 324 | goto err0; | ||
| 325 | } | 324 | } |
| 326 | 325 | ||
| 327 | p->pdev = pdev; | 326 | p->pdev = pdev; |
| 328 | platform_set_drvdata(pdev, p); | 327 | platform_set_drvdata(pdev, p); |
| 329 | 328 | ||
| 330 | res = platform_get_resource(pdev, IORESOURCE_MEM, 0); | ||
| 331 | if (!res) { | ||
| 332 | dev_err(&pdev->dev, "failed to get I/O memory\n"); | ||
| 333 | ret = -EINVAL; | ||
| 334 | goto err0; | ||
| 335 | } | ||
| 336 | |||
| 337 | irq = platform_get_irq(pdev, 0); | 329 | irq = platform_get_irq(pdev, 0); |
| 338 | if (irq < 0) { | 330 | if (irq < 0) { |
| 339 | dev_err(&pdev->dev, "failed to get irq\n"); | 331 | dev_err(&pdev->dev, "failed to get irq\n"); |
| 340 | ret = -EINVAL; | 332 | return -EINVAL; |
| 341 | goto err0; | ||
| 342 | } | 333 | } |
| 343 | 334 | ||
| 344 | /* map memory, let base point to the STI instance */ | 335 | /* map memory, let base point to the STI instance */ |
| 345 | p->base = ioremap_nocache(res->start, resource_size(res)); | 336 | res = platform_get_resource(pdev, IORESOURCE_MEM, 0); |
| 346 | if (p->base == NULL) { | 337 | p->base = devm_ioremap_resource(&pdev->dev, res); |
| 347 | dev_err(&pdev->dev, "failed to remap I/O memory\n"); | 338 | if (IS_ERR(p->base)) |
| 348 | ret = -ENXIO; | 339 | return PTR_ERR(p->base); |
| 349 | goto err0; | ||
| 350 | } | ||
| 351 | 340 | ||
| 352 | /* get hold of clock */ | 341 | /* get hold of clock */ |
| 353 | p->clk = clk_get(&pdev->dev, "sclk"); | 342 | p->clk = devm_clk_get(&pdev->dev, "sclk"); |
| 354 | if (IS_ERR(p->clk)) { | 343 | if (IS_ERR(p->clk)) { |
| 355 | dev_err(&pdev->dev, "cannot get clock\n"); | 344 | dev_err(&pdev->dev, "cannot get clock\n"); |
| 356 | ret = PTR_ERR(p->clk); | 345 | return PTR_ERR(p->clk); |
| 357 | goto err1; | ||
| 358 | } | 346 | } |
| 359 | 347 | ||
| 360 | if (request_irq(irq, em_sti_interrupt, | 348 | if (devm_request_irq(&pdev->dev, irq, em_sti_interrupt, |
| 361 | IRQF_TIMER | IRQF_IRQPOLL | IRQF_NOBALANCING, | 349 | IRQF_TIMER | IRQF_IRQPOLL | IRQF_NOBALANCING, |
| 362 | dev_name(&pdev->dev), p)) { | 350 | dev_name(&pdev->dev), p)) { |
| 363 | dev_err(&pdev->dev, "failed to request low IRQ\n"); | 351 | dev_err(&pdev->dev, "failed to request low IRQ\n"); |
| 364 | ret = -ENOENT; | 352 | return -ENOENT; |
| 365 | goto err2; | ||
| 366 | } | 353 | } |
| 367 | 354 | ||
| 368 | raw_spin_lock_init(&p->lock); | 355 | raw_spin_lock_init(&p->lock); |
| 369 | em_sti_register_clockevent(p); | 356 | em_sti_register_clockevent(p); |
| 370 | em_sti_register_clocksource(p); | 357 | em_sti_register_clocksource(p); |
| 371 | return 0; | 358 | return 0; |
| 372 | |||
| 373 | err2: | ||
| 374 | clk_put(p->clk); | ||
| 375 | err1: | ||
| 376 | iounmap(p->base); | ||
| 377 | err0: | ||
| 378 | kfree(p); | ||
| 379 | return ret; | ||
| 380 | } | 359 | } |
| 381 | 360 | ||
| 382 | static int em_sti_remove(struct platform_device *pdev) | 361 | static int em_sti_remove(struct platform_device *pdev) |
diff --git a/drivers/clocksource/exynos_mct.c b/drivers/clocksource/exynos_mct.c index a70480409ea5..5b34768f4d7c 100644 --- a/drivers/clocksource/exynos_mct.c +++ b/drivers/clocksource/exynos_mct.c | |||
| @@ -16,6 +16,7 @@ | |||
| 16 | #include <linux/err.h> | 16 | #include <linux/err.h> |
| 17 | #include <linux/clk.h> | 17 | #include <linux/clk.h> |
| 18 | #include <linux/clockchips.h> | 18 | #include <linux/clockchips.h> |
| 19 | #include <linux/cpu.h> | ||
| 19 | #include <linux/platform_device.h> | 20 | #include <linux/platform_device.h> |
| 20 | #include <linux/delay.h> | 21 | #include <linux/delay.h> |
| 21 | #include <linux/percpu.h> | 22 | #include <linux/percpu.h> |
| @@ -24,7 +25,6 @@ | |||
| 24 | #include <linux/of_address.h> | 25 | #include <linux/of_address.h> |
| 25 | #include <linux/clocksource.h> | 26 | #include <linux/clocksource.h> |
| 26 | 27 | ||
| 27 | #include <asm/localtimer.h> | ||
| 28 | #include <asm/mach/time.h> | 28 | #include <asm/mach/time.h> |
| 29 | 29 | ||
| 30 | #define EXYNOS4_MCTREG(x) (x) | 30 | #define EXYNOS4_MCTREG(x) (x) |
| @@ -80,7 +80,7 @@ static unsigned int mct_int_type; | |||
| 80 | static int mct_irqs[MCT_NR_IRQS]; | 80 | static int mct_irqs[MCT_NR_IRQS]; |
| 81 | 81 | ||
| 82 | struct mct_clock_event_device { | 82 | struct mct_clock_event_device { |
| 83 | struct clock_event_device *evt; | 83 | struct clock_event_device evt; |
| 84 | unsigned long base; | 84 | unsigned long base; |
| 85 | char name[10]; | 85 | char name[10]; |
| 86 | }; | 86 | }; |
| @@ -295,8 +295,6 @@ static void exynos4_clockevent_init(void) | |||
| 295 | setup_irq(mct_irqs[MCT_G0_IRQ], &mct_comp_event_irq); | 295 | setup_irq(mct_irqs[MCT_G0_IRQ], &mct_comp_event_irq); |
| 296 | } | 296 | } |
| 297 | 297 | ||
| 298 | #ifdef CONFIG_LOCAL_TIMERS | ||
| 299 | |||
| 300 | static DEFINE_PER_CPU(struct mct_clock_event_device, percpu_mct_tick); | 298 | static DEFINE_PER_CPU(struct mct_clock_event_device, percpu_mct_tick); |
| 301 | 299 | ||
| 302 | /* Clock event handling */ | 300 | /* Clock event handling */ |
| @@ -369,7 +367,7 @@ static inline void exynos4_tick_set_mode(enum clock_event_mode mode, | |||
| 369 | 367 | ||
| 370 | static int exynos4_mct_tick_clear(struct mct_clock_event_device *mevt) | 368 | static int exynos4_mct_tick_clear(struct mct_clock_event_device *mevt) |
| 371 | { | 369 | { |
| 372 | struct clock_event_device *evt = mevt->evt; | 370 | struct clock_event_device *evt = &mevt->evt; |
| 373 | 371 | ||
| 374 | /* | 372 | /* |
| 375 | * This is for supporting oneshot mode. | 373 | * This is for supporting oneshot mode. |
| @@ -391,7 +389,7 @@ static int exynos4_mct_tick_clear(struct mct_clock_event_device *mevt) | |||
| 391 | static irqreturn_t exynos4_mct_tick_isr(int irq, void *dev_id) | 389 | static irqreturn_t exynos4_mct_tick_isr(int irq, void *dev_id) |
| 392 | { | 390 | { |
| 393 | struct mct_clock_event_device *mevt = dev_id; | 391 | struct mct_clock_event_device *mevt = dev_id; |
| 394 | struct clock_event_device *evt = mevt->evt; | 392 | struct clock_event_device *evt = &mevt->evt; |
| 395 | 393 | ||
| 396 | exynos4_mct_tick_clear(mevt); | 394 | exynos4_mct_tick_clear(mevt); |
| 397 | 395 | ||
| @@ -400,13 +398,12 @@ static irqreturn_t exynos4_mct_tick_isr(int irq, void *dev_id) | |||
| 400 | return IRQ_HANDLED; | 398 | return IRQ_HANDLED; |
| 401 | } | 399 | } |
| 402 | 400 | ||
| 403 | static int __cpuinit exynos4_local_timer_setup(struct clock_event_device *evt) | 401 | static int exynos4_local_timer_setup(struct clock_event_device *evt) |
| 404 | { | 402 | { |
| 405 | struct mct_clock_event_device *mevt; | 403 | struct mct_clock_event_device *mevt; |
| 406 | unsigned int cpu = smp_processor_id(); | 404 | unsigned int cpu = smp_processor_id(); |
| 407 | 405 | ||
| 408 | mevt = this_cpu_ptr(&percpu_mct_tick); | 406 | mevt = container_of(evt, struct mct_clock_event_device, evt); |
| 409 | mevt->evt = evt; | ||
| 410 | 407 | ||
| 411 | mevt->base = EXYNOS4_MCT_L_BASE(cpu); | 408 | mevt->base = EXYNOS4_MCT_L_BASE(cpu); |
| 412 | sprintf(mevt->name, "mct_tick%d", cpu); | 409 | sprintf(mevt->name, "mct_tick%d", cpu); |
| @@ -448,14 +445,37 @@ static void exynos4_local_timer_stop(struct clock_event_device *evt) | |||
| 448 | disable_percpu_irq(mct_irqs[MCT_L0_IRQ]); | 445 | disable_percpu_irq(mct_irqs[MCT_L0_IRQ]); |
| 449 | } | 446 | } |
| 450 | 447 | ||
| 451 | static struct local_timer_ops exynos4_mct_tick_ops __cpuinitdata = { | 448 | static int exynos4_mct_cpu_notify(struct notifier_block *self, |
| 452 | .setup = exynos4_local_timer_setup, | 449 | unsigned long action, void *hcpu) |
| 453 | .stop = exynos4_local_timer_stop, | 450 | { |
| 451 | struct mct_clock_event_device *mevt; | ||
| 452 | |||
| 453 | /* | ||
| 454 | * Grab cpu pointer in each case to avoid spurious | ||
| 455 | * preemptible warnings | ||
| 456 | */ | ||
| 457 | switch (action & ~CPU_TASKS_FROZEN) { | ||
| 458 | case CPU_STARTING: | ||
| 459 | mevt = this_cpu_ptr(&percpu_mct_tick); | ||
| 460 | exynos4_local_timer_setup(&mevt->evt); | ||
| 461 | break; | ||
| 462 | case CPU_DYING: | ||
| 463 | mevt = this_cpu_ptr(&percpu_mct_tick); | ||
| 464 | exynos4_local_timer_stop(&mevt->evt); | ||
| 465 | break; | ||
| 466 | } | ||
| 467 | |||
| 468 | return NOTIFY_OK; | ||
| 469 | } | ||
| 470 | |||
| 471 | static struct notifier_block exynos4_mct_cpu_nb = { | ||
| 472 | .notifier_call = exynos4_mct_cpu_notify, | ||
| 454 | }; | 473 | }; |
| 455 | #endif /* CONFIG_LOCAL_TIMERS */ | ||
| 456 | 474 | ||
| 457 | static void __init exynos4_timer_resources(struct device_node *np, void __iomem *base) | 475 | static void __init exynos4_timer_resources(struct device_node *np, void __iomem *base) |
| 458 | { | 476 | { |
| 477 | int err; | ||
| 478 | struct mct_clock_event_device *mevt = this_cpu_ptr(&percpu_mct_tick); | ||
| 459 | struct clk *mct_clk, *tick_clk; | 479 | struct clk *mct_clk, *tick_clk; |
| 460 | 480 | ||
| 461 | tick_clk = np ? of_clk_get_by_name(np, "fin_pll") : | 481 | tick_clk = np ? of_clk_get_by_name(np, "fin_pll") : |
| @@ -473,9 +493,7 @@ static void __init exynos4_timer_resources(struct device_node *np, void __iomem | |||
| 473 | if (!reg_base) | 493 | if (!reg_base) |
| 474 | panic("%s: unable to ioremap mct address space\n", __func__); | 494 | panic("%s: unable to ioremap mct address space\n", __func__); |
| 475 | 495 | ||
| 476 | #ifdef CONFIG_LOCAL_TIMERS | ||
| 477 | if (mct_int_type == MCT_INT_PPI) { | 496 | if (mct_int_type == MCT_INT_PPI) { |
| 478 | int err; | ||
| 479 | 497 | ||
| 480 | err = request_percpu_irq(mct_irqs[MCT_L0_IRQ], | 498 | err = request_percpu_irq(mct_irqs[MCT_L0_IRQ], |
| 481 | exynos4_mct_tick_isr, "MCT", | 499 | exynos4_mct_tick_isr, "MCT", |
| @@ -484,8 +502,16 @@ static void __init exynos4_timer_resources(struct device_node *np, void __iomem | |||
| 484 | mct_irqs[MCT_L0_IRQ], err); | 502 | mct_irqs[MCT_L0_IRQ], err); |
| 485 | } | 503 | } |
| 486 | 504 | ||
| 487 | local_timer_register(&exynos4_mct_tick_ops); | 505 | err = register_cpu_notifier(&exynos4_mct_cpu_nb); |
| 488 | #endif /* CONFIG_LOCAL_TIMERS */ | 506 | if (err) |
| 507 | goto out_irq; | ||
| 508 | |||
| 509 | /* Immediately configure the timer on the boot CPU */ | ||
| 510 | exynos4_local_timer_setup(&mevt->evt); | ||
| 511 | return; | ||
| 512 | |||
| 513 | out_irq: | ||
| 514 | free_percpu_irq(mct_irqs[MCT_L0_IRQ], &percpu_mct_tick); | ||
| 489 | } | 515 | } |
| 490 | 516 | ||
| 491 | void __init mct_init(void __iomem *base, int irq_g0, int irq_l0, int irq_l1) | 517 | void __init mct_init(void __iomem *base, int irq_g0, int irq_l0, int irq_l1) |
diff --git a/drivers/clocksource/metag_generic.c b/drivers/clocksource/metag_generic.c index 6722f0e2fe40..9e4db41abe3c 100644 --- a/drivers/clocksource/metag_generic.c +++ b/drivers/clocksource/metag_generic.c | |||
| @@ -109,7 +109,7 @@ unsigned long long sched_clock(void) | |||
| 109 | return ticks << HARDWARE_TO_NS_SHIFT; | 109 | return ticks << HARDWARE_TO_NS_SHIFT; |
| 110 | } | 110 | } |
| 111 | 111 | ||
| 112 | static void __cpuinit arch_timer_setup(unsigned int cpu) | 112 | static void arch_timer_setup(unsigned int cpu) |
| 113 | { | 113 | { |
| 114 | unsigned int txdivtime; | 114 | unsigned int txdivtime; |
| 115 | struct clock_event_device *clk = &per_cpu(local_clockevent, cpu); | 115 | struct clock_event_device *clk = &per_cpu(local_clockevent, cpu); |
| @@ -154,7 +154,7 @@ static void __cpuinit arch_timer_setup(unsigned int cpu) | |||
| 154 | } | 154 | } |
| 155 | } | 155 | } |
| 156 | 156 | ||
| 157 | static int __cpuinit arch_timer_cpu_notify(struct notifier_block *self, | 157 | static int arch_timer_cpu_notify(struct notifier_block *self, |
| 158 | unsigned long action, void *hcpu) | 158 | unsigned long action, void *hcpu) |
| 159 | { | 159 | { |
| 160 | int cpu = (long)hcpu; | 160 | int cpu = (long)hcpu; |
| @@ -169,7 +169,7 @@ static int __cpuinit arch_timer_cpu_notify(struct notifier_block *self, | |||
| 169 | return NOTIFY_OK; | 169 | return NOTIFY_OK; |
| 170 | } | 170 | } |
| 171 | 171 | ||
| 172 | static struct notifier_block __cpuinitdata arch_timer_cpu_nb = { | 172 | static struct notifier_block arch_timer_cpu_nb = { |
| 173 | .notifier_call = arch_timer_cpu_notify, | 173 | .notifier_call = arch_timer_cpu_notify, |
| 174 | }; | 174 | }; |
| 175 | 175 | ||
diff --git a/drivers/clocksource/moxart_timer.c b/drivers/clocksource/moxart_timer.c new file mode 100644 index 000000000000..5eb2c35932b1 --- /dev/null +++ b/drivers/clocksource/moxart_timer.c | |||
| @@ -0,0 +1,165 @@ | |||
| 1 | /* | ||
| 2 | * MOXA ART SoCs timer handling. | ||
| 3 | * | ||
| 4 | * Copyright (C) 2013 Jonas Jensen | ||
| 5 | * | ||
| 6 | * Jonas Jensen <jonas.jensen@gmail.com> | ||
| 7 | * | ||
| 8 | * This file is licensed under the terms of the GNU General Public | ||
| 9 | * License version 2. This program is licensed "as is" without any | ||
| 10 | * warranty of any kind, whether express or implied. | ||
| 11 | */ | ||
| 12 | |||
| 13 | #include <linux/clk.h> | ||
| 14 | #include <linux/clockchips.h> | ||
| 15 | #include <linux/interrupt.h> | ||
| 16 | #include <linux/irq.h> | ||
| 17 | #include <linux/irqreturn.h> | ||
| 18 | #include <linux/of.h> | ||
| 19 | #include <linux/of_address.h> | ||
| 20 | #include <linux/of_irq.h> | ||
| 21 | #include <linux/io.h> | ||
| 22 | #include <linux/clocksource.h> | ||
| 23 | #include <linux/bitops.h> | ||
| 24 | |||
| 25 | #define TIMER1_BASE 0x00 | ||
| 26 | #define TIMER2_BASE 0x10 | ||
| 27 | #define TIMER3_BASE 0x20 | ||
| 28 | |||
| 29 | #define REG_COUNT 0x0 /* writable */ | ||
| 30 | #define REG_LOAD 0x4 | ||
| 31 | #define REG_MATCH1 0x8 | ||
| 32 | #define REG_MATCH2 0xC | ||
| 33 | |||
| 34 | #define TIMER_CR 0x30 | ||
| 35 | #define TIMER_INTR_STATE 0x34 | ||
| 36 | #define TIMER_INTR_MASK 0x38 | ||
| 37 | |||
| 38 | /* | ||
| 39 | * TIMER_CR flags: | ||
| 40 | * | ||
| 41 | * TIMEREG_CR_*_CLOCK 0: PCLK, 1: EXT1CLK | ||
| 42 | * TIMEREG_CR_*_INT overflow interrupt enable bit | ||
| 43 | */ | ||
| 44 | #define TIMEREG_CR_1_ENABLE BIT(0) | ||
| 45 | #define TIMEREG_CR_1_CLOCK BIT(1) | ||
| 46 | #define TIMEREG_CR_1_INT BIT(2) | ||
| 47 | #define TIMEREG_CR_2_ENABLE BIT(3) | ||
| 48 | #define TIMEREG_CR_2_CLOCK BIT(4) | ||
| 49 | #define TIMEREG_CR_2_INT BIT(5) | ||
| 50 | #define TIMEREG_CR_3_ENABLE BIT(6) | ||
| 51 | #define TIMEREG_CR_3_CLOCK BIT(7) | ||
| 52 | #define TIMEREG_CR_3_INT BIT(8) | ||
| 53 | #define TIMEREG_CR_COUNT_UP BIT(9) | ||
| 54 | |||
| 55 | #define TIMER1_ENABLE (TIMEREG_CR_2_ENABLE | TIMEREG_CR_1_ENABLE) | ||
| 56 | #define TIMER1_DISABLE (TIMEREG_CR_2_ENABLE) | ||
| 57 | |||
| 58 | static void __iomem *base; | ||
| 59 | static unsigned int clock_count_per_tick; | ||
| 60 | |||
| 61 | static void moxart_clkevt_mode(enum clock_event_mode mode, | ||
| 62 | struct clock_event_device *clk) | ||
| 63 | { | ||
| 64 | switch (mode) { | ||
| 65 | case CLOCK_EVT_MODE_RESUME: | ||
| 66 | case CLOCK_EVT_MODE_ONESHOT: | ||
| 67 | writel(TIMER1_DISABLE, base + TIMER_CR); | ||
| 68 | writel(~0, base + TIMER1_BASE + REG_LOAD); | ||
| 69 | break; | ||
| 70 | case CLOCK_EVT_MODE_PERIODIC: | ||
| 71 | writel(clock_count_per_tick, base + TIMER1_BASE + REG_LOAD); | ||
| 72 | writel(TIMER1_ENABLE, base + TIMER_CR); | ||
| 73 | break; | ||
| 74 | case CLOCK_EVT_MODE_UNUSED: | ||
| 75 | case CLOCK_EVT_MODE_SHUTDOWN: | ||
| 76 | default: | ||
| 77 | writel(TIMER1_DISABLE, base + TIMER_CR); | ||
| 78 | break; | ||
| 79 | } | ||
| 80 | } | ||
| 81 | |||
| 82 | static int moxart_clkevt_next_event(unsigned long cycles, | ||
| 83 | struct clock_event_device *unused) | ||
| 84 | { | ||
| 85 | u32 u; | ||
| 86 | |||
| 87 | writel(TIMER1_DISABLE, base + TIMER_CR); | ||
| 88 | |||
| 89 | u = readl(base + TIMER1_BASE + REG_COUNT) - cycles; | ||
| 90 | writel(u, base + TIMER1_BASE + REG_MATCH1); | ||
| 91 | |||
| 92 | writel(TIMER1_ENABLE, base + TIMER_CR); | ||
| 93 | |||
| 94 | return 0; | ||
| 95 | } | ||
| 96 | |||
| 97 | static struct clock_event_device moxart_clockevent = { | ||
| 98 | .name = "moxart_timer", | ||
| 99 | .rating = 200, | ||
| 100 | .features = CLOCK_EVT_FEAT_PERIODIC | CLOCK_EVT_FEAT_ONESHOT, | ||
| 101 | .set_mode = moxart_clkevt_mode, | ||
| 102 | .set_next_event = moxart_clkevt_next_event, | ||
| 103 | }; | ||
| 104 | |||
| 105 | static irqreturn_t moxart_timer_interrupt(int irq, void *dev_id) | ||
| 106 | { | ||
| 107 | struct clock_event_device *evt = dev_id; | ||
| 108 | evt->event_handler(evt); | ||
| 109 | return IRQ_HANDLED; | ||
| 110 | } | ||
| 111 | |||
| 112 | static struct irqaction moxart_timer_irq = { | ||
| 113 | .name = "moxart-timer", | ||
| 114 | .flags = IRQF_TIMER, | ||
| 115 | .handler = moxart_timer_interrupt, | ||
| 116 | .dev_id = &moxart_clockevent, | ||
| 117 | }; | ||
| 118 | |||
| 119 | static void __init moxart_timer_init(struct device_node *node) | ||
| 120 | { | ||
| 121 | int ret, irq; | ||
| 122 | unsigned long pclk; | ||
| 123 | struct clk *clk; | ||
| 124 | |||
| 125 | base = of_iomap(node, 0); | ||
| 126 | if (!base) | ||
| 127 | panic("%s: of_iomap failed\n", node->full_name); | ||
| 128 | |||
| 129 | irq = irq_of_parse_and_map(node, 0); | ||
| 130 | if (irq <= 0) | ||
| 131 | panic("%s: irq_of_parse_and_map failed\n", node->full_name); | ||
| 132 | |||
| 133 | ret = setup_irq(irq, &moxart_timer_irq); | ||
| 134 | if (ret) | ||
| 135 | panic("%s: setup_irq failed\n", node->full_name); | ||
| 136 | |||
| 137 | clk = of_clk_get(node, 0); | ||
| 138 | if (IS_ERR(clk)) | ||
| 139 | panic("%s: of_clk_get failed\n", node->full_name); | ||
| 140 | |||
| 141 | pclk = clk_get_rate(clk); | ||
| 142 | |||
| 143 | if (clocksource_mmio_init(base + TIMER2_BASE + REG_COUNT, | ||
| 144 | "moxart_timer", pclk, 200, 32, | ||
| 145 | clocksource_mmio_readl_down)) | ||
| 146 | panic("%s: clocksource_mmio_init failed\n", node->full_name); | ||
| 147 | |||
| 148 | clock_count_per_tick = DIV_ROUND_CLOSEST(pclk, HZ); | ||
| 149 | |||
| 150 | writel(~0, base + TIMER2_BASE + REG_LOAD); | ||
| 151 | writel(TIMEREG_CR_2_ENABLE, base + TIMER_CR); | ||
| 152 | |||
| 153 | moxart_clockevent.cpumask = cpumask_of(0); | ||
| 154 | moxart_clockevent.irq = irq; | ||
| 155 | |||
| 156 | /* | ||
| 157 | * documentation is not publicly available: | ||
| 158 | * min_delta / max_delta obtained by trial-and-error, | ||
| 159 | * max_delta 0xfffffffe should be ok because count | ||
| 160 | * register size is u32 | ||
| 161 | */ | ||
| 162 | clockevents_config_and_register(&moxart_clockevent, pclk, | ||
| 163 | 0x4, 0xfffffffe); | ||
| 164 | } | ||
| 165 | CLOCKSOURCE_OF_DECLARE(moxart, "moxa,moxart-timer", moxart_timer_init); | ||
diff --git a/drivers/clocksource/nomadik-mtu.c b/drivers/clocksource/nomadik-mtu.c index 2242cd3d618d..ed7b73b508e0 100644 --- a/drivers/clocksource/nomadik-mtu.c +++ b/drivers/clocksource/nomadik-mtu.c | |||
| @@ -165,7 +165,8 @@ static void nmdk_clkevt_resume(struct clock_event_device *cedev) | |||
| 165 | 165 | ||
| 166 | static struct clock_event_device nmdk_clkevt = { | 166 | static struct clock_event_device nmdk_clkevt = { |
| 167 | .name = "mtu_1", | 167 | .name = "mtu_1", |
| 168 | .features = CLOCK_EVT_FEAT_ONESHOT | CLOCK_EVT_FEAT_PERIODIC, | 168 | .features = CLOCK_EVT_FEAT_ONESHOT | CLOCK_EVT_FEAT_PERIODIC | |
| 169 | CLOCK_EVT_FEAT_DYNIRQ, | ||
| 169 | .rating = 200, | 170 | .rating = 200, |
| 170 | .set_mode = nmdk_clkevt_mode, | 171 | .set_mode = nmdk_clkevt_mode, |
| 171 | .set_next_event = nmdk_clkevt_next, | 172 | .set_next_event = nmdk_clkevt_next, |
diff --git a/drivers/clocksource/samsung_pwm_timer.c b/drivers/clocksource/samsung_pwm_timer.c index 09e8bc7bc92f..85082e8d3052 100644 --- a/drivers/clocksource/samsung_pwm_timer.c +++ b/drivers/clocksource/samsung_pwm_timer.c | |||
| @@ -44,16 +44,28 @@ | |||
| 44 | #define TCFG1_SHIFT(x) ((x) * 4) | 44 | #define TCFG1_SHIFT(x) ((x) * 4) |
| 45 | #define TCFG1_MUX_MASK 0xf | 45 | #define TCFG1_MUX_MASK 0xf |
| 46 | 46 | ||
| 47 | /* | ||
| 48 | * Each channel occupies 4 bits in TCON register, but there is a gap of 4 | ||
| 49 | * bits (one channel) after channel 0, so channels have different numbering | ||
| 50 | * when accessing TCON register. | ||
| 51 | * | ||
| 52 | * In addition, the location of autoreload bit for channel 4 (TCON channel 5) | ||
| 53 | * in its set of bits is 2 as opposed to 3 for other channels. | ||
| 54 | */ | ||
| 47 | #define TCON_START(chan) (1 << (4 * (chan) + 0)) | 55 | #define TCON_START(chan) (1 << (4 * (chan) + 0)) |
| 48 | #define TCON_MANUALUPDATE(chan) (1 << (4 * (chan) + 1)) | 56 | #define TCON_MANUALUPDATE(chan) (1 << (4 * (chan) + 1)) |
| 49 | #define TCON_INVERT(chan) (1 << (4 * (chan) + 2)) | 57 | #define TCON_INVERT(chan) (1 << (4 * (chan) + 2)) |
| 50 | #define TCON_AUTORELOAD(chan) (1 << (4 * (chan) + 3)) | 58 | #define _TCON_AUTORELOAD(chan) (1 << (4 * (chan) + 3)) |
| 59 | #define _TCON_AUTORELOAD4(chan) (1 << (4 * (chan) + 2)) | ||
| 60 | #define TCON_AUTORELOAD(chan) \ | ||
| 61 | ((chan < 5) ? _TCON_AUTORELOAD(chan) : _TCON_AUTORELOAD4(chan)) | ||
| 51 | 62 | ||
| 52 | DEFINE_SPINLOCK(samsung_pwm_lock); | 63 | DEFINE_SPINLOCK(samsung_pwm_lock); |
| 53 | EXPORT_SYMBOL(samsung_pwm_lock); | 64 | EXPORT_SYMBOL(samsung_pwm_lock); |
| 54 | 65 | ||
| 55 | struct samsung_pwm_clocksource { | 66 | struct samsung_pwm_clocksource { |
| 56 | void __iomem *base; | 67 | void __iomem *base; |
| 68 | void __iomem *source_reg; | ||
| 57 | unsigned int irq[SAMSUNG_PWM_NUM]; | 69 | unsigned int irq[SAMSUNG_PWM_NUM]; |
| 58 | struct samsung_pwm_variant variant; | 70 | struct samsung_pwm_variant variant; |
| 59 | 71 | ||
| @@ -195,17 +207,6 @@ static int samsung_set_next_event(unsigned long cycles, | |||
| 195 | return 0; | 207 | return 0; |
| 196 | } | 208 | } |
| 197 | 209 | ||
| 198 | static void samsung_timer_resume(void) | ||
| 199 | { | ||
| 200 | /* event timer restart */ | ||
| 201 | samsung_time_setup(pwm.event_id, pwm.clock_count_per_tick - 1); | ||
| 202 | samsung_time_start(pwm.event_id, true); | ||
| 203 | |||
| 204 | /* source timer restart */ | ||
| 205 | samsung_time_setup(pwm.source_id, pwm.tcnt_max); | ||
| 206 | samsung_time_start(pwm.source_id, true); | ||
| 207 | } | ||
| 208 | |||
| 209 | static void samsung_set_mode(enum clock_event_mode mode, | 210 | static void samsung_set_mode(enum clock_event_mode mode, |
| 210 | struct clock_event_device *evt) | 211 | struct clock_event_device *evt) |
| 211 | { | 212 | { |
| @@ -222,20 +223,29 @@ static void samsung_set_mode(enum clock_event_mode mode, | |||
| 222 | 223 | ||
| 223 | case CLOCK_EVT_MODE_UNUSED: | 224 | case CLOCK_EVT_MODE_UNUSED: |
| 224 | case CLOCK_EVT_MODE_SHUTDOWN: | 225 | case CLOCK_EVT_MODE_SHUTDOWN: |
| 225 | break; | ||
| 226 | |||
| 227 | case CLOCK_EVT_MODE_RESUME: | 226 | case CLOCK_EVT_MODE_RESUME: |
| 228 | samsung_timer_resume(); | ||
| 229 | break; | 227 | break; |
| 230 | } | 228 | } |
| 231 | } | 229 | } |
| 232 | 230 | ||
| 231 | static void samsung_clockevent_resume(struct clock_event_device *cev) | ||
| 232 | { | ||
| 233 | samsung_timer_set_prescale(pwm.event_id, pwm.tscaler_div); | ||
| 234 | samsung_timer_set_divisor(pwm.event_id, pwm.tdiv); | ||
| 235 | |||
| 236 | if (pwm.variant.has_tint_cstat) { | ||
| 237 | u32 mask = (1 << pwm.event_id); | ||
| 238 | writel(mask | (mask << 5), pwm.base + REG_TINT_CSTAT); | ||
| 239 | } | ||
| 240 | } | ||
| 241 | |||
| 233 | static struct clock_event_device time_event_device = { | 242 | static struct clock_event_device time_event_device = { |
| 234 | .name = "samsung_event_timer", | 243 | .name = "samsung_event_timer", |
| 235 | .features = CLOCK_EVT_FEAT_PERIODIC | CLOCK_EVT_FEAT_ONESHOT, | 244 | .features = CLOCK_EVT_FEAT_PERIODIC | CLOCK_EVT_FEAT_ONESHOT, |
| 236 | .rating = 200, | 245 | .rating = 200, |
| 237 | .set_next_event = samsung_set_next_event, | 246 | .set_next_event = samsung_set_next_event, |
| 238 | .set_mode = samsung_set_mode, | 247 | .set_mode = samsung_set_mode, |
| 248 | .resume = samsung_clockevent_resume, | ||
| 239 | }; | 249 | }; |
| 240 | 250 | ||
| 241 | static irqreturn_t samsung_clock_event_isr(int irq, void *dev_id) | 251 | static irqreturn_t samsung_clock_event_isr(int irq, void *dev_id) |
| @@ -286,23 +296,34 @@ static void __init samsung_clockevent_init(void) | |||
| 286 | } | 296 | } |
| 287 | } | 297 | } |
| 288 | 298 | ||
| 289 | static void __iomem *samsung_timer_reg(void) | 299 | static void samsung_clocksource_suspend(struct clocksource *cs) |
| 290 | { | 300 | { |
| 291 | switch (pwm.source_id) { | 301 | samsung_time_stop(pwm.source_id); |
| 292 | case 0: | ||
| 293 | case 1: | ||
| 294 | case 2: | ||
| 295 | case 3: | ||
| 296 | return pwm.base + pwm.source_id * 0x0c + 0x14; | ||
| 297 | |||
| 298 | case 4: | ||
| 299 | return pwm.base + 0x40; | ||
| 300 | |||
| 301 | default: | ||
| 302 | BUG(); | ||
| 303 | } | ||
| 304 | } | 302 | } |
| 305 | 303 | ||
| 304 | static void samsung_clocksource_resume(struct clocksource *cs) | ||
| 305 | { | ||
| 306 | samsung_timer_set_prescale(pwm.source_id, pwm.tscaler_div); | ||
| 307 | samsung_timer_set_divisor(pwm.source_id, pwm.tdiv); | ||
| 308 | |||
| 309 | samsung_time_setup(pwm.source_id, pwm.tcnt_max); | ||
| 310 | samsung_time_start(pwm.source_id, true); | ||
| 311 | } | ||
| 312 | |||
| 313 | static cycle_t samsung_clocksource_read(struct clocksource *c) | ||
| 314 | { | ||
| 315 | return ~readl_relaxed(pwm.source_reg); | ||
| 316 | } | ||
| 317 | |||
| 318 | static struct clocksource samsung_clocksource = { | ||
| 319 | .name = "samsung_clocksource_timer", | ||
| 320 | .rating = 250, | ||
| 321 | .read = samsung_clocksource_read, | ||
| 322 | .suspend = samsung_clocksource_suspend, | ||
| 323 | .resume = samsung_clocksource_resume, | ||
| 324 | .flags = CLOCK_SOURCE_IS_CONTINUOUS, | ||
| 325 | }; | ||
| 326 | |||
| 306 | /* | 327 | /* |
| 307 | * Override the global weak sched_clock symbol with this | 328 | * Override the global weak sched_clock symbol with this |
| 308 | * local implementation which uses the clocksource to get some | 329 | * local implementation which uses the clocksource to get some |
| @@ -312,17 +333,11 @@ static void __iomem *samsung_timer_reg(void) | |||
| 312 | */ | 333 | */ |
| 313 | static u64 notrace samsung_read_sched_clock(void) | 334 | static u64 notrace samsung_read_sched_clock(void) |
| 314 | { | 335 | { |
| 315 | void __iomem *reg = samsung_timer_reg(); | 336 | return samsung_clocksource_read(NULL); |
| 316 | |||
| 317 | if (!reg) | ||
| 318 | return 0; | ||
| 319 | |||
| 320 | return ~__raw_readl(reg); | ||
| 321 | } | 337 | } |
| 322 | 338 | ||
| 323 | static void __init samsung_clocksource_init(void) | 339 | static void __init samsung_clocksource_init(void) |
| 324 | { | 340 | { |
| 325 | void __iomem *reg = samsung_timer_reg(); | ||
| 326 | unsigned long pclk; | 341 | unsigned long pclk; |
| 327 | unsigned long clock_rate; | 342 | unsigned long clock_rate; |
| 328 | int ret; | 343 | int ret; |
| @@ -337,22 +352,22 @@ static void __init samsung_clocksource_init(void) | |||
| 337 | samsung_time_setup(pwm.source_id, pwm.tcnt_max); | 352 | samsung_time_setup(pwm.source_id, pwm.tcnt_max); |
| 338 | samsung_time_start(pwm.source_id, true); | 353 | samsung_time_start(pwm.source_id, true); |
| 339 | 354 | ||
| 355 | if (pwm.source_id == 4) | ||
| 356 | pwm.source_reg = pwm.base + 0x40; | ||
| 357 | else | ||
| 358 | pwm.source_reg = pwm.base + pwm.source_id * 0x0c + 0x14; | ||
| 359 | |||
| 340 | sched_clock_register(samsung_read_sched_clock, | 360 | sched_clock_register(samsung_read_sched_clock, |
| 341 | pwm.variant.bits, clock_rate); | 361 | pwm.variant.bits, clock_rate); |
| 342 | 362 | ||
| 343 | ret = clocksource_mmio_init(reg, "samsung_clocksource_timer", | 363 | samsung_clocksource.mask = CLOCKSOURCE_MASK(pwm.variant.bits); |
| 344 | clock_rate, 250, pwm.variant.bits, | 364 | ret = clocksource_register_hz(&samsung_clocksource, clock_rate); |
| 345 | clocksource_mmio_readl_down); | ||
| 346 | if (ret) | 365 | if (ret) |
| 347 | panic("samsung_clocksource_timer: can't register clocksource\n"); | 366 | panic("samsung_clocksource_timer: can't register clocksource\n"); |
| 348 | } | 367 | } |
| 349 | 368 | ||
| 350 | static void __init samsung_timer_resources(void) | 369 | static void __init samsung_timer_resources(void) |
| 351 | { | 370 | { |
| 352 | pwm.timerclk = clk_get(NULL, "timers"); | ||
| 353 | if (IS_ERR(pwm.timerclk)) | ||
| 354 | panic("failed to get timers clock for timer"); | ||
| 355 | |||
| 356 | clk_prepare_enable(pwm.timerclk); | 371 | clk_prepare_enable(pwm.timerclk); |
| 357 | 372 | ||
| 358 | pwm.tcnt_max = (1UL << pwm.variant.bits) - 1; | 373 | pwm.tcnt_max = (1UL << pwm.variant.bits) - 1; |
| @@ -397,6 +412,10 @@ void __init samsung_pwm_clocksource_init(void __iomem *base, | |||
| 397 | memcpy(&pwm.variant, variant, sizeof(pwm.variant)); | 412 | memcpy(&pwm.variant, variant, sizeof(pwm.variant)); |
| 398 | memcpy(pwm.irq, irqs, SAMSUNG_PWM_NUM * sizeof(*irqs)); | 413 | memcpy(pwm.irq, irqs, SAMSUNG_PWM_NUM * sizeof(*irqs)); |
| 399 | 414 | ||
| 415 | pwm.timerclk = clk_get(NULL, "timers"); | ||
| 416 | if (IS_ERR(pwm.timerclk)) | ||
| 417 | panic("failed to get timers clock for timer"); | ||
| 418 | |||
| 400 | _samsung_pwm_clocksource_init(); | 419 | _samsung_pwm_clocksource_init(); |
| 401 | } | 420 | } |
| 402 | 421 | ||
| @@ -404,7 +423,6 @@ void __init samsung_pwm_clocksource_init(void __iomem *base, | |||
| 404 | static void __init samsung_pwm_alloc(struct device_node *np, | 423 | static void __init samsung_pwm_alloc(struct device_node *np, |
| 405 | const struct samsung_pwm_variant *variant) | 424 | const struct samsung_pwm_variant *variant) |
| 406 | { | 425 | { |
| 407 | struct resource res; | ||
| 408 | struct property *prop; | 426 | struct property *prop; |
| 409 | const __be32 *cur; | 427 | const __be32 *cur; |
| 410 | u32 val; | 428 | u32 val; |
| @@ -423,20 +441,16 @@ static void __init samsung_pwm_alloc(struct device_node *np, | |||
| 423 | pwm.variant.output_mask |= 1 << val; | 441 | pwm.variant.output_mask |= 1 << val; |
| 424 | } | 442 | } |
| 425 | 443 | ||
| 426 | of_address_to_resource(np, 0, &res); | 444 | pwm.base = of_iomap(np, 0); |
| 427 | if (!request_mem_region(res.start, | ||
| 428 | resource_size(&res), "samsung-pwm")) { | ||
| 429 | pr_err("%s: failed to request IO mem region\n", __func__); | ||
| 430 | return; | ||
| 431 | } | ||
| 432 | |||
| 433 | pwm.base = ioremap(res.start, resource_size(&res)); | ||
| 434 | if (!pwm.base) { | 445 | if (!pwm.base) { |
| 435 | pr_err("%s: failed to map PWM registers\n", __func__); | 446 | pr_err("%s: failed to map PWM registers\n", __func__); |
| 436 | release_mem_region(res.start, resource_size(&res)); | ||
| 437 | return; | 447 | return; |
| 438 | } | 448 | } |
| 439 | 449 | ||
| 450 | pwm.timerclk = of_clk_get_by_name(np, "timers"); | ||
| 451 | if (IS_ERR(pwm.timerclk)) | ||
| 452 | panic("failed to get timers clock for timer"); | ||
| 453 | |||
| 440 | _samsung_pwm_clocksource_init(); | 454 | _samsung_pwm_clocksource_init(); |
| 441 | } | 455 | } |
| 442 | 456 | ||
diff --git a/drivers/clocksource/sh_cmt.c b/drivers/clocksource/sh_cmt.c index 08d0c418c94a..0965e9848b3d 100644 --- a/drivers/clocksource/sh_cmt.c +++ b/drivers/clocksource/sh_cmt.c | |||
| @@ -37,6 +37,7 @@ | |||
| 37 | 37 | ||
| 38 | struct sh_cmt_priv { | 38 | struct sh_cmt_priv { |
| 39 | void __iomem *mapbase; | 39 | void __iomem *mapbase; |
| 40 | void __iomem *mapbase_str; | ||
| 40 | struct clk *clk; | 41 | struct clk *clk; |
| 41 | unsigned long width; /* 16 or 32 bit version of hardware block */ | 42 | unsigned long width; /* 16 or 32 bit version of hardware block */ |
| 42 | unsigned long overflow_bit; | 43 | unsigned long overflow_bit; |
| @@ -79,6 +80,12 @@ struct sh_cmt_priv { | |||
| 79 | * CMCSR 0xffca0060 16-bit | 80 | * CMCSR 0xffca0060 16-bit |
| 80 | * CMCNT 0xffca0064 32-bit | 81 | * CMCNT 0xffca0064 32-bit |
| 81 | * CMCOR 0xffca0068 32-bit | 82 | * CMCOR 0xffca0068 32-bit |
| 83 | * | ||
| 84 | * "32-bit counter and 32-bit control" as found on r8a73a4 and r8a7790: | ||
| 85 | * CMSTR 0xffca0500 32-bit | ||
| 86 | * CMCSR 0xffca0510 32-bit | ||
| 87 | * CMCNT 0xffca0514 32-bit | ||
| 88 | * CMCOR 0xffca0518 32-bit | ||
| 82 | */ | 89 | */ |
| 83 | 90 | ||
| 84 | static unsigned long sh_cmt_read16(void __iomem *base, unsigned long offs) | 91 | static unsigned long sh_cmt_read16(void __iomem *base, unsigned long offs) |
| @@ -109,9 +116,7 @@ static void sh_cmt_write32(void __iomem *base, unsigned long offs, | |||
| 109 | 116 | ||
| 110 | static inline unsigned long sh_cmt_read_cmstr(struct sh_cmt_priv *p) | 117 | static inline unsigned long sh_cmt_read_cmstr(struct sh_cmt_priv *p) |
| 111 | { | 118 | { |
| 112 | struct sh_timer_config *cfg = p->pdev->dev.platform_data; | 119 | return p->read_control(p->mapbase_str, 0); |
| 113 | |||
| 114 | return p->read_control(p->mapbase - cfg->channel_offset, 0); | ||
| 115 | } | 120 | } |
| 116 | 121 | ||
| 117 | static inline unsigned long sh_cmt_read_cmcsr(struct sh_cmt_priv *p) | 122 | static inline unsigned long sh_cmt_read_cmcsr(struct sh_cmt_priv *p) |
| @@ -127,9 +132,7 @@ static inline unsigned long sh_cmt_read_cmcnt(struct sh_cmt_priv *p) | |||
| 127 | static inline void sh_cmt_write_cmstr(struct sh_cmt_priv *p, | 132 | static inline void sh_cmt_write_cmstr(struct sh_cmt_priv *p, |
| 128 | unsigned long value) | 133 | unsigned long value) |
| 129 | { | 134 | { |
| 130 | struct sh_timer_config *cfg = p->pdev->dev.platform_data; | 135 | p->write_control(p->mapbase_str, 0, value); |
| 131 | |||
| 132 | p->write_control(p->mapbase - cfg->channel_offset, 0, value); | ||
| 133 | } | 136 | } |
| 134 | 137 | ||
| 135 | static inline void sh_cmt_write_cmcsr(struct sh_cmt_priv *p, | 138 | static inline void sh_cmt_write_cmcsr(struct sh_cmt_priv *p, |
| @@ -676,7 +679,7 @@ static int sh_cmt_register(struct sh_cmt_priv *p, char *name, | |||
| 676 | static int sh_cmt_setup(struct sh_cmt_priv *p, struct platform_device *pdev) | 679 | static int sh_cmt_setup(struct sh_cmt_priv *p, struct platform_device *pdev) |
| 677 | { | 680 | { |
| 678 | struct sh_timer_config *cfg = pdev->dev.platform_data; | 681 | struct sh_timer_config *cfg = pdev->dev.platform_data; |
| 679 | struct resource *res; | 682 | struct resource *res, *res2; |
| 680 | int irq, ret; | 683 | int irq, ret; |
| 681 | ret = -ENXIO; | 684 | ret = -ENXIO; |
| 682 | 685 | ||
| @@ -694,6 +697,9 @@ static int sh_cmt_setup(struct sh_cmt_priv *p, struct platform_device *pdev) | |||
| 694 | goto err0; | 697 | goto err0; |
| 695 | } | 698 | } |
| 696 | 699 | ||
| 700 | /* optional resource for the shared timer start/stop register */ | ||
| 701 | res2 = platform_get_resource(p->pdev, IORESOURCE_MEM, 1); | ||
| 702 | |||
| 697 | irq = platform_get_irq(p->pdev, 0); | 703 | irq = platform_get_irq(p->pdev, 0); |
| 698 | if (irq < 0) { | 704 | if (irq < 0) { |
| 699 | dev_err(&p->pdev->dev, "failed to get irq\n"); | 705 | dev_err(&p->pdev->dev, "failed to get irq\n"); |
| @@ -707,6 +713,15 @@ static int sh_cmt_setup(struct sh_cmt_priv *p, struct platform_device *pdev) | |||
| 707 | goto err0; | 713 | goto err0; |
| 708 | } | 714 | } |
| 709 | 715 | ||
| 716 | /* map second resource for CMSTR */ | ||
| 717 | p->mapbase_str = ioremap_nocache(res2 ? res2->start : | ||
| 718 | res->start - cfg->channel_offset, | ||
| 719 | res2 ? resource_size(res2) : 2); | ||
| 720 | if (p->mapbase_str == NULL) { | ||
| 721 | dev_err(&p->pdev->dev, "failed to remap I/O second memory\n"); | ||
| 722 | goto err1; | ||
| 723 | } | ||
| 724 | |||
| 710 | /* request irq using setup_irq() (too early for request_irq()) */ | 725 | /* request irq using setup_irq() (too early for request_irq()) */ |
| 711 | p->irqaction.name = dev_name(&p->pdev->dev); | 726 | p->irqaction.name = dev_name(&p->pdev->dev); |
| 712 | p->irqaction.handler = sh_cmt_interrupt; | 727 | p->irqaction.handler = sh_cmt_interrupt; |
| @@ -719,11 +734,17 @@ static int sh_cmt_setup(struct sh_cmt_priv *p, struct platform_device *pdev) | |||
| 719 | if (IS_ERR(p->clk)) { | 734 | if (IS_ERR(p->clk)) { |
| 720 | dev_err(&p->pdev->dev, "cannot get clock\n"); | 735 | dev_err(&p->pdev->dev, "cannot get clock\n"); |
| 721 | ret = PTR_ERR(p->clk); | 736 | ret = PTR_ERR(p->clk); |
| 722 | goto err1; | 737 | goto err2; |
| 723 | } | 738 | } |
| 724 | 739 | ||
| 725 | p->read_control = sh_cmt_read16; | 740 | if (res2 && (resource_size(res2) == 4)) { |
| 726 | p->write_control = sh_cmt_write16; | 741 | /* assume both CMSTR and CMCSR to be 32-bit */ |
| 742 | p->read_control = sh_cmt_read32; | ||
| 743 | p->write_control = sh_cmt_write32; | ||
| 744 | } else { | ||
| 745 | p->read_control = sh_cmt_read16; | ||
| 746 | p->write_control = sh_cmt_write16; | ||
| 747 | } | ||
| 727 | 748 | ||
| 728 | if (resource_size(res) == 6) { | 749 | if (resource_size(res) == 6) { |
| 729 | p->width = 16; | 750 | p->width = 16; |
| @@ -752,22 +773,23 @@ static int sh_cmt_setup(struct sh_cmt_priv *p, struct platform_device *pdev) | |||
| 752 | cfg->clocksource_rating); | 773 | cfg->clocksource_rating); |
| 753 | if (ret) { | 774 | if (ret) { |
| 754 | dev_err(&p->pdev->dev, "registration failed\n"); | 775 | dev_err(&p->pdev->dev, "registration failed\n"); |
| 755 | goto err2; | 776 | goto err3; |
| 756 | } | 777 | } |
| 757 | p->cs_enabled = false; | 778 | p->cs_enabled = false; |
| 758 | 779 | ||
| 759 | ret = setup_irq(irq, &p->irqaction); | 780 | ret = setup_irq(irq, &p->irqaction); |
| 760 | if (ret) { | 781 | if (ret) { |
| 761 | dev_err(&p->pdev->dev, "failed to request irq %d\n", irq); | 782 | dev_err(&p->pdev->dev, "failed to request irq %d\n", irq); |
| 762 | goto err2; | 783 | goto err3; |
| 763 | } | 784 | } |
| 764 | 785 | ||
| 765 | platform_set_drvdata(pdev, p); | 786 | platform_set_drvdata(pdev, p); |
| 766 | 787 | ||
| 767 | return 0; | 788 | return 0; |
| 768 | err2: | 789 | err3: |
| 769 | clk_put(p->clk); | 790 | clk_put(p->clk); |
| 770 | 791 | err2: | |
| 792 | iounmap(p->mapbase_str); | ||
| 771 | err1: | 793 | err1: |
| 772 | iounmap(p->mapbase); | 794 | iounmap(p->mapbase); |
| 773 | err0: | 795 | err0: |
diff --git a/drivers/clocksource/sun4i_timer.c b/drivers/clocksource/sun4i_timer.c index d4674e78ef35..8ead0258740a 100644 --- a/drivers/clocksource/sun4i_timer.c +++ b/drivers/clocksource/sun4i_timer.c | |||
| @@ -19,42 +19,83 @@ | |||
| 19 | #include <linux/interrupt.h> | 19 | #include <linux/interrupt.h> |
| 20 | #include <linux/irq.h> | 20 | #include <linux/irq.h> |
| 21 | #include <linux/irqreturn.h> | 21 | #include <linux/irqreturn.h> |
| 22 | #include <linux/sched_clock.h> | ||
| 22 | #include <linux/of.h> | 23 | #include <linux/of.h> |
| 23 | #include <linux/of_address.h> | 24 | #include <linux/of_address.h> |
| 24 | #include <linux/of_irq.h> | 25 | #include <linux/of_irq.h> |
| 25 | 26 | ||
| 26 | #define TIMER_IRQ_EN_REG 0x00 | 27 | #define TIMER_IRQ_EN_REG 0x00 |
| 27 | #define TIMER_IRQ_EN(val) (1 << val) | 28 | #define TIMER_IRQ_EN(val) BIT(val) |
| 28 | #define TIMER_IRQ_ST_REG 0x04 | 29 | #define TIMER_IRQ_ST_REG 0x04 |
| 29 | #define TIMER_CTL_REG(val) (0x10 * val + 0x10) | 30 | #define TIMER_CTL_REG(val) (0x10 * val + 0x10) |
| 30 | #define TIMER_CTL_ENABLE (1 << 0) | 31 | #define TIMER_CTL_ENABLE BIT(0) |
| 31 | #define TIMER_CTL_AUTORELOAD (1 << 1) | 32 | #define TIMER_CTL_RELOAD BIT(1) |
| 32 | #define TIMER_CTL_ONESHOT (1 << 7) | 33 | #define TIMER_CTL_CLK_SRC(val) (((val) & 0x3) << 2) |
| 33 | #define TIMER_INTVAL_REG(val) (0x10 * val + 0x14) | 34 | #define TIMER_CTL_CLK_SRC_OSC24M (1) |
| 34 | #define TIMER_CNTVAL_REG(val) (0x10 * val + 0x18) | 35 | #define TIMER_CTL_CLK_PRES(val) (((val) & 0x7) << 4) |
| 35 | 36 | #define TIMER_CTL_ONESHOT BIT(7) | |
| 36 | #define TIMER_SCAL 16 | 37 | #define TIMER_INTVAL_REG(val) (0x10 * (val) + 0x14) |
| 38 | #define TIMER_CNTVAL_REG(val) (0x10 * (val) + 0x18) | ||
| 37 | 39 | ||
| 38 | static void __iomem *timer_base; | 40 | static void __iomem *timer_base; |
| 41 | static u32 ticks_per_jiffy; | ||
| 42 | |||
| 43 | /* | ||
| 44 | * When we disable a timer, we need to wait at least for 2 cycles of | ||
| 45 | * the timer source clock. We will use for that the clocksource timer | ||
| 46 | * that is already setup and runs at the same frequency than the other | ||
| 47 | * timers, and we never will be disabled. | ||
| 48 | */ | ||
| 49 | static void sun4i_clkevt_sync(void) | ||
| 50 | { | ||
| 51 | u32 old = readl(timer_base + TIMER_CNTVAL_REG(1)); | ||
| 52 | |||
| 53 | while ((old - readl(timer_base + TIMER_CNTVAL_REG(1))) < 3) | ||
| 54 | cpu_relax(); | ||
| 55 | } | ||
| 56 | |||
| 57 | static void sun4i_clkevt_time_stop(u8 timer) | ||
| 58 | { | ||
| 59 | u32 val = readl(timer_base + TIMER_CTL_REG(timer)); | ||
| 60 | writel(val & ~TIMER_CTL_ENABLE, timer_base + TIMER_CTL_REG(timer)); | ||
| 61 | sun4i_clkevt_sync(); | ||
| 62 | } | ||
| 63 | |||
| 64 | static void sun4i_clkevt_time_setup(u8 timer, unsigned long delay) | ||
| 65 | { | ||
| 66 | writel(delay, timer_base + TIMER_INTVAL_REG(timer)); | ||
| 67 | } | ||
| 68 | |||
| 69 | static void sun4i_clkevt_time_start(u8 timer, bool periodic) | ||
| 70 | { | ||
| 71 | u32 val = readl(timer_base + TIMER_CTL_REG(timer)); | ||
| 72 | |||
| 73 | if (periodic) | ||
| 74 | val &= ~TIMER_CTL_ONESHOT; | ||
| 75 | else | ||
| 76 | val |= TIMER_CTL_ONESHOT; | ||
| 77 | |||
| 78 | writel(val | TIMER_CTL_ENABLE | TIMER_CTL_RELOAD, | ||
| 79 | timer_base + TIMER_CTL_REG(timer)); | ||
| 80 | } | ||
| 39 | 81 | ||
| 40 | static void sun4i_clkevt_mode(enum clock_event_mode mode, | 82 | static void sun4i_clkevt_mode(enum clock_event_mode mode, |
| 41 | struct clock_event_device *clk) | 83 | struct clock_event_device *clk) |
| 42 | { | 84 | { |
| 43 | u32 u = readl(timer_base + TIMER_CTL_REG(0)); | ||
| 44 | |||
| 45 | switch (mode) { | 85 | switch (mode) { |
| 46 | case CLOCK_EVT_MODE_PERIODIC: | 86 | case CLOCK_EVT_MODE_PERIODIC: |
| 47 | u &= ~(TIMER_CTL_ONESHOT); | 87 | sun4i_clkevt_time_stop(0); |
| 48 | writel(u | TIMER_CTL_ENABLE, timer_base + TIMER_CTL_REG(0)); | 88 | sun4i_clkevt_time_setup(0, ticks_per_jiffy); |
| 89 | sun4i_clkevt_time_start(0, true); | ||
| 49 | break; | 90 | break; |
| 50 | |||
| 51 | case CLOCK_EVT_MODE_ONESHOT: | 91 | case CLOCK_EVT_MODE_ONESHOT: |
| 52 | writel(u | TIMER_CTL_ONESHOT, timer_base + TIMER_CTL_REG(0)); | 92 | sun4i_clkevt_time_stop(0); |
| 93 | sun4i_clkevt_time_start(0, false); | ||
| 53 | break; | 94 | break; |
| 54 | case CLOCK_EVT_MODE_UNUSED: | 95 | case CLOCK_EVT_MODE_UNUSED: |
| 55 | case CLOCK_EVT_MODE_SHUTDOWN: | 96 | case CLOCK_EVT_MODE_SHUTDOWN: |
| 56 | default: | 97 | default: |
| 57 | writel(u & ~(TIMER_CTL_ENABLE), timer_base + TIMER_CTL_REG(0)); | 98 | sun4i_clkevt_time_stop(0); |
| 58 | break; | 99 | break; |
| 59 | } | 100 | } |
| 60 | } | 101 | } |
| @@ -62,10 +103,9 @@ static void sun4i_clkevt_mode(enum clock_event_mode mode, | |||
| 62 | static int sun4i_clkevt_next_event(unsigned long evt, | 103 | static int sun4i_clkevt_next_event(unsigned long evt, |
| 63 | struct clock_event_device *unused) | 104 | struct clock_event_device *unused) |
| 64 | { | 105 | { |
| 65 | u32 u = readl(timer_base + TIMER_CTL_REG(0)); | 106 | sun4i_clkevt_time_stop(0); |
| 66 | writel(evt, timer_base + TIMER_CNTVAL_REG(0)); | 107 | sun4i_clkevt_time_setup(0, evt); |
| 67 | writel(u | TIMER_CTL_ENABLE | TIMER_CTL_AUTORELOAD, | 108 | sun4i_clkevt_time_start(0, false); |
| 68 | timer_base + TIMER_CTL_REG(0)); | ||
| 69 | 109 | ||
| 70 | return 0; | 110 | return 0; |
| 71 | } | 111 | } |
| @@ -96,6 +136,11 @@ static struct irqaction sun4i_timer_irq = { | |||
| 96 | .dev_id = &sun4i_clockevent, | 136 | .dev_id = &sun4i_clockevent, |
| 97 | }; | 137 | }; |
| 98 | 138 | ||
| 139 | static u32 sun4i_timer_sched_read(void) | ||
| 140 | { | ||
| 141 | return ~readl(timer_base + TIMER_CNTVAL_REG(1)); | ||
| 142 | } | ||
| 143 | |||
| 99 | static void __init sun4i_timer_init(struct device_node *node) | 144 | static void __init sun4i_timer_init(struct device_node *node) |
| 100 | { | 145 | { |
| 101 | unsigned long rate = 0; | 146 | unsigned long rate = 0; |
| @@ -114,22 +159,23 @@ static void __init sun4i_timer_init(struct device_node *node) | |||
| 114 | clk = of_clk_get(node, 0); | 159 | clk = of_clk_get(node, 0); |
| 115 | if (IS_ERR(clk)) | 160 | if (IS_ERR(clk)) |
| 116 | panic("Can't get timer clock"); | 161 | panic("Can't get timer clock"); |
| 162 | clk_prepare_enable(clk); | ||
| 117 | 163 | ||
| 118 | rate = clk_get_rate(clk); | 164 | rate = clk_get_rate(clk); |
| 119 | 165 | ||
| 120 | writel(rate / (TIMER_SCAL * HZ), | 166 | writel(~0, timer_base + TIMER_INTVAL_REG(1)); |
| 121 | timer_base + TIMER_INTVAL_REG(0)); | 167 | writel(TIMER_CTL_ENABLE | TIMER_CTL_RELOAD | |
| 168 | TIMER_CTL_CLK_SRC(TIMER_CTL_CLK_SRC_OSC24M), | ||
| 169 | timer_base + TIMER_CTL_REG(1)); | ||
| 170 | |||
| 171 | setup_sched_clock(sun4i_timer_sched_read, 32, rate); | ||
| 172 | clocksource_mmio_init(timer_base + TIMER_CNTVAL_REG(1), node->name, | ||
| 173 | rate, 300, 32, clocksource_mmio_readl_down); | ||
| 122 | 174 | ||
| 123 | /* set clock source to HOSC, 16 pre-division */ | 175 | ticks_per_jiffy = DIV_ROUND_UP(rate, HZ); |
| 124 | val = readl(timer_base + TIMER_CTL_REG(0)); | ||
| 125 | val &= ~(0x07 << 4); | ||
| 126 | val &= ~(0x03 << 2); | ||
| 127 | val |= (4 << 4) | (1 << 2); | ||
| 128 | writel(val, timer_base + TIMER_CTL_REG(0)); | ||
| 129 | 176 | ||
| 130 | /* set mode to auto reload */ | 177 | writel(TIMER_CTL_CLK_SRC(TIMER_CTL_CLK_SRC_OSC24M), |
| 131 | val = readl(timer_base + TIMER_CTL_REG(0)); | 178 | timer_base + TIMER_CTL_REG(0)); |
| 132 | writel(val | TIMER_CTL_AUTORELOAD, timer_base + TIMER_CTL_REG(0)); | ||
| 133 | 179 | ||
| 134 | ret = setup_irq(irq, &sun4i_timer_irq); | 180 | ret = setup_irq(irq, &sun4i_timer_irq); |
| 135 | if (ret) | 181 | if (ret) |
| @@ -141,8 +187,8 @@ static void __init sun4i_timer_init(struct device_node *node) | |||
| 141 | 187 | ||
| 142 | sun4i_clockevent.cpumask = cpumask_of(0); | 188 | sun4i_clockevent.cpumask = cpumask_of(0); |
| 143 | 189 | ||
| 144 | clockevents_config_and_register(&sun4i_clockevent, rate / TIMER_SCAL, | 190 | clockevents_config_and_register(&sun4i_clockevent, rate, 0x1, |
| 145 | 0x1, 0xff); | 191 | 0xffffffff); |
| 146 | } | 192 | } |
| 147 | CLOCKSOURCE_OF_DECLARE(sun4i, "allwinner,sun4i-timer", | 193 | CLOCKSOURCE_OF_DECLARE(sun4i, "allwinner,sun4i-timer", |
| 148 | sun4i_timer_init); | 194 | sun4i_timer_init); |
diff --git a/drivers/clocksource/time-armada-370-xp.c b/drivers/clocksource/time-armada-370-xp.c index 2bec8dca74b6..d8e47e502785 100644 --- a/drivers/clocksource/time-armada-370-xp.c +++ b/drivers/clocksource/time-armada-370-xp.c | |||
| @@ -13,12 +13,26 @@ | |||
| 13 | * | 13 | * |
| 14 | * Timer 0 is used as free-running clocksource, while timer 1 is | 14 | * Timer 0 is used as free-running clocksource, while timer 1 is |
| 15 | * used as clock_event_device. | 15 | * used as clock_event_device. |
| 16 | * | ||
| 17 | * --- | ||
| 18 | * Clocksource driver for Armada 370 and Armada XP SoC. | ||
| 19 | * This driver implements one compatible string for each SoC, given | ||
| 20 | * each has its own characteristics: | ||
| 21 | * | ||
| 22 | * * Armada 370 has no 25 MHz fixed timer. | ||
| 23 | * | ||
| 24 | * * Armada XP cannot work properly without such 25 MHz fixed timer as | ||
| 25 | * doing otherwise leads to using a clocksource whose frequency varies | ||
| 26 | * when doing cpufreq frequency changes. | ||
| 27 | * | ||
| 28 | * See Documentation/devicetree/bindings/timer/marvell,armada-370-xp-timer.txt | ||
| 16 | */ | 29 | */ |
| 17 | 30 | ||
| 18 | #include <linux/init.h> | 31 | #include <linux/init.h> |
| 19 | #include <linux/platform_device.h> | 32 | #include <linux/platform_device.h> |
| 20 | #include <linux/kernel.h> | 33 | #include <linux/kernel.h> |
| 21 | #include <linux/clk.h> | 34 | #include <linux/clk.h> |
| 35 | #include <linux/cpu.h> | ||
| 22 | #include <linux/timer.h> | 36 | #include <linux/timer.h> |
| 23 | #include <linux/clockchips.h> | 37 | #include <linux/clockchips.h> |
| 24 | #include <linux/interrupt.h> | 38 | #include <linux/interrupt.h> |
| @@ -28,20 +42,19 @@ | |||
| 28 | #include <linux/irq.h> | 42 | #include <linux/irq.h> |
| 29 | #include <linux/module.h> | 43 | #include <linux/module.h> |
| 30 | #include <linux/sched_clock.h> | 44 | #include <linux/sched_clock.h> |
| 31 | |||
| 32 | #include <asm/localtimer.h> | ||
| 33 | #include <linux/percpu.h> | 45 | #include <linux/percpu.h> |
| 46 | |||
| 34 | /* | 47 | /* |
| 35 | * Timer block registers. | 48 | * Timer block registers. |
| 36 | */ | 49 | */ |
| 37 | #define TIMER_CTRL_OFF 0x0000 | 50 | #define TIMER_CTRL_OFF 0x0000 |
| 38 | #define TIMER0_EN 0x0001 | 51 | #define TIMER0_EN BIT(0) |
| 39 | #define TIMER0_RELOAD_EN 0x0002 | 52 | #define TIMER0_RELOAD_EN BIT(1) |
| 40 | #define TIMER0_25MHZ 0x0800 | 53 | #define TIMER0_25MHZ BIT(11) |
| 41 | #define TIMER0_DIV(div) ((div) << 19) | 54 | #define TIMER0_DIV(div) ((div) << 19) |
| 42 | #define TIMER1_EN 0x0004 | 55 | #define TIMER1_EN BIT(2) |
| 43 | #define TIMER1_RELOAD_EN 0x0008 | 56 | #define TIMER1_RELOAD_EN BIT(3) |
| 44 | #define TIMER1_25MHZ 0x1000 | 57 | #define TIMER1_25MHZ BIT(12) |
| 45 | #define TIMER1_DIV(div) ((div) << 22) | 58 | #define TIMER1_DIV(div) ((div) << 22) |
| 46 | #define TIMER_EVENTS_STATUS 0x0004 | 59 | #define TIMER_EVENTS_STATUS 0x0004 |
| 47 | #define TIMER0_CLR_MASK (~0x1) | 60 | #define TIMER0_CLR_MASK (~0x1) |
| @@ -69,7 +82,19 @@ static bool timer25Mhz = true; | |||
| 69 | */ | 82 | */ |
| 70 | static u32 ticks_per_jiffy; | 83 | static u32 ticks_per_jiffy; |
| 71 | 84 | ||
| 72 | static struct clock_event_device __percpu **percpu_armada_370_xp_evt; | 85 | static struct clock_event_device __percpu *armada_370_xp_evt; |
| 86 | |||
| 87 | static void timer_ctrl_clrset(u32 clr, u32 set) | ||
| 88 | { | ||
| 89 | writel((readl(timer_base + TIMER_CTRL_OFF) & ~clr) | set, | ||
| 90 | timer_base + TIMER_CTRL_OFF); | ||
| 91 | } | ||
| 92 | |||
| 93 | static void local_timer_ctrl_clrset(u32 clr, u32 set) | ||
| 94 | { | ||
| 95 | writel((readl(local_base + TIMER_CTRL_OFF) & ~clr) | set, | ||
| 96 | local_base + TIMER_CTRL_OFF); | ||
| 97 | } | ||
| 73 | 98 | ||
| 74 | static u64 notrace armada_370_xp_read_sched_clock(void) | 99 | static u64 notrace armada_370_xp_read_sched_clock(void) |
| 75 | { | 100 | { |
| @@ -83,7 +108,6 @@ static int | |||
| 83 | armada_370_xp_clkevt_next_event(unsigned long delta, | 108 | armada_370_xp_clkevt_next_event(unsigned long delta, |
| 84 | struct clock_event_device *dev) | 109 | struct clock_event_device *dev) |
| 85 | { | 110 | { |
| 86 | u32 u; | ||
| 87 | /* | 111 | /* |
| 88 | * Clear clockevent timer interrupt. | 112 | * Clear clockevent timer interrupt. |
| 89 | */ | 113 | */ |
| @@ -97,11 +121,8 @@ armada_370_xp_clkevt_next_event(unsigned long delta, | |||
| 97 | /* | 121 | /* |
| 98 | * Enable the timer. | 122 | * Enable the timer. |
| 99 | */ | 123 | */ |
| 100 | u = readl(local_base + TIMER_CTRL_OFF); | 124 | local_timer_ctrl_clrset(TIMER0_RELOAD_EN, |
| 101 | u = ((u & ~TIMER0_RELOAD_EN) | TIMER0_EN | | 125 | TIMER0_EN | TIMER0_DIV(TIMER_DIVIDER_SHIFT)); |
| 102 | TIMER0_DIV(TIMER_DIVIDER_SHIFT)); | ||
| 103 | writel(u, local_base + TIMER_CTRL_OFF); | ||
| 104 | |||
| 105 | return 0; | 126 | return 0; |
| 106 | } | 127 | } |
| 107 | 128 | ||
| @@ -109,8 +130,6 @@ static void | |||
| 109 | armada_370_xp_clkevt_mode(enum clock_event_mode mode, | 130 | armada_370_xp_clkevt_mode(enum clock_event_mode mode, |
| 110 | struct clock_event_device *dev) | 131 | struct clock_event_device *dev) |
| 111 | { | 132 | { |
| 112 | u32 u; | ||
| 113 | |||
| 114 | if (mode == CLOCK_EVT_MODE_PERIODIC) { | 133 | if (mode == CLOCK_EVT_MODE_PERIODIC) { |
| 115 | 134 | ||
| 116 | /* | 135 | /* |
| @@ -122,18 +141,14 @@ armada_370_xp_clkevt_mode(enum clock_event_mode mode, | |||
| 122 | /* | 141 | /* |
| 123 | * Enable timer. | 142 | * Enable timer. |
| 124 | */ | 143 | */ |
| 125 | 144 | local_timer_ctrl_clrset(0, TIMER0_RELOAD_EN | | |
| 126 | u = readl(local_base + TIMER_CTRL_OFF); | 145 | TIMER0_EN | |
| 127 | 146 | TIMER0_DIV(TIMER_DIVIDER_SHIFT)); | |
| 128 | writel((u | TIMER0_EN | TIMER0_RELOAD_EN | | ||
| 129 | TIMER0_DIV(TIMER_DIVIDER_SHIFT)), | ||
| 130 | local_base + TIMER_CTRL_OFF); | ||
| 131 | } else { | 147 | } else { |
| 132 | /* | 148 | /* |
| 133 | * Disable timer. | 149 | * Disable timer. |
| 134 | */ | 150 | */ |
| 135 | u = readl(local_base + TIMER_CTRL_OFF); | 151 | local_timer_ctrl_clrset(TIMER0_EN, 0); |
| 136 | writel(u & ~TIMER0_EN, local_base + TIMER_CTRL_OFF); | ||
| 137 | 152 | ||
| 138 | /* | 153 | /* |
| 139 | * ACK pending timer interrupt. | 154 | * ACK pending timer interrupt. |
| @@ -142,21 +157,14 @@ armada_370_xp_clkevt_mode(enum clock_event_mode mode, | |||
| 142 | } | 157 | } |
| 143 | } | 158 | } |
| 144 | 159 | ||
| 145 | static struct clock_event_device armada_370_xp_clkevt = { | 160 | static int armada_370_xp_clkevt_irq; |
| 146 | .name = "armada_370_xp_per_cpu_tick", | ||
| 147 | .features = CLOCK_EVT_FEAT_ONESHOT | CLOCK_EVT_FEAT_PERIODIC, | ||
| 148 | .shift = 32, | ||
| 149 | .rating = 300, | ||
| 150 | .set_next_event = armada_370_xp_clkevt_next_event, | ||
| 151 | .set_mode = armada_370_xp_clkevt_mode, | ||
| 152 | }; | ||
| 153 | 161 | ||
| 154 | static irqreturn_t armada_370_xp_timer_interrupt(int irq, void *dev_id) | 162 | static irqreturn_t armada_370_xp_timer_interrupt(int irq, void *dev_id) |
| 155 | { | 163 | { |
| 156 | /* | 164 | /* |
| 157 | * ACK timer interrupt and call event handler. | 165 | * ACK timer interrupt and call event handler. |
| 158 | */ | 166 | */ |
| 159 | struct clock_event_device *evt = *(struct clock_event_device **)dev_id; | 167 | struct clock_event_device *evt = dev_id; |
| 160 | 168 | ||
| 161 | writel(TIMER0_CLR_MASK, local_base + LCL_TIMER_EVENTS_STATUS); | 169 | writel(TIMER0_CLR_MASK, local_base + LCL_TIMER_EVENTS_STATUS); |
| 162 | evt->event_handler(evt); | 170 | evt->event_handler(evt); |
| @@ -167,91 +175,83 @@ static irqreturn_t armada_370_xp_timer_interrupt(int irq, void *dev_id) | |||
| 167 | /* | 175 | /* |
| 168 | * Setup the local clock events for a CPU. | 176 | * Setup the local clock events for a CPU. |
| 169 | */ | 177 | */ |
| 170 | static int __cpuinit armada_370_xp_timer_setup(struct clock_event_device *evt) | 178 | static int armada_370_xp_timer_setup(struct clock_event_device *evt) |
| 171 | { | 179 | { |
| 172 | u32 u; | 180 | u32 clr = 0, set = 0; |
| 173 | int cpu = smp_processor_id(); | 181 | int cpu = smp_processor_id(); |
| 174 | 182 | ||
| 175 | /* Use existing clock_event for cpu 0 */ | ||
| 176 | if (!smp_processor_id()) | ||
| 177 | return 0; | ||
| 178 | |||
| 179 | u = readl(local_base + TIMER_CTRL_OFF); | ||
| 180 | if (timer25Mhz) | 183 | if (timer25Mhz) |
| 181 | writel(u | TIMER0_25MHZ, local_base + TIMER_CTRL_OFF); | 184 | set = TIMER0_25MHZ; |
| 182 | else | 185 | else |
| 183 | writel(u & ~TIMER0_25MHZ, local_base + TIMER_CTRL_OFF); | 186 | clr = TIMER0_25MHZ; |
| 184 | 187 | local_timer_ctrl_clrset(clr, set); | |
| 185 | evt->name = armada_370_xp_clkevt.name; | 188 | |
| 186 | evt->irq = armada_370_xp_clkevt.irq; | 189 | evt->name = "armada_370_xp_per_cpu_tick", |
| 187 | evt->features = armada_370_xp_clkevt.features; | 190 | evt->features = CLOCK_EVT_FEAT_ONESHOT | |
| 188 | evt->shift = armada_370_xp_clkevt.shift; | 191 | CLOCK_EVT_FEAT_PERIODIC; |
| 189 | evt->rating = armada_370_xp_clkevt.rating, | 192 | evt->shift = 32, |
| 193 | evt->rating = 300, | ||
| 190 | evt->set_next_event = armada_370_xp_clkevt_next_event, | 194 | evt->set_next_event = armada_370_xp_clkevt_next_event, |
| 191 | evt->set_mode = armada_370_xp_clkevt_mode, | 195 | evt->set_mode = armada_370_xp_clkevt_mode, |
| 196 | evt->irq = armada_370_xp_clkevt_irq; | ||
| 192 | evt->cpumask = cpumask_of(cpu); | 197 | evt->cpumask = cpumask_of(cpu); |
| 193 | 198 | ||
| 194 | *__this_cpu_ptr(percpu_armada_370_xp_evt) = evt; | ||
| 195 | |||
| 196 | clockevents_config_and_register(evt, timer_clk, 1, 0xfffffffe); | 199 | clockevents_config_and_register(evt, timer_clk, 1, 0xfffffffe); |
| 197 | enable_percpu_irq(evt->irq, 0); | 200 | enable_percpu_irq(evt->irq, 0); |
| 198 | 201 | ||
| 199 | return 0; | 202 | return 0; |
| 200 | } | 203 | } |
| 201 | 204 | ||
| 202 | static void armada_370_xp_timer_stop(struct clock_event_device *evt) | 205 | static void armada_370_xp_timer_stop(struct clock_event_device *evt) |
| 203 | { | 206 | { |
| 204 | evt->set_mode(CLOCK_EVT_MODE_UNUSED, evt); | 207 | evt->set_mode(CLOCK_EVT_MODE_UNUSED, evt); |
| 205 | disable_percpu_irq(evt->irq); | 208 | disable_percpu_irq(evt->irq); |
| 206 | } | 209 | } |
| 207 | 210 | ||
| 208 | static struct local_timer_ops armada_370_xp_local_timer_ops __cpuinitdata = { | 211 | static int armada_370_xp_timer_cpu_notify(struct notifier_block *self, |
| 209 | .setup = armada_370_xp_timer_setup, | 212 | unsigned long action, void *hcpu) |
| 210 | .stop = armada_370_xp_timer_stop, | 213 | { |
| 214 | /* | ||
| 215 | * Grab cpu pointer in each case to avoid spurious | ||
| 216 | * preemptible warnings | ||
| 217 | */ | ||
| 218 | switch (action & ~CPU_TASKS_FROZEN) { | ||
| 219 | case CPU_STARTING: | ||
| 220 | armada_370_xp_timer_setup(this_cpu_ptr(armada_370_xp_evt)); | ||
| 221 | break; | ||
| 222 | case CPU_DYING: | ||
| 223 | armada_370_xp_timer_stop(this_cpu_ptr(armada_370_xp_evt)); | ||
| 224 | break; | ||
| 225 | } | ||
| 226 | |||
| 227 | return NOTIFY_OK; | ||
| 228 | } | ||
| 229 | |||
| 230 | static struct notifier_block armada_370_xp_timer_cpu_nb = { | ||
| 231 | .notifier_call = armada_370_xp_timer_cpu_notify, | ||
| 211 | }; | 232 | }; |
| 212 | 233 | ||
| 213 | void __init armada_370_xp_timer_init(void) | 234 | static void __init armada_370_xp_timer_common_init(struct device_node *np) |
| 214 | { | 235 | { |
| 215 | u32 u; | 236 | u32 clr = 0, set = 0; |
| 216 | struct device_node *np; | ||
| 217 | int res; | 237 | int res; |
| 218 | 238 | ||
| 219 | np = of_find_compatible_node(NULL, NULL, "marvell,armada-370-xp-timer"); | ||
| 220 | timer_base = of_iomap(np, 0); | 239 | timer_base = of_iomap(np, 0); |
| 221 | WARN_ON(!timer_base); | 240 | WARN_ON(!timer_base); |
| 222 | local_base = of_iomap(np, 1); | 241 | local_base = of_iomap(np, 1); |
| 223 | 242 | ||
| 224 | if (of_find_property(np, "marvell,timer-25Mhz", NULL)) { | 243 | if (timer25Mhz) |
| 225 | /* The fixed 25MHz timer is available so let's use it */ | 244 | set = TIMER0_25MHZ; |
| 226 | u = readl(local_base + TIMER_CTRL_OFF); | 245 | else |
| 227 | writel(u | TIMER0_25MHZ, | 246 | clr = TIMER0_25MHZ; |
| 228 | local_base + TIMER_CTRL_OFF); | 247 | timer_ctrl_clrset(clr, set); |
| 229 | u = readl(timer_base + TIMER_CTRL_OFF); | 248 | local_timer_ctrl_clrset(clr, set); |
| 230 | writel(u | TIMER0_25MHZ, | ||
| 231 | timer_base + TIMER_CTRL_OFF); | ||
| 232 | timer_clk = 25000000; | ||
| 233 | } else { | ||
| 234 | unsigned long rate = 0; | ||
| 235 | struct clk *clk = of_clk_get(np, 0); | ||
| 236 | WARN_ON(IS_ERR(clk)); | ||
| 237 | rate = clk_get_rate(clk); | ||
| 238 | u = readl(local_base + TIMER_CTRL_OFF); | ||
| 239 | writel(u & ~(TIMER0_25MHZ), | ||
| 240 | local_base + TIMER_CTRL_OFF); | ||
| 241 | |||
| 242 | u = readl(timer_base + TIMER_CTRL_OFF); | ||
| 243 | writel(u & ~(TIMER0_25MHZ), | ||
| 244 | timer_base + TIMER_CTRL_OFF); | ||
| 245 | |||
| 246 | timer_clk = rate / TIMER_DIVIDER; | ||
| 247 | timer25Mhz = false; | ||
| 248 | } | ||
| 249 | 249 | ||
| 250 | /* | 250 | /* |
| 251 | * We use timer 0 as clocksource, and private(local) timer 0 | 251 | * We use timer 0 as clocksource, and private(local) timer 0 |
| 252 | * for clockevents | 252 | * for clockevents |
| 253 | */ | 253 | */ |
| 254 | armada_370_xp_clkevt.irq = irq_of_parse_and_map(np, 4); | 254 | armada_370_xp_clkevt_irq = irq_of_parse_and_map(np, 4); |
| 255 | 255 | ||
| 256 | ticks_per_jiffy = (timer_clk + HZ / 2) / HZ; | 256 | ticks_per_jiffy = (timer_clk + HZ / 2) / HZ; |
| 257 | 257 | ||
| @@ -267,35 +267,52 @@ void __init armada_370_xp_timer_init(void) | |||
| 267 | writel(0xffffffff, timer_base + TIMER0_VAL_OFF); | 267 | writel(0xffffffff, timer_base + TIMER0_VAL_OFF); |
| 268 | writel(0xffffffff, timer_base + TIMER0_RELOAD_OFF); | 268 | writel(0xffffffff, timer_base + TIMER0_RELOAD_OFF); |
| 269 | 269 | ||
| 270 | u = readl(timer_base + TIMER_CTRL_OFF); | 270 | timer_ctrl_clrset(0, TIMER0_EN | TIMER0_RELOAD_EN | |
| 271 | 271 | TIMER0_DIV(TIMER_DIVIDER_SHIFT)); | |
| 272 | writel((u | TIMER0_EN | TIMER0_RELOAD_EN | | ||
| 273 | TIMER0_DIV(TIMER_DIVIDER_SHIFT)), timer_base + TIMER_CTRL_OFF); | ||
| 274 | 272 | ||
| 275 | clocksource_mmio_init(timer_base + TIMER0_VAL_OFF, | 273 | clocksource_mmio_init(timer_base + TIMER0_VAL_OFF, |
| 276 | "armada_370_xp_clocksource", | 274 | "armada_370_xp_clocksource", |
| 277 | timer_clk, 300, 32, clocksource_mmio_readl_down); | 275 | timer_clk, 300, 32, clocksource_mmio_readl_down); |
| 278 | 276 | ||
| 279 | /* Register the clockevent on the private timer of CPU 0 */ | 277 | register_cpu_notifier(&armada_370_xp_timer_cpu_nb); |
| 280 | armada_370_xp_clkevt.cpumask = cpumask_of(0); | ||
| 281 | clockevents_config_and_register(&armada_370_xp_clkevt, | ||
| 282 | timer_clk, 1, 0xfffffffe); | ||
| 283 | 278 | ||
| 284 | percpu_armada_370_xp_evt = alloc_percpu(struct clock_event_device *); | 279 | armada_370_xp_evt = alloc_percpu(struct clock_event_device); |
| 285 | 280 | ||
| 286 | 281 | ||
| 287 | /* | 282 | /* |
| 288 | * Setup clockevent timer (interrupt-driven). | 283 | * Setup clockevent timer (interrupt-driven). |
| 289 | */ | 284 | */ |
| 290 | *__this_cpu_ptr(percpu_armada_370_xp_evt) = &armada_370_xp_clkevt; | 285 | res = request_percpu_irq(armada_370_xp_clkevt_irq, |
| 291 | res = request_percpu_irq(armada_370_xp_clkevt.irq, | ||
| 292 | armada_370_xp_timer_interrupt, | 286 | armada_370_xp_timer_interrupt, |
| 293 | armada_370_xp_clkevt.name, | 287 | "armada_370_xp_per_cpu_tick", |
| 294 | percpu_armada_370_xp_evt); | 288 | armada_370_xp_evt); |
| 295 | if (!res) { | 289 | /* Immediately configure the timer on the boot CPU */ |
| 296 | enable_percpu_irq(armada_370_xp_clkevt.irq, 0); | 290 | if (!res) |
| 297 | #ifdef CONFIG_LOCAL_TIMERS | 291 | armada_370_xp_timer_setup(this_cpu_ptr(armada_370_xp_evt)); |
| 298 | local_timer_register(&armada_370_xp_local_timer_ops); | 292 | } |
| 299 | #endif | 293 | |
| 300 | } | 294 | static void __init armada_xp_timer_init(struct device_node *np) |
| 295 | { | ||
| 296 | struct clk *clk = of_clk_get_by_name(np, "fixed"); | ||
| 297 | |||
| 298 | /* The 25Mhz fixed clock is mandatory, and must always be available */ | ||
| 299 | BUG_ON(IS_ERR(clk)); | ||
| 300 | timer_clk = clk_get_rate(clk); | ||
| 301 | |||
| 302 | armada_370_xp_timer_common_init(np); | ||
| 303 | } | ||
| 304 | CLOCKSOURCE_OF_DECLARE(armada_xp, "marvell,armada-xp-timer", | ||
| 305 | armada_xp_timer_init); | ||
| 306 | |||
| 307 | static void __init armada_370_timer_init(struct device_node *np) | ||
| 308 | { | ||
| 309 | struct clk *clk = of_clk_get(np, 0); | ||
| 310 | |||
| 311 | BUG_ON(IS_ERR(clk)); | ||
| 312 | timer_clk = clk_get_rate(clk) / TIMER_DIVIDER; | ||
| 313 | timer25Mhz = false; | ||
| 314 | |||
| 315 | armada_370_xp_timer_common_init(np); | ||
| 301 | } | 316 | } |
| 317 | CLOCKSOURCE_OF_DECLARE(armada_370, "marvell,armada-370-timer", | ||
| 318 | armada_370_timer_init); | ||
diff --git a/drivers/clocksource/time-orion.c b/drivers/clocksource/time-orion.c index ecbeb6810215..9c7f018a67ca 100644 --- a/drivers/clocksource/time-orion.c +++ b/drivers/clocksource/time-orion.c | |||
| @@ -19,7 +19,7 @@ | |||
| 19 | #include <linux/of_address.h> | 19 | #include <linux/of_address.h> |
| 20 | #include <linux/of_irq.h> | 20 | #include <linux/of_irq.h> |
| 21 | #include <linux/spinlock.h> | 21 | #include <linux/spinlock.h> |
| 22 | #include <asm/sched_clock.h> | 22 | #include <linux/sched_clock.h> |
| 23 | 23 | ||
| 24 | #define TIMER_CTRL 0x00 | 24 | #define TIMER_CTRL 0x00 |
| 25 | #define TIMER0_EN BIT(0) | 25 | #define TIMER0_EN BIT(0) |
diff --git a/drivers/clocksource/timer-marco.c b/drivers/clocksource/timer-marco.c index e5dc9129ca26..09a17d9a6594 100644 --- a/drivers/clocksource/timer-marco.c +++ b/drivers/clocksource/timer-marco.c | |||
| @@ -10,6 +10,7 @@ | |||
| 10 | #include <linux/interrupt.h> | 10 | #include <linux/interrupt.h> |
| 11 | #include <linux/clockchips.h> | 11 | #include <linux/clockchips.h> |
| 12 | #include <linux/clocksource.h> | 12 | #include <linux/clocksource.h> |
| 13 | #include <linux/cpu.h> | ||
| 13 | #include <linux/bitops.h> | 14 | #include <linux/bitops.h> |
| 14 | #include <linux/irq.h> | 15 | #include <linux/irq.h> |
| 15 | #include <linux/clk.h> | 16 | #include <linux/clk.h> |
| @@ -18,7 +19,6 @@ | |||
| 18 | #include <linux/of_irq.h> | 19 | #include <linux/of_irq.h> |
| 19 | #include <linux/of_address.h> | 20 | #include <linux/of_address.h> |
| 20 | #include <linux/sched_clock.h> | 21 | #include <linux/sched_clock.h> |
| 21 | #include <asm/localtimer.h> | ||
| 22 | #include <asm/mach/time.h> | 22 | #include <asm/mach/time.h> |
| 23 | 23 | ||
| 24 | #define SIRFSOC_TIMER_32COUNTER_0_CTRL 0x0000 | 24 | #define SIRFSOC_TIMER_32COUNTER_0_CTRL 0x0000 |
| @@ -151,13 +151,7 @@ static void sirfsoc_clocksource_resume(struct clocksource *cs) | |||
| 151 | BIT(1) | BIT(0), sirfsoc_timer_base + SIRFSOC_TIMER_64COUNTER_CTRL); | 151 | BIT(1) | BIT(0), sirfsoc_timer_base + SIRFSOC_TIMER_64COUNTER_CTRL); |
| 152 | } | 152 | } |
| 153 | 153 | ||
| 154 | static struct clock_event_device sirfsoc_clockevent = { | 154 | static struct clock_event_device __percpu *sirfsoc_clockevent; |
| 155 | .name = "sirfsoc_clockevent", | ||
| 156 | .rating = 200, | ||
| 157 | .features = CLOCK_EVT_FEAT_ONESHOT, | ||
| 158 | .set_mode = sirfsoc_timer_set_mode, | ||
| 159 | .set_next_event = sirfsoc_timer_set_next_event, | ||
| 160 | }; | ||
| 161 | 155 | ||
| 162 | static struct clocksource sirfsoc_clocksource = { | 156 | static struct clocksource sirfsoc_clocksource = { |
| 163 | .name = "sirfsoc_clocksource", | 157 | .name = "sirfsoc_clocksource", |
| @@ -173,37 +167,38 @@ static struct irqaction sirfsoc_timer_irq = { | |||
| 173 | .name = "sirfsoc_timer0", | 167 | .name = "sirfsoc_timer0", |
| 174 | .flags = IRQF_TIMER | IRQF_NOBALANCING, | 168 | .flags = IRQF_TIMER | IRQF_NOBALANCING, |
| 175 | .handler = sirfsoc_timer_interrupt, | 169 | .handler = sirfsoc_timer_interrupt, |
| 176 | .dev_id = &sirfsoc_clockevent, | ||
| 177 | }; | 170 | }; |
| 178 | 171 | ||
| 179 | #ifdef CONFIG_LOCAL_TIMERS | ||
| 180 | |||
| 181 | static struct irqaction sirfsoc_timer1_irq = { | 172 | static struct irqaction sirfsoc_timer1_irq = { |
| 182 | .name = "sirfsoc_timer1", | 173 | .name = "sirfsoc_timer1", |
| 183 | .flags = IRQF_TIMER | IRQF_NOBALANCING, | 174 | .flags = IRQF_TIMER | IRQF_NOBALANCING, |
| 184 | .handler = sirfsoc_timer_interrupt, | 175 | .handler = sirfsoc_timer_interrupt, |
| 185 | }; | 176 | }; |
| 186 | 177 | ||
| 187 | static int __cpuinit sirfsoc_local_timer_setup(struct clock_event_device *ce) | 178 | static int sirfsoc_local_timer_setup(struct clock_event_device *ce) |
| 188 | { | 179 | { |
| 189 | /* Use existing clock_event for cpu 0 */ | 180 | int cpu = smp_processor_id(); |
| 190 | if (!smp_processor_id()) | 181 | struct irqaction *action; |
| 191 | return 0; | 182 | |
| 183 | if (cpu == 0) | ||
| 184 | action = &sirfsoc_timer_irq; | ||
| 185 | else | ||
| 186 | action = &sirfsoc_timer1_irq; | ||
| 192 | 187 | ||
| 193 | ce->irq = sirfsoc_timer1_irq.irq; | 188 | ce->irq = action->irq; |
| 194 | ce->name = "local_timer"; | 189 | ce->name = "local_timer"; |
| 195 | ce->features = sirfsoc_clockevent.features; | 190 | ce->features = CLOCK_EVT_FEAT_ONESHOT; |
| 196 | ce->rating = sirfsoc_clockevent.rating; | 191 | ce->rating = 200; |
| 197 | ce->set_mode = sirfsoc_timer_set_mode; | 192 | ce->set_mode = sirfsoc_timer_set_mode; |
| 198 | ce->set_next_event = sirfsoc_timer_set_next_event; | 193 | ce->set_next_event = sirfsoc_timer_set_next_event; |
| 199 | ce->shift = sirfsoc_clockevent.shift; | 194 | clockevents_calc_mult_shift(ce, CLOCK_TICK_RATE, 60); |
| 200 | ce->mult = sirfsoc_clockevent.mult; | 195 | ce->max_delta_ns = clockevent_delta2ns(-2, ce); |
| 201 | ce->max_delta_ns = sirfsoc_clockevent.max_delta_ns; | 196 | ce->min_delta_ns = clockevent_delta2ns(2, ce); |
| 202 | ce->min_delta_ns = sirfsoc_clockevent.min_delta_ns; | 197 | ce->cpumask = cpumask_of(cpu); |
| 203 | 198 | ||
| 204 | sirfsoc_timer1_irq.dev_id = ce; | 199 | action->dev_id = ce; |
| 205 | BUG_ON(setup_irq(ce->irq, &sirfsoc_timer1_irq)); | 200 | BUG_ON(setup_irq(ce->irq, action)); |
| 206 | irq_set_affinity(sirfsoc_timer1_irq.irq, cpumask_of(1)); | 201 | irq_set_affinity(action->irq, cpumask_of(cpu)); |
| 207 | 202 | ||
| 208 | clockevents_register_device(ce); | 203 | clockevents_register_device(ce); |
| 209 | return 0; | 204 | return 0; |
| @@ -211,31 +206,48 @@ static int __cpuinit sirfsoc_local_timer_setup(struct clock_event_device *ce) | |||
| 211 | 206 | ||
| 212 | static void sirfsoc_local_timer_stop(struct clock_event_device *ce) | 207 | static void sirfsoc_local_timer_stop(struct clock_event_device *ce) |
| 213 | { | 208 | { |
| 209 | int cpu = smp_processor_id(); | ||
| 210 | |||
| 214 | sirfsoc_timer_count_disable(1); | 211 | sirfsoc_timer_count_disable(1); |
| 215 | 212 | ||
| 216 | remove_irq(sirfsoc_timer1_irq.irq, &sirfsoc_timer1_irq); | 213 | if (cpu == 0) |
| 214 | remove_irq(sirfsoc_timer_irq.irq, &sirfsoc_timer_irq); | ||
| 215 | else | ||
| 216 | remove_irq(sirfsoc_timer1_irq.irq, &sirfsoc_timer1_irq); | ||
| 217 | } | 217 | } |
| 218 | 218 | ||
| 219 | static struct local_timer_ops sirfsoc_local_timer_ops __cpuinitdata = { | 219 | static int sirfsoc_cpu_notify(struct notifier_block *self, |
| 220 | .setup = sirfsoc_local_timer_setup, | 220 | unsigned long action, void *hcpu) |
| 221 | .stop = sirfsoc_local_timer_stop, | 221 | { |
| 222 | /* | ||
| 223 | * Grab cpu pointer in each case to avoid spurious | ||
| 224 | * preemptible warnings | ||
| 225 | */ | ||
| 226 | switch (action & ~CPU_TASKS_FROZEN) { | ||
| 227 | case CPU_STARTING: | ||
| 228 | sirfsoc_local_timer_setup(this_cpu_ptr(sirfsoc_clockevent)); | ||
| 229 | break; | ||
| 230 | case CPU_DYING: | ||
| 231 | sirfsoc_local_timer_stop(this_cpu_ptr(sirfsoc_clockevent)); | ||
| 232 | break; | ||
| 233 | } | ||
| 234 | |||
| 235 | return NOTIFY_OK; | ||
| 236 | } | ||
| 237 | |||
| 238 | static struct notifier_block sirfsoc_cpu_nb = { | ||
| 239 | .notifier_call = sirfsoc_cpu_notify, | ||
| 222 | }; | 240 | }; |
| 223 | #endif /* CONFIG_LOCAL_TIMERS */ | ||
| 224 | 241 | ||
| 225 | static void __init sirfsoc_clockevent_init(void) | 242 | static void __init sirfsoc_clockevent_init(void) |
| 226 | { | 243 | { |
| 227 | clockevents_calc_mult_shift(&sirfsoc_clockevent, CLOCK_TICK_RATE, 60); | 244 | sirfsoc_clockevent = alloc_percpu(struct clock_event_device); |
| 228 | 245 | BUG_ON(!sirfsoc_clockevent); | |
| 229 | sirfsoc_clockevent.max_delta_ns = | 246 | |
| 230 | clockevent_delta2ns(-2, &sirfsoc_clockevent); | 247 | BUG_ON(register_cpu_notifier(&sirfsoc_cpu_nb)); |
| 231 | sirfsoc_clockevent.min_delta_ns = | 248 | |
| 232 | clockevent_delta2ns(2, &sirfsoc_clockevent); | 249 | /* Immediately configure the timer on the boot CPU */ |
| 233 | 250 | sirfsoc_local_timer_setup(this_cpu_ptr(sirfsoc_clockevent)); | |
| 234 | sirfsoc_clockevent.cpumask = cpumask_of(0); | ||
| 235 | clockevents_register_device(&sirfsoc_clockevent); | ||
| 236 | #ifdef CONFIG_LOCAL_TIMERS | ||
| 237 | local_timer_register(&sirfsoc_local_timer_ops); | ||
| 238 | #endif | ||
| 239 | } | 251 | } |
| 240 | 252 | ||
| 241 | /* initialize the kernel jiffy timer source */ | 253 | /* initialize the kernel jiffy timer source */ |
| @@ -273,8 +285,6 @@ static void __init sirfsoc_marco_timer_init(void) | |||
| 273 | 285 | ||
| 274 | BUG_ON(clocksource_register_hz(&sirfsoc_clocksource, CLOCK_TICK_RATE)); | 286 | BUG_ON(clocksource_register_hz(&sirfsoc_clocksource, CLOCK_TICK_RATE)); |
| 275 | 287 | ||
| 276 | BUG_ON(setup_irq(sirfsoc_timer_irq.irq, &sirfsoc_timer_irq)); | ||
| 277 | |||
| 278 | sirfsoc_clockevent_init(); | 288 | sirfsoc_clockevent_init(); |
| 279 | } | 289 | } |
| 280 | 290 | ||
| @@ -288,11 +298,9 @@ static void __init sirfsoc_of_timer_init(struct device_node *np) | |||
| 288 | if (!sirfsoc_timer_irq.irq) | 298 | if (!sirfsoc_timer_irq.irq) |
| 289 | panic("No irq passed for timer0 via DT\n"); | 299 | panic("No irq passed for timer0 via DT\n"); |
| 290 | 300 | ||
| 291 | #ifdef CONFIG_LOCAL_TIMERS | ||
| 292 | sirfsoc_timer1_irq.irq = irq_of_parse_and_map(np, 1); | 301 | sirfsoc_timer1_irq.irq = irq_of_parse_and_map(np, 1); |
| 293 | if (!sirfsoc_timer1_irq.irq) | 302 | if (!sirfsoc_timer1_irq.irq) |
| 294 | panic("No irq passed for timer1 via DT\n"); | 303 | panic("No irq passed for timer1 via DT\n"); |
| 295 | #endif | ||
| 296 | 304 | ||
| 297 | sirfsoc_marco_timer_init(); | 305 | sirfsoc_marco_timer_init(); |
| 298 | } | 306 | } |
