summaryrefslogtreecommitdiffstats
path: root/c/src/lib/libcpu/arm/at91rm9200/clock/clock.c
blob: 503239613b6909b965c417ee4b3acf112d3d5163 (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
/*
 *  AT91RM9200 clock specific using the System Timer
 *
 *  Copyright (c) 2003 by Cogent Computer Systems
 *  Written by Mike Kelly <mike@cogcomp.com>
 *         and Jay Monkman <jtm@lopingdog.com>
 *
 *  The license and distribution terms for this file may be
 *  found in the file LICENSE in this distribution or at
 *
 *  http://www.rtems.com/license/LICENSE.
 *
 *
 *  $Id$
 */
#include <rtems.h>
#include <rtems/clockdrv.h>
#include <rtems/libio.h>

#include <stdlib.h>
#include <bsp.h>
#include <irq.h>
#include <at91rm9200.h>
#include <at91rm9200_pmc.h>


static unsigned long st_pimr_reload;

/**
 * Enables clock interrupt.
 *
 * If the interrupt is always on, this can be a NOP.
 */
static void clock_isr_on(const rtems_irq_connect_data *unused)
{
    /* enable timer interrupt */
    ST_REG(ST_IER) = ST_SR_PITS;
}

/**
 * Disables clock interrupts
 *
 * If the interrupt is always on, this can be a NOP.
 */
static void clock_isr_off(const rtems_irq_connect_data *unused)
{
    /* disable timer interrupt */
    ST_REG(ST_IDR) = ST_SR_PITS;
    return;
}

/**
 * Tests to see if clock interrupt is enabled, and returns 1 if so.
 * If interrupt is not enabled, returns 0.
 *
 * If the interrupt is always on, this always returns 1.
 */
static int clock_isr_is_on(const rtems_irq_connect_data *irq)
{
    /* check timer interrupt */
    return ST_REG(ST_IMR) & ST_SR_PITS;
}

rtems_isr Clock_isr(rtems_vector_number vector);

/* Replace the first value with the clock's interrupt name. */
rtems_irq_connect_data clock_isr_data = {AT91RM9200_INT_SYSIRQ,
                                         (rtems_irq_hdl)Clock_isr,
					 NULL,
                                         clock_isr_on,
                                         clock_isr_off,
                                         clock_isr_is_on};


#define Clock_driver_support_install_isr( _new, _old ) \
  do {                                                 \
      (_old) = NULL;                                   \
      BSP_install_rtems_irq_handler(&clock_isr_data);  \
  } while(0)

uint16_t st_pimr_value;
void Clock_driver_support_initialize_hardware(void)
{
  uint32_t st_str;
  int slck;

  /* the system timer is driven from SLCK */
  slck = at91rm9200_get_slck();
  st_pimr_value =
    (((rtems_configuration_get_microseconds_per_tick() * slck) + (1000000/2))/ 1000000);
  st_pimr_reload = st_pimr_value;

  /* read the status to clear the int */
  st_str = ST_REG(ST_SR);

  /* set priority */
  AIC_SMR_REG(AIC_SMR_SYSIRQ) = AIC_SMR_PRIOR(0x7);

  /* set the timer value */
  ST_REG(ST_PIMR) = st_pimr_reload;
}

uint32_t bsp_clock_nanoseconds_since_last_tick(void)
{
  uint16_t slck_counts;

  slck_counts = st_pimr_value - st_pimr_reload;
  return (rtems_configuration_get_microseconds_per_tick() * slck_counts * 1000)
     / st_pimr_value;
}

#define Clock_driver_nanoseconds_since_last_tick \
  bsp_clock_nanoseconds_since_last_tick

#define CLOCK_VECTOR 0

#define Clock_driver_support_at_tick() \
  do { \
    uint32_t st_str; \
    \
    /* read the status to clear the int */ \
    st_str = ST_REG(ST_SR); \
  } while (0)

void Clock_driver_support_shutdown_hardware( void )
{
    BSP_remove_rtems_irq_handler(&clock_isr_data);
}

#include "../../../../libbsp/shared/clockdrv_shell.h"