* [PATCH] spi-nor: Add support for Atmel Dataflash memories
@ 2018-02-28 11:55 Radu Pirea
2018-05-04 18:38 ` Boris Brezillon
0 siblings, 1 reply; 4+ messages in thread
From: Radu Pirea @ 2018-02-28 11:55 UTC (permalink / raw)
To: cyrille.pitchen, marek.vasut, dwmw2, computersforpeace,
boris.brezillon, richard, linux-mtd, linux-kernel, nicolas.ferre
Cc: Radu Pirea
This patch add support in spi-nor for allmost all dataflash memories
supported by old mtd_dataflash driver.
Signed-off-by: Radu Pirea <radu.pirea@microchip.com>
---
drivers/mtd/spi-nor/spi-nor.c | 150 +++++++++++++++++++++++++++++++++++++++++-
include/linux/mtd/spi-nor.h | 10 +++
2 files changed, 158 insertions(+), 2 deletions(-)
diff --git a/drivers/mtd/spi-nor/spi-nor.c b/drivers/mtd/spi-nor/spi-nor.c
index d445a4d..4cb3cf7 100644
--- a/drivers/mtd/spi-nor/spi-nor.c
+++ b/drivers/mtd/spi-nor/spi-nor.c
@@ -89,6 +89,7 @@ struct flash_info {
#define NO_CHIP_ERASE BIT(12) /* Chip does not support chip erase */
#define SPI_NOR_SKIP_SFDP BIT(13) /* Skip parsing of SFDP tables */
#define USE_CLSR BIT(14) /* use CLSR command */
+#define SPI_DATAFLASH BIT(15) /* Atmel Dataflash memory */
int (*quad_enable)(struct spi_nor *nor);
};
@@ -306,6 +307,20 @@ static int s3an_sr_ready(struct spi_nor *nor)
return !!(val & XSR_RDY);
}
+static int dataflash_sr_ready(struct spi_nor *nor)
+{
+ int ret;
+ u8 val;
+
+ ret = nor->read_reg(nor, SPINOR_OP_DFRDSR, &val, 1);
+ if (ret < 0) {
+ dev_err(nor->dev, "error %d reading DFSR\n", ret);
+ return ret;
+ }
+
+ return !!(val & DFSR_RDY);
+}
+
static inline int spi_nor_sr_ready(struct spi_nor *nor)
{
int sr = read_sr(nor);
@@ -354,6 +369,8 @@ static int spi_nor_ready(struct spi_nor *nor)
if (nor->flags & SNOR_F_READY_XSR_RDY)
sr = s3an_sr_ready(nor);
+ else if (nor->flags & SPI_DATAFLASH)
+ sr = dataflash_sr_ready(nor);
else
sr = spi_nor_sr_ready(nor);
if (sr < 0)
@@ -457,6 +474,44 @@ static loff_t spi_nor_s3an_addr_convert(struct spi_nor *nor, unsigned int addr)
return page | offset;
}
+static loff_t spi_nor_dataflash_addr_convert(struct spi_nor *nor,
+ unsigned int addr)
+{
+ unsigned int offset;
+ unsigned int page;
+ unsigned int page_offset;
+
+ page = addr / nor->page_size;
+ offset = addr % nor->page_size;
+ page_offset = fls(nor->page_size);
+ if (is_power_of_2(nor->page_size))
+ page_offset--;
+
+ return (page << page_offset) | offset;
+}
+
+static int spi_nor_dataflash_erase_sector(struct spi_nor *nor, u32 addr)
+{
+ u32 block_size = 8 * nor->page_size;
+ u32 blocks = nor->mtd.erasesize / block_size;
+ u32 addr_local;
+ u8 buf[SPI_NOR_MAX_ADDR_WIDTH];
+ int i, j;
+
+ for (j = 0; j < blocks; j++) {
+ addr_local = spi_nor_dataflash_addr_convert(nor, addr);
+ for (i = nor->addr_width - 1; i >= 0; i--) {
+ buf[i] = addr_local & 0xff;
+ addr_local >>= 8;
+ }
+ nor->write_reg(nor, nor->erase_opcode, buf, nor->addr_width);
+ addr += block_size;
+ spi_nor_wait_till_ready(nor);
+ }
+
+ return 0;
+}
+
/*
* Initiate the erasure of a single sector
*/
@@ -542,7 +597,11 @@ static int spi_nor_erase(struct mtd_info *mtd, struct erase_info *instr)
while (len) {
write_enable(nor);
- ret = spi_nor_erase_sector(nor, addr);
+ if (nor->flags & SPI_DATAFLASH)
+ ret = spi_nor_dataflash_erase_sector(nor, addr);
+ else
+ ret = spi_nor_erase_sector(nor, addr);
+
if (ret)
goto erase_err;
@@ -914,6 +973,20 @@ static int macronix_quad_enable(struct spi_nor *nor);
.page_size = 256, \
.flags = (_flags),
+#define INFOP(_jedec_id, _ext_id, _sector_size, _n_sectors, _page_size, _flags) \
+ .id = { \
+ ((_jedec_id) >> 16) & 0xff, \
+ ((_jedec_id) >> 8) & 0xff, \
+ (_jedec_id) & 0xff, \
+ ((_ext_id) >> 8) & 0xff, \
+ (_ext_id) & 0xff, \
+ }, \
+ .id_len = (!(_jedec_id) ? 0 : (3 + ((_ext_id) ? 2 : 0))), \
+ .sector_size = (_sector_size), \
+ .n_sectors = (_n_sectors), \
+ .page_size = _page_size, \
+ .flags = (_flags),
+
#define INFO6(_jedec_id, _ext_id, _sector_size, _n_sectors, _flags) \
.id = { \
((_jedec_id) >> 16) & 0xff, \
@@ -975,7 +1048,14 @@ static const struct flash_info spi_nor_ids[] = {
{ "at26df161a", INFO(0x1f4601, 0, 64 * 1024, 32, SECT_4K) },
{ "at26df321", INFO(0x1f4700, 0, 64 * 1024, 64, SECT_4K) },
- { "at45db081d", INFO(0x1f2500, 0, 64 * 1024, 16, SECT_4K) },
+ { "at45db021d", INFOP(0x1f2300, 0, 512 * 264, 2, 264, SPI_DATAFLASH | NO_CHIP_ERASE) },
+ { "at45db041d", INFOP(0x1f2400, 0, 256 * 264, 8, 264, SPI_DATAFLASH | NO_CHIP_ERASE) },
+ { "at45db081d", INFOP(0x1f2500, 0, 256 * 264, 16, 264, SPI_DATAFLASH | NO_CHIP_ERASE) },
+ { "at45db161d", INFOP(0x1f2600, 0, 256 * 528, 16, 528, SPI_DATAFLASH | NO_CHIP_ERASE) },
+ { "at45db321d", INFOP(0x1f2700, 0, 128 * 528, 64, 528, SPI_DATAFLASH | NO_CHIP_ERASE) },
+ { "at45db321d", INFOP(0x1f2701, 0, 128 * 528, 64, 528, SPI_DATAFLASH | NO_CHIP_ERASE) },
+ { "at45db642d", INFOP(0x1f2800, 0, 256 * 1056, 32, 1056, SPI_DATAFLASH | NO_CHIP_ERASE) },
+ { "at45db641e", INFOP(0x1f2800, 0x0100, 1024 * 264, 32, 264, SPI_DATAFLASH | NO_CHIP_ERASE) },
/* EON -- en25xxx */
{ "en25f32", INFO(0x1c3116, 0, 64 * 1024, 64, SECT_4K) },
@@ -1278,6 +1358,9 @@ static int spi_nor_read(struct mtd_info *mtd, loff_t from, size_t len,
if (nor->flags & SNOR_F_S3AN_ADDR_DEFAULT)
addr = spi_nor_s3an_addr_convert(nor, addr);
+ if (nor->flags & SPI_DATAFLASH)
+ addr = spi_nor_dataflash_addr_convert(nor, addr);
+
ret = nor->read(nor, addr, len, buf);
if (ret == 0) {
/* We shouldn't see 0-length reads */
@@ -1379,6 +1462,21 @@ static int sst_write(struct mtd_info *mtd, loff_t to, size_t len,
return ret;
}
+static int dataflash_memtobuf(struct spi_nor *nor, u32 addr)
+{
+ u8 buf[SPI_NOR_MAX_ADDR_WIDTH];
+ int i;
+
+ addr = spi_nor_dataflash_addr_convert(nor, addr);
+
+ for (i = nor->addr_width - 1; i >= 0; i--) {
+ buf[i] = addr & 0xff;
+ addr >>= 8;
+ }
+
+ return nor->write_reg(nor, SPINOR_OP_DFMTB, buf, nor->addr_width);
+}
+
/*
* Write an address range to the nor chip. Data must be written in
* FLASH_PAGESIZE chunks. The address range may be any size provided
@@ -1420,9 +1518,17 @@ static int spi_nor_write(struct mtd_info *mtd, loff_t to, size_t len,
page_remain = min_t(size_t,
nor->page_size - page_offset, len - i);
+ if (nor->flags & SPI_DATAFLASH) {
+ dataflash_memtobuf(nor, addr);
+ spi_nor_wait_till_ready(nor);
+ }
+
if (nor->flags & SNOR_F_S3AN_ADDR_DEFAULT)
addr = spi_nor_s3an_addr_convert(nor, addr);
+ if (nor->flags & SPI_DATAFLASH)
+ addr = spi_nor_dataflash_addr_convert(nor, addr);
+
write_enable(nor);
ret = nor->write(nor, addr, page_remain, buf + i);
if (ret < 0)
@@ -1742,6 +1848,37 @@ static int s3an_nor_scan(const struct flash_info *info, struct spi_nor *nor)
return 0;
}
+static int dataflash_nor_scan(const struct flash_info *info,
+ struct spi_nor *nor)
+{
+ int ret;
+ u8 val;
+
+ ret = nor->read_reg(nor, SPINOR_OP_DFRDSR, &val, 1);
+ if (ret < 0) {
+ dev_err(nor->dev, "error reading status register\n");
+ return ret;
+ }
+
+ nor->erase_opcode = SPINOR_OP_DFBE_8k;
+ nor->program_opcode = SPINOR_OP_DFBTOM;
+ nor->read_opcode = SPINOR_OP_DFRD;
+ nor->flags |= SNOR_F_NO_OP_CHIP_ERASE;
+
+ if (val & DFSR_PAGESIZE) {
+ /* Flash in Power of 2 mode */
+ nor->mtd.erasesize = nor->mtd.erasesize / nor->page_size *
+ (1 << (fls(nor->page_size) - 1));
+ nor->mtd.size = nor->mtd.erasesize * info->n_sectors;
+ nor->page_size = 1 << (fls(nor->page_size) - 1);
+ nor->mtd.writebufsize = nor->page_size;
+ }
+
+ nor->read_dummy = 32;
+
+ return 0;
+}
+
struct spi_nor_read_command {
u8 num_mode_clocks;
u8 num_wait_states;
@@ -2818,6 +2955,9 @@ int spi_nor_scan(struct spi_nor *nor, const char *name,
if (info->flags & SPI_S3AN)
nor->flags |= SNOR_F_READY_XSR_RDY;
+ if (info->flags & SPI_DATAFLASH)
+ nor->flags |= SPI_DATAFLASH;
+
/* Parse the Serial Flash Discoverable Parameters table. */
ret = spi_nor_init_params(nor, info, ¶ms);
if (ret)
@@ -2922,6 +3062,12 @@ int spi_nor_scan(struct spi_nor *nor, const char *name,
return ret;
}
+ if (info->flags & SPI_DATAFLASH) {
+ ret = dataflash_nor_scan(info, nor);
+ if (ret)
+ return ret;
+ }
+
/* Send all the required SPI flash commands to initialize device */
nor->info = info;
ret = spi_nor_init(nor);
diff --git a/include/linux/mtd/spi-nor.h b/include/linux/mtd/spi-nor.h
index de36969..843edf9 100644
--- a/include/linux/mtd/spi-nor.h
+++ b/include/linux/mtd/spi-nor.h
@@ -91,6 +91,16 @@
#define SPINOR_OP_WRDI 0x04 /* Write disable */
#define SPINOR_OP_AAI_WP 0xad /* Auto address increment word program */
+/* Used for Atmel Dataflashes only. */
+#define SPINOR_OP_DFRDSR 0xd7
+#define SPINOR_OP_DFBE_8k 0x50
+#define SPINOR_OP_DFMTB 0x53
+#define SPINOR_OP_DFBTOM 0x82
+#define SPINOR_OP_DFRD 0xe8
+
+#define DFSR_PAGESIZE BIT(0) /* Page size in Po2 or Linear */
+#define DFSR_RDY BIT(7) /* Ready */
+
/* Used for S3AN flashes only */
#define SPINOR_OP_XSE 0x50 /* Sector erase */
#define SPINOR_OP_XPP 0x82 /* Page program */
--
2.7.4
^ permalink raw reply related [flat|nested] 4+ messages in thread
* Re: [PATCH] spi-nor: Add support for Atmel Dataflash memories
2018-02-28 11:55 [PATCH] spi-nor: Add support for Atmel Dataflash memories Radu Pirea
@ 2018-05-04 18:38 ` Boris Brezillon
2018-05-07 8:23 ` Nicolas Ferre
0 siblings, 1 reply; 4+ messages in thread
From: Boris Brezillon @ 2018-05-04 18:38 UTC (permalink / raw)
To: Radu Pirea
Cc: cyrille.pitchen, marek.vasut, dwmw2, computersforpeace, richard,
linux-mtd, linux-kernel, nicolas.ferre
Hi Radu,
Sorry for the late reply.
On Wed, 28 Feb 2018 13:55:01 +0200
Radu Pirea <radu.pirea@microchip.com> wrote:
> This patch add support in spi-nor for allmost all dataflash memories
> supported by old mtd_dataflash driver.
Those devices clearly use a different instruction set, so I don't think
they fit in this framework. Can you tell us why you want to move
dataflash support to the SPI NOR framework. I think I know why, but I'd
like to get your version. My guess is that some people want to connect
dataflash chips to the Atmel QSPI controller, and it's not supported
right now because the Atmel QSPI controller implements the SPI-NOR
interface and not the generic SPI one, thus preventing anything that
is not a SPI NOR from being connected to this controller.
If I'm right, then the solution is to convert the QSPI driver to the
spi-mem interface [1] and move it to drivers/spi/.
Regards,
Boris
[1]http://patchwork.ozlabs.org/project/linux-mtd/list/?series=41174
^ permalink raw reply [flat|nested] 4+ messages in thread
* Re: [PATCH] spi-nor: Add support for Atmel Dataflash memories
2018-05-04 18:38 ` Boris Brezillon
@ 2018-05-07 8:23 ` Nicolas Ferre
2018-05-07 8:34 ` Boris Brezillon
0 siblings, 1 reply; 4+ messages in thread
From: Nicolas Ferre @ 2018-05-07 8:23 UTC (permalink / raw)
To: Boris Brezillon, Radu Pirea
Cc: cyrille.pitchen, marek.vasut, dwmw2, computersforpeace, richard,
linux-mtd, linux-kernel, Tudor Ambarus - M18064
On 04/05/2018 at 20:38, Boris Brezillon wrote:
> Hi Radu,
>
> Sorry for the late reply.
>
> On Wed, 28 Feb 2018 13:55:01 +0200
> Radu Pirea <radu.pirea@microchip.com> wrote:
>
>> This patch add support in spi-nor for allmost all dataflash memories
>> supported by old mtd_dataflash driver.
>
> Those devices clearly use a different instruction set, so I don't think
> they fit in this framework. Can you tell us why you want to move
> dataflash support to the SPI NOR framework. I think I know why, but I'd
> like to get your version. My guess is that some people want to connect
> dataflash chips to the Atmel QSPI controller, and it's not supported
> right now because the Atmel QSPI controller implements the SPI-NOR
> interface and not the generic SPI one, thus preventing anything that
> is not a SPI NOR from being connected to this controller.
>
> If I'm right, then the solution is to convert the QSPI driver to the
> spi-mem interface [1] and move it to drivers/spi/.
No, I we didn't think about this. Dataflash is not so popular those days
and we don't want to revive it anyway. Our QSPI driver has already a lot
of things to handle in QSPI-related topics to not mix it with oldies ;-)
The rationale behind this work is to get rid of the very old dataflash
standalone driver and benefit from the whole spi-nor infrastructure like
cache coherency management and DMA handling (which were broken in the
old dataflash driver in recent kernels).
Best regards,
Nicolas
> [1]http://patchwork.ozlabs.org/project/linux-mtd/list/?series=41174
>
--
Nicolas Ferre
^ permalink raw reply [flat|nested] 4+ messages in thread
* Re: [PATCH] spi-nor: Add support for Atmel Dataflash memories
2018-05-07 8:23 ` Nicolas Ferre
@ 2018-05-07 8:34 ` Boris Brezillon
0 siblings, 0 replies; 4+ messages in thread
From: Boris Brezillon @ 2018-05-07 8:34 UTC (permalink / raw)
To: Nicolas Ferre
Cc: Radu Pirea, cyrille.pitchen, marek.vasut, dwmw2,
computersforpeace, richard, linux-mtd, linux-kernel,
Tudor Ambarus - M18064
Hi Nicolas,
On Mon, 7 May 2018 10:23:56 +0200
Nicolas Ferre <nicolas.ferre@microchip.com> wrote:
> On 04/05/2018 at 20:38, Boris Brezillon wrote:
> > Hi Radu,
> >
> > Sorry for the late reply.
> >
> > On Wed, 28 Feb 2018 13:55:01 +0200
> > Radu Pirea <radu.pirea@microchip.com> wrote:
> >
> >> This patch add support in spi-nor for allmost all dataflash memories
> >> supported by old mtd_dataflash driver.
> >
> > Those devices clearly use a different instruction set, so I don't think
> > they fit in this framework. Can you tell us why you want to move
> > dataflash support to the SPI NOR framework. I think I know why, but I'd
> > like to get your version. My guess is that some people want to connect
> > dataflash chips to the Atmel QSPI controller, and it's not supported
> > right now because the Atmel QSPI controller implements the SPI-NOR
> > interface and not the generic SPI one, thus preventing anything that
> > is not a SPI NOR from being connected to this controller.
> >
> > If I'm right, then the solution is to convert the QSPI driver to the
> > spi-mem interface [1] and move it to drivers/spi/.
>
> No, I we didn't think about this. Dataflash is not so popular those days
> and we don't want to revive it anyway. Our QSPI driver has already a lot
> of things to handle in QSPI-related topics to not mix it with oldies ;-)
>
> The rationale behind this work is to get rid of the very old dataflash
> standalone driver and benefit from the whole spi-nor infrastructure like
> cache coherency management and DMA handling (which were broken in the
> old dataflash driver in recent kernels).
Still don't think that's a good move, especially since those flashes are
using a completely different instruction set and are not exactly
behaving like SPI NORs. If we need some of the spi-nor logic to help
handle dataflash chips in a more efficient/safe way, then those bits
should be exposed as helpers at the MTD level instead of turning
spi-nor into a Frankenstein framework.
Regards,
Boris
^ permalink raw reply [flat|nested] 4+ messages in thread
end of thread, other threads:[~2018-05-07 8:34 UTC | newest]
Thread overview: 4+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2018-02-28 11:55 [PATCH] spi-nor: Add support for Atmel Dataflash memories Radu Pirea
2018-05-04 18:38 ` Boris Brezillon
2018-05-07 8:23 ` Nicolas Ferre
2018-05-07 8:34 ` Boris Brezillon
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox