/* * DaVinci timer subsystem * * Author: Kevin Hilman, MontaVista Software, Inc. * * 2007 (c) MontaVista Software, Inc. This file is licensed under * the terms of the GNU General Public License version 2. This program * is licensed "as is" without any warranty of any kind, whether express * or implied. */ #include #include #include #include #include #include /* Timer register offsets */ #define PID12 0x0 #define TIM12 0x10 #define TIM34 0x14 #define PRD12 0x18 #define PRD34 0x1c #define TCR 0x20 #define TGCR 0x24 #define WDTCR 0x28 /* Timer register bitfields */ #define TCR_ENAMODE_DISABLE 0x0 #define TCR_ENAMODE_ONESHOT 0x1 #define TCR_ENAMODE_PERIODIC 0x2 #define TCR_ENAMODE_MASK 0x3 #define TGCR_TIMMODE_SHIFT 2 #define TGCR_TIMMODE_64BIT_GP 0x0 #define TGCR_TIMMODE_32BIT_UNCHAINED 0x1 #define TGCR_TIMMODE_64BIT_WDOG 0x2 #define TGCR_TIMMODE_32BIT_CHAINED 0x3 #define TGCR_TIM12RS_SHIFT 0 #define TGCR_TIM34RS_SHIFT 1 #define TGCR_RESET 0x0 #define TGCR_UNRESET 0x1 #define TGCR_RESET_MASK 0x3 #define WDTCR_WDEN_SHIFT 14 #define WDTCR_WDEN_DISABLE 0x0 #define WDTCR_WDEN_ENABLE 0x1 #define WDTCR_WDKEY_SHIFT 16 #define WDTCR_WDKEY_SEQ0 0xa5c6 #define WDTCR_WDKEY_SEQ1 0xda7e #define DAVINCI_TIMER_CLOCK 24000000 struct timer_s { void __iomem *base; unsigned long tim_off; unsigned long prd_off; unsigned long enamode_shift; }; static struct timer_s timers[] = { { .base = IOMEM(DAVINCI_TIMER0_BASE), .enamode_shift = 6, .tim_off = TIM12, .prd_off = PRD12, }, { .base = IOMEM(DAVINCI_TIMER0_BASE), .enamode_shift = 22, .tim_off = TIM34, .prd_off = PRD34, }, { .base = IOMEM(DAVINCI_TIMER1_BASE), .enamode_shift = 6, .tim_off = TIM12, .prd_off = PRD12, }, { .base = IOMEM(DAVINCI_TIMER1_BASE), .enamode_shift = 22, .tim_off = TIM34, .prd_off = PRD34, }, }; static struct timer_s *t = &timers[0]; static uint64_t davinci_cs_read(void) { return (uint64_t)__raw_readl(t->base + t->tim_off); } static struct clocksource davinci_cs = { .read = davinci_cs_read, .mask = CLOCKSOURCE_MASK(32), }; static int timer32_config(struct timer_s *t) { u32 tcr; tcr = __raw_readl(t->base + TCR); /* disable timer */ tcr &= ~(TCR_ENAMODE_MASK << t->enamode_shift); __raw_writel(tcr, t->base + TCR); /* reset counter to zero, set new period */ __raw_writel(0, t->base + t->tim_off); __raw_writel(0xffffffff, t->base + t->prd_off); /* Set enable mode for periodic timer */ tcr |= TCR_ENAMODE_PERIODIC << t->enamode_shift; __raw_writel(tcr, t->base + TCR); return 0; } /* Global init of 64-bit timer as a whole */ static void __init timer_init(void __iomem *base) { u32 tgcr; /* Disabled, Internal clock source */ __raw_writel(0, base + TCR); /* reset both timers, no pre-scaler for timer34 */ tgcr = 0; __raw_writel(tgcr, base + TGCR); /* Set both timers to unchained 32-bit */ tgcr = TGCR_TIMMODE_32BIT_UNCHAINED << TGCR_TIMMODE_SHIFT; __raw_writel(tgcr, base + TGCR); /* Unreset timers */ tgcr |= (TGCR_UNRESET << TGCR_TIM12RS_SHIFT) | (TGCR_UNRESET << TGCR_TIM34RS_SHIFT); __raw_writel(tgcr, base + TGCR); /* Init both counters to zero */ __raw_writel(0, base + TIM12); __raw_writel(0, base + TIM34); } static int clocksource_init(void) { clocks_calc_mult_shift(&davinci_cs.mult, &davinci_cs.shift, DAVINCI_TIMER_CLOCK, NSEC_PER_SEC, 10); init_clock(&davinci_cs); timer_init(IOMEM(DAVINCI_TIMER0_BASE)); timer_init(IOMEM(DAVINCI_TIMER1_BASE)); timer32_config(t); return 0; } core_initcall(clocksource_init); /* reset board using watchdog timer */ static void __noreturn davinci_restart_soc(struct restart_handler *rst) { u32 tgcr, wdtcr; void __iomem *base; base = IOMEM(DAVINCI_WDOG_BASE); /* disable, internal clock source */ __raw_writel(0, base + TCR); /* reset timer, set mode to 64-bit watchdog, and unreset */ tgcr = 0; __raw_writel(tgcr, base + TGCR); tgcr = TGCR_TIMMODE_64BIT_WDOG << TGCR_TIMMODE_SHIFT; tgcr |= (TGCR_UNRESET << TGCR_TIM12RS_SHIFT) | (TGCR_UNRESET << TGCR_TIM34RS_SHIFT); __raw_writel(tgcr, base + TGCR); /* clear counter and period regs */ __raw_writel(0, base + TIM12); __raw_writel(0, base + TIM34); __raw_writel(0, base + PRD12); __raw_writel(0, base + PRD34); /* put watchdog in pre-active state */ wdtcr = __raw_readl(base + WDTCR); wdtcr = (WDTCR_WDKEY_SEQ0 << WDTCR_WDKEY_SHIFT) | (WDTCR_WDEN_ENABLE << WDTCR_WDEN_SHIFT); __raw_writel(wdtcr, base + WDTCR); /* put watchdog in active state */ wdtcr = (WDTCR_WDKEY_SEQ1 << WDTCR_WDKEY_SHIFT) | (WDTCR_WDEN_ENABLE << WDTCR_WDEN_SHIFT); __raw_writel(wdtcr, base + WDTCR); /* write an invalid value to the WDKEY field to trigger * a watchdog reset */ wdtcr = 0x00004000; __raw_writel(wdtcr, base + WDTCR); hang(); } static int restart_register_feature(void) { restart_handler_register_fn(davinci_restart_soc); return 0; } coredevice_initcall(restart_register_feature);