/** * spi_nor_otp_read_secr() - read security register * @nor: pointer to 'struct spi_nor' * @addr: offset to read from * @len: number of bytes to read * @buf: pointer to dst buffer * * Read a security register by using the SPINOR_OP_RSECR commands. * * In Winbond/GigaDevice datasheets the term "security register" stands for * an one-time-programmable memory area, consisting of multiple bytes (usually * 256). Thus one "security register" maps to one OTP region. * * This method is used on GigaDevice and Winbond flashes. * * Please note, the read must not span multiple registers. * * Return: number of bytes read successfully, -errno otherwise
*/ int spi_nor_otp_read_secr(struct spi_nor *nor, loff_t addr, size_t len, u8 *buf)
{
u8 addr_nbytes, read_opcode, read_dummy; struct spi_mem_dirmap_desc *rdesc; enum spi_nor_protocol read_proto; int ret;
/** * spi_nor_otp_write_secr() - write security register * @nor: pointer to 'struct spi_nor' * @addr: offset to write to * @len: number of bytes to write * @buf: pointer to src buffer * * Write a security register by using the SPINOR_OP_PSECR commands. * * For more information on the term "security register", see the documentation * of spi_nor_otp_read_secr(). * * This method is used on GigaDevice and Winbond flashes. * * Please note, the write must not span multiple registers. * * Return: number of bytes written successfully, -errno otherwise
*/ int spi_nor_otp_write_secr(struct spi_nor *nor, loff_t addr, size_t len, const u8 *buf)
{ enum spi_nor_protocol write_proto; struct spi_mem_dirmap_desc *wdesc;
u8 addr_nbytes, program_opcode; int ret, written;
/* * We only support a write to one single page. For now all winbond * flashes only have one page per security register.
*/
ret = spi_nor_write_enable(nor); if (ret) goto out;
written = spi_nor_write_data(nor, addr, len, buf); if (written < 0) goto out;
/** * spi_nor_otp_erase_secr() - erase a security register * @nor: pointer to 'struct spi_nor' * @addr: offset of the security register to be erased * * Erase a security register by using the SPINOR_OP_ESECR command. * * For more information on the term "security register", see the documentation * of spi_nor_otp_read_secr(). * * This method is used on GigaDevice and Winbond flashes. * * Return: 0 on success, -errno otherwise
*/ int spi_nor_otp_erase_secr(struct spi_nor *nor, loff_t addr)
{
u8 erase_opcode = nor->erase_opcode; int ret;
ret = spi_nor_write_enable(nor); if (ret) return ret;
nor->erase_opcode = SPINOR_OP_ESECR;
ret = spi_nor_erase_sector(nor, addr);
nor->erase_opcode = erase_opcode; if (ret) return ret;
if (region >= ARRAY_SIZE(lock_bits)) return -EINVAL;
return lock_bits[region];
}
/** * spi_nor_otp_lock_sr2() - lock the OTP region * @nor: pointer to 'struct spi_nor' * @region: OTP region * * Lock the OTP region by writing the status register-2. This method is used on * GigaDevice and Winbond flashes. * * Return: 0 on success, -errno otherwise.
*/ int spi_nor_otp_lock_sr2(struct spi_nor *nor, unsignedint region)
{
u8 *cr = nor->bouncebuf; int ret, lock_bit;
lock_bit = spi_nor_otp_lock_bit_cr(region); if (lock_bit < 0) return lock_bit;
ret = spi_nor_read_cr(nor, cr); if (ret) return ret;
/* no need to write the register if region is already locked */ if (cr[0] & lock_bit) return 0;
/** * spi_nor_otp_is_locked_sr2() - get the OTP region lock status * @nor: pointer to 'struct spi_nor' * @region: OTP region * * Retrieve the OTP region lock bit by reading the status register-2. This * method is used on GigaDevice and Winbond flashes. * * Return: 0 on success, -errno otherwise.
*/ int spi_nor_otp_is_locked_sr2(struct spi_nor *nor, unsignedint region)
{
u8 *cr = nor->bouncebuf; int ret, lock_bit;
lock_bit = spi_nor_otp_lock_bit_cr(region); if (lock_bit < 0) return lock_bit;
ret = spi_nor_read_cr(nor, cr); if (ret) return ret;
/* Translate the file offsets from and to OTP regions. */ static loff_t spi_nor_otp_region_to_offset(struct spi_nor *nor, unsignedint region)
{ return region * spi_nor_otp_region_len(nor);
}
/* * If any of the affected OTP regions are locked the entire range is * considered locked.
*/ for (region = spi_nor_otp_offset_to_region(nor, ofs);
region <= spi_nor_otp_offset_to_region(nor, ofs + len - 1);
region++) {
locked = ops->is_locked(nor, region); /* take the branch it is locked or in case of an error */ if (locked) return locked;
}
if (ofs < 0 || ofs >= spi_nor_otp_size(nor)) return 0;
/* don't access beyond the end */
total_len = min_t(size_t, total_len, spi_nor_otp_size(nor) - ofs);
if (!total_len) return 0;
ret = spi_nor_prep_and_lock(nor); if (ret) return ret;
if (is_write) {
ret = spi_nor_mtd_otp_range_is_locked(nor, ofs, total_len); if (ret < 0) { goto out;
} elseif (ret) {
ret = -EROFS; goto out;
}
}
while (total_len) { /* * The OTP regions are mapped into a contiguous area starting * at 0 as expected by the MTD layer. This will map the MTD * file offsets to the address of an OTP region as used in the * actual SPI commands.
*/
region = spi_nor_otp_offset_to_region(nor, ofs);
rstart = spi_nor_otp_region_start(nor, region);
/* * The size of a OTP region is expected to be a power of two, * thus we can just mask the lower bits and get the offset into * a region.
*/
rofs = ofs & (rlen - 1);
/* don't access beyond one OTP region */
len = min_t(size_t, total_len, rlen - rofs);
if (is_write)
ret = ops->write(nor, rstart + rofs, len, buf); else
ret = ops->read(nor, rstart + rofs, len, (u8 *)buf); if (ret == 0)
ret = -EIO; if (ret < 0) goto out;
if (WARN_ON(!is_power_of_2(spi_nor_otp_region_len(nor)))) return;
/* * We only support user_prot callbacks (yet). * * Some SPI NOR flashes like Macronix ones can be ordered in two * different variants. One with a factory locked OTP area and one where * it is left to the user to write to it. The factory locked OTP is * usually preprogrammed with an "electrical serial number". We don't * support these for now.
*/
mtd->_get_user_prot_info = spi_nor_mtd_otp_info;
mtd->_read_user_prot_reg = spi_nor_mtd_otp_read;
mtd->_write_user_prot_reg = spi_nor_mtd_otp_write;
mtd->_lock_user_prot_reg = spi_nor_mtd_otp_lock;
mtd->_erase_user_prot_reg = spi_nor_mtd_otp_erase;
}
Messung V0.5
¤ Dauer der Verarbeitung: 0.9 Sekunden
(vorverarbeitet)
¤
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.