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.c
|
|
|
|
|
* Date: 2022-05-10 14:53:42
|
|
|
|
|
* LastEditTime: 2022-05-10 08:56:27
|
2023-05-11 10:25:21 +08:00
|
|
|
|
* Description: This file is for functions in this file are the minimum required functions
|
|
|
|
|
* for this driver.
|
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.h"
|
|
|
|
|
#include "fnand_hw.h"
|
|
|
|
|
#include <stdio.h>
|
|
|
|
|
#include <string.h>
|
|
|
|
|
#include "fnand_id.h"
|
|
|
|
|
#include "fnand_common_cmd.h"
|
|
|
|
|
#include "fdebug.h"
|
|
|
|
|
#define FNAND_DEBUG_TAG "FNAND"
|
|
|
|
|
#define FNAND_DEBUG_I(format, ...) FT_DEBUG_PRINT_I(FNAND_DEBUG_TAG, format, ##__VA_ARGS__)
|
|
|
|
|
#define FNAND_DEBUG_W(format, ...) FT_DEBUG_PRINT_W(FNAND_DEBUG_TAG, format, ##__VA_ARGS__)
|
|
|
|
|
#define FNAND_DEBUG_E(format, ...) FT_DEBUG_PRINT_E(FNAND_DEBUG_TAG, format, ##__VA_ARGS__)
|
|
|
|
|
|
|
|
|
|
extern void FNandHwInit(uintptr_t base_address, FNandInterMode inter_mode);
|
|
|
|
|
extern void FNandHwReset(uintptr_t base_address);
|
|
|
|
|
extern void FNandEnable(uintptr_t base_address);
|
|
|
|
|
extern FError FNandToggleInit(FNand *instance_p, u32 chip_addr);
|
|
|
|
|
extern FError FNandOnfiInit(FNand *instance_p, u32 chip_addr);
|
|
|
|
|
extern FError FNandTimingInterfaceUpdate(FNand *instance_p, u32 chip_addr);
|
|
|
|
|
extern void FNandIsrEnable(FNand *instance_p, u32 int_mask);
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* @name: FNandScan
|
|
|
|
|
* @msg: Nand scanning
|
|
|
|
|
* @note:
|
|
|
|
|
* @param {FNand} *instance_p is the pointer to the FNand instance.
|
|
|
|
|
* @return {FT_SUCCESS} Scan nand is ok
|
|
|
|
|
*/
|
|
|
|
|
FError FNandScan(FNand *instance_p)
|
|
|
|
|
{
|
|
|
|
|
FASSERT(instance_p != NULL);
|
|
|
|
|
FASSERT(instance_p->is_ready == FT_COMPONENT_IS_READY);
|
|
|
|
|
return FNandDetect(instance_p);
|
|
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
u32 FNandCheckBusy(FNand *instance_p)
|
|
|
|
|
{
|
|
|
|
|
FASSERT(instance_p != NULL);
|
|
|
|
|
FASSERT(instance_p->is_ready == FT_COMPONENT_IS_READY);
|
|
|
|
|
FNandConfig *config_p;
|
|
|
|
|
config_p = &instance_p->config;
|
|
|
|
|
|
|
|
|
|
return FNAND_READREG(config_p->base_address, FNAND_STATE_OFFSET) & FNAND_STATE_BUSY_OFFSET;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
FError FNandSendCmd(FNand *instance_p, struct FNandDmaDescriptor *descriptor_p, FNandOperationType isr_type)
|
|
|
|
|
{
|
|
|
|
|
FNandConfig *config_p;
|
|
|
|
|
u32 timeout_cnt = 0;
|
|
|
|
|
FASSERT(instance_p != NULL);
|
|
|
|
|
FASSERT(instance_p->is_ready == FT_COMPONENT_IS_READY);
|
|
|
|
|
FASSERT(isr_type < FNAND_TYPE_NUM);
|
|
|
|
|
|
|
|
|
|
config_p = &instance_p->config;
|
|
|
|
|
|
|
|
|
|
FNandHwReset(config_p->base_address);
|
|
|
|
|
|
|
|
|
|
if (0 != FNandCheckBusy(instance_p))
|
|
|
|
|
{
|
|
|
|
|
FNAND_DEBUG_E("Nand is busy");
|
|
|
|
|
return FNAND_IS_BUSY;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* write dma addr to register */
|
|
|
|
|
FNAND_WRITEREG(config_p->base_address, FNAND_MADDR0_OFFSET, ((uintptr)descriptor_p) & FNAND_MADDR0_DT_LOW_ADDR_MASK);
|
|
|
|
|
|
|
|
|
|
#ifdef __aarch64__
|
|
|
|
|
/* 将高位地址填入寄存器 */
|
|
|
|
|
FNAND_CLEARBIT(config_p->base_address, FNAND_MADDR1_OFFSET, FNAND_MADDR1_DT_HIGH_8BITADDR_MASK);
|
|
|
|
|
FNAND_SETBIT(config_p->base_address, FNAND_MADDR1_OFFSET, ((uintptr)descriptor_p >> 32) & FNAND_MADDR1_DT_HIGH_8BITADDR_MASK);
|
|
|
|
|
#else
|
|
|
|
|
FNAND_CLEARBIT(config_p->base_address, FNAND_MADDR1_OFFSET, FNAND_MADDR1_DT_HIGH_8BITADDR_MASK);
|
|
|
|
|
#endif
|
|
|
|
|
/* 中断模式操作 */
|
|
|
|
|
if (instance_p->work_mode == FNAND_WORK_MODE_ISR)
|
|
|
|
|
{
|
|
|
|
|
if (isr_type == FNAND_CMD_TYPE)
|
|
|
|
|
{
|
|
|
|
|
FNandIsrEnable(instance_p, FNAND_INTRMASK_CMD_FINISH_MASK);
|
|
|
|
|
}
|
|
|
|
|
else if (isr_type == FNAND_WRITE_PAGE_TYPE)
|
|
|
|
|
{
|
|
|
|
|
FNandIsrEnable(instance_p, FNAND_INTRMASK_PGFINISH_MASK);
|
|
|
|
|
}
|
|
|
|
|
else if (isr_type == FNAND_READ_PAGE_TYPE)
|
|
|
|
|
{
|
|
|
|
|
FNandIsrEnable(instance_p, FNAND_INTRMASK_DMA_PGFINISH_MASK);
|
|
|
|
|
}
|
|
|
|
|
else if (isr_type == FNAND_WAIT_ECC_TYPE)
|
|
|
|
|
{
|
|
|
|
|
FNandIsrEnable(instance_p, FNAND_INTRMASK_ECC_FINISH_MASK);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
FNAND_SETBIT(config_p->base_address, FNAND_MADDR1_OFFSET, FNAND_MADDR1_DMA_EN_MASK);
|
|
|
|
|
|
|
|
|
|
if (instance_p->work_mode == FNAND_WORK_MODE_ISR && (instance_p->wait_irq_fun_p != NULL))
|
|
|
|
|
{
|
|
|
|
|
if (instance_p->wait_irq_fun_p)
|
|
|
|
|
{
|
|
|
|
|
if (instance_p->wait_irq_fun_p(instance_p->wait_args) != FT_SUCCESS)
|
|
|
|
|
{
|
|
|
|
|
FNAND_DEBUG_E("wait_irq_fun_p is failed");
|
|
|
|
|
return FNAND_ERR_IRQ_OP_FAILED;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
2023-05-11 10:25:21 +08:00
|
|
|
|
FNAND_DEBUG_E("The member wait_irq_fun_p of instance_p is null");
|
2022-11-10 22:22:48 +08:00
|
|
|
|
FNAND_WRITEREG(config_p->base_address, FNAND_INTRMASK_OFFSET, FNAND_INTRMASK_ALL_INT_MASK);
|
|
|
|
|
return FNAND_ERR_IRQ_LACK_OF_CALLBACK;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return FT_SUCCESS ;
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
if (isr_type == FNAND_CMD_TYPE)
|
|
|
|
|
{
|
|
|
|
|
while (0 == (FNAND_READREG(config_p->base_address, FNAND_STATE_OFFSET) & FNAND_STATE_CMD_PGFINISH_OFFSET))
|
|
|
|
|
{
|
|
|
|
|
if (timeout_cnt++ >= 0xffffff)
|
|
|
|
|
{
|
2023-05-11 10:25:21 +08:00
|
|
|
|
FNAND_DEBUG_E("FNAND_CMD_TYPE is sending timeout");
|
2022-11-10 22:22:48 +08:00
|
|
|
|
return FNAND_OP_TIMEOUT;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
else if (isr_type == FNAND_WRITE_PAGE_TYPE)
|
|
|
|
|
{
|
|
|
|
|
while (0 == (FNAND_READREG(config_p->base_address, FNAND_STATE_OFFSET) & FNAND_STATE_PG_PGFINISH_OFFSET))
|
|
|
|
|
{
|
|
|
|
|
if (timeout_cnt++ >= 0xffffff)
|
|
|
|
|
{
|
2023-05-11 10:25:21 +08:00
|
|
|
|
FNAND_DEBUG_E("FNAND_CMD_TYPE is sending timeout");
|
2022-11-10 22:22:48 +08:00
|
|
|
|
return FNAND_OP_TIMEOUT;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
else if (isr_type == FNAND_READ_PAGE_TYPE)
|
|
|
|
|
{
|
|
|
|
|
while (0 == (FNAND_READREG(config_p->base_address, FNAND_STATE_OFFSET) & FNAND_STATE_DMA_PGFINISH_OFFSET))
|
|
|
|
|
{
|
|
|
|
|
if (timeout_cnt++ >= 0xffffff)
|
|
|
|
|
{
|
2023-05-11 10:25:21 +08:00
|
|
|
|
FNAND_DEBUG_E("FNAND_CMD_TYPE is sending timeout");
|
2022-11-10 22:22:48 +08:00
|
|
|
|
return FNAND_OP_TIMEOUT;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
else if (isr_type == FNAND_WAIT_ECC_TYPE)
|
|
|
|
|
{
|
|
|
|
|
while (0 == (FNAND_READREG(config_p->base_address, FNAND_STATE_OFFSET) & FNAND_STATE_ECC_FINISH_OFFSET))
|
|
|
|
|
{
|
|
|
|
|
if (timeout_cnt++ >= 0xffffff)
|
|
|
|
|
{
|
2023-05-11 10:25:21 +08:00
|
|
|
|
FNAND_DEBUG_E("FNAND_CMD_TYPE is sending timeout");
|
2022-11-10 22:22:48 +08:00
|
|
|
|
return FNAND_OP_TIMEOUT;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return FT_SUCCESS;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* @name: FNandOperationWaitIrqRegister
|
|
|
|
|
* @msg: When nand is sent in interrupt mode, the action that waits while the operation completes
|
|
|
|
|
* @note:
|
|
|
|
|
* @param {FNand} *instance_p is the pointer to the FNand instance.
|
|
|
|
|
* @param {FNandOperationWaitIrqCallback} wait_irq_fun_p , When the user adds this function, return FT_SUCCESS reports success, otherwise failure
|
|
|
|
|
* @param {void} *wait_args
|
|
|
|
|
* @return {*}
|
|
|
|
|
*/
|
|
|
|
|
void FNandOperationWaitIrqRegister(FNand *instance_p, FNandOperationWaitIrqCallback wait_irq_fun_p, void *wait_args)
|
|
|
|
|
{
|
|
|
|
|
FASSERT(instance_p != NULL);
|
|
|
|
|
FASSERT(instance_p->is_ready == FT_COMPONENT_IS_READY);
|
|
|
|
|
|
|
|
|
|
instance_p->wait_irq_fun_p = wait_irq_fun_p;
|
|
|
|
|
instance_p->wait_args = wait_args;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* @name: FNandCfgInitialize
|
|
|
|
|
* @msg: Initialize the NAND controller
|
|
|
|
|
* @param {FNand} *instance_p is the pointer to the FNand instance.
|
|
|
|
|
* @param {FNandConfig} * points to the FNand device configuration structure.
|
|
|
|
|
* @return {FError} FT_SUCCESS if successful
|
|
|
|
|
* @note:
|
|
|
|
|
*/
|
|
|
|
|
FError FNandCfgInitialize(FNand *instance_p,
|
|
|
|
|
FNandConfig *config_p)
|
|
|
|
|
{
|
|
|
|
|
u32 i;
|
|
|
|
|
FError ret;
|
|
|
|
|
/* Assert arguments */
|
|
|
|
|
FASSERT(instance_p != NULL);
|
|
|
|
|
FASSERT(config_p != NULL);
|
|
|
|
|
|
|
|
|
|
/* Clear instance memory and make copy of configuration */
|
|
|
|
|
memset(instance_p, 0, sizeof(FNand));
|
|
|
|
|
instance_p->config = *config_p;
|
|
|
|
|
instance_p->is_ready = FT_COMPONENT_IS_READY;
|
|
|
|
|
|
|
|
|
|
/* lsd config */
|
|
|
|
|
FNAND_CLEARBIT(FLSD_CONFIG_BASE, 0xc0, 1);
|
|
|
|
|
|
|
|
|
|
instance_p->work_mode = FNAND_WORK_MODE_ISR ; /* 默认采用中断模式 */
|
|
|
|
|
for (i = 0; i < FNAND_CONNECT_MAX_NUM; i++)
|
|
|
|
|
{
|
|
|
|
|
instance_p->inter_mode[i] = FNAND_ASYN_SDR; /* 初始化阶段以异步模式启动 */
|
|
|
|
|
instance_p->timing_mode[i] = FNAND_TIMING_MODE0 ;
|
|
|
|
|
/* 初始化时序配置 */
|
|
|
|
|
ret = FNandTimingInterfaceUpdate(instance_p, i);
|
|
|
|
|
if (ret != FT_SUCCESS)
|
|
|
|
|
{
|
|
|
|
|
FNAND_DEBUG_E("%s, FNandTimingInterfaceUpdate is error", __func__);
|
|
|
|
|
return ret;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
FNandHwInit(instance_p->config.base_address, instance_p->inter_mode[0]);
|
|
|
|
|
FNandHwReset(instance_p->config.base_address);
|
|
|
|
|
|
|
|
|
|
/* init ecc strength */
|
|
|
|
|
FNAND_CLEARBIT(instance_p->config.base_address, FNAND_CTRL0_OFFSET, FNAND_CTRL0_ECC_CORRECT_MAKE(7UL)); /* clear all ecc_correct */
|
|
|
|
|
if (instance_p->config.ecc_strength == 0x8)
|
|
|
|
|
{
|
|
|
|
|
FNAND_SETBIT(instance_p->config.base_address, FNAND_CTRL0_OFFSET, FNAND_CTRL0_ECC_CORRECT_MAKE(7UL));
|
|
|
|
|
}
|
|
|
|
|
else if (instance_p->config.ecc_strength == 0x4)
|
|
|
|
|
{
|
|
|
|
|
FNAND_SETBIT(instance_p->config.base_address, FNAND_CTRL0_OFFSET, FNAND_CTRL0_ECC_CORRECT_MAKE(3UL));
|
|
|
|
|
}
|
|
|
|
|
else if (instance_p->config.ecc_strength == 0x2)
|
|
|
|
|
{
|
|
|
|
|
FNAND_SETBIT(instance_p->config.base_address, FNAND_CTRL0_OFFSET, FNAND_CTRL0_ECC_CORRECT_MAKE(1UL));
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
FNAND_SETBIT(instance_p->config.base_address, FNAND_CTRL0_OFFSET, FNAND_CTRL0_ECC_CORRECT_MAKE(0UL));
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
FNandEnable(instance_p->config.base_address);
|
|
|
|
|
|
|
|
|
|
/* init bbm */
|
|
|
|
|
FNandInitBbtDesc(instance_p);
|
|
|
|
|
return (FT_SUCCESS);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* @name: FNandWritePage
|
|
|
|
|
* @msg: Write operations one page at a time, including writing page data and spare data
|
|
|
|
|
* @note:
|
|
|
|
|
* @param {FNand} *instance_p is the pointer to the FNand instance.
|
|
|
|
|
* @param {u32} page_addr is the address to which the page needs to be written
|
|
|
|
|
* @param {u8} *buffer is page writes a pointer to the buffer
|
|
|
|
|
* @param {u32} page_copy_offset is the offset of the page writing , Buffer write data to 0 + page_copy_offset
|
|
|
|
|
* @param {u32} length is page data write length
|
|
|
|
|
* @param {u8} *oob_buffer is the data buffer pointer needs to be written to the spare space
|
|
|
|
|
* @param {u32} oob_copy_offset is the offset of the spare space writing , Buffer write data to page length + oob_copy_offset
|
|
|
|
|
* @param {u32} oob_length is the length to be written to the spare space
|
|
|
|
|
* @param {u32} chip_addr chip address
|
|
|
|
|
* @return {FError} FT_SUCCESS ,write page is successful
|
|
|
|
|
*/
|
|
|
|
|
FError FNandWritePage(FNand *instance_p, u32 page_addr, u8 *buffer, u32 page_copy_offset, u32 length, u8 *oob_buffer, u32 oob_copy_offset, u32 oob_length, u32 chip_addr)
|
|
|
|
|
{
|
|
|
|
|
FASSERT(instance_p != NULL);
|
|
|
|
|
FASSERT(instance_p->is_ready == FT_COMPONENT_IS_READY);
|
|
|
|
|
FASSERT(chip_addr < FNAND_CONNECT_MAX_NUM);
|
|
|
|
|
FASSERT(instance_p->write_hw_ecc_p);
|
|
|
|
|
|
|
|
|
|
FNandOpData op_data =
|
|
|
|
|
{
|
|
|
|
|
.page_addr = page_addr,
|
|
|
|
|
.page_buf = NULL, /* page 数据缓存空间 */
|
|
|
|
|
.page_offset = 0, /* 从offset开始拷贝页数据 */
|
|
|
|
|
.page_length = 0, /* 从offset开始拷贝页数据的长度 */
|
|
|
|
|
.obb_required = 0, /* obb 是否读取的标志位,1 需要操作oob 区域 */
|
|
|
|
|
.oob_buf = NULL, /* obb 数据缓存空间 */
|
|
|
|
|
.oob_offset = 0, /* 从offset开始拷贝页数据 */
|
|
|
|
|
.oob_length = 0, /* 从offset开始拷贝页数据的长度 */
|
|
|
|
|
.chip_addr = chip_addr, /* 芯片地址 */
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
if (buffer && (length > 0))
|
|
|
|
|
{
|
|
|
|
|
op_data.page_buf = buffer;
|
|
|
|
|
op_data.page_length = length;
|
|
|
|
|
op_data.page_offset = page_copy_offset;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (oob_buffer && (oob_length > 0))
|
|
|
|
|
{
|
|
|
|
|
op_data.obb_required = 1;
|
|
|
|
|
op_data.oob_buf = oob_buffer;
|
|
|
|
|
op_data.oob_length = oob_length;
|
|
|
|
|
op_data.oob_offset = oob_copy_offset;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return instance_p->write_hw_ecc_p(instance_p, &op_data);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* @name: FNandWritePage
|
|
|
|
|
* @msg: Write operations one page at a time, including writing page data and spare data ,without hw ecc
|
|
|
|
|
* @note:
|
|
|
|
|
* @param {FNand} *instance_p is the pointer to the FNand instance.
|
|
|
|
|
* @param {u32} page_addr is the address to which the page needs to be written
|
|
|
|
|
* @param {u8} *buffer is page writes a pointer to the buffer
|
|
|
|
|
* @param {u32} page_copy_offset is the offset of the page writing , Buffer write data to 0 + page_copy_offset
|
|
|
|
|
* @param {u32} length is page data write length
|
|
|
|
|
* @param {u8} *oob_buffer is the data buffer pointer needs to be written to the spare space
|
|
|
|
|
* @param {u32} oob_copy_offset is the offset of the spare space writing , Buffer write data to page length + oob_copy_offset
|
|
|
|
|
* @param {u32} oob_length is the length to be written to the spare space
|
|
|
|
|
* @param {u32} chip_addr chip address
|
|
|
|
|
* @return {FError} FT_SUCCESS ,write page is successful
|
|
|
|
|
*/
|
|
|
|
|
FError FNandWritePageRaw(FNand *instance_p, u32 page_addr, u8 *buffer, u32 page_copy_offset, u32 length, u8 *oob_buffer, u32 oob_copy_offset, u32 oob_length, u32 chip_addr)
|
|
|
|
|
{
|
|
|
|
|
FASSERT(instance_p != NULL);
|
|
|
|
|
FASSERT(instance_p->is_ready == FT_COMPONENT_IS_READY);
|
|
|
|
|
FASSERT(chip_addr < FNAND_CONNECT_MAX_NUM);
|
|
|
|
|
FASSERT(instance_p->write_hw_ecc_p);
|
|
|
|
|
|
|
|
|
|
FNandOpData op_data =
|
|
|
|
|
{
|
|
|
|
|
.page_addr = page_addr,
|
|
|
|
|
.page_buf = NULL, /* page 数据缓存空间 */
|
|
|
|
|
.page_offset = 0, /* 从offset开始拷贝页数据 */
|
|
|
|
|
.page_length = 0, /* 从offset开始拷贝页数据的长度 */
|
|
|
|
|
.obb_required = 0, /* obb 是否读取的标志位,1 需要操作oob 区域 */
|
|
|
|
|
.oob_buf = NULL, /* obb 数据缓存空间 */
|
|
|
|
|
.oob_offset = 0, /* 从offset开始拷贝页数据 */
|
|
|
|
|
.oob_length = 0, /* 从offset开始拷贝页数据的长度 */
|
|
|
|
|
.chip_addr = chip_addr, /* 芯片地址 */
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
if (buffer && (length > 0))
|
|
|
|
|
{
|
|
|
|
|
op_data.page_buf = buffer;
|
|
|
|
|
op_data.page_length = length;
|
|
|
|
|
op_data.page_offset = page_copy_offset;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (oob_buffer && (oob_length > 0))
|
|
|
|
|
{
|
|
|
|
|
op_data.obb_required = 1;
|
|
|
|
|
op_data.oob_buf = oob_buffer;
|
|
|
|
|
op_data.oob_length = oob_length;
|
|
|
|
|
op_data.oob_offset = oob_copy_offset;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return instance_p->write_p(instance_p, &op_data);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* @name: FNandReadPage
|
|
|
|
|
* @msg: Read operations one page at a time, including reading page data and spare space data
|
|
|
|
|
* @note:
|
|
|
|
|
* @param {FNand} *instance_p is the pointer to the FNand instance.
|
|
|
|
|
* @param {u32} page_addr is the address to which the page needs to be readed
|
|
|
|
|
* @param {u8} *buffer is the buffer used by the user to read page data
|
|
|
|
|
* @param {u32} page_copy_offset is the offset of the page reading , Buffer read data from 0 + page_copy_offset of per page
|
|
|
|
|
* @param {u32} length is page data read length
|
|
|
|
|
* @param {u8} *oob_buffer is buffer that read data from the spare space
|
|
|
|
|
* @param {u32} oob_copy_offset is the offset of the spare space reading , Buffer reads data from page length + oob_copy_offset
|
|
|
|
|
* @param {u32} oob_length is the length to be written to the spare space
|
|
|
|
|
* @param {u32} chip_addr chip address
|
|
|
|
|
* @return {FError} FT_SUCCESS is read successful
|
|
|
|
|
*/
|
|
|
|
|
FError FNandReadPage(FNand *instance_p, u32 page_addr, u8 *buffer, u32 page_copy_offset, u32 length, u8 *oob_buffer, u32 oob_copy_offset, u32 oob_length, u32 chip_addr)
|
|
|
|
|
{
|
|
|
|
|
FASSERT(instance_p != NULL);
|
|
|
|
|
FASSERT(instance_p->is_ready == FT_COMPONENT_IS_READY);
|
|
|
|
|
FASSERT(chip_addr < FNAND_CONNECT_MAX_NUM);
|
|
|
|
|
FASSERT(instance_p->read_hw_ecc_p);
|
|
|
|
|
|
|
|
|
|
FNandOpData op_data =
|
|
|
|
|
{
|
|
|
|
|
.page_addr = page_addr,
|
|
|
|
|
.page_buf = NULL, /* page 数据缓存空间 */
|
|
|
|
|
.page_offset = 0, /* 从offset开始拷贝页数据 */
|
|
|
|
|
.page_length = 0, /* 从offset开始拷贝页数据的长度 */
|
|
|
|
|
.obb_required = 0, /* obb 是否读取的标志位,1 需要操作oob 区域 */
|
|
|
|
|
.oob_buf = NULL, /* obb 数据缓存空间 */
|
|
|
|
|
.oob_offset = 0, /* 从offset开始拷贝页数据 */
|
|
|
|
|
.oob_length = 0, /* 从offset开始拷贝页数据的长度 */
|
|
|
|
|
.chip_addr = chip_addr, /* 芯片地址 */
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
/* clear buffer */
|
|
|
|
|
if (buffer && (length > 0))
|
|
|
|
|
{
|
|
|
|
|
op_data.page_buf = buffer;
|
|
|
|
|
op_data.page_length = length;
|
|
|
|
|
op_data.page_offset = page_copy_offset;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (oob_buffer && (oob_length > 0))
|
|
|
|
|
{
|
|
|
|
|
op_data.obb_required = 1;
|
|
|
|
|
op_data.oob_buf = oob_buffer;
|
|
|
|
|
op_data.oob_length = oob_length;
|
|
|
|
|
op_data.oob_offset = oob_copy_offset;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return instance_p->read_hw_ecc_p(instance_p, &op_data);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
FError FNandReadPageRaw(FNand *instance_p, u32 page_addr, u8 *buffer, u32 page_copy_offset, u32 length, u8 *oob_buffer, u32 oob_copy_offset, u32 oob_length, u32 chip_addr)
|
|
|
|
|
{
|
|
|
|
|
FASSERT(instance_p != NULL);
|
|
|
|
|
FASSERT(instance_p->is_ready == FT_COMPONENT_IS_READY);
|
|
|
|
|
FASSERT(chip_addr < FNAND_CONNECT_MAX_NUM);
|
|
|
|
|
FASSERT(instance_p->read_hw_ecc_p);
|
|
|
|
|
|
|
|
|
|
FNandOpData op_data =
|
|
|
|
|
{
|
|
|
|
|
.page_addr = page_addr,
|
|
|
|
|
.page_buf = NULL, /* page 数据缓存空间 */
|
|
|
|
|
.page_offset = 0, /* 从offset开始拷贝页数据 */
|
|
|
|
|
.page_length = 0, /* 从offset开始拷贝页数据的长度 */
|
|
|
|
|
.obb_required = 0, /* obb 是否读取的标志位,1 需要操作oob 区域 */
|
|
|
|
|
.oob_buf = NULL, /* obb 数据缓存空间 */
|
|
|
|
|
.oob_offset = 0, /* 从offset开始拷贝页数据 */
|
|
|
|
|
.oob_length = 0, /* 从offset开始拷贝页数据的长度 */
|
|
|
|
|
.chip_addr = chip_addr, /* 芯片地址 */
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
/* clear buffer */
|
|
|
|
|
if (buffer && (length > 0))
|
|
|
|
|
{
|
|
|
|
|
op_data.page_buf = buffer;
|
|
|
|
|
op_data.page_length = length;
|
|
|
|
|
op_data.page_offset = page_copy_offset;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (oob_buffer && (oob_length > 0))
|
|
|
|
|
{
|
|
|
|
|
op_data.obb_required = 1;
|
|
|
|
|
op_data.oob_buf = oob_buffer;
|
|
|
|
|
op_data.oob_length = oob_length;
|
|
|
|
|
op_data.oob_offset = oob_copy_offset;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return instance_p->read_p(instance_p, &op_data);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* @name: FNandEraseBlock
|
|
|
|
|
* @msg: erase block data
|
|
|
|
|
* @note: 擦除之后增加read status 命令进行检查。(70h)
|
|
|
|
|
* @param {FNand} *instance_p is the pointer to the FNand instance.
|
|
|
|
|
* @param {u32} block is block number
|
|
|
|
|
* @param {u32} chip_addr is chip address
|
|
|
|
|
* @return {FError} FT_SUCCESS is erase is successful
|
|
|
|
|
*/
|
|
|
|
|
FError FNandEraseBlock(FNand *instance_p, u32 block, u32 chip_addr)
|
|
|
|
|
{
|
|
|
|
|
u32 page_address;
|
|
|
|
|
FASSERT(instance_p != NULL);
|
|
|
|
|
FASSERT(instance_p->is_ready == FT_COMPONENT_IS_READY);
|
|
|
|
|
FASSERT(chip_addr < FNAND_CONNECT_MAX_NUM);
|
|
|
|
|
page_address = block * instance_p->nand_geometry[chip_addr].pages_per_block;
|
|
|
|
|
return instance_p->erase_p(instance_p, page_address, chip_addr);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* @name: FNandReadPageOOb
|
|
|
|
|
* @msg: Read spare space fo per page
|
|
|
|
|
* @note:
|
|
|
|
|
* @param {FNand} *instance_p is the instance pointer
|
|
|
|
|
* @param {u32} page_addr is the Row Address of the spare space needs to be read
|
|
|
|
|
* @param {u8} *oob_buffer is the buffer used by the user to read spare space data
|
|
|
|
|
* @param {u32} oob_copy_offset is the offset of the spare space reading , Buffer reads data from page length + page_copy_offset
|
|
|
|
|
* @param {u32} oob_length is the length of data retrieved from spare space
|
|
|
|
|
* @param {u32} chip_addr is chip address
|
|
|
|
|
* @return {FError} FT_SUCCESS is read successful
|
|
|
|
|
*/
|
|
|
|
|
FError FNandReadPageOOb(FNand *instance_p, u32 page_addr, u8 *oob_buffer, u32 oob_copy_offset, u32 oob_length, u32 chip_addr)
|
|
|
|
|
{
|
|
|
|
|
FASSERT(instance_p != NULL);
|
|
|
|
|
FASSERT(instance_p->is_ready == FT_COMPONENT_IS_READY);
|
|
|
|
|
FASSERT(chip_addr < FNAND_CONNECT_MAX_NUM);
|
|
|
|
|
|
|
|
|
|
FNandOpData op_data =
|
|
|
|
|
{
|
|
|
|
|
.page_addr = page_addr,
|
|
|
|
|
.page_buf = NULL, /* page 数据缓存空间 */
|
|
|
|
|
.page_offset = 0, /* 从offset开始拷贝页数据 */
|
|
|
|
|
.page_length = 0, /* 从offset开始拷贝页数据的长度 */
|
|
|
|
|
.obb_required = 1, /* obb 是否读取的标志位,1 需要操作oob 区域 */
|
|
|
|
|
.oob_buf = oob_buffer, /* obb 数据缓存空间 */
|
|
|
|
|
.oob_offset = oob_copy_offset, /* 从offset开始拷贝页数据 */
|
|
|
|
|
.oob_length = oob_length, /* 从offset开始拷贝页数据的长度 */
|
|
|
|
|
.chip_addr = chip_addr, /* 芯片地址 */
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
return instance_p->read_oob_p(instance_p, &op_data);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* @name: FNandWritePageOOb
|
|
|
|
|
* @msg: write data to the spare space
|
|
|
|
|
* @note:
|
|
|
|
|
* @param {FNand} *instance_p is the instance pointer
|
|
|
|
|
* @param {u32} page_addr is the Row Address of the spare space needs to be write
|
|
|
|
|
* @param {u8} *oob_buffer is buffer that writes data to the spare space
|
|
|
|
|
* @param {u32} page_copy_offset is the offset of the spare space writing , Buffer write data to page length + page_copy_offset
|
|
|
|
|
* @param {u32} oob_length is the length to be written to the spare space
|
|
|
|
|
* @param {u32} chip_addr is chip address
|
|
|
|
|
* @return {FError} FT_SUCCESS is write successful
|
|
|
|
|
*/
|
|
|
|
|
FError FNandWritePageOOb(FNand *instance_p, u32 page_addr, u8 *oob_buffer, u32 page_copy_offset, u32 oob_length, u32 chip_addr)
|
|
|
|
|
{
|
|
|
|
|
FASSERT(instance_p != NULL);
|
|
|
|
|
FASSERT(instance_p->is_ready == FT_COMPONENT_IS_READY);
|
|
|
|
|
FASSERT(chip_addr < FNAND_CONNECT_MAX_NUM);
|
|
|
|
|
|
|
|
|
|
FNandOpData op_data =
|
|
|
|
|
{
|
|
|
|
|
.page_addr = page_addr,
|
|
|
|
|
.page_buf = NULL, /* page 数据缓存空间 */
|
|
|
|
|
.page_offset = 0, /* 从offset开始拷贝页数据 */
|
|
|
|
|
.page_length = 0, /* 从offset开始拷贝页数据的长度 */
|
|
|
|
|
.obb_required = 1, /* obb 是否读取的标志位,1 需要操作oob 区域 */
|
|
|
|
|
.oob_buf = oob_buffer, /* obb 数据缓存空间 */
|
|
|
|
|
.oob_offset = page_copy_offset, /* 从offset开始拷贝页数据 */
|
|
|
|
|
.oob_length = oob_length, /* 从offset开始拷贝页数据的长度 */
|
|
|
|
|
.chip_addr = chip_addr, /* 芯片地址 */
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
return instance_p->write_oob_p(instance_p, &op_data);
|
|
|
|
|
}
|