/****************************************************************************** * * Copyright (c) 2017-2019 by Löwenware Ltd * Please, refer LICENSE file for legal information * ******************************************************************************/ /** * @file timer.c * @author Ilja Kartašov * @brief * * @see https://lowenware.com/ */ #include #include #include #include "timer.h" const unsigned int m_interval = 200000; unsigned int m_current = 0; #ifndef CONFIG_ARM_TIMER #define CONFIG_ARM_TIMER 1 #endif #define TIMER_ENABLE ((1 << 31) | (1 << 29) | (1 << 28)) #define TIMER_RELOAD 1 /* * https://www.raspberrypi.org/forums/viewtopic.php?t=213393 * The sequence on a real PI3 is * 1.) Route the local timer to a core register 0x40000024 (bits 0..2) * QA7_rev3.4.pdf page 18 ... say write 0 which is core 0 * * 2.) Setup timer status control register 0x40000034 (all 32 bits) * QA7_rev3.4.pdf page 17 ... reload value 5000000 = like half sec, enable clock, enable interrupt * You can play with clock prescalers etc later. * 3.) Hit timer interrupt clear and reload register 0x40000038 (bits 30 & 31) * QA7_rev3.4.pdf page 18 ... write 1 to both bits which clears irq signal and loads value from above * * 4.) Setup timer interrupt control register 0x40000040 (all bits ... zero all but the one bit set) * QA7_rev3.4.pdf page 13 ... now this depends what mode Core0 leaves your bootstub in. * If you did no EL changes in stub the core0 will still be in Hyp mode if like me you dropped it to SVC mode it is Non Secure * * If Core0 enters in Hyp mode ... set nCNTHPIRQ_IRQ bit 1 * If Core0 enters in Svc mode ... set nCNTPNSIRQ_IRQ bit 2 * * 5.) Now you need to enable global interupts * asm(" cpsie i") * */ void Timer_init(void) { #if CONFIG_ARM_TIMER == 1 /* Route local timer to a core0 */ AARCH64_LOCAL_INT_ROUTING &= ~0x03; /* Set up timer status control register */ AARCH64_LOCAL_TIMER_STATCTL = TIMER_ENABLE | TIMER_RELOAD; /* clear interrupt flag and reload timer */ AARCH64_LOCAL_TIMER_RECLR |= (1 << 31) | (1 << 30); /* Set timer interrupt control register */ AARCH64_CORE0_TIMER_IRQCTL = (1 << 1); /* nCNTPNSIR1 - Non Secure*/ #else m_current = aarch64_get32r(TIMER_CLO); m_current += m_interval; aarch64_set32r(TIMER_C1, m_current); #endif } void Timer_incFromISR(void) { m_current++; /*= m_interval;*/ #if CONFIG_ARM_TIMER == 1 /* clear interrupt flag and reload timer */ AARCH64_LOCAL_TIMER_RECLR |= (1 << 31) | (1 << 30); #else aarch64_set32r(TIMER_C1, m_current); aarch64_set32r(TIMER_CS, TIMER_CS_M1); #endif /* Log_putS("Timer: "); Log_putI(m_current, 10); Log_putS("\r\n"); */ } uint32_t Timer_getTicks(void) { return m_current; }