Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
CTCaer
GitHub Repository: CTCaer/hekate
Path: blob/master/bdk/soc/timer.c
1476 views
1
/*
2
* Timer/Watchdog driver for Tegra X1
3
*
4
* Copyright (c) 2019 CTCaer
5
*
6
* This program is free software; you can redistribute it and/or modify it
7
* under the terms and conditions of the GNU General Public License,
8
* version 2, as published by the Free Software Foundation.
9
*
10
* This program is distributed in the hope it will be useful, but WITHOUT
11
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
12
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
13
* more details.
14
*
15
* You should have received a copy of the GNU General Public License
16
* along with this program. If not, see <http://www.gnu.org/licenses/>.
17
*/
18
19
#include <soc/bpmp.h>
20
#include <soc/irq.h>
21
#include <soc/timer.h>
22
#include <soc/t210.h>
23
#include <utils/types.h>
24
25
#define EXCP_TYPE_ADDR 0x4003FFF8
26
#define EXCP_TYPE_WDT 0x544457 // "WDT".
27
28
#define USE_RTC_TIMER
29
30
u32 get_tmr_s()
31
{
32
(void)RTC(APBDEV_RTC_MILLI_SECONDS);
33
return (u32)RTC(APBDEV_RTC_SECONDS);
34
}
35
36
u32 get_tmr_ms()
37
{
38
// The registers must be read with the following order:
39
// RTC_MILLI_SECONDS (0x10) -> RTC_SHADOW_SECONDS (0xC)
40
return (u32)(RTC(APBDEV_RTC_MILLI_SECONDS) + (RTC(APBDEV_RTC_SHADOW_SECONDS) * 1000));
41
}
42
43
u32 get_tmr_us()
44
{
45
return (u32)TMR(TIMERUS_CNTR_1US);
46
}
47
48
void msleep(u32 ms)
49
{
50
#ifdef USE_RTC_TIMER
51
u32 start = (u32)RTC(APBDEV_RTC_MILLI_SECONDS) + (RTC(APBDEV_RTC_SHADOW_SECONDS) * 1000);
52
// Casting to u32 is important!
53
while (((u32)(RTC(APBDEV_RTC_MILLI_SECONDS) + (RTC(APBDEV_RTC_SHADOW_SECONDS) * 1000)) - start) <= ms)
54
;
55
#else
56
bpmp_msleep(ms);
57
#endif
58
}
59
60
void usleep(u32 us)
61
{
62
#ifdef USE_RTC_TIMER
63
u32 start = (u32)TMR(TIMERUS_CNTR_1US);
64
65
// Check if timer is at upper limits and use BPMP sleep so it doesn't wake up immediately.
66
if ((start + us) < start)
67
bpmp_usleep(us);
68
else
69
while ((u32)(TMR(TIMERUS_CNTR_1US) - start) <= us) // Casting to u32 is important!
70
;
71
#else
72
bpmp_usleep(us);
73
#endif
74
}
75
76
// Instruction wait loop. Each loop is 3 cycles (SUBS+BGT). Usage: isleep(ILOOP(instr)). Base 408MHz: 7.35ns.
77
void __attribute__((target("arm"))) isleep(u32 is)
78
{
79
asm volatile( "0:" "SUBS %[is_cnt], #1;" "BGT 0b;" : [is_cnt] "+r" (is));
80
}
81
82
void timer_usleep(u32 us)
83
{
84
TMR(TIMER_TMR8_TMR_PTV) = TIMER_EN | us;
85
86
irq_wait_event(IRQ_TMR8);
87
88
TMR(TIMER_TMR8_TMR_PCR) = TIMER_INTR_CLR;
89
}
90
91
void watchdog_start(u32 us, u32 mode)
92
{
93
// WDT4 is for BPMP.
94
TMR(TIMER_WDT4_UNLOCK_PATTERN) = TIMER_MAGIC_PTRN;
95
TMR(TIMER_TMR9_TMR_PTV) = TIMER_EN | TIMER_PER_EN | us;
96
TMR(TIMER_WDT4_CONFIG) = TIMER_SRC(9) | TIMER_PER(1) | mode;
97
TMR(TIMER_WDT4_COMMAND) = TIMER_START_CNT;
98
}
99
100
void watchdog_end()
101
{
102
// WDT4 is for BPMP.
103
TMR(TIMER_TMR9_TMR_PTV) = 0;
104
TMR(TIMER_WDT4_UNLOCK_PATTERN) = TIMER_MAGIC_PTRN;
105
TMR(TIMER_WDT4_COMMAND) = TIMER_START_CNT; // Re-arm to clear any interrupts.
106
TMR(TIMER_WDT4_COMMAND) = TIMER_CNT_DISABLE;
107
TMR(TIMER_TMR9_TMR_PCR) = TIMER_INTR_CLR;
108
}
109
110
void watchdog_handle()
111
{
112
// Disable watchdog and clear its interrupts.
113
watchdog_end();
114
115
// Set watchdog magic.
116
*(u32 *)EXCP_TYPE_ADDR = EXCP_TYPE_WDT;
117
}
118
119
bool watchdog_fired()
120
{
121
// Return if watchdog got fired. User handles clearing.
122
return (*(u32 *)EXCP_TYPE_ADDR == EXCP_TYPE_WDT);
123
}
124
125