Root/nandboot/src/jz4730_nand.c

1/*
2 * jz4730_nand.c
3 *
4 * NAND read routine for JZ4730
5 *
6 * Copyright (c) 2005-2008 Ingenic Semiconductor Inc.
7 *
8 * This program is free software; you can redistribute it and/or
9 * modify it under the terms of the GNU General Public License as
10 * published by the Free Software Foundation; either version 2 of
11 * the License, or (at your option) any later version.
12 */
13
14#include <config.h>
15
16#ifdef CONFIG_JZ4730
17
18#include <nand.h>
19#include <jz4730.h>
20
21/* NAND command/address/data port */
22#define NAND_DATAPORT 0xB4000000 /* read-write area */
23#define NAND_CMDPORT 0xB4040000 /* write only area */
24#define NAND_ADDRPORT 0xB4080000 /* write only area */
25
26#define ECC_BLOCK 256 /* 3-bytes HW ECC per 256-bytes data */
27#define ECC_POS 4 /* ECC offset to spare area */
28
29#define __nand_enable() (REG_EMC_NFCSR |= EMC_NFCSR_NFE | EMC_NFCSR_FCE)
30#define __nand_disable() (REG_EMC_NFCSR &= ~(EMC_NFCSR_NFE | EMC_NFCSR_FCE))
31#define __nand_ecc_enable() (REG_EMC_NFCSR |= EMC_NFCSR_ECCE | EMC_NFCSR_ERST)
32#define __nand_ecc_disable() (REG_EMC_NFCSR &= ~EMC_NFCSR_ECCE)
33#define __nand_ready() (REG_EMC_NFCSR & EMC_NFCSR_RB)
34#define __nand_sync() while (!__nand_ready())
35#define __nand_ecc() (REG_EMC_NFECC & 0x00ffffff)
36#define __nand_cmd(n) (REG8(NAND_CMDPORT) = (n))
37#define __nand_addr(n) (REG8(NAND_ADDRPORT) = (n))
38#define __nand_data8() REG8(NAND_DATAPORT)
39#define __nand_data16() REG16(NAND_DATAPORT)
40
41/*--------------------------------------------------------------*/
42
43static inline void nand_wait_ready(void)
44{
45    __nand_sync();
46}
47
48static inline void nand_read_buf16(void *buf, int count)
49{
50    int i;
51    u16 *p = (u16 *)buf;
52
53    for (i = 0; i < count; i += 2)
54        *p++ = __nand_data16();
55}
56
57static inline void nand_read_buf8(void *buf, int count)
58{
59    int i;
60    u8 *p = (u8 *)buf;
61
62    for (i = 0; i < count; i++)
63        *p++ = __nand_data8();
64}
65
66static inline void nand_read_buf(void *buf, int count, int bw)
67{
68    if (bw == 8)
69        nand_read_buf8(buf, count);
70    else
71        nand_read_buf16(buf, count);
72}
73
74/*
75 * Read oob
76 */
77static int nand_read_oob(struct nand_param *nandp, int page_addr, u8 *buf, int size)
78{
79    int page_size, row_cycle, bus_width;
80    int col_addr;
81
82    page_size = nandp->page_size;
83    row_cycle = nandp->row_cycle;
84    bus_width = nandp->bus_width;
85
86    if (page_size == 2048)
87        col_addr = 2048;
88    else
89        col_addr = 0;
90
91    if (page_size == 2048)
92        /* Send READ0 command */
93        __nand_cmd(NAND_CMD_READ0);
94    else
95        /* Send READOOB command */
96        __nand_cmd(NAND_CMD_READOOB);
97
98    /* Send column address */
99    __nand_addr(col_addr & 0xff);
100    if (page_size == 2048)
101        __nand_addr((col_addr >> 8) & 0xff);
102
103    /* Send page address */
104    __nand_addr(page_addr & 0xff);
105    __nand_addr((page_addr >> 8) & 0xff);
106    if (row_cycle == 3)
107        __nand_addr((page_addr >> 16) & 0xff);
108
109    /* Send READSTART command for 2048 ps NAND */
110    if (page_size == 2048)
111        __nand_cmd(NAND_CMD_READSTART);
112
113    /* Wait for device ready */
114    nand_wait_ready();
115
116    /* Read oob data */
117    nand_read_buf(buf, size, bus_width);
118
119    return 0;
120}
121
122/*
123 * nand_read_page()
124 *
125 * Input:
126 *
127 * nandp - pointer to nand info
128 * block - block number: 0, 1, 2, ...
129 * page - page number within a block: 0, 1, 2, ...
130 * dst - pointer to target buffer
131 */
132int nand_read_page(struct nand_param *nandp, int block, int page, u8 *dst)
133{
134    int page_size, oob_size, page_per_block;
135    int row_cycle, bus_width, ecc_count;
136    int page_addr, i, j;
137    u8 *databuf;
138    u8 oob_buf[64];
139    u32 calc_ecc[8];
140
141    page_size = nandp->page_size;
142    oob_size = nandp->oob_size;
143    page_per_block = nandp->page_per_block;
144    row_cycle = nandp->row_cycle;
145    bus_width = nandp->bus_width;
146
147    page_addr = page + block * page_per_block;
148
149    /*
150     * Read page data
151     */
152
153    /* Send READ0 command */
154    __nand_cmd(NAND_CMD_READ0);
155
156    /* Send column address */
157    __nand_addr(0);
158    if (page_size == 2048)
159        __nand_addr(0);
160
161    /* Send page address */
162    __nand_addr(page_addr & 0xff);
163    __nand_addr((page_addr >> 8) & 0xff);
164    if (row_cycle == 3)
165        __nand_addr((page_addr >> 16) & 0xff);
166
167    /* Send READSTART command for 2048 ps NAND */
168    if (page_size == 2048)
169        __nand_cmd(NAND_CMD_READSTART);
170
171    /* Wait for device ready */
172    nand_wait_ready();
173
174    /* Read page data */
175    databuf = dst;
176
177    ecc_count = page_size / ECC_BLOCK;
178
179    for (i = 0; i < ecc_count; i++) {
180
181        /* Enable HW ECC */
182        __nand_ecc_enable();
183
184        /* Read data */
185        nand_read_buf((void *)databuf, ECC_BLOCK, bus_width);
186
187        /* Disable HW ECC */
188        __nand_ecc_disable();
189
190        /* Record the ECC */
191        calc_ecc[i] = __nand_ecc();
192
193        databuf += ECC_BLOCK;
194    }
195
196    /*
197     * Read oob data
198     */
199    nand_read_oob(nandp, page_addr, oob_buf, oob_size);
200
201    /*
202     * ECC correction
203     *
204     * Note: the ECC correction algorithm should be conformed to
205     * the encoding algorithm. It depends on what encoding algorithm
206     * is used? SW ECC? HW ECC?
207     */
208
209    return 0;
210}
211
212/*
213 * Check bad block
214 *
215 * Note: the bad block flag may be store in either the first or the last
216 * page of the block.
217 */
218int block_is_bad(struct nand_param *nandp, int block)
219{
220    int page_addr;
221    u8 oob_buf[64];
222
223    page_addr = block * nandp->page_per_block;
224    nand_read_oob(nandp, page_addr, oob_buf, nandp->oob_size);
225    if (oob_buf[nandp->bad_block_pos] != 0xff)
226        return 1;
227
228    page_addr = (block + 1) * nandp->page_per_block - 1;
229    nand_read_oob(nandp, page_addr, oob_buf, nandp->oob_size);
230    if (oob_buf[nandp->bad_block_pos] != 0xff)
231        return 1;
232
233    return 0;
234}
235
236/*
237 * Enable NAND controller
238 */
239void nand_enable(void)
240{
241    __nand_enable();
242
243    REG_EMC_SMCR3 = 0x04444400;
244}
245
246/*
247 * Disable NAND controller
248 */
249void nand_disable(void)
250{
251    __nand_disable();
252}
253
254#endif /* CONFIG_JZ4730 */
255

Archive Download this file



interactive