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

267 lines
7.8 KiB
C
Raw Normal View History

/*
* 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 files is for
*
* Modify History:
* Ver   Who        Date         Changes
* ----- ------     --------    --------------------------------------
*/
#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_strengthecc
* @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 + 4 * (2 * i + j));
value = FNAND_READREG(base_address, 0xB8 + 0x10 * i + 4 * j);
// FNAND_ECC_DEBUG_W("index:%x i is %d ,j is %d ",
// 0xB8 + 0x10 * i + 4*j,i,j);
if (value)
{
// FNAND_ECC_DEBUG_W("offset:%x value:0x%08x\n",
// 0xB8 + 0x10 * i + 4*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]);
}
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;
}