source: rtems/c/src/lib/libbsp/powerpc/shared/clock/clock.c @ d3c32136

4.104.114.9
Last change on this file since d3c32136 was d3c32136, checked in by Thomas Doerfler <Thomas.Doerfler@…>, on Jul 18, 2008 at 3:56:48 PM

Changed special purpose register inline functions to macros.
fixed some minors in mpc83xx support
added file for mpc55xx watchdog support

  • Property mode set to 100644
File size: 6.4 KB
Line 
1/**
2 * @file
3 *
4 * @ingroup powerpc_shared
5 *
6 * @brief Source file for a clock driver.
7 */
8
9/*
10 * Copyright (c) 2008
11 * Embedded Brains GmbH
12 * Obere Lagerstr. 30
13 * D-82178 Puchheim
14 * Germany
15 * rtems@embedded-brains.de
16 *
17 * The license and distribution terms for this file may be found in the file
18 * LICENSE in this distribution or at http://www.rtems.com/license/LICENSE.
19 */
20
21#include <rtems/libio.h>
22#include <rtems/clockdrv.h>
23
24#include <libcpu/powerpc-utility.h>
25#include <libcpu/raw_exception.h>
26
27#include <bsp/ppc_exc_bspsupp.h>
28
29#define RTEMS_STATUS_CHECKS_USE_PRINTK
30
31#include <rtems/status-checks.h>
32
33/*
34 * This variable must be defined in the BSP and valid before clock driver
35 * initialization.  The clicks refer to the decrementer and time base.
36 */
37extern uint32_t bsp_clicks_per_usec;
38
39#define PPC_CLOCK_DECREMENTER_MAX UINT32_MAX
40
41volatile uint32_t Clock_driver_ticks = 0;
42
43rtems_device_major_number rtems_clock_major = -1;
44
45rtems_device_minor_number rtems_clock_minor = -1;
46
47static uint32_t ppc_clock_decrementer_value = PPC_CLOCK_DECREMENTER_MAX;
48
49static uint32_t ppc_clock_next_time_base = 0;
50
51static void ppc_clock_no_tick()
52{
53        /* Do nothing */
54}
55
56static void (*ppc_clock_tick)() = ppc_clock_no_tick;
57
58int ppc_clock_exception_handler( BSP_Exception_frame *frame, unsigned number)
59{
60        uint32_t reg1;
61        uint32_t reg2;
62        uint32_t reg3;
63        uint32_t msr;
64
65        /* Set new decrementer value according to a reference time base */
66        asm volatile (
67                "lwz %0, ppc_clock_next_time_base@sdarel(13);"
68                "lwz %1, ppc_clock_decrementer_value@sdarel(13);"
69                "mftb %2;"
70                "add %0, %0, %1;"
71                "subf %1, %2, %0;"
72                "stw %0, ppc_clock_next_time_base@sdarel(13);"
73                "mtdec %1;"
74                : "=r" (reg1), "=r" (reg2), "=r" (reg3)
75        );
76
77        /* Increment clock ticks */
78        Clock_driver_ticks += 1;
79
80        /* Enable external exceptions */
81        msr = ppc_external_exceptions_enable();
82
83        /* Call clock ticker  */
84        ppc_clock_tick();
85
86        /* Restore machine state */
87        ppc_external_exceptions_disable( msr);
88
89        return 0;
90}
91
92int ppc_clock_exception_handler_classic( BSP_Exception_frame *frame, unsigned number)
93{
94        uint32_t reg1;
95        uint32_t reg2;
96        uint32_t msr;
97
98        /* Set new decrementer value */
99        asm volatile(
100                "lwz %1, ppc_clock_decrementer_value@sdarel(13);"
101                "mfdec %0;"
102                "add %0, %0, %1;"
103                "mtdec %0"
104                : "=r" (reg1), "=r" (reg2)
105        );
106
107        /* Increment clock ticks */
108        Clock_driver_ticks += 1;
109
110        /* Enable external exceptions */
111        msr = ppc_external_exceptions_enable();
112
113        /* Call clock ticker  */
114        ppc_clock_tick();
115
116        /* Restore machine state */
117        ppc_external_exceptions_disable( msr);
118
119        return 0;
120}
121
122int ppc_clock_exception_handler_booke( BSP_Exception_frame *frame, unsigned number)
123{
124        uint32_t msr;
125
126        /* Acknowledge decrementer request */
127        PPC_SET_SPECIAL_PURPOSE_REGISTER( BOOKE_TSR, BOOKE_TSR_DIS);
128
129        /* Increment clock ticks */
130        Clock_driver_ticks += 1;
131
132        /* Enable external exceptions */
133        msr = ppc_external_exceptions_enable();
134
135        /* Call clock ticker  */
136        ppc_clock_tick();
137
138        /* Restore machine state */
139        ppc_external_exceptions_disable( msr);
140
141        return 0;
142}
143
144int ppc_clock_exception_handler_e300( BSP_Exception_frame *frame, unsigned number)
145{
146        uint32_t msr;
147
148        /* Increment clock ticks */
149        Clock_driver_ticks += 1;
150
151        /* Enable external exceptions */
152        msr = ppc_external_exceptions_enable();
153
154        /* Call clock ticker  */
155        ppc_clock_tick();
156
157        /* Restore machine state */
158        ppc_external_exceptions_disable( msr);
159
160        return 0;
161}
162
163uint32_t ppc_clock_nanoseconds_since_last_tick()
164{
165        return ((ppc_clock_decrementer_value - ppc_decrementer_register()) * 1000) / bsp_clicks_per_usec;
166}
167
168void Clock_exit()
169{
170        /* Set the decrementer to the maximum value */
171        ppc_set_decrementer_register( PPC_CLOCK_DECREMENTER_MAX);
172
173        /* Use default clock handler */
174        ppc_clock_tick = ppc_clock_no_tick;
175}
176
177rtems_device_driver Clock_initialize( rtems_device_major_number major, rtems_device_minor_number minor, void *arg)
178{
179        /* Current CPU type */
180        ppc_cpu_id_t cpu_type = get_ppc_cpu_type();
181
182        /* Make major/minor available to others such as shared memory driver */
183        rtems_clock_major = major;
184        rtems_clock_minor = minor;
185
186        /*
187         * Set default ticker.
188         *
189         * The function rtems_clock_tick() returns a status code.  This value
190         * will be discarded since the RTEMS documentation claims that it is
191         * always successful.
192         */
193        ppc_clock_tick = (void (*)()) rtems_clock_tick;
194
195        /* Set the decrementer to the maximum value */
196        ppc_set_decrementer_register( PPC_CLOCK_DECREMENTER_MAX);
197
198        /* Decrementer value */
199        ppc_clock_decrementer_value = bsp_clicks_per_usec * rtems_configuration_get_microseconds_per_tick() - 1;
200
201        /* Check decrementer value */
202        if (ppc_clock_decrementer_value == 0) {
203                ppc_clock_decrementer_value = PPC_CLOCK_DECREMENTER_MAX;
204                SYSLOG_ERROR( "Decrementer value would be zero, will be set to maximum value instead\n");
205        }
206
207        /* Set the nanoseconds since last tick handler */
208        rtems_clock_set_nanoseconds_extension( ppc_clock_nanoseconds_since_last_tick);
209
210        if (ppc_cpu_is_bookE()) {
211                /* Set decrementer auto-reload value */
212                PPC_SET_SPECIAL_PURPOSE_REGISTER( BOOKE_DECAR, ppc_clock_decrementer_value);
213
214                /* Install exception handler */
215                ppc_exc_set_handler( ASM_BOOKE_DEC_VECTOR, ppc_clock_exception_handler_booke);
216
217                /* Enable decrementer and auto-reload */
218                PPC_SET_SPECIAL_PURPOSE_REGISTER_BITS( BOOKE_TCR, BOOKE_TCR_DIE | BOOKE_TCR_ARE);
219        } else if (cpu_type == PPC_e300c2 || cpu_type == PPC_e300c3) {
220                /* TODO: Not tested for e300c2 */
221
222                /* Enable auto-reload */
223                PPC_SET_SPECIAL_PURPOSE_REGISTER_BITS( HID0, 0x00000040);
224
225                /* Install exception handler */
226                ppc_exc_set_handler( ASM_DEC_VECTOR, ppc_clock_exception_handler_e300);
227        } else {
228                /* Here the decrementer value is actually the interval */
229                ++ppc_clock_decrementer_value;
230
231                /* Initialize next time base */
232                ppc_clock_next_time_base = ppc_time_base() + ppc_clock_decrementer_value;
233
234                /* Install exception handler */
235                ppc_exc_set_handler( ASM_DEC_VECTOR, ppc_clock_exception_handler);
236        }
237
238        /* Set the decrementer value */
239        ppc_set_decrementer_register( ppc_clock_decrementer_value);
240
241        return RTEMS_SUCCESSFUL;
242}
243
244rtems_device_driver Clock_control( rtems_device_major_number major, rtems_device_minor_number minor, void *arg)
245{
246        rtems_libio_ioctl_args_t *io = arg;
247
248        if (io == NULL) {
249                return RTEMS_SUCCESSFUL;
250        }
251
252        if (io->command == rtems_build_name( 'I', 'S', 'R', ' ')) {
253                ppc_clock_tick();
254        } else if (io->command == rtems_build_name( 'N', 'E', 'W', ' ')) {
255                if (io->buffer != NULL) {
256                        ppc_clock_tick = io->buffer;
257                } else {
258                        ppc_clock_tick = ppc_clock_no_tick;
259                }
260        }
261
262        return RTEMS_SUCCESSFUL;
263}
Note: See TracBrowser for help on using the repository browser.