Skip to content
Snippets Groups Projects
cros_ec.c 29.2 KiB
Newer Older
  • Learn to ignore specific revisions
  • 	int node = dev_of_offset(dev);
    
    Hung-ying Tyan's avatar
    Hung-ying Tyan committed
    	char id[MSG_BYTES];
    
    	gpio_request_by_name(dev, "ec-interrupt", 0, &cdev->ec_int,
    			     GPIOD_IS_IN);
    
    	cdev->optimise_flash_write = fdtdec_get_bool(blob, node,
    						     "optimise-flash-write");
    
    	if (cros_ec_check_version(cdev)) {
    		debug("%s: Could not detect CROS-EC version\n", __func__);
    		return -CROS_EC_ERR_CHECK_VERSION;
    	}
    
    	if (cros_ec_read_id(cdev, id, sizeof(id))) {
    		debug("%s: Could not read KBC ID\n", __func__);
    		return -CROS_EC_ERR_READ_ID;
    	}
    
    	/* Remember this device for use by the cros_ec command */
    
    	debug("Google Chrome EC v%d CROS-EC driver ready, id '%s'\n",
    	      cdev->protocol_version, id);
    
    int cros_ec_decode_ec_flash(const void *blob, int node,
    			    struct fdt_cros_ec *config)
    
    	int flash_node;
    
    
    	flash_node = fdt_subnode_offset(blob, node, "flash");
    	if (flash_node < 0) {
    		debug("Failed to find flash node\n");
    		return -1;
    	}
    
    	if (fdtdec_read_fmap_entry(blob, flash_node, "flash",
    				   &config->flash)) {
    		debug("Failed to decode flash node in chrome-ec'\n");
    		return -1;
    	}
    
    	config->flash_erase_value = fdtdec_get_int(blob, flash_node,
    						    "erase-value", -1);
    	for (node = fdt_first_subnode(blob, flash_node); node >= 0;
    	     node = fdt_next_subnode(blob, node)) {
    		const char *name = fdt_get_name(blob, node, NULL);
    		enum ec_flash_region region;
    
    		if (0 == strcmp(name, "ro")) {
    			region = EC_FLASH_REGION_RO;
    		} else if (0 == strcmp(name, "rw")) {
    			region = EC_FLASH_REGION_RW;
    		} else if (0 == strcmp(name, "wp-ro")) {
    			region = EC_FLASH_REGION_WP_RO;
    		} else {
    			debug("Unknown EC flash region name '%s'\n", name);
    			return -1;
    		}
    
    		if (fdtdec_read_fmap_entry(blob, node, "reg",
    					   &config->region[region])) {
    			debug("Failed to decode flash region in chrome-ec'\n");
    			return -1;
    		}
    	}
    
    	return 0;
    }
    
    
    int cros_ec_i2c_tunnel(struct udevice *dev, int port, struct i2c_msg *in,
    		       int nmsgs)
    
    {
    	struct cros_ec_dev *cdev = dev_get_uclass_priv(dev);
    	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 = &params.p;
    	struct ec_response_i2c_passthru *r = &response.r;
    	struct ec_params_i2c_passthru_msg *msg;
    	uint8_t *pdata, *read_ptr = NULL;
    	int read_len;
    	int size;
    	int rv;
    	int i;
    
    
    
    	p->num_msgs = nmsgs;
    	size = sizeof(*p) + p->num_msgs * sizeof(*msg);
    
    	/* Create a message to write the register address and optional data */
    	pdata = (uint8_t *)p + size;
    
    	read_len = 0;
    	for (i = 0, msg = p->msg; i < nmsgs; i++, msg++, in++) {
    		bool is_read = in->flags & I2C_M_RD;
    
    		msg->addr_flags = in->addr;
    		msg->len = in->len;
    		if (is_read) {
    			msg->addr_flags |= EC_I2C_FLAG_READ;
    			read_len += in->len;
    			read_ptr = in->buf;
    			if (sizeof(*r) + read_len > sizeof(response)) {
    				puts("Read length too big for buffer\n");
    				return -1;
    			}
    		} else {
    			if (pdata - (uint8_t *)p + in->len > sizeof(params)) {
    				puts("Params too large for buffer\n");
    				return -1;
    			}
    			memcpy(pdata, in->buf, in->len);
    			pdata += in->len;
    		}
    	}
    
    	rv = ec_command(cdev, EC_CMD_I2C_PASSTHRU, 0, p, pdata - (uint8_t *)p,
    			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;
    	}
    
    	/* We only support a single read message for each transfer */
    	if (read_len)
    		memcpy(read_ptr, r->data, read_len);
    
    	return 0;
    }
    
    
    UCLASS_DRIVER(cros_ec) = {
    	.id		= UCLASS_CROS_EC,
    	.name		= "cros_ec",
    	.per_device_auto_alloc_size = sizeof(struct cros_ec_dev),
    
    	.post_bind	= dm_scan_fdt_dev,