[U-Boot-Users] NAND flash driver for MPC 8548
sagarwal
sagarwal at teaktechnologies.com
Fri Mar 30 08:19:39 CEST 2007
Hi
Have a driver working well for connecting up
NAND flash chips to the Motorola PowerPC PPC 8548
on the local bus using the user programmable machine
UPM. Should work fine with some adjustments for
bus speed (works for me at LBUS at 50Mhz) and signal
hookups (absolutely need to connect the Ready/Busy
coming out of the NAND chip to a GPIO pin).
C file attached.
shalabh
-------------- next part --------------
/*
*
* See file CREDITS for list of people who contributed to this
* project.
*
* 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
*/
#include <common.h>
#if (CONFIG_COMMANDS & CFG_CMD_NAND)
#if !defined(CFG_NAND_LEGACY)
#include <nand.h>
#include <asm/processor.h>
#include <asm/immap_85xx.h>
#define MAMX_OPCODE_NORMAL_OP 0x0
#define MAMX_OPCODE_WRITE_ARRAY 0x10000000
#define MAMX_OPCODE_READ_ARRAY 0x20000000
#define MAMX_OPCODE_RUN_ARRAY_PATTERN 0x30000000
/*
* This NAND driver uses the UPM machine of the 85xx.
* This consists of a 64 location array which contains
* words that encode the behaviour of various different
* hardware signals (chip select, write enable etc.)
* in order to interface with the NAND
*
* Each Ram word describes a single local bus cycle and
* encodes signals at a granularity of 4 phases for chip
* select and 2 phases for other signals
*
*
* 0 1 2 3 4-7 8 9 10 11
* -----------------------------------------------
* |LCS1|LCS2|LCS3|LCS4| X X X X |WE0|WE0|WE1|WE1|
* -----------------------------------------------
*
* 12 13 14 15 16 17 18-25
* -----------------------------------------------
* |CLE0|CLE1|RE0|RE1|ALE0|ALE1| X X X X X X X X |
* -----------------------------------------------
*
* 26 27 28-28 29 31
* ----------------------------------
* |AMX|AMX|X X X X |UTA| X | LAST |
* ----------------------------------
*
* where:
* LCS1-LCS4 - Chip select (active LOW)
* 4 quarter cycle phases of chip select
*
* WE0-WE0 - Write enable (active LOW) 1st LBUS half cycle
* If both bits are 10 = write enable is low
* If both bits are 11 = write enable is high
*
* WE1-WE1 - Write enable (active LOW) 2nd LBUS half cycle
* If both bits are 10 = write enable is low
* If both bits are 11 = write enable is high
*
* CLE0-CLE1 - Command latch enable (active HIGH)
* Turn active HIGH to latch in a command opcode
*
* RE0-RE1 - Read enable (active LOW)
*
* ALE0-ALE1 - Address latch enable (active HIGH)
* Turn active HIGH to latch in an address byte
*
* AMX - These bits are turned on when we want
* the IO[0:7] lines to put out a command
* opcode or address value
*
* UTA - Bit is turned high when we want to latch
* in IO[0:7] as data into the CPU (e.g. we turn
* on read enable, we turn on UTA to let 85xx to
* latch in IO[0:7] as valid data byte
*
* LAST - sequence will terminate at RAM word with this
* bit set
*
* When UPM machine is not active, all signals are
* driven high - this is not ideal for certain signals
* like command latch enable, so before we start
* a command we take command latch low for a couple
* of cycles and then take it high to start a command.
*/
static unsigned long UPMATable[] = {
/*
* Single Read (offset 0)
* Words 0 to 7
*/
0xfff30000, /* start off with all signals inactive */
0xfff30000,
0x0ff30000, /* assert chip select */
0x0ff30000,
0x0ff00000, /* assert read enable */
0x0ff00000,
0x0ff30004, /* deassert read enable and latch in data
(basically latch in value on edge of read pulse) */
0xfff30001, /* deassert chip select, set last bit */
/*
* Unused (typically used for read burst sequence)
*/
0xfff30001, 0xfff30001, 0xfff30001, 0xfff30001, // Words 8 to 11
0xfff30001, 0xfff30001, 0xfff30001, 0xfff30001, // Words 12 to 15
0xfff30001, 0xfff30001, 0xfff30001, 0xfff30001, // Words 16 to 19
0xfff30001, 0xfff00001, 0xfff30001, 0xfff30001, // Words 20 to 23
/*
* Single Write Data
* Words 24 to 31
*/
0xfff30000, /* start off with all signals inactive */
0xfff30000,
0x0ff30000, /* assert chip select */
0x0ff30000,
0x0fa30000, /* assert write enable */
0x0fa30000,
0x0ff30004, /* deassert write enable and latch out data from CPU
onto IO bus */
0xfff30001, /* deassert chip select, set last bit */
/*
* Write command opcode
* Words 32 to 47
*/
0xfff30000, /* start off with all signals inactive */
0xfff30000,
0x0ff30000, /* assert chip select */
0x0ff30000,
0x0ff30000,
0x0ff30000,
0x0ff30000,
0x0fff0000, /* assert command latch enable */
0x0fff0000,
0x0fff0000,
0x0fff0000,
0x0faf0000, /* assert write enable */
0x0fff0030, /* deassert write enable & toggle AMX at the same time
to send value of MAR register to IO[0:7]. Nand will
latch in IO[0:7] on this edge of write enable */
0x0fff0030,
0x0ff30030, /* deassert command latch */
0xfff30031, /* deassert chip select, set last bit */
/*
* Write address byte
* Words 48 to 59
*/
0xfff30000, /* start off with all signals inactive */
0x0ff30000, /* assert chip select */
0x0ff30000,
0x0ff30000,
0x0ff3c000, /* assert address latch enable */
0x0ff3c000,
0x0ff3c000,
0x0fa3c000, /* assert write enable */
0x0ff3c030, /* deassert write enable & toggle AMX at the same time
to send value of MAR register to IO[0:7]. Nand will
latch in IO[0:7] on this edge of write enable */
0x0ff3c030,
0x0ff30030, /* deassert address latch enable */
0xfff30031, /* deassert chip select, set last bit */
/*
* Unused
*/
0xfff30001, 0xfff30001, 0xfff30001, 0xfff30001, // Words 60 to 63
};
#define UPM_SIZE_ARRAY 64
#define UPMA_WRITE_COMMAND 32
#define UPMA_WRITE_ADDRESS 48
#define MAX_CMDWAIT_200USECS 2000
static void board_upm_nand_lbus_init (void)
{
volatile immap_t *immap = (immap_t *)CFG_IMMR;
volatile ccsr_lbc_t *lbc = &immap->im_lbc;
int i, counter = 0;
volatile ccsr_gur_t *gur = &immap->im_gur;
/*
* Configure PCI2_AD[7:0] as a general purpose input
* The R/B (ready busy signal) from NAND comes in GPIO pin 15
*/
gur->gpiocr |= 0x00010000;
/*
* Now program the UPM Ram array with the different
* command sequences
*
* We use the MAMR to write the address (0-63) inside
* the RAM array that we want to program
*
* We use MDR for the data to written to the address
*
* A dummy write to flash needs to be done in order
* to actually write to the UPM array
*/
lbc->mamr = MAMX_OPCODE_WRITE_ARRAY;
/* Write word to RAM arrays */
for (i = 0; i < UPM_SIZE_ARRAY; i++) {
lbc->mamr = MAMX_OPCODE_WRITE_ARRAY | i;
if (lbc->mamr != (MAMX_OPCODE_WRITE_ARRAY | i)) {
goto failed;
}
lbc->mdr = UPMATable[i];
if (lbc->mdr != UPMATable[i]) {
goto failed;
}
/* needs to be followed by a dummy write */
*((volatile char *) (CFG_NANDFLASH_BASE)) = 0x0;
/*
* Wait until the address auto increments by 1
* to confirm that the write to the RAM location
* had completed
*/
counter = 0;
while ((lbc->mamr & 0x3f) != ((i+1)%64)) {
udelay(1);
if (counter++ > 10) {
goto failed;
}
}
}
/* change MAMR back to normal mode */
lbc->mamr = MAMX_OPCODE_NORMAL_OP;
/* wait until the write of MAMR finished */
counter = 0;
while (lbc->mamr != MAMX_OPCODE_NORMAL_OP) {
udelay(10);
if (counter++ >= 10) {
goto failed;
}
}
return;
failed:
printk("Failed to initialize LBUS for NAND flash\n");
}
static void upm_run_pattern (unsigned char io_value,
unsigned int pattern_offset)
{
volatile immap_t *immap = (immap_t *)CFG_IMMR;
volatile ccsr_lbc_t *lbc = &immap->im_lbc;
int counter;
/*
* The contents of MAR are driven onto the
* address pins during a AMX phase (see bits
* 26-27 of a RAM word field description)
*
* So we program MAR with either a NAND flash
* command opcode or a NAND flash row/column address
*
* This needs to be done before we trigger the
* start of the sequence
*/
lbc->mar = io_value << 24;
asm("sync; isync; msync");
/*
* Write in the offset of the sequence we want
*
* 32 for a command write
* 48 for an address cycle
*/
lbc->mamr = MAMX_OPCODE_RUN_ARRAY_PATTERN | pattern_offset;
asm("sync; isync; msync");
/*
* dummy write to flash needed to trigger the start of the
* pattern generation
*/
*((volatile char *) (CFG_NANDFLASH_BASE)) = 0x0;
asm("sync; isync; msync");
/*
* change MAMR back to normal mode
* Once in normal mode, the UPM will automatically run
* the sequence at RAM offset 0 when the CPU does a read
* on the flash address or the sequence at offset 24 for
* a CPU write
*/
lbc->mamr = MAMX_OPCODE_NORMAL_OP;
/* wait until the write of MAMR finished */
counter = 0;
while (lbc->mamr != MAMX_OPCODE_NORMAL_OP) {
udelay(10);
if (counter++ >= 10) {
printk("NAND: Failed to issue command/addr sequence\n");
}
}
}
static void upm_send_nand_command (unsigned char cmd)
{
upm_run_pattern(cmd, UPMA_WRITE_COMMAND);
}
static void upm_send_nand_address_byte (unsigned char addr)
{
/*
* delay between command and address or consecutive
* address bytes is needed to meet data sheet timing
*/
ndelay(10);
upm_run_pattern(addr, UPMA_WRITE_ADDRESS);
}
static void board_nand_chip_select (struct mtd_info *mtd, int chip)
{
/* CS will be turned on via LBUS & UPM state machine */
}
static void board_nand_hwcontrol (struct mtd_info *mtd, int chip)
{
/* command latch enable will be turned via UPM state machine */
}
static int board_nand_dev_ready (struct mtd_info *mtd)
{
volatile immap_t *immap = (immap_t *)CFG_IMMR;
volatile ccsr_gur_t *gur = &immap->im_gur;
/*
* GPIO pin 15 is connected to the ready busy line
* coming out of NAND flash
*
* Ready when high, busy when low
*/
if (gur->gpindr & 0x00010000) {
return (1);
}
return 0;
}
static void board_nand_cmdfunc (struct mtd_info *mtd, unsigned command,
int column, int page_addr)
{
int counter = 0;
#ifdef DEBUGNAND
printk("board_nand_cmdfunc : executing command %x column %d page %d\n",
command, column, page_addr);
#endif
switch (command) {
case NAND_CMD_PAGEPROG:
/*
* Especially at 75Mhz, we need some delay between
* the time the last data byte (to be written) is put
* on the bus and when the page program command is issued
*/
ndelay(100);
goto issue_cmd;
case NAND_CMD_READOOB:
/* emulate out of band read - copied from nand_command_lp */
column += mtd->oobblock;
command = NAND_CMD_READ0;
/* fall through */
case NAND_CMD_READ0:
case NAND_CMD_READID:
case NAND_CMD_STATUS:
case NAND_CMD_ERASE1:
case NAND_CMD_ERASE2:
case NAND_CMD_RESET:
case NAND_CMD_SEQIN:
issue_cmd:
upm_send_nand_command(command);
if (column != -1) {
upm_send_nand_address_byte(column & 0xff);
if (command != NAND_CMD_READID) {
upm_send_nand_address_byte(column >> 8);
}
}
if (page_addr != -1) {
upm_send_nand_address_byte(page_addr & 0xff);
upm_send_nand_address_byte((page_addr >> 8) & 0xff);
/* samsung is bigger than 128M */
upm_send_nand_address_byte((page_addr >> 16) & 0xff);
}
break;
default:
printk(KERN_ERR "Unsupported NAND command %d\n", command);
return;
}
/* Some commands require extra commands after the address cycle to be sent */
switch (command) {
case NAND_CMD_READ0:
ndelay(25);
upm_send_nand_command(NAND_CMD_READSTART);
break;
default:
break;
}
/*
* delay of 100nsecs before ready busy line correctly
* reflects status
*/
ndelay(100);
/*
* wait_for ready busy:
* 1. Page block read - typically takes 1.5 usecs
* 2. Page block write - typically takes 5.25 usecs
* 3. Block erase - typically takes 70 usecs
* but we will let the caller handle
* the wait
*/
if (command == NAND_CMD_ERASE2)
return;
while (!board_nand_dev_ready(mtd)) {
ndelay(100);
counter++;
if (counter > MAX_CMDWAIT_200USECS) {
printk("ERROR: NAND device still busy after 200usecs\n");
break;
}
}
}
int board_nand_init(struct nand_chip *nand)
{
/* NAND flash on this board uses BR1 in the local bus */
/* BR1 & OR1 should have been setup already - see the
* define CFG_BR1_PRELIM */
board_upm_nand_lbus_init();
nand->cmdfunc = board_nand_cmdfunc;
/* buswidth is 8 */
nand->options = 0;
/* chip select enabled via UPM state machine */
nand->select_chip = board_nand_chip_select;
nand->dev_ready = board_nand_dev_ready;
nand->eccmode = NAND_ECC_SOFT;
nand->hwcontrol = board_nand_hwcontrol;
nand->dev_ready = board_nand_dev_ready;
return 0;
}
#else
#error "U-Boot legacy NAND support not available."
#endif
#endif
More information about the U-Boot
mailing list