1/*
2 * Copyright 2018, Data61
3 * Commonwealth Scientific and Industrial Research Organisation (CSIRO)
4 * ABN 41 687 119 230.
5 *
6 * This software may be distributed and modified according to the terms of
7 * the GNU General Public License version 2. Note that NO WARRANTY is provided.
8 * See "LICENSE_GPLv2.txt" for details.
9 *
10 * @TAG(DATA61_GPL)
11 */
12
13/*
14 *
15 * Copyright 2016, 2017 Hesham Almatary, Data61/CSIRO <hesham.almatary@data61.csiro.au>
16 * Copyright 2015, 2016 Hesham Almatary <heshamelmatary@gmail.com>
17 */
18
19#include <types.h>
20#include <util.h>
21#include <machine/io.h>
22#include <kernel/vspace.h>
23#include <arch/machine.h>
24#include <arch/kernel/vspace.h>
25#include <plat/machine.h>
26#include <linker.h>
27#include <plat/machine/devices.h>
28#include <plat/machine/hardware.h>
29#include <arch/sbi.h>
30
31#define MAX_AVAIL_P_REGS 2
32
33#define RESET_CYCLES ((CONFIG_SPIKE_CLOCK_FREQ / MS_IN_S) * CONFIG_TIMER_TICK_MS)
34
35/* Available physical memory regions on platform (RAM minus kernel image). */
36/* NOTE: Regions are not allowed to be adjacent! */
37
38static word_t BOOT_DATA num_avail_p_regs = 0;
39static p_region_t BOOT_DATA avail_p_regs[MAX_AVAIL_P_REGS];
40
41BOOT_CODE int get_num_avail_p_regs(void)
42{
43    return num_avail_p_regs;
44}
45
46BOOT_CODE p_region_t get_avail_p_reg(unsigned int i)
47{
48    return avail_p_regs[i];
49}
50
51BOOT_CODE bool_t add_avail_p_reg(p_region_t reg)
52{
53    if (num_avail_p_regs == MAX_AVAIL_P_REGS) {
54        return false;
55    }
56    avail_p_regs[num_avail_p_regs] = reg;
57    num_avail_p_regs++;
58    return true;
59}
60
61/**
62   DONT_TRANSLATE
63 */
64interrupt_t
65getActiveIRQ(void)
66{
67
68    uint64_t temp = 0;
69    asm volatile ("csrr %0, scause":"=r" (temp)::);
70
71    if (!(temp & BIT(CONFIG_WORD_SIZE - 1))) {
72        return irqInvalid;
73    }
74
75    return (temp & 0xf);
76}
77
78/* Check for pending IRQ */
79bool_t isIRQPending(void)
80{
81    return (getActiveIRQ() != irqInvalid);
82}
83
84/* Enable or disable irq according to the 'disable' flag. */
85/**
86   DONT_TRANSLATE
87*/
88void
89maskInterrupt(bool_t disable, interrupt_t irq)
90{
91    if (disable) {
92        if (irq > 1) {
93            clear_sie_mask(BIT(irq));
94        }
95    } else {
96        /* FIXME: currently only account for user/supervisor and timer interrupts */
97        if (irq == 4 /* user timer */ || irq == 5 /* supervisor timer */) {
98            set_sie_mask(BIT(irq));
99        } else {
100            /* TODO: account for external and PLIC interrupts */
101        }
102    }
103}
104
105/* Determine if the given IRQ should be reserved by the kernel. */
106bool_t CONST
107isReservedIRQ(irq_t irq)
108{
109    printf("isReservedIRQ \n");
110    return false;
111}
112
113/* Handle a platform-reserved IRQ. */
114void
115handleReservedIRQ(irq_t irq)
116{
117    printf("handleReservedIRQ \n");
118}
119
120void
121ackInterrupt(irq_t irq)
122{
123    // don't ack the kernel timer interrupt, see the comment in resetTimer
124    // to understand why
125    if (irq != KERNEL_TIMER_IRQ) {
126        clear_sip_mask(BIT(irq));
127    }
128    //set_csr(scause, 0);
129
130    if (irq == 1) {
131        sbi_clear_ipi();
132    }
133}
134
135static inline uint64_t get_cycles(void)
136#if __riscv_xlen == 32
137{
138    uint32_t nH, nL;
139    __asm__ __volatile__ (
140        "rdtimeh %0\n"
141        "rdtime  %1\n"
142        : "=r" (nH), "=r" (nL));
143    return ((uint64_t) ((uint64_t) nH << 32)) | (nL);
144}
145#else
146{
147    uint64_t n;
148    __asm__ __volatile__ (
149        "rdtime %0"
150        : "=r" (n));
151    return n;
152}
153#endif
154
155static inline int read_current_timer(unsigned long *timer_val)
156{
157    *timer_val = get_cycles();
158    return 0;
159}
160
161void
162resetTimer(void)
163{
164    uint64_t target;
165    // ack the timer interrupt. we do this here as due to slow simulation platform there
166    // is a race between us setting the new interrupt here, and the ackInterrupt call in
167    // handleInterrupt that will happen at some point after this call to resetTimer
168    clear_sip_mask(KERNEL_TIMER_IRQ);
169    // repeatedly try and set the timer in a loop as otherwise there is a race and we
170    // may set a timeout in the past, resulting in it never getting triggered
171    do {
172        target = get_cycles() + RESET_CYCLES;
173        sbi_set_timer(target);
174    } while (get_cycles() > target);
175}
176
177/**
178   DONT_TRANSLATE
179 */
180BOOT_CODE void
181initTimer(void)
182{
183    sbi_set_timer(get_cycles() + RESET_CYCLES);
184}
185
186void plat_cleanL2Range(paddr_t start, paddr_t end)
187{
188}
189void plat_invalidateL2Range(paddr_t start, paddr_t end)
190{
191}
192
193void plat_cleanInvalidateL2Range(paddr_t start, paddr_t end)
194{
195}
196
197/**
198   DONT_TRANSLATE
199 */
200BOOT_CODE void
201initL2Cache(void)
202{
203}
204
205/**
206   DONT_TRANSLATE
207 */
208BOOT_CODE void
209initIRQController(void)
210{
211    /* Do nothing */
212}
213
214void
215handleSpuriousIRQ(void)
216{
217    /* Do nothing */
218    printf("Superior IRQ!! \n");
219}
220