Sergii Dmytruk has uploaded this change for review. ( https://review.coreboot.org/c/flashrom/+/59402 )
Change subject: [RFC] spi: add functions for OTP regions ......................................................................
[RFC] spi: add functions for OTP regions
These are functions for entering/leaving OTP mode and reading/writing/erasing secure registers.
Also introduces part of the structure that describes OTP, because new code uses it.
This one and other patches resurrecting the work of Hatim Kanchwala aimed at adding OTP to flashrom.
This chain of patches are based on CB:59075, which in turn depend on patches that introduce write-protect support.
Change-Id: Ic33e2c1de8b0ca02df9118218a663ce63826f339 Signed-off-by: Hatim Kanchwala <hatim at hatimak.me> Signed-off-by: Sergii Dmytruk sergii.dmytruk@3mdeb.com --- M chipdrivers.h M flash.h A otp.h M spi.h M spi25.c 5 files changed, 167 insertions(+), 1 deletion(-)
git pull ssh://review.coreboot.org:29418/flashrom refs/changes/02/59402/1
diff --git a/chipdrivers.h b/chipdrivers.h index e1d6aa9..a5fbec9 100644 --- a/chipdrivers.h +++ b/chipdrivers.h @@ -59,6 +59,11 @@ int spi_enter_4ba(struct flashctx *flash); int spi_exit_4ba(struct flashctx *flash); int spi_set_extended_address(struct flashctx *, uint8_t addr_high); +int spi_otp_mode_enter(struct flashctx *flash); +int spi_otp_mode_exit(struct flashctx *flash); +int spi_sec_reg_read(struct flashctx *flash, uint8_t *buf, uint32_t start_addr, uint32_t len); +int spi_sec_reg_prog(struct flashctx *flash, uint8_t const *buf, uint32_t start_addr, uint32_t len); +int spi_sec_reg_erase(struct flashctx *flash, uint32_t addr);
/* spi25_statusreg.c */ diff --git a/flash.h b/flash.h index 391a2d4..d4b364e 100644 --- a/flash.h +++ b/flash.h @@ -245,7 +245,7 @@ /* SPI specific options (TODO: Make it a union in case other bustypes get specific options.) */ uint8_t wrea_override; /**< override opcode for write extended address register */
- struct wp *wp; + struct otp *otp; };
typedef int (*chip_restore_fn_cb_t)(struct flashctx *flash, uint8_t status); diff --git a/otp.h b/otp.h new file mode 100644 index 0000000..635d6cb --- /dev/null +++ b/otp.h @@ -0,0 +1,52 @@ +/* + * This file is part of the flashrom project. + * + * Copyright (C) 2016 Hatim Kanchwala <hatim at hatimak.me> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#ifndef __OTP_H__ +#define __OTP_H__ 1 + +#include <stdint.h> + +#include "flash.h" + +struct flashctx; + +/* Bits for otp.feature_bits field */ +/* Need to enter special mode to work with OTP */ +#define OTP_KIND_MODE (1 << 0) +/* Need to use special opcodes to interact with OTP */ +#define OTP_KIND_REGS (1 << 1) +/* Block protect bits must be cleared before entering OTP mode */ +#define OTP_MODE_CLEAR_BP (1 << 2) +/* OTP lock must be set while in OTP mode */ +#define OTP_MODE_LOCK_WHILE_IN (1 << 3) +/* OTP registers are read as one (FIXME: not implemented) */ +#define OTP_REGS_FUSED_READ (1 << 4) +/* OTP registers are erased as one (FIXME: not implemented) */ +#define OTP_REGS_FUSED_ERASE (1 << 5) + +struct otp { + int feature_bits; /* must contain either OTP_KIND_MODE or OTP_KIND_REGS */ + + /* These opcodes are different for different manufacturers. */ + uint8_t otp_enter_opcode; + uint8_t otp_exit_opcode; +}; + +#endif /* !__OTP_H__ */ diff --git a/spi.h b/spi.h index 09da579..203ef19 100644 --- a/spi.h +++ b/spi.h @@ -178,6 +178,26 @@ #define JEDEC_AAI_WORD_PROGRAM_CONT_OUTSIZE 0x03 #define JEDEC_AAI_WORD_PROGRAM_INSIZE 0x00
+/* Enter OTP mode (supported by most Eon chips) */ +#define JEDEC_ENTER_OTP 0x3A +#define JEDEC_ENTER_OTP_OUTSIZE 0x01 +#define JEDEC_ENTER_OTP_INSIZE 0x00 + +/* Read Security Register(s) (supported by most GigaDevice chips) */ +#define JEDEC_READ_SEC_REG 0x48 +#define JEDEC_READ_SEC_REG_OUTSIZE 0x05 +/* JEDEC_READ_SEC_REG_INSIZE any length */ + +/* Program Security Register(s) (supported by most GigaDevice chips) */ +#define JEDEC_PROG_BYTE_SEC_REG 0x42 +#define JEDEC_PROG_BYTE_SEC_REG_OUTSIZE 0x05 +#define JEDEC_PROG_BYTE_SEC_REG_INSIZE 0x00 + +/* Erase Security Register(s) (supported by most GigaDevice chips) */ +#define JEDEC_ERASE_SEC_REG 0x44 +#define JEDEC_ERASE_SEC_REG_OUTSIZE 0x04 +#define JEDEC_ERASE_SEC_REG_INSIZE 0x00 + /* Read the memory with 4-byte address From ANY mode (3-bytes or 4-bytes) it works with 4-byte address */ #define JEDEC_READ_4BA 0x13 diff --git a/spi25.c b/spi25.c index 213273f..629e239 100644 --- a/spi25.c +++ b/spi25.c @@ -26,6 +26,7 @@ #include "chipdrivers.h" #include "programmer.h" #include "spi.h" +#include "otp.h"
enum id_type { RDID, @@ -839,3 +840,91 @@ { return spi_enter_exit_4ba(flash, false); } + +/* This function maps the additional OTP sector to the top or bottom sector + * (depending on the chip). The mapped sector behaves like just another normal + * sector. */ +int spi_otp_mode_enter(struct flashctx *flash) +{ + if (!flash->chip->otp || !flash->chip->otp->otp_enter_opcode) + return 1; + + const unsigned char cmd[1] = { + flash->chip->otp->otp_enter_opcode + }; + return spi_send_command(flash, sizeof(cmd), 0, cmd, NULL); +} + +int spi_otp_mode_exit(struct flashctx *flash) +{ + if (!flash->chip->otp || !flash->chip->otp->otp_exit_opcode) + return 1; + + const unsigned char cmd[1] = { + flash->chip->otp->otp_exit_opcode + }; + return spi_send_command(flash, sizeof(cmd), 0, cmd, NULL); +} + +int spi_sec_reg_read(struct flashctx *flash, uint8_t *buf, uint32_t start_addr, uint32_t len) +{ + /* We assume that start_addr and len are correct and proceed without any error checking. */ + uint8_t cmd[JEDEC_READ_SEC_REG_OUTSIZE] = { + JEDEC_READ_SEC_REG, + (start_addr >> 16), + (start_addr >> 8), + start_addr, + 0x00, /* dummy data */ + }; + + int result = spi_send_command(flash, sizeof(cmd), len, cmd, buf); + if (result) + msg_cerr("%s failed.\n", __func__); + return result; +} + +int spi_sec_reg_prog(struct flashctx *flash, uint8_t const *buf, uint32_t start_addr, uint32_t len) +{ + /* We assume that start_addr and len are correct, the security register is unlocked + * and proceed without any error checking. */ + int ret = spi_write_enable(flash); + if (ret) { + msg_cerr("%s failed\n", __func__); + return ret; + } + + uint8_t cmd[JEDEC_PROG_BYTE_SEC_REG_OUTSIZE - 1 + len]; + cmd[0] = JEDEC_PROG_BYTE_SEC_REG; + cmd[1] = (start_addr >> 16); + cmd[2] = (start_addr >> 8); + cmd[3] = start_addr; + memcpy(&cmd[4], buf, len); + + ret = spi_send_command(flash, sizeof(cmd), 0, cmd, NULL); + if (ret || spi_poll_wip(flash, 10)) + msg_cerr("%s\n", __func__); + + return ret; +} + +int spi_sec_reg_erase(struct flashctx *flash, uint32_t addr) +{ + /* We assume that addr is correct and proceed without any error checking. */ + int ret = spi_write_enable(flash); + if (ret) { + msg_cerr("%s failed\n", __func__); + return ret; + } + + uint8_t cmd[JEDEC_ERASE_SEC_REG_OUTSIZE] = { + JEDEC_ERASE_SEC_REG, + (addr >> 16), + (addr >> 8), + addr, + }; + + ret = spi_send_command(flash, sizeof(cmd), 0, cmd, NULL); + if (ret || spi_poll_wip(flash, 10)) + msg_cerr("%s\n", __func__); + return ret; +}