1
0
mirror of git://projects.qi-hardware.com/xburst-tools.git synced 2024-12-22 23:31:10 +02:00

-add nandboot to xburst-tool

-nandboot load the zImage kernel

Signed-off-by: Xiangfu Liu <xiangfu.z@gmail.com>
This commit is contained in:
Xiangfu Liu 2009-07-01 10:53:48 +08:00
parent fe6e51cd2a
commit 056ecbbe29
20 changed files with 11543 additions and 0 deletions

22
nandboot/README Normal file
View File

@ -0,0 +1,22 @@
This is the source code of the NAND Secondary Program Loader (SPL).
The NAND SPL itself will be first loaded by the IPL (Initial Program Loader)
inside the CPU, then it loads the kernel image from NAND into RAM and
starts the kernel from RAM.
To build the NAND SPL, follow next steps:
$ cd src/
$ make
And you will get a binary file called n-boot.bin.
Before building the SPL, you should open config.h and check the
configuration is correct for your system.
For JZ4730, the n-boot.bin must be less than 4KB.
For JZ4740, the n-boot.bin must be less than 8KB.
The platform definitions were declared in include/jz47xx_board.h.
Please check and modify it according to your system.

14
nandboot/config.h Normal file
View File

@ -0,0 +1,14 @@
/*
* config.h
*
*/
#ifndef __CONFIG_H__
#define __CONFIG_H__
/*
* Select one of the following definitions
*/
//#define CONFIG_JZ4730 1
#define CONFIG_JZ4740 1
#endif /* __CONFIG_H__ */

5045
nandboot/include/jz4730.h Normal file

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,52 @@
/*
* jz4730_board.h
*
* JZ4730 board definitions.
*
* Copyright (c) 2005-2008 Ingenic Semiconductor Inc.
*
*/
#ifndef __JZ4730_BOARD_H__
#define __JZ4730_BOARD_H__
/*-------------------------------------------------------------------
* Frequency of the external OSC in Hz.
*/
#define CFG_EXTAL 12000000
/*-------------------------------------------------------------------
* CPU speed.
*/
#define CFG_CPU_SPEED 336000000
/*-------------------------------------------------------------------
* Serial console.
*/
#define CFG_UART_BASE UART3_BASE
#define CONFIG_BAUDRATE 9600
/*-------------------------------------------------------------------
* SDRAM info.
*/
// SDRAM paramters
#define CFG_SDRAM_BW16 0 /* Data bus width: 0-32bit, 1-16bit */
#define CFG_SDRAM_BANK4 1 /* Banks each chip: 0-2bank, 1-4bank */
#define CFG_SDRAM_ROW 13 /* Row address: 11 to 13 */
#define CFG_SDRAM_COL 9 /* Column address: 8 to 12 */
#define CFG_SDRAM_CASL 2 /* CAS latency: 2 or 3 */
// SDRAM Timings, unit: ns
#define CFG_SDRAM_TRAS 45 /* RAS# Active Time */
#define CFG_SDRAM_RCD 20 /* RAS# to CAS# Delay */
#define CFG_SDRAM_TPC 20 /* RAS# Precharge Time */
#define CFG_SDRAM_TRWL 7 /* Write Latency Time */
#define CFG_SDRAM_TREF 7812 /* Refresh period: 8192 refresh cycles/64ms */
/*-------------------------------------------------------------------
* Linux kernel command line.
*/
#define CFG_CMDLINE "mem=32M console=ttyS0,57600n8 ip=off rootfstype=yaffs2 root=/dev/mtdblock2 rw init=/etc/inittab"
#endif /* __JZ4730_BOARD_H__ */

4762
nandboot/include/jz4740.h Normal file

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,57 @@
/*
* jz4740_board.h
*
* JZ4740 board definitions.
*
* Copyright (c) 2005-2008 Ingenic Semiconductor Inc.
*
*/
#ifndef __JZ4740_BOARD_H__
#define __JZ4740_BOARD_H__
/*-------------------------------------------------------------------
* NAND Boot config code
*/
#define JZ4740_NANDBOOT_CFG JZ4740_NANDBOOT_B8R3 /* NAND Boot config code */
/*-------------------------------------------------------------------
* Frequency of the external OSC in Hz.
*/
#define CFG_EXTAL 12000000
/*-------------------------------------------------------------------
* CPU speed.
*/
#define CFG_CPU_SPEED 336000000
/*-------------------------------------------------------------------
* Serial console.
*/
#define CFG_UART_BASE UART0_BASE
#define CONFIG_BAUDRATE 57600
/*-------------------------------------------------------------------
* SDRAM info.
*/
// SDRAM paramters
#define CFG_SDRAM_BW16 0 /* Data bus width: 0-32bit, 1-16bit */
#define CFG_SDRAM_BANK4 1 /* Banks each chip: 0-2bank, 1-4bank */
#define CFG_SDRAM_ROW 13 /* Row address: 11 to 13 */
#define CFG_SDRAM_COL 9 /* Column address: 8 to 12 */
#define CFG_SDRAM_CASL 2 /* CAS latency: 2 or 3 */
// SDRAM Timings, unit: ns
#define CFG_SDRAM_TRAS 45 /* RAS# Active Time */
#define CFG_SDRAM_RCD 20 /* RAS# to CAS# Delay */
#define CFG_SDRAM_TPC 20 /* RAS# Precharge Time */
#define CFG_SDRAM_TRWL 7 /* Write Latency Time */
#define CFG_SDRAM_TREF 7812 /* Refresh period: 8192 refresh cycles/64ms */
/*-------------------------------------------------------------------
* Linux kernel command line.
*/
#define CFG_CMDLINE "mem=32M console=ttyS0,57600n8 ip=off rootfstype=yaffs2 root=/dev/mtdblock2 rw init=/etc/inittab"
#endif /* __JZ4740_BOARD_H__ */

70
nandboot/include/nand.h Normal file
View File

