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

468 lines
15 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.

/*
* 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_timing.c
* Date: 2022-05-09 14:53:42
* LastEditTime: 2022-05-09 08:56:27
* Description:  This files is for
*
* Modify History:
* Ver   Who        Date         Changes
* ----- ------     --------    --------------------------------------
*/
#include "ferror_code.h"
#include "fnand.h"
#include "fnand_hw.h"
#include "fdebug.h"
#define FNAND_TIMING_DEBUG_TAG "FNAND_TIMING"
#define FNAND_TIMING_DEBUG_I(format, ...) FT_DEBUG_PRINT_I(FNAND_TIMING_DEBUG_TAG, format, ##__VA_ARGS__)
#define FNAND_TIMING_DEBUG_W(format, ...) FT_DEBUG_PRINT_W(FNAND_TIMING_DEBUG_TAG, format, ##__VA_ARGS__)
#define FNAND_TIMING_DEBUG_E(format, ...) FT_DEBUG_PRINT_E(FNAND_TIMING_DEBUG_TAG, format, ##__VA_ARGS__)
#define FNAND_TIMING_ASY_NUM 12
#define FNAND_TIMING_SYN_NUM 14
#define FNAND_TIMING_TOG_NUM 12
const u16 fnand_timing_asy_mode0[FNAND_TIMING_ASY_NUM] = {0x03, 0x03, 0x28, 0x28, 0x03, 0x03, 0x06, 0x06, 0x28, 0x70, 0x30, 0x50};
const u16 fnand_timing_asy_mode1[FNAND_TIMING_ASY_NUM] = {0x03, 0x03, 0x14, 0x14, 0x03, 0x03, 0x06, 0x06, 0x14, 0x70, 0x20, 0x28};
const u16 fnand_timing_asy_mode2[FNAND_TIMING_ASY_NUM] = {0x03, 0x03, 0x0D, 0x0D, 0x03, 0x03, 0x06, 0x06, 0x0D, 0x70, 0x20, 0x1A};
const u16 fnand_timing_asy_mode3[FNAND_TIMING_ASY_NUM] = {0x03, 0x03, 0x0A, 0x0A, 0x03, 0x03, 0x06, 0x06, 0x0A, 0x70, 0x20, 0x14};
const u16 fnand_timing_asy_mode4[FNAND_TIMING_ASY_NUM] = {0x03, 0x03, 0x08, 0x08, 0x03, 0x03, 0x06, 0x06, 0x08, 0x70, 0x15, 0x10};
const u16 fnand_timing_asy_mode5[FNAND_TIMING_ASY_NUM] = {0x03, 0x03, 0x07, 0x07, 0x03, 0x03, 0x06, 0x06, 0x07, 0x20, 0x15, 0x0E};
const u16 fnand_timing_syn_mode0[FNAND_TIMING_SYN_NUM] = {0x20, 0x41, 0x05, 0x20, 0x10, 0x19, 0x62, 0x40, 0x38, 0x20, 0x00, 0x09, 0x50, 0x20};
const u16 fnand_timing_syn_mode1[FNAND_TIMING_SYN_NUM] = {0x18, 0x32, 0x06, 0x18, 0x0C, 0x10, 0x76, 0x40, 0x2A, 0x18, 0x00, 0x12, 0x24, 0x18};
const u16 fnand_timing_syn_mode2[FNAND_TIMING_SYN_NUM] = {0x10, 0x0A, 0x04, 0x10, 0x08, 0x0A, 0x6E, 0x50, 0x1D, 0x10, 0x00, 0x0C, 0x18, 0x10};
const u16 fnand_timing_syn_mode3[FNAND_TIMING_SYN_NUM] = {0x0C, 0x1A, 0x02, 0x0C, 0x06, 0x08, 0x78, 0x7C, 0x15, 0x0C, 0x00, 0x08, 0x12, 0x0C};
const u16 fnand_timing_syn_mode4[FNAND_TIMING_SYN_NUM] = {0x08, 0x17, 0x05, 0x08, 0x04, 0x01, 0x73, 0x40, 0x0C, 0x08, 0x00, 0x06, 0x0C, 0x10};
const u16 fnand_timing_tog_ddr_mode0[FNAND_TIMING_TOG_NUM] = {0x14, 0x0a, 0x08, 0x08, 0xc8, 0xc8, 0x08, 0x08, 0x14, 0x0a, 0x14, 0x08}; /* 600M clk */
#define ONFI_DYN_TIMING_MAX ((u16)~0U)
static const struct FNandSdrTimings onfi_sdr_timings[] =
{
{
.tCCS_min = 500000,
.tR_max = 200000000,
.tADL_min = 400000,
.tALH_min = 20000,
.tALS_min = 50000,
.tAR_min = 25000,
.tCEA_max = 100000,
.tCEH_min = 20000,
.tCH_min = 20000,
.tCHZ_max = 100000,
.tCLH_min = 20000,
.tCLR_min = 20000,
.tCLS_min = 50000,
.tCOH_min = 0,
.tCS_min = 70000,
.tDH_min = 20000,
.tDS_min = 40000,
.tFEAT_max = 1000000,
.tIR_min = 10000,
.tITC_max = 1000000,
.tRC_min = 100000,
.tREA_max = 40000,
.tREH_min = 30000,
.tRHOH_min = 0,
.tRHW_min = 200000,
.tRHZ_max = 200000,
.tRLOH_min = 0,
.tRP_min = 50000,
.tRR_min = 40000,
.tRST_max = 250000000000ULL,
.tWB_max = 200000,
.tWC_min = 100000,
.tWH_min = 30000,
.tWHR_min = 120000,
.tWP_min = 50000,
.tWW_min = 100000,
},
/* Mode 1 */
{
.tCCS_min = 500000,
.tR_max = 200000000,
.tADL_min = 400000,
.tALH_min = 10000,
.tALS_min = 25000,
.tAR_min = 10000,
.tCEA_max = 45000,
.tCEH_min = 20000,
.tCH_min = 10000,
.tCHZ_max = 50000,
.tCLH_min = 10000,
.tCLR_min = 10000,
.tCLS_min = 25000,
.tCOH_min = 15000,
.tCS_min = 35000,
.tDH_min = 10000,
.tDS_min = 20000,
.tFEAT_max = 1000000,
.tIR_min = 0,
.tITC_max = 1000000,
.tRC_min = 50000,
.tREA_max = 30000,
.tREH_min = 15000,
.tRHOH_min = 15000,
.tRHW_min = 100000,
.tRHZ_max = 100000,
.tRLOH_min = 0,
.tRP_min = 25000,
.tRR_min = 20000,
.tRST_max = 500000000,
.tWB_max = 100000,
.tWC_min = 45000,
.tWH_min = 15000,
.tWHR_min = 80000,
.tWP_min = 25000,
.tWW_min = 100000,
},
/* Mode 2 */
{
.tCCS_min = 500000,
.tR_max = 200000000,
.tADL_min = 400000,
.tALH_min = 10000,
.tALS_min = 15000,
.tAR_min = 10000,
.tCEA_max = 30000,
.tCEH_min = 20000,
.tCH_min = 10000,
.tCHZ_max = 50000,
.tCLH_min = 10000,
.tCLR_min = 10000,
.tCLS_min = 15000,
.tCOH_min = 15000,
.tCS_min = 25000,
.tDH_min = 5000,
.tDS_min = 15000,
.tFEAT_max = 1000000,
.tIR_min = 0,
.tITC_max = 1000000,
.tRC_min = 35000,
.tREA_max = 25000,
.tREH_min = 15000,
.tRHOH_min = 15000,
.tRHW_min = 100000,
.tRHZ_max = 100000,
.tRLOH_min = 0,
.tRR_min = 20000,
.tRST_max = 500000000,
.tWB_max = 100000,
.tRP_min = 17000,
.tWC_min = 35000,
.tWH_min = 15000,
.tWHR_min = 80000,
.tWP_min = 17000,
.tWW_min = 100000,
},
/* Mode 3 */
{
.tCCS_min = 500000,
.tR_max = 200000000,
.tADL_min = 400000,
.tALH_min = 5000,
.tALS_min = 10000,
.tAR_min = 10000,
.tCEA_max = 25000,
.tCEH_min = 20000,
.tCH_min = 5000,
.tCHZ_max = 50000,
.tCLH_min = 5000,
.tCLR_min = 10000,
.tCLS_min = 10000,
.tCOH_min = 15000,
.tCS_min = 25000,
.tDH_min = 5000,
.tDS_min = 10000,
.tFEAT_max = 1000000,
.tIR_min = 0,
.tITC_max = 1000000,
.tRC_min = 30000,
.tREA_max = 20000,
.tREH_min = 10000,
.tRHOH_min = 15000,
.tRHW_min = 100000,
.tRHZ_max = 100000,
.tRLOH_min = 0,
.tRP_min = 15000,
.tRR_min = 20000,
.tRST_max = 500000000,
.tWB_max = 100000,
.tWC_min = 30000,
.tWH_min = 10000,
.tWHR_min = 80000,
.tWP_min = 15000,
.tWW_min = 100000,
},
/* Mode 4 */
{
.tCCS_min = 500000,
.tR_max = 200000000,
.tADL_min = 400000,
.tALH_min = 5000,
.tALS_min = 10000,
.tAR_min = 10000,
.tCEA_max = 25000,
.tCEH_min = 20000,
.tCH_min = 5000,
.tCHZ_max = 30000,
.tCLH_min = 5000,
.tCLR_min = 10000,
.tCLS_min = 10000,
.tCOH_min = 15000,
.tCS_min = 20000,
.tDH_min = 5000,
.tDS_min = 10000,
.tFEAT_max = 1000000,
.tIR_min = 0,
.tITC_max = 1000000,
.tRC_min = 25000,
.tREA_max = 20000,
.tREH_min = 10000,
.tRHOH_min = 15000,
.tRHW_min = 100000,
.tRHZ_max = 100000,
.tRLOH_min = 5000,
.tRP_min = 12000,
.tRR_min = 20000,
.tRST_max = 500000000,
.tWB_max = 100000,
.tWC_min = 25000,
.tWH_min = 10000,
.tWHR_min = 80000,
.tWP_min = 12000,
.tWW_min = 100000,
},
/* Mode 5 */
{
.tCCS_min = 500000,
.tR_max = 200000000,
.tADL_min = 400000,
.tALH_min = 5000,
.tALS_min = 10000,
.tAR_min = 10000,
.tCEA_max = 25000,
.tCEH_min = 20000,
.tCH_min = 5000,
.tCHZ_max = 30000,
.tCLH_min = 5000,
.tCLR_min = 10000,
.tCLS_min = 10000,
.tCOH_min = 15000,
.tCS_min = 15000,
.tDH_min = 5000,
.tDS_min = 7000,
.tFEAT_max = 1000000,
.tIR_min = 0,
.tITC_max = 1000000,
.tRC_min = 20000,
.tREA_max = 16000,
.tREH_min = 7000,
.tRHOH_min = 15000,
.tRHW_min = 100000,
.tRHZ_max = 100000,
.tRLOH_min = 5000,
.tRP_min = 10000,
.tRR_min = 20000,
.tRST_max = 500000000,
.tWB_max = 100000,
.tWC_min = 20000,
.tWH_min = 7000,
.tWHR_min = 80000,
.tWP_min = 10000,
.tWW_min = 100000,
},
};
static FError FNandMemcpyToReg16(FNand *instance_p, u32 reg, u32 reg_step, const u16 *buf, u32 len)
{
u32 i;
u32 value = 0;
if (!instance_p || !buf)
{
FNAND_TIMING_DEBUG_E("instance_p is %p ,buf is %p", instance_p, buf);
return FNAND_ERR_INVAILD_PARAMETER;
}
for (i = 0; i < len; i++)
{
value = (value << 16) + buf[i];
if (i % 2)
{
FNAND_WRITEREG(instance_p->config.base_address, reg, value);
value = 0;
reg += reg_step;
}
}
return FT_SUCCESS;
}
/**
* @name:
* @msg: 根据inter_mode 与 timing_mode
* @note:
* @return {*}
* @param {FNand} *instance_p
*/
FError FNandTimingInterfaceUpdate(FNand *instance_p, u32 chip_addr)
{
FASSERT(instance_p != NULL);
FASSERT(instance_p->is_ready == FT_COMPONENT_IS_READY);
FASSERT(chip_addr < FNAND_CONNECT_MAX_NUM);
const u16 *target_timming_data = NULL;
FNandConfig *config_p = &instance_p->config ;
u32 value = 0 ;
FError ret;
FNandSetOption(instance_p, FNAND_OPS_INTER_MODE_SELECT, instance_p->inter_mode[chip_addr]);
FNAND_CLEARBIT(config_p->base_address, FNAND_CTRL1_OFFSET, FNAND_CTRL1_SAMPL_PHASE_MAKE(0xffffUL)); /* clear sampl_phase */
switch (instance_p->inter_mode[chip_addr])
{
case FNAND_ASYN_SDR:
if (FNAND_TIMING_MODE4 == (instance_p->timing_mode[chip_addr] & 0xf))
{
target_timming_data = fnand_timing_asy_mode4;
value = FNAND_CTRL1_SAMPL_PHASE_MAKE(4UL) ;
}
else if (FNAND_TIMING_MODE3 == (instance_p->timing_mode[chip_addr] & 0xf))
{
target_timming_data = fnand_timing_asy_mode3;
value = FNAND_CTRL1_SAMPL_PHASE_MAKE(5UL) ;
}
else if (FNAND_TIMING_MODE2 == (instance_p->timing_mode[chip_addr] & 0xf))
{
target_timming_data = fnand_timing_asy_mode2;
value = FNAND_CTRL1_SAMPL_PHASE_MAKE(6UL) ;
}
else if (FNAND_TIMING_MODE1 == (instance_p->timing_mode[chip_addr] & 0xf))
{
target_timming_data = fnand_timing_asy_mode1;
value = FNAND_CTRL1_SAMPL_PHASE_MAKE(5UL) ;
}
else
{
target_timming_data = fnand_timing_asy_mode0;
value = FNAND_CTRL1_SAMPL_PHASE_MAKE(1UL) ;
}
ret = FNandMemcpyToReg16(instance_p, FNAND_ASY_TIMING0_OFFSET, 4, target_timming_data, FNAND_TIMING_ASY_NUM);
if (ret != FT_SUCCESS)
{
return ret;
}
FNAND_SETBIT(config_p->base_address, FNAND_CTRL1_OFFSET, value);
FNAND_WRITEREG(config_p->base_address, FNAND_INTERVAL_OFFSET, 1);
break;
case FNAND_ONFI_DDR:
if (FNAND_TIMING_MODE4 == (instance_p->timing_mode[chip_addr] & 0xf))
{
FNAND_WRITEREG(config_p->base_address, FNAND_INTERVAL_OFFSET, 0x30);
target_timming_data = fnand_timing_syn_mode4;
value = FNAND_CTRL1_SAMPL_PHASE_MAKE(0xdUL) ;
}
else if (FNAND_TIMING_MODE3 == (instance_p->timing_mode[chip_addr] & 0xf))
{
FNAND_WRITEREG(config_p->base_address, FNAND_INTERVAL_OFFSET, 0x18);
target_timming_data = fnand_timing_syn_mode3;
value = FNAND_CTRL1_SAMPL_PHASE_MAKE(5UL) ;
}
else if (FNAND_TIMING_MODE2 == (instance_p->timing_mode[chip_addr] & 0xf))
{
FNAND_WRITEREG(config_p->base_address, FNAND_INTERVAL_OFFSET, 0x20);
target_timming_data = fnand_timing_syn_mode2;
value = FNAND_CTRL1_SAMPL_PHASE_MAKE(0x8UL) ;
}
else if (FNAND_TIMING_MODE1 == (instance_p->timing_mode[chip_addr] & 0xf))
{
FNAND_WRITEREG(config_p->base_address, FNAND_INTERVAL_OFFSET, 0x40);
target_timming_data = fnand_timing_syn_mode1;
value = FNAND_CTRL1_SAMPL_PHASE_MAKE(0x12UL) ;
}
else
{
FNAND_WRITEREG(config_p->base_address, FNAND_INTERVAL_OFFSET, 0x40);
target_timming_data = fnand_timing_syn_mode0;
value = FNAND_CTRL1_SAMPL_PHASE_MAKE(0x12UL) ;
}
ret = FNandMemcpyToReg16(instance_p, FNAND_SYN_TIMING6_OFFSET, 4, target_timming_data, FNAND_TIMING_SYN_NUM);
if (ret != FT_SUCCESS)
{
return ret;
}
FNAND_SETBIT(config_p->base_address, FNAND_CTRL1_OFFSET, value);
break;
case FNAND_TOG_ASYN_DDR:
value = FNAND_CTRL1_SAMPL_PHASE_MAKE(8UL);
target_timming_data = fnand_timing_tog_ddr_mode0;
ret = FNandMemcpyToReg16(instance_p, FNAND_TOG_TIMING13_OFFSET, 4, target_timming_data, FNAND_TIMING_SYN_NUM);
if (ret != FT_SUCCESS)
{
return ret;
}
FNAND_WRITEREG(config_p->base_address, FNAND_INTERVAL_OFFSET, 0xc8);
FNAND_SETBIT(config_p->base_address, FNAND_CTRL1_OFFSET, value);
break;
default:
FNAND_TIMING_DEBUG_E("Error inter_mode is %x", instance_p->inter_mode[chip_addr]);
return FNAND_ERR_INVAILD_PARAMETER;
}
return FT_SUCCESS;
}
const struct FNandSdrTimings *FNandAsyncTimingModeToSdrTimings(FNandAsyncTimint mode)
{
if (mode >= FNAND_ASYNC_TIM_INT_MODE4)
{
FNAND_TIMING_DEBUG_E("FNandAsyncTimingModeToSdrTimings set is over mode range");
return NULL;
}
return &onfi_sdr_timings[mode];
}
/**
* @name:
* @msg:
* @return {*}
* @param {FNand} *instance_p
* @param {FNandAsyncTimint} mode
* @Note 当前只支持onfi 模式
*/
FError FNandFillTimingModeTiming(FNand *instance_p, FNandAsyncTimint mode)
{
struct FNandSdrTimings *sdr_timing_p = NULL;
const struct FNandSdrTimings *source_timing_p = NULL;
FASSERT(instance_p != NULL);
sdr_timing_p = &instance_p->sdr_timing;
source_timing_p = FNandAsyncTimingModeToSdrTimings(mode);
FASSERT(source_timing_p != NULL);
*sdr_timing_p = *source_timing_p;
return FT_SUCCESS;
}