Root/qiboot/src/cpu/s3c2410/nand_read.c

1/*
2 * nand_read.c: Simple NAND read functions for booting from NAND
3 *
4 * This is used by cpu/arm920/start.S assembler code,
5 * and the board-specific linker script must make sure this
6 * file is linked within the first 4kB of NAND flash.
7 *
8 * Taken from GPLv2 licensed vivi bootloader,
9 * Copyright (C) 2002 MIZI Research, Inc.
10 *
11 * Author: Hwang, Chideok <hwang@mizi.com>
12 * Date : $Date: 2004/02/04 10:37:37 $
13 *
14 * u-boot integration and bad-block skipping (C) 2006 by OpenMoko, Inc.
15 * Author: Harald Welte <laforge@openmoko.org>
16 */
17
18/* NOTE this stuff runs in steppingstone context! */
19
20/* the API refers to 512-byte blocks */
21
22#include <qi.h>
23#include "nand_read.h"
24
25#define NAND_CMD_READ0 0
26#define NAND_CMD_READOOB 0x50
27
28#define __REGb(x) (*(volatile unsigned char *)(x))
29#define __REGw(x) (*(volatile unsigned short *)(x))
30#define __REGi(x) (*(volatile unsigned int *)(x))
31#define NF_BASE 0x4e000000
32#define NFCONF __REGi(NF_BASE + 0x0)
33#define NFCMD __REGb(NF_BASE + 0x4)
34#define NFADDR __REGb(NF_BASE + 0x8)
35#define NFDATA __REGb(NF_BASE + 0xc)
36#define NFSTAT __REGb(NF_BASE + 0x10)
37#define NFSTAT_BUSY 1
38#define nand_select() (NFCONF &= ~0x800)
39#define nand_deselect() (NFCONF |= 0x800)
40#define nand_clear_RnB() do {} while (0)
41
42
43static inline void nand_wait(void)
44{
45    int i;
46
47    while (!(NFSTAT & NFSTAT_BUSY))
48        for (i=0; i<10; i++);
49}
50
51/* configuration for 2410 with 512byte sized flash */
52#define NAND_PAGE_SIZE 512
53#define BAD_BLOCK_OFFSET 5
54#define NAND_BLOCK_MASK (NAND_PAGE_SIZE - 1)
55#define NAND_BLOCK_SIZE 0x4000
56
57static int is_bad_block(unsigned long block_index)
58{
59    unsigned char data;
60
61    nand_clear_RnB();
62
63        NFCMD = NAND_CMD_READOOB; /* 0x50 */
64        NFADDR = BAD_BLOCK_OFFSET & 0xf;
65        NFADDR = (block_index ) & 0xff;
66        NFADDR = (block_index >> 8 ) & 0xff;
67        NFADDR = (block_index >> 16) & 0xff;
68
69    nand_wait();
70    data = (NFDATA & 0xff);
71
72    if (data != 0xff)
73        return 1;
74
75    return 0;
76}
77
78static int nand_read_page_ll(unsigned char *buf, unsigned long block512)
79{
80    unsigned int i;
81
82    nand_clear_RnB();
83
84    NFCMD = NAND_CMD_READ0;
85
86        /* Write Address */
87        NFADDR = 0;
88        NFADDR = (block512 ) & 0xff;
89        NFADDR = (block512 >> 8 ) & 0xff;
90        NFADDR = (block512 >> 16) & 0xff;
91
92    nand_wait();
93
94        for (i = 0; i < NAND_PAGE_SIZE; i++) {
95                *buf = (NFDATA & 0xff);
96                buf++;
97        }
98
99    return 1;
100}
101
102/* low level nand read function */
103int nand_read_ll(unsigned char *buf, unsigned long start_block512, int blocks512)
104{
105    int i, j;
106    int bad_count = 0;
107
108    /* chip Enable */
109    nand_select();
110    nand_clear_RnB();
111
112    for (i = 0; i < 10; i++)
113        ;
114
115    while (blocks512 > 0) {
116        if (is_bad_block(start_block512) ||
117                is_bad_block(start_block512 + 1)) {
118            start_block512 += 1;
119            blocks512 += 1;
120            if (bad_count++ == 4)
121                return -1;
122            continue;
123        }
124
125        j = nand_read_page_ll(buf, start_block512);
126        start_block512 += j;
127        buf += j << 9;
128        blocks512 -= j;
129    }
130
131    /* chip Disable */
132    nand_deselect();
133
134    return 0;
135}
136
137

Archive Download this file



interactive