~ [ source navigation ] ~ [ diff markup ] ~ [ identifier search ] ~

TOMOYO Linux Cross Reference
Linux/arch/arm/mach-davinci/time.c

Version: ~ [ linux-5.5-rc7 ] ~ [ linux-5.4.13 ] ~ [ linux-5.3.18 ] ~ [ linux-5.2.21 ] ~ [ linux-5.1.21 ] ~ [ linux-5.0.21 ] ~ [ linux-4.20.17 ] ~ [ linux-4.19.97 ] ~ [ linux-4.18.20 ] ~ [ linux-4.17.19 ] ~ [ linux-4.16.18 ] ~ [ linux-4.15.18 ] ~ [ linux-4.14.166 ] ~ [ linux-4.13.16 ] ~ [ linux-4.12.14 ] ~ [ linux-4.11.12 ] ~ [ linux-4.10.17 ] ~ [ linux-4.9.210 ] ~ [ linux-4.8.17 ] ~ [ linux-4.7.10 ] ~ [ linux-4.6.7 ] ~ [ linux-4.5.7 ] ~ [ linux-4.4.210 ] ~ [ linux-4.3.6 ] ~ [ linux-4.2.8 ] ~ [ linux-4.1.52 ] ~ [ linux-4.0.9 ] ~ [ linux-3.19.8 ] ~ [ linux-3.18.140 ] ~ [ linux-3.17.8 ] ~ [ linux-3.16.81 ] ~ [ linux-3.15.10 ] ~ [ linux-3.14.79 ] ~ [ linux-3.13.11 ] ~ [ linux-3.12.74 ] ~ [ linux-3.11.10 ] ~ [ linux-3.10.108 ] ~ [ linux-3.9.11 ] ~ [ linux-3.8.13 ] ~ [ linux-3.7.10 ] ~ [ linux-3.6.11 ] ~ [ linux-3.5.7 ] ~ [ linux-3.4.113 ] ~ [ linux-3.3.8 ] ~ [ linux-3.2.102 ] ~ [ linux-3.1.10 ] ~ [ linux-3.0.101 ] ~ [ linux-2.6.32.71 ] ~ [ linux-2.6.0 ] ~ [ linux-2.4.37.11 ] ~ [ unix-v6-master ] ~ [ ccs-tools-1.8.5 ] ~ [ policy-sample ] ~
Architecture: ~ [ i386 ] ~ [ alpha ] ~ [ m68k ] ~ [ mips ] ~ [ ppc ] ~ [ sparc ] ~ [ sparc64 ] ~

  1 /*
  2  * DaVinci timer subsystem
  3  *
  4  * Author: Kevin Hilman, MontaVista Software, Inc. <source@mvista.com>
  5  *
  6  * 2007 (c) MontaVista Software, Inc. This file is licensed under
  7  * the terms of the GNU General Public License version 2. This program
  8  * is licensed "as is" without any warranty of any kind, whether express
  9  * or implied.
 10  */
 11 #include <linux/kernel.h>
 12 #include <linux/init.h>
 13 #include <linux/types.h>
 14 #include <linux/interrupt.h>
 15 #include <linux/clocksource.h>
 16 #include <linux/clockchips.h>
 17 #include <linux/io.h>
 18 #include <linux/clk.h>
 19 #include <linux/err.h>
 20 #include <linux/platform_device.h>
 21 
 22 #include <mach/hardware.h>
 23 #include <asm/mach/irq.h>
 24 #include <asm/mach/time.h>
 25 #include <mach/cputype.h>
 26 #include <mach/time.h>
 27 #include "clock.h"
 28 
 29 static struct clock_event_device clockevent_davinci;
 30 static unsigned int davinci_clock_tick_rate;
 31 
 32 /*
 33  * This driver configures the 2 64-bit count-up timers as 4 independent
 34  * 32-bit count-up timers used as follows:
 35  */
 36 
 37 enum {
 38         TID_CLOCKEVENT,
 39         TID_CLOCKSOURCE,
 40 };
 41 
 42 /* Timer register offsets */
 43 #define PID12                   0x0
 44 #define TIM12                   0x10
 45 #define TIM34                   0x14
 46 #define PRD12                   0x18
 47 #define PRD34                   0x1c
 48 #define TCR                     0x20
 49 #define TGCR                    0x24
 50 #define WDTCR                   0x28
 51 
 52 /* Offsets of the 8 compare registers */
 53 #define CMP12_0                 0x60
 54 #define CMP12_1                 0x64
 55 #define CMP12_2                 0x68
 56 #define CMP12_3                 0x6c
 57 #define CMP12_4                 0x70
 58 #define CMP12_5                 0x74
 59 #define CMP12_6                 0x78
 60 #define CMP12_7                 0x7c
 61 
 62 /* Timer register bitfields */
 63 #define TCR_ENAMODE_DISABLE          0x0
 64 #define TCR_ENAMODE_ONESHOT          0x1
 65 #define TCR_ENAMODE_PERIODIC         0x2
 66 #define TCR_ENAMODE_MASK             0x3
 67 
 68 #define TGCR_TIMMODE_SHIFT           2
 69 #define TGCR_TIMMODE_64BIT_GP        0x0
 70 #define TGCR_TIMMODE_32BIT_UNCHAINED 0x1
 71 #define TGCR_TIMMODE_64BIT_WDOG      0x2
 72 #define TGCR_TIMMODE_32BIT_CHAINED   0x3
 73 
 74 #define TGCR_TIM12RS_SHIFT           0
 75 #define TGCR_TIM34RS_SHIFT           1
 76 #define TGCR_RESET                   0x0
 77 #define TGCR_UNRESET                 0x1
 78 #define TGCR_RESET_MASK              0x3
 79 
 80 #define WDTCR_WDEN_SHIFT             14
 81 #define WDTCR_WDEN_DISABLE           0x0
 82 #define WDTCR_WDEN_ENABLE            0x1
 83 #define WDTCR_WDKEY_SHIFT            16
 84 #define WDTCR_WDKEY_SEQ0             0xa5c6
 85 #define WDTCR_WDKEY_SEQ1             0xda7e
 86 
 87 struct timer_s {
 88         char *name;
 89         unsigned int id;
 90         unsigned long period;
 91         unsigned long opts;
 92         unsigned long flags;
 93         void __iomem *base;
 94         unsigned long tim_off;
 95         unsigned long prd_off;
 96         unsigned long enamode_shift;
 97         struct irqaction irqaction;
 98 };
 99 static struct timer_s timers[];
