blob: 49cd8f396349c82fc078e371b3ad88bdcb70c8d8 [file] [log] [blame]
/*
* otp_stability_test - test OTP stability.
*
* (C) Copyright 2013 Google Inc.
*
* See file CREDITS for list of people who contributed to this
* project.
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License as
* published by the Free Software Foundation; either version 2 of
* the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston,
* MA 02111-1307 USA
*/
#include <c2k_otp.h>
#include <command.h>
#include <common.h>
#include <errno.h>
#include <fcntl.h>
#include <fs.h>
#include <malloc.h>
#include <init.h>
#include <types.h>
#include <mach/gpio.h>
#include <asm/hardware.h>
#include <asm/io.h>
#include "../arch/arm/boards/optimus/leds.h"
#define OTP_KEY_SIZE_BYTES 256
#define OTP_HEADER_OFFSET_BITS 32
#define LED_BLINK_DELAY_MILLISECONDS 150
/*
* Dumps a key to stdout, for debugging.
*/
static void _dump_key(char *key_name, uint8_t *key, unsigned int key_size) {
int i;
printf("%s:\n", key_name);
for (i = 0; i < key_size; ++i) {
if ((i % 16) == 0) {
printf("\n");
}
printf(" %.2x", key[i]);
}
printf("\n");
}
static void flash_led_forever(void) {
/* Turn off both blue and red leds to start. */
comcerto_gpio_set_0(GPIO_BLUE_LED);
comcerto_gpio_set_0(GPIO_RED_LED);
/* Flash the red LED continuously. */
while (true) {
mdelay(LED_BLINK_DELAY_MILLISECONDS);
comcerto_gpio_set_1(GPIO_RED_LED);
if (ctrlc()) {
break;
}
mdelay(LED_BLINK_DELAY_MILLISECONDS);
comcerto_gpio_set_0(GPIO_RED_LED);
if (ctrlc()) {
break;
}
}
/* Reset to barebox norm: red on, blue off. */
comcerto_gpio_set_0(GPIO_BLUE_LED);
comcerto_gpio_set_1(GPIO_RED_LED);
}
/*
* Checks that the value in the OTP at an offset matches a given key.
*
* Returns 1 if the values match, 0 otherwise.
*/
static int check_otp_value(uint8_t *expected_key, long offset) {
int rv = 1;
uint8_t *otp_key;
otp_key = xmalloc(OTP_KEY_SIZE_BYTES);
if (otp_read(offset, otp_key, OTP_KEY_SIZE_BYTES) != 0) {
printf("Error: otp_read failed!\n");
rv = 0;
goto end;
}
if (memcmp(expected_key, otp_key, OTP_KEY_SIZE_BYTES) != 0) {
printf("OTP key mismatch!\n\n");
_dump_key("Expected value", expected_key, OTP_KEY_SIZE_BYTES);
printf("\n");
_dump_key("Read value", otp_key, OTP_KEY_SIZE_BYTES);
rv = 0;
goto end;
}
end:
free(otp_key);
return rv;
}
static int do_otp_stability_test(struct command *cmdtp, int argc, char *argv[])
{
int fd, rv = 0;
uint8_t *provided_key;
long offset = 0, good_read_count = 0;
if (argc < 2)
return COMMAND_ERROR_USAGE;
provided_key = xmalloc(OTP_KEY_SIZE_BYTES);
fd = open(argv[1], O_RDONLY);
if (fd < 0) {
perror(argv[1]);
rv = 1;
goto end;
}
if (read(fd, provided_key, OTP_KEY_SIZE_BYTES) != OTP_KEY_SIZE_BYTES) {
perror("file read");
close(fd);
rv = 1;
goto end;
}
close(fd);
if (argc > 2) {
offset = simple_strtol(argv[2], NULL, 10);
if (offset <= 0 || (offset & 0xFFFFFFFF) != offset) {
printf("Error: invalid offset %s\n", argv[2]);
rv = 1;
goto end;
}
printf("For debug purposes, using an offset of %ld bytes\n", offset);
offset *= 8; // Convert from bytes to bits;
} else {
offset = OTP_HEADER_OFFSET_BITS;
}
while (true) {
if (!check_otp_value(provided_key, offset)) {
flash_led_forever();
/* User has pressed ctrl-c. */
break;
}
good_read_count++;
if (good_read_count % 1000 == 0) {
printf("OTP has read correctly %ld times\n", good_read_count);
}
if (ctrlc())
break;
}
end:
free(provided_key);
return rv;
}
static const __maybe_unused char cmd_otp_stability_test_help[] =
"Usage: otp_stability_test <key_file> [offset]\n"
"Performs a stability test on the OTP, ensuring that the correct value\n"
"is always read\n";
BAREBOX_CMD_START(otp_stability_test)
.cmd = do_otp_stability_test,
.usage = "perform OTP stability test",
BAREBOX_CMD_HELP(cmd_otp_stability_test_help)
BAREBOX_CMD_END