18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-or-later 28c2ecf20Sopenharmony_ci/* 38c2ecf20Sopenharmony_ci * Copyright (C) 2017 Free Electrons 48c2ecf20Sopenharmony_ci * Copyright (C) 2017 NextThing Co 58c2ecf20Sopenharmony_ci * 68c2ecf20Sopenharmony_ci * Author: Boris Brezillon <boris.brezillon@free-electrons.com> 78c2ecf20Sopenharmony_ci */ 88c2ecf20Sopenharmony_ci 98c2ecf20Sopenharmony_ci#include "linux/delay.h" 108c2ecf20Sopenharmony_ci#include "internals.h" 118c2ecf20Sopenharmony_ci 128c2ecf20Sopenharmony_ci#define MACRONIX_READ_RETRY_BIT BIT(0) 138c2ecf20Sopenharmony_ci#define MACRONIX_NUM_READ_RETRY_MODES 6 148c2ecf20Sopenharmony_ci 158c2ecf20Sopenharmony_ci#define ONFI_FEATURE_ADDR_MXIC_PROTECTION 0xA0 168c2ecf20Sopenharmony_ci#define MXIC_BLOCK_PROTECTION_ALL_LOCK 0x38 178c2ecf20Sopenharmony_ci#define MXIC_BLOCK_PROTECTION_ALL_UNLOCK 0x0 188c2ecf20Sopenharmony_ci 198c2ecf20Sopenharmony_ci#define ONFI_FEATURE_ADDR_MXIC_RANDOMIZER 0xB0 208c2ecf20Sopenharmony_ci#define MACRONIX_RANDOMIZER_BIT BIT(1) 218c2ecf20Sopenharmony_ci#define MACRONIX_RANDOMIZER_ENPGM BIT(0) 228c2ecf20Sopenharmony_ci#define MACRONIX_RANDOMIZER_RANDEN BIT(1) 238c2ecf20Sopenharmony_ci#define MACRONIX_RANDOMIZER_RANDOPT BIT(2) 248c2ecf20Sopenharmony_ci#define MACRONIX_RANDOMIZER_MODE_ENTER \ 258c2ecf20Sopenharmony_ci (MACRONIX_RANDOMIZER_ENPGM | \ 268c2ecf20Sopenharmony_ci MACRONIX_RANDOMIZER_RANDEN | \ 278c2ecf20Sopenharmony_ci MACRONIX_RANDOMIZER_RANDOPT) 288c2ecf20Sopenharmony_ci#define MACRONIX_RANDOMIZER_MODE_EXIT \ 298c2ecf20Sopenharmony_ci (MACRONIX_RANDOMIZER_RANDEN | \ 308c2ecf20Sopenharmony_ci MACRONIX_RANDOMIZER_RANDOPT) 318c2ecf20Sopenharmony_ci 328c2ecf20Sopenharmony_ci#define MXIC_CMD_POWER_DOWN 0xB9 338c2ecf20Sopenharmony_ci 348c2ecf20Sopenharmony_cistruct nand_onfi_vendor_macronix { 358c2ecf20Sopenharmony_ci u8 reserved; 368c2ecf20Sopenharmony_ci u8 reliability_func; 378c2ecf20Sopenharmony_ci} __packed; 388c2ecf20Sopenharmony_ci 398c2ecf20Sopenharmony_cistatic int macronix_nand_setup_read_retry(struct nand_chip *chip, int mode) 408c2ecf20Sopenharmony_ci{ 418c2ecf20Sopenharmony_ci u8 feature[ONFI_SUBFEATURE_PARAM_LEN]; 428c2ecf20Sopenharmony_ci 438c2ecf20Sopenharmony_ci if (!chip->parameters.supports_set_get_features || 448c2ecf20Sopenharmony_ci !test_bit(ONFI_FEATURE_ADDR_READ_RETRY, 458c2ecf20Sopenharmony_ci chip->parameters.set_feature_list)) 468c2ecf20Sopenharmony_ci return -ENOTSUPP; 478c2ecf20Sopenharmony_ci 488c2ecf20Sopenharmony_ci feature[0] = mode; 498c2ecf20Sopenharmony_ci return nand_set_features(chip, ONFI_FEATURE_ADDR_READ_RETRY, feature); 508c2ecf20Sopenharmony_ci} 518c2ecf20Sopenharmony_ci 528c2ecf20Sopenharmony_cistatic int macronix_nand_randomizer_check_enable(struct nand_chip *chip) 538c2ecf20Sopenharmony_ci{ 548c2ecf20Sopenharmony_ci u8 feature[ONFI_SUBFEATURE_PARAM_LEN]; 558c2ecf20Sopenharmony_ci int ret; 568c2ecf20Sopenharmony_ci 578c2ecf20Sopenharmony_ci ret = nand_get_features(chip, ONFI_FEATURE_ADDR_MXIC_RANDOMIZER, 588c2ecf20Sopenharmony_ci feature); 598c2ecf20Sopenharmony_ci if (ret < 0) 608c2ecf20Sopenharmony_ci return ret; 618c2ecf20Sopenharmony_ci 628c2ecf20Sopenharmony_ci if (feature[0]) 638c2ecf20Sopenharmony_ci return feature[0]; 648c2ecf20Sopenharmony_ci 658c2ecf20Sopenharmony_ci feature[0] = MACRONIX_RANDOMIZER_MODE_ENTER; 668c2ecf20Sopenharmony_ci ret = nand_set_features(chip, ONFI_FEATURE_ADDR_MXIC_RANDOMIZER, 678c2ecf20Sopenharmony_ci feature); 688c2ecf20Sopenharmony_ci if (ret < 0) 698c2ecf20Sopenharmony_ci return ret; 708c2ecf20Sopenharmony_ci 718c2ecf20Sopenharmony_ci /* RANDEN and RANDOPT OTP bits are programmed */ 728c2ecf20Sopenharmony_ci feature[0] = 0x0; 738c2ecf20Sopenharmony_ci ret = nand_prog_page_op(chip, 0, 0, feature, 1); 748c2ecf20Sopenharmony_ci if (ret < 0) 758c2ecf20Sopenharmony_ci return ret; 768c2ecf20Sopenharmony_ci 778c2ecf20Sopenharmony_ci ret = nand_get_features(chip, ONFI_FEATURE_ADDR_MXIC_RANDOMIZER, 788c2ecf20Sopenharmony_ci feature); 798c2ecf20Sopenharmony_ci if (ret < 0) 808c2ecf20Sopenharmony_ci return ret; 818c2ecf20Sopenharmony_ci 828c2ecf20Sopenharmony_ci feature[0] &= MACRONIX_RANDOMIZER_MODE_EXIT; 838c2ecf20Sopenharmony_ci ret = nand_set_features(chip, ONFI_FEATURE_ADDR_MXIC_RANDOMIZER, 848c2ecf20Sopenharmony_ci feature); 858c2ecf20Sopenharmony_ci if (ret < 0) 868c2ecf20Sopenharmony_ci return ret; 878c2ecf20Sopenharmony_ci 888c2ecf20Sopenharmony_ci return 0; 898c2ecf20Sopenharmony_ci} 908c2ecf20Sopenharmony_ci 918c2ecf20Sopenharmony_cistatic void macronix_nand_onfi_init(struct nand_chip *chip) 928c2ecf20Sopenharmony_ci{ 938c2ecf20Sopenharmony_ci struct nand_parameters *p = &chip->parameters; 948c2ecf20Sopenharmony_ci struct nand_onfi_vendor_macronix *mxic; 958c2ecf20Sopenharmony_ci struct device_node *dn = nand_get_flash_node(chip); 968c2ecf20Sopenharmony_ci int rand_otp = 0; 978c2ecf20Sopenharmony_ci int ret; 988c2ecf20Sopenharmony_ci 998c2ecf20Sopenharmony_ci if (!p->onfi) 1008c2ecf20Sopenharmony_ci return; 1018c2ecf20Sopenharmony_ci 1028c2ecf20Sopenharmony_ci if (of_find_property(dn, "mxic,enable-randomizer-otp", NULL)) 1038c2ecf20Sopenharmony_ci rand_otp = 1; 1048c2ecf20Sopenharmony_ci 1058c2ecf20Sopenharmony_ci mxic = (struct nand_onfi_vendor_macronix *)p->onfi->vendor; 1068c2ecf20Sopenharmony_ci /* Subpage write is prohibited in randomizer operatoin */ 1078c2ecf20Sopenharmony_ci if (rand_otp && chip->options & NAND_NO_SUBPAGE_WRITE && 1088c2ecf20Sopenharmony_ci mxic->reliability_func & MACRONIX_RANDOMIZER_BIT) { 1098c2ecf20Sopenharmony_ci if (p->supports_set_get_features) { 1108c2ecf20Sopenharmony_ci bitmap_set(p->set_feature_list, 1118c2ecf20Sopenharmony_ci ONFI_FEATURE_ADDR_MXIC_RANDOMIZER, 1); 1128c2ecf20Sopenharmony_ci bitmap_set(p->get_feature_list, 1138c2ecf20Sopenharmony_ci ONFI_FEATURE_ADDR_MXIC_RANDOMIZER, 1); 1148c2ecf20Sopenharmony_ci ret = macronix_nand_randomizer_check_enable(chip); 1158c2ecf20Sopenharmony_ci if (ret < 0) { 1168c2ecf20Sopenharmony_ci bitmap_clear(p->set_feature_list, 1178c2ecf20Sopenharmony_ci ONFI_FEATURE_ADDR_MXIC_RANDOMIZER, 1188c2ecf20Sopenharmony_ci 1); 1198c2ecf20Sopenharmony_ci bitmap_clear(p->get_feature_list, 1208c2ecf20Sopenharmony_ci ONFI_FEATURE_ADDR_MXIC_RANDOMIZER, 1218c2ecf20Sopenharmony_ci 1); 1228c2ecf20Sopenharmony_ci pr_info("Macronix NAND randomizer failed\n"); 1238c2ecf20Sopenharmony_ci } else { 1248c2ecf20Sopenharmony_ci pr_info("Macronix NAND randomizer enabled\n"); 1258c2ecf20Sopenharmony_ci } 1268c2ecf20Sopenharmony_ci } 1278c2ecf20Sopenharmony_ci } 1288c2ecf20Sopenharmony_ci 1298c2ecf20Sopenharmony_ci if ((mxic->reliability_func & MACRONIX_READ_RETRY_BIT) == 0) 1308c2ecf20Sopenharmony_ci return; 1318c2ecf20Sopenharmony_ci 1328c2ecf20Sopenharmony_ci chip->read_retries = MACRONIX_NUM_READ_RETRY_MODES; 1338c2ecf20Sopenharmony_ci chip->ops.setup_read_retry = macronix_nand_setup_read_retry; 1348c2ecf20Sopenharmony_ci 1358c2ecf20Sopenharmony_ci if (p->supports_set_get_features) { 1368c2ecf20Sopenharmony_ci bitmap_set(p->set_feature_list, 1378c2ecf20Sopenharmony_ci ONFI_FEATURE_ADDR_READ_RETRY, 1); 1388c2ecf20Sopenharmony_ci bitmap_set(p->get_feature_list, 1398c2ecf20Sopenharmony_ci ONFI_FEATURE_ADDR_READ_RETRY, 1); 1408c2ecf20Sopenharmony_ci } 1418c2ecf20Sopenharmony_ci} 1428c2ecf20Sopenharmony_ci 1438c2ecf20Sopenharmony_ci/* 1448c2ecf20Sopenharmony_ci * Macronix AC series does not support using SET/GET_FEATURES to change 1458c2ecf20Sopenharmony_ci * the timings unlike what is declared in the parameter page. Unflag 1468c2ecf20Sopenharmony_ci * this feature to avoid unnecessary downturns. 1478c2ecf20Sopenharmony_ci */ 1488c2ecf20Sopenharmony_cistatic void macronix_nand_fix_broken_get_timings(struct nand_chip *chip) 1498c2ecf20Sopenharmony_ci{ 1508c2ecf20Sopenharmony_ci int i; 1518c2ecf20Sopenharmony_ci static const char * const broken_get_timings[] = { 1528c2ecf20Sopenharmony_ci "MX30LF1G18AC", 1538c2ecf20Sopenharmony_ci "MX30LF1G28AC", 1548c2ecf20Sopenharmony_ci "MX30LF2G18AC", 1558c2ecf20Sopenharmony_ci "MX30LF2G28AC", 1568c2ecf20Sopenharmony_ci "MX30LF4G18AC", 1578c2ecf20Sopenharmony_ci "MX30LF4G28AC", 1588c2ecf20Sopenharmony_ci "MX60LF8G18AC", 1598c2ecf20Sopenharmony_ci "MX30UF1G18AC", 1608c2ecf20Sopenharmony_ci "MX30UF1G16AC", 1618c2ecf20Sopenharmony_ci "MX30UF2G18AC", 1628c2ecf20Sopenharmony_ci "MX30UF2G16AC", 1638c2ecf20Sopenharmony_ci "MX30UF4G18AC", 1648c2ecf20Sopenharmony_ci "MX30UF4G16AC", 1658c2ecf20Sopenharmony_ci "MX30UF4G28AC", 1668c2ecf20Sopenharmony_ci }; 1678c2ecf20Sopenharmony_ci 1688c2ecf20Sopenharmony_ci if (!chip->parameters.supports_set_get_features) 1698c2ecf20Sopenharmony_ci return; 1708c2ecf20Sopenharmony_ci 1718c2ecf20Sopenharmony_ci i = match_string(broken_get_timings, ARRAY_SIZE(broken_get_timings), 1728c2ecf20Sopenharmony_ci chip->parameters.model); 1738c2ecf20Sopenharmony_ci if (i < 0) 1748c2ecf20Sopenharmony_ci return; 1758c2ecf20Sopenharmony_ci 1768c2ecf20Sopenharmony_ci bitmap_clear(chip->parameters.get_feature_list, 1778c2ecf20Sopenharmony_ci ONFI_FEATURE_ADDR_TIMING_MODE, 1); 1788c2ecf20Sopenharmony_ci bitmap_clear(chip->parameters.set_feature_list, 1798c2ecf20Sopenharmony_ci ONFI_FEATURE_ADDR_TIMING_MODE, 1); 1808c2ecf20Sopenharmony_ci} 1818c2ecf20Sopenharmony_ci 1828c2ecf20Sopenharmony_ci/* 1838c2ecf20Sopenharmony_ci * Macronix NAND supports Block Protection by Protectoin(PT) pin; 1848c2ecf20Sopenharmony_ci * active high at power-on which protects the entire chip even the #WP is 1858c2ecf20Sopenharmony_ci * disabled. Lock/unlock protection area can be partition according to 1868c2ecf20Sopenharmony_ci * protection bits, i.e. upper 1/2 locked, upper 1/4 locked and so on. 1878c2ecf20Sopenharmony_ci */ 1888c2ecf20Sopenharmony_cistatic int mxic_nand_lock(struct nand_chip *chip, loff_t ofs, uint64_t len) 1898c2ecf20Sopenharmony_ci{ 1908c2ecf20Sopenharmony_ci u8 feature[ONFI_SUBFEATURE_PARAM_LEN]; 1918c2ecf20Sopenharmony_ci int ret; 1928c2ecf20Sopenharmony_ci 1938c2ecf20Sopenharmony_ci feature[0] = MXIC_BLOCK_PROTECTION_ALL_LOCK; 1948c2ecf20Sopenharmony_ci nand_select_target(chip, 0); 1958c2ecf20Sopenharmony_ci ret = nand_set_features(chip, ONFI_FEATURE_ADDR_MXIC_PROTECTION, 1968c2ecf20Sopenharmony_ci feature); 1978c2ecf20Sopenharmony_ci nand_deselect_target(chip); 1988c2ecf20Sopenharmony_ci if (ret) 1998c2ecf20Sopenharmony_ci pr_err("%s all blocks failed\n", __func__); 2008c2ecf20Sopenharmony_ci 2018c2ecf20Sopenharmony_ci return ret; 2028c2ecf20Sopenharmony_ci} 2038c2ecf20Sopenharmony_ci 2048c2ecf20Sopenharmony_cistatic int mxic_nand_unlock(struct nand_chip *chip, loff_t ofs, uint64_t len) 2058c2ecf20Sopenharmony_ci{ 2068c2ecf20Sopenharmony_ci u8 feature[ONFI_SUBFEATURE_PARAM_LEN]; 2078c2ecf20Sopenharmony_ci int ret; 2088c2ecf20Sopenharmony_ci 2098c2ecf20Sopenharmony_ci feature[0] = MXIC_BLOCK_PROTECTION_ALL_UNLOCK; 2108c2ecf20Sopenharmony_ci nand_select_target(chip, 0); 2118c2ecf20Sopenharmony_ci ret = nand_set_features(chip, ONFI_FEATURE_ADDR_MXIC_PROTECTION, 2128c2ecf20Sopenharmony_ci feature); 2138c2ecf20Sopenharmony_ci nand_deselect_target(chip); 2148c2ecf20Sopenharmony_ci if (ret) 2158c2ecf20Sopenharmony_ci pr_err("%s all blocks failed\n", __func__); 2168c2ecf20Sopenharmony_ci 2178c2ecf20Sopenharmony_ci return ret; 2188c2ecf20Sopenharmony_ci} 2198c2ecf20Sopenharmony_ci 2208c2ecf20Sopenharmony_cistatic void macronix_nand_block_protection_support(struct nand_chip *chip) 2218c2ecf20Sopenharmony_ci{ 2228c2ecf20Sopenharmony_ci u8 feature[ONFI_SUBFEATURE_PARAM_LEN]; 2238c2ecf20Sopenharmony_ci int ret; 2248c2ecf20Sopenharmony_ci 2258c2ecf20Sopenharmony_ci bitmap_set(chip->parameters.get_feature_list, 2268c2ecf20Sopenharmony_ci ONFI_FEATURE_ADDR_MXIC_PROTECTION, 1); 2278c2ecf20Sopenharmony_ci 2288c2ecf20Sopenharmony_ci feature[0] = MXIC_BLOCK_PROTECTION_ALL_UNLOCK; 2298c2ecf20Sopenharmony_ci nand_select_target(chip, 0); 2308c2ecf20Sopenharmony_ci ret = nand_get_features(chip, ONFI_FEATURE_ADDR_MXIC_PROTECTION, 2318c2ecf20Sopenharmony_ci feature); 2328c2ecf20Sopenharmony_ci nand_deselect_target(chip); 2338c2ecf20Sopenharmony_ci if (ret || feature[0] != MXIC_BLOCK_PROTECTION_ALL_LOCK) { 2348c2ecf20Sopenharmony_ci if (ret) 2358c2ecf20Sopenharmony_ci pr_err("Block protection check failed\n"); 2368c2ecf20Sopenharmony_ci 2378c2ecf20Sopenharmony_ci bitmap_clear(chip->parameters.get_feature_list, 2388c2ecf20Sopenharmony_ci ONFI_FEATURE_ADDR_MXIC_PROTECTION, 1); 2398c2ecf20Sopenharmony_ci return; 2408c2ecf20Sopenharmony_ci } 2418c2ecf20Sopenharmony_ci 2428c2ecf20Sopenharmony_ci bitmap_set(chip->parameters.set_feature_list, 2438c2ecf20Sopenharmony_ci ONFI_FEATURE_ADDR_MXIC_PROTECTION, 1); 2448c2ecf20Sopenharmony_ci 2458c2ecf20Sopenharmony_ci chip->ops.lock_area = mxic_nand_lock; 2468c2ecf20Sopenharmony_ci chip->ops.unlock_area = mxic_nand_unlock; 2478c2ecf20Sopenharmony_ci} 2488c2ecf20Sopenharmony_ci 2498c2ecf20Sopenharmony_cistatic int nand_power_down_op(struct nand_chip *chip) 2508c2ecf20Sopenharmony_ci{ 2518c2ecf20Sopenharmony_ci int ret; 2528c2ecf20Sopenharmony_ci 2538c2ecf20Sopenharmony_ci if (nand_has_exec_op(chip)) { 2548c2ecf20Sopenharmony_ci struct nand_op_instr instrs[] = { 2558c2ecf20Sopenharmony_ci NAND_OP_CMD(MXIC_CMD_POWER_DOWN, 0), 2568c2ecf20Sopenharmony_ci }; 2578c2ecf20Sopenharmony_ci 2588c2ecf20Sopenharmony_ci struct nand_operation op = NAND_OPERATION(chip->cur_cs, instrs); 2598c2ecf20Sopenharmony_ci 2608c2ecf20Sopenharmony_ci ret = nand_exec_op(chip, &op); 2618c2ecf20Sopenharmony_ci if (ret) 2628c2ecf20Sopenharmony_ci return ret; 2638c2ecf20Sopenharmony_ci 2648c2ecf20Sopenharmony_ci } else { 2658c2ecf20Sopenharmony_ci chip->legacy.cmdfunc(chip, MXIC_CMD_POWER_DOWN, -1, -1); 2668c2ecf20Sopenharmony_ci } 2678c2ecf20Sopenharmony_ci 2688c2ecf20Sopenharmony_ci return 0; 2698c2ecf20Sopenharmony_ci} 2708c2ecf20Sopenharmony_ci 2718c2ecf20Sopenharmony_cistatic int mxic_nand_suspend(struct nand_chip *chip) 2728c2ecf20Sopenharmony_ci{ 2738c2ecf20Sopenharmony_ci int ret; 2748c2ecf20Sopenharmony_ci 2758c2ecf20Sopenharmony_ci nand_select_target(chip, 0); 2768c2ecf20Sopenharmony_ci ret = nand_power_down_op(chip); 2778c2ecf20Sopenharmony_ci if (ret < 0) 2788c2ecf20Sopenharmony_ci pr_err("Suspending MXIC NAND chip failed (%d)\n", ret); 2798c2ecf20Sopenharmony_ci nand_deselect_target(chip); 2808c2ecf20Sopenharmony_ci 2818c2ecf20Sopenharmony_ci return ret; 2828c2ecf20Sopenharmony_ci} 2838c2ecf20Sopenharmony_ci 2848c2ecf20Sopenharmony_cistatic void mxic_nand_resume(struct nand_chip *chip) 2858c2ecf20Sopenharmony_ci{ 2868c2ecf20Sopenharmony_ci /* 2878c2ecf20Sopenharmony_ci * Toggle #CS pin to resume NAND device and don't care 2888c2ecf20Sopenharmony_ci * of the others CLE, #WE, #RE pins status. 2898c2ecf20Sopenharmony_ci * A NAND controller ensure it is able to assert/de-assert #CS 2908c2ecf20Sopenharmony_ci * by sending any byte over the NAND bus. 2918c2ecf20Sopenharmony_ci * i.e., 2928c2ecf20Sopenharmony_ci * NAND power down command or reset command w/o R/B# status checking. 2938c2ecf20Sopenharmony_ci */ 2948c2ecf20Sopenharmony_ci nand_select_target(chip, 0); 2958c2ecf20Sopenharmony_ci nand_power_down_op(chip); 2968c2ecf20Sopenharmony_ci /* The minimum of a recovery time tRDP is 35 us */ 2978c2ecf20Sopenharmony_ci usleep_range(35, 100); 2988c2ecf20Sopenharmony_ci nand_deselect_target(chip); 2998c2ecf20Sopenharmony_ci} 3008c2ecf20Sopenharmony_ci 3018c2ecf20Sopenharmony_cistatic void macronix_nand_deep_power_down_support(struct nand_chip *chip) 3028c2ecf20Sopenharmony_ci{ 3038c2ecf20Sopenharmony_ci int i; 3048c2ecf20Sopenharmony_ci static const char * const deep_power_down_dev[] = { 3058c2ecf20Sopenharmony_ci "MX30UF1G28AD", 3068c2ecf20Sopenharmony_ci "MX30UF2G28AD", 3078c2ecf20Sopenharmony_ci "MX30UF4G28AD", 3088c2ecf20Sopenharmony_ci }; 3098c2ecf20Sopenharmony_ci 3108c2ecf20Sopenharmony_ci i = match_string(deep_power_down_dev, ARRAY_SIZE(deep_power_down_dev), 3118c2ecf20Sopenharmony_ci chip->parameters.model); 3128c2ecf20Sopenharmony_ci if (i < 0) 3138c2ecf20Sopenharmony_ci return; 3148c2ecf20Sopenharmony_ci 3158c2ecf20Sopenharmony_ci chip->ops.suspend = mxic_nand_suspend; 3168c2ecf20Sopenharmony_ci chip->ops.resume = mxic_nand_resume; 3178c2ecf20Sopenharmony_ci} 3188c2ecf20Sopenharmony_ci 3198c2ecf20Sopenharmony_cistatic int macronix_nand_init(struct nand_chip *chip) 3208c2ecf20Sopenharmony_ci{ 3218c2ecf20Sopenharmony_ci if (nand_is_slc(chip)) 3228c2ecf20Sopenharmony_ci chip->options |= NAND_BBM_FIRSTPAGE | NAND_BBM_SECONDPAGE; 3238c2ecf20Sopenharmony_ci 3248c2ecf20Sopenharmony_ci macronix_nand_fix_broken_get_timings(chip); 3258c2ecf20Sopenharmony_ci macronix_nand_onfi_init(chip); 3268c2ecf20Sopenharmony_ci macronix_nand_block_protection_support(chip); 3278c2ecf20Sopenharmony_ci macronix_nand_deep_power_down_support(chip); 3288c2ecf20Sopenharmony_ci 3298c2ecf20Sopenharmony_ci return 0; 3308c2ecf20Sopenharmony_ci} 3318c2ecf20Sopenharmony_ci 3328c2ecf20Sopenharmony_ciconst struct nand_manufacturer_ops macronix_nand_manuf_ops = { 3338c2ecf20Sopenharmony_ci .init = macronix_nand_init, 3348c2ecf20Sopenharmony_ci}; 335