100 
101 /* values for 'opts' field of struct timer_s */
102 #define TIMER_OPTS_DISABLED             0x01
103 #define TIMER_OPTS_ONESHOT              0x02
104 #define TIMER_OPTS_PERIODIC             0x04
105 #define TIMER_OPTS_STATE_MASK           0x07
106 
107 #define TIMER_OPTS_USE_COMPARE          0x80000000
108 #define USING_COMPARE(t)                ((t)->opts & TIMER_OPTS_USE_COMPARE)
109 
110 static char *id_to_name[] = {
111         [T0_BOT]        = "timer0_0",
112         [T0_TOP]        = "timer0_1",
113         [T1_BOT]        = "timer1_0",
114         [T1_TOP]        = "timer1_1",
115 };
116 
117 static int timer32_config(struct timer_s *t)
118 {
119         u32 tcr;
120         struct davinci_soc_info *soc_info = &davinci_soc_info;
121 
122         if (USING_COMPARE(t)) {
123                 struct davinci_timer_instance *dtip =
124                                 soc_info->timer_info->timers;
125                 int event_timer = ID_TO_TIMER(timers[TID_CLOCKEVENT].id);
126 
127                 /*
128                  * Next interrupt should be the current time reg value plus
129                  * the new period (using 32-bit unsigned addition/wrapping
130                  * to 0 on overflow).  This assumes that the clocksource
131                  * is setup to count to 2^32-1 before wrapping around to 0.
132                  */
133                 __raw_writel(__raw_readl(t->base + t->tim_off) + t->period,
134                         t->base + dtip[event_timer].cmp_off);
135         } else {
136                 tcr = __raw_readl(t->base + TCR);
137 
138                 /* disable timer */
139                 tcr &= ~(TCR_ENAMODE_MASK << t->enamode_shift);
140                 __raw_writel(tcr, t->base + TCR);
141 
142                 /* reset counter to zero, set new period */
143                 __raw_writel(0, t->base + t->tim_off);
144                 __raw_writel(t->period, t->base + t->prd_off);
145 
146                 /* Set enable mode */
147                 if (t->opts & TIMER_OPTS_ONESHOT)
148                         tcr |= TCR_ENAMODE_ONESHOT << t->enamode_shift;
149                 else if (t->opts & TIMER_OPTS_PERIODIC)
150                         tcr |= TCR_ENAMODE_PERIODIC << t->enamode_shift;
151 
152                 __raw_writel(tcr, t->base + TCR);
153         }
154         return 0;
155 }
156 
157 static inline u32 timer32_read(struct timer_s *t)
158 {
159         return __raw_readl(t->base + t->tim_off);
160 }
161 
162 static irqreturn_t timer_interrupt(int irq, void *dev_id)
163 {
164         struct clock_event_device *evt = &clockevent_davinci;
165 
166         evt->event_handler(evt);
167         return IRQ_HANDLED;
168 }
169 
170 /* called when 32-bit counter wraps */
171 static irqreturn_t freerun_interrupt(int irq, void *dev_id)
172 {
173         return IRQ_HANDLED;
174 }
175 
176 static struct timer_s timers[] = {
177         [TID_CLOCKEVENT] = {
178                 .name      = "clockevent",
179                 .opts      = TIMER_OPTS_DISABLED,
180                 .irqaction = {
181                         .flags   = IRQF_DISABLED | IRQF_TIMER,
182                         .handler = timer_interrupt,
183                 }
184         },
185         [TID_CLOCKSOURCE] = {
186                 .name       = "free-run counter",
187                 .period     = ~0,
188                 .opts       = TIMER_OPTS_PERIODIC,
189                 .irqaction = {
190                         .flags   = IRQF_DISABLED | IRQF_TIMER,
191                         .handler = freerun_interrupt,
192                 }
193         },
194 };
195 
196 static void __init timer_init(void)
197 {
198         struct davinci_soc_info *soc_info = &davinci_soc_info;
199         struct davinci_timer_instance *dtip = soc_info->timer_info->timers;
200         void __iomem *base[2];
201         int i;
202 
203         /* Global init of each 64-bit timer as a whole */
204         for(i=0; i<2; i++) {
205                 u32 tgcr;
206 
207                 base[i] = ioremap(dtip[i].base, SZ_4K);
208                 if (WARN_ON(!base[i]))
209                         continue;
210 
211                 /* Disabled, Internal clock source */
212                 __raw_writel(0, base[i] + TCR);
213 
214                 /* reset both timers, no pre-scaler for timer34 */
215                 tgcr = 0;
216                 __raw_writel(tgcr, base[i] + TGCR);
217 
218                 /* Set both timers to unchained 32-bit */
219                 tgcr = TGCR_TIMMODE_32BIT_UNCHAINED << TGCR_TIMMODE_SHIFT;
220                 __raw_writel(tgcr, base[i] + TGCR);
221 
222                 /* Unreset timers */
223                 tgcr |= (TGCR_UNRESET << TGCR_TIM12RS_SHIFT) |
224                         (TGCR_UNRESET << TGCR_TIM34RS_SHIFT);
225                 __raw_writel(tgcr, base[i] + TGCR);
226 
227                 /* Init both counters to zero */
228                 __raw_writel(0, base[i] + TIM12);
229                 __raw_writel(0, base[i] + TIM34);
230         }
231 
232         /* Init of each timer as a 32-bit timer */
233         for (i=0; i< ARRAY_SIZE(timers); i++) {
234                 struct timer_s *t = &timers[i];
235                 int timer = ID_TO_TIMER(t->id);
236                 u32 irq;
237 
238                 t->base = base[timer];
239                 if (!t->base)
240                         continue;
241 
242                 if (IS_TIMER_BOT(t->id)) {
243                         t->enamode_shift = 6;
244                         t->tim_off = TIM12;
245                         t->prd_off = PRD12;
246                         irq = dtip[timer].bottom_irq;
247                 } else {
248                         t->enamode_shift = 22;
249                         t->tim_off = TIM34;
250                         t->prd_off = PRD34;
251                         irq = dtip[timer].top_irq;
252                 }
253 
254                 /* Register interrupt */
255                 t->irqaction.name = t->name;
256                 t->irqaction.dev_id = (void *)t;
257 
258                 if (t->irqaction.handler != NULL) {
259                         irq = USING_COMPARE(t) ? dtip[i].cmp_irq : irq;
260                         setup_irq(irq, &t->irqaction);
261                 }
262         }
263 }
264 
265 /*
266  * clocksource
267  */
268 static cycle_t read_cycles(struct clocksource *cs)
269 {
270         struct timer_s *t = &timers[TID_CLOCKSOURCE];
271 
272         return (cycles_t)timer32_read(t);
273 }
274 
275 /*
276  * Kernel assumes that sched_clock can be called early but may not have
277  * things ready yet.
278  */
279 static cycle_t read_dummy(struct clocksource *cs)
280 {
281         return 0;
282 }
283 
284 
285 static struct clocksource clocksource_davinci = {
286         .rating         = 300,
287         .read           = read_dummy,
288         .mask           = CLOCKSOURCE_MASK(32),
289         .flags          = CLOCK_SOURCE_IS_CONTINUOUS,
290 };
291 
292 /*
293  * Overwrite weak default sched_clock with something more precise
294  */
295 unsigned long long notrace sched_clock(void)
296 {
297         const cycle_t cyc = clocksource_davinci.read(&clocksource_davinci);
298 
299         return clocksource_cyc2ns(cyc, clocksource_davinci.mult,
300                                 clocksource_davinci.shift);
301 }
302 
303 /*
304  * clockevent
305  */
306 static int davinci_set_next_event(unsigned long cycles,
307                                   struct clock_event_device *evt)
308 {
309         struct timer_s *t = &timers[TID_CLOCKEVENT];
310 
311         t->period = cycles;
312         timer32_config(t);
313         return 0;
314 }
315 
316 static void davinci_set_mode(enum clock_event_mode mode,
317                              struct clock_event_device *evt)
318 {
319         struct timer_s *t = &timers[TID_CLOCKEVENT];
320 
321         switch (mode) {
322         case CLOCK_EVT_MODE_PERIODIC:
323                 t->period = davinci_clock_tick_rate / (HZ);
324                 t->opts &= ~TIMER_OPTS_STATE_MASK;
325                 t->opts |= TIMER_OPTS_PERIODIC;
326                 timer32_config(t);
327                 break;
328         case CLOCK_EVT_MODE_ONESHOT:
329                 t->opts &= ~TIMER_OPTS_STATE_MASK;
330                 t->opts |= TIMER_OPTS_ONESHOT;
331                 break;
332         case CLOCK_EVT_MODE_UNUSED:
333         case CLOCK_EVT_MODE_SHUTDOWN:
334                 t->opts &= ~TIMER_OPTS_STATE_MASK;
335                 t->opts |= TIMER_OPTS_DISABLED;
336                 break;
337         case CLOCK_EVT_MODE_RESUME:
338                 break;
339         }
340 }
341 
342 static struct clock_event_device clockevent_davinci = {
343         .features       = CLOCK_EVT_FEAT_PERIODIC | CLOCK_EVT_FEAT_ONESHOT,
344         .shift          = 32,
345         .set_next_event = davinci_set_next_event,
346         .set_mode       = davinci_set_mode,
347 };
348 
349 
350 static void __init davinci_timer_init(void)
351 {
352         struct clk *timer_clk;
353         struct davinci_soc_info *soc_info = &davinci_soc_info;
354         unsigned int clockevent_id;
355         unsigned int clocksource_id;
356         static char err[] __initdata = KERN_ERR
357                 "%s: can't register clocksource!\n";
358         int i;
359 
360         clockevent_id = soc_info->timer_info->clockevent_id;
361         clocksource_id = soc_info->timer_info->clocksource_id;
362 
363         timers[TID_CLOCKEVENT].id = clockevent_id;
364         timers[TID_CLOCKSOURCE].id = clocksource_id;
365 
366         /*
367          * If using same timer for both clock events & clocksource,
368          * a compare register must be used to generate an event interrupt.
369          * This is equivalent to a oneshot timer only (not periodic).
370          */
371         if (clockevent_id == clocksource_id) {
372                 struct davinci_timer_instance *dtip =
373                                 soc_info->timer_info->timers;
374                 int event_timer = ID_TO_TIMER(clockevent_id);
375 
376                 /* Only bottom timers can use compare regs */
377                 if (IS_TIMER_TOP(clockevent_id))
378                         pr_warning("davinci_timer_init: Invalid use"
379                                 " of system timers.  Results unpredictable.\n");
380                 else if ((dtip[event_timer].cmp_off == 0)
381                                 || (dtip[event_timer].cmp_irq == 0))
382                         pr_warning("davinci_timer_init:  Invalid timer instance"
383                                 " setup.  Results unpredictable.\n");
384                 else {
385                         timers[TID_CLOCKEVENT].opts |= TIMER_OPTS_USE_COMPARE;
386                         clockevent_davinci.features = CLOCK_EVT_FEAT_ONESHOT;
387                 }
388         }
389 
390         timer_clk = clk_get(NULL, "timer0");
391         BUG_ON(IS_ERR(timer_clk));
392         clk_enable(timer_clk);
393 
394         /* init timer hw */
395         timer_init();
396 
397         davinci_clock_tick_rate = clk_get_rate(timer_clk);
398 
399         /* setup clocksource */
400         clocksource_davinci.read = read_cycles;
401         clocksource_davinci.name = id_to_name[clocksource_id];
402         if (clocksource_register_hz(&clocksource_davinci,
403                                     davinci_clock_tick_rate))
404                 printk(err, clocksource_davinci.name);
405 
406         /* setup clockevent */
407         clockevent_davinci.name = id_to_name[timers[TID_CLOCKEVENT].id];
408         clockevent_davinci.mult = div_sc(davinci_clock_tick_rate, NSEC_PER_SEC,
409                                          clockevent_davinci.shift);
410         clockevent_davinci.max_delta_ns =
411                 clockevent_delta2ns(0xfffffffe, &clockevent_davinci);
412         clockevent_davinci.min_delta_ns = 50000; /* 50 usec */
413 
414         clockevent_davinci.cpumask = cpumask_of(0);
415         clockevents_register_device(&clockevent_davinci);
416 
417         for (i=0; i< ARRAY_SIZE(timers); i++)
418                 timer32_config(&timers[i]);
419 }
420 
421 struct sys_timer davinci_timer = {
422         .init   = davinci_timer_init,
423 };
424 
425 
426 /* reset board using watchdog timer */
427 void davinci_watchdog_reset(struct platform_device *pdev)
428 {
429         u32 tgcr, wdtcr;
430         void __iomem *base;
431         struct clk *wd_clk;
432 
433         base = ioremap(pdev->resource[0].start, SZ_4K);
434         if (WARN_ON(!base))
435                 return;
436 
437         wd_clk = clk_get(&pdev->dev, NULL);
438         if (WARN_ON(IS_ERR(wd_clk)))
439                 return;
440         clk_enable(wd_clk);
441 
442         /* disable, internal clock source */
443         __raw_writel(0, base + TCR);
444 
445         /* reset timer, set mode to 64-bit watchdog, and unreset */
446         tgcr = 0;
447         __raw_writel(tgcr, base + TGCR);
448         tgcr = TGCR_TIMMODE_64BIT_WDOG << TGCR_TIMMODE_SHIFT;
449         tgcr |= (TGCR_UNRESET << TGCR_TIM12RS_SHIFT) |
450                 (TGCR_UNRESET << TGCR_TIM34RS_SHIFT);
451         __raw_writel(tgcr, base + TGCR);
452 
453         /* clear counter and period regs */
454         __raw_writel(0, base + TIM12);
455         __raw_writel(0, base + TIM34);
456         __raw_writel(0, base + PRD12);
457         __raw_writel(0, base + PRD34);
458 
459         /* put watchdog in pre-active state */
460         wdtcr = __raw_readl(base + WDTCR);
461         wdtcr = (WDTCR_WDKEY_SEQ0 << WDTCR_WDKEY_SHIFT) |
462                 (WDTCR_WDEN_ENABLE << WDTCR_WDEN_SHIFT);
463         __raw_writel(wdtcr, base + WDTCR);
464 
465         /* put watchdog in active state */
466         wdtcr = (WDTCR_WDKEY_SEQ1 << WDTCR_WDKEY_SHIFT) |
467                 (WDTCR_WDEN_ENABLE << WDTCR_WDEN_SHIFT);
468         __raw_writel(wdtcr, base + WDTCR);
469 
470         /* write an invalid value to the WDKEY field to trigger
471          * a watchdog reset */
472         wdtcr = 0x00004000;
473         __raw_writel(wdtcr, base + WDTCR);
474 }
475 

~ [ source navigation ] ~ [ diff markup ] ~ [ identifier search ] ~

kernel.org | git.kernel.org | LWN.net | Project Home | Wiki (Japanese) | Wiki (English) | SVN repository | Mail admin

Linux® is a registered trademark of Linus Torvalds in the United States and other countries.
TOMOYO® is a registered trademark of NTT DATA CORPORATION.

osdn.jp