Skip to content
Snippets Groups Projects
Commit 980615ac authored by Davide Cardillo's avatar Davide Cardillo
Browse files

[ALL][SPI FLASH] Add support for QSPI SST SST26VF032Q

parent a35dcd43
No related branches found
No related tags found
No related merge requests found
......@@ -329,7 +329,8 @@ struct flash_info {
* available I/O mode via a
* volatile bit.
*/
#define SST_BLOCK_PROTECT BIT(22) /* SST global protection */
#define SST_WRITE_PAGE BIT(23) /* use SST PAGE byte programming */
/* Part specific fixup hooks. */
const struct spi_nor_fixups *fixups;
};
......
......@@ -40,6 +40,9 @@ static const struct flash_info sst_parts[] = {
{ "sst26vf064b", INFO(0xbf2643, 0, 64 * 1024, 128,
SECT_4K | SPI_NOR_DUAL_READ |
SPI_NOR_QUAD_READ) },
{ "sst26vf032b", INFO(0xbf2642, 0, 64 * 1024, 64,
SECT_4K | SPI_NOR_DUAL_READ | SST_WRITE_PAGE |
SPI_NOR_QUAD_READ | SST_BLOCK_PROTECT) },
};
static int sst_write(struct mtd_info *mtd, loff_t to, size_t len,
......@@ -47,6 +50,9 @@ static int sst_write(struct mtd_info *mtd, loff_t to, size_t len,
{
struct spi_nor *nor = mtd_to_spi_nor(mtd);
size_t actual = 0;
loff_t msize;
size_t wsize;
int psize = 256;
int ret;
dev_dbg(nor->dev, "to 0x%08x, len %zd\n", (u32)to, len);
......@@ -61,37 +67,62 @@ static int sst_write(struct mtd_info *mtd, loff_t to, size_t len,
nor->sst_write_second = false;
/* Start write from odd address. */
if (to % 2) {
nor->program_opcode = SPINOR_OP_BP;
/* write one byte. */
ret = spi_nor_write_data(nor, to, 1, buf);
if (ret < 0)
goto out;
WARN(ret != 1, "While writing 1 byte written %i bytes\n", ret);
ret = spi_nor_wait_till_ready(nor);
if (ret)
goto out;
to++;
actual++;
}
if (nor->info->flags & SST_WRITE_PAGE) {
while ( actual < len ) {
/* to avoid wrap around in page programming */
msize = (to + psize) - ((to + psize) % psize);
wsize = (to + len) < msize ? len : (msize - to);
/* write in page mode */
nor->program_opcode = SPINOR_OP_BP;
ret = spi_nor_write_data(nor, to, wsize, buf + actual);
if (ret < 0)
goto out;
WARN(ret != wsize, "While writing %lu bytes written %i bytes\n",
wsize, (int)ret);
ret = spi_nor_wait_till_ready(nor);
if (ret)
goto out;
to += wsize;
actual += wsize;
}
} else {
/* Start write from odd address. */
if (to % 2) {
nor->program_opcode = SPINOR_OP_BP;
/* write one byte. */
ret = spi_nor_write_data(nor, to, 1, buf);
if (ret < 0)
goto out;
WARN(ret != 1, "While writing 1 byte written %i bytes\n", ret);
ret = spi_nor_wait_till_ready(nor);
if (ret)
goto out;
to++;
actual++;
}
/* Write out most of the data here. */
for (; actual < len - 1; actual += 2) {
nor->program_opcode = SPINOR_OP_AAI_WP;
/* write two bytes. */
ret = spi_nor_write_data(nor, to, 2, buf + actual);
if (ret < 0)
goto out;
WARN(ret != 2, "While writing 2 bytes written %i bytes\n", ret);
ret = spi_nor_wait_till_ready(nor);
if (ret)
goto out;
to += 2;
nor->sst_write_second = true;
}
/* Write out most of the data here. */
for (; actual < len - 1; actual += 2) {
nor->program_opcode = SPINOR_OP_AAI_WP;
/* write two bytes. */
ret = spi_nor_write_data(nor, to, 2, buf + actual);
if (ret < 0)
goto out;
WARN(ret != 2, "While writing 2 bytes written %i bytes\n", ret);
ret = spi_nor_wait_till_ready(nor);
if (ret)
goto out;
to += 2;
nor->sst_write_second = true;
}
nor->sst_write_second = false;
......@@ -128,15 +159,68 @@ out:
return ret;
}
static inline int sst_unlock_global_protection( struct spi_nor *nor ) {
int ret;
struct spi_mem_op op =
SPI_MEM_OP(SPI_MEM_OP_CMD(SPINOR_OP_ULBPR, 0),
SPI_MEM_OP_NO_ADDR,
SPI_MEM_OP_NO_DUMMY,
SPI_MEM_OP_NO_DATA);
dev_info(nor->dev,"sst unlock global protection\n");
ret = spi_nor_write_enable(nor);
if (ret)
return ret;
spi_nor_spimem_setup_op(nor, &op, nor->reg_proto);
ret = spi_mem_exec_op(nor->spimem, &op);
if (ret) {
dev_err(nor->dev,
"timeout while unlock global protection\n");
}
ret = spi_nor_write_disable(nor);
return ret;
}
static int sst_global_lock(struct spi_nor *nor, loff_t ofs, uint64_t len) {
return -EOPNOTSUPP;
}
static int sst_global_unlock(struct spi_nor *nor, loff_t ofs, uint64_t len) {
int ret = -EOPNOTSUPP;
if (nor->info->flags & SST_BLOCK_PROTECT)
ret = sst_unlock_global_protection(nor);
return ret;
}
static int sst_is_global_locked(struct spi_nor *nor, loff_t ofs, uint64_t len) {
return -EOPNOTSUPP;
}
static const struct spi_nor_locking_ops sst_locking_ops = {
.lock = sst_global_lock,
.unlock = sst_global_unlock,
.is_locked = sst_is_global_locked,
};
static void sst_default_init(struct spi_nor *nor)
{
nor->flags |= SNOR_F_HAS_LOCK;
if (nor->info->flags & SST_BLOCK_PROTECT) {
sst_unlock_global_protection(nor);
nor->params->locking_ops = &sst_locking_ops;
}
}
static void sst_post_sfdp_fixups(struct spi_nor *nor)
{
if (nor->info->flags & SST_WRITE)
nor->mtd._write = sst_write;
if (nor->info->flags & SST_BLOCK_PROTECT)
sst_unlock_global_protection(nor);
}
static const struct spi_nor_fixups sst_fixups = {
......
......@@ -52,6 +52,7 @@
#define SPINOR_OP_RDEAR 0xc8 /* Read Extended Address Register */
#define SPINOR_OP_WREAR 0xc5 /* Write Extended Address Register */
#define SPINOR_OP_SRSTEN 0x66 /* Software Reset Enable */
#define SPINOR_OP_ULBPR 0x98 /* Global Block Protection Unlock */
#define SPINOR_OP_SRST 0x99 /* Software Reset */
/* 4-byte address opcodes - used on Spansion and some Macronix flashes. */
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment