Ejemplo n.º 1
0
int cadence_qspi_apb_process_queue(struct struct_cqspi *cadence_qspi,
				  struct spi_device *spi, unsigned int n_trans,
				  struct spi_transfer **spi_xfer)
{
	struct platform_device *pdev = cadence_qspi->pdev;
	struct cqspi_platform_data *pdata = pdev->dev.platform_data;
	struct spi_transfer *cmd_xfer = spi_xfer[0];
	struct spi_transfer *data_xfer = (n_trans >= 2) ? spi_xfer[1] : NULL;
	void __iomem *iobase = cadence_qspi->iobase;
	unsigned int sclk;
	int ret = 0;
	struct cqspi_flash_pdata *f_pdata;

	pr_debug("%s %d\n", __func__, n_trans);

	if (!cmd_xfer->len) {
		pr_err("QSPI: SPI transfer length is 0.\n");
		return -EINVAL;
	}

	/* Switch chip select. */
	if (cadence_qspi->current_cs != spi->chip_select) {
		cadence_qspi->current_cs = spi->chip_select;
		cadence_qspi_switch_cs(cadence_qspi, spi->chip_select);
	}

	/* Setup baudrate divisor and delays */
	f_pdata = &(pdata->f_pdata[cadence_qspi->current_cs]);
	sclk = cmd_xfer->speed_hz ?
		cmd_xfer->speed_hz : spi->max_speed_hz;
	cadence_qspi_apb_controller_disable(iobase);
	cadence_qspi_apb_config_baudrate_div(iobase,
		pdata->master_ref_clk_hz, sclk);
	cadence_qspi_apb_delay(cadence_qspi,
		pdata->master_ref_clk_hz, sclk);
	cadence_qspi_apb_readdata_capture(iobase, 1,
		f_pdata->read_delay);
	cadence_qspi_apb_controller_enable(iobase);

	/*
	 * Use STIG command to send if the transfer length is less than
	 * 4 or if only one transfer.
	 */
	 if ((cmd_xfer->len < 4) || (n_trans == 1)) {
		 /* STIG command */
		 if (data_xfer && data_xfer->rx_buf) {
			 /* STIG read */
			 ret = cadence_qspi_apb_command_read(iobase,
				cmd_xfer->len, cmd_xfer->tx_buf,
				data_xfer->len, data_xfer->rx_buf);
		 } else {
			 /* STIG write */
			 ret = cadence_qspi_apb_command_write(iobase,
				 cmd_xfer->len, cmd_xfer->tx_buf);
		 }
	 } else if (cmd_xfer->len >= 4 && (n_trans == 2)){
		 /* Indirect operation */
		 if (data_xfer->rx_buf) {
			 /* Indirect read */
			 ret = cadence_qspi_apb_indirect_read_setup(iobase,
				 pdata->qspi_ahb_phy, cmd_xfer->len,
				 cmd_xfer->tx_buf, spi->addr_width);
			if (pdata->enable_dma) {
				ret = cadence_qspi_apb_indirect_read_dma(
					cadence_qspi, data_xfer->len,
					data_xfer->rx_buf);
			} else {
			 ret = cadence_qspi_apb_indirect_read_execute(
				cadence_qspi, data_xfer->len,
				data_xfer->rx_buf);
			}
		 } else {
			 /* Indirect write */
			 ret = cadence_qspi_apb_indirect_write_setup(
				 iobase, pdata->qspi_ahb_phy,
				 cmd_xfer->len, cmd_xfer->tx_buf);
			if (pdata->enable_dma) {
				ret = cadence_qspi_apb_indirect_write_dma(
					cadence_qspi, data_xfer->len,
					(unsigned char *)data_xfer->tx_buf);
			} else {
				ret = cadence_qspi_apb_indirect_write_execute(
					cadence_qspi, data_xfer->len,
					data_xfer->tx_buf);
			}
		 }
	 } else {
		pr_err("QSPI : Unknown SPI transfer.\n");
		return -EINVAL;
	 }
	return ret;
}
Ejemplo n.º 2
0
/* Calibration sequence to determine the read data capture delay register */
static int spi_calibration(struct udevice *bus)
{
	struct cadence_spi_platdata *plat = bus->platdata;
	struct cadence_spi_priv *priv = dev_get_priv(bus);
	void *base = priv->regbase;
	u8 opcode_rdid = 0x9F;
	unsigned int idcode = 0, temp = 0;
	int err = 0, i, range_lo = -1, range_hi = -1;

	/* start with slowest clock (1 MHz) */
	cadence_spi_write_speed(bus, 1000000);

	/* configure the read data capture delay register to 0 */
	cadence_qspi_apb_readdata_capture(base, 1, 0);

	/* Enable QSPI */
	cadence_qspi_apb_controller_enable(base);

	/* read the ID which will be our golden value */
	err = cadence_qspi_apb_command_read(base, 1, &opcode_rdid,
		3, (u8 *)&idcode);
	if (err) {
		puts("SF: Calibration failed (read)\n");
		return err;
	}

	/* use back the intended clock and find low range */
	cadence_spi_write_speed(bus, plat->max_hz);
	for (i = 0; i < CQSPI_READ_CAPTURE_MAX_DELAY; i++) {
		/* Disable QSPI */
		cadence_qspi_apb_controller_disable(base);

		/* reconfigure the read data capture delay register */
		cadence_qspi_apb_readdata_capture(base, 1, i);

		/* Enable back QSPI */
		cadence_qspi_apb_controller_enable(base);

		/* issue a RDID to get the ID value */
		err = cadence_qspi_apb_command_read(base, 1, &opcode_rdid,
			3, (u8 *)&temp);
		if (err) {
			puts("SF: Calibration failed (read)\n");
			return err;
		}

		/* search for range lo */
		if (range_lo == -1 && temp == idcode) {
			range_lo = i;
			continue;
		}

		/* search for range hi */
		if (range_lo != -1 && temp != idcode) {
			range_hi = i - 1;
			break;
		}
		range_hi = i;
	}

	if (range_lo == -1) {
		puts("SF: Calibration failed (low range)\n");
		return err;
	}

	/* Disable QSPI for subsequent initialization */
	cadence_qspi_apb_controller_disable(base);

	/* configure the final value for read data capture delay register */
	cadence_qspi_apb_readdata_capture(base, 1, (range_hi + range_lo) / 2);
	debug("SF: Read data capture delay calibrated to %i (%i - %i)\n",
	      (range_hi + range_lo) / 2, range_lo, range_hi);

	/* just to ensure we do once only when speed or chip select change */
	priv->qspi_calibrated_hz = plat->max_hz;
	priv->qspi_calibrated_cs = spi_chip_select(bus);

	return 0;
}