[U-Boot] [RFC PATCH] sf: New SF-NOR framework
Jagannadha Sutradharudu Teki
jagannadh.teki at gmail.com
Tue Nov 11 21:50:35 CET 2014
This is long lasting work that I did last few months back,
I'm sure it's where much need now.
- spi driver: drivers/spi/fsl_qspi.c
- flash attributes in spi_slave {} and
- etc ...
making spi subsystem becomes more flash specific rather operating
as a generic spi bus. So SF-NOR divides normal spi flash operations
through generic SPI API's(sf_spi.c) and more spi flash(sf) specific
operations through SF NOR API's.
So the controllers those are operating more on flash needs to
write a driver on drivers/mtd/spi/ example fsl_qspi.c
I have not tested more accuratly as of now, will come back again
with new feature additions/removal, zynq_qspi additions and more...
Note: dm-spi ops can gets effected with this new framework
{ .ops = &spi_flash_std_ops, } and will fix that in next
version patches.
Signed-off-by: Jagannadha Sutradharudu Teki <jagannadh.teki at gmail.com>
---
doc/SPI/README.sf-nor | 51 ++++++
drivers/mtd/spi/Makefile | 4 +-
drivers/mtd/spi/sf_core.c | 389 ++++++++++++++++++++++++++++++++++++++++++++++
drivers/mtd/spi/sf_core.h | 263 +++++++++++++++++++++++++++++++
drivers/mtd/spi/sf_ops.c | 147 +++++++-----------
drivers/mtd/spi/sf_spi.c | 230 +++++++++++++++++++++++++++
include/spi_flash.h | 15 +-
7 files changed, 996 insertions(+), 103 deletions(-)
create mode 100644 doc/SPI/README.sf-nor
create mode 100644 drivers/mtd/spi/sf_core.c
create mode 100644 drivers/mtd/spi/sf_core.h
create mode 100644 drivers/mtd/spi/sf_spi.c
diff --git a/doc/SPI/README.sf-nor b/doc/SPI/README.sf-nor
new file mode 100644
index 0000000..ded60f1
--- /dev/null
+++ b/doc/SPI/README.sf-nor
@@ -0,0 +1,51 @@
+SF-NOR framework:
+================
+
+1. Introduction
+
+Due to vast increasing of new spi flash features and operations the current
+serial flash framework in u-boot is difficult to manage the relation between
+spi bus vs spi flash(one of the connected slave). All newly added features
+are effecting spi_slave {} to become flash specific rather than generic spi bus.
+
+So there is a new framework that divides normal flash operations through generic
+SPI API's and more spi flash(sf) specific operations through SF NOR API's.
+
+This division of operations are taken care by new framework called "sf-nor".
+
+2. SF NOR
+
+ _______________
+ | |
+ | cmd_sf.c |
+ |_______________|
+ |
+ |
+ _______V_______
+ | |
+ | spi_flash.h |
+ |_______________|
+ |
+ |
+ _________V_________
+ | |
+ | sf_core |
+ | (sf_core.c) |
+ |___________________|
+ | |
+ | |
+ ____V____ |
+ | | |
+ | sf_spi.c| |
+ |_________| |
+ | |
+ | |
+ V V
+ drivers/spi/* drivers/mtd/spi/zynq_qspi.c
+
+common/cmd_sf.c: spi flash command interface
+include/spi_flash.h: spi flash api interface
+drivers/mtd/spi/sf_core.c: SF Core
+drivers/mtd/spi/sf_spi.c: sf emulation for all drivers/spi/*
+drivers/spi: spi drivers
+drivers/mtd/spi/zynq_qspi.c: zynq qspi controller driver
diff --git a/drivers/mtd/spi/Makefile b/drivers/mtd/spi/Makefile
index 15789a0..2ddeadf 100644
--- a/drivers/mtd/spi/Makefile
+++ b/drivers/mtd/spi/Makefile
@@ -13,9 +13,9 @@ obj-$(CONFIG_SPL_SPI_BOOT) += fsl_espi_spl.o
endif
#ifndef CONFIG_DM_SPI
-obj-$(CONFIG_SPI_FLASH) += sf_probe.o
+obj-$(CONFIG_SPI_FLASH) += sf_core.o
#endif
-obj-$(CONFIG_CMD_SF) += sf.o
+obj-$(CONFIG_CMD_SF) += sf_spi.o
obj-$(CONFIG_SPI_FLASH) += sf_ops.o sf_params.o
obj-$(CONFIG_SPI_FRAM_RAMTRON) += ramtron.o
obj-$(CONFIG_SPI_FLASH_SANDBOX) += sandbox.o
diff --git a/drivers/mtd/spi/sf_core.c b/drivers/mtd/spi/sf_core.c
new file mode 100644
index 0000000..dcc78a7
--- /dev/null
+++ b/drivers/mtd/spi/sf_core.c
@@ -0,0 +1,389 @@
+/*
+ * SPI flash probing
+ *
+ * Copyright (C) 2008 Atmel Corporation
+ * Copyright (C) 2010 Reinhard Meyer, EMK Elektronik
+ * Copyright (C) 2013 Jagannadha Sutradharudu Teki, Xilinx Inc.
+ *
+ * SPDX-License-Identifier: GPL-2.0+
+ */
+
+#include <common.h>
+#include <dm.h>
+#include <errno.h>
+#include <fdtdec.h>
+#include <malloc.h>
+#include <spi.h>
+#include <spi_flash.h>
+#include <asm/io.h>
+
+#include "sf_core.h"
+
+DECLARE_GLOBAL_DATA_PTR;
+
+/* Read commands array */
+static u8 spi_read_cmds_array[] = {
+ CMD_READ_ARRAY_SLOW,
+ CMD_READ_DUAL_OUTPUT_FAST,
+ CMD_READ_DUAL_IO_FAST,
+ CMD_READ_QUAD_OUTPUT_FAST,
+ CMD_READ_QUAD_IO_FAST,
+};
+
+#ifdef CONFIG_SPI_FLASH_MACRONIX
+static int spi_flash_set_qeb_mxic(struct sf_nor *nor)
+{
+ u8 qeb_status;
+ int ret;
+
+ ret = spi_flash_cmd_read_status(flash, &qeb_status);
+ if (ret < 0)
+ return ret;
+
+ if (qeb_status & STATUS_QEB_MXIC) {
+ debug("SF: mxic: QEB is already set\n");
+ } else {
+ ret = spi_flash_cmd_write_status(flash, STATUS_QEB_MXIC);
+ if (ret < 0)
+ return ret;
+ }
+
+ return ret;
+}
+#endif
+
+#if defined(CONFIG_SPI_FLASH_SPANSION) || defined(CONFIG_SPI_FLASH_WINBOND)
+static int spi_flash_set_qeb_winspan(struct spi_flash *flash)
+{
+ u8 qeb_status;
+ int ret;
+
+ ret = spi_flash_cmd_read_config(flash, &qeb_status);
+ if (ret < 0)
+ return ret;
+
+ if (qeb_status & STATUS_QEB_WINSPAN) {
+ debug("SF: winspan: QEB is already set\n");
+ } else {
+ ret = spi_flash_cmd_write_config(flash, STATUS_QEB_WINSPAN);
+ if (ret < 0)
+ return ret;
+ }
+
+ return ret;
+}
+#endif
+
+static int spi_flash_set_qeb(struct sf_nor *nor, u8 idcode0)
+{
+ switch (idcode0) {
+#ifdef CONFIG_SPI_FLASH_MACRONIX
+ case SPI_FLASH_CFI_MFR_MACRONIX:
+ return spi_flash_set_qeb_mxic(nor);
+#endif
+#if defined(CONFIG_SPI_FLASH_SPANSION) || defined(CONFIG_SPI_FLASH_WINBOND)
+ case SPI_FLASH_CFI_MFR_SPANSION:
+ case SPI_FLASH_CFI_MFR_WINBOND:
+ return spi_flash_set_qeb_winspan(nor);
+#endif
+#ifdef CONFIG_SPI_FLASH_STMICRO
+ case SPI_FLASH_CFI_MFR_STMICRO:
+ debug("SF: QEB is volatile for %02x flash\n", idcode0);
+ return 0;
+#endif
+ default:
+ printf("SF: Need set QEB func for %02x flash\n", idcode0);
+ return -1;
+ }
+}
+
+static int spi_flash_validate_params(struct sf_nor *nor, u8 *idcode)
+{
+ struct spi_flash *flash = nor->priv;
+ struct spi_slave *spi = flash->spi;
+ const struct spi_flash_params *params;
+ u8 cmd;
+ u16 jedec = idcode[1] << 8 | idcode[2];
+ u16 ext_jedec = idcode[3] << 8 | idcode[4];
+
+ /* Validate params from spi_flash_params table */
+ params = spi_flash_params_table;
+ for (; params->name != NULL; params++) {
+ if ((params->jedec >> 16) == idcode[0]) {
+ if ((params->jedec & 0xFFFF) == jedec) {
+ if (params->ext_jedec == 0)
+ break;
+ else if (params->ext_jedec == ext_jedec)
+ break;
+ }
+ }
+ }
+
+ if (!params->name) {
+ printf("SF: Unsupported flash IDs: ");
+ printf("manuf %02x, jedec %04x, ext_jedec %04x\n",
+ idcode[0], jedec, ext_jedec);
+ return -EPROTONOSUPPORT;
+ }
+
+ /* Assign spi data */
+ flash->spi = spi;
+ flash->name = params->name;
+ nor->memory_map = spi->memory_map;
+ nor->dual_flash = flash->spi->option;
+
+ /* Assign spi_flash ops */
+#ifndef CONFIG_DM_SPI_FLASH
+ flash->write = sf_nor_write;
+#if defined(CONFIG_SPI_FLASH_SST)
+ if (params->flags & SST_WP)
+ flash->write = sst_write_wp;
+#endif
+ flash->erase = sf_nor_erase;
+ flash->read = sf_nor_read;
+#endif
+
+ /* Compute the flash size */
+ nor->shift = (nor->dual_flash & SF_DUAL_PARALLEL_FLASH) ? 1 : 0;
+ /*
+ * The Spansion S25FL032P and S25FL064P have 256b pages, yet use the
+ * 0x4d00 Extended JEDEC code. The rest of the Spansion flashes with
+ * the 0x4d00 Extended JEDEC code have 512b pages. All of the others
+ * have 256b pages.
+ */
+ if (ext_jedec == 0x4d00) {
+ if ((jedec == 0x0215) || (jedec == 0x216))
+ nor->page_size = 256;
+ else
+ nor->page_size = 512;
+ } else {
+ nor->page_size = 256;
+ }
+ nor->page_size <<= nor->shift;
+ nor->sector_size = params->sector_size << nor->shift;
+ flash->size = nor->sector_size * params->nr_sectors << nor->shift;
+#ifdef CONFIG_SF_DUAL_FLASH
+ if (nor->dual_flash & SF_DUAL_STACKED_FLASH)
+ flash->size <<= 1;
+#endif
+
+ /* Compute erase sector and command */
+ if (params->flags & SECT_4K) {
+ nor->erase_cmd = CMD_ERASE_4K;
+ flash->erase_size = 4096 << nor->shift;
+ } else if (params->flags & SECT_32K) {
+ nor->erase_cmd = CMD_ERASE_32K;
+ flash->erase_size = 32768 << nor->shift;
+ } else {
+ nor->erase_cmd = CMD_ERASE_64K;
+ flash->erase_size = nor->sector_size;
+ }
+
+ /* Look for the fastest read cmd */
+ cmd = fls(params->e_rd_cmd & flash->spi->op_mode_rx);
+ if (cmd) {
+ cmd = spi_read_cmds_array[cmd - 1];
+ nor->read_cmd = cmd;
+ } else {
+ /* Go for default supported read cmd */
+ nor->read_cmd = CMD_READ_ARRAY_FAST;
+ }
+
+ /* Not require to look for fastest only two write cmds yet */
+ if (params->flags & WR_QPP && flash->spi->op_mode_tx & SPI_OPM_TX_QPP)
+ nor->write_cmd = CMD_QUAD_PAGE_PROGRAM;
+ else
+ /* Go for default supported write cmd */
+ nor->write_cmd = CMD_PAGE_PROGRAM;
+
+ /* Read dummy_byte: dummy byte is determined based on the
+ * dummy cycles of a particular command.
+ * Fast commands - dummy_byte = dummy_cycles/8
+ * I/O commands- dummy_byte = (dummy_cycles * no.of lines)/8
+ * For I/O commands except cmd[0] everything goes on no.of lines
+ * based on particular command but incase of fast commands except
+ * data all go on single line irrespective of command.
+ */
+ switch (nor->read_cmd) {
+ case CMD_READ_QUAD_IO_FAST:
+ nor->dummy_byte = 2;
+ break;
+ case CMD_READ_ARRAY_SLOW:
+ nor->dummy_byte = 0;
+ break;
+ default:
+ nor->dummy_byte = 1;
+ }
+
+ /* Poll cmd selection */
+ nor->poll_cmd = CMD_READ_STATUS;
+#ifdef CONFIG_SPI_FLASH_STMICRO
+ if (params->flags & E_FSR)
+ nor->poll_cmd = CMD_FLAG_STATUS;
+#endif
+
+ /* Configure the BAR - discover bank cmds and read current bank */
+#ifdef CONFIG_SPI_FLASH_BAR
+ u8 curr_bank = 0;
+ if (flash->size > SPI_FLASH_16MB_BOUN) {
+ int ret;
+
+ nor->bank_read_cmd = (idcode[0] == 0x01) ?
+ CMD_BANKADDR_BRRD : CMD_EXTNADDR_RDEAR;
+ nor->bank_write_cmd = (idcode[0] == 0x01) ?
+ CMD_BANKADDR_BRWR : CMD_EXTNADDR_WREAR;
+
+ ret = spi_flash_read_common(flash, &nor->bank_read_cmd, 1,
+ &curr_bank, 1);
+ if (ret) {
+ debug("SF: fail to read bank addr register\n");
+ return ret;
+ }
+ nor->bank_curr = curr_bank;
+ } else {
+ nor->bank_curr = curr_bank;
+ }
+#endif
+
+ /* Flash powers up read-only, so clear BP# bits */
+#if defined(CONFIG_SPI_FLASH_ATMEL) || \
+ defined(CONFIG_SPI_FLASH_MACRONIX) || \
+ defined(CONFIG_SPI_FLASH_SST)
+ spi_flash_cmd_write_status(nor, 0);
+#endif
+
+ return 0;
+}
+
+#ifdef CONFIG_OF_CONTROL
+int spi_flash_decode_fdt(const void *blob, struct sf_nor *nor)
+{
+ struct spi_flash *flash = nor->priv;
+ fdt_addr_t addr;
+ fdt_size_t size;
+ int node;
+
+ /* If there is no node, do nothing */
+ node = fdtdec_next_compatible(blob, 0, COMPAT_GENERIC_SPI_FLASH);
+ if (node < 0)
+ return 0;
+
+ addr = fdtdec_get_addr_size(blob, node, "memory-map", &size);
+ if (addr == FDT_ADDR_T_NONE) {
+ debug("%s: Cannot decode address\n", __func__);
+ return 0;
+ }
+
+ if (flash->size != size) {
+ debug("%s: Memory map must cover entire device\n", __func__);
+ return -1;
+ }
+ nor->memory_map = map_sysmem(addr, size);
+
+ return 0;
+}
+#endif /* CONFIG_OF_CONTROL */
+
+#ifdef CONFIG_SYS_SPI_ST_ENABLE_WP_PIN
+/* enable the W#/Vpp signal to disable writing to the status register */
+static int spi_enable_wp_pin(struct spi_flash *flash)
+{
+ u8 status;
+ int ret;
+
+ ret = spi_flash_cmd_read_status(flash, &status);
+ if (ret < 0)
+ return ret;
+
+ ret = spi_flash_cmd_write_status(flash, STATUS_SRWD);
+ if (ret < 0)
+ return ret;
+
+ ret = spi_flash_cmd_write_disable(flash);
+ if (ret < 0)
+ return ret;
+
+ return 0;
+}
+#else
+static int spi_enable_wp_pin(struct spi_flash *flash)
+{
+ return 0;
+}
+#endif
+
+/**
+ * spi_flash_probe_slave() - Probe for a SPI flash device on a bus
+ *
+ * @spi: Bus to probe
+ * @flashp: Pointer to place to put flash info, which may be NULL if the
+ * space should be allocated
+ */
+int sf_nor_scan(struct sf_nor *nor)
+{
+ struct spi_flash *flash = nor->priv;
+ u8 cmd, idcode[5];
+ int ret;
+
+ /* Read the ID codes */
+ cmd = CMD_READ_ID;
+ ret = nor->read(nor, &cmd, 1, idcode, 5);
+ if (ret) {
+ printf("SF: Failed to get idcodes\n");
+ goto err_read_id;
+ }
+
+#ifdef DEBUG
+ printf("SF: Got idcodes\n");
+ print_buffer(0, idcode, 1, sizeof(idcode), 0);
+#endif
+
+ if (spi_flash_validate_params(nor, idcode)) {
+ ret = -EINVAL;
+ goto err_read_id;
+ }
+
+ /* Set the quad enable bit - only for quad commands */
+ if ((nor->read_cmd == CMD_READ_QUAD_OUTPUT_FAST) ||
+ (nor->read_cmd == CMD_READ_QUAD_IO_FAST) ||
+ (nor->write_cmd == CMD_QUAD_PAGE_PROGRAM)) {
+ if (spi_flash_set_qeb(nor, idcode[0])) {
+ debug("SF: Fail to set QEB for %02x\n", idcode[0]);
+ ret = -EINVAL;
+ goto err_read_id;
+ }
+ }
+
+#ifdef CONFIG_OF_CONTROL
+ if (spi_flash_decode_fdt(gd->fdt_blob, nor)) {
+ debug("SF: FDT decode error\n");
+ ret = -EINVAL;
+ goto err_read_id;
+ }
+#endif
+#ifndef CONFIG_SPL_BUILD
+ printf("SF: Detected %s with page size ", flash->name);
+ print_size(nor->page_size, ", erase size ");
+ print_size(flash->erase_size, ", total ");
+ print_size(flash->size, "");
+ if (nor->memory_map)
+ printf(", mapped at %p", nor->memory_map);
+ puts("\n");
+#endif
+#ifndef CONFIG_SPI_FLASH_BAR
+ if (((nor->dual_flash == SF_SINGLE_FLASH) &&
+ (flash->size > SPI_FLASH_16MB_BOUN)) ||
+ ((nor->dual_flash > SF_SINGLE_FLASH) &&
+ (flash->size > SPI_FLASH_16MB_BOUN << 1))) {
+ puts("SF: Warning - Only lower 16MiB accessible,");
+ puts(" Full access #define CONFIG_SPI_FLASH_BAR\n");
+ }
+#endif
+ if (spi_enable_wp_pin(flash))
+ puts("Enable WP pin failed\n");
+
+ return 0;
+
+err_read_id:
+ return ret;
+}
diff --git a/drivers/mtd/spi/sf_core.h b/drivers/mtd/spi/sf_core.h
new file mode 100644
index 0000000..05af241
--- /dev/null
+++ b/drivers/mtd/spi/sf_core.h
@@ -0,0 +1,263 @@
+/*
+ * SPI flash internal definitions
+ *
+ * Copyright (C) 2008 Atmel Corporation
+ * Copyright (C) 2013 Jagannadha Sutradharudu Teki, Xilinx Inc.
+ *
+ * SPDX-License-Identifier: GPL-2.0+
+ */
+
+#ifndef _SF_INTERNAL_H_
+#define _SF_INTERNAL_H_
+
+#include <linux/types.h>
+#include <linux/compiler.h>
+
+/* Dual SPI flash memories - see SPI_COMM_DUAL_... */
+enum spi_dual_flash {
+ SF_SINGLE_FLASH = 0,
+ SF_DUAL_STACKED_FLASH = 1 << 0,
+ SF_DUAL_PARALLEL_FLASH = 1 << 1,
+};
+
+/* Enum list - Full read commands */
+enum spi_read_cmds {
+ ARRAY_SLOW = 1 << 0,
+ DUAL_OUTPUT_FAST = 1 << 1,
+ DUAL_IO_FAST = 1 << 2,
+ QUAD_OUTPUT_FAST = 1 << 3,
+ QUAD_IO_FAST = 1 << 4,
+};
+
+#define RD_EXTN (ARRAY_SLOW | DUAL_OUTPUT_FAST | DUAL_IO_FAST)
+#define RD_FULL (RD_EXTN | QUAD_OUTPUT_FAST | QUAD_IO_FAST)
+
+/* sf param flags */
+enum {
+ SECT_4K = 1 << 0,
+ SECT_32K = 1 << 1,
+ E_FSR = 1 << 2,
+ WR_QPP = 1 << 3,
+};
+
+#define SPI_FLASH_3B_ADDR_LEN 3
+#define SPI_FLASH_CMD_LEN (1 + SPI_FLASH_3B_ADDR_LEN)
+#define SPI_FLASH_16MB_BOUN 0x1000000
+
+/* CFI Manufacture ID's */
+#define SPI_FLASH_CFI_MFR_SPANSION 0x01
+#define SPI_FLASH_CFI_MFR_STMICRO 0x20
+#define SPI_FLASH_CFI_MFR_MACRONIX 0xc2
+#define SPI_FLASH_CFI_MFR_WINBOND 0xef
+
+/* Erase commands */
+#define CMD_ERASE_4K 0x20
+#define CMD_ERASE_32K 0x52
+#define CMD_ERASE_CHIP 0xc7
+#define CMD_ERASE_64K 0xd8
+
+/* Write commands */
+#define CMD_WRITE_STATUS 0x01
+#define CMD_PAGE_PROGRAM 0x02
+#define CMD_WRITE_DISABLE 0x04
+#define CMD_READ_STATUS 0x05
+#define CMD_QUAD_PAGE_PROGRAM 0x32
+#define CMD_READ_STATUS1 0x35
+#define CMD_WRITE_ENABLE 0x06
+#define CMD_READ_CONFIG 0x35
+#define CMD_FLAG_STATUS 0x70
+
+/* Read commands */
+#define CMD_READ_ARRAY_SLOW 0x03
+#define CMD_READ_ARRAY_FAST 0x0b
+#define CMD_READ_DUAL_OUTPUT_FAST 0x3b
+#define CMD_READ_DUAL_IO_FAST 0xbb
+#define CMD_READ_QUAD_OUTPUT_FAST 0x6b
+#define CMD_READ_QUAD_IO_FAST 0xeb
+#define CMD_READ_ID 0x9f
+
+/* Bank addr access commands */
+#ifdef CONFIG_SPI_FLASH_BAR
+# define CMD_BANKADDR_BRWR 0x17
+# define CMD_BANKADDR_BRRD 0x16
+# define CMD_EXTNADDR_WREAR 0xC5
+# define CMD_EXTNADDR_RDEAR 0xC8
+#endif
+
+/* Common status */
+#define STATUS_WIP (1 << 0)
+#define STATUS_QEB_WINSPAN (1 << 1)
+#define STATUS_QEB_MXIC (1 << 6)
+#define STATUS_PEC (1 << 7)
+
+#ifdef CONFIG_SYS_SPI_ST_ENABLE_WP_PIN
+#define STATUS_SRWD (1 << 7) /* SR write protect */
+#endif
+
+/* Flash timeout values */
+#define SPI_FLASH_PROG_TIMEOUT (2 * CONFIG_SYS_HZ)
+#define SPI_FLASH_PAGE_ERASE_TIMEOUT (5 * CONFIG_SYS_HZ)
+#define SPI_FLASH_SECTOR_ERASE_TIMEOUT (10 * CONFIG_SYS_HZ)
+
+/* SST specific */
+#ifdef CONFIG_SPI_FLASH_SST
+# define SST_WP 0x01 /* Supports AAI word program */
+# define CMD_SST_BP 0x02 /* Byte Program */
+# define CMD_SST_AAI_WP 0xAD /* Auto Address Incr Word Program */
+
+int sst_write_wp(struct spi_flash *flash, u32 offset, size_t len,
+ const void *buf);
+#endif
+
+/**
+ * struct spi_flash_params - SPI/QSPI flash device params structure
+ *
+ * @name: Device name ([MANUFLETTER][DEVTYPE][DENSITY][EXTRAINFO])
+ * @jedec: Device jedec ID (0x[1byte_manuf_id][2byte_dev_id])
+ * @ext_jedec: Device ext_jedec ID
+ * @sector_size: Sector size of this device
+ * @nr_sectors: No.of sectors on this device
+ * @e_rd_cmd: Enum list for read commands
+ * @flags: Important param, for flash specific behaviour
+ */
+struct spi_flash_params {
+ const char *name;
+ u32 jedec;
+ u16 ext_jedec;
+ u32 sector_size;
+ u32 nr_sectors;
+ u8 e_rd_cmd;
+ u16 flags;
+};
+
+extern const struct spi_flash_params spi_flash_params_table[];
+
+/* Send a single-byte command to the device and read the response */
+int spi_flash_cmd(struct spi_slave *spi, u8 cmd, void *response, size_t len);
+
+/*
+ * Send a multi-byte command to the device and read the response. Used
+ * for flash array reads, etc.
+ */
+int spi_flash_cmd_read(struct spi_slave *spi, const u8 *cmd,
+ size_t cmd_len, void *data, size_t data_len);
+
+/*
+ * Send a multi-byte command to the device followed by (optional)
+ * data. Used for programming the flash array, etc.
+ */
+int spi_flash_cmd_write(struct spi_slave *spi, const u8 *cmd, size_t cmd_len,
+ const void *data, size_t data_len);
+
+
+/* Flash erase(sectors) operation, support all possible erase commands */
+int sf_nor_erase(struct spi_flash *flash, u32 offset, size_t len);
+
+/* Read the status register */
+int spi_flash_cmd_read_status(struct sf_nor *nor, u8 *rs);
+
+/* Program the status register */
+int spi_flash_cmd_write_status(struct sf_nor *nor, u8 ws);
+
+/* Read the config register */
+int spi_flash_cmd_read_config(struct sf_nor *nor, u8 *rc);
+
+/* Program the config register */
+int spi_flash_cmd_write_config(struct sf_nor *nor, u8 wc);
+
+/* Enable writing on the SPI flash */
+static inline int spi_flash_cmd_write_enable(struct spi_flash *flash)
+{
+ return spi_flash_cmd(flash->spi, CMD_WRITE_ENABLE, NULL, 0);
+}
+
+/* Disable writing on the SPI flash */
+static inline int spi_flash_cmd_write_disable(struct spi_flash *flash)
+{
+ return spi_flash_cmd(flash->spi, CMD_WRITE_DISABLE, NULL, 0);
+}
+
+/*
+ * Send the read status command to the device and wait for the wip
+ * (write-in-progress) bit to clear itself.
+ */
+int spi_flash_cmd_wait_ready(struct sf_nor *nor, unsigned long timeout);
+
+/*
+ * Used for spi_flash write operation
+ * - SPI claim
+ * - spi_flash_cmd_write_enable
+ * - spi_flash_cmd_write
+ * - spi_flash_cmd_wait_ready
+ * - SPI release
+ */
+int sf_nor_write_common(struct sf_nor *nor, const u8 *cmd,
+ size_t cmd_len, const void *buf, size_t buf_len);
+
+/*
+ * Flash write operation, support all possible write commands.
+ * Write the requested data out breaking it up into multiple write
+ * commands as needed per the write size.
+ */
+int sf_nor_write(struct spi_flash *flash, u32 offset,
+ size_t len, const void *buf);
+
+/*
+ * Same as spi_flash_cmd_read() except it also claims/releases the SPI
+ * bus. Used as common part of the ->read() operation.
+ */
+int spi_flash_read_common(struct spi_flash *flash, const u8 *cmd,
+ size_t cmd_len, void *data, size_t data_len);
+
+/* Flash read operation, support all possible read commands */
+int sf_nor_read(struct spi_flash *flash, u32 offset,
+ size_t len, void *data);
+
+
+/**
+ * struct sf_nor - SF NOR structure
+ *
+ * @spi: SPI slave
+ * @poll_cmd: Poll cmd - for flash erase/program
+ * @erase_cmd: Erase cmd 4K, 32K, 64K
+ * @read_cmd: Read cmd - Array Fast, Extn read and quad read.
+ * @write_cmd: Write cmd - page and quad program.
+ * @read: Flash read ops: Read len bytes at offset into buf
+ * Supported cmds: Fast Array Read
+ * @write: Flash write ops: Write len bytes from buf into offeset
+ * Supported cmds: Page Program
+ * @erase: Flash erase ops: Erase len bytes from offset
+ * Supported cmds: Sector erase 4K, 32K, 64K
+ * return 0 - Sucess, 1 - Failure
+ */
+struct sf_nor {
+ u32 page_size;
+ u32 sector_size;
+
+ u8 dual_flash;
+ u8 shift;
+
+#ifdef CONFIG_SPI_FLASH_BAR
+ u8 bank_read_cmd;
+ u8 bank_write_cmd;
+ u8 bank_curr;
+#endif
+ u8 poll_cmd;
+ u8 erase_cmd;
+ u8 read_cmd;
+ u8 write_cmd;
+ u8 dummy_byte;
+
+ void *memory_map;
+ int (*read)(struct sf_nor *nor, const u8 *cmd, size_t cmd_len,
+ void *data, size_t data_len);
+ int (*write)(struct sf_nor *nor, const u8 *cmd, size_t cmd_len,
+ const void *data, size_t data_len);
+ int (*wait_till_ready)(struct sf_nor *nor);
+ void *priv;
+};
+
+/* Scan for sf nor flash */
+int sf_nor_scan(struct sf_nor *nor);
+
+#endif /* _SF_INTERNAL_H_ */
diff --git a/drivers/mtd/spi/sf_ops.c b/drivers/mtd/spi/sf_ops.c
index 85cf22d..2ae2d66 100644
--- a/drivers/mtd/spi/sf_ops.c
+++ b/drivers/mtd/spi/sf_ops.c
@@ -15,7 +15,7 @@
#include <spi_flash.h>
#include <watchdog.h>
-#include "sf_internal.h"
+#include "sf_core.h"
static void spi_flash_addr(u32 addr, u8 *cmd)
{
@@ -25,13 +25,13 @@ static void spi_flash_addr(u32 addr, u8 *cmd)
cmd[3] = addr >> 0;
}
-int spi_flash_cmd_read_status(struct spi_flash *flash, u8 *rs)
+int spi_flash_cmd_read_status(struct sf_nor *nor, u8 *rs)
{
int ret;
u8 cmd;
cmd = CMD_READ_STATUS;
- ret = spi_flash_read_common(flash, &cmd, 1, rs, 1);
+ ret = nor->read(nor, &cmd, 1, rs, 1);
if (ret < 0) {
debug("SF: fail to read status register\n");
return ret;
@@ -40,13 +40,13 @@ int spi_flash_cmd_read_status(struct spi_flash *flash, u8 *rs)
return 0;
}
-int spi_flash_cmd_write_status(struct spi_flash *flash, u8 ws)
+int spi_flash_cmd_write_status(struct sf_nor *nor, u8 ws)
{
u8 cmd;
int ret;
cmd = CMD_WRITE_STATUS;
- ret = spi_flash_write_common(flash, &cmd, 1, &ws, 1);
+ ret = sf_nor_write_common(nor, &cmd, 1, &ws, 1);
if (ret < 0) {
debug("SF: fail to write status register\n");
return ret;
@@ -62,7 +62,7 @@ int spi_flash_cmd_read_config(struct spi_flash *flash, u8 *rc)
u8 cmd;
cmd = CMD_READ_CONFIG;
- ret = spi_flash_read_common(flash, &cmd, 1, rc, 1);
+ ret = nor->read(flash, &cmd, 1, rc, 1);
if (ret < 0) {
debug("SF: fail to read config register\n");
return ret;
@@ -71,19 +71,19 @@ int spi_flash_cmd_read_config(struct spi_flash *flash, u8 *rc)
return 0;
}
-int spi_flash_cmd_write_config(struct spi_flash *flash, u8 wc)
+int spi_flash_cmd_write_config(struct sf_nor *nor, u8 wc)
{
u8 data[2];
u8 cmd;
int ret;
- ret = spi_flash_cmd_read_status(flash, &data[0]);
+ ret = spi_flash_cmd_read_status(nor, &data[0]);
if (ret < 0)
return ret;
cmd = CMD_WRITE_STATUS;
data[1] = wc;
- ret = spi_flash_write_common(flash, &cmd, 1, &data, 2);
+ ret = sf_nor_write_common(nor, &cmd, 1, &data, 2);
if (ret) {
debug("SF: fail to write config register\n");
return ret;
@@ -99,18 +99,18 @@ static int spi_flash_cmd_bankaddr_write(struct spi_flash *flash, u8 bank_sel)
u8 cmd;
int ret;
- if (flash->bank_curr == bank_sel) {
+ if (nor->bank_curr == bank_sel) {
debug("SF: not require to enable bank%d\n", bank_sel);
return 0;
}
- cmd = flash->bank_write_cmd;
- ret = spi_flash_write_common(flash, &cmd, 1, &bank_sel, 1);
+ cmd = nor->bank_write_cmd;
+ ret = sf_nor_write_common(flash, &cmd, 1, &bank_sel, 1);
if (ret < 0) {
debug("SF: fail to write bank register\n");
return ret;
}
- flash->bank_curr = bank_sel;
+ nor->bank_curr = bank_sel;
return 0;
}
@@ -120,7 +120,7 @@ static int spi_flash_bank(struct spi_flash *flash, u32 offset)
u8 bank_sel;
int ret;
- bank_sel = offset / (SPI_FLASH_16MB_BOUN << flash->shift);
+ bank_sel = offset / (SPI_FLASH_16MB_BOUN << nor->shift);
ret = spi_flash_cmd_bankaddr_write(flash, bank_sel);
if (ret) {
@@ -135,7 +135,7 @@ static int spi_flash_bank(struct spi_flash *flash, u32 offset)
#ifdef CONFIG_SF_DUAL_FLASH
static void spi_flash_dual_flash(struct spi_flash *flash, u32 *addr)
{
- switch (flash->dual_flash) {
+ switch (nor->dual_flash) {
case SF_DUAL_STACKED_FLASH:
if (*addr >= (flash->size >> 1)) {
*addr -= flash->size >> 1;
@@ -145,17 +145,18 @@ static void spi_flash_dual_flash(struct spi_flash *flash, u32 *addr)
}
break;
case SF_DUAL_PARALLEL_FLASH:
- *addr >>= flash->shift;
+ *addr >>= nor->shift;
break;
default:
- debug("SF: Unsupported dual_flash=%d\n", flash->dual_flash);
+ debug("SF: Unsupported dual_flash=%d\n", nor->dual_flash);
break;
}
}
#endif
-int spi_flash_cmd_wait_ready(struct spi_flash *flash, unsigned long timeout)
+int spi_flash_cmd_wait_ready(struct sf_nor *nor, unsigned long timeout)
{
+ struct spi_flash *flash = nor->priv;
struct spi_slave *spi = flash->spi;
unsigned long timebase;
unsigned long flags = SPI_XFER_BEGIN;
@@ -163,7 +164,7 @@ int spi_flash_cmd_wait_ready(struct spi_flash *flash, unsigned long timeout)
u8 status;
u8 check_status = 0x0;
u8 poll_bit = STATUS_WIP;
- u8 cmd = flash->poll_cmd;
+ u8 cmd = nor->poll_cmd;
if (cmd == CMD_FLAG_STATUS) {
poll_bit = STATUS_PEC;
@@ -204,35 +205,28 @@ int spi_flash_cmd_wait_ready(struct spi_flash *flash, unsigned long timeout)
return -1;
}
-int spi_flash_write_common(struct spi_flash *flash, const u8 *cmd,
+int sf_nor_write_common(struct sf_nor *nor, const u8 *cmd,
size_t cmd_len, const void *buf, size_t buf_len)
{
- struct spi_slave *spi = flash->spi;
unsigned long timeout = SPI_FLASH_PROG_TIMEOUT;
int ret;
if (buf == NULL)
timeout = SPI_FLASH_PAGE_ERASE_TIMEOUT;
- ret = spi_claim_bus(flash->spi);
- if (ret) {
- debug("SF: unable to claim SPI bus\n");
- return ret;
- }
-
- ret = spi_flash_cmd_write_enable(flash);
+ ret = nor->read(nor, (u8 *)CMD_WRITE_ENABLE, 1, NULL, 0);
if (ret < 0) {
debug("SF: enabling write failed\n");
return ret;
}
- ret = spi_flash_cmd_write(spi, cmd, cmd_len, buf, buf_len);
+ ret = nor->write(nor, cmd, cmd_len, buf, buf_len);
if (ret < 0) {
debug("SF: write cmd failed\n");
return ret;
}
- ret = spi_flash_cmd_wait_ready(flash, timeout);
+ ret = spi_flash_cmd_wait_ready(nor, timeout);
if (ret < 0) {
debug("SF: write %s timed out\n",
timeout == SPI_FLASH_PROG_TIMEOUT ?
@@ -240,13 +234,12 @@ int spi_flash_write_common(struct spi_flash *flash, const u8 *cmd,
return ret;
}
- spi_release_bus(spi);
-
return ret;
}
-int spi_flash_cmd_erase_ops(struct spi_flash *flash, u32 offset, size_t len)
+int sf_nor_erase(struct spi_flash *flash, u32 offset, size_t len)
{
+ struct sf_nor *nor = flash->nor;
u32 erase_size, erase_addr;
u8 cmd[SPI_FLASH_CMD_LEN];
int ret = -1;
@@ -257,12 +250,12 @@ int spi_flash_cmd_erase_ops(struct spi_flash *flash, u32 offset, size_t len)
return -1;
}
- cmd[0] = flash->erase_cmd;
+ cmd[0] = nor->erase_cmd;
while (len) {
erase_addr = offset;
#ifdef CONFIG_SF_DUAL_FLASH
- if (flash->dual_flash > SF_SINGLE_FLASH)
+ if (nor->dual_flash > SF_SINGLE_FLASH)
spi_flash_dual_flash(flash, &erase_addr);
#endif
#ifdef CONFIG_SPI_FLASH_BAR
@@ -275,7 +268,7 @@ int spi_flash_cmd_erase_ops(struct spi_flash *flash, u32 offset, size_t len)
debug("SF: erase %2x %2x %2x %2x (%x)\n", cmd[0], cmd[1],
cmd[2], cmd[3], erase_addr);
- ret = spi_flash_write_common(flash, cmd, sizeof(cmd), NULL, 0);
+ ret = sf_nor_write_common(nor, cmd, sizeof(cmd), NULL, 0);
if (ret < 0) {
debug("SF: erase failed\n");
break;
@@ -288,23 +281,23 @@ int spi_flash_cmd_erase_ops(struct spi_flash *flash, u32 offset, size_t len)
return ret;
}
-int spi_flash_cmd_write_ops(struct spi_flash *flash, u32 offset,
- size_t len, const void *buf)
+int sf_nor_write(struct spi_flash *flash, u32 offset, size_t len, const void *buf)
{
+ struct sf_nor *nor = flash->nor;
unsigned long byte_addr, page_size;
u32 write_addr;
size_t chunk_len, actual;
u8 cmd[SPI_FLASH_CMD_LEN];
int ret = -1;
- page_size = flash->page_size;
+ page_size = nor->page_size;
- cmd[0] = flash->write_cmd;
+ cmd[0] = nor->write_cmd;
for (actual = 0; actual < len; actual += chunk_len) {
write_addr = offset;
#ifdef CONFIG_SF_DUAL_FLASH
- if (flash->dual_flash > SF_SINGLE_FLASH)
+ if (nor->dual_flash > SF_SINGLE_FLASH)
spi_flash_dual_flash(flash, &write_addr);
#endif
#ifdef CONFIG_SPI_FLASH_BAR
@@ -323,8 +316,7 @@ int spi_flash_cmd_write_ops(struct spi_flash *flash, u32 offset,
debug("SF: 0x%p => cmd = { 0x%02x 0x%02x%02x%02x } chunk_len = %zu\n",
buf + actual, cmd[0], cmd[1], cmd[2], cmd[3], chunk_len);
- ret = spi_flash_write_common(flash, cmd, sizeof(cmd),
- buf + actual, chunk_len);
+ ret = sf_nor_write_common(nor, cmd, sizeof(cmd), buf + actual, chunk_len);
if (ret < 0) {
debug("SF: write failed\n");
break;
@@ -336,64 +328,42 @@ int spi_flash_cmd_write_ops(struct spi_flash *flash, u32 offset,
return ret;
}
-int spi_flash_read_common(struct spi_flash *flash, const u8 *cmd,
- size_t cmd_len, void *data, size_t data_len)
-{
- struct spi_slave *spi = flash->spi;
- int ret;
-
- ret = spi_claim_bus(flash->spi);
- if (ret) {
- debug("SF: unable to claim SPI bus\n");
- return ret;
- }
-
- ret = spi_flash_cmd_read(spi, cmd, cmd_len, data, data_len);
- if (ret < 0) {
- debug("SF: read cmd failed\n");
- return ret;
- }
-
- spi_release_bus(spi);
-
- return ret;
-}
-
-int spi_flash_cmd_read_ops(struct spi_flash *flash, u32 offset,
+int sf_nor_read(struct spi_flash *flash, u32 offset,
size_t len, void *data)
{
+ struct sf_nor *nor = flash->nor;
u8 *cmd, cmdsz;
u32 remain_len, read_len, read_addr;
int bank_sel = 0;
int ret = -1;
/* Handle memory-mapped SPI */
- if (flash->memory_map) {
+ if (nor->memory_map) {
ret = spi_claim_bus(flash->spi);
if (ret) {
debug("SF: unable to claim SPI bus\n");
return ret;
}
spi_xfer(flash->spi, 0, NULL, NULL, SPI_XFER_MMAP);
- memcpy(data, flash->memory_map + offset, len);
+ memcpy(data, nor->memory_map + offset, len);
spi_xfer(flash->spi, 0, NULL, NULL, SPI_XFER_MMAP_END);
spi_release_bus(flash->spi);
return 0;
}
- cmdsz = SPI_FLASH_CMD_LEN + flash->dummy_byte;
+ cmdsz = SPI_FLASH_CMD_LEN + nor->dummy_byte;
cmd = calloc(1, cmdsz);
if (!cmd) {
debug("SF: Failed to allocate cmd\n");
return -ENOMEM;
}
- cmd[0] = flash->read_cmd;
+ cmd[0] = nor->read_cmd;
while (len) {
read_addr = offset;
#ifdef CONFIG_SF_DUAL_FLASH
- if (flash->dual_flash > SF_SINGLE_FLASH)
+ if (nor->dual_flash > SF_SINGLE_FLASH)
spi_flash_dual_flash(flash, &read_addr);
#endif
#ifdef CONFIG_SPI_FLASH_BAR
@@ -401,7 +371,7 @@ int spi_flash_cmd_read_ops(struct spi_flash *flash, u32 offset,
if (bank_sel < 0)
return ret;
#endif
- remain_len = ((SPI_FLASH_16MB_BOUN << flash->shift) *
+ remain_len = ((SPI_FLASH_16MB_BOUN << nor->shift) *
(bank_sel + 1)) - offset;
if (len < remain_len)
read_len = len;
@@ -410,7 +380,7 @@ int spi_flash_cmd_read_ops(struct spi_flash *flash, u32 offset,
spi_flash_addr(read_addr, cmd);
- ret = spi_flash_read_common(flash, cmd, cmdsz, data, read_len);
+ ret = nor->read(nor, cmd, cmdsz, data, read_len);
if (ret < 0) {
debug("SF: read failed\n");
break;
@@ -426,8 +396,9 @@ int spi_flash_cmd_read_ops(struct spi_flash *flash, u32 offset,
}
#ifdef CONFIG_SPI_FLASH_SST
-static int sst_byte_write(struct spi_flash *flash, u32 offset, const void *buf)
+static int sst_byte_write(struct sf_nor *nor, u32 offset, const void *buf)
{
+ struct spi_flash *flash = nor->priv;
int ret;
u8 cmd[4] = {
CMD_SST_BP,
@@ -439,20 +410,21 @@ static int sst_byte_write(struct spi_flash *flash, u32 offset, const void *buf)
debug("BP[%02x]: 0x%p => cmd = { 0x%02x 0x%06x }\n",
spi_w8r8(flash->spi, CMD_READ_STATUS), buf, cmd[0], offset);
- ret = spi_flash_cmd_write_enable(flash);
+ ret = nor->read(nor, (u8 *)CMD_WRITE_ENABLE, 1, NULL, 0);
if (ret)
return ret;
- ret = spi_flash_cmd_write(flash->spi, cmd, sizeof(cmd), buf, 1);
+ ret = nor->write(nor, cmd, sizeof(cmd), buf, 1);
if (ret)
return ret;
- return spi_flash_cmd_wait_ready(flash, SPI_FLASH_PROG_TIMEOUT);
+ return spi_flash_cmd_wait_ready(nor, SPI_FLASH_PROG_TIMEOUT);
}
int sst_write_wp(struct spi_flash *flash, u32 offset, size_t len,
const void *buf)
{
+ struct sf_nor *nor = flash->nor;
size_t actual, cmd_len;
int ret;
u8 cmd[4];
@@ -466,15 +438,17 @@ int sst_write_wp(struct spi_flash *flash, u32 offset, size_t len,
/* If the data is not word aligned, write out leading single byte */
actual = offset % 2;
if (actual) {
- ret = sst_byte_write(flash, offset, buf);
+ ret = sst_byte_write(nor, offset, buf);
if (ret)
goto done;
}
offset += actual;
- ret = spi_flash_cmd_write_enable(flash);
- if (ret)
- goto done;
+ ret = nor->read(nor, (u8 *)CMD_WRITE_ENABLE, 1, NULL, 0);
+ if (ret < 0) {
+ debug("SF: enabling write failed\n");
+ return ret;
+ }
cmd_len = 4;
cmd[0] = CMD_SST_AAI_WP;
@@ -487,14 +461,14 @@ int sst_write_wp(struct spi_flash *flash, u32 offset, size_t len,
spi_w8r8(flash->spi, CMD_READ_STATUS), buf + actual,
cmd[0], offset);
- ret = spi_flash_cmd_write(flash->spi, cmd, cmd_len,
+ ret = nor->write(nor, cmd, cmd_len,
buf + actual, 2);
if (ret) {
debug("SF: sst word program failed\n");
break;
}
- ret = spi_flash_cmd_wait_ready(flash, SPI_FLASH_PROG_TIMEOUT);
+ ret = spi_flash_cmd_wait_ready(nor, SPI_FLASH_PROG_TIMEOUT);
if (ret)
break;
@@ -503,17 +477,16 @@ int sst_write_wp(struct spi_flash *flash, u32 offset, size_t len,
}
if (!ret)
- ret = spi_flash_cmd_write_disable(flash);
+ ret = nor->read(nor, (u8 *)CMD_WRITE_DISABLE, 1, NULL, 0);
/* If there is a single trailing byte, write it out */
if (!ret && actual != len)
- ret = sst_byte_write(flash, offset, buf + actual);
+ ret = sst_byte_write(nor, offset, buf + actual);
done:
debug("SF: sst: program %s %zu bytes @ 0x%zx\n",
ret ? "failure" : "success", len, offset - actual);
- spi_release_bus(flash->spi);
return ret;
}
#endif
diff --git a/drivers/mtd/spi/sf_spi.c b/drivers/mtd/spi/sf_spi.c
new file mode 100644
index 0000000..d525b61
--- /dev/null
+++ b/drivers/mtd/spi/sf_spi.c
@@ -0,0 +1,230 @@
+/*
+ * SPI flash interface
+ *
+ * Copyright (C) 2008 Atmel Corporation
+ * Copyright (C) 2010 Reinhard Meyer, EMK Elektronik
+ *
+ * SPDX-License-Identifier: GPL-2.0+
+ */
+
+#include <common.h>
+#include <errno.h>
+#include <malloc.h>
+#include <spi.h>
+#include <spi_flash.h>
+#include "sf_core.h"
+
+static int spi_sf_read_write(struct spi_slave *spi,
+ const u8 *cmd, size_t cmd_len,
+ const u8 *data_out, u8 *data_in,
+ size_t data_len)
+{
+ unsigned long flags = SPI_XFER_BEGIN;
+ int ret;
+
+ if (data_len == 0)
+ flags |= SPI_XFER_END;
+
+ ret = spi_xfer(spi, cmd_len * 8, cmd, NULL, flags);
+ if (ret) {
+ printf("SF: Failed to send command (%zu bytes): %d\n",
+ cmd_len, ret);
+ } else if (data_len != 0) {
+ ret = spi_xfer(spi, data_len * 8, data_out, data_in,
+ SPI_XFER_END);
+ if (ret)
+ printf("SF: Failed to transfer %zu bytes of data: %d\n",
+ data_len, ret);
+ }
+
+ return ret;
+}
+
+static int spi_sf_read(struct sf_nor *nor, const u8 *cmd, size_t cmd_len,
+ void *data, size_t data_len)
+{
+ struct spi_flash *flash = nor->priv;
+ struct spi_slave *spi = flash->spi;
+ int ret;
+
+ /* claim spi bus */
+ ret = spi_claim_bus(spi);
+ if (ret) {
+ printf("SF_SPI: failed to claim SPI bus\n");
+ return ret;
+ }
+
+ ret = spi_sf_read_write(spi, cmd, cmd_len, NULL, data, data_len);
+ if (ret < 0) {
+ printf("SF_SPI: failed to read sf_nor\n");
+ spi_release_bus(spi);
+ return ret;
+ }
+
+ /* release spi bus */
+ spi_release_bus(spi);
+
+ return ret;
+}
+
+static int spi_sf_write(struct sf_nor *nor, const u8 *cmd, size_t cmd_len,
+ const void *data, size_t data_len)
+{
+ struct spi_flash *flash = nor->priv;
+ struct spi_slave *spi = flash->spi;
+ int ret;
+
+ /* claim spi bus */
+ ret = spi_claim_bus(spi);
+ if (ret) {
+ printf("SF_SPI: failed to claim SPI bus\n");
+ return ret;
+ }
+
+ ret = spi_sf_read_write(spi, cmd, cmd_len, data, NULL, data_len);
+ if (ret < 0) {
+ printf("SF_SPI: failed to write sf_nor\n");
+ spi_release_bus(spi);
+ return ret;
+ }
+
+ /* release spi bus */
+ spi_release_bus(spi);
+
+ return ret;
+}
+
+int spi_flash_probe_slave(struct spi_slave *spi, struct spi_flash *flash)
+{
+ struct sf_nor *nor;
+ int ret;
+
+ /* Setup spi_slave */
+ if (!spi) {
+ printf("SF: Failed to set up slave\n");
+ return -ENODEV;
+ }
+
+ nor = flash->nor;
+ nor->read = spi_sf_read;
+ nor->write = spi_sf_write;
+
+ nor->priv = flash;
+ flash->spi = spi;
+
+ /* scan for nor flash */
+ ret = sf_nor_scan(nor);
+ if (ret < 0) {
+ printf("SF_SPI: sf_nor_scan failed\n");
+ spi_release_bus(spi);
+ return ret;
+ }
+
+ spi_release_bus(spi);
+
+ return 0;
+}
+
+#ifndef CONFIG_DM_SPI_FLASH
+struct spi_flash *spi_flash_probe_tail(struct spi_slave *bus)
+{
+ struct spi_flash *flash;
+
+ /* Allocate space if needed (not used by sf-uclass */
+ flash = calloc(1, sizeof(*flash));
+ if (!flash) {
+ debug("SF: Failed to allocate spi_flash\n");
+ return NULL;
+ }
+
+ if (spi_flash_probe_slave(bus, flash)) {
+ spi_free_slave(bus);
+ free(flash);
+ return NULL;
+ }
+
+ return flash;
+}
+
+struct spi_flash *spi_flash_probe(unsigned int busnum, unsigned int cs,
+ unsigned int max_hz, unsigned int spi_mode)
+{
+ struct spi_slave *bus;
+
+ bus = spi_setup_slave(busnum, cs, max_hz, spi_mode);
+ return spi_flash_probe_tail(bus);
+}
+
+#ifdef CONFIG_OF_SPI_FLASH
+struct spi_flash *spi_flash_probe_fdt(const void *blob, int slave_node,
+ int spi_node)
+{
+ struct spi_slave *bus;
+
+ bus = spi_setup_slave_fdt(blob, slave_node, spi_node);
+ return spi_flash_probe_tail(bus);
+}
+#endif
+
+void spi_flash_free(struct spi_flash *flash)
+{
+ spi_free_slave(flash->spi);
+ free(flash);
+}
+
+#else /* defined CONFIG_DM_SPI_FLASH */
+
+static int spi_flash_std_read(struct udevice *dev, u32 offset, size_t len,
+ void *buf)
+{
+ struct spi_flash *flash = dev->uclass_priv;
+
+ return spi_flash_cmd_read_ops(flash, offset, len, buf);
+}
+
+int spi_flash_std_write(struct udevice *dev, u32 offset, size_t len,
+ const void *buf)
+{
+ struct spi_flash *flash = dev->uclass_priv;
+
+ return spi_flash_cmd_write_ops(flash, offset, len, buf);
+}
+
+int spi_flash_std_erase(struct udevice *dev, u32 offset, size_t len)
+{
+ struct spi_flash *flash = dev->uclass_priv;
+
+ return spi_flash_cmd_erase_ops(flash, offset, len);
+}
+
+int spi_flash_std_probe(struct udevice *dev)
+{
+ struct spi_slave *slave = dev_get_parentdata(dev);
+ struct spi_flash *flash;
+
+ flash = dev->uclass_priv;
+ flash->dev = dev;
+ debug("%s: slave=%p, cs=%d\n", __func__, slave, slave->cs);
+ return spi_flash_probe_slave(slave, flash);
+}
+
+static const struct dm_spi_flash_ops spi_flash_std_ops = {
+ .read = spi_flash_std_read,
+ .write = spi_flash_std_write,
+ .erase = spi_flash_std_erase,
+};
+
+static const struct udevice_id spi_flash_std_ids[] = {
+ { .compatible = "spi-flash" },
+ { }
+};
+
+U_BOOT_DRIVER(spi_flash_std) = {
+ .name = "spi_flash_std",
+ .id = UCLASS_SPI_FLASH,
+ .of_match = spi_flash_std_ids,
+ .probe = spi_flash_std_probe,
+ .priv_auto_alloc_size = sizeof(struct spi_flash),
+ .ops = &spi_flash_std_ops,
+};
+#endif /* CONFIG_DM_SPI_FLASH */
diff --git a/include/spi_flash.h b/include/spi_flash.h
index 5913b39..90ce389 100644
--- a/include/spi_flash.h
+++ b/include/spi_flash.h
@@ -68,26 +68,13 @@ struct spi_flash {
#else
struct spi_slave *spi;
#endif
+ struct sf_nor *nor;
const char *name;
- u8 dual_flash;
- u8 shift;
u32 size;
- u32 page_size;
u32 sector_size;
u32 erase_size;
-#ifdef CONFIG_SPI_FLASH_BAR
- u8 bank_read_cmd;
- u8 bank_write_cmd;
- u8 bank_curr;
-#endif
- u8 poll_cmd;
- u8 erase_cmd;
- u8 read_cmd;
- u8 write_cmd;
- u8 dummy_byte;
- void *memory_map;
#ifndef CONFIG_DM_SPI_FLASH
/*
* These are not strictly needed for driver model, but keep them here
--
1.9.1
More information about the U-Boot
mailing list