stm32: Export DMA memory size option

We need different memory size configuration in different application.
Let's export the memory size option to DMA function parameters.

BUG=chrome-os-partner:14316
TEST=Boot on snow. Check I2C host command works.
BRANCH=none

Change-Id: I30481ddf86a1526d517961e009898642ecdd649a
Signed-off-by: Vic Yang <victoryang@chromium.org>
Reviewed-on: https://gerrit.chromium.org/gerrit/33981
Reviewed-by: Vincent Palatin <vpalatin@chromium.org>
This commit is contained in:
Vic Yang
2012-09-25 14:40:15 +08:00
committed by Gerrit
parent c51a8982ff
commit cfcd1412ea
5 changed files with 74 additions and 31 deletions

View File

@@ -78,8 +78,6 @@ static void prepare_channel(struct dma_channel *chan, unsigned count,
REG32(&chan->ccr) = ctrl;
ctrl |= flags;
ctrl |= 0 << 10; /* MSIZE (memory size in bytes) */
ctrl |= 1 << 8; /* PSIZE (16-bits for now) */
REG32(&chan->ccr) = ctrl;
}
@@ -89,19 +87,22 @@ void dma_go(struct dma_channel *chan)
REG32(&chan->ccr) |= DMA_EN;
}
void dma_prepare_tx(struct dma_channel *chan, unsigned count, void *periph,
const void *memory)
void dma_prepare_tx(const struct dma_option *option, unsigned count,
const void *memory)
{
prepare_channel(chan, count, periph, memory,
DMA_MINC_MASK | DMA_DIR_FROM_MEM_MASK);
struct dma_channel *chan = dma_get_channel(option->channel);
prepare_channel(chan, count, option->periph, memory,
DMA_MINC_MASK | DMA_DIR_FROM_MEM_MASK | option->flags);
}
int dma_start_rx(unsigned channel, unsigned count, void *periph,
int dma_start_rx(const struct dma_option *option, unsigned count,
const void *memory)
{
struct dma_channel *chan = dma_get_channel(channel);
struct dma_channel *chan = dma_get_channel(option->channel);
prepare_channel(chan, count, periph, memory, DMA_MINC_MASK);
prepare_channel(chan, count, option->periph, memory,
DMA_MINC_MASK | option->flags);
dma_go(chan);
return 0;
}

View File

@@ -54,6 +54,14 @@ struct dma_ctlr {
struct dma_channel chan[DMA_NUM_CHANNELS];
};
/* DMA channel options */
struct dma_option {
unsigned channel; /* DMA channel */
void *periph; /* Pointer to peripheral data register */
unsigned flags; /* DMA flags for the control register. Normally
used to select memory size. */
};
/* Defines for accessing DMA ccr */
#define DMA_PL_SHIFT 12
#define DMA_PL_MASK (3 << DMA_PL_SHIFT)
@@ -72,6 +80,14 @@ enum {
#define DMA_MINC_MASK (1 << 7)
#define DMA_TCIF(channel) (1 << (1 + 4 * channel))
#define DMA_MSIZE_BYTE (0 << 10)
#define DMA_MSIZE_HALF_WORD (1 << 10)
#define DMA_MSIZE_WORD (2 << 10)
#define DMA_PSIZE_BYTE (0 << 8)
#define DMA_PSIZE_HALF_WORD (1 << 8)
#define DMA_PSIZE_WORD (2 << 8)
#define DMA_POLLING_INTERVAL_US 100 /* us */
#define DMA_TRANSFER_TIMEOUT_US 100000 /* us */
@@ -103,24 +119,23 @@ struct dma_channel *dma_get_channel(int channel);
*
* Call dma_go() afterwards to actually start the transfer.
*
* @param chan Channel to prepare (use dma_get_channel())
* @param option DMA channel options
* @param count Number of bytes to transfer
* @param periph Pointer to peripheral data register
* @param memory Pointer to memory address
*
* @return pointer to prepared channel
*/
void dma_prepare_tx(struct dma_channel *chan, unsigned count,
void *periph, const void *memory);
void dma_prepare_tx(const struct dma_option *option, unsigned count,
const void *memory);
/**
* Start a DMA transfer to receive data to memory from a peripheral
*
* @param channel Channel number to read (DMAC_...)
* @param option DMA channel options
* @param count Number of bytes to transfer
* @param periph Pointer to peripheral data register
* @param memory Pointer to memory address
*/
int dma_start_rx(unsigned channel, unsigned count, void *periph,
int dma_start_rx(const struct dma_option *option, unsigned count,
const void *memory);
/**

View File

@@ -72,6 +72,20 @@ enum {
STOP_SENT_RETRY_US = 150,
};
static const struct dma_option dma_tx_option[NUM_PORTS] = {
{DMAC_I2C_TX, (void *)&STM32_I2C_DR(I2C1),
DMA_MSIZE_BYTE | DMA_PSIZE_HALF_WORD},
{DMAC_I2C_TX, (void *)&STM32_I2C_DR(I2C2),
DMA_MSIZE_BYTE | DMA_PSIZE_HALF_WORD},
};
static const struct dma_option dma_rx_option[NUM_PORTS] = {
{DMAC_I2C_RX, (void *)&STM32_I2C_DR(I2C1),
DMA_MSIZE_BYTE | DMA_PSIZE_HALF_WORD},
{DMAC_I2C_RX, (void *)&STM32_I2C_DR(I2C2),
DMA_MSIZE_BYTE | DMA_PSIZE_HALF_WORD},
};
static uint16_t i2c_sr1[NUM_PORTS];
static struct mutex i2c_mutex;
@@ -128,7 +142,7 @@ static int i2c_write_raw_slave(int port, void *buf, int len)
/* Configuring DMA1 channel DMAC_I2X_TX */
enable_ack(port);
chan = dma_get_channel(DMAC_I2C_TX);
dma_prepare_tx(chan, len, (void *)&STM32_I2C_DR(port), buf);
dma_prepare_tx(dma_tx_option + port, len, buf);
/* Start the DMA */
dma_go(chan);
@@ -237,8 +251,8 @@ static void i2c_event_handler(int port)
if (i2c_sr1[port] & (1 << 1)) {
/* If it's a receiver slave */
if (!(STM32_I2C_SR2(port) & (1 << 2))) {
dma_start_rx(DMAC_I2C_RX, sizeof(host_buffer),
(void *)&STM32_I2C_DR(port), host_buffer);
dma_start_rx(dma_rx_option + port, sizeof(host_buffer),
host_buffer);
STM32_I2C_CR2(port) |= (1 << 11);
rx_pending = 1;
@@ -714,17 +728,15 @@ static int i2c_master_transmit(int port, int slave_addr, uint8_t *data,
int size, int stop)
{
int rv, rv_start;
struct dma_channel *chan;
disable_ack(port);
/* Configuring DMA1 channel DMAC_I2X_TX */
chan = dma_get_channel(DMAC_I2C_TX);
dma_prepare_tx(chan, size, (void *)&STM32_I2C_DR(port), data);
dma_prepare_tx(dma_tx_option + port, size, data);
dma_enable_tc_interrupt(DMAC_I2C_TX);
/* Start the DMA */
dma_go(chan);
dma_go(dma_get_channel(DMAC_I2C_TX));
/* Configuring i2c2 to use DMA */
STM32_I2C_CR2(port) |= CR2_DMAEN;
@@ -768,8 +780,7 @@ static int i2c_master_receive(int port, int slave_addr, uint8_t *data,
/* Master receive only supports DMA for payloads > 1 byte */
if (size > 1) {
enable_ack(port);
dma_start_rx(DMAC_I2C_RX, size, (void *)&STM32_I2C_DR(port),
data);
dma_start_rx(dma_rx_option + port, size, data);
dma_enable_tc_interrupt(DMAC_I2C_RX);

View File

@@ -253,10 +253,8 @@
#define STM32_I2C1_PORT 0
#define STM32_I2C2_PORT 1
static inline uint16_t *stm32_i2c_reg(int port, int offset)
{
return (uint16_t *)((STM32_I2C1_BASE + (port * 0x400)) + offset);
}
#define stm32_i2c_reg(port, offset) \
((uint16_t *)((STM32_I2C1_BASE + ((port) * 0x400)) + (offset)))
#define STM32_I2C_CR1(n) REG16(stm32_i2c_reg(n, 0x00))
#define STM32_I2C_CR2(n) REG16(stm32_i2c_reg(n, 0x04))
@@ -417,6 +415,8 @@ struct spi_ctlr {
*/
#define stm32_spi_addr(port) \
((struct spi_ctlr *)(port == 0 ? STM32_SPI1_BASE : STM32_SPI2_BASE))
#define stm32_spi_port(addr) \
((addr) == STM32_SPI1_BASE ? 0 : 1)
/* --- Debug --- */

View File

@@ -22,6 +22,21 @@
#define CPUTS(outstr) cputs(CC_SPI, outstr)
#define CPRINTF(format, args...) cprintf(CC_SPI, format, ## args)
/* DMA channel option */
static const struct dma_option dma_tx_option[2] = {
{DMA_SPI1_TX, (void *)&stm32_spi_addr(STM32_SPI1_PORT)->data,
DMA_MSIZE_BYTE | DMA_PSIZE_HALF_WORD},
{DMA_SPI2_TX, (void *)&stm32_spi_addr(STM32_SPI2_PORT)->data,
DMA_MSIZE_BYTE | DMA_PSIZE_HALF_WORD},
};
static const struct dma_option dma_rx_option[2] = {
{DMA_SPI1_RX, (void *)&stm32_spi_addr(STM32_SPI1_PORT)->data,
DMA_MSIZE_BYTE | DMA_PSIZE_HALF_WORD},
{DMA_SPI2_RX, (void *)&stm32_spi_addr(STM32_SPI2_PORT)->data,
DMA_MSIZE_BYTE | DMA_PSIZE_HALF_WORD},
};
/* Status register flags that we use */
enum {
SR_RXNE = 1 << 0,
@@ -179,7 +194,7 @@ static void reply(struct spi_ctlr *spi, struct dma_channel *txdma,
/* Add the checksum and get ready to send */
msg[msg_len - 2] = sum & 0xff;
msg[msg_len - 1] = SPI_MSG_PREAMBLE_BYTE;
dma_prepare_tx(txdma, msg_len, (void *)&spi->data, msg);
dma_prepare_tx(dma_tx_option[stm32_spi_port(spi)], msg_len, msg);
/* Kick off the DMA to send the data */
dma_go(txdma);
@@ -206,7 +221,8 @@ static void setup_for_transaction(struct spi_ctlr *spi)
/* read a byte in case there is one, and the rx dma gets it */
dmac = REG16(&spi->data);
dmac = DMA_CHANNEL_FOR_SPI_RX(spi);
dma_start_rx(dmac, sizeof(in_msg), (void *)&spi->data, in_msg);
dma_start_rx(dma_rx_option[stm32_spi_port(spi)],
sizeof(in_msg), in_msg);
}
/**