u-boot/board/nm/nmhw21/fct_atecc.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"
);