brintos

brintos / linux-shallow public Read only

0
0
Text · 30.9 KiB · 48c1d0e Raw
1231 lines · c
1// SPDX-License-Identifier: GPL-2.0-or-later2/*3 * Copyright © 2004-2008 Simtec Electronics4 *	http://armlinux.simtec.co.uk/5 *	Ben Dooks <ben@simtec.co.uk>6 *7 * Samsung S3C2410/S3C2440/S3C2412 NAND driver8*/9 10#define pr_fmt(fmt) "nand-s3c2410: " fmt11 12#ifdef CONFIG_MTD_NAND_S3C2410_DEBUG13#define DEBUG14#endif15 16#include <linux/module.h>17#include <linux/types.h>18#include <linux/kernel.h>19#include <linux/string.h>20#include <linux/io.h>21#include <linux/ioport.h>22#include <linux/platform_device.h>23#include <linux/delay.h>24#include <linux/err.h>25#include <linux/slab.h>26#include <linux/clk.h>27#include <linux/cpufreq.h>28#include <linux/of.h>29 30#include <linux/mtd/mtd.h>31#include <linux/mtd/rawnand.h>32#include <linux/mtd/partitions.h>33 34#include <linux/platform_data/mtd-nand-s3c2410.h>35 36#define S3C2410_NFREG(x) (x)37 38#define S3C2410_NFCONF		S3C2410_NFREG(0x00)39#define S3C2410_NFCMD		S3C2410_NFREG(0x04)40#define S3C2410_NFADDR		S3C2410_NFREG(0x08)41#define S3C2410_NFDATA		S3C2410_NFREG(0x0C)42#define S3C2410_NFSTAT		S3C2410_NFREG(0x10)43#define S3C2410_NFECC		S3C2410_NFREG(0x14)44#define S3C2440_NFCONT		S3C2410_NFREG(0x04)45#define S3C2440_NFCMD		S3C2410_NFREG(0x08)46#define S3C2440_NFADDR		S3C2410_NFREG(0x0C)47#define S3C2440_NFDATA		S3C2410_NFREG(0x10)48#define S3C2440_NFSTAT		S3C2410_NFREG(0x20)49#define S3C2440_NFMECC0		S3C2410_NFREG(0x2C)50#define S3C2412_NFSTAT		S3C2410_NFREG(0x28)51#define S3C2412_NFMECC0		S3C2410_NFREG(0x34)52#define S3C2410_NFCONF_EN		(1<<15)53#define S3C2410_NFCONF_INITECC		(1<<12)54#define S3C2410_NFCONF_nFCE		(1<<11)55#define S3C2410_NFCONF_TACLS(x)		((x)<<8)56#define S3C2410_NFCONF_TWRPH0(x)	((x)<<4)57#define S3C2410_NFCONF_TWRPH1(x)	((x)<<0)58#define S3C2410_NFSTAT_BUSY		(1<<0)59#define S3C2440_NFCONF_TACLS(x)		((x)<<12)60#define S3C2440_NFCONF_TWRPH0(x)	((x)<<8)61#define S3C2440_NFCONF_TWRPH1(x)	((x)<<4)62#define S3C2440_NFCONT_INITECC		(1<<4)63#define S3C2440_NFCONT_nFCE		(1<<1)64#define S3C2440_NFCONT_ENABLE		(1<<0)65#define S3C2440_NFSTAT_READY		(1<<0)66#define S3C2412_NFCONF_NANDBOOT		(1<<31)67#define S3C2412_NFCONT_INIT_MAIN_ECC	(1<<5)68#define S3C2412_NFCONT_nFCE0		(1<<1)69#define S3C2412_NFSTAT_READY		(1<<0)70 71/* new oob placement block for use with hardware ecc generation72 */73static int s3c2410_ooblayout_ecc(struct mtd_info *mtd, int section,74				 struct mtd_oob_region *oobregion)75{76	if (section)77		return -ERANGE;78 79	oobregion->offset = 0;80	oobregion->length = 3;81 82	return 0;83}84 85static int s3c2410_ooblayout_free(struct mtd_info *mtd, int section,86				  struct mtd_oob_region *oobregion)87{88	if (section)89		return -ERANGE;90 91	oobregion->offset = 8;92	oobregion->length = 8;93 94	return 0;95}96 97static const struct mtd_ooblayout_ops s3c2410_ooblayout_ops = {98	.ecc = s3c2410_ooblayout_ecc,99	.free = s3c2410_ooblayout_free,100};101 102/* controller and mtd information */103 104struct s3c2410_nand_info;105 106/**107 * struct s3c2410_nand_mtd - driver MTD structure108 * @chip: The NAND chip information.109 * @set: The platform information supplied for this set of NAND chips.110 * @info: Link back to the hardware information.111*/112struct s3c2410_nand_mtd {113	struct nand_chip		chip;114	struct s3c2410_nand_set		*set;115	struct s3c2410_nand_info	*info;116};117 118enum s3c_cpu_type {119	TYPE_S3C2410,120	TYPE_S3C2412,121	TYPE_S3C2440,122};123 124enum s3c_nand_clk_state {125	CLOCK_DISABLE	= 0,126	CLOCK_ENABLE,127	CLOCK_SUSPEND,128};129 130/* overview of the s3c2410 nand state */131 132/**133 * struct s3c2410_nand_info - NAND controller state.134 * @controller: Base controller structure.135 * @mtds: An array of MTD instances on this controller.136 * @platform: The platform data for this board.137 * @device: The platform device we bound to.138 * @clk: The clock resource for this controller.139 * @regs: The area mapped for the hardware registers.140 * @sel_reg: Pointer to the register controlling the NAND selection.141 * @sel_bit: The bit in @sel_reg to select the NAND chip.142 * @mtd_count: The number of MTDs created from this controller.143 * @save_sel: The contents of @sel_reg to be saved over suspend.144 * @clk_rate: The clock rate from @clk.145 * @clk_state: The current clock state.146 * @cpu_type: The exact type of this controller.147 */148struct s3c2410_nand_info {149	/* mtd info */150	struct nand_controller		controller;151	struct s3c2410_nand_mtd		*mtds;152	struct s3c2410_platform_nand	*platform;153 154	/* device info */155	struct device			*device;156	struct clk			*clk;157	void __iomem			*regs;158	void __iomem			*sel_reg;159	int				sel_bit;160	int				mtd_count;161	unsigned long			save_sel;162	unsigned long			clk_rate;163	enum s3c_nand_clk_state		clk_state;164 165	enum s3c_cpu_type		cpu_type;166};167 168struct s3c24XX_nand_devtype_data {169	enum s3c_cpu_type type;170};171 172static const struct s3c24XX_nand_devtype_data s3c2410_nand_devtype_data = {173	.type = TYPE_S3C2410,174};175 176static const struct s3c24XX_nand_devtype_data s3c2412_nand_devtype_data = {177	.type = TYPE_S3C2412,178};179 180static const struct s3c24XX_nand_devtype_data s3c2440_nand_devtype_data = {181	.type = TYPE_S3C2440,182};183 184/* conversion functions */185 186static struct s3c2410_nand_mtd *s3c2410_nand_mtd_toours(struct mtd_info *mtd)187{188	return container_of(mtd_to_nand(mtd), struct s3c2410_nand_mtd,189			    chip);190}191 192static struct s3c2410_nand_info *s3c2410_nand_mtd_toinfo(struct mtd_info *mtd)193{194	return s3c2410_nand_mtd_toours(mtd)->info;195}196 197static struct s3c2410_nand_info *to_nand_info(struct platform_device *dev)198{199	return platform_get_drvdata(dev);200}201 202static struct s3c2410_platform_nand *to_nand_plat(struct platform_device *dev)203{204	return dev_get_platdata(&dev->dev);205}206 207static inline int allow_clk_suspend(struct s3c2410_nand_info *info)208{209#ifdef CONFIG_MTD_NAND_S3C2410_CLKSTOP210	return 1;211#else212	return 0;213#endif214}215 216/**217 * s3c2410_nand_clk_set_state - Enable, disable or suspend NAND clock.218 * @info: The controller instance.219 * @new_state: State to which clock should be set.220 */221static void s3c2410_nand_clk_set_state(struct s3c2410_nand_info *info,222		enum s3c_nand_clk_state new_state)223{224	if (!allow_clk_suspend(info) && new_state == CLOCK_SUSPEND)225		return;226 227	if (info->clk_state == CLOCK_ENABLE) {228		if (new_state != CLOCK_ENABLE)229			clk_disable_unprepare(info->clk);230	} else {231		if (new_state == CLOCK_ENABLE)232			clk_prepare_enable(info->clk);233	}234 235	info->clk_state = new_state;236}237 238/* timing calculations */239 240#define NS_IN_KHZ 1000000241 242/**243 * s3c_nand_calc_rate - calculate timing data.244 * @wanted: The cycle time in nanoseconds.245 * @clk: The clock rate in kHz.246 * @max: The maximum divider value.247 *248 * Calculate the timing value from the given parameters.249 */250static int s3c_nand_calc_rate(int wanted, unsigned long clk, int max)251{252	int result;253 254	result = DIV_ROUND_UP((wanted * clk), NS_IN_KHZ);255 256	pr_debug("result %d from %ld, %d\n", result, clk, wanted);257 258	if (result > max) {259		pr_err("%d ns is too big for current clock rate %ld\n",260			wanted, clk);261		return -1;262	}263 264	if (result < 1)265		result = 1;266 267	return result;268}269 270#define to_ns(ticks, clk) (((ticks) * NS_IN_KHZ) / (unsigned int)(clk))271 272/* controller setup */273 274/**275 * s3c2410_nand_setrate - setup controller timing information.276 * @info: The controller instance.277 *278 * Given the information supplied by the platform, calculate and set279 * the necessary timing registers in the hardware to generate the280 * necessary timing cycles to the hardware.281 */282static int s3c2410_nand_setrate(struct s3c2410_nand_info *info)283{284	struct s3c2410_platform_nand *plat = info->platform;285	int tacls_max = (info->cpu_type == TYPE_S3C2412) ? 8 : 4;286	int tacls, twrph0, twrph1;287	unsigned long clkrate = clk_get_rate(info->clk);288	unsigned long set, cfg, mask;289	unsigned long flags;290 291	/* calculate the timing information for the controller */292 293	info->clk_rate = clkrate;294	clkrate /= 1000;	/* turn clock into kHz for ease of use */295 296	if (plat != NULL) {297		tacls = s3c_nand_calc_rate(plat->tacls, clkrate, tacls_max);298		twrph0 = s3c_nand_calc_rate(plat->twrph0, clkrate, 8);299		twrph1 = s3c_nand_calc_rate(plat->twrph1, clkrate, 8);300	} else {301		/* default timings */302		tacls = tacls_max;303		twrph0 = 8;304		twrph1 = 8;305	}306 307	if (tacls < 0 || twrph0 < 0 || twrph1 < 0) {308		dev_err(info->device, "cannot get suitable timings\n");309		return -EINVAL;310	}311 312	dev_info(info->device, "Tacls=%d, %dns Twrph0=%d %dns, Twrph1=%d %dns\n",313		tacls, to_ns(tacls, clkrate), twrph0, to_ns(twrph0, clkrate),314						twrph1, to_ns(twrph1, clkrate));315 316	switch (info->cpu_type) {317	case TYPE_S3C2410:318		mask = (S3C2410_NFCONF_TACLS(3) |319			S3C2410_NFCONF_TWRPH0(7) |320			S3C2410_NFCONF_TWRPH1(7));321		set = S3C2410_NFCONF_EN;322		set |= S3C2410_NFCONF_TACLS(tacls - 1);323		set |= S3C2410_NFCONF_TWRPH0(twrph0 - 1);324		set |= S3C2410_NFCONF_TWRPH1(twrph1 - 1);325		break;326 327	case TYPE_S3C2440:328	case TYPE_S3C2412:329		mask = (S3C2440_NFCONF_TACLS(tacls_max - 1) |330			S3C2440_NFCONF_TWRPH0(7) |331			S3C2440_NFCONF_TWRPH1(7));332 333		set = S3C2440_NFCONF_TACLS(tacls - 1);334		set |= S3C2440_NFCONF_TWRPH0(twrph0 - 1);335		set |= S3C2440_NFCONF_TWRPH1(twrph1 - 1);336		break;337 338	default:339		BUG();340	}341 342	local_irq_save(flags);343 344	cfg = readl(info->regs + S3C2410_NFCONF);345	cfg &= ~mask;346	cfg |= set;347	writel(cfg, info->regs + S3C2410_NFCONF);348 349	local_irq_restore(flags);350 351	dev_dbg(info->device, "NF_CONF is 0x%lx\n", cfg);352 353	return 0;354}355 356/**357 * s3c2410_nand_inithw - basic hardware initialisation358 * @info: The hardware state.359 *360 * Do the basic initialisation of the hardware, using s3c2410_nand_setrate()361 * to setup the hardware access speeds and set the controller to be enabled.362*/363static int s3c2410_nand_inithw(struct s3c2410_nand_info *info)364{365	int ret;366 367	ret = s3c2410_nand_setrate(info);368	if (ret < 0)369		return ret;370 371	switch (info->cpu_type) {372	case TYPE_S3C2410:373	default:374		break;375 376	case TYPE_S3C2440:377	case TYPE_S3C2412:378		/* enable the controller and de-assert nFCE */379 380		writel(S3C2440_NFCONT_ENABLE, info->regs + S3C2440_NFCONT);381	}382 383	return 0;384}385 386/**387 * s3c2410_nand_select_chip - select the given nand chip388 * @this: NAND chip object.389 * @chip: The chip number.390 *391 * This is called by the MTD layer to either select a given chip for the392 * @mtd instance, or to indicate that the access has finished and the393 * chip can be de-selected.394 *395 * The routine ensures that the nFCE line is correctly setup, and any396 * platform specific selection code is called to route nFCE to the specific397 * chip.398 */399static void s3c2410_nand_select_chip(struct nand_chip *this, int chip)400{401	struct s3c2410_nand_info *info;402	struct s3c2410_nand_mtd *nmtd;403	unsigned long cur;404 405	nmtd = nand_get_controller_data(this);406	info = nmtd->info;407 408	if (chip != -1)409		s3c2410_nand_clk_set_state(info, CLOCK_ENABLE);410 411	cur = readl(info->sel_reg);412 413	if (chip == -1) {414		cur |= info->sel_bit;415	} else {416		if (nmtd->set != NULL && chip > nmtd->set->nr_chips) {417			dev_err(info->device, "invalid chip %d\n", chip);418			return;419		}420 421		if (info->platform != NULL) {422			if (info->platform->select_chip != NULL)423				(info->platform->select_chip) (nmtd->set, chip);424		}425 426		cur &= ~info->sel_bit;427	}428 429	writel(cur, info->sel_reg);430 431	if (chip == -1)432		s3c2410_nand_clk_set_state(info, CLOCK_SUSPEND);433}434 435/* s3c2410_nand_hwcontrol436 *437 * Issue command and address cycles to the chip438*/439 440static void s3c2410_nand_hwcontrol(struct nand_chip *chip, int cmd,441				   unsigned int ctrl)442{443	struct mtd_info *mtd = nand_to_mtd(chip);444	struct s3c2410_nand_info *info = s3c2410_nand_mtd_toinfo(mtd);445 446	if (cmd == NAND_CMD_NONE)447		return;448 449	if (ctrl & NAND_CLE)450		writeb(cmd, info->regs + S3C2410_NFCMD);451	else452		writeb(cmd, info->regs + S3C2410_NFADDR);453}454 455/* command and control functions */456 457static void s3c2440_nand_hwcontrol(struct nand_chip *chip, int cmd,458				   unsigned int ctrl)459{460	struct mtd_info *mtd = nand_to_mtd(chip);461	struct s3c2410_nand_info *info = s3c2410_nand_mtd_toinfo(mtd);462 463	if (cmd == NAND_CMD_NONE)464		return;465 466	if (ctrl & NAND_CLE)467		writeb(cmd, info->regs + S3C2440_NFCMD);468	else469		writeb(cmd, info->regs + S3C2440_NFADDR);470}471 472/* s3c2410_nand_devready()473 *474 * returns 0 if the nand is busy, 1 if it is ready475*/476 477static int s3c2410_nand_devready(struct nand_chip *chip)478{479	struct mtd_info *mtd = nand_to_mtd(chip);480	struct s3c2410_nand_info *info = s3c2410_nand_mtd_toinfo(mtd);481	return readb(info->regs + S3C2410_NFSTAT) & S3C2410_NFSTAT_BUSY;482}483 484static int s3c2440_nand_devready(struct nand_chip *chip)485{486	struct mtd_info *mtd = nand_to_mtd(chip);487	struct s3c2410_nand_info *info = s3c2410_nand_mtd_toinfo(mtd);488	return readb(info->regs + S3C2440_NFSTAT) & S3C2440_NFSTAT_READY;489}490 491static int s3c2412_nand_devready(struct nand_chip *chip)492{493	struct mtd_info *mtd = nand_to_mtd(chip);494	struct s3c2410_nand_info *info = s3c2410_nand_mtd_toinfo(mtd);495	return readb(info->regs + S3C2412_NFSTAT) & S3C2412_NFSTAT_READY;496}497 498/* ECC handling functions */499 500static int s3c2410_nand_correct_data(struct nand_chip *chip, u_char *dat,501				     u_char *read_ecc, u_char *calc_ecc)502{503	struct mtd_info *mtd = nand_to_mtd(chip);504	struct s3c2410_nand_info *info = s3c2410_nand_mtd_toinfo(mtd);505	unsigned int diff0, diff1, diff2;506	unsigned int bit, byte;507 508	pr_debug("%s(%p,%p,%p,%p)\n", __func__, mtd, dat, read_ecc, calc_ecc);509 510	diff0 = read_ecc[0] ^ calc_ecc[0];511	diff1 = read_ecc[1] ^ calc_ecc[1];512	diff2 = read_ecc[2] ^ calc_ecc[2];513 514	pr_debug("%s: rd %*phN calc %*phN diff %02x%02x%02x\n",515		 __func__, 3, read_ecc, 3, calc_ecc,516		 diff0, diff1, diff2);517 518	if (diff0 == 0 && diff1 == 0 && diff2 == 0)519		return 0;		/* ECC is ok */520 521	/* sometimes people do not think about using the ECC, so check522	 * to see if we have an 0xff,0xff,0xff read ECC and then ignore523	 * the error, on the assumption that this is an un-eccd page.524	 */525	if (read_ecc[0] == 0xff && read_ecc[1] == 0xff && read_ecc[2] == 0xff526	    && info->platform->ignore_unset_ecc)527		return 0;528 529	/* Can we correct this ECC (ie, one row and column change).530	 * Note, this is similar to the 256 error code on smartmedia */531 532	if (((diff0 ^ (diff0 >> 1)) & 0x55) == 0x55 &&533	    ((diff1 ^ (diff1 >> 1)) & 0x55) == 0x55 &&534	    ((diff2 ^ (diff2 >> 1)) & 0x55) == 0x55) {535		/* calculate the bit position of the error */536 537		bit  = ((diff2 >> 3) & 1) |538		       ((diff2 >> 4) & 2) |539		       ((diff2 >> 5) & 4);540 541		/* calculate the byte position of the error */542 543		byte = ((diff2 << 7) & 0x100) |544		       ((diff1 << 0) & 0x80)  |545		       ((diff1 << 1) & 0x40)  |546		       ((diff1 << 2) & 0x20)  |547		       ((diff1 << 3) & 0x10)  |548		       ((diff0 >> 4) & 0x08)  |549		       ((diff0 >> 3) & 0x04)  |550		       ((diff0 >> 2) & 0x02)  |551		       ((diff0 >> 1) & 0x01);552 553		dev_dbg(info->device, "correcting error bit %d, byte %d\n",554			bit, byte);555 556		dat[byte] ^= (1 << bit);557		return 1;558	}559 560	/* if there is only one bit difference in the ECC, then561	 * one of only a row or column parity has changed, which562	 * means the error is most probably in the ECC itself */563 564	diff0 |= (diff1 << 8);565	diff0 |= (diff2 << 16);566 567	/* equal to "(diff0 & ~(1 << __ffs(diff0)))" */568	if ((diff0 & (diff0 - 1)) == 0)569		return 1;570 571	return -1;572}573 574/* ECC functions575 *576 * These allow the s3c2410 and s3c2440 to use the controller's ECC577 * generator block to ECC the data as it passes through]578*/579 580static void s3c2410_nand_enable_hwecc(struct nand_chip *chip, int mode)581{582	struct s3c2410_nand_info *info;583	unsigned long ctrl;584 585	info = s3c2410_nand_mtd_toinfo(nand_to_mtd(chip));586	ctrl = readl(info->regs + S3C2410_NFCONF);587	ctrl |= S3C2410_NFCONF_INITECC;588	writel(ctrl, info->regs + S3C2410_NFCONF);589}590 591static void s3c2412_nand_enable_hwecc(struct nand_chip *chip, int mode)592{593	struct s3c2410_nand_info *info;594	unsigned long ctrl;595 596	info = s3c2410_nand_mtd_toinfo(nand_to_mtd(chip));597	ctrl = readl(info->regs + S3C2440_NFCONT);598	writel(ctrl | S3C2412_NFCONT_INIT_MAIN_ECC,599	       info->regs + S3C2440_NFCONT);600}601 602static void s3c2440_nand_enable_hwecc(struct nand_chip *chip, int mode)603{604	struct s3c2410_nand_info *info;605	unsigned long ctrl;606 607	info = s3c2410_nand_mtd_toinfo(nand_to_mtd(chip));608	ctrl = readl(info->regs + S3C2440_NFCONT);609	writel(ctrl | S3C2440_NFCONT_INITECC, info->regs + S3C2440_NFCONT);610}611 612static int s3c2410_nand_calculate_ecc(struct nand_chip *chip,613				      const u_char *dat, u_char *ecc_code)614{615	struct mtd_info *mtd = nand_to_mtd(chip);616	struct s3c2410_nand_info *info = s3c2410_nand_mtd_toinfo(mtd);617 618	ecc_code[0] = readb(info->regs + S3C2410_NFECC + 0);619	ecc_code[1] = readb(info->regs + S3C2410_NFECC + 1);620	ecc_code[2] = readb(info->regs + S3C2410_NFECC + 2);621 622	pr_debug("%s: returning ecc %*phN\n", __func__, 3, ecc_code);623 624	return 0;625}626 627static int s3c2412_nand_calculate_ecc(struct nand_chip *chip,628				      const u_char *dat, u_char *ecc_code)629{630	struct mtd_info *mtd = nand_to_mtd(chip);631	struct s3c2410_nand_info *info = s3c2410_nand_mtd_toinfo(mtd);632	unsigned long ecc = readl(info->regs + S3C2412_NFMECC0);633 634	ecc_code[0] = ecc;635	ecc_code[1] = ecc >> 8;636	ecc_code[2] = ecc >> 16;637 638	pr_debug("%s: returning ecc %*phN\n", __func__, 3, ecc_code);639 640	return 0;641}642 643static int s3c2440_nand_calculate_ecc(struct nand_chip *chip,644				      const u_char *dat, u_char *ecc_code)645{646	struct mtd_info *mtd = nand_to_mtd(chip);647	struct s3c2410_nand_info *info = s3c2410_nand_mtd_toinfo(mtd);648	unsigned long ecc = readl(info->regs + S3C2440_NFMECC0);649 650	ecc_code[0] = ecc;651	ecc_code[1] = ecc >> 8;652	ecc_code[2] = ecc >> 16;653 654	pr_debug("%s: returning ecc %06lx\n", __func__, ecc & 0xffffff);655 656	return 0;657}658 659/* over-ride the standard functions for a little more speed. We can660 * use read/write block to move the data buffers to/from the controller661*/662 663static void s3c2410_nand_read_buf(struct nand_chip *this, u_char *buf, int len)664{665	readsb(this->legacy.IO_ADDR_R, buf, len);666}667 668static void s3c2440_nand_read_buf(struct nand_chip *this, u_char *buf, int len)669{670	struct mtd_info *mtd = nand_to_mtd(this);671	struct s3c2410_nand_info *info = s3c2410_nand_mtd_toinfo(mtd);672 673	readsl(info->regs + S3C2440_NFDATA, buf, len >> 2);674 675	/* cleanup if we've got less than a word to do */676	if (len & 3) {677		buf += len & ~3;678 679		for (; len & 3; len--)680			*buf++ = readb(info->regs + S3C2440_NFDATA);681	}682}683 684static void s3c2410_nand_write_buf(struct nand_chip *this, const u_char *buf,685				   int len)686{687	writesb(this->legacy.IO_ADDR_W, buf, len);688}689 690static void s3c2440_nand_write_buf(struct nand_chip *this, const u_char *buf,691				   int len)692{693	struct mtd_info *mtd = nand_to_mtd(this);694	struct s3c2410_nand_info *info = s3c2410_nand_mtd_toinfo(mtd);695 696	writesl(info->regs + S3C2440_NFDATA, buf, len >> 2);697 698	/* cleanup any fractional write */699	if (len & 3) {700		buf += len & ~3;701 702		for (; len & 3; len--, buf++)703			writeb(*buf, info->regs + S3C2440_NFDATA);704	}705}706 707/* device management functions */708 709static void s3c24xx_nand_remove(struct platform_device *pdev)710{711	struct s3c2410_nand_info *info = to_nand_info(pdev);712 713	if (info == NULL)714		return;715 716	/* Release all our mtds  and their partitions, then go through717	 * freeing the resources used718	 */719 720	if (info->mtds != NULL) {721		struct s3c2410_nand_mtd *ptr = info->mtds;722		int mtdno;723 724		for (mtdno = 0; mtdno < info->mtd_count; mtdno++, ptr++) {725			pr_debug("releasing mtd %d (%p)\n", mtdno, ptr);726			WARN_ON(mtd_device_unregister(nand_to_mtd(&ptr->chip)));727			nand_cleanup(&ptr->chip);728		}729	}730 731	/* free the common resources */732 733	if (!IS_ERR(info->clk))734		s3c2410_nand_clk_set_state(info, CLOCK_DISABLE);735}736 737static int s3c2410_nand_add_partition(struct s3c2410_nand_info *info,738				      struct s3c2410_nand_mtd *mtd,739				      struct s3c2410_nand_set *set)740{741	if (set) {742		struct mtd_info *mtdinfo = nand_to_mtd(&mtd->chip);743 744		mtdinfo->name = set->name;745 746		return mtd_device_register(mtdinfo, set->partitions,747					   set->nr_partitions);748	}749 750	return -ENODEV;751}752 753static int s3c2410_nand_setup_interface(struct nand_chip *chip, int csline,754					const struct nand_interface_config *conf)755{756	struct mtd_info *mtd = nand_to_mtd(chip);757	struct s3c2410_nand_info *info = s3c2410_nand_mtd_toinfo(mtd);758	struct s3c2410_platform_nand *pdata = info->platform;759	const struct nand_sdr_timings *timings;760	int tacls;761 762	timings = nand_get_sdr_timings(conf);763	if (IS_ERR(timings))764		return -ENOTSUPP;765 766	tacls = timings->tCLS_min - timings->tWP_min;767	if (tacls < 0)768		tacls = 0;769 770	pdata->tacls  = DIV_ROUND_UP(tacls, 1000);771	pdata->twrph0 = DIV_ROUND_UP(timings->tWP_min, 1000);772	pdata->twrph1 = DIV_ROUND_UP(timings->tCLH_min, 1000);773 774	return s3c2410_nand_setrate(info);775}776 777/**778 * s3c2410_nand_init_chip - initialise a single instance of an chip779 * @info: The base NAND controller the chip is on.780 * @nmtd: The new controller MTD instance to fill in.781 * @set: The information passed from the board specific platform data.782 *783 * Initialise the given @nmtd from the information in @info and @set. This784 * readies the structure for use with the MTD layer functions by ensuring785 * all pointers are setup and the necessary control routines selected.786 */787static void s3c2410_nand_init_chip(struct s3c2410_nand_info *info,788				   struct s3c2410_nand_mtd *nmtd,789				   struct s3c2410_nand_set *set)790{791	struct device_node *np = info->device->of_node;792	struct nand_chip *chip = &nmtd->chip;793	void __iomem *regs = info->regs;794 795	nand_set_flash_node(chip, set->of_node);796 797	chip->legacy.write_buf    = s3c2410_nand_write_buf;798	chip->legacy.read_buf     = s3c2410_nand_read_buf;799	chip->legacy.select_chip  = s3c2410_nand_select_chip;800	chip->legacy.chip_delay   = 50;801	nand_set_controller_data(chip, nmtd);802	chip->options	   = set->options;803	chip->controller   = &info->controller;804 805	/*806	 * let's keep behavior unchanged for legacy boards booting via pdata and807	 * auto-detect timings only when booting with a device tree.808	 */809	if (!np)810		chip->options |= NAND_KEEP_TIMINGS;811 812	switch (info->cpu_type) {813	case TYPE_S3C2410:814		chip->legacy.IO_ADDR_W = regs + S3C2410_NFDATA;815		info->sel_reg   = regs + S3C2410_NFCONF;816		info->sel_bit	= S3C2410_NFCONF_nFCE;817		chip->legacy.cmd_ctrl  = s3c2410_nand_hwcontrol;818		chip->legacy.dev_ready = s3c2410_nand_devready;819		break;820 821	case TYPE_S3C2440:822		chip->legacy.IO_ADDR_W = regs + S3C2440_NFDATA;823		info->sel_reg   = regs + S3C2440_NFCONT;824		info->sel_bit	= S3C2440_NFCONT_nFCE;825		chip->legacy.cmd_ctrl  = s3c2440_nand_hwcontrol;826		chip->legacy.dev_ready = s3c2440_nand_devready;827		chip->legacy.read_buf  = s3c2440_nand_read_buf;828		chip->legacy.write_buf	= s3c2440_nand_write_buf;829		break;830 831	case TYPE_S3C2412:832		chip->legacy.IO_ADDR_W = regs + S3C2440_NFDATA;833		info->sel_reg   = regs + S3C2440_NFCONT;834		info->sel_bit	= S3C2412_NFCONT_nFCE0;835		chip->legacy.cmd_ctrl  = s3c2440_nand_hwcontrol;836		chip->legacy.dev_ready = s3c2412_nand_devready;837 838		if (readl(regs + S3C2410_NFCONF) & S3C2412_NFCONF_NANDBOOT)839			dev_info(info->device, "System booted from NAND\n");840 841		break;842	}843 844	chip->legacy.IO_ADDR_R = chip->legacy.IO_ADDR_W;845 846	nmtd->info	   = info;847	nmtd->set	   = set;848 849	chip->ecc.engine_type = info->platform->engine_type;850 851	/*852	 * If you use u-boot BBT creation code, specifying this flag will853	 * let the kernel fish out the BBT from the NAND.854	 */855	if (set->flash_bbt)856		chip->bbt_options |= NAND_BBT_USE_FLASH;857}858 859/**860 * s3c2410_nand_attach_chip - Init the ECC engine after NAND scan861 * @chip: The NAND chip862 *863 * This hook is called by the core after the identification of the NAND chip,864 * once the relevant per-chip information is up to date.. This call ensure that865 * we update the internal state accordingly.866 *867 * The internal state is currently limited to the ECC state information.868*/869static int s3c2410_nand_attach_chip(struct nand_chip *chip)870{871	struct mtd_info *mtd = nand_to_mtd(chip);872	struct s3c2410_nand_info *info = s3c2410_nand_mtd_toinfo(mtd);873 874	switch (chip->ecc.engine_type) {875 876	case NAND_ECC_ENGINE_TYPE_NONE:877		dev_info(info->device, "ECC disabled\n");878		break;879 880	case NAND_ECC_ENGINE_TYPE_SOFT:881		/*882		 * This driver expects Hamming based ECC when engine_type is set883		 * to NAND_ECC_ENGINE_TYPE_SOFT. Force ecc.algo to884		 * NAND_ECC_ALGO_HAMMING to avoid adding an extra ecc_algo field885		 * to s3c2410_platform_nand.886		 */887		chip->ecc.algo = NAND_ECC_ALGO_HAMMING;888		dev_info(info->device, "soft ECC\n");889		break;890 891	case NAND_ECC_ENGINE_TYPE_ON_HOST:892		chip->ecc.calculate = s3c2410_nand_calculate_ecc;893		chip->ecc.correct   = s3c2410_nand_correct_data;894		chip->ecc.strength  = 1;895 896		switch (info->cpu_type) {897		case TYPE_S3C2410:898			chip->ecc.hwctl	    = s3c2410_nand_enable_hwecc;899			chip->ecc.calculate = s3c2410_nand_calculate_ecc;900			break;901 902		case TYPE_S3C2412:903			chip->ecc.hwctl     = s3c2412_nand_enable_hwecc;904			chip->ecc.calculate = s3c2412_nand_calculate_ecc;905			break;906 907		case TYPE_S3C2440:908			chip->ecc.hwctl     = s3c2440_nand_enable_hwecc;909			chip->ecc.calculate = s3c2440_nand_calculate_ecc;910			break;911		}912 913		dev_dbg(info->device, "chip %p => page shift %d\n",914			chip, chip->page_shift);915 916		/* change the behaviour depending on whether we are using917		 * the large or small page nand device */918		if (chip->page_shift > 10) {919			chip->ecc.size	    = 256;920			chip->ecc.bytes	    = 3;921		} else {922			chip->ecc.size	    = 512;923			chip->ecc.bytes	    = 3;924			mtd_set_ooblayout(nand_to_mtd(chip),925					  &s3c2410_ooblayout_ops);926		}927 928		dev_info(info->device, "hardware ECC\n");929		break;930 931	default:932		dev_err(info->device, "invalid ECC mode!\n");933		return -EINVAL;934	}935 936	if (chip->bbt_options & NAND_BBT_USE_FLASH)937		chip->options |= NAND_SKIP_BBTSCAN;938 939	return 0;940}941 942static const struct nand_controller_ops s3c24xx_nand_controller_ops = {943	.attach_chip = s3c2410_nand_attach_chip,944	.setup_interface = s3c2410_nand_setup_interface,945};946 947static const struct of_device_id s3c24xx_nand_dt_ids[] = {948	{949		.compatible = "samsung,s3c2410-nand",950		.data = &s3c2410_nand_devtype_data,951	}, {952		/* also compatible with s3c6400 */953		.compatible = "samsung,s3c2412-nand",954		.data = &s3c2412_nand_devtype_data,955	}, {956		.compatible = "samsung,s3c2440-nand",957		.data = &s3c2440_nand_devtype_data,958	},959	{ /* sentinel */ }960};961MODULE_DEVICE_TABLE(of, s3c24xx_nand_dt_ids);962 963static int s3c24xx_nand_probe_dt(struct platform_device *pdev)964{965	const struct s3c24XX_nand_devtype_data *devtype_data;966	struct s3c2410_platform_nand *pdata;967	struct s3c2410_nand_info *info = platform_get_drvdata(pdev);968	struct device_node *np = pdev->dev.of_node, *child;969	struct s3c2410_nand_set *sets;970 971	devtype_data = of_device_get_match_data(&pdev->dev);972	if (!devtype_data)973		return -ENODEV;974 975	info->cpu_type = devtype_data->type;976 977	pdata = devm_kzalloc(&pdev->dev, sizeof(*pdata), GFP_KERNEL);978	if (!pdata)979		return -ENOMEM;980 981	pdev->dev.platform_data = pdata;982 983	pdata->nr_sets = of_get_child_count(np);984	if (!pdata->nr_sets)985		return 0;986 987	sets = devm_kcalloc(&pdev->dev, pdata->nr_sets, sizeof(*sets),988			    GFP_KERNEL);989	if (!sets)990		return -ENOMEM;991 992	pdata->sets = sets;993 994	for_each_available_child_of_node(np, child) {995		sets->name = (char *)child->name;996		sets->of_node = child;997		sets->nr_chips = 1;998 999		of_node_get(child);1000 1001		sets++;1002	}1003 1004	return 0;1005}1006 1007static int s3c24xx_nand_probe_pdata(struct platform_device *pdev)1008{1009	struct s3c2410_nand_info *info = platform_get_drvdata(pdev);1010 1011	info->cpu_type = platform_get_device_id(pdev)->driver_data;1012 1013	return 0;1014}1015 1016/* s3c24xx_nand_probe1017 *1018 * called by device layer when it finds a device matching1019 * one our driver can handled. This code checks to see if1020 * it can allocate all necessary resources then calls the1021 * nand layer to look for devices1022*/1023static int s3c24xx_nand_probe(struct platform_device *pdev)1024{1025	struct s3c2410_platform_nand *plat;1026	struct s3c2410_nand_info *info;1027	struct s3c2410_nand_mtd *nmtd;1028	struct s3c2410_nand_set *sets;1029	struct resource *res;1030	int err = 0;1031	int size;1032	int nr_sets;1033	int setno;1034 1035	info = devm_kzalloc(&pdev->dev, sizeof(*info), GFP_KERNEL);1036	if (info == NULL) {1037		err = -ENOMEM;1038		goto exit_error;1039	}1040 1041	platform_set_drvdata(pdev, info);1042 1043	nand_controller_init(&info->controller);1044	info->controller.ops = &s3c24xx_nand_controller_ops;1045 1046	/* get the clock source and enable it */1047 1048	info->clk = devm_clk_get(&pdev->dev, "nand");1049	if (IS_ERR(info->clk)) {1050		dev_err(&pdev->dev, "failed to get clock\n");1051		err = -ENOENT;1052		goto exit_error;1053	}1054 1055	s3c2410_nand_clk_set_state(info, CLOCK_ENABLE);1056 1057	if (pdev->dev.of_node)1058		err = s3c24xx_nand_probe_dt(pdev);1059	else1060		err = s3c24xx_nand_probe_pdata(pdev);1061 1062	if (err)1063		goto exit_error;1064 1065	plat = to_nand_plat(pdev);1066 1067	/* allocate and map the resource */1068 1069	/* currently we assume we have the one resource */1070	res = pdev->resource;1071	size = resource_size(res);1072 1073	info->device	= &pdev->dev;1074	info->platform	= plat;1075 1076	info->regs = devm_ioremap_resource(&pdev->dev, res);1077	if (IS_ERR(info->regs)) {1078		err = PTR_ERR(info->regs);1079		goto exit_error;1080	}1081 1082	dev_dbg(&pdev->dev, "mapped registers at %p\n", info->regs);1083 1084	if (!plat->sets || plat->nr_sets < 1) {1085		err = -EINVAL;1086		goto exit_error;1087	}1088 1089	sets = plat->sets;1090	nr_sets = plat->nr_sets;1091 1092	info->mtd_count = nr_sets;1093 1094	/* allocate our information */1095 1096	size = nr_sets * sizeof(*info->mtds);1097	info->mtds = devm_kzalloc(&pdev->dev, size, GFP_KERNEL);1098	if (info->mtds == NULL) {1099		err = -ENOMEM;1100		goto exit_error;1101	}1102 1103	/* initialise all possible chips */1104 1105	nmtd = info->mtds;1106 1107	for (setno = 0; setno < nr_sets; setno++, nmtd++, sets++) {1108		struct mtd_info *mtd = nand_to_mtd(&nmtd->chip);1109 1110		pr_debug("initialising set %d (%p, info %p)\n",1111			 setno, nmtd, info);1112 1113		mtd->dev.parent = &pdev->dev;1114		s3c2410_nand_init_chip(info, nmtd, sets);1115 1116		err = nand_scan(&nmtd->chip, sets ? sets->nr_chips : 1);1117		if (err)1118			goto exit_error;1119 1120		s3c2410_nand_add_partition(info, nmtd, sets);1121	}1122 1123	/* initialise the hardware */1124	err = s3c2410_nand_inithw(info);1125	if (err != 0)1126		goto exit_error;1127 1128	if (allow_clk_suspend(info)) {1129		dev_info(&pdev->dev, "clock idle support enabled\n");1130		s3c2410_nand_clk_set_state(info, CLOCK_SUSPEND);1131	}1132 1133	return 0;1134 1135 exit_error:1136	s3c24xx_nand_remove(pdev);1137 1138	if (err == 0)1139		err = -EINVAL;1140	return err;1141}1142 1143/* PM Support */1144#ifdef CONFIG_PM1145 1146static int s3c24xx_nand_suspend(struct platform_device *dev, pm_message_t pm)1147{1148	struct s3c2410_nand_info *info = platform_get_drvdata(dev);1149 1150	if (info) {1151		info->save_sel = readl(info->sel_reg);1152 1153		/* For the moment, we must ensure nFCE is high during1154		 * the time we are suspended. This really should be1155		 * handled by suspending the MTDs we are using, but1156		 * that is currently not the case. */1157 1158		writel(info->save_sel | info->sel_bit, info->sel_reg);1159 1160		s3c2410_nand_clk_set_state(info, CLOCK_DISABLE);1161	}1162 1163	return 0;1164}1165 1166static int s3c24xx_nand_resume(struct platform_device *dev)1167{1168	struct s3c2410_nand_info *info = platform_get_drvdata(dev);1169	unsigned long sel;1170 1171	if (info) {1172		s3c2410_nand_clk_set_state(info, CLOCK_ENABLE);1173		s3c2410_nand_inithw(info);1174 1175		/* Restore the state of the nFCE line. */1176 1177		sel = readl(info->sel_reg);1178		sel &= ~info->sel_bit;1179		sel |= info->save_sel & info->sel_bit;1180		writel(sel, info->sel_reg);1181 1182		s3c2410_nand_clk_set_state(info, CLOCK_SUSPEND);1183	}1184 1185	return 0;1186}1187 1188#else1189#define s3c24xx_nand_suspend NULL1190#define s3c24xx_nand_resume NULL1191#endif1192 1193/* driver device registration */1194 1195static const struct platform_device_id s3c24xx_driver_ids[] = {1196	{1197		.name		= "s3c2410-nand",1198		.driver_data	= TYPE_S3C2410,1199	}, {1200		.name		= "s3c2440-nand",1201		.driver_data	= TYPE_S3C2440,1202	}, {1203		.name		= "s3c2412-nand",1204		.driver_data	= TYPE_S3C2412,1205	}, {1206		.name		= "s3c6400-nand",1207		.driver_data	= TYPE_S3C2412, /* compatible with 2412 */1208	},1209	{ }1210};1211 1212MODULE_DEVICE_TABLE(platform, s3c24xx_driver_ids);1213 1214static struct platform_driver s3c24xx_nand_driver = {1215	.probe		= s3c24xx_nand_probe,1216	.remove_new	= s3c24xx_nand_remove,1217	.suspend	= s3c24xx_nand_suspend,1218	.resume		= s3c24xx_nand_resume,1219	.id_table	= s3c24xx_driver_ids,1220	.driver		= {1221		.name	= "s3c24xx-nand",1222		.of_match_table = s3c24xx_nand_dt_ids,1223	},1224};1225 1226module_platform_driver(s3c24xx_nand_driver);1227 1228MODULE_LICENSE("GPL");1229MODULE_AUTHOR("Ben Dooks <ben@simtec.co.uk>");1230MODULE_DESCRIPTION("S3C24XX MTD NAND driver");1231