blob: bacd47e60f1f1f2325484d26992363b3e519c492 [file] [log] [blame]
Marek Behúnef2b6b12017-06-09 19:28:44 +02001/*
2 * I2C Driver for Atmel ATSHA204 over I2C
3 *
4 * Copyright (C) 2014 Josh Datko, Cryptotronix, jbd@cryptotronix.com
5 * 2016 Tomas Hlavacek, CZ.NIC, tmshlvck@gmail.com
6 * 2017 Marek Behun, CZ.NIC, marek.behun@nic.cz
7 *
8 * This program is free software; you can redistribute it and/or modify it
9 * under the terms of the GNU General Public License version 2 as
10 * published by the Free Software Foundation.
11 */
12
13#include <common.h>
14#include <dm.h>
15#include <i2c.h>
16#include <errno.h>
17#include <atsha204a-i2c.h>
Simon Glass0f2af882020-05-10 11:40:05 -060018#include <log.h>
Simon Glassdbd79542020-05-10 11:40:11 -060019#include <linux/delay.h>
Simon Glass48b6c6b2019-11-14 12:57:16 -070020#include <u-boot/crc.h>
Marek Behúnef2b6b12017-06-09 19:28:44 +020021
22#define ATSHA204A_TWLO 60
23#define ATSHA204A_TRANSACTION_TIMEOUT 100000
24#define ATSHA204A_TRANSACTION_RETRY 5
25#define ATSHA204A_EXECTIME 5000
26
27DECLARE_GLOBAL_DATA_PTR;
28
29/*
30 * The ATSHA204A uses an (to me) unknown CRC-16 algorithm.
31 * The Reveng CRC-16 catalogue does not contain it.
32 *
33 * Because in Atmel's documentation only a primitive implementation
34 * can be found, I have implemented this one with lookup table.
35 */
36
37/*
38 * This is the code that computes the table below:
39 *
40 * int i, j;
41 * for (i = 0; i < 256; ++i) {
42 * u8 c = 0;
43 * for (j = 0; j < 8; ++j) {
44 * c = (c << 1) | ((i >> j) & 1);
45 * }
46 * bitreverse_table[i] = c;
47 * }
48 */
49
50static u8 const bitreverse_table[256] = {
51 0x00, 0x80, 0x40, 0xc0, 0x20, 0xa0, 0x60, 0xe0,
52 0x10, 0x90, 0x50, 0xd0, 0x30, 0xb0, 0x70, 0xf0,
53 0x08, 0x88, 0x48, 0xc8, 0x28, 0xa8, 0x68, 0xe8,
54 0x18, 0x98, 0x58, 0xd8, 0x38, 0xb8, 0x78, 0xf8,
55 0x04, 0x84, 0x44, 0xc4, 0x24, 0xa4, 0x64, 0xe4,
56 0x14, 0x94, 0x54, 0xd4, 0x34, 0xb4, 0x74, 0xf4,
57 0x0c, 0x8c, 0x4c, 0xcc, 0x2c, 0xac, 0x6c, 0xec,
58 0x1c, 0x9c, 0x5c, 0xdc, 0x3c, 0xbc, 0x7c, 0xfc,
59 0x02, 0x82, 0x42, 0xc2, 0x22, 0xa2, 0x62, 0xe2,
60 0x12, 0x92, 0x52, 0xd2, 0x32, 0xb2, 0x72, 0xf2,
61 0x0a, 0x8a, 0x4a, 0xca, 0x2a, 0xaa, 0x6a, 0xea,
62 0x1a, 0x9a, 0x5a, 0xda, 0x3a, 0xba, 0x7a, 0xfa,
63 0x06, 0x86, 0x46, 0xc6, 0x26, 0xa6, 0x66, 0xe6,
64 0x16, 0x96, 0x56, 0xd6, 0x36, 0xb6, 0x76, 0xf6,
65 0x0e, 0x8e, 0x4e, 0xce, 0x2e, 0xae, 0x6e, 0xee,
66 0x1e, 0x9e, 0x5e, 0xde, 0x3e, 0xbe, 0x7e, 0xfe,
67 0x01, 0x81, 0x41, 0xc1, 0x21, 0xa1, 0x61, 0xe1,
68 0x11, 0x91, 0x51, 0xd1, 0x31, 0xb1, 0x71, 0xf1,
69 0x09, 0x89, 0x49, 0xc9, 0x29, 0xa9, 0x69, 0xe9,
70 0x19, 0x99, 0x59, 0xd9, 0x39, 0xb9, 0x79, 0xf9,
71 0x05, 0x85, 0x45, 0xc5, 0x25, 0xa5, 0x65, 0xe5,
72 0x15, 0x95, 0x55, 0xd5, 0x35, 0xb5, 0x75, 0xf5,
73 0x0d, 0x8d, 0x4d, 0xcd, 0x2d, 0xad, 0x6d, 0xed,
74 0x1d, 0x9d, 0x5d, 0xdd, 0x3d, 0xbd, 0x7d, 0xfd,
75 0x03, 0x83, 0x43, 0xc3, 0x23, 0xa3, 0x63, 0xe3,
76 0x13, 0x93, 0x53, 0xd3, 0x33, 0xb3, 0x73, 0xf3,
77 0x0b, 0x8b, 0x4b, 0xcb, 0x2b, 0xab, 0x6b, 0xeb,
78 0x1b, 0x9b, 0x5b, 0xdb, 0x3b, 0xbb, 0x7b, 0xfb,
79 0x07, 0x87, 0x47, 0xc7, 0x27, 0xa7, 0x67, 0xe7,
80 0x17, 0x97, 0x57, 0xd7, 0x37, 0xb7, 0x77, 0xf7,
81 0x0f, 0x8f, 0x4f, 0xcf, 0x2f, 0xaf, 0x6f, 0xef,
82 0x1f, 0x9f, 0x5f, 0xdf, 0x3f, 0xbf, 0x7f, 0xff,
83};
84
85/*
86 * This is the code that computes the table below:
87 *
88 * int i, j;
89 * for (i = 0; i < 256; ++i) {
90 * u16 c = i << 8;
91 * for (j = 0; j < 8; ++j) {
92 * int b = c >> 15;
93 * c <<= 1;
94 * if (b)
95 * c ^= 0x8005;
96 * }
97 * crc16_table[i] = c;
98 * }
99 */
100static u16 const crc16_table[256] = {
101 0x0000, 0x8005, 0x800f, 0x000a, 0x801b, 0x001e, 0x0014, 0x8011,
102 0x8033, 0x0036, 0x003c, 0x8039, 0x0028, 0x802d, 0x8027, 0x0022,
103 0x8063, 0x0066, 0x006c, 0x8069, 0x0078, 0x807d, 0x8077, 0x0072,
104 0x0050, 0x8055, 0x805f, 0x005a, 0x804b, 0x004e, 0x0044, 0x8041,
105 0x80c3, 0x00c6, 0x00cc, 0x80c9, 0x00d8, 0x80dd, 0x80d7, 0x00d2,
106 0x00f0, 0x80f5, 0x80ff, 0x00fa, 0x80eb, 0x00ee, 0x00e4, 0x80e1,
107 0x00a0, 0x80a5, 0x80af, 0x00aa, 0x80bb, 0x00be, 0x00b4, 0x80b1,
108 0x8093, 0x0096, 0x009c, 0x8099, 0x0088, 0x808d, 0x8087, 0x0082,
109 0x8183, 0x0186, 0x018c, 0x8189, 0x0198, 0x819d, 0x8197, 0x0192,
110 0x01b0, 0x81b5, 0x81bf, 0x01ba, 0x81ab, 0x01ae, 0x01a4, 0x81a1,
111 0x01e0, 0x81e5, 0x81ef, 0x01ea, 0x81fb, 0x01fe, 0x01f4, 0x81f1,
112 0x81d3, 0x01d6, 0x01dc, 0x81d9, 0x01c8, 0x81cd, 0x81c7, 0x01c2,
113 0x0140, 0x8145, 0x814f, 0x014a, 0x815b, 0x015e, 0x0154, 0x8151,
114 0x8173, 0x0176, 0x017c, 0x8179, 0x0168, 0x816d, 0x8167, 0x0162,
115 0x8123, 0x0126, 0x012c, 0x8129, 0x0138, 0x813d, 0x8137, 0x0132,
116 0x0110, 0x8115, 0x811f, 0x011a, 0x810b, 0x010e, 0x0104, 0x8101,
117 0x8303, 0x0306, 0x030c, 0x8309, 0x0318, 0x831d, 0x8317, 0x0312,
118 0x0330, 0x8335, 0x833f, 0x033a, 0x832b, 0x032e, 0x0324, 0x8321,
119 0x0360, 0x8365, 0x836f, 0x036a, 0x837b, 0x037e, 0x0374, 0x8371,
120 0x8353, 0x0356, 0x035c, 0x8359, 0x0348, 0x834d, 0x8347, 0x0342,
121 0x03c0, 0x83c5, 0x83cf, 0x03ca, 0x83db, 0x03de, 0x03d4, 0x83d1,
122 0x83f3, 0x03f6, 0x03fc, 0x83f9, 0x03e8, 0x83ed, 0x83e7, 0x03e2,
123 0x83a3, 0x03a6, 0x03ac, 0x83a9, 0x03b8, 0x83bd, 0x83b7, 0x03b2,
124 0x0390, 0x8395, 0x839f, 0x039a, 0x838b, 0x038e, 0x0384, 0x8381,
125 0x0280, 0x8285, 0x828f, 0x028a, 0x829b, 0x029e, 0x0294, 0x8291,
126 0x82b3, 0x02b6, 0x02bc, 0x82b9, 0x02a8, 0x82ad, 0x82a7, 0x02a2,
127 0x82e3, 0x02e6, 0x02ec, 0x82e9, 0x02f8, 0x82fd, 0x82f7, 0x02f2,
128 0x02d0, 0x82d5, 0x82df, 0x02da, 0x82cb, 0x02ce, 0x02c4, 0x82c1,
129 0x8243, 0x0246, 0x024c, 0x8249, 0x0258, 0x825d, 0x8257, 0x0252,
130 0x0270, 0x8275, 0x827f, 0x027a, 0x826b, 0x026e, 0x0264, 0x8261,
131 0x0220, 0x8225, 0x822f, 0x022a, 0x823b, 0x023e, 0x0234, 0x8231,
132 0x8213, 0x0216, 0x021c, 0x8219, 0x0208, 0x820d, 0x8207, 0x0202,
133};
134
135static inline u16 crc16_byte(u16 crc, const u8 data)
136{
137 u16 t = crc16_table[((crc >> 8) ^ bitreverse_table[data]) & 0xff];
138 return ((crc << 8) ^ t);
139}
140
141static u16 atsha204a_crc16(const u8 *buffer, size_t len)
142{
143 u16 crc = 0;
144
145 while (len--)
146 crc = crc16_byte(crc, *buffer++);
147
148 return cpu_to_le16(crc);
149}
150
151static int atsha204a_send(struct udevice *dev, const u8 *buf, u8 len)
152{
153 fdt_addr_t *priv = dev_get_priv(dev);
154 struct i2c_msg msg;
155
156 msg.addr = *priv;
157 msg.flags = I2C_M_STOP;
158 msg.len = len;
159 msg.buf = (u8 *) buf;
160
161 return dm_i2c_xfer(dev, &msg, 1);
162}
163
164static int atsha204a_recv(struct udevice *dev, u8 *buf, u8 len)
165{
166 fdt_addr_t *priv = dev_get_priv(dev);
167 struct i2c_msg msg;
168
169 msg.addr = *priv;
170 msg.flags = I2C_M_RD | I2C_M_STOP;
171 msg.len = len;
172 msg.buf = (u8 *) buf;
173
174 return dm_i2c_xfer(dev, &msg, 1);
175}
176
177static int atsha204a_recv_resp(struct udevice *dev,
178 struct atsha204a_resp *resp)
179{
180 int res;
181 u16 resp_crc, computed_crc;
182 u8 *p = (u8 *) resp;
183
184 res = atsha204a_recv(dev, p, 4);
185 if (res)
186 return res;
187
188 if (resp->length > 4) {
189 if (resp->length > sizeof(*resp))
190 return -EMSGSIZE;
191
192 res = atsha204a_recv(dev, p + 4, resp->length - 4);
193 if (res)
194 return res;
195 }
196
197 resp_crc = (u16) p[resp->length - 2]
198 | (((u16) p[resp->length - 1]) << 8);
199 computed_crc = atsha204a_crc16(p, resp->length - 2);
200
201 if (resp_crc != computed_crc) {
202 debug("Invalid checksum in ATSHA204A response\n");
203 return -EBADMSG;
204 }
205
206 return 0;
207}
208
209int atsha204a_wakeup(struct udevice *dev)
210{
211 u8 req[4];
212 struct atsha204a_resp resp;
213 int try, res;
214
215 debug("Waking up ATSHA204A\n");
216
217 for (try = 1; try <= 10; ++try) {
218 debug("Try %i... ", try);
219
220 memset(req, 0, 4);
221 res = atsha204a_send(dev, req, 4);
222 if (res) {
223 debug("failed on I2C send, trying again\n");
224 continue;
225 }
226
227 udelay(ATSHA204A_TWLO);
228
229 res = atsha204a_recv_resp(dev, &resp);
230 if (res) {
231 debug("failed on receiving response, ending\n");
232 return res;
233 }
234
235 if (resp.code != ATSHA204A_STATUS_AFTER_WAKE) {
236 debug ("failed (responce code = %02x), ending\n",
237 resp.code);
238 return -EBADMSG;
239 }
240
241 debug("success\n");
242 break;
243 }
244
245 return 0;
246}
247
248int atsha204a_idle(struct udevice *dev)
249{
250 int res;
251 u8 req = ATSHA204A_FUNC_IDLE;
252
253 res = atsha204a_send(dev, &req, 1);
254 if (res)
255 debug("Failed putting ATSHA204A idle\n");
256 return res;
257}
258
259int atsha204a_sleep(struct udevice *dev)
260{
261 int res;
262 u8 req = ATSHA204A_FUNC_IDLE;
263
264 res = atsha204a_send(dev, &req, 1);
265 if (res)
266 debug("Failed putting ATSHA204A to sleep\n");
267 return res;
268}
269
270static int atsha204a_transaction(struct udevice *dev, struct atsha204a_req *req,
271 struct atsha204a_resp *resp)
272{
273 int res, timeout = ATSHA204A_TRANSACTION_TIMEOUT;
274
275 res = atsha204a_send(dev, (u8 *) req, req->length + 1);
276 if (res) {
277 debug("ATSHA204A transaction send failed\n");
278 return -EBUSY;
279 }
280
281 do {
282 res = atsha204a_recv_resp(dev, resp);
283 if (!res || res == -EMSGSIZE || res == -EBADMSG)
284 break;
285
286 debug("ATSHA204A transaction polling for response "
287 "(timeout = %d)\n", timeout);
288
289 udelay(ATSHA204A_EXECTIME);
290 timeout -= ATSHA204A_EXECTIME;
291 } while (timeout > 0);
292
293 if (timeout <= 0) {
294 debug("ATSHA204A transaction timed out\n");
295 return -ETIMEDOUT;
296 }
297
298 return res;
299}
300
301static void atsha204a_req_crc32(struct atsha204a_req *req)
302{
303 u8 *p = (u8 *) req;
304 u16 computed_crc;
305 u16 *crc_ptr = (u16 *) &p[req->length - 1];
306
307 /* The buffer to crc16 starts at byte 1, not 0 */
308 computed_crc = atsha204a_crc16(p + 1, req->length - 2);
309
310 *crc_ptr = cpu_to_le16(computed_crc);
311}
312
313int atsha204a_read(struct udevice *dev, enum atsha204a_zone zone, bool read32,
314 u16 addr, u8 *buffer)
315{
316 int res, retry = ATSHA204A_TRANSACTION_RETRY;
317 struct atsha204a_req req;
318 struct atsha204a_resp resp;
319
320 req.function = ATSHA204A_FUNC_COMMAND;
321 req.length = 7;
322 req.command = ATSHA204A_CMD_READ;
323
324 req.param1 = (u8) zone;
325 if (read32)
326 req.param1 |= 0x80;
327
328 req.param2 = cpu_to_le16(addr);
329
330 atsha204a_req_crc32(&req);
331
332 do {
333 res = atsha204a_transaction(dev, &req, &resp);
334 if (!res)
335 break;
336
337 debug("ATSHA204A read retry (%d)\n", retry);
338 retry--;
339 atsha204a_wakeup(dev);
340 } while (retry >= 0);
341
342 if (res) {
343 debug("ATSHA204A read failed\n");
344 return res;
345 }
346
347 if (resp.length != (read32 ? 32 : 4) + 3) {
348 debug("ATSHA204A read bad response length (%d)\n",
349 resp.length);
350 return -EBADMSG;
351 }
352
353 memcpy(buffer, ((u8 *) &resp) + 1, read32 ? 32 : 4);
354
355 return 0;
356}
357
358int atsha204a_get_random(struct udevice *dev, u8 *buffer, size_t max)
359{
360 int res;
361 struct atsha204a_req req;
362 struct atsha204a_resp resp;
363
364 req.function = ATSHA204A_FUNC_COMMAND;
365 req.length = 7;
366 req.command = ATSHA204A_CMD_RANDOM;
367
368 req.param1 = 1;
369 req.param2 = 0;
370
371 /* We do not have to compute the checksum dynamically */
372 req.data[0] = 0x27;
373 req.data[1] = 0x47;
374
375 res = atsha204a_transaction(dev, &req, &resp);
376 if (res) {
377 debug("ATSHA204A random transaction failed\n");
378 return res;
379 }
380
381 memcpy(buffer, ((u8 *) &resp) + 1, max >= 32 ? 32 : max);
382 return 0;
383}
384
385static int atsha204a_ofdata_to_platdata(struct udevice *dev)
386{
387 fdt_addr_t *priv = dev_get_priv(dev);
388 fdt_addr_t addr;
389
390 addr = fdtdec_get_addr(gd->fdt_blob, dev_of_offset(dev), "reg");
391 if (addr == FDT_ADDR_T_NONE) {
392 debug("Can't get ATSHA204A I2C base address\n");
393 return -ENXIO;
394 }
395
396 *priv = addr;
397 return 0;
398}
399
400static const struct udevice_id atsha204a_ids[] = {
401 { .compatible = "atmel,atsha204a" },
402 { }
403};
404
405U_BOOT_DRIVER(atsha204) = {
406 .name = "atsha204",
407 .id = UCLASS_MISC,
408 .of_match = atsha204a_ids,
409 .ofdata_to_platdata = atsha204a_ofdata_to_platdata,
Simon Glass8a2b47f2020-12-03 16:55:17 -0700410 .priv_auto = sizeof(fdt_addr_t),
Marek Behúnef2b6b12017-06-09 19:28:44 +0200411};