1 | /** |
---|
2 | * @file |
---|
3 | * |
---|
4 | * @ingroup arm_beagle |
---|
5 | * |
---|
6 | * @brief Clock driver configuration. |
---|
7 | */ |
---|
8 | |
---|
9 | /* |
---|
10 | * Copyright (c) 2014 Ben Gras <beng@shrike-systems.com>. |
---|
11 | * |
---|
12 | * The license and distribution terms for this file may be |
---|
13 | * found in the file LICENSE in this distribution or at |
---|
14 | * http://www.rtems.org/license/LICENSE. |
---|
15 | */ |
---|
16 | |
---|
17 | #include <rtems.h> |
---|
18 | #include <rtems/timecounter.h> |
---|
19 | #include <bsp.h> |
---|
20 | |
---|
21 | #include <libcpu/omap_timer.h> |
---|
22 | |
---|
23 | static struct timecounter beagle_clock_tc; |
---|
24 | |
---|
25 | static omap_timer_registers_t regs_v1 = { |
---|
26 | .TIDR = OMAP3_TIMER_TIDR, |
---|
27 | .TIOCP_CFG = OMAP3_TIMER_TIOCP_CFG, |
---|
28 | .TISTAT = OMAP3_TIMER_TISTAT, |
---|
29 | .TISR = OMAP3_TIMER_TISR, |
---|
30 | .TIER = OMAP3_TIMER_TIER, |
---|
31 | .TWER = OMAP3_TIMER_TWER, |
---|
32 | .TCLR = OMAP3_TIMER_TCLR, |
---|
33 | .TCRR = OMAP3_TIMER_TCRR, |
---|
34 | .TLDR = OMAP3_TIMER_TLDR, |
---|
35 | .TTGR = OMAP3_TIMER_TTGR, |
---|
36 | .TWPS = OMAP3_TIMER_TWPS, |
---|
37 | .TMAR = OMAP3_TIMER_TMAR, |
---|
38 | .TCAR1 = OMAP3_TIMER_TCAR1, |
---|
39 | .TSICR = OMAP3_TIMER_TSICR, |
---|
40 | .TCAR2 = OMAP3_TIMER_TCAR2, |
---|
41 | .TPIR = OMAP3_TIMER_TPIR, |
---|
42 | .TNIR = OMAP3_TIMER_TNIR, |
---|
43 | .TCVR = OMAP3_TIMER_TCVR, |
---|
44 | .TOCR = OMAP3_TIMER_TOCR, |
---|
45 | .TOWR = OMAP3_TIMER_TOWR, |
---|
46 | }; |
---|
47 | |
---|
48 | #if IS_AM335X |
---|
49 | /* AM335X has a different ip block for the non 1ms timers */ |
---|
50 | static omap_timer_registers_t regs_v2 = { |
---|
51 | .TIDR = AM335X_TIMER_TIDR, |
---|
52 | .TIOCP_CFG = AM335X_TIMER_TIOCP_CFG, |
---|
53 | .TISTAT = AM335X_TIMER_IRQSTATUS_RAW, |
---|
54 | .TISR = AM335X_TIMER_IRQSTATUS, |
---|
55 | .TIER = AM335X_TIMER_IRQENABLE_SET, |
---|
56 | .TWER = AM335X_TIMER_IRQWAKEEN, |
---|
57 | .TCLR = AM335X_TIMER_TCLR, |
---|
58 | .TCRR = AM335X_TIMER_TCRR, |
---|
59 | .TLDR = AM335X_TIMER_TLDR, |
---|
60 | .TTGR = AM335X_TIMER_TTGR, |
---|
61 | .TWPS = AM335X_TIMER_TWPS, |
---|
62 | .TMAR = AM335X_TIMER_TMAR, |
---|
63 | .TCAR1 = AM335X_TIMER_TCAR1, |
---|
64 | .TSICR = AM335X_TIMER_TSICR, |
---|
65 | .TCAR2 = AM335X_TIMER_TCAR2, |
---|
66 | .TPIR = -1, /* UNDEF */ |
---|
67 | .TNIR = -1, /* UNDEF */ |
---|
68 | .TCVR = -1, /* UNDEF */ |
---|
69 | .TOCR = -1, /* UNDEF */ |
---|
70 | .TOWR = -1 /* UNDEF */ |
---|
71 | }; |
---|
72 | #endif |
---|
73 | |
---|
74 | /* which timers are in use? target-dependent. |
---|
75 | * initialize at compile time. |
---|
76 | */ |
---|
77 | |
---|
78 | #if IS_DM3730 |
---|
79 | |
---|
80 | static omap_timer_t dm37xx_timer = { |
---|
81 | .base = OMAP3_GPTIMER1_BASE, |
---|
82 | .irq_nr = OMAP3_GPT1_IRQ, |
---|
83 | .regs = ®s_v1 |
---|
84 | }; |
---|
85 | |
---|
86 | /* free running timer */ |
---|
87 | static omap_timer_t dm37xx_fr_timer = { |
---|
88 | .base = OMAP3_GPTIMER10_BASE, |
---|
89 | .irq_nr = OMAP3_GPT10_IRQ, |
---|
90 | .regs = ®s_v1 |
---|
91 | }; |
---|
92 | |
---|
93 | static struct omap_timer *fr_timer = &dm37xx_fr_timer; |
---|
94 | static struct omap_timer *timer = &dm37xx_timer; |
---|
95 | |
---|
96 | #endif |
---|
97 | |
---|
98 | #if IS_AM335X |
---|
99 | |
---|
100 | /* normal timer */ |
---|
101 | static omap_timer_t am335x_timer = { |
---|
102 | .base = AM335X_DMTIMER1_1MS_BASE, |
---|
103 | .irq_nr = AM335X_INT_TINT1_1MS, |
---|
104 | .regs = ®s_v1 |
---|
105 | }; |
---|
106 | |
---|
107 | /* free running timer */ |
---|
108 | static omap_timer_t am335x_fr_timer = { |
---|
109 | .base = AM335X_DMTIMER7_BASE, |
---|
110 | .irq_nr = AM335X_INT_TINT7, |
---|
111 | .regs = ®s_v2 |
---|
112 | }; |
---|
113 | |
---|
114 | static struct omap_timer *fr_timer = &am335x_fr_timer; |
---|
115 | static struct omap_timer *timer = &am335x_timer; |
---|
116 | |
---|
117 | #endif |
---|
118 | |
---|
119 | #if IS_AM335X |
---|
120 | #define FRCLOCK_HZ (16*1500000) |
---|
121 | #endif |
---|
122 | |
---|
123 | #if IS_DM3730 |
---|
124 | #define FRCLOCK_HZ (8*1625000) |
---|
125 | #endif |
---|
126 | |
---|
127 | #ifndef FRCLOCK_HZ |
---|
128 | #error expected IS_AM335X or IS_DM3730 to be defined. |
---|
129 | #endif |
---|
130 | |
---|
131 | static void |
---|
132 | omap3_frclock_init(void) |
---|
133 | { |
---|
134 | uint32_t tisr; |
---|
135 | |
---|
136 | #if IS_DM3730 |
---|
137 | /* Stop timer */ |
---|
138 | mmio_clear(fr_timer->base + fr_timer->regs->TCLR, |
---|
139 | OMAP3_TCLR_ST); |
---|
140 | |
---|
141 | /* Use functional clock source for GPTIMER10 */ |
---|
142 | mmio_set(OMAP3_CM_CLKSEL_CORE, OMAP3_CLKSEL_GPT10); |
---|
143 | #endif |
---|
144 | |
---|
145 | #if IS_AM335X |
---|
146 | /* Disable the module and wait for the module to be disabled */ |
---|
147 | set32(CM_PER_TIMER7_CLKCTRL, CM_MODULEMODE_MASK, |
---|
148 | CM_MODULEMODE_DISABLED); |
---|
149 | while ((mmio_read(CM_PER_TIMER7_CLKCTRL) & CM_CLKCTRL_IDLEST) |
---|
150 | != CM_CLKCTRL_IDLEST_DISABLE); |
---|
151 | |
---|
152 | set32(CLKSEL_TIMER7_CLK, CLKSEL_TIMER7_CLK_SEL_MASK, |
---|
153 | CLKSEL_TIMER7_CLK_SEL_SEL2); |
---|
154 | while ((read32(CLKSEL_TIMER7_CLK) & CLKSEL_TIMER7_CLK_SEL_MASK) |
---|
155 | != CLKSEL_TIMER7_CLK_SEL_SEL2); |
---|
156 | |
---|
157 | /* enable the module and wait for the module to be ready */ |
---|
158 | set32(CM_PER_TIMER7_CLKCTRL, CM_MODULEMODE_MASK, |
---|
159 | CM_MODULEMODE_ENABLE); |
---|
160 | while ((mmio_read(CM_PER_TIMER7_CLKCTRL) & CM_CLKCTRL_IDLEST) |
---|
161 | != CM_CLKCTRL_IDLEST_FUNC); |
---|
162 | |
---|
163 | /* Stop timer */ |
---|
164 | mmio_clear(fr_timer->base + fr_timer->regs->TCLR, |
---|
165 | OMAP3_TCLR_ST); |
---|
166 | #endif |
---|
167 | |
---|
168 | /* Start and auto-reload at 0 */ |
---|
169 | mmio_write(fr_timer->base + fr_timer->regs->TLDR, 0x0); |
---|
170 | mmio_write(fr_timer->base + fr_timer->regs->TCRR, 0x0); |
---|
171 | |
---|
172 | /* Set up overflow interrupt */ |
---|
173 | tisr = OMAP3_TISR_MAT_IT_FLAG | OMAP3_TISR_OVF_IT_FLAG | |
---|
174 | OMAP3_TISR_TCAR_IT_FLAG; |
---|
175 | /* Clear interrupt status */ |
---|
176 | mmio_write(fr_timer->base + fr_timer->regs->TISR, tisr); |
---|
177 | mmio_write(fr_timer->base + fr_timer->regs->TIER, |
---|
178 | OMAP3_TIER_OVF_IT_ENA); |
---|
179 | |
---|
180 | /* Start timer, without prescaler */ |
---|
181 | mmio_set(fr_timer->base + fr_timer->regs->TCLR, |
---|
182 | OMAP3_TCLR_OVF_TRG | OMAP3_TCLR_AR | OMAP3_TCLR_ST); |
---|
183 | } |
---|
184 | |
---|
185 | static uint32_t |
---|
186 | beagle_clock_get_timecount(struct timecounter *tc) |
---|
187 | { |
---|
188 | return mmio_read(fr_timer->base + fr_timer->regs->TCRR); |
---|
189 | } |
---|
190 | |
---|
191 | static void |
---|
192 | beagle_clock_initialize(void) |
---|
193 | { |
---|
194 | uint32_t freq = 1000000UL/rtems_configuration_get_microseconds_per_tick(); |
---|
195 | |
---|
196 | /* we only support 1ms resolution */ |
---|
197 | uint32_t tisr; |
---|
198 | #if IS_DM3730 |
---|
199 | /* Stop timer */ |
---|
200 | mmio_clear(timer->base + timer->regs->TCLR, OMAP3_TCLR_ST); |
---|
201 | |
---|
202 | /* Use 32 KHz clock source for GPTIMER1 */ |
---|
203 | mmio_clear(OMAP3_CM_CLKSEL_WKUP, OMAP3_CLKSEL_GPT1); |
---|
204 | #endif |
---|
205 | |
---|
206 | #if IS_AM335X |
---|
207 | /* disable the module and wait for the module to be disabled */ |
---|
208 | set32(CM_WKUP_TIMER1_CLKCTRL, CM_MODULEMODE_MASK, |
---|
209 | CM_MODULEMODE_DISABLED); |
---|
210 | while ((mmio_read(CM_WKUP_TIMER1_CLKCTRL) & CM_CLKCTRL_IDLEST) |
---|
211 | != CM_CLKCTRL_IDLEST_DISABLE); |
---|
212 | |
---|
213 | set32(CLKSEL_TIMER1MS_CLK, CLKSEL_TIMER1MS_CLK_SEL_MASK, |
---|
214 | CLKSEL_TIMER1MS_CLK_SEL_SEL2); |
---|
215 | while ((read32(CLKSEL_TIMER1MS_CLK) & |
---|
216 | CLKSEL_TIMER1MS_CLK_SEL_MASK) != |
---|
217 | CLKSEL_TIMER1MS_CLK_SEL_SEL2); |
---|
218 | |
---|
219 | /* enable the module and wait for the module to be ready */ |
---|
220 | set32(CM_WKUP_TIMER1_CLKCTRL, CM_MODULEMODE_MASK, |
---|
221 | CM_MODULEMODE_ENABLE); |
---|
222 | while ((mmio_read(CM_WKUP_TIMER1_CLKCTRL) & CM_CLKCTRL_IDLEST) |
---|
223 | != CM_CLKCTRL_IDLEST_FUNC); |
---|
224 | |
---|
225 | /* Stop timer */ |
---|
226 | mmio_clear(timer->base + timer->regs->TCLR, OMAP3_TCLR_ST); |
---|
227 | #endif |
---|
228 | |
---|
229 | /* Use 1-ms tick mode for GPTIMER1 TRM 16.2.4.2.1 */ |
---|
230 | mmio_write(timer->base + timer->regs->TPIR, 232000); |
---|
231 | mmio_write(timer->base + timer->regs->TNIR, -768000); |
---|
232 | mmio_write(timer->base + timer->regs->TLDR, |
---|
233 | 0xffffffff - (32768 / freq) + 1); |
---|
234 | mmio_write(timer->base + timer->regs->TCRR, |
---|
235 | 0xffffffff - (32768 / freq) + 1); |
---|
236 | |
---|
237 | /* Set up overflow interrupt */ |
---|
238 | tisr = OMAP3_TISR_MAT_IT_FLAG | OMAP3_TISR_OVF_IT_FLAG | |
---|
239 | OMAP3_TISR_TCAR_IT_FLAG; |
---|
240 | /* Clear interrupt status */ |
---|
241 | mmio_write(timer->base + timer->regs->TISR, tisr); |
---|
242 | mmio_write(timer->base + timer->regs->TIER, OMAP3_TIER_OVF_IT_ENA); |
---|
243 | |
---|
244 | /* Start timer */ |
---|
245 | mmio_set(timer->base + timer->regs->TCLR, |
---|
246 | OMAP3_TCLR_OVF_TRG | OMAP3_TCLR_AR | OMAP3_TCLR_ST); |
---|
247 | /* also initilize the free runnning timer */ |
---|
248 | omap3_frclock_init(); |
---|
249 | |
---|
250 | #if IS_AM335X |
---|
251 | /* Disable AM335X watchdog */ |
---|
252 | mmio_write(AM335X_WDT_BASE+AM335X_WDT_WSPR, 0xAAAA); |
---|
253 | while(mmio_read(AM335X_WDT_BASE+AM335X_WDT_WWPS) != 0) ; |
---|
254 | mmio_write(AM335X_WDT_BASE+AM335X_WDT_WSPR, 0x5555); |
---|
255 | while(mmio_read(AM335X_WDT_BASE+AM335X_WDT_WWPS) != 0) ; |
---|
256 | #endif |
---|
257 | |
---|
258 | /* Install timecounter */ \ |
---|
259 | beagle_clock_tc.tc_get_timecount = beagle_clock_get_timecount; |
---|
260 | beagle_clock_tc.tc_counter_mask = 0xffffffff; |
---|
261 | beagle_clock_tc.tc_frequency = FRCLOCK_HZ; |
---|
262 | beagle_clock_tc.tc_quality = RTEMS_TIMECOUNTER_QUALITY_CLOCK_DRIVER; |
---|
263 | rtems_timecounter_install(&beagle_clock_tc); |
---|
264 | } |
---|
265 | |
---|
266 | static void beagle_clock_at_tick(void) |
---|
267 | { |
---|
268 | mmio_write(timer->base + timer->regs->TISR, |
---|
269 | OMAP3_TISR_MAT_IT_FLAG | OMAP3_TISR_OVF_IT_FLAG | |
---|
270 | OMAP3_TISR_TCAR_IT_FLAG); |
---|
271 | } |
---|
272 | |
---|
273 | static rtems_interrupt_handler clock_isr = NULL; |
---|
274 | |
---|
275 | static void beagle_clock_handler_install(rtems_interrupt_handler isr) |
---|
276 | { |
---|
277 | rtems_status_code sc = RTEMS_SUCCESSFUL; |
---|
278 | |
---|
279 | sc = rtems_interrupt_handler_install( |
---|
280 | timer->irq_nr, |
---|
281 | "Clock", |
---|
282 | RTEMS_INTERRUPT_UNIQUE, |
---|
283 | isr, |
---|
284 | NULL |
---|
285 | ); |
---|
286 | |
---|
287 | if (sc != RTEMS_SUCCESSFUL) { |
---|
288 | rtems_fatal_error_occurred(0xdeadbeef); |
---|
289 | } |
---|
290 | clock_isr = isr; |
---|
291 | } |
---|
292 | |
---|
293 | static void beagle_clock_cleanup(void) |
---|
294 | { |
---|
295 | rtems_status_code sc = RTEMS_SUCCESSFUL; |
---|
296 | |
---|
297 | /* Disable timer */ |
---|
298 | mmio_clear(timer->base + timer->regs->TCLR, OMAP3_TCLR_ST); |
---|
299 | |
---|
300 | /* Remove interrupt handler */ |
---|
301 | sc = rtems_interrupt_handler_remove( |
---|
302 | timer->irq_nr, |
---|
303 | clock_isr, |
---|
304 | NULL |
---|
305 | ); |
---|
306 | if (sc != RTEMS_SUCCESSFUL) { |
---|
307 | rtems_fatal_error_occurred(0xdeadbeef); |
---|
308 | } |
---|
309 | clock_isr = NULL; |
---|
310 | |
---|
311 | /* stop frclock */ |
---|
312 | mmio_clear(fr_timer->base + fr_timer->regs->TCLR, OMAP3_TCLR_ST); |
---|
313 | } |
---|
314 | |
---|
315 | #define Clock_driver_support_at_tick() beagle_clock_at_tick() |
---|
316 | #define Clock_driver_support_initialize_hardware() beagle_clock_initialize() |
---|
317 | #define Clock_driver_support_install_isr(isr, old_isr) \ |
---|
318 | do { \ |
---|
319 | beagle_clock_handler_install(isr); \ |
---|
320 | old_isr = NULL; \ |
---|
321 | } while (0) |
---|
322 | |
---|
323 | #define Clock_driver_support_shutdown_hardware() beagle_clock_cleanup() |
---|
324 | |
---|
325 | /* Include shared source clock driver code */ |
---|
326 | #include "../../shared/clockdrv_shell.h" |
---|