sh_flctl.c 23.5 KB
Newer Older
1 2 3
/*
 * SuperH FLCTL nand controller
 *
M
Magnus Damm 已提交
4 5
 * Copyright (c) 2008 Renesas Solutions Corp.
 * Copyright (c) 2008 Atom Create Engineering Co., Ltd.
6
 *
M
Magnus Damm 已提交
7
 * Based on fsl_elbc_nand.c, Copyright (c) 2006-2007 Freescale Semiconductor
8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26
 *
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation; version 2 of the License.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program; if not, write to the Free Software
 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
 *
 */

#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/delay.h>
27
#include <linux/interrupt.h>
28 29
#include <linux/io.h>
#include <linux/platform_device.h>
30
#include <linux/pm_runtime.h>
31
#include <linux/slab.h>
32
#include <linux/string.h>
33 34 35 36 37 38 39 40 41 42 43 44 45 46 47

#include <linux/mtd/mtd.h>
#include <linux/mtd/nand.h>
#include <linux/mtd/partitions.h>
#include <linux/mtd/sh_flctl.h>

static struct nand_ecclayout flctl_4secc_oob_16 = {
	.eccbytes = 10,
	.eccpos = {0, 1, 2, 3, 4, 5, 6, 7, 8, 9},
	.oobfree = {
		{.offset = 12,
		. length = 4} },
};

static struct nand_ecclayout flctl_4secc_oob_64 = {
48 49 50 51 52 53
	.eccbytes = 4 * 10,
	.eccpos = {
		 6,  7,  8,  9, 10, 11, 12, 13, 14, 15,
		22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
		38, 39, 40, 41, 42, 43, 44, 45, 46, 47,
		54, 55, 56, 57, 58, 59, 60, 61, 62, 63 },
54
	.oobfree = {
55 56 57 58
		{.offset =  2, .length = 4},
		{.offset = 16, .length = 6},
		{.offset = 32, .length = 6},
		{.offset = 48, .length = 6} },
59 60 61 62 63 64 65 66 67 68 69 70
};

static uint8_t scan_ff_pattern[] = { 0xff, 0xff };

static struct nand_bbt_descr flctl_4secc_smallpage = {
	.options = NAND_BBT_SCAN2NDPAGE,
	.offs = 11,
	.len = 1,
	.pattern = scan_ff_pattern,
};

static struct nand_bbt_descr flctl_4secc_largepage = {
71
	.options = NAND_BBT_SCAN2NDPAGE,
72
	.offs = 0,
73 74 75 76 77 78
	.len = 2,
	.pattern = scan_ff_pattern,
};

static void empty_fifo(struct sh_flctl *flctl)
{
79 80
	writel(flctl->flintdmacr_base | AC1CLR | AC0CLR, FLINTDMACR(flctl));
	writel(flctl->flintdmacr_base, FLINTDMACR(flctl));
81 82 83 84 85 86 87
}

static void start_translation(struct sh_flctl *flctl)
{
	writeb(TRSTRT, FLTRCR(flctl));
}

M
Magnus Damm 已提交
88 89
static void timeout_error(struct sh_flctl *flctl, const char *str)
{
L
Lucas De Marchi 已提交
90
	dev_err(&flctl->pdev->dev, "Timeout occurred in %s\n", str);
M
Magnus Damm 已提交
91 92
}

93 94 95 96 97 98 99 100 101 102 103 104
static void wait_completion(struct sh_flctl *flctl)
{
	uint32_t timeout = LOOP_TIMEOUT_MAX;

	while (timeout--) {
		if (readb(FLTRCR(flctl)) & TREND) {
			writeb(0x0, FLTRCR(flctl));
			return;
		}
		udelay(1);
	}

M
Magnus Damm 已提交
105
	timeout_error(flctl, __func__);
106 107 108 109 110 111 112 113 114 115 116 117
	writeb(0x0, FLTRCR(flctl));
}

static void set_addr(struct mtd_info *mtd, int column, int page_addr)
{
	struct sh_flctl *flctl = mtd_to_flctl(mtd);
	uint32_t addr = 0;

	if (column == -1) {
		addr = page_addr;	/* ERASE1 */
	} else if (page_addr != -1) {
		/* SEQIN, READ0, etc.. */
118 119
		if (flctl->chip.options & NAND_BUSWIDTH_16)
			column >>= 1;
120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151
		if (flctl->page_size) {
			addr = column & 0x0FFF;
			addr |= (page_addr & 0xff) << 16;
			addr |= ((page_addr >> 8) & 0xff) << 24;
			/* big than 128MB */
			if (flctl->rw_ADRCNT == ADRCNT2_E) {
				uint32_t 	addr2;
				addr2 = (page_addr >> 16) & 0xff;
				writel(addr2, FLADR2(flctl));
			}
		} else {
			addr = column;
			addr |= (page_addr & 0xff) << 8;
			addr |= ((page_addr >> 8) & 0xff) << 16;
			addr |= ((page_addr >> 16) & 0xff) << 24;
		}
	}
	writel(addr, FLADR(flctl));
}

