Lines Matching +full:cmd +full:- +full:dat +full:- +full:delay +full:- +full:select
1 // SPDX-License-Identifier: GPL-2.0-or-later
3 * Copyright © 2004-2008 Simtec Electronics
10 #define pr_fmt(fmt) "nand-s3c2410: " fmt
23 #include <linux/delay.h>
34 #include <linux/platform_data/mtd-nand-s3c2410.h>
77 return -ERANGE; in s3c2410_ooblayout_ecc()
79 oobregion->offset = 0; in s3c2410_ooblayout_ecc()
80 oobregion->length = 3; in s3c2410_ooblayout_ecc()
89 return -ERANGE; in s3c2410_ooblayout_free()
91 oobregion->offset = 8; in s3c2410_ooblayout_free()
92 oobregion->length = 8; in s3c2410_ooblayout_free()
107 * struct s3c2410_nand_mtd - driver MTD structure
134 * struct s3c2410_nand_info - NAND controller state.
142 * @sel_bit: The bit in @sel_reg to select the NAND chip.
196 return s3c2410_nand_mtd_toours(mtd)->info; in s3c2410_nand_mtd_toinfo()
206 return dev_get_platdata(&dev->dev); in to_nand_plat()
219 * s3c2410_nand_clk_set_state - Enable, disable or suspend NAND clock.
229 if (info->clk_state == CLOCK_ENABLE) { in s3c2410_nand_clk_set_state()
231 clk_disable_unprepare(info->clk); in s3c2410_nand_clk_set_state()
234 clk_prepare_enable(info->clk); in s3c2410_nand_clk_set_state()
237 info->clk_state = new_state; in s3c2410_nand_clk_set_state()
245 * s3c_nand_calc_rate - calculate timing data.
263 return -1; in s3c_nand_calc_rate()
277 * s3c2410_nand_setrate - setup controller timing information.
286 struct s3c2410_platform_nand *plat = info->platform; in s3c2410_nand_setrate()
287 int tacls_max = (info->cpu_type == TYPE_S3C2412) ? 8 : 4; in s3c2410_nand_setrate()
289 unsigned long clkrate = clk_get_rate(info->clk); in s3c2410_nand_setrate()
295 info->clk_rate = clkrate; in s3c2410_nand_setrate()
299 tacls = s3c_nand_calc_rate(plat->tacls, clkrate, tacls_max); in s3c2410_nand_setrate()
300 twrph0 = s3c_nand_calc_rate(plat->twrph0, clkrate, 8); in s3c2410_nand_setrate()
301 twrph1 = s3c_nand_calc_rate(plat->twrph1, clkrate, 8); in s3c2410_nand_setrate()
310 dev_err(info->device, "cannot get suitable timings\n"); in s3c2410_nand_setrate()
311 return -EINVAL; in s3c2410_nand_setrate()
314 dev_info(info->device, "Tacls=%d, %dns Twrph0=%d %dns, Twrph1=%d %dns\n", in s3c2410_nand_setrate()
318 switch (info->cpu_type) { in s3c2410_nand_setrate()
324 set |= S3C2410_NFCONF_TACLS(tacls - 1); in s3c2410_nand_setrate()
325 set |= S3C2410_NFCONF_TWRPH0(twrph0 - 1); in s3c2410_nand_setrate()
326 set |= S3C2410_NFCONF_TWRPH1(twrph1 - 1); in s3c2410_nand_setrate()
331 mask = (S3C2440_NFCONF_TACLS(tacls_max - 1) | in s3c2410_nand_setrate()
335 set = S3C2440_NFCONF_TACLS(tacls - 1); in s3c2410_nand_setrate()
336 set |= S3C2440_NFCONF_TWRPH0(twrph0 - 1); in s3c2410_nand_setrate()
337 set |= S3C2440_NFCONF_TWRPH1(twrph1 - 1); in s3c2410_nand_setrate()
346 cfg = readl(info->regs + S3C2410_NFCONF); in s3c2410_nand_setrate()
349 writel(cfg, info->regs + S3C2410_NFCONF); in s3c2410_nand_setrate()
353 dev_dbg(info->device, "NF_CONF is 0x%lx\n", cfg); in s3c2410_nand_setrate()
359 * s3c2410_nand_inithw - basic hardware initialisation
373 switch (info->cpu_type) { in s3c2410_nand_inithw()
380 /* enable the controller and de-assert nFCE */ in s3c2410_nand_inithw()
382 writel(S3C2440_NFCONT_ENABLE, info->regs + S3C2440_NFCONT); in s3c2410_nand_inithw()
389 * s3c2410_nand_select_chip - select the given nand chip
393 * This is called by the MTD layer to either select a given chip for the
395 * chip can be de-selected.
408 info = nmtd->info; in s3c2410_nand_select_chip()
410 if (chip != -1) in s3c2410_nand_select_chip()
413 cur = readl(info->sel_reg); in s3c2410_nand_select_chip()
415 if (chip == -1) { in s3c2410_nand_select_chip()
416 cur |= info->sel_bit; in s3c2410_nand_select_chip()
418 if (nmtd->set != NULL && chip > nmtd->set->nr_chips) { in s3c2410_nand_select_chip()
419 dev_err(info->device, "invalid chip %d\n", chip); in s3c2410_nand_select_chip()
423 if (info->platform != NULL) { in s3c2410_nand_select_chip()
424 if (info->platform->select_chip != NULL) in s3c2410_nand_select_chip()
425 (info->platform->select_chip) (nmtd->set, chip); in s3c2410_nand_select_chip()
428 cur &= ~info->sel_bit; in s3c2410_nand_select_chip()
431 writel(cur, info->sel_reg); in s3c2410_nand_select_chip()
433 if (chip == -1) in s3c2410_nand_select_chip()
442 static void s3c2410_nand_hwcontrol(struct nand_chip *chip, int cmd, in s3c2410_nand_hwcontrol() argument
448 if (cmd == NAND_CMD_NONE) in s3c2410_nand_hwcontrol()
452 writeb(cmd, info->regs + S3C2410_NFCMD); in s3c2410_nand_hwcontrol()
454 writeb(cmd, info->regs + S3C2410_NFADDR); in s3c2410_nand_hwcontrol()
459 static void s3c2440_nand_hwcontrol(struct nand_chip *chip, int cmd, in s3c2440_nand_hwcontrol() argument
465 if (cmd == NAND_CMD_NONE) in s3c2440_nand_hwcontrol()
469 writeb(cmd, info->regs + S3C2440_NFCMD); in s3c2440_nand_hwcontrol()
471 writeb(cmd, info->regs + S3C2440_NFADDR); in s3c2440_nand_hwcontrol()
483 return readb(info->regs + S3C2410_NFSTAT) & S3C2410_NFSTAT_BUSY; in s3c2410_nand_devready()
490 return readb(info->regs + S3C2440_NFSTAT) & S3C2440_NFSTAT_READY; in s3c2440_nand_devready()
497 return readb(info->regs + S3C2412_NFSTAT) & S3C2412_NFSTAT_READY; in s3c2412_nand_devready()
502 static int s3c2410_nand_correct_data(struct nand_chip *chip, u_char *dat, in s3c2410_nand_correct_data() argument
510 pr_debug("%s(%p,%p,%p,%p)\n", __func__, mtd, dat, read_ecc, calc_ecc); in s3c2410_nand_correct_data()
525 * the error, on the assumption that this is an un-eccd page. in s3c2410_nand_correct_data()
528 && info->platform->ignore_unset_ecc) in s3c2410_nand_correct_data()
555 dev_dbg(info->device, "correcting error bit %d, byte %d\n", in s3c2410_nand_correct_data()
558 dat[byte] ^= (1 << bit); in s3c2410_nand_correct_data()
570 if ((diff0 & (diff0 - 1)) == 0) in s3c2410_nand_correct_data()
573 return -1; in s3c2410_nand_correct_data()
588 ctrl = readl(info->regs + S3C2410_NFCONF); in s3c2410_nand_enable_hwecc()
590 writel(ctrl, info->regs + S3C2410_NFCONF); in s3c2410_nand_enable_hwecc()
599 ctrl = readl(info->regs + S3C2440_NFCONT); in s3c2412_nand_enable_hwecc()
601 info->regs + S3C2440_NFCONT); in s3c2412_nand_enable_hwecc()
610 ctrl = readl(info->regs + S3C2440_NFCONT); in s3c2440_nand_enable_hwecc()
611 writel(ctrl | S3C2440_NFCONT_INITECC, info->regs + S3C2440_NFCONT); in s3c2440_nand_enable_hwecc()
615 const u_char *dat, u_char *ecc_code) in s3c2410_nand_calculate_ecc() argument
620 ecc_code[0] = readb(info->regs + S3C2410_NFECC + 0); in s3c2410_nand_calculate_ecc()
621 ecc_code[1] = readb(info->regs + S3C2410_NFECC + 1); in s3c2410_nand_calculate_ecc()
622 ecc_code[2] = readb(info->regs + S3C2410_NFECC + 2); in s3c2410_nand_calculate_ecc()
630 const u_char *dat, u_char *ecc_code) in s3c2412_nand_calculate_ecc() argument
634 unsigned long ecc = readl(info->regs + S3C2412_NFMECC0); in s3c2412_nand_calculate_ecc()
646 const u_char *dat, u_char *ecc_code) in s3c2440_nand_calculate_ecc() argument
650 unsigned long ecc = readl(info->regs + S3C2440_NFMECC0); in s3c2440_nand_calculate_ecc()
661 /* over-ride the standard functions for a little more speed. We can
667 readsb(this->legacy.IO_ADDR_R, buf, len); in s3c2410_nand_read_buf()
675 readsl(info->regs + S3C2440_NFDATA, buf, len >> 2); in s3c2440_nand_read_buf()
681 for (; len & 3; len--) in s3c2440_nand_read_buf()
682 *buf++ = readb(info->regs + S3C2440_NFDATA); in s3c2440_nand_read_buf()
689 writesb(this->legacy.IO_ADDR_W, buf, len); in s3c2410_nand_write_buf()
698 writesl(info->regs + S3C2440_NFDATA, buf, len >> 2); in s3c2440_nand_write_buf()
704 for (; len & 3; len--, buf++) in s3c2440_nand_write_buf()
705 writeb(*buf, info->regs + S3C2440_NFDATA); in s3c2440_nand_write_buf()
722 if (info->mtds != NULL) { in s3c24xx_nand_remove()
723 struct s3c2410_nand_mtd *ptr = info->mtds; in s3c24xx_nand_remove()
726 for (mtdno = 0; mtdno < info->mtd_count; mtdno++, ptr++) { in s3c24xx_nand_remove()
728 WARN_ON(mtd_device_unregister(nand_to_mtd(&ptr->chip))); in s3c24xx_nand_remove()
729 nand_cleanup(&ptr->chip); in s3c24xx_nand_remove()
735 if (!IS_ERR(info->clk)) in s3c24xx_nand_remove()
744 struct mtd_info *mtdinfo = nand_to_mtd(&mtd->chip); in s3c2410_nand_add_partition()
746 mtdinfo->name = set->name; in s3c2410_nand_add_partition()
748 return mtd_device_register(mtdinfo, set->partitions, in s3c2410_nand_add_partition()
749 set->nr_partitions); in s3c2410_nand_add_partition()
752 return -ENODEV; in s3c2410_nand_add_partition()
760 struct s3c2410_platform_nand *pdata = info->platform; in s3c2410_nand_setup_interface()
766 return -ENOTSUPP; in s3c2410_nand_setup_interface()
768 tacls = timings->tCLS_min - timings->tWP_min; in s3c2410_nand_setup_interface()
772 pdata->tacls = DIV_ROUND_UP(tacls, 1000); in s3c2410_nand_setup_interface()
773 pdata->twrph0 = DIV_ROUND_UP(timings->tWP_min, 1000); in s3c2410_nand_setup_interface()
774 pdata->twrph1 = DIV_ROUND_UP(timings->tCLH_min, 1000); in s3c2410_nand_setup_interface()
780 * s3c2410_nand_init_chip - initialise a single instance of an chip
793 struct device_node *np = info->device->of_node; in s3c2410_nand_init_chip()
794 struct nand_chip *chip = &nmtd->chip; in s3c2410_nand_init_chip()
795 void __iomem *regs = info->regs; in s3c2410_nand_init_chip()
797 nand_set_flash_node(chip, set->of_node); in s3c2410_nand_init_chip()
799 chip->legacy.write_buf = s3c2410_nand_write_buf; in s3c2410_nand_init_chip()
800 chip->legacy.read_buf = s3c2410_nand_read_buf; in s3c2410_nand_init_chip()
801 chip->legacy.select_chip = s3c2410_nand_select_chip; in s3c2410_nand_init_chip()
802 chip->legacy.chip_delay = 50; in s3c2410_nand_init_chip()
804 chip->options = set->options; in s3c2410_nand_init_chip()
805 chip->controller = &info->controller; in s3c2410_nand_init_chip()
809 * auto-detect timings only when booting with a device tree. in s3c2410_nand_init_chip()
812 chip->options |= NAND_KEEP_TIMINGS; in s3c2410_nand_init_chip()
814 switch (info->cpu_type) { in s3c2410_nand_init_chip()
816 chip->legacy.IO_ADDR_W = regs + S3C2410_NFDATA; in s3c2410_nand_init_chip()
817 info->sel_reg = regs + S3C2410_NFCONF; in s3c2410_nand_init_chip()
818 info->sel_bit = S3C2410_NFCONF_nFCE; in s3c2410_nand_init_chip()
819 chip->legacy.cmd_ctrl = s3c2410_nand_hwcontrol; in s3c2410_nand_init_chip()
820 chip->legacy.dev_ready = s3c2410_nand_devready; in s3c2410_nand_init_chip()
824 chip->legacy.IO_ADDR_W = regs + S3C2440_NFDATA; in s3c2410_nand_init_chip()
825 info->sel_reg = regs + S3C2440_NFCONT; in s3c2410_nand_init_chip()
826 info->sel_bit = S3C2440_NFCONT_nFCE; in s3c2410_nand_init_chip()
827 chip->legacy.cmd_ctrl = s3c2440_nand_hwcontrol; in s3c2410_nand_init_chip()
828 chip->legacy.dev_ready = s3c2440_nand_devready; in s3c2410_nand_init_chip()
829 chip->legacy.read_buf = s3c2440_nand_read_buf; in s3c2410_nand_init_chip()
830 chip->legacy.write_buf = s3c2440_nand_write_buf; in s3c2410_nand_init_chip()
834 chip->legacy.IO_ADDR_W = regs + S3C2440_NFDATA; in s3c2410_nand_init_chip()
835 info->sel_reg = regs + S3C2440_NFCONT; in s3c2410_nand_init_chip()
836 info->sel_bit = S3C2412_NFCONT_nFCE0; in s3c2410_nand_init_chip()
837 chip->legacy.cmd_ctrl = s3c2440_nand_hwcontrol; in s3c2410_nand_init_chip()
838 chip->legacy.dev_ready = s3c2412_nand_devready; in s3c2410_nand_init_chip()
841 dev_info(info->device, "System booted from NAND\n"); in s3c2410_nand_init_chip()
846 chip->legacy.IO_ADDR_R = chip->legacy.IO_ADDR_W; in s3c2410_nand_init_chip()
848 nmtd->info = info; in s3c2410_nand_init_chip()
849 nmtd->set = set; in s3c2410_nand_init_chip()
851 chip->ecc.engine_type = info->platform->engine_type; in s3c2410_nand_init_chip()
854 * If you use u-boot BBT creation code, specifying this flag will in s3c2410_nand_init_chip()
857 if (set->flash_bbt) in s3c2410_nand_init_chip()
858 chip->bbt_options |= NAND_BBT_USE_FLASH; in s3c2410_nand_init_chip()
862 * s3c2410_nand_attach_chip - Init the ECC engine after NAND scan
866 * once the relevant per-chip information is up to date.. This call ensure that
876 switch (chip->ecc.engine_type) { in s3c2410_nand_attach_chip()
879 dev_info(info->device, "ECC disabled\n"); in s3c2410_nand_attach_chip()
889 chip->ecc.algo = NAND_ECC_ALGO_HAMMING; in s3c2410_nand_attach_chip()
890 dev_info(info->device, "soft ECC\n"); in s3c2410_nand_attach_chip()
894 chip->ecc.calculate = s3c2410_nand_calculate_ecc; in s3c2410_nand_attach_chip()
895 chip->ecc.correct = s3c2410_nand_correct_data; in s3c2410_nand_attach_chip()
896 chip->ecc.strength = 1; in s3c2410_nand_attach_chip()
898 switch (info->cpu_type) { in s3c2410_nand_attach_chip()
900 chip->ecc.hwctl = s3c2410_nand_enable_hwecc; in s3c2410_nand_attach_chip()
901 chip->ecc.calculate = s3c2410_nand_calculate_ecc; in s3c2410_nand_attach_chip()
905 chip->ecc.hwctl = s3c2412_nand_enable_hwecc; in s3c2410_nand_attach_chip()
906 chip->ecc.calculate = s3c2412_nand_calculate_ecc; in s3c2410_nand_attach_chip()
910 chip->ecc.hwctl = s3c2440_nand_enable_hwecc; in s3c2410_nand_attach_chip()
911 chip->ecc.calculate = s3c2440_nand_calculate_ecc; in s3c2410_nand_attach_chip()
915 dev_dbg(info->device, "chip %p => page shift %d\n", in s3c2410_nand_attach_chip()
916 chip, chip->page_shift); in s3c2410_nand_attach_chip()
920 if (chip->page_shift > 10) { in s3c2410_nand_attach_chip()
921 chip->ecc.size = 256; in s3c2410_nand_attach_chip()
922 chip->ecc.bytes = 3; in s3c2410_nand_attach_chip()
924 chip->ecc.size = 512; in s3c2410_nand_attach_chip()
925 chip->ecc.bytes = 3; in s3c2410_nand_attach_chip()
930 dev_info(info->device, "hardware ECC\n"); in s3c2410_nand_attach_chip()
934 dev_err(info->device, "invalid ECC mode!\n"); in s3c2410_nand_attach_chip()
935 return -EINVAL; in s3c2410_nand_attach_chip()
938 if (chip->bbt_options & NAND_BBT_USE_FLASH) in s3c2410_nand_attach_chip()
939 chip->options |= NAND_SKIP_BBTSCAN; in s3c2410_nand_attach_chip()
951 .compatible = "samsung,s3c2410-nand",
955 .compatible = "samsung,s3c2412-nand",
958 .compatible = "samsung,s3c2440-nand",
970 struct device_node *np = pdev->dev.of_node, *child; in s3c24xx_nand_probe_dt()
973 devtype_data = of_device_get_match_data(&pdev->dev); in s3c24xx_nand_probe_dt()
975 return -ENODEV; in s3c24xx_nand_probe_dt()
977 info->cpu_type = devtype_data->type; in s3c24xx_nand_probe_dt()
979 pdata = devm_kzalloc(&pdev->dev, sizeof(*pdata), GFP_KERNEL); in s3c24xx_nand_probe_dt()
981 return -ENOMEM; in s3c24xx_nand_probe_dt()
983 pdev->dev.platform_data = pdata; in s3c24xx_nand_probe_dt()
985 pdata->nr_sets = of_get_child_count(np); in s3c24xx_nand_probe_dt()
986 if (!pdata->nr_sets) in s3c24xx_nand_probe_dt()
989 sets = devm_kcalloc(&pdev->dev, pdata->nr_sets, sizeof(*sets), in s3c24xx_nand_probe_dt()
992 return -ENOMEM; in s3c24xx_nand_probe_dt()
994 pdata->sets = sets; in s3c24xx_nand_probe_dt()
997 sets->name = (char *)child->name; in s3c24xx_nand_probe_dt()
998 sets->of_node = child; in s3c24xx_nand_probe_dt()
999 sets->nr_chips = 1; in s3c24xx_nand_probe_dt()
1013 info->cpu_type = platform_get_device_id(pdev)->driver_data; in s3c24xx_nand_probe_pdata()
1037 info = devm_kzalloc(&pdev->dev, sizeof(*info), GFP_KERNEL); in s3c24xx_nand_probe()
1039 err = -ENOMEM; in s3c24xx_nand_probe()
1045 nand_controller_init(&info->controller); in s3c24xx_nand_probe()
1046 info->controller.ops = &s3c24xx_nand_controller_ops; in s3c24xx_nand_probe()
1050 info->clk = devm_clk_get(&pdev->dev, "nand"); in s3c24xx_nand_probe()
1051 if (IS_ERR(info->clk)) { in s3c24xx_nand_probe()
1052 dev_err(&pdev->dev, "failed to get clock\n"); in s3c24xx_nand_probe()
1053 err = -ENOENT; in s3c24xx_nand_probe()
1059 if (pdev->dev.of_node) in s3c24xx_nand_probe()
1072 res = pdev->resource; in s3c24xx_nand_probe()
1075 info->device = &pdev->dev; in s3c24xx_nand_probe()
1076 info->platform = plat; in s3c24xx_nand_probe()
1078 info->regs = devm_ioremap_resource(&pdev->dev, res); in s3c24xx_nand_probe()
1079 if (IS_ERR(info->regs)) { in s3c24xx_nand_probe()
1080 err = PTR_ERR(info->regs); in s3c24xx_nand_probe()
1084 dev_dbg(&pdev->dev, "mapped registers at %p\n", info->regs); in s3c24xx_nand_probe()
1086 if (!plat->sets || plat->nr_sets < 1) { in s3c24xx_nand_probe()
1087 err = -EINVAL; in s3c24xx_nand_probe()
1091 sets = plat->sets; in s3c24xx_nand_probe()
1092 nr_sets = plat->nr_sets; in s3c24xx_nand_probe()
1094 info->mtd_count = nr_sets; in s3c24xx_nand_probe()
1098 size = nr_sets * sizeof(*info->mtds); in s3c24xx_nand_probe()
1099 info->mtds = devm_kzalloc(&pdev->dev, size, GFP_KERNEL); in s3c24xx_nand_probe()
1100 if (info->mtds == NULL) { in s3c24xx_nand_probe()
1101 err = -ENOMEM; in s3c24xx_nand_probe()
1107 nmtd = info->mtds; in s3c24xx_nand_probe()
1110 struct mtd_info *mtd = nand_to_mtd(&nmtd->chip); in s3c24xx_nand_probe()
1115 mtd->dev.parent = &pdev->dev; in s3c24xx_nand_probe()
1118 err = nand_scan(&nmtd->chip, sets ? sets->nr_chips : 1); in s3c24xx_nand_probe()
1131 dev_info(&pdev->dev, "clock idle support enabled\n"); in s3c24xx_nand_probe()
1141 err = -EINVAL; in s3c24xx_nand_probe()
1153 info->save_sel = readl(info->sel_reg); in s3c24xx_nand_suspend()
1160 writel(info->save_sel | info->sel_bit, info->sel_reg); in s3c24xx_nand_suspend()
1179 sel = readl(info->sel_reg); in s3c24xx_nand_resume()
1180 sel &= ~info->sel_bit; in s3c24xx_nand_resume()
1181 sel |= info->save_sel & info->sel_bit; in s3c24xx_nand_resume()
1182 writel(sel, info->sel_reg); in s3c24xx_nand_resume()
1199 .name = "s3c2410-nand",
1202 .name = "s3c2440-nand",
1205 .name = "s3c2412-nand",
1208 .name = "s3c6400-nand",
1223 .name = "s3c24xx-nand",