Blame view
drivers/clocksource/nomadik-mtu.c
7.29 KB
28ad94ec6 [ARM] 5590/1: Add... |
1 |
/* |
28ad94ec6 [ARM] 5590/1: Add... |
2 |
* Copyright (C) 2008 STMicroelectronics |
b102c01fa ARM: 5978/1: plat... |
3 |
* Copyright (C) 2010 Alessandro Rubini |
8fbb97a2b ARM: 6488/1: noma... |
4 |
* Copyright (C) 2010 Linus Walleij for ST-Ericsson |
28ad94ec6 [ARM] 5590/1: Add... |
5 6 7 8 9 10 11 12 13 14 |
* * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2, as * published by the Free Software Foundation. */ #include <linux/init.h> #include <linux/interrupt.h> #include <linux/irq.h> #include <linux/io.h> #include <linux/clockchips.h> |
694e33a7f ARM: plat-nomadik... |
15 |
#include <linux/clocksource.h> |
c7785ea0d clocksource: noma... |
16 17 18 |
#include <linux/of_address.h> #include <linux/of_irq.h> #include <linux/of_platform.h> |
ba327b1e5 ARM: 6145/1: ux50... |
19 |
#include <linux/clk.h> |
28ad94ec6 [ARM] 5590/1: Add... |
20 |
#include <linux/jiffies.h> |
6f179b724 clocksource: noma... |
21 |
#include <linux/delay.h> |
ba327b1e5 ARM: 6145/1: ux50... |
22 |
#include <linux/err.h> |
38ff87f77 sched_clock: Make... |
23 |
#include <linux/sched_clock.h> |
28ad94ec6 [ARM] 5590/1: Add... |
24 |
#include <asm/mach/time.h> |
28ad94ec6 [ARM] 5590/1: Add... |
25 |
|
05387a9fb ARM: plat-nomadik... |
26 |
/* |
05387a9fb ARM: plat-nomadik... |
27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 |
* The MTU device hosts four different counters, with 4 set of * registers. These are register names. */ #define MTU_IMSC 0x00 /* Interrupt mask set/clear */ #define MTU_RIS 0x04 /* Raw interrupt status */ #define MTU_MIS 0x08 /* Masked interrupt status */ #define MTU_ICR 0x0C /* Interrupt clear register */ /* per-timer registers take 0..3 as argument */ #define MTU_LR(x) (0x10 + 0x10 * (x) + 0x00) /* Load value */ #define MTU_VAL(x) (0x10 + 0x10 * (x) + 0x04) /* Current value */ #define MTU_CR(x) (0x10 + 0x10 * (x) + 0x08) /* Control reg */ #define MTU_BGLR(x) (0x10 + 0x10 * (x) + 0x0c) /* At next overflow */ /* bits for the control register */ #define MTU_CRn_ENA 0x80 #define MTU_CRn_PERIODIC 0x40 /* if 0 = free-running */ #define MTU_CRn_PRESCALE_MASK 0x0c #define MTU_CRn_PRESCALE_1 0x00 #define MTU_CRn_PRESCALE_16 0x04 #define MTU_CRn_PRESCALE_256 0x08 #define MTU_CRn_32BITS 0x02 #define MTU_CRn_ONESHOT 0x01 /* if 0 = wraps reloading from BGLR*/ /* Other registers are usual amba/primecell registers, currently not used */ #define MTU_ITCR 0xff0 #define MTU_ITOP 0xff4 #define MTU_PERIPH_ID0 0xfe0 #define MTU_PERIPH_ID1 0xfe4 #define MTU_PERIPH_ID2 0xfe8 #define MTU_PERIPH_ID3 0xfeC #define MTU_PCELL0 0xff0 #define MTU_PCELL1 0xff4 #define MTU_PCELL2 0xff8 #define MTU_PCELL3 0xffC |
28ad94ec6 [ARM] 5590/1: Add... |
65 |
|
b9576623c ARM: plat-nomadik... |
66 |
static void __iomem *mtu_base; |
2f73a0684 ARM: plat-nomadik... |
67 68 69 |
static bool clkevt_periodic; static u32 clk_prescale; static u32 nmdk_cycle; /* write-once */ |
6f179b724 clocksource: noma... |
70 |
static struct delay_timer mtu_delay_timer; |
2f73a0684 ARM: plat-nomadik... |
71 |
|
ea7113f70 clocksource: noma... |
72 |
#ifdef CONFIG_CLKSRC_NOMADIK_MTU_SCHED_CLOCK |
2a847513c ARM: 6107/1: plat... |
73 |
/* |
2a847513c ARM: 6107/1: plat... |
74 75 |
* Override the global weak sched_clock symbol with this * local implementation which uses the clocksource to get some |
8fbb97a2b ARM: 6488/1: noma... |
76 |
* better resolution when scheduling the kernel. |
2a847513c ARM: 6107/1: plat... |
77 |
*/ |
e25bc5f5a clocksource: noma... |
78 |
static u64 notrace nomadik_read_sched_clock(void) |
2a847513c ARM: 6107/1: plat... |
79 |
{ |
8fbb97a2b ARM: 6488/1: noma... |
80 81 |
if (unlikely(!mtu_base)) return 0; |
2f0778afa ARM: 7205/2: sche... |
82 |
return -readl(mtu_base + MTU_VAL(0)); |
2a847513c ARM: 6107/1: plat... |
83 |
} |
cba13830d ARM: plat-nomadik... |
84 |
#endif |
2f73a0684 ARM: plat-nomadik... |
85 |
|
6f179b724 clocksource: noma... |
86 87 88 89 |
static unsigned long nmdk_timer_read_current_timer(void) { return ~readl_relaxed(mtu_base + MTU_VAL(0)); } |
b102c01fa ARM: 5978/1: plat... |
90 |
/* Clockevent device: use one-shot mode */ |
2f73a0684 ARM: plat-nomadik... |
91 92 93 94 95 96 97 98 99 100 101 |
static int nmdk_clkevt_next(unsigned long evt, struct clock_event_device *ev) { writel(1 << 1, mtu_base + MTU_IMSC); writel(evt, mtu_base + MTU_LR(1)); /* Load highest value, enable device, enable interrupts */ writel(MTU_CRn_ONESHOT | clk_prescale | MTU_CRn_32BITS | MTU_CRn_ENA, mtu_base + MTU_CR(1)); return 0; } |
7172c19a2 clksrc: delete no... |
102 |
static void nmdk_clkevt_reset(void) |
2f73a0684 ARM: plat-nomadik... |
103 104 |
{ if (clkevt_periodic) { |
2f73a0684 ARM: plat-nomadik... |
105 106 107 108 109 110 111 112 113 114 115 116 117 |
/* Timer: configure load and background-load, and fire it up */ writel(nmdk_cycle, mtu_base + MTU_LR(1)); writel(nmdk_cycle, mtu_base + MTU_BGLR(1)); writel(MTU_CRn_PERIODIC | clk_prescale | MTU_CRn_32BITS | MTU_CRn_ENA, mtu_base + MTU_CR(1)); writel(1 << 1, mtu_base + MTU_IMSC); } else { /* Generate an interrupt to start the clockevent again */ (void) nmdk_clkevt_next(nmdk_cycle, NULL); } } |
28ad94ec6 [ARM] 5590/1: Add... |
118 119 120 |
static void nmdk_clkevt_mode(enum clock_event_mode mode, struct clock_event_device *dev) { |
28ad94ec6 [ARM] 5590/1: Add... |
121 122 |
switch (mode) { case CLOCK_EVT_MODE_PERIODIC: |
2f73a0684 ARM: plat-nomadik... |
123 124 |
clkevt_periodic = true; nmdk_clkevt_reset(); |
28ad94ec6 [ARM] 5590/1: Add... |
125 126 |
break; case CLOCK_EVT_MODE_ONESHOT: |
2f73a0684 ARM: plat-nomadik... |
127 |
clkevt_periodic = false; |
b102c01fa ARM: 5978/1: plat... |
128 |
break; |
28ad94ec6 [ARM] 5590/1: Add... |
129 130 |
case CLOCK_EVT_MODE_SHUTDOWN: case CLOCK_EVT_MODE_UNUSED: |
b102c01fa ARM: 5978/1: plat... |
131 |
writel(0, mtu_base + MTU_IMSC); |
2917947a6 ARM: 6153/1: noma... |
132 |
/* disable timer */ |
2f73a0684 ARM: plat-nomadik... |
133 |
writel(0, mtu_base + MTU_CR(1)); |
2917947a6 ARM: 6153/1: noma... |
134 135 |
/* load some high default value */ writel(0xffffffff, mtu_base + MTU_LR(1)); |
28ad94ec6 [ARM] 5590/1: Add... |
136 137 138 139 140 |
break; case CLOCK_EVT_MODE_RESUME: break; } } |
7172c19a2 clksrc: delete no... |
141 |
static void nmdk_clksrc_reset(void) |
8726e96fc ARM: ux500: conve... |
142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 |
{ /* Disable */ writel(0, mtu_base + MTU_CR(0)); /* ClockSource: configure load and background-load, and fire it up */ writel(nmdk_cycle, mtu_base + MTU_LR(0)); writel(nmdk_cycle, mtu_base + MTU_BGLR(0)); writel(clk_prescale | MTU_CRn_32BITS | MTU_CRn_ENA, mtu_base + MTU_CR(0)); } static void nmdk_clkevt_resume(struct clock_event_device *cedev) { nmdk_clkevt_reset(); nmdk_clksrc_reset(); } |
28ad94ec6 [ARM] 5590/1: Add... |
159 |
static struct clock_event_device nmdk_clkevt = { |
b102c01fa ARM: 5978/1: plat... |
160 |
.name = "mtu_1", |
74adcbffa ARM: nomadik: add... |
161 162 |
.features = CLOCK_EVT_FEAT_ONESHOT | CLOCK_EVT_FEAT_PERIODIC | CLOCK_EVT_FEAT_DYNIRQ, |
b102c01fa ARM: 5978/1: plat... |
163 |
.rating = 200, |
28ad94ec6 [ARM] 5590/1: Add... |
164 |
.set_mode = nmdk_clkevt_mode, |
b102c01fa ARM: 5978/1: plat... |
165 |
.set_next_event = nmdk_clkevt_next, |
8726e96fc ARM: ux500: conve... |
166 |
.resume = nmdk_clkevt_resume, |
28ad94ec6 [ARM] 5590/1: Add... |
167 168 169 |
}; /* |
b102c01fa ARM: 5978/1: plat... |
170 |
* IRQ Handler for timer 1 of the MTU block. |
28ad94ec6 [ARM] 5590/1: Add... |
171 172 173 |
*/ static irqreturn_t nmdk_timer_interrupt(int irq, void *dev_id) { |
b102c01fa ARM: 5978/1: plat... |
174 |
struct clock_event_device *evdev = dev_id; |
28ad94ec6 [ARM] 5590/1: Add... |
175 |
|
b102c01fa ARM: 5978/1: plat... |
176 177 |
writel(1 << 1, mtu_base + MTU_ICR); /* Interrupt clear reg */ evdev->event_handler(evdev); |
28ad94ec6 [ARM] 5590/1: Add... |
178 179 |
return IRQ_HANDLED; } |
28ad94ec6 [ARM] 5590/1: Add... |
180 181 |
static struct irqaction nmdk_timer_irq = { .name = "Nomadik Timer Tick", |
38c30a842 clocksource: misc... |
182 |
.flags = IRQF_TIMER, |
28ad94ec6 [ARM] 5590/1: Add... |
183 |
.handler = nmdk_timer_interrupt, |
b102c01fa ARM: 5978/1: plat... |
184 |
.dev_id = &nmdk_clkevt, |
28ad94ec6 [ARM] 5590/1: Add... |
185 |
}; |
7172c19a2 clksrc: delete no... |
186 187 |
static void __init nmdk_timer_init(void __iomem *base, int irq, struct clk *pclk, struct clk *clk) |
28ad94ec6 [ARM] 5590/1: Add... |
188 |
{ |
28ad94ec6 [ARM] 5590/1: Add... |
189 |
unsigned long rate; |
ba327b1e5 ARM: 6145/1: ux50... |
190 |
|
b9576623c ARM: plat-nomadik... |
191 |
mtu_base = base; |
16defa668 clocksource/mtu-n... |
192 |
|
c7785ea0d clocksource: noma... |
193 194 |
BUG_ON(clk_prepare_enable(pclk)); BUG_ON(clk_prepare_enable(clk)); |
b102c01fa ARM: 5978/1: plat... |
195 196 |
/* |
a0719f52d ARM: 6376/1: plat... |
197 198 199 200 201 202 |
* Tick rate is 2.4MHz for Nomadik and 2.4Mhz, 100MHz or 133 MHz * for ux500. * Use a divide-by-16 counter if the tick rate is more than 32MHz. * At 32 MHz, the timer (with 32 bit counter) can be programmed * to wake-up at a max 127s a head in time. Dividing a 2.4 MHz timer * with 16 gives too low timer resolution. |
b102c01fa ARM: 5978/1: plat... |
203 |
*/ |
c7785ea0d clocksource: noma... |
204 |
rate = clk_get_rate(clk); |
a0719f52d ARM: 6376/1: plat... |
205 |
if (rate > 32000000) { |
b102c01fa ARM: 5978/1: plat... |
206 |
rate /= 16; |
2f73a0684 ARM: plat-nomadik... |
207 |
clk_prescale = MTU_CRn_PRESCALE_16; |
b102c01fa ARM: 5978/1: plat... |
208 |
} else { |
2f73a0684 ARM: plat-nomadik... |
209 |
clk_prescale = MTU_CRn_PRESCALE_1; |
b102c01fa ARM: 5978/1: plat... |
210 |
} |
28ad94ec6 [ARM] 5590/1: Add... |
211 |
|
213668317 ARM: plat-nomadik... |
212 213 |
/* Cycles for periodic mode */ nmdk_cycle = DIV_ROUND_CLOSEST(rate, HZ); |
2f73a0684 ARM: plat-nomadik... |
214 |
|
b102c01fa ARM: 5978/1: plat... |
215 |
/* Timer 0 is the free running clocksource */ |
2f73a0684 ARM: plat-nomadik... |
216 |
nmdk_clksrc_reset(); |
28ad94ec6 [ARM] 5590/1: Add... |
217 |
|
bfe45e0be clocksource: conv... |
218 219 |
if (clocksource_mmio_init(mtu_base + MTU_VAL(0), "mtu_0", rate, 200, 32, clocksource_mmio_readl_down)) |
b102c01fa ARM: 5978/1: plat... |
220 221 |
pr_err("timer: failed to initialize clock source %s ", |
bfe45e0be clocksource: conv... |
222 |
"mtu_0"); |
2f0778afa ARM: 7205/2: sche... |
223 |
|
ea7113f70 clocksource: noma... |
224 |
#ifdef CONFIG_CLKSRC_NOMADIK_MTU_SCHED_CLOCK |
e25bc5f5a clocksource: noma... |
225 |
sched_clock_register(nomadik_read_sched_clock, 32, rate); |
cba13830d ARM: plat-nomadik... |
226 |
#endif |
2f0778afa ARM: 7205/2: sche... |
227 |
|
a3b86a6d6 ARM: plat-nomadik... |
228 |
/* Timer 1 is used for events, register irq and clockevents */ |
0813069d0 ARM: plat-nomadik... |
229 |
setup_irq(irq, &nmdk_timer_irq); |
a3b86a6d6 ARM: plat-nomadik... |
230 |
nmdk_clkevt.cpumask = cpumask_of(0); |
00f4e13c4 clocksource : Nom... |
231 |
nmdk_clkevt.irq = irq; |
a3b86a6d6 ARM: plat-nomadik... |
232 |
clockevents_config_and_register(&nmdk_clkevt, rate, 2, 0xffffffffU); |
6f179b724 clocksource: noma... |
233 234 235 236 |
mtu_delay_timer.read_current_timer = &nmdk_timer_read_current_timer; mtu_delay_timer.freq = rate; register_current_timer_delay(&mtu_delay_timer); |
28ad94ec6 [ARM] 5590/1: Add... |
237 |
} |
c7785ea0d clocksource: noma... |
238 |
|
3c09f4dae ARM: nomadik: fix... |
239 |
static void __init nmdk_timer_of_init(struct device_node *node) |
c7785ea0d clocksource: noma... |
240 |
{ |
c7785ea0d clocksource: noma... |
241 242 243 244 |
struct clk *pclk; struct clk *clk; void __iomem *base; int irq; |
c7785ea0d clocksource: noma... |
245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 |
base = of_iomap(node, 0); if (!base) panic("Can't remap registers"); pclk = of_clk_get_by_name(node, "apb_pclk"); if (IS_ERR(pclk)) panic("could not get apb_pclk"); clk = of_clk_get_by_name(node, "timclk"); if (IS_ERR(clk)) panic("could not get timclk"); irq = irq_of_parse_and_map(node, 0); if (irq <= 0) panic("Can't parse IRQ"); |
7172c19a2 clksrc: delete no... |
260 |
nmdk_timer_init(base, irq, pclk, clk); |
c7785ea0d clocksource: noma... |
261 262 263 |
} CLOCKSOURCE_OF_DECLARE(nomadik_mtu, "st,nomadik-mtu", nmdk_timer_of_init); |