static void wait_rfifo_ready(struct sh_flctl *flctl)
{
	uint32_t timeout = LOOP_TIMEOUT_MAX;

	while (timeout--) {
		uint32_t val;
		/* check FIFO */
		val = readl(FLDTCNTR(flctl)) >> 16;
		if (val & 0xFF)
			return;
		udelay(1);
	}
M
Magnus Damm 已提交
152
	timeout_error(flctl, __func__);
153 154 155 156 157 158 159 160 161 162 163 164 165
}

static void wait_wfifo_ready(struct sh_flctl *flctl)
{
	uint32_t len, timeout = LOOP_TIMEOUT_MAX;

	while (timeout--) {
		/* check FIFO */
		len = (readl(FLDTCNTR(flctl)) >> 16) & 0xFF;
		if (len >= 4)
			return;
		udelay(1);
	}
M
Magnus Damm 已提交
166
	timeout_error(flctl, __func__);
167 168
}

169 170
static enum flctl_ecc_res_t wait_recfifo_ready
		(struct sh_flctl *flctl, int sector_number)
171 172 173 174
{
	uint32_t timeout = LOOP_TIMEOUT_MAX;
	void __iomem *ecc_reg[4];
	int i;
175
	int state = FL_SUCCESS;
176 177
	uint32_t data, size;

178 179 180 181 182 183 184
	/*
	 * First this loops checks in FLDTCNTR if we are ready to read out the
	 * oob data. This is the case if either all went fine without errors or
	 * if the bottom part of the loop corrected the errors or marked them as
	 * uncorrectable and the controller is given time to push the data into
	 * the FIFO.
	 */
185
	while (timeout--) {
186
		/* check if all is ok and we can read out the OOB */
187
		size = readl(FLDTCNTR(flctl)) >> 24;
188 189 190 191 192 193 194 195 196 197 198 199
		if ((size & 0xFF) == 4)
			return state;

		/* check if a correction code has been calculated */
		if (!(readl(FL4ECCCR(flctl)) & _4ECCEND)) {
			/*
			 * either we wait for the fifo to be filled or a
			 * correction pattern is being generated
			 */
			udelay(1);
			continue;
		}
200

201 202 203 204 205 206 207 208 209
		/* check for an uncorrectable error */
		if (readl(FL4ECCCR(flctl)) & _4ECCFA) {
			/* check if we face a non-empty page */
			for (i = 0; i < 512; i++) {
				if (flctl->done_buff[i] != 0xff) {
					state = FL_ERROR; /* can't correct */
					break;
				}
			}
210

211 212 213 214 215 216
			if (state == FL_SUCCESS)
				dev_dbg(&flctl->pdev->dev,
				"reading empty sector %d, ecc error ignored\n",
				sector_number);

			writel(0, FL4ECCCR(flctl));
217
			continue;
218
		}
219 220 221 222 223 224 225 226

		/* start error correction */
		ecc_reg[0] = FL4ECCRESULT0(flctl);
		ecc_reg[1] = FL4ECCRESULT1(flctl);
		ecc_reg[2] = FL4ECCRESULT2(flctl);
		ecc_reg[3] = FL4ECCRESULT3(flctl);

		for (i = 0; i < 3; i++) {
227
			uint8_t org;
B
Bastian Hecht 已提交
228
			unsigned int index;
229

230 231
			data = readl(ecc_reg[i]);

232 233 234 235 236 237 238 239 240 241
			if (flctl->page_size)
				index = (512 * sector_number) +
					(data >> 16);
			else
				index = data >> 16;

			org = flctl->done_buff[index];
			flctl->done_buff[index] = org ^ (data & 0xFF);
		}
		state = FL_REPAIRABLE;
242 243 244
		writel(0, FL4ECCCR(flctl));
	}

M
Magnus Damm 已提交
245
	timeout_error(flctl, __func__);
246
	return FL_TIMEOUT;	/* timeout */
247 248 249 250 251 252 253 254 255 256 257 258 259 260
}

static void wait_wecfifo_ready(struct sh_flctl *flctl)
{
	uint32_t timeout = LOOP_TIMEOUT_MAX;
	uint32_t len;

	while (timeout--) {
		/* check FLECFIFO */
		len = (readl(FLDTCNTR(flctl)) >> 24) & 0xFF;
		if (len >= 4)
			return;
		udelay(1);
	}
M
Magnus Damm 已提交
261
	timeout_error(flctl, __func__);
262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283
}

static void read_datareg(struct sh_flctl *flctl, int offset)
{
	unsigned long data;
	unsigned long *buf = (unsigned long *)&flctl->done_buff[offset];

	wait_completion(flctl);

	data = readl(FLDATAR(flctl));
	*buf = le32_to_cpu(data);
}

