1 | // SPDX-License-Identifier: GPL-2.0-only |
2 | /* |
3 | * (C) 2005, 2006 Red Hat Inc. |
4 | * |
5 | * Author: David Woodhouse <dwmw2@infradead.org> |
6 | * Tom Sylla <tom.sylla@amd.com> |
7 | * |
8 | * Overview: |
9 | * This is a device driver for the NAND flash controller found on |
10 | * the AMD CS5535/CS5536 companion chipsets for the Geode processor. |
11 | * mtd-id for command line partitioning is cs553x_nand_cs[0-3] |
12 | * where 0-3 reflects the chip select for NAND. |
13 | */ |
14 | |
15 | #include <linux/kernel.h> |
16 | #include <linux/slab.h> |
17 | #include <linux/init.h> |
18 | #include <linux/module.h> |
19 | #include <linux/delay.h> |
20 | #include <linux/mtd/mtd.h> |
21 | #include <linux/mtd/rawnand.h> |
22 | #include <linux/mtd/partitions.h> |
23 | #include <linux/iopoll.h> |
24 | |
25 | #include <asm/msr.h> |
26 | |
27 | #define NR_CS553X_CONTROLLERS 4 |
28 | |
29 | #define MSR_DIVIL_GLD_CAP 0x51400000 /* DIVIL capabilitiies */ |
30 | #define CAP_CS5535 0x2df000ULL |
31 | #define CAP_CS5536 0x5df500ULL |
32 | |
33 | /* NAND Timing MSRs */ |
34 | #define MSR_NANDF_DATA 0x5140001b /* NAND Flash Data Timing MSR */ |
35 | #define MSR_NANDF_CTL 0x5140001c /* NAND Flash Control Timing */ |
36 | #define MSR_NANDF_RSVD 0x5140001d /* Reserved */ |
37 | |
38 | /* NAND BAR MSRs */ |
39 | #define MSR_DIVIL_LBAR_FLSH0 0x51400010 /* Flash Chip Select 0 */ |
40 | #define MSR_DIVIL_LBAR_FLSH1 0x51400011 /* Flash Chip Select 1 */ |
41 | #define MSR_DIVIL_LBAR_FLSH2 0x51400012 /* Flash Chip Select 2 */ |
42 | #define MSR_DIVIL_LBAR_FLSH3 0x51400013 /* Flash Chip Select 3 */ |
43 | /* Each made up of... */ |
44 | #define FLSH_LBAR_EN (1ULL<<32) |
45 | #define FLSH_NOR_NAND (1ULL<<33) /* 1 for NAND */ |
46 | #define FLSH_MEM_IO (1ULL<<34) /* 1 for MMIO */ |
47 | /* I/O BARs have BASE_ADDR in bits 15:4, IO_MASK in 47:36 */ |
48 | /* MMIO BARs have BASE_ADDR in bits 31:12, MEM_MASK in 63:44 */ |
49 | |
50 | /* Pin function selection MSR (IDE vs. flash on the IDE pins) */ |
51 | #define MSR_DIVIL_BALL_OPTS 0x51400015 |
52 | #define PIN_OPT_IDE (1<<0) /* 0 for flash, 1 for IDE */ |
53 | |
54 | /* Registers within the NAND flash controller BAR -- memory mapped */ |
55 | #define MM_NAND_DATA 0x00 /* 0 to 0x7ff, in fact */ |
56 | #define MM_NAND_CTL 0x800 /* Any even address 0x800-0x80e */ |
57 | #define MM_NAND_IO 0x801 /* Any odd address 0x801-0x80f */ |
58 | #define MM_NAND_STS 0x810 |
59 | #define MM_NAND_ECC_LSB 0x811 |
60 | #define MM_NAND_ECC_MSB 0x812 |
61 | #define MM_NAND_ECC_COL 0x813 |
62 | #define MM_NAND_LAC 0x814 |
63 | #define MM_NAND_ECC_CTL 0x815 |
64 | |
65 | /* Registers within the NAND flash controller BAR -- I/O mapped */ |
66 | #define IO_NAND_DATA 0x00 /* 0 to 3, in fact */ |
67 | #define IO_NAND_CTL 0x04 |
68 | #define IO_NAND_IO 0x05 |
69 | #define IO_NAND_STS 0x06 |
70 | #define IO_NAND_ECC_CTL 0x08 |
71 | #define IO_NAND_ECC_LSB 0x09 |
72 | #define IO_NAND_ECC_MSB 0x0a |
73 | #define IO_NAND_ECC_COL 0x0b |
74 | #define IO_NAND_LAC 0x0c |
75 | |
76 | #define CS_NAND_CTL_DIST_EN (1<<4) /* Enable NAND Distract interrupt */ |
77 | #define CS_NAND_CTL_RDY_INT_MASK (1<<3) /* Enable RDY/BUSY# interrupt */ |
78 | #define CS_NAND_CTL_ALE (1<<2) |
79 | #define CS_NAND_CTL_CLE (1<<1) |
80 | #define CS_NAND_CTL_CE (1<<0) /* Keep low; 1 to reset */ |
81 | |
82 | #define CS_NAND_STS_FLASH_RDY (1<<3) |
83 | #define CS_NAND_CTLR_BUSY (1<<2) |
84 | #define CS_NAND_CMD_COMP (1<<1) |
85 | #define CS_NAND_DIST_ST (1<<0) |
86 | |
87 | #define CS_NAND_ECC_PARITY (1<<2) |
88 | #define CS_NAND_ECC_CLRECC (1<<1) |
89 | #define CS_NAND_ECC_ENECC (1<<0) |
90 | |
91 | struct cs553x_nand_controller { |
92 | struct nand_controller base; |
93 | struct nand_chip chip; |
94 | void __iomem *mmio; |
95 | }; |
96 | |
97 | static struct cs553x_nand_controller * |
98 | to_cs553x(struct nand_controller *controller) |
99 | { |
100 | return container_of(controller, struct cs553x_nand_controller, base); |
101 | } |
102 | |
103 | static int cs553x_write_ctrl_byte(struct cs553x_nand_controller *cs553x, |
104 | u32 ctl, u8 data) |
105 | { |
106 | u8 status; |
107 | |
108 | writeb(val: ctl, addr: cs553x->mmio + MM_NAND_CTL); |
109 | writeb(val: data, addr: cs553x->mmio + MM_NAND_IO); |
110 | return readb_poll_timeout_atomic(cs553x->mmio + MM_NAND_STS, status, |
111 | !(status & CS_NAND_CTLR_BUSY), 1, |
112 | 100000); |
113 | } |
114 | |
115 | static void cs553x_data_in(struct cs553x_nand_controller *cs553x, void *buf, |
116 | unsigned int len) |
117 | { |
118 | writeb(val: 0, addr: cs553x->mmio + MM_NAND_CTL); |
119 | while (unlikely(len > 0x800)) { |
120 | memcpy_fromio(buf, cs553x->mmio, 0x800); |
121 | buf += 0x800; |
122 | len -= 0x800; |
123 | } |
124 | memcpy_fromio(buf, cs553x->mmio, len); |
125 | } |
126 | |
127 | static void cs553x_data_out(struct cs553x_nand_controller *cs553x, |
128 | const void *buf, unsigned int len) |
129 | { |
130 | writeb(val: 0, addr: cs553x->mmio + MM_NAND_CTL); |
131 | while (unlikely(len > 0x800)) { |
132 | memcpy_toio(cs553x->mmio, buf, 0x800); |
133 | buf += 0x800; |
134 | len -= 0x800; |
135 | } |
136 | memcpy_toio(cs553x->mmio, buf, len); |
137 | } |
138 | |
139 | static int cs553x_wait_ready(struct cs553x_nand_controller *cs553x, |
140 | unsigned int timeout_ms) |
141 | { |
142 | u8 mask = CS_NAND_CTLR_BUSY | CS_NAND_STS_FLASH_RDY; |
143 | u8 status; |
144 | |
145 | return readb_poll_timeout(cs553x->mmio + MM_NAND_STS, status, |
146 | (status & mask) == CS_NAND_STS_FLASH_RDY, 100, |
147 | timeout_ms * 1000); |
148 | } |
149 | |
150 | static int cs553x_exec_instr(struct cs553x_nand_controller *cs553x, |
151 | const struct nand_op_instr *instr) |
152 | { |
153 | unsigned int i; |
154 | int ret = 0; |
155 | |
156 | switch (instr->type) { |
157 | case NAND_OP_CMD_INSTR: |
158 | ret = cs553x_write_ctrl_byte(cs553x, CS_NAND_CTL_CLE, |
159 | data: instr->ctx.cmd.opcode); |
160 | break; |
161 | |
162 | case NAND_OP_ADDR_INSTR: |
163 | for (i = 0; i < instr->ctx.addr.naddrs; i++) { |
164 | ret = cs553x_write_ctrl_byte(cs553x, CS_NAND_CTL_ALE, |
165 | data: instr->ctx.addr.addrs[i]); |
166 | if (ret) |
167 | break; |
168 | } |
169 | break; |
170 | |
171 | case NAND_OP_DATA_IN_INSTR: |
172 | cs553x_data_in(cs553x, buf: instr->ctx.data.buf.in, |
173 | len: instr->ctx.data.len); |
174 | break; |
175 | |
176 | case NAND_OP_DATA_OUT_INSTR: |
177 | cs553x_data_out(cs553x, buf: instr->ctx.data.buf.out, |
178 | len: instr->ctx.data.len); |
179 | break; |
180 | |
181 | case NAND_OP_WAITRDY_INSTR: |
182 | ret = cs553x_wait_ready(cs553x, timeout_ms: instr->ctx.waitrdy.timeout_ms); |
183 | break; |
184 | } |
185 | |
186 | if (instr->delay_ns) |
187 | ndelay(instr->delay_ns); |
188 | |
189 | return ret; |
190 | } |
191 | |
192 | static int cs553x_exec_op(struct nand_chip *this, |
193 | const struct nand_operation *op, |
194 | bool check_only) |
195 | { |
196 | struct cs553x_nand_controller *cs553x = to_cs553x(controller: this->controller); |
197 | unsigned int i; |
198 | int ret; |
199 | |
200 | if (check_only) |
201 | return true; |
202 | |
203 | /* De-assert the CE pin */ |
204 | writeb(val: 0, addr: cs553x->mmio + MM_NAND_CTL); |
205 | for (i = 0; i < op->ninstrs; i++) { |
206 | ret = cs553x_exec_instr(cs553x, instr: &op->instrs[i]); |
207 | if (ret) |
208 | break; |
209 | } |
210 | |
211 | /* Re-assert the CE pin. */ |
212 | writeb(CS_NAND_CTL_CE, addr: cs553x->mmio + MM_NAND_CTL); |
213 | |
214 | return ret; |
215 | } |
216 | |
217 | static void cs_enable_hwecc(struct nand_chip *this, int mode) |
218 | { |
219 | struct cs553x_nand_controller *cs553x = to_cs553x(controller: this->controller); |
220 | |
221 | writeb(val: 0x07, addr: cs553x->mmio + MM_NAND_ECC_CTL); |
222 | } |
223 | |
224 | static int cs_calculate_ecc(struct nand_chip *this, const u_char *dat, |
225 | u_char *ecc_code) |
226 | { |
227 | struct cs553x_nand_controller *cs553x = to_cs553x(controller: this->controller); |
228 | uint32_t ecc; |
229 | |
230 | ecc = readl(addr: cs553x->mmio + MM_NAND_STS); |
231 | |
232 | ecc_code[1] = ecc >> 8; |
233 | ecc_code[0] = ecc >> 16; |
234 | ecc_code[2] = ecc >> 24; |
235 | return 0; |
236 | } |
237 | |
238 | static struct cs553x_nand_controller *controllers[4]; |
239 | |
240 | static int cs553x_attach_chip(struct nand_chip *chip) |
241 | { |
242 | if (chip->ecc.engine_type != NAND_ECC_ENGINE_TYPE_ON_HOST) |
243 | return 0; |
244 | |
245 | chip->ecc.size = 256; |
246 | chip->ecc.bytes = 3; |
247 | chip->ecc.hwctl = cs_enable_hwecc; |
248 | chip->ecc.calculate = cs_calculate_ecc; |
249 | chip->ecc.correct = rawnand_sw_hamming_correct; |
250 | chip->ecc.strength = 1; |
251 | |
252 | return 0; |
253 | } |
254 | |
255 | static const struct nand_controller_ops cs553x_nand_controller_ops = { |
256 | .exec_op = cs553x_exec_op, |
257 | .attach_chip = cs553x_attach_chip, |
258 | }; |
259 | |
260 | static int __init cs553x_init_one(int cs, int mmio, unsigned long adr) |
261 | { |
262 | struct cs553x_nand_controller *controller; |
263 | int err = 0; |
264 | struct nand_chip *this; |
265 | struct mtd_info *new_mtd; |
266 | |
267 | pr_notice("Probing CS553x NAND controller CS#%d at %sIO 0x%08lx\n" , |
268 | cs, mmio ? "MM" : "P" , adr); |
269 | |
270 | if (!mmio) { |
271 | pr_notice("PIO mode not yet implemented for CS553X NAND controller\n" ); |
272 | return -ENXIO; |
273 | } |
274 | |
275 | /* Allocate memory for MTD device structure and private data */ |
276 | controller = kzalloc(size: sizeof(*controller), GFP_KERNEL); |
277 | if (!controller) { |
278 | err = -ENOMEM; |
279 | goto out; |
280 | } |
281 | |
282 | this = &controller->chip; |
283 | nand_controller_init(nfc: &controller->base); |
284 | controller->base.ops = &cs553x_nand_controller_ops; |
285 | this->controller = &controller->base; |
286 | new_mtd = nand_to_mtd(chip: this); |
287 | |
288 | /* Link the private data with the MTD structure */ |
289 | new_mtd->owner = THIS_MODULE; |
290 | |
291 | /* map physical address */ |
292 | controller->mmio = ioremap(offset: adr, size: 4096); |
293 | if (!controller->mmio) { |
294 | pr_warn("ioremap cs553x NAND @0x%08lx failed\n" , adr); |
295 | err = -EIO; |
296 | goto out_mtd; |
297 | } |
298 | |
299 | /* Enable the following for a flash based bad block table */ |
300 | this->bbt_options = NAND_BBT_USE_FLASH; |
301 | |
302 | new_mtd->name = kasprintf(GFP_KERNEL, fmt: "cs553x_nand_cs%d" , cs); |
303 | if (!new_mtd->name) { |
304 | err = -ENOMEM; |
305 | goto out_ior; |
306 | } |
307 | |
308 | /* Scan to find existence of the device */ |
309 | err = nand_scan(chip: this, max_chips: 1); |
310 | if (err) |
311 | goto out_free; |
312 | |
313 | controllers[cs] = controller; |
314 | goto out; |
315 | |
316 | out_free: |
317 | kfree(objp: new_mtd->name); |
318 | out_ior: |
319 | iounmap(addr: controller->mmio); |
320 | out_mtd: |
321 | kfree(objp: controller); |
322 | out: |
323 | return err; |
324 | } |
325 | |
326 | static int is_geode(void) |
327 | { |
328 | /* These are the CPUs which will have a CS553[56] companion chip */ |
329 | if (boot_cpu_data.x86_vendor == X86_VENDOR_AMD && |
330 | boot_cpu_data.x86 == 5 && |
331 | boot_cpu_data.x86_model == 10) |
332 | return 1; /* Geode LX */ |
333 | |
334 | if ((boot_cpu_data.x86_vendor == X86_VENDOR_NSC || |
335 | boot_cpu_data.x86_vendor == X86_VENDOR_CYRIX) && |
336 | boot_cpu_data.x86 == 5 && |
337 | boot_cpu_data.x86_model == 5) |
338 | return 1; /* Geode GX (née GX2) */ |
339 | |
340 | return 0; |
341 | } |
342 | |
343 | static int __init cs553x_init(void) |
344 | { |
345 | int err = -ENXIO; |
346 | int i; |
347 | uint64_t val; |
348 | |
349 | /* If the CPU isn't a Geode GX or LX, abort */ |
350 | if (!is_geode()) |
351 | return -ENXIO; |
352 | |
353 | /* If it doesn't have the CS553[56], abort */ |
354 | rdmsrl(MSR_DIVIL_GLD_CAP, val); |
355 | val &= ~0xFFULL; |
356 | if (val != CAP_CS5535 && val != CAP_CS5536) |
357 | return -ENXIO; |
358 | |
359 | /* If it doesn't have the NAND controller enabled, abort */ |
360 | rdmsrl(MSR_DIVIL_BALL_OPTS, val); |
361 | if (val & PIN_OPT_IDE) { |
362 | pr_info("CS553x NAND controller: Flash I/O not enabled in MSR_DIVIL_BALL_OPTS.\n" ); |
363 | return -ENXIO; |
364 | } |
365 | |
366 | for (i = 0; i < NR_CS553X_CONTROLLERS; i++) { |
367 | rdmsrl(MSR_DIVIL_LBAR_FLSH0 + i, val); |
368 | |
369 | if ((val & (FLSH_LBAR_EN|FLSH_NOR_NAND)) == (FLSH_LBAR_EN|FLSH_NOR_NAND)) |
370 | err = cs553x_init_one(cs: i, mmio: !!(val & FLSH_MEM_IO), adr: val & 0xFFFFFFFF); |
371 | } |
372 | |
373 | /* Register all devices together here. This means we can easily hack it to |
374 | do mtdconcat etc. if we want to. */ |
375 | for (i = 0; i < NR_CS553X_CONTROLLERS; i++) { |
376 | if (controllers[i]) { |
377 | /* If any devices registered, return success. Else the last error. */ |
378 | mtd_device_register(nand_to_mtd(&controllers[i]->chip), |
379 | NULL, 0); |
380 | err = 0; |
381 | } |
382 | } |
383 | |
384 | return err; |
385 | } |
386 | |
387 | module_init(cs553x_init); |
388 | |
389 | static void __exit cs553x_cleanup(void) |
390 | { |
391 | int i; |
392 | |
393 | for (i = 0; i < NR_CS553X_CONTROLLERS; i++) { |
394 | struct cs553x_nand_controller *controller = controllers[i]; |
395 | struct nand_chip *this = &controller->chip; |
396 | struct mtd_info *mtd = nand_to_mtd(chip: this); |
397 | int ret; |
398 | |
399 | if (!mtd) |
400 | continue; |
401 | |
402 | /* Release resources, unregister device */ |
403 | ret = mtd_device_unregister(master: mtd); |
404 | WARN_ON(ret); |
405 | nand_cleanup(chip: this); |
406 | kfree(objp: mtd->name); |
407 | controllers[i] = NULL; |
408 | |
409 | /* unmap physical address */ |
410 | iounmap(addr: controller->mmio); |
411 | |
412 | /* Free the MTD device structure */ |
413 | kfree(objp: controller); |
414 | } |
415 | } |
416 | |
417 | module_exit(cs553x_cleanup); |
418 | |
419 | MODULE_LICENSE("GPL" ); |
420 | MODULE_AUTHOR("David Woodhouse <dwmw2@infradead.org>" ); |
421 | MODULE_DESCRIPTION("NAND controller driver for AMD CS5535/CS5536 companion chip" ); |
422 | |