[flashrom] [PATCH] Initial support for Marvell 88SE94xx v1

Carl-Daniel Hailfinger c-d.hailfinger.devel.2006 at gmx.net
Mon Apr 28 08:45:14 CEST 2014


Am 27.04.2014 05:22 schrieb Stefan Tauner:
> On Sun, 27 Apr 2014 02:14:24 +0200
> Carl-Daniel Hailfinger <c-d.hailfinger.devel.2006 at gmx.net> wrote:
>
>> Index: flashrom-satamv_spi_mv94xx/programmer.h
>> ===================================================================
>> --- flashrom-satamv_spi_mv94xx/programmer.h	(Revision 1780)
>> +++ flashrom-satamv_spi_mv94xx/programmer.h	(Arbeitskopie)
>> @@ -527,6 +527,7 @@
>>  #if CONFIG_USBBLASTER_SPI == 1
>>  	SPI_CONTROLLER_USBBLASTER,
>>  #endif
>> +	SPI_CONTROLLER_SATAMV,
>>  };
> Needs to be guarded too IMHO

Definitely, thanks for catching this. The arch dependencies on
i386/x86_64 are broken as well, but I don't have a quick fix for this
because one half of the driver has the dependency, the other half doesn't.

Amit confirmed that probe works: "Found Winbond flash chip "W25X40" (512
kB, SPI) on satamv." However, reading failed due to incorrect limits in
max_data_read and max_data_write.

New version, read should work fine. Write might work, but I'd rather
wait a bit for that unless we know the image is correct and the flash
chip can be accessed easily with another external programmer.

Signed-off-by: Carl-Daniel Hailfinger <c-d.hailfinger.devel.2006 at gmx.net>

Index: flashrom-satamv_spi_mv94xx/satamv.c
===================================================================
--- flashrom-satamv_spi_mv94xx/satamv.c	(Revision 1780)
+++ flashrom-satamv_spi_mv94xx/satamv.c	(Arbeitskopie)
@@ -1,8 +1,8 @@
 /*
  * This file is part of the flashrom project.
  *
- * Copyright (C) 2010,2011 Carl-Daniel Hailfinger
- * Written by Carl-Daniel Hailfinger for Angelbird Ltd.
+ * Copyright (C) 2010,2011,2014 Carl-Daniel Hailfinger
+ * Parts written by Carl-Daniel Hailfinger 2010, 2011 for Angelbird Ltd.
  *
  * 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
@@ -19,12 +19,20 @@
  */
 
 /* Datasheets are not public (yet?) */
+
+// FIXME: This arch limitation is only valid for the 88SX60 series due to I/O port access
 #if defined(__i386__) || defined(__x86_64__)
 
 #include <stdlib.h>
+#include <string.h>
+#include <sys/types.h>
+#include <sys/stat.h>
 #include "flash.h"
 #include "programmer.h"
+#include "chipdrivers.h"
 #include "hwaccess.h"
+#include "spi.h"
+#include <unistd.h>
 
 uint8_t *mv_bar;
 uint16_t mv_iobar;
@@ -32,20 +40,44 @@
 const struct dev_entry satas_mv[] = {
 	/* 88SX6041 and 88SX6042 are the same according to the datasheet. */
 	{0x11ab, 0x7042, OK, "Marvell", "88SX7042 PCI-e 4-port SATA-II"},
+	{0x1b4b, 0x9445, OK, "Marvell", "88SE9445 PCI-e 4-port SAS/SATA 6 Gbps"},
 
 	{0},
 };
 
 #define NVRAM_PARAM			0x1045c
 #define FLASH_PARAM			0x1046c
+#define EXPANSION_ROM_WINDOW0_REMAP	0x004c8
+#define MV94XX_SPI_CONTROL		0x0c800
+#define MV94XX_SPI_ADDRESS		0x0c804
+#define MV94XX_SPI_WRITE_DATA		0x0c808
+#define MV94XX_SPI_READ_DATA		0x0c80c
 #define EXPANSION_ROM_BAR_CONTROL	0x00d2c
 #define PCI_BAR2_CONTROL		0x00c08
 #define GPIO_PORT_CONTROL		0x104f0
 
+#define MV94XX_SPI_DATA_DIR_READ	(1 << 2)
+#define MV94XX_SPI_ADDR_PHASE		(1 << 1)
+#define MV94XX_SPI_START		(1 << 0)
+
+static int satamv_spi_send_command(struct flashctx *flash, unsigned int writecnt, unsigned int readcnt,
+				   const unsigned char *writearr, unsigned char *readarr);
 static void satamv_chip_writeb(const struct flashctx *flash, uint8_t val,
 			       chipaddr addr);
 static uint8_t satamv_chip_readb(const struct flashctx *flash,
 				 const chipaddr addr);
