blob: 5c1e8f5cb62120dee7a0111ae892785c53b9ddf7 [file] [log] [blame]
Akshay Belsare52aefd92023-04-04 10:26:40 +05301/*
2 * Copyright (c) 2022-2023, Advanced Micro Devices, Inc. All rights reserved.
3 *
4 * SPDX-License-Identifier: BSD-3-Clause
5 */
6
7#include <assert.h>
8#include <stddef.h>
9
10#include <debug.h>
11#include <mmio.h>
12#include <platform.h>
13#include <tftf_lib.h>
14#include <timer.h>
15#include <utils_def.h>
16
17#define TTC_OFFSET_TMR_0 U(0)
18#define TTC_OFFSET_TMR_1 U(4)
19#define TTC_OFFSET_TMR_2 U(8)
20
21#define TTC_CLK_CNTRL_OFFSET U(0x00) /* Clock Control Reg, RW */
22#define TTC_CNT_CNTRL_OFFSET U(0x0C) /* Counter Control Reg, RW */
23#define TTC_COUNT_VAL_OFFSET U(0x18) /* Counter Value Reg, RO */
24#define TTC_INTR_VAL_OFFSET U(0x24) /* Interval Count Reg, RW */
25#define TTC_ISR_OFFSET U(0x54) /* Interrupt Status Reg, RO */
26#define TTC_IER_OFFSET U(0x60) /* Interrupt Enable Reg, RW */
27
28#define TTC_CNT_CNTRL_DISABLE_MASK BIT(0)
29
30#define TTC_CLK_SEL_OFFSET U(0x360)
31#define TTC_CLK_SEL_MASK GENMASK(1, 0)
32
33#define TTC_CLK_SEL_PS_REF BIT(0)
34#define TTC_CLK_SEL_RPU_REF BIT(4)
35
36#define TIMER_IRQ U(69)
37
38#define RET_SUCCESS U(0)
39
40/*
41 * Setup the timers to use pre-scaling, using a fixed value for now that will
42 * work across most input frequency, but it may need to be more dynamic
43 */
44#define PRESCALE_EXPONENT U(16) /* 2 ^ PRESCALE_EXPONENT = PRESCALE */
45#define PRESCALE U(65536) /* The exponent must match this */
46#define CLK_CNTRL_PRESCALE ((PRESCALE_EXPONENT - 1) << 1U)
47#define CLK_CNTRL_PRESCALE_EN BIT(0)
48#define CNT_CNTRL_RESET BIT(4)
49
50/* Resolution obtained as per the input clock and Prescale value
51 * Clock Selected : PS_REF_CLK
52 * Clock Value : 33333333Hz (33.33MHz)
53 * Prescalar for TTC, N : 15 (highest)
54 * Prescalar Applied 2^(N+1) : 65536
55 * Input clock : (PS_REF_CLK)/Prescalar) : 508.6263Hz
56 * Resolution (1/InputClock) : 1.966miliseconds ~2ms
57 */
58const unsigned long INTERVAL = 2;
59
60static void timer_write_32(uint32_t offset, uint32_t val)
61{
62 /* actual write */
63 mmio_write_32(SYS_CNT_BASE1 + offset, val);
64}
65
66static uint32_t timer_read_32(uint32_t offset)
67{
68 /* actual read */
69 return mmio_read_32(SYS_CNT_BASE1 + offset);
70}
71
72static int cancel_timer(void)
73{
74 /* Disable Interrupt */
75 timer_write_32(TTC_IER_OFFSET, 0);
76
77 /* Disable Counter */
78 timer_write_32(TTC_CLK_CNTRL_OFFSET, !CLK_CNTRL_PRESCALE_EN);
79 timer_write_32(TTC_CNT_CNTRL_OFFSET, !CLK_CNTRL_PRESCALE_EN);
80
81 return RET_SUCCESS;
82}
83
84static void clocksetup(void)
85{
86 timer_write_32(TTC_OFFSET_TMR_0 + TTC_CLK_CNTRL_OFFSET, 0x0);
87
88 mmio_write_32(LPD_IOU_SLCR + TTC_CLK_SEL_OFFSET, TTC_CLK_SEL_PS_REF);
89
90 VERBOSE("%s TTC_CLK_SEL = 0x%x\n", __func__,
91 mmio_read_32(LPD_IOU_SLCR + TTC_CLK_SEL_OFFSET));
92}
93
94static void setcounts(unsigned long time_out_ms)
95{
96 unsigned long intrvl = (time_out_ms / INTERVAL) + (time_out_ms % INTERVAL);
97
98 timer_write_32(TTC_INTR_VAL_OFFSET, intrvl);
99}
100
101static int program_timer(unsigned long time_out_ms)
102{
103 uint32_t reg;
104
105 /* Disable and program the counter */
106 reg = timer_read_32(TTC_CNT_CNTRL_OFFSET);
107 reg |= TTC_CNT_CNTRL_DISABLE_MASK;
108 timer_write_32(TTC_CNT_CNTRL_OFFSET, reg);
109
110 setcounts(time_out_ms);
111
112 /* Enable the interrupt */
113 timer_write_32(TTC_IER_OFFSET, 0x01);
114
115 /* Enable the counter */
116 reg |= CNT_CNTRL_RESET;
117 reg &= ~TTC_CNT_CNTRL_DISABLE_MASK;
118 timer_write_32(TTC_CNT_CNTRL_OFFSET, reg);
119
120 return RET_SUCCESS;
121}
122
123static int handler_timer(void)
124{
125 uint32_t status;
126
127 /* Disable the interrupts */
128 timer_write_32(TTC_IER_OFFSET, 0x00);
129
130 status = timer_read_32(TTC_ISR_OFFSET);
131 if (status & 0x1)
132 INFO("Timer Event! %x\n", status);
133 else
134 ERROR("Its not a Timer Event %d\n", status);
135
136 return RET_SUCCESS;
137}
138
139static const plat_timer_t versal_timers = {
140 .program = program_timer,
141 .cancel = cancel_timer,
142 .handler = handler_timer,
143 .timer_step_value = INTERVAL,
144 .timer_irq = TIMER_IRQ
145};
146
147int plat_initialise_timer_ops(const plat_timer_t **timer_ops)
148{
149 assert(timer_ops != NULL);
150
151 /* Disable all Interrupts on the TTC */
152 timer_write_32(TTC_OFFSET_TMR_0 + TTC_IER_OFFSET, 0);
153 timer_write_32(TTC_OFFSET_TMR_1 + TTC_IER_OFFSET, 0);
154 timer_write_32(TTC_OFFSET_TMR_2 + TTC_IER_OFFSET, 0);
155
156 clocksetup();
157
158 /*
159 * Setup the clock event timer to be an interval timer which
160 * is prescaled by 32 using the interval interrupt. Leave it
161 * disabled for now.
162 */
163 timer_write_32(TTC_OFFSET_TMR_0 + TTC_CNT_CNTRL_OFFSET, 0x23);
164 timer_write_32(TTC_OFFSET_TMR_0 + TTC_CLK_CNTRL_OFFSET,
165 CLK_CNTRL_PRESCALE | CLK_CNTRL_PRESCALE_EN);
166 timer_write_32(TTC_OFFSET_TMR_0 + TTC_IER_OFFSET, 0x01);
167
168 *timer_ops = &versal_timers;
169
170 return RET_SUCCESS;
171}