@ -0,0 +1,70 @@
/*
* nand.h
*
* Standard NAND Flash definitions.
*/
#ifndef __NAND_H__
#define __NAND_H__
/*
* Standard NAND flash commands
*/
#define NAND_CMD_READ0 0
#define NAND_CMD_READ1 1
#define NAND_CMD_RNDOUT 5
#define NAND_CMD_PAGEPROG 0x10
#define NAND_CMD_READOOB 0x50
#define NAND_CMD_ERASE1 0x60
#define NAND_CMD_STATUS 0x70
#define NAND_CMD_STATUS_MULTI 0x71
#define NAND_CMD_SEQIN 0x80
#define NAND_CMD_RNDIN 0x85
#define NAND_CMD_READID 0x90
#define NAND_CMD_ERASE2 0xd0
#define NAND_CMD_RESET 0xff
/* Extended commands for large page devices */
#define NAND_CMD_READSTART 0x30
#define NAND_CMD_RNDOUTSTART 0xE0
#define NAND_CMD_CACHEDPROG 0x15
/* Status bits */
#define NAND_STATUS_FAIL 0x01
#define NAND_STATUS_FAIL_N1 0x02
#define NAND_STATUS_TRUE_READY 0x20
#define NAND_STATUS_READY 0x40
#define NAND_STATUS_WP 0x80
/*
* NAND Flash Manufacturer ID Codes
*/
#define NAND_MFR_TOSHIBA 0x98
#define NAND_MFR_SAMSUNG 0xec
#define NAND_MFR_FUJITSU 0x04
#define NAND_MFR_NATIONAL 0x8f
#define NAND_MFR_RENESAS 0x07
#define NAND_MFR_STMICRO 0x20
#define NAND_MFR_HYNIX 0xad
#define NAND_MFR_MICRON 0x2c
/*
* NAND parameter struct
*/
struct nand_param {
unsigned int bus_width; /* data bus width: 8-bit/16-bit */
unsigned int row_cycle; /* row address cycles: 2/3 */
unsigned int page_size; /* page size in bytes: 512/2048 */
unsigned int oob_size; /* oob size in bytes: 16/64 */
unsigned int page_per_block; /* pages per block: 32/64/128 */
unsigned int bad_block_pos; /* bad block pos in oob: 0/5 */
};
/*
* NAND routines
*/
extern void nand_enable(void);
extern void nand_disable(void);
extern int block_is_bad(struct nand_param *nandp, int block);
extern int nand_read_page(struct nand_param *nandp, int block, int page, unsigned char *dst);
#endif /* __NAND_H__ */

8
nandboot/include/types.h Normal file
View File

@ -0,0 +1,8 @@
#ifndef __TYPES_H__
#define __TYPES_H__
#define u32 unsigned int
#define u16 unsigned short
#define u8 unsigned char
#endif /* __TYPES_H__ */

36
nandboot/src/Makefile Normal file
View File

@ -0,0 +1,36 @@
#
# Makefile of the n-boot
#
# Copyright (c) 2005-2008 Ingenic Semiconductor Inc.
#
# 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.
#
OBJS := head.o nand_boot.o cpu.o jz_serial.o \
jz4730.o jz4730_nand.o jz4730_board.o \
jz4740.o jz4740_nand.o jz4740_board.o
CROSS := mipsel-openwrt-linux-
CFLAGS := -O2 -G 0 -mno-abicalls -fno-pic -mips32 -I../include -I../
AFLAGS = -D__ASSEMBLY__ $(CFLAGS)
LDFLAGS := -T ld.script -nostdlib -EL
.c.o:
$(CROSS)gcc $(CFLAGS) -c $< -o $@
.S.o:
$(CROSS)gcc $(AFLAGS) -c $< -o $@
n-boot.bin: n-boot
$(CROSS)objdump -D n-boot $< > n-boot.dump
$(CROSS)objcopy -O binary $< $@
n-boot: $(OBJS)
$(CROSS)ld $(LDFLAGS) $^ -o $@
clean:
rm -fr *.o n-boot n-boot.bin n-boot.dump

106
nandboot/src/cpu.c Normal file
View File

@ -0,0 +1,106 @@
/*
* cpu.c
*
* CPU common routines
*
* Copyright (c) 2005-2008 Ingenic Semiconductor Inc.
* Author: Peter Wei <jlwei@ingenic.cn>
*
* 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.
*/
#include <types.h>
/*
* Cache Operations
*/
#define Index_Invalidate_I 0x00
#define Index_Writeback_Inv_D 0x01
#define Index_Invalidate_SI 0x02
#define Index_Writeback_Inv_SD 0x03
#define Index_Load_Tag_I 0x04
#define Index_Load_Tag_D 0x05
#define Index_Load_Tag_SI 0x06
#define Index_Load_Tag_SD 0x07
#define Index_Store_Tag_I 0x08
#define Index_Store_Tag_D 0x09
#define Index_Store_Tag_SI 0x0A
#define Index_Store_Tag_SD 0x0B
#define Create_Dirty_Excl_D 0x0d
#define Create_Dirty_Excl_SD 0x0f
#define Hit_Invalidate_I 0x10
#define Hit_Invalidate_D 0x11
#define Hit_Invalidate_SI 0x12
#define Hit_Invalidate_SD 0x13
#define Fill 0x14
#define Hit_Writeback_Inv_D 0x15
/* 0x16 is unused */
#define Hit_Writeback_Inv_SD 0x17
#define Hit_Writeback_I 0x18
#define Hit_Writeback_D 0x19
/* 0x1a is unused */
#define Hit_Writeback_SD 0x1b
/* 0x1c is unused */
/* 0x1e is unused */
#define Hit_Set_Virtual_SI 0x1e
#define Hit_Set_Virtual_SD 0x1f
#define CFG_DCACHE_SIZE 16384
#define CFG_ICACHE_SIZE 16384
#define CFG_CACHELINE_SIZE 32
#define K0BASE 0x80000000
void flush_icache_all(void)
{
unsigned int addr, t = 0;
asm volatile ("mtc0 $0, $28"); /* Clear Taglo */
asm volatile ("mtc0 $0, $29"); /* Clear TagHi */
for (addr = K0BASE; addr < K0BASE + CFG_ICACHE_SIZE;
addr += CFG_CACHELINE_SIZE) {
asm volatile (
".set mips3\n\t"
" cache %0, 0(%1)\n\t"
".set mips2\n\t"
:
: "I" (Index_Store_Tag_I), "r"(addr));
}
/* invalicate btb */
asm volatile (
".set mips32\n\t"
"mfc0 %0, $16, 7\n\t"
"nop\n\t"
"ori %0,2\n\t"
"mtc0 %0, $16, 7\n\t"
".set mips2\n\t"
:
: "r" (t));
}
void flush_dcache_all(void)
{
unsigned int addr;
for (addr = K0BASE; addr < K0BASE + CFG_DCACHE_SIZE;
addr += CFG_CACHELINE_SIZE) {
asm volatile (
".set mips3\n\t"
" cache %0, 0(%1)\n\t"
".set mips2\n\t"
:
: "I" (Index_Writeback_Inv_D), "r"(addr));
}
asm volatile ("sync");
}
void flush_cache_all(void)
{
flush_dcache_all();
flush_icache_all();
}

50
nandboot/src/head.S Normal file
View File

@ -0,0 +1,50 @@
/*
* head.S
*
* Entry of n-boot
*
* Copyright (c) 2005-2008 Ingenic Semiconductor Inc.
* Author: <jlwei@ingenic.cn>
*
* 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.
*/
#include <config.h>
#ifdef CONFIG_JZ4740
#include <jz4740.h>
#include <jz4740_board.h>
#endif
.text
.set noreorder
.global startup
startup:
#ifdef CONFIG_JZ4740
.word JZ4740_NANDBOOT_CFG /* fetched by CPU during NAND Boot */
#endif
/*
* Disable all interrupts
*/
la $8, 0xB0001004 /* INTC_IMR */
li $9, 0xffffffff
sw $9, 0($8)
/*
* CU0=UM=EXL=IE=0, BEV=ERL=1, IP2~7=1
*/
li $26, 0x0040FC04
mtc0 $26, $12 /* CP0_STATUS */
/* IV=1, use the specical interrupt vector (0x200) */
li $26, 0x00800000
mtc0 $26, $13 /* CP0_CAUSE */
/* Setup stack pointer */
la $29, 0x80004000
/* Jump to the nand boot routine */
j nand_boot
nop
.set reorder