static void read_fiforeg(struct sh_flctl *flctl, int rlen, int offset)
{
	int i, len_4align;
	unsigned long *buf = (unsigned long *)&flctl->done_buff[offset];

	len_4align = (rlen + 3) / 4;

	for (i = 0; i < len_4align; i++) {
		wait_rfifo_ready(flctl);
284
		buf[i] = readl(FLDTFIFO(flctl));
285 286 287 288
		buf[i] = be32_to_cpu(buf[i]);
	}
}

289 290
static enum flctl_ecc_res_t read_ecfiforeg
		(struct sh_flctl *flctl, uint8_t *buff, int sector)
291 292
{
	int i;
293
	enum flctl_ecc_res_t res;
294 295
	unsigned long *ecc_buf = (unsigned long *)buff;

296 297 298 299 300 301 302
	res = wait_recfifo_ready(flctl , sector);

	if (res != FL_ERROR) {
		for (i = 0; i < 4; i++) {
			ecc_buf[i] = readl(FLECFIFO(flctl));
			ecc_buf[i] = be32_to_cpu(ecc_buf[i]);
		}
303 304
	}

305
	return res;
306 307
}

B
Bastian Hecht 已提交
308 309
static void write_fiforeg(struct sh_flctl *flctl, int rlen,
						unsigned int offset)
310 311
{
	int i, len_4align;
B
Bastian Hecht 已提交
312
	unsigned long *buf = (unsigned long *)&flctl->done_buff[offset];
313 314 315 316

	len_4align = (rlen + 3) / 4;
	for (i = 0; i < len_4align; i++) {
		wait_wfifo_ready(flctl);
B
Bastian Hecht 已提交
317
		writel(cpu_to_be32(buf[i]), FLDTFIFO(flctl));
318 319 320
	}
}

B
Bastian Hecht 已提交
321 322
static void write_ec_fiforeg(struct sh_flctl *flctl, int rlen,
						unsigned int offset)
323 324
{
	int i, len_4align;
B
Bastian Hecht 已提交
325
	unsigned long *buf = (unsigned long *)&flctl->done_buff[offset];
326 327 328 329

	len_4align = (rlen + 3) / 4;
	for (i = 0; i < len_4align; i++) {
		wait_wecfifo_ready(flctl);
B
Bastian Hecht 已提交
330
		writel(cpu_to_be32(buf[i]), FLECFIFO(flctl));
331 332 333
	}
}

334 335 336
static void set_cmd_regs(struct mtd_info *mtd, uint32_t cmd, uint32_t flcmcdr_val)
{
	struct sh_flctl *flctl = mtd_to_flctl(mtd);
337
	uint32_t flcmncr_val = flctl->flcmncr_base & ~SEL_16BIT;
338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356
	uint32_t flcmdcr_val, addr_len_bytes = 0;

	/* Set SNAND bit if page size is 2048byte */
	if (flctl->page_size)
		flcmncr_val |= SNAND_E;
	else
		flcmncr_val &= ~SNAND_E;

	/* default FLCMDCR val */
	flcmdcr_val = DOCMD1_E | DOADR_E;

	/* Set for FLCMDCR */
	switch (cmd) {
	case NAND_CMD_ERASE1:
		addr_len_bytes = flctl->erase_ADRCNT;
		flcmdcr_val |= DOCMD2_E;
		break;
	case NAND_CMD_READ0:
	case NAND_CMD_READOOB:
357
	case NAND_CMD_RNDOUT:
358 359
		addr_len_bytes = flctl->rw_ADRCNT;
		flcmdcr_val |= CDSRC_E;
360 361
		if (flctl->chip.options & NAND_BUSWIDTH_16)
			flcmncr_val |= SEL_16BIT;
362 363 364 365 366 367 368
		break;
	case NAND_CMD_SEQIN:
		/* This case is that cmd is READ0 or READ1 or READ00 */
		flcmdcr_val &= ~DOADR_E;	/* ONLY execute 1st cmd */
		break;
	case NAND_CMD_PAGEPROG:
		addr_len_bytes = flctl->rw_ADRCNT;
369
		flcmdcr_val |= DOCMD2_E | CDSRC_E | SELRW;
370 371
		if (flctl->chip.options & NAND_BUSWIDTH_16)
			flcmncr_val |= SEL_16BIT;
372 373 374
		break;
	case NAND_CMD_READID:
		flcmncr_val &= ~SNAND_E;
375
		flcmdcr_val |= CDSRC_E;
376 377 378 379 380 381 382 383 384 385 386 387 388 389 390 391 392 393 394 395 396
		addr_len_bytes = ADRCNT_1;
		break;
	case NAND_CMD_STATUS:
	case NAND_CMD_RESET:
		flcmncr_val &= ~SNAND_E;
		flcmdcr_val &= ~(DOADR_E | DOSR_E);
		break;
	default:
		break;
	}

	/* Set address bytes parameter */
	flcmdcr_val |= addr_len_bytes;

	/* Now actually write */
	writel(flcmncr_val, FLCMNCR(flctl));
	writel(flcmdcr_val, FLCMDCR(flctl));
	writel(flcmcdr_val, FLCMCDR(flctl));
}

