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