kzm: implement MCS timer driver

- use gpt, so we can have overflow and compare interrupts at the same
time (epit only allows compare)
- set the gpt to use the ipg_highfreq timer, as the standard ipg is too
low and breaks the timer calculations
This commit is contained in:
Anna Lyons
2017-12-14 16:59:15 +11:00
committed by Kent Mcleod
parent ea07ad0414
commit 4db4a3b882
6 changed files with 171 additions and 4 deletions

View File

@@ -0,0 +1,72 @@
/*
* Copyright 2019, Data61
* Commonwealth Scientific and Industrial Research Organisation (CSIRO)
* ABN 41 687 119 230.
*
* This software may be distributed and modified according to the terms of
* the GNU General Public License version 2. Note that NO WARRANTY is provided.
* See "LICENSE_GPLv2.txt" for details.
*
* @TAG(DATA61_GPL)
*/
#ifndef __DRIVERS_TIMER_IMX31_GPT_H
#define __DRIVERS_TIMER_IMX31_GPT_H
#include <config.h>
#ifndef CONFIG_KERNEL_MCS
#error "This driver should only be selected for MCS kernel"
#endif /* CONFIG_KERNEL_MCS */
/* gptir and gptsr bits */
#define OF1IE 0 /* output compare 1 */
#define ROV 5 /* roll over */
/* Memory map for GPT (General Purpose Timer). */
struct timer {
uint32_t gptcr; /* control */
uint32_t gptpr; /* prescaler */
uint32_t gptsr; /* status register */
uint32_t gptir; /* interrupt register */
uint32_t gptcr1;
uint32_t gptcr2;
uint32_t gptcr3;
uint32_t gpticr1;
uint32_t gpticr2;
uint32_t gptcnt;
};
typedef volatile struct timer timer_t;
extern timer_t *gpt;
extern ticks_t high_bits;
static inline ticks_t getCurrentTime(void)
{
return ((high_bits + !!(gpt->gptsr & BIT(ROV))) << 32llu) + gpt->gptcnt;
}
static inline void setDeadline(ticks_t deadline)
{
if (((uint32_t) deadline) > gpt->gptcnt) {
/* turn on compare irq */
gpt->gptir |= BIT(OF1IE);
/* set the deadline */
do {
gpt->gptcr1 = (uint32_t) deadline;
} while (gpt->gptcr1 != (uint32_t) deadline);
}
}
static inline void ackDeadlineIRQ(void)
{
if (gpt->gptsr & BIT(ROV)) {
high_bits++;
}
/* turn off compare irq */
gpt->gptir &= ~(BIT(OF1IE));
/* ack either irq */
gpt->gptsr |= (BIT(OF1IE) | BIT(ROV));
}
#endif /* !__DRIVERS_TIMER_IMX31_GPT_H */

View File

@@ -37,6 +37,7 @@ register_driver(
PREFIX src/drivers/timer
CFILES "imx31-epit.c"
)
register_driver(compatibility_strings "fsl,imx31-gpt" PREFIX src/drivers/timer CFILES "imx31-gpt.c")
register_driver(
compatibility_strings "ti,omap3430-timer"
PREFIX src/drivers/timer

View File

@@ -0,0 +1,53 @@
/*
* Copyright 2019, Data61
* Commonwealth Scientific and Industrial Research Organisation (CSIRO)
* ABN 41 687 119 230.
*
* This software may be distributed and modified according to the terms of
* the GNU General Public License version 2. Note that NO WARRANTY is provided.
* See "LICENSE_GPLv2.txt" for details.
*
* @TAG(DATA61_GPL)
*/
#include <config.h>
#include <types.h>
#include <machine/io.h>
#include <kernel/vspace.h>
#include <arch/machine.h>
#include <arch/kernel/vspace.h>
#include <linker.h>
/* gptcr bits */
#define EN 0
#define ENMOD 1
#define FRR 9
#define CLKSRC 6
#define SWR 15
timer_t *gpt = (timer_t *) TIMER_PPTR;
ticks_t high_bits = 0;
enum IPGConstants {
IPG_CLK = 1,
IPG_CLK_HIGHFREQ = 2,
IPG_CLK_32K = 3
};
interrupt_t active_irq = irqInvalid;
BOOT_CODE void initTimer(void)
{
/* reset the gpt */
gpt->gptcr = 0;
/* clear the status register */
gpt->gptcr = 0x3F;
/* software reset */
gpt->gptcr = BIT(SWR);
/* configure the gpt */
gpt->gptcr = BIT(ENMOD) | BIT(FRR) | (IPG_CLK_HIGHFREQ << CLKSRC);
/* enable overflow irq */
gpt->gptir = BIT(ROV);
/* turn it on */
gpt->gptcr |= BIT(EN);
}

View File

@@ -22,14 +22,24 @@ if(KernelPlatformKZM)
set(KernelArmMach "imx" CACHE INTERNAL "")
list(APPEND KernelDTSList "tools/dts/kzm.dts")
list(APPEND KernelDTSList "src/plat/imx31/overlay-kzm.dts")
if(KernelIsMCS)
list(APPEND KernelDTSList "src/plat/imx31/mcs-overlay-kzm.dts")
set(TimerFrequency 18600000llu) # 18.6MHz -- calculated by trial and error, roughly precise
set(TimerDriver drivers/timer/imx31-gpt.h)
else()
set(TimerFrequency 32768llu)
set(TimerDriver drivers/timer/imx31-epit.h)
add_bf_source_old("KernelPlatformKZM" "imx31-epit.bf" "include" "drivers/timer")
endif()
declare_default_headers(
TIMER_FREQUENCY 32768llu
TIMER_FREQUENCY ${TimerFrequency}
MAX_IRQ 63
INTERRUPT_CONTROLLER drivers/irq/imx31.h
TIMER drivers/timer/imx31-epit.h
TIMER ${TimerDriver}
KERNEL_WCET 10u
CLK_SHIFT 47u
CLK_MAGIC 7566531633llu
)
endif()
add_sources(DEP "KernelPlatformKZM" CFILES src/plat/imx31/machine/hardware.c)
add_bf_source_old("KernelPlatformKZM" "imx31-epit.bf" "include" "drivers/timer")

View File

@@ -0,0 +1,21 @@
/*
* Copyright 2019, Data61
* Commonwealth Scientific and Industrial Research Organisation (CSIRO)
* ABN 41 687 119 230.
*
* This software may be distributed and modified according to the terms of
* the GNU General Public License version 2. Note that NO WARRANTY is provided.
* See "LICENSE_GPLv2.txt" for details.
*
* @TAG(DATA61_GPL)
*/
/ {
chosen {
seL4,kernel-devices =
"serial0",
&{/interrupt-controller@68000000},
&{/l2cc@30000000},
&{/soc/aips@53f00000/timer@53f90000};
};
};

View File

@@ -176,6 +176,7 @@ devices:
index: 0
kernel: TIMER_PPTR
interrupts:
# IMX6 also has the imx31-gpt.
KERNEL_TIMER_IRQ: 0
# i.MX EPIT (no Linux binding, this is seL4-specific.)
- compatible:
@@ -186,6 +187,15 @@ devices:
kernel: EPIT_PPTR
interrupts:
KERNEL_TIMER_IRQ: 0
# i.MX GPT
- compatible:
- fsl,imx31-gpt
regions:
- executeNever: true
index: 0
kernel: TIMER_PPTR
interrupts:
KERNEL_TIMER_IRQ: 0
# QCOM Krait timer (timer/qcom,msm-timer.txt)
- compatible:
- qcom,kpss-timer