hc
2024-05-10 23fa18eaa71266feff7ba8d83022d9e1cc83c65a
kernel/drivers/mtd/nand/raw/cs553x_nand.c
....@@ -1,19 +1,15 @@
1
+// SPDX-License-Identifier: GPL-2.0-only
12 /*
23 * (C) 2005, 2006 Red Hat Inc.
34 *
45 * Author: David Woodhouse <dwmw2@infradead.org>
56 * Tom Sylla <tom.sylla@amd.com>
67 *
7
- * This program is free software; you can redistribute it and/or modify
8
- * it under the terms of the GNU General Public License version 2 as
9
- * published by the Free Software Foundation.
10
- *
118 * Overview:
129 * This is a device driver for the NAND flash controller found on
1310 * the AMD CS5535/CS5536 companion chipsets for the Geode processor.
1411 * mtd-id for command line partitioning is cs553x_nand_cs[0-3]
1512 * where 0-3 reflects the chip select for NAND.
16
- *
1713 */
1814
1915 #include <linux/kernel.h>
....@@ -25,9 +21,9 @@
2521 #include <linux/mtd/rawnand.h>
2622 #include <linux/mtd/nand_ecc.h>
2723 #include <linux/mtd/partitions.h>
24
+#include <linux/iopoll.h>
2825
2926 #include <asm/msr.h>
30
-#include <asm/io.h>
3127
3228 #define NR_CS553X_CONTROLLERS 4
3329
....@@ -93,85 +89,151 @@
9389 #define CS_NAND_ECC_CLRECC (1<<1)
9490 #define CS_NAND_ECC_ENECC (1<<0)
9591
96
-static void cs553x_read_buf(struct mtd_info *mtd, u_char *buf, int len)
97
-{
98
- struct nand_chip *this = mtd_to_nand(mtd);
92
+struct cs553x_nand_controller {
93
+ struct nand_controller base;
94
+ struct nand_chip chip;
95
+ void __iomem *mmio;
96
+};
9997
98
+static struct cs553x_nand_controller *
99
+to_cs553x(struct nand_controller *controller)
100
+{
101
+ return container_of(controller, struct cs553x_nand_controller, base);
102
+}
103
+
104
+static int cs553x_write_ctrl_byte(struct cs553x_nand_controller *cs553x,
105
+ u32 ctl, u8 data)
106
+{
107
+ u8 status;
108
+ int ret;
109
+
110
+ writeb(ctl, cs553x->mmio + MM_NAND_CTL);
111
+ writeb(data, cs553x->mmio + MM_NAND_IO);
112
+ ret = readb_poll_timeout_atomic(cs553x->mmio + MM_NAND_STS, status,
113
+ !(status & CS_NAND_CTLR_BUSY), 1,
114
+ 100000);
115
+ if (ret)
116
+ return ret;
117
+
118
+ return 0;
119
+}
120
+
121
+static void cs553x_data_in(struct cs553x_nand_controller *cs553x, void *buf,
122
+ unsigned int len)
123
+{
124
+ writeb(0, cs553x->mmio + MM_NAND_CTL);
100125 while (unlikely(len > 0x800)) {
101
- memcpy_fromio(buf, this->IO_ADDR_R, 0x800);
126
+ memcpy_fromio(buf, cs553x->mmio, 0x800);
102127 buf += 0x800;
103128 len -= 0x800;
104129 }
105
- memcpy_fromio(buf, this->IO_ADDR_R, len);
130
+ memcpy_fromio(buf, cs553x->mmio, len);
106131 }
107132
108
-static void cs553x_write_buf(struct mtd_info *mtd, const u_char *buf, int len)
133
+static void cs553x_data_out(struct cs553x_nand_controller *cs553x,
134
+ const void *buf, unsigned int len)
109135 {
110
- struct nand_chip *this = mtd_to_nand(mtd);
111
-
136
+ writeb(0, cs553x->mmio + MM_NAND_CTL);
112137 while (unlikely(len > 0x800)) {
113
- memcpy_toio(this->IO_ADDR_R, buf, 0x800);
138
+ memcpy_toio(cs553x->mmio, buf, 0x800);
114139 buf += 0x800;
115140 len -= 0x800;
116141 }
117
- memcpy_toio(this->IO_ADDR_R, buf, len);
142
+ memcpy_toio(cs553x->mmio, buf, len);
118143 }
119144
120
-static unsigned char cs553x_read_byte(struct mtd_info *mtd)
145
+static int cs553x_wait_ready(struct cs553x_nand_controller *cs553x,
146
+ unsigned int timeout_ms)
121147 {
122
- struct nand_chip *this = mtd_to_nand(mtd);
123
- return readb(this->IO_ADDR_R);
148
+ u8 mask = CS_NAND_CTLR_BUSY | CS_NAND_STS_FLASH_RDY;
149
+ u8 status;
150
+
151
+ return readb_poll_timeout(cs553x->mmio + MM_NAND_STS, status,
152
+ (status & mask) == CS_NAND_STS_FLASH_RDY, 100,
153
+ timeout_ms * 1000);
124154 }
125155
126
-static void cs553x_write_byte(struct mtd_info *mtd, u_char byte)
156
+static int cs553x_exec_instr(struct cs553x_nand_controller *cs553x,
157
+ const struct nand_op_instr *instr)
127158 {
128
- struct nand_chip *this = mtd_to_nand(mtd);
129
- int i = 100000;
159
+ unsigned int i;
160
+ int ret = 0;
130161
131
- while (i && readb(this->IO_ADDR_R + MM_NAND_STS) & CS_NAND_CTLR_BUSY) {
132
- udelay(1);
133
- i--;
162
+ switch (instr->type) {
163
+ case NAND_OP_CMD_INSTR:
164
+ ret = cs553x_write_ctrl_byte(cs553x, CS_NAND_CTL_CLE,
165
+ instr->ctx.cmd.opcode);
166
+ break;
167
+
168
+ case NAND_OP_ADDR_INSTR:
169
+ for (i = 0; i < instr->ctx.addr.naddrs; i++) {
170
+ ret = cs553x_write_ctrl_byte(cs553x, CS_NAND_CTL_ALE,
171
+ instr->ctx.addr.addrs[i]);
172
+ if (ret)
173
+ break;
174
+ }
175
+ break;
176
+
177
+ case NAND_OP_DATA_IN_INSTR:
178
+ cs553x_data_in(cs553x, instr->ctx.data.buf.in,
179
+ instr->ctx.data.len);
180
+ break;
181
+
182
+ case NAND_OP_DATA_OUT_INSTR:
183
+ cs553x_data_out(cs553x, instr->ctx.data.buf.out,
184
+ instr->ctx.data.len);
185
+ break;
186
+
187
+ case NAND_OP_WAITRDY_INSTR:
188
+ ret = cs553x_wait_ready(cs553x, instr->ctx.waitrdy.timeout_ms);
189
+ break;
134190 }
135
- writeb(byte, this->IO_ADDR_W + 0x801);
191
+
192
+ if (instr->delay_ns)
193
+ ndelay(instr->delay_ns);
194
+
195
+ return ret;
136196 }
137197
138
-static void cs553x_hwcontrol(struct mtd_info *mtd, int cmd,
139
- unsigned int ctrl)
198
+static int cs553x_exec_op(struct nand_chip *this,
199
+ const struct nand_operation *op,
200
+ bool check_only)
140201 {
141
- struct nand_chip *this = mtd_to_nand(mtd);
142
- void __iomem *mmio_base = this->IO_ADDR_R;
143
- if (ctrl & NAND_CTRL_CHANGE) {
144
- unsigned char ctl = (ctrl & ~NAND_CTRL_CHANGE ) ^ 0x01;
145
- writeb(ctl, mmio_base + MM_NAND_CTL);
202
+ struct cs553x_nand_controller *cs553x = to_cs553x(this->controller);
203
+ unsigned int i;
204
+ int ret;
205
+
206
+ if (check_only)
207
+ return true;
208
+
209
+ /* De-assert the CE pin */
210
+ writeb(0, cs553x->mmio + MM_NAND_CTL);
211
+ for (i = 0; i < op->ninstrs; i++) {
212
+ ret = cs553x_exec_instr(cs553x, &op->instrs[i]);
213
+ if (ret)
214
+ break;
146215 }
147
- if (cmd != NAND_CMD_NONE)
148
- cs553x_write_byte(mtd, cmd);
216
+
217
+ /* Re-assert the CE pin. */
218
+ writeb(CS_NAND_CTL_CE, cs553x->mmio + MM_NAND_CTL);
219
+
220
+ return ret;
149221 }
150222
151
-static int cs553x_device_ready(struct mtd_info *mtd)
223
+static void cs_enable_hwecc(struct nand_chip *this, int mode)
152224 {
153
- struct nand_chip *this = mtd_to_nand(mtd);
154
- void __iomem *mmio_base = this->IO_ADDR_R;
155
- unsigned char foo = readb(mmio_base + MM_NAND_STS);
225
+ struct cs553x_nand_controller *cs553x = to_cs553x(this->controller);
156226
157
- return (foo & CS_NAND_STS_FLASH_RDY) && !(foo & CS_NAND_CTLR_BUSY);
227
+ writeb(0x07, cs553x->mmio + MM_NAND_ECC_CTL);
158228 }
159229
160
-static void cs_enable_hwecc(struct mtd_info *mtd, int mode)
230
+static int cs_calculate_ecc(struct nand_chip *this, const u_char *dat,
231
+ u_char *ecc_code)
161232 {
162
- struct nand_chip *this = mtd_to_nand(mtd);
163
- void __iomem *mmio_base = this->IO_ADDR_R;
164
-
165
- writeb(0x07, mmio_base + MM_NAND_ECC_CTL);
166
-}
167
-
168
-static int cs_calculate_ecc(struct mtd_info *mtd, const u_char *dat, u_char *ecc_code)
169
-{
233
+ struct cs553x_nand_controller *cs553x = to_cs553x(this->controller);
170234 uint32_t ecc;
171
- struct nand_chip *this = mtd_to_nand(mtd);
172
- void __iomem *mmio_base = this->IO_ADDR_R;
173235
174
- ecc = readl(mmio_base + MM_NAND_STS);
236
+ ecc = readl(cs553x->mmio + MM_NAND_STS);
175237
176238 ecc_code[1] = ecc >> 8;
177239 ecc_code[0] = ecc >> 16;
....@@ -179,10 +241,31 @@
179241 return 0;
180242 }
181243
182
-static struct mtd_info *cs553x_mtd[4];
244
+static struct cs553x_nand_controller *controllers[4];
245
+
246
+static int cs553x_attach_chip(struct nand_chip *chip)
247
+{
248
+ if (chip->ecc.engine_type != NAND_ECC_ENGINE_TYPE_ON_HOST)
249
+ return 0;
250
+
251
+ chip->ecc.size = 256;
252
+ chip->ecc.bytes = 3;
253
+ chip->ecc.hwctl = cs_enable_hwecc;
254
+ chip->ecc.calculate = cs_calculate_ecc;
255
+ chip->ecc.correct = nand_correct_data;
256
+ chip->ecc.strength = 1;
257
+
258
+ return 0;
259
+}
260
+
261
+static const struct nand_controller_ops cs553x_nand_controller_ops = {
262
+ .exec_op = cs553x_exec_op,
263
+ .attach_chip = cs553x_attach_chip,
264
+};
183265
184266 static int __init cs553x_init_one(int cs, int mmio, unsigned long adr)
185267 {
268
+ struct cs553x_nand_controller *controller;
186269 int err = 0;
187270 struct nand_chip *this;
188271 struct mtd_info *new_mtd;
....@@ -196,40 +279,28 @@
196279 }
197280
198281 /* Allocate memory for MTD device structure and private data */
199
- this = kzalloc(sizeof(struct nand_chip), GFP_KERNEL);
200
- if (!this) {
282
+ controller = kzalloc(sizeof(*controller), GFP_KERNEL);
283
+ if (!controller) {
201284 err = -ENOMEM;
202285 goto out;
203286 }
204287
288
+ this = &controller->chip;
289
+ nand_controller_init(&controller->base);
290
+ controller->base.ops = &cs553x_nand_controller_ops;
291
+ this->controller = &controller->base;
205292 new_mtd = nand_to_mtd(this);
206293
207294 /* Link the private data with the MTD structure */
208295 new_mtd->owner = THIS_MODULE;
209296
210297 /* map physical address */
211
- this->IO_ADDR_R = this->IO_ADDR_W = ioremap(adr, 4096);
212
- if (!this->IO_ADDR_R) {
298
+ controller->mmio = ioremap(adr, 4096);
299
+ if (!controller->mmio) {
213300 pr_warn("ioremap cs553x NAND @0x%08lx failed\n", adr);
214301 err = -EIO;
215302 goto out_mtd;
216303 }
217
-
218
- this->cmd_ctrl = cs553x_hwcontrol;
219
- this->dev_ready = cs553x_device_ready;
220
- this->read_byte = cs553x_read_byte;
221
- this->read_buf = cs553x_read_buf;
222
- this->write_buf = cs553x_write_buf;
223
-
224
- this->chip_delay = 0;
225
-
226
- this->ecc.mode = NAND_ECC_HW;
227
- this->ecc.size = 256;
228
- this->ecc.bytes = 3;
229
- this->ecc.hwctl = cs_enable_hwecc;
230
- this->ecc.calculate = cs_calculate_ecc;
231
- this->ecc.correct = nand_correct_data;
232
- this->ecc.strength = 1;
233304
234305 /* Enable the following for a flash based bad block table */
235306 this->bbt_options = NAND_BBT_USE_FLASH;
....@@ -245,15 +316,15 @@
245316 if (err)
246317 goto out_free;
247318
248
- cs553x_mtd[cs] = new_mtd;
319
+ controllers[cs] = controller;
249320 goto out;
250321
251322 out_free:
252323 kfree(new_mtd->name);
253324 out_ior:
254
- iounmap(this->IO_ADDR_R);
325
+ iounmap(controller->mmio);
255326 out_mtd:
256
- kfree(this);
327
+ kfree(controller);
257328 out:
258329 return err;
259330 }
....@@ -308,9 +379,10 @@
308379 /* Register all devices together here. This means we can easily hack it to
309380 do mtdconcat etc. if we want to. */
310381 for (i = 0; i < NR_CS553X_CONTROLLERS; i++) {
311
- if (cs553x_mtd[i]) {
382
+ if (controllers[i]) {
312383 /* If any devices registered, return success. Else the last error. */
313
- mtd_device_register(cs553x_mtd[i], NULL, 0);
384
+ mtd_device_register(nand_to_mtd(&controllers[i]->chip),
385
+ NULL, 0);
314386 err = 0;
315387 }
316388 }
....@@ -325,26 +397,26 @@
325397 int i;
326398
327399 for (i = 0; i < NR_CS553X_CONTROLLERS; i++) {
328
- struct mtd_info *mtd = cs553x_mtd[i];
329
- struct nand_chip *this;
330
- void __iomem *mmio_base;
400
+ struct cs553x_nand_controller *controller = controllers[i];
401
+ struct nand_chip *this = &controller->chip;
402
+ struct mtd_info *mtd = nand_to_mtd(this);
403
+ int ret;
331404
332405 if (!mtd)
333406 continue;
334407
335
- this = mtd_to_nand(mtd);
336
- mmio_base = this->IO_ADDR_R;
337
-
338408 /* Release resources, unregister device */
339
- nand_release(this);
409
+ ret = mtd_device_unregister(mtd);
410
+ WARN_ON(ret);
411
+ nand_cleanup(this);
340412 kfree(mtd->name);
341
- cs553x_mtd[i] = NULL;
413
+ controllers[i] = NULL;
342414
343415 /* unmap physical address */
344
- iounmap(mmio_base);
416
+ iounmap(controller->mmio);
345417
346418 /* Free the MTD device structure */
347
- kfree(this);
419
+ kfree(controller);
348420 }
349421 }
350422