static int flctl_read_page_hwecc(struct mtd_info *mtd, struct nand_chip *chip,
397
				uint8_t *buf, int oob_required, int page)
398
{
399
	chip->read_buf(mtd, buf, mtd->writesize);
400 401
	if (oob_required)
		chip->read_buf(mtd, chip->oob_poi, mtd->oobsize);
402 403 404
	return 0;
}

405
static int flctl_write_page_hwecc(struct mtd_info *mtd, struct nand_chip *chip,
406
				   const uint8_t *buf, int oob_required)
407
{
408
	chip->write_buf(mtd, buf, mtd->writesize);
409
	chip->write_buf(mtd, chip->oob_poi, mtd->oobsize);
410
	return 0;
411 412 413 414 415 416
}

static void execmd_read_page_sector(struct mtd_info *mtd, int page_addr)
{
	struct sh_flctl *flctl = mtd_to_flctl(mtd);
	int sector, page_sectors;
417
	enum flctl_ecc_res_t ecc_result;
418

419 420 421 422
	page_sectors = flctl->page_size ? 4 : 1;

	set_cmd_regs(mtd, NAND_CMD_READ0,
		(NAND_CMD_READSTART << 8) | NAND_CMD_READ0);
423 424 425

	writel(readl(FLCMNCR(flctl)) | ACM_SACCES_MODE | _4ECCCORRECT,
		 FLCMNCR(flctl));
426 427
	writel(readl(FLCMDCR(flctl)) | page_sectors, FLCMDCR(flctl));
	writel(page_addr << 2, FLADR(flctl));
428

429 430
	empty_fifo(flctl);
	start_translation(flctl);
431 432 433 434

	for (sector = 0; sector < page_sectors; sector++) {
		read_fiforeg(flctl, 512, 512 * sector);

435
		ecc_result = read_ecfiforeg(flctl,
436 437
			&flctl->done_buff[mtd->writesize + 16 * sector],
			sector);
438

439 440 441 442 443 444 445 446 447 448 449 450 451 452 453
		switch (ecc_result) {
		case FL_REPAIRABLE:
			dev_info(&flctl->pdev->dev,
				"applied ecc on page 0x%x", page_addr);
			flctl->mtd.ecc_stats.corrected++;
			break;
		case FL_ERROR:
			dev_warn(&flctl->pdev->dev,
				"page 0x%x contains corrupted data\n",
				page_addr);
			flctl->mtd.ecc_stats.failed++;
			break;
		default:
			;
		}
454
	}
455 456 457

	wait_completion(flctl);

458 459 460 461 462 463 464
	writel(readl(FLCMNCR(flctl)) & ~(ACM_SACCES_MODE | _4ECCCORRECT),
			FLCMNCR(flctl));
}

static void execmd_read_oob(struct mtd_info *mtd, int page_addr)
{
	struct sh_flctl *flctl = mtd_to_flctl(mtd);
465 466
	int page_sectors = flctl->page_size ? 4 : 1;
	int i;
467 468 469 470 471 472

	set_cmd_regs(mtd, NAND_CMD_READ0,
		(NAND_CMD_READSTART << 8) | NAND_CMD_READ0);

	empty_fifo(flctl);

473 474
	for (i = 0; i < page_sectors; i++) {
		set_addr(mtd, (512 + 16) * i + 512 , page_addr);
475 476 477
		writel(16, FLDTCNTR(flctl));

		start_translation(flctl);
478
		read_fiforeg(flctl, 16, 16 * i);
479 480 481 482 483 484 485
		wait_completion(flctl);
	}
}

static void execmd_write_page_sector(struct mtd_info *mtd)
{
	struct sh_flctl *flctl = mtd_to_flctl(mtd);
486
	int page_addr = flctl->seqin_page_addr;
487 488
	int sector, page_sectors;

489
	page_sectors = flctl->page_size ? 4 : 1;
490 491 492 493

	set_cmd_regs(mtd, NAND_CMD_PAGEPROG,
			(NAND_CMD_PAGEPROG << 8) | NAND_CMD_SEQIN);

494 495 496 497 498
	empty_fifo(flctl);
	writel(readl(FLCMNCR(flctl)) | ACM_SACCES_MODE, FLCMNCR(flctl));
	writel(readl(FLCMDCR(flctl)) | page_sectors, FLCMDCR(flctl));
	writel(page_addr << 2, FLADR(flctl));
	start_translation(flctl);
499

500
	for (sector = 0; sector < page_sectors; sector++) {
501
		write_fiforeg(flctl, 512, 512 * sector);
502
		write_ec_fiforeg(flctl, 16, mtd->writesize + 16 * sector);
503 504
	}

505
	wait_completion(flctl);
506 507 508 509 510 511 512 513 514
	writel(readl(FLCMNCR(flctl)) & ~ACM_SACCES_MODE, FLCMNCR(flctl));
}

