summaryrefslogtreecommitdiff
path: root/peripherals/hsmc4/hsmc4_ecc.c
diff options
context:
space:
mode:
Diffstat (limited to 'peripherals/hsmc4/hsmc4_ecc.c')
-rw-r--r--peripherals/hsmc4/hsmc4_ecc.c703
1 files changed, 703 insertions, 0 deletions
diff --git a/peripherals/hsmc4/hsmc4_ecc.c b/peripherals/hsmc4/hsmc4_ecc.c
new file mode 100644
index 0000000..e27655f
--- /dev/null
+++ b/peripherals/hsmc4/hsmc4_ecc.c
@@ -0,0 +1,703 @@
+/* ----------------------------------------------------------------------------
+ * ATMEL Microcontroller Software Support
+ * ----------------------------------------------------------------------------
+ * Copyright (c) 2008, Atmel Corporation
+ *
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * - Redistributions of source code must retain the above copyright notice,
+ * this list of conditions and the disclaimer below.
+ *
+ * Atmel's name may not be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * DISCLAIMER: THIS SOFTWARE IS PROVIDED BY ATMEL "AS IS" AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT ARE
+ * DISCLAIMED. IN NO EVENT SHALL ATMEL BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA,
+ * OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
+ * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ * ----------------------------------------------------------------------------
+ */
+
+//------------------------------------------------------------------------------
+// Headers
+//------------------------------------------------------------------------------
+#include "hsmc4.h"
+#include "hsmc4_ecc.h"
+#include <utility/trace.h>
+#include <utility/assert.h>
+
+//------------------------------------------------------------------------------
+// Internal function
+//------------------------------------------------------------------------------
+//------------------------------------------------------------------------------
+/// Counts and return the number of bits set to '1' in the given byte.
+/// \param byte Byte to count.
+//------------------------------------------------------------------------------
+static unsigned char CountBitsInByte(unsigned char byte)
+{
+ unsigned char count = 0;
+ while (byte > 0) {
+
+ if (byte & 1) {
+
+ count++;
+ }
+ byte >>= 1;
+ }
+
+ return count;
+}
+//------------------------------------------------------------------------------
+/// Counts and return the number of bits set to '1' in the given hsiao code.
+/// \param code Hsizo code.
+//------------------------------------------------------------------------------
+static unsigned char CountBitsInCode(unsigned char *code)
+{
+ return CountBitsInByte(code[0])
+ + CountBitsInByte(code[1])
+ + CountBitsInByte(code[2]);
+}
+
+//------------------------------------------------------------------------------
+/// Get all ECC parity and Nparity value.
+//------------------------------------------------------------------------------
+void HSMC4_EccGetValue(unsigned int *ecc)
+{
+ ecc[0] = AT91C_BASE_HSMC4->HSMC4_ECCPR0;
+ ecc[1] = AT91C_BASE_HSMC4->HSMC4_ECCPR1;
+ ecc[2] = AT91C_BASE_HSMC4->HSMC4_ECCPR2;
+ ecc[3] = AT91C_BASE_HSMC4->HSMC4_ECCPR3;
+ ecc[4] = AT91C_BASE_HSMC4->HSMC4_ECCPR4;
+ ecc[5] = AT91C_BASE_HSMC4->HSMC4_ECCPR5;
+ ecc[6] = AT91C_BASE_HSMC4->HSMC4_ECCPR6;
+ ecc[7] = AT91C_BASE_HSMC4->HSMC4_ECCPR7;
+ ecc[8] = AT91C_BASE_HSMC4->HSMC4_ECCPR8;
+ ecc[9] = AT91C_BASE_HSMC4->HSMC4_ECCPR9;
+ ecc[10] = AT91C_BASE_HSMC4->HSMC4_ECCPR10;
+ ecc[11] = AT91C_BASE_HSMC4->HSMC4_ECCPR11;
+ ecc[12] = AT91C_BASE_HSMC4->HSMC4_ECCPR12;
+ ecc[13] = AT91C_BASE_HSMC4->HSMC4_ECCPR13;
+ ecc[14] = AT91C_BASE_HSMC4->HSMC4_ECCPR14;
+ ecc[15] = AT91C_BASE_HSMC4->HSMC4_Eccpr15;
+#ifdef DUMP_ECC_PARITY
+ TRACE_INFO("Ecc parity(0-7) %x, %x, %x, %x, %x, %x, %x, %x \n\r",ecc[0],ecc[1],ecc[2],ecc[3],ecc[4],ecc[5],ecc[6],ecc[7]);
+ TRACE_INFO("Ecc parity(8-15) %x, %x, %x, %x, %x, %x, %x, %x \n\r",ecc[8],ecc[9],ecc[10],ecc[11],ecc[12],ecc[13],ecc[14],ecc[15]);
+#endif
+}
+
+//------------------------------------------------------------------------------
+// Exported functions
+//------------------------------------------------------------------------------
+//------------------------------------------------------------------------------
+/// Configures ECC mode in HSMC4 peripheral as specified.
+/// \param type Type of correction.
+/// \param pageSize Page size of NAND flash device.
+//------------------------------------------------------------------------------
+void HSMC4_EccConfigure(unsigned int type, unsigned int pageSize)
+{
+ // Software Reset ECC.
+ AT91C_BASE_HSMC4->HSMC4_ECCCR = (0x1 << 1) ;
+ AT91C_BASE_HSMC4->HSMC4_ECCCMD = type | pageSize;
+}
+
+//------------------------------------------------------------------------------
+/// Returns type of ECC correction setting.
+//------------------------------------------------------------------------------
+unsigned int HSMC4_GetEccCorrectoinType(void)
+{
+ return ((AT91C_BASE_HSMC4->HSMC4_ECCCMD)& AT91C_ECC_TYPCORRECT);
+}
+
+//------------------------------------------------------------------------------
+/// Returns ECC status by giving ecc number
+/// \param eccNumber ecc parity number from 0 to 15.
+//------------------------------------------------------------------------------
+unsigned char HSMC4_GetEccStatus(unsigned char eccNumber)
+{
+ unsigned int status;
+ if (eccNumber < 8){
+ status = AT91C_BASE_HSMC4->HSMC4_ECCSR1;
+ }
+ else {
+ status = AT91C_BASE_HSMC4->HSMC4_ECCSR2;
+ eccNumber -=8;
+ }
+ return ((status >> (eccNumber * 4)) & 0x07);
+}
+//------------------------------------------------------------------------------
+/// Verifies 4-bytes hsiao codes for a data block whose size is a page Size
+/// word. Page words block is verified between the given HSIAO code
+/// generated by hardware and original HSIAO codes store has been previously stored.
+/// Returns 0 if the data is correct, Hsiao_ERROR_SINGLEBIT if one or more
+/// block(s) have had a single bit corrected, or either Hsiao_ERROR_ECC
+/// or Hsiao_ERROR_MULTIPLEBITS.
+/// \param data Data buffer to verify.
+/// \param originalCode Original codes.
+/// \param verifyCode codes to be verified.
+//------------------------------------------------------------------------------
+static unsigned char HSMC4_VerifyPageOf8bitHsiao(
+ unsigned char *data,
+ const unsigned char *originalCode,
+ const unsigned char *verifyCode)
+{
+ unsigned char correctionCode[4];
+ unsigned char bitCount;
+ // Xor both codes together
+ correctionCode[0] = verifyCode[0] ^ originalCode[0];
+ correctionCode[1] = verifyCode[1] ^ originalCode[1];
+ correctionCode[2] = verifyCode[2] ^ originalCode[2];
+ correctionCode[3] = verifyCode[3] ^ originalCode[3];
+ TRACE_DEBUG("Correction code = %02X %02X %02X %02X\n\r",
+ correctionCode[0], correctionCode[1], correctionCode[2], correctionCode[3]);
+ // If all bytes are 0, there is no error
+ if ((correctionCode[0] == 0)
+ && (correctionCode[1] == 0)
+ && (correctionCode[2] == 0)
+ && (correctionCode[3] == 0)) {
+
+ return 0;
+ }
+ // If there is a single bit error, there are 15 bits set to 1
+ bitCount = CountBitsInByte(correctionCode[0]) +
+ CountBitsInByte(correctionCode[1]) +
+ CountBitsInByte(correctionCode[2]) +
+ CountBitsInByte(correctionCode[3]);
+ if (bitCount == 15) {
+ // Get byte and bit indexes
+ unsigned short byte = (correctionCode[0] & 0xf0) >> 4;
+ byte |= (correctionCode[1] & 0xff) << 4;
+ unsigned char bit = correctionCode[0] & 0x0f;
+ // Correct bit
+ TRACE_INFO("Correcting byte #%d at bit %d\n\r", byte, bit);
+ data[byte] ^= (1 << bit);
+
+ return Hsiao_ERROR_SINGLEBIT;
+ }
+
+ // Check if ECC has been corrupted
+ if (bitCount == 1) {
+ return Hsiao_ERROR_ECC;
+ }
+ // Otherwise, this is a multi-bit error
+ else {
+ return Hsiao_ERROR_MULTIPLEBITS;
+ }
+}
+
+//------------------------------------------------------------------------------
+/// Verifies 3-bytes hsiao codes for a data block whose size is multiple of
+/// 256 bytes. Each 256-bytes block is verified between the given HSIAO code
+/// generated by hardware and original HSIAO codes store has been previously stored.
+/// Returns 0 if the data is correct, Hsiao_ERROR_SINGLEBIT if one or more
+/// block(s) have had a single bit corrected, or either Hsiao_ERROR_ECC
+/// or Hsiao_ERROR_MULTIPLEBITS.
+/// \param data Data buffer to verify.
+/// \param size Size of the data in words.
+/// \param originalCode Original codes.
+/// \param verifyCode codes to be verified.
+//------------------------------------------------------------------------------
+static unsigned char HSMC4_Verify256x8bitHsiao(
+ unsigned char *data,
+ unsigned int size,
+ const unsigned char *originalCode,
+ const unsigned char *verifyCode)
+{
+ unsigned char correctionCode[3];
+ unsigned int position = 0;
+ unsigned char byte;
+ unsigned char bit;
+ unsigned char error = 0;
+
+ TRACE_DEBUG("HSMC4_Verify512x8bitHsiao()\n\r");
+ while (position < size) {
+ // Xor both codes together
+ correctionCode[0] = verifyCode[0] ^ originalCode[0];
+ correctionCode[1] = verifyCode[1] ^ originalCode[1];
+ correctionCode[2] = verifyCode[2] ^ originalCode[2];
+ TRACE_DEBUG("Correction code = %02X %02X %02X\n\r",
+ correctionCode[0], correctionCode[1], correctionCode[2]);
+
+ // If all bytes are 0, there is no error
+ if ( correctionCode[0] || correctionCode[1] || correctionCode[2]) {
+ // If there is a single bit error, there are 11 bits set to 1
+ if (CountBitsInCode(correctionCode) == 11) {
+ // Get byte and bit indexes
+ byte = (correctionCode[0] & 0xf8) >> 3;
+ byte |= (correctionCode[1] & 0x07) << 5;
+ bit = correctionCode[0] & 0x07;
+ // Correct bit
+ TRACE_INFO("Correcting byte #%d at bit %d\n\r", (position + byte), bit);
+ data[byte] ^= (1 << bit);
+ error = Hsiao_ERROR_SINGLEBIT;
+ }
+ // Check if ECC has been corrupted
+ else if (CountBitsInCode(correctionCode) == 1) {
+ return Hsiao_ERROR_ECC;
+ }
+ else {
+ // Otherwise, this is a multi-bit error
+ return Hsiao_ERROR_MULTIPLEBITS;
+ }
+ }
+ data += 256;
+ originalCode += 3;
+ verifyCode += 3;
+ position += 256;
+ }
+ return error;
+}
+
+//------------------------------------------------------------------------------
+/// Verifies 3-bytes hsiao codes for a data block whose size is multiple of
+/// 512 bytes. Each 512-bytes block is verified between the given HSIAO code
+/// generated by hardware and original HSIAO codes store has been previously stored.
+/// Returns 0 if the data is correct, Hsiao_ERROR_SINGLEBIT if one or more
+/// block(s) have had a single bit corrected, or either Hsiao_ERROR_ECC
+/// or Hsiao_ERROR_MULTIPLEBITS.
+/// \param data Data buffer to verify.
+/// \param size Size of the data in words.
+/// \param originalCode Original codes.
+/// \param verifyCode codes to be verified.
+//------------------------------------------------------------------------------
+static unsigned char HSMC4_Verify512x8bitHsiao(
+ unsigned char *data,
+ unsigned int size,
+ const unsigned char *originalCode,
+ const unsigned char *verifyCode)
+{
+ unsigned char correctionCode[3];
+ unsigned int position = 0;
+ unsigned short byte;
+ unsigned char bit;
+ unsigned char error = 0;
+
+ TRACE_DEBUG("HSMC4_Verify512x8bitHsiao()\n\r");
+ while (position < size) {
+ // Xor both codes together
+ correctionCode[0] = verifyCode[0] ^ originalCode[0];
+ correctionCode[1] = verifyCode[1] ^ originalCode[1];
+ correctionCode[2] = verifyCode[2] ^ originalCode[2];
+ TRACE_DEBUG("Correction code = %02X %02X %02X\n\r",
+ correctionCode[0], correctionCode[1], correctionCode[2]);
+
+ // If all bytes are 0, there is no error
+ if ( correctionCode[0] || correctionCode[1] || correctionCode[2]) {
+ // If there is a single bit error, there are 11 bits set to 1
+ if (CountBitsInCode(correctionCode) == 12) {
+ // Get byte and bit indexes
+ byte = (correctionCode[0] & 0xf8) >> 3;
+ byte |= (correctionCode[1] & 0x0f) << 5;
+ bit = correctionCode[0] & 0x07;
+ // Correct bit
+ TRACE_INFO("Correcting byte #%d at bit %d\n\r", (position + byte), bit);
+ data[byte] ^= (1 << bit);
+ error = Hsiao_ERROR_SINGLEBIT;
+ }
+ // Check if ECC has been corrupted
+ else if (CountBitsInCode(correctionCode) == 1) {
+ return Hsiao_ERROR_ECC;
+ }
+ else {
+ // Otherwise, this is a multi-bit error
+ return Hsiao_ERROR_MULTIPLEBITS;
+ }
+ }
+ data += 512;
+ originalCode += 3;
+ verifyCode += 3;
+ position += 512;
+ }
+ return error;
+}
+
+//------------------------------------------------------------------------------
+/// Verifies 4-bytes hsiao codes for a data block whose size is a page Size
+/// word. Page words block is verified between the given HSIAO code
+/// generated by hardware and original HSIAO codes store has been previously stored.
+/// Returns 0 if the data is correct, Hsiao_ERROR_SINGLEBIT if one or more
+/// block(s) have had a single bit corrected, or either Hsiao_ERROR_ECC
+/// or Hsiao_ERROR_MULTIPLEBITS.
+/// \param data Data buffer to verify.
+/// \param originalCode Original codes.
+/// \param verifyCode codes to be verified.
+//------------------------------------------------------------------------------
+static unsigned char HSMC4_VerifyPageOf16bitHsiao(
+ unsigned short *data,
+ const unsigned char *originalCode,
+ const unsigned char *verifyCode)
+{
+ unsigned char correctionCode[4];
+ unsigned char bitCount;
+ // Xor both codes together
+ correctionCode[0] = verifyCode[0] ^ originalCode[0];
+ correctionCode[1] = verifyCode[1] ^ originalCode[1];
+ correctionCode[2] = verifyCode[2] ^ originalCode[2];
+ correctionCode[3] = verifyCode[3] ^ originalCode[3];
+ TRACE_DEBUG("Correction code = %02X %02X %02X %02X\n\r",
+ correctionCode[0], correctionCode[1], correctionCode[2], correctionCode[3]);
+ // If all bytes are 0, there is no error
+ if ((correctionCode[0] == 0)
+ && (correctionCode[1] == 0)
+ && (correctionCode[2] == 0)
+ && (correctionCode[3] == 0)) {
+
+ return 0;
+ }
+ // If there is a single bit error, there are 11 bits set to 1
+ bitCount = CountBitsInByte(correctionCode[0]) +
+ CountBitsInByte(correctionCode[1]) +
+ CountBitsInByte(correctionCode[2]) +
+ CountBitsInByte(correctionCode[3]);
+ printf("bitCount = %d \n\r",bitCount);
+ if (bitCount == 12) {
+ // Get byte and bit indexes
+ unsigned char word = (correctionCode[0] & 0xf0) >> 4;
+ word |= (correctionCode[1] & 0xff) << 4;
+ unsigned char bit = correctionCode[0] & 0x0f;
+ // Correct bit
+ TRACE_INFO("Correcting word #%d at bit %d\n\r", word, bit);
+ data[word] ^= (1 << bit);
+
+ return Hsiao_ERROR_SINGLEBIT;
+ }
+
+ // Check if ECC has been corrupted
+ if (bitCount == 1) {
+ return Hsiao_ERROR_ECC;
+ }
+ // Otherwise, this is a multi-bit error
+ else {
+ return Hsiao_ERROR_MULTIPLEBITS;
+ }
+}
+
+//------------------------------------------------------------------------------
+/// Verifies 3-bytes hsiao codes for a data block whose size is multiple of
+/// 256 word.Each 256-words block is verified between the given HSIAO code
+/// generated by hardware and original HSIAO codes store has been previously stored.
+/// Returns 0 if the data is correct, Hsiao_ERROR_SINGLEBIT if one or more
+/// block(s) have had a single bit corrected, or either Hsiao_ERROR_ECC
+/// or Hsiao_ERROR_MULTIPLEBITS.
+/// \param data Data buffer to verify.
+/// \param size Size of the data in words.
+/// \param originalCode Original codes.
+/// \param verifyCode codes to be verified.
+//------------------------------------------------------------------------------
+static unsigned char HSMC4_Verify256x16bitHsiao(
+ unsigned short *data,
+ unsigned int size,
+ const unsigned char *originalCode,
+ const unsigned char *verifyCode
+ )
+{
+ unsigned char correctionCode[3];
+ unsigned int position = 0;
+ unsigned char word;
+ unsigned char bit;
+ unsigned char error = 0;
+
+ TRACE_DEBUG("HSMC4_Verify512x8bitHsiao()\n\r");
+ while (position < size) {
+ // Xor both codes together
+ correctionCode[0] = verifyCode[0] ^ originalCode[0];
+ correctionCode[1] = verifyCode[1] ^ originalCode[1];
+ correctionCode[2] = verifyCode[2] ^ originalCode[2];
+ TRACE_DEBUG("Correction code = %02X %02X %02X\n\r",
+ correctionCode[0], correctionCode[1], correctionCode[2]);
+
+ // If all bytes are 0, there is no error
+ if ( correctionCode[0] || correctionCode[1] || correctionCode[2]) {
+ // If there is a single bit error, there are 11 bits set to 1
+ if (CountBitsInCode(correctionCode) == 12) {
+ // Get word and bit indexes
+ word = (correctionCode[0] & 0xf0) >> 4;
+ word |= (correctionCode[1] & 0x0f) << 4;
+ bit = correctionCode[0] & 0x0f;
+ // Correct bit
+ TRACE_INFO("Correcting word #%d at bit %d\n\r", (position + word), bit);
+ data[word] ^= (1 << bit);
+ error = Hsiao_ERROR_SINGLEBIT;
+ }
+ // Check if ECC has been corrupted
+ else if (CountBitsInCode(correctionCode) == 1) {
+ return Hsiao_ERROR_ECC;
+ }
+ else {
+ // Otherwise, this is a multi-bit error
+ return Hsiao_ERROR_MULTIPLEBITS;
+ }
+ }
+ data += 256;
+ originalCode += 3;
+ verifyCode += 3;
+ position += 256;
+ }
+ return error;
+}
+
+//------------------------------------------------------------------------------
+/// Verifies hsiao codes for a data block. The block is verified between the given
+/// HSIAO code generated by hardware and original HSIAO codes store has been
+/// previously stored.
+/// Returns 0 if the data is correct, Hsiao_ERROR_SINGLEBIT if one or more
+/// block(s) have had a single bit corrected, or either Hsiao_ERROR_ECC
+/// or Hsiao_ERROR_MULTIPLEBITS.
+/// \param data Data buffer to verify.
+/// \param size Size of the data in words.
+/// \param originalCode Original codes.
+/// \param verifyCode codes to be verified.
+/// \param dataPath 8bit/16bit data path.
+//------------------------------------------------------------------------------
+unsigned char HSMC4_VerifyHsiao(
+ unsigned char *data,
+ unsigned int size,
+ const unsigned char *originalCode,
+ const unsigned char *verifyCode,
+ unsigned char dataPath)
+{
+ unsigned char correctionType;
+ unsigned char error = 0;
+ correctionType = HSMC4_GetEccCorrectoinType();
+ // For 16-bit data path
+ if (dataPath == 16) {
+ switch (correctionType){
+ case AT91C_ECC_TYPCORRECT_ONE_PER_PAGE:
+ error = HSMC4_VerifyPageOf16bitHsiao((unsigned short*)data, originalCode, verifyCode);
+ break;
+ case AT91C_ECC_TYPCORRECT_ONE_EVERY_256_BYTES:
+ error= HSMC4_Verify256x16bitHsiao((unsigned short*)data, size / 2, originalCode, verifyCode);
+ break;
+ case AT91C_ECC_TYPCORRECT_ONE_EVERY_512_BYTES:
+ TRACE_WARNING("16-bit 512 per page correction not yet implement! \n\r");
+ break;
+ }
+ }
+ // For 8-bit data path
+ else {
+ switch (correctionType){
+ case AT91C_ECC_TYPCORRECT_ONE_PER_PAGE:
+ error = HSMC4_VerifyPageOf8bitHsiao(data, originalCode, verifyCode);
+ break;
+ case AT91C_ECC_TYPCORRECT_ONE_EVERY_256_BYTES:
+ error = HSMC4_Verify256x8bitHsiao(data, size, originalCode, verifyCode);
+ break;
+ case AT91C_ECC_TYPCORRECT_ONE_EVERY_512_BYTES:
+ error = HSMC4_Verify512x8bitHsiao(data, size, originalCode, verifyCode);
+ break;
+ }
+ }
+ return error;
+}
+
+//------------------------------------------------------------------------------
+/// Get 32-bit ECC code for 16-bit data path NAND flash.
+/// 32-bit ECC is generated in order to perform one bit correction
+/// for a page in page 512/1024/2048/4096 for 16-bit words
+/// \param size Data size in bytes.
+/// \param code Codes buffer.
+//------------------------------------------------------------------------------
+void HSMC4_Get24bitPerPageEcc(unsigned int pageDataSize, unsigned char *code)
+{
+ unsigned int eccParity;
+ unsigned int eccNparity;
+ unsigned int ecc[16];
+ // Get Parity value.
+ HSMC4_EccGetValue(ecc);
+
+ // ---- P16384'P8192'P4096'P2048' P1024'P512'P256' --- 4th. Ecc Byte to store
+ /// P128' P64' P32' P16' P8' P4' P2' P1' --- 3rd. Ecc Byte to store
+ // ---- P16384 P8192 P4096 P2048 P1024 P512 P256 --- 2nd. Ecc Byte to store
+ // P128 P64 P32 P16 P8 P4 P2 P1 --- 1st. Ecc Byte to store
+
+ // Invert codes (linux compatibility)
+ eccParity = ~(ecc[0]);
+ eccNparity = ~(ecc[1]);
+ TRACE_DEBUG("ecc Parity is 0x%08x, ecc Nparity is 0x%08x \n\r", eccParity, eccNparity);
+ code[0] = eccParity & 0xff;
+ code[1] = (eccParity >> 8 )& 0xff;
+ code[2] = eccNparity & 0xff;
+ code[3] = (eccNparity >> 8 )& 0xff;
+}
+
+//------------------------------------------------------------------------------
+/// Get 24-bit ECC code for 8-bit data path NAND flash.
+/// 24-bit ECC is generated in order to perform one bit correction
+/// for 256 byte in page 512/1024/2048/4096 for 8-bit words
+/// \param size Data size in bytes.
+/// \param code Codes buffer.
+//------------------------------------------------------------------------------
+void HSMC4_Get24bitPer256Ecc(unsigned int pageDataSize, unsigned char *code)
+{
+ unsigned char i;
+ unsigned char numEcc;
+ unsigned int eccParity;
+ unsigned int ecc[16];
+ HSMC4_EccGetValue(ecc);
+ numEcc = pageDataSize / 256;
+
+ // P2048' P1024' P512' P256' P128' P64' P32' P16' --- 3rd. Ecc Byte to store
+ // P8' P4' P2' P1' P2048 P1024 P512 P256 --- 2nd. Ecc Byte to store
+ // P128 P64 P32 P16 P8 P4 P2 P1 --- 1st. Ecc Byte to store
+ for (i = 0; i < numEcc; i++) {
+ // Get Parity and NParity value.
+ eccParity = ecc[i];
+ // Invert codes (linux compatibility)
+ eccParity = ~eccParity;
+ TRACE_DEBUG("ecc Parity%d is 0x%08x \n\r", i, eccParity);
+ code[i * 3] = eccParity & 0xff;
+ code[i * 3 + 1] = (eccParity >> 8) & 0xff;
+ code[i * 3 + 2] = (eccParity >> 16) & 0xff;
+ }
+}
+
+//------------------------------------------------------------------------------
+/// Get 24-bit ECC code for 8-bit data path NAND flash.
+/// 24-bit ECC is generated in order to perform one bit correction
+/// for 512 byte in page 512/1024/2048/4096 for 8-bit words
+/// \param size Data size in bytes.
+/// \param code Codes buffer.
+//------------------------------------------------------------------------------
+void HSMC4_Get24bitPer512Ecc(unsigned int pageDataSize, unsigned char *code)
+{
+ unsigned char i;
+ unsigned char numEcc;
+ unsigned int eccParity;
+ unsigned int ecc[16];
+ HSMC4_EccGetValue(ecc);
+ numEcc = pageDataSize / 512;
+
+ // P2048' P1024' P512' P256' P128' P64' P32' P16' --- 3rd. Ecc Byte to store
+ // P8' P4' P2' P1' P2048 P1024 P512 P256 --- 2nd. Ecc Byte to store
+ // P128 P64 P32 P16 P8 P4 P2 P1 --- 1st. Ecc Byte to store
+ for (i = 0; i < numEcc; i++) {
+ // Get Parity and NParity value.
+ eccParity = ecc[i];
+ // Invert codes (linux compatibility)
+ eccParity = ~eccParity;
+ TRACE_DEBUG("ecc Parity%d is 0x%08x \n\r", i, eccParity);
+ code[i * 3] = eccParity & 0xff;
+ code[i * 3 + 1] = (eccParity >> 8) & 0xff;
+ code[i * 3 + 2] = (eccParity >> 16) & 0xff;
+ }
+}
+
+//------------------------------------------------------------------------------
+/// Get 32-bit ECC code for 16-bit data path NAND flash.
+/// 32-bit ECC is generated in order to perform one bit correction
+/// for 256 word in page 512/1024/2048/4096 for 16-bit words
+/// \param size Data size in bytes.
+/// \param code Codes buffer.
+//------------------------------------------------------------------------------
+void HSMC4_Get32bitPer256Ecc(unsigned int pageDataSize, unsigned char *code)
+{
+ unsigned char i;
+ unsigned char numEcc;
+ unsigned int eccParity;
+ unsigned int eccNparity;
+ unsigned int ecc[16];
+ HSMC4_EccGetValue(ecc);
+ numEcc = pageDataSize / 256;
+
+ // P2048' P1024' P512' P256' P128' P64' P32' P16' --- 3rd. Ecc Byte to store
+ // P8' P4' P2' P1' P2048 P1024 P512 P256 --- 2nd. Ecc Byte to store
+ // P128 P64 P32 P16 P8 P4 P2 P1 --- 1st. Ecc Byte to store
+ for (i = 0; i < numEcc; i+= 2) {
+ // Get Parity value.
+ eccParity = ecc[i];
+ // Invert codes (linux compatibility)
+ eccParity = ~eccParity;
+ // Get NParity value.
+ eccNparity = ecc[i + 1];
+ eccNparity = ~eccNparity;
+ TRACE_DEBUG("ecc Parity%d is 0x%08x, ecc Nparity%d is 0x%08x \n\r", i, eccParity, i, eccNparity);
+ code[i * 3] = eccParity & 0xff;
+ code[i * 3 + 1] = ((eccParity >> 8) & 0x0f ) | ((eccNparity & 0x0f) << 4);
+ code[i * 3 + 2] = (eccNparity >> 4) & 0xff;
+
+ code[(i + 1) * 3] = (eccParity >> 16) & 0xff;
+ code[(i + 1) * 3 + 1] = ((eccParity >> 24) & 0x0f ) | (((eccNparity >> 16)& 0x0f) << 4);
+ code[(i + 1) * 3 + 2] = (eccNparity >> 20) & 0xff;
+
+ }
+}
+
+//------------------------------------------------------------------------------
+/// Get 32-bit ECC code for 16-bit data path NAND flash.
+/// 32-bit ECC is generated in order to perform one bit correction
+/// for a page in page 512/1024/2048/4096 for 16-bit words
+/// \param size Data size in bytes.
+/// \param code Codes buffer.
+//------------------------------------------------------------------------------
+void HSMC4_Get32bitPerPageEcc(unsigned int pageDataSize, unsigned char *code)
+{
+ unsigned int eccParity;
+ unsigned int eccNparity;
+ unsigned int ecc[16];
+ // Get Parity value.
+ HSMC4_EccGetValue(ecc);
+
+ // ---- P16384'P8192'P4096'P2048' P1024'P512'P256' --- 4th. Ecc Byte to store
+ /// P128' P64' P32' P16' P8' P4' P2' P1' --- 3rd. Ecc Byte to store
+ // ---- P16384 P8192 P4096 P2048 P1024 P512 P256 --- 2nd. Ecc Byte to store
+ // P128 P64 P32 P16 P8 P4 P2 P1 --- 1st. Ecc Byte to store
+
+ // Invert codes (linux compatibility)
+ eccParity = ~(ecc[0]);
+ eccNparity = ~(ecc[1]);
+ TRACE_DEBUG("ecc Parity%d is 0x%08x, ecc Nparity%d is 0x%08x \n\r", eccParity, eccNparity);
+ code[0] = eccParity & 0xff;
+ code[1] = (eccParity >> 8 )& 0xff;
+ code[2] = eccNparity & 0xff;
+ code[3] = (eccNparity >> 8 )& 0xff;
+}
+
+//------------------------------------------------------------------------------
+/// Get ECC code for 8bit/16-bit data path NAND flash by giving data path.
+/// 24-bit or 32-bit ECC is generated in order to perform one bit correction
+/// for a page in page 512/1024/2048/4096.
+/// \param size Data size in bytes.
+/// \param code Codes buffer.
+/// \param dataPath 8bit/16bit data path.
+//------------------------------------------------------------------------------
+void HSMC4_GetEccParity(unsigned int pageDataSize, unsigned char *code, unsigned char dataPath)
+{
+ unsigned char correctionType;
+ correctionType = HSMC4_GetEccCorrectoinType();
+ // For 16-bit data path
+ if (dataPath == 16) {
+ switch (correctionType){
+ case AT91C_ECC_TYPCORRECT_ONE_PER_PAGE:
+ HSMC4_Get32bitPerPageEcc(pageDataSize, code);
+ break;
+ case AT91C_ECC_TYPCORRECT_ONE_EVERY_256_BYTES:
+ HSMC4_Get32bitPer256Ecc(pageDataSize, code);
+ break;
+ case AT91C_ECC_TYPCORRECT_ONE_EVERY_512_BYTES:
+ TRACE_WARNING("16 bit 512 byte correct not yet implement! \n\r");
+ break;
+ }
+ }
+ // For 8-bit data path
+ else {
+ switch (correctionType){
+ case AT91C_ECC_TYPCORRECT_ONE_PER_PAGE:
+ HSMC4_Get24bitPerPageEcc(pageDataSize, code);
+ break;
+ case AT91C_ECC_TYPCORRECT_ONE_EVERY_256_BYTES:
+ HSMC4_Get24bitPer256Ecc(pageDataSize, code);
+ break;
+ case AT91C_ECC_TYPCORRECT_ONE_EVERY_512_BYTES:
+ HSMC4_Get24bitPer512Ecc(pageDataSize, code);
+ break;
+ }
+ }
+} \ No newline at end of file
personal git repositories of Harald Welte. Your mileage may vary