summaryrefslogtreecommitdiff
path: root/target/linux/mvebu/patches-3.10/0152-mtd-nand-pxa3xx-Add-multiple-chunk-write-support.patch
diff options
context:
space:
mode:
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.patch146
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 0000000..058dc0b
--- /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);
+