Merge branch 'master' of git://git.denx.de/u-boot-spi

This commit is contained in:
Tom Rini 2014-01-13 13:45:15 -05:00
commit 10fcda8e25
16 changed files with 1173 additions and 200 deletions

6
README
View file

@ -2756,6 +2756,12 @@ CBFS (Coreboot Filesystem) support
Define this option to use the Bank addr/Extended addr
support on SPI flashes which has size > 16Mbytes.
CONFIG_SF_DUAL_FLASH Dual flash memories
Define this option to use dual flash support where two flash
memories can be connected with a given cs line.
currently Xilinx Zynq qspi support these type of connections.
- SystemACE Support:
CONFIG_SYSTEMACE

View file

@ -358,7 +358,8 @@ static void show_time(struct test_info *test, int stage)
int bps; /* Bits per second */
speed = (long long)test->bytes * 1000;
do_div(speed, test->time_ms[stage] * 1024);
if (test->time_ms[stage])
do_div(speed, test->time_ms[stage] * 1024);
bps = speed * 8;
printf("%d %s: %d ticks, %d KiB/s %d.%03d Mbps\n", stage,
@ -446,11 +447,13 @@ static int do_spi_flash_test(int argc, char * const argv[])
{
unsigned long offset;
unsigned long len;
uint8_t *buf = (uint8_t *)CONFIG_SYS_TEXT_BASE;
uint8_t *buf, *from;
char *endp;
uint8_t *vbuf;
int ret;
if (argc < 3)
return -1;
offset = simple_strtoul(argv[1], &endp, 16);
if (*argv[1] == 0 || *endp != 0)
return -1;
@ -460,17 +463,18 @@ static int do_spi_flash_test(int argc, char * const argv[])
vbuf = malloc(len);
if (!vbuf) {
printf("Cannot allocate memory\n");
printf("Cannot allocate memory (%lu bytes)\n", len);
return 1;
}
buf = malloc(len);
if (!buf) {
free(vbuf);
printf("Cannot allocate memory\n");
printf("Cannot allocate memory (%lu bytes)\n", len);
return 1;
}
memcpy(buf, (char *)CONFIG_SYS_TEXT_BASE, len);
from = map_sysmem(CONFIG_SYS_TEXT_BASE, 0);
memcpy(buf, from, len);
ret = spi_flash_test(flash, buf, len, offset, vbuf);
free(vbuf);
free(buf);

92
doc/SPI/README.dual-flash Normal file
View file

@ -0,0 +1,92 @@
SPI/QSPI Dual flash connection modes:
=====================================
This describes how SPI/QSPI flash memories are connected to a given
controller in a single chip select line.
Current spi_flash framework supports, single flash memory connected
to a given controller with single chip select line, but there are some
hw logics(ex: xilinx zynq qspi) that describes two/dual memories are
connected with a single chip select line from a controller.
"dual_flash" from include/spi.h describes these types of connection mode
Possible connections:
--------------------
SF_SINGLE_FLASH:
- single spi flash memory connected with single chip select line.
+------------+ CS +---------------+
| |----------------------->| |
| Controller | I0[3:0] | Flash memory |
| SPI/QSPI |<======================>| (SPI/QSPI) |
| | CLK | |
| |----------------------->| |
+------------+ +---------------+
SF_DUAL_STACKED_FLASH:
- dual spi/qspi flash memories are connected with a single chipselect
line and these two memories are operating stacked fasion with shared buses.
- xilinx zynq qspi controller has implemented this feature [1]
+------------+ CS +---------------+
| |---------------------->| |
| | I0[3:0] | Upper Flash |
| | +=========>| memory |
| | | CLK | (SPI/QSPI) |
| | | +---->| |
| Controller | CS | | +---------------+
| SPI/QSPI |------------|----|---->| |
| | I0[3:0] | | | Lower Flash |
| |<===========+====|====>| memory |
| | CLK | | (SPI/QSPI) |
| |-----------------+---->| |
+------------+ +---------------+
- two memory flash devices should has same hw part attributes (like size,
vendor..etc)
- Configurations:
on LQSPI_CFG register, Enable TWO_MEM[BIT:30] on LQSPI_CFG
Enable U_PAGE[BIT:28] if U_PAGE flag set - upper memory
Disable U_PAGE[BIT:28] if U_PAGE flag unset - lower memory
- Operation:
accessing memories serially like one after another.
by default, if U_PAGE is unset lower memory should accessible,
once user wants to access upper memory need to set U_PAGE.
SPI_FLASH_CONN_DUALPARALLEL:
- dual spi/qspi flash memories are connected with a single chipselect
line and these two memories are operating parallel with separate buses.
- xilinx zynq qspi controller has implemented this feature [1]
+-------------+ CS +---------------+
| |---------------------->| |
| | I0[3:0] | Upper Flash |
| |<=====================>| memory |
| | CLK | (SPI/QSPI) |
| |---------------------->| |
| Controller | CS +---------------+
| SPI/QSPI |---------------------->| |
| | I0[3:0] | Lower Flash |
| |<=====================>| memory |
| | CLK | (SPI/QSPI) |
| |---------------------->| |
+-------------+ +---------------+
- two memory flash devices should has same hw part attributes (like size,
vendor..etc)
- Configurations:
Need to enable SEP_BUS[BIT:29],TWO_MEM[BIT:30] on LQSPI_CFG register.
- Operation:
Even bits, i.e. bit 0, 2, 4 ., of a data word is located in the lower memory
and odd bits, i.e. bit 1, 3, 5, ., of a data word is located in the upper memory.
Note: Technically there is only one CS line from the controller, but
zynq qspi controller has an internal hw logic to enable additional CS
when controller is configured for dual memories.
[1] http://www.xilinx.com/support/documentation/user_guides/ug585-Zynq-7000-TRM.pdf
--
Jagannadha Sutradharudu Teki <jaganna@xilinx.com>
05-01-2014.

View file

@ -0,0 +1,41 @@
SPI Flash test on Faraday A369 EVB:
==================================
U-Boot 2014.01-rc2-g3444b6f (Dec 20 2013 - 10:58:40)
CPU: FA626TE 528 MHz
AHB: 132 MHz
APB: 66 MHz
I2C: ready
DRAM: 256 MiB
MMU: on
NAND: 512 MiB
MMC: ftsdc010: 0
*** Warning - bad CRC, using default environment
In: serial
Out: serial
Err: serial
Net: FTGMAC100#0
Hit any key to stop autoboot: 0
=> sf probe 0:0
SF: Detected MX25L1605D with page size 256 Bytes, erase size 64 KiB, total 2 MiB
=> sf read 0x10800000 0 0x400
SF: 1024 bytes @ 0x0 Read: OK
=> md 0x10800000
10800000: ea000013 e59ff014 e59ff014 e59ff014 ................
10800010: e59ff014 e59ff014 e59ff014 e59ff014 ................
10800020: 1ff7b0c0 1ff7b120 1ff7b180 1ff7b1e0 .... ...........
10800030: 1ff7b240 1ff7b2a0 1ff7b300 deadbeef @...............
10800040: 10800000 0002c1f0 0007409c 00032048 .........@..H ..
10800050: 1fd6af40 e10f0000 e3c0001f e38000d3 @...............
10800060: e129f000 eb000001 eb000223 e12fff1e ..).....#...../.
10800070: e3a00000 ee070f1e ee080f17 ee070f15 ................
10800080: ee070f9a ee110f10 e3c00c03 e3c00087 ................
10800090: e3c00a02 e3800002 e3800a01 ee010f10 ................
108000a0: e1a0c00e eb007a68 e1a0e00c e1a0f00e ....hz..........
108000b0: e1a00000 e1a00000 e1a00000 e1a00000 ................
108000c0: e51fd078 e58de000 e14fe000 e58de004 x.........O.....
108000d0: e3a0d013 e169f00d e1a0e00f e1b0f00e ......i.........
108000e0: e24dd048 e88d1fff e51f20a0 e892000c H.M...... ......
108000f0: e28d0048 e28d5034 e1a0100e e885000f H...4P..........

View file

@ -11,6 +11,11 @@ SPI FLASH (drivers/mtd/spi):
- Bank Address Register (Accessing flashes > 16Mbytes in 3-byte addressing)
- Added memory_mapped support for read operations.
- Common probe support for all supported flash vendors except, ramtron.
- Extended read commands support(dual read, dual IO read)
- Quad Page Program support.
- Quad Read support(quad fast read, quad IO read)
- Dual flash connection topology support(accessing two spi flash memories with single cs)
- Banking support on dual flash connection topology.
SPI DRIVERS (drivers/spi):
-
@ -18,14 +23,10 @@ SPI DRIVERS (drivers/spi):
TODO:
- Runtime detection of spi_flash params, SFDP(if possible)
- Add support for multibus build/accessing.
- Extended read commands support(dual read, dual IO read)
- Quad Page Program support.
- Quad Read support(quad fast read, quad IO read)
- Dual flash connection topology support(accessing two spi flash memories with single cs)
- Banking support on dual flash connection topology.
- Need proper cleanups on spi_flash and drivers.
--
Jagannadha Sutradharudu Teki <jagannadh.teki@gmail.com>
18-09-2013.
07-10-2013.
08-01-2014.

View file

@ -10,8 +10,8 @@ obj-$(CONFIG_SPL_SPI_LOAD) += spi_spl_load.o
obj-$(CONFIG_SPL_SPI_BOOT) += fsl_espi_spl.o
endif
obj-$(CONFIG_CMD_SF) += sf.o
obj-$(CONFIG_SPI_FLASH) += sf_probe.o sf_ops.o
obj-$(CONFIG_CMD_SF) += sf.o
obj-$(CONFIG_SPI_FLASH) += sf_params.o sf_probe.o sf_ops.o
obj-$(CONFIG_SPI_FRAM_RAMTRON) += ramtron.o
obj-$(CONFIG_SPI_FLASH_SANDBOX) += sandbox.o
obj-$(CONFIG_SPI_M95XXX) += eeprom_m95xxx.o

View file

@ -18,6 +18,10 @@ static int spi_flash_read_write(struct spi_slave *spi,
unsigned long flags = SPI_XFER_BEGIN;
int ret;
#ifdef CONFIG_SF_DUAL_FLASH
if (spi->flags & SPI_XFER_U_PAGE)
flags |= SPI_XFER_U_PAGE;
#endif
if (data_len == 0)
flags |= SPI_XFER_END;

View file

@ -10,12 +10,15 @@
#ifndef _SF_INTERNAL_H_
#define _SF_INTERNAL_H_
#define SPI_FLASH_3B_ADDR_LEN 3
#define SPI_FLASH_CMD_LEN (1 + SPI_FLASH_3B_ADDR_LEN)
#define SPI_FLASH_16MB_BOUN 0x1000000
/* SECT flags */
#define SECT_4K (1 << 1)
#define SECT_32K (1 << 2)
#define E_FSR (1 << 3)
/* 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
@ -28,6 +31,7 @@
#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
@ -36,6 +40,10 @@
/* 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 */
@ -47,8 +55,10 @@
#endif
/* Common status */
#define STATUS_WIP 0x01
#define STATUS_PEC 0x80
#define STATUS_WIP (1 << 0)
#define STATUS_QEB_WINSPAN (1 << 1)
#define STATUS_QEB_MXIC (1 << 6)
#define STATUS_PEC (1 << 7)
/* Flash timeout values */
#define SPI_FLASH_PROG_TIMEOUT (2 * CONFIG_SYS_HZ)
@ -86,11 +96,17 @@ int spi_flash_cmd_write(struct spi_slave *spi, const u8 *cmd, size_t cmd_len,
/* Flash erase(sectors) operation, support all possible erase commands */
int spi_flash_cmd_erase_ops(struct spi_flash *flash, u32 offset, size_t len);
/* Program the status register */
int spi_flash_cmd_write_status(struct spi_flash *flash, u8 sr);
/* Read the status register */
int spi_flash_cmd_read_status(struct spi_flash *flash, u8 *rs);
/* Set quad enbale bit */
int spi_flash_set_qeb(struct spi_flash *flash);
/* Program the status register */
int spi_flash_cmd_write_status(struct spi_flash *flash, u8 ws);
/* Read the config register */
int spi_flash_cmd_read_config(struct spi_flash *flash, u8 *rc);
/* Program the config register */
int spi_flash_cmd_write_config(struct spi_flash *flash, u8 wc);
/* Enable writing on the SPI flash */
static inline int spi_flash_cmd_write_enable(struct spi_flash *flash)

View file

@ -9,6 +9,7 @@
*/
#include <common.h>
#include <malloc.h>
#include <spi.h>
#include <spi_flash.h>
#include <watchdog.h>
@ -23,13 +24,28 @@ static void spi_flash_addr(u32 addr, u8 *cmd)
cmd[3] = addr >> 0;
}
int spi_flash_cmd_write_status(struct spi_flash *flash, u8 sr)
int spi_flash_cmd_read_status(struct spi_flash *flash, u8 *rs)
{
int ret;
u8 cmd;
cmd = CMD_READ_STATUS;
ret = spi_flash_read_common(flash, &cmd, 1, rs, 1);
if (ret < 0) {
debug("SF: fail to read status register\n");
return ret;
}
return 0;
}
int spi_flash_cmd_write_status(struct spi_flash *flash, u8 ws)
{
u8 cmd;
int ret;
cmd = CMD_WRITE_STATUS;
ret = spi_flash_write_common(flash, &cmd, 1, &sr, 1);
ret = spi_flash_write_common(flash, &cmd, 1, &ws, 1);
if (ret < 0) {
debug("SF: fail to write status register\n");
return ret;
@ -38,6 +54,44 @@ int spi_flash_cmd_write_status(struct spi_flash *flash, u8 sr)
return 0;
}
#if defined(CONFIG_SPI_FLASH_SPANSION) || defined(CONFIG_SPI_FLASH_WINBOND)
int spi_flash_cmd_read_config(struct spi_flash *flash, u8 *rc)
{
int ret;
u8 cmd;
cmd = CMD_READ_CONFIG;
ret = spi_flash_read_common(flash, &cmd, 1, rc, 1);
if (ret < 0) {
debug("SF: fail to read config register\n");
return ret;
}
return 0;
}
int spi_flash_cmd_write_config(struct spi_flash *flash, u8 wc)
{
u8 data[2];
u8 cmd;
int ret;
ret = spi_flash_cmd_read_status(flash, &data[0]);
if (ret < 0)
return ret;
cmd = CMD_WRITE_STATUS;
data[1] = wc;
ret = spi_flash_write_common(flash, &cmd, 1, &data, 2);
if (ret) {
debug("SF: fail to write config register\n");
return ret;
}
return 0;
}
#endif
#ifdef CONFIG_SPI_FLASH_BAR
static int spi_flash_cmd_bankaddr_write(struct spi_flash *flash, u8 bank_sel)
{
@ -65,7 +119,7 @@ static int spi_flash_bank(struct spi_flash *flash, u32 offset)
u8 bank_sel;
int ret;
bank_sel = offset / SPI_FLASH_16MB_BOUN;
bank_sel = offset / (SPI_FLASH_16MB_BOUN << flash->shift);
ret = spi_flash_cmd_bankaddr_write(flash, bank_sel);
if (ret) {
@ -73,7 +127,29 @@ static int spi_flash_bank(struct spi_flash *flash, u32 offset)
return ret;
}
return 0;
return bank_sel;
}
#endif
#ifdef CONFIG_SF_DUAL_FLASH
static void spi_flash_dual_flash(struct spi_flash *flash, u32 *addr)
{
switch (flash->dual_flash) {
case SF_DUAL_STACKED_FLASH:
if (*addr >= (flash->size >> 1)) {
*addr -= flash->size >> 1;
flash->spi->flags |= SPI_XFER_U_PAGE;
} else {
flash->spi->flags &= ~SPI_XFER_U_PAGE;
}
break;
case SF_DUAL_PARALLEL_FLASH:
*addr >>= flash->shift;
break;
default:
debug("SF: Unsupported dual_flash=%d\n", flash->dual_flash);
break;
}
}
#endif
@ -81,6 +157,7 @@ int spi_flash_cmd_wait_ready(struct spi_flash *flash, unsigned long timeout)
{
struct spi_slave *spi = flash->spi;
unsigned long timebase;
unsigned long flags = SPI_XFER_BEGIN;
int ret;
u8 status;
u8 check_status = 0x0;
@ -92,7 +169,11 @@ int spi_flash_cmd_wait_ready(struct spi_flash *flash, unsigned long timeout)
check_status = poll_bit;
}
ret = spi_xfer(spi, 8, &cmd, NULL, SPI_XFER_BEGIN);
#ifdef CONFIG_SF_DUAL_FLASH
if (spi->flags & SPI_XFER_U_PAGE)
flags |= SPI_XFER_U_PAGE;
#endif
ret = spi_xfer(spi, 8, &cmd, NULL, flags);
if (ret) {
debug("SF: fail to read %s status register\n",
cmd == CMD_READ_STATUS ? "read" : "flag");
@ -165,8 +246,8 @@ int spi_flash_write_common(struct spi_flash *flash, const u8 *cmd,
int spi_flash_cmd_erase_ops(struct spi_flash *flash, u32 offset, size_t len)
{
u32 erase_size;
u8 cmd[4];
u32 erase_size, erase_addr;
u8 cmd[SPI_FLASH_CMD_LEN];
int ret = -1;
erase_size = flash->erase_size;
@ -177,15 +258,21 @@ int spi_flash_cmd_erase_ops(struct spi_flash *flash, u32 offset, size_t len)
cmd[0] = flash->erase_cmd;
while (len) {
erase_addr = offset;
#ifdef CONFIG_SF_DUAL_FLASH
if (flash->dual_flash > SF_SINGLE_FLASH)
spi_flash_dual_flash(flash, &erase_addr);
#endif
#ifdef CONFIG_SPI_FLASH_BAR
ret = spi_flash_bank(flash, offset);
ret = spi_flash_bank(flash, erase_addr);
if (ret < 0)
return ret;
#endif
spi_flash_addr(offset, cmd);
spi_flash_addr(erase_addr, cmd);
debug("SF: erase %2x %2x %2x %2x (%x)\n", cmd[0], cmd[1],
cmd[2], cmd[3], offset);
cmd[2], cmd[3], erase_addr);
ret = spi_flash_write_common(flash, cmd, sizeof(cmd), NULL, 0);
if (ret < 0) {
@ -204,16 +291,23 @@ int spi_flash_cmd_write_ops(struct spi_flash *flash, u32 offset,
size_t len, const void *buf)
{
unsigned long byte_addr, page_size;
u32 write_addr;
size_t chunk_len, actual;
u8 cmd[4];
u8 cmd[SPI_FLASH_CMD_LEN];
int ret = -1;
page_size = flash->page_size;
cmd[0] = CMD_PAGE_PROGRAM;
cmd[0] = flash->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)
spi_flash_dual_flash(flash, &write_addr);
#endif
#ifdef CONFIG_SPI_FLASH_BAR
ret = spi_flash_bank(flash, offset);
ret = spi_flash_bank(flash, write_addr);
if (ret < 0)
return ret;
#endif
@ -223,9 +317,9 @@ int spi_flash_cmd_write_ops(struct spi_flash *flash, u32 offset,
if (flash->spi->max_write_size)
chunk_len = min(chunk_len, flash->spi->max_write_size);
spi_flash_addr(offset, cmd);
spi_flash_addr(write_addr, cmd);
debug("PP: 0x%p => cmd = { 0x%02x 0x%02x%02x%02x } chunk_len = %zu\n",
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),
@ -267,8 +361,9 @@ int spi_flash_read_common(struct spi_flash *flash, const u8 *cmd,
int spi_flash_cmd_read_ops(struct spi_flash *flash, u32 offset,
size_t len, void *data)
{
u8 cmd[5], bank_sel = 0;
u32 remain_len, read_len;
u8 *cmd, cmdsz;
u32 remain_len, read_len, read_addr;
int bank_sel = 0;
int ret = -1;
/* Handle memory-mapped SPI */
@ -285,29 +380,33 @@ int spi_flash_cmd_read_ops(struct spi_flash *flash, u32 offset,
return 0;
}
cmd[0] = CMD_READ_ARRAY_FAST;
cmd[4] = 0x00;
cmdsz = SPI_FLASH_CMD_LEN + flash->dummy_byte;
cmd = malloc(cmdsz);
memset(cmd, 0, cmdsz);
cmd[0] = flash->read_cmd;
while (len) {
#ifdef CONFIG_SPI_FLASH_BAR
bank_sel = offset / SPI_FLASH_16MB_BOUN;
read_addr = offset;
ret = spi_flash_cmd_bankaddr_write(flash, bank_sel);
if (ret) {
debug("SF: fail to set bank%d\n", bank_sel);
return ret;
}
#ifdef CONFIG_SF_DUAL_FLASH
if (flash->dual_flash > SF_SINGLE_FLASH)
spi_flash_dual_flash(flash, &read_addr);
#endif
remain_len = (SPI_FLASH_16MB_BOUN * (bank_sel + 1)) - offset;
#ifdef CONFIG_SPI_FLASH_BAR
bank_sel = spi_flash_bank(flash, read_addr);
if (bank_sel < 0)
return ret;
#endif
remain_len = ((SPI_FLASH_16MB_BOUN << flash->shift) *
(bank_sel + 1)) - offset;
if (len < remain_len)
read_len = len;
else
read_len = remain_len;
spi_flash_addr(offset, cmd);
spi_flash_addr(read_addr, cmd);
ret = spi_flash_read_common(flash, cmd, sizeof(cmd),
data, read_len);
ret = spi_flash_read_common(flash, cmd, cmdsz, data, read_len);
if (ret < 0) {
debug("SF: read failed\n");
break;

130
drivers/mtd/spi/sf_params.c Normal file
View file

@ -0,0 +1,130 @@
/*
* SPI flash Params table
*
* Copyright (C) 2013 Jagannadha Sutradharudu Teki, Xilinx Inc.
*
* SPDX-License-Identifier: GPL-2.0+
*/
#include <common.h>
#include <spi_flash.h>
#include "sf_internal.h"
/* SPI/QSPI flash device params structure */
const struct spi_flash_params spi_flash_params_table[] = {
#ifdef CONFIG_SPI_FLASH_ATMEL /* ATMEL */
{"AT45DB011D", 0x1f2200, 0x0, 64 * 1024, 4, 0, SECT_4K},
{"AT45DB021D", 0x1f2300, 0x0, 64 * 1024, 8, 0, SECT_4K},
{"AT45DB041D", 0x1f2400, 0x0, 64 * 1024, 8, 0, SECT_4K},
{"AT45DB081D", 0x1f2500, 0x0, 64 * 1024, 16, 0, SECT_4K},
{"AT45DB161D", 0x1f2600, 0x0, 64 * 1024, 32, 0, SECT_4K},
{"AT45DB321D", 0x1f2700, 0x0, 64 * 1024, 64, 0, SECT_4K},
{"AT45DB641D", 0x1f2800, 0x0, 64 * 1024, 128, 0, SECT_4K},
{"AT25DF321", 0x1f4701, 0x0, 64 * 1024, 64, 0, SECT_4K},
#endif
#ifdef CONFIG_SPI_FLASH_EON /* EON */
{"EN25Q32B", 0x1c3016, 0x0, 64 * 1024, 64, 0, 0},
{"EN25Q64", 0x1c3017, 0x0, 64 * 1024, 128, 0, SECT_4K},
{"EN25Q128B", 0x1c3018, 0x0, 64 * 1024, 256, 0, 0},
{"EN25S64", 0x1c3817, 0x0, 64 * 1024, 128, 0, 0},
#endif
#ifdef CONFIG_SPI_FLASH_GIGADEVICE /* GIGADEVICE */
{"GD25Q64B", 0xc84017, 0x0, 64 * 1024, 128, 0, SECT_4K},
{"GD25LQ32", 0xc86016, 0x0, 64 * 1024, 64, 0, SECT_4K},
#endif
#ifdef CONFIG_SPI_FLASH_MACRONIX /* MACRONIX */
{"MX25L2006E", 0xc22012, 0x0, 64 * 1024, 4, 0, 0},
{"MX25L4005", 0xc22013, 0x0, 64 * 1024, 8, 0, 0},
{"MX25L8005", 0xc22014, 0x0, 64 * 1024, 16, 0, 0},
{"MX25L1605D", 0xc22015, 0x0, 64 * 1024, 32, 0, 0},
{"MX25L3205D", 0xc22016, 0x0, 64 * 1024, 64, 0, 0},
{"MX25L6405D", 0xc22017, 0x0, 64 * 1024, 128, 0, 0},
{"MX25L12805", 0xc22018, 0x0, 64 * 1024, 256, RD_FULL, WR_QPP},
{"MX25L25635F", 0xc22019, 0x0, 64 * 1024, 512, RD_FULL, WR_QPP},
{"MX25L51235F", 0xc2201a, 0x0, 64 * 1024, 1024, RD_FULL, WR_QPP},
{"MX25L12855E", 0xc22618, 0x0, 64 * 1024, 256, RD_FULL, WR_QPP},
#endif
#ifdef CONFIG_SPI_FLASH_SPANSION /* SPANSION */
{"S25FL008A", 0x010213, 0x0, 64 * 1024, 16, 0, 0},
{"S25FL016A", 0x010214, 0x0, 64 * 1024, 32, 0, 0},
{"S25FL032A", 0x010215, 0x0, 64 * 1024, 64, 0, 0},
{"S25FL064A", 0x010216, 0x0, 64 * 1024, 128, 0, 0},
{"S25FL128P_256K", 0x012018, 0x0300, 256 * 1024, 64, RD_FULL, WR_QPP},
{"S25FL128P_64K", 0x012018, 0x0301, 64 * 1024, 256, RD_FULL, WR_QPP},
{"S25FL032P", 0x010215, 0x4d00, 64 * 1024, 64, RD_FULL, WR_QPP},
{"S25FL064P", 0x010216, 0x4d00, 64 * 1024, 128, RD_FULL, WR_QPP},
{"S25FL128S_64K", 0x012018, 0x4d01, 64 * 1024, 256, RD_FULL, WR_QPP},
{"S25FL256S_256K", 0x010219, 0x4d00, 64 * 1024, 512, RD_FULL, WR_QPP},
{"S25FL256S_64K", 0x010219, 0x4d01, 64 * 1024, 512, RD_FULL, WR_QPP},
{"S25FL512S_256K", 0x010220, 0x4d00, 64 * 1024, 1024, RD_FULL, WR_QPP},
{"S25FL512S_64K", 0x010220, 0x4d01, 64 * 1024, 1024, RD_FULL, WR_QPP},
#endif
#ifdef CONFIG_SPI_FLASH_STMICRO /* STMICRO */
{"M25P10", 0x202011, 0x0, 32 * 1024, 4, 0, 0},
{"M25P20", 0x202012, 0x0, 64 * 1024, 4, 0, 0},
{"M25P40", 0x202013, 0x0, 64 * 1024, 8, 0, 0},
{"M25P80", 0x202014, 0x0, 64 * 1024, 16, 0, 0},
{"M25P16", 0x202015, 0x0, 64 * 1024, 32, 0, 0},
{"M25P32", 0x202016, 0x0, 64 * 1024, 64, 0, 0},
{"M25P64", 0x202017, 0x0, 64 * 1024, 128, 0, 0},
{"M25P128", 0x202018, 0x0, 256 * 1024, 64, 0, 0},
{"N25Q32", 0x20ba16, 0x0, 64 * 1024, 64, RD_FULL, WR_QPP | SECT_4K},
{"N25Q32A", 0x20bb16, 0x0, 64 * 1024, 64, RD_FULL, WR_QPP | SECT_4K},
{"N25Q64", 0x20ba17, 0x0, 64 * 1024, 128, RD_FULL, WR_QPP | SECT_4K},
{"N25Q64A", 0x20bb17, 0x0, 64 * 1024, 128, RD_FULL, WR_QPP | SECT_4K},
{"N25Q128", 0x20ba18, 0x0, 64 * 1024, 256, RD_FULL, WR_QPP},
{"N25Q128A", 0x20bb18, 0x0, 64 * 1024, 256, RD_FULL, WR_QPP},
{"N25Q256", 0x20ba19, 0x0, 64 * 1024, 512, RD_FULL, WR_QPP | SECT_4K},
{"N25Q256A", 0x20bb19, 0x0, 64 * 1024, 512, RD_FULL, WR_QPP | SECT_4K},
{"N25Q512", 0x20ba20, 0x0, 64 * 1024, 1024, RD_FULL, WR_QPP | E_FSR | SECT_4K},
{"N25Q512A", 0x20bb20, 0x0, 64 * 1024, 1024, RD_FULL, WR_QPP | E_FSR | SECT_4K},
{"N25Q1024", 0x20ba21, 0x0, 64 * 1024, 2048, RD_FULL, WR_QPP | E_FSR | SECT_4K},
{"N25Q1024A", 0x20bb21, 0x0, 64 * 1024, 2048, RD_FULL, WR_QPP | E_FSR | SECT_4K},
#endif
#ifdef CONFIG_SPI_FLASH_SST /* SST */
{"SST25VF040B", 0xbf258d, 0x0, 64 * 1024, 8, 0, SECT_4K | SST_WP},
{"SST25VF080B", 0xbf258e, 0x0, 64 * 1024, 16, 0, SECT_4K | SST_WP},
{"SST25VF016B", 0xbf2541, 0x0, 64 * 1024, 32, 0, SECT_4K | SST_WP},
{"SST25VF032B", 0xbf254a, 0x0, 64 * 1024, 64, 0, SECT_4K | SST_WP},
{"SST25VF064C", 0xbf254b, 0x0, 64 * 1024, 128, 0, SECT_4K},
{"SST25WF512", 0xbf2501, 0x0, 64 * 1024, 1, 0, SECT_4K | SST_WP},
{"SST25WF010", 0xbf2502, 0x0, 64 * 1024, 2, 0, SECT_4K | SST_WP},
{"SST25WF020", 0xbf2503, 0x0, 64 * 1024, 4, 0, SECT_4K | SST_WP},
{"SST25WF040", 0xbf2504, 0x0, 64 * 1024, 8, 0, SECT_4K | SST_WP},
{"SST25WF080", 0xbf2505, 0x0, 64 * 1024, 16, 0, SECT_4K | SST_WP},
#endif
#ifdef CONFIG_SPI_FLASH_WINBOND /* WINBOND */
{"W25P80", 0xef2014, 0x0, 64 * 1024, 16, 0, 0},
{"W25P16", 0xef2015, 0x0, 64 * 1024, 32, 0, 0},
{"W25P32", 0xef2016, 0x0, 64 * 1024, 64, 0, 0},
{"W25X40", 0xef3013, 0x0, 64 * 1024, 8, 0, SECT_4K},
{"W25X16", 0xef3015, 0x0, 64 * 1024, 32, 0, SECT_4K},
{"W25X32", 0xef3016, 0x0, 64 * 1024, 64, 0, SECT_4K},
{"W25X64", 0xef3017, 0x0, 64 * 1024, 128, 0, SECT_4K},
{"W25Q80BL", 0xef4014, 0x0, 64 * 1024, 16, RD_FULL, WR_QPP | SECT_4K},
{"W25Q16CL", 0xef4015, 0x0, 64 * 1024, 32, RD_FULL, WR_QPP | SECT_4K},
{"W25Q32BV", 0xef4016, 0x0, 64 * 1024, 64, RD_FULL, WR_QPP | SECT_4K},
{"W25Q64CV", 0xef4017, 0x0, 64 * 1024, 128, RD_FULL, WR_QPP | SECT_4K},
{"W25Q128BV", 0xef4018, 0x0, 64 * 1024, 256, RD_FULL, WR_QPP | SECT_4K},
{"W25Q256", 0xef4019, 0x0, 64 * 1024, 512, RD_FULL, WR_QPP | SECT_4K},
{"W25Q80BW", 0xef5014, 0x0, 64 * 1024, 16, RD_FULL, WR_QPP | SECT_4K},
{"W25Q16DW", 0xef6015, 0x0, 64 * 1024, 32, RD_FULL, WR_QPP | SECT_4K},
{"W25Q32DW", 0xef6016, 0x0, 64 * 1024, 64, RD_FULL, WR_QPP | SECT_4K},
{"W25Q64DW", 0xef6017, 0x0, 64 * 1024, 128, RD_FULL, WR_QPP | SECT_4K},
{"W25Q128FW", 0xef6018, 0x0, 64 * 1024, 256, RD_FULL, WR_QPP | SECT_4K},
#endif
/*
* Note:
* Below paired flash devices has similar spi_flash params.
* (S25FL129P_64K, S25FL128S_64K)
* (W25Q80BL, W25Q80BV)
* (W25Q16CL, W25Q16DV)
* (W25Q32BV, W25Q32FV_SPI)
* (W25Q64CV, W25Q64FV_SPI)
* (W25Q128BV, W25Q128FV_SPI)
* (W25Q32DW, W25Q32FV_QPI)
* (W25Q64DW, W25Q64FV_QPI)
* (W25Q128FW, W25Q128FV_QPI)
*/
};

View file

@ -19,154 +19,93 @@
DECLARE_GLOBAL_DATA_PTR;
/**
* 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
* @flags: Importent param, for flash specific behaviour
*/
struct spi_flash_params {
const char *name;
u32 jedec;
u16 ext_jedec;
u32 sector_size;
u32 nr_sectors;
u16 flags;
/* 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,
};
static const struct spi_flash_params spi_flash_params_table[] = {
#ifdef CONFIG_SPI_FLASH_ATMEL /* ATMEL */
{"AT45DB011D", 0x1f2200, 0x0, 64 * 1024, 4, SECT_4K},
{"AT45DB021D", 0x1f2300, 0x0, 64 * 1024, 8, SECT_4K},
{"AT45DB041D", 0x1f2400, 0x0, 64 * 1024, 8, SECT_4K},
{"AT45DB081D", 0x1f2500, 0x0, 64 * 1024, 16, SECT_4K},
{"AT45DB161D", 0x1f2600, 0x0, 64 * 1024, 32, SECT_4K},
{"AT45DB321D", 0x1f2700, 0x0, 64 * 1024, 64, SECT_4K},
{"AT45DB641D", 0x1f2800, 0x0, 64 * 1024, 128, SECT_4K},
{"AT25DF321", 0x1f4701, 0x0, 64 * 1024, 64, SECT_4K},
#ifdef CONFIG_SPI_FLASH_MACRONIX
static int spi_flash_set_qeb_mxic(struct spi_flash *flash)
{
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
#ifdef CONFIG_SPI_FLASH_EON /* EON */
{"EN25Q32B", 0x1c3016, 0x0, 64 * 1024, 64, 0},
{"EN25Q64", 0x1c3017, 0x0, 64 * 1024, 128, SECT_4K},
{"EN25Q128B", 0x1c3018, 0x0, 64 * 1024, 256, 0},
{"EN25S64", 0x1c3817, 0x0, 64 * 1024, 128, 0},
#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
#ifdef CONFIG_SPI_FLASH_GIGADEVICE /* GIGADEVICE */
{"GD25Q64B", 0xc84017, 0x0, 64 * 1024, 128, SECT_4K},
{"GD25LQ32", 0xc86016, 0x0, 64 * 1024, 64, SECT_4K},
static int spi_flash_set_qeb(struct spi_flash *flash, u8 idcode0)
{
switch (idcode0) {
#ifdef CONFIG_SPI_FLASH_MACRONIX
case SPI_FLASH_CFI_MFR_MACRONIX:
return spi_flash_set_qeb_mxic(flash);
#endif
#ifdef CONFIG_SPI_FLASH_MACRONIX /* MACRONIX */
{"MX25L2006E", 0xc22012, 0x0, 64 * 1024, 4, 0},
{"MX25L4005", 0xc22013, 0x0, 64 * 1024, 8, 0},
{"MX25L8005", 0xc22014, 0x0, 64 * 1024, 16, 0},
{"MX25L1605D", 0xc22015, 0x0, 64 * 1024, 32, 0},
{"MX25L3205D", 0xc22016, 0x0, 64 * 1024, 64, 0},
{"MX25L6405D", 0xc22017, 0x0, 64 * 1024, 128, 0},
{"MX25L12805", 0xc22018, 0x0, 64 * 1024, 256, 0},
{"MX25L25635F", 0xc22019, 0x0, 64 * 1024, 512, 0},
{"MX25L51235F", 0xc2201a, 0x0, 64 * 1024, 1024, 0},
{"MX25L12855E", 0xc22618, 0x0, 64 * 1024, 256, 0},
#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(flash);
#endif
#ifdef CONFIG_SPI_FLASH_SPANSION /* SPANSION */
{"S25FL008A", 0x010213, 0x0, 64 * 1024, 16, 0},
{"S25FL016A", 0x010214, 0x0, 64 * 1024, 32, 0},
{"S25FL032A", 0x010215, 0x0, 64 * 1024, 64, 0},
{"S25FL064A", 0x010216, 0x0, 64 * 1024, 128, 0},
{"S25FL128P_256K", 0x012018, 0x0300, 256 * 1024, 64, 0},
{"S25FL128P_64K", 0x012018, 0x0301, 64 * 1024, 256, 0},
{"S25FL032P", 0x010215, 0x4d00, 64 * 1024, 64, 0},
{"S25FL064P", 0x010216, 0x4d00, 64 * 1024, 128, 0},
{"S25FL128S_64K", 0x012018, 0x4d01, 64 * 1024, 256, 0},
{"S25FL256S_256K", 0x010219, 0x4d00, 64 * 1024, 512, 0},
{"S25FL256S_64K", 0x010219, 0x4d01, 64 * 1024, 512, 0},
{"S25FL512S_256K", 0x010220, 0x4d00, 64 * 1024, 1024, 0},
{"S25FL512S_64K", 0x010220, 0x4d01, 64 * 1024, 1024, 0},
#ifdef CONFIG_SPI_FLASH_STMICRO
case SPI_FLASH_CFI_MFR_STMICRO:
debug("SF: QEB is volatile for %02x flash\n", idcode0);
return 0;
#endif
#ifdef CONFIG_SPI_FLASH_STMICRO /* STMICRO */
{"M25P10", 0x202011, 0x0, 32 * 1024, 4, 0},
{"M25P20", 0x202012, 0x0, 64 * 1024, 4, 0},
{"M25P40", 0x202013, 0x0, 64 * 1024, 8, 0},
{"M25P80", 0x202014, 0x0, 64 * 1024, 16, 0},
{"M25P16", 0x202015, 0x0, 64 * 1024, 32, 0},
{"M25P32", 0x202016, 0x0, 64 * 1024, 64, 0},
{"M25P64", 0x202017, 0x0, 64 * 1024, 128, 0},
{"M25P128", 0x202018, 0x0, 256 * 1024, 64, 0},
{"N25Q32", 0x20ba16, 0x0, 64 * 1024, 64, SECT_4K},
{"N25Q32A", 0x20bb16, 0x0, 64 * 1024, 64, SECT_4K},
{"N25Q64", 0x20ba17, 0x0, 64 * 1024, 128, SECT_4K},
{"N25Q64A", 0x20bb17, 0x0, 64 * 1024, 128, SECT_4K},
{"N25Q128", 0x20ba18, 0x0, 64 * 1024, 256, SECT_4K},
{"N25Q128A", 0x20bb18, 0x0, 64 * 1024, 256, SECT_4K},
{"N25Q256", 0x20ba19, 0x0, 64 * 1024, 512, SECT_4K},
{"N25Q256A", 0x20bb19, 0x0, 64 * 1024, 512, SECT_4K},
{"N25Q512", 0x20ba20, 0x0, 64 * 1024, 1024, E_FSR | SECT_4K},
{"N25Q512A", 0x20bb20, 0x0, 64 * 1024, 1024, E_FSR | SECT_4K},
{"N25Q1024", 0x20ba21, 0x0, 64 * 1024, 2048, E_FSR | SECT_4K},
{"N25Q1024A", 0x20bb21, 0x0, 64 * 1024, 2048, E_FSR | SECT_4K},
#endif
#ifdef CONFIG_SPI_FLASH_SST /* SST */
{"SST25VF040B", 0xbf258d, 0x0, 64 * 1024, 8, SECT_4K | SST_WP},
{"SST25VF080B", 0xbf258e, 0x0, 64 * 1024, 16, SECT_4K | SST_WP},
{"SST25VF016B", 0xbf2541, 0x0, 64 * 1024, 32, SECT_4K | SST_WP},
{"SST25VF032B", 0xbf254a, 0x0, 64 * 1024, 64, SECT_4K | SST_WP},
{"SST25VF064C", 0xbf254b, 0x0, 64 * 1024, 128, SECT_4K},
{"SST25WF512", 0xbf2501, 0x0, 64 * 1024, 1, SECT_4K | SST_WP},
{"SST25WF010", 0xbf2502, 0x0, 64 * 1024, 2, SECT_4K | SST_WP},
{"SST25WF020", 0xbf2503, 0x0, 64 * 1024, 4, SECT_4K | SST_WP},
{"SST25WF040", 0xbf2504, 0x0, 64 * 1024, 8, SECT_4K | SST_WP},
{"SST25WF080", 0xbf2505, 0x0, 64 * 1024, 16, SECT_4K | SST_WP},
#endif
#ifdef CONFIG_SPI_FLASH_WINBOND /* WINBOND */
{"W25P80", 0xef2014, 0x0, 64 * 1024, 16, 0},
{"W25P16", 0xef2015, 0x0, 64 * 1024, 32, 0},
{"W25P32", 0xef2016, 0x0, 64 * 1024, 64, 0},
{"W25X40", 0xef3013, 0x0, 64 * 1024, 8, SECT_4K},
{"W25X16", 0xef3015, 0x0, 64 * 1024, 32, SECT_4K},
{"W25X32", 0xef3016, 0x0, 64 * 1024, 64, SECT_4K},
{"W25X64", 0xef3017, 0x0, 64 * 1024, 128, SECT_4K},
{"W25Q80BL", 0xef4014, 0x0, 64 * 1024, 16, SECT_4K},
{"W25Q16CL", 0xef4015, 0x0, 64 * 1024, 32, SECT_4K},
{"W25Q32BV", 0xef4016, 0x0, 64 * 1024, 64, SECT_4K},
{"W25Q64CV", 0xef4017, 0x0, 64 * 1024, 128, SECT_4K},
{"W25Q128BV", 0xef4018, 0x0, 64 * 1024, 256, SECT_4K},
{"W25Q256", 0xef4019, 0x0, 64 * 1024, 512, SECT_4K},
{"W25Q80BW", 0xef5014, 0x0, 64 * 1024, 16, SECT_4K},
{"W25Q16DW", 0xef6015, 0x0, 64 * 1024, 32, SECT_4K},
{"W25Q32DW", 0xef6016, 0x0, 64 * 1024, 64, SECT_4K},
{"W25Q64DW", 0xef6017, 0x0, 64 * 1024, 128, SECT_4K},
{"W25Q128FW", 0xef6018, 0x0, 64 * 1024, 256, SECT_4K},
#endif
/*
* Note:
* Below paired flash devices has similar spi_flash params.
* (S25FL129P_64K, S25FL128S_64K)
* (W25Q80BL, W25Q80BV)
* (W25Q16CL, W25Q16DV)
* (W25Q32BV, W25Q32FV_SPI)
* (W25Q64CV, W25Q64FV_SPI)
* (W25Q128BV, W25Q128FV_SPI)
* (W25Q32DW, W25Q32FV_QPI)
* (W25Q64DW, W25Q64FV_QPI)
* (W25Q128FW, W25Q128FV_QPI)
*/
};
default:
printf("SF: Need set QEB func for %02x flash\n", idcode0);
return -1;
}
}
static struct spi_flash *spi_flash_validate_params(struct spi_slave *spi,
u8 *idcode)
{
const struct spi_flash_params *params;
struct spi_flash *flash;
int i;
u8 cmd;
u16 jedec = idcode[1] << 8 | idcode[2];
u16 ext_jedec = idcode[3] << 8 | idcode[4];
/* Get the flash id (jedec = manuf_id + dev_id, ext_jedec) */
for (i = 0; i < ARRAY_SIZE(spi_flash_params_table); i++) {
params = &spi_flash_params_table[i];
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)
@ -177,7 +116,7 @@ static struct spi_flash *spi_flash_validate_params(struct spi_slave *spi,
}
}
if (i == ARRAY_SIZE(spi_flash_params_table)) {
if (!params->name) {
printf("SF: Unsupported flash IDs: ");
printf("manuf %02x, jedec %04x, ext_jedec %04x\n",
idcode[0], jedec, ext_jedec);
@ -195,6 +134,7 @@ static struct spi_flash *spi_flash_validate_params(struct spi_slave *spi,
flash->spi = spi;
flash->name = params->name;
flash->memory_map = spi->memory_map;
flash->dual_flash = flash->spi->option;
/* Assign spi_flash ops */
flash->write = spi_flash_cmd_write_ops;
@ -206,23 +146,74 @@ static struct spi_flash *spi_flash_validate_params(struct spi_slave *spi,
flash->read = spi_flash_cmd_read_ops;
/* Compute the flash size */
flash->page_size = (ext_jedec == 0x4d00) ? 512 : 256;
flash->sector_size = params->sector_size;
flash->size = flash->sector_size * params->nr_sectors;
flash->shift = (flash->dual_flash & SF_DUAL_PARALLEL_FLASH) ? 1 : 0;
flash->page_size = ((ext_jedec == 0x4d00) ? 512 : 256) << flash->shift;
flash->sector_size = params->sector_size << flash->shift;
flash->size = flash->sector_size * params->nr_sectors << flash->shift;
#ifdef CONFIG_SF_DUAL_FLASH
if (flash->dual_flash & SF_DUAL_STACKED_FLASH)
flash->size <<= 1;
#endif
/* Compute erase sector and command */
if (params->flags & SECT_4K) {
flash->erase_cmd = CMD_ERASE_4K;
flash->erase_size = 4096;
flash->erase_size = 4096 << flash->shift;
} else if (params->flags & SECT_32K) {
flash->erase_cmd = CMD_ERASE_32K;
flash->erase_size = 32768;
flash->erase_size = 32768 << flash->shift;
} else {
flash->erase_cmd = CMD_ERASE_64K;
flash->erase_size = flash->sector_size;
}
/* Poll cmd seclection */
/* 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];
flash->read_cmd = cmd;
} else {
/* Go for default supported read cmd */
flash->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)
flash->write_cmd = CMD_QUAD_PAGE_PROGRAM;
else
/* Go for default supported write cmd */
flash->write_cmd = CMD_PAGE_PROGRAM;
/* Set the quad enable bit - only for quad commands */
if ((flash->read_cmd == CMD_READ_QUAD_OUTPUT_FAST) ||
(flash->read_cmd == CMD_READ_QUAD_IO_FAST) ||
(flash->write_cmd == CMD_QUAD_PAGE_PROGRAM)) {
if (spi_flash_set_qeb(flash, idcode[0])) {
debug("SF: Fail to set QEB for %02x\n", idcode[0]);
return NULL;
}
}
/* 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 (flash->read_cmd) {
case CMD_READ_QUAD_IO_FAST:
flash->dummy_byte = 2;
break;
case CMD_READ_ARRAY_SLOW:
flash->dummy_byte = 0;
break;
default:
flash->dummy_byte = 1;
}
/* Poll cmd selection */
flash->poll_cmd = CMD_READ_STATUS;
#ifdef CONFIG_SPI_FLASH_STMICRO
if (params->flags & E_FSR)
@ -339,7 +330,10 @@ static struct spi_flash *spi_flash_probe_slave(struct spi_slave *spi)
puts("\n");
#endif
#ifndef CONFIG_SPI_FLASH_BAR
if (flash->size > SPI_FLASH_16MB_BOUN) {
if (((flash->dual_flash == SF_SINGLE_FLASH) &&
(flash->size > SPI_FLASH_16MB_BOUN)) ||
((flash->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");
}

View file

@ -19,6 +19,7 @@ obj-$(CONFIG_CF_SPI) += cf_spi.o
obj-$(CONFIG_CF_QSPI) += cf_qspi.o
obj-$(CONFIG_DAVINCI_SPI) += davinci_spi.o
obj-$(CONFIG_EXYNOS_SPI) += exynos_spi.o
obj-$(CONFIG_FTSSP010_SPI) += ftssp010_spi.o
obj-$(CONFIG_ICH_SPI) += ich.o
obj-$(CONFIG_KIRKWOOD_SPI) += kirkwood_spi.o
obj-$(CONFIG_MPC52XX_SPI) += mpc52xx_spi.o

508
drivers/spi/ftssp010_spi.c Normal file
View file

@ -0,0 +1,508 @@
/*
* (C) Copyright 2013
* Faraday Technology Corporation. <http://www.faraday-tech.com/tw/>
* Kuo-Jung Su <dantesu@gmail.com>
*
* SPDX-License-Identifier: GPL-2.0+
*/
#include <common.h>
#include <linux/compat.h>
#include <asm/io.h>
#include <malloc.h>
#include <spi.h>
#ifndef CONFIG_FTSSP010_BASE_LIST
#define CONFIG_FTSSP010_BASE_LIST { CONFIG_FTSSP010_BASE }
#endif
#ifndef CONFIG_FTSSP010_GPIO_BASE
#define CONFIG_FTSSP010_GPIO_BASE 0
#endif
#ifndef CONFIG_FTSSP010_GPIO_LIST
#define CONFIG_FTSSP010_GPIO_LIST { CONFIG_FTSSP010_GPIO_BASE }
#endif
#ifndef CONFIG_FTSSP010_CLOCK
#define CONFIG_FTSSP010_CLOCK clk_get_rate("SSP");
#endif
#ifndef CONFIG_FTSSP010_TIMEOUT
#define CONFIG_FTSSP010_TIMEOUT 100
#endif
/* FTSSP010 chip registers */
struct ftssp010_regs {
uint32_t cr[3];/* control register */
uint32_t sr; /* status register */
uint32_t icr; /* interrupt control register */
uint32_t isr; /* interrupt status register */
uint32_t dr; /* data register */
uint32_t rsvd[17];
uint32_t revr; /* revision register */
uint32_t fear; /* feature register */
};
/* Control Register 0 */
#define CR0_FFMT_MASK (7 << 12)
#define CR0_FFMT_SSP (0 << 12)
#define CR0_FFMT_SPI (1 << 12)
#define CR0_FFMT_MICROWIRE (2 << 12)
#define CR0_FFMT_I2S (3 << 12)
#define CR0_FFMT_AC97 (4 << 12)
#define CR0_FLASH (1 << 11)
#define CR0_FSDIST(x) (((x) & 0x03) << 8)
#define CR0_LOOP (1 << 7) /* loopback mode */
#define CR0_LSB (1 << 6) /* LSB */
#define CR0_FSPO (1 << 5) /* fs atcive low (I2S only) */
#define CR0_FSJUSTIFY (1 << 4)
#define CR0_OPM_SLAVE (0 << 2)
#define CR0_OPM_MASTER (3 << 2)
#define CR0_OPM_I2S_MSST (3 << 2) /* master stereo mode */
#define CR0_OPM_I2S_MSMO (2 << 2) /* master mono mode */
#define CR0_OPM_I2S_SLST (1 << 2) /* slave stereo mode */
#define CR0_OPM_I2S_SLMO (0 << 2) /* slave mono mode */
#define CR0_SCLKPO (1 << 1) /* clock polarity */
#define CR0_SCLKPH (1 << 0) /* clock phase */
/* Control Register 1 */
#define CR1_PDL(x) (((x) & 0xff) << 24) /* padding length */
#define CR1_SDL(x) ((((x) - 1) & 0x1f) << 16) /* data length */
#define CR1_DIV(x) (((x) - 1) & 0xffff) /* clock divider */
/* Control Register 2 */
#define CR2_CS(x) (((x) & 3) << 10) /* CS/FS select */
#define CR2_FS (1 << 9) /* CS/FS signal level */
#define CR2_TXEN (1 << 8) /* tx enable */
#define CR2_RXEN (1 << 7) /* rx enable */
#define CR2_RESET (1 << 6) /* chip reset */
#define CR2_TXFC (1 << 3) /* tx fifo Clear */
#define CR2_RXFC (1 << 2) /* rx fifo Clear */
#define CR2_TXDOE (1 << 1) /* tx data output enable */
#define CR2_EN (1 << 0) /* chip enable */
/* Status Register */
#define SR_RFF (1 << 0) /* rx fifo full */
#define SR_TFNF (1 << 1) /* tx fifo not full */
#define SR_BUSY (1 << 2) /* chip busy */
#define SR_RFVE(reg) (((reg) >> 4) & 0x1f) /* rx fifo valid entries */
#define SR_TFVE(reg) (((reg) >> 12) & 0x1f) /* tx fifo valid entries */
/* Feature Register */
#define FEAR_BITS(reg) ((((reg) >> 0) & 0xff) + 1) /* data width */
#define FEAR_RFSZ(reg) ((((reg) >> 8) & 0xff) + 1) /* rx fifo size */
#define FEAR_TFSZ(reg) ((((reg) >> 16) & 0xff) + 1) /* tx fifo size */
#define FEAR_AC97 (1 << 24)
#define FEAR_I2S (1 << 25)
#define FEAR_SPI_MWR (1 << 26)
#define FEAR_SSP (1 << 27)
#define FEAR_SPDIF (1 << 28)
/* FTGPIO010 chip registers */
struct ftgpio010_regs {
uint32_t out; /* 0x00: Data Output */
uint32_t in; /* 0x04: Data Input */
uint32_t dir; /* 0x08: Direction */
uint32_t bypass; /* 0x0c: Bypass */
uint32_t set; /* 0x10: Data Set */
uint32_t clr; /* 0x14: Data Clear */
uint32_t pull_up; /* 0x18: Pull-Up Enabled */
uint32_t pull_st; /* 0x1c: Pull State (0=pull-down, 1=pull-up) */
};
struct ftssp010_gpio {
struct ftgpio010_regs *regs;
uint32_t pin;
};
struct ftssp010_spi {
struct spi_slave slave;
struct ftssp010_gpio gpio;
struct ftssp010_regs *regs;
uint32_t fifo;
uint32_t mode;
uint32_t div;
uint32_t clk;
uint32_t speed;
uint32_t revision;
};
static inline struct ftssp010_spi *to_ftssp010_spi(struct spi_slave *slave)
{
return container_of(slave, struct ftssp010_spi, slave);
}
static int get_spi_chip(int bus, struct ftssp010_spi *chip)
{
uint32_t fear, base[] = CONFIG_FTSSP010_BASE_LIST;
if (bus >= ARRAY_SIZE(base) || !base[bus])
return -1;
chip->regs = (struct ftssp010_regs *)base[bus];
chip->revision = readl(&chip->regs->revr);
fear = readl(&chip->regs->fear);
chip->fifo = min_t(uint32_t, FEAR_TFSZ(fear), FEAR_RFSZ(fear));
return 0;
}
static int get_spi_gpio(int bus, struct ftssp010_gpio *chip)
{
uint32_t base[] = CONFIG_FTSSP010_GPIO_LIST;
if (bus >= ARRAY_SIZE(base) || !base[bus])
return -1;
chip->regs = (struct ftgpio010_regs *)(base[bus] & 0xfff00000);
chip->pin = base[bus] & 0x1f;
/* make it an output pin */
setbits_le32(&chip->regs->dir, 1 << chip->pin);
return 0;
}
static int ftssp010_wait(struct ftssp010_spi *chip)
{
struct ftssp010_regs *regs = chip->regs;
int ret = -1;
ulong t;
/* wait until device idle */
for (t = get_timer(0); get_timer(t) < CONFIG_FTSSP010_TIMEOUT; ) {
if (readl(&regs->sr) & SR_BUSY)
continue;
ret = 0;
break;
}
if (ret)
puts("ftspi010: busy timeout\n");
return ret;
}
static int ftssp010_wait_tx(struct ftssp010_spi *chip)
{
struct ftssp010_regs *regs = chip->regs;
int ret = -1;
ulong t;
/* wait until tx fifo not full */
for (t = get_timer(0); get_timer(t) < CONFIG_FTSSP010_TIMEOUT; ) {
if (!(readl(&regs->sr) & SR_TFNF))
continue;
ret = 0;
break;
}
if (ret)
puts("ftssp010: tx timeout\n");
return ret;
}
static int ftssp010_wait_rx(struct ftssp010_spi *chip)
{
struct ftssp010_regs *regs = chip->regs;
int ret = -1;
ulong t;
/* wait until rx fifo not empty */
for (t = get_timer(0); get_timer(t) < CONFIG_FTSSP010_TIMEOUT; ) {
if (!SR_RFVE(readl(&regs->sr)))
continue;
ret = 0;
break;
}
if (ret)
puts("ftssp010: rx timeout\n");
return ret;
}
static int ftssp010_spi_work_transfer_v2(struct ftssp010_spi *chip,
const void *tx_buf, void *rx_buf, int len, uint flags)
{
struct ftssp010_regs *regs = chip->regs;
const uint8_t *txb = tx_buf;
uint8_t *rxb = rx_buf;
while (len > 0) {
int i, depth = min(chip->fifo >> 2, len);
uint32_t xmsk = 0;
if (tx_buf) {
for (i = 0; i < depth; ++i) {
ftssp010_wait_tx(chip);
writel(*txb++, &regs->dr);
}
xmsk |= CR2_TXEN | CR2_TXDOE;
if ((readl(&regs->cr[2]) & xmsk) != xmsk)
setbits_le32(&regs->cr[2], xmsk);
}
if (rx_buf) {
xmsk |= CR2_RXEN;
if ((readl(&regs->cr[2]) & xmsk) != xmsk)
setbits_le32(&regs->cr[2], xmsk);
for (i = 0; i < depth; ++i) {
ftssp010_wait_rx(chip);
*rxb++ = (uint8_t)readl(&regs->dr);
}
}
len -= depth;
}
return 0;
}
static int ftssp010_spi_work_transfer_v1(struct ftssp010_spi *chip,
const void *tx_buf, void *rx_buf, int len, uint flags)
{
struct ftssp010_regs *regs = chip->regs;
const uint8_t *txb = tx_buf;
uint8_t *rxb = rx_buf;
while (len > 0) {
int i, depth = min(chip->fifo >> 2, len);
uint32_t tmp;
for (i = 0; i < depth; ++i) {
ftssp010_wait_tx(chip);
writel(txb ? (*txb++) : 0, &regs->dr);
}
for (i = 0; i < depth; ++i) {
ftssp010_wait_rx(chip);
tmp = readl(&regs->dr);
if (rxb)
*rxb++ = (uint8_t)tmp;
}
len -= depth;
}
return 0;
}
static void ftssp010_cs_set(struct ftssp010_spi *chip, int high)
{
struct ftssp010_regs *regs = chip->regs;
struct ftssp010_gpio *gpio = &chip->gpio;
uint32_t mask;
/* cs pull high/low */
if (chip->revision >= 0x11900) {
mask = CR2_CS(chip->slave.cs) | (high ? CR2_FS : 0);
writel(mask, &regs->cr[2]);
} else if (gpio->regs) {
mask = 1 << gpio->pin;
if (high)
writel(mask, &gpio->regs->set);
else
writel(mask, &gpio->regs->clr);
}
/* extra delay for signal propagation */
udelay_masked(1);
}
/*
* Determine if a SPI chipselect is valid.
* This function is provided by the board if the low-level SPI driver
* needs it to determine if a given chipselect is actually valid.
*
* Returns: 1 if bus:cs identifies a valid chip on this board, 0
* otherwise.
*/
int spi_cs_is_valid(unsigned int bus, unsigned int cs)
{
struct ftssp010_spi chip;
if (get_spi_chip(bus, &chip))
return 0;
if (!cs)
return 1;
else if ((cs < 4) && (chip.revision >= 0x11900))
return 1;
return 0;
}
/*
* Activate a SPI chipselect.
* This function is provided by the board code when using a driver
* that can't control its chipselects automatically (e.g.
* common/soft_spi.c). When called, it should activate the chip select
* to the device identified by "slave".
*/
void spi_cs_activate(struct spi_slave *slave)
{
struct ftssp010_spi *chip = to_ftssp010_spi(slave);
struct ftssp010_regs *regs = chip->regs;
/* cs pull */
if (chip->mode & SPI_CS_HIGH)
ftssp010_cs_set(chip, 1);
else
ftssp010_cs_set(chip, 0);
/* chip enable + fifo clear */
setbits_le32(&regs->cr[2], CR2_EN | CR2_TXFC | CR2_RXFC);
}
/*
* Deactivate a SPI chipselect.
* This function is provided by the board code when using a driver
* that can't control its chipselects automatically (e.g.
* common/soft_spi.c). When called, it should deactivate the chip
* select to the device identified by "slave".
*/
void spi_cs_deactivate(struct spi_slave *slave)
{
struct ftssp010_spi *chip = to_ftssp010_spi(slave);
/* wait until chip idle */
ftssp010_wait(chip);
/* cs pull */
if (chip->mode & SPI_CS_HIGH)
ftssp010_cs_set(chip, 0);
else
ftssp010_cs_set(chip, 1);
}
void spi_init(void)
{
/* nothing to do */
}
struct spi_slave *spi_setup_slave(uint bus, uint cs, uint max_hz, uint mode)
{
struct ftssp010_spi *chip;
if (mode & SPI_3WIRE) {
puts("ftssp010: can't do 3-wire\n");
return NULL;
}
if (mode & SPI_SLAVE) {
puts("ftssp010: can't do slave mode\n");
return NULL;
}
if (mode & SPI_PREAMBLE) {
puts("ftssp010: can't skip preamble bytes\n");
return NULL;
}
if (!spi_cs_is_valid(bus, cs)) {
puts("ftssp010: invalid (bus, cs)\n");
return NULL;
}
chip = spi_alloc_slave(struct ftssp010_spi, bus, cs);
if (!chip)
return NULL;
if (get_spi_chip(bus, chip))
goto free_out;
if (chip->revision < 0x11900 && get_spi_gpio(bus, &chip->gpio)) {
puts("ftssp010: Before revision 1.19.0, its clock & cs are\n"
"controlled by tx engine which is not synced with rx engine,\n"
"so the clock & cs might be shutdown before rx engine\n"
"finishs its jobs.\n"
"If possible, please add a dedicated gpio for it.\n");
}
chip->mode = mode;
chip->clk = CONFIG_FTSSP010_CLOCK;
chip->div = 2;
if (max_hz) {
while (chip->div < 0xffff) {
if ((chip->clk / (2 * chip->div)) <= max_hz)
break;
chip->div += 1;
}
}
chip->speed = chip->clk / (2 * chip->div);
return &chip->slave;
free_out:
free(chip);
return NULL;
}
void spi_free_slave(struct spi_slave *slave)
{
free(slave);
}
int spi_claim_bus(struct spi_slave *slave)
{
struct ftssp010_spi *chip = to_ftssp010_spi(slave);
struct ftssp010_regs *regs = chip->regs;
writel(CR1_SDL(8) | CR1_DIV(chip->div), &regs->cr[1]);
if (chip->revision >= 0x11900) {
writel(CR0_OPM_MASTER | CR0_FFMT_SPI | CR0_FSPO | CR0_FLASH,
&regs->cr[0]);
writel(CR2_TXFC | CR2_RXFC,
&regs->cr[2]);
} else {
writel(CR0_OPM_MASTER | CR0_FFMT_SPI | CR0_FSPO,
&regs->cr[0]);
writel(CR2_TXFC | CR2_RXFC | CR2_EN | CR2_TXDOE,
&regs->cr[2]);
}
if (chip->mode & SPI_LOOP)
setbits_le32(&regs->cr[0], CR0_LOOP);
if (chip->mode & SPI_CPOL)
setbits_le32(&regs->cr[0], CR0_SCLKPO);
if (chip->mode & SPI_CPHA)
setbits_le32(&regs->cr[0], CR0_SCLKPH);
spi_cs_deactivate(slave);
return 0;
}
void spi_release_bus(struct spi_slave *slave)
{
struct ftssp010_spi *chip = to_ftssp010_spi(slave);
struct ftssp010_regs *regs = chip->regs;
writel(0, &regs->cr[2]);
}
int spi_xfer(struct spi_slave *slave, unsigned int bitlen,
const void *dout, void *din, unsigned long flags)
{
struct ftssp010_spi *chip = to_ftssp010_spi(slave);
uint32_t len = bitlen >> 3;
if (flags & SPI_XFER_BEGIN)
spi_cs_activate(slave);
if (chip->revision >= 0x11900)
ftssp010_spi_work_transfer_v2(chip, dout, din, len, flags);
else
ftssp010_spi_work_transfer_v1(chip, dout, din, len, flags);
if (flags & SPI_XFER_END)
spi_cs_deactivate(slave);
return 0;
}

View file

@ -151,7 +151,6 @@ static int sh_spi_send(struct sh_spi *ss, const unsigned char *tx_data,
{
int i, cur_len, ret = 0;
int remain = (int)len;
unsigned long tmp;
if (len >= SH_SPI_FIFO_SIZE)
sh_spi_set_bit(SH_SPI_SSA, &ss->regs->cr1);
@ -183,9 +182,7 @@ static int sh_spi_send(struct sh_spi *ss, const unsigned char *tx_data,
}
if (flags & SPI_XFER_END) {
tmp = sh_spi_read(&ss->regs->cr1);
tmp = tmp & ~(SH_SPI_SSD | SH_SPI_SSDB);
sh_spi_write(tmp, &ss->regs->cr1);
sh_spi_clear_bit(SH_SPI_SSD | SH_SPI_SSDB, &ss->regs->cr1);
sh_spi_set_bit(SH_SPI_SSA, &ss->regs->cr1);
udelay(100);
write_fifo_empty_wait(ss);
@ -198,16 +195,13 @@ static int sh_spi_receive(struct sh_spi *ss, unsigned char *rx_data,
unsigned int len, unsigned long flags)
{
int i;
unsigned long tmp;
if (len > SH_SPI_MAX_BYTE)
sh_spi_write(SH_SPI_MAX_BYTE, &ss->regs->cr3);
else
sh_spi_write(len, &ss->regs->cr3);
tmp = sh_spi_read(&ss->regs->cr1);
tmp = tmp & ~(SH_SPI_SSD | SH_SPI_SSDB);
sh_spi_write(tmp, &ss->regs->cr1);
sh_spi_clear_bit(SH_SPI_SSD | SH_SPI_SSDB, &ss->regs->cr1);
sh_spi_set_bit(SH_SPI_SSA, &ss->regs->cr1);
for (i = 0; i < len; i++) {

View file

@ -30,6 +30,24 @@
#define SPI_XFER_MMAP 0x08 /* Memory Mapped start */
#define SPI_XFER_MMAP_END 0x10 /* Memory Mapped End */
#define SPI_XFER_ONCE (SPI_XFER_BEGIN | SPI_XFER_END)
#define SPI_XFER_U_PAGE (1 << 5)
/* SPI TX operation modes */
#define SPI_OPM_TX_QPP 1 << 0
/* SPI RX operation modes */
#define SPI_OPM_RX_AS 1 << 0
#define SPI_OPM_RX_DOUT 1 << 1
#define SPI_OPM_RX_DIO 1 << 2
#define SPI_OPM_RX_QOF 1 << 3
#define SPI_OPM_RX_QIOF 1 << 4
#define SPI_OPM_RX_EXTN SPI_OPM_RX_AS | SPI_OPM_RX_DOUT | \
SPI_OPM_RX_DIO | SPI_OPM_RX_QOF | \
SPI_OPM_RX_QIOF
/* SPI bus connection options */
#define SPI_CONN_DUAL_SHARED 1 << 0
#define SPI_CONN_DUAL_SEPARATED 1 << 1
/* Header byte that marks the start of the message */
#define SPI_PREAMBLE_END_BYTE 0xec
@ -43,17 +61,25 @@
*
* @bus: ID of the bus that the slave is attached to.
* @cs: ID of the chip select connected to the slave.
* @op_mode_rx: SPI RX operation mode.
* @op_mode_tx: SPI TX operation mode.
* @wordlen: Size of SPI word in number of bits
* @max_write_size: If non-zero, the maximum number of bytes which can
* be written at once, excluding command bytes.
* @memory_map: Address of read-only SPI flash access.
* @option: Varies SPI bus options - separate, shared bus.
* @flags: Indication of SPI flags.
*/
struct spi_slave {
unsigned int bus;
unsigned int cs;
u8 op_mode_rx;
u8 op_mode_tx;
unsigned int wordlen;
unsigned int max_write_size;
void *memory_map;
u8 option;
u8 flags;
};
/**

View file

@ -19,11 +19,60 @@
#include <linux/types.h>
#include <linux/compiler.h>
/* sf param flags */
#define SECT_4K 1 << 1
#define SECT_32K 1 << 2
#define E_FSR 1 << 3
#define WR_QPP 1 << 4
/* 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
/* Dual SPI flash memories */
enum spi_dual_flash {
SF_SINGLE_FLASH = 0,
SF_DUAL_STACKED_FLASH = 1 << 0,
SF_DUAL_PARALLEL_FLASH = 1 << 1,
};
/**
* 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: Importent 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[];
/**
* struct spi_flash - SPI flash structure
*
* @spi: SPI slave
* @name: Name of SPI flash
* @dual_flash: Indicates dual flash memories - dual stacked, parallel
* @shift: Flash shift useful in dual parallel
* @size: Total flash size
* @page_size: Write (page) size
* @sector_size: Sector size
@ -33,6 +82,9 @@
* @bank_curr: Current flash bank
* @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.
* @dummy_byte: Dummy cycles for read operation.
* @memory_map: Address of read-only SPI flash access
* @read: Flash read ops: Read len bytes at offset into buf
* Supported cmds: Fast Array Read
@ -45,6 +97,8 @@
struct spi_flash {
struct spi_slave *spi;
const char *name;
u8 dual_flash;
u8 shift;
u32 size;
u32 page_size;
@ -57,6 +111,9 @@ struct spi_flash {
#endif
u8 poll_cmd;
u8 erase_cmd;
u8 read_cmd;
u8 write_cmd;
u8 dummy_byte;
void *memory_map;
int (*read)(struct spi_flash *flash, u32 offset, size_t len, void *buf);