summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--chip/stm32/dma.c63
-rw-r--r--chip/stm32/usb_pd_phy.c101
-rw-r--r--include/config.h3
-rw-r--r--include/dma.h16
-rw-r--r--include/task.h4
5 files changed, 94 insertions, 93 deletions
diff --git a/chip/stm32/dma.c b/chip/stm32/dma.c
index 0f2e89bc14..096ec45186 100644
--- a/chip/stm32/dma.c
+++ b/chip/stm32/dma.c
@@ -16,8 +16,11 @@
#define CPUTS(outstr) cputs(CC_DMA, outstr)
#define CPRINTF(format, args...) cprintf(CC_DMA, format, ## args)
-/* Task IDs for the interrupt handlers to wake up */
-static task_id_t id[STM32_DMAC_COUNT];
+/* Callback data to use when IRQ fires */
+static struct {
+ void (*cb)(void *); /* Callback function to call */
+ void *cb_data; /* Callback data for callback function */
+} dma_irq[STM32_DMAC_COUNT];
/**
* Return the IRQ for the DMA channel
@@ -206,14 +209,8 @@ void dma_test(void)
void dma_init(void)
{
- int i;
-
/* Enable DMA1; current chips don't have DMA2 */
STM32_RCC_AHBENR |= STM32_RCC_HB_DMA1;
-
- /* Initialize data for interrupt handlers */
- for (i = 0; i < STM32_DMAC_COUNT; i++)
- id[i] = TASK_ID_INVALID;
}
int dma_wait(enum dma_channel channel)
@@ -232,12 +229,27 @@ int dma_wait(enum dma_channel channel)
return EC_SUCCESS;
}
+static inline void _dma_wake_callback(void *cb_data)
+{
+ task_id_t id = (task_id_t)(int)cb_data;
+ if (id != TASK_ID_INVALID)
+ task_set_event(id, TASK_EVENT_DMA_TC, 0);
+}
+
void dma_enable_tc_interrupt(enum dma_channel channel)
{
+ dma_enable_tc_interrupt_callback(channel, _dma_wake_callback,
+ (void *)(int)task_get_current());
+}
+
+void dma_enable_tc_interrupt_callback(enum dma_channel channel,
+ void (*callback)(void *),
+ void *callback_data)
+{
stm32_dma_chan_t *chan = dma_get_channel(channel);
- /* Store task ID so the ISR knows which task to wake */
- id[channel] = task_get_current();
+ dma_irq[channel].cb = callback;
+ dma_irq[channel].cb_data = callback_data;
chan->ccr |= STM32_DMA_CCR_TCIE;
task_enable_irq(dma_get_irq(channel));
@@ -247,10 +259,11 @@ void dma_disable_tc_interrupt(enum dma_channel channel)
{
stm32_dma_chan_t *chan = dma_get_channel(channel);
- id[channel] = TASK_ID_INVALID;
-
chan->ccr &= ~STM32_DMA_CCR_TCIE;
task_disable_irq(dma_get_irq(channel));
+
+ dma_irq[channel].cb = NULL;
+ dma_irq[channel].cb_data = NULL;
}
void dma_clear_isr(enum dma_channel channel)
@@ -266,11 +279,12 @@ void dma_event_interrupt_channel_1(void)
{
if (STM32_DMA1_REGS->isr & STM32_DMA_ISR_TCIF(STM32_DMAC_CH1)) {
dma_clear_isr(STM32_DMAC_CH1);
- if (id[STM32_DMAC_CH1] != TASK_ID_INVALID)
- task_wake(id[STM32_DMAC_CH1]);
+ if (dma_irq[STM32_DMAC_CH1].cb != NULL)
+ (*dma_irq[STM32_DMAC_CH1].cb)
+ (dma_irq[STM32_DMAC_CH1].cb_data);
}
}
-DECLARE_IRQ(STM32_IRQ_DMA_CHANNEL_1, dma_event_interrupt_channel_1, 3);
+DECLARE_IRQ(STM32_IRQ_DMA_CHANNEL_1, dma_event_interrupt_channel_1, 1);
void dma_event_interrupt_channel_2_3(void)
{
@@ -279,12 +293,12 @@ void dma_event_interrupt_channel_2_3(void)
for (i = STM32_DMAC_CH2; i <= STM32_DMAC_CH3; i++) {
if (STM32_DMA1_REGS->isr & STM32_DMA_ISR_TCIF(i)) {
dma_clear_isr(i);
- if (id[i] != TASK_ID_INVALID)
- task_wake(id[i]);
+ if (dma_irq[i].cb != NULL)
+ (*dma_irq[i].cb)(dma_irq[i].cb_data);
}
}
}
-DECLARE_IRQ(STM32_IRQ_DMA_CHANNEL_2_3, dma_event_interrupt_channel_2_3, 3);
+DECLARE_IRQ(STM32_IRQ_DMA_CHANNEL_2_3, dma_event_interrupt_channel_2_3, 1);
void dma_event_interrupt_channel_4_7(void)
{
@@ -293,12 +307,12 @@ void dma_event_interrupt_channel_4_7(void)
for (i = STM32_DMAC_CH4; i <= STM32_DMAC_CH7; i++) {
if (STM32_DMA1_REGS->isr & STM32_DMA_ISR_TCIF(i)) {
dma_clear_isr(i);
- if (id[i] != TASK_ID_INVALID)
- task_wake(id[i]);
+ if (dma_irq[i].cb != NULL)
+ (*dma_irq[i].cb)(dma_irq[i].cb_data);
}
}
}
-DECLARE_IRQ(STM32_IRQ_DMA_CHANNEL_4_7, dma_event_interrupt_channel_4_7, 3);
+DECLARE_IRQ(STM32_IRQ_DMA_CHANNEL_4_7, dma_event_interrupt_channel_4_7, 1);
#else /* !CHIP_FAMILY_STM32F0 */
@@ -306,11 +320,12 @@ DECLARE_IRQ(STM32_IRQ_DMA_CHANNEL_4_7, dma_event_interrupt_channel_4_7, 3);
void CONCAT2(dma_event_interrupt_channel_, x)(void) \
{ \
dma_clear_isr(CONCAT2(STM32_DMAC_CH, x)); \
- if (id[CONCAT2(STM32_DMAC_CH, x)] != TASK_ID_INVALID) \
- task_wake(id[CONCAT2(STM32_DMAC_CH, x)]); \
+ if (dma_irq[CONCAT2(STM32_DMAC_CH, x)].cb != NULL) \
+ (*dma_irq[CONCAT2(STM32_DMAC_CH, x)].cb) \
+ (dma_irq[CONCAT2(STM32_DMAC_CH, x)].cb_data); \
} \
DECLARE_IRQ(CONCAT2(STM32_IRQ_DMA_CHANNEL_, x), \
- CONCAT2(dma_event_interrupt_channel_, x), 3);
+ CONCAT2(dma_event_interrupt_channel_, x), 1);
DECLARE_DMA_IRQ(1);
DECLARE_DMA_IRQ(2);
diff --git a/chip/stm32/usb_pd_phy.c b/chip/stm32/usb_pd_phy.c
index 55c465986d..1a09b8e07a 100644
--- a/chip/stm32/usb_pd_phy.c
+++ b/chip/stm32/usb_pd_phy.c
@@ -76,6 +76,9 @@ static struct pd_physical {
static timestamp_t rx_edge_ts[PD_PORT_COUNT][PD_RX_TRANSITION_COUNT];
static int rx_edge_ts_idx[PD_PORT_COUNT];
+/* keep track of transmit polarity for DMA interrupt */
+static int tx_dma_polarities[PD_PORT_COUNT];
+
void pd_init_dequeue(int port)
{
/* preamble ends with 1 */
@@ -273,26 +276,10 @@ void pd_tx_spi_init(int port)
/* Enable Tx DMA for our first transaction */
spi->cr2 = STM32_SPI_CR2_TXDMAEN | STM32_SPI_CR2_DATASIZE(8);
-#ifdef CONFIG_USB_PD_TX_USES_SPI_MASTER
- /*
- * Enable the master SPI: LSB first, force NSS, TX only, CPOL and CPHA
- * high.
- */
- spi->cr1 = STM32_SPI_CR1_LSBFIRST | STM32_SPI_CR1_BIDIMODE
- | STM32_SPI_CR1_SSM | STM32_SPI_CR1_SSI
- | STM32_SPI_CR1_BIDIOE | STM32_SPI_CR1_MSTR
- | STM32_SPI_CR1_BR_DIV64R | STM32_SPI_CR1_SPE
- | STM32_SPI_CR1_CPOL | STM32_SPI_CR1_CPHA;
-
-#if CPU_CLOCK != 38400000
-#error "CPU_CLOCK must be 38.4MHz to use SPI master for USB PD Tx"
-#endif
-#else
/* Enable the slave SPI: LSB first, force NSS, TX only, CPHA */
spi->cr1 = STM32_SPI_CR1_SPE | STM32_SPI_CR1_LSBFIRST
| STM32_SPI_CR1_SSM | STM32_SPI_CR1_BIDIMODE
| STM32_SPI_CR1_BIDIOE | STM32_SPI_CR1_CPHA;
-#endif
}
void pd_tx_set_circular_mode(int port)
@@ -300,6 +287,28 @@ void pd_tx_set_circular_mode(int port)
pd_phy[port].dma_tx_option.flags |= STM32_DMA_CCR_CIRC;
}
+static void tx_dma_done(void *data)
+{
+ int port = (int)data;
+ int polarity = tx_dma_polarities[port];
+ stm32_spi_regs_t *spi = SPI_REGS(port);
+
+ while (spi->sr & STM32_SPI_SR_FTLVL)
+ ; /* wait for TX FIFO empty */
+ while (spi->sr & STM32_SPI_SR_BSY)
+ ; /* wait for BSY == 0 */
+
+ /* put TX pins and reference in Hi-Z */
+ pd_tx_disable(port, polarity);
+
+ /* Stop counting */
+ pd_phy[port].tim_tx->cr1 &= ~1;
+
+#if defined(CONFIG_COMMON_RUNTIME) && defined(CONFIG_DMA_DEFAULT_HANDLERS)
+ task_set_event(PORT_TO_TASK_ID(port), TASK_EVENT_DMA_TC, 0);
+#endif
+}
+
int pd_start_tx(int port, int polarity, int bit_len)
{
stm32_dma_chan_t *tx = dma_get_channel(DMAC_SPI_TX(port));
@@ -329,8 +338,10 @@ int pd_start_tx(int port, int polarity, int bit_len)
/* Kick off the DMA to send the data */
dma_clear_isr(DMAC_SPI_TX(port));
-#ifdef CONFIG_COMMON_RUNTIME
- dma_enable_tc_interrupt(DMAC_SPI_TX(port));
+#if defined(CONFIG_COMMON_RUNTIME) && defined(CONFIG_DMA_DEFAULT_HANDLERS)
+ tx_dma_polarities[port] = polarity;
+ dma_enable_tc_interrupt_callback(DMAC_SPI_TX(port), &tx_dma_done,
+ (void *)port);
#endif
dma_go(tx);
@@ -343,65 +354,29 @@ int pd_start_tx(int port, int polarity, int bit_len)
*/
pd_tx_enable(port, polarity);
-#ifndef CONFIG_USB_PD_TX_USES_SPI_MASTER
/* Start counting at 300Khz*/
pd_phy[port].tim_tx->cr1 |= 1;
-#endif
return bit_len;
}
void pd_tx_done(int port, int polarity)
{
- stm32_spi_regs_t *spi = SPI_REGS(port);
+#if defined(CONFIG_COMMON_RUNTIME) && defined(CONFIG_DMA_DEFAULT_HANDLERS)
+ int rv;
- /* wait for DMA */
-#ifdef CONFIG_COMMON_RUNTIME
- task_wait_event(DMA_TRANSFER_TIMEOUT_US);
+ /* wait for DMA, DMA interrupt will stop the SPI clock */
+ do {
+ rv = task_wait_event(DMA_TRANSFER_TIMEOUT_US);
+ } while (!(rv & (TASK_EVENT_TIMER | TASK_EVENT_DMA_TC)));
dma_disable_tc_interrupt(DMAC_SPI_TX(port));
-#endif
-
- /* wait for real end of transmission */
-#if defined(CHIP_FAMILY_STM32F0) || defined(CHIP_FAMILY_STM32F3)
- while (spi->sr & STM32_SPI_SR_FTLVL)
- ; /* wait for TX FIFO empty */
-#else
- while (!(spi->sr & STM32_SPI_SR_TXE))
- ; /* wait for TXE == 1 */
-#endif
-
- /*
- * At the end of transmitting, the last bit is guaranteed by the
- * protocol to be low, and it is necessary that the TX line stay low
- * until pd_tx_disable().
- *
- * When using SPI slave mode for TX, this is done by writing out dummy
- * 0 byte at end.
- * When using SPI master mode, the CPOL and CPHA are set high, which
- * means that after the last bit is transmitted there are no more
- * clock edges. Hopefully, this is sufficient to guarantee that the
- * MOSI line does not change before pd_tx_disable().
- */
-#ifndef CONFIG_USB_PD_TX_USES_SPI_MASTER
- /* ensure that we are not pushing out junk */
- *(uint8_t *)&spi->dr = 0;
- while (spi->sr & STM32_SPI_SR_FTLVL)
- ; /* wait for TX FIFO empty */
#else
- while (spi->sr & STM32_SPI_SR_BSY)
- ; /* wait for BSY == 0 */
+ tx_dma_polarities[port] = polarity;
+ tx_dma_done((void *)port);
#endif
- /* put TX pins and reference in Hi-Z */
- pd_tx_disable(port, polarity);
-
-#ifndef CONFIG_USB_PD_TX_USES_SPI_MASTER
- /* Stop counting */
- pd_phy[port].tim_tx->cr1 &= ~1;
-
/* Reset SPI to clear remaining data in buffer */
pd_tx_spi_reset(port);
-#endif
}
/* --- RX operation using comparator linked to timer --- */
@@ -542,7 +517,6 @@ void pd_hw_init(int port)
phy->tim_tx = (void *)TIM_REG_TX(port);
phy->tim_rx = (void *)TIM_REG_RX(port);
-#ifndef CONFIG_USB_PD_TX_USES_SPI_MASTER
/* --- set the TX timer with updates at 600KHz (BMC frequency) --- */
__hw_timer_enable_clock(TIM_CLOCK_PD_TX(port), 1);
/* Timer configuration */
@@ -567,7 +541,6 @@ void pd_hw_init(int port)
phy->tim_tx->psc = 0;
/* Reload the pre-scaler and reset the counter */
phy->tim_tx->egr = 0x0001;
-#endif
#ifndef CONFIG_USB_PD_TX_PHY_ONLY
/* configure RX DMA */
phy->dma_tim_option.channel = DMAC_TIM_RX(port);
diff --git a/include/config.h b/include/config.h
index e1ae4750d4..2270277265 100644
--- a/include/config.h
+++ b/include/config.h
@@ -1174,9 +1174,6 @@
/* Use comparator module for PD RX interrupt */
#define CONFIG_USB_PD_RX_COMP_IRQ
-/* USB PD transmit uses SPI master */
-#undef CONFIG_USB_PD_TX_USES_SPI_MASTER
-
/* Support for USB type-c superspeed mux */
#undef CONFIG_USBC_SS_MUX
diff --git a/include/dma.h b/include/dma.h
index 5e5553a794..3ecef70361 100644
--- a/include/dma.h
+++ b/include/dma.h
@@ -118,13 +118,27 @@ void dma_test(void);
void dma_clear_isr(enum dma_channel channel);
/**
- * Enable "Transfer Complete" interrupt for a DMA channel
+ * Enable "Transfer Complete" interrupt for a DMA channel.
+ * Will Wake up calling task when complete.
*
* @param channel Which channel's interrupts to change
*/
void dma_enable_tc_interrupt(enum dma_channel channel);
/**
+ * Enable "Transfer Complete" interrupt for a DMA channel with callback
+ * NOTE: The callback is run at highest interrupt priority so should be
+ * fast and not depend on get_time().
+ *
+ * @param channel Which channel's interrupts to change
+ * @param callback Pointer to callback function to call on interrupt
+ * @param callback_data Data to pass through to callback function
+ */
+void dma_enable_tc_interrupt_callback(enum dma_channel channel,
+ void (*callback)(void *),
+ void *callback_data);
+
+/**
* Disable "Transfer Complete" interrupt for a DMA channel
*
* @param channel Which channel's interrupts to change
diff --git a/include/task.h b/include/task.h
index 1ec546fdb1..0c71e804ba 100644
--- a/include/task.h
+++ b/include/task.h
@@ -13,7 +13,9 @@
/* Task event bitmasks */
/* Tasks may use the bits in TASK_EVENT_CUSTOM for their own events */
-#define TASK_EVENT_CUSTOM(x) (x & 0x07ffffff)
+#define TASK_EVENT_CUSTOM(x) (x & 0x03ffffff)
+/* DMA transmit complete event */
+#define TASK_EVENT_DMA_TC (1 << 26)
/* ADC interrupt handler event */
#define TASK_EVENT_ADC_DONE (1 << 27)
/* I2C interrupt handler event */