1/**
2 * \file
3 * \brief Platform code for the Cortex-A15 MPCore.
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, Universitaetstr. 6, CH-8092 Zurich. Attn: Systems Group.
13 */
14
15#include <a15_gt.h>
16#include <maps/a15mpcore_map.h>
17#include <assert.h>
18#include <cp15.h>
19#include <gic.h>
20#include <kernel.h>
21#include <init.h>
22#include <paging_kernel_arch.h>
23#include <platform.h>
24#include <systime.h>
25
26#define MSG(format, ...) \
27    printk( LOG_NOTE, "CortexA15 platform: "format, ## __VA_ARGS__ )
28
29/* These are called from the A9/A15 common GIC (interrupt controller) code. */
30
31lpaddr_t
32platform_get_distributor_address(void) {
33    assert(paging_mmu_enabled());
34    return platform_get_private_region() + A15MPCORE_GICD_OFFSET;
35}
36
37lpaddr_t
38platform_get_gic_cpu_address(void) {
39    assert(paging_mmu_enabled());
40    return platform_get_private_region() + A15MPCORE_GICC_OFFSET;
41}
42
43/* A15 platforms don't need anything special done. */
44void
45platform_revision_init(void) {
46}
47
48/*
49 * Return the core count from the interrupt controller
50 */
51size_t
52platform_get_core_count(void) {
53    return gic_cpu_count();
54}
55
56/* Timeslice counter uses the Non-secure Physical Timer. */
57
58/* See TRM 8.2.3 */
59/* This *should* be IRQ 30, for the non-secure timer, but GEM5 only
60 * provides the secure timer, even in NS mode.
61 * The timerirq parameter allows this to be overridden. */
62
63/// For now, use secure timer
64#define DEFAULT_TIMER_IRQ 29
65
66extern uint32_t timerirq;
67extern uint32_t cntfrq;
68
69void
70timers_init(int timeslice) {
71    /* If there was a cntfrq parameter passed, then overwrite the current
72     * CNTFRQ register.  We need to do this if there was no bootloader to set
73     * it for us, as on the FVP simulators. */
74    if(cntfrq != 0) a15_gt_set_cntfrq(cntfrq);
75
76    systime_frequency = a15_gt_frequency();
77
78    /* The timeslice is in ms, so divide by 1000. */
79    kernel_timeslice = ns_to_systime(timeslice * 1000000);
80
81    MSG("System counter frequency is %uHz.\n", systime_frequency);
82    MSG("Timeslice interrupt every %u ticks (%dms).\n",
83            kernel_timeslice, timeslice);
84
85    a15_gt_init();
86
87    if(timerirq == 0) timerirq= DEFAULT_TIMER_IRQ;
88    MSG("Timer interrupt is %u\n", timerirq);
89
90    /* Enable the interrupt. */
91    gic_enable_interrupt(timerirq, 0, 0, 0, 0);
92
93    /* Set the first timeout. */
94    systime_set_timeout(systime_now() + kernel_timeslice);
95
96    /* We use the system counter for timestamps, which doesn't need any
97     * further initialisation. */
98}
99
100uint64_t
101timestamp_read(void) {
102    return a15_gt_counter();
103}
104
105uint32_t
106timestamp_freq(void) {
107    return a15_gt_frequency();
108}
109
110bool timer_interrupt(uint32_t irq)
111{
112    if (irq == timerirq) {
113        gic_ack_irq(irq);
114        a15_gt_mask_interrupt();
115
116        /* Reset the timeout. */
117        uint64_t now = systime_now();
118        systime_set_timeout(now + kernel_timeslice);
119        return 1;
120    }
121
122    return 0;
123}
124
125systime_t systime_now(void)
126{
127    return a15_gt_counter();
128}
129
130void systime_set_timeout(systime_t timeout)
131{
132    a15_gt_set_comparator(timeout);
133}
134