Lines Matching +full:cmd +full:- +full:dat +full:- +full:pins

1 // SPDX-License-Identifier: GPL-2.0+
7 * https://github.com/yuq/sunxi-nfc-mtd
10 * https://github.com/hno/Allwinner-Info
78 #define NFC_PAGE_SHIFT(x) (((x) < 10 ? 0 : (x) - 10) << 8)
114 #define NFC_ADR_NUM(x) (((x) - 1) << 16)
173 * native NAND R/B pins (those which can be muxed to the NAND
245 u8 cmd[2]; member
292 div_m = (clock_get_pll6() + hz - 1) / hz; in sunxi_nfc_set_clk_rate()
304 &ccm->nand0_clk_cfg); in sunxi_nfc_set_clk_rate()
307 setbits_le32(&ccm->ahb_gate0, (1 << AHB_GATE_OFFSET_NAND0)); in sunxi_nfc_set_clk_rate()
309 setbits_le32(&ccm->ahb_gate1, (1 << AHB_GATE_OFFSET_DMA)); in sunxi_nfc_set_clk_rate()
311 setbits_le32(&ccm->ahb_gate0, (1 << AHB_GATE_OFFSET_DMA)); in sunxi_nfc_set_clk_rate()
320 int ret = -ETIMEDOUT; in sunxi_nfc_wait_int()
330 status = readl(nfc->regs + NFC_REG_ST); in sunxi_nfc_wait_int()
339 writel(status & flags, nfc->regs + NFC_REG_ST); in sunxi_nfc_wait_int()
352 if (!(readl(nfc->regs + NFC_REG_ST) & NFC_CMD_FIFO_STATUS)) in sunxi_nfc_wait_cmd_fifo_empty()
356 dev_err(nfc->dev, "wait for empty cmd FIFO timedout\n"); in sunxi_nfc_wait_cmd_fifo_empty()
357 return -ETIMEDOUT; in sunxi_nfc_wait_cmd_fifo_empty()
366 writel(0, nfc->regs + NFC_REG_ECC_CTL); in sunxi_nfc_rst()
367 writel(NFC_RESET, nfc->regs + NFC_REG_CTL); in sunxi_nfc_rst()
371 if (!(readl(nfc->regs + NFC_REG_CTL) & NFC_RESET)) in sunxi_nfc_rst()
375 dev_err(nfc->dev, "wait for NAND controller reset timedout\n"); in sunxi_nfc_rst()
376 return -ETIMEDOUT; in sunxi_nfc_rst()
383 struct sunxi_nfc *nfc = to_sunxi_nfc(sunxi_nand->nand.controller); in sunxi_nfc_dev_ready()
385 unsigned long timeo = (sunxi_nand->nand.state == FL_ERASING ? 400 : 20); in sunxi_nfc_dev_ready()
388 if (sunxi_nand->selected < 0) in sunxi_nfc_dev_ready()
391 rb = &sunxi_nand->sels[sunxi_nand->selected].rb; in sunxi_nfc_dev_ready()
393 switch (rb->type) { in sunxi_nfc_dev_ready()
395 ret = !!(readl(nfc->regs + NFC_REG_ST) & in sunxi_nfc_dev_ready()
396 NFC_RB_STATE(rb->info.nativeid)); in sunxi_nfc_dev_ready()
401 ret = !!(readl(nfc->regs + NFC_REG_ST) & in sunxi_nfc_dev_ready()
402 NFC_RB_STATE(rb->info.nativeid)); in sunxi_nfc_dev_ready()
405 ret = dm_gpio_get_value(&rb->info.gpio); in sunxi_nfc_dev_ready()
410 dev_err(nfc->dev, "cannot check R/B NAND status!\n"); in sunxi_nfc_dev_ready()
421 struct sunxi_nfc *nfc = to_sunxi_nfc(sunxi_nand->nand.controller); in sunxi_nfc_select_chip()
425 if (chip > 0 && chip >= sunxi_nand->nsels) in sunxi_nfc_select_chip()
428 if (chip == sunxi_nand->selected) in sunxi_nfc_select_chip()
431 ctl = readl(nfc->regs + NFC_REG_CTL) & in sunxi_nfc_select_chip()
435 sel = &sunxi_nand->sels[chip]; in sunxi_nfc_select_chip()
437 ctl |= NFC_CE_SEL(sel->cs) | NFC_EN | in sunxi_nfc_select_chip()
438 NFC_PAGE_SHIFT(nand->page_shift - 10); in sunxi_nfc_select_chip()
439 if (sel->rb.type == RB_NONE) { in sunxi_nfc_select_chip()
440 nand->dev_ready = NULL; in sunxi_nfc_select_chip()
442 nand->dev_ready = sunxi_nfc_dev_ready; in sunxi_nfc_select_chip()
443 if (sel->rb.type == RB_NATIVE) in sunxi_nfc_select_chip()
444 ctl |= NFC_RB_SEL(sel->rb.info.nativeid); in sunxi_nfc_select_chip()
447 writel(mtd->writesize, nfc->regs + NFC_REG_SPARE_AREA); in sunxi_nfc_select_chip()
449 if (nfc->clk_rate != sunxi_nand->clk_rate) { in sunxi_nfc_select_chip()
450 sunxi_nfc_set_clk_rate(sunxi_nand->clk_rate); in sunxi_nfc_select_chip()
451 nfc->clk_rate = sunxi_nand->clk_rate; in sunxi_nfc_select_chip()
455 writel(sunxi_nand->timing_ctl, nfc->regs + NFC_REG_TIMING_CTL); in sunxi_nfc_select_chip()
456 writel(sunxi_nand->timing_cfg, nfc->regs + NFC_REG_TIMING_CFG); in sunxi_nfc_select_chip()
457 writel(ctl, nfc->regs + NFC_REG_CTL); in sunxi_nfc_select_chip()
459 sunxi_nand->selected = chip; in sunxi_nfc_select_chip()
466 struct sunxi_nfc *nfc = to_sunxi_nfc(sunxi_nand->nand.controller); in sunxi_nfc_read_buf()
473 cnt = min(len - offs, NFC_SRAM_SIZE); in sunxi_nfc_read_buf()
479 writel(cnt, nfc->regs + NFC_REG_CNT); in sunxi_nfc_read_buf()
481 writel(tmp, nfc->regs + NFC_REG_CMD); in sunxi_nfc_read_buf()
488 memcpy_fromio(buf + offs, nfc->regs + NFC_RAM0_BASE, in sunxi_nfc_read_buf()
499 struct sunxi_nfc *nfc = to_sunxi_nfc(sunxi_nand->nand.controller); in sunxi_nfc_write_buf()
506 cnt = min(len - offs, NFC_SRAM_SIZE); in sunxi_nfc_write_buf()
512 writel(cnt, nfc->regs + NFC_REG_CNT); in sunxi_nfc_write_buf()
513 memcpy_toio(nfc->regs + NFC_RAM0_BASE, buf + offs, cnt); in sunxi_nfc_write_buf()
516 writel(tmp, nfc->regs + NFC_REG_CMD); in sunxi_nfc_write_buf()
535 static void sunxi_nfc_cmd_ctrl(struct mtd_info *mtd, int dat, in sunxi_nfc_cmd_ctrl() argument
540 struct sunxi_nfc *nfc = to_sunxi_nfc(sunxi_nand->nand.controller); in sunxi_nfc_cmd_ctrl()
549 tmp = readl(nfc->regs + NFC_REG_CTL); in sunxi_nfc_cmd_ctrl()
554 writel(tmp, nfc->regs + NFC_REG_CTL); in sunxi_nfc_cmd_ctrl()
557 if (dat == NAND_CMD_NONE && (ctrl & NAND_NCE) && in sunxi_nfc_cmd_ctrl()
559 u32 cmd = 0; in sunxi_nfc_cmd_ctrl() local
561 if (!sunxi_nand->addr_cycles && !sunxi_nand->cmd_cycles) in sunxi_nfc_cmd_ctrl()
564 if (sunxi_nand->cmd_cycles--) in sunxi_nfc_cmd_ctrl()
565 cmd |= NFC_SEND_CMD1 | sunxi_nand->cmd[0]; in sunxi_nfc_cmd_ctrl()
567 if (sunxi_nand->cmd_cycles--) { in sunxi_nfc_cmd_ctrl()
568 cmd |= NFC_SEND_CMD2; in sunxi_nfc_cmd_ctrl()
569 writel(sunxi_nand->cmd[1], in sunxi_nfc_cmd_ctrl()
570 nfc->regs + NFC_REG_RCMD_SET); in sunxi_nfc_cmd_ctrl()
573 sunxi_nand->cmd_cycles = 0; in sunxi_nfc_cmd_ctrl()
575 if (sunxi_nand->addr_cycles) { in sunxi_nfc_cmd_ctrl()
576 cmd |= NFC_SEND_ADR | in sunxi_nfc_cmd_ctrl()
577 NFC_ADR_NUM(sunxi_nand->addr_cycles); in sunxi_nfc_cmd_ctrl()
578 writel(sunxi_nand->addr[0], in sunxi_nfc_cmd_ctrl()
579 nfc->regs + NFC_REG_ADDR_LOW); in sunxi_nfc_cmd_ctrl()
582 if (sunxi_nand->addr_cycles > 4) in sunxi_nfc_cmd_ctrl()
583 writel(sunxi_nand->addr[1], in sunxi_nfc_cmd_ctrl()
584 nfc->regs + NFC_REG_ADDR_HIGH); in sunxi_nfc_cmd_ctrl()
586 writel(cmd, nfc->regs + NFC_REG_CMD); in sunxi_nfc_cmd_ctrl()
587 sunxi_nand->addr[0] = 0; in sunxi_nfc_cmd_ctrl()
588 sunxi_nand->addr[1] = 0; in sunxi_nfc_cmd_ctrl()
589 sunxi_nand->addr_cycles = 0; in sunxi_nfc_cmd_ctrl()
594 sunxi_nand->cmd[sunxi_nand->cmd_cycles++] = dat; in sunxi_nfc_cmd_ctrl()
596 sunxi_nand->addr[sunxi_nand->addr_cycles / 4] |= in sunxi_nfc_cmd_ctrl()
597 dat << ((sunxi_nand->addr_cycles % 4) * 8); in sunxi_nfc_cmd_ctrl()
598 sunxi_nand->addr_cycles++; in sunxi_nfc_cmd_ctrl()
677 while (count--) in sunxi_nfc_randomizer_step()
687 int mod = mtd->erasesize / mtd->writesize; in sunxi_nfc_randomizer_state()
693 if (mtd->ecc_step_size == 512) in sunxi_nfc_randomizer_state()
706 struct sunxi_nfc *nfc = to_sunxi_nfc(nand->controller); in sunxi_nfc_randomizer_config()
707 u32 ecc_ctl = readl(nfc->regs + NFC_REG_ECC_CTL); in sunxi_nfc_randomizer_config()
710 if (!(nand->options & NAND_NEED_SCRAMBLING)) in sunxi_nfc_randomizer_config()
713 ecc_ctl = readl(nfc->regs + NFC_REG_ECC_CTL); in sunxi_nfc_randomizer_config()
715 ecc_ctl = readl(nfc->regs + NFC_REG_ECC_CTL) & ~NFC_RANDOM_SEED_MSK; in sunxi_nfc_randomizer_config()
716 writel(ecc_ctl | NFC_RANDOM_SEED(state), nfc->regs + NFC_REG_ECC_CTL); in sunxi_nfc_randomizer_config()
722 struct sunxi_nfc *nfc = to_sunxi_nfc(nand->controller); in sunxi_nfc_randomizer_enable()
724 if (!(nand->options & NAND_NEED_SCRAMBLING)) in sunxi_nfc_randomizer_enable()
727 writel(readl(nfc->regs + NFC_REG_ECC_CTL) | NFC_RANDOM_EN, in sunxi_nfc_randomizer_enable()
728 nfc->regs + NFC_REG_ECC_CTL); in sunxi_nfc_randomizer_enable()
734 struct sunxi_nfc *nfc = to_sunxi_nfc(nand->controller); in sunxi_nfc_randomizer_disable()
736 if (!(nand->options & NAND_NEED_SCRAMBLING)) in sunxi_nfc_randomizer_disable()
739 writel(readl(nfc->regs + NFC_REG_ECC_CTL) & ~NFC_RANDOM_EN, in sunxi_nfc_randomizer_disable()
740 nfc->regs + NFC_REG_ECC_CTL); in sunxi_nfc_randomizer_disable()
773 struct sunxi_nfc *nfc = to_sunxi_nfc(nand->controller); in sunxi_nfc_hw_ecc_enable()
774 struct sunxi_nand_hw_ecc *data = nand->ecc.priv; in sunxi_nfc_hw_ecc_enable()
777 ecc_ctl = readl(nfc->regs + NFC_REG_ECC_CTL); in sunxi_nfc_hw_ecc_enable()
780 ecc_ctl |= NFC_ECC_EN | NFC_ECC_MODE(data->mode) | NFC_ECC_EXCEPTION; in sunxi_nfc_hw_ecc_enable()
782 if (nand->ecc.size == 512) in sunxi_nfc_hw_ecc_enable()
785 writel(ecc_ctl, nfc->regs + NFC_REG_ECC_CTL); in sunxi_nfc_hw_ecc_enable()
791 struct sunxi_nfc *nfc = to_sunxi_nfc(nand->controller); in sunxi_nfc_hw_ecc_disable()
793 writel(readl(nfc->regs + NFC_REG_ECC_CTL) & ~NFC_ECC_EN, in sunxi_nfc_hw_ecc_disable()
794 nfc->regs + NFC_REG_ECC_CTL); in sunxi_nfc_hw_ecc_disable()
813 struct sunxi_nfc *nfc = to_sunxi_nfc(nand->controller); in sunxi_nfc_hw_ecc_read_chunk()
814 struct nand_ecc_ctrl *ecc = &nand->ecc; in sunxi_nfc_hw_ecc_read_chunk()
820 nand->cmdfunc(mtd, NAND_CMD_RNDOUT, data_off, -1); in sunxi_nfc_hw_ecc_read_chunk()
822 sunxi_nfc_randomizer_read_buf(mtd, NULL, ecc->size, false, page); in sunxi_nfc_hw_ecc_read_chunk()
824 if (data_off + ecc->size != oob_off) in sunxi_nfc_hw_ecc_read_chunk()
825 nand->cmdfunc(mtd, NAND_CMD_RNDOUT, oob_off, -1); in sunxi_nfc_hw_ecc_read_chunk()
833 nfc->regs + NFC_REG_CMD); in sunxi_nfc_hw_ecc_read_chunk()
840 *cur_off = oob_off + ecc->bytes + 4; in sunxi_nfc_hw_ecc_read_chunk()
842 status = readl(nfc->regs + NFC_REG_ECC_ST); in sunxi_nfc_hw_ecc_read_chunk()
846 if (unlikely(!(readl(nfc->regs + NFC_REG_PAT_ID) & 0x1))) in sunxi_nfc_hw_ecc_read_chunk()
849 memset(data, pattern, ecc->size); in sunxi_nfc_hw_ecc_read_chunk()
850 memset(oob, pattern, ecc->bytes + 4); in sunxi_nfc_hw_ecc_read_chunk()
855 ret = NFC_ECC_ERR_CNT(0, readl(nfc->regs + NFC_REG_ECC_ERR_CNT(0))); in sunxi_nfc_hw_ecc_read_chunk()
857 memcpy_fromio(data, nfc->regs + NFC_RAM0_BASE, ecc->size); in sunxi_nfc_hw_ecc_read_chunk()
859 nand->cmdfunc(mtd, NAND_CMD_RNDOUT, oob_off, -1); in sunxi_nfc_hw_ecc_read_chunk()
860 sunxi_nfc_randomizer_read_buf(mtd, oob, ecc->bytes + 4, true, page); in sunxi_nfc_hw_ecc_read_chunk()
864 * Re-read the data with the randomizer disabled to identify in sunxi_nfc_hw_ecc_read_chunk()
867 if (nand->options & NAND_NEED_SCRAMBLING) { in sunxi_nfc_hw_ecc_read_chunk()
868 nand->cmdfunc(mtd, NAND_CMD_RNDOUT, data_off, -1); in sunxi_nfc_hw_ecc_read_chunk()
869 nand->read_buf(mtd, data, ecc->size); in sunxi_nfc_hw_ecc_read_chunk()
870 nand->cmdfunc(mtd, NAND_CMD_RNDOUT, oob_off, -1); in sunxi_nfc_hw_ecc_read_chunk()
871 nand->read_buf(mtd, oob, ecc->bytes + 4); in sunxi_nfc_hw_ecc_read_chunk()
874 ret = nand_check_erased_ecc_chunk(data, ecc->size, in sunxi_nfc_hw_ecc_read_chunk()
875 oob, ecc->bytes + 4, in sunxi_nfc_hw_ecc_read_chunk()
876 NULL, 0, ecc->strength); in sunxi_nfc_hw_ecc_read_chunk()
884 sunxi_nfc_user_data_to_buf(readl(nfc->regs + in sunxi_nfc_hw_ecc_read_chunk()
888 /* De-randomize the Bad Block Marker. */ in sunxi_nfc_hw_ecc_read_chunk()
889 if (bbm && nand->options & NAND_NEED_SCRAMBLING) in sunxi_nfc_hw_ecc_read_chunk()
894 mtd->ecc_stats.failed++; in sunxi_nfc_hw_ecc_read_chunk()
896 mtd->ecc_stats.corrected += ret; in sunxi_nfc_hw_ecc_read_chunk()
908 struct nand_ecc_ctrl *ecc = &nand->ecc; in sunxi_nfc_hw_ecc_read_extra_oob()
909 int offset = ((ecc->bytes + 4) * ecc->steps); in sunxi_nfc_hw_ecc_read_extra_oob()
910 int len = mtd->oobsize - offset; in sunxi_nfc_hw_ecc_read_extra_oob()
916 nand->cmdfunc(mtd, NAND_CMD_RNDOUT, in sunxi_nfc_hw_ecc_read_extra_oob()
917 offset + mtd->writesize, -1); in sunxi_nfc_hw_ecc_read_extra_oob()
925 *cur_off = mtd->oobsize + mtd->writesize; in sunxi_nfc_hw_ecc_read_extra_oob()
940 struct sunxi_nfc *nfc = to_sunxi_nfc(nand->controller); in sunxi_nfc_hw_ecc_write_chunk()
941 struct nand_ecc_ctrl *ecc = &nand->ecc; in sunxi_nfc_hw_ecc_write_chunk()
945 nand->cmdfunc(mtd, NAND_CMD_RNDIN, data_off, -1); in sunxi_nfc_hw_ecc_write_chunk()
947 sunxi_nfc_randomizer_write_buf(mtd, data, ecc->size, false, page); in sunxi_nfc_hw_ecc_write_chunk()
950 if ((nand->options & NAND_NEED_SCRAMBLING) && bbm) { in sunxi_nfc_hw_ecc_write_chunk()
956 nfc->regs + NFC_REG_USER_DATA(0)); in sunxi_nfc_hw_ecc_write_chunk()
959 nfc->regs + NFC_REG_USER_DATA(0)); in sunxi_nfc_hw_ecc_write_chunk()
962 if (data_off + ecc->size != oob_off) in sunxi_nfc_hw_ecc_write_chunk()
963 nand->cmdfunc(mtd, NAND_CMD_RNDIN, oob_off, -1); in sunxi_nfc_hw_ecc_write_chunk()
972 nfc->regs + NFC_REG_CMD); in sunxi_nfc_hw_ecc_write_chunk()
979 *cur_off = oob_off + ecc->bytes + 4; in sunxi_nfc_hw_ecc_write_chunk()
989 struct nand_ecc_ctrl *ecc = &nand->ecc; in sunxi_nfc_hw_ecc_write_extra_oob()
990 int offset = ((ecc->bytes + 4) * ecc->steps); in sunxi_nfc_hw_ecc_write_extra_oob()
991 int len = mtd->oobsize - offset; in sunxi_nfc_hw_ecc_write_extra_oob()
997 nand->cmdfunc(mtd, NAND_CMD_RNDIN, in sunxi_nfc_hw_ecc_write_extra_oob()
998 offset + mtd->writesize, -1); in sunxi_nfc_hw_ecc_write_extra_oob()
1002 *cur_off = mtd->oobsize + mtd->writesize; in sunxi_nfc_hw_ecc_write_extra_oob()
1009 struct nand_ecc_ctrl *ecc = &chip->ecc; in sunxi_nfc_hw_ecc_read_page()
1016 for (i = 0; i < ecc->steps; i++) { in sunxi_nfc_hw_ecc_read_page()
1017 int data_off = i * ecc->size; in sunxi_nfc_hw_ecc_read_page()
1018 int oob_off = i * (ecc->bytes + 4); in sunxi_nfc_hw_ecc_read_page()
1020 u8 *oob = chip->oob_poi + oob_off; in sunxi_nfc_hw_ecc_read_page()
1023 oob_off + mtd->writesize, in sunxi_nfc_hw_ecc_read_page()
1033 sunxi_nfc_hw_ecc_read_extra_oob(mtd, chip->oob_poi, &cur_off, in sunxi_nfc_hw_ecc_read_page()
1046 struct nand_ecc_ctrl *ecc = &chip->ecc; in sunxi_nfc_hw_ecc_read_subpage()
1052 chip->cmdfunc(mtd, NAND_CMD_READ0, 0, page); in sunxi_nfc_hw_ecc_read_subpage()
1053 for (i = data_offs / ecc->size; in sunxi_nfc_hw_ecc_read_subpage()
1054 i < DIV_ROUND_UP(data_offs + readlen, ecc->size); i++) { in sunxi_nfc_hw_ecc_read_subpage()
1055 int data_off = i * ecc->size; in sunxi_nfc_hw_ecc_read_subpage()
1056 int oob_off = i * (ecc->bytes + 4); in sunxi_nfc_hw_ecc_read_subpage()
1058 u8 *oob = chip->oob_poi + oob_off; in sunxi_nfc_hw_ecc_read_subpage()
1061 oob, oob_off + mtd->writesize, in sunxi_nfc_hw_ecc_read_subpage()
1077 struct nand_ecc_ctrl *ecc = &chip->ecc; in sunxi_nfc_hw_ecc_write_page()
1082 for (i = 0; i < ecc->steps; i++) { in sunxi_nfc_hw_ecc_write_page()
1083 int data_off = i * ecc->size; in sunxi_nfc_hw_ecc_write_page()
1084 int oob_off = i * (ecc->bytes + 4); in sunxi_nfc_hw_ecc_write_page()
1086 const u8 *oob = chip->oob_poi + oob_off; in sunxi_nfc_hw_ecc_write_page()
1089 oob_off + mtd->writesize, in sunxi_nfc_hw_ecc_write_page()
1095 if (oob_required || (chip->options & NAND_NEED_SCRAMBLING)) in sunxi_nfc_hw_ecc_write_page()
1096 sunxi_nfc_hw_ecc_write_extra_oob(mtd, chip->oob_poi, in sunxi_nfc_hw_ecc_write_page()
1110 struct nand_ecc_ctrl *ecc = &chip->ecc; in sunxi_nfc_hw_ecc_write_subpage()
1115 for (i = data_offs / ecc->size; in sunxi_nfc_hw_ecc_write_subpage()
1116 i < DIV_ROUND_UP(data_offs + data_len, ecc->size); i++) { in sunxi_nfc_hw_ecc_write_subpage()
1117 int data_off = i * ecc->size; in sunxi_nfc_hw_ecc_write_subpage()
1118 int oob_off = i * (ecc->bytes + 4); in sunxi_nfc_hw_ecc_write_subpage()
1120 const u8 *oob = chip->oob_poi + oob_off; in sunxi_nfc_hw_ecc_write_subpage()
1123 oob_off + mtd->writesize, in sunxi_nfc_hw_ecc_write_subpage()
1139 struct nand_ecc_ctrl *ecc = &chip->ecc; in sunxi_nfc_hw_syndrome_ecc_read_page()
1146 for (i = 0; i < ecc->steps; i++) { in sunxi_nfc_hw_syndrome_ecc_read_page()
1147 int data_off = i * (ecc->size + ecc->bytes + 4); in sunxi_nfc_hw_syndrome_ecc_read_page()
1148 int oob_off = data_off + ecc->size; in sunxi_nfc_hw_syndrome_ecc_read_page()
1149 u8 *data = buf + (i * ecc->size); in sunxi_nfc_hw_syndrome_ecc_read_page()
1150 u8 *oob = chip->oob_poi + (i * (ecc->bytes + 4)); in sunxi_nfc_hw_syndrome_ecc_read_page()
1162 sunxi_nfc_hw_ecc_read_extra_oob(mtd, chip->oob_poi, &cur_off, in sunxi_nfc_hw_syndrome_ecc_read_page()
1175 struct nand_ecc_ctrl *ecc = &chip->ecc; in sunxi_nfc_hw_syndrome_ecc_write_page()
1180 for (i = 0; i < ecc->steps; i++) { in sunxi_nfc_hw_syndrome_ecc_write_page()
1181 int data_off = i * (ecc->size + ecc->bytes + 4); in sunxi_nfc_hw_syndrome_ecc_write_page()
1182 int oob_off = data_off + ecc->size; in sunxi_nfc_hw_syndrome_ecc_write_page()
1183 const u8 *data = buf + (i * ecc->size); in sunxi_nfc_hw_syndrome_ecc_write_page()
1184 const u8 *oob = chip->oob_poi + (i * (ecc->bytes + 4)); in sunxi_nfc_hw_syndrome_ecc_write_page()
1193 if (oob_required || (chip->options & NAND_NEED_SCRAMBLING)) in sunxi_nfc_hw_syndrome_ecc_write_page()
1194 sunxi_nfc_hw_ecc_write_extra_oob(mtd, chip->oob_poi, in sunxi_nfc_hw_syndrome_ecc_write_page()
1217 return -EINVAL; in _sunxi_nand_lookup_timing()
1230 if (timings->tCLS_min > min_clk_period) in sunxi_nand_chip_set_timings()
1231 min_clk_period = timings->tCLS_min; in sunxi_nand_chip_set_timings()
1234 if (timings->tCLH_min > min_clk_period) in sunxi_nand_chip_set_timings()
1235 min_clk_period = timings->tCLH_min; in sunxi_nand_chip_set_timings()
1238 if (timings->tCS_min > min_clk_period) in sunxi_nand_chip_set_timings()
1239 min_clk_period = timings->tCS_min; in sunxi_nand_chip_set_timings()
1242 if (timings->tCH_min > min_clk_period) in sunxi_nand_chip_set_timings()
1243 min_clk_period = timings->tCH_min; in sunxi_nand_chip_set_timings()
1246 if (timings->tWP_min > min_clk_period) in sunxi_nand_chip_set_timings()
1247 min_clk_period = timings->tWP_min; in sunxi_nand_chip_set_timings()
1250 if (timings->tWH_min > min_clk_period) in sunxi_nand_chip_set_timings()
1251 min_clk_period = timings->tWH_min; in sunxi_nand_chip_set_timings()
1254 if (timings->tALS_min > min_clk_period) in sunxi_nand_chip_set_timings()
1255 min_clk_period = timings->tALS_min; in sunxi_nand_chip_set_timings()
1258 if (timings->tDS_min > min_clk_period) in sunxi_nand_chip_set_timings()
1259 min_clk_period = timings->tDS_min; in sunxi_nand_chip_set_timings()
1262 if (timings->tDH_min > min_clk_period) in sunxi_nand_chip_set_timings()
1263 min_clk_period = timings->tDH_min; in sunxi_nand_chip_set_timings()
1266 if (timings->tRR_min > (min_clk_period * 3)) in sunxi_nand_chip_set_timings()
1267 min_clk_period = DIV_ROUND_UP(timings->tRR_min, 3); in sunxi_nand_chip_set_timings()
1270 if (timings->tALH_min > min_clk_period) in sunxi_nand_chip_set_timings()
1271 min_clk_period = timings->tALH_min; in sunxi_nand_chip_set_timings()
1274 if (timings->tRP_min > min_clk_period) in sunxi_nand_chip_set_timings()
1275 min_clk_period = timings->tRP_min; in sunxi_nand_chip_set_timings()
1278 if (timings->tREH_min > min_clk_period) in sunxi_nand_chip_set_timings()
1279 min_clk_period = timings->tREH_min; in sunxi_nand_chip_set_timings()
1282 if (timings->tRC_min > (min_clk_period * 2)) in sunxi_nand_chip_set_timings()
1283 min_clk_period = DIV_ROUND_UP(timings->tRC_min, 2); in sunxi_nand_chip_set_timings()
1286 if (timings->tWC_min > (min_clk_period * 2)) in sunxi_nand_chip_set_timings()
1287 min_clk_period = DIV_ROUND_UP(timings->tWC_min, 2); in sunxi_nand_chip_set_timings()
1289 /* T16 - T19 + tCAD */ in sunxi_nand_chip_set_timings()
1290 tWB = sunxi_nand_lookup_timing(tWB_lut, timings->tWB_max, in sunxi_nand_chip_set_timings()
1293 dev_err(nfc->dev, "unsupported tWB\n"); in sunxi_nand_chip_set_timings()
1297 tADL = DIV_ROUND_UP(timings->tADL_min, min_clk_period) >> 3; in sunxi_nand_chip_set_timings()
1299 dev_err(nfc->dev, "unsupported tADL\n"); in sunxi_nand_chip_set_timings()
1300 return -EINVAL; in sunxi_nand_chip_set_timings()
1303 tWHR = DIV_ROUND_UP(timings->tWHR_min, min_clk_period) >> 3; in sunxi_nand_chip_set_timings()
1305 dev_err(nfc->dev, "unsupported tWHR\n"); in sunxi_nand_chip_set_timings()
1306 return -EINVAL; in sunxi_nand_chip_set_timings()
1309 tRHW = sunxi_nand_lookup_timing(tRHW_lut, timings->tRHW_min, in sunxi_nand_chip_set_timings()
1312 dev_err(nfc->dev, "unsupported tRHW\n"); in sunxi_nand_chip_set_timings()
1323 chip->timing_cfg = NFC_TIMING_CFG(tWB, tADL, tWHR, tRHW, tCAD); in sunxi_nand_chip_set_timings()
1330 chip->timing_ctl = (timings->tRC_min < 30000) ? NFC_TIMING_CTL_EDO : 0; in sunxi_nand_chip_set_timings()
1341 chip->clk_rate = 1000000000L / min_clk_period; in sunxi_nand_chip_set_timings()
1348 struct mtd_info *mtd = nand_to_mtd(&chip->nand); in sunxi_nand_chip_init_timings()
1353 mode = onfi_get_async_timing_mode(&chip->nand); in sunxi_nand_chip_init_timings()
1355 mode = chip->nand.onfi_timing_mode_default; in sunxi_nand_chip_init_timings()
1360 mode = fls(mode) - 1; in sunxi_nand_chip_init_timings()
1365 for (i = 0; i < chip->nsels; i++) { in sunxi_nand_chip_init_timings()
1366 chip->nand.select_chip(mtd, i); in sunxi_nand_chip_init_timings()
1367 ret = chip->nand.onfi_set_features(mtd, in sunxi_nand_chip_init_timings()
1368 &chip->nand, in sunxi_nand_chip_init_timings()
1371 chip->nand.select_chip(mtd, -1); in sunxi_nand_chip_init_timings()
1372 if (ret && ret != -ENOTSUPP) in sunxi_nand_chip_init_timings()
1396 return -ENOMEM; in sunxi_nand_hw_common_ecc_ctrl_init()
1398 if (ecc->size != 512 && ecc->size != 1024) in sunxi_nand_hw_common_ecc_ctrl_init()
1399 return -EINVAL; in sunxi_nand_hw_common_ecc_ctrl_init()
1402 if (ecc->size == 512 && mtd->writesize > 512) { in sunxi_nand_hw_common_ecc_ctrl_init()
1403 ecc->size = 1024; in sunxi_nand_hw_common_ecc_ctrl_init()
1404 ecc->strength *= 2; in sunxi_nand_hw_common_ecc_ctrl_init()
1409 if (ecc->strength <= strengths[i]) { in sunxi_nand_hw_common_ecc_ctrl_init()
1411 * Update ecc->strength value with the actual strength in sunxi_nand_hw_common_ecc_ctrl_init()
1414 ecc->strength = strengths[i]; in sunxi_nand_hw_common_ecc_ctrl_init()
1420 dev_err(nfc->dev, "unsupported strength\n"); in sunxi_nand_hw_common_ecc_ctrl_init()
1421 ret = -ENOTSUPP; in sunxi_nand_hw_common_ecc_ctrl_init()
1425 data->mode = i; in sunxi_nand_hw_common_ecc_ctrl_init()
1428 ecc->bytes = DIV_ROUND_UP(ecc->strength * fls(8 * 1024), 8); in sunxi_nand_hw_common_ecc_ctrl_init()
1431 ecc->bytes = ALIGN(ecc->bytes, 2); in sunxi_nand_hw_common_ecc_ctrl_init()
1433 layout = &data->layout; in sunxi_nand_hw_common_ecc_ctrl_init()
1434 nsectors = mtd->writesize / ecc->size; in sunxi_nand_hw_common_ecc_ctrl_init()
1436 if (mtd->oobsize < ((ecc->bytes + 4) * nsectors)) { in sunxi_nand_hw_common_ecc_ctrl_init()
1437 ret = -EINVAL; in sunxi_nand_hw_common_ecc_ctrl_init()
1441 layout->eccbytes = (ecc->bytes * nsectors); in sunxi_nand_hw_common_ecc_ctrl_init()
1443 ecc->layout = layout; in sunxi_nand_hw_common_ecc_ctrl_init()
1444 ecc->priv = data; in sunxi_nand_hw_common_ecc_ctrl_init()
1457 kfree(ecc->priv); in sunxi_nand_hw_common_ecc_ctrl_cleanup()
1473 ecc->read_page = sunxi_nfc_hw_ecc_read_page; in sunxi_nand_hw_ecc_ctrl_init()
1474 ecc->write_page = sunxi_nfc_hw_ecc_write_page; in sunxi_nand_hw_ecc_ctrl_init()
1475 ecc->read_subpage = sunxi_nfc_hw_ecc_read_subpage; in sunxi_nand_hw_ecc_ctrl_init()
1476 ecc->write_subpage = sunxi_nfc_hw_ecc_write_subpage; in sunxi_nand_hw_ecc_ctrl_init()
1477 layout = ecc->layout; in sunxi_nand_hw_ecc_ctrl_init()
1478 nsectors = mtd->writesize / ecc->size; in sunxi_nand_hw_ecc_ctrl_init()
1482 layout->oobfree[i].offset = in sunxi_nand_hw_ecc_ctrl_init()
1483 layout->oobfree[i - 1].offset + in sunxi_nand_hw_ecc_ctrl_init()
1484 layout->oobfree[i - 1].length + in sunxi_nand_hw_ecc_ctrl_init()
1485 ecc->bytes; in sunxi_nand_hw_ecc_ctrl_init()
1486 layout->oobfree[i].length = 4; in sunxi_nand_hw_ecc_ctrl_init()
1493 layout->oobfree[i].length = 2; in sunxi_nand_hw_ecc_ctrl_init()
1494 layout->oobfree[i].offset = 2; in sunxi_nand_hw_ecc_ctrl_init()
1497 for (j = 0; j < ecc->bytes; j++) in sunxi_nand_hw_ecc_ctrl_init()
1498 layout->eccpos[(ecc->bytes * i) + j] = in sunxi_nand_hw_ecc_ctrl_init()
1499 layout->oobfree[i].offset + in sunxi_nand_hw_ecc_ctrl_init()
1500 layout->oobfree[i].length + j; in sunxi_nand_hw_ecc_ctrl_init()
1503 if (mtd->oobsize > (ecc->bytes + 4) * nsectors) { in sunxi_nand_hw_ecc_ctrl_init()
1504 layout->oobfree[nsectors].offset = in sunxi_nand_hw_ecc_ctrl_init()
1505 layout->oobfree[nsectors - 1].offset + in sunxi_nand_hw_ecc_ctrl_init()
1506 layout->oobfree[nsectors - 1].length + in sunxi_nand_hw_ecc_ctrl_init()
1507 ecc->bytes; in sunxi_nand_hw_ecc_ctrl_init()
1508 layout->oobfree[nsectors].length = mtd->oobsize - in sunxi_nand_hw_ecc_ctrl_init()
1509 ((ecc->bytes + 4) * nsectors); in sunxi_nand_hw_ecc_ctrl_init()
1527 ecc->prepad = 4; in sunxi_nand_hw_syndrome_ecc_ctrl_init()
1528 ecc->read_page = sunxi_nfc_hw_syndrome_ecc_read_page; in sunxi_nand_hw_syndrome_ecc_ctrl_init()
1529 ecc->write_page = sunxi_nfc_hw_syndrome_ecc_write_page; in sunxi_nand_hw_syndrome_ecc_ctrl_init()
1531 layout = ecc->layout; in sunxi_nand_hw_syndrome_ecc_ctrl_init()
1532 nsectors = mtd->writesize / ecc->size; in sunxi_nand_hw_syndrome_ecc_ctrl_init()
1534 for (i = 0; i < (ecc->bytes * nsectors); i++) in sunxi_nand_hw_syndrome_ecc_ctrl_init()
1535 layout->eccpos[i] = i; in sunxi_nand_hw_syndrome_ecc_ctrl_init()
1537 layout->oobfree[0].length = mtd->oobsize - i; in sunxi_nand_hw_syndrome_ecc_ctrl_init()
1538 layout->oobfree[0].offset = i; in sunxi_nand_hw_syndrome_ecc_ctrl_init()
1546 switch (ecc->mode) { in sunxi_nand_ecc_cleanup()
1552 kfree(ecc->layout); in sunxi_nand_ecc_cleanup()
1564 if (!ecc->size) { in sunxi_nand_ecc_init()
1565 ecc->size = nand->ecc_step_ds; in sunxi_nand_ecc_init()
1566 ecc->strength = nand->ecc_strength_ds; in sunxi_nand_ecc_init()
1569 if (!ecc->size || !ecc->strength) in sunxi_nand_ecc_init()
1570 return -EINVAL; in sunxi_nand_ecc_init()
1572 switch (ecc->mode) { in sunxi_nand_ecc_init()
1586 ecc->layout = kzalloc(sizeof(*ecc->layout), GFP_KERNEL); in sunxi_nand_ecc_init()
1587 if (!ecc->layout) in sunxi_nand_ecc_init()
1588 return -ENOMEM; in sunxi_nand_ecc_init()
1589 ecc->layout->oobfree[0].length = mtd->oobsize; in sunxi_nand_ecc_init()
1593 return -EINVAL; in sunxi_nand_ecc_init()
1602 const void *blob = gd->fdt_blob; in sunxi_nand_chip_init()
1612 return -EINVAL; in sunxi_nand_chip_init()
1617 return -EINVAL; in sunxi_nand_chip_init()
1625 return -ENOMEM; in sunxi_nand_chip_init()
1628 chip->nsels = nsels; in sunxi_nand_chip_init()
1629 chip->selected = -1; in sunxi_nand_chip_init()
1632 cs[i] = -1; in sunxi_nand_chip_init()
1633 rb[i] = -1; in sunxi_nand_chip_init()
1636 ret = fdtdec_get_int_array(gd->fdt_blob, node, "reg", cs, nsels); in sunxi_nand_chip_init()
1642 ret = fdtdec_get_int_array(gd->fdt_blob, node, "allwinner,rb", rb, in sunxi_nand_chip_init()
1656 return -EINVAL; in sunxi_nand_chip_init()
1659 if (test_and_set_bit(tmp, &nfc->assigned_cs)) { in sunxi_nand_chip_init()
1661 return -EINVAL; in sunxi_nand_chip_init()
1664 chip->sels[i].cs = tmp; in sunxi_nand_chip_init()
1668 chip->sels[i].rb.type = RB_NATIVE; in sunxi_nand_chip_init()
1669 chip->sels[i].rb.info.nativeid = tmp; in sunxi_nand_chip_init()
1672 "rb-gpios", i, in sunxi_nand_chip_init()
1673 &chip->sels[i].rb.info.gpio, in sunxi_nand_chip_init()
1676 chip->sels[i].rb.type = RB_GPIO; in sunxi_nand_chip_init()
1678 chip->sels[i].rb.type = RB_NONE; in sunxi_nand_chip_init()
1697 nand = &chip->nand; in sunxi_nand_chip_init()
1699 nand->chip_delay = 200; in sunxi_nand_chip_init()
1700 nand->controller = &nfc->controller; in sunxi_nand_chip_init()
1705 nand->ecc.mode = NAND_ECC_HW; in sunxi_nand_chip_init()
1706 nand->flash_node = node; in sunxi_nand_chip_init()
1707 nand->select_chip = sunxi_nfc_select_chip; in sunxi_nand_chip_init()
1708 nand->cmd_ctrl = sunxi_nfc_cmd_ctrl; in sunxi_nand_chip_init()
1709 nand->read_buf = sunxi_nfc_read_buf; in sunxi_nand_chip_init()
1710 nand->write_buf = sunxi_nfc_write_buf; in sunxi_nand_chip_init()
1711 nand->read_byte = sunxi_nfc_read_byte; in sunxi_nand_chip_init()
1718 if (nand->bbt_options & NAND_BBT_USE_FLASH) in sunxi_nand_chip_init()
1719 nand->bbt_options |= NAND_BBT_NO_OOB; in sunxi_nand_chip_init()
1721 if (nand->options & NAND_NEED_SCRAMBLING) in sunxi_nand_chip_init()
1722 nand->options |= NAND_NO_SUBPAGE_WRITE; in sunxi_nand_chip_init()
1724 nand->options |= NAND_SUBPAGE_READ; in sunxi_nand_chip_init()
1732 ret = sunxi_nand_ecc_init(mtd, &nand->ecc); in sunxi_nand_chip_init()
1750 list_add_tail(&chip->node, &nfc->chips); in sunxi_nand_chip_init()
1757 const void *blob = gd->fdt_blob; in sunxi_nand_chips_init()
1767 return -EINVAL; in sunxi_nand_chips_init()
1786 while (!list_empty(&nfc->chips)) { in sunxi_nand_chips_cleanup()
1787 chip = list_first_entry(&nfc->chips, struct sunxi_nand_chip, in sunxi_nand_chips_cleanup()
1789 nand_release(&chip->mtd); in sunxi_nand_chips_cleanup()
1790 sunxi_nand_ecc_cleanup(&chip->nand.ecc); in sunxi_nand_chips_cleanup()
1791 list_del(&chip->node); in sunxi_nand_chips_cleanup()
1799 const void *blob = gd->fdt_blob; in sunxi_nand_init()
1809 spin_lock_init(&nfc->controller.lock); in sunxi_nand_init()
1810 init_waitqueue_head(&nfc->controller.wq); in sunxi_nand_init()
1811 INIT_LIST_HEAD(&nfc->chips); in sunxi_nand_init()
1830 nfc->regs = (void *)regs; in sunxi_nand_init()