1/**
2 * \file timers.c
3 * \brief Timer support for ARMv8
4 */
5
6/*
7 * Copyright (c) 2016 ETH Zurich.
8 * All rights reserved.
9 *
10 * This file is distributed under the terms in the attached LICENSE file.
11 * If you do not find this file, copies can be found by writing to:
12 * ETH Zurich D-INFK, Universitaetsstrasse 6, CH-8092 Zurich. Attn: Systems Group.
13 */
14
15#include <kernel.h>
16#include <offsets.h>
17#include <platform.h>
18#include <serial.h>
19#include <sysreg.h>
20#include <arch/arm/gic.h>
21#include <systime.h>
22#include <timers.h>
23#include <dev/armv8_dev.h>
24
25cycles_t ticks_per_ms = 1;
26
27/*
28 * Timers
29 */
30void timers_init(int timeslice)
31{
32    printk(LOG_NOTE, "isr_el1=%p\n", sysreg_read_isr_el1());
33    {
34        //armv8_CNTPS_CTL_EL1_t kctl;
35        armv8_CNTKCTL_EL1_t kctl;
36        kctl = armv8_CNTKCTL_EL1_rd(NULL);
37
38        /* don't trap access to CNTFRQ* and CNTFRQ* registers from EL0 to EL1 */
39        kctl = armv8_CNTKCTL_EL1_EL0PCTEN_insert(kctl, 0x1);
40        kctl = armv8_CNTKCTL_EL1_EL0VCTEN_insert(kctl, 0x1);
41
42        /* trap access to CNTP_* and CNTV_* registers from EL0 to EL1 */
43        kctl = armv8_CNTKCTL_EL1_EL0PTEN_insert(kctl, 0x0);
44        kctl = armv8_CNTKCTL_EL1_EL0VTEN_insert(kctl, 0x0);
45
46        armv8_CNTKCTL_EL1_wr(NULL, kctl);
47    }
48
49    /* enable the timer */
50    armv8_CNTP_CTL_EL0_IMASK_wrf(NULL, 0x0);
51    armv8_CNTP_CTL_EL0_ENABLE_wrf(NULL, 0x1);
52
53    /* set the compare value */
54    armv8_CNTP_CVAL_EL0_wr(NULL, 0xffffffffffffffff);
55
56
57    /* systime_frequency is ticks per milisecond, while timer_get_frequency is in HZ */
58    systime_frequency = timer_get_frequency() / 1000;
59
60    /* The timeslice is in ms */
61    kernel_timeslice = ns_to_systime(timeslice * 1000000);
62
63    printf("System counter frequency is %uHz.\n", timer_get_frequency());
64    printf("Timeslice interrupt every %u ticks (%dms).\n",
65            kernel_timeslice, timeslice);
66
67    // Wait for n time units, close to cycles
68    armv8_CNTP_TVAL_EL0_wr(NULL, 100);
69
70    while (timer_is_set())
71        ;
72
73    timer_reset(timeslice);
74
75    armv8_PMCR_EL0_t pmcr = 0;
76    pmcr = armv8_PMCR_EL0_E_insert(pmcr, 1); /* All counters are enabled.*/
77    pmcr = armv8_PMCR_EL0_P_insert(pmcr, 1); /* reset all event counters */
78    pmcr = armv8_PMCR_EL0_C_insert(pmcr, 1); /* reset all clock counters */
79    pmcr = armv8_PMCR_EL0_D_insert(pmcr, 0); /* set counter to tick every clock cycle (1=ever 64th) */
80    pmcr = armv8_PMCR_EL0_X_insert(pmcr, 1); /* enable event support */
81    pmcr = armv8_PMCR_EL0_DP_insert(pmcr, 0); /* don't disable cycle counter */
82    //pmcr = armv8_PMCR_EL0_N_insert(pmcr, 6);  /* N is RO ? */
83    armv8_PMCR_EL0_wr(NULL, pmcr);
84
85// AT: disable for now because it's not supported by QEMU version<2.6.0
86// AT: doesn't seem to break anything
87//    armv8_PMUSERENR_EL0_t pmu = 0;
88    /* don't trap access to PM registers to EL 1 */
89//    pmu = armv8_PMUSERENR_EL0_EN_insert(pmu, 1);
90    /* don't trap software increment wrap to EL 1 */
91//    pmu = armv8_PMUSERENR_EL0_SW_insert(pmu, 1);
92    /* don't trap cycle counter to EL 1 */
93//    pmu = armv8_PMUSERENR_EL0_CR_insert(pmu, 1);
94    /* don't trap event counter read to EL 1*/
95//    pmu = armv8_PMUSERENR_EL0_ER_insert(pmu, 1);
96//    armv8_PMUSERENR_EL0_wr(NULL, pmu);
97}
98
99/**
100 *
101 * @param ms
102 */
103void timer_reset(uint64_t ms)
104{
105    uint32_t val = ms * systime_frequency;
106    armv8_CNTP_TVAL_EL0_wr(NULL, val);
107}
108
109
110systime_t systime_now(void)
111{
112    return timer_get_timestamp();
113}
114