mvebu: backport mainline patches from kernel 3.13
[openwrt/staging/wigyori.git] / target / linux / mvebu / patches-3.10 / 0152-mtd-nand-pxa3xx-Add-multiple-chunk-write-support.patch
1 From db95c66cebb6297595a5a32b369d1033b08775ce Mon Sep 17 00:00:00 2001
2 From: Ezequiel Garcia <ezequiel.garcia@free-electrons.com>
3 Date: Thu, 14 Nov 2013 18:25:38 -0300
4 Subject: [PATCH 152/203] mtd: nand: pxa3xx: Add multiple chunk write support
5
6 This commit adds write support for large pages (4 KiB, 8 KiB).
7 Such support is implemented by issuing a multiple command sequence,
8 transfering a set of 2 KiB chunks per transaction.
9
10 The splitted command sequence requires to send the SEQIN command
11 independently of the PAGEPROG command and therefore it's set as
12 an execution command.
13
14 Since PAGEPROG enables ECC, each 2 KiB chunk of data is written
15 together with ECC code at a controller-fixed location within
16 the flash page.
17
18 Currently, only devices with a 4 KiB page size has been tested.
19
20 Signed-off-by: Ezequiel Garcia <ezequiel.garcia@free-electrons.com>
21 Tested-by: Daniel Mack <zonque@gmail.com>
22 Signed-off-by: Brian Norris <computersforpeace@gmail.com>
23 ---
24 drivers/mtd/nand/pxa3xx_nand.c | 81 +++++++++++++++++++++++++++++++++++++-----
25 1 file changed, 73 insertions(+), 8 deletions(-)
26
27 --- a/drivers/mtd/nand/pxa3xx_nand.c
28 +++ b/drivers/mtd/nand/pxa3xx_nand.c
29 @@ -760,6 +760,20 @@ static int prepare_set_command(struct px
30
31 info->buf_start = column;
32 set_command_address(info, mtd->writesize, 0, page_addr);
33 +
34 + /*
35 + * Multiple page programming needs to execute the initial
36 + * SEQIN command that sets the page address.
37 + */
38 + if (mtd->writesize > PAGE_CHUNK_SIZE) {
39 + info->ndcb0 |= NDCB0_CMD_TYPE(0x1)
40 + | NDCB0_EXT_CMD_TYPE(ext_cmd_type)
41 + | addr_cycle
42 + | command;
43 + /* No data transfer in this case */
44 + info->data_size = 0;
45 + exec_cmd = 1;
46 + }
47 break;
48
49 case NAND_CMD_PAGEPROG:
50 @@ -769,13 +783,40 @@ static int prepare_set_command(struct px
51 break;
52 }
53
54 - info->ndcb0 |= NDCB0_CMD_TYPE(0x1)
55 - | NDCB0_AUTO_RS
56 - | NDCB0_ST_ROW_EN
57 - | NDCB0_DBC
58 - | (NAND_CMD_PAGEPROG << 8)
59 - | NAND_CMD_SEQIN
60 - | addr_cycle;
61 + /* Second command setting for large pages */
62 + if (mtd->writesize > PAGE_CHUNK_SIZE) {
63 + /*
64 + * Multiple page write uses the 'extended command'
65 + * field. This can be used to issue a command dispatch
66 + * or a naked-write depending on the current stage.
67 + */
68 + info->ndcb0 |= NDCB0_CMD_TYPE(0x1)
69 + | NDCB0_LEN_OVRD
70 + | NDCB0_EXT_CMD_TYPE(ext_cmd_type);
71 + info->ndcb3 = info->chunk_size +
72 + info->oob_size;
73 +
74 + /*
75 + * This is the command dispatch that completes a chunked
76 + * page program operation.
77 + */
78 + if (info->data_size == 0) {
79 + info->ndcb0 = NDCB0_CMD_TYPE(0x1)
80 + | NDCB0_EXT_CMD_TYPE(ext_cmd_type)
81 + | command;
82 + info->ndcb1 = 0;
83 + info->ndcb2 = 0;
84 + info->ndcb3 = 0;
85 + }
86 + } else {
87 + info->ndcb0 |= NDCB0_CMD_TYPE(0x1)
88 + | NDCB0_AUTO_RS
89 + | NDCB0_ST_ROW_EN
90 + | NDCB0_DBC
91 + | (NAND_CMD_PAGEPROG << 8)
92 + | NAND_CMD_SEQIN
93 + | addr_cycle;
94 + }
95 break;
96
97 case NAND_CMD_PARAM:
98 @@ -919,8 +960,15 @@ static void armada370_nand_cmdfunc(struc
99 case NAND_CMD_READOOB:
100 ext_cmd_type = EXT_CMD_TYPE_MONO;
101 break;
102 + case NAND_CMD_SEQIN:
103 + ext_cmd_type = EXT_CMD_TYPE_DISPATCH;
104 + break;
105 + case NAND_CMD_PAGEPROG:
106 + ext_cmd_type = EXT_CMD_TYPE_NAKED_RW;
107 + break;
108 default:
109 ext_cmd_type = 0;
110 + break;
111 }
112
113 prepare_start_command(info, command);
114 @@ -958,7 +1006,16 @@ static void armada370_nand_cmdfunc(struc
115 }
116
117 /* Check if the sequence is complete */
118 - if (info->data_size == 0)
119 + if (info->data_size == 0 && command != NAND_CMD_PAGEPROG)
120 + break;
121 +
122 + /*
123 + * After a splitted program command sequence has issued
124 + * the command dispatch, the command sequence is complete.
125 + */
126 + if (info->data_size == 0 &&
127 + command == NAND_CMD_PAGEPROG &&
128 + ext_cmd_type == EXT_CMD_TYPE_DISPATCH)
129 break;
130
131 if (command == NAND_CMD_READ0 || command == NAND_CMD_READOOB) {
132 @@ -967,6 +1024,14 @@ static void armada370_nand_cmdfunc(struc
133 ext_cmd_type = EXT_CMD_TYPE_LAST_RW;
134 else
135 ext_cmd_type = EXT_CMD_TYPE_NAKED_RW;
136 +
137 + /*
138 + * If a splitted program command has no more data to transfer,
139 + * the command dispatch must be issued to complete.
140 + */
141 + } else if (command == NAND_CMD_PAGEPROG &&
142 + info->data_size == 0) {
143 + ext_cmd_type = EXT_CMD_TYPE_DISPATCH;
144 }
145 } while (1);
146