diff options
-rw-r--r-- | drivers/mtd/nand/raw/fsmc_nand.c | 150 |
1 files changed, 99 insertions, 51 deletions
diff --git a/drivers/mtd/nand/raw/fsmc_nand.c b/drivers/mtd/nand/raw/fsmc_nand.c index 75a825dc5a4c..28c48dcc514e 100644 --- a/drivers/mtd/nand/raw/fsmc_nand.c +++ b/drivers/mtd/nand/raw/fsmc_nand.c | |||
@@ -254,43 +254,6 @@ static inline struct fsmc_nand_data *mtd_to_fsmc(struct mtd_info *mtd) | |||
254 | } | 254 | } |
255 | 255 | ||
256 | /* | 256 | /* |
257 | * fsmc_cmd_ctrl - For facilitaing Hardware access | ||
258 | * This routine allows hardware specific access to control-lines(ALE,CLE) | ||
259 | */ | ||
260 | static void fsmc_cmd_ctrl(struct mtd_info *mtd, int cmd, unsigned int ctrl) | ||
261 | { | ||
262 | struct nand_chip *this = mtd_to_nand(mtd); | ||
263 | struct fsmc_nand_data *host = mtd_to_fsmc(mtd); | ||
264 | |||
265 | if (ctrl & NAND_CTRL_CHANGE) { | ||
266 | u32 pc; | ||
267 | |||
268 | if (ctrl & NAND_CLE) { | ||
269 | this->IO_ADDR_R = host->cmd_va; | ||
270 | this->IO_ADDR_W = host->cmd_va; | ||
271 | } else if (ctrl & NAND_ALE) { | ||
272 | this->IO_ADDR_R = host->addr_va; | ||
273 | this->IO_ADDR_W = host->addr_va; | ||
274 | } else { | ||
275 | this->IO_ADDR_R = host->data_va; | ||
276 | this->IO_ADDR_W = host->data_va; | ||
277 | } | ||
278 | |||
279 | pc = readl(host->regs_va + PC); | ||
280 | if (ctrl & NAND_NCE) | ||
281 | pc |= FSMC_ENABLE; | ||
282 | else | ||
283 | pc &= ~FSMC_ENABLE; | ||
284 | writel_relaxed(pc, host->regs_va + PC); | ||
285 | } | ||
286 | |||
287 | mb(); | ||
288 | |||
289 | if (cmd != NAND_CMD_NONE) | ||
290 | writeb_relaxed(cmd, this->IO_ADDR_W); | ||
291 | } | ||
292 | |||
293 | /* | ||
294 | * fsmc_nand_setup - FSMC (Flexible Static Memory Controller) init routine | 257 | * fsmc_nand_setup - FSMC (Flexible Static Memory Controller) init routine |
295 | * | 258 | * |
296 | * This routine initializes timing parameters related to NAND memory access in | 259 | * This routine initializes timing parameters related to NAND memory access in |
@@ -645,6 +608,102 @@ static void fsmc_write_buf_dma(struct mtd_info *mtd, const uint8_t *buf, | |||
645 | dma_xfer(host, (void *)buf, len, DMA_TO_DEVICE); | 608 | dma_xfer(host, (void *)buf, len, DMA_TO_DEVICE); |
646 | } | 609 | } |
647 | 610 | ||
611 | /* fsmc_select_chip - assert or deassert nCE */ | ||
612 | static void fsmc_select_chip(struct mtd_info *mtd, int chipnr) | ||
613 | { | ||
614 | struct fsmc_nand_data *host = mtd_to_fsmc(mtd); | ||
615 | u32 pc; | ||
616 | |||
617 | /* Support only one CS */ | ||
618 | if (chipnr > 0) | ||
619 | return; | ||
620 | |||
621 | pc = readl(host->regs_va + PC); | ||
622 | if (chipnr < 0) | ||
623 | writel_relaxed(pc & ~FSMC_ENABLE, host->regs_va + PC); | ||
624 | else | ||
625 | writel_relaxed(pc | FSMC_ENABLE, host->regs_va + PC); | ||
626 | |||
627 | /* nCE line must be asserted before starting any operation */ | ||
628 | mb(); | ||
629 | } | ||
630 | |||
631 | /* | ||
632 | * fsmc_exec_op - hook called by the core to execute NAND operations | ||
633 | * | ||
634 | * This controller is simple enough and thus does not need to use the parser | ||
635 | * provided by the core, instead, handle every situation here. | ||
636 | */ | ||
637 | static int fsmc_exec_op(struct nand_chip *chip, const struct nand_operation *op, | ||
638 | bool check_only) | ||
639 | { | ||
640 | struct mtd_info *mtd = nand_to_mtd(chip); | ||
641 | struct fsmc_nand_data *host = mtd_to_fsmc(mtd); | ||
642 | const struct nand_op_instr *instr = NULL; | ||
643 | int ret = 0; | ||
644 | unsigned int op_id; | ||
645 | int i; | ||
646 | |||
647 | pr_debug("Executing operation [%d instructions]:\n", op->ninstrs); | ||
648 | for (op_id = 0; op_id < op->ninstrs; op_id++) { | ||
649 | instr = &op->instrs[op_id]; | ||
650 | |||
651 | switch (instr->type) { | ||
652 | case NAND_OP_CMD_INSTR: | ||
653 | pr_debug(" ->CMD [0x%02x]\n", | ||
654 | instr->ctx.cmd.opcode); | ||
655 | |||
656 | writeb_relaxed(instr->ctx.cmd.opcode, host->cmd_va); | ||
657 | break; | ||
658 | |||
659 | case NAND_OP_ADDR_INSTR: | ||
660 | pr_debug(" ->ADDR [%d cyc]", | ||
661 | instr->ctx.addr.naddrs); | ||
662 | |||
663 | for (i = 0; i < instr->ctx.addr.naddrs; i++) | ||
664 | writeb_relaxed(instr->ctx.addr.addrs[i], | ||
665 | host->addr_va); | ||
666 | break; | ||
667 | |||
668 | case NAND_OP_DATA_IN_INSTR: | ||
669 | pr_debug(" ->DATA_IN [%d B%s]\n", instr->ctx.data.len, | ||
670 | instr->ctx.data.force_8bit ? | ||
671 | ", force 8-bit" : ""); | ||
672 | |||
673 | if (host->mode == USE_DMA_ACCESS) | ||
674 | fsmc_read_buf_dma(mtd, instr->ctx.data.buf.in, | ||
675 | instr->ctx.data.len); | ||
676 | else | ||
677 | fsmc_read_buf(mtd, instr->ctx.data.buf.in, | ||
678 | instr->ctx.data.len); | ||
679 | break; | ||
680 | |||
681 | case NAND_OP_DATA_OUT_INSTR: | ||
682 | pr_debug(" ->DATA_OUT [%d B%s]\n", instr->ctx.data.len, | ||
683 | instr->ctx.data.force_8bit ? | ||
684 | ", force 8-bit" : ""); | ||
685 | |||
686 | if (host->mode == USE_DMA_ACCESS) | ||
687 | fsmc_write_buf_dma(mtd, instr->ctx.data.buf.out, | ||
688 | instr->ctx.data.len); | ||
689 | else | ||
690 | fsmc_write_buf(mtd, instr->ctx.data.buf.out, | ||
691 | instr->ctx.data.len); | ||
692 | break; | ||
693 | |||
694 | case NAND_OP_WAITRDY_INSTR: | ||
695 | pr_debug(" ->WAITRDY [max %d ms]\n", | ||
696 | instr->ctx.waitrdy.timeout_ms); | ||
697 | |||
698 | ret = nand_soft_waitrdy(chip, | ||
699 | instr->ctx.waitrdy.timeout_ms); | ||
700 | break; | ||
701 | } | ||
702 | } | ||
703 | |||
704 | return ret; | ||
705 | } | ||
706 | |||
648 | /* | 707 | /* |
649 | * fsmc_read_page_hwecc | 708 | * fsmc_read_page_hwecc |
650 | * @mtd: mtd info structure | 709 | * @mtd: mtd info structure |
@@ -944,9 +1003,8 @@ static int __init fsmc_nand_probe(struct platform_device *pdev) | |||
944 | nand_set_flash_node(nand, pdev->dev.of_node); | 1003 | nand_set_flash_node(nand, pdev->dev.of_node); |
945 | 1004 | ||
946 | mtd->dev.parent = &pdev->dev; | 1005 | mtd->dev.parent = &pdev->dev; |
947 | nand->IO_ADDR_R = host->data_va; | 1006 | nand->exec_op = fsmc_exec_op; |
948 | nand->IO_ADDR_W = host->data_va; | 1007 | nand->select_chip = fsmc_select_chip; |
949 | nand->cmd_ctrl = fsmc_cmd_ctrl; | ||
950 | nand->chip_delay = 30; | 1008 | nand->chip_delay = 30; |
951 | 1009 | ||
952 | /* | 1010 | /* |
@@ -958,8 +1016,7 @@ static int __init fsmc_nand_probe(struct platform_device *pdev) | |||
958 | nand->ecc.size = 512; | 1016 | nand->ecc.size = 512; |
959 | nand->badblockbits = 7; | 1017 | nand->badblockbits = 7; |
960 | 1018 | ||
961 | switch (host->mode) { | 1019 | if (host->mode == USE_DMA_ACCESS) { |
962 | case USE_DMA_ACCESS: | ||
963 | dma_cap_zero(mask); | 1020 | dma_cap_zero(mask); |
964 | dma_cap_set(DMA_MEMCPY, mask); | 1021 | dma_cap_set(DMA_MEMCPY, mask); |
965 | host->read_dma_chan = dma_request_channel(mask, filter, NULL); | 1022 | host->read_dma_chan = dma_request_channel(mask, filter, NULL); |
@@ -972,15 +1029,6 @@ static int __init fsmc_nand_probe(struct platform_device *pdev) | |||
972 | dev_err(&pdev->dev, "Unable to get write dma channel\n"); | 1029 | dev_err(&pdev->dev, "Unable to get write dma channel\n"); |
973 | goto err_req_write_chnl; | 1030 | goto err_req_write_chnl; |
974 | } | 1031 | } |
975 | nand->read_buf = fsmc_read_buf_dma; | ||
976 | nand->write_buf = fsmc_write_buf_dma; | ||
977 | break; | ||
978 | |||
979 | default: | ||
980 | case USE_WORD_ACCESS: | ||
981 | nand->read_buf = fsmc_read_buf; | ||
982 | nand->write_buf = fsmc_write_buf; | ||
983 | break; | ||
984 | } | 1032 | } |
985 | 1033 | ||
986 | if (host->dev_timings) | 1034 | if (host->dev_timings) |