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/time_source.h>
12 #include <libfdt.h>
13 #include <matrix.h>
14 #include <sama5d2.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 static const char * const tcb_clocks[] = { "t0_clk", "gclk", "slow_clk" };
54 static vaddr_t tcb_base;
55 static uint32_t tcb_rate;
56 
atmel_tcb_enable_clocks(const void * fdt,int node)57 static TEE_Result atmel_tcb_enable_clocks(const void *fdt, int node)
58 {
59 	unsigned int i = 0;
60 	struct clk *clk = NULL;
61 	TEE_Result res = TEE_ERROR_GENERIC;
62 
63 	for (i = 0; i < ARRAY_SIZE(tcb_clocks); i++) {
64 		res = clk_dt_get_by_name(fdt, node, tcb_clocks[i], &clk);
65 		if (res)
66 			return res;
67 
68 		clk_enable(clk);
69 	}
70 
71 	return TEE_SUCCESS;
72 }
73 
atmel_tcb_get_sys_time(TEE_Time * time)74 static TEE_Result atmel_tcb_get_sys_time(TEE_Time *time)
75 {
76 	uint64_t cv0 = 0;
77 	uint64_t cv1 = 0;
78 
79 	if (!tcb_base)
80 		return TEE_ERROR_BAD_STATE;
81 
82 	do {
83 		cv1 = io_read32(tcb_base + TCB_CV(1));
84 		cv0 = io_read32(tcb_base + TCB_CV(0));
85 	} while (io_read32(tcb_base + TCB_CV(1)) != cv1);
86 
87 	cv0 |= cv1 << 32;
88 
89 	time->seconds = cv0 / tcb_rate;
90 	time->millis = (cv0 % tcb_rate) / (tcb_rate / TEE_TIME_MILLIS_BASE);
91 
92 	return TEE_SUCCESS;
93 }
94 
95 static const struct time_source atmel_tcb_time_source = {
96 	.name = "atmel_tcb",
97 	.protection_level = 1000,
98 	.get_sys_time = atmel_tcb_get_sys_time,
99 };
100 
REGISTER_TIME_SOURCE(atmel_tcb_time_source)101 REGISTER_TIME_SOURCE(atmel_tcb_time_source)
102 
103 static void atmel_tcb_configure(void)
104 {
105 	/* Disable write protection */
106 	io_write32(tcb_base + TCB_WPMR, TCB_WPMR_WAKEY);
107 
108 	/* Disable all irqs for both channel 0 & 1 */
109 	io_write32(tcb_base + TCB_IDR(0), 0xff);
110 	io_write32(tcb_base + TCB_IDR(1), 0xff);
111 
112 	/*
113 	 * In order to avoid wrapping, use a 64 bit counter by chaining
114 	 * two channels. We use the slow_clk which runs at 32K and is sufficient
115 	 * for the millisecond precision, this will wrap in approximately
116 	 * 17851025 years so no worries here.
117 	 *
118 	 * Channel 0 is configured to generate a clock on TIOA0 which is cleared
119 	 * when reaching 0x80000000 and set when reaching 0.
120 	 */
121 	io_write32(tcb_base + TCB_CMR(0),
122 		   TCB_CMR_TIMER_CLOCK5 | TCB_CMR_WAVE | TCB_CMR_ACPA_SET |
123 		   TCB_CMR_ACPC_CLEAR);
124 	io_write32(tcb_base + TCB_RC(0), 0x80000000);
125 	io_write32(tcb_base + TCB_RA(0), 0x1);
126 	io_write32(tcb_base + TCB_CCR(0), TCB_CCR_CLKEN);
127 
128 	/* Channel 1 is configured to use TIOA0 as input */
129 	io_write32(tcb_base + TCB_CMR(1), TCB_CMR_XC1 | TCB_CMR_WAVE);
130 	io_write32(tcb_base + TCB_CCR(1), TCB_CCR_CLKEN);
131 
132 	/* Set XC1 input to be TIOA0 (ie output of Channel 0) */
133 	io_write32(tcb_base + TCB_BMR, TCB_BMR_TC1XC1S_TIOA0);
134 
135 	/* Sync & start all timers */
136 	io_write32(tcb_base + TCB_BCR, TCB_BCR_SYNC);
137 
138 	/* Enable write protection */
139 	io_write32(tcb_base + TCB_WPMR, TCB_WPMR_WAKEY | 1);
140 }
141 
atmel_tcb_check(void)142 static TEE_Result atmel_tcb_check(void)
143 {
144 	if (!tcb_base)
145 		panic("Missing TCB base ! Check the device-tree");
146 
147 	return TEE_SUCCESS;
148 }
149 
150 boot_final(atmel_tcb_check);
151 
atmel_tcb_probe(const void * fdt,int node,const void * compat_data __unused)152 static TEE_Result atmel_tcb_probe(const void *fdt, int node,
153 				  const void *compat_data __unused)
154 {
155 	size_t size = 0;
156 	struct clk *clk = NULL;
157 	TEE_Result res = TEE_ERROR_GENERIC;
158 	unsigned int peri_id = AT91C_ID_TC0;
159 
160 	/* Enable all TCB clocks */
161 	res = atmel_tcb_enable_clocks(fdt, node);
162 	if (res)
163 		return res;
164 
165 	if (tcb_base)
166 		return TEE_SUCCESS;
167 
168 	if (_fdt_get_status(fdt, node) != DT_STATUS_OK_SEC)
169 		return TEE_SUCCESS;
170 
171 	res = clk_dt_get_by_name(fdt, node, "slow_clk", &clk);
172 	if (res)
173 		return res;
174 
175 	if (dt_map_dev(fdt, node, &tcb_base, &size, DT_MAP_AUTO) < 0)
176 		return TEE_ERROR_GENERIC;
177 
178 	if (tcb_base == AT91C_BASE_TC0)
179 		peri_id = AT91C_ID_TC0;
180 	else
181 		peri_id = AT91C_ID_TC1;
182 
183 	matrix_configure_periph_secure(peri_id);
184 
185 	tcb_rate = clk_get_rate(clk);
186 	assert(tcb_rate);
187 
188 	atmel_tcb_configure();
189 
190 	return TEE_SUCCESS;
191 }
192 
193 static const struct dt_device_match atmel_tcb_match_table[] = {
194 	{ .compatible = "atmel,sama5d2-tcb" },
195 	{ }
196 };
197 
198 DEFINE_DT_DRIVER(atmel_tcb_dt_driver) = {
199 	.name = "atmel_tcb",
200 	.type = DT_DRIVER_NOTYPE,
201 	.match_table = atmel_tcb_match_table,
202 	.probe = atmel_tcb_probe,
203 };
204