mirror of
git://projects.qi-hardware.com/xburst-tools.git
synced 2024-11-01 20:21:54 +02:00
4a8bada671
Giant patch: - renames everything from kboot to qi - changes filenames accordingly in several places - fixes the linker script so stuff that does not execute from steppingstone context has real linked addresses in the relocated region, it means all code and pointers work now outside first 4KBytes - adds src/gta02/gta02.c to contain board-specific init and other functions - adds sophisticated structs to define most features in the board-specific files, including board type detection, board revision detection, and multiple kernel source definition (NAND, SD FAT, SD ext2, etc), including auto sequencing of trying the kernel sources in order (filesystems and partition support not done yet) - GTA02 detects itself by NOR presence and reports A5 / A6 - commandlines for kernel also come from board-specific kernel source definitions so correct kernel commandlines are provided depending on boot device -- on GTA02 now boots NAND kernel into NAND jffs2 filesystem - CRC32 is checked on loaded kernel image to make sure we know about corruption in bootloader Signed-off-by: Andy Green <andy@openmoko.com>
170 lines
3.8 KiB
C
170 lines
3.8 KiB
C
/*
|
|
* nand_read.c: Simple NAND read functions for booting from NAND
|
|
*
|
|
* This is used by cpu/arm920/start.S assembler code,
|
|
* and the board-specific linker script must make sure this
|
|
* file is linked within the first 4kB of NAND flash.
|
|
*
|
|
* Taken from GPLv2 licensed vivi bootloader,
|
|
* Copyright (C) 2002 MIZI Research, Inc.
|
|
*
|
|
* Author: Hwang, Chideok <hwang@mizi.com>
|
|
* Date : $Date: 2004/02/04 10:37:37 $
|
|
*
|
|
* u-boot integration and bad-block skipping (C) 2006 by OpenMoko, Inc.
|
|
* Author: Harald Welte <laforge@openmoko.org>
|
|
*/
|
|
|
|
/* NOTE this stuff runs in steppingstone context! */
|
|
|
|
|
|
#include <qi.h>
|
|
#include "nand_read.h"
|
|
|
|
#define NAND_CMD_READ0 0
|
|
#define NAND_CMD_READSTART 0x30
|
|
|
|
#define __REGb(x) (*(volatile unsigned char *)(x))
|
|
#define __REGw(x) (*(volatile unsigned short *)(x))
|
|
#define __REGi(x) (*(volatile unsigned int *)(x))
|
|
#define NF_BASE 0x4e000000
|
|
#define NFCONF __REGi(NF_BASE + 0x0)
|
|
#define NFCONT __REGi(NF_BASE + 0x4)
|
|
#define NFCMD __REGb(NF_BASE + 0x8)
|
|
#define NFADDR __REGb(NF_BASE + 0xc)
|
|
#define NFDATA __REGb(NF_BASE + 0x10)
|
|
#define NFDATA16 __REGw(NF_BASE + 0x10)
|
|
#define NFSTAT __REGb(NF_BASE + 0x20)
|
|
#define NFSTAT_BUSY 1
|
|
#define nand_select() (NFCONT &= ~(1 << 1))
|
|
#define nand_deselect() (NFCONT |= (1 << 1))
|
|
#define nand_clear_RnB() (NFSTAT |= (1 << 2))
|
|
|
|
static inline void nand_wait(void)
|
|
{
|
|
int i;
|
|
|
|
while (!(NFSTAT & NFSTAT_BUSY))
|
|
for (i=0; i<10; i++);
|
|
}
|
|
|
|
/* configuration for 2440 with 2048byte sized flash */
|
|
#define NAND_5_ADDR_CYCLE
|
|
#define NAND_PAGE_SIZE 2048
|
|
#define BAD_BLOCK_OFFSET NAND_PAGE_SIZE
|
|
#define NAND_BLOCK_MASK (NAND_PAGE_SIZE - 1)
|
|
#define NAND_BLOCK_SIZE (NAND_PAGE_SIZE * 64)
|
|
|
|
static int is_bad_block(unsigned long i)
|
|
{
|
|
unsigned char data;
|
|
unsigned long page_num;
|
|
|
|
nand_clear_RnB();
|
|
page_num = i >> 11; /* addr / 2048 */
|
|
NFCMD = NAND_CMD_READ0;
|
|
NFADDR = BAD_BLOCK_OFFSET & 0xff;
|
|
NFADDR = (BAD_BLOCK_OFFSET >> 8) & 0xff;
|
|
NFADDR = page_num & 0xff;
|
|
NFADDR = (page_num >> 8) & 0xff;
|
|
NFADDR = (page_num >> 16) & 0xff;
|
|
NFCMD = NAND_CMD_READSTART;
|
|
nand_wait();
|
|
data = (NFDATA & 0xff);
|
|
#ifdef DEBUG
|
|
serial_putc(2, '$');
|
|
serial_putc(2, '0');
|
|
serial_putc(2, 'x');
|
|
print32((unsigned int)data);
|
|
serial_putc(2, ' ');
|
|
#endif
|
|
|
|
if (data != 0xff)
|
|
return 1;
|
|
|
|
return 0;
|
|
}
|
|
|
|
static int nand_read_page_ll(unsigned char *buf, unsigned long addr)
|
|
{
|
|
unsigned short *ptr16 = (unsigned short *)buf;
|
|
unsigned int i, page_num;
|
|
#if 0
|
|
unsigned char ecc[64];
|
|
unsigned short *p16 = (unsigned short *)ecc;
|
|
#endif
|
|
|
|
nand_clear_RnB();
|
|
|
|
NFCMD = NAND_CMD_READ0;
|
|
|
|
page_num = addr >> 11; /* addr / 2048 */
|
|
/* Write Address */
|
|
NFADDR = 0;
|
|
NFADDR = 0;
|
|
NFADDR = page_num & 0xff;
|
|
NFADDR = (page_num >> 8) & 0xff;
|
|
NFADDR = (page_num >> 16) & 0xff;
|
|
NFCMD = NAND_CMD_READSTART;
|
|
nand_wait();
|
|
|
|
for (i = 0; i < NAND_PAGE_SIZE/2; i++)
|
|
*ptr16++ = NFDATA16;
|
|
#if 0
|
|
for (i = 0; i < 64 / 2; i++) {
|
|
*p16++ = NFDATA16;
|
|
}
|
|
#endif
|
|
return NAND_PAGE_SIZE;
|
|
}
|
|
|
|
/* low level nand read function */
|
|
int nand_read_ll(unsigned char *buf, unsigned long start_addr, int size)
|
|
{
|
|
int i, j;
|
|
int bad_count = 0;
|
|
|
|
if ((start_addr & NAND_BLOCK_MASK) || (size & NAND_BLOCK_MASK))
|
|
return -1; /* invalid alignment */
|
|
|
|
/* chip Enable */
|
|
nand_select();
|
|
nand_clear_RnB();
|
|
|
|
for (i = 0; i < 10; i++)
|
|
;
|
|
|
|
for (i = start_addr; i < (start_addr + size);) {
|
|
if ((i & (NAND_BLOCK_SIZE - 1)) == 0) {
|
|
if (is_bad_block(i) ||
|
|
is_bad_block(i + NAND_PAGE_SIZE)) {
|
|
serial_putc(2, '!');
|
|
serial_putc(2, '0');
|
|
serial_putc(2, 'x');
|
|
print32((unsigned int)i);
|
|
serial_putc(2, ' ');
|
|
|
|
i += NAND_BLOCK_SIZE;
|
|
size += NAND_BLOCK_SIZE;
|
|
if (bad_count++ == 4) {
|
|
serial_putc(2, '+');
|
|
serial_putc(2, '\n');
|
|
return -1;
|
|
}
|
|
serial_putc(2, '\n');
|
|
continue;
|
|
}
|
|
}
|
|
|
|
j = nand_read_page_ll(buf, i);
|
|
i += j;
|
|
buf += j;
|
|
}
|
|
|
|
/* chip Disable */
|
|
nand_deselect();
|
|
|
|
return 0;
|
|
}
|
|
|