* [U-Boot-Users] NAND flash driver for MPC 8548
@ 2007-03-30 6:19 sagarwal
0 siblings, 0 replies; 7+ messages in thread
From: sagarwal @ 2007-03-30 6:19 UTC (permalink / raw)
To: u-boot
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
^ permalink raw reply [flat|nested] 7+ messages in thread
* [U-Boot-Users] NAND flash driver for MPC 8548
@ 2007-03-30 6:33 sagarwal
2007-03-30 13:21 ` Ben Warren
0 siblings, 1 reply; 7+ messages in thread
From: sagarwal @ 2007-03-30 6:33 UTC (permalink / raw)
To: u-boot
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 enclosed.
shalabh
/*
*
* 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
^ permalink raw reply [flat|nested] 7+ messages in thread
* [U-Boot-Users] NAND flash driver for MPC 8548
2007-03-30 6:33 sagarwal
@ 2007-03-30 13:21 ` Ben Warren
[not found] ` <20070330184653.GC31819@teaktechnologies.com>
0 siblings, 1 reply; 7+ messages in thread
From: Ben Warren @ 2007-03-30 13:21 UTC (permalink / raw)
To: u-boot
Shalabh,
On Thu, 2007-03-29 at 23:33 -0700, sagarwal wrote:
> 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 enclosed.
>
> shalabh
Is your intent to have this included in the U-boot tree?
regards,
Ben
^ permalink raw reply [flat|nested] 7+ messages in thread
* [U-Boot-Users] NAND flash driver for MPC 8548
[not found] ` <20070330184653.GC31819@teaktechnologies.com>
@ 2007-03-30 19:04 ` Ben Warren
2007-03-30 19:48 ` Andy Fleming
2007-03-30 20:12 ` Wolfgang Denk
0 siblings, 2 replies; 7+ messages in thread
From: Ben Warren @ 2007-03-30 19:04 UTC (permalink / raw)
To: u-boot
Shalabh,
On Fri, 2007-03-30 at 11:46 -0700, sagarwal wrote:
> Ben
>
> My intent was more to let other people looking for
> a NAND driver for the 8548 know about it. Right
> now our project here is still some ways away from
> merging our diffs. I've also exchanged emails
> with Andrew Fleming. I guess I sent the code
> in haste. I apologize.
>
> shalabh
No need to apologize. You did nothing wrong. If somebody finds this
useful it's a good thing.
regards,
Ben
^ permalink raw reply [flat|nested] 7+ messages in thread
* [U-Boot-Users] NAND flash driver for MPC 8548
2007-03-30 19:04 ` Ben Warren
@ 2007-03-30 19:48 ` Andy Fleming
2007-03-30 20:06 ` Chris Fester
2007-03-30 20:12 ` Wolfgang Denk
1 sibling, 1 reply; 7+ messages in thread
From: Andy Fleming @ 2007-03-30 19:48 UTC (permalink / raw)
To: u-boot
On 3/30/07, Ben Warren <bwarren@qstreams.com> wrote:
> Shalabh,
>
> On Fri, 2007-03-30 at 11:46 -0700, sagarwal wrote:
> > Ben
> >
> > My intent was more to let other people looking for
> > a NAND driver for the 8548 know about it. Right
> > now our project here is still some ways away from
> > merging our diffs. I've also exchanged emails
> > with Andrew Fleming. I guess I sent the code
> > in haste. I apologize.
> >
> > shalabh
>
> No need to apologize. You did nothing wrong. If somebody finds this
> useful it's a good thing.
I certainly hope I didn't give the impression you shouldn't have sent
the code out. It's good code, and some people will certainly find it
useful. My goal was to let you know what needed to be done to get the
code merged.
Thanks,
Andy
^ permalink raw reply [flat|nested] 7+ messages in thread
* [U-Boot-Users] NAND flash driver for MPC 8548
2007-03-30 19:48 ` Andy Fleming
@ 2007-03-30 20:06 ` Chris Fester
0 siblings, 0 replies; 7+ messages in thread
From: Chris Fester @ 2007-03-30 20:06 UTC (permalink / raw)
To: u-boot
Shalabh (or anyone else who's interested),
> On Fri, 2007-03-30 at 11:46 -0700, sagarwal wrote:
> > Ben
> >
> > My intent was more to let other people looking for
> > a NAND driver for the 8548 know about it. Right
> > now our project here is still some ways away from
> > merging our diffs. I've also exchanged emails
> > with Andrew Fleming. I guess I sent the code
> > in haste. I apologize.
We've got a preliminary driver for mpc834x series chips working with the
UPM and an STMicro 128MB NAND flash for Linux (yeah, sorry for being
off-topic). It's still rough around the edges and not ready for a
community merge, but it works semi-reliably now. Let me know off list
if you'd like the source.
Share and Enjoy! :)
Chris
^ permalink raw reply [flat|nested] 7+ messages in thread
* [U-Boot-Users] NAND flash driver for MPC 8548
2007-03-30 19:04 ` Ben Warren
2007-03-30 19:48 ` Andy Fleming
@ 2007-03-30 20:12 ` Wolfgang Denk
1 sibling, 0 replies; 7+ messages in thread
From: Wolfgang Denk @ 2007-03-30 20:12 UTC (permalink / raw)
To: u-boot
In message <1175281460.23521.38.camel@saruman.qstreams.net> you wrote:
>
> > My intent was more to let other people looking for
> > a NAND driver for the 8548 know about it. Right
...
> No need to apologize. You did nothing wrong. If somebody finds this
> useful it's a good thing.
It would be even more useful if it came in proper patch format.
Best regards,
Wolfgang Denk
--
DENX Software Engineering GmbH, HRB 165235 Munich, CEO: Wolfgang Denk
Office: Kirchenstr. 5, D-82194 Groebenzell, Germany
Phone: (+49)-8142-66989-10 Fax: (+49)-8142-66989-80 Email: wd at denx.de
Unix is like a toll road on which you have to stop every 50 feet to
pay another nickel. But hey! You only feel 5 cents poorer each time.
- Larry Wall in <1992Aug13.192357.15731@netlabs.com>
^ permalink raw reply [flat|nested] 7+ messages in thread
end of thread, other threads:[~2007-03-30 20:12 UTC | newest]
Thread overview: 7+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2007-03-30 6:19 [U-Boot-Users] NAND flash driver for MPC 8548 sagarwal
-- strict thread matches above, loose matches on Subject: below --
2007-03-30 6:33 sagarwal
2007-03-30 13:21 ` Ben Warren
[not found] ` <20070330184653.GC31819@teaktechnologies.com>
2007-03-30 19:04 ` Ben Warren
2007-03-30 19:48 ` Andy Fleming
2007-03-30 20:06 ` Chris Fester
2007-03-30 20:12 ` Wolfgang Denk
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox