diff options
Diffstat (limited to 'arch/blackfin/kernel/time-ts.c')
| -rw-r--r-- | arch/blackfin/kernel/time-ts.c | 222 |
1 files changed, 183 insertions, 39 deletions
diff --git a/arch/blackfin/kernel/time-ts.c b/arch/blackfin/kernel/time-ts.c index 27646121280a..0791eba40d9f 100644 --- a/arch/blackfin/kernel/time-ts.c +++ b/arch/blackfin/kernel/time-ts.c | |||
| @@ -20,8 +20,9 @@ | |||
| 20 | 20 | ||
| 21 | #include <asm/blackfin.h> | 21 | #include <asm/blackfin.h> |
| 22 | #include <asm/time.h> | 22 | #include <asm/time.h> |
| 23 | #include <asm/gptimers.h> | ||
| 23 | 24 | ||
| 24 | #ifdef CONFIG_CYCLES_CLOCKSOURCE | 25 | #if defined(CONFIG_CYCLES_CLOCKSOURCE) |
| 25 | 26 | ||
| 26 | /* Accelerators for sched_clock() | 27 | /* Accelerators for sched_clock() |
| 27 | * convert from cycles(64bits) => nanoseconds (64bits) | 28 | * convert from cycles(64bits) => nanoseconds (64bits) |
| @@ -58,15 +59,15 @@ static inline unsigned long long cycles_2_ns(cycle_t cyc) | |||
| 58 | return (cyc * cyc2ns_scale) >> CYC2NS_SCALE_FACTOR; | 59 | return (cyc * cyc2ns_scale) >> CYC2NS_SCALE_FACTOR; |
| 59 | } | 60 | } |
| 60 | 61 | ||
| 61 | static cycle_t read_cycles(struct clocksource *cs) | 62 | static cycle_t bfin_read_cycles(struct clocksource *cs) |
| 62 | { | 63 | { |
| 63 | return __bfin_cycles_off + (get_cycles() << __bfin_cycles_mod); | 64 | return __bfin_cycles_off + (get_cycles() << __bfin_cycles_mod); |
| 64 | } | 65 | } |
| 65 | 66 | ||
| 66 | static struct clocksource clocksource_bfin = { | 67 | static struct clocksource bfin_cs_cycles = { |
| 67 | .name = "bfin_cycles", | 68 | .name = "bfin_cs_cycles", |
| 68 | .rating = 350, | 69 | .rating = 350, |
| 69 | .read = read_cycles, | 70 | .read = bfin_read_cycles, |
| 70 | .mask = CLOCKSOURCE_MASK(64), | 71 | .mask = CLOCKSOURCE_MASK(64), |
| 71 | .shift = 22, | 72 | .shift = 22, |
| 72 | .flags = CLOCK_SOURCE_IS_CONTINUOUS, | 73 | .flags = CLOCK_SOURCE_IS_CONTINUOUS, |
| @@ -74,53 +75,198 @@ static struct clocksource clocksource_bfin = { | |||
| 74 | 75 | ||
| 75 | unsigned long long sched_clock(void) | 76 | unsigned long long sched_clock(void) |
| 76 | { | 77 | { |
| 77 | return cycles_2_ns(read_cycles(&clocksource_bfin)); | 78 | return cycles_2_ns(bfin_read_cycles(&bfin_cs_cycles)); |
| 78 | } | 79 | } |
| 79 | 80 | ||
| 80 | static int __init bfin_clocksource_init(void) | 81 | static int __init bfin_cs_cycles_init(void) |
| 81 | { | 82 | { |
| 82 | set_cyc2ns_scale(get_cclk() / 1000); | 83 | set_cyc2ns_scale(get_cclk() / 1000); |
| 83 | 84 | ||
| 84 | clocksource_bfin.mult = clocksource_hz2mult(get_cclk(), clocksource_bfin.shift); | 85 | bfin_cs_cycles.mult = \ |
| 86 | clocksource_hz2mult(get_cclk(), bfin_cs_cycles.shift); | ||
| 85 | 87 | ||
| 86 | if (clocksource_register(&clocksource_bfin)) | 88 | if (clocksource_register(&bfin_cs_cycles)) |
| 87 | panic("failed to register clocksource"); | 89 | panic("failed to register clocksource"); |
| 88 | 90 | ||
| 89 | return 0; | 91 | return 0; |
| 90 | } | 92 | } |
| 93 | #else | ||
| 94 | # define bfin_cs_cycles_init() | ||
| 95 | #endif | ||
| 96 | |||
| 97 | #ifdef CONFIG_GPTMR0_CLOCKSOURCE | ||
| 98 | |||
| 99 | void __init setup_gptimer0(void) | ||
| 100 | { | ||
| 101 | disable_gptimers(TIMER0bit); | ||
| 102 | |||
| 103 | set_gptimer_config(TIMER0_id, \ | ||
| 104 | TIMER_OUT_DIS | TIMER_PERIOD_CNT | TIMER_MODE_PWM); | ||
| 105 | set_gptimer_period(TIMER0_id, -1); | ||
| 106 | set_gptimer_pwidth(TIMER0_id, -2); | ||
| 107 | SSYNC(); | ||
| 108 | enable_gptimers(TIMER0bit); | ||
| 109 | } | ||
| 110 | |||
| 111 | static cycle_t bfin_read_gptimer0(void) | ||
| 112 | { | ||
| 113 | return bfin_read_TIMER0_COUNTER(); | ||
| 114 | } | ||
| 115 | |||
| 116 | static struct clocksource bfin_cs_gptimer0 = { | ||
| 117 | .name = "bfin_cs_gptimer0", | ||
| 118 | .rating = 400, | ||
| 119 | .read = bfin_read_gptimer0, | ||
| 120 | .mask = CLOCKSOURCE_MASK(32), | ||
| 121 | .shift = 22, | ||
| 122 | .flags = CLOCK_SOURCE_IS_CONTINUOUS, | ||
| 123 | }; | ||
| 124 | |||
| 125 | static int __init bfin_cs_gptimer0_init(void) | ||
| 126 | { | ||
| 127 | setup_gptimer0(); | ||
| 91 | 128 | ||
| 129 | bfin_cs_gptimer0.mult = \ | ||
| 130 | clocksource_hz2mult(get_sclk(), bfin_cs_gptimer0.shift); | ||
| 131 | |||
| 132 | if (clocksource_register(&bfin_cs_gptimer0)) | ||
| 133 | panic("failed to register clocksource"); | ||
| 134 | |||
| 135 | return 0; | ||
| 136 | } | ||
| 92 | #else | 137 | #else |
| 93 | # define bfin_clocksource_init() | 138 | # define bfin_cs_gptimer0_init() |
| 94 | #endif | 139 | #endif |
| 95 | 140 | ||
| 141 | #ifdef CONFIG_CORE_TIMER_IRQ_L1 | ||
| 142 | __attribute__((l1_text)) | ||
| 143 | #endif | ||
| 144 | irqreturn_t timer_interrupt(int irq, void *dev_id); | ||
| 145 | |||
| 146 | static int bfin_timer_set_next_event(unsigned long, \ | ||
| 147 | struct clock_event_device *); | ||
| 148 | |||
| 149 | static void bfin_timer_set_mode(enum clock_event_mode, \ | ||
| 150 | struct clock_event_device *); | ||
| 151 | |||
| 152 | static struct clock_event_device clockevent_bfin = { | ||
| 153 | #if defined(CONFIG_TICKSOURCE_GPTMR0) | ||
| 154 | .name = "bfin_gptimer0", | ||
| 155 | .rating = 300, | ||
| 156 | .irq = IRQ_TIMER0, | ||
| 157 | #else | ||
| 158 | .name = "bfin_core_timer", | ||
| 159 | .rating = 350, | ||
| 160 | .irq = IRQ_CORETMR, | ||
| 161 | #endif | ||
| 162 | .shift = 32, | ||
| 163 | .features = CLOCK_EVT_FEAT_PERIODIC | CLOCK_EVT_FEAT_ONESHOT, | ||
| 164 | .set_next_event = bfin_timer_set_next_event, | ||
| 165 | .set_mode = bfin_timer_set_mode, | ||
| 166 | }; | ||
| 167 | |||
| 168 | static struct irqaction bfin_timer_irq = { | ||
| 169 | #if defined(CONFIG_TICKSOURCE_GPTMR0) | ||
| 170 | .name = "Blackfin GPTimer0", | ||
| 171 | #else | ||
| 172 | .name = "Blackfin CoreTimer", | ||
| 173 | #endif | ||
| 174 | .flags = IRQF_DISABLED | IRQF_TIMER | \ | ||
| 175 | IRQF_IRQPOLL | IRQF_PERCPU, | ||
| 176 | .handler = timer_interrupt, | ||
| 177 | .dev_id = &clockevent_bfin, | ||
| 178 | }; | ||
| 179 | |||
| 180 | #if defined(CONFIG_TICKSOURCE_GPTMR0) | ||
| 96 | static int bfin_timer_set_next_event(unsigned long cycles, | 181 | static int bfin_timer_set_next_event(unsigned long cycles, |
| 97 | struct clock_event_device *evt) | 182 | struct clock_event_device *evt) |
| 98 | { | 183 | { |
| 184 | disable_gptimers(TIMER0bit); | ||
| 185 | |||
| 186 | /* it starts counting three SCLK cycles after the TIMENx bit is set */ | ||
| 187 | set_gptimer_pwidth(TIMER0_id, cycles - 3); | ||
| 188 | enable_gptimers(TIMER0bit); | ||
| 189 | return 0; | ||
| 190 | } | ||
| 191 | |||
| 192 | static void bfin_timer_set_mode(enum clock_event_mode mode, | ||
| 193 | struct clock_event_device *evt) | ||
| 194 | { | ||
| 195 | switch (mode) { | ||
| 196 | case CLOCK_EVT_MODE_PERIODIC: { | ||
| 197 | set_gptimer_config(TIMER0_id, \ | ||
| 198 | TIMER_OUT_DIS | TIMER_IRQ_ENA | \ | ||
| 199 | TIMER_PERIOD_CNT | TIMER_MODE_PWM); | ||
| 200 | set_gptimer_period(TIMER0_id, get_sclk() / HZ); | ||
| 201 | set_gptimer_pwidth(TIMER0_id, get_sclk() / HZ - 1); | ||
| 202 | enable_gptimers(TIMER0bit); | ||
| 203 | break; | ||
| 204 | } | ||
| 205 | case CLOCK_EVT_MODE_ONESHOT: | ||
| 206 | disable_gptimers(TIMER0bit); | ||
| 207 | set_gptimer_config(TIMER0_id, \ | ||
| 208 | TIMER_OUT_DIS | TIMER_IRQ_ENA | TIMER_MODE_PWM); | ||
| 209 | set_gptimer_period(TIMER0_id, 0); | ||
| 210 | break; | ||
| 211 | case CLOCK_EVT_MODE_UNUSED: | ||
| 212 | case CLOCK_EVT_MODE_SHUTDOWN: | ||
| 213 | disable_gptimers(TIMER0bit); | ||
| 214 | break; | ||
| 215 | case CLOCK_EVT_MODE_RESUME: | ||
| 216 | break; | ||
| 217 | } | ||
| 218 | } | ||
| 219 | |||
| 220 | static void bfin_timer_ack(void) | ||
| 221 | { | ||
| 222 | set_gptimer_status(TIMER_GROUP1, TIMER_STATUS_TIMIL0); | ||
| 223 | } | ||
| 224 | |||
| 225 | static void __init bfin_timer_init(void) | ||
| 226 | { | ||
| 227 | disable_gptimers(TIMER0bit); | ||
| 228 | } | ||
| 229 | |||
| 230 | static unsigned long __init bfin_clockevent_check(void) | ||
| 231 | { | ||
| 232 | setup_irq(IRQ_TIMER0, &bfin_timer_irq); | ||
| 233 | return get_sclk(); | ||
| 234 | } | ||
| 235 | |||
| 236 | #else /* CONFIG_TICKSOURCE_CORETMR */ | ||
| 237 | |||
| 238 | static int bfin_timer_set_next_event(unsigned long cycles, | ||
| 239 | struct clock_event_device *evt) | ||
| 240 | { | ||
| 241 | bfin_write_TCNTL(TMPWR); | ||
| 242 | CSYNC(); | ||
| 99 | bfin_write_TCOUNT(cycles); | 243 | bfin_write_TCOUNT(cycles); |
| 100 | CSYNC(); | 244 | CSYNC(); |
| 245 | bfin_write_TCNTL(TMPWR | TMREN); | ||
| 101 | return 0; | 246 | return 0; |
| 102 | } | 247 | } |
| 103 | 248 | ||
| 104 | static void bfin_timer_set_mode(enum clock_event_mode mode, | 249 | static void bfin_timer_set_mode(enum clock_event_mode mode, |
| 105 | struct clock_event_device *evt) | 250 | struct clock_event_device *evt) |
| 106 | { | 251 | { |
| 107 | switch (mode) { | 252 | switch (mode) { |
| 108 | case CLOCK_EVT_MODE_PERIODIC: { | 253 | case CLOCK_EVT_MODE_PERIODIC: { |
| 109 | unsigned long tcount = ((get_cclk() / (HZ * TIME_SCALE)) - 1); | 254 | unsigned long tcount = ((get_cclk() / (HZ * TIME_SCALE)) - 1); |
| 110 | bfin_write_TCNTL(TMPWR); | 255 | bfin_write_TCNTL(TMPWR); |
| 111 | bfin_write_TSCALE(TIME_SCALE - 1); | ||
| 112 | CSYNC(); | 256 | CSYNC(); |
| 257 | bfin_write_TSCALE(TIME_SCALE - 1); | ||
| 113 | bfin_write_TPERIOD(tcount); | 258 | bfin_write_TPERIOD(tcount); |
| 114 | bfin_write_TCOUNT(tcount); | 259 | bfin_write_TCOUNT(tcount); |
| 115 | bfin_write_TCNTL(TMPWR | TMREN | TAUTORLD); | ||
| 116 | CSYNC(); | 260 | CSYNC(); |
| 261 | bfin_write_TCNTL(TMPWR | TMREN | TAUTORLD); | ||
| 117 | break; | 262 | break; |
| 118 | } | 263 | } |
| 119 | case CLOCK_EVT_MODE_ONESHOT: | 264 | case CLOCK_EVT_MODE_ONESHOT: |
| 265 | bfin_write_TCNTL(TMPWR); | ||
| 266 | CSYNC(); | ||
| 120 | bfin_write_TSCALE(TIME_SCALE - 1); | 267 | bfin_write_TSCALE(TIME_SCALE - 1); |
| 268 | bfin_write_TPERIOD(0); | ||
| 121 | bfin_write_TCOUNT(0); | 269 | bfin_write_TCOUNT(0); |
| 122 | bfin_write_TCNTL(TMPWR | TMREN); | ||
| 123 | CSYNC(); | ||
| 124 | break; | 270 | break; |
| 125 | case CLOCK_EVT_MODE_UNUSED: | 271 | case CLOCK_EVT_MODE_UNUSED: |
| 126 | case CLOCK_EVT_MODE_SHUTDOWN: | 272 | case CLOCK_EVT_MODE_SHUTDOWN: |
| @@ -132,6 +278,10 @@ static void bfin_timer_set_mode(enum clock_event_mode mode, | |||
| 132 | } | 278 | } |
| 133 | } | 279 | } |
| 134 | 280 | ||
| 281 | static void bfin_timer_ack(void) | ||
| 282 | { | ||
| 283 | } | ||
| 284 | |||
| 135 | static void __init bfin_timer_init(void) | 285 | static void __init bfin_timer_init(void) |
| 136 | { | 286 | { |
| 137 | /* power up the timer, but don't enable it just yet */ | 287 | /* power up the timer, but don't enable it just yet */ |
| @@ -145,38 +295,32 @@ static void __init bfin_timer_init(void) | |||
| 145 | bfin_write_TPERIOD(0); | 295 | bfin_write_TPERIOD(0); |
| 146 | bfin_write_TCOUNT(0); | 296 | bfin_write_TCOUNT(0); |
| 147 | 297 | ||
| 148 | /* now enable the timer */ | ||
| 149 | CSYNC(); | 298 | CSYNC(); |
| 150 | } | 299 | } |
| 151 | 300 | ||
| 301 | static unsigned long __init bfin_clockevent_check(void) | ||
| 302 | { | ||
| 303 | setup_irq(IRQ_CORETMR, &bfin_timer_irq); | ||
| 304 | return get_cclk() / TIME_SCALE; | ||
| 305 | } | ||
| 306 | |||
| 307 | void __init setup_core_timer(void) | ||
| 308 | { | ||
| 309 | bfin_timer_init(); | ||
| 310 | bfin_timer_set_mode(CLOCK_EVT_MODE_PERIODIC, NULL); | ||
| 311 | } | ||
| 312 | #endif /* CONFIG_TICKSOURCE_GPTMR0 */ | ||
| 313 | |||
| 152 | /* | 314 | /* |
| 153 | * timer_interrupt() needs to keep up the real-time clock, | 315 | * timer_interrupt() needs to keep up the real-time clock, |
| 154 | * as well as call the "do_timer()" routine every clocktick | 316 | * as well as call the "do_timer()" routine every clocktick |
| 155 | */ | 317 | */ |
| 156 | #ifdef CONFIG_CORE_TIMER_IRQ_L1 | ||
| 157 | __attribute__((l1_text)) | ||
| 158 | #endif | ||
| 159 | irqreturn_t timer_interrupt(int irq, void *dev_id); | ||
| 160 | |||
| 161 | static struct clock_event_device clockevent_bfin = { | ||
| 162 | .name = "bfin_core_timer", | ||
| 163 | .features = CLOCK_EVT_FEAT_PERIODIC | CLOCK_EVT_FEAT_ONESHOT, | ||
| 164 | .shift = 32, | ||
| 165 | .set_next_event = bfin_timer_set_next_event, | ||
| 166 | .set_mode = bfin_timer_set_mode, | ||
| 167 | }; | ||
| 168 | |||
| 169 | static struct irqaction bfin_timer_irq = { | ||
| 170 | .name = "Blackfin Core Timer", | ||
| 171 | .flags = IRQF_DISABLED | IRQF_TIMER | IRQF_IRQPOLL, | ||
| 172 | .handler = timer_interrupt, | ||
| 173 | .dev_id = &clockevent_bfin, | ||
| 174 | }; | ||
| 175 | |||
| 176 | irqreturn_t timer_interrupt(int irq, void *dev_id) | 318 | irqreturn_t timer_interrupt(int irq, void *dev_id) |
| 177 | { | 319 | { |
| 178 | struct clock_event_device *evt = dev_id; | 320 | struct clock_event_device *evt = dev_id; |
| 321 | smp_mb(); | ||
| 179 | evt->event_handler(evt); | 322 | evt->event_handler(evt); |
| 323 | bfin_timer_ack(); | ||
| 180 | return IRQ_HANDLED; | 324 | return IRQ_HANDLED; |
| 181 | } | 325 | } |
| 182 | 326 | ||
| @@ -184,9 +328,8 @@ static int __init bfin_clockevent_init(void) | |||
| 184 | { | 328 | { |
| 185 | unsigned long timer_clk; | 329 | unsigned long timer_clk; |
| 186 | 330 | ||
| 187 | timer_clk = get_cclk() / TIME_SCALE; | 331 | timer_clk = bfin_clockevent_check(); |
| 188 | 332 | ||
| 189 | setup_irq(IRQ_CORETMR, &bfin_timer_irq); | ||
| 190 | bfin_timer_init(); | 333 | bfin_timer_init(); |
| 191 | 334 | ||
| 192 | clockevent_bfin.mult = div_sc(timer_clk, NSEC_PER_SEC, clockevent_bfin.shift); | 335 | clockevent_bfin.mult = div_sc(timer_clk, NSEC_PER_SEC, clockevent_bfin.shift); |
| @@ -218,6 +361,7 @@ void __init time_init(void) | |||
| 218 | xtime.tv_nsec = 0; | 361 | xtime.tv_nsec = 0; |
| 219 | set_normalized_timespec(&wall_to_monotonic, -xtime.tv_sec, -xtime.tv_nsec); | 362 | set_normalized_timespec(&wall_to_monotonic, -xtime.tv_sec, -xtime.tv_nsec); |
| 220 | 363 | ||
| 221 | bfin_clocksource_init(); | 364 | bfin_cs_cycles_init(); |
| 365 | bfin_cs_gptimer0_init(); | ||
| 222 | bfin_clockevent_init(); | 366 | bfin_clockevent_init(); |
| 223 | } | 367 | } |