161
nandboot/src/jz4730.c Normal file
View File

@ -0,0 +1,161 @@
/*
* jz4730.c
*
* JZ4730 common routines
*
* Copyright (c) 2005-2007 Ingenic Semiconductor Inc.
* Author: <jlwei@ingenic.cn>
*
* 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.
*/
#include <config.h>
#ifdef CONFIG_JZ4730
#include <jz4730.h>
#include <jz4730_board.h>
void pll_init(void)
{
unsigned int nf, plcr1;
nf = CFG_CPU_SPEED * 2 / CFG_EXTAL;
plcr1 = ((nf-2) << CPM_PLCR1_PLL1FD_BIT) |
(0 << CPM_PLCR1_PLL1RD_BIT) | /* RD=0, NR=2, 1.8432 = 3.6864/2 */
(0 << CPM_PLCR1_PLL1OD_BIT) | /* OD=0, NO=1 */
(0x20 << CPM_PLCR1_PLL1ST_BIT) | /* PLL stable time */
CPM_PLCR1_PLL1EN; /* enable PLL */
/* Clock divisors.
*
* CFCR values: when CPM_CFCR_UCS(bit 28) is set, select external USB clock.
*
* 0x00411110 -> 1:2:2:2:2
* 0x00422220 -> 1:3:3:3:3
* 0x00433330 -> 1:4:4:4:4
* 0x00444440 -> 1:6:6:6:6
* 0x00455550 -> 1:8:8:8:8
* 0x00466660 -> 1:12:12:12:12
*/
REG_CPM_CFCR = 0x00422220 | (((CFG_CPU_SPEED/48000000) - 1) << 25);
/* PLL out frequency */
REG_CPM_PLCR1 = plcr1;
}
#define MEM_CLK (CFG_CPU_SPEED / 3)
/*
* Init SDRAM memory.
*/
void sdram_init(void)
{
register unsigned int dmcr0, dmcr, sdmode, tmp, ns;
unsigned int cas_latency_sdmr[2] = {
EMC_SDMR_CAS_2,
EMC_SDMR_CAS_3,
};
unsigned int cas_latency_dmcr[2] = {
1 << EMC_DMCR_TCL_BIT, /* CAS latency is 2 */
2 << EMC_DMCR_TCL_BIT /* CAS latency is 3 */
};
REG_EMC_BCR = 0; /* Disable bus release */
REG_EMC_RTCSR = 0; /* Disable clock for counting */
/* Fault DMCR value for mode register setting*/
#define SDRAM_ROW0 11
#define SDRAM_COL0 8
#define SDRAM_BANK40 0
dmcr0 = ((SDRAM_ROW0-11)<<EMC_DMCR_RA_BIT) |
((SDRAM_COL0-8)<<EMC_DMCR_CA_BIT) |
(SDRAM_BANK40<<EMC_DMCR_BA_BIT) |
(CFG_SDRAM_BW16<<EMC_DMCR_BW_BIT) |
EMC_DMCR_EPIN |
cas_latency_dmcr[((CFG_SDRAM_CASL == 3) ? 1 : 0)];
/* Basic DMCR value */
dmcr = ((CFG_SDRAM_ROW-11)<<EMC_DMCR_RA_BIT) |
((CFG_SDRAM_COL-8)<<EMC_DMCR_CA_BIT) |
(CFG_SDRAM_BANK4<<EMC_DMCR_BA_BIT) |
(CFG_SDRAM_BW16<<EMC_DMCR_BW_BIT) |
EMC_DMCR_EPIN |
cas_latency_dmcr[((CFG_SDRAM_CASL == 3) ? 1 : 0)];
/* SDRAM timing */
ns = 1000000000 / MEM_CLK;
tmp = CFG_SDRAM_TRAS/ns;
if (tmp < 4)
tmp = 4;
if (tmp > 11)
tmp = 11;
dmcr |= ((tmp-4) << EMC_DMCR_TRAS_BIT);
tmp = CFG_SDRAM_RCD/ns;
if (tmp > 3)
tmp = 3;
dmcr |= (tmp << EMC_DMCR_RCD_BIT);
tmp = CFG_SDRAM_TPC/ns;
if (tmp > 7)
tmp = 7;
dmcr |= (tmp << EMC_DMCR_TPC_BIT);
tmp = CFG_SDRAM_TRWL/ns;
if (tmp > 3)
tmp = 3;
dmcr |= (tmp << EMC_DMCR_TRWL_BIT);
tmp = (CFG_SDRAM_TRAS + CFG_SDRAM_TPC)/ns;
if (tmp > 14)
tmp = 14;
dmcr |= (((tmp + 1) >> 1) << EMC_DMCR_TRC_BIT);
/* SDRAM mode value */
sdmode = EMC_SDMR_BT_SEQ |
EMC_SDMR_OM_NORMAL |
EMC_SDMR_BL_4 |
cas_latency_sdmr[((CFG_SDRAM_CASL == 3) ? 1 : 0)];
if (CFG_SDRAM_BW16)
sdmode <<= 1;
else
sdmode <<= 2;
/* Stage 1. Precharge all banks by writing SDMR with DMCR.MRSET=0 */
REG_EMC_DMCR = dmcr;
REG8(EMC_SDMR0|sdmode) = 0;
REG8(EMC_SDMR1|sdmode) = 0;
/* Wait for precharge, > 200us */
tmp = (CFG_CPU_SPEED / 1000000) * 1000;
while (tmp--);
/* Stage 2. Enable auto-refresh */
REG_EMC_DMCR = dmcr | EMC_DMCR_RFSH;
tmp = CFG_SDRAM_TREF/ns;
tmp = tmp/64 + 1;
if (tmp > 0xff) tmp = 0xff;
REG_EMC_RTCOR = tmp;
REG_EMC_RTCNT = 0;
REG_EMC_RTCSR = EMC_RTCSR_CKS_64; /* Divisor is 64, CKO/64 */
/* Wait for number of auto-refresh cycles */
tmp = (CFG_CPU_SPEED / 1000000) * 1000;
while (tmp--);
/* Stage 3. Mode Register Set */
REG_EMC_DMCR = dmcr0 | EMC_DMCR_RFSH | EMC_DMCR_MRSET;
REG8(EMC_SDMR0|sdmode) = 0;
REG8(EMC_SDMR1|sdmode) = 0;
/* Set back to the ture basic DMCR value */
REG_EMC_DMCR = dmcr | EMC_DMCR_RFSH | EMC_DMCR_MRSET;
/* everything is ok now */
}
#endif /* CONFIG_JZ4730 */

