Unverified Commit a41461b6 authored by Arnd Bergmann's avatar Arnd Bergmann
Browse files

Merge tag 'imx-ecspi-5.15' of...

Merge tag 'imx-ecspi-5.15' of git://git.kernel.org/pub/scm/linux/kernel/git/shawnguo/linux into arm/drivers

i.MX eCSPI errata handling for 5.15:

It includes all required changes for handling i.MX6/7 eCSPI errata
ERR009165, which causes FIFO transfer to be sent twice in DMA mode.
Both SPI and DMA maintainers agree to merge it through arm-soc tree.

* tag 'imx-ecspi-5.15' of git://git.kernel.org/pub/scm/linux/kernel/git/shawnguo/linux:
  dmaengine: imx-sdma: add terminated list for freed descriptor in worker
  dmaengine: imx-sdma: add uart rom script
  dma: imx-sdma: add i.mx6ul compatible name
  dmaengine: imx-sdma: remove ERR009165 on i.mx6ul
  spi: imx: remove ERR009165 workaround on i.mx6ul
  spi: imx: fix ERR009165
  dmaengine: imx-sdma: add mcu_2_ecspi script
  dmaengine: dma: imx-sdma: add fw_loaded and is_ram_script
  dmaengine: imx-sdma: remove duplicated sdma_load_context
  Revert "dmaengine: imx-sdma: refine to load context only once"
  Revert "ARM: dts: imx6: Use correct SDMA script for SPI cores"
  Revert "ARM: dts: imx6q: Use correct SDMA script for SPI5 core"

Link: https://lore.kernel.org/r/20210809071838.GF30984@dragon


Signed-off-by: default avatarArnd Bergmann <arnd@arndb.de>
parents d2c334f4 4e2b10be
Loading
Loading
Loading
Loading
+1 −0
Original line number Diff line number Diff line
@@ -9,6 +9,7 @@ Required properties:
      "fsl,imx53-sdma"
      "fsl,imx6q-sdma"
      "fsl,imx7d-sdma"
      "fsl,imx6ul-sdma"
      "fsl,imx8mq-sdma"
      "fsl,imx8mm-sdma"
      "fsl,imx8mn-sdma"
+1 −1
Original line number Diff line number Diff line
@@ -177,7 +177,7 @@
					clocks = <&clks IMX6Q_CLK_ECSPI5>,
						 <&clks IMX6Q_CLK_ECSPI5>;
					clock-names = "ipg", "per";
					dmas = <&sdma 11 8 1>, <&sdma 12 8 2>;
					dmas = <&sdma 11 7 1>, <&sdma 12 7 2>;
					dma-names = "rx", "tx";
					status = "disabled";
				};
+4 −4
Original line number Diff line number Diff line
@@ -334,7 +334,7 @@
					clocks = <&clks IMX6QDL_CLK_ECSPI1>,
						 <&clks IMX6QDL_CLK_ECSPI1>;
					clock-names = "ipg", "per";
					dmas = <&sdma 3 8 1>, <&sdma 4 8 2>;
					dmas = <&sdma 3 7 1>, <&sdma 4 7 2>;
					dma-names = "rx", "tx";
					status = "disabled";
				};
@@ -348,7 +348,7 @@
					clocks = <&clks IMX6QDL_CLK_ECSPI2>,
						 <&clks IMX6QDL_CLK_ECSPI2>;
					clock-names = "ipg", "per";
					dmas = <&sdma 5 8 1>, <&sdma 6 8 2>;
					dmas = <&sdma 5 7 1>, <&sdma 6 7 2>;
					dma-names = "rx", "tx";
					status = "disabled";
				};
@@ -362,7 +362,7 @@
					clocks = <&clks IMX6QDL_CLK_ECSPI3>,
						 <&clks IMX6QDL_CLK_ECSPI3>;
					clock-names = "ipg", "per";
					dmas = <&sdma 7 8 1>, <&sdma 8 8 2>;
					dmas = <&sdma 7 7 1>, <&sdma 8 7 2>;
					dma-names = "rx", "tx";
					status = "disabled";
				};
