1 // SPDX-License-Identifier: BSD-2-Clause
2 /*
3 * Copyright 2021-2023 Microchip
4 */
5
6 #include <assert.h>
7 #include <drivers/clk.h>
8 #include <drivers/clk_dt.h>
9 #include <drivers/i2c.h>
10 #include <io.h>
11 #include <kernel/dt.h>
12 #include <kernel/dt_driver.h>
13 #include <libfdt.h>
14 #include <matrix.h>
15 #include <platform_config.h>
16 #include <string.h>
17
18 #define TWIHS_CR 0x0
19 #define TWIHS_CR_SWRST BIT(7)
20 #define TWIHS_CR_SVDIS BIT(5)
21 #define TWIHS_CR_MSEN BIT(2)
22 #define TWIHS_CR_STOP BIT(1)
23 #define TWIHS_CR_START BIT(0)
24
25 #define TWIHS_MMR 0x4
26 #define TWIHS_MMR_DADR_SHIFT 16
27 #define TWIHS_MMR_DADR_MASK 0x7F
28 #define TWIHS_MMR_MREAD BIT32(12)
29
30 #define TWIHS_CWGR 0x10
31 #define TWIHS_CWGR_HOLD_SHIFT 24
32 #define TWIHS_CWGR_HOLD_MAX 0x1F
33 #define TWIHS_CWGR_CKDIV_SHIFT 16
34 #define TWIHS_CWGR_CKDIV_MAX 0x7
35 #define TWIHS_CWGR_CHDIV_SHIFT 8
36
37 #define TWIHS_CKSRC BIT32(20)
38
39 #define TWIHS_SR 0x20
40 #define TWIHS_SR_NACK BIT32(8)
41 #define TWIHS_SR_TXRDY BIT32(2)
42 #define TWIHS_SR_RXRDY BIT32(1)
43 #define TWIHS_SR_TXCOMP BIT32(0)
44
45 #define TWIHS_RHR 0x30
46 #define TWIHS_THR 0x34
47
48 #define TWIHS_WPMR 0xE4
49 #define TWIHS_WPMR_WPKEY SHIFT_U32(0x545749, 8)
50
51 #define I2C_BUS_FREQ 400000
52
53 struct atmel_i2c {
54 uint32_t sda_hold_time;
55 vaddr_t base;
56 struct clk *clk;
57 struct i2c_ctrl i2c_ctrl;
58 };
59
atmel_i2c_from_i2c_ctrl(struct i2c_ctrl * i2c_ctrl)60 static struct atmel_i2c *atmel_i2c_from_i2c_ctrl(struct i2c_ctrl *i2c_ctrl)
61 {
62 return container_of(i2c_ctrl, struct atmel_i2c, i2c_ctrl);
63 }
64
atmel_i2c_send_one_byte(struct atmel_i2c * i2c,uint8_t byte)65 static TEE_Result atmel_i2c_send_one_byte(struct atmel_i2c *i2c, uint8_t byte)
66 {
67 uint32_t sr = 0;
68
69 io_write32(i2c->base + TWIHS_THR, byte);
70
71 while (true) {
72 sr = io_read32(i2c->base + TWIHS_SR);
73 if (sr & TWIHS_SR_NACK) {
74 EMSG("I2C received NACK while writing");
75 return TEE_ERROR_GENERIC;
76 }
77 if (sr & TWIHS_SR_TXRDY)
78 break;
79 }
80
81 return TEE_SUCCESS;
82 }
83
atmel_i2c_wait_txcomp(struct atmel_i2c * i2c)84 static void atmel_i2c_wait_txcomp(struct atmel_i2c *i2c)
85 {
86 uint32_t sr = 0;
87
88 while (true) {
89 sr = io_read32(i2c->base + TWIHS_SR);
90 if (sr & TWIHS_SR_TXCOMP)
91 return;
92 }
93 }
94
atmel_i2c_send_start(struct atmel_i2c * i2c)95 static void atmel_i2c_send_start(struct atmel_i2c *i2c)
96 {
97 io_write32(i2c->base + TWIHS_CR, TWIHS_CR_START);
98 }
99
atmel_i2c_send_stop(struct atmel_i2c * i2c)100 static void atmel_i2c_send_stop(struct atmel_i2c *i2c)
101 {
102 io_write32(i2c->base + TWIHS_CR, TWIHS_CR_STOP);
103 }
104
atmel_i2c_write_data_no_stop(struct i2c_dev * i2c_dev,const uint8_t * buf,size_t len)105 static TEE_Result atmel_i2c_write_data_no_stop(struct i2c_dev *i2c_dev,
106 const uint8_t *buf, size_t len)
107 {
108 size_t i = 0;
109 TEE_Result res = TEE_ERROR_GENERIC;
110 struct atmel_i2c *i2c = atmel_i2c_from_i2c_ctrl(i2c_dev->ctrl);
111 uint32_t mmr = SHIFT_U32(i2c_dev->addr, TWIHS_MMR_DADR_SHIFT);
112
113 io_write32(i2c->base + TWIHS_MMR, mmr);
114
115 for (i = 0; i < len; i++) {
116 res = atmel_i2c_send_one_byte(i2c, buf[i]);
117 if (res)
118 return res;
119 }
120
121 return TEE_SUCCESS;
122 }
123
atmel_i2c_write_data(struct i2c_dev * i2c_dev,const uint8_t * buf,size_t len)124 static TEE_Result atmel_i2c_write_data(struct i2c_dev *i2c_dev,
125 const uint8_t *buf, size_t len)
126 {
127 TEE_Result res = TEE_ERROR_GENERIC;
128 struct atmel_i2c *i2c = atmel_i2c_from_i2c_ctrl(i2c_dev->ctrl);
129
130 res = atmel_i2c_write_data_no_stop(i2c_dev, buf, len);
131 if (res)
132 return res;
133
134 atmel_i2c_send_stop(i2c);
135 atmel_i2c_wait_txcomp(i2c);
136
137 return TEE_SUCCESS;
138 }
139
atmel_i2c_recv_one_byte(struct atmel_i2c * i2c,uint8_t * byte)140 static TEE_Result atmel_i2c_recv_one_byte(struct atmel_i2c *i2c,
141 uint8_t *byte)
142 {
143 uint32_t sr = 0;
144
145 while (true) {
146 sr = io_read32(i2c->base + TWIHS_SR);
147 if (sr & TWIHS_SR_NACK) {
148 EMSG("I2C received NACK while reading");
149 return TEE_ERROR_GENERIC;
150 }
151 if (sr & TWIHS_SR_RXRDY)
152 break;
153 }
154
155 *byte = io_read32(i2c->base + TWIHS_RHR);
156
157 return TEE_SUCCESS;
158 }
159
atmel_i2c_read_data(struct i2c_dev * i2c_dev,uint8_t * buf,size_t len)160 static TEE_Result atmel_i2c_read_data(struct i2c_dev *i2c_dev, uint8_t *buf,
161 size_t len)
162 {
163 size_t i = 0;
164 TEE_Result res = TEE_ERROR_GENERIC;
165 struct atmel_i2c *i2c = atmel_i2c_from_i2c_ctrl(i2c_dev->ctrl);
166 uint32_t mmr = TWIHS_MMR_MREAD | SHIFT_U32(i2c_dev->addr,
167 TWIHS_MMR_DADR_SHIFT);
168
169 io_write32(i2c->base + TWIHS_MMR, mmr);
170
171 atmel_i2c_send_start(i2c);
172
173 for (i = 0; i < len; i++) {
174 if (i == len - 1)
175 atmel_i2c_send_stop(i2c);
176
177 res = atmel_i2c_recv_one_byte(i2c, &buf[i]);
178 if (res)
179 return res;
180 }
181
182 atmel_i2c_wait_txcomp(i2c);
183
184 return TEE_SUCCESS;
185 }
186
atmel_i2c_smbus(struct i2c_dev * i2c_dev,enum i2c_smbus_dir dir,enum i2c_smbus_protocol proto __unused,uint8_t cmd_code,uint8_t buf[I2C_SMBUS_MAX_BUF_SIZE],size_t len)187 static TEE_Result atmel_i2c_smbus(struct i2c_dev *i2c_dev,
188 enum i2c_smbus_dir dir,
189 enum i2c_smbus_protocol proto __unused,
190 uint8_t cmd_code,
191 uint8_t buf[I2C_SMBUS_MAX_BUF_SIZE],
192 size_t len)
193 {
194 TEE_Result res = TEE_ERROR_GENERIC;
195
196 /* Send command code first */
197 res = atmel_i2c_write_data_no_stop(i2c_dev, &cmd_code, 1);
198 if (res)
199 return res;
200
201 if (dir == I2C_SMBUS_READ)
202 return atmel_i2c_read_data(i2c_dev, buf, len);
203 else
204 return atmel_i2c_write_data(i2c_dev, buf, len);
205 }
206
flsi(unsigned int val)207 static unsigned int flsi(unsigned int val)
208 {
209 if (val == 0)
210 return 0;
211
212 return sizeof(unsigned int) * 8 - __builtin_clz(val);
213 }
214
atmel_i2c_init_clk(struct atmel_i2c * i2c)215 static TEE_Result atmel_i2c_init_clk(struct atmel_i2c *i2c)
216 {
217 long div = 0;
218 long hold = 0;
219 uint32_t cwgr = 0;
220 uint32_t cxdiv = 0;
221 uint32_t ckdiv = 0;
222 unsigned long clk = clk_get_rate(i2c->clk);
223
224 /*
225 * Since we will configure both CHDIV and CLDIV with the same value
226 * use 2 * clk
227 */
228 div = UDIV_ROUND_NEAREST(clk, 2 * I2C_BUS_FREQ) - 3;
229 if (div < 0)
230 div = 0;
231
232 /* CHDIV/CLDIV are on 8 bits, CKDIV on 3 bits */
233 ckdiv = flsi(div >> 8);
234 if (ckdiv > TWIHS_CWGR_CKDIV_MAX) {
235 EMSG("CKDIV value too large");
236 return TEE_ERROR_BAD_PARAMETERS;
237 }
238 cxdiv = div >> ckdiv;
239
240 if (i2c->sda_hold_time) {
241 /* hold_time = (HOLD + 3) x tperipheral clock */
242 hold = UDIV_ROUND_NEAREST(i2c->sda_hold_time * clk, 1000000000);
243 hold -= 3;
244 if (hold < 0 || hold > TWIHS_CWGR_HOLD_MAX) {
245 EMSG("Incorrect hold value");
246 return TEE_ERROR_BAD_PARAMETERS;
247 }
248
249 cwgr |= hold << TWIHS_CWGR_HOLD_SHIFT;
250 }
251
252 cwgr |= ckdiv << TWIHS_CWGR_CKDIV_SHIFT;
253 /* CHDIV == CLDIV */
254 cwgr |= cxdiv << TWIHS_CWGR_CHDIV_SHIFT;
255 cwgr |= cxdiv;
256 io_write32(i2c->base + TWIHS_CWGR, cwgr);
257
258 return TEE_SUCCESS;
259 }
260
atmel_i2c_init_hw(struct atmel_i2c * i2c)261 static TEE_Result atmel_i2c_init_hw(struct atmel_i2c *i2c)
262 {
263 /* Unlock TWIHS IP */
264 io_write32(i2c->base + TWIHS_WPMR, TWIHS_WPMR_WPKEY);
265
266 /* Configure master mode */
267 io_write32(i2c->base + TWIHS_CR, TWIHS_CR_SWRST);
268
269 io_write32(i2c->base + TWIHS_CR, TWIHS_CR_SVDIS);
270 io_write32(i2c->base + TWIHS_CR, TWIHS_CR_MSEN);
271
272 return atmel_i2c_init_clk(i2c);
273 }
274
275 static const struct i2c_ctrl_ops atmel_i2c_ops = {
276 .read = atmel_i2c_read_data,
277 .write = atmel_i2c_write_data,
278 .smbus = atmel_i2c_smbus,
279 };
280
atmel_i2c_get_dt_i2c(struct dt_pargs * args,void * data,struct i2c_dev ** out_device)281 static TEE_Result atmel_i2c_get_dt_i2c(struct dt_pargs *args, void *data,
282 struct i2c_dev **out_device)
283 {
284 struct i2c_dev *i2c_dev = NULL;
285 struct i2c_ctrl *i2c_ctrl = data;
286
287 i2c_dev = i2c_create_dev(i2c_ctrl, args->fdt, args->consumer_node);
288 if (!i2c_dev)
289 return TEE_ERROR_OUT_OF_MEMORY;
290
291 *out_device = i2c_dev;
292
293 return TEE_SUCCESS;
294 }
295
atmel_i2c_node_probe(const void * fdt,int node,const void * compat_data __unused)296 static TEE_Result atmel_i2c_node_probe(const void *fdt, int node,
297 const void *compat_data __unused)
298 {
299 size_t size = 0;
300 const uint32_t *cuint = 0;
301 unsigned int matrix_id = 0;
302 struct i2c_ctrl *i2c_ctrl = NULL;
303 struct atmel_i2c *atmel_i2c = NULL;
304 TEE_Result res = TEE_ERROR_GENERIC;
305 int status = fdt_get_status(fdt, node);
306
307 if (status != DT_STATUS_OK_SEC)
308 return TEE_SUCCESS;
309
310 atmel_i2c = calloc(1, sizeof(struct atmel_i2c));
311 if (!atmel_i2c)
312 return TEE_ERROR_OUT_OF_MEMORY;
313
314 i2c_ctrl = &atmel_i2c->i2c_ctrl;
315 i2c_ctrl->ops = &atmel_i2c_ops;
316
317 res = clk_dt_get_by_index(fdt, node, 0, &atmel_i2c->clk);
318 if (res)
319 goto err_free;
320
321 res = matrix_dt_get_id(fdt, node, &matrix_id);
322 if (res)
323 goto err_free;
324
325 if (dt_map_dev(fdt, node, &atmel_i2c->base, &size, DT_MAP_AUTO) < 0) {
326 res = TEE_ERROR_GENERIC;
327 goto err_free;
328 }
329
330 matrix_configure_periph_secure(matrix_id);
331
332 cuint = fdt_getprop(fdt, node, "i2c-sda-hold-time-ns", NULL);
333 if (cuint)
334 atmel_i2c->sda_hold_time = fdt32_to_cpu(*cuint);
335
336 clk_enable(atmel_i2c->clk);
337
338 res = atmel_i2c_init_hw(atmel_i2c);
339 if (res)
340 goto err_clk_disable;
341
342 res = i2c_register_provider(fdt, node, atmel_i2c_get_dt_i2c, i2c_ctrl);
343 if (res)
344 goto err_clk_disable;
345
346 return TEE_SUCCESS;
347
348 err_clk_disable:
349 clk_disable(atmel_i2c->clk);
350 err_free:
351 free(atmel_i2c);
352
353 return res;
354 }
355
356 static const struct dt_device_match atmel_i2c_match_table[] = {
357 { .compatible = "atmel,sama5d2-i2c" },
358 { }
359 };
360
361 DEFINE_DT_DRIVER(atmel_i2c_dt_driver) = {
362 .name = "atmel_i2c",
363 .type = DT_DRIVER_NOTYPE,
364 .match_table = atmel_i2c_match_table,
365 .probe = atmel_i2c_node_probe,
366 };
367