View File

@ -0,0 +1,29 @@
/*
* board-pmp.c
*
* JZ4730-based PMP board routines.
*
* Copyright (c) 2005-2008 Ingenic Semiconductor Inc.
* Author: <jlwei@ingenic.cn>
*
* 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.
*/
#include <config.h>
#include <jz4730.h>
#include <jz4730_board.h>
#ifdef CONFIG_JZ4730
void gpio_init(void)
{
__harb_usb0_uhc();
__gpio_as_emc();
__gpio_as_uart0();
__gpio_as_uart3();
}
#endif /* CONFIG_JZ4730 */

254
nandboot/src/jz4730_nand.c Normal file
View File

@ -0,0 +1,254 @@
/*
* jz4730_nand.c
*
* NAND read routine for JZ4730
*
* Copyright (c) 2005-2008 Ingenic Semiconductor Inc.
*
* 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.
*/
#include <config.h>
#ifdef CONFIG_JZ4730
#include <nand.h>
#include <jz4730.h>
/* NAND command/address/data port */
#define NAND_DATAPORT 0xB4000000 /* read-write area */
#define NAND_CMDPORT 0xB4040000 /* write only area */
#define NAND_ADDRPORT 0xB4080000 /* write only area */
#define ECC_BLOCK 256 /* 3-bytes HW ECC per 256-bytes data */
#define ECC_POS 4 /* ECC offset to spare area */
#define __nand_enable() (REG_EMC_NFCSR |= EMC_NFCSR_NFE | EMC_NFCSR_FCE)
#define __nand_disable() (REG_EMC_NFCSR &= ~(EMC_NFCSR_NFE | EMC_NFCSR_FCE))
#define __nand_ecc_enable() (REG_EMC_NFCSR |= EMC_NFCSR_ECCE | EMC_NFCSR_ERST)
#define __nand_ecc_disable() (REG_EMC_NFCSR &= ~EMC_NFCSR_ECCE)
#define __nand_ready() (REG_EMC_NFCSR & EMC_NFCSR_RB)
#define __nand_sync() while (!__nand_ready())
#define __nand_ecc() (REG_EMC_NFECC & 0x00ffffff)
#define __nand_cmd(n) (REG8(NAND_CMDPORT) = (n))
#define __nand_addr(n) (REG8(NAND_ADDRPORT) = (n))
#define __nand_data8() REG8(NAND_DATAPORT)
#define __nand_data16() REG16(NAND_DATAPORT)
/*--------------------------------------------------------------*/
static inline void nand_wait_ready(void)
{
__nand_sync();
}
static inline void nand_read_buf16(void *buf, int count)
{
int i;
u16 *p = (u16 *)buf;
for (i = 0; i < count; i += 2)
*p++ = __nand_data16();
}
static inline void nand_read_buf8(void *buf, int count)
{
int i;
u8 *p = (u8 *)buf;
for (i = 0; i < count; i++)
*p++ = __nand_data8();
}
static inline void nand_read_buf(void *buf, int count, int bw)
{
if (bw == 8)
nand_read_buf8(buf, count);
else
nand_read_buf16(buf, count);
}
/*
* Read oob
*/
static int nand_read_oob(struct nand_param *nandp, int page_addr, u8 *buf, int size)
{
int page_size, row_cycle, bus_width;
int col_addr;
page_size = nandp->page_size;
row_cycle = nandp->row_cycle;
bus_width = nandp->bus_width;
if (page_size == 2048)
col_addr = 2048;
else
col_addr = 0;
if (page_size == 2048)
/* Send READ0 command */
__nand_cmd(NAND_CMD_READ0);
else
/* Send READOOB command */
__nand_cmd(NAND_CMD_READOOB);
/* Send column address */
__nand_addr(col_addr & 0xff);
if (page_size == 2048)
__nand_addr((col_addr >> 8) & 0xff);
/* Send page address */
__nand_addr(page_addr & 0xff);
__nand_addr((page_addr >> 8) & 0xff);
if (row_cycle == 3)
__nand_addr((page_addr >> 16) & 0xff);
/* Send READSTART command for 2048 ps NAND */
if (page_size == 2048)
__nand_cmd(NAND_CMD_READSTART);
/* Wait for device ready */
nand_wait_ready();
/* Read oob data */
nand_read_buf(buf, size, bus_width);
return 0;
}
/*
* nand_read_page()
*
* Input:
*
* nandp - pointer to nand info
* block - block number: 0, 1, 2, ...
* page - page number within a block: 0, 1, 2, ...
* dst - pointer to target buffer
*/
int nand_read_page(struct nand_param *nandp, int block, int page, u8 *dst)
{
int page_size, oob_size, page_per_block;
int row_cycle, bus_width, ecc_count;
int page_addr, i, j;
u8 *databuf;
u8 oob_buf[64];
u32 calc_ecc[8];
page_size = nandp->page_size;
oob_size = nandp->oob_size;
page_per_block = nandp->page_per_block;
row_cycle = nandp->row_cycle;
bus_width = nandp->bus_width;
page_addr = page + block * page_per_block;
/*
* Read page data
*/
/* Send READ0 command */
__nand_cmd(NAND_CMD_READ0);
/* Send column address */
__nand_addr(0);
if (page_size == 2048)
__nand_addr(0);
/* Send page address */
__nand_addr(page_addr & 0xff);
__nand_addr((page_addr >> 8) & 0xff);
if (row_cycle == 3)
__nand_addr((page_addr >> 16) & 0xff);
/* Send READSTART command for 2048 ps NAND */
if (page_size == 2048)
__nand_cmd(NAND_CMD_READSTART);
/* Wait for device ready */
nand_wait_ready();
/* Read page data */
databuf = dst;
ecc_count = page_size / ECC_BLOCK;
for (i = 0; i < ecc_count; i++) {
/* Enable HW ECC */
__nand_ecc_enable();
/* Read data */
nand_read_buf((void *)databuf, ECC_BLOCK, bus_width);
/* Disable HW ECC */
__nand_ecc_disable();
/* Record the ECC */
calc_ecc[i] = __nand_ecc();
databuf += ECC_BLOCK;
}
/*
* Read oob data
*/
nand_read_oob(nandp, page_addr, oob_buf, oob_size);
/*
* ECC correction
*
* Note: the ECC correction algorithm should be conformed to
* the encoding algorithm. It depends on what encoding algorithm
* is used? SW ECC? HW ECC?
*/
return 0;
}
/*
* Check bad block
*
* Note: the bad block flag may be store in either the first or the last
* page of the block.
*/
int block_is_bad(struct nand_param *nandp, int block)
{
int page_addr;
u8 oob_buf[64];
page_addr = block * nandp->page_per_block;
nand_read_oob(nandp, page_addr, oob_buf, nandp->oob_size);
if (oob_buf[nandp->bad_block_pos] != 0xff)
return 1;
page_addr = (block + 1) * nandp->page_per_block - 1;
nand_read_oob(nandp, page_addr, oob_buf, nandp->oob_size);
if (oob_buf[nandp->bad_block_pos] != 0xff)
return 1;
return 0;
}
/*
* Enable NAND controller
*/
void nand_enable(void)
{
__nand_enable();
REG_EMC_SMCR3 = 0x04444400;
}
/*
* Disable NAND controller
*/
void nand_disable(void)
{
__nand_disable();
}
#endif /* CONFIG_JZ4730 */

