1 // SPDX-License-Identifier: BSD-2-Clause
2 /*
3 * Copyright (c) 2022, Microchip
4 */
5
6 #include <assert.h>
7 #include <drivers/clk.h>
8 #include <drivers/clk_dt.h>
9 #include <io.h>
10 #include <kernel/boot.h>
11 #include <kernel/tee_time.h>
12 #include <libfdt.h>
13 #include <matrix.h>
14 #include <platform_config.h>
15 #include <tee_api_defines.h>
16
17 #define TCB_CHAN(chan) ((chan) * 0x40)
18
19 #define TCB_CCR(chan) (0x0 + TCB_CHAN(chan))
20 #define TCB_CCR_SWTRG 0x4
21 #define TCB_CCR_CLKEN 0x1
22
23 #define TCB_CMR(chan) (0x4 + TCB_CHAN(chan))
24 #define TCB_CMR_WAVE BIT32(15)
25 #define TCB_CMR_TIMER_CLOCK5 4
26 #define TCB_CMR_XC1 6
27 #define TCB_CMR_ACPA_SET BIT32(16)
28 #define TCB_CMR_ACPC_CLEAR SHIFT_U32(2, 18)
29
30 #define TCB_CV(chan) (0x10 + TCB_CHAN(chan))
31
32 #define TCB_RA(chan) (0x14 + TCB_CHAN(chan))
33 #define TCB_RB(chan) (0x18 + TCB_CHAN(chan))
34 #define TCB_RC(chan) (0x1c + TCB_CHAN(chan))
35
36 #define TCB_IER(chan) (0x24 + TCB_CHAN(chan))
37 #define TCB_IER_COVFS 0x1
38
39 #define TCB_SR(chan) (0x20 + TCB_CHAN(chan))
40 #define TCB_SR_COVFS 0x1
41
42 #define TCB_IDR(chan) (0x28 + TCB_CHAN(chan))
43
44 #define TCB_BCR 0xc0
45 #define TCB_BCR_SYNC 0x1
46
47 #define TCB_BMR 0xc4
48 #define TCB_BMR_TC1XC1S_TIOA0 SHIFT_U32(2, 2)
49
50 #define TCB_WPMR 0xe4
51 #define TCB_WPMR_WAKEY 0x54494d
52
53 #ifdef CFG_SAMA7G5
54 static const char * const tcb_clocks[] = {
55 "t0_clk", "t1_clk", "t2_clk", "slow_clk"};
56 #else
57 static const char * const tcb_clocks[] = { "t0_clk", "gclk", "slow_clk" };
58 #endif
59 static vaddr_t tcb_base;
60 static uint32_t tcb_rate;
61
atmel_tcb_enable_clocks(const void * fdt,int node)62 static TEE_Result atmel_tcb_enable_clocks(const void *fdt, int node)
63 {
64 unsigned int i = 0;
65 struct clk *clk = NULL;
66 TEE_Result res = TEE_ERROR_GENERIC;
67
68 for (i = 0; i < ARRAY_SIZE(tcb_clocks); i++) {
69 res = clk_dt_get_by_name(fdt, node, tcb_clocks[i], &clk);
70 if (res)
71 return res;
72
73 clk_enable(clk);
74 }
75
76 return TEE_SUCCESS;
77 }
78
tee_time_get_sys_time(TEE_Time * time)79 TEE_Result tee_time_get_sys_time(TEE_Time *time)
80 {
81 uint64_t cv0 = 0;
82 uint64_t cv1 = 0;
83
84 if (!tcb_base)
85 return TEE_ERROR_BAD_STATE;
86
87 do {
88 cv1 = io_read32(tcb_base + TCB_CV(1));
89 cv0 = io_read32(tcb_base + TCB_CV(0));
90 } while (io_read32(tcb_base + TCB_CV(1)) != cv1);
91
92 cv0 |= cv1 << 32;
93
94 time->seconds = cv0 / tcb_rate;
95 time->millis = (cv0 % tcb_rate) / (tcb_rate / TEE_TIME_MILLIS_BASE);
96
97 return TEE_SUCCESS;
98 }
99
tee_time_get_sys_time_protection_level(void)100 uint32_t tee_time_get_sys_time_protection_level(void)
101 {
102 return 1000;
103 }
104
atmel_tcb_configure(void)105 static void atmel_tcb_configure(void)
106 {
107 /* Disable write protection */
108 io_write32(tcb_base + TCB_WPMR, TCB_WPMR_WAKEY);
109
110 /* Disable all irqs for both channel 0 & 1 */
111 io_write32(tcb_base + TCB_IDR(0), 0xff);
112 io_write32(tcb_base + TCB_IDR(1), 0xff);
113
114 /*
115 * In order to avoid wrapping, use a 64 bit counter by chaining
116 * two channels. We use the slow_clk which runs at 32K and is sufficient
117 * for the millisecond precision, this will wrap in approximately
118 * 17851025 years so no worries here.
119 *
120 * Channel 0 is configured to generate a clock on TIOA0 which is cleared
121 * when reaching 0x80000000 and set when reaching 0.
122 */
123 io_write32(tcb_base + TCB_CMR(0),
124 TCB_CMR_TIMER_CLOCK5 | TCB_CMR_WAVE | TCB_CMR_ACPA_SET |
125 TCB_CMR_ACPC_CLEAR);
126 io_write32(tcb_base + TCB_RC(0), 0x80000000);
127 io_write32(tcb_base + TCB_RA(0), 0x1);
128 io_write32(tcb_base + TCB_CCR(0), TCB_CCR_CLKEN);
129
130 /* Channel 1 is configured to use TIOA0 as input */
131 io_write32(tcb_base + TCB_CMR(1), TCB_CMR_XC1 | TCB_CMR_WAVE);
132 io_write32(tcb_base + TCB_CCR(1), TCB_CCR_CLKEN);
133
134 /* Set XC1 input to be TIOA0 (ie output of Channel 0) */
135 io_write32(tcb_base + TCB_BMR, TCB_BMR_TC1XC1S_TIOA0);
136
137 /* Sync & start all timers */
138 io_write32(tcb_base + TCB_BCR, TCB_BCR_SYNC);
139
140 /* Enable write protection */
141 io_write32(tcb_base + TCB_WPMR, TCB_WPMR_WAKEY | 1);
142 }
143
atmel_tcb_check(void)144 static TEE_Result atmel_tcb_check(void)
145 {
146 if (!tcb_base)
147 panic("Missing TCB base ! Check the device-tree");
148
149 return TEE_SUCCESS;
150 }
151
152 boot_final(atmel_tcb_check);
153
atmel_tcb_probe(const void * fdt,int node,const void * compat_data __unused)154 static TEE_Result atmel_tcb_probe(const void *fdt, int node,
155 const void *compat_data __unused)
156 {
157 size_t size = 0;
158 struct clk *clk = NULL;
159 TEE_Result res = TEE_ERROR_GENERIC;
160 unsigned int peri_id = AT91C_ID_TC0;
161
162 /* Enable all TCB clocks */
163 res = atmel_tcb_enable_clocks(fdt, node);
164 if (res)
165 return res;
166
167 if (tcb_base)
168 return TEE_SUCCESS;
169
170 if (fdt_get_status(fdt, node) != DT_STATUS_OK_SEC)
171 return TEE_SUCCESS;
172
173 res = clk_dt_get_by_name(fdt, node, "slow_clk", &clk);
174 if (res)
175 return res;
176
177 res = matrix_dt_get_id(fdt, node, &peri_id);
178 if (res)
179 return res;
180
181 if (dt_map_dev(fdt, node, &tcb_base, &size, DT_MAP_AUTO) < 0)
182 return TEE_ERROR_GENERIC;
183
184 matrix_configure_periph_secure(peri_id);
185
186 tcb_rate = clk_get_rate(clk);
187 assert(tcb_rate);
188
189 atmel_tcb_configure();
190
191 return TEE_SUCCESS;
192 }
193
194 static const struct dt_device_match atmel_tcb_match_table[] = {
195 { .compatible = "atmel,sama5d2-tcb" },
196 { }
197 };
198
199 DEFINE_DT_DRIVER(atmel_tcb_dt_driver) = {
200 .name = "atmel_tcb",
201 .type = DT_DRIVER_NOTYPE,
202 .match_table = atmel_tcb_match_table,
203 .probe = atmel_tcb_probe,
204 };
205