linux-2.6.24: improve mpc8313e-rdb support
authorJeremy Laine <jeremy.laine@m4x.org>
Mon, 18 Feb 2008 16:33:18 +0000 (16:33 +0000)
committerJeremy Laine <jeremy.laine@m4x.org>
Mon, 18 Feb 2008 16:33:18 +0000 (16:33 +0000)
* apply patch for NAND controller
* modularise kernel some more to reduce kernel size

packages/linux/linux-2.6.24/mpc8313e-rdb/defconfig
packages/linux/linux-2.6.24/mpc8313e-rdb/mpc831x-nand.patch [new file with mode: 0644]
packages/linux/linux_2.6.24.bb

index 9c38570..b87f62a 100644 (file)
@@ -707,7 +707,7 @@ CONFIG_EEPROM_93CX6=m
 # SCSI device support
 #
 # CONFIG_RAID_ATTRS is not set
-CONFIG_SCSI=y
+CONFIG_SCSI=m
 CONFIG_SCSI_DMA=y
 # CONFIG_SCSI_TGT is not set
 # CONFIG_SCSI_NETLINK is not set
@@ -716,11 +716,11 @@ CONFIG_SCSI_PROC_FS=y
 #
 # SCSI support type (disk, tape, CD-ROM)
 #
-CONFIG_BLK_DEV_SD=y
+CONFIG_BLK_DEV_SD=m
 # CONFIG_CHR_DEV_ST is not set
 # CONFIG_CHR_DEV_OSST is not set
 # CONFIG_BLK_DEV_SR is not set
-CONFIG_CHR_DEV_SG=y
+# CONFIG_CHR_DEV_SG is not set
 # CONFIG_CHR_DEV_SCH is not set
 
 #
@@ -735,47 +735,11 @@ CONFIG_SCSI_WAIT_SCAN=m
 #
 # SCSI Transports
 #
-CONFIG_SCSI_SPI_ATTRS=y
+CONFIG_SCSI_SPI_ATTRS=m
 # CONFIG_SCSI_FC_ATTRS is not set
 # CONFIG_SCSI_ISCSI_ATTRS is not set
 # CONFIG_SCSI_SAS_LIBSAS is not set
 # CONFIG_SCSI_SRP_ATTRS is not set
-CONFIG_SCSI_LOWLEVEL=y
-# CONFIG_ISCSI_TCP is not set
-# CONFIG_BLK_DEV_3W_XXXX_RAID is not set
-# CONFIG_SCSI_3W_9XXX is not set
-# CONFIG_SCSI_ACARD is not set
-# CONFIG_SCSI_AACRAID is not set
-# CONFIG_SCSI_AIC7XXX is not set
-# CONFIG_SCSI_AIC7XXX_OLD is not set
-# CONFIG_SCSI_AIC79XX is not set
-# CONFIG_SCSI_AIC94XX is not set
-# CONFIG_SCSI_DPT_I2O is not set
-# CONFIG_SCSI_ADVANSYS is not set
-# CONFIG_SCSI_ARCMSR is not set
-# CONFIG_MEGARAID_NEWGEN is not set
-# CONFIG_MEGARAID_LEGACY is not set
-# CONFIG_MEGARAID_SAS is not set
-# CONFIG_SCSI_HPTIOP is not set
-# CONFIG_SCSI_BUSLOGIC is not set
-# CONFIG_SCSI_DMX3191D is not set
-# CONFIG_SCSI_EATA is not set
-# CONFIG_SCSI_FUTURE_DOMAIN is not set
-# CONFIG_SCSI_GDTH is not set
-# CONFIG_SCSI_IPS is not set
-# CONFIG_SCSI_INITIO is not set
-# CONFIG_SCSI_INIA100 is not set
-# CONFIG_SCSI_STEX is not set
-# CONFIG_SCSI_SYM53C8XX_2 is not set
-# CONFIG_SCSI_QLOGIC_1280 is not set
-# CONFIG_SCSI_QLA_FC is not set
-# CONFIG_SCSI_QLA_ISCSI is not set
-# CONFIG_SCSI_LPFC is not set
-# CONFIG_SCSI_DC395x is not set
-# CONFIG_SCSI_DC390T is not set
-# CONFIG_SCSI_NSP32 is not set
-# CONFIG_SCSI_DEBUG is not set
-# CONFIG_SCSI_SRP is not set
 # CONFIG_ATA is not set
 # CONFIG_MD is not set
 # CONFIG_FUSION is not set
@@ -813,25 +777,7 @@ CONFIG_CICADA_PHY=y
 # CONFIG_ICPLUS_PHY is not set
 # CONFIG_FIXED_PHY is not set
 # CONFIG_MDIO_BITBANG is not set
-CONFIG_NET_ETHERNET=y
-CONFIG_MII=y
-# CONFIG_HAPPYMEAL is not set
-# CONFIG_SUNGEM is not set
-# CONFIG_CASSINI is not set
-# CONFIG_NET_VENDOR_3COM is not set
-# CONFIG_NET_TULIP is not set
-# CONFIG_HP100 is not set
-# CONFIG_IBM_NEW_EMAC_ZMII is not set
-# CONFIG_IBM_NEW_EMAC_RGMII is not set
-# CONFIG_IBM_NEW_EMAC_TAH is not set
-# CONFIG_IBM_NEW_EMAC_EMAC4 is not set
-CONFIG_NET_PCI=y
-# CONFIG_PCNET32 is not set
-# CONFIG_AMD8111_ETH is not set
-# CONFIG_ADAPTEC_STARFIRE is not set
-# CONFIG_B44 is not set
-# CONFIG_FORCEDETH is not set
-# CONFIG_EEPRO100 is not set
+# CONFIG_NET_ETHERNET is not set
 CONFIG_E100=y
 # CONFIG_FEALNX is not set
 # CONFIG_NATSEMI is not set
@@ -865,17 +811,7 @@ CONFIG_GIANFAR=y
 CONFIG_GFAR_NAPI=y
 # CONFIG_QLA3XXX is not set
 # CONFIG_ATL1 is not set
-CONFIG_NETDEV_10000=y
-# CONFIG_CHELSIO_T1 is not set
-# CONFIG_CHELSIO_T3 is not set
-# CONFIG_IXGBE is not set
-# CONFIG_IXGB is not set
-# CONFIG_S2IO is not set
-# CONFIG_MYRI10GE is not set
-# CONFIG_NETXEN_NIC is not set
-# CONFIG_NIU is not set
-# CONFIG_MLX4_CORE is not set
-# CONFIG_TEHUTI is not set
+# CONFIG_NETDEV_10000 is not set
 # CONFIG_TR is not set
 
 #
@@ -1509,7 +1445,7 @@ CONFIG_USB_UHCI_HCD=y
 #
 # may also be needed; see USB_STORAGE Help for more information
 #
-CONFIG_USB_STORAGE=y
+CONFIG_USB_STORAGE=m
 # CONFIG_USB_STORAGE_DEBUG is not set
 # CONFIG_USB_STORAGE_DATAFAB is not set
 # CONFIG_USB_STORAGE_FREECOM is not set