@@ -376,7 +376,7 @@
					clocks = <&clks IMX6QDL_CLK_ECSPI4>,
						 <&clks IMX6QDL_CLK_ECSPI4>;
					clock-names = "ipg", "per";
					dmas = <&sdma 9 8 1>, <&sdma 10 8 2>;
					dmas = <&sdma 9 7 1>, <&sdma 10 7 2>;
					dma-names = "rx", "tx";
					status = "disabled";
				};
+70 −23
Original line number Diff line number Diff line
@@ -198,12 +198,12 @@ struct sdma_script_start_addrs {
	s32 per_2_firi_addr;
	s32 mcu_2_firi_addr;
	s32 uart_2_per_addr;
	s32 uart_2_mcu_addr;
	s32 uart_2_mcu_ram_addr;
	s32 per_2_app_addr;
	s32 mcu_2_app_addr;
	s32 per_2_per_addr;
	s32 uartsh_2_per_addr;
	s32 uartsh_2_mcu_addr;
	s32 uartsh_2_mcu_ram_addr;
	s32 per_2_shp_addr;
	s32 mcu_2_shp_addr;
	s32 ata_2_mcu_addr;
@@ -230,6 +230,10 @@ struct sdma_script_start_addrs {
	s32 zcanfd_2_mcu_addr;
	s32 zqspi_2_mcu_addr;
	s32 mcu_2_ecspi_addr;
	s32 mcu_2_sai_addr;
	s32 sai_2_mcu_addr;
	s32 uart_2_mcu_addr;
	s32 uartsh_2_mcu_addr;
	/* End of v3 array */
	s32 mcu_2_zqspi_addr;
	/* End of v4 array */
@@ -433,9 +437,10 @@ struct sdma_channel {
	unsigned long			watermark_level;
	u32				shp_addr, per_addr;
	enum dma_status			status;
	bool				context_loaded;
	struct imx_dma_data		data;
	struct work_struct		terminate_worker;
	struct list_head                terminated;
	bool				is_ram_script;
};

#define IMX_DMA_SG_LOOP		BIT(0)
@@ -476,6 +481,13 @@ struct sdma_driver_data {
	int num_events;
	struct sdma_script_start_addrs	*script_addrs;
	bool check_ratio;
	/*
	 * ecspi ERR009165 fixed should be done in sdma script
	 * and it has been fixed in soc from i.mx6ul.
	 * please get more information from the below link:
	 * https://www.nxp.com/docs/en/errata/IMX6DQCE.pdf
	 */
	bool ecspi_fixed;
};

struct sdma_engine {
@@ -499,6 +511,7 @@ struct sdma_engine {
	struct sdma_buffer_descriptor	*bd0;
	/* clock ratio for AHB:SDMA core. 1:1 is 1, 2:1 is 0*/
	bool				clk_ratio;
	bool                            fw_loaded;
};

static int sdma_config_write(struct dma_chan *chan,
@@ -595,6 +608,13 @@ static struct sdma_driver_data sdma_imx6q = {
	.script_addrs = &sdma_script_imx6q,
};

static struct sdma_driver_data sdma_imx6ul = {
	.chnenbl0 = SDMA_CHNENBL0_IMX35,
	.num_events = 48,
	.script_addrs = &sdma_script_imx6q,
	.ecspi_fixed = true,
};

static struct sdma_script_start_addrs sdma_script_imx7d = {
	.ap_2_ap_addr = 644,
	.uart_2_mcu_addr = 819,
@@ -628,6 +648,7 @@ static const struct of_device_id sdma_dt_ids[] = {
	{ .compatible = "fsl,imx31-sdma", .data = &sdma_imx31, },
	{ .compatible = "fsl,imx25-sdma", .data = &sdma_imx25, },
	{ .compatible = "fsl,imx7d-sdma", .data = &sdma_imx7d, },
	{ .compatible = "fsl,imx6ul-sdma", .data = &sdma_imx6ul, },
	{ .compatible = "fsl,imx8mq-sdma", .data = &sdma_imx8mq, },
	{ /* sentinel */ }
};
@@ -919,6 +940,7 @@ static void sdma_get_pc(struct sdma_channel *sdmac,
	sdmac->pc_to_device = 0;
	sdmac->device_to_device = 0;
	sdmac->pc_to_pc = 0;
	sdmac->is_ram_script = false;

	switch (peripheral_type) {
	case IMX_DMATYPE_MEMORY:
@@ -945,6 +967,17 @@ static void sdma_get_pc(struct sdma_channel *sdmac,
		emi_2_per = sdma->script_addrs->mcu_2_ata_addr;
		break;
	case IMX_DMATYPE_CSPI:
		per_2_emi = sdma->script_addrs->app_2_mcu_addr;

		/* Use rom script mcu_2_app if ERR009165 fixed */
		if (sdmac->sdma->drvdata->ecspi_fixed) {
			emi_2_per = sdma->script_addrs->mcu_2_app_addr;
		} else {
			emi_2_per = sdma->script_addrs->mcu_2_ecspi_addr;
			sdmac->is_ram_script = true;
		}

		break;
	case IMX_DMATYPE_EXT:
	case IMX_DMATYPE_SSI:
	case IMX_DMATYPE_SAI:
@@ -954,6 +987,7 @@ static void sdma_get_pc(struct sdma_channel *sdmac,
	case IMX_DMATYPE_SSI_DUAL:
		per_2_emi = sdma->script_addrs->ssish_2_mcu_addr;
		emi_2_per = sdma->script_addrs->mcu_2_ssish_addr;
		sdmac->is_ram_script = true;
		break;
	case IMX_DMATYPE_SSI_SP:
	case IMX_DMATYPE_MMC:
@@ -968,6 +1002,7 @@ static void sdma_get_pc(struct sdma_channel *sdmac,
		per_2_emi = sdma->script_addrs->asrc_2_mcu_addr;
		emi_2_per = sdma->script_addrs->asrc_2_mcu_addr;
		per_2_per = sdma->script_addrs->per_2_per_addr;
		sdmac->is_ram_script = true;
		break;
	case IMX_DMATYPE_ASRC_SP:
		per_2_emi = sdma->script_addrs->shp_2_mcu_addr;
@@ -1008,9 +1043,6 @@ static int sdma_load_context(struct sdma_channel *sdmac)
	int ret;
	unsigned long flags;

	if (sdmac->context_loaded)
		return 0;

	if (sdmac->direction == DMA_DEV_TO_MEM)
		load_address = sdmac->pc_from_device;
	else if (sdmac->direction == DMA_DEV_TO_DEV)
@@ -1053,8 +1085,6 @@ static int sdma_load_context(struct sdma_channel *sdmac)

	spin_unlock_irqrestore(&sdma->channel_0_lock, flags);

	sdmac->context_loaded = true;

	return ret;
}

@@ -1078,9 +1108,6 @@ static void sdma_channel_terminate_work(struct work_struct *work)
{
	struct sdma_channel *sdmac = container_of(work, struct sdma_channel,
						  terminate_worker);
	unsigned long flags;
	LIST_HEAD(head);

	/*
	 * According to NXP R&D team a delay of one BD SDMA cost time
	 * (maximum is 1ms) should be added after disable of the channel
@@ -1089,11 +1116,7 @@ static void sdma_channel_terminate_work(struct work_struct *work)
	 */
	usleep_range(1000, 2000);

	spin_lock_irqsave(&sdmac->vc.lock, flags);
	vchan_get_all_descriptors(&sdmac->vc, &head);
	spin_unlock_irqrestore(&sdmac->vc.lock, flags);
	vchan_dma_desc_free_list(&sdmac->vc, &head);
	sdmac->context_loaded = false;
	vchan_dma_desc_free_list(&sdmac->vc, &sdmac->terminated);
}

static int sdma_terminate_all(struct dma_chan *chan)
@@ -1107,6 +1130,13 @@ static int sdma_terminate_all(struct dma_chan *chan)

	if (sdmac->desc) {
		vchan_terminate_vdesc(&sdmac->desc->vd);
		/*
		 * move out current descriptor into terminated list so that
		 * it could be free in sdma_channel_terminate_work alone
		 * later without potential involving next descriptor raised
		 * up before the last descriptor terminated.
		 */
		vchan_get_all_descriptors(&sdmac->vc, &sdmac->terminated);
		sdmac->desc = NULL;
		schedule_work(&sdmac->terminate_worker);
	}
@@ -1168,7 +1198,6 @@ static void sdma_set_watermarklevel_for_p2p(struct sdma_channel *sdmac)
static int sdma_config_channel(struct dma_chan *chan)
{
	struct sdma_channel *sdmac = to_sdma_chan(chan);
	int ret;

	sdma_disable_channel(chan);

@@ -1208,9 +1237,7 @@ static int sdma_config_channel(struct dma_chan *chan)
		sdmac->watermark_level = 0; /* FIXME: M3_BASE_ADDRESS */
	}

	ret = sdma_load_context(sdmac);

	return ret;
	return 0;
}

static int sdma_set_channel_priority(struct sdma_channel *sdmac,
@@ -1361,7 +1388,6 @@ static void sdma_free_chan_resources(struct dma_chan *chan)

	sdmac->event_id0 = 0;
	sdmac->event_id1 = 0;
	sdmac->context_loaded = false;

	sdma_set_channel_priority(sdmac, 0);

@@ -1374,6 +1400,11 @@ static struct sdma_desc *sdma_transfer_init(struct sdma_channel *sdmac,
{
	struct sdma_desc *desc;

	if (!sdmac->sdma->fw_loaded && sdmac->is_ram_script) {
		dev_warn_once(sdmac->sdma->dev, "sdma firmware not ready!\n");
		goto err_out;
	}

	desc = kzalloc((sizeof(*desc)), GFP_NOWAIT);
	if (!desc)
		goto err_out;
@@ -1722,8 +1753,8 @@ static void sdma_issue_pending(struct dma_chan *chan)

#define SDMA_SCRIPT_ADDRS_ARRAY_SIZE_V1	34
#define SDMA_SCRIPT_ADDRS_ARRAY_SIZE_V2	38
#define SDMA_SCRIPT_ADDRS_ARRAY_SIZE_V3	41
#define SDMA_SCRIPT_ADDRS_ARRAY_SIZE_V4	42
#define SDMA_SCRIPT_ADDRS_ARRAY_SIZE_V3	45
#define SDMA_SCRIPT_ADDRS_ARRAY_SIZE_V4	46

static void sdma_add_scripts(struct sdma_engine *sdma,
		const struct sdma_script_start_addrs *addr)
@@ -1747,6 +1778,19 @@ static void sdma_add_scripts(struct sdma_engine *sdma,
	for (i = 0; i < sdma->script_number; i++)
		if (addr_arr[i] > 0)
			saddr_arr[i] = addr_arr[i];

	/*
	 * get uart_2_mcu_addr/uartsh_2_mcu_addr rom script specially because
	 * they are now replaced by uart_2_mcu_ram_addr/uartsh_2_mcu_ram_addr
	 * to be compatible with legacy freescale/nxp sdma firmware, and they
	 * are located in the bottom part of sdma_script_start_addrs which are
	 * beyond the SDMA_SCRIPT_ADDRS_ARRAY_SIZE_V1.
	 */
	if (addr->uart_2_mcu_addr)
		sdma->script_addrs->uart_2_mcu_addr = addr->uart_2_mcu_addr;
	if (addr->uartsh_2_mcu_addr)
		sdma->script_addrs->uartsh_2_mcu_addr = addr->uartsh_2_mcu_addr;

}

static void sdma_load_firmware(const struct firmware *fw, void *context)
@@ -1803,6 +1847,8 @@ static void sdma_load_firmware(const struct firmware *fw, void *context)

	sdma_add_scripts(sdma, addr);

	sdma->fw_loaded = true;

	dev_info(sdma->dev, "loaded firmware %d.%d\n",
			header->version_major,
			header->version_minor);
@@ -2086,6 +2132,7 @@ static int sdma_probe(struct platform_device *pdev)

		sdmac->channel = i;
		sdmac->vc.desc_free = sdma_desc_free;
		INIT_LIST_HEAD(&sdmac->terminated);
		INIT_WORK(&sdmac->terminate_worker,
				sdma_channel_terminate_work);
		/*
+35 −6
Original line number Diff line number Diff line
@@ -77,6 +77,11 @@ struct spi_imx_devtype_data {
	bool has_slavemode;
	unsigned int fifo_size;
	bool dynamic_burst;
	/*
	 * ERR009165 fixed or not:
	 * https://www.nxp.com/docs/en/errata/IMX6DQCE.pdf
	 */
	bool tx_glitch_fixed;
	enum spi_imx_devtype devtype;
};

@@ -608,8 +613,14 @@ static int mx51_ecspi_prepare_transfer(struct spi_imx_data *spi_imx,
	ctrl |= mx51_ecspi_clkdiv(spi_imx, spi_imx->spi_bus_clk, &clk);
	spi_imx->spi_bus_clk = clk;

	if (spi_imx->usedma)
	/*
	 * ERR009165: work in XHC mode instead of SMC as PIO on the chips
	 * before i.mx6ul.
	 */
	if (spi_imx->usedma && spi_imx->devtype_data->tx_glitch_fixed)
		ctrl |= MX51_ECSPI_CTRL_SMC;
	else
		ctrl &= ~MX51_ECSPI_CTRL_SMC;

	writel(ctrl, spi_imx->base + MX51_ECSPI_CTRL);

@@ -618,12 +629,16 @@ static int mx51_ecspi_prepare_transfer(struct spi_imx_data *spi_imx,

static void mx51_setup_wml(struct spi_imx_data *spi_imx)
{
	u32 tx_wml = 0;

	if (spi_imx->devtype_data->tx_glitch_fixed)
		tx_wml = spi_imx->wml;
	/*
	 * Configure the DMA register: setup the watermark
	 * and enable DMA request.
	 */
	writel(MX51_ECSPI_DMA_RX_WML(spi_imx->wml - 1) |
		MX51_ECSPI_DMA_TX_WML(spi_imx->wml) |
		MX51_ECSPI_DMA_TX_WML(tx_wml) |
		MX51_ECSPI_DMA_RXT_WML(spi_imx->wml) |
		MX51_ECSPI_DMA_TEDEN | MX51_ECSPI_DMA_RXDEN |
		MX51_ECSPI_DMA_RXTDEN, spi_imx->base + MX51_ECSPI_DMA);
@@ -1014,6 +1029,23 @@ static struct spi_imx_devtype_data imx53_ecspi_devtype_data = {
	.devtype = IMX53_ECSPI,
};

static struct spi_imx_devtype_data imx6ul_ecspi_devtype_data = {
	.intctrl = mx51_ecspi_intctrl,
	.prepare_message = mx51_ecspi_prepare_message,
	.prepare_transfer = mx51_ecspi_prepare_transfer,
	.trigger = mx51_ecspi_trigger,
	.rx_available = mx51_ecspi_rx_available,
	.reset = mx51_ecspi_reset,
	.setup_wml = mx51_setup_wml,
	.fifo_size = 64,
	.has_dmamode = true,
	.dynamic_burst = true,
	.has_slavemode = true,
	.tx_glitch_fixed = true,
	.disable = mx51_ecspi_disable,
	.devtype = IMX51_ECSPI,
};

static const struct of_device_id spi_imx_dt_ids[] = {
	{ .compatible = "fsl,imx1-cspi", .data = &imx1_cspi_devtype_data, },
	{ .compatible = "fsl,imx21-cspi", .data = &imx21_cspi_devtype_data, },
@@ -1022,6 +1054,7 @@ static const struct of_device_id spi_imx_dt_ids[] = {
	{ .compatible = "fsl,imx35-cspi", .data = &imx35_cspi_devtype_data, },
	{ .compatible = "fsl,imx51-ecspi", .data = &imx51_ecspi_devtype_data, },
	{ .compatible = "fsl,imx53-ecspi", .data = &imx53_ecspi_devtype_data, },
	{ .compatible = "fsl,imx6ul-ecspi", .data = &imx6ul_ecspi_devtype_data, },
	{ /* sentinel */ }
};
MODULE_DEVICE_TABLE(of, spi_imx_dt_ids);
@@ -1239,10 +1272,6 @@ static int spi_imx_sdma_init(struct device *dev, struct spi_imx_data *spi_imx,
{
	int ret;

	/* use pio mode for i.mx6dl chip TKT238285 */
	if (of_machine_is_compatible("fsl,imx6dl"))
		return 0;

	spi_imx->wml = spi_imx->devtype_data->fifo_size / 2;

	/* Prepare for TX DMA: */