Commit be6ee378 authored by Alexander Potashev's avatar Alexander Potashev

RT75957. kinetis nand: import an existing NAND driver

Import the existing NAND Flash Controller driver for MCF5441x from
http://repository.timesys.com/buildsources/u/u-boot/u-boot-2009.08/u-boot-2009.08-mfc5441x.patch

The NAND Flash Controllers on MCF5441x and Kinetis are compatible, we
will use this driver for Kinetis.
parent 24052ec7
......@@ -50,6 +50,7 @@ COBJS-$(CONFIG_NAND_S3C64XX) += s3c64xx.o
COBJS-$(CONFIG_NAND_SPEAR) += spr_nand.o
COBJS-$(CONFIG_NAND_OMAP_GPMC) += omap_gpmc.o
COBJS-$(CONFIG_NAND_PLAT) += nand_plat.o
COBJS-$(CONFIG_NAND_FSL_NFC) += fsl_nfc.o
endif
COBJS := $(COBJS-y)
......
/*
* Copyright (C) 2009-2010 Freescale Semiconductor, Inc. All rights reserved.
*
* Author: Shaohui Xie <b21989@freescale.com>
* Jason Jin <jason.jin@freescale.com>
*
* Description:
* MPC5125 Nand driver.
* Port to m54418twr board.
*
* Based on original driver mpc5121_nfc.c.
*
* This 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; either version 2 of the License, or
* (at your option) any later version.
*/
#include <common.h>
#include <malloc.h>
#include <linux/mtd/mtd.h>
#include <linux/mtd/nand.h>
#include <linux/mtd/nand_ecc.h>
#include <linux/mtd/compat.h>
#include <mtd/fsl_nfc.h>
#include <nand.h>
#include <asm/errno.h>
#include <asm/io.h>
#include <asm/processor.h>
#include <asm/immap.h>
#define DRV_NAME "fsl_nfc"
#define DRV_VERSION "0.5"
/* Timeouts */
#define NFC_RESET_TIMEOUT 1000 /* 1 ms */
#define NFC_TIMEOUT 5000 /* 1/10 s */
#define ECC_SRAM_ADDR 0x100
#define ECC_STATUS_MASK 0x80
#define ECC_ERR_COUNT 0x3F
#define MIN(x, y) ((x < y) ? x : y)
#ifdef CONFIG_MTD_NAND_FSL_NFC_SWECC
static int hardware_ecc;
#else
static int hardware_ecc = 1;
#endif
struct fsl_nfc_prv {
struct mtd_info mtd;
struct nand_chip chip;
int irq;
void __iomem *regs;
struct clk *clk;
uint column;
int spareonly;
u8 *testbuf;
};
int fsl_nfc_chip;
static int get_status;
static int get_id;
static u8 bbt_pattern[] = {'B', 'b', 't', '0' };
static u8 mirror_pattern[] = {'1', 't', 'b', 'B' };
static struct nand_bbt_descr bbt_main_descr = {
.options = NAND_BBT_LASTBLOCK | NAND_BBT_CREATE | NAND_BBT_WRITE |
NAND_BBT_2BIT | NAND_BBT_VERSION,
.offs = 11,
.len = 4,
.veroffs = 15,
.maxblocks = 4,
.pattern = bbt_pattern,
};
static struct nand_bbt_descr bbt_mirror_descr = {
.options = NAND_BBT_LASTBLOCK | NAND_BBT_CREATE | NAND_BBT_WRITE |
NAND_BBT_2BIT | NAND_BBT_VERSION,
.offs = 11,
.len = 4,
.veroffs = 15,
.maxblocks = 4,
.pattern = mirror_pattern,
};
static struct nand_ecclayout nand_hw_eccoob_512 = {
.eccbytes = 8,
.eccpos = {
8, 9, 10, 11, 12, 13, 14, 15,
},
.oobfree = {
{0, 5} /* byte 5 is factory bad block marker */
},
};
static struct nand_ecclayout fsl_nfc_ecc45 = {
.eccbytes = 45,
.eccpos = {19, 20, 21, 22, 23,
24, 25, 26, 27, 28, 29, 30, 31,
32, 33, 34, 35, 36, 37, 38, 39,
40, 41, 42, 43, 44, 45, 46, 47,
48, 49, 50, 51, 52, 53, 54, 55,
56, 57, 58, 59, 60, 61, 62, 63},
.oobfree = {
{.offset = 8,
.length = 11} }
};
static struct nand_ecclayout fsl_nfc_ecc15 = {
.eccbytes = 15,
.eccpos = {49, 50, 51, 52, 53, 54, 55,
56, 57, 58, 59, 60, 61, 62, 63},
.oobfree = {
{.offset = 8,
.length = 41} }
};
static struct nand_ecclayout fsl_nfc_ecc23 = {
.eccbytes = 23,
.eccpos = {41, 42, 43, 44, 45, 46, 47,
48, 49, 50, 51, 52, 53, 54, 55,
56, 57, 58, 59, 60, 61, 62, 63},
.oobfree = {
{.offset = 8,
.length = 33} }
};
static struct nand_ecclayout nand_hw_eccoob_2k = {
.eccbytes = 32,
.eccpos = {
/* 8 bytes of ecc for each 512 bytes of data */
8, 9, 10, 11, 12, 13, 14, 15,
24, 25, 26, 27, 28, 29, 30, 31,
40, 41, 42, 43, 44, 45, 46, 47,
56, 57, 58, 59, 60, 61, 62, 63,
},
.oobfree = {
{2, 5}, /* bytes 0 and 1 are factory bad block markers */
{16, 7},
{32, 7},
{48, 7},
},
};
/* ecc struct for nand 5125 */
static struct nand_ecclayout nand5125_hw_eccoob_2k = {
.eccbytes = 60,
.eccpos = {
/* 60 bytes of ecc for one page bytes of data */
4, 5,
6, 7, 8, 9, 10, 11, 12, 13, 14, 15,
16, 17, 18, 19, 20, 21, 22, 23, 24, 25,
26, 27, 28, 29, 30, 31, 32, 33, 34, 35,
36, 37, 38, 39, 40, 41, 42, 43, 44, 45,
46, 47, 48, 49, 50, 51, 52, 53, 54, 55,
56, 57, 58, 59, 60, 61, 62, 63,
},
.oobfree = {
{2, 2}, /* bytes 0 and 1 are factory bad block markers */
},
};
static inline u32 nfc_read(struct mtd_info *mtd, uint reg)
{
struct nand_chip *chip = mtd->priv;
struct fsl_nfc_prv *prv = chip->priv;
return in_be32(prv->regs + reg);
}
/* Write NFC register */
static inline void nfc_write(struct mtd_info *mtd, uint reg, u32 val)
{
struct nand_chip *chip = mtd->priv;
struct fsl_nfc_prv *prv = chip->priv;
out_be32(prv->regs + reg, val);
}
/* Set bits in NFC register */
static inline void nfc_set(struct mtd_info *mtd, uint reg, u32 bits)
{
nfc_write(mtd, reg, nfc_read(mtd, reg) | bits);
}
/* Clear bits in NFC register */
static inline void nfc_clear(struct mtd_info *mtd, uint reg, u32 bits)
{
nfc_write(mtd, reg, nfc_read(mtd, reg) & ~bits);
}
static inline void
nfc_set_field(struct mtd_info *mtd, u32 reg, u32 mask, u32 shift, u32 val)
{
struct nand_chip *chip = mtd->priv;
struct fsl_nfc_prv *prv = chip->priv;
out_be32(prv->regs + reg,
(in_be32(prv->regs + reg) & (~mask))
| val << shift);
}
static inline int
nfc_get_field(struct mtd_info *mtd, u32 reg, u32 field_mask)
{
struct nand_chip *chip = mtd->priv;
struct fsl_nfc_prv *prv = chip->priv;
return in_be32(prv->regs + reg) & field_mask;
}
static inline u8 nfc_check_status(struct mtd_info *mtd)
{
u8 fls_status = 0;
fls_status = nfc_get_field(mtd, NFC_FLASH_STATUS2, STATUS_BYTE1_MASK);
return fls_status;
}
/* clear cmd_done and cmd_idle falg for the coming command */
static void fsl_nfc_clear(struct mtd_info *mtd)
{
nfc_write(mtd, NFC_IRQ_STATUS, 1 << CMD_DONE_CLEAR_SHIFT);
nfc_write(mtd, NFC_IRQ_STATUS, 1 << IDLE_CLEAR_SHIFT);
}
/* Wait for operation complete */
static void fsl_nfc_done(struct mtd_info *mtd)
{
struct nand_chip *chip = mtd->priv;
struct fsl_nfc_prv *prv = chip->priv;
uint start = 0;
nfc_set_field(mtd, NFC_FLASH_CMD2, START_MASK,
START_SHIFT, 1);
start = get_timer(0);
while (!nfc_get_field(mtd, NFC_IRQ_STATUS, CMD_DONE_IRQ_MASK)) {
if (get_timer(start) > NFC_TIMEOUT) {
printf("Timeout while waiting for BUSY.\n");
}
}
fsl_nfc_clear(mtd);
}
static u8 fsl_nfc_get_id(struct mtd_info *mtd, int col)
{
u32 flash_id1 = 0;
u8 *pid;
flash_id1 = nfc_read(mtd, NFC_FLASH_STATUS1);
pid = (u8 *)&flash_id1;
return *(pid + col);
}
static inline u8 fsl_nfc_get_status(struct mtd_info *mtd)
{
u32 flash_status = 0;
u8 *pstatus;
flash_status = nfc_read(mtd, NFC_FLASH_STATUS2);
pstatus = (u8 *)&flash_status;
return *(pstatus + 3);
}
/* Invoke command cycle */
static inline void
fsl_nfc_send_cmd(struct mtd_info *mtd, u32 cmd_byte1,
u32 cmd_byte2, u32 cmd_code)
{
fsl_nfc_clear(mtd);
nfc_set_field(mtd, NFC_FLASH_CMD2, CMD_BYTE1_MASK,
CMD_BYTE1_SHIFT, cmd_byte1);
nfc_set_field(mtd, NFC_FLASH_CMD1, CMD_BYTE2_MASK,
CMD_BYTE2_SHIFT, cmd_byte2);
nfc_set_field(mtd, NFC_FLASH_CMD2, BUFNO_MASK,
BUFNO_SHIFT, 0);
nfc_set_field(mtd, NFC_FLASH_CMD2, CMD_CODE_MASK,
CMD_CODE_SHIFT, cmd_code);
if (cmd_code == RANDOM_OUT_CMD_CODE)
nfc_set_field(mtd, NFC_FLASH_CMD2, BUFNO_MASK,
BUFNO_SHIFT, 1);
}
/* Receive ID and status from NAND flash */
static inline void
fsl_nfc_send_one_byte(struct mtd_info *mtd, u32 cmd_byte1, u32 cmd_code)
{
fsl_nfc_clear(mtd);
nfc_set_field(mtd, NFC_FLASH_CMD2, CMD_BYTE1_MASK,
CMD_BYTE1_SHIFT, cmd_byte1);
nfc_set_field(mtd, NFC_FLASH_CMD2, BUFNO_MASK,
BUFNO_SHIFT, 0);
nfc_set_field(mtd, NFC_FLASH_CMD2, CMD_CODE_MASK,
CMD_CODE_SHIFT, cmd_code);
}
/* Do address cycle(s) */
static void
fsl_nfc_addr_cycle(struct mtd_info *mtd, int column, int page)
{
if (column != -1) {
nfc_set_field(mtd, NFC_COL_ADDR,
COL_ADDR_MASK,
COL_ADDR_SHIFT, column);
}
if (page != -1) {
nfc_set_field(mtd, NFC_ROW_ADDR,
ROW_ADDR_MASK,
ROW_ADDR_SHIFT, page);
}
/* DMA Disable */
nfc_clear(mtd, NFC_FLASH_CONFIG, CONFIG_DMA_REQ_MASK);
/* PAGE_CNT = 1 */
nfc_set_field(mtd, NFC_FLASH_CONFIG, CONFIG_PAGE_CNT_MASK,
CONFIG_PAGE_CNT_SHIFT, 0x1);
}
/* Control chips select signal on m54418twr board */
static void
m54418twr_select_chip(struct mtd_info *mtd, int chip)
{
volatile gpio_t *gpio = (gpio_t *) MMAP_GPIO;
if (chip < 0) {
gpio->par_fbctl &= (GPIO_PAR_FBCTL_ALE_MASK &
GPIO_PAR_FBCTL_TA_MASK);
gpio->par_fbctl |= GPIO_PAR_FBCTL_ALE_FB_TS |
GPIO_PAR_FBCTL_TA_TA;
gpio->par_be =
GPIO_PAR_BE_BE3_BE3 | GPIO_PAR_BE_BE2_BE2 |
GPIO_PAR_BE_BE1_BE1 | GPIO_PAR_BE_BE0_BE0;
gpio->par_cs &= ~GPIO_PAR_CS_CS1_NFC_CE;
gpio->par_cs = GPIO_PAR_CS_CS0_CS0;
return;
}
gpio->par_fbctl &= (GPIO_PAR_FBCTL_ALE_MASK & GPIO_PAR_FBCTL_TA_MASK);
gpio->par_fbctl |= GPIO_PAR_FBCTL_ALE_FB_ALE |
GPIO_PAR_FBCTL_TA_NFC_RB;
gpio->par_be =
GPIO_PAR_BE_BE3_FB_A1 | GPIO_PAR_BE_BE2_FB_A0 |
GPIO_PAR_BE_BE1_BE1 | GPIO_PAR_BE_BE0_BE0;
gpio->par_cs &= (GPIO_PAR_BE_BE3_MASK & GPIO_PAR_BE_BE2_MASK);
gpio->par_cs = GPIO_PAR_CS_CS1_NFC_CE;
}
void board_nand_select_device(struct nand_chip *nand, int chip)
{
fsl_nfc_chip = chip;
}
/* Read NAND Ready/Busy signal */
static int
fsl_nfc_dev_ready(struct mtd_info *mtd)
{
/*
* NFC handles ready/busy signal internally. Therefore, this function
* always returns status as ready.
*/
return 1;
}
/* Write command to NAND flash */
static void
fsl_nfc_command(struct mtd_info *mtd, unsigned command,
int column, int page)
{
struct nand_chip *chip = mtd->priv;
struct fsl_nfc_prv *prv = chip->priv;
prv->column = (column >= 0) ? column : 0;
prv->spareonly = 0;
get_id = 0;
get_status = 0;
switch (command) {
case NAND_CMD_PAGEPROG:
fsl_nfc_send_cmd(mtd,
PROGRAM_PAGE_CMD_BYTE1,
PROGRAM_PAGE_CMD_BYTE2,
PROGRAM_PAGE_CMD_CODE);
break;
/*
* NFC does not support sub-page reads and writes,
* so emulate them using full page transfers.
*/
case NAND_CMD_READ0:
column = 0;
goto read0;
break;
case NAND_CMD_READ1:
prv->column += 256;
command = NAND_CMD_READ0;
column = 0;
goto read0;
break;
case NAND_CMD_READOOB:
prv->spareonly = 1;
command = NAND_CMD_READ0;
column = 0;
read0:
fsl_nfc_send_cmd(mtd,
PAGE_READ_CMD_BYTE1,
PAGE_READ_CMD_BYTE2,
READ_PAGE_CMD_CODE);
break;
case NAND_CMD_SEQIN:
fsl_nfc_command(mtd, NAND_CMD_READ0, column, page);
column = 0;
break;
case NAND_CMD_ERASE1:
fsl_nfc_send_cmd(mtd,
ERASE_CMD_BYTE1,
ERASE_CMD_BYTE2,
ERASE_CMD_CODE);
break;
case NAND_CMD_ERASE2:
return;
case NAND_CMD_READID:
get_id = 1;
fsl_nfc_send_one_byte(mtd, command, READ_ID_CMD_CODE);
break;
case NAND_CMD_STATUS:
get_status = 1;
fsl_nfc_send_one_byte(mtd, command, STATUS_READ_CMD_CODE);
break;
case NAND_CMD_RNDOUT:
fsl_nfc_send_cmd(mtd,
RANDOM_OUT_CMD_BYTE1,
RANDOM_OUT_CMD_BYTE2,
RANDOM_OUT_CMD_CODE);
break;
case NAND_CMD_RESET:
fsl_nfc_send_one_byte(mtd, command, RESET_CMD_CODE);
break;
default:
return;
}
fsl_nfc_addr_cycle(mtd, column, page);
fsl_nfc_done(mtd);
}
/* Copy data from/to NFC spare buffers. */
static void
fsl_nfc_copy_spare(struct mtd_info *mtd, uint offset,
u8 *buffer, uint size, int wr)
{
struct nand_chip *nand = mtd->priv;
struct fsl_nfc_prv *prv = nand->priv;
uint o, s, sbsize, blksize;
/*
* NAND spare area is available through NFC spare buffers.
* The NFC divides spare area into (page_size / 512) chunks.
* Each chunk is placed into separate spare memory area, using
* first (spare_size / num_of_chunks) bytes of the buffer.
*
* For NAND device in which the spare area is not divided fully
* by the number of chunks, number of used bytes in each spare
* buffer is rounded down to the nearest even number of bytes,
* and all remaining bytes are added to the last used spare area.
*
* For more information read section 26.6.10 of MPC5121e
* Microcontroller Reference Manual, Rev. 3.
*/
/* Calculate number of valid bytes in each spare buffer */
/* sbsize = (mtd->oobsize / (mtd->writesize / 512)) & ~1;*/
sbsize = (mtd->oobsize / (mtd->writesize / 2048)) & ~1;
while (size) {
/* Calculate spare buffer number */
s = offset / sbsize;
if (s > NFC_SPARE_BUFFERS - 1)
s = NFC_SPARE_BUFFERS - 1;
/*
* Calculate offset to requested data block in selected spare
* buffer and its size.
*/
o = offset - (s * sbsize);
blksize = min(sbsize - o, size);
if (wr)
memcpy(prv->regs + NFC_SPARE_AREA(s) + o,
buffer, blksize);
else {
memcpy(buffer,
prv->regs + NFC_SPARE_AREA(s) + o, blksize);
}
buffer += blksize;
offset += blksize;
size -= blksize;
};
}
/* Copy data from/to NFC main and spare buffers */
static void
fsl_nfc_buf_copy(struct mtd_info *mtd, u_char *buf, int len, int wr)
{
struct nand_chip *chip = mtd->priv;
struct fsl_nfc_prv *prv = chip->priv;
uint c = prv->column;
uint l;
/* Handle spare area access */
if (prv->spareonly || c >= mtd->writesize) {
/* Calculate offset from beginning of spare area */
if (c >= mtd->writesize)
c -= mtd->writesize;
prv->column += len;
fsl_nfc_copy_spare(mtd, c, buf, len, wr);
return;
}
/*
* Handle main area access - limit copy length to prevent
* crossing main/spare boundary.
*/
l = min((uint)len, mtd->writesize - c);
prv->column += l;
if (wr)
memcpy(prv->regs + NFC_MAIN_AREA(0) + c, buf, l);
else {
if (get_status) {
get_status = 0;
*buf = fsl_nfc_get_status(mtd);
} else if (l == 1 && c <= 3 && get_id) {
*buf = fsl_nfc_get_id(mtd, c);
} else
memcpy(buf, prv->regs + NFC_MAIN_AREA(0) + c, l);
}
/* Handle crossing main/spare boundary */
if (l != len) {
buf += l;
len -= l;
fsl_nfc_buf_copy(mtd, buf, len, wr);
}
}
/* Read data from NFC buffers */
static void
fsl_nfc_read_buf(struct mtd_info *mtd, u_char *buf, int len)
{
fsl_nfc_buf_copy(mtd, buf, len, 0);
}
/* Write data to NFC buffers */
static void
fsl_nfc_write_buf(struct mtd_info *mtd, const u_char *buf, int len)
{
fsl_nfc_buf_copy(mtd, (u_char *)buf, len, 1);
}
/* Compare buffer with NAND flash */
static int
fsl_nfc_verify_buf(struct mtd_info *mtd, const u_char *buf, int len)
{
u_char tmp[256];
uint bsize;
while (len) {
bsize = min(len, 256);
fsl_nfc_read_buf(mtd, tmp, bsize);
if (memcmp(buf, tmp, bsize))
return 1;
buf += bsize;
len -= bsize;
}
return 0;
}
/* Read byte from NFC buffers */
static u8
fsl_nfc_read_byte(struct mtd_info *mtd)
{
u8 tmp;
fsl_nfc_read_buf(mtd, &tmp, sizeof(tmp));
return tmp;
}
/* Read word from NFC buffers */
static u16
fsl_nfc_read_word(struct mtd_info *mtd)
{
u16 tmp;
fsl_nfc_read_buf(mtd, (u_char *)&tmp, sizeof(tmp));
return tmp;
}
static void fsl_nfc_check_ecc_status(struct mtd_info *mtd)
{
struct nand_chip *chip = mtd->priv;
struct fsl_nfc_prv *prv = chip->priv;
u8 ecc_status, ecc_count;
ecc_status = *(u8 *)(prv->regs + ECC_SRAM_ADDR * 8 + 7);
ecc_count = ecc_status & ECC_ERR_COUNT;
if (ecc_status & ECC_STATUS_MASK) {
/*mtd->ecc_stats.failed++;*/
printf("ECC failed to correct all errors!\n");
} else if (ecc_count) {
/*mtd->ecc_stats.corrected += ecc_count;*/
printf("ECC corrected %d errors\n", ecc_count);
}
}
static void
copy_from_to_spare(struct mtd_info *mtd, void *pbuf, int len, int wr)
{
struct nand_chip *chip = mtd->priv;
struct fsl_nfc_prv *prv = chip->priv;
int i = 0, copy_count, copy_size;
/* copy_count = mtd->writesize / 512;*/
copy_count = mtd->writesize / 2048;
/*
* Each spare area has 16 bytes for 512, 2K and normal 4K nand.
* For 4K nand with large 218 byte spare size, the size is 26 bytes for
* the first 7 buffers and 36 for the last.
*/
/* copy_size = mtd->oobsize == 218 ? 26 : 16;*/
copy_size = 64;
/*
* Each spare area has 16 bytes for 512, 2K and normal 4K nand.
* For 4K nand with large 218 byte spare size, the size is 26
* bytes for the first 7 buffers and 36 for the last.
*/
for (i = 0; i < copy_count - 1 && len > 0; i++) {
if (wr)
memcpy(prv->regs + NFC_SPARE_AREA(i),
pbuf, MIN(len, copy_size));
else
memcpy(pbuf, prv->regs + NFC_SPARE_AREA(i),
MIN(len, copy_size));
pbuf += copy_size;
len -= copy_size;
}
if (len > 0) {
if (wr)