+
+static const struct spi_programmer spi_programmer_satamv = {
+	.type		= SPI_CONTROLLER_SATAMV,
+	.max_data_read	= 4,
+	.max_data_write	= 4,
+	.command	= satamv_spi_send_command,
+	.multicommand	= default_spi_send_multicommand,
+	.read		= default_spi_read,
+	.write_256	= default_spi_write_256,
+	.write_aai	= default_spi_write_aai,
+};
+
 static const struct par_programmer par_programmer_satamv = {
 		.chip_readb		= satamv_chip_readb,
 		.chip_readw		= fallback_chip_readw,
@@ -57,6 +89,44 @@
 		.chip_writen		= fallback_chip_writen,
 };
 
+static int init_94xx(struct pci_dev *dev)
+{
+	uintptr_t addr;
+	uint32_t tmp;
+
+	msg_pspew("Initializing 94xx\n");
+
+	addr = pcidev_readbar(dev, PCI_BASE_ADDRESS_2);
+	if (!addr)
+		return 1;
+	msg_pspew("addr=0x%08" PRIXPTR "\n", addr);
+
+	mv_bar = rphysmap("Marvell 88SE94xx registers", addr, 0x40000);
+	if (mv_bar == ERROR_PTR)
+		return 1;
+	msg_pspew("mv_bar=%p\n", mv_bar);
+
+	/* Read some registers for fun.
+	 * TODO: Remove once everything is working
+	 */
+	tmp = pci_mmio_readl(mv_bar + EXPANSION_ROM_WINDOW0_REMAP);
+	msg_pspew("PCIe Expansion ROM Window Remap: 0x%04x\n", tmp);
+
+	tmp = pci_mmio_readl(mv_bar + MV94XX_SPI_CONTROL);
+	msg_pspew("SPI Flash Control: 0x%08x\n", tmp);
+
+	tmp = pci_mmio_readl(mv_bar + MV94XX_SPI_ADDRESS);
+	msg_pspew("SPI Flash Address: 0x%08x\n", tmp);
+
+	tmp = pci_mmio_readl(mv_bar + MV94XX_SPI_READ_DATA);
+	msg_pspew("SPI Flash Read Data: 0x%08x\n", tmp);
+
+	/* Register SPI programmer */
+	register_spi_programmer(&spi_programmer_satamv);
+
+	return 0;
+}
+
 /*
  * Random notes:
  * FCE#		Flash Chip Enable
@@ -78,6 +148,7 @@
 	struct pci_dev *dev = NULL;
 	uintptr_t addr;
 	uint32_t tmp;
+	uint16_t id;
 
 	if (rget_io_perms())
 		return 1;
@@ -87,6 +158,12 @@
 	if (!dev)
 		return 1;
 
+	id = dev->device_id;
+
+	/* If 9445, do separate init */
+	if (id == 0x9445)
+		return init_94xx(dev);
+
 	addr = pcidev_readbar(dev, PCI_BASE_ADDRESS_0);
 	if (!addr)
 		return 1;
@@ -192,6 +269,118 @@
 	return satamv_indirect_chip_readb(addr);
 }
 
