diff --git a/board/link/board.h b/board/link/board.h index d061e90f63..aaa17d7ee2 100644 --- a/board/link/board.h +++ b/board/link/board.h @@ -11,6 +11,7 @@ /* Optional features */ #define CONFIG_PECI #define CONFIG_TMP006 +#define CONFIG_PSTORE /* 66.667 Mhz clock frequency */ #define CPU_CLOCK 66666667 diff --git a/common/build.mk b/common/build.mk index 9c4a6fb6d5..34952d410b 100644 --- a/common/build.mk +++ b/common/build.mk @@ -14,6 +14,7 @@ common-$(CONFIG_TASK_I8042CMD)+=i8042.o keyboard.o common-$(CONFIG_TASK_X86POWER)+=x86_power.o common-$(CONFIG_TASK_GAIAPOWER)+=gaia_power.o common-$(CONFIG_FLASH)+=flash_commands.o +common-$(CONFIG_PSTORE)+=pstore_commands.o common-$(CONFIG_PWM)+=pwm_commands.o common-$(CONFIG_TEMP_SENSOR)+=temp_sensor.o common-$(CONFIG_TMP006)+=tmp006.o diff --git a/common/host_command.c b/common/host_command.c index 1314a0cfe1..f52c6095ad 100644 --- a/common/host_command.c +++ b/common/host_command.c @@ -5,19 +5,20 @@ /* Host command module for Chrome EC */ +#include "board.h" #include "config.h" #include "console.h" #include "flash_commands.h" #include "host_command.h" -#include "pwm_commands.h" -#include "usb_charge_commands.h" #include "lpc.h" #include "lpc_commands.h" +#include "pstore_commands.h" +#include "pwm_commands.h" #include "system.h" #include "task.h" #include "timer.h" #include "uart.h" -#include "registers.h" +#include "usb_charge_commands.h" #include "util.h" static int host_command[2]; @@ -192,6 +193,17 @@ static void command_process(int slot) case EC_LPC_COMMAND_USB_CHARGE_SET_MODE: lpc_send_host_response(slot, usb_charge_command_set_mode(data)); return; +#ifdef CONFIG_PSTORE + case EC_LPC_COMMAND_PSTORE_INFO: + lpc_send_host_response(slot, pstore_command_get_info(data)); + return; + case EC_LPC_COMMAND_PSTORE_READ: + lpc_send_host_response(slot, pstore_command_read(data)); + return; + case EC_LPC_COMMAND_PSTORE_WRITE: + lpc_send_host_response(slot, pstore_command_write(data)); + return; +#endif default: lpc_send_host_response(slot, EC_LPC_STATUS_INVALID_COMMAND); } diff --git a/common/pstore_commands.c b/common/pstore_commands.c new file mode 100644 index 0000000000..24ce7c7878 --- /dev/null +++ b/common/pstore_commands.c @@ -0,0 +1,109 @@ +/* Copyright (c) 2012 The Chromium OS Authors. All rights reserved. + * Use of this source code is governed by a BSD-style license that can be + * found in the LICENSE file. + */ + +/* Persistent storage commands for Chrome EC */ + +#include "board.h" +#include "eeprom.h" +#include "lpc_commands.h" +#include "pstore_commands.h" +#include "uart.h" +#include "util.h" + +/* TODO: move these to board.h */ +#ifdef CONFIG_PSTORE +/* Start block and block count for host persistent storage in EC EEPROM */ +#define PSTORE_EEPROM_BLOCK_START 16 +#define PSTORE_EEPROM_BLOCK_COUNT 16 +#endif + +enum lpc_status pstore_command_get_info(uint8_t *data) +{ + struct lpc_response_pstore_info *r = + (struct lpc_response_pstore_info *)data; + + uart_printf("ee block size=%d, count=%d\n", + eeprom_get_block_size(), eeprom_get_block_count()); + + ASSERT(PSTORE_EEPROM_BLOCK_START + PSTORE_EEPROM_BLOCK_COUNT <= + eeprom_get_block_count()); + + r->pstore_size = PSTORE_EEPROM_BLOCK_COUNT * eeprom_get_block_size(); + r->access_size = sizeof(uint32_t); + return EC_LPC_STATUS_SUCCESS; +} + + +enum lpc_status pstore_command_read(uint8_t *data) +{ + struct lpc_params_pstore_read *p = + (struct lpc_params_pstore_read *)data; + struct lpc_response_pstore_read *r = + (struct lpc_response_pstore_read *)data; + char *dest = r->data; + int block_size = eeprom_get_block_size(); + int block = p->offset / block_size + PSTORE_EEPROM_BLOCK_COUNT; + int offset = p->offset % block_size; + int bytes_left = p->size; + + if (p->size > sizeof(r->data)) + return EC_LPC_STATUS_ERROR; + + while (bytes_left) { + /* Read what we can from the current block */ + int bytes_this = MIN(bytes_left, block_size - offset); + + if (block >= + PSTORE_EEPROM_BLOCK_START + PSTORE_EEPROM_BLOCK_COUNT) + return EC_LPC_STATUS_ERROR; + + if (eeprom_read(block, offset, bytes_this, dest)) + return EC_LPC_STATUS_ERROR; + + /* Continue to the next block if necessary */ + offset = 0; + block++; + bytes_left -= bytes_this; + dest += bytes_this; + } + + return EC_LPC_STATUS_SUCCESS; +} + + +enum lpc_status pstore_command_write(uint8_t *data) +{ + struct lpc_params_pstore_write *p = + (struct lpc_params_pstore_write *)data; + + const char *src = p->data; + int block_size = eeprom_get_block_size(); + int block = p->offset / block_size + PSTORE_EEPROM_BLOCK_COUNT; + int offset = p->offset % block_size; + int bytes_left = p->size; + + if (p->size > sizeof(p->data)) + return EC_LPC_STATUS_ERROR; + + while (bytes_left) { + /* Write what we can to the current block */ + int bytes_this = MIN(bytes_left, block_size - offset); + + if (block >= + PSTORE_EEPROM_BLOCK_START + PSTORE_EEPROM_BLOCK_COUNT) + return EC_LPC_STATUS_ERROR; + + if (eeprom_write(block, offset, bytes_this, src)) + return EC_LPC_STATUS_ERROR; + + /* Continue to the next block if necessary */ + offset = 0; + block++; + bytes_left -= bytes_this; + src += bytes_this; + } + + return EC_LPC_STATUS_SUCCESS; +} diff --git a/include/flash_commands.h b/include/flash_commands.h index 5efc7e2a67..9a46bef5e5 100644 --- a/include/flash_commands.h +++ b/include/flash_commands.h @@ -1,4 +1,4 @@ -/* Copyright (c) 2011 The Chromium OS Authors. All rights reserved. +/* Copyright (c) 2012 The Chromium OS Authors. All rights reserved. * Use of this source code is governed by a BSD-style license that can be * found in the LICENSE file. */ @@ -11,9 +11,6 @@ #include "common.h" #include "lpc_commands.h" -/* Initializes the module. */ -int flash_commands_init(void); - /* Host command handlers. */ enum lpc_status flash_command_get_info(uint8_t *data); enum lpc_status flash_command_read(uint8_t *data); diff --git a/include/lpc_commands.h b/include/lpc_commands.h index ac4118dc83..3d419e5c9d 100644 --- a/include/lpc_commands.h +++ b/include/lpc_commands.h @@ -136,7 +136,6 @@ struct lpc_response_flash_info { uint32_t protect_block_size; } __attribute__ ((packed)); - /* Read flash */ #define EC_LPC_COMMAND_FLASH_READ 0x11 struct lpc_params_flash_read { @@ -147,16 +146,14 @@ struct lpc_response_flash_read { uint8_t data[EC_LPC_FLASH_SIZE_MAX]; } __attribute__ ((packed)); - /* Write flash */ #define EC_LPC_COMMAND_FLASH_WRITE 0x12 struct lpc_params_flash_write { - uint32_t offset; /* Byte offset to erase */ - uint32_t size; /* Size to erase in bytes */ + uint32_t offset; /* Byte offset to write */ + uint32_t size; /* Size to write in bytes */ uint8_t data[EC_LPC_FLASH_SIZE_MAX]; } __attribute__ ((packed)); - /* Erase flash */ #define EC_LPC_COMMAND_FLASH_ERASE 0x13 struct lpc_params_flash_erase { @@ -249,7 +246,6 @@ struct lpc_params_pwm_set_keyboard_backlight { uint8_t percent; } __attribute__ ((packed)); - /*****************************************************************************/ /* USB charging control commands */ @@ -260,4 +256,38 @@ struct lpc_params_usb_charge_set_mode { uint8_t mode; } __attribute__ ((packed)); +/*****************************************************************************/ +/* Persistent storage for host */ + +/* Maximum bytes that can be read/written in a single command */ +#define EC_LPC_PSTORE_SIZE_MAX 64 + +/* Get persistent storage info */ +#define EC_LPC_COMMAND_PSTORE_INFO 0x40 +struct lpc_response_pstore_info { + /* Persistent storage size, in bytes */ + uint32_t pstore_size; + /* Access size. Read/write offset and size must be a multiple + * of this. */ + uint32_t access_size; +} __attribute__ ((packed)); + +/* Read persistent storage */ +#define EC_LPC_COMMAND_PSTORE_READ 0x41 +struct lpc_params_pstore_read { + uint32_t offset; /* Byte offset to read */ + uint32_t size; /* Size to read in bytes */ +} __attribute__ ((packed)); +struct lpc_response_pstore_read { + uint8_t data[EC_LPC_PSTORE_SIZE_MAX]; +} __attribute__ ((packed)); + +/* Write persistent storage */ +#define EC_LPC_COMMAND_PSTORE_WRITE 0x42 +struct lpc_params_pstore_write { + uint32_t offset; /* Byte offset to write */ + uint32_t size; /* Size to write in bytes */ + uint8_t data[EC_LPC_PSTORE_SIZE_MAX]; +} __attribute__ ((packed)); + #endif /* __CROS_EC_LPC_COMMANDS_H */ diff --git a/include/pstore_commands.h b/include/pstore_commands.h new file mode 100644 index 0000000000..123d6f28f9 --- /dev/null +++ b/include/pstore_commands.h @@ -0,0 +1,18 @@ +/* Copyright (c) 2012 The Chromium OS Authors. All rights reserved. + * Use of this source code is governed by a BSD-style license that can be + * found in the LICENSE file. + */ + +/* Persistent storage commands for Chrome EC */ + +#ifndef __CROS_EC_PSTORE_COMMANDS_H +#define __CROS_EC_PSTORE_COMMANDS_H + +#include "common.h" + +/* Host command handlers. */ +enum lpc_status pstore_command_get_info(uint8_t *data); +enum lpc_status pstore_command_read(uint8_t *data); +enum lpc_status pstore_command_write(uint8_t *data); + +#endif /* __CROS_EC_PSTORE_COMMANDS_H */ diff --git a/util/ectool.c b/util/ectool.c index a0bd71c236..676bcc4fe8 100644 --- a/util/ectool.c +++ b/util/ectool.c @@ -28,6 +28,12 @@ const char help_str[] = " Erases EC flash\n" " hello\n" " Checks for basic communication with EC\n" + " pstoreinfo\n" + " Prints information on the EC host persistent storage\n" + " pstoreread \n" + " Reads from EC host persistent storage to a file\n" + " pstorewrite \n" + " Writes to EC host persistent storage from a file\n" " readtest \n" " Reads a pattern from the EC via LPC\n" " sertest\n" @@ -55,6 +61,72 @@ const char help_str[] = ""; +/* Write a buffer to the file. Return non-zero if error. */ +static int write_file(const char *filename, const char *buf, int size) +{ + FILE *f; + int i; + + /* Write to file */ + f = fopen(filename, "wb"); + if (!f) { + perror("Error opening output file"); + return -1; + } + i = fwrite(buf, 1, size, f); + fclose(f); + if (i != size) { + perror("Error writing to file"); + return -1; + } + + return 0; +} + + +/* Read a file into a buffer. Sets *size to the size of the buffer. Returns + * the buffer, which must be freed with free() by the caller. Returns NULL if + * error. */ +static char *read_file(const char *filename, int *size) +{ + FILE *f = fopen(filename, "rb"); + char *buf; + int i; + + if (!f) { + perror("Error opening input file"); + return NULL; + } + + fseek(f, 0, SEEK_END); + *size = ftell(f); + rewind(f); + if (*size > 0x100000) { + fprintf(stderr, "File seems unreasonably large\n"); + fclose(f); + return NULL; + } + + buf = (char *)malloc(*size); + if (!buf) { + fprintf(stderr, "Unable to allocate buffer.\n"); + fclose(f); + return NULL; + } + + printf("Reading %d bytes from %s...\n", *size, filename); + i = fread(buf, 1, *size, f); + fclose(f); + if (i != *size) { + perror("Error reading file"); + free(buf); + return NULL; + } + + return buf; +} + + /* Waits for the EC to be unbusy. Returns 0 if unbusy, non-zero if * timeout. */ int wait_for_ec(int status_addr, int timeout_usec) @@ -283,7 +355,6 @@ int cmd_flash_read(int argc, char *argv[]) int i; char *e; char *buf; - FILE *f; if (argc < 3) { fprintf(stderr, @@ -322,20 +393,11 @@ int cmd_flash_read(int argc, char *argv[]) memcpy(buf + i, r.data, p.size); } - /* Write to file */ - f = fopen(argv[2], "wb"); - if (!f) { - perror("Error opening output file"); - free(buf); - return -1; - } - i = fwrite(buf, 1, size, f); - fclose(f); + rv = write_file(argv[2], buf, size); free(buf); - if (i != size) { - perror("Error writing to file"); + if (rv) return -1; - } + printf("done.\n"); return 0; } @@ -349,7 +411,6 @@ int cmd_flash_write(int argc, char *argv[]) int i; char *e; char *buf; - FILE *f; if (argc < 2) { fprintf(stderr, "Usage: flashwrite \n"); @@ -362,34 +423,9 @@ int cmd_flash_write(int argc, char *argv[]) } /* Read the input file */ - f = fopen(argv[1], "rb"); - if (!f) { - perror("Error opening input file"); + buf = read_file(argv[1], &size); + if (!buf) return -1; - } - fseek(f, 0, SEEK_END); - size = ftell(f); - rewind(f); - if (size > 0x100000) { - fprintf(stderr, "File seems unreasonably large\n"); - fclose(f); - return -1; - } - - buf = (char *)malloc(size); - if (!buf) { - fprintf(stderr, "Unable to allocate buffer.\n"); - fclose(f); - return -1; - } - - printf("Reading %d bytes from %s...\n", size, argv[1]); - i = fread(buf, 1, size, f); - if (i != size) { - perror("Error reading file"); - free(buf); - return -1; - } printf("Writing to offset %d...\n", offset); @@ -460,6 +496,7 @@ int cmd_serial_test(int argc, char *argv[]) return 0; } + int cmd_temperature(int argc, char *argv[]) { int rv; @@ -493,6 +530,7 @@ int cmd_temperature(int argc, char *argv[]) return rv; } + int cmd_pwm_get_fan_rpm(void) { int rv; @@ -509,6 +547,7 @@ int cmd_pwm_get_fan_rpm(void) return 0; } + int cmd_pwm_set_fan_rpm(int argc, char *argv[]) { struct lpc_params_pwm_set_fan_target_rpm p; @@ -535,6 +574,7 @@ int cmd_pwm_set_fan_rpm(int argc, char *argv[]) return 0; } + int cmd_pwm_get_keyboard_backlight(void) { struct lpc_response_pwm_get_keyboard_backlight r; @@ -550,6 +590,7 @@ int cmd_pwm_get_keyboard_backlight(void) return 0; } + int cmd_pwm_set_keyboard_backlight(int argc, char *argv[]) { struct lpc_params_pwm_set_keyboard_backlight p; @@ -576,6 +617,7 @@ int cmd_pwm_set_keyboard_backlight(int argc, char *argv[]) return 0; } + int cmd_usb_charge_set_mode(int argc, char *argv[]) { struct lpc_params_usb_charge_set_mode p; @@ -609,6 +651,124 @@ int cmd_usb_charge_set_mode(int argc, char *argv[]) return 0; } + +int cmd_pstore_info(void) +{ + struct lpc_response_pstore_info r; + int rv; + + rv = ec_command(EC_LPC_COMMAND_PSTORE_INFO, NULL, 0, &r, sizeof(r)); + if (rv) + return rv; + + printf("PstoreSize %d\nAccessSize %d\n", r.pstore_size, r.access_size); + return 0; +} + + +int cmd_pstore_read(int argc, char *argv[]) +{ + struct lpc_params_pstore_read p; + struct lpc_response_pstore_read r; + int offset, size; + int rv; + int i; + char *e; + char *buf; + + if (argc < 3) { + fprintf(stderr, + "Usage: pstoreread \n"); + return -1; + } + offset = strtol(argv[0], &e, 0); + if ((e && *e) || offset < 0 || offset > 0x10000) { + fprintf(stderr, "Bad offset.\n"); + return -1; + } + size = strtol(argv[1], &e, 0); + if ((e && *e) || size <= 0 || size > 0x10000) { + fprintf(stderr, "Bad size.\n"); + return -1; + } + printf("Reading %d bytes at offset %d...\n", size, offset); + + buf = (char *)malloc(size); + if (!buf) { + fprintf(stderr, "Unable to allocate buffer.\n"); + return -1; + } + + /* Read data in chunks */ + for (i = 0; i < size; i += EC_LPC_PSTORE_SIZE_MAX) { + p.offset = offset + i; + p.size = MIN(size - i, EC_LPC_PSTORE_SIZE_MAX); + rv = ec_command(EC_LPC_COMMAND_PSTORE_READ, + &p, sizeof(p), &r, sizeof(r)); + if (rv) { + fprintf(stderr, "Read error at offset %d\n", i); + free(buf); + return -1; + } + memcpy(buf + i, r.data, p.size); + } + + rv = write_file(argv[2], buf, size); + free(buf); + if (rv) + return -1; + + printf("done.\n"); + return 0; +} + + +int cmd_pstore_write(int argc, char *argv[]) +{ + struct lpc_params_pstore_write p; + int offset, size; + int rv; + int i; + char *e; + char *buf; + + if (argc < 2) { + fprintf(stderr, "Usage: pstorewrite \n"); + return -1; + } + offset = strtol(argv[0], &e, 0); + if ((e && *e) || offset < 0 || offset > 0x10000) { + fprintf(stderr, "Bad offset.\n"); + return -1; + } + + /* Read the input file */ + buf = read_file(argv[1], &size); + if (!buf) + return -1; + + printf("Writing to offset %d...\n", offset); + + /* Write data in chunks */ + for (i = 0; i < size; i += EC_LPC_PSTORE_SIZE_MAX) { + p.offset = offset + i; + p.size = MIN(size - i, EC_LPC_PSTORE_SIZE_MAX); + memcpy(p.data, buf + i, p.size); + rv = ec_command(EC_LPC_COMMAND_PSTORE_WRITE, + &p, sizeof(p), NULL, 0); + if (rv) { + fprintf(stderr, "Write error at offset %d\n", i); + free(buf); + return -1; + } + } + + free(buf); + printf("done.\n"); + return 0; +} + + int main(int argc, char *argv[]) { if (argc < 2 || !strcasecmp(argv[1], "-?") || @@ -652,6 +812,12 @@ int main(int argc, char *argv[]) return cmd_pwm_set_keyboard_backlight(argc - 2, argv + 2); if (!strcasecmp(argv[1], "usbchargemode")) return cmd_usb_charge_set_mode(argc - 2, argv + 2); + if (!strcasecmp(argv[1], "pstoreinfo")) + return cmd_pstore_info(); + if (!strcasecmp(argv[1], "pstoreread")) + return cmd_pstore_read(argc - 2, argv + 2); + if (!strcasecmp(argv[1], "pstorewrite")) + return cmd_pstore_write(argc - 2, argv + 2); /* If we're still here, command was unknown */ fprintf(stderr, "Unknown command '%s'\n\n", argv[1]);