mirror of
https://gitea.osmocom.org/sim-card/simtrace2.git
synced 2026-03-16 21:28:33 +03:00
the reset/ATR handling has been heavily updated/fixed. instead of using the timer counter peripheral to handle the waiting time and corresponding timeout, the USART peripheral internal timeout mechanism is used. this is particularly important for the SIMtrace board since the clock signal is not connected to the timer counter. thus this change adds card emulation support for SIMtrace boards. Fi and Di have been properly rename to F and D since the "i" stands only for an "indicated" value, not the actual value. this does not change the USB protocol (the variable have just been renamed). additional variables store more information about the card capabilities NOTE: it has only be tested for the SIMtrace board Change-Id: Ibcb2c8cace9137695adf5fb3de43566f7cfb93b5
212 lines
5.7 KiB
C
212 lines
5.7 KiB
C
/* SIMtrace TC (Timer / Clock) code for ETU tracking
|
|
*
|
|
* (C) 2006-2016 by Harald Welte <laforge@gnumonks.org>
|
|
*
|
|
* 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"
|
|
|
|
void card_emu_wt_halfed(void *handle);
|
|
void card_emu_wt_expired(void *handle);
|
|
|
|
/* 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 */
|
|
card_emu_wt_halfed(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 */
|
|
card_emu_wt_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;
|
|
}
|