sciphone_g2: NAND SPL functionality added

Implementation of Secondary Program Loader which loads U-Boot
from NAND memory to SDRAM memory. SBL is loaded by IPL
(Initial Program Loader) at processor startup.

Signed-off-by: Marcin Mielczarczyk <marcin.mielczarczyk@tieto.com>
master
Marcin Mielczarczyk 12 years ago
parent 171c69aa43
commit f920a1e2fe
  1. 2
      Makefile
  2. 42
      drivers/mtd/nand/mt62xx_nand.c
  3. 76
      include/configs/sciphone_g2.h
  4. 82
      nand_spl/board/mtk/sciphone_g2/Makefile
  5. 26
      nand_spl/board/mtk/sciphone_g2/config.mk
  6. 221
      nand_spl/board/mtk/sciphone_g2/lowlevel_init.S
  7. 54
      nand_spl/board/mtk/sciphone_g2/u-boot.lds
  8. 484
      nand_spl/nand_boot_detect.c

@ -972,8 +972,8 @@ omap730p2_cs3boot_config : unconfig
sciphone_g2_config: unconfig
@mkdir -p $(obj)include
@ > $(obj)include/config.h
@$(MKCONFIG) -n $@ -a sciphone_g2 arm arm926ejs sciphone_g2 mtk mtk
@echo "CONFIG_NAND_U_BOOT = y" >> $(obj)include/config.mk
spear300_config \
spear310_config \

