aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorChristian Riesch <christian.riesch@omicron.at>2014-03-06 07:18:30 -0500
committerBrian Norris <computersforpeace@gmail.com>2014-07-11 22:44:25 -0400
commit4f5cb243823b3a83864a8f51266aff6bc08436b3 (patch)
tree9afa64b970f452f25faa61a3c2a384d7849af056
parentaf7447505732ea729af6a99e76fc558b6e3fcbcd (diff)
mtd: cfi_cmdset_0002: Add support for locking OTP memory
This patch adds support for the locking of the one time programmable (OTP) memory of Micron M29EW devices. Signed-off-by: Christian Riesch <christian.riesch@omicron.at> Signed-off-by: Brian Norris <computersforpeace@gmail.com>
-rw-r--r--drivers/mtd/chips/cfi_cmdset_0002.c89
1 files changed, 84 insertions, 5 deletions
diff --git a/drivers/mtd/chips/cfi_cmdset_0002.c b/drivers/mtd/chips/cfi_cmdset_0002.c
index 6c575e65010b..bf313be6ee26 100644
--- a/drivers/mtd/chips/cfi_cmdset_0002.c
+++ b/drivers/mtd/chips/cfi_cmdset_0002.c
@@ -69,6 +69,7 @@ static int cfi_amdstd_read_user_prot_reg(struct mtd_info *, loff_t, size_t,
69 size_t *, u_char *); 69 size_t *, u_char *);
70static int cfi_amdstd_write_user_prot_reg(struct mtd_info *, loff_t, size_t, 70static int cfi_amdstd_write_user_prot_reg(struct mtd_info *, loff_t, size_t,
71 size_t *, u_char *); 71 size_t *, u_char *);
72static int cfi_amdstd_lock_user_prot_reg(struct mtd_info *, loff_t, size_t);
72 73
73static int cfi_amdstd_panic_write(struct mtd_info *mtd, loff_t to, size_t len, 74static int cfi_amdstd_panic_write(struct mtd_info *mtd, loff_t to, size_t len,
74 size_t *retlen, const u_char *buf); 75 size_t *retlen, const u_char *buf);
@@ -533,6 +534,7 @@ struct mtd_info *cfi_cmdset_0002(struct map_info *map, int primary)
533 mtd->_get_fact_prot_info = cfi_amdstd_get_fact_prot_info; 534 mtd->_get_fact_prot_info = cfi_amdstd_get_fact_prot_info;
534 mtd->_get_user_prot_info = cfi_amdstd_get_user_prot_info; 535 mtd->_get_user_prot_info = cfi_amdstd_get_user_prot_info;
535 mtd->_write_user_prot_reg = cfi_amdstd_write_user_prot_reg; 536 mtd->_write_user_prot_reg = cfi_amdstd_write_user_prot_reg;
537 mtd->_lock_user_prot_reg = cfi_amdstd_lock_user_prot_reg;
536 mtd->flags = MTD_CAP_NORFLASH; 538 mtd->flags = MTD_CAP_NORFLASH;
537 mtd->name = map->name; 539 mtd->name = map->name;
538 mtd->writesize = 1; 540 mtd->writesize = 1;
@@ -1153,7 +1155,7 @@ static int cfi_amdstd_read (struct mtd_info *mtd, loff_t from, size_t len, size_
1153} 1155}
1154 1156
1155typedef int (*otp_op_t)(struct map_info *map, struct flchip *chip, 1157typedef int (*otp_op_t)(struct map_info *map, struct flchip *chip,
1156 loff_t adr, size_t len, u_char *buf); 1158 loff_t adr, size_t len, u_char *buf, size_t grouplen);
1157 1159
1158static inline void otp_enter(struct map_info *map, struct flchip *chip, 1160static inline void otp_enter(struct map_info *map, struct flchip *chip,
1159 loff_t adr, size_t len) 1161 loff_t adr, size_t len)
@@ -1187,7 +1189,10 @@ static inline void otp_exit(struct map_info *map, struct flchip *chip,
1187 INVALIDATE_CACHED_RANGE(map, chip->start + adr, len); 1189 INVALIDATE_CACHED_RANGE(map, chip->start + adr, len);
1188} 1190}
1189 1191
1190static inline int do_read_secsi_onechip(struct map_info *map, struct flchip *chip, loff_t adr, size_t len, u_char *buf) 1192static inline int do_read_secsi_onechip(struct map_info *map,
1193 struct flchip *chip, loff_t adr,
1194 size_t len, u_char *buf,
1195 size_t grouplen)
1191{ 1196{
1192 DECLARE_WAITQUEUE(wait, current); 1197 DECLARE_WAITQUEUE(wait, current);
1193 unsigned long timeo = jiffies + HZ; 1198 unsigned long timeo = jiffies + HZ;
@@ -1246,7 +1251,8 @@ static int cfi_amdstd_secsi_read (struct mtd_info *mtd, loff_t from, size_t len,
1246 else 1251 else
1247 thislen = len; 1252 thislen = len;
1248 1253
1249 ret = do_read_secsi_onechip(map, &cfi->chips[chipnum], ofs, thislen, buf); 1254 ret = do_read_secsi_onechip(map, &cfi->chips[chipnum], ofs,
1255 thislen, buf, 0);
1250 if (ret) 1256 if (ret)
1251 break; 1257 break;
1252 1258
@@ -1265,7 +1271,7 @@ static int __xipram do_write_oneword(struct map_info *map, struct flchip *chip,
1265 int mode); 1271 int mode);
1266 1272
1267static int do_otp_write(struct map_info *map, struct flchip *chip, loff_t adr, 1273static int do_otp_write(struct map_info *map, struct flchip *chip, loff_t adr,
1268 size_t len, u_char *buf) 1274 size_t len, u_char *buf, size_t grouplen)
1269{ 1275{
1270 int ret; 1276 int ret;
1271 while (len) { 1277 while (len) {
@@ -1294,6 +1300,70 @@ static int do_otp_write(struct map_info *map, struct flchip *chip, loff_t adr,
1294 return 0; 1300 return 0;
1295} 1301}
1296 1302
1303static int do_otp_lock(struct map_info *map, struct flchip *chip, loff_t adr,
1304 size_t len, u_char *buf, size_t grouplen)
1305{
1306 struct cfi_private *cfi = map->fldrv_priv;
1307 uint8_t lockreg;
1308 unsigned long timeo;
1309 int ret;
1310
1311 /* make sure area matches group boundaries */
1312 if ((adr != 0) || (len != grouplen))
1313 return -EINVAL;
1314
1315 mutex_lock(&chip->mutex);
1316 ret = get_chip(map, chip, chip->start, FL_LOCKING);
1317 if (ret) {
1318 mutex_unlock(&chip->mutex);
1319 return ret;
1320 }
1321 chip->state = FL_LOCKING;
1322
1323 /* Enter lock register command */
1324 cfi_send_gen_cmd(0xAA, cfi->addr_unlock1, chip->start, map, cfi,
1325 cfi->device_type, NULL);
1326 cfi_send_gen_cmd(0x55, cfi->addr_unlock2, chip->start, map, cfi,
1327 cfi->device_type, NULL);
1328 cfi_send_gen_cmd(0x40, cfi->addr_unlock1, chip->start, map, cfi,
1329 cfi->device_type, NULL);
1330
1331 /* read lock register */
1332 lockreg = cfi_read_query(map, 0);
1333
1334 /* set bit 0 to protect extended memory block */
1335 lockreg &= ~0x01;
1336
1337 /* set bit 0 to protect extended memory block */
1338 /* write lock register */
1339 map_write(map, CMD(0xA0), chip->start);
1340 map_write(map, CMD(lockreg), chip->start);
1341
1342 /* wait for chip to become ready */
1343 timeo = jiffies + msecs_to_jiffies(2);
1344 for (;;) {
1345 if (chip_ready(map, adr))
1346 break;
1347
1348 if (time_after(jiffies, timeo)) {
1349 pr_err("Waiting for chip to be ready timed out.\n");
1350 ret = -EIO;
1351 break;
1352 }
1353 UDELAY(map, chip, 0, 1);
1354 }
1355
1356 /* exit protection commands */
1357 map_write(map, CMD(0x90), chip->start);
1358 map_write(map, CMD(0x00), chip->start);
1359
1360 chip->state = FL_READY;
1361 put_chip(map, chip, chip->start);
1362 mutex_unlock(&chip->mutex);
1363
1364 return ret;
1365}
1366
1297static int cfi_amdstd_otp_walk(struct mtd_info *mtd, loff_t from, size_t len, 1367static int cfi_amdstd_otp_walk(struct mtd_info *mtd, loff_t from, size_t len,
1298 size_t *retlen, u_char *buf, 1368 size_t *retlen, u_char *buf,
1299 otp_op_t action, int user_regs) 1369 otp_op_t action, int user_regs)
@@ -1392,7 +1462,8 @@ static int cfi_amdstd_otp_walk(struct mtd_info *mtd, loff_t from, size_t len,
1392 } else if ((from < otpsize) && (len > 0)) { 1462 } else if ((from < otpsize) && (len > 0)) {
1393 size_t size; 1463 size_t size;
1394 size = (len < otpsize - from) ? len : otpsize - from; 1464 size = (len < otpsize - from) ? len : otpsize - from;
1395 ret = action(map, chip, otpoffset + from, size, buf); 1465 ret = action(map, chip, otpoffset + from, size, buf,
1466 otpsize);
1396 if (ret < 0) 1467 if (ret < 0)
1397 return ret; 1468 return ret;
1398 1469
@@ -1445,6 +1516,14 @@ static int cfi_amdstd_write_user_prot_reg(struct mtd_info *mtd, loff_t from,
1445 do_otp_write, 1); 1516 do_otp_write, 1);
1446} 1517}
1447 1518
1519static int cfi_amdstd_lock_user_prot_reg(struct mtd_info *mtd, loff_t from,
1520 size_t len)
1521{
1522 size_t retlen;
1523 return cfi_amdstd_otp_walk(mtd, from, len, &retlen, NULL,
1524 do_otp_lock, 1);
1525}
1526
1448static int __xipram do_write_oneword(struct map_info *map, struct flchip *chip, 1527static int __xipram do_write_oneword(struct map_info *map, struct flchip *chip,
1449 unsigned long adr, map_word datum, 1528 unsigned long adr, map_word datum,
1450 int mode) 1529 int mode)