165
nandboot/src/jz4740.c Normal file
View File

@ -0,0 +1,165 @@
/*
* jz4740.c
*
* JZ4740 common routines
*
* Copyright (c) 2005-2008 Ingenic Semiconductor Inc.
* Author: Peter Wei <jlwei@ingenic.cn>
*
* 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.
*/
#include <config.h>
#ifdef CONFIG_JZ4740
#include <jz4740.h>
#include <jz4740_board.h>
/* PLL output clock = EXTAL * NF / (NR * NO)
*
* NF = FD + 2, NR = RD + 2
* NO = 1 (if OD = 0), NO = 2 (if OD = 1 or 2), NO = 4 (if OD = 3)
*/
void pll_init(void)
{
register unsigned int cfcr, plcr1;
int n2FR[33] = {
0, 0, 1, 2, 3, 0, 4, 0, 5, 0, 0, 0, 6, 0, 0, 0,
7, 0, 0, 0, 0, 0, 0, 0, 8, 0, 0, 0, 0, 0, 0, 0,
9
};
int div[5] = {1, 3, 3, 3, 3}; /* divisors of I:S:P:M:L */
int nf, pllout2;
cfcr = CPM_CPCCR_CLKOEN |
CPM_CPCCR_PCS |
(n2FR[div[0]] << CPM_CPCCR_CDIV_BIT) |
(n2FR[div[1]] << CPM_CPCCR_HDIV_BIT) |
(n2FR[div[2]] << CPM_CPCCR_PDIV_BIT) |
(n2FR[div[3]] << CPM_CPCCR_MDIV_BIT) |
(n2FR[div[4]] << CPM_CPCCR_LDIV_BIT);
pllout2 = (cfcr & CPM_CPCCR_PCS) ? CFG_CPU_SPEED : (CFG_CPU_SPEED / 2);
/* Init USB Host clock, pllout2 must be n*48MHz */
REG_CPM_UHCCDR = pllout2 / 48000000 - 1;
nf = CFG_CPU_SPEED * 2 / CFG_EXTAL;
plcr1 = ((nf - 2) << CPM_CPPCR_PLLM_BIT) | /* FD */
(0 << CPM_CPPCR_PLLN_BIT) | /* RD=0, NR=2 */
(0 << CPM_CPPCR_PLLOD_BIT) | /* OD=0, NO=1 */
(0x20 << CPM_CPPCR_PLLST_BIT) | /* PLL stable time */
CPM_CPPCR_PLLEN; /* enable PLL */
/* init PLL */
REG_CPM_CPCCR = cfcr;
REG_CPM_CPPCR = plcr1;
}
/*
* Init SDRAM memory.
*/
void sdram_init(void)
{
register unsigned int dmcr0, dmcr, sdmode, tmp, cpu_clk, mem_clk, ns;
unsigned int cas_latency_sdmr[2] = {
EMC_SDMR_CAS_2,
EMC_SDMR_CAS_3,
};
unsigned int cas_latency_dmcr[2] = {
1 << EMC_DMCR_TCL_BIT, /* CAS latency is 2 */
2 << EMC_DMCR_TCL_BIT /* CAS latency is 3 */
};
int div[] = {1, 2, 3, 4, 6, 8, 12, 16, 24, 32};
cpu_clk = CFG_CPU_SPEED;
mem_clk = cpu_clk * div[__cpm_get_cdiv()] / div[__cpm_get_mdiv()];
REG_EMC_BCR = 0; /* Disable bus release */
REG_EMC_RTCSR = 0; /* Disable clock for counting */
/* Fault DMCR value for mode register setting*/
#define SDRAM_ROW0 11
#define SDRAM_COL0 8
#define SDRAM_BANK40 0
dmcr0 = ((SDRAM_ROW0-11)<<EMC_DMCR_RA_BIT) |
((SDRAM_COL0-8)<<EMC_DMCR_CA_BIT) |
(SDRAM_BANK40<<EMC_DMCR_BA_BIT) |
(CFG_SDRAM_BW16<<EMC_DMCR_BW_BIT) |
EMC_DMCR_EPIN |
cas_latency_dmcr[((CFG_SDRAM_CASL == 3) ? 1 : 0)];
/* Basic DMCR value */
dmcr = ((CFG_SDRAM_ROW-11)<<EMC_DMCR_RA_BIT) |
((CFG_SDRAM_COL-8)<<EMC_DMCR_CA_BIT) |
(CFG_SDRAM_BANK4<<EMC_DMCR_BA_BIT) |
(CFG_SDRAM_BW16<<EMC_DMCR_BW_BIT) |
EMC_DMCR_EPIN |
cas_latency_dmcr[((CFG_SDRAM_CASL == 3) ? 1 : 0)];
/* SDRAM timimg */
ns = 1000000000 / mem_clk;
tmp = CFG_SDRAM_TRAS/ns;
if (tmp < 4) tmp = 4;
if (tmp > 11) tmp = 11;
dmcr |= ((tmp-4) << EMC_DMCR_TRAS_BIT);
tmp = CFG_SDRAM_RCD/ns;
if (tmp > 3) tmp = 3;
dmcr |= (tmp << EMC_DMCR_RCD_BIT);
tmp = CFG_SDRAM_TPC/ns;
if (tmp > 7) tmp = 7;
dmcr |= (tmp << EMC_DMCR_TPC_BIT);
tmp = CFG_SDRAM_TRWL/ns;
if (tmp > 3) tmp = 3;
dmcr |= (tmp << EMC_DMCR_TRWL_BIT);
tmp = (CFG_SDRAM_TRAS + CFG_SDRAM_TPC)/ns;
if (tmp > 14) tmp = 14;
dmcr |= (((tmp + 1) >> 1) << EMC_DMCR_TRC_BIT);
/* SDRAM mode value */
sdmode = EMC_SDMR_BT_SEQ |
EMC_SDMR_OM_NORMAL |
EMC_SDMR_BL_4 |
cas_latency_sdmr[((CFG_SDRAM_CASL == 3) ? 1 : 0)];
/* Stage 1. Precharge all banks by writing SDMR with DMCR.MRSET=0 */
REG_EMC_DMCR = dmcr;
REG8(EMC_SDMR0|sdmode) = 0;
/* Wait for precharge, > 200us */
tmp = (cpu_clk / 1000000) * 1000;
while (tmp--);
/* Stage 2. Enable auto-refresh */
REG_EMC_DMCR = dmcr | EMC_DMCR_RFSH;
tmp = CFG_SDRAM_TREF/ns;
tmp = tmp/64 + 1;
if (tmp > 0xff) tmp = 0xff;
REG_EMC_RTCOR = tmp;
REG_EMC_RTCNT = 0;
REG_EMC_RTCSR = EMC_RTCSR_CKS_64; /* Divisor is 64, CKO/64 */
/* Wait for number of auto-refresh cycles */
tmp = (cpu_clk / 1000000) * 1000;
while (tmp--);
/* Stage 3. Mode Register Set */
REG_EMC_DMCR = dmcr0 | EMC_DMCR_RFSH | EMC_DMCR_MRSET;
REG8(EMC_SDMR0|sdmode) = 0;
/* Set back to basic DMCR value */
REG_EMC_DMCR = dmcr | EMC_DMCR_RFSH | EMC_DMCR_MRSET;
/* everything is ok now */
}
#endif /* CONFIG_JZ4740 */

