/* SPDX-License-Identifier: GPL-2.0 */ /** * rawnand_chip.c * * Copyright (C) 2019 Allwinner. * * 2019.9.11 cuizhikui */ #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, } };