mtd: brcmnand: Check flash write protect pin status
Subsystems (2)
PATCH 1/1 mtd: brcmnand: Check flash write protect pin status
With v6.x and v7.x controller lets the driver to enable disable #WP pin. So to be safe let driver send flash status cmd whenever the #WP pin status is being changed and makes sure the controller and the the flash are both ready to accept new cmds by verifying the WP protect/unprotect bit is set correctly in the flash status byte. Modify enable/disable #WP register only when the nand controller is not ready.
--- drivers/mtd/nand/brcmnand/brcmnand.c | 75 +++++++++++++++++++++++++++++++----- 1 file changed, 65 insertions(+), 10 deletions(-)
drivers/mtd/nand/brcmnand/brcmnand.c +65 -10
@@ -101,6 +101,9 @@ struct brcm_nand_dma_desc {#define BRCMNAND_MIN_BLOCKSIZE (8 * 1024)#define BRCMNAND_MIN_DEVSIZE (4ULL * 1024 * 1024) +#define FLASH_RDY (NAND_STATUS_READY) +#define NAND_CTRL_RDY (INTFC_CTLR_READY | INTFC_FLASH_READY) +/* Controller feature flags */ enum {BRCMNAND_HAS_1K_SECTORS =BIT (0 ),
@@ -765,13 +768,62 @@ enum { CS_SELECT_AUTO_DEVICE_ID_CFG = BIT(30), }; -static inline void brcmnand_set_wp (struct brcmnand_controller *ctrl,bool en) +static int bcmnand_ctrl_busy_poll (struct brcmnand_controller *ctrl,u32 mask) +{ +unsigned long timeout = jiffies +msecs_to_jiffies (200 ); + +if (!mask) + mask =INTFC_CTLR_READY ; + +while ((brcmnand_read_reg (ctrl,BRCMNAND_INTFC_STATUS ) & mask) != + mask) { +if (time_after (jiffies, timeout)) { +dev_warn (ctrl->dev,"timeout on ctrl_ready\n" ); +return -ETIMEDOUT ; + } +cpu_relax (); + } +return 0 ; +} + +static inline void brcmnand_set_wp_reg (struct brcmnand_controller *ctrl,int en) {u32 val = en ?CS_SELECT_NAND_WP :0 ;brcmnand_rmw_reg (ctrl,BRCMNAND_CS_SELECT ,CS_SELECT_NAND_WP ,0 , val); } +static void brcmnand_set_wp (struct brcmnand_host *host,int en) +{ +struct brcmnand_controller *ctrl = host->ctrl; +struct mtd_info *mtd = &host->mtd; +struct nand_chip *chip = mtd->priv; +u32 sts_reg; +bool is_wp; + +/* +* make sure ctrl/flash ready before and after +* changing state of WP PIN +*/ +bcmnand_ctrl_busy_poll (ctrl,NAND_CTRL_RDY |FLASH_RDY ); +brcmnand_set_wp_reg (ctrl, en); + chip->cmdfunc (mtd,NAND_CMD_STATUS ,-1 ,-1 ); +bcmnand_ctrl_busy_poll (ctrl,NAND_CTRL_RDY |FLASH_RDY ); + sts_reg =brcmnand_read_reg (ctrl,BRCMNAND_INTFC_STATUS ); +/* NAND_STATUS_WP 0x80 = not protected, 0x00 = protected */ + is_wp = (sts_reg &NAND_STATUS_WP ) ? false : true; + +if (is_wp != en) { +u32 nand_wp =brcmnand_read_reg (ctrl,BRCMNAND_CS_SELECT ); + + nand_wp &=CS_SELECT_NAND_WP ; +dev_err_ratelimited (&host->pdev->dev, +"#WP %s sts:0x%x expected %s NAND_WP 0x%x\n" , + is_wp ?"On" :"Off" , sts_reg &0xff , + en ?"On" :"Off" , nand_wp ?1 :0 ); + } +} +/*********************************************************************** * Flash DMA ***********************************************************************/
@@ -1029,7 +1081,7 @@ static void brcmnand_wp(struct mtd_info *mtd, int wp)dev_dbg (ctrl->dev,"WP %s\n" , wp ?"on" :"off" ); old_wp = wp; } -brcmnand_set_wp (ctrl, wp); +brcmnand_set_wp (host, wp); } }
@@ -1158,15 +1210,18 @@ static void brcmnand_send_cmd(struct brcmnand_host *host, int cmd) {struct brcmnand_controller *ctrl = host->ctrl;u32 intfc; +u32 mask =NAND_CTRL_RDY ;dev_dbg (ctrl->dev,"send native cmd %d addr_lo 0x%x\n" , cmd,brcmnand_read_reg (ctrl,BRCMNAND_CMD_ADDRESS ));BUG_ON (ctrl->cmd_pending !=0 ); ctrl->cmd_pending = cmd; +bcmnand_ctrl_busy_poll (ctrl, mask); intfc =brcmnand_read_reg (ctrl,BRCMNAND_INTFC_STATUS );WARN_ON (!(intfc &INTFC_CTLR_READY )); +mb ();/* flush previous writes */ brcmnand_write_reg (ctrl,BRCMNAND_CMD_START , cmd <<brcmnand_cmd_shift (ctrl));
@@ -2462,14 +2517,6 @@ int brcmnand_probe(struct platform_device *pdev, struct brcmnand_soc *soc)/* Disable XOR addressing */ brcmnand_rmw_reg (ctrl,BRCMNAND_CS_XOR ,0xff ,0 ,0 ); -if (ctrl->features &BRCMNAND_HAS_WP ) { -/* Permanently disable write protection */ -if (wp_on ==2 ) -brcmnand_set_wp (ctrl, false); - }else { - wp_on =0 ; - } -/* IRQ */ ctrl->irq =platform_get_irq (pdev,0 );if ((int )ctrl->irq <0 ) {
@@ -2522,6 +2569,14 @@ int brcmnand_probe(struct platform_device *pdev, struct brcmnand_soc *soc) }list_add_tail (&host->node, &ctrl->host_list); + +if (ctrl->features &BRCMNAND_HAS_WP ) { +/* Permanently disable write protection */ +if (wp_on ==2 ) +brcmnand_set_wp (host, false); + }else { + wp_on =0 ; + } } }
Signature · 1 line
1.9.1
Hi Kamal,
Can you Cc the MTD and NAND maintainers when you send NAND/MTD patches?
Also, for the subject prefix, I'd prefer 'mtd: nand: brcm:'.
Quoted 6 lines · On Tue, 14 Feb 2017 11:23:44 -0500 Kamal Dasu <[email protected]> wrote:
With v6.x and v7.x controller lets the driver to enable disable #WP pin. So to be safe let driver send flash status cmd whenever the #WP pin status is being changed and makes sure the controller and the the flash are both ready to accept new cmds by verifying the WP protect/unprotect bit is set correctly in the flash status byte. Modify enable/disable #WP register only when the nand controller is not ready.
You mean 'is ready' here, right?
I still have a hard time understanding what the problem is with this commit message. Can you try to clarify that?
Quoted 21 lines
Signed-off-by Kamal Dasu <[email protected]>--- drivers/mtd/nand/brcmnand/brcmnand.c | 75 +++++++++++++++++++++++++++++++----- 1 file changed, 65 insertions(+), 10 deletions(-)drivers/mtd/nand/brcmnand/brcmnand.c +3
-0@@ -101,6 +101,9 @@ struct brcm_nand_dma_desc {#define BRCMNAND_MIN_BLOCKSIZE (8 * 1024)#define BRCMNAND_MIN_DEVSIZE (4ULL * 1024 * 1024) +#define FLASH_RDY (NAND_STATUS_READY) +#define NAND_CTRL_RDY (INTFC_CTLR_READY | INTFC_FLASH_READY) +/* Controller feature flags */ enum {BRCMNAND_HAS_1K_SECTORS =BIT (0 ),
drivers/mtd/nand/brcmnand/brcmnand.c enum { · line 776
Quoted 10 lines
drivers/mtd/nand/brcmnand/brcmnand.c +6
-1@@ -765,13 +768,62 @@ enum { CS_SELECT_AUTO_DEVICE_ID_CFG = BIT(30), }; -static inline void brcmnand_set_wp (struct brcmnand_controller *ctrl,bool en) +static int bcmnand_ctrl_busy_poll (struct brcmnand_controller *ctrl,u32 mask) +{ +unsigned long timeout = jiffies +msecs_to_jiffies (200 ); + +if (!mask) + mask =INTFC_CTLR_READY ;
Do you really need this check? All users of bcmnand_ctrl_busy_poll() are passing mask != 0.
Quoted 37 lines
drivers/mtd/nand/brcmnand/brcmnand.c +31
-0+ +while ((brcmnand_read_reg (ctrl,BRCMNAND_INTFC_STATUS ) & mask) != + mask) { +if (time_after (jiffies, timeout)) { +dev_warn (ctrl->dev,"timeout on ctrl_ready\n" ); +return -ETIMEDOUT ; + } +cpu_relax (); + } +return 0 ; +} + +static inline void brcmnand_set_wp_reg (struct brcmnand_controller *ctrl,int en) {u32 val = en ?CS_SELECT_NAND_WP :0 ;brcmnand_rmw_reg (ctrl,BRCMNAND_CS_SELECT ,CS_SELECT_NAND_WP ,0 , val); } +static void brcmnand_set_wp (struct brcmnand_host *host,int en) +{ +struct brcmnand_controller *ctrl = host->ctrl; +struct mtd_info *mtd = &host->mtd; +struct nand_chip *chip = mtd->priv; +u32 sts_reg; +bool is_wp; + +/* +* make sure ctrl/flash ready before and after +* changing state of WP PIN +*/ +bcmnand_ctrl_busy_poll (ctrl,NAND_CTRL_RDY |FLASH_RDY ); +brcmnand_set_wp_reg (ctrl, en); + chip->cmdfunc (mtd,NAND_CMD_STATUS ,-1 ,-1 ); +bcmnand_ctrl_busy_poll (ctrl,NAND_CTRL_RDY |FLASH_RDY ); + sts_reg =brcmnand_read_reg (ctrl,BRCMNAND_INTFC_STATUS ); +/* NAND_STATUS_WP 0x80 = not protected, 0x00 = protected */
drivers/mtd/nand/brcmnand/brcmnand.c enum { · line 823
Quoted 10 lines
drivers/mtd/nand/brcmnand/brcmnand.c +10
-0+ is_wp = (sts_reg &NAND_STATUS_WP ) ? false : true; + +if (is_wp != en) { +u32 nand_wp =brcmnand_read_reg (ctrl,BRCMNAND_CS_SELECT ); + + nand_wp &=CS_SELECT_NAND_WP ; +dev_err_ratelimited (&host->pdev->dev, +"#WP %s sts:0x%x expected %s NAND_WP 0x%x\n" , + is_wp ?"On" :"Off" , sts_reg &0xff , + en ?"On" :"Off" , nand_wp ?1 :0 );
Hm, so this function can fail. Shouldn't you make it return a return code instead of ignoring failures? This way, you can return an error from the probe.
Quoted 16 lines
drivers/mtd/nand/brcmnand/brcmnand.c +4
-1+ } +} +/*********************************************************************** * Flash DMA ***********************************************************************/ @@ -1029,7 +1081,7 @@ static void brcmnand_wp(struct mtd_info *mtd, int wp)dev_dbg (ctrl->dev,"WP %s\n" , wp ?"on" :"off" ); old_wp = wp; } -brcmnand_set_wp (ctrl, wp); +brcmnand_set_wp (host, wp); } }
drivers/mtd/nand/brcmnand/brcmnand.c static void brcmnand_send_cmd(struct brcmnand_host *host, int cmd) · line 1213
Quoted 4 lines
drivers/mtd/nand/brcmnand/brcmnand.c +1
-0@@ -1158,15 +1210,18 @@ static void brcmnand_send_cmd(struct brcmnand_host *host, int cmd) {struct brcmnand_controller *ctrl = host->ctrl;u32 intfc; +u32 mask =NAND_CTRL_RDY ;
No need for this local variable...
drivers/mtd/nand/brcmnand/brcmnand.c static void brcmnand_send_cmd(struct brcmnand_host *host, int cmd) · line 1220
Quoted 7 lines
drivers/mtd/nand/brcmnand/brcmnand.c +1
-0dev_dbg (ctrl->dev,"send native cmd %d addr_lo 0x%x\n" , cmd,brcmnand_read_reg (ctrl,BRCMNAND_CMD_ADDRESS ));BUG_ON (ctrl->cmd_pending !=0 ); ctrl->cmd_pending = cmd; +bcmnand_ctrl_busy_poll (ctrl, mask);
... just call
bcmnand_ctrl_busy_poll(ctrl, NAND_CTRL_RDY);
here.
drivers/mtd/nand/brcmnand/brcmnand.c static void brcmnand_send_cmd(struct brcmnand_host *host, int cmd) · line 1224
Quoted 4 lines
drivers/mtd/nand/brcmnand/brcmnand.c +1
-0intfc =brcmnand_read_reg (ctrl,BRCMNAND_INTFC_STATUS );WARN_ON (!(intfc &INTFC_CTLR_READY )); +
Drop this extra empty line.
Quoted 20 lines
drivers/mtd/nand/brcmnand/brcmnand.c +0
-8mb ();/* flush previous writes */ brcmnand_write_reg (ctrl,BRCMNAND_CMD_START , cmd <<brcmnand_cmd_shift (ctrl));@@ -2462,14 +2517,6 @@ int brcmnand_probe(struct platform_device *pdev, struct brcmnand_soc *soc)/* Disable XOR addressing */ brcmnand_rmw_reg (ctrl,BRCMNAND_CS_XOR ,0xff ,0 ,0 ); -if (ctrl->features &BRCMNAND_HAS_WP ) { -/* Permanently disable write protection */ -if (wp_on ==2 ) -brcmnand_set_wp (ctrl, false); - }else { - wp_on =0 ; - } -/* IRQ */ ctrl->irq =platform_get_irq (pdev,0 );if ((int )ctrl->irq <0 ) {@@ -2522,6 +2569,14 @@ int brcmnand_probe(struct platform_device *pdev, struct brcmnand_soc *soc) }
drivers/mtd/nand/brcmnand/brcmnand.c int brcmnand_probe(struct platform_device *pdev, struct brcmnand_soc *soc) · line 2579
Quoted 10 lines
drivers/mtd/nand/brcmnand/brcmnand.c +8
-0list_add_tail (&host->node, &ctrl->host_list); + +if (ctrl->features &BRCMNAND_HAS_WP ) { +/* Permanently disable write protection */ +if (wp_on ==2 ) +brcmnand_set_wp (host, false); + }else { + wp_on =0 ; + }
Hm, this is not really related to the change you describe in your commit message. This should probably go in a separate commit.
Quoted 3 lines
drivers/mtd/nand/brcmnand/brcmnand.c +0
-0} }
Boris,
Quoted 6 lines · Boris Brezillon
Hi Kamal,
Can you Cc the MTD and NAND maintainers when you send NAND/MTD patches?
Also, for the subject prefix, I'd prefer 'mtd: nand: brcm:'.
Ok
Quoted 11 lines
Quoted 6 lines · On Tue, 14 Feb 2017 11:23:44 -0500 Kamal Dasu <[email protected]> wrote:
With v6.x and v7.x controller lets the driver to enable disable #WP pin. So to be safe let driver send flash status cmd whenever the #WP pin status is being changed and makes sure the controller and the the flash are both ready to accept new cmds by verifying the WP protect/unprotect bit is set correctly in the flash status byte. Modify enable/disable #WP register only when the nand controller is not ready.
You mean 'is ready' here, right?
Yes, will fix this.
Quoted 4 lines
I still have a hard time understanding what the problem is with this commit message. Can you try to clarify that?
Software assumed that setting/resetting the NAND_WP controller
register would assert/de-assert the #WP pin instantaneously from the flash parts perspective, and was proceeding to erase/program. Nand driver was not verifying flash status byte for WP. In rigorous testing we found this was causing rare data corruptions with erase and/or subsequent programming. So to make sure the flash part is ready to accept erase/program commands was to send status read command and read back the WP bit status from the flash whenever we change the pin state. I will clarify this in the commit message as well.
Quoted 24 lines
Quoted 24 lines
Signed-off-by Kamal Dasu <[email protected]>--- drivers/mtd/nand/brcmnand/brcmnand.c | 75 +++++++++++++++++++++++++++++++----- 1 file changed, 65 insertions(+), 10 deletions(-)drivers/mtd/nand/brcmnand/brcmnand.c +3
-0@@ -101,6 +101,9 @@ struct brcm_nand_dma_desc {#define BRCMNAND_MIN_BLOCKSIZE (8 * 1024)#define BRCMNAND_MIN_DEVSIZE (4ULL * 1024 * 1024) +#define FLASH_RDY (NAND_STATUS_READY) +#define NAND_CTRL_RDY (INTFC_CTLR_READY | INTFC_FLASH_READY) +/* Controller feature flags */ enum {BRCMNAND_HAS_1K_SECTORS =BIT (0 ),@@ -765,13 +768,62 @@ enum { CS_SELECT_AUTO_DEVICE_ID_CFG = BIT(30), };
Quoted 10 lines
drivers/mtd/nand/brcmnand/brcmnand.c enum { · line 776
Quoted 7 lines
drivers/mtd/nand/brcmnand/brcmnand.c +6
-1-static inline void brcmnand_set_wp (struct brcmnand_controller *ctrl,bool en) +static int bcmnand_ctrl_busy_poll (struct brcmnand_controller *ctrl,u32 mask) +{ +unsigned long timeout = jiffies +msecs_to_jiffies (200 ); + +if (!mask) + mask =INTFC_CTLR_READY ;Do you really need this check? All users of
bcmnand_ctrl_busy_poll()are passing mask != 0.
Will remove this check.
Quoted 43 lines
Quoted 43 lines
drivers/mtd/nand/brcmnand/brcmnand.c +37
-0+ +while ((brcmnand_read_reg (ctrl,BRCMNAND_INTFC_STATUS ) & mask) != + mask) { +if (time_after (jiffies, timeout)) { +dev_warn (ctrl->dev,"timeout on ctrl_ready\n" ); +return -ETIMEDOUT ; + } +cpu_relax (); + } +return 0 ; +} + +static inline void brcmnand_set_wp_reg (struct brcmnand_controller *ctrl,int en) {u32 val = en ?CS_SELECT_NAND_WP :0 ;brcmnand_rmw_reg (ctrl,BRCMNAND_CS_SELECT ,CS_SELECT_NAND_WP ,0 , val); } +static void brcmnand_set_wp (struct brcmnand_host *host,int en) +{ +struct brcmnand_controller *ctrl = host->ctrl; +struct mtd_info *mtd = &host->mtd; +struct nand_chip *chip = mtd->priv; +u32 sts_reg; +bool is_wp; + +/* +* make sure ctrl/flash ready before and after +* changing state of WP PIN +*/ +bcmnand_ctrl_busy_poll (ctrl,NAND_CTRL_RDY |FLASH_RDY ); +brcmnand_set_wp_reg (ctrl, en); + chip->cmdfunc (mtd,NAND_CMD_STATUS ,-1 ,-1 ); +bcmnand_ctrl_busy_poll (ctrl,NAND_CTRL_RDY |FLASH_RDY ); + sts_reg =brcmnand_read_reg (ctrl,BRCMNAND_INTFC_STATUS ); +/* NAND_STATUS_WP 0x80 = not protected, 0x00 = protected */ + is_wp = (sts_reg &NAND_STATUS_WP ) ? false : true; + +if (is_wp != en) { +u32 nand_wp =brcmnand_read_reg (ctrl,BRCMNAND_CS_SELECT ); + + nand_wp &=CS_SELECT_NAND_WP ;
Quoted 9 lines
drivers/mtd/nand/brcmnand/brcmnand.c enum { · line 823
Quoted 4 lines
drivers/mtd/nand/brcmnand/brcmnand.c +4
-0+dev_err_ratelimited (&host->pdev->dev, +"#WP %s sts:0x%x expected %s NAND_WP 0x%x\n" , + is_wp ?"On" :"Off" , sts_reg &0xff , + en ?"On" :"Off" , nand_wp ?1 :0 );Hm, so this function can fail. Shouldn't you make it return a return code instead of ignoring failures? This way, you can return an error from the probe.
Should not happen, but can return err though.
Quoted 15 lines
Quoted 15 lines
drivers/mtd/nand/brcmnand/brcmnand.c +4
-1+ } +} +/*********************************************************************** * Flash DMA ***********************************************************************/ @@ -1029,7 +1081,7 @@ static void brcmnand_wp(struct mtd_info *mtd, int wp)dev_dbg (ctrl->dev,"WP %s\n" , wp ?"on" :"off" ); old_wp = wp; } -brcmnand_set_wp (ctrl, wp); +brcmnand_set_wp (host, wp); } }
Quoted 7 lines
drivers/mtd/nand/brcmnand/brcmnand.c static void brcmnand_send_cmd(struct brcmnand_host *host, int cmd) · line 1213
Quoted 5 lines
drivers/mtd/nand/brcmnand/brcmnand.c +1
-0@@ -1158,15 +1210,18 @@ static void brcmnand_send_cmd(struct brcmnand_host *host, int cmd) {struct brcmnand_controller *ctrl = host->ctrl;u32 intfc; +u32 mask =NAND_CTRL_RDY ;No need for this local variable...
Will fix this.
Quoted 13 lines
drivers/mtd/nand/brcmnand/brcmnand.c static void brcmnand_send_cmd(struct brcmnand_host *host, int cmd) · line 1220
Quoted 8 lines
drivers/mtd/nand/brcmnand/brcmnand.c +1
-0dev_dbg (ctrl->dev,"send native cmd %d addr_lo 0x%x\n" , cmd,brcmnand_read_reg (ctrl,BRCMNAND_CMD_ADDRESS ));BUG_ON (ctrl->cmd_pending !=0 ); ctrl->cmd_pending = cmd; +bcmnand_ctrl_busy_poll (ctrl, mask);... just call
bcmnand_ctrl_busy_poll(ctrl, NAND_CTRL_RDY);
Quoted 9 lines
here.
drivers/mtd/nand/brcmnand/brcmnand.c static void brcmnand_send_cmd(struct brcmnand_host *host, int cmd) · line 1224
Quoted 4 lines
drivers/mtd/nand/brcmnand/brcmnand.c +1
-0intfc =brcmnand_read_reg (ctrl,BRCMNAND_INTFC_STATUS );WARN_ON (!(intfc &INTFC_CTLR_READY )); +Drop this extra empty line.
Ok.
Quoted 21 lines
Quoted 21 lines
drivers/mtd/nand/brcmnand/brcmnand.c +0
-8mb ();/* flush previous writes */ brcmnand_write_reg (ctrl,BRCMNAND_CMD_START , cmd <<brcmnand_cmd_shift (ctrl));@@ -2462,14 +2517,6 @@ int brcmnand_probe(struct platform_device *pdev, struct brcmnand_soc *soc)/* Disable XOR addressing */ brcmnand_rmw_reg (ctrl,BRCMNAND_CS_XOR ,0xff ,0 ,0 ); -if (ctrl->features &BRCMNAND_HAS_WP ) { -/* Permanently disable write protection */ -if (wp_on ==2 ) -brcmnand_set_wp (ctrl, false); - }else { - wp_on =0 ; - } -/* IRQ */ ctrl->irq =platform_get_irq (pdev,0 );if ((int )ctrl->irq <0 ) {@@ -2522,6 +2569,14 @@ int brcmnand_probe(struct platform_device *pdev, struct brcmnand_soc *soc) }
Quoted 13 lines
drivers/mtd/nand/brcmnand/brcmnand.c int brcmnand_probe(struct platform_device *pdev, struct brcmnand_soc *soc) · line 2579
Quoted 9 lines
drivers/mtd/nand/brcmnand/brcmnand.c +8
-0list_add_tail (&host->node, &ctrl->host_list); + +if (ctrl->features &BRCMNAND_HAS_WP ) { +/* Permanently disable write protection */ +if (wp_on ==2 ) +brcmnand_set_wp (host, false); + }else { + wp_on =0 ; + }Hm, this is not really related to the change you describe in your commit message. This should probably go in a separate commit.
It is related to the change since this code moved within the probe function due the new brcmnand_set_wp() prototype. So has to be part of the same commit.
Quoted 4 lines
drivers/mtd/nand/brcmnand/brcmnand.c int brcmnand_probe(struct platform_device *pdev, struct brcmnand_soc *soc) · line 2582
Quoted 3 lines
drivers/mtd/nand/brcmnand/brcmnand.c +0
-0} }
Thanks
Kamal
Quoted 6 lines · On Wed, 15 Feb 2017 13:51:15 -0500 Kamal Dasu <[email protected]> wrote:
Quoted 5 lines
I still have a hard time understanding what the problem is with this commit message. Can you try to clarify that?
Quoted 9 lines
Software assumed that setting/resetting the
NAND_WPcontroller
register would assert/de-assert the #WP pin instantaneously from the flash parts perspective, and was proceeding to erase/program. Nand driver was not verifying flash status byte for WP. In rigorous testing we found this was causing rare data corruptions with erase and/or subsequent programming. So to make sure the flash part is ready to accept erase/program commands was to send status read command and read back the WP bit status from the flash whenever we change the pin state. I will clarify this in the commit message as well.
I prefer this explanation ;-).
[...]
Quoted 36 lines
Quoted 22 lines
Quoted 22 lines
mb(); /* flush previous writes */ brcmnand_write_reg(ctrl, BRCMNAND_CMD_START, cmd << brcmnand_cmd_shift(ctrl));drivers/mtd/nand/brcmnand/brcmnand.c +0
-8@@ -2462,14 +2517,6 @@ int brcmnand_probe(struct platform_device *pdev, struct brcmnand_soc *soc)/* Disable XOR addressing */ brcmnand_rmw_reg (ctrl,BRCMNAND_CS_XOR ,0xff ,0 ,0 ); -if (ctrl->features &BRCMNAND_HAS_WP ) { -/* Permanently disable write protection */ -if (wp_on ==2 ) -brcmnand_set_wp (ctrl, false); - }else { - wp_on =0 ; - } -/* IRQ */ ctrl->irq =platform_get_irq (pdev,0 );if ((int )ctrl->irq <0 ) {@@ -2522,6 +2569,14 @@ int brcmnand_probe(struct platform_device *pdev, struct brcmnand_soc *soc) }Quoted 13 lines
drivers/mtd/nand/brcmnand/brcmnand.c int brcmnand_probe(struct platform_device *pdev, struct brcmnand_soc *soc) · line 2579
Quoted 9 lines
drivers/mtd/nand/brcmnand/brcmnand.c +8
-0list_add_tail (&host->node, &ctrl->host_list); + +if (ctrl->features &BRCMNAND_HAS_WP ) { +/* Permanently disable write protection */ +if (wp_on ==2 ) +brcmnand_set_wp (host, false); + }else { + wp_on =0 ; + }Hm, this is not really related to the change you describe in your commit message. This should probably go in a separate commit.
Quoted 3 lines
It is related to the change since this code moved within the probe function due the new
brcmnand_set_wp()prototype. So has to be part of the same commit.
You could change the prototype of brcmnand_set_wp() in the first patch (+ move in the call where appropriate in the probe function and patch brcmnand_wp() to pass host instead of ctrl), and then rework the brcmnand_set_wp() implementation in a second patch.