0001
0002
0003
0004
0005
0006
0007
0008 #include <linux/log2.h>
0009 #include <linux/mtd/mtd.h>
0010 #include <linux/mtd/spi-nor.h>
0011
0012 #include "core.h"
0013
0014 #define spi_nor_otp_region_len(nor) ((nor)->params->otp.org->len)
0015 #define spi_nor_otp_n_regions(nor) ((nor)->params->otp.org->n_regions)
0016
0017
0018
0019
0020
0021
0022
0023
0024
0025
0026
0027
0028
0029
0030
0031
0032
0033
0034
0035
0036 int spi_nor_otp_read_secr(struct spi_nor *nor, loff_t addr, size_t len, u8 *buf)
0037 {
0038 u8 addr_nbytes, read_opcode, read_dummy;
0039 struct spi_mem_dirmap_desc *rdesc;
0040 enum spi_nor_protocol read_proto;
0041 int ret;
0042
0043 read_opcode = nor->read_opcode;
0044 addr_nbytes = nor->addr_nbytes;
0045 read_dummy = nor->read_dummy;
0046 read_proto = nor->read_proto;
0047 rdesc = nor->dirmap.rdesc;
0048
0049 nor->read_opcode = SPINOR_OP_RSECR;
0050 nor->read_dummy = 8;
0051 nor->read_proto = SNOR_PROTO_1_1_1;
0052 nor->dirmap.rdesc = NULL;
0053
0054 ret = spi_nor_read_data(nor, addr, len, buf);
0055
0056 nor->read_opcode = read_opcode;
0057 nor->addr_nbytes = addr_nbytes;
0058 nor->read_dummy = read_dummy;
0059 nor->read_proto = read_proto;
0060 nor->dirmap.rdesc = rdesc;
0061
0062 return ret;
0063 }
0064
0065
0066
0067
0068
0069
0070
0071
0072
0073
0074
0075
0076
0077
0078
0079
0080
0081
0082
0083 int spi_nor_otp_write_secr(struct spi_nor *nor, loff_t addr, size_t len,
0084 const u8 *buf)
0085 {
0086 enum spi_nor_protocol write_proto;
0087 struct spi_mem_dirmap_desc *wdesc;
0088 u8 addr_nbytes, program_opcode;
0089 int ret, written;
0090
0091 program_opcode = nor->program_opcode;
0092 addr_nbytes = nor->addr_nbytes;
0093 write_proto = nor->write_proto;
0094 wdesc = nor->dirmap.wdesc;
0095
0096 nor->program_opcode = SPINOR_OP_PSECR;
0097 nor->write_proto = SNOR_PROTO_1_1_1;
0098 nor->dirmap.wdesc = NULL;
0099
0100
0101
0102
0103
0104 ret = spi_nor_write_enable(nor);
0105 if (ret)
0106 goto out;
0107
0108 written = spi_nor_write_data(nor, addr, len, buf);
0109 if (written < 0)
0110 goto out;
0111
0112 ret = spi_nor_wait_till_ready(nor);
0113
0114 out:
0115 nor->program_opcode = program_opcode;
0116 nor->addr_nbytes = addr_nbytes;
0117 nor->write_proto = write_proto;
0118 nor->dirmap.wdesc = wdesc;
0119
0120 return ret ?: written;
0121 }
0122
0123
0124
0125
0126
0127
0128
0129
0130
0131
0132
0133
0134
0135
0136
0137 int spi_nor_otp_erase_secr(struct spi_nor *nor, loff_t addr)
0138 {
0139 u8 erase_opcode = nor->erase_opcode;
0140 int ret;
0141
0142 ret = spi_nor_write_enable(nor);
0143 if (ret)
0144 return ret;
0145
0146 nor->erase_opcode = SPINOR_OP_ESECR;
0147 ret = spi_nor_erase_sector(nor, addr);
0148 nor->erase_opcode = erase_opcode;
0149 if (ret)
0150 return ret;
0151
0152 return spi_nor_wait_till_ready(nor);
0153 }
0154
0155 static int spi_nor_otp_lock_bit_cr(unsigned int region)
0156 {
0157 static const int lock_bits[] = { SR2_LB1, SR2_LB2, SR2_LB3 };
0158
0159 if (region >= ARRAY_SIZE(lock_bits))
0160 return -EINVAL;
0161
0162 return lock_bits[region];
0163 }
0164
0165
0166
0167
0168
0169
0170
0171
0172
0173
0174
0175 int spi_nor_otp_lock_sr2(struct spi_nor *nor, unsigned int region)
0176 {
0177 u8 *cr = nor->bouncebuf;
0178 int ret, lock_bit;
0179
0180 lock_bit = spi_nor_otp_lock_bit_cr(region);
0181 if (lock_bit < 0)
0182 return lock_bit;
0183
0184 ret = spi_nor_read_cr(nor, cr);
0185 if (ret)
0186 return ret;
0187
0188
0189 if (cr[0] & lock_bit)
0190 return 0;
0191
0192 cr[0] |= lock_bit;
0193
0194 return spi_nor_write_16bit_cr_and_check(nor, cr[0]);
0195 }
0196
0197
0198
0199
0200
0201
0202
0203
0204
0205
0206
0207 int spi_nor_otp_is_locked_sr2(struct spi_nor *nor, unsigned int region)
0208 {
0209 u8 *cr = nor->bouncebuf;
0210 int ret, lock_bit;
0211
0212 lock_bit = spi_nor_otp_lock_bit_cr(region);
0213 if (lock_bit < 0)
0214 return lock_bit;
0215
0216 ret = spi_nor_read_cr(nor, cr);
0217 if (ret)
0218 return ret;
0219
0220 return cr[0] & lock_bit;
0221 }
0222
0223 static loff_t spi_nor_otp_region_start(const struct spi_nor *nor, unsigned int region)
0224 {
0225 const struct spi_nor_otp_organization *org = nor->params->otp.org;
0226
0227 return org->base + region * org->offset;
0228 }
0229
0230 static size_t spi_nor_otp_size(struct spi_nor *nor)
0231 {
0232 return spi_nor_otp_n_regions(nor) * spi_nor_otp_region_len(nor);
0233 }
0234
0235
0236 static loff_t spi_nor_otp_region_to_offset(struct spi_nor *nor, unsigned int region)
0237 {
0238 return region * spi_nor_otp_region_len(nor);
0239 }
0240
0241 static unsigned int spi_nor_otp_offset_to_region(struct spi_nor *nor, loff_t ofs)
0242 {
0243 return div64_u64(ofs, spi_nor_otp_region_len(nor));
0244 }
0245
0246 static int spi_nor_mtd_otp_info(struct mtd_info *mtd, size_t len,
0247 size_t *retlen, struct otp_info *buf)
0248 {
0249 struct spi_nor *nor = mtd_to_spi_nor(mtd);
0250 const struct spi_nor_otp_ops *ops = nor->params->otp.ops;
0251 unsigned int n_regions = spi_nor_otp_n_regions(nor);
0252 unsigned int i;
0253 int ret, locked;
0254
0255 if (len < n_regions * sizeof(*buf))
0256 return -ENOSPC;
0257
0258 ret = spi_nor_lock_and_prep(nor);
0259 if (ret)
0260 return ret;
0261
0262 for (i = 0; i < n_regions; i++) {
0263 buf->start = spi_nor_otp_region_to_offset(nor, i);
0264 buf->length = spi_nor_otp_region_len(nor);
0265
0266 locked = ops->is_locked(nor, i);
0267 if (locked < 0) {
0268 ret = locked;
0269 goto out;
0270 }
0271
0272 buf->locked = !!locked;
0273 buf++;
0274 }
0275
0276 *retlen = n_regions * sizeof(*buf);
0277
0278 out:
0279 spi_nor_unlock_and_unprep(nor);
0280
0281 return ret;
0282 }
0283
0284 static int spi_nor_mtd_otp_range_is_locked(struct spi_nor *nor, loff_t ofs,
0285 size_t len)
0286 {
0287 const struct spi_nor_otp_ops *ops = nor->params->otp.ops;
0288 unsigned int region;
0289 int locked;
0290
0291
0292
0293
0294
0295 for (region = spi_nor_otp_offset_to_region(nor, ofs);
0296 region <= spi_nor_otp_offset_to_region(nor, ofs + len - 1);
0297 region++) {
0298 locked = ops->is_locked(nor, region);
0299
0300 if (locked)
0301 return locked;
0302 }
0303
0304 return 0;
0305 }
0306
0307 static int spi_nor_mtd_otp_read_write(struct mtd_info *mtd, loff_t ofs,
0308 size_t total_len, size_t *retlen,
0309 const u8 *buf, bool is_write)
0310 {
0311 struct spi_nor *nor = mtd_to_spi_nor(mtd);
0312 const struct spi_nor_otp_ops *ops = nor->params->otp.ops;
0313 const size_t rlen = spi_nor_otp_region_len(nor);
0314 loff_t rstart, rofs;
0315 unsigned int region;
0316 size_t len;
0317 int ret;
0318
0319 if (ofs < 0 || ofs >= spi_nor_otp_size(nor))
0320 return 0;
0321
0322
0323 total_len = min_t(size_t, total_len, spi_nor_otp_size(nor) - ofs);
0324
0325 if (!total_len)
0326 return 0;
0327
0328 ret = spi_nor_lock_and_prep(nor);
0329 if (ret)
0330 return ret;
0331
0332 if (is_write) {
0333 ret = spi_nor_mtd_otp_range_is_locked(nor, ofs, total_len);
0334 if (ret < 0) {
0335 goto out;
0336 } else if (ret) {
0337 ret = -EROFS;
0338 goto out;
0339 }
0340 }
0341
0342 while (total_len) {
0343
0344
0345
0346
0347
0348
0349 region = spi_nor_otp_offset_to_region(nor, ofs);
0350 rstart = spi_nor_otp_region_start(nor, region);
0351
0352
0353
0354
0355
0356
0357 rofs = ofs & (rlen - 1);
0358
0359
0360 len = min_t(size_t, total_len, rlen - rofs);
0361
0362 if (is_write)
0363 ret = ops->write(nor, rstart + rofs, len, buf);
0364 else
0365 ret = ops->read(nor, rstart + rofs, len, (u8 *)buf);
0366 if (ret == 0)
0367 ret = -EIO;
0368 if (ret < 0)
0369 goto out;
0370
0371 *retlen += ret;
0372 ofs += ret;
0373 buf += ret;
0374 total_len -= ret;
0375 }
0376 ret = 0;
0377
0378 out:
0379 spi_nor_unlock_and_unprep(nor);
0380 return ret;
0381 }
0382
0383 static int spi_nor_mtd_otp_read(struct mtd_info *mtd, loff_t from, size_t len,
0384 size_t *retlen, u8 *buf)
0385 {
0386 return spi_nor_mtd_otp_read_write(mtd, from, len, retlen, buf, false);
0387 }
0388
0389 static int spi_nor_mtd_otp_write(struct mtd_info *mtd, loff_t to, size_t len,
0390 size_t *retlen, const u8 *buf)
0391 {
0392 return spi_nor_mtd_otp_read_write(mtd, to, len, retlen, buf, true);
0393 }
0394
0395 static int spi_nor_mtd_otp_erase(struct mtd_info *mtd, loff_t from, size_t len)
0396 {
0397 struct spi_nor *nor = mtd_to_spi_nor(mtd);
0398 const struct spi_nor_otp_ops *ops = nor->params->otp.ops;
0399 const size_t rlen = spi_nor_otp_region_len(nor);
0400 unsigned int region;
0401 loff_t rstart;
0402 int ret;
0403
0404
0405 if (!ops->erase)
0406 return -EOPNOTSUPP;
0407
0408 if (!len)
0409 return 0;
0410
0411 if (from < 0 || (from + len) > spi_nor_otp_size(nor))
0412 return -EINVAL;
0413
0414
0415 if (!IS_ALIGNED(len, rlen) || !IS_ALIGNED(from, rlen))
0416 return -EINVAL;
0417
0418 ret = spi_nor_lock_and_prep(nor);
0419 if (ret)
0420 return ret;
0421
0422 ret = spi_nor_mtd_otp_range_is_locked(nor, from, len);
0423 if (ret < 0) {
0424 goto out;
0425 } else if (ret) {
0426 ret = -EROFS;
0427 goto out;
0428 }
0429
0430 while (len) {
0431 region = spi_nor_otp_offset_to_region(nor, from);
0432 rstart = spi_nor_otp_region_start(nor, region);
0433
0434 ret = ops->erase(nor, rstart);
0435 if (ret)
0436 goto out;
0437
0438 len -= rlen;
0439 from += rlen;
0440 }
0441
0442 out:
0443 spi_nor_unlock_and_unprep(nor);
0444
0445 return ret;
0446 }
0447
0448 static int spi_nor_mtd_otp_lock(struct mtd_info *mtd, loff_t from, size_t len)
0449 {
0450 struct spi_nor *nor = mtd_to_spi_nor(mtd);
0451 const struct spi_nor_otp_ops *ops = nor->params->otp.ops;
0452 const size_t rlen = spi_nor_otp_region_len(nor);
0453 unsigned int region;
0454 int ret;
0455
0456 if (from < 0 || (from + len) > spi_nor_otp_size(nor))
0457 return -EINVAL;
0458
0459
0460 if (!IS_ALIGNED(len, rlen) || !IS_ALIGNED(from, rlen))
0461 return -EINVAL;
0462
0463 ret = spi_nor_lock_and_prep(nor);
0464 if (ret)
0465 return ret;
0466
0467 while (len) {
0468 region = spi_nor_otp_offset_to_region(nor, from);
0469 ret = ops->lock(nor, region);
0470 if (ret)
0471 goto out;
0472
0473 len -= rlen;
0474 from += rlen;
0475 }
0476
0477 out:
0478 spi_nor_unlock_and_unprep(nor);
0479
0480 return ret;
0481 }
0482
0483 void spi_nor_set_mtd_otp_ops(struct spi_nor *nor)
0484 {
0485 struct mtd_info *mtd = &nor->mtd;
0486
0487 if (!nor->params->otp.ops)
0488 return;
0489
0490 if (WARN_ON(!is_power_of_2(spi_nor_otp_region_len(nor))))
0491 return;
0492
0493
0494
0495
0496
0497
0498
0499
0500
0501
0502 mtd->_get_user_prot_info = spi_nor_mtd_otp_info;
0503 mtd->_read_user_prot_reg = spi_nor_mtd_otp_read;
0504 mtd->_write_user_prot_reg = spi_nor_mtd_otp_write;
0505 mtd->_lock_user_prot_reg = spi_nor_mtd_otp_lock;
0506 mtd->_erase_user_prot_reg = spi_nor_mtd_otp_erase;
0507 }