xref: /openbmc/linux/drivers/mtd/nand/raw/s3c2410.c (revision c900529f3d9161bfde5cca0754f83b4d3c3e0220)
11a59d1b8SThomas Gleixner // SPDX-License-Identifier: GPL-2.0-or-later
293db446aSBoris Brezillon /*
393db446aSBoris Brezillon  * Copyright © 2004-2008 Simtec Electronics
493db446aSBoris Brezillon  *	http://armlinux.simtec.co.uk/
593db446aSBoris Brezillon  *	Ben Dooks <ben@simtec.co.uk>
693db446aSBoris Brezillon  *
793db446aSBoris Brezillon  * Samsung S3C2410/S3C2440/S3C2412 NAND driver
893db446aSBoris Brezillon */
993db446aSBoris Brezillon 
1093db446aSBoris Brezillon #define pr_fmt(fmt) "nand-s3c2410: " fmt
1193db446aSBoris Brezillon 
1293db446aSBoris Brezillon #ifdef CONFIG_MTD_NAND_S3C2410_DEBUG
1393db446aSBoris Brezillon #define DEBUG
1493db446aSBoris Brezillon #endif
1593db446aSBoris Brezillon 
1693db446aSBoris Brezillon #include <linux/module.h>
1793db446aSBoris Brezillon #include <linux/types.h>
1893db446aSBoris Brezillon #include <linux/kernel.h>
1993db446aSBoris Brezillon #include <linux/string.h>
2093db446aSBoris Brezillon #include <linux/io.h>
2193db446aSBoris Brezillon #include <linux/ioport.h>
2293db446aSBoris Brezillon #include <linux/platform_device.h>
2393db446aSBoris Brezillon #include <linux/delay.h>
2493db446aSBoris Brezillon #include <linux/err.h>
2593db446aSBoris Brezillon #include <linux/slab.h>
2693db446aSBoris Brezillon #include <linux/clk.h>
2793db446aSBoris Brezillon #include <linux/cpufreq.h>
2893db446aSBoris Brezillon #include <linux/of.h>
2993db446aSBoris Brezillon 
3093db446aSBoris Brezillon #include <linux/mtd/mtd.h>
3193db446aSBoris Brezillon #include <linux/mtd/rawnand.h>
3293db446aSBoris Brezillon #include <linux/mtd/partitions.h>
3393db446aSBoris Brezillon 
3493db446aSBoris Brezillon #include <linux/platform_data/mtd-nand-s3c2410.h>
3593db446aSBoris Brezillon 
3693db446aSBoris Brezillon #define S3C2410_NFREG(x) (x)
3793db446aSBoris Brezillon 
3893db446aSBoris Brezillon #define S3C2410_NFCONF		S3C2410_NFREG(0x00)
3993db446aSBoris Brezillon #define S3C2410_NFCMD		S3C2410_NFREG(0x04)
4093db446aSBoris Brezillon #define S3C2410_NFADDR		S3C2410_NFREG(0x08)
4193db446aSBoris Brezillon #define S3C2410_NFDATA		S3C2410_NFREG(0x0C)
4293db446aSBoris Brezillon #define S3C2410_NFSTAT		S3C2410_NFREG(0x10)
4393db446aSBoris Brezillon #define S3C2410_NFECC		S3C2410_NFREG(0x14)
4493db446aSBoris Brezillon #define S3C2440_NFCONT		S3C2410_NFREG(0x04)
4593db446aSBoris Brezillon #define S3C2440_NFCMD		S3C2410_NFREG(0x08)
4693db446aSBoris Brezillon #define S3C2440_NFADDR		S3C2410_NFREG(0x0C)
4793db446aSBoris Brezillon #define S3C2440_NFDATA		S3C2410_NFREG(0x10)
4893db446aSBoris Brezillon #define S3C2440_NFSTAT		S3C2410_NFREG(0x20)
4993db446aSBoris Brezillon #define S3C2440_NFMECC0		S3C2410_NFREG(0x2C)
5093db446aSBoris Brezillon #define S3C2412_NFSTAT		S3C2410_NFREG(0x28)
5193db446aSBoris Brezillon #define S3C2412_NFMECC0		S3C2410_NFREG(0x34)
5293db446aSBoris Brezillon #define S3C2410_NFCONF_EN		(1<<15)
5393db446aSBoris Brezillon #define S3C2410_NFCONF_INITECC		(1<<12)
5493db446aSBoris Brezillon #define S3C2410_NFCONF_nFCE		(1<<11)
5593db446aSBoris Brezillon #define S3C2410_NFCONF_TACLS(x)		((x)<<8)
5693db446aSBoris Brezillon #define S3C2410_NFCONF_TWRPH0(x)	((x)<<4)
5793db446aSBoris Brezillon #define S3C2410_NFCONF_TWRPH1(x)	((x)<<0)
5893db446aSBoris Brezillon #define S3C2410_NFSTAT_BUSY		(1<<0)
5993db446aSBoris Brezillon #define S3C2440_NFCONF_TACLS(x)		((x)<<12)
6093db446aSBoris Brezillon #define S3C2440_NFCONF_TWRPH0(x)	((x)<<8)
6193db446aSBoris Brezillon #define S3C2440_NFCONF_TWRPH1(x)	((x)<<4)
6293db446aSBoris Brezillon #define S3C2440_NFCONT_INITECC		(1<<4)
6393db446aSBoris Brezillon #define S3C2440_NFCONT_nFCE		(1<<1)
6493db446aSBoris Brezillon #define S3C2440_NFCONT_ENABLE		(1<<0)
6593db446aSBoris Brezillon #define S3C2440_NFSTAT_READY		(1<<0)
6693db446aSBoris Brezillon #define S3C2412_NFCONF_NANDBOOT		(1<<31)
6793db446aSBoris Brezillon #define S3C2412_NFCONT_INIT_MAIN_ECC	(1<<5)
6893db446aSBoris Brezillon #define S3C2412_NFCONT_nFCE0		(1<<1)
6993db446aSBoris Brezillon #define S3C2412_NFSTAT_READY		(1<<0)
7093db446aSBoris Brezillon 
7193db446aSBoris Brezillon /* new oob placement block for use with hardware ecc generation
7293db446aSBoris Brezillon  */
s3c2410_ooblayout_ecc(struct mtd_info * mtd,int section,struct mtd_oob_region * oobregion)7393db446aSBoris Brezillon static int s3c2410_ooblayout_ecc(struct mtd_info *mtd, int section,
7493db446aSBoris Brezillon 				 struct mtd_oob_region *oobregion)
7593db446aSBoris Brezillon {
7693db446aSBoris Brezillon 	if (section)
7793db446aSBoris Brezillon 		return -ERANGE;
7893db446aSBoris Brezillon 
7993db446aSBoris Brezillon 	oobregion->offset = 0;
8093db446aSBoris Brezillon 	oobregion->length = 3;
8193db446aSBoris Brezillon 
8293db446aSBoris Brezillon 	return 0;
8393db446aSBoris Brezillon }
8493db446aSBoris Brezillon 
s3c2410_ooblayout_free(struct mtd_info * mtd,int section,struct mtd_oob_region * oobregion)8593db446aSBoris Brezillon static int s3c2410_ooblayout_free(struct mtd_info *mtd, int section,
8693db446aSBoris Brezillon 				  struct mtd_oob_region *oobregion)
8793db446aSBoris Brezillon {
8893db446aSBoris Brezillon 	if (section)
8993db446aSBoris Brezillon 		return -ERANGE;
9093db446aSBoris Brezillon 
9193db446aSBoris Brezillon 	oobregion->offset = 8;
9293db446aSBoris Brezillon 	oobregion->length = 8;
9393db446aSBoris Brezillon 
9493db446aSBoris Brezillon 	return 0;
9593db446aSBoris Brezillon }
9693db446aSBoris Brezillon 
9793db446aSBoris Brezillon static const struct mtd_ooblayout_ops s3c2410_ooblayout_ops = {
9893db446aSBoris Brezillon 	.ecc = s3c2410_ooblayout_ecc,
9993db446aSBoris Brezillon 	.free = s3c2410_ooblayout_free,
10093db446aSBoris Brezillon };
10193db446aSBoris Brezillon 
10293db446aSBoris Brezillon /* controller and mtd information */
10393db446aSBoris Brezillon 
10493db446aSBoris Brezillon struct s3c2410_nand_info;
10593db446aSBoris Brezillon 
10693db446aSBoris Brezillon /**
10793db446aSBoris Brezillon  * struct s3c2410_nand_mtd - driver MTD structure
10893db446aSBoris Brezillon  * @mtd: The MTD instance to pass to the MTD layer.
10993db446aSBoris Brezillon  * @chip: The NAND chip information.
11093db446aSBoris Brezillon  * @set: The platform information supplied for this set of NAND chips.
11193db446aSBoris Brezillon  * @info: Link back to the hardware information.
11293db446aSBoris Brezillon */
11393db446aSBoris Brezillon struct s3c2410_nand_mtd {
11493db446aSBoris Brezillon 	struct nand_chip		chip;
11593db446aSBoris Brezillon 	struct s3c2410_nand_set		*set;
11693db446aSBoris Brezillon 	struct s3c2410_nand_info	*info;
11793db446aSBoris Brezillon };
11893db446aSBoris Brezillon 
11993db446aSBoris Brezillon enum s3c_cpu_type {
12093db446aSBoris Brezillon 	TYPE_S3C2410,
12193db446aSBoris Brezillon 	TYPE_S3C2412,
12293db446aSBoris Brezillon 	TYPE_S3C2440,
12393db446aSBoris Brezillon };
12493db446aSBoris Brezillon 
12593db446aSBoris Brezillon enum s3c_nand_clk_state {
12693db446aSBoris Brezillon 	CLOCK_DISABLE	= 0,
12793db446aSBoris Brezillon 	CLOCK_ENABLE,
12893db446aSBoris Brezillon 	CLOCK_SUSPEND,
12993db446aSBoris Brezillon };
13093db446aSBoris Brezillon 
13193db446aSBoris Brezillon /* overview of the s3c2410 nand state */
13293db446aSBoris Brezillon 
13393db446aSBoris Brezillon /**
13493db446aSBoris Brezillon  * struct s3c2410_nand_info - NAND controller state.
1355a933b0dSLee Jones  * @controller: Base controller structure.
1365a933b0dSLee Jones  * @mtds: An array of MTD instances on this controller.
13793db446aSBoris Brezillon  * @platform: The platform data for this board.
13893db446aSBoris Brezillon  * @device: The platform device we bound to.
13993db446aSBoris Brezillon  * @clk: The clock resource for this controller.
14093db446aSBoris Brezillon  * @regs: The area mapped for the hardware registers.
14193db446aSBoris Brezillon  * @sel_reg: Pointer to the register controlling the NAND selection.
14293db446aSBoris Brezillon  * @sel_bit: The bit in @sel_reg to select the NAND chip.
14393db446aSBoris Brezillon  * @mtd_count: The number of MTDs created from this controller.
14493db446aSBoris Brezillon  * @save_sel: The contents of @sel_reg to be saved over suspend.
14593db446aSBoris Brezillon  * @clk_rate: The clock rate from @clk.
14693db446aSBoris Brezillon  * @clk_state: The current clock state.
14793db446aSBoris Brezillon  * @cpu_type: The exact type of this controller.
1485a933b0dSLee Jones  * @freq_transition: CPUFreq notifier block
14993db446aSBoris Brezillon  */
15093db446aSBoris Brezillon struct s3c2410_nand_info {
15193db446aSBoris Brezillon 	/* mtd info */
1527da45139SMiquel Raynal 	struct nand_controller		controller;
15393db446aSBoris Brezillon 	struct s3c2410_nand_mtd		*mtds;
15493db446aSBoris Brezillon 	struct s3c2410_platform_nand	*platform;
15593db446aSBoris Brezillon 
15693db446aSBoris Brezillon 	/* device info */
15793db446aSBoris Brezillon 	struct device			*device;
15893db446aSBoris Brezillon 	struct clk			*clk;
15993db446aSBoris Brezillon 	void __iomem			*regs;
16093db446aSBoris Brezillon 	void __iomem			*sel_reg;
16193db446aSBoris Brezillon 	int				sel_bit;
16293db446aSBoris Brezillon 	int				mtd_count;
16393db446aSBoris Brezillon 	unsigned long			save_sel;
16493db446aSBoris Brezillon 	unsigned long			clk_rate;
16593db446aSBoris Brezillon 	enum s3c_nand_clk_state		clk_state;
16693db446aSBoris Brezillon 
16793db446aSBoris Brezillon 	enum s3c_cpu_type		cpu_type;
16893db446aSBoris Brezillon };
16993db446aSBoris Brezillon 
17093db446aSBoris Brezillon struct s3c24XX_nand_devtype_data {
17193db446aSBoris Brezillon 	enum s3c_cpu_type type;
17293db446aSBoris Brezillon };
17393db446aSBoris Brezillon 
17493db446aSBoris Brezillon static const struct s3c24XX_nand_devtype_data s3c2410_nand_devtype_data = {
17593db446aSBoris Brezillon 	.type = TYPE_S3C2410,
17693db446aSBoris Brezillon };
17793db446aSBoris Brezillon 
17893db446aSBoris Brezillon static const struct s3c24XX_nand_devtype_data s3c2412_nand_devtype_data = {
17993db446aSBoris Brezillon 	.type = TYPE_S3C2412,
18093db446aSBoris Brezillon };
18193db446aSBoris Brezillon 
18293db446aSBoris Brezillon static const struct s3c24XX_nand_devtype_data s3c2440_nand_devtype_data = {
18393db446aSBoris Brezillon 	.type = TYPE_S3C2440,
18493db446aSBoris Brezillon };
18593db446aSBoris Brezillon 
18693db446aSBoris Brezillon /* conversion functions */
18793db446aSBoris Brezillon 
s3c2410_nand_mtd_toours(struct mtd_info * mtd)18893db446aSBoris Brezillon static struct s3c2410_nand_mtd *s3c2410_nand_mtd_toours(struct mtd_info *mtd)
18993db446aSBoris Brezillon {
19093db446aSBoris Brezillon 	return container_of(mtd_to_nand(mtd), struct s3c2410_nand_mtd,
19193db446aSBoris Brezillon 			    chip);
19293db446aSBoris Brezillon }
19393db446aSBoris Brezillon 
s3c2410_nand_mtd_toinfo(struct mtd_info * mtd)19493db446aSBoris Brezillon static struct s3c2410_nand_info *s3c2410_nand_mtd_toinfo(struct mtd_info *mtd)
19593db446aSBoris Brezillon {
19693db446aSBoris Brezillon 	return s3c2410_nand_mtd_toours(mtd)->info;
19793db446aSBoris Brezillon }
19893db446aSBoris Brezillon 
to_nand_info(struct platform_device * dev)19993db446aSBoris Brezillon static struct s3c2410_nand_info *to_nand_info(struct platform_device *dev)
20093db446aSBoris Brezillon {
20193db446aSBoris Brezillon 	return platform_get_drvdata(dev);
20293db446aSBoris Brezillon }
20393db446aSBoris Brezillon 
to_nand_plat(struct platform_device * dev)20493db446aSBoris Brezillon static struct s3c2410_platform_nand *to_nand_plat(struct platform_device *dev)
20593db446aSBoris Brezillon {
20693db446aSBoris Brezillon 	return dev_get_platdata(&dev->dev);
20793db446aSBoris Brezillon }
20893db446aSBoris Brezillon 
allow_clk_suspend(struct s3c2410_nand_info * info)20993db446aSBoris Brezillon static inline int allow_clk_suspend(struct s3c2410_nand_info *info)
21093db446aSBoris Brezillon {
21193db446aSBoris Brezillon #ifdef CONFIG_MTD_NAND_S3C2410_CLKSTOP
21293db446aSBoris Brezillon 	return 1;
21393db446aSBoris Brezillon #else
21493db446aSBoris Brezillon 	return 0;
21593db446aSBoris Brezillon #endif
21693db446aSBoris Brezillon }
21793db446aSBoris Brezillon 
21893db446aSBoris Brezillon /**
21993db446aSBoris Brezillon  * s3c2410_nand_clk_set_state - Enable, disable or suspend NAND clock.
22093db446aSBoris Brezillon  * @info: The controller instance.
22193db446aSBoris Brezillon  * @new_state: State to which clock should be set.
22293db446aSBoris Brezillon  */
s3c2410_nand_clk_set_state(struct s3c2410_nand_info * info,enum s3c_nand_clk_state new_state)22393db446aSBoris Brezillon static void s3c2410_nand_clk_set_state(struct s3c2410_nand_info *info,
22493db446aSBoris Brezillon 		enum s3c_nand_clk_state new_state)
22593db446aSBoris Brezillon {
22693db446aSBoris Brezillon 	if (!allow_clk_suspend(info) && new_state == CLOCK_SUSPEND)
22793db446aSBoris Brezillon 		return;
22893db446aSBoris Brezillon 
22993db446aSBoris Brezillon 	if (info->clk_state == CLOCK_ENABLE) {
23093db446aSBoris Brezillon 		if (new_state != CLOCK_ENABLE)
23193db446aSBoris Brezillon 			clk_disable_unprepare(info->clk);
23293db446aSBoris Brezillon 	} else {
23393db446aSBoris Brezillon 		if (new_state == CLOCK_ENABLE)
23493db446aSBoris Brezillon 			clk_prepare_enable(info->clk);
23593db446aSBoris Brezillon 	}
23693db446aSBoris Brezillon 
23793db446aSBoris Brezillon 	info->clk_state = new_state;
23893db446aSBoris Brezillon }
23993db446aSBoris Brezillon 
24093db446aSBoris Brezillon /* timing calculations */
24193db446aSBoris Brezillon 
24293db446aSBoris Brezillon #define NS_IN_KHZ 1000000
24393db446aSBoris Brezillon 
24493db446aSBoris Brezillon /**
24593db446aSBoris Brezillon  * s3c_nand_calc_rate - calculate timing data.
24693db446aSBoris Brezillon  * @wanted: The cycle time in nanoseconds.
24793db446aSBoris Brezillon  * @clk: The clock rate in kHz.
24893db446aSBoris Brezillon  * @max: The maximum divider value.
24993db446aSBoris Brezillon  *
25093db446aSBoris Brezillon  * Calculate the timing value from the given parameters.
25193db446aSBoris Brezillon  */
s3c_nand_calc_rate(int wanted,unsigned long clk,int max)25293db446aSBoris Brezillon static int s3c_nand_calc_rate(int wanted, unsigned long clk, int max)
25393db446aSBoris Brezillon {
25493db446aSBoris Brezillon 	int result;
25593db446aSBoris Brezillon 
25693db446aSBoris Brezillon 	result = DIV_ROUND_UP((wanted * clk), NS_IN_KHZ);
25793db446aSBoris Brezillon 
25893db446aSBoris Brezillon 	pr_debug("result %d from %ld, %d\n", result, clk, wanted);
25993db446aSBoris Brezillon 
26093db446aSBoris Brezillon 	if (result > max) {
26193db446aSBoris Brezillon 		pr_err("%d ns is too big for current clock rate %ld\n",
26293db446aSBoris Brezillon 			wanted, clk);
26393db446aSBoris Brezillon 		return -1;
26493db446aSBoris Brezillon 	}
26593db446aSBoris Brezillon 
26693db446aSBoris Brezillon 	if (result < 1)
26793db446aSBoris Brezillon 		result = 1;
26893db446aSBoris Brezillon 
26993db446aSBoris Brezillon 	return result;
27093db446aSBoris Brezillon }
27193db446aSBoris Brezillon 
27293db446aSBoris Brezillon #define to_ns(ticks, clk) (((ticks) * NS_IN_KHZ) / (unsigned int)(clk))
27393db446aSBoris Brezillon 
27493db446aSBoris Brezillon /* controller setup */
27593db446aSBoris Brezillon 
27693db446aSBoris Brezillon /**
27793db446aSBoris Brezillon  * s3c2410_nand_setrate - setup controller timing information.
27893db446aSBoris Brezillon  * @info: The controller instance.
27993db446aSBoris Brezillon  *
28093db446aSBoris Brezillon  * Given the information supplied by the platform, calculate and set
28193db446aSBoris Brezillon  * the necessary timing registers in the hardware to generate the
28293db446aSBoris Brezillon  * necessary timing cycles to the hardware.
28393db446aSBoris Brezillon  */
s3c2410_nand_setrate(struct s3c2410_nand_info * info)28493db446aSBoris Brezillon static int s3c2410_nand_setrate(struct s3c2410_nand_info *info)
28593db446aSBoris Brezillon {
28693db446aSBoris Brezillon 	struct s3c2410_platform_nand *plat = info->platform;
28793db446aSBoris Brezillon 	int tacls_max = (info->cpu_type == TYPE_S3C2412) ? 8 : 4;
28893db446aSBoris Brezillon 	int tacls, twrph0, twrph1;
28993db446aSBoris Brezillon 	unsigned long clkrate = clk_get_rate(info->clk);
2903f649ab7SKees Cook 	unsigned long set, cfg, mask;
29193db446aSBoris Brezillon 	unsigned long flags;
29293db446aSBoris Brezillon 
29393db446aSBoris Brezillon 	/* calculate the timing information for the controller */
29493db446aSBoris Brezillon 
29593db446aSBoris Brezillon 	info->clk_rate = clkrate;
29693db446aSBoris Brezillon 	clkrate /= 1000;	/* turn clock into kHz for ease of use */
29793db446aSBoris Brezillon 
29893db446aSBoris Brezillon 	if (plat != NULL) {
29993db446aSBoris Brezillon 		tacls = s3c_nand_calc_rate(plat->tacls, clkrate, tacls_max);
30093db446aSBoris Brezillon 		twrph0 = s3c_nand_calc_rate(plat->twrph0, clkrate, 8);
30193db446aSBoris Brezillon 		twrph1 = s3c_nand_calc_rate(plat->twrph1, clkrate, 8);
30293db446aSBoris Brezillon 	} else {
30393db446aSBoris Brezillon 		/* default timings */
30493db446aSBoris Brezillon 		tacls = tacls_max;
30593db446aSBoris Brezillon 		twrph0 = 8;
30693db446aSBoris Brezillon 		twrph1 = 8;
30793db446aSBoris Brezillon 	}
30893db446aSBoris Brezillon 
30993db446aSBoris Brezillon 	if (tacls < 0 || twrph0 < 0 || twrph1 < 0) {
31093db446aSBoris Brezillon 		dev_err(info->device, "cannot get suitable timings\n");
31193db446aSBoris Brezillon 		return -EINVAL;
31293db446aSBoris Brezillon 	}
31393db446aSBoris Brezillon 
31493db446aSBoris Brezillon 	dev_info(info->device, "Tacls=%d, %dns Twrph0=%d %dns, Twrph1=%d %dns\n",
31593db446aSBoris Brezillon 		tacls, to_ns(tacls, clkrate), twrph0, to_ns(twrph0, clkrate),
31693db446aSBoris Brezillon 						twrph1, to_ns(twrph1, clkrate));
31793db446aSBoris Brezillon 
31893db446aSBoris Brezillon 	switch (info->cpu_type) {
31993db446aSBoris Brezillon 	case TYPE_S3C2410:
32093db446aSBoris Brezillon 		mask = (S3C2410_NFCONF_TACLS(3) |
32193db446aSBoris Brezillon 			S3C2410_NFCONF_TWRPH0(7) |
32293db446aSBoris Brezillon 			S3C2410_NFCONF_TWRPH1(7));
32393db446aSBoris Brezillon 		set = S3C2410_NFCONF_EN;
32493db446aSBoris Brezillon 		set |= S3C2410_NFCONF_TACLS(tacls - 1);
32593db446aSBoris Brezillon 		set |= S3C2410_NFCONF_TWRPH0(twrph0 - 1);
32693db446aSBoris Brezillon 		set |= S3C2410_NFCONF_TWRPH1(twrph1 - 1);
32793db446aSBoris Brezillon 		break;
32893db446aSBoris Brezillon 
32993db446aSBoris Brezillon 	case TYPE_S3C2440:
33093db446aSBoris Brezillon 	case TYPE_S3C2412:
33193db446aSBoris Brezillon 		mask = (S3C2440_NFCONF_TACLS(tacls_max - 1) |
33293db446aSBoris Brezillon 			S3C2440_NFCONF_TWRPH0(7) |
33393db446aSBoris Brezillon 			S3C2440_NFCONF_TWRPH1(7));
33493db446aSBoris Brezillon 
33593db446aSBoris Brezillon 		set = S3C2440_NFCONF_TACLS(tacls - 1);
33693db446aSBoris Brezillon 		set |= S3C2440_NFCONF_TWRPH0(twrph0 - 1);
33793db446aSBoris Brezillon 		set |= S3C2440_NFCONF_TWRPH1(twrph1 - 1);
33893db446aSBoris Brezillon 		break;
33993db446aSBoris Brezillon 
34093db446aSBoris Brezillon 	default:
34193db446aSBoris Brezillon 		BUG();
34293db446aSBoris Brezillon 	}
34393db446aSBoris Brezillon 
34493db446aSBoris Brezillon 	local_irq_save(flags);
34593db446aSBoris Brezillon 
34693db446aSBoris Brezillon 	cfg = readl(info->regs + S3C2410_NFCONF);
34793db446aSBoris Brezillon 	cfg &= ~mask;
34893db446aSBoris Brezillon 	cfg |= set;
34993db446aSBoris Brezillon 	writel(cfg, info->regs + S3C2410_NFCONF);
35093db446aSBoris Brezillon 
35193db446aSBoris Brezillon 	local_irq_restore(flags);
35293db446aSBoris Brezillon 
35393db446aSBoris Brezillon 	dev_dbg(info->device, "NF_CONF is 0x%lx\n", cfg);
35493db446aSBoris Brezillon 
35593db446aSBoris Brezillon 	return 0;
35693db446aSBoris Brezillon }
35793db446aSBoris Brezillon 
35893db446aSBoris Brezillon /**
35993db446aSBoris Brezillon  * s3c2410_nand_inithw - basic hardware initialisation
36093db446aSBoris Brezillon  * @info: The hardware state.
36193db446aSBoris Brezillon  *
36293db446aSBoris Brezillon  * Do the basic initialisation of the hardware, using s3c2410_nand_setrate()
36393db446aSBoris Brezillon  * to setup the hardware access speeds and set the controller to be enabled.
36493db446aSBoris Brezillon */
s3c2410_nand_inithw(struct s3c2410_nand_info * info)36593db446aSBoris Brezillon static int s3c2410_nand_inithw(struct s3c2410_nand_info *info)
36693db446aSBoris Brezillon {
36793db446aSBoris Brezillon 	int ret;
36893db446aSBoris Brezillon 
36993db446aSBoris Brezillon 	ret = s3c2410_nand_setrate(info);
37093db446aSBoris Brezillon 	if (ret < 0)
37193db446aSBoris Brezillon 		return ret;
37293db446aSBoris Brezillon 
37393db446aSBoris Brezillon 	switch (info->cpu_type) {
37493db446aSBoris Brezillon 	case TYPE_S3C2410:
37593db446aSBoris Brezillon 	default:
37693db446aSBoris Brezillon 		break;
37793db446aSBoris Brezillon 
37893db446aSBoris Brezillon 	case TYPE_S3C2440:
37993db446aSBoris Brezillon 	case TYPE_S3C2412:
38093db446aSBoris Brezillon 		/* enable the controller and de-assert nFCE */
38193db446aSBoris Brezillon 
38293db446aSBoris Brezillon 		writel(S3C2440_NFCONT_ENABLE, info->regs + S3C2440_NFCONT);
38393db446aSBoris Brezillon 	}
38493db446aSBoris Brezillon 
38593db446aSBoris Brezillon 	return 0;
38693db446aSBoris Brezillon }
38793db446aSBoris Brezillon 
38893db446aSBoris Brezillon /**
38993db446aSBoris Brezillon  * s3c2410_nand_select_chip - select the given nand chip
390758b56f5SBoris Brezillon  * @this: NAND chip object.
39193db446aSBoris Brezillon  * @chip: The chip number.
39293db446aSBoris Brezillon  *
39393db446aSBoris Brezillon  * This is called by the MTD layer to either select a given chip for the
39493db446aSBoris Brezillon  * @mtd instance, or to indicate that the access has finished and the
39593db446aSBoris Brezillon  * chip can be de-selected.
39693db446aSBoris Brezillon  *
39793db446aSBoris Brezillon  * The routine ensures that the nFCE line is correctly setup, and any
39893db446aSBoris Brezillon  * platform specific selection code is called to route nFCE to the specific
39993db446aSBoris Brezillon  * chip.
40093db446aSBoris Brezillon  */
s3c2410_nand_select_chip(struct nand_chip * this,int chip)401758b56f5SBoris Brezillon static void s3c2410_nand_select_chip(struct nand_chip *this, int chip)
40293db446aSBoris Brezillon {
40393db446aSBoris Brezillon 	struct s3c2410_nand_info *info;
40493db446aSBoris Brezillon 	struct s3c2410_nand_mtd *nmtd;
40593db446aSBoris Brezillon 	unsigned long cur;
40693db446aSBoris Brezillon 
40793db446aSBoris Brezillon 	nmtd = nand_get_controller_data(this);
40893db446aSBoris Brezillon 	info = nmtd->info;
40993db446aSBoris Brezillon 
41093db446aSBoris Brezillon 	if (chip != -1)
41193db446aSBoris Brezillon 		s3c2410_nand_clk_set_state(info, CLOCK_ENABLE);
41293db446aSBoris Brezillon 
41393db446aSBoris Brezillon 	cur = readl(info->sel_reg);
41493db446aSBoris Brezillon 
41593db446aSBoris Brezillon 	if (chip == -1) {
41693db446aSBoris Brezillon 		cur |= info->sel_bit;
41793db446aSBoris Brezillon 	} else {
41893db446aSBoris Brezillon 		if (nmtd->set != NULL && chip > nmtd->set->nr_chips) {
41993db446aSBoris Brezillon 			dev_err(info->device, "invalid chip %d\n", chip);
42093db446aSBoris Brezillon 			return;
42193db446aSBoris Brezillon 		}
42293db446aSBoris Brezillon 
42393db446aSBoris Brezillon 		if (info->platform != NULL) {
42493db446aSBoris Brezillon 			if (info->platform->select_chip != NULL)
42593db446aSBoris Brezillon 				(info->platform->select_chip) (nmtd->set, chip);
42693db446aSBoris Brezillon 		}
42793db446aSBoris Brezillon 
42893db446aSBoris Brezillon 		cur &= ~info->sel_bit;
42993db446aSBoris Brezillon 	}
43093db446aSBoris Brezillon 
43193db446aSBoris Brezillon 	writel(cur, info->sel_reg);
43293db446aSBoris Brezillon 
43393db446aSBoris Brezillon 	if (chip == -1)
43493db446aSBoris Brezillon 		s3c2410_nand_clk_set_state(info, CLOCK_SUSPEND);
43593db446aSBoris Brezillon }
43693db446aSBoris Brezillon 
43793db446aSBoris Brezillon /* s3c2410_nand_hwcontrol
43893db446aSBoris Brezillon  *
43993db446aSBoris Brezillon  * Issue command and address cycles to the chip
44093db446aSBoris Brezillon */
44193db446aSBoris Brezillon 
s3c2410_nand_hwcontrol(struct nand_chip * chip,int cmd,unsigned int ctrl)4420f808c16SBoris Brezillon static void s3c2410_nand_hwcontrol(struct nand_chip *chip, int cmd,
44393db446aSBoris Brezillon 				   unsigned int ctrl)
44493db446aSBoris Brezillon {
4450f808c16SBoris Brezillon 	struct mtd_info *mtd = nand_to_mtd(chip);
44693db446aSBoris Brezillon 	struct s3c2410_nand_info *info = s3c2410_nand_mtd_toinfo(mtd);
44793db446aSBoris Brezillon 
44893db446aSBoris Brezillon 	if (cmd == NAND_CMD_NONE)
44993db446aSBoris Brezillon 		return;
45093db446aSBoris Brezillon 
45193db446aSBoris Brezillon 	if (ctrl & NAND_CLE)
45293db446aSBoris Brezillon 		writeb(cmd, info->regs + S3C2410_NFCMD);
45393db446aSBoris Brezillon 	else
45493db446aSBoris Brezillon 		writeb(cmd, info->regs + S3C2410_NFADDR);
45593db446aSBoris Brezillon }
45693db446aSBoris Brezillon 
45793db446aSBoris Brezillon /* command and control functions */
45893db446aSBoris Brezillon 
s3c2440_nand_hwcontrol(struct nand_chip * chip,int cmd,unsigned int ctrl)4590f808c16SBoris Brezillon static void s3c2440_nand_hwcontrol(struct nand_chip *chip, int cmd,
46093db446aSBoris Brezillon 				   unsigned int ctrl)
46193db446aSBoris Brezillon {
4620f808c16SBoris Brezillon 	struct mtd_info *mtd = nand_to_mtd(chip);
46393db446aSBoris Brezillon 	struct s3c2410_nand_info *info = s3c2410_nand_mtd_toinfo(mtd);
46493db446aSBoris Brezillon 
46593db446aSBoris Brezillon 	if (cmd == NAND_CMD_NONE)
46693db446aSBoris Brezillon 		return;
46793db446aSBoris Brezillon 
46893db446aSBoris Brezillon 	if (ctrl & NAND_CLE)
46993db446aSBoris Brezillon 		writeb(cmd, info->regs + S3C2440_NFCMD);
47093db446aSBoris Brezillon 	else
47193db446aSBoris Brezillon 		writeb(cmd, info->regs + S3C2440_NFADDR);
47293db446aSBoris Brezillon }
47393db446aSBoris Brezillon 
47493db446aSBoris Brezillon /* s3c2410_nand_devready()
47593db446aSBoris Brezillon  *
47693db446aSBoris Brezillon  * returns 0 if the nand is busy, 1 if it is ready
47793db446aSBoris Brezillon */
47893db446aSBoris Brezillon 
s3c2410_nand_devready(struct nand_chip * chip)47950a487e7SBoris Brezillon static int s3c2410_nand_devready(struct nand_chip *chip)
48093db446aSBoris Brezillon {
48150a487e7SBoris Brezillon 	struct mtd_info *mtd = nand_to_mtd(chip);
48293db446aSBoris Brezillon 	struct s3c2410_nand_info *info = s3c2410_nand_mtd_toinfo(mtd);
48393db446aSBoris Brezillon 	return readb(info->regs + S3C2410_NFSTAT) & S3C2410_NFSTAT_BUSY;
48493db446aSBoris Brezillon }
48593db446aSBoris Brezillon 
s3c2440_nand_devready(struct nand_chip * chip)48650a487e7SBoris Brezillon static int s3c2440_nand_devready(struct nand_chip *chip)
48793db446aSBoris Brezillon {
48850a487e7SBoris Brezillon 	struct mtd_info *mtd = nand_to_mtd(chip);
48993db446aSBoris Brezillon 	struct s3c2410_nand_info *info = s3c2410_nand_mtd_toinfo(mtd);
49093db446aSBoris Brezillon 	return readb(info->regs + S3C2440_NFSTAT) & S3C2440_NFSTAT_READY;
49193db446aSBoris Brezillon }
49293db446aSBoris Brezillon 
s3c2412_nand_devready(struct nand_chip * chip)49350a487e7SBoris Brezillon static int s3c2412_nand_devready(struct nand_chip *chip)
49493db446aSBoris Brezillon {
49550a487e7SBoris Brezillon 	struct mtd_info *mtd = nand_to_mtd(chip);
49693db446aSBoris Brezillon 	struct s3c2410_nand_info *info = s3c2410_nand_mtd_toinfo(mtd);
49793db446aSBoris Brezillon 	return readb(info->regs + S3C2412_NFSTAT) & S3C2412_NFSTAT_READY;
49893db446aSBoris Brezillon }
49993db446aSBoris Brezillon 
50093db446aSBoris Brezillon /* ECC handling functions */
50193db446aSBoris Brezillon 
s3c2410_nand_correct_data(struct nand_chip * chip,u_char * dat,u_char * read_ecc,u_char * calc_ecc)50200da2ea9SBoris Brezillon static int s3c2410_nand_correct_data(struct nand_chip *chip, u_char *dat,
50393db446aSBoris Brezillon 				     u_char *read_ecc, u_char *calc_ecc)
50493db446aSBoris Brezillon {
50500da2ea9SBoris Brezillon 	struct mtd_info *mtd = nand_to_mtd(chip);
50693db446aSBoris Brezillon 	struct s3c2410_nand_info *info = s3c2410_nand_mtd_toinfo(mtd);
50793db446aSBoris Brezillon 	unsigned int diff0, diff1, diff2;
50893db446aSBoris Brezillon 	unsigned int bit, byte;
50993db446aSBoris Brezillon 
51093db446aSBoris Brezillon 	pr_debug("%s(%p,%p,%p,%p)\n", __func__, mtd, dat, read_ecc, calc_ecc);
51193db446aSBoris Brezillon 
51293db446aSBoris Brezillon 	diff0 = read_ecc[0] ^ calc_ecc[0];
51393db446aSBoris Brezillon 	diff1 = read_ecc[1] ^ calc_ecc[1];
51493db446aSBoris Brezillon 	diff2 = read_ecc[2] ^ calc_ecc[2];
51593db446aSBoris Brezillon 
51693db446aSBoris Brezillon 	pr_debug("%s: rd %*phN calc %*phN diff %02x%02x%02x\n",
51793db446aSBoris Brezillon 		 __func__, 3, read_ecc, 3, calc_ecc,
51893db446aSBoris Brezillon 		 diff0, diff1, diff2);
51993db446aSBoris Brezillon 
52093db446aSBoris Brezillon 	if (diff0 == 0 && diff1 == 0 && diff2 == 0)
52193db446aSBoris Brezillon 		return 0;		/* ECC is ok */
52293db446aSBoris Brezillon 
52393db446aSBoris Brezillon 	/* sometimes people do not think about using the ECC, so check
52493db446aSBoris Brezillon 	 * to see if we have an 0xff,0xff,0xff read ECC and then ignore
52593db446aSBoris Brezillon 	 * the error, on the assumption that this is an un-eccd page.
52693db446aSBoris Brezillon 	 */
52793db446aSBoris Brezillon 	if (read_ecc[0] == 0xff && read_ecc[1] == 0xff && read_ecc[2] == 0xff
52893db446aSBoris Brezillon 	    && info->platform->ignore_unset_ecc)
52993db446aSBoris Brezillon 		return 0;
53093db446aSBoris Brezillon 
53193db446aSBoris Brezillon 	/* Can we correct this ECC (ie, one row and column change).
53293db446aSBoris Brezillon 	 * Note, this is similar to the 256 error code on smartmedia */
53393db446aSBoris Brezillon 
53493db446aSBoris Brezillon 	if (((diff0 ^ (diff0 >> 1)) & 0x55) == 0x55 &&
53593db446aSBoris Brezillon 	    ((diff1 ^ (diff1 >> 1)) & 0x55) == 0x55 &&
53693db446aSBoris Brezillon 	    ((diff2 ^ (diff2 >> 1)) & 0x55) == 0x55) {
53793db446aSBoris Brezillon 		/* calculate the bit position of the error */
53893db446aSBoris Brezillon 
53993db446aSBoris Brezillon 		bit  = ((diff2 >> 3) & 1) |
54093db446aSBoris Brezillon 		       ((diff2 >> 4) & 2) |
54193db446aSBoris Brezillon 		       ((diff2 >> 5) & 4);
54293db446aSBoris Brezillon 
54393db446aSBoris Brezillon 		/* calculate the byte position of the error */
54493db446aSBoris Brezillon 
54593db446aSBoris Brezillon 		byte = ((diff2 << 7) & 0x100) |
54693db446aSBoris Brezillon 		       ((diff1 << 0) & 0x80)  |
54793db446aSBoris Brezillon 		       ((diff1 << 1) & 0x40)  |
54893db446aSBoris Brezillon 		       ((diff1 << 2) & 0x20)  |
54993db446aSBoris Brezillon 		       ((diff1 << 3) & 0x10)  |
55093db446aSBoris Brezillon 		       ((diff0 >> 4) & 0x08)  |
55193db446aSBoris Brezillon 		       ((diff0 >> 3) & 0x04)  |
55293db446aSBoris Brezillon 		       ((diff0 >> 2) & 0x02)  |
55393db446aSBoris Brezillon 		       ((diff0 >> 1) & 0x01);
55493db446aSBoris Brezillon 
55593db446aSBoris Brezillon 		dev_dbg(info->device, "correcting error bit %d, byte %d\n",
55693db446aSBoris Brezillon 			bit, byte);
55793db446aSBoris Brezillon 
55893db446aSBoris Brezillon 		dat[byte] ^= (1 << bit);
55993db446aSBoris Brezillon 		return 1;
56093db446aSBoris Brezillon 	}
56193db446aSBoris Brezillon 
56293db446aSBoris Brezillon 	/* if there is only one bit difference in the ECC, then
56393db446aSBoris Brezillon 	 * one of only a row or column parity has changed, which
56493db446aSBoris Brezillon 	 * means the error is most probably in the ECC itself */
56593db446aSBoris Brezillon 
56693db446aSBoris Brezillon 	diff0 |= (diff1 << 8);
56793db446aSBoris Brezillon 	diff0 |= (diff2 << 16);
56893db446aSBoris Brezillon 
56993db446aSBoris Brezillon 	/* equal to "(diff0 & ~(1 << __ffs(diff0)))" */
57093db446aSBoris Brezillon 	if ((diff0 & (diff0 - 1)) == 0)
57193db446aSBoris Brezillon 		return 1;
57293db446aSBoris Brezillon 
57393db446aSBoris Brezillon 	return -1;
57493db446aSBoris Brezillon }
57593db446aSBoris Brezillon 
57693db446aSBoris Brezillon /* ECC functions
57793db446aSBoris Brezillon  *
57893db446aSBoris Brezillon  * These allow the s3c2410 and s3c2440 to use the controller's ECC
57993db446aSBoris Brezillon  * generator block to ECC the data as it passes through]
58093db446aSBoris Brezillon */
58193db446aSBoris Brezillon 
s3c2410_nand_enable_hwecc(struct nand_chip * chip,int mode)582ec47636cSBoris Brezillon static void s3c2410_nand_enable_hwecc(struct nand_chip *chip, int mode)
58393db446aSBoris Brezillon {
584ec47636cSBoris Brezillon 	struct s3c2410_nand_info *info;
58593db446aSBoris Brezillon 	unsigned long ctrl;
58693db446aSBoris Brezillon 
587ec47636cSBoris Brezillon 	info = s3c2410_nand_mtd_toinfo(nand_to_mtd(chip));
58893db446aSBoris Brezillon 	ctrl = readl(info->regs + S3C2410_NFCONF);
58993db446aSBoris Brezillon 	ctrl |= S3C2410_NFCONF_INITECC;
59093db446aSBoris Brezillon 	writel(ctrl, info->regs + S3C2410_NFCONF);
59193db446aSBoris Brezillon }
59293db446aSBoris Brezillon 
s3c2412_nand_enable_hwecc(struct nand_chip * chip,int mode)593ec47636cSBoris Brezillon static void s3c2412_nand_enable_hwecc(struct nand_chip *chip, int mode)
59493db446aSBoris Brezillon {
595ec47636cSBoris Brezillon 	struct s3c2410_nand_info *info;
59693db446aSBoris Brezillon 	unsigned long ctrl;
59793db446aSBoris Brezillon 
598ec47636cSBoris Brezillon 	info = s3c2410_nand_mtd_toinfo(nand_to_mtd(chip));
59993db446aSBoris Brezillon 	ctrl = readl(info->regs + S3C2440_NFCONT);
60093db446aSBoris Brezillon 	writel(ctrl | S3C2412_NFCONT_INIT_MAIN_ECC,
60193db446aSBoris Brezillon 	       info->regs + S3C2440_NFCONT);
60293db446aSBoris Brezillon }
60393db446aSBoris Brezillon 
s3c2440_nand_enable_hwecc(struct nand_chip * chip,int mode)604ec47636cSBoris Brezillon static void s3c2440_nand_enable_hwecc(struct nand_chip *chip, int mode)
60593db446aSBoris Brezillon {
606ec47636cSBoris Brezillon 	struct s3c2410_nand_info *info;
60793db446aSBoris Brezillon 	unsigned long ctrl;
60893db446aSBoris Brezillon 
609ec47636cSBoris Brezillon 	info = s3c2410_nand_mtd_toinfo(nand_to_mtd(chip));
61093db446aSBoris Brezillon 	ctrl = readl(info->regs + S3C2440_NFCONT);
61193db446aSBoris Brezillon 	writel(ctrl | S3C2440_NFCONT_INITECC, info->regs + S3C2440_NFCONT);
61293db446aSBoris Brezillon }
61393db446aSBoris Brezillon 
s3c2410_nand_calculate_ecc(struct nand_chip * chip,const u_char * dat,u_char * ecc_code)614af37d2c3SBoris Brezillon static int s3c2410_nand_calculate_ecc(struct nand_chip *chip,
615af37d2c3SBoris Brezillon 				      const u_char *dat, u_char *ecc_code)
61693db446aSBoris Brezillon {
617af37d2c3SBoris Brezillon 	struct mtd_info *mtd = nand_to_mtd(chip);
61893db446aSBoris Brezillon 	struct s3c2410_nand_info *info = s3c2410_nand_mtd_toinfo(mtd);
61993db446aSBoris Brezillon 
62093db446aSBoris Brezillon 	ecc_code[0] = readb(info->regs + S3C2410_NFECC + 0);
62193db446aSBoris Brezillon 	ecc_code[1] = readb(info->regs + S3C2410_NFECC + 1);
62293db446aSBoris Brezillon 	ecc_code[2] = readb(info->regs + S3C2410_NFECC + 2);
62393db446aSBoris Brezillon 
62493db446aSBoris Brezillon 	pr_debug("%s: returning ecc %*phN\n", __func__, 3, ecc_code);
62593db446aSBoris Brezillon 
62693db446aSBoris Brezillon 	return 0;
62793db446aSBoris Brezillon }
62893db446aSBoris Brezillon 
s3c2412_nand_calculate_ecc(struct nand_chip * chip,const u_char * dat,u_char * ecc_code)629af37d2c3SBoris Brezillon static int s3c2412_nand_calculate_ecc(struct nand_chip *chip,
630af37d2c3SBoris Brezillon 				      const u_char *dat, u_char *ecc_code)
63193db446aSBoris Brezillon {
632af37d2c3SBoris Brezillon 	struct mtd_info *mtd = nand_to_mtd(chip);
63393db446aSBoris Brezillon 	struct s3c2410_nand_info *info = s3c2410_nand_mtd_toinfo(mtd);
63493db446aSBoris Brezillon 	unsigned long ecc = readl(info->regs + S3C2412_NFMECC0);
63593db446aSBoris Brezillon 
63693db446aSBoris Brezillon 	ecc_code[0] = ecc;
63793db446aSBoris Brezillon 	ecc_code[1] = ecc >> 8;
63893db446aSBoris Brezillon 	ecc_code[2] = ecc >> 16;
63993db446aSBoris Brezillon 
64093db446aSBoris Brezillon 	pr_debug("%s: returning ecc %*phN\n", __func__, 3, ecc_code);
64193db446aSBoris Brezillon 
64293db446aSBoris Brezillon 	return 0;
64393db446aSBoris Brezillon }
64493db446aSBoris Brezillon 
s3c2440_nand_calculate_ecc(struct nand_chip * chip,const u_char * dat,u_char * ecc_code)645af37d2c3SBoris Brezillon static int s3c2440_nand_calculate_ecc(struct nand_chip *chip,
646af37d2c3SBoris Brezillon 				      const u_char *dat, u_char *ecc_code)
64793db446aSBoris Brezillon {
648af37d2c3SBoris Brezillon 	struct mtd_info *mtd = nand_to_mtd(chip);
64993db446aSBoris Brezillon 	struct s3c2410_nand_info *info = s3c2410_nand_mtd_toinfo(mtd);
65093db446aSBoris Brezillon 	unsigned long ecc = readl(info->regs + S3C2440_NFMECC0);
65193db446aSBoris Brezillon 
65293db446aSBoris Brezillon 	ecc_code[0] = ecc;
65393db446aSBoris Brezillon 	ecc_code[1] = ecc >> 8;
65493db446aSBoris Brezillon 	ecc_code[2] = ecc >> 16;
65593db446aSBoris Brezillon 
65693db446aSBoris Brezillon 	pr_debug("%s: returning ecc %06lx\n", __func__, ecc & 0xffffff);
65793db446aSBoris Brezillon 
65893db446aSBoris Brezillon 	return 0;
65993db446aSBoris Brezillon }
66093db446aSBoris Brezillon 
66193db446aSBoris Brezillon /* over-ride the standard functions for a little more speed. We can
66293db446aSBoris Brezillon  * use read/write block to move the data buffers to/from the controller
66393db446aSBoris Brezillon */
66493db446aSBoris Brezillon 
s3c2410_nand_read_buf(struct nand_chip * this,u_char * buf,int len)6657e534323SBoris Brezillon static void s3c2410_nand_read_buf(struct nand_chip *this, u_char *buf, int len)
66693db446aSBoris Brezillon {
66782fc5099SBoris Brezillon 	readsb(this->legacy.IO_ADDR_R, buf, len);
66893db446aSBoris Brezillon }
66993db446aSBoris Brezillon 
s3c2440_nand_read_buf(struct nand_chip * this,u_char * buf,int len)6707e534323SBoris Brezillon static void s3c2440_nand_read_buf(struct nand_chip *this, u_char *buf, int len)
67193db446aSBoris Brezillon {
6727e534323SBoris Brezillon 	struct mtd_info *mtd = nand_to_mtd(this);
67393db446aSBoris Brezillon 	struct s3c2410_nand_info *info = s3c2410_nand_mtd_toinfo(mtd);
67493db446aSBoris Brezillon 
67593db446aSBoris Brezillon 	readsl(info->regs + S3C2440_NFDATA, buf, len >> 2);
67693db446aSBoris Brezillon 
67793db446aSBoris Brezillon 	/* cleanup if we've got less than a word to do */
67893db446aSBoris Brezillon 	if (len & 3) {
67993db446aSBoris Brezillon 		buf += len & ~3;
68093db446aSBoris Brezillon 
68193db446aSBoris Brezillon 		for (; len & 3; len--)
68293db446aSBoris Brezillon 			*buf++ = readb(info->regs + S3C2440_NFDATA);
68393db446aSBoris Brezillon 	}
68493db446aSBoris Brezillon }
68593db446aSBoris Brezillon 
s3c2410_nand_write_buf(struct nand_chip * this,const u_char * buf,int len)686c0739d85SBoris Brezillon static void s3c2410_nand_write_buf(struct nand_chip *this, const u_char *buf,
68793db446aSBoris Brezillon 				   int len)
68893db446aSBoris Brezillon {
68982fc5099SBoris Brezillon 	writesb(this->legacy.IO_ADDR_W, buf, len);
69093db446aSBoris Brezillon }
69193db446aSBoris Brezillon 
s3c2440_nand_write_buf(struct nand_chip * this,const u_char * buf,int len)692c0739d85SBoris Brezillon static void s3c2440_nand_write_buf(struct nand_chip *this, const u_char *buf,
69393db446aSBoris Brezillon 				   int len)
69493db446aSBoris Brezillon {
695c0739d85SBoris Brezillon 	struct mtd_info *mtd = nand_to_mtd(this);
69693db446aSBoris Brezillon 	struct s3c2410_nand_info *info = s3c2410_nand_mtd_toinfo(mtd);
69793db446aSBoris Brezillon 
69893db446aSBoris Brezillon 	writesl(info->regs + S3C2440_NFDATA, buf, len >> 2);
69993db446aSBoris Brezillon 
70093db446aSBoris Brezillon 	/* cleanup any fractional write */
70193db446aSBoris Brezillon 	if (len & 3) {
70293db446aSBoris Brezillon 		buf += len & ~3;
70393db446aSBoris Brezillon 
70493db446aSBoris Brezillon 		for (; len & 3; len--, buf++)
70593db446aSBoris Brezillon 			writeb(*buf, info->regs + S3C2440_NFDATA);
70693db446aSBoris Brezillon 	}
70793db446aSBoris Brezillon }
70893db446aSBoris Brezillon 
70993db446aSBoris Brezillon /* device management functions */
71093db446aSBoris Brezillon 
s3c24xx_nand_remove(struct platform_device * pdev)711*ec185b18SUwe Kleine-König static void s3c24xx_nand_remove(struct platform_device *pdev)
71293db446aSBoris Brezillon {
71393db446aSBoris Brezillon 	struct s3c2410_nand_info *info = to_nand_info(pdev);
71493db446aSBoris Brezillon 
71593db446aSBoris Brezillon 	if (info == NULL)
716*ec185b18SUwe Kleine-König 		return;
71793db446aSBoris Brezillon 
71893db446aSBoris Brezillon 	/* Release all our mtds  and their partitions, then go through
71993db446aSBoris Brezillon 	 * freeing the resources used
72093db446aSBoris Brezillon 	 */
72193db446aSBoris Brezillon 
72293db446aSBoris Brezillon 	if (info->mtds != NULL) {
72393db446aSBoris Brezillon 		struct s3c2410_nand_mtd *ptr = info->mtds;
72493db446aSBoris Brezillon 		int mtdno;
72593db446aSBoris Brezillon 
72693db446aSBoris Brezillon 		for (mtdno = 0; mtdno < info->mtd_count; mtdno++, ptr++) {
72793db446aSBoris Brezillon 			pr_debug("releasing mtd %d (%p)\n", mtdno, ptr);
7289748110bSMiquel Raynal 			WARN_ON(mtd_device_unregister(nand_to_mtd(&ptr->chip)));
7299748110bSMiquel Raynal 			nand_cleanup(&ptr->chip);
73093db446aSBoris Brezillon 		}
73193db446aSBoris Brezillon 	}
73293db446aSBoris Brezillon 
73393db446aSBoris Brezillon 	/* free the common resources */
73493db446aSBoris Brezillon 
73593db446aSBoris Brezillon 	if (!IS_ERR(info->clk))
73693db446aSBoris Brezillon 		s3c2410_nand_clk_set_state(info, CLOCK_DISABLE);
73793db446aSBoris Brezillon }
73893db446aSBoris Brezillon 
s3c2410_nand_add_partition(struct s3c2410_nand_info * info,struct s3c2410_nand_mtd * mtd,struct s3c2410_nand_set * set)73993db446aSBoris Brezillon static int s3c2410_nand_add_partition(struct s3c2410_nand_info *info,
74093db446aSBoris Brezillon 				      struct s3c2410_nand_mtd *mtd,
74193db446aSBoris Brezillon 				      struct s3c2410_nand_set *set)
74293db446aSBoris Brezillon {
74393db446aSBoris Brezillon 	if (set) {
74493db446aSBoris Brezillon 		struct mtd_info *mtdinfo = nand_to_mtd(&mtd->chip);
74593db446aSBoris Brezillon 
74693db446aSBoris Brezillon 		mtdinfo->name = set->name;
74793db446aSBoris Brezillon 
74829597ca1SRafał Miłecki 		return mtd_device_register(mtdinfo, set->partitions,
74929597ca1SRafał Miłecki 					   set->nr_partitions);
75093db446aSBoris Brezillon 	}
75193db446aSBoris Brezillon 
75293db446aSBoris Brezillon 	return -ENODEV;
75393db446aSBoris Brezillon }
75493db446aSBoris Brezillon 
s3c2410_nand_setup_interface(struct nand_chip * chip,int csline,const struct nand_interface_config * conf)7554c46667bSMiquel Raynal static int s3c2410_nand_setup_interface(struct nand_chip *chip, int csline,
7564c46667bSMiquel Raynal 					const struct nand_interface_config *conf)
75793db446aSBoris Brezillon {
758858838b8SBoris Brezillon 	struct mtd_info *mtd = nand_to_mtd(chip);
75993db446aSBoris Brezillon 	struct s3c2410_nand_info *info = s3c2410_nand_mtd_toinfo(mtd);
76093db446aSBoris Brezillon 	struct s3c2410_platform_nand *pdata = info->platform;
76193db446aSBoris Brezillon 	const struct nand_sdr_timings *timings;
76293db446aSBoris Brezillon 	int tacls;
76393db446aSBoris Brezillon 
76493db446aSBoris Brezillon 	timings = nand_get_sdr_timings(conf);
76593db446aSBoris Brezillon 	if (IS_ERR(timings))
76693db446aSBoris Brezillon 		return -ENOTSUPP;
76793db446aSBoris Brezillon 
76893db446aSBoris Brezillon 	tacls = timings->tCLS_min - timings->tWP_min;
76993db446aSBoris Brezillon 	if (tacls < 0)
77093db446aSBoris Brezillon 		tacls = 0;
77193db446aSBoris Brezillon 
77293db446aSBoris Brezillon 	pdata->tacls  = DIV_ROUND_UP(tacls, 1000);
77393db446aSBoris Brezillon 	pdata->twrph0 = DIV_ROUND_UP(timings->tWP_min, 1000);
77493db446aSBoris Brezillon 	pdata->twrph1 = DIV_ROUND_UP(timings->tCLH_min, 1000);
77593db446aSBoris Brezillon 
77693db446aSBoris Brezillon 	return s3c2410_nand_setrate(info);
77793db446aSBoris Brezillon }
77893db446aSBoris Brezillon 
77993db446aSBoris Brezillon /**
78093db446aSBoris Brezillon  * s3c2410_nand_init_chip - initialise a single instance of an chip
78193db446aSBoris Brezillon  * @info: The base NAND controller the chip is on.
78293db446aSBoris Brezillon  * @nmtd: The new controller MTD instance to fill in.
78393db446aSBoris Brezillon  * @set: The information passed from the board specific platform data.
78493db446aSBoris Brezillon  *
78593db446aSBoris Brezillon  * Initialise the given @nmtd from the information in @info and @set. This
78693db446aSBoris Brezillon  * readies the structure for use with the MTD layer functions by ensuring
78793db446aSBoris Brezillon  * all pointers are setup and the necessary control routines selected.
78893db446aSBoris Brezillon  */
s3c2410_nand_init_chip(struct s3c2410_nand_info * info,struct s3c2410_nand_mtd * nmtd,struct s3c2410_nand_set * set)78993db446aSBoris Brezillon static void s3c2410_nand_init_chip(struct s3c2410_nand_info *info,
79093db446aSBoris Brezillon 				   struct s3c2410_nand_mtd *nmtd,
79193db446aSBoris Brezillon 				   struct s3c2410_nand_set *set)
79293db446aSBoris Brezillon {
79393db446aSBoris Brezillon 	struct device_node *np = info->device->of_node;
79493db446aSBoris Brezillon 	struct nand_chip *chip = &nmtd->chip;
79593db446aSBoris Brezillon 	void __iomem *regs = info->regs;
79693db446aSBoris Brezillon 
79793db446aSBoris Brezillon 	nand_set_flash_node(chip, set->of_node);
79893db446aSBoris Brezillon 
799716bbbabSBoris Brezillon 	chip->legacy.write_buf    = s3c2410_nand_write_buf;
800716bbbabSBoris Brezillon 	chip->legacy.read_buf     = s3c2410_nand_read_buf;
8017d6c37e9SBoris Brezillon 	chip->legacy.select_chip  = s3c2410_nand_select_chip;
8023cece3abSBoris Brezillon 	chip->legacy.chip_delay   = 50;
80393db446aSBoris Brezillon 	nand_set_controller_data(chip, nmtd);
80493db446aSBoris Brezillon 	chip->options	   = set->options;
80593db446aSBoris Brezillon 	chip->controller   = &info->controller;
80693db446aSBoris Brezillon 
80793db446aSBoris Brezillon 	/*
80893db446aSBoris Brezillon 	 * let's keep behavior unchanged for legacy boards booting via pdata and
80993db446aSBoris Brezillon 	 * auto-detect timings only when booting with a device tree.
81093db446aSBoris Brezillon 	 */
8117a08dbaeSBoris Brezillon 	if (!np)
8127a08dbaeSBoris Brezillon 		chip->options |= NAND_KEEP_TIMINGS;
81393db446aSBoris Brezillon 
81493db446aSBoris Brezillon 	switch (info->cpu_type) {
81593db446aSBoris Brezillon 	case TYPE_S3C2410:
81682fc5099SBoris Brezillon 		chip->legacy.IO_ADDR_W = regs + S3C2410_NFDATA;
81793db446aSBoris Brezillon 		info->sel_reg   = regs + S3C2410_NFCONF;
81893db446aSBoris Brezillon 		info->sel_bit	= S3C2410_NFCONF_nFCE;
819bf6065c6SBoris Brezillon 		chip->legacy.cmd_ctrl  = s3c2410_nand_hwcontrol;
8208395b753SBoris Brezillon 		chip->legacy.dev_ready = s3c2410_nand_devready;
82193db446aSBoris Brezillon 		break;
82293db446aSBoris Brezillon 
82393db446aSBoris Brezillon 	case TYPE_S3C2440:
82482fc5099SBoris Brezillon 		chip->legacy.IO_ADDR_W = regs + S3C2440_NFDATA;
82593db446aSBoris Brezillon 		info->sel_reg   = regs + S3C2440_NFCONT;
82693db446aSBoris Brezillon 		info->sel_bit	= S3C2440_NFCONT_nFCE;
827bf6065c6SBoris Brezillon 		chip->legacy.cmd_ctrl  = s3c2440_nand_hwcontrol;
8288395b753SBoris Brezillon 		chip->legacy.dev_ready = s3c2440_nand_devready;
829716bbbabSBoris Brezillon 		chip->legacy.read_buf  = s3c2440_nand_read_buf;
830716bbbabSBoris Brezillon 		chip->legacy.write_buf	= s3c2440_nand_write_buf;
83193db446aSBoris Brezillon 		break;
83293db446aSBoris Brezillon 
83393db446aSBoris Brezillon 	case TYPE_S3C2412:
83482fc5099SBoris Brezillon 		chip->legacy.IO_ADDR_W = regs + S3C2440_NFDATA;
83593db446aSBoris Brezillon 		info->sel_reg   = regs + S3C2440_NFCONT;
83693db446aSBoris Brezillon 		info->sel_bit	= S3C2412_NFCONT_nFCE0;
837bf6065c6SBoris Brezillon 		chip->legacy.cmd_ctrl  = s3c2440_nand_hwcontrol;
8388395b753SBoris Brezillon 		chip->legacy.dev_ready = s3c2412_nand_devready;
83993db446aSBoris Brezillon 
84093db446aSBoris Brezillon 		if (readl(regs + S3C2410_NFCONF) & S3C2412_NFCONF_NANDBOOT)
84193db446aSBoris Brezillon 			dev_info(info->device, "System booted from NAND\n");
84293db446aSBoris Brezillon 
84393db446aSBoris Brezillon 		break;
84493db446aSBoris Brezillon 	}
84593db446aSBoris Brezillon 
84682fc5099SBoris Brezillon 	chip->legacy.IO_ADDR_R = chip->legacy.IO_ADDR_W;
84793db446aSBoris Brezillon 
84893db446aSBoris Brezillon 	nmtd->info	   = info;
84993db446aSBoris Brezillon 	nmtd->set	   = set;
85093db446aSBoris Brezillon 
851bace41f8SMiquel Raynal 	chip->ecc.engine_type = info->platform->engine_type;
85293db446aSBoris Brezillon 
85393db446aSBoris Brezillon 	/*
85493db446aSBoris Brezillon 	 * If you use u-boot BBT creation code, specifying this flag will
85593db446aSBoris Brezillon 	 * let the kernel fish out the BBT from the NAND.
85693db446aSBoris Brezillon 	 */
85793db446aSBoris Brezillon 	if (set->flash_bbt)
85893db446aSBoris Brezillon 		chip->bbt_options |= NAND_BBT_USE_FLASH;
85993db446aSBoris Brezillon }
86093db446aSBoris Brezillon 
86193db446aSBoris Brezillon /**
86212748318SMiquel Raynal  * s3c2410_nand_attach_chip - Init the ECC engine after NAND scan
86312748318SMiquel Raynal  * @chip: The NAND chip
86493db446aSBoris Brezillon  *
86512748318SMiquel Raynal  * This hook is called by the core after the identification of the NAND chip,
86612748318SMiquel Raynal  * once the relevant per-chip information is up to date.. This call ensure that
86793db446aSBoris Brezillon  * we update the internal state accordingly.
86893db446aSBoris Brezillon  *
86993db446aSBoris Brezillon  * The internal state is currently limited to the ECC state information.
87093db446aSBoris Brezillon */
s3c2410_nand_attach_chip(struct nand_chip * chip)87112748318SMiquel Raynal static int s3c2410_nand_attach_chip(struct nand_chip *chip)
87293db446aSBoris Brezillon {
87312748318SMiquel Raynal 	struct mtd_info *mtd = nand_to_mtd(chip);
87412748318SMiquel Raynal 	struct s3c2410_nand_info *info = s3c2410_nand_mtd_toinfo(mtd);
87593db446aSBoris Brezillon 
876bace41f8SMiquel Raynal 	switch (chip->ecc.engine_type) {
87793db446aSBoris Brezillon 
878bace41f8SMiquel Raynal 	case NAND_ECC_ENGINE_TYPE_NONE:
87993db446aSBoris Brezillon 		dev_info(info->device, "ECC disabled\n");
88093db446aSBoris Brezillon 		break;
88193db446aSBoris Brezillon 
882bace41f8SMiquel Raynal 	case NAND_ECC_ENGINE_TYPE_SOFT:
88393db446aSBoris Brezillon 		/*
884bace41f8SMiquel Raynal 		 * This driver expects Hamming based ECC when engine_type is set
885bace41f8SMiquel Raynal 		 * to NAND_ECC_ENGINE_TYPE_SOFT. Force ecc.algo to
886bace41f8SMiquel Raynal 		 * NAND_ECC_ALGO_HAMMING to avoid adding an extra ecc_algo field
887bace41f8SMiquel Raynal 		 * to s3c2410_platform_nand.
88893db446aSBoris Brezillon 		 */
889e0a564aeSMiquel Raynal 		chip->ecc.algo = NAND_ECC_ALGO_HAMMING;
89093db446aSBoris Brezillon 		dev_info(info->device, "soft ECC\n");
89193db446aSBoris Brezillon 		break;
89293db446aSBoris Brezillon 
893bace41f8SMiquel Raynal 	case NAND_ECC_ENGINE_TYPE_ON_HOST:
89493db446aSBoris Brezillon 		chip->ecc.calculate = s3c2410_nand_calculate_ecc;
89593db446aSBoris Brezillon 		chip->ecc.correct   = s3c2410_nand_correct_data;
89693db446aSBoris Brezillon 		chip->ecc.strength  = 1;
89793db446aSBoris Brezillon 
89893db446aSBoris Brezillon 		switch (info->cpu_type) {
89993db446aSBoris Brezillon 		case TYPE_S3C2410:
90093db446aSBoris Brezillon 			chip->ecc.hwctl	    = s3c2410_nand_enable_hwecc;
90193db446aSBoris Brezillon 			chip->ecc.calculate = s3c2410_nand_calculate_ecc;
90293db446aSBoris Brezillon 			break;
90393db446aSBoris Brezillon 
90493db446aSBoris Brezillon 		case TYPE_S3C2412:
90593db446aSBoris Brezillon 			chip->ecc.hwctl     = s3c2412_nand_enable_hwecc;
90693db446aSBoris Brezillon 			chip->ecc.calculate = s3c2412_nand_calculate_ecc;
90793db446aSBoris Brezillon 			break;
90893db446aSBoris Brezillon 
90993db446aSBoris Brezillon 		case TYPE_S3C2440:
91093db446aSBoris Brezillon 			chip->ecc.hwctl     = s3c2440_nand_enable_hwecc;
91193db446aSBoris Brezillon 			chip->ecc.calculate = s3c2440_nand_calculate_ecc;
91293db446aSBoris Brezillon 			break;
91393db446aSBoris Brezillon 		}
91493db446aSBoris Brezillon 
91593db446aSBoris Brezillon 		dev_dbg(info->device, "chip %p => page shift %d\n",
91693db446aSBoris Brezillon 			chip, chip->page_shift);
91793db446aSBoris Brezillon 
91893db446aSBoris Brezillon 		/* change the behaviour depending on whether we are using
91993db446aSBoris Brezillon 		 * the large or small page nand device */
92093db446aSBoris Brezillon 		if (chip->page_shift > 10) {
92193db446aSBoris Brezillon 			chip->ecc.size	    = 256;
92293db446aSBoris Brezillon 			chip->ecc.bytes	    = 3;
92393db446aSBoris Brezillon 		} else {
92493db446aSBoris Brezillon 			chip->ecc.size	    = 512;
92593db446aSBoris Brezillon 			chip->ecc.bytes	    = 3;
92693db446aSBoris Brezillon 			mtd_set_ooblayout(nand_to_mtd(chip),
92793db446aSBoris Brezillon 					  &s3c2410_ooblayout_ops);
92893db446aSBoris Brezillon 		}
92993db446aSBoris Brezillon 
93093db446aSBoris Brezillon 		dev_info(info->device, "hardware ECC\n");
93193db446aSBoris Brezillon 		break;
93293db446aSBoris Brezillon 
93393db446aSBoris Brezillon 	default:
93493db446aSBoris Brezillon 		dev_err(info->device, "invalid ECC mode!\n");
93593db446aSBoris Brezillon 		return -EINVAL;
93693db446aSBoris Brezillon 	}
93793db446aSBoris Brezillon 
93893db446aSBoris Brezillon 	if (chip->bbt_options & NAND_BBT_USE_FLASH)
93993db446aSBoris Brezillon 		chip->options |= NAND_SKIP_BBTSCAN;
94093db446aSBoris Brezillon 
94193db446aSBoris Brezillon 	return 0;
94293db446aSBoris Brezillon }
94393db446aSBoris Brezillon 
94412748318SMiquel Raynal static const struct nand_controller_ops s3c24xx_nand_controller_ops = {
94512748318SMiquel Raynal 	.attach_chip = s3c2410_nand_attach_chip,
9464c46667bSMiquel Raynal 	.setup_interface = s3c2410_nand_setup_interface,
94712748318SMiquel Raynal };
94812748318SMiquel Raynal 
94993db446aSBoris Brezillon static const struct of_device_id s3c24xx_nand_dt_ids[] = {
95093db446aSBoris Brezillon 	{
95193db446aSBoris Brezillon 		.compatible = "samsung,s3c2410-nand",
95293db446aSBoris Brezillon 		.data = &s3c2410_nand_devtype_data,
95393db446aSBoris Brezillon 	}, {
95493db446aSBoris Brezillon 		/* also compatible with s3c6400 */
95593db446aSBoris Brezillon 		.compatible = "samsung,s3c2412-nand",
95693db446aSBoris Brezillon 		.data = &s3c2412_nand_devtype_data,
95793db446aSBoris Brezillon 	}, {
95893db446aSBoris Brezillon 		.compatible = "samsung,s3c2440-nand",
95993db446aSBoris Brezillon 		.data = &s3c2440_nand_devtype_data,
96093db446aSBoris Brezillon 	},
96193db446aSBoris Brezillon 	{ /* sentinel */ }
96293db446aSBoris Brezillon };
96393db446aSBoris Brezillon MODULE_DEVICE_TABLE(of, s3c24xx_nand_dt_ids);
96493db446aSBoris Brezillon 
s3c24xx_nand_probe_dt(struct platform_device * pdev)96593db446aSBoris Brezillon static int s3c24xx_nand_probe_dt(struct platform_device *pdev)
96693db446aSBoris Brezillon {
96793db446aSBoris Brezillon 	const struct s3c24XX_nand_devtype_data *devtype_data;
96893db446aSBoris Brezillon 	struct s3c2410_platform_nand *pdata;
96993db446aSBoris Brezillon 	struct s3c2410_nand_info *info = platform_get_drvdata(pdev);
97093db446aSBoris Brezillon 	struct device_node *np = pdev->dev.of_node, *child;
97193db446aSBoris Brezillon 	struct s3c2410_nand_set *sets;
97293db446aSBoris Brezillon 
97393db446aSBoris Brezillon 	devtype_data = of_device_get_match_data(&pdev->dev);
97493db446aSBoris Brezillon 	if (!devtype_data)
97593db446aSBoris Brezillon 		return -ENODEV;
97693db446aSBoris Brezillon 
97793db446aSBoris Brezillon 	info->cpu_type = devtype_data->type;
97893db446aSBoris Brezillon 
97993db446aSBoris Brezillon 	pdata = devm_kzalloc(&pdev->dev, sizeof(*pdata), GFP_KERNEL);
98093db446aSBoris Brezillon 	if (!pdata)
98193db446aSBoris Brezillon 		return -ENOMEM;
98293db446aSBoris Brezillon 
98393db446aSBoris Brezillon 	pdev->dev.platform_data = pdata;
98493db446aSBoris Brezillon 
98593db446aSBoris Brezillon 	pdata->nr_sets = of_get_child_count(np);
98693db446aSBoris Brezillon 	if (!pdata->nr_sets)
98793db446aSBoris Brezillon 		return 0;
98893db446aSBoris Brezillon 
989a86854d0SKees Cook 	sets = devm_kcalloc(&pdev->dev, pdata->nr_sets, sizeof(*sets),
99093db446aSBoris Brezillon 			    GFP_KERNEL);
99193db446aSBoris Brezillon 	if (!sets)
99293db446aSBoris Brezillon 		return -ENOMEM;
99393db446aSBoris Brezillon 
99493db446aSBoris Brezillon 	pdata->sets = sets;
99593db446aSBoris Brezillon 
99693db446aSBoris Brezillon 	for_each_available_child_of_node(np, child) {
99793db446aSBoris Brezillon 		sets->name = (char *)child->name;
99893db446aSBoris Brezillon 		sets->of_node = child;
99993db446aSBoris Brezillon 		sets->nr_chips = 1;
100093db446aSBoris Brezillon 
100193db446aSBoris Brezillon 		of_node_get(child);
100293db446aSBoris Brezillon 
100393db446aSBoris Brezillon 		sets++;
100493db446aSBoris Brezillon 	}
100593db446aSBoris Brezillon 
100693db446aSBoris Brezillon 	return 0;
100793db446aSBoris Brezillon }
100893db446aSBoris Brezillon 
s3c24xx_nand_probe_pdata(struct platform_device * pdev)100993db446aSBoris Brezillon static int s3c24xx_nand_probe_pdata(struct platform_device *pdev)
101093db446aSBoris Brezillon {
101193db446aSBoris Brezillon 	struct s3c2410_nand_info *info = platform_get_drvdata(pdev);
101293db446aSBoris Brezillon 
101393db446aSBoris Brezillon 	info->cpu_type = platform_get_device_id(pdev)->driver_data;
101493db446aSBoris Brezillon 
101593db446aSBoris Brezillon 	return 0;
101693db446aSBoris Brezillon }
101793db446aSBoris Brezillon 
101893db446aSBoris Brezillon /* s3c24xx_nand_probe
101993db446aSBoris Brezillon  *
102093db446aSBoris Brezillon  * called by device layer when it finds a device matching
102193db446aSBoris Brezillon  * one our driver can handled. This code checks to see if
102293db446aSBoris Brezillon  * it can allocate all necessary resources then calls the
102393db446aSBoris Brezillon  * nand layer to look for devices
102493db446aSBoris Brezillon */
s3c24xx_nand_probe(struct platform_device * pdev)102593db446aSBoris Brezillon static int s3c24xx_nand_probe(struct platform_device *pdev)
102693db446aSBoris Brezillon {
102793db446aSBoris Brezillon 	struct s3c2410_platform_nand *plat;
102893db446aSBoris Brezillon 	struct s3c2410_nand_info *info;
102993db446aSBoris Brezillon 	struct s3c2410_nand_mtd *nmtd;
103093db446aSBoris Brezillon 	struct s3c2410_nand_set *sets;
103193db446aSBoris Brezillon 	struct resource *res;
103293db446aSBoris Brezillon 	int err = 0;
103393db446aSBoris Brezillon 	int size;
103493db446aSBoris Brezillon 	int nr_sets;
103593db446aSBoris Brezillon 	int setno;
103693db446aSBoris Brezillon 
103793db446aSBoris Brezillon 	info = devm_kzalloc(&pdev->dev, sizeof(*info), GFP_KERNEL);
103893db446aSBoris Brezillon 	if (info == NULL) {
103993db446aSBoris Brezillon 		err = -ENOMEM;
104093db446aSBoris Brezillon 		goto exit_error;
104193db446aSBoris Brezillon 	}
104293db446aSBoris Brezillon 
104393db446aSBoris Brezillon 	platform_set_drvdata(pdev, info);
104493db446aSBoris Brezillon 
10457da45139SMiquel Raynal 	nand_controller_init(&info->controller);
104612748318SMiquel Raynal 	info->controller.ops = &s3c24xx_nand_controller_ops;
104793db446aSBoris Brezillon 
104893db446aSBoris Brezillon 	/* get the clock source and enable it */
104993db446aSBoris Brezillon 
105093db446aSBoris Brezillon 	info->clk = devm_clk_get(&pdev->dev, "nand");
105193db446aSBoris Brezillon 	if (IS_ERR(info->clk)) {
105293db446aSBoris Brezillon 		dev_err(&pdev->dev, "failed to get clock\n");
105393db446aSBoris Brezillon 		err = -ENOENT;
105493db446aSBoris Brezillon 		goto exit_error;
105593db446aSBoris Brezillon 	}
105693db446aSBoris Brezillon 
105793db446aSBoris Brezillon 	s3c2410_nand_clk_set_state(info, CLOCK_ENABLE);
105893db446aSBoris Brezillon 
105993db446aSBoris Brezillon 	if (pdev->dev.of_node)
106093db446aSBoris Brezillon 		err = s3c24xx_nand_probe_dt(pdev);
106193db446aSBoris Brezillon 	else
106293db446aSBoris Brezillon 		err = s3c24xx_nand_probe_pdata(pdev);
106393db446aSBoris Brezillon 
106493db446aSBoris Brezillon 	if (err)
106593db446aSBoris Brezillon 		goto exit_error;
106693db446aSBoris Brezillon 
106793db446aSBoris Brezillon 	plat = to_nand_plat(pdev);
106893db446aSBoris Brezillon 
106993db446aSBoris Brezillon 	/* allocate and map the resource */
107093db446aSBoris Brezillon 
107193db446aSBoris Brezillon 	/* currently we assume we have the one resource */
107293db446aSBoris Brezillon 	res = pdev->resource;
107393db446aSBoris Brezillon 	size = resource_size(res);
107493db446aSBoris Brezillon 
107593db446aSBoris Brezillon 	info->device	= &pdev->dev;
107693db446aSBoris Brezillon 	info->platform	= plat;
107793db446aSBoris Brezillon 
107893db446aSBoris Brezillon 	info->regs = devm_ioremap_resource(&pdev->dev, res);
107993db446aSBoris Brezillon 	if (IS_ERR(info->regs)) {
108093db446aSBoris Brezillon 		err = PTR_ERR(info->regs);
108193db446aSBoris Brezillon 		goto exit_error;
108293db446aSBoris Brezillon 	}
108393db446aSBoris Brezillon 
108493db446aSBoris Brezillon 	dev_dbg(&pdev->dev, "mapped registers at %p\n", info->regs);
108593db446aSBoris Brezillon 
1086bdc4e58dSBoris Brezillon 	if (!plat->sets || plat->nr_sets < 1) {
1087bdc4e58dSBoris Brezillon 		err = -EINVAL;
1088bdc4e58dSBoris Brezillon 		goto exit_error;
1089bdc4e58dSBoris Brezillon 	}
1090bdc4e58dSBoris Brezillon 
1091bdc4e58dSBoris Brezillon 	sets = plat->sets;
1092bdc4e58dSBoris Brezillon 	nr_sets = plat->nr_sets;
109393db446aSBoris Brezillon 
109493db446aSBoris Brezillon 	info->mtd_count = nr_sets;
109593db446aSBoris Brezillon 
109693db446aSBoris Brezillon 	/* allocate our information */
109793db446aSBoris Brezillon 
109893db446aSBoris Brezillon 	size = nr_sets * sizeof(*info->mtds);
109993db446aSBoris Brezillon 	info->mtds = devm_kzalloc(&pdev->dev, size, GFP_KERNEL);
110093db446aSBoris Brezillon 	if (info->mtds == NULL) {
110193db446aSBoris Brezillon 		err = -ENOMEM;
110293db446aSBoris Brezillon 		goto exit_error;
110393db446aSBoris Brezillon 	}
110493db446aSBoris Brezillon 
110593db446aSBoris Brezillon 	/* initialise all possible chips */
110693db446aSBoris Brezillon 
110793db446aSBoris Brezillon 	nmtd = info->mtds;
110893db446aSBoris Brezillon 
1109bdc4e58dSBoris Brezillon 	for (setno = 0; setno < nr_sets; setno++, nmtd++, sets++) {
111093db446aSBoris Brezillon 		struct mtd_info *mtd = nand_to_mtd(&nmtd->chip);
111193db446aSBoris Brezillon 
111293db446aSBoris Brezillon 		pr_debug("initialising set %d (%p, info %p)\n",
111393db446aSBoris Brezillon 			 setno, nmtd, info);
111493db446aSBoris Brezillon 
111593db446aSBoris Brezillon 		mtd->dev.parent = &pdev->dev;
111693db446aSBoris Brezillon 		s3c2410_nand_init_chip(info, nmtd, sets);
111793db446aSBoris Brezillon 
111800ad378fSBoris Brezillon 		err = nand_scan(&nmtd->chip, sets ? sets->nr_chips : 1);
1119bb00ff2fSMiquel Raynal 		if (err)
1120bb00ff2fSMiquel Raynal 			goto exit_error;
1121bb00ff2fSMiquel Raynal 
112293db446aSBoris Brezillon 		s3c2410_nand_add_partition(info, nmtd, sets);
112393db446aSBoris Brezillon 	}
112493db446aSBoris Brezillon 
112593db446aSBoris Brezillon 	/* initialise the hardware */
112693db446aSBoris Brezillon 	err = s3c2410_nand_inithw(info);
112793db446aSBoris Brezillon 	if (err != 0)
112893db446aSBoris Brezillon 		goto exit_error;
112993db446aSBoris Brezillon 
113093db446aSBoris Brezillon 	if (allow_clk_suspend(info)) {
113193db446aSBoris Brezillon 		dev_info(&pdev->dev, "clock idle support enabled\n");
113293db446aSBoris Brezillon 		s3c2410_nand_clk_set_state(info, CLOCK_SUSPEND);
113393db446aSBoris Brezillon 	}
113493db446aSBoris Brezillon 
113593db446aSBoris Brezillon 	return 0;
113693db446aSBoris Brezillon 
113793db446aSBoris Brezillon  exit_error:
113893db446aSBoris Brezillon 	s3c24xx_nand_remove(pdev);
113993db446aSBoris Brezillon 
114093db446aSBoris Brezillon 	if (err == 0)
114193db446aSBoris Brezillon 		err = -EINVAL;
114293db446aSBoris Brezillon 	return err;
114393db446aSBoris Brezillon }
114493db446aSBoris Brezillon 
114593db446aSBoris Brezillon /* PM Support */
114693db446aSBoris Brezillon #ifdef CONFIG_PM
114793db446aSBoris Brezillon 
s3c24xx_nand_suspend(struct platform_device * dev,pm_message_t pm)114893db446aSBoris Brezillon static int s3c24xx_nand_suspend(struct platform_device *dev, pm_message_t pm)
114993db446aSBoris Brezillon {
115093db446aSBoris Brezillon 	struct s3c2410_nand_info *info = platform_get_drvdata(dev);
115193db446aSBoris Brezillon 
115293db446aSBoris Brezillon 	if (info) {
115393db446aSBoris Brezillon 		info->save_sel = readl(info->sel_reg);
115493db446aSBoris Brezillon 
115593db446aSBoris Brezillon 		/* For the moment, we must ensure nFCE is high during
115693db446aSBoris Brezillon 		 * the time we are suspended. This really should be
115793db446aSBoris Brezillon 		 * handled by suspending the MTDs we are using, but
115893db446aSBoris Brezillon 		 * that is currently not the case. */
115993db446aSBoris Brezillon 
116093db446aSBoris Brezillon 		writel(info->save_sel | info->sel_bit, info->sel_reg);
116193db446aSBoris Brezillon 
116293db446aSBoris Brezillon 		s3c2410_nand_clk_set_state(info, CLOCK_DISABLE);
116393db446aSBoris Brezillon 	}
116493db446aSBoris Brezillon 
116593db446aSBoris Brezillon 	return 0;
116693db446aSBoris Brezillon }
116793db446aSBoris Brezillon 
s3c24xx_nand_resume(struct platform_device * dev)116893db446aSBoris Brezillon static int s3c24xx_nand_resume(struct platform_device *dev)
116993db446aSBoris Brezillon {
117093db446aSBoris Brezillon 	struct s3c2410_nand_info *info = platform_get_drvdata(dev);
117193db446aSBoris Brezillon 	unsigned long sel;
117293db446aSBoris Brezillon 
117393db446aSBoris Brezillon 	if (info) {
117493db446aSBoris Brezillon 		s3c2410_nand_clk_set_state(info, CLOCK_ENABLE);
117593db446aSBoris Brezillon 		s3c2410_nand_inithw(info);
117693db446aSBoris Brezillon 
117793db446aSBoris Brezillon 		/* Restore the state of the nFCE line. */
117893db446aSBoris Brezillon 
117993db446aSBoris Brezillon 		sel = readl(info->sel_reg);
118093db446aSBoris Brezillon 		sel &= ~info->sel_bit;
118193db446aSBoris Brezillon 		sel |= info->save_sel & info->sel_bit;
118293db446aSBoris Brezillon 		writel(sel, info->sel_reg);
118393db446aSBoris Brezillon 
118493db446aSBoris Brezillon 		s3c2410_nand_clk_set_state(info, CLOCK_SUSPEND);
118593db446aSBoris Brezillon 	}
118693db446aSBoris Brezillon 
118793db446aSBoris Brezillon 	return 0;
118893db446aSBoris Brezillon }
118993db446aSBoris Brezillon 
119093db446aSBoris Brezillon #else
119193db446aSBoris Brezillon #define s3c24xx_nand_suspend NULL
119293db446aSBoris Brezillon #define s3c24xx_nand_resume NULL
119393db446aSBoris Brezillon #endif
119493db446aSBoris Brezillon 
119593db446aSBoris Brezillon /* driver device registration */
119693db446aSBoris Brezillon 
119793db446aSBoris Brezillon static const struct platform_device_id s3c24xx_driver_ids[] = {
119893db446aSBoris Brezillon 	{
119993db446aSBoris Brezillon 		.name		= "s3c2410-nand",
120093db446aSBoris Brezillon 		.driver_data	= TYPE_S3C2410,
120193db446aSBoris Brezillon 	}, {
120293db446aSBoris Brezillon 		.name		= "s3c2440-nand",
120393db446aSBoris Brezillon 		.driver_data	= TYPE_S3C2440,
120493db446aSBoris Brezillon 	}, {
120593db446aSBoris Brezillon 		.name		= "s3c2412-nand",
120693db446aSBoris Brezillon 		.driver_data	= TYPE_S3C2412,
120793db446aSBoris Brezillon 	}, {
120893db446aSBoris Brezillon 		.name		= "s3c6400-nand",
120993db446aSBoris Brezillon 		.driver_data	= TYPE_S3C2412, /* compatible with 2412 */
121093db446aSBoris Brezillon 	},
121193db446aSBoris Brezillon 	{ }
121293db446aSBoris Brezillon };
121393db446aSBoris Brezillon 
121493db446aSBoris Brezillon MODULE_DEVICE_TABLE(platform, s3c24xx_driver_ids);
121593db446aSBoris Brezillon 
121693db446aSBoris Brezillon static struct platform_driver s3c24xx_nand_driver = {
121793db446aSBoris Brezillon 	.probe		= s3c24xx_nand_probe,
1218*ec185b18SUwe Kleine-König 	.remove_new	= s3c24xx_nand_remove,
121993db446aSBoris Brezillon 	.suspend	= s3c24xx_nand_suspend,
122093db446aSBoris Brezillon 	.resume		= s3c24xx_nand_resume,
122193db446aSBoris Brezillon 	.id_table	= s3c24xx_driver_ids,
122293db446aSBoris Brezillon 	.driver		= {
122393db446aSBoris Brezillon 		.name	= "s3c24xx-nand",
122493db446aSBoris Brezillon 		.of_match_table = s3c24xx_nand_dt_ids,
122593db446aSBoris Brezillon 	},
122693db446aSBoris Brezillon };
122793db446aSBoris Brezillon 
122893db446aSBoris Brezillon module_platform_driver(s3c24xx_nand_driver);
122993db446aSBoris Brezillon 
123093db446aSBoris Brezillon MODULE_LICENSE("GPL");
123193db446aSBoris Brezillon MODULE_AUTHOR("Ben Dooks <ben@simtec.co.uk>");
123293db446aSBoris Brezillon MODULE_DESCRIPTION("S3C24XX MTD NAND driver");
1233