View File

@ -0,0 +1,28 @@
/*
* board-pmp.c
*
* JZ4730-based PMP board routines.
*
* Copyright (c) 2005-2008 Ingenic Semiconductor Inc.
* Author: <jlwei@ingenic.cn>
*
* 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.
*/
#include <config.h>
#ifdef CONFIG_JZ4740
#include <jz4740.h>
#include <jz4740_board.h>
void gpio_init(void)
{
__gpio_as_uart0();
__gpio_as_sdram_32bit();
}
#endif /* CONFIG_JZ4740 */

329
nandboot/src/jz4740_nand.c Normal file
View File

@ -0,0 +1,329 @@
/*
* jz4740_nand.c
*
* NAND read routine for JZ4740
*
* Copyright (c) 2005-2008 Ingenic Semiconductor Inc.
*
* 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.
*/
#include <config.h>
#ifdef CONFIG_JZ4740
#include <nand.h>
#include <jz4740.h>
#define NAND_DATAPORT 0xb8000000
#define NAND_ADDRPORT 0xb8010000
#define NAND_COMMPORT 0xb8008000
#define ECC_BLOCK 512
#define ECC_POS 6
#define PAR_SIZE 9
#define __nand_cmd(n) (REG8(NAND_COMMPORT) = (n))
#define __nand_addr(n) (REG8(NAND_ADDRPORT) = (n))
#define __nand_data8() REG8(NAND_DATAPORT)
#define __nand_data16() REG16(NAND_DATAPORT)
#define __nand_enable() (REG_EMC_NFCSR |= EMC_NFCSR_NFE1 | EMC_NFCSR_NFCE1)
#define __nand_disable() (REG_EMC_NFCSR &= ~(EMC_NFCSR_NFCE1))
#define __nand_ecc_rs_encoding() \
(REG_EMC_NFECR = EMC_NFECR_ECCE | EMC_NFECR_ERST | EMC_NFECR_RS | EMC_NFECR_RS_ENCODING)
#define __nand_ecc_rs_decoding() \
(REG_EMC_NFECR = EMC_NFECR_ECCE | EMC_NFECR_ERST | EMC_NFECR_RS | EMC_NFECR_RS_DECODING)
#define __nand_ecc_disable() (REG_EMC_NFECR &= ~EMC_NFECR_ECCE)
#define __nand_ecc_encode_sync() while (!(REG_EMC_NFINTS & EMC_NFINTS_ENCF))
#define __nand_ecc_decode_sync() while (!(REG_EMC_NFINTS & EMC_NFINTS_DECF))
/*--------------------------------------------------------------*/
static inline void nand_wait_ready(void)
{
unsigned int timeout = 1000;
while ((REG_GPIO_PXPIN(2) & 0x40000000) && timeout--);
while (!(REG_GPIO_PXPIN(2) & 0x40000000));
}
static inline void nand_read_buf16(void *buf, int count)
{
int i;
u16 *p = (u16 *)buf;
for (i = 0; i < count; i += 2)
*p++ = __nand_data16();
}
static inline void nand_read_buf8(void *buf, int count)
{
int i;
u8 *p = (u8 *)buf;
for (i = 0; i < count; i++)
*p++ = __nand_data8();
}
static inline void nand_read_buf(void *buf, int count, int bw)
{
if (bw == 8)
nand_read_buf8(buf, count);
else
nand_read_buf16(buf, count);
}
/*
* Correct 1~9-bit errors in 512-bytes data
*/
static void rs_correct(unsigned char *dat, int idx, int mask)
{
int i, j;
unsigned short d, d1, dm;
i = (idx * 9) >> 3;
j = (idx * 9) & 0x7;
i = (j == 0) ? (i - 1) : i;
j = (j == 0) ? 7 : (j - 1);
if (i > 512) return;
if (i == 512)
d = dat[i - 1];
else
d = (dat[i] << 8) | dat[i - 1];
d1 = (d >> j) & 0x1ff;
d1 ^= mask;
dm = ~(0x1ff << j);
d = (d & dm) | (d1 << j);
dat[i - 1] = d & 0xff;
if (i < 512)
dat[i] = (d >> 8) & 0xff;
}
/*
* Read oob
*/
static int nand_read_oob(struct nand_param *nandp, int page_addr, u8 *buf, int size)
{
int page_size, row_cycle, bus_width;
int col_addr;
page_size = nandp->page_size;
row_cycle = nandp->row_cycle;
bus_width = nandp->bus_width;
if (page_size == 2048)
col_addr = 2048;
else
col_addr = 0;
if (page_size == 2048)
/* Send READ0 command */
__nand_cmd(NAND_CMD_READ0);
else
/* Send READOOB command */
__nand_cmd(NAND_CMD_READOOB);
/* Send column address */
__nand_addr(col_addr & 0xff);
if (page_size == 2048)
__nand_addr((col_addr >> 8) & 0xff);
/* Send page address */
__nand_addr(page_addr & 0xff);
__nand_addr((page_addr >> 8) & 0xff);
if (row_cycle == 3)
__nand_addr((page_addr >> 16) & 0xff);
/* Send READSTART command for 2048 ps NAND */
if (page_size == 2048)
__nand_cmd(NAND_CMD_READSTART);
/* Wait for device ready */
nand_wait_ready();
/* Read oob data */
nand_read_buf(buf, size, bus_width);
return 0;
}
/*
* nand_read_page()
*
* Input:
*
* nandp - pointer to nand info
* block - block number: 0, 1, 2, ...
* page - page number within a block: 0, 1, 2, ...
* dst - pointer to target buffer
*/
int nand_read_page(struct nand_param *nandp, int block, int page, u8 *dst)
{
int page_size, oob_size, page_per_block;
int row_cycle, bus_width, ecc_count;
int page_addr, i, j;
u8 *data_buf;
u8 oob_buf[64];
page_size = nandp->page_size;
oob_size = nandp->oob_size;
page_per_block = nandp->page_per_block;
row_cycle = nandp->row_cycle;
bus_width = nandp->bus_width;
page_addr = page + block * page_per_block;
/*
* Read oob data
*/
nand_read_oob(nandp, page_addr, oob_buf, oob_size);
/*
* Read page data
*/
/* Send READ0 command */
__nand_cmd(NAND_CMD_READ0);
/* Send column address */
__nand_addr(0);
if (page_size == 2048)
__nand_addr(0);
/* Send page address */
__nand_addr(page_addr & 0xff);
__nand_addr((page_addr >> 8) & 0xff);
if (row_cycle == 3)
__nand_addr((page_addr >> 16) & 0xff);
/* Send READSTART command for 2048 ps NAND */
if (page_size == 2048)
__nand_cmd(NAND_CMD_READSTART);
/* Wait for device ready */
nand_wait_ready();
/* Read page data */
data_buf = dst;
ecc_count = page_size / ECC_BLOCK;
for (i = 0; i < ecc_count; i++) {
volatile u8 *paraddr = (volatile u8 *)EMC_NFPAR0;
unsigned int stat;
/* Enable RS decoding */
REG_EMC_NFINTS = 0x0;
__nand_ecc_rs_decoding();
/* Read data */
nand_read_buf((void *)data_buf, ECC_BLOCK, bus_width);
/* Set PAR values */
for (j = 0; j < PAR_SIZE; j++) {
*paraddr++ = oob_buf[ECC_POS + i*PAR_SIZE + j];
}
/* Set PRDY */
REG_EMC_NFECR |= EMC_NFECR_PRDY;
/* Wait for completion */
__nand_ecc_decode_sync();
/* Disable decoding */
__nand_ecc_disable();
/* Check result of decoding */
stat = REG_EMC_NFINTS;
if (stat & EMC_NFINTS_ERR) {
/* Error occurred */
if (stat & EMC_NFINTS_UNCOR) {
/* Uncorrectable error occurred */
}
else {
unsigned int errcnt, index, mask;
errcnt = (stat & EMC_NFINTS_ERRCNT_MASK) >> EMC_NFINTS_ERRCNT_BIT;
switch (errcnt) {
case 4:
index = (REG_EMC_NFERR3 & EMC_NFERR_INDEX_MASK) >> EMC_NFERR_INDEX_BIT;
mask = (REG_EMC_NFERR3 & EMC_NFERR_MASK_MASK) >> EMC_NFERR_MASK_BIT;
rs_correct(data_buf, index, mask);
case 3:
index = (REG_EMC_NFERR2 & EMC_NFERR_INDEX_MASK) >> EMC_NFERR_INDEX_BIT;
mask = (REG_EMC_NFERR2 & EMC_NFERR_MASK_MASK) >> EMC_NFERR_MASK_BIT;
rs_correct(data_buf, index, mask);
case 2:
index = (REG_EMC_NFERR1 & EMC_NFERR_INDEX_MASK) >> EMC_NFERR_INDEX_BIT;
mask = (REG_EMC_NFERR1 & EMC_NFERR_MASK_MASK) >> EMC_NFERR_MASK_BIT;
rs_correct(data_buf, index, mask);
case 1:
index = (REG_EMC_NFERR0 & EMC_NFERR_INDEX_MASK) >> EMC_NFERR_INDEX_BIT;
mask = (REG_EMC_NFERR0 & EMC_NFERR_MASK_MASK) >> EMC_NFERR_MASK_BIT;
rs_correct(data_buf, index, mask);
break;
default:
break;
}
}
}
data_buf += ECC_BLOCK;
}
return 0;
}
/*
* Check bad block
*
* Note: the bad block flag may be store in either the first or the last
* page of the block.
*/
int block_is_bad(struct nand_param *nandp, int block)
{
int page_addr;
u8 oob_buf[64];
page_addr = block * nandp->page_per_block;
nand_read_oob(nandp, page_addr, oob_buf, nandp->oob_size);
if (oob_buf[nandp->bad_block_pos] != 0xff)
return 1;
page_addr = (block + 1) * nandp->page_per_block - 1;
nand_read_oob(nandp, page_addr, oob_buf, nandp->oob_size);
if (oob_buf[nandp->bad_block_pos] != 0xff)
return 1;
return 0;
}
/*
* Enable NAND controller
*/
void nand_enable(void)
{
__nand_enable();
REG_EMC_SMCR1 = 0x04444400;
}
/*
* Disable NAND controller
*/
void nand_disable(void)
{
__nand_disable();
}
#endif /* CONFIG_JZ4740 */

