|
|
|
@ -1055,87 +1055,6 @@ int cros_ec_decode_ec_flash(const void *blob, int node, |
|
|
|
|
return 0; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
int cros_ec_i2c_xfer_old(struct cros_ec_dev *dev, uchar chip, uint addr, |
|
|
|
|
int alen, uchar *buffer, int len, int is_read) |
|
|
|
|
{ |
|
|
|
|
union { |
|
|
|
|
struct ec_params_i2c_passthru p; |
|
|
|
|
uint8_t outbuf[EC_PROTO2_MAX_PARAM_SIZE]; |
|
|
|
|
} params; |
|
|
|
|
union { |
|
|
|
|
struct ec_response_i2c_passthru r; |
|
|
|
|
uint8_t inbuf[EC_PROTO2_MAX_PARAM_SIZE]; |
|
|
|
|
} response; |
|
|
|
|
struct ec_params_i2c_passthru *p = ¶ms.p; |
|
|
|
|
struct ec_response_i2c_passthru *r = &response.r; |
|
|
|
|
struct ec_params_i2c_passthru_msg *msg = p->msg; |
|
|
|
|
uint8_t *pdata; |
|
|
|
|
int read_len, write_len; |
|
|
|
|
int size; |
|
|
|
|
int rv; |
|
|
|
|
|
|
|
|
|
p->port = 0; |
|
|
|
|
|
|
|
|
|
if (alen != 1) { |
|
|
|
|
printf("Unsupported address length %d\n", alen); |
|
|
|
|
return -1; |
|
|
|
|
} |
|
|
|
|
if (is_read) { |
|
|
|
|
read_len = len; |
|
|
|
|
write_len = alen; |
|
|
|
|
p->num_msgs = 2; |
|
|
|
|
} else { |
|
|
|
|
read_len = 0; |
|
|
|
|
write_len = alen + len; |
|
|
|
|
p->num_msgs = 1; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
size = sizeof(*p) + p->num_msgs * sizeof(*msg); |
|
|
|
|
if (size + write_len > sizeof(params)) { |
|
|
|
|
puts("Params too large for buffer\n"); |
|
|
|
|
return -1; |
|
|
|
|
} |
|
|
|
|
if (sizeof(*r) + read_len > sizeof(response)) { |
|
|
|
|
puts("Read length too big for buffer\n"); |
|
|
|
|
return -1; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
/* Create a message to write the register address and optional data */ |
|
|
|
|
pdata = (uint8_t *)p + size; |
|
|
|
|
msg->addr_flags = chip; |
|
|
|
|
msg->len = write_len; |
|
|
|
|
pdata[0] = addr; |
|
|
|
|
if (!is_read) |
|
|
|
|
memcpy(pdata + 1, buffer, len); |
|
|
|
|
msg++; |
|
|
|
|
|
|
|
|
|
if (read_len) { |
|
|
|
|
msg->addr_flags = chip | EC_I2C_FLAG_READ; |
|
|
|
|
msg->len = read_len; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
rv = ec_command(dev, EC_CMD_I2C_PASSTHRU, 0, p, size + write_len, |
|
|
|
|
r, sizeof(*r) + read_len); |
|
|
|
|
if (rv < 0) |
|
|
|
|
return rv; |
|
|
|
|
|
|
|
|
|
/* Parse response */ |
|
|
|
|
if (r->i2c_status & EC_I2C_STATUS_ERROR) { |
|
|
|
|
printf("Transfer failed with status=0x%x\n", r->i2c_status); |
|
|
|
|
return -1; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
if (rv < sizeof(*r) + read_len) { |
|
|
|
|
puts("Truncated read response\n"); |
|
|
|
|
return -1; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
if (read_len) |
|
|
|
|
memcpy(buffer, r->data, read_len); |
|
|
|
|
|
|
|
|
|
return 0; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
int cros_ec_i2c_tunnel(struct udevice *dev, struct i2c_msg *in, int nmsgs) |
|
|
|
|
{ |
|
|
|
|
struct cros_ec_dev *cdev = dev_get_uclass_priv(dev); |
|
|
|
@ -1266,187 +1185,6 @@ static int do_read_write(struct cros_ec_dev *dev, int is_write, int argc, |
|
|
|
|
return 0; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* get_alen() - Small parser helper function to get address length |
|
|
|
|
* |
|
|
|
|
* Returns the address length. |
|
|
|
|
*/ |
|
|
|
|
static uint get_alen(char *arg) |
|
|
|
|
{ |
|
|
|
|
int j; |
|
|
|
|
int alen; |
|
|
|
|
|
|
|
|
|
alen = 1; |
|
|
|
|
for (j = 0; j < 8; j++) { |
|
|
|
|
if (arg[j] == '.') { |
|
|
|
|
alen = arg[j+1] - '0'; |
|
|
|
|
break; |
|
|
|
|
} else if (arg[j] == '\0') { |
|
|
|
|
break; |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
return alen; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
#define DISP_LINE_LEN 16 |
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
* TODO(sjg@chromium.org): This code copied almost verbatim from cmd_i2c.c |
|
|
|
|
* so we can remove it later. |
|
|
|
|
*/ |
|
|
|
|
static int cros_ec_i2c_md(struct cros_ec_dev *dev, int flag, int argc, |
|
|
|
|
char * const argv[]) |
|
|
|
|
{ |
|
|
|
|
u_char chip; |
|
|
|
|
uint addr, alen, length = 0x10; |
|
|
|
|
int j, nbytes, linebytes; |
|
|
|
|
|
|
|
|
|
if (argc < 2) |
|
|
|
|
return CMD_RET_USAGE; |
|
|
|
|
|
|
|
|
|
if (1 || (flag & CMD_FLAG_REPEAT) == 0) { |
|
|
|
|
/*
|
|
|
|
|
* New command specified. |
|
|
|
|
*/ |
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
* I2C chip address |
|
|
|
|
*/ |
|
|
|
|
chip = simple_strtoul(argv[0], NULL, 16); |
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
* I2C data address within the chip. This can be 1 or |
|
|
|
|
* 2 bytes long. Some day it might be 3 bytes long :-). |
|
|
|
|
*/ |
|
|
|
|
addr = simple_strtoul(argv[1], NULL, 16); |
|
|
|
|
alen = get_alen(argv[1]); |
|
|
|
|
if (alen > 3) |
|
|
|
|
return CMD_RET_USAGE; |
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
* If another parameter, it is the length to display. |
|
|
|
|
* Length is the number of objects, not number of bytes. |
|
|
|
|
*/ |
|
|
|
|
if (argc > 2) |
|
|
|
|
length = simple_strtoul(argv[2], NULL, 16); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
* Print the lines. |
|
|
|
|
* |
|
|
|
|
* We buffer all read data, so we can make sure data is read only |
|
|
|
|
* once. |
|
|
|
|
*/ |
|
|
|
|
nbytes = length; |
|
|
|
|
do { |
|
|
|
|
unsigned char linebuf[DISP_LINE_LEN]; |
|
|
|
|
unsigned char *cp; |
|
|
|
|
|
|
|
|
|
linebytes = (nbytes > DISP_LINE_LEN) ? DISP_LINE_LEN : nbytes; |
|
|
|
|
|
|
|
|
|
if (cros_ec_i2c_xfer_old(dev, chip, addr, alen, linebuf, |
|
|
|
|
linebytes, 1)) |
|
|
|
|
puts("Error reading the chip.\n"); |
|
|
|
|
else { |
|
|
|
|
printf("%04x:", addr); |
|
|
|
|
cp = linebuf; |
|
|
|
|
for (j = 0; j < linebytes; j++) { |
|
|
|
|
printf(" %02x", *cp++); |
|
|
|
|
addr++; |
|
|
|
|
} |
|
|
|
|
puts(" "); |
|
|
|
|
cp = linebuf; |
|
|
|
|
for (j = 0; j < linebytes; j++) { |
|
|
|
|
if ((*cp < 0x20) || (*cp > 0x7e)) |
|
|
|
|
puts("."); |
|
|
|
|
else |
|
|
|
|
printf("%c", *cp); |
|
|
|
|
cp++; |
|
|
|
|
} |
|
|
|
|
putc('\n'); |
|
|
|
|
} |
|
|
|
|
nbytes -= linebytes; |
|
|
|
|
} while (nbytes > 0); |
|
|
|
|
|
|
|
|
|
return 0; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
static int cros_ec_i2c_mw(struct cros_ec_dev *dev, int flag, int argc, |
|
|
|
|
char * const argv[]) |
|
|
|
|
{ |
|
|
|
|
uchar chip; |
|
|
|
|
ulong addr; |
|
|
|
|
uint alen; |
|
|
|
|
uchar byte; |
|
|
|
|
int count; |
|
|
|
|
|
|
|
|
|
if ((argc < 3) || (argc > 4)) |
|
|
|
|
return CMD_RET_USAGE; |
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
* Chip is always specified. |
|
|
|
|
*/ |
|
|
|
|
chip = simple_strtoul(argv[0], NULL, 16); |
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
* Address is always specified. |
|
|
|
|
*/ |
|
|
|
|
addr = simple_strtoul(argv[1], NULL, 16); |
|
|
|
|
alen = get_alen(argv[1]); |
|
|
|
|
if (alen > 3) |
|
|
|
|
return CMD_RET_USAGE; |
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
* Value to write is always specified. |
|
|
|
|
*/ |
|
|
|
|
byte = simple_strtoul(argv[2], NULL, 16); |
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
* Optional count |
|
|
|
|
*/ |
|
|
|
|
if (argc == 4) |
|
|
|
|
count = simple_strtoul(argv[3], NULL, 16); |
|
|
|
|
else |
|
|
|
|
count = 1; |
|
|
|
|
|
|
|
|
|
while (count-- > 0) { |
|
|
|
|
if (cros_ec_i2c_xfer_old(dev, chip, addr++, alen, &byte, 1, 0)) |
|
|
|
|
puts("Error writing the chip.\n"); |
|
|
|
|
/*
|
|
|
|
|
* Wait for the write to complete. The write can take |
|
|
|
|
* up to 10mSec (we allow a little more time). |
|
|
|
|
*/ |
|
|
|
|
/*
|
|
|
|
|
* No write delay with FRAM devices. |
|
|
|
|
*/ |
|
|
|
|
#if !defined(CONFIG_SYS_I2C_FRAM) |
|
|
|
|
udelay(11000); |
|
|
|
|
#endif |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
return 0; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
/* Temporary code until we have driver model and can use the i2c command */ |
|
|
|
|
static int cros_ec_i2c_passthrough(struct cros_ec_dev *dev, int flag, |
|
|
|
|
int argc, char * const argv[]) |
|
|
|
|
{ |
|
|
|
|
const char *cmd; |
|
|
|
|
|
|
|
|
|
if (argc < 1) |
|
|
|
|
return CMD_RET_USAGE; |
|
|
|
|
cmd = *argv++; |
|
|
|
|
argc--; |
|
|
|
|
if (0 == strcmp("md", cmd)) |
|
|
|
|
cros_ec_i2c_md(dev, flag, argc, argv); |
|
|
|
|
else if (0 == strcmp("mw", cmd)) |
|
|
|
|
cros_ec_i2c_mw(dev, flag, argc, argv); |
|
|
|
|
else |
|
|
|
|
return CMD_RET_USAGE; |
|
|
|
|
|
|
|
|
|
return 0; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
static int do_cros_ec(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[]) |
|
|
|
|
{ |
|
|
|
|
struct cros_ec_dev *dev; |
|
|
|
@ -1696,8 +1434,6 @@ static int do_cros_ec(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[]) |
|
|
|
|
debug("%s: Could not access LDO%d\n", __func__, index); |
|
|
|
|
return ret; |
|
|
|
|
} |
|
|
|
|
} else if (0 == strcmp("i2c", cmd)) { |
|
|
|
|
ret = cros_ec_i2c_passthrough(dev, flag, argc - 2, argv + 2); |
|
|
|
|
} else { |
|
|
|
|
return CMD_RET_USAGE; |
|
|
|
|
} |
|
|
|
@ -1734,9 +1470,7 @@ U_BOOT_CMD( |
|
|
|
|
"crosec vbnvcontext [hexstring] Read [write] VbNvContext from EC\n" |
|
|
|
|
"crosec ldo <idx> [<state>] Switch/Read LDO state\n" |
|
|
|
|
"crosec test run tests on cros_ec\n" |
|
|
|
|
"crosec version Read CROS-EC version\n" |
|
|
|
|
"crosec i2c md chip address[.0, .1, .2] [# of objects] - read from I2C passthru\n" |
|
|
|
|
"crosec i2c mw chip address[.0, .1, .2] value [count] - write to I2C passthru (fill)" |
|
|
|
|
"crosec version Read CROS-EC version" |
|
|
|
|
); |
|
|
|
|
#endif |
|
|
|
|
|
|
|
|
|