162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-or-later 262306a36Sopenharmony_ci/* 362306a36Sopenharmony_ci * Copyright (C) 2017 Free Electrons 462306a36Sopenharmony_ci * Copyright (C) 2017 NextThing Co 562306a36Sopenharmony_ci * 662306a36Sopenharmony_ci * Author: Boris Brezillon <boris.brezillon@free-electrons.com> 762306a36Sopenharmony_ci */ 862306a36Sopenharmony_ci 962306a36Sopenharmony_ci#include <linux/sizes.h> 1062306a36Sopenharmony_ci#include <linux/slab.h> 1162306a36Sopenharmony_ci 1262306a36Sopenharmony_ci#include "internals.h" 1362306a36Sopenharmony_ci 1462306a36Sopenharmony_ci#define NAND_HYNIX_CMD_SET_PARAMS 0x36 1562306a36Sopenharmony_ci#define NAND_HYNIX_CMD_APPLY_PARAMS 0x16 1662306a36Sopenharmony_ci 1762306a36Sopenharmony_ci#define NAND_HYNIX_1XNM_RR_REPEAT 8 1862306a36Sopenharmony_ci 1962306a36Sopenharmony_ci/** 2062306a36Sopenharmony_ci * struct hynix_read_retry - read-retry data 2162306a36Sopenharmony_ci * @nregs: number of register to set when applying a new read-retry mode 2262306a36Sopenharmony_ci * @regs: register offsets (NAND chip dependent) 2362306a36Sopenharmony_ci * @values: array of values to set in registers. The array size is equal to 2462306a36Sopenharmony_ci * (nregs * nmodes) 2562306a36Sopenharmony_ci */ 2662306a36Sopenharmony_cistruct hynix_read_retry { 2762306a36Sopenharmony_ci int nregs; 2862306a36Sopenharmony_ci const u8 *regs; 2962306a36Sopenharmony_ci u8 values[]; 3062306a36Sopenharmony_ci}; 3162306a36Sopenharmony_ci 3262306a36Sopenharmony_ci/** 3362306a36Sopenharmony_ci * struct hynix_nand - private Hynix NAND struct 3462306a36Sopenharmony_ci * @nand_technology: manufacturing process expressed in picometer 3562306a36Sopenharmony_ci * @read_retry: read-retry information 3662306a36Sopenharmony_ci */ 3762306a36Sopenharmony_cistruct hynix_nand { 3862306a36Sopenharmony_ci const struct hynix_read_retry *read_retry; 3962306a36Sopenharmony_ci}; 4062306a36Sopenharmony_ci 4162306a36Sopenharmony_ci/** 4262306a36Sopenharmony_ci * struct hynix_read_retry_otp - structure describing how the read-retry OTP 4362306a36Sopenharmony_ci * area 4462306a36Sopenharmony_ci * @nregs: number of hynix private registers to set before reading the reading 4562306a36Sopenharmony_ci * the OTP area 4662306a36Sopenharmony_ci * @regs: registers that should be configured 4762306a36Sopenharmony_ci * @values: values that should be set in regs 4862306a36Sopenharmony_ci * @page: the address to pass to the READ_PAGE command. Depends on the NAND 4962306a36Sopenharmony_ci * chip 5062306a36Sopenharmony_ci * @size: size of the read-retry OTP section 5162306a36Sopenharmony_ci */ 5262306a36Sopenharmony_cistruct hynix_read_retry_otp { 5362306a36Sopenharmony_ci int nregs; 5462306a36Sopenharmony_ci const u8 *regs; 5562306a36Sopenharmony_ci const u8 *values; 5662306a36Sopenharmony_ci int page; 5762306a36Sopenharmony_ci int size; 5862306a36Sopenharmony_ci}; 5962306a36Sopenharmony_ci 6062306a36Sopenharmony_cistatic bool hynix_nand_has_valid_jedecid(struct nand_chip *chip) 6162306a36Sopenharmony_ci{ 6262306a36Sopenharmony_ci u8 jedecid[5] = { }; 6362306a36Sopenharmony_ci int ret; 6462306a36Sopenharmony_ci 6562306a36Sopenharmony_ci ret = nand_readid_op(chip, 0x40, jedecid, sizeof(jedecid)); 6662306a36Sopenharmony_ci if (ret) 6762306a36Sopenharmony_ci return false; 6862306a36Sopenharmony_ci 6962306a36Sopenharmony_ci return !strncmp("JEDEC", jedecid, sizeof(jedecid)); 7062306a36Sopenharmony_ci} 7162306a36Sopenharmony_ci 7262306a36Sopenharmony_cistatic int hynix_nand_cmd_op(struct nand_chip *chip, u8 cmd) 7362306a36Sopenharmony_ci{ 7462306a36Sopenharmony_ci if (nand_has_exec_op(chip)) { 7562306a36Sopenharmony_ci struct nand_op_instr instrs[] = { 7662306a36Sopenharmony_ci NAND_OP_CMD(cmd, 0), 7762306a36Sopenharmony_ci }; 7862306a36Sopenharmony_ci struct nand_operation op = NAND_OPERATION(chip->cur_cs, instrs); 7962306a36Sopenharmony_ci 8062306a36Sopenharmony_ci return nand_exec_op(chip, &op); 8162306a36Sopenharmony_ci } 8262306a36Sopenharmony_ci 8362306a36Sopenharmony_ci chip->legacy.cmdfunc(chip, cmd, -1, -1); 8462306a36Sopenharmony_ci 8562306a36Sopenharmony_ci return 0; 8662306a36Sopenharmony_ci} 8762306a36Sopenharmony_ci 8862306a36Sopenharmony_cistatic int hynix_nand_reg_write_op(struct nand_chip *chip, u8 addr, u8 val) 8962306a36Sopenharmony_ci{ 9062306a36Sopenharmony_ci u16 column = ((u16)addr << 8) | addr; 9162306a36Sopenharmony_ci 9262306a36Sopenharmony_ci if (nand_has_exec_op(chip)) { 9362306a36Sopenharmony_ci struct nand_op_instr instrs[] = { 9462306a36Sopenharmony_ci NAND_OP_ADDR(1, &addr, 0), 9562306a36Sopenharmony_ci NAND_OP_8BIT_DATA_OUT(1, &val, 0), 9662306a36Sopenharmony_ci }; 9762306a36Sopenharmony_ci struct nand_operation op = NAND_OPERATION(chip->cur_cs, instrs); 9862306a36Sopenharmony_ci 9962306a36Sopenharmony_ci return nand_exec_op(chip, &op); 10062306a36Sopenharmony_ci } 10162306a36Sopenharmony_ci 10262306a36Sopenharmony_ci chip->legacy.cmdfunc(chip, NAND_CMD_NONE, column, -1); 10362306a36Sopenharmony_ci chip->legacy.write_byte(chip, val); 10462306a36Sopenharmony_ci 10562306a36Sopenharmony_ci return 0; 10662306a36Sopenharmony_ci} 10762306a36Sopenharmony_ci 10862306a36Sopenharmony_cistatic int hynix_nand_setup_read_retry(struct nand_chip *chip, int retry_mode) 10962306a36Sopenharmony_ci{ 11062306a36Sopenharmony_ci struct hynix_nand *hynix = nand_get_manufacturer_data(chip); 11162306a36Sopenharmony_ci const u8 *values; 11262306a36Sopenharmony_ci int i, ret; 11362306a36Sopenharmony_ci 11462306a36Sopenharmony_ci values = hynix->read_retry->values + 11562306a36Sopenharmony_ci (retry_mode * hynix->read_retry->nregs); 11662306a36Sopenharmony_ci 11762306a36Sopenharmony_ci /* Enter 'Set Hynix Parameters' mode */ 11862306a36Sopenharmony_ci ret = hynix_nand_cmd_op(chip, NAND_HYNIX_CMD_SET_PARAMS); 11962306a36Sopenharmony_ci if (ret) 12062306a36Sopenharmony_ci return ret; 12162306a36Sopenharmony_ci 12262306a36Sopenharmony_ci /* 12362306a36Sopenharmony_ci * Configure the NAND in the requested read-retry mode. 12462306a36Sopenharmony_ci * This is done by setting pre-defined values in internal NAND 12562306a36Sopenharmony_ci * registers. 12662306a36Sopenharmony_ci * 12762306a36Sopenharmony_ci * The set of registers is NAND specific, and the values are either 12862306a36Sopenharmony_ci * predefined or extracted from an OTP area on the NAND (values are 12962306a36Sopenharmony_ci * probably tweaked at production in this case). 13062306a36Sopenharmony_ci */ 13162306a36Sopenharmony_ci for (i = 0; i < hynix->read_retry->nregs; i++) { 13262306a36Sopenharmony_ci ret = hynix_nand_reg_write_op(chip, hynix->read_retry->regs[i], 13362306a36Sopenharmony_ci values[i]); 13462306a36Sopenharmony_ci if (ret) 13562306a36Sopenharmony_ci return ret; 13662306a36Sopenharmony_ci } 13762306a36Sopenharmony_ci 13862306a36Sopenharmony_ci /* Apply the new settings. */ 13962306a36Sopenharmony_ci return hynix_nand_cmd_op(chip, NAND_HYNIX_CMD_APPLY_PARAMS); 14062306a36Sopenharmony_ci} 14162306a36Sopenharmony_ci 14262306a36Sopenharmony_ci/** 14362306a36Sopenharmony_ci * hynix_get_majority - get the value that is occurring the most in a given 14462306a36Sopenharmony_ci * set of values 14562306a36Sopenharmony_ci * @in: the array of values to test 14662306a36Sopenharmony_ci * @repeat: the size of the in array 14762306a36Sopenharmony_ci * @out: pointer used to store the output value 14862306a36Sopenharmony_ci * 14962306a36Sopenharmony_ci * This function implements the 'majority check' logic that is supposed to 15062306a36Sopenharmony_ci * overcome the unreliability of MLC NANDs when reading the OTP area storing 15162306a36Sopenharmony_ci * the read-retry parameters. 15262306a36Sopenharmony_ci * 15362306a36Sopenharmony_ci * It's based on a pretty simple assumption: if we repeat the same value 15462306a36Sopenharmony_ci * several times and then take the one that is occurring the most, we should 15562306a36Sopenharmony_ci * find the correct value. 15662306a36Sopenharmony_ci * Let's hope this dummy algorithm prevents us from losing the read-retry 15762306a36Sopenharmony_ci * parameters. 15862306a36Sopenharmony_ci */ 15962306a36Sopenharmony_cistatic int hynix_get_majority(const u8 *in, int repeat, u8 *out) 16062306a36Sopenharmony_ci{ 16162306a36Sopenharmony_ci int i, j, half = repeat / 2; 16262306a36Sopenharmony_ci 16362306a36Sopenharmony_ci /* 16462306a36Sopenharmony_ci * We only test the first half of the in array because we must ensure 16562306a36Sopenharmony_ci * that the value is at least occurring repeat / 2 times. 16662306a36Sopenharmony_ci * 16762306a36Sopenharmony_ci * This loop is suboptimal since we may count the occurrences of the 16862306a36Sopenharmony_ci * same value several time, but we are doing that on small sets, which 16962306a36Sopenharmony_ci * makes it acceptable. 17062306a36Sopenharmony_ci */ 17162306a36Sopenharmony_ci for (i = 0; i < half; i++) { 17262306a36Sopenharmony_ci int cnt = 0; 17362306a36Sopenharmony_ci u8 val = in[i]; 17462306a36Sopenharmony_ci 17562306a36Sopenharmony_ci /* Count all values that are matching the one at index i. */ 17662306a36Sopenharmony_ci for (j = i + 1; j < repeat; j++) { 17762306a36Sopenharmony_ci if (in[j] == val) 17862306a36Sopenharmony_ci cnt++; 17962306a36Sopenharmony_ci } 18062306a36Sopenharmony_ci 18162306a36Sopenharmony_ci /* We found a value occurring more than repeat / 2. */ 18262306a36Sopenharmony_ci if (cnt > half) { 18362306a36Sopenharmony_ci *out = val; 18462306a36Sopenharmony_ci return 0; 18562306a36Sopenharmony_ci } 18662306a36Sopenharmony_ci } 18762306a36Sopenharmony_ci 18862306a36Sopenharmony_ci return -EIO; 18962306a36Sopenharmony_ci} 19062306a36Sopenharmony_ci 19162306a36Sopenharmony_cistatic int hynix_read_rr_otp(struct nand_chip *chip, 19262306a36Sopenharmony_ci const struct hynix_read_retry_otp *info, 19362306a36Sopenharmony_ci void *buf) 19462306a36Sopenharmony_ci{ 19562306a36Sopenharmony_ci int i, ret; 19662306a36Sopenharmony_ci 19762306a36Sopenharmony_ci ret = nand_reset_op(chip); 19862306a36Sopenharmony_ci if (ret) 19962306a36Sopenharmony_ci return ret; 20062306a36Sopenharmony_ci 20162306a36Sopenharmony_ci ret = hynix_nand_cmd_op(chip, NAND_HYNIX_CMD_SET_PARAMS); 20262306a36Sopenharmony_ci if (ret) 20362306a36Sopenharmony_ci return ret; 20462306a36Sopenharmony_ci 20562306a36Sopenharmony_ci for (i = 0; i < info->nregs; i++) { 20662306a36Sopenharmony_ci ret = hynix_nand_reg_write_op(chip, info->regs[i], 20762306a36Sopenharmony_ci info->values[i]); 20862306a36Sopenharmony_ci if (ret) 20962306a36Sopenharmony_ci return ret; 21062306a36Sopenharmony_ci } 21162306a36Sopenharmony_ci 21262306a36Sopenharmony_ci ret = hynix_nand_cmd_op(chip, NAND_HYNIX_CMD_APPLY_PARAMS); 21362306a36Sopenharmony_ci if (ret) 21462306a36Sopenharmony_ci return ret; 21562306a36Sopenharmony_ci 21662306a36Sopenharmony_ci /* Sequence to enter OTP mode? */ 21762306a36Sopenharmony_ci ret = hynix_nand_cmd_op(chip, 0x17); 21862306a36Sopenharmony_ci if (ret) 21962306a36Sopenharmony_ci return ret; 22062306a36Sopenharmony_ci 22162306a36Sopenharmony_ci ret = hynix_nand_cmd_op(chip, 0x4); 22262306a36Sopenharmony_ci if (ret) 22362306a36Sopenharmony_ci return ret; 22462306a36Sopenharmony_ci 22562306a36Sopenharmony_ci ret = hynix_nand_cmd_op(chip, 0x19); 22662306a36Sopenharmony_ci if (ret) 22762306a36Sopenharmony_ci return ret; 22862306a36Sopenharmony_ci 22962306a36Sopenharmony_ci /* Now read the page */ 23062306a36Sopenharmony_ci ret = nand_read_page_op(chip, info->page, 0, buf, info->size); 23162306a36Sopenharmony_ci if (ret) 23262306a36Sopenharmony_ci return ret; 23362306a36Sopenharmony_ci 23462306a36Sopenharmony_ci /* Put everything back to normal */ 23562306a36Sopenharmony_ci ret = nand_reset_op(chip); 23662306a36Sopenharmony_ci if (ret) 23762306a36Sopenharmony_ci return ret; 23862306a36Sopenharmony_ci 23962306a36Sopenharmony_ci ret = hynix_nand_cmd_op(chip, NAND_HYNIX_CMD_SET_PARAMS); 24062306a36Sopenharmony_ci if (ret) 24162306a36Sopenharmony_ci return ret; 24262306a36Sopenharmony_ci 24362306a36Sopenharmony_ci ret = hynix_nand_reg_write_op(chip, 0x38, 0); 24462306a36Sopenharmony_ci if (ret) 24562306a36Sopenharmony_ci return ret; 24662306a36Sopenharmony_ci 24762306a36Sopenharmony_ci ret = hynix_nand_cmd_op(chip, NAND_HYNIX_CMD_APPLY_PARAMS); 24862306a36Sopenharmony_ci if (ret) 24962306a36Sopenharmony_ci return ret; 25062306a36Sopenharmony_ci 25162306a36Sopenharmony_ci return nand_read_page_op(chip, 0, 0, NULL, 0); 25262306a36Sopenharmony_ci} 25362306a36Sopenharmony_ci 25462306a36Sopenharmony_ci#define NAND_HYNIX_1XNM_RR_COUNT_OFFS 0 25562306a36Sopenharmony_ci#define NAND_HYNIX_1XNM_RR_REG_COUNT_OFFS 8 25662306a36Sopenharmony_ci#define NAND_HYNIX_1XNM_RR_SET_OFFS(x, setsize, inv) \ 25762306a36Sopenharmony_ci (16 + ((((x) * 2) + ((inv) ? 1 : 0)) * (setsize))) 25862306a36Sopenharmony_ci 25962306a36Sopenharmony_cistatic int hynix_mlc_1xnm_rr_value(const u8 *buf, int nmodes, int nregs, 26062306a36Sopenharmony_ci int mode, int reg, bool inv, u8 *val) 26162306a36Sopenharmony_ci{ 26262306a36Sopenharmony_ci u8 tmp[NAND_HYNIX_1XNM_RR_REPEAT]; 26362306a36Sopenharmony_ci int val_offs = (mode * nregs) + reg; 26462306a36Sopenharmony_ci int set_size = nmodes * nregs; 26562306a36Sopenharmony_ci int i, ret; 26662306a36Sopenharmony_ci 26762306a36Sopenharmony_ci for (i = 0; i < NAND_HYNIX_1XNM_RR_REPEAT; i++) { 26862306a36Sopenharmony_ci int set_offs = NAND_HYNIX_1XNM_RR_SET_OFFS(i, set_size, inv); 26962306a36Sopenharmony_ci 27062306a36Sopenharmony_ci tmp[i] = buf[val_offs + set_offs]; 27162306a36Sopenharmony_ci } 27262306a36Sopenharmony_ci 27362306a36Sopenharmony_ci ret = hynix_get_majority(tmp, NAND_HYNIX_1XNM_RR_REPEAT, val); 27462306a36Sopenharmony_ci if (ret) 27562306a36Sopenharmony_ci return ret; 27662306a36Sopenharmony_ci 27762306a36Sopenharmony_ci if (inv) 27862306a36Sopenharmony_ci *val = ~*val; 27962306a36Sopenharmony_ci 28062306a36Sopenharmony_ci return 0; 28162306a36Sopenharmony_ci} 28262306a36Sopenharmony_ci 28362306a36Sopenharmony_cistatic u8 hynix_1xnm_mlc_read_retry_regs[] = { 28462306a36Sopenharmony_ci 0xcc, 0xbf, 0xaa, 0xab, 0xcd, 0xad, 0xae, 0xaf 28562306a36Sopenharmony_ci}; 28662306a36Sopenharmony_ci 28762306a36Sopenharmony_cistatic int hynix_mlc_1xnm_rr_init(struct nand_chip *chip, 28862306a36Sopenharmony_ci const struct hynix_read_retry_otp *info) 28962306a36Sopenharmony_ci{ 29062306a36Sopenharmony_ci struct hynix_nand *hynix = nand_get_manufacturer_data(chip); 29162306a36Sopenharmony_ci struct hynix_read_retry *rr = NULL; 29262306a36Sopenharmony_ci int ret, i, j; 29362306a36Sopenharmony_ci u8 nregs, nmodes; 29462306a36Sopenharmony_ci u8 *buf; 29562306a36Sopenharmony_ci 29662306a36Sopenharmony_ci buf = kmalloc(info->size, GFP_KERNEL); 29762306a36Sopenharmony_ci if (!buf) 29862306a36Sopenharmony_ci return -ENOMEM; 29962306a36Sopenharmony_ci 30062306a36Sopenharmony_ci ret = hynix_read_rr_otp(chip, info, buf); 30162306a36Sopenharmony_ci if (ret) 30262306a36Sopenharmony_ci goto out; 30362306a36Sopenharmony_ci 30462306a36Sopenharmony_ci ret = hynix_get_majority(buf, NAND_HYNIX_1XNM_RR_REPEAT, 30562306a36Sopenharmony_ci &nmodes); 30662306a36Sopenharmony_ci if (ret) 30762306a36Sopenharmony_ci goto out; 30862306a36Sopenharmony_ci 30962306a36Sopenharmony_ci ret = hynix_get_majority(buf + NAND_HYNIX_1XNM_RR_REPEAT, 31062306a36Sopenharmony_ci NAND_HYNIX_1XNM_RR_REPEAT, 31162306a36Sopenharmony_ci &nregs); 31262306a36Sopenharmony_ci if (ret) 31362306a36Sopenharmony_ci goto out; 31462306a36Sopenharmony_ci 31562306a36Sopenharmony_ci rr = kzalloc(sizeof(*rr) + (nregs * nmodes), GFP_KERNEL); 31662306a36Sopenharmony_ci if (!rr) { 31762306a36Sopenharmony_ci ret = -ENOMEM; 31862306a36Sopenharmony_ci goto out; 31962306a36Sopenharmony_ci } 32062306a36Sopenharmony_ci 32162306a36Sopenharmony_ci for (i = 0; i < nmodes; i++) { 32262306a36Sopenharmony_ci for (j = 0; j < nregs; j++) { 32362306a36Sopenharmony_ci u8 *val = rr->values + (i * nregs); 32462306a36Sopenharmony_ci 32562306a36Sopenharmony_ci ret = hynix_mlc_1xnm_rr_value(buf, nmodes, nregs, i, j, 32662306a36Sopenharmony_ci false, val); 32762306a36Sopenharmony_ci if (!ret) 32862306a36Sopenharmony_ci continue; 32962306a36Sopenharmony_ci 33062306a36Sopenharmony_ci ret = hynix_mlc_1xnm_rr_value(buf, nmodes, nregs, i, j, 33162306a36Sopenharmony_ci true, val); 33262306a36Sopenharmony_ci if (ret) 33362306a36Sopenharmony_ci goto out; 33462306a36Sopenharmony_ci } 33562306a36Sopenharmony_ci } 33662306a36Sopenharmony_ci 33762306a36Sopenharmony_ci rr->nregs = nregs; 33862306a36Sopenharmony_ci rr->regs = hynix_1xnm_mlc_read_retry_regs; 33962306a36Sopenharmony_ci hynix->read_retry = rr; 34062306a36Sopenharmony_ci chip->ops.setup_read_retry = hynix_nand_setup_read_retry; 34162306a36Sopenharmony_ci chip->read_retries = nmodes; 34262306a36Sopenharmony_ci 34362306a36Sopenharmony_ciout: 34462306a36Sopenharmony_ci kfree(buf); 34562306a36Sopenharmony_ci 34662306a36Sopenharmony_ci if (ret) 34762306a36Sopenharmony_ci kfree(rr); 34862306a36Sopenharmony_ci 34962306a36Sopenharmony_ci return ret; 35062306a36Sopenharmony_ci} 35162306a36Sopenharmony_ci 35262306a36Sopenharmony_cistatic const u8 hynix_mlc_1xnm_rr_otp_regs[] = { 0x38 }; 35362306a36Sopenharmony_cistatic const u8 hynix_mlc_1xnm_rr_otp_values[] = { 0x52 }; 35462306a36Sopenharmony_ci 35562306a36Sopenharmony_cistatic const struct hynix_read_retry_otp hynix_mlc_1xnm_rr_otps[] = { 35662306a36Sopenharmony_ci { 35762306a36Sopenharmony_ci .nregs = ARRAY_SIZE(hynix_mlc_1xnm_rr_otp_regs), 35862306a36Sopenharmony_ci .regs = hynix_mlc_1xnm_rr_otp_regs, 35962306a36Sopenharmony_ci .values = hynix_mlc_1xnm_rr_otp_values, 36062306a36Sopenharmony_ci .page = 0x21f, 36162306a36Sopenharmony_ci .size = 784 36262306a36Sopenharmony_ci }, 36362306a36Sopenharmony_ci { 36462306a36Sopenharmony_ci .nregs = ARRAY_SIZE(hynix_mlc_1xnm_rr_otp_regs), 36562306a36Sopenharmony_ci .regs = hynix_mlc_1xnm_rr_otp_regs, 36662306a36Sopenharmony_ci .values = hynix_mlc_1xnm_rr_otp_values, 36762306a36Sopenharmony_ci .page = 0x200, 36862306a36Sopenharmony_ci .size = 528, 36962306a36Sopenharmony_ci }, 37062306a36Sopenharmony_ci}; 37162306a36Sopenharmony_ci 37262306a36Sopenharmony_cistatic int hynix_nand_rr_init(struct nand_chip *chip) 37362306a36Sopenharmony_ci{ 37462306a36Sopenharmony_ci int i, ret = 0; 37562306a36Sopenharmony_ci bool valid_jedecid; 37662306a36Sopenharmony_ci 37762306a36Sopenharmony_ci valid_jedecid = hynix_nand_has_valid_jedecid(chip); 37862306a36Sopenharmony_ci 37962306a36Sopenharmony_ci /* 38062306a36Sopenharmony_ci * We only support read-retry for 1xnm NANDs, and those NANDs all 38162306a36Sopenharmony_ci * expose a valid JEDEC ID. 38262306a36Sopenharmony_ci */ 38362306a36Sopenharmony_ci if (valid_jedecid) { 38462306a36Sopenharmony_ci u8 nand_tech = chip->id.data[5] >> 4; 38562306a36Sopenharmony_ci 38662306a36Sopenharmony_ci /* 1xnm technology */ 38762306a36Sopenharmony_ci if (nand_tech == 4) { 38862306a36Sopenharmony_ci for (i = 0; i < ARRAY_SIZE(hynix_mlc_1xnm_rr_otps); 38962306a36Sopenharmony_ci i++) { 39062306a36Sopenharmony_ci /* 39162306a36Sopenharmony_ci * FIXME: Hynix recommend to copy the 39262306a36Sopenharmony_ci * read-retry OTP area into a normal page. 39362306a36Sopenharmony_ci */ 39462306a36Sopenharmony_ci ret = hynix_mlc_1xnm_rr_init(chip, 39562306a36Sopenharmony_ci hynix_mlc_1xnm_rr_otps); 39662306a36Sopenharmony_ci if (!ret) 39762306a36Sopenharmony_ci break; 39862306a36Sopenharmony_ci } 39962306a36Sopenharmony_ci } 40062306a36Sopenharmony_ci } 40162306a36Sopenharmony_ci 40262306a36Sopenharmony_ci if (ret) 40362306a36Sopenharmony_ci pr_warn("failed to initialize read-retry infrastructure"); 40462306a36Sopenharmony_ci 40562306a36Sopenharmony_ci return 0; 40662306a36Sopenharmony_ci} 40762306a36Sopenharmony_ci 40862306a36Sopenharmony_cistatic void hynix_nand_extract_oobsize(struct nand_chip *chip, 40962306a36Sopenharmony_ci bool valid_jedecid) 41062306a36Sopenharmony_ci{ 41162306a36Sopenharmony_ci struct mtd_info *mtd = nand_to_mtd(chip); 41262306a36Sopenharmony_ci struct nand_memory_organization *memorg; 41362306a36Sopenharmony_ci u8 oobsize; 41462306a36Sopenharmony_ci 41562306a36Sopenharmony_ci memorg = nanddev_get_memorg(&chip->base); 41662306a36Sopenharmony_ci 41762306a36Sopenharmony_ci oobsize = ((chip->id.data[3] >> 2) & 0x3) | 41862306a36Sopenharmony_ci ((chip->id.data[3] >> 4) & 0x4); 41962306a36Sopenharmony_ci 42062306a36Sopenharmony_ci if (valid_jedecid) { 42162306a36Sopenharmony_ci switch (oobsize) { 42262306a36Sopenharmony_ci case 0: 42362306a36Sopenharmony_ci memorg->oobsize = 2048; 42462306a36Sopenharmony_ci break; 42562306a36Sopenharmony_ci case 1: 42662306a36Sopenharmony_ci memorg->oobsize = 1664; 42762306a36Sopenharmony_ci break; 42862306a36Sopenharmony_ci case 2: 42962306a36Sopenharmony_ci memorg->oobsize = 1024; 43062306a36Sopenharmony_ci break; 43162306a36Sopenharmony_ci case 3: 43262306a36Sopenharmony_ci memorg->oobsize = 640; 43362306a36Sopenharmony_ci break; 43462306a36Sopenharmony_ci default: 43562306a36Sopenharmony_ci /* 43662306a36Sopenharmony_ci * We should never reach this case, but if that 43762306a36Sopenharmony_ci * happens, this probably means Hynix decided to use 43862306a36Sopenharmony_ci * a different extended ID format, and we should find 43962306a36Sopenharmony_ci * a way to support it. 44062306a36Sopenharmony_ci */ 44162306a36Sopenharmony_ci WARN(1, "Invalid OOB size"); 44262306a36Sopenharmony_ci break; 44362306a36Sopenharmony_ci } 44462306a36Sopenharmony_ci } else { 44562306a36Sopenharmony_ci switch (oobsize) { 44662306a36Sopenharmony_ci case 0: 44762306a36Sopenharmony_ci memorg->oobsize = 128; 44862306a36Sopenharmony_ci break; 44962306a36Sopenharmony_ci case 1: 45062306a36Sopenharmony_ci memorg->oobsize = 224; 45162306a36Sopenharmony_ci break; 45262306a36Sopenharmony_ci case 2: 45362306a36Sopenharmony_ci memorg->oobsize = 448; 45462306a36Sopenharmony_ci break; 45562306a36Sopenharmony_ci case 3: 45662306a36Sopenharmony_ci memorg->oobsize = 64; 45762306a36Sopenharmony_ci break; 45862306a36Sopenharmony_ci case 4: 45962306a36Sopenharmony_ci memorg->oobsize = 32; 46062306a36Sopenharmony_ci break; 46162306a36Sopenharmony_ci case 5: 46262306a36Sopenharmony_ci memorg->oobsize = 16; 46362306a36Sopenharmony_ci break; 46462306a36Sopenharmony_ci case 6: 46562306a36Sopenharmony_ci memorg->oobsize = 640; 46662306a36Sopenharmony_ci break; 46762306a36Sopenharmony_ci default: 46862306a36Sopenharmony_ci /* 46962306a36Sopenharmony_ci * We should never reach this case, but if that 47062306a36Sopenharmony_ci * happens, this probably means Hynix decided to use 47162306a36Sopenharmony_ci * a different extended ID format, and we should find 47262306a36Sopenharmony_ci * a way to support it. 47362306a36Sopenharmony_ci */ 47462306a36Sopenharmony_ci WARN(1, "Invalid OOB size"); 47562306a36Sopenharmony_ci break; 47662306a36Sopenharmony_ci } 47762306a36Sopenharmony_ci 47862306a36Sopenharmony_ci /* 47962306a36Sopenharmony_ci * The datasheet of H27UCG8T2BTR mentions that the "Redundant 48062306a36Sopenharmony_ci * Area Size" is encoded "per 8KB" (page size). This chip uses 48162306a36Sopenharmony_ci * a page size of 16KiB. The datasheet mentions an OOB size of 48262306a36Sopenharmony_ci * 1.280 bytes, but the OOB size encoded in the ID bytes (using 48362306a36Sopenharmony_ci * the existing logic above) is 640 bytes. 48462306a36Sopenharmony_ci * Update the OOB size for this chip by taking the value 48562306a36Sopenharmony_ci * determined above and scaling it to the actual page size (so 48662306a36Sopenharmony_ci * the actual OOB size for this chip is: 640 * 16k / 8k). 48762306a36Sopenharmony_ci */ 48862306a36Sopenharmony_ci if (chip->id.data[1] == 0xde) 48962306a36Sopenharmony_ci memorg->oobsize *= memorg->pagesize / SZ_8K; 49062306a36Sopenharmony_ci } 49162306a36Sopenharmony_ci 49262306a36Sopenharmony_ci mtd->oobsize = memorg->oobsize; 49362306a36Sopenharmony_ci} 49462306a36Sopenharmony_ci 49562306a36Sopenharmony_cistatic void hynix_nand_extract_ecc_requirements(struct nand_chip *chip, 49662306a36Sopenharmony_ci bool valid_jedecid) 49762306a36Sopenharmony_ci{ 49862306a36Sopenharmony_ci struct nand_device *base = &chip->base; 49962306a36Sopenharmony_ci struct nand_ecc_props requirements = {}; 50062306a36Sopenharmony_ci u8 ecc_level = (chip->id.data[4] >> 4) & 0x7; 50162306a36Sopenharmony_ci 50262306a36Sopenharmony_ci if (valid_jedecid) { 50362306a36Sopenharmony_ci /* Reference: H27UCG8T2E datasheet */ 50462306a36Sopenharmony_ci requirements.step_size = 1024; 50562306a36Sopenharmony_ci 50662306a36Sopenharmony_ci switch (ecc_level) { 50762306a36Sopenharmony_ci case 0: 50862306a36Sopenharmony_ci requirements.step_size = 0; 50962306a36Sopenharmony_ci requirements.strength = 0; 51062306a36Sopenharmony_ci break; 51162306a36Sopenharmony_ci case 1: 51262306a36Sopenharmony_ci requirements.strength = 4; 51362306a36Sopenharmony_ci break; 51462306a36Sopenharmony_ci case 2: 51562306a36Sopenharmony_ci requirements.strength = 24; 51662306a36Sopenharmony_ci break; 51762306a36Sopenharmony_ci case 3: 51862306a36Sopenharmony_ci requirements.strength = 32; 51962306a36Sopenharmony_ci break; 52062306a36Sopenharmony_ci case 4: 52162306a36Sopenharmony_ci requirements.strength = 40; 52262306a36Sopenharmony_ci break; 52362306a36Sopenharmony_ci case 5: 52462306a36Sopenharmony_ci requirements.strength = 50; 52562306a36Sopenharmony_ci break; 52662306a36Sopenharmony_ci case 6: 52762306a36Sopenharmony_ci requirements.strength = 60; 52862306a36Sopenharmony_ci break; 52962306a36Sopenharmony_ci default: 53062306a36Sopenharmony_ci /* 53162306a36Sopenharmony_ci * We should never reach this case, but if that 53262306a36Sopenharmony_ci * happens, this probably means Hynix decided to use 53362306a36Sopenharmony_ci * a different extended ID format, and we should find 53462306a36Sopenharmony_ci * a way to support it. 53562306a36Sopenharmony_ci */ 53662306a36Sopenharmony_ci WARN(1, "Invalid ECC requirements"); 53762306a36Sopenharmony_ci } 53862306a36Sopenharmony_ci } else { 53962306a36Sopenharmony_ci /* 54062306a36Sopenharmony_ci * The ECC requirements field meaning depends on the 54162306a36Sopenharmony_ci * NAND technology. 54262306a36Sopenharmony_ci */ 54362306a36Sopenharmony_ci u8 nand_tech = chip->id.data[5] & 0x7; 54462306a36Sopenharmony_ci 54562306a36Sopenharmony_ci if (nand_tech < 3) { 54662306a36Sopenharmony_ci /* > 26nm, reference: H27UBG8T2A datasheet */ 54762306a36Sopenharmony_ci if (ecc_level < 5) { 54862306a36Sopenharmony_ci requirements.step_size = 512; 54962306a36Sopenharmony_ci requirements.strength = 1 << ecc_level; 55062306a36Sopenharmony_ci } else if (ecc_level < 7) { 55162306a36Sopenharmony_ci if (ecc_level == 5) 55262306a36Sopenharmony_ci requirements.step_size = 2048; 55362306a36Sopenharmony_ci else 55462306a36Sopenharmony_ci requirements.step_size = 1024; 55562306a36Sopenharmony_ci requirements.strength = 24; 55662306a36Sopenharmony_ci } else { 55762306a36Sopenharmony_ci /* 55862306a36Sopenharmony_ci * We should never reach this case, but if that 55962306a36Sopenharmony_ci * happens, this probably means Hynix decided 56062306a36Sopenharmony_ci * to use a different extended ID format, and 56162306a36Sopenharmony_ci * we should find a way to support it. 56262306a36Sopenharmony_ci */ 56362306a36Sopenharmony_ci WARN(1, "Invalid ECC requirements"); 56462306a36Sopenharmony_ci } 56562306a36Sopenharmony_ci } else { 56662306a36Sopenharmony_ci /* <= 26nm, reference: H27UBG8T2B datasheet */ 56762306a36Sopenharmony_ci if (!ecc_level) { 56862306a36Sopenharmony_ci requirements.step_size = 0; 56962306a36Sopenharmony_ci requirements.strength = 0; 57062306a36Sopenharmony_ci } else if (ecc_level < 5) { 57162306a36Sopenharmony_ci requirements.step_size = 512; 57262306a36Sopenharmony_ci requirements.strength = 1 << (ecc_level - 1); 57362306a36Sopenharmony_ci } else { 57462306a36Sopenharmony_ci requirements.step_size = 1024; 57562306a36Sopenharmony_ci requirements.strength = 24 + 57662306a36Sopenharmony_ci (8 * (ecc_level - 5)); 57762306a36Sopenharmony_ci } 57862306a36Sopenharmony_ci } 57962306a36Sopenharmony_ci } 58062306a36Sopenharmony_ci 58162306a36Sopenharmony_ci nanddev_set_ecc_requirements(base, &requirements); 58262306a36Sopenharmony_ci} 58362306a36Sopenharmony_ci 58462306a36Sopenharmony_cistatic void hynix_nand_extract_scrambling_requirements(struct nand_chip *chip, 58562306a36Sopenharmony_ci bool valid_jedecid) 58662306a36Sopenharmony_ci{ 58762306a36Sopenharmony_ci u8 nand_tech; 58862306a36Sopenharmony_ci 58962306a36Sopenharmony_ci /* We need scrambling on all TLC NANDs*/ 59062306a36Sopenharmony_ci if (nanddev_bits_per_cell(&chip->base) > 2) 59162306a36Sopenharmony_ci chip->options |= NAND_NEED_SCRAMBLING; 59262306a36Sopenharmony_ci 59362306a36Sopenharmony_ci /* And on MLC NANDs with sub-3xnm process */ 59462306a36Sopenharmony_ci if (valid_jedecid) { 59562306a36Sopenharmony_ci nand_tech = chip->id.data[5] >> 4; 59662306a36Sopenharmony_ci 59762306a36Sopenharmony_ci /* < 3xnm */ 59862306a36Sopenharmony_ci if (nand_tech > 0) 59962306a36Sopenharmony_ci chip->options |= NAND_NEED_SCRAMBLING; 60062306a36Sopenharmony_ci } else { 60162306a36Sopenharmony_ci nand_tech = chip->id.data[5] & 0x7; 60262306a36Sopenharmony_ci 60362306a36Sopenharmony_ci /* < 32nm */ 60462306a36Sopenharmony_ci if (nand_tech > 2) 60562306a36Sopenharmony_ci chip->options |= NAND_NEED_SCRAMBLING; 60662306a36Sopenharmony_ci } 60762306a36Sopenharmony_ci} 60862306a36Sopenharmony_ci 60962306a36Sopenharmony_cistatic void hynix_nand_decode_id(struct nand_chip *chip) 61062306a36Sopenharmony_ci{ 61162306a36Sopenharmony_ci struct mtd_info *mtd = nand_to_mtd(chip); 61262306a36Sopenharmony_ci struct nand_memory_organization *memorg; 61362306a36Sopenharmony_ci bool valid_jedecid; 61462306a36Sopenharmony_ci u8 tmp; 61562306a36Sopenharmony_ci 61662306a36Sopenharmony_ci memorg = nanddev_get_memorg(&chip->base); 61762306a36Sopenharmony_ci 61862306a36Sopenharmony_ci /* 61962306a36Sopenharmony_ci * Exclude all SLC NANDs from this advanced detection scheme. 62062306a36Sopenharmony_ci * According to the ranges defined in several datasheets, it might 62162306a36Sopenharmony_ci * appear that even SLC NANDs could fall in this extended ID scheme. 62262306a36Sopenharmony_ci * If that the case rework the test to let SLC NANDs go through the 62362306a36Sopenharmony_ci * detection process. 62462306a36Sopenharmony_ci */ 62562306a36Sopenharmony_ci if (chip->id.len < 6 || nand_is_slc(chip)) { 62662306a36Sopenharmony_ci nand_decode_ext_id(chip); 62762306a36Sopenharmony_ci return; 62862306a36Sopenharmony_ci } 62962306a36Sopenharmony_ci 63062306a36Sopenharmony_ci /* Extract pagesize */ 63162306a36Sopenharmony_ci memorg->pagesize = 2048 << (chip->id.data[3] & 0x03); 63262306a36Sopenharmony_ci mtd->writesize = memorg->pagesize; 63362306a36Sopenharmony_ci 63462306a36Sopenharmony_ci tmp = (chip->id.data[3] >> 4) & 0x3; 63562306a36Sopenharmony_ci /* 63662306a36Sopenharmony_ci * When bit7 is set that means we start counting at 1MiB, otherwise 63762306a36Sopenharmony_ci * we start counting at 128KiB and shift this value the content of 63862306a36Sopenharmony_ci * ID[3][4:5]. 63962306a36Sopenharmony_ci * The only exception is when ID[3][4:5] == 3 and ID[3][7] == 0, in 64062306a36Sopenharmony_ci * this case the erasesize is set to 768KiB. 64162306a36Sopenharmony_ci */ 64262306a36Sopenharmony_ci if (chip->id.data[3] & 0x80) { 64362306a36Sopenharmony_ci memorg->pages_per_eraseblock = (SZ_1M << tmp) / 64462306a36Sopenharmony_ci memorg->pagesize; 64562306a36Sopenharmony_ci mtd->erasesize = SZ_1M << tmp; 64662306a36Sopenharmony_ci } else if (tmp == 3) { 64762306a36Sopenharmony_ci memorg->pages_per_eraseblock = (SZ_512K + SZ_256K) / 64862306a36Sopenharmony_ci memorg->pagesize; 64962306a36Sopenharmony_ci mtd->erasesize = SZ_512K + SZ_256K; 65062306a36Sopenharmony_ci } else { 65162306a36Sopenharmony_ci memorg->pages_per_eraseblock = (SZ_128K << tmp) / 65262306a36Sopenharmony_ci memorg->pagesize; 65362306a36Sopenharmony_ci mtd->erasesize = SZ_128K << tmp; 65462306a36Sopenharmony_ci } 65562306a36Sopenharmony_ci 65662306a36Sopenharmony_ci /* 65762306a36Sopenharmony_ci * Modern Toggle DDR NANDs have a valid JEDECID even though they are 65862306a36Sopenharmony_ci * not exposing a valid JEDEC parameter table. 65962306a36Sopenharmony_ci * These NANDs use a different NAND ID scheme. 66062306a36Sopenharmony_ci */ 66162306a36Sopenharmony_ci valid_jedecid = hynix_nand_has_valid_jedecid(chip); 66262306a36Sopenharmony_ci 66362306a36Sopenharmony_ci hynix_nand_extract_oobsize(chip, valid_jedecid); 66462306a36Sopenharmony_ci hynix_nand_extract_ecc_requirements(chip, valid_jedecid); 66562306a36Sopenharmony_ci hynix_nand_extract_scrambling_requirements(chip, valid_jedecid); 66662306a36Sopenharmony_ci} 66762306a36Sopenharmony_ci 66862306a36Sopenharmony_cistatic void hynix_nand_cleanup(struct nand_chip *chip) 66962306a36Sopenharmony_ci{ 67062306a36Sopenharmony_ci struct hynix_nand *hynix = nand_get_manufacturer_data(chip); 67162306a36Sopenharmony_ci 67262306a36Sopenharmony_ci if (!hynix) 67362306a36Sopenharmony_ci return; 67462306a36Sopenharmony_ci 67562306a36Sopenharmony_ci kfree(hynix->read_retry); 67662306a36Sopenharmony_ci kfree(hynix); 67762306a36Sopenharmony_ci nand_set_manufacturer_data(chip, NULL); 67862306a36Sopenharmony_ci} 67962306a36Sopenharmony_ci 68062306a36Sopenharmony_cistatic int 68162306a36Sopenharmony_cih27ucg8t2atrbc_choose_interface_config(struct nand_chip *chip, 68262306a36Sopenharmony_ci struct nand_interface_config *iface) 68362306a36Sopenharmony_ci{ 68462306a36Sopenharmony_ci onfi_fill_interface_config(chip, iface, NAND_SDR_IFACE, 4); 68562306a36Sopenharmony_ci 68662306a36Sopenharmony_ci return nand_choose_best_sdr_timings(chip, iface, NULL); 68762306a36Sopenharmony_ci} 68862306a36Sopenharmony_ci 68962306a36Sopenharmony_cistatic int h27ucg8t2etrbc_init(struct nand_chip *chip) 69062306a36Sopenharmony_ci{ 69162306a36Sopenharmony_ci struct mtd_info *mtd = nand_to_mtd(chip); 69262306a36Sopenharmony_ci 69362306a36Sopenharmony_ci chip->options |= NAND_NEED_SCRAMBLING; 69462306a36Sopenharmony_ci mtd_set_pairing_scheme(mtd, &dist3_pairing_scheme); 69562306a36Sopenharmony_ci 69662306a36Sopenharmony_ci return 0; 69762306a36Sopenharmony_ci} 69862306a36Sopenharmony_ci 69962306a36Sopenharmony_cistatic int hynix_nand_init(struct nand_chip *chip) 70062306a36Sopenharmony_ci{ 70162306a36Sopenharmony_ci struct hynix_nand *hynix; 70262306a36Sopenharmony_ci int ret; 70362306a36Sopenharmony_ci 70462306a36Sopenharmony_ci if (!nand_is_slc(chip)) 70562306a36Sopenharmony_ci chip->options |= NAND_BBM_LASTPAGE; 70662306a36Sopenharmony_ci else 70762306a36Sopenharmony_ci chip->options |= NAND_BBM_FIRSTPAGE | NAND_BBM_SECONDPAGE; 70862306a36Sopenharmony_ci 70962306a36Sopenharmony_ci hynix = kzalloc(sizeof(*hynix), GFP_KERNEL); 71062306a36Sopenharmony_ci if (!hynix) 71162306a36Sopenharmony_ci return -ENOMEM; 71262306a36Sopenharmony_ci 71362306a36Sopenharmony_ci nand_set_manufacturer_data(chip, hynix); 71462306a36Sopenharmony_ci 71562306a36Sopenharmony_ci if (!strncmp("H27UCG8T2ATR-BC", chip->parameters.model, 71662306a36Sopenharmony_ci sizeof("H27UCG8T2ATR-BC") - 1)) 71762306a36Sopenharmony_ci chip->ops.choose_interface_config = 71862306a36Sopenharmony_ci h27ucg8t2atrbc_choose_interface_config; 71962306a36Sopenharmony_ci 72062306a36Sopenharmony_ci if (!strncmp("H27UCG8T2ETR-BC", chip->parameters.model, 72162306a36Sopenharmony_ci sizeof("H27UCG8T2ETR-BC") - 1)) 72262306a36Sopenharmony_ci h27ucg8t2etrbc_init(chip); 72362306a36Sopenharmony_ci 72462306a36Sopenharmony_ci ret = hynix_nand_rr_init(chip); 72562306a36Sopenharmony_ci if (ret) 72662306a36Sopenharmony_ci hynix_nand_cleanup(chip); 72762306a36Sopenharmony_ci 72862306a36Sopenharmony_ci return ret; 72962306a36Sopenharmony_ci} 73062306a36Sopenharmony_ci 73162306a36Sopenharmony_cistatic void hynix_fixup_onfi_param_page(struct nand_chip *chip, 73262306a36Sopenharmony_ci struct nand_onfi_params *p) 73362306a36Sopenharmony_ci{ 73462306a36Sopenharmony_ci /* 73562306a36Sopenharmony_ci * Certain chips might report a 0 on sdr_timing_mode field 73662306a36Sopenharmony_ci * (bytes 129-130). This has been seen on H27U4G8F2GDA-BI. 73762306a36Sopenharmony_ci * According to ONFI specification, bit 0 of this field "shall be 1". 73862306a36Sopenharmony_ci * Forcibly set this bit. 73962306a36Sopenharmony_ci */ 74062306a36Sopenharmony_ci p->sdr_timing_modes |= cpu_to_le16(BIT(0)); 74162306a36Sopenharmony_ci} 74262306a36Sopenharmony_ci 74362306a36Sopenharmony_ciconst struct nand_manufacturer_ops hynix_nand_manuf_ops = { 74462306a36Sopenharmony_ci .detect = hynix_nand_decode_id, 74562306a36Sopenharmony_ci .init = hynix_nand_init, 74662306a36Sopenharmony_ci .cleanup = hynix_nand_cleanup, 74762306a36Sopenharmony_ci .fixup_onfi_param_page = hynix_fixup_onfi_param_page, 74862306a36Sopenharmony_ci}; 749