119
nandboot/src/jz_serial.c Normal file
View File

@ -0,0 +1,119 @@
/*
* Jz47xx UART support
*
* Options hardcoded to 8N1
*
* Copyright (c) 2005 - 2008, Ingenic Semiconductor Inc.
* Ingenic Semiconductor, <jlwei@ingenic.cn>
*
* 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 <config.h>
#ifdef CONFIG_JZ4730
#include <jz4730.h>
#include <jz4730_board.h>
#endif
#ifdef CONFIG_JZ4740
#include <jz4740.h>
#include <jz4740_board.h>
#endif
#undef UART_BASE
#ifndef CFG_UART_BASE
#define UART_BASE UART0_BASE
#else
#define UART_BASE CFG_UART_BASE
#endif
/******************************************************************************
*
* serial_init - initialize a channel
*
* This routine initializes the number of data bits, parity
* and set the selected baud rate. Interrupts are disabled.
* Set the modem control signals if the option is selected.
*
* RETURNS: N/A
*/
static void serial_setbrg (void)
{
volatile u8 *uart_lcr = (volatile u8 *)(UART_BASE + OFF_LCR);
volatile u8 *uart_dlhr = (volatile u8 *)(UART_BASE + OFF_DLHR);
volatile u8 *uart_dllr = (volatile u8 *)(UART_BASE + OFF_DLLR);
u32 baud_div, tmp;
baud_div = CFG_EXTAL / 16 / CONFIG_BAUDRATE;
tmp = *uart_lcr;
tmp |= UART_LCR_DLAB;
*uart_lcr = tmp;
*uart_dlhr = (baud_div >> 8) & 0xff;
*uart_dllr = baud_div & 0xff;
tmp &= ~UART_LCR_DLAB;
*uart_lcr = tmp;
}
int serial_init (void)
{
volatile u8 *uart_fcr = (volatile u8 *)(UART_BASE + OFF_FCR);
volatile u8 *uart_lcr = (volatile u8 *)(UART_BASE + OFF_LCR);
volatile u8 *uart_ier = (volatile u8 *)(UART_BASE + OFF_IER);
volatile u8 *uart_sircr = (volatile u8 *)(UART_BASE + OFF_SIRCR);
/* Disable port interrupts while changing hardware */
*uart_ier = 0;
/* Disable UART unit function */
*uart_fcr = ~UART_FCR_UUE;
/* Set both receiver and transmitter in UART mode (not SIR) */
*uart_sircr = ~(SIRCR_RSIRE | SIRCR_TSIRE);
/* Set databits, stopbits and parity. (8-bit data, 1 stopbit, no parity) */
*uart_lcr = UART_LCR_WLEN_8 | UART_LCR_STOP_1;
/* Set baud rate */
serial_setbrg();
/* Enable UART unit, enable and clear FIFO */
*uart_fcr = UART_FCR_UUE | UART_FCR_FE | UART_FCR_TFLS | UART_FCR_RFLS;
return 0;
}
void serial_putc (const char c)
{
volatile u8 *uart_lsr = (volatile u8 *)(UART_BASE + OFF_LSR);
volatile u8 *uart_tdr = (volatile u8 *)(UART_BASE + OFF_TDR);
if (c == '\n') serial_putc ('\r');
/* Wait for fifo to shift out some bytes */
while ( !((*uart_lsr & (UART_LSR_TDRQ | UART_LSR_TEMT)) == 0x60) );
*uart_tdr = (u8)c;
}
void serial_puts (const char *s)
{
while (*s) {
serial_putc (*s++);
}
}

