xref: /openbmc/linux/drivers/mtd/spi-nor/otp.c (revision 069089ac)
1*069089acSMichael Walle // SPDX-License-Identifier: GPL-2.0
2*069089acSMichael Walle /*
3*069089acSMichael Walle  * OTP support for SPI NOR flashes
4*069089acSMichael Walle  *
5*069089acSMichael Walle  * Copyright (C) 2021 Michael Walle <michael@walle.cc>
6*069089acSMichael Walle  */
7*069089acSMichael Walle 
8*069089acSMichael Walle #include <linux/log2.h>
9*069089acSMichael Walle #include <linux/mtd/mtd.h>
10*069089acSMichael Walle #include <linux/mtd/spi-nor.h>
11*069089acSMichael Walle 
12*069089acSMichael Walle #include "core.h"
13*069089acSMichael Walle 
14*069089acSMichael Walle #define spi_nor_otp_region_len(nor) ((nor)->params->otp.org->len)
15*069089acSMichael Walle #define spi_nor_otp_n_regions(nor) ((nor)->params->otp.org->n_regions)
16*069089acSMichael Walle 
17*069089acSMichael Walle static loff_t spi_nor_otp_region_start(const struct spi_nor *nor, unsigned int region)
18*069089acSMichael Walle {
19*069089acSMichael Walle 	const struct spi_nor_otp_organization *org = nor->params->otp.org;
20*069089acSMichael Walle 
21*069089acSMichael Walle 	return org->base + region * org->offset;
22*069089acSMichael Walle }
23*069089acSMichael Walle 
24*069089acSMichael Walle static size_t spi_nor_otp_size(struct spi_nor *nor)
25*069089acSMichael Walle {
26*069089acSMichael Walle 	return spi_nor_otp_n_regions(nor) * spi_nor_otp_region_len(nor);
27*069089acSMichael Walle }
28*069089acSMichael Walle 
29*069089acSMichael Walle /* Translate the file offsets from and to OTP regions. */
30*069089acSMichael Walle static loff_t spi_nor_otp_region_to_offset(struct spi_nor *nor, unsigned int region)
31*069089acSMichael Walle {
32*069089acSMichael Walle 	return region * spi_nor_otp_region_len(nor);
33*069089acSMichael Walle }
34*069089acSMichael Walle 
35*069089acSMichael Walle static unsigned int spi_nor_otp_offset_to_region(struct spi_nor *nor, loff_t ofs)
36*069089acSMichael Walle {
37*069089acSMichael Walle 	return div64_u64(ofs, spi_nor_otp_region_len(nor));
38*069089acSMichael Walle }
39*069089acSMichael Walle 
40*069089acSMichael Walle static int spi_nor_mtd_otp_info(struct mtd_info *mtd, size_t len,
41*069089acSMichael Walle 				size_t *retlen, struct otp_info *buf)
42*069089acSMichael Walle {
43*069089acSMichael Walle 	struct spi_nor *nor = mtd_to_spi_nor(mtd);
44*069089acSMichael Walle 	const struct spi_nor_otp_ops *ops = nor->params->otp.ops;
45*069089acSMichael Walle 	unsigned int n_regions = spi_nor_otp_n_regions(nor);
46*069089acSMichael Walle 	unsigned int i;
47*069089acSMichael Walle 	int ret, locked;
48*069089acSMichael Walle 
49*069089acSMichael Walle 	if (len < n_regions * sizeof(*buf))
50*069089acSMichael Walle 		return -ENOSPC;
51*069089acSMichael Walle 
52*069089acSMichael Walle 	ret = spi_nor_lock_and_prep(nor);
53*069089acSMichael Walle 	if (ret)
54*069089acSMichael Walle 		return ret;
55*069089acSMichael Walle 
56*069089acSMichael Walle 	for (i = 0; i < n_regions; i++) {
57*069089acSMichael Walle 		buf->start = spi_nor_otp_region_to_offset(nor, i);
58*069089acSMichael Walle 		buf->length = spi_nor_otp_region_len(nor);
59*069089acSMichael Walle 
60*069089acSMichael Walle 		locked = ops->is_locked(nor, i);
61*069089acSMichael Walle 		if (locked < 0) {
62*069089acSMichael Walle 			ret = locked;
63*069089acSMichael Walle 			goto out;
64*069089acSMichael Walle 		}
65*069089acSMichael Walle 
66*069089acSMichael Walle 		buf->locked = !!locked;
67*069089acSMichael Walle 		buf++;
68*069089acSMichael Walle 	}
69*069089acSMichael Walle 
70*069089acSMichael Walle 	*retlen = n_regions * sizeof(*buf);
71*069089acSMichael Walle 
72*069089acSMichael Walle out:
73*069089acSMichael Walle 	spi_nor_unlock_and_unprep(nor);
74*069089acSMichael Walle 
75*069089acSMichael Walle 	return ret;
76*069089acSMichael Walle }
77*069089acSMichael Walle 
78*069089acSMichael Walle static int spi_nor_mtd_otp_read_write(struct mtd_info *mtd, loff_t ofs,
79*069089acSMichael Walle 				      size_t total_len, size_t *retlen,
80*069089acSMichael Walle 				      u8 *buf, bool is_write)
81*069089acSMichael Walle {
82*069089acSMichael Walle 	struct spi_nor *nor = mtd_to_spi_nor(mtd);
83*069089acSMichael Walle 	const struct spi_nor_otp_ops *ops = nor->params->otp.ops;
84*069089acSMichael Walle 	const size_t rlen = spi_nor_otp_region_len(nor);
85*069089acSMichael Walle 	loff_t rstart, rofs;
86*069089acSMichael Walle 	unsigned int region;
87*069089acSMichael Walle 	size_t len;
88*069089acSMichael Walle 	int ret;
89*069089acSMichael Walle 
90*069089acSMichael Walle 	if (ofs < 0 || ofs >= spi_nor_otp_size(nor))
91*069089acSMichael Walle 		return 0;
92*069089acSMichael Walle 
93*069089acSMichael Walle 	ret = spi_nor_lock_and_prep(nor);
94*069089acSMichael Walle 	if (ret)
95*069089acSMichael Walle 		return ret;
96*069089acSMichael Walle 
97*069089acSMichael Walle 	/* don't access beyond the end */
98*069089acSMichael Walle 	total_len = min_t(size_t, total_len, spi_nor_otp_size(nor) - ofs);
99*069089acSMichael Walle 
100*069089acSMichael Walle 	*retlen = 0;
101*069089acSMichael Walle 	while (total_len) {
102*069089acSMichael Walle 		/*
103*069089acSMichael Walle 		 * The OTP regions are mapped into a contiguous area starting
104*069089acSMichael Walle 		 * at 0 as expected by the MTD layer. This will map the MTD
105*069089acSMichael Walle 		 * file offsets to the address of an OTP region as used in the
106*069089acSMichael Walle 		 * actual SPI commands.
107*069089acSMichael Walle 		 */
108*069089acSMichael Walle 		region = spi_nor_otp_offset_to_region(nor, ofs);
109*069089acSMichael Walle 		rstart = spi_nor_otp_region_start(nor, region);
110*069089acSMichael Walle 
111*069089acSMichael Walle 		/*
112*069089acSMichael Walle 		 * The size of a OTP region is expected to be a power of two,
113*069089acSMichael Walle 		 * thus we can just mask the lower bits and get the offset into
114*069089acSMichael Walle 		 * a region.
115*069089acSMichael Walle 		 */
116*069089acSMichael Walle 		rofs = ofs & (rlen - 1);
117*069089acSMichael Walle 
118*069089acSMichael Walle 		/* don't access beyond one OTP region */
119*069089acSMichael Walle 		len = min_t(size_t, total_len, rlen - rofs);
120*069089acSMichael Walle 
121*069089acSMichael Walle 		if (is_write)
122*069089acSMichael Walle 			ret = ops->write(nor, rstart + rofs, len, buf);
123*069089acSMichael Walle 		else
124*069089acSMichael Walle 			ret = ops->read(nor, rstart + rofs, len, buf);
125*069089acSMichael Walle 		if (ret == 0)
126*069089acSMichael Walle 			ret = -EIO;
127*069089acSMichael Walle 		if (ret < 0)
128*069089acSMichael Walle 			goto out;
129*069089acSMichael Walle 
130*069089acSMichael Walle 		*retlen += ret;
131*069089acSMichael Walle 		ofs += ret;
132*069089acSMichael Walle 		buf += ret;
133*069089acSMichael Walle 		total_len -= ret;
134*069089acSMichael Walle 	}
135*069089acSMichael Walle 	ret = 0;
136*069089acSMichael Walle 
137*069089acSMichael Walle out:
138*069089acSMichael Walle 	spi_nor_unlock_and_unprep(nor);
139*069089acSMichael Walle 	return ret;
140*069089acSMichael Walle }
141*069089acSMichael Walle 
142*069089acSMichael Walle static int spi_nor_mtd_otp_read(struct mtd_info *mtd, loff_t from, size_t len,
143*069089acSMichael Walle 				size_t *retlen, u8 *buf)
144*069089acSMichael Walle {
145*069089acSMichael Walle 	return spi_nor_mtd_otp_read_write(mtd, from, len, retlen, buf, false);
146*069089acSMichael Walle }
147*069089acSMichael Walle 
148*069089acSMichael Walle static int spi_nor_mtd_otp_write(struct mtd_info *mtd, loff_t to, size_t len,
149*069089acSMichael Walle 				 size_t *retlen, u8 *buf)
150*069089acSMichael Walle {
151*069089acSMichael Walle 	return spi_nor_mtd_otp_read_write(mtd, to, len, retlen, buf, true);
152*069089acSMichael Walle }
153*069089acSMichael Walle 
154*069089acSMichael Walle static int spi_nor_mtd_otp_lock(struct mtd_info *mtd, loff_t from, size_t len)
155*069089acSMichael Walle {
156*069089acSMichael Walle 	struct spi_nor *nor = mtd_to_spi_nor(mtd);
157*069089acSMichael Walle 	const struct spi_nor_otp_ops *ops = nor->params->otp.ops;
158*069089acSMichael Walle 	const size_t rlen = spi_nor_otp_region_len(nor);
159*069089acSMichael Walle 	unsigned int region;
160*069089acSMichael Walle 	int ret;
161*069089acSMichael Walle 
162*069089acSMichael Walle 	if (from < 0 || (from + len) > spi_nor_otp_size(nor))
163*069089acSMichael Walle 		return -EINVAL;
164*069089acSMichael Walle 
165*069089acSMichael Walle 	/* the user has to explicitly ask for whole regions */
166*069089acSMichael Walle 	if (!IS_ALIGNED(len, rlen) || !IS_ALIGNED(from, rlen))
167*069089acSMichael Walle 		return -EINVAL;
168*069089acSMichael Walle 
169*069089acSMichael Walle 	ret = spi_nor_lock_and_prep(nor);
170*069089acSMichael Walle 	if (ret)
171*069089acSMichael Walle 		return ret;
172*069089acSMichael Walle 
173*069089acSMichael Walle 	while (len) {
174*069089acSMichael Walle 		region = spi_nor_otp_offset_to_region(nor, from);
175*069089acSMichael Walle 		ret = ops->lock(nor, region);
176*069089acSMichael Walle 		if (ret)
177*069089acSMichael Walle 			goto out;
178*069089acSMichael Walle 
179*069089acSMichael Walle 		len -= rlen;
180*069089acSMichael Walle 		from += rlen;
181*069089acSMichael Walle 	}
182*069089acSMichael Walle 
183*069089acSMichael Walle out:
184*069089acSMichael Walle 	spi_nor_unlock_and_unprep(nor);
185*069089acSMichael Walle 
186*069089acSMichael Walle 	return ret;
187*069089acSMichael Walle }
188*069089acSMichael Walle 
189*069089acSMichael Walle void spi_nor_otp_init(struct spi_nor *nor)
190*069089acSMichael Walle {
191*069089acSMichael Walle 	struct mtd_info *mtd = &nor->mtd;
192*069089acSMichael Walle 
193*069089acSMichael Walle 	if (!nor->params->otp.ops)
194*069089acSMichael Walle 		return;
195*069089acSMichael Walle 
196*069089acSMichael Walle 	if (WARN_ON(!is_power_of_2(spi_nor_otp_region_len(nor))))
197*069089acSMichael Walle 		return;
198*069089acSMichael Walle 
199*069089acSMichael Walle 	/*
200*069089acSMichael Walle 	 * We only support user_prot callbacks (yet).
201*069089acSMichael Walle 	 *
202*069089acSMichael Walle 	 * Some SPI NOR flashes like Macronix ones can be ordered in two
203*069089acSMichael Walle 	 * different variants. One with a factory locked OTP area and one where
204*069089acSMichael Walle 	 * it is left to the user to write to it. The factory locked OTP is
205*069089acSMichael Walle 	 * usually preprogrammed with an "electrical serial number". We don't
206*069089acSMichael Walle 	 * support these for now.
207*069089acSMichael Walle 	 */
208*069089acSMichael Walle 	mtd->_get_user_prot_info = spi_nor_mtd_otp_info;
209*069089acSMichael Walle 	mtd->_read_user_prot_reg = spi_nor_mtd_otp_read;
210*069089acSMichael Walle 	mtd->_write_user_prot_reg = spi_nor_mtd_otp_write;
211*069089acSMichael Walle 	mtd->_lock_user_prot_reg = spi_nor_mtd_otp_lock;
212*069089acSMichael Walle }
213