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