diff --git a/packages/linux/linux-2.6.24/mpc8313e-rdb/mpc831x-nand.patch b/packages/linux/linux-2.6.24/mpc8313e-rdb/mpc831x-nand.patch
new file mode 100644 (file)
index 0000000..7c6502d
--- /dev/null
@@ -0,0 +1,1807 @@
+diff -urN linux-2.6.24.orig/arch/powerpc/boot/dts/mpc8313erdb.dts linux-2.6.24/arch/powerpc/boot/dts/mpc8313erdb.dts
+--- linux-2.6.24.orig/arch/powerpc/boot/dts/mpc8313erdb.dts    2008-01-24 23:58:37.000000000 +0100
++++ linux-2.6.24/arch/powerpc/boot/dts/mpc8313erdb.dts 2008-02-18 16:39:43.000000000 +0100
+@@ -36,6 +36,12 @@
+               device_type = "memory";
+               reg = <00000000 08000000>;      // 128MB at 0
+       };
++      
++      nand0 {
++              device_type = "nand";
++              compatible = "fsl-nand";
++              reg = <e2800000 00000200>;
++      };
+       soc8313@e0000000 {
+               #address-cells = <1>;
+@@ -177,6 +183,16 @@
+                       reg = <700 100>;
+                       device_type = "ipic";
+               };
++
++              elbc@5000 {
++                      device_type = "elbc";
++                      compatible = "fsl-elbc";
++                      reg = <5000 1000>;
++                      interrupts = <4d 8>;
++                      interrupt-parent = < &ipic >;
++                      allow-direct-device-sleep;
++              };
++
+       };
+       pci@e0008500 {
+diff -urN linux-2.6.24.orig/arch/powerpc/sysdev/fsl_soc.c linux-2.6.24/arch/powerpc/sysdev/fsl_soc.c
+--- linux-2.6.24.orig/arch/powerpc/sysdev/fsl_soc.c    2008-01-24 23:58:37.000000000 +0100
++++ linux-2.6.24/arch/powerpc/sysdev/fsl_soc.c 2008-02-18 17:07:57.000000000 +0100
+@@ -6,6 +6,12 @@
+  * 2006 (c) MontaVista Software, Inc.
+  * Vitaly Bordug <vbordug@ru.mvista.com>
+  *
++ * Change log:
++ * Copyright (C) 2006 Freescale Semiconductor, Inc.
++ * 2006: Lo Wilson (r43300@freescale.com)
++ *         Added support for Enhanced Local Bus Controller
++ *         Added support for USB UTMI mode on-chip PHY
++ *
+  * 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;  either version 2 of the  License, or (at your
+@@ -28,6 +34,8 @@
+ #include <linux/fsl_devices.h>
+ #include <linux/fs_enet_pd.h>
+ #include <linux/fs_uart_pd.h>
++#include <linux/mtd/nand.h>
++#include <linux/mtd/fsl_elbc.h>
+ #include <asm/system.h>
+ #include <asm/atomic.h>
+@@ -671,6 +679,75 @@
+ arch_initcall(fsl_usb_of_init);
++static int __init fsl_elbc_of_init(void)
++{
++      struct device_node *np;
++      unsigned int i;
++      struct platform_device *elbc_dev = NULL;
++      struct platform_device *nand_dev = NULL;
++      int ret;
++
++      /* find and register the enhanced local bus controller */
++      for (np = NULL, i = 0;
++           (np = of_find_compatible_node(np, "elbc", "fsl-elbc")) != NULL;
++           i++) {
++              struct resource r[2];
++
++              memset(&r, 0, sizeof(r));
++
++              ret = of_address_to_resource(np, 0, &r[0]);
++              if (ret)
++                      goto err;
++
++              r[1].start = r[1].end = irq_of_parse_and_map(np, 0);
++              r[1].flags = IORESOURCE_IRQ;
++
++              elbc_dev =
++                  platform_device_register_simple("fsl-elbc", i, r, 2);
++              if (IS_ERR(elbc_dev)) {
++                      ret = PTR_ERR(elbc_dev);
++                      goto err;
++              }
++      }
++
++      /* find and register NAND memories if the eLBC was found */
++      for (np = NULL, i = 0;
++           elbc_dev &&
++           (np = of_find_compatible_node(np, "nand", "fsl-nand")) != NULL;
++           i++) {
++              struct resource r;
++              struct platform_fsl_nand_chip chip_data;
++
++              memset(&r, 0, sizeof(r));
++              memset(&chip_data, 0, sizeof(chip_data));
++
++              ret = of_address_to_resource(np, 0, &r);
++              if (ret)
++                      goto err;
++
++              nand_dev =
++                  platform_device_register_simple("fsl-nand", i, &r, 1);
++              if (IS_ERR(nand_dev)) {
++                      ret = PTR_ERR(nand_dev);
++                      goto err;
++              }
++
++              chip_data.name = of_get_property(np, "name", NULL);
++              chip_data.partitions_str = of_get_property(np, "partitions", NULL);
++
++              ret = platform_device_add_data(nand_dev, &chip_data,
++                                      sizeof(struct platform_fsl_nand_chip));
++              if (ret)
++                      goto err;
++      }
++      return 0;
++
++err:
++      return ret;
++}
++
++arch_initcall(fsl_elbc_of_init);
++
+ #ifndef CONFIG_PPC_CPM_NEW_BINDING
+ #ifdef CONFIG_CPM2
+diff -urN linux-2.6.24.orig/drivers/mtd/nand/fsl_elbc.c linux-2.6.24/drivers/mtd/nand/fsl_elbc.c
+--- linux-2.6.24.orig/drivers/mtd/nand/fsl_elbc.c      1970-01-01 01:00:00.000000000 +0100
++++ linux-2.6.24/drivers/mtd/nand/fsl_elbc.c   2008-02-18 17:08:08.000000000 +0100
+@@ -0,0 +1,1324 @@
++/* linux/drivers/mtd/nand/fsl_elbc.c
++ *
++ * Copyright (C) 2006 Freescale Semiconductor, Inc.
++ *
++ * Freescale Enhanced Local Bus Controller NAND driver
++ *
++ * Author: Nick Spence <Nick.Spence@freescale.com>
++ * Maintainer: Tony Li <Tony.Li@freescale.com>
++ *
++ * Changelog:
++ *      2006-12 Tony Li <Tony.Li@freescale.com>
++ *              Adopt to MPC8313ERDB board
++ *
++ * 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; either version 2 of the License, or
++ * (at your option) any later version.
++ *
++ * 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., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
++*/
++
++//#ifdef CONFIG_MTD_NAND_DEBUG
++//#define DEBUG
++//#endif
++//#define DEBUG
++
++#include <linux/module.h>
++#include <linux/types.h>
++#include <linux/init.h>
++#include <linux/kernel.h>
++#include <linux/string.h>
++#include <linux/ioport.h>
++#include <linux/platform_device.h>
++#include <linux/delay.h>
++#include <linux/err.h>
++#include <linux/slab.h>
++#include <linux/interrupt.h>
++#include <linux/device.h>
++#include <linux/fsl_devices.h>
++
++#include <linux/mtd/mtd.h>
++#include <linux/mtd/nand.h>
++#include <linux/mtd/nand_ecc.h>
++#include <linux/mtd/partitions.h>
++
++#include <asm/io.h>
++#include <linux/mtd/fsl_elbc.h>
++
++#define PFX "fsl-elbc: "
++
++#undef CFG_FCM_DEBUG
++#define CFG_FCM_DEBUG_LVL 3
++#ifdef CFG_FCM_DEBUG
++static int fcm_debug_level = CFG_FCM_DEBUG_LVL;
++#define FCM_DEBUG(n, args...)                 \
++      do {                                    \
++              if (n <= fcm_debug_level)       \
++                      printk(args);           \
++      } while(0)
++#else /* CONFIG_FCM_DEBUG */
++#define FCM_DEBUG(n, args...) do { } while(0)
++#endif
++
++#define FCM_SIZE (8 * 1024)
++
++#define MAX_BANKS (8)
++
++/* use interrupt instead of busy waiting TODO */
++#define FCM_USE_INTERRUPT
++
++#define MIN(x, y)             ((x < y) ? x : y)
++
++#define ERR_BYTE 0xFF /* Value returned for read bytes when read failed */
++
++#define FCM_TIMEOUT_MSECS 100 /* Maximum number of mSecs to wait for FCM */
++
++
++
++struct fsl_elbc_ctrl;
++
++/* mtd information per set */
++
++struct fsl_elbc_mtd {
++      struct mtd_info         mtd;
++      struct nand_chip        chip;
++      struct platform_fsl_nand_chip pl_chip;
++      struct fsl_elbc_ctrl    *ctrl;
++
++      struct device           *device;
++//    int                     nr_chips;       /* Number of chips in set    */
++//    int                     nr_partitions;  /* Number of partitions or 0 */
++      char                    *name;          /* Name of set (optional)    */
++      int                     *nr_map;        /* Physical chip num (option)*/
++//    struct mtd_partition    *partitions;    /* MTD partition list (option*/
++//    struct nand_ecclayout   *ecclayout;
++      unsigned int            options;
++      struct resource         *area;
++      int                     bank;   /* Chip select bank number           */
++      unsigned int            pbase;  /* Chip select base physical address */
++      unsigned int            vbase;  /* Chip select base virtual address  */
++      int                     pgs;    /* NAND page size (0=512, 1=2048)    */
++      unsigned int            fmr;    /* FCM Flash Mode Register value     */
++};
++
++/* overview of the fsl elbc controller */
++
++struct fsl_elbc_ctrl {
++      struct nand_hw_control          controller;
++      struct fsl_elbc_mtd             *nmtd[MAX_BANKS];
++
++      /* device info */
++      atomic_t        childs_active;
++      struct device   *device;
++      struct resource *area;
++      lbus83xx_t      *regs;
++      int             irq;
++      wait_queue_head_t irq_wait;
++      unsigned int    irq_status; /* status read from LTESR by irq handler */
++      u_char         *addr;       /* Address of assigned FCM buffer        */
++      unsigned int    page;       /* Last page written to / read from      */
++      unsigned int    read_bytes; /* Number of bytes read during command   */
++      unsigned int    index;      /* Pointer to next byte to 'read'        */
++      unsigned int    status;     /* status read from LTESR after last op  */
++      int             oobbuf;     /* Pointer to OOB block                  */
++      unsigned int    mdr;        /* UPM/FCM Data Register value           */
++      unsigned int    use_mdr;    /* Non zero if the MDR is to be set      */
++};
++
++struct fsl_elbc_ctrl elbc_ctrl;
++
++/* These map to the positions used by the FCM hardware ECC generator */
++
++/* Small Page FLASH with FMR[ECCM] = 0 */
++static struct nand_ecclayout fsl_elbc_oob_sp_eccm0 = { /* TODO */
++//TODO        .useecc = MTD_NANDECC_AUTOPL_USR, /* MTD_NANDECC_PLACEONLY, */
++      .eccbytes = 3,
++      .eccpos = {6, 7, 8},
++      .oobfree = { {0, 5}, {9, 7} }
++};
++
++/* Small Page FLASH with FMR[ECCM] = 1 */
++static struct nand_ecclayout fsl_elbc_oob_sp_eccm1 = { /* TODO */
++//TODO        .useecc = MTD_NANDECC_AUTOPL_USR, /* MTD_NANDECC_PLACEONLY, */
++      .eccbytes = 3,
++      .eccpos = {8, 9, 10},
++      .oobfree = { {0, 5}, {6, 2}, {11, 5} }
++};
++
++/* Large Page FLASH with FMR[ECCM] = 0 */
++static struct nand_ecclayout fsl_elbc_oob_lp_eccm0 = {
++//TODO        .useecc = MTD_NANDECC_AUTOPL_USR, /* MTD_NANDECC_PLACEONLY, */
++      .eccbytes = 12,
++      .eccpos = {6, 7, 8, 22, 23, 24, 38, 39, 40, 54, 55, 56},
++      .oobfree = { {1, 5}, {9, 13}, {25, 13}, {41, 13}, {57, 7} }
++};
++
++/* Large Page FLASH with FMR[ECCM] = 1 */
++static struct nand_ecclayout fsl_elbc_oob_lp_eccm1 = {
++//TODO        .useecc = MTD_NANDECC_AUTOPL_USR, /* MTD_NANDECC_PLACEONLY, */
++      .eccbytes = 12,
++      .eccpos = {8, 9, 10, 24, 25, 26, 40, 41, 42, 56, 57, 58},
++      .oobfree = { {1, 7}, {11, 13}, {27, 13}, {43, 13}, {59, 5} }
++};
++
++/*=================================*/
++
++/*
++ * Set up the FCM hardware block and page address fields, and the fcm
++ * structure addr field to point to the correct FCM buffer in memory
++ */
++static void set_addr(struct mtd_info *mtd, int column, int page_addr, int oob)
++{
++      struct nand_chip *chip = mtd->priv;
++      struct fsl_elbc_mtd *nmtd = chip->priv;
++      struct fsl_elbc_ctrl *ctrl = nmtd->ctrl;
++      volatile lbus83xx_t *lbc = ctrl->regs;
++      int buf_num;
++
++      ctrl->page = page_addr;
++
++      lbc->fbar = page_addr >> (chip->phys_erase_shift - chip->page_shift);
++      if (nmtd->pgs) {
++              lbc->fpar = ((page_addr << FPAR_LP_PI_SHIFT) & FPAR_LP_PI) |
++                          ( oob ? FPAR_LP_MS : 0) |
++                            column;
++              buf_num = (page_addr & 1) << 2;
++      } else {
++              lbc->fpar = ((page_addr << FPAR_SP_PI_SHIFT) & FPAR_SP_PI) |
++                          ( oob ? FPAR_SP_MS : 0) |
++                            column;
++              buf_num = page_addr & 7;
++      }
++      ctrl->addr = (unsigned char*)(nmtd->vbase + (buf_num * 1024));
++
++      /* for OOB data point to the second half of the buffer */
++      if (oob) {
++              ctrl->addr += (nmtd->pgs ? 2048 : 512);
++      }
++      FCM_DEBUG(2,"set_addr: bank=%d, ctrl->addr=0x%p (0x%08x)\n", buf_num, ctrl->addr, nmtd->vbase);
++}
++
++/*
++ * execute FCM command and wait for it to complete
++ */
++static int fsl_elbc_run_command(struct mtd_info *mtd)
++{
++      struct nand_chip *chip = mtd->priv;
++      struct fsl_elbc_mtd *nmtd = chip->priv;
++      struct fsl_elbc_ctrl *ctrl = nmtd->ctrl;
++      volatile lbus83xx_t *lbc = ctrl->regs;
++      /* Setup the FMR[OP] to execute without write protection */
++      lbc->fmr = nmtd->fmr | 3;
++      if (ctrl->use_mdr)
++              lbc->mdr = ctrl->mdr;
++
++      FCM_DEBUG(5,"fsl_elbc_run_command: fmr= %08X fir= %08X fcr= %08X\n",
++              lbc->fmr, lbc->fir, lbc->fcr);
++      FCM_DEBUG(5,"fsl_elbc_run_command: fbar=%08X fpar=%08X fbcr=%08X bank=%d\n",
++              lbc->fbar, lbc->fpar, lbc->fbcr, nmtd->bank);
++
++      /* clear event registers */
++      lbc->lteatr = 0;
++      lbc->ltesr |= (LTESR_FCT | LTESR_PAR | LTESR_CC);
++
++      /* execute special operation */
++      lbc->lsor = nmtd->bank;
++
++      /* wait for FCM complete flag or timeout */
++/* TODO */
++#ifdef FCM_USE_INTERRUPT
++      ctrl->status = ctrl->irq_status = 0;
++      wait_event_timeout(ctrl->irq_wait, ctrl->irq_status, FCM_TIMEOUT_MSECS * HZ/1000);
++      ctrl->status = ctrl->irq_status;
++#else
++      {
++      unsigned long timeout;
++      unsigned long now;
++      now = jiffies_to_msecs(jiffies);
++      timeout = now + FCM_TIMEOUT_MSECS;
++      while (time_before(now, timeout)) {
++              ctrl->status = lbc->ltesr & (LTESR_FCT | LTESR_PAR | LTESR_CC);
++              if (ctrl->status)
++                      break;
++              now = jiffies_to_msecs(jiffies);
++      }
++      }
++#endif
++
++      /* store mdr value in case it was needed */
++      if (ctrl->use_mdr)
++              ctrl->mdr = lbc->mdr;
++
++      ctrl->use_mdr = 0;
++
++      FCM_DEBUG(5,"fsl_elbc_run_command: stat=%08X mdr= %08X fmr= %08X\n",
++              ctrl->status, ctrl->mdr, lbc->fmr);
++
++      /* returns 0 on success otherwise non-zero) */
++      return (ctrl->status == LTESR_CC ? 0 : EFAULT);
++}
++
++/* cmdfunc send commands to the FCM */
++static void fsl_elbc_cmdfunc(struct mtd_info *mtd, unsigned command,
++                      int column, int page_addr)
++{
++      struct nand_chip *chip = mtd->priv;
++      struct fsl_elbc_mtd *nmtd = chip->priv;
++      struct fsl_elbc_ctrl *ctrl = nmtd->ctrl;
++      volatile lbus83xx_t *lbc = ctrl->regs;
++
++      ctrl->use_mdr = 0;
++
++      /* clear the read buffer */
++      ctrl->read_bytes = 0;
++      if (command != NAND_CMD_PAGEPROG) {
++              ctrl->index = 0;
++              ctrl->oobbuf = -1;
++      }
++
++      switch (command) {
++      /* READ0 and READ1 read the entire buffer to use hardware ECC */
++      case NAND_CMD_READ1:
++              FCM_DEBUG(2,"fsl_elbc_cmdfunc: NAND_CMD_READ1, page_addr:"
++                          " 0x%x, column: 0x%x.\n", page_addr, column);
++              ctrl->index = column + 256;
++              goto read0;
++      case NAND_CMD_READ0:
++              FCM_DEBUG(2,"fsl_elbc_cmdfunc: NAND_CMD_READ0, page_addr:"
++                          " 0x%x, column: 0x%x.\n", page_addr, column);
++              ctrl->index = column;
++read0:
++              if (nmtd->pgs) {
++                      lbc->fir = (FIR_OP_CW0 << FIR_OP0_SHIFT) |
++                                 (FIR_OP_CA  << FIR_OP1_SHIFT) |
++                                 (FIR_OP_PA  << FIR_OP2_SHIFT) |
++                                 (FIR_OP_CW1 << FIR_OP3_SHIFT) |
++                                 (FIR_OP_RBW << FIR_OP4_SHIFT);
++              } else {
++                      lbc->fir = (FIR_OP_CW0 << FIR_OP0_SHIFT) |
++                                 (FIR_OP_CA  << FIR_OP1_SHIFT) |
++                                 (FIR_OP_PA  << FIR_OP2_SHIFT) |
++                                 (FIR_OP_RBW << FIR_OP3_SHIFT);
++              }
++              lbc->fcr = (NAND_CMD_READ0     << FCR_CMD0_SHIFT) |
++                         (NAND_CMD_READSTART << FCR_CMD1_SHIFT);
++              lbc->fbcr = 0; /* read entire page to enable ECC */
++              set_addr(mtd, 0, page_addr, 0);
++              ctrl->read_bytes = mtd->writesize + mtd->oobsize;
++              goto write_cmd2;
++      /* READOOB read only the OOB becasue no ECC is performed */
++      case NAND_CMD_READOOB:
++              FCM_DEBUG(2,"fsl_elbc_cmdfunc: NAND_CMD_READOOB, page_addr:"
++                          " 0x%x, column: 0x%x.\n", page_addr, column);
++              if (nmtd->pgs) {
++                      lbc->fir = (FIR_OP_CW0 << FIR_OP0_SHIFT) |
++                                 (FIR_OP_CA  << FIR_OP1_SHIFT) |
++                                 (FIR_OP_PA  << FIR_OP2_SHIFT) |
++                                 (FIR_OP_CW1 << FIR_OP3_SHIFT) |
++                                 (FIR_OP_RBW << FIR_OP4_SHIFT);
++                      lbc->fcr = (NAND_CMD_READ0     << FCR_CMD0_SHIFT) |
++                                 (NAND_CMD_READSTART << FCR_CMD1_SHIFT);
++              } else {
++                      lbc->fir = (FIR_OP_CW0 << FIR_OP0_SHIFT) |
++                                 (FIR_OP_CA  << FIR_OP1_SHIFT) |
++                                 (FIR_OP_PA  << FIR_OP2_SHIFT) |
++                                 (FIR_OP_RBW << FIR_OP3_SHIFT);
++                      lbc->fcr = (NAND_CMD_READOOB << FCR_CMD0_SHIFT);
++              }
++              lbc->fbcr = mtd->oobsize - column;
++              set_addr(mtd, column, page_addr, 1);
++              ctrl->read_bytes = mtd->oobsize;
++              ctrl->index = column;
++              goto write_cmd2;
++      /* READID must read all 5 possible bytes while CEB is active */
++      case NAND_CMD_READID:
++              FCM_DEBUG(2,"fsl_elbc_cmdfunc: NAND_CMD_READID.\n");
++              lbc->fir = (FIR_OP_CW0 << FIR_OP0_SHIFT) |
++                         (FIR_OP_UA  << FIR_OP1_SHIFT) |
++                         (FIR_OP_RBW << FIR_OP2_SHIFT);
++              lbc->fcr = (NAND_CMD_READID << FCR_CMD0_SHIFT);
++              lbc->fbcr = 5; /* 5 bytes for manuf, device and exts */
++              ctrl->use_mdr = 1;
++              ctrl->mdr = 0;
++              goto write_cmd0;
++      /* ERASE1 stores the block and page address */
++      case NAND_CMD_ERASE1:
++              FCM_DEBUG(2,"fsl_elbc_cmdfunc: NAND_CMD_ERASE1, page_addr:"
++                          " 0x%x.\n", page_addr);
++              set_addr(mtd, 0, page_addr, 0);
++              goto end;
++      /* ERASE2 uses the block and page address from ERASE1 */
++      case NAND_CMD_ERASE2:
++              FCM_DEBUG(2,"fsl_elbc_cmdfunc: NAND_CMD_ERASE2.\n");
++              lbc->fir = (FIR_OP_CW0 << FIR_OP0_SHIFT) |
++                         (FIR_OP_PA  << FIR_OP1_SHIFT) |
++                         (FIR_OP_CM1 << FIR_OP2_SHIFT);
++              lbc->fcr = (NAND_CMD_ERASE1 << FCR_CMD0_SHIFT) |
++                         (NAND_CMD_ERASE2 << FCR_CMD1_SHIFT);
++              lbc->fbcr = 0;
++              goto write_cmd1;
++      /* SEQIN sets up the addr buffer and all registers except the length */
++      case NAND_CMD_SEQIN:
++              FCM_DEBUG(2,"fsl_elbc_cmdfunc: NAND_CMD_SEQIN/PAGE_PROG, page_addr:"
++                          " 0x%x, column: 0x%x.\n", page_addr, column);
++              if (column == 0) {
++                      lbc->fbcr = 0; /* write entire page to enable ECC */
++              } else {
++                      lbc->fbcr = 1; /* mark as partial page so no HW ECC */
++              }
++              if (nmtd->pgs) {
++                      /* always use READ0 for large page devices */
++                      lbc->fir = (FIR_OP_CW0 << FIR_OP0_SHIFT) |
++                                 (FIR_OP_CA  << FIR_OP1_SHIFT) |
++                                 (FIR_OP_PA  << FIR_OP2_SHIFT) |
++                                 (FIR_OP_WB  << FIR_OP3_SHIFT) |
++                                 (FIR_OP_CW1 << FIR_OP4_SHIFT);
++                      lbc->fcr = (NAND_CMD_SEQIN << FCR_CMD0_SHIFT) |
++                                 (NAND_CMD_PAGEPROG << FCR_CMD1_SHIFT);
++                      set_addr(mtd, column, page_addr, 0);
++              } else {
++                      lbc->fir = (FIR_OP_CW0 << FIR_OP0_SHIFT) |
++                                 (FIR_OP_CM2 << FIR_OP1_SHIFT) |
++                                 (FIR_OP_CA  << FIR_OP2_SHIFT) |
++                                 (FIR_OP_PA  << FIR_OP3_SHIFT) |
++                                 (FIR_OP_WB  << FIR_OP4_SHIFT) |
++                                 (FIR_OP_CW1 << FIR_OP5_SHIFT);
++                      if (column >= mtd->writesize) {
++                              /* OOB area --> READOOB */
++                              column -= mtd->writesize;
++                              lbc->fcr = (NAND_CMD_READOOB << FCR_CMD0_SHIFT)
++                                       | (NAND_CMD_PAGEPROG<< FCR_CMD1_SHIFT)
++                                       | (NAND_CMD_SEQIN << FCR_CMD2_SHIFT);
++                              set_addr(mtd, column, page_addr, 1);
++                      } else if (column < 256) {
++                              /* First 256 bytes --> READ0 */
++                              lbc->fcr = (NAND_CMD_READ0 << FCR_CMD0_SHIFT)
++                                       | (NAND_CMD_PAGEPROG<< FCR_CMD1_SHIFT)
++                                       | (NAND_CMD_SEQIN << FCR_CMD2_SHIFT);
++                              set_addr(mtd, column, page_addr, 0);
++                      } else {
++                              /* Second 256 bytes --> READ1 */
++                              column -= 256;
++                              lbc->fcr = (NAND_CMD_READ1 << FCR_CMD0_SHIFT)
++                                       | (NAND_CMD_PAGEPROG<< FCR_CMD1_SHIFT)
++                                       | (NAND_CMD_SEQIN << FCR_CMD2_SHIFT);
++                              set_addr(mtd, column, page_addr, 0);
++                      }
++              }
++              goto end;
++      /* PAGEPROG reuses all of the setup from SEQIN and adds the length */
++      case NAND_CMD_PAGEPROG:
++              FCM_DEBUG(2,"fsl_elbc_cmdfunc: NAND_CMD_PAGEPROG"
++                          " writing %d bytes.\n",ctrl->index);
++              /* if the write did not start at 0 or is not a full page */
++              /* then set the exact length, otherwise use a full page  */
++              /* write so the HW generates the ECC. */
++              if (lbc->fbcr ||
++                 (ctrl->index != (mtd->writesize + mtd->oobsize)))
++                      lbc->fbcr = ctrl->index;
++              goto write_cmd2;
++      /* CMD_STATUS must read the status byte while CEB is active */
++      /* Note - it does not wait for the ready line */
++      case NAND_CMD_STATUS:
++              FCM_DEBUG(2,"fsl_elbc_cmdfunc: NAND_CMD_STATUS.\n");
++              lbc->fir = (FIR_OP_CM0 << FIR_OP0_SHIFT) |
++                         (FIR_OP_RBW << FIR_OP1_SHIFT);
++              lbc->fcr = (NAND_CMD_STATUS << FCR_CMD0_SHIFT);
++              lbc->fbcr = 1;
++              goto write_cmd0;
++      /* RESET without waiting for the ready line */
++      case NAND_CMD_RESET:
++              FCM_DEBUG(2,"fsl_elbc_cmdfunc: NAND_CMD_RESET.\n");
++              lbc->fir = (FIR_OP_CM0 << FIR_OP0_SHIFT);
++              lbc->fcr = (NAND_CMD_RESET << FCR_CMD0_SHIFT);
++              lbc->fbcr = 0;
++              goto write_cmd0;
++      default:
++              printk("fsl_elbc_cmdfunc: error, unsupported command.\n");
++              goto end;
++      }
++
++      /* Short cuts fall through to save code */
++ write_cmd0:
++      set_addr(mtd, 0, 0, 0);
++ write_cmd1:
++      ctrl->read_bytes = lbc->fbcr;
++ write_cmd2:
++      fsl_elbc_run_command(mtd);
++
++#ifdef CONFIG_MTD_NAND_VERIFY_WRITE
++      /* if we wrote a page then read back the oob to get the ECC */
++      if ((command == NAND_CMD_PAGEPROG) &&
++          (chip->ecc.mode > NAND_ECC_SOFT) &&
++          (lbc->fbcr == 0) &&
++          (ctrl->oobbuf != 0) &&
++          (ctrl->oobbuf != -1)) {
++              int i;
++              uint *oob_config;
++              unsigned char *oob_buf;
++
++              i = ctrl->page;
++              oob_buf = (unsigned char*) ctrl->oobbuf;
++              oob_config = chip->ecc.layout->eccpos;
++
++              /* wait for the write to complete and check it passed */
++              if (!(chip->waitfunc(mtd, chip) & 0x01)) {
++                      /* read back the OOB */
++                      fsl_elbc_cmdfunc(mtd, NAND_CMD_READOOB, 0, i);
++                      /* if it succeeded then copy the ECC bytes */
++                      if (ctrl->status == LTESR_CC) {
++                              for (i=0; i < chip->ecc.layout->eccbytes; i++) {
++                                      oob_buf[oob_config[i]] =
++                                              ctrl->addr[oob_config[i]];
++                              }
++                      }
++              }
++      }
++#endif
++
++ end:
++      return;
++}
++
++/* select chip */
++
++static void fsl_elbc_select_chip(struct mtd_info *mtd, int chip)
++{
++}
++
++/* fsl_elbc_cmd_ctrl
++ *
++ * Issue command and address cycles to the chip
++*/
++
++static void fsl_elbc_cmd_ctrl(struct mtd_info *mtd, int dat,
++                                  unsigned int ctrl)
++{
++}
++
++/* fsl_elbc_dev_ready()
++ *
++ * returns 0 if the nand is busy, 1 if it is ready
++*/
++
++static int fsl_elbc_dev_ready(struct mtd_info *mtd)
++{
++      return 0;
++}
++
++/*
++ * FCM does not support 16 bit data busses
++ */
++static u16 fsl_elbc_read_word(struct mtd_info *mtd)
++{
++      struct nand_chip *chip = mtd->priv;
++      struct fsl_elbc_ctrl *ctrl = (struct fsl_elbc_ctrl *) chip->controller;
++
++      dev_err(ctrl->device, "fsl_elbc_read_word: UNIMPLEMENTED.\n");
++      return 0;
++}
++
++/*
++ * Write buf to the FCM Controller Data Buffer
++ */
++static void fsl_elbc_write_buf(struct mtd_info *mtd, const u_char *buf, int len)
++{
++      struct nand_chip *chip = mtd->priv;
++      struct fsl_elbc_mtd *nmtd = chip->priv;
++      struct fsl_elbc_ctrl *ctrl = nmtd->ctrl;
++
++      FCM_DEBUG(3,"fsl_elbc_write_buf: writing %d bytes starting with 0x%lx"
++                  " at %d.\n", len, *((unsigned long*) buf), ctrl->index);
++
++      /* If armed catch the address of the OOB buffer so that it can be */
++      /* updated with the real signature after the program comletes */
++      if (!ctrl->oobbuf)
++              ctrl->oobbuf = (int) buf;
++
++      /* copy the data into the FCM hardware buffer and update the index */
++      memcpy(&(ctrl->addr[ctrl->index]), buf, len);
++      ctrl->index += len;
++      return;
++}
++
++
++/*
++ * read a byte from either the FCM hardware buffer if it has any data left
++ * otherwise issue a command to read a single byte.
++ */
++static u_char fsl_elbc_read_byte(struct mtd_info *mtd)
++{
++      struct nand_chip *chip = mtd->priv;
++      struct fsl_elbc_mtd *nmtd = chip->priv;
++      struct fsl_elbc_ctrl *ctrl = nmtd->ctrl;
++      volatile lbus83xx_t *lbc = ctrl->regs;
++      unsigned char byte;
++
++      /* If there are still bytes in the FCM then use the next byte */
++      if(ctrl->index < ctrl->read_bytes) {
++              byte = ctrl->addr[(ctrl->index)++];
++              FCM_DEBUG(4,"fsl_elbc_read_byte: byte %u (%02X): %d of %d.\n",
++                        byte, byte, ctrl->index-1, ctrl->read_bytes);
++      } else {
++              /* otherwise issue a command to read 1 byte */
++              lbc->fir = (FIR_OP_RSW << FIR_OP0_SHIFT);
++              ctrl->use_mdr = 1;
++              ctrl->read_bytes = 0;
++              ctrl->index = 0;
++              ctrl->read_bytes = 0;
++              ctrl->index = 0;
++              byte = fsl_elbc_run_command(mtd) ? ERR_BYTE : ctrl->mdr & 0xff;
++              FCM_DEBUG(4,"fsl_elbc_read_byte: byte %u (%02X) from bus.\n",
++                        byte, byte);
++      }
++
++      return byte;
++}
++
++/*
++ * Read from the FCM Controller Data Buffer
++ */
++static void fsl_elbc_read_buf(struct mtd_info *mtd, u_char* buf, int len)
++{
++      struct nand_chip *chip = mtd->priv;
++      struct fsl_elbc_mtd *nmtd = chip->priv;
++      struct fsl_elbc_ctrl *ctrl = nmtd->ctrl;
++      int i;
++      int rest;
++      unsigned long old_status;
++
++      FCM_DEBUG(3,"fsl_elbc_read_buf: reading %d bytes.\n", len);
++
++      /* see how much is still in the FCM buffer */
++      i = min((unsigned int)len, (ctrl->read_bytes - ctrl->index));
++      rest = len - i;
++      len = i;
++
++      /* copying bytes even if there was an error so that the oob works */
++      memcpy(buf, &(ctrl->addr[(ctrl->index)]), len);
++      ctrl->index += len;
++
++      /* If more data is needed then issue another block read */
++      if (rest) {
++              FCM_DEBUG(3,"fsl_elbc_read_buf: getting %d more bytes.\n",
++                          rest);
++
++              buf += len;
++
++              /* keep last status in case it was an error */
++              old_status = ctrl->status;
++
++              /* read full next page to use HW ECC if enabled */
++              fsl_elbc_cmdfunc(mtd, NAND_CMD_READ0, 0, ctrl->page + 1);
++
++              /* preserve the worst status code */
++              if (ctrl->status == LTESR_CC)
++                      ctrl->status = old_status;
++
++              fsl_elbc_read_buf(mtd, buf, rest);
++      }
++      return;
++}
++
++
++/*
++ * Verify buffer against the FCM Controller Data Buffer
++ */
++static int fsl_elbc_verify_buf(struct mtd_info *mtd, const u_char *buf, int len)
++{
++      struct nand_chip *chip = mtd->priv;
++      struct fsl_elbc_mtd *nmtd = chip->priv;
++      struct fsl_elbc_ctrl *ctrl = nmtd->ctrl;
++      int i;
++      int rest;
++
++      FCM_DEBUG(3,"fsl_elbc_verify_buf: checking %d bytes starting with 0x%02lx.\n",
++              len, *((unsigned long*) buf));
++
++      /* If last read failed then return error bytes */
++      if (ctrl->status != LTESR_CC) {
++              return EFAULT;
++      }
++
++      /* see how much is still in the FCM buffer */
++      i = min((unsigned int)len, (ctrl->read_bytes - ctrl->index));
++      rest = len - i;
++      len = i;
++
++      if (memcmp(buf, &(ctrl->addr[(ctrl->index)]), len)) {
++              return EFAULT;
++      }
++
++      ctrl->index += len;
++      if (rest) {
++              FCM_DEBUG(3,"fsl_elbc_verify_buf: getting %d more bytes.\n", rest);
++              buf += len;
++
++              /* read full next page to use HW ECC if enabled */
++              fsl_elbc_cmdfunc(mtd, NAND_CMD_READ0, 0, ctrl->page + 1);
++
++              return fsl_elbc_verify_buf(mtd, buf, rest);
++      }
++      return 0;
++}
++
++/* this function is called after Program and Erase Operations to
++ * check for success or failure */
++static int fsl_elbc_wait(struct mtd_info *mtd, struct nand_chip *this)
++{
++      struct nand_chip *chip = mtd->priv;
++      struct fsl_elbc_mtd *nmtd = chip->priv;
++      struct fsl_elbc_ctrl *ctrl = nmtd->ctrl;
++      volatile lbus83xx_t *lbc = ctrl->regs;
++
++      if (ctrl->status != LTESR_CC) {
++              return(0x1); /* Status Read error */
++      }
++
++      /* Use READ_STATUS command, but wait for the device to be ready */
++      ctrl->use_mdr = 0;
++      ctrl->oobbuf = -1;
++      lbc->fir = (FIR_OP_CW0 << FIR_OP0_SHIFT) |
++                 (FIR_OP_RBW << FIR_OP1_SHIFT);
++      lbc->fcr = (NAND_CMD_STATUS << FCR_CMD0_SHIFT);
++      set_addr(mtd, 0, 0, 0);
++      lbc->fbcr = 1;
++      ctrl->index = 0;
++      ctrl->read_bytes = lbc->fbcr;
++      fsl_elbc_run_command(mtd);
++      if (ctrl->status != LTESR_CC) {
++              return(0x1); /* Status Read error */
++      }
++      return chip->read_byte(mtd);
++}
++
++/* ECC handling functions */
++
++/*
++ * fsl_elbc_enable_hwecc - start ECC generation
++ */
++static void fsl_elbc_enable_hwecc(struct mtd_info *mtd, int mode)
++{
++      return;
++}
++
++/*
++ * fsl_elbc_calculate_ecc - Calculate the ECC bytes
++ * This is done by hardware during the write process, so we use this
++ * to arm the oob buf capture on the next write_buf() call. The ECC bytes
++ * only need to be captured if CONFIG_MTD_NAND_VERIFY_WRITE is defined which
++ * reads back the pages and checks they match the data and oob buffers.
++ */
++static int fsl_elbc_calculate_ecc(struct mtd_info *mtd, const u_char *dat, u_char *ecc_code)
++{
++#ifdef CONFIG_MTD_NAND_VERIFY_WRITE
++      struct nand_chip *chip = mtd->priv;
++      struct fsl_elbc_mtd *nmtd = chip->priv;
++      struct fsl_elbc_ctrl *ctrl = nmtd->ctrl;
++
++      /* arm capture of oob buf ptr on next write_buf */
++      ctrl->oobbuf = 0;
++#endif
++      return 0;
++}
++
++/*
++ * fsl_elbc_correct_data - Detect and correct bit error(s)
++ * The detection and correction is done automatically by the hardware,
++ * if the complete page was read. If the status code is okay then there
++ * was no error, otherwise we return an error code indicating an uncorrectable
++ * error.
++ */
++static int fsl_elbc_correct_data(struct mtd_info *mtd, u_char *dat, u_char *read_ecc, u_char *calc_ecc)
++{
++      struct nand_chip *chip = mtd->priv;
++      struct fsl_elbc_mtd *nmtd = chip->priv;
++      struct fsl_elbc_ctrl *ctrl = nmtd->ctrl;
++
++      /* No errors */
++      if (ctrl->status == LTESR_CC)
++              return 0;
++
++      return -1; /* uncorrectable error */
++}
++
++/*************************************************************************/
++/*                     Chip setup and control functions                  */
++/*************************************************************************/
++
++/*
++ * Dummy scan_bbt to complete setup of the FMR based on NAND size
++ */
++static int fsl_elbc_chip_init_tail (struct mtd_info *mtd)
++{
++      struct nand_chip *chip = mtd->priv;
++      struct fsl_elbc_mtd *nmtd = chip->priv;
++      struct fsl_elbc_ctrl *ctrl = nmtd->ctrl;
++      volatile lbus83xx_t *lbc = ctrl->regs;
++      unsigned int i;
++      unsigned int al;
++
++      /* calculate FMR Address Length field */
++      al = 0;
++      for (i = chip->pagemask >> 16; i ; i >>= 8) {
++              al++;
++      }
++
++      /* add to ECCM mode set in fsl_elbc_init */
++      nmtd->fmr |= 12 << FMR_CWTO_SHIFT |  /* Timeout > 12 mSecs */
++                   al << FMR_AL_SHIFT;
++
++      FCM_DEBUG(1,"fsl_elbc_init: nand->options  =   %08X\n", chip->options);
++      FCM_DEBUG(1,"fsl_elbc_init: nand->numchips = %10d\n", chip->numchips);
++      FCM_DEBUG(1,"fsl_elbc_init: nand->chipsize = %10ld\n", chip->chipsize);
++      FCM_DEBUG(1,"fsl_elbc_init: nand->pagemask = %10X\n", chip->pagemask);
++      FCM_DEBUG(1,"fsl_elbc_init: nand->chip_delay = %8d\n", chip->chip_delay);
++      FCM_DEBUG(1,"fsl_elbc_init: nand->badblockpos = %7d\n", chip->badblockpos);
++      FCM_DEBUG(1,"fsl_elbc_init: nand->chip_shift = %8d\n", chip->chip_shift);
++      FCM_DEBUG(1,"fsl_elbc_init: nand->page_shift = %8d\n", chip->page_shift);
++      FCM_DEBUG(1,"fsl_elbc_init: nand->phys_erase_shift = %2d\n",
++                                                    chip->phys_erase_shift);
++      FCM_DEBUG(1,"fsl_elbc_init: nand->ecclayout= %10p\n", chip->ecclayout);
++      FCM_DEBUG(1,"fsl_elbc_init: nand->eccmode  = %10d\n", chip->ecc.mode );
++      FCM_DEBUG(1,"fsl_elbc_init: nand->eccsteps = %10d\n", chip->ecc.steps);
++      FCM_DEBUG(1,"fsl_elbc_init: nand->eccsize  = %10d\n", chip->ecc.size );
++      FCM_DEBUG(1,"fsl_elbc_init: nand->eccbytes = %10d\n", chip->ecc.bytes);
++      FCM_DEBUG(1,"fsl_elbc_init: nand->ecctotal = %10d\n", chip->ecc.total);
++      FCM_DEBUG(1,"fsl_elbc_init: nand->ecclayout= %10p\n", chip->ecc.layout);
++      FCM_DEBUG(1,"fsl_elbc_init: mtd->flags     =   %08X\n", mtd->flags);
++      FCM_DEBUG(1,"fsl_elbc_init: mtd->size      = %10d\n", mtd->size);
++      FCM_DEBUG(1,"fsl_elbc_init: mtd->erasesize = %10d\n", mtd->erasesize);
++      FCM_DEBUG(1,"fsl_elbc_init: mtd->writesize = %10d\n", mtd->writesize);
++      FCM_DEBUG(1,"fsl_elbc_init: mtd->oobsize   = %10d\n", mtd->oobsize);
++      FCM_DEBUG(1,"fsl_elbc_init: mtd->ecctype   = %10d\n", mtd->ecctype);
++      FCM_DEBUG(1,"fsl_elbc_init: mtd->eccsize   = %10d\n", mtd->eccsize);
++
++      /* adjust Option Register and ECC to match Flash page size */
++      if (mtd->writesize == 512)
++              lbc->bank[nmtd->bank].or &= ~(OR_FCM_PGS);
++      else if (mtd->writesize == 2048) {
++              lbc->bank[nmtd->bank].or |= OR_FCM_PGS;
++              /* adjust ecc setup if needed */
++              if ( (lbc->bank[nmtd->bank].br & BR_DECC) == BR_DECC_CHK_GEN) {
++                      chip->ecc.size = 2048;
++                      chip->ecc.steps = 1;
++//TODO                        chip->ecc.bytes += 9;
++//TODO                        chip->ecc.total += 9;
++                      chip->ecc.layout = (nmtd->fmr & FMR_ECCM) ?
++                                      &fsl_elbc_oob_lp_eccm1 : &fsl_elbc_oob_lp_eccm0;
++                      mtd->ecclayout = chip->ecc.layout;
++              }
++      }
++      else {
++              printk("fsl_elbc_init: page size %d is not supported\n",
++                      mtd->writesize);
++              return -1;
++      }
++      nmtd->pgs = (lbc->bank[nmtd->bank].or>>OR_FCM_PGS_SHIFT) & 1;
++
++      /* fix up the oobavail size in case the layout was changed */
++      chip->ecc.layout->oobavail = 0;
++      for (i = 0; chip->ecc.layout->oobfree[i].length; i++)
++              chip->ecc.layout->oobavail +=
++                      chip->ecc.layout->oobfree[i].length;
++
++      /* return to the default bbt_scan_routine */
++      chip->scan_bbt = nand_default_bbt;
++
++      /* restore complete options including the real SKIP_BBTSCAN setting */
++      chip->options = nmtd->options;
++
++      /* Check, if we should skip the bad block table scan */
++      if (chip->options & NAND_SKIP_BBTSCAN)
++              return 0;
++
++      return chip->scan_bbt(mtd);
++}
++/* fsl_elbc_chip_init
++ *
++ * init a single instance of an chip
++*/
++
++static int fsl_elbc_chip_init(struct fsl_elbc_mtd *nmtd)
++{
++      struct fsl_elbc_ctrl *ctrl = nmtd->ctrl;
++      volatile lbus83xx_t *lbc = ctrl->regs;
++      struct nand_chip *chip = &nmtd->chip;
++
++      FCM_DEBUG(1,"eLBC Set Information for bank %d\n", nmtd->bank);
++      FCM_DEBUG(1,"  name          = %s\n",
++              nmtd->pl_chip.name ? nmtd->pl_chip.name : "(NULL)");
++      FCM_DEBUG(1,"  nr_chips      = %d\n", nmtd->pl_chip.nr_chips);
++      FCM_DEBUG(1,"  partitions    = %s\n",
++              nmtd->pl_chip.partitions_str ?
++                      nmtd->pl_chip.partitions_str : "(NULL)");
++      dev_dbg(nmtd->device,"eLBC Set Information for bank %d\n", nmtd->bank);
++      dev_dbg(nmtd->device,"  name          = %s\n",
++              nmtd->name ? nmtd->name : "(NULL)");
++      dev_dbg(nmtd->device,"  nr_chips      = %d\n", nmtd->pl_chip.nr_chips);
++      dev_dbg(nmtd->device,"  partitions    = %s\n",
++              nmtd->pl_chip.partitions_str ?
++                      nmtd->pl_chip.partitions_str : "(NULL)");
++
++      /* Fill in fsl_elbc_mtd structure */
++      nmtd->name      = (char *) nmtd->pl_chip.name;
++      nmtd->mtd.name  = nmtd->name;
++      nmtd->mtd.priv  = chip;
++      nmtd->mtd.owner = THIS_MODULE;
++      nmtd->pgs = (lbc->bank[nmtd->bank].or>>OR_FCM_PGS_SHIFT) & 1;
++// TODO       nmtd->fmr = FMR_ECCM; /* rest filled in later */
++      nmtd->fmr = 0; /* rest filled in later */
++
++      /* fill in nand_chip structure */
++      /* set physical base address from the Base Register */
++      chip->IO_ADDR_W = (void __iomem*) (nmtd->pbase);
++      chip->IO_ADDR_R = chip->IO_ADDR_W;
++
++      /* set up function call table */
++//    chip->hwcontrol  = fsl_elbc_hwcontrol;
++      chip->read_byte  = fsl_elbc_read_byte;
++      chip->read_word  = fsl_elbc_read_word;
++      chip->write_buf  = fsl_elbc_write_buf;
++      chip->read_buf   = fsl_elbc_read_buf;
++      chip->verify_buf = fsl_elbc_verify_buf;
++      chip->select_chip  = fsl_elbc_select_chip;
++// TODO       chip->block_bad
++// TODO       chip->block_markbad
++      chip->cmd_ctrl  = fsl_elbc_cmd_ctrl;
++      chip->dev_ready = fsl_elbc_dev_ready;
++      chip->cmdfunc    = fsl_elbc_cmdfunc;
++      chip->waitfunc   = fsl_elbc_wait;
++      chip->scan_bbt   = fsl_elbc_chip_init_tail;
++// TODO       chip->errstat
++
++      /* set up nand options */
++      chip->options = NAND_NO_READRDY;
++      chip->chip_delay   = 1;
++
++      chip->controller   = &ctrl->controller;
++      chip->priv         = nmtd;
++
++      /* If CS Base Register selects full hardware ECC then use it */
++      if ( (lbc->bank[nmtd->bank].br & BR_DECC) == BR_DECC_CHK_GEN) {
++              chip->ecc.mode      = NAND_ECC_HW;
++              chip->ecc.calculate = fsl_elbc_calculate_ecc;
++              chip->ecc.correct   = fsl_elbc_correct_data;
++              chip->ecc.hwctl     = fsl_elbc_enable_hwecc;
++              /* put in small page settings and adjust later if needed */
++              chip->ecc.layout = (nmtd->fmr & FMR_ECCM) ?
++                              &fsl_elbc_oob_sp_eccm1 : &fsl_elbc_oob_sp_eccm0;
++              chip->ecc.size      = 512;
++              chip->ecc.bytes     = 3;
++      } else {
++              /* otherwise fall back to default software ECC */
++              chip->ecc.mode      = NAND_ECC_SOFT;
++      }
++
++      /* force BBT scan to get to custom scan_bbt for final settings */
++      nmtd->options = chip->options;
++      chip-> options &= ~(NAND_SKIP_BBTSCAN);
++
++      return 0;
++}
++
++
++
++static int fsl_elbc_chip_remove(struct platform_device *pdev)
++{
++      struct fsl_elbc_mtd *nmtd = platform_get_drvdata(pdev);
++      struct fsl_elbc_ctrl *ctrl = nmtd->ctrl;
++
++      nand_release(&nmtd->mtd);
++
++      if (nmtd->vbase != 0) {
++              iounmap((void __iomem*)nmtd->vbase);
++              nmtd->vbase = 0;
++      }
++
++/* TODO
++      if (nmtd->area != NULL) {
++              release_resource(nmtd->area);
++              kfree(nmtd->area);
++              nmtd->area = NULL;
++      }
++*/
++
++      platform_set_drvdata(pdev, NULL);
++
++      ctrl->nmtd[nmtd->bank] = NULL;
++      atomic_dec(&ctrl->childs_active);
++
++      kfree(nmtd);
++
++      return 0;
++}
++
++#ifdef CONFIG_MTD_PARTITIONS
++const char *part_probes[] = { "cmdlinepart", NULL };
++#endif
++
++static int fsl_elbc_chip_probe(struct platform_device *pdev)
++{
++      struct platform_fsl_nand_chip *pnc = pdev->dev.platform_data;
++      struct fsl_elbc_ctrl *ctrl = &elbc_ctrl;
++      volatile lbus83xx_t *lbc = ctrl->regs;
++      struct fsl_elbc_mtd *nmtd;
++      struct resource *res;
++      int err = 0;
++      int size;
++      int bank;
++      int mtd_parts_nb = 0;
++      struct mtd_partition *mtd_parts = 0;
++
++      dev_dbg(&pdev->dev, "fsl_elbc_chip_probe(%p)\n", pdev);
++
++      /* check that the platform data structure was supplied */
++      if (pnc == NULL) {
++              dev_err(&pdev->dev,"Device needs a platform data structure\n");
++              return -ENOENT;
++      }
++
++      /* check that the device has a name */
++      if (pnc->name == NULL) {
++              dev_err(&pdev->dev,"Device requires a name\n");
++              return -ENOENT;
++      }
++      /* get, allocate and map the memory resource */
++      res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
++      if (res == NULL) {
++              dev_err(&pdev->dev,"failed to get memory region resource\n");
++              return -ENOENT;
++      }
++      /* find which chip select it is connected to */
++      for (bank=0; bank < MAX_BANKS; bank++) {
++              if ( (lbc->bank[bank].br & BR_V) &&
++                  ((lbc->bank[bank].br & BR_MSEL) == BR_MS_FCM) &&
++                  ((lbc->bank[bank].br & lbc->bank[bank].or & BR_BA) ==
++                                              res->start) ) {
++                      break;
++              }
++      }
++
++      if (bank >= MAX_BANKS) {
++              dev_err(&pdev->dev,"address did not match any chip selects\n");
++              return -ENOENT;
++      }
++
++      nmtd = kmalloc (sizeof(*nmtd), GFP_KERNEL);
++      if (!nmtd) {
++              dev_err(ctrl->device, "no memory for nand chip structure\n");
++              return -ENOMEM;
++      }
++      memset(nmtd, 0, sizeof(*nmtd));
++
++      platform_set_drvdata(pdev, nmtd);
++
++      atomic_inc(&ctrl->childs_active);
++      if (pnc)
++              memcpy(&(nmtd->pl_chip), pnc, sizeof(*pnc));
++      ctrl->nmtd[bank] = nmtd;
++      nmtd->bank = bank;
++      nmtd->ctrl = ctrl;
++      nmtd->device = &pdev->dev;
++
++      size = ( res->end - res->start ) + 1;
++/* TODO - already requested by the elbc instance ?????
++      ctrl->area = request_mem_region(res->start, size, pdev->name);
++      if (ctrl->area == NULL) {
++              dev_err(&pdev->dev, "failed to get memory region\n");
++              err = -ENOENT;
++              goto exit_error;
++      }
++*/
++      nmtd->pbase = res->start;
++      nmtd->vbase = (unsigned int) ioremap(nmtd->pbase, FCM_SIZE);
++      if (nmtd->vbase == 0) {
++              dev_err(ctrl->device, "failed to ioremap() memory region\n");
++              err = -EIO;
++              goto exit_error;
++      }
++
++      err = fsl_elbc_chip_init(nmtd);
++      if (err != 0)
++              goto exit_error;
++
++      err = nand_scan(&nmtd->mtd,
++                       nmtd->pl_chip.nr_chips ? nmtd->pl_chip.nr_chips : 1 );
++      if (err != 0)
++              goto exit_error;
++
++#ifdef CONFIG_MTD_PARTITIONS
++      /* check for command line partition information */
++      if (!(nmtd->pl_chip.options & FSL_ELBC_NO_CMDLINE_PARTITIONS))
++               mtd_parts_nb = parse_mtd_partitions(
++                                      &nmtd->mtd,
++                                      part_probes,
++                                      &mtd_parts,
++                                      0);
++#if 0
++      /* otherwise try local partition string */
++      if (mtd_parts_nb <= 0 && nmtd->pl_chip.partitions_str)
++               mtd_parts_nb = parse_mtd_string_partitions(
++                                      &nmtd->mtd,
++                                      part_probes,
++                                      &mtd_parts,
++                                      0,
++                                      nmtd->pl_chip.partitions_str);
++#endif
++      if (mtd_parts_nb > 0)
++              err = add_mtd_partitions(&nmtd->mtd,
++                                        mtd_parts,
++                                        mtd_parts_nb);
++      else
++#endif
++              err = add_mtd_device(&nmtd->mtd);
++
++      if (err == 0)
++              return 0;
++
++ exit_error:
++      fsl_elbc_chip_remove(pdev);
++
++      if (err == 0)
++              err = -EINVAL;
++      return err;
++}
++
++
++/**************************************************************************/
++/*                  Controller setup and control functions                */
++/**************************************************************************/
++
++static int fsl_elbc_ctrl_init(struct fsl_elbc_ctrl *ctrl,
++                             struct platform_device *pdev)
++{
++      volatile lbus83xx_t *lbc= (lbus83xx_t*) ctrl->regs;
++
++      /* Enable only FCM detection of timeouts, ECC errors and completion */
++      lbc->ltedr = ~(LTESR_FCT | LTESR_PAR | LTESR_CC);
++
++      /* clear event registers */
++      lbc->lteatr = 0;
++      lbc->ltesr |= (LTESR_FCT | LTESR_PAR | LTESR_CC);
++
++      /* Enable interrupts for any detected events */
++      lbc->lteir = ~0;
++
++      ctrl->read_bytes = 0;
++      ctrl->index = 0;
++      ctrl->addr = (unsigned char*) (NULL);
++      ctrl->oobbuf = -1;
++
++      return 0;
++}
++
++static int fsl_elbc_ctrl_remove(struct platform_device *pdev)
++{
++      struct fsl_elbc_ctrl *ctrl = platform_get_drvdata(pdev);
++
++        if (atomic_read(&ctrl->childs_active))
++                return -EBUSY;
++
++      if (ctrl->regs != NULL) {
++              iounmap(ctrl->regs);
++              ctrl->regs = NULL;
++      }
++
++/* TODO
++      if (ctrl->area != NULL) {
++              release_resource(ctrl->area);
++              kfree(ctrl->area);
++              ctrl->area = NULL;
++      }
++*/
++      if (ctrl->irq) {
++              free_irq(ctrl->irq, pdev);
++              ctrl->irq = 0;
++      }
++
++      platform_set_drvdata(pdev, NULL);
++      memset(ctrl, 0, sizeof(*ctrl));
++
++      return 0;
++}
++
++
++/* interrupt handler code */
++
++static irqreturn_t fsl_elbc_ctrl_irq(int irqno, void *param)
++{
++      struct fsl_elbc_ctrl *ctrl = platform_get_drvdata((struct platform_device*)param);
++      volatile lbus83xx_t *lbc= (lbus83xx_t*) ctrl->regs;
++
++      ctrl->irq_status = lbc->ltesr & (LTESR_FCT | LTESR_PAR | LTESR_CC);
++      if (ctrl->irq_status)
++              wake_up(&ctrl->irq_wait);
++
++      /* clear event registers */
++      lbc->lteatr = 0;
++      lbc->ltesr |= ctrl->irq_status;
++
++      return IRQ_HANDLED;
++}
++
++
++/* fsl_elbc_ctrl_probe
++ *
++ * called by device layer when it finds a device matching
++ * one our driver can handled. This code allocates all of
++ * the resources needed for the controller only.  The
++ * resources for the NAND banks themselves are allocated
++ * in the chip probe function.
++*/
++
++static int fsl_elbc_ctrl_probe(struct platform_device *pdev)
++{
++      struct fsl_elbc_ctrl *ctrl;
++      struct resource *res;
++      int err = 0;
++      int size;
++      int ret;
++
++      dev_dbg(&pdev->dev, "fsl_elbc_ctrl_probe(%p)\n", pdev);
++      ctrl = &elbc_ctrl;
++
++      memset(ctrl, 0, sizeof(*ctrl));
++      platform_set_drvdata(pdev, ctrl);
++
++      spin_lock_init(&ctrl->controller.lock);
++      init_waitqueue_head(&ctrl->controller.wq);
++      init_waitqueue_head(&ctrl->irq_wait);
++
++      /* get, allocate and map the memory resource */
++      res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
++      if (res == NULL) {
++              dev_err(&pdev->dev,"failed to get memory region resouce\n");
++              err = -ENOENT;
++              goto exit_error;
++      }
++
++      size = ( res->end - res->start ) + 1;
++/* TODO - already requested by the elbc instance ?????
++      ctrl->area = request_mem_region(res->start, size, pdev->name);
++      if (ctrl->area == NULL) {
++              dev_err(&pdev->dev, "failed to get memory region\n");
++              err = -ENOENT;
++              goto exit_error;
++      }
++*/
++      ctrl->regs = ioremap(res->start, size);
++      if (ctrl->regs == 0) {
++              dev_err(&pdev->dev, "failed to ioremap() region\n");
++              err = -EIO;
++              goto exit_error;
++      }
++
++      /* get and allocate the irq resource */
++      res = platform_get_resource(pdev, IORESOURCE_IRQ, 0);
++      if (res == NULL) {
++              dev_err(&pdev->dev, "failed to get irq resource\n");
++              err = -ENOENT;
++              goto exit_error;
++      }
++
++      ret = request_irq(res->start, fsl_elbc_ctrl_irq, 0, pdev->name, pdev);
++      if (ret != 0) {
++              dev_err(&pdev->dev, "failed to install irq (%d)\n", ret);
++              err = -EIO;
++              goto exit_error;
++      }
++
++      ctrl->irq       = res->start;
++      ctrl->device    = &pdev->dev;
++      dev_dbg(&pdev->dev, "mapped registers at %p\n", ctrl->regs);
++
++      /* initialise the hardware */
++
++      err = fsl_elbc_ctrl_init(ctrl, pdev);
++      if (err == 0)
++              return 0;
++
++ exit_error:
++      fsl_elbc_ctrl_remove(pdev);
++
++      if (err == 0)
++              err = -EINVAL;
++      return err;
++}
++
++/* PM Support */
++#ifdef CONFIG_PM
++
++static int fsl_elbc_ctrl_suspend(struct platform_device *dev, pm_message_t pm)
++{
++      return 0;
++}
++
++static int fsl_elbc_ctrl_resume(struct platform_device *dev)
++{
++      return 0;
++}
++
++#else
++#define fsl_elbc_ctrl_suspend NULL
++#define fsl_elbc_ctrl_resume NULL
++#endif
++
++/*************************************************************************/
++/*                        device driver registration                     */
++/*************************************************************************/
++
++
++static struct platform_driver fsl_elbc_ctrl_driver = {
++      .probe          = fsl_elbc_ctrl_probe,
++      .remove         = fsl_elbc_ctrl_remove,
++      .suspend        = fsl_elbc_ctrl_suspend,
++      .resume         = fsl_elbc_ctrl_resume,
++      .driver         = {
++              .name   = "fsl-elbc",
++              .owner  = THIS_MODULE,
++      },
++};
++
++static struct platform_driver fsl_elbc_chip_driver = {
++      .probe          = fsl_elbc_chip_probe,
++      .remove         = fsl_elbc_chip_remove,
++      .driver         = {
++              .name   = "fsl-nand",
++              .owner  = THIS_MODULE,
++      },
++};
++
++static int __init fsl_elbc_init(void)
++{
++        int ret;
++
++      printk("Freescale eLBC NAND Driver (C) 2006 Freescale\n");
++
++        ret = platform_driver_register(&fsl_elbc_ctrl_driver);
++        if (!ret)
++                ret = platform_driver_register(&fsl_elbc_chip_driver);
++
++        return ret;
++}
++
++static void __exit fsl_elbc_exit(void)
++{
++      platform_driver_unregister(&fsl_elbc_chip_driver);
++      platform_driver_unregister(&fsl_elbc_ctrl_driver);
++}
++
++module_init(fsl_elbc_init);
++module_exit(fsl_elbc_exit);
++
++MODULE_LICENSE("GPL");
++MODULE_AUTHOR("Nick Spence");
++MODULE_DESCRIPTION("Freescale Enhanced Local Bus Controller MTD NAND driver");
+diff -urN linux-2.6.24.orig/drivers/mtd/nand/Kconfig linux-2.6.24/drivers/mtd/nand/Kconfig
+--- linux-2.6.24.orig/drivers/mtd/nand/Kconfig 2008-01-24 23:58:37.000000000 +0100
++++ linux-2.6.24/drivers/mtd/nand/Kconfig      2008-02-18 16:39:43.000000000 +0100
+@@ -284,6 +284,14 @@
+       depends on MTD_NAND && MACH_ARMCORE
++config MTD_NAND_FSL_ELBC
++      tristate "NAND support for MPC831x"
++      depends on MTD_NAND && PPC_MPC831x
++      help
++        The MPC831x includes a NAND FLASH Controller Module with built-in hardware
++        ECC capabilities. Enabling this This option will enable you to use these to
++        control external NAND device.
++
+ config MTD_NAND_NANDSIM
+       tristate "Support for NAND Flash Simulator"
+       depends on MTD_PARTITIONS
+diff -urN linux-2.6.24.orig/drivers/mtd/nand/Makefile linux-2.6.24/drivers/mtd/nand/Makefile
+--- linux-2.6.24.orig/drivers/mtd/nand/Makefile        2008-01-24 23:58:37.000000000 +0100
++++ linux-2.6.24/drivers/mtd/nand/Makefile     2008-02-18 16:40:08.000000000 +0100
+@@ -29,5 +29,6 @@
+ obj-$(CONFIG_MTD_NAND_BASLER_EXCITE)  += excite_nandflash.o
+ obj-$(CONFIG_MTD_NAND_PLATFORM)               += plat_nand.o
+ obj-$(CONFIG_MTD_ALAUDA)              += alauda.o
++obj-$(CONFIG_MTD_NAND_FSL_ELBC)               += fsl_elbc.o
+ nand-objs := nand_base.o nand_bbt.o
+diff -urN linux-2.6.24.orig/include/linux/mtd/fsl_elbc.h linux-2.6.24/include/linux/mtd/fsl_elbc.h
+--- linux-2.6.24.orig/include/linux/mtd/fsl_elbc.h     1970-01-01 01:00:00.000000000 +0100
++++ linux-2.6.24/include/linux/mtd/fsl_elbc.h  2008-02-18 16:39:43.000000000 +0100
+@@ -0,0 +1,313 @@
++/*
++ * (C) Copyright 2004-2006 Freescale Semiconductor, Inc.
++ *
++ * Freescale Enhanced Local Bus Controller Internal Memory Map
++ *
++ * History :
++ * 20061010 : Extracted fomr immap_83xx.h
++ *
++ * 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; either version 2 of
++ * the License, or (at your option) any later version.
++ *
++ * 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., 59 Temple Place, Suite 330, Boston,
++ * MA 02111-1307 USA
++ *
++ */
++#ifdef __KERNEL__
++#ifndef __FSL_ELBC__
++#define __FSL_ELBC__
++
++/*
++ * Local Bus Controller Registers
++ */
++typedef struct lbus_bank{
++      u32 br;             /**< Base Register  */
++#define BR0 0x5000
++#define BR1 0x5008
++#define BR2 0x5010
++#define BR3 0x5018
++#define BR4 0x5020
++#define BR5 0x5028
++#define BR6 0x5030
++#define BR7 0x5038
++
++#define BR_BA           0xFFFF8000
++#define BR_BA_SHIFT             15
++#define BR_PS           0x00001800
++#define BR_PS_SHIFT             11
++#define BR_PS_8         0x00000800  /* Port Size 8 bit */
++#define BR_PS_16        0x00001000  /* Port Size 16 bit */
++#define BR_PS_32        0x00001800  /* Port Size 32 bit */
++#define BR_DECC         0x00000600
++#define BR_DECC_SHIFT            9
++#define BR_DECC_OFF     0x00000000  /* HW ECC checking and generation off */
++#define BR_DECC_CHK     0x00000200  /* HW ECC checking on, generation off */
++#define BR_DECC_CHK_GEN 0x00000400  /* HW ECC checking and generation on */
++#define BR_WP           0x00000100
++#define BR_WP_SHIFT              8
++#define BR_MSEL         0x000000E0
++#define BR_MSEL_SHIFT            5
++#define BR_MS_GPCM      0x00000000  /* GPCM */
++#define BR_MS_FCM       0x00000020  /* FCM */
++#define BR_MS_SDRAM     0x00000060  /* SDRAM */
++#define BR_MS_UPMA      0x00000080  /* UPMA */
++#define BR_MS_UPMB      0x000000A0  /* UPMB */
++#define BR_MS_UPMC      0x000000C0  /* UPMC */
++#define BR_V            0x00000001
++#define BR_V_SHIFT               0
++#define BR_RES          ~(BR_BA|BR_PS|BR_DECC|BR_WP|BR_MSEL|BR_V)
++
++      u32 or;             /**< Base Register  */
++#define OR0 0x5004
++#define OR1 0x500C
++#define OR2 0x5014
++#define OR3 0x501C
++#define OR4 0x5024
++#define OR5 0x502C
++#define OR6 0x5034
++#define OR7 0x503C
++
++#define OR_GPCM_AM              0xFFFF8000
++#define OR_GPCM_AM_SHIFT                15
++#define OR_GPCM_BCTLD           0x00001000
++#define OR_GPCM_BCTLD_SHIFT             12
++#define OR_GPCM_CSNT            0x00000800
++#define OR_GPCM_CSNT_SHIFT              11
++#define OR_GPCM_ACS             0x00000600
++#define OR_GPCM_ACS_SHIFT                9
++#define OR_GPCM_ACS_0b10        0x00000400
++#define OR_GPCM_ACS_0b11        0x00000600
++#define OR_GPCM_XACS            0x00000100
++#define OR_GPCM_XACS_SHIFT               8
++#define OR_GPCM_SCY             0x000000F0
++#define OR_GPCM_SCY_SHIFT                4
++#define OR_GPCM_SCY_1           0x00000010
++#define OR_GPCM_SCY_2           0x00000020
++#define OR_GPCM_SCY_3           0x00000030
++#define OR_GPCM_SCY_4           0x00000040
++#define OR_GPCM_SCY_5           0x00000050
++#define OR_GPCM_SCY_6           0x00000060
++#define OR_GPCM_SCY_7           0x00000070
++#define OR_GPCM_SCY_8           0x00000080
++#define OR_GPCM_SCY_9           0x00000090
++#define OR_GPCM_SCY_10          0x000000a0
++#define OR_GPCM_SCY_11          0x000000b0
++#define OR_GPCM_SCY_12          0x000000c0
++#define OR_GPCM_SCY_13          0x000000d0
++#define OR_GPCM_SCY_14          0x000000e0
++#define OR_GPCM_SCY_15          0x000000f0
++#define OR_GPCM_SETA            0x00000008
++#define OR_GPCM_SETA_SHIFT               3
++#define OR_GPCM_TRLX            0x00000004
++#define OR_GPCM_TRLX_SHIFT               2
++#define OR_GPCM_EHTR            0x00000002
++#define OR_GPCM_EHTR_SHIFT               1
++#define OR_GPCM_EAD             0x00000001
++#define OR_GPCM_EAD_SHIFT                0
++
++#define OR_UPM_AM    0xFFFF8000
++#define OR_UPM_AM_SHIFT      15
++#define OR_UPM_XAM   0x00006000
++#define OR_UPM_XAM_SHIFT     13
++#define OR_UPM_BCTLD 0x00001000
++#define OR_UPM_BCTLD_SHIFT   12
++#define OR_UPM_BI    0x00000100
++#define OR_UPM_BI_SHIFT       8
++#define OR_UPM_TRLX  0x00000004
++#define OR_UPM_TRLX_SHIFT     2
++#define OR_UPM_EHTR  0x00000002
++#define OR_UPM_EHTR_SHIFT     1
++#define OR_UPM_EAD   0x00000001
++#define OR_UPM_EAD_SHIFT      0
++
++#define OR_SDRAM_AM    0xFFFF8000
++#define OR_SDRAM_AM_SHIFT      15
++#define OR_SDRAM_XAM   0x00006000
++#define OR_SDRAM_XAM_SHIFT     13
++#define OR_SDRAM_COLS  0x00001C00
++#define OR_SDRAM_COLS_SHIFT    10
++#define OR_SDRAM_ROWS  0x000001C0
++#define OR_SDRAM_ROWS_SHIFT     6
++#define OR_SDRAM_PMSEL 0x00000020
++#define OR_SDRAM_PMSEL_SHIFT    5
++#define OR_SDRAM_EAD   0x00000001
++#define OR_SDRAM_EAD_SHIFT      0
++
++#define OR_FCM_AM               0xFFFF8000
++#define OR_FCM_AM_SHIFT                 15
++#define OR_FCM_BCTLD            0x00001000
++#define OR_FCM_BCTLD_SHIFT              12
++#define OR_FCM_PGS              0x00000400
++#define OR_FCM_PGS_SHIFT                10
++#define OR_FCM_CSCT             0x00000200
++#define OR_FCM_CSCT_SHIFT                9
++#define OR_FCM_CST              0x00000100
++#define OR_FCM_CST_SHIFT                 8
++#define OR_FCM_CHT              0x00000080
++#define OR_FCM_CHT_SHIFT                 7
++#define OR_FCM_SCY              0x00000070
++#define OR_FCM_SCY_SHIFT                 4
++#define OR_FCM_SCY_1            0x00000010
++#define OR_FCM_SCY_2            0x00000020
++#define OR_FCM_SCY_3            0x00000030
++#define OR_FCM_SCY_4            0x00000040
++#define OR_FCM_SCY_5            0x00000050
++#define OR_FCM_SCY_6            0x00000060
++#define OR_FCM_SCY_7            0x00000070
++#define OR_FCM_RST              0x00000008
++#define OR_FCM_RST_SHIFT                 3
++#define OR_FCM_TRLX             0x00000004
++#define OR_FCM_TRLX_SHIFT                2
++#define OR_FCM_EHTR             0x00000002
++#define OR_FCM_EHTR_SHIFT                1
++} lbus_bank_t;
++
++typedef struct lbus83xx {
++      lbus_bank_t bank[8];
++      u8 res0[0x28];
++      u32 mar;                /**< UPM Address Register */
++      u8 res1[0x4];
++      u32 mamr;               /**< UPMA Mode Register */
++      u32 mbmr;               /**< UPMB Mode Register */
++      u32 mcmr;               /**< UPMC Mode Register */
++      u8 res2[0x8];
++      u32 mrtpr;              /**< Memory Refresh Timer Prescaler Register */
++      u32 mdr;                /**< UPM Data Register */
++      u8 res3[0x4];
++      u32 lsor;               /**< Special Operation Initiation Register */
++      u32 lsdmr;              /**< SDRAM Mode Register */
++      u8 res4[0x8];
++      u32 lurt;               /**< UPM Refresh Timer */
++      u32 lsrt;               /**< SDRAM Refresh Timer */
++      u8 res5[0x8];
++      u32 ltesr;              /**< Transfer Error Status Register */
++#define LTESR_BM   0x80000000
++#define LTESR_FCT  0x40000000
++#define LTESR_PAR  0x20000000
++#define LTESR_WP   0x04000000
++#define LTESR_ATMW 0x00800000
++#define LTESR_ATMR 0x00400000
++#define LTESR_CS   0x00080000
++#define LTESR_CC   0x00000001
++      u32 ltedr;              /**< Transfer Error Disable Register */
++      u32 lteir;              /**< Transfer Error Interrupt Register */
++      u32 lteatr;             /**< Transfer Error Attributes Register */
++      u32 ltear;              /**< Transfer Error Address Register */
++      u8 res6[0xC];
++      u32 lbcr;               /**< Configuration Register */
++#define LBCR_LDIS  0x80000000
++#define LBCR_LDIS_SHIFT    31
++#define LBCR_BCTLC 0x00C00000
++#define LBCR_BCTLC_SHIFT   22
++#define LBCR_AHD   0x00200000
++#define LBCR_LPBSE 0x00020000
++#define LBCR_LPBSE_SHIFT   17
++#define LBCR_EPAR  0x00010000
++#define LBCR_EPAR_SHIFT    16
++#define LBCR_BMT   0x0000FF00
++#define LBCR_BMT_SHIFT      8
++#define LBCR_INIT  0x00040000
++      u32 lcrr;               /**< Clock Ratio Register */
++#define LCRR_DBYP    0x80000000
++#define LCRR_DBYP_SHIFT      31
++#define LCRR_BUFCMDC 0x30000000
++#define LCRR_BUFCMDC_SHIFT   28
++#define LCRR_ECL     0x03000000
++#define LCRR_ECL_SHIFT       24
++#define LCRR_EADC    0x00030000
++#define LCRR_EADC_SHIFT      16
++#define LCRR_CLKDIV  0x0000000F
++#define LCRR_CLKDIV_SHIFT     0
++      u8 res7[0x8];
++      u32 fmr;               /**< Flash Mode Register */
++#define FMR_CWTO     0x0000F000
++#define FMR_CWTO_SHIFT       12
++#define FMR_BOOT     0x00000800
++#define FMR_ECCM     0x00000100
++#define FMR_AL       0x00000030
++#define FMR_AL_SHIFT          4
++#define FMR_OP       0x00000003
++#define FMR_OP_SHIFT          0
++      u32 fir;               /**< Flash Instruction Register */
++#define FIR_OP0      0xF0000000
++#define FIR_OP0_SHIFT        28
++#define FIR_OP1      0x0F000000
++#define FIR_OP1_SHIFT        24
++#define FIR_OP2      0x00F00000
++#define FIR_OP2_SHIFT        20
++#define FIR_OP3      0x000F0000
++#define FIR_OP3_SHIFT        16
++#define FIR_OP4      0x0000F000
++#define FIR_OP4_SHIFT        12
++#define FIR_OP5      0x00000F00
++#define FIR_OP5_SHIFT         8
++#define FIR_OP6      0x000000F0
++#define FIR_OP6_SHIFT         4
++#define FIR_OP7      0x0000000F
++#define FIR_OP7_SHIFT         0
++#define FIR_OP_NOP   0x0      /* No operation and end of sequence */
++#define FIR_OP_CA    0x1        /* Issue current column address */
++#define FIR_OP_PA    0x2        /* Issue current block+page address */
++#define FIR_OP_UA    0x3        /* Issue user defined address */
++#define FIR_OP_CM0   0x4        /* Issue command from FCR[CMD0] */
++#define FIR_OP_CM1   0x5        /* Issue command from FCR[CMD1] */
++#define FIR_OP_CM2   0x6        /* Issue command from FCR[CMD2] */
++#define FIR_OP_CM3   0x7        /* Issue command from FCR[CMD3] */
++#define FIR_OP_WB    0x8        /* Write FBCR bytes from FCM buffer */
++#define FIR_OP_WS    0x9        /* Write 1 or 2 bytes from MDR[AS] */
++#define FIR_OP_RB    0xA        /* Read FBCR bytes to FCM buffer */
++#define FIR_OP_RS    0xB        /* Read 1 or 2 bytes to MDR[AS] */
++#define FIR_OP_CW0   0xC        /* Wait then issue FCR[CMD0] */
++#define FIR_OP_CW1   0xD        /* Wait then issue FCR[CMD1] */
++#define FIR_OP_RBW   0xE        /* Wait then read FBCR bytes */
++#define FIR_OP_RSW   0xE        /* Wait then read 1 or 2 bytes */
++      u32 fcr;               /**< Flash Command Register */
++#define FCR_CMD0     0xFF000000
++#define FCR_CMD0_SHIFT       24
++#define FCR_CMD1     0x00FF0000
++#define FCR_CMD1_SHIFT       16
++#define FCR_CMD2     0x0000FF00
++#define FCR_CMD2_SHIFT        8
++#define FCR_CMD3     0x000000FF
++#define FCR_CMD3_SHIFT        0
++      u32 fbar;              /**< Flash Block Address Register */
++#define FBAR_BLK     0x00FFFFFF
++      u32 fpar;              /**< Flash Page Address Register */
++#define FPAR_SP_PI   0x00007C00
++#define FPAR_SP_PI_SHIFT     10
++#define FPAR_SP_MS   0x00000200
++#define FPAR_SP_CI   0x000001FF
++#define FPAR_SP_CI_SHIFT      0
++#define FPAR_LP_PI   0x0003F000
++#define FPAR_LP_PI_SHIFT     12
++#define FPAR_LP_MS   0x00000800
++#define FPAR_LP_CI   0x000007FF
++#define FPAR_LP_CI_SHIFT      0
++      u32 fbcr;              /**< Flash Byte Count Register */
++#define FBCR_BC      0x00000FFF
++      u8 res11[0x8];
++      u8 res8[0xF00];
++} lbus83xx_t;
++
++struct platform_fsl_nand_chip {
++      const char      *name;
++      int             nr_chips;
++      const char      *partitions_str;
++      unsigned int    options;
++};
++
++/* Setting this option prevents the command line from being parsed
++ * for MTD partitions. */
++#define FSL_ELBC_NO_CMDLINE_PARTITIONS        0x10000000
++
++#endif /* __FSL_ELBC__ */
++#endif /* __KERNEL__ */
index afb4515..04470bd 100644 (file)
@@ -7,7 +7,7 @@ DEFAULT_PREFERENCE_mpc8313e-rdb = "1"
 
 DEPENDS_append_mpc8313e-rdb = " dtc-native"
 
-PR = "r5"
+PR = "r6"
 
 SRC_URI = "${KERNELORG_MIRROR}/pub/linux/kernel/v2.6/linux-2.6.24.tar.bz2 \
            http://kamikaze.waninkoko.info/patches/2.6.24/kamikaze1/broken-out/squashfs-lzma-2.6.24.patch;patch=1 \
@@ -24,6 +24,7 @@ SRC_URI_append_gesbc-9302 = " \
        "
 
 SRC_URI_append_mpc8313e-rdb = "\
+       file://mpc831x-nand.patch;patch=1 \
        file://mpc8313e-rdb-leds.patch;patch=1 \
        file://mpc8313e-rdb-rtc.patch;patch=1"