diff options
Diffstat (limited to 'drivers/misc')
-rw-r--r-- | drivers/misc/cros_ec.c | 122 | ||||
-rw-r--r-- | drivers/misc/cros_ec_lpc.c | 4 | ||||
-rw-r--r-- | drivers/misc/cros_ec_sandbox.c | 99 | ||||
-rw-r--r-- | drivers/misc/cros_ec_spi.c | 87 |
4 files changed, 282 insertions, 30 deletions
diff --git a/drivers/misc/cros_ec.c b/drivers/misc/cros_ec.c index 068373b..521edfd 100644 --- a/drivers/misc/cros_ec.c +++ b/drivers/misc/cros_ec.c @@ -16,6 +16,7 @@ #include <common.h> #include <command.h> +#include <dm.h> #include <i2c.h> #include <cros_ec.h> #include <fdtdec.h> @@ -24,6 +25,8 @@ #include <asm/errno.h> #include <asm/io.h> #include <asm-generic/gpio.h> +#include <dm/device-internal.h> +#include <dm/uclass-internal.h> #ifdef DEBUG_TRACE #define debug_trace(fmt, b...) debug(fmt, #b) @@ -38,7 +41,9 @@ enum { CROS_EC_CMD_HASH_TIMEOUT_MS = 2000, }; +#ifndef CONFIG_DM_CROS_EC static struct cros_ec_dev static_dev, *last_dev; +#endif DECLARE_GLOBAL_DATA_PTR; @@ -204,6 +209,9 @@ static int send_command_proto3(struct cros_ec_dev *dev, const void *dout, int dout_len, uint8_t **dinp, int din_len) { +#ifdef CONFIG_DM_CROS_EC + struct dm_cros_ec_ops *ops; +#endif int out_bytes, in_bytes; int rv; @@ -218,6 +226,10 @@ static int send_command_proto3(struct cros_ec_dev *dev, if (in_bytes < 0) return in_bytes; +#ifdef CONFIG_DM_CROS_EC + ops = dm_cros_ec_get_ops(dev->dev); + rv = ops->packet(dev->dev, out_bytes, in_bytes); +#else switch (dev->interface) { #ifdef CONFIG_CROS_EC_SPI case CROS_EC_IF_SPI: @@ -235,6 +247,7 @@ static int send_command_proto3(struct cros_ec_dev *dev, debug("%s: Unsupported interface\n", __func__); rv = -1; } +#endif if (rv < 0) return rv; @@ -246,6 +259,9 @@ static int send_command(struct cros_ec_dev *dev, uint8_t cmd, int cmd_version, const void *dout, int dout_len, uint8_t **dinp, int din_len) { +#ifdef CONFIG_DM_CROS_EC + struct dm_cros_ec_ops *ops; +#endif int ret = -1; /* Handle protocol version 3 support */ @@ -254,6 +270,11 @@ static int send_command(struct cros_ec_dev *dev, uint8_t cmd, int cmd_version, dout, dout_len, dinp, din_len); } +#ifdef CONFIG_DM_CROS_EC + ops = dm_cros_ec_get_ops(dev->dev); + ret = ops->command(dev->dev, cmd, cmd_version, + (const uint8_t *)dout, dout_len, dinp, din_len); +#else switch (dev->interface) { #ifdef CONFIG_CROS_EC_SPI case CROS_EC_IF_SPI: @@ -280,6 +301,7 @@ static int send_command(struct cros_ec_dev *dev, uint8_t cmd, int cmd_version, default: ret = -1; } +#endif return ret; } @@ -990,6 +1012,7 @@ int cros_ec_get_ldo(struct cros_ec_dev *dev, uint8_t index, uint8_t *state) return 0; } +#ifndef CONFIG_DM_CROS_EC /** * Decode EC interface details from the device tree and allocate a suitable * device. @@ -1055,11 +1078,61 @@ static int cros_ec_decode_fdt(const void *blob, int node, return 0; } +#endif -int cros_ec_init(const void *blob, struct cros_ec_dev **cros_ecp) +#ifdef CONFIG_DM_CROS_EC +int cros_ec_register(struct udevice *dev) { + struct cros_ec_dev *cdev = dev->uclass_priv; + const void *blob = gd->fdt_blob; + int node = dev->of_offset; char id[MSG_BYTES]; + + cdev->dev = dev; + fdtdec_decode_gpio(blob, node, "ec-interrupt", &cdev->ec_int); + cdev->optimise_flash_write = fdtdec_get_bool(blob, node, + "optimise-flash-write"); + + /* we will poll the EC interrupt line */ + fdtdec_setup_gpio(&cdev->ec_int); + if (fdt_gpio_isvalid(&cdev->ec_int)) { + gpio_request(cdev->ec_int.gpio, "cros-ec-irq"); + gpio_direction_input(cdev->ec_int.gpio); + } + + 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 CROS-EC driver ready, id '%s'\n", id); + + return 0; +} +#else +int cros_ec_init(const void *blob, struct cros_ec_dev **cros_ecp) +{ struct cros_ec_dev *dev; + char id[MSG_BYTES]; +#ifdef CONFIG_DM_CROS_EC + struct udevice *udev; + int ret; + + ret = uclass_find_device(UCLASS_CROS_EC, 0, &udev); + if (!ret) + device_remove(udev); + ret = uclass_get_device(UCLASS_CROS_EC, 0, &udev); + if (ret) + return ret; + dev = udev->uclass_priv; + return 0; +#else int node = 0; *cros_ecp = NULL; @@ -1108,11 +1181,14 @@ int cros_ec_init(const void *blob, struct cros_ec_dev **cros_ecp) default: return 0; } +#endif /* we will poll the EC interrupt line */ fdtdec_setup_gpio(&dev->ec_int); - if (fdt_gpio_isvalid(&dev->ec_int)) + if (fdt_gpio_isvalid(&dev->ec_int)) { + gpio_request(dev->ec_int.gpio, "cros-ec-irq"); gpio_direction_input(dev->ec_int.gpio); + } if (cros_ec_check_version(dev)) { debug("%s: Could not detect CROS-EC version\n", __func__); @@ -1125,11 +1201,15 @@ int cros_ec_init(const void *blob, struct cros_ec_dev **cros_ecp) } /* Remember this device for use by the cros_ec command */ - last_dev = *cros_ecp = dev; + *cros_ecp = dev; +#ifndef CONFIG_DM_CROS_EC + last_dev = dev; +#endif debug("Google Chrome EC CROS-EC driver ready, id '%s'\n", id); return 0; } +#endif int cros_ec_decode_region(int argc, char * const argv[]) { @@ -1147,15 +1227,10 @@ int cros_ec_decode_region(int argc, char * const argv[]) return -1; } -int cros_ec_decode_ec_flash(const void *blob, struct fdt_cros_ec *config) +int cros_ec_decode_ec_flash(const void *blob, int node, + struct fdt_cros_ec *config) { - int flash_node, node; - - node = fdtdec_next_compatible(blob, 0, COMPAT_GOOGLE_CROS_EC); - if (node < 0) { - debug("Failed to find chrome-ec node'\n"); - return -1; - } + int flash_node; flash_node = fdt_subnode_offset(blob, node, "flash"); if (flash_node < 0) { @@ -1516,7 +1591,10 @@ static int cros_ec_i2c_passthrough(struct cros_ec_dev *dev, int flag, static int do_cros_ec(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[]) { - struct cros_ec_dev *dev = last_dev; + struct cros_ec_dev *dev; +#ifdef CONFIG_DM_CROS_EC + struct udevice *udev; +#endif const char *cmd; int ret = 0; @@ -1525,19 +1603,31 @@ static int do_cros_ec(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[]) cmd = argv[1]; if (0 == strcmp("init", cmd)) { +#ifndef CONFIG_DM_CROS_EC ret = cros_ec_init(gd->fdt_blob, &dev); if (ret) { printf("Could not init cros_ec device (err %d)\n", ret); return 1; } +#endif return 0; } +#ifdef CONFIG_DM_CROS_EC + ret = uclass_get_device(UCLASS_CROS_EC, 0, &udev); + if (ret) { + printf("Cannot get cros-ec device (err=%d)\n", ret); + return 1; + } + dev = udev->uclass_priv; +#else /* Just use the last allocated device; there should be only one */ if (!last_dev) { printf("No CROS-EC device available\n"); return 1; } + dev = last_dev; +#endif if (0 == strcmp("id", cmd)) { char id[MSG_BYTES]; @@ -1794,3 +1884,11 @@ U_BOOT_CMD( "crosec i2c mw chip address[.0, .1, .2] value [count] - write to I2C passthru (fill)" ); #endif + +#ifdef CONFIG_DM_CROS_EC +UCLASS_DRIVER(cros_ec) = { + .id = UCLASS_CROS_EC, + .name = "cros_ec", + .per_device_auto_alloc_size = sizeof(struct cros_ec_dev), +}; +#endif diff --git a/drivers/misc/cros_ec_lpc.c b/drivers/misc/cros_ec_lpc.c index 0e02671..07624a1 100644 --- a/drivers/misc/cros_ec_lpc.c +++ b/drivers/misc/cros_ec_lpc.c @@ -54,7 +54,7 @@ int cros_ec_lpc_command(struct cros_ec_dev *dev, uint8_t cmd, int cmd_version, int csum; int i; - if (dout_len > EC_HOST_PARAM_SIZE) { + if (dout_len > EC_PROTO2_MAX_PARAM_SIZE) { debug("%s: Cannot send %d bytes\n", __func__, dout_len); return -1; } @@ -159,7 +159,7 @@ int cros_ec_lpc_init(struct cros_ec_dev *dev, const void *blob) byte = 0xff; byte &= inb(EC_LPC_ADDR_HOST_CMD); byte &= inb(EC_LPC_ADDR_HOST_DATA); - for (i = 0; i < EC_HOST_PARAM_SIZE && (byte == 0xff); i++) + for (i = 0; i < EC_PROTO2_MAX_PARAM_SIZE && (byte == 0xff); i++) byte &= inb(EC_LPC_ADDR_HOST_PARAM + i); if (byte == 0xff) { debug("%s: CROS_EC device not found on LPC bus\n", diff --git a/drivers/misc/cros_ec_sandbox.c b/drivers/misc/cros_ec_sandbox.c index 8a04af5..99cc529 100644 --- a/drivers/misc/cros_ec_sandbox.c +++ b/drivers/misc/cros_ec_sandbox.c @@ -8,6 +8,7 @@ #include <common.h> #include <cros_ec.h> +#include <dm.h> #include <ec_commands.h> #include <errno.h> #include <hash.h> @@ -85,7 +86,7 @@ struct ec_state { struct ec_keymatrix_entry *matrix; /* the key matrix info */ uint8_t keyscan[KEYBOARD_COLS]; bool recovery_req; -} s_state, *state; +} s_state, *g_state; /** * cros_ec_read_state() - read the sandbox EC state from the state file @@ -138,7 +139,7 @@ static int cros_ec_read_state(const void *blob, int node) */ static int cros_ec_write_state(void *blob, int node) { - struct ec_state *ec = &s_state; + struct ec_state *ec = g_state; /* We are guaranteed enough space to write basic properties */ fdt_setprop_u32(blob, node, "current-image", ec->current_image); @@ -369,7 +370,7 @@ static int process_cmd(struct ec_state *ec, struct fmap_entry *entry; int ret, size; - entry = &state->ec_config.region[EC_FLASH_REGION_RW]; + entry = &ec->ec_config.region[EC_FLASH_REGION_RW]; switch (req->cmd) { case EC_VBOOT_HASH_RECALC: @@ -426,7 +427,7 @@ static int process_cmd(struct ec_state *ec, case EC_FLASH_REGION_RO: case EC_FLASH_REGION_RW: case EC_FLASH_REGION_WP_RO: - entry = &state->ec_config.region[req->region]; + entry = &ec->ec_config.region[req->region]; resp->offset = entry->offset; resp->size = entry->length; len = sizeof(*resp); @@ -466,16 +467,24 @@ static int process_cmd(struct ec_state *ec, return len; } +#ifdef CONFIG_DM_CROS_EC +int cros_ec_sandbox_packet(struct udevice *udev, int out_bytes, int in_bytes) +{ + struct cros_ec_dev *dev = udev->uclass_priv; + struct ec_state *ec = dev_get_priv(dev->dev); +#else int cros_ec_sandbox_packet(struct cros_ec_dev *dev, int out_bytes, int in_bytes) { + struct ec_state *ec = &s_state; +#endif struct ec_host_request *req_hdr = (struct ec_host_request *)dev->dout; const void *req_data = req_hdr + 1; struct ec_host_response *resp_hdr = (struct ec_host_response *)dev->din; void *resp_data = resp_hdr + 1; int len; - len = process_cmd(&s_state, req_hdr, req_data, resp_hdr, resp_data); + len = process_cmd(ec, req_hdr, req_data, resp_hdr, resp_data); if (len < 0) return len; @@ -498,7 +507,11 @@ int cros_ec_sandbox_decode_fdt(struct cros_ec_dev *dev, const void *blob) void cros_ec_check_keyboard(struct cros_ec_dev *dev) { +#ifdef CONFIG_DM_CROS_EC + struct ec_state *ec = dev_get_priv(dev->dev); +#else struct ec_state *ec = &s_state; +#endif ulong start; printf("Press keys for EC to detect on reset (ESC=recovery)..."); @@ -512,6 +525,52 @@ void cros_ec_check_keyboard(struct cros_ec_dev *dev) } } +#ifdef CONFIG_DM_CROS_EC +int cros_ec_probe(struct udevice *dev) +{ + struct ec_state *ec = dev->priv; + struct cros_ec_dev *cdev = dev->uclass_priv; + const void *blob = gd->fdt_blob; + int node; + int err; + + memcpy(ec, &s_state, sizeof(*ec)); + err = cros_ec_decode_ec_flash(blob, dev->of_offset, &ec->ec_config); + if (err) + return err; + + node = fdtdec_next_compatible(blob, 0, COMPAT_GOOGLE_CROS_EC_KEYB); + if (node < 0) { + debug("%s: No cros_ec keyboard found\n", __func__); + } else if (keyscan_read_fdt_matrix(ec, blob, node)) { + debug("%s: Could not read key matrix\n", __func__); + return -1; + } + + /* If we loaded EC data, check that the length matches */ + if (ec->flash_data && + ec->flash_data_len != ec->ec_config.flash.length) { + printf("EC data length is %x, expected %x, discarding data\n", + ec->flash_data_len, ec->ec_config.flash.length); + os_free(ec->flash_data); + ec->flash_data = NULL; + } + + /* Otherwise allocate the memory */ + if (!ec->flash_data) { + ec->flash_data_len = ec->ec_config.flash.length; + ec->flash_data = os_malloc(ec->flash_data_len); + if (!ec->flash_data) + return -ENOMEM; + } + + cdev->dev = dev; + g_state = ec; + return cros_ec_register(dev); +} + +#else + /** * Initialize sandbox EC emulation. * @@ -525,8 +584,13 @@ int cros_ec_sandbox_init(struct cros_ec_dev *dev, const void *blob) int node; int err; - state = &s_state; - err = cros_ec_decode_ec_flash(blob, &ec->ec_config); + node = fdtdec_next_compatible(blob, 0, COMPAT_GOOGLE_CROS_EC); + if (node < 0) { + debug("Failed to find chrome-ec node'\n"); + return -1; + } + + err = cros_ec_decode_ec_flash(blob, node, &ec->ec_config); if (err) return err; @@ -557,3 +621,24 @@ int cros_ec_sandbox_init(struct cros_ec_dev *dev, const void *blob) return 0; } +#endif + +#ifdef CONFIG_DM_CROS_EC +struct dm_cros_ec_ops cros_ec_ops = { + .packet = cros_ec_sandbox_packet, +}; + +static const struct udevice_id cros_ec_ids[] = { + { .compatible = "google,cros-ec" }, + { } +}; + +U_BOOT_DRIVER(cros_ec_sandbox) = { + .name = "cros_ec", + .id = UCLASS_CROS_EC, + .of_match = cros_ec_ids, + .probe = cros_ec_probe, + .priv_auto_alloc_size = sizeof(struct ec_state), + .ops = &cros_ec_ops, +}; +#endif diff --git a/drivers/misc/cros_ec_spi.c b/drivers/misc/cros_ec_spi.c index 015333f..e403664 100644 --- a/drivers/misc/cros_ec_spi.c +++ b/drivers/misc/cros_ec_spi.c @@ -15,23 +15,34 @@ #include <common.h> #include <cros_ec.h> +#include <dm.h> +#include <errno.h> #include <spi.h> +DECLARE_GLOBAL_DATA_PTR; + +#ifdef CONFIG_DM_CROS_EC +int cros_ec_spi_packet(struct udevice *udev, int out_bytes, int in_bytes) +{ + struct cros_ec_dev *dev = udev->uclass_priv; +#else int cros_ec_spi_packet(struct cros_ec_dev *dev, int out_bytes, int in_bytes) { +#endif + struct spi_slave *slave = dev_get_parentdata(dev->dev); int rv; /* Do the transfer */ - if (spi_claim_bus(dev->spi)) { + if (spi_claim_bus(slave)) { debug("%s: Cannot claim SPI bus\n", __func__); return -1; } - rv = spi_xfer(dev->spi, max(out_bytes, in_bytes) * 8, + rv = spi_xfer(slave, max(out_bytes, in_bytes) * 8, dev->dout, dev->din, SPI_XFER_BEGIN | SPI_XFER_END); - spi_release_bus(dev->spi); + spi_release_bus(slave); if (rv) { debug("%s: Cannot complete SPI transfer\n", __func__); @@ -56,10 +67,19 @@ int cros_ec_spi_packet(struct cros_ec_dev *dev, int out_bytes, int in_bytes) * @param din_len Maximum size of response in bytes * @return number of bytes in response, or -1 on error */ +#ifdef CONFIG_DM_CROS_EC +int cros_ec_spi_command(struct udevice *udev, uint8_t cmd, int cmd_version, + const uint8_t *dout, int dout_len, + uint8_t **dinp, int din_len) +{ + struct cros_ec_dev *dev = udev->uclass_priv; +#else int cros_ec_spi_command(struct cros_ec_dev *dev, uint8_t cmd, int cmd_version, const uint8_t *dout, int dout_len, uint8_t **dinp, int din_len) { +#endif + struct spi_slave *slave = dev_get_parentdata(dev->dev); int in_bytes = din_len + 4; /* status, length, checksum, trailer */ uint8_t *out; uint8_t *p; @@ -92,7 +112,7 @@ int cros_ec_spi_command(struct cros_ec_dev *dev, uint8_t cmd, int cmd_version, */ memset(dev->din, '\0', in_bytes); - if (spi_claim_bus(dev->spi)) { + if (spi_claim_bus(slave)) { debug("%s: Cannot claim SPI bus\n", __func__); return -1; } @@ -113,10 +133,10 @@ int cros_ec_spi_command(struct cros_ec_dev *dev, uint8_t cmd, int cmd_version, p = dev->din + sizeof(int64_t) - 2; len = dout_len + 4; cros_ec_dump_data("out", cmd, out, len); - rv = spi_xfer(dev->spi, max(len, in_bytes) * 8, out, p, + rv = spi_xfer(slave, max(len, in_bytes) * 8, out, p, SPI_XFER_BEGIN | SPI_XFER_END); - spi_release_bus(dev->spi); + spi_release_bus(slave); if (rv) { debug("%s: Cannot complete SPI transfer\n", __func__); @@ -146,6 +166,7 @@ int cros_ec_spi_command(struct cros_ec_dev *dev, uint8_t cmd, int cmd_version, return len; } +#ifndef CONFIG_DM_CROS_EC int cros_ec_spi_decode_fdt(struct cros_ec_dev *dev, const void *blob) { /* Decode interface-specific FDT params */ @@ -165,11 +186,59 @@ int cros_ec_spi_decode_fdt(struct cros_ec_dev *dev, const void *blob) */ int cros_ec_spi_init(struct cros_ec_dev *dev, const void *blob) { - dev->spi = spi_setup_slave_fdt(blob, dev->node, dev->parent_node); - if (!dev->spi) { + int ret; + + ret = spi_setup_slave_fdt(blob, dev->node, dev->parent_node, + &slave); + if (ret) { debug("%s: Could not setup SPI slave\n", __func__); - return -1; + return ret; } return 0; } +#endif + +#ifdef CONFIG_DM_CROS_EC +int cros_ec_probe(struct udevice *dev) +{ + struct spi_slave *slave = dev_get_parentdata(dev); + int ret; + + /* + * TODO(sjg@chromium.org) + * + * This is really horrible at present. It is an artifact of removing + * the child_pre_probe() method for SPI. Everything here could go in + * an automatic function, except that spi_get_bus_and_cs() wants to + * set it up manually and call device_probe_child(). + * + * The solution may be to re-enable the child_pre_probe() method for + * SPI and have it do nothing if the child is already passed in via + * device_probe_child(). + */ + slave->dev = dev; + ret = spi_ofdata_to_platdata(gd->fdt_blob, dev->of_offset, slave); + if (ret) + return ret; + return cros_ec_register(dev); +} + +struct dm_cros_ec_ops cros_ec_ops = { + .packet = cros_ec_spi_packet, + .command = cros_ec_spi_command, +}; + +static const struct udevice_id cros_ec_ids[] = { + { .compatible = "google,cros-ec" }, + { } +}; + +U_BOOT_DRIVER(cros_ec_spi) = { + .name = "cros_ec", + .id = UCLASS_CROS_EC, + .of_match = cros_ec_ids, + .probe = cros_ec_probe, + .ops = &cros_ec_ops, +}; +#endif |