From patchwork Sat Oct 14 01:26:45 2017 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 8bit X-Patchwork-Submitter: flashrom-git@coreboot.org X-Patchwork-Id: 825785 Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@bilbo.ozlabs.org Authentication-Results: ozlabs.org; spf=none (mailfrom) smtp.mailfrom=flashrom.org (client-ip=80.81.252.135; helo=mail.coreboot.org; envelope-from=flashrom-bounces@flashrom.org; receiver=) Received: from mail.coreboot.org (mail.coreboot.org [80.81.252.135]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by ozlabs.org (Postfix) with ESMTPS id 3yDRnX6zhzz9rxm for ; Sat, 14 Oct 2017 12:29:03 +1100 (AEDT) Received: from [127.0.0.1] (helo=ra.coreboot.org) by mail.coreboot.org with esmtp (Exim 4.86_2) (envelope-from ) id 1e3BDz-0006yF-NF; Sat, 14 Oct 2017 03:26:47 +0200 Received: from flashrom-git by mail.coreboot.org with local (Exim 4.86_2) (envelope-from ) id 1e3BDx-0006wl-8s for flashrom@flashrom.org; Sat, 14 Oct 2017 03:26:45 +0200 Date: Sat, 14 Oct 2017 03:26:45 +0200 To: flashrom@flashrom.org MIME-Version: 1.0 From: flashrom-git@coreboot.org In-Reply-To: <150794440521.26653.14788992977529253276@ra.coreboot.org> References: <150794440521.26653.14788992977529253276@ra.coreboot.org> X-Git-Host: ra.coreboot.org X-Git-Repo: flashrom X-Git-Refname: refs/heads/staging X-Git-Reftype: branch X-Git-Rev: 50a5660c9c11c77c794783cd9a3343bc3ff07b6e X-Git-NotificationType: diff X-Git-Multimail-Version: 1.4.dev Auto-Submitted: auto-generated Message-Id: Subject: [flashrom] 01/01: 4BA: Basic support for 4-bytes addressing mode extensions X-BeenThere: flashrom@flashrom.org X-Mailman-Version: 2.1.22 Precedence: list List-Id: flashrom discussion and development mailing list List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Reply-To: flashrom@flashrom.org Errors-To: flashrom-bounces@flashrom.org Sender: "flashrom" X-Duff: Orig. Duff, Duff Lite, Duff Dry, Duff Dark, Raspberry Duff, Lady Duff, Red Duff, Tartar Control Duff This is an automated email from the git hooks/post-receive script. flashrom-git pushed a commit to branch staging in repository flashrom. View the commit online: https://www.flashrom.org/git/flashrom.git/commit/?id=50a5660c9c11c77c794783cd9a3343bc3ff07b6e commit 50a5660c9c11c77c794783cd9a3343bc3ff07b6e Author: Boris Baykov AuthorDate: Sat Jun 11 18:28:59 2016 +0200 4BA: Basic support for 4-bytes addressing mode extensions If flash chip is switched to 4-bytes addressing mode then all read/erase/program instructions will be switched from 3-bytes mode to 4-bytes mode. Then well known instructions like 03h (Read), 02h (Program) and 20h,52h,D8h (Erase) will become one byte longer and accept 4-bytes address instead of 3-bytes. This patch provides support for well known instructions in 4-bytes addressing mode. Also here is the code to enter 4-bytes addressing mode by execute the instruction B7h (Enter 4-bytes mode). Patched files ------------- chipdrivers.h + added functions declarations for spi4ba.c flash.h + feature definitions added Makefile + added spi4ba.c Added files ----------- spi4ba.h + definitions for 4-bytes addressing JEDEC commands + functions declarations from spi4ba.c (same as in chipdrivers.h, just to see) spi4ba.c + functions for enter 4-bytes addressing mode + functions for read/write/erase in 4-bytes addressing mode Change-Id: Ie72e2a89cd75fb4d09f48e81c4c1d927c317b7a7 Signed-off-by: Boris Baykov , Russia, Jan 2014 [clg: ported from https://www.flashrom.org/pipermail/flashrom/2015-January/013199.html ] Signed-off-by: Cédric Le Goater Reviewed-on: https://review.coreboot.org/20513 Reviewed-by: David Hendricks Reviewed-by: Nico Huber Tested-by: build bot (Jenkins) --- Makefile | 2 +- chipdrivers.h | 10 ++ flash.h | 3 + spi4ba.c | 327 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ spi4ba.h | 54 ++++++++++ 5 files changed, 395 insertions(+), 1 deletion(-) diff --git a/Makefile b/Makefile index 9184bb35d..5573127ef 100644 --- a/Makefile +++ b/Makefile @@ -514,7 +514,7 @@ endif CHIP_OBJS = jedec.o stm50.o w39.o w29ee011.o \ sst28sf040.o 82802ab.o \ sst49lfxxxc.o sst_fwhub.o flashchips.o spi.o spi25.o spi25_statusreg.o \ - opaque.o sfdp.o en29lv640b.o at45db.o + spi4ba.o opaque.o sfdp.o en29lv640b.o at45db.o ############################################################################### # Library code. diff --git a/chipdrivers.h b/chipdrivers.h index c85eac96c..dccd1ff92 100644 --- a/chipdrivers.h +++ b/chipdrivers.h @@ -195,4 +195,14 @@ int erase_sector_stm50(struct flashctx *flash, unsigned int block, unsigned int int probe_en29lv640b(struct flashctx *flash); int write_en29lv640b(struct flashctx *flash, const uint8_t *buf, unsigned int start, unsigned int len); +/* spi4ba.c */ +int spi_enter_4ba_b7(struct flashctx *flash); +int spi_enter_4ba_b7_we(struct flashctx *flash); +int spi_byte_program_4ba(struct flashctx *flash, unsigned int addr, uint8_t databyte); +int spi_nbyte_program_4ba(struct flashctx *flash, unsigned int addr, const uint8_t *bytes, unsigned int len); +int spi_nbyte_read_4ba(struct flashctx *flash, unsigned int addr, uint8_t *bytes, unsigned int len); +int spi_block_erase_20_4ba(struct flashctx *flash, unsigned int addr, unsigned int blocklen); +int spi_block_erase_52_4ba(struct flashctx *flash, unsigned int addr, unsigned int blocklen); +int spi_block_erase_d8_4ba(struct flashctx *flash, unsigned int addr, unsigned int blocklen); + #endif /* !__CHIPDRIVERS_H__ */ diff --git a/flash.h b/flash.h index 67c7d20c4..611450fe5 100644 --- a/flash.h +++ b/flash.h @@ -119,6 +119,9 @@ enum write_granularity { #define FEATURE_WRSR_EITHER (FEATURE_WRSR_EWSR | FEATURE_WRSR_WREN) #define FEATURE_OTP (1 << 8) #define FEATURE_QPI (1 << 9) +/* Feature bits used for 4-bytes addressing mode */ +#define FEATURE_4BA_SUPPORT (1 << 10) +#define FEATURE_4BA_ONLY (1 << 11) enum test_state { OK = 0, diff --git a/spi4ba.c b/spi4ba.c new file mode 100644 index 000000000..72df87427 --- /dev/null +++ b/spi4ba.c @@ -0,0 +1,327 @@ +/* + * This file is part of the flashrom project. + * + * Copyright (C) 2014 Boris Baykov + * + * 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; version 2 of the License. + * + * 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 + */ + +/* + * SPI chip driver functions for 4-bytes addressing + */ + +#include +#include "flash.h" +#include "chipdrivers.h" +#include "spi.h" +#include "programmer.h" +#include "spi4ba.h" + +/* #define MSG_TRACE_4BA_FUNCS 1 */ + +#ifdef MSG_TRACE_4BA_FUNCS +#define msg_trace(...) print(MSG_DEBUG, __VA_ARGS__) +#else +#define msg_trace(...) +#endif + +/* Enter 4-bytes addressing mode (without sending WREN before) */ +int spi_enter_4ba_b7(struct flashctx *flash) +{ + const unsigned char cmd[JEDEC_ENTER_4_BYTE_ADDR_MODE_OUTSIZE] = { JEDEC_ENTER_4_BYTE_ADDR_MODE }; + + msg_trace("-> %s\n", __func__); + + /* Switch to 4-bytes addressing mode */ + return spi_send_command(flash, sizeof(cmd), 0, cmd, NULL); +} + +/* Enter 4-bytes addressing mode with sending WREN before */ +int spi_enter_4ba_b7_we(struct flashctx *flash) +{ + int result; + struct spi_command cmds[] = { + { + .writecnt = JEDEC_WREN_OUTSIZE, + .writearr = (const unsigned char[]){ JEDEC_WREN }, + .readcnt = 0, + .readarr = NULL, + }, { + .writecnt = JEDEC_ENTER_4_BYTE_ADDR_MODE_OUTSIZE, + .writearr = (const unsigned char[]){ JEDEC_ENTER_4_BYTE_ADDR_MODE }, + .readcnt = 0, + .readarr = NULL, + }, { + .writecnt = 0, + .writearr = NULL, + .readcnt = 0, + .readarr = NULL, + }}; + + msg_trace("-> %s\n", __func__); + + /* Switch to 4-bytes addressing mode */ + result = spi_send_multicommand(flash, cmds); + if (result) { + msg_cerr("%s failed during command execution\n", __func__); + } + return result; +} + +/* Program one flash byte from 4-bytes addressing mode */ +int spi_byte_program_4ba(struct flashctx *flash, unsigned int addr, + uint8_t databyte) +{ + int result; + struct spi_command cmds[] = { + { + .writecnt = JEDEC_WREN_OUTSIZE, + .writearr = (const unsigned char[]){ JEDEC_WREN }, + .readcnt = 0, + .readarr = NULL, + }, { + .writecnt = JEDEC_BYTE_PROGRAM_OUTSIZE + 1, + .writearr = (const unsigned char[]){ + JEDEC_BYTE_PROGRAM, + (addr >> 24) & 0xff, + (addr >> 16) & 0xff, + (addr >> 8) & 0xff, + (addr & 0xff), + databyte + }, + .readcnt = 0, + .readarr = NULL, + }, { + .writecnt = 0, + .writearr = NULL, + .readcnt = 0, + .readarr = NULL, + }}; + + msg_trace("-> %s (0x%08X)\n", __func__, addr); + + result = spi_send_multicommand(flash, cmds); + if (result) { + msg_cerr("%s failed during command execution at address 0x%x\n", + __func__, addr); + } + return result; +} + +/* Program flash bytes from 4-bytes addressing mode */ +int spi_nbyte_program_4ba(struct flashctx *flash, unsigned int addr, + const uint8_t *bytes, unsigned int len) +{ + int result; + unsigned char cmd[(JEDEC_BYTE_PROGRAM_OUTSIZE + 1) - 1 + 256] = { + JEDEC_BYTE_PROGRAM, + (addr >> 24) & 0xff, + (addr >> 16) & 0xff, + (addr >> 8) & 0xff, + (addr >> 0) & 0xff + }; + struct spi_command cmds[] = { + { + .writecnt = JEDEC_WREN_OUTSIZE, + .writearr = (const unsigned char[]){ JEDEC_WREN }, + .readcnt = 0, + .readarr = NULL, + }, { + .writecnt = (JEDEC_BYTE_PROGRAM_OUTSIZE + 1) - 1 + len, + .writearr = cmd, + .readcnt = 0, + .readarr = NULL, + }, { + .writecnt = 0, + .writearr = NULL, + .readcnt = 0, + .readarr = NULL, + }}; + + msg_trace("-> %s (0x%08X-0x%08X)\n", __func__, addr, addr + len - 1); + + if (!len) { + msg_cerr("%s called for zero-length write\n", __func__); + return 1; + } + if (len > 256) { + msg_cerr("%s called for too long a write\n", __func__); + return 1; + } + + memcpy(&cmd[(JEDEC_BYTE_PROGRAM_OUTSIZE + 1) - 1], bytes, len); + + result = spi_send_multicommand(flash, cmds); + if (result) { + msg_cerr("%s failed during command execution at address 0x%x\n", + __func__, addr); + } + return result; +} + +/* Read flash bytes from 4-bytes addressing mode */ +int spi_nbyte_read_4ba(struct flashctx *flash, unsigned int addr, + uint8_t *bytes, unsigned int len) +{ + const unsigned char cmd[JEDEC_READ_OUTSIZE + 1] = { + JEDEC_READ, + (addr >> 24) & 0xff, + (addr >> 16) & 0xff, + (addr >> 8) & 0xff, + (addr >> 0) & 0xff + }; + + msg_trace("-> %s (0x%08X-0x%08X)\n", __func__, addr, addr + len - 1); + + /* Send Read */ + return spi_send_command(flash, sizeof(cmd), len, cmd, bytes); +} + +/* Erases 4 KB of flash from 4-bytes addressing mode */ +int spi_block_erase_20_4ba(struct flashctx *flash, unsigned int addr, + unsigned int blocklen) +{ + int result; + struct spi_command cmds[] = { + { + .writecnt = JEDEC_WREN_OUTSIZE, + .writearr = (const unsigned char[]){ JEDEC_WREN }, + .readcnt = 0, + .readarr = NULL, + }, { + .writecnt = JEDEC_SE_OUTSIZE + 1, + .writearr = (const unsigned char[]){ + JEDEC_SE, + (addr >> 24) & 0xff, + (addr >> 16) & 0xff, + (addr >> 8) & 0xff, + (addr & 0xff) + }, + .readcnt = 0, + .readarr = NULL, + }, { + .writecnt = 0, + .writearr = NULL, + .readcnt = 0, + .readarr = NULL, + }}; + + msg_trace("-> %s (0x%08X-0x%08X)\n", __func__, addr, addr + blocklen - 1); + + result = spi_send_multicommand(flash, cmds); + if (result) { + msg_cerr("%s failed during command execution at address 0x%x\n", + __func__, addr); + return result; + } + /* Wait until the Write-In-Progress bit is cleared. + * This usually takes 15-800 ms, so wait in 10 ms steps. + */ + while (spi_read_status_register(flash) & SPI_SR_WIP) + programmer_delay(10 * 1000); + /* FIXME: Check the status register for errors. */ + return 0; +} + +/* Erases 32 KB of flash from 4-bytes addressing mode */ +int spi_block_erase_52_4ba(struct flashctx *flash, unsigned int addr, + unsigned int blocklen) +{ + int result; + struct spi_command cmds[] = { + { + .writecnt = JEDEC_WREN_OUTSIZE, + .writearr = (const unsigned char[]){ JEDEC_WREN }, + .readcnt = 0, + .readarr = NULL, + }, { + .writecnt = JEDEC_BE_52_OUTSIZE + 1, + .writearr = (const unsigned char[]){ + JEDEC_BE_52, + (addr >> 24) & 0xff, + (addr >> 16) & 0xff, + (addr >> 8) & 0xff, + (addr & 0xff) + }, + .readcnt = 0, + .readarr = NULL, + }, { + .writecnt = 0, + .writearr = NULL, + .readcnt = 0, + .readarr = NULL, + }}; + + msg_trace("-> %s (0x%08X-0x%08X)\n", __func__, addr, addr + blocklen - 1); + + result = spi_send_multicommand(flash, cmds); + if (result) { + msg_cerr("%s failed during command execution at address 0x%x\n", + __func__, addr); + return result; + } + /* Wait until the Write-In-Progress bit is cleared. + * This usually takes 100-4000 ms, so wait in 100 ms steps. + */ + while (spi_read_status_register(flash) & SPI_SR_WIP) + programmer_delay(100 * 1000); + /* FIXME: Check the status register for errors. */ + return 0; +} + +/* Erases 64 KB of flash from 4-bytes addressing mode */ +int spi_block_erase_d8_4ba(struct flashctx *flash, unsigned int addr, + unsigned int blocklen) +{ + int result; + struct spi_command cmds[] = { + { + .writecnt = JEDEC_WREN_OUTSIZE, + .writearr = (const unsigned char[]){ JEDEC_WREN }, + .readcnt = 0, + .readarr = NULL, + }, { + .writecnt = JEDEC_BE_D8_OUTSIZE + 1, + .writearr = (const unsigned char[]){ + JEDEC_BE_D8, + (addr >> 24) & 0xff, + (addr >> 16) & 0xff, + (addr >> 8) & 0xff, + (addr & 0xff) + }, + .readcnt = 0, + .readarr = NULL, + }, { + .writecnt = 0, + .writearr = NULL, + .readcnt = 0, + .readarr = NULL, + }}; + + msg_trace("-> %s (0x%08X-0x%08X)\n", __func__, addr, addr + blocklen - 1); + + result = spi_send_multicommand(flash, cmds); + if (result) { + msg_cerr("%s failed during command execution at address 0x%x\n", + __func__, addr); + return result; + } + /* Wait until the Write-In-Progress bit is cleared. + * This usually takes 100-4000 ms, so wait in 100 ms steps. + */ + while (spi_read_status_register(flash) & SPI_SR_WIP) + programmer_delay(100 * 1000); + /* FIXME: Check the status register for errors. */ + return 0; +} diff --git a/spi4ba.h b/spi4ba.h new file mode 100644 index 000000000..15feecb40 --- /dev/null +++ b/spi4ba.h @@ -0,0 +1,54 @@ +/* + * This file is part of the flashrom project. + * + * Copyright (C) 2014 Boris Baykov + * + * 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 +*/ + +/* + * JEDEC flash chips instructions for 4-bytes addressing + * SPI chip driver functions for 4-bytes addressing + */ + +#ifndef __SPI_4BA_H__ +#define __SPI_4BA_H__ 1 + +/* Enter 4-byte Address Mode */ +#define JEDEC_ENTER_4_BYTE_ADDR_MODE 0xB7 +#define JEDEC_ENTER_4_BYTE_ADDR_MODE_OUTSIZE 0x01 +#define JEDEC_ENTER_4_BYTE_ADDR_MODE_INSIZE 0x00 + +/* Exit 4-byte Address Mode */ +#define JEDEC_EXIT_4_BYTE_ADDR_MODE 0xE9 +#define JEDEC_EXIT_4_BYTE_ADDR_MODE_OUTSIZE 0x01 +#define JEDEC_EXIT_4_BYTE_ADDR_MODE_INSIZE 0x00 + +/* enter 4-bytes addressing mode */ +int spi_enter_4ba_b7(struct flashctx *flash); +int spi_enter_4ba_b7_we(struct flashctx *flash); + +/* read/write flash bytes in 4-bytes addressing mode */ +int spi_byte_program_4ba(struct flashctx *flash, unsigned int addr, uint8_t databyte); +int spi_nbyte_program_4ba(struct flashctx *flash, unsigned int addr, const uint8_t *bytes, unsigned int len); +int spi_nbyte_read_4ba(struct flashctx *flash, unsigned int addr, uint8_t *bytes, unsigned int len); + +/* erase flash bytes in 4-bytes addressing mode */ +int spi_block_erase_20_4ba(struct flashctx *flash, unsigned int addr, unsigned int blocklen); +int spi_block_erase_52_4ba(struct flashctx *flash, unsigned int addr, unsigned int blocklen); +int spi_block_erase_d8_4ba(struct flashctx *flash, unsigned int addr, unsigned int blocklen); + + +#endif /* __SPI_4BA_H__ */