| From foo@baz Fri Mar 16 15:43:17 CET 2018 |
| From: Miquel Raynal <miquel.raynal@free-electrons.com> |
| Date: Wed, 8 Nov 2017 17:00:27 +0100 |
| Subject: mtd: nand: fix interpretation of NAND_CMD_NONE in nand_command[_lp]() |
| |
| From: Miquel Raynal <miquel.raynal@free-electrons.com> |
| |
| |
| [ Upstream commit df467899da0b71465760b4e35127bce837244eee ] |
| |
| Some drivers (like nand_hynix.c) call ->cmdfunc() with NAND_CMD_NONE |
| and a column address and expect the controller to only send address |
| cycles. Right now, the default ->cmdfunc() implementations provided by |
| the core do not filter out the command cycle in this case and forwards |
| the request to the controller driver through the ->cmd_ctrl() method. |
| The thing is, NAND controller drivers can get this wrong and send a |
| command cycle with a NAND_CMD_NONE opcode and since NAND_CMD_NONE is |
| -1, and the command field is usually casted to an u8, we end up sending |
| the 0xFF command which is actually a RESET operation. |
| |
| Add conditions in nand_command[_lp]() functions to sending the initial |
| command cycle when command == NAND_CMD_NONE. |
| |
| Signed-off-by: Miquel Raynal <miquel.raynal@free-electrons.com> |
| Signed-off-by: Boris Brezillon <boris.brezillon@free-electrons.com> |
| Signed-off-by: Sasha Levin <alexander.levin@microsoft.com> |
| Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org> |
| --- |
| drivers/mtd/nand/nand_base.c | 9 +++++++-- |
| 1 file changed, 7 insertions(+), 2 deletions(-) |
| |
| --- a/drivers/mtd/nand/nand_base.c |
| +++ b/drivers/mtd/nand/nand_base.c |
| @@ -710,7 +710,8 @@ static void nand_command(struct mtd_info |
| chip->cmd_ctrl(mtd, readcmd, ctrl); |
| ctrl &= ~NAND_CTRL_CHANGE; |
| } |
| - chip->cmd_ctrl(mtd, command, ctrl); |
| + if (command != NAND_CMD_NONE) |
| + chip->cmd_ctrl(mtd, command, ctrl); |
| |
| /* Address cycle, when necessary */ |
| ctrl = NAND_CTRL_ALE | NAND_CTRL_CHANGE; |
| @@ -739,6 +740,7 @@ static void nand_command(struct mtd_info |
| */ |
| switch (command) { |
| |
| + case NAND_CMD_NONE: |
| case NAND_CMD_PAGEPROG: |
| case NAND_CMD_ERASE1: |
| case NAND_CMD_ERASE2: |
| @@ -832,7 +834,9 @@ static void nand_command_lp(struct mtd_i |
| } |
| |
| /* Command latch cycle */ |
| - chip->cmd_ctrl(mtd, command, NAND_NCE | NAND_CLE | NAND_CTRL_CHANGE); |
| + if (command != NAND_CMD_NONE) |
| + chip->cmd_ctrl(mtd, command, |
| + NAND_NCE | NAND_CLE | NAND_CTRL_CHANGE); |
| |
| if (column != -1 || page_addr != -1) { |
| int ctrl = NAND_CTRL_CHANGE | NAND_NCE | NAND_ALE; |
| @@ -868,6 +872,7 @@ static void nand_command_lp(struct mtd_i |
| */ |
| switch (command) { |
| |
| + case NAND_CMD_NONE: |
| case NAND_CMD_CACHEDPROG: |
| case NAND_CMD_PAGEPROG: |
| case NAND_CMD_ERASE1: |