blob: 76ce77d1b59e3519bc797f4076572928c67db831 [file] [log] [blame]
Harald Welte9d3e3822015-11-09 00:50:54 +01001/* SIMtrace TC (Timer / Clock) code for ETU tracking */
2
Harald Welte042f0d32016-02-24 21:01:50 +01003/* (C) 2006-2016 by Harald Welte <hwelte@hmw-consulting.de>
Harald Welte9d3e3822015-11-09 00:50:54 +01004 *
5 * This program is free software; you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License as published by
7 * the Free Software Foundation; either version 2 of the License, or
8 * (at your option) any later version.
9 *
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
14 *
15 * You should have received a copy of the GNU General Public License
16 * along with this program; if not, write to the Free Software
17 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
18 *
19 */
20
21#include <stdint.h>
22
23#include "utils.h"
24#include "tc_etu.h"
25
26#include "chip.h"
27
28/* pins for Channel 0 of TC-block 0 */
29#define PIN_TCLK0 {PIO_PA4, PIOA, ID_PIOA, PIO_PERIPH_B, PIO_DEFAULT }
30#define PIN_TIOA0 {PIO_PA0, PIOA, ID_PIOA, PIO_PERIPH_B, PIO_DEFAULT}
31#define PIN_TIOB0 {PIO_PA1, PIOA, ID_PIOA, PIO_PERIPH_B, PIO_DEFAULT}
32static const Pin pins_tc0[] = { PIN_TCLK0, PIN_TIOA0, PIN_TIOB0 };
33
34/* pins for Channel 2 of TC-block 0 */
35#define PIN_TCLK2 {PIO_PA29, PIOA, ID_PIOA, PIO_PERIPH_B, PIO_DEFAULT}
36#define PIN_TIOA2 {PIO_PA26, PIOA, ID_PIOA, PIO_PERIPH_B, PIO_DEFAULT}
37#define PIN_TIOB2 {PIO_PA27, PIOA, ID_PIOA, PIO_PERIPH_B, PIO_DEFAULT}
38static const Pin pins_tc2[] = { PIN_TCLK2, PIN_TIOA2, PIN_TIOB2 };
39
40struct tc_etu_state {
41 /* total negotiated waiting time (default = 9600) */
42 uint16_t waiting_time;
43 /* how many clock cycles per ETU (default = 372) */
44 uint16_t clocks_per_etu;
45 /* how many ETUs does waiting time correspond ? */
46 uint16_t wait_events;
47 /* how many ETUs have we seen expire so far? */
48 uint16_t nr_events;
49 /* channel number */
50 uint8_t chan_nr;
51 /* Timer/Counter register pointer */
52 TcChannel *chan;
53 /* User reference */
54 void *handle;
55};
56
57#define INIT_TE_STATE(n) { \
58 .waiting_time = 9600, \
59 .clocks_per_etu = 372, \
60 .wait_events = 10, \
61 .nr_events = 0, \
62 .chan_nr = n, \
63}
64
65static struct tc_etu_state te_state0 = INIT_TE_STATE(0);
66static struct tc_etu_state te_state2 = INIT_TE_STATE(2);
67
68static struct tc_etu_state *get_te(uint8_t chan_nr)
69{
70 if (chan_nr == 0)
71 return &te_state0;
72 else
73 return &te_state2;
74}
75
76static void tc_etu_irq(struct tc_etu_state *te)
77{
78 uint32_t sr = te->chan->TC_SR;
79
80 if (sr & TC_SR_ETRGS) {
81 /* external trigger, i.e. we have seen a bit on I/O */
82 te->nr_events = 0;
83 }
84
85 if (sr & TC_SR_CPCS) {
86 /* Compare C event has occurred, i.e. 1 ETU expired */
87 te->nr_events++;
88 if (te->nr_events == te->wait_events/2) {
89 /* Indicate that half the waiting tim has expired */
90 tc_etu_wtime_half_expired(te->handle);
91 }
92 if (te->nr_events >= te->wait_events) {
93 TcChannel *chan = te->chan;
94 chan->TC_CMR |= TC_CMR_ENETRG;
95
96 /* disable and re-enable clock to make it stop */
97 chan->TC_CCR = TC_CCR_CLKDIS;
98 chan->TC_CCR = TC_CCR_CLKEN;
99
100 /* Indicate that the waiting tim has expired */
101 tc_etu_wtime_expired(te->handle);
102 }
103 }
104}
105
106void TC0_IrqHandler(void)
107{
108 tc_etu_irq(&te_state0);
109}
110
111void TC2_IrqHandler(void)
112{
113 tc_etu_irq(&te_state2);
114}
115
116static void recalc_nr_events(struct tc_etu_state *te)
117{
118 te->wait_events = te->waiting_time / 12;
119 te->chan->TC_RC = te->clocks_per_etu * 12;
120}
121
122void tc_etu_set_wtime(uint8_t chan_nr, uint16_t wtime)
123{
124 struct tc_etu_state *te = get_te(chan_nr);
125 te->waiting_time = wtime;
126 recalc_nr_events(te);
127}
128
129void tc_etu_set_etu(uint8_t chan_nr, uint16_t etu)
130{
131 struct tc_etu_state *te = get_te(chan_nr);
132 te->clocks_per_etu = etu;
133 recalc_nr_events(te);
134}
135
Harald Welte042f0d32016-02-24 21:01:50 +0100136void tc_etu_enable(uint8_t chan_nr)
137{
138 struct tc_etu_state *te = get_te(chan_nr);
139
140 te->nr_events = 0;
141 te->chan->TC_CCR = TC_CCR_CLKEN|TC_CCR_SWTRG;
142}
143
144void tc_etu_disable(uint8_t chan_nr)
145{
146 struct tc_etu_state *te = get_te(chan_nr);
147
148 te->nr_events = 0;
149 te->chan->TC_CCR = TC_CCR_CLKDIS;
150}
151
Harald Welte9d3e3822015-11-09 00:50:54 +0100152void tc_etu_init(uint8_t chan_nr, void *handle)
153{
154 struct tc_etu_state *te = get_te(chan_nr);
155 uint32_t tc_clks;
156
157 te->handle = handle;
158
159 switch (chan_nr) {
160 case 0:
161 /* Configure PA4(TCLK0), PA0(TIOA0), PA1(TIB0) */
162 PIO_Configure(pins_tc0, ARRAY_SIZE(pins_tc0));
163 PMC_EnablePeripheral(ID_TC0);
164 /* route TCLK0 to XC2 */
165 TC0->TC_BMR &= ~TC_BMR_TC0XC0S_Msk;
166 TC0->TC_BMR |= TC_BMR_TC0XC0S_TCLK0;
167 tc_clks = TC_CMR_TCCLKS_XC0;
168 /* register interrupt handler */
169 NVIC_EnableIRQ(TC0_IRQn);
170
171 te->chan = &TC0->TC_CHANNEL[0];
172 break;
173 case 2:
174 /* Configure PA29(TCLK2), PA26(TIOA2), PA27(TIOB2) */
175 PIO_Configure(pins_tc2, ARRAY_SIZE(pins_tc2));
176 PMC_EnablePeripheral(ID_TC2);
177 /* route TCLK2 to XC2. TC0 really means TCA in this case */
178 TC0->TC_BMR &= ~TC_BMR_TC2XC2S_Msk;
179 TC0->TC_BMR |= TC_BMR_TC2XC2S_TCLK2;
180 tc_clks = TC_CMR_TCCLKS_XC2;
181 /* register interrupt handler */
182 NVIC_EnableIRQ(TC2_IRQn);
183
184 te->chan = &TC0->TC_CHANNEL[2];
185 break;
186 default:
187 return;
188 }
189
190 /* enable interrupts for Compare-C and external trigger */
191 te->chan->TC_IER = TC_IER_CPCS | TC_IER_ETRGS;
192
193 te->chan->TC_CMR = tc_clks | /* XC(TCLK) clock */
194 TC_CMR_WAVE | /* wave mode */
195 TC_CMR_ETRGEDG_FALLING | /* ext trig on falling edge */
196 TC_CMR_EEVT_TIOB | /* ext trig is TIOB0 */
197 TC_CMR_ENETRG | /* enable ext trig */
198 TC_CMR_WAVSEL_UP_RC | /* wave mode up */
199 TC_CMR_ACPA_SET | /* set TIOA on a compare */
200 TC_CMR_ACPC_CLEAR | /* clear TIOA on C compare */
201 TC_CMR_ASWTRG_CLEAR; /* Clear TIOA on sw trig */
202
203 tc_etu_set_etu(chan_nr, 372);
204
Harald Welte042f0d32016-02-24 21:01:50 +0100205 /* start with a disabled clock */
206 tc_etu_disable(chan_nr);
Harald Welte9d3e3822015-11-09 00:50:54 +0100207
208 /* Reset to start timers */
209 TC0->TC_BCR = TC_BCR_SYNC;
210}