776 lines
23 KiB
C
776 lines
23 KiB
C
/* SPDX-License-Identifier: GPL-2.0 */
|
|
/**
|
|
* rawnand_chip.c
|
|
*
|
|
* Copyright (C) 2019 Allwinner.
|
|
*
|
|
* 2019.9.11 cuizhikui<cuizhikui@allwinnertech.com>
|
|
*/
|
|
|
|
|
|
#include "rawnand.h"
|
|
#include "rawnand_chip.h"
|
|
#include "rawnand_debug.h"
|
|
#include "rawnand_ids.h"
|
|
|
|
struct itf_ops_t rawnand_itf_ops;
|
|
|
|
int set_nand_onfi_ddr2_confiure_default(struct nand_chip_info *nci)
|
|
{
|
|
u8 addr;
|
|
u8 p[4];
|
|
u8 pr[4]; //read back value
|
|
|
|
addr = 0x02; //feature address 02h, NV-DDR2 Configuration
|
|
|
|
p[0] = 0x0;
|
|
p[0] |= (nci->nfc_init_ddr_info->en_ext_verf & 0x1);
|
|
p[0] |= ((nci->nfc_init_ddr_info->en_dqs_c & 0x1) << 1);
|
|
p[0] |= ((nci->nfc_init_ddr_info->en_re_c & 0x1) << 2);
|
|
p[0] |= ((nci->nfc_init_ddr_info->odt & 0x7) << 4);
|
|
p[1] = 0x0;
|
|
p[1] |= (nci->nfc_init_ddr_info->dout_re_warmup_cycle & 0x7);
|
|
p[1] |= ((nci->nfc_init_ddr_info->din_dqs_warmup_cycle & 0x7) << 4);
|
|
p[2] = 0x0;
|
|
p[3] = 0x0;
|
|
|
|
nand_set_feature(nci, &addr, p);
|
|
nand_get_feature(nci, &addr, pr);
|
|
if ((pr[0] != p[0]) || (pr[1] != p[1])) {
|
|
RAWNAND_ERR("set feature(addr 0x02) NV-DDR2 Configuration failed!\n");
|
|
return ERR_NO_113;
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
int set_nand_onfi_driver_strength_default(struct nand_chip_info *nci)
|
|
{
|
|
u8 addr;
|
|
u8 p[4];
|
|
u8 pr[4]; //read back value
|
|
u32 drive;
|
|
|
|
drive = nci->nfc_init_ddr_info->output_driver_strength;
|
|
if (drive > 3) {
|
|
RAWNAND_ERR("wrong onfi nand flash driver strength value: %d. keep default value\n", drive);
|
|
return 0;
|
|
}
|
|
|
|
addr = 0x10; //feature address 10h, Programmable output driver strength
|
|
p[0] = 0x0;
|
|
p[0] |= ((nci->nfc_init_ddr_info->output_driver_strength & 0x3) << 0);
|
|
p[1] = 0x0;
|
|
p[2] = 0x0;
|
|
p[3] = 0x0;
|
|
nand_set_feature(nci, &addr, p);
|
|
nand_get_feature(nci, &addr, pr);
|
|
if (pr[0] != p[0]) {
|
|
RAWNAND_ERR("set feature(addr 0x10) Programmable output driver strength failed!\n");
|
|
return ERR_NO_112;
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
int micron_onfi_rb_strength_setting(struct nand_chip_info *nci)
|
|
{
|
|
/*int ret = 0;*/
|
|
u8 addr;
|
|
u8 p[4];
|
|
u8 pr[4]; //read back value
|
|
/*micron nand flash*/
|
|
if (nci->nfc_init_ddr_info->output_driver_strength <= 3) {
|
|
addr = 0x80; //feature address 80h, Programmable output driver strength
|
|
p[0] = 0x0;
|
|
p[0] |= ((nci->nfc_init_ddr_info->output_driver_strength & 0x3) << 0);
|
|
p[1] = 0x0;
|
|
p[2] = 0x0;
|
|
p[3] = 0x0;
|
|
nand_set_feature(nci, &addr, p);
|
|
nand_get_feature(nci, &addr, pr);
|
|
if (pr[0] != p[0]) {
|
|
RAWNAND_ERR("set feature(addr 0x80) Programmable output driver strength failed!\n");
|
|
return ERR_NO_111;
|
|
}
|
|
}
|
|
|
|
if (nci->nfc_init_ddr_info->rb_pull_down_strength <= 3) {
|
|
addr = 0x81; //feature address 81h, Programmable R/B# Pull-Down strength
|
|
p[0] = 0x0;
|
|
p[0] |= ((nci->nfc_init_ddr_info->rb_pull_down_strength & 0x3) << 0);
|
|
p[1] = 0x0;
|
|
p[2] = 0x0;
|
|
p[3] = 0x0;
|
|
nand_set_feature(nci, &addr, p);
|
|
nand_get_feature(nci, &addr, pr);
|
|
if (pr[0] != p[0]) {
|
|
RAWNAND_ERR("set feature(addr 0x80) Programmable R/B# Pull-Down strength failed!\n");
|
|
return ERR_NO_110;
|
|
}
|
|
}
|
|
return NAND_OP_TRUE;
|
|
}
|
|
|
|
int set_nand_onfi_rb_strength_default(struct nand_chip_info *nci)
|
|
{
|
|
u8 addr;
|
|
u8 p[4];
|
|
u8 pr[4]; //read back value
|
|
|
|
if (nci->id[0] == 0x2c) {
|
|
/*micron nand flash*/
|
|
if (nci->nfc_init_ddr_info->output_driver_strength <= 3) {
|
|
addr = 0x80; //feature address 80h, Programmable output driver strength
|
|
p[0] = 0x0;
|
|
p[0] |= ((nci->nfc_init_ddr_info->output_driver_strength & 0x3) << 0);
|
|
p[1] = 0x0;
|
|
p[2] = 0x0;
|
|
p[3] = 0x0;
|
|
nand_set_feature(nci, &addr, p);
|
|
nand_get_feature(nci, &addr, pr);
|
|
if (pr[0] != p[0]) {
|
|
RAWNAND_ERR("set feature(addr 0x80) Programmable output driver strength failed!\n");
|
|
return ERR_NO_111;
|
|
}
|
|
}
|
|
|
|
if (nci->nfc_init_ddr_info->rb_pull_down_strength <= 3) {
|
|
addr = 0x81; //feature address 81h, Programmable R/B# Pull-Down strength
|
|
p[0] = 0x0;
|
|
p[0] |= ((nci->nfc_init_ddr_info->rb_pull_down_strength & 0x3) << 0);
|
|
p[1] = 0x0;
|
|
p[2] = 0x0;
|
|
p[3] = 0x0;
|
|
nand_set_feature(nci, &addr, p);
|
|
nand_get_feature(nci, &addr, pr);
|
|
if (pr[0] != p[0]) {
|
|
RAWNAND_ERR("set feature(addr 0x80) Programmable R/B# Pull-Down strength failed!\n");
|
|
return ERR_NO_110;
|
|
}
|
|
}
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
int set_nand_onfi_timing_mode_default(struct nand_chip_info *nci, nand_if_type if_type, u32 timing_mode)
|
|
{
|
|
u8 addr;
|
|
u8 p[4];
|
|
|
|
if (!SUPPORT_CHANGE_ONFI_TIMING_MODE) {
|
|
RAWNAND_ERR("don't support change onfi timing mode. if_type: %d\n", if_type);
|
|
return ERR_NO_71;
|
|
}
|
|
|
|
if ((if_type != SDR) && (if_type != ONFI_DDR) && (if_type != ONFI_DDR2)) {
|
|
RAWNAND_ERR("wrong onfi interface type: %d\n", if_type);
|
|
return ERR_NO_70;
|
|
}
|
|
|
|
if ((if_type == SDR) && (timing_mode > 5)) {
|
|
RAWNAND_ERR("wrong onfi timing mode(%d) in interface type(%d)\n", if_type, timing_mode);
|
|
return ERR_NO_69;
|
|
}
|
|
if ((if_type == ONFI_DDR) && (timing_mode > 5)) {
|
|
RAWNAND_ERR("wrong onfi timing mode(%d) in interface type(%d)\n", if_type, timing_mode);
|
|
return ERR_NO_68;
|
|
}
|
|
if ((if_type == ONFI_DDR2) && (timing_mode > 7)) {
|
|
RAWNAND_ERR("wrong onfi timing mode(%d) in interface type(%d)\n", if_type, timing_mode);
|
|
return ERR_NO_67;
|
|
}
|
|
|
|
addr = 0x01; //feature address 01h, Timing Mode
|
|
p[0] = 0;
|
|
if (if_type == ONFI_DDR)
|
|
p[0] = (0x1U << 4) | (timing_mode & 0xf);
|
|
else if (if_type == ONFI_DDR2)
|
|
p[0] = (0x2U << 4) | (timing_mode & 0xf);
|
|
else
|
|
p[0] = (timing_mode & 0xf);
|
|
|
|
p[1] = 0x0;
|
|
p[2] = 0x0;
|
|
p[3] = 0x0;
|
|
nand_set_feature(nci, &addr, p);
|
|
//aw_delay(0x100); //max tITC is 1us
|
|
|
|
return 0;
|
|
}
|
|
|
|
s32 set_nand_toggle_specific_setting_default(struct nand_chip_info *nci)
|
|
{
|
|
u8 addr;
|
|
u8 p[4];
|
|
u8 pr[4]; //read back value
|
|
|
|
addr = 0x02; //feature address 02h, Toggle 2.0-specific Configuration
|
|
p[0] = 0x0;
|
|
p[0] |= (nci->nfc_init_ddr_info->en_ext_verf & 0x1);
|
|
p[0] |= ((nci->nfc_init_ddr_info->en_dqs_c & 0x1) << 1);
|
|
p[0] |= ((nci->nfc_init_ddr_info->en_re_c & 0x1) << 2);
|
|
p[0] |= ((nci->nfc_init_ddr_info->odt & 0x7) << 4);
|
|
p[1] = 0x0;
|
|
p[1] |= ((nci->nfc_init_ddr_info->dout_re_warmup_cycle & 0x7) << 0);
|
|
p[1] |= ((nci->nfc_init_ddr_info->din_dqs_warmup_cycle & 0x7) << 4);
|
|
p[2] = 0x0;
|
|
p[3] = 0x0;
|
|
nand_set_feature(nci, &addr, p);
|
|
nand_get_feature(nci, &addr, pr);
|
|
if ((pr[0] != p[0]) || (pr[1] != p[1])) {
|
|
RAWNAND_ERR("set feature(addr 0x02) Toggle 2.0-specific Configuration failed!\n");
|
|
return ERR_NO_66;
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
int set_nand_toggle_driver_strength_default(struct nand_chip_info *nci)
|
|
{
|
|
u8 addr;
|
|
u8 p[4];
|
|
u8 pr[4]; //read back value
|
|
u32 drive;
|
|
|
|
drive = nci->nfc_init_ddr_info->output_driver_strength;
|
|
if ((drive != 2) && (drive != 4) && (drive != 6)) {
|
|
RAWNAND_INFO("reserved toggle nand flash driver strength value: %d. keep default value.\n", drive);
|
|
return 0;
|
|
}
|
|
|
|
addr = 0x10; //feature address 10h, Programmable output driver strength
|
|
p[0] = 0x0;
|
|
p[0] |= ((nci->nfc_init_ddr_info->output_driver_strength & 0x7) << 0); //2, 4, 6
|
|
p[1] = 0x0;
|
|
p[2] = 0x0;
|
|
p[3] = 0x0;
|
|
nand_set_feature(nci, &addr, p);
|
|
nand_get_feature(nci, &addr, pr);
|
|
if (pr[0] != p[0]) {
|
|
RAWNAND_ERR("set feature(addr 0x10) Programmable output driver strength failed!\n");
|
|
return ERR_NO_65;
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
int set_nand_toggle_vendor_specific_setting_default(struct nand_chip_info *nci)
|
|
{
|
|
u8 addr;
|
|
u8 p[4];
|
|
//u8 pr[4]; //read back value
|
|
|
|
if ((nci->id[0] == 0x45) || (nci->id[0] == 0x98)) {
|
|
/*sandisk/toshiba nand flash*/
|
|
addr = 0x80; //Sandisk: This address (80h) is a vendor-specific setting used to turn on or turn off Toggle Mode
|
|
p[0] = 0x0;
|
|
if ((nci->interface_type == TOG_DDR) || (nci->interface_type == TOG_DDR2))
|
|
p[0] = 0x0; //enable toggle mode
|
|
else
|
|
p[0] = 0x1; //disable toggle mode
|
|
p[1] = 0x0;
|
|
p[2] = 0x0;
|
|
p[3] = 0x0;
|
|
nand_set_feature(nci, &addr, p);
|
|
#if 0
|
|
nfc_get_feature(addr, pr);
|
|
if (pr[0] != p[0]) {
|
|
RAWNAND_ERR("set feature(addr 0x80) Programmable output driver strength failed!\n");
|
|
return ERR_NO_64;
|
|
}
|
|
#endif
|
|
} else if (nci->id[0] == NAND_MFR_HYNIX) {
|
|
u8 pr[1] = {0};
|
|
addr = 0x01;
|
|
p[0] = 0x0;
|
|
if ((nci->interface_type == TOG_DDR) || (nci->interface_type == TOG_DDR2))
|
|
p[0] = (0x2 & 0x3)<<4; //enable toggle mode
|
|
else
|
|
p[0] = (0x0 & 0x3)<<4; //disable toggle mode
|
|
p[1] = 0x0;
|
|
p[2] = 0x0;
|
|
p[3] = 0x0;
|
|
nand_set_feature(nci, &addr, p);
|
|
nand_get_feature(nci, &addr, pr);
|
|
if (pr[0] != p[0]) {
|
|
RAWNAND_ERR("set feature(addr 0x01) %x,%x!\n", p[0], pr[0]);
|
|
return ERR_NO_64;
|
|
}
|
|
RAWNAND_DBG("set feature(addr 0x01) %x,%x!\n", p[0], pr[0]);
|
|
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
int sandisk_toggle_vendor_specific_setting(struct nand_chip_info *nci)
|
|
{
|
|
u8 addr;
|
|
u8 p[4];
|
|
addr = 0x80; //Sandisk: This address (80h) is a vendor-specific setting used to turn on or turn off Toggle Mode
|
|
p[0] = 0x0;
|
|
if ((nci->interface_type == TOG_DDR) || (nci->interface_type == TOG_DDR2))
|
|
p[0] = 0x0; //enable toggle mode
|
|
else
|
|
p[0] = 0x1; //disable toggle mode
|
|
p[1] = 0x0;
|
|
p[2] = 0x0;
|
|
p[3] = 0x0;
|
|
nand_set_feature(nci, &addr, p);
|
|
|
|
return NAND_OP_TRUE;
|
|
}
|
|
|
|
int toshiba_toggle_vendor_specific_setting(struct nand_chip_info *nci)
|
|
{
|
|
u8 addr;
|
|
u8 p[4];
|
|
addr = 0x80; //toshiba: This address (80h) is a vendor-specific setting used to turn on or turn off Toggle Mode
|
|
p[0] = 0x0;
|
|
if ((nci->interface_type == TOG_DDR) || (nci->interface_type == TOG_DDR2))
|
|
p[0] = 0x0; //to toggle ddr1.0
|
|
else
|
|
p[0] = 0x1; //to sdr
|
|
p[1] = 0x0;
|
|
p[2] = 0x0;
|
|
p[3] = 0x0;
|
|
nand_set_feature(nci, &addr, p);
|
|
|
|
return NAND_OP_TRUE;
|
|
}
|
|
|
|
int rawnand_async_to_onfi_ddr_or_ddr2_set(struct nand_chip_info *nci, nand_if_type ddr_type)
|
|
{
|
|
int ret = 0;
|
|
/* Async => ONFI DDR/DDR2 */
|
|
RAWNAND_DBG("mode 1 : Async => ONFI DDR/DDR2\n");
|
|
if ((nci->itf_cfg.onfi_cfg.support_ddr2_specific_cfg) && (ddr_type == ONFI_DDR2)) {
|
|
if (rawnand_itf_ops.onfi.ddr2_cfg) {
|
|
ret = rawnand_itf_ops.onfi.ddr2_cfg(nci);
|
|
if (ret) {
|
|
RAWNAND_ERR("%s rawnand onfi async set to ddr2 failed,while setup nand onfi ddr2 para!\n", __func__);
|
|
return ret;
|
|
}
|
|
}
|
|
}
|
|
|
|
if (nci->itf_cfg.onfi_cfg.support_io_driver_strength) {
|
|
if (rawnand_itf_ops.onfi.driver_strength) {
|
|
ret = rawnand_itf_ops.onfi.driver_strength(nci);
|
|
/*ret = _setup_nand_onfi_driver_strength(nci);*/
|
|
if (ret) {
|
|
RAWNAND_ERR("rawnand onfi async set to %s failed,while setup io driver strength!\n",
|
|
(ddr_type == ONFI_DDR2) ? "ddr2" : "ddr");
|
|
return ret;
|
|
}
|
|
}
|
|
}
|
|
|
|
if (nci->itf_cfg.onfi_cfg.support_rb_pull_down_strength) {
|
|
if (rawnand_itf_ops.onfi.rb_strength) {
|
|
/*ret = _setup_nand_onfi_vendor_specific_feature(nci);*/
|
|
ret = rawnand_itf_ops.onfi.rb_strength(nci);
|
|
if (ret) {
|
|
RAWNAND_ERR("%s rawnand onfi async set to %s failed,while setup nand vendor_specific feature!\n", __func__,
|
|
(ddr_type == ONFI_DDR2) ? "ddr2" : "ddr");
|
|
return ret;
|
|
}
|
|
}
|
|
}
|
|
|
|
if (nci->itf_cfg.onfi_cfg.support_change_onfi_timing_mode) {
|
|
if (rawnand_itf_ops.onfi.timing_mode) {
|
|
/*ret = _change_nand_onfi_timing_mode(nci, ddr_type, nci->timing_mode);*/
|
|
ret = rawnand_itf_ops.onfi.timing_mode(nci, ddr_type, nci->timing_mode);
|
|
if (ret) {
|
|
RAWNAND_ERR("%s rawnand onfi async set to %s failed,while setup onfi timing mode!\n", __func__,
|
|
(ddr_type == ONFI_DDR2) ? "ddr2" : "ddr");
|
|
RAWNAND_ERR("nand flash switch to nv-ddr or nv-ddr2 failed!\n");
|
|
return ret;
|
|
}
|
|
}
|
|
}
|
|
|
|
return NAND_OP_TRUE;
|
|
}
|
|
|
|
int rawnand_onfi_ddr_or_ddr2_to_async_set(struct nand_chip_info *nci, nand_if_type ddr_type,
|
|
nand_if_type pre_ddr_type)
|
|
{
|
|
int ret = 0;
|
|
|
|
/* ONFI DDR/DDR2 => Async */
|
|
RAWNAND_DBG("mode 2 : ONFI DDR/DDR2 => Async\n");
|
|
if ((nci->itf_cfg.onfi_cfg.support_ddr2_specific_cfg) && (pre_ddr_type == ONFI_DDR2)) {
|
|
if (rawnand_itf_ops.onfi.ddr2_cfg) {
|
|
/*ret = _setup_nand_onfi_ddr2_para(nci);*/
|
|
ret = rawnand_itf_ops.onfi.ddr2_cfg(nci);
|
|
if (ret != 0) {
|
|
RAWNAND_ERR("%s rawnand onfi ddr2 set to async failed,while setup nand onfi ddr2 para!\n", __func__);
|
|
return ret;
|
|
}
|
|
}
|
|
}
|
|
|
|
if (nci->itf_cfg.onfi_cfg.support_io_driver_strength) {
|
|
if (rawnand_itf_ops.onfi.driver_strength) {
|
|
/*ret = _setup_nand_onfi_driver_strength(nci);*/
|
|
ret = rawnand_itf_ops.onfi.driver_strength(nci);
|
|
if (ret != 0) {
|
|
RAWNAND_ERR("%s rawnand onfi async set to %s failed,while setup io driver strength!\n", __func__, (ddr_type == ONFI_DDR2) ? "ddr2" : "ddr");
|
|
return ret;
|
|
}
|
|
}
|
|
}
|
|
|
|
if (nci->itf_cfg.onfi_cfg.support_rb_pull_down_strength) {
|
|
if (rawnand_itf_ops.onfi.rb_strength) {
|
|
/*ret = _setup_nand_onfi_vendor_specific_feature(nci);*/
|
|
ret = rawnand_itf_ops.onfi.rb_strength(nci);
|
|
if (ret) {
|
|
RAWNAND_ERR("%s rawnand onfi async set to %s failed,while setup vendor specific cfg!\n", __func__, (ddr_type == ONFI_DDR2) ? "ddr2" : "ddr");
|
|
return ret;
|
|
}
|
|
}
|
|
}
|
|
|
|
/* use async reset to aysnc interface */
|
|
nand_reset_chip(nci);
|
|
|
|
/* change to proper timing mode in async interface */
|
|
if (nci->itf_cfg.onfi_cfg.support_change_onfi_timing_mode) {
|
|
if (rawnand_itf_ops.onfi.timing_mode) {
|
|
/*ret = _change_nand_onfi_timing_mode(nci, ddr_type, nci->timing_mode);*/
|
|
ret = rawnand_itf_ops.onfi.timing_mode(nci, ddr_type, nci->timing_mode);
|
|
if (ret) {
|
|
RAWNAND_ERR("%s rawnand onfi async set to %s failed,while set onfi timing mode!\n", __func__, (ddr_type == ONFI_DDR2) ? "ddr2" : "ddr");
|
|
RAWNAND_ERR("nand flash change timing mode at async interface failed!\n");
|
|
return ret;
|
|
}
|
|
}
|
|
}
|
|
|
|
return NAND_OP_TRUE;
|
|
}
|
|
|
|
int rawnand_async_to_toggle_ddr_or_ddr2_set(struct nand_chip_info *nci, nand_if_type ddr_type)
|
|
{
|
|
int ret = 0;
|
|
/* Async => Toggle DDR/DDR2 */
|
|
RAWNAND_DBG("mode 3 : Async => Toggle %s\n", (ddr_type == TOG_DDR2) ? "DDR2" : "DDR");
|
|
nand_reset_chip(nci);
|
|
if (nci->itf_cfg.toggle_cfg.support_specific_setting) {
|
|
if (ddr_type == TOG_DDR2) {
|
|
if (rawnand_itf_ops.toggle.specific_setting) {
|
|
/*ret = _setup_nand_toggle_ddr2_para(nci);*/
|
|
ret = rawnand_itf_ops.toggle.specific_setting(nci);
|
|
if (ret) {
|
|
RAWNAND_ERR("%s rawnand async set to toggle ddr2 failed,while specific setting!\n", __func__);
|
|
return ret;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
if (nci->itf_cfg.toggle_cfg.support_io_driver_strength_setting) {
|
|
if (rawnand_itf_ops.toggle.driver_strength) {
|
|
/*ret = _setup_nand_toggle_driver_strength(nci);*/
|
|
ret = rawnand_itf_ops.toggle.driver_strength(nci);
|
|
if (ret) {
|
|
RAWNAND_ERR("%s rawnand async set to toggle %s failed,while toggle driver strength!\n", __func__,
|
|
(ddr_type == TOG_DDR2) ? "ddr2" : "ddr");
|
|
return ret;
|
|
}
|
|
}
|
|
}
|
|
|
|
if (nci->itf_cfg.toggle_cfg.support_vendor_specific_setting) {
|
|
if (rawnand_itf_ops.toggle.vendor_specific_setting) {
|
|
/*ret = _setup_nand_toggle_vendor_specific_feature(nci);*/
|
|
ret = rawnand_itf_ops.toggle.vendor_specific_setting(nci);
|
|
if (ret) {
|
|
RAWNAND_ERR("%s rawnand async set to toggle %s failed,while toggle vendor specific setting!\n", __func__,
|
|
(ddr_type == TOG_DDR2) ? "ddr2" : "ddr");
|
|
return ret;
|
|
}
|
|
}
|
|
}
|
|
|
|
return NAND_OP_TRUE;
|
|
}
|
|
int rawnand_toggle_ddr_or_ddr2_to_async_set(struct nand_chip_info *nci, nand_if_type ddr_type,
|
|
nand_if_type pre_ddr_type)
|
|
{
|
|
int ret = 0;
|
|
|
|
/* Toggle DDR/DDR2 => Async */
|
|
RAWNAND_DBG("mode 4 : Toggle DDR/DDR2 => Async\n");
|
|
if ((nci->itf_cfg.toggle_cfg.support_specific_setting) && (pre_ddr_type == TOG_DDR2)) {
|
|
// clear ddr2 parameter
|
|
if (rawnand_itf_ops.toggle.specific_setting) {
|
|
/*ret = _setup_nand_toggle_ddr2_para(nci);*/
|
|
ret = rawnand_itf_ops.toggle.specific_setting(nci);
|
|
if (ret != 0) {
|
|
RAWNAND_ERR("%s rawnand async set to toggle ddr2 failed,while specific setting!\n", __func__);
|
|
return ret;
|
|
}
|
|
}
|
|
}
|
|
|
|
if (nci->itf_cfg.toggle_cfg.support_io_driver_strength_setting) {
|
|
if (rawnand_itf_ops.toggle.driver_strength) {
|
|
/*ret = _setup_nand_toggle_driver_strength(nci);*/
|
|
ret = rawnand_itf_ops.toggle.driver_strength(nci);
|
|
if (ret) {
|
|
RAWNAND_ERR("%s rawnand async set to toggle %s failed,while toggle driver strength!\n", __func__,
|
|
(ddr_type == TOG_DDR2) ? "ddr2" : "ddr");
|
|
return ret;
|
|
}
|
|
}
|
|
}
|
|
|
|
if (nci->itf_cfg.toggle_cfg.support_vendor_specific_setting) {
|
|
if (rawnand_itf_ops.toggle.vendor_specific_setting) {
|
|
/*ret = _setup_nand_toggle_vendor_specific_feature(nci);*/
|
|
ret = rawnand_itf_ops.toggle.vendor_specific_setting(nci);
|
|
if (ret) {
|
|
RAWNAND_ERR("%s rawnand async set to toggle %s failed,while toggle vendor specific setting!\n",
|
|
__func__, (ddr_type == TOG_DDR2) ? "ddr2" : "ddr");
|
|
return ret;
|
|
}
|
|
}
|
|
}
|
|
|
|
return NAND_OP_TRUE;
|
|
}
|
|
|
|
int rawnand_toggle_ddr2_to_toggle_ddr_set(struct nand_chip_info *nci)
|
|
{
|
|
int ret = 0;
|
|
/* Toggle DDR2 <=> Toggle DDR */
|
|
RAWNAND_DBG("mode 5 : Toggle DDR2 <=> Toggle DDR\n");
|
|
if (nci->itf_cfg.toggle_cfg.support_specific_setting) {
|
|
if (rawnand_itf_ops.toggle.specific_setting) {
|
|
/*ret = _setup_nand_toggle_ddr2_para(nci);*/
|
|
ret = rawnand_itf_ops.toggle.specific_setting(nci);
|
|
if (ret) {
|
|
RAWNAND_ERR("%s rawnand toggle ddr2 to toggle ddr failed,while specific setting!\n", __func__);
|
|
return ret;
|
|
}
|
|
}
|
|
}
|
|
|
|
if (nci->itf_cfg.toggle_cfg.support_io_driver_strength_setting) {
|
|
if (rawnand_itf_ops.toggle.driver_strength) {
|
|
/*ret = _setup_nand_toggle_driver_strength(nci);*/
|
|
ret = rawnand_itf_ops.toggle.driver_strength(nci);
|
|
if (ret) {
|
|
RAWNAND_ERR("%s rawnand toggle ddr to toggle ddr failed,while set io driver strenth!\n", __func__);
|
|
return ret;
|
|
}
|
|
}
|
|
}
|
|
|
|
if (nci->itf_cfg.toggle_cfg.support_vendor_specific_setting) {
|
|
if (rawnand_itf_ops.toggle.vendor_specific_setting) {
|
|
/*ret = _setup_nand_toggle_vendor_specific_feature(nci);*/
|
|
ret = rawnand_itf_ops.toggle.vendor_specific_setting(nci);
|
|
if (ret) {
|
|
RAWNAND_ERR("%s rawnand toggle ddr2 to toggle ddr failed,while set vendor specific feature!\n", __func__);
|
|
return ret;
|
|
}
|
|
}
|
|
}
|
|
|
|
return NAND_OP_TRUE;
|
|
}
|
|
int rawnand_itf_unchanged_set(struct nand_chip_info *nci, nand_if_type ddr_type,
|
|
nand_if_type pre_ddr_type)
|
|
{
|
|
int ret = 0;
|
|
RAWNAND_DBG("mode 6\n");
|
|
if (ddr_type == SDR) {
|
|
if (nci->itf_cfg.onfi_cfg.support_change_onfi_timing_mode) {
|
|
if (rawnand_itf_ops.onfi.timing_mode) {
|
|
/*ret = _change_nand_onfi_timing_mode(nci, ddr_type, nci->timing_mode);*/
|
|
ret = rawnand_itf_ops.onfi.timing_mode(nci, ddr_type, nci->timing_mode);
|
|
if (ret) {
|
|
RAWNAND_ERR("%s nand flash change timing mode at async interface failed!continue...\n", __func__);
|
|
return ret;
|
|
}
|
|
}
|
|
}
|
|
} else if ((ddr_type == ONFI_DDR) || (ddr_type == ONFI_DDR2)) {
|
|
if ((nci->itf_cfg.onfi_cfg.support_ddr2_specific_cfg) && (ddr_type == ONFI_DDR2)) {
|
|
if (rawnand_itf_ops.onfi.ddr2_cfg) {
|
|
/*ret = _setup_nand_onfi_ddr2_para(nci);*/
|
|
ret = rawnand_itf_ops.onfi.ddr2_cfg(nci);
|
|
if (ret) {
|
|
RAWNAND_ERR("%s rawnand set onfi ddr2 fail,while onfi ddr2 para!\n", __func__);
|
|
return ret;
|
|
}
|
|
}
|
|
}
|
|
|
|
if (nci->itf_cfg.onfi_cfg.support_io_driver_strength) {
|
|
if (rawnand_itf_ops.onfi.driver_strength) {
|
|
/*ret = _setup_nand_onfi_driver_strength(nci);*/
|
|
ret = rawnand_itf_ops.onfi.driver_strength(nci);
|
|
if (ret) {
|
|
RAWNAND_ERR("%s rawnand set onfi %s failed,while onfi driver strength!\n", __func__,
|
|
(ddr_type == ONFI_DDR2) ? "ddr2" : "ddr");
|
|
return ret;
|
|
}
|
|
}
|
|
}
|
|
|
|
if (nci->itf_cfg.onfi_cfg.support_rb_pull_down_strength) {
|
|
if (rawnand_itf_ops.onfi.rb_strength) {
|
|
/*ret = _setup_nand_onfi_vendor_specific_feature(nci);*/
|
|
ret = rawnand_itf_ops.onfi.rb_strength(nci);
|
|
if (ret) {
|
|
RAWNAND_ERR("%s rawnand set onfi %s failed,while onfi vendor specific feature!\n", __func__,
|
|
(ddr_type == ONFI_DDR2) ? "ddr2" : "ddr");
|
|
return ret;
|
|
}
|
|
}
|
|
}
|
|
|
|
if (nci->itf_cfg.onfi_cfg.support_change_onfi_timing_mode) {
|
|
if (rawnand_itf_ops.onfi.timing_mode) {
|
|
/*ret = _change_nand_onfi_timing_mode(nci, ddr_type, nci->timing_mode);*/
|
|
ret = rawnand_itf_ops.onfi.timing_mode(nci, ddr_type, nci->timing_mode);
|
|
if (ret) {
|
|
RAWNAND_ERR("%s rawnand set onfi %s failed,while onfi timing mode!\n", __func__,
|
|
(ddr_type == ONFI_DDR2) ? "ddr2" : "ddr");
|
|
return ret;
|
|
}
|
|
}
|
|
}
|
|
} else if ((ddr_type == TOG_DDR) || (ddr_type == TOG_DDR2)) {
|
|
if ((nci->itf_cfg.toggle_cfg.support_specific_setting) && (ddr_type == TOG_DDR2)) {
|
|
if (rawnand_itf_ops.toggle.specific_setting) {
|
|
/*ret = _setup_nand_toggle_ddr2_para(nci);*/
|
|
ret = rawnand_itf_ops.toggle.specific_setting(nci);
|
|
if (ret) {
|
|
RAWNAND_ERR("%s rawnand toggle ddr2 to toggle ddr failed,while specific setting!\n", __func__);
|
|
return ret;
|
|
}
|
|
}
|
|
}
|
|
|
|
if (nci->itf_cfg.toggle_cfg.support_io_driver_strength_setting) {
|
|
if (rawnand_itf_ops.toggle.driver_strength) {
|
|
/*ret = _setup_nand_toggle_driver_strength(nci);*/
|
|
ret = rawnand_itf_ops.toggle.driver_strength(nci);
|
|
if (ret) {
|
|
RAWNAND_ERR("%s rawnand set to toggle %s failed,while toggle driver strength!\n", __func__,
|
|
(ddr_type == TOG_DDR2) ? "ddr2" : "ddr");
|
|
return ret;
|
|
}
|
|
}
|
|
}
|
|
|
|
if (nci->itf_cfg.toggle_cfg.support_vendor_specific_setting) {
|
|
if (rawnand_itf_ops.toggle.vendor_specific_setting) {
|
|
/*ret = _setup_nand_toggle_vendor_specific_feature(nci);*/
|
|
ret = rawnand_itf_ops.toggle.vendor_specific_setting(nci);
|
|
if (ret) {
|
|
RAWNAND_ERR("%s rawnand set to toggle %s failed,while toggle vendor specific setting!\n", __func__,
|
|
(ddr_type == TOG_DDR2) ? "ddr2" : "ddr");
|
|
return ret;
|
|
}
|
|
}
|
|
}
|
|
} else {
|
|
RAWNAND_ERR("wrong nand interface type!\n");
|
|
return -1;
|
|
}
|
|
return NAND_OP_TRUE;
|
|
}
|
|
|
|
void rawnand_update_timings_ift_ops(int mfr_type)
|
|
{
|
|
switch (mfr_type) {
|
|
case NAND_MFR_MICRON:
|
|
rawnand_itf_ops = micron_itf_ops;
|
|
break;
|
|
case NAND_MFR_HYNIX:
|
|
rawnand_itf_ops = hynix_itf_ops;
|
|
break;
|
|
case NAND_MFR_INTEL:
|
|
rawnand_itf_ops = intel_itf_ops;
|
|
break;
|
|
case NAND_MFR_SANDISK:
|
|
rawnand_itf_ops = sandisk_itf_ops;
|
|
break;
|
|
case NAND_MFR_TOSHIBA:
|
|
rawnand_itf_ops = toshiba_itf_ops;
|
|
break;
|
|
case NAND_MFR_SAMSUNG:
|
|
rawnand_itf_ops = sansumg_itf_ops;
|
|
break;
|
|
default:
|
|
break;
|
|
}
|
|
}
|
|
|
|
struct itf_ops_t sansumg_itf_ops = {
|
|
.toggle = {
|
|
.specific_setting = set_nand_toggle_specific_setting_default,
|
|
.driver_strength = set_nand_toggle_driver_strength_default,
|
|
.vendor_specific_setting = set_nand_toggle_vendor_specific_setting_default,
|
|
}
|
|
};
|
|
|
|
struct itf_ops_t sandisk_itf_ops = {
|
|
.toggle = {
|
|
.specific_setting = set_nand_toggle_specific_setting_default,
|
|
.driver_strength = set_nand_toggle_driver_strength_default,
|
|
.vendor_specific_setting = sandisk_toggle_vendor_specific_setting,
|
|
}
|
|
};
|
|
|
|
struct itf_ops_t toshiba_itf_ops = {
|
|
.toggle = {
|
|
.specific_setting = set_nand_toggle_specific_setting_default,
|
|
.driver_strength = set_nand_toggle_driver_strength_default,
|
|
.vendor_specific_setting = toshiba_toggle_vendor_specific_setting,
|
|
}
|
|
};
|
|
|
|
struct itf_ops_t hynix_itf_ops = {
|
|
.onfi = {
|
|
.ddr2_cfg = set_nand_onfi_ddr2_confiure_default,
|
|
.driver_strength = set_nand_onfi_driver_strength_default,
|
|
.rb_strength = set_nand_onfi_rb_strength_default,
|
|
.timing_mode = set_nand_onfi_timing_mode_default,
|
|
},
|
|
|
|
.toggle = {
|
|
.specific_setting = set_nand_toggle_specific_setting_default,
|
|
.driver_strength = set_nand_toggle_driver_strength_default,
|
|
.vendor_specific_setting = set_nand_toggle_vendor_specific_setting_default,
|
|
}
|
|
};
|
|
|
|
struct itf_ops_t micron_itf_ops = {
|
|
.onfi = {
|
|
.ddr2_cfg = set_nand_onfi_ddr2_confiure_default,
|
|
.driver_strength = set_nand_onfi_driver_strength_default,
|
|
.rb_strength = micron_onfi_rb_strength_setting,
|
|
.timing_mode = set_nand_onfi_timing_mode_default,
|
|
}
|
|
};
|
|
|
|
struct itf_ops_t intel_itf_ops = {
|
|
.onfi = {
|
|
.ddr2_cfg = set_nand_onfi_ddr2_confiure_default,
|
|
.driver_strength = set_nand_onfi_driver_strength_default,
|
|
.rb_strength = set_nand_onfi_rb_strength_default,
|
|
.timing_mode = set_nand_onfi_timing_mode_default,
|
|
}
|
|
};
|