source: rtems/c/src/lib/libcpu/sh/sh7750/clock/ckinit.c @ 99f6793

4.104.114.95
Last change on this file since 99f6793 was 99f6793, checked in by Joel Sherrill <joel.sherrill@…>, on 11/26/07 at 23:02:03

2007-11-26 Joel Sherrill <joel.sherrill@…>

  • sh7032/clock/ckinit.c, sh7032/delay/delay.c, sh7032/timer/timer.c, sh7045/clock/ckinit.c, sh7045/timer/timer.c, sh7750/clock/ckinit.c, sh7750/timer/timer.c: Eliminate the clicks_per_microsecond field in the SuperH CPU Table and define another mechanism for drivers to obtain this information.
  • Property mode set to 100644
File size: 7.5 KB
Line 
1/*
2 * This file contains the generic RTEMS clock driver the Hitachi SH 7750
3 *
4 * Copyright (C) 2001 OKTET Ltd., St.-Petersburg, Russia
5 * Author: Victor V. Vengerov <vvv@oktet.ru>
6 *
7 *  COPYRIGHT (c) 2001
8 *  On-Line Applications Research Corporation (OAR).
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.com/license/LICENSE.
13 *
14 *  $Id$
15 */
16
17#include <rtems.h>
18
19#include <stdlib.h>
20
21#include <rtems/libio.h>
22#include <rtems/score/sh_io.h>
23#include <rtems/score/sh.h>
24#include <rtems/score/ispsh7750.h>
25#include <rtems/score/iosh7750.h>
26
27extern uint32_t bsp_clicks_per_second;
28
29#ifndef CLOCKPRIO
30#define CLOCKPRIO 10
31#endif
32
33/* Clock timer prescaler division ratio */
34#define CLOCK_PRESCALER 4
35#define TCR0_TPSC       SH7750_TCR_TPSC_DIV4
36
37/*
38 *  The interrupt vector number associated with the clock tick device
39 *  driver.
40 */
41
42#define CLOCK_VECTOR SH7750_EVT_TO_NUM(SH7750_EVT_TUNI0)
43
44/*
45 *  Clock_driver_ticks is a monotonically increasing counter of the
46 *  number of clock ticks since the driver was initialized.
47 */
48
49volatile uint32_t   Clock_driver_ticks;
50
51static void Clock_exit( void );
52static rtems_isr Clock_isr( rtems_vector_number vector );
53
54/*
55 * These are set by clock driver during its init
56 */
57rtems_device_major_number rtems_clock_major = ~0;
58rtems_device_minor_number rtems_clock_minor;
59
60/*
61 *  The previous ISR on this clock tick interrupt vector.
62 */
63
64rtems_isr_entry  Old_ticker;
65
66/*
67 *  Isr Handler
68 */
69
70/* Clock_isr --
71 *     Clock interrupt handling routine.
72 *
73 * PARAMETERS:
74 *     vector - interrupt vector number
75 *
76 * RETURNS:
77 *     none
78 */
79rtems_isr
80Clock_isr(rtems_vector_number vector)
81{
82    uint16_t   tcr;
83
84    /* reset the timer underflow flag */
85    tcr = read16(SH7750_TCR0);
86    write16(tcr & ~SH7750_TCR_UNF, SH7750_TCR0);
87
88    /* Increment the clock interrupt counter */
89    Clock_driver_ticks++ ;
90
91    /* Invoke rtems clock service routine */
92    rtems_clock_tick();
93}
94
95/* Install_clock --
96 *     Install a clock tick handler and reprograms the chip.  This
97 *     is used to initially establish the clock tick.
98 *
99 * PARAMETERS:
100 *     clock_isr - Clock interrupt stay routine
101 *
102 * RETURNS:
103 *     none
104 *
105 * SIDE EFFECTS:
106 *     Establish clock interrupt handler, configure Timer 0 hardware
107 */
108void
109Install_clock(rtems_isr_entry clock_isr)
110{
111    int cpudiv = 1; /* CPU frequency divider */
112    int tidiv = 1;  /* Timer input frequency divider */
113    uint32_t   timer_divider; /* Calculated Timer Divider value */
114    uint8_t   temp8;
115    uint16_t   temp16;
116
117    /*
118     *  Initialize the clock tick device driver variables
119     */
120
121    Clock_driver_ticks = 0;
122
123    /* Get CPU frequency divider from clock unit */
124    switch (read16(SH7750_FRQCR) & SH7750_FRQCR_IFC)
125    {
126        case SH7750_FRQCR_IFCDIV1:
127            cpudiv = 1;
128            break;
129
130        case SH7750_FRQCR_IFCDIV2:
131            cpudiv = 2;
132            break;
133
134        case SH7750_FRQCR_IFCDIV3:
135            cpudiv = 3;
136            break;
137
138        case SH7750_FRQCR_IFCDIV4:
139            cpudiv = 4;
140            break;
141
142        case SH7750_FRQCR_IFCDIV6:
143            cpudiv = 6;
144            break;
145
146        case SH7750_FRQCR_IFCDIV8:
147            cpudiv = 8;
148            break;
149
150        default:
151            rtems_fatal_error_occurred( RTEMS_NOT_CONFIGURED);
152    }
153
154    /* Get peripheral module frequency divider from clock unit */
155    switch (read16(SH7750_FRQCR) & SH7750_FRQCR_PFC)
156    {
157        case SH7750_FRQCR_PFCDIV2:
158            tidiv = 2 * CLOCK_PRESCALER;
159            break;
160
161        case SH7750_FRQCR_PFCDIV3:
162            tidiv = 3 * CLOCK_PRESCALER;
163            break;
164
165        case SH7750_FRQCR_PFCDIV4:
166            tidiv = 4 * CLOCK_PRESCALER;
167            break;
168
169        case SH7750_FRQCR_PFCDIV6:
170            tidiv = 6 * CLOCK_PRESCALER;
171            break;
172
173        case SH7750_FRQCR_PFCDIV8:
174            tidiv = 8 * CLOCK_PRESCALER;
175            break;
176
177        default:
178            rtems_fatal_error_occurred( RTEMS_NOT_CONFIGURED);
179    }
180    timer_divider =
181        (bsp_clicks_per_second * cpudiv / (tidiv*1000000)) *
182        rtems_configuration_get_microseconds_per_tick();
183
184    /*
185     *  Hardware specific initialization
186     */
187
188    /* Stop the Timer 0 */
189    temp8 = read8(SH7750_TSTR);
190    temp8 &= ~SH7750_TSTR_STR0;
191    write8(temp8, SH7750_TSTR);
192
193    /* Establish interrupt handler */
194    rtems_interrupt_catch( Clock_isr, CLOCK_VECTOR, &Old_ticker );
195
196    /* Reset counter */
197    write32(timer_divider, SH7750_TCNT0);
198
199    /* Load divider */
200    write32(timer_divider, SH7750_TCOR0);
201
202    write16(
203        SH7750_TCR_UNIE |        /* Enable Underflow Interrupt */
204        SH7750_TCR_CKEG_RAISE |  /* Count on rising edge */
205        TCR0_TPSC,               /* Timer prescaler ratio */
206        SH7750_TCR0);
207
208    /* Set clock interrupt priority */
209    temp16 = read16(SH7750_IPRA);
210    temp16 = (temp16 & ~SH7750_IPRA_TMU0) | (CLOCKPRIO << SH7750_IPRA_TMU0_S);
211    write16(temp16, SH7750_IPRA);
212
213    /* Start the Timer 0 */
214    temp8 = read8(SH7750_TSTR);
215    temp8 |= SH7750_TSTR_STR0;
216    write8(temp8, SH7750_TSTR);
217
218    /*
219     *  Schedule the clock cleanup routine to execute if the application exits.
220     */
221
222    atexit( Clock_exit );
223}
224
225/* Clock_exit --
226 *     Clean up before the application exits
227 *
228 * PARAMETERS:
229 *     none
230 *
231 * RETURNS:
232 *     none
233 *
234 * SIDE EFFECTS:
235 *     Stop Timer 0 counting, set timer 0 interrupt priority level to 0.
236 */
237void
238Clock_exit(void)
239{
240    uint8_t   temp8 = 0;
241    uint16_t   temp16 = 0;
242
243    /* turn off the timer interrupts */
244    /* Stop the Timer 0 */
245    temp8 = read8(SH7750_TSTR);
246    temp8 &= ~SH7750_TSTR_STR0;
247    write8(temp8, SH7750_TSTR);
248
249    /* Lower timer interrupt priority to 0 */
250    temp16 = read16(SH7750_IPRA);
251    temp16 = (temp16 & ~SH7750_IPRA_TMU0) | (0 << SH7750_IPRA_TMU0_S);
252    write16(temp16, SH7750_IPRA);
253
254  /* old vector shall not be installed */
255}
256
257/* Clock_initialize --
258 *     Device driver entry point for clock tick driver initialization.
259 *
260 * PARAMETERS:
261 *     major - clock major device number
262 *     minor - clock minor device number
263 *     pargp - driver initialize primitive argument, not used
264 *
265 * RETURNS:
266 *     RTEMS_SUCCESSFUL
267 */
268rtems_device_driver
269Clock_initialize(rtems_device_major_number major,
270                 rtems_device_minor_number minor,
271                 void *pargp)
272{
273    Install_clock( Clock_isr );
274
275    /*
276     * make major/minor avail to others such as shared memory driver
277     */
278    rtems_clock_major = major;
279    rtems_clock_minor = minor;
280
281    return RTEMS_SUCCESSFUL;
282}
283
284/* Clock_control --
285 *     Device driver entry point for clock driver IOCTL functions.
286 *
287 * PARAMETERS:
288 *     major - clock major device number
289 *     minor - clock minor device number
290 *     pargp - driver ioctl primitive argument, not used
291 *
292 * RETURNS:
293 *     RTEMS_SUCCESSFUL
294 */
295rtems_device_driver
296Clock_control(rtems_device_major_number major,
297              rtems_device_minor_number minor,
298              void *pargp)
299{
300  uint32_t   isrlevel;
301  rtems_libio_ioctl_args_t *args = pargp;
302
303  if (args != 0)
304    {
305      /*
306       * This is hokey, but until we get a defined interface
307       * to do this, it will just be this simple...
308       */
309
310      if (args->command == rtems_build_name('I', 'S', 'R', ' '))
311        {
312          Clock_isr(CLOCK_VECTOR);
313        }
314      else if (args->command == rtems_build_name('N', 'E', 'W', ' '))
315        {
316          rtems_isr_entry       ignored ;
317          rtems_interrupt_disable( isrlevel );
318          rtems_interrupt_catch( args->buffer, CLOCK_VECTOR, &ignored );
319
320          rtems_interrupt_enable( isrlevel );
321        }
322    }
323  return RTEMS_SUCCESSFUL;
324}
Note: See TracBrowser for help on using the repository browser.