* [PATCHv2] drivers: mtd: devices: Add quad read support.
@ 2013-09-26 10:32 Sourav Poddar
2013-09-26 11:00 ` David Woodhouse
2013-10-07 12:11 ` Sourav Poddar
0 siblings, 2 replies; 11+ messages in thread
From: Sourav Poddar @ 2013-09-26 10:32 UTC (permalink / raw)
To: dwmw2, artem.bityutskiy, computersforpeace, linux-mtd, b32955
Cc: Sourav Poddar, broonie, balbi
Some flash also support quad read mode.
Adding support for adding quad mode in m25p80.
Signed-off-by: Sourav Poddar <sourav.poddar@ti.com>
---
v1->v2:
- Make the code more modular
- put proper error checks
drivers/mtd/devices/m25p80.c | 155 +++++++++++++++++++++++++++++++++++++++---
1 files changed, 144 insertions(+), 11 deletions(-)
diff --git a/drivers/mtd/devices/m25p80.c b/drivers/mtd/devices/m25p80.c
index 26b14f9..3c8a794 100644
--- a/drivers/mtd/devices/m25p80.c
+++ b/drivers/mtd/devices/m25p80.c
@@ -41,6 +41,7 @@
#define OPCODE_WRSR 0x01 /* Write status register 1 byte */
#define OPCODE_NORM_READ 0x03 /* Read data bytes (low frequency) */
#define OPCODE_FAST_READ 0x0b /* Read data bytes (high frequency) */
+#define OPCODE_QUAD_READ 0x6b /* QUAD READ */
#define OPCODE_PP 0x02 /* Page program (up to 256 bytes) */
#define OPCODE_BE_4K 0x20 /* Erase 4KiB block */
#define OPCODE_BE_4K_PMC 0xd7 /* Erase 4KiB block on PMC chips */
@@ -48,10 +49,12 @@
#define OPCODE_CHIP_ERASE 0xc7 /* Erase whole flash chip */
#define OPCODE_SE 0xd8 /* Sector erase (usually 64KiB) */
#define OPCODE_RDID 0x9f /* Read JEDEC ID */
+#define OPCODE_RDCR 0x35 /* Read configuration register */
/* 4-byte address opcodes - used on Spansion and some Macronix flashes. */
#define OPCODE_NORM_READ_4B 0x13 /* Read data bytes (low frequency) */
#define OPCODE_FAST_READ_4B 0x0c /* Read data bytes (high frequency) */
+#define OPCODE_QUAD_READ_4B 0x6c /* Read data bytes */
#define OPCODE_PP_4B 0x12 /* Page program (up to 256 bytes) */
#define OPCODE_SE_4B 0xdc /* Sector erase (usually 64KiB) */
@@ -76,6 +79,9 @@
#define SR_BP2 0x10 /* Block protect 2 */
#define SR_SRWD 0x80 /* SR write protect */
+/* Configuration Register bits. */
+#define QUAD_CR_EN 0x2 /* Quad I/O */
+
/* Define max times to check status register before we give up. */
#define MAX_READY_WAIT_JIFFIES (40 * HZ) /* M25P16 specs 40s max chip erase */
#define MAX_CMD_SIZE 5
@@ -95,6 +101,7 @@ struct m25p {
u8 program_opcode;
u8 *command;
bool fast_read;
+ bool quad_read;
};
static inline struct m25p *mtd_to_m25p(struct mtd_info *mtd)
@@ -163,6 +170,25 @@ static inline int write_disable(struct m25p *flash)
return spi_write_then_read(flash->spi, &code, 1, NULL, 0);
}
+/* Read the configuration register, returning its value in the location
+ * Return the configuration register value.
+ * Returns negative if error occurred.
+*/
+static int read_cr(struct m25p *flash)
+{
+ u8 code = OPCODE_RDCR;
+ int ret;
+ u8 val;
+
+ ret = spi_write_then_read(flash->spi, &code, 1, &val, 1);
+ if (ret < 0) {
+ dev_err(&flash->spi->dev, "error %d reading CR\n", ret);
+ return ret;
+ }
+
+ return val;
+}
+
/*
* Enable/disable 4-byte addressing mode.
*/
@@ -336,6 +362,97 @@ static int m25p80_erase(struct mtd_info *mtd, struct erase_info *instr)
return 0;
}
+/* Write status register and configuration register with 2 bytes
+* The first byte will be written to the status register, while the second byte
+* will be written to the configuration register.
+* Returns negative if error occurred.
+*/
+static int write_sr_cr(struct m25p *flash, u16 val)
+{
+ flash->command[0] = OPCODE_WRSR;
+ flash->command[1] = val & 0xff;
+ flash->command[2] = (val >> 8);
+
+ return spi_write(flash->spi, flash->command, 3);
+}
+
+static int quad_enable(struct m25p *flash)
+{
+ int ret;
+ int quad_en = QUAD_CR_EN << 8;
+
+ write_enable(flash);
+
+ ret = write_sr_cr(flash, quad_en);
+ if (ret < 0) {
+ dev_err(&flash->spi->dev,
+ "error while writing configuration register");
+ return -EINVAL;
+ }
+
+ /* read back and check it */
+ ret = read_cr(flash);
+ if (!(ret > 0 && (ret & QUAD_CR_EN))) {
+ dev_err(&flash->spi->dev,
+ "Quad bit not set");
+ return -EINVAL;
+ }
+
+ return 0;
+}
+
+static int m25p80_quad_read(struct mtd_info *mtd, loff_t from, size_t len,
+ size_t *retlen, u_char *buf)
+{
+ struct m25p *flash = mtd_to_m25p(mtd);
+ struct spi_transfer t[2];
+ struct spi_message m;
+ uint8_t opcode;
+
+ pr_debug("%s: %s from 0x%08x, len %zd\n", dev_name(&flash->spi->dev),
+ __func__, (u32)from, len);
+
+ spi_message_init(&m);
+ memset(t, 0, (sizeof(t)));
+
+ t[0].tx_buf = flash->command;
+ t[0].len = m25p_cmdsz(flash) + (flash->quad_read ? 1 : 0);
+ spi_message_add_tail(&t[0], &m);
+
+ t[1].rx_buf = buf;
+ t[1].len = len;
+ t[1].rx_nbits = SPI_NBITS_QUAD;
+ spi_message_add_tail(&t[1], &m);
+
+ mutex_lock(&flash->lock);
+
+ /* Wait till previous write/erase is done. */
+ if (wait_till_ready(flash)) {
+ /* REVISIT status return?? */
+ mutex_unlock(&flash->lock);
+ return 1;
+ }
+
+ /* FIXME switch to OPCODE_QUAD_READ. It's required for higher
+ * clocks; and at this writing, every chip this driver handles
+ * supports that opcode.
+ */
+
+ /* Set up the write data buffer. */
+ opcode = flash->read_opcode;
+ flash->command[0] = opcode;
+ m25p_addr2cmd(flash, from, flash->command);
+
+ spi_sync(flash->spi, &m);
+
+ *retlen = m.actual_length - m25p_cmdsz(flash) -
+ (flash->quad_read ? 1 : 0);
+
+ mutex_unlock(&flash->lock);
+
+ return 0;
+}
+
/*
* Read an address range from the flash chip. The address range
* may be any size provided it is within the physical boundaries.
@@ -928,6 +1045,7 @@ static int m25p_probe(struct spi_device *spi)
unsigned i;
struct mtd_part_parser_data ppdata;
struct device_node __maybe_unused *np = spi->dev.of_node;
+ int ret;
#ifdef CONFIG_MTD_OF_PARTS
if (!of_device_is_available(np))
@@ -979,15 +1097,9 @@ static int m25p_probe(struct spi_device *spi)
}
}
- flash = kzalloc(sizeof *flash, GFP_KERNEL);
+ flash = devm_kzalloc(&spi->dev, sizeof(*flash), GFP_KERNEL);
if (!flash)
return -ENOMEM;
- flash->command = kmalloc(MAX_CMD_SIZE + (flash->fast_read ? 1 : 0),
- GFP_KERNEL);
- if (!flash->command) {
- kfree(flash);
- return -ENOMEM;
- }
flash->spi = spi;
mutex_init(&flash->lock);
@@ -1015,7 +1127,6 @@ static int m25p_probe(struct spi_device *spi)
flash->mtd.flags = MTD_CAP_NORFLASH;
flash->mtd.size = info->sector_size * info->n_sectors;
flash->mtd._erase = m25p80_erase;
- flash->mtd._read = m25p80_read;
/* flash protection support for STmicro chips */
if (JEDEC_MFR(info->jedec_id) == CFI_MFR_ST) {
@@ -1067,6 +1178,28 @@ static int m25p_probe(struct spi_device *spi)
flash->program_opcode = OPCODE_PP;
+ flash->quad_read = false;
+ if (spi->mode && SPI_RX_QUAD)
+ flash->quad_read = true;
+
+ flash->command = kmalloc(MAX_CMD_SIZE + (flash->fast_read ? 1 :
+ (flash->quad_read ? 1 : 0)), GFP_KERNEL);
+ if (!flash->command) {
+ kfree(flash);
+ return -ENOMEM;
+ }
+
+ if (flash->quad_read) {
+ ret = quad_enable(flash);
+ if (ret) {
+ dev_err(&spi->dev,
+ "error enabling quad");
+ return -EINVAL;
+ }
+ flash->mtd._read = m25p80_quad_read;
+ } else
+ flash->mtd._read = m25p80_read;
+
if (info->addr_width)
flash->addr_width = info->addr_width;
else if (flash->mtd.size > 0x1000000) {
@@ -1074,9 +1207,9 @@ static int m25p_probe(struct spi_device *spi)
flash->addr_width = 4;
if (JEDEC_MFR(info->jedec_id) == CFI_MFR_AMD) {
/* Dedicated 4-byte command set */
- flash->read_opcode = flash->fast_read ?
- OPCODE_FAST_READ_4B :
- OPCODE_NORM_READ_4B;
+ flash->read_opcode = (flash->fast_read ?
+ OPCODE_FAST_READ_4B : (flash->quad_read ?
+ OPCODE_QUAD_READ_4B : OPCODE_NORM_READ_4B));
flash->program_opcode = OPCODE_PP_4B;
/* No small sector erase for 4-byte command set */
flash->erase_opcode = OPCODE_SE_4B;
--
1.7.1
^ permalink raw reply related [flat|nested] 11+ messages in thread* Re: [PATCHv2] drivers: mtd: devices: Add quad read support.
2013-09-26 10:32 [PATCHv2] drivers: mtd: devices: Add quad read support Sourav Poddar
@ 2013-09-26 11:00 ` David Woodhouse
2013-09-26 11:21 ` Sourav Poddar
2013-09-26 11:59 ` Mark Brown
2013-10-07 12:11 ` Sourav Poddar
1 sibling, 2 replies; 11+ messages in thread
From: David Woodhouse @ 2013-09-26 11:00 UTC (permalink / raw)
To: Sourav Poddar
Cc: artem.bityutskiy, balbi, b32955, broonie, linux-mtd,
computersforpeace
[-- Attachment #1: Type: text/plain, Size: 931 bytes --]
On Thu, 2013-09-26 at 16:02 +0530, Sourav Poddar wrote:
> Some flash also support quad read mode.
> Adding support for adding quad mode in m25p80.
>
> Signed-off-by: Sourav Poddar <sourav.poddar@ti.com>
This seems sane enough to me if Mark agrees that it's correct from the
SPI point of view.
Do we have a solution for the vf610-twr host controller, and is this
going to work for that too? Or are we still stuck on questions like "how
are we going to program the LUT to do what the request asks?" and "how
*does* the request actually hand the required information to the
controller?"
I've seen a bunch of "*this* is how you indicate dummy cycles", and
"*this* is how you request a quad-read transfer" type responses; have we
got all the way there yet?
--
David Woodhouse Open Source Technology Centre
David.Woodhouse@intel.com Intel Corporation
[-- Attachment #2: smime.p7s --]
[-- Type: application/x-pkcs7-signature, Size: 5745 bytes --]
^ permalink raw reply [flat|nested] 11+ messages in thread
* Re: [PATCHv2] drivers: mtd: devices: Add quad read support.
2013-09-26 11:00 ` David Woodhouse
@ 2013-09-26 11:21 ` Sourav Poddar
2013-09-26 11:31 ` David Woodhouse
2013-09-27 2:40 ` Huang Shijie
2013-09-26 11:59 ` Mark Brown
1 sibling, 2 replies; 11+ messages in thread
From: Sourav Poddar @ 2013-09-26 11:21 UTC (permalink / raw)
To: David Woodhouse
Cc: artem.bityutskiy, balbi, b32955, broonie, linux-mtd,
computersforpeace
Hi David,
On Thursday 26 September 2013 04:30 PM, David Woodhouse wrote:
> On Thu, 2013-09-26 at 16:02 +0530, Sourav Poddar wrote:
>> Some flash also support quad read mode.
>> Adding support for adding quad mode in m25p80.
>>
>> Signed-off-by: Sourav Poddar<sourav.poddar@ti.com>
> This seems sane enough to me if Mark agrees that it's correct from the
> SPI point of view.
>
> Do we have a solution for the vf610-twr host controller, and is this
> going to work for that too? Or are we still stuck on questions like "how
> are we going to program the LUT to do what the request asks?" and "how
> *does* the request actually hand the required information to the
> controller?"
>
If the pupose of LUT is to just set the dummy cycles, and vf610-twr
hardware state machine does not have have any other dependency
on LUT, this patch should work.
Yes, this patch also solves the issue of communicating the appropriate
request
to the handler through some spi transfer parameters already available in
spi.c.
As explained in one comment in my previous version,
If you see spi.c, "spi-rx-bus-width" property is already added. We will
set this
property in dts to 4 in case of quad read. Once this is set, spi->mode will
be set to SPI_RX_QUAD in spi.c. which can be used by mtd layer to decide
whether
its a quad read or not.
Then, we can use tx_nbits/rx_nbits property of spi_transfer to
communicate to the
controller whether the ongoing transfer is a quad/single read/write.
> I've seen a bunch of "*this* is how you indicate dummy cycles", and
> "*this* is how you request a quad-read transfer" type responses; have we
> got all the way there yet?
>
^ permalink raw reply [flat|nested] 11+ messages in thread
* Re: [PATCHv2] drivers: mtd: devices: Add quad read support.
2013-09-26 11:21 ` Sourav Poddar
@ 2013-09-26 11:31 ` David Woodhouse
2013-09-27 2:40 ` Huang Shijie
1 sibling, 0 replies; 11+ messages in thread
From: David Woodhouse @ 2013-09-26 11:31 UTC (permalink / raw)
To: Sourav Poddar
Cc: artem.bityutskiy, balbi, b32955, broonie, linux-mtd,
computersforpeace
[-- Attachment #1: Type: text/plain, Size: 641 bytes --]
On Thu, 2013-09-26 at 16:51 +0530, Sourav Poddar wrote:
> Yes, this patch also solves the issue of communicating the appropriate
> request to the handler through some spi transfer parameters already
> available in spi.c.
Great, thanks for confirming that.
So making vf610-twr conform to the Linux SPI API and do the right thing
according to the requests it receives is now Someone Else's Problem™ and
I look forward to never having to think about it again.
Have fun :)
--
David Woodhouse Open Source Technology Centre
David.Woodhouse@intel.com Intel Corporation
[-- Attachment #2: smime.p7s --]
[-- Type: application/x-pkcs7-signature, Size: 5745 bytes --]
^ permalink raw reply [flat|nested] 11+ messages in thread
* Re: [PATCHv2] drivers: mtd: devices: Add quad read support.
2013-09-26 11:21 ` Sourav Poddar
2013-09-26 11:31 ` David Woodhouse
@ 2013-09-27 2:40 ` Huang Shijie
2013-09-27 5:54 ` Sourav Poddar
1 sibling, 1 reply; 11+ messages in thread
From: Huang Shijie @ 2013-09-27 2:40 UTC (permalink / raw)
To: Sourav Poddar
Cc: artem.bityutskiy, balbi, broonie, linux-mtd, computersforpeace,
David Woodhouse
于 2013年09月26日 19:21, Sourav Poddar 写道:
> If the pupose of LUT is to just set the dummy cycles, and vf610-twr
> hardware state machine does not have have any other dependency
> on LUT, this patch should work.
Hi Sourav & David:
The key issue about the vf610-twr is that:
[0] Use the LUT makes the Quadspi driver more efficiency.
[1] the vf610-twr needs to know the SPI NOR commands for Page Program.
Why? because the driver can not change the size of write-buffer
from 256bytes to the 64byte(TXFIFO SIZE).
[2] the dummy and other things.
Mark said the Quadspi is not a SPI controller, instead it is a SPI NOR
controller, and Mark suggested me
to rewrite the m25p80.c for the Quadspi.
thanks
Huang Shijie
^ permalink raw reply [flat|nested] 11+ messages in thread* Re: [PATCHv2] drivers: mtd: devices: Add quad read support.
2013-09-27 2:40 ` Huang Shijie
@ 2013-09-27 5:54 ` Sourav Poddar
2013-09-27 6:16 ` Huang Shijie
0 siblings, 1 reply; 11+ messages in thread
From: Sourav Poddar @ 2013-09-27 5:54 UTC (permalink / raw)
To: Huang Shijie
Cc: artem.bityutskiy, balbi, broonie, linux-mtd, computersforpeace,
David Woodhouse
On Friday 27 September 2013 08:10 AM, Huang Shijie wrote:
> 于 2013年09月26日 19:21, Sourav Poddar 写道:
>> If the pupose of LUT is to just set the dummy cycles, and vf610-twr
>> hardware state machine does not have have any other dependency
>> on LUT, this patch should work.
> Hi Sourav & David:
>
> The key issue about the vf610-twr is that:
> [0] Use the LUT makes the Quadspi driver more efficiency.
> [1] the vf610-twr needs to know the SPI NOR commands for Page Program.
> Why? because the driver can not change the size of write-buffer
> from 256bytes to the 64byte(TXFIFO SIZE).
Not clear about this. But, you will anyway know what you are using from
the m25p80 side rite?
> [2] the dummy and other things.
>
Dummy stuffs can be handled from m25p80 side rite? fast read dummy cycle
support is already there. While,
$subject patch adds it for quad read.
> Mark said the Quadspi is not a SPI controller, instead it is a SPI NOR
> controller, and Mark suggested me
> to rewrite the m25p80.c for the Quadspi.
>
> thanks
> Huang Shijie
>
>
^ permalink raw reply [flat|nested] 11+ messages in thread
* Re: [PATCHv2] drivers: mtd: devices: Add quad read support.
2013-09-27 5:54 ` Sourav Poddar
@ 2013-09-27 6:16 ` Huang Shijie
2013-09-27 6:27 ` Sourav Poddar
0 siblings, 1 reply; 11+ messages in thread
From: Huang Shijie @ 2013-09-27 6:16 UTC (permalink / raw)
To: Sourav Poddar
Cc: artem.bityutskiy, balbi, broonie, linux-mtd, computersforpeace,
David Woodhouse
于 2013年09月27日 13:54, Sourav Poddar 写道:
> On Friday 27 September 2013 08:10 AM, Huang Shijie wrote:
>> 于 2013年09月26日 19:21, Sourav Poddar 写道:
>>> If the pupose of LUT is to just set the dummy cycles, and vf610-twr
>>> hardware state machine does not have have any other dependency
>>> on LUT, this patch should work.
>> Hi Sourav & David:
>>
>> The key issue about the vf610-twr is that:
>> [0] Use the LUT makes the Quadspi driver more efficiency.
>> [1] the vf610-twr needs to know the SPI NOR commands for Page
>> Program.
>> Why? because the driver can not change the size of
>> write-buffer from 256bytes to the 64byte(TXFIFO SIZE).
> Not clear about this. But, you will anyway know what you are using
> from the m25p80 side rite?
The TX FIFO is 64 bytes in the Vybrid, but the Page Program may writes
265 bytes per time.
If the TX FIFO is smaller then the size of Page Program, we have to
wait until the Write(64bytes) is finished.
If we do not wait, the write will not finished.
>> [2] the dummy and other things.
>>
> Dummy stuffs can be handled from m25p80 side rite? fast read dummy
> cycle support is already there. While,
> $subject patch adds it for quad read.
The m25p80 can only handle the 8bit dummy now, such as fast read and
QOR(0x6b).
But it can not handle the QIOR (0XEB, may needs 4bit dummy), and can not
handle the DDR QIOR(0XED, may
needs 6bit dummy).
thanks
Huang Shijie
^ permalink raw reply [flat|nested] 11+ messages in thread
* Re: [PATCHv2] drivers: mtd: devices: Add quad read support.
2013-09-27 6:16 ` Huang Shijie
@ 2013-09-27 6:27 ` Sourav Poddar
2013-09-27 7:05 ` Huang Shijie
0 siblings, 1 reply; 11+ messages in thread
From: Sourav Poddar @ 2013-09-27 6:27 UTC (permalink / raw)
To: Huang Shijie
Cc: artem.bityutskiy, balbi, broonie, linux-mtd, computersforpeace,
David Woodhouse
On Friday 27 September 2013 11:46 AM, Huang Shijie wrote:
> 于 2013年09月27日 13:54, Sourav Poddar 写道:
>> On Friday 27 September 2013 08:10 AM, Huang Shijie wrote:
>>> 于 2013年09月26日 19:21, Sourav Poddar 写道:
>>>> If the pupose of LUT is to just set the dummy cycles, and vf610-twr
>>>> hardware state machine does not have have any other dependency
>>>> on LUT, this patch should work.
>>> Hi Sourav & David:
>>>
>>> The key issue about the vf610-twr is that:
>>> [0] Use the LUT makes the Quadspi driver more efficiency.
>>> [1] the vf610-twr needs to know the SPI NOR commands for Page
>>> Program.
>>> Why? because the driver can not change the size of
>>> write-buffer from 256bytes to the 64byte(TXFIFO SIZE).
>> Not clear about this. But, you will anyway know what you are using
>> from the m25p80 side rite?
>
> The TX FIFO is 64 bytes in the Vybrid, but the Page Program may
> writes 265 bytes per time.
>
> If the TX FIFO is smaller then the size of Page Program, we have to
> wait until the Write(64bytes) is finished.
> If we do not wait, the write will not finished.
>
>
hmm..I think thats should be handle in your controller by checking
t->tx_buf and see what command is used.
>
>>> [2] the dummy and other things.
>>>
>> Dummy stuffs can be handled from m25p80 side rite? fast read dummy
>> cycle support is already there. While,
>> $subject patch adds it for quad read.
> The m25p80 can only handle the 8bit dummy now, such as fast read and
> QOR(0x6b).
>
> But it can not handle the QIOR (0XEB, may needs 4bit dummy), and can
> not handle the DDR QIOR(0XED, may
> needs 6bit dummy).
>
Correct, as I explained in one of my comment on v1, that the creating of
a quad api is justified for this reason itself, since
there are other quad commands wth different dummy cycle requirements. We
can build on top of $subject patch and try
to add support for other quad commands also. ?
> thanks
> Huang Shijie
>
^ permalink raw reply [flat|nested] 11+ messages in thread
* Re: [PATCHv2] drivers: mtd: devices: Add quad read support.
2013-09-27 6:27 ` Sourav Poddar
@ 2013-09-27 7:05 ` Huang Shijie
0 siblings, 0 replies; 11+ messages in thread
From: Huang Shijie @ 2013-09-27 7:05 UTC (permalink / raw)
To: Sourav Poddar
Cc: artem.bityutskiy, balbi, broonie, linux-mtd, computersforpeace,
David Woodhouse
于 2013年09月27日 14:27, Sourav Poddar 写道:
> hmm..I think thats should be handle in your controller by checking
> t->tx_buf and see what command is used.
Just as Mark ever said:
Parsing out the command makes the QuadSPI driver looks like a SPI
NOR driver, not a SPI driver.
And that's why i need to rewrite the m25p80 code.
Btw: i do not object your patch, i hope it can be merged as soon as
possible.
thanks
Huang Shijie
^ permalink raw reply [flat|nested] 11+ messages in thread
* Re: [PATCHv2] drivers: mtd: devices: Add quad read support.
2013-09-26 11:00 ` David Woodhouse
2013-09-26 11:21 ` Sourav Poddar
@ 2013-09-26 11:59 ` Mark Brown
1 sibling, 0 replies; 11+ messages in thread
From: Mark Brown @ 2013-09-26 11:59 UTC (permalink / raw)
To: David Woodhouse
Cc: artem.bityutskiy, balbi, b32955, linux-mtd, Sourav Poddar,
computersforpeace
[-- Attachment #1: Type: text/plain, Size: 631 bytes --]
On Thu, Sep 26, 2013 at 12:00:43PM +0100, David Woodhouse wrote:
> This seems sane enough to me if Mark agrees that it's correct from the
> SPI point of view.
I didn't really look at the patch but since it doesn't involve changes
to the SPI API providing it does the right thing it should be fine.
> I've seen a bunch of "*this* is how you indicate dummy cycles", and
> "*this* is how you request a quad-read transfer" type responses; have we
> got all the way there yet?
Nobody added an API for dummy cycles yet but it's fairly obvious how to
add them if someone wants to do that. The quad read stuff is in
mainline already.
[-- Attachment #2: Digital signature --]
[-- Type: application/pgp-signature, Size: 836 bytes --]
^ permalink raw reply [flat|nested] 11+ messages in thread
* Re: [PATCHv2] drivers: mtd: devices: Add quad read support.
2013-09-26 10:32 [PATCHv2] drivers: mtd: devices: Add quad read support Sourav Poddar
2013-09-26 11:00 ` David Woodhouse
@ 2013-10-07 12:11 ` Sourav Poddar
1 sibling, 0 replies; 11+ messages in thread
From: Sourav Poddar @ 2013-10-07 12:11 UTC (permalink / raw)
To: b32955
Cc: artem.bityutskiy, balbi, broonie, linux-mtd, Sourav Poddar,
computersforpeace, dwmw2
Hi Brian,
On Thursday 26 September 2013 04:02 PM, Sourav Poddar wrote:
> Some flash also support quad read mode.
> Adding support for adding quad mode in m25p80.
>
> Signed-off-by: Sourav Poddar<sourav.poddar@ti.com>
> ---
> v1->v2:
> - Make the code more modular
> - put proper error checks
> drivers/mtd/devices/m25p80.c | 155 +++++++++++++++++++++++++++++++++++++++---
> 1 files changed, 144 insertions(+), 11 deletions(-)
>
> diff --git a/drivers/mtd/devices/m25p80.c b/drivers/mtd/devices/m25p80.c
> index 26b14f9..3c8a794 100644
> --- a/drivers/mtd/devices/m25p80.c
> +++ b/drivers/mtd/devices/m25p80.c
> @@ -41,6 +41,7 @@
> #define OPCODE_WRSR 0x01 /* Write status register 1 byte */
> #define OPCODE_NORM_READ 0x03 /* Read data bytes (low frequency) */
> #define OPCODE_FAST_READ 0x0b /* Read data bytes (high frequency) */
> +#define OPCODE_QUAD_READ 0x6b /* QUAD READ */
> #define OPCODE_PP 0x02 /* Page program (up to 256 bytes) */
> #define OPCODE_BE_4K 0x20 /* Erase 4KiB block */
> #define OPCODE_BE_4K_PMC 0xd7 /* Erase 4KiB block on PMC chips */
> @@ -48,10 +49,12 @@
> #define OPCODE_CHIP_ERASE 0xc7 /* Erase whole flash chip */
> #define OPCODE_SE 0xd8 /* Sector erase (usually 64KiB) */
> #define OPCODE_RDID 0x9f /* Read JEDEC ID */
> +#define OPCODE_RDCR 0x35 /* Read configuration register */
>
> /* 4-byte address opcodes - used on Spansion and some Macronix flashes. */
> #define OPCODE_NORM_READ_4B 0x13 /* Read data bytes (low frequency) */
> #define OPCODE_FAST_READ_4B 0x0c /* Read data bytes (high frequency) */
> +#define OPCODE_QUAD_READ_4B 0x6c /* Read data bytes */
> #define OPCODE_PP_4B 0x12 /* Page program (up to 256 bytes) */
> #define OPCODE_SE_4B 0xdc /* Sector erase (usually 64KiB) */
>
> @@ -76,6 +79,9 @@
> #define SR_BP2 0x10 /* Block protect 2 */
> #define SR_SRWD 0x80 /* SR write protect */
>
> +/* Configuration Register bits. */
> +#define QUAD_CR_EN 0x2 /* Quad I/O */
> +
> /* Define max times to check status register before we give up. */
> #define MAX_READY_WAIT_JIFFIES (40 * HZ) /* M25P16 specs 40s max chip erase */
> #define MAX_CMD_SIZE 5
> @@ -95,6 +101,7 @@ struct m25p {
> u8 program_opcode;
> u8 *command;
> bool fast_read;
> + bool quad_read;
> };
>
> static inline struct m25p *mtd_to_m25p(struct mtd_info *mtd)
> @@ -163,6 +170,25 @@ static inline int write_disable(struct m25p *flash)
> return spi_write_then_read(flash->spi,&code, 1, NULL, 0);
> }
>
> +/* Read the configuration register, returning its value in the location
> + * Return the configuration register value.
> + * Returns negative if error occurred.
> +*/
> +static int read_cr(struct m25p *flash)
> +{
> + u8 code = OPCODE_RDCR;
> + int ret;
> + u8 val;
> +
> + ret = spi_write_then_read(flash->spi,&code, 1,&val, 1);
> + if (ret< 0) {
> + dev_err(&flash->spi->dev, "error %d reading CR\n", ret);
> + return ret;
> + }
> +
> + return val;
> +}
> +
> /*
> * Enable/disable 4-byte addressing mode.
> */
> @@ -336,6 +362,97 @@ static int m25p80_erase(struct mtd_info *mtd, struct erase_info *instr)
> return 0;
> }
>
> +/* Write status register and configuration register with 2 bytes
> +* The first byte will be written to the status register, while the second byte
> +* will be written to the configuration register.
> +* Returns negative if error occurred.
> +*/
> +static int write_sr_cr(struct m25p *flash, u16 val)
> +{
> + flash->command[0] = OPCODE_WRSR;
> + flash->command[1] = val& 0xff;
> + flash->command[2] = (val>> 8);
> +
> + return spi_write(flash->spi, flash->command, 3);
> +}
> +
> +static int quad_enable(struct m25p *flash)
> +{
> + int ret;
> + int quad_en = QUAD_CR_EN<< 8;
> +
> + write_enable(flash);
> +
> + ret = write_sr_cr(flash, quad_en);
> + if (ret< 0) {
> + dev_err(&flash->spi->dev,
> + "error while writing configuration register");
> + return -EINVAL;
> + }
> +
> + /* read back and check it */
> + ret = read_cr(flash);
> + if (!(ret> 0&& (ret& QUAD_CR_EN))) {
> + dev_err(&flash->spi->dev,
> + "Quad bit not set");
> + return -EINVAL;
> + }
> +
> + return 0;
> +}
> +
> +static int m25p80_quad_read(struct mtd_info *mtd, loff_t from, size_t len,
> + size_t *retlen, u_char *buf)
> +{
> + struct m25p *flash = mtd_to_m25p(mtd);
> + struct spi_transfer t[2];
> + struct spi_message m;
> + uint8_t opcode;
> +
> + pr_debug("%s: %s from 0x%08x, len %zd\n", dev_name(&flash->spi->dev),
> + __func__, (u32)from, len);
> +
> + spi_message_init(&m);
> + memset(t, 0, (sizeof(t)));
> +
> + t[0].tx_buf = flash->command;
> + t[0].len = m25p_cmdsz(flash) + (flash->quad_read ? 1 : 0);
> + spi_message_add_tail(&t[0],&m);
> +
> + t[1].rx_buf = buf;
> + t[1].len = len;
> + t[1].rx_nbits = SPI_NBITS_QUAD;
> + spi_message_add_tail(&t[1],&m);
> +
> + mutex_lock(&flash->lock);
> +
> + /* Wait till previous write/erase is done. */
> + if (wait_till_ready(flash)) {
> + /* REVISIT status return?? */
> + mutex_unlock(&flash->lock);
> + return 1;
> + }
> +
> + /* FIXME switch to OPCODE_QUAD_READ. It's required for higher
> + * clocks; and at this writing, every chip this driver handles
> + * supports that opcode.
> + */
> +
> + /* Set up the write data buffer. */
> + opcode = flash->read_opcode;
> + flash->command[0] = opcode;
> + m25p_addr2cmd(flash, from, flash->command);
> +
> + spi_sync(flash->spi,&m);
> +
> + *retlen = m.actual_length - m25p_cmdsz(flash) -
> + (flash->quad_read ? 1 : 0);
> +
> + mutex_unlock(&flash->lock);
> +
> + return 0;
> +}
> +
> /*
> * Read an address range from the flash chip. The address range
> * may be any size provided it is within the physical boundaries.
> @@ -928,6 +1045,7 @@ static int m25p_probe(struct spi_device *spi)
> unsigned i;
> struct mtd_part_parser_data ppdata;
> struct device_node __maybe_unused *np = spi->dev.of_node;
> + int ret;
>
> #ifdef CONFIG_MTD_OF_PARTS
> if (!of_device_is_available(np))
> @@ -979,15 +1097,9 @@ static int m25p_probe(struct spi_device *spi)
> }
> }
>
> - flash = kzalloc(sizeof *flash, GFP_KERNEL);
> + flash = devm_kzalloc(&spi->dev, sizeof(*flash), GFP_KERNEL);
> if (!flash)
> return -ENOMEM;
> - flash->command = kmalloc(MAX_CMD_SIZE + (flash->fast_read ? 1 : 0),
> - GFP_KERNEL);
> - if (!flash->command) {
> - kfree(flash);
> - return -ENOMEM;
> - }
>
> flash->spi = spi;
> mutex_init(&flash->lock);
> @@ -1015,7 +1127,6 @@ static int m25p_probe(struct spi_device *spi)
> flash->mtd.flags = MTD_CAP_NORFLASH;
> flash->mtd.size = info->sector_size * info->n_sectors;
> flash->mtd._erase = m25p80_erase;
> - flash->mtd._read = m25p80_read;
>
> /* flash protection support for STmicro chips */
> if (JEDEC_MFR(info->jedec_id) == CFI_MFR_ST) {
> @@ -1067,6 +1178,28 @@ static int m25p_probe(struct spi_device *spi)
>
> flash->program_opcode = OPCODE_PP;
>
> + flash->quad_read = false;
> + if (spi->mode&& SPI_RX_QUAD)
> + flash->quad_read = true;
> +
> + flash->command = kmalloc(MAX_CMD_SIZE + (flash->fast_read ? 1 :
> + (flash->quad_read ? 1 : 0)), GFP_KERNEL);
> + if (!flash->command) {
> + kfree(flash);
> + return -ENOMEM;
> + }
> +
> + if (flash->quad_read) {
> + ret = quad_enable(flash);
> + if (ret) {
> + dev_err(&spi->dev,
> + "error enabling quad");
> + return -EINVAL;
> + }
> + flash->mtd._read = m25p80_quad_read;
> + } else
> + flash->mtd._read = m25p80_read;
> +
> if (info->addr_width)
> flash->addr_width = info->addr_width;
> else if (flash->mtd.size> 0x1000000) {
> @@ -1074,9 +1207,9 @@ static int m25p_probe(struct spi_device *spi)
> flash->addr_width = 4;
> if (JEDEC_MFR(info->jedec_id) == CFI_MFR_AMD) {
> /* Dedicated 4-byte command set */
> - flash->read_opcode = flash->fast_read ?
> - OPCODE_FAST_READ_4B :
> - OPCODE_NORM_READ_4B;
> + flash->read_opcode = (flash->fast_read ?
> + OPCODE_FAST_READ_4B : (flash->quad_read ?
> + OPCODE_QUAD_READ_4B : OPCODE_NORM_READ_4B));
> flash->program_opcode = OPCODE_PP_4B;
> /* No small sector erase for 4-byte command set */
> flash->erase_opcode = OPCODE_SE_4B;
Gentle Ping on this..
^ permalink raw reply [flat|nested] 11+ messages in thread
end of thread, other threads:[~2013-10-07 12:12 UTC | newest]
Thread overview: 11+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2013-09-26 10:32 [PATCHv2] drivers: mtd: devices: Add quad read support Sourav Poddar
2013-09-26 11:00 ` David Woodhouse
2013-09-26 11:21 ` Sourav Poddar
2013-09-26 11:31 ` David Woodhouse
2013-09-27 2:40 ` Huang Shijie
2013-09-27 5:54 ` Sourav Poddar
2013-09-27 6:16 ` Huang Shijie
2013-09-27 6:27 ` Sourav Poddar
2013-09-27 7:05 ` Huang Shijie
2013-09-26 11:59 ` Mark Brown
2013-10-07 12:11 ` Sourav Poddar
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).