From 044ad7c3987460ede48ff27afd6bdb0ca05a0432 Mon Sep 17 00:00:00 2001 From: Harald Welte Date: Mon, 4 Jul 2011 20:52:54 +0200 Subject: import at91lib from at91lib_20100901_softpack_1_9_v_1_0_svn_v15011 it's sad to see that atmel doesn't publish their svn repo or has a centralized location or even puts proper version/release info into the library itself --- peripherals/hsmc4/hsmc4_ecc.c | 703 ++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 703 insertions(+) create mode 100644 peripherals/hsmc4/hsmc4_ecc.c (limited to 'peripherals/hsmc4/hsmc4_ecc.c') 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 +#include + +//------------------------------------------------------------------------------ +// 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 -- cgit v1.2.3