diff options
Diffstat (limited to 'target/linux/mvebu/patches-3.10/0152-mtd-nand-pxa3xx-Add-multiple-chunk-write-support.patch')
-rw-r--r-- | target/linux/mvebu/patches-3.10/0152-mtd-nand-pxa3xx-Add-multiple-chunk-write-support.patch | 146 |
1 files changed, 146 insertions, 0 deletions
diff --git a/target/linux/mvebu/patches-3.10/0152-mtd-nand-pxa3xx-Add-multiple-chunk-write-support.patch b/target/linux/mvebu/patches-3.10/0152-mtd-nand-pxa3xx-Add-multiple-chunk-write-support.patch new file mode 100644 index 0000000000..058dc0bc3c --- /dev/null +++ b/target/linux/mvebu/patches-3.10/0152-mtd-nand-pxa3xx-Add-multiple-chunk-write-support.patch @@ -0,0 +1,146 @@ +From db95c66cebb6297595a5a32b369d1033b08775ce Mon Sep 17 00:00:00 2001 +From: Ezequiel Garcia <ezequiel.garcia@free-electrons.com> +Date: Thu, 14 Nov 2013 18:25:38 -0300 +Subject: [PATCH 152/203] mtd: nand: pxa3xx: Add multiple chunk write support + +This commit adds write support for large pages (4 KiB, 8 KiB). +Such support is implemented by issuing a multiple command sequence, +transfering a set of 2 KiB chunks per transaction. + +The splitted command sequence requires to send the SEQIN command +independently of the PAGEPROG command and therefore it's set as +an execution command. + +Since PAGEPROG enables ECC, each 2 KiB chunk of data is written +together with ECC code at a controller-fixed location within +the flash page. + +Currently, only devices with a 4 KiB page size has been tested. + +Signed-off-by: Ezequiel Garcia <ezequiel.garcia@free-electrons.com> +Tested-by: Daniel Mack <zonque@gmail.com> +Signed-off-by: Brian Norris <computersforpeace@gmail.com> +--- + drivers/mtd/nand/pxa3xx_nand.c | 81 +++++++++++++++++++++++++++++++++++++----- + 1 file changed, 73 insertions(+), 8 deletions(-) + +--- a/drivers/mtd/nand/pxa3xx_nand.c ++++ b/drivers/mtd/nand/pxa3xx_nand.c +@@ -760,6 +760,20 @@ static int prepare_set_command(struct px + + info->buf_start = column; + set_command_address(info, mtd->writesize, 0, page_addr); ++ ++ /* ++ * Multiple page programming needs to execute the initial ++ * SEQIN command that sets the page address. ++ */ ++ if (mtd->writesize > PAGE_CHUNK_SIZE) { ++ info->ndcb0 |= NDCB0_CMD_TYPE(0x1) ++ | NDCB0_EXT_CMD_TYPE(ext_cmd_type) ++ | addr_cycle ++ | command; ++ /* No data transfer in this case */ ++ info->data_size = 0; ++ exec_cmd = 1; ++ } + break; + + case NAND_CMD_PAGEPROG: +@@ -769,13 +783,40 @@ static int prepare_set_command(struct px + break; + } + +- info->ndcb0 |= NDCB0_CMD_TYPE(0x1) +- | NDCB0_AUTO_RS +- | NDCB0_ST_ROW_EN +- | NDCB0_DBC +- | (NAND_CMD_PAGEPROG << 8) +- | NAND_CMD_SEQIN +- | addr_cycle; ++ /* Second command setting for large pages */ ++ if (mtd->writesize > PAGE_CHUNK_SIZE) { ++ /* ++ * Multiple page write uses the 'extended command' ++ * field. This can be used to issue a command dispatch ++ * or a naked-write depending on the current stage. ++ */ ++ info->ndcb0 |= NDCB0_CMD_TYPE(0x1) ++ | NDCB0_LEN_OVRD ++ | NDCB0_EXT_CMD_TYPE(ext_cmd_type); ++ info->ndcb3 = info->chunk_size + ++ info->oob_size; ++ ++ /* ++ * This is the command dispatch that completes a chunked ++ * page program operation. ++ */ ++ if (info->data_size == 0) { ++ info->ndcb0 = NDCB0_CMD_TYPE(0x1) ++ | NDCB0_EXT_CMD_TYPE(ext_cmd_type) ++ | command; ++ info->ndcb1 = 0; ++ info->ndcb2 = 0; ++ info->ndcb3 = 0; ++ } ++ } else { ++ info->ndcb0 |= NDCB0_CMD_TYPE(0x1) ++ | NDCB0_AUTO_RS ++ | NDCB0_ST_ROW_EN ++ | NDCB0_DBC ++ | (NAND_CMD_PAGEPROG << 8) ++ | NAND_CMD_SEQIN ++ | addr_cycle; ++ } + break; + + case NAND_CMD_PARAM: +@@ -919,8 +960,15 @@ static void armada370_nand_cmdfunc(struc + case NAND_CMD_READOOB: + ext_cmd_type = EXT_CMD_TYPE_MONO; + break; ++ case NAND_CMD_SEQIN: ++ ext_cmd_type = EXT_CMD_TYPE_DISPATCH; ++ break; ++ case NAND_CMD_PAGEPROG: ++ ext_cmd_type = EXT_CMD_TYPE_NAKED_RW; ++ break; + default: + ext_cmd_type = 0; ++ break; + } + + prepare_start_command(info, command); +@@ -958,7 +1006,16 @@ static void armada370_nand_cmdfunc(struc + } + + /* Check if the sequence is complete */ +- if (info->data_size == 0) ++ if (info->data_size == 0 && command != NAND_CMD_PAGEPROG) ++ break; ++ ++ /* ++ * After a splitted program command sequence has issued ++ * the command dispatch, the command sequence is complete. ++ */ ++ if (info->data_size == 0 && ++ command == NAND_CMD_PAGEPROG && ++ ext_cmd_type == EXT_CMD_TYPE_DISPATCH) + break; + + if (command == NAND_CMD_READ0 || command == NAND_CMD_READOOB) { +@@ -967,6 +1024,14 @@ static void armada370_nand_cmdfunc(struc + ext_cmd_type = EXT_CMD_TYPE_LAST_RW; + else + ext_cmd_type = EXT_CMD_TYPE_NAKED_RW; ++ ++ /* ++ * If a splitted program command has no more data to transfer, ++ * the command dispatch must be issued to complete. ++ */ ++ } else if (command == NAND_CMD_PAGEPROG && ++ info->data_size == 0) { ++ ext_cmd_type = EXT_CMD_TYPE_DISPATCH; + } + } while (1); + |