summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authormartin yan <martin.yan@microchip.corp-partner.google.com>2022-01-14 11:04:50 -0500
committerCommit Bot <commit-bot@chromium.org>2022-01-24 20:12:52 +0000
commit294e26a203fb74d2a3a3218279b6e18ca22780be (patch)
tree62ee3de9a81598a226bb76409e309f8c7c1142c7
parent96525123ba63b081f0855197961f8029539b937b (diff)
downloadchrome-ec-294e26a203fb74d2a3a3218279b6e18ca22780be.tar.gz
zephyr: mchp: Add cros_flash driver
Add cros_flash driver and related configs BUG=none BRANCH=main TEST=zmake testall Signed-off-by: martin yan <martin.yan@microchip.corp-partner.google.com> Change-Id: I4b8aadf5820871e0abcff0306eefae634a4ee8df Reviewed-on: https://chromium-review.googlesource.com/c/chromiumos/platform/ec/+/3388451 Reviewed-by: Keith Short <keithshort@chromium.org>
-rw-r--r--zephyr/Kconfig.flash2
-rw-r--r--zephyr/Kconfig.header3
-rw-r--r--zephyr/Kconfig.init_priority1
-rw-r--r--zephyr/drivers/cros_flash/CMakeLists.txt5
-rw-r--r--zephyr/drivers/cros_flash/Kconfig23
-rw-r--r--zephyr/drivers/cros_flash/cros_flash_xec.c617
-rw-r--r--zephyr/dts/bindings/cros_flash/microchip,xec-cros-flash.yaml9
7 files changed, 658 insertions, 2 deletions
diff --git a/zephyr/Kconfig.flash b/zephyr/Kconfig.flash
index f6a8b2d103..0e0fd6ce49 100644
--- a/zephyr/Kconfig.flash
+++ b/zephyr/Kconfig.flash
@@ -6,6 +6,7 @@ if PLATFORM_EC_FLASH_CROS
config PLATFORM_EC_SPI_FLASH_REGS
bool "Enable SPI flash registers"
+ default y if SOC_FAMILY_MEC
default y if SOC_FAMILY_NPCX
help
Enables flash registers for SPI flash (both internal and external).
@@ -64,6 +65,7 @@ config PLATFORM_EC_CONSOLE_CMD_SYSJUMP
choice PLATFORM_EC_STORAGE_TYPE
prompt "Code storage type"
default PLATFORM_EC_EXTERNAL_STORAGE if SOC_FAMILY_NPCX
+ default PLATFORM_EC_EXTERNAL_STORAGE if SOC_FAMILY_MEC
default PLATFORM_EC_INTERNAL_STORAGE if SOC_FAMILY_RISCV_ITE
help
Sets the EC code storage type.
diff --git a/zephyr/Kconfig.header b/zephyr/Kconfig.header
index 43e66ec3e4..e5c137b99e 100644
--- a/zephyr/Kconfig.header
+++ b/zephyr/Kconfig.header
@@ -6,7 +6,7 @@ config PLATFORM_EC_RO_HEADER
bool "RO section includes a header"
default y
depends on CROS_EC_RO
- depends on SOC_FAMILY_NPCX
+ depends on SOC_FAMILY_NPCX || SOC_FAMILY_MEC
help
The RO image residing on flash memory has a header section. The header
is used on some chips (such as the npcx) to load the image correctly
@@ -24,6 +24,7 @@ config PLATFORM_EC_RO_HEADER_OFFSET
config PLATFORM_EC_RO_HEADER_SIZE
hex "Size of the RO header"
default 0x40 if SOC_FAMILY_NPCX
+ default 0x140 if SOC_SERIES_MEC172X
default 0x0
help
The size of the RO header in bytes. This values should come from the
diff --git a/zephyr/Kconfig.init_priority b/zephyr/Kconfig.init_priority
index 5370072c2c..c974bb4d8f 100644
--- a/zephyr/Kconfig.init_priority
+++ b/zephyr/Kconfig.init_priority
@@ -5,6 +5,7 @@
config PLATFORM_EC_FLASH_INIT_PRIORITY
int "Init priority of the flash module"
default 90 if SOC_FAMILY_NPCX
+ default 90 if SOC_FAMILY_MEC
default 52
help
The initialization priority of the flash module. This should always be
diff --git a/zephyr/drivers/cros_flash/CMakeLists.txt b/zephyr/drivers/cros_flash/CMakeLists.txt
index 6611589ad4..1846d10576 100644
--- a/zephyr/drivers/cros_flash/CMakeLists.txt
+++ b/zephyr/drivers/cros_flash/CMakeLists.txt
@@ -1,4 +1,7 @@
-# SPDX-License-Identifier: Apache-2.0
+# Copyright 2021 The Chromium OS Authors. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
zephyr_library_sources_ifdef(CONFIG_CROS_FLASH_IT8XXX2 cros_flash_it8xxx2.c)
zephyr_library_sources_ifdef(CONFIG_CROS_FLASH_NPCX cros_flash_npcx.c)
+zephyr_library_sources_ifdef(CONFIG_CROS_FLASH_XEC cros_flash_xec.c)
diff --git a/zephyr/drivers/cros_flash/Kconfig b/zephyr/drivers/cros_flash/Kconfig
index 05de5c5e5b..5c73e0c3b9 100644
--- a/zephyr/drivers/cros_flash/Kconfig
+++ b/zephyr/drivers/cros_flash/Kconfig
@@ -33,3 +33,26 @@ config CROS_FLASH_IT8XXX2
This option enables the flash driver for the it8xxx2 chip. We can
access the flash by read, write and erase. The it8xxx2 flash size
is 1M byte.
+
+config CROS_FLASH_XEC
+ bool "Microchip XEC flash driver for the Zephyr shim"
+ depends on SOC_FAMILY_MEC
+ default y
+ help
+ This option enables the flash driver for the MEC172x chips. Flash
+ access is via the QSPI driver to one of three ports: internal 512KB
+ SPI flash in the MEC1727 or external shared or private ports on
+ MEC1723, etc.
+
+if CROS_FLASH_XEC
+
+config CROS_FLASH_XEC_INIT_PRIORITY
+ int "Microchip XEC flash driver priority for the Zephyr shim"
+ default 85
+ help
+ This sets the priority of the MCHP flash driver for zephyr shim.
+ This driver depends on the SPI controller and SPI NOR flash drivers.
+ Its priority must be lower than CONFIG_SPI_INIT_PRIORITY and
+ CONFIG_SPI_NOR_INIT_PRIORITY.
+
+endif # CROS_FLASH_XEC
diff --git a/zephyr/drivers/cros_flash/cros_flash_xec.c b/zephyr/drivers/cros_flash/cros_flash_xec.c
new file mode 100644
index 0000000000..e9a8b6a3b0
--- /dev/null
+++ b/zephyr/drivers/cros_flash/cros_flash_xec.c
@@ -0,0 +1,617 @@
+/* Copyright 2022 The Chromium OS Authors. All rights reserved.
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+
+#define DT_DRV_COMPAT microchip_xec_cros_flash
+
+#include <drivers/cros_flash.h>
+#include <drivers/flash.h>
+#include <drivers/gpio.h>
+#include <drivers/spi.h>
+#include <kernel.h>
+#include <logging/log.h>
+#include <soc.h>
+
+#include "flash.h"
+#include "gpio.h"
+#include "spi_flash_reg.h"
+#include "../drivers/flash/spi_nor.h"
+
+LOG_MODULE_REGISTER(cros_flash, LOG_LEVEL_ERR);
+
+static int all_protected;
+static int addr_prot_start;
+static int addr_prot_length;
+static uint8_t saved_sr1;
+
+/* Device data */
+struct cros_flash_xec_data {
+ const struct device *flash_dev;
+ const struct device *spi_ctrl_dev;
+};
+
+static struct spi_config spi_cfg;
+
+#define FLASH_DEV DT_NODELABEL(int_flash)
+#define SPI_CONTROLLER_DEV DT_NODELABEL(spi0)
+
+/* cros ec flash local functions */
+static int cros_flash_xec_get_status_reg(const struct device *dev,
+ uint8_t cmd_code, uint8_t *data)
+{
+ uint8_t opcode;
+ struct cros_flash_xec_data *dev_data = dev->data;
+
+ struct spi_buf spi_buf[2] = {
+ [0] = {
+ .buf = &opcode,
+ .len = 1,
+ },
+ [1] = {
+ .buf = data,
+ .len = 1,
+ }
+ };
+
+ const struct spi_buf_set tx_set = {
+ .buffers = spi_buf,
+ .count = 2,
+ };
+
+ const struct spi_buf_set rx_set = {
+ .buffers = spi_buf,
+ .count = 2,
+ };
+
+ if (data == 0)
+ return -EINVAL;
+
+ opcode = cmd_code;
+ return spi_transceive(dev_data->spi_ctrl_dev, &spi_cfg, &tx_set,
+ &rx_set);
+}
+
+static int cros_flash_xec_wait_ready(const struct device *dev)
+{
+ int wait_period = 10; /* 10 us period t0 check status register */
+ int timeout = (10 * USEC_PER_SEC) / wait_period; /* 10 seconds */
+
+ do {
+ uint8_t reg;
+
+ cros_flash_xec_get_status_reg(dev, SPI_NOR_CMD_RDSR, &reg);
+ if ((reg & SPI_NOR_WIP_BIT) == 0)
+ break;
+
+ k_usleep(wait_period);
+ } while (--timeout); /* Wait for busy bit clear */
+
+ if (timeout)
+ return 0;
+ else
+ return -ETIMEDOUT;
+}
+
+/* Check the BUSY bit is cleared and WE bit is set */
+static int cros_flash_xec_wait_ready_and_we(const struct device *dev)
+{
+ int wait_period = 10; /* 10 us period t0 check status register */
+ int timeout = (10 * USEC_PER_SEC) / wait_period; /* 10 seconds */
+
+ do {
+ uint8_t reg;
+
+ cros_flash_xec_get_status_reg(dev, SPI_NOR_CMD_RDSR, &reg);
+ if ((reg & SPI_NOR_WIP_BIT) == 0 &&
+ (reg & SPI_NOR_WEL_BIT) != 0) {
+ break;
+ }
+ k_usleep(wait_period);
+ } while (--timeout); /* Wait for busy bit clear */
+
+ if (timeout)
+ return 0;
+ else
+ return -ETIMEDOUT;
+}
+
+static int cros_flash_xec_set_write_enable(const struct device *dev)
+{
+ int ret;
+ uint8_t opcode = SPI_NOR_CMD_WREN;
+ struct cros_flash_xec_data *data = dev->data;
+
+ struct spi_buf spi_buf = {
+ .buf = &opcode,
+ .len = 1,
+ };
+
+ const struct spi_buf_set tx_set = {
+ .buffers = &spi_buf,
+ .count = 1,
+ };
+
+ /* Wait for previous operation to complete */
+ ret = cros_flash_xec_wait_ready(dev);
+ if (ret != 0)
+ return ret;
+
+ /* Write enable command */
+ ret = spi_transceive(data->spi_ctrl_dev, &spi_cfg, &tx_set, NULL);
+ if (ret != 0)
+ return ret;
+
+ /* Wait for flash is not busy */
+ return cros_flash_xec_wait_ready_and_we(dev);
+}
+
+static int cros_flash_xec_set_status_reg(const struct device *dev,
+ uint8_t *data)
+{
+ uint8_t opcode = SPI_NOR_CMD_WRSR;
+ int ret = 0;
+ struct cros_flash_xec_data *dev_data = dev->data;
+
+ struct spi_buf spi_buf[2] = {
+ [0] = {
+ .buf = &opcode,
+ .len = 1,
+ },
+ [1] = {
+ .buf = data,
+ .len = 1,
+ }
+ };
+
+ const struct spi_buf_set tx_set = {
+ .buffers = spi_buf,
+ .count = 2,
+ };
+
+ if (data == 0)
+ return -EINVAL;
+
+ /* Enable write */
+ ret = cros_flash_xec_set_write_enable(dev);
+ if (ret != 0)
+ return ret;
+
+ ret = spi_transceive(dev_data->spi_ctrl_dev, &spi_cfg, &tx_set, NULL);
+ if (ret != 0)
+ return ret;
+ return cros_flash_xec_wait_ready(dev);
+}
+
+static int cros_flash_xec_write_protection_set(const struct device *dev,
+ bool enable)
+{
+ int ret = 0;
+
+ /* Write protection can be cleared only by core domain reset */
+ if (!enable) {
+ LOG_ERR("WP can be disabled only via core domain reset ");
+ return -ENOTSUP;
+ }
+ /* MCHP TODO need API call to set flash WP# pin active: GPIO driver? */
+
+ return ret;
+}
+
+static int cros_flash_xec_write_protection_is_set(const struct device *dev)
+{
+ /* MCHP TODO - Read WP# pin state: GPIO driver? */
+ return 0;
+}
+
+static int cros_flash_xec_uma_lock(const struct device *dev, bool enable)
+{
+ struct cros_flash_xec_data *data = dev->data;
+
+ if (enable)
+ spi_cfg.operation |= SPI_LOCK_ON;
+ else
+ spi_cfg.operation &= ~SPI_LOCK_ON;
+
+ return spi_transceive(data->spi_ctrl_dev, &spi_cfg, NULL, NULL);
+}
+
+static void flash_get_status(const struct device *dev, uint8_t *sr1)
+{
+ if (all_protected) {
+ *sr1 = saved_sr1;
+ return;
+ }
+
+ /* Lock physical flash operations */
+ crec_flash_lock_mapped_storage(1);
+
+ /* Read status register1 */
+ cros_flash_xec_get_status_reg(dev, SPI_NOR_CMD_RDSR, sr1);
+
+ /* Unlock physical flash operations */
+ crec_flash_lock_mapped_storage(0);
+}
+
+static int flash_set_status(const struct device *dev, uint8_t sr1)
+{
+ int rv;
+ uint8_t regs[2];
+
+ regs[0] = sr1;
+ regs[1] = 0;
+
+ /* Lock physical flash operations */
+ crec_flash_lock_mapped_storage(1);
+ rv = cros_flash_xec_set_status_reg(dev, regs);
+ /* Unlock physical flash operations */
+ crec_flash_lock_mapped_storage(0);
+
+ return rv;
+}
+
+static int is_int_flash_protected(const struct device *dev)
+{
+ return cros_flash_xec_write_protection_is_set(dev);
+}
+
+static void flash_protect_int_flash(const struct device *dev, int enable)
+{
+ /*
+ * Please notice the type of WP_IF bit is R/W1S. Once it's set,
+ * only rebooting EC can clear it.
+ */
+ if (enable)
+ cros_flash_xec_write_protection_set(dev, enable);
+}
+
+static void flash_uma_lock(const struct device *dev, int enable)
+{
+ if (enable && !all_protected) {
+ /*
+ * Store SR1 for later use since we're about to lock
+ * out all access (including read access) to these regs.
+ */
+ flash_get_status(dev, &saved_sr1);
+ }
+
+ cros_flash_xec_uma_lock(dev, enable);
+ all_protected = enable;
+}
+
+static int flash_set_status_for_prot(const struct device *dev, int reg1)
+{
+ /*
+ * Writing SR regs will fail if our UMA lock is enabled. If WP
+ * is deasserted then remove the lock and allow the write.
+ */
+ if (all_protected) {
+ if (is_int_flash_protected(dev))
+ return EC_ERROR_ACCESS_DENIED;
+
+ if (crec_flash_get_protect() & EC_FLASH_PROTECT_GPIO_ASSERTED)
+ return EC_ERROR_ACCESS_DENIED;
+
+ flash_uma_lock(dev, 0);
+ }
+
+ /*
+ * If WP# is active and ec doesn't protect the status registers of
+ * internal spi-flash, protect it now before setting them.
+ */
+#ifdef CONFIG_WP_ACTIVE_HIGH
+ flash_protect_int_flash(dev, gpio_get_level(GPIO_WP));
+#else
+ flash_protect_int_flash(dev, !gpio_get_level(GPIO_WP_L));
+#endif /*_CONFIG_WP_ACTIVE_HIGH_*/
+
+ flash_set_status(dev, reg1);
+
+ spi_flash_reg_to_protect(reg1, 0, &addr_prot_start,
+ &addr_prot_length);
+
+ return EC_SUCCESS;
+}
+
+static int flash_check_prot_reg(const struct device *dev, unsigned int offset,
+ unsigned int bytes)
+{
+ unsigned int start;
+ unsigned int len;
+ uint8_t sr1;
+ int rv = EC_SUCCESS;
+
+ /*
+ * If WP# is active and ec doesn't protect the status registers of
+ * internal spi-flash, protect it now.
+ */
+#ifdef CONFIG_WP_ACTIVE_HIGH
+ flash_protect_int_flash(dev, gpio_get_level(GPIO_WP));
+#else
+ flash_protect_int_flash(dev, !gpio_get_level(GPIO_WP_L));
+#endif /* CONFIG_WP_ACTIVE_HIGH */
+
+ /* Invalid value */
+ if (offset + bytes > CONFIG_FLASH_SIZE_BYTES)
+ return EC_ERROR_INVAL;
+
+ /* Compute current protect range */
+ flash_get_status(dev, &sr1);
+ rv = spi_flash_reg_to_protect(sr1, 0, &start, &len);
+ if (rv)
+ return rv;
+
+ /* Check if ranges overlap */
+ if (MAX(start, offset) < MIN(start + len, offset + bytes))
+ return EC_ERROR_ACCESS_DENIED;
+
+ return EC_SUCCESS;
+}
+
+static int flash_write_prot_reg(const struct device *dev, unsigned int offset,
+ unsigned int bytes, int hw_protect)
+{
+ int rv;
+ uint8_t sr1;
+
+ /* Invalid values */
+ if (offset + bytes > CONFIG_FLASH_SIZE_BYTES)
+ return EC_ERROR_INVAL;
+
+ /* Compute desired protect range */
+ flash_get_status(dev, &sr1);
+ rv = spi_flash_protect_to_reg(offset, bytes, &sr1, 0);
+ if (rv)
+ return rv;
+
+ if (hw_protect)
+ sr1 |= SPI_FLASH_SR1_SRP0;
+
+ return flash_set_status_for_prot(dev, sr1);
+}
+
+static int flash_check_prot_range(unsigned int offset, unsigned int bytes)
+{
+ /* Invalid value */
+ if (offset + bytes > CONFIG_FLASH_SIZE_BYTES)
+ return EC_ERROR_INVAL;
+
+ /* Check if ranges overlap */
+ if (MAX(addr_prot_start, offset) <
+ MIN(addr_prot_start + addr_prot_length, offset + bytes)) {
+ return EC_ERROR_ACCESS_DENIED;
+ }
+
+ return EC_SUCCESS;
+}
+
+/* cros ec flash api functions */
+static int cros_flash_xec_init(const struct device *dev)
+{
+ /* Initialize UMA to unlocked */
+ flash_uma_lock(dev, 0);
+
+ /*
+ * Protect status registers of internal spi-flash if WP# is active
+ * during ec initialization.
+ */
+#ifdef CONFIG_WP_ACTIVE_HIGH
+ flash_protect_int_flash(dev, gpio_get_level(GPIO_WP));
+#else
+ flash_protect_int_flash(dev, !gpio_get_level(GPIO_WP_L));
+#endif /*CONFIG_WP_ACTIVE_HIGH */
+
+ return 0;
+}
+
+/* TODO(b/205175314): Migrate cros-flash driver to Zephyr flash driver) */
+static int cros_flash_xec_read(const struct device *dev, int offset, int size,
+ char *dst_data)
+{
+ struct cros_flash_xec_data *data = dev->data;
+
+ return flash_read(data->flash_dev, offset, dst_data, size);
+}
+
+static int cros_flash_xec_write(const struct device *dev, int offset, int size,
+ const char *src_data)
+{
+ int ret = 0;
+ struct cros_flash_xec_data *data = dev->data;
+
+ /* check protection */
+ if (all_protected)
+ return EC_ERROR_ACCESS_DENIED;
+
+ /* check protection */
+ if (flash_check_prot_range(offset, size))
+ return EC_ERROR_ACCESS_DENIED;
+
+ /* Invalid data pointer? */
+ if (src_data == 0)
+ return -EINVAL;
+
+ ret = flash_write(data->flash_dev, offset, src_data, size);
+
+ return ret;
+}
+
+static int cros_flash_xec_erase(const struct device *dev, int offset, int size)
+{
+ int ret = 0;
+ struct cros_flash_xec_data *data = dev->data;
+
+ /* check protection */
+ if (all_protected)
+ return EC_ERROR_ACCESS_DENIED;
+
+ /* check protection */
+ if (flash_check_prot_range(offset, size))
+ return EC_ERROR_ACCESS_DENIED;
+
+ /* address must be aligned to erase size */
+ if ((offset % CONFIG_FLASH_ERASE_SIZE) != 0)
+ return -EINVAL;
+
+ /* Erase size must be a non-zero multiple of sectors */
+ if ((size == 0) || (size % CONFIG_FLASH_ERASE_SIZE) != 0)
+ return -EINVAL;
+
+ ret = flash_erase(data->flash_dev, offset, size);
+
+ return ret;
+}
+
+static int cros_flash_xec_get_protect(const struct device *dev, int bank)
+{
+ uint32_t addr = bank * CONFIG_FLASH_BANK_SIZE;
+
+ return flash_check_prot_reg(dev, addr, CONFIG_FLASH_BANK_SIZE);
+}
+
+static uint32_t cros_flash_xec_get_protect_flags(const struct device *dev)
+{
+ uint32_t flags = 0;
+ int rv;
+ uint8_t sr1;
+ unsigned int start, len;
+
+ /* Check if WP region is protected in status register */
+ rv = flash_check_prot_reg(dev, WP_BANK_OFFSET * CONFIG_FLASH_BANK_SIZE,
+ WP_BANK_COUNT * CONFIG_FLASH_BANK_SIZE);
+ if (rv == EC_ERROR_ACCESS_DENIED)
+ flags |= EC_FLASH_PROTECT_RO_AT_BOOT;
+ else if (rv)
+ return EC_FLASH_PROTECT_ERROR_UNKNOWN;
+
+ /*
+ * If the status register protects a range, but SRP0 is not set,
+ * or Quad Enable (QE) is set,
+ * flags should indicate EC_FLASH_PROTECT_ERROR_INCONSISTENT.
+ */
+ flash_get_status(dev, &sr1);
+ rv = spi_flash_reg_to_protect(sr1, 0, &start, &len);
+ if (rv)
+ return EC_FLASH_PROTECT_ERROR_UNKNOWN;
+
+ if (len && (!(sr1 & SPI_FLASH_SR1_SRP0)))
+ flags |= EC_FLASH_PROTECT_ERROR_INCONSISTENT;
+
+ /* Read all-protected state from our shadow copy */
+ if (all_protected)
+ flags |= EC_FLASH_PROTECT_ALL_NOW;
+
+ return flags;
+}
+
+static int cros_flash_xec_protect_at_boot(const struct device *dev,
+ uint32_t new_flags)
+{
+ int ret;
+
+ if ((new_flags & (EC_FLASH_PROTECT_RO_AT_BOOT |
+ EC_FLASH_PROTECT_ALL_AT_BOOT)) == 0) {
+ /* Clear protection bits in status register */
+ return flash_set_status_for_prot(dev, 0);
+ }
+
+ ret = flash_write_prot_reg(dev, CONFIG_WP_STORAGE_OFF,
+ CONFIG_WP_STORAGE_SIZE, 1);
+
+ /*
+ * Set UMA_LOCK bit for locking all UMA transaction.
+ * But we still can read directly from flash mapping address
+ */
+ if (new_flags & EC_FLASH_PROTECT_ALL_AT_BOOT)
+ flash_uma_lock(dev, 1);
+
+ return ret;
+}
+
+static int cros_flash_xec_protect_now(const struct device *dev, int all)
+{
+ if (all) {
+ /*
+ * Set UMA_LOCK bit for locking all UMA transaction.
+ * But we still can read directly from flash mapping address
+ */
+ flash_uma_lock(dev, 1);
+ } else {
+ /* TODO: Implement RO "now" protection */
+ }
+
+ return EC_SUCCESS;
+}
+
+static int cros_flash_xec_get_jedec_id(const struct device *dev,
+ uint8_t *manufacturer, uint16_t *device)
+{
+ int ret;
+ uint8_t jedec_id[3];
+ struct cros_flash_xec_data *data = dev->data;
+
+ /* Lock physical flash operations */
+ crec_flash_lock_mapped_storage(1);
+
+ ret = flash_read_jedec_id(data->flash_dev, jedec_id);
+ if (ret == 0) {
+ *manufacturer = jedec_id[0];
+ *device = (jedec_id[1] << 8) | jedec_id[2];
+ }
+
+ /* Unlock physical flash operations */
+ crec_flash_lock_mapped_storage(0);
+
+ return ret;
+}
+
+static int cros_flash_xec_get_status(const struct device *dev, uint8_t *sr1,
+ uint8_t *sr2)
+{
+ flash_get_status(dev, sr1);
+ *sr2 = 0;
+
+ return EC_SUCCESS;
+}
+
+/* cros ec flash driver registration */
+static const struct cros_flash_driver_api cros_flash_xec_driver_api = {
+ .init = cros_flash_xec_init,
+ .physical_read = cros_flash_xec_read,
+ .physical_write = cros_flash_xec_write,
+ .physical_erase = cros_flash_xec_erase,
+ .physical_get_protect = cros_flash_xec_get_protect,
+ .physical_get_protect_flags = cros_flash_xec_get_protect_flags,
+ .physical_protect_at_boot = cros_flash_xec_protect_at_boot,
+ .physical_protect_now = cros_flash_xec_protect_now,
+ .physical_get_jedec_id = cros_flash_xec_get_jedec_id,
+ .physical_get_status = cros_flash_xec_get_status,
+};
+
+static int flash_xec_init(const struct device *dev)
+{
+ struct cros_flash_xec_data *data = dev->data;
+
+ data->flash_dev = DEVICE_DT_GET(FLASH_DEV);
+ if (!device_is_ready(data->flash_dev)) {
+ LOG_ERR("%s device not ready", data->flash_dev->name);
+ return -ENODEV;
+ }
+
+ data->spi_ctrl_dev = DEVICE_DT_GET(SPI_CONTROLLER_DEV);
+ if (!device_is_ready(data->spi_ctrl_dev)) {
+ LOG_ERR("%s device not ready", data->spi_ctrl_dev->name);
+ return -ENODEV;
+ }
+
+ return EC_SUCCESS;
+}
+
+#if CONFIG_CROS_FLASH_XEC_INIT_PRIORITY <= CONFIG_SPI_NOR_INIT_PRIORITY
+#error "CONFIG_CROS_FLASH_XEC_INIT_PRIORITY must be greater than" \
+ "CONFIG_SPI_NOR_INIT_PRIORITY."
+#endif
+static struct cros_flash_xec_data cros_flash_data;
+DEVICE_DT_INST_DEFINE(0, flash_xec_init, NULL, &cros_flash_data, NULL,
+ POST_KERNEL, CONFIG_CROS_FLASH_XEC_INIT_PRIORITY,
+ &cros_flash_xec_driver_api);
diff --git a/zephyr/dts/bindings/cros_flash/microchip,xec-cros-flash.yaml b/zephyr/dts/bindings/cros_flash/microchip,xec-cros-flash.yaml
new file mode 100644
index 0000000000..2b9aea1554
--- /dev/null
+++ b/zephyr/dts/bindings/cros_flash/microchip,xec-cros-flash.yaml
@@ -0,0 +1,9 @@
+# Copyright 2022 The Chromium OS Authors. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+description: Microchip, XEC-cros-flash node
+
+compatible: "microchip,xec-cros-flash"
+
+include: cros-flash-controller.yaml