From patchwork Sat Jun 11 16:28:59 2016 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 8bit X-Patchwork-Submitter: =?utf-8?q?C=C3=A9dric_Le_Goater?= X-Patchwork-Id: 634085 Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@bilbo.ozlabs.org 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 3rRkzV6Tdvz9s2Q for ; Sun, 12 Jun 2016 02:30:14 +1000 (AEST) Received: from [127.0.0.1] (helo=ra.coresystems.de) by mail.coreboot.org with esmtp (Exim 4.86_2) (envelope-from ) id 1bBlmu-0001j3-Uz; Sat, 11 Jun 2016 18:29:33 +0200 Received: from 7.mo6.mail-out.ovh.net ([46.105.59.196]) by mail.coreboot.org with esmtps (TLSv1.2:ECDHE-RSA-AES256-GCM-SHA384:256) (Exim 4.86_2) (envelope-from ) id 1bBlmd-0001h5-W6 for flashrom@flashrom.org; Sat, 11 Jun 2016 18:29:30 +0200 Received: from player693.ha.ovh.net (b9.ovh.net [213.186.33.59]) by mo6.mail-out.ovh.net (Postfix) with ESMTP id 3415CFFA08E for ; Sat, 11 Jun 2016 18:29:15 +0200 (CEST) Received: from hermes.ibm.com (LFbn-1-2234-107.w90-76.abo.wanadoo.fr [90.76.55.107]) (Authenticated sender: clg@kaod.org) by player693.ha.ovh.net (Postfix) with ESMTPSA id CD40744007E; Sat, 11 Jun 2016 18:29:10 +0200 (CEST) From: =?UTF-8?q?C=C3=A9dric=20Le=20Goater?= To: flashrom@flashrom.org Date: Sat, 11 Jun 2016 18:28:59 +0200 Message-Id: <1465662544-5730-2-git-send-email-clg@kaod.org> X-Mailer: git-send-email 2.1.4 In-Reply-To: <1465662544-5730-1-git-send-email-clg@kaod.org> References: <1465662544-5730-1-git-send-email-clg@kaod.org> MIME-Version: 1.0 X-Ovh-Tracer-Id: 4349069867061316526 X-VR-SPAMSTATE: OK X-VR-SPAMSCORE: -100 X-VR-SPAMCAUSE: gggruggvucftvghtrhhoucdtuddrfeekledrjeelgddutddtucetufdoteggodetrfdotffvucfrrhhofhhilhgvmecuqfggjfenuceurghilhhouhhtmecufedttdenucesvcftvggtihhpihgvnhhtshculddquddttddm X-Spam-Score: -3.0 (---) Subject: [flashrom] [PATCH 1/6] 4BA: Basic support for 4-bytes addressing mode extensions X-BeenThere: flashrom@flashrom.org X-Mailman-Version: 2.1.21 Precedence: list List-Id: flashrom discussion and development mailing list List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , 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 From: Boris Baykov 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 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 --- Makefile | 2 +- chipdrivers.h | 10 ++ flash.h | 3 + spi4ba.c | 327 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ spi4ba.h | 54 ++++++++++ 5 files changed, 395 insertions(+), 1 deletion(-) create mode 100644 spi4ba.c create mode 100644 spi4ba.h diff --git a/Makefile b/Makefile index 4ebde1efbe3f..d7713986008e 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 c85eac96cc31..dccd1ff92ec1 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 da049d178439..7bd4b1376d40 100644 --- a/flash.h +++ b/flash.h @@ -123,6 +123,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 000000000000..72df874275c9 --- /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 000000000000..15feecb40802 --- /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__ */