// SPDX-License-Identifier: GPL-2.0 /* * OTP support for SPI NOR flashes * * Copyright (C) 2021 Michael Walle <[email protected]> */ #include <linux/log2.h> #include <linux/mtd/mtd.h> #include <linux/mtd/spi-nor.h> #include "core.h" #define spi_nor_otp_region_len(nor) … #define spi_nor_otp_n_regions(nor) … /** * 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) { … } /** * 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) { … } /** * 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) { … } static int spi_nor_otp_lock_bit_cr(unsigned int 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, unsigned int region) { … } /** * 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, unsigned int region) { … } static loff_t spi_nor_otp_region_start(const struct spi_nor *nor, unsigned int region) { … } static size_t spi_nor_otp_size(struct spi_nor *nor) { … } /* Translate the file offsets from and to OTP regions. */ static loff_t spi_nor_otp_region_to_offset(struct spi_nor *nor, unsigned int region) { … } static unsigned int spi_nor_otp_offset_to_region(struct spi_nor *nor, loff_t ofs) { … } static int spi_nor_mtd_otp_info(struct mtd_info *mtd, size_t len, size_t *retlen, struct otp_info *buf) { … } static int spi_nor_mtd_otp_range_is_locked(struct spi_nor *nor, loff_t ofs, size_t len) { … } static int spi_nor_mtd_otp_read_write(struct mtd_info *mtd, loff_t ofs, size_t total_len, size_t *retlen, const u8 *buf, bool is_write) { … } static int spi_nor_mtd_otp_read(struct mtd_info *mtd, loff_t from, size_t len, size_t *retlen, u8 *buf) { … } static int spi_nor_mtd_otp_write(struct mtd_info *mtd, loff_t to, size_t len, size_t *retlen, const u8 *buf) { … } static int spi_nor_mtd_otp_erase(struct mtd_info *mtd, loff_t from, size_t len) { … } static int spi_nor_mtd_otp_lock(struct mtd_info *mtd, loff_t from, size_t len) { … } void spi_nor_set_mtd_otp_ops(struct spi_nor *nor) { … }