Ejemplo n.º 1
0
/*
 * zynq_qspi_start_transfer - Initiates the QSPI transfer
 * @qspi:	Pointer to the spi_device structure
 * @transfer:	Pointer to the spi_transfer structure which provide information
 *		about next transfer parameters
 *
 * This function fills the TX FIFO, starts the QSPI transfer, and waits for the
 * transfer to be completed.
 *
 * returns:	Number of bytes transferred in the last transfer
 */
static int zynq_qspi_start_transfer(struct spi_device *qspi,
			struct spi_transfer *transfer)
{
	struct zynq_qspi *zqspi = &qspi->master;
	static u8 current_u_page;
	u32 data = 0;
	u8 instruction = 0;
	u8 index;

	debug("%s: qspi: 0x%08x transfer: 0x%08x len: %d\n", __func__,
	      (u32)qspi, (u32)transfer, transfer->len);

	zqspi->txbuf = transfer->tx_buf;
	zqspi->rxbuf = transfer->rx_buf;
	zqspi->bytes_to_transfer = transfer->len;
	zqspi->bytes_to_receive = transfer->len;

	if (zqspi->txbuf)
		instruction = *(u8 *)zqspi->txbuf;

	if (instruction && zqspi->is_inst) {
		for (index = 0; index < ARRAY_SIZE(flash_inst); index++)
			if (instruction == flash_inst[index].opcode)
				break;

		/*
		 * Instruction might have already been transmitted. This is a
		 * 'data only' transfer
		 */
		if (index == ARRAY_SIZE(flash_inst))
			goto xfer_data;

		zqspi->curr_inst = &flash_inst[index];
		zqspi->inst_response = 1;

		if ((zqspi->is_dual == MODE_DUAL_STACKED) &&
				(current_u_page != zqspi->u_page)) {
			if (zqspi->u_page) {
				/* Configure two memories on shared bus
				 * by enabling upper mem
				 */
				writel((ZYNQ_QSPI_LCFG_TWO_MEM_MASK |
					ZYNQ_QSPI_LCFG_U_PAGE |
					(1 << ZYNQ_QSPI_LCFG_DUMMY_SHIFT) |
					ZYNQ_QSPI_FR_QOUT_CODE),
					&zynq_qspi_base->lcr);
			} else {
				/* Configure two memories on shared bus
				 * by enabling lower mem
				 */
				writel((ZYNQ_QSPI_LCFG_TWO_MEM_MASK |
					(1 << ZYNQ_QSPI_LCFG_DUMMY_SHIFT) |
					ZYNQ_QSPI_FR_QOUT_CODE),
					&zynq_qspi_base->lcr);
			}

			current_u_page = zqspi->u_page;
		}

		/* Get the instruction */
		data = 0;
		zynq_qspi_copy_write_data(zqspi, &data,
					zqspi->curr_inst->inst_size);

		/*
		 * Write the instruction to LSB of the FIFO. The core is
		 * designed such that it is not necessary to check whether the
		 * write FIFO is full before writing. However, write would be
		 * delayed if the user tries to write when write FIFO is full
		 */
		writel(data, &zynq_qspi_base->confr +
				(zqspi->curr_inst->offset / 4));

		/*
		 * Read status register and Read ID instructions don't require
		 * to ignore the extra bytes in response of instruction as
		 * response contains the value
		 */
		if ((instruction == ZYNQ_QSPI_FLASH_OPCODE_RDSR1) ||
		    (instruction == ZYNQ_QSPI_FLASH_OPCODE_RDSR2) ||
		    (instruction == ZYNQ_QSPI_FLASH_OPCODE_RDID) ||
		    (instruction == ZYNQ_QSPI_FLASH_OPCODE_BRRD) ||
		    (instruction == ZYNQ_QSPI_FLASH_OPCODE_RDEAR)) {
			if (zqspi->bytes_to_transfer < 4)
				zqspi->bytes_to_transfer = 0;
			else
				zqspi->bytes_to_transfer -= 3;
		}
	}

xfer_data:
	/*
	 * In case of Fast, Dual and Quad reads, transmit the instruction first.
	 * Address and dummy byte should be transmitted after instruction
	 * is transmitted
	 */
	if (((zqspi->is_inst == 0) && (zqspi->bytes_to_transfer)) ||
	    ((zqspi->bytes_to_transfer) &&
	     (instruction != ZYNQ_QSPI_FLASH_OPCODE_FR) &&
	     (instruction != ZYNQ_QSPI_FLASH_OPCODE_DR) &&
	     (instruction != ZYNQ_QSPI_FLASH_OPCODE_QR) &&
	     (instruction != ZYNQ_QSPI_FLASH_OPCODE_DIOR)))
		zynq_qspi_fill_tx_fifo(zqspi, ZYNQ_QSPI_FIFO_DEPTH);

