2022-11-10 22:22:48 +08:00
|
|
|
|
/*
|
|
|
|
|
* 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
|
2023-05-11 10:25:21 +08:00
|
|
|
|
* Description: This file is for ecc validation related api
|
2022-11-10 22:22:48 +08:00
|
|
|
|
*
|
|
|
|
|
* Modify History:
|
|
|
|
|
* Ver Who Date Changes
|
|
|
|
|
* ----- ------ -------- --------------------------------------
|
2023-05-11 10:25:21 +08:00
|
|
|
|
* 1.0 huanghe 2022/05/10 first release
|
2022-11-10 22:22:48 +08:00
|
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
#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)
|
|
|
|
|
{
|
2023-05-11 10:25:21 +08:00
|
|
|
|
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:
|
2022-11-10 22:22:48 +08:00
|
|
|
|
ecc_total = 0;
|
2023-05-11 10:25:21 +08:00
|
|
|
|
break;
|
2022-11-10 22:22:48 +08:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
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)
|
|
|
|
|
{
|
2023-05-11 10:25:21 +08:00
|
|
|
|
FNAND_ECC_DEBUG_E("Page buffer is null");
|
2022-11-10 22:22:48 +08:00
|
|
|
|
return -1;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* i */
|
|
|
|
|
for (i = 0; i < hw_ecc_steps; i++)
|
|
|
|
|
{
|
|
|
|
|
for (j = 0; j < 4; j++)
|
2023-05-11 10:25:21 +08:00
|
|
|
|
{
|
2022-11-10 22:22:48 +08:00
|
|
|
|
value = FNAND_READREG(base_address, 0xB8 + 0x10 * i + 4 * j);
|
2023-05-11 10:25:21 +08:00
|
|
|
|
|
2022-11-10 22:22:48 +08:00
|
|
|
|
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;
|
|
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|