1 // SPDX-License-Identifier: GPL-2.0
2 /*
3  * Copyright (c) 2025, SaluteDevices. All Rights Reserved.
4  *
5  * Author: Martin Kurbanov <mmkurbanov@salutedevices.com>
6  */
7 
8 #include <linux/mtd/mtd.h>
9 #include <linux/mtd/spinand.h>
10 
11 /**
12  * spinand_otp_page_size() - Get SPI-NAND OTP page size
13  * @spinand: the spinand device
14  *
15  * Return: the OTP page size.
16  */
spinand_otp_page_size(struct spinand_device * spinand)17 size_t spinand_otp_page_size(struct spinand_device *spinand)
18 {
19 	struct nand_device *nand = spinand_to_nand(spinand);
20 
21 	return nanddev_page_size(nand) + nanddev_per_page_oobsize(nand);
22 }
23 
spinand_otp_size(struct spinand_device * spinand,const struct spinand_otp_layout * layout)24 static size_t spinand_otp_size(struct spinand_device *spinand,
25 			       const struct spinand_otp_layout *layout)
26 {
27 	return layout->npages * spinand_otp_page_size(spinand);
28 }
29 
30 /**
31  * spinand_fact_otp_size() - Get SPI-NAND factory OTP area size
32  * @spinand: the spinand device
33  *
34  * Return: the OTP size.
35  */
spinand_fact_otp_size(struct spinand_device * spinand)36 size_t spinand_fact_otp_size(struct spinand_device *spinand)
37 {
38 	return spinand_otp_size(spinand, &spinand->fact_otp->layout);
39 }
40 
41 /**
42  * spinand_user_otp_size() - Get SPI-NAND user OTP area size
43  * @spinand: the spinand device
44  *
45  * Return: the OTP size.
46  */
spinand_user_otp_size(struct spinand_device * spinand)47 size_t spinand_user_otp_size(struct spinand_device *spinand)
48 {
49 	return spinand_otp_size(spinand, &spinand->user_otp->layout);
50 }
51 
spinand_otp_check_bounds(struct spinand_device * spinand,loff_t ofs,size_t len,const struct spinand_otp_layout * layout)52 static int spinand_otp_check_bounds(struct spinand_device *spinand, loff_t ofs,
53 				    size_t len,
54 				    const struct spinand_otp_layout *layout)
55 {
56 	if (ofs < 0 || ofs + len > spinand_otp_size(spinand, layout))
57 		return -EINVAL;
58 
59 	return 0;
60 }
61 
spinand_user_otp_check_bounds(struct spinand_device * spinand,loff_t ofs,size_t len)62 static int spinand_user_otp_check_bounds(struct spinand_device *spinand,
63 					 loff_t ofs, size_t len)
64 {
65 	return spinand_otp_check_bounds(spinand, ofs, len,
66 					&spinand->user_otp->layout);
67 }
68 
spinand_otp_rw(struct spinand_device * spinand,loff_t ofs,size_t len,size_t * retlen,u8 * buf,bool is_write,const struct spinand_otp_layout * layout)69 static int spinand_otp_rw(struct spinand_device *spinand, loff_t ofs,
70 			  size_t len, size_t *retlen, u8 *buf, bool is_write,
71 			  const struct spinand_otp_layout *layout)
72 {
73 	struct nand_page_io_req req = {};
74 	unsigned long long page;
75 	size_t copied = 0;
76 	size_t otp_pagesize = spinand_otp_page_size(spinand);
77 	int ret;
78 
79 	if (!len)
80 		return 0;
81 
82 	ret = spinand_otp_check_bounds(spinand, ofs, len, layout);
83 	if (ret)
84 		return ret;
85 
86 	ret = spinand_upd_cfg(spinand, CFG_OTP_ENABLE, CFG_OTP_ENABLE);
87 	if (ret)
88 		return ret;
89 
90 	page = ofs;
91 	req.dataoffs = do_div(page, otp_pagesize);
92 	req.pos.page = page + layout->start_page;
93 	req.type = is_write ? NAND_PAGE_WRITE : NAND_PAGE_READ;
94 	req.mode = MTD_OPS_RAW;
95 	req.databuf.in = buf;
96 
97 	while (copied < len) {
98 		req.datalen = min_t(unsigned int,
99 				    otp_pagesize - req.dataoffs,
100 				    len - copied);
101 
102 		if (is_write)
103 			ret = spinand_write_page(spinand, &req);
104 		else
105 			ret = spinand_read_page(spinand, &req);
106 
107 		if (ret < 0)
108 			break;
109 
110 		req.databuf.in += req.datalen;
111 		req.pos.page++;
112 		req.dataoffs = 0;
113 		copied += req.datalen;
114 	}
115 
116 	*retlen = copied;
117 
118 	if (spinand_upd_cfg(spinand, CFG_OTP_ENABLE, 0)) {
119 		dev_warn(&spinand_to_mtd(spinand)->dev,
120 			 "Can not disable OTP mode\n");
121 		ret = -EIO;
122 	}
123 
124 	return ret;
125 }
126 
127 /**
128  * spinand_fact_otp_read() - Read from OTP area
129  * @spinand: the spinand device
130  * @ofs: the offset to read
131  * @len: the number of data bytes to read
132  * @retlen: the pointer to variable to store the number of read bytes
133  * @buf: the buffer to store the read data
134  *
135  * Return: 0 on success, an error code otherwise.
136  */
spinand_fact_otp_read(struct spinand_device * spinand,loff_t ofs,size_t len,size_t * retlen,u8 * buf)137 int spinand_fact_otp_read(struct spinand_device *spinand, loff_t ofs,
138 			  size_t len, size_t *retlen, u8 *buf)
139 {
140 	return spinand_otp_rw(spinand, ofs, len, retlen, buf, false,
141 			      &spinand->fact_otp->layout);
142 }
143 
144 /**
145  * spinand_user_otp_read() - Read from OTP area
146  * @spinand: the spinand device
147  * @ofs: the offset to read
148  * @len: the number of data bytes to read
149  * @retlen: the pointer to variable to store the number of read bytes
150  * @buf: the buffer to store the read data
151  *
152  * Return: 0 on success, an error code otherwise.
153  */
spinand_user_otp_read(struct spinand_device * spinand,loff_t ofs,size_t len,size_t * retlen,u8 * buf)154 int spinand_user_otp_read(struct spinand_device *spinand, loff_t ofs,
155 			  size_t len, size_t *retlen, u8 *buf)
156 {
157 	return spinand_otp_rw(spinand, ofs, len, retlen, buf, false,
158 			      &spinand->user_otp->layout);
159 }
160 
161 /**
162  * spinand_user_otp_write() - Write to OTP area
163  * @spinand:  the spinand device
164  * @ofs: the offset to write to
165  * @len: the number of bytes to write
166  * @retlen: the pointer to variable to store the number of written bytes
167  * @buf: the buffer with data to write
168  *
169  * Return: 0 on success, an error code otherwise.
170  */
spinand_user_otp_write(struct spinand_device * spinand,loff_t ofs,size_t len,size_t * retlen,const u8 * buf)171 int spinand_user_otp_write(struct spinand_device *spinand, loff_t ofs,
172 			   size_t len, size_t *retlen, const u8 *buf)
173 {
174 	return spinand_otp_rw(spinand, ofs, len, retlen, (u8 *)buf, true,
175 			      &spinand->user_otp->layout);
176 }
177 
spinand_mtd_otp_info(struct mtd_info * mtd,size_t len,size_t * retlen,struct otp_info * buf,bool is_fact)178 static int spinand_mtd_otp_info(struct mtd_info *mtd, size_t len,
179 				size_t *retlen, struct otp_info *buf,
180 				bool is_fact)
181 {
182 	struct spinand_device *spinand = mtd_to_spinand(mtd);
183 	int ret;
184 
185 	*retlen = 0;
186 
187 	mutex_lock(&spinand->lock);
188 
189 	if (is_fact)
190 		ret = spinand->fact_otp->ops->info(spinand, len, buf, retlen);
191 	else
192 		ret = spinand->user_otp->ops->info(spinand, len, buf, retlen);
193 
194 	mutex_unlock(&spinand->lock);
195 
196 	return ret;
197 }
198 
spinand_mtd_fact_otp_info(struct mtd_info * mtd,size_t len,size_t * retlen,struct otp_info * buf)199 static int spinand_mtd_fact_otp_info(struct mtd_info *mtd, size_t len,
200 				     size_t *retlen, struct otp_info *buf)
201 {
202 	return spinand_mtd_otp_info(mtd, len, retlen, buf, true);
203 }
204 
spinand_mtd_user_otp_info(struct mtd_info * mtd,size_t len,size_t * retlen,struct otp_info * buf)205 static int spinand_mtd_user_otp_info(struct mtd_info *mtd, size_t len,
206 				     size_t *retlen, struct otp_info *buf)
207 {
208 	return spinand_mtd_otp_info(mtd, len, retlen, buf, false);
209 }
210 
spinand_mtd_otp_read(struct mtd_info * mtd,loff_t ofs,size_t len,size_t * retlen,u8 * buf,bool is_fact)211 static int spinand_mtd_otp_read(struct mtd_info *mtd, loff_t ofs, size_t len,
212 				size_t *retlen, u8 *buf, bool is_fact)
213 {
214 	struct spinand_device *spinand = mtd_to_spinand(mtd);
215 	int ret;
216 
217 	*retlen = 0;
218 
219 	if (!len)
220 		return 0;
221 
222 	ret = spinand_otp_check_bounds(spinand, ofs, len,
223 				       is_fact ? &spinand->fact_otp->layout :
224 						 &spinand->user_otp->layout);
225 	if (ret)
226 		return ret;
227 
228 	mutex_lock(&spinand->lock);
229 
230 	if (is_fact)
231 		ret = spinand->fact_otp->ops->read(spinand, ofs, len, retlen,
232 						   buf);
233 	else
234 		ret = spinand->user_otp->ops->read(spinand, ofs, len, retlen,
235 						   buf);
236 
237 	mutex_unlock(&spinand->lock);
238 
239 	return ret;
240 }
241 
spinand_mtd_fact_otp_read(struct mtd_info * mtd,loff_t ofs,size_t len,size_t * retlen,u8 * buf)242 static int spinand_mtd_fact_otp_read(struct mtd_info *mtd, loff_t ofs,
243 				     size_t len, size_t *retlen, u8 *buf)
244 {
245 	return spinand_mtd_otp_read(mtd, ofs, len, retlen, buf, true);
246 }
247 
spinand_mtd_user_otp_read(struct mtd_info * mtd,loff_t ofs,size_t len,size_t * retlen,u8 * buf)248 static int spinand_mtd_user_otp_read(struct mtd_info *mtd, loff_t ofs,
249 				     size_t len, size_t *retlen, u8 *buf)
250 {
251 	return spinand_mtd_otp_read(mtd, ofs, len, retlen, buf, false);
252 }
253 
spinand_mtd_user_otp_write(struct mtd_info * mtd,loff_t ofs,size_t len,size_t * retlen,const u8 * buf)254 static int spinand_mtd_user_otp_write(struct mtd_info *mtd, loff_t ofs,
255 				      size_t len, size_t *retlen, const u8 *buf)
256 {
257 	struct spinand_device *spinand = mtd_to_spinand(mtd);
258 	const struct spinand_user_otp_ops *ops = spinand->user_otp->ops;
259 	int ret;
260 
261 	*retlen = 0;
262 
263 	if (!len)
264 		return 0;
265 
266 	ret = spinand_user_otp_check_bounds(spinand, ofs, len);
267 	if (ret)
268 		return ret;
269 
270 	mutex_lock(&spinand->lock);
271 	ret = ops->write(spinand, ofs, len, retlen, buf);
272 	mutex_unlock(&spinand->lock);
273 
274 	return ret;
275 }
276 
spinand_mtd_user_otp_erase(struct mtd_info * mtd,loff_t ofs,size_t len)277 static int spinand_mtd_user_otp_erase(struct mtd_info *mtd, loff_t ofs,
278 				      size_t len)
279 {
280 	struct spinand_device *spinand = mtd_to_spinand(mtd);
281 	const struct spinand_user_otp_ops *ops = spinand->user_otp->ops;
282 	int ret;
283 
284 	if (!len)
285 		return 0;
286 
287 	ret = spinand_user_otp_check_bounds(spinand, ofs, len);
288 	if (ret)
289 		return ret;
290 
291 	mutex_lock(&spinand->lock);
292 	ret = ops->erase(spinand, ofs, len);
293 	mutex_unlock(&spinand->lock);
294 
295 	return ret;
296 }
297 
spinand_mtd_user_otp_lock(struct mtd_info * mtd,loff_t ofs,size_t len)298 static int spinand_mtd_user_otp_lock(struct mtd_info *mtd, loff_t ofs,
299 				     size_t len)
300 {
301 	struct spinand_device *spinand = mtd_to_spinand(mtd);
302 	const struct spinand_user_otp_ops *ops = spinand->user_otp->ops;
303 	int ret;
304 
305 	if (!len)
306 		return 0;
307 
308 	ret = spinand_user_otp_check_bounds(spinand, ofs, len);
309 	if (ret)
310 		return ret;
311 
312 	mutex_lock(&spinand->lock);
313 	ret = ops->lock(spinand, ofs, len);
314 	mutex_unlock(&spinand->lock);
315 
316 	return ret;
317 }
318 
319 /**
320  * spinand_set_mtd_otp_ops() - Setup OTP methods
321  * @spinand: the spinand device
322  *
323  * Setup OTP methods.
324  *
325  * Return: 0 on success, a negative error code otherwise.
326  */
spinand_set_mtd_otp_ops(struct spinand_device * spinand)327 int spinand_set_mtd_otp_ops(struct spinand_device *spinand)
328 {
329 	struct mtd_info *mtd = spinand_to_mtd(spinand);
330 	const struct spinand_fact_otp_ops *fact_ops = spinand->fact_otp->ops;
331 	const struct spinand_user_otp_ops *user_ops = spinand->user_otp->ops;
332 
333 	if (!user_ops && !fact_ops)
334 		return -EINVAL;
335 
336 	if (user_ops) {
337 		if (user_ops->info)
338 			mtd->_get_user_prot_info = spinand_mtd_user_otp_info;
339 
340 		if (user_ops->read)
341 			mtd->_read_user_prot_reg = spinand_mtd_user_otp_read;
342 
343 		if (user_ops->write)
344 			mtd->_write_user_prot_reg = spinand_mtd_user_otp_write;
345 
346 		if (user_ops->lock)
347 			mtd->_lock_user_prot_reg = spinand_mtd_user_otp_lock;
348 
349 		if (user_ops->erase)
350 			mtd->_erase_user_prot_reg = spinand_mtd_user_otp_erase;
351 	}
352 
353 	if (fact_ops) {
354 		if (fact_ops->info)
355 			mtd->_get_fact_prot_info = spinand_mtd_fact_otp_info;
356 
357 		if (fact_ops->read)
358 			mtd->_read_fact_prot_reg = spinand_mtd_fact_otp_read;
359 	}
360 
361 	return 0;
362 }
363