ubl/nand.c

1086 lines
27 KiB
C

/*
* nand.c - NAND flash functions
*
* Copyright (C) 2008 Hugo Villeneuve <hugo@hugovil.com>
*
* Based on TI DaVinci Flash and Boot Utilities, original copyright follows:
* Copyright 2008 Texas Instruments, Inc. <www.ti.com>
*
* 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., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA.
*/
#include "common.h"
#include "davinci.h"
#include "util.h"
#include "uart.h"
#include "nand.h"
/* BUS width defines */
#define BUS_8BIT 0x01
#define BUS_16BIT 0x02
#define BUS_32BIT 0x04
/* NAND flash addresses */
#define NAND_DATA_OFFSET 0x00
#define NAND_ALE_OFFSET 0x08
#define NAND_CLE_OFFSET 0x10
#define NAND_TIMEOUT 20480
/* NAND flash commands */
#define NAND_LO_PAGE 0x00
#define NAND_HI_PAGE 0x01
#define NAND_LOCK 0x2A
#define NAND_UNLOCK_START 0x23
#define NAND_UNLOCK_END 0x24
#define NAND_READ_30H 0x30
#define NAND_EXTRA_PAGE 0x50
#define NAND_RDID 0x90
#define NAND_RDIDADD 0x00
#define NAND_RESET 0xFF
#define NAND_PGRM_START 0x80
#define NAND_PGRM_END 0x10
#define NAND_RDY 0x40
#define NAND_PGM_FAIL 0x01
#define NAND_BERASEC1 0x60
#define NAND_BERASEC2 0xD0
#define NAND_STATUS 0x70
/* Status output */
#define NAND_NANDFSR_READY 0x01
#define NAND_STATUS_WRITEREADY 0xC0
#define NAND_STATUS_ERROR 0x01
#define NAND_STATUS_BUSY 0x40
#define UNKNOWN_NAND 0xFF /* Unknown device id */
/* Gives the page size in bytes without the spare bytes */
#define NANDFLASH_PAGESIZE(x) ((x >> 8) << 8)
union flash_data {
uint8_t c;
uint16_t w;
uint32_t l;
};
union flash_ptr {
volatile uint8_t *cp;
volatile uint16_t *wp;
volatile uint32_t *lp;
};
struct nand_dev_infos_t {
uint8_t id; /* Device ID */
uint16_t num_blocks; /* Number of blocks */
uint8_t pages_per_block; /* Number of pages per block */
uint16_t bytes_per_page; /* Number of bytes per page (with spare) */
};
struct nand_info_t {
uint32_t base_addr; /* Base address of NAND CS memory space. */
int bus_width; /* Bus width: 0 = 8 bits, 1 = 16 bits */
int id; /* Index into nand_dev_infos_t array. */
int num_blocks; /* Number of blocks */
int pages_per_block; /* Number of pages per block */
int bytes_per_page; /* Number of bytes per page (with spare) */
int num_cab; /* Number of Column address cycles */
int num_rab; /* Number of Row address cycles */
uint32_t ecc_mask; /* Mask for ECC register */
int large_page; /* True if page size >= 2048 bytes */
int ecc_index; /* ECC position is different for small and
* large page devices. */
int chunk_size; /* Always read/write in 512 bytes chunk max.
* This will be set based on page size. */
int spare_bytes; /* Number of spare area bytes per page. */
int blk_addr_shift; /* Number of bits by which to shift block address */
int page_addr_shift; /* Number of bits by which to shift page address */
int cs_offset; /*
* Chip-select offset:
* 0 = CS2 space
* 1 = CS3 space
* 2 = CS4 space
* 3 = CS5 space
*/
};
/* Buffer for storing data read from NAND flash */
static uint8_t read_buf[MAX_PAGE_SIZE] __attribute__((section(".ddrram")));
/* Symbol from linker script */
extern uint32_t __NANDFlash;
/* structure for holding details about the NAND device itself */
static volatile struct nand_info_t nand_info;
/* Table of ROM supported NAND devices */
static const struct nand_dev_infos_t nand_dev_infos[] = {
/* id, num_blocks, pages_per_block, bytes_per_page */
{0x6E, 256, 16, 256+8}, /* 1 MB */
{0x68, 256, 16, 256+8}, /* 1 MB */
{0xEC, 256, 16, 256+8}, /* 1 MB */
{0xE8, 256, 16, 256+8}, /* 1 MB */
{0xEA, 512, 16, 256+8}, /* 2 MB */
{0xE3, 512, 16, 512+16}, /* 4 MB */
{0xE5, 512, 16, 512+16}, /* 4 MB */
{0xE6, 1024, 16, 512+16}, /* 8 MB */
{0x39, 1024, 16, 512+16}, /* 8 MB */
{0x6B, 1024, 16, 512+16}, /* 8 MB */
{0x73, 1024, 32, 512+16}, /* 16 MB */
{0x33, 1024, 32, 512+16}, /* 16 MB */
{0x75, 2048, 32, 512+16}, /* 32 MB */
{0x35, 2048, 32, 512+16}, /* 32 MB */
{0x43, 1024, 32, 512+16}, /* 16 MB 0x1243 */
{0x45, 2048, 32, 512+16}, /* 32 MB 0x1245 */
{0x53, 1024, 32, 512+16}, /* 16 MB 0x1253 */
{0x55, 2048, 32, 512+16}, /* 32 MB 0x1255 */
{0x36, 4096, 32, 512+16}, /* 64 MB */
{0x46, 4096, 32, 512+16}, /* 64 MB 0x1346 */
{0x56, 4096, 32, 512+16}, /* 64 MB 0x1356 */
{0x76, 4096, 32, 512+16}, /* 64 MB */
{0x74, 8192, 32, 512+16}, /* 128 MB 0x1374 */
{0x79, 8192, 32, 512+16}, /* 128 MB */
{0x71, 16384, 32, 512+16}, /* 256 MB */
{0xF1, 1024, 64, 2048+64}, /* 128 MB - Big Block */
{0xA1, 1024, 64, 2048+64}, /* 128 MB - Big Block */
{0xAA, 2048, 64, 2048+64}, /* 256 MB - Big Block */
{0xDA, 2048, 64, 2048+64}, /* 256 MB - Big Block */
{0xDC, 4096, 64, 2048+64}, /* 512 MB - Big Block */
{0xAC, 4096, 64, 2048+64}, /* 512 MB - Big Block */
{0xB1, 1024, 64, 2048+64}, /* 128 MB - Big Block */
{0xC1, 1024, 64, 2048+64}, /* 128 MB - Big Block */
{0xD3, 4096, 64, 2048+64}, /* 512 MB - Big Block */
{0x00, 0, 0, 0} /* Indicate end of table */
};
static volatile uint8_t *
flash_make_addr(uint32_t baseAddr, uint32_t offset)
{
return (volatile uint8_t *) (baseAddr + offset);
}
static void
flash_write_data(uint32_t offset, uint32_t data)
{
volatile union flash_ptr addr;
union flash_data dataword;
dataword.l = data;
addr.cp = flash_make_addr(nand_info.base_addr, offset);
switch (nand_info.bus_width) {
case BUS_8BIT:
*addr.cp = dataword.c;
break;
case BUS_16BIT:
*addr.wp = dataword.w;
break;
}
}
static void
flash_write_cmd(uint32_t cmd)
{
flash_write_data(NAND_CLE_OFFSET, cmd);
}
static void
flash_write_addr(uint32_t addr)
{
flash_write_data(NAND_ALE_OFFSET, addr);
}
static void
flash_write_bytes(const uint8_t *src, uint32_t numBytes)
{
volatile union flash_ptr destAddr, srcAddr;
uint32_t i;
srcAddr.cp = (volatile uint8_t *) src;
destAddr.cp = flash_make_addr(nand_info.base_addr, NAND_DATA_OFFSET);
switch (nand_info.bus_width) {
case BUS_8BIT:
for (i = 0; i < numBytes; i++)
*destAddr.cp = *srcAddr.cp++;
break;
case BUS_16BIT:
for (i = 0; i < (numBytes >> 1); i++)
*destAddr.wp = *srcAddr.wp++;
break;
}
}
static void
flash_write_addr_bytes(uint32_t numAddrBytes, uint32_t addr)
{
uint32_t i;
for (i = 0; i < numAddrBytes; i++)
flash_write_addr((addr >> (8*i)) & 0xff);
}
static void
flash_write_row_addr_bytes(uint32_t block, uint32_t page)
{
uint32_t row_addr;
row_addr =
(block << (nand_info.blk_addr_shift - nand_info.page_addr_shift)) | page;
flash_write_addr_bytes(nand_info.num_rab, row_addr);
}
static void
flash_write_addr_cycles(uint32_t block, uint32_t page)
{
flash_write_addr_bytes(nand_info.num_cab, 0x00000000);
flash_write_row_addr_bytes(block, page);
}
static uint32_t
flash_read_data(void)
{
volatile union flash_ptr addr;
union flash_data cmdword;
cmdword.l = 0x0;
addr.cp = flash_make_addr(nand_info.base_addr, NAND_DATA_OFFSET);
switch (nand_info.bus_width) {
case BUS_8BIT:
cmdword.c = *addr.cp;
break;
case BUS_16BIT:
cmdword.w = *addr.wp;
break;
}
return cmdword.l;
}
static void
flash_read_bytes(uint8_t *dest, uint32_t numBytes)
{
volatile union flash_ptr destAddr, srcAddr;
uint32_t i;
destAddr.cp = (volatile uint8_t *) dest;
srcAddr.cp = flash_make_addr(nand_info.base_addr, NAND_DATA_OFFSET);
switch (nand_info.bus_width) {
case BUS_8BIT:
for (i = 0; i < numBytes; i++)
*destAddr.cp++ = *srcAddr.cp;
break;
case BUS_16BIT:
for (i = 0; i < (numBytes >> 1); i++)
*destAddr.wp++ = *srcAddr.wp;
break;
}
}
/* Poll bit of NANDFSR to indicate ready */
static int
nand_wait_for_ready(uint32_t timeout)
{
volatile uint32_t cnt = timeout;
uint32_t ready;
waitloop(200);
do {
ready = AEMIF->NANDFSR & NAND_NANDFSR_READY;
cnt--;
} while ((cnt > 0) && !ready);
if (cnt == 0) {
log_info("NAND busy timeout");
return E_FAIL;
}
return E_PASS;
}
/* Wait for the status to be ready in NAND register
* There were some problems reported in DM320 with Ready/Busy pin
* not working with all NANDs. So this check has also been added.
*/
static int
nand_wait_for_status(uint32_t timeout)
{
volatile uint32_t cnt;
uint32_t status;
cnt = timeout;
do {
flash_write_cmd(NAND_STATUS);
status = flash_read_data() &
(NAND_STATUS_ERROR | NAND_STATUS_BUSY);
cnt--;
} while ((cnt > 0) && !status);
if (cnt == 0) {
log_info("NAND status timeout");
return E_FAIL;
}
return E_PASS;
}
/* Read the current ECC calculation and restart process */
static uint32_t
nand_read_ecc(void)
{
uint32_t retval;
/* Read and mask appropriate (based on CSn space flash is in)
* ECC register */
retval = ((uint32_t *)(&(AEMIF->NANDF1ECC)))[nand_info.cs_offset] &
nand_info.ecc_mask;
waitloop(5);
#ifdef NAND_DEBUG
uart_send_str("Value read from ECC register: ");
uart_send_hexnum(retval, 8);
uart_send_lf();
#endif
/* Write appropriate bit to start ECC calculations */
AEMIF->NANDFCR |= (1<<(8 + (nand_info.cs_offset)));
return retval;
}
/* Get details of the NAND flash used from the id and the table of NAND
* devices. */
static int
nand_get_details(uint8_t *out_manID, uint8_t *out_deviceID)
{
uint32_t manID, deviceID, i, j;
/* Issue device read ID command. */
flash_write_cmd(NAND_RDID);
flash_write_addr(NAND_RDIDADD);
/* Read ID bytes */
manID = flash_read_data() & 0xFF;
deviceID = flash_read_data() & 0xFF;
j = flash_read_data() & 0xFF;
j = flash_read_data() & 0xFF;
*out_manID = manID;
*out_deviceID = deviceID;
uart_send_str(" ID:");
uart_send_hexnum(deviceID, 2);
if (nand_info.bus_width == BUS_16BIT)
uart_send_str(", 16");
else
uart_send_str(", 8");
log_info("-bit bus");
i = 0;
while (nand_dev_infos[i].id != 0x00) {
if (deviceID == nand_dev_infos[i].id) {
nand_info.id = (uint8_t) nand_dev_infos[i].id;
nand_info.pages_per_block =
nand_dev_infos[i].pages_per_block;
nand_info.num_blocks = nand_dev_infos[i].num_blocks;
nand_info.bytes_per_page = NANDFLASH_PAGESIZE(
nand_dev_infos[i].bytes_per_page);
nand_info.spare_bytes = nand_dev_infos[i].bytes_per_page -
nand_info.bytes_per_page;
/* Configure small or large page device. */
if (nand_info.bytes_per_page >= 2048) {
/* Set the large page flag */
nand_info.large_page = true;
nand_info.ecc_index = 2;
nand_info.chunk_size = 512; /* Limit to 512 bytes */
} else {
/* Clear the large page flag */
nand_info.large_page = false;
nand_info.ecc_index = 0;
nand_info.chunk_size = nand_info.bytes_per_page;
}
/* Setup address shift values */
j = 0;
while ((nand_info.pages_per_block >> j) > 1)
j++;
nand_info.blk_addr_shift = j;
nand_info.page_addr_shift = (nand_info.large_page) ? 16 : 8;
nand_info.blk_addr_shift += nand_info.page_addr_shift;
/* Set number of column address bytes needed */
nand_info.num_cab = nand_info.page_addr_shift >> 3;
j = 0;
while ((nand_info.num_blocks >> j) > 1)
j++;
/* Set number of row address bytes needed */
if ((nand_info.blk_addr_shift + j) <= 24)
nand_info.num_rab = 3 -
nand_info.num_cab;
else if ((nand_info.blk_addr_shift + j) <= 32)
nand_info.num_rab = 4 -
nand_info.num_cab;
else
nand_info.num_rab = 5 -
nand_info.num_cab;
/* Set the ECC bit mask */
if (nand_info.bytes_per_page < 512)
nand_info.ecc_mask = 0x07FF07FF;
else
nand_info.ecc_mask = 0x0FFF0FFF;
/* Report informations */
uart_send_str(" Blocks: ");
uart_send_hexnum(nand_info.num_blocks, 5);
uart_send_str(", Pages/block: ");
uart_send_hexnum(nand_info.pages_per_block, 3);
uart_send_str(", Bytes per page: ");
uart_send_hexnum(nand_info.bytes_per_page, 4);
uart_send_lf();
/* Report additional debug informations */
#ifdef NAND_DEBUG
uart_send_str(" Page shift: ");
uart_send_hexnum(nand_info.page_addr_shift, 2);
uart_send_lf();
uart_send_str(" Block shift: ");
uart_send_hexnum(nand_info.blk_addr_shift, 2);
uart_send_lf();
uart_send_str(" Column address bytes: ");
uart_send_hexnum(nand_info.num_cab, 2);
uart_send_lf();
uart_send_str(" Row address bytes: ");
uart_send_hexnum(nand_info.num_rab, 2);
uart_send_lf();
uart_send_str(" ECC mask: ");
uart_send_hexnum(nand_info.ecc_mask, 8);
uart_send_lf();
#endif
return E_PASS;
}
i++;
}
/* No match was found for the device ID */
return E_FAIL;
}
static int
nand_set_a1cr(uint8_t manID, uint8_t deviceID)
{
if (deviceID != 0xA1) {
log_info( "Unsupported NAND device" );
return E_FAIL;
}
switch (manID) {
/* ST/Numonyx */
case 0x20:
AEMIF->A1CR = 0x1844431C;
break;
/* Micron */
case 0x2C:
AEMIF->A1CR = 0x102442EC;
break;
/* Spansion */
case 0x01:
AEMIF->A1CR = 0x1844437C;
break;
/* Toshiba */
case 0x98:
AEMIF->A1CR = 0x102442DC;
break;
default:
log_info( "Unsupported NAND device" );
return E_FAIL;
}
return E_PASS;
}
static void
nand_write_spare(uint32_t eccvalue)
{
uint32_t spare_data[4] = {
0xFFFFFFFF,
0xFFFFFFFF,
0xFFFFFFFF,
0xFFFFFFFF
};
/* Place the ECC values where the RBL expects them */
spare_data[nand_info.ecc_index] = eccvalue;
/* Write spare bytes infos */
if (nand_info.bytes_per_page == 256)
flash_write_bytes((uint8_t *) spare_data, 8);
else
flash_write_bytes((uint8_t *) spare_data, 16);
}
/*
* RBL-expected layout for large page NAND (ex: 2048 bytes/page):
*
* DM35x DM644x
* -----------------------------
* 512 DATA 2048 DATA
* 16 SPARE 64 SPARE
* 512 DATA
* 16 SPARE
* 512 DATA
* 16 SPARE
* 512 DATA
* 16 SPARE
*
* So for big block NAND devices (bytes per page > 512) on the DM35x, we must
* write 512 bytes and write the ECC immediately after that data, and repeat
* until all the page is written.
*/
/* Generic routine to write a page of data to NAND */
static int
nand_write_page(uint32_t block, uint32_t page, const uint8_t *src)
{
uint32_t hw_ecc[4]; /* Maximum of 2048 bytes/page (4 * 512 = 2048) */
uint8_t numWrites, i;
numWrites = (nand_info.bytes_per_page >> 9); /* Divide by 512 */
if (numWrites == 0)
numWrites++;
/* Write program command */
flash_write_cmd(NAND_PGRM_START);
/* Write address bytes */
flash_write_addr_cycles(block, page);
/* Starting the ECC in the NANDFCR register for CS2 (bit no.8) */
nand_read_ecc();
/* Write data */
for (i = 0; i < numWrites; i++) {
/* Write data to page */
flash_write_bytes(src, nand_info.chunk_size);
/* Read the ECC value */
hw_ecc[i] = nand_read_ecc();
/* Format ECC */
endian_data(&(hw_ecc[i]));
#if defined(DM35x)
/* Write spare area */
nand_write_spare(hw_ecc[i]);
#endif
/* Increment the pointer */
src += nand_info.chunk_size;
}
#if defined(DM644x)
for (i = 0; i < numWrites; i++) {
nand_write_spare(hw_ecc[i]);
}
#endif
/* Write program end command */
flash_write_cmd(NAND_PGRM_END);
/* Wait for the device to be ready */
if (nand_wait_for_ready(NAND_TIMEOUT) != E_PASS)
return E_FAIL;
/* Return status check result */
return nand_wait_for_status(NAND_TIMEOUT);
}
static uint32_t
nand_read_spare(void)
{
uint32_t spare_ecc[4], spare_ecc_temp;
/* Read the stored ECC value(s) */
if (nand_info.bytes_per_page == 256)
flash_read_bytes((uint8_t *) spare_ecc, 8);
else
flash_read_bytes((uint8_t *) spare_ecc, 16);
spare_ecc_temp = spare_ecc[nand_info.ecc_index];
/* Format ECC */
endian_data(&spare_ecc_temp);
return spare_ecc_temp;
}
/*
* GPLv2 code taken from the kernel to correct the bit error.
* The content of the ECC register is in the sprue20c.pdf. For
* the odd/even there are four bits spare each. The kernel is
* shifting this around and it is the easiest just to do the
* same.
*/
static uint32_t squeeze_ecc_bits(uint32_t tmp)
{
/* Squeeze 4 bytes ECC into 3 bytes by removing RESERVED bits
* and shifting. RESERVED bits are 31 to 28 and 15 to 12. */
tmp = (tmp & 0x00000fff) | ((tmp & 0x0fff0000) >> 4);
/* Invert so that erased block ECC is correct */
return ~tmp;
}
static int nand_check_fix(
const uint32_t _calc_ecc,
const uint32_t _ecc_nand, uint8_t *dat, int size)
{
uint32_t ecc_nand, ecc_calc;
ecc_calc = squeeze_ecc_bits(_calc_ecc);
ecc_nand = squeeze_ecc_bits(_ecc_nand);
uint32_t diff = ecc_calc ^ ecc_nand;
if (diff) {
if ((((diff >> 12) ^ diff) & 0xfff) == 0xfff) {
/* Correctable error */
if ((diff >> (12 + 3)) < size) {
uint8_t find_bit = 1 << ((diff >> 12) & 7);
uint32_t find_byte = diff >> (12 + 3);
dat[find_byte] ^= find_bit;
log_info("Correcting single bit error.");
uart_send_str("BYTE=");
uart_send_hexnum(find_byte, 8);
uart_send_str(" BIT=");
uart_send_hexnum(find_bit, 8);
uart_send_lf();
return 1;
} else {
log_info("Too many bit errors:");
uart_send_hexnum(diff >> (12+3), 8);
uart_send_lf();
return -1;
}
} else if (!(diff & (diff - 1))) {
/* Single bit ECC error in the ECC itself,
nothing to fix */
log_info("Bit error in the spare data. Ignoring");
return 1;
} else {
/* Uncorrectable error */
log_info("Uncorrectable error");
return -1;
}
}
return 0;
}
/* Read a page from NAND */
int
nand_read_page(uint32_t block, uint32_t page, uint8_t *orig_dest)
{
uint32_t hw_ecc[4];
uint32_t spare_ecc[4];
uint8_t numReads, i;
uint8_t *dest = orig_dest;
numReads = (nand_info.bytes_per_page >> 9); /* Divide by 512 */
if (numReads == 0)
numReads++;
/* Write read command */
flash_write_cmd(NAND_LO_PAGE);
/* Write address bytes */
flash_write_addr_cycles(block, page);
/* Additional confirm command for big_block devices */
if (nand_info.large_page)
flash_write_cmd(NAND_READ_30H);
/* Wait for data to be available */
if (nand_wait_for_ready(NAND_TIMEOUT) != E_PASS)
return E_FAIL;
/* Starting the ECC in the NANDFCR register for CS2(bit no.8) */
nand_read_ecc();
/* Read the page data */
for (i = 0; i < numReads; i++) {
/* Read data bytes */
flash_read_bytes(dest, nand_info.chunk_size);
/* Read hardware computed ECC */
hw_ecc[i] = nand_read_ecc();
#if defined(DM35x)
/* Read spare area ECC */
spare_ecc[i] = nand_read_spare();
#endif
/* Increment the pointer */
dest += nand_info.chunk_size;
}
#if defined(DM644x)
for (i = 0; i < numReads; i++) {
spare_ecc[i] = nand_read_spare();
}
#endif
#ifndef NAND_BYPASS_READ_PAGE_ECC_CHECK
for (i = 0; i < numReads; i++) {
/* Verify ECC values */
if (nand_check_fix(hw_ecc[i], spare_ecc[i], &orig_dest[i * nand_info.chunk_size], nand_info.chunk_size) < 0) {
log_info("NAND ECC failure:");
uart_send_str("HW = ");
uart_send_hexnum(hw_ecc[i], 8);
uart_send_lf();
uart_send_str("SPARE =");
uart_send_hexnum(spare_ecc[i], 8);
uart_send_lf();
return E_FAIL;
}
}
#endif /* NAND_BYPASS_READ_PAGE_ECC_CHECK */
/* Return status check result */
return nand_wait_for_status(NAND_TIMEOUT);
}
/* Verify data written by reading and comparing byte for byte */
static int
nand_verify_page(int block, int page, const uint8_t *src)
{
int i;
if (nand_read_page(block, page, read_buf) != E_PASS)
return E_FAIL;
for (i = 0; i < nand_info.bytes_per_page; i++) {
/* Check for data read errors */
if (src[i] != read_buf[i]) {
int k = i;
uart_send_str("NAND verify page failed at block ");
uart_send_hexnum(block, 4);
uart_send_str(", page ");
uart_send_hexnum(page, 4);
uart_send_str(", offset ");
uart_send_hexnum(i, 4);
uart_send_lf();
for (k = i - 8; k < (i + 20); k += 4) {
uart_send_str("offset ");
uart_send_hexnum(k, 4);
uart_send_str(", ram=");
uart_send_hexnum(*((uint32_t *) &src[k]), 8);
uart_send_str(", nand=");
uart_send_hexnum(*((uint32_t *) &read_buf[k]), 8);
uart_send_lf();
}
return E_FAIL;
}
}
return E_PASS;
}
/* NAND Flash unprotect command */
static uint32_t
nand_unprotect_blocks(uint32_t startBlkNum, uint32_t blkCnt)
{
uint32_t endBlkNum;
endBlkNum = startBlkNum + blkCnt - 1;
uart_send_str("Unprotecting blocks ");
uart_send_hexnum(startBlkNum, 4);
uart_send_str(" to ");
uart_send_hexnum(endBlkNum, 4);
uart_send_lf();
/* Do bounds checking */
if (endBlkNum >= nand_info.num_blocks) {
log_fail("Invalid last block");
return E_FAIL;
}
flash_write_cmd(NAND_UNLOCK_START);
flash_write_row_addr_bytes(startBlkNum, 0);
flash_write_cmd(NAND_UNLOCK_END);
flash_write_row_addr_bytes(endBlkNum, 0);
return E_PASS;
}
/* NAND Flash protect command */
static void
nand_protect_blocks(void)
{
log_info("Protecting the entire NAND flash");
flash_write_cmd(NAND_LOCK);
}
/* NAND Flash erase block function */
static uint32_t
nand_erase_blocks(uint32_t startBlkNum, uint32_t blkCnt)
{
uint32_t i;
/* Do bounds checking */
if ((startBlkNum + blkCnt - 1) >= nand_info.num_blocks)
return E_FAIL;
/* Output info about what we are doing */
uart_send_str("Erasing blocks ");
uart_send_hexnum(startBlkNum, 4);
uart_send_str(" to ");
uart_send_hexnum(startBlkNum + blkCnt - 1, 4);
uart_send_lf();
for (i = 0; i < blkCnt; i++) {
/* Start erase command */
flash_write_cmd(NAND_BERASEC1);
/* Write the row addr bytes only */
flash_write_row_addr_bytes(startBlkNum + i, 0);
/* Confirm erase command */
flash_write_cmd(NAND_BERASEC2);
/* Wait for the device to be ready */
if (nand_wait_for_ready(NAND_TIMEOUT) != E_PASS)
return E_FAIL;
/* Verify the op succeeded by reading status from flash */
if (nand_wait_for_status(NAND_TIMEOUT) != E_PASS)
return E_FAIL;
}
return E_PASS;
}
/* Initialize NAND interface and find the details of the NAND used */
int
nand_init(void)
{
uint32_t width;
uint32_t *CSRegs;
uint8_t manID, deviceID;
log_info("Initializing NAND flash:");
#ifdef NAND_BYPASS_READ_PAGE_ECC_CHECK
log_info(" Bypassing ECC checks");
#endif /* NAND_BYPASS_READ_PAGE_ECC_CHECK */
/* Set NAND flash base address */
nand_info.base_addr = (uint32_t) &__NANDFlash;
/* Get the cs_offset (can be 0 through 3 - corresponds with CS2 through
* CS5) */
nand_info.cs_offset = (nand_info.base_addr >> 25) - 1;
/* Setting the nand_width = 0(8 bit NAND) or 1(16 bit NAND). AEMIF CS2
* bus Width is given by the BOOTCFG(bit no.5). */
width = (((SYSTEM->BOOTCFG) & 0x20) >> 5);
nand_info.bus_width = (width)?BUS_16BIT:BUS_8BIT;
/* Setup AEMIF registers for NAND */
CSRegs = (uint32_t *) &(AEMIF->A1CR);
/* Set correct AxCR reg */
CSRegs[nand_info.cs_offset] = 0x3FFFFFFC | width;
/* NAND enable for CSx. */
AEMIF->NANDFCR |= (0x1 << (nand_info.cs_offset));
nand_read_ecc();
/* Send reset command to NAND */
flash_write_cmd(NAND_RESET);
if (nand_wait_for_ready(NAND_TIMEOUT) != E_PASS)
return E_FAIL;
if (nand_get_details(&manID, &deviceID) != E_PASS)
return E_FAIL;
return nand_set_a1cr(manID, deviceID);
}
static int
nand_write_verify_page(int block, int page, const uint8_t *src)
{
int status;
status = nand_write_page(block, page, src);
if (status != E_PASS)
return E_FAIL;
waitloop(200);
/* Verify the page just written */
return nand_verify_page(block, page, src);
}
int
nand_write_prog(struct nand_image_descriptor_t *im_desc, const uint8_t *src,
size_t size)
{
int num_blocks;
int max_block_num;
int page_num;
uint32_t count_mask;
im_desc->page_num = 1; /* Always start data in page 1 */
/* Do some rounding based on data buffer size */
im_desc->size_in_pages = 0;
while ((im_desc->size_in_pages * nand_info.bytes_per_page) < size)
im_desc->size_in_pages++;
/* Get total number of blocks needed */
num_blocks = 0;
while ((num_blocks * nand_info.pages_per_block) <
(im_desc->size_in_pages + 1))
num_blocks++;
uart_send_str("Needed blocks: ");
uart_send_hexnum(num_blocks, 4);
uart_send_lf();
uart_send_str("Needed pages: ");
uart_send_hexnum(im_desc->size_in_pages, 4);
uart_send_lf();
/* Check whether writing UBL or APP (based on destination block) */
if (im_desc->block_num <= END_UBL_BLOCK_NUM)
max_block_num = END_UBL_BLOCK_NUM;
else
max_block_num = im_desc->block_num + MAX_BLOCK_PER_UBOOT - 1;
NAND_WRITE_RETRY:
if (im_desc->block_num > max_block_num) {
log_fail("Block > last block");
return E_FAIL;
}
uart_send_str("Trying block ");
uart_send_hexnum(im_desc->block_num, 4);
uart_send_lf();
/* Unprotect all needed blocks of the Flash */
if (nand_unprotect_blocks(im_desc->block_num, num_blocks) != E_PASS) {
im_desc->block_num++;
log_info("Unprotect failed");
goto NAND_WRITE_RETRY;
}
/* Erase the block where the header goes and the data starts */
if (nand_erase_blocks(im_desc->block_num, num_blocks) != E_PASS) {
im_desc->block_num++;
log_info("Erase failed");
goto NAND_WRITE_RETRY;
}
#ifdef NAND_DEBUG_WRITE_RAMP
{
int k;
/* Usefull for debugging NAND ECC and spare bytes errors. */
for (k = 0; k < 512; k++)
ptr[k] = 0xCAFE0000 | k;
}
#endif
page_num = 0; /* Start in page 0. */
if (im_desc->magic != UBL_CMD_FLASH_DATA) {
/* Write the header to page 0. */
log_info("Writing header");
if (nand_write_verify_page(im_desc->block_num, page_num,
(uint8_t *) im_desc) != E_PASS)
return E_FAIL;
/* Set starting page number for next data portion. */
page_num = 1;
}
/* The following assumes power of 2 page_cnt - *should* always be
* valid. */
count_mask = nand_info.pages_per_block - 1;
log_info("Writing data");
do {
/* Write data on a per page basis */
if (nand_write_verify_page(im_desc->block_num,
page_num & count_mask, src)
!= E_PASS)
return E_FAIL;
page_num++;
src += nand_info.bytes_per_page;
if (!(page_num & count_mask))
im_desc->block_num++;
} while (page_num <= im_desc->size_in_pages);
nand_protect_blocks();
return E_PASS;
}
int
nand_erase_all(void)
{
/* Unprotect the NAND Flash */
nand_unprotect_blocks(0, nand_info.num_blocks - 1);
/* Erase all the pages */
if (nand_erase_blocks(0, nand_info.num_blocks - 1) != E_PASS)
return E_FAIL;
/* Protect the device */
nand_protect_blocks();
return E_PASS;
}
int
nand_get_pages_per_block(void)
{
return nand_info.pages_per_block;
}
int
nand_get_bytes_per_page(void)
{
return nand_info.bytes_per_page;
}
int
nand_get_bytes_per_block(void)
{
return nand_info.pages_per_block * nand_info.bytes_per_page;
}