[mcs814x] nuport-mac: various fixes
[openwrt/svn-archive/archive.git] / package / uboot-xburst / files / cpu / mips / jz4740_nand.c
1 /*
2 * Platform independend driver for JZ4740.
3 *
4 * Copyright (c) 2007 Ingenic Semiconductor Inc.
5 * Author: <jlwei@ingenic.cn>
6 *
7 * This program is free software; you can redistribute it and/or
8 * modify it under the terms of the GNU General Public License as
9 * published by the Free Software Foundation; either version 2 of
10 * the License, or (at your option) any later version.
11 */
12 #include <common.h>
13
14 #if defined(CONFIG_CMD_NAND) && defined(CONFIG_JZ4740)
15
16 #include <nand.h>
17 #include <asm/jz4740.h>
18 #include <asm/io.h>
19
20 #define PAR_SIZE 9
21 #define __nand_ecc_enable() (REG_EMC_NFECR = EMC_NFECR_ECCE | EMC_NFECR_ERST )
22 #define __nand_ecc_disable() (REG_EMC_NFECR &= ~EMC_NFECR_ECCE)
23
24 #define __nand_select_rs_ecc() (REG_EMC_NFECR |= EMC_NFECR_RS)
25
26 #define __nand_rs_ecc_encoding() (REG_EMC_NFECR |= EMC_NFECR_RS_ENCODING)
27 #define __nand_rs_ecc_decoding() (REG_EMC_NFECR |= EMC_NFECR_RS_DECODING)
28 #define __nand_ecc_encode_sync() while (!(REG_EMC_NFINTS & EMC_NFINTS_ENCF))
29 #define __nand_ecc_decode_sync() while (!(REG_EMC_NFINTS & EMC_NFINTS_DECF))
30
31 static void jz_hwcontrol(struct mtd_info *mtd, int cmd, unsigned int ctrl)
32 {
33 struct nand_chip *this = mtd->priv;
34 unsigned long nandaddr = (unsigned long)this->IO_ADDR_W;
35
36 if (ctrl & NAND_CTRL_CHANGE) {
37 /* Change this to use I/O accessors. */
38 if (ctrl & NAND_NCE)
39 REG_EMC_NFCSR |= EMC_NFCSR_NFCE1;
40 else
41 REG_EMC_NFCSR &= ~EMC_NFCSR_NFCE1;
42 }
43
44 if (cmd == NAND_CMD_NONE)
45 return;
46
47 if (ctrl & NAND_CLE)
48 nandaddr |= 0x00008000;
49 else /* must be ALE */
50 nandaddr |= 0x00010000;
51
52 writeb(cmd, (uint8_t *)nandaddr);
53 }
54
55 static int jz_device_ready(struct mtd_info *mtd)
56 {
57 int ready;
58 udelay(20); /* FIXME: add 20us delay */
59 ready = (REG_GPIO_PXPIN(2) & 0x40000000) ? 1 : 0;
60 return ready;
61 }
62
63 /*
64 * EMC setup
65 */
66 static void jz_device_setup(void)
67 {
68 /* Set NFE bit */
69 REG_EMC_NFCSR |= EMC_NFCSR_NFE1;
70 REG_EMC_SMCR1 = 0x094c4400;
71 /* REG_EMC_SMCR3 = 0x04444400; */
72 }
73
74 void board_nand_select_device(struct nand_chip *nand, int chip)
75 {
76 /*
77 * Don't use "chip" to address the NAND device,
78 * generate the cs from the address where it is encoded.
79 */
80 }
81
82 static int jzsoc_nand_calculate_rs_ecc(struct mtd_info* mtd, const u_char* dat,
83 u_char* ecc_code)
84 {
85 volatile u8 *paraddr = (volatile u8 *)EMC_NFPAR0;
86 short i;
87
88 __nand_ecc_encode_sync()
89 __nand_ecc_disable();
90
91 for(i = 0; i < PAR_SIZE; i++)
92 ecc_code[i] = *paraddr++;
93
94 return 0;
95 }
96
97 static void jzsoc_nand_enable_rs_hwecc(struct mtd_info* mtd, int mode)
98 {
99 __nand_ecc_enable();
100 __nand_select_rs_ecc();
101
102 REG_EMC_NFINTS = 0x0;
103 if (NAND_ECC_READ == mode){
104 __nand_rs_ecc_decoding();
105 }
106 if (NAND_ECC_WRITE == mode){
107 __nand_rs_ecc_encoding();
108 }
109 }
110
111 /* Correct 1~9-bit errors in 512-bytes data */
112 static void jzsoc_rs_correct(unsigned char *dat, int idx, int mask)
113 {
114 int i;
115
116 idx--;
117
118 i = idx + (idx >> 3);
119 if (i >= 512)
120 return;
121
122 mask <<= (idx & 0x7);
123
124 dat[i] ^= mask & 0xff;
125 if (i < 511)
126 dat[i+1] ^= (mask >> 8) & 0xff;
127 }
128
129 static int jzsoc_nand_rs_correct_data(struct mtd_info *mtd, u_char *dat,
130 u_char *read_ecc, u_char *calc_ecc)
131 {
132 volatile u8 *paraddr = (volatile u8 *)EMC_NFPAR0;
133 short k;
134 u32 stat;
135 /* Set PAR values */
136
137 for (k = 0; k < PAR_SIZE; k++) {
138 *paraddr++ = read_ecc[k];
139 }
140
141 /* Set PRDY */
142 REG_EMC_NFECR |= EMC_NFECR_PRDY;
143
144 /* Wait for completion */
145 __nand_ecc_decode_sync();
146 __nand_ecc_disable();
147
148 /* Check decoding */
149 stat = REG_EMC_NFINTS;
150 if (stat & EMC_NFINTS_ERR) {
151 if (stat & EMC_NFINTS_UNCOR) {
152 printk("Uncorrectable error occurred\n");
153 return -1;
154 }
155 else {
156 u32 errcnt = (stat & EMC_NFINTS_ERRCNT_MASK) >> EMC_NFINTS_ERRCNT_BIT;
157 switch (errcnt) {
158 case 4:
159 jzsoc_rs_correct(dat, (REG_EMC_NFERR3 & EMC_NFERR_INDEX_MASK) >> EMC_NFERR_INDEX_BIT, (REG_EMC_NFERR3 & EMC_NFERR_MASK_MASK) >> EMC_NFERR_MASK_BIT);
160 case 3:
161 jzsoc_rs_correct(dat, (REG_EMC_NFERR2 & EMC_NFERR_INDEX_MASK) >> EMC_NFERR_INDEX_BIT, (REG_EMC_NFERR2 & EMC_NFERR_MASK_MASK) >> EMC_NFERR_MASK_BIT);
162 case 2:
163 jzsoc_rs_correct(dat, (REG_EMC_NFERR1 & EMC_NFERR_INDEX_MASK) >> EMC_NFERR_INDEX_BIT, (REG_EMC_NFERR1 & EMC_NFERR_MASK_MASK) >> EMC_NFERR_MASK_BIT);
164 case 1:
165 jzsoc_rs_correct(dat, (REG_EMC_NFERR0 & EMC_NFERR_INDEX_MASK) >> EMC_NFERR_INDEX_BIT, (REG_EMC_NFERR0 & EMC_NFERR_MASK_MASK) >> EMC_NFERR_MASK_BIT);
166 return 0;
167 default:
168 break;
169 }
170 }
171 }
172 /* no error need to be correct */
173 return 0;
174 }
175
176 /*
177 * Main initialization routine
178 */
179 int board_nand_init(struct nand_chip *nand)
180 {
181 jz_device_setup();
182
183 nand->cmd_ctrl = jz_hwcontrol;
184 nand->dev_ready = jz_device_ready;
185
186 /* FIXME: should use NAND_ECC_SOFT */
187 nand->ecc.hwctl = jzsoc_nand_enable_rs_hwecc;
188 nand->ecc.correct = jzsoc_nand_rs_correct_data;
189 nand->ecc.calculate = jzsoc_nand_calculate_rs_ecc;
190 nand->ecc.mode = NAND_ECC_HW;
191 nand->ecc.size = 512;
192 nand->ecc.bytes = 9;
193
194 /* 20 us command delay time */
195 nand->chip_delay = 20;
196
197 return 0;
198 }
199 #endif /* (CONFIG_SYS_CMD_NAND) */