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@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@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@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