@ -92,6 +92,24 @@
*/
#define ECC_SPARE_BYTE_POS 8
/*
* Macro which counts zeroes until first set bit.
* This is used to avoid dividing, so no additional library is needed.
* It's important as this file is compiled also in SPL and there is no need
* to link additional library.
*/
#ifdef CONFIG_ARM926EJS
#define COUNT_ZEROES(x) __builtin_ctz(x)
#else
#define COUNT_ZEROES(x) (ffs(x) - 1)
#endif
#ifdef CONFIG_PRELOADER
#define nand_print(x)
#else
#define nand_print(x) printk(KERN_ERR (x))
#endif
static void nand_ctrl_change(int cmd, int address, int *addr_cycle,
int write_size)
{
@ -192,10 +210,12 @@ static int mt62xx_nand_dev_ready(struct mtd_info *mtd)
static void mt62xx_nand_select_chip(struct mtd_info *mtd, int chip)
{
if (chip > NAND_CHIPS_MAX) {
printk(KERN_ERR "Wrong NAND chip number!\n");
nand_print("Wrong NAND chip number!\n");
return;
}
writel(chip, MTK_NFI_CSEL);
if (chip != -1)
writel(chip, MTK_NFI_CSEL);
}
static void mt62xx_nand_read_buf(struct mtd_info *mtd, uint8_t *buf, int len)
@ -205,7 +225,7 @@ static void mt62xx_nand_read_buf(struct mtd_info *mtd, uint8_t *buf, int len)
int i;
if (len % 4)
printk(KERN_ERR "Length parameter is not aligned\n");
nand_print("Length parameter is not aligned\n");
for (i = 0; i < len/4; ++i)
buf_32[i] = readl(chip->IO_ADDR_R);
@ -232,10 +252,10 @@ static void mt62xx_nand_write_ecc(struct mtd_info *mtd, int len)
uint8_t ecc[8];
/*
* Two ECC blocks are combined in Sciphone G2 format,
* that's why there is division by 2.
* Two ECC blocks are combined on MT62xx platform,
* that's why writesize is multiplied by 2.
*/
ecc_blocks = mtd->writesize/chip->ecc.size/2;
ecc_blocks = (mtd->writesize * 2) >> COUNT_ZEROES(chip->ecc.size);
for (ecc_nr = 0; ecc_nr < ecc_blocks; ++ecc_nr) {
int ecc_p, ecc_c, pos = 0;
@ -286,7 +306,7 @@ static void mt62xx_nand_write_buf(struct mtd_info *mtd, const uint8_t *buf,
mt62xx_nand_write_ecc(mtd, len);
} else {
if (len % 4)
printk(KERN_ERR "Length parameter is not aligned\n");
nand_print("Length parameter is not aligned\n");
for (i = 0; i < len/4; ++i)
writel(buf_32[i], chip->IO_ADDR_W);
@ -307,7 +327,7 @@ static int mt62xx_nand_ecc_calculate(struct mtd_info *mtd, const uint8_t *dat,
* which is currently read. We can use it to calculate which ECC block
* has been already read.
*/
*ecc_code = readw(MTK_NFI_ADDRCNTR)/chip->ecc.size;
*ecc_code = readw(MTK_NFI_ADDRCNTR) >> COUNT_ZEROES(chip->ecc.size);
return 0;
}
@ -370,6 +390,12 @@ int board_nand_init(struct nand_chip *chip)
7 << NFI_ACCCON_LCD2NAND_SHIFT,
MTK_NFI_ACCCON);
/*
* Reset NFI page format control register.
* After processor reset it's not always zero what renders problems.
*/
writel(0, MTK_NFI_PAGEFMT);
/* Flush and reset NFI FIFO */
writel(NFI_OPCON_FIFO_FLUSH | NFI_OPCON_FIFO_RST, MTK_NFI_OPCON);
while(readl(MTK_NFI_OPCON))

@ -20,6 +20,18 @@
*
*/
/*
* U-Boot configuration is split in two parts:
* - SPL configuration
* - normal configuration
*
* MT62XX platform has IPL (Initial Program Loader) in ROM.
* After processor power up IPL execution is started. IPL tries to load
* code from NAND to internal RAM (64KB) and starts executing loaded code.
* SBL (Secondary Program Loader) is loaded by IPL. SBL configures basic
* peripherals (PLL, SDRAM memory) and loads U-Boot from NAND to SDRAM.
*/
#ifndef __CONFIG_H
#define __CONFIG_H
@ -27,6 +39,29 @@
#define CONFIG_ARM926EJS
/* DRAM memory related configurations */
#define CONFIG_NR_DRAM_BANKS 1
#define PHYS_SDRAM_1 0x00000000
#define PHYS_SDRAM_1_SIZE 0x04000000 /* 64 MB */
#define CONFIG_SYS_SDRAM_BASE PHYS_SDRAM_1
/* NAND memory related configurations */
#define CONFIG_NAND_MT62XX
#define CONFIG_SYS_MAX_NAND_DEVICE 1
#define CONFIG_SYS_NAND_BASE MTK_NFI_BASE
/* There is no NOR flash, so undefine these commands */
#undef CONFIG_CMD_FLASH
#undef CONFIG_CMD_IMLS
#define CONFIG_SYS_NO_FLASH
#ifndef CONFIG_PRELOADER
/*
* Configuration of U-Boot when running from DRAM (normal operation).
*/
/* We have already been loaded to RAM */
#define CONFIG_SKIP_LOWLEVEL_INIT
@ -40,16 +75,8 @@
#define CONFIG_BAUDRATE 115200
#define CONFIG_SYS_BAUDRATE_TABLE {9600, 19200, 38400, 57600, 115200}
/* There is no NOR flash, so undefine these commands */
#undef CONFIG_CMD_FLASH
#undef CONFIG_CMD_IMLS
#define CONFIG_SYS_NO_FLASH
/* Configure NAND storage */
#define CONFIG_NAND_MT62XX
/* Turn on some U-Boot commands */
#define CONFIG_CMD_NAND
#define CONFIG_SYS_MAX_NAND_DEVICE 1
#define CONFIG_SYS_NAND_BASE MTK_NFI_BASE
#define CONFIG_CMD_MEMORY
#define CONFIG_CMD_LOADB
#define CONFIG_CMD_RUN
@ -81,14 +108,6 @@
#define CONFIG_BOOTARGS "console=ttyMTK0,115200n8 mem=64M@0"
#define CONFIG_BOOTCOMMAND "bootm 0x800000"
/* Memory related information */
#define CONFIG_NR_DRAM_BANKS 1
#define PHYS_SDRAM_1 0x00000000
#define PHYS_SDRAM_1_SIZE 0x04000000 /* 64 MB */
#define CONFIG_SYS_SDRAM_BASE PHYS_SDRAM_1
#define CONFIG_SYS_INIT_SP_ADDR (CONFIG_SYS_SDRAM_BASE + 0x1000)
#define CONFIG_MAX_RAM_BANK_SIZE 0x10000000
#define CONFIG_STACKSIZE (128 * 1024)
#ifdef CONFIG_USE_IRQ
# define CONFIG_STACKSIZE_IRQ (4 * 1024) /* IRQ stack */
@ -97,8 +116,11 @@
#define CONFIG_SYS_MEMTEST_START 0x00000000
#define CONFIG_SYS_MEMTEST_END 0x02FFFFFF
#define CONFIG_SYS_MALLOC_LEN (CONFIG_ENV_SIZE + 256 * 1024)
#define CONFIG_SYS_GBL_DATA_SIZE 128
#define CONFIG_SYS_MALLOC_LEN (CONFIG_ENV_SIZE + 256 * 1024)
#define CONFIG_MAX_RAM_BANK_SIZE 0x10000000
#define CONFIG_SYS_INIT_SP_ADDR (CONFIG_SYS_SDRAM_BASE + CONFIG_STACKSIZE)
/* This is needed to make hello_world.c happy */
#define CONFIG_SYS_MAX_FLASH_SECT 512
@ -132,4 +154,22 @@
#endif /* CONFIG_MMC */
#else /* CONFIG_PRELOADER */
/*
* Configuration of U-Boot for SPL.
*/
#define CONFIG_STACKSIZE 1024
#define CONFIG_SYS_MALLOC_LEN 1024
#define INTERNAL_RAM_BASE 0x40000000
#define CONFIG_SYS_INIT_SP_ADDR (INTERNAL_RAM_BASE + CONFIG_STACKSIZE)
#define CONFIG_ENV_SIZE 0x0
/* Address of U-Boot in NAND */
#define CONFIG_SYS_NAND_U_BOOT_OFFS 0x20000
#define CONFIG_SYS_NAND_U_BOOT_SIZE 1000000 /* 1MB */
#define CONFIG_SYS_NAND_U_BOOT_DST 0x500000
#define CONFIG_SYS_NAND_U_BOOT_START 0x500000
#endif /* CONFIG_PRELOADER */
#endif /* __CONFIG_H */

@ -0,0 +1,82 @@
#
# (C) Copyright 2006-2007
# Stefan Roese, DENX Software Engineering, sr@denx.de.
#
# (C) Copyright 2008
# Guennadi Liakhovetki, DENX Software Engineering, <lg@denx.de>
#
# 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
#
CONFIG_NAND_SPL = y
include $(TOPDIR)/config.mk
include $(TOPDIR)/nand_spl/board/$(BOARDDIR)/config.mk
LDSCRIPT= $(TOPDIR)/nand_spl/board/$(BOARDDIR)/u-boot.lds
LDFLAGS = -Bstatic -T $(nandobj)u-boot.lds -Ttext $(CONFIG_SYS_TEXT_BASE) $(PLATFORM_LDFLAGS)
AFLAGS += -DCONFIG_PRELOADER -DCONFIG_NAND_SPL -DCONFIG_SYS_TEXT_BASE=$(CONFIG_SYS_TEXT_BASE)
CFLAGS += -DCONFIG_PRELOADER -DCONFIG_NAND_SPL -DCONFIG_SYS_TEXT_BASE=$(CONFIG_SYS_TEXT_BASE)
SOBJS = start.o lowlevel_init.o
COBJS = nand_boot_detect.o mt62xx_nand.o nand_ids.o
SRCS := $(addprefix $(obj),$(SOBJS:.o=.S) $(COBJS:.o=.c))
OBJS := $(addprefix $(obj),$(SOBJS) $(COBJS))
__OBJS := $(SOBJS) $(COBJS)
LNDIR := $(OBJTREE)/nand_spl/board/$(BOARDDIR)
nandobj := $(OBJTREE)/nand_spl/
ALL = $(nandobj)u-boot-spl $(nandobj)u-boot-spl.bin $(nandobj)u-boot-spl-16k.bin
#all: $(obj).depend $(ALL)
all: $(ALL)
$(nandobj)u-boot-spl-16k.bin: $(nandobj)u-boot-spl
$(OBJCOPY) ${OBJCFLAGS} --pad-to=$(PAD_TO) -O binary $< $@
$(nandobj)u-boot-spl.bin: $(nandobj)u-boot-spl
$(OBJCOPY) ${OBJCFLAGS} -O binary $< $@
$(nandobj)u-boot-spl: $(OBJS) $(nandobj)u-boot.lds
cd $(LNDIR) && $(LD) $(LDFLAGS) $(__OBJS) \
-Map $(nandobj)u-boot-spl.map \
-o $(nandobj)u-boot-spl
$(nandobj)u-boot.lds: $(LDSCRIPT)
$(CPP) $(CPPFLAGS) $(LDPPFLAGS) -ansi -D__ASSEMBLY__ -P - <$^ >$@
#########################################################################
$(obj)%.o: $(SRCTREE)/arch/arm/cpu/arm926ejs/%.S
$(CC) $(AFLAGS) -c -o $@ $<
$(obj)%.o: $(SRCTREE)/nand_spl/%.c
$(CC) $(CFLAGS) -c -o $@ $<
$(obj)%.o: $(SRCTREE)/drivers/mtd/nand/%.c
$(CC) $(CFLAGS) -c -o $@ $<
# defines $(obj).depend target
include $(SRCTREE)/rules.mk
sinclude $(obj).depend
#########################################################################

@ -0,0 +1,26 @@
#
# (C) Copyright 2006
# Stefan Roese, DENX Software Engineering, sr@denx.de.
#
# 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
# On Siphone G2 the SPL is located in SRAM.
# CONFIG_SYS_TEXT_BASE for SPL:
CONFIG_SYS_TEXT_BASE = 0x40002000

@ -0,0 +1,221 @@
/*
* (C) 2010 by Tieto <www.tieto.com>
* Marcin Mielczarczyk <marcin.mielczarczyk@tieto.com>
*
* All Rights Reserved
*
* 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 Street, Fifth Floor, Boston, MA 02110-1301 USA.
*
*/
#include <config.h>
#include <asm/arch-mtk/mt6235.h>
#include <asm/arch-mtk/emi.h>
#include <asm/arch-mtk/system.h>
.globl lowlevel_init
.type lowlevel_init,function
lowlevel_init:
/* -----------------------------
* Initialize PLL
* -----------------------------
*/
/* Power on PLL */
ldr r0, =MTK_PLL_PDN_CON
mov r1, #0
str r1, [r0]
/* Turn on MCU and DSP dividers, mark that SYSCLK is 26MHz */
ldr r0, =MTK_PLL_CLK_CON
mov r1, #0x83
str r1, [r0]
/* Reset PLL */
ldr r0, =MTK_PLL_PLL
mov r1, #0x80
str r1, [r0]
mov r1, #0
str r1, [r0]
mov r1, #0xFF
PLL_DELAY_loop:
subs r1, r1, #1
bgt PLL_DELAY_loop
/* Turn on PLL for MCU, DSP and USB */
mov r1, #0x70
str r1, [r0]
/*
* Setup MCU clock register:
* ARMCLK = 208MHz, AHBx4CLK = 52MHz, AHBx8CLK = 104MHz
* we have to write to the read-only part (EMICLK) as well, otherwise
* the EMI won't work! (datasheet lies)
*/
ldr r0, =MTK_CONFG_MCUCLK_CON
ldr r1, =0x7F37
str r1, [r0]
/* -----------------------------
* Initialize SDRAM controller
* -----------------------------
*/
/* Reset index of SDRAM config table */
mov r7, #0
SDRAM_TRY_CONFIG:
adr r1, SDRAM_CONFIG_TABLE
/* Calculate config table offset (index * element_size) */
lsl r2, r7, #3
/* Calculate address of element in config table */
add r1, r1, r2
/* Load start address of SDRAM configuration */
ldr r0, [r1]
/* Check if end of SDRAM config table is reached */
cmp r0, #0
beq SDRAM_PASSED
/* Load end address of SDRAM configuration */
ldr r6, [r1, #4]
/* Configure SDRAM controller */
SDRAM_REGSET_LOOP:
ldr r1, [r0]
ldr r2, [r0, #4]
str r1, [r2]
add r0, r0, #8
mov r1, #0xFF
SDRAM_DELAY_LOOP:
subs r1, r1, #1
bgt SDRAM_DELAY_LOOP
cmp r0, r6
blt SDRAM_REGSET_LOOP
/* Perform test to check if SDRAM is properly configured */
mov r0, #0x1000
mov r1, #0x0
mov r2, #16384
SDRAM_WRITE_LOOP:
str r1, [r0]
add r0, r0, #4
add r1, r1, #1
cmp r1, r2
blt SDRAM_WRITE_LOOP
mov r0, #0x1000
mov r3, #0x0
SDRAM_VERIFY_LOOP:
ldr r1, [r0]
add r0, r0, #4
cmp r1, r3
bne SDRAM_FAILED
add r3, r3, #1
cmp r3, r2
blt SDRAM_VERIFY_LOOP
SDRAM_PASSED:
/* return from function */
mov pc, lr
/* SDRAM configuration failed, try another one */
SDRAM_FAILED:
/* Increment SDRAM config table index */
add r7, r7, #1
b SDRAM_TRY_CONFIG
SDRAM_CONFIG_TABLE:
.word SDRAM_64MB_CONFIG
.word SDRAM_64MB_CONFIG_END
.word SDRAM_32MB_CONFIG
.word SDRAM_32MB_CONFIG_END
.word 0
/* This configuration is for 64MB SDRAM memory */
SDRAM_64MB_CONFIG:
.word 0x00088E3A
.word MTK_EMI_GENA
.word 0x000000C0
.word MTK_EMI_GENB
.word 0x18C618C6
.word MTK_EMI_GENC
.word 0x0001000E
.word MTK_EMI_GEND
.word 0x00332000
.word MTK_EMI_CONI
.word 0x3CD24431
.word MTK_EMI_CONJ
.word 0x02000000
.word MTK_EMI_CONK
.word 0x18007505
.word MTK_EMI_CONL
.word 0x00002828
.word MTK_EMI_CONM
.word 0x1500013
.word MTK_EMI_CONN
.word 0x500013
.word MTK_EMI_CONN
.word 0x2500013
.word MTK_EMI_CONN
.word 0x500013
.word MTK_EMI_CONN
.word 0x4500013
.word MTK_EMI_CONN
.word 0x500013
.word MTK_EMI_CONN
.word 0x8500013
.word MTK_EMI_CONN
.word 0x500013
.word MTK_EMI_CONN
.word 0x80500013
.word MTK_EMI_CONN
.word 0x500013
.word MTK_EMI_CONN
SDRAM_64MB_CONFIG_END:
/* This configuration is for 32MB SDRAM memory */
SDRAM_32MB_CONFIG:
.word 0x00088a0a
.word MTK_EMI_GENA
.word 0x00000280
.word MTK_EMI_GENB
.word 0x52945294
.word MTK_EMI_GENC
.word 0x0001000E
.word MTK_EMI_GEND
.word 0x02334000
.word MTK_EMI_CONI
.word 0x16c12212
.word MTK_EMI_CONJ
.word 0x032d0000
.word MTK_EMI_CONK
.word 0x1c016605
.word MTK_EMI_CONL
.word 0x00002828
.word MTK_EMI_CONM
.word 0x1400013
.word MTK_EMI_CONN
.word 0x400013
.word MTK_EMI_CONN
.word 0x2400013
.word MTK_EMI_CONN
.word 0x400013
.word MTK_EMI_CONN
.word 0x4400013
.word MTK_EMI_CONN
.word 0x400013
.word MTK_EMI_CONN
.word 0x8400013
.word MTK_EMI_CONN
.word 0x400013
.word MTK_EMI_CONN
.word 0x80400013
.word MTK_EMI_CONN
.word 0x400013
.word MTK_EMI_CONN
SDRAM_32MB_CONFIG_END:

@ -0,0 +1,54 @@
/*
* (C) Copyright 2002
* Gary Jennejohn, DENX Software Engineering, <garyj@denx.de>
*
* (C) Copyright 2008
* Guennadi Liakhovetki, DENX Software Engineering, <lg@denx.de>
*
* 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
*/
OUTPUT_FORMAT("elf32-littlearm", "elf32-littlearm", "elf32-littlearm")
OUTPUT_ARCH(arm)
ENTRY(_start)
SECTIONS
{
. = 0x00000000;
. = ALIGN(4);
.text :
{
start.o (.text)
*(.text)
}
. = ALIGN(4);
.rodata : { *(SORT_BY_ALIGNMENT(SORT_BY_NAME(.rodata*))) }
. = ALIGN(4);
.data : { *(.data) }
. = ALIGN(4);
.got : { *(.got) }
. = ALIGN(4);
__bss_start = .;
.bss : { *(.bss) . = ALIGN(4); }
_end = .;
}

@ -0,0 +1,484 @@
/*
* (C) Copyright 2006-2008
* Stefan Roese, DENX Software Engineering, sr@denx.de.
*
* Rework by Marcin Mielczarczyk <marcin.mielczarczyk@tieto.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., 59 Temple Place, Suite 330, Boston,
* MA 02111-1307 USA
*/
#include <common.h>
#include <nand.h>
#include <asm/io.h>
#include <linux/err.h>
/*
* SPL has no malloc availble and below are definitions of some temporary
* buffers in RAM for general purpose.
*/
#define RAM_BUF1 (CONFIG_SYS_SDRAM_BASE + 0x1000)
#define RAM_BUF2 (RAM_BUF1 + 0x1000)
#define RAM_BUF3 (RAM_BUF2 + 0x1000)
/*
* Macro which counts zeroes until first set bit.
* This is used to avoid dividing, so no additional library is needed.
* It's important as this file is compiled also in SPL and there is no need
* to link additional library.
*/
#ifdef CONFIG_ARM926EJS
#define COUNT_ZEROES(x) __builtin_ctz(x)
#else
#define COUNT_ZEROES(x) (ffs(x) - 1)
#endif
nand_info_t nand_info[1];
#define CONFIG_SYS_NAND_READ_DELAY \
{ volatile int dummy; int i; for (i=0; i<10000; i++) dummy = i; }
/*
* NAND command for small page NAND devices (512)
*/
static void nand_command(struct mtd_info *mtd, unsigned int cmd,
int column, int page_addr)
{
struct nand_chip *chip = mtd->priv;
int ctrl = NAND_CTRL_CLE | NAND_CTRL_CHANGE;
if (chip->dev_ready)
while (!chip->dev_ready(mtd))
;
else
CONFIG_SYS_NAND_READ_DELAY;
/* Begin command latch cycle */
chip->cmd_ctrl(mtd, cmd, NAND_CTRL_CLE | NAND_CTRL_CHANGE);
ctrl = NAND_CTRL_ALE | NAND_CTRL_CHANGE;
/* Serially input address */
if (column != -1) {
/* Adjust columns for 16 bit buswidth */
if (chip->options & NAND_BUSWIDTH_16)
column >>= 1;
chip->cmd_ctrl(mtd, column, ctrl);
ctrl &= ~NAND_CTRL_CHANGE;
}
if (page_addr != -1) {
chip->cmd_ctrl(mtd, page_addr, ctrl);
ctrl &= ~NAND_CTRL_CHANGE;
chip->cmd_ctrl(mtd, page_addr >> 8, ctrl);
/* One more address cycle for devices > 32MiB */
if (chip->chipsize > (32 << 20))
chip->cmd_ctrl(mtd, page_addr >> 16, ctrl);
}
chip->cmd_ctrl(mtd, NAND_CMD_NONE, NAND_NCE | NAND_CTRL_CHANGE);
/*
* Wait a while for the data to be ready
*/
if (chip->dev_ready)
while (!chip->dev_ready(mtd))
;
else
CONFIG_SYS_NAND_READ_DELAY;
}
/*
* NAND command for large page NAND devices (2k)
*/
static void nand_command_lp(struct mtd_info *mtd, unsigned int cmd, int column,
int page_addr)
{
struct nand_chip *chip = mtd->priv;
if (chip->dev_ready)
while (!chip->dev_ready(mtd))
;
else
CONFIG_SYS_NAND_READ_DELAY;
/* Emulate NAND_CMD_READOOB */
if (cmd == NAND_CMD_READOOB) {
page_addr += mtd->writesize;
cmd = NAND_CMD_READ0;
}
/* Command latch cycle */
chip->cmd_ctrl(mtd, cmd & 0xff,
NAND_NCE | NAND_CLE | NAND_CTRL_CHANGE);
if (column != -1 || page_addr != -1) {
int ctrl = NAND_CTRL_CHANGE | NAND_NCE | NAND_ALE;
/* Serially input address */
if (column != -1) {
/* Adjust columns for 16 bit buswidth */
if (chip->options & NAND_BUSWIDTH_16)
column >>= 1;
chip->cmd_ctrl(mtd, column, ctrl);
ctrl &= ~NAND_CTRL_CHANGE;
chip->cmd_ctrl(mtd, column >> 8, ctrl);
}
if (page_addr != -1) {
chip->cmd_ctrl(mtd, page_addr, ctrl);
chip->cmd_ctrl(mtd, page_addr >> 8,
NAND_NCE | NAND_ALE);
/* One more address cycle for devices > 128MiB */
if (chip->chipsize > (128 << 20))
chip->cmd_ctrl(mtd, page_addr >> 16,
NAND_NCE | NAND_ALE);
}
}
chip->cmd_ctrl(mtd, NAND_CMD_NONE, NAND_NCE | NAND_CTRL_CHANGE);
chip->cmd_ctrl(mtd, NAND_CMD_READSTART,
NAND_CTRL_CLE | NAND_CTRL_CHANGE);
chip->cmd_ctrl(mtd, NAND_CMD_NONE, NAND_NCE | NAND_CTRL_CHANGE);
/*
* Wait a while for the data to be ready
*/
if (chip->dev_ready)
while (!chip->dev_ready(mtd))
;
else
CONFIG_SYS_NAND_READ_DELAY;
}
static int nand_is_bad_block(struct mtd_info *mtd, int page_addr)
{
struct nand_chip *chip = mtd->priv;
if ((page_addr & (mtd->erasesize - 1)) != 0)
/*
* Page address is not aligned to block address,
* in this case there is no reason to check bad block.
*/
return 0;
chip->cmdfunc(mtd, NAND_CMD_READOOB, 0, page_addr);
chip->read_buf(mtd, chip->oob_poi, mtd->oobsize);
return (chip->oob_poi[5] != 0xFF) ? 1: 0;
}
static int nand_read_page(struct mtd_info *mtd, int page_addr,
unsigned char *dst)
{
struct nand_chip *chip = mtd->priv;
uint8_t *ecc_calc;
uint8_t *ecc_code;
int i;
int eccsize = chip->ecc.size;
int eccbytes = chip->ecc.bytes;
int eccsteps = chip->ecc.steps;
uint32_t *eccpos = chip->ecc.layout->eccpos;
uint8_t *p = dst;
chip->cmdfunc(mtd, NAND_CMD_READ0, 0, page_addr);
/*
* No malloc available for now, just use some temporary locations
* in SDRAM.
*/
ecc_calc = (uint8_t *)RAM_BUF2;
ecc_code = (uint8_t *)RAM_BUF3;
for (i = 0; eccsteps; eccsteps--, i += eccbytes, p += eccsize) {
chip->ecc.hwctl(mtd, NAND_ECC_READ);
chip->read_buf(mtd, p, eccsize);
chip->ecc.calculate(mtd, p, &ecc_calc[i]);
}
chip->read_buf(mtd, chip->oob_poi, mtd->oobsize);
/* Pick the ECC bytes out of the oob data */
for (i = 0; i < chip->ecc.total; i++)
ecc_code[i] = chip->oob_poi[eccpos[i]];
eccsteps = chip->ecc.steps;
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.
*/
chip->ecc.correct(mtd, p, &ecc_code[i], &ecc_calc[i]);
}
return 0;
}
static void nand_load(struct mtd_info *mtd, unsigned int offset,
unsigned int size, uint8_t *dst)
{
unsigned int page, end_page, pages_per_block;
/*
* Offset should be aligned to page and block size, otherwise
* there will be no chance to detect bad block of start offset.
*/
page = offset >> COUNT_ZEROES(mtd->writesize);
end_page = page + (size >> COUNT_ZEROES(mtd->writesize));
/* If size is not aligned to page then read one more page */
if (size & (mtd->writesize - 1))
end_page++;
pages_per_block = mtd->erasesize >> COUNT_ZEROES(mtd->writesize);
while (page < end_page) {
/* If this read is in new block, check for babd block*/
if ((page & (pages_per_block - 1)) == 0) {
if (nand_is_bad_block(mtd, page)) {
/*
* Bad block is detected.
* Jump to next block and continue code loading.
* In this case not full image will be loaded.
*/
page += pages_per_block;
continue;
}
}
nand_read_page(mtd, page, dst);
page++;
dst += mtd->writesize;
}
}
#if defined(CONFIG_ARM)
void board_init_f (ulong bootflag)
{
relocate_code (CONFIG_SYS_TEXT_BASE - TOTAL_MALLOC_LEN, NULL,
CONFIG_SYS_TEXT_BASE);
}
#endif
/*
* Get the flash and manufacturer id and lookup if the type is supported
*/
static const struct nand_flash_dev *nand_get_flash_type(struct mtd_info *mtd,
struct nand_chip *chip,
int busw, int *maf_id)
{
const struct nand_flash_dev *type = NULL;
int i, dev_id, maf_idx;
int tmp_id, tmp_manf;
/* Select the device */
chip->select_chip(mtd, 0);
/*
* Reset the chip, required by some chips (e.g. Micron MT29FxGxxxxx)
* after power-up
*/
chip->cmdfunc(mtd, NAND_CMD_RESET, -1, -1);
/* Send the command for reading device ID */
chip->cmdfunc(mtd, NAND_CMD_READID, 0x00, -1);
/* Read manufacturer and device IDs */
*maf_id = chip->read_byte(mtd);
dev_id = chip->read_byte(mtd);
/* Try again to make sure, as some systems the bus-hold or other
* interface concerns can cause random data which looks like a
* possibly credible NAND flash to appear. If the two results do
* not match, ignore the device completely.
*/
chip->cmdfunc(mtd, NAND_CMD_READID, 0x00, -1);
/* Read manufacturer and device IDs */
tmp_manf = chip->read_byte(mtd);
tmp_id = chip->read_byte(mtd);
if (tmp_manf != *maf_id || tmp_id != dev_id)
return ERR_PTR(-ENODEV);
/* Lookup the flash id */
for (i = 0; nand_flash_ids[i].name != NULL; i++) {
if (dev_id == nand_flash_ids[i].id) {
type = &nand_flash_ids[i];
break;
}
}
if (!type)
return ERR_PTR(-ENODEV);
if (!mtd->name)
mtd->name = type->name;
chip->chipsize = (uint64_t)type->chipsize << 20;
/* Newer devices have all the information in additional id bytes */
if (!type->pagesize) {
int extid;
/* The 3rd id byte holds MLC / multichip data */
chip->cellinfo = chip->read_byte(mtd);
/* The 4th id byte is the important one */
extid = chip->read_byte(mtd);
/* Calc pagesize */
mtd->writesize = 1024 << (extid & 0x3);
extid >>= 2;
/* Calc oobsize */
mtd->oobsize = (8 << (extid & 0x01)) * (mtd->writesize >> 9);
extid >>= 2;
/* Calc blocksize. Blocksize is multiples of 64KiB */
mtd->erasesize = (64 * 1024) << (extid & 0x03);
extid >>= 2;
/* Get buswidth information */
busw = (extid & 0x01) ? NAND_BUSWIDTH_16 : 0;
} else {
/*
* Old devices have chip data hardcoded in the device id table
*/
mtd->erasesize = type->erasesize;
mtd->writesize = type->pagesize;
mtd->oobsize = mtd->writesize / 32;
busw = type->options & NAND_BUSWIDTH_16;
}
/* Try to identify manufacturer */
for (maf_idx = 0; nand_manuf_ids[maf_idx].id != 0x0; maf_idx++) {
if (nand_manuf_ids[maf_idx].id == *maf_id)
break;
}
/*
* Check, if buswidth is correct. Hardware drivers should set
* chip correct !
*/
if (busw != (chip->options & NAND_BUSWIDTH_16))
return ERR_PTR(-EINVAL);
/* Calculate the address shift from the page size */
chip->page_shift = ffs(mtd->writesize) - 1;
chip->bbt_erase_shift = chip->phys_erase_shift =
ffs(mtd->erasesize) - 1;
if (chip->chipsize & 0xffffffff)
chip->chip_shift = ffs((unsigned)chip->chipsize) - 1;
else
chip->chip_shift = ffs((unsigned)(chip->chipsize >> 32)) + 31;
/* Set the bad block position */
chip->badblockpos = mtd->writesize > 512 ?
NAND_LARGE_BADBLOCK_POS : NAND_SMALL_BADBLOCK_POS;
/* Get chip options, preserve non chip based options */
chip->options &= ~NAND_CHIPOPTIONS_MSK;
chip->options |= type->options & NAND_CHIPOPTIONS_MSK;
/*
* Set chip as a default. Board drivers can override it, if necessary
*/
chip->options |= NAND_NO_AUTOINCR;
/* Check if chip is a not a samsung device. Do not clear the
* options for chips which are not having an extended id.
*/
if (*maf_id != NAND_MFR_SAMSUNG && !type->pagesize)
chip->options &= ~NAND_SAMSUNG_LP_OPTIONS;
/* Do not replace user supplied command function ! */
if (mtd->writesize > 512 && chip->cmdfunc == nand_command)
chip->cmdfunc = nand_command_lp;
return type;
}
int nand_scan_ident(struct mtd_info *mtd, int maxchips,
const struct nand_flash_dev *table)
{
int busw, nand_maf_id;
struct nand_chip *chip = mtd->priv;
const struct nand_flash_dev *type;
/* Get buswidth to select the correct functions */
busw = chip->options & NAND_BUSWIDTH_16;
/* Read the flash type */
type = nand_get_flash_type(mtd, chip, busw, &nand_maf_id);
if (IS_ERR(type)) {
chip->select_chip(mtd, -1);
return PTR_ERR(type);
}
/* Store the number of chips and calc total size for mtd */
chip->numchips = 1;
mtd->size = chip->chipsize;
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 chip;
nand_info_t *mtd = nand_info;
__attribute__((noreturn)) void (*uboot)(void);
/*
* Init board specific nand support
*/
mtd->priv = &chip;
chip.IO_ADDR_R = (void __iomem *)CONFIG_SYS_NAND_BASE;
chip.IO_ADDR_W = (void __iomem *)CONFIG_SYS_NAND_BASE;
chip.dev_ready = NULL;
chip.cmdfunc = nand_command;
chip.options = 0;
board_nand_init(&chip);
chip.ecc.steps = mtd->writesize >> COUNT_ZEROES(chip.ecc.size);
chip.oob_poi = (uint8_t *)RAM_BUF1;
if (chip.select_chip)
chip.select_chip(mtd, 0);
/*
* Load U-Boot image from NAND into RAM
*/
nand_load(mtd, CONFIG_SYS_NAND_U_BOOT_OFFS, CONFIG_SYS_NAND_U_BOOT_SIZE,
(uint8_t *)CONFIG_SYS_NAND_U_BOOT_DST);
#ifdef CONFIG_NAND_ENV_DST
nand_load(mtd, CONFIG_ENV_OFFSET, CONFIG_ENV_SIZE,
(uint8_t *)CONFIG_NAND_ENV_DST);
#ifdef CONFIG_ENV_OFFSET_REDUND
nand_load(mtd, CONFIG_ENV_OFFSET_REDUND, CONFIG_ENV_SIZE,
(uint8_t *)CONFIG_NAND_ENV_DST + CONFIG_ENV_SIZE);
#endif
#endif
if (chip.select_chip)
chip.select_chip(mtd, -1);
/*
* Jump to U-Boot image
*/
uboot = (void *)CONFIG_SYS_NAND_U_BOOT_START;
(*uboot)();
}
Loading…
Cancel
Save