mirror of
https://github.com/brain-hackers/u-boot-brain
synced 2024-08-16 23:18:51 +09:00
![Sughosh Ganu](/assets/img/avatar_default.png)
The patch adds basic board support for TI's OMAP-L138 based Hawkboard. This board is pretty similar to the da850 EVM. Support for nand and network access is added in this version. The following bootup procedure is used. At reset, the Rom Boot Loader(RBL), initialises the ddr and the nand controllers and copies the second stage bootloader(nand_spl) to RAM. The secondary bootloader then copies u-boot from a predefined location in the nand flash to the RAM, and passes control to the u-boot image. Three config options are supported * hawkboard_config - Used to create the u-boot.bin. Tftp the u-boot.bin image to the RAM from u-boot, and flash to the nand flash at address 0xe0000. * hawkboard_nand_config - Used to generate the secondary bootloader(nand_spl) image. This creates an elf file u-boot-spl under nand_spl/. Create an AIS signed image using this file, and flash it to the nand flash at address 0x20000. The ais file should fit in one block. * hawkboard_uart_config - This is same as the first image, but with the TEXT_BASE as expected by the RBL(0xc1080000). Create the AIS Signed-off-by: Sughosh Ganu <urwithsughosh@gmail.com> Signed-off-by: Ben Gardiner <bengardiner@nanometrics.ca> Signed-off-by: Sandeep Paulraj <s-paulraj@ti.com>
273 lines
7.2 KiB
C
273 lines
7.2 KiB
C
/*
|
|
* (C) Copyright 2006-2008
|
|
* Stefan Roese, DENX Software Engineering, sr@denx.de.
|
|
*
|
|
* 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>
|
|
#include <nand.h>
|
|
#include <asm/io.h>
|
|
|
|
#define CONFIG_SYS_NAND_READ_DELAY \
|
|
{ volatile int dummy; int i; for (i=0; i<10000; i++) dummy = i; }
|
|
|
|
static int nand_ecc_pos[] = CONFIG_SYS_NAND_ECCPOS;
|
|
|
|
#if (CONFIG_SYS_NAND_PAGE_SIZE <= 512)
|
|
/*
|
|
* NAND command for small page NAND devices (512)
|
|
*/
|
|
static int nand_command(struct mtd_info *mtd, int block, int page, int offs, u8 cmd)
|
|
{
|
|
struct nand_chip *this = mtd->priv;
|
|
int page_addr = page + block * CONFIG_SYS_NAND_PAGE_COUNT;
|
|
|
|
if (this->dev_ready)
|
|
while (!this->dev_ready(mtd))
|
|
;
|
|
else
|
|
CONFIG_SYS_NAND_READ_DELAY;
|
|
|
|
/* Begin command latch cycle */
|
|
this->cmd_ctrl(mtd, cmd, NAND_CTRL_CLE | NAND_CTRL_CHANGE);
|
|
/* Set ALE and clear CLE to start address cycle */
|
|
/* Column address */
|
|
this->cmd_ctrl(mtd, offs, NAND_CTRL_ALE | NAND_CTRL_CHANGE);
|
|
this->cmd_ctrl(mtd, page_addr & 0xff, NAND_CTRL_ALE); /* A[16:9] */
|
|
this->cmd_ctrl(mtd, (page_addr >> 8) & 0xff,
|
|
NAND_CTRL_ALE); /* A[24:17] */
|
|
#ifdef CONFIG_SYS_NAND_4_ADDR_CYCLE
|
|
/* One more address cycle for devices > 32MiB */
|
|
this->cmd_ctrl(mtd, (page_addr >> 16) & 0x0f,
|
|
NAND_CTRL_ALE); /* A[28:25] */
|
|
#endif
|
|
/* Latch in address */
|
|
this->cmd_ctrl(mtd, NAND_CMD_NONE, NAND_NCE | NAND_CTRL_CHANGE);
|
|
|
|
/*
|
|
* Wait a while for the data to be ready
|
|
*/
|
|
if (this->dev_ready)
|
|
while (!this->dev_ready(mtd))
|
|
;
|
|
else
|
|
CONFIG_SYS_NAND_READ_DELAY;
|
|
|
|
return 0;
|
|
}
|
|
#else
|
|
/*
|
|
* NAND command for large page NAND devices (2k)
|
|
*/
|
|
static int nand_command(struct mtd_info *mtd, int block, int page, int offs, u8 cmd)
|
|
{
|
|
struct nand_chip *this = mtd->priv;
|
|
int page_addr = page + block * CONFIG_SYS_NAND_PAGE_COUNT;
|
|
|
|
if (this->dev_ready)
|
|
while (!this->dev_ready(mtd))
|
|
;
|
|
else
|
|
CONFIG_SYS_NAND_READ_DELAY;
|
|
|
|
/* Emulate NAND_CMD_READOOB */
|
|
if (cmd == NAND_CMD_READOOB) {
|
|
offs += CONFIG_SYS_NAND_PAGE_SIZE;
|
|
cmd = NAND_CMD_READ0;
|
|
}
|
|
|
|
/* Begin command latch cycle */
|
|
this->cmd_ctrl(mtd, cmd, NAND_CTRL_CLE | NAND_CTRL_CHANGE);
|
|
/* Set ALE and clear CLE to start address cycle */
|
|
/* Column address */
|
|
this->cmd_ctrl(mtd, offs & 0xff,
|
|
NAND_CTRL_ALE | NAND_CTRL_CHANGE); /* A[7:0] */
|
|
this->cmd_ctrl(mtd, (offs >> 8) & 0xff, NAND_CTRL_ALE); /* A[11:9] */
|
|
/* Row address */
|
|
this->cmd_ctrl(mtd, (page_addr & 0xff), NAND_CTRL_ALE); /* A[19:12] */
|
|
this->cmd_ctrl(mtd, ((page_addr >> 8) & 0xff),
|
|
NAND_CTRL_ALE); /* A[27:20] */
|
|
#ifdef CONFIG_SYS_NAND_5_ADDR_CYCLE
|
|
/* One more address cycle for devices > 128MiB */
|
|
this->cmd_ctrl(mtd, (page_addr >> 16) & 0x0f,
|
|
NAND_CTRL_ALE); /* A[31:28] */
|
|
#endif
|
|
/* Latch in address */
|
|
this->cmd_ctrl(mtd, NAND_CMD_READSTART,
|
|
NAND_CTRL_CLE | NAND_CTRL_CHANGE);
|
|
this->cmd_ctrl(mtd, NAND_CMD_NONE, NAND_NCE | NAND_CTRL_CHANGE);
|
|
|
|
/*
|
|
* Wait a while for the data to be ready
|
|
*/
|
|
if (this->dev_ready)
|
|
while (!this->dev_ready(mtd))
|
|
;
|
|
else
|
|
CONFIG_SYS_NAND_READ_DELAY;
|
|
|
|
return 0;
|
|
}
|
|
#endif
|
|
|
|
static int nand_is_bad_block(struct mtd_info *mtd, int block)
|
|
{
|
|
struct nand_chip *this = mtd->priv;
|
|
|
|
nand_command(mtd, block, 0, CONFIG_SYS_NAND_BAD_BLOCK_POS, NAND_CMD_READOOB);
|
|
|
|
/*
|
|
* Read one byte
|
|
*/
|
|
if (readb(this->IO_ADDR_R) != 0xff)
|
|
return 1;
|
|
|
|
return 0;
|
|
}
|
|
|
|
static int nand_read_page(struct mtd_info *mtd, int block, int page, uchar *dst)
|
|
{
|
|
struct nand_chip *this = mtd->priv;
|
|
u_char *ecc_calc;
|
|
u_char *ecc_code;
|
|
u_char *oob_data;
|
|
int i;
|
|
int eccsize = CONFIG_SYS_NAND_ECCSIZE;
|
|
int eccbytes = CONFIG_SYS_NAND_ECCBYTES;
|
|
int eccsteps = CONFIG_SYS_NAND_ECCSTEPS;
|
|
uint8_t *p = dst;
|
|
int stat;
|
|
|
|
nand_command(mtd, block, page, 0, NAND_CMD_READ0);
|
|
|
|
/* No malloc available for now, just use some temporary locations
|
|
* in SDRAM
|
|
*/
|
|
ecc_calc = (u_char *)(CONFIG_SYS_SDRAM_BASE + 0x10000);
|
|
ecc_code = ecc_calc + 0x100;
|
|
oob_data = ecc_calc + 0x200;
|
|
|
|
for (i = 0; eccsteps; eccsteps--, i += eccbytes, p += eccsize) {
|
|
this->ecc.hwctl(mtd, NAND_ECC_READ);
|
|
this->read_buf(mtd, p, eccsize);
|
|
this->ecc.calculate(mtd, p, &ecc_calc[i]);
|
|
}
|
|
this->read_buf(mtd, oob_data, CONFIG_SYS_NAND_OOBSIZE);
|
|
|
|
/* Pick the ECC bytes out of the oob data */
|
|
for (i = 0; i < CONFIG_SYS_NAND_ECCTOTAL; i++)
|
|
ecc_code[i] = oob_data[nand_ecc_pos[i]];
|
|
|
|
eccsteps = CONFIG_SYS_NAND_ECCSTEPS;
|
|
p = dst;
|
|
|
|
for (i = 0 ; eccsteps; eccsteps--, i += eccbytes, p += eccsize) {
|
|
/* No chance to do something with the possible error message
|
|
* from correct_data(). We just hope that all possible errors
|
|
* are corrected by this routine.
|
|
*/
|
|
stat = this->ecc.correct(mtd, p, &ecc_code[i], &ecc_calc[i]);
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
static int nand_load(struct mtd_info *mtd, unsigned int offs,
|
|
unsigned int uboot_size, uchar *dst)
|
|
{
|
|
unsigned int block, lastblock;
|
|
unsigned int page;
|
|
|
|
/*
|
|
* offs has to be aligned to a page address!
|
|
*/
|
|
block = offs / CONFIG_SYS_NAND_BLOCK_SIZE;
|
|
lastblock = (offs + uboot_size - 1) / CONFIG_SYS_NAND_BLOCK_SIZE;
|
|
page = (offs % CONFIG_SYS_NAND_BLOCK_SIZE) / CONFIG_SYS_NAND_PAGE_SIZE;
|
|
|
|
while (block <= lastblock) {
|
|
if (!nand_is_bad_block(mtd, block)) {
|
|
/*
|
|
* Skip bad blocks
|
|
*/
|
|
while (page < CONFIG_SYS_NAND_PAGE_COUNT) {
|
|
nand_read_page(mtd, block, page, dst);
|
|
dst += CONFIG_SYS_NAND_PAGE_SIZE;
|
|
page++;
|
|
}
|
|
|
|
page = 0;
|
|
} else {
|
|
lastblock++;
|
|
}
|
|
|
|
block++;
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
/*
|
|
* The main entry for NAND booting. It's necessary that SDRAM is already
|
|
* configured and available since this code loads the main U-Boot image
|
|
* from NAND into SDRAM and starts it from there.
|
|
*/
|
|
void nand_boot(void)
|
|
{
|
|
struct nand_chip nand_chip;
|
|
nand_info_t nand_info;
|
|
int ret;
|
|
__attribute__((noreturn)) void (*uboot)(void);
|
|
|
|
/*
|
|
* Init board specific nand support
|
|
*/
|
|
nand_chip.select_chip = NULL;
|
|
nand_info.priv = &nand_chip;
|
|
nand_chip.IO_ADDR_R = nand_chip.IO_ADDR_W = (void __iomem *)CONFIG_SYS_NAND_BASE;
|
|
nand_chip.dev_ready = NULL; /* preset to NULL */
|
|
board_nand_init(&nand_chip);
|
|
|
|
if (nand_chip.select_chip)
|
|
nand_chip.select_chip(&nand_info, 0);
|
|
|
|
/*
|
|
* Load U-Boot image from NAND into RAM
|
|
*/
|
|
ret = nand_load(&nand_info, CONFIG_SYS_NAND_U_BOOT_OFFS, CONFIG_SYS_NAND_U_BOOT_SIZE,
|
|
(uchar *)CONFIG_SYS_NAND_U_BOOT_DST);
|
|
|
|
#ifdef CONFIG_NAND_ENV_DST
|
|
nand_load(&nand_info, CONFIG_ENV_OFFSET, CONFIG_ENV_SIZE,
|
|
(uchar *)CONFIG_NAND_ENV_DST);
|
|
|
|
#ifdef CONFIG_ENV_OFFSET_REDUND
|
|
nand_load(&nand_info, CONFIG_ENV_OFFSET_REDUND, CONFIG_ENV_SIZE,
|
|
(uchar *)CONFIG_NAND_ENV_DST + CONFIG_ENV_SIZE);
|
|
#endif
|
|
#endif
|
|
|
|
if (nand_chip.select_chip)
|
|
nand_chip.select_chip(&nand_info, -1);
|
|
|
|
/*
|
|
* Jump to U-Boot image
|
|
*/
|
|
uboot = (void *)CONFIG_SYS_NAND_U_BOOT_START;
|
|
(*uboot)();
|
|
}
|