static void execmd_write_oob(struct mtd_info *mtd)
{
	struct sh_flctl *flctl = mtd_to_flctl(mtd);
	int page_addr = flctl->seqin_page_addr;
	int sector, page_sectors;

515
	page_sectors = flctl->page_size ? 4 : 1;
516 517 518 519

	set_cmd_regs(mtd, NAND_CMD_PAGEPROG,
			(NAND_CMD_PAGEPROG << 8) | NAND_CMD_SEQIN);

520
	for (sector = 0; sector < page_sectors; sector++) {
521 522 523 524 525 526 527 528 529 530 531 532 533 534 535 536
		empty_fifo(flctl);
		set_addr(mtd, sector * 528 + 512, page_addr);
		writel(16, FLDTCNTR(flctl));	/* set read size */

		start_translation(flctl);
		write_fiforeg(flctl, 16, 16 * sector);
		wait_completion(flctl);
	}
}

static void flctl_cmdfunc(struct mtd_info *mtd, unsigned int command,
			int column, int page_addr)
{
	struct sh_flctl *flctl = mtd_to_flctl(mtd);
	uint32_t read_cmd = 0;

537 538
	pm_runtime_get_sync(&flctl->pdev->dev);

539 540 541 542 543 544 545 546 547 548 549 550 551 552 553 554 555 556 557 558 559
	flctl->read_bytes = 0;
	if (command != NAND_CMD_PAGEPROG)
		flctl->index = 0;

	switch (command) {
	case NAND_CMD_READ1:
	case NAND_CMD_READ0:
		if (flctl->hwecc) {
			/* read page with hwecc */
			execmd_read_page_sector(mtd, page_addr);
			break;
		}
		if (flctl->page_size)
			set_cmd_regs(mtd, command, (NAND_CMD_READSTART << 8)
				| command);
		else
			set_cmd_regs(mtd, command, command);

		set_addr(mtd, 0, page_addr);

		flctl->read_bytes = mtd->writesize + mtd->oobsize;
560 561
		if (flctl->chip.options & NAND_BUSWIDTH_16)
			column >>= 1;
562 563 564 565 566 567 568 569 570 571 572 573 574 575 576 577 578 579 580 581 582
		flctl->index += column;
		goto read_normal_exit;

	case NAND_CMD_READOOB:
		if (flctl->hwecc) {
			/* read page with hwecc */
			execmd_read_oob(mtd, page_addr);
			break;
		}

		if (flctl->page_size) {
			set_cmd_regs(mtd, command, (NAND_CMD_READSTART << 8)
				| NAND_CMD_READ0);
			set_addr(mtd, mtd->writesize, page_addr);
		} else {
			set_cmd_regs(mtd, command, command);
			set_addr(mtd, 0, page_addr);
		}
		flctl->read_bytes = mtd->oobsize;
		goto read_normal_exit;

583 584 585 586 587 588 589 590 591 592 593 594 595 596 597
	case NAND_CMD_RNDOUT:
		if (flctl->hwecc)
			break;

		if (flctl->page_size)
			set_cmd_regs(mtd, command, (NAND_CMD_RNDOUTSTART << 8)
				| command);
		else
			set_cmd_regs(mtd, command, command);

		set_addr(mtd, column, 0);

		flctl->read_bytes = mtd->writesize + mtd->oobsize - column;
		goto read_normal_exit;

598 599 600
	case NAND_CMD_READID:
		set_cmd_regs(mtd, command, command);

601 602 603 604 605 606
		/* READID is always performed using an 8-bit bus */
		if (flctl->chip.options & NAND_BUSWIDTH_16)
			column <<= 1;
		set_addr(mtd, column, 0);

		flctl->read_bytes = 8;
607
		writel(flctl->read_bytes, FLDTCNTR(flctl)); /* set read size */
608
		empty_fifo(flctl);
609
		start_translation(flctl);
610 611
		read_fiforeg(flctl, flctl->read_bytes, 0);
		wait_completion(flctl);
612 613 614 615 616 617 618 619 620 621 622 623 624 625 626 627 628 629 630 631 632 633 634 635 636 637 638 639 640 641 642 643 644 645 646 647 648 649 650 651 652 653 654 655 656 657 658 659 660 661 662 663 664 665 666 667 668 669 670 671 672 673 674 675 676 677 678 679 680 681 682 683 684 685 686 687 688 689 690 691 692 693
		break;

	case NAND_CMD_ERASE1:
		flctl->erase1_page_addr = page_addr;
		break;

	case NAND_CMD_ERASE2:
		set_cmd_regs(mtd, NAND_CMD_ERASE1,
			(command << 8) | NAND_CMD_ERASE1);
		set_addr(mtd, -1, flctl->erase1_page_addr);
		start_translation(flctl);
		wait_completion(flctl);
		break;

	case NAND_CMD_SEQIN:
		if (!flctl->page_size) {
			/* output read command */
			if (column >= mtd->writesize) {
				column -= mtd->writesize;
				read_cmd = NAND_CMD_READOOB;
			} else if (column < 256) {
				read_cmd = NAND_CMD_READ0;
			} else {
				column -= 256;
				read_cmd = NAND_CMD_READ1;
			}
		}
		flctl->seqin_column = column;
		flctl->seqin_page_addr = page_addr;
		flctl->seqin_read_cmd = read_cmd;
		break;

	case NAND_CMD_PAGEPROG:
		empty_fifo(flctl);
		if (!flctl->page_size) {
			set_cmd_regs(mtd, NAND_CMD_SEQIN,
					flctl->seqin_read_cmd);
			set_addr(mtd, -1, -1);
			writel(0, FLDTCNTR(flctl));	/* set 0 size */
			start_translation(flctl);
			wait_completion(flctl);
		}
		if (flctl->hwecc) {
			/* write page with hwecc */
			if (flctl->seqin_column == mtd->writesize)
				execmd_write_oob(mtd);
			else if (!flctl->seqin_column)
				execmd_write_page_sector(mtd);
			else
				printk(KERN_ERR "Invalid address !?\n");
			break;
		}
		set_cmd_regs(mtd, command, (command << 8) | NAND_CMD_SEQIN);
		set_addr(mtd, flctl->seqin_column, flctl->seqin_page_addr);
		writel(flctl->index, FLDTCNTR(flctl));	/* set write size */
		start_translation(flctl);
		write_fiforeg(flctl, flctl->index, 0);
		wait_completion(flctl);
		break;

	case NAND_CMD_STATUS:
		set_cmd_regs(mtd, command, command);
		set_addr(mtd, -1, -1);

		flctl->read_bytes = 1;
		writel(flctl->read_bytes, FLDTCNTR(flctl)); /* set read size */
		start_translation(flctl);
		read_datareg(flctl, 0); /* read and end */
		break;

	case NAND_CMD_RESET:
		set_cmd_regs(mtd, command, command);
		set_addr(mtd, -1, -1);

		writel(0, FLDTCNTR(flctl));	/* set 0 size */
		start_translation(flctl);
		wait_completion(flctl);
		break;

	default:
		break;
	}
694
	goto runtime_exit;
695 696 697

read_normal_exit:
	writel(flctl->read_bytes, FLDTCNTR(flctl));	/* set read size */
698
	empty_fifo(flctl);
699 700 701
	start_translation(flctl);
	read_fiforeg(flctl, flctl->read_bytes, 0);
	wait_completion(flctl);
702 703
runtime_exit:
	pm_runtime_put_sync(&flctl->pdev->dev);
704 705 706 707 708 709
	return;
}

