Linux Audio

Check our new training course

Buildroot integration, development and maintenance

Need a Buildroot system for your embedded project?
Loading...
v6.8
  1// SPDX-License-Identifier: GPL-2.0+
  2/*
  3 * Generic Error-Correcting Code (ECC) engine
  4 *
  5 * Copyright (C) 2019 Macronix
  6 * Author:
  7 *     Miquèl RAYNAL <miquel.raynal@bootlin.com>
  8 *
  9 *
 10 * This file describes the abstraction of any NAND ECC engine. It has been
 11 * designed to fit most cases, including parallel NANDs and SPI-NANDs.
 12 *
 13 * There are three main situations where instantiating this ECC engine makes
 14 * sense:
 15 *   - external: The ECC engine is outside the NAND pipeline, typically this
 16 *               is a software ECC engine, or an hardware engine that is
 17 *               outside the NAND controller pipeline.
 18 *   - pipelined: The ECC engine is inside the NAND pipeline, ie. on the
 19 *                controller's side. This is the case of most of the raw NAND
 20 *                controllers. In the pipeline case, the ECC bytes are
 21 *                generated/data corrected on the fly when a page is
 22 *                written/read.
 23 *   - ondie: The ECC engine is inside the NAND pipeline, on the chip's side.
 24 *            Some NAND chips can correct themselves the data.
 25 *
 26 * Besides the initial setup and final cleanups, the interfaces are rather
 27 * simple:
 28 *   - prepare: Prepare an I/O request. Enable/disable the ECC engine based on
 29 *              the I/O request type. In case of software correction or external
 30 *              engine, this step may involve to derive the ECC bytes and place
 31 *              them in the OOB area before a write.
 32 *   - finish: Finish an I/O request. Correct the data in case of a read
 33 *             request and report the number of corrected bits/uncorrectable
 34 *             errors. Most likely empty for write operations, unless you have
 35 *             hardware specific stuff to do, like shutting down the engine to
 36 *             save power.
 37 *
 38 * The I/O request should be enclosed in a prepare()/finish() pair of calls
 39 * and will behave differently depending on the requested I/O type:
 40 *   - raw: Correction disabled
 41 *   - ecc: Correction enabled
 42 *
 43 * The request direction is impacting the logic as well:
 44 *   - read: Load data from the NAND chip
 45 *   - write: Store data in the NAND chip
 46 *
 47 * Mixing all this combinations together gives the following behavior.
 48 * Those are just examples, drivers are free to add custom steps in their
 49 * prepare/finish hook.
 50 *
 51 * [external ECC engine]
 52 *   - external + prepare + raw + read: do nothing
 53 *   - external + finish  + raw + read: do nothing
 54 *   - external + prepare + raw + write: do nothing
 55 *   - external + finish  + raw + write: do nothing
 56 *   - external + prepare + ecc + read: do nothing
 57 *   - external + finish  + ecc + read: calculate expected ECC bytes, extract
 58 *                                      ECC bytes from OOB buffer, correct
 59 *                                      and report any bitflip/error
 60 *   - external + prepare + ecc + write: calculate ECC bytes and store them at
 61 *                                       the right place in the OOB buffer based
 62 *                                       on the OOB layout
 63 *   - external + finish  + ecc + write: do nothing
 64 *
 65 * [pipelined ECC engine]
 66 *   - pipelined + prepare + raw + read: disable the controller's ECC engine if
 67 *                                       activated
 68 *   - pipelined + finish  + raw + read: do nothing
 69 *   - pipelined + prepare + raw + write: disable the controller's ECC engine if
 70 *                                        activated
 71 *   - pipelined + finish  + raw + write: do nothing
 72 *   - pipelined + prepare + ecc + read: enable the controller's ECC engine if
 73 *                                       deactivated
 74 *   - pipelined + finish  + ecc + read: check the status, report any
 75 *                                       error/bitflip
 76 *   - pipelined + prepare + ecc + write: enable the controller's ECC engine if
 77 *                                        deactivated
 78 *   - pipelined + finish  + ecc + write: do nothing
 79 *
 80 * [ondie ECC engine]
 81 *   - ondie + prepare + raw + read: send commands to disable the on-chip ECC
 82 *                                   engine if activated
 83 *   - ondie + finish  + raw + read: do nothing
 84 *   - ondie + prepare + raw + write: send commands to disable the on-chip ECC
 85 *                                    engine if activated
 86 *   - ondie + finish  + raw + write: do nothing
 87 *   - ondie + prepare + ecc + read: send commands to enable the on-chip ECC
 88 *                                   engine if deactivated
 89 *   - ondie + finish  + ecc + read: send commands to check the status, report
 90 *                                   any error/bitflip
 91 *   - ondie + prepare + ecc + write: send commands to enable the on-chip ECC
 92 *                                    engine if deactivated
 93 *   - ondie + finish  + ecc + write: do nothing
 94 */
 95
 96#include <linux/module.h>
 97#include <linux/mtd/nand.h>
 98#include <linux/platform_device.h>
 99#include <linux/slab.h>
100#include <linux/of.h>
 
