299 lines
8.2 KiB
C
299 lines
8.2 KiB
C
/*
|
||
* 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;
|
||
|
||
}
|
||
|
||
|
||
|