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