Commit 34a82443 authored by David Brownell's avatar David Brownell Committed by David Woodhouse

[MTD] dataflash OTP support

Now that we can tell when we have one of the newer DataFlash chips,
optionally expose the 128 bytes of OTP memory they provide.  Tested
on at45db642 revision B and D chips.

Switch mtdchar over to a generic HAVE_MTD_OTP flag instead of adding
another #ifdef for each type of chip whose driver has OTP support.
Signed-off-by: default avatarDavid Brownell <dbrownell@users.sourceforge.net>
Cc: Bryan Wu <cooloney@kernel.org>
Cc: Michael Hennerich <michael.hennerich@analog.com>
Signed-off-by: default avatarAndrew Morton <akpm@linux-foundation.org>
Signed-off-by: default avatarDavid Woodhouse <David.Woodhouse@intel.com>
parent 623fa579
...@@ -172,6 +172,11 @@ config MTD_CHAR ...@@ -172,6 +172,11 @@ config MTD_CHAR
memory chips, and also use ioctl() to obtain information about memory chips, and also use ioctl() to obtain information about
the device, or to erase parts of it. the device, or to erase parts of it.
config HAVE_MTD_OTP
bool
help
Enable access to OTP regions using MTD_CHAR.
config MTD_BLKDEVS config MTD_BLKDEVS
tristate "Common interface to block layer for MTD 'translation layers'" tristate "Common interface to block layer for MTD 'translation layers'"
depends on BLOCK depends on BLOCK
......
...@@ -154,6 +154,7 @@ config MTD_CFI_I8 ...@@ -154,6 +154,7 @@ config MTD_CFI_I8
config MTD_OTP config MTD_OTP
bool "Protection Registers aka one-time programmable (OTP) bits" bool "Protection Registers aka one-time programmable (OTP) bits"
depends on MTD_CFI_ADV_OPTIONS depends on MTD_CFI_ADV_OPTIONS
select HAVE_MTD_OTP
default n default n
help help
This enables support for reading, writing and locking so called This enables support for reading, writing and locking so called
......
...@@ -59,6 +59,17 @@ config MTD_DATAFLASH ...@@ -59,6 +59,17 @@ config MTD_DATAFLASH
Sometimes DataFlash chips are packaged inside MMC-format Sometimes DataFlash chips are packaged inside MMC-format
cards; at this writing, the MMC stack won't handle those. cards; at this writing, the MMC stack won't handle those.
config MTD_DATAFLASH_OTP
bool "DataFlash OTP support (Security Register)"
depends on MTD_DATAFLASH
select HAVE_MTD_OTP
help
Newer DataFlash chips (revisions C and D) support 128 bytes of
one-time-programmable (OTP) data. The first half may be written
(once) with up to 64 bytes of data, such as a serial number or
other key product data. The second half is programmed with a
unique-to-each-chip bit pattern at the factory.
config MTD_M25P80 config MTD_M25P80
tristate "Support most SPI Flash chips (AT26DF, M25P, W25X, ...)" tristate "Support most SPI Flash chips (AT26DF, M25P, W25X, ...)"
depends on SPI_MASTER && EXPERIMENTAL depends on SPI_MASTER && EXPERIMENTAL
......
...@@ -80,7 +80,8 @@ ...@@ -80,7 +80,8 @@
*/ */
#define OP_READ_ID 0x9F #define OP_READ_ID 0x9F
#define OP_READ_SECURITY 0x77 #define OP_READ_SECURITY 0x77
#define OP_WRITE_SECURITY 0x9A /* OTP bits */ #define OP_WRITE_SECURITY_REVC 0x9A
#define OP_WRITE_SECURITY 0x9B /* revision D */
struct dataflash { struct dataflash {
...@@ -451,16 +452,192 @@ static int dataflash_write(struct mtd_info *mtd, loff_t to, size_t len, ...@@ -451,16 +452,192 @@ static int dataflash_write(struct mtd_info *mtd, loff_t to, size_t len,
/* ......................................................................... */ /* ......................................................................... */
#ifdef CONFIG_MTD_DATAFLASH_OTP
static int dataflash_get_otp_info(struct mtd_info *mtd,
struct otp_info *info, size_t len)
{
/* Report both blocks as identical: bytes 0..64, locked.
* Unless the user block changed from all-ones, we can't
* tell whether it's still writable; so we assume it isn't.
*/
info->start = 0;
info->length = 64;
info->locked = 1;
return sizeof(*info);
}
static ssize_t otp_read(struct spi_device *spi, unsigned base,
uint8_t *buf, loff_t off, size_t len)
{
struct spi_message m;
size_t l;
uint8_t *scratch;
struct spi_transfer t;
int status;
if (off > 64)
return -EINVAL;
if ((off + len) > 64)
len = 64 - off;
if (len == 0)
return len;
spi_message_init(&m);
l = 4 + base + off + len;
scratch = kzalloc(l, GFP_KERNEL);
if (!scratch)
return -ENOMEM;
/* OUT: OP_READ_SECURITY, 3 don't-care bytes, zeroes
* IN: ignore 4 bytes, data bytes 0..N (max 127)
*/
scratch[0] = OP_READ_SECURITY;
memset(&t, 0, sizeof t);
t.tx_buf = scratch;
t.rx_buf = scratch;
t.len = l;
spi_message_add_tail(&t, &m);
dataflash_waitready(spi);
status = spi_sync(spi, &m);
if (status >= 0) {
memcpy(buf, scratch + 4 + base + off, len);
status = len;
}
kfree(scratch);
return status;
}
static int dataflash_read_fact_otp(struct mtd_info *mtd,
loff_t from, size_t len, size_t *retlen, u_char *buf)
{
struct dataflash *priv = (struct dataflash *)mtd->priv;
int status;
/* 64 bytes, from 0..63 ... start at 64 on-chip */
mutex_lock(&priv->lock);
status = otp_read(priv->spi, 64, buf, from, len);
mutex_unlock(&priv->lock);
if (status < 0)
return status;
*retlen = status;
return 0;
}
static int dataflash_read_user_otp(struct mtd_info *mtd,
loff_t from, size_t len, size_t *retlen, u_char *buf)
{
struct dataflash *priv = (struct dataflash *)mtd->priv;
int status;
/* 64 bytes, from 0..63 ... start at 0 on-chip */
mutex_lock(&priv->lock);
status = otp_read(priv->spi, 0, buf, from, len);
mutex_unlock(&priv->lock);
if (status < 0)
return status;
*retlen = status;
return 0;
}
static int dataflash_write_user_otp(struct mtd_info *mtd,
loff_t from, size_t len, size_t *retlen, u_char *buf)
{
struct spi_message m;
const size_t l = 4 + 64;
uint8_t *scratch;
struct spi_transfer t;
struct dataflash *priv = (struct dataflash *)mtd->priv;
int status;
if (len > 64)
return -EINVAL;
/* Strictly speaking, we *could* truncate the write ... but
* let's not do that for the only write that's ever possible.
*/
if ((from + len) > 64)
return -EINVAL;
/* OUT: OP_WRITE_SECURITY, 3 zeroes, 64 data-or-zero bytes
* IN: ignore all
*/
scratch = kzalloc(l, GFP_KERNEL);
if (!scratch)
return -ENOMEM;
scratch[0] = OP_WRITE_SECURITY;
memcpy(scratch + 4 + from, buf, len);
spi_message_init(&m);
memset(&t, 0, sizeof t);
t.tx_buf = scratch;
t.len = l;
spi_message_add_tail(&t, &m);
/* Write the OTP bits, if they've not yet been written.
* This modifies SRAM buffer1.
*/
mutex_lock(&priv->lock);
dataflash_waitready(priv->spi);
status = spi_sync(priv->spi, &m);
mutex_unlock(&priv->lock);
kfree(scratch);
if (status >= 0) {
status = 0;
*retlen = len;
}
return status;
}
static char *otp_setup(struct mtd_info *device, char revision)
{
device->get_fact_prot_info = dataflash_get_otp_info;
device->read_fact_prot_reg = dataflash_read_fact_otp;
device->get_user_prot_info = dataflash_get_otp_info;
device->read_user_prot_reg = dataflash_read_user_otp;
/* rev c parts (at45db321c and at45db1281 only!) use a
* different write procedure; not (yet?) implemented.
*/
if (revision > 'c')
device->write_user_prot_reg = dataflash_write_user_otp;
return ", OTP";
}
#else
static char *otp_setup(struct mtd_info *device)
{
return " (OTP)";
}
#endif
/* ......................................................................... */
/* /*
* Register DataFlash device with MTD subsystem. * Register DataFlash device with MTD subsystem.
*/ */
static int __devinit static int __devinit
add_dataflash(struct spi_device *spi, char *name, add_dataflash_otp(struct spi_device *spi, char *name,
int nr_pages, int pagesize, int pageoffset) int nr_pages, int pagesize, int pageoffset, char revision)
{ {
struct dataflash *priv; struct dataflash *priv;
struct mtd_info *device; struct mtd_info *device;
struct flash_platform_data *pdata = spi->dev.platform_data; struct flash_platform_data *pdata = spi->dev.platform_data;
char *otp_tag = "";
priv = kzalloc(sizeof *priv, GFP_KERNEL); priv = kzalloc(sizeof *priv, GFP_KERNEL);
if (!priv) if (!priv)
...@@ -489,8 +666,12 @@ add_dataflash(struct spi_device *spi, char *name, ...@@ -489,8 +666,12 @@ add_dataflash(struct spi_device *spi, char *name,
device->write = dataflash_write; device->write = dataflash_write;
device->priv = priv; device->priv = priv;
dev_info(&spi->dev, "%s (%d KBytes) pagesize %d bytes\n", if (revision >= 'c')
name, DIV_ROUND_UP(device->size, 1024), pagesize); otp_tag = otp_setup(device, revision);
dev_info(&spi->dev, "%s (%d KBytes) pagesize %d bytes%s\n",
name, DIV_ROUND_UP(device->size, 1024),
pagesize, otp_tag);
dev_set_drvdata(&spi->dev, priv); dev_set_drvdata(&spi->dev, priv);
if (mtd_has_partitions()) { if (mtd_has_partitions()) {
...@@ -519,6 +700,14 @@ add_dataflash(struct spi_device *spi, char *name, ...@@ -519,6 +700,14 @@ add_dataflash(struct spi_device *spi, char *name,
return add_mtd_device(device) == 1 ? -ENODEV : 0; return add_mtd_device(device) == 1 ? -ENODEV : 0;
} }
static inline int __devinit
add_dataflash(struct spi_device *spi, char *name,
int nr_pages, int pagesize, int pageoffset)
{
return add_dataflash_otp(spi, name, nr_pages, pagesize,
pageoffset, 0);
}
struct flash_info { struct flash_info {
char *name; char *name;
...@@ -664,13 +853,16 @@ static int __devinit dataflash_probe(struct spi_device *spi) ...@@ -664,13 +853,16 @@ static int __devinit dataflash_probe(struct spi_device *spi)
* Try to detect dataflash by JEDEC ID. * Try to detect dataflash by JEDEC ID.
* If it succeeds we know we have either a C or D part. * If it succeeds we know we have either a C or D part.
* D will support power of 2 pagesize option. * D will support power of 2 pagesize option.
* Both support the security register, though with different
* write procedures.
*/ */
info = jedec_probe(spi); info = jedec_probe(spi);
if (IS_ERR(info)) if (IS_ERR(info))
return PTR_ERR(info); return PTR_ERR(info);
if (info != NULL) if (info != NULL)
return add_dataflash(spi, info->name, info->nr_pages, return add_dataflash_otp(spi, info->name, info->nr_pages,
info->pagesize, info->pageoffset); info->pagesize, info->pageoffset,
(info->flags & SUP_POW2PS) ? 'd' : 'c');
/* /*
* Older chips support only legacy commands, identifing * Older chips support only legacy commands, identifing
......
...@@ -350,7 +350,7 @@ static void mtdchar_erase_callback (struct erase_info *instr) ...@@ -350,7 +350,7 @@ static void mtdchar_erase_callback (struct erase_info *instr)
wake_up((wait_queue_head_t *)instr->priv); wake_up((wait_queue_head_t *)instr->priv);
} }
#if defined(CONFIG_MTD_OTP) || defined(CONFIG_MTD_ONENAND_OTP) #ifdef CONFIG_HAVE_MTD_OTP
static int otp_select_filemode(struct mtd_file_info *mfi, int mode) static int otp_select_filemode(struct mtd_file_info *mfi, int mode)
{ {
struct mtd_info *mtd = mfi->mtd; struct mtd_info *mtd = mfi->mtd;
...@@ -663,7 +663,7 @@ static int mtd_ioctl(struct inode *inode, struct file *file, ...@@ -663,7 +663,7 @@ static int mtd_ioctl(struct inode *inode, struct file *file,
break; break;
} }
#if defined(CONFIG_MTD_OTP) || defined(CONFIG_MTD_ONENAND_OTP) #ifdef CONFIG_HAVE_MTD_OTP
case OTPSELECT: case OTPSELECT:
{ {
int mode; int mode;
......
...@@ -29,6 +29,7 @@ config MTD_ONENAND_GENERIC ...@@ -29,6 +29,7 @@ config MTD_ONENAND_GENERIC
config MTD_ONENAND_OTP config MTD_ONENAND_OTP
bool "OneNAND OTP Support" bool "OneNAND OTP Support"
select HAVE_MTD_OTP
help help
One Block of the NAND Flash Array memory is reserved as One Block of the NAND Flash Array memory is reserved as
a One-Time Programmable Block memory area. a One-Time Programmable Block memory area.
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment