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