Skip to content

Commit cad3193

Browse files
mwalleambarus
authored andcommitted
mtd: spi-nor: implement OTP support for Winbond and similar flashes
Use the new OTP ops to implement OTP access on Winbond flashes. Most Winbond flashes provides up to four different OTP regions ("Security Registers"). Winbond devices use a special opcode to read and write to the OTP regions, just like the RDSFDP opcode. In fact, it seems that the (undocumented) first OTP area of the newer flashes is the actual SFDP table. On a side note, Winbond devices also allow erasing the OTP regions as long as the area isn't locked down. Signed-off-by: Michael Walle <michael@walle.cc> Signed-off-by: Tudor Ambarus <tudor.ambarus@microchip.com> Link: https://lore.kernel.org/r/20210321235140.8308-3-michael@walle.cc
1 parent 069089a commit cad3193

4 files changed

Lines changed: 179 additions & 1 deletion

File tree

drivers/mtd/spi-nor/core.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1034,7 +1034,7 @@ static int spi_nor_write_16bit_sr_and_check(struct spi_nor *nor, u8 sr1)
10341034
*
10351035
* Return: 0 on success, -errno otherwise.
10361036
*/
1037-
static int spi_nor_write_16bit_cr_and_check(struct spi_nor *nor, u8 cr)
1037+
int spi_nor_write_16bit_cr_and_check(struct spi_nor *nor, u8 cr)
10381038
{
10391039
int ret;
10401040
u8 *sr_cr = nor->bouncebuf;

drivers/mtd/spi-nor/core.h

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -495,13 +495,19 @@ int spi_nor_read_sr(struct spi_nor *nor, u8 *sr);
495495
int spi_nor_read_cr(struct spi_nor *nor, u8 *cr);
496496
int spi_nor_write_sr(struct spi_nor *nor, const u8 *sr, size_t len);
497497
int spi_nor_write_sr_and_check(struct spi_nor *nor, u8 sr1);
498+
int spi_nor_write_16bit_cr_and_check(struct spi_nor *nor, u8 cr);
498499

499500
int spi_nor_xread_sr(struct spi_nor *nor, u8 *sr);
500501
ssize_t spi_nor_read_data(struct spi_nor *nor, loff_t from, size_t len,
501502
u8 *buf);
502503
ssize_t spi_nor_write_data(struct spi_nor *nor, loff_t to, size_t len,
503504
const u8 *buf);
504505

506+
int spi_nor_otp_read_secr(struct spi_nor *nor, loff_t addr, size_t len, u8 *buf);
507+
int spi_nor_otp_write_secr(struct spi_nor *nor, loff_t addr, size_t len, u8 *buf);
508+
int spi_nor_otp_lock_sr2(struct spi_nor *nor, unsigned int region);
509+
int spi_nor_otp_is_locked_sr2(struct spi_nor *nor, unsigned int region);
510+
505511
int spi_nor_hwcaps_read2cmd(u32 hwcaps);
506512
u8 spi_nor_convert_3to4_read(u8 opcode);
507513
void spi_nor_set_read_settings(struct spi_nor_read_command *read,

drivers/mtd/spi-nor/otp.c

Lines changed: 164 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,170 @@
1414
#define spi_nor_otp_region_len(nor) ((nor)->params->otp.org->len)
1515
#define spi_nor_otp_n_regions(nor) ((nor)->params->otp.org->n_regions)
1616

17+
/**
18+
* spi_nor_otp_read_secr() - read OTP data
19+
* @nor: pointer to 'struct spi_nor'
20+
* @from: offset to read from
21+
* @len: number of bytes to read
22+
* @buf: pointer to dst buffer
23+
*
24+
* Read OTP data from one region by using the SPINOR_OP_RSECR commands. This
25+
* method is used on GigaDevice and Winbond flashes.
26+
*
27+
* Return: number of bytes read successfully, -errno otherwise
28+
*/
29+
int spi_nor_otp_read_secr(struct spi_nor *nor, loff_t addr, size_t len, u8 *buf)
30+
{
31+
u8 addr_width, read_opcode, read_dummy;
32+
struct spi_mem_dirmap_desc *rdesc;
33+
enum spi_nor_protocol read_proto;
34+
int ret;
35+
36+
read_opcode = nor->read_opcode;
37+
addr_width = nor->addr_width;
38+
read_dummy = nor->read_dummy;
39+
read_proto = nor->read_proto;
40+
rdesc = nor->dirmap.rdesc;
41+
42+
nor->read_opcode = SPINOR_OP_RSECR;
43+
nor->addr_width = 3;
44+
nor->read_dummy = 8;
45+
nor->read_proto = SNOR_PROTO_1_1_1;
46+
nor->dirmap.rdesc = NULL;
47+
48+
ret = spi_nor_read_data(nor, addr, len, buf);
49+
50+
nor->read_opcode = read_opcode;
51+
nor->addr_width = addr_width;
52+
nor->read_dummy = read_dummy;
53+
nor->read_proto = read_proto;
54+
nor->dirmap.rdesc = rdesc;
55+
56+
return ret;
57+
}
58+
59+
/**
60+
* spi_nor_otp_write_secr() - write OTP data
61+
* @nor: pointer to 'struct spi_nor'
62+
* @to: offset to write to
63+
* @len: number of bytes to write
64+
* @buf: pointer to src buffer
65+
*
66+
* Write OTP data to one region by using the SPINOR_OP_PSECR commands. This
67+
* method is used on GigaDevice and Winbond flashes.
68+
*
69+
* Please note, the write must not span multiple OTP regions.
70+
*
71+
* Return: number of bytes written successfully, -errno otherwise
72+
*/
73+
int spi_nor_otp_write_secr(struct spi_nor *nor, loff_t addr, size_t len, u8 *buf)
74+
{
75+
enum spi_nor_protocol write_proto;
76+
struct spi_mem_dirmap_desc *wdesc;
77+
u8 addr_width, program_opcode;
78+
int ret, written;
79+
80+
program_opcode = nor->program_opcode;
81+
addr_width = nor->addr_width;
82+
write_proto = nor->write_proto;
83+
wdesc = nor->dirmap.wdesc;
84+
85+
nor->program_opcode = SPINOR_OP_PSECR;
86+
nor->addr_width = 3;
87+
nor->write_proto = SNOR_PROTO_1_1_1;
88+
nor->dirmap.wdesc = NULL;
89+
90+
/*
91+
* We only support a write to one single page. For now all winbond
92+
* flashes only have one page per OTP region.
93+
*/
94+
ret = spi_nor_write_enable(nor);
95+
if (ret)
96+
goto out;
97+
98+
written = spi_nor_write_data(nor, addr, len, buf);
99+
if (written < 0)
100+
goto out;
101+
102+
ret = spi_nor_wait_till_ready(nor);
103+
104+
out:
105+
nor->program_opcode = program_opcode;
106+
nor->addr_width = addr_width;
107+
nor->write_proto = write_proto;
108+
nor->dirmap.wdesc = wdesc;
109+
110+
return ret ?: written;
111+
}
112+
113+
static int spi_nor_otp_lock_bit_cr(unsigned int region)
114+
{
115+
static const int lock_bits[] = { SR2_LB1, SR2_LB2, SR2_LB3 };
116+
117+
if (region >= ARRAY_SIZE(lock_bits))
118+
return -EINVAL;
119+
120+
return lock_bits[region];
121+
}
122+
123+
/**
124+
* spi_nor_otp_lock_sr2() - lock the OTP region
125+
* @nor: pointer to 'struct spi_nor'
126+
* @region: OTP region
127+
*
128+
* Lock the OTP region by writing the status register-2. This method is used on
129+
* GigaDevice and Winbond flashes.
130+
*
131+
* Return: 0 on success, -errno otherwise.
132+
*/
133+
int spi_nor_otp_lock_sr2(struct spi_nor *nor, unsigned int region)
134+
{
135+
u8 *cr = nor->bouncebuf;
136+
int ret, lock_bit;
137+
138+
lock_bit = spi_nor_otp_lock_bit_cr(region);
139+
if (lock_bit < 0)
140+
return lock_bit;
141+
142+
ret = spi_nor_read_cr(nor, cr);
143+
if (ret)
144+
return ret;
145+
146+
/* no need to write the register if region is already locked */
147+
if (cr[0] & lock_bit)
148+
return 0;
149+
150+
cr[0] |= lock_bit;
151+
152+
return spi_nor_write_16bit_cr_and_check(nor, cr[0]);
153+
}
154+
155+
/**
156+
* spi_nor_otp_is_locked_sr2() - get the OTP region lock status
157+
* @nor: pointer to 'struct spi_nor'
158+
* @region: OTP region
159+
*
160+
* Retrieve the OTP region lock bit by reading the status register-2. This
161+
* method is used on GigaDevice and Winbond flashes.
162+
*
163+
* Return: 0 on success, -errno otherwise.
164+
*/
165+
int spi_nor_otp_is_locked_sr2(struct spi_nor *nor, unsigned int region)
166+
{
167+
u8 *cr = nor->bouncebuf;
168+
int ret, lock_bit;
169+
170+
lock_bit = spi_nor_otp_lock_bit_cr(region);
171+
if (lock_bit < 0)
172+
return lock_bit;
173+
174+
ret = spi_nor_read_cr(nor, cr);
175+
if (ret)
176+
return ret;
177+
178+
return cr[0] & lock_bit;
179+
}
180+
17181
static loff_t spi_nor_otp_region_start(const struct spi_nor *nor, unsigned int region)
18182
{
19183
const struct spi_nor_otp_organization *org = nor->params->otp.org;

include/linux/mtd/spi-nor.h

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -107,6 +107,11 @@
107107
#define SPINOR_OP_RD_EVCR 0x65 /* Read EVCR register */
108108
#define SPINOR_OP_WD_EVCR 0x61 /* Write EVCR register */
109109

110+
/* Used for GigaDevices and Winbond flashes. */
111+
#define SPINOR_OP_ESECR 0x44 /* Erase Security registers */
112+
#define SPINOR_OP_PSECR 0x42 /* Program Security registers */
113+
#define SPINOR_OP_RSECR 0x48 /* Read Security registers */
114+
110115
/* Status Register bits. */
111116
#define SR_WIP BIT(0) /* Write in progress */
112117
#define SR_WEL BIT(1) /* Write enable latch */
@@ -138,6 +143,9 @@
138143

139144
/* Status Register 2 bits. */
140145
#define SR2_QUAD_EN_BIT1 BIT(1)
146+
#define SR2_LB1 BIT(3) /* Security Register Lock Bit 1 */
147+
#define SR2_LB2 BIT(4) /* Security Register Lock Bit 2 */
148+
#define SR2_LB3 BIT(5) /* Security Register Lock Bit 3 */
141149
#define SR2_QUAD_EN_BIT7 BIT(7)
142150

143151
/* Supported SPI protocols */

0 commit comments

Comments
 (0)