source: rtems/c/src/lib/libbsp/arm/beagle/clock.c @ 0afac6a

4.115
Last change on this file since 0afac6a was 75acd9e, checked in by Alexander Krutwig <alexander.krutwig@…>, on 04/01/15 at 13:33:25

bsps: Convert clock drivers to use a timecounter

Update #2271.

  • Property mode set to 100644
File size: 8.6 KB
Line 
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
23static struct timecounter beagle_clock_tc;
24
25static 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 */
50static 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
80static omap_timer_t dm37xx_timer = {
81  .base = OMAP3_GPTIMER1_BASE,
82  .irq_nr = OMAP3_GPT1_IRQ,
83  .regs = &regs_v1
84};
85
86/* free running timer */
87static omap_timer_t dm37xx_fr_timer = {
88  .base = OMAP3_GPTIMER10_BASE,
89  .irq_nr = OMAP3_GPT10_IRQ,
90  .regs = &regs_v1
91};
92
93static struct omap_timer *fr_timer = &dm37xx_fr_timer;
94static struct omap_timer *timer = &dm37xx_timer;
95
96#endif
97
98#if IS_AM335X
99
100/* normal timer */
101static omap_timer_t am335x_timer = {
102  .base = AM335X_DMTIMER1_1MS_BASE,
103  .irq_nr = AM335X_INT_TINT1_1MS,
104  .regs = &regs_v1
105};
106
107/* free running timer */
108static omap_timer_t am335x_fr_timer = {
109  .base = AM335X_DMTIMER7_BASE,
110  .irq_nr = AM335X_INT_TINT7,
111  .regs = &regs_v2
112};
113
114static struct omap_timer *fr_timer = &am335x_fr_timer;
115static 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
131static void
132omap3_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
185static uint32_t
186beagle_clock_get_timecount(struct timecounter *tc)
187{
188  return mmio_read(fr_timer->base + fr_timer->regs->TCRR);
189}
190
191static void
192beagle_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
266static 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
273static rtems_interrupt_handler clock_isr = NULL;
274
275static 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
293static 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"
Note: See TracBrowser for help on using the repository browser.