Files
OpenCellular/common/host_command.c
Randall Spangler 7ee63359b8 Support preserving reset flags across a reset
This is needed for flash pre-init to be able to hard reset to clear
uncommitted write protect flags without losing the reset flags.

BUG=chrome-os-partner:11368
TEST=manual

Use reboot and sysinfo commands...

1. reset with keyboard.  flags -> reset-pin
2. 'reboot soft preserve'  flags -> soft reset-pin power-on
3. 'reboot hard preserve'  flags -> hard soft reset-pin power-on
4. 'reboot soft'.  flags -> soft
5. 'reboot hard'.  flags -> hard power-on

Change-Id: I6164a78d99c5c10330f90f651148c5795e7afdda
Signed-off-by: Randall Spangler <rspangler@chromium.org>
Reviewed-on: https://gerrit.chromium.org/gerrit/27418
2012-07-16 10:20:58 -07:00

232 lines
5.7 KiB
C

/* 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.
*/
/* Host command module for Chrome EC */
#include "common.h"
#include "console.h"
#include "ec_commands.h"
#include "host_command.h"
#include "link_defs.h"
#include "lpc.h"
#include "system.h"
#include "task.h"
#include "timer.h"
#include "util.h"
/* Console output macros */
#define CPUTS(outstr) cputs(CC_SYSTEM, outstr)
#define CPRINTF(format, args...) cprintf(CC_SYSTEM, format, ## args)
#define TASK_EVENT_CMD_PENDING TASK_EVENT_CUSTOM(1)
static struct host_cmd_handler_args *pending_args;
#ifndef CONFIG_LPC
static uint8_t host_memmap[EC_MEMMAP_SIZE];
#endif
uint8_t *host_get_memmap(int offset)
{
#ifdef CONFIG_LPC
return lpc_get_memmap_range() + offset;
#else
return host_memmap + offset;
#endif
}
void host_command_received(struct host_cmd_handler_args *args)
{
/* TODO: should warn if we already think we're in a command */
/*
* If this is the reboot command, reboot immediately. This gives the
* host processor a way to unwedge the EC even if it's busy with some
* other command.
*/
if (args->command == EC_CMD_REBOOT) {
system_reset(SYSTEM_RESET_HARD);
/* Reset should never return; if it does, post an error */
host_send_response(EC_RES_ERROR);
return;
}
/* Save the command */
pending_args = args;
/* Wake up the task to handle the command */
task_set_event(TASK_ID_HOSTCMD, TASK_EVENT_CMD_PENDING, 0);
}
/*
* Find a command by command number. Returns the command structure, or NULL if
* no match found.
*/
static const struct host_command *find_host_command(int command)
{
const struct host_command *cmd;
for (cmd = __hcmds; cmd < __hcmds_end; cmd++) {
if (command == cmd->command)
return cmd;
}
return NULL;
}
static int host_command_proto_version(struct host_cmd_handler_args *args)
{
struct ec_response_proto_version *r =
(struct ec_response_proto_version *)args->response;
r->version = EC_PROTO_VERSION;
args->response_size = sizeof(*r);
return EC_RES_SUCCESS;
}
DECLARE_HOST_COMMAND(EC_CMD_PROTO_VERSION,
host_command_proto_version,
EC_VER_MASK(0));
static int host_command_hello(struct host_cmd_handler_args *args)
{
const struct ec_params_hello *p =
(const struct ec_params_hello *)args->params;
struct ec_response_hello *r =
(struct ec_response_hello *)args->response;
uint32_t d = p->in_data;
r->out_data = d + 0x01020304;
args->response_size = sizeof(*r);
return EC_RES_SUCCESS;
}
DECLARE_HOST_COMMAND(EC_CMD_HELLO,
host_command_hello,
EC_VER_MASK(0));
static int host_command_read_test(struct host_cmd_handler_args *args)
{
const struct ec_params_read_test *p =
(const struct ec_params_read_test *)args->params;
struct ec_response_read_test *r =
(struct ec_response_read_test *)args->response;
int offset = p->offset;
int size = p->size / sizeof(uint32_t);
int i;
if (size > ARRAY_SIZE(r->data))
return EC_RES_ERROR;
for (i = 0; i < size; i++)
r->data[i] = offset + i;
args->response_size = sizeof(*r);
return EC_RES_SUCCESS;
}
DECLARE_HOST_COMMAND(EC_CMD_READ_TEST,
host_command_read_test,
EC_VER_MASK(0));
#ifndef CONFIG_LPC
/*
* Host command to read memory map is not needed on LPC, because LPC can
* directly map the data to the host's memory space.
*/
static int host_command_read_memmap(struct host_cmd_handler_args *args)
{
const struct ec_params_read_memmap *p =
(const struct ec_params_read_memmap *)args->params;
/* Copy params out of data before we overwrite it with output */
uint8_t offset = p->offset;
uint8_t size = p->size;
if (size > EC_MEMMAP_SIZE || offset > EC_MEMMAP_SIZE ||
offset + size > EC_MEMMAP_SIZE)
return EC_RES_INVALID_PARAM;
args->response = host_get_memmap(offset);
args->response_size = size;
return EC_RES_SUCCESS;
}
DECLARE_HOST_COMMAND(EC_CMD_READ_MEMMAP,
host_command_read_memmap,
EC_VER_MASK(0));
#endif
static int host_command_get_cmd_versions(struct host_cmd_handler_args *args)
{
const struct ec_params_get_cmd_versions *p =
(const struct ec_params_get_cmd_versions *)args->params;
struct ec_response_get_cmd_versions *r =
(struct ec_response_get_cmd_versions *)args->response;
const struct host_command *cmd = find_host_command(p->cmd);
if (!cmd)
return EC_RES_INVALID_PARAM;
r->version_mask = cmd->version_mask;
args->response_size = sizeof(*r);
return EC_RES_SUCCESS;
}
DECLARE_HOST_COMMAND(EC_CMD_GET_CMD_VERSIONS,
host_command_get_cmd_versions,
EC_VER_MASK(0));
enum ec_status host_command_process(struct host_cmd_handler_args *args)
{
const struct host_command *cmd = find_host_command(args->command);
CPRINTF("[%T hostcmd 0x%02x]\n", args->command);
if (!cmd)
return EC_RES_INVALID_COMMAND;
if (!(EC_VER_MASK(args->version) & cmd->version_mask))
return EC_RES_INVALID_VERSION;
return cmd->handler(args);
}
/*****************************************************************************/
/* Initialization / task */
static int host_command_init(void)
{
/* Initialize memory map ID area */
host_get_memmap(EC_MEMMAP_ID)[0] = 'E';
host_get_memmap(EC_MEMMAP_ID)[1] = 'C';
*host_get_memmap(EC_MEMMAP_ID_VERSION) = 1;
*host_get_memmap(EC_MEMMAP_EVENTS_VERSION) = 1;
host_set_single_event(EC_HOST_EVENT_INTERFACE_READY);
CPRINTF("[%T hostcmd init 0x%x]\n", host_get_events());
return EC_SUCCESS;
}
void host_command_task(void)
{
host_command_init();
while (1) {
/* wait for the next command event */
int evt = task_wait_event(-1);
/* process it */
if ((evt & TASK_EVENT_CMD_PENDING) && pending_args) {
enum ec_status res = host_command_process(pending_args);
host_send_response(res);
}
}
}