rt-thread/bsp/phytium/libraries/standalone/drivers/nand/fnand/fnand_ecc.c

299 lines
8.2 KiB
C
Raw Blame History

This file contains invisible Unicode characters

This file contains invisible Unicode characters that are indistinguishable to humans but may be processed differently by a computer. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

/*
* Copyright : (C) 2022 Phytium Information Technology, Inc.
* All Rights Reserved.
*
* This program is OPEN SOURCE software: you can redistribute it and/or modify it
* under the terms of the Phytium Public License as published by the Phytium Technology Co.,Ltd,
* either version 1.0 of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,but WITHOUT ANY WARRANTY;
* without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
* See the Phytium Public License for more details.
*
*
* FilePath: fnand_ecc.c
* Date: 2022-05-12 14:17:42
* LastEditTime: 2022-05-12 15:56:27
* Description:  This file is for ecc validation related api
*
* Modify History:
* Ver   Who        Date         Changes
* ----- ------     --------    --------------------------------------
* 1.0 huanghe 2022/05/10 first release
*/
#include "fnand_ecc.h"
#include "fnand.h"
#include "fnand_hw.h"
#include "fdebug.h"
#define FNAND_ECC_DEBUG_TAG "FNAND_ECC"
#define FNAND_ECC_DEBUG_I(format, ...) FT_DEBUG_PRINT_I(FNAND_ECC_DEBUG_TAG, format, ##__VA_ARGS__)
#define FNAND_ECC_DEBUG_W(format, ...) FT_DEBUG_PRINT_W(FNAND_ECC_DEBUG_TAG, format, ##__VA_ARGS__)
#define FNAND_ECC_DEBUG_E(format, ...) FT_DEBUG_PRINT_E(FNAND_ECC_DEBUG_TAG, format, ##__VA_ARGS__)
/**
* @name: FNandGetEccTotalLength
* @msg: 根据page size 与 ecc_strength纠错个数确定硬件ecc 产生
* @param {u32} bytes_per_page
* @param {u32} ecc_strength
* @return {*}
* @note:
*/
u32 FNandGetEccTotalLength(u32 bytes_per_page, u32 ecc_strength)
{
int ecc_total = 0;
switch (bytes_per_page)
{
case 0x200:
if (ecc_strength == 8)
{
ecc_total = 0x0D;
}
else if (ecc_strength == 4)
{
ecc_total = 7;
}
else if (ecc_strength == 2)
{
ecc_total = 4;
}
else
{
ecc_total = 0;
}
break;
case 0x800:
if (ecc_strength == 8)
{
ecc_total = 0x34;
}
else if (ecc_strength == 4)
{
ecc_total = 0x1a;
}
else if (ecc_strength == 2)
{
ecc_total = 0xd;
}
else
{
ecc_total = 0;
}
break;
case 0x1000:
if (ecc_strength == 8)
{
ecc_total = 0x68;
}
else if (ecc_strength == 4)
{
ecc_total = 0x34;
}
else if (ecc_strength == 2)
{
ecc_total = 0x1a;
}
else
{
ecc_total = 0;
}
break;
case 0x2000:
if (ecc_strength == 8)
{
ecc_total = 0xD0;
}
else if (ecc_strength == 4)
{
ecc_total = 0x68;
}
else if (ecc_strength == 2)
{
ecc_total = 0x34;
}
else
{
ecc_total = 0;
}
break;
case 0x4000:
if (ecc_strength == 8)
{
ecc_total = 0x1A0;
}
if (ecc_strength == 4)
{
ecc_total = 0xD0;
}
else if (ecc_strength == 2)
{
ecc_total = 0x68;
}
else
{
ecc_total = 0;
}
break;
default:
ecc_total = 0;
break;
}
FNAND_ECC_DEBUG_I("[%s %d]writesize: 0x%x, ecc strength: %d, ecc_total: 0x%x\n", __func__, __LINE__, bytes_per_page, ecc_strength, ecc_total);
return ecc_total;
}
/**
* @name: FNandCorrectEcc
* @msg:
* @note:
* @return {*}
* @param {uintptr_t} base_address
* @param {u32} ecc_step_size 单次ecc 使用的步长大小
* @param {u32} hw_ecc_steps 一页操作需要进行的ecc 次数
* @param {u8*} buf page 页 对应的指针
* @param {u32} length
*/
// s32 FNandCorrectEcc(uintptr_t base_address,u32 ecc_step_size,u32 hw_ecc_steps,u8* buf ,u32 length)
// {
// u32 i, j;
// u32 value, tmp;
// int stat = 0;
// if(!buf)
// {
// FNAND_ECC_DEBUG_E("page buffer is null");
// return -1;
// }
// /* i */
// for (i = 0; i < hw_ecc_steps; i++)
// {
// for (j = 0; j < 2; j++) {
// value = FNAND_READREG(base_address, 0xB8 + 4 * (2 * i + j));
// FNAND_ECC_DEBUG_W("index:%x i is %d ,j is %d ",
// 0xB8 + 4 * (2 * i + j),i,j);
// if (value)
// {
// FNAND_ECC_DEBUG_W("offset:%x value:0x%08x\n",
// 0xB8 + 4 * (2 * i + j), value);
// //phytium_nfc_data_dump2(nfc, nfc->dma_buf + (ecc_step_size * i + tmp/8)/512, 512);
// }
// tmp = value & 0xFFFF;
// if (tmp && (tmp <= 4096))
// {
// tmp -= 1;
// FNAND_ECC_DEBUG_W( "ECC_CORRECT %x %02x\n",
// ecc_step_size * i + tmp / 8,
// buf[ecc_step_size * i + tmp / 8]);
// buf[ecc_step_size*i + tmp/8] ^= (0x01 << tmp%8);
// stat++;
// FNAND_ECC_DEBUG_W( "ECC_CORRECT xor %x %02x\n",
// 0x01 << tmp % 8,
// buf[ecc_step_size * i + tmp / 8]);
// }
// else
// {
// FNAND_ECC_DEBUG_E("ECC_CORRECT offset > 4096!\n");
// }
// tmp = (value >> 16) & 0xFFFF;
// if (tmp && (tmp <= 4096) )
// {
// tmp -= 1;
// FNAND_ECC_DEBUG_W( "ECC_CORRECT %x %02x\n",
// ecc_step_size * i + tmp / 8,
// buf[ecc_step_size * i + tmp / 8]);
// buf[ecc_step_size*i + tmp/8] ^= (0x01 << tmp%8);
// stat++;
// FNAND_ECC_DEBUG_W( "ECC_CORRECT xor %x %02x\n",
// ecc_step_size * i + tmp / 8,
// buf[ecc_step_size * i + tmp / 8]);
// }
// else
// {
// FNAND_ECC_DEBUG_E("ECC_CORRECT offset > 4096!\n");
// }
// }
// }
// return stat;
// }
// 校验offset 0xb8 + i * 0x10
// 校验强度为 2 j = 1
// 校验强度为 4 j = 2
// 校验强度为 8 j = 4
s32 FNandCorrectEcc(uintptr_t base_address, u32 ecc_step_size, u32 hw_ecc_steps, u8 *buf, u32 length)
{
u32 i, j;
u32 value, tmp;
int stat = 0;
if (!buf)
{
FNAND_ECC_DEBUG_E("Page buffer is null");
return -1;
}
/* i */
for (i = 0; i < hw_ecc_steps; i++)
{
for (j = 0; j < 4; j++)
{
value = FNAND_READREG(base_address, 0xB8 + 0x10 * i + 4 * j);
tmp = value & 0xFFFF;
if (tmp && (tmp <= 4096))
{
tmp -= 1;
FNAND_ECC_DEBUG_W("ECC_CORRECT %x %02x\n",
ecc_step_size * i + tmp / 8,
buf[ecc_step_size * i + tmp / 8]);
buf[ecc_step_size * i + tmp / 8] ^= (0x01 << tmp % 8);
stat++;
FNAND_ECC_DEBUG_W("ECC_CORRECT xor %x %02x\n",
0x01 << tmp % 8,
buf[ecc_step_size * i + tmp / 8]);
}
tmp = (value >> 16) & 0xFFFF;
if (tmp && (tmp <= 4096))
{
tmp -= 1;
FNAND_ECC_DEBUG_W("ECC_CORRECT %x %02x\n",
ecc_step_size * i + tmp / 8,
buf[ecc_step_size * i + tmp / 8]);
buf[ecc_step_size * i + tmp / 8] ^= (0x01 << tmp % 8);
stat++;
FNAND_ECC_DEBUG_W("ECC_CORRECT xor %x %02x\n",
ecc_step_size * i + tmp / 8,
buf[ecc_step_size * i + tmp / 8]);
}
}
}
return stat;
}