static void flctl_select_chip(struct mtd_info *mtd, int chipnr)
{
	struct sh_flctl *flctl = mtd_to_flctl(mtd);
710
	int ret;
711 712 713

	switch (chipnr) {
	case -1:
714
		flctl->flcmncr_base &= ~CE0_ENABLE;
715 716

		pm_runtime_get_sync(&flctl->pdev->dev);
717
		writel(flctl->flcmncr_base, FLCMNCR(flctl));
718 719 720 721 722 723 724

		if (flctl->qos_request) {
			dev_pm_qos_remove_request(&flctl->pm_qos);
			flctl->qos_request = 0;
		}

		pm_runtime_put_sync(&flctl->pdev->dev);
725 726
		break;
	case 0:
727
		flctl->flcmncr_base |= CE0_ENABLE;
728 729 730 731 732 733 734 735 736 737 738 739

		if (!flctl->qos_request) {
			ret = dev_pm_qos_add_request(&flctl->pdev->dev,
							&flctl->pm_qos, 100);
			if (ret < 0)
				dev_err(&flctl->pdev->dev,
					"PM QoS request failed: %d\n", ret);
			flctl->qos_request = 1;
		}

		if (flctl->holden) {
			pm_runtime_get_sync(&flctl->pdev->dev);
740
			writel(HOLDEN, FLHOLDCR(flctl));
741 742
			pm_runtime_put_sync(&flctl->pdev->dev);
		}
743 744 745 746 747 748 749 750 751 752
		break;
	default:
		BUG();
	}
}

