atmel_nand.c 14.3 KB
Newer Older
A
Andrew Victor 已提交
1 2 3 4 5 6 7 8 9
/*
 *  Copyright (C) 2003 Rick Bronson
 *
 *  Derived from drivers/mtd/nand/autcpu12.c
 *	 Copyright (c) 2001 Thomas Gleixner (gleixner@autronix.de)
 *
 *  Derived from drivers/mtd/spia.c
 *	 Copyright (C) 2000 Steven J. Hill (sjhill@cotw.com)
 *
10 11 12 13 14 15 16 17 18
 *
 *  Add Hardware ECC support for AT91SAM9260 / AT91SAM9263
 *     Richard Genoud (richard.genoud@gmail.com), Adeneo Copyright (C) 2007
 *
 *     Derived from Das U-Boot source code
 *     		(u-boot-1.1.5/board/atmel/at91sam9263ek/nand.c)
 *     (C) Copyright 2006 ATMEL Rousset, Lacressonniere Nicolas
 *
 *
A
Andrew Victor 已提交
19 20 21 22 23 24 25 26 27 28 29 30 31
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License version 2 as
 * published by the Free Software Foundation.
 *
 */

#include <linux/slab.h>
#include <linux/module.h>
#include <linux/platform_device.h>
#include <linux/mtd/mtd.h>
#include <linux/mtd/nand.h>
#include <linux/mtd/partitions.h>

32
#include <asm/gpio.h>
A
Andrew Victor 已提交
33 34 35 36
#include <asm/io.h>

#include <asm/arch/board.h>

37
#ifdef CONFIG_MTD_NAND_ATMEL_ECC_HW
38 39 40 41 42
#define hard_ecc	1
#else
#define hard_ecc	0
#endif

43
#ifdef CONFIG_MTD_NAND_ATMEL_ECC_NONE
44 45 46 47 48 49 50
#define no_ecc		1
#else
#define no_ecc		0
#endif