	writel(ZYNQ_QSPI_IXR_ALL_MASK, &zynq_qspi_base->ier);
	/* Start the transfer by enabling manual start bit */

	/* wait for completion */
	do {
		data = zynq_qspi_irq_poll(zqspi);
	} while (data == 0);

	return (transfer->len) - (zqspi->bytes_to_transfer);
}
Ejemplo n.º 2
0
/*
 * zynq_qspi_start_transfer - Initiates the QSPI transfer
 * @qspi:	Pointer to the spi_device structure
 * @transfer:	Pointer to the spi_transfer structure which provide information
 *		about next transfer parameters
 *
 * This function fills the TX FIFO, starts the QSPI transfer, and waits for the
 * transfer to be completed.
 *
 * returns:	Number of bytes transferred in the last transfer
 */
static int zynq_qspi_start_transfer(struct zynq_qspi_priv *priv)
{
	static u8 current_u_page;
	u32 data = 0;
	struct zynq_qspi_regs *regs = priv->regs;

	debug("%s: qspi: 0x%08x transfer: 0x%08x len: %d\n", __func__,
	      (u32)priv, (u32)priv, priv->len);

	priv->bytes_to_transfer = priv->len;
	priv->bytes_to_receive = priv->len;

	if (priv->is_inst && (priv->is_dual == SF_DUAL_STACKED_FLASH) &&
	    (current_u_page != priv->u_page)) {
		if (priv->u_page) {
			if (priv->is_dio == SF_DUALIO_FLASH)
				writel((ZYNQ_QSPI_LCFG_TWO_MEM_MASK |
					ZYNQ_QSPI_LCFG_U_PAGE |
					(1 << ZYNQ_QSPI_LCFG_DUMMY_SHIFT) |
					ZYNQ_QSPI_FR_DUALIO_CODE),
					&regs->lcr);
			else
				/* Configure two memories on shared bus
				 * by enabling upper mem
				 */
				writel((ZYNQ_QSPI_LCFG_TWO_MEM_MASK |
					ZYNQ_QSPI_LCFG_U_PAGE |
					(1 << ZYNQ_QSPI_LCFG_DUMMY_SHIFT) |
					ZYNQ_QSPI_FR_QOUT_CODE),
					&regs->lcr);
		} else {
			if (priv->is_dio == SF_DUALIO_FLASH)
				writel((ZYNQ_QSPI_LCFG_TWO_MEM_MASK |
					(1 << ZYNQ_QSPI_LCFG_DUMMY_SHIFT) |
					ZYNQ_QSPI_FR_DUALIO_CODE),
					&regs->lcr);
			else
				/* Configure two memories on shared bus
				 * by enabling lower mem
				 */
				writel((ZYNQ_QSPI_LCFG_TWO_MEM_MASK |
					(1 << ZYNQ_QSPI_LCFG_DUMMY_SHIFT) |
					ZYNQ_QSPI_FR_QOUT_CODE),
					&regs->lcr);
		}
		current_u_page = priv->u_page;
	}

	if (priv->len < 4)
		zynq_qspi_fill_tx_fifo(priv, priv->len);
	else
		zynq_qspi_fill_tx_fifo(priv, ZYNQ_QSPI_FIFO_DEPTH);

	writel(ZYNQ_QSPI_IXR_ALL_MASK, &regs->ier);
	/* Start the transfer by enabling manual start bit */

	/* wait for completion */
	do {
		data = zynq_qspi_irq_poll(priv);
	} while (data == 0);

	return (priv->len) - (priv->bytes_to_transfer);
}