os-core/kernel/drivers/timer/timer.c

97 lines
2.8 KiB
C

/******************************************************************************
*
* Copyright (c) 2017-2019 by Löwenware Ltd
* Please, refer LICENSE file for legal information
*
******************************************************************************/
/**
* @file timer.c
* @author Ilja Kartašov <ik@lowenware.com>
* @brief
*
* @see https://lowenware.com/
*/
#include <aarch64/aarch64.h>
#include <drivers/soc/bcm2837/bcm2837.h>
#include <leos/log.h>
#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;
}