static void flctl_write_buf(struct mtd_info *mtd, const uint8_t *buf, int len)
{
	struct sh_flctl *flctl = mtd_to_flctl(mtd);

B
Bastian Hecht 已提交
753
	memcpy(&flctl->done_buff[flctl->index], buf, len);
754 755 756 757 758 759 760 761
	flctl->index += len;
}

static uint8_t flctl_read_byte(struct mtd_info *mtd)
{
	struct sh_flctl *flctl = mtd_to_flctl(mtd);
	uint8_t data;

B
Bastian Hecht 已提交
762
	data = flctl->done_buff[flctl->index];
763 764 765 766
	flctl->index++;
	return data;
}

767 768
static uint16_t flctl_read_word(struct mtd_info *mtd)
{
B
Bastian Hecht 已提交
769 770 771 772 773
	struct sh_flctl *flctl = mtd_to_flctl(mtd);
	uint16_t *buf = (uint16_t *)&flctl->done_buff[flctl->index];

	flctl->index += 2;
	return *buf;
774 775
}

776 777
static void flctl_read_buf(struct mtd_info *mtd, uint8_t *buf, int len)
{
778
	struct sh_flctl *flctl = mtd_to_flctl(mtd);
779

B
Bastian Hecht 已提交
780
	memcpy(buf, &flctl->done_buff[flctl->index], len);
781
	flctl->index += len;
782 783 784 785 786 787 788 789 790 791 792 793 794 795 796 797 798 799 800 801 802 803 804 805 806 807 808 809 810 811 812 813 814 815 816 817 818 819 820 821 822 823 824 825 826 827 828 829
}

static int flctl_chip_init_tail(struct mtd_info *mtd)
{
	struct sh_flctl *flctl = mtd_to_flctl(mtd);
	struct nand_chip *chip = &flctl->chip;

	if (mtd->writesize == 512) {
		flctl->page_size = 0;
		if (chip->chipsize > (32 << 20)) {
			/* big than 32MB */
			flctl->rw_ADRCNT = ADRCNT_4;
			flctl->erase_ADRCNT = ADRCNT_3;
		} else if (chip->chipsize > (2 << 16)) {
			/* big than 128KB */
			flctl->rw_ADRCNT = ADRCNT_3;
			flctl->erase_ADRCNT = ADRCNT_2;
		} else {
			flctl->rw_ADRCNT = ADRCNT_2;
			flctl->erase_ADRCNT = ADRCNT_1;
		}
	} else {
		flctl->page_size = 1;
		if (chip->chipsize > (128 << 20)) {
			/* big than 128MB */
			flctl->rw_ADRCNT = ADRCNT2_E;
			flctl->erase_ADRCNT = ADRCNT_3;
		} else if (chip->chipsize > (8 << 16)) {
			/* big than 512KB */
			flctl->rw_ADRCNT = ADRCNT_4;
			flctl->erase_ADRCNT = ADRCNT_2;
		} else {
			flctl->rw_ADRCNT = ADRCNT_3;
			flctl->erase_ADRCNT = ADRCNT_1;
		}
	}

	if (flctl->hwecc) {
		if (mtd->writesize == 512) {
			chip->ecc.layout = &flctl_4secc_oob_16;
			chip->badblock_pattern = &flctl_4secc_smallpage;
		} else {
			chip->ecc.layout = &flctl_4secc_oob_64;
			chip->badblock_pattern = &flctl_4secc_largepage;
		}

		chip->ecc.size = 512;
		chip->ecc.bytes = 10;
M
Mike Dunn 已提交
830
		chip->ecc.strength = 4;
831 832 833 834 835
		chip->ecc.read_page = flctl_read_page_hwecc;
		chip->ecc.write_page = flctl_write_page_hwecc;
		chip->ecc.mode = NAND_ECC_HW;

		/* 4 symbols ECC enabled */
836
		flctl->flcmncr_base |= _4ECCEN;
837 838 839 840 841 842 843
	} else {
		chip->ecc.mode = NAND_ECC_SOFT;
	}

	return 0;
}

844 845 846 847 848 849 850 851 852 853
static irqreturn_t flctl_handle_flste(int irq, void *dev_id)
{
	struct sh_flctl *flctl = dev_id;

	dev_err(&flctl->pdev->dev, "flste irq: %x\n", readl(FLINTDMACR(flctl)));
	writel(flctl->flintdmacr_base, FLINTDMACR(flctl));

	return IRQ_HANDLED;
}

