source: umon/ports/beagleboneblack/nand740.c @ 9049385

Last change on this file since 9049385 was dee5246, checked in by Jarielle Catbagan <jcatbagan93@…>, on 06/19/15 at 18:53:54

Duplicated csb740 directory to beagleboneblack directory for BBB port

  • Property mode set to 100644
File size: 8.0 KB
Line 
1/*
2 * Board/device specific connection between the generic
3 * nand command and the CSB740's NAND memory access through
4 * the OMAP3530.
5 *
6 * The CSB740 uses K9K4GO8UOM NAND (512Mx8bit) device from Samsung.
7 * It is connected to the OMAP3530's CS3 through the CPLD.
8 * The device ID for this part number should be: 0xECDC109554
9 *
10 *  Maker code:         0xEC
11 *      Device code:    0xDC
12 *  Third cycle:        0x10
13 *  Fourth cycle:       0x95
14 *  Fifth cycle:        0x54
15 *
16 * Blocksize: 128K      (smallest eraseable chunk)
17 * Pagesize:  2K  (64 pages per block)
18 *
19 * Taken from the NAND datasheet...
20 *   The 528M byte physical space requires 30 addresses, thereby
21 *   requiring five cycles for addressing :
22 *   2 cycles of column address, 3 cycles of row address, in that
23 *   order. Page Read and Page Program need the same five address
24 *   cycles following the required command input. In Block Erase
25 *   operation, however, only the three row address cycles are used.
26 *   Device operations are selected by writing specific commands into
27 *   the command register.
28 *
29 * Taken from ONFI Spec:
30 *   The address is comprised of a row address and a column address.
31 *   The row address identifies the page, block, and LUN to be accessed.
32 *   The column address identifies the byte or word within a page to access.
33 *
34 * Note:
35 *      Apparently this Sansung device is not ONFI compliant.  There was an
36 *  earlier version of the CSB740 that had a Micron part on it and it was
37 *  ONFI compliant (ONFI=Open Nand Flash Interface specification).
38 *
39 */
40#include "config.h"
41#if INCLUDE_NANDCMD
42#include "stddefs.h"
43#include "genlib.h"
44#include "omap3530.h"
45#include "omap3530_mem.h"
46#include "nand.h"
47
48static int pgSiz;
49static int blkSiz;
50static char onfi;
51
52#define NANDSTAT_FAIL   0x01
53#define NANDSTAT_READY  0x40
54#define NANDSTAT_NOTWP  0x80
55
56#define NAND_CMD(cs) (vuchar *)(0x6e00007C + (0x30 * cs))
57#define NAND_ADR(cs) (vuchar *)(0x6e000080 + (0x30 * cs))
58#define NAND_DAT(cs) (vuchar *)(0x6e000084 + (0x30 * cs))
59
60#define PREFETCH_READ_MODE()    GPMC_REG(GPMC_PREFETCH_CONFIG1) &= ~1
61#define WRITE_POSTING_MODE()    GPMC_REG(GPMC_PREFETCH_CONFIG1) |= 1
62
63#define NAND_CS_BASEADDR        0x18000000
64
65/* some discussion to follow:
66 * http://e2e.ti.com/support/dsp/omap_applications_processors/f/42/p/29683/103192.aspx
67 * Address is "page/block/column"...
68 */
69
70/* nandBusyWait():
71 * Poll the WAIT3 bit of the gmpc-status register, waiting for
72 * it to go active.
73 * The R/B (ready/busy) pin of the NAND device is low when busy.
74 * It is tied to WAIT3 of the CPU. 
75 */
76void
77nandHardBusyWait(void)
78{
79        while((GPMC_REG(GPMC_STATUS) & 0x800) == 0x800);
80        //while((GPMC_REG(GPMC_STATUS) & 0x800) == 0);
81}
82
83void
84nandSoftBusyWait(void)
85{
86        do {
87                *NAND_CMD(3) = 0x70;
88        } while((*NAND_DAT(3) & NANDSTAT_READY) == 0);
89}
90
91void
92nandSetColAddr(unsigned long addr)
93{
94        // Column1 (A07|A06|A05|A04|A03|A02|A01|A00):
95        *NAND_ADR(3) = ((addr & 0x000000ff));
96
97        // Column2 (---|---|---|---|A11|A10|A09|A08):
98        *NAND_ADR(3) = ((addr & 0x00000f00) >> 8);
99}
100
101void
102nandSetRowAddr(unsigned long addr)
103{
104        // Row1 (A19|A18|A17|A16|A15|A14|A13|A12):
105        *NAND_ADR(3) = ((addr & 0x000ff000) >> 12);
106
107        // Row2 (A27|A26|A25|A24|A23|A22|A21|A20):
108        *NAND_ADR(3) = ((addr & 0x0ff00000) >> 20);
109
110        // Row3 (---|---|---|---|---|---|A29|A28):
111        *NAND_ADR(3) = ((addr & 0x30000000) >> 28);
112}
113
114/* nandReadChunk():
115 * Transfer some chunk of memory from NAND to a destination.
116 */
117int
118nandReadChunk(char *src, char *dest, int len)
119{
120        unsigned long addr = (long)src;
121
122        PREFETCH_READ_MODE();
123
124        if (nandVerbose)
125                printf("nandReadChunk(src=0x%x,dest=0x%x,len=%d)\n",src,dest,len);
126
127        while(len > 0) {
128                int tot;
129
130                *NAND_CMD(3) = 0x00;
131                nandSetColAddr(addr);
132                nandSetRowAddr(addr);
133                *NAND_CMD(3) = 0x30;
134
135                nandHardBusyWait();
136
137                tot = len > pgSiz ? pgSiz : len;
138                memcpy(dest,(char *)NAND_CS_BASEADDR,tot);
139
140                len -= tot;
141                dest += tot;
142        }
143        return(0);
144}
145
146int
147nandWriteChunk(char *dest, char *src, int len)
148{
149        unsigned long addr = (long)dest;
150
151        WRITE_POSTING_MODE();
152
153        if (nandVerbose)
154                printf("nandWriteBlock(dest=0x%x,src=0x%x,len=%d)\n",dest,src,len);
155
156        *NAND_CMD(3) = 0x80;
157        nandSetColAddr(addr);
158        nandSetRowAddr(addr);
159        memcpy((char *)NAND_CS_BASEADDR,src,len);
160        *NAND_CMD(3) = 0x10;
161       
162        nandSoftBusyWait();
163
164        return(0);
165}
166
167int
168nandEraseChunk(char *base, int len)
169{
170        unsigned long addr = (long)base;
171
172        if (nandVerbose)
173                printf("nandEraseChunk(addr=0x%x,len=%d)\n",addr,len);
174
175        *NAND_CMD(3) = 0x60;
176        nandSetRowAddr(addr);
177        *NAND_CMD(3) = 0xd0;
178       
179        nandSoftBusyWait();
180
181        return(0);
182}
183
184void
185nandId(void)
186{
187        uchar d[5];
188        uchar d1[4];
189
190        *NAND_CMD(3) = 0x90;
191        *NAND_ADR(3) = 0x00;
192        d[0] = *NAND_DAT(3);
193        d[1] = *NAND_DAT(3);
194        d[2] = *NAND_DAT(3);
195        d[3] = *NAND_DAT(3);
196        d[4] = *NAND_DAT(3);
197
198        switch(d[3] & 3) {
199                case 0:
200                        pgSiz = 1024;
201                        break;
202                case 1:
203                        pgSiz = 1024*2;
204                        break;
205                case 2:
206                        pgSiz = 1024*4;
207                        break;
208                case 3:
209                        pgSiz = 1024*8;
210                        break;
211        }
212        switch((d[3] & 0x30) >> 4) {
213                case 0:
214                        blkSiz = 1024*64;
215                        break;
216                case 1:
217                        blkSiz = 1024*128;
218                        break;
219                case 2:
220                        blkSiz = 1024*256;
221                        break;
222                case 3:
223                        blkSiz = 1024*512;
224                        break;
225        }
226
227        *NAND_CMD(3) = 0x90;
228        *NAND_ADR(3) = 0x20;
229        d1[0] = *NAND_DAT(3);
230        d1[1] = *NAND_DAT(3);
231        d1[2] = *NAND_DAT(3);
232        d1[3] = *NAND_DAT(3);
233        if (memcmp((char *)d1,"ONFI",4) == 0)
234                onfi = 1;
235        else
236                onfi = 0;
237
238        if (nandVerbose) {
239                printf("nandID():  %02x%02x%02x%02x%02x\n",d[0],d[1],d[2],d[3],d[4]);
240                printf("nandID+():  %02x%02x%02x%02x%02x\n",d1[0],d1[1],d1[2],d1[3]);
241                printf("Page size:  0x%x\n",pgSiz);
242                printf("Block size: 0x%x\n",blkSiz);
243                printf("%sONFI compliant\n",onfi ? "" : "Not ");
244        }
245}
246
247int
248nandInit(void)
249{
250        vulong cfgreg;
251
252#if 0
253        printf("CFG1: dm -4 0x%08x 1 = %08x\n",
254                MYGPMC_REG(GPMC_CS3_CONFIG1),GPMC_REG(GPMC_CS3_CONFIG1));
255        printf("CFG2: dm -4 0x%08x 1 = %08x\n",
256                MYGPMC_REG(GPMC_CS3_CONFIG2),GPMC_REG(GPMC_CS3_CONFIG2));
257        printf("CFG3: dm -4 0x%08x 1 = %08x\n",
258                MYGPMC_REG(GPMC_CS3_CONFIG3),GPMC_REG(GPMC_CS3_CONFIG3));
259        printf("CFG4: dm -4 0x%08x 1 = %08x\n",
260                MYGPMC_REG(GPMC_CS3_CONFIG4),GPMC_REG(GPMC_CS3_CONFIG4));
261        printf("CFG5: dm -4 0x%08x 1 = %08x\n",
262                MYGPMC_REG(GPMC_CS3_CONFIG5),GPMC_REG(GPMC_CS3_CONFIG5));
263        printf("CFG6: dm -4 0x%08x 1 = %08x\n",
264                MYGPMC_REG(GPMC_CS3_CONFIG6),GPMC_REG(GPMC_CS3_CONFIG6));
265        printf("CFG7: dm -4 0x%08x 1 = %08x\n",
266                MYGPMC_REG(GPMC_CS3_CONFIG7),GPMC_REG(GPMC_CS3_CONFIG7));
267#endif
268
269
270        /* WAIT3 of the CPU is tied to the NAND's READY pin.  The NAND
271         * is on CS3.  Referring to section 11.1.7.2.10 of the OMAP3530 TRM,
272         * the GPMC_CONFIGX registers must be programmed...
273         */
274        GPMC_REG(GPMC_CONFIG) |= 0x1;                           // Force posted write.
275        GPMC_REG(GPMC_CONFIG) &= ~0x800;                        // WAIT3 active low.
276        GPMC_REG(GPMC_CS3_CONFIG7) = 0x00000858;        // Base addr 0x18000000
277        GPMC_REG(GPMC_CS3_CONFIG1) = 0x00030800;        // 8-bit NAND, WAIT3
278        GPMC_REG(GPMC_CS3_CONFIG2) = 0x00000000;        // Chipselect timing
279        GPMC_REG(GPMC_CS3_CONFIG3) |= 0x7;
280        GPMC_REG(GPMC_CS3_CONFIG6) = 0x8f0307c0;
281
282        // Set drive strength of BE0/CLE
283        *(vulong *)0x48002444 |= 0x00000020;
284
285        /***********************************************************
286         *
287         * ALE and CLE on the NAND are both active high, so we want
288         * them to be pulled low...
289         *
290         * ALE config is the low half of this config register, so we only
291         * touch the bottom half...
292         */
293        cfgreg = SCM_REG(PADCONFS_GPMC_NADV_ALE);       // NOE[31:16], NADV_ALE[15:0]
294        cfgreg &= 0xffff0000;
295        cfgreg |= 0x00000008;
296        SCM_REG(PADCONFS_GPMC_NADV_ALE) = cfgreg;
297        /*
298         * CLE config is the upper half of this config register, so we only
299         * touch the upper half...
300         */
301        cfgreg = SCM_REG(PADCONFS_GPMC_NWE);            // NBE0_CLE[31:16], NWE[15:0]
302        cfgreg &= 0x0000ffff;
303        cfgreg |= 0x00080000;
304        SCM_REG(PADCONFS_GPMC_NWE) = cfgreg;
305
306
307        /* WAIT3 of CPU is tied to R/B pin of NAND...
308         * So, we configure that pin to run as WAIT3.
309         * NOTE:
310         *  There is some confusion between this and what is in cpuio.c. 
311         *  The PADCONFS_GPMC_WAIT2 register sets this pin as GPIO-65 there;
312         *  however the comments are confusing.
313         */
314        cfgreg = SCM_REG(PADCONFS_GPMC_WAIT2);          // WAIT3[31:16], WAIT2[15:0]
315        cfgreg &= 0x0000ffff;
316        cfgreg |= 0x00080000;
317        SCM_REG(PADCONFS_GPMC_NWE) = cfgreg;
318
319        nandId();
320        return(0);
321}
322
323int
324nandInfo(void)
325{
326        nandId();
327        return(0);
328}
329
330
331#endif
332
333
Note: See TracBrowser for help on using the repository browser.