예제 #1
0
int spi_xfer(struct spi_slave *slave,
        const void *dout,
        unsigned int bitsout,
        void *din,
        unsigned int bitsin)
{
    unsigned int writeCnt = bitsout/8;
    unsigned int readCnt = bitsin/8;
    unsigned char* writeBuff = (unsigned char*)dout;
    unsigned char* readBuff = (unsigned char*)din;

    //
    // First byte is cmd opcode
    // and should not be sent through the buffer.
    //
    unsigned char cmd = *writeBuff++;

    writeCnt--;

    SPI_TRACE("%s, cmd=0x%02x, writecnt=%d, readcnt=%d\n", __func__, cmd, writeCnt, readCnt);
    writeb(cmd, spibar + 0);

    int ret = check_readwritecnt(writeCnt, readCnt);
    if (ret != 0)
        return ret;

    //
    // Set tx/rx count using  extended TxByteCount and RxByteCount registers
    //
    // SPIx1E SpiExtRegIndx
    // SPIx1F SpiExtRegData
    // SPIx1F_x05 TxByteCount
    // SPIx1F_x06 RxByteCoun
    //
    writeb(SPI_TX_BYTE_COUNT_IDX, spibar + SPI_EXT_REG_INDX);
    writeb(writeCnt, spibar + SPI_EXT_REG_DATA);

    writeb(SPI_RX_BYTE_COUNT_IDX, spibar + SPI_EXT_REG_INDX);
    writeb(readCnt, spibar + SPI_EXT_REG_DATA);

    SPI_TRACE("Filling buffer: ");
    int count;
    for (count = 0; count < writeCnt; count++) {
        SPI_TRACE("[%02x]", writeBuff[count]);
        writeb(writeBuff[count], spibar + SPI_FIFO_BASE + count);
    }
    SPI_TRACE("\n");

    execute_command();

    SPI_TRACE("Reading buffer: ");
    for (count = 0; count < readCnt; count++) {
        readBuff[count] = readb(spibar + SPI_FIFO_BASE + (writeCnt + count) % FIFO_SIZE_YANGTZE);
        SPI_TRACE("[%02x]", readBuff[count]);
    }
    SPI_TRACE("\n");

    return 0;
}
예제 #2
0
파일: sb600spi.c 프로젝트: 173210/flashrom
static int spi100_spi_send_command(struct flashctx *flash, unsigned int writecnt,
				  unsigned int readcnt,
				  const unsigned char *writearr,
				  unsigned char *readarr)
{
	/* First byte is cmd which can not be sent through the buffer. */
	unsigned char cmd = *writearr++;
	writecnt--;
	msg_pspew("%s, cmd=0x%02x, writecnt=%d, readcnt=%d\n", __func__, cmd, writecnt, readcnt);
	mmio_writeb(cmd, sb600_spibar + 0);

	int ret = check_readwritecnt(flash, writecnt, readcnt);
	if (ret != 0)
		return ret;

	/* Use the extended TxByteCount and RxByteCount registers. */
	mmio_writeb(writecnt, sb600_spibar + 0x48);
	mmio_writeb(readcnt, sb600_spibar + 0x4b);

	msg_pspew("Filling buffer: ");
	int count;
	for (count = 0; count < writecnt; count++) {
		msg_pspew("[%02x]", writearr[count]);
		mmio_writeb(writearr[count], sb600_spibar + 0x80 + count);
	}
	msg_pspew("\n");

	execute_command();

	msg_pspew("Reading buffer: ");
	for (count = 0; count < readcnt; count++) {
		readarr[count] = mmio_readb(sb600_spibar + 0x80 + (writecnt + count) % FIFO_SIZE_YANGTZE);
		msg_pspew("[%02x]", readarr[count]);
	}
	msg_pspew("\n");

	return 0;
}
예제 #3
0
파일: sb600spi.c 프로젝트: 173210/flashrom
static int sb600_spi_send_command(struct flashctx *flash, unsigned int writecnt,
				  unsigned int readcnt,
				  const unsigned char *writearr,
				  unsigned char *readarr)
{
	/* First byte is cmd which can not be sent through the FIFO. */
	unsigned char cmd = *writearr++;
	writecnt--;
	msg_pspew("%s, cmd=0x%02x, writecnt=%d, readcnt=%d\n", __func__, cmd, writecnt, readcnt);
	mmio_writeb(cmd, sb600_spibar + 0);

	int ret = check_readwritecnt(flash, writecnt, readcnt);
	if (ret != 0)
		return ret;

	/* This is a workaround for a bug in SPI controller. If we only send
	 * an opcode and no additional data/address, the SPI controller will
	 * read one byte too few from the chip. Basically, the last byte of
	 * the chip response is discarded and will not end up in the FIFO.
	 * It is unclear if the CS# line is set high too early as well.
	 */
	unsigned int readoffby1 = (writecnt > 0) ? 0 : 1;
	uint8_t readwrite = (readcnt + readoffby1) << 4 | (writecnt);
	mmio_writeb(readwrite, sb600_spibar + 1);

	reset_internal_fifo_pointer();
	msg_pspew("Filling FIFO: ");
	int count;
	for (count = 0; count < writecnt; count++) {
		msg_pspew("[%02x]", writearr[count]);
		mmio_writeb(writearr[count], sb600_spibar + 0xC);
	}
	msg_pspew("\n");
	if (compare_internal_fifo_pointer(writecnt))
		return SPI_PROGRAMMER_ERROR;

	/*
	 * We should send the data in sequence, which means we need to reset
	 * the FIFO pointer to the first byte we want to send.
	 */
	reset_internal_fifo_pointer();
	execute_command();
	if (compare_internal_fifo_pointer(writecnt + readcnt))
		return SPI_PROGRAMMER_ERROR;

	/*
	 * After the command executed, we should find out the index of the
	 * received byte. Here we just reset the FIFO pointer and skip the
	 * writecnt.
	 * It would be possible to increase the FIFO pointer by one instead
	 * of reading and discarding one byte from the FIFO.
	 * The FIFO is implemented on top of an 8 byte ring buffer and the
	 * buffer is never cleared. For every byte that is shifted out after
	 * the opcode, the FIFO already stores the response from the chip.
	 * Usually, the chip will respond with 0x00 or 0xff.
	 */
	reset_internal_fifo_pointer();

	/* Skip the bytes we sent. */
	msg_pspew("Skipping: ");
	for (count = 0; count < writecnt; count++) {
		msg_pspew("[%02x]", mmio_readb(sb600_spibar + 0xC));
	}
	msg_pspew("\n");
	if (compare_internal_fifo_pointer(writecnt))
		return SPI_PROGRAMMER_ERROR;

	msg_pspew("Reading FIFO: ");
	for (count = 0; count < readcnt; count++) {
		readarr[count] = mmio_readb(sb600_spibar + 0xC);
		msg_pspew("[%02x]", readarr[count]);
	}
	msg_pspew("\n");
	if (compare_internal_fifo_pointer(writecnt+readcnt))
		return SPI_PROGRAMMER_ERROR;

	if (mmio_readb(sb600_spibar + 1) != readwrite) {
		msg_perr("Unexpected change in AMD SPI read/write count!\n");
		msg_perr("Something else is accessing the flash chip and causes random corruption.\n"
			 "Please stop all applications and drivers and IPMI which access the flash chip.\n");
		return SPI_PROGRAMMER_ERROR;
	}

	return 0;
}