]> git.sur5r.net Git - u-boot/blob - board/prodrive/alpr/nand.c
Merge with /home/stefan/git/u-boot/denx
[u-boot] / board / prodrive / alpr / nand.c
1 /*
2  * (C) Copyright 2006
3  * Heiko Schocher, DENX Software Engineering, hs@denx.de
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 #include <asm/io.h>
26
27 #if (CONFIG_COMMANDS & CFG_CMD_NAND)
28
29 #include <nand.h>
30
31 #if 0
32 #define HS_printf(fmt,arg...) \
33         printf("HS %s %s: " fmt,__FILE__, __FUNCTION__, ##arg)
34 #else
35 #define HS_printf(fmt,arg...) \
36         do { } while (0)
37 #endif
38
39 #if 0
40 #define CPLD_REG        uchar
41 #else
42 #define CPLD_REG        u16
43 #endif
44
45 struct alpr_ndfc_regs {
46         CPLD_REG cmd[4];
47         CPLD_REG addr_wait;
48         CPLD_REG term;
49         CPLD_REG dummy;
50         uchar    dum2[2];
51         CPLD_REG data;
52 };
53
54 static u8 hwctl;
55 static struct alpr_ndfc_regs *alpr_ndfc;
56 static int      alpr_chip = 0;
57
58 #if 1
59 static int pdnb3_nand_dev_ready(struct mtd_info *mtd);
60
61 #if 1
62 static u_char alpr_read (void *padr) {
63         return (u_char )*((u16 *)(padr));
64 }
65 #else
66 static u_char alpr_read (void *padr) {
67         u16     hilf;
68         u_char ret = 0;
69         hilf = *((u16 *)(padr));
70         ret = hilf;
71 printf("%p hilf: %x ret: %x\n", padr, hilf, ret);
72         return ret;
73 }
74 #endif
75
76 static void alpr_write (u_char byte, void *padr) {
77 HS_printf("%p  Byte: %x\n", padr, byte);
78         *(volatile u16 *)padr = (u16)(byte);
79 }
80
81 #elif 0
82 #define alpr_read(a) (*(volatile u16 *) (a))
83 #define alpr_write(a, b) ((*(volatile u16 *) (a)) = (b))
84 #else
85 #define alpr_read(a) readw(a)
86 #define alpr_write(a, b) writew(a, b)
87 #endif
88 /*
89  * The ALPR has a NAND Flash Controller (NDFC) that handles all accesses to
90  * the NAND devices.  The NDFC has command, address and data registers that
91  * when accessed will set up the NAND flash pins appropriately.  We'll use the
92  * hwcontrol function to save the configuration in a global variable.
93  * We can then use this information in the read and write functions to
94  * determine which NDFC register to access.
95  *
96  * There are 2 NAND devices on the board, a Hynix HY27US08561A (32 MByte).
97  */
98 static void pdnb3_nand_hwcontrol(struct mtd_info *mtd, int cmd)
99 {
100 HS_printf("cmd: %x\n", cmd);
101         switch (cmd) {
102         case NAND_CTL_SETCLE:
103                 hwctl |= 0x1;
104                 break;
105         case NAND_CTL_CLRCLE:
106                 hwctl &= ~0x1;
107                 break;
108         case NAND_CTL_SETALE:
109                 hwctl |= 0x2;
110                 break;
111         case NAND_CTL_CLRALE:
112                 hwctl &= ~0x2;
113                 break;
114         case NAND_CTL_SETNCE:
115                 break;
116         case NAND_CTL_CLRNCE:
117                 alpr_write(0x00, &(alpr_ndfc->term));
118                 break;
119         }
120 }
121
122 static void pdnb3_nand_write_byte(struct mtd_info *mtd, u_char byte)
123 {
124 HS_printf("hwctl: %x %x %x %x\n", hwctl, byte, &(alpr_ndfc->cmd[alpr_chip]), &(alpr_ndfc->addr_wait));
125         if (hwctl & 0x1)
126                 alpr_write(byte, &(alpr_ndfc->cmd[alpr_chip]));
127         else if (hwctl & 0x2) {
128                 alpr_write(byte, &(alpr_ndfc->addr_wait));
129         } else
130                 alpr_write(byte, &(alpr_ndfc->data));
131 }
132
133 static u_char pdnb3_nand_read_byte(struct mtd_info *mtd)
134 {
135         return alpr_read(&(alpr_ndfc->data));
136 }
137
138 static void pdnb3_nand_write_buf(struct mtd_info *mtd, const u_char *buf, int len)
139 {
140         int i;
141
142 /*printf("%s chip:%d hwctl:%x size:%d\n", __FUNCTION__, alpr_chip, hwctl, len);*/
143         for (i = 0; i < len; i++) {
144                 if (hwctl & 0x1)
145                         alpr_write(buf[i], &(alpr_ndfc->cmd[alpr_chip]));
146                 else if (hwctl & 0x2) {
147                         alpr_write(buf[i], &(alpr_ndfc->addr_wait));
148                 } else {
149                         alpr_write(buf[i], &(alpr_ndfc->data));
150                         /*printf("i: %d\n", i);*/
151                 }       
152         }
153 }
154
155 static void pdnb3_nand_read_buf(struct mtd_info *mtd, u_char *buf, int len)
156 {
157         int i;
158
159         for (i = 0; i < len; i++) {
160                 buf[i] = alpr_read(&(alpr_ndfc->data));
161         }
162 }
163
164 static int pdnb3_nand_verify_buf(struct mtd_info *mtd, const u_char *buf, int len)
165 {
166         int i;
167
168         for (i = 0; i < len; i++)
169                 if (buf[i] != alpr_read(&(alpr_ndfc->data)))
170                         return i;
171
172         return 0;
173 }
174
175 static int pdnb3_nand_dev_ready(struct mtd_info *mtd)
176 {
177 #if 1
178         volatile u_char val;
179
180 /*printf("%s aufruf\n", __FUNCTION__);*/
181         /*
182          * Blocking read to wait for NAND to be ready
183          */
184         val = alpr_read(&(alpr_ndfc->addr_wait));
185
186         /*
187          * Return always true
188          */
189         return 1;
190 #else
191         u8 hwctl_org = hwctl;
192         unsigned long   timeo;
193         u8      val;
194
195         hwctl = 0x01;
196         pdnb3_nand_write_byte (mtd, NAND_CMD_STATUS);
197         hwctl = hwctl_org;
198
199         reset_timer();
200         while (1) {
201                 if (get_timer(0) > timeo) {
202                         printf("Timeout!");
203                         return 0;
204                         }
205
206 val = pdnb3_nand_read_byte(mtd);
207 /*printf("%s val: %x\n", __FUNCTION__, val);*/
208                         if (val & NAND_STATUS_READY)
209                                 break;
210         }
211         return 1;
212 #endif
213
214 }
215
216 static void alpr_select_chip(struct mtd_info *mtd, int chip)
217 {
218         alpr_chip = chip;
219 }
220
221 static int alpr_nand_wait(struct mtd_info *mtd, struct nand_chip *this, int state)
222 {
223         unsigned long   timeo;
224
225         if (state == FL_ERASING)
226                 timeo = CFG_HZ * 400;
227         else
228                 timeo = CFG_HZ * 20;
229
230         if ((state == FL_ERASING) && (this->options & NAND_IS_AND))
231                 this->cmdfunc(mtd, NAND_CMD_STATUS_MULTI, -1, -1);
232         else
233                 this->cmdfunc(mtd, NAND_CMD_STATUS, -1, -1);
234
235         reset_timer();
236
237         while (1) {
238                 if (get_timer(0) > timeo) {
239                         printf("Timeout!");
240                         return 0;
241                         }
242
243                         if (this->read_byte(mtd) & NAND_STATUS_READY)
244                                 break;
245         }
246         return this->read_byte(mtd);
247 }
248
249 void board_nand_init(struct nand_chip *nand)
250 {
251         alpr_ndfc = (struct alpr_ndfc_regs *)CFG_NAND_BASE;
252
253         nand->eccmode = NAND_ECC_SOFT;
254
255         /* Set address of NAND IO lines (Using Linear Data Access Region) */
256         nand->IO_ADDR_R = (void __iomem *) ((ulong) alpr_ndfc + 0x10);
257         nand->IO_ADDR_W = (void __iomem *) ((ulong) alpr_ndfc + 0x10);
258         /* Reference hardware control function */
259         nand->hwcontrol  = pdnb3_nand_hwcontrol;
260         /* Set command delay time */
261         nand->hwcontrol  = pdnb3_nand_hwcontrol;
262         nand->write_byte = pdnb3_nand_write_byte;
263         nand->read_byte  = pdnb3_nand_read_byte;
264         nand->write_buf  = pdnb3_nand_write_buf;
265         nand->read_buf   = pdnb3_nand_read_buf;
266         nand->verify_buf = pdnb3_nand_verify_buf;
267         nand->dev_ready  = pdnb3_nand_dev_ready;
268         nand->select_chip = alpr_select_chip;
269         nand->waitfunc   = alpr_nand_wait;
270 }
271 #endif