Harald Welte | 9d3e382 | 2015-11-09 00:50:54 +0100 | [diff] [blame] | 1 | /* SIMtrace TC (Timer / Clock) code for ETU tracking */ |
| 2 | |
Harald Welte | 042f0d3 | 2016-02-24 21:01:50 +0100 | [diff] [blame] | 3 | /* (C) 2006-2016 by Harald Welte <hwelte@hmw-consulting.de> |
Harald Welte | 9d3e382 | 2015-11-09 00:50:54 +0100 | [diff] [blame] | 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 | |
Harald Welte | 2bff7cd | 2017-03-05 22:14:04 +0100 | [diff] [blame] | 28 | /* pins for Channel 0 of TC-block 0, we only use TCLK + TIOB */ |
Harald Welte | 9d3e382 | 2015-11-09 00:50:54 +0100 | [diff] [blame] | 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} |
Harald Welte | 2bff7cd | 2017-03-05 22:14:04 +0100 | [diff] [blame] | 32 | static const Pin pins_tc0[] = { PIN_TCLK0, PIN_TIOB0 }; |
Harald Welte | 9d3e382 | 2015-11-09 00:50:54 +0100 | [diff] [blame] | 33 | |
Harald Welte | 2bff7cd | 2017-03-05 22:14:04 +0100 | [diff] [blame] | 34 | /* pins for Channel 2 of TC-block 0, we only use TCLK + TIOB */ |
Harald Welte | 9d3e382 | 2015-11-09 00:50:54 +0100 | [diff] [blame] | 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} |
Harald Welte | 2bff7cd | 2017-03-05 22:14:04 +0100 | [diff] [blame] | 38 | static const Pin pins_tc2[] = { PIN_TCLK2, PIN_TIOB2 }; |
Harald Welte | 9d3e382 | 2015-11-09 00:50:54 +0100 | [diff] [blame] | 39 | |
| 40 | struct 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 | |
| 65 | static struct tc_etu_state te_state0 = INIT_TE_STATE(0); |
| 66 | static struct tc_etu_state te_state2 = INIT_TE_STATE(2); |
| 67 | |
| 68 | static 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 | |
| 76 | static 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 | |
| 106 | void TC0_IrqHandler(void) |
| 107 | { |
| 108 | tc_etu_irq(&te_state0); |
| 109 | } |
| 110 | |
| 111 | void TC2_IrqHandler(void) |
| 112 | { |
| 113 | tc_etu_irq(&te_state2); |
| 114 | } |
| 115 | |
| 116 | static 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 | |
| 122 | void 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 | |
| 129 | void 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 Welte | 042f0d3 | 2016-02-24 21:01:50 +0100 | [diff] [blame] | 136 | void 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 | |
| 144 | void 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 Welte | 9d3e382 | 2015-11-09 00:50:54 +0100 | [diff] [blame] | 152 | void 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: |
Harald Welte | 2bff7cd | 2017-03-05 22:14:04 +0100 | [diff] [blame] | 161 | /* Configure PA4(TCLK0), PA1(TIB0) */ |
Harald Welte | 9d3e382 | 2015-11-09 00:50:54 +0100 | [diff] [blame] | 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: |
Harald Welte | 2bff7cd | 2017-03-05 22:14:04 +0100 | [diff] [blame] | 174 | /* Configure PA29(TCLK2), PA27(TIOB2) */ |
Harald Welte | 9d3e382 | 2015-11-09 00:50:54 +0100 | [diff] [blame] | 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 Welte | 042f0d3 | 2016-02-24 21:01:50 +0100 | [diff] [blame] | 205 | /* start with a disabled clock */ |
| 206 | tc_etu_disable(chan_nr); |
Harald Welte | 9d3e382 | 2015-11-09 00:50:54 +0100 | [diff] [blame] | 207 | |
| 208 | /* Reset to start timers */ |
| 209 | TC0->TC_BCR = TC_BCR_SYNC; |
| 210 | } |