Commit 1c4351a2 authored by Mike J. Chen's avatar Mike J. Chen Committed by Fabio Baltieri
Browse files

drivers: mcux: spi and dma: add explicit dma channel type for SPI_TX



The spi_mcux_flexcomm driver uses a special last DMA blk_cfg
to trigger a release of the SPI chip select. This transfer
is always a 4-byte transfer, regardless of the width specified
during dma_configure().

The way the spi_mcux_flexcomm driver communicated this special
transfer was kind of a hack, where the dma_mcux_lpc driver would
assume that when a blk_cfg with source_addr_adj and dest_addr_adj
both set to NO_CHANGE was for this SPI_TX special case.

However, this is an unsafe hack since it is perfectly valid
to have dma use cases for both src/dest_addr_adj to be NO_CHANGE
that is not for SPI_TX. One example is when transmitting a
fixed/repeating value to a periperhal address (e.g. send 100
bytes of the same value from a single memory address over SPI).

This CL introduces a dma_mcux_lpc specific dma channel_direction
which the two drivers now use to cleary request this special
transfer case.

Signed-off-by: default avatarMike J. Chen <mjchen@google.com>
parent df46b30b
Loading
Loading
Loading
Loading
+4 −2
Original line number Diff line number Diff line
@@ -224,8 +224,9 @@ static int dma_mcux_lpc_queue_descriptors(struct channel_data *data,
		 * address does not need to be change for these
		 * transactions and the transfer width is 4 bytes
		 */
		if ((local_block.source_addr_adj == DMA_ADDR_ADJ_NO_CHANGE) &&
			(local_block.dest_addr_adj == DMA_ADDR_ADJ_NO_CHANGE)) {
		if ((data->dir == LPC_DMA_SPI_MCUX_FLEXCOMM_TX) &&
		    (local_block.block_size == sizeof(uint32_t)) &&
		    (local_block.next_block == NULL)) {
			src_inc = 0;
			dest_inc = 0;
			width = sizeof(uint32_t);
@@ -438,6 +439,7 @@ static int dma_mcux_lpc_configure(const struct device *dev, uint32_t channel,
			}
		}
		break;
	case LPC_DMA_SPI_MCUX_FLEXCOMM_TX:
	case MEMORY_TO_PERIPHERAL:
		/* Set the source increment value */
		if (block_config->source_gather_en) {
+4 −11
Original line number Diff line number Diff line
@@ -15,6 +15,7 @@
#include <zephyr/logging/log.h>
#ifdef CONFIG_SPI_MCUX_FLEXCOMM_DMA
#include <zephyr/drivers/dma.h>
#include <zephyr/drivers/dma/dma_mcux_lpc.h>
#endif
#include <zephyr/drivers/pinctrl.h>
#include <zephyr/sys_clock.h>
@@ -398,15 +399,15 @@ static int spi_mcux_dma_tx_load(const struct device *dev, const struct spi_confi
	blk_cfg = &stream->dma_blk_cfg[dma_block_num];
	/* tx direction has memory as source and periph as dest. */
	blk_cfg->dest_address = (uint32_t)&base->FIFOWR;
	blk_cfg->dest_addr_adj = DMA_ADDR_ADJ_NO_CHANGE;
	blk_cfg->source_gather_en = 0;
	if (last_packet) {
		data->last_word = spi_mcux_get_last_tx_word(spi_cfg, buf, len, config->def_char,
							    data->word_size_bits);
		blk_cfg->source_address = (uint32_t)&data->last_word;
		blk_cfg->source_addr_adj = DMA_ADDR_ADJ_NO_CHANGE;
		blk_cfg->block_size = sizeof(uint32_t);
		blk_cfg->next_block = NULL;
		blk_cfg->source_addr_adj = DMA_ADDR_ADJ_NO_CHANGE;
		blk_cfg->dest_addr_adj = DMA_ADDR_ADJ_NO_CHANGE;
		data->dma_tx.wait_for_dma_status = DMA_STATUS_COMPLETE;
	} else {
		blk_cfg->block_size = len;
@@ -418,14 +419,6 @@ static int spi_mcux_dma_tx_load(const struct device *dev, const struct spi_confi
			data->dummy_tx_buffer = 0;
			blk_cfg->source_address = (uint32_t)&data->dummy_tx_buffer;
			blk_cfg->source_addr_adj = DMA_ADDR_ADJ_NO_CHANGE;
			/* The DMA driver uses the special case of source_addr_adj and dest_addr_adj
			 * both set to DMA_ADDR_ADJ_NO_CHANGE to set the transfer width to 32 bits,
			 * which is required on the last packet. To keep that case from being
			 * inadvertantly triggered on a dummy transfer we must set the dest_addr_adj
			 * to increment. This flag is ignored on the peripheral side of the
			 * transfer, so this does not affect anything except the special case.
			 */
			blk_cfg->dest_addr_adj = DMA_ADDR_ADJ_INCREMENT;
		}
		data->dma_tx.wait_for_dma_status = DMA_STATUS_BLOCK;
	}
@@ -919,7 +912,7 @@ static DEVICE_API(spi, spi_mcux_driver_api) = {
		.channel =					\
			DT_INST_DMAS_CELL_BY_NAME(id, tx, channel),	\
		.dma_cfg = {						\
			.channel_direction = MEMORY_TO_PERIPHERAL,	\
			.channel_direction = LPC_DMA_SPI_MCUX_FLEXCOMM_TX,	\
			.dma_callback = spi_mcux_dma_callback,		\
			.complete_callback_en = true,			\
			.block_count = 2,				\
+7 −0
Original line number Diff line number Diff line
@@ -53,4 +53,11 @@
/* Used by driver to extract burstpower setting */
#define LPC_DMA_GET_BURSTPOWER(slot) (((slot) & 0xE0) >> 5)

/*
 * Special channel_direction for SPI_MCUX_FLEXCOMM_TX so
 * that DMA driver can configure the last descriptor
 * to deassert CS.
 */
#define LPC_DMA_SPI_MCUX_FLEXCOMM_TX (DMA_CHANNEL_DIRECTION_PRIV_START)

#endif /* ZEPHYR_INCLUDE_DRIVERS_DMA_DMA_MCUX_LPC_H_ */