Lines Matching +full:nand +full:- +full:ecc +full:- +full:strength

1 // SPDX-License-Identifier: GPL-2.0+
6 * https://github.com/yuq/sunxi-nfc-mtd
9 * https://github.com/hno/Allwinner-Info
16 #include <linux/dma-mapping.h>
71 #define NFC_PAGE_SHIFT(x) (((x) < 10 ? 0 : (x) - 10) << 8)
108 #define NFC_ADR_NUM(x) (((x) - 1) << 16)
162 * struct sunxi_nand_chip_sel - stores information related to NAND Chip Select
164 * @cs: the NAND CS id used to communicate with a NAND Chip
165 * @rb: the Ready/Busy pin ID. -1 means no R/B pin connected to the NFC
173 * struct sunxi_nand_hw_ecc - stores information related to HW ECC support
175 * @mode: the sunxi ECC mode field deduced from ECC requirements
182 * struct sunxi_nand_chip - stores NAND chip device related information
184 * @node: used to store NAND chips into a list
185 * @nand: base NAND chip structure
186 * @ecc: ECC controller structure
187 * @clk_rate: clk_rate required for this NAND chip
188 * @timing_cfg: TIMING_CFG register value for this NAND chip
189 * @timing_ctl: TIMING_CTL register value for this NAND chip
190 * @nsels: number of CS lines required by the NAND chip
195 struct nand_chip nand; member
196 struct sunxi_nand_hw_ecc *ecc; member
204 static inline struct sunxi_nand_chip *to_sunxi_nand(struct nand_chip *nand) in to_sunxi_nand() argument
206 return container_of(nand, struct sunxi_nand_chip, nand); in to_sunxi_nand()
210 * NAND Controller capabilities structure: stores NAND controller capabilities
225 * struct sunxi_nfc - stores sunxi NAND controller information
229 * @regs: NAND controller registers
230 * @ahb_clk: NAND controller AHB clock
231 * @mod_clk: NAND controller mod clock
232 * @reset: NAND controller reset line
234 * @clk_rate: NAND controller current clock rate
235 * @chips: a list containing all the NAND chips attached to this NAND
237 * @complete: a completion object used to wait for NAND controller events
238 * @dmac: the DMA channel attached to the NAND controller
239 * @caps: NAND Controller capabilities
264 u32 st = readl(nfc->regs + NFC_REG_ST); in sunxi_nfc_interrupt()
265 u32 ien = readl(nfc->regs + NFC_REG_INT); in sunxi_nfc_interrupt()
271 complete(&nfc->complete); in sunxi_nfc_interrupt()
273 writel(st & NFC_INT_MASK, nfc->regs + NFC_REG_ST); in sunxi_nfc_interrupt()
274 writel(~st & ien & NFC_INT_MASK, nfc->regs + NFC_REG_INT); in sunxi_nfc_interrupt()
285 return -EINVAL; in sunxi_nfc_wait_events()
291 init_completion(&nfc->complete); in sunxi_nfc_wait_events()
293 writel(events, nfc->regs + NFC_REG_INT); in sunxi_nfc_wait_events()
295 ret = wait_for_completion_timeout(&nfc->complete, in sunxi_nfc_wait_events()
298 ret = -ETIMEDOUT; in sunxi_nfc_wait_events()
302 writel(0, nfc->regs + NFC_REG_INT); in sunxi_nfc_wait_events()
306 ret = readl_poll_timeout(nfc->regs + NFC_REG_ST, status, in sunxi_nfc_wait_events()
311 writel(events & NFC_INT_MASK, nfc->regs + NFC_REG_ST); in sunxi_nfc_wait_events()
314 dev_err(nfc->dev, "wait interrupt timedout\n"); in sunxi_nfc_wait_events()
324 ret = readl_poll_timeout(nfc->regs + NFC_REG_ST, status, in sunxi_nfc_wait_cmd_fifo_empty()
328 dev_err(nfc->dev, "wait for empty cmd FIFO timedout\n"); in sunxi_nfc_wait_cmd_fifo_empty()
338 writel(0, nfc->regs + NFC_REG_ECC_CTL); in sunxi_nfc_rst()
339 writel(NFC_RESET, nfc->regs + NFC_REG_CTL); in sunxi_nfc_rst()
341 ret = readl_poll_timeout(nfc->regs + NFC_REG_CTL, ctl, in sunxi_nfc_rst()
345 dev_err(nfc->dev, "wait for NAND controller reset timedout\n"); in sunxi_nfc_rst()
366 ret = dma_map_sg(nfc->dev, sg, 1, ddir); in sunxi_nfc_dma_op_prepare()
368 return -ENOMEM; in sunxi_nfc_dma_op_prepare()
370 if (!nfc->caps->has_mdma) { in sunxi_nfc_dma_op_prepare()
371 dmad = dmaengine_prep_slave_sg(nfc->dmac, sg, 1, tdir, DMA_CTRL_ACK); in sunxi_nfc_dma_op_prepare()
373 ret = -EINVAL; in sunxi_nfc_dma_op_prepare()
378 writel(readl(nfc->regs + NFC_REG_CTL) | NFC_RAM_METHOD, in sunxi_nfc_dma_op_prepare()
379 nfc->regs + NFC_REG_CTL); in sunxi_nfc_dma_op_prepare()
380 writel(nchunks, nfc->regs + NFC_REG_SECTOR_NUM); in sunxi_nfc_dma_op_prepare()
381 writel(chunksize, nfc->regs + NFC_REG_CNT); in sunxi_nfc_dma_op_prepare()
383 if (nfc->caps->has_mdma) { in sunxi_nfc_dma_op_prepare()
384 writel(readl(nfc->regs + NFC_REG_CTL) & ~NFC_DMA_TYPE_NORMAL, in sunxi_nfc_dma_op_prepare()
385 nfc->regs + NFC_REG_CTL); in sunxi_nfc_dma_op_prepare()
386 writel(chunksize * nchunks, nfc->regs + NFC_REG_MDMA_CNT); in sunxi_nfc_dma_op_prepare()
387 writel(sg_dma_address(sg), nfc->regs + NFC_REG_MDMA_ADDR); in sunxi_nfc_dma_op_prepare()
399 writel(readl(nfc->regs + NFC_REG_CTL) & ~NFC_RAM_METHOD, in sunxi_nfc_dma_op_prepare()
400 nfc->regs + NFC_REG_CTL); in sunxi_nfc_dma_op_prepare()
403 dma_unmap_sg(nfc->dev, sg, 1, ddir); in sunxi_nfc_dma_op_prepare()
411 dma_unmap_sg(nfc->dev, sg, 1, ddir); in sunxi_nfc_dma_op_cleanup()
412 writel(readl(nfc->regs + NFC_REG_CTL) & ~NFC_RAM_METHOD, in sunxi_nfc_dma_op_cleanup()
413 nfc->regs + NFC_REG_CTL); in sunxi_nfc_dma_op_cleanup()
416 static void sunxi_nfc_select_chip(struct nand_chip *nand, unsigned int cs) in sunxi_nfc_select_chip() argument
418 struct mtd_info *mtd = nand_to_mtd(nand); in sunxi_nfc_select_chip()
419 struct sunxi_nand_chip *sunxi_nand = to_sunxi_nand(nand); in sunxi_nfc_select_chip()
420 struct sunxi_nfc *nfc = to_sunxi_nfc(sunxi_nand->nand.controller); in sunxi_nfc_select_chip()
424 if (cs > 0 && cs >= sunxi_nand->nsels) in sunxi_nfc_select_chip()
427 ctl = readl(nfc->regs + NFC_REG_CTL) & in sunxi_nfc_select_chip()
430 sel = &sunxi_nand->sels[cs]; in sunxi_nfc_select_chip()
431 ctl |= NFC_CE_SEL(sel->cs) | NFC_EN | NFC_PAGE_SHIFT(nand->page_shift); in sunxi_nfc_select_chip()
432 if (sel->rb >= 0) in sunxi_nfc_select_chip()
433 ctl |= NFC_RB_SEL(sel->rb); in sunxi_nfc_select_chip()
435 writel(mtd->writesize, nfc->regs + NFC_REG_SPARE_AREA); in sunxi_nfc_select_chip()
437 if (nfc->clk_rate != sunxi_nand->clk_rate) { in sunxi_nfc_select_chip()
438 clk_set_rate(nfc->mod_clk, sunxi_nand->clk_rate); in sunxi_nfc_select_chip()
439 nfc->clk_rate = sunxi_nand->clk_rate; in sunxi_nfc_select_chip()
442 writel(sunxi_nand->timing_ctl, nfc->regs + NFC_REG_TIMING_CTL); in sunxi_nfc_select_chip()
443 writel(sunxi_nand->timing_cfg, nfc->regs + NFC_REG_TIMING_CFG); in sunxi_nfc_select_chip()
444 writel(ctl, nfc->regs + NFC_REG_CTL); in sunxi_nfc_select_chip()
447 static void sunxi_nfc_read_buf(struct nand_chip *nand, uint8_t *buf, int len) in sunxi_nfc_read_buf() argument
449 struct sunxi_nand_chip *sunxi_nand = to_sunxi_nand(nand); in sunxi_nfc_read_buf()
450 struct sunxi_nfc *nfc = to_sunxi_nfc(sunxi_nand->nand.controller); in sunxi_nfc_read_buf()
459 cnt = min(len - offs, NFC_SRAM_SIZE); in sunxi_nfc_read_buf()
465 writel(cnt, nfc->regs + NFC_REG_CNT); in sunxi_nfc_read_buf()
467 writel(tmp, nfc->regs + NFC_REG_CMD); in sunxi_nfc_read_buf()
478 memcpy_fromio(buf + offs, nfc->regs + NFC_RAM0_BASE, in sunxi_nfc_read_buf()
484 static void sunxi_nfc_write_buf(struct nand_chip *nand, const uint8_t *buf, in sunxi_nfc_write_buf() argument
487 struct sunxi_nand_chip *sunxi_nand = to_sunxi_nand(nand); in sunxi_nfc_write_buf()
488 struct sunxi_nfc *nfc = to_sunxi_nfc(sunxi_nand->nand.controller); in sunxi_nfc_write_buf()
497 cnt = min(len - offs, NFC_SRAM_SIZE); in sunxi_nfc_write_buf()
503 writel(cnt, nfc->regs + NFC_REG_CNT); in sunxi_nfc_write_buf()
504 memcpy_toio(nfc->regs + NFC_RAM0_BASE, buf + offs, cnt); in sunxi_nfc_write_buf()
507 writel(tmp, nfc->regs + NFC_REG_CMD); in sunxi_nfc_write_buf()
596 while (count--) in sunxi_nfc_randomizer_step()
603 static u16 sunxi_nfc_randomizer_state(struct nand_chip *nand, int page, in sunxi_nfc_randomizer_state() argument
604 bool ecc) in sunxi_nfc_randomizer_state() argument
606 struct mtd_info *mtd = nand_to_mtd(nand); in sunxi_nfc_randomizer_state()
608 int mod = mtd_div_by_ws(mtd->erasesize, mtd); in sunxi_nfc_randomizer_state()
613 if (ecc) { in sunxi_nfc_randomizer_state()
614 if (mtd->ecc_step_size == 512) in sunxi_nfc_randomizer_state()
623 static void sunxi_nfc_randomizer_config(struct nand_chip *nand, int page, in sunxi_nfc_randomizer_config() argument
624 bool ecc) in sunxi_nfc_randomizer_config() argument
626 struct sunxi_nfc *nfc = to_sunxi_nfc(nand->controller); in sunxi_nfc_randomizer_config()
627 u32 ecc_ctl = readl(nfc->regs + NFC_REG_ECC_CTL); in sunxi_nfc_randomizer_config()
630 if (!(nand->options & NAND_NEED_SCRAMBLING)) in sunxi_nfc_randomizer_config()
633 ecc_ctl = readl(nfc->regs + NFC_REG_ECC_CTL); in sunxi_nfc_randomizer_config()
634 state = sunxi_nfc_randomizer_state(nand, page, ecc); in sunxi_nfc_randomizer_config()
635 ecc_ctl = readl(nfc->regs + NFC_REG_ECC_CTL) & ~NFC_RANDOM_SEED_MSK; in sunxi_nfc_randomizer_config()
636 writel(ecc_ctl | NFC_RANDOM_SEED(state), nfc->regs + NFC_REG_ECC_CTL); in sunxi_nfc_randomizer_config()
639 static void sunxi_nfc_randomizer_enable(struct nand_chip *nand) in sunxi_nfc_randomizer_enable() argument
641 struct sunxi_nfc *nfc = to_sunxi_nfc(nand->controller); in sunxi_nfc_randomizer_enable()
643 if (!(nand->options & NAND_NEED_SCRAMBLING)) in sunxi_nfc_randomizer_enable()
646 writel(readl(nfc->regs + NFC_REG_ECC_CTL) | NFC_RANDOM_EN, in sunxi_nfc_randomizer_enable()
647 nfc->regs + NFC_REG_ECC_CTL); in sunxi_nfc_randomizer_enable()
650 static void sunxi_nfc_randomizer_disable(struct nand_chip *nand) in sunxi_nfc_randomizer_disable() argument
652 struct sunxi_nfc *nfc = to_sunxi_nfc(nand->controller); in sunxi_nfc_randomizer_disable()
654 if (!(nand->options & NAND_NEED_SCRAMBLING)) in sunxi_nfc_randomizer_disable()
657 writel(readl(nfc->regs + NFC_REG_ECC_CTL) & ~NFC_RANDOM_EN, in sunxi_nfc_randomizer_disable()
658 nfc->regs + NFC_REG_ECC_CTL); in sunxi_nfc_randomizer_disable()
661 static void sunxi_nfc_randomize_bbm(struct nand_chip *nand, int page, u8 *bbm) in sunxi_nfc_randomize_bbm() argument
663 u16 state = sunxi_nfc_randomizer_state(nand, page, true); in sunxi_nfc_randomize_bbm()
669 static void sunxi_nfc_randomizer_write_buf(struct nand_chip *nand, in sunxi_nfc_randomizer_write_buf() argument
671 bool ecc, int page) in sunxi_nfc_randomizer_write_buf() argument
673 sunxi_nfc_randomizer_config(nand, page, ecc); in sunxi_nfc_randomizer_write_buf()
674 sunxi_nfc_randomizer_enable(nand); in sunxi_nfc_randomizer_write_buf()
675 sunxi_nfc_write_buf(nand, buf, len); in sunxi_nfc_randomizer_write_buf()
676 sunxi_nfc_randomizer_disable(nand); in sunxi_nfc_randomizer_write_buf()
679 static void sunxi_nfc_randomizer_read_buf(struct nand_chip *nand, uint8_t *buf, in sunxi_nfc_randomizer_read_buf() argument
680 int len, bool ecc, int page) in sunxi_nfc_randomizer_read_buf() argument
682 sunxi_nfc_randomizer_config(nand, page, ecc); in sunxi_nfc_randomizer_read_buf()
683 sunxi_nfc_randomizer_enable(nand); in sunxi_nfc_randomizer_read_buf()
684 sunxi_nfc_read_buf(nand, buf, len); in sunxi_nfc_randomizer_read_buf()
685 sunxi_nfc_randomizer_disable(nand); in sunxi_nfc_randomizer_read_buf()
688 static void sunxi_nfc_hw_ecc_enable(struct nand_chip *nand) in sunxi_nfc_hw_ecc_enable() argument
690 struct sunxi_nand_chip *sunxi_nand = to_sunxi_nand(nand); in sunxi_nfc_hw_ecc_enable()
691 struct sunxi_nfc *nfc = to_sunxi_nfc(nand->controller); in sunxi_nfc_hw_ecc_enable()
694 ecc_ctl = readl(nfc->regs + NFC_REG_ECC_CTL); in sunxi_nfc_hw_ecc_enable()
697 ecc_ctl |= NFC_ECC_EN | NFC_ECC_MODE(sunxi_nand->ecc->mode) | in sunxi_nfc_hw_ecc_enable()
700 if (nand->ecc.size == 512) in sunxi_nfc_hw_ecc_enable()
703 writel(ecc_ctl, nfc->regs + NFC_REG_ECC_CTL); in sunxi_nfc_hw_ecc_enable()
706 static void sunxi_nfc_hw_ecc_disable(struct nand_chip *nand) in sunxi_nfc_hw_ecc_disable() argument
708 struct sunxi_nfc *nfc = to_sunxi_nfc(nand->controller); in sunxi_nfc_hw_ecc_disable()
710 writel(readl(nfc->regs + NFC_REG_ECC_CTL) & ~NFC_ECC_EN, in sunxi_nfc_hw_ecc_disable()
711 nfc->regs + NFC_REG_ECC_CTL); in sunxi_nfc_hw_ecc_disable()
727 static void sunxi_nfc_hw_ecc_get_prot_oob_bytes(struct nand_chip *nand, u8 *oob, in sunxi_nfc_hw_ecc_get_prot_oob_bytes() argument
730 struct sunxi_nfc *nfc = to_sunxi_nfc(nand->controller); in sunxi_nfc_hw_ecc_get_prot_oob_bytes()
732 sunxi_nfc_user_data_to_buf(readl(nfc->regs + NFC_REG_USER_DATA(step)), in sunxi_nfc_hw_ecc_get_prot_oob_bytes()
735 /* De-randomize the Bad Block Marker. */ in sunxi_nfc_hw_ecc_get_prot_oob_bytes()
736 if (bbm && (nand->options & NAND_NEED_SCRAMBLING)) in sunxi_nfc_hw_ecc_get_prot_oob_bytes()
737 sunxi_nfc_randomize_bbm(nand, page, oob); in sunxi_nfc_hw_ecc_get_prot_oob_bytes()
740 static void sunxi_nfc_hw_ecc_set_prot_oob_bytes(struct nand_chip *nand, in sunxi_nfc_hw_ecc_set_prot_oob_bytes() argument
744 struct sunxi_nfc *nfc = to_sunxi_nfc(nand->controller); in sunxi_nfc_hw_ecc_set_prot_oob_bytes()
748 if (bbm && (nand->options & NAND_NEED_SCRAMBLING)) { in sunxi_nfc_hw_ecc_set_prot_oob_bytes()
750 sunxi_nfc_randomize_bbm(nand, page, user_data); in sunxi_nfc_hw_ecc_set_prot_oob_bytes()
755 nfc->regs + NFC_REG_USER_DATA(step)); in sunxi_nfc_hw_ecc_set_prot_oob_bytes()
758 static void sunxi_nfc_hw_ecc_update_stats(struct nand_chip *nand, in sunxi_nfc_hw_ecc_update_stats() argument
761 struct mtd_info *mtd = nand_to_mtd(nand); in sunxi_nfc_hw_ecc_update_stats()
764 mtd->ecc_stats.failed++; in sunxi_nfc_hw_ecc_update_stats()
766 mtd->ecc_stats.corrected += ret; in sunxi_nfc_hw_ecc_update_stats()
771 static int sunxi_nfc_hw_ecc_correct(struct nand_chip *nand, u8 *data, u8 *oob, in sunxi_nfc_hw_ecc_correct() argument
774 struct sunxi_nfc *nfc = to_sunxi_nfc(nand->controller); in sunxi_nfc_hw_ecc_correct()
775 struct nand_ecc_ctrl *ecc = &nand->ecc; in sunxi_nfc_hw_ecc_correct() local
781 return -EBADMSG; in sunxi_nfc_hw_ecc_correct()
786 if (unlikely(!(readl(nfc->regs + NFC_REG_PAT_ID) & 0x1))) { in sunxi_nfc_hw_ecc_correct()
794 memset(data, pattern, ecc->size); in sunxi_nfc_hw_ecc_correct()
797 memset(oob, pattern, ecc->bytes + 4); in sunxi_nfc_hw_ecc_correct()
802 tmp = readl(nfc->regs + NFC_REG_ECC_ERR_CNT(step)); in sunxi_nfc_hw_ecc_correct()
807 static int sunxi_nfc_hw_ecc_read_chunk(struct nand_chip *nand, in sunxi_nfc_hw_ecc_read_chunk() argument
814 struct sunxi_nfc *nfc = to_sunxi_nfc(nand->controller); in sunxi_nfc_hw_ecc_read_chunk()
815 struct nand_ecc_ctrl *ecc = &nand->ecc; in sunxi_nfc_hw_ecc_read_chunk() local
821 nand_change_read_column_op(nand, data_off, NULL, 0, false); in sunxi_nfc_hw_ecc_read_chunk()
823 sunxi_nfc_randomizer_read_buf(nand, NULL, ecc->size, false, page); in sunxi_nfc_hw_ecc_read_chunk()
825 if (data_off + ecc->size != oob_off) in sunxi_nfc_hw_ecc_read_chunk()
826 nand_change_read_column_op(nand, oob_off, NULL, 0, false); in sunxi_nfc_hw_ecc_read_chunk()
832 sunxi_nfc_randomizer_enable(nand); in sunxi_nfc_hw_ecc_read_chunk()
834 nfc->regs + NFC_REG_CMD); in sunxi_nfc_hw_ecc_read_chunk()
837 sunxi_nfc_randomizer_disable(nand); in sunxi_nfc_hw_ecc_read_chunk()
841 *cur_off = oob_off + ecc->bytes + 4; in sunxi_nfc_hw_ecc_read_chunk()
843 ret = sunxi_nfc_hw_ecc_correct(nand, data, oob_required ? oob : NULL, 0, in sunxi_nfc_hw_ecc_read_chunk()
844 readl(nfc->regs + NFC_REG_ECC_ST), in sunxi_nfc_hw_ecc_read_chunk()
851 * Re-read the data with the randomizer disabled to identify in sunxi_nfc_hw_ecc_read_chunk()
854 if (nand->options & NAND_NEED_SCRAMBLING) in sunxi_nfc_hw_ecc_read_chunk()
855 nand_change_read_column_op(nand, data_off, data, in sunxi_nfc_hw_ecc_read_chunk()
856 ecc->size, false); in sunxi_nfc_hw_ecc_read_chunk()
858 memcpy_fromio(data, nfc->regs + NFC_RAM0_BASE, in sunxi_nfc_hw_ecc_read_chunk()
859 ecc->size); in sunxi_nfc_hw_ecc_read_chunk()
861 nand_change_read_column_op(nand, oob_off, oob, ecc->bytes + 4, in sunxi_nfc_hw_ecc_read_chunk()
864 ret = nand_check_erased_ecc_chunk(data, ecc->size, in sunxi_nfc_hw_ecc_read_chunk()
865 oob, ecc->bytes + 4, in sunxi_nfc_hw_ecc_read_chunk()
866 NULL, 0, ecc->strength); in sunxi_nfc_hw_ecc_read_chunk()
870 memcpy_fromio(data, nfc->regs + NFC_RAM0_BASE, ecc->size); in sunxi_nfc_hw_ecc_read_chunk()
873 nand_change_read_column_op(nand, oob_off, NULL, 0, in sunxi_nfc_hw_ecc_read_chunk()
875 sunxi_nfc_randomizer_read_buf(nand, oob, ecc->bytes + 4, in sunxi_nfc_hw_ecc_read_chunk()
878 sunxi_nfc_hw_ecc_get_prot_oob_bytes(nand, oob, 0, in sunxi_nfc_hw_ecc_read_chunk()
883 sunxi_nfc_hw_ecc_update_stats(nand, max_bitflips, ret); in sunxi_nfc_hw_ecc_read_chunk()
888 static void sunxi_nfc_hw_ecc_read_extra_oob(struct nand_chip *nand, in sunxi_nfc_hw_ecc_read_extra_oob() argument
892 struct mtd_info *mtd = nand_to_mtd(nand); in sunxi_nfc_hw_ecc_read_extra_oob()
893 struct nand_ecc_ctrl *ecc = &nand->ecc; in sunxi_nfc_hw_ecc_read_extra_oob() local
894 int offset = ((ecc->bytes + 4) * ecc->steps); in sunxi_nfc_hw_ecc_read_extra_oob()
895 int len = mtd->oobsize - offset; in sunxi_nfc_hw_ecc_read_extra_oob()
901 nand_change_read_column_op(nand, mtd->writesize, NULL, 0, in sunxi_nfc_hw_ecc_read_extra_oob()
905 sunxi_nfc_read_buf(nand, oob + offset, len); in sunxi_nfc_hw_ecc_read_extra_oob()
907 sunxi_nfc_randomizer_read_buf(nand, oob + offset, len, in sunxi_nfc_hw_ecc_read_extra_oob()
911 *cur_off = mtd->oobsize + mtd->writesize; in sunxi_nfc_hw_ecc_read_extra_oob()
914 static int sunxi_nfc_hw_ecc_read_chunks_dma(struct nand_chip *nand, uint8_t *buf, in sunxi_nfc_hw_ecc_read_chunks_dma() argument
918 bool randomized = nand->options & NAND_NEED_SCRAMBLING; in sunxi_nfc_hw_ecc_read_chunks_dma()
919 struct sunxi_nfc *nfc = to_sunxi_nfc(nand->controller); in sunxi_nfc_hw_ecc_read_chunks_dma()
920 struct mtd_info *mtd = nand_to_mtd(nand); in sunxi_nfc_hw_ecc_read_chunks_dma()
921 struct nand_ecc_ctrl *ecc = &nand->ecc; in sunxi_nfc_hw_ecc_read_chunks_dma() local
931 ret = sunxi_nfc_dma_op_prepare(nfc, buf, ecc->size, nchunks, in sunxi_nfc_hw_ecc_read_chunks_dma()
936 sunxi_nfc_hw_ecc_enable(nand); in sunxi_nfc_hw_ecc_read_chunks_dma()
937 sunxi_nfc_randomizer_config(nand, page, false); in sunxi_nfc_hw_ecc_read_chunks_dma()
938 sunxi_nfc_randomizer_enable(nand); in sunxi_nfc_hw_ecc_read_chunks_dma()
941 NAND_CMD_READSTART, nfc->regs + NFC_REG_RCMD_SET); in sunxi_nfc_hw_ecc_read_chunks_dma()
945 if (nfc->caps->has_mdma) in sunxi_nfc_hw_ecc_read_chunks_dma()
948 dma_async_issue_pending(nfc->dmac); in sunxi_nfc_hw_ecc_read_chunks_dma()
951 nfc->regs + NFC_REG_CMD); in sunxi_nfc_hw_ecc_read_chunks_dma()
954 if (ret && !nfc->caps->has_mdma) in sunxi_nfc_hw_ecc_read_chunks_dma()
955 dmaengine_terminate_all(nfc->dmac); in sunxi_nfc_hw_ecc_read_chunks_dma()
957 sunxi_nfc_randomizer_disable(nand); in sunxi_nfc_hw_ecc_read_chunks_dma()
958 sunxi_nfc_hw_ecc_disable(nand); in sunxi_nfc_hw_ecc_read_chunks_dma()
965 status = readl(nfc->regs + NFC_REG_ECC_ST); in sunxi_nfc_hw_ecc_read_chunks_dma()
968 int data_off = i * ecc->size; in sunxi_nfc_hw_ecc_read_chunks_dma()
969 int oob_off = i * (ecc->bytes + 4); in sunxi_nfc_hw_ecc_read_chunks_dma()
971 u8 *oob = nand->oob_poi + oob_off; in sunxi_nfc_hw_ecc_read_chunks_dma()
974 ret = sunxi_nfc_hw_ecc_correct(nand, randomized ? data : NULL, in sunxi_nfc_hw_ecc_read_chunks_dma()
978 /* ECC errors are handled in the second loop. */ in sunxi_nfc_hw_ecc_read_chunks_dma()
984 nand_change_read_column_op(nand, in sunxi_nfc_hw_ecc_read_chunks_dma()
985 mtd->writesize + oob_off, in sunxi_nfc_hw_ecc_read_chunks_dma()
986 oob, ecc->bytes + 4, false); in sunxi_nfc_hw_ecc_read_chunks_dma()
988 sunxi_nfc_hw_ecc_get_prot_oob_bytes(nand, oob, i, in sunxi_nfc_hw_ecc_read_chunks_dma()
995 sunxi_nfc_hw_ecc_update_stats(nand, &max_bitflips, ret); in sunxi_nfc_hw_ecc_read_chunks_dma()
1000 int data_off = i * ecc->size; in sunxi_nfc_hw_ecc_read_chunks_dma()
1001 int oob_off = i * (ecc->bytes + 4); in sunxi_nfc_hw_ecc_read_chunks_dma()
1003 u8 *oob = nand->oob_poi + oob_off; in sunxi_nfc_hw_ecc_read_chunks_dma()
1009 * Re-read the data with the randomizer disabled to in sunxi_nfc_hw_ecc_read_chunks_dma()
1014 nand_change_read_column_op(nand, data_off, in sunxi_nfc_hw_ecc_read_chunks_dma()
1015 data, ecc->size, in sunxi_nfc_hw_ecc_read_chunks_dma()
1019 nand_change_read_column_op(nand, in sunxi_nfc_hw_ecc_read_chunks_dma()
1020 mtd->writesize + oob_off, in sunxi_nfc_hw_ecc_read_chunks_dma()
1021 oob, ecc->bytes + 4, false); in sunxi_nfc_hw_ecc_read_chunks_dma()
1023 ret = nand_check_erased_ecc_chunk(data, ecc->size, in sunxi_nfc_hw_ecc_read_chunks_dma()
1024 oob, ecc->bytes + 4, in sunxi_nfc_hw_ecc_read_chunks_dma()
1026 ecc->strength); in sunxi_nfc_hw_ecc_read_chunks_dma()
1030 sunxi_nfc_hw_ecc_update_stats(nand, &max_bitflips, ret); in sunxi_nfc_hw_ecc_read_chunks_dma()
1035 sunxi_nfc_hw_ecc_read_extra_oob(nand, nand->oob_poi, in sunxi_nfc_hw_ecc_read_chunks_dma()
1042 static int sunxi_nfc_hw_ecc_write_chunk(struct nand_chip *nand, in sunxi_nfc_hw_ecc_write_chunk() argument
1048 struct sunxi_nfc *nfc = to_sunxi_nfc(nand->controller); in sunxi_nfc_hw_ecc_write_chunk()
1049 struct nand_ecc_ctrl *ecc = &nand->ecc; in sunxi_nfc_hw_ecc_write_chunk() local
1053 nand_change_write_column_op(nand, data_off, NULL, 0, false); in sunxi_nfc_hw_ecc_write_chunk()
1055 sunxi_nfc_randomizer_write_buf(nand, data, ecc->size, false, page); in sunxi_nfc_hw_ecc_write_chunk()
1057 if (data_off + ecc->size != oob_off) in sunxi_nfc_hw_ecc_write_chunk()
1058 nand_change_write_column_op(nand, oob_off, NULL, 0, false); in sunxi_nfc_hw_ecc_write_chunk()
1064 sunxi_nfc_randomizer_enable(nand); in sunxi_nfc_hw_ecc_write_chunk()
1065 sunxi_nfc_hw_ecc_set_prot_oob_bytes(nand, oob, 0, bbm, page); in sunxi_nfc_hw_ecc_write_chunk()
1069 nfc->regs + NFC_REG_CMD); in sunxi_nfc_hw_ecc_write_chunk()
1072 sunxi_nfc_randomizer_disable(nand); in sunxi_nfc_hw_ecc_write_chunk()
1076 *cur_off = oob_off + ecc->bytes + 4; in sunxi_nfc_hw_ecc_write_chunk()
1081 static void sunxi_nfc_hw_ecc_write_extra_oob(struct nand_chip *nand, in sunxi_nfc_hw_ecc_write_extra_oob() argument
1085 struct mtd_info *mtd = nand_to_mtd(nand); in sunxi_nfc_hw_ecc_write_extra_oob()
1086 struct nand_ecc_ctrl *ecc = &nand->ecc; in sunxi_nfc_hw_ecc_write_extra_oob() local
1087 int offset = ((ecc->bytes + 4) * ecc->steps); in sunxi_nfc_hw_ecc_write_extra_oob()
1088 int len = mtd->oobsize - offset; in sunxi_nfc_hw_ecc_write_extra_oob()
1094 nand_change_write_column_op(nand, offset + mtd->writesize, in sunxi_nfc_hw_ecc_write_extra_oob()
1097 sunxi_nfc_randomizer_write_buf(nand, oob + offset, len, false, page); in sunxi_nfc_hw_ecc_write_extra_oob()
1100 *cur_off = mtd->oobsize + mtd->writesize; in sunxi_nfc_hw_ecc_write_extra_oob()
1103 static int sunxi_nfc_hw_ecc_read_page(struct nand_chip *nand, uint8_t *buf, in sunxi_nfc_hw_ecc_read_page() argument
1106 struct mtd_info *mtd = nand_to_mtd(nand); in sunxi_nfc_hw_ecc_read_page()
1107 struct nand_ecc_ctrl *ecc = &nand->ecc; in sunxi_nfc_hw_ecc_read_page() local
1112 sunxi_nfc_select_chip(nand, nand->cur_cs); in sunxi_nfc_hw_ecc_read_page()
1114 nand_read_page_op(nand, page, 0, NULL, 0); in sunxi_nfc_hw_ecc_read_page()
1116 sunxi_nfc_hw_ecc_enable(nand); in sunxi_nfc_hw_ecc_read_page()
1118 for (i = 0; i < ecc->steps; i++) { in sunxi_nfc_hw_ecc_read_page()
1119 int data_off = i * ecc->size; in sunxi_nfc_hw_ecc_read_page()
1120 int oob_off = i * (ecc->bytes + 4); in sunxi_nfc_hw_ecc_read_page()
1122 u8 *oob = nand->oob_poi + oob_off; in sunxi_nfc_hw_ecc_read_page()
1124 ret = sunxi_nfc_hw_ecc_read_chunk(nand, data, data_off, oob, in sunxi_nfc_hw_ecc_read_page()
1125 oob_off + mtd->writesize, in sunxi_nfc_hw_ecc_read_page()
1135 sunxi_nfc_hw_ecc_read_extra_oob(nand, nand->oob_poi, &cur_off, in sunxi_nfc_hw_ecc_read_page()
1138 sunxi_nfc_hw_ecc_disable(nand); in sunxi_nfc_hw_ecc_read_page()
1143 static int sunxi_nfc_hw_ecc_read_page_dma(struct nand_chip *nand, u8 *buf, in sunxi_nfc_hw_ecc_read_page_dma() argument
1148 sunxi_nfc_select_chip(nand, nand->cur_cs); in sunxi_nfc_hw_ecc_read_page_dma()
1150 nand_read_page_op(nand, page, 0, NULL, 0); in sunxi_nfc_hw_ecc_read_page_dma()
1152 ret = sunxi_nfc_hw_ecc_read_chunks_dma(nand, buf, oob_required, page, in sunxi_nfc_hw_ecc_read_page_dma()
1153 nand->ecc.steps); in sunxi_nfc_hw_ecc_read_page_dma()
1158 return sunxi_nfc_hw_ecc_read_page(nand, buf, oob_required, page); in sunxi_nfc_hw_ecc_read_page_dma()
1161 static int sunxi_nfc_hw_ecc_read_subpage(struct nand_chip *nand, in sunxi_nfc_hw_ecc_read_subpage() argument
1165 struct mtd_info *mtd = nand_to_mtd(nand); in sunxi_nfc_hw_ecc_read_subpage()
1166 struct nand_ecc_ctrl *ecc = &nand->ecc; in sunxi_nfc_hw_ecc_read_subpage() local
1170 sunxi_nfc_select_chip(nand, nand->cur_cs); in sunxi_nfc_hw_ecc_read_subpage()
1172 nand_read_page_op(nand, page, 0, NULL, 0); in sunxi_nfc_hw_ecc_read_subpage()
1174 sunxi_nfc_hw_ecc_enable(nand); in sunxi_nfc_hw_ecc_read_subpage()
1176 for (i = data_offs / ecc->size; in sunxi_nfc_hw_ecc_read_subpage()
1177 i < DIV_ROUND_UP(data_offs + readlen, ecc->size); i++) { in sunxi_nfc_hw_ecc_read_subpage()
1178 int data_off = i * ecc->size; in sunxi_nfc_hw_ecc_read_subpage()
1179 int oob_off = i * (ecc->bytes + 4); in sunxi_nfc_hw_ecc_read_subpage()
1181 u8 *oob = nand->oob_poi + oob_off; in sunxi_nfc_hw_ecc_read_subpage()
1183 ret = sunxi_nfc_hw_ecc_read_chunk(nand, data, data_off, in sunxi_nfc_hw_ecc_read_subpage()
1185 oob_off + mtd->writesize, in sunxi_nfc_hw_ecc_read_subpage()
1192 sunxi_nfc_hw_ecc_disable(nand); in sunxi_nfc_hw_ecc_read_subpage()
1197 static int sunxi_nfc_hw_ecc_read_subpage_dma(struct nand_chip *nand, in sunxi_nfc_hw_ecc_read_subpage_dma() argument
1201 int nchunks = DIV_ROUND_UP(data_offs + readlen, nand->ecc.size); in sunxi_nfc_hw_ecc_read_subpage_dma()
1204 sunxi_nfc_select_chip(nand, nand->cur_cs); in sunxi_nfc_hw_ecc_read_subpage_dma()
1206 nand_read_page_op(nand, page, 0, NULL, 0); in sunxi_nfc_hw_ecc_read_subpage_dma()
1208 ret = sunxi_nfc_hw_ecc_read_chunks_dma(nand, buf, false, page, nchunks); in sunxi_nfc_hw_ecc_read_subpage_dma()
1213 return sunxi_nfc_hw_ecc_read_subpage(nand, data_offs, readlen, in sunxi_nfc_hw_ecc_read_subpage_dma()
1217 static int sunxi_nfc_hw_ecc_write_page(struct nand_chip *nand, in sunxi_nfc_hw_ecc_write_page() argument
1221 struct mtd_info *mtd = nand_to_mtd(nand); in sunxi_nfc_hw_ecc_write_page()
1222 struct nand_ecc_ctrl *ecc = &nand->ecc; in sunxi_nfc_hw_ecc_write_page() local
1225 sunxi_nfc_select_chip(nand, nand->cur_cs); in sunxi_nfc_hw_ecc_write_page()
1227 nand_prog_page_begin_op(nand, page, 0, NULL, 0); in sunxi_nfc_hw_ecc_write_page()
1229 sunxi_nfc_hw_ecc_enable(nand); in sunxi_nfc_hw_ecc_write_page()
1231 for (i = 0; i < ecc->steps; i++) { in sunxi_nfc_hw_ecc_write_page()
1232 int data_off = i * ecc->size; in sunxi_nfc_hw_ecc_write_page()
1233 int oob_off = i * (ecc->bytes + 4); in sunxi_nfc_hw_ecc_write_page()
1235 const u8 *oob = nand->oob_poi + oob_off; in sunxi_nfc_hw_ecc_write_page()
1237 ret = sunxi_nfc_hw_ecc_write_chunk(nand, data, data_off, oob, in sunxi_nfc_hw_ecc_write_page()
1238 oob_off + mtd->writesize, in sunxi_nfc_hw_ecc_write_page()
1244 if (oob_required || (nand->options & NAND_NEED_SCRAMBLING)) in sunxi_nfc_hw_ecc_write_page()
1245 sunxi_nfc_hw_ecc_write_extra_oob(nand, nand->oob_poi, in sunxi_nfc_hw_ecc_write_page()
1248 sunxi_nfc_hw_ecc_disable(nand); in sunxi_nfc_hw_ecc_write_page()
1250 return nand_prog_page_end_op(nand); in sunxi_nfc_hw_ecc_write_page()
1253 static int sunxi_nfc_hw_ecc_write_subpage(struct nand_chip *nand, in sunxi_nfc_hw_ecc_write_subpage() argument
1258 struct mtd_info *mtd = nand_to_mtd(nand); in sunxi_nfc_hw_ecc_write_subpage()
1259 struct nand_ecc_ctrl *ecc = &nand->ecc; in sunxi_nfc_hw_ecc_write_subpage() local
1262 sunxi_nfc_select_chip(nand, nand->cur_cs); in sunxi_nfc_hw_ecc_write_subpage()
1264 nand_prog_page_begin_op(nand, page, 0, NULL, 0); in sunxi_nfc_hw_ecc_write_subpage()
1266 sunxi_nfc_hw_ecc_enable(nand); in sunxi_nfc_hw_ecc_write_subpage()
1268 for (i = data_offs / ecc->size; in sunxi_nfc_hw_ecc_write_subpage()
1269 i < DIV_ROUND_UP(data_offs + data_len, ecc->size); i++) { in sunxi_nfc_hw_ecc_write_subpage()
1270 int data_off = i * ecc->size; in sunxi_nfc_hw_ecc_write_subpage()
1271 int oob_off = i * (ecc->bytes + 4); in sunxi_nfc_hw_ecc_write_subpage()
1273 const u8 *oob = nand->oob_poi + oob_off; in sunxi_nfc_hw_ecc_write_subpage()
1275 ret = sunxi_nfc_hw_ecc_write_chunk(nand, data, data_off, oob, in sunxi_nfc_hw_ecc_write_subpage()
1276 oob_off + mtd->writesize, in sunxi_nfc_hw_ecc_write_subpage()
1282 sunxi_nfc_hw_ecc_disable(nand); in sunxi_nfc_hw_ecc_write_subpage()
1284 return nand_prog_page_end_op(nand); in sunxi_nfc_hw_ecc_write_subpage()
1287 static int sunxi_nfc_hw_ecc_write_page_dma(struct nand_chip *nand, in sunxi_nfc_hw_ecc_write_page_dma() argument
1292 struct sunxi_nfc *nfc = to_sunxi_nfc(nand->controller); in sunxi_nfc_hw_ecc_write_page_dma()
1293 struct nand_ecc_ctrl *ecc = &nand->ecc; in sunxi_nfc_hw_ecc_write_page_dma() local
1298 sunxi_nfc_select_chip(nand, nand->cur_cs); in sunxi_nfc_hw_ecc_write_page_dma()
1304 ret = sunxi_nfc_dma_op_prepare(nfc, buf, ecc->size, ecc->steps, in sunxi_nfc_hw_ecc_write_page_dma()
1309 for (i = 0; i < ecc->steps; i++) { in sunxi_nfc_hw_ecc_write_page_dma()
1310 const u8 *oob = nand->oob_poi + (i * (ecc->bytes + 4)); in sunxi_nfc_hw_ecc_write_page_dma()
1312 sunxi_nfc_hw_ecc_set_prot_oob_bytes(nand, oob, i, !i, page); in sunxi_nfc_hw_ecc_write_page_dma()
1315 nand_prog_page_begin_op(nand, page, 0, NULL, 0); in sunxi_nfc_hw_ecc_write_page_dma()
1317 sunxi_nfc_hw_ecc_enable(nand); in sunxi_nfc_hw_ecc_write_page_dma()
1318 sunxi_nfc_randomizer_config(nand, page, false); in sunxi_nfc_hw_ecc_write_page_dma()
1319 sunxi_nfc_randomizer_enable(nand); in sunxi_nfc_hw_ecc_write_page_dma()
1322 nfc->regs + NFC_REG_WCMD_SET); in sunxi_nfc_hw_ecc_write_page_dma()
1326 if (nfc->caps->has_mdma) in sunxi_nfc_hw_ecc_write_page_dma()
1329 dma_async_issue_pending(nfc->dmac); in sunxi_nfc_hw_ecc_write_page_dma()
1333 nfc->regs + NFC_REG_CMD); in sunxi_nfc_hw_ecc_write_page_dma()
1336 if (ret && !nfc->caps->has_mdma) in sunxi_nfc_hw_ecc_write_page_dma()
1337 dmaengine_terminate_all(nfc->dmac); in sunxi_nfc_hw_ecc_write_page_dma()
1339 sunxi_nfc_randomizer_disable(nand); in sunxi_nfc_hw_ecc_write_page_dma()
1340 sunxi_nfc_hw_ecc_disable(nand); in sunxi_nfc_hw_ecc_write_page_dma()
1347 if (oob_required || (nand->options & NAND_NEED_SCRAMBLING)) in sunxi_nfc_hw_ecc_write_page_dma()
1349 sunxi_nfc_hw_ecc_write_extra_oob(nand, nand->oob_poi, in sunxi_nfc_hw_ecc_write_page_dma()
1352 return nand_prog_page_end_op(nand); in sunxi_nfc_hw_ecc_write_page_dma()
1355 return sunxi_nfc_hw_ecc_write_page(nand, buf, oob_required, page); in sunxi_nfc_hw_ecc_write_page_dma()
1358 static int sunxi_nfc_hw_ecc_read_oob(struct nand_chip *nand, int page) in sunxi_nfc_hw_ecc_read_oob() argument
1360 u8 *buf = nand_get_data_buf(nand); in sunxi_nfc_hw_ecc_read_oob()
1362 return nand->ecc.read_page(nand, buf, 1, page); in sunxi_nfc_hw_ecc_read_oob()
1365 static int sunxi_nfc_hw_ecc_write_oob(struct nand_chip *nand, int page) in sunxi_nfc_hw_ecc_write_oob() argument
1367 struct mtd_info *mtd = nand_to_mtd(nand); in sunxi_nfc_hw_ecc_write_oob()
1368 u8 *buf = nand_get_data_buf(nand); in sunxi_nfc_hw_ecc_write_oob()
1371 memset(buf, 0xff, mtd->writesize); in sunxi_nfc_hw_ecc_write_oob()
1372 ret = nand->ecc.write_page(nand, buf, 1, page); in sunxi_nfc_hw_ecc_write_oob()
1377 return nand_prog_page_end_op(nand); in sunxi_nfc_hw_ecc_write_oob()
1395 return -EINVAL; in _sunxi_nand_lookup_timing()
1401 static int sunxi_nfc_setup_interface(struct nand_chip *nand, int csline, in sunxi_nfc_setup_interface() argument
1404 struct sunxi_nand_chip *sunxi_nand = to_sunxi_nand(nand); in sunxi_nfc_setup_interface()
1405 struct sunxi_nfc *nfc = to_sunxi_nfc(sunxi_nand->nand.controller); in sunxi_nfc_setup_interface()
1413 return -ENOTSUPP; in sunxi_nfc_setup_interface()
1416 if (timings->tCLS_min > min_clk_period) in sunxi_nfc_setup_interface()
1417 min_clk_period = timings->tCLS_min; in sunxi_nfc_setup_interface()
1420 if (timings->tCLH_min > min_clk_period) in sunxi_nfc_setup_interface()
1421 min_clk_period = timings->tCLH_min; in sunxi_nfc_setup_interface()
1424 if (timings->tCS_min > min_clk_period) in sunxi_nfc_setup_interface()
1425 min_clk_period = timings->tCS_min; in sunxi_nfc_setup_interface()
1428 if (timings->tCH_min > min_clk_period) in sunxi_nfc_setup_interface()
1429 min_clk_period = timings->tCH_min; in sunxi_nfc_setup_interface()
1432 if (timings->tWP_min > min_clk_period) in sunxi_nfc_setup_interface()
1433 min_clk_period = timings->tWP_min; in sunxi_nfc_setup_interface()
1436 if (timings->tWH_min > min_clk_period) in sunxi_nfc_setup_interface()
1437 min_clk_period = timings->tWH_min; in sunxi_nfc_setup_interface()
1440 if (timings->tALS_min > min_clk_period) in sunxi_nfc_setup_interface()
1441 min_clk_period = timings->tALS_min; in sunxi_nfc_setup_interface()
1444 if (timings->tDS_min > min_clk_period) in sunxi_nfc_setup_interface()
1445 min_clk_period = timings->tDS_min; in sunxi_nfc_setup_interface()
1448 if (timings->tDH_min > min_clk_period) in sunxi_nfc_setup_interface()
1449 min_clk_period = timings->tDH_min; in sunxi_nfc_setup_interface()
1452 if (timings->tRR_min > (min_clk_period * 3)) in sunxi_nfc_setup_interface()
1453 min_clk_period = DIV_ROUND_UP(timings->tRR_min, 3); in sunxi_nfc_setup_interface()
1456 if (timings->tALH_min > min_clk_period) in sunxi_nfc_setup_interface()
1457 min_clk_period = timings->tALH_min; in sunxi_nfc_setup_interface()
1460 if (timings->tRP_min > min_clk_period) in sunxi_nfc_setup_interface()
1461 min_clk_period = timings->tRP_min; in sunxi_nfc_setup_interface()
1464 if (timings->tREH_min > min_clk_period) in sunxi_nfc_setup_interface()
1465 min_clk_period = timings->tREH_min; in sunxi_nfc_setup_interface()
1468 if (timings->tRC_min > (min_clk_period * 2)) in sunxi_nfc_setup_interface()
1469 min_clk_period = DIV_ROUND_UP(timings->tRC_min, 2); in sunxi_nfc_setup_interface()
1472 if (timings->tWC_min > (min_clk_period * 2)) in sunxi_nfc_setup_interface()
1473 min_clk_period = DIV_ROUND_UP(timings->tWC_min, 2); in sunxi_nfc_setup_interface()
1475 /* T16 - T19 + tCAD */ in sunxi_nfc_setup_interface()
1476 if (timings->tWB_max > (min_clk_period * 20)) in sunxi_nfc_setup_interface()
1477 min_clk_period = DIV_ROUND_UP(timings->tWB_max, 20); in sunxi_nfc_setup_interface()
1479 if (timings->tADL_min > (min_clk_period * 32)) in sunxi_nfc_setup_interface()
1480 min_clk_period = DIV_ROUND_UP(timings->tADL_min, 32); in sunxi_nfc_setup_interface()
1482 if (timings->tWHR_min > (min_clk_period * 32)) in sunxi_nfc_setup_interface()
1483 min_clk_period = DIV_ROUND_UP(timings->tWHR_min, 32); in sunxi_nfc_setup_interface()
1485 if (timings->tRHW_min > (min_clk_period * 20)) in sunxi_nfc_setup_interface()
1486 min_clk_period = DIV_ROUND_UP(timings->tRHW_min, 20); in sunxi_nfc_setup_interface()
1489 * In non-EDO, tREA should be less than tRP to guarantee that the in sunxi_nfc_setup_interface()
1491 * the sunxi NAND controller does not allow us to have different in sunxi_nfc_setup_interface()
1497 * 2/ Use EDO mode (only works if timings->tRLOH > 0) in sunxi_nfc_setup_interface()
1499 if (timings->tREA_max > min_clk_period && !timings->tRLOH_min) in sunxi_nfc_setup_interface()
1500 min_clk_period = timings->tREA_max; in sunxi_nfc_setup_interface()
1502 tWB = sunxi_nand_lookup_timing(tWB_lut, timings->tWB_max, in sunxi_nfc_setup_interface()
1505 dev_err(nfc->dev, "unsupported tWB\n"); in sunxi_nfc_setup_interface()
1509 tADL = DIV_ROUND_UP(timings->tADL_min, min_clk_period) >> 3; in sunxi_nfc_setup_interface()
1511 dev_err(nfc->dev, "unsupported tADL\n"); in sunxi_nfc_setup_interface()
1512 return -EINVAL; in sunxi_nfc_setup_interface()
1515 tWHR = DIV_ROUND_UP(timings->tWHR_min, min_clk_period) >> 3; in sunxi_nfc_setup_interface()
1517 dev_err(nfc->dev, "unsupported tWHR\n"); in sunxi_nfc_setup_interface()
1518 return -EINVAL; in sunxi_nfc_setup_interface()
1521 tRHW = sunxi_nand_lookup_timing(tRHW_lut, timings->tRHW_min, in sunxi_nfc_setup_interface()
1524 dev_err(nfc->dev, "unsupported tRHW\n"); in sunxi_nfc_setup_interface()
1532 * TODO: according to ONFI specs this value only applies for DDR NAND, in sunxi_nfc_setup_interface()
1538 sunxi_nand->timing_cfg = NFC_TIMING_CFG(tWB, tADL, tWHR, tRHW, tCAD); in sunxi_nfc_setup_interface()
1549 sunxi_nand->clk_rate = NSEC_PER_SEC / min_clk_period; in sunxi_nfc_setup_interface()
1550 real_clk_rate = clk_round_rate(nfc->mod_clk, sunxi_nand->clk_rate); in sunxi_nfc_setup_interface()
1552 dev_err(nfc->dev, "Unable to round clk %lu\n", in sunxi_nfc_setup_interface()
1553 sunxi_nand->clk_rate); in sunxi_nfc_setup_interface()
1554 return -EINVAL; in sunxi_nfc_setup_interface()
1557 sunxi_nand->timing_ctl = 0; in sunxi_nfc_setup_interface()
1565 if (min_clk_period * 2 < 30 || min_clk_period * 1000 < timings->tREA_max) in sunxi_nfc_setup_interface()
1566 sunxi_nand->timing_ctl = NFC_TIMING_CTL_EDO; in sunxi_nfc_setup_interface()
1574 struct nand_chip *nand = mtd_to_nand(mtd); in sunxi_nand_ooblayout_ecc() local
1575 struct nand_ecc_ctrl *ecc = &nand->ecc; in sunxi_nand_ooblayout_ecc() local
1577 if (section >= ecc->steps) in sunxi_nand_ooblayout_ecc()
1578 return -ERANGE; in sunxi_nand_ooblayout_ecc()
1580 oobregion->offset = section * (ecc->bytes + 4) + 4; in sunxi_nand_ooblayout_ecc()
1581 oobregion->length = ecc->bytes; in sunxi_nand_ooblayout_ecc()
1589 struct nand_chip *nand = mtd_to_nand(mtd); in sunxi_nand_ooblayout_free() local
1590 struct nand_ecc_ctrl *ecc = &nand->ecc; in sunxi_nand_ooblayout_free() local
1592 if (section > ecc->steps) in sunxi_nand_ooblayout_free()
1593 return -ERANGE; in sunxi_nand_ooblayout_free()
1600 if (!section && ecc->engine_type == NAND_ECC_ENGINE_TYPE_ON_HOST) { in sunxi_nand_ooblayout_free()
1601 oobregion->offset = 2; in sunxi_nand_ooblayout_free()
1602 oobregion->length = 2; in sunxi_nand_ooblayout_free()
1607 oobregion->offset = section * (ecc->bytes + 4); in sunxi_nand_ooblayout_free()
1609 if (section < ecc->steps) in sunxi_nand_ooblayout_free()
1610 oobregion->length = 4; in sunxi_nand_ooblayout_free()
1612 oobregion->offset = mtd->oobsize - oobregion->offset; in sunxi_nand_ooblayout_free()
1618 .ecc = sunxi_nand_ooblayout_ecc,
1624 kfree(sunxi_nand->ecc); in sunxi_nand_hw_ecc_ctrl_cleanup()
1627 static int sunxi_nand_hw_ecc_ctrl_init(struct nand_chip *nand, in sunxi_nand_hw_ecc_ctrl_init() argument
1628 struct nand_ecc_ctrl *ecc, in sunxi_nand_hw_ecc_ctrl_init() argument
1632 struct sunxi_nand_chip *sunxi_nand = to_sunxi_nand(nand); in sunxi_nand_hw_ecc_ctrl_init()
1633 struct sunxi_nfc *nfc = to_sunxi_nfc(nand->controller); in sunxi_nand_hw_ecc_ctrl_init()
1634 struct mtd_info *mtd = nand_to_mtd(nand); in sunxi_nand_hw_ecc_ctrl_init()
1640 if (nanddev->ecc.user_conf.flags & NAND_ECC_MAXIMIZE_STRENGTH) { in sunxi_nand_hw_ecc_ctrl_init()
1643 ecc->size = 1024; in sunxi_nand_hw_ecc_ctrl_init()
1644 nsectors = mtd->writesize / ecc->size; in sunxi_nand_hw_ecc_ctrl_init()
1647 bytes = (mtd->oobsize - 2) / nsectors; in sunxi_nand_hw_ecc_ctrl_init()
1649 /* 4 non-ECC bytes are added before each ECC bytes section */ in sunxi_nand_hw_ecc_ctrl_init()
1650 bytes -= 4; in sunxi_nand_hw_ecc_ctrl_init()
1654 bytes--; in sunxi_nand_hw_ecc_ctrl_init()
1656 ecc->strength = bytes * 8 / fls(8 * ecc->size); in sunxi_nand_hw_ecc_ctrl_init()
1659 if (strengths[i] > ecc->strength) in sunxi_nand_hw_ecc_ctrl_init()
1664 ecc->strength = 0; in sunxi_nand_hw_ecc_ctrl_init()
1666 ecc->strength = strengths[i - 1]; in sunxi_nand_hw_ecc_ctrl_init()
1669 if (ecc->size != 512 && ecc->size != 1024) in sunxi_nand_hw_ecc_ctrl_init()
1670 return -EINVAL; in sunxi_nand_hw_ecc_ctrl_init()
1672 sunxi_nand->ecc = kzalloc(sizeof(*sunxi_nand->ecc), GFP_KERNEL); in sunxi_nand_hw_ecc_ctrl_init()
1673 if (!sunxi_nand->ecc) in sunxi_nand_hw_ecc_ctrl_init()
1674 return -ENOMEM; in sunxi_nand_hw_ecc_ctrl_init()
1676 /* Prefer 1k ECC chunk over 512 ones */ in sunxi_nand_hw_ecc_ctrl_init()
1677 if (ecc->size == 512 && mtd->writesize > 512) { in sunxi_nand_hw_ecc_ctrl_init()
1678 ecc->size = 1024; in sunxi_nand_hw_ecc_ctrl_init()
1679 ecc->strength *= 2; in sunxi_nand_hw_ecc_ctrl_init()
1682 /* Add ECC info retrieval from DT */ in sunxi_nand_hw_ecc_ctrl_init()
1684 if (ecc->strength <= strengths[i]) { in sunxi_nand_hw_ecc_ctrl_init()
1686 * Update ecc->strength value with the actual strength in sunxi_nand_hw_ecc_ctrl_init()
1687 * that will be used by the ECC engine. in sunxi_nand_hw_ecc_ctrl_init()
1689 ecc->strength = strengths[i]; in sunxi_nand_hw_ecc_ctrl_init()
1695 dev_err(nfc->dev, "unsupported strength\n"); in sunxi_nand_hw_ecc_ctrl_init()
1696 ret = -ENOTSUPP; in sunxi_nand_hw_ecc_ctrl_init()
1700 sunxi_nand->ecc->mode = i; in sunxi_nand_hw_ecc_ctrl_init()
1702 /* HW ECC always request ECC bytes for 1024 bytes blocks */ in sunxi_nand_hw_ecc_ctrl_init()
1703 ecc->bytes = DIV_ROUND_UP(ecc->strength * fls(8 * 1024), 8); in sunxi_nand_hw_ecc_ctrl_init()
1705 /* HW ECC always work with even numbers of ECC bytes */ in sunxi_nand_hw_ecc_ctrl_init()
1706 ecc->bytes = ALIGN(ecc->bytes, 2); in sunxi_nand_hw_ecc_ctrl_init()
1708 nsectors = mtd->writesize / ecc->size; in sunxi_nand_hw_ecc_ctrl_init()
1710 if (mtd->oobsize < ((ecc->bytes + 4) * nsectors)) { in sunxi_nand_hw_ecc_ctrl_init()
1711 ret = -EINVAL; in sunxi_nand_hw_ecc_ctrl_init()
1715 ecc->read_oob = sunxi_nfc_hw_ecc_read_oob; in sunxi_nand_hw_ecc_ctrl_init()
1716 ecc->write_oob = sunxi_nfc_hw_ecc_write_oob; in sunxi_nand_hw_ecc_ctrl_init()
1719 if (nfc->dmac || nfc->caps->has_mdma) { in sunxi_nand_hw_ecc_ctrl_init()
1720 ecc->read_page = sunxi_nfc_hw_ecc_read_page_dma; in sunxi_nand_hw_ecc_ctrl_init()
1721 ecc->read_subpage = sunxi_nfc_hw_ecc_read_subpage_dma; in sunxi_nand_hw_ecc_ctrl_init()
1722 ecc->write_page = sunxi_nfc_hw_ecc_write_page_dma; in sunxi_nand_hw_ecc_ctrl_init()
1723 nand->options |= NAND_USES_DMA; in sunxi_nand_hw_ecc_ctrl_init()
1725 ecc->read_page = sunxi_nfc_hw_ecc_read_page; in sunxi_nand_hw_ecc_ctrl_init()
1726 ecc->read_subpage = sunxi_nfc_hw_ecc_read_subpage; in sunxi_nand_hw_ecc_ctrl_init()
1727 ecc->write_page = sunxi_nfc_hw_ecc_write_page; in sunxi_nand_hw_ecc_ctrl_init()
1731 ecc->write_subpage = sunxi_nfc_hw_ecc_write_subpage; in sunxi_nand_hw_ecc_ctrl_init()
1732 ecc->read_oob_raw = nand_read_oob_std; in sunxi_nand_hw_ecc_ctrl_init()
1733 ecc->write_oob_raw = nand_write_oob_std; in sunxi_nand_hw_ecc_ctrl_init()
1738 kfree(sunxi_nand->ecc); in sunxi_nand_hw_ecc_ctrl_init()
1745 struct nand_ecc_ctrl *ecc = &sunxi_nand->nand.ecc; in sunxi_nand_ecc_cleanup() local
1747 switch (ecc->engine_type) { in sunxi_nand_ecc_cleanup()
1757 static int sunxi_nand_attach_chip(struct nand_chip *nand) in sunxi_nand_attach_chip() argument
1760 nanddev_get_ecc_requirements(&nand->base); in sunxi_nand_attach_chip()
1761 struct nand_ecc_ctrl *ecc = &nand->ecc; in sunxi_nand_attach_chip() local
1762 struct device_node *np = nand_get_flash_node(nand); in sunxi_nand_attach_chip()
1765 if (nand->bbt_options & NAND_BBT_USE_FLASH) in sunxi_nand_attach_chip()
1766 nand->bbt_options |= NAND_BBT_NO_OOB; in sunxi_nand_attach_chip()
1768 if (nand->options & NAND_NEED_SCRAMBLING) in sunxi_nand_attach_chip()
1769 nand->options |= NAND_NO_SUBPAGE_WRITE; in sunxi_nand_attach_chip()
1771 nand->options |= NAND_SUBPAGE_READ; in sunxi_nand_attach_chip()
1773 if (!ecc->size) { in sunxi_nand_attach_chip()
1774 ecc->size = requirements->step_size; in sunxi_nand_attach_chip()
1775 ecc->strength = requirements->strength; in sunxi_nand_attach_chip()
1778 if (!ecc->size || !ecc->strength) in sunxi_nand_attach_chip()
1779 return -EINVAL; in sunxi_nand_attach_chip()
1781 switch (ecc->engine_type) { in sunxi_nand_attach_chip()
1783 ret = sunxi_nand_hw_ecc_ctrl_init(nand, ecc, np); in sunxi_nand_attach_chip()
1791 return -EINVAL; in sunxi_nand_attach_chip()
1797 static int sunxi_nfc_exec_subop(struct nand_chip *nand, in sunxi_nfc_exec_subop() argument
1800 struct sunxi_nfc *nfc = to_sunxi_nfc(nand->controller); in sunxi_nfc_exec_subop()
1806 for (i = 0; i < subop->ninstrs; i++) { in sunxi_nfc_exec_subop()
1807 const struct nand_op_instr *instr = &subop->instrs[i]; in sunxi_nfc_exec_subop()
1809 switch (instr->type) { in sunxi_nfc_exec_subop()
1813 return -EINVAL; in sunxi_nfc_exec_subop()
1816 extcmd |= instr->ctx.cmd.opcode; in sunxi_nfc_exec_subop()
1819 NFC_CMD(instr->ctx.cmd.opcode); in sunxi_nfc_exec_subop()
1827 u32 addr = instr->ctx.addr.addrs[j + start]; in sunxi_nfc_exec_subop()
1844 if (instr->type == NAND_OP_DATA_OUT_INSTR) { in sunxi_nfc_exec_subop()
1846 memcpy_toio(nfc->regs + NFC_RAM0_BASE, in sunxi_nfc_exec_subop()
1847 instr->ctx.data.buf.out + start, in sunxi_nfc_exec_subop()
1850 inbuf = instr->ctx.data.buf.in + start; in sunxi_nfc_exec_subop()
1866 writel(addrs[0], nfc->regs + NFC_REG_ADDR_LOW); in sunxi_nfc_exec_subop()
1867 writel(addrs[1], nfc->regs + NFC_REG_ADDR_HIGH); in sunxi_nfc_exec_subop()
1872 nfc->regs + in sunxi_nfc_exec_subop()
1877 writel(cnt, nfc->regs + NFC_REG_CNT); in sunxi_nfc_exec_subop()
1879 writel(cmd, nfc->regs + NFC_REG_CMD); in sunxi_nfc_exec_subop()
1888 memcpy_fromio(inbuf, nfc->regs + NFC_RAM0_BASE, cnt); in sunxi_nfc_exec_subop()
1893 static int sunxi_nfc_soft_waitrdy(struct nand_chip *nand, in sunxi_nfc_soft_waitrdy() argument
1896 return nand_soft_waitrdy(nand, in sunxi_nfc_soft_waitrdy()
1897 subop->instrs[0].ctx.waitrdy.timeout_ms); in sunxi_nfc_soft_waitrdy()
1930 static int sunxi_nfc_exec_op(struct nand_chip *nand, in sunxi_nfc_exec_op() argument
1933 struct sunxi_nand_chip *sunxi_nand = to_sunxi_nand(nand); in sunxi_nfc_exec_op()
1937 sunxi_nfc_select_chip(nand, op->cs); in sunxi_nfc_exec_op()
1939 if (sunxi_nand->sels[op->cs].rb >= 0) in sunxi_nfc_exec_op()
1944 return nand_op_parser_exec_op(nand, parser, op, check_only); in sunxi_nfc_exec_op()
1958 struct nand_chip *nand; in sunxi_nand_chip_init() local
1965 return -EINVAL; in sunxi_nand_chip_init()
1970 return -EINVAL; in sunxi_nand_chip_init()
1976 return -ENOMEM; in sunxi_nand_chip_init()
1978 sunxi_nand->nsels = nsels; in sunxi_nand_chip_init()
1992 return -EINVAL; in sunxi_nand_chip_init()
1995 if (test_and_set_bit(tmp, &nfc->assigned_cs)) { in sunxi_nand_chip_init()
1997 return -EINVAL; in sunxi_nand_chip_init()
2000 sunxi_nand->sels[i].cs = tmp; in sunxi_nand_chip_init()
2004 sunxi_nand->sels[i].rb = tmp; in sunxi_nand_chip_init()
2006 sunxi_nand->sels[i].rb = -1; in sunxi_nand_chip_init()
2009 nand = &sunxi_nand->nand; in sunxi_nand_chip_init()
2011 nand->controller = &nfc->controller; in sunxi_nand_chip_init()
2012 nand->controller->ops = &sunxi_nand_controller_ops; in sunxi_nand_chip_init()
2015 * Set the ECC mode to the default value in case nothing is specified in sunxi_nand_chip_init()
2018 nand->ecc.engine_type = NAND_ECC_ENGINE_TYPE_ON_HOST; in sunxi_nand_chip_init()
2019 nand_set_flash_node(nand, np); in sunxi_nand_chip_init()
2021 mtd = nand_to_mtd(nand); in sunxi_nand_chip_init()
2022 mtd->dev.parent = dev; in sunxi_nand_chip_init()
2024 ret = nand_scan(nand, nsels); in sunxi_nand_chip_init()
2031 nand_cleanup(nand); in sunxi_nand_chip_init()
2035 list_add_tail(&sunxi_nand->node, &nfc->chips); in sunxi_nand_chip_init()
2042 struct device_node *np = dev->of_node; in sunxi_nand_chips_init()
2048 dev_err(dev, "too many NAND chips: %d (max = 8)\n", nchips); in sunxi_nand_chips_init()
2049 return -EINVAL; in sunxi_nand_chips_init()
2069 while (!list_empty(&nfc->chips)) { in sunxi_nand_chips_cleanup()
2070 sunxi_nand = list_first_entry(&nfc->chips, in sunxi_nand_chips_cleanup()
2073 chip = &sunxi_nand->nand; in sunxi_nand_chips_cleanup()
2078 list_del(&sunxi_nand->node); in sunxi_nand_chips_cleanup()
2086 if (nfc->caps->has_mdma) in sunxi_nfc_dma_init()
2089 nfc->dmac = dma_request_chan(nfc->dev, "rxtx"); in sunxi_nfc_dma_init()
2090 if (IS_ERR(nfc->dmac)) { in sunxi_nfc_dma_init()
2091 ret = PTR_ERR(nfc->dmac); in sunxi_nfc_dma_init()
2092 if (ret == -EPROBE_DEFER) in sunxi_nfc_dma_init()
2096 dev_warn(nfc->dev, "failed to request rxtx DMA channel: %d\n", ret); in sunxi_nfc_dma_init()
2097 nfc->dmac = NULL; in sunxi_nfc_dma_init()
2101 dmac_cfg.src_addr = r->start + nfc->caps->reg_io_data; in sunxi_nfc_dma_init()
2105 dmac_cfg.src_maxburst = nfc->caps->dma_maxburst; in sunxi_nfc_dma_init()
2106 dmac_cfg.dst_maxburst = nfc->caps->dma_maxburst; in sunxi_nfc_dma_init()
2107 dmaengine_slave_config(nfc->dmac, &dmac_cfg); in sunxi_nfc_dma_init()
2114 struct device *dev = &pdev->dev; in sunxi_nfc_probe()
2122 return -ENOMEM; in sunxi_nfc_probe()
2124 nfc->dev = dev; in sunxi_nfc_probe()
2125 nand_controller_init(&nfc->controller); in sunxi_nfc_probe()
2126 INIT_LIST_HEAD(&nfc->chips); in sunxi_nfc_probe()
2129 nfc->regs = devm_ioremap_resource(dev, r); in sunxi_nfc_probe()
2130 if (IS_ERR(nfc->regs)) in sunxi_nfc_probe()
2131 return PTR_ERR(nfc->regs); in sunxi_nfc_probe()
2137 nfc->ahb_clk = devm_clk_get(dev, "ahb"); in sunxi_nfc_probe()
2138 if (IS_ERR(nfc->ahb_clk)) { in sunxi_nfc_probe()
2140 return PTR_ERR(nfc->ahb_clk); in sunxi_nfc_probe()
2143 ret = clk_prepare_enable(nfc->ahb_clk); in sunxi_nfc_probe()
2147 nfc->mod_clk = devm_clk_get(dev, "mod"); in sunxi_nfc_probe()
2148 if (IS_ERR(nfc->mod_clk)) { in sunxi_nfc_probe()
2150 ret = PTR_ERR(nfc->mod_clk); in sunxi_nfc_probe()
2154 ret = clk_prepare_enable(nfc->mod_clk); in sunxi_nfc_probe()
2158 nfc->reset = devm_reset_control_get_optional_exclusive(dev, "ahb"); in sunxi_nfc_probe()
2159 if (IS_ERR(nfc->reset)) { in sunxi_nfc_probe()
2160 ret = PTR_ERR(nfc->reset); in sunxi_nfc_probe()
2164 ret = reset_control_deassert(nfc->reset); in sunxi_nfc_probe()
2170 nfc->caps = of_device_get_match_data(&pdev->dev); in sunxi_nfc_probe()
2171 if (!nfc->caps) { in sunxi_nfc_probe()
2172 ret = -EINVAL; in sunxi_nfc_probe()
2180 writel(0, nfc->regs + NFC_REG_INT); in sunxi_nfc_probe()
2182 0, "sunxi-nand", nfc); in sunxi_nfc_probe()
2195 dev_err(dev, "failed to init nand chips\n"); in sunxi_nfc_probe()
2202 if (nfc->dmac) in sunxi_nfc_probe()
2203 dma_release_channel(nfc->dmac); in sunxi_nfc_probe()
2205 reset_control_assert(nfc->reset); in sunxi_nfc_probe()
2207 clk_disable_unprepare(nfc->mod_clk); in sunxi_nfc_probe()
2209 clk_disable_unprepare(nfc->ahb_clk); in sunxi_nfc_probe()
2220 reset_control_assert(nfc->reset); in sunxi_nfc_remove()
2222 if (nfc->dmac) in sunxi_nfc_remove()
2223 dma_release_channel(nfc->dmac); in sunxi_nfc_remove()
2224 clk_disable_unprepare(nfc->mod_clk); in sunxi_nfc_remove()
2225 clk_disable_unprepare(nfc->ahb_clk); in sunxi_nfc_remove()
2243 .compatible = "allwinner,sun4i-a10-nand",
2247 .compatible = "allwinner,sun8i-a23-nand-controller",
2266 MODULE_DESCRIPTION("Allwinner NAND Flash Controller driver");