1/*
2 * Copyright 2014, General Dynamics C4 Systems
3 *
4 * This software may be distributed and modified according to the terms of
5 * the GNU General Public License version 2. Note that NO WARRANTY is provided.
6 * See "LICENSE_GPLv2.txt" for details.
7 *
8 * @TAG(GD_GPL)
9 */
10
11#include <config.h>
12#include <types.h>
13#include <machine/io.h>
14#include <kernel/vspace.h>
15#include <arch/machine.h>
16#include <arch/kernel/vspace.h>
17#include <plat/machine.h>
18#include <linker.h>
19#include <plat/machine/devices.h>
20#include <plat/machine/hardware.h>
21#include <plat/machine/timer.h>
22
23#define TIOCP_CFG_SOFTRESET BIT(0)
24
25#define TIER_MATCHENABLE BIT(0)
26#define TIER_OVERFLOWENABLE BIT(1)
27#define TIER_COMPAREENABLE BIT(2)
28
29#define TCLR_AUTORELOAD BIT(1)
30#define TCLR_COMPAREENABLE BIT(6)
31#define TCLR_STARTTIMER BIT(0)
32
33timer_t *timer = (timer_t *) DMTIMER0_PPTR;
34
35#define WDT_REG(base, off) ((volatile uint32_t *)((base) + (off)))
36#define WDT_REG_WWPS 0x34
37#define WDT_REG_WSPR 0x48
38#define WDT_WWPS_PEND_WSPR BIT(4)
39
40static BOOT_CODE void
41disableWatchdog(void)
42{
43    uint32_t wdt = WDT1_PPTR;
44
45    // am335x ref man, sec 20.4.3.8
46    *WDT_REG(wdt, WDT_REG_WSPR) = 0xaaaa;
47    while ((*WDT_REG(wdt, WDT_REG_WWPS) & WDT_WWPS_PEND_WSPR)) {
48        continue;
49    }
50    *WDT_REG(wdt, WDT_REG_WSPR) = 0x5555;
51    while ((*WDT_REG(wdt, WDT_REG_WWPS) & WDT_WWPS_PEND_WSPR)) {
52        continue;
53    }
54}
55
56/*
57 * Enable DMTIMER clocks, otherwise their registers wont be accessible.
58 * This could be moved out of kernel.
59 */
60static BOOT_CODE void
61enableTimers(void)
62{
63    uint32_t cmper = CMPER_PPTR;
64
65    /* XXX repeat this for DMTIMER4..7 */
66    /* select clock */
67    *CMPER_REG(cmper, CMPER_CLKSEL_TIMER3) = CMPER_CKLSEL_MOSC;
68    while ((*CMPER_REG(cmper, CMPER_CLKSEL_TIMER3) & 3) != CMPER_CKLSEL_MOSC) {
69        continue;
70    }
71
72    /* enable clock */
73    *CMPER_REG(cmper, CMPER_TIMER3_CLKCTRL) = CMPER_CLKCTRL_ENABLE;
74    while ((*CMPER_REG(cmper, CMPER_TIMER3_CLKCTRL) & 3) != CMPER_CLKCTRL_ENABLE) {
75        continue;
76    }
77}
78
79/* Configure dmtimer0 as kernel preemption timer */
80BOOT_CODE void
81initTimer(void)
82{
83    int timeout;
84
85    disableWatchdog();
86    enableTimers();
87
88    timer->cfg = TIOCP_CFG_SOFTRESET;
89
90    for (timeout = 10000; (timer->cfg & TIOCP_CFG_SOFTRESET) && timeout > 0; timeout--)
91        ;
92    if (!timeout) {
93        printf("init timer failed\n");
94        return;
95    }
96
97    maskInterrupt(/*disable*/ true, DMTIMER0_IRQ);
98
99    /* Set the reload value */
100    timer->tldr = 0xFFFFFFFFUL - TIMER_RELOAD;
101
102    /* Enables interrupt on overflow */
103    timer->tier = TIER_OVERFLOWENABLE;
104
105    /* Clear the read register */
106    timer->tcrr = 0xFFFFFFFFUL - TIMER_RELOAD;
107
108    /* Set autoreload and start the timer */
109    timer->tclr = TCLR_AUTORELOAD | TCLR_STARTTIMER;
110}
111
112BOOT_CODE void
113initIRQController(void)
114{
115    intc->intcps_sysconfig = INTCPS_SYSCONFIG_SOFTRESET;
116    while (!(intc->intcps_sysstatus & INTCPS_SYSSTATUS_RESETDONE)) ;
117}
118
119BOOT_CODE void cpu_initLocalIRQController(void) {}
120
121void plat_cleanL2Range(paddr_t start, paddr_t end) {}
122void plat_invalidateL2Range(paddr_t start, paddr_t end) {}
123void plat_cleanInvalidateL2Range(paddr_t start, paddr_t end) {}
124void plat_cleanInvalidateCache(void) {}
125