Skip to content

Commit

Permalink
spi: sf: Add 4byte addressing support
Browse files Browse the repository at this point in the history
Add 4 byte addressing support in sf framework
for the devices of size greater thab 16M and
for the controllers which are capable of 4 byte
addressing.

Signed-off-by: Siva Durga Prasad Paladugu <[email protected]>
Signed-off-by: Michal Simek <[email protected]>
  • Loading branch information
Siva Durga Prasad Paladugu authored and Michal Simek committed Aug 14, 2015
1 parent 3b297ca commit ff1b3de
Show file tree
Hide file tree
Showing 3 changed files with 80 additions and 30 deletions.
95 changes: 67 additions & 28 deletions drivers/mtd/spi/sf_ops.c
Original file line number Diff line number Diff line change
Expand Up @@ -17,12 +17,19 @@

#include "sf_internal.h"

static void spi_flash_addr(u32 addr, u8 *cmd)
static void spi_flash_addr(u32 addr, u8 *cmd, u8 four_byte)
{
/* cmd[0] is actual command */
cmd[1] = addr >> 16;
cmd[2] = addr >> 8;
cmd[3] = addr >> 0;
if (four_byte) {
cmd[1] = addr >> 24;
cmd[2] = addr >> 16;
cmd[3] = addr >> 8;
cmd[4] = addr >> 0;
} else {
cmd[1] = addr >> 16;
cmd[2] = addr >> 8;
cmd[3] = addr >> 0;
}
}

int spi_flash_cmd_read_status(struct spi_flash *flash, u8 *rs)
Expand Down Expand Up @@ -384,7 +391,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, erase_addr, bank_addr;
u8 cmd[SPI_FLASH_CMD_LEN];
u8 cmd[SPI_FLASH_CMD_LEN + 1];
u32 cmdlen;
int ret = -1;

erase_size = flash->erase_size;
Expand All @@ -404,12 +412,19 @@ int spi_flash_cmd_erase_ops(struct spi_flash *flash, u32 offset, size_t len)
if (flash->dual_flash == SF_DUAL_STACKED_FLASH)
bank_addr = erase_addr;
#endif

if (flash->spi->bytemode != SPI_4BYTE_MODE) {
#ifdef CONFIG_SPI_FLASH_BAR
ret = spi_flash_bank(flash, bank_addr);
if (ret < 0)
return ret;
ret = spi_flash_bank(flash, bank_addr);
if (ret < 0)
return ret;
#endif
spi_flash_addr(erase_addr, cmd);
spi_flash_addr(erase_addr, cmd, 0);
cmdlen = SPI_FLASH_CMD_LEN;
} else {
spi_flash_addr(erase_addr, cmd, 1);
cmdlen = SPI_FLASH_CMD_LEN + 1;
}

debug("SF: erase %2x %2x %2x %2x (%x)\n", cmd[0], cmd[1],
cmd[2], cmd[3], erase_addr);
Expand All @@ -419,7 +434,7 @@ int spi_flash_cmd_erase_ops(struct spi_flash *flash, u32 offset, size_t len)
flash->spi->flags |= SPI_XFER_STRIPE;
#endif

