2 * (C) Copyright 2005 Samsung Electronis
3 * Kyungmin Park <kyungmin.park@samsung.com>
5 * See file CREDITS for list of people who contributed to this
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.
13 * This program is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 * GNU General Public License for more details.
18 * You should have received a copy of the GNU General Public License
19 * along with this program; if not, write to the Free Software
20 * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
26 #include <asm/string.h>
28 #include "onenand_regs.h"
30 #define onenand_readw(a) (*(volatile unsigned short *)(a))
31 #define onenand_writew(v, a) ((*(volatile unsigned short *)(a)) = (u16) (v))
33 #define SAMSUNG_MFR_ID 0xEC
34 #define NUMONYX_MFR_ID 0x20
35 #define KFM1G16Q2A_DEV_ID 0x30
36 #define KFN2G16Q2A_DEV_ID 0x40
37 #define NAND01GR4E_DEV_ID 0x30
38 #define NAND02GR4E_DEV_ID 0x40
39 #define NAND04GR4E_DEV_ID 0x58
41 #define THIS_ONENAND(a) (ONENAND_ADDR + (a))
43 #define READ_INTERRUPT() \
44 onenand_readw(THIS_ONENAND(ONENAND_REG_INTERRUPT))
46 #define READ_CTRL_STATUS() \
47 onenand_readw(THIS_ONENAND(ONENAND_REG_CTRL_STATUS))
49 #define READ_ECC_STATUS() \
50 onenand_readw(THIS_ONENAND(ONENAND_REG_ECC_STATUS))
52 #define SET_EMIFS_CS_CONFIG(v) \
53 (*(volatile unsigned long *)(OMAP_EMIFS_CS_CONFIG) = (v))
55 #define onenand_block_address(block) (block)
56 #define onenand_sector_address(page) (page << 2)
57 #define onenand_buffer_address() ((1 << 3) << 8)
58 #define onenand_bufferram_address(block) (0)
60 #if defined(CFG_SYNC_BURST_READ) && defined(CONFIG_OMAP1610)
61 static inline void set_sync_burst_read(void)
65 | (0x1 << 15) /* Read Mode: Synchronous */
66 | (0x4 << 12) /* Burst Read Latency: 4 cycles */
67 | (0x4 << 9) /* Burst Length: 8 word */
68 | (0x1 << 7) /* RDY signal plarity */
69 | (0x1 << 6) /* INT signal plarity */
70 | (0x1 << 5) /* I/O buffer enable */
72 onenand_writew(value, THIS_ONENAND(ONENAND_REG_SYS_CFG1));
75 | (4 << 16) /* Synchronous Burst Read */
76 | (1 << 12) /* PGWST/WELEN */
77 | (1 << 8) /* WRWST */
78 | (4 << 4) /* RDWST */
79 | (1 << 0) /* FCLKDIV => 48MHz */
81 SET_EMIFS_CS_CONFIG(value);
84 static inline void set_async_read(void)
88 | (0x0 << 15) /* Read Mode: Asynchronous */
89 | (0x4 << 12) /* Burst Read Latency: 4 cycles */
90 | (0x0 << 9) /* Burst Length: continuous */
91 | (0x1 << 7) /* RDY signal plarity */
92 | (0x1 << 6) /* INT signal plarity */
93 | (0x0 << 5) /* I/O buffer disable */
95 onenand_writew(value, THIS_ONENAND(ONENAND_REG_SYS_CFG1));
98 | (0 << 16) /* Asynchronous Read */
99 | (1 << 12) /* PGWST/WELEN */
100 | (1 << 8) /* WRWST */
101 | (3 << 4) /* RDWST */
102 | (1 << 0) /* FCLKDIV => 48MHz */
104 SET_EMIFS_CS_CONFIG(value);
107 #define set_sync_burst_read(...) do { } while (0)
108 #define set_async_read(...) do { } while (0)
114 unsigned short mf_id, dev_id;
115 mf_id = (*(volatile unsigned short *)(THIS_ONENAND(ONENAND_REG_MANUFACTURER_ID)));
116 dev_id = (*(volatile unsigned short *)(THIS_ONENAND(ONENAND_REG_DEVICE_ID)));
118 if(mf_id == SAMSUNG_MFR_ID) {
119 if (dev_id == KFM1G16Q2A_DEV_ID) {
120 printf("Detected Samsung MuxOneNAND1G Flash \r\n");
122 } else if (dev_id == KFN2G16Q2A_DEV_ID) {
123 printf("Detected Samsung MuxOneNAND2G Flash \r\n");
126 printf(" ONENAND Flash unsupported\r\n");
129 } else if (mf_id == NUMONYX_MFR_ID) {
130 if (dev_id == NAND01GR4E_DEV_ID) {
131 printf("Detected Numonyx OneNAND 1G Flash \r\n");
133 } else if (dev_id == NAND02GR4E_DEV_ID) {
134 printf("Detected Numonyx OneNAND 2G Flash \r\n");
136 } else if (dev_id == NAND04GR4E_DEV_ID) {
137 printf("Detected Numonyx OneNAND 4G Flash \r\n");
140 printf("Numonyx OneNAND Flash unsupported \r\n");
144 printf("ONENAND Flash Unsupported\r\n");
149 /* read a page with ECC */
150 static inline int onenand_read_page(ulong block, ulong page, u_char *buf)
154 #ifndef __HAVE_ARCH_MEMCPY32
155 unsigned int offset, value;
157 unsigned int ctrl, ecc;
158 unsigned short bbmarker;
161 onenand_writew(onenand_block_address(block),
162 THIS_ONENAND(ONENAND_REG_START_ADDRESS1));
164 onenand_writew(onenand_sector_address(page),
165 THIS_ONENAND(ONENAND_REG_START_ADDRESS8));
167 onenand_writew(onenand_buffer_address(),
168 THIS_ONENAND(ONENAND_REG_START_BUFFER));
170 onenand_writew(onenand_bufferram_address(block),
171 THIS_ONENAND(ONENAND_REG_START_ADDRESS2));
173 onenand_writew(ONENAND_INT_CLEAR, THIS_ONENAND(ONENAND_REG_INTERRUPT));
175 onenand_writew(ONENAND_CMD_READ, THIS_ONENAND(ONENAND_REG_COMMAND));
177 #ifndef __HAVE_ARCH_MEMCPY32
178 p = (unsigned long *) buf;
180 base = (unsigned long *) (ONENAND_ADDR + ONENAND_DATARAM);
182 while (!(READ_INTERRUPT() & ONENAND_INT_MASTER))
185 ctrl = READ_CTRL_STATUS();
187 if (ctrl & ONENAND_CTRL_ERROR) {
191 if (READ_INTERRUPT() & ONENAND_INT_READ) {
193 ecc = READ_ECC_STATUS();
194 if (ecc & ONENAND_ECC_2BIT_ALL) {
198 /* Check if the block is bad. Bad block markers */
199 /* are stored in spare area of 1st or 2nd page */
200 if ((page == 0) || (page == 1))
202 unsigned long *spareArea = (unsigned long *) (ONENAND_ADDR + ONENAND_SPARERAM);
203 bbmarker = *spareArea;
204 /* for bad block markers */
205 if (bbmarker != 0xFFFF){
211 #ifdef __HAVE_ARCH_MEMCPY32
212 /* 32 bytes boundary memory copy */
213 memcpy32(buf, base, ONENAND_PAGE_SIZE);
215 for (offset = 0; offset < (ONENAND_PAGE_SIZE >> 2); offset++) {
216 value = *(base + offset);
224 #define ONENAND_START_PAGE 0
225 #define ONENAND_PAGES_PER_BLOCK 64
228 * onenand_read_block - Read a block data to buf
229 * @return 0 on sucess
232 int onenand_read_block(unsigned char *buf, ulong block)
234 int page, offset = 0;
236 set_sync_burst_read();
238 /* NOTE: you must read page from page 1 of block 0 */
239 /* read the block page by page*/
240 for (page = ONENAND_START_PAGE;
241 page < ONENAND_PAGES_PER_BLOCK; page++) {
243 if (onenand_read_page(block, page, buf + offset)){
248 offset += ONENAND_PAGE_SIZE;