summaryrefslogtreecommitdiffstats
path: root/qemu/roms/u-boot/drivers/misc
diff options
context:
space:
mode:
authorYang Zhang <yang.z.zhang@intel.com>2015-08-28 09:58:54 +0800
committerYang Zhang <yang.z.zhang@intel.com>2015-09-01 12:44:00 +0800
commite44e3482bdb4d0ebde2d8b41830ac2cdb07948fb (patch)
tree66b09f592c55df2878107a468a91d21506104d3f /qemu/roms/u-boot/drivers/misc
parent9ca8dbcc65cfc63d6f5ef3312a33184e1d726e00 (diff)
Add qemu 2.4.0
Change-Id: Ic99cbad4b61f8b127b7dc74d04576c0bcbaaf4f5 Signed-off-by: Yang Zhang <yang.z.zhang@intel.com>
Diffstat (limited to 'qemu/roms/u-boot/drivers/misc')
-rw-r--r--qemu/roms/u-boot/drivers/misc/Makefile25
-rw-r--r--qemu/roms/u-boot/drivers/misc/ali512x.c402
-rw-r--r--qemu/roms/u-boot/drivers/misc/cbmem_console.c67
-rw-r--r--qemu/roms/u-boot/drivers/misc/cros_ec.c1796
-rw-r--r--qemu/roms/u-boot/drivers/misc/cros_ec_i2c.c176
-rw-r--r--qemu/roms/u-boot/drivers/misc/cros_ec_lpc.c194
-rw-r--r--qemu/roms/u-boot/drivers/misc/cros_ec_sandbox.c559
-rw-r--r--qemu/roms/u-boot/drivers/misc/cros_ec_spi.c175
-rw-r--r--qemu/roms/u-boot/drivers/misc/ds4510.c423
-rw-r--r--qemu/roms/u-boot/drivers/misc/fsl_ifc.c171
-rw-r--r--qemu/roms/u-boot/drivers/misc/fsl_iim.c281
-rw-r--r--qemu/roms/u-boot/drivers/misc/gpio_led.c53
-rw-r--r--qemu/roms/u-boot/drivers/misc/mc9sdz60.c35
-rw-r--r--qemu/roms/u-boot/drivers/misc/mxc_ocotp.c200
-rw-r--r--qemu/roms/u-boot/drivers/misc/mxs_ocotp.c311
-rw-r--r--qemu/roms/u-boot/drivers/misc/ns87308.c101
-rw-r--r--qemu/roms/u-boot/drivers/misc/pdsp188x.c45
-rw-r--r--qemu/roms/u-boot/drivers/misc/status_led.c111
-rw-r--r--qemu/roms/u-boot/drivers/misc/twl4030_led.c34
19 files changed, 5159 insertions, 0 deletions
diff --git a/qemu/roms/u-boot/drivers/misc/Makefile b/qemu/roms/u-boot/drivers/misc/Makefile
new file mode 100644
index 000000000..2f2e48f97
--- /dev/null
+++ b/qemu/roms/u-boot/drivers/misc/Makefile
@@ -0,0 +1,25 @@
+#
+# (C) Copyright 2000-2007
+# Wolfgang Denk, DENX Software Engineering, wd@denx.de.
+#
+# SPDX-License-Identifier: GPL-2.0+
+#
+
+obj-$(CONFIG_ALI152X) += ali512x.o
+obj-$(CONFIG_DS4510) += ds4510.o
+obj-$(CONFIG_CBMEM_CONSOLE) += cbmem_console.o
+obj-$(CONFIG_CROS_EC) += cros_ec.o
+obj-$(CONFIG_CROS_EC_LPC) += cros_ec_lpc.o
+obj-$(CONFIG_CROS_EC_I2C) += cros_ec_i2c.o
+obj-$(CONFIG_CROS_EC_SANDBOX) += cros_ec_sandbox.o
+obj-$(CONFIG_CROS_EC_SPI) += cros_ec_spi.o
+obj-$(CONFIG_FSL_IIM) += fsl_iim.o
+obj-$(CONFIG_GPIO_LED) += gpio_led.o
+obj-$(CONFIG_FSL_MC9SDZ60) += mc9sdz60.o
+obj-$(CONFIG_MXC_OCOTP) += mxc_ocotp.o
+obj-$(CONFIG_MXS_OCOTP) += mxs_ocotp.o
+obj-$(CONFIG_NS87308) += ns87308.o
+obj-$(CONFIG_PDSP188x) += pdsp188x.o
+obj-$(CONFIG_STATUS_LED) += status_led.o
+obj-$(CONFIG_TWL4030_LED) += twl4030_led.o
+obj-$(CONFIG_FSL_IFC) += fsl_ifc.o
diff --git a/qemu/roms/u-boot/drivers/misc/ali512x.c b/qemu/roms/u-boot/drivers/misc/ali512x.c
new file mode 100644
index 000000000..f271f8a68
--- /dev/null
+++ b/qemu/roms/u-boot/drivers/misc/ali512x.c
@@ -0,0 +1,402 @@
+/*
+ * (C) Copyright 2002
+ * Daniel Engström, Omicron Ceti AB <daniel@omicron.se>.
+ *
+ * SPDX-License-Identifier: GPL-2.0+
+ */
+
+/*
+ * Based on sc520cdp.c from rolo 1.6:
+ *----------------------------------------------------------------------
+ * (C) Copyright 2000
+ * Sysgo Real-Time Solutions GmbH
+ * Klein-Winternheim, Germany
+ *----------------------------------------------------------------------
+ */
+
+#include <config.h>
+
+#include <common.h>
+#include <asm/io.h>
+#include <ali512x.h>
+
+
+/* ALI M5123 Logical device numbers:
+ * 0 FDC
+ * 1 unused?
+ * 2 unused?
+ * 3 lpt
+ * 4 UART1
+ * 5 UART2
+ * 6 RTC
+ * 7 mouse/kbd
+ * 8 CIO
+ */
+
+/*
+ ************************************************************
+ * Some access primitives for the ALi chip: *
+ ************************************************************
+ */
+
+static void ali_write(u8 index, u8 value)
+{
+ /* write an arbirary register */
+ outb(index, ALI_INDEX);
+ outb(value, ALI_DATA);
+}
+
+#if 0
+static int ali_read(u8 index)
+{
+ outb(index, ALI_INDEX);
+ return inb(ALI_DATA);
+}
+#endif
+
+#define ALI_OPEN() \
+ outb(0x51, ALI_INDEX); \
+ outb(0x23, ALI_INDEX)
+
+
+#define ALI_CLOSE() \
+ outb(0xbb, ALI_INDEX)
+
+/* Select a logical device */
+#define ALI_SELDEV(dev) \
+ ali_write(0x07, dev)
+
+
+void ali512x_init(void)
+{
+ ALI_OPEN();
+
+ ali_write(0x02, 0x01); /* soft reset */
+ ali_write(0x03, 0x03); /* disable access to CIOs */
+ ali_write(0x22, 0x00); /* disable direct powerdown */
+ ali_write(0x23, 0x00); /* disable auto powerdown */
+ ali_write(0x24, 0x00); /* IR 8 is active hi, pin26 is PDIR */
+
+ ALI_CLOSE();
+}
+
+void ali512x_set_fdc(int enabled, u16 io, u8 irq, u8 dma_channel)
+{
+ ALI_OPEN();
+ ALI_SELDEV(0);
+
+ ali_write(0x30, enabled?1:0);
+ if (enabled) {
+ ali_write(0x60, io >> 8);
+ ali_write(0x61, io & 0xff);
+ ali_write(0x70, irq);
+ ali_write(0x74, dma_channel);
+
+ /* AT mode, no drive swap */
+ ali_write(0xf0, 0x08);
+ ali_write(0xf1, 0x00);
+ ali_write(0xf2, 0xff);
+ ali_write(0xf4, 0x00);
+ }
+ ALI_CLOSE();
+}
+
+
+void ali512x_set_pp(int enabled, u16 io, u8 irq, u8 dma_channel)
+{
+ ALI_OPEN();
+ ALI_SELDEV(3);
+
+ ali_write(0x30, enabled?1:0);
+ if (enabled) {
+ ali_write(0x60, io >> 8);
+ ali_write(0x61, io & 0xff);
+ ali_write(0x70, irq);
+ ali_write(0x74, dma_channel);
+
+ /* mode: EPP 1.9, ECP FIFO threshold = 7, IRQ active low */
+ ali_write(0xf0, 0xbc);
+ /* 12 MHz, Burst DMA in ECP */
+ ali_write(0xf1, 0x05);
+ }
+ ALI_CLOSE();
+
+}
+
+void ali512x_set_uart(int enabled, int index, u16 io, u8 irq)
+{
+ ALI_OPEN();
+ ALI_SELDEV(index?5:4);
+
+ ali_write(0x30, enabled?1:0);
+ if (enabled) {
+ ali_write(0x60, io >> 8);
+ ali_write(0x61, io & 0xff);
+ ali_write(0x70, irq);
+
+ ali_write(0xf0, 0x00);
+ ali_write(0xf1, 0x00);
+
+ /* huh? write 0xf2 twice - a typo in rolo
+ * or some secret ali errata? Who knows?
+ */
+ if (index) {
+ ali_write(0xf2, 0x00);
+ }
+ ali_write(0xf2, 0x0c);
+ }
+ ALI_CLOSE();
+
+}
+
+void ali512x_set_uart2_irda(int enabled)
+{
+ ALI_OPEN();
+ ALI_SELDEV(5);
+
+ ali_write(0xf1, enabled?0x48:0x00); /* fullduplex IrDa */
+ ALI_CLOSE();
+
+}
+
+void ali512x_set_rtc(int enabled, u16 io, u8 irq)
+{
+ ALI_OPEN();
+ ALI_SELDEV(6);
+
+ ali_write(0x30, enabled?1:0);
+ if (enabled) {
+ ali_write(0x60, io >> 8);
+ ali_write(0x61, io & 0xff);
+ ali_write(0x70, irq);
+
+ ali_write(0xf0, 0x00);
+ }
+ ALI_CLOSE();
+}
+
+void ali512x_set_kbc(int enabled, u8 kbc_irq, u8 mouse_irq)
+{
+ ALI_OPEN();
+ ALI_SELDEV(7);
+
+ ali_write(0x30, enabled?1:0);
+ if (enabled) {
+ ali_write(0x70, kbc_irq);
+ ali_write(0x72, mouse_irq);
+
+ ali_write(0xf0, 0x00);
+ }
+ ALI_CLOSE();
+}
+
+
+/* Common I/O
+ *
+ * (This descripotsion is base on several incompete sources
+ * since I have not been able to obtain any datasheet for the device
+ * there may be some mis-understandings burried in here.
+ * -- Daniel daniel@omicron.se)
+ *
+ * There are 22 CIO pins numbered
+ * 10-17
+ * 20-25
+ * 30-37
+ *
+ * 20-24 are dedicated CIO pins, the other 17 are muliplexed with
+ * other functions.
+ *
+ * Secondary
+ * CIO Pin Function Decription
+ * =======================================================
+ * CIO10 IRQIN1 Interrupt input 1?
+ * CIO11 IRQIN2 Interrupt input 2?
+ * CIO12 IRRX IrDa Receive
+ * CIO13 IRTX IrDa Transmit
+ * CIO14 P21 KBC P21 fucntion
+ * CIO15 P20 KBC P21 fucntion
+ * CIO16 I2C_CLK I2C Clock
+ * CIO17 I2C_DAT I2C Data
+ *
+ * CIO20 -
+ * CIO21 -
+ * CIO22 -
+ * CIO23 -
+ * CIO24 -
+ * CIO25 LOCK Keylock
+ *
+ * CIO30 KBC_CLK Keybaord Clock
+ * CIO31 CS0J General Chip Select decoder CS0J
+ * CIO32 CS1J General Chip Select decoder CS1J
+ * CIO33 ALT_KCLK Alternative Keyboard Clock
+ * CIO34 ALT_KDAT Alternative Keyboard Data
+ * CIO35 ALT_MCLK Alternative Mouse Clock
+ * CIO36 ALT_MDAT Alternative Mouse Data
+ * CIO37 ALT_KBC Alternative KBC select
+ *
+ * The CIO use an indirect address scheme.
+ *
+ * Reigster 3 in the SIO is used to select the index and data
+ * port addresses where the CIO I/O registers show up.
+ * The function selection registers are accessible under
+ * function SIO 8.
+ *
+ * SIO reigster 3 (CIO Address Selection) bit definitions:
+ * bit 7 CIO index and data registers enabled
+ * bit 1-0 CIO indirect registers port address select
+ * 0 index = 0xE0 data = 0xE1
+ * 1 index = 0xE2 data = 0xE3
+ * 2 index = 0xE4 data = 0xE5
+ * 3 index = 0xEA data = 0xEB
+ *
+ * There are three CIO I/O register accessed via CIO index port and CIO data port
+ * 0x01 CIO 10-17 data
+ * 0x02 CIO 20-25 data (bits 7-6 unused)
+ * 0x03 CIO 30-37 data
+ *
+ *
+ * The pin function is accessed through normal
+ * SIO registers, each register have the same format:
+ *
+ * Bit Function Value
+ * 0 Input/output 1=input
+ * 1 Polarity of signal 1=inverted
+ * 2 Unused ??
+ * 3 Function (normal or special) 1=special
+ * 7-4 Unused
+ *
+ * SIO REG
+ * 0xe0 CIO 10 Config
+ * 0xe1 CIO 11 Config
+ * 0xe2 CIO 12 Config
+ * 0xe3 CIO 13 Config
+ * 0xe4 CIO 14 Config
+ * 0xe5 CIO 15 Config
+ * 0xe6 CIO 16 Config
+ * 0xe7 CIO 16 Config
+ *
+ * 0xe8 CIO 20 Config
+ * 0xe9 CIO 21 Config
+ * 0xea CIO 22 Config
+ * 0xeb CIO 23 Config
+ * 0xec CIO 24 Config
+ * 0xed CIO 25 Config
+ *
+ * 0xf5 CIO 30 Config
+ * 0xf6 CIO 31 Config
+ * 0xf7 CIO 32 Config
+ * 0xf8 CIO 33 Config
+ * 0xf9 CIO 34 Config
+ * 0xfa CIO 35 Config
+ * 0xfb CIO 36 Config
+ * 0xfc CIO 37 Config
+ *
+ */
+
+#define ALI_CIO_PORT_SEL 0x83
+#define ALI_CIO_INDEX 0xea
+#define ALI_CIO_DATA 0xeb
+
+void ali512x_set_cio(int enabled)
+{
+ int i;
+
+ ALI_OPEN();
+
+ if (enabled) {
+ ali_write(0x3, ALI_CIO_PORT_SEL); /* Enable CIO data register */
+ } else {
+ ali_write(0x3, ALI_CIO_PORT_SEL & ~0x80);
+ }
+
+ ALI_SELDEV(8);
+
+ ali_write(0x30, enabled?1:0);
+
+ /* set all pins to input to start with */
+ for (i=0xe0;i<0xee;i++) {
+ ali_write(i, 1);
+ }
+
+ for (i=0xf5;i<0xfe;i++) {
+ ali_write(i, 1);
+ }
+
+ ALI_CLOSE();
+}
+
+
+void ali512x_cio_function(int pin, int special, int inv, int input)
+{
+ u8 data;
+ u8 addr;
+
+ /* valid pins are 10-17, 20-25 and 30-37 */
+ if (pin >= 10 && pin <= 17) {
+ addr = 0xe0+(pin&7);
+ } else if (pin >= 20 && pin <= 25) {
+ addr = 0xe8+(pin&7);
+ } else if (pin >= 30 && pin <= 37) {
+ addr = 0xf5+(pin&7);
+ } else {
+ return;
+ }
+
+ ALI_OPEN();
+
+ ALI_SELDEV(8);
+
+
+ data=0xf4;
+ if (special) {
+ data |= 0x08;
+ } else {
+ if (inv) {
+ data |= 0x02;
+ }
+ if (input) {
+ data |= 0x01;
+ }
+ }
+
+ ali_write(addr, data);
+
+ ALI_CLOSE();
+}
+
+void ali512x_cio_out(int pin, int value)
+{
+ u8 reg;
+ u8 data;
+ u8 bit;
+
+ reg = pin/10;
+ bit = 1 << (pin%10);
+
+
+ outb(reg, ALI_CIO_INDEX); /* select I/O register */
+ data = inb(ALI_CIO_DATA);
+ if (value) {
+ data |= bit;
+ } else {
+ data &= ~bit;
+ }
+ outb(data, ALI_CIO_DATA);
+}
+
+int ali512x_cio_in(int pin)
+{
+ u8 reg;
+ u8 data;
+ u8 bit;
+
+ /* valid pins are 10-17, 20-25 and 30-37 */
+ reg = pin/10;
+ bit = 1 << (pin%10);
+
+
+ outb(reg, ALI_CIO_INDEX); /* select I/O register */
+ data = inb(ALI_CIO_DATA);
+
+ return data & bit;
+}
diff --git a/qemu/roms/u-boot/drivers/misc/cbmem_console.c b/qemu/roms/u-boot/drivers/misc/cbmem_console.c
new file mode 100644
index 000000000..80a84fdf8
--- /dev/null
+++ b/qemu/roms/u-boot/drivers/misc/cbmem_console.c
@@ -0,0 +1,67 @@
+/*
+ * Copyright (C) 2011 The ChromiumOS Authors. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; version 2 of the License.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA, 02110-1301 USA
+ */
+
+#include <common.h>
+
+#ifndef CONFIG_SYS_COREBOOT
+#error This driver requires coreboot
+#endif
+
+#include <asm/arch/sysinfo.h>
+
+struct cbmem_console {
+ u32 buffer_size;
+ u32 buffer_cursor;
+ u8 buffer_body[0];
+} __attribute__ ((__packed__));
+
+static struct cbmem_console *cbmem_console_p;
+
+void cbmemc_putc(char data)
+{
+ int cursor;
+
+ cursor = cbmem_console_p->buffer_cursor++;
+ if (cursor < cbmem_console_p->buffer_size)
+ cbmem_console_p->buffer_body[cursor] = data;
+}
+
+void cbmemc_puts(const char *str)
+{
+ char c;
+
+ while ((c = *str++) != 0)
+ cbmemc_putc(c);
+}
+
+int cbmemc_init(void)
+{
+ int rc;
+ struct stdio_dev cons_dev;
+ cbmem_console_p = lib_sysinfo.cbmem_cons;
+
+ memset(&cons_dev, 0, sizeof(cons_dev));
+
+ strcpy(cons_dev.name, "cbmem");
+ cons_dev.flags = DEV_FLAGS_OUTPUT; /* Output only */
+ cons_dev.putc = cbmemc_putc;
+ cons_dev.puts = cbmemc_puts;
+
+ rc = stdio_register(&cons_dev);
+
+ return (rc == 0) ? 1 : rc;
+}
diff --git a/qemu/roms/u-boot/drivers/misc/cros_ec.c b/qemu/roms/u-boot/drivers/misc/cros_ec.c
new file mode 100644
index 000000000..068373b94
--- /dev/null
+++ b/qemu/roms/u-boot/drivers/misc/cros_ec.c
@@ -0,0 +1,1796 @@
+/*
+ * Chromium OS cros_ec driver
+ *
+ * Copyright (c) 2012 The Chromium OS Authors.
+ *
+ * SPDX-License-Identifier: GPL-2.0+
+ */
+
+/*
+ * This is the interface to the Chrome OS EC. It provides keyboard functions,
+ * power control and battery management. Quite a few other functions are
+ * provided to enable the EC software to be updated, talk to the EC's I2C bus
+ * and store a small amount of data in a memory which persists while the EC
+ * is not reset.
+ */
+
+#include <common.h>
+#include <command.h>
+#include <i2c.h>
+#include <cros_ec.h>
+#include <fdtdec.h>
+#include <malloc.h>
+#include <spi.h>
+#include <asm/errno.h>
+#include <asm/io.h>
+#include <asm-generic/gpio.h>
+
+#ifdef DEBUG_TRACE
+#define debug_trace(fmt, b...) debug(fmt, #b)
+#else
+#define debug_trace(fmt, b...)
+#endif
+
+enum {
+ /* Timeout waiting for a flash erase command to complete */
+ CROS_EC_CMD_TIMEOUT_MS = 5000,
+ /* Timeout waiting for a synchronous hash to be recomputed */
+ CROS_EC_CMD_HASH_TIMEOUT_MS = 2000,
+};
+
+static struct cros_ec_dev static_dev, *last_dev;
+
+DECLARE_GLOBAL_DATA_PTR;
+
+/* Note: depends on enum ec_current_image */
+static const char * const ec_current_image_name[] = {"unknown", "RO", "RW"};
+
+void cros_ec_dump_data(const char *name, int cmd, const uint8_t *data, int len)
+{
+#ifdef DEBUG
+ int i;
+
+ printf("%s: ", name);
+ if (cmd != -1)
+ printf("cmd=%#x: ", cmd);
+ for (i = 0; i < len; i++)
+ printf("%02x ", data[i]);
+ printf("\n");
+#endif
+}
+
+/*
+ * Calculate a simple 8-bit checksum of a data block
+ *
+ * @param data Data block to checksum
+ * @param size Size of data block in bytes
+ * @return checksum value (0 to 255)
+ */
+int cros_ec_calc_checksum(const uint8_t *data, int size)
+{
+ int csum, i;
+
+ for (i = csum = 0; i < size; i++)
+ csum += data[i];
+ return csum & 0xff;
+}
+
+/**
+ * Create a request packet for protocol version 3.
+ *
+ * The packet is stored in the device's internal output buffer.
+ *
+ * @param dev CROS-EC device
+ * @param cmd Command to send (EC_CMD_...)
+ * @param cmd_version Version of command to send (EC_VER_...)
+ * @param dout Output data (may be NULL If dout_len=0)
+ * @param dout_len Size of output data in bytes
+ * @return packet size in bytes, or <0 if error.
+ */
+static int create_proto3_request(struct cros_ec_dev *dev,
+ int cmd, int cmd_version,
+ const void *dout, int dout_len)
+{
+ struct ec_host_request *rq = (struct ec_host_request *)dev->dout;
+ int out_bytes = dout_len + sizeof(*rq);
+
+ /* Fail if output size is too big */
+ if (out_bytes > (int)sizeof(dev->dout)) {
+ debug("%s: Cannot send %d bytes\n", __func__, dout_len);
+ return -EC_RES_REQUEST_TRUNCATED;
+ }
+
+ /* Fill in request packet */
+ rq->struct_version = EC_HOST_REQUEST_VERSION;
+ rq->checksum = 0;
+ rq->command = cmd;
+ rq->command_version = cmd_version;
+ rq->reserved = 0;
+ rq->data_len = dout_len;
+
+ /* Copy data after header */
+ memcpy(rq + 1, dout, dout_len);
+
+ /* Write checksum field so the entire packet sums to 0 */
+ rq->checksum = (uint8_t)(-cros_ec_calc_checksum(dev->dout, out_bytes));
+
+ cros_ec_dump_data("out", cmd, dev->dout, out_bytes);
+
+ /* Return size of request packet */
+ return out_bytes;
+}
+
+/**
+ * Prepare the device to receive a protocol version 3 response.
+ *
+ * @param dev CROS-EC device
+ * @param din_len Maximum size of response in bytes
+ * @return maximum expected number of bytes in response, or <0 if error.
+ */
+static int prepare_proto3_response_buffer(struct cros_ec_dev *dev, int din_len)
+{
+ int in_bytes = din_len + sizeof(struct ec_host_response);
+
+ /* Fail if input size is too big */
+ if (in_bytes > (int)sizeof(dev->din)) {
+ debug("%s: Cannot receive %d bytes\n", __func__, din_len);
+ return -EC_RES_RESPONSE_TOO_BIG;
+ }
+
+ /* Return expected size of response packet */
+ return in_bytes;
+}
+
+/**
+ * Handle a protocol version 3 response packet.
+ *
+ * The packet must already be stored in the device's internal input buffer.
+ *
+ * @param dev CROS-EC device
+ * @param dinp Returns pointer to response data
+ * @param din_len Maximum size of response in bytes
+ * @return number of bytes of response data, or <0 if error
+ */
+static int handle_proto3_response(struct cros_ec_dev *dev,
+ uint8_t **dinp, int din_len)
+{
+ struct ec_host_response *rs = (struct ec_host_response *)dev->din;
+ int in_bytes;
+ int csum;
+
+ cros_ec_dump_data("in-header", -1, dev->din, sizeof(*rs));
+
+ /* Check input data */
+ if (rs->struct_version != EC_HOST_RESPONSE_VERSION) {
+ debug("%s: EC response version mismatch\n", __func__);
+ return -EC_RES_INVALID_RESPONSE;
+ }
+
+ if (rs->reserved) {
+ debug("%s: EC response reserved != 0\n", __func__);
+ return -EC_RES_INVALID_RESPONSE;
+ }
+
+ if (rs->data_len > din_len) {
+ debug("%s: EC returned too much data\n", __func__);
+ return -EC_RES_RESPONSE_TOO_BIG;
+ }
+
+ cros_ec_dump_data("in-data", -1, dev->din + sizeof(*rs), rs->data_len);
+
+ /* Update in_bytes to actual data size */
+ in_bytes = sizeof(*rs) + rs->data_len;
+
+ /* Verify checksum */
+ csum = cros_ec_calc_checksum(dev->din, in_bytes);
+ if (csum) {
+ debug("%s: EC response checksum invalid: 0x%02x\n", __func__,
+ csum);
+ return -EC_RES_INVALID_CHECKSUM;
+ }
+
+ /* Return error result, if any */
+ if (rs->result)
+ return -(int)rs->result;
+
+ /* If we're still here, set response data pointer and return length */
+ *dinp = (uint8_t *)(rs + 1);
+
+ return rs->data_len;
+}
+
+static int send_command_proto3(struct cros_ec_dev *dev,
+ int cmd, int cmd_version,
+ const void *dout, int dout_len,
+ uint8_t **dinp, int din_len)
+{
+ int out_bytes, in_bytes;
+ int rv;
+
+ /* Create request packet */
+ out_bytes = create_proto3_request(dev, cmd, cmd_version,
+ dout, dout_len);
+ if (out_bytes < 0)
+ return out_bytes;
+
+ /* Prepare response buffer */
+ in_bytes = prepare_proto3_response_buffer(dev, din_len);
+ if (in_bytes < 0)
+ return in_bytes;
+
+ switch (dev->interface) {
+#ifdef CONFIG_CROS_EC_SPI
+ case CROS_EC_IF_SPI:
+ rv = cros_ec_spi_packet(dev, out_bytes, in_bytes);
+ break;
+#endif
+#ifdef CONFIG_CROS_EC_SANDBOX
+ case CROS_EC_IF_SANDBOX:
+ rv = cros_ec_sandbox_packet(dev, out_bytes, in_bytes);
+ break;
+#endif
+ case CROS_EC_IF_NONE:
+ /* TODO: support protocol 3 for LPC, I2C; for now fall through */
+ default:
+ debug("%s: Unsupported interface\n", __func__);
+ rv = -1;
+ }
+ if (rv < 0)
+ return rv;
+
+ /* Process the response */
+ return handle_proto3_response(dev, dinp, din_len);
+}
+
+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)
+{
+ int ret = -1;
+
+ /* Handle protocol version 3 support */
+ if (dev->protocol_version == 3) {
+ return send_command_proto3(dev, cmd, cmd_version,
+ dout, dout_len, dinp, din_len);
+ }
+
+ switch (dev->interface) {
+#ifdef CONFIG_CROS_EC_SPI
+ case CROS_EC_IF_SPI:
+ ret = cros_ec_spi_command(dev, cmd, cmd_version,
+ (const uint8_t *)dout, dout_len,
+ dinp, din_len);
+ break;
+#endif
+#ifdef CONFIG_CROS_EC_I2C
+ case CROS_EC_IF_I2C:
+ ret = cros_ec_i2c_command(dev, cmd, cmd_version,
+ (const uint8_t *)dout, dout_len,
+ dinp, din_len);
+ break;
+#endif
+#ifdef CONFIG_CROS_EC_LPC
+ case CROS_EC_IF_LPC:
+ ret = cros_ec_lpc_command(dev, cmd, cmd_version,
+ (const uint8_t *)dout, dout_len,
+ dinp, din_len);
+ break;
+#endif
+ case CROS_EC_IF_NONE:
+ default:
+ ret = -1;
+ }
+
+ return ret;
+}
+
+/**
+ * Send a command to the CROS-EC device and return the reply.
+ *
+ * The device's internal input/output buffers are used.
+ *
+ * @param dev CROS-EC device
+ * @param cmd Command to send (EC_CMD_...)
+ * @param cmd_version Version of command to send (EC_VER_...)
+ * @param dout Output data (may be NULL If dout_len=0)
+ * @param dout_len Size of output data in bytes
+ * @param dinp Response data (may be NULL If din_len=0).
+ * If not NULL, it will be updated to point to the data
+ * and will always be double word aligned (64-bits)
+ * @param din_len Maximum size of response in bytes
+ * @return number of bytes in response, or -1 on error
+ */
+static int ec_command_inptr(struct cros_ec_dev *dev, uint8_t cmd,
+ int cmd_version, const void *dout, int dout_len, uint8_t **dinp,
+ int din_len)
+{
+ uint8_t *din = NULL;
+ int len;
+
+ len = send_command(dev, cmd, cmd_version, dout, dout_len,
+ &din, din_len);
+
+ /* If the command doesn't complete, wait a while */
+ if (len == -EC_RES_IN_PROGRESS) {
+ struct ec_response_get_comms_status *resp = NULL;
+ ulong start;
+
+ /* Wait for command to complete */
+ start = get_timer(0);
+ do {
+ int ret;
+
+ mdelay(50); /* Insert some reasonable delay */
+ ret = send_command(dev, EC_CMD_GET_COMMS_STATUS, 0,
+ NULL, 0,
+ (uint8_t **)&resp, sizeof(*resp));
+ if (ret < 0)
+ return ret;
+
+ if (get_timer(start) > CROS_EC_CMD_TIMEOUT_MS) {
+ debug("%s: Command %#02x timeout\n",
+ __func__, cmd);
+ return -EC_RES_TIMEOUT;
+ }
+ } while (resp->flags & EC_COMMS_STATUS_PROCESSING);
+
+ /* OK it completed, so read the status response */
+ /* not sure why it was 0 for the last argument */
+ len = send_command(dev, EC_CMD_RESEND_RESPONSE, 0,
+ NULL, 0, &din, din_len);
+ }
+
+ debug("%s: len=%d, dinp=%p, *dinp=%p\n", __func__, len, dinp,
+ dinp ? *dinp : NULL);
+ if (dinp) {
+ /* If we have any data to return, it must be 64bit-aligned */
+ assert(len <= 0 || !((uintptr_t)din & 7));
+ *dinp = din;
+ }
+
+ return len;
+}
+
+/**
+ * Send a command to the CROS-EC device and return the reply.
+ *
+ * The device's internal input/output buffers are used.
+ *
+ * @param dev CROS-EC device
+ * @param cmd Command to send (EC_CMD_...)
+ * @param cmd_version Version of command to send (EC_VER_...)
+ * @param dout Output data (may be NULL If dout_len=0)
+ * @param dout_len Size of output data in bytes
+ * @param din Response data (may be NULL If din_len=0).
+ * It not NULL, it is a place for ec_command() to copy the
+ * data to.
+ * @param din_len Maximum size of response in bytes
+ * @return number of bytes in response, or -1 on error
+ */
+static int ec_command(struct cros_ec_dev *dev, uint8_t cmd, int cmd_version,
+ const void *dout, int dout_len,
+ void *din, int din_len)
+{
+ uint8_t *in_buffer;
+ int len;
+
+ assert((din_len == 0) || din);
+ len = ec_command_inptr(dev, cmd, cmd_version, dout, dout_len,
+ &in_buffer, din_len);
+ if (len > 0) {
+ /*
+ * If we were asked to put it somewhere, do so, otherwise just
+ * disregard the result.
+ */
+ if (din && in_buffer) {
+ assert(len <= din_len);
+ memmove(din, in_buffer, len);
+ }
+ }
+ return len;
+}
+
+int cros_ec_scan_keyboard(struct cros_ec_dev *dev, struct mbkp_keyscan *scan)
+{
+ if (ec_command(dev, EC_CMD_MKBP_STATE, 0, NULL, 0, scan,
+ sizeof(scan->data)) != sizeof(scan->data))
+ return -1;
+
+ return 0;
+}
+
+int cros_ec_read_id(struct cros_ec_dev *dev, char *id, int maxlen)
+{
+ struct ec_response_get_version *r;
+
+ if (ec_command_inptr(dev, EC_CMD_GET_VERSION, 0, NULL, 0,
+ (uint8_t **)&r, sizeof(*r)) != sizeof(*r))
+ return -1;
+
+ if (maxlen > (int)sizeof(r->version_string_ro))
+ maxlen = sizeof(r->version_string_ro);
+
+ switch (r->current_image) {
+ case EC_IMAGE_RO:
+ memcpy(id, r->version_string_ro, maxlen);
+ break;
+ case EC_IMAGE_RW:
+ memcpy(id, r->version_string_rw, maxlen);
+ break;
+ default:
+ return -1;
+ }
+
+ id[maxlen - 1] = '\0';
+ return 0;
+}
+
+int cros_ec_read_version(struct cros_ec_dev *dev,
+ struct ec_response_get_version **versionp)
+{
+ if (ec_command_inptr(dev, EC_CMD_GET_VERSION, 0, NULL, 0,
+ (uint8_t **)versionp, sizeof(**versionp))
+ != sizeof(**versionp))
+ return -1;
+
+ return 0;
+}
+
+int cros_ec_read_build_info(struct cros_ec_dev *dev, char **strp)
+{
+ if (ec_command_inptr(dev, EC_CMD_GET_BUILD_INFO, 0, NULL, 0,
+ (uint8_t **)strp, EC_PROTO2_MAX_PARAM_SIZE) < 0)
+ return -1;
+
+ return 0;
+}
+
+int cros_ec_read_current_image(struct cros_ec_dev *dev,
+ enum ec_current_image *image)
+{
+ struct ec_response_get_version *r;
+
+ if (ec_command_inptr(dev, EC_CMD_GET_VERSION, 0, NULL, 0,
+ (uint8_t **)&r, sizeof(*r)) != sizeof(*r))
+ return -1;
+
+ *image = r->current_image;
+ return 0;
+}
+
+static int cros_ec_wait_on_hash_done(struct cros_ec_dev *dev,
+ struct ec_response_vboot_hash *hash)
+{
+ struct ec_params_vboot_hash p;
+ ulong start;
+
+ start = get_timer(0);
+ while (hash->status == EC_VBOOT_HASH_STATUS_BUSY) {
+ mdelay(50); /* Insert some reasonable delay */
+
+ p.cmd = EC_VBOOT_HASH_GET;
+ if (ec_command(dev, EC_CMD_VBOOT_HASH, 0, &p, sizeof(p),
+ hash, sizeof(*hash)) < 0)
+ return -1;
+
+ if (get_timer(start) > CROS_EC_CMD_HASH_TIMEOUT_MS) {
+ debug("%s: EC_VBOOT_HASH_GET timeout\n", __func__);
+ return -EC_RES_TIMEOUT;
+ }
+ }
+ return 0;
+}
+
+
+int cros_ec_read_hash(struct cros_ec_dev *dev,
+ struct ec_response_vboot_hash *hash)
+{
+ struct ec_params_vboot_hash p;
+ int rv;
+
+ p.cmd = EC_VBOOT_HASH_GET;
+ if (ec_command(dev, EC_CMD_VBOOT_HASH, 0, &p, sizeof(p),
+ hash, sizeof(*hash)) < 0)
+ return -1;
+
+ /* If the EC is busy calculating the hash, fidget until it's done. */
+ rv = cros_ec_wait_on_hash_done(dev, hash);
+ if (rv)
+ return rv;
+
+ /* If the hash is valid, we're done. Otherwise, we have to kick it off
+ * again and wait for it to complete. Note that we explicitly assume
+ * that hashing zero bytes is always wrong, even though that would
+ * produce a valid hash value. */
+ if (hash->status == EC_VBOOT_HASH_STATUS_DONE && hash->size)
+ return 0;
+
+ debug("%s: No valid hash (status=%d size=%d). Compute one...\n",
+ __func__, hash->status, hash->size);
+
+ p.cmd = EC_VBOOT_HASH_START;
+ p.hash_type = EC_VBOOT_HASH_TYPE_SHA256;
+ p.nonce_size = 0;
+ p.offset = EC_VBOOT_HASH_OFFSET_RW;
+
+ if (ec_command(dev, EC_CMD_VBOOT_HASH, 0, &p, sizeof(p),
+ hash, sizeof(*hash)) < 0)
+ return -1;
+
+ rv = cros_ec_wait_on_hash_done(dev, hash);
+ if (rv)
+ return rv;
+
+ debug("%s: hash done\n", __func__);
+
+ return 0;
+}
+
+static int cros_ec_invalidate_hash(struct cros_ec_dev *dev)
+{
+ struct ec_params_vboot_hash p;
+ struct ec_response_vboot_hash *hash;
+
+ /* We don't have an explict command for the EC to discard its current
+ * hash value, so we'll just tell it to calculate one that we know is
+ * wrong (we claim that hashing zero bytes is always invalid).
+ */
+ p.cmd = EC_VBOOT_HASH_RECALC;
+ p.hash_type = EC_VBOOT_HASH_TYPE_SHA256;
+ p.nonce_size = 0;
+ p.offset = 0;
+ p.size = 0;
+
+ debug("%s:\n", __func__);
+
+ if (ec_command_inptr(dev, EC_CMD_VBOOT_HASH, 0, &p, sizeof(p),
+ (uint8_t **)&hash, sizeof(*hash)) < 0)
+ return -1;
+
+ /* No need to wait for it to finish */
+ return 0;
+}
+
+int cros_ec_reboot(struct cros_ec_dev *dev, enum ec_reboot_cmd cmd,
+ uint8_t flags)
+{
+ struct ec_params_reboot_ec p;
+
+ p.cmd = cmd;
+ p.flags = flags;
+
+ if (ec_command_inptr(dev, EC_CMD_REBOOT_EC, 0, &p, sizeof(p), NULL, 0)
+ < 0)
+ return -1;
+
+ if (!(flags & EC_REBOOT_FLAG_ON_AP_SHUTDOWN)) {
+ /*
+ * EC reboot will take place immediately so delay to allow it
+ * to complete. Note that some reboot types (EC_REBOOT_COLD)
+ * will reboot the AP as well, in which case we won't actually
+ * get to this point.
+ */
+ /*
+ * TODO(rspangler@chromium.org): Would be nice if we had a
+ * better way to determine when the reboot is complete. Could
+ * we poll a memory-mapped LPC value?
+ */
+ udelay(50000);
+ }
+
+ return 0;
+}
+
+int cros_ec_interrupt_pending(struct cros_ec_dev *dev)
+{
+ /* no interrupt support : always poll */
+ if (!fdt_gpio_isvalid(&dev->ec_int))
+ return -ENOENT;
+
+ return !gpio_get_value(dev->ec_int.gpio);
+}
+
+int cros_ec_info(struct cros_ec_dev *dev, struct ec_response_mkbp_info *info)
+{
+ if (ec_command(dev, EC_CMD_MKBP_INFO, 0, NULL, 0, info,
+ sizeof(*info)) != sizeof(*info))
+ return -1;
+
+ return 0;
+}
+
+int cros_ec_get_host_events(struct cros_ec_dev *dev, uint32_t *events_ptr)
+{
+ struct ec_response_host_event_mask *resp;
+
+ /*
+ * Use the B copy of the event flags, because the main copy is already
+ * used by ACPI/SMI.
+ */
+ if (ec_command_inptr(dev, EC_CMD_HOST_EVENT_GET_B, 0, NULL, 0,
+ (uint8_t **)&resp, sizeof(*resp)) < (int)sizeof(*resp))
+ return -1;
+
+ if (resp->mask & EC_HOST_EVENT_MASK(EC_HOST_EVENT_INVALID))
+ return -1;
+
+ *events_ptr = resp->mask;
+ return 0;
+}
+
+int cros_ec_clear_host_events(struct cros_ec_dev *dev, uint32_t events)
+{
+ struct ec_params_host_event_mask params;
+
+ params.mask = events;
+
+ /*
+ * Use the B copy of the event flags, so it affects the data returned
+ * by cros_ec_get_host_events().
+ */
+ if (ec_command_inptr(dev, EC_CMD_HOST_EVENT_CLEAR_B, 0,
+ &params, sizeof(params), NULL, 0) < 0)
+ return -1;
+
+ return 0;
+}
+
+int cros_ec_flash_protect(struct cros_ec_dev *dev,
+ uint32_t set_mask, uint32_t set_flags,
+ struct ec_response_flash_protect *resp)
+{
+ struct ec_params_flash_protect params;
+
+ params.mask = set_mask;
+ params.flags = set_flags;
+
+ if (ec_command(dev, EC_CMD_FLASH_PROTECT, EC_VER_FLASH_PROTECT,
+ &params, sizeof(params),
+ resp, sizeof(*resp)) != sizeof(*resp))
+ return -1;
+
+ return 0;
+}
+
+static int cros_ec_check_version(struct cros_ec_dev *dev)
+{
+ struct ec_params_hello req;
+ struct ec_response_hello *resp;
+
+#ifdef CONFIG_CROS_EC_LPC
+ /* LPC has its own way of doing this */
+ if (dev->interface == CROS_EC_IF_LPC)
+ return cros_ec_lpc_check_version(dev);
+#endif
+
+ /*
+ * TODO(sjg@chromium.org).
+ * There is a strange oddity here with the EC. We could just ignore
+ * the response, i.e. pass the last two parameters as NULL and 0.
+ * In this case we won't read back very many bytes from the EC.
+ * On the I2C bus the EC gets upset about this and will try to send
+ * the bytes anyway. This means that we will have to wait for that
+ * to complete before continuing with a new EC command.
+ *
+ * This problem is probably unique to the I2C bus.
+ *
+ * So for now, just read all the data anyway.
+ */
+
+ /* Try sending a version 3 packet */
+ dev->protocol_version = 3;
+ if (ec_command_inptr(dev, EC_CMD_HELLO, 0, &req, sizeof(req),
+ (uint8_t **)&resp, sizeof(*resp)) > 0) {
+ return 0;
+ }
+
+ /* Try sending a version 2 packet */
+ dev->protocol_version = 2;
+ if (ec_command_inptr(dev, EC_CMD_HELLO, 0, &req, sizeof(req),
+ (uint8_t **)&resp, sizeof(*resp)) > 0) {
+ return 0;
+ }
+
+ /*
+ * Fail if we're still here, since the EC doesn't understand any
+ * protcol version we speak. Version 1 interface without command
+ * version is no longer supported, and we don't know about any new
+ * protocol versions.
+ */
+ dev->protocol_version = 0;
+ printf("%s: ERROR: old EC interface not supported\n", __func__);
+ return -1;
+}
+
+int cros_ec_test(struct cros_ec_dev *dev)
+{
+ struct ec_params_hello req;
+ struct ec_response_hello *resp;
+
+ req.in_data = 0x12345678;
+ if (ec_command_inptr(dev, EC_CMD_HELLO, 0, &req, sizeof(req),
+ (uint8_t **)&resp, sizeof(*resp)) < sizeof(*resp)) {
+ printf("ec_command_inptr() returned error\n");
+ return -1;
+ }
+ if (resp->out_data != req.in_data + 0x01020304) {
+ printf("Received invalid handshake %x\n", resp->out_data);
+ return -1;
+ }
+
+ return 0;
+}
+
+int cros_ec_flash_offset(struct cros_ec_dev *dev, enum ec_flash_region region,
+ uint32_t *offset, uint32_t *size)
+{
+ struct ec_params_flash_region_info p;
+ struct ec_response_flash_region_info *r;
+ int ret;
+
+ p.region = region;
+ ret = ec_command_inptr(dev, EC_CMD_FLASH_REGION_INFO,
+ EC_VER_FLASH_REGION_INFO,
+ &p, sizeof(p), (uint8_t **)&r, sizeof(*r));
+ if (ret != sizeof(*r))
+ return -1;
+
+ if (offset)
+ *offset = r->offset;
+ if (size)
+ *size = r->size;
+
+ return 0;
+}
+
+int cros_ec_flash_erase(struct cros_ec_dev *dev, uint32_t offset, uint32_t size)
+{
+ struct ec_params_flash_erase p;
+
+ p.offset = offset;
+ p.size = size;
+ return ec_command_inptr(dev, EC_CMD_FLASH_ERASE, 0, &p, sizeof(p),
+ NULL, 0);
+}
+
+/**
+ * Write a single block to the flash
+ *
+ * Write a block of data to the EC flash. The size must not exceed the flash
+ * write block size which you can obtain from cros_ec_flash_write_burst_size().
+ *
+ * The offset starts at 0. You can obtain the region information from
+ * cros_ec_flash_offset() to find out where to write for a particular region.
+ *
+ * Attempting to write to the region where the EC is currently running from
+ * will result in an error.
+ *
+ * @param dev CROS-EC device
+ * @param data Pointer to data buffer to write
+ * @param offset Offset within flash to write to.
+ * @param size Number of bytes to write
+ * @return 0 if ok, -1 on error
+ */
+static int cros_ec_flash_write_block(struct cros_ec_dev *dev,
+ const uint8_t *data, uint32_t offset, uint32_t size)
+{
+ struct ec_params_flash_write p;
+
+ p.offset = offset;
+ p.size = size;
+ assert(data && p.size <= EC_FLASH_WRITE_VER0_SIZE);
+ memcpy(&p + 1, data, p.size);
+
+ return ec_command_inptr(dev, EC_CMD_FLASH_WRITE, 0,
+ &p, sizeof(p), NULL, 0) >= 0 ? 0 : -1;
+}
+
+/**
+ * Return optimal flash write burst size
+ */
+static int cros_ec_flash_write_burst_size(struct cros_ec_dev *dev)
+{
+ return EC_FLASH_WRITE_VER0_SIZE;
+}
+
+/**
+ * Check if a block of data is erased (all 0xff)
+ *
+ * This function is useful when dealing with flash, for checking whether a
+ * data block is erased and thus does not need to be programmed.
+ *
+ * @param data Pointer to data to check (must be word-aligned)
+ * @param size Number of bytes to check (must be word-aligned)
+ * @return 0 if erased, non-zero if any word is not erased
+ */
+static int cros_ec_data_is_erased(const uint32_t *data, int size)
+{
+ assert(!(size & 3));
+ size /= sizeof(uint32_t);
+ for (; size > 0; size -= 4, data++)
+ if (*data != -1U)
+ return 0;
+
+ return 1;
+}
+
+int cros_ec_flash_write(struct cros_ec_dev *dev, const uint8_t *data,
+ uint32_t offset, uint32_t size)
+{
+ uint32_t burst = cros_ec_flash_write_burst_size(dev);
+ uint32_t end, off;
+ int ret;
+
+ /*
+ * TODO: round up to the nearest multiple of write size. Can get away
+ * without that on link right now because its write size is 4 bytes.
+ */
+ end = offset + size;
+ for (off = offset; off < end; off += burst, data += burst) {
+ uint32_t todo;
+
+ /* If the data is empty, there is no point in programming it */
+ todo = min(end - off, burst);
+ if (dev->optimise_flash_write &&
+ cros_ec_data_is_erased((uint32_t *)data, todo))
+ continue;
+
+ ret = cros_ec_flash_write_block(dev, data, off, todo);
+ if (ret)
+ return ret;
+ }
+
+ return 0;
+}
+
+/**
+ * Read a single block from the flash
+ *
+ * Read a block of data from the EC flash. The size must not exceed the flash
+ * write block size which you can obtain from cros_ec_flash_write_burst_size().
+ *
+ * The offset starts at 0. You can obtain the region information from
+ * cros_ec_flash_offset() to find out where to read for a particular region.
+ *
+ * @param dev CROS-EC device
+ * @param data Pointer to data buffer to read into
+ * @param offset Offset within flash to read from
+ * @param size Number of bytes to read
+ * @return 0 if ok, -1 on error
+ */
+static int cros_ec_flash_read_block(struct cros_ec_dev *dev, uint8_t *data,
+ uint32_t offset, uint32_t size)
+{
+ struct ec_params_flash_read p;
+
+ p.offset = offset;
+ p.size = size;
+
+ return ec_command(dev, EC_CMD_FLASH_READ, 0,
+ &p, sizeof(p), data, size) >= 0 ? 0 : -1;
+}
+
+int cros_ec_flash_read(struct cros_ec_dev *dev, uint8_t *data, uint32_t offset,
+ uint32_t size)
+{
+ uint32_t burst = cros_ec_flash_write_burst_size(dev);
+ uint32_t end, off;
+ int ret;
+
+ end = offset + size;
+ for (off = offset; off < end; off += burst, data += burst) {
+ ret = cros_ec_flash_read_block(dev, data, off,
+ min(end - off, burst));
+ if (ret)
+ return ret;
+ }
+
+ return 0;
+}
+
+int cros_ec_flash_update_rw(struct cros_ec_dev *dev,
+ const uint8_t *image, int image_size)
+{
+ uint32_t rw_offset, rw_size;
+ int ret;
+
+ if (cros_ec_flash_offset(dev, EC_FLASH_REGION_RW, &rw_offset, &rw_size))
+ return -1;
+ if (image_size > (int)rw_size)
+ return -1;
+
+ /* Invalidate the existing hash, just in case the AP reboots
+ * unexpectedly during the update. If that happened, the EC RW firmware
+ * would be invalid, but the EC would still have the original hash.
+ */
+ ret = cros_ec_invalidate_hash(dev);
+ if (ret)
+ return ret;
+
+ /*
+ * Erase the entire RW section, so that the EC doesn't see any garbage
+ * past the new image if it's smaller than the current image.
+ *
+ * TODO: could optimize this to erase just the current image, since
+ * presumably everything past that is 0xff's. But would still need to
+ * round up to the nearest multiple of erase size.
+ */
+ ret = cros_ec_flash_erase(dev, rw_offset, rw_size);
+ if (ret)
+ return ret;
+
+ /* Write the image */
+ ret = cros_ec_flash_write(dev, image, rw_offset, image_size);
+ if (ret)
+ return ret;
+
+ return 0;
+}
+
+int cros_ec_read_vbnvcontext(struct cros_ec_dev *dev, uint8_t *block)
+{
+ struct ec_params_vbnvcontext p;
+ int len;
+
+ p.op = EC_VBNV_CONTEXT_OP_READ;
+
+ len = ec_command(dev, EC_CMD_VBNV_CONTEXT, EC_VER_VBNV_CONTEXT,
+ &p, sizeof(p), block, EC_VBNV_BLOCK_SIZE);
+ if (len < EC_VBNV_BLOCK_SIZE)
+ return -1;
+
+ return 0;
+}
+
+int cros_ec_write_vbnvcontext(struct cros_ec_dev *dev, const uint8_t *block)
+{
+ struct ec_params_vbnvcontext p;
+ int len;
+
+ p.op = EC_VBNV_CONTEXT_OP_WRITE;
+ memcpy(p.block, block, sizeof(p.block));
+
+ len = ec_command_inptr(dev, EC_CMD_VBNV_CONTEXT, EC_VER_VBNV_CONTEXT,
+ &p, sizeof(p), NULL, 0);
+ if (len < 0)
+ return -1;
+
+ return 0;
+}
+
+int cros_ec_set_ldo(struct cros_ec_dev *dev, uint8_t index, uint8_t state)
+{
+ struct ec_params_ldo_set params;
+
+ params.index = index;
+ params.state = state;
+
+ if (ec_command_inptr(dev, EC_CMD_LDO_SET, 0,
+ &params, sizeof(params),
+ NULL, 0))
+ return -1;
+
+ return 0;
+}
+
+int cros_ec_get_ldo(struct cros_ec_dev *dev, uint8_t index, uint8_t *state)
+{
+ struct ec_params_ldo_get params;
+ struct ec_response_ldo_get *resp;
+
+ params.index = index;
+
+ if (ec_command_inptr(dev, EC_CMD_LDO_GET, 0,
+ &params, sizeof(params),
+ (uint8_t **)&resp, sizeof(*resp)) != sizeof(*resp))
+ return -1;
+
+ *state = resp->state;
+
+ return 0;
+}
+
+/**
+ * Decode EC interface details from the device tree and allocate a suitable
+ * device.
+ *
+ * @param blob Device tree blob
+ * @param node Node to decode from
+ * @param devp Returns a pointer to the new allocated device
+ * @return 0 if ok, -1 on error
+ */
+static int cros_ec_decode_fdt(const void *blob, int node,
+ struct cros_ec_dev **devp)
+{
+ enum fdt_compat_id compat;
+ struct cros_ec_dev *dev;
+ int parent;
+
+ /* See what type of parent we are inside (this is expensive) */
+ parent = fdt_parent_offset(blob, node);
+ if (parent < 0) {
+ debug("%s: Cannot find node parent\n", __func__);
+ return -1;
+ }
+
+ dev = &static_dev;
+ dev->node = node;
+ dev->parent_node = parent;
+
+ compat = fdtdec_lookup(blob, parent);
+ switch (compat) {
+#ifdef CONFIG_CROS_EC_SPI
+ case COMPAT_SAMSUNG_EXYNOS_SPI:
+ dev->interface = CROS_EC_IF_SPI;
+ if (cros_ec_spi_decode_fdt(dev, blob))
+ return -1;
+ break;
+#endif
+#ifdef CONFIG_CROS_EC_I2C
+ case COMPAT_SAMSUNG_S3C2440_I2C:
+ dev->interface = CROS_EC_IF_I2C;
+ if (cros_ec_i2c_decode_fdt(dev, blob))
+ return -1;
+ break;
+#endif
+#ifdef CONFIG_CROS_EC_LPC
+ case COMPAT_INTEL_LPC:
+ dev->interface = CROS_EC_IF_LPC;
+ break;
+#endif
+#ifdef CONFIG_CROS_EC_SANDBOX
+ case COMPAT_SANDBOX_HOST_EMULATION:
+ dev->interface = CROS_EC_IF_SANDBOX;
+ break;
+#endif
+ default:
+ debug("%s: Unknown compat id %d\n", __func__, compat);
+ return -1;
+ }
+
+ fdtdec_decode_gpio(blob, node, "ec-interrupt", &dev->ec_int);
+ dev->optimise_flash_write = fdtdec_get_bool(blob, node,
+ "optimise-flash-write");
+ *devp = dev;
+
+ return 0;
+}
+
+int cros_ec_init(const void *blob, struct cros_ec_dev **cros_ecp)
+{
+ char id[MSG_BYTES];
+ struct cros_ec_dev *dev;
+ int node = 0;
+
+ *cros_ecp = NULL;
+ do {
+ node = fdtdec_next_compatible(blob, node,
+ COMPAT_GOOGLE_CROS_EC);
+ if (node < 0) {
+ debug("%s: Node not found\n", __func__);
+ return 0;
+ }
+ } while (!fdtdec_get_is_enabled(blob, node));
+
+ if (cros_ec_decode_fdt(blob, node, &dev)) {
+ debug("%s: Failed to decode device.\n", __func__);
+ return -CROS_EC_ERR_FDT_DECODE;
+ }
+
+ switch (dev->interface) {
+#ifdef CONFIG_CROS_EC_SPI
+ case CROS_EC_IF_SPI:
+ if (cros_ec_spi_init(dev, blob)) {
+ debug("%s: Could not setup SPI interface\n", __func__);
+ return -CROS_EC_ERR_DEV_INIT;
+ }
+ break;
+#endif
+#ifdef CONFIG_CROS_EC_I2C
+ case CROS_EC_IF_I2C:
+ if (cros_ec_i2c_init(dev, blob))
+ return -CROS_EC_ERR_DEV_INIT;
+ break;
+#endif
+#ifdef CONFIG_CROS_EC_LPC
+ case CROS_EC_IF_LPC:
+ if (cros_ec_lpc_init(dev, blob))
+ return -CROS_EC_ERR_DEV_INIT;
+ break;
+#endif
+#ifdef CONFIG_CROS_EC_SANDBOX
+ case CROS_EC_IF_SANDBOX:
+ if (cros_ec_sandbox_init(dev, blob))
+ return -CROS_EC_ERR_DEV_INIT;
+ break;
+#endif
+ case CROS_EC_IF_NONE:
+ default:
+ return 0;
+ }
+
+ /* we will poll the EC interrupt line */
+ fdtdec_setup_gpio(&dev->ec_int);
+ if (fdt_gpio_isvalid(&dev->ec_int))
+ gpio_direction_input(dev->ec_int.gpio);
+
+ if (cros_ec_check_version(dev)) {
+ debug("%s: Could not detect CROS-EC version\n", __func__);
+ return -CROS_EC_ERR_CHECK_VERSION;
+ }
+
+ if (cros_ec_read_id(dev, 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 */
+ last_dev = *cros_ecp = dev;
+ debug("Google Chrome EC CROS-EC driver ready, id '%s'\n", id);
+
+ return 0;
+}
+
+int cros_ec_decode_region(int argc, char * const argv[])
+{
+ if (argc > 0) {
+ if (0 == strcmp(*argv, "rw"))
+ return EC_FLASH_REGION_RW;
+ else if (0 == strcmp(*argv, "ro"))
+ return EC_FLASH_REGION_RO;
+
+ debug("%s: Invalid region '%s'\n", __func__, *argv);
+ } else {
+ debug("%s: Missing region parameter\n", __func__);
+ }
+
+ return -1;
+}
+
+int cros_ec_decode_ec_flash(const void *blob, 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;
+ }
+
+ 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_xfer(struct cros_ec_dev *dev, uchar chip, uint addr,
+ int alen, uchar *buffer, int len, int is_read)
+{
+ union {
+ struct ec_params_i2c_passthru p;
+ uint8_t outbuf[EC_PROTO2_MAX_PARAM_SIZE];
+ } params;
+ union {
+ struct ec_response_i2c_passthru r;
+ uint8_t inbuf[EC_PROTO2_MAX_PARAM_SIZE];
+ } response;
+ struct ec_params_i2c_passthru *p = &params.p;
+ struct ec_response_i2c_passthru *r = &response.r;
+ struct ec_params_i2c_passthru_msg *msg = p->msg;
+ uint8_t *pdata;
+ int read_len, write_len;
+ int size;
+ int rv;
+
+ p->port = 0;
+
+ if (alen != 1) {
+ printf("Unsupported address length %d\n", alen);
+ return -1;
+ }
+ if (is_read) {
+ read_len = len;
+ write_len = alen;
+ p->num_msgs = 2;
+ } else {
+ read_len = 0;
+ write_len = alen + len;
+ p->num_msgs = 1;
+ }
+
+ size = sizeof(*p) + p->num_msgs * sizeof(*msg);
+ if (size + write_len > sizeof(params)) {
+ puts("Params too large for buffer\n");
+ return -1;
+ }
+ if (sizeof(*r) + read_len > sizeof(response)) {
+ puts("Read length too big for buffer\n");
+ return -1;
+ }
+
+ /* Create a message to write the register address and optional data */
+ pdata = (uint8_t *)p + size;
+ msg->addr_flags = chip;
+ msg->len = write_len;
+ pdata[0] = addr;
+ if (!is_read)
+ memcpy(pdata + 1, buffer, len);
+ msg++;
+
+ if (read_len) {
+ msg->addr_flags = chip | EC_I2C_FLAG_READ;
+ msg->len = read_len;
+ }
+
+ rv = ec_command(dev, EC_CMD_I2C_PASSTHRU, 0, p, size + write_len,
+ r, sizeof(*r) + read_len);
+ if (rv < 0)
+ return rv;
+
+ /* Parse response */
+ if (r->i2c_status & EC_I2C_STATUS_ERROR) {
+ printf("Transfer failed with status=0x%x\n", r->i2c_status);
+ return -1;
+ }
+
+ if (rv < sizeof(*r) + read_len) {
+ puts("Truncated read response\n");
+ return -1;
+ }
+
+ if (read_len)
+ memcpy(buffer, r->data, read_len);
+
+ return 0;
+}
+
+#ifdef CONFIG_CMD_CROS_EC
+
+/**
+ * Perform a flash read or write command
+ *
+ * @param dev CROS-EC device to read/write
+ * @param is_write 1 do to a write, 0 to do a read
+ * @param argc Number of arguments
+ * @param argv Arguments (2 is region, 3 is address)
+ * @return 0 for ok, 1 for a usage error or -ve for ec command error
+ * (negative EC_RES_...)
+ */
+static int do_read_write(struct cros_ec_dev *dev, int is_write, int argc,
+ char * const argv[])
+{
+ uint32_t offset, size = -1U, region_size;
+ unsigned long addr;
+ char *endp;
+ int region;
+ int ret;
+
+ region = cros_ec_decode_region(argc - 2, argv + 2);
+ if (region == -1)
+ return 1;
+ if (argc < 4)
+ return 1;
+ addr = simple_strtoul(argv[3], &endp, 16);
+ if (*argv[3] == 0 || *endp != 0)
+ return 1;
+ if (argc > 4) {
+ size = simple_strtoul(argv[4], &endp, 16);
+ if (*argv[4] == 0 || *endp != 0)
+ return 1;
+ }
+
+ ret = cros_ec_flash_offset(dev, region, &offset, &region_size);
+ if (ret) {
+ debug("%s: Could not read region info\n", __func__);
+ return ret;
+ }
+ if (size == -1U)
+ size = region_size;
+
+ ret = is_write ?
+ cros_ec_flash_write(dev, (uint8_t *)addr, offset, size) :
+ cros_ec_flash_read(dev, (uint8_t *)addr, offset, size);
+ if (ret) {
+ debug("%s: Could not %s region\n", __func__,
+ is_write ? "write" : "read");
+ return ret;
+ }
+
+ return 0;
+}
+
+/**
+ * get_alen() - Small parser helper function to get address length
+ *
+ * Returns the address length.
+ */
+static uint get_alen(char *arg)
+{
+ int j;
+ int alen;
+
+ alen = 1;
+ for (j = 0; j < 8; j++) {
+ if (arg[j] == '.') {
+ alen = arg[j+1] - '0';
+ break;
+ } else if (arg[j] == '\0') {
+ break;
+ }
+ }
+ return alen;
+}
+
+#define DISP_LINE_LEN 16
+
+/*
+ * TODO(sjg@chromium.org): This code copied almost verbatim from cmd_i2c.c
+ * so we can remove it later.
+ */
+static int cros_ec_i2c_md(struct cros_ec_dev *dev, int flag, int argc,
+ char * const argv[])
+{
+ u_char chip;
+ uint addr, alen, length = 0x10;
+ int j, nbytes, linebytes;
+
+ if (argc < 2)
+ return CMD_RET_USAGE;
+
+ if (1 || (flag & CMD_FLAG_REPEAT) == 0) {
+ /*
+ * New command specified.
+ */
+
+ /*
+ * I2C chip address
+ */
+ chip = simple_strtoul(argv[0], NULL, 16);
+
+ /*
+ * I2C data address within the chip. This can be 1 or
+ * 2 bytes long. Some day it might be 3 bytes long :-).
+ */
+ addr = simple_strtoul(argv[1], NULL, 16);
+ alen = get_alen(argv[1]);
+ if (alen > 3)
+ return CMD_RET_USAGE;
+
+ /*
+ * If another parameter, it is the length to display.
+ * Length is the number of objects, not number of bytes.
+ */
+ if (argc > 2)
+ length = simple_strtoul(argv[2], NULL, 16);
+ }
+
+ /*
+ * Print the lines.
+ *
+ * We buffer all read data, so we can make sure data is read only
+ * once.
+ */
+ nbytes = length;
+ do {
+ unsigned char linebuf[DISP_LINE_LEN];
+ unsigned char *cp;
+
+ linebytes = (nbytes > DISP_LINE_LEN) ? DISP_LINE_LEN : nbytes;
+
+ if (cros_ec_i2c_xfer(dev, chip, addr, alen, linebuf, linebytes,
+ 1))
+ puts("Error reading the chip.\n");
+ else {
+ printf("%04x:", addr);
+ cp = linebuf;
+ for (j = 0; j < linebytes; j++) {
+ printf(" %02x", *cp++);
+ addr++;
+ }
+ puts(" ");
+ cp = linebuf;
+ for (j = 0; j < linebytes; j++) {
+ if ((*cp < 0x20) || (*cp > 0x7e))
+ puts(".");
+ else
+ printf("%c", *cp);
+ cp++;
+ }
+ putc('\n');
+ }
+ nbytes -= linebytes;
+ } while (nbytes > 0);
+
+ return 0;
+}
+
+static int cros_ec_i2c_mw(struct cros_ec_dev *dev, int flag, int argc,
+ char * const argv[])
+{
+ uchar chip;
+ ulong addr;
+ uint alen;
+ uchar byte;
+ int count;
+
+ if ((argc < 3) || (argc > 4))
+ return CMD_RET_USAGE;
+
+ /*
+ * Chip is always specified.
+ */
+ chip = simple_strtoul(argv[0], NULL, 16);
+
+ /*
+ * Address is always specified.
+ */
+ addr = simple_strtoul(argv[1], NULL, 16);
+ alen = get_alen(argv[1]);
+ if (alen > 3)
+ return CMD_RET_USAGE;
+
+ /*
+ * Value to write is always specified.
+ */
+ byte = simple_strtoul(argv[2], NULL, 16);
+
+ /*
+ * Optional count
+ */
+ if (argc == 4)
+ count = simple_strtoul(argv[3], NULL, 16);
+ else
+ count = 1;
+
+ while (count-- > 0) {
+ if (cros_ec_i2c_xfer(dev, chip, addr++, alen, &byte, 1, 0))
+ puts("Error writing the chip.\n");
+ /*
+ * Wait for the write to complete. The write can take
+ * up to 10mSec (we allow a little more time).
+ */
+/*
+ * No write delay with FRAM devices.
+ */
+#if !defined(CONFIG_SYS_I2C_FRAM)
+ udelay(11000);
+#endif
+ }
+
+ return 0;
+}
+
+/* Temporary code until we have driver model and can use the i2c command */
+static int cros_ec_i2c_passthrough(struct cros_ec_dev *dev, int flag,
+ int argc, char * const argv[])
+{
+ const char *cmd;
+
+ if (argc < 1)
+ return CMD_RET_USAGE;
+ cmd = *argv++;
+ argc--;
+ if (0 == strcmp("md", cmd))
+ cros_ec_i2c_md(dev, flag, argc, argv);
+ else if (0 == strcmp("mw", cmd))
+ cros_ec_i2c_mw(dev, flag, argc, argv);
+ else
+ return CMD_RET_USAGE;
+
+ return 0;
+}
+
+static int do_cros_ec(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])
+{
+ struct cros_ec_dev *dev = last_dev;
+ const char *cmd;
+ int ret = 0;
+
+ if (argc < 2)
+ return CMD_RET_USAGE;
+
+ cmd = argv[1];
+ if (0 == strcmp("init", cmd)) {
+ ret = cros_ec_init(gd->fdt_blob, &dev);
+ if (ret) {
+ printf("Could not init cros_ec device (err %d)\n", ret);
+ return 1;
+ }
+ return 0;
+ }
+
+ /* Just use the last allocated device; there should be only one */
+ if (!last_dev) {
+ printf("No CROS-EC device available\n");
+ return 1;
+ }
+ if (0 == strcmp("id", cmd)) {
+ char id[MSG_BYTES];
+
+ if (cros_ec_read_id(dev, id, sizeof(id))) {
+ debug("%s: Could not read KBC ID\n", __func__);
+ return 1;
+ }
+ printf("%s\n", id);
+ } else if (0 == strcmp("info", cmd)) {
+ struct ec_response_mkbp_info info;
+
+ if (cros_ec_info(dev, &info)) {
+ debug("%s: Could not read KBC info\n", __func__);
+ return 1;
+ }
+ printf("rows = %u\n", info.rows);
+ printf("cols = %u\n", info.cols);
+ printf("switches = %#x\n", info.switches);
+ } else if (0 == strcmp("curimage", cmd)) {
+ enum ec_current_image image;
+
+ if (cros_ec_read_current_image(dev, &image)) {
+ debug("%s: Could not read KBC image\n", __func__);
+ return 1;
+ }
+ printf("%d\n", image);
+ } else if (0 == strcmp("hash", cmd)) {
+ struct ec_response_vboot_hash hash;
+ int i;
+
+ if (cros_ec_read_hash(dev, &hash)) {
+ debug("%s: Could not read KBC hash\n", __func__);
+ return 1;
+ }
+
+ if (hash.hash_type == EC_VBOOT_HASH_TYPE_SHA256)
+ printf("type: SHA-256\n");
+ else
+ printf("type: %d\n", hash.hash_type);
+
+ printf("offset: 0x%08x\n", hash.offset);
+ printf("size: 0x%08x\n", hash.size);
+
+ printf("digest: ");
+ for (i = 0; i < hash.digest_size; i++)
+ printf("%02x", hash.hash_digest[i]);
+ printf("\n");
+ } else if (0 == strcmp("reboot", cmd)) {
+ int region;
+ enum ec_reboot_cmd cmd;
+
+ if (argc >= 3 && !strcmp(argv[2], "cold"))
+ cmd = EC_REBOOT_COLD;
+ else {
+ region = cros_ec_decode_region(argc - 2, argv + 2);
+ if (region == EC_FLASH_REGION_RO)
+ cmd = EC_REBOOT_JUMP_RO;
+ else if (region == EC_FLASH_REGION_RW)
+ cmd = EC_REBOOT_JUMP_RW;
+ else
+ return CMD_RET_USAGE;
+ }
+
+ if (cros_ec_reboot(dev, cmd, 0)) {
+ debug("%s: Could not reboot KBC\n", __func__);
+ return 1;
+ }
+ } else if (0 == strcmp("events", cmd)) {
+ uint32_t events;
+
+ if (cros_ec_get_host_events(dev, &events)) {
+ debug("%s: Could not read host events\n", __func__);
+ return 1;
+ }
+ printf("0x%08x\n", events);
+ } else if (0 == strcmp("clrevents", cmd)) {
+ uint32_t events = 0x7fffffff;
+
+ if (argc >= 3)
+ events = simple_strtol(argv[2], NULL, 0);
+
+ if (cros_ec_clear_host_events(dev, events)) {
+ debug("%s: Could not clear host events\n", __func__);
+ return 1;
+ }
+ } else if (0 == strcmp("read", cmd)) {
+ ret = do_read_write(dev, 0, argc, argv);
+ if (ret > 0)
+ return CMD_RET_USAGE;
+ } else if (0 == strcmp("write", cmd)) {
+ ret = do_read_write(dev, 1, argc, argv);
+ if (ret > 0)
+ return CMD_RET_USAGE;
+ } else if (0 == strcmp("erase", cmd)) {
+ int region = cros_ec_decode_region(argc - 2, argv + 2);
+ uint32_t offset, size;
+
+ if (region == -1)
+ return CMD_RET_USAGE;
+ if (cros_ec_flash_offset(dev, region, &offset, &size)) {
+ debug("%s: Could not read region info\n", __func__);
+ ret = -1;
+ } else {
+ ret = cros_ec_flash_erase(dev, offset, size);
+ if (ret) {
+ debug("%s: Could not erase region\n",
+ __func__);
+ }
+ }
+ } else if (0 == strcmp("regioninfo", cmd)) {
+ int region = cros_ec_decode_region(argc - 2, argv + 2);
+ uint32_t offset, size;
+
+ if (region == -1)
+ return CMD_RET_USAGE;
+ ret = cros_ec_flash_offset(dev, region, &offset, &size);
+ if (ret) {
+ debug("%s: Could not read region info\n", __func__);
+ } else {
+ printf("Region: %s\n", region == EC_FLASH_REGION_RO ?
+ "RO" : "RW");
+ printf("Offset: %x\n", offset);
+ printf("Size: %x\n", size);
+ }
+ } else if (0 == strcmp("vbnvcontext", cmd)) {
+ uint8_t block[EC_VBNV_BLOCK_SIZE];
+ char buf[3];
+ int i, len;
+ unsigned long result;
+
+ if (argc <= 2) {
+ ret = cros_ec_read_vbnvcontext(dev, block);
+ if (!ret) {
+ printf("vbnv_block: ");
+ for (i = 0; i < EC_VBNV_BLOCK_SIZE; i++)
+ printf("%02x", block[i]);
+ putc('\n');
+ }
+ } else {
+ /*
+ * TODO(clchiou): Move this to a utility function as
+ * cmd_spi might want to call it.
+ */
+ memset(block, 0, EC_VBNV_BLOCK_SIZE);
+ len = strlen(argv[2]);
+ buf[2] = '\0';
+ for (i = 0; i < EC_VBNV_BLOCK_SIZE; i++) {
+ if (i * 2 >= len)
+ break;
+ buf[0] = argv[2][i * 2];
+ if (i * 2 + 1 >= len)
+ buf[1] = '0';
+ else
+ buf[1] = argv[2][i * 2 + 1];
+ strict_strtoul(buf, 16, &result);
+ block[i] = result;
+ }
+ ret = cros_ec_write_vbnvcontext(dev, block);
+ }
+ if (ret) {
+ debug("%s: Could not %s VbNvContext\n", __func__,
+ argc <= 2 ? "read" : "write");
+ }
+ } else if (0 == strcmp("test", cmd)) {
+ int result = cros_ec_test(dev);
+
+ if (result)
+ printf("Test failed with error %d\n", result);
+ else
+ puts("Test passed\n");
+ } else if (0 == strcmp("version", cmd)) {
+ struct ec_response_get_version *p;
+ char *build_string;
+
+ ret = cros_ec_read_version(dev, &p);
+ if (!ret) {
+ /* Print versions */
+ printf("RO version: %1.*s\n",
+ (int)sizeof(p->version_string_ro),
+ p->version_string_ro);
+ printf("RW version: %1.*s\n",
+ (int)sizeof(p->version_string_rw),
+ p->version_string_rw);
+ printf("Firmware copy: %s\n",
+ (p->current_image <
+ ARRAY_SIZE(ec_current_image_name) ?
+ ec_current_image_name[p->current_image] :
+ "?"));
+ ret = cros_ec_read_build_info(dev, &build_string);
+ if (!ret)
+ printf("Build info: %s\n", build_string);
+ }
+ } else if (0 == strcmp("ldo", cmd)) {
+ uint8_t index, state;
+ char *endp;
+
+ if (argc < 3)
+ return CMD_RET_USAGE;
+ index = simple_strtoul(argv[2], &endp, 10);
+ if (*argv[2] == 0 || *endp != 0)
+ return CMD_RET_USAGE;
+ if (argc > 3) {
+ state = simple_strtoul(argv[3], &endp, 10);
+ if (*argv[3] == 0 || *endp != 0)
+ return CMD_RET_USAGE;
+ ret = cros_ec_set_ldo(dev, index, state);
+ } else {
+ ret = cros_ec_get_ldo(dev, index, &state);
+ if (!ret) {
+ printf("LDO%d: %s\n", index,
+ state == EC_LDO_STATE_ON ?
+ "on" : "off");
+ }
+ }
+
+ if (ret) {
+ debug("%s: Could not access LDO%d\n", __func__, index);
+ return ret;
+ }
+ } else if (0 == strcmp("i2c", cmd)) {
+ ret = cros_ec_i2c_passthrough(dev, flag, argc - 2, argv + 2);
+ } else {
+ return CMD_RET_USAGE;
+ }
+
+ if (ret < 0) {
+ printf("Error: CROS-EC command failed (error %d)\n", ret);
+ ret = 1;
+ }
+
+ return ret;
+}
+
+U_BOOT_CMD(
+ crosec, 6, 1, do_cros_ec,
+ "CROS-EC utility command",
+ "init Re-init CROS-EC (done on startup automatically)\n"
+ "crosec id Read CROS-EC ID\n"
+ "crosec info Read CROS-EC info\n"
+ "crosec curimage Read CROS-EC current image\n"
+ "crosec hash Read CROS-EC hash\n"
+ "crosec reboot [rw | ro | cold] Reboot CROS-EC\n"
+ "crosec events Read CROS-EC host events\n"
+ "crosec clrevents [mask] Clear CROS-EC host events\n"
+ "crosec regioninfo <ro|rw> Read image info\n"
+ "crosec erase <ro|rw> Erase EC image\n"
+ "crosec read <ro|rw> <addr> [<size>] Read EC image\n"
+ "crosec write <ro|rw> <addr> [<size>] Write EC image\n"
+ "crosec vbnvcontext [hexstring] Read [write] VbNvContext from EC\n"
+ "crosec ldo <idx> [<state>] Switch/Read LDO state\n"
+ "crosec test run tests on cros_ec\n"
+ "crosec version Read CROS-EC version\n"
+ "crosec i2c md chip address[.0, .1, .2] [# of objects] - read from I2C passthru\n"
+ "crosec i2c mw chip address[.0, .1, .2] value [count] - write to I2C passthru (fill)"
+);
+#endif
diff --git a/qemu/roms/u-boot/drivers/misc/cros_ec_i2c.c b/qemu/roms/u-boot/drivers/misc/cros_ec_i2c.c
new file mode 100644
index 000000000..513cdb1cb
--- /dev/null
+++ b/qemu/roms/u-boot/drivers/misc/cros_ec_i2c.c
@@ -0,0 +1,176 @@
+/*
+ * Chromium OS cros_ec driver - I2C interface
+ *
+ * Copyright (c) 2012 The Chromium OS Authors.
+ *
+ * SPDX-License-Identifier: GPL-2.0+
+ */
+
+/*
+ * The Matrix Keyboard Protocol driver handles talking to the keyboard
+ * controller chip. Mostly this is for keyboard functions, but some other
+ * things have slipped in, so we provide generic services to talk to the
+ * KBC.
+ */
+
+#include <common.h>
+#include <i2c.h>
+#include <cros_ec.h>
+
+#ifdef DEBUG_TRACE
+#define debug_trace(fmt, b...) debug(fmt, #b)
+#else
+#define debug_trace(fmt, b...)
+#endif
+
+int cros_ec_i2c_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)
+{
+ int old_bus = 0;
+ /* version8, cmd8, arglen8, out8[dout_len], csum8 */
+ int out_bytes = dout_len + 4;
+ /* response8, arglen8, in8[din_len], checksum8 */
+ int in_bytes = din_len + 3;
+ uint8_t *ptr;
+ /* Receive input data, so that args will be dword aligned */
+ uint8_t *in_ptr;
+ int len, csum, ret;
+
+ old_bus = i2c_get_bus_num();
+
+ /*
+ * Sanity-check I/O sizes given transaction overhead in internal
+ * buffers.
+ */
+ if (out_bytes > sizeof(dev->dout)) {
+ debug("%s: Cannot send %d bytes\n", __func__, dout_len);
+ return -1;
+ }
+ if (in_bytes > sizeof(dev->din)) {
+ debug("%s: Cannot receive %d bytes\n", __func__, din_len);
+ return -1;
+ }
+ assert(dout_len >= 0);
+ assert(dinp);
+
+ /*
+ * Copy command and data into output buffer so we can do a single I2C
+ * burst transaction.
+ */
+ ptr = dev->dout;
+
+ /*
+ * in_ptr starts of pointing to a dword-aligned input data buffer.
+ * We decrement it back by the number of header bytes we expect to
+ * receive, so that the first parameter of the resulting input data
+ * will be dword aligned.
+ */
+ in_ptr = dev->din + sizeof(int64_t);
+
+ if (dev->protocol_version != 2) {
+ /* Something we don't support */
+ debug("%s: Protocol version %d unsupported\n",
+ __func__, dev->protocol_version);
+ return -1;
+ }
+
+ *ptr++ = EC_CMD_VERSION0 + cmd_version;
+ *ptr++ = cmd;
+ *ptr++ = dout_len;
+ in_ptr -= 2; /* Expect status, length bytes */
+
+ memcpy(ptr, dout, dout_len);
+ ptr += dout_len;
+
+ *ptr++ = (uint8_t)
+ cros_ec_calc_checksum(dev->dout, dout_len + 3);
+
+ /* Set to the proper i2c bus */
+ if (i2c_set_bus_num(dev->bus_num)) {
+ debug("%s: Cannot change to I2C bus %d\n", __func__,
+ dev->bus_num);
+ return -1;
+ }
+
+ /* Send output data */
+ cros_ec_dump_data("out", -1, dev->dout, out_bytes);
+ ret = i2c_write(dev->addr, 0, 0, dev->dout, out_bytes);
+ if (ret) {
+ debug("%s: Cannot complete I2C write to 0x%x\n",
+ __func__, dev->addr);
+ ret = -1;
+ }
+
+ if (!ret) {
+ ret = i2c_read(dev->addr, 0, 0, in_ptr, in_bytes);
+ if (ret) {
+ debug("%s: Cannot complete I2C read from 0x%x\n",
+ __func__, dev->addr);
+ ret = -1;
+ }
+ }
+
+ /* Return to original bus number */
+ i2c_set_bus_num(old_bus);
+ if (ret)
+ return ret;
+
+ if (*in_ptr != EC_RES_SUCCESS) {
+ debug("%s: Received bad result code %d\n", __func__, *in_ptr);
+ return -(int)*in_ptr;
+ }
+
+ len = in_ptr[1];
+ if (len + 3 > sizeof(dev->din)) {
+ debug("%s: Received length %#02x too large\n",
+ __func__, len);
+ return -1;
+ }
+ csum = cros_ec_calc_checksum(in_ptr, 2 + len);
+ if (csum != in_ptr[2 + len]) {
+ debug("%s: Invalid checksum rx %#02x, calced %#02x\n",
+ __func__, in_ptr[2 + din_len], csum);
+ return -1;
+ }
+ din_len = min(din_len, len);
+ cros_ec_dump_data("in", -1, in_ptr, din_len + 3);
+
+ /* Return pointer to dword-aligned input data, if any */
+ *dinp = dev->din + sizeof(int64_t);
+
+ return din_len;
+}
+
+int cros_ec_i2c_decode_fdt(struct cros_ec_dev *dev, const void *blob)
+{
+ /* Decode interface-specific FDT params */
+ dev->max_frequency = fdtdec_get_int(blob, dev->node,
+ "i2c-max-frequency", 100000);
+ dev->bus_num = i2c_get_bus_num_fdt(dev->parent_node);
+ if (dev->bus_num == -1) {
+ debug("%s: Failed to read bus number\n", __func__);
+ return -1;
+ }
+ dev->addr = fdtdec_get_int(blob, dev->node, "reg", -1);
+ if (dev->addr == -1) {
+ debug("%s: Failed to read device address\n", __func__);
+ return -1;
+ }
+
+ return 0;
+}
+
+/**
+ * Initialize I2C protocol.
+ *
+ * @param dev CROS_EC device
+ * @param blob Device tree blob
+ * @return 0 if ok, -1 on error
+ */
+int cros_ec_i2c_init(struct cros_ec_dev *dev, const void *blob)
+{
+ i2c_init(dev->max_frequency, dev->addr);
+
+ return 0;
+}
diff --git a/qemu/roms/u-boot/drivers/misc/cros_ec_lpc.c b/qemu/roms/u-boot/drivers/misc/cros_ec_lpc.c
new file mode 100644
index 000000000..0e02671c9
--- /dev/null
+++ b/qemu/roms/u-boot/drivers/misc/cros_ec_lpc.c
@@ -0,0 +1,194 @@
+/*
+ * Chromium OS cros_ec driver - LPC interface
+ *
+ * Copyright (c) 2012 The Chromium OS Authors.
+ *
+ * SPDX-License-Identifier: GPL-2.0+
+ */
+
+/*
+ * The Matrix Keyboard Protocol driver handles talking to the keyboard
+ * controller chip. Mostly this is for keyboard functions, but some other
+ * things have slipped in, so we provide generic services to talk to the
+ * KBC.
+ */
+
+#include <common.h>
+#include <command.h>
+#include <cros_ec.h>
+#include <asm/io.h>
+
+#ifdef DEBUG_TRACE
+#define debug_trace(fmt, b...) debug(fmt, ##b)
+#else
+#define debug_trace(fmt, b...)
+#endif
+
+static int wait_for_sync(struct cros_ec_dev *dev)
+{
+ unsigned long start;
+
+ start = get_timer(0);
+ while (inb(EC_LPC_ADDR_HOST_CMD) & EC_LPC_STATUS_BUSY_MASK) {
+ if (get_timer(start) > 1000) {
+ debug("%s: Timeout waiting for CROS_EC sync\n",
+ __func__);
+ return -1;
+ }
+ }
+
+ return 0;
+}
+
+int cros_ec_lpc_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)
+{
+ const int cmd_addr = EC_LPC_ADDR_HOST_CMD;
+ const int data_addr = EC_LPC_ADDR_HOST_DATA;
+ const int args_addr = EC_LPC_ADDR_HOST_ARGS;
+ const int param_addr = EC_LPC_ADDR_HOST_PARAM;
+
+ struct ec_lpc_host_args args;
+ uint8_t *d;
+ int csum;
+ int i;
+
+ if (dout_len > EC_HOST_PARAM_SIZE) {
+ debug("%s: Cannot send %d bytes\n", __func__, dout_len);
+ return -1;
+ }
+
+ /* Fill in args */
+ args.flags = EC_HOST_ARGS_FLAG_FROM_HOST;
+ args.command_version = cmd_version;
+ args.data_size = dout_len;
+
+ /* Calculate checksum */
+ csum = cmd + args.flags + args.command_version + args.data_size;
+ for (i = 0, d = (uint8_t *)dout; i < dout_len; i++, d++)
+ csum += *d;
+
+ args.checksum = (uint8_t)csum;
+
+ if (wait_for_sync(dev)) {
+ debug("%s: Timeout waiting ready\n", __func__);
+ return -1;
+ }
+
+ /* Write args */
+ for (i = 0, d = (uint8_t *)&args; i < sizeof(args); i++, d++)
+ outb(*d, args_addr + i);
+
+ /* Write data, if any */
+ debug_trace("cmd: %02x, ver: %02x", cmd, cmd_version);
+ for (i = 0, d = (uint8_t *)dout; i < dout_len; i++, d++) {
+ outb(*d, param_addr + i);
+ debug_trace("%02x ", *d);
+ }
+
+ outb(cmd, cmd_addr);
+ debug_trace("\n");
+
+ if (wait_for_sync(dev)) {
+ debug("%s: Timeout waiting for response\n", __func__);
+ return -1;
+ }
+
+ /* Check result */
+ i = inb(data_addr);
+ if (i) {
+ debug("%s: CROS_EC result code %d\n", __func__, i);
+ return -i;
+ }
+
+ /* Read back args */
+ for (i = 0, d = (uint8_t *)&args; i < sizeof(args); i++, d++)
+ *d = inb(args_addr + i);
+
+ /*
+ * If EC didn't modify args flags, then somehow we sent a new-style
+ * command to an old EC, which means it would have read its params
+ * from the wrong place.
+ */
+ if (!(args.flags & EC_HOST_ARGS_FLAG_TO_HOST)) {
+ debug("%s: CROS_EC protocol mismatch\n", __func__);
+ return -EC_RES_INVALID_RESPONSE;
+ }
+
+ if (args.data_size > din_len) {
+ debug("%s: CROS_EC returned too much data %d > %d\n",
+ __func__, args.data_size, din_len);
+ return -EC_RES_INVALID_RESPONSE;
+ }
+
+ /* Read data, if any */
+ for (i = 0, d = (uint8_t *)dev->din; i < args.data_size; i++, d++) {
+ *d = inb(param_addr + i);
+ debug_trace("%02x ", *d);
+ }
+ debug_trace("\n");
+
+ /* Verify checksum */
+ csum = cmd + args.flags + args.command_version + args.data_size;
+ for (i = 0, d = (uint8_t *)dev->din; i < args.data_size; i++, d++)
+ csum += *d;
+
+ if (args.checksum != (uint8_t)csum) {
+ debug("%s: CROS_EC response has invalid checksum\n", __func__);
+ return -EC_RES_INVALID_CHECKSUM;
+ }
+ *dinp = dev->din;
+
+ /* Return actual amount of data received */
+ return args.data_size;
+}
+
+/**
+ * Initialize LPC protocol.
+ *
+ * @param dev CROS_EC device
+ * @param blob Device tree blob
+ * @return 0 if ok, -1 on error
+ */
+int cros_ec_lpc_init(struct cros_ec_dev *dev, const void *blob)
+{
+ int byte, i;
+
+ /* See if we can find an EC at the other end */
+ 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++)
+ byte &= inb(EC_LPC_ADDR_HOST_PARAM + i);
+ if (byte == 0xff) {
+ debug("%s: CROS_EC device not found on LPC bus\n",
+ __func__);
+ return -1;
+ }
+
+ return 0;
+}
+
+/*
+ * Test if LPC command args are supported.
+ *
+ * The cheapest way to do this is by looking for the memory-mapped
+ * flag. This is faster than sending a new-style 'hello' command and
+ * seeing whether the EC sets the EC_HOST_ARGS_FLAG_FROM_HOST flag
+ * in args when it responds.
+ */
+int cros_ec_lpc_check_version(struct cros_ec_dev *dev)
+{
+ if (inb(EC_LPC_ADDR_MEMMAP + EC_MEMMAP_ID) == 'E' &&
+ inb(EC_LPC_ADDR_MEMMAP + EC_MEMMAP_ID + 1)
+ == 'C' &&
+ (inb(EC_LPC_ADDR_MEMMAP +
+ EC_MEMMAP_HOST_CMD_FLAGS) &
+ EC_HOST_CMD_FLAG_LPC_ARGS_SUPPORTED)) {
+ return 0;
+ }
+
+ printf("%s: ERROR: old EC interface not supported\n", __func__);
+ return -1;
+}
diff --git a/qemu/roms/u-boot/drivers/misc/cros_ec_sandbox.c b/qemu/roms/u-boot/drivers/misc/cros_ec_sandbox.c
new file mode 100644
index 000000000..4bb1d60e5
--- /dev/null
+++ b/qemu/roms/u-boot/drivers/misc/cros_ec_sandbox.c
@@ -0,0 +1,559 @@
+/*
+ * Chromium OS cros_ec driver - sandbox emulation
+ *
+ * Copyright (c) 2013 The Chromium OS Authors.
+ *
+ * SPDX-License-Identifier: GPL-2.0+
+ */
+
+#include <common.h>
+#include <cros_ec.h>
+#include <ec_commands.h>
+#include <errno.h>
+#include <hash.h>
+#include <malloc.h>
+#include <os.h>
+#include <sha256.h>
+#include <spi.h>
+#include <asm/state.h>
+#include <asm/sdl.h>
+#include <linux/input.h>
+
+/*
+ * Ultimately it shold be possible to connect an Chrome OS EC emulation
+ * to U-Boot and remove all of this code. But this provides a test
+ * environment for bringing up chromeos_sandbox and demonstrating its
+ * utility.
+ *
+ * This emulation includes the following:
+ *
+ * 1. Emulation of the keyboard, by converting keypresses received from SDL
+ * into key scan data, passed back from the EC as key scan messages. The
+ * key layout is read from the device tree.
+ *
+ * 2. Emulation of vboot context - so this can be read/written as required.
+ *
+ * 3. Save/restore of EC state, so that the vboot context, flash memory
+ * contents and current image can be preserved across boots. This is important
+ * since the EC is supposed to continue running even if the AP resets.
+ *
+ * 4. Some event support, in particular allowing Escape to be pressed on boot
+ * to enter recovery mode. The EC passes this to U-Boot through the normal
+ * event message.
+ *
+ * 5. Flash read/write/erase support, so that software sync works. The
+ * protect messages are supported but no protection is implemented.
+ *
+ * 6. Hashing of the EC image, again to support software sync.
+ *
+ * Other features can be added, although a better path is probably to link
+ * the EC image in with U-Boot (Vic has demonstrated a prototype for this).
+ */
+
+DECLARE_GLOBAL_DATA_PTR;
+
+#define KEYBOARD_ROWS 8
+#define KEYBOARD_COLS 13
+
+/* A single entry of the key matrix */
+struct ec_keymatrix_entry {
+ int row; /* key matrix row */
+ int col; /* key matrix column */
+ int keycode; /* corresponding linux key code */
+};
+
+/**
+ * struct ec_state - Information about the EC state
+ *
+ * @vbnv_context: Vboot context data stored by EC
+ * @ec_config: FDT config information about the EC (e.g. flashmap)
+ * @flash_data: Contents of flash memory
+ * @flash_data_len: Size of flash memory
+ * @current_image: Current image the EC is running
+ * @matrix_count: Number of keys to decode in matrix
+ * @matrix: Information about keyboard matrix
+ * @keyscan: Current keyscan information (bit set for each row/column pressed)
+ * @recovery_req: Keyboard recovery requested
+ */
+struct ec_state {
+ uint8_t vbnv_context[EC_VBNV_BLOCK_SIZE];
+ struct fdt_cros_ec ec_config;
+ uint8_t *flash_data;
+ int flash_data_len;
+ enum ec_current_image current_image;
+ int matrix_count;
+ struct ec_keymatrix_entry *matrix; /* the key matrix info */
+ uint8_t keyscan[KEYBOARD_COLS];
+ bool recovery_req;
+} s_state, *state;
+
+/**
+ * cros_ec_read_state() - read the sandbox EC state from the state file
+ *
+ * If data is available, then blob and node will provide access to it. If
+ * not this function sets up an empty EC.
+ *
+ * @param blob: Pointer to device tree blob, or NULL if no data to read
+ * @param node: Node offset to read from
+ */
+static int cros_ec_read_state(const void *blob, int node)
+{
+ struct ec_state *ec = &s_state;
+ const char *prop;
+ int len;
+
+ /* Set everything to defaults */
+ ec->current_image = EC_IMAGE_RO;
+ if (!blob)
+ return 0;
+
+ /* Read the data if available */
+ ec->current_image = fdtdec_get_int(blob, node, "current-image",
+ EC_IMAGE_RO);
+ prop = fdt_getprop(blob, node, "vbnv-context", &len);
+ if (prop && len == sizeof(ec->vbnv_context))
+ memcpy(ec->vbnv_context, prop, len);
+
+ prop = fdt_getprop(blob, node, "flash-data", &len);
+ if (prop) {
+ ec->flash_data_len = len;
+ ec->flash_data = os_malloc(len);
+ if (!ec->flash_data)
+ return -ENOMEM;
+ memcpy(ec->flash_data, prop, len);
+ debug("%s: Loaded EC flash data size %#x\n", __func__, len);
+ }
+
+ return 0;
+}
+
+/**
+ * cros_ec_write_state() - Write out our state to the state file
+ *
+ * The caller will ensure that there is a node ready for the state. The node
+ * may already contain the old state, in which case it is overridden.
+ *
+ * @param blob: Device tree blob holding state
+ * @param node: Node to write our state into
+ */
+static int cros_ec_write_state(void *blob, int node)
+{
+ struct ec_state *ec = &s_state;
+
+ /* We are guaranteed enough space to write basic properties */
+ fdt_setprop_u32(blob, node, "current-image", ec->current_image);
+ fdt_setprop(blob, node, "vbnv-context", ec->vbnv_context,
+ sizeof(ec->vbnv_context));
+ return state_setprop(node, "flash-data", ec->flash_data,
+ ec->ec_config.flash.length);
+}
+
+SANDBOX_STATE_IO(cros_ec, "google,cros-ec", cros_ec_read_state,
+ cros_ec_write_state);
+
+/**
+ * Return the number of bytes used in the specified image.
+ *
+ * This is the actual size of code+data in the image, as opposed to the
+ * amount of space reserved in flash for that image. This code is similar to
+ * that used by the real EC code base.
+ *
+ * @param ec Current emulated EC state
+ * @param entry Flash map entry containing the image to check
+ * @return actual image size in bytes, 0 if the image contains no content or
+ * error.
+ */
+static int get_image_used(struct ec_state *ec, struct fmap_entry *entry)
+{
+ int size;
+
+ /*
+ * Scan backwards looking for 0xea byte, which is by definition the
+ * last byte of the image. See ec.lds.S for how this is inserted at
+ * the end of the image.
+ */
+ for (size = entry->length - 1;
+ size > 0 && ec->flash_data[entry->offset + size] != 0xea;
+ size--)
+ ;
+
+ return size ? size + 1 : 0; /* 0xea byte IS part of the image */
+}
+
+/**
+ * Read the key matrix from the device tree
+ *
+ * Keymap entries in the fdt take the form of 0xRRCCKKKK where
+ * RR=Row CC=Column KKKK=Key Code
+ *
+ * @param ec Current emulated EC state
+ * @param blob Device tree blob containing keyscan information
+ * @param node Keyboard node of device tree containing keyscan information
+ * @return 0 if ok, -1 on error
+ */
+static int keyscan_read_fdt_matrix(struct ec_state *ec, const void *blob,
+ int node)
+{
+ const u32 *cell;
+ int upto;
+ int len;
+
+ cell = fdt_getprop(blob, node, "linux,keymap", &len);
+ ec->matrix_count = len / 4;
+ ec->matrix = calloc(ec->matrix_count, sizeof(*ec->matrix));
+ if (!ec->matrix) {
+ debug("%s: Out of memory for key matrix\n", __func__);
+ return -1;
+ }
+
+ /* Now read the data */
+ for (upto = 0; upto < ec->matrix_count; upto++) {
+ struct ec_keymatrix_entry *matrix = &ec->matrix[upto];
+ u32 word;
+
+ word = fdt32_to_cpu(*cell++);
+ matrix->row = word >> 24;
+ matrix->col = (word >> 16) & 0xff;
+ matrix->keycode = word & 0xffff;
+
+ /* Hard-code some sanity limits for now */
+ if (matrix->row >= KEYBOARD_ROWS ||
+ matrix->col >= KEYBOARD_COLS) {
+ debug("%s: Matrix pos out of range (%d,%d)\n",
+ __func__, matrix->row, matrix->col);
+ return -1;
+ }
+ }
+
+ if (upto != ec->matrix_count) {
+ debug("%s: Read mismatch from key matrix\n", __func__);
+ return -1;
+ }
+
+ return 0;
+}
+
+/**
+ * Return the next keyscan message contents
+ *
+ * @param ec Current emulated EC state
+ * @param scan Place to put keyscan bytes for the keyscan message (must hold
+ * enough space for a full keyscan)
+ * @return number of bytes of valid scan data
+ */
+static int cros_ec_keyscan(struct ec_state *ec, uint8_t *scan)
+{
+ const struct ec_keymatrix_entry *matrix;
+ int bytes = KEYBOARD_COLS;
+ int key[8]; /* allow up to 8 keys to be pressed at once */
+ int count;
+ int i;
+
+ memset(ec->keyscan, '\0', bytes);
+ count = sandbox_sdl_scan_keys(key, ARRAY_SIZE(key));
+
+ /* Look up keycode in matrix */
+ for (i = 0, matrix = ec->matrix; i < ec->matrix_count; i++, matrix++) {
+ bool found;
+ int j;
+
+ for (found = false, j = 0; j < count; j++) {
+ if (matrix->keycode == key[j])
+ found = true;
+ }
+
+ if (found) {
+ debug("%d: %d,%d\n", matrix->keycode, matrix->row,
+ matrix->col);
+ ec->keyscan[matrix->col] |= 1 << matrix->row;
+ }
+ }
+
+ memcpy(scan, ec->keyscan, bytes);
+ return bytes;
+}
+
+/**
+ * Process an emulated EC command
+ *
+ * @param ec Current emulated EC state
+ * @param req_hdr Pointer to request header
+ * @param req_data Pointer to body of request
+ * @param resp_hdr Pointer to place to put response header
+ * @param resp_data Pointer to place to put response data, if any
+ * @return length of response data, or 0 for no response data, or -1 on error
+ */
+static int process_cmd(struct ec_state *ec,
+ struct ec_host_request *req_hdr, const void *req_data,
+ struct ec_host_response *resp_hdr, void *resp_data)
+{
+ int len;
+
+ /* TODO(sjg@chromium.org): Check checksums */
+ debug("EC command %#0x\n", req_hdr->command);
+
+ switch (req_hdr->command) {
+ case EC_CMD_HELLO: {
+ const struct ec_params_hello *req = req_data;
+ struct ec_response_hello *resp = resp_data;
+
+ resp->out_data = req->in_data + 0x01020304;
+ len = sizeof(*resp);
+ break;
+ }
+ case EC_CMD_GET_VERSION: {
+ struct ec_response_get_version *resp = resp_data;
+
+ strcpy(resp->version_string_ro, "sandbox_ro");
+ strcpy(resp->version_string_rw, "sandbox_rw");
+ resp->current_image = ec->current_image;
+ debug("Current image %d\n", resp->current_image);
+ len = sizeof(*resp);
+ break;
+ }
+ case EC_CMD_VBNV_CONTEXT: {
+ const struct ec_params_vbnvcontext *req = req_data;
+ struct ec_response_vbnvcontext *resp = resp_data;
+
+ switch (req->op) {
+ case EC_VBNV_CONTEXT_OP_READ:
+ memcpy(resp->block, ec->vbnv_context,
+ sizeof(resp->block));
+ len = sizeof(*resp);
+ break;
+ case EC_VBNV_CONTEXT_OP_WRITE:
+ memcpy(ec->vbnv_context, resp->block,
+ sizeof(resp->block));
+ len = 0;
+ break;
+ default:
+ printf(" ** Unknown vbnv_context command %#02x\n",
+ req->op);
+ return -1;
+ }
+ break;
+ }
+ case EC_CMD_REBOOT_EC: {
+ const struct ec_params_reboot_ec *req = req_data;
+
+ printf("Request reboot type %d\n", req->cmd);
+ switch (req->cmd) {
+ case EC_REBOOT_DISABLE_JUMP:
+ len = 0;
+ break;
+ case EC_REBOOT_JUMP_RW:
+ ec->current_image = EC_IMAGE_RW;
+ len = 0;
+ break;
+ default:
+ puts(" ** Unknown type");
+ return -1;
+ }
+ break;
+ }
+ case EC_CMD_HOST_EVENT_GET_B: {
+ struct ec_response_host_event_mask *resp = resp_data;
+
+ resp->mask = 0;
+ if (ec->recovery_req) {
+ resp->mask |= EC_HOST_EVENT_MASK(
+ EC_HOST_EVENT_KEYBOARD_RECOVERY);
+ }
+
+ len = sizeof(*resp);
+ break;
+ }
+ case EC_CMD_VBOOT_HASH: {
+ const struct ec_params_vboot_hash *req = req_data;
+ struct ec_response_vboot_hash *resp = resp_data;
+ struct fmap_entry *entry;
+ int ret, size;
+
+ entry = &state->ec_config.region[EC_FLASH_REGION_RW];
+
+ switch (req->cmd) {
+ case EC_VBOOT_HASH_RECALC:
+ case EC_VBOOT_HASH_GET:
+ size = SHA256_SUM_LEN;
+ len = get_image_used(ec, entry);
+ ret = hash_block("sha256",
+ ec->flash_data + entry->offset,
+ len, resp->hash_digest, &size);
+ if (ret) {
+ printf(" ** hash_block() failed\n");
+ return -1;
+ }
+ resp->status = EC_VBOOT_HASH_STATUS_DONE;
+ resp->hash_type = EC_VBOOT_HASH_TYPE_SHA256;
+ resp->digest_size = size;
+ resp->reserved0 = 0;
+ resp->offset = entry->offset;
+ resp->size = len;
+ len = sizeof(*resp);
+ break;
+ default:
+ printf(" ** EC_CMD_VBOOT_HASH: Unknown command %d\n",
+ req->cmd);
+ return -1;
+ }
+ break;
+ }
+ case EC_CMD_FLASH_PROTECT: {
+ const struct ec_params_flash_protect *req = req_data;
+ struct ec_response_flash_protect *resp = resp_data;
+ uint32_t expect = EC_FLASH_PROTECT_ALL_NOW |
+ EC_FLASH_PROTECT_ALL_AT_BOOT;
+
+ printf("mask=%#x, flags=%#x\n", req->mask, req->flags);
+ if (req->flags == expect || req->flags == 0) {
+ resp->flags = req->flags ? EC_FLASH_PROTECT_ALL_NOW :
+ 0;
+ resp->valid_flags = EC_FLASH_PROTECT_ALL_NOW;
+ resp->writable_flags = 0;
+ len = sizeof(*resp);
+ } else {
+ puts(" ** unexpected flash protect request\n");
+ return -1;
+ }
+ break;
+ }
+ case EC_CMD_FLASH_REGION_INFO: {
+ const struct ec_params_flash_region_info *req = req_data;
+ struct ec_response_flash_region_info *resp = resp_data;
+ struct fmap_entry *entry;
+
+ switch (req->region) {
+ case EC_FLASH_REGION_RO:
+ case EC_FLASH_REGION_RW:
+ case EC_FLASH_REGION_WP_RO:
+ entry = &state->ec_config.region[req->region];
+ resp->offset = entry->offset;
+ resp->size = entry->length;
+ len = sizeof(*resp);
+ printf("EC flash region %d: offset=%#x, size=%#x\n",
+ req->region, resp->offset, resp->size);
+ break;
+ default:
+ printf("** Unknown flash region %d\n", req->region);
+ return -1;
+ }
+ break;
+ }
+ case EC_CMD_FLASH_ERASE: {
+ const struct ec_params_flash_erase *req = req_data;
+
+ memset(ec->flash_data + req->offset,
+ ec->ec_config.flash_erase_value,
+ req->size);
+ len = 0;
+ break;
+ }
+ case EC_CMD_FLASH_WRITE: {
+ const struct ec_params_flash_write *req = req_data;
+
+ memcpy(ec->flash_data + req->offset, req + 1, req->size);
+ len = 0;
+ break;
+ }
+ case EC_CMD_MKBP_STATE:
+ len = cros_ec_keyscan(ec, resp_data);
+ break;
+ default:
+ printf(" ** Unknown EC command %#02x\n", req_hdr->command);
+ return -1;
+ }
+
+ return len;
+}
+
+int cros_ec_sandbox_packet(struct cros_ec_dev *dev, int out_bytes,
+ int in_bytes)
+{
+ 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);
+ if (len < 0)
+ return len;
+
+ resp_hdr->struct_version = 3;
+ resp_hdr->result = EC_RES_SUCCESS;
+ resp_hdr->data_len = len;
+ resp_hdr->reserved = 0;
+ len += sizeof(*resp_hdr);
+ resp_hdr->checksum = 0;
+ resp_hdr->checksum = (uint8_t)
+ -cros_ec_calc_checksum((const uint8_t *)resp_hdr, len);
+
+ return in_bytes;
+}
+
+int cros_ec_sandbox_decode_fdt(struct cros_ec_dev *dev, const void *blob)
+{
+ return 0;
+}
+
+void cros_ec_check_keyboard(struct cros_ec_dev *dev)
+{
+ struct ec_state *ec = &s_state;
+ ulong start;
+
+ printf("Press keys for EC to detect on reset (ESC=recovery)...");
+ start = get_timer(0);
+ while (get_timer(start) < 1000)
+ ;
+ putc('\n');
+ if (!sandbox_sdl_key_pressed(KEY_ESC)) {
+ ec->recovery_req = true;
+ printf(" - EC requests recovery\n");
+ }
+}
+
+/**
+ * Initialize sandbox EC emulation.
+ *
+ * @param dev CROS_EC device
+ * @param blob Device tree blob
+ * @return 0 if ok, -1 on error
+ */
+int cros_ec_sandbox_init(struct cros_ec_dev *dev, const void *blob)
+{
+ struct ec_state *ec = &s_state;
+ int node;
+ int err;
+
+ state = &s_state;
+ err = cros_ec_decode_ec_flash(blob, &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;
+ }
+
+ return 0;
+}
diff --git a/qemu/roms/u-boot/drivers/misc/cros_ec_spi.c b/qemu/roms/u-boot/drivers/misc/cros_ec_spi.c
new file mode 100644
index 000000000..7df709cc7
--- /dev/null
+++ b/qemu/roms/u-boot/drivers/misc/cros_ec_spi.c
@@ -0,0 +1,175 @@
+/*
+ * Chromium OS cros_ec driver - SPI interface
+ *
+ * Copyright (c) 2012 The Chromium OS Authors.
+ *
+ * SPDX-License-Identifier: GPL-2.0+
+ */
+
+/*
+ * The Matrix Keyboard Protocol driver handles talking to the keyboard
+ * controller chip. Mostly this is for keyboard functions, but some other
+ * things have slipped in, so we provide generic services to talk to the
+ * KBC.
+ */
+
+#include <common.h>
+#include <cros_ec.h>
+#include <spi.h>
+
+int cros_ec_spi_packet(struct cros_ec_dev *dev, int out_bytes, int in_bytes)
+{
+ int rv;
+
+ /* Do the transfer */
+ if (spi_claim_bus(dev->spi)) {
+ debug("%s: Cannot claim SPI bus\n", __func__);
+ return -1;
+ }
+
+ rv = spi_xfer(dev->spi, max(out_bytes, in_bytes) * 8,
+ dev->dout, dev->din,
+ SPI_XFER_BEGIN | SPI_XFER_END);
+
+ spi_release_bus(dev->spi);
+
+ if (rv) {
+ debug("%s: Cannot complete SPI transfer\n", __func__);
+ return -1;
+ }
+
+ return in_bytes;
+}
+
+/**
+ * Send a command to a LPC CROS_EC device and return the reply.
+ *
+ * The device's internal input/output buffers are used.
+ *
+ * @param dev CROS_EC device
+ * @param cmd Command to send (EC_CMD_...)
+ * @param cmd_version Version of command to send (EC_VER_...)
+ * @param dout Output data (may be NULL If dout_len=0)
+ * @param dout_len Size of output data in bytes
+ * @param dinp Returns pointer to response data. This will be
+ * untouched unless we return a value > 0.
+ * @param din_len Maximum size of response in bytes
+ * @return number of bytes in response, or -1 on error
+ */
+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)
+{
+ int in_bytes = din_len + 4; /* status, length, checksum, trailer */
+ uint8_t *out;
+ uint8_t *p;
+ int csum, len;
+ int rv;
+
+ if (dev->protocol_version != 2) {
+ debug("%s: Unsupported EC protcol version %d\n",
+ __func__, dev->protocol_version);
+ return -1;
+ }
+
+ /*
+ * Sanity-check input size to make sure it plus transaction overhead
+ * fits in the internal device buffer.
+ */
+ if (in_bytes > sizeof(dev->din)) {
+ debug("%s: Cannot receive %d bytes\n", __func__, din_len);
+ return -1;
+ }
+
+ /* We represent message length as a byte */
+ if (dout_len > 0xff) {
+ debug("%s: Cannot send %d bytes\n", __func__, dout_len);
+ return -1;
+ }
+
+ /*
+ * Clear input buffer so we don't get false hits for MSG_HEADER
+ */
+ memset(dev->din, '\0', in_bytes);
+
+ if (spi_claim_bus(dev->spi)) {
+ debug("%s: Cannot claim SPI bus\n", __func__);
+ return -1;
+ }
+
+ out = dev->dout;
+ out[0] = cmd_version;
+ out[1] = cmd;
+ out[2] = (uint8_t)dout_len;
+ memcpy(out + 3, dout, dout_len);
+ csum = cros_ec_calc_checksum(out, 3)
+ + cros_ec_calc_checksum(dout, dout_len);
+ out[3 + dout_len] = (uint8_t)csum;
+
+ /*
+ * Send output data and receive input data starting such that the
+ * message body will be dword aligned.
+ */
+ 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,
+ SPI_XFER_BEGIN | SPI_XFER_END);
+
+ spi_release_bus(dev->spi);
+
+ if (rv) {
+ debug("%s: Cannot complete SPI transfer\n", __func__);
+ return -1;
+ }
+
+ len = min(p[1], din_len);
+ cros_ec_dump_data("in", -1, p, len + 3);
+
+ /* Response code is first byte of message */
+ if (p[0] != EC_RES_SUCCESS) {
+ printf("%s: Returned status %d\n", __func__, p[0]);
+ return -(int)(p[0]);
+ }
+
+ /* Check checksum */
+ csum = cros_ec_calc_checksum(p, len + 2);
+ if (csum != p[len + 2]) {
+ debug("%s: Invalid checksum rx %#02x, calced %#02x\n", __func__,
+ p[2 + len], csum);
+ return -1;
+ }
+
+ /* Anything else is the response data */
+ *dinp = p + 2;
+
+ return len;
+}
+
+int cros_ec_spi_decode_fdt(struct cros_ec_dev *dev, const void *blob)
+{
+ /* Decode interface-specific FDT params */
+ dev->max_frequency = fdtdec_get_int(blob, dev->node,
+ "spi-max-frequency", 500000);
+ dev->cs = fdtdec_get_int(blob, dev->node, "reg", 0);
+
+ return 0;
+}
+
+/**
+ * Initialize SPI protocol.
+ *
+ * @param dev CROS_EC device
+ * @param blob Device tree blob
+ * @return 0 if ok, -1 on error
+ */
+int cros_ec_spi_init(struct cros_ec_dev *dev, const void *blob)
+{
+ dev->spi = spi_setup_slave_fdt(blob, dev->parent_node, dev->node);
+ if (!dev->spi) {
+ debug("%s: Could not setup SPI slave\n", __func__);
+ return -1;
+ }
+
+ return 0;
+}
diff --git a/qemu/roms/u-boot/drivers/misc/ds4510.c b/qemu/roms/u-boot/drivers/misc/ds4510.c
new file mode 100644
index 000000000..aa893c35f
--- /dev/null
+++ b/qemu/roms/u-boot/drivers/misc/ds4510.c
@@ -0,0 +1,423 @@
+/*
+ * Copyright 2008 Extreme Engineering Solutions, Inc.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * Version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
+ * MA 02111-1307 USA
+ */
+
+/*
+ * Driver for DS4510, a CPU supervisor with integrated EEPROM, SRAM,
+ * and 4 programmable non-volatile GPIO pins.
+ */
+
+#include <common.h>
+#include <i2c.h>
+#include <command.h>
+#include <ds4510.h>
+
+/* Default to an address that hopefully won't corrupt other i2c devices */
+#ifndef CONFIG_SYS_I2C_DS4510_ADDR
+#define CONFIG_SYS_I2C_DS4510_ADDR (~0)
+#endif
+
+enum {
+ DS4510_CMD_INFO,
+ DS4510_CMD_DEVICE,
+ DS4510_CMD_NV,
+ DS4510_CMD_RSTDELAY,
+ DS4510_CMD_OUTPUT,
+ DS4510_CMD_INPUT,
+ DS4510_CMD_PULLUP,
+ DS4510_CMD_EEPROM,
+ DS4510_CMD_SEEPROM,
+ DS4510_CMD_SRAM,
+};
+
+/*
+ * Write to DS4510, taking page boundaries into account
+ */
+int ds4510_mem_write(uint8_t chip, int offset, uint8_t *buf, int count)
+{
+ int wrlen;
+ int i = 0;
+
+ do {
+ wrlen = DS4510_EEPROM_PAGE_SIZE -
+ DS4510_EEPROM_PAGE_OFFSET(offset);
+ if (count < wrlen)
+ wrlen = count;
+ if (i2c_write(chip, offset, 1, &buf[i], wrlen))
+ return -1;
+
+ /*
+ * This delay isn't needed for SRAM writes but shouldn't delay
+ * things too much, so do it unconditionally for simplicity
+ */
+ udelay(DS4510_EEPROM_PAGE_WRITE_DELAY_MS * 1000);
+ count -= wrlen;
+ offset += wrlen;
+ i += wrlen;
+ } while (count > 0);
+
+ return 0;
+}
+
+/*
+ * General read from DS4510
+ */
+int ds4510_mem_read(uint8_t chip, int offset, uint8_t *buf, int count)
+{
+ return i2c_read(chip, offset, 1, buf, count);
+}
+
+/*
+ * Write SEE bit in config register.
+ * nv = 0 - Writes to SEEPROM registers behave like EEPROM
+ * nv = 1 - Writes to SEEPROM registers behave like SRAM
+ */
+int ds4510_see_write(uint8_t chip, uint8_t nv)
+{
+ uint8_t data;
+
+ if (i2c_read(chip, DS4510_CFG, 1, &data, 1))
+ return -1;
+
+ if (nv) /* Treat SEEPROM bits as EEPROM */
+ data &= ~DS4510_CFG_SEE;
+ else /* Treat SEEPROM bits as SRAM */
+ data |= DS4510_CFG_SEE;
+
+ return ds4510_mem_write(chip, DS4510_CFG, &data, 1);
+}
+
+/*
+ * Write de-assertion of reset signal delay
+ */
+int ds4510_rstdelay_write(uint8_t chip, uint8_t delay)
+{
+ uint8_t data;
+
+ if (i2c_read(chip, DS4510_RSTDELAY, 1, &data, 1))
+ return -1;
+
+ data &= ~DS4510_RSTDELAY_MASK;
+ data |= delay & DS4510_RSTDELAY_MASK;
+
+ return ds4510_mem_write(chip, DS4510_RSTDELAY, &data, 1);
+}
+
+/*
+ * Write pullup characteristics of IO pins
+ */
+int ds4510_pullup_write(uint8_t chip, uint8_t val)
+{
+ val &= DS4510_IO_MASK;
+
+ return ds4510_mem_write(chip, DS4510_PULLUP, (uint8_t *)&val, 1);
+}
+
+/*
+ * Read pullup characteristics of IO pins
+ */
+int ds4510_pullup_read(uint8_t chip)
+{
+ uint8_t val;
+
+ if (i2c_read(chip, DS4510_PULLUP, 1, &val, 1))
+ return -1;
+
+ return val & DS4510_IO_MASK;
+}
+
+/*
+ * Write drive level of IO pins
+ */
+int ds4510_gpio_write(uint8_t chip, uint8_t val)
+{
+ uint8_t data;
+ int i;
+
+ for (i = 0; i < DS4510_NUM_IO; i++) {
+ if (i2c_read(chip, DS4510_IO0 - i, 1, &data, 1))
+ return -1;
+
+ if (val & (0x1 << i))
+ data |= 0x1;
+ else
+ data &= ~0x1;
+
+ if (ds4510_mem_write(chip, DS4510_IO0 - i, &data, 1))
+ return -1;
+ }
+
+ return 0;
+}
+
+/*
+ * Read drive level of IO pins
+ */
+int ds4510_gpio_read(uint8_t chip)
+{
+ uint8_t data;
+ int val = 0;
+ int i;
+
+ for (i = 0; i < DS4510_NUM_IO; i++) {
+ if (i2c_read(chip, DS4510_IO0 - i, 1, &data, 1))
+ return -1;
+
+ if (data & 1)
+ val |= (1 << i);
+ }
+
+ return val;
+}
+
+/*
+ * Read physical level of IO pins
+ */
+int ds4510_gpio_read_val(uint8_t chip)
+{
+ uint8_t val;
+
+ if (i2c_read(chip, DS4510_IO_STATUS, 1, &val, 1))
+ return -1;
+
+ return val & DS4510_IO_MASK;
+}
+
+#ifdef CONFIG_CMD_DS4510
+#ifdef CONFIG_CMD_DS4510_INFO
+/*
+ * Display DS4510 information
+ */
+static int ds4510_info(uint8_t chip)
+{
+ int i;
+ int tmp;
+ uint8_t data;
+
+ printf("DS4510 @ 0x%x:\n\n", chip);
+
+ if (i2c_read(chip, DS4510_RSTDELAY, 1, &data, 1))
+ return -1;
+ printf("rstdelay = 0x%x\n\n", data & DS4510_RSTDELAY_MASK);
+
+ if (i2c_read(chip, DS4510_CFG, 1, &data, 1))
+ return -1;
+ printf("config = 0x%x\n", data);
+ printf(" /ready = %d\n", data & DS4510_CFG_READY ? 1 : 0);
+ printf(" trip pt = %d\n", data & DS4510_CFG_TRIP_POINT ? 1 : 0);
+ printf(" rst sts = %d\n", data & DS4510_CFG_RESET ? 1 : 0);
+ printf(" /see = %d\n", data & DS4510_CFG_SEE ? 1 : 0);
+ printf(" swrst = %d\n\n", data & DS4510_CFG_SWRST ? 1 : 0);
+
+ printf("gpio pins: 3210\n");
+ printf("---------------\n");
+ printf("pullup ");
+
+ tmp = ds4510_pullup_read(chip);
+ if (tmp == -1)
+ return tmp;
+ for (i = DS4510_NUM_IO - 1; i >= 0; i--)
+ printf("%d", (tmp & (1 << i)) ? 1 : 0);
+ printf("\n");
+
+ printf("driven ");
+ tmp = ds4510_gpio_read(chip);
+ if (tmp == -1)
+ return -1;
+ for (i = DS4510_NUM_IO - 1; i >= 0; i--)
+ printf("%d", (tmp & (1 << i)) ? 1 : 0);
+ printf("\n");
+
+ printf("read ");
+ tmp = ds4510_gpio_read_val(chip);
+ if (tmp == -1)
+ return -1;
+ for (i = DS4510_NUM_IO - 1; i >= 0; i--)
+ printf("%d", (tmp & (1 << i)) ? 1 : 0);
+ printf("\n");
+
+ return 0;
+}
+#endif /* CONFIG_CMD_DS4510_INFO */
+
+cmd_tbl_t cmd_ds4510[] = {
+ U_BOOT_CMD_MKENT(device, 3, 0, (void *)DS4510_CMD_DEVICE, "", ""),
+ U_BOOT_CMD_MKENT(nv, 3, 0, (void *)DS4510_CMD_NV, "", ""),
+ U_BOOT_CMD_MKENT(output, 4, 0, (void *)DS4510_CMD_OUTPUT, "", ""),
+ U_BOOT_CMD_MKENT(input, 3, 0, (void *)DS4510_CMD_INPUT, "", ""),
+ U_BOOT_CMD_MKENT(pullup, 4, 0, (void *)DS4510_CMD_PULLUP, "", ""),
+#ifdef CONFIG_CMD_DS4510_INFO
+ U_BOOT_CMD_MKENT(info, 2, 0, (void *)DS4510_CMD_INFO, "", ""),
+#endif
+#ifdef CONFIG_CMD_DS4510_RST
+ U_BOOT_CMD_MKENT(rstdelay, 3, 0, (void *)DS4510_CMD_RSTDELAY, "", ""),
+#endif
+#ifdef CONFIG_CMD_DS4510_MEM
+ U_BOOT_CMD_MKENT(eeprom, 6, 0, (void *)DS4510_CMD_EEPROM, "", ""),
+ U_BOOT_CMD_MKENT(seeprom, 6, 0, (void *)DS4510_CMD_SEEPROM, "", ""),
+ U_BOOT_CMD_MKENT(sram, 6, 0, (void *)DS4510_CMD_SRAM, "", ""),
+#endif
+};
+
+int do_ds4510(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])
+{
+ static uint8_t chip = CONFIG_SYS_I2C_DS4510_ADDR;
+ cmd_tbl_t *c;
+ ulong ul_arg2 = 0;
+ ulong ul_arg3 = 0;
+ int tmp;
+#ifdef CONFIG_CMD_DS4510_MEM
+ ulong addr;
+ ulong off;
+ ulong cnt;
+ int end;
+ int (*rw_func)(uint8_t, int, uint8_t *, int);
+#endif
+
+ c = find_cmd_tbl(argv[1], cmd_ds4510, ARRAY_SIZE(cmd_ds4510));
+
+ /* All commands but "device" require 'maxargs' arguments */
+ if (!c || !((argc == (c->maxargs)) ||
+ (((int)c->cmd == DS4510_CMD_DEVICE) &&
+ (argc == (c->maxargs - 1))))) {
+ return cmd_usage(cmdtp);
+ }
+
+ /* arg2 used as chip addr and pin number */
+ if (argc > 2)
+ ul_arg2 = simple_strtoul(argv[2], NULL, 16);
+
+ /* arg3 used as output/pullup value */
+ if (argc > 3)
+ ul_arg3 = simple_strtoul(argv[3], NULL, 16);
+
+ switch ((int)c->cmd) {
+ case DS4510_CMD_DEVICE:
+ if (argc == 3)
+ chip = ul_arg2;
+ printf("Current device address: 0x%x\n", chip);
+ return 0;
+ case DS4510_CMD_NV:
+ return ds4510_see_write(chip, ul_arg2);
+ case DS4510_CMD_OUTPUT:
+ tmp = ds4510_gpio_read(chip);
+ if (tmp == -1)
+ return -1;
+ if (ul_arg3)
+ tmp |= (1 << ul_arg2);
+ else
+ tmp &= ~(1 << ul_arg2);
+ return ds4510_gpio_write(chip, tmp);
+ case DS4510_CMD_INPUT:
+ tmp = ds4510_gpio_read_val(chip);
+ if (tmp == -1)
+ return -1;
+ return (tmp & (1 << ul_arg2)) != 0;
+ case DS4510_CMD_PULLUP:
+ tmp = ds4510_pullup_read(chip);
+ if (tmp == -1)
+ return -1;
+ if (ul_arg3)
+ tmp |= (1 << ul_arg2);
+ else
+ tmp &= ~(1 << ul_arg2);
+ return ds4510_pullup_write(chip, tmp);
+#ifdef CONFIG_CMD_DS4510_INFO
+ case DS4510_CMD_INFO:
+ return ds4510_info(chip);
+#endif
+#ifdef CONFIG_CMD_DS4510_RST
+ case DS4510_CMD_RSTDELAY:
+ return ds4510_rstdelay_write(chip, ul_arg2);
+#endif
+#ifdef CONFIG_CMD_DS4510_MEM
+ case DS4510_CMD_EEPROM:
+ end = DS4510_EEPROM + DS4510_EEPROM_SIZE;
+ off = DS4510_EEPROM;
+ break;
+ case DS4510_CMD_SEEPROM:
+ end = DS4510_SEEPROM + DS4510_SEEPROM_SIZE;
+ off = DS4510_SEEPROM;
+ break;
+ case DS4510_CMD_SRAM:
+ end = DS4510_SRAM + DS4510_SRAM_SIZE;
+ off = DS4510_SRAM;
+ break;
+#endif
+ default:
+ /* We should never get here... */
+ return 1;
+ }
+
+#ifdef CONFIG_CMD_DS4510_MEM
+ /* Only eeprom, seeprom, and sram commands should make it here */
+ if (strcmp(argv[2], "read") == 0)
+ rw_func = ds4510_mem_read;
+ else if (strcmp(argv[2], "write") == 0)
+ rw_func = ds4510_mem_write;
+ else
+ return cmd_usage(cmdtp);
+
+ addr = simple_strtoul(argv[3], NULL, 16);
+ off += simple_strtoul(argv[4], NULL, 16);
+ cnt = simple_strtoul(argv[5], NULL, 16);
+
+ if ((off + cnt) > end) {
+ printf("ERROR: invalid len\n");
+ return -1;
+ }
+
+ return rw_func(chip, off, (uint8_t *)addr, cnt);
+#endif
+}
+
+U_BOOT_CMD(
+ ds4510, 6, 1, do_ds4510,
+ "ds4510 eeprom/seeprom/sram/gpio access",
+ "device [dev]\n"
+ " - show or set current device address\n"
+#ifdef CONFIG_CMD_DS4510_INFO
+ "ds4510 info\n"
+ " - display ds4510 info\n"
+#endif
+ "ds4510 output pin 0|1\n"
+ " - set pin low or high-Z\n"
+ "ds4510 input pin\n"
+ " - read value of pin\n"
+ "ds4510 pullup pin 0|1\n"
+ " - disable/enable pullup on specified pin\n"
+ "ds4510 nv 0|1\n"
+ " - make gpio and seeprom writes volatile/non-volatile"
+#ifdef CONFIG_CMD_DS4510_RST
+ "\n"
+ "ds4510 rstdelay 0-3\n"
+ " - set reset output delay"
+#endif
+#ifdef CONFIG_CMD_DS4510_MEM
+ "\n"
+ "ds4510 eeprom read addr off cnt\n"
+ "ds4510 eeprom write addr off cnt\n"
+ " - read/write 'cnt' bytes at EEPROM offset 'off'\n"
+ "ds4510 seeprom read addr off cnt\n"
+ "ds4510 seeprom write addr off cnt\n"
+ " - read/write 'cnt' bytes at SRAM-shadowed EEPROM offset 'off'\n"
+ "ds4510 sram read addr off cnt\n"
+ "ds4510 sram write addr off cnt\n"
+ " - read/write 'cnt' bytes at SRAM offset 'off'"
+#endif
+);
+#endif /* CONFIG_CMD_DS4510 */
diff --git a/qemu/roms/u-boot/drivers/misc/fsl_ifc.c b/qemu/roms/u-boot/drivers/misc/fsl_ifc.c
new file mode 100644
index 000000000..3902e9ff5
--- /dev/null
+++ b/qemu/roms/u-boot/drivers/misc/fsl_ifc.c
@@ -0,0 +1,171 @@
+/*
+ * Copyright 2010-2011 Freescale Semiconductor, Inc.
+ * Author: Dipen Dudhat <dipen.dudhat@freescale.com>
+ *
+ * SPDX-License-Identifier: GPL-2.0+
+ */
+
+#include <common.h>
+#include <fsl_ifc.h>
+
+void print_ifc_regs(void)
+{
+ int i, j;
+
+ printf("IFC Controller Registers\n");
+ for (i = 0; i < CONFIG_SYS_FSL_IFC_BANK_COUNT; i++) {
+ printf("CSPR%d:0x%08X\tAMASK%d:0x%08X\tCSOR%d:0x%08X\n",
+ i, get_ifc_cspr(i), i, get_ifc_amask(i),
+ i, get_ifc_csor(i));
+ for (j = 0; j < 4; j++)
+ printf("IFC_FTIM%d:0x%08X\n", j, get_ifc_ftim(i, j));
+ }
+}
+
+void init_early_memctl_regs(void)
+{
+#if defined(CONFIG_SYS_CSPR0) && defined(CONFIG_SYS_CSOR0)
+ set_ifc_ftim(IFC_CS0, IFC_FTIM0, CONFIG_SYS_CS0_FTIM0);
+ set_ifc_ftim(IFC_CS0, IFC_FTIM1, CONFIG_SYS_CS0_FTIM1);
+ set_ifc_ftim(IFC_CS0, IFC_FTIM2, CONFIG_SYS_CS0_FTIM2);
+ set_ifc_ftim(IFC_CS0, IFC_FTIM3, CONFIG_SYS_CS0_FTIM3);
+
+#ifndef CONFIG_A003399_NOR_WORKAROUND
+#ifdef CONFIG_SYS_CSPR0_EXT
+ set_ifc_cspr_ext(IFC_CS0, CONFIG_SYS_CSPR0_EXT);
+#endif
+#ifdef CONFIG_SYS_CSOR0_EXT
+ set_ifc_csor_ext(IFC_CS0, CONFIG_SYS_CSOR0_EXT);
+#endif
+ set_ifc_cspr(IFC_CS0, CONFIG_SYS_CSPR0);
+ set_ifc_amask(IFC_CS0, CONFIG_SYS_AMASK0);
+ set_ifc_csor(IFC_CS0, CONFIG_SYS_CSOR0);
+#endif
+#endif
+
+#ifdef CONFIG_SYS_CSPR1_EXT
+ set_ifc_cspr_ext(IFC_CS1, CONFIG_SYS_CSPR1_EXT);
+#endif
+#ifdef CONFIG_SYS_CSOR1_EXT
+ set_ifc_csor_ext(IFC_CS1, CONFIG_SYS_CSOR1_EXT);
+#endif
+#if defined(CONFIG_SYS_CSPR1) && defined(CONFIG_SYS_CSOR1)
+ set_ifc_ftim(IFC_CS1, IFC_FTIM0, CONFIG_SYS_CS1_FTIM0);
+ set_ifc_ftim(IFC_CS1, IFC_FTIM1, CONFIG_SYS_CS1_FTIM1);
+ set_ifc_ftim(IFC_CS1, IFC_FTIM2, CONFIG_SYS_CS1_FTIM2);
+ set_ifc_ftim(IFC_CS1, IFC_FTIM3, CONFIG_SYS_CS1_FTIM3);
+
+ set_ifc_csor(IFC_CS1, CONFIG_SYS_CSOR1);
+ set_ifc_amask(IFC_CS1, CONFIG_SYS_AMASK1);
+ set_ifc_cspr(IFC_CS1, CONFIG_SYS_CSPR1);
+#endif
+
+#ifdef CONFIG_SYS_CSPR2_EXT
+ set_ifc_cspr_ext(IFC_CS2, CONFIG_SYS_CSPR2_EXT);
+#endif
+#ifdef CONFIG_SYS_CSOR2_EXT
+ set_ifc_csor_ext(IFC_CS2, CONFIG_SYS_CSOR2_EXT);
+#endif
+#if defined(CONFIG_SYS_CSPR2) && defined(CONFIG_SYS_CSOR2)
+ set_ifc_ftim(IFC_CS2, IFC_FTIM0, CONFIG_SYS_CS2_FTIM0);
+ set_ifc_ftim(IFC_CS2, IFC_FTIM1, CONFIG_SYS_CS2_FTIM1);
+ set_ifc_ftim(IFC_CS2, IFC_FTIM2, CONFIG_SYS_CS2_FTIM2);
+ set_ifc_ftim(IFC_CS2, IFC_FTIM3, CONFIG_SYS_CS2_FTIM3);
+
+ set_ifc_csor(IFC_CS2, CONFIG_SYS_CSOR2);
+ set_ifc_amask(IFC_CS2, CONFIG_SYS_AMASK2);
+ set_ifc_cspr(IFC_CS2, CONFIG_SYS_CSPR2);
+#endif
+
+#ifdef CONFIG_SYS_CSPR3_EXT
+ set_ifc_cspr_ext(IFC_CS3, CONFIG_SYS_CSPR3_EXT);
+#endif
+#ifdef CONFIG_SYS_CSOR3_EXT
+ set_ifc_csor_ext(IFC_CS3, CONFIG_SYS_CSOR3_EXT);
+#endif
+#if defined(CONFIG_SYS_CSPR3) && defined(CONFIG_SYS_CSOR3)
+ set_ifc_ftim(IFC_CS3, IFC_FTIM0, CONFIG_SYS_CS3_FTIM0);
+ set_ifc_ftim(IFC_CS3, IFC_FTIM1, CONFIG_SYS_CS3_FTIM1);
+ set_ifc_ftim(IFC_CS3, IFC_FTIM2, CONFIG_SYS_CS3_FTIM2);
+ set_ifc_ftim(IFC_CS3, IFC_FTIM3, CONFIG_SYS_CS3_FTIM3);
+
+ set_ifc_cspr(IFC_CS3, CONFIG_SYS_CSPR3);
+ set_ifc_amask(IFC_CS3, CONFIG_SYS_AMASK3);
+ set_ifc_csor(IFC_CS3, CONFIG_SYS_CSOR3);
+#endif
+
+#ifdef CONFIG_SYS_CSPR4_EXT
+ set_ifc_cspr_ext(IFC_CS4, CONFIG_SYS_CSPR4_EXT);
+#endif
+#ifdef CONFIG_SYS_CSOR4_EXT
+ set_ifc_csor_ext(IFC_CS4, CONFIG_SYS_CSOR4_EXT);
+#endif
+#if defined(CONFIG_SYS_CSPR4) && defined(CONFIG_SYS_CSOR4)
+ set_ifc_ftim(IFC_CS4, IFC_FTIM0, CONFIG_SYS_CS4_FTIM0);
+ set_ifc_ftim(IFC_CS4, IFC_FTIM1, CONFIG_SYS_CS4_FTIM1);
+ set_ifc_ftim(IFC_CS4, IFC_FTIM2, CONFIG_SYS_CS4_FTIM2);
+ set_ifc_ftim(IFC_CS4, IFC_FTIM3, CONFIG_SYS_CS4_FTIM3);
+
+ set_ifc_cspr(IFC_CS4, CONFIG_SYS_CSPR4);
+ set_ifc_amask(IFC_CS4, CONFIG_SYS_AMASK4);
+ set_ifc_csor(IFC_CS4, CONFIG_SYS_CSOR4);
+#endif
+
+#ifdef CONFIG_SYS_CSPR5_EXT
+ set_ifc_cspr_ext(IFC_CS5, CONFIG_SYS_CSPR5_EXT);
+#endif
+#ifdef CONFIG_SYS_CSOR5_EXT
+ set_ifc_csor_ext(IFC_CS5, CONFIG_SYS_CSOR5_EXT);
+#endif
+#if defined(CONFIG_SYS_CSPR5) && defined(CONFIG_SYS_CSOR5)
+ set_ifc_ftim(IFC_CS5, IFC_FTIM0, CONFIG_SYS_CS5_FTIM0);
+ set_ifc_ftim(IFC_CS5, IFC_FTIM1, CONFIG_SYS_CS5_FTIM1);
+ set_ifc_ftim(IFC_CS5, IFC_FTIM2, CONFIG_SYS_CS5_FTIM2);
+ set_ifc_ftim(IFC_CS5, IFC_FTIM3, CONFIG_SYS_CS5_FTIM3);
+
+ set_ifc_cspr(IFC_CS5, CONFIG_SYS_CSPR5);
+ set_ifc_amask(IFC_CS5, CONFIG_SYS_AMASK5);
+ set_ifc_csor(IFC_CS5, CONFIG_SYS_CSOR5);
+#endif
+
+#ifdef CONFIG_SYS_CSPR6_EXT
+ set_ifc_cspr_ext(IFC_CS6, CONFIG_SYS_CSPR6_EXT);
+#endif
+#ifdef CONFIG_SYS_CSOR6_EXT
+ set_ifc_csor_ext(IFC_CS6, CONFIG_SYS_CSOR6_EXT);
+#endif
+#if defined(CONFIG_SYS_CSPR6) && defined(CONFIG_SYS_CSOR6)
+ set_ifc_ftim(IFC_CS6, IFC_FTIM0, CONFIG_SYS_CS6_FTIM0);
+ set_ifc_ftim(IFC_CS6, IFC_FTIM1, CONFIG_SYS_CS6_FTIM1);
+ set_ifc_ftim(IFC_CS6, IFC_FTIM2, CONFIG_SYS_CS6_FTIM2);
+ set_ifc_ftim(IFC_CS6, IFC_FTIM3, CONFIG_SYS_CS6_FTIM3);
+
+ set_ifc_cspr(IFC_CS6, CONFIG_SYS_CSPR6);
+ set_ifc_amask(IFC_CS6, CONFIG_SYS_AMASK6);
+ set_ifc_csor(IFC_CS6, CONFIG_SYS_CSOR6);
+#endif
+
+#ifdef CONFIG_SYS_CSPR7_EXT
+ set_ifc_cspr_ext(IFC_CS7, CONFIG_SYS_CSPR7_EXT);
+#endif
+#ifdef CONFIG_SYS_CSOR7_EXT
+ set_ifc_csor_ext(IFC_CS7, CONFIG_SYS_CSOR7_EXT);
+#endif
+#if defined(CONFIG_SYS_CSPR7) && defined(CONFIG_SYS_CSOR7)
+ set_ifc_ftim(IFC_CS7, IFC_FTIM0, CONFIG_SYS_CS7_FTIM0);
+ set_ifc_ftim(IFC_CS7, IFC_FTIM1, CONFIG_SYS_CS7_FTIM1);
+ set_ifc_ftim(IFC_CS7, IFC_FTIM2, CONFIG_SYS_CS7_FTIM2);
+ set_ifc_ftim(IFC_CS7, IFC_FTIM3, CONFIG_SYS_CS7_FTIM3);
+
+ set_ifc_cspr(IFC_CS7, CONFIG_SYS_CSPR7);
+ set_ifc_amask(IFC_CS7, CONFIG_SYS_AMASK7);
+ set_ifc_csor(IFC_CS7, CONFIG_SYS_CSOR7);
+#endif
+}
+
+void init_final_memctl_regs(void)
+{
+#ifdef CONFIG_SYS_CSPR0_FINAL
+ set_ifc_cspr(IFC_CS0, CONFIG_SYS_CSPR0_FINAL);
+#endif
+}
diff --git a/qemu/roms/u-boot/drivers/misc/fsl_iim.c b/qemu/roms/u-boot/drivers/misc/fsl_iim.c
new file mode 100644
index 000000000..36433a74f
--- /dev/null
+++ b/qemu/roms/u-boot/drivers/misc/fsl_iim.c
@@ -0,0 +1,281 @@
+/*
+ * (C) Copyright 2009-2013 ADVANSEE
+ * Benoît Thébaudeau <benoit.thebaudeau@advansee.com>
+ *
+ * Based on the mpc512x iim code:
+ * Copyright 2008 Silicon Turnkey Express, Inc.
+ * Martha Marx <mmarx@silicontkx.com>
+ *
+ * SPDX-License-Identifier: GPL-2.0+
+ */
+
+#include <common.h>
+#include <fuse.h>
+#include <asm/errno.h>
+#include <asm/io.h>
+#ifndef CONFIG_MPC512X
+#include <asm/arch/imx-regs.h>
+#endif
+#if defined(CONFIG_MX51) || defined(CONFIG_MX53)
+#include <asm/arch/clock.h>
+#endif
+
+/* FSL IIM-specific constants */
+#define STAT_BUSY 0x80
+#define STAT_PRGD 0x02
+#define STAT_SNSD 0x01
+
+#define STATM_PRGD_M 0x02
+#define STATM_SNSD_M 0x01
+
+#define ERR_PRGE 0x80
+#define ERR_WPE 0x40
+#define ERR_OPE 0x20
+#define ERR_RPE 0x10
+#define ERR_WLRE 0x08
+#define ERR_SNSE 0x04
+#define ERR_PARITYE 0x02
+
+#define EMASK_PRGE_M 0x80
+#define EMASK_WPE_M 0x40
+#define EMASK_OPE_M 0x20
+#define EMASK_RPE_M 0x10
+#define EMASK_WLRE_M 0x08
+#define EMASK_SNSE_M 0x04
+#define EMASK_PARITYE_M 0x02
+
+#define FCTL_DPC 0x80
+#define FCTL_PRG_LENGTH_MASK 0x70
+#define FCTL_ESNS_N 0x08
+#define FCTL_ESNS_0 0x04
+#define FCTL_ESNS_1 0x02
+#define FCTL_PRG 0x01
+
+#define UA_A_BANK_MASK 0x38
+#define UA_A_ROWH_MASK 0x07
+
+#define LA_A_ROWL_MASK 0xf8
+#define LA_A_BIT_MASK 0x07
+
+#define PREV_PROD_REV_MASK 0xf8
+#define PREV_PROD_VT_MASK 0x07
+
+/* Select the correct accessors depending on endianness */
+#if __BYTE_ORDER == __LITTLE_ENDIAN
+#define iim_read32 in_le32
+#define iim_write32 out_le32
+#define iim_clrsetbits32 clrsetbits_le32
+#define iim_clrbits32 clrbits_le32
+#define iim_setbits32 setbits_le32
+#elif __BYTE_ORDER == __BIG_ENDIAN
+#define iim_read32 in_be32
+#define iim_write32 out_be32
+#define iim_clrsetbits32 clrsetbits_be32
+#define iim_clrbits32 clrbits_be32
+#define iim_setbits32 setbits_be32
+#else
+#error Endianess is not defined: please fix to continue
+#endif
+
+/* IIM control registers */
+struct fsl_iim {
+ u32 stat;
+ u32 statm;
+ u32 err;
+ u32 emask;
+ u32 fctl;
+ u32 ua;
+ u32 la;
+ u32 sdat;
+ u32 prev;
+ u32 srev;
+ u32 prg_p;
+ u32 scs[0x1f5];
+ struct {
+ u32 word[0x100];
+ } bank[8];
+};
+
+#if !defined(CONFIG_MX51) && !defined(CONFIG_MX53)
+#define enable_efuse_prog_supply(enable)
+#endif
+
+static int prepare_access(struct fsl_iim **regs, u32 bank, u32 word, int assert,
+ const char *caller)
+{
+ *regs = (struct fsl_iim *)IIM_BASE_ADDR;
+
+ if (bank >= ARRAY_SIZE((*regs)->bank) ||
+ word >= ARRAY_SIZE((*regs)->bank[0].word) ||
+ !assert) {
+ printf("fsl_iim %s(): Invalid argument\n", caller);
+ return -EINVAL;
+ }
+
+ return 0;
+}
+
+static void clear_status(struct fsl_iim *regs)
+{
+ iim_setbits32(&regs->stat, 0);
+ iim_setbits32(&regs->err, 0);
+}
+
+static void finish_access(struct fsl_iim *regs, u32 *stat, u32 *err)
+{
+ *stat = iim_read32(&regs->stat);
+ *err = iim_read32(&regs->err);
+ clear_status(regs);
+}
+
+static int prepare_read(struct fsl_iim **regs, u32 bank, u32 word, u32 *val,
+ const char *caller)
+{
+ int ret;
+
+ ret = prepare_access(regs, bank, word, val != NULL, caller);
+ if (ret)
+ return ret;
+
+ clear_status(*regs);
+
+ return 0;
+}
+
+int fuse_read(u32 bank, u32 word, u32 *val)
+{
+ struct fsl_iim *regs;
+ u32 stat, err;
+ int ret;
+
+ ret = prepare_read(&regs, bank, word, val, __func__);
+ if (ret)
+ return ret;
+
+ *val = iim_read32(&regs->bank[bank].word[word]);
+ finish_access(regs, &stat, &err);
+
+ if (err & ERR_RPE) {
+ puts("fsl_iim fuse_read(): Read protect error\n");
+ return -EIO;
+ }
+
+ return 0;
+}
+
+static void direct_access(struct fsl_iim *regs, u32 bank, u32 word, u32 bit,
+ u32 fctl, u32 *stat, u32 *err)
+{
+ iim_write32(&regs->ua, bank << 3 | word >> 5);
+ iim_write32(&regs->la, (word << 3 | bit) & 0xff);
+ if (fctl == FCTL_PRG)
+ iim_write32(&regs->prg_p, 0xaa);
+ iim_setbits32(&regs->fctl, fctl);
+ while (iim_read32(&regs->stat) & STAT_BUSY)
+ udelay(20);
+ finish_access(regs, stat, err);
+}
+
+int fuse_sense(u32 bank, u32 word, u32 *val)
+{
+ struct fsl_iim *regs;
+ u32 stat, err;
+ int ret;
+
+ ret = prepare_read(&regs, bank, word, val, __func__);
+ if (ret)
+ return ret;
+
+ direct_access(regs, bank, word, 0, FCTL_ESNS_N, &stat, &err);
+
+ if (err & ERR_SNSE) {
+ puts("fsl_iim fuse_sense(): Explicit sense cycle error\n");
+ return -EIO;
+ }
+
+ if (!(stat & STAT_SNSD)) {
+ puts("fsl_iim fuse_sense(): Explicit sense cycle did not complete\n");
+ return -EIO;
+ }
+
+ *val = iim_read32(&regs->sdat);
+ return 0;
+}
+
+static int prog_bit(struct fsl_iim *regs, u32 bank, u32 word, u32 bit)
+{
+ u32 stat, err;
+
+ clear_status(regs);
+ direct_access(regs, bank, word, bit, FCTL_PRG, &stat, &err);
+ iim_write32(&regs->prg_p, 0x00);
+
+ if (err & ERR_PRGE) {
+ puts("fsl_iim fuse_prog(): Program error\n");
+ return -EIO;
+ }
+
+ if (err & ERR_WPE) {
+ puts("fsl_iim fuse_prog(): Write protect error\n");
+ return -EIO;
+ }
+
+ if (!(stat & STAT_PRGD)) {
+ puts("fsl_iim fuse_prog(): Program did not complete\n");
+ return -EIO;
+ }
+
+ return 0;
+}
+
+static int prepare_write(struct fsl_iim **regs, u32 bank, u32 word, u32 val,
+ const char *caller)
+{
+ return prepare_access(regs, bank, word, !(val & ~0xff), caller);
+}
+
+int fuse_prog(u32 bank, u32 word, u32 val)
+{
+ struct fsl_iim *regs;
+ u32 bit;
+ int ret;
+
+ ret = prepare_write(&regs, bank, word, val, __func__);
+ if (ret)
+ return ret;
+
+ enable_efuse_prog_supply(1);
+ for (bit = 0; val; bit++, val >>= 1)
+ if (val & 0x01) {
+ ret = prog_bit(regs, bank, word, bit);
+ if (ret) {
+ enable_efuse_prog_supply(0);
+ return ret;
+ }
+ }
+ enable_efuse_prog_supply(0);
+
+ return 0;
+}
+
+int fuse_override(u32 bank, u32 word, u32 val)
+{
+ struct fsl_iim *regs;
+ u32 stat, err;
+ int ret;
+
+ ret = prepare_write(&regs, bank, word, val, __func__);
+ if (ret)
+ return ret;
+
+ clear_status(regs);
+ iim_write32(&regs->bank[bank].word[word], val);
+ finish_access(regs, &stat, &err);
+
+ if (err & ERR_OPE) {
+ puts("fsl_iim fuse_override(): Override protect error\n");
+ return -EIO;
+ }
+
+ return 0;
+}
diff --git a/qemu/roms/u-boot/drivers/misc/gpio_led.c b/qemu/roms/u-boot/drivers/misc/gpio_led.c
new file mode 100644
index 000000000..3e95727d7
--- /dev/null
+++ b/qemu/roms/u-boot/drivers/misc/gpio_led.c
@@ -0,0 +1,53 @@
+/*
+ * Status LED driver based on GPIO access conventions of Linux
+ *
+ * Copyright (C) 2010 Thomas Chou <thomas@wytron.com.tw>
+ * Licensed under the GPL-2 or later.
+ */
+
+#include <common.h>
+#include <status_led.h>
+#include <asm/gpio.h>
+
+#ifndef CONFIG_GPIO_LED_INVERTED_TABLE
+#define CONFIG_GPIO_LED_INVERTED_TABLE {}
+#endif
+
+static led_id_t gpio_led_inv[] = CONFIG_GPIO_LED_INVERTED_TABLE;
+
+static int gpio_led_gpio_value(led_id_t mask, int state)
+{
+ int i, gpio_value = (state == STATUS_LED_ON);
+
+ for (i = 0; i < ARRAY_SIZE(gpio_led_inv); i++) {
+ if (gpio_led_inv[i] == mask)
+ gpio_value = !gpio_value;
+ }
+
+ return gpio_value;
+}
+
+void __led_init(led_id_t mask, int state)
+{
+ int gpio_value;
+
+ if (gpio_request(mask, "gpio_led") != 0) {
+ printf("%s: failed requesting GPIO%lu!\n", __func__, mask);
+ return;
+ }
+
+ gpio_value = gpio_led_gpio_value(mask, state);
+ gpio_direction_output(mask, gpio_value);
+}
+
+void __led_set(led_id_t mask, int state)
+{
+ int gpio_value = gpio_led_gpio_value(mask, state);
+
+ gpio_set_value(mask, gpio_value);
+}
+
+void __led_toggle(led_id_t mask)
+{
+ gpio_set_value(mask, !gpio_get_value(mask));
+}
diff --git a/qemu/roms/u-boot/drivers/misc/mc9sdz60.c b/qemu/roms/u-boot/drivers/misc/mc9sdz60.c
new file mode 100644
index 000000000..cd56b58c2
--- /dev/null
+++ b/qemu/roms/u-boot/drivers/misc/mc9sdz60.c
@@ -0,0 +1,35 @@
+/*
+ * (C) Copyright 2010 Stefano Babic <sbabic@denx.de>
+ *
+ * SPDX-License-Identifier: GPL-2.0+
+ */
+
+
+#include <config.h>
+#include <common.h>
+#include <asm/errno.h>
+#include <linux/types.h>
+#include <i2c.h>
+#include <mc9sdz60.h>
+
+#ifndef CONFIG_SYS_FSL_MC9SDZ60_I2C_ADDR
+#error "You have to configure I2C address for MC9SDZ60"
+#endif
+
+
+u8 mc9sdz60_reg_read(enum mc9sdz60_reg reg)
+{
+ u8 val;
+
+ if (i2c_read(CONFIG_SYS_FSL_MC9SDZ60_I2C_ADDR, reg, 1, &val, 1)) {
+ puts("Error reading MC9SDZ60 register\n");
+ return -1;
+ }
+
+ return val;
+}
+
+void mc9sdz60_reg_write(enum mc9sdz60_reg reg, u8 val)
+{
+ i2c_write(CONFIG_SYS_FSL_MC9SDZ60_I2C_ADDR, reg, 1, &val, 1);
+}
diff --git a/qemu/roms/u-boot/drivers/misc/mxc_ocotp.c b/qemu/roms/u-boot/drivers/misc/mxc_ocotp.c
new file mode 100644
index 000000000..3de124569
--- /dev/null
+++ b/qemu/roms/u-boot/drivers/misc/mxc_ocotp.c
@@ -0,0 +1,200 @@
+/*
+ * (C) Copyright 2013 ADVANSEE
+ * Benoît Thébaudeau <benoit.thebaudeau@advansee.com>
+ *
+ * Based on Dirk Behme's
+ * https://github.com/dirkbehme/u-boot-imx6/blob/28b17e9/drivers/misc/imx_otp.c,
+ * which is based on Freescale's
+ * http://git.freescale.com/git/cgit.cgi/imx/uboot-imx.git/tree/drivers/misc/imx_otp.c?h=imx_v2009.08_1.1.0&id=9aa74e6,
+ * which is:
+ * Copyright (C) 2011 Freescale Semiconductor, Inc.
+ *
+ * SPDX-License-Identifier: GPL-2.0+
+ */
+
+#include <common.h>
+#include <fuse.h>
+#include <asm/errno.h>
+#include <asm/io.h>
+#include <asm/arch/clock.h>
+#include <asm/arch/imx-regs.h>
+
+#define BO_CTRL_WR_UNLOCK 16
+#define BM_CTRL_WR_UNLOCK 0xffff0000
+#define BV_CTRL_WR_UNLOCK_KEY 0x3e77
+#define BM_CTRL_ERROR 0x00000200
+#define BM_CTRL_BUSY 0x00000100
+#define BO_CTRL_ADDR 0
+#define BM_CTRL_ADDR 0x0000007f
+
+#define BO_TIMING_STROBE_READ 16
+#define BM_TIMING_STROBE_READ 0x003f0000
+#define BV_TIMING_STROBE_READ_NS 37
+#define BO_TIMING_RELAX 12
+#define BM_TIMING_RELAX 0x0000f000
+#define BV_TIMING_RELAX_NS 17
+#define BO_TIMING_STROBE_PROG 0
+#define BM_TIMING_STROBE_PROG 0x00000fff
+#define BV_TIMING_STROBE_PROG_US 10
+
+#define BM_READ_CTRL_READ_FUSE 0x00000001
+
+#define BF(value, field) (((value) << BO_##field) & BM_##field)
+
+#define WRITE_POSTAMBLE_US 2
+
+static void wait_busy(struct ocotp_regs *regs, unsigned int delay_us)
+{
+ while (readl(&regs->ctrl) & BM_CTRL_BUSY)
+ udelay(delay_us);
+}
+
+static void clear_error(struct ocotp_regs *regs)
+{
+ writel(BM_CTRL_ERROR, &regs->ctrl_clr);
+}
+
+static int prepare_access(struct ocotp_regs **regs, u32 bank, u32 word,
+ int assert, const char *caller)
+{
+ *regs = (struct ocotp_regs *)OCOTP_BASE_ADDR;
+
+ if (bank >= ARRAY_SIZE((*regs)->bank) ||
+ word >= ARRAY_SIZE((*regs)->bank[0].fuse_regs) >> 2 ||
+ !assert) {
+ printf("mxc_ocotp %s(): Invalid argument\n", caller);
+ return -EINVAL;
+ }
+
+ enable_ocotp_clk(1);
+
+ wait_busy(*regs, 1);
+ clear_error(*regs);
+
+ return 0;
+}
+
+static int finish_access(struct ocotp_regs *regs, const char *caller)
+{
+ u32 err;
+
+ err = !!(readl(&regs->ctrl) & BM_CTRL_ERROR);
+ clear_error(regs);
+
+ enable_ocotp_clk(0);
+
+ if (err) {
+ printf("mxc_ocotp %s(): Access protect error\n", caller);
+ return -EIO;
+ }
+
+ return 0;
+}
+
+static int prepare_read(struct ocotp_regs **regs, u32 bank, u32 word, u32 *val,
+ const char *caller)
+{
+ return prepare_access(regs, bank, word, val != NULL, caller);
+}
+
+int fuse_read(u32 bank, u32 word, u32 *val)
+{
+ struct ocotp_regs *regs;
+ int ret;
+
+ ret = prepare_read(&regs, bank, word, val, __func__);
+ if (ret)
+ return ret;
+
+ *val = readl(&regs->bank[bank].fuse_regs[word << 2]);
+
+ return finish_access(regs, __func__);
+}
+
+static void set_timing(struct ocotp_regs *regs)
+{
+ u32 ipg_clk;
+ u32 relax, strobe_read, strobe_prog;
+ u32 timing;
+
+ ipg_clk = mxc_get_clock(MXC_IPG_CLK);
+
+ relax = DIV_ROUND_UP(ipg_clk * BV_TIMING_RELAX_NS, 1000000000) - 1;
+ strobe_read = DIV_ROUND_UP(ipg_clk * BV_TIMING_STROBE_READ_NS,
+ 1000000000) + 2 * (relax + 1) - 1;
+ strobe_prog = DIV_ROUND(ipg_clk * BV_TIMING_STROBE_PROG_US, 1000000) +
+ 2 * (relax + 1) - 1;
+
+ timing = BF(strobe_read, TIMING_STROBE_READ) |
+ BF(relax, TIMING_RELAX) |
+ BF(strobe_prog, TIMING_STROBE_PROG);
+
+ clrsetbits_le32(&regs->timing, BM_TIMING_STROBE_READ | BM_TIMING_RELAX |
+ BM_TIMING_STROBE_PROG, timing);
+}
+
+static void setup_direct_access(struct ocotp_regs *regs, u32 bank, u32 word,
+ int write)
+{
+ u32 wr_unlock = write ? BV_CTRL_WR_UNLOCK_KEY : 0;
+ u32 addr = bank << 3 | word;
+
+ set_timing(regs);
+ clrsetbits_le32(&regs->ctrl, BM_CTRL_WR_UNLOCK | BM_CTRL_ADDR,
+ BF(wr_unlock, CTRL_WR_UNLOCK) |
+ BF(addr, CTRL_ADDR));
+}
+
+int fuse_sense(u32 bank, u32 word, u32 *val)
+{
+ struct ocotp_regs *regs;
+ int ret;
+
+ ret = prepare_read(&regs, bank, word, val, __func__);
+ if (ret)
+ return ret;
+
+ setup_direct_access(regs, bank, word, false);
+ writel(BM_READ_CTRL_READ_FUSE, &regs->read_ctrl);
+ wait_busy(regs, 1);
+ *val = readl(&regs->read_fuse_data);
+
+ return finish_access(regs, __func__);
+}
+
+static int prepare_write(struct ocotp_regs **regs, u32 bank, u32 word,
+ const char *caller)
+{
+ return prepare_access(regs, bank, word, true, caller);
+}
+
+int fuse_prog(u32 bank, u32 word, u32 val)
+{
+ struct ocotp_regs *regs;
+ int ret;
+
+ ret = prepare_write(&regs, bank, word, __func__);
+ if (ret)
+ return ret;
+
+ setup_direct_access(regs, bank, word, true);
+ writel(val, &regs->data);
+ wait_busy(regs, BV_TIMING_STROBE_PROG_US);
+ udelay(WRITE_POSTAMBLE_US);
+
+ return finish_access(regs, __func__);
+}
+
+int fuse_override(u32 bank, u32 word, u32 val)
+{
+ struct ocotp_regs *regs;
+ int ret;
+
+ ret = prepare_write(&regs, bank, word, __func__);
+ if (ret)
+ return ret;
+
+ writel(val, &regs->bank[bank].fuse_regs[word << 2]);
+
+ return finish_access(regs, __func__);
+}
diff --git a/qemu/roms/u-boot/drivers/misc/mxs_ocotp.c b/qemu/roms/u-boot/drivers/misc/mxs_ocotp.c
new file mode 100644
index 000000000..545d3ebf5
--- /dev/null
+++ b/qemu/roms/u-boot/drivers/misc/mxs_ocotp.c
@@ -0,0 +1,311 @@
+/*
+ * Freescale i.MX28 OCOTP Driver
+ *
+ * Copyright (C) 2014 Marek Vasut <marex@denx.de>
+ *
+ * SPDX-License-Identifier: GPL-2.0+
+ *
+ * Note: The i.MX23/i.MX28 OCOTP block is a predecessor to the OCOTP block
+ * used in i.MX6 . While these blocks are very similar at the first
+ * glance, by digging deeper, one will notice differences (like the
+ * tight dependence on MXS power block, some completely new registers
+ * etc.) which would make common driver an ifdef nightmare :-(
+ */
+
+#include <common.h>
+#include <fuse.h>
+#include <asm/errno.h>
+#include <asm/io.h>
+#include <asm/arch/clock.h>
+#include <asm/arch/imx-regs.h>
+#include <asm/arch/sys_proto.h>
+
+#define MXS_OCOTP_TIMEOUT 100000
+
+static struct mxs_ocotp_regs *ocotp_regs =
+ (struct mxs_ocotp_regs *)MXS_OCOTP_BASE;
+static struct mxs_power_regs *power_regs =
+ (struct mxs_power_regs *)MXS_POWER_BASE;
+static struct mxs_clkctrl_regs *clkctrl_regs =
+ (struct mxs_clkctrl_regs *)MXS_CLKCTRL_BASE;
+
+static int mxs_ocotp_wait_busy_clear(void)
+{
+ uint32_t reg;
+ int timeout = MXS_OCOTP_TIMEOUT;
+
+ while (--timeout) {
+ reg = readl(&ocotp_regs->hw_ocotp_ctrl);
+ if (!(reg & OCOTP_CTRL_BUSY))
+ break;
+ udelay(10);
+ }
+
+ if (!timeout)
+ return -EINVAL;
+
+ /* Wait a little as per FSL datasheet's 'write postamble' section. */
+ udelay(10);
+
+ return 0;
+}
+
+static void mxs_ocotp_clear_error(void)
+{
+ writel(OCOTP_CTRL_ERROR, &ocotp_regs->hw_ocotp_ctrl_clr);
+}
+
+static int mxs_ocotp_read_bank_open(bool open)
+{
+ int ret = 0;
+
+ if (open) {
+ writel(OCOTP_CTRL_RD_BANK_OPEN,
+ &ocotp_regs->hw_ocotp_ctrl_set);
+
+ /*
+ * Wait before polling the BUSY bit, since the BUSY bit might
+ * be asserted only after a few HCLK cycles and if we were to
+ * poll immediatelly, we could miss the busy bit.
+ */
+ udelay(10);
+ ret = mxs_ocotp_wait_busy_clear();
+ } else {
+ writel(OCOTP_CTRL_RD_BANK_OPEN,
+ &ocotp_regs->hw_ocotp_ctrl_clr);
+ }
+
+ return ret;
+}
+
+static void mxs_ocotp_scale_vddio(bool enter, uint32_t *val)
+{
+ uint32_t scale_val;
+
+ if (enter) {
+ /*
+ * Enter the fuse programming VDDIO voltage setup. We start
+ * scaling the voltage from it's current value down to 2.8V
+ * which is the one and only correct voltage for programming
+ * the OCOTP fuses (according to datasheet).
+ */
+ scale_val = readl(&power_regs->hw_power_vddioctrl);
+ scale_val &= POWER_VDDIOCTRL_TRG_MASK;
+
+ /* Return the original voltage. */
+ *val = scale_val;
+
+ /*
+ * Start scaling VDDIO down to 0x2, which is 2.8V . Actually,
+ * the value 0x0 should be 2.8V, but that's not the case on
+ * most designs due to load etc., so we play safe. Undervolt
+ * can actually cause incorrect programming of the fuses and
+ * or reboots of the board.
+ */
+ while (scale_val > 2) {
+ clrsetbits_le32(&power_regs->hw_power_vddioctrl,
+ POWER_VDDIOCTRL_TRG_MASK, --scale_val);
+ udelay(500);
+ }
+ } else {
+ /* Start scaling VDDIO up to original value . */
+ for (scale_val = 2; scale_val <= *val; scale_val++) {
+ clrsetbits_le32(&power_regs->hw_power_vddioctrl,
+ POWER_VDDIOCTRL_TRG_MASK, scale_val);
+ udelay(500);
+ }
+ }
+
+ mdelay(10);
+}
+
+static int mxs_ocotp_wait_hclk_ready(void)
+{
+ uint32_t reg, timeout = MXS_OCOTP_TIMEOUT;
+
+ while (--timeout) {
+ reg = readl(&clkctrl_regs->hw_clkctrl_hbus);
+ if (!(reg & CLKCTRL_HBUS_ASM_BUSY))
+ break;
+ }
+
+ if (!timeout)
+ return -EINVAL;
+
+ return 0;
+}
+
+static int mxs_ocotp_scale_hclk(bool enter, uint32_t *val)
+{
+ uint32_t scale_val;
+ int ret;
+
+ ret = mxs_ocotp_wait_hclk_ready();
+ if (ret)
+ return ret;
+
+ /* Set CPU bypass */
+ writel(CLKCTRL_CLKSEQ_BYPASS_CPU,
+ &clkctrl_regs->hw_clkctrl_clkseq_set);
+
+ if (enter) {
+ /* Return the original HCLK clock speed. */
+ *val = readl(&clkctrl_regs->hw_clkctrl_hbus);
+ *val &= CLKCTRL_HBUS_DIV_MASK;
+
+ /* Scale the HCLK to 454/19 = 23.9 MHz . */
+ scale_val = (~19) << CLKCTRL_HBUS_DIV_OFFSET;
+ scale_val &= CLKCTRL_HBUS_DIV_MASK;
+ } else {
+ /* Scale the HCLK back to original frequency. */
+ scale_val = (~(*val)) << CLKCTRL_HBUS_DIV_OFFSET;
+ scale_val &= CLKCTRL_HBUS_DIV_MASK;
+ }
+
+ writel(CLKCTRL_HBUS_DIV_MASK,
+ &clkctrl_regs->hw_clkctrl_hbus_set);
+ writel(scale_val,
+ &clkctrl_regs->hw_clkctrl_hbus_clr);
+
+ mdelay(10);
+
+ ret = mxs_ocotp_wait_hclk_ready();
+ if (ret)
+ return ret;
+
+ /* Disable CPU bypass */
+ writel(CLKCTRL_CLKSEQ_BYPASS_CPU,
+ &clkctrl_regs->hw_clkctrl_clkseq_clr);
+
+ mdelay(10);
+
+ return 0;
+}
+
+static int mxs_ocotp_write_fuse(uint32_t addr, uint32_t mask)
+{
+ uint32_t hclk_val, vddio_val;
+ int ret;
+
+ /* Make sure the banks are closed for reading. */
+ ret = mxs_ocotp_read_bank_open(0);
+ if (ret) {
+ puts("Failed closing banks for reading!\n");
+ return ret;
+ }
+
+ ret = mxs_ocotp_scale_hclk(1, &hclk_val);
+ if (ret) {
+ puts("Failed scaling down the HCLK!\n");
+ return ret;
+ }
+ mxs_ocotp_scale_vddio(1, &vddio_val);
+
+ ret = mxs_ocotp_wait_busy_clear();
+ if (ret) {
+ puts("Failed waiting for ready state!\n");
+ goto fail;
+ }
+
+ /* Program the fuse address */
+ writel(addr | OCOTP_CTRL_WR_UNLOCK_KEY, &ocotp_regs->hw_ocotp_ctrl);
+
+ /* Program the data. */
+ writel(mask, &ocotp_regs->hw_ocotp_data);
+
+ udelay(10);
+
+ ret = mxs_ocotp_wait_busy_clear();
+ if (ret) {
+ puts("Failed waiting for ready state!\n");
+ goto fail;
+ }
+
+fail:
+ mxs_ocotp_scale_vddio(0, &vddio_val);
+ ret = mxs_ocotp_scale_hclk(0, &hclk_val);
+ if (ret) {
+ puts("Failed scaling up the HCLK!\n");
+ return ret;
+ }
+
+ return ret;
+}
+
+static int mxs_ocotp_read_fuse(uint32_t reg, uint32_t *val)
+{
+ int ret;
+
+ /* Register offset from CUST0 */
+ reg = ((uint32_t)&ocotp_regs->hw_ocotp_cust0) + (reg << 4);
+
+ ret = mxs_ocotp_wait_busy_clear();
+ if (ret) {
+ puts("Failed waiting for ready state!\n");
+ return ret;
+ }
+
+ mxs_ocotp_clear_error();
+
+ ret = mxs_ocotp_read_bank_open(1);
+ if (ret) {
+ puts("Failed opening banks for reading!\n");
+ return ret;
+ }
+
+ *val = readl(reg);
+
+ ret = mxs_ocotp_read_bank_open(0);
+ if (ret) {
+ puts("Failed closing banks for reading!\n");
+ return ret;
+ }
+
+ return ret;
+}
+
+static int mxs_ocotp_valid(u32 bank, u32 word)
+{
+ if (bank > 4)
+ return -EINVAL;
+ if (word > 7)
+ return -EINVAL;
+ return 0;
+}
+
+/*
+ * The 'fuse' command API
+ */
+int fuse_read(u32 bank, u32 word, u32 *val)
+{
+ int ret;
+
+ ret = mxs_ocotp_valid(bank, word);
+ if (ret)
+ return ret;
+
+ return mxs_ocotp_read_fuse((bank << 3) | word, val);
+}
+
+int fuse_prog(u32 bank, u32 word, u32 val)
+{
+ int ret;
+
+ ret = mxs_ocotp_valid(bank, word);
+ if (ret)
+ return ret;
+
+ return mxs_ocotp_write_fuse((bank << 3) | word, val);
+}
+
+int fuse_sense(u32 bank, u32 word, u32 *val)
+{
+ /* We do not support sensing :-( */
+ return -EINVAL;
+}
+
+int fuse_override(u32 bank, u32 word, u32 val)
+{
+ /* We do not support overriding :-( */
+ return -EINVAL;
+}
diff --git a/qemu/roms/u-boot/drivers/misc/ns87308.c b/qemu/roms/u-boot/drivers/misc/ns87308.c
new file mode 100644
index 000000000..8a92ccb88
--- /dev/null
+++ b/qemu/roms/u-boot/drivers/misc/ns87308.c
@@ -0,0 +1,101 @@
+/*
+ * (C) Copyright 2000
+ * Rob Taylor, Flying Pig Systems. robt@flyingpig.com.
+ *
+ * SPDX-License-Identifier: GPL-2.0+
+ */
+
+#include <config.h>
+
+#include <ns87308.h>
+
+void initialise_ns87308 (void)
+{
+#ifdef CONFIG_SYS_NS87308_PS2MOD
+ unsigned char data;
+
+ /*
+ * Switch floppy drive to PS/2 mode.
+ */
+ read_pnp_config(SUPOERIO_CONF1, &data);
+ data &= 0xFB;
+ write_pnp_config(SUPOERIO_CONF1, data);
+#endif
+
+#if (CONFIG_SYS_NS87308_DEVS & CONFIG_SYS_NS87308_KBC1)
+ PNP_SET_DEVICE_BASE(LDEV_KBC1, CONFIG_SYS_NS87308_KBC1_BASE);
+ write_pnp_config(LUN_CONFIG_REG, 0);
+ write_pnp_config(CBASE_HIGH, 0x00);
+ write_pnp_config(CBASE_LOW, 0x64);
+#endif
+
+#if (CONFIG_SYS_NS87308_DEVS & CONFIG_SYS_NS87308_MOUSE)
+ PNP_ACTIVATE_DEVICE(LDEV_MOUSE);
+#endif
+
+#if (CONFIG_SYS_NS87308_DEVS & CONFIG_SYS_NS87308_RTC_APC)
+ PNP_SET_DEVICE_BASE(LDEV_RTC_APC, CONFIG_SYS_NS87308_RTC_BASE);
+#endif
+
+#if (CONFIG_SYS_NS87308_DEVS & CONFIG_SYS_NS87308_FDC)
+ PNP_SET_DEVICE_BASE(LDEV_FDC, CONFIG_SYS_NS87308_FDC_BASE);
+ write_pnp_config(LUN_CONFIG_REG, 0x40);
+#endif
+
+#if (CONFIG_SYS_NS87308_DEVS & CONFIG_SYS_NS87308_RARP)
+ PNP_SET_DEVICE_BASE(LDEV_PARP, CONFIG_SYS_NS87308_LPT_BASE);
+#endif
+
+#if (CONFIG_SYS_NS87308_DEVS & CONFIG_SYS_NS87308_UART1)
+ PNP_SET_DEVICE_BASE(LDEV_UART1, CONFIG_SYS_NS87308_UART1_BASE);
+#endif
+
+#if (CONFIG_SYS_NS87308_DEVS & CONFIG_SYS_NS87308_UART2)
+ PNP_SET_DEVICE_BASE(LDEV_UART2, CONFIG_SYS_NS87308_UART2_BASE);
+#endif
+
+#if (CONFIG_SYS_NS87308_DEVS & CONFIG_SYS_NS87308_GPIO)
+ PNP_SET_DEVICE_BASE(LDEV_GPIO, CONFIG_SYS_NS87308_GPIO_BASE);
+#endif
+
+#if (CONFIG_SYS_NS87308_DEVS & CONFIG_SYS_NS87308_POWRMAN)
+#ifndef CONFIG_SYS_NS87308_PWMAN_BASE
+ PNP_ACTIVATE_DEVICE(LDEV_POWRMAN);
+#else
+ PNP_SET_DEVICE_BASE(LDEV_POWRMAN, CONFIG_SYS_NS87308_PWMAN_BASE);
+
+ /*
+ * Enable all units
+ */
+ write_pm_reg(CONFIG_SYS_NS87308_PWMAN_BASE, PWM_FER1, 0x7d);
+ write_pm_reg(CONFIG_SYS_NS87308_PWMAN_BASE, PWM_FER2, 0x87);
+
+#ifdef CONFIG_SYS_NS87308_PMC1
+ write_pm_reg(CONFIG_SYS_NS87308_PWMAN_BASE, PWM_PMC1, CONFIG_SYS_NS87308_PMC1);
+#endif
+
+#ifdef CONFIG_SYS_NS87308_PMC2
+ write_pm_reg(CONFIG_SYS_NS87308_PWMAN_BASE, PWM_PMC2, CONFIG_SYS_NS87308_PMC2);
+#endif
+
+#ifdef CONFIG_SYS_NS87308_PMC3
+ write_pm_reg(CONFIG_SYS_NS87308_PWMAN_BASE, PWM_PMC3, CONFIG_SYS_NS87308_PMC3);
+#endif
+#endif
+#endif
+
+#ifdef CONFIG_SYS_NS87308_CS0_BASE
+ PNP_PGCS_CSLINE_BASE(0, CONFIG_SYS_NS87308_CS0_BASE);
+ PNP_PGCS_CSLINE_CONF(0, CONFIG_SYS_NS87308_CS0_CONF);
+#endif
+
+#ifdef CONFIG_SYS_NS87308_CS1_BASE
+ PNP_PGCS_CSLINE_BASE(1, CONFIG_SYS_NS87308_CS1_BASE);
+ PNP_PGCS_CSLINE_CONF(1, CONFIG_SYS_NS87308_CS1_CONF);
+#endif
+
+#ifdef CONFIG_SYS_NS87308_CS2_BASE
+ PNP_PGCS_CSLINE_BASE(2, CONFIG_SYS_NS87308_CS2_BASE);
+ PNP_PGCS_CSLINE_CONF(2, CONFIG_SYS_NS87308_CS2_CONF);
+#endif
+}
diff --git a/qemu/roms/u-boot/drivers/misc/pdsp188x.c b/qemu/roms/u-boot/drivers/misc/pdsp188x.c
new file mode 100644
index 000000000..aa4351a0a
--- /dev/null
+++ b/qemu/roms/u-boot/drivers/misc/pdsp188x.c
@@ -0,0 +1,45 @@
+/*
+ * Copyright 2010 Sergey Poselenov, Emcraft Systems, <sposelenov@emcraft.com>
+ * Copyright 2010 Ilya Yanok, Emcraft Systems, <yanok@emcraft.com>
+ *
+ * SPDX-License-Identifier: GPL-2.0+
+ */
+
+#include <common.h>
+#include <led-display.h>
+#include <asm/io.h>
+
+#ifdef CONFIG_CMD_DISPLAY
+#define CWORD_CLEAR 0x80
+#define CLEAR_DELAY (110 * 2)
+#define DISPLAY_SIZE 8
+
+static int pos; /* Current display position */
+
+/* Handle different display commands */
+void display_set(int cmd)
+{
+ if (cmd & DISPLAY_CLEAR) {
+ out_8((unsigned char *)CONFIG_SYS_DISP_CWORD, CWORD_CLEAR);
+ udelay(1000 * CLEAR_DELAY);
+ }
+
+ if (cmd & DISPLAY_HOME) {
+ pos = 0;
+ }
+}
+
+/*
+ * Display a character at the current display position.
+ * Characters beyond the display size are ignored.
+ */
+int display_putc(char c)
+{
+ if (pos >= DISPLAY_SIZE)
+ return -1;
+
+ out_8((unsigned char *)CONFIG_SYS_DISP_CHR_RAM + pos++, c);
+
+ return c;
+}
+#endif
diff --git a/qemu/roms/u-boot/drivers/misc/status_led.c b/qemu/roms/u-boot/drivers/misc/status_led.c
new file mode 100644
index 000000000..ed9adb21d
--- /dev/null
+++ b/qemu/roms/u-boot/drivers/misc/status_led.c
@@ -0,0 +1,111 @@
+/*
+ * (C) Copyright 2000-2003
+ * Wolfgang Denk, DENX Software Engineering, wd@denx.de.
+ *
+ * SPDX-License-Identifier: GPL-2.0+
+ */
+
+#include <common.h>
+#include <status_led.h>
+
+/*
+ * The purpose of this code is to signal the operational status of a
+ * target which usually boots over the network; while running in
+ * U-Boot, a status LED is blinking. As soon as a valid BOOTP reply
+ * message has been received, the LED is turned off. The Linux
+ * kernel, once it is running, will start blinking the LED again,
+ * with another frequency.
+ */
+
+/* ------------------------------------------------------------------------- */
+
+typedef struct {
+ led_id_t mask;
+ int state;
+ int period;
+ int cnt;
+} led_dev_t;
+
+led_dev_t led_dev[] = {
+ { STATUS_LED_BIT,
+ STATUS_LED_STATE,
+ STATUS_LED_PERIOD,
+ 0,
+ },
+#if defined(STATUS_LED_BIT1)
+ { STATUS_LED_BIT1,
+ STATUS_LED_STATE1,
+ STATUS_LED_PERIOD1,
+ 0,
+ },
+#endif
+#if defined(STATUS_LED_BIT2)
+ { STATUS_LED_BIT2,
+ STATUS_LED_STATE2,
+ STATUS_LED_PERIOD2,
+ 0,
+ },
+#endif
+#if defined(STATUS_LED_BIT3)
+ { STATUS_LED_BIT3,
+ STATUS_LED_STATE3,
+ STATUS_LED_PERIOD3,
+ 0,
+ },
+#endif
+};
+
+#define MAX_LED_DEV (sizeof(led_dev)/sizeof(led_dev_t))
+
+static int status_led_init_done = 0;
+
+static void status_led_init (void)
+{
+ led_dev_t *ld;
+ int i;
+
+ for (i = 0, ld = led_dev; i < MAX_LED_DEV; i++, ld++)
+ __led_init (ld->mask, ld->state);
+ status_led_init_done = 1;
+}
+
+void status_led_tick (ulong timestamp)
+{
+ led_dev_t *ld;
+ int i;
+
+ if (!status_led_init_done)
+ status_led_init ();
+
+ for (i = 0, ld = led_dev; i < MAX_LED_DEV; i++, ld++) {
+
+ if (ld->state != STATUS_LED_BLINKING)
+ continue;
+
+ if (++ld->cnt >= ld->period) {
+ __led_toggle (ld->mask);
+ ld->cnt -= ld->period;
+ }
+
+ }
+}
+
+void status_led_set (int led, int state)
+{
+ led_dev_t *ld;
+
+ if (led < 0 || led >= MAX_LED_DEV)
+ return;
+
+ if (!status_led_init_done)
+ status_led_init ();
+
+ ld = &led_dev[led];
+
+ ld->state = state;
+ if (state == STATUS_LED_BLINKING) {
+ ld->cnt = 0; /* always start with full period */
+ state = STATUS_LED_ON; /* always start with LED _ON_ */
+ }
+ __led_set (ld->mask, state);
+}
diff --git a/qemu/roms/u-boot/drivers/misc/twl4030_led.c b/qemu/roms/u-boot/drivers/misc/twl4030_led.c
new file mode 100644
index 000000000..432e74125
--- /dev/null
+++ b/qemu/roms/u-boot/drivers/misc/twl4030_led.c
@@ -0,0 +1,34 @@
+/*
+ * Copyright (c) 2009 Wind River Systems, Inc.
+ * Tom Rix <Tom.Rix at windriver.com>
+ *
+ * SPDX-License-Identifier: GPL-2.0+
+ *
+ * twl4030_led_init is from cpu/omap3/common.c, power_init_r
+ *
+ * (C) Copyright 2004-2008
+ * Texas Instruments, <www.ti.com>
+ *
+ * Author :
+ * Sunil Kumar <sunilsaini05 at gmail.com>
+ * Shashi Ranjan <shashiranjanmca05 at gmail.com>
+ *
+ * Derived from Beagle Board and 3430 SDP code by
+ * Richard Woodruff <r-woodruff2 at ti.com>
+ * Syed Mohammed Khasim <khasim at ti.com>
+ */
+
+#include <twl4030.h>
+
+void twl4030_led_init(unsigned char ledon_mask)
+{
+ /* LEDs need to have corresponding PWMs enabled */
+ if (ledon_mask & TWL4030_LED_LEDEN_LEDAON)
+ ledon_mask |= TWL4030_LED_LEDEN_LEDAPWM;
+ if (ledon_mask & TWL4030_LED_LEDEN_LEDBON)
+ ledon_mask |= TWL4030_LED_LEDEN_LEDBPWM;
+
+ twl4030_i2c_write_u8(TWL4030_CHIP_LED, TWL4030_LED_LEDEN,
+ ledon_mask);
+
+}