brintos

brintos / linux-shallow public Read only

0
0
Text · 8.6 KiB · 861975e Raw
340 lines · c
1// SPDX-License-Identifier: GPL-2.02/*3 *  Copyright (C) 2000 Steven J. Hill (sjhill@realitydiluted.com)4 *		  2002-2006 Thomas Gleixner (tglx@linutronix.de)5 *6 *  Credits:7 *	David Woodhouse for adding multichip support8 *9 *	Aleph One Ltd. and Toby Churchill Ltd. for supporting the10 *	rework for 2K page size chips11 *12 * This file contains all ONFI helpers.13 */14 15#include <linux/slab.h>16 17#include "internals.h"18 19#define ONFI_PARAM_PAGES 320 21u16 onfi_crc16(u16 crc, u8 const *p, size_t len)22{23	int i;24	while (len--) {25		crc ^= *p++ << 8;26		for (i = 0; i < 8; i++)27			crc = (crc << 1) ^ ((crc & 0x8000) ? 0x8005 : 0);28	}29 30	return crc;31}32 33/* Parse the Extended Parameter Page. */34static int nand_flash_detect_ext_param_page(struct nand_chip *chip,35					    struct nand_onfi_params *p)36{37	struct nand_device *base = &chip->base;38	struct nand_ecc_props requirements;39	struct onfi_ext_param_page *ep;40	struct onfi_ext_section *s;41	struct onfi_ext_ecc_info *ecc;42	uint8_t *cursor;43	int ret;44	int len;45	int i;46 47	len = le16_to_cpu(p->ext_param_page_length) * 16;48	ep = kmalloc(len, GFP_KERNEL);49	if (!ep)50		return -ENOMEM;51 52	/*53	 * Use the Change Read Column command to skip the ONFI param pages and54	 * ensure we read at the right location.55	 */56	ret = nand_change_read_column_op(chip,57					 sizeof(*p) * p->num_of_param_pages,58					 ep, len, true);59	if (ret)60		goto ext_out;61 62	ret = -EINVAL;63	if ((onfi_crc16(ONFI_CRC_BASE, ((uint8_t *)ep) + 2, len - 2)64		!= le16_to_cpu(ep->crc))) {65		pr_debug("fail in the CRC.\n");66		goto ext_out;67	}68 69	/*70	 * Check the signature.71	 * Do not strictly follow the ONFI spec, maybe changed in future.72	 */73	if (strncmp(ep->sig, "EPPS", 4)) {74		pr_debug("The signature is invalid.\n");75		goto ext_out;76	}77 78	/* find the ECC section. */79	cursor = (uint8_t *)(ep + 1);80	for (i = 0; i < ONFI_EXT_SECTION_MAX; i++) {81		s = ep->sections + i;82		if (s->type == ONFI_SECTION_TYPE_2)83			break;84		cursor += s->length * 16;85	}86	if (i == ONFI_EXT_SECTION_MAX) {87		pr_debug("We can not find the ECC section.\n");88		goto ext_out;89	}90 91	/* get the info we want. */92	ecc = (struct onfi_ext_ecc_info *)cursor;93 94	if (!ecc->codeword_size) {95		pr_debug("Invalid codeword size\n");96		goto ext_out;97	}98 99	requirements.strength = ecc->ecc_bits;100	requirements.step_size = 1 << ecc->codeword_size;101	nanddev_set_ecc_requirements(base, &requirements);102 103	ret = 0;104 105ext_out:106	kfree(ep);107	return ret;108}109 110/*111 * Recover data with bit-wise majority112 */113static void nand_bit_wise_majority(const void **srcbufs,114				   unsigned int nsrcbufs,115				   void *dstbuf,116				   unsigned int bufsize)117{118	int i, j, k;119 120	for (i = 0; i < bufsize; i++) {121		u8 val = 0;122 123		for (j = 0; j < 8; j++) {124			unsigned int cnt = 0;125 126			for (k = 0; k < nsrcbufs; k++) {127				const u8 *srcbuf = srcbufs[k];128 129				if (srcbuf[i] & BIT(j))130					cnt++;131			}132 133			if (cnt > nsrcbufs / 2)134				val |= BIT(j);135		}136 137		((u8 *)dstbuf)[i] = val;138	}139}140 141/*142 * Check if the NAND chip is ONFI compliant, returns 1 if it is, 0 otherwise.143 */144int nand_onfi_detect(struct nand_chip *chip)145{146	struct nand_device *base = &chip->base;147	struct mtd_info *mtd = nand_to_mtd(chip);148	struct nand_memory_organization *memorg;149	struct nand_onfi_params *p = NULL, *pbuf;150	struct onfi_params *onfi;151	bool use_datain = false;152	int onfi_version = 0;153	char id[4];154	int i, ret, val;155	u16 crc;156 157	memorg = nanddev_get_memorg(&chip->base);158 159	/* Try ONFI for unknown chip or LP */160	ret = nand_readid_op(chip, 0x20, id, sizeof(id));161	if (ret || strncmp(id, "ONFI", 4))162		return 0;163 164	/* ONFI chip: allocate a buffer to hold its parameter page */165	pbuf = kzalloc((sizeof(*pbuf) * ONFI_PARAM_PAGES), GFP_KERNEL);166	if (!pbuf)167		return -ENOMEM;168 169	if (!nand_has_exec_op(chip) || chip->controller->supported_op.data_only_read)170		use_datain = true;171 172	for (i = 0; i < ONFI_PARAM_PAGES; i++) {173		if (!i)174			ret = nand_read_param_page_op(chip, 0, &pbuf[i],175						      sizeof(*pbuf));176		else if (use_datain)177			ret = nand_read_data_op(chip, &pbuf[i], sizeof(*pbuf),178						true, false);179		else180			ret = nand_change_read_column_op(chip, sizeof(*pbuf) * i,181							 &pbuf[i], sizeof(*pbuf),182							 true);183		if (ret) {184			ret = 0;185			goto free_onfi_param_page;186		}187 188		crc = onfi_crc16(ONFI_CRC_BASE, (u8 *)&pbuf[i], 254);189		if (crc == le16_to_cpu(pbuf[i].crc)) {190			p = &pbuf[i];191			break;192		}193	}194 195	if (i == ONFI_PARAM_PAGES) {196		const void *srcbufs[ONFI_PARAM_PAGES];197		unsigned int j;198 199		for (j = 0; j < ONFI_PARAM_PAGES; j++)200			srcbufs[j] = pbuf + j;201 202		pr_warn("Could not find a valid ONFI parameter page, trying bit-wise majority to recover it\n");203		nand_bit_wise_majority(srcbufs, ONFI_PARAM_PAGES, pbuf,204				       sizeof(*pbuf));205 206		crc = onfi_crc16(ONFI_CRC_BASE, (u8 *)pbuf, 254);207		if (crc != le16_to_cpu(pbuf->crc)) {208			pr_err("ONFI parameter recovery failed, aborting\n");209			goto free_onfi_param_page;210		}211		p = pbuf;212	}213 214	if (chip->manufacturer.desc && chip->manufacturer.desc->ops &&215	    chip->manufacturer.desc->ops->fixup_onfi_param_page)216		chip->manufacturer.desc->ops->fixup_onfi_param_page(chip, p);217 218	/* Check version */219	val = le16_to_cpu(p->revision);220	if (val & ONFI_VERSION_2_3)221		onfi_version = 23;222	else if (val & ONFI_VERSION_2_2)223		onfi_version = 22;224	else if (val & ONFI_VERSION_2_1)225		onfi_version = 21;226	else if (val & ONFI_VERSION_2_0)227		onfi_version = 20;228	else if (val & ONFI_VERSION_1_0)229		onfi_version = 10;230 231	if (!onfi_version) {232		pr_info("unsupported ONFI version: %d\n", val);233		goto free_onfi_param_page;234	}235 236	sanitize_string(p->manufacturer, sizeof(p->manufacturer));237	sanitize_string(p->model, sizeof(p->model));238	chip->parameters.model = kstrdup(p->model, GFP_KERNEL);239	if (!chip->parameters.model) {240		ret = -ENOMEM;241		goto free_onfi_param_page;242	}243 244	memorg->pagesize = le32_to_cpu(p->byte_per_page);245	mtd->writesize = memorg->pagesize;246 247	/*248	 * pages_per_block and blocks_per_lun may not be a power-of-2 size249	 * (don't ask me who thought of this...). MTD assumes that these250	 * dimensions will be power-of-2, so just truncate the remaining area.251	 */252	memorg->pages_per_eraseblock =253			1 << (fls(le32_to_cpu(p->pages_per_block)) - 1);254	mtd->erasesize = memorg->pages_per_eraseblock * memorg->pagesize;255 256	memorg->oobsize = le16_to_cpu(p->spare_bytes_per_page);257	mtd->oobsize = memorg->oobsize;258 259	memorg->luns_per_target = p->lun_count;260	memorg->planes_per_lun = 1 << p->interleaved_bits;261 262	/* See erasesize comment */263	memorg->eraseblocks_per_lun =264		1 << (fls(le32_to_cpu(p->blocks_per_lun)) - 1);265	memorg->max_bad_eraseblocks_per_lun = le32_to_cpu(p->blocks_per_lun);266	memorg->bits_per_cell = p->bits_per_cell;267 268	if (le16_to_cpu(p->features) & ONFI_FEATURE_16_BIT_BUS)269		chip->options |= NAND_BUSWIDTH_16;270 271	if (p->ecc_bits != 0xff) {272		struct nand_ecc_props requirements = {273			.strength = p->ecc_bits,274			.step_size = 512,275		};276 277		nanddev_set_ecc_requirements(base, &requirements);278	} else if (onfi_version >= 21 &&279		(le16_to_cpu(p->features) & ONFI_FEATURE_EXT_PARAM_PAGE)) {280 281		/*282		 * The nand_flash_detect_ext_param_page() uses the283		 * Change Read Column command which maybe not supported284		 * by the chip->legacy.cmdfunc. So try to update the285		 * chip->legacy.cmdfunc now. We do not replace user supplied286		 * command function.287		 */288		nand_legacy_adjust_cmdfunc(chip);289 290		/* The Extended Parameter Page is supported since ONFI 2.1. */291		if (nand_flash_detect_ext_param_page(chip, p))292			pr_warn("Failed to detect ONFI extended param page\n");293	} else {294		pr_warn("Could not retrieve ONFI ECC requirements\n");295	}296 297	/* Save some parameters from the parameter page for future use */298	if (le16_to_cpu(p->opt_cmd) & ONFI_OPT_CMD_SET_GET_FEATURES) {299		chip->parameters.supports_set_get_features = true;300		bitmap_set(chip->parameters.get_feature_list,301			   ONFI_FEATURE_ADDR_TIMING_MODE, 1);302		bitmap_set(chip->parameters.set_feature_list,303			   ONFI_FEATURE_ADDR_TIMING_MODE, 1);304	}305 306	if (le16_to_cpu(p->opt_cmd) & ONFI_OPT_CMD_READ_CACHE)307		chip->parameters.supports_read_cache = true;308 309	onfi = kzalloc(sizeof(*onfi), GFP_KERNEL);310	if (!onfi) {311		ret = -ENOMEM;312		goto free_model;313	}314 315	onfi->version = onfi_version;316	onfi->tPROG = le16_to_cpu(p->t_prog);317	onfi->tBERS = le16_to_cpu(p->t_bers);318	onfi->tR = le16_to_cpu(p->t_r);319	onfi->tCCS = le16_to_cpu(p->t_ccs);320	onfi->fast_tCAD = le16_to_cpu(p->nvddr_nvddr2_features) & BIT(0);321	onfi->sdr_timing_modes = le16_to_cpu(p->sdr_timing_modes);322	if (le16_to_cpu(p->features) & ONFI_FEATURE_NV_DDR)323		onfi->nvddr_timing_modes = le16_to_cpu(p->nvddr_timing_modes);324	onfi->vendor_revision = le16_to_cpu(p->vendor_revision);325	memcpy(onfi->vendor, p->vendor, sizeof(p->vendor));326	chip->parameters.onfi = onfi;327 328	/* Identification done, free the full ONFI parameter page and exit */329	kfree(pbuf);330 331	return 1;332 333free_model:334	kfree(chip->parameters.model);335free_onfi_param_page:336	kfree(pbuf);337 338	return ret;339}340