205 lines
3.3 KiB
C
205 lines
3.3 KiB
C
/*
|
|
* fct_atecc.c
|
|
*
|
|
* Microchip ATECC608 test
|
|
*
|
|
* Copyright (C) 2018-2020 NetModule AG - http://www.netmodule.com/
|
|
*
|
|
* SPDX-License-Identifier: GPL-2.0+
|
|
*/
|
|
|
|
#include <common.h>
|
|
#include <errno.h>
|
|
#include <i2c.h>
|
|
|
|
#include "fct_atecc.h"
|
|
|
|
|
|
#define REG_SLEEP 0x01
|
|
#define REG_COMMAND 0x03
|
|
|
|
#define WAKE_DELAY_US 1500
|
|
|
|
#define RNG_MAX_EXEC_TIME_MS 23
|
|
#define READ_MAX_EXEC_TIME_MS 1 /* 4 bytes read, 32 bytes = ? */
|
|
|
|
|
|
static void wake_chip(void)
|
|
{
|
|
int j;
|
|
|
|
|
|
i2c_set_bus_speed(50000);
|
|
|
|
/* wake up sequence, same as i2c probe on command line (proven to work) */
|
|
for (j = 0; j < 128; j++) {
|
|
i2c_probe(j);
|
|
}
|
|
|
|
udelay(WAKE_DELAY_US+1000);
|
|
|
|
i2c_set_bus_speed(400000);
|
|
}
|
|
|
|
static int put_in_sleep(void)
|
|
{
|
|
uchar temp[1];
|
|
int ret;
|
|
|
|
/* put back into sleep mode */
|
|
ret = i2c_write(CONFIG_ATECC_I2C_ADDR, REG_SLEEP, 1, temp, 0);
|
|
if (ret != 0) {
|
|
puts("can't put device in sleep mode\n");
|
|
}
|
|
|
|
return ret;
|
|
}
|
|
|
|
static int test_rng(void)
|
|
{
|
|
uchar rng_cmd[7] = { 7, 0x1B, 0x00, 0x00, 0x00, 0x24, 0xCD };
|
|
uchar temp[32+3];
|
|
int ret;
|
|
|
|
|
|
ret = i2c_write(CONFIG_ATECC_I2C_ADDR, REG_COMMAND, 1, rng_cmd, 7);
|
|
if (ret != 0) {
|
|
puts("error sending command\n");
|
|
goto abort;
|
|
}
|
|
|
|
mdelay(RNG_MAX_EXEC_TIME_MS+10);
|
|
|
|
/*
|
|
* Get random number
|
|
* will be ff ff 00 00 ff ff 00 00 .. if chip is unlocked
|
|
*/
|
|
memset(temp, 0x00, sizeof(temp));
|
|
ret = i2c_read(CONFIG_ATECC_I2C_ADDR, 0x00, 0, temp, 32+3);
|
|
if (ret != 0) {
|
|
puts("error reading RNG response\n");
|
|
goto abort;
|
|
}
|
|
#if 0
|
|
for (i=0; i<32+3; i++) {
|
|
printf("%02x ", temp[i]);
|
|
}
|
|
puts("\n");
|
|
#endif
|
|
if (temp[0] != 0x23 || temp[33] != 0x41 || temp[34] != 0x1a) {
|
|
puts("invalid data returned\n");
|
|
goto abort;
|
|
}
|
|
|
|
if (temp[33] == 0x41 && temp[34] == 0x1a) {
|
|
puts("RNG: ok (chip unlocked)\n");
|
|
}
|
|
else {
|
|
puts("RNG: ok (chip locked)\n");
|
|
}
|
|
|
|
abort:
|
|
return ret;
|
|
}
|
|
|
|
static int test_serial_num(void)
|
|
{
|
|
uchar read_cfg32_cmd[7] = { 7, 0x02, 0x80, 0x00, 0x00, 0x09, 0xAD };
|
|
uchar temp[32+3];
|
|
uchar sn[9];
|
|
int ret;
|
|
int i;
|
|
|
|
|
|
/*
|
|
* Read beginning of config zone, get S/N
|
|
* S/N = 0..3, 8..12
|
|
*/
|
|
ret = i2c_write(CONFIG_ATECC_I2C_ADDR, REG_COMMAND, 1, read_cfg32_cmd, 7);
|
|
if (ret != 0) {
|
|
puts("error sending READ command\n");
|
|
goto abort;
|
|
}
|
|
|
|
mdelay(READ_MAX_EXEC_TIME_MS+10);
|
|
|
|
memset(temp, 0x00, sizeof(temp));
|
|
ret = i2c_read(CONFIG_ATECC_I2C_ADDR, 0x00, 0, temp, 32+3);
|
|
if (ret != 0) {
|
|
puts("error reading response\n");
|
|
goto abort;
|
|
}
|
|
#if 0
|
|
for (i=0; i<32+3; i++) {
|
|
printf("%02x ", temp[i]);
|
|
}
|
|
puts("\n");
|
|
#endif
|
|
memcpy(&sn[0], &temp[1], 4);
|
|
memcpy(&sn[4], &temp[9], 5);
|
|
puts("S/N: ");
|
|
for (i=0; i<9; i++) {
|
|
printf("%02x ", sn[i]);
|
|
}
|
|
puts("\n");
|
|
|
|
abort:
|
|
return ret;
|
|
}
|
|
|
|
|
|
static int do_atecc_test(void)
|
|
{
|
|
int ret;
|
|
|
|
i2c_set_bus_num(CONFIG_ATECC_I2C_BUS);
|
|
|
|
wake_chip();
|
|
|
|
ret = test_rng();
|
|
if (ret != 0) {
|
|
goto abort;
|
|
}
|
|
|
|
ret = test_serial_num();
|
|
if (ret != 0) {
|
|
goto abort;
|
|
}
|
|
|
|
ret = put_in_sleep();
|
|
if (ret != 0) {
|
|
goto abort;
|
|
}
|
|
|
|
i2c_set_bus_speed(100000);
|
|
|
|
puts("test passed\n");
|
|
return 0;
|
|
|
|
abort:
|
|
i2c_set_bus_speed(100000);
|
|
|
|
puts("test failed\n");
|
|
return 1;
|
|
}
|
|
|
|
static int do_fct_test(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])
|
|
{
|
|
if (argc != 2)
|
|
goto cmd_usage;
|
|
|
|
do_atecc_test();
|
|
|
|
return 0;
|
|
|
|
cmd_usage:
|
|
return cmd_usage(cmdtp);
|
|
}
|
|
|
|
|
|
U_BOOT_CMD(
|
|
fct, 2, 1, do_fct_test,
|
|
"factory test subsystem\n",
|
|
"atecc - tests ATECC chip"
|
|
);
|