1 // SPDX-License-Identifier: GPL-2.0
4 * Copyright 2017 Free Electrons
6 * Author: Boris Brezillon <boris.brezillon@free-electrons.com>
8 * Derived from the atmel_nand.c driver which contained the following
11 * Copyright 2003 Rick Bronson
13 * Derived from drivers/mtd/nand/autcpu12.c (removed in v3.8)
14 * Copyright 2001 Thomas Gleixner (gleixner@autronix.de)
16 * Derived from drivers/mtd/spia.c (removed in v3.8)
17 * Copyright 2000 Steven J. Hill (sjhill@cotw.com)
19 * Add Hardware ECC support for AT91SAM9260 / AT91SAM9263
20 * Richard Genoud (richard.genoud@gmail.com), Adeneo Copyright 2007
22 * Derived from Das U-Boot source code
23 * (u-boot-1.1.5/board/atmel/at91sam9263ek/nand.c)
24 * Copyright 2006 ATMEL Rousset, Lacressonniere Nicolas
26 * Add Programmable Multibit ECC support for various AT91 SoC
27 * Copyright 2012 ATMEL, Hong Xu
29 * Add Nand Flash Controller support for SAMA5 SoC
30 * Copyright 2013 ATMEL, Josh Wu (josh.wu@atmel.com)
32 * The PMECC is an hardware assisted BCH engine, which means part of the
33 * ECC algorithm is left to the software. The hardware/software repartition
34 * is explained in the "PMECC Controller Functional Description" chapter in
35 * Atmel datasheets, and some of the functions in this file are directly
36 * implementing the algorithms described in the "Software Implementation"
39 * TODO: it seems that the software BCH implementation in lib/bch.c is already
40 * providing some of the logic we are implementing here. It would be smart
41 * to expose the needed lib/bch.c helpers/functions and re-use them here.
44 #include <linux/genalloc.h>
45 #include <linux/iopoll.h>
46 #include <linux/module.h>
47 #include <linux/mtd/rawnand.h>
48 #include <linux/of_irq.h>
49 #include <linux/of_platform.h>
50 #include <linux/platform_device.h>
51 #include <linux/slab.h>
55 /* Galois field dimension */
56 #define PMECC_GF_DIMENSION_13 13
57 #define PMECC_GF_DIMENSION_14 14
59 /* Primitive Polynomial used by PMECC */
60 #define PMECC_GF_13_PRIMITIVE_POLY 0x201b
61 #define PMECC_GF_14_PRIMITIVE_POLY 0x4443
63 #define PMECC_LOOKUP_TABLE_SIZE_512 0x2000
64 #define PMECC_LOOKUP_TABLE_SIZE_1024 0x4000
66 /* Time out value for reading PMECC status register */
67 #define PMECC_MAX_TIMEOUT_MS 100
69 /* PMECC Register Definitions */
70 #define ATMEL_PMECC_CFG 0x0
71 #define PMECC_CFG_BCH_STRENGTH(x) (x)
72 #define PMECC_CFG_BCH_STRENGTH_MASK GENMASK(2, 0)
73 #define PMECC_CFG_SECTOR512 (0 << 4)
74 #define PMECC_CFG_SECTOR1024 (1 << 4)
75 #define PMECC_CFG_NSECTORS(x) ((fls(x) - 1) << 8)
76 #define PMECC_CFG_READ_OP (0 << 12)
77 #define PMECC_CFG_WRITE_OP (1 << 12)
78 #define PMECC_CFG_SPARE_ENABLE BIT(16)
79 #define PMECC_CFG_AUTO_ENABLE BIT(20)
81 #define ATMEL_PMECC_SAREA 0x4
82 #define ATMEL_PMECC_SADDR 0x8
83 #define ATMEL_PMECC_EADDR 0xc
85 #define ATMEL_PMECC_CLK 0x10
86 #define PMECC_CLK_133MHZ (2 << 0)
88 #define ATMEL_PMECC_CTRL 0x14
89 #define PMECC_CTRL_RST BIT(0)
90 #define PMECC_CTRL_DATA BIT(1)
91 #define PMECC_CTRL_USER BIT(2)
92 #define PMECC_CTRL_ENABLE BIT(4)
93 #define PMECC_CTRL_DISABLE BIT(5)
95 #define ATMEL_PMECC_SR 0x18
96 #define PMECC_SR_BUSY BIT(0)
97 #define PMECC_SR_ENABLE BIT(4)
99 #define ATMEL_PMECC_IER 0x1c
100 #define ATMEL_PMECC_IDR 0x20
101 #define ATMEL_PMECC_IMR 0x24
102 #define ATMEL_PMECC_ISR 0x28
103 #define PMECC_ERROR_INT BIT(0)
105 #define ATMEL_PMECC_ECC(sector, n) \
106 ((((sector) + 1) * 0x40) + (n))
108 #define ATMEL_PMECC_REM(sector, n) \
109 ((((sector) + 1) * 0x40) + ((n) * 4) + 0x200)
111 /* PMERRLOC Register Definitions */
112 #define ATMEL_PMERRLOC_ELCFG 0x0
113 #define PMERRLOC_ELCFG_SECTOR_512 (0 << 0)
114 #define PMERRLOC_ELCFG_SECTOR_1024 (1 << 0)
115 #define PMERRLOC_ELCFG_NUM_ERRORS(n) ((n) << 16)
117 #define ATMEL_PMERRLOC_ELPRIM 0x4
118 #define ATMEL_PMERRLOC_ELEN 0x8
119 #define ATMEL_PMERRLOC_ELDIS 0xc
120 #define PMERRLOC_DISABLE BIT(0)
122 #define ATMEL_PMERRLOC_ELSR 0x10
123 #define PMERRLOC_ELSR_BUSY BIT(0)
125 #define ATMEL_PMERRLOC_ELIER 0x14
126 #define ATMEL_PMERRLOC_ELIDR 0x18
127 #define ATMEL_PMERRLOC_ELIMR 0x1c
128 #define ATMEL_PMERRLOC_ELISR 0x20
129 #define PMERRLOC_ERR_NUM_MASK GENMASK(12, 8)
130 #define PMERRLOC_CALC_DONE BIT(0)
132 #define ATMEL_PMERRLOC_SIGMA(x) (((x) * 0x4) + 0x28)
134 #define ATMEL_PMERRLOC_EL(offs, x) (((x) * 0x4) + (offs))
136 struct atmel_pmecc_gf_tables
{
141 struct atmel_pmecc_caps
{
142 const int *strengths
;
145 bool correct_erased_chunks
;
150 const struct atmel_pmecc_caps
*caps
;
154 void __iomem
*errloc
;
160 struct atmel_pmecc_user_conf_cache
{
167 struct atmel_pmecc_user
{
168 struct atmel_pmecc_user_conf_cache cache
;
169 struct atmel_pmecc
*pmecc
;
170 const struct atmel_pmecc_gf_tables
*gf_tables
;
182 static DEFINE_MUTEX(pmecc_gf_tables_lock
);
183 static const struct atmel_pmecc_gf_tables
*pmecc_gf_tables_512
;
184 static const struct atmel_pmecc_gf_tables
*pmecc_gf_tables_1024
;
186 static inline int deg(unsigned int poly
)
188 /* polynomial degree is the most-significant bit index */
189 return fls(poly
) - 1;
192 static int atmel_pmecc_build_gf_tables(int mm
, unsigned int poly
,
193 struct atmel_pmecc_gf_tables
*gf_tables
)
195 unsigned int i
, x
= 1;
196 const unsigned int k
= BIT(deg(poly
));
197 unsigned int nn
= BIT(mm
) - 1;
199 /* primitive polynomial must be of degree m */
203 for (i
= 0; i
< nn
; i
++) {
204 gf_tables
->alpha_to
[i
] = x
;
205 gf_tables
->index_of
[x
] = i
;
207 /* polynomial is not primitive (a^i=1 with 0<i<2^m-1) */
213 gf_tables
->alpha_to
[nn
] = 1;
214 gf_tables
->index_of
[0] = 0;
219 static const struct atmel_pmecc_gf_tables
*
220 atmel_pmecc_create_gf_tables(const struct atmel_pmecc_user_req
*req
)
222 struct atmel_pmecc_gf_tables
*gf_tables
;
223 unsigned int poly
, degree
, table_size
;
226 if (req
->ecc
.sectorsize
== 512) {
227 degree
= PMECC_GF_DIMENSION_13
;
228 poly
= PMECC_GF_13_PRIMITIVE_POLY
;
229 table_size
= PMECC_LOOKUP_TABLE_SIZE_512
;
231 degree
= PMECC_GF_DIMENSION_14
;
232 poly
= PMECC_GF_14_PRIMITIVE_POLY
;
233 table_size
= PMECC_LOOKUP_TABLE_SIZE_1024
;
236 gf_tables
= kzalloc(sizeof(*gf_tables
) +
237 (2 * table_size
* sizeof(u16
)),
240 return ERR_PTR(-ENOMEM
);
242 gf_tables
->alpha_to
= (void *)(gf_tables
+ 1);
243 gf_tables
->index_of
= gf_tables
->alpha_to
+ table_size
;
245 ret
= atmel_pmecc_build_gf_tables(degree
, poly
, gf_tables
);
254 static const struct atmel_pmecc_gf_tables
*
255 atmel_pmecc_get_gf_tables(const struct atmel_pmecc_user_req
*req
)
257 const struct atmel_pmecc_gf_tables
**gf_tables
, *ret
;
259 mutex_lock(&pmecc_gf_tables_lock
);
260 if (req
->ecc
.sectorsize
== 512)
261 gf_tables
= &pmecc_gf_tables_512
;
263 gf_tables
= &pmecc_gf_tables_1024
;
268 ret
= atmel_pmecc_create_gf_tables(req
);
272 mutex_unlock(&pmecc_gf_tables_lock
);
277 static int atmel_pmecc_prepare_user_req(struct atmel_pmecc
*pmecc
,
278 struct atmel_pmecc_user_req
*req
)
280 int i
, max_eccbytes
, eccbytes
= 0, eccstrength
= 0;
282 if (req
->pagesize
<= 0 || req
->oobsize
<= 0 || req
->ecc
.bytes
<= 0)
285 if (req
->ecc
.ooboffset
>= 0 &&
286 req
->ecc
.ooboffset
+ req
->ecc
.bytes
> req
->oobsize
)
289 if (req
->ecc
.sectorsize
== ATMEL_PMECC_SECTOR_SIZE_AUTO
) {
290 if (req
->ecc
.strength
!= ATMEL_PMECC_MAXIMIZE_ECC_STRENGTH
)
293 if (req
->pagesize
> 512)
294 req
->ecc
.sectorsize
= 1024;
296 req
->ecc
.sectorsize
= 512;
299 if (req
->ecc
.sectorsize
!= 512 && req
->ecc
.sectorsize
!= 1024)
302 if (req
->pagesize
% req
->ecc
.sectorsize
)
305 req
->ecc
.nsectors
= req
->pagesize
/ req
->ecc
.sectorsize
;
307 max_eccbytes
= req
->ecc
.bytes
;
309 for (i
= 0; i
< pmecc
->caps
->nstrengths
; i
++) {
310 int nbytes
, strength
= pmecc
->caps
->strengths
[i
];
312 if (req
->ecc
.strength
!= ATMEL_PMECC_MAXIMIZE_ECC_STRENGTH
&&
313 strength
< req
->ecc
.strength
)
316 nbytes
= DIV_ROUND_UP(strength
* fls(8 * req
->ecc
.sectorsize
),
318 nbytes
*= req
->ecc
.nsectors
;
320 if (nbytes
> max_eccbytes
)
323 eccstrength
= strength
;
326 if (req
->ecc
.strength
!= ATMEL_PMECC_MAXIMIZE_ECC_STRENGTH
)
333 req
->ecc
.bytes
= eccbytes
;
334 req
->ecc
.strength
= eccstrength
;
336 if (req
->ecc
.ooboffset
< 0)
337 req
->ecc
.ooboffset
= req
->oobsize
- eccbytes
;
342 struct atmel_pmecc_user
*
343 atmel_pmecc_create_user(struct atmel_pmecc
*pmecc
,
344 struct atmel_pmecc_user_req
*req
)
346 struct atmel_pmecc_user
*user
;
347 const struct atmel_pmecc_gf_tables
*gf_tables
;
348 int strength
, size
, ret
;
350 ret
= atmel_pmecc_prepare_user_req(pmecc
, req
);
354 size
= sizeof(*user
);
355 size
= ALIGN(size
, sizeof(u16
));
356 /* Reserve space for partial_syn, si and smu */
357 size
+= ((2 * req
->ecc
.strength
) + 1) * sizeof(u16
) *
358 (2 + req
->ecc
.strength
+ 2);
359 /* Reserve space for lmu. */
360 size
+= (req
->ecc
.strength
+ 1) * sizeof(u16
);
361 /* Reserve space for mu, dmu and delta. */
362 size
= ALIGN(size
, sizeof(s32
));
363 size
+= (req
->ecc
.strength
+ 1) * sizeof(s32
) * 3;
365 user
= kzalloc(size
, GFP_KERNEL
);
367 return ERR_PTR(-ENOMEM
);
371 user
->partial_syn
= (s16
*)PTR_ALIGN(user
+ 1, sizeof(u16
));
372 user
->si
= user
->partial_syn
+ ((2 * req
->ecc
.strength
) + 1);
373 user
->lmu
= user
->si
+ ((2 * req
->ecc
.strength
) + 1);
374 user
->smu
= user
->lmu
+ (req
->ecc
.strength
+ 1);
375 user
->mu
= (s32
*)PTR_ALIGN(user
->smu
+
376 (((2 * req
->ecc
.strength
) + 1) *
377 (req
->ecc
.strength
+ 2)),
379 user
->dmu
= user
->mu
+ req
->ecc
.strength
+ 1;
380 user
->delta
= user
->dmu
+ req
->ecc
.strength
+ 1;
382 gf_tables
= atmel_pmecc_get_gf_tables(req
);
383 if (IS_ERR(gf_tables
)) {
385 return ERR_CAST(gf_tables
);
388 user
->gf_tables
= gf_tables
;
390 user
->eccbytes
= req
->ecc
.bytes
/ req
->ecc
.nsectors
;
392 for (strength
= 0; strength
< pmecc
->caps
->nstrengths
; strength
++) {
393 if (pmecc
->caps
->strengths
[strength
] == req
->ecc
.strength
)
397 user
->cache
.cfg
= PMECC_CFG_BCH_STRENGTH(strength
) |
398 PMECC_CFG_NSECTORS(req
->ecc
.nsectors
);
400 if (req
->ecc
.sectorsize
== 1024)
401 user
->cache
.cfg
|= PMECC_CFG_SECTOR1024
;
403 user
->cache
.sarea
= req
->oobsize
- 1;
404 user
->cache
.saddr
= req
->ecc
.ooboffset
;
405 user
->cache
.eaddr
= req
->ecc
.ooboffset
+ req
->ecc
.bytes
- 1;
409 EXPORT_SYMBOL_GPL(atmel_pmecc_create_user
);
411 void atmel_pmecc_destroy_user(struct atmel_pmecc_user
*user
)
415 EXPORT_SYMBOL_GPL(atmel_pmecc_destroy_user
);
417 static int get_strength(struct atmel_pmecc_user
*user
)
419 const int *strengths
= user
->pmecc
->caps
->strengths
;
421 return strengths
[user
->cache
.cfg
& PMECC_CFG_BCH_STRENGTH_MASK
];
424 static int get_sectorsize(struct atmel_pmecc_user
*user
)
426 return user
->cache
.cfg
& PMECC_CFG_SECTOR1024
? 1024 : 512;
429 static void atmel_pmecc_gen_syndrome(struct atmel_pmecc_user
*user
, int sector
)
431 int strength
= get_strength(user
);
435 /* Fill odd syndromes */
436 for (i
= 0; i
< strength
; i
++) {
437 value
= readl_relaxed(user
->pmecc
->regs
.base
+
438 ATMEL_PMECC_REM(sector
, i
/ 2));
442 user
->partial_syn
[(2 * i
) + 1] = value
;
446 static void atmel_pmecc_substitute(struct atmel_pmecc_user
*user
)
448 int degree
= get_sectorsize(user
) == 512 ? 13 : 14;
449 int cw_len
= BIT(degree
) - 1;
450 int strength
= get_strength(user
);
451 s16
*alpha_to
= user
->gf_tables
->alpha_to
;
452 s16
*index_of
= user
->gf_tables
->index_of
;
453 s16
*partial_syn
= user
->partial_syn
;
458 * si[] is a table that holds the current syndrome value,
459 * an element of that table belongs to the field
463 memset(&si
[1], 0, sizeof(s16
) * ((2 * strength
) - 1));
465 /* Computation 2t syndromes based on S(x) */
467 for (i
= 1; i
< 2 * strength
; i
+= 2) {
468 for (j
= 0; j
< degree
; j
++) {
469 if (partial_syn
[i
] & BIT(j
))
470 si
[i
] = alpha_to
[i
* j
] ^ si
[i
];
473 /* Even syndrome = (Odd syndrome) ** 2 */
474 for (i
= 2, j
= 1; j
<= strength
; i
= ++j
<< 1) {
480 tmp
= index_of
[si
[j
]];
481 tmp
= (tmp
* 2) % cw_len
;
482 si
[i
] = alpha_to
[tmp
];
487 static void atmel_pmecc_get_sigma(struct atmel_pmecc_user
*user
)
489 s16
*lmu
= user
->lmu
;
492 s32
*dmu
= user
->dmu
;
493 s32
*delta
= user
->delta
;
494 int degree
= get_sectorsize(user
) == 512 ? 13 : 14;
495 int cw_len
= BIT(degree
) - 1;
496 int strength
= get_strength(user
);
497 int num
= 2 * strength
+ 1;
498 s16
*index_of
= user
->gf_tables
->index_of
;
499 s16
*alpha_to
= user
->gf_tables
->alpha_to
;
501 u32 dmu_0_count
, tmp
;
502 s16
*smu
= user
->smu
;
504 /* index of largest delta */
516 memset(smu
, 0, sizeof(s16
) * num
);
519 /* discrepancy set to 1 */
521 /* polynom order set to 0 */
523 delta
[0] = (mu
[0] * 2 - lmu
[0]) >> 1;
529 /* Sigma(x) set to 1 */
530 memset(&smu
[num
], 0, sizeof(s16
) * num
);
533 /* discrepancy set to S1 */
536 /* polynom order set to 0 */
539 delta
[1] = (mu
[1] * 2 - lmu
[1]) >> 1;
541 /* Init the Sigma(x) last row */
542 memset(&smu
[(strength
+ 1) * num
], 0, sizeof(s16
) * num
);
544 for (i
= 1; i
<= strength
; i
++) {
546 /* Begin Computing Sigma (Mu+1) and L(mu) */
547 /* check if discrepancy is set to 0 */
551 tmp
= ((strength
- (lmu
[i
] >> 1) - 1) / 2);
552 if ((strength
- (lmu
[i
] >> 1) - 1) & 0x1)
557 if (dmu_0_count
== tmp
) {
558 for (j
= 0; j
<= (lmu
[i
] >> 1) + 1; j
++)
559 smu
[(strength
+ 1) * num
+ j
] =
562 lmu
[strength
+ 1] = lmu
[i
];
567 for (j
= 0; j
<= lmu
[i
] >> 1; j
++)
568 smu
[(i
+ 1) * num
+ j
] = smu
[i
* num
+ j
];
570 /* copy previous polynom order to the next */
575 /* find largest delta with dmu != 0 */
576 for (j
= 0; j
< i
; j
++) {
577 if ((dmu
[j
]) && (delta
[j
] > largest
)) {
583 /* compute difference */
584 diff
= (mu
[i
] - mu
[ro
]);
586 /* Compute degree of the new smu polynomial */
587 if ((lmu
[i
] >> 1) > ((lmu
[ro
] >> 1) + diff
))
590 lmu
[i
+ 1] = ((lmu
[ro
] >> 1) + diff
) * 2;
592 /* Init smu[i+1] with 0 */
593 for (k
= 0; k
< num
; k
++)
594 smu
[(i
+ 1) * num
+ k
] = 0;
596 /* Compute smu[i+1] */
597 for (k
= 0; k
<= lmu
[ro
] >> 1; k
++) {
600 if (!(smu
[ro
* num
+ k
] && dmu
[i
]))
603 a
= index_of
[dmu
[i
]];
604 b
= index_of
[dmu
[ro
]];
605 c
= index_of
[smu
[ro
* num
+ k
]];
606 tmp
= a
+ (cw_len
- b
) + c
;
607 a
= alpha_to
[tmp
% cw_len
];
608 smu
[(i
+ 1) * num
+ (k
+ diff
)] = a
;
611 for (k
= 0; k
<= lmu
[i
] >> 1; k
++)
612 smu
[(i
+ 1) * num
+ k
] ^= smu
[i
* num
+ k
];
615 /* End Computing Sigma (Mu+1) and L(mu) */
616 /* In either case compute delta */
617 delta
[i
+ 1] = (mu
[i
+ 1] * 2 - lmu
[i
+ 1]) >> 1;
619 /* Do not compute discrepancy for the last iteration */
623 for (k
= 0; k
<= (lmu
[i
+ 1] >> 1); k
++) {
626 dmu
[i
+ 1] = si
[tmp
+ 3];
627 } else if (smu
[(i
+ 1) * num
+ k
] && si
[tmp
+ 3 - k
]) {
630 a
= index_of
[smu
[(i
+ 1) * num
+ k
]];
631 b
= si
[2 * (i
- 1) + 3 - k
];
635 dmu
[i
+ 1] = alpha_to
[tmp
] ^ dmu
[i
+ 1];
641 static int atmel_pmecc_err_location(struct atmel_pmecc_user
*user
)
643 int sector_size
= get_sectorsize(user
);
644 int degree
= sector_size
== 512 ? 13 : 14;
645 struct atmel_pmecc
*pmecc
= user
->pmecc
;
646 int strength
= get_strength(user
);
647 int ret
, roots_nbr
, i
, err_nbr
= 0;
648 int num
= (2 * strength
) + 1;
649 s16
*smu
= user
->smu
;
652 writel(PMERRLOC_DISABLE
, pmecc
->regs
.errloc
+ ATMEL_PMERRLOC_ELDIS
);
654 for (i
= 0; i
<= user
->lmu
[strength
+ 1] >> 1; i
++) {
655 writel_relaxed(smu
[(strength
+ 1) * num
+ i
],
656 pmecc
->regs
.errloc
+ ATMEL_PMERRLOC_SIGMA(i
));
660 val
= (err_nbr
- 1) << 16;
661 if (sector_size
== 1024)
664 writel(val
, pmecc
->regs
.errloc
+ ATMEL_PMERRLOC_ELCFG
);
665 writel((sector_size
* 8) + (degree
* strength
),
666 pmecc
->regs
.errloc
+ ATMEL_PMERRLOC_ELEN
);
668 ret
= readl_relaxed_poll_timeout(pmecc
->regs
.errloc
+
669 ATMEL_PMERRLOC_ELISR
,
670 val
, val
& PMERRLOC_CALC_DONE
, 0,
671 PMECC_MAX_TIMEOUT_MS
* 1000);
674 "PMECC: Timeout to calculate error location.\n");
678 roots_nbr
= (val
& PMERRLOC_ERR_NUM_MASK
) >> 8;
679 /* Number of roots == degree of smu hence <= cap */
680 if (roots_nbr
== user
->lmu
[strength
+ 1] >> 1)
684 * Number of roots does not match the degree of smu
685 * unable to correct error.
690 int atmel_pmecc_correct_sector(struct atmel_pmecc_user
*user
, int sector
,
691 void *data
, void *ecc
)
693 struct atmel_pmecc
*pmecc
= user
->pmecc
;
694 int sectorsize
= get_sectorsize(user
);
695 int eccbytes
= user
->eccbytes
;
698 if (!(user
->isr
& BIT(sector
)))
701 atmel_pmecc_gen_syndrome(user
, sector
);
702 atmel_pmecc_substitute(user
);
703 atmel_pmecc_get_sigma(user
);
705 nerrors
= atmel_pmecc_err_location(user
);
709 for (i
= 0; i
< nerrors
; i
++) {
715 errpos
= readl_relaxed(pmecc
->regs
.errloc
+
716 ATMEL_PMERRLOC_EL(pmecc
->caps
->el_offset
, i
));
722 if (byte
< sectorsize
) {
725 } else if (byte
< sectorsize
+ eccbytes
) {
726 ptr
= ecc
+ byte
- sectorsize
;
730 "Invalid errpos value (%d, max is %d)\n",
731 errpos
, (sectorsize
+ eccbytes
) * 8);
736 "Bit flip in %s area, byte %d: 0x%02x -> 0x%02x\n",
737 area
, byte
, *ptr
, (unsigned int)(*ptr
^ BIT(bit
)));
744 EXPORT_SYMBOL_GPL(atmel_pmecc_correct_sector
);
746 bool atmel_pmecc_correct_erased_chunks(struct atmel_pmecc_user
*user
)
748 return user
->pmecc
->caps
->correct_erased_chunks
;
750 EXPORT_SYMBOL_GPL(atmel_pmecc_correct_erased_chunks
);
752 void atmel_pmecc_get_generated_eccbytes(struct atmel_pmecc_user
*user
,
753 int sector
, void *ecc
)
755 struct atmel_pmecc
*pmecc
= user
->pmecc
;
759 for (i
= 0; i
< user
->eccbytes
; i
++)
760 ptr
[i
] = readb_relaxed(pmecc
->regs
.base
+
761 ATMEL_PMECC_ECC(sector
, i
));
763 EXPORT_SYMBOL_GPL(atmel_pmecc_get_generated_eccbytes
);
765 void atmel_pmecc_reset(struct atmel_pmecc
*pmecc
)
767 writel(PMECC_CTRL_RST
, pmecc
->regs
.base
+ ATMEL_PMECC_CTRL
);
768 writel(PMECC_CTRL_DISABLE
, pmecc
->regs
.base
+ ATMEL_PMECC_CTRL
);
770 EXPORT_SYMBOL_GPL(atmel_pmecc_reset
);
772 int atmel_pmecc_enable(struct atmel_pmecc_user
*user
, int op
)
774 struct atmel_pmecc
*pmecc
= user
->pmecc
;
777 if (op
!= NAND_ECC_READ
&& op
!= NAND_ECC_WRITE
) {
778 dev_err(pmecc
->dev
, "Bad ECC operation!");
782 mutex_lock(&user
->pmecc
->lock
);
784 cfg
= user
->cache
.cfg
;
785 if (op
== NAND_ECC_WRITE
)
786 cfg
|= PMECC_CFG_WRITE_OP
;
788 cfg
|= PMECC_CFG_AUTO_ENABLE
;
790 writel(cfg
, pmecc
->regs
.base
+ ATMEL_PMECC_CFG
);
791 writel(user
->cache
.sarea
, pmecc
->regs
.base
+ ATMEL_PMECC_SAREA
);
792 writel(user
->cache
.saddr
, pmecc
->regs
.base
+ ATMEL_PMECC_SADDR
);
793 writel(user
->cache
.eaddr
, pmecc
->regs
.base
+ ATMEL_PMECC_EADDR
);
795 writel(PMECC_CTRL_ENABLE
, pmecc
->regs
.base
+ ATMEL_PMECC_CTRL
);
796 writel(PMECC_CTRL_DATA
, pmecc
->regs
.base
+ ATMEL_PMECC_CTRL
);
800 EXPORT_SYMBOL_GPL(atmel_pmecc_enable
);
802 void atmel_pmecc_disable(struct atmel_pmecc_user
*user
)
804 atmel_pmecc_reset(user
->pmecc
);
805 mutex_unlock(&user
->pmecc
->lock
);
807 EXPORT_SYMBOL_GPL(atmel_pmecc_disable
);
809 int atmel_pmecc_wait_rdy(struct atmel_pmecc_user
*user
)
811 struct atmel_pmecc
*pmecc
= user
->pmecc
;
815 ret
= readl_relaxed_poll_timeout(pmecc
->regs
.base
+
817 status
, !(status
& PMECC_SR_BUSY
), 0,
818 PMECC_MAX_TIMEOUT_MS
* 1000);
821 "Timeout while waiting for PMECC ready.\n");
825 user
->isr
= readl_relaxed(pmecc
->regs
.base
+ ATMEL_PMECC_ISR
);
829 EXPORT_SYMBOL_GPL(atmel_pmecc_wait_rdy
);
831 static struct atmel_pmecc
*atmel_pmecc_create(struct platform_device
*pdev
,
832 const struct atmel_pmecc_caps
*caps
,
833 int pmecc_res_idx
, int errloc_res_idx
)
835 struct device
*dev
= &pdev
->dev
;
836 struct atmel_pmecc
*pmecc
;
837 struct resource
*res
;
839 pmecc
= devm_kzalloc(dev
, sizeof(*pmecc
), GFP_KERNEL
);
841 return ERR_PTR(-ENOMEM
);
845 mutex_init(&pmecc
->lock
);
847 res
= platform_get_resource(pdev
, IORESOURCE_MEM
, pmecc_res_idx
);
848 pmecc
->regs
.base
= devm_ioremap_resource(dev
, res
);
849 if (IS_ERR(pmecc
->regs
.base
))
850 return ERR_CAST(pmecc
->regs
.base
);
852 res
= platform_get_resource(pdev
, IORESOURCE_MEM
, errloc_res_idx
);
853 pmecc
->regs
.errloc
= devm_ioremap_resource(dev
, res
);
854 if (IS_ERR(pmecc
->regs
.errloc
))
855 return ERR_CAST(pmecc
->regs
.errloc
);
857 /* Disable all interrupts before registering the PMECC handler. */
858 writel(0xffffffff, pmecc
->regs
.base
+ ATMEL_PMECC_IDR
);
859 atmel_pmecc_reset(pmecc
);
864 static void devm_atmel_pmecc_put(struct device
*dev
, void *res
)
866 struct atmel_pmecc
**pmecc
= res
;
868 put_device((*pmecc
)->dev
);
871 static struct atmel_pmecc
*atmel_pmecc_get_by_node(struct device
*userdev
,
872 struct device_node
*np
)
874 struct platform_device
*pdev
;
875 struct atmel_pmecc
*pmecc
, **ptr
;
878 pdev
= of_find_device_by_node(np
);
880 return ERR_PTR(-EPROBE_DEFER
);
881 pmecc
= platform_get_drvdata(pdev
);
887 ptr
= devres_alloc(devm_atmel_pmecc_put
, sizeof(*ptr
), GFP_KERNEL
);
895 devres_add(userdev
, ptr
);
900 put_device(&pdev
->dev
);
904 static const int atmel_pmecc_strengths
[] = { 2, 4, 8, 12, 24, 32 };
906 static struct atmel_pmecc_caps at91sam9g45_caps
= {
907 .strengths
= atmel_pmecc_strengths
,
912 static struct atmel_pmecc_caps sama5d4_caps
= {
913 .strengths
= atmel_pmecc_strengths
,
916 .correct_erased_chunks
= true,
919 static struct atmel_pmecc_caps sama5d2_caps
= {
920 .strengths
= atmel_pmecc_strengths
,
923 .correct_erased_chunks
= true,
926 static const struct of_device_id atmel_pmecc_legacy_match
[] = {
927 { .compatible
= "atmel,sama5d4-nand", &sama5d4_caps
},
928 { .compatible
= "atmel,sama5d2-nand", &sama5d2_caps
},
932 struct atmel_pmecc
*devm_atmel_pmecc_get(struct device
*userdev
)
934 struct atmel_pmecc
*pmecc
;
935 struct device_node
*np
;
938 return ERR_PTR(-EINVAL
);
940 if (!userdev
->of_node
)
943 np
= of_parse_phandle(userdev
->of_node
, "ecc-engine", 0);
945 pmecc
= atmel_pmecc_get_by_node(userdev
, np
);
949 * Support old DT bindings: in this case the PMECC iomem
950 * resources are directly defined in the user pdev at position
951 * 1 and 2. Extract all relevant information from there.
953 struct platform_device
*pdev
= to_platform_device(userdev
);
954 const struct atmel_pmecc_caps
*caps
;
955 const struct of_device_id
*match
;
957 /* No PMECC engine available. */
958 if (!of_property_read_bool(userdev
->of_node
,
962 caps
= &at91sam9g45_caps
;
964 /* Find the caps associated to the NAND dev node. */
965 match
= of_match_node(atmel_pmecc_legacy_match
,
967 if (match
&& match
->data
)
970 pmecc
= atmel_pmecc_create(pdev
, caps
, 1, 2);
975 EXPORT_SYMBOL(devm_atmel_pmecc_get
);
977 static const struct of_device_id atmel_pmecc_match
[] = {
978 { .compatible
= "atmel,at91sam9g45-pmecc", &at91sam9g45_caps
},
979 { .compatible
= "atmel,sama5d4-pmecc", &sama5d4_caps
},
980 { .compatible
= "atmel,sama5d2-pmecc", &sama5d2_caps
},
983 MODULE_DEVICE_TABLE(of
, atmel_pmecc_match
);
985 static int atmel_pmecc_probe(struct platform_device
*pdev
)
987 struct device
*dev
= &pdev
->dev
;
988 const struct atmel_pmecc_caps
*caps
;
989 struct atmel_pmecc
*pmecc
;
991 caps
= of_device_get_match_data(&pdev
->dev
);
993 dev_err(dev
, "Invalid caps\n");
997 pmecc
= atmel_pmecc_create(pdev
, caps
, 0, 1);
999 return PTR_ERR(pmecc
);
1001 platform_set_drvdata(pdev
, pmecc
);
1006 static struct platform_driver atmel_pmecc_driver
= {
1008 .name
= "atmel-pmecc",
1009 .of_match_table
= of_match_ptr(atmel_pmecc_match
),
1011 .probe
= atmel_pmecc_probe
,
1013 module_platform_driver(atmel_pmecc_driver
);
1015 MODULE_LICENSE("GPL");
1016 MODULE_AUTHOR("Boris Brezillon <boris.brezillon@free-electrons.com>");
1017 MODULE_DESCRIPTION("PMECC engine driver");
1018 MODULE_ALIAS("platform:atmel_pmecc");