101#include <linux/of_platform.h>
102
103static LIST_HEAD(on_host_hw_engines);
104static DEFINE_MUTEX(on_host_hw_engines_mutex);
105
106/**
107 * nand_ecc_init_ctx - Init the ECC engine context
108 * @nand: the NAND device
109 *
110 * On success, the caller is responsible of calling @nand_ecc_cleanup_ctx().
111 */
112int nand_ecc_init_ctx(struct nand_device *nand)
113{
114	if (!nand->ecc.engine || !nand->ecc.engine->ops->init_ctx)
115		return 0;
116
117	return nand->ecc.engine->ops->init_ctx(nand);
118}
119EXPORT_SYMBOL(nand_ecc_init_ctx);
120
121/**
122 * nand_ecc_cleanup_ctx - Cleanup the ECC engine context
123 * @nand: the NAND device
124 */
125void nand_ecc_cleanup_ctx(struct nand_device *nand)
126{
127	if (nand->ecc.engine && nand->ecc.engine->ops->cleanup_ctx)
128		nand->ecc.engine->ops->cleanup_ctx(nand);
129}
130EXPORT_SYMBOL(nand_ecc_cleanup_ctx);
131
132/**
133 * nand_ecc_prepare_io_req - Prepare an I/O request
134 * @nand: the NAND device
135 * @req: the I/O request
136 */
137int nand_ecc_prepare_io_req(struct nand_device *nand,
138			    struct nand_page_io_req *req)
139{
140	if (!nand->ecc.engine || !nand->ecc.engine->ops->prepare_io_req)
141		return 0;
142
143	return nand->ecc.engine->ops->prepare_io_req(nand, req);
144}
145EXPORT_SYMBOL(nand_ecc_prepare_io_req);
146
147/**
148 * nand_ecc_finish_io_req - Finish an I/O request
149 * @nand: the NAND device
150 * @req: the I/O request
151 */
152int nand_ecc_finish_io_req(struct nand_device *nand,
153			   struct nand_page_io_req *req)
154{
155	if (!nand->ecc.engine || !nand->ecc.engine->ops->finish_io_req)
156		return 0;
157
158	return nand->ecc.engine->ops->finish_io_req(nand, req);
159}
160EXPORT_SYMBOL(nand_ecc_finish_io_req);
161
162/* Define default OOB placement schemes for large and small page devices */
163static int nand_ooblayout_ecc_sp(struct mtd_info *mtd, int section,
164				 struct mtd_oob_region *oobregion)
165{
166	struct nand_device *nand = mtd_to_nanddev(mtd);
167	unsigned int total_ecc_bytes = nand->ecc.ctx.total;
168
169	if (section > 1)
170		return -ERANGE;
171
172	if (!section) {
173		oobregion->offset = 0;
174		if (mtd->oobsize == 16)
175			oobregion->length = 4;
176		else
177			oobregion->length = 3;
178	} else {
179		if (mtd->oobsize == 8)
180			return -ERANGE;
181
182		oobregion->offset = 6;
183		oobregion->length = total_ecc_bytes - 4;
184	}
185
186	return 0;
187}
188
189static int nand_ooblayout_free_sp(struct mtd_info *mtd, int section,
190				  struct mtd_oob_region *oobregion)
191{
192	if (section > 1)
193		return -ERANGE;
194
195	if (mtd->oobsize == 16) {
196		if (section)
197			return -ERANGE;
198
199		oobregion->length = 8;
200		oobregion->offset = 8;
201	} else {
202		oobregion->length = 2;
203		if (!section)
204			oobregion->offset = 3;
205		else
206			oobregion->offset = 6;
207	}
208
209	return 0;
210}
211
212static const struct mtd_ooblayout_ops nand_ooblayout_sp_ops = {
213	.ecc = nand_ooblayout_ecc_sp,
214	.free = nand_ooblayout_free_sp,
215};
216
217const struct mtd_ooblayout_ops *nand_get_small_page_ooblayout(void)
218{
219	return &nand_ooblayout_sp_ops;
220}
221EXPORT_SYMBOL_GPL(nand_get_small_page_ooblayout);
222
223static int nand_ooblayout_ecc_lp(struct mtd_info *mtd, int section,
224				 struct mtd_oob_region *oobregion)
225{
226	struct nand_device *nand = mtd_to_nanddev(mtd);
227	unsigned int total_ecc_bytes = nand->ecc.ctx.total;
228
229	if (section || !total_ecc_bytes)
230		return -ERANGE;
231
232	oobregion->length = total_ecc_bytes;
233	oobregion->offset = mtd->oobsize - oobregion->length;
234
235	return 0;
236}
237
238static int nand_ooblayout_free_lp(struct mtd_info *mtd, int section,
239				  struct mtd_oob_region *oobregion)
240{
241	struct nand_device *nand = mtd_to_nanddev(mtd);
242	unsigned int total_ecc_bytes = nand->ecc.ctx.total;
243
244	if (section)
245		return -ERANGE;
246
247	oobregion->length = mtd->oobsize - total_ecc_bytes - 2;
248	oobregion->offset = 2;
249
250	return 0;
251}
252
253static const struct mtd_ooblayout_ops nand_ooblayout_lp_ops = {
254	.ecc = nand_ooblayout_ecc_lp,
255	.free = nand_ooblayout_free_lp,
256};
257
258const struct mtd_ooblayout_ops *nand_get_large_page_ooblayout(void)
259{
260	return &nand_ooblayout_lp_ops;
261}
262EXPORT_SYMBOL_GPL(nand_get_large_page_ooblayout);
263
264/*
265 * Support the old "large page" layout used for 1-bit Hamming ECC where ECC
266 * are placed at a fixed offset.
267 */
268static int nand_ooblayout_ecc_lp_hamming(struct mtd_info *mtd, int section,
269					 struct mtd_oob_region *oobregion)
270{
271	struct nand_device *nand = mtd_to_nanddev(mtd);
272	unsigned int total_ecc_bytes = nand->ecc.ctx.total;
273
274	if (section)
275		return -ERANGE;
276
277	switch (mtd->oobsize) {
278	case 64:
279		oobregion->offset = 40;
280		break;
281	case 128:
282		oobregion->offset = 80;
283		break;
284	default:
285		return -EINVAL;
286	}
287
288	oobregion->length = total_ecc_bytes;
289	if (oobregion->offset + oobregion->length > mtd->oobsize)
290		return -ERANGE;
291
292	return 0;
293}
294
295static int nand_ooblayout_free_lp_hamming(struct mtd_info *mtd, int section,
296					  struct mtd_oob_region *oobregion)
297{
298	struct nand_device *nand = mtd_to_nanddev(mtd);
299	unsigned int total_ecc_bytes = nand->ecc.ctx.total;
300	int ecc_offset = 0;
301
302	if (section < 0 || section > 1)
303		return -ERANGE;
304
305	switch (mtd->oobsize) {
306	case 64:
307		ecc_offset = 40;
308		break;
309	case 128:
310		ecc_offset = 80;
311		break;
312	default:
313		return -EINVAL;
314	}
315
316	if (section == 0) {
317		oobregion->offset = 2;
318		oobregion->length = ecc_offset - 2;
319	} else {
320		oobregion->offset = ecc_offset + total_ecc_bytes;
321		oobregion->length = mtd->oobsize - oobregion->offset;
322	}
323
324	return 0;
325}
326
327static const struct mtd_ooblayout_ops nand_ooblayout_lp_hamming_ops = {
328	.ecc = nand_ooblayout_ecc_lp_hamming,
329	.free = nand_ooblayout_free_lp_hamming,
330};
331
332const struct mtd_ooblayout_ops *nand_get_large_page_hamming_ooblayout(void)
333{
334	return &nand_ooblayout_lp_hamming_ops;
335}
336EXPORT_SYMBOL_GPL(nand_get_large_page_hamming_ooblayout);
337
338static enum nand_ecc_engine_type
339of_get_nand_ecc_engine_type(struct device_node *np)
340{
341	struct device_node *eng_np;
342
343	if (of_property_read_bool(np, "nand-no-ecc-engine"))
344		return NAND_ECC_ENGINE_TYPE_NONE;
345
346	if (of_property_read_bool(np, "nand-use-soft-ecc-engine"))
347		return NAND_ECC_ENGINE_TYPE_SOFT;
348
349	eng_np = of_parse_phandle(np, "nand-ecc-engine", 0);
350	of_node_put(eng_np);
351
352	if (eng_np) {
353		if (eng_np == np)
354			return NAND_ECC_ENGINE_TYPE_ON_DIE;
355		else
356			return NAND_ECC_ENGINE_TYPE_ON_HOST;
357	}
358
359	return NAND_ECC_ENGINE_TYPE_INVALID;
360}
361
362static const char * const nand_ecc_placement[] = {
363	[NAND_ECC_PLACEMENT_OOB] = "oob",
364	[NAND_ECC_PLACEMENT_INTERLEAVED] = "interleaved",
365};
366
367static enum nand_ecc_placement of_get_nand_ecc_placement(struct device_node *np)
368{
369	enum nand_ecc_placement placement;
370	const char *pm;
371	int err;
372
373	err = of_property_read_string(np, "nand-ecc-placement", &pm);
374	if (!err) {
375		for (placement = NAND_ECC_PLACEMENT_OOB;
376		     placement < ARRAY_SIZE(nand_ecc_placement); placement++) {
377			if (!strcasecmp(pm, nand_ecc_placement[placement]))
378				return placement;
379		}
380	}
381
382	return NAND_ECC_PLACEMENT_UNKNOWN;
383}
384
385static const char * const nand_ecc_algos[] = {
386	[NAND_ECC_ALGO_HAMMING] = "hamming",
387	[NAND_ECC_ALGO_BCH] = "bch",
388	[NAND_ECC_ALGO_RS] = "rs",
389};
390
391static enum nand_ecc_algo of_get_nand_ecc_algo(struct device_node *np)
392{
393	enum nand_ecc_algo ecc_algo;
394	const char *pm;
395	int err;
396
397	err = of_property_read_string(np, "nand-ecc-algo", &pm);
398	if (!err) {
399		for (ecc_algo = NAND_ECC_ALGO_HAMMING;
400		     ecc_algo < ARRAY_SIZE(nand_ecc_algos);
401		     ecc_algo++) {
402			if (!strcasecmp(pm, nand_ecc_algos[ecc_algo]))
403				return ecc_algo;
404		}
405	}
406
407	return NAND_ECC_ALGO_UNKNOWN;
408}
409
410static int of_get_nand_ecc_step_size(struct device_node *np)
411{
412	int ret;
413	u32 val;
414
415	ret = of_property_read_u32(np, "nand-ecc-step-size", &val);
416	return ret ? ret : val;
417}
418
419static int of_get_nand_ecc_strength(struct device_node *np)
420{
421	int ret;
422	u32 val;
423
424	ret = of_property_read_u32(np, "nand-ecc-strength", &val);
425	return ret ? ret : val;
426}
427
428void of_get_nand_ecc_user_config(struct nand_device *nand)
429{
430	struct device_node *dn = nanddev_get_of_node(nand);
431	int strength, size;
432
433	nand->ecc.user_conf.engine_type = of_get_nand_ecc_engine_type(dn);
434	nand->ecc.user_conf.algo = of_get_nand_ecc_algo(dn);
435	nand->ecc.user_conf.placement = of_get_nand_ecc_placement(dn);
436
437	strength = of_get_nand_ecc_strength(dn);
438	if (strength >= 0)
439		nand->ecc.user_conf.strength = strength;
440
441	size = of_get_nand_ecc_step_size(dn);
442	if (size >= 0)
443		nand->ecc.user_conf.step_size = size;
444
445	if (of_property_read_bool(dn, "nand-ecc-maximize"))
446		nand->ecc.user_conf.flags |= NAND_ECC_MAXIMIZE_STRENGTH;
447}
448EXPORT_SYMBOL(of_get_nand_ecc_user_config);
449
450/**
451 * nand_ecc_is_strong_enough - Check if the chip configuration meets the
452 *                             datasheet requirements.
453 *
454 * @nand: Device to check
455 *
456 * If our configuration corrects A bits per B bytes and the minimum
457 * required correction level is X bits per Y bytes, then we must ensure
458 * both of the following are true:
459 *
460 * (1) A / B >= X / Y
461 * (2) A >= X
462 *
463 * Requirement (1) ensures we can correct for the required bitflip density.
464 * Requirement (2) ensures we can correct even when all bitflips are clumped
465 * in the same sector.
466 */
467bool nand_ecc_is_strong_enough(struct nand_device *nand)
468{
469	const struct nand_ecc_props *reqs = nanddev_get_ecc_requirements(nand);
470	const struct nand_ecc_props *conf = nanddev_get_ecc_conf(nand);
471	struct mtd_info *mtd = nanddev_to_mtd(nand);
472	int corr, ds_corr;
473
474	if (conf->step_size == 0 || reqs->step_size == 0)
475		/* Not enough information */
476		return true;
477
478	/*
479	 * We get the number of corrected bits per page to compare
480	 * the correction density.
481	 */
482	corr = (mtd->writesize * conf->strength) / conf->step_size;
483	ds_corr = (mtd->writesize * reqs->strength) / reqs->step_size;
484
485	return corr >= ds_corr && conf->strength >= reqs->strength;
486}
487EXPORT_SYMBOL(nand_ecc_is_strong_enough);
488
489/* ECC engine driver internal helpers */
490int nand_ecc_init_req_tweaking(struct nand_ecc_req_tweak_ctx *ctx,
491			       struct nand_device *nand)
492{
493	unsigned int total_buffer_size;
494
495	ctx->nand = nand;
496
497	/* Let the user decide the exact length of each buffer */
498	if (!ctx->page_buffer_size)
499		ctx->page_buffer_size = nanddev_page_size(nand);
500	if (!ctx->oob_buffer_size)
501		ctx->oob_buffer_size = nanddev_per_page_oobsize(nand);
502
503	total_buffer_size = ctx->page_buffer_size + ctx->oob_buffer_size;
504
505	ctx->spare_databuf = kzalloc(total_buffer_size, GFP_KERNEL);
506	if (!ctx->spare_databuf)
507		return -ENOMEM;
508
509	ctx->spare_oobbuf = ctx->spare_databuf + ctx->page_buffer_size;
510
511	return 0;
512}
513EXPORT_SYMBOL_GPL(nand_ecc_init_req_tweaking);
514
515void nand_ecc_cleanup_req_tweaking(struct nand_ecc_req_tweak_ctx *ctx)
516{
517	kfree(ctx->spare_databuf);
518}
519EXPORT_SYMBOL_GPL(nand_ecc_cleanup_req_tweaking);
520
521/*
522 * Ensure data and OOB area is fully read/written otherwise the correction might
523 * not work as expected.
524 */
525void nand_ecc_tweak_req(struct nand_ecc_req_tweak_ctx *ctx,
526			struct nand_page_io_req *req)
527{
528	struct nand_device *nand = ctx->nand;
529	struct nand_page_io_req *orig, *tweak;
530
531	/* Save the original request */
532	ctx->orig_req = *req;
533	ctx->bounce_data = false;
534	ctx->bounce_oob = false;
535	orig = &ctx->orig_req;
536	tweak = req;
537
538	/* Ensure the request covers the entire page */
539	if (orig->datalen < nanddev_page_size(nand)) {
540		ctx->bounce_data = true;
541		tweak->dataoffs = 0;
542		tweak->datalen = nanddev_page_size(nand);
543		tweak->databuf.in = ctx->spare_databuf;
544		memset(tweak->databuf.in, 0xFF, ctx->page_buffer_size);
545	}
546
547	if (orig->ooblen < nanddev_per_page_oobsize(nand)) {
548		ctx->bounce_oob = true;
549		tweak->ooboffs = 0;
550		tweak->ooblen = nanddev_per_page_oobsize(nand);
551		tweak->oobbuf.in = ctx->spare_oobbuf;
552		memset(tweak->oobbuf.in, 0xFF, ctx->oob_buffer_size);
553	}
554
555	/* Copy the data that must be writen in the bounce buffers, if needed */
556	if (orig->type == NAND_PAGE_WRITE) {
557		if (ctx->bounce_data)
558			memcpy((void *)tweak->databuf.out + orig->dataoffs,
559			       orig->databuf.out, orig->datalen);
560
561		if (ctx->bounce_oob)
562			memcpy((void *)tweak->oobbuf.out + orig->ooboffs,
563			       orig->oobbuf.out, orig->ooblen);
564	}
565}
566EXPORT_SYMBOL_GPL(nand_ecc_tweak_req);
567
568void nand_ecc_restore_req(struct nand_ecc_req_tweak_ctx *ctx,
569			  struct nand_page_io_req *req)
570{
571	struct nand_page_io_req *orig, *tweak;
572
573	orig = &ctx->orig_req;
574	tweak = req;
575
576	/* Restore the data read from the bounce buffers, if needed */
577	if (orig->type == NAND_PAGE_READ) {
578		if (ctx->bounce_data)
579			memcpy(orig->databuf.in,
580			       tweak->databuf.in + orig->dataoffs,
581			       orig->datalen);
582
583		if (ctx->bounce_oob)
584			memcpy(orig->oobbuf.in,
585			       tweak->oobbuf.in + orig->ooboffs,
586			       orig->ooblen);
587	}
588
589	/* Ensure the original request is restored */
590	*req = *orig;
591}
592EXPORT_SYMBOL_GPL(nand_ecc_restore_req);
593
594struct nand_ecc_engine *nand_ecc_get_sw_engine(struct nand_device *nand)
595{
596	unsigned int algo = nand->ecc.user_conf.algo;
597
598	if (algo == NAND_ECC_ALGO_UNKNOWN)
599		algo = nand->ecc.defaults.algo;
600
601	switch (algo) {
602	case NAND_ECC_ALGO_HAMMING:
603		return nand_ecc_sw_hamming_get_engine();
604	case NAND_ECC_ALGO_BCH:
605		return nand_ecc_sw_bch_get_engine();
606	default:
607		break;
608	}
609
610	return NULL;
611}
612EXPORT_SYMBOL(nand_ecc_get_sw_engine);
613
614struct nand_ecc_engine *nand_ecc_get_on_die_hw_engine(struct nand_device *nand)
615{
616	return nand->ecc.ondie_engine;
617}
618EXPORT_SYMBOL(nand_ecc_get_on_die_hw_engine);
619
620int nand_ecc_register_on_host_hw_engine(struct nand_ecc_engine *engine)
621{
622	struct nand_ecc_engine *item;
623
624	if (!engine)
625		return -EINVAL;
626
627	/* Prevent multiple registrations of one engine */
628	list_for_each_entry(item, &on_host_hw_engines, node)
629		if (item == engine)
630			return 0;
631
632	mutex_lock(&on_host_hw_engines_mutex);
633	list_add_tail(&engine->node, &on_host_hw_engines);
634	mutex_unlock(&on_host_hw_engines_mutex);
635
636	return 0;
637}
638EXPORT_SYMBOL(nand_ecc_register_on_host_hw_engine);
639
640int nand_ecc_unregister_on_host_hw_engine(struct nand_ecc_engine *engine)
641{
642	if (!engine)
643		return -EINVAL;
644
645	mutex_lock(&on_host_hw_engines_mutex);
646	list_del(&engine->node);
647	mutex_unlock(&on_host_hw_engines_mutex);
648
649	return 0;
650}
651EXPORT_SYMBOL(nand_ecc_unregister_on_host_hw_engine);
652
653static struct nand_ecc_engine *nand_ecc_match_on_host_hw_engine(struct device *dev)
654{
655	struct nand_ecc_engine *item;
656
657	list_for_each_entry(item, &on_host_hw_engines, node)
658		if (item->dev == dev)
659			return item;
660
661	return NULL;
662}
663
664struct nand_ecc_engine *nand_ecc_get_on_host_hw_engine(struct nand_device *nand)
665{
666	struct nand_ecc_engine *engine = NULL;
667	struct device *dev = &nand->mtd.dev;
668	struct platform_device *pdev;
669	struct device_node *np;
670
671	if (list_empty(&on_host_hw_engines))
672		return NULL;
673
674	/* Check for an explicit nand-ecc-engine property */
675	np = of_parse_phandle(dev->of_node, "nand-ecc-engine", 0);
676	if (np) {
677		pdev = of_find_device_by_node(np);
678		if (!pdev)
679			return ERR_PTR(-EPROBE_DEFER);
680
681		engine = nand_ecc_match_on_host_hw_engine(&pdev->dev);
682		platform_device_put(pdev);
683		of_node_put(np);
684
685		if (!engine)
686			return ERR_PTR(-EPROBE_DEFER);
687	}
688
689	if (engine)
690		get_device(engine->dev);
691
692	return engine;
693}
694EXPORT_SYMBOL(nand_ecc_get_on_host_hw_engine);
695
696void nand_ecc_put_on_host_hw_engine(struct nand_device *nand)
697{
698	put_device(nand->ecc.engine->dev);
699}
700EXPORT_SYMBOL(nand_ecc_put_on_host_hw_engine);
701
702/*
703 * In the case of a pipelined engine, the device registering the ECC
704 * engine is not necessarily the ECC engine itself but may be a host controller.
705 * It is then useful to provide a helper to retrieve the right device object
706 * which actually represents the ECC engine.
707 */
708struct device *nand_ecc_get_engine_dev(struct device *host)
709{
710	struct platform_device *ecc_pdev;
711	struct device_node *np;
712
713	/*
714	 * If the device node contains this property, it means we need to follow
715	 * it in order to get the right ECC engine device we are looking for.
716	 */
717	np = of_parse_phandle(host->of_node, "nand-ecc-engine", 0);
718	if (!np)
719		return host;
720
721	ecc_pdev = of_find_device_by_node(np);
722	if (!ecc_pdev) {
723		of_node_put(np);
724		return NULL;
725	}
726
727	platform_device_put(ecc_pdev);
728	of_node_put(np);
729
730	return &ecc_pdev->dev;
731}
732
733MODULE_LICENSE("GPL");
734MODULE_AUTHOR("Miquel Raynal <miquel.raynal@bootlin.com>");
735MODULE_DESCRIPTION("Generic ECC engine");
v6.2
  1// SPDX-License-Identifier: GPL-2.0+
  2/*
  3 * Generic Error-Correcting Code (ECC) engine
  4 *
  5 * Copyright (C) 2019 Macronix
  6 * Author:
  7 *     Miquèl RAYNAL <miquel.raynal@bootlin.com>
  8 *
  9 *
 10 * This file describes the abstraction of any NAND ECC engine. It has been
 11 * designed to fit most cases, including parallel NANDs and SPI-NANDs.
 12 *
 13 * There are three main situations where instantiating this ECC engine makes
 14 * sense:
 15 *   - external: The ECC engine is outside the NAND pipeline, typically this
 16 *               is a software ECC engine, or an hardware engine that is
 17 *               outside the NAND controller pipeline.
 18 *   - pipelined: The ECC engine is inside the NAND pipeline, ie. on the
 19 *                controller's side. This is the case of most of the raw NAND
 20 *                controllers. In the pipeline case, the ECC bytes are
 21 *                generated/data corrected on the fly when a page is
 22 *                written/read.
 23 *   - ondie: The ECC engine is inside the NAND pipeline, on the chip's side.
 24 *            Some NAND chips can correct themselves the data.
 25 *
 26 * Besides the initial setup and final cleanups, the interfaces are rather
 27 * simple:
 28 *   - prepare: Prepare an I/O request. Enable/disable the ECC engine based on
 29 *              the I/O request type. In case of software correction or external
 30 *              engine, this step may involve to derive the ECC bytes and place
 31 *              them in the OOB area before a write.
 32 *   - finish: Finish an I/O request. Correct the data in case of a read
 33 *             request and report the number of corrected bits/uncorrectable
 34 *             errors. Most likely empty for write operations, unless you have
 35 *             hardware specific stuff to do, like shutting down the engine to
 36 *             save power.
 37 *
 38 * The I/O request should be enclosed in a prepare()/finish() pair of calls
 39 * and will behave differently depending on the requested I/O type:
 40 *   - raw: Correction disabled
 41 *   - ecc: Correction enabled
 42 *
 43 * The request direction is impacting the logic as well:
 44 *   - read: Load data from the NAND chip
 45 *   - write: Store data in the NAND chip
 46 *
 47 * Mixing all this combinations together gives the following behavior.
 48 * Those are just examples, drivers are free to add custom steps in their
 49 * prepare/finish hook.
 50 *
 51 * [external ECC engine]
 52 *   - external + prepare + raw + read: do nothing
 53 *   - external + finish  + raw + read: do nothing
 54 *   - external + prepare + raw + write: do nothing
 55 *   - external + finish  + raw + write: do nothing
 56 *   - external + prepare + ecc + read: do nothing
 57 *   - external + finish  + ecc + read: calculate expected ECC bytes, extract
 58 *                                      ECC bytes from OOB buffer, correct
 59 *                                      and report any bitflip/error
 60 *   - external + prepare + ecc + write: calculate ECC bytes and store them at
 61 *                                       the right place in the OOB buffer based
 62 *                                       on the OOB layout
 63 *   - external + finish  + ecc + write: do nothing
 64 *
 65 * [pipelined ECC engine]
 66 *   - pipelined + prepare + raw + read: disable the controller's ECC engine if
 67 *                                       activated
 68 *   - pipelined + finish  + raw + read: do nothing
 69 *   - pipelined + prepare + raw + write: disable the controller's ECC engine if
 70 *                                        activated
 71 *   - pipelined + finish  + raw + write: do nothing
 72 *   - pipelined + prepare + ecc + read: enable the controller's ECC engine if
 73 *                                       deactivated
 74 *   - pipelined + finish  + ecc + read: check the status, report any
 75 *                                       error/bitflip
 76 *   - pipelined + prepare + ecc + write: enable the controller's ECC engine if
 77 *                                        deactivated
 78 *   - pipelined + finish  + ecc + write: do nothing
 79 *
 80 * [ondie ECC engine]
 81 *   - ondie + prepare + raw + read: send commands to disable the on-chip ECC
 82 *                                   engine if activated
 83 *   - ondie + finish  + raw + read: do nothing
 84 *   - ondie + prepare + raw + write: send commands to disable the on-chip ECC
 85 *                                    engine if activated
 86 *   - ondie + finish  + raw + write: do nothing
 87 *   - ondie + prepare + ecc + read: send commands to enable the on-chip ECC
 88 *                                   engine if deactivated
 89 *   - ondie + finish  + ecc + read: send commands to check the status, report
 90 *                                   any error/bitflip
 91 *   - ondie + prepare + ecc + write: send commands to enable the on-chip ECC
 92 *                                    engine if deactivated
 93 *   - ondie + finish  + ecc + write: do nothing
 94 */
 95
 96#include <linux/module.h>
 97#include <linux/mtd/nand.h>
 
 98#include <linux/slab.h>
 99#include <linux/of.h>
