diff --git a/chip/stm32/dma.c b/chip/stm32/dma.c index 06f65e12f9..aae499e4b2 100644 --- a/chip/stm32/dma.c +++ b/chip/stm32/dma.c @@ -19,36 +19,58 @@ /* Task IDs for the interrupt handlers to wake up */ static task_id_t id[DMA_NUM_CHANNELS]; +/* Registers for the DMA controller */ +struct dma_ctlr { + uint32_t isr; + uint32_t ifcr; + dma_channel_t chan[DMA_NUM_CHANNELS]; +}; + +/* Always use dma_ctlr_t so volatile keyword is included! */ +typedef volatile struct dma_ctlr dma_ctlr_t; + +/** + * Return the IRQ for the DMA channel + * + * @param channel Channel number + * @return IRQ for the channel + */ +static int dma_get_irq(enum dma_channel channel) +{ + return STM32_IRQ_DMA_CHANNEL_1 + channel; +} + +/** + * Get a pointer to the DMA peripheral controller that owns the channel + * + * @param channel Channel number to get the controller for (DMAC_...) + * @return pointer to DMA channel registers + */ +static dma_ctlr_t *dma_get_ctlr(void) +{ + return (dma_ctlr_t *)STM32_DMA1_BASE; +} + /* * Note, you must decrement the channel value by 1 from what is specified * in the datasheets, as they index from 1 and this indexes from 0! */ -struct dma_channel *dma_get_channel(int channel) +dma_channel_t *dma_get_channel(enum dma_channel channel) { - struct dma_channel *chan; - struct dma_ctlr *dma; + dma_ctlr_t *dma = dma_get_ctlr(); /* Get a pointer to the correct controller and channel */ ASSERT(channel < DMA_NUM_CHANNELS); - if (channel < DMA1_NUM_CHANNELS) { - dma = (struct dma_ctlr *)STM32_DMA1_BASE; - chan = &dma->chan[channel]; - } else { - dma = (struct dma_ctlr *)STM32_DMA2_BASE; - chan = &dma->chan[channel - DMA1_NUM_CHANNELS]; - } - return chan; + return &dma->chan[channel]; } -void dma_disable(unsigned channel) +void dma_disable(enum dma_channel channel) { - struct dma_channel *chan; + dma_channel_t *chan = dma_get_channel(channel); - chan = dma_get_channel(channel); - - if (REG32(&chan->ccr) & DMA_EN) - REG32(&chan->ccr) &= ~DMA_EN; + if (chan->ccr & DMA_EN) + chan->ccr &= ~DMA_EN; } /** @@ -57,76 +79,72 @@ void dma_disable(unsigned channel) * @param chan Channel number to read (DMAC_...) * @param count Number of bytes to transfer * @param periph Pointer to peripheral data register - * @param memory Pointer to memory address + * @param memory Pointer to memory address for receive/transmit * @param flags DMA flags for the control register, normally: DMA_MINC_MASK | * (DMA_DIR_FROM_MEM_MASK for tx * 0 for rx) */ -static void prepare_channel(struct dma_channel *chan, unsigned count, - void *periph, const void *memory, unsigned flags) +static void prepare_channel(dma_channel_t *chan, unsigned count, + void *periph, void *memory, unsigned flags) { - uint32_t ctrl; + uint32_t ctrl = DMA_PL_VERY_HIGH << DMA_PL_SHIFT; - if (REG32(&chan->ccr) & DMA_EN) - REG32(&chan->ccr) &= ~DMA_EN; + if (chan->ccr & DMA_EN) + chan->ccr &= ~DMA_EN; /* Following the order in Doc ID 15965 Rev 5 p194 */ - REG32(&chan->cpar) = (uint32_t)periph; - REG32(&chan->cmar) = (uint32_t)memory; - REG32(&chan->cndtr) = count; - ctrl = DMA_PL_VERY_HIGH << DMA_PL_SHIFT; - REG32(&chan->ccr) = ctrl; + chan->cpar = (uint32_t)periph; + chan->cmar = (uint32_t)memory; + chan->cndtr = count; + chan->ccr = ctrl; ctrl |= flags; - REG32(&chan->ccr) = ctrl; + chan->ccr = ctrl; } -void dma_go(struct dma_channel *chan) +void dma_go(dma_channel_t *chan) { /* Fire it up */ - REG32(&chan->ccr) |= DMA_EN; + chan->ccr |= DMA_EN; } void dma_prepare_tx(const struct dma_option *option, unsigned count, const void *memory) { - struct dma_channel *chan = dma_get_channel(option->channel); + dma_channel_t *chan = dma_get_channel(option->channel); - prepare_channel(chan, count, option->periph, memory, + /* + * Cast away const for memory pointer; this is ok because we know + * we're preparing the channel for transmit. + */ + prepare_channel(chan, count, option->periph, (void *)memory, DMA_MINC_MASK | DMA_DIR_FROM_MEM_MASK | option->flags); } -int dma_start_rx(const struct dma_option *option, unsigned count, - const void *memory) +void dma_start_rx(const struct dma_option *option, unsigned count, + void *memory) { - struct dma_channel *chan = dma_get_channel(option->channel); + dma_channel_t *chan = dma_get_channel(option->channel); prepare_channel(chan, count, option->periph, memory, DMA_MINC_MASK | option->flags); dma_go(chan); - return 0; } -int dma_bytes_done(struct dma_channel *chan, int orig_count) +int dma_bytes_done(dma_channel_t *chan, int orig_count) { - if (!(REG32(&chan->ccr) & DMA_EN)) + if (!(chan->ccr & DMA_EN)) return 0; - return orig_count - REG32(&chan->cndtr); + return orig_count - chan->cndtr; } - #ifdef CONFIG_DMA_HELP -void dma_dump(unsigned channel) +void dma_dump(enum dma_channel channel) { - struct dma_channel *chan; - struct dma_ctlr *dma; + dma_ctlr_t *dma = dma_get_ctlr(); + dma_channel_t *chan = dma_get_channel(channel); - /* Get a pointer to the correct controller and channel */ - ASSERT(channel < DMA_NUM_CHANNELS); - dma = (struct dma_ctlr *)STM32_DMA1_BASE; - - chan = dma_get_channel(channel); CPRINTF("ccr=%x, cndtr=%x, cpar=%x, cmar=%x\n", chan->ccr, chan->cndtr, chan->cpar, chan->cmar); CPRINTF("chan %d, isr=%x, ifcr=%x\n", @@ -135,61 +153,58 @@ void dma_dump(unsigned channel) (dma->ifcr >> (channel * 4)) & 0xf); } -void dma_check(int channel, char *buff) +void dma_check(enum dma_channel channel, char *buf) { - struct dma_channel *chan; + dma_channel_t *chan; int count; int i; chan = dma_get_channel(channel); - count = REG32(&chan->cndtr); + count = chan->cndtr; CPRINTF("c=%d\n", count); - udelay(1000 * 100); - CPRINTF("c=%d\n", - REG32(&chan->cndtr)); + udelay(100 * MSEC); + CPRINTF("c=%d\n", chan->cndtr); for (i = 0; i < count; i++) - CPRINTF("%02x ", buff[i]); - udelay(1000 * 100); - CPRINTF("c=%d\n", - REG32(&chan->cndtr)); + CPRINTF("%02x ", buf[i]); + udelay(100 * MSEC); + CPRINTF("c=%d\n", chan->cndtr); for (i = 0; i < count; i++) - CPRINTF("%02x ", buff[i]); + CPRINTF("%02x ", buf[i]); } /* Run a check of memory-to-memory DMA */ void dma_test(void) { + dma_channel_t *chan = dma_get_channel(channel); unsigned channel = 3; - struct dma_channel *chan; uint32_t ctrl; char periph[16], memory[16]; unsigned count = sizeof(periph); int i; - chan = dma_get_channel(channel); memset(memory, '\0', sizeof(memory)); for (i = 0; i < count; i++) periph[i] = 10 + i; /* Following the order in Doc ID 15965 Rev 5 p194 */ - REG32(&chan->cpar) = (uint32_t)periph; - REG32(&chan->cmar) = (uint32_t)memory; - REG32(&chan->cndtr) = count; + chan->cpar = (uint32_t)periph; + chan->cmar = (uint32_t)memory; + chan->cndtr = count; ctrl = DMA_PL_MEDIUM << DMA_PL_SHIFT; - REG32(&chan->ccr) = ctrl; + chan->ccr = ctrl; ctrl |= DMA_MINC_MASK; /* | DMA_DIR_FROM_MEM_MASK */; ctrl |= 1 << 14; /* MEM2MEM */ ctrl |= 1 << 6; /* PINC */ /* ctrl |= 2 << 10; */ /* ctrl |= 2 << 8; */ - REG32(&chan->ccr) = ctrl; + chan->ccr = ctrl; ctrl |= DMA_EN; - REG32(&chan->ccr) = ctrl; + chan->ccr = ctrl; for (i = 0; i < count; i++) CPRINTF("%d/%d ", periph[i], memory[i]); - CPRINTF("\ncount=%d\n", REG32(&chan->cndtr)); + CPRINTF("\ncount=%d\n", chan->cndtr); } #endif /* CONFIG_DMA_HELP */ @@ -197,7 +212,7 @@ static void dma_init(void) { int i; - /* Enable DMA1, we don't support DMA2 yet */ + /* Enable DMA1; current chips don't have DMA2 */ STM32_RCC_AHBENR |= RCC_AHBENR_DMA1EN; /* Initialize data for interrupt handlers */ @@ -206,106 +221,78 @@ static void dma_init(void) } DECLARE_HOOK(HOOK_INIT, dma_init, HOOK_PRIO_INIT_DMA); -int dma_wait(int channel) +int dma_wait(enum dma_channel channel) { - struct dma_ctlr *dma; - uint32_t mask; + dma_ctlr_t *dma = dma_get_ctlr(); + uint32_t mask = DMA_TCIF(channel); timestamp_t deadline; - dma = dma_get_ctlr(channel); - mask = DMA_TCIF(channel); - deadline.val = get_time().val + DMA_TRANSFER_TIMEOUT_US; - while ((REG32(&dma->isr) & mask) != mask) { + while ((dma->isr & mask) != mask) { if (deadline.val <= get_time().val) - return -1; + return EC_ERROR_TIMEOUT; else udelay(DMA_POLLING_INTERVAL_US); } - return 0; + return EC_SUCCESS; } -int dma_get_irq(int channel) +void dma_enable_tc_interrupt(enum dma_channel channel) { - ASSERT(channel < DMA_NUM_CHANNELS); - if (channel < DMA1_NUM_CHANNELS) - return STM32_IRQ_DMA_CHANNEL_1 + channel; - else - return STM32_IRQ_DMA2_CHANNEL1 + channel - - DMA1_NUM_CHANNELS; -} + dma_channel_t *chan = dma_get_channel(channel); -void dma_enable_tc_interrupt(int channel) -{ - struct dma_channel *chan; - chan = dma_get_channel(channel); - - /* Storing task ID's so the ISRs knows which task to wake */ + /* Store task ID so the ISR knows which task to wake */ id[channel] = task_get_current(); - REG32(&chan->ccr) |= DMA_TCIE; + chan->ccr |= DMA_TCIE; task_enable_irq(dma_get_irq(channel)); } -void dma_disable_tc_interrupt(int channel) +void dma_disable_tc_interrupt(enum dma_channel channel) { - struct dma_channel *chan; - chan = dma_get_channel(channel); + dma_channel_t *chan = dma_get_channel(channel); id[channel] = TASK_ID_INVALID; - REG32(&chan->ccr) &= ~DMA_TCIE; + chan->ccr &= ~DMA_TCIE; task_disable_irq(dma_get_irq(channel)); } -void dma_clear_isr(int channel) +void dma_clear_isr(enum dma_channel channel) { - struct dma_ctlr *dma; + dma_ctlr_t *dma = dma_get_ctlr(); - dma = dma_get_ctlr(channel); - /* Adjusting the channel number if it's from the second DMA */ - if (channel > DMA1_NUM_CHANNELS) - channel -= DMA1_NUM_CHANNELS; - REG32(&dma->ifcr) |= 0x0f << (4 * channel); -} - -struct dma_ctlr *dma_get_ctlr(int channel) -{ - ASSERT(channel < DMA_NUM_CHANNELS); - if (channel < DMA1_NUM_CHANNELS) - return (struct dma_ctlr *)STM32_DMA1_BASE; - else - return (struct dma_ctlr *)STM32_DMA2_BASE; + dma->ifcr |= 0x0f << (4 * channel); } static void dma_event_interrupt_channel_4(void) { - dma_clear_isr(DMAC_I2C2_TX); - if (id[DMAC_I2C2_TX] != TASK_ID_INVALID) - task_wake(id[DMAC_I2C2_TX]); + dma_clear_isr(DMAC_CH4); + if (id[DMAC_CH4] != TASK_ID_INVALID) + task_wake(id[DMAC_CH4]); } DECLARE_IRQ(STM32_IRQ_DMA_CHANNEL_4, dma_event_interrupt_channel_4, 3); static void dma_event_interrupt_channel_5(void) { - dma_clear_isr(DMAC_I2C2_RX); - if (id[DMAC_I2C2_RX] != TASK_ID_INVALID) - task_wake(id[DMAC_I2C2_RX]); + dma_clear_isr(DMAC_CH5); + if (id[DMAC_CH5] != TASK_ID_INVALID) + task_wake(id[DMAC_CH5]); } DECLARE_IRQ(STM32_IRQ_DMA_CHANNEL_5, dma_event_interrupt_channel_5, 3); static void dma_event_interrupt_channel_6(void) { - dma_clear_isr(DMAC_I2C1_TX); - if (id[DMAC_I2C1_TX] != TASK_ID_INVALID) - task_wake(id[DMAC_I2C1_TX]); + dma_clear_isr(DMAC_CH6); + if (id[DMAC_CH6] != TASK_ID_INVALID) + task_wake(id[DMAC_CH6]); } DECLARE_IRQ(STM32_IRQ_DMA_CHANNEL_6, dma_event_interrupt_channel_6, 3); static void dma_event_interrupt_channel_7(void) { - dma_clear_isr(DMAC_I2C1_RX); - if (id[DMAC_I2C1_RX] != TASK_ID_INVALID) - task_wake(id[DMAC_I2C1_RX]); + dma_clear_isr(DMAC_CH7); + if (id[DMAC_CH7] != TASK_ID_INVALID) + task_wake(id[DMAC_CH7]); } DECLARE_IRQ(STM32_IRQ_DMA_CHANNEL_7, dma_event_interrupt_channel_7, 3); diff --git a/chip/stm32/i2c-stm32f100.c b/chip/stm32/i2c-stm32f100.c index 6803f1fa33..a76987ac74 100644 --- a/chip/stm32/i2c-stm32f100.c +++ b/chip/stm32/i2c-stm32f100.c @@ -127,7 +127,7 @@ static void i2c_init_port(unsigned int port); static int i2c_write_raw_slave(int port, void *buf, int len) { - struct dma_channel *chan; + dma_channel_t *chan; int rv; /* we don't want to race with TxE interrupt event */ diff --git a/chip/stm32/spi.c b/chip/stm32/spi.c index b557875126..eac7736bcc 100644 --- a/chip/stm32/spi.c +++ b/chip/stm32/spi.c @@ -121,7 +121,7 @@ static const uint8_t out_preamble[4] = { * @param nss_mask Bit to check in GPIO register (when high, we abort) * @return 0 if bytes received, -1 if we hit a timeout or NSS went high */ -static int wait_for_bytes(struct dma_channel *rxdma, int needed, +static int wait_for_bytes(dma_channel_t *rxdma, int needed, uint16_t *nss_reg, uint32_t nss_mask) { timestamp_t deadline; @@ -178,7 +178,7 @@ static int wait_for_bytes(struct dma_channel *rxdma, int needed, * SPI_MSG_HEADER_LEN bytes into out_msg * @param msg_len Number of message bytes to send */ -static void reply(struct dma_channel *txdma, +static void reply(dma_channel_t *txdma, enum ec_status status, char *msg_ptr, int msg_len) { char *msg; @@ -250,7 +250,7 @@ static void setup_for_transaction(void) static void spi_send_response(struct host_cmd_handler_args *args) { enum ec_status result = args->result; - struct dma_channel *txdma; + dma_channel_t *txdma; /* If we are too late, don't bother */ if (!active) @@ -277,7 +277,7 @@ static void spi_send_response(struct host_cmd_handler_args *args) */ static void spi_send_response_packet(struct host_packet *pkt) { - struct dma_channel *txdma; + dma_channel_t *txdma; /* If we are too late, don't bother */ if (!active) @@ -300,7 +300,7 @@ static void spi_send_response_packet(struct host_packet *pkt) */ void spi_event(enum gpio_signal signal) { - struct dma_channel *rxdma; + dma_channel_t *rxdma; uint16_t *nss_reg; uint32_t nss_mask; diff --git a/include/dma.h b/include/dma.h index c784558612..eeefc45654 100644 --- a/include/dma.h +++ b/include/dma.h @@ -11,37 +11,43 @@ #include "common.h" /* - * Available DMA channels, numbered from 0 + * Available DMA channels, numbered from 0. * * Note: The STM datasheet tends to number things from 1. We should ask * the European elevator engineers to talk to MCU engineer counterparts * about this. This means that if the datasheet refers to channel n, - * you need to use n-1 in the code. + * you need to use DMAC_CHn (=n-1) in the code. + * + * Also note that channels are overloaded; obviously you can only use one + * function on each channel at a time. */ -enum { - DMAC_ADC, - DMAC_SPI1_RX, - DMAC_SPI1_TX, - DMAC_SPI2_RX, - DMAC_SPI2_TX, +enum dma_channel { + /* Channel numbers */ + DMAC_CH1 = 0, + DMAC_CH2 = 1, + DMAC_CH3 = 2, + DMAC_CH4 = 3, + DMAC_CH5 = 4, + DMAC_CH6 = 5, + DMAC_CH7 = 6, - /* - * The same channels are used for i2c2 and spi, you can't use them at - * the same time or it will cause dma to not work - */ - DMAC_I2C2_TX = 3, - DMAC_I2C2_RX = 4, - DMAC_I2C1_TX = 5, - DMAC_I2C1_RX = 6, + /* Channel functions */ + DMAC_ADC = DMAC_CH1, + DMAC_SPI1_RX = DMAC_CH2, + DMAC_SPI1_TX = DMAC_CH3, + DMAC_I2C2_TX = DMAC_CH4, + DMAC_I2C2_RX = DMAC_CH5, + DMAC_USART1_TX = DMAC_CH4, + DMAC_USART1_RX = DMAC_CH5, + DMAC_I2C1_TX = DMAC_CH6, + DMAC_I2C1_RX = DMAC_CH7, - /* DMA1 has 7 channels, DMA2 has 5 */ - DMA1_NUM_CHANNELS = 7, - DMA2_NUM_CHANNELS = 5, - DMA_NUM_CHANNELS = DMA1_NUM_CHANNELS + DMA2_NUM_CHANNELS, + /* Only DMA1 (with 7 channels) is present on STM32F100 and STM32L151x */ + DMA_NUM_CHANNELS = 7, }; -/* A single channel of the DMA controller */ -struct dma_channel { +/* Registers for a single channel of the DMA controller */ +struct dma_channel_regs { uint32_t ccr; /* Control */ uint32_t cndtr; /* Number of data to transfer */ uint32_t cpar; /* Peripheral address */ @@ -49,16 +55,12 @@ struct dma_channel { uint32_t reserved; }; -/* Registers for the DMA controller */ -struct dma_ctlr { - uint32_t isr; - uint32_t ifcr; - struct dma_channel chan[DMA_NUM_CHANNELS]; -}; +/* Always use dma_channel_t so volatile keyword is included! */ +typedef volatile struct dma_channel_regs dma_channel_t; /* DMA channel options */ struct dma_option { - unsigned channel; /* DMA channel */ + enum dma_channel channel; /* DMA channel */ void *periph; /* Pointer to peripheral data register */ unsigned flags; /* DMA flags for the control register. Normally used to select memory size. */ @@ -93,28 +95,13 @@ enum { #define DMA_POLLING_INTERVAL_US 100 /* us */ #define DMA_TRANSFER_TIMEOUT_US (100 * MSEC) /* us */ -/* - * Certain DMA channels must be used for certain peripherals and transfer - * directions. We provide an easy way for drivers to select the correct - * channel. - */ - -/** - * @param spi SPI port to request: STM32_SPI1_PORT or STM32_SPI2_PORT - * @return DMA channel to use for rx / tx on that port - */ -#define DMA_CHANNEL_FOR_SPI_RX(spi) \ - ((spi) == STM32_SPI1_PORT ? DMAC_SPI1_RX : DMAC_SPI2_RX) -#define DMA_CHANNEL_FOR_SPI_TX(spi) \ - ((spi) == STM32_SPI1_PORT ? DMAC_SPI1_TX : DMAC_SPI2_TX) - /** * Get a pointer to a DMA channel. * - * @param channel Channel number to read (DMAC_...) + * @param channel Channel to read * @return pointer to DMA channel registers */ -struct dma_channel *dma_get_channel(int channel); +dma_channel_t *dma_get_channel(enum dma_channel channel); /** * Prepare a DMA transfer to transmit data from memory to a peripheral @@ -137,17 +124,17 @@ void dma_prepare_tx(const struct dma_option *option, unsigned count, * @param count Number of bytes to transfer * @param memory Pointer to memory address */ -int dma_start_rx(const struct dma_option *option, unsigned count, - const void *memory); +void dma_start_rx(const struct dma_option *option, unsigned count, + void *memory); /** * Stop a DMA transfer on a channel * * Disable the DMA channel and immediate stop all transfers on it. * - * @param channel Channel number to stop (DMAC_...) + * @param channel Channel to stop */ -void dma_disable(unsigned channel); +void dma_disable(enum dma_channel channel); /** * Get the number of bytes available to read, or number of bytes written @@ -155,75 +142,69 @@ void dma_disable(unsigned channel); * Since the DMA controller counts downwards, if we know the starting value * we can work out how many bytes have been completed so far. * - * @param chan DMA channel to check (use dma_get_channel()) + * @param chan DMA channel to check, from dma_get_channel() * @param orig_count Original number of bytes requested on channel * @return number of bytes completed on a channel, or 0 if this channel is * not enabled */ -int dma_bytes_done(struct dma_channel *chan, int orig_count); +int dma_bytes_done(dma_channel_t *chan, int orig_count); /** * Start a previously-prepared dma channel * - * @param chan Channel to start (returned from dma_prepare...()) + * @param chan Channel to start, from dma_get_channel() */ -void dma_go(struct dma_channel *chan); +void dma_go(dma_channel_t *chan); +#ifdef CONFIG_DMA_HELP /** * Testing: Print out the data transferred by a channel * - * @param channel Channel number to read (DMAC_...) + * @param channel Channel to read * @param buff Start of DMA buffer */ -void dma_check(int channel, char *buff); +void dma_check(enum dma_channel channel, char *buf); /** * Dump out imformation about a dma channel * - * @param channel Channel number to read (DMAC_...) + * @param channel Channel to read */ -void dma_dump(unsigned channel); +void dma_dump(enum dma_channel channel); /** * Testing: Test that DMA works correctly for memory to memory transfers */ void dma_test(void); +#endif /* CONFIG_DMA_HELP */ /** * Clear the DMA interrupt/event flags for a given channel * - * @param channel Which channel's isr to clear (DMAC_...) + * @param channel Which channel's isr to clear */ -void dma_clear_isr(int channel); +void dma_clear_isr(enum dma_channel channel); /** * Enable "Transfer Complete" interrupt for a DMA channel * - * @param channel Which channel's interrupts to change (DMAC_...) + * @param channel Which channel's interrupts to change */ -void dma_enable_tc_interrupt(int channel); +void dma_enable_tc_interrupt(enum dma_channel channel); /** * Disable "Transfer Complete" interrupt for a DMA channel * - * @param channel Which channel's interrupts to change (DMAC_...) + * @param channel Which channel's interrupts to change */ -void dma_disable_tc_interrupt(int channel); - -/** - * Get a pointer to the DMA peripheral controller that owns the channel - * - * @param channel Channel number to get the controller for (DMAC_...) - * @return pointer to DMA channel registers - */ -struct dma_ctlr *dma_get_ctlr(int channel); +void dma_disable_tc_interrupt(enum dma_channel channel); /** * Wait for the DMA transfer to complete by polling the transfer complete flag * - * @param channelĀ» Channel number to wait on (DMAC_...) - * @return -1 for timeout, 0 for sucess + * @param channel Channel number to wait on + * @return EC_ERROR_TIMEOUT for timeout, EC_SUCCESS for success */ -int dma_wait(int channel); +int dma_wait(enum dma_channel channel); #endif