* Platform independend driver for NDFC (NanD Flash Controller)
* integrated into EP440 cores
*
- * (C) Copyright 2006
+ * (C) Copyright 2006-2007
* Stefan Roese, DENX Software Engineering, sr@denx.de.
*
* Based on original work by
#include <common.h>
-#if (CONFIG_COMMANDS & CFG_CMD_NAND) && !defined(CFG_NAND_LEGACY)
+#if defined(CONFIG_CMD_NAND) && !defined(CFG_NAND_LEGACY) && \
+ (defined(CONFIG_440EP) || defined(CONFIG_440GR) || \
+ defined(CONFIG_440EPX) || defined(CONFIG_440GRX) || \
+ defined(CONFIG_405EZ) || defined(CONFIG_405EX))
#include <nand.h>
#include <linux/mtd/ndfc.h>
+#include <linux/mtd/nand_ecc.h>
#include <asm/processor.h>
-#include <ppc440.h>
+#include <asm/io.h>
+#include <ppc4xx.h>
static u8 hwctl = 0;
static void ndfc_write_byte(struct mtd_info *mtdinfo, u_char byte)
{
- struct nand_chip *this = mtdinfo->priv;
- ulong base = (ulong) this->IO_ADDR_W;
+ struct nand_chip *this = mtdinfo->priv;
+ ulong base = (ulong) this->IO_ADDR_W & 0xfffffffc;
if (hwctl & 0x1)
- out8(base + NDFC_CMD, byte);
+ out_8((u8 *)(base + NDFC_CMD), byte);
else if (hwctl & 0x2)
- out8(base + NDFC_ALE, byte);
+ out_8((u8 *)(base + NDFC_ALE), byte);
else
- out8(base + NDFC_DATA, byte);
+ out_8((u8 *)(base + NDFC_DATA), byte);
}
static u_char ndfc_read_byte(struct mtd_info *mtdinfo)
{
- struct nand_chip *this = mtdinfo->priv;
- ulong base = (ulong) this->IO_ADDR_W;
+ struct nand_chip *this = mtdinfo->priv;
+ ulong base = (ulong) this->IO_ADDR_W & 0xfffffffc;
- return (in8(base + NDFC_DATA));
+ return (in_8((u8 *)(base + NDFC_DATA)));
}
static int ndfc_dev_ready(struct mtd_info *mtdinfo)
{
- struct nand_chip *this = mtdinfo->priv;
- ulong base = (ulong) this->IO_ADDR_W;
+ struct nand_chip *this = mtdinfo->priv;
+ ulong base = (ulong) this->IO_ADDR_W & 0xfffffffc;
- while (!(in32(base + NDFC_STAT) & NDFC_STAT_IS_READY))
+ while (!(in_be32((u32 *)(base + NDFC_STAT)) & NDFC_STAT_IS_READY))
;
return 1;
}
-#ifndef CONFIG_NAND_SPL
-/*
- * Don't use these speedup functions in NAND boot image, since the image
- * has to fit into 4kByte.
- */
+static void ndfc_enable_hwecc(struct mtd_info *mtdinfo, int mode)
+{
+ struct nand_chip *this = mtdinfo->priv;
+ ulong base = (ulong) this->IO_ADDR_W & 0xfffffffc;
+ u32 ccr;
+
+ ccr = in_be32((u32 *)(base + NDFC_CCR));
+ ccr |= NDFC_CCR_RESET_ECC;
+ out_be32((u32 *)(base + NDFC_CCR), ccr);
+}
+
+static int ndfc_calculate_ecc(struct mtd_info *mtdinfo,
+ const u_char *dat, u_char *ecc_code)
+{
+ struct nand_chip *this = mtdinfo->priv;
+ ulong base = (ulong) this->IO_ADDR_W & 0xfffffffc;
+ u32 ecc;
+ u8 *p = (u8 *)&ecc;
+
+ ecc = in_be32((u32 *)(base + NDFC_ECC));
+
+ /* The NDFC uses Smart Media (SMC) bytes order
+ */
+ ecc_code[0] = p[1];
+ ecc_code[1] = p[2];
+ ecc_code[2] = p[3];
+
+ return 0;
+}
/*
* Speedups for buffer read/write/verify
*/
static void ndfc_read_buf(struct mtd_info *mtdinfo, uint8_t *buf, int len)
{
- struct nand_chip *this = mtdinfo->priv;
- ulong base = (ulong) this->IO_ADDR_W;
+ struct nand_chip *this = mtdinfo->priv;
+ ulong base = (ulong) this->IO_ADDR_W & 0xfffffffc;
uint32_t *p = (uint32_t *) buf;
- for(;len > 0; len -= 4)
- *p++ = in32(base + NDFC_DATA);
+ for (;len > 0; len -= 4)
+ *p++ = in_be32((u32 *)(base + NDFC_DATA));
}
+#ifndef CONFIG_NAND_SPL
+/*
+ * Don't use these speedup functions in NAND boot image, since the image
+ * has to fit into 4kByte.
+ */
static void ndfc_write_buf(struct mtd_info *mtdinfo, const uint8_t *buf, int len)
{
- struct nand_chip *this = mtdinfo->priv;
- ulong base = (ulong) this->IO_ADDR_W;
+ struct nand_chip *this = mtdinfo->priv;
+ ulong base = (ulong) this->IO_ADDR_W & 0xfffffffc;
uint32_t *p = (uint32_t *) buf;
- for(; len > 0; len -= 4)
- out32(base + NDFC_DATA, *p++);
+ for (; len > 0; len -= 4)
+ out_be32((u32 *)(base + NDFC_DATA), *p++);
}
static int ndfc_verify_buf(struct mtd_info *mtdinfo, const uint8_t *buf, int len)
{
- struct nand_chip *this = mtdinfo->priv;
- ulong base = (ulong) this->IO_ADDR_W;
+ struct nand_chip *this = mtdinfo->priv;
+ ulong base = (ulong) this->IO_ADDR_W & 0xfffffffc;
uint32_t *p = (uint32_t *) buf;
- for(; len > 0; len -= 4)
- if (*p++ != in32(base + NDFC_DATA))
+ for (; len > 0; len -= 4)
+ if (*p++ != in_be32((u32 *)(base + NDFC_DATA)))
return -1;
return 0;
}
#endif /* #ifndef CONFIG_NAND_SPL */
-void board_nand_init(struct nand_chip *nand)
+void board_nand_select_device(struct nand_chip *nand, int chip)
+{
+ /*
+ * Don't use "chip" to address the NAND device,
+ * generate the cs from the address where it is encoded.
+ */
+ int cs = (ulong)nand->IO_ADDR_W & 0x00000003;
+ ulong base = (ulong)nand->IO_ADDR_W & 0xfffffffc;
+
+ /* Set NandFlash Core Configuration Register */
+ /* 1 col x 2 rows */
+ out_be32((u32 *)(base + NDFC_CCR), 0x00000000 | (cs << 24));
+}
+
+int board_nand_init(struct nand_chip *nand)
{
- nand->eccmode = NAND_ECC_SOFT;
+ int cs = (ulong)nand->IO_ADDR_W & 0x00000003;
+ ulong base = (ulong)nand->IO_ADDR_W & 0xfffffffc;
nand->hwcontrol = ndfc_hwcontrol;
nand->read_byte = ndfc_read_byte;
+ nand->read_buf = ndfc_read_buf;
nand->write_byte = ndfc_write_byte;
nand->dev_ready = ndfc_dev_ready;
+ nand->eccmode = NAND_ECC_HW3_256;
+ nand->enable_hwecc = ndfc_enable_hwecc;
+ nand->calculate_ecc = ndfc_calculate_ecc;
+ nand->correct_data = nand_correct_data;
+
#ifndef CONFIG_NAND_SPL
nand->write_buf = ndfc_write_buf;
- nand->read_buf = ndfc_read_buf;
nand->verify_buf = ndfc_verify_buf;
#else
/*
* Setup EBC (CS0 only right now)
*/
- mtdcr(ebccfga, xbcfg);
- mtdcr(ebccfgd, 0xb8400000);
+ mtebc(EBC0_CFG, 0xb8400000);
mtebc(pb0cr, CFG_EBC_PB0CR);
mtebc(pb0ap, CFG_EBC_PB0AP);
#endif
- /* Set NandFlash Core Configuration Register */
- /* Chip select 3, 1col x 2 rows */
- out32(CFG_NAND_BASE + NDFC_CCR, 0x00000000 | (CFG_NAND_CS << 24));
- out32(CFG_NAND_BASE + NDFC_BCFG0 + (CFG_NAND_CS << 2), 0x80002222);
+ /*
+ * Select required NAND chip in NDFC
+ */
+ board_nand_select_device(nand, cs);
+ out_be32((u32 *)(base + NDFC_BCFG0 + (cs << 2)), 0x80002222);
+
+ return 0;
}
#endif