blob: 9d302d14f3e6631bb7d33dcfc22cf01b514d73f9 [file] [log] [blame]
Harald Welte9d3e3822015-11-09 00:50:54 +01001/* SIMtrace TC (Timer / Clock) code for ETU tracking */
2
3/* (C) 2006-2015 by Harald Welte <hwelte@hmw-consulting.de>
4 *
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
136void tc_etu_init(uint8_t chan_nr, void *handle)
137{
138 struct tc_etu_state *te = get_te(chan_nr);
139 uint32_t tc_clks;
140
141 te->handle = handle;
142
143 switch (chan_nr) {
144 case 0:
145 /* Configure PA4(TCLK0), PA0(TIOA0), PA1(TIB0) */
146 PIO_Configure(pins_tc0, ARRAY_SIZE(pins_tc0));
147 PMC_EnablePeripheral(ID_TC0);
148 /* route TCLK0 to XC2 */
149 TC0->TC_BMR &= ~TC_BMR_TC0XC0S_Msk;
150 TC0->TC_BMR |= TC_BMR_TC0XC0S_TCLK0;
151 tc_clks = TC_CMR_TCCLKS_XC0;
152 /* register interrupt handler */
153 NVIC_EnableIRQ(TC0_IRQn);
154
155 te->chan = &TC0->TC_CHANNEL[0];
156 break;
157 case 2:
158 /* Configure PA29(TCLK2), PA26(TIOA2), PA27(TIOB2) */
159 PIO_Configure(pins_tc2, ARRAY_SIZE(pins_tc2));
160 PMC_EnablePeripheral(ID_TC2);
161 /* route TCLK2 to XC2. TC0 really means TCA in this case */
162 TC0->TC_BMR &= ~TC_BMR_TC2XC2S_Msk;
163 TC0->TC_BMR |= TC_BMR_TC2XC2S_TCLK2;
164 tc_clks = TC_CMR_TCCLKS_XC2;
165 /* register interrupt handler */
166 NVIC_EnableIRQ(TC2_IRQn);
167
168 te->chan = &TC0->TC_CHANNEL[2];
169 break;
170 default:
171 return;
172 }
173
174 /* enable interrupts for Compare-C and external trigger */
175 te->chan->TC_IER = TC_IER_CPCS | TC_IER_ETRGS;
176
177 te->chan->TC_CMR = tc_clks | /* XC(TCLK) clock */
178 TC_CMR_WAVE | /* wave mode */
179 TC_CMR_ETRGEDG_FALLING | /* ext trig on falling edge */
180 TC_CMR_EEVT_TIOB | /* ext trig is TIOB0 */
181 TC_CMR_ENETRG | /* enable ext trig */
182 TC_CMR_WAVSEL_UP_RC | /* wave mode up */
183 TC_CMR_ACPA_SET | /* set TIOA on a compare */
184 TC_CMR_ACPC_CLEAR | /* clear TIOA on C compare */
185 TC_CMR_ASWTRG_CLEAR; /* Clear TIOA on sw trig */
186
187 tc_etu_set_etu(chan_nr, 372);
188
189 /* enable master clock for TC */
190 te->chan->TC_CCR = TC_CCR_CLKEN;
191
192 /* Reset to start timers */
193 TC0->TC_BCR = TC_BCR_SYNC;
194}