openpcd/firmware/src/simtrace/tc_etu.c

129 lines
3.8 KiB
C

/* SimTrace TC (Timer / Clock) support code
* (C) 2006 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 <lib_AT91SAM7.h>
#include <AT91SAM7.h>
#include <os/dbgu.h>
#include "../openpcd.h"
static AT91PS_TCB tcb;
static AT91PS_TC tcetu = AT91C_BASE_TC0;
static uint16_t waiting_time = 9600;
static uint16_t clocks_per_etu = 372;
static uint16_t wait_events;
static __ramfunc void tc_etu_irq(void)
{
uint32_t sr = tcetu->TC_SR;
static uint16_t nr_events;
if (sr & AT91C_TC_ETRGS) {
/* external trigger, i.e. we have seen a bit on I/O */
//DEBUGPCR("tE");
nr_events = 0;
/* Make sure we don't accept any additional external trigger */
/* Enabling the line below will cause race conditions. We
* thus re-trigger at all zero-bits in the byte and thus wait
* up to 12 etu longer than required */
//tcetu->TC_CMR &= ~AT91C_TC_ENETRG;
}
if (sr & AT91C_TC_CPCS) {
/* Compare C event has occurred, i.e. 1 etu expired */
//DEBUGPCR("tC");
nr_events++;
if (nr_events >= wait_events) {
/* enable external triggers again to catch start bit */
tcetu->TC_CMR |= AT91C_TC_ENETRG;
/* disable and re-enable clock to make it stop */
tcetu->TC_CCR = AT91C_TC_CLKDIS;
tcetu->TC_CCR = AT91C_TC_CLKEN;
//DEBUGPCR("%u", nr_events);
/* Indicate that the waiting time has expired */
iso7816_wtime_expired();
}
}
}
static void recalc_nr_events(void)
{
wait_events = waiting_time/12;
/* clocks_per_etu * 12 equals 'sbit + 8 data bits + parity + 2 stop bits */
tcetu->TC_RC = clocks_per_etu * 12;
}
void tc_etu_set_wtime(uint16_t wtime)
{
waiting_time = wtime;
recalc_nr_events();
//DEBUGPCR("wtime=%u, actually waiting %u", wtime, wait_events * 12);
}
void tc_etu_set_etu(uint16_t etu)
{
clocks_per_etu = etu;
recalc_nr_events();
}
void tc_etu_init(void)
{
/* Cfg PA4(TCLK0), PA0(TIOA0), PA1(TIOB0) */
AT91F_PIO_CfgPeriph(AT91C_BASE_PIOA, 0,
AT91C_PA4_TCLK0 | AT91C_PA0_TIOA0 | AT91C_PA1_TIOB0);
AT91F_PMC_EnablePeriphClock(AT91C_BASE_PMC,
((unsigned int) 1 << AT91C_ID_TC0));
/* Connect TCLK0 to XC0 */
tcb->TCB_BMR &= ~(AT91C_TCB_TC0XC0S);
tcb->TCB_BMR |= AT91C_TCB_TC0XC0S_TCLK0;
/* Register Interrupt handler */
AT91F_AIC_ConfigureIt(AT91C_BASE_AIC, AT91C_ID_TC0,
OPENPCD_IRQ_PRIO_TC_FDT,
AT91C_AIC_SRCTYPE_INT_HIGH_LEVEL, &tc_etu_irq);
AT91F_AIC_EnableIt(AT91C_BASE_AIC, AT91C_ID_TC0);
/* enable interrupts for Compare-C and External Trigger */
tcetu->TC_IER = AT91C_TC_CPCS | AT91C_TC_ETRGS;
tcetu->TC_CMR = AT91C_TC_CLKS_XC0 | /* XC0 (TCLK0) clock */
AT91C_TC_WAVE | /* Wave Mode */
AT91C_TC_ETRGEDG_FALLING |/* Ext trig on falling edge */
AT91C_TC_EEVT_TIOB | /* Ext trigger is TIOB0 */
AT91C_TC_ENETRG | /* Enable ext. trigger */
AT91C_TC_WAVESEL_UP_AUTO |/* Wave mode UP */
AT91C_TC_ACPA_SET | /* Set TIOA0 on A compare */
AT91C_TC_ACPC_CLEAR | /* Clear TIOA0 on C compare */
AT91C_TC_ASWTRG_CLEAR; /* Clear TIOa0 on software trigger */
tc_etu_set_etu(372);
/* Enable master clock for TC0 */
tcetu->TC_CCR = AT91C_TC_CLKEN;
/* Reset to start timers */
tcb->TCB_BCR = 1;
}