]>
Commit | Line | Data |
---|---|---|
3a6591a8 XL |
1 | /* |
2 | * Platform independend driver for JZ4740. | |
3 | * | |
4 | * Copyright (c) 2007 Ingenic Semiconductor Inc. | |
5 | * Author: <jlwei@ingenic.cn> | |
6 | * | |
1a459660 | 7 | * SPDX-License-Identifier: GPL-2.0+ |
3a6591a8 XL |
8 | */ |
9 | #include <common.h> | |
10 | ||
11 | #include <nand.h> | |
12 | #include <asm/io.h> | |
13 | #include <asm/jz4740.h> | |
14 | ||
15 | #define JZ_NAND_DATA_ADDR ((void __iomem *)0xB8000000) | |
16 | #define JZ_NAND_CMD_ADDR (JZ_NAND_DATA_ADDR + 0x8000) | |
17 | #define JZ_NAND_ADDR_ADDR (JZ_NAND_DATA_ADDR + 0x10000) | |
18 | ||
19 | #define BIT(x) (1 << (x)) | |
20 | #define JZ_NAND_ECC_CTRL_ENCODING BIT(3) | |
21 | #define JZ_NAND_ECC_CTRL_RS BIT(2) | |
22 | #define JZ_NAND_ECC_CTRL_RESET BIT(1) | |
23 | #define JZ_NAND_ECC_CTRL_ENABLE BIT(0) | |
24 | ||
25 | #define EMC_SMCR1_OPT_NAND 0x094c4400 | |
26 | /* Optimize the timing of nand */ | |
27 | ||
28 | static struct jz4740_emc * emc = (struct jz4740_emc *)JZ4740_EMC_BASE; | |
29 | ||
30 | static struct nand_ecclayout qi_lb60_ecclayout_2gb = { | |
31 | .eccbytes = 72, | |
32 | .eccpos = { | |
33 | 12, 13, 14, 15, 16, 17, 18, 19, | |
34 | 20, 21, 22, 23, 24, 25, 26, 27, | |
35 | 28, 29, 30, 31, 32, 33, 34, 35, | |
36 | 36, 37, 38, 39, 40, 41, 42, 43, | |
37 | 44, 45, 46, 47, 48, 49, 50, 51, | |
38 | 52, 53, 54, 55, 56, 57, 58, 59, | |
39 | 60, 61, 62, 63, 64, 65, 66, 67, | |
40 | 68, 69, 70, 71, 72, 73, 74, 75, | |
41 | 76, 77, 78, 79, 80, 81, 82, 83 }, | |
42 | .oobfree = { | |
43 | {.offset = 2, | |
44 | .length = 10 }, | |
45 | {.offset = 84, | |
46 | .length = 44 } } | |
47 | }; | |
48 | ||
49 | static int is_reading; | |
50 | ||
51 | static void jz_nand_cmd_ctrl(struct mtd_info *mtd, int cmd, unsigned int ctrl) | |
52 | { | |
53 | struct nand_chip *this = mtd->priv; | |
54 | uint32_t reg; | |
55 | ||
56 | if (ctrl & NAND_CTRL_CHANGE) { | |
57 | if (ctrl & NAND_ALE) | |
58 | this->IO_ADDR_W = JZ_NAND_ADDR_ADDR; | |
59 | else if (ctrl & NAND_CLE) | |
60 | this->IO_ADDR_W = JZ_NAND_CMD_ADDR; | |
61 | else | |
62 | this->IO_ADDR_W = JZ_NAND_DATA_ADDR; | |
63 | ||
64 | reg = readl(&emc->nfcsr); | |
65 | if (ctrl & NAND_NCE) | |
66 | reg |= EMC_NFCSR_NFCE1; | |
67 | else | |
68 | reg &= ~EMC_NFCSR_NFCE1; | |
69 | writel(reg, &emc->nfcsr); | |
70 | } | |
71 | ||
72 | if (cmd != NAND_CMD_NONE) | |
73 | writeb(cmd, this->IO_ADDR_W); | |
74 | } | |
75 | ||
76 | static int jz_nand_device_ready(struct mtd_info *mtd) | |
77 | { | |
78 | return (readl(GPIO_PXPIN(2)) & 0x40000000) ? 1 : 0; | |
79 | } | |
80 | ||
81 | void board_nand_select_device(struct nand_chip *nand, int chip) | |
82 | { | |
83 | /* | |
84 | * Don't use "chip" to address the NAND device, | |
85 | * generate the cs from the address where it is encoded. | |
86 | */ | |
87 | } | |
88 | ||
89 | static int jz_nand_rs_calculate_ecc(struct mtd_info *mtd, const u_char *dat, | |
90 | u_char *ecc_code) | |
91 | { | |
92 | uint32_t status; | |
93 | int i; | |
94 | ||
95 | if (is_reading) | |
96 | return 0; | |
97 | ||
98 | do { | |
99 | status = readl(&emc->nfints); | |
100 | } while (!(status & EMC_NFINTS_ENCF)); | |
101 | ||
102 | /* disable ecc */ | |
103 | writel(readl(&emc->nfecr) & ~EMC_NFECR_ECCE, &emc->nfecr); | |
104 | ||
105 | for (i = 0; i < 9; i++) | |
106 | ecc_code[i] = readb(&emc->nfpar[i]); | |
107 | ||
108 | return 0; | |
109 | } | |
110 | ||
111 | static void jz_nand_hwctl(struct mtd_info *mtd, int mode) | |
112 | { | |
113 | uint32_t reg; | |
114 | ||
115 | writel(0, &emc->nfints); | |
116 | reg = readl(&emc->nfecr); | |
117 | reg |= JZ_NAND_ECC_CTRL_RESET; | |
118 | reg |= JZ_NAND_ECC_CTRL_ENABLE; | |
119 | reg |= JZ_NAND_ECC_CTRL_RS; | |
120 | ||
121 | switch (mode) { | |
122 | case NAND_ECC_READ: | |
123 | reg &= ~JZ_NAND_ECC_CTRL_ENCODING; | |
124 | is_reading = 1; | |
125 | break; | |
126 | case NAND_ECC_WRITE: | |
127 | reg |= JZ_NAND_ECC_CTRL_ENCODING; | |
128 | is_reading = 0; | |
129 | break; | |
130 | default: | |
131 | break; | |
132 | } | |
133 | ||
134 | writel(reg, &emc->nfecr); | |
135 | } | |
136 | ||
137 | /* Correct 1~9-bit errors in 512-bytes data */ | |
138 | static void jz_rs_correct(unsigned char *dat, int idx, int mask) | |
139 | { | |
140 | int i; | |
141 | ||
142 | idx--; | |
143 | ||
144 | i = idx + (idx >> 3); | |
145 | if (i >= 512) | |
146 | return; | |
147 | ||
148 | mask <<= (idx & 0x7); | |
149 | ||
150 | dat[i] ^= mask & 0xff; | |
151 | if (i < 511) | |
152 | dat[i + 1] ^= (mask >> 8) & 0xff; | |
153 | } | |
154 | ||
155 | static int jz_nand_rs_correct_data(struct mtd_info *mtd, u_char *dat, | |
156 | u_char *read_ecc, u_char *calc_ecc) | |
157 | { | |
158 | int k; | |
159 | uint32_t errcnt, index, mask, status; | |
160 | ||
161 | /* Set PAR values */ | |
162 | const uint8_t all_ff_ecc[] = { | |
163 | 0xcd, 0x9d, 0x90, 0x58, 0xf4, 0x8b, 0xff, 0xb7, 0x6f }; | |
164 | ||
165 | if (read_ecc[0] == 0xff && read_ecc[1] == 0xff && | |
166 | read_ecc[2] == 0xff && read_ecc[3] == 0xff && | |
167 | read_ecc[4] == 0xff && read_ecc[5] == 0xff && | |
168 | read_ecc[6] == 0xff && read_ecc[7] == 0xff && | |
169 | read_ecc[8] == 0xff) { | |
170 | for (k = 0; k < 9; k++) | |
171 | writeb(all_ff_ecc[k], &emc->nfpar[k]); | |
172 | } else { | |
173 | for (k = 0; k < 9; k++) | |
174 | writeb(read_ecc[k], &emc->nfpar[k]); | |
175 | } | |
176 | /* Set PRDY */ | |
177 | writel(readl(&emc->nfecr) | EMC_NFECR_PRDY, &emc->nfecr); | |
178 | ||
179 | /* Wait for completion */ | |
180 | do { | |
181 | status = readl(&emc->nfints); | |
182 | } while (!(status & EMC_NFINTS_DECF)); | |
183 | ||
184 | /* disable ecc */ | |
185 | writel(readl(&emc->nfecr) & ~EMC_NFECR_ECCE, &emc->nfecr); | |
186 | ||
187 | /* Check decoding */ | |
188 | if (!(status & EMC_NFINTS_ERR)) | |
189 | return 0; | |
190 | ||
191 | if (status & EMC_NFINTS_UNCOR) { | |
192 | printf("uncorrectable ecc\n"); | |
193 | return -1; | |
194 | } | |
195 | ||
196 | errcnt = (status & EMC_NFINTS_ERRCNT_MASK) >> EMC_NFINTS_ERRCNT_BIT; | |
197 | ||
198 | switch (errcnt) { | |
199 | case 4: | |
200 | index = (readl(&emc->nferr[3]) & EMC_NFERR_INDEX_MASK) >> | |
201 | EMC_NFERR_INDEX_BIT; | |
202 | mask = (readl(&emc->nferr[3]) & EMC_NFERR_MASK_MASK) >> | |
203 | EMC_NFERR_MASK_BIT; | |
204 | jz_rs_correct(dat, index, mask); | |
205 | case 3: | |
206 | index = (readl(&emc->nferr[2]) & EMC_NFERR_INDEX_MASK) >> | |
207 | EMC_NFERR_INDEX_BIT; | |
208 | mask = (readl(&emc->nferr[2]) & EMC_NFERR_MASK_MASK) >> | |
209 | EMC_NFERR_MASK_BIT; | |
210 | jz_rs_correct(dat, index, mask); | |
211 | case 2: | |
212 | index = (readl(&emc->nferr[1]) & EMC_NFERR_INDEX_MASK) >> | |
213 | EMC_NFERR_INDEX_BIT; | |
214 | mask = (readl(&emc->nferr[1]) & EMC_NFERR_MASK_MASK) >> | |
215 | EMC_NFERR_MASK_BIT; | |
216 | jz_rs_correct(dat, index, mask); | |
217 | case 1: | |
218 | index = (readl(&emc->nferr[0]) & EMC_NFERR_INDEX_MASK) >> | |
219 | EMC_NFERR_INDEX_BIT; | |
220 | mask = (readl(&emc->nferr[0]) & EMC_NFERR_MASK_MASK) >> | |
221 | EMC_NFERR_MASK_BIT; | |
222 | jz_rs_correct(dat, index, mask); | |
223 | default: | |
224 | break; | |
225 | } | |
226 | ||
227 | return errcnt; | |
228 | } | |
229 | ||
230 | /* | |
231 | * Main initialization routine | |
232 | */ | |
233 | int board_nand_init(struct nand_chip *nand) | |
234 | { | |
235 | uint32_t reg; | |
236 | ||
237 | reg = readl(&emc->nfcsr); | |
238 | reg |= EMC_NFCSR_NFE1; /* EMC setup, Set NFE bit */ | |
239 | writel(reg, &emc->nfcsr); | |
240 | ||
241 | writel(EMC_SMCR1_OPT_NAND, &emc->smcr[1]); | |
242 | ||
243 | nand->IO_ADDR_R = JZ_NAND_DATA_ADDR; | |
244 | nand->IO_ADDR_W = JZ_NAND_DATA_ADDR; | |
245 | nand->cmd_ctrl = jz_nand_cmd_ctrl; | |
246 | nand->dev_ready = jz_nand_device_ready; | |
247 | nand->ecc.hwctl = jz_nand_hwctl; | |
248 | nand->ecc.correct = jz_nand_rs_correct_data; | |
249 | nand->ecc.calculate = jz_nand_rs_calculate_ecc; | |
250 | nand->ecc.mode = NAND_ECC_HW_OOB_FIRST; | |
251 | nand->ecc.size = CONFIG_SYS_NAND_ECCSIZE; | |
252 | nand->ecc.bytes = CONFIG_SYS_NAND_ECCBYTES; | |
dfe64e2c | 253 | nand->ecc.strength = 4; |
3a6591a8 XL |
254 | nand->ecc.layout = &qi_lb60_ecclayout_2gb; |
255 | nand->chip_delay = 50; | |
eab22764 | 256 | nand->bbt_options |= NAND_BBT_USE_FLASH; |
3a6591a8 XL |
257 | |
258 | return 0; | |
259 | } |