1
0
mirror of git://projects.qi-hardware.com/xburst-tools.git synced 2025-04-21 12:27:27 +03: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

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);
}