/* Register access macros */
#define ecc_readl(add, reg)				\
51
	__raw_readl(add + ATMEL_ECC_##reg)
52
#define ecc_writel(add, reg, value)			\
53
	__raw_writel((value), add + ATMEL_ECC_##reg)
54

55
#include "atmel_nand_ecc.h"	/* Hardware ECC registers */
56 57 58 59 60 61

/* oob layout for large page size
 * bad block info is on bytes 0 and 1
 * the bytes have to be consecutives to avoid
 * several NAND_CMD_RNDOUT during read
 */
62
static struct nand_ecclayout atmel_oobinfo_large = {
63 64 65 66 67 68 69 70 71 72 73 74
	.eccbytes = 4,
	.eccpos = {60, 61, 62, 63},
	.oobfree = {
		{2, 58}
	},
};

/* oob layout for small page size
 * bad block info is on bytes 4 and 5
 * the bytes have to be consecutives to avoid
 * several NAND_CMD_RNDOUT during read
 */
75
static struct nand_ecclayout atmel_oobinfo_small = {
76 77 78 79 80 81 82
	.eccbytes = 4,
	.eccpos = {0, 1, 2, 3},
	.oobfree = {
		{6, 10}
	},
};

83
struct atmel_nand_host {
A
Andrew Victor 已提交
84 85 86
	struct nand_chip	nand_chip;
	struct mtd_info		mtd;
	void __iomem		*io_base;
87
	struct atmel_nand_data	*board;
88 89
	struct device		*dev;
	void __iomem		*ecc;
A
Andrew Victor 已提交
90 91
};

92 93 94
/*
 * Enable NAND.
 */
95
static void atmel_nand_enable(struct atmel_nand_host *host)
96 97
{
	if (host->board->enable_pin)
98
		gpio_set_value(host->board->enable_pin, 0);
99 100 101 102 103
}

/*
 * Disable NAND.
 */
104
static void atmel_nand_disable(struct atmel_nand_host *host)
105 106
{
	if (host->board->enable_pin)
107
		gpio_set_value(host->board->enable_pin, 1);
108 109
}

A
Andrew Victor 已提交
110 111 112
/*
 * Hardware specific access to control-lines
 */
113
static void atmel_nand_cmd_ctrl(struct mtd_info *mtd, int cmd, unsigned int ctrl)
A
Andrew Victor 已提交
114 115
{
	struct nand_chip *nand_chip = mtd->priv;
116
	struct atmel_nand_host *host = nand_chip->priv;
A
Andrew Victor 已提交
117

118
	if (ctrl & NAND_CTRL_CHANGE) {
119
		if (ctrl & NAND_NCE)
120
			atmel_nand_enable(host);
121
		else
122
			atmel_nand_disable(host);
123
	}
A
Andrew Victor 已提交
124 125 126 127 128 129 130 131 132 133 134 135
	if (cmd == NAND_CMD_NONE)
		return;

	if (ctrl & NAND_CLE)
		writeb(cmd, host->io_base + (1 << host->board->cle));
	else
		writeb(cmd, host->io_base + (1 << host->board->ale));
}

/*
 * Read the Device Ready pin.
 */
136
static int atmel_nand_device_ready(struct mtd_info *mtd)
A
Andrew Victor 已提交
137 138
{
	struct nand_chip *nand_chip = mtd->priv;
139
	struct atmel_nand_host *host = nand_chip->priv;
A
Andrew Victor 已提交
140

141
	return gpio_get_value(host->board->rdy_pin);
A
Andrew Victor 已提交
142 143
}

144 145 146
/*
 * write oob for small pages
 */
147
static int atmel_nand_write_oob_512(struct mtd_info *mtd,
148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174
		struct nand_chip *chip, int page)
{
	int chunk = chip->ecc.bytes + chip->ecc.prepad + chip->ecc.postpad;
	int eccsize = chip->ecc.size, length = mtd->oobsize;
	int len, pos, status = 0;
	const uint8_t *bufpoi = chip->oob_poi;

	pos = eccsize + chunk;

	chip->cmdfunc(mtd, NAND_CMD_SEQIN, pos, page);
	len = min_t(int, length, chunk);
	chip->write_buf(mtd, bufpoi, len);
	bufpoi += len;
	length -= len;
	if (length > 0)
		chip->write_buf(mtd, bufpoi, length);

	chip->cmdfunc(mtd, NAND_CMD_PAGEPROG, -1, -1);
	status = chip->waitfunc(mtd, chip);

	return status & NAND_STATUS_FAIL ? -EIO : 0;

}

/*
 * read oob for small pages
 */
175
static int atmel_nand_read_oob_512(struct mtd_info *mtd,
176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194
		struct nand_chip *chip,	int page, int sndcmd)
{
	if (sndcmd) {
		chip->cmdfunc(mtd, NAND_CMD_READOOB, 0, page);
		sndcmd = 0;
	}
	chip->read_buf(mtd, chip->oob_poi, mtd->oobsize);
	return sndcmd;
}

/*
 * Calculate HW ECC
 *
 * function called after a write
 *
 * mtd:        MTD block structure
 * dat:        raw data (unused)
 * ecc_code:   buffer for ECC
 */
195
static int atmel_nand_calculate(struct mtd_info *mtd,
196 197 198
		const u_char *dat, unsigned char *ecc_code)
{
	struct nand_chip *nand_chip = mtd->priv;
199
	struct atmel_nand_host *host = nand_chip->priv;
200 201 202 203
	uint32_t *eccpos = nand_chip->ecc.layout->eccpos;
	unsigned int ecc_value;

	/* get the first 2 ECC bytes */
204
	ecc_value = ecc_readl(host->ecc, PR);
205 206 207 208 209

	ecc_code[eccpos[0]] = ecc_value & 0xFF;
	ecc_code[eccpos[1]] = (ecc_value >> 8) & 0xFF;

	/* get the last 2 ECC bytes */
210
	ecc_value = ecc_readl(host->ecc, NPR) & ATMEL_ECC_NPARITY;
211 212 213 214 215 216 217 218 219 220 221 222 223 224

	ecc_code[eccpos[2]] = ecc_value & 0xFF;
	ecc_code[eccpos[3]] = (ecc_value >> 8) & 0xFF;

	return 0;
}

/*
 * HW ECC read page function
 *
 * mtd:        mtd info structure
 * chip:       nand chip info structure
 * buf:        buffer to store read data
 */
225
static int atmel_nand_read_page(struct mtd_info *mtd,
226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283
		struct nand_chip *chip, uint8_t *buf)
{
	int eccsize = chip->ecc.size;
	int eccbytes = chip->ecc.bytes;
	uint32_t *eccpos = chip->ecc.layout->eccpos;
	uint8_t *p = buf;
	uint8_t *oob = chip->oob_poi;
	uint8_t *ecc_pos;
	int stat;

	/* read the page */
	chip->read_buf(mtd, p, eccsize);

	/* move to ECC position if needed */
	if (eccpos[0] != 0) {
		/* This only works on large pages
		 * because the ECC controller waits for
		 * NAND_CMD_RNDOUTSTART after the
		 * NAND_CMD_RNDOUT.
		 * anyway, for small pages, the eccpos[0] == 0
		 */
		chip->cmdfunc(mtd, NAND_CMD_RNDOUT,
				mtd->writesize + eccpos[0], -1);
	}

	/* the ECC controller needs to read the ECC just after the data */
	ecc_pos = oob + eccpos[0];
	chip->read_buf(mtd, ecc_pos, eccbytes);

	/* check if there's an error */
	stat = chip->ecc.correct(mtd, p, oob, NULL);

	if (stat < 0)
		mtd->ecc_stats.failed++;
	else
		mtd->ecc_stats.corrected += stat;

	/* get back to oob start (end of page) */
	chip->cmdfunc(mtd, NAND_CMD_RNDOUT, mtd->writesize, -1);

	/* read the oob */
	chip->read_buf(mtd, oob, mtd->oobsize);

	return 0;
}

/*
 * HW ECC Correction
 *
 * function called after a read
 *
 * mtd:        MTD block structure
 * dat:        raw data read from the chip
 * read_ecc:   ECC from the chip (unused)
 * isnull:     unused
 *
 * Detect and correct a 1 bit error for a page
 */
284
static int atmel_nand_correct(struct mtd_info *mtd, u_char *dat,
285 286 287
		u_char *read_ecc, u_char *isnull)
{
	struct nand_chip *nand_chip = mtd->priv;
288
	struct atmel_nand_host *host = nand_chip->priv;
289 290 291 292 293 294 295
	unsigned int ecc_status;
	unsigned int ecc_word, ecc_bit;

	/* get the status from the Status Register */
	ecc_status = ecc_readl(host->ecc, SR);

	/* if there's no error */
296
	if (likely(!(ecc_status & ATMEL_ECC_RECERR)))
297 298 299
		return 0;

	/* get error bit offset (4 bits) */
300
	ecc_bit = ecc_readl(host->ecc, PR) & ATMEL_ECC_BITADDR;
301
	/* get word address (12 bits) */
302
	ecc_word = ecc_readl(host->ecc, PR) & ATMEL_ECC_WORDADDR;
303 304 305
	ecc_word >>= 4;

	/* if there are multiple errors */
306
	if (ecc_status & ATMEL_ECC_MULERR) {
307 308
		/* check if it is a freshly erased block
		 * (filled with 0xff) */
309 310
		if ((ecc_bit == ATMEL_ECC_BITADDR)
				&& (ecc_word == (ATMEL_ECC_WORDADDR >> 4))) {
311 312 313 314 315 316
			/* the block has just been erased, return OK */
			return 0;
		}
		/* it doesn't seems to be a freshly
		 * erased block.
		 * We can't correct so many errors */
317
		dev_dbg(host->dev, "atmel_nand : multiple errors detected."
318 319 320 321 322
				" Unable to correct.\n");
		return -EIO;
	}

	/* if there's a single bit error : we can correct it */
323
	if (ecc_status & ATMEL_ECC_ECCERR) {
324 325 326
		/* there's nothing much to do here.
		 * the bit error is on the ECC itself.
		 */
327
		dev_dbg(host->dev, "atmel_nand : one bit error on ECC code."
328 329 330 331
				" Nothing to correct\n");
		return 0;
	}

332
	dev_dbg(host->dev, "atmel_nand : one bit error on data."
333 334 335 336 337 338 339 340 341 342 343
			" (word offset in the page :"
			" 0x%x bit offset : 0x%x)\n",
			ecc_word, ecc_bit);
	/* correct the error */
	if (nand_chip->options & NAND_BUSWIDTH_16) {
		/* 16 bits words */
		((unsigned short *) dat)[ecc_word] ^= (1 << ecc_bit);
	} else {
		/* 8 bits words */
		dat[ecc_word] ^= (1 << ecc_bit);
	}
344
	dev_dbg(host->dev, "atmel_nand : error corrected\n");
345 346 347 348 349 350
	return 1;
}

/*
 * Enable HW ECC : unsused
 */
351
static void atmel_nand_hwctl(struct mtd_info *mtd, int mode) { ; }
352

353
#ifdef CONFIG_MTD_PARTITIONS
354
static const char *part_probes[] = { "cmdlinepart", NULL };
355 356
#endif

A
Andrew Victor 已提交
357 358 359
/*
 * Probe for the NAND device.
 */
360
static int __init atmel_nand_probe(struct platform_device *pdev)
A
Andrew Victor 已提交
361
{
362
	struct atmel_nand_host *host;
A
Andrew Victor 已提交
363 364
	struct mtd_info *mtd;
	struct nand_chip *nand_chip;
365 366
	struct resource *regs;
	struct resource *mem;
A
Andrew Victor 已提交
367 368 369 370 371 372 373
	int res;

#ifdef CONFIG_MTD_PARTITIONS
	struct mtd_partition *partitions = NULL;
	int num_partitions = 0;
#endif

374 375 376 377 378 379
	mem = platform_get_resource(pdev, IORESOURCE_MEM, 0);
	if (!mem) {
		printk(KERN_ERR "atmel_nand: can't get I/O resource mem\n");
		return -ENXIO;
	}

A
Andrew Victor 已提交
380
	/* Allocate memory for the device structure (and zero it) */
381
	host = kzalloc(sizeof(struct atmel_nand_host), GFP_KERNEL);
A
Andrew Victor 已提交
382
	if (!host) {
383
		printk(KERN_ERR "atmel_nand: failed to allocate device structure.\n");
A
Andrew Victor 已提交
384 385 386
		return -ENOMEM;
	}

387
	host->io_base = ioremap(mem->start, mem->end - mem->start + 1);
A
Andrew Victor 已提交
388
	if (host->io_base == NULL) {
389
		printk(KERN_ERR "atmel_nand: ioremap failed\n");
390 391
		res = -EIO;
		goto err_nand_ioremap;
A
Andrew Victor 已提交
392 393 394 395 396
	}

	mtd = &host->mtd;
	nand_chip = &host->nand_chip;
	host->board = pdev->dev.platform_data;
397
	host->dev = &pdev->dev;
A
Andrew Victor 已提交
398 399 400 401 402 403 404 405

	nand_chip->priv = host;		/* link the private data structures */
	mtd->priv = nand_chip;
	mtd->owner = THIS_MODULE;

	/* Set address of NAND IO lines */
	nand_chip->IO_ADDR_R = host->io_base;
	nand_chip->IO_ADDR_W = host->io_base;
406
	nand_chip->cmd_ctrl = atmel_nand_cmd_ctrl;
I
Ivan Kuten 已提交
407 408

	if (host->board->rdy_pin)
409
		nand_chip->dev_ready = atmel_nand_device_ready;
I
Ivan Kuten 已提交
410

411 412
	regs = platform_get_resource(pdev, IORESOURCE_MEM, 1);
	if (!regs && hard_ecc) {
413
		printk(KERN_ERR "atmel_nand: can't get I/O resource "
414 415 416
				"regs\nFalling back on software ECC\n");
	}

A
Andrew Victor 已提交
417
	nand_chip->ecc.mode = NAND_ECC_SOFT;	/* enable ECC */
418 419 420 421 422
	if (no_ecc)
		nand_chip->ecc.mode = NAND_ECC_NONE;
	if (hard_ecc && regs) {
		host->ecc = ioremap(regs->start, regs->end - regs->start + 1);
		if (host->ecc == NULL) {
423
			printk(KERN_ERR "atmel_nand: ioremap failed\n");
424 425 426 427
			res = -EIO;
			goto err_ecc_ioremap;
		}
		nand_chip->ecc.mode = NAND_ECC_HW_SYNDROME;
428 429 430 431
		nand_chip->ecc.calculate = atmel_nand_calculate;
		nand_chip->ecc.correct = atmel_nand_correct;
		nand_chip->ecc.hwctl = atmel_nand_hwctl;
		nand_chip->ecc.read_page = atmel_nand_read_page;
432 433 434 435 436
		nand_chip->ecc.bytes = 4;
		nand_chip->ecc.prepad = 0;
		nand_chip->ecc.postpad = 0;
	}

A
Andrew Victor 已提交
437 438
	nand_chip->chip_delay = 20;		/* 20us command delay time */

439 440 441
	if (host->board->bus_width_16)		/* 16-bit bus width */
		nand_chip->options |= NAND_BUSWIDTH_16;

A
Andrew Victor 已提交
442
	platform_set_drvdata(pdev, host);
443
	atmel_nand_enable(host);
A
Andrew Victor 已提交
444 445

	if (host->board->det_pin) {
446
		if (gpio_get_value(host->board->det_pin)) {
A
Andrew Victor 已提交
447 448
			printk ("No SmartMedia card inserted.\n");
			res = ENXIO;
449
			goto err_no_card;
A
Andrew Victor 已提交
450 451 452
		}
	}

453 454 455
	/* first scan to find the device and get the page size */
	if (nand_scan_ident(mtd, 1)) {
		res = -ENXIO;
456
		goto err_scan_ident;
457 458 459 460 461 462 463 464 465
	}

	if (nand_chip->ecc.mode == NAND_ECC_HW_SYNDROME) {
		/* ECC is calculated for the whole page (1 step) */
		nand_chip->ecc.size = mtd->writesize;

		/* set ECC page size and oob layout */
		switch (mtd->writesize) {
		case 512:
466 467 468 469
			nand_chip->ecc.layout = &atmel_oobinfo_small;
			nand_chip->ecc.read_oob = atmel_nand_read_oob_512;
			nand_chip->ecc.write_oob = atmel_nand_write_oob_512;
			ecc_writel(host->ecc, MR, ATMEL_ECC_PAGESIZE_528);
470 471
			break;
		case 1024:
472 473
			nand_chip->ecc.layout = &atmel_oobinfo_large;
			ecc_writel(host->ecc, MR, ATMEL_ECC_PAGESIZE_1056);
474 475
			break;
		case 2048:
476 477
			nand_chip->ecc.layout = &atmel_oobinfo_large;
			ecc_writel(host->ecc, MR, ATMEL_ECC_PAGESIZE_2112);
478 479
			break;
		case 4096:
480 481
			nand_chip->ecc.layout = &atmel_oobinfo_large;
			ecc_writel(host->ecc, MR, ATMEL_ECC_PAGESIZE_4224);
482 483 484 485 486 487 488 489 490 491 492 493 494 495 496 497 498 499
			break;
		default:
			/* page size not handled by HW ECC */
			/* switching back to soft ECC */
			nand_chip->ecc.mode = NAND_ECC_SOFT;
			nand_chip->ecc.calculate = NULL;
			nand_chip->ecc.correct = NULL;
			nand_chip->ecc.hwctl = NULL;
			nand_chip->ecc.read_page = NULL;
			nand_chip->ecc.postpad = 0;
			nand_chip->ecc.prepad = 0;
			nand_chip->ecc.bytes = 0;
			break;
		}
	}

	/* second phase scan */
	if (nand_scan_tail(mtd)) {
A
Andrew Victor 已提交
500
		res = -ENXIO;
501
		goto err_scan_tail;
A
Andrew Victor 已提交
502 503 504
	}

#ifdef CONFIG_MTD_PARTITIONS
505
#ifdef CONFIG_MTD_CMDLINE_PARTS
506
	mtd->name = "atmel_nand";
507 508
	num_partitions = parse_mtd_partitions(mtd, part_probes,
					      &partitions, 0);
509
#endif
510 511 512
	if (num_partitions <= 0 && host->board->partition_info)
		partitions = host->board->partition_info(mtd->size,
							 &num_partitions);
A
Andrew Victor 已提交
513 514

	if ((!partitions) || (num_partitions == 0)) {
515
		printk(KERN_ERR "atmel_nand: No parititions defined, or unsupported device.\n");
A
Andrew Victor 已提交
516
		res = ENXIO;
517
		goto err_no_partitions;
A
Andrew Victor 已提交
518 519 520 521 522 523 524 525 526 527
	}

	res = add_mtd_partitions(mtd, partitions, num_partitions);
#else
	res = add_mtd_device(mtd);
#endif

	if (!res)
		return res;

528
#ifdef CONFIG_MTD_PARTITIONS
529
err_no_partitions:
530
#endif
A
Andrew Victor 已提交
531
	nand_release(mtd);
532 533 534
err_scan_tail:
err_scan_ident:
err_no_card:
535
	atmel_nand_disable(host);
A
Andrew Victor 已提交
536
	platform_set_drvdata(pdev, NULL);
537 538 539
	if (host->ecc)
		iounmap(host->ecc);
err_ecc_ioremap:
A
Andrew Victor 已提交
540
	iounmap(host->io_base);
541
err_nand_ioremap:
A
Andrew Victor 已提交
542 543 544 545 546 547 548
	kfree(host);
	return res;
}

/*
 * Remove a NAND device.
 */
549
static int __devexit atmel_nand_remove(struct platform_device *pdev)
A
Andrew Victor 已提交
550
{
551
	struct atmel_nand_host *host = platform_get_drvdata(pdev);
A
Andrew Victor 已提交
552 553 554 555
	struct mtd_info *mtd = &host->mtd;

	nand_release(mtd);

556
	atmel_nand_disable(host);
A
Andrew Victor 已提交
557

558 559
	if (host->ecc)
		iounmap(host->ecc);
A
Andrew Victor 已提交
560 561 562 563 564 565
	iounmap(host->io_base);
	kfree(host);

	return 0;
}

566 567 568
static struct platform_driver atmel_nand_driver = {
	.probe		= atmel_nand_probe,
	.remove		= atmel_nand_remove,
A
Andrew Victor 已提交
569
	.driver		= {
570
		.name	= "atmel_nand",
A
Andrew Victor 已提交
571 572 573 574
		.owner	= THIS_MODULE,
	},
};

575
static int __init atmel_nand_init(void)
A
Andrew Victor 已提交
576
{
577
	return platform_driver_register(&atmel_nand_driver);
A
Andrew Victor 已提交
578 579 580
}


581
static void __exit atmel_nand_exit(void)
A
Andrew Victor 已提交
582
{
583
	platform_driver_unregister(&atmel_nand_driver);
A
Andrew Victor 已提交
584 585 586
}


587 588
module_init(atmel_nand_init);
module_exit(atmel_nand_exit);
A
Andrew Victor 已提交
589 590 591

MODULE_LICENSE("GPL");
MODULE_AUTHOR("Rick Bronson");
592
MODULE_DESCRIPTION("NAND/SmartMedia driver for AT91 / AVR32");
593
MODULE_ALIAS("platform:atmel_nand");