mirror of
https://gitea.osmocom.org/sim-card/simtrace2.git
synced 2026-03-17 13:48:32 +03:00
When initializing the TC blocks, let's only configure the GPIO pins TCLK and TIOB, and not the unused TIOA pin. That pin is actually used for (separate) different functions in both qmod and owhw.
211 lines
5.6 KiB
C
211 lines
5.6 KiB
C
/* SIMtrace TC (Timer / Clock) code for ETU tracking */
|
|
|
|
/* (C) 2006-2016 by Harald Welte <hwelte@hmw-consulting.de>
|
|
*
|
|
* This program is free software; you can redistribute it and/or modify
|
|
* it under the terms of the GNU General Public License as published by
|
|
* the Free Software Foundation; either version 2 of the License, or
|
|
* (at your option) any later version.
|
|
*
|
|
* This program is distributed in the hope that it will be useful,
|
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
* GNU General Public License for more details.
|
|
*
|
|
* You should have received a copy of the GNU General Public License
|
|
* along with this program; if not, write to the Free Software
|
|
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
|
*
|
|
*/
|
|
|
|
#include <stdint.h>
|
|
|
|
#include "utils.h"
|
|
#include "tc_etu.h"
|
|
|
|
#include "chip.h"
|
|
|
|
/* pins for Channel 0 of TC-block 0, we only use TCLK + TIOB */
|
|
#define PIN_TCLK0 {PIO_PA4, PIOA, ID_PIOA, PIO_PERIPH_B, PIO_DEFAULT }
|
|
#define PIN_TIOA0 {PIO_PA0, PIOA, ID_PIOA, PIO_PERIPH_B, PIO_DEFAULT}
|
|
#define PIN_TIOB0 {PIO_PA1, PIOA, ID_PIOA, PIO_PERIPH_B, PIO_DEFAULT}
|
|
static const Pin pins_tc0[] = { PIN_TCLK0, PIN_TIOB0 };
|
|
|
|
/* pins for Channel 2 of TC-block 0, we only use TCLK + TIOB */
|
|
#define PIN_TCLK2 {PIO_PA29, PIOA, ID_PIOA, PIO_PERIPH_B, PIO_DEFAULT}
|
|
#define PIN_TIOA2 {PIO_PA26, PIOA, ID_PIOA, PIO_PERIPH_B, PIO_DEFAULT}
|
|
#define PIN_TIOB2 {PIO_PA27, PIOA, ID_PIOA, PIO_PERIPH_B, PIO_DEFAULT}
|
|
static const Pin pins_tc2[] = { PIN_TCLK2, PIN_TIOB2 };
|
|
|
|
struct tc_etu_state {
|
|
/* total negotiated waiting time (default = 9600) */
|
|
uint16_t waiting_time;
|
|
/* how many clock cycles per ETU (default = 372) */
|
|
uint16_t clocks_per_etu;
|
|
/* how many ETUs does waiting time correspond ? */
|
|
uint16_t wait_events;
|
|
/* how many ETUs have we seen expire so far? */
|
|
uint16_t nr_events;
|
|
/* channel number */
|
|
uint8_t chan_nr;
|
|
/* Timer/Counter register pointer */
|
|
TcChannel *chan;
|
|
/* User reference */
|
|
void *handle;
|
|
};
|
|
|
|
#define INIT_TE_STATE(n) { \
|
|
.waiting_time = 9600, \
|
|
.clocks_per_etu = 372, \
|
|
.wait_events = 10, \
|
|
.nr_events = 0, \
|
|
.chan_nr = n, \
|
|
}
|
|
|
|
static struct tc_etu_state te_state0 = INIT_TE_STATE(0);
|
|
static struct tc_etu_state te_state2 = INIT_TE_STATE(2);
|
|
|
|
static struct tc_etu_state *get_te(uint8_t chan_nr)
|
|
{
|
|
if (chan_nr == 0)
|
|
return &te_state0;
|
|
else
|
|
return &te_state2;
|
|
}
|
|
|
|
static void tc_etu_irq(struct tc_etu_state *te)
|
|
{
|
|
uint32_t sr = te->chan->TC_SR;
|
|
|
|
if (sr & TC_SR_ETRGS) {
|
|
/* external trigger, i.e. we have seen a bit on I/O */
|
|
te->nr_events = 0;
|
|
}
|
|
|
|
if (sr & TC_SR_CPCS) {
|
|
/* Compare C event has occurred, i.e. 1 ETU expired */
|
|
te->nr_events++;
|
|
if (te->nr_events == te->wait_events/2) {
|
|
/* Indicate that half the waiting tim has expired */
|
|
tc_etu_wtime_half_expired(te->handle);
|
|
}
|
|
if (te->nr_events >= te->wait_events) {
|
|
TcChannel *chan = te->chan;
|
|
chan->TC_CMR |= TC_CMR_ENETRG;
|
|
|
|
/* disable and re-enable clock to make it stop */
|
|
chan->TC_CCR = TC_CCR_CLKDIS;
|
|
chan->TC_CCR = TC_CCR_CLKEN;
|
|
|
|
/* Indicate that the waiting tim has expired */
|
|
tc_etu_wtime_expired(te->handle);
|
|
}
|
|
}
|
|
}
|
|
|
|
void TC0_IrqHandler(void)
|
|
{
|
|
tc_etu_irq(&te_state0);
|
|
}
|
|
|
|
void TC2_IrqHandler(void)
|
|
{
|
|
tc_etu_irq(&te_state2);
|
|
}
|
|
|
|
static void recalc_nr_events(struct tc_etu_state *te)
|
|
{
|
|
te->wait_events = te->waiting_time / 12;
|
|
te->chan->TC_RC = te->clocks_per_etu * 12;
|
|
}
|
|
|
|
void tc_etu_set_wtime(uint8_t chan_nr, uint16_t wtime)
|
|
{
|
|
struct tc_etu_state *te = get_te(chan_nr);
|
|
te->waiting_time = wtime;
|
|
recalc_nr_events(te);
|
|
}
|
|
|
|
void tc_etu_set_etu(uint8_t chan_nr, uint16_t etu)
|
|
{
|
|
struct tc_etu_state *te = get_te(chan_nr);
|
|
te->clocks_per_etu = etu;
|
|
recalc_nr_events(te);
|
|
}
|
|
|
|
void tc_etu_enable(uint8_t chan_nr)
|
|
{
|
|
struct tc_etu_state *te = get_te(chan_nr);
|
|
|
|
te->nr_events = 0;
|
|
te->chan->TC_CCR = TC_CCR_CLKEN|TC_CCR_SWTRG;
|
|
}
|
|
|
|
void tc_etu_disable(uint8_t chan_nr)
|
|
{
|
|
struct tc_etu_state *te = get_te(chan_nr);
|
|
|
|
te->nr_events = 0;
|
|
te->chan->TC_CCR = TC_CCR_CLKDIS;
|
|
}
|
|
|
|
void tc_etu_init(uint8_t chan_nr, void *handle)
|
|
{
|
|
struct tc_etu_state *te = get_te(chan_nr);
|
|
uint32_t tc_clks;
|
|
|
|
te->handle = handle;
|
|
|
|
switch (chan_nr) {
|
|
case 0:
|
|
/* Configure PA4(TCLK0), PA1(TIB0) */
|
|
PIO_Configure(pins_tc0, ARRAY_SIZE(pins_tc0));
|
|
PMC_EnablePeripheral(ID_TC0);
|
|
/* route TCLK0 to XC2 */
|
|
TC0->TC_BMR &= ~TC_BMR_TC0XC0S_Msk;
|
|
TC0->TC_BMR |= TC_BMR_TC0XC0S_TCLK0;
|
|
tc_clks = TC_CMR_TCCLKS_XC0;
|
|
/* register interrupt handler */
|
|
NVIC_EnableIRQ(TC0_IRQn);
|
|
|
|
te->chan = &TC0->TC_CHANNEL[0];
|
|
break;
|
|
case 2:
|
|
/* Configure PA29(TCLK2), PA27(TIOB2) */
|
|
PIO_Configure(pins_tc2, ARRAY_SIZE(pins_tc2));
|
|
PMC_EnablePeripheral(ID_TC2);
|
|
/* route TCLK2 to XC2. TC0 really means TCA in this case */
|
|
TC0->TC_BMR &= ~TC_BMR_TC2XC2S_Msk;
|
|
TC0->TC_BMR |= TC_BMR_TC2XC2S_TCLK2;
|
|
tc_clks = TC_CMR_TCCLKS_XC2;
|
|
/* register interrupt handler */
|
|
NVIC_EnableIRQ(TC2_IRQn);
|
|
|
|
te->chan = &TC0->TC_CHANNEL[2];
|
|
break;
|
|
default:
|
|
return;
|
|
}
|
|
|
|
/* enable interrupts for Compare-C and external trigger */
|
|
te->chan->TC_IER = TC_IER_CPCS | TC_IER_ETRGS;
|
|
|
|
te->chan->TC_CMR = tc_clks | /* XC(TCLK) clock */
|
|
TC_CMR_WAVE | /* wave mode */
|
|
TC_CMR_ETRGEDG_FALLING | /* ext trig on falling edge */
|
|
TC_CMR_EEVT_TIOB | /* ext trig is TIOB0 */
|
|
TC_CMR_ENETRG | /* enable ext trig */
|
|
TC_CMR_WAVSEL_UP_RC | /* wave mode up */
|
|
TC_CMR_ACPA_SET | /* set TIOA on a compare */
|
|
TC_CMR_ACPC_CLEAR | /* clear TIOA on C compare */
|
|
TC_CMR_ASWTRG_CLEAR; /* Clear TIOA on sw trig */
|
|
|
|
tc_etu_set_etu(chan_nr, 372);
|
|
|
|
/* start with a disabled clock */
|
|
tc_etu_disable(chan_nr);
|
|
|
|
/* Reset to start timers */
|
|
TC0->TC_BCR = TC_BCR_SYNC;
|
|
}
|