Commit 07a05972 authored by David Brownell's avatar David Brownell Committed by Kevin Hilman

davinci_nand: chipselects, we got your chipselects

Support various flavors of chipselect:

 - EMIF chipselects, controlled by platform_device.id;
   now uses a spinlock for NANDFCR mutual exclusion.

 - NAND packages with multiple chipselects, with a new
   platform data field; use that for the dm355 EVM.

The EMIF CS support is only sanity tested; needs more, on a
board using NAND and HWECC on a nonzero chipselect.

Update the "no NAND chip" message so it doesn't presume a hack
specific to the dm6446evm:  "boot via NOR, then swap CS0 jumper";
and use the errno returned from nand_scan.

Plus minor tweaks:  rename 1-bit ECC procedures to match current
method names, not old 2.6.10 ones; and include marker comments
between driver sections.
Signed-off-by: default avatarDavid Brownell <dbrownell@users.sourceforge.net>
parent 2acdf27b
...@@ -79,6 +79,7 @@ struct mtd_partition davinci_nand_partitions[] = { ...@@ -79,6 +79,7 @@ struct mtd_partition davinci_nand_partitions[] = {
}; };
static struct davinci_nand_pdata davinci_nand_data = { static struct davinci_nand_pdata davinci_nand_data = {
.mask_chipsel = BIT(14),
.parts = davinci_nand_partitions, .parts = davinci_nand_partitions,
.nr_parts = ARRAY_SIZE(davinci_nand_partitions), .nr_parts = ARRAY_SIZE(davinci_nand_partitions),
.ecc_mode = NAND_ECC_HW_SYNDROME, .ecc_mode = NAND_ECC_HW_SYNDROME,
......
...@@ -61,6 +61,9 @@ struct davinci_nand_pdata { /* platform_data */ ...@@ -61,6 +61,9 @@ struct davinci_nand_pdata { /* platform_data */
u32 mask_ale; u32 mask_ale;
u32 mask_cle; u32 mask_cle;
/* for packages using two chipselects */
u32 mask_chipsel;
/* board's default static partition info */ /* board's default static partition info */
struct mtd_partition *parts; struct mtd_partition *parts;
unsigned nr_parts; unsigned nr_parts;
......
...@@ -31,13 +31,8 @@ ...@@ -31,13 +31,8 @@
* (small page NAND). It should work for some other DaVinci NAND * (small page NAND). It should work for some other DaVinci NAND
* configurations, but it ignores the dm355 4-bit ECC hardware. * configurations, but it ignores the dm355 4-bit ECC hardware.
* *
* Currently makes assumptions about how the NAND device(s) are wired: * Currently assumes EM_WAIT connects all of the NAND devices in
* - connected on the first chipselect, controlled by A1CR * a "wire-OR" configuration.
* - single NAND chip
* - EM_WAIT is connected to the NAND device, not another device
*
* Modifications:
* ver. 1.0: Feb 2005, Vinod/Sudhakar
*/ */
#include <linux/kernel.h> #include <linux/kernel.h>
...@@ -47,6 +42,7 @@ ...@@ -47,6 +42,7 @@
#include <linux/err.h> #include <linux/err.h>
#include <linux/clk.h> #include <linux/clk.h>
#include <linux/io.h> #include <linux/io.h>
#include <linux/spinlock.h>
#include <linux/mtd/mtd.h> #include <linux/mtd/mtd.h>
#include <linux/mtd/nand.h> #include <linux/mtd/nand.h>
#include <linux/mtd/partitions.h> #include <linux/mtd/partitions.h>
...@@ -85,11 +81,16 @@ struct davinci_nand_info { ...@@ -85,11 +81,16 @@ struct davinci_nand_info {
void __iomem *vaddr; void __iomem *vaddr;
u32 ioaddr; u32 ioaddr;
u32 current_cs;
u32 mask_chipsel;
u32 mask_ale; u32 mask_ale;
u32 mask_cle; u32 mask_cle;
u32 core_chipsel;
}; };
#define NAND_CHIPSEL 0 static DEFINE_SPINLOCK(davinci_nand_lock);
#define to_davinci_nand(m) container_of(m, struct davinci_nand_info, mtd) #define to_davinci_nand(m) container_of(m, struct davinci_nand_info, mtd)
...@@ -115,7 +116,7 @@ static void nand_davinci_hwcontrol(struct mtd_info *mtd, int cmd, ...@@ -115,7 +116,7 @@ static void nand_davinci_hwcontrol(struct mtd_info *mtd, int cmd,
unsigned int ctrl) unsigned int ctrl)
{ {
struct davinci_nand_info *info = to_davinci_nand(mtd); struct davinci_nand_info *info = to_davinci_nand(mtd);
u32 addr = info->ioaddr; u32 addr = info->current_cs;
struct nand_chip *nand = mtd->priv; struct nand_chip *nand = mtd->priv;
/* Did the control lines change? */ /* Did the control lines change? */
...@@ -134,23 +135,44 @@ static void nand_davinci_hwcontrol(struct mtd_info *mtd, int cmd, ...@@ -134,23 +135,44 @@ static void nand_davinci_hwcontrol(struct mtd_info *mtd, int cmd,
static void nand_davinci_select_chip(struct mtd_info *mtd, int chip) static void nand_davinci_select_chip(struct mtd_info *mtd, int chip)
{ {
/* do nothing */ struct davinci_nand_info *info = to_davinci_nand(mtd);
u32 addr = info->ioaddr;
/* maybe kick in a second chipselect */
if (chip > 0)
addr |= info->mask_chipsel;
info->current_cs = addr;
info->chip.IO_ADDR_W = (void __iomem __force *)addr;
info->chip.IO_ADDR_R = info->chip.IO_ADDR_W;
} }
static void nand_davinci_enable_hwecc_1bit(struct mtd_info *mtd, int mode) /*----------------------------------------------------------------------*/
/*
* 1-bit hardware ECC ... context maintained for each core chipselect
*/
static void nand_davinci_hwctl_1bit(struct mtd_info *mtd, int mode)
{ {
struct davinci_nand_info *info; struct davinci_nand_info *info;
u32 retval; u32 retval;
unsigned long flags;
info = to_davinci_nand(mtd); info = to_davinci_nand(mtd);
/* Reset ECC hardware */ /* Reset ECC hardware */
retval = davinci_nand_readl(info, NANDF1ECC_OFFSET); retval = davinci_nand_readl(info, NANDF1ECC_OFFSET
+ 4 * info->core_chipsel);
spin_lock_irqsave(&davinci_nand_lock, flags);
/* Restart ECC hardware */ /* Restart ECC hardware */
retval = davinci_nand_readl(info, NANDFCR_OFFSET); retval = davinci_nand_readl(info, NANDFCR_OFFSET);
retval |= BIT(8); retval |= BIT(8 + info->core_chipsel);
davinci_nand_writel(info, NANDFCR_OFFSET, retval); davinci_nand_writel(info, NANDFCR_OFFSET, retval);
spin_unlock_irqrestore(&davinci_nand_lock, flags);
} }
/* /*
...@@ -167,7 +189,7 @@ static inline u32 nand_davinci_readecc_1bit(struct mtd_info *mtd) ...@@ -167,7 +189,7 @@ static inline u32 nand_davinci_readecc_1bit(struct mtd_info *mtd)
/* /*
* Read DaVinci ECC registers and rework into MTD format * Read DaVinci ECC registers and rework into MTD format
*/ */
static int nand_davinci_calculate_ecc_1bit(struct mtd_info *mtd, static int nand_davinci_calculate_1bit(struct mtd_info *mtd,
const u_char *dat, u_char *ecc_code) const u_char *dat, u_char *ecc_code)
{ {
unsigned int ecc_val = nand_davinci_readecc_1bit(mtd); unsigned int ecc_val = nand_davinci_readecc_1bit(mtd);
...@@ -182,7 +204,7 @@ static int nand_davinci_calculate_ecc_1bit(struct mtd_info *mtd, ...@@ -182,7 +204,7 @@ static int nand_davinci_calculate_ecc_1bit(struct mtd_info *mtd,
return 0; return 0;
} }
static int nand_davinci_correct_data_1bit(struct mtd_info *mtd, u_char *dat, static int nand_davinci_correct_1bit(struct mtd_info *mtd, u_char *dat,
u_char *read_ecc, u_char *calc_ecc) u_char *read_ecc, u_char *calc_ecc)
{ {
struct nand_chip *chip = mtd->priv; struct nand_chip *chip = mtd->priv;
...@@ -214,6 +236,8 @@ static int nand_davinci_correct_data_1bit(struct mtd_info *mtd, u_char *dat, ...@@ -214,6 +236,8 @@ static int nand_davinci_correct_data_1bit(struct mtd_info *mtd, u_char *dat,
return 0; return 0;
} }
/*----------------------------------------------------------------------*/
/* /*
* NOTE: NAND boot requires ALE == EM_A[1], CLE == EM_A[2], so that's * NOTE: NAND boot requires ALE == EM_A[1], CLE == EM_A[2], so that's
* how these chips are normally wired. This translates to both 8 and 16 * how these chips are normally wired. This translates to both 8 and 16
...@@ -341,6 +365,8 @@ static void __init nand_dm6446evm_flash_init(struct davinci_nand_info *info) ...@@ -341,6 +365,8 @@ static void __init nand_dm6446evm_flash_init(struct davinci_nand_info *info)
} }
} }
/*----------------------------------------------------------------------*/
static int __init nand_davinci_probe(struct platform_device *pdev) static int __init nand_davinci_probe(struct platform_device *pdev)
{ {
struct davinci_nand_pdata *pdata = pdev->dev.platform_data; struct davinci_nand_pdata *pdata = pdev->dev.platform_data;
...@@ -353,8 +379,8 @@ static int __init nand_davinci_probe(struct platform_device *pdev) ...@@ -353,8 +379,8 @@ static int __init nand_davinci_probe(struct platform_device *pdev)
u32 val; u32 val;
nand_ecc_modes_t ecc_mode; nand_ecc_modes_t ecc_mode;
/* only one chipselect is supported for now */ /* which external chipselect will we be managing? */
if (pdev->id != NAND_CHIPSEL) if (pdev->id < 0 || pdev->id > 3)
return -ENODEV; return -ENODEV;
info = kzalloc(sizeof(*info), GFP_KERNEL); info = kzalloc(sizeof(*info), GFP_KERNEL);
...@@ -401,6 +427,10 @@ static int __init nand_davinci_probe(struct platform_device *pdev) ...@@ -401,6 +427,10 @@ static int __init nand_davinci_probe(struct platform_device *pdev)
info->ioaddr = (u32 __force) vaddr; info->ioaddr = (u32 __force) vaddr;
info->current_cs = info->ioaddr;
info->core_chipsel = pdev->id;
info->mask_chipsel = pdata->mask_chipsel;
/* use nandboot-capable ALE/CLE masks by default */ /* use nandboot-capable ALE/CLE masks by default */
if (pdata && pdata->mask_ale) if (pdata && pdata->mask_ale)
info->mask_ale = pdata->mask_cle; info->mask_ale = pdata->mask_cle;
...@@ -441,9 +471,9 @@ static int __init nand_davinci_probe(struct platform_device *pdev) ...@@ -441,9 +471,9 @@ static int __init nand_davinci_probe(struct platform_device *pdev)
case NAND_ECC_SOFT: case NAND_ECC_SOFT:
break; break;
case NAND_ECC_HW: case NAND_ECC_HW:
info->chip.ecc.calculate = nand_davinci_calculate_ecc_1bit; info->chip.ecc.calculate = nand_davinci_calculate_1bit;
info->chip.ecc.correct = nand_davinci_correct_data_1bit; info->chip.ecc.correct = nand_davinci_correct_1bit;
info->chip.ecc.hwctl = nand_davinci_enable_hwecc_1bit; info->chip.ecc.hwctl = nand_davinci_hwctl_1bit;
info->chip.ecc.size = 512; info->chip.ecc.size = 512;
info->chip.ecc.bytes = 3; info->chip.ecc.bytes = 3;
break; break;
...@@ -479,15 +509,19 @@ static int __init nand_davinci_probe(struct platform_device *pdev) ...@@ -479,15 +509,19 @@ static int __init nand_davinci_probe(struct platform_device *pdev)
if (machine_is_davinci_evm()) if (machine_is_davinci_evm())
nand_dm6446evm_flash_init(info); nand_dm6446evm_flash_init(info);
/* put "CS2NAND" (CS0) into NAND mode */ spin_lock_irq(&davinci_nand_lock);
/* put CSxNAND into NAND mode */
val = davinci_nand_readl(info, NANDFCR_OFFSET); val = davinci_nand_readl(info, NANDFCR_OFFSET);
val |= BIT(0); val |= BIT(info->core_chipsel);
davinci_nand_writel(info, NANDFCR_OFFSET, val); davinci_nand_writel(info, NANDFCR_OFFSET, val);
/* Scan to find existence of the device */ spin_unlock_irq(&davinci_nand_lock);
if (nand_scan(&info->mtd, 1)) {
dev_err(&pdev->dev, "chip select is not set for 'NAND'\n"); /* Scan to find existence of the device(s) */
ret = -ENXIO; ret = nand_scan(&info->mtd, pdata->mask_chipsel ? 2 : 1);
if (ret < 0) {
dev_dbg(&pdev->dev, "no NAND chip(s) found\n");
goto err_scan; goto err_scan;
} }
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment