summaryrefslogtreecommitdiff
path: root/drivers/mtd/nand/s3c2410.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/mtd/nand/s3c2410.c')
-rw-r--r--drivers/mtd/nand/s3c2410.c459
1 files changed, 240 insertions, 219 deletions
diff --git a/drivers/mtd/nand/s3c2410.c b/drivers/mtd/nand/s3c2410.c
index 556139ed1fdf..e910b5f0d780 100644
--- a/drivers/mtd/nand/s3c2410.c
+++ b/drivers/mtd/nand/s3c2410.c
@@ -1,10 +1,26 @@
/* linux/drivers/mtd/nand/s3c2410.c
*
- * Copyright © 2004-2008 Simtec Electronics
- * http://armlinux.simtec.co.uk/
+ * Copyright (c) 2004,2005 Simtec Electronics
+ * http://www.simtec.co.uk/products/SWLINUX/
* Ben Dooks <ben@simtec.co.uk>
*
- * Samsung S3C2410/S3C2440/S3C2412 NAND driver
+ * Samsung S3C2410/S3C240 NAND driver
+ *
+ * Changelog:
+ * 21-Sep-2004 BJD Initial version
+ * 23-Sep-2004 BJD Multiple device support
+ * 28-Sep-2004 BJD Fixed ECC placement for Hardware mode
+ * 12-Oct-2004 BJD Fixed errors in use of platform data
+ * 18-Feb-2005 BJD Fix sparse errors
+ * 14-Mar-2005 BJD Applied tglx's code reduction patch
+ * 02-May-2005 BJD Fixed s3c2440 support
+ * 02-May-2005 BJD Reduced hwcontrol decode
+ * 20-Jun-2005 BJD Updated s3c2440 support, fixed timing bug
+ * 08-Jul-2005 BJD Fix OOPS when no platform data supplied
+ * 20-Oct-2005 BJD Fix timing calculation bug
+ * 14-Jan-2006 BJD Allow clock to be stopped when idle
+ *
+ * $Id: s3c2410.c,v 1.23 2006/04/01 18:06:29 bjd Exp $
*
* 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
@@ -19,11 +35,7 @@
* 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
-*/
-
-#ifdef CONFIG_MTD_NAND_S3C2410_DEBUG
-#define DEBUG
-#endif
+ */
#include <linux/module.h>
#include <linux/types.h>
@@ -36,7 +48,6 @@
#include <linux/err.h>
#include <linux/slab.h>
#include <linux/clk.h>
-#include <linux/cpufreq.h>
#include <linux/mtd/mtd.h>
#include <linux/mtd/nand.h>
@@ -48,6 +59,14 @@
#include <asm/plat-s3c/regs-nand.h>
#include <asm/plat-s3c/nand.h>
+/* Name of the kernel boot parameter with the partitions table */
+#define PARTITON_PARAMETER_NAME "onboard_boot"
+
+#if defined(CONFIG_MTD_NAND_S3C2410_DEBUG) && !defined(DEBUG)
+#define DEBUG
+#endif
+
+
#ifdef CONFIG_MTD_NAND_S3C2410_HWECC
static int hardware_ecc = 1;
#else
@@ -60,14 +79,34 @@ static int clock_stop = 1;
static const int clock_stop = 0;
#endif
-
-/* new oob placement block for use with hardware ecc generation
+/*
+ * These are the values that we are using in the U-Boot too.
+ * Luis Galdos
*/
-
static struct nand_ecclayout nand_hw_eccoob = {
- .eccbytes = 3,
- .eccpos = {0, 1, 2},
- .oobfree = {{8, 8}}
+ .eccbytes = 4,
+ .eccpos = { 40, 41, 42, 43 },
+ .oobfree = {
+ {
+ .offset = 2,
+ .length = 38
+ }
+ }
+};
+
+/*
+ * Nand flash oob definition for SLC 512b page size by jsgood
+ * IMPORTANT: These values are coming from the U-Boot
+ */
+static struct nand_ecclayout nand_hw_eccoob_16 = {
+ .eccbytes = 6,
+ .eccpos = { 0, 1, 2, 3, 6, 7 },
+ .oobfree = {
+ {
+ .offset = 8,
+ .length = 8
+ }
+ }
};
/* controller and mtd information */
@@ -105,13 +144,8 @@ struct s3c2410_nand_info {
int sel_bit;
int mtd_count;
unsigned long save_sel;
- unsigned long clk_rate;
enum s3c_cpu_type cpu_type;
-
-#ifdef CONFIG_CPU_FREQ
- struct notifier_block freq_transition;
-#endif
};
/* conversion functions */
@@ -169,18 +203,17 @@ static int s3c_nand_calc_rate(int wanted, unsigned long clk, int max)
/* controller setup */
-static int s3c2410_nand_setrate(struct s3c2410_nand_info *info)
+static int s3c2410_nand_inithw(struct s3c2410_nand_info *info,
+ struct platform_device *pdev)
{
- struct s3c2410_platform_nand *plat = info->platform;
+ struct s3c2410_platform_nand *plat = to_nand_plat(pdev);
+ unsigned long clkrate = clk_get_rate(info->clk);
int tacls_max = (info->cpu_type == TYPE_S3C2412) ? 8 : 4;
int tacls, twrph0, twrph1;
- unsigned long clkrate = clk_get_rate(info->clk);
- unsigned long set, cfg, mask;
- unsigned long flags;
+ unsigned long cfg = 0;
/* calculate the timing information for the controller */
- info->clk_rate = clkrate;
clkrate /= 1000; /* turn clock into kHz for ease of use */
if (plat != NULL) {
@@ -200,71 +233,39 @@ static int s3c2410_nand_setrate(struct s3c2410_nand_info *info)
}
dev_info(info->device, "Tacls=%d, %dns Twrph0=%d %dns, Twrph1=%d %dns\n",
- tacls, to_ns(tacls, clkrate), twrph0, to_ns(twrph0, clkrate), twrph1, to_ns(twrph1, clkrate));
-
- switch (info->cpu_type) {
- case TYPE_S3C2410:
- mask = (S3C2410_NFCONF_TACLS(3) |
- S3C2410_NFCONF_TWRPH0(7) |
- S3C2410_NFCONF_TWRPH1(7));
- set = S3C2410_NFCONF_EN;
- set |= S3C2410_NFCONF_TACLS(tacls - 1);
- set |= S3C2410_NFCONF_TWRPH0(twrph0 - 1);
- set |= S3C2410_NFCONF_TWRPH1(twrph1 - 1);
- break;
-
- case TYPE_S3C2440:
- case TYPE_S3C2412:
- mask = (S3C2410_NFCONF_TACLS(tacls_max - 1) |
- S3C2410_NFCONF_TWRPH0(7) |
- S3C2410_NFCONF_TWRPH1(7));
-
- set = S3C2440_NFCONF_TACLS(tacls - 1);
- set |= S3C2440_NFCONF_TWRPH0(twrph0 - 1);
- set |= S3C2440_NFCONF_TWRPH1(twrph1 - 1);
- break;
-
- default:
- /* keep compiler happy */
- mask = 0;
- set = 0;
- BUG();
- }
-
- dev_dbg(info->device, "NF_CONF is 0x%lx\n", cfg);
-
- local_irq_save(flags);
-
+ tacls, to_ns(tacls, clkrate), twrph0, to_ns(twrph0, clkrate), twrph1, to_ns(twrph1, clkrate));
+
+
+ /*
+ * First get the current value of the configuration register, otherwise
+ * some chip-information that is coming from the bootloader will be
+ * gone (e.g. the page size, which is required for the HWECC)
+ * Luis Galdos
+ */
cfg = readl(info->regs + S3C2410_NFCONF);
- cfg &= ~mask;
- cfg |= set;
- writel(cfg, info->regs + S3C2410_NFCONF);
-
- local_irq_restore(flags);
-
- return 0;
-}
-
-static int s3c2410_nand_inithw(struct s3c2410_nand_info *info)
-{
- int ret;
-
- ret = s3c2410_nand_setrate(info);
- if (ret < 0)
- return ret;
-
+
switch (info->cpu_type) {
case TYPE_S3C2410:
- default:
+ cfg |= S3C2410_NFCONF_EN;
+ cfg |= S3C2410_NFCONF_TACLS(tacls - 1);
+ cfg |= S3C2410_NFCONF_TWRPH0(twrph0 - 1);
+ cfg |= S3C2410_NFCONF_TWRPH1(twrph1 - 1);
break;
case TYPE_S3C2440:
case TYPE_S3C2412:
+ cfg |= S3C2440_NFCONF_TACLS(tacls - 1);
+ cfg |= S3C2440_NFCONF_TWRPH0(twrph0 - 1);
+ cfg |= S3C2440_NFCONF_TWRPH1(twrph1 - 1);
+
/* enable the controller and de-assert nFCE */
writel(S3C2440_NFCONT_ENABLE, info->regs + S3C2440_NFCONT);
}
+ dev_dbg(info->device, "NF_CONF is 0x%lx\n", cfg);
+
+ writel(cfg, info->regs + S3C2410_NFCONF);
return 0;
}
@@ -310,7 +311,7 @@ static void s3c2410_nand_select_chip(struct mtd_info *mtd, int chip)
/* s3c2410_nand_hwcontrol
*
* Issue command and address cycles to the chip
-*/
+ */
static void s3c2410_nand_hwcontrol(struct mtd_info *mtd, int cmd,
unsigned int ctrl)
@@ -345,7 +346,7 @@ static void s3c2440_nand_hwcontrol(struct mtd_info *mtd, int cmd,
/* s3c2410_nand_devready()
*
* returns 0 if the nand is busy, 1 if it is ready
-*/
+ */
static int s3c2410_nand_devready(struct mtd_info *mtd)
{
@@ -371,81 +372,80 @@ static int s3c2410_nand_correct_data(struct mtd_info *mtd, u_char *dat,
u_char *read_ecc, u_char *calc_ecc)
{
struct s3c2410_nand_info *info = s3c2410_nand_mtd_toinfo(mtd);
- unsigned int diff0, diff1, diff2;
- unsigned int bit, byte;
-
- pr_debug("%s(%p,%p,%p,%p)\n", __func__, mtd, dat, read_ecc, calc_ecc);
-
- diff0 = read_ecc[0] ^ calc_ecc[0];
- diff1 = read_ecc[1] ^ calc_ecc[1];
- diff2 = read_ecc[2] ^ calc_ecc[2];
-
- pr_debug("%s: rd %02x%02x%02x calc %02x%02x%02x diff %02x%02x%02x\n",
- __func__,
- read_ecc[0], read_ecc[1], read_ecc[2],
- calc_ecc[0], calc_ecc[1], calc_ecc[2],
- diff0, diff1, diff2);
-
- if (diff0 == 0 && diff1 == 0 && diff2 == 0)
- return 0; /* ECC is ok */
-
+ unsigned long nfmeccdata0, nfmeccdata1;
+ unsigned long nfestat0;
+ unsigned char err_type;
+ int retval;
+ unsigned int offset;
+ unsigned char wrong_value, corr_value;
+ struct s3c2410_nand_mtd *nmtd = s3c2410_nand_mtd_toours(mtd);
+ struct nand_chip *chip = &nmtd->chip;
+
+ pr_debug("%s: read %02x%02x%02x%02x calc %02x%02x%02x%02x\n", __func__,
+ read_ecc[0], read_ecc[1], read_ecc[2], read_ecc[3],
+ calc_ecc[0], calc_ecc[1], calc_ecc[2], calc_ecc[3]);
+
/* sometimes people do not think about using the ECC, so check
* to see if we have an 0xff,0xff,0xff read ECC and then ignore
* the error, on the assumption that this is an un-eccd page.
*/
if (read_ecc[0] == 0xff && read_ecc[1] == 0xff && read_ecc[2] == 0xff
- && info->platform->ignore_unset_ecc)
+ && read_ecc[3] == 0xff && info->platform->ignore_unset_ecc) {
+ pr_debug("Ignoring the HWECC calculation?\n");
return 0;
-
- /* Can we correct this ECC (ie, one row and column change).
- * Note, this is similar to the 256 error code on smartmedia */
-
- if (((diff0 ^ (diff0 >> 1)) & 0x55) == 0x55 &&
- ((diff1 ^ (diff1 >> 1)) & 0x55) == 0x55 &&
- ((diff2 ^ (diff2 >> 1)) & 0x55) == 0x55) {
- /* calculate the bit position of the error */
-
- bit = ((diff2 >> 3) & 1) |
- ((diff2 >> 4) & 2) |
- ((diff2 >> 5) & 4);
-
- /* calculate the byte position of the error */
-
- byte = ((diff2 << 7) & 0x100) |
- ((diff1 << 0) & 0x80) |
- ((diff1 << 1) & 0x40) |
- ((diff1 << 2) & 0x20) |
- ((diff1 << 3) & 0x10) |
- ((diff0 >> 4) & 0x08) |
- ((diff0 >> 3) & 0x04) |
- ((diff0 >> 2) & 0x02) |
- ((diff0 >> 1) & 0x01);
-
- dev_dbg(info->device, "correcting error bit %d, byte %d\n",
- bit, byte);
-
- dat[byte] ^= (1 << bit);
- return 1;
}
- /* if there is only one bit difference in the ECC, then
- * one of only a row or column parity has changed, which
- * means the error is most probably in the ECC itself */
-
- diff0 |= (diff1 << 8);
- diff0 |= (diff2 << 16);
-
- if ((diff0 & ~(1<<fls(diff0))) == 0)
- return 1;
-
- return -1;
+ /*
+ * If the chip has a small page then set the fourth byte to 0xff, so that
+ * we can use the NAND-controller to check if the ECC is correct or not.
+ * Please note that this "workaround" is coming from the U-Boot, which has
+ * an ECC-layout with only three ECC-bytes (but why?).
+ * (Luis Galdos)
+ */
+ if (chip->page_shift <= 10) {
+ pr_debug("Setting the fourth byte to 0xff\n");
+ read_ecc[3] = 0xff;
+ }
+
+ /*
+ * The below code is coming from the driver 's3c_nand.c' (by jsgood)
+ * Luis Galdos
+ */
+ nfmeccdata0 = (read_ecc[1] << 16) | read_ecc[0];
+ nfmeccdata1 = (read_ecc[3] << 16) | read_ecc[2];
+ writel(nfmeccdata0, info->regs + S3C2440_NFECCD0);
+ writel(nfmeccdata1, info->regs + S3C2440_NFECCD1);
+ nfestat0 = readl(info->regs + S3C2412_NFMECC_ERR0);
+ err_type = nfestat0 & 0x3;
+
+ switch (err_type) {
+ case 0:
+ retval = 0;
+ break;
+ case 1:
+ offset = (nfestat0 >> 7) & 0x7ff;
+ wrong_value = dat[offset];
+ corr_value = wrong_value ^ (1 << ((nfestat0 >> 4) & 0x7));
+ printk(KERN_DEBUG "[NAND BitErr]: 1 bit error detected at page byte %u. Correcting from 0x%02x to 0x%02x\n",
+ offset, wrong_value, corr_value);
+ dat[offset] = corr_value;
+ retval = 1;
+ break;
+ default:
+ printk(KERN_ERR "[NAND BitErr]: More than 1 bit error detected. Uncorrectable error.\n");
+ retval = -1;
+ break;
+ }
+
+ return retval;
}
+
/* ECC functions
*
* These allow the s3c2410 and s3c2440 to use the controller's ECC
* generator block to ECC the data as it passes through]
-*/
+ */
static void s3c2410_nand_enable_hwecc(struct mtd_info *mtd, int mode)
{
@@ -462,8 +462,21 @@ static void s3c2412_nand_enable_hwecc(struct mtd_info *mtd, int mode)
struct s3c2410_nand_info *info = s3c2410_nand_mtd_toinfo(mtd);
unsigned long ctrl;
+ /*
+ * According to the manual: unlock the main area and set the data transfer
+ * direction (read or write) too
+ * Luis Galdos
+ */
ctrl = readl(info->regs + S3C2440_NFCONT);
- writel(ctrl | S3C2412_NFCONT_INIT_MAIN_ECC, info->regs + S3C2440_NFCONT);
+ ctrl |= S3C2412_NFCONT_INIT_MAIN_ECC;
+ ctrl &= ~S3C2412_NFCONT_MAIN_ECC_LOCK;
+
+ if (mode == NAND_ECC_WRITE)
+ ctrl |= S3C2412_NFCONT_ECC4_DIRWR;
+ else
+ ctrl &= ~S3C2412_NFCONT_ECC4_DIRWR;
+
+ writel(ctrl, info->regs + S3C2440_NFCONT);
}
static void s3c2440_nand_enable_hwecc(struct mtd_info *mtd, int mode)
@@ -492,13 +505,25 @@ static int s3c2410_nand_calculate_ecc(struct mtd_info *mtd, const u_char *dat, u
static int s3c2412_nand_calculate_ecc(struct mtd_info *mtd, const u_char *dat, u_char *ecc_code)
{
struct s3c2410_nand_info *info = s3c2410_nand_mtd_toinfo(mtd);
- unsigned long ecc = readl(info->regs + S3C2412_NFMECC0);
+ unsigned long ecc, nfcont;
+
+ /*
+ * According to the manual: lock the main area before reading from the ECC
+ * status register.
+ * Luis Galdos
+ */
+ nfcont = readl(info->regs + S3C2440_NFCONT);
+ nfcont |= S3C2412_NFCONT_MAIN_ECC_LOCK;
+ writel(nfcont, info->regs + S3C2440_NFCONT);
- ecc_code[0] = ecc;
- ecc_code[1] = ecc >> 8;
- ecc_code[2] = ecc >> 16;
+ ecc = readl(info->regs + S3C2412_NFMECC0);
+ ecc_code[0] = ecc & 0xff;
+ ecc_code[1] = (ecc >> 8) & 0xff;
+ ecc_code[2] = (ecc >> 16) & 0xff;
+ ecc_code[3] = (ecc >> 24) & 0xff;
- pr_debug("calculate_ecc: returning ecc %02x,%02x,%02x\n", ecc_code[0], ecc_code[1], ecc_code[2]);
+ pr_debug("calculate_ecc: returning ecc %02x,%02x,%02x,%02x\n",
+ ecc_code[0], ecc_code[1], ecc_code[2], ecc_code[3]);
return 0;
}
@@ -519,7 +544,7 @@ static int s3c2440_nand_calculate_ecc(struct mtd_info *mtd, const u_char *dat, u
/* over-ride the standard functions for a little more speed. We can
* use read/write block to move the data buffers to/from the controller
-*/
+ */
static void s3c2410_nand_read_buf(struct mtd_info *mtd, u_char *buf, int len)
{
@@ -545,52 +570,6 @@ static void s3c2440_nand_write_buf(struct mtd_info *mtd, const u_char *buf, int
writesl(info->regs + S3C2440_NFDATA, buf, len / 4);
}
-/* cpufreq driver support */
-
-#ifdef CONFIG_CPU_FREQ
-
-static int s3c2410_nand_cpufreq_transition(struct notifier_block *nb,
- unsigned long val, void *data)
-{
- struct s3c2410_nand_info *info;
- unsigned long newclk;
-
- info = container_of(nb, struct s3c2410_nand_info, freq_transition);
- newclk = clk_get_rate(info->clk);
-
- if ((val == CPUFREQ_POSTCHANGE && newclk < info->clk_rate) ||
- (val == CPUFREQ_PRECHANGE && newclk > info->clk_rate)) {
- s3c2410_nand_setrate(info);
- }
-
- return 0;
-}
-
-static inline int s3c2410_nand_cpufreq_register(struct s3c2410_nand_info *info)
-{
- info->freq_transition.notifier_call = s3c2410_nand_cpufreq_transition;
-
- return cpufreq_register_notifier(&info->freq_transition,
- CPUFREQ_TRANSITION_NOTIFIER);
-}
-
-static inline void s3c2410_nand_cpufreq_deregister(struct s3c2410_nand_info *info)
-{
- cpufreq_unregister_notifier(&info->freq_transition,
- CPUFREQ_TRANSITION_NOTIFIER);
-}
-
-#else
-static inline int s3c2410_nand_cpufreq_register(struct s3c2410_nand_info *info)
-{
- return 0;
-}
-
-static inline void s3c2410_nand_cpufreq_deregister(struct s3c2410_nand_info *info)
-{
-}
-#endif
-
/* device management functions */
static int s3c2410_nand_remove(struct platform_device *pdev)
@@ -602,10 +581,9 @@ static int s3c2410_nand_remove(struct platform_device *pdev)
if (info == NULL)
return 0;
- s3c2410_nand_cpufreq_deregister(info);
-
- /* Release all our mtds and their partitions, then go through
- * freeing the resources used
+ /* first thing we need to do is release all our mtds
+ * and their partitions, then go through freeing the
+ * resources used
*/
if (info->mtds != NULL) {
@@ -670,7 +648,7 @@ static int s3c2410_nand_add_partition(struct s3c2410_nand_info *info,
/* s3c2410_nand_init_chip
*
* init a single instance of an chip
-*/
+ */
static void s3c2410_nand_init_chip(struct s3c2410_nand_info *info,
struct s3c2410_nand_mtd *nmtd,
@@ -752,11 +730,14 @@ static void s3c2410_nand_init_chip(struct s3c2410_nand_info *info,
chip->ecc.mode = NAND_ECC_SOFT;
}
+ /* @FIXME: Here seems to be something wrong. (Luis Galdos) */
+#if 0
if (set->ecc_layout != NULL)
chip->ecc.layout = set->ecc_layout;
if (set->disable_ecc)
chip->ecc.mode = NAND_ECC_NONE;
+#endif
}
/* s3c2410_nand_update_chip
@@ -770,20 +751,26 @@ static void s3c2410_nand_update_chip(struct s3c2410_nand_info *info,
{
struct nand_chip *chip = &nmtd->chip;
- dev_dbg(info->device, "chip %p => page shift %d\n",
- chip, chip->page_shift);
+ printk("%s: chip %p: %d\n", __func__, chip, chip->page_shift);
if (hardware_ecc) {
/* change the behaviour depending on wether we are using
* the large or small page nand device */
if (chip->page_shift > 10) {
- chip->ecc.size = 256;
- chip->ecc.bytes = 3;
+ chip->ecc.size = 2048;
+ chip->ecc.bytes = 4;
+ chip->ecc.layout = &nand_hw_eccoob;
} else {
+ /*
+ * IMPORTANT: For using only three ECC-bytes is required to set
+ * the fourth byte to '0xff', otherwise we can't use the internal
+ * NAND-controller for checking if the ECC is correct or not.
+ * (Luis Galdos)
+ */
chip->ecc.size = 512;
chip->ecc.bytes = 3;
- chip->ecc.layout = &nand_hw_eccoob;
+ chip->ecc.layout = &nand_hw_eccoob_16;
}
}
}
@@ -794,7 +781,7 @@ static void s3c2410_nand_update_chip(struct s3c2410_nand_info *info,
* one our driver can handled. This code checks to see if
* it can allocate all necessary resources then calls the
* nand layer to look for devices
-*/
+ */
static int s3c24xx_nand_probe(struct platform_device *pdev,
enum s3c_cpu_type cpu_type)
@@ -809,6 +796,18 @@ static int s3c24xx_nand_probe(struct platform_device *pdev,
int nr_sets;
int setno;
+ /*
+ * Required variables for accessing to the partitions from the command line
+ * Luis Galdos
+ */
+#if defined(CONFIG_MTD_CMDLINE_PARTS)
+ struct mtd_partition *mtd_parts;
+ int nr_parts;
+ const char *name_back;
+ struct s3c2410_nand_set nand_sets[1];
+ const char *part_probes[] = { "cmdlinepart", NULL };
+#endif
+
pr_debug("s3c2410_nand_probe(%p)\n", pdev);
info = kmalloc(sizeof(*info), GFP_KERNEL);
@@ -864,7 +863,7 @@ static int s3c24xx_nand_probe(struct platform_device *pdev,
/* initialise the hardware */
- err = s3c2410_nand_inithw(info);
+ err = s3c2410_nand_inithw(info, pdev);
if (err != 0)
goto exit_error;
@@ -891,12 +890,33 @@ static int s3c24xx_nand_probe(struct platform_device *pdev,
for (setno = 0; setno < nr_sets; setno++, nmtd++) {
pr_debug("initialising set %d (%p, info %p)\n", setno, nmtd, info);
-
s3c2410_nand_init_chip(info, nmtd, sets);
-
nmtd->scan_res = nand_scan_ident(&nmtd->mtd,
(sets) ? sets->nr_chips : 1);
+ /*
+ * This is the code required for accessing to the partitions table
+ * passed by the bootloader
+ * (Luis Galdos)
+ */
+#if defined(CONFIG_MTD_CMDLINE_PARTS)
+ /*
+ * Need to reset the name of the MTD-device then the name of the
+ * partition passed by the U-Boot differs from the assigned name.
+ * U-Boot : onboard_boot
+ * Device : NAND 128MiB 3,3V 8-bit
+ */
+ name_back = nmtd->mtd.name;
+ nmtd->mtd.name= PARTITON_PARAMETER_NAME;
+ nr_parts = parse_mtd_partitions(&nmtd->mtd, part_probes, &mtd_parts, 0);
+ nmtd->mtd.name = name_back;
+ nand_sets[0].name = "NAND-Parts";
+ nand_sets[0].nr_chips = 1;
+ nand_sets[0].partitions = mtd_parts;
+ nand_sets[0].nr_partitions = nr_parts;
+ sets = nand_sets;
+#endif /* defined(CONFIG_MTD_CMDLINE_PARTS) */
+
if (nmtd->scan_res == 0) {
s3c2410_nand_update_chip(info, nmtd);
nand_scan_tail(&nmtd->mtd);
@@ -907,12 +927,6 @@ static int s3c24xx_nand_probe(struct platform_device *pdev,
sets++;
}
- err = s3c2410_nand_cpufreq_register(info);
- if (err < 0) {
- dev_err(&pdev->dev, "failed to init cpufreq support\n");
- goto exit_error;
- }
-
if (allow_clk_stop(info)) {
dev_info(&pdev->dev, "clock idle support enabled\n");
clk_disable(info->clk);
@@ -960,7 +974,7 @@ static int s3c24xx_nand_resume(struct platform_device *dev)
if (info) {
clk_enable(info->clk);
- s3c2410_nand_inithw(info);
+ s3c2410_nand_inithw(info, dev);
/* Restore the state of the nFCE line. */
@@ -1035,9 +1049,16 @@ static int __init s3c2410_nand_init(void)
{
printk("S3C24XX NAND Driver, (c) 2004 Simtec Electronics\n");
- platform_driver_register(&s3c2412_nand_driver);
- platform_driver_register(&s3c2440_nand_driver);
- return platform_driver_register(&s3c2410_nand_driver);
+ if (platform_driver_register(&s3c2440_nand_driver))
+ printk(KERN_ERR "Registering S3C2440 NAND driver\n");
+
+ if (platform_driver_register(&s3c2412_nand_driver))
+ printk(KERN_ERR "Registering S3C2412 NAND driver\n");
+
+ if (platform_driver_register(&s3c2410_nand_driver))
+ printk(KERN_ERR "Registering S3C2410 NAND driver\n");
+
+ return 0;
}
static void __exit s3c2410_nand_exit(void)