29
nandboot/src/ld.script Normal file
View File

@ -0,0 +1,29 @@
OUTPUT_ARCH(mips)
ENTRY(startup)
MEMORY
{
ram : ORIGIN = 0x80000000 , LENGTH = 0x100000
}
SECTIONS
{
. = ALIGN(4);
.text : { *(.text*) } > ram
. = ALIGN(4);
.rodata : { *(.rodata*) } > ram
. = ALIGN(4);
.sdata : { *(.sdata*) } > ram
. = ALIGN(4);
.data : { *(.data*) *(.scommon*) *(.reginfo*) } > ram
_gp = ALIGN(16);
.got : { *(.got*) } > ram
. = ALIGN(4);
.sbss : { *(.sbss*) } > ram
.bss : { *(.bss*) } > ram
. = ALIGN (4);
}

207
nandboot/src/nand_boot.c Normal file
View File

@ -0,0 +1,207 @@
/*
* nand_boot.c
*
* NAND boot routine.
*
* Then nand boot loader can load the zImage type to execute.
* To get the zImage, build the kernel by 'make zImage'.
*
* Copyright (c) 2005-2008 Ingenic Semiconductor Inc.
* Author: <jlwei@ingenic.cn>
*
* 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.
*/
#include <config.h>
#include <nand.h>
#ifdef CONFIG_JZ4730
#include <jz4730.h>
#include <jz4730_board.h>
#endif
#ifdef CONFIG_JZ4740
#include <jz4740.h>
#include <jz4740_board.h>
#endif
/*
* NAND Flash parameters (must be conformed to the NAND being used)
*/
static struct nand_param nand_p = {
.bus_width = 8, /* data bus width: 8-bit/16-bit */
.row_cycle = 3, /* row address cycles: 2/3 */
.page_size = 2048, /* page size in bytes: 512/2048 */
.oob_size = 64, /* oob size in bytes: 16/64 */
.page_per_block = 128, /* pages per block: 32/64/128 */
.bad_block_pos = 0 /* bad block pos in oob: 0/5 */
};
#define SIZE_KB (1 * 1024)
#define SIZE_MB (1 * 1024 * 1024)
/*
* Kernel image
*/
#define CFG_KERNEL_OFFS (256 * SIZE_KB) /* NAND offset of kernel image being loaded, has to be aligned to a block address! */
#define CFG_KERNEL_SIZE (2 * SIZE_MB) /* Size of kernel image, has to be integer multiply of a block size! */
#define CFG_KERNEL_DST 0x80600000 /* Load kernel to this addr */
#define CFG_KERNEL_START 0x80600000 /* Start kernel from this addr */
/*
* Kernel parameters
*/
#define PARAM_BASE 0x80004000
/*
* Local variables
*/
static u32 *param_addr = 0;
static u8 *tmpbuf = 0;
static u8 cmdline[256] = CFG_CMDLINE;
extern void gpio_init(void);
extern int serial_init (void);
extern void pll_init(void);
extern void sdram_init(void);
/*
* Load kernel image from NAND into RAM
*/
static int nand_load(struct nand_param *nandp, int offs, int kernel_size, u8 *dst)
{
int page_size, page_per_block;
int block;
int block_size;
int blockcopy_count;
int page;
page_size = nandp->page_size;
page_per_block = nandp->page_per_block;
/*
* Enable NANDFlash controller
*/
nand_enable();
/*
* offs has to be aligned to a block address!
*/
block_size = page_size * page_per_block;
block = offs / block_size;
blockcopy_count = 0;
while (blockcopy_count < (kernel_size / block_size)) {
for (page = 0; page < page_per_block; page++) {
if (page == 0) {
/*
* New block
*/
if (block_is_bad(nandp, block)) {
block++;
/*
* Skip bad block
*/
continue;
}
}
nand_read_page(nandp, block, page, dst);
dst += page_size;
}
block++;
blockcopy_count++;
}
/*
* Disable NANDFlash controller
*/
nand_disable();
return 0;
}
/*
* NAND Boot routine
*/
void nand_boot(void)
{
unsigned int boot_sel, i;
void (*kernel)(int, char **, char *);
/*
* Init gpio, serial, pll and sdram
*/
gpio_init();
serial_init();
serial_puts("\n\nNAND Secondary Program Loader\n\n");
pll_init();
sdram_init();
#ifdef CONFIG_JZ4740
/*
* JZ4740 can detect some NAND parameters from the boot select
*/
boot_sel = REG_EMC_BCR >> 30;
if (boot_sel == 0x2)
nand_p.page_size = 512;
else
nand_p.page_size = 2048;
#endif
#ifdef CONFIG_JZ4730
/*
* JZ4730 can detect some NAND parameters from the boot select
*/
boot_sel = (REG_EMC_NFCSR & 0x70) >> 4;
nand_p.bus_width = (boot_sel & 0x1) ? 16 : 8;
nand_p.page_size = (boot_sel & 0x2) ? 2048 : 512;
nand_p.row_cycle = (boot_sel & 0x4) ? 3 : 2;
#endif
/*
* Load kernel image from NAND into RAM
*/
nand_load(&nand_p, CFG_KERNEL_OFFS, CFG_KERNEL_SIZE, (u8 *)CFG_KERNEL_DST);
serial_puts("Starting kernel ...\n\n");
/*
* Prepare kernel parameters and environment
*/
param_addr = (u32 *)PARAM_BASE;
param_addr[0] = 0; /* might be address of ascii-z string: "memsize" */
param_addr[1] = 0; /* might be address of ascii-z string: "0x01000000" */
param_addr[2] = 0;
param_addr[3] = 0;
param_addr[4] = 0;
param_addr[5] = PARAM_BASE + 32;
param_addr[6] = CFG_KERNEL_START;
tmpbuf = (u8 *)(PARAM_BASE + 32);
for (i = 0; i < 256; i++)
tmpbuf[i] = cmdline[i]; /* linux command line */
kernel = (void (*)(int, char **, char *))CFG_KERNEL_START;
/*
* Flush caches
*/
flush_cache_all();
/*
* Jump to kernel image
*/
(*kernel)(2, (char **)(PARAM_BASE + 16), (char *)PARAM_BASE);
}