]> git.sur5r.net Git - freertos/blob - FreeRTOS/Demo/CORTEX_A5_SAMA5D2x_Xplained_IAR/AtmelFiles/drivers/peripherals/pmecc.c
Add SAMA5D2 Xplained IAR demo.
[freertos] / FreeRTOS / Demo / CORTEX_A5_SAMA5D2x_Xplained_IAR / AtmelFiles / drivers / peripherals / pmecc.c
1 /* ----------------------------------------------------------------------------\r
2  *         SAM Software Package License\r
3  * ----------------------------------------------------------------------------\r
4  * Copyright (c) 2012, Atmel Corporation\r
5  * All rights reserved.\r
6  *\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
9  *\r
10  * - Redistributions of source code must retain the above copyright notice,\r
11  * this list of conditions and the disclaimer below.\r
12  *\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
15  *\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
27  */\r
28 \r
29 /** \file */\r
30 \r
31 /*----------------------------------------------------------------------------\r
32  *        Headers\r
33  *----------------------------------------------------------------------------*/\r
34 \r
35 #include "chip.h"\r
36 #include "trace.h"\r
37 \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
41 \r
42 /*--------------------------------------------------------------------------- */\r
43 /*         Local types                                                        */\r
44 /*--------------------------------------------------------------------------- */\r
45 \r
46 /** PMECC configuration descriptor */\r
47 struct _pmecc_descriptor {\r
48         /** Number of Sectors in one Page */\r
49         uint32_t page_size;\r
50 \r
51         /** The spare area size is equal to (SPARESIZE+1) bytes */\r
52         uint32_t spare_size;\r
53 \r
54         /** 0 for 512, 1 for 1024 bytes, like in PMECCFG register */\r
55         uint32_t sector_size;\r
56 \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
60 \r
61         /** Real size in bytes of ECC in spare */\r
62         uint32_t ecc_size_byte;\r
63 \r
64         /** The first byte address of the ECC area */\r
65         uint32_t ecc_start_address;\r
66 \r
67         /** The last byte address of the ECC area */\r
68         uint32_t ecc_end_address;\r
69 \r
70         /** NAND Write Access*/\r
71         uint32_t nand_wr;\r
72 \r
73         /** Spare Enable */\r
74         uint32_t spare_ena;\r
75 \r
76         /** Automatic Mode */\r
77         uint32_t mode_auto;\r
78 \r
79         /** The PMECC Module data path Setup Time is set to CLKCTRL+1. */\r
80         uint32_t clk_ctrl;\r
81 \r
82         /** */\r
83         uint32_t interrupt;\r
84 \r
85         /** defines the error correcting capability selected at encoding/decoding time */\r
86         int32_t tt;\r
87 \r
88         /** degree of the remainders, GF(2**mm) */\r
89         int32_t mm;\r
90 \r
91         /** length of codeword =  nn=2**mm -1 */\r
92         int32_t nn;\r
93 \r
94         /** Gallois field table */\r
95         const int16_t *alpha_to;\r
96 \r
97         /** Index of Gallois field table */\r
98         const int16_t *index_of;\r
99 \r
100         /** */\r
101         int16_t partial_syn[100];\r
102 \r
103         /** Holds the current syndrome value, an element of that table belongs to the field.*/\r
104         int16_t si[100];\r
105 \r
106         /** sigma table */\r
107         int16_t smu[PMECC_NB_ERROR_MAX + 2][2 * PMECC_NB_ERROR_MAX + 1];\r
108 \r
109         /** polynom order */\r
110         int16_t lmu[PMECC_NB_ERROR_MAX + 1];\r
111 };\r
112 \r
113 /*--------------------------------------------------------------------------- */\r
114 /*         Local variables                                                    */\r
115 /*--------------------------------------------------------------------------- */\r
116 \r
117 /** Pmecc decriptor instance */\r
118 struct _pmecc_descriptor pmecc_desc;\r
119 \r
120 /*----------------------------------------------------------------------------\r
121  *        Local functions\r
122  *----------------------------------------------------------------------------*/\r
123 \r
124  /**\r
125  * \brief Build the pseudo syndromes table\r
126  * \param sector Targetted sector.\r
127  */\r
128 static void gen_syn(uint32_t sector)\r
129 {\r
130         int16_t *remainer;\r
131         uint32_t index;\r
132 \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
137         }\r
138 }\r
139 \r
140 /**\r
141  * \brief The substitute function evaluates the polynomial remainder,\r
142  * with different values of the field primitive elements.\r
143  */\r
144 static uint32_t substitute(void)\r
145 {\r
146         int32_t i, j;\r
147         int16_t *si;\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
151 \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
154 \r
155         for (i = 1; i < 2 * PMECC_NB_ERROR_MAX; i++)\r
156                 si[i] = 0;\r
157 \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
161                 si[i] = 0;\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
165                 }\r
166         }\r
167         /* Even syndrome = (Odd syndrome) ** 2 */\r
168         for (i = 2; i <= 2 * pmecc_desc.tt; i = i + 2) {\r
169                 j = i / 2;\r
170                 if (si[j] == 0) {\r
171                         si[i] = 0;\r
172                 } else {\r
173                         si[i] = alpha_to[(2 * index_of[si[j]]) % pmecc_desc.nn];\r
174                 }\r
175         }\r
176         return 0;\r
177 }\r
178 \r
179 /**\r
180  * \brief The substitute function finding the value of the error\r
181  * location polynomial.\r
182  */\r
183 static uint32_t get_sigma(void)\r
184 {\r
185         uint32_t dmu_0_count;\r
186         int32_t i, j, k;\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
190 \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
195         int32_t largest;\r
196         int32_t diff;\r
197 \r
198         dmu_0_count = 0;\r
199 \r
200         /* -- First Row -- */\r
201 \r
202         /* Mu */\r
203         mu[0]  = -1;\r
204         /* Actually -1/2 */\r
205         /* Sigma(x) set to 1 */\r
206 \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
210 \r
211         /* discrepancy set to 1 */\r
212         dmu[0] = 1;\r
213 \r
214         /* polynom order set to 0 */\r
215         lmu[0] = 0;\r
216 \r
217         /* delta set to -1 */\r
218         delta[0]  = (mu[0] * 2 - lmu[0]) >> 1;\r
219 \r
220         /* -- Second Row -- */\r
221 \r
222         /* Mu */\r
223         mu[1] = 0;\r
224 \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
229 \r
230         /* discrepancy set to S1 */\r
231         dmu[1] = si[1];\r
232 \r
233         /* polynom order set to 0 */\r
234         lmu[1] = 0;\r
235 \r
236         /* delta set to 0 */\r
237         delta[1]  = (mu[1] * 2 - lmu[1]) >> 1;\r
238 \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
242 \r
243         for (i = 1; i <= tt; i++) {\r
244                 mu[i+1] = i << 1;\r
245 \r
246                 /* Compute Sigma (Mu+1)             */\r
247                 /* And L(mu)                        */\r
248                 /* check if discrepancy is set to 0 */\r
249                 if ( dmu[i] == 0) {\r
250                         dmu_0_count++;\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
256                                         return 0;\r
257                                 }\r
258                         } else {\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
263                                         return 0;\r
264                                 }\r
265                         }\r
266 \r
267                         /* copy polynom */\r
268                         for (j = 0; j <= (lmu[i] >> 1); j++)\r
269                                 pmecc_desc.smu[i + 1][j] = pmecc_desc.smu[i][j];\r
270 \r
271                         /* copy previous polynom order to the next */\r
272                         lmu[i + 1] = lmu[i];\r
273                 } else {\r
274                         /* find largest delta with dmu != 0 */\r
275                         ro = 0;\r
276                         largest = -1;\r
277                         for (j = 0; j < i; j++) {\r
278                                 if (dmu[j]) {\r
279                                         if (delta[j] > largest) {\r
280                                                 largest = delta[j];\r
281                                                 ro = j;\r
282                                         }\r
283                                 }\r
284                         }\r
285 \r
286                         /* compute difference */\r
287                         diff = (mu[i] - mu[ro]);\r
288 \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
292                         else\r
293                                 lmu[i + 1] = ((lmu[ro] >> 1) + diff) * 2;\r
294 \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
298 \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
305                         }\r
306                         for (k = 0; k <= (lmu[i] >> 1); k++)\r
307                                 pmecc_desc.smu[i+1][k] ^= pmecc_desc.smu[i][k];\r
308                 }\r
309 \r
310                 /*************************************************/\r
311                 /*      End Compute Sigma (Mu+1)                 */\r
312                 /*      And L(mu)                                */\r
313                 /*************************************************/\r
314                 /* In either case compute delta */\r
315                 delta[i + 1] = (mu[i + 1] * 2 - lmu[i + 1]) >> 1;\r
316 \r
317                 /* Do not compute discrepancy for the last iteration */\r
318                 if (i < tt) {\r
319                         for (k = 0 ; k <= (lmu[i + 1] >> 1); k++) {\r
320                                 if (k == 0)\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
326                         }\r
327                 }\r
328         }\r
329         return 0;\r
330 }\r
331 \r
332 /**\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
337  */\r
338 static int32_t error_location (uint32_t sector_size_in_bits)\r
339 {\r
340         uint32_t alphax;\r
341         uint32_t *sigma;\r
342         uint32_t error_number;\r
343         uint32_t nbr_of_roots;\r
344 \r
345         /* Disable PMECC Error Location IP */\r
346         HSMC->HSMC_ELDIS |= 0xFFFFFFFF;\r
347         error_number = 0;\r
348         alphax = 0;\r
349 \r
350         sigma = (uint32_t*)&HSMC->HSMC_SIGMA0;\r
351 \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
354                 error_number++;\r
355         }\r
356 \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
360 \r
361         while ((HSMC->HSMC_ELISR & HSMC_ELISR_DONE) == 0);\r
362 \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
367 \r
368         /* Number of roots not match the degree of smu ==> unable to correct error */\r
369         return -1;\r
370 }\r
371 \r
372 /**\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
378  */\r
379 static uint32_t error_correction(uint32_t sector_base_address, uint32_t extra_bytes, uint32_t error_nbr)\r
380 {\r
381         uint32_t *error_pos;\r
382         uint32_t byte_pos;\r
383         uint32_t bit_pos;\r
384         uint32_t sector_size;\r
385         uint32_t ecc_size;\r
386         uint32_t ecc_end_addr;\r
387 \r
388         error_pos = (uint32_t*)&HSMC->HSMC_ERRLOC0;\r
389 \r
390         sector_size = 512 * (((HSMC->HSMC_PMECCFG & HSMC_PMECCFG_SECTORSZ) >> 4) + 1);\r
391 \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
395 \r
396         while (error_nbr) {\r
397                 byte_pos = (*error_pos - 1) / 8;\r
398                 bit_pos = (*error_pos - 1) % 8;\r
399 \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
403 \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
407                         } else {\r
408                                 data_ptr = (uint8_t*)(sector_base_address + byte_pos + ecc_size);\r
409                         }\r
410 \r
411                         trace_info("Correct error bit @[#Byte %u,Bit# %u]\n\r",\r
412                                         (unsigned)byte_pos, (unsigned)bit_pos);\r
413 \r
414                         if (*data_ptr & (1 << bit_pos))\r
415                                 *data_ptr &= (0xFF ^ (1 << bit_pos));\r
416                         else\r
417                                 *data_ptr |= (1 << bit_pos);\r
418                 }\r
419                 error_pos++;\r
420                 error_nbr--;\r
421         }\r
422         return 0;\r
423 }\r
424 \r
425 /**\r
426  * \brief Configure the PMECC peripheral\r
427  * \param pPmeccDescriptor Pointer to a PmeccDescriptor instance.\r
428  */\r
429 static void _pmecc_configure(void)\r
430 {\r
431         /* Disable ECC module */\r
432         HSMC->HSMC_PMECCTRL |= HSMC_PMECCTRL_DISABLE;\r
433 \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
445 \r
446         /* Disable all interrupts */\r
447         HSMC->HSMC_PMECCIDR = 0xFF;\r
448 \r
449         /* Enable ECC module */\r
450         HSMC->HSMC_PMECCTRL |= HSMC_PMECCTRL_ENABLE;\r
451 }\r
452 \r
453 \r
454 /*----------------------------------------------------------------------------\r
455  *        Export functions\r
456  *----------------------------------------------------------------------------*/\r
457 \r
458 /**\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
463  */\r
464 void build_gf(uint32_t mm, int32_t* index_of, int32_t* alpha_to)\r
465 {\r
466         uint32_t i;\r
467         uint32_t mask;\r
468         uint32_t nn;\r
469         uint32_t p[15];\r
470 \r
471         nn = (1 << mm) - 1;\r
472         /* set default value */\r
473         for (i = 1; i < mm; i++)\r
474                 p[i] = 0;\r
475 \r
476         /*  1 + X^mm */\r
477         p[0]  = 1;\r
478         p[mm] = 1;\r
479 \r
480         /*  others  */\r
481         if (mm == 3)\r
482                 p[1] = 1;\r
483         else if (mm == 4)\r
484                 p[1] = 1;\r
485         else if (mm == 5)\r
486                 p[2] = 1;\r
487         else if (mm == 6)\r
488                 p[1] = 1;\r
489         else if (mm == 7)\r
490                 p[3] = 1;\r
491         else if (mm == 8)\r
492                 p[2] = p[3] = p[4] = 1;\r
493         else if (mm == 9)\r
494                 p[4] = 1;\r
495         else if (mm == 10)\r
496                 p[3] = 1;\r
497         else if (mm == 11)\r
498                 p[2] = 1;\r
499         else if (mm == 12)\r
500                 p[1] = p[4] = p[6] = 1;\r
501         else if (mm == 13)\r
502                 p[1] = p[3] = p[4] = 1;\r
503         else if (mm == 14)\r
504                 p[1] = p[6] = p[10] = 1;\r
505         else if (mm == 15)\r
506                 p[1] = 1;\r
507 \r
508         /*-- First of All */\r
509         /*-- build alpha ^ mm it will help to generate the field (primitiv) */\r
510         alpha_to[mm] = 0;\r
511         for (i = 0; i < mm; i++)\r
512                 if (p[i])\r
513                         alpha_to[mm] |= 1 << i;\r
514 \r
515         /* Secondly */\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
519         mask = 1;\r
520         for (i = 0; i < mm; i++) {\r
521                 alpha_to[i] = mask;\r
522                 index_of[alpha_to[i]] = i;\r
523                 mask <<= 1;\r
524         }\r
525 \r
526         index_of[alpha_to[mm]] = mm;\r
527 \r
528         /* use a mask to select the MSB bit of the */\r
529         /* LFSR ! */\r
530         mask >>= 1; /* previous value moust be decremented */\r
531 \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
538                 else\r
539                         /*  only shift is enabled */\r
540                         alpha_to[i] = alpha_to[i-1] << 1;\r
541                 /*  lookup table */\r
542                 //index_of[alpha_to[i]] = i ;\r
543                 index_of[alpha_to[i]] = i%nn ;\r
544         }\r
545         /* of course index of 0 is undefined in a multiplicative field */\r
546         index_of[0] = -1;\r
547 }\r
548 \r
549 /**\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
559  */\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
563 {\r
564         uint8_t nb_sectors_per_page = 0;\r
565 \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
571         }\r
572 \r
573         /* Number of Sectors in one Page */\r
574         switch (sector_size) {\r
575         /* 512 bytes per sector */\r
576         case 0:\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
581                 break;\r
582 \r
583         /* 1024 bytes per sector */\r
584         case 1:\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
589                 break;\r
590         }\r
591 \r
592         switch (nb_sectors_per_page) {\r
593         case 1:\r
594                 pmecc_desc.page_size = HSMC_PMECCFG_PAGESIZE_PAGESIZE_1SEC;\r
595                 break;\r
596         case 2:\r
597                 pmecc_desc.page_size = HSMC_PMECCFG_PAGESIZE_PAGESIZE_2SEC;\r
598                 break;\r
599         case 4:\r
600                 pmecc_desc.page_size = HSMC_PMECCFG_PAGESIZE_PAGESIZE_4SEC;\r
601                 break;\r
602         case 8:\r
603                 pmecc_desc.page_size = HSMC_PMECCFG_PAGESIZE_PAGESIZE_8SEC;\r
604                 break;\r
605         default :\r
606                 pmecc_desc.page_size = HSMC_PMECCFG_PAGESIZE_PAGESIZE_1SEC;\r
607                 break;\r
608         }\r
609 \r
610         pmecc_desc.nn = (1 << pmecc_desc.mm) - 1;\r
611 \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
614         case 2:\r
615                 pmecc_desc.err_bit_nbr_capability = HSMC_PMECCFG_BCH_ERR_BCH_ERR2;\r
616                 break;\r
617         case 4:\r
618                 pmecc_desc.err_bit_nbr_capability = HSMC_PMECCFG_BCH_ERR_BCH_ERR4;\r
619                 break;\r
620         case 8:\r
621                 pmecc_desc.err_bit_nbr_capability = HSMC_PMECCFG_BCH_ERR_BCH_ERR8;\r
622                 break;\r
623         case 12:\r
624                 pmecc_desc.err_bit_nbr_capability = HSMC_PMECCFG_BCH_ERR_BCH_ERR12;\r
625                 break;\r
626         case 24:\r
627                 pmecc_desc.err_bit_nbr_capability = HSMC_PMECCFG_BCH_ERR_BCH_ERR24;\r
628                 break;\r
629         default:\r
630                 pmecc_desc.err_bit_nbr_capability = HSMC_PMECCFG_BCH_ERR_BCH_ERR2;\r
631                 ecc_errors_per_sector = 2;\r
632                 break;\r
633         }\r
634 \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
639         } else  {\r
640                 pmecc_desc.ecc_size_byte = (((pmecc_desc.mm * ecc_errors_per_sector ) / 8 ) + 1 ) * nb_sectors_per_page;\r
641         }\r
642         if (ecc_offset_in_spare <= 2) {\r
643                 pmecc_desc.ecc_start_address = PMECC_ECC_DEFAULT_START_ADDR;\r
644         } else {\r
645                 pmecc_desc.ecc_start_address = ecc_offset_in_spare;\r
646         }\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
649                 return 1;\r
650         }\r
651         pmecc_desc.spare_size = pmecc_desc.ecc_end_address;\r
652 \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
657         } else {\r
658                 pmecc_desc.spare_ena = 0;\r
659         }\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
668         return 0;\r
669 }\r
670 \r
671 /**\r
672  * \brief Return PMECC page size.\r
673  */\r
674 uint32_t pmecc_get_page_size(void)\r
675 {\r
676         return pmecc_desc.page_size;\r
677 }\r
678 \r
679 /**\r
680  * \brief Return PMECC ecc size.\r
681  */\r
682 uint32_t pmecc_get_ecc_bytes(void)\r
683 {\r
684         return pmecc_desc.ecc_size_byte;\r
685 }\r
686 \r
687 /**\r
688  * \brief Return PMECC ecc start address.\r
689  */\r
690 uint32_t pmecc_get_ecc_start_address(void)\r
691 {\r
692         return pmecc_desc.ecc_start_address;\r
693 }\r
694 \r
695 /**\r
696  * \brief Return PMECC ecc end address.\r
697  */\r
698 uint32_t pmecc_get_ecc_end_address(void)\r
699 {\r
700         return pmecc_desc.ecc_end_address;\r
701 }\r
702 \r
703 \r
704 typedef uint32_t (*pmecc_correction_algo_t)(Smc *, struct _pmecc_descriptor *, uint32_t, uint32_t);\r
705 \r
706 /**\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
711  */\r
712 uint32_t pmecc_correction(uint32_t pmecc_status, uint32_t page_buffer)\r
713 {\r
714         uint32_t sector_number = 0;\r
715         uint32_t sector_base_address;\r
716         volatile int32_t error_nbr;\r
717 \r
718         /* Set the sector size (512 or 1024 bytes) */\r
719         HSMC->HSMC_ELCFG = pmecc_desc.sector_size >> 4;\r
720 \r
721         while (sector_number < (uint32_t)((1 << ((HSMC->HSMC_PMECCFG & HSMC_PMECCFG_PAGESIZE_Msk) >> 8)))) {\r
722                 error_nbr = 0;\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
726                         substitute();\r
727                         get_sigma();\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
730 \r
731                         if (error_nbr == -1)\r
732                                 return 1;\r
733                         else\r
734                                 error_correction(sector_base_address, 0, error_nbr); /* Extra byte is 0 */\r
735                 }\r
736                 sector_number++;\r
737                 pmecc_status = pmecc_status >> 1;\r
738         }\r
739         return 0;\r
740 }\r
741 \r
742 /**\r
743  * \brief Disable pmecc.\r
744  */\r
745 void pmecc_disable(void)\r
746 {\r
747         /* Disable ECC module */\r
748         HSMC->HSMC_PMECCTRL |= HSMC_PMECCTRL_DISABLE;\r
749 }\r