void __iomem *sel_reg;
int sel_bit;
int mtd_count;
+ unsigned long save_sel;
enum s3c_cpu_type cpu_type;
};
if (diff0 == 0 && diff1 == 0 && diff2 == 0)
return 0; /* ECC is ok */
+ /* sometimes people do not think about using the ECC, so check
+ * to see if we have an 0xff,0xff,0xff read ECC and then ignore
+ * the error, on the assumption that this is an un-eccd page.
+ */
+ if (read_ecc[0] == 0xff && read_ecc[1] == 0xff && read_ecc[2] == 0xff
+ && info->platform->ignore_unset_ecc)
+ return 0;
+
/* Can we correct this ECC (ie, one row and column change).
* Note, this is similar to the 256 error code on smartmedia */
((diff2 ^ (diff2 >> 1)) & 0x55) == 0x55) {
/* calculate the bit position of the error */
- bit = (diff2 >> 2) & 1;
- bit |= (diff2 >> 3) & 2;
- bit |= (diff2 >> 4) & 4;
+ bit = ((diff2 >> 3) & 1) |
+ ((diff2 >> 4) & 2) |
+ ((diff2 >> 5) & 4);
/* calculate the byte position of the error */
- byte = (diff1 << 1) & 0x80;
- byte |= (diff1 << 2) & 0x40;
- byte |= (diff1 << 3) & 0x20;
- byte |= (diff1 << 4) & 0x10;
-
- byte |= (diff0 >> 3) & 0x08;
- byte |= (diff0 >> 2) & 0x04;
- byte |= (diff0 >> 1) & 0x02;
- byte |= (diff0 >> 0) & 0x01;
-
- byte |= (diff2 << 8) & 0x100;
+ byte = ((diff2 << 7) & 0x100) |
+ ((diff1 << 0) & 0x80) |
+ ((diff1 << 1) & 0x40) |
+ ((diff1 << 2) & 0x20) |
+ ((diff1 << 3) & 0x10) |
+ ((diff0 >> 4) & 0x08) |
+ ((diff0 >> 3) & 0x04) |
+ ((diff0 >> 2) & 0x02) |
+ ((diff0 >> 1) & 0x01);
dev_dbg(info->device, "correcting error bit %d, byte %d\n",
bit, byte);
if ((diff0 & ~(1<<fls(diff0))) == 0)
return 1;
- return 0;
+ return -1;
}
/* ECC functions
ecc_code[1] = ecc >> 8;
ecc_code[2] = ecc >> 16;
- pr_debug("%s: returning ecc %06lx\n", __func__, ecc);
+ pr_debug("%s: returning ecc %06lx\n", __func__, ecc & 0xffffff);
return 0;
}
chip->ecc.calculate = s3c2410_nand_calculate_ecc;
chip->ecc.correct = s3c2410_nand_correct_data;
chip->ecc.mode = NAND_ECC_HW;
- chip->ecc.size = 512;
- chip->ecc.bytes = 3;
- chip->ecc.layout = &nand_hw_eccoob;
switch (info->cpu_type) {
case TYPE_S3C2410:
} else {
chip->ecc.mode = NAND_ECC_SOFT;
}
+
+ if (set->ecc_layout != NULL)
+ chip->ecc.layout = set->ecc_layout;
+
+ if (set->disable_ecc)
+ chip->ecc.mode = NAND_ECC_NONE;
+}
+
+/* s3c2410_nand_update_chip
+ *
+ * post-probe chip update, to change any items, such as the
+ * layout for large page nand
+ */
+
+static void s3c2410_nand_update_chip(struct s3c2410_nand_info *info,
+ struct s3c2410_nand_mtd *nmtd)
+{
+ struct nand_chip *chip = &nmtd->chip;
+
+ printk("%s: chip %p: %d\n", __func__, chip, chip->page_shift);
+
+ if (hardware_ecc) {
+ /* change the behaviour depending on wether we are using
+ * the large or small page nand device */
+
+ if (chip->page_shift > 10) {
+ chip->ecc.size = 256;
+ chip->ecc.bytes = 3;
+ } else {
+ chip->ecc.size = 512;
+ chip->ecc.bytes = 3;
+ chip->ecc.layout = &nand_hw_eccoob;
+ }
+ }
}
/* s3c2410_nand_probe
s3c2410_nand_init_chip(info, nmtd, sets);
- nmtd->scan_res = nand_scan(&nmtd->mtd, (sets) ? sets->nr_chips : 1);
+ nmtd->scan_res = nand_scan_ident(&nmtd->mtd,
+ (sets) ? sets->nr_chips : 1);
if (nmtd->scan_res == 0) {
+ s3c2410_nand_update_chip(info, nmtd);
+ nand_scan_tail(&nmtd->mtd);
s3c2410_nand_add_partition(info, nmtd, sets);
}
struct s3c2410_nand_info *info = platform_get_drvdata(dev);
if (info) {
+ info->save_sel = readl(info->sel_reg);
+
+ /* For the moment, we must ensure nFCE is high during
+ * the time we are suspended. This really should be
+ * handled by suspending the MTDs we are using, but
+ * that is currently not the case. */
+
+ writel(info->save_sel | info->sel_bit, info->sel_reg);
+
if (!allow_clk_stop(info))
clk_disable(info->clk);
}
static int s3c24xx_nand_resume(struct platform_device *dev)
{
struct s3c2410_nand_info *info = platform_get_drvdata(dev);
+ unsigned long sel;
if (info) {
clk_enable(info->clk);
s3c2410_nand_inithw(info, dev);
+ /* Restore the state of the nFCE line. */
+
+ sel = readl(info->sel_reg);
+ sel &= ~info->sel_bit;
+ sel |= info->save_sel & info->sel_bit;
+ writel(sel, info->sel_reg);
+
if (allow_clk_stop(info))
clk_disable(info->clk);
}
MODULE_LICENSE("GPL");
MODULE_AUTHOR("Ben Dooks <ben@simtec.co.uk>");
MODULE_DESCRIPTION("S3C24XX MTD NAND driver");
+MODULE_ALIAS("platform:s3c2410-nand");
+MODULE_ALIAS("platform:s3c2412-nand");
+MODULE_ALIAS("platform:s3c2440-nand");