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