Signed-off-by: Amit Uttamchandani amit.uttam@gmail.com --- programmer.h | 1 + satamv.c | 151 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 152 insertions(+)
diff --git a/programmer.h b/programmer.h index d4d1f90..0259022 100644 --- a/programmer.h +++ b/programmer.h @@ -527,6 +527,7 @@ enum spi_controller { #if CONFIG_USBBLASTER_SPI == 1 SPI_CONTROLLER_USBBLASTER, #endif + SPI_CONTROLLER_SATAMV, };
#define MAX_DATA_UNSPECIFIED 0 diff --git a/satamv.c b/satamv.c index 3065f0c..16787b8 100644 --- a/satamv.c +++ b/satamv.c @@ -22,9 +22,15 @@ #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 +38,46 @@ uint16_t mv_iobar; 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 SPI_FLASH_CONTROL 0x0c800 +#define SPI_FLASH_ADDRESS 0x0c804 +#define SPI_FLASH_WRITE_DATA 0x0c808 +#define SPI_FLASH_READ_DATA 0x0c80c #define EXPANSION_ROM_BAR_CONTROL 0x00d2c #define PCI_BAR2_CONTROL 0x00c08 #define GPIO_PORT_CONTROL 0x104f0
+static unsigned int spi_write_256_chunksize = 256; + +static int satamv_spi_send_command(struct flashctx *flash, unsigned int writecnt, + unsigned int readcnt, + const unsigned char *writearr, + unsigned char *readarr); +static int satamv_spi_write_256(struct flashctx *flash, uint8_t *buf, + unsigned int start, unsigned int len); 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 = MAX_DATA_READ_UNLIMITED, + .max_data_write = MAX_DATA_UNSPECIFIED, + .command = satamv_spi_send_command, + .multicommand = default_spi_send_multicommand, + .read = default_spi_read, + .write_256 = satamv_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 @@ static const struct par_programmer par_programmer_satamv = { .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 + SPI_FLASH_CONTROL); + msg_pspew("SPI Flash Control: 0x%08x\n", tmp); + + tmp = pci_mmio_readl(mv_bar + SPI_FLASH_ADDRESS); + msg_pspew("SPI Flash Address: 0x%08x\n", tmp); + + tmp = pci_mmio_readl(mv_bar + SPI_FLASH_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 @@ int satamv_init(void) struct pci_dev *dev = NULL; uintptr_t addr; uint32_t tmp; + uint16_t id;
if (rget_io_perms()) return 1; @@ -87,6 +158,12 @@ int satamv_init(void) 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,80 @@ static uint8_t satamv_chip_readb(const struct flashctx *flash, 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) +{ + uint8_t busy; + int i; + + msg_pspew("%s:", __func__); + msg_pspew(" SPI Flash Control Start: 0x%04x", pci_mmio_readl(mv_bar + SPI_FLASH_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 { + busy = pci_mmio_readl(mv_bar + SPI_FLASH_CONTROL); + msg_pspew("SPI Flash Control during busy wait (while loop 1): 0x%04x\n", busy); + busy &= 0x1; + } while (busy); + + if (readcnt > 4) { + msg_pinfo("%s called with unsupported readcnt %i.\n", + __func__, readcnt); + return SPI_INVALID_LENGTH; + } + + /* Write FFs to WRITE_DATA and READ_DATA */ + pci_mmio_writel(0xffffffff, mv_bar + SPI_FLASH_WRITE_DATA); + pci_mmio_writel(0xffffffff, mv_bar + SPI_FLASH_READ_DATA); + + switch (writecnt) { + case 1: + pci_mmio_writel((0x00000005 | (writearr[0]<<8) | (readcnt<<4)), mv_bar + SPI_FLASH_CONTROL); + break; + case 2: + break; + case 4: + break; + case 5: + break; + default: + msg_pinfo("%s called with unsupported writecnt %i.\n", + __func__, writecnt); + return SPI_INVALID_LENGTH; + } + + if (readcnt > 0) { + do { + busy = pci_mmio_readl(mv_bar + SPI_FLASH_CONTROL); + msg_pspew("SPI Flash Control during busy wait (while loop 2): 0x%04x\n", busy); + busy &= 0x1; + } while (busy); + + /* Read from SPI Flash */ + pci_mmio_writel((0x00000005 | (readcnt<<4)), mv_bar + SPI_FLASH_CONTROL); + msg_pspew("SPI Return: 0x%04x\n", pci_mmio_readl(mv_bar + SPI_FLASH_READ_DATA)); + + for (i = 0; i < readcnt; i++) + readarr[i] = pci_mmio_readl(mv_bar + SPI_FLASH_READ_DATA); + } + + msg_pspew("SPI Flash Control End: 0x%04x\n", pci_mmio_readl(mv_bar + SPI_FLASH_CONTROL)); + + return 0; +} + +static int satamv_spi_write_256(struct flashctx *flash, uint8_t *buf, + unsigned int start, unsigned int len) +{ + return spi_write_chunked(flash, buf, start, len, + spi_write_256_chunksize); +} + #else #error PCI port I/O access is not supported on this architecture yet. #endif