summaryrefslogtreecommitdiff
path: root/hal/leon/src/timer.c
blob: c1f8dc4446e54491d9ed2e45422277044821c137 (plain)
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
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
/* Cesar project {{{
 *
 * Copyright (C) 2008 Spidcom
 *
 * <<<Licence>>>
 *
 * }}} */
/**
 * \file    hal/leon/src/timer.c
 * \brief   Functions to use the Leon Timer. 
 * \ingroup hal_leon
 *
 * The second timer on Leon use three registers.
 *      * timer_value 0x80000050
 *      * reload 0x80000054
 *      * config 0x80000058
 *
 * The config register corresponds to :
 *      * bit 0 : enable
 *      * bit 1 : reload automatic
 *      * bit 2 : reload the timer.
 *
 * The timer tick is 1 us on Cesar.
 *
 * The leon documentation is present on gevrey and these data at page 40-41.
 */
#include "common/std.h"
#include "hal/leon/timer.h"
#include "mac/common/ntb.h"

#include "hal/leon/inc/timer_ctx.h"
#include "hal/leon/inc/timer.h"
#include <cyg/infra/diag.h>

#define LEON_TIMER_BASE 0x80000050

#define LEON_TIMER_VALUE LEON_TIMER_BASE
#define LEON_TIMER_RELOAD (LEON_TIMER_BASE + 4)
#define LEON_TIMER_CONFIG (LEON_TIMER_BASE + 8)

static leon_timer_t leon_timer_global;
static volatile u32 *leon_timer_value = (u32 *) LEON_TIMER_VALUE;
static volatile u32 *leon_timer_reload = (u32 *) LEON_TIMER_RELOAD;
static volatile u32 *leon_timer_config = (u32 *) LEON_TIMER_CONFIG;

/**
 * Initialise Leon timer.
 * \param  user_data  user data passed to the callback
 * \param  cb  timer callback, called in ISR context
 * \param  phy  phy context used to get the phy date.
 * \return  the newly created context
 */
leon_timer_t *
leon_timer_init (void *user_data, leon_timer_cb_t cb, phy_t *phy)
{
    cyg_priority_t priority;

    dbg_assert (cb);
    dbg_assert (phy);

    leon_timer_global.phy = phy;
    leon_timer_global.status = false;
    leon_timer_global.cb = cb;
    leon_timer_global.user_data = user_data;

    /** Configure the timer to be 
     * disable.
     * do not reload automatically.
     * do not load.
     */
    *leon_timer_value = 0x0;
    *leon_timer_config = 0x0;

    /** Configure ecos for the ISR and DSR
     */
    leon_timer_global.it_vector = CYGNUM_HAL_INTERRUPT_9;
    priority = 0; // High priorirty

    // Create interrupt timer2
    cyg_drv_interrupt_create(
        leon_timer_global.it_vector,
        priority,
        0,
        &leon_timer_interrupt_isr,
        &leon_timer_interrupt_dsr,
        &leon_timer_global.it_handle,
        &leon_timer_global.it_timer);

    // Attach the interrupt created to the vector.
    cyg_drv_interrupt_attach(leon_timer_global.it_handle);

    // Unmask the interrupt we just configured.
    cyg_drv_interrupt_unmask(leon_timer_global.it_vector);


    //TODO remove this trace
    diag_write_string("Init done\n");

    return &leon_timer_global;
}

/**
 * Uninitialise the Leon timer.
 * \param  ctx  Leon timer context
 */
void
leon_timer_uninit (leon_timer_t *ctx)
{
    dbg_assert (ctx);

    /** Disable the timer. */
    *leon_timer_config = 0x0;
    ctx->status = false;

    // Mask the interruption.
    cyg_drv_interrupt_mask (leon_timer_global.it_vector);
    // Detach the it.
    cyg_drv_interrupt_detach (leon_timer_global.it_handle);
    // remove the it.
    cyg_drv_interrupt_delete (leon_timer_global.it_handle);
}

/**
 * Program the timer to the given date.
 * TODO substract the system date...
 * \param  ctx  Leon timer context
 * \param  date  timer expiration date
 */
void
leon_timer_program (leon_timer_t *ctx, u32 date)
{
    dbg_assert (ctx);
    dbg_assert (date);

    /** Reconfigure the timer. */
    *leon_timer_config = 0x0;
    *leon_timer_reload = date - phy_date (ctx->phy);
    /** reload and enable the timer. */
    *leon_timer_config = 0x5;

    diag_printf("val config=%x\n",*leon_timer_config);
    diag_write_string("Timer programed\n");
}

/**
 * Cancel timer programmation.
 * \param  ctx  Leon timer context
 */
void
leon_timer_cancel (leon_timer_t *ctx)
{
    dbg_assert (ctx);

    /** Disable the timer. */
    *leon_timer_config = 0x0;

    ctx->status = false;
}

/**
 * Interrupt service routine for interrupt timer2.
 *
 * \param  vector  interruption vector.
 * \param  data  data...
 */
cyg_uint32 leon_timer_interrupt_isr(
    cyg_vector_t vector,
    cyg_addrword_t data)
{
    // Block this interrupt from occurring until
    // the DSR completes.
    cyg_drv_interrupt_mask(vector);

    // Tell the processor that we have received
    // the interrupt.
    cyg_drv_interrupt_acknowledge(vector);

    // Tell the kernel that chained interrupt processing
    // is done and the DSR needs to be executed next.
    return CYG_ISR_CALL_DSR;
}

/**
 * Deferred service routine for interrupt timer2.
 *
 * \param  vector interruption
 * \param  count  ....
 * \param  data  ....
 */
void leon_timer_interrupt_dsr(
    cyg_vector_t vector,
    cyg_ucount32 count,
    cyg_addrword_t data)
{
    // Allow this interrupt to occur again.
    cyg_drv_interrupt_unmask(vector);

    // call back the callback function.
    dbg_assert (leon_timer_global.cb);
    (*leon_timer_global.cb) (leon_timer_global.user_data);
}