blob: da8467b52d63180ca97d240020946e7d4422911e [file] [log] [blame]
Akshay Belsare52aefd92023-04-04 10:26:40 +05301/*
Amit Nagal2373cbb2025-04-01 15:18:18 +05302 * Copyright (c) 2022-2025, Advanced Micro Devices, Inc. All rights reserved.
Akshay Belsare52aefd92023-04-04 10:26:40 +05303 *
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)
Amit Nagal2373cbb2025-04-01 15:18:18 +053029#define TTC_ISR_INTERVAL_BIT BIT_32(0)
Akshay Belsare52aefd92023-04-04 10:26:40 +053030
Akshay Belsare52aefd92023-04-04 10:26:40 +053031#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
Akshay Belsare52aefd92023-04-04 10:26:40 +053036#define RET_SUCCESS U(0)
37
38/*
39 * Setup the timers to use pre-scaling, using a fixed value for now that will
40 * work across most input frequency, but it may need to be more dynamic
41 */
42#define PRESCALE_EXPONENT U(16) /* 2 ^ PRESCALE_EXPONENT = PRESCALE */
43#define PRESCALE U(65536) /* The exponent must match this */
44#define CLK_CNTRL_PRESCALE ((PRESCALE_EXPONENT - 1) << 1U)
45#define CLK_CNTRL_PRESCALE_EN BIT(0)
46#define CNT_CNTRL_RESET BIT(4)
47
48/* Resolution obtained as per the input clock and Prescale value
49 * Clock Selected : PS_REF_CLK
50 * Clock Value : 33333333Hz (33.33MHz)
51 * Prescalar for TTC, N : 15 (highest)
52 * Prescalar Applied 2^(N+1) : 65536
53 * Input clock : (PS_REF_CLK)/Prescalar) : 508.6263Hz
54 * Resolution (1/InputClock) : 1.966miliseconds ~2ms
55 */
56const unsigned long INTERVAL = 2;
57
58static void timer_write_32(uint32_t offset, uint32_t val)
59{
60 /* actual write */
61 mmio_write_32(SYS_CNT_BASE1 + offset, val);
62}
63
64static uint32_t timer_read_32(uint32_t offset)
65{
66 /* actual read */
67 return mmio_read_32(SYS_CNT_BASE1 + offset);
68}
69
70static int cancel_timer(void)
71{
Amit Nagal2373cbb2025-04-01 15:18:18 +053072 uint32_t status;
73 uint32_t reg;
74
75 status = timer_read_32(TTC_ISR_OFFSET);
76 if (status & TTC_ISR_INTERVAL_BIT) {
77 VERBOSE("Timer Interval Interrupt Event! %x\n", status);
78 } else {
79 INFO("Its not a Timer Interval Interrupt Event %d\n", status);
80 }
Akshay Belsare52aefd92023-04-04 10:26:40 +053081 /* Disable Interrupt */
82 timer_write_32(TTC_IER_OFFSET, 0);
83
84 /* Disable Counter */
Amit Nagal2373cbb2025-04-01 15:18:18 +053085 reg = timer_read_32(TTC_CNT_CNTRL_OFFSET);
86 reg |= TTC_CNT_CNTRL_DISABLE_MASK;
87 timer_write_32(TTC_CNT_CNTRL_OFFSET, reg);
Akshay Belsare52aefd92023-04-04 10:26:40 +053088
89 return RET_SUCCESS;
90}
91
92static void clocksetup(void)
93{
94 timer_write_32(TTC_OFFSET_TMR_0 + TTC_CLK_CNTRL_OFFSET, 0x0);
95
96 mmio_write_32(LPD_IOU_SLCR + TTC_CLK_SEL_OFFSET, TTC_CLK_SEL_PS_REF);
97
98 VERBOSE("%s TTC_CLK_SEL = 0x%x\n", __func__,
99 mmio_read_32(LPD_IOU_SLCR + TTC_CLK_SEL_OFFSET));
100}
101
102static void setcounts(unsigned long time_out_ms)
103{
104 unsigned long intrvl = (time_out_ms / INTERVAL) + (time_out_ms % INTERVAL);
105
106 timer_write_32(TTC_INTR_VAL_OFFSET, intrvl);
107}
108
109static int program_timer(unsigned long time_out_ms)
110{
111 uint32_t reg;
112
113 /* Disable and program the counter */
114 reg = timer_read_32(TTC_CNT_CNTRL_OFFSET);
115 reg |= TTC_CNT_CNTRL_DISABLE_MASK;
116 timer_write_32(TTC_CNT_CNTRL_OFFSET, reg);
117
118 setcounts(time_out_ms);
119
120 /* Enable the interrupt */
121 timer_write_32(TTC_IER_OFFSET, 0x01);
122
123 /* Enable the counter */
124 reg |= CNT_CNTRL_RESET;
125 reg &= ~TTC_CNT_CNTRL_DISABLE_MASK;
126 timer_write_32(TTC_CNT_CNTRL_OFFSET, reg);
127
128 return RET_SUCCESS;
129}
130
131static int handler_timer(void)
132{
133 uint32_t status;
134
135 /* Disable the interrupts */
136 timer_write_32(TTC_IER_OFFSET, 0x00);
137
138 status = timer_read_32(TTC_ISR_OFFSET);
139 if (status & 0x1)
140 INFO("Timer Event! %x\n", status);
141 else
142 ERROR("Its not a Timer Event %d\n", status);
143
144 return RET_SUCCESS;
145}
146
Prasad Kummari1d8f2222023-08-25 12:02:33 +0530147static const plat_timer_t timers = {
Akshay Belsare52aefd92023-04-04 10:26:40 +0530148 .program = program_timer,
149 .cancel = cancel_timer,
150 .handler = handler_timer,
151 .timer_step_value = INTERVAL,
Prasad Kummari1d8f2222023-08-25 12:02:33 +0530152 .timer_irq = TTC_TIMER_IRQ
Akshay Belsare52aefd92023-04-04 10:26:40 +0530153};
154
155int plat_initialise_timer_ops(const plat_timer_t **timer_ops)
156{
157 assert(timer_ops != NULL);
158
159 /* Disable all Interrupts on the TTC */
160 timer_write_32(TTC_OFFSET_TMR_0 + TTC_IER_OFFSET, 0);
161 timer_write_32(TTC_OFFSET_TMR_1 + TTC_IER_OFFSET, 0);
162 timer_write_32(TTC_OFFSET_TMR_2 + TTC_IER_OFFSET, 0);
163
164 clocksetup();
165
166 /*
167 * Setup the clock event timer to be an interval timer which
168 * is prescaled by 32 using the interval interrupt. Leave it
169 * disabled for now.
170 */
171 timer_write_32(TTC_OFFSET_TMR_0 + TTC_CNT_CNTRL_OFFSET, 0x23);
172 timer_write_32(TTC_OFFSET_TMR_0 + TTC_CLK_CNTRL_OFFSET,
Prasad Kummari1d8f2222023-08-25 12:02:33 +0530173 CLK_CNTRL_PRESCALE | CLK_CNTRL_PRESCALE_EN);
Akshay Belsare52aefd92023-04-04 10:26:40 +0530174 timer_write_32(TTC_OFFSET_TMR_0 + TTC_IER_OFFSET, 0x01);
175
Prasad Kummari1d8f2222023-08-25 12:02:33 +0530176 *timer_ops = &timers;
Akshay Belsare52aefd92023-04-04 10:26:40 +0530177
178 return RET_SUCCESS;
179}