ret = spi_flash_write_common(flash, cmd, sizeof(cmd), NULL, 0);
ret = spi_flash_write_common(flash, cmd, cmdlen, NULL, 0);
if (ret < 0) {
debug("SF: erase failed\n");
break;
Expand All @@ -438,8 +453,9 @@ int spi_flash_cmd_write_ops(struct spi_flash *flash, u32 offset,
unsigned long byte_addr, page_size;
u32 write_addr, bank_addr;
size_t chunk_len, actual;
u8 cmd[SPI_FLASH_CMD_LEN];
u8 cmd[SPI_FLASH_CMD_LEN + 1];
int ret = -1;
u32 cmdlen;

page_size = flash->page_size;

Expand All @@ -454,19 +470,29 @@ int spi_flash_cmd_write_ops(struct spi_flash *flash, u32 offset,
if (flash->dual_flash == SF_DUAL_STACKED_FLASH)
bank_addr = write_addr;
#endif

if (flash->spi->bytemode != SPI_4BYTE_MODE) {
#ifdef CONFIG_SPI_FLASH_BAR
ret = spi_flash_bank(flash, bank_addr);
if (ret < 0)
return ret;
ret = spi_flash_bank(flash, bank_addr);
if (ret < 0)
return ret;
#endif
}

byte_addr = offset % page_size;
chunk_len = min(len - actual, (size_t)(page_size - byte_addr));

if (flash->spi->max_write_size)
chunk_len = min(chunk_len,
(size_t)flash->spi->max_write_size);

spi_flash_addr(write_addr, cmd);
if (flash->spi->bytemode == SPI_4BYTE_MODE) {
spi_flash_addr(write_addr, cmd, 1);
cmdlen = SPI_FLASH_CMD_LEN + 1;
} else {
spi_flash_addr(write_addr, cmd, 0);
cmdlen = SPI_FLASH_CMD_LEN;
}

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);
Expand All @@ -475,7 +501,7 @@ int spi_flash_cmd_write_ops(struct spi_flash *flash, u32 offset,
if (flash->dual_flash == SF_DUAL_PARALLEL_FLASH)
flash->spi->flags |= SPI_XFER_STRIPE;
#endif
ret = spi_flash_write_common(flash, cmd, sizeof(cmd),
ret = spi_flash_write_common(flash, cmd, cmdlen,
buf + actual, chunk_len);
if (ret < 0) {
debug("SF: write failed\n");
Expand Down Expand Up @@ -534,6 +560,10 @@ int spi_flash_cmd_read_ops(struct spi_flash *flash, u32 offset,
}

cmdsz = SPI_FLASH_CMD_LEN + flash->dummy_byte;

if (flash->spi->bytemode == SPI_4BYTE_MODE)
cmdsz += 1;

cmd = calloc(1, cmdsz);
if (!cmd) {
debug("SF: Failed to allocate cmd\n");
Expand All @@ -551,23 +581,32 @@ int spi_flash_cmd_read_ops(struct spi_flash *flash, u32 offset,
if (flash->dual_flash == SF_DUAL_STACKED_FLASH)
bank_addr = read_addr;
#endif
if (flash->spi->bytemode != SPI_4BYTE_MODE) {
#ifdef CONFIG_SPI_FLASH_BAR
bank_sel = spi_flash_bank(flash, bank_addr);
if (bank_sel < 0)
return ret;
if ((flash->dual_flash == SF_DUAL_STACKED_FLASH) &&
(flash->spi->flags & SPI_XFER_U_PAGE))
bank_sel += (flash->size >> 1)/SPI_FLASH_16MB_BOUN;
bank_sel = spi_flash_bank(flash, bank_addr);
if (bank_sel < 0)
return ret;
if ((flash->dual_flash == SF_DUAL_STACKED_FLASH) &&
(flash->spi->flags & SPI_XFER_U_PAGE))
bank_sel += (flash->size >> 1)/
SPI_FLASH_16MB_BOUN;
#endif
remain_len = ((SPI_FLASH_16MB_BOUN << flash->shift) *
(bank_sel + 1)) - offset;
if (len < remain_len)
remain_len = ((SPI_FLASH_16MB_BOUN << flash->shift) *
(bank_sel + 1)) - offset;
if (len < remain_len)
read_len = len;
else
read_len = remain_len;
} else {
read_len = len;
else
read_len = remain_len;
}

spi_flash_addr(read_addr, cmd);
if (flash->spi->bytemode == SPI_4BYTE_MODE)
spi_flash_addr(read_addr, cmd, 1);
else
spi_flash_addr(read_addr, cmd, 0);

debug("%s: Byte Mode:0x%x\n",__func__, flash->spi->bytemode);
#ifdef CONFIG_SPI_GENERIC
if (flash->dual_flash == SF_DUAL_PARALLEL_FLASH)
flash->spi->flags |= SPI_XFER_STRIPE;
Expand Down
11 changes: 9 additions & 2 deletions drivers/mtd/spi/sf_probe.c
Original file line number Diff line number Diff line change
Expand Up @@ -214,8 +214,15 @@ static int spi_flash_validate_params(struct spi_slave *spi, u8 *idcode,
* in case of warm bootup, the chip was set to 4-byte mode in kernel.
*/
if (flash->size > SPI_FLASH_16MB_BOUN) {
if (spi_flash_cmd_4B_addr_switch(flash, false, idcode[0]) < 0)
debug("SF: enter 3B address mode failed\n");
if (flash->spi->bytemode == SPI_4BYTE_MODE) {
if (spi_flash_cmd_4B_addr_switch(flash, true,
idcode[0]) < 0)
debug("SF: enter 4B address mode failed\n");
} else {
if (spi_flash_cmd_4B_addr_switch(flash, false,
idcode[0]) < 0)
debug("SF: enter 3B address mode failed\n");
}
}

#ifdef CONFIG_SF_DUAL_FLASH
Expand Down
4 changes: 4 additions & 0 deletions include/spi.h
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,9 @@
#define SPI_SLAVE 0x40 /* slave mode */
#define SPI_PREAMBLE 0x80 /* Skip preamble bytes */

#define SPI_3BYTE_MODE 0x0
#define SPI_4BYTE_MODE 0x1

/* SPI transfer flags */
#define SPI_XFER_BEGIN 0x01 /* Assert CS before transfer */
#define SPI_XFER_END 0x02 /* Deassert CS after transfer */
Expand Down Expand Up @@ -137,6 +140,7 @@ struct spi_slave {
u8 option;
u8 dio;
u32 flags;
u32 bytemode;
};

/**
Expand Down

0 comments on commit ff1b3de

Please sign in to comment.