blob: 04a73249105b1e001d8434a8a2e13bf674718959 [file] [log] [blame]
Kévin Redon9a12d682018-07-08 13:21:16 +02001/* SIMtrace TC (Timer / Clock) code for ETU tracking
Harald Welte9d3e3822015-11-09 00:50:54 +01002 *
Kévin Redon9a12d682018-07-08 13:21:16 +02003 * (C) 2006-2016 by Harald Welte <laforge@gnumonks.org>
Harald Welte9d3e3822015-11-09 00:50:54 +01004 *
Kévin Redon9a12d682018-07-08 13:21:16 +02005 * 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.
Harald Welte9d3e3822015-11-09 00:50:54 +01009 *
Kévin Redon9a12d682018-07-08 13:21:16 +020010 * 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.
Harald Welte9d3e3822015-11-09 00:50:54 +010014 *
Kévin Redon9a12d682018-07-08 13:21:16 +020015 * 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
Harald Welte9d3e3822015-11-09 00:50:54 +010018 */
Harald Welte9d3e3822015-11-09 00:50:54 +010019#include <stdint.h>
20
21#include "utils.h"
22#include "tc_etu.h"
23
24#include "chip.h"
25
Harald Welte2bff7cd2017-03-05 22:14:04 +010026/* pins for Channel 0 of TC-block 0, we only use TCLK + TIOB */
Harald Welte9d3e3822015-11-09 00:50:54 +010027#define PIN_TCLK0 {PIO_PA4, PIOA, ID_PIOA, PIO_PERIPH_B, PIO_DEFAULT }
28#define PIN_TIOA0 {PIO_PA0, PIOA, ID_PIOA, PIO_PERIPH_B, PIO_DEFAULT}
29#define PIN_TIOB0 {PIO_PA1, PIOA, ID_PIOA, PIO_PERIPH_B, PIO_DEFAULT}
Harald Welte2bff7cd2017-03-05 22:14:04 +010030static const Pin pins_tc0[] = { PIN_TCLK0, PIN_TIOB0 };
Harald Welte9d3e3822015-11-09 00:50:54 +010031
Harald Welte2bff7cd2017-03-05 22:14:04 +010032/* pins for Channel 2 of TC-block 0, we only use TCLK + TIOB */
Harald Welte9d3e3822015-11-09 00:50:54 +010033#define PIN_TCLK2 {PIO_PA29, PIOA, ID_PIOA, PIO_PERIPH_B, PIO_DEFAULT}
34#define PIN_TIOA2 {PIO_PA26, PIOA, ID_PIOA, PIO_PERIPH_B, PIO_DEFAULT}
35#define PIN_TIOB2 {PIO_PA27, PIOA, ID_PIOA, PIO_PERIPH_B, PIO_DEFAULT}
Harald Welte2bff7cd2017-03-05 22:14:04 +010036static const Pin pins_tc2[] = { PIN_TCLK2, PIN_TIOB2 };
Harald Welte9d3e3822015-11-09 00:50:54 +010037
38struct tc_etu_state {
39 /* total negotiated waiting time (default = 9600) */
40 uint16_t waiting_time;
41 /* how many clock cycles per ETU (default = 372) */
42 uint16_t clocks_per_etu;
43 /* how many ETUs does waiting time correspond ? */
44 uint16_t wait_events;
45 /* how many ETUs have we seen expire so far? */
46 uint16_t nr_events;
47 /* channel number */
48 uint8_t chan_nr;
49 /* Timer/Counter register pointer */
50 TcChannel *chan;
51 /* User reference */
52 void *handle;
53};
54
55#define INIT_TE_STATE(n) { \
56 .waiting_time = 9600, \
57 .clocks_per_etu = 372, \
58 .wait_events = 10, \
59 .nr_events = 0, \
60 .chan_nr = n, \
61}
62
63static struct tc_etu_state te_state0 = INIT_TE_STATE(0);
64static struct tc_etu_state te_state2 = INIT_TE_STATE(2);
65
66static struct tc_etu_state *get_te(uint8_t chan_nr)
67{
68 if (chan_nr == 0)
69 return &te_state0;
70 else
71 return &te_state2;
72}
73
74static void tc_etu_irq(struct tc_etu_state *te)
75{
76 uint32_t sr = te->chan->TC_SR;
77
78 if (sr & TC_SR_ETRGS) {
79 /* external trigger, i.e. we have seen a bit on I/O */
80 te->nr_events = 0;
81 }
82
83 if (sr & TC_SR_CPCS) {
84 /* Compare C event has occurred, i.e. 1 ETU expired */
85 te->nr_events++;
86 if (te->nr_events == te->wait_events/2) {
87 /* Indicate that half the waiting tim has expired */
88 tc_etu_wtime_half_expired(te->handle);
89 }
90 if (te->nr_events >= te->wait_events) {
91 TcChannel *chan = te->chan;
92 chan->TC_CMR |= TC_CMR_ENETRG;
93
94 /* disable and re-enable clock to make it stop */
95 chan->TC_CCR = TC_CCR_CLKDIS;
96 chan->TC_CCR = TC_CCR_CLKEN;
97
98 /* Indicate that the waiting tim has expired */
99 tc_etu_wtime_expired(te->handle);
100 }
101 }
102}
103
104void TC0_IrqHandler(void)
105{
106 tc_etu_irq(&te_state0);
107}
108
109void TC2_IrqHandler(void)
110{
111 tc_etu_irq(&te_state2);
112}
113
114static void recalc_nr_events(struct tc_etu_state *te)
115{
116 te->wait_events = te->waiting_time / 12;
117 te->chan->TC_RC = te->clocks_per_etu * 12;
118}
119
120void tc_etu_set_wtime(uint8_t chan_nr, uint16_t wtime)
121{
122 struct tc_etu_state *te = get_te(chan_nr);
123 te->waiting_time = wtime;
124 recalc_nr_events(te);
125}
126
127void tc_etu_set_etu(uint8_t chan_nr, uint16_t etu)
128{
129 struct tc_etu_state *te = get_te(chan_nr);
130 te->clocks_per_etu = etu;
131 recalc_nr_events(te);
132}
133
Harald Welte042f0d32016-02-24 21:01:50 +0100134void tc_etu_enable(uint8_t chan_nr)
135{
136 struct tc_etu_state *te = get_te(chan_nr);
137
138 te->nr_events = 0;
139 te->chan->TC_CCR = TC_CCR_CLKEN|TC_CCR_SWTRG;
140}
141
142void tc_etu_disable(uint8_t chan_nr)
143{
144 struct tc_etu_state *te = get_te(chan_nr);
145
146 te->nr_events = 0;
147 te->chan->TC_CCR = TC_CCR_CLKDIS;
148}
149
Harald Welte9d3e3822015-11-09 00:50:54 +0100150void tc_etu_init(uint8_t chan_nr, void *handle)
151{
152 struct tc_etu_state *te = get_te(chan_nr);
153 uint32_t tc_clks;
154
155 te->handle = handle;
156
157 switch (chan_nr) {
158 case 0:
Harald Welte2bff7cd2017-03-05 22:14:04 +0100159 /* Configure PA4(TCLK0), PA1(TIB0) */
Harald Welte9d3e3822015-11-09 00:50:54 +0100160 PIO_Configure(pins_tc0, ARRAY_SIZE(pins_tc0));
161 PMC_EnablePeripheral(ID_TC0);
162 /* route TCLK0 to XC2 */
163 TC0->TC_BMR &= ~TC_BMR_TC0XC0S_Msk;
164 TC0->TC_BMR |= TC_BMR_TC0XC0S_TCLK0;
165 tc_clks = TC_CMR_TCCLKS_XC0;
166 /* register interrupt handler */
167 NVIC_EnableIRQ(TC0_IRQn);
168
169 te->chan = &TC0->TC_CHANNEL[0];
170 break;
171 case 2:
Harald Welte2bff7cd2017-03-05 22:14:04 +0100172 /* Configure PA29(TCLK2), PA27(TIOB2) */
Harald Welte9d3e3822015-11-09 00:50:54 +0100173 PIO_Configure(pins_tc2, ARRAY_SIZE(pins_tc2));
174 PMC_EnablePeripheral(ID_TC2);
175 /* route TCLK2 to XC2. TC0 really means TCA in this case */
176 TC0->TC_BMR &= ~TC_BMR_TC2XC2S_Msk;
177 TC0->TC_BMR |= TC_BMR_TC2XC2S_TCLK2;
178 tc_clks = TC_CMR_TCCLKS_XC2;
179 /* register interrupt handler */
180 NVIC_EnableIRQ(TC2_IRQn);
181
182 te->chan = &TC0->TC_CHANNEL[2];
183 break;
184 default:
185 return;
186 }
187
188 /* enable interrupts for Compare-C and external trigger */
189 te->chan->TC_IER = TC_IER_CPCS | TC_IER_ETRGS;
190
191 te->chan->TC_CMR = tc_clks | /* XC(TCLK) clock */
192 TC_CMR_WAVE | /* wave mode */
193 TC_CMR_ETRGEDG_FALLING | /* ext trig on falling edge */
194 TC_CMR_EEVT_TIOB | /* ext trig is TIOB0 */
195 TC_CMR_ENETRG | /* enable ext trig */
196 TC_CMR_WAVSEL_UP_RC | /* wave mode up */
197 TC_CMR_ACPA_SET | /* set TIOA on a compare */
198 TC_CMR_ACPC_CLEAR | /* clear TIOA on C compare */
199 TC_CMR_ASWTRG_CLEAR; /* Clear TIOA on sw trig */
200
201 tc_etu_set_etu(chan_nr, 372);
202
Harald Welte042f0d32016-02-24 21:01:50 +0100203 /* start with a disabled clock */
204 tc_etu_disable(chan_nr);
Harald Welte9d3e3822015-11-09 00:50:54 +0100205
206 /* Reset to start timers */
207 TC0->TC_BCR = TC_BCR_SYNC;
208}