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