1 /*-
2 * SPDX-License-Identifier: BSD-2-Clause-FreeBSD
3 *
4 * Copyright (C) 2009-2012 Semihalf
5 * All rights reserved.
6 *
7 * Redistribution and use in source and binary forms, with or without
8 * modification, are permitted provided that the following conditions
9 * are met:
10 * 1. Redistributions of source code must retain the above copyright
11 * notice, this list of conditions and the following disclaimer.
12 * 2. Redistributions in binary form must reproduce the above copyright
13 * notice, this list of conditions and the following disclaimer in the
14 * documentation and/or other materials provided with the distribution.
15 *
16 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
17 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
18 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
19 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
20 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
21 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
22 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
23 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
24 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
25 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
26 * SUCH DAMAGE.
27 */
28
29 #include <sys/cdefs.h>
30 __FBSDID("$FreeBSD$");
31
32 #include <sys/param.h>
33 #include <sys/systm.h>
34 #include <sys/conf.h>
35 #include <sys/bus.h>
36 #include <sys/malloc.h>
37 #include <sys/uio.h>
38 #include <sys/bio.h>
39
40 #include <dev/nand/nand.h>
41 #include <dev/nand/nandbus.h>
42 #include <dev/nand/nand_dev.h>
43 #include "nand_if.h"
44 #include "nandbus_if.h"
45
46 static int nand_page_stat(struct nand_chip *, struct page_stat_io *);
47 static int nand_block_stat(struct nand_chip *, struct block_stat_io *);
48
49 static d_ioctl_t nand_ioctl;
50 static d_open_t nand_open;
51 static d_strategy_t nand_strategy;
52
53 static struct cdevsw nand_cdevsw = {
54 .d_version = D_VERSION,
55 .d_name = "nand",
56 .d_open = nand_open,
57 .d_read = physread,
58 .d_write = physwrite,
59 .d_ioctl = nand_ioctl,
60 .d_strategy = nand_strategy,
61 };
62
63 static int
offset_to_page(struct chip_geom * cg,uint32_t offset)64 offset_to_page(struct chip_geom *cg, uint32_t offset)
65 {
66
67 return (offset / cg->page_size);
68 }
69
70 static int
offset_to_page_off(struct chip_geom * cg,uint32_t offset)71 offset_to_page_off(struct chip_geom *cg, uint32_t offset)
72 {
73
74 return (offset % cg->page_size);
75 }
76
77 int
nand_make_dev(struct nand_chip * chip)78 nand_make_dev(struct nand_chip *chip)
79 {
80 struct nandbus_ivar *ivar;
81 device_t parent, nandbus;
82 int parent_unit, unit;
83 char *name;
84
85 ivar = device_get_ivars(chip->dev);
86 nandbus = device_get_parent(chip->dev);
87
88 if (ivar->chip_cdev_name) {
89 name = ivar->chip_cdev_name;
90
91 /*
92 * If we got distinct name for chip device we can enumarete it
93 * based on contoller number.
94 */
95 parent = device_get_parent(nandbus);
96 } else {
97 name = "nand";
98 parent = nandbus;
99 }
100
101 parent_unit = device_get_unit(parent);
102 unit = parent_unit * 4 + chip->num;
103 chip->cdev = make_dev(&nand_cdevsw, unit, UID_ROOT, GID_WHEEL,
104 0640, "%s%d.%d", name, parent_unit, chip->num);
105
106 if (chip->cdev == NULL)
107 return (ENXIO);
108
109 if (bootverbose)
110 device_printf(chip->dev, "Created cdev %s%d.%d for chip "
111 "[0x%0x, 0x%0x]\n", name, parent_unit, chip->num,
112 ivar->man_id, ivar->dev_id);
113
114 chip->cdev->si_drv1 = chip;
115
116 return (0);
117 }
118
119 void
nand_destroy_dev(struct nand_chip * chip)120 nand_destroy_dev(struct nand_chip *chip)
121 {
122
123 if (chip->cdev)
124 destroy_dev(chip->cdev);
125 }
126
127 static int
nand_open(struct cdev * dev,int oflags,int devtype,struct thread * td)128 nand_open(struct cdev *dev, int oflags, int devtype, struct thread *td)
129 {
130
131 return (0);
132 }
133
134 static int
nand_read(struct nand_chip * chip,uint32_t offset,void * buf,uint32_t len)135 nand_read(struct nand_chip *chip, uint32_t offset, void *buf, uint32_t len)
136 {
137 struct chip_geom *cg;
138 device_t nandbus;
139 int start_page, count, off, err = 0;
140 uint8_t *ptr, *tmp;
141
142 nand_debug(NDBG_CDEV, "Read from chip%d [%p] at %d\n", chip->num,
143 chip, offset);
144
145 nandbus = device_get_parent(chip->dev);
146 NANDBUS_LOCK(nandbus);
147 NANDBUS_SELECT_CS(device_get_parent(chip->dev), chip->num);
148
149 cg = &chip->chip_geom;
150 start_page = offset_to_page(cg, offset);
151 off = offset_to_page_off(cg, offset);
152 count = (len > cg->page_size - off) ? cg->page_size - off : len;
153
154 ptr = (uint8_t *)buf;
155 while (len > 0) {
156 if (len < cg->page_size) {
157 tmp = malloc(cg->page_size, M_NAND, M_WAITOK);
158 if (!tmp) {
159 err = ENOMEM;
160 break;
161 }
162 err = NAND_READ_PAGE(chip->dev, start_page,
163 tmp, cg->page_size, 0);
164 if (err) {
165 free(tmp, M_NAND);
166 break;
167 }
168 bcopy(tmp + off, ptr, count);
169 free(tmp, M_NAND);
170 } else {
171 err = NAND_READ_PAGE(chip->dev, start_page,
172 ptr, cg->page_size, 0);
173 if (err)
174 break;
175 }
176
177 len -= count;
178 start_page++;
179 ptr += count;
180 count = (len > cg->page_size) ? cg->page_size : len;
181 off = 0;
182 }
183
184 NANDBUS_UNLOCK(nandbus);
185 return (err);
186 }
187
188 static int
nand_write(struct nand_chip * chip,uint32_t offset,void * buf,uint32_t len)189 nand_write(struct nand_chip *chip, uint32_t offset, void* buf, uint32_t len)
190 {
191 struct chip_geom *cg;
192 device_t nandbus;
193 int off, start_page, err = 0;
194 uint8_t *ptr;
195
196 nand_debug(NDBG_CDEV, "Write to chip %d [%p] at %d\n", chip->num,
197 chip, offset);
198
199 nandbus = device_get_parent(chip->dev);
200 NANDBUS_LOCK(nandbus);
201 NANDBUS_SELECT_CS(device_get_parent(chip->dev), chip->num);
202
203 cg = &chip->chip_geom;
204 start_page = offset_to_page(cg, offset);
205 off = offset_to_page_off(cg, offset);
206
207 if (off != 0 || (len % cg->page_size) != 0) {
208 printf("Not aligned write start [0x%08x] size [0x%08x]\n",
209 off, len);
210 NANDBUS_UNLOCK(nandbus);
211 return (EINVAL);
212 }
213
214 ptr = (uint8_t *)buf;
215 while (len > 0) {
216 err = NAND_PROGRAM_PAGE(chip->dev, start_page, ptr,
217 cg->page_size, 0);
218 if (err)
219 break;
220
221 len -= cg->page_size;
222 start_page++;
223 ptr += cg->page_size;
224 }
225
226 NANDBUS_UNLOCK(nandbus);
227 return (err);
228 }
229
230 static void
nand_strategy(struct bio * bp)231 nand_strategy(struct bio *bp)
232 {
233 struct nand_chip *chip;
234 struct cdev *dev;
235 int err = 0;
236
237 dev = bp->bio_dev;
238 chip = dev->si_drv1;
239
240 nand_debug(NDBG_CDEV, "Strategy %s on chip %d [%p]\n",
241 bp->bio_cmd == BIO_READ ? "READ" : "WRITE",
242 chip->num, chip);
243
244 if (bp->bio_cmd == BIO_READ) {
245 err = nand_read(chip,
246 bp->bio_offset & 0xffffffff,
247 bp->bio_data, bp->bio_bcount);
248 } else {
249 err = nand_write(chip,
250 bp->bio_offset & 0xffffffff,
251 bp->bio_data, bp->bio_bcount);
252 }
253
254 if (err == 0)
255 bp->bio_resid = 0;
256 else {
257 bp->bio_error = EIO;
258 bp->bio_flags |= BIO_ERROR;
259 bp->bio_resid = bp->bio_bcount;
260 }
261
262 biodone(bp);
263 }
264
265 static int
nand_oob_access(struct nand_chip * chip,uint32_t page,uint32_t offset,uint32_t len,uint8_t * data,uint8_t write)266 nand_oob_access(struct nand_chip *chip, uint32_t page, uint32_t offset,
267 uint32_t len, uint8_t *data, uint8_t write)
268 {
269 struct chip_geom *cg;
270 uint8_t *buf = NULL;
271 int ret = 0;
272
273 cg = &chip->chip_geom;
274
275 buf = malloc(cg->oob_size, M_NAND, M_WAITOK);
276 if (!buf)
277 return (ENOMEM);
278
279 memset(buf, 0xff, cg->oob_size);
280
281 if (!write) {
282 ret = nand_read_oob(chip, page, buf, cg->oob_size);
283 copyout(buf, data, len);
284 } else {
285 copyin(data, buf, len);
286 ret = nand_prog_oob(chip, page, buf, cg->oob_size);
287 }
288
289 free(buf, M_NAND);
290
291 return (ret);
292 }
293
294 static int
nand_ioctl(struct cdev * dev,u_long cmd,caddr_t data,int fflag,struct thread * td)295 nand_ioctl(struct cdev *dev, u_long cmd, caddr_t data, int fflag,
296 struct thread *td)
297 {
298 struct nand_chip *chip;
299 struct chip_geom *cg;
300 struct nand_oob_rw *oob_rw = NULL;
301 struct nand_raw_rw *raw_rw = NULL;
302 device_t nandbus;
303 size_t bufsize = 0, len = 0;
304 size_t raw_size;
305 off_t off;
306 uint8_t *buf = NULL;
307 int ret = 0;
308 uint8_t status;
309
310 chip = (struct nand_chip *)dev->si_drv1;
311 cg = &chip->chip_geom;
312 nandbus = device_get_parent(chip->dev);
313
314 if ((cmd == NAND_IO_RAW_READ) || (cmd == NAND_IO_RAW_PROG)) {
315 raw_rw = (struct nand_raw_rw *)data;
316 raw_size = cg->pgs_per_blk * (cg->page_size + cg->oob_size);
317
318 /* Check if len is not bigger than chip size */
319 if (raw_rw->len > raw_size)
320 return (EFBIG);
321
322 /*
323 * Do not ask for too much memory, in case of large transfers
324 * read/write in 16-pages chunks
325 */
326 bufsize = 16 * (cg->page_size + cg->oob_size);
327 if (raw_rw->len < bufsize)
328 bufsize = raw_rw->len;
329
330 buf = malloc(bufsize, M_NAND, M_WAITOK);
331 len = raw_rw->len;
332 off = 0;
333 }
334 switch(cmd) {
335 case NAND_IO_ERASE:
336 ret = nand_erase_blocks(chip, ((off_t *)data)[0],
337 ((off_t *)data)[1]);
338 break;
339
340 case NAND_IO_OOB_READ:
341 oob_rw = (struct nand_oob_rw *)data;
342 ret = nand_oob_access(chip, oob_rw->page, 0,
343 oob_rw->len, oob_rw->data, 0);
344 break;
345
346 case NAND_IO_OOB_PROG:
347 oob_rw = (struct nand_oob_rw *)data;
348 ret = nand_oob_access(chip, oob_rw->page, 0,
349 oob_rw->len, oob_rw->data, 1);
350 break;
351
352 case NAND_IO_GET_STATUS:
353 NANDBUS_LOCK(nandbus);
354 ret = NANDBUS_GET_STATUS(nandbus, &status);
355 if (ret == 0)
356 *(uint8_t *)data = status;
357 NANDBUS_UNLOCK(nandbus);
358 break;
359
360 case NAND_IO_RAW_PROG:
361 while (len > 0) {
362 if (len < bufsize)
363 bufsize = len;
364 ret = copyin(raw_rw->data + off, buf, bufsize);
365 if (ret)
366 break;
367 ret = nand_prog_pages_raw(chip, raw_rw->off + off, buf,
368 bufsize);
369 if (ret)
370 break;
371 len -= bufsize;
372 off += bufsize;
373 }
374 break;
375
376 case NAND_IO_RAW_READ:
377 while (len > 0) {
378 if (len < bufsize)
379 bufsize = len;
380
381 ret = nand_read_pages_raw(chip, raw_rw->off + off, buf,
382 bufsize);
383 if (ret)
384 break;
385
386 ret = copyout(buf, raw_rw->data + off, bufsize);
387 if (ret)
388 break;
389 len -= bufsize;
390 off += bufsize;
391 }
392 break;
393
394 case NAND_IO_PAGE_STAT:
395 ret = nand_page_stat(chip, (struct page_stat_io *)data);
396 break;
397
398 case NAND_IO_BLOCK_STAT:
399 ret = nand_block_stat(chip, (struct block_stat_io *)data);
400 break;
401
402 case NAND_IO_GET_CHIP_PARAM:
403 nand_get_chip_param(chip, (struct chip_param_io *)data);
404 break;
405
406 default:
407 printf("Unknown nand_ioctl request \n");
408 ret = EIO;
409 }
410
411 if (buf)
412 free(buf, M_NAND);
413
414 return (ret);
415 }
416
417 static int
nand_page_stat(struct nand_chip * chip,struct page_stat_io * page_stat)418 nand_page_stat(struct nand_chip *chip, struct page_stat_io *page_stat)
419 {
420 struct chip_geom *cg;
421 struct page_stat *stat;
422 int num_pages;
423
424 cg = &chip->chip_geom;
425 num_pages = cg->pgs_per_blk * cg->blks_per_lun * cg->luns;
426 if (page_stat->page_num >= num_pages)
427 return (EINVAL);
428
429 stat = &chip->pg_stat[page_stat->page_num];
430 page_stat->page_read = stat->page_read;
431 page_stat->page_written = stat->page_written;
432 page_stat->page_raw_read = stat->page_raw_read;
433 page_stat->page_raw_written = stat->page_raw_written;
434 page_stat->ecc_succeded = stat->ecc_stat.ecc_succeded;
435 page_stat->ecc_corrected = stat->ecc_stat.ecc_corrected;
436 page_stat->ecc_failed = stat->ecc_stat.ecc_failed;
437
438 return (0);
439 }
440
441 static int
nand_block_stat(struct nand_chip * chip,struct block_stat_io * block_stat)442 nand_block_stat(struct nand_chip *chip, struct block_stat_io *block_stat)
443 {
444 struct chip_geom *cg;
445 uint32_t block_num = block_stat->block_num;
446
447 cg = &chip->chip_geom;
448 if (block_num >= cg->blks_per_lun * cg->luns)
449 return (EINVAL);
450
451 block_stat->block_erased = chip->blk_stat[block_num].block_erased;
452
453 return (0);
454 }
455