Skip to content

Commit a3b219e

Browse files
m-kurbanovmiquelraynal
authored andcommitted
mtd: spinand: esmt: OTP access for F50{L,D}1G41LB
Support for OTP area access on ESMT F50L1G41LB and F50D1G41LB chips. Signed-off-by: Martin Kurbanov <[email protected]> Signed-off-by: Miquel Raynal <[email protected]>
1 parent b741d3f commit a3b219e

File tree

1 file changed

+88
-2
lines changed

1 file changed

+88
-2
lines changed

drivers/mtd/nand/spi/esmt.c

Lines changed: 88 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -8,10 +8,15 @@
88
#include <linux/device.h>
99
#include <linux/kernel.h>
1010
#include <linux/mtd/spinand.h>
11+
#include <linux/spi/spi-mem.h>
1112

1213
/* ESMT uses GigaDevice 0xc8 JECDEC ID on some SPI NANDs */
1314
#define SPINAND_MFR_ESMT_C8 0xc8
1415

16+
#define ESMT_F50L1G41LB_CFG_OTP_PROTECT BIT(7)
17+
#define ESMT_F50L1G41LB_CFG_OTP_LOCK \
18+
(CFG_OTP_ENABLE | ESMT_F50L1G41LB_CFG_OTP_PROTECT)
19+
1520
static SPINAND_OP_VARIANTS(read_cache_variants,
1621
SPINAND_PAGE_READ_FROM_CACHE_X4_OP(0, 1, NULL, 0),
1722
SPINAND_PAGE_READ_FROM_CACHE_X2_OP(0, 1, NULL, 0),
@@ -102,6 +107,83 @@ static const struct mtd_ooblayout_ops f50l1g41lb_ooblayout = {
102107
.free = f50l1g41lb_ooblayout_free,
103108
};
104109

110+
static int f50l1g41lb_otp_info(struct spinand_device *spinand, size_t len,
111+
struct otp_info *buf, size_t *retlen, bool user)
112+
{
113+
if (len < sizeof(*buf))
114+
return -EINVAL;
115+
116+
buf->locked = 0;
117+
buf->start = 0;
118+
buf->length = user ? spinand_user_otp_size(spinand) :
119+
spinand_fact_otp_size(spinand);
120+
121+
*retlen = sizeof(*buf);
122+
return 0;
123+
}
124+
125+
static int f50l1g41lb_fact_otp_info(struct spinand_device *spinand, size_t len,
126+
struct otp_info *buf, size_t *retlen)
127+
{
128+
return f50l1g41lb_otp_info(spinand, len, buf, retlen, false);
129+
}
130+
131+
static int f50l1g41lb_user_otp_info(struct spinand_device *spinand, size_t len,
132+
struct otp_info *buf, size_t *retlen)
133+
{
134+
return f50l1g41lb_otp_info(spinand, len, buf, retlen, true);
135+
}
136+
137+
static int f50l1g41lb_otp_lock(struct spinand_device *spinand, loff_t from,
138+
size_t len)
139+
{
140+
struct spi_mem_op write_op = SPINAND_WR_EN_DIS_OP(true);
141+
struct spi_mem_op exec_op = SPINAND_PROG_EXEC_OP(0);
142+
u8 status;
143+
int ret;
144+
145+
ret = spinand_upd_cfg(spinand, ESMT_F50L1G41LB_CFG_OTP_LOCK,
146+
ESMT_F50L1G41LB_CFG_OTP_LOCK);
147+
if (!ret)
148+
return ret;
149+
150+
ret = spi_mem_exec_op(spinand->spimem, &write_op);
151+
if (!ret)
152+
goto out;
153+
154+
ret = spi_mem_exec_op(spinand->spimem, &exec_op);
155+
if (!ret)
156+
goto out;
157+
158+
ret = spinand_wait(spinand,
159+
SPINAND_WRITE_INITIAL_DELAY_US,
160+
SPINAND_WRITE_POLL_DELAY_US,
161+
&status);
162+
if (!ret && (status & STATUS_PROG_FAILED))
163+
ret = -EIO;
164+
165+
out:
166+
if (spinand_upd_cfg(spinand, ESMT_F50L1G41LB_CFG_OTP_LOCK, 0)) {
167+
dev_warn(&spinand_to_mtd(spinand)->dev,
168+
"Can not disable OTP mode\n");
169+
ret = -EIO;
170+
}
171+
172+
return ret;
173+
}
174+
175+
static const struct spinand_user_otp_ops f50l1g41lb_user_otp_ops = {
176+
.info = f50l1g41lb_user_otp_info,
177+
.lock = f50l1g41lb_otp_lock,
178+
.read = spinand_user_otp_read,
179+
.write = spinand_user_otp_write,
180+
};
181+
182+
static const struct spinand_fact_otp_ops f50l1g41lb_fact_otp_ops = {
183+
.info = f50l1g41lb_fact_otp_info,
184+
.read = spinand_fact_otp_read,
185+
};
186+
105187
static const struct spinand_info esmt_c8_spinand_table[] = {
106188
SPINAND_INFO("F50L1G41LB",
107189
SPINAND_ID(SPINAND_READID_METHOD_OPCODE_ADDR, 0x01, 0x7f,
@@ -112,7 +194,9 @@ static const struct spinand_info esmt_c8_spinand_table[] = {
112194
&write_cache_variants,
113195
&update_cache_variants),
114196
0,
115-
SPINAND_ECCINFO(&f50l1g41lb_ooblayout, NULL)),
197+
SPINAND_ECCINFO(&f50l1g41lb_ooblayout, NULL),
198+
SPINAND_USER_OTP_INFO(28, 2, &f50l1g41lb_user_otp_ops),
199+
SPINAND_FACT_OTP_INFO(2, 0, &f50l1g41lb_fact_otp_ops)),
116200
SPINAND_INFO("F50D1G41LB",
117201
SPINAND_ID(SPINAND_READID_METHOD_OPCODE_ADDR, 0x11, 0x7f,
118202
0x7f, 0x7f),
@@ -122,7 +206,9 @@ static const struct spinand_info esmt_c8_spinand_table[] = {
122206
&write_cache_variants,
123207
&update_cache_variants),
124208
0,
125-
SPINAND_ECCINFO(&f50l1g41lb_ooblayout, NULL)),
209+
SPINAND_ECCINFO(&f50l1g41lb_ooblayout, NULL),
210+
SPINAND_USER_OTP_INFO(28, 2, &f50l1g41lb_user_otp_ops),
211+
SPINAND_FACT_OTP_INFO(2, 0, &f50l1g41lb_fact_otp_ops)),
126212
SPINAND_INFO("F50D2G41KA",
127213
SPINAND_ID(SPINAND_READID_METHOD_OPCODE_ADDR, 0x51, 0x7f,
128214
0x7f, 0x7f),

0 commit comments

Comments
 (0)