468 lines
15 KiB
C
468 lines
15 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_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;
|
||
}
|