100#include <linux/of_device.h>
101#include <linux/of_platform.h>
102
103static LIST_HEAD(on_host_hw_engines);
104static DEFINE_MUTEX(on_host_hw_engines_mutex);
105
106/**
107 * nand_ecc_init_ctx - Init the ECC engine context
108 * @nand: the NAND device
109 *
110 * On success, the caller is responsible of calling @nand_ecc_cleanup_ctx().
111 */
112int nand_ecc_init_ctx(struct nand_device *nand)
113{
114	if (!nand->ecc.engine || !nand->ecc.engine->ops->init_ctx)
115		return 0;
116
117	return nand->ecc.engine->ops->init_ctx(nand);
118}
119EXPORT_SYMBOL(nand_ecc_init_ctx);
120
121/**
122 * nand_ecc_cleanup_ctx - Cleanup the ECC engine context
123 * @nand: the NAND device
124 */
125void nand_ecc_cleanup_ctx(struct nand_device *nand)
126{
127	if (nand->ecc.engine && nand->ecc.engine->ops->cleanup_ctx)
128		nand->ecc.engine->ops->cleanup_ctx(nand);
129}
130EXPORT_SYMBOL(nand_ecc_cleanup_ctx);
131
132/**
133 * nand_ecc_prepare_io_req - Prepare an I/O request
134 * @nand: the NAND device
135 * @req: the I/O request
136 */
137int nand_ecc_prepare_io_req(struct nand_device *nand,
138			    struct nand_page_io_req *req)
139{
140	if (!nand->ecc.engine || !nand->ecc.engine->ops->prepare_io_req)
141		return 0;
142
143	return nand->ecc.engine->ops->prepare_io_req(nand, req);
144}
145EXPORT_SYMBOL(nand_ecc_prepare_io_req);
146
147/**
148 * nand_ecc_finish_io_req - Finish an I/O request
149 * @nand: the NAND device
150 * @req: the I/O request
151 */
152int nand_ecc_finish_io_req(struct nand_device *nand,
153			   struct nand_page_io_req *req)
154{
155	if (!nand->ecc.engine || !nand->ecc.engine->ops->finish_io_req)
156		return 0;
157
158	return nand->ecc.engine->ops->finish_io_req(nand, req);
159}
160EXPORT_SYMBOL(nand_ecc_finish_io_req);
161
162/* Define default OOB placement schemes for large and small page devices */
163static int nand_ooblayout_ecc_sp(struct mtd_info *mtd, int section,
164				 struct mtd_oob_region *oobregion)
165{
166	struct nand_device *nand = mtd_to_nanddev(mtd);
167	unsigned int total_ecc_bytes = nand->ecc.ctx.total;
168
169	if (section > 1)
170		return -ERANGE;
171
172	if (!section) {
173		oobregion->offset = 0;
174		if (mtd->oobsize == 16)
175			oobregion->length = 4;
176		else
177			oobregion->length = 3;
178	} else {
179		if (mtd->oobsize == 8)
180			return -ERANGE;
181
182		oobregion->offset = 6;
183		oobregion->length = total_ecc_bytes - 4;
184	}
185
186	return 0;
187}
188
189static int nand_ooblayout_free_sp(struct mtd_info *mtd, int section,
190				  struct mtd_oob_region *oobregion)
191{
192	if (section > 1)
193		return -ERANGE;
194
195	if (mtd->oobsize == 16) {
196		if (section)
197			return -ERANGE;
198
199		oobregion->length = 8;
200		oobregion->offset = 8;
201	} else {
202		oobregion->length = 2;
203		if (!section)
204			oobregion->offset = 3;
205		else
206			oobregion->offset = 6;
207	}
208
209	return 0;
210}
211
212static const struct mtd_ooblayout_ops nand_ooblayout_sp_ops = {
213	.ecc = nand_ooblayout_ecc_sp,
214	.free = nand_ooblayout_free_sp,
215};
216
217const struct mtd_ooblayout_ops *nand_get_small_page_ooblayout(void)
218{
219	return &nand_ooblayout_sp_ops;
220}
221EXPORT_SYMBOL_GPL(nand_get_small_page_ooblayout);
222
223static int nand_ooblayout_ecc_lp(struct mtd_info *mtd, int section,
224				 struct mtd_oob_region *oobregion)
225{
226	struct nand_device *nand = mtd_to_nanddev(mtd);
227	unsigned int total_ecc_bytes = nand->ecc.ctx.total;
228
229	if (section || !total_ecc_bytes)
230		return -ERANGE;
231
232	oobregion->length = total_ecc_bytes;
233	oobregion->offset = mtd->oobsize - oobregion->length;
234
235	return 0;
236}
237
238static int nand_ooblayout_free_lp(struct mtd_info *mtd, int section,
239				  struct mtd_oob_region *oobregion)
240{
241	struct nand_device *nand = mtd_to_nanddev(mtd);
242	unsigned int total_ecc_bytes = nand->ecc.ctx.total;
243
244	if (section)
245		return -ERANGE;
246
247	oobregion->length = mtd->oobsize - total_ecc_bytes - 2;
248	oobregion->offset = 2;
249
250	return 0;
251}
252
253static const struct mtd_ooblayout_ops nand_ooblayout_lp_ops = {
254	.ecc = nand_ooblayout_ecc_lp,
255	.free = nand_ooblayout_free_lp,
256};
257
258const struct mtd_ooblayout_ops *nand_get_large_page_ooblayout(void)
259{
260	return &nand_ooblayout_lp_ops;
261}
262EXPORT_SYMBOL_GPL(nand_get_large_page_ooblayout);
263
264/*
265 * Support the old "large page" layout used for 1-bit Hamming ECC where ECC
266 * are placed at a fixed offset.
267 */
268static int nand_ooblayout_ecc_lp_hamming(struct mtd_info *mtd, int section,
269					 struct mtd_oob_region *oobregion)
270{
271	struct nand_device *nand = mtd_to_nanddev(mtd);
272	unsigned int total_ecc_bytes = nand->ecc.ctx.total;
273
274	if (section)
275		return -ERANGE;
276
277	switch (mtd->oobsize) {
278	case 64:
279		oobregion->offset = 40;
280		break;
281	case 128:
282		oobregion->offset = 80;
283		break;
284	default:
285		return -EINVAL;
286	}
287
288	oobregion->length = total_ecc_bytes;
289	if (oobregion->offset + oobregion->length > mtd->oobsize)
290		return -ERANGE;
291
292	return 0;
293}
294
295static int nand_ooblayout_free_lp_hamming(struct mtd_info *mtd, int section,
296					  struct mtd_oob_region *oobregion)
297{
298	struct nand_device *nand = mtd_to_nanddev(mtd);
299	unsigned int total_ecc_bytes = nand->ecc.ctx.total;
300	int ecc_offset = 0;
301
302	if (section < 0 || section > 1)
303		return -ERANGE;
304
305	switch (mtd->oobsize) {
306	case 64:
307		ecc_offset = 40;
308		break;
309	case 128:
310		ecc_offset = 80;
311		break;
312	default:
313		return -EINVAL;
314	}
315
316	if (section == 0) {
317		oobregion->offset = 2;
318		oobregion->length = ecc_offset - 2;
319	} else {
320		oobregion->offset = ecc_offset + total_ecc_bytes;
321		oobregion->length = mtd->oobsize - oobregion->offset;
322	}
323
324	return 0;
325}
326
327static const struct mtd_ooblayout_ops nand_ooblayout_lp_hamming_ops = {
328	.ecc = nand_ooblayout_ecc_lp_hamming,
329	.free = nand_ooblayout_free_lp_hamming,
330};
331
332const struct mtd_ooblayout_ops *nand_get_large_page_hamming_ooblayout(void)
333{
334	return &nand_ooblayout_lp_hamming_ops;
335}
336EXPORT_SYMBOL_GPL(nand_get_large_page_hamming_ooblayout);
337
338static enum nand_ecc_engine_type
339of_get_nand_ecc_engine_type(struct device_node *np)
340{
341	struct device_node *eng_np;
342
343	if (of_property_read_bool(np, "nand-no-ecc-engine"))
344		return NAND_ECC_ENGINE_TYPE_NONE;
345
346	if (of_property_read_bool(np, "nand-use-soft-ecc-engine"))
347		return NAND_ECC_ENGINE_TYPE_SOFT;
348
349	eng_np = of_parse_phandle(np, "nand-ecc-engine", 0);
350	of_node_put(eng_np);
351
352	if (eng_np) {
353		if (eng_np == np)
354			return NAND_ECC_ENGINE_TYPE_ON_DIE;
355		else
356			return NAND_ECC_ENGINE_TYPE_ON_HOST;
357	}
358
359	return NAND_ECC_ENGINE_TYPE_INVALID;
360}
361
362static const char * const nand_ecc_placement[] = {
363	[NAND_ECC_PLACEMENT_OOB] = "oob",
364	[NAND_ECC_PLACEMENT_INTERLEAVED] = "interleaved",
365};
366
367static enum nand_ecc_placement of_get_nand_ecc_placement(struct device_node *np)
368{
369	enum nand_ecc_placement placement;
370	const char *pm;
371	int err;
372
373	err = of_property_read_string(np, "nand-ecc-placement", &pm);
374	if (!err) {
375		for (placement = NAND_ECC_PLACEMENT_OOB;
376		     placement < ARRAY_SIZE(nand_ecc_placement); placement++) {
377			if (!strcasecmp(pm, nand_ecc_placement[placement]))
378				return placement;
379		}
380	}
381
382	return NAND_ECC_PLACEMENT_UNKNOWN;
383}
384
385static const char * const nand_ecc_algos[] = {
386	[NAND_ECC_ALGO_HAMMING] = "hamming",
387	[NAND_ECC_ALGO_BCH] = "bch",
388	[NAND_ECC_ALGO_RS] = "rs",
389};
390
391static enum nand_ecc_algo of_get_nand_ecc_algo(struct device_node *np)
392{
393	enum nand_ecc_algo ecc_algo;
394	const char *pm;
395	int err;
396
397	err = of_property_read_string(np, "nand-ecc-algo", &pm);
398	if (!err) {
399		for (ecc_algo = NAND_ECC_ALGO_HAMMING;
400		     ecc_algo < ARRAY_SIZE(nand_ecc_algos);
401		     ecc_algo++) {
402			if (!strcasecmp(pm, nand_ecc_algos[ecc_algo]))
403				return ecc_algo;
404		}
405	}
406
407	return NAND_ECC_ALGO_UNKNOWN;
408}
409
410static int of_get_nand_ecc_step_size(struct device_node *np)
411{
412	int ret;
413	u32 val;
414
415	ret = of_property_read_u32(np, "nand-ecc-step-size", &val);
416	return ret ? ret : val;
417}
418
419static int of_get_nand_ecc_strength(struct device_node *np)
420{
421	int ret;
422	u32 val;
423
424	ret = of_property_read_u32(np, "nand-ecc-strength", &val);
425	return ret ? ret : val;
426}
427
428void of_get_nand_ecc_user_config(struct nand_device *nand)
429{
430	struct device_node *dn = nanddev_get_of_node(nand);
431	int strength, size;
432
433	nand->ecc.user_conf.engine_type = of_get_nand_ecc_engine_type(dn);
434	nand->ecc.user_conf.algo = of_get_nand_ecc_algo(dn);
435	nand->ecc.user_conf.placement = of_get_nand_ecc_placement(dn);
436
437	strength = of_get_nand_ecc_strength(dn);
438	if (strength >= 0)
439		nand->ecc.user_conf.strength = strength;
440
441	size = of_get_nand_ecc_step_size(dn);
442	if (size >= 0)
443		nand->ecc.user_conf.step_size = size;
444
445	if (of_property_read_bool(dn, "nand-ecc-maximize"))
446		nand->ecc.user_conf.flags |= NAND_ECC_MAXIMIZE_STRENGTH;
447}
448EXPORT_SYMBOL(of_get_nand_ecc_user_config);
449
450/**
451 * nand_ecc_is_strong_enough - Check if the chip configuration meets the
452 *                             datasheet requirements.
453 *
454 * @nand: Device to check
455 *
456 * If our configuration corrects A bits per B bytes and the minimum
457 * required correction level is X bits per Y bytes, then we must ensure
458 * both of the following are true:
459 *
460 * (1) A / B >= X / Y
461 * (2) A >= X
462 *
463 * Requirement (1) ensures we can correct for the required bitflip density.
464 * Requirement (2) ensures we can correct even when all bitflips are clumped
465 * in the same sector.
466 */
467bool nand_ecc_is_strong_enough(struct nand_device *nand)
468{
469	const struct nand_ecc_props *reqs = nanddev_get_ecc_requirements(nand);
470	const struct nand_ecc_props *conf = nanddev_get_ecc_conf(nand);
471	struct mtd_info *mtd = nanddev_to_mtd(nand);
472	int corr, ds_corr;
473
474	if (conf->step_size == 0 || reqs->step_size == 0)
475		/* Not enough information */
476		return true;
477
478	/*
479	 * We get the number of corrected bits per page to compare
480	 * the correction density.
481	 */
482	corr = (mtd->writesize * conf->strength) / conf->step_size;
483	ds_corr = (mtd->writesize * reqs->strength) / reqs->step_size;
484
485	return corr >= ds_corr && conf->strength >= reqs->strength;
486}
487EXPORT_SYMBOL(nand_ecc_is_strong_enough);
488
489/* ECC engine driver internal helpers */
490int nand_ecc_init_req_tweaking(struct nand_ecc_req_tweak_ctx *ctx,
491			       struct nand_device *nand)
492{
493	unsigned int total_buffer_size;
494
495	ctx->nand = nand;
496
497	/* Let the user decide the exact length of each buffer */
498	if (!ctx->page_buffer_size)
499		ctx->page_buffer_size = nanddev_page_size(nand);
500	if (!ctx->oob_buffer_size)
501		ctx->oob_buffer_size = nanddev_per_page_oobsize(nand);
502
503	total_buffer_size = ctx->page_buffer_size + ctx->oob_buffer_size;
504
505	ctx->spare_databuf = kzalloc(total_buffer_size, GFP_KERNEL);
506	if (!ctx->spare_databuf)
507		return -ENOMEM;
508
509	ctx->spare_oobbuf = ctx->spare_databuf + ctx->page_buffer_size;
510
511	return 0;
512}
513EXPORT_SYMBOL_GPL(nand_ecc_init_req_tweaking);
514
515void nand_ecc_cleanup_req_tweaking(struct nand_ecc_req_tweak_ctx *ctx)
516{
517	kfree(ctx->spare_databuf);
518}
519EXPORT_SYMBOL_GPL(nand_ecc_cleanup_req_tweaking);
520
521/*
522 * Ensure data and OOB area is fully read/written otherwise the correction might
523 * not work as expected.
524 */
525void nand_ecc_tweak_req(struct nand_ecc_req_tweak_ctx *ctx,
526			struct nand_page_io_req *req)
527{
528	struct nand_device *nand = ctx->nand;
529	struct nand_page_io_req *orig, *tweak;
530
531	/* Save the original request */
532	ctx->orig_req = *req;
533	ctx->bounce_data = false;
534	ctx->bounce_oob = false;
535	orig = &ctx->orig_req;
536	tweak = req;
537
538	/* Ensure the request covers the entire page */
539	if (orig->datalen < nanddev_page_size(nand)) {
540		ctx->bounce_data = true;
541		tweak->dataoffs = 0;
542		tweak->datalen = nanddev_page_size(nand);
543		tweak->databuf.in = ctx->spare_databuf;
544		memset(tweak->databuf.in, 0xFF, ctx->page_buffer_size);
545	}
546
547	if (orig->ooblen < nanddev_per_page_oobsize(nand)) {
548		ctx->bounce_oob = true;
549		tweak->ooboffs = 0;
550		tweak->ooblen = nanddev_per_page_oobsize(nand);
551		tweak->oobbuf.in = ctx->spare_oobbuf;
552		memset(tweak->oobbuf.in, 0xFF, ctx->oob_buffer_size);
553	}
554
555	/* Copy the data that must be writen in the bounce buffers, if needed */
556	if (orig->type == NAND_PAGE_WRITE) {
557		if (ctx->bounce_data)
558			memcpy((void *)tweak->databuf.out + orig->dataoffs,
559			       orig->databuf.out, orig->datalen);
560
561		if (ctx->bounce_oob)
562			memcpy((void *)tweak->oobbuf.out + orig->ooboffs,
563			       orig->oobbuf.out, orig->ooblen);
564	}
565}
566EXPORT_SYMBOL_GPL(nand_ecc_tweak_req);
567
568void nand_ecc_restore_req(struct nand_ecc_req_tweak_ctx *ctx,
569			  struct nand_page_io_req *req)
570{
571	struct nand_page_io_req *orig, *tweak;
572
573	orig = &ctx->orig_req;
574	tweak = req;
575
576	/* Restore the data read from the bounce buffers, if needed */
577	if (orig->type == NAND_PAGE_READ) {
578		if (ctx->bounce_data)
579			memcpy(orig->databuf.in,
580			       tweak->databuf.in + orig->dataoffs,
581			       orig->datalen);
582
583		if (ctx->bounce_oob)
584			memcpy(orig->oobbuf.in,
585			       tweak->oobbuf.in + orig->ooboffs,
586			       orig->ooblen);
587	}
588
589	/* Ensure the original request is restored */
590	*req = *orig;
591}
592EXPORT_SYMBOL_GPL(nand_ecc_restore_req);
593
594struct nand_ecc_engine *nand_ecc_get_sw_engine(struct nand_device *nand)
595{
596	unsigned int algo = nand->ecc.user_conf.algo;
597
598	if (algo == NAND_ECC_ALGO_UNKNOWN)
599		algo = nand->ecc.defaults.algo;
600
601	switch (algo) {
602	case NAND_ECC_ALGO_HAMMING:
603		return nand_ecc_sw_hamming_get_engine();
604	case NAND_ECC_ALGO_BCH:
605		return nand_ecc_sw_bch_get_engine();
606	default:
607		break;
608	}
609
610	return NULL;
611}
612EXPORT_SYMBOL(nand_ecc_get_sw_engine);
613
614struct nand_ecc_engine *nand_ecc_get_on_die_hw_engine(struct nand_device *nand)
615{
616	return nand->ecc.ondie_engine;
617}
618EXPORT_SYMBOL(nand_ecc_get_on_die_hw_engine);
619
620int nand_ecc_register_on_host_hw_engine(struct nand_ecc_engine *engine)
621{
622	struct nand_ecc_engine *item;
623
624	if (!engine)
625		return -EINVAL;
626
627	/* Prevent multiple registrations of one engine */
628	list_for_each_entry(item, &on_host_hw_engines, node)
629		if (item == engine)
630			return 0;
631
632	mutex_lock(&on_host_hw_engines_mutex);
633	list_add_tail(&engine->node, &on_host_hw_engines);
634	mutex_unlock(&on_host_hw_engines_mutex);
635
636	return 0;
637}
638EXPORT_SYMBOL(nand_ecc_register_on_host_hw_engine);
639
640int nand_ecc_unregister_on_host_hw_engine(struct nand_ecc_engine *engine)
641{
642	if (!engine)
643		return -EINVAL;
644
645	mutex_lock(&on_host_hw_engines_mutex);
646	list_del(&engine->node);
647	mutex_unlock(&on_host_hw_engines_mutex);
648
649	return 0;
650}
651EXPORT_SYMBOL(nand_ecc_unregister_on_host_hw_engine);
652
653static struct nand_ecc_engine *nand_ecc_match_on_host_hw_engine(struct device *dev)
654{
655	struct nand_ecc_engine *item;
656
657	list_for_each_entry(item, &on_host_hw_engines, node)
658		if (item->dev == dev)
659			return item;
660
661	return NULL;
662}
663
664struct nand_ecc_engine *nand_ecc_get_on_host_hw_engine(struct nand_device *nand)
665{
666	struct nand_ecc_engine *engine = NULL;
667	struct device *dev = &nand->mtd.dev;
668	struct platform_device *pdev;
669	struct device_node *np;
670
671	if (list_empty(&on_host_hw_engines))
672		return NULL;
673
674	/* Check for an explicit nand-ecc-engine property */
675	np = of_parse_phandle(dev->of_node, "nand-ecc-engine", 0);
676	if (np) {
677		pdev = of_find_device_by_node(np);
678		if (!pdev)
679			return ERR_PTR(-EPROBE_DEFER);
680
681		engine = nand_ecc_match_on_host_hw_engine(&pdev->dev);
682		platform_device_put(pdev);
683		of_node_put(np);
684
685		if (!engine)
686			return ERR_PTR(-EPROBE_DEFER);
687	}
688
689	if (engine)
690		get_device(engine->dev);
691
692	return engine;
693}
694EXPORT_SYMBOL(nand_ecc_get_on_host_hw_engine);
695
696void nand_ecc_put_on_host_hw_engine(struct nand_device *nand)
697{
698	put_device(nand->ecc.engine->dev);
699}
700EXPORT_SYMBOL(nand_ecc_put_on_host_hw_engine);
701
702/*
703 * In the case of a pipelined engine, the device registering the ECC
704 * engine is not necessarily the ECC engine itself but may be a host controller.
705 * It is then useful to provide a helper to retrieve the right device object
706 * which actually represents the ECC engine.
707 */
708struct device *nand_ecc_get_engine_dev(struct device *host)
709{
710	struct platform_device *ecc_pdev;
711	struct device_node *np;
712
713	/*
714	 * If the device node contains this property, it means we need to follow
715	 * it in order to get the right ECC engine device we are looking for.
716	 */
717	np = of_parse_phandle(host->of_node, "nand-ecc-engine", 0);
718	if (!np)
719		return host;
720
721	ecc_pdev = of_find_device_by_node(np);
722	if (!ecc_pdev) {
723		of_node_put(np);
724		return NULL;
725	}
726
727	platform_device_put(ecc_pdev);
728	of_node_put(np);
729
730	return &ecc_pdev->dev;
731}
732
733MODULE_LICENSE("GPL");
734MODULE_AUTHOR("Miquel Raynal <miquel.raynal@bootlin.com>");
735MODULE_DESCRIPTION("Generic ECC engine");