aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/mtd/nand/pxa3xx_nand.c
diff options
context:
space:
mode:
authorEzequiel Garcia <ezequiel.garcia@free-electrons.com>2013-11-14 16:25:37 -0500
committerBrian Norris <computersforpeace@gmail.com>2014-01-03 14:22:17 -0500
commit70ed85232a93af5253bff4802ef4ead1e83faa5f (patch)
treecebcf7518e565e974d4a200a35a4c2d968d1886e /drivers/mtd/nand/pxa3xx_nand.c
parentfa543bef72d62c14f25c6f48f5981f7ecc5402f2 (diff)
mtd: nand: pxa3xx: Introduce multiple page I/O support
As preparation work to fully support large pages, this commit adds the initial infrastructure to support splitted (aka chunked) I/O operation. This commit adds support for read, and follow-up patches will add write support. When a read (aka READ0) command is issued, the driver loops issuing the same command until all the requested data is transfered, changing the 'extended' command field as needed. For instance, if the driver is required to read a 4 KiB page, using a chunk size of 2 KiB, the transaction is splitted in: 1. Monolithic read, first 2 KiB page chunk is read 2. Last naked read, second and last 2KiB page chunk is read If ECC is enabled it is calculated on each chunk transfered and added at a controller-fixed location after the data chunk that must be spare area. 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>
Diffstat (limited to 'drivers/mtd/nand/pxa3xx_nand.c')
-rw-r--r--drivers/mtd/nand/pxa3xx_nand.c182
1 files changed, 172 insertions, 10 deletions
diff --git a/drivers/mtd/nand/pxa3xx_nand.c b/drivers/mtd/nand/pxa3xx_nand.c
index c17c28594a29..72dce4546451 100644
--- a/drivers/mtd/nand/pxa3xx_nand.c
+++ b/drivers/mtd/nand/pxa3xx_nand.c
@@ -103,6 +103,8 @@
103#define NDCB0_ST_ROW_EN (0x1 << 26) 103#define NDCB0_ST_ROW_EN (0x1 << 26)
104#define NDCB0_AUTO_RS (0x1 << 25) 104#define NDCB0_AUTO_RS (0x1 << 25)
105#define NDCB0_CSEL (0x1 << 24) 105#define NDCB0_CSEL (0x1 << 24)
106#define NDCB0_EXT_CMD_TYPE_MASK (0x7 << 29)
107#define NDCB0_EXT_CMD_TYPE(x) (((x) << 29) & NDCB0_EXT_CMD_TYPE_MASK)
106#define NDCB0_CMD_TYPE_MASK (0x7 << 21) 108#define NDCB0_CMD_TYPE_MASK (0x7 << 21)
107#define NDCB0_CMD_TYPE(x) (((x) << 21) & NDCB0_CMD_TYPE_MASK) 109#define NDCB0_CMD_TYPE(x) (((x) << 21) & NDCB0_CMD_TYPE_MASK)
108#define NDCB0_NC (0x1 << 20) 110#define NDCB0_NC (0x1 << 20)
@@ -113,6 +115,14 @@
113#define NDCB0_CMD1_MASK (0xff) 115#define NDCB0_CMD1_MASK (0xff)
114#define NDCB0_ADDR_CYC_SHIFT (16) 116#define NDCB0_ADDR_CYC_SHIFT (16)
115 117
118#define EXT_CMD_TYPE_DISPATCH 6 /* Command dispatch */
119#define EXT_CMD_TYPE_NAKED_RW 5 /* Naked read or Naked write */
120#define EXT_CMD_TYPE_READ 4 /* Read */
121#define EXT_CMD_TYPE_DISP_WR 4 /* Command dispatch with write */
122#define EXT_CMD_TYPE_FINAL 3 /* Final command */
123#define EXT_CMD_TYPE_LAST_RW 1 /* Last naked read/write */
124#define EXT_CMD_TYPE_MONO 0 /* Monolithic read/write */
125
116/* macros for registers read/write */ 126/* macros for registers read/write */
117#define nand_writel(info, off, val) \ 127#define nand_writel(info, off, val) \
118 __raw_writel((val), (info)->mmio_base + (off)) 128 __raw_writel((val), (info)->mmio_base + (off))
@@ -206,8 +216,8 @@ struct pxa3xx_nand_info {
206 int use_spare; /* use spare ? */ 216 int use_spare; /* use spare ? */
207 int need_wait; 217 int need_wait;
208 218
209 unsigned int fifo_size; /* max. data size in the FIFO */
210 unsigned int data_size; /* data to be read from FIFO */ 219 unsigned int data_size; /* data to be read from FIFO */
220 unsigned int chunk_size; /* split commands chunk size */
211 unsigned int oob_size; 221 unsigned int oob_size;
212 unsigned int spare_size; 222 unsigned int spare_size;
213 unsigned int ecc_size; 223 unsigned int ecc_size;
@@ -271,6 +281,31 @@ static struct nand_bbt_descr bbt_mirror_descr = {
271 .pattern = bbt_mirror_pattern 281 .pattern = bbt_mirror_pattern
272}; 282};
273 283
284static struct nand_ecclayout ecc_layout_4KB_bch4bit = {
285 .eccbytes = 64,
286 .eccpos = {
287 32, 33, 34, 35, 36, 37, 38, 39,
288 40, 41, 42, 43, 44, 45, 46, 47,
289 48, 49, 50, 51, 52, 53, 54, 55,
290 56, 57, 58, 59, 60, 61, 62, 63,
291 96, 97, 98, 99, 100, 101, 102, 103,
292 104, 105, 106, 107, 108, 109, 110, 111,
293 112, 113, 114, 115, 116, 117, 118, 119,
294 120, 121, 122, 123, 124, 125, 126, 127},
295 /* Bootrom looks in bytes 0 & 5 for bad blocks */
296 .oobfree = { {6, 26}, { 64, 32} }
297};
298
299static struct nand_ecclayout ecc_layout_4KB_bch8bit = {
300 .eccbytes = 128,
301 .eccpos = {
302 32, 33, 34, 35, 36, 37, 38, 39,
303 40, 41, 42, 43, 44, 45, 46, 47,
304 48, 49, 50, 51, 52, 53, 54, 55,
305 56, 57, 58, 59, 60, 61, 62, 63},
306 .oobfree = { }
307};
308
274/* Define a default flash type setting serve as flash detecting only */ 309/* Define a default flash type setting serve as flash detecting only */
275#define DEFAULT_FLASH_TYPE (&builtin_flash_types[0]) 310#define DEFAULT_FLASH_TYPE (&builtin_flash_types[0])
276 311
@@ -429,7 +464,7 @@ static void disable_int(struct pxa3xx_nand_info *info, uint32_t int_mask)
429 464
430static void handle_data_pio(struct pxa3xx_nand_info *info) 465static void handle_data_pio(struct pxa3xx_nand_info *info)
431{ 466{
432 unsigned int do_bytes = min(info->data_size, info->fifo_size); 467 unsigned int do_bytes = min(info->data_size, info->chunk_size);
433 468
434 switch (info->state) { 469 switch (info->state) {
435 case STATE_PIO_WRITING: 470 case STATE_PIO_WRITING:
@@ -666,7 +701,7 @@ static void prepare_start_command(struct pxa3xx_nand_info *info, int command)
666} 701}
667 702
668static int prepare_set_command(struct pxa3xx_nand_info *info, int command, 703static int prepare_set_command(struct pxa3xx_nand_info *info, int command,
669 uint16_t column, int page_addr) 704 int ext_cmd_type, uint16_t column, int page_addr)
670{ 705{
671 int addr_cycle, exec_cmd; 706 int addr_cycle, exec_cmd;
672 struct pxa3xx_nand_host *host; 707 struct pxa3xx_nand_host *host;
@@ -699,9 +734,20 @@ static int prepare_set_command(struct pxa3xx_nand_info *info, int command,
699 if (command == NAND_CMD_READOOB) 734 if (command == NAND_CMD_READOOB)
700 info->buf_start += mtd->writesize; 735 info->buf_start += mtd->writesize;
701 736
702 /* Second command setting for large pages */ 737 /*
703 if (mtd->writesize >= PAGE_CHUNK_SIZE) 738 * Multiple page read needs an 'extended command type' field,
739 * which is either naked-read or last-read according to the
740 * state.
741 */
742 if (mtd->writesize == PAGE_CHUNK_SIZE) {
704 info->ndcb0 |= NDCB0_DBC | (NAND_CMD_READSTART << 8); 743 info->ndcb0 |= NDCB0_DBC | (NAND_CMD_READSTART << 8);
744 } else if (mtd->writesize > PAGE_CHUNK_SIZE) {
745 info->ndcb0 |= NDCB0_DBC | (NAND_CMD_READSTART << 8)
746 | NDCB0_LEN_OVRD
747 | NDCB0_EXT_CMD_TYPE(ext_cmd_type);
748 info->ndcb3 = info->chunk_size +
749 info->oob_size;
750 }
705 751
706 set_command_address(info, mtd->writesize, column, page_addr); 752 set_command_address(info, mtd->writesize, column, page_addr);
707 break; 753 break;
@@ -817,7 +863,8 @@ static void pxa3xx_nand_cmdfunc(struct mtd_info *mtd, unsigned command,
817 prepare_start_command(info, command); 863 prepare_start_command(info, command);
818 864
819 info->state = STATE_PREPARED; 865 info->state = STATE_PREPARED;
820 exec_cmd = prepare_set_command(info, command, column, page_addr); 866 exec_cmd = prepare_set_command(info, command, 0, column, page_addr);
867
821 if (exec_cmd) { 868 if (exec_cmd) {
822 init_completion(&info->cmd_complete); 869 init_completion(&info->cmd_complete);
823 init_completion(&info->dev_ready); 870 init_completion(&info->dev_ready);
@@ -835,6 +882,93 @@ static void pxa3xx_nand_cmdfunc(struct mtd_info *mtd, unsigned command,
835 info->state = STATE_IDLE; 882 info->state = STATE_IDLE;
836} 883}
837 884
885static void armada370_nand_cmdfunc(struct mtd_info *mtd,
886 const unsigned command,
887 int column, int page_addr)
888{
889 struct pxa3xx_nand_host *host = mtd->priv;
890 struct pxa3xx_nand_info *info = host->info_data;
891 int ret, exec_cmd, ext_cmd_type;
892
893 /*
894 * if this is a x16 device then convert the input
895 * "byte" address into a "word" address appropriate
896 * for indexing a word-oriented device
897 */
898 if (info->reg_ndcr & NDCR_DWIDTH_M)
899 column /= 2;
900
901 /*
902 * There may be different NAND chip hooked to
903 * different chip select, so check whether
904 * chip select has been changed, if yes, reset the timing
905 */
906 if (info->cs != host->cs) {
907 info->cs = host->cs;
908 nand_writel(info, NDTR0CS0, info->ndtr0cs0);
909 nand_writel(info, NDTR1CS0, info->ndtr1cs0);
910 }
911
912 /* Select the extended command for the first command */
913 switch (command) {
914 case NAND_CMD_READ0:
915 case NAND_CMD_READOOB:
916 ext_cmd_type = EXT_CMD_TYPE_MONO;
917 break;
918 default:
919 ext_cmd_type = 0;
920 }
921
922 prepare_start_command(info, command);
923
924 /*
925 * Prepare the "is ready" completion before starting a command
926 * transaction sequence. If the command is not executed the
927 * completion will be completed, see below.
928 *
929 * We can do that inside the loop because the command variable
930 * is invariant and thus so is the exec_cmd.
931 */
932 info->need_wait = 1;
933 init_completion(&info->dev_ready);
934 do {
935 info->state = STATE_PREPARED;
936 exec_cmd = prepare_set_command(info, command, ext_cmd_type,
937 column, page_addr);
938 if (!exec_cmd) {
939 info->need_wait = 0;
940 complete(&info->dev_ready);
941 break;
942 }
943
944 init_completion(&info->cmd_complete);
945 pxa3xx_nand_start(info);
946
947 ret = wait_for_completion_timeout(&info->cmd_complete,
948 CHIP_DELAY_TIMEOUT);
949 if (!ret) {
950 dev_err(&info->pdev->dev, "Wait time out!!!\n");
951 /* Stop State Machine for next command cycle */
952 pxa3xx_nand_stop(info);
953 break;
954 }
955
956 /* Check if the sequence is complete */
957 if (info->data_size == 0)
958 break;
959
960 if (command == NAND_CMD_READ0 || command == NAND_CMD_READOOB) {
961 /* Last read: issue a 'last naked read' */
962 if (info->data_size == info->chunk_size)
963 ext_cmd_type = EXT_CMD_TYPE_LAST_RW;
964 else
965 ext_cmd_type = EXT_CMD_TYPE_NAKED_RW;
966 }
967 } while (1);
968
969 info->state = STATE_IDLE;
970}
971
838static int pxa3xx_nand_write_page_hwecc(struct mtd_info *mtd, 972static int pxa3xx_nand_write_page_hwecc(struct mtd_info *mtd,
839 struct nand_chip *chip, const uint8_t *buf, int oob_required) 973 struct nand_chip *chip, const uint8_t *buf, int oob_required)
840{ 974{
@@ -1015,13 +1149,14 @@ static int pxa3xx_nand_detect_config(struct pxa3xx_nand_info *info)
1015 1149
1016 if (ndcr & NDCR_PAGE_SZ) { 1150 if (ndcr & NDCR_PAGE_SZ) {
1017 /* Controller's FIFO size */ 1151 /* Controller's FIFO size */
1018 info->fifo_size = 2048; 1152 info->chunk_size = 2048;
1019 host->read_id_bytes = 4; 1153 host->read_id_bytes = 4;
1020 } else { 1154 } else {
1021 info->fifo_size = 512; 1155 info->chunk_size = 512;
1022 host->read_id_bytes = 2; 1156 host->read_id_bytes = 2;
1023 } 1157 }
1024 1158
1159 /* Set an initial chunk size */
1025 info->reg_ndcr = ndcr & ~NDCR_INT_MASK; 1160 info->reg_ndcr = ndcr & ~NDCR_INT_MASK;
1026 info->ndtr0cs0 = nand_readl(info, NDTR0CS0); 1161 info->ndtr0cs0 = nand_readl(info, NDTR0CS0);
1027 info->ndtr1cs0 = nand_readl(info, NDTR1CS0); 1162 info->ndtr1cs0 = nand_readl(info, NDTR1CS0);
@@ -1125,6 +1260,7 @@ static int pxa_ecc_init(struct pxa3xx_nand_info *info,
1125 * is used with non-ONFI compliant devices. 1260 * is used with non-ONFI compliant devices.
1126 */ 1261 */
1127 if (page_size == 2048) { 1262 if (page_size == 2048) {
1263 info->chunk_size = 2048;
1128 info->spare_size = 40; 1264 info->spare_size = 40;
1129 info->ecc_size = 24; 1265 info->ecc_size = 24;
1130 ecc->mode = NAND_ECC_HW; 1266 ecc->mode = NAND_ECC_HW;
@@ -1133,6 +1269,7 @@ static int pxa_ecc_init(struct pxa3xx_nand_info *info,
1133 return 1; 1269 return 1;
1134 1270
1135 } else if (page_size == 512) { 1271 } else if (page_size == 512) {
1272 info->chunk_size = 512;
1136 info->spare_size = 8; 1273 info->spare_size = 8;
1137 info->ecc_size = 8; 1274 info->ecc_size = 8;
1138 ecc->mode = NAND_ECC_HW; 1275 ecc->mode = NAND_ECC_HW;
@@ -1147,7 +1284,28 @@ static int armada370_ecc_init(struct pxa3xx_nand_info *info,
1147 struct nand_ecc_ctrl *ecc, 1284 struct nand_ecc_ctrl *ecc,
1148 int strength, int page_size) 1285 int strength, int page_size)
1149{ 1286{
1150 /* Unimplemented yet */ 1287 if (strength == 4 && page_size == 4096) {
1288 info->ecc_bch = 1;
1289 info->chunk_size = 2048;
1290 info->spare_size = 32;
1291 info->ecc_size = 32;
1292 ecc->mode = NAND_ECC_HW;
1293 ecc->size = info->chunk_size;
1294 ecc->layout = &ecc_layout_4KB_bch4bit;
1295 ecc->strength = 16;
1296 return 1;
1297
1298 } else if (strength == 8 && page_size == 4096) {
1299 info->ecc_bch = 1;
1300 info->chunk_size = 1024;
1301 info->spare_size = 0;
1302 info->ecc_size = 32;
1303 ecc->mode = NAND_ECC_HW;
1304 ecc->size = info->chunk_size;
1305 ecc->layout = &ecc_layout_4KB_bch8bit;
1306 ecc->strength = 16;
1307 return 1;
1308 }
1151 return 0; 1309 return 0;
1152} 1310}
1153 1311
@@ -1315,12 +1473,16 @@ static int alloc_nand_resource(struct platform_device *pdev)
1315 chip->controller = &info->controller; 1473 chip->controller = &info->controller;
1316 chip->waitfunc = pxa3xx_nand_waitfunc; 1474 chip->waitfunc = pxa3xx_nand_waitfunc;
1317 chip->select_chip = pxa3xx_nand_select_chip; 1475 chip->select_chip = pxa3xx_nand_select_chip;
1318 chip->cmdfunc = pxa3xx_nand_cmdfunc;
1319 chip->read_word = pxa3xx_nand_read_word; 1476 chip->read_word = pxa3xx_nand_read_word;
1320 chip->read_byte = pxa3xx_nand_read_byte; 1477 chip->read_byte = pxa3xx_nand_read_byte;
1321 chip->read_buf = pxa3xx_nand_read_buf; 1478 chip->read_buf = pxa3xx_nand_read_buf;
1322 chip->write_buf = pxa3xx_nand_write_buf; 1479 chip->write_buf = pxa3xx_nand_write_buf;
1323 chip->options |= NAND_NO_SUBPAGE_WRITE; 1480 chip->options |= NAND_NO_SUBPAGE_WRITE;
1481
1482 if (info->variant == PXA3XX_NAND_VARIANT_ARMADA370)
1483 chip->cmdfunc = armada370_nand_cmdfunc;
1484 else
1485 chip->cmdfunc = pxa3xx_nand_cmdfunc;
1324 } 1486 }
1325 1487
1326 spin_lock_init(&chip->controller->lock); 1488 spin_lock_init(&chip->controller->lock);