This patch adds support for the SPI Chips Atmel AT25DF32, ST M25P80, ST M25P16, M25P32, ST M25P64 attached to the ICH9. Because chipset plays an important role in communicating with these chips, it was not possible to integrate this support into the already existing spi.c This module was tested with the devices as mentioned above, but it should be easy to expand it for other SPI chips attached to an ICH.
Signed-off-by: Claus Gindhart claus.gindhart@kontron.com
---
Mit freundlichen Grüßen / Best regards
Claus Gindhart SW R&D Kontron Modular Computers phone :++49 (0)8341-803-374 mailto:claus.gindhart@kontron.com http://www.kontron.com
Kontron Modular Computers GmbH Geschaeftsfuehrer / Managing Directors: Ulrich Gehrmann, Thomas Sabisch Sitz der Gesellschaft / Registered Office: Kaufbeuren, Rechtsform / Legal: GmbH Amtsgericht / Local District Court Kempten, HRB Nr. / Trade Register No. 6195
The information contained in this document is CONFIDENTIAL and property of Kontron. Any unauthorized review, use, disclosure or distribution is prohibited without express written consent of Kontron. If you are not the intended recipient, please contact the sender and destroy all copies of the original message and enclosed attachments.
Diese E-Mail enthält vertrauliche und/oder rechtlich geschützte Informationen und ist Eigentum von Kontron. Die Verwendung und Weitergabe von jeglichen Inhalten ist ohne ausdrückliche schriftliche Genehmigung von Kontron strikt untersagt. Wenn Sie diese E-Mail irrtümlich erhalten haben, informieren Sie bitte sofort den Absender und vernichten diese Mail und enthaltene Dokumente.
Hi Claus,
On 09.05.2008 15:02, Claus Gindhart wrote:
This patch adds support for the SPI Chips Atmel AT25DF32, ST M25P80, ST M25P16, M25P32, ST M25P64 attached to the ICH9. Because chipset plays an important role in communicating with these chips, it was not possible to integrate this support into the already existing spi.c This module was tested with the devices as mentioned above, but it should be easy to expand it for other SPI chips attached to an ICH.
Signed-off-by: Claus Gindhart claus.gindhart@kontron.com
Thank you very much for your contribution! I'll review the code in the next few days. There are a few merging errors in ichspi.c which make compilation impossible. I have highlighted them below. Could you resend the patch with those merging errors fixed?
I can see what you mean with the problems of integrating your code into spi.c. The redesign I have in mind fixes that.
Regards, Carl-Daniel
Index: ichspi.c
--- ichspi.c (revision 0) +++ ichspi.c (revision 0) @@ -0,0 +1,665 @@ +/*
- This file is part of the flashrom project.
- Initially implemented by Stefan Wildemann stefan.wildemann@kontron.com
- Adapted to flashrom by Claus Gindhart claus.gindhart@kontron.com
- 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
- */
+/*
- This module is designed for supporting the devices
- ST M25P40
- ST M25P80
- ST M25P16
- ST M25P32
- ST M25P64
- AT 25DF321
- */
+#define DEVELOPPERS_DEBUG
+#include <stdio.h> +#include <string.h> +#include <stdint.h> +#include <sys/mman.h> +#include <pci/pci.h> +#include "flash.h"
+/* Includes from the testsw_ng module */ +#include "ichspiacc.h"
+/* HW access functions */
+/* Current flash descriptor, to avoid passing it as argument everywhere */ +static struct flashchip *curflash; +static OPCODES *curopcodes;
+static inline uint8_t REGREAD8(int X) +{
- volatile uint8_t regval;
- regval = *(volatile uint8_t *)(curflash->virtual_registers + X);
- return regval;
+}
+static inline uint16_t REGREAD16(int X) +{
- volatile uint16_t regval;
- regval = *(volatile uint16_t *)(curflash->virtual_registers + X);
- return regval;
+}
+static inline uint32_t REGREAD32(int X) +{
- volatile uint32_t regval;
- regval = *(volatile uint32_t *)(curflash->virtual_registers + X);
- return regval;
+}
+#define REGWRITE32(X,Y) (*(uint32_t *)(curflash->virtual_registers+X)=Y) +#define REGWRITE16(X,Y) (*(uint16_t *)(curflash->virtual_registers+X)=Y) +#define REGWRITE8(X,Y) (*(uint8_t *)(curflash->virtual_registers+X)=Y)
+/* Common SPI functions */ +static int ProgramOpcodes(OPCODES * op); +static int RunOpcode(uint8_t nr, OPCODE op, uint32_t offset, uint8_t datalength,
uint8_t * data);
+static int read_page_ichspi(struct flashchip *flash, uint8_t * buf, int Offset); +static int is_supported_chipset();
+OPCODES O_ST_M25P = {
- {
SPI_ST_M25P_COMMAND_WRITE_ENABLE,
0
- },
- {
{SPI_ST_M25P_COMMAND_WRITE, SPI_OPCODE_TYPE_WRITE_WITH_ADDRESS, 1}, // Write Byte
{SPI_ST_M25P_COMMAND_READ, SPI_OPCODE_TYPE_READ_WITH_ADDRESS, 0}, // Read Data
{SPI_ST_M25P_COMMAND_ERASE, SPI_OPCODE_TYPE_WRITE_WITH_ADDRESS, 1}, // Erase 4k Sector
{SPI_ST_M25P_COMMAND_READ_STATUS, SPI_OPCODE_TYPE_READ_NO_ADDRESS, 0}, // Read Device Status Reg
{SPI_ST_M25P_COMMAND_RES_PD, SPI_OPCODE_TYPE_READ_WITH_ADDRESS, 0}, // Resume Deep Power-Down
{SPI_ST_M25P_COMMAND_WRITE_S, SPI_OPCODE_TYPE_WRITE_NO_ADDRESS, 1}, // Write Status Register
{SPI_ST_M25P_COMMAND_JDEC, SPI_OPCODE_TYPE_READ_NO_ADDRESS, 0}, // Read JDEC ID
{SPI_ST_M25P_COMMAND_BULK_ERASE, SPI_OPCODE_TYPE_WRITE_NO_ADDRESS, 1}, // Bulk erase
}
+};
+OPCODES O_AT_25DF = {
- {
SPI_ST_M25P_COMMAND_WRITE_ENABLE,
0
- },
- {
{SPI_ST_M25P_COMMAND_WRITE, SPI_OPCODE_TYPE_WRITE_WITH_ADDRESS, 1}, // Write Byte
{SPI_ST_M25P_COMMAND_READ, SPI_OPCODE_TYPE_READ_WITH_ADDRESS, 0}, // Read Data
{SPI_ST_M25P_COMMAND_ERASE, SPI_OPCODE_TYPE_WRITE_WITH_ADDRESS, 1}, // Erase Sector
{SPI_ST_M25P_COMMAND_READ_STATUS, SPI_OPCODE_TYPE_READ_NO_ADDRESS, 0}, // Read Device Status Reg
{SPI_ST_M25P_COMMAND_RES_PD, SPI_OPCODE_TYPE_READ_WITH_ADDRESS, 0}, // Resume Deep Power-Down
{SPI_ST_M25P_COMMAND_WRITE_S, SPI_OPCODE_TYPE_WRITE_NO_ADDRESS, 1}, // Write Status Register
{SPI_ST_M25P_COMMAND_JDEC, SPI_OPCODE_TYPE_READ_NO_ADDRESS, 0}, // Read JDEC ID
{SPI_ST_M25P_COMMAND_BULK_ERASE, SPI_OPCODE_TYPE_WRITE_NO_ADDRESS, 1}, // Bulk erase
}
+};
+int ProgramOpcodes(OPCODES * op) +{
- uint8_t a;
+#ifdef DEVELOPPERS_DEBUG
- printf_debug("ProgramOpcodes:");
+#endif
- uint16_t temp16;
- uint32_t temp32;
- /* Program Prefix Opcodes */
- temp16 = 0;
- /* 0:7 Prefix Opcode 1 */
- temp16 = (op->preop[0]);
- /* 8:16 Prefix Opcode 2 */
- temp16 |= ((uint16_t) op->preop[1]) << 8;
- REGWRITE16(REG_PREOP, temp16);
+#ifdef DEVELOPPERS_DEBUG
- printf("REG_PREOP == 0x%04X (0x%04X)\n", REGREAD16(REG_PREOP), temp16);
+#endif
- /*Program Opcode Types 0 - 7 */
- temp16 = 0;
- for (a = 0; a < 8; a++) {
temp16 |= ((uint16_t) op->opcode[a].spi_type) << (a * 2);
- }
- REGWRITE16(REG_OPTYPE, temp16);
+#ifdef DEVELOPPERS_DEBUG
- printf("REG_OPTYPE = 0x%04X (0x%04X)\n", REGREAD16(REG_OPTYPE), temp16);
+#endif
- /*Program Allowable Opcodes 0 - 3 */
- temp32 = 0;
- for (a = 0; a < 4; a++) {
temp32 |= ((uint32_t) op->opcode[a].opcode) << (a * 8);
- }
- REGWRITE32(REG_OPMENU, temp32);
- /*Program Allowable Opcodes 4 - 7 */
- temp32 = 0;
- for (a = 4; a < 8; a++) {
temp32 |= ((uint32_t) op->opcode[a].opcode) << ((a - 4) * 8);
- }
- REGWRITE32(REG_OPMENU + 4, temp32);
+#ifdef DEVELOPPERS_DEBUG
- printf("REG_OPMENU = 0x%08X%08X\n", REGREAD32(REG_OPMENU + 4),
REGREAD32(REG_OPMENU));
- printf("ProgramOpcodes end\n");
+#endif
- return 0;
+}
+int RunOpcode(uint8_t nr, OPCODE op, uint32_t offset, uint8_t datalength,
uint8_t * data)
+{ +#ifdef DEVELOPPERS_DEBUG
- printf_debug("RunOpcode::");
+#endif
- int write_cmd = 0;
- uint32_t temp32;
- uint32_t a;
- /* Is it a write command? */
- if ((op.spi_type == SPI_OPCODE_TYPE_WRITE_NO_ADDRESS)
|| (op.spi_type == SPI_OPCODE_TYPE_WRITE_WITH_ADDRESS)) {
write_cmd = 1;
printf_debug("Write command detected!");
- }
- /* Programm Offset in Flash into FADDR */
- REGWRITE32(REG_FADDR, (offset & 0x00FFFFFF)); /*SPI addresses are 24 BIT only */
- printf_debug("REG_FADDR == 0x%08X (0x%08X)", REGREAD32(REG_FADDR),
offset);
- /* Program data into FDATA0 to N */
- if (write_cmd && (datalength != 0)) {
printf_debug("Going to write data bytes to FDATA0");
temp32 = 0;
for (a = 0; a < datalength; a++) {
if ((a % 4) == 0) {
temp32 = 0;
}
temp32 |= ((uint32_t) data[a]) << ((a % 4) * 8);
if ((a % 4) == 3) {
REGWRITE32(REG_FDATA0 + (a - (a % 4)), temp32);
printf_debug("REG_FDATA0 + 0x%X) == 0x%08X",
a - (a % 4),
REGREAD32(REG_FDATA0 +
(a - (a % 4))));
}
}
if (((a - 1) % 4) != 3) {
printf_debug("writing rest");
REGWRITE32(REG_FDATA0 + ((a - 1) - ((a - 1) % 4)),
temp32);
printf_debug("REG_FDATA0 + 0x%X) == 0x%08X",
(a - 1) - ((a - 1) % 4),
REGREAD32(REG_FDATA0 +
((a - 1) - ((a - 1) % 4))));
}
- }
- /* Assemble SSFS + SSFC */
- temp32 = 0;
- /* clear error status registers */
- temp32 |= (SSFS_CDS + SSFS_FCERR);
- /* USE 20 MhZ */
- temp32 |= SSFC_SCF_20MHZ;
- if (datalength != 0) {
uint32_t datatemp;
temp32 |= SSFC_DS;
datatemp = ((uint32_t) ((datalength - 1) & 0x3f)) << (8 + 8);
//printf_debug("datatemp = 0x%08X", datatemp);
temp32 |= datatemp;
- }
- /* Select opcode */
- temp32 |= ((uint32_t) (nr & 0x07)) << (8 + 4);
- /* Handle Atomic */
- if (op.atomic != 0) {
printf_debug("Atomic operation detected");
/* Select atomic command */
temp32 |= SSFC_ACS;
/* Selct prefix opcode */
if ((op.atomic - 1) == 1) {
/*Select prefix opcode 2 */
temp32 |= SSFC_SPOP;
}
- }
- /* Start */
- temp32 |= SSFC_SCGO;
- /* write it */
- //printf_debug("going to write 0x%08X to REG_SSFS", temp32);
- REGWRITE32(REG_SSFS, temp32);
- /*wait for cycle complete */
- while ((REGREAD32(REG_SSFS) & SSFS_CDS) == 0) {
/*TODO; Do something that this can't lead into an endless loop. but some
* commands may cause this to be last more than 30 seconds */
- }
- //printf_debug("REG_SSFS == 0x%08X", REGREAD32(REG_SSFS));
- if ((REGREAD32(REG_SSFS) & SSFS_FCERR) != 0) {
printf_debug("Transaction error!");
return 1;
- }
- if ((!write_cmd) && (datalength != 0)) {
printf_debug("Going to read data from FDATA0");
for (a = 0; a < datalength; a++) {
if ((a % 4) == 0) {
temp32 = REGREAD32(REG_FDATA0 + (a));
printf_debug("REG_FDATA0 + 0x%X == 0x%08X", (a),
REGREAD32(REG_FDATA0 + (a)));
}
data[a] =
(temp32 & (((uint32_t) 0xff) << ((a % 4) * 8))) >>
((a % 4) * 8);
}
- }
- return 0;
+}
+static volatile uint8_t *mmap_base = 0;
+int map_ich_registers(struct flashchip *flash) +{
- int offset_from_page = (RCRB + SPIBAR) % 0x1000;
- int base_of_page = (RCRB + SPIBAR) & ~0xFFF;
- mmap_base = mmap(0, 0x1000, PROT_WRITE | PROT_READ, MAP_SHARED,
fd_mem, (off_t) base_of_page);
- if (mmap_base == MAP_FAILED) {
perror("Can't mmap registers using " MEM_DEV);
return -1;
- }
- flash->virtual_registers = mmap_base + offset_from_page;
- return 0;
+}
+void munmap_ich_registers(void) +{
- if (mmap_base) {
munmap((void *)mmap_base, 0x1000);
mmap_base = 0;
- }
+}
+/* check for ICH8/9 chipset */ +static int is_supported_chipset() +{
- struct pci_dev *temp;
- struct pci_filter filter;
- uint8_t tmpid;
- pci_filter_init(NULL, &filter);
- filter.vendor = 0x8086; /* Vendor Intel */
- for (temp = pacc->devices; temp; temp = temp->next) {
if (pci_filter_match(&filter, temp)) {
tmpid = (temp->device_id & 0xff00) >> 8; /* upper byte of device-id */
/* return success if ICH8/9 found */
if ((tmpid == 0x28) || (tmpid == 0x29))
return 1;
}
- }
- return 0;
+}
+/* ST-chips with deprecated 'Electronic Signature' and no JEDEC id support */ +/* untested */ +int probe_ichspi_stm25_sig(struct flashchip *flash) +{
- uint8_t byte[65];
- curflash = flash;
- curopcodes = &O_ST_M25P;
- if (!is_supported_chipset())
return 0;
- if (map_ich_registers(flash)) {
perror("Error mapping ICH registers\n");
return 0;
- }
- ProgramOpcodes(curopcodes);
- /* resume from Deep Power-Down mode and read Electronic Signature (4) */
- if (RunOpcode(4, curopcodes->opcode[4], 0x00000000, 1, byte) != 0) {
perror("RunOpcode");
munmap_ich_registers();
return 0;
- }
- printf_debug("ReadID Result %02x", byte[0]);
- /* FIXME: use defines for the signatures */
- if (!
((byte[0] == 0x12) || (byte[0] == 0x13) || (byte[0] == 0x14)
|| (byte[0] == 0x15) || (byte[0] == 0x16))) {
munmap_ich_registers();
return 0;
- }
- printf_debug("Chip detected, Electronic Signature 0x%02x\n", byte[0]);
- return 1;
+}
+/* untested */ +int probe_ichspi_stm25(struct flashchip *flash) +{
- uint8_t byte[65];
- uint32_t largeid1;
- curflash = flash;
- curopcodes = &O_ST_M25P;
- if (!is_supported_chipset())
return 0;
- if (map_ich_registers(flash)) {
perror("Error mapping ICH registers\n");
return 0;
- }
- /* initialize controller with opcodes */
- ProgramOpcodes(curopcodes);
- /* resume from Deep Power-Down mode (4) */
- if (RunOpcode(4, curopcodes->opcode[4], 0x00000000, 0, byte) != 0) {
perror("RunOpcode");
munmap_ich_registers();
return 0;
- }
- /* do a read JEDEC id (6) */
- if (RunOpcode(6, curopcodes->opcode[6], 0x00000000, 3, byte) != 0) {
perror("RunOpcode");
munmap_ich_registers();
return 0;
- }
+<<<<<<< ichspi.c
The line above indicates a merging error.
- printf("ReadID Result %02x %02x %02x %02x\n",byte[0],byte[1],byte[2],byte[3]);
- if(!((byte[0] == 0x13) || (byte[0] == 0x14) || (byte[0] == 0x15) || (byte[0] == 0x16)))
- {
+=======
The line above indicates a merging error.
+#ifdef DEVELOPPERS_DEBUG
- printf_debug("JEDEC-ID Result %02x %02x %02x\n", byte[0], byte[1],
byte[2]);
+#endif
- if (byte[0] != flash->manufacture_id) {
munmap_ich_registers();
return 0;
- }
- largeid1 = (byte[1] << 8) | byte[2];
- if (largeid1 != flash->model_id) {
+>>>>>>> 1.7
The line above indicates a merging error.
munmap_ich_registers();
return 0;
- }
+<<<<<<< ichspi.c +=======
The 2 lines above indicates a merging error.
- printf_debug("Chip detected, Jedec ID 0x%x\n", largeid1);
- return 1;
+}
+int probe_ichspi_at25df(struct flashchip *flash) +{
- uint8_t byte[65];
- uint32_t largeid1;
- curflash = flash;
- curopcodes = &O_AT_25DF;
- if (!is_supported_chipset())
return 0;
- if (map_ich_registers(flash)) {
perror("Error mapping ICH registers\n");
return 0;
- }
- /* initialize controller with opcodes */
- ProgramOpcodes(curopcodes);
- /* resume from Deep Power-Down mode (4) */
- if (RunOpcode(4, curopcodes->opcode[4], 0x00000000, 0, byte) != 0) {
perror("RunOpcode");
munmap_ich_registers();
return 0;
- }
+>>>>>>> 1.7
The line above indicates a merging error.
- /* do a read JEDEC id (6) */
- if (RunOpcode(6, curopcodes->opcode[6], 0x00000000, 3, byte) != 0) {
perror("RunOpcode");
munmap_ich_registers();
return 0;
- }
+#ifdef DEVELOPPERS_DEBUG
- printf_debug("JEDEC-ID Result %02x %02x %02x\n", byte[0], byte[1],
byte[2]);
+#endif
- if (byte[0] != flash->manufacture_id) {
munmap_ich_registers();
return 0;
- }
- largeid1 = (byte[1] << 8) | byte[2];
- if (largeid1 != flash->model_id) {
munmap_ich_registers();
return 0;
- }
- /* perform global unprotect by writing 0 into whole status reg */
- byte[0] = 0;
- if (RunOpcode(5, curopcodes->opcode[5], 0x00000000, 1, byte) != 0) {
printf_debug("Error global unprotect\n");
return -1;
- }
- printf_debug("Chip detected, Jedec ID 0x%x\n", largeid1);
- return 1;
+}
+int erase_block_ichspi(struct flashchip *flash, int offset) +{ +#ifdef DEVELOPPERS_DEBUG
- printf("Spi_Erase,Offset=%d,sectors=%d\n", offset, 1);
+#endif
- // TODO: Is this correct ?
- if (RunOpcode(2, curopcodes->opcode[2], offset, 0, NULL) != 0) {
printf_debug("Error erasing sector at 0x%x", offset);
return -1;
- }
- printf("DONE BLOCK 0x%x\n", offset);
- return 0;
+}
+static int read_page_ichspi(struct flashchip *flash, uint8_t * buf, int Offset) +{
- int page_size = flash->page_size;
- uint32_t remaining = flash->page_size;
- int a;
+#ifdef DEVELOPPERS_DEBUG
- printf("Spi_Read,Offset=%d,number=%d,buf=%p\n", Offset, page_size, buf);
+#endif
- for (a = 0; a < page_size; a += MAXDATABYTES) {
if (remaining < MAXDATABYTES) {
if (RunOpcode
(1, curopcodes->opcode[1],
Offset + (page_size - remaining), remaining,
&buf[page_size - remaining]) != 0) {
printf_debug("Error reading");
return 1;
}
remaining = 0;
} else {
if (RunOpcode
(1, curopcodes->opcode[1],
Offset + (page_size - remaining), MAXDATABYTES,
&buf[page_size - remaining]) != 0) {
printf_debug("Error reading");
return 1;
}
remaining -= MAXDATABYTES;
}
- }
- return 0;
+}
+static int write_page_ichspi(struct flashchip *flash, uint8_t * bytes,
int Offset)
+{
- int page_size = flash->page_size;
- uint32_t remaining = page_size;
- int a;
+#ifdef DEVELOPPERS_DEBUG
- printf("Spi_Write,Offset=%d,number=%d,buf=%p\n", Offset, page_size,
bytes);
+#endif
- for (a = 0; a < page_size; a += MAXDATABYTES) {
if (remaining < MAXDATABYTES) {
if (RunOpcode
(0, curopcodes->opcode[0],
Offset + (page_size - remaining), remaining,
&bytes[page_size - remaining]) != 0) {
printf_debug("Error writing");
return 1;
}
remaining = 0;
} else {
if (RunOpcode
(0, curopcodes->opcode[0],
Offset + (page_size - remaining), MAXDATABYTES,
&bytes[page_size - remaining]) != 0) {
printf_debug("Error writing");
return 1;
}
remaining -= MAXDATABYTES;
}
- }
- return 0;
+}
+/* Bulk erase
- */
+int erase_ichspi(struct flashchip *flash) +{
- printf_debug("Bulk erase requested");
- if (RunOpcode(7, curopcodes->opcode[7], 0, 0, NULL) != 0) {
printf_debug("Error erasing sector");
return 1;
- }
- return 0;
+}
+int read_ichspi(struct flashchip *flash, uint8_t * buf) +{
- int i, rc = 0;
- int total_size = flash->total_size * 1024;
- int page_size = flash->page_size;
- for (i = 0; (i < total_size / page_size) && (rc == 0); i++) {
rc = read_page_ichspi(flash, (void *)(buf + i * page_size),
i * page_size);
- }
- return rc;
+}
+int write_ichspi(struct flashchip *flash, uint8_t * buf) +{
- int i, rc = 0;
- int total_size = flash->total_size * 1024;
- int page_size = flash->page_size;
- printf("Programming page: \n");
- for (i = 0; (i < total_size / page_size) && (rc == 0); i++) {
printf
("\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b");
/* Auto Skip Blocks, which already contain the desired data
* Faster, because we only write, what has changed
* More secure, because blocks, which are excluded
* (with the exclude or layout feature)
* are not erased and rewritten; data is retained also
* in sudden power off situations
*/
if (!memcmp((void *)(buf + i * page_size),
(void *)(flash->virtual_memory + i * page_size),
page_size)) {
printf("SKIPPED\n");
continue;
}
rc = erase_block_ichspi(flash, i * page_size);
if (!rc)
write_page_ichspi(flash, (void *)(buf + i * page_size),
i * page_size);
- }
- printf("\n");
- munmap_ich_registers();
- return rc;
+}