[oe-commits] org.oe.dev linux-2.6.23: add NAND flash driver for mpc8323e-rdb, fix NOR mapping

jeremy_laine commit openembedded-commits at lists.openembedded.org
Wed Nov 28 20:09:19 UTC 2007


linux-2.6.23: add NAND flash driver for mpc8323e-rdb, fix NOR mapping

Author: jeremy_laine at openembedded.org
Branch: org.openembedded.dev
Revision: 960ad5e7a507f613f81d637270a55cbe938265d1
ViewMTN: http://monotone.openembedded.org/revision/info/960ad5e7a507f613f81d637270a55cbe938265d1
Files:
1
packages/linux/linux-2.6.23/mpc8313e-rdb/mpc831x-nand.patch
packages/linux/linux-2.6.23/mpc8313e-rdb/defconfig
packages/linux/linux_2.6.23.bb
Diffs:

#
# mt diff -r6b8f9f938c511ccca723f4b026eba98d9fa49dc4 -r960ad5e7a507f613f81d637270a55cbe938265d1
#
# 
# 
# add_file "packages/linux/linux-2.6.23/mpc8313e-rdb/mpc831x-nand.patch"
#  content [ff71d36374ddc75c81a9a36be82543a7ebd0c0f9]
# 
# patch "packages/linux/linux-2.6.23/mpc8313e-rdb/defconfig"
#  from [833b5c58762860dc89c9faa2e931a92a1238b985]
#    to [6dfb929add3d0888be47385b039b2c401d117a8e]
# 
# patch "packages/linux/linux_2.6.23.bb"
#  from [00a00d10df9de70b87c4f01ef218370ab40cc076]
#    to [45c1b7177dff55702c2f6482f8dc4d5b673e87bd]
# 
============================================================
--- packages/linux/linux-2.6.23/mpc8313e-rdb/mpc831x-nand.patch	ff71d36374ddc75c81a9a36be82543a7ebd0c0f9
+++ packages/linux/linux-2.6.23/mpc8313e-rdb/mpc831x-nand.patch	ff71d36374ddc75c81a9a36be82543a7ebd0c0f9
@@ -0,0 +1,1807 @@
+diff -urN linux-2.6.23.orig/arch/powerpc/boot/dts/mpc8313erdb.dts linux-2.6.23/arch/powerpc/boot/dts/mpc8313erdb.dts
+--- linux-2.6.23.orig/arch/powerpc/boot/dts/mpc8313erdb.dts	2007-10-09 22:31:38.000000000 +0200
++++ linux-2.6.23/arch/powerpc/boot/dts/mpc8313erdb.dts	2007-11-28 20:36:57.000000000 +0100
+@@ -37,6 +37,12 @@
+ 		device_type = "memory";
+ 		reg = <00000000 08000000>;	// 128MB at 0
+ 	};
++	
++	nand0 {
++		device_type = "nand";
++		compatible = "fsl-nand";
++		reg = <e2800000 00000200>;
++	};
+ 
+ 	soc8313 at e0000000 {
+ 		#address-cells = <1>;
+@@ -210,5 +216,15 @@
+ 			built-in;
+ 			device_type = "ipic";
+ 		};
++
++		elbc at 5000 {
++			device_type = "elbc";
++			compatible = "fsl-elbc";
++			reg = <5000 1000>;
++			interrupts = <4d 8>;
++			interrupt-parent = < &ipic >;
++			allow-direct-device-sleep;
++		};
++
+ 	};
+ };
+diff -urN linux-2.6.23.orig/arch/powerpc/sysdev/fsl_soc.c linux-2.6.23/arch/powerpc/sysdev/fsl_soc.c
+--- linux-2.6.23.orig/arch/powerpc/sysdev/fsl_soc.c	2007-10-09 22:31:38.000000000 +0200
++++ linux-2.6.23/arch/powerpc/sysdev/fsl_soc.c	2007-11-28 20:36:39.000000000 +0100
+@@ -6,6 +6,12 @@
+  * 2006 (c) MontaVista Software, Inc.
+  * Vitaly Bordug <vbordug at ru.mvista.com>
+  *
++ * Change log:
++ * Copyright (C) 2006 Freescale Semiconductor, Inc.
++ * 2006: Lo Wilson (r43300 at 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
+@@ -27,6 +33,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>
+@@ -648,6 +656,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 = get_property(np, "name", NULL);
++		chip_data.partitions_str = 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);
++
+ #ifdef CONFIG_CPM2
+ 
+ extern void init_scc_ioports(struct fs_uart_platform_info*);
+diff -urN linux-2.6.23.orig/drivers/mtd/nand/fsl_elbc.c linux-2.6.23/drivers/mtd/nand/fsl_elbc.c
+--- linux-2.6.23.orig/drivers/mtd/nand/fsl_elbc.c	1970-01-01 01:00:00.000000000 +0100
++++ linux-2.6.23/drivers/mtd/nand/fsl_elbc.c	2007-11-28 20:36:39.000000000 +0100
+@@ -0,0 +1,1325 @@
++/* 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 at freescale.com>
++ * Maintainer: Tony Li <Tony.Li at freescale.com>
++ *
++ * Changelog:
++ *      2006-12 Tony Li <Tony.Li at 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 <asm/mpc83xx.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_O%s
>>> DIFF TRUNCATED @ 16K






More information about the Openembedded-commits mailing list