1 /* 2 * (C) Copyright 2002 3 * Sysgo Real-Time Solutions, GmbH <www.elinos.com> 4 * Marius Groeger <mgroeger@sysgo.de> 5 * 6 * (C) Copyright 2002 7 * Sysgo Real-Time Solutions, GmbH <www.elinos.com> 8 * Alex Zuepke <azu@sysgo.de> 9 * 10 * (C) Copyright 2002 11 * Gary Jennejohn, DENX Software Engineering, <gj@denx.de> 12 * 13 * (C) Copyright 2009 14 * Ilya Yanok, Emcraft Systems Ltd, <yanok@emcraft.com> 15 * 16 * SPDX-License-Identifier: GPL-2.0+ 17 */ 18 19 #include <common.h> 20 #include <div64.h> 21 #include <asm/io.h> 22 #include <asm/arch/imx-regs.h> 23 24 /* General purpose timers bitfields */ 25 #define GPTCR_SWR (1 << 15) /* Software reset */ 26 #define GPTCR_FRR (1 << 8) /* Freerun / restart */ 27 #define GPTCR_CLKSOURCE_32 (4 << 1) /* Clock source */ 28 #define GPTCR_TEN 1 /* Timer enable */ 29 30 DECLARE_GLOBAL_DATA_PTR; 31 32 #define timestamp (gd->arch.tbl) 33 #define lastinc (gd->arch.lastinc) 34 35 /* 36 * "time" is measured in 1 / CONFIG_SYS_HZ seconds, 37 * "tick" is internal timer period 38 */ 39 #ifdef CONFIG_MX27_TIMER_HIGH_PRECISION 40 /* ~0.4% error - measured with stop-watch on 100s boot-delay */ 41 static inline unsigned long long tick_to_time(unsigned long long tick) 42 { 43 tick *= CONFIG_SYS_HZ; 44 do_div(tick, CONFIG_MX27_CLK32); 45 return tick; 46 } 47 48 static inline unsigned long long time_to_tick(unsigned long long time) 49 { 50 time *= CONFIG_MX27_CLK32; 51 do_div(time, CONFIG_SYS_HZ); 52 return time; 53 } 54 55 static inline unsigned long long us_to_tick(unsigned long long us) 56 { 57 us = us * CONFIG_MX27_CLK32 + 999999; 58 do_div(us, 1000000); 59 return us; 60 } 61 #else 62 /* ~2% error */ 63 #define TICK_PER_TIME ((CONFIG_MX27_CLK32 + CONFIG_SYS_HZ / 2) / \ 64 CONFIG_SYS_HZ) 65 #define US_PER_TICK (1000000 / CONFIG_MX27_CLK32) 66 67 static inline unsigned long long tick_to_time(unsigned long long tick) 68 { 69 do_div(tick, TICK_PER_TIME); 70 return tick; 71 } 72 73 static inline unsigned long long time_to_tick(unsigned long long time) 74 { 75 return time * TICK_PER_TIME; 76 } 77 78 static inline unsigned long long us_to_tick(unsigned long long us) 79 { 80 us += US_PER_TICK - 1; 81 do_div(us, US_PER_TICK); 82 return us; 83 } 84 #endif 85 86 /* nothing really to do with interrupts, just starts up a counter. */ 87 /* The 32768Hz 32-bit timer overruns in 131072 seconds */ 88 int timer_init(void) 89 { 90 int i; 91 struct gpt_regs *regs = (struct gpt_regs *)IMX_TIM1_BASE; 92 struct pll_regs *pll = (struct pll_regs *)IMX_PLL_BASE; 93 94 /* setup GP Timer 1 */ 95 writel(GPTCR_SWR, ®s->gpt_tctl); 96 97 writel(readl(&pll->pccr0) | PCCR0_GPT1_EN, &pll->pccr0); 98 writel(readl(&pll->pccr1) | PCCR1_PERCLK1_EN, &pll->pccr1); 99 100 for (i = 0; i < 100; i++) 101 writel(0, ®s->gpt_tctl); /* We have no udelay by now */ 102 writel(0, ®s->gpt_tprer); /* 32Khz */ 103 /* Freerun Mode, PERCLK1 input */ 104 writel(readl(®s->gpt_tctl) | GPTCR_CLKSOURCE_32 | GPTCR_FRR, 105 ®s->gpt_tctl); 106 writel(readl(®s->gpt_tctl) | GPTCR_TEN, ®s->gpt_tctl); 107 108 return 0; 109 } 110 111 unsigned long long get_ticks(void) 112 { 113 struct gpt_regs *regs = (struct gpt_regs *)IMX_TIM1_BASE; 114 ulong now = readl(®s->gpt_tcn); /* current tick value */ 115 116 if (now >= lastinc) { 117 /* 118 * normal mode (non roll) 119 * move stamp forward with absolut diff ticks 120 */ 121 timestamp += (now - lastinc); 122 } else { 123 /* we have rollover of incrementer */ 124 timestamp += (0xFFFFFFFF - lastinc) + now; 125 } 126 lastinc = now; 127 return timestamp; 128 } 129 130 ulong get_timer_masked(void) 131 { 132 /* 133 * get_ticks() returns a long long (64 bit), it wraps in 134 * 2^64 / CONFIG_MX27_CLK32 = 2^64 / 2^15 = 2^49 ~ 5 * 10^14 (s) ~ 135 * 5 * 10^9 days... and get_ticks() * CONFIG_SYS_HZ wraps in 136 * 5 * 10^6 days - long enough. 137 */ 138 return tick_to_time(get_ticks()); 139 } 140 141 ulong get_timer(ulong base) 142 { 143 return get_timer_masked() - base; 144 } 145 146 /* delay x useconds AND preserve advance timstamp value */ 147 void __udelay(unsigned long usec) 148 { 149 unsigned long long tmp; 150 ulong tmo; 151 152 tmo = us_to_tick(usec); 153 tmp = get_ticks() + tmo; /* get current timestamp */ 154 155 while (get_ticks() < tmp) /* loop till event */ 156 /*NOP*/; 157 } 158 159 ulong get_tbclk(void) 160 { 161 return CONFIG_MX27_CLK32; 162 } 163