BeagleBoard: Forced newer revisions to default to xM.
[pandora-x-loader.git] / drivers / onenand.c
1 /*
2  * (C) Copyright 2005 Samsung Electronis
3  * Kyungmin Park <kyungmin.park@samsung.com>
4  *
5  * See file CREDITS for list of people who contributed to this
6  * project.
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  * 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.
17  *
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,
21  * MA 02111-1307 USA
22  */
23
24 #include <common.h>
25
26 #include <asm/string.h>
27
28 #include "onenand_regs.h"
29
30 #define onenand_readw(a)        (*(volatile unsigned short *)(a))
31 #define onenand_writew(v, a)    ((*(volatile unsigned short *)(a)) = (u16) (v))
32
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
40
41 #define THIS_ONENAND(a)         (ONENAND_ADDR + (a))
42
43 #define READ_INTERRUPT()                                                \
44         onenand_readw(THIS_ONENAND(ONENAND_REG_INTERRUPT))
45
46 #define READ_CTRL_STATUS()                                              \
47         onenand_readw(THIS_ONENAND(ONENAND_REG_CTRL_STATUS))
48
49 #define READ_ECC_STATUS()                                               \
50         onenand_readw(THIS_ONENAND(ONENAND_REG_ECC_STATUS))
51         
52 #define SET_EMIFS_CS_CONFIG(v)                                  \
53         (*(volatile unsigned long *)(OMAP_EMIFS_CS_CONFIG) = (v))
54
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)
59
60 #if defined(CFG_SYNC_BURST_READ) && defined(CONFIG_OMAP1610)
61 static inline void set_sync_burst_read(void)
62 {
63         unsigned int value;
64         value = 0
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 */
71                 ;
72         onenand_writew(value, THIS_ONENAND(ONENAND_REG_SYS_CFG1));
73
74         value = 0
75                 | (4 << 16)             /* Synchronous Burst Read */
76                 | (1 << 12)             /* PGWST/WELEN */
77                 | (1 << 8)              /* WRWST */
78                 | (4 << 4)              /* RDWST */
79                 | (1 << 0)              /* FCLKDIV => 48MHz */
80                 ;
81         SET_EMIFS_CS_CONFIG(value);
82 }
83
84 static inline void set_async_read(void)
85 {
86         unsigned int value;
87         value = 0
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 */
94                 ;
95         onenand_writew(value, THIS_ONENAND(ONENAND_REG_SYS_CFG1));
96
97         value = 0
98                 | (0 << 16)             /* Asynchronous Read */
99                 | (1 << 12)             /* PGWST/WELEN */
100                 | (1 << 8)              /* WRWST */
101                 | (3 << 4)              /* RDWST */
102                 | (1 << 0)              /* FCLKDIV => 48MHz */
103                 ;
104         SET_EMIFS_CS_CONFIG(value);
105 }
106 #else
107 #define set_sync_burst_read(...)        do { } while (0)
108 #define set_async_read(...)             do { } while (0)
109 #endif
110
111 int
112 onenand_chip()
113 {
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)));
117
118         if(mf_id == SAMSUNG_MFR_ID) {
119                 if (dev_id == KFM1G16Q2A_DEV_ID) {
120                 printf("Detected Samsung MuxOneNAND1G Flash \r\n");
121                 return 0;
122                 } else if (dev_id == KFN2G16Q2A_DEV_ID) {
123                         printf("Detected Samsung MuxOneNAND2G Flash \r\n");
124                         return 0;
125                 } else {
126                         printf(" ONENAND Flash unsupported\r\n");
127                         return 1;
128                 }
129         } else if (mf_id == NUMONYX_MFR_ID) {
130                 if (dev_id == NAND01GR4E_DEV_ID) {
131                         printf("Detected Numonyx OneNAND 1G Flash \r\n");
132                         return 0;
133                 } else if (dev_id == NAND02GR4E_DEV_ID) {
134                         printf("Detected Numonyx OneNAND 2G Flash \r\n");
135                         return 0;
136                 } else if (dev_id == NAND04GR4E_DEV_ID) {
137                         printf("Detected Numonyx OneNAND 4G Flash \r\n");
138                         return 0;
139                 } else {
140                         printf("Numonyx OneNAND Flash unsupported \r\n");
141                         return 1;
142                 }
143         } else {
144                 printf("ONENAND Flash Unsupported\r\n");
145                 return 1;
146         }
147 }
148
149 /* read a page with ECC */
150 static inline int onenand_read_page(ulong block, ulong page, u_char *buf)
151 {
152         unsigned long *base;
153
154 #ifndef __HAVE_ARCH_MEMCPY32
155         unsigned int offset, value;
156         unsigned long *p;
157         unsigned int ctrl, ecc;
158         unsigned short bbmarker;
159 #endif
160
161         onenand_writew(onenand_block_address(block),
162                 THIS_ONENAND(ONENAND_REG_START_ADDRESS1));
163
164         onenand_writew(onenand_sector_address(page),
165                 THIS_ONENAND(ONENAND_REG_START_ADDRESS8));
166
167         onenand_writew(onenand_buffer_address(),
168                 THIS_ONENAND(ONENAND_REG_START_BUFFER));
169
170         onenand_writew(onenand_bufferram_address(block),
171                 THIS_ONENAND(ONENAND_REG_START_ADDRESS2));
172
173         onenand_writew(ONENAND_INT_CLEAR, THIS_ONENAND(ONENAND_REG_INTERRUPT));
174
175         onenand_writew(ONENAND_CMD_READ, THIS_ONENAND(ONENAND_REG_COMMAND));
176
177 #ifndef __HAVE_ARCH_MEMCPY32
178         p = (unsigned long *) buf;
179 #endif
180         base = (unsigned long *) (ONENAND_ADDR + ONENAND_DATARAM);
181
182         while (!(READ_INTERRUPT() & ONENAND_INT_MASTER))
183                 continue;
184
185         ctrl = READ_CTRL_STATUS();
186         
187         if (ctrl & ONENAND_CTRL_ERROR) {
188                 hang();
189         }
190         
191         if (READ_INTERRUPT() & ONENAND_INT_READ) {
192
193                 ecc = READ_ECC_STATUS();
194                 if (ecc & ONENAND_ECC_2BIT_ALL) {
195                         hang();
196                 }
197
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))
201                 {
202                     unsigned long *spareArea = (unsigned long *) (ONENAND_ADDR + ONENAND_SPARERAM);
203                     bbmarker = *spareArea;
204                     /* for bad block markers */
205                     if (bbmarker != 0xFFFF){
206                         return 1;
207                     }
208                 }
209         }
210         
211 #ifdef __HAVE_ARCH_MEMCPY32
212         /* 32 bytes boundary memory copy */
213         memcpy32(buf, base, ONENAND_PAGE_SIZE);
214 #else
215         for (offset = 0; offset < (ONENAND_PAGE_SIZE >> 2); offset++) {
216                 value = *(base + offset);
217                 *p++ = value;
218         }
219 #endif
220
221         return 0;
222 }
223
224 #define ONENAND_START_PAGE              0
225 #define ONENAND_PAGES_PER_BLOCK         64
226
227 /**
228  * onenand_read_block - Read a block data to buf
229  * @return 0 on sucess
230  */ 
231
232 int onenand_read_block(unsigned char *buf, ulong block)
233 {
234         int page, offset = 0;
235
236         set_sync_burst_read();
237
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++) {
242
243                 if (onenand_read_page(block, page, buf + offset)){
244                     set_async_read();
245                     return 1;
246                 }
247
248                 offset += ONENAND_PAGE_SIZE;
249         }
250
251         set_async_read();
252
253         return 0;
254 }
255