uboot/drivers/misc/cros_ec_sandbox.c
<<
>>
Prefs
   1// SPDX-License-Identifier: GPL-2.0+
   2/*
   3 * Chromium OS cros_ec driver - sandbox emulation
   4 *
   5 * Copyright (c) 2013 The Chromium OS Authors.
   6 */
   7
   8#define LOG_CATEGORY UCLASS_CROS_EC
   9
  10#include <common.h>
  11#include <cros_ec.h>
  12#include <dm.h>
  13#include <ec_commands.h>
  14#include <errno.h>
  15#include <hash.h>
  16#include <log.h>
  17#include <os.h>
  18#include <u-boot/sha256.h>
  19#include <spi.h>
  20#include <asm/malloc.h>
  21#include <asm/state.h>
  22#include <asm/sdl.h>
  23#include <asm/test.h>
  24#include <linux/input.h>
  25
  26/*
  27 * Ultimately it shold be possible to connect an Chrome OS EC emulation
  28 * to U-Boot and remove all of this code. But this provides a test
  29 * environment for bringing up chromeos_sandbox and demonstrating its
  30 * utility.
  31 *
  32 * This emulation includes the following:
  33 *
  34 * 1. Emulation of the keyboard, by converting keypresses received from SDL
  35 * into key scan data, passed back from the EC as key scan messages. The
  36 * key layout is read from the device tree.
  37 *
  38 * 2. Emulation of vboot context - so this can be read/written as required.
  39 *
  40 * 3. Save/restore of EC state, so that the vboot context, flash memory
  41 * contents and current image can be preserved across boots. This is important
  42 * since the EC is supposed to continue running even if the AP resets.
  43 *
  44 * 4. Some event support, in particular allowing Escape to be pressed on boot
  45 * to enter recovery mode. The EC passes this to U-Boot through the normal
  46 * event message.
  47 *
  48 * 5. Flash read/write/erase support, so that software sync works. The
  49 * protect messages are supported but no protection is implemented.
  50 *
  51 * 6. Hashing of the EC image, again to support software sync.
  52 *
  53 * Other features can be added, although a better path is probably to link
  54 * the EC image in with U-Boot (Vic has demonstrated a prototype for this).
  55 */
  56
  57#define KEYBOARD_ROWS   8
  58#define KEYBOARD_COLS   13
  59
  60/* A single entry of the key matrix */
  61struct ec_keymatrix_entry {
  62        int row;        /* key matrix row */
  63        int col;        /* key matrix column */
  64        int keycode;    /* corresponding linux key code */
  65};
  66
  67enum {
  68        VSTORE_SLOT_COUNT       = 4,
  69        PWM_CHANNEL_COUNT       = 4,
  70};
  71
  72struct vstore_slot {
  73        bool locked;
  74        u8 data[EC_VSTORE_SLOT_SIZE];
  75};
  76
  77struct ec_pwm_channel {
  78        uint duty;      /* not ns, EC_PWM_MAX_DUTY = 100% */
  79};
  80
  81/**
  82 * struct ec_state - Information about the EC state
  83 *
  84 * @vbnv_context: Vboot context data stored by EC
  85 * @ec_config: FDT config information about the EC (e.g. flashmap)
  86 * @flash_data: Contents of flash memory
  87 * @flash_data_len: Size of flash memory
  88 * @current_image: Current image the EC is running
  89 * @matrix_count: Number of keys to decode in matrix
  90 * @matrix: Information about keyboard matrix
  91 * @keyscan: Current keyscan information (bit set for each row/column pressed)
  92 * @recovery_req: Keyboard recovery requested
  93 * @test_flags: Flags that control behaviour for tests
  94 * @slot_locked: Locked vstore slots (mask)
  95 * @pwm: Information per PWM channel
  96 */
  97struct ec_state {
  98        u8 vbnv_context[EC_VBNV_BLOCK_SIZE_V2];
  99        struct fdt_cros_ec ec_config;
 100        uint8_t *flash_data;
 101        int flash_data_len;
 102        enum ec_current_image current_image;
 103        int matrix_count;
 104        struct ec_keymatrix_entry *matrix;      /* the key matrix info */
 105        uint8_t keyscan[KEYBOARD_COLS];
 106        bool recovery_req;
 107        uint test_flags;
 108        struct vstore_slot slot[VSTORE_SLOT_COUNT];
 109        struct ec_pwm_channel pwm[PWM_CHANNEL_COUNT];
 110} s_state, *g_state;
 111
 112/**
 113 * cros_ec_read_state() - read the sandbox EC state from the state file
 114 *
 115 * If data is available, then blob and node will provide access to it. If
 116 * not this function sets up an empty EC.
 117 *
 118 * @param blob: Pointer to device tree blob, or NULL if no data to read
 119 * @param node: Node offset to read from
 120 */
 121static int cros_ec_read_state(const void *blob, int node)
 122{
 123        struct ec_state *ec = &s_state;
 124        const char *prop;
 125        int len;
 126
 127        /* Set everything to defaults */
 128        ec->current_image = EC_IMAGE_RO;
 129        if (!blob)
 130                return 0;
 131
 132        /* Read the data if available */
 133        ec->current_image = fdtdec_get_int(blob, node, "current-image",
 134                                           EC_IMAGE_RO);
 135        prop = fdt_getprop(blob, node, "vbnv-context", &len);
 136        if (prop && len == sizeof(ec->vbnv_context))
 137                memcpy(ec->vbnv_context, prop, len);
 138
 139        prop = fdt_getprop(blob, node, "flash-data", &len);
 140        if (prop) {
 141                ec->flash_data_len = len;
 142                ec->flash_data = malloc(len);
 143                if (!ec->flash_data)
 144                        return -ENOMEM;
 145                memcpy(ec->flash_data, prop, len);
 146                debug("%s: Loaded EC flash data size %#x\n", __func__, len);
 147        }
 148
 149        return 0;
 150}
 151
 152/**
 153 * cros_ec_write_state() - Write out our state to the state file
 154 *
 155 * The caller will ensure that there is a node ready for the state. The node
 156 * may already contain the old state, in which case it is overridden.
 157 *
 158 * @param blob: Device tree blob holding state
 159 * @param node: Node to write our state into
 160 */
 161static int cros_ec_write_state(void *blob, int node)
 162{
 163        struct ec_state *ec = g_state;
 164
 165        if (!g_state)
 166                return 0;
 167
 168        /* We are guaranteed enough space to write basic properties */
 169        fdt_setprop_u32(blob, node, "current-image", ec->current_image);
 170        fdt_setprop(blob, node, "vbnv-context", ec->vbnv_context,
 171                    sizeof(ec->vbnv_context));
 172
 173        return state_setprop(node, "flash-data", ec->flash_data,
 174                             ec->ec_config.flash.length);
 175}
 176
 177SANDBOX_STATE_IO(cros_ec, "google,cros-ec", cros_ec_read_state,
 178                 cros_ec_write_state);
 179
 180/**
 181 * Return the number of bytes used in the specified image.
 182 *
 183 * This is the actual size of code+data in the image, as opposed to the
 184 * amount of space reserved in flash for that image. This code is similar to
 185 * that used by the real EC code base.
 186 *
 187 * @param ec    Current emulated EC state
 188 * @param entry Flash map entry containing the image to check
 189 * @return actual image size in bytes, 0 if the image contains no content or
 190 * error.
 191 */
 192static int get_image_used(struct ec_state *ec, struct fmap_entry *entry)
 193{
 194        int size;
 195
 196        /*
 197         * Scan backwards looking for 0xea byte, which is by definition the
 198         * last byte of the image.  See ec.lds.S for how this is inserted at
 199         * the end of the image.
 200         */
 201        for (size = entry->length - 1;
 202             size > 0 && ec->flash_data[entry->offset + size] != 0xea;
 203             size--)
 204                ;
 205
 206        return size ? size + 1 : 0;  /* 0xea byte IS part of the image */
 207}
 208
 209/**
 210 * Read the key matrix from the device tree
 211 *
 212 * Keymap entries in the fdt take the form of 0xRRCCKKKK where
 213 * RR=Row CC=Column KKKK=Key Code
 214 *
 215 * @param ec    Current emulated EC state
 216 * @param node  Keyboard node of device tree containing keyscan information
 217 * @return 0 if ok, -1 on error
 218 */
 219static int keyscan_read_fdt_matrix(struct ec_state *ec, ofnode node)
 220{
 221        const u32 *cell;
 222        int upto;
 223        int len;
 224
 225        cell = ofnode_get_property(node, "linux,keymap", &len);
 226        if (!cell)
 227                return log_msg_ret("prop", -EINVAL);
 228        ec->matrix_count = len / 4;
 229        ec->matrix = calloc(ec->matrix_count, sizeof(*ec->matrix));
 230        if (!ec->matrix) {
 231                return log_msg_ret("mem", -ENOMEM);
 232        }
 233
 234        /* Now read the data */
 235        for (upto = 0; upto < ec->matrix_count; upto++) {
 236                struct ec_keymatrix_entry *matrix = &ec->matrix[upto];
 237                u32 word;
 238
 239                word = fdt32_to_cpu(*cell++);
 240                matrix->row = word >> 24;
 241                matrix->col = (word >> 16) & 0xff;
 242                matrix->keycode = word & 0xffff;
 243
 244                /* Hard-code some sanity limits for now */
 245                if (matrix->row >= KEYBOARD_ROWS ||
 246                    matrix->col >= KEYBOARD_COLS) {
 247                        debug("%s: Matrix pos out of range (%d,%d)\n",
 248                              __func__, matrix->row, matrix->col);
 249                        return log_msg_ret("matrix", -ERANGE);
 250                }
 251        }
 252
 253        if (upto != ec->matrix_count) {
 254                return log_msg_ret("matrix", -E2BIG);
 255        }
 256
 257        return 0;
 258}
 259
 260/**
 261 * Return the next keyscan message contents
 262 *
 263 * @param ec    Current emulated EC state
 264 * @param scan  Place to put keyscan bytes for the keyscan message (must hold
 265 *              enough space for a full keyscan)
 266 * @return number of bytes of valid scan data
 267 */
 268static int cros_ec_keyscan(struct ec_state *ec, uint8_t *scan)
 269{
 270        const struct ec_keymatrix_entry *matrix;
 271        int bytes = KEYBOARD_COLS;
 272        int key[8];     /* allow up to 8 keys to be pressed at once */
 273        int count;
 274        int i;
 275
 276        memset(ec->keyscan, '\0', bytes);
 277        count = sandbox_sdl_scan_keys(key, ARRAY_SIZE(key));
 278
 279        /* Look up keycode in matrix */
 280        for (i = 0, matrix = ec->matrix; i < ec->matrix_count; i++, matrix++) {
 281                bool found;
 282                int j;
 283
 284                for (found = false, j = 0; j < count; j++) {
 285                        if (matrix->keycode == key[j])
 286                                found = true;
 287                }
 288
 289                if (found) {
 290                        debug("%d: %d,%d\n", matrix->keycode, matrix->row,
 291                              matrix->col);
 292                        ec->keyscan[matrix->col] |= 1 << matrix->row;
 293                }
 294        }
 295
 296        memcpy(scan, ec->keyscan, bytes);
 297        return bytes;
 298}
 299
 300/**
 301 * Process an emulated EC command
 302 *
 303 * @param ec            Current emulated EC state
 304 * @param req_hdr       Pointer to request header
 305 * @param req_data      Pointer to body of request
 306 * @param resp_hdr      Pointer to place to put response header
 307 * @param resp_data     Pointer to place to put response data, if any
 308 * @return length of response data, or 0 for no response data, or -1 on error
 309 */
 310static int process_cmd(struct ec_state *ec,
 311                       struct ec_host_request *req_hdr, const void *req_data,
 312                       struct ec_host_response *resp_hdr, void *resp_data)
 313{
 314        int len;
 315
 316        /* TODO(sjg@chromium.org): Check checksums */
 317        debug("EC command %#0x\n", req_hdr->command);
 318
 319        switch (req_hdr->command) {
 320        case EC_CMD_HELLO: {
 321                const struct ec_params_hello *req = req_data;
 322                struct ec_response_hello *resp = resp_data;
 323
 324                resp->out_data = req->in_data + 0x01020304;
 325                if (ec->test_flags & CROSECT_BREAK_HELLO)
 326                        resp->out_data++;
 327                len = sizeof(*resp);
 328                break;
 329        }
 330        case EC_CMD_GET_VERSION: {
 331                struct ec_response_get_version *resp = resp_data;
 332
 333                strcpy(resp->version_string_ro, "sandbox_ro");
 334                strcpy(resp->version_string_rw, "sandbox_rw");
 335                resp->current_image = ec->current_image;
 336                debug("Current image %d\n", resp->current_image);
 337                len = sizeof(*resp);
 338                break;
 339        }
 340        case EC_CMD_VBNV_CONTEXT: {
 341                const struct ec_params_vbnvcontext *req = req_data;
 342                struct ec_response_vbnvcontext *resp = resp_data;
 343
 344                switch (req->op) {
 345                case EC_VBNV_CONTEXT_OP_READ:
 346                        memcpy(resp->block, ec->vbnv_context,
 347                               EC_VBNV_BLOCK_SIZE_V2);
 348                        len = EC_VBNV_BLOCK_SIZE_V2;
 349                        break;
 350                case EC_VBNV_CONTEXT_OP_WRITE:
 351                        memcpy(ec->vbnv_context, req->block,
 352                               EC_VBNV_BLOCK_SIZE_V2);
 353                        len = 0;
 354                        break;
 355                default:
 356                        printf("   ** Unknown vbnv_context command %#02x\n",
 357                               req->op);
 358                        return -1;
 359                }
 360                break;
 361        }
 362        case EC_CMD_REBOOT_EC: {
 363                const struct ec_params_reboot_ec *req = req_data;
 364
 365                printf("Request reboot type %d\n", req->cmd);
 366                switch (req->cmd) {
 367                case EC_REBOOT_DISABLE_JUMP:
 368                        len = 0;
 369                        break;
 370                case EC_REBOOT_JUMP_RW:
 371                        ec->current_image = EC_IMAGE_RW;
 372                        len = 0;
 373                        break;
 374                default:
 375                        puts("   ** Unknown type");
 376                        return -1;
 377                }
 378                break;
 379        }
 380        case EC_CMD_HOST_EVENT_GET_B: {
 381                struct ec_response_host_event_mask *resp = resp_data;
 382
 383                resp->mask = 0;
 384                if (ec->recovery_req) {
 385                        resp->mask |= EC_HOST_EVENT_MASK(
 386                                        EC_HOST_EVENT_KEYBOARD_RECOVERY);
 387                }
 388                if (ec->test_flags & CROSECT_LID_OPEN)
 389                        resp->mask |=
 390                                EC_HOST_EVENT_MASK(EC_HOST_EVENT_LID_OPEN);
 391                len = sizeof(*resp);
 392                break;
 393        }
 394        case EC_CMD_HOST_EVENT_CLEAR_B: {
 395                const struct ec_params_host_event_mask *req = req_data;
 396
 397                if (req->mask & EC_HOST_EVENT_MASK(EC_HOST_EVENT_LID_OPEN))
 398                        ec->test_flags &= ~CROSECT_LID_OPEN;
 399                len = 0;
 400                break;
 401                }
 402        case EC_CMD_VBOOT_HASH: {
 403                const struct ec_params_vboot_hash *req = req_data;
 404                struct ec_response_vboot_hash *resp = resp_data;
 405                struct fmap_entry *entry;
 406                int ret, size;
 407
 408                entry = &ec->ec_config.region[EC_FLASH_REGION_ACTIVE];
 409
 410                switch (req->cmd) {
 411                case EC_VBOOT_HASH_RECALC:
 412                case EC_VBOOT_HASH_GET:
 413                        size = SHA256_SUM_LEN;
 414                        len = get_image_used(ec, entry);
 415                        ret = hash_block("sha256",
 416                                         ec->flash_data + entry->offset,
 417                                         len, resp->hash_digest, &size);
 418                        if (ret) {
 419                                printf("   ** hash_block() failed\n");
 420                                return -1;
 421                        }
 422                        resp->status = EC_VBOOT_HASH_STATUS_DONE;
 423                        resp->hash_type = EC_VBOOT_HASH_TYPE_SHA256;
 424                        resp->digest_size = size;
 425                        resp->reserved0 = 0;
 426                        resp->offset = entry->offset;
 427                        resp->size = len;
 428                        len = sizeof(*resp);
 429                        break;
 430                default:
 431                        printf("   ** EC_CMD_VBOOT_HASH: Unknown command %d\n",
 432                               req->cmd);
 433                        return -1;
 434                }
 435                break;
 436        }
 437        case EC_CMD_FLASH_PROTECT: {
 438                const struct ec_params_flash_protect *req = req_data;
 439                struct ec_response_flash_protect *resp = resp_data;
 440                uint32_t expect = EC_FLASH_PROTECT_ALL_NOW |
 441                                EC_FLASH_PROTECT_ALL_AT_BOOT;
 442
 443                printf("mask=%#x, flags=%#x\n", req->mask, req->flags);
 444                if (req->flags == expect || req->flags == 0) {
 445                        resp->flags = req->flags ? EC_FLASH_PROTECT_ALL_NOW :
 446                                                                0;
 447                        resp->valid_flags = EC_FLASH_PROTECT_ALL_NOW;
 448                        resp->writable_flags = 0;
 449                        len = sizeof(*resp);
 450                } else {
 451                        puts("   ** unexpected flash protect request\n");
 452                        return -1;
 453                }
 454                break;
 455        }
 456        case EC_CMD_FLASH_REGION_INFO: {
 457                const struct ec_params_flash_region_info *req = req_data;
 458                struct ec_response_flash_region_info *resp = resp_data;
 459                struct fmap_entry *entry;
 460
 461                switch (req->region) {
 462                case EC_FLASH_REGION_RO:
 463                case EC_FLASH_REGION_ACTIVE:
 464                case EC_FLASH_REGION_WP_RO:
 465                        entry = &ec->ec_config.region[req->region];
 466                        resp->offset = entry->offset;
 467                        resp->size = entry->length;
 468                        len = sizeof(*resp);
 469                        printf("EC flash region %d: offset=%#x, size=%#x\n",
 470                               req->region, resp->offset, resp->size);
 471                        break;
 472                default:
 473                        printf("** Unknown flash region %d\n", req->region);
 474                        return -1;
 475                }
 476                break;
 477        }
 478        case EC_CMD_FLASH_ERASE: {
 479                const struct ec_params_flash_erase *req = req_data;
 480
 481                memset(ec->flash_data + req->offset,
 482                       ec->ec_config.flash_erase_value,
 483                       req->size);
 484                len = 0;
 485                break;
 486        }
 487        case EC_CMD_FLASH_WRITE: {
 488                const struct ec_params_flash_write *req = req_data;
 489
 490                memcpy(ec->flash_data + req->offset, req + 1, req->size);
 491                len = 0;
 492                break;
 493        }
 494        case EC_CMD_MKBP_STATE:
 495                len = cros_ec_keyscan(ec, resp_data);
 496                break;
 497        case EC_CMD_GET_NEXT_EVENT: {
 498                struct ec_response_get_next_event *resp = resp_data;
 499
 500                resp->event_type = EC_MKBP_EVENT_KEY_MATRIX;
 501                cros_ec_keyscan(ec, resp->data.key_matrix);
 502                len = sizeof(*resp);
 503                break;
 504        }
 505        case EC_CMD_GET_SKU_ID: {
 506                struct ec_sku_id_info *resp = resp_data;
 507
 508                resp->sku_id = 1234;
 509                len = sizeof(*resp);
 510                break;
 511        }
 512        case EC_CMD_GET_FEATURES: {
 513                struct ec_response_get_features *resp = resp_data;
 514
 515                resp->flags[0] = EC_FEATURE_MASK_0(EC_FEATURE_FLASH) |
 516                        EC_FEATURE_MASK_0(EC_FEATURE_I2C) |
 517                        EC_FEATURE_MASK_0(EC_FEATURE_VSTORE);
 518                resp->flags[1] =
 519                        EC_FEATURE_MASK_1(EC_FEATURE_UNIFIED_WAKE_MASKS) |
 520                        EC_FEATURE_MASK_1(EC_FEATURE_ISH);
 521                len = sizeof(*resp);
 522                break;
 523        }
 524        case EC_CMD_VSTORE_INFO: {
 525                struct ec_response_vstore_info *resp = resp_data;
 526                int i;
 527
 528                resp->slot_count = VSTORE_SLOT_COUNT;
 529                resp->slot_locked = 0;
 530                for (i = 0; i < VSTORE_SLOT_COUNT; i++) {
 531                        if (ec->slot[i].locked)
 532                                resp->slot_locked |= 1 << i;
 533                }
 534                len = sizeof(*resp);
 535                break;
 536        };
 537        case EC_CMD_VSTORE_WRITE: {
 538                const struct ec_params_vstore_write *req = req_data;
 539                struct vstore_slot *slot;
 540
 541                if (req->slot >= EC_VSTORE_SLOT_MAX)
 542                        return -EINVAL;
 543                slot = &ec->slot[req->slot];
 544                slot->locked = true;
 545                memcpy(slot->data, req->data, EC_VSTORE_SLOT_SIZE);
 546                len = 0;
 547                break;
 548        }
 549        case EC_CMD_VSTORE_READ: {
 550                const struct ec_params_vstore_read *req = req_data;
 551                struct ec_response_vstore_read *resp = resp_data;
 552                struct vstore_slot *slot;
 553
 554                if (req->slot >= EC_VSTORE_SLOT_MAX)
 555                        return -EINVAL;
 556                slot = &ec->slot[req->slot];
 557                memcpy(resp->data, slot->data, EC_VSTORE_SLOT_SIZE);
 558                len = sizeof(*resp);
 559                break;
 560        }
 561        case EC_CMD_PWM_GET_DUTY: {
 562                const struct ec_params_pwm_get_duty *req = req_data;
 563                struct ec_response_pwm_get_duty *resp = resp_data;
 564                struct ec_pwm_channel *pwm;
 565
 566                if (req->pwm_type != EC_PWM_TYPE_GENERIC)
 567                        return -EINVAL;
 568                if (req->index >= PWM_CHANNEL_COUNT)
 569                        return -EINVAL;
 570                pwm = &ec->pwm[req->index];
 571                resp->duty = pwm->duty;
 572                len = sizeof(*resp);
 573                break;
 574        }
 575        case EC_CMD_PWM_SET_DUTY: {
 576                const struct ec_params_pwm_set_duty *req = req_data;
 577                struct ec_pwm_channel *pwm;
 578
 579                if (req->pwm_type != EC_PWM_TYPE_GENERIC)
 580                        return -EINVAL;
 581                if (req->index >= PWM_CHANNEL_COUNT)
 582                        return -EINVAL;
 583                pwm = &ec->pwm[req->index];
 584                pwm->duty = req->duty;
 585                len = 0;
 586                break;
 587        }
 588        default:
 589                printf("   ** Unknown EC command %#02x\n", req_hdr->command);
 590                return -1;
 591        }
 592
 593        return len;
 594}
 595
 596int cros_ec_sandbox_packet(struct udevice *udev, int out_bytes, int in_bytes)
 597{
 598        struct cros_ec_dev *dev = dev_get_uclass_priv(udev);
 599        struct ec_state *ec = dev_get_priv(dev->dev);
 600        struct ec_host_request *req_hdr = (struct ec_host_request *)dev->dout;
 601        const void *req_data = req_hdr + 1;
 602        struct ec_host_response *resp_hdr = (struct ec_host_response *)dev->din;
 603        void *resp_data = resp_hdr + 1;
 604        int len;
 605
 606        len = process_cmd(ec, req_hdr, req_data, resp_hdr, resp_data);
 607        if (len < 0)
 608                return len;
 609
 610        resp_hdr->struct_version = 3;
 611        resp_hdr->result = EC_RES_SUCCESS;
 612        resp_hdr->data_len = len;
 613        resp_hdr->reserved = 0;
 614        len += sizeof(*resp_hdr);
 615        resp_hdr->checksum = 0;
 616        resp_hdr->checksum = (uint8_t)
 617                -cros_ec_calc_checksum((const uint8_t *)resp_hdr, len);
 618
 619        return in_bytes;
 620}
 621
 622void cros_ec_check_keyboard(struct udevice *dev)
 623{
 624        struct ec_state *ec = dev_get_priv(dev);
 625        ulong start;
 626
 627        printf("\nPress keys for EC to detect on reset (ESC=recovery)...");
 628        start = get_timer(0);
 629        while (get_timer(start) < 2000) {
 630                if (tstc()) {
 631                        int ch = getchar();
 632
 633                        if (ch == 0x1b) {
 634                                ec->recovery_req = true;
 635                                printf("EC requests recovery");
 636                        }
 637                }
 638        }
 639        putc('\n');
 640}
 641
 642/* Return the byte of EC switch states */
 643static int cros_ec_sandbox_get_switches(struct udevice *dev)
 644{
 645        struct ec_state *ec = dev_get_priv(dev);
 646
 647        return ec->test_flags & CROSECT_LID_OPEN ? EC_SWITCH_LID_OPEN : 0;
 648}
 649
 650void sandbox_cros_ec_set_test_flags(struct udevice *dev, uint flags)
 651{
 652        struct ec_state *ec = dev_get_priv(dev);
 653
 654        ec->test_flags = flags;
 655}
 656
 657int sandbox_cros_ec_get_pwm_duty(struct udevice *dev, uint index, uint *duty)
 658{
 659        struct ec_state *ec = dev_get_priv(dev);
 660        struct ec_pwm_channel *pwm;
 661
 662        if (index >= PWM_CHANNEL_COUNT)
 663                return -ENOSPC;
 664        pwm = &ec->pwm[index];
 665        *duty = pwm->duty;
 666
 667        return 0;
 668}
 669
 670int cros_ec_probe(struct udevice *dev)
 671{
 672        struct ec_state *ec = dev_get_priv(dev);
 673        struct cros_ec_dev *cdev = dev_get_uclass_priv(dev);
 674        struct udevice *keyb_dev;
 675        ofnode node;
 676        int err;
 677
 678        memcpy(ec, &s_state, sizeof(*ec));
 679        err = cros_ec_decode_ec_flash(dev, &ec->ec_config);
 680        if (err) {
 681                debug("%s: Cannot device EC flash\n", __func__);
 682                return err;
 683        }
 684
 685        node = ofnode_null();
 686        for (device_find_first_child(dev, &keyb_dev);
 687             keyb_dev;
 688             device_find_next_child(&keyb_dev)) {
 689                if (device_get_uclass_id(keyb_dev) == UCLASS_KEYBOARD) {
 690                        node = dev_ofnode(keyb_dev);
 691                        break;
 692                }
 693        }
 694        if (!ofnode_valid(node)) {
 695                debug("%s: No cros_ec keyboard found\n", __func__);
 696        } else if (keyscan_read_fdt_matrix(ec, node)) {
 697                debug("%s: Could not read key matrix\n", __func__);
 698                return -1;
 699        }
 700
 701        /* If we loaded EC data, check that the length matches */
 702        if (ec->flash_data &&
 703            ec->flash_data_len != ec->ec_config.flash.length) {
 704                printf("EC data length is %x, expected %x, discarding data\n",
 705                       ec->flash_data_len, ec->ec_config.flash.length);
 706                free(ec->flash_data);
 707                ec->flash_data = NULL;
 708        }
 709
 710        /* Otherwise allocate the memory */
 711        if (!ec->flash_data) {
 712                ec->flash_data_len = ec->ec_config.flash.length;
 713                ec->flash_data = malloc(ec->flash_data_len);
 714                if (!ec->flash_data)
 715                        return -ENOMEM;
 716        }
 717
 718        cdev->dev = dev;
 719        g_state = ec;
 720        return cros_ec_register(dev);
 721}
 722
 723struct dm_cros_ec_ops cros_ec_ops = {
 724        .packet = cros_ec_sandbox_packet,
 725        .get_switches = cros_ec_sandbox_get_switches,
 726};
 727
 728static const struct udevice_id cros_ec_ids[] = {
 729        { .compatible = "google,cros-ec-sandbox" },
 730        { }
 731};
 732
 733U_BOOT_DRIVER(google_cros_ec_sandbox) = {
 734        .name           = "google_cros_ec_sandbox",
 735        .id             = UCLASS_CROS_EC,
 736        .of_match       = cros_ec_ids,
 737        .probe          = cros_ec_probe,
 738        .priv_auto      = sizeof(struct ec_state),
 739        .ops            = &cros_ec_ops,
 740};
 741