pandora.c: Set GPBR1 register so that charging starts early.
[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 KFM1G16Q2A_DEV_ID       0x30
35 #define KFN2G16Q2A_DEV_ID       0x40
36
37
38 #define THIS_ONENAND(a)         (ONENAND_ADDR + (a))
39
40 #define READ_INTERRUPT()                                                \
41         onenand_readw(THIS_ONENAND(ONENAND_REG_INTERRUPT))
42
43 #define READ_CTRL_STATUS()                                              \
44         onenand_readw(THIS_ONENAND(ONENAND_REG_CTRL_STATUS))
45
46 #define READ_ECC_STATUS()                                               \
47         onenand_readw(THIS_ONENAND(ONENAND_REG_ECC_STATUS))
48         
49 #define SET_EMIFS_CS_CONFIG(v)                                  \
50         (*(volatile unsigned long *)(OMAP_EMIFS_CS_CONFIG) = (v))
51
52 #define onenand_block_address(block)            (block)
53 #define onenand_sector_address(page)            (page << 2)
54 #define onenand_buffer_address()                ((1 << 3) << 8)
55 #define onenand_bufferram_address(block)        (0)
56
57 #if defined(CFG_SYNC_BURST_READ) && defined(CONFIG_OMAP1610)
58 static inline void set_sync_burst_read(void)
59 {
60         unsigned int value;
61         value = 0
62                 | (0x1 << 15)           /* Read Mode: Synchronous */
63                 | (0x4 << 12)           /* Burst Read Latency: 4 cycles */
64                 | (0x4 << 9)            /* Burst Length: 8 word */
65                 | (0x1 << 7)            /* RDY signal plarity */
66                 | (0x1 << 6)            /* INT signal plarity */
67                 | (0x1 << 5)            /* I/O buffer enable */
68                 ;
69         onenand_writew(value, THIS_ONENAND(ONENAND_REG_SYS_CFG1));
70
71         value = 0
72                 | (4 << 16)             /* Synchronous Burst Read */
73                 | (1 << 12)             /* PGWST/WELEN */
74                 | (1 << 8)              /* WRWST */
75                 | (4 << 4)              /* RDWST */
76                 | (1 << 0)              /* FCLKDIV => 48MHz */
77                 ;
78         SET_EMIFS_CS_CONFIG(value);
79 }
80
81 static inline void set_async_read(void)
82 {
83         unsigned int value;
84         value = 0
85                 | (0x0 << 15)           /* Read Mode: Asynchronous */
86                 | (0x4 << 12)           /* Burst Read Latency: 4 cycles */
87                 | (0x0 << 9)            /* Burst Length: continuous */
88                 | (0x1 << 7)            /* RDY signal plarity */
89                 | (0x1 << 6)            /* INT signal plarity */
90                 | (0x0 << 5)            /* I/O buffer disable */
91                 ;
92         onenand_writew(value, THIS_ONENAND(ONENAND_REG_SYS_CFG1));
93
94         value = 0
95                 | (0 << 16)             /* Asynchronous Read */
96                 | (1 << 12)             /* PGWST/WELEN */
97                 | (1 << 8)              /* WRWST */
98                 | (3 << 4)              /* RDWST */
99                 | (1 << 0)              /* FCLKDIV => 48MHz */
100                 ;
101         SET_EMIFS_CS_CONFIG(value);
102 }
103 #else
104 #define set_sync_burst_read(...)        do { } while (0)
105 #define set_async_read(...)             do { } while (0)
106 #endif
107
108 int
109 onenand_chip()
110 {
111         unsigned short mf_id, dev_id;
112         mf_id = (*(volatile unsigned short *)(THIS_ONENAND(ONENAND_REG_MANUFACTURER_ID)));
113         dev_id = (*(volatile unsigned short *)(THIS_ONENAND(ONENAND_REG_DEVICE_ID)));
114
115         if(mf_id == SAMSUNG_MFR_ID) {
116                 if (dev_id == KFM1G16Q2A_DEV_ID) {
117                 printf("Detected Samsung MuxOneNAND1G Flash \r\n");
118                 return 0;
119                 } else if (dev_id == KFN2G16Q2A_DEV_ID) {
120                         printf("Detected Samsung MuxOneNAND2G Flash \r\n");
121                         return 0;
122                 } else {
123                         printf(" ONENAND Flash unsupported\r\n");
124                         return 1;
125                 }
126         } else {
127                 printf("ONENAND Flash Unsupported\r\n");
128                 return 1;
129         }
130 }
131
132 /* read a page with ECC */
133 static inline int onenand_read_page(ulong block, ulong page, u_char *buf)
134 {
135         unsigned long *base;
136
137 #ifndef __HAVE_ARCH_MEMCPY32
138         unsigned int offset, value;
139         unsigned long *p;
140         unsigned int ctrl, ecc;
141         unsigned short bbmarker;
142 #endif
143
144         onenand_writew(onenand_block_address(block),
145                 THIS_ONENAND(ONENAND_REG_START_ADDRESS1));
146
147         onenand_writew(onenand_sector_address(page),
148                 THIS_ONENAND(ONENAND_REG_START_ADDRESS8));
149
150         onenand_writew(onenand_buffer_address(),
151                 THIS_ONENAND(ONENAND_REG_START_BUFFER));
152
153         onenand_writew(onenand_bufferram_address(block),
154                 THIS_ONENAND(ONENAND_REG_START_ADDRESS2));
155
156         onenand_writew(ONENAND_INT_CLEAR, THIS_ONENAND(ONENAND_REG_INTERRUPT));
157
158         onenand_writew(ONENAND_CMD_READ, THIS_ONENAND(ONENAND_REG_COMMAND));
159
160 #ifndef __HAVE_ARCH_MEMCPY32
161         p = (unsigned long *) buf;
162 #endif
163         base = (unsigned long *) (ONENAND_ADDR + ONENAND_DATARAM);
164
165         while (!(READ_INTERRUPT() & ONENAND_INT_MASTER))
166                 continue;
167
168         ctrl = READ_CTRL_STATUS();
169         
170         if (ctrl & ONENAND_CTRL_ERROR) {
171                 hang();
172         }
173         
174         if (READ_INTERRUPT() & ONENAND_INT_READ) {
175
176                 ecc = READ_ECC_STATUS();
177                 if (ecc & ONENAND_ECC_2BIT_ALL) {
178                         hang();
179                 }
180
181                 /* Check if the block is bad. Bad block markers    */
182                 /* are stored in spare area of 1st or 2nd page */
183                 if ((page == 0) || (page == 1))
184                 {
185                     unsigned long *spareArea = (unsigned long *) (ONENAND_ADDR + ONENAND_SPARERAM);
186                     bbmarker = *spareArea;
187                     /* for bad block markers */
188                     if (bbmarker != 0xFFFF){
189                         return 1;
190                     }
191                 }
192         }
193         
194 #ifdef __HAVE_ARCH_MEMCPY32
195         /* 32 bytes boundary memory copy */
196         memcpy32(buf, base, ONENAND_PAGE_SIZE);
197 #else
198         for (offset = 0; offset < (ONENAND_PAGE_SIZE >> 2); offset++) {
199                 value = *(base + offset);
200                 *p++ = value;
201         }
202 #endif
203
204         return 0;
205 }
206
207 #define ONENAND_START_PAGE              0
208 #define ONENAND_PAGES_PER_BLOCK         64
209
210 /**
211  * onenand_read_block - Read a block data to buf
212  * @return 0 on sucess
213  */ 
214
215 int onenand_read_block(unsigned char *buf, ulong block)
216 {
217         int page, offset = 0;
218
219         set_sync_burst_read();
220
221         /* NOTE: you must read page from page 1 of block 0 */
222         /* read the block page by page*/
223         for (page = ONENAND_START_PAGE;
224             page < ONENAND_PAGES_PER_BLOCK; page++) {
225
226                 if (onenand_read_page(block, page, buf + offset)){
227                     set_async_read();
228                     return 1;
229                 }
230
231                 offset += ONENAND_PAGE_SIZE;
232         }
233
234         set_async_read();
235
236         return 0;
237 }
238