| /* |
| * 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 |