Lines Matching +full:delta +full:- +full:sigma
1 // SPDX-License-Identifier: GPL-2.0
6 * Author: Boris Brezillon <boris.brezillon@free-electrons.com>
22 * Derived from Das U-Boot source code
23 * (u-boot-1.1.5/board/atmel/at91sam9263ek/nand.c)
37 * sub-section.
41 * to expose the needed lib/bch.c helpers/functions and re-use them here.
75 #define PMECC_CFG_NSECTORS(x) ((fls(x) - 1) << 8)
178 s32 *delta; member
188 /* polynomial degree is the most-significant bit index */ in deg()
189 return fls(poly) - 1; in deg()
197 unsigned int nn = BIT(mm) - 1; in atmel_pmecc_build_gf_tables()
201 return -EINVAL; in atmel_pmecc_build_gf_tables()
204 gf_tables->alpha_to[i] = x; in atmel_pmecc_build_gf_tables()
205 gf_tables->index_of[x] = i; in atmel_pmecc_build_gf_tables()
207 /* polynomial is not primitive (a^i=1 with 0<i<2^m-1) */ in atmel_pmecc_build_gf_tables()
208 return -EINVAL; in atmel_pmecc_build_gf_tables()
213 gf_tables->alpha_to[nn] = 1; in atmel_pmecc_build_gf_tables()
214 gf_tables->index_of[0] = 0; in atmel_pmecc_build_gf_tables()
226 if (req->ecc.sectorsize == 512) { in atmel_pmecc_create_gf_tables()
240 return ERR_PTR(-ENOMEM); in atmel_pmecc_create_gf_tables()
242 gf_tables->alpha_to = (void *)(gf_tables + 1); in atmel_pmecc_create_gf_tables()
243 gf_tables->index_of = gf_tables->alpha_to + table_size; in atmel_pmecc_create_gf_tables()
260 if (req->ecc.sectorsize == 512) in atmel_pmecc_get_gf_tables()
282 if (req->pagesize <= 0 || req->oobsize <= 0 || req->ecc.bytes <= 0) in atmel_pmecc_prepare_user_req()
283 return -EINVAL; in atmel_pmecc_prepare_user_req()
285 if (req->ecc.ooboffset >= 0 && in atmel_pmecc_prepare_user_req()
286 req->ecc.ooboffset + req->ecc.bytes > req->oobsize) in atmel_pmecc_prepare_user_req()
287 return -EINVAL; in atmel_pmecc_prepare_user_req()
289 if (req->ecc.sectorsize == ATMEL_PMECC_SECTOR_SIZE_AUTO) { in atmel_pmecc_prepare_user_req()
290 if (req->ecc.strength != ATMEL_PMECC_MAXIMIZE_ECC_STRENGTH) in atmel_pmecc_prepare_user_req()
291 return -EINVAL; in atmel_pmecc_prepare_user_req()
293 if (req->pagesize > 512) in atmel_pmecc_prepare_user_req()
294 req->ecc.sectorsize = 1024; in atmel_pmecc_prepare_user_req()
296 req->ecc.sectorsize = 512; in atmel_pmecc_prepare_user_req()
299 if (req->ecc.sectorsize != 512 && req->ecc.sectorsize != 1024) in atmel_pmecc_prepare_user_req()
300 return -EINVAL; in atmel_pmecc_prepare_user_req()
302 if (req->pagesize % req->ecc.sectorsize) in atmel_pmecc_prepare_user_req()
303 return -EINVAL; in atmel_pmecc_prepare_user_req()
305 req->ecc.nsectors = req->pagesize / req->ecc.sectorsize; in atmel_pmecc_prepare_user_req()
307 max_eccbytes = req->ecc.bytes; in atmel_pmecc_prepare_user_req()
309 for (i = 0; i < pmecc->caps->nstrengths; i++) { in atmel_pmecc_prepare_user_req()
310 int nbytes, strength = pmecc->caps->strengths[i]; in atmel_pmecc_prepare_user_req()
312 if (req->ecc.strength != ATMEL_PMECC_MAXIMIZE_ECC_STRENGTH && in atmel_pmecc_prepare_user_req()
313 strength < req->ecc.strength) in atmel_pmecc_prepare_user_req()
316 nbytes = DIV_ROUND_UP(strength * fls(8 * req->ecc.sectorsize), in atmel_pmecc_prepare_user_req()
318 nbytes *= req->ecc.nsectors; in atmel_pmecc_prepare_user_req()
326 if (req->ecc.strength != ATMEL_PMECC_MAXIMIZE_ECC_STRENGTH) in atmel_pmecc_prepare_user_req()
331 return -EINVAL; in atmel_pmecc_prepare_user_req()
333 req->ecc.bytes = eccbytes; in atmel_pmecc_prepare_user_req()
334 req->ecc.strength = eccstrength; in atmel_pmecc_prepare_user_req()
336 if (req->ecc.ooboffset < 0) in atmel_pmecc_prepare_user_req()
337 req->ecc.ooboffset = req->oobsize - eccbytes; in atmel_pmecc_prepare_user_req()
357 size += ((2 * req->ecc.strength) + 1) * sizeof(u16) * in atmel_pmecc_create_user()
358 (2 + req->ecc.strength + 2); in atmel_pmecc_create_user()
360 size += (req->ecc.strength + 1) * sizeof(u16); in atmel_pmecc_create_user()
361 /* Reserve space for mu, dmu and delta. */ in atmel_pmecc_create_user()
363 size += (req->ecc.strength + 1) * sizeof(s32) * 3; in atmel_pmecc_create_user()
365 user = devm_kzalloc(pmecc->dev, size, GFP_KERNEL); in atmel_pmecc_create_user()
367 return ERR_PTR(-ENOMEM); in atmel_pmecc_create_user()
369 user->pmecc = pmecc; in atmel_pmecc_create_user()
371 user->partial_syn = (s16 *)PTR_ALIGN(user + 1, sizeof(u16)); in atmel_pmecc_create_user()
372 user->si = user->partial_syn + ((2 * req->ecc.strength) + 1); in atmel_pmecc_create_user()
373 user->lmu = user->si + ((2 * req->ecc.strength) + 1); in atmel_pmecc_create_user()
374 user->smu = user->lmu + (req->ecc.strength + 1); in atmel_pmecc_create_user()
375 user->mu = (s32 *)PTR_ALIGN(user->smu + in atmel_pmecc_create_user()
376 (((2 * req->ecc.strength) + 1) * in atmel_pmecc_create_user()
377 (req->ecc.strength + 2)), in atmel_pmecc_create_user()
379 user->dmu = user->mu + req->ecc.strength + 1; in atmel_pmecc_create_user()
380 user->delta = user->dmu + req->ecc.strength + 1; in atmel_pmecc_create_user()
386 user->gf_tables = gf_tables; in atmel_pmecc_create_user()
388 user->eccbytes = req->ecc.bytes / req->ecc.nsectors; in atmel_pmecc_create_user()
390 for (strength = 0; strength < pmecc->caps->nstrengths; strength++) { in atmel_pmecc_create_user()
391 if (pmecc->caps->strengths[strength] == req->ecc.strength) in atmel_pmecc_create_user()
395 user->cache.cfg = PMECC_CFG_BCH_STRENGTH(strength) | in atmel_pmecc_create_user()
396 PMECC_CFG_NSECTORS(req->ecc.nsectors); in atmel_pmecc_create_user()
398 if (req->ecc.sectorsize == 1024) in atmel_pmecc_create_user()
399 user->cache.cfg |= PMECC_CFG_SECTOR1024; in atmel_pmecc_create_user()
401 user->cache.sarea = req->oobsize - 1; in atmel_pmecc_create_user()
402 user->cache.saddr = req->ecc.ooboffset; in atmel_pmecc_create_user()
403 user->cache.eaddr = req->ecc.ooboffset + req->ecc.bytes - 1; in atmel_pmecc_create_user()
411 const int *strengths = user->pmecc->caps->strengths; in get_strength()
413 return strengths[user->cache.cfg & PMECC_CFG_BCH_STRENGTH_MASK]; in get_strength()
418 return user->cache.cfg & PMECC_CFG_SECTOR1024 ? 1024 : 512; in get_sectorsize()
429 value = readl_relaxed(user->pmecc->regs.base + in atmel_pmecc_gen_syndrome()
434 user->partial_syn[(2 * i) + 1] = value; in atmel_pmecc_gen_syndrome()
441 int cw_len = BIT(degree) - 1; in atmel_pmecc_substitute()
443 s16 *alpha_to = user->gf_tables->alpha_to; in atmel_pmecc_substitute()
444 s16 *index_of = user->gf_tables->index_of; in atmel_pmecc_substitute()
445 s16 *partial_syn = user->partial_syn; in atmel_pmecc_substitute()
453 si = user->si; in atmel_pmecc_substitute()
455 memset(&si[1], 0, sizeof(s16) * ((2 * strength) - 1)); in atmel_pmecc_substitute()
481 s16 *lmu = user->lmu; in atmel_pmecc_get_sigma()
482 s16 *si = user->si; in atmel_pmecc_get_sigma()
483 s32 *mu = user->mu; in atmel_pmecc_get_sigma()
484 s32 *dmu = user->dmu; in atmel_pmecc_get_sigma()
485 s32 *delta = user->delta; in atmel_pmecc_get_sigma() local
487 int cw_len = BIT(degree) - 1; in atmel_pmecc_get_sigma()
490 s16 *index_of = user->gf_tables->index_of; in atmel_pmecc_get_sigma()
491 s16 *alpha_to = user->gf_tables->alpha_to; in atmel_pmecc_get_sigma()
494 s16 *smu = user->smu; in atmel_pmecc_get_sigma()
496 /* index of largest delta */ in atmel_pmecc_get_sigma()
506 mu[0] = -1; in atmel_pmecc_get_sigma()
515 delta[0] = (mu[0] * 2 - lmu[0]) >> 1; in atmel_pmecc_get_sigma()
521 /* Sigma(x) set to 1 */ in atmel_pmecc_get_sigma()
531 delta[1] = (mu[1] * 2 - lmu[1]) >> 1; in atmel_pmecc_get_sigma()
533 /* Init the Sigma(x) last row */ in atmel_pmecc_get_sigma()
538 /* Begin Computing Sigma (Mu+1) and L(mu) */ in atmel_pmecc_get_sigma()
543 tmp = ((strength - (lmu[i] >> 1) - 1) / 2); in atmel_pmecc_get_sigma()
544 if ((strength - (lmu[i] >> 1) - 1) & 0x1) in atmel_pmecc_get_sigma()
566 largest = -1; in atmel_pmecc_get_sigma()
567 /* find largest delta with dmu != 0 */ in atmel_pmecc_get_sigma()
569 if ((dmu[j]) && (delta[j] > largest)) { in atmel_pmecc_get_sigma()
570 largest = delta[j]; in atmel_pmecc_get_sigma()
576 diff = (mu[i] - mu[ro]); in atmel_pmecc_get_sigma()
598 tmp = a + (cw_len - b) + c; in atmel_pmecc_get_sigma()
607 /* End Computing Sigma (Mu+1) and L(mu) */ in atmel_pmecc_get_sigma()
608 /* In either case compute delta */ in atmel_pmecc_get_sigma()
609 delta[i + 1] = (mu[i + 1] * 2 - lmu[i + 1]) >> 1; in atmel_pmecc_get_sigma()
616 tmp = 2 * (i - 1); in atmel_pmecc_get_sigma()
619 } else if (smu[(i + 1) * num + k] && si[tmp + 3 - k]) { in atmel_pmecc_get_sigma()
623 b = si[2 * (i - 1) + 3 - k]; in atmel_pmecc_get_sigma()
637 struct atmel_pmecc *pmecc = user->pmecc; in atmel_pmecc_err_location()
641 s16 *smu = user->smu; in atmel_pmecc_err_location()
644 writel(PMERRLOC_DISABLE, pmecc->regs.errloc + ATMEL_PMERRLOC_ELDIS); in atmel_pmecc_err_location()
646 for (i = 0; i <= user->lmu[strength + 1] >> 1; i++) { in atmel_pmecc_err_location()
648 pmecc->regs.errloc + ATMEL_PMERRLOC_SIGMA(i)); in atmel_pmecc_err_location()
652 val = (err_nbr - 1) << 16; in atmel_pmecc_err_location()
656 writel(val, pmecc->regs.errloc + ATMEL_PMERRLOC_ELCFG); in atmel_pmecc_err_location()
658 pmecc->regs.errloc + ATMEL_PMERRLOC_ELEN); in atmel_pmecc_err_location()
660 ret = readl_relaxed_poll_timeout(pmecc->regs.errloc + in atmel_pmecc_err_location()
665 dev_err(pmecc->dev, in atmel_pmecc_err_location()
672 if (roots_nbr == user->lmu[strength + 1] >> 1) in atmel_pmecc_err_location()
673 return err_nbr - 1; in atmel_pmecc_err_location()
679 return -EBADMSG; in atmel_pmecc_err_location()
685 struct atmel_pmecc *pmecc = user->pmecc; in atmel_pmecc_correct_sector()
687 int eccbytes = user->eccbytes; in atmel_pmecc_correct_sector()
690 if (!(user->isr & BIT(sector))) in atmel_pmecc_correct_sector()
707 errpos = readl_relaxed(pmecc->regs.errloc + in atmel_pmecc_correct_sector()
708 ATMEL_PMERRLOC_EL(pmecc->caps->el_offset, i)); in atmel_pmecc_correct_sector()
709 errpos--; in atmel_pmecc_correct_sector()
718 ptr = ecc + byte - sectorsize; in atmel_pmecc_correct_sector()
721 dev_dbg(pmecc->dev, in atmel_pmecc_correct_sector()
724 return -EINVAL; in atmel_pmecc_correct_sector()
727 dev_dbg(pmecc->dev, in atmel_pmecc_correct_sector()
728 "Bit flip in %s area, byte %d: 0x%02x -> 0x%02x\n", in atmel_pmecc_correct_sector()
740 return user->pmecc->caps->correct_erased_chunks; in atmel_pmecc_correct_erased_chunks()
747 struct atmel_pmecc *pmecc = user->pmecc; in atmel_pmecc_get_generated_eccbytes()
751 for (i = 0; i < user->eccbytes; i++) in atmel_pmecc_get_generated_eccbytes()
752 ptr[i] = readb_relaxed(pmecc->regs.base + in atmel_pmecc_get_generated_eccbytes()
759 writel(PMECC_CTRL_RST, pmecc->regs.base + ATMEL_PMECC_CTRL); in atmel_pmecc_reset()
760 writel(PMECC_CTRL_DISABLE, pmecc->regs.base + ATMEL_PMECC_CTRL); in atmel_pmecc_reset()
766 struct atmel_pmecc *pmecc = user->pmecc; in atmel_pmecc_enable()
770 dev_err(pmecc->dev, "Bad ECC operation!"); in atmel_pmecc_enable()
771 return -EINVAL; in atmel_pmecc_enable()
774 mutex_lock(&user->pmecc->lock); in atmel_pmecc_enable()
776 cfg = user->cache.cfg; in atmel_pmecc_enable()
782 writel(cfg, pmecc->regs.base + ATMEL_PMECC_CFG); in atmel_pmecc_enable()
783 writel(user->cache.sarea, pmecc->regs.base + ATMEL_PMECC_SAREA); in atmel_pmecc_enable()
784 writel(user->cache.saddr, pmecc->regs.base + ATMEL_PMECC_SADDR); in atmel_pmecc_enable()
785 writel(user->cache.eaddr, pmecc->regs.base + ATMEL_PMECC_EADDR); in atmel_pmecc_enable()
787 writel(PMECC_CTRL_ENABLE, pmecc->regs.base + ATMEL_PMECC_CTRL); in atmel_pmecc_enable()
788 writel(PMECC_CTRL_DATA, pmecc->regs.base + ATMEL_PMECC_CTRL); in atmel_pmecc_enable()
796 atmel_pmecc_reset(user->pmecc); in atmel_pmecc_disable()
797 mutex_unlock(&user->pmecc->lock); in atmel_pmecc_disable()
803 struct atmel_pmecc *pmecc = user->pmecc; in atmel_pmecc_wait_rdy()
807 ret = readl_relaxed_poll_timeout(pmecc->regs.base + in atmel_pmecc_wait_rdy()
812 dev_err(pmecc->dev, in atmel_pmecc_wait_rdy()
817 user->isr = readl_relaxed(pmecc->regs.base + ATMEL_PMECC_ISR); in atmel_pmecc_wait_rdy()
827 struct device *dev = &pdev->dev; in atmel_pmecc_create()
832 return ERR_PTR(-ENOMEM); in atmel_pmecc_create()
834 pmecc->caps = caps; in atmel_pmecc_create()
835 pmecc->dev = dev; in atmel_pmecc_create()
836 mutex_init(&pmecc->lock); in atmel_pmecc_create()
838 pmecc->regs.base = devm_platform_ioremap_resource(pdev, pmecc_res_idx); in atmel_pmecc_create()
839 if (IS_ERR(pmecc->regs.base)) in atmel_pmecc_create()
840 return ERR_CAST(pmecc->regs.base); in atmel_pmecc_create()
842 pmecc->regs.errloc = devm_platform_ioremap_resource(pdev, errloc_res_idx); in atmel_pmecc_create()
843 if (IS_ERR(pmecc->regs.errloc)) in atmel_pmecc_create()
844 return ERR_CAST(pmecc->regs.errloc); in atmel_pmecc_create()
847 writel(0xffffffff, pmecc->regs.base + ATMEL_PMECC_IDR); in atmel_pmecc_create()
857 put_device((*pmecc)->dev); in devm_atmel_pmecc_put()
869 return ERR_PTR(-EPROBE_DEFER); in atmel_pmecc_get_by_node()
872 ret = -EPROBE_DEFER; in atmel_pmecc_get_by_node()
878 ret = -ENOMEM; in atmel_pmecc_get_by_node()
889 put_device(&pdev->dev); in atmel_pmecc_get_by_node()
916 { .compatible = "atmel,sama5d4-nand", &sama5d4_caps },
917 { .compatible = "atmel,sama5d2-nand", &sama5d2_caps },
927 return ERR_PTR(-EINVAL); in devm_atmel_pmecc_get()
929 if (!userdev->of_node) in devm_atmel_pmecc_get()
932 np = of_parse_phandle(userdev->of_node, "ecc-engine", 0); in devm_atmel_pmecc_get()
947 if (!of_property_read_bool(userdev->of_node, in devm_atmel_pmecc_get()
948 "atmel,has-pmecc")) in devm_atmel_pmecc_get()
955 userdev->of_node); in devm_atmel_pmecc_get()
956 if (match && match->data) in devm_atmel_pmecc_get()
957 caps = match->data; in devm_atmel_pmecc_get()
967 { .compatible = "atmel,at91sam9g45-pmecc", &at91sam9g45_caps },
968 { .compatible = "atmel,sama5d4-pmecc", &sama5d4_caps },
969 { .compatible = "atmel,sama5d2-pmecc", &sama5d2_caps },
976 struct device *dev = &pdev->dev; in atmel_pmecc_probe()
980 caps = of_device_get_match_data(&pdev->dev); in atmel_pmecc_probe()
983 return -EINVAL; in atmel_pmecc_probe()
997 .name = "atmel-pmecc",
1005 MODULE_AUTHOR("Boris Brezillon <boris.brezillon@free-electrons.com>");