source: rtems/c/src/lib/libbsp/arm/shared/arm-a9mpcore-clock-config.c @ 1468d70

4.115
Last change on this file since 1468d70 was c499856, checked in by Chris Johns <chrisj@…>, on 03/20/14 at 21:10:47

Change all references of rtems.com to rtems.org.

  • Property mode set to 100644
File size: 4.2 KB
Line 
1/*
2 * Copyright (c) 2013-2014 embedded brains GmbH.  All rights reserved.
3 *
4 *  embedded brains GmbH
5 *  Dornierstr. 4
6 *  82178 Puchheim
7 *  Germany
8 *  <info@embedded-brains.de>
9 *
10 * The license and distribution terms for this file may be
11 * found in the file LICENSE in this distribution or at
12 * http://www.rtems.org/license/LICENSE.
13 */
14
15#include <rtems/counter.h>
16
17#include <bsp.h>
18#include <bsp/fatal.h>
19#include <bsp/irq.h>
20#include <bsp/arm-a9mpcore-regs.h>
21#include <bsp/arm-a9mpcore-clock.h>
22
23#define A9MPCORE_GT ((volatile a9mpcore_gt *) BSP_ARM_A9MPCORE_GT_BASE)
24
25static uint64_t a9mpcore_clock_last_tick_k;
26
27/* This is defined in clockdrv_shell.h */
28void Clock_isr(rtems_irq_hdl_param arg);
29
30__attribute__ ((weak)) uint32_t a9mpcore_clock_periphclk(void)
31{
32  /* default to the BSP option. */
33  return BSP_ARM_A9MPCORE_PERIPHCLK;
34}
35
36static void a9mpcore_clock_at_tick(void)
37{
38  volatile a9mpcore_gt *gt = A9MPCORE_GT;
39
40  gt->irqst = A9MPCORE_GT_IRQST_EFLG;
41}
42
43static void a9mpcore_clock_handler_install(void)
44{
45  rtems_status_code sc;
46
47  sc = rtems_interrupt_handler_install(
48    A9MPCORE_IRQ_GT,
49    "Clock",
50    RTEMS_INTERRUPT_UNIQUE,
51    (rtems_interrupt_handler) Clock_isr,
52    NULL
53  );
54  if (sc != RTEMS_SUCCESSFUL) {
55    bsp_fatal(BSP_ARM_A9MPCORE_FATAL_CLOCK_IRQ_INSTALL);
56  }
57}
58
59static uint64_t a9mpcore_clock_get_counter(volatile a9mpcore_gt *gt)
60{
61  uint32_t cl;
62  uint32_t cu1;
63  uint32_t cu2;
64
65  do {
66    cu1 = gt->cntrupper;
67    cl = gt->cntrlower;
68    cu2 = gt->cntrupper;
69  } while (cu1 != cu2);
70
71  return ((uint64_t) cu2 << 32) | cl;
72}
73
74static void a9mpcore_clock_initialize(void)
75{
76  volatile a9mpcore_gt *gt = A9MPCORE_GT;
77  uint64_t periphclk = a9mpcore_clock_periphclk();
78  uint64_t us_per_tick = rtems_configuration_get_microseconds_per_tick();
79  uint32_t interval = (uint32_t) ((periphclk * us_per_tick) / 1000000);
80  uint64_t cmpval;
81
82  a9mpcore_clock_last_tick_k = (UINT64_C(1000000000) << 32) / periphclk;
83
84  gt->ctrl &= A9MPCORE_GT_CTRL_TMR_EN;
85  gt->irqst = A9MPCORE_GT_IRQST_EFLG;
86
87  cmpval = a9mpcore_clock_get_counter(gt);
88  cmpval += interval;
89
90  gt->cmpvallower = (uint32_t) cmpval;
91  gt->cmpvalupper = (uint32_t) (cmpval >> 32);
92  gt->autoinc = interval;
93  gt->ctrl = A9MPCORE_GT_CTRL_AUTOINC_EN
94    | A9MPCORE_GT_CTRL_IRQ_EN
95    | A9MPCORE_GT_CTRL_COMP_EN
96    | A9MPCORE_GT_CTRL_TMR_EN;
97
98  rtems_counter_initialize_converter((uint32_t) periphclk);
99}
100
101CPU_Counter_ticks _CPU_Counter_read(void)
102{
103  volatile a9mpcore_gt *gt = A9MPCORE_GT;
104
105  return gt->cntrlower;
106}
107
108static void a9mpcore_clock_cleanup_isr(void *arg)
109{
110  volatile a9mpcore_gt *gt = A9MPCORE_GT;
111
112  (void) arg;
113
114  gt->ctrl &= A9MPCORE_GT_CTRL_TMR_EN;
115  gt->irqst = A9MPCORE_GT_IRQST_EFLG;
116}
117
118static void a9mpcore_clock_cleanup(void)
119{
120  rtems_status_code sc;
121
122  /*
123   * The relevant registers / bits of the global timer are banked and chances
124   * are on an SPM system, that we are executing on the wrong CPU to reset
125   * them. Thus we will have the actual cleanup done with the next clock tick.
126   * The ISR will execute on the right CPU for the cleanup.
127   */
128  sc = rtems_interrupt_handler_install(
129    A9MPCORE_IRQ_GT,
130    "Clock",
131    RTEMS_INTERRUPT_REPLACE,
132    a9mpcore_clock_cleanup_isr,
133    NULL
134  );
135  if (sc != RTEMS_SUCCESSFUL) {
136    bsp_fatal(BSP_ARM_A9MPCORE_FATAL_CLOCK_IRQ_REMOVE);
137  }
138}
139
140static uint32_t a9mpcore_clock_nanoseconds_since_last_tick(void)
141{
142  volatile a9mpcore_gt *gt = A9MPCORE_GT;
143  uint64_t k = a9mpcore_clock_last_tick_k;
144  uint32_t c = gt->cntrlower;
145  uint32_t n = gt->cmpvallower;
146  uint32_t i = gt->autoinc;
147
148  if ((gt->irqst & A9MPCORE_GT_IRQST_EFLG) != 0) {
149    n = gt->cmpvallower - i;
150  }
151
152  return (uint32_t) (((c - n + i) * k) >> 32);
153}
154
155#define Clock_driver_support_at_tick() \
156  a9mpcore_clock_at_tick()
157
158#define Clock_driver_support_initialize_hardware() \
159  a9mpcore_clock_initialize()
160
161#define Clock_driver_support_install_isr(isr, old_isr) \
162  do { \
163    a9mpcore_clock_handler_install();   \
164    old_isr = NULL; \
165  } while (0)
166
167#define Clock_driver_support_shutdown_hardware() \
168  a9mpcore_clock_cleanup()
169
170#define Clock_driver_nanoseconds_since_last_tick \
171  a9mpcore_clock_nanoseconds_since_last_tick
172
173/* Include shared source clock driver code */
174#include "../../shared/clockdrv_shell.h"
Note: See TracBrowser for help on using the repository browser.