blob: f127bb79a301bc9e278fc972bb08ea18c2250b29 [file] [log] [blame]
anzhou113d2d22020-06-04 13:20:18 +08001/*
2 * Copyright (c) 2020, NVIDIA Corporation. All rights reserved.
3 *
4 * SPDX-License-Identifier: BSD-3-Clause
5 */
6
7#include <assert.h>
8#include <stddef.h>
9#include <platform.h>
10
11#include <mmio.h>
12#include <timer.h>
13#include <tftf_lib.h>
14#include <utils_def.h>
15
16/* timer granularity in ms */
17#define TEGRA_RTC_STEP_VALUE_MS U(5)
18
anzhou113d2d22020-06-04 13:20:18 +080019/* set to 1 = busy every eight 32kHz clocks during copy of sec+msec to AHB */
20#define TEGRA_RTC_REG_BUSY U(0x004)
21#define TEGRA_RTC_REG_SECONDS U(0x008)
22/* when msec is read, the seconds are buffered into shadow seconds. */
23#define TEGRA_RTC_REG_SHADOW_SECONDS U(0x00c)
24#define TEGRA_RTC_REG_MILLI_SECONDS U(0x010)
25#define TEGRA_RTC_REG_SECONDS_ALARM0 U(0x014)
26#define TEGRA_RTC_REG_SECONDS_ALARM1 U(0x018)
27#define TEGRA_RTC_REG_MILLI_SECONDS_ALARM0 U(0x01c)
28#define TEGRA_RTC_REG_MSEC_CDN_ALARM0 U(0x024)
29#define TEGRA_RTC_REG_INTR_MASK U(0x028)
30/* write 1 bits to clear status bits */
31#define TEGRA_RTC_REG_INTR_STATUS U(0x02c)
32
33/*
34 * bits in the TEGRA_RTC_REG_BUSY register
35 * bit 0: 1 = busy, 0 = idle
36 */
37#define TEGRA_RTC_REG_BUSY_BIT BIT_32(0)
38
39/* bits in INTR_MASK and INTR_STATUS */
40#define TEGRA_RTC_INTR_MSEC_CDN_ALARM BIT_32(4)
41#define TEGRA_RTC_INTR_SEC_CDN_ALARM BIT_32(3)
42#define TEGRA_RTC_INTR_MSEC_ALARM BIT_32(2)
43#define TEGRA_RTC_INTR_SEC_ALARM1 BIT_32(1)
44#define TEGRA_RTC_INTR_SEC_ALARM0 BIT_32(0)
45
46static bool is_rtc_busy(void)
47{
48 uint32_t reg = mmio_read_32(TEGRA_RTC_BASE + TEGRA_RTC_REG_BUSY) &
49 TEGRA_RTC_REG_BUSY_BIT;
50
51 /* 1 = busy, 0 = idle */
52 return (reg == 1U);
53}
54
55/*
56 * Wait for hardware to be ready for writing.
57 * This function tries to maximize the amount of time before the next update.
58 * It does this by waiting for the RTC to become busy with its periodic update,
59 * then returning once the RTC first becomes not busy.
60 * This periodic update (where the seconds and milliseconds are copied to the
61 * AHB side) occurs every eight 32kHz clocks (~250uS).
62 * The behavior of this function allows us to make some assumptions without
63 * introducing a race, because 250uS is plenty of time to write a value.
64 */
65static void wait_until_idle(void)
66{
67 uint32_t retries = 500U;
68
69 /* wait until idle */
70 while (is_rtc_busy() || (retries-- > 0U)) {
71 waitus(1ULL);
72 }
73}
74
75static void timer_idle_write_32(uint32_t offset, uint32_t val)
76{
77 /* wait until the RTC is idle first */
78 wait_until_idle();
79
80 /* actual write */
81 mmio_write_32(TEGRA_RTC_BASE + offset, val);
82
83 /* wait until RTC has processed the write */
84 wait_until_idle();
85}
86
87static uint32_t timer_idle_read_32(uint32_t offset)
88{
89 /* wait until the RTC is idle first */
90 wait_until_idle();
91
92 /* actual read */
93 return mmio_read_32(TEGRA_RTC_BASE + offset);
94}
95
96static int cancel_timer(void)
97{
98 /* read current values to clear them */
99 (void)timer_idle_read_32(TEGRA_RTC_REG_MILLI_SECONDS);
100 (void)timer_idle_read_32(TEGRA_RTC_REG_SHADOW_SECONDS);
101
102 /* clear the alarm */
103 timer_idle_write_32(TEGRA_RTC_REG_MSEC_CDN_ALARM0, 0U);
104 /* clear all status values */
105 timer_idle_write_32(TEGRA_RTC_REG_INTR_STATUS, 0xffffffffU);
106 /* disable all interrupts */
107 timer_idle_write_32(TEGRA_RTC_REG_INTR_MASK, 0U);
108
109 return 0;
110}
111
112static int program_timer(unsigned long time_out_ms)
113{
114 uint32_t reg;
115
116 /* set timer value */
117 reg = BIT_32(31) | (0x0fffffffU & time_out_ms);
118 timer_idle_write_32(TEGRA_RTC_REG_MSEC_CDN_ALARM0, reg);
119
120 /* enable timer interrupt */
121 timer_idle_write_32(TEGRA_RTC_REG_INTR_MASK, TEGRA_RTC_INTR_MSEC_ALARM);
122
123 /* program timeout value */
124 reg = timer_idle_read_32(TEGRA_RTC_REG_MILLI_SECONDS);
125 timer_idle_write_32(TEGRA_RTC_REG_MILLI_SECONDS_ALARM0, reg + time_out_ms);
126
127 return 0;
128}
129
130static int handler_timer(void)
131{
132 uint32_t __unused reg, status, mask;
133
134 /* disable timer interrupt */
135 reg = timer_idle_read_32(TEGRA_RTC_REG_INTR_MASK);
136 reg &= ~TEGRA_RTC_INTR_MSEC_CDN_ALARM;
137 timer_idle_write_32(TEGRA_RTC_REG_INTR_MASK, reg);
138
139 /* read current values to clear them */
140 reg = timer_idle_read_32(TEGRA_RTC_REG_MILLI_SECONDS);
141 reg = timer_idle_read_32(TEGRA_RTC_REG_SHADOW_SECONDS);
142
143 /* clear interrupts */
144 status = timer_idle_read_32(TEGRA_RTC_REG_INTR_STATUS);
145 mask = timer_idle_read_32(TEGRA_RTC_REG_INTR_MASK);
146 mask &= ~status;
147 if (status != 0U) {
148 timer_idle_write_32(TEGRA_RTC_REG_INTR_MASK, mask);
149 timer_idle_write_32(TEGRA_RTC_REG_INTR_STATUS, status);
150 }
151
152 return 0;
153}
154
155static const plat_timer_t tegra_timers = {
156 .program = program_timer,
157 .cancel = cancel_timer,
158 .handler = handler_timer,
159 .timer_step_value = TEGRA_RTC_STEP_VALUE_MS,
160 .timer_irq = TEGRA_RTC_IRQ
161};
162
163int plat_initialise_timer_ops(const plat_timer_t **timer_ops)
164{
165 assert(timer_ops != NULL);
166 *timer_ops = &tegra_timers;
167
168 /* clear the timers */
169 cancel_timer();
170
171 return 0;
172}