M
Magnus Damm 已提交
854
static int __devinit flctl_probe(struct platform_device *pdev)
855 856 857 858 859 860
{
	struct resource *res;
	struct sh_flctl *flctl;
	struct mtd_info *flctl_mtd;
	struct nand_chip *nand;
	struct sh_flctl_platform_data *pdata;
M
Magnus Damm 已提交
861
	int ret = -ENXIO;
862
	int irq;
863 864 865

	pdata = pdev->dev.platform_data;
	if (pdata == NULL) {
M
Magnus Damm 已提交
866 867
		dev_err(&pdev->dev, "no platform data defined\n");
		return -EINVAL;
868 869 870 871
	}

	flctl = kzalloc(sizeof(struct sh_flctl), GFP_KERNEL);
	if (!flctl) {
M
Magnus Damm 已提交
872
		dev_err(&pdev->dev, "failed to allocate driver data\n");
873 874 875 876 877
		return -ENOMEM;
	}

	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
	if (!res) {
M
Magnus Damm 已提交
878
		dev_err(&pdev->dev, "failed to get I/O memory\n");
879
		goto err_iomap;
880 881
	}

882
	flctl->reg = ioremap(res->start, resource_size(res));
883
	if (flctl->reg == NULL) {
M
Magnus Damm 已提交
884
		dev_err(&pdev->dev, "failed to remap I/O memory\n");
885
		goto err_iomap;
886 887
	}

888 889 890 891 892 893 894 895 896 897 898 899
	irq = platform_get_irq(pdev, 0);
	if (irq < 0) {
		dev_err(&pdev->dev, "failed to get flste irq data\n");
		goto err_flste;
	}

	ret = request_irq(irq, flctl_handle_flste, IRQF_SHARED, "flste", flctl);
	if (ret) {
		dev_err(&pdev->dev, "request interrupt failed.\n");
		goto err_flste;
	}

900 901 902 903
	platform_set_drvdata(pdev, flctl);
	flctl_mtd = &flctl->mtd;
	nand = &flctl->chip;
	flctl_mtd->priv = nand;
M
Magnus Damm 已提交
904
	flctl->pdev = pdev;
905
	flctl->hwecc = pdata->has_hwecc;
906
	flctl->holden = pdata->use_holden;
907 908
	flctl->flcmncr_base = pdata->flcmncr_val;
	flctl->flintdmacr_base = flctl->hwecc ? (STERINTE | ECERB) : STERINTE;
909 910 911 912 913 914 915 916 917 918 919

	/* Set address of hardware control function */
	/* 20 us command delay time */
	nand->chip_delay = 20;

	nand->read_byte = flctl_read_byte;
	nand->write_buf = flctl_write_buf;
	nand->read_buf = flctl_read_buf;
	nand->select_chip = flctl_select_chip;
	nand->cmdfunc = flctl_cmdfunc;

920 921 922 923 924
	if (pdata->flcmncr_val & SEL_16BIT) {
		nand->options |= NAND_BUSWIDTH_16;
		nand->read_word = flctl_read_word;
	}

925 926 927
	pm_runtime_enable(&pdev->dev);
	pm_runtime_resume(&pdev->dev);

928
	ret = nand_scan_ident(flctl_mtd, 1, NULL);
929
	if (ret)
930
		goto err_chip;
931 932 933

	ret = flctl_chip_init_tail(flctl_mtd);
	if (ret)
934
		goto err_chip;
935 936 937

	ret = nand_scan_tail(flctl_mtd);
	if (ret)
938
		goto err_chip;
939

940
	mtd_device_register(flctl_mtd, pdata->parts, pdata->nr_parts);
941 942 943

	return 0;

944 945
err_chip:
	pm_runtime_disable(&pdev->dev);
946 947
	free_irq(irq, flctl);
err_flste:
948
	iounmap(flctl->reg);
949
err_iomap:
950 951 952 953
	kfree(flctl);
	return ret;
}

M
Magnus Damm 已提交
954
static int __devexit flctl_remove(struct platform_device *pdev)
955 956 957 958
{
	struct sh_flctl *flctl = platform_get_drvdata(pdev);

	nand_release(&flctl->mtd);
959
	pm_runtime_disable(&pdev->dev);
960
	free_irq(platform_get_irq(pdev, 0), flctl);
961
	iounmap(flctl->reg);
962 963 964 965 966 967 968 969 970 971 972 973 974 975 976
	kfree(flctl);

	return 0;
}

static struct platform_driver flctl_driver = {
	.remove		= flctl_remove,
	.driver = {
		.name	= "sh_flctl",
		.owner	= THIS_MODULE,
	},
};

static int __init flctl_nand_init(void)
{
977
	return platform_driver_probe(&flctl_driver, flctl_probe);
978 979 980 981 982 983 984 985 986 987 988 989 990 991
}

static void __exit flctl_nand_cleanup(void)
{
	platform_driver_unregister(&flctl_driver);
}

module_init(flctl_nand_init);
module_exit(flctl_nand_cleanup);

MODULE_LICENSE("GPL");
MODULE_AUTHOR("Yoshihiro Shimoda");
MODULE_DESCRIPTION("SuperH FLCTL driver");
MODULE_ALIAS("platform:sh_flctl");