1*88364387SHung-ying Tyan /* 2*88364387SHung-ying Tyan * Chromium OS cros_ec driver 3*88364387SHung-ying Tyan * 4*88364387SHung-ying Tyan * Copyright (c) 2012 The Chromium OS Authors. 5*88364387SHung-ying Tyan * See file CREDITS for list of people who contributed to this 6*88364387SHung-ying Tyan * project. 7*88364387SHung-ying Tyan * 8*88364387SHung-ying Tyan * This program is free software; you can redistribute it and/or 9*88364387SHung-ying Tyan * modify it under the terms of the GNU General Public License as 10*88364387SHung-ying Tyan * published by the Free Software Foundation; either version 2 of 11*88364387SHung-ying Tyan * the License, or (at your option) any later version. 12*88364387SHung-ying Tyan * 13*88364387SHung-ying Tyan * This program is distributed in the hope that it will be useful, 14*88364387SHung-ying Tyan * but WITHOUT ANY WARRANTY; without even the implied warranty of 15*88364387SHung-ying Tyan * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 16*88364387SHung-ying Tyan * GNU General Public License for more details. 17*88364387SHung-ying Tyan * 18*88364387SHung-ying Tyan * You should have received a copy of the GNU General Public License 19*88364387SHung-ying Tyan * along with this program; if not, write to the Free Software 20*88364387SHung-ying Tyan * Foundation, Inc., 59 Temple Place, Suite 330, Boston, 21*88364387SHung-ying Tyan * MA 02111-1307 USA 22*88364387SHung-ying Tyan */ 23*88364387SHung-ying Tyan 24*88364387SHung-ying Tyan /* 25*88364387SHung-ying Tyan * The Matrix Keyboard Protocol driver handles talking to the keyboard 26*88364387SHung-ying Tyan * controller chip. Mostly this is for keyboard functions, but some other 27*88364387SHung-ying Tyan * things have slipped in, so we provide generic services to talk to the 28*88364387SHung-ying Tyan * KBC. 29*88364387SHung-ying Tyan */ 30*88364387SHung-ying Tyan 31*88364387SHung-ying Tyan #include <common.h> 32*88364387SHung-ying Tyan #include <command.h> 33*88364387SHung-ying Tyan #include <i2c.h> 34*88364387SHung-ying Tyan #include <cros_ec.h> 35*88364387SHung-ying Tyan #include <fdtdec.h> 36*88364387SHung-ying Tyan #include <malloc.h> 37*88364387SHung-ying Tyan #include <spi.h> 38*88364387SHung-ying Tyan #include <asm/io.h> 39*88364387SHung-ying Tyan #include <asm-generic/gpio.h> 40*88364387SHung-ying Tyan 41*88364387SHung-ying Tyan #ifdef DEBUG_TRACE 42*88364387SHung-ying Tyan #define debug_trace(fmt, b...) debug(fmt, #b) 43*88364387SHung-ying Tyan #else 44*88364387SHung-ying Tyan #define debug_trace(fmt, b...) 45*88364387SHung-ying Tyan #endif 46*88364387SHung-ying Tyan 47*88364387SHung-ying Tyan enum { 48*88364387SHung-ying Tyan /* Timeout waiting for a flash erase command to complete */ 49*88364387SHung-ying Tyan CROS_EC_CMD_TIMEOUT_MS = 5000, 50*88364387SHung-ying Tyan /* Timeout waiting for a synchronous hash to be recomputed */ 51*88364387SHung-ying Tyan CROS_EC_CMD_HASH_TIMEOUT_MS = 2000, 52*88364387SHung-ying Tyan }; 53*88364387SHung-ying Tyan 54*88364387SHung-ying Tyan static struct cros_ec_dev static_dev, *last_dev; 55*88364387SHung-ying Tyan 56*88364387SHung-ying Tyan DECLARE_GLOBAL_DATA_PTR; 57*88364387SHung-ying Tyan 58*88364387SHung-ying Tyan /* Note: depends on enum ec_current_image */ 59*88364387SHung-ying Tyan static const char * const ec_current_image_name[] = {"unknown", "RO", "RW"}; 60*88364387SHung-ying Tyan 61*88364387SHung-ying Tyan void cros_ec_dump_data(const char *name, int cmd, const uint8_t *data, int len) 62*88364387SHung-ying Tyan { 63*88364387SHung-ying Tyan #ifdef DEBUG 64*88364387SHung-ying Tyan int i; 65*88364387SHung-ying Tyan 66*88364387SHung-ying Tyan printf("%s: ", name); 67*88364387SHung-ying Tyan if (cmd != -1) 68*88364387SHung-ying Tyan printf("cmd=%#x: ", cmd); 69*88364387SHung-ying Tyan for (i = 0; i < len; i++) 70*88364387SHung-ying Tyan printf("%02x ", data[i]); 71*88364387SHung-ying Tyan printf("\n"); 72*88364387SHung-ying Tyan #endif 73*88364387SHung-ying Tyan } 74*88364387SHung-ying Tyan 75*88364387SHung-ying Tyan /* 76*88364387SHung-ying Tyan * Calculate a simple 8-bit checksum of a data block 77*88364387SHung-ying Tyan * 78*88364387SHung-ying Tyan * @param data Data block to checksum 79*88364387SHung-ying Tyan * @param size Size of data block in bytes 80*88364387SHung-ying Tyan * @return checksum value (0 to 255) 81*88364387SHung-ying Tyan */ 82*88364387SHung-ying Tyan int cros_ec_calc_checksum(const uint8_t *data, int size) 83*88364387SHung-ying Tyan { 84*88364387SHung-ying Tyan int csum, i; 85*88364387SHung-ying Tyan 86*88364387SHung-ying Tyan for (i = csum = 0; i < size; i++) 87*88364387SHung-ying Tyan csum += data[i]; 88*88364387SHung-ying Tyan return csum & 0xff; 89*88364387SHung-ying Tyan } 90*88364387SHung-ying Tyan 91*88364387SHung-ying Tyan static int send_command(struct cros_ec_dev *dev, uint8_t cmd, int cmd_version, 92*88364387SHung-ying Tyan const void *dout, int dout_len, 93*88364387SHung-ying Tyan uint8_t **dinp, int din_len) 94*88364387SHung-ying Tyan { 95*88364387SHung-ying Tyan int ret; 96*88364387SHung-ying Tyan 97*88364387SHung-ying Tyan switch (dev->interface) { 98*88364387SHung-ying Tyan #ifdef CONFIG_CROS_EC_SPI 99*88364387SHung-ying Tyan case CROS_EC_IF_SPI: 100*88364387SHung-ying Tyan ret = cros_ec_spi_command(dev, cmd, cmd_version, 101*88364387SHung-ying Tyan (const uint8_t *)dout, dout_len, 102*88364387SHung-ying Tyan dinp, din_len); 103*88364387SHung-ying Tyan break; 104*88364387SHung-ying Tyan #endif 105*88364387SHung-ying Tyan #ifdef CONFIG_CROS_EC_I2C 106*88364387SHung-ying Tyan case CROS_EC_IF_I2C: 107*88364387SHung-ying Tyan ret = cros_ec_i2c_command(dev, cmd, cmd_version, 108*88364387SHung-ying Tyan (const uint8_t *)dout, dout_len, 109*88364387SHung-ying Tyan dinp, din_len); 110*88364387SHung-ying Tyan break; 111*88364387SHung-ying Tyan #endif 112*88364387SHung-ying Tyan #ifdef CONFIG_CROS_EC_LPC 113*88364387SHung-ying Tyan case CROS_EC_IF_LPC: 114*88364387SHung-ying Tyan ret = cros_ec_lpc_command(dev, cmd, cmd_version, 115*88364387SHung-ying Tyan (const uint8_t *)dout, dout_len, 116*88364387SHung-ying Tyan dinp, din_len); 117*88364387SHung-ying Tyan break; 118*88364387SHung-ying Tyan #endif 119*88364387SHung-ying Tyan case CROS_EC_IF_NONE: 120*88364387SHung-ying Tyan default: 121*88364387SHung-ying Tyan ret = -1; 122*88364387SHung-ying Tyan } 123*88364387SHung-ying Tyan 124*88364387SHung-ying Tyan return ret; 125*88364387SHung-ying Tyan } 126*88364387SHung-ying Tyan 127*88364387SHung-ying Tyan /** 128*88364387SHung-ying Tyan * Send a command to the CROS-EC device and return the reply. 129*88364387SHung-ying Tyan * 130*88364387SHung-ying Tyan * The device's internal input/output buffers are used. 131*88364387SHung-ying Tyan * 132*88364387SHung-ying Tyan * @param dev CROS-EC device 133*88364387SHung-ying Tyan * @param cmd Command to send (EC_CMD_...) 134*88364387SHung-ying Tyan * @param cmd_version Version of command to send (EC_VER_...) 135*88364387SHung-ying Tyan * @param dout Output data (may be NULL If dout_len=0) 136*88364387SHung-ying Tyan * @param dout_len Size of output data in bytes 137*88364387SHung-ying Tyan * @param dinp Response data (may be NULL If din_len=0). 138*88364387SHung-ying Tyan * If not NULL, it will be updated to point to the data 139*88364387SHung-ying Tyan * and will always be double word aligned (64-bits) 140*88364387SHung-ying Tyan * @param din_len Maximum size of response in bytes 141*88364387SHung-ying Tyan * @return number of bytes in response, or -1 on error 142*88364387SHung-ying Tyan */ 143*88364387SHung-ying Tyan static int ec_command_inptr(struct cros_ec_dev *dev, uint8_t cmd, 144*88364387SHung-ying Tyan int cmd_version, const void *dout, int dout_len, uint8_t **dinp, 145*88364387SHung-ying Tyan int din_len) 146*88364387SHung-ying Tyan { 147*88364387SHung-ying Tyan uint8_t *din; 148*88364387SHung-ying Tyan int len; 149*88364387SHung-ying Tyan 150*88364387SHung-ying Tyan if (cmd_version != 0 && !dev->cmd_version_is_supported) { 151*88364387SHung-ying Tyan debug("%s: Command version >0 unsupported\n", __func__); 152*88364387SHung-ying Tyan return -1; 153*88364387SHung-ying Tyan } 154*88364387SHung-ying Tyan len = send_command(dev, cmd, cmd_version, dout, dout_len, 155*88364387SHung-ying Tyan &din, din_len); 156*88364387SHung-ying Tyan 157*88364387SHung-ying Tyan /* If the command doesn't complete, wait a while */ 158*88364387SHung-ying Tyan if (len == -EC_RES_IN_PROGRESS) { 159*88364387SHung-ying Tyan struct ec_response_get_comms_status *resp; 160*88364387SHung-ying Tyan ulong start; 161*88364387SHung-ying Tyan 162*88364387SHung-ying Tyan /* Wait for command to complete */ 163*88364387SHung-ying Tyan start = get_timer(0); 164*88364387SHung-ying Tyan do { 165*88364387SHung-ying Tyan int ret; 166*88364387SHung-ying Tyan 167*88364387SHung-ying Tyan mdelay(50); /* Insert some reasonable delay */ 168*88364387SHung-ying Tyan ret = send_command(dev, EC_CMD_GET_COMMS_STATUS, 0, 169*88364387SHung-ying Tyan NULL, 0, 170*88364387SHung-ying Tyan (uint8_t **)&resp, sizeof(*resp)); 171*88364387SHung-ying Tyan if (ret < 0) 172*88364387SHung-ying Tyan return ret; 173*88364387SHung-ying Tyan 174*88364387SHung-ying Tyan if (get_timer(start) > CROS_EC_CMD_TIMEOUT_MS) { 175*88364387SHung-ying Tyan debug("%s: Command %#02x timeout\n", 176*88364387SHung-ying Tyan __func__, cmd); 177*88364387SHung-ying Tyan return -EC_RES_TIMEOUT; 178*88364387SHung-ying Tyan } 179*88364387SHung-ying Tyan } while (resp->flags & EC_COMMS_STATUS_PROCESSING); 180*88364387SHung-ying Tyan 181*88364387SHung-ying Tyan /* OK it completed, so read the status response */ 182*88364387SHung-ying Tyan /* not sure why it was 0 for the last argument */ 183*88364387SHung-ying Tyan len = send_command(dev, EC_CMD_RESEND_RESPONSE, 0, 184*88364387SHung-ying Tyan NULL, 0, &din, din_len); 185*88364387SHung-ying Tyan } 186*88364387SHung-ying Tyan 187*88364387SHung-ying Tyan debug("%s: len=%d, dinp=%p, *dinp=%p\n", __func__, len, dinp, *dinp); 188*88364387SHung-ying Tyan if (dinp) { 189*88364387SHung-ying Tyan /* If we have any data to return, it must be 64bit-aligned */ 190*88364387SHung-ying Tyan assert(len <= 0 || !((uintptr_t)din & 7)); 191*88364387SHung-ying Tyan *dinp = din; 192*88364387SHung-ying Tyan } 193*88364387SHung-ying Tyan 194*88364387SHung-ying Tyan return len; 195*88364387SHung-ying Tyan } 196*88364387SHung-ying Tyan 197*88364387SHung-ying Tyan /** 198*88364387SHung-ying Tyan * Send a command to the CROS-EC device and return the reply. 199*88364387SHung-ying Tyan * 200*88364387SHung-ying Tyan * The device's internal input/output buffers are used. 201*88364387SHung-ying Tyan * 202*88364387SHung-ying Tyan * @param dev CROS-EC device 203*88364387SHung-ying Tyan * @param cmd Command to send (EC_CMD_...) 204*88364387SHung-ying Tyan * @param cmd_version Version of command to send (EC_VER_...) 205*88364387SHung-ying Tyan * @param dout Output data (may be NULL If dout_len=0) 206*88364387SHung-ying Tyan * @param dout_len Size of output data in bytes 207*88364387SHung-ying Tyan * @param din Response data (may be NULL If din_len=0). 208*88364387SHung-ying Tyan * It not NULL, it is a place for ec_command() to copy the 209*88364387SHung-ying Tyan * data to. 210*88364387SHung-ying Tyan * @param din_len Maximum size of response in bytes 211*88364387SHung-ying Tyan * @return number of bytes in response, or -1 on error 212*88364387SHung-ying Tyan */ 213*88364387SHung-ying Tyan static int ec_command(struct cros_ec_dev *dev, uint8_t cmd, int cmd_version, 214*88364387SHung-ying Tyan const void *dout, int dout_len, 215*88364387SHung-ying Tyan void *din, int din_len) 216*88364387SHung-ying Tyan { 217*88364387SHung-ying Tyan uint8_t *in_buffer; 218*88364387SHung-ying Tyan int len; 219*88364387SHung-ying Tyan 220*88364387SHung-ying Tyan assert((din_len == 0) || din); 221*88364387SHung-ying Tyan len = ec_command_inptr(dev, cmd, cmd_version, dout, dout_len, 222*88364387SHung-ying Tyan &in_buffer, din_len); 223*88364387SHung-ying Tyan if (len > 0) { 224*88364387SHung-ying Tyan /* 225*88364387SHung-ying Tyan * If we were asked to put it somewhere, do so, otherwise just 226*88364387SHung-ying Tyan * disregard the result. 227*88364387SHung-ying Tyan */ 228*88364387SHung-ying Tyan if (din && in_buffer) { 229*88364387SHung-ying Tyan assert(len <= din_len); 230*88364387SHung-ying Tyan memmove(din, in_buffer, len); 231*88364387SHung-ying Tyan } 232*88364387SHung-ying Tyan } 233*88364387SHung-ying Tyan return len; 234*88364387SHung-ying Tyan } 235*88364387SHung-ying Tyan 236*88364387SHung-ying Tyan int cros_ec_scan_keyboard(struct cros_ec_dev *dev, struct mbkp_keyscan *scan) 237*88364387SHung-ying Tyan { 238*88364387SHung-ying Tyan if (ec_command(dev, EC_CMD_CROS_EC_STATE, 0, NULL, 0, scan, 239*88364387SHung-ying Tyan sizeof(scan->data)) < sizeof(scan->data)) 240*88364387SHung-ying Tyan return -1; 241*88364387SHung-ying Tyan 242*88364387SHung-ying Tyan return 0; 243*88364387SHung-ying Tyan } 244*88364387SHung-ying Tyan 245*88364387SHung-ying Tyan int cros_ec_read_id(struct cros_ec_dev *dev, char *id, int maxlen) 246*88364387SHung-ying Tyan { 247*88364387SHung-ying Tyan struct ec_response_get_version *r; 248*88364387SHung-ying Tyan 249*88364387SHung-ying Tyan if (ec_command_inptr(dev, EC_CMD_GET_VERSION, 0, NULL, 0, 250*88364387SHung-ying Tyan (uint8_t **)&r, sizeof(*r)) < sizeof(*r)) 251*88364387SHung-ying Tyan return -1; 252*88364387SHung-ying Tyan 253*88364387SHung-ying Tyan if (maxlen > sizeof(r->version_string_ro)) 254*88364387SHung-ying Tyan maxlen = sizeof(r->version_string_ro); 255*88364387SHung-ying Tyan 256*88364387SHung-ying Tyan switch (r->current_image) { 257*88364387SHung-ying Tyan case EC_IMAGE_RO: 258*88364387SHung-ying Tyan memcpy(id, r->version_string_ro, maxlen); 259*88364387SHung-ying Tyan break; 260*88364387SHung-ying Tyan case EC_IMAGE_RW: 261*88364387SHung-ying Tyan memcpy(id, r->version_string_rw, maxlen); 262*88364387SHung-ying Tyan break; 263*88364387SHung-ying Tyan default: 264*88364387SHung-ying Tyan return -1; 265*88364387SHung-ying Tyan } 266*88364387SHung-ying Tyan 267*88364387SHung-ying Tyan id[maxlen - 1] = '\0'; 268*88364387SHung-ying Tyan return 0; 269*88364387SHung-ying Tyan } 270*88364387SHung-ying Tyan 271*88364387SHung-ying Tyan int cros_ec_read_version(struct cros_ec_dev *dev, 272*88364387SHung-ying Tyan struct ec_response_get_version **versionp) 273*88364387SHung-ying Tyan { 274*88364387SHung-ying Tyan if (ec_command_inptr(dev, EC_CMD_GET_VERSION, 0, NULL, 0, 275*88364387SHung-ying Tyan (uint8_t **)versionp, sizeof(**versionp)) 276*88364387SHung-ying Tyan < sizeof(**versionp)) 277*88364387SHung-ying Tyan return -1; 278*88364387SHung-ying Tyan 279*88364387SHung-ying Tyan return 0; 280*88364387SHung-ying Tyan } 281*88364387SHung-ying Tyan 282*88364387SHung-ying Tyan int cros_ec_read_build_info(struct cros_ec_dev *dev, char **strp) 283*88364387SHung-ying Tyan { 284*88364387SHung-ying Tyan if (ec_command_inptr(dev, EC_CMD_GET_BUILD_INFO, 0, NULL, 0, 285*88364387SHung-ying Tyan (uint8_t **)strp, EC_HOST_PARAM_SIZE) < 0) 286*88364387SHung-ying Tyan return -1; 287*88364387SHung-ying Tyan 288*88364387SHung-ying Tyan return 0; 289*88364387SHung-ying Tyan } 290*88364387SHung-ying Tyan 291*88364387SHung-ying Tyan int cros_ec_read_current_image(struct cros_ec_dev *dev, 292*88364387SHung-ying Tyan enum ec_current_image *image) 293*88364387SHung-ying Tyan { 294*88364387SHung-ying Tyan struct ec_response_get_version *r; 295*88364387SHung-ying Tyan 296*88364387SHung-ying Tyan if (ec_command_inptr(dev, EC_CMD_GET_VERSION, 0, NULL, 0, 297*88364387SHung-ying Tyan (uint8_t **)&r, sizeof(*r)) < sizeof(*r)) 298*88364387SHung-ying Tyan return -1; 299*88364387SHung-ying Tyan 300*88364387SHung-ying Tyan *image = r->current_image; 301*88364387SHung-ying Tyan return 0; 302*88364387SHung-ying Tyan } 303*88364387SHung-ying Tyan 304*88364387SHung-ying Tyan static int cros_ec_wait_on_hash_done(struct cros_ec_dev *dev, 305*88364387SHung-ying Tyan struct ec_response_vboot_hash *hash) 306*88364387SHung-ying Tyan { 307*88364387SHung-ying Tyan struct ec_params_vboot_hash p; 308*88364387SHung-ying Tyan ulong start; 309*88364387SHung-ying Tyan 310*88364387SHung-ying Tyan start = get_timer(0); 311*88364387SHung-ying Tyan while (hash->status == EC_VBOOT_HASH_STATUS_BUSY) { 312*88364387SHung-ying Tyan mdelay(50); /* Insert some reasonable delay */ 313*88364387SHung-ying Tyan 314*88364387SHung-ying Tyan p.cmd = EC_VBOOT_HASH_GET; 315*88364387SHung-ying Tyan if (ec_command(dev, EC_CMD_VBOOT_HASH, 0, &p, sizeof(p), 316*88364387SHung-ying Tyan hash, sizeof(*hash)) < 0) 317*88364387SHung-ying Tyan return -1; 318*88364387SHung-ying Tyan 319*88364387SHung-ying Tyan if (get_timer(start) > CROS_EC_CMD_HASH_TIMEOUT_MS) { 320*88364387SHung-ying Tyan debug("%s: EC_VBOOT_HASH_GET timeout\n", __func__); 321*88364387SHung-ying Tyan return -EC_RES_TIMEOUT; 322*88364387SHung-ying Tyan } 323*88364387SHung-ying Tyan } 324*88364387SHung-ying Tyan return 0; 325*88364387SHung-ying Tyan } 326*88364387SHung-ying Tyan 327*88364387SHung-ying Tyan 328*88364387SHung-ying Tyan int cros_ec_read_hash(struct cros_ec_dev *dev, 329*88364387SHung-ying Tyan struct ec_response_vboot_hash *hash) 330*88364387SHung-ying Tyan { 331*88364387SHung-ying Tyan struct ec_params_vboot_hash p; 332*88364387SHung-ying Tyan int rv; 333*88364387SHung-ying Tyan 334*88364387SHung-ying Tyan p.cmd = EC_VBOOT_HASH_GET; 335*88364387SHung-ying Tyan if (ec_command(dev, EC_CMD_VBOOT_HASH, 0, &p, sizeof(p), 336*88364387SHung-ying Tyan hash, sizeof(*hash)) < 0) 337*88364387SHung-ying Tyan return -1; 338*88364387SHung-ying Tyan 339*88364387SHung-ying Tyan /* If the EC is busy calculating the hash, fidget until it's done. */ 340*88364387SHung-ying Tyan rv = cros_ec_wait_on_hash_done(dev, hash); 341*88364387SHung-ying Tyan if (rv) 342*88364387SHung-ying Tyan return rv; 343*88364387SHung-ying Tyan 344*88364387SHung-ying Tyan /* If the hash is valid, we're done. Otherwise, we have to kick it off 345*88364387SHung-ying Tyan * again and wait for it to complete. Note that we explicitly assume 346*88364387SHung-ying Tyan * that hashing zero bytes is always wrong, even though that would 347*88364387SHung-ying Tyan * produce a valid hash value. */ 348*88364387SHung-ying Tyan if (hash->status == EC_VBOOT_HASH_STATUS_DONE && hash->size) 349*88364387SHung-ying Tyan return 0; 350*88364387SHung-ying Tyan 351*88364387SHung-ying Tyan debug("%s: No valid hash (status=%d size=%d). Compute one...\n", 352*88364387SHung-ying Tyan __func__, hash->status, hash->size); 353*88364387SHung-ying Tyan 354*88364387SHung-ying Tyan p.cmd = EC_VBOOT_HASH_RECALC; 355*88364387SHung-ying Tyan p.hash_type = EC_VBOOT_HASH_TYPE_SHA256; 356*88364387SHung-ying Tyan p.nonce_size = 0; 357*88364387SHung-ying Tyan p.offset = EC_VBOOT_HASH_OFFSET_RW; 358*88364387SHung-ying Tyan 359*88364387SHung-ying Tyan if (ec_command(dev, EC_CMD_VBOOT_HASH, 0, &p, sizeof(p), 360*88364387SHung-ying Tyan hash, sizeof(*hash)) < 0) 361*88364387SHung-ying Tyan return -1; 362*88364387SHung-ying Tyan 363*88364387SHung-ying Tyan rv = cros_ec_wait_on_hash_done(dev, hash); 364*88364387SHung-ying Tyan if (rv) 365*88364387SHung-ying Tyan return rv; 366*88364387SHung-ying Tyan 367*88364387SHung-ying Tyan debug("%s: hash done\n", __func__); 368*88364387SHung-ying Tyan 369*88364387SHung-ying Tyan return 0; 370*88364387SHung-ying Tyan } 371*88364387SHung-ying Tyan 372*88364387SHung-ying Tyan static int cros_ec_invalidate_hash(struct cros_ec_dev *dev) 373*88364387SHung-ying Tyan { 374*88364387SHung-ying Tyan struct ec_params_vboot_hash p; 375*88364387SHung-ying Tyan struct ec_response_vboot_hash *hash; 376*88364387SHung-ying Tyan 377*88364387SHung-ying Tyan /* We don't have an explict command for the EC to discard its current 378*88364387SHung-ying Tyan * hash value, so we'll just tell it to calculate one that we know is 379*88364387SHung-ying Tyan * wrong (we claim that hashing zero bytes is always invalid). 380*88364387SHung-ying Tyan */ 381*88364387SHung-ying Tyan p.cmd = EC_VBOOT_HASH_RECALC; 382*88364387SHung-ying Tyan p.hash_type = EC_VBOOT_HASH_TYPE_SHA256; 383*88364387SHung-ying Tyan p.nonce_size = 0; 384*88364387SHung-ying Tyan p.offset = 0; 385*88364387SHung-ying Tyan p.size = 0; 386*88364387SHung-ying Tyan 387*88364387SHung-ying Tyan debug("%s:\n", __func__); 388*88364387SHung-ying Tyan 389*88364387SHung-ying Tyan if (ec_command_inptr(dev, EC_CMD_VBOOT_HASH, 0, &p, sizeof(p), 390*88364387SHung-ying Tyan (uint8_t **)&hash, sizeof(*hash)) < 0) 391*88364387SHung-ying Tyan return -1; 392*88364387SHung-ying Tyan 393*88364387SHung-ying Tyan /* No need to wait for it to finish */ 394*88364387SHung-ying Tyan return 0; 395*88364387SHung-ying Tyan } 396*88364387SHung-ying Tyan 397*88364387SHung-ying Tyan int cros_ec_reboot(struct cros_ec_dev *dev, enum ec_reboot_cmd cmd, 398*88364387SHung-ying Tyan uint8_t flags) 399*88364387SHung-ying Tyan { 400*88364387SHung-ying Tyan struct ec_params_reboot_ec p; 401*88364387SHung-ying Tyan 402*88364387SHung-ying Tyan p.cmd = cmd; 403*88364387SHung-ying Tyan p.flags = flags; 404*88364387SHung-ying Tyan 405*88364387SHung-ying Tyan if (ec_command_inptr(dev, EC_CMD_REBOOT_EC, 0, &p, sizeof(p), NULL, 0) 406*88364387SHung-ying Tyan < 0) 407*88364387SHung-ying Tyan return -1; 408*88364387SHung-ying Tyan 409*88364387SHung-ying Tyan if (!(flags & EC_REBOOT_FLAG_ON_AP_SHUTDOWN)) { 410*88364387SHung-ying Tyan /* 411*88364387SHung-ying Tyan * EC reboot will take place immediately so delay to allow it 412*88364387SHung-ying Tyan * to complete. Note that some reboot types (EC_REBOOT_COLD) 413*88364387SHung-ying Tyan * will reboot the AP as well, in which case we won't actually 414*88364387SHung-ying Tyan * get to this point. 415*88364387SHung-ying Tyan */ 416*88364387SHung-ying Tyan /* 417*88364387SHung-ying Tyan * TODO(rspangler@chromium.org): Would be nice if we had a 418*88364387SHung-ying Tyan * better way to determine when the reboot is complete. Could 419*88364387SHung-ying Tyan * we poll a memory-mapped LPC value? 420*88364387SHung-ying Tyan */ 421*88364387SHung-ying Tyan udelay(50000); 422*88364387SHung-ying Tyan } 423*88364387SHung-ying Tyan 424*88364387SHung-ying Tyan return 0; 425*88364387SHung-ying Tyan } 426*88364387SHung-ying Tyan 427*88364387SHung-ying Tyan int cros_ec_interrupt_pending(struct cros_ec_dev *dev) 428*88364387SHung-ying Tyan { 429*88364387SHung-ying Tyan /* no interrupt support : always poll */ 430*88364387SHung-ying Tyan if (!fdt_gpio_isvalid(&dev->ec_int)) 431*88364387SHung-ying Tyan return 1; 432*88364387SHung-ying Tyan 433*88364387SHung-ying Tyan return !gpio_get_value(dev->ec_int.gpio); 434*88364387SHung-ying Tyan } 435*88364387SHung-ying Tyan 436*88364387SHung-ying Tyan int cros_ec_info(struct cros_ec_dev *dev, struct ec_response_cros_ec_info *info) 437*88364387SHung-ying Tyan { 438*88364387SHung-ying Tyan if (ec_command(dev, EC_CMD_CROS_EC_INFO, 0, NULL, 0, info, 439*88364387SHung-ying Tyan sizeof(*info)) < sizeof(*info)) 440*88364387SHung-ying Tyan return -1; 441*88364387SHung-ying Tyan 442*88364387SHung-ying Tyan return 0; 443*88364387SHung-ying Tyan } 444*88364387SHung-ying Tyan 445*88364387SHung-ying Tyan int cros_ec_get_host_events(struct cros_ec_dev *dev, uint32_t *events_ptr) 446*88364387SHung-ying Tyan { 447*88364387SHung-ying Tyan struct ec_response_host_event_mask *resp; 448*88364387SHung-ying Tyan 449*88364387SHung-ying Tyan /* 450*88364387SHung-ying Tyan * Use the B copy of the event flags, because the main copy is already 451*88364387SHung-ying Tyan * used by ACPI/SMI. 452*88364387SHung-ying Tyan */ 453*88364387SHung-ying Tyan if (ec_command_inptr(dev, EC_CMD_HOST_EVENT_GET_B, 0, NULL, 0, 454*88364387SHung-ying Tyan (uint8_t **)&resp, sizeof(*resp)) < sizeof(*resp)) 455*88364387SHung-ying Tyan return -1; 456*88364387SHung-ying Tyan 457*88364387SHung-ying Tyan if (resp->mask & EC_HOST_EVENT_MASK(EC_HOST_EVENT_INVALID)) 458*88364387SHung-ying Tyan return -1; 459*88364387SHung-ying Tyan 460*88364387SHung-ying Tyan *events_ptr = resp->mask; 461*88364387SHung-ying Tyan return 0; 462*88364387SHung-ying Tyan } 463*88364387SHung-ying Tyan 464*88364387SHung-ying Tyan int cros_ec_clear_host_events(struct cros_ec_dev *dev, uint32_t events) 465*88364387SHung-ying Tyan { 466*88364387SHung-ying Tyan struct ec_params_host_event_mask params; 467*88364387SHung-ying Tyan 468*88364387SHung-ying Tyan params.mask = events; 469*88364387SHung-ying Tyan 470*88364387SHung-ying Tyan /* 471*88364387SHung-ying Tyan * Use the B copy of the event flags, so it affects the data returned 472*88364387SHung-ying Tyan * by cros_ec_get_host_events(). 473*88364387SHung-ying Tyan */ 474*88364387SHung-ying Tyan if (ec_command_inptr(dev, EC_CMD_HOST_EVENT_CLEAR_B, 0, 475*88364387SHung-ying Tyan ¶ms, sizeof(params), NULL, 0) < 0) 476*88364387SHung-ying Tyan return -1; 477*88364387SHung-ying Tyan 478*88364387SHung-ying Tyan return 0; 479*88364387SHung-ying Tyan } 480*88364387SHung-ying Tyan 481*88364387SHung-ying Tyan int cros_ec_flash_protect(struct cros_ec_dev *dev, 482*88364387SHung-ying Tyan uint32_t set_mask, uint32_t set_flags, 483*88364387SHung-ying Tyan struct ec_response_flash_protect *resp) 484*88364387SHung-ying Tyan { 485*88364387SHung-ying Tyan struct ec_params_flash_protect params; 486*88364387SHung-ying Tyan 487*88364387SHung-ying Tyan params.mask = set_mask; 488*88364387SHung-ying Tyan params.flags = set_flags; 489*88364387SHung-ying Tyan 490*88364387SHung-ying Tyan if (ec_command(dev, EC_CMD_FLASH_PROTECT, EC_VER_FLASH_PROTECT, 491*88364387SHung-ying Tyan ¶ms, sizeof(params), 492*88364387SHung-ying Tyan resp, sizeof(*resp)) < sizeof(*resp)) 493*88364387SHung-ying Tyan return -1; 494*88364387SHung-ying Tyan 495*88364387SHung-ying Tyan return 0; 496*88364387SHung-ying Tyan } 497*88364387SHung-ying Tyan 498*88364387SHung-ying Tyan static int cros_ec_check_version(struct cros_ec_dev *dev) 499*88364387SHung-ying Tyan { 500*88364387SHung-ying Tyan struct ec_params_hello req; 501*88364387SHung-ying Tyan struct ec_response_hello *resp; 502*88364387SHung-ying Tyan 503*88364387SHung-ying Tyan #ifdef CONFIG_CROS_EC_LPC 504*88364387SHung-ying Tyan /* LPC has its own way of doing this */ 505*88364387SHung-ying Tyan if (dev->interface == CROS_EC_IF_LPC) 506*88364387SHung-ying Tyan return cros_ec_lpc_check_version(dev); 507*88364387SHung-ying Tyan #endif 508*88364387SHung-ying Tyan 509*88364387SHung-ying Tyan /* 510*88364387SHung-ying Tyan * TODO(sjg@chromium.org). 511*88364387SHung-ying Tyan * There is a strange oddity here with the EC. We could just ignore 512*88364387SHung-ying Tyan * the response, i.e. pass the last two parameters as NULL and 0. 513*88364387SHung-ying Tyan * In this case we won't read back very many bytes from the EC. 514*88364387SHung-ying Tyan * On the I2C bus the EC gets upset about this and will try to send 515*88364387SHung-ying Tyan * the bytes anyway. This means that we will have to wait for that 516*88364387SHung-ying Tyan * to complete before continuing with a new EC command. 517*88364387SHung-ying Tyan * 518*88364387SHung-ying Tyan * This problem is probably unique to the I2C bus. 519*88364387SHung-ying Tyan * 520*88364387SHung-ying Tyan * So for now, just read all the data anyway. 521*88364387SHung-ying Tyan */ 522*88364387SHung-ying Tyan dev->cmd_version_is_supported = 1; 523*88364387SHung-ying Tyan if (ec_command_inptr(dev, EC_CMD_HELLO, 0, &req, sizeof(req), 524*88364387SHung-ying Tyan (uint8_t **)&resp, sizeof(*resp)) > 0) { 525*88364387SHung-ying Tyan /* It appears to understand new version commands */ 526*88364387SHung-ying Tyan dev->cmd_version_is_supported = 1; 527*88364387SHung-ying Tyan } else { 528*88364387SHung-ying Tyan dev->cmd_version_is_supported = 0; 529*88364387SHung-ying Tyan if (ec_command_inptr(dev, EC_CMD_HELLO, 0, &req, 530*88364387SHung-ying Tyan sizeof(req), (uint8_t **)&resp, 531*88364387SHung-ying Tyan sizeof(*resp)) < 0) { 532*88364387SHung-ying Tyan debug("%s: Failed both old and new command style\n", 533*88364387SHung-ying Tyan __func__); 534*88364387SHung-ying Tyan return -1; 535*88364387SHung-ying Tyan } 536*88364387SHung-ying Tyan } 537*88364387SHung-ying Tyan 538*88364387SHung-ying Tyan return 0; 539*88364387SHung-ying Tyan } 540*88364387SHung-ying Tyan 541*88364387SHung-ying Tyan int cros_ec_test(struct cros_ec_dev *dev) 542*88364387SHung-ying Tyan { 543*88364387SHung-ying Tyan struct ec_params_hello req; 544*88364387SHung-ying Tyan struct ec_response_hello *resp; 545*88364387SHung-ying Tyan 546*88364387SHung-ying Tyan req.in_data = 0x12345678; 547*88364387SHung-ying Tyan if (ec_command_inptr(dev, EC_CMD_HELLO, 0, &req, sizeof(req), 548*88364387SHung-ying Tyan (uint8_t **)&resp, sizeof(*resp)) < sizeof(*resp)) { 549*88364387SHung-ying Tyan printf("ec_command_inptr() returned error\n"); 550*88364387SHung-ying Tyan return -1; 551*88364387SHung-ying Tyan } 552*88364387SHung-ying Tyan if (resp->out_data != req.in_data + 0x01020304) { 553*88364387SHung-ying Tyan printf("Received invalid handshake %x\n", resp->out_data); 554*88364387SHung-ying Tyan return -1; 555*88364387SHung-ying Tyan } 556*88364387SHung-ying Tyan 557*88364387SHung-ying Tyan return 0; 558*88364387SHung-ying Tyan } 559*88364387SHung-ying Tyan 560*88364387SHung-ying Tyan int cros_ec_flash_offset(struct cros_ec_dev *dev, enum ec_flash_region region, 561*88364387SHung-ying Tyan uint32_t *offset, uint32_t *size) 562*88364387SHung-ying Tyan { 563*88364387SHung-ying Tyan struct ec_params_flash_region_info p; 564*88364387SHung-ying Tyan struct ec_response_flash_region_info *r; 565*88364387SHung-ying Tyan int ret; 566*88364387SHung-ying Tyan 567*88364387SHung-ying Tyan p.region = region; 568*88364387SHung-ying Tyan ret = ec_command_inptr(dev, EC_CMD_FLASH_REGION_INFO, 569*88364387SHung-ying Tyan EC_VER_FLASH_REGION_INFO, 570*88364387SHung-ying Tyan &p, sizeof(p), (uint8_t **)&r, sizeof(*r)); 571*88364387SHung-ying Tyan if (ret != sizeof(*r)) 572*88364387SHung-ying Tyan return -1; 573*88364387SHung-ying Tyan 574*88364387SHung-ying Tyan if (offset) 575*88364387SHung-ying Tyan *offset = r->offset; 576*88364387SHung-ying Tyan if (size) 577*88364387SHung-ying Tyan *size = r->size; 578*88364387SHung-ying Tyan 579*88364387SHung-ying Tyan return 0; 580*88364387SHung-ying Tyan } 581*88364387SHung-ying Tyan 582*88364387SHung-ying Tyan int cros_ec_flash_erase(struct cros_ec_dev *dev, uint32_t offset, uint32_t size) 583*88364387SHung-ying Tyan { 584*88364387SHung-ying Tyan struct ec_params_flash_erase p; 585*88364387SHung-ying Tyan 586*88364387SHung-ying Tyan p.offset = offset; 587*88364387SHung-ying Tyan p.size = size; 588*88364387SHung-ying Tyan return ec_command_inptr(dev, EC_CMD_FLASH_ERASE, 0, &p, sizeof(p), 589*88364387SHung-ying Tyan NULL, 0); 590*88364387SHung-ying Tyan } 591*88364387SHung-ying Tyan 592*88364387SHung-ying Tyan /** 593*88364387SHung-ying Tyan * Write a single block to the flash 594*88364387SHung-ying Tyan * 595*88364387SHung-ying Tyan * Write a block of data to the EC flash. The size must not exceed the flash 596*88364387SHung-ying Tyan * write block size which you can obtain from cros_ec_flash_write_burst_size(). 597*88364387SHung-ying Tyan * 598*88364387SHung-ying Tyan * The offset starts at 0. You can obtain the region information from 599*88364387SHung-ying Tyan * cros_ec_flash_offset() to find out where to write for a particular region. 600*88364387SHung-ying Tyan * 601*88364387SHung-ying Tyan * Attempting to write to the region where the EC is currently running from 602*88364387SHung-ying Tyan * will result in an error. 603*88364387SHung-ying Tyan * 604*88364387SHung-ying Tyan * @param dev CROS-EC device 605*88364387SHung-ying Tyan * @param data Pointer to data buffer to write 606*88364387SHung-ying Tyan * @param offset Offset within flash to write to. 607*88364387SHung-ying Tyan * @param size Number of bytes to write 608*88364387SHung-ying Tyan * @return 0 if ok, -1 on error 609*88364387SHung-ying Tyan */ 610*88364387SHung-ying Tyan static int cros_ec_flash_write_block(struct cros_ec_dev *dev, 611*88364387SHung-ying Tyan const uint8_t *data, uint32_t offset, uint32_t size) 612*88364387SHung-ying Tyan { 613*88364387SHung-ying Tyan struct ec_params_flash_write p; 614*88364387SHung-ying Tyan 615*88364387SHung-ying Tyan p.offset = offset; 616*88364387SHung-ying Tyan p.size = size; 617*88364387SHung-ying Tyan assert(data && p.size <= sizeof(p.data)); 618*88364387SHung-ying Tyan memcpy(p.data, data, p.size); 619*88364387SHung-ying Tyan 620*88364387SHung-ying Tyan return ec_command_inptr(dev, EC_CMD_FLASH_WRITE, 0, 621*88364387SHung-ying Tyan &p, sizeof(p), NULL, 0) >= 0 ? 0 : -1; 622*88364387SHung-ying Tyan } 623*88364387SHung-ying Tyan 624*88364387SHung-ying Tyan /** 625*88364387SHung-ying Tyan * Return optimal flash write burst size 626*88364387SHung-ying Tyan */ 627*88364387SHung-ying Tyan static int cros_ec_flash_write_burst_size(struct cros_ec_dev *dev) 628*88364387SHung-ying Tyan { 629*88364387SHung-ying Tyan struct ec_params_flash_write p; 630*88364387SHung-ying Tyan return sizeof(p.data); 631*88364387SHung-ying Tyan } 632*88364387SHung-ying Tyan 633*88364387SHung-ying Tyan /** 634*88364387SHung-ying Tyan * Check if a block of data is erased (all 0xff) 635*88364387SHung-ying Tyan * 636*88364387SHung-ying Tyan * This function is useful when dealing with flash, for checking whether a 637*88364387SHung-ying Tyan * data block is erased and thus does not need to be programmed. 638*88364387SHung-ying Tyan * 639*88364387SHung-ying Tyan * @param data Pointer to data to check (must be word-aligned) 640*88364387SHung-ying Tyan * @param size Number of bytes to check (must be word-aligned) 641*88364387SHung-ying Tyan * @return 0 if erased, non-zero if any word is not erased 642*88364387SHung-ying Tyan */ 643*88364387SHung-ying Tyan static int cros_ec_data_is_erased(const uint32_t *data, int size) 644*88364387SHung-ying Tyan { 645*88364387SHung-ying Tyan assert(!(size & 3)); 646*88364387SHung-ying Tyan size /= sizeof(uint32_t); 647*88364387SHung-ying Tyan for (; size > 0; size -= 4, data++) 648*88364387SHung-ying Tyan if (*data != -1U) 649*88364387SHung-ying Tyan return 0; 650*88364387SHung-ying Tyan 651*88364387SHung-ying Tyan return 1; 652*88364387SHung-ying Tyan } 653*88364387SHung-ying Tyan 654*88364387SHung-ying Tyan int cros_ec_flash_write(struct cros_ec_dev *dev, const uint8_t *data, 655*88364387SHung-ying Tyan uint32_t offset, uint32_t size) 656*88364387SHung-ying Tyan { 657*88364387SHung-ying Tyan uint32_t burst = cros_ec_flash_write_burst_size(dev); 658*88364387SHung-ying Tyan uint32_t end, off; 659*88364387SHung-ying Tyan int ret; 660*88364387SHung-ying Tyan 661*88364387SHung-ying Tyan /* 662*88364387SHung-ying Tyan * TODO: round up to the nearest multiple of write size. Can get away 663*88364387SHung-ying Tyan * without that on link right now because its write size is 4 bytes. 664*88364387SHung-ying Tyan */ 665*88364387SHung-ying Tyan end = offset + size; 666*88364387SHung-ying Tyan for (off = offset; off < end; off += burst, data += burst) { 667*88364387SHung-ying Tyan uint32_t todo; 668*88364387SHung-ying Tyan 669*88364387SHung-ying Tyan /* If the data is empty, there is no point in programming it */ 670*88364387SHung-ying Tyan todo = min(end - off, burst); 671*88364387SHung-ying Tyan if (dev->optimise_flash_write && 672*88364387SHung-ying Tyan cros_ec_data_is_erased((uint32_t *)data, todo)) 673*88364387SHung-ying Tyan continue; 674*88364387SHung-ying Tyan 675*88364387SHung-ying Tyan ret = cros_ec_flash_write_block(dev, data, off, todo); 676*88364387SHung-ying Tyan if (ret) 677*88364387SHung-ying Tyan return ret; 678*88364387SHung-ying Tyan } 679*88364387SHung-ying Tyan 680*88364387SHung-ying Tyan return 0; 681*88364387SHung-ying Tyan } 682*88364387SHung-ying Tyan 683*88364387SHung-ying Tyan /** 684*88364387SHung-ying Tyan * Read a single block from the flash 685*88364387SHung-ying Tyan * 686*88364387SHung-ying Tyan * Read a block of data from the EC flash. The size must not exceed the flash 687*88364387SHung-ying Tyan * write block size which you can obtain from cros_ec_flash_write_burst_size(). 688*88364387SHung-ying Tyan * 689*88364387SHung-ying Tyan * The offset starts at 0. You can obtain the region information from 690*88364387SHung-ying Tyan * cros_ec_flash_offset() to find out where to read for a particular region. 691*88364387SHung-ying Tyan * 692*88364387SHung-ying Tyan * @param dev CROS-EC device 693*88364387SHung-ying Tyan * @param data Pointer to data buffer to read into 694*88364387SHung-ying Tyan * @param offset Offset within flash to read from 695*88364387SHung-ying Tyan * @param size Number of bytes to read 696*88364387SHung-ying Tyan * @return 0 if ok, -1 on error 697*88364387SHung-ying Tyan */ 698*88364387SHung-ying Tyan static int cros_ec_flash_read_block(struct cros_ec_dev *dev, uint8_t *data, 699*88364387SHung-ying Tyan uint32_t offset, uint32_t size) 700*88364387SHung-ying Tyan { 701*88364387SHung-ying Tyan struct ec_params_flash_read p; 702*88364387SHung-ying Tyan 703*88364387SHung-ying Tyan p.offset = offset; 704*88364387SHung-ying Tyan p.size = size; 705*88364387SHung-ying Tyan 706*88364387SHung-ying Tyan return ec_command(dev, EC_CMD_FLASH_READ, 0, 707*88364387SHung-ying Tyan &p, sizeof(p), data, size) >= 0 ? 0 : -1; 708*88364387SHung-ying Tyan } 709*88364387SHung-ying Tyan 710*88364387SHung-ying Tyan int cros_ec_flash_read(struct cros_ec_dev *dev, uint8_t *data, uint32_t offset, 711*88364387SHung-ying Tyan uint32_t size) 712*88364387SHung-ying Tyan { 713*88364387SHung-ying Tyan uint32_t burst = cros_ec_flash_write_burst_size(dev); 714*88364387SHung-ying Tyan uint32_t end, off; 715*88364387SHung-ying Tyan int ret; 716*88364387SHung-ying Tyan 717*88364387SHung-ying Tyan end = offset + size; 718*88364387SHung-ying Tyan for (off = offset; off < end; off += burst, data += burst) { 719*88364387SHung-ying Tyan ret = cros_ec_flash_read_block(dev, data, off, 720*88364387SHung-ying Tyan min(end - off, burst)); 721*88364387SHung-ying Tyan if (ret) 722*88364387SHung-ying Tyan return ret; 723*88364387SHung-ying Tyan } 724*88364387SHung-ying Tyan 725*88364387SHung-ying Tyan return 0; 726*88364387SHung-ying Tyan } 727*88364387SHung-ying Tyan 728*88364387SHung-ying Tyan int cros_ec_flash_update_rw(struct cros_ec_dev *dev, 729*88364387SHung-ying Tyan const uint8_t *image, int image_size) 730*88364387SHung-ying Tyan { 731*88364387SHung-ying Tyan uint32_t rw_offset, rw_size; 732*88364387SHung-ying Tyan int ret; 733*88364387SHung-ying Tyan 734*88364387SHung-ying Tyan if (cros_ec_flash_offset(dev, EC_FLASH_REGION_RW, &rw_offset, &rw_size)) 735*88364387SHung-ying Tyan return -1; 736*88364387SHung-ying Tyan if (image_size > rw_size) 737*88364387SHung-ying Tyan return -1; 738*88364387SHung-ying Tyan 739*88364387SHung-ying Tyan /* Invalidate the existing hash, just in case the AP reboots 740*88364387SHung-ying Tyan * unexpectedly during the update. If that happened, the EC RW firmware 741*88364387SHung-ying Tyan * would be invalid, but the EC would still have the original hash. 742*88364387SHung-ying Tyan */ 743*88364387SHung-ying Tyan ret = cros_ec_invalidate_hash(dev); 744*88364387SHung-ying Tyan if (ret) 745*88364387SHung-ying Tyan return ret; 746*88364387SHung-ying Tyan 747*88364387SHung-ying Tyan /* 748*88364387SHung-ying Tyan * Erase the entire RW section, so that the EC doesn't see any garbage 749*88364387SHung-ying Tyan * past the new image if it's smaller than the current image. 750*88364387SHung-ying Tyan * 751*88364387SHung-ying Tyan * TODO: could optimize this to erase just the current image, since 752*88364387SHung-ying Tyan * presumably everything past that is 0xff's. But would still need to 753*88364387SHung-ying Tyan * round up to the nearest multiple of erase size. 754*88364387SHung-ying Tyan */ 755*88364387SHung-ying Tyan ret = cros_ec_flash_erase(dev, rw_offset, rw_size); 756*88364387SHung-ying Tyan if (ret) 757*88364387SHung-ying Tyan return ret; 758*88364387SHung-ying Tyan 759*88364387SHung-ying Tyan /* Write the image */ 760*88364387SHung-ying Tyan ret = cros_ec_flash_write(dev, image, rw_offset, image_size); 761*88364387SHung-ying Tyan if (ret) 762*88364387SHung-ying Tyan return ret; 763*88364387SHung-ying Tyan 764*88364387SHung-ying Tyan return 0; 765*88364387SHung-ying Tyan } 766*88364387SHung-ying Tyan 767*88364387SHung-ying Tyan int cros_ec_read_vbnvcontext(struct cros_ec_dev *dev, uint8_t *block) 768*88364387SHung-ying Tyan { 769*88364387SHung-ying Tyan struct ec_params_vbnvcontext p; 770*88364387SHung-ying Tyan int len; 771*88364387SHung-ying Tyan 772*88364387SHung-ying Tyan p.op = EC_VBNV_CONTEXT_OP_READ; 773*88364387SHung-ying Tyan 774*88364387SHung-ying Tyan len = ec_command(dev, EC_CMD_VBNV_CONTEXT, EC_VER_VBNV_CONTEXT, 775*88364387SHung-ying Tyan &p, sizeof(p), block, EC_VBNV_BLOCK_SIZE); 776*88364387SHung-ying Tyan if (len < EC_VBNV_BLOCK_SIZE) 777*88364387SHung-ying Tyan return -1; 778*88364387SHung-ying Tyan 779*88364387SHung-ying Tyan return 0; 780*88364387SHung-ying Tyan } 781*88364387SHung-ying Tyan 782*88364387SHung-ying Tyan int cros_ec_write_vbnvcontext(struct cros_ec_dev *dev, const uint8_t *block) 783*88364387SHung-ying Tyan { 784*88364387SHung-ying Tyan struct ec_params_vbnvcontext p; 785*88364387SHung-ying Tyan int len; 786*88364387SHung-ying Tyan 787*88364387SHung-ying Tyan p.op = EC_VBNV_CONTEXT_OP_WRITE; 788*88364387SHung-ying Tyan memcpy(p.block, block, sizeof(p.block)); 789*88364387SHung-ying Tyan 790*88364387SHung-ying Tyan len = ec_command_inptr(dev, EC_CMD_VBNV_CONTEXT, EC_VER_VBNV_CONTEXT, 791*88364387SHung-ying Tyan &p, sizeof(p), NULL, 0); 792*88364387SHung-ying Tyan if (len < 0) 793*88364387SHung-ying Tyan return -1; 794*88364387SHung-ying Tyan 795*88364387SHung-ying Tyan return 0; 796*88364387SHung-ying Tyan } 797*88364387SHung-ying Tyan 798*88364387SHung-ying Tyan int cros_ec_set_ldo(struct cros_ec_dev *dev, uint8_t index, uint8_t state) 799*88364387SHung-ying Tyan { 800*88364387SHung-ying Tyan struct ec_params_ldo_set params; 801*88364387SHung-ying Tyan 802*88364387SHung-ying Tyan params.index = index; 803*88364387SHung-ying Tyan params.state = state; 804*88364387SHung-ying Tyan 805*88364387SHung-ying Tyan if (ec_command_inptr(dev, EC_CMD_LDO_SET, 0, 806*88364387SHung-ying Tyan ¶ms, sizeof(params), 807*88364387SHung-ying Tyan NULL, 0)) 808*88364387SHung-ying Tyan return -1; 809*88364387SHung-ying Tyan 810*88364387SHung-ying Tyan return 0; 811*88364387SHung-ying Tyan } 812*88364387SHung-ying Tyan 813*88364387SHung-ying Tyan int cros_ec_get_ldo(struct cros_ec_dev *dev, uint8_t index, uint8_t *state) 814*88364387SHung-ying Tyan { 815*88364387SHung-ying Tyan struct ec_params_ldo_get params; 816*88364387SHung-ying Tyan struct ec_response_ldo_get *resp; 817*88364387SHung-ying Tyan 818*88364387SHung-ying Tyan params.index = index; 819*88364387SHung-ying Tyan 820*88364387SHung-ying Tyan if (ec_command_inptr(dev, EC_CMD_LDO_GET, 0, 821*88364387SHung-ying Tyan ¶ms, sizeof(params), 822*88364387SHung-ying Tyan (uint8_t **)&resp, sizeof(*resp)) < sizeof(*resp)) 823*88364387SHung-ying Tyan return -1; 824*88364387SHung-ying Tyan 825*88364387SHung-ying Tyan *state = resp->state; 826*88364387SHung-ying Tyan 827*88364387SHung-ying Tyan return 0; 828*88364387SHung-ying Tyan } 829*88364387SHung-ying Tyan 830*88364387SHung-ying Tyan /** 831*88364387SHung-ying Tyan * Decode MBKP details from the device tree and allocate a suitable device. 832*88364387SHung-ying Tyan * 833*88364387SHung-ying Tyan * @param blob Device tree blob 834*88364387SHung-ying Tyan * @param node Node to decode from 835*88364387SHung-ying Tyan * @param devp Returns a pointer to the new allocated device 836*88364387SHung-ying Tyan * @return 0 if ok, -1 on error 837*88364387SHung-ying Tyan */ 838*88364387SHung-ying Tyan static int cros_ec_decode_fdt(const void *blob, int node, 839*88364387SHung-ying Tyan struct cros_ec_dev **devp) 840*88364387SHung-ying Tyan { 841*88364387SHung-ying Tyan enum fdt_compat_id compat; 842*88364387SHung-ying Tyan struct cros_ec_dev *dev; 843*88364387SHung-ying Tyan int parent; 844*88364387SHung-ying Tyan 845*88364387SHung-ying Tyan /* See what type of parent we are inside (this is expensive) */ 846*88364387SHung-ying Tyan parent = fdt_parent_offset(blob, node); 847*88364387SHung-ying Tyan if (parent < 0) { 848*88364387SHung-ying Tyan debug("%s: Cannot find node parent\n", __func__); 849*88364387SHung-ying Tyan return -1; 850*88364387SHung-ying Tyan } 851*88364387SHung-ying Tyan 852*88364387SHung-ying Tyan dev = &static_dev; 853*88364387SHung-ying Tyan dev->node = node; 854*88364387SHung-ying Tyan dev->parent_node = parent; 855*88364387SHung-ying Tyan 856*88364387SHung-ying Tyan compat = fdtdec_lookup(blob, parent); 857*88364387SHung-ying Tyan switch (compat) { 858*88364387SHung-ying Tyan #ifdef CONFIG_CROS_EC_SPI 859*88364387SHung-ying Tyan case COMPAT_SAMSUNG_EXYNOS_SPI: 860*88364387SHung-ying Tyan dev->interface = CROS_EC_IF_SPI; 861*88364387SHung-ying Tyan if (cros_ec_spi_decode_fdt(dev, blob)) 862*88364387SHung-ying Tyan return -1; 863*88364387SHung-ying Tyan break; 864*88364387SHung-ying Tyan #endif 865*88364387SHung-ying Tyan #ifdef CONFIG_CROS_EC_I2C 866*88364387SHung-ying Tyan case COMPAT_SAMSUNG_S3C2440_I2C: 867*88364387SHung-ying Tyan dev->interface = CROS_EC_IF_I2C; 868*88364387SHung-ying Tyan if (cros_ec_i2c_decode_fdt(dev, blob)) 869*88364387SHung-ying Tyan return -1; 870*88364387SHung-ying Tyan break; 871*88364387SHung-ying Tyan #endif 872*88364387SHung-ying Tyan #ifdef CONFIG_CROS_EC_LPC 873*88364387SHung-ying Tyan case COMPAT_INTEL_LPC: 874*88364387SHung-ying Tyan dev->interface = CROS_EC_IF_LPC; 875*88364387SHung-ying Tyan break; 876*88364387SHung-ying Tyan #endif 877*88364387SHung-ying Tyan default: 878*88364387SHung-ying Tyan debug("%s: Unknown compat id %d\n", __func__, compat); 879*88364387SHung-ying Tyan return -1; 880*88364387SHung-ying Tyan } 881*88364387SHung-ying Tyan 882*88364387SHung-ying Tyan fdtdec_decode_gpio(blob, node, "ec-interrupt", &dev->ec_int); 883*88364387SHung-ying Tyan dev->optimise_flash_write = fdtdec_get_bool(blob, node, 884*88364387SHung-ying Tyan "optimise-flash-write"); 885*88364387SHung-ying Tyan *devp = dev; 886*88364387SHung-ying Tyan 887*88364387SHung-ying Tyan return 0; 888*88364387SHung-ying Tyan } 889*88364387SHung-ying Tyan 890*88364387SHung-ying Tyan int cros_ec_init(const void *blob, struct cros_ec_dev **cros_ecp) 891*88364387SHung-ying Tyan { 892*88364387SHung-ying Tyan char id[MSG_BYTES]; 893*88364387SHung-ying Tyan struct cros_ec_dev *dev; 894*88364387SHung-ying Tyan int node = 0; 895*88364387SHung-ying Tyan 896*88364387SHung-ying Tyan *cros_ecp = NULL; 897*88364387SHung-ying Tyan do { 898*88364387SHung-ying Tyan node = fdtdec_next_compatible(blob, node, 899*88364387SHung-ying Tyan COMPAT_GOOGLE_CROS_EC); 900*88364387SHung-ying Tyan if (node < 0) { 901*88364387SHung-ying Tyan debug("%s: Node not found\n", __func__); 902*88364387SHung-ying Tyan return 0; 903*88364387SHung-ying Tyan } 904*88364387SHung-ying Tyan } while (!fdtdec_get_is_enabled(blob, node)); 905*88364387SHung-ying Tyan 906*88364387SHung-ying Tyan if (cros_ec_decode_fdt(blob, node, &dev)) { 907*88364387SHung-ying Tyan debug("%s: Failed to decode device.\n", __func__); 908*88364387SHung-ying Tyan return -CROS_EC_ERR_FDT_DECODE; 909*88364387SHung-ying Tyan } 910*88364387SHung-ying Tyan 911*88364387SHung-ying Tyan switch (dev->interface) { 912*88364387SHung-ying Tyan #ifdef CONFIG_CROS_EC_SPI 913*88364387SHung-ying Tyan case CROS_EC_IF_SPI: 914*88364387SHung-ying Tyan if (cros_ec_spi_init(dev, blob)) { 915*88364387SHung-ying Tyan debug("%s: Could not setup SPI interface\n", __func__); 916*88364387SHung-ying Tyan return -CROS_EC_ERR_DEV_INIT; 917*88364387SHung-ying Tyan } 918*88364387SHung-ying Tyan break; 919*88364387SHung-ying Tyan #endif 920*88364387SHung-ying Tyan #ifdef CONFIG_CROS_EC_I2C 921*88364387SHung-ying Tyan case CROS_EC_IF_I2C: 922*88364387SHung-ying Tyan if (cros_ec_i2c_init(dev, blob)) 923*88364387SHung-ying Tyan return -CROS_EC_ERR_DEV_INIT; 924*88364387SHung-ying Tyan break; 925*88364387SHung-ying Tyan #endif 926*88364387SHung-ying Tyan #ifdef CONFIG_CROS_EC_LPC 927*88364387SHung-ying Tyan case CROS_EC_IF_LPC: 928*88364387SHung-ying Tyan if (cros_ec_lpc_init(dev, blob)) 929*88364387SHung-ying Tyan return -CROS_EC_ERR_DEV_INIT; 930*88364387SHung-ying Tyan break; 931*88364387SHung-ying Tyan #endif 932*88364387SHung-ying Tyan case CROS_EC_IF_NONE: 933*88364387SHung-ying Tyan default: 934*88364387SHung-ying Tyan return 0; 935*88364387SHung-ying Tyan } 936*88364387SHung-ying Tyan 937*88364387SHung-ying Tyan /* we will poll the EC interrupt line */ 938*88364387SHung-ying Tyan fdtdec_setup_gpio(&dev->ec_int); 939*88364387SHung-ying Tyan if (fdt_gpio_isvalid(&dev->ec_int)) 940*88364387SHung-ying Tyan gpio_direction_input(dev->ec_int.gpio); 941*88364387SHung-ying Tyan 942*88364387SHung-ying Tyan if (cros_ec_check_version(dev)) { 943*88364387SHung-ying Tyan debug("%s: Could not detect CROS-EC version\n", __func__); 944*88364387SHung-ying Tyan return -CROS_EC_ERR_CHECK_VERSION; 945*88364387SHung-ying Tyan } 946*88364387SHung-ying Tyan 947*88364387SHung-ying Tyan if (cros_ec_read_id(dev, id, sizeof(id))) { 948*88364387SHung-ying Tyan debug("%s: Could not read KBC ID\n", __func__); 949*88364387SHung-ying Tyan return -CROS_EC_ERR_READ_ID; 950*88364387SHung-ying Tyan } 951*88364387SHung-ying Tyan 952*88364387SHung-ying Tyan /* Remember this device for use by the cros_ec command */ 953*88364387SHung-ying Tyan last_dev = *cros_ecp = dev; 954*88364387SHung-ying Tyan debug("Google Chrome EC CROS-EC driver ready, id '%s'\n", id); 955*88364387SHung-ying Tyan 956*88364387SHung-ying Tyan return 0; 957*88364387SHung-ying Tyan } 958*88364387SHung-ying Tyan 959*88364387SHung-ying Tyan #ifdef CONFIG_CMD_CROS_EC 960*88364387SHung-ying Tyan int cros_ec_decode_region(int argc, char * const argv[]) 961*88364387SHung-ying Tyan { 962*88364387SHung-ying Tyan if (argc > 0) { 963*88364387SHung-ying Tyan if (0 == strcmp(*argv, "rw")) 964*88364387SHung-ying Tyan return EC_FLASH_REGION_RW; 965*88364387SHung-ying Tyan else if (0 == strcmp(*argv, "ro")) 966*88364387SHung-ying Tyan return EC_FLASH_REGION_RO; 967*88364387SHung-ying Tyan 968*88364387SHung-ying Tyan debug("%s: Invalid region '%s'\n", __func__, *argv); 969*88364387SHung-ying Tyan } else { 970*88364387SHung-ying Tyan debug("%s: Missing region parameter\n", __func__); 971*88364387SHung-ying Tyan } 972*88364387SHung-ying Tyan 973*88364387SHung-ying Tyan return -1; 974*88364387SHung-ying Tyan } 975*88364387SHung-ying Tyan 976*88364387SHung-ying Tyan /** 977*88364387SHung-ying Tyan * Perform a flash read or write command 978*88364387SHung-ying Tyan * 979*88364387SHung-ying Tyan * @param dev CROS-EC device to read/write 980*88364387SHung-ying Tyan * @param is_write 1 do to a write, 0 to do a read 981*88364387SHung-ying Tyan * @param argc Number of arguments 982*88364387SHung-ying Tyan * @param argv Arguments (2 is region, 3 is address) 983*88364387SHung-ying Tyan * @return 0 for ok, 1 for a usage error or -ve for ec command error 984*88364387SHung-ying Tyan * (negative EC_RES_...) 985*88364387SHung-ying Tyan */ 986*88364387SHung-ying Tyan static int do_read_write(struct cros_ec_dev *dev, int is_write, int argc, 987*88364387SHung-ying Tyan char * const argv[]) 988*88364387SHung-ying Tyan { 989*88364387SHung-ying Tyan uint32_t offset, size = -1U, region_size; 990*88364387SHung-ying Tyan unsigned long addr; 991*88364387SHung-ying Tyan char *endp; 992*88364387SHung-ying Tyan int region; 993*88364387SHung-ying Tyan int ret; 994*88364387SHung-ying Tyan 995*88364387SHung-ying Tyan region = cros_ec_decode_region(argc - 2, argv + 2); 996*88364387SHung-ying Tyan if (region == -1) 997*88364387SHung-ying Tyan return 1; 998*88364387SHung-ying Tyan if (argc < 4) 999*88364387SHung-ying Tyan return 1; 1000*88364387SHung-ying Tyan addr = simple_strtoul(argv[3], &endp, 16); 1001*88364387SHung-ying Tyan if (*argv[3] == 0 || *endp != 0) 1002*88364387SHung-ying Tyan return 1; 1003*88364387SHung-ying Tyan if (argc > 4) { 1004*88364387SHung-ying Tyan size = simple_strtoul(argv[4], &endp, 16); 1005*88364387SHung-ying Tyan if (*argv[4] == 0 || *endp != 0) 1006*88364387SHung-ying Tyan return 1; 1007*88364387SHung-ying Tyan } 1008*88364387SHung-ying Tyan 1009*88364387SHung-ying Tyan ret = cros_ec_flash_offset(dev, region, &offset, ®ion_size); 1010*88364387SHung-ying Tyan if (ret) { 1011*88364387SHung-ying Tyan debug("%s: Could not read region info\n", __func__); 1012*88364387SHung-ying Tyan return ret; 1013*88364387SHung-ying Tyan } 1014*88364387SHung-ying Tyan if (size == -1U) 1015*88364387SHung-ying Tyan size = region_size; 1016*88364387SHung-ying Tyan 1017*88364387SHung-ying Tyan ret = is_write ? 1018*88364387SHung-ying Tyan cros_ec_flash_write(dev, (uint8_t *)addr, offset, size) : 1019*88364387SHung-ying Tyan cros_ec_flash_read(dev, (uint8_t *)addr, offset, size); 1020*88364387SHung-ying Tyan if (ret) { 1021*88364387SHung-ying Tyan debug("%s: Could not %s region\n", __func__, 1022*88364387SHung-ying Tyan is_write ? "write" : "read"); 1023*88364387SHung-ying Tyan return ret; 1024*88364387SHung-ying Tyan } 1025*88364387SHung-ying Tyan 1026*88364387SHung-ying Tyan return 0; 1027*88364387SHung-ying Tyan } 1028*88364387SHung-ying Tyan 1029*88364387SHung-ying Tyan static int do_cros_ec(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[]) 1030*88364387SHung-ying Tyan { 1031*88364387SHung-ying Tyan struct cros_ec_dev *dev = last_dev; 1032*88364387SHung-ying Tyan const char *cmd; 1033*88364387SHung-ying Tyan int ret = 0; 1034*88364387SHung-ying Tyan 1035*88364387SHung-ying Tyan if (argc < 2) 1036*88364387SHung-ying Tyan return CMD_RET_USAGE; 1037*88364387SHung-ying Tyan 1038*88364387SHung-ying Tyan cmd = argv[1]; 1039*88364387SHung-ying Tyan if (0 == strcmp("init", cmd)) { 1040*88364387SHung-ying Tyan ret = cros_ec_init(gd->fdt_blob, &dev); 1041*88364387SHung-ying Tyan if (ret) { 1042*88364387SHung-ying Tyan printf("Could not init cros_ec device (err %d)\n", ret); 1043*88364387SHung-ying Tyan return 1; 1044*88364387SHung-ying Tyan } 1045*88364387SHung-ying Tyan return 0; 1046*88364387SHung-ying Tyan } 1047*88364387SHung-ying Tyan 1048*88364387SHung-ying Tyan /* Just use the last allocated device; there should be only one */ 1049*88364387SHung-ying Tyan if (!last_dev) { 1050*88364387SHung-ying Tyan printf("No CROS-EC device available\n"); 1051*88364387SHung-ying Tyan return 1; 1052*88364387SHung-ying Tyan } 1053*88364387SHung-ying Tyan if (0 == strcmp("id", cmd)) { 1054*88364387SHung-ying Tyan char id[MSG_BYTES]; 1055*88364387SHung-ying Tyan 1056*88364387SHung-ying Tyan if (cros_ec_read_id(dev, id, sizeof(id))) { 1057*88364387SHung-ying Tyan debug("%s: Could not read KBC ID\n", __func__); 1058*88364387SHung-ying Tyan return 1; 1059*88364387SHung-ying Tyan } 1060*88364387SHung-ying Tyan printf("%s\n", id); 1061*88364387SHung-ying Tyan } else if (0 == strcmp("info", cmd)) { 1062*88364387SHung-ying Tyan struct ec_response_cros_ec_info info; 1063*88364387SHung-ying Tyan 1064*88364387SHung-ying Tyan if (cros_ec_info(dev, &info)) { 1065*88364387SHung-ying Tyan debug("%s: Could not read KBC info\n", __func__); 1066*88364387SHung-ying Tyan return 1; 1067*88364387SHung-ying Tyan } 1068*88364387SHung-ying Tyan printf("rows = %u\n", info.rows); 1069*88364387SHung-ying Tyan printf("cols = %u\n", info.cols); 1070*88364387SHung-ying Tyan printf("switches = %#x\n", info.switches); 1071*88364387SHung-ying Tyan } else if (0 == strcmp("curimage", cmd)) { 1072*88364387SHung-ying Tyan enum ec_current_image image; 1073*88364387SHung-ying Tyan 1074*88364387SHung-ying Tyan if (cros_ec_read_current_image(dev, &image)) { 1075*88364387SHung-ying Tyan debug("%s: Could not read KBC image\n", __func__); 1076*88364387SHung-ying Tyan return 1; 1077*88364387SHung-ying Tyan } 1078*88364387SHung-ying Tyan printf("%d\n", image); 1079*88364387SHung-ying Tyan } else if (0 == strcmp("hash", cmd)) { 1080*88364387SHung-ying Tyan struct ec_response_vboot_hash hash; 1081*88364387SHung-ying Tyan int i; 1082*88364387SHung-ying Tyan 1083*88364387SHung-ying Tyan if (cros_ec_read_hash(dev, &hash)) { 1084*88364387SHung-ying Tyan debug("%s: Could not read KBC hash\n", __func__); 1085*88364387SHung-ying Tyan return 1; 1086*88364387SHung-ying Tyan } 1087*88364387SHung-ying Tyan 1088*88364387SHung-ying Tyan if (hash.hash_type == EC_VBOOT_HASH_TYPE_SHA256) 1089*88364387SHung-ying Tyan printf("type: SHA-256\n"); 1090*88364387SHung-ying Tyan else 1091*88364387SHung-ying Tyan printf("type: %d\n", hash.hash_type); 1092*88364387SHung-ying Tyan 1093*88364387SHung-ying Tyan printf("offset: 0x%08x\n", hash.offset); 1094*88364387SHung-ying Tyan printf("size: 0x%08x\n", hash.size); 1095*88364387SHung-ying Tyan 1096*88364387SHung-ying Tyan printf("digest: "); 1097*88364387SHung-ying Tyan for (i = 0; i < hash.digest_size; i++) 1098*88364387SHung-ying Tyan printf("%02x", hash.hash_digest[i]); 1099*88364387SHung-ying Tyan printf("\n"); 1100*88364387SHung-ying Tyan } else if (0 == strcmp("reboot", cmd)) { 1101*88364387SHung-ying Tyan int region; 1102*88364387SHung-ying Tyan enum ec_reboot_cmd cmd; 1103*88364387SHung-ying Tyan 1104*88364387SHung-ying Tyan if (argc >= 3 && !strcmp(argv[2], "cold")) 1105*88364387SHung-ying Tyan cmd = EC_REBOOT_COLD; 1106*88364387SHung-ying Tyan else { 1107*88364387SHung-ying Tyan region = cros_ec_decode_region(argc - 2, argv + 2); 1108*88364387SHung-ying Tyan if (region == EC_FLASH_REGION_RO) 1109*88364387SHung-ying Tyan cmd = EC_REBOOT_JUMP_RO; 1110*88364387SHung-ying Tyan else if (region == EC_FLASH_REGION_RW) 1111*88364387SHung-ying Tyan cmd = EC_REBOOT_JUMP_RW; 1112*88364387SHung-ying Tyan else 1113*88364387SHung-ying Tyan return CMD_RET_USAGE; 1114*88364387SHung-ying Tyan } 1115*88364387SHung-ying Tyan 1116*88364387SHung-ying Tyan if (cros_ec_reboot(dev, cmd, 0)) { 1117*88364387SHung-ying Tyan debug("%s: Could not reboot KBC\n", __func__); 1118*88364387SHung-ying Tyan return 1; 1119*88364387SHung-ying Tyan } 1120*88364387SHung-ying Tyan } else if (0 == strcmp("events", cmd)) { 1121*88364387SHung-ying Tyan uint32_t events; 1122*88364387SHung-ying Tyan 1123*88364387SHung-ying Tyan if (cros_ec_get_host_events(dev, &events)) { 1124*88364387SHung-ying Tyan debug("%s: Could not read host events\n", __func__); 1125*88364387SHung-ying Tyan return 1; 1126*88364387SHung-ying Tyan } 1127*88364387SHung-ying Tyan printf("0x%08x\n", events); 1128*88364387SHung-ying Tyan } else if (0 == strcmp("clrevents", cmd)) { 1129*88364387SHung-ying Tyan uint32_t events = 0x7fffffff; 1130*88364387SHung-ying Tyan 1131*88364387SHung-ying Tyan if (argc >= 3) 1132*88364387SHung-ying Tyan events = simple_strtol(argv[2], NULL, 0); 1133*88364387SHung-ying Tyan 1134*88364387SHung-ying Tyan if (cros_ec_clear_host_events(dev, events)) { 1135*88364387SHung-ying Tyan debug("%s: Could not clear host events\n", __func__); 1136*88364387SHung-ying Tyan return 1; 1137*88364387SHung-ying Tyan } 1138*88364387SHung-ying Tyan } else if (0 == strcmp("read", cmd)) { 1139*88364387SHung-ying Tyan ret = do_read_write(dev, 0, argc, argv); 1140*88364387SHung-ying Tyan if (ret > 0) 1141*88364387SHung-ying Tyan return CMD_RET_USAGE; 1142*88364387SHung-ying Tyan } else if (0 == strcmp("write", cmd)) { 1143*88364387SHung-ying Tyan ret = do_read_write(dev, 1, argc, argv); 1144*88364387SHung-ying Tyan if (ret > 0) 1145*88364387SHung-ying Tyan return CMD_RET_USAGE; 1146*88364387SHung-ying Tyan } else if (0 == strcmp("erase", cmd)) { 1147*88364387SHung-ying Tyan int region = cros_ec_decode_region(argc - 2, argv + 2); 1148*88364387SHung-ying Tyan uint32_t offset, size; 1149*88364387SHung-ying Tyan 1150*88364387SHung-ying Tyan if (region == -1) 1151*88364387SHung-ying Tyan return CMD_RET_USAGE; 1152*88364387SHung-ying Tyan if (cros_ec_flash_offset(dev, region, &offset, &size)) { 1153*88364387SHung-ying Tyan debug("%s: Could not read region info\n", __func__); 1154*88364387SHung-ying Tyan ret = -1; 1155*88364387SHung-ying Tyan } else { 1156*88364387SHung-ying Tyan ret = cros_ec_flash_erase(dev, offset, size); 1157*88364387SHung-ying Tyan if (ret) { 1158*88364387SHung-ying Tyan debug("%s: Could not erase region\n", 1159*88364387SHung-ying Tyan __func__); 1160*88364387SHung-ying Tyan } 1161*88364387SHung-ying Tyan } 1162*88364387SHung-ying Tyan } else if (0 == strcmp("regioninfo", cmd)) { 1163*88364387SHung-ying Tyan int region = cros_ec_decode_region(argc - 2, argv + 2); 1164*88364387SHung-ying Tyan uint32_t offset, size; 1165*88364387SHung-ying Tyan 1166*88364387SHung-ying Tyan if (region == -1) 1167*88364387SHung-ying Tyan return CMD_RET_USAGE; 1168*88364387SHung-ying Tyan ret = cros_ec_flash_offset(dev, region, &offset, &size); 1169*88364387SHung-ying Tyan if (ret) { 1170*88364387SHung-ying Tyan debug("%s: Could not read region info\n", __func__); 1171*88364387SHung-ying Tyan } else { 1172*88364387SHung-ying Tyan printf("Region: %s\n", region == EC_FLASH_REGION_RO ? 1173*88364387SHung-ying Tyan "RO" : "RW"); 1174*88364387SHung-ying Tyan printf("Offset: %x\n", offset); 1175*88364387SHung-ying Tyan printf("Size: %x\n", size); 1176*88364387SHung-ying Tyan } 1177*88364387SHung-ying Tyan } else if (0 == strcmp("vbnvcontext", cmd)) { 1178*88364387SHung-ying Tyan uint8_t block[EC_VBNV_BLOCK_SIZE]; 1179*88364387SHung-ying Tyan char buf[3]; 1180*88364387SHung-ying Tyan int i, len; 1181*88364387SHung-ying Tyan unsigned long result; 1182*88364387SHung-ying Tyan 1183*88364387SHung-ying Tyan if (argc <= 2) { 1184*88364387SHung-ying Tyan ret = cros_ec_read_vbnvcontext(dev, block); 1185*88364387SHung-ying Tyan if (!ret) { 1186*88364387SHung-ying Tyan printf("vbnv_block: "); 1187*88364387SHung-ying Tyan for (i = 0; i < EC_VBNV_BLOCK_SIZE; i++) 1188*88364387SHung-ying Tyan printf("%02x", block[i]); 1189*88364387SHung-ying Tyan putc('\n'); 1190*88364387SHung-ying Tyan } 1191*88364387SHung-ying Tyan } else { 1192*88364387SHung-ying Tyan /* 1193*88364387SHung-ying Tyan * TODO(clchiou): Move this to a utility function as 1194*88364387SHung-ying Tyan * cmd_spi might want to call it. 1195*88364387SHung-ying Tyan */ 1196*88364387SHung-ying Tyan memset(block, 0, EC_VBNV_BLOCK_SIZE); 1197*88364387SHung-ying Tyan len = strlen(argv[2]); 1198*88364387SHung-ying Tyan buf[2] = '\0'; 1199*88364387SHung-ying Tyan for (i = 0; i < EC_VBNV_BLOCK_SIZE; i++) { 1200*88364387SHung-ying Tyan if (i * 2 >= len) 1201*88364387SHung-ying Tyan break; 1202*88364387SHung-ying Tyan buf[0] = argv[2][i * 2]; 1203*88364387SHung-ying Tyan if (i * 2 + 1 >= len) 1204*88364387SHung-ying Tyan buf[1] = '0'; 1205*88364387SHung-ying Tyan else 1206*88364387SHung-ying Tyan buf[1] = argv[2][i * 2 + 1]; 1207*88364387SHung-ying Tyan strict_strtoul(buf, 16, &result); 1208*88364387SHung-ying Tyan block[i] = result; 1209*88364387SHung-ying Tyan } 1210*88364387SHung-ying Tyan ret = cros_ec_write_vbnvcontext(dev, block); 1211*88364387SHung-ying Tyan } 1212*88364387SHung-ying Tyan if (ret) { 1213*88364387SHung-ying Tyan debug("%s: Could not %s VbNvContext\n", __func__, 1214*88364387SHung-ying Tyan argc <= 2 ? "read" : "write"); 1215*88364387SHung-ying Tyan } 1216*88364387SHung-ying Tyan } else if (0 == strcmp("test", cmd)) { 1217*88364387SHung-ying Tyan int result = cros_ec_test(dev); 1218*88364387SHung-ying Tyan 1219*88364387SHung-ying Tyan if (result) 1220*88364387SHung-ying Tyan printf("Test failed with error %d\n", result); 1221*88364387SHung-ying Tyan else 1222*88364387SHung-ying Tyan puts("Test passed\n"); 1223*88364387SHung-ying Tyan } else if (0 == strcmp("version", cmd)) { 1224*88364387SHung-ying Tyan struct ec_response_get_version *p; 1225*88364387SHung-ying Tyan char *build_string; 1226*88364387SHung-ying Tyan 1227*88364387SHung-ying Tyan ret = cros_ec_read_version(dev, &p); 1228*88364387SHung-ying Tyan if (!ret) { 1229*88364387SHung-ying Tyan /* Print versions */ 1230*88364387SHung-ying Tyan printf("RO version: %1.*s\n", 1231*88364387SHung-ying Tyan sizeof(p->version_string_ro), 1232*88364387SHung-ying Tyan p->version_string_ro); 1233*88364387SHung-ying Tyan printf("RW version: %1.*s\n", 1234*88364387SHung-ying Tyan sizeof(p->version_string_rw), 1235*88364387SHung-ying Tyan p->version_string_rw); 1236*88364387SHung-ying Tyan printf("Firmware copy: %s\n", 1237*88364387SHung-ying Tyan (p->current_image < 1238*88364387SHung-ying Tyan ARRAY_SIZE(ec_current_image_name) ? 1239*88364387SHung-ying Tyan ec_current_image_name[p->current_image] : 1240*88364387SHung-ying Tyan "?")); 1241*88364387SHung-ying Tyan ret = cros_ec_read_build_info(dev, &build_string); 1242*88364387SHung-ying Tyan if (!ret) 1243*88364387SHung-ying Tyan printf("Build info: %s\n", build_string); 1244*88364387SHung-ying Tyan } 1245*88364387SHung-ying Tyan } else if (0 == strcmp("ldo", cmd)) { 1246*88364387SHung-ying Tyan uint8_t index, state; 1247*88364387SHung-ying Tyan char *endp; 1248*88364387SHung-ying Tyan 1249*88364387SHung-ying Tyan if (argc < 3) 1250*88364387SHung-ying Tyan return CMD_RET_USAGE; 1251*88364387SHung-ying Tyan index = simple_strtoul(argv[2], &endp, 10); 1252*88364387SHung-ying Tyan if (*argv[2] == 0 || *endp != 0) 1253*88364387SHung-ying Tyan return CMD_RET_USAGE; 1254*88364387SHung-ying Tyan if (argc > 3) { 1255*88364387SHung-ying Tyan state = simple_strtoul(argv[3], &endp, 10); 1256*88364387SHung-ying Tyan if (*argv[3] == 0 || *endp != 0) 1257*88364387SHung-ying Tyan return CMD_RET_USAGE; 1258*88364387SHung-ying Tyan ret = cros_ec_set_ldo(dev, index, state); 1259*88364387SHung-ying Tyan } else { 1260*88364387SHung-ying Tyan ret = cros_ec_get_ldo(dev, index, &state); 1261*88364387SHung-ying Tyan if (!ret) { 1262*88364387SHung-ying Tyan printf("LDO%d: %s\n", index, 1263*88364387SHung-ying Tyan state == EC_LDO_STATE_ON ? 1264*88364387SHung-ying Tyan "on" : "off"); 1265*88364387SHung-ying Tyan } 1266*88364387SHung-ying Tyan } 1267*88364387SHung-ying Tyan 1268*88364387SHung-ying Tyan if (ret) { 1269*88364387SHung-ying Tyan debug("%s: Could not access LDO%d\n", __func__, index); 1270*88364387SHung-ying Tyan return ret; 1271*88364387SHung-ying Tyan } 1272*88364387SHung-ying Tyan } else { 1273*88364387SHung-ying Tyan return CMD_RET_USAGE; 1274*88364387SHung-ying Tyan } 1275*88364387SHung-ying Tyan 1276*88364387SHung-ying Tyan if (ret < 0) { 1277*88364387SHung-ying Tyan printf("Error: CROS-EC command failed (error %d)\n", ret); 1278*88364387SHung-ying Tyan ret = 1; 1279*88364387SHung-ying Tyan } 1280*88364387SHung-ying Tyan 1281*88364387SHung-ying Tyan return ret; 1282*88364387SHung-ying Tyan } 1283*88364387SHung-ying Tyan 1284*88364387SHung-ying Tyan U_BOOT_CMD( 1285*88364387SHung-ying Tyan crosec, 5, 1, do_cros_ec, 1286*88364387SHung-ying Tyan "CROS-EC utility command", 1287*88364387SHung-ying Tyan "init Re-init CROS-EC (done on startup automatically)\n" 1288*88364387SHung-ying Tyan "crosec id Read CROS-EC ID\n" 1289*88364387SHung-ying Tyan "crosec info Read CROS-EC info\n" 1290*88364387SHung-ying Tyan "crosec curimage Read CROS-EC current image\n" 1291*88364387SHung-ying Tyan "crosec hash Read CROS-EC hash\n" 1292*88364387SHung-ying Tyan "crosec reboot [rw | ro | cold] Reboot CROS-EC\n" 1293*88364387SHung-ying Tyan "crosec events Read CROS-EC host events\n" 1294*88364387SHung-ying Tyan "crosec clrevents [mask] Clear CROS-EC host events\n" 1295*88364387SHung-ying Tyan "crosec regioninfo <ro|rw> Read image info\n" 1296*88364387SHung-ying Tyan "crosec erase <ro|rw> Erase EC image\n" 1297*88364387SHung-ying Tyan "crosec read <ro|rw> <addr> [<size>] Read EC image\n" 1298*88364387SHung-ying Tyan "crosec write <ro|rw> <addr> [<size>] Write EC image\n" 1299*88364387SHung-ying Tyan "crosec vbnvcontext [hexstring] Read [write] VbNvContext from EC\n" 1300*88364387SHung-ying Tyan "crosec ldo <idx> [<state>] Switch/Read LDO state\n" 1301*88364387SHung-ying Tyan "crosec test run tests on cros_ec\n" 1302*88364387SHung-ying Tyan "crosec version Read CROS-EC version" 1303*88364387SHung-ying Tyan ); 1304*88364387SHung-ying Tyan #endif 1305