source: rtems/c/src/lib/libbsp/arm/beagle/clock.c @ 53dd6d61

4.115
Last change on this file since 53dd6d61 was 53dd6d61, checked in by Ben Gras <beng@…>, on 11/03/14 at 18:53:40

BSP for several Beagle products

Specifically the beagleboard, beagleboard xM, beaglebone, beaglebone black.

More info on these targets: http://www.beagleboard.org/

This commit forms a basic BSP by combining Claas's work with

. new clock and irq code and definitions for

beagle targets (beagleboard and beaglebones), mostly
reused from the Minix codebase, thus making
irqs, ticks and non-polled console mode work too

. new timer code for ns timing with high timer resolution,

24MHz on the AM335X and 13MHz on the DM37XX

. select the console uart based on target at configure time
. removing all the lpc32xx-specific macros and code and

other unused code and definitions that the beagle bsp
was based on

. re-using some standard functions instead of lpc32xx versions
. fixed some whitespace problem in preinstall.am
. fixed some compile warnings
. configure MMU: set 1MB sections directly in the TTBR,

just to show the difference between cacheable RAM and
non-cacheable device memory and invalid ranges; this lets us
turn on caches and not rely on boot loader MMU configuration.
Verified to work when MMU is initially either on or off when
RTEMS gets control.

Thanks for testing, commentary, improvements and fixes to Chris Johns,
Brandon Matthews, Matt Carberry, Romain Bornet, AZ technology and others.

Signed-Off-By: Ben Gras <beng@…>

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