blob: a6e1afa63584ce8b7618c00e535a9e02c46b0447 [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
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{
72 /* Disable Interrupt */
73 timer_write_32(TTC_IER_OFFSET, 0);
74
75 /* Disable Counter */
76 timer_write_32(TTC_CLK_CNTRL_OFFSET, !CLK_CNTRL_PRESCALE_EN);
77 timer_write_32(TTC_CNT_CNTRL_OFFSET, !CLK_CNTRL_PRESCALE_EN);
78
79 return RET_SUCCESS;
80}
81
82static void clocksetup(void)
83{
84 timer_write_32(TTC_OFFSET_TMR_0 + TTC_CLK_CNTRL_OFFSET, 0x0);
85
86 mmio_write_32(LPD_IOU_SLCR + TTC_CLK_SEL_OFFSET, TTC_CLK_SEL_PS_REF);
87
88 VERBOSE("%s TTC_CLK_SEL = 0x%x\n", __func__,
89 mmio_read_32(LPD_IOU_SLCR + TTC_CLK_SEL_OFFSET));
90}
91
92static void setcounts(unsigned long time_out_ms)
93{
94 unsigned long intrvl = (time_out_ms / INTERVAL) + (time_out_ms % INTERVAL);
95
96 timer_write_32(TTC_INTR_VAL_OFFSET, intrvl);
97}
98
99static int program_timer(unsigned long time_out_ms)
100{
101 uint32_t reg;
102
103 /* Disable and program the counter */
104 reg = timer_read_32(TTC_CNT_CNTRL_OFFSET);
105 reg |= TTC_CNT_CNTRL_DISABLE_MASK;
106 timer_write_32(TTC_CNT_CNTRL_OFFSET, reg);
107
108 setcounts(time_out_ms);
109
110 /* Enable the interrupt */
111 timer_write_32(TTC_IER_OFFSET, 0x01);
112
113 /* Enable the counter */
114 reg |= CNT_CNTRL_RESET;
115 reg &= ~TTC_CNT_CNTRL_DISABLE_MASK;
116 timer_write_32(TTC_CNT_CNTRL_OFFSET, reg);
117
118 return RET_SUCCESS;
119}
120
121static int handler_timer(void)
122{
123 uint32_t status;
124
125 /* Disable the interrupts */
126 timer_write_32(TTC_IER_OFFSET, 0x00);
127
128 status = timer_read_32(TTC_ISR_OFFSET);
129 if (status & 0x1)
130 INFO("Timer Event! %x\n", status);
131 else
132 ERROR("Its not a Timer Event %d\n", status);
133
134 return RET_SUCCESS;
135}
136
Prasad Kummari1d8f2222023-08-25 12:02:33 +0530137static const plat_timer_t timers = {
Akshay Belsare52aefd92023-04-04 10:26:40 +0530138 .program = program_timer,
139 .cancel = cancel_timer,
140 .handler = handler_timer,
141 .timer_step_value = INTERVAL,
Prasad Kummari1d8f2222023-08-25 12:02:33 +0530142 .timer_irq = TTC_TIMER_IRQ
Akshay Belsare52aefd92023-04-04 10:26:40 +0530143};
144
145int plat_initialise_timer_ops(const plat_timer_t **timer_ops)
146{
147 assert(timer_ops != NULL);
148
149 /* Disable all Interrupts on the TTC */
150 timer_write_32(TTC_OFFSET_TMR_0 + TTC_IER_OFFSET, 0);
151 timer_write_32(TTC_OFFSET_TMR_1 + TTC_IER_OFFSET, 0);
152 timer_write_32(TTC_OFFSET_TMR_2 + TTC_IER_OFFSET, 0);
153
154 clocksetup();
155
156 /*
157 * Setup the clock event timer to be an interval timer which
158 * is prescaled by 32 using the interval interrupt. Leave it
159 * disabled for now.
160 */
161 timer_write_32(TTC_OFFSET_TMR_0 + TTC_CNT_CNTRL_OFFSET, 0x23);
162 timer_write_32(TTC_OFFSET_TMR_0 + TTC_CLK_CNTRL_OFFSET,
Prasad Kummari1d8f2222023-08-25 12:02:33 +0530163 CLK_CNTRL_PRESCALE | CLK_CNTRL_PRESCALE_EN);
Akshay Belsare52aefd92023-04-04 10:26:40 +0530164 timer_write_32(TTC_OFFSET_TMR_0 + TTC_IER_OFFSET, 0x01);
165
Prasad Kummari1d8f2222023-08-25 12:02:33 +0530166 *timer_ops = &timers;
Akshay Belsare52aefd92023-04-04 10:26:40 +0530167
168 return RET_SUCCESS;
169}