brintos

brintos / linux-shallow public Read only

0
0
Text · 12.1 KiB · 9a729aa Raw
508 lines · c
1// SPDX-License-Identifier: GPL-2.02/*3 * OTP support for SPI NOR flashes4 *5 * Copyright (C) 2021 Michael Walle <michael@walle.cc>6 */7 8#include <linux/log2.h>9#include <linux/mtd/mtd.h>10#include <linux/mtd/spi-nor.h>11 12#include "core.h"13 14#define spi_nor_otp_region_len(nor) ((nor)->params->otp.org->len)15#define spi_nor_otp_n_regions(nor) ((nor)->params->otp.org->n_regions)16 17/**18 * spi_nor_otp_read_secr() - read security register19 * @nor:	pointer to 'struct spi_nor'20 * @addr:       offset to read from21 * @len:        number of bytes to read22 * @buf:        pointer to dst buffer23 *24 * Read a security register by using the SPINOR_OP_RSECR commands.25 *26 * In Winbond/GigaDevice datasheets the term "security register" stands for27 * an one-time-programmable memory area, consisting of multiple bytes (usually28 * 256). Thus one "security register" maps to one OTP region.29 *30 * This method is used on GigaDevice and Winbond flashes.31 *32 * Please note, the read must not span multiple registers.33 *34 * Return: number of bytes read successfully, -errno otherwise35 */36int spi_nor_otp_read_secr(struct spi_nor *nor, loff_t addr, size_t len, u8 *buf)37{38	u8 addr_nbytes, read_opcode, read_dummy;39	struct spi_mem_dirmap_desc *rdesc;40	enum spi_nor_protocol read_proto;41	int ret;42 43	read_opcode = nor->read_opcode;44	addr_nbytes = nor->addr_nbytes;45	read_dummy = nor->read_dummy;46	read_proto = nor->read_proto;47	rdesc = nor->dirmap.rdesc;48 49	nor->read_opcode = SPINOR_OP_RSECR;50	nor->read_dummy = 8;51	nor->read_proto = SNOR_PROTO_1_1_1;52	nor->dirmap.rdesc = NULL;53 54	ret = spi_nor_read_data(nor, addr, len, buf);55 56	nor->read_opcode = read_opcode;57	nor->addr_nbytes = addr_nbytes;58	nor->read_dummy = read_dummy;59	nor->read_proto = read_proto;60	nor->dirmap.rdesc = rdesc;61 62	return ret;63}64 65/**66 * spi_nor_otp_write_secr() - write security register67 * @nor:        pointer to 'struct spi_nor'68 * @addr:       offset to write to69 * @len:        number of bytes to write70 * @buf:        pointer to src buffer71 *72 * Write a security register by using the SPINOR_OP_PSECR commands.73 *74 * For more information on the term "security register", see the documentation75 * of spi_nor_otp_read_secr().76 *77 * This method is used on GigaDevice and Winbond flashes.78 *79 * Please note, the write must not span multiple registers.80 *81 * Return: number of bytes written successfully, -errno otherwise82 */83int spi_nor_otp_write_secr(struct spi_nor *nor, loff_t addr, size_t len,84			   const u8 *buf)85{86	enum spi_nor_protocol write_proto;87	struct spi_mem_dirmap_desc *wdesc;88	u8 addr_nbytes, program_opcode;89	int ret, written;90 91	program_opcode = nor->program_opcode;92	addr_nbytes = nor->addr_nbytes;93	write_proto = nor->write_proto;94	wdesc = nor->dirmap.wdesc;95 96	nor->program_opcode = SPINOR_OP_PSECR;97	nor->write_proto = SNOR_PROTO_1_1_1;98	nor->dirmap.wdesc = NULL;99 100	/*101	 * We only support a write to one single page. For now all winbond102	 * flashes only have one page per security register.103	 */104	ret = spi_nor_write_enable(nor);105	if (ret)106		goto out;107 108	written = spi_nor_write_data(nor, addr, len, buf);109	if (written < 0)110		goto out;111 112	ret = spi_nor_wait_till_ready(nor);113 114out:115	nor->program_opcode = program_opcode;116	nor->addr_nbytes = addr_nbytes;117	nor->write_proto = write_proto;118	nor->dirmap.wdesc = wdesc;119 120	return ret ?: written;121}122 123/**124 * spi_nor_otp_erase_secr() - erase a security register125 * @nor:        pointer to 'struct spi_nor'126 * @addr:       offset of the security register to be erased127 *128 * Erase a security register by using the SPINOR_OP_ESECR command.129 *130 * For more information on the term "security register", see the documentation131 * of spi_nor_otp_read_secr().132 *133 * This method is used on GigaDevice and Winbond flashes.134 *135 * Return: 0 on success, -errno otherwise136 */137int spi_nor_otp_erase_secr(struct spi_nor *nor, loff_t addr)138{139	u8 erase_opcode = nor->erase_opcode;140	int ret;141 142	ret = spi_nor_write_enable(nor);143	if (ret)144		return ret;145 146	nor->erase_opcode = SPINOR_OP_ESECR;147	ret = spi_nor_erase_sector(nor, addr);148	nor->erase_opcode = erase_opcode;149	if (ret)150		return ret;151 152	return spi_nor_wait_till_ready(nor);153}154 155static int spi_nor_otp_lock_bit_cr(unsigned int region)156{157	static const int lock_bits[] = { SR2_LB1, SR2_LB2, SR2_LB3 };158 159	if (region >= ARRAY_SIZE(lock_bits))160		return -EINVAL;161 162	return lock_bits[region];163}164 165/**166 * spi_nor_otp_lock_sr2() - lock the OTP region167 * @nor:        pointer to 'struct spi_nor'168 * @region:     OTP region169 *170 * Lock the OTP region by writing the status register-2. This method is used on171 * GigaDevice and Winbond flashes.172 *173 * Return: 0 on success, -errno otherwise.174 */175int spi_nor_otp_lock_sr2(struct spi_nor *nor, unsigned int region)176{177	u8 *cr = nor->bouncebuf;178	int ret, lock_bit;179 180	lock_bit = spi_nor_otp_lock_bit_cr(region);181	if (lock_bit < 0)182		return lock_bit;183 184	ret = spi_nor_read_cr(nor, cr);185	if (ret)186		return ret;187 188	/* no need to write the register if region is already locked */189	if (cr[0] & lock_bit)190		return 0;191 192	cr[0] |= lock_bit;193 194	return spi_nor_write_16bit_cr_and_check(nor, cr[0]);195}196 197/**198 * spi_nor_otp_is_locked_sr2() - get the OTP region lock status199 * @nor:        pointer to 'struct spi_nor'200 * @region:     OTP region201 *202 * Retrieve the OTP region lock bit by reading the status register-2. This203 * method is used on GigaDevice and Winbond flashes.204 *205 * Return: 0 on success, -errno otherwise.206 */207int spi_nor_otp_is_locked_sr2(struct spi_nor *nor, unsigned int region)208{209	u8 *cr = nor->bouncebuf;210	int ret, lock_bit;211 212	lock_bit = spi_nor_otp_lock_bit_cr(region);213	if (lock_bit < 0)214		return lock_bit;215 216	ret = spi_nor_read_cr(nor, cr);217	if (ret)218		return ret;219 220	return cr[0] & lock_bit;221}222 223static loff_t spi_nor_otp_region_start(const struct spi_nor *nor, unsigned int region)224{225	const struct spi_nor_otp_organization *org = nor->params->otp.org;226 227	return org->base + region * org->offset;228}229 230static size_t spi_nor_otp_size(struct spi_nor *nor)231{232	return spi_nor_otp_n_regions(nor) * spi_nor_otp_region_len(nor);233}234 235/* Translate the file offsets from and to OTP regions. */236static loff_t spi_nor_otp_region_to_offset(struct spi_nor *nor, unsigned int region)237{238	return region * spi_nor_otp_region_len(nor);239}240 241static unsigned int spi_nor_otp_offset_to_region(struct spi_nor *nor, loff_t ofs)242{243	return div64_u64(ofs, spi_nor_otp_region_len(nor));244}245 246static int spi_nor_mtd_otp_info(struct mtd_info *mtd, size_t len,247				size_t *retlen, struct otp_info *buf)248{249	struct spi_nor *nor = mtd_to_spi_nor(mtd);250	const struct spi_nor_otp_ops *ops = nor->params->otp.ops;251	unsigned int n_regions = spi_nor_otp_n_regions(nor);252	unsigned int i;253	int ret, locked;254 255	if (len < n_regions * sizeof(*buf))256		return -ENOSPC;257 258	ret = spi_nor_prep_and_lock(nor);259	if (ret)260		return ret;261 262	for (i = 0; i < n_regions; i++) {263		buf->start = spi_nor_otp_region_to_offset(nor, i);264		buf->length = spi_nor_otp_region_len(nor);265 266		locked = ops->is_locked(nor, i);267		if (locked < 0) {268			ret = locked;269			goto out;270		}271 272		buf->locked = !!locked;273		buf++;274	}275 276	*retlen = n_regions * sizeof(*buf);277 278out:279	spi_nor_unlock_and_unprep(nor);280 281	return ret;282}283 284static int spi_nor_mtd_otp_range_is_locked(struct spi_nor *nor, loff_t ofs,285					   size_t len)286{287	const struct spi_nor_otp_ops *ops = nor->params->otp.ops;288	unsigned int region;289	int locked;290 291	/*292	 * If any of the affected OTP regions are locked the entire range is293	 * considered locked.294	 */295	for (region = spi_nor_otp_offset_to_region(nor, ofs);296	     region <= spi_nor_otp_offset_to_region(nor, ofs + len - 1);297	     region++) {298		locked = ops->is_locked(nor, region);299		/* take the branch it is locked or in case of an error */300		if (locked)301			return locked;302	}303 304	return 0;305}306 307static int spi_nor_mtd_otp_read_write(struct mtd_info *mtd, loff_t ofs,308				      size_t total_len, size_t *retlen,309				      const u8 *buf, bool is_write)310{311	struct spi_nor *nor = mtd_to_spi_nor(mtd);312	const struct spi_nor_otp_ops *ops = nor->params->otp.ops;313	const size_t rlen = spi_nor_otp_region_len(nor);314	loff_t rstart, rofs;315	unsigned int region;316	size_t len;317	int ret;318 319	if (ofs < 0 || ofs >= spi_nor_otp_size(nor))320		return 0;321 322	/* don't access beyond the end */323	total_len = min_t(size_t, total_len, spi_nor_otp_size(nor) - ofs);324 325	if (!total_len)326		return 0;327 328	ret = spi_nor_prep_and_lock(nor);329	if (ret)330		return ret;331 332	if (is_write) {333		ret = spi_nor_mtd_otp_range_is_locked(nor, ofs, total_len);334		if (ret < 0) {335			goto out;336		} else if (ret) {337			ret = -EROFS;338			goto out;339		}340	}341 342	while (total_len) {343		/*344		 * The OTP regions are mapped into a contiguous area starting345		 * at 0 as expected by the MTD layer. This will map the MTD346		 * file offsets to the address of an OTP region as used in the347		 * actual SPI commands.348		 */349		region = spi_nor_otp_offset_to_region(nor, ofs);350		rstart = spi_nor_otp_region_start(nor, region);351 352		/*353		 * The size of a OTP region is expected to be a power of two,354		 * thus we can just mask the lower bits and get the offset into355		 * a region.356		 */357		rofs = ofs & (rlen - 1);358 359		/* don't access beyond one OTP region */360		len = min_t(size_t, total_len, rlen - rofs);361 362		if (is_write)363			ret = ops->write(nor, rstart + rofs, len, buf);364		else365			ret = ops->read(nor, rstart + rofs, len, (u8 *)buf);366		if (ret == 0)367			ret = -EIO;368		if (ret < 0)369			goto out;370 371		*retlen += ret;372		ofs += ret;373		buf += ret;374		total_len -= ret;375	}376	ret = 0;377 378out:379	spi_nor_unlock_and_unprep(nor);380	return ret;381}382 383static int spi_nor_mtd_otp_read(struct mtd_info *mtd, loff_t from, size_t len,384				size_t *retlen, u8 *buf)385{386	return spi_nor_mtd_otp_read_write(mtd, from, len, retlen, buf, false);387}388 389static int spi_nor_mtd_otp_write(struct mtd_info *mtd, loff_t to, size_t len,390				 size_t *retlen, const u8 *buf)391{392	return spi_nor_mtd_otp_read_write(mtd, to, len, retlen, buf, true);393}394 395static int spi_nor_mtd_otp_erase(struct mtd_info *mtd, loff_t from, size_t len)396{397	struct spi_nor *nor = mtd_to_spi_nor(mtd);398	const struct spi_nor_otp_ops *ops = nor->params->otp.ops;399	const size_t rlen = spi_nor_otp_region_len(nor);400	unsigned int region;401	loff_t rstart;402	int ret;403 404	/* OTP erase is optional */405	if (!ops->erase)406		return -EOPNOTSUPP;407 408	if (!len)409		return 0;410 411	if (from < 0 || (from + len) > spi_nor_otp_size(nor))412		return -EINVAL;413 414	/* the user has to explicitly ask for whole regions */415	if (!IS_ALIGNED(len, rlen) || !IS_ALIGNED(from, rlen))416		return -EINVAL;417 418	ret = spi_nor_prep_and_lock(nor);419	if (ret)420		return ret;421 422	ret = spi_nor_mtd_otp_range_is_locked(nor, from, len);423	if (ret < 0) {424		goto out;425	} else if (ret) {426		ret = -EROFS;427		goto out;428	}429 430	while (len) {431		region = spi_nor_otp_offset_to_region(nor, from);432		rstart = spi_nor_otp_region_start(nor, region);433 434		ret = ops->erase(nor, rstart);435		if (ret)436			goto out;437 438		len -= rlen;439		from += rlen;440	}441 442out:443	spi_nor_unlock_and_unprep(nor);444 445	return ret;446}447 448static int spi_nor_mtd_otp_lock(struct mtd_info *mtd, loff_t from, size_t len)449{450	struct spi_nor *nor = mtd_to_spi_nor(mtd);451	const struct spi_nor_otp_ops *ops = nor->params->otp.ops;452	const size_t rlen = spi_nor_otp_region_len(nor);453	unsigned int region;454	int ret;455 456	if (from < 0 || (from + len) > spi_nor_otp_size(nor))457		return -EINVAL;458 459	/* the user has to explicitly ask for whole regions */460	if (!IS_ALIGNED(len, rlen) || !IS_ALIGNED(from, rlen))461		return -EINVAL;462 463	ret = spi_nor_prep_and_lock(nor);464	if (ret)465		return ret;466 467	while (len) {468		region = spi_nor_otp_offset_to_region(nor, from);469		ret = ops->lock(nor, region);470		if (ret)471			goto out;472 473		len -= rlen;474		from += rlen;475	}476 477out:478	spi_nor_unlock_and_unprep(nor);479 480	return ret;481}482 483void spi_nor_set_mtd_otp_ops(struct spi_nor *nor)484{485	struct mtd_info *mtd = &nor->mtd;486 487	if (!nor->params->otp.ops)488		return;489 490	if (WARN_ON(!is_power_of_2(spi_nor_otp_region_len(nor))))491		return;492 493	/*494	 * We only support user_prot callbacks (yet).495	 *496	 * Some SPI NOR flashes like Macronix ones can be ordered in two497	 * different variants. One with a factory locked OTP area and one where498	 * it is left to the user to write to it. The factory locked OTP is499	 * usually preprogrammed with an "electrical serial number". We don't500	 * support these for now.501	 */502	mtd->_get_user_prot_info = spi_nor_mtd_otp_info;503	mtd->_read_user_prot_reg = spi_nor_mtd_otp_read;504	mtd->_write_user_prot_reg = spi_nor_mtd_otp_write;505	mtd->_lock_user_prot_reg = spi_nor_mtd_otp_lock;506	mtd->_erase_user_prot_reg = spi_nor_mtd_otp_erase;507}508