MINI2440: arm920t/ changes
[u-boot-openmoko/mini2440.git] / cpu / arm920t / s3c24x0 / nand_read.c
blobd776de7d5730b522f18f000253b4d0087fe6adb8
1 /*
2 * nand_read.c: Simple NAND read functions for booting from NAND
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.
8 * Taken from GPLv2 licensed vivi bootloader,
9 * Copyright (C) 2002 MIZI Research, Inc.
11 * Author: Hwang, Chideok <hwang@mizi.com>
12 * Date : $Date: 2004/02/04 10:37:37 $
14 * u-boot integration and bad-block skipping (C) 2006 by OpenMoko, Inc.
15 * Author: Harald Welte <laforge@openmoko.org>
18 #include <common.h>
19 #include <linux/mtd/nand.h>
21 #ifdef CONFIG_S3C2410_NAND_BOOT
23 #define __REGb(x) (*(volatile unsigned char *)(x))
24 #define __REGw(x) (*(volatile unsigned short *)(x))
25 #define __REGi(x) (*(volatile unsigned int *)(x))
26 #define NF_BASE 0x4e000000
27 #if defined(CONFIG_S3C2410)
28 #define NFCONF __REGi(NF_BASE + 0x0)
29 #define NFCMD __REGb(NF_BASE + 0x4)
30 #define NFADDR __REGb(NF_BASE + 0x8)
31 #define NFDATA __REGb(NF_BASE + 0xc)
32 #define NFSTAT __REGb(NF_BASE + 0x10)
33 #define NFSTAT_BUSY 1
34 #define nand_select() (NFCONF &= ~0x800)
35 #define nand_deselect() (NFCONF |= 0x800)
36 #define nand_clear_RnB() do {} while (0)
37 #elif defined(CONFIG_S3C2440) || defined(CONFIG_S3C2442)
38 #define NFCONF __REGi(NF_BASE + 0x0)
39 #define NFCONT __REGi(NF_BASE + 0x4)
40 #define NFCMD __REGb(NF_BASE + 0x8)
41 #define NFADDR __REGb(NF_BASE + 0xc)
42 #define NFDATA __REGb(NF_BASE + 0x10)
43 #define NFDATA16 __REGw(NF_BASE + 0x10)
44 #define NFSTAT __REGb(NF_BASE + 0x20)
45 #define NFSTAT_BUSY 1
46 #define nand_select() (NFCONT &= ~(1 << 1))
47 #define nand_deselect() (NFCONT |= (1 << 1))
48 #define nand_clear_RnB() (NFSTAT |= (1 << 2))
49 #endif
51 static inline void nand_wait(void)
53 int i;
55 while (!(NFSTAT & NFSTAT_BUSY))
56 for (i=0; i<10; i++);
59 #if defined(CONFIG_S3C2410) || defined(CONFIG_MINI2440)
60 /* configuration for 2410 with 512byte sized flash */
61 #define NAND_PAGE_SIZE 512
62 #define BAD_BLOCK_OFFSET 5
63 #define NAND_BLOCK_MASK (NAND_PAGE_SIZE - 1)
64 #define NAND_BLOCK_SIZE 0x4000
65 #else
66 /* configuration for 2440 with 2048byte sized flash */
67 #define NAND_5_ADDR_CYCLE
68 #define NAND_PAGE_SIZE 2048
69 #define BAD_BLOCK_OFFSET NAND_PAGE_SIZE
70 #define NAND_BLOCK_MASK (NAND_PAGE_SIZE - 1)
71 #define NAND_BLOCK_SIZE (NAND_PAGE_SIZE * 64)
72 #endif
74 /* compile time failure in case of an invalid configuration */
75 #if defined(CONFIG_S3C2410) && (NAND_PAGE_SIZE != 512)
76 #error "S3C2410 does not support nand page size != 512"
77 #endif
79 static int is_bad_block(unsigned long i)
81 unsigned char data;
82 unsigned long page_num;
84 nand_clear_RnB();
85 #if (NAND_PAGE_SIZE == 512)
86 NFCMD = NAND_CMD_READOOB; /* 0x50 */
87 NFADDR = BAD_BLOCK_OFFSET & 0xf;
88 NFADDR = (i >> 9) & 0xff;
89 NFADDR = (i >> 17) & 0xff;
90 NFADDR = (i >> 25) & 0xff;
91 #elif (NAND_PAGE_SIZE == 2048)
92 page_num = i >> 11; /* addr / 2048 */
93 NFCMD = NAND_CMD_READ0;
94 NFADDR = BAD_BLOCK_OFFSET & 0xff;
95 NFADDR = (BAD_BLOCK_OFFSET >> 8) & 0xff;
96 NFADDR = page_num & 0xff;
97 NFADDR = (page_num >> 8) & 0xff;
98 NFADDR = (page_num >> 16) & 0xff;
99 NFCMD = NAND_CMD_READSTART;
100 #endif
101 nand_wait();
102 data = (NFDATA & 0xff);
103 if (data != 0xff)
104 return 1;
106 return 0;
109 static int nand_read_page_ll(unsigned char *buf, unsigned long addr)
111 unsigned short *ptr16 = (unsigned short *)buf;
112 unsigned int i, page_num;
114 nand_clear_RnB();
116 NFCMD = NAND_CMD_READ0;
118 #if (NAND_PAGE_SIZE == 512)
119 /* Write Address */
120 NFADDR = addr & 0xff;
121 NFADDR = (addr >> 9) & 0xff;
122 NFADDR = (addr >> 17) & 0xff;
123 NFADDR = (addr >> 25) & 0xff;
124 #elif (NAND_PAGE_SIZE == 2048)
125 page_num = addr >> 11; /* addr / 2048 */
126 /* Write Address */
127 NFADDR = 0;
128 NFADDR = 0;
129 NFADDR = page_num & 0xff;
130 NFADDR = (page_num >> 8) & 0xff;
131 NFADDR = (page_num >> 16) & 0xff;
132 NFCMD = NAND_CMD_READSTART;
133 #else
134 #error "unsupported nand page size"
135 #endif
136 nand_wait();
138 #if defined(CONFIG_S3C2410)
139 for (i = 0; i < NAND_PAGE_SIZE; i++) {
140 *buf = (NFDATA & 0xff);
141 buf++;
143 #elif defined(CONFIG_S3C2440) || defined(CONFIG_S3C2442)
144 for (i = 0; i < NAND_PAGE_SIZE/2; i++) {
145 *ptr16 = NFDATA16;
146 ptr16++;
148 #endif
150 return NAND_PAGE_SIZE;
153 /* low level nand read function */
154 int nand_read_ll(unsigned char *buf, unsigned long start_addr, int size)
156 int i, j;
158 if ((start_addr & NAND_BLOCK_MASK) || (size & NAND_BLOCK_MASK))
159 return -1; /* invalid alignment */
161 /* chip Enable */
162 nand_select();
163 nand_clear_RnB();
164 for (i=0; i<10; i++);
166 for (i=start_addr; i < (start_addr + size);) {
167 #ifdef CONFIG_S3C2410_NAND_SKIP_BAD
168 if (i % NAND_BLOCK_SIZE == 0) {
169 if (is_bad_block(i) ||
170 is_bad_block(i + NAND_PAGE_SIZE)) {
171 /* Bad block */
172 i += NAND_BLOCK_SIZE;
173 size += NAND_BLOCK_SIZE;
174 continue;
177 #endif
178 j = nand_read_page_ll(buf, i);
179 i += j;
180 buf += j;
183 /* chip Disable */
184 nand_deselect();
186 return 0;
189 #endif /* CONFIG_S3C2410_NAND_BOOT */