+static int satamv_spi_send_command(struct flashctx *flash, unsigned int writecnt,
+		unsigned int readcnt,
+		const unsigned char *writearr,
+		unsigned char *readarr)
+{
+	uint32_t tmp;
+	uint32_t spi_cntl = 0x0;
+	int i;
+
+	if (writecnt == 0) {
+		msg_perr("%s: Tried to send an empty SPI command!\n"
+			 "Please report a bug at flashrom at flashrom.org\n", __func__);
+		return ERROR_FLASHROM_BUG;
+	}
+	if (!(((readcnt == 0) && (writecnt <= 8)) || (((writecnt == 1) || (writecnt == 4)) && (readcnt <= 4)))) {
+		msg_pinfo("%s called with unsupported readcnt(%i)/writecnt(%i) combination.\n", __func__,
+			  readcnt, writecnt);
+		return SPI_INVALID_LENGTH;
+	}
+
+	msg_pspew("%s:", __func__);
+	msg_pspew(" SPI Flash Control Start: 0x%08x", pci_mmio_readl(mv_bar + MV94XX_SPI_CONTROL));
+	msg_pspew(" writecnt=%d, readcnt=%d\n", writecnt, readcnt);
+
+	for (i = 0; i < writecnt; i++)
+		msg_pspew("writearr[%d]=0x%x\n", i, writearr[i]);
+
+	do {
+		tmp = pci_mmio_readl(mv_bar + MV94XX_SPI_CONTROL);
+		msg_pspew("SPI Flash Control during busy wait (while loop 1): 0x%08x\n", tmp);
+		tmp &= 0x1;
+	} while (tmp);
+
+
+	/* Clear WRITE_DATA and READ_DATA. Unneeded, but a great help for debugging. */
+	pci_mmio_writel(0xffffffff, mv_bar + MV94XX_SPI_WRITE_DATA);
+	pci_mmio_writel(0xffffffff, mv_bar + MV94XX_SPI_READ_DATA);
+
+	if (readcnt > 0) {
+		switch (writecnt) {
+		case 4:
+			spi_cntl |= MV94XX_SPI_ADDR_PHASE;
+			pci_mmio_writel((writearr[1] << 16) | (writearr[2] << 8) | writearr[3],
+					mv_bar + MV94XX_SPI_ADDRESS);
+		case 1:
+			break;
+		}
+		spi_cntl |= MV94XX_SPI_DATA_DIR_READ;
+		spi_cntl |= readcnt << 4;
+		spi_cntl |= writearr[0] << 8;
+	} else {
+		uint32_t wr_data = 0xffffffff;
+		switch (writecnt) {
+		case 8:
+			wr_data = (writearr[7] << 24) | (writearr[6] << 16) | (writearr[5] << 8) | writearr[4];
+			break;
+		case 7:
+			wr_data = (writearr[6] << 16) | (writearr[5] << 8) | writearr[4];
+			break;
+		case 6:
+			wr_data = (writearr[5] << 8) | writearr[4];
+			break;
+		case 5:
+			wr_data = (writearr[4] << 24) | (writearr[3] << 16) | (writearr[2] << 8) | writearr[1];
+			break;
+		case 4:
+			wr_data = (writearr[3] << 16) | (writearr[2] << 8) | writearr[1];
+			break;
+		case 3:
+			wr_data = (writearr[2] << 8) | writearr[1];
+			break;
+		case 2:
+			wr_data = writearr[1];
+			break;
+		case 1:
+			/* Only a command, no data. */
+			break;
+		}
+		if (writecnt >= 6) {
+			/* Have to use the address field. */
+			spi_cntl |= MV94XX_SPI_ADDR_PHASE;
+			pci_mmio_writel((writearr[1] << 16) | (writearr[2] << 8) | writearr[3],
+					mv_bar + MV94XX_SPI_ADDRESS);
+			spi_cntl |= (writecnt - 3) << 4;
+		} else {
+			spi_cntl |= writecnt << 4;
+		}
+		pci_mmio_writel(wr_data, mv_bar + MV94XX_SPI_WRITE_DATA);
+		spi_cntl |= writearr[0] << 8;
+	}
+
+	pci_mmio_writel(spi_cntl, mv_bar + MV94XX_SPI_CONTROL);
+	pci_mmio_writel(spi_cntl | MV94XX_SPI_START, mv_bar + MV94XX_SPI_CONTROL);
+			
+	do {
+		tmp = pci_mmio_readl(mv_bar + MV94XX_SPI_CONTROL);
+		msg_pspew("SPI Flash Control during busy wait (while loop 1): 0x%08x\n", tmp);
+		tmp &= 0x1;
+	} while (tmp);
+
+
+	if (readcnt > 0) {
+		tmp = pci_mmio_readl(mv_bar + MV94XX_SPI_READ_DATA);
+		for (i = 0; i < readcnt; i++)
+			readarr[i] = (tmp >> (i * 8)) & 0xff;
+	}
+
+	msg_pspew("SPI Flash Control End: 0x%08x\n", pci_mmio_readl(mv_bar + MV94XX_SPI_CONTROL));
+
+	return 0;
+}
+
 #else
 #error PCI port I/O access is not supported on this architecture yet.
 #endif
Index: flashrom-satamv_spi_mv94xx/programmer.h
===================================================================
--- flashrom-satamv_spi_mv94xx/programmer.h	(Revision 1780)
+++ flashrom-satamv_spi_mv94xx/programmer.h	(Arbeitskopie)
@@ -527,6 +527,9 @@
 #if CONFIG_USBBLASTER_SPI == 1
 	SPI_CONTROLLER_USBBLASTER,
 #endif
+#if CONFIG_SATAMV == 1
+	SPI_CONTROLLER_SATAMV,
+#endif
 };
 
 #define MAX_DATA_UNSPECIFIED 0

-- 
http://www.hailfinger.org/





More information about the flashrom mailing list