1 /* ----------------------------------------------------------------------------
\r
2 * SAM Software Package License
\r
3 * ----------------------------------------------------------------------------
\r
4 * Copyright (c) 2012, Atmel Corporation
\r
5 * All rights reserved.
\r
7 * Redistribution and use in source and binary forms, with or without
\r
8 * modification, are permitted provided that the following conditions are met:
\r
10 * - Redistributions of source code must retain the above copyright notice,
\r
11 * this list of conditions and the disclaimer below.
\r
13 * Atmel's name may not be used to endorse or promote products derived from
\r
14 * this software without specific prior written permission.
\r
16 * DISCLAIMER: THIS SOFTWARE IS PROVIDED BY ATMEL "AS IS" AND ANY EXPRESS OR
\r
17 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
\r
18 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT ARE
\r
19 * DISCLAIMED. IN NO EVENT SHALL ATMEL BE LIABLE FOR ANY DIRECT, INDIRECT,
\r
20 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
\r
21 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA,
\r
22 * OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
\r
23 * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
\r
24 * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
\r
25 * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
\r
26 * ----------------------------------------------------------------------------
\r
31 /*----------------------------------------------------------------------------
\r
33 *----------------------------------------------------------------------------*/
\r
38 #include "peripherals/pmecc.h"
\r
39 #include "peripherals/pmecc_gallois_field_512.h"
\r
40 #include "peripherals/pmecc_gallois_field_1024.h"
\r
42 /*--------------------------------------------------------------------------- */
\r
44 /*--------------------------------------------------------------------------- */
\r
46 /** PMECC configuration descriptor */
\r
47 struct _pmecc_descriptor {
\r
48 /** Number of Sectors in one Page */
\r
51 /** The spare area size is equal to (SPARESIZE+1) bytes */
\r
52 uint32_t spare_size;
\r
54 /** 0 for 512, 1 for 1024 bytes, like in PMECCFG register */
\r
55 uint32_t sector_size;
\r
57 /** Coded value of ECC bit number correction
\r
58 * 0 (2 bits), 1 (4 bits), 2 (8 bits), 3 (12 bits), 4 (24 bits), 5 (NU)) */
\r
59 uint32_t err_bit_nbr_capability;
\r
61 /** Real size in bytes of ECC in spare */
\r
62 uint32_t ecc_size_byte;
\r
64 /** The first byte address of the ECC area */
\r
65 uint32_t ecc_start_address;
\r
67 /** The last byte address of the ECC area */
\r
68 uint32_t ecc_end_address;
\r
70 /** NAND Write Access*/
\r
76 /** Automatic Mode */
\r
79 /** The PMECC Module data path Setup Time is set to CLKCTRL+1. */
\r
85 /** defines the error correcting capability selected at encoding/decoding time */
\r
88 /** degree of the remainders, GF(2**mm) */
\r
91 /** length of codeword = nn=2**mm -1 */
\r
94 /** Gallois field table */
\r
95 const int16_t *alpha_to;
\r
97 /** Index of Gallois field table */
\r
98 const int16_t *index_of;
\r
101 int16_t partial_syn[100];
\r
103 /** Holds the current syndrome value, an element of that table belongs to the field.*/
\r
107 int16_t smu[PMECC_NB_ERROR_MAX + 2][2 * PMECC_NB_ERROR_MAX + 1];
\r
109 /** polynom order */
\r
110 int16_t lmu[PMECC_NB_ERROR_MAX + 1];
\r
113 /*--------------------------------------------------------------------------- */
\r
114 /* Local variables */
\r
115 /*--------------------------------------------------------------------------- */
\r
117 /** Pmecc decriptor instance */
\r
118 struct _pmecc_descriptor pmecc_desc;
\r
120 /*----------------------------------------------------------------------------
\r
122 *----------------------------------------------------------------------------*/
\r
125 * \brief Build the pseudo syndromes table
\r
126 * \param sector Targetted sector.
\r
128 static void gen_syn(uint32_t sector)
\r
133 remainer = (int16_t*)&HSMC->SMC_REM[sector];
\r
134 for (index = 0; index < (uint32_t)pmecc_desc.tt; index++) {
\r
135 /* Fill odd syndromes */
\r
136 pmecc_desc.partial_syn[1 + (2 * index)] = remainer[index];
\r
141 * \brief The substitute function evaluates the polynomial remainder,
\r
142 * with different values of the field primitive elements.
\r
144 static uint32_t substitute(void)
\r
148 int16_t *p_partial_syn = pmecc_desc.partial_syn;
\r
149 const int16_t *alpha_to = pmecc_desc.alpha_to;
\r
150 const int16_t *index_of = pmecc_desc.index_of;
\r
152 /* si[] is a table that holds the current syndrome value, an element of that table belongs to the field.*/
\r
153 si = pmecc_desc.si;
\r
155 for (i = 1; i < 2 * PMECC_NB_ERROR_MAX; i++)
\r
158 /* Computation 2t syndromes based on S(x) */
\r
159 /* Odd syndromes */
\r
160 for (i = 1; i <= 2 * pmecc_desc.tt - 1; i = i + 2) {
\r
162 for (j = 0; j < pmecc_desc.mm; j++) {
\r
163 if (p_partial_syn[i] & ((uint16_t)0x1 << j))
\r
164 si[i] = alpha_to[(i * j)] ^ si[i];
\r
167 /* Even syndrome = (Odd syndrome) ** 2 */
\r
168 for (i = 2; i <= 2 * pmecc_desc.tt; i = i + 2) {
\r
173 si[i] = alpha_to[(2 * index_of[si[j]]) % pmecc_desc.nn];
\r
180 * \brief The substitute function finding the value of the error
\r
181 * location polynomial.
\r
183 static uint32_t get_sigma(void)
\r
185 uint32_t dmu_0_count;
\r
187 int16_t *lmu = pmecc_desc.lmu;
\r
188 int16_t *si = pmecc_desc.si;
\r
189 int16_t tt = pmecc_desc.tt;
\r
191 int32_t mu[PMECC_NB_ERROR_MAX+1]; /* mu */
\r
192 int32_t dmu[PMECC_NB_ERROR_MAX+1]; /* discrepancy */
\r
193 int32_t delta[PMECC_NB_ERROR_MAX+1]; /* delta order */
\r
194 int32_t ro; /* index of largest delta */
\r
200 /* -- First Row -- */
\r
204 /* Actually -1/2 */
\r
205 /* Sigma(x) set to 1 */
\r
207 for (i = 0; i < (2 * PMECC_NB_ERROR_MAX + 1); i++)
\r
208 pmecc_desc.smu[0][i] = 0;
\r
209 pmecc_desc.smu[0][0] = 1;
\r
211 /* discrepancy set to 1 */
\r
214 /* polynom order set to 0 */
\r
217 /* delta set to -1 */
\r
218 delta[0] = (mu[0] * 2 - lmu[0]) >> 1;
\r
220 /* -- Second Row -- */
\r
225 /* Sigma(x) set to 1 */
\r
226 for (i = 0; i < (2 * PMECC_NB_ERROR_MAX + 1); i++)
\r
227 pmecc_desc.smu[1][i] = 0;
\r
228 pmecc_desc.smu[1][0] = 1;
\r
230 /* discrepancy set to S1 */
\r
233 /* polynom order set to 0 */
\r
236 /* delta set to 0 */
\r
237 delta[1] = (mu[1] * 2 - lmu[1]) >> 1;
\r
239 /* Init the Sigma(x) last row */
\r
240 for (i = 0; i < (2 * PMECC_NB_ERROR_MAX + 1); i++)
\r
241 pmecc_desc.smu[tt + 1][i] = 0;
\r
243 for (i = 1; i <= tt; i++) {
\r
246 /* Compute Sigma (Mu+1) */
\r
248 /* check if discrepancy is set to 0 */
\r
249 if ( dmu[i] == 0) {
\r
251 if (( tt - (lmu[i] >> 1) - 1) & 0x1) {
\r
252 if (dmu_0_count == (uint32_t)((tt - (lmu[i] >> 1) - 1) / 2) + 2) {
\r
253 for (j = 0; j <= (lmu[i] >> 1) + 1; j++)
\r
254 pmecc_desc.smu[tt+1][j] = pmecc_desc.smu[i][j];
\r
255 lmu[tt + 1] = lmu[i];
\r
259 if (dmu_0_count == (uint32_t)((tt - (lmu[i] >> 1) - 1) / 2) + 1) {
\r
260 for (j = 0; j <= (lmu[i] >> 1) + 1; j++)
\r
261 pmecc_desc.smu[tt + 1][j] = pmecc_desc.smu[i][j];
\r
262 lmu[tt + 1] = lmu[i];
\r
268 for (j = 0; j <= (lmu[i] >> 1); j++)
\r
269 pmecc_desc.smu[i + 1][j] = pmecc_desc.smu[i][j];
\r
271 /* copy previous polynom order to the next */
\r
272 lmu[i + 1] = lmu[i];
\r
274 /* find largest delta with dmu != 0 */
\r
277 for (j = 0; j < i; j++) {
\r
279 if (delta[j] > largest) {
\r
280 largest = delta[j];
\r
286 /* compute difference */
\r
287 diff = (mu[i] - mu[ro]);
\r
289 /* Compute degree of the new smu polynomial */
\r
290 if ((lmu[i] >> 1) > ((lmu[ro] >> 1) + diff))
\r
291 lmu[i + 1] = lmu[i];
\r
293 lmu[i + 1] = ((lmu[ro] >> 1) + diff) * 2;
\r
295 /* Init smu[i+1] with 0 */
\r
296 for (k = 0; k < (2 * PMECC_NB_ERROR_MAX + 1); k++)
\r
297 pmecc_desc.smu[i+1][k] = 0;
\r
299 /* Compute smu[i+1] */
\r
300 for (k = 0; k <= (lmu[ro] >> 1); k++) {
\r
301 if (pmecc_desc.smu[ro][k] && dmu[i])
\r
302 pmecc_desc.smu[i + 1][k + diff] = pmecc_desc.alpha_to[(pmecc_desc.index_of[dmu[i]] +
\r
303 (pmecc_desc.nn - pmecc_desc.index_of[dmu[ro]]) +
\r
304 pmecc_desc.index_of[pmecc_desc.smu[ro][k]]) % pmecc_desc.nn];
\r
306 for (k = 0; k <= (lmu[i] >> 1); k++)
\r
307 pmecc_desc.smu[i+1][k] ^= pmecc_desc.smu[i][k];
\r
310 /*************************************************/
\r
311 /* End Compute Sigma (Mu+1) */
\r
313 /*************************************************/
\r
314 /* In either case compute delta */
\r
315 delta[i + 1] = (mu[i + 1] * 2 - lmu[i + 1]) >> 1;
\r
317 /* Do not compute discrepancy for the last iteration */
\r
319 for (k = 0 ; k <= (lmu[i + 1] >> 1); k++) {
\r
321 dmu[i + 1] = si[2 * (i - 1) + 3];
\r
322 /* check if one operand of the multiplier is null, its index is -1 */
\r
323 else if (pmecc_desc.smu[i+1][k] && si[2 * (i - 1) + 3 - k])
\r
324 dmu[i + 1] = pmecc_desc.alpha_to[(pmecc_desc.index_of[pmecc_desc.smu[i + 1][k]] +
\r
325 pmecc_desc.index_of[si[2 * (i - 1) + 3 - k]]) % pmecc_desc.nn] ^ dmu[i + 1];
\r
333 * \brief Init the PMECC Error Location peripheral and start the error
\r
334 * location processing
\r
335 * \param sector_size_in_bits Size of the sector in bits.
\r
336 * \return Number of errors
\r
338 static int32_t error_location (uint32_t sector_size_in_bits)
\r
342 uint32_t error_number;
\r
343 uint32_t nbr_of_roots;
\r
345 /* Disable PMECC Error Location IP */
\r
346 HSMC->HSMC_ELDIS |= 0xFFFFFFFF;
\r
350 sigma = (uint32_t*)&HSMC->HSMC_SIGMA0;
\r
352 for (alphax = 0; alphax <= (uint32_t)(pmecc_desc.lmu[pmecc_desc.tt + 1] >> 1); alphax++) {
\r
353 *sigma++ = pmecc_desc.smu[pmecc_desc.tt + 1][alphax];
\r
357 /* Enable error location process */
\r
358 HSMC->HSMC_ELCFG |= ((error_number - 1) << 16);
\r
359 HSMC->HSMC_ELEN = sector_size_in_bits;
\r
361 while ((HSMC->HSMC_ELISR & HSMC_ELISR_DONE) == 0);
\r
363 nbr_of_roots = (HSMC->HSMC_ELISR & HSMC_ELISR_ERR_CNT_Msk) >> 8;
\r
364 /* Number of roots == degree of smu hence <= tt */
\r
365 if (nbr_of_roots == (uint32_t)(pmecc_desc.lmu[pmecc_desc.tt + 1] >> 1))
\r
366 return (error_number - 1);
\r
368 /* Number of roots not match the degree of smu ==> unable to correct error */
\r
373 * \brief Correct errors indicated in the PMECCEL error location registers.
\r
374 * \param sector_base_address Base address of the sector.
\r
375 * \param extra_bytes Number of extra bytes of the sector.(encoded Spare Area, only for the last sector)
\r
376 * \param error_nbr Number of error to correct
\r
377 * \return Number of errors
\r
379 static uint32_t error_correction(uint32_t sector_base_address, uint32_t extra_bytes, uint32_t error_nbr)
\r
381 uint32_t *error_pos;
\r
384 uint32_t sector_size;
\r
386 uint32_t ecc_end_addr;
\r
388 error_pos = (uint32_t*)&HSMC->HSMC_ERRLOC0;
\r
390 sector_size = 512 * (((HSMC->HSMC_PMECCFG & HSMC_PMECCFG_SECTORSZ) >> 4) + 1);
\r
392 /* Get number of ECC bytes */
\r
393 ecc_end_addr = HSMC->HSMC_PMECCEADDR;
\r
394 ecc_size = (ecc_end_addr - HSMC->HSMC_PMECCSADDR) + 1;
\r
396 while (error_nbr) {
\r
397 byte_pos = (*error_pos - 1) / 8;
\r
398 bit_pos = (*error_pos - 1) % 8;
\r
400 /* If error is located in the data area(not in ECC) */
\r
401 if ( byte_pos < (sector_size + extra_bytes)) {
\r
402 uint8_t *data_ptr = NULL;
\r
404 /* If the error position is before ECC area */
\r
405 if ( byte_pos < sector_size + HSMC->HSMC_PMECCSADDR) {
\r
406 data_ptr = (uint8_t*)(sector_base_address + byte_pos);
\r
408 data_ptr = (uint8_t*)(sector_base_address + byte_pos + ecc_size);
\r
411 trace_info("Correct error bit @[#Byte %u,Bit# %u]\n\r",
\r
412 (unsigned)byte_pos, (unsigned)bit_pos);
\r
414 if (*data_ptr & (1 << bit_pos))
\r
415 *data_ptr &= (0xFF ^ (1 << bit_pos));
\r
417 *data_ptr |= (1 << bit_pos);
\r
426 * \brief Configure the PMECC peripheral
\r
427 * \param pPmeccDescriptor Pointer to a PmeccDescriptor instance.
\r
429 static void _pmecc_configure(void)
\r
431 /* Disable ECC module */
\r
432 HSMC->HSMC_PMECCTRL |= HSMC_PMECCTRL_DISABLE;
\r
434 /* Reset the ECC module */
\r
435 HSMC->HSMC_PMECCTRL = HSMC_PMECCTRL_RST;
\r
436 HSMC->HSMC_PMECCFG = pmecc_desc.err_bit_nbr_capability |
\r
437 pmecc_desc.sector_size |
\r
438 pmecc_desc.page_size |
\r
439 pmecc_desc.nand_wr |
\r
440 pmecc_desc.spare_ena |
\r
441 pmecc_desc.mode_auto;
\r
442 HSMC->HSMC_PMECCSAREA = pmecc_desc.spare_size - 1;
\r
443 HSMC->HSMC_PMECCSADDR = pmecc_desc.ecc_start_address;
\r
444 HSMC->HSMC_PMECCEADDR = pmecc_desc.ecc_end_address - 1;
\r
446 /* Disable all interrupts */
\r
447 HSMC->HSMC_PMECCIDR = 0xFF;
\r
449 /* Enable ECC module */
\r
450 HSMC->HSMC_PMECCTRL |= HSMC_PMECCTRL_ENABLE;
\r
454 /*----------------------------------------------------------------------------
\r
456 *----------------------------------------------------------------------------*/
\r
459 * \brief This function is able to build Galois Field.
\r
460 * \param mm degree of the remainders.
\r
461 * \param index_of Pointer to a buffer for index_of table.
\r
462 * \param alpha_to Pointer to a buffer for alpha_to table.
\r
464 void build_gf(uint32_t mm, int32_t* index_of, int32_t* alpha_to)
\r
471 nn = (1 << mm) - 1;
\r
472 /* set default value */
\r
473 for (i = 1; i < mm; i++)
\r
492 p[2] = p[3] = p[4] = 1;
\r
500 p[1] = p[4] = p[6] = 1;
\r
502 p[1] = p[3] = p[4] = 1;
\r
504 p[1] = p[6] = p[10] = 1;
\r
508 /*-- First of All */
\r
509 /*-- build alpha ^ mm it will help to generate the field (primitiv) */
\r
511 for (i = 0; i < mm; i++)
\r
513 alpha_to[mm] |= 1 << i;
\r
516 /* Build elements from 0 to mm - 1 */
\r
517 /* very easy because degree is less than mm so it is */
\r
518 /* just a logical shift ! (only the remainder) */
\r
520 for (i = 0; i < mm; i++) {
\r
521 alpha_to[i] = mask;
\r
522 index_of[alpha_to[i]] = i;
\r
526 index_of[alpha_to[mm]] = mm;
\r
528 /* use a mask to select the MSB bit of the */
\r
530 mask >>= 1; /* previous value moust be decremented */
\r
532 /* then finish the building */
\r
533 for (i = mm + 1; i <= nn; i++) {
\r
534 /* check if the msb bit of the lfsr is set */
\r
535 if (alpha_to[i-1] & mask)
\r
536 /* feedback loop is set */
\r
537 alpha_to[i] = alpha_to[mm] ^ ((alpha_to[i-1] ^ mask) << 1);
\r
539 /* only shift is enabled */
\r
540 alpha_to[i] = alpha_to[i-1] << 1;
\r
542 //index_of[alpha_to[i]] = i ;
\r
543 index_of[alpha_to[i]] = i%nn ;
\r
545 /* of course index of 0 is undefined in a multiplicative field */
\r
550 * \brief Initialize the PMECC peripheral
\r
551 * \param sector_size 0 for 512, 1 for 1024.
\r
552 * \param ecc_errors_per_sector Coded value of ECC bit number correction(2,4,8,12,24).
\r
553 * \param page_data_size Data area size in byte.
\r
554 * \param page_spare_size Spare area size in byte.
\r
555 * \param ecc_offset_in_spare offset of the first ecc byte in spare zone.
\r
556 * \param spare_protected 1: The spare area is protected with the last sector of data.
\r
557 * 0: The spare area is skipped in read or write mode.
\r
558 * \return 0 if successful; otherwise returns 1.
\r
560 uint8_t pmecc_initialize(uint8_t sector_size , uint8_t ecc_errors_per_sector,
\r
561 uint32_t page_data_size, uint32_t page_spare_size,
\r
562 uint16_t ecc_offset_in_spare, uint8_t spare_protected)
\r
564 uint8_t nb_sectors_per_page = 0;
\r
566 if (ecc_errors_per_sector == 0xFF) {
\r
567 /* ONFI 2.2 : a value of 0xff indaicate we must apply a correction on sector > 512 bytes,
\r
568 so we set at the maximum allowed by PMECC 24 bits on 1024 sectors. */
\r
569 ecc_errors_per_sector = 24;
\r
570 sector_size = 1; /* 1 for 1024 bytes per sector */
\r
573 /* Number of Sectors in one Page */
\r
574 switch (sector_size) {
\r
575 /* 512 bytes per sector */
\r
577 pmecc_desc.sector_size = 0;
\r
578 nb_sectors_per_page = page_data_size / 512;
\r
579 pmecc_desc.mm = 13;
\r
580 pmecc_get_gf_512_tables(&pmecc_desc.alpha_to, &pmecc_desc.index_of);
\r
583 /* 1024 bytes per sector */
\r
585 pmecc_desc.sector_size = HSMC_PMECCFG_SECTORSZ;
\r
586 nb_sectors_per_page = page_data_size / 1024;
\r
587 pmecc_desc.mm = 14;
\r
588 pmecc_get_gf_1024_tables(&pmecc_desc.alpha_to, &pmecc_desc.index_of);
\r
592 switch (nb_sectors_per_page) {
\r
594 pmecc_desc.page_size = HSMC_PMECCFG_PAGESIZE_PAGESIZE_1SEC;
\r
597 pmecc_desc.page_size = HSMC_PMECCFG_PAGESIZE_PAGESIZE_2SEC;
\r
600 pmecc_desc.page_size = HSMC_PMECCFG_PAGESIZE_PAGESIZE_4SEC;
\r
603 pmecc_desc.page_size = HSMC_PMECCFG_PAGESIZE_PAGESIZE_8SEC;
\r
606 pmecc_desc.page_size = HSMC_PMECCFG_PAGESIZE_PAGESIZE_1SEC;
\r
610 pmecc_desc.nn = (1 << pmecc_desc.mm) - 1;
\r
612 /* Coded value of ECC bit number correction (0 (2 bits), 1 (4 bits), 2 (8 bits), 3 (12 bits), 4 (24 bits), 5 (NU)) */
\r
613 switch (ecc_errors_per_sector) {
\r
615 pmecc_desc.err_bit_nbr_capability = HSMC_PMECCFG_BCH_ERR_BCH_ERR2;
\r
618 pmecc_desc.err_bit_nbr_capability = HSMC_PMECCFG_BCH_ERR_BCH_ERR4;
\r
621 pmecc_desc.err_bit_nbr_capability = HSMC_PMECCFG_BCH_ERR_BCH_ERR8;
\r
624 pmecc_desc.err_bit_nbr_capability = HSMC_PMECCFG_BCH_ERR_BCH_ERR12;
\r
627 pmecc_desc.err_bit_nbr_capability = HSMC_PMECCFG_BCH_ERR_BCH_ERR24;
\r
630 pmecc_desc.err_bit_nbr_capability = HSMC_PMECCFG_BCH_ERR_BCH_ERR2;
\r
631 ecc_errors_per_sector = 2;
\r
635 /* Real value of ECC bit number correction (2, 4, 8, 12, 24) */
\r
636 pmecc_desc.tt = ecc_errors_per_sector;
\r
637 if (((pmecc_desc.mm * ecc_errors_per_sector ) % 8 ) == 0) {
\r
638 pmecc_desc.ecc_size_byte = ((pmecc_desc.mm * ecc_errors_per_sector ) / 8) * nb_sectors_per_page;
\r
640 pmecc_desc.ecc_size_byte = (((pmecc_desc.mm * ecc_errors_per_sector ) / 8 ) + 1 ) * nb_sectors_per_page;
\r
642 if (ecc_offset_in_spare <= 2) {
\r
643 pmecc_desc.ecc_start_address = PMECC_ECC_DEFAULT_START_ADDR;
\r
645 pmecc_desc.ecc_start_address = ecc_offset_in_spare;
\r
647 pmecc_desc.ecc_end_address = pmecc_desc.ecc_start_address + pmecc_desc.ecc_size_byte;
\r
648 if (pmecc_desc.ecc_end_address > page_spare_size) {
\r
651 pmecc_desc.spare_size = pmecc_desc.ecc_end_address;
\r
653 //pmecc_desc.nand_wr = PMECC_CFG_NANDWR; /* NAND write access */
\r
654 pmecc_desc.nand_wr = 0; /* NAND Read access */
\r
655 if (spare_protected) {
\r
656 pmecc_desc.spare_ena = HSMC_PMECCFG_SPAREEN;
\r
658 pmecc_desc.spare_ena = 0;
\r
660 /* PMECC_CFG_AUTO indicates that the spare is error protected. In this case, the ECC computation takes into account the whole spare area
\r
661 minus the ECC area in the ECC computation operation */
\r
662 pmecc_desc.mode_auto = 0;
\r
663 /* At 133 Mhz, this field must be programmed with 2,
\r
664 indicating that the setup time is 3 clock cycles.*/
\r
665 pmecc_desc.clk_ctrl = 2;
\r
666 pmecc_desc.interrupt = 0;
\r
667 _pmecc_configure();
\r
672 * \brief Return PMECC page size.
\r
674 uint32_t pmecc_get_page_size(void)
\r
676 return pmecc_desc.page_size;
\r
680 * \brief Return PMECC ecc size.
\r
682 uint32_t pmecc_get_ecc_bytes(void)
\r
684 return pmecc_desc.ecc_size_byte;
\r
688 * \brief Return PMECC ecc start address.
\r
690 uint32_t pmecc_get_ecc_start_address(void)
\r
692 return pmecc_desc.ecc_start_address;
\r
696 * \brief Return PMECC ecc end address.
\r
698 uint32_t pmecc_get_ecc_end_address(void)
\r
700 return pmecc_desc.ecc_end_address;
\r
704 typedef uint32_t (*pmecc_correction_algo_t)(Smc *, struct _pmecc_descriptor *, uint32_t, uint32_t);
\r
707 * \brief Launch error detection functions and correct corrupted bits.
\r
708 * \param pmecc_status Value of the PMECC status register.
\r
709 * \param page_buffer Base address of the buffer containing the page to be corrected.
\r
710 * \return 0 if all errors have been corrected, 1 if too many errors detected
\r
712 uint32_t pmecc_correction(uint32_t pmecc_status, uint32_t page_buffer)
\r
714 uint32_t sector_number = 0;
\r
715 uint32_t sector_base_address;
\r
716 volatile int32_t error_nbr;
\r
718 /* Set the sector size (512 or 1024 bytes) */
\r
719 HSMC->HSMC_ELCFG = pmecc_desc.sector_size >> 4;
\r
721 while (sector_number < (uint32_t)((1 << ((HSMC->HSMC_PMECCFG & HSMC_PMECCFG_PAGESIZE_Msk) >> 8)))) {
\r
723 if (pmecc_status & 0x1) {
\r
724 sector_base_address = page_buffer + (sector_number * ((pmecc_desc.sector_size >> 4) + 1) * 512);
\r
725 gen_syn(sector_number);
\r
728 error_nbr = error_location((((pmecc_desc.sector_size >> 4) + 1) * 512 * 8) +
\r
729 (pmecc_desc.tt * (13 + (pmecc_desc.sector_size >> 4)))); /* number of bits of the sector + ecc */
\r
731 if (error_nbr == -1)
\r
734 error_correction(sector_base_address, 0, error_nbr); /* Extra byte is 0 */
\r
737 pmecc_status = pmecc_status >> 1;
\r
743 * \brief Disable pmecc.
\r
745 void pmecc_disable(void)
\r
747 /* Disable ECC module */
\r
748 HSMC->HSMC_PMECCTRL |= HSMC_PMECCTRL_DISABLE;
\r