mirror of
https://github.com/u-boot/u-boot.git
synced 2025-05-08 02:08:00 +00:00
mtd: spi: spi-nor-core: Add back U-Boot specific features
For legacy reasons, we will have to keep around U-Boot specific SPI_FLASH_BAR and SPI_TX_BYTE. Add them back to the new framework Signed-off-by: Vignesh R <vigneshr@ti.com> Reviewed-by: Jagan Teki <jagan@openedev.com> Tested-by: Jagan Teki <jagan@amarulasolutions.com> #zynq-microzed
This commit is contained in:
parent
0c6f187cdb
commit
8c927809ea
2 changed files with 168 additions and 3 deletions
|
@ -291,6 +291,7 @@ static struct spi_nor *mtd_to_spi_nor(struct mtd_info *mtd)
|
||||||
return mtd->priv;
|
return mtd->priv;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#ifndef CONFIG_SPI_FLASH_BAR
|
||||||
static u8 spi_nor_convert_opcode(u8 opcode, const u8 table[][2], size_t size)
|
static u8 spi_nor_convert_opcode(u8 opcode, const u8 table[][2], size_t size)
|
||||||
{
|
{
|
||||||
size_t i;
|
size_t i;
|
||||||
|
@ -365,6 +366,7 @@ static void spi_nor_set_4byte_opcodes(struct spi_nor *nor,
|
||||||
nor->program_opcode = spi_nor_convert_3to4_program(nor->program_opcode);
|
nor->program_opcode = spi_nor_convert_3to4_program(nor->program_opcode);
|
||||||
nor->erase_opcode = spi_nor_convert_3to4_erase(nor->erase_opcode);
|
nor->erase_opcode = spi_nor_convert_3to4_erase(nor->erase_opcode);
|
||||||
}
|
}
|
||||||
|
#endif /* !CONFIG_SPI_FLASH_BAR */
|
||||||
|
|
||||||
/* Enable/disable 4-byte addressing mode. */
|
/* Enable/disable 4-byte addressing mode. */
|
||||||
static int set_4byte(struct spi_nor *nor, const struct flash_info *info,
|
static int set_4byte(struct spi_nor *nor, const struct flash_info *info,
|
||||||
|
@ -499,6 +501,79 @@ static int spi_nor_wait_till_ready(struct spi_nor *nor)
|
||||||
DEFAULT_READY_WAIT_JIFFIES);
|
DEFAULT_READY_WAIT_JIFFIES);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#ifdef CONFIG_SPI_FLASH_BAR
|
||||||
|
/*
|
||||||
|
* This "clean_bar" is necessary in a situation when one was accessing
|
||||||
|
* spi flash memory > 16 MiB by using Bank Address Register's BA24 bit.
|
||||||
|
*
|
||||||
|
* After it the BA24 bit shall be cleared to allow access to correct
|
||||||
|
* memory region after SW reset (by calling "reset" command).
|
||||||
|
*
|
||||||
|
* Otherwise, the BA24 bit may be left set and then after reset, the
|
||||||
|
* ROM would read/write/erase SPL from 16 MiB * bank_sel address.
|
||||||
|
*/
|
||||||
|
static int clean_bar(struct spi_nor *nor)
|
||||||
|
{
|
||||||
|
u8 cmd, bank_sel = 0;
|
||||||
|
|
||||||
|
if (nor->bank_curr == 0)
|
||||||
|
return 0;
|
||||||
|
cmd = nor->bank_write_cmd;
|
||||||
|
nor->bank_curr = 0;
|
||||||
|
write_enable(nor);
|
||||||
|
|
||||||
|
return nor->write_reg(nor, cmd, &bank_sel, 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
static int write_bar(struct spi_nor *nor, u32 offset)
|
||||||
|
{
|
||||||
|
u8 cmd, bank_sel;
|
||||||
|
int ret;
|
||||||
|
|
||||||
|
bank_sel = offset / SZ_16M;
|
||||||
|
if (bank_sel == nor->bank_curr)
|
||||||
|
goto bar_end;
|
||||||
|
|
||||||
|
cmd = nor->bank_write_cmd;
|
||||||
|
write_enable(nor);
|
||||||
|
ret = nor->write_reg(nor, cmd, &bank_sel, 1);
|
||||||
|
if (ret < 0) {
|
||||||
|
debug("SF: fail to write bank register\n");
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
bar_end:
|
||||||
|
nor->bank_curr = bank_sel;
|
||||||
|
return nor->bank_curr;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int read_bar(struct spi_nor *nor, const struct flash_info *info)
|
||||||
|
{
|
||||||
|
u8 curr_bank = 0;
|
||||||
|
int ret;
|
||||||
|
|
||||||
|
switch (JEDEC_MFR(info)) {
|
||||||
|
case SNOR_MFR_SPANSION:
|
||||||
|
nor->bank_read_cmd = SPINOR_OP_BRRD;
|
||||||
|
nor->bank_write_cmd = SPINOR_OP_BRWR;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
nor->bank_read_cmd = SPINOR_OP_RDEAR;
|
||||||
|
nor->bank_write_cmd = SPINOR_OP_WREAR;
|
||||||
|
}
|
||||||
|
|
||||||
|
ret = nor->read_reg(nor, nor->bank_read_cmd,
|
||||||
|
&curr_bank, 1);
|
||||||
|
if (ret) {
|
||||||
|
debug("SF: fail to read bank addr register\n");
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
nor->bank_curr = curr_bank;
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Initiate the erasure of a single sector
|
* Initiate the erasure of a single sector
|
||||||
*/
|
*/
|
||||||
|
@ -543,6 +618,11 @@ static int spi_nor_erase(struct mtd_info *mtd, struct erase_info *instr)
|
||||||
len = instr->len;
|
len = instr->len;
|
||||||
|
|
||||||
while (len) {
|
while (len) {
|
||||||
|
#ifdef CONFIG_SPI_FLASH_BAR
|
||||||
|
ret = write_bar(nor, addr);
|
||||||
|
if (ret < 0)
|
||||||
|
return ret;
|
||||||
|
#endif
|
||||||
write_enable(nor);
|
write_enable(nor);
|
||||||
|
|
||||||
ret = spi_nor_erase_sector(nor, addr);
|
ret = spi_nor_erase_sector(nor, addr);
|
||||||
|
@ -557,9 +637,12 @@ static int spi_nor_erase(struct mtd_info *mtd, struct erase_info *instr)
|
||||||
goto erase_err;
|
goto erase_err;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
erase_err:
|
||||||
|
#ifdef CONFIG_SPI_FLASH_BAR
|
||||||
|
ret = clean_bar(nor);
|
||||||
|
#endif
|
||||||
write_disable(nor);
|
write_disable(nor);
|
||||||
|
|
||||||
erase_err:
|
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1144,8 +1227,23 @@ static int spi_nor_read(struct mtd_info *mtd, loff_t from, size_t len,
|
||||||
|
|
||||||
while (len) {
|
while (len) {
|
||||||
loff_t addr = from;
|
loff_t addr = from;
|
||||||
|
size_t read_len = len;
|
||||||
|
|
||||||
ret = nor->read(nor, addr, len, buf);
|
#ifdef CONFIG_SPI_FLASH_BAR
|
||||||
|
u32 remain_len;
|
||||||
|
|
||||||
|
ret = write_bar(nor, addr);
|
||||||
|
if (ret < 0)
|
||||||
|
return log_ret(ret);
|
||||||
|
remain_len = (SZ_16M * (nor->bank_curr + 1)) - addr;
|
||||||
|
|
||||||
|
if (len < remain_len)
|
||||||
|
read_len = len;
|
||||||
|
else
|
||||||
|
read_len = remain_len;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
ret = nor->read(nor, addr, read_len, buf);
|
||||||
if (ret == 0) {
|
if (ret == 0) {
|
||||||
/* We shouldn't see 0-length reads */
|
/* We shouldn't see 0-length reads */
|
||||||
ret = -EIO;
|
ret = -EIO;
|
||||||
|
@ -1162,18 +1260,49 @@ static int spi_nor_read(struct mtd_info *mtd, loff_t from, size_t len,
|
||||||
ret = 0;
|
ret = 0;
|
||||||
|
|
||||||
read_err:
|
read_err:
|
||||||
|
#ifdef CONFIG_SPI_FLASH_BAR
|
||||||
|
ret = clean_bar(nor);
|
||||||
|
#endif
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
#ifdef CONFIG_SPI_FLASH_SST
|
#ifdef CONFIG_SPI_FLASH_SST
|
||||||
|
static int sst_write_byteprogram(struct spi_nor *nor, loff_t to, size_t len,
|
||||||
|
size_t *retlen, const u_char *buf)
|
||||||
|
{
|
||||||
|
size_t actual;
|
||||||
|
int ret = 0;
|
||||||
|
|
||||||
|
for (actual = 0; actual < len; actual++) {
|
||||||
|
nor->program_opcode = SPINOR_OP_BP;
|
||||||
|
|
||||||
|
write_enable(nor);
|
||||||
|
/* write one byte. */
|
||||||
|
ret = nor->write(nor, to, 1, buf + actual);
|
||||||
|
if (ret < 0)
|
||||||
|
goto sst_write_err;
|
||||||
|
ret = spi_nor_wait_till_ready(nor);
|
||||||
|
if (ret)
|
||||||
|
goto sst_write_err;
|
||||||
|
to++;
|
||||||
|
}
|
||||||
|
|
||||||
|
sst_write_err:
|
||||||
|
write_disable(nor);
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
static int sst_write(struct mtd_info *mtd, loff_t to, size_t len,
|
static int sst_write(struct mtd_info *mtd, loff_t to, size_t len,
|
||||||
size_t *retlen, const u_char *buf)
|
size_t *retlen, const u_char *buf)
|
||||||
{
|
{
|
||||||
struct spi_nor *nor = mtd_to_spi_nor(mtd);
|
struct spi_nor *nor = mtd_to_spi_nor(mtd);
|
||||||
|
struct spi_slave *spi = nor->spi;
|
||||||
size_t actual;
|
size_t actual;
|
||||||
int ret;
|
int ret;
|
||||||
|
|
||||||
dev_dbg(nor->dev, "to 0x%08x, len %zd\n", (u32)to, len);
|
dev_dbg(nor->dev, "to 0x%08x, len %zd\n", (u32)to, len);
|
||||||
|
if (spi->mode & SPI_TX_BYTE)
|
||||||
|
return sst_write_byteprogram(nor, to, len, retlen, buf);
|
||||||
|
|
||||||
write_enable(nor);
|
write_enable(nor);
|
||||||
|
|
||||||
|
@ -1271,6 +1400,11 @@ static int spi_nor_write(struct mtd_info *mtd, loff_t to, size_t len,
|
||||||
page_remain = min_t(size_t,
|
page_remain = min_t(size_t,
|
||||||
nor->page_size - page_offset, len - i);
|
nor->page_size - page_offset, len - i);
|
||||||
|
|
||||||
|
#ifdef CONFIG_SPI_FLASH_BAR
|
||||||
|
ret = write_bar(nor, addr);
|
||||||
|
if (ret < 0)
|
||||||
|
return ret;
|
||||||
|
#endif
|
||||||
write_enable(nor);
|
write_enable(nor);
|
||||||
ret = nor->write(nor, addr, page_remain, buf + i);
|
ret = nor->write(nor, addr, page_remain, buf + i);
|
||||||
if (ret < 0)
|
if (ret < 0)
|
||||||
|
@ -1289,6 +1423,9 @@ static int spi_nor_write(struct mtd_info *mtd, loff_t to, size_t len,
|
||||||
}
|
}
|
||||||
|
|
||||||
write_err:
|
write_err:
|
||||||
|
#ifdef CONFIG_SPI_FLASH_BAR
|
||||||
|
ret = clean_bar(nor);
|
||||||
|
#endif
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -2532,12 +2669,20 @@ int spi_nor_scan(struct spi_nor *nor)
|
||||||
/* already configured from SFDP */
|
/* already configured from SFDP */
|
||||||
} else if (info->addr_width) {
|
} else if (info->addr_width) {
|
||||||
nor->addr_width = info->addr_width;
|
nor->addr_width = info->addr_width;
|
||||||
} else if (mtd->size > 0x1000000) {
|
} else if (mtd->size > SZ_16M) {
|
||||||
|
#ifndef CONFIG_SPI_FLASH_BAR
|
||||||
/* enable 4-byte addressing if the device exceeds 16MiB */
|
/* enable 4-byte addressing if the device exceeds 16MiB */
|
||||||
nor->addr_width = 4;
|
nor->addr_width = 4;
|
||||||
if (JEDEC_MFR(info) == SNOR_MFR_SPANSION ||
|
if (JEDEC_MFR(info) == SNOR_MFR_SPANSION ||
|
||||||
info->flags & SPI_NOR_4B_OPCODES)
|
info->flags & SPI_NOR_4B_OPCODES)
|
||||||
spi_nor_set_4byte_opcodes(nor, info);
|
spi_nor_set_4byte_opcodes(nor, info);
|
||||||
|
#else
|
||||||
|
/* Configure the BAR - discover bank cmds and read current bank */
|
||||||
|
nor->addr_width = 3;
|
||||||
|
ret = read_bar(nor, info);
|
||||||
|
if (ret < 0)
|
||||||
|
return ret;
|
||||||
|
#endif
|
||||||
} else {
|
} else {
|
||||||
nor->addr_width = 3;
|
nor->addr_width = 3;
|
||||||
}
|
}
|
||||||
|
@ -2569,3 +2714,14 @@ int spi_nor_scan(struct spi_nor *nor)
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* U-Boot specific functions, need to extend MTD to support these */
|
||||||
|
int spi_flash_cmd_get_sw_write_prot(struct spi_nor *nor)
|
||||||
|
{
|
||||||
|
int sr = read_sr(nor);
|
||||||
|
|
||||||
|
if (sr < 0)
|
||||||
|
return sr;
|
||||||
|
|
||||||
|
return (sr >> 2) & 7;
|
||||||
|
}
|
||||||
|
|
|
@ -105,6 +105,7 @@
|
||||||
|
|
||||||
/* Used for Spansion flashes only. */
|
/* Used for Spansion flashes only. */
|
||||||
#define SPINOR_OP_BRWR 0x17 /* Bank register write */
|
#define SPINOR_OP_BRWR 0x17 /* Bank register write */
|
||||||
|
#define SPINOR_OP_BRRD 0x16 /* Bank register read */
|
||||||
#define SPINOR_OP_CLSR 0x30 /* Clear status register 1 */
|
#define SPINOR_OP_CLSR 0x30 /* Clear status register 1 */
|
||||||
|
|
||||||
/* Used for Micron flashes only. */
|
/* Used for Micron flashes only. */
|
||||||
|
@ -256,6 +257,9 @@ struct flash_info;
|
||||||
* @read_opcode: the read opcode
|
* @read_opcode: the read opcode
|
||||||
* @read_dummy: the dummy needed by the read operation
|
* @read_dummy: the dummy needed by the read operation
|
||||||
* @program_opcode: the program opcode
|
* @program_opcode: the program opcode
|
||||||
|
* @bank_read_cmd: Bank read cmd
|
||||||
|
* @bank_write_cmd: Bank write cmd
|
||||||
|
* @bank_curr: Current flash bank
|
||||||
* @sst_write_second: used by the SST write operation
|
* @sst_write_second: used by the SST write operation
|
||||||
* @flags: flag options for the current SPI-NOR (SNOR_F_*)
|
* @flags: flag options for the current SPI-NOR (SNOR_F_*)
|
||||||
* @read_proto: the SPI protocol for read operations
|
* @read_proto: the SPI protocol for read operations
|
||||||
|
@ -291,6 +295,11 @@ struct spi_nor {
|
||||||
u8 read_opcode;
|
u8 read_opcode;
|
||||||
u8 read_dummy;
|
u8 read_dummy;
|
||||||
u8 program_opcode;
|
u8 program_opcode;
|
||||||
|
#ifdef CONFIG_SPI_FLASH_BAR
|
||||||
|
u8 bank_read_cmd;
|
||||||
|
u8 bank_write_cmd;
|
||||||
|
u8 bank_curr;
|
||||||
|
#endif
|
||||||
enum spi_nor_protocol read_proto;
|
enum spi_nor_protocol read_proto;
|
||||||
enum spi_nor_protocol write_proto;
|
enum spi_nor_protocol write_proto;
|
||||||
enum spi_nor_protocol reg_proto;
|
enum spi_nor_protocol reg_proto;
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue