From 47c7e189b9adb5819316be66a410e47149a2ddea Mon Sep 17 00:00:00 2001 From: Vincent Palatin Date: Thu, 21 Dec 2017 09:59:57 +0100 Subject: stm32: add SPI slave support for STM32H7 Update the host command support on the STM32 SPI slave for the STM32H7 silicon. Signed-off-by: Vincent Palatin BRANCH=none BUG=b:67081508 TEST=with a servo v2 connected to ZerbleBarn, send host commands v3 through the servo FTDI SPI interface. Change-Id: I26ff4b6a3a45e446cd16e9da43c6932c24c37256 Reviewed-on: https://chromium-review.googlesource.com/839864 Commit-Ready: Vincent Palatin Tested-by: Vincent Palatin Reviewed-by: Shawn N --- chip/stm32/registers.h | 8 ++++++++ chip/stm32/spi.c | 54 ++++++++++++++++++++++++++++++++++++++++---------- 2 files changed, 51 insertions(+), 11 deletions(-) diff --git a/chip/stm32/registers.h b/chip/stm32/registers.h index e8a8f826aa..df9b83b3d8 100644 --- a/chip/stm32/registers.h +++ b/chip/stm32/registers.h @@ -1597,6 +1597,7 @@ struct stm32_spi_regs { uint32_t crcpoly; uint32_t rxcrcr; uint32_t txcrcr; + uint32_t udrdr; #else /* !CHIP_FAMILY_STM32H7 */ uint16_t cr1; uint16_t _pad0; @@ -1628,6 +1629,12 @@ typedef volatile struct stm32_spi_regs stm32_spi_regs_t; #define STM32_SPI_CR1_DIV(div) ((div) << 28) #define STM32_SPI_CFG1_DATASIZE(n) (((n) - 1) << 0) #define STM32_SPI_CFG1_FTHLV(n) (((n) - 1) << 5) +#define STM32_SPI_CFG1_UDRCFG_CONST (0 << 9) +#define STM32_SPI_CFG1_UDRCFG_LAST_RX (1 << 9) +#define STM32_SPI_CFG1_UDRCFG_LAST_TX (2 << 9) +#define STM32_SPI_CFG1_UDRDET_BEGIN_FRM (0 << 11) +#define STM32_SPI_CFG1_UDRDET_END_FRM (1 << 11) +#define STM32_SPI_CFG1_UDRDET_BEGIN_SS (2 << 11) #define STM32_SPI_CFG1_RXDMAEN (1 << 14) #define STM32_SPI_CFG1_TXDMAEN (1 << 15) #define STM32_SPI_CFG1_CRCSIZE(n) (((n) - 1) << 16) @@ -1636,6 +1643,7 @@ typedef volatile struct stm32_spi_regs stm32_spi_regs_t; #define STM32_SPI_CFG2_AFCNTR (1 << 31) #define STM32_SPI_SR_RXNE (1 << 0) +#define STM32_SPI_SR_UDR (1 << 5) #define STM32_SPI_SR_FRLVL (3 << 13) #define STM32_SPI_SR_TXC (1 << 12) #else /* !CHIP_FAMILY_STM32H7 */ diff --git a/chip/stm32/spi.c b/chip/stm32/spi.c index cdb1e0666b..570f371d27 100644 --- a/chip/stm32/spi.c +++ b/chip/stm32/spi.c @@ -27,14 +27,23 @@ #define CPRINTS(format, args...) cprints(CC_SPI, format, ## args) #define CPRINTF(format, args...) cprintf(CC_SPI, format, ## args) +/* SPI FIFO registers */ +#ifdef CHIP_FAMILY_STM32H7 +#define SPI_TXDR REG8(&STM32_SPI1_REGS->txdr) +#define SPI_RXDR REG8(&STM32_SPI1_REGS->rxdr) +#else +#define SPI_TXDR STM32_SPI1_REGS->dr +#define SPI_RXDR STM32_SPI1_REGS->dr +#endif + /* DMA channel option */ static const struct dma_option dma_tx_option = { - STM32_DMAC_SPI1_TX, (void *)&STM32_SPI1_REGS->dr, + STM32_DMAC_SPI1_TX, (void *)&SPI_TXDR, STM32_DMA_CCR_MSIZE_8_BIT | STM32_DMA_CCR_PSIZE_8_BIT }; static const struct dma_option dma_rx_option = { - STM32_DMAC_SPI1_RX, (void *)&STM32_SPI1_REGS->dr, + STM32_DMAC_SPI1_RX, (void *)&SPI_RXDR, STM32_DMA_CCR_MSIZE_8_BIT | STM32_DMA_CCR_PSIZE_8_BIT }; @@ -157,7 +166,7 @@ enum spi_state { * @param nss GPIO signal for NSS control line * @return 0 if bytes received, -1 if we hit a timeout or NSS went high */ -static int wait_for_bytes(stm32_dma_chan_t *rxdma, int needed, +static int wait_for_bytes(dma_chan_t *rxdma, int needed, enum gpio_signal nss) { timestamp_t deadline; @@ -215,7 +224,7 @@ static int wait_for_bytes(stm32_dma_chan_t *rxdma, int needed, * SPI_PROTO2_OFFSET bytes into out_msg * @param msg_len Number of message bytes to send */ -static void reply(stm32_dma_chan_t *txdma, +static void reply(dma_chan_t *txdma, enum ec_status status, char *msg_ptr, int msg_len) { char *msg = out_msg; @@ -271,7 +280,7 @@ static void tx_status(uint8_t byte) { stm32_spi_regs_t *spi = STM32_SPI1_REGS; - spi->dr = byte; + SPI_TXDR = byte; #if defined(CHIP_FAMILY_STM32F0) || defined(CHIP_FAMILY_STM32L4) /* It sends the byte 4 times in order to be sure it bypassed the FIFO * from the STM32F0 line. @@ -279,6 +288,8 @@ static void tx_status(uint8_t byte) spi->dr = byte; spi->dr = byte; spi->dr = byte; +#elif defined(CHIP_FAMILY_STM32H7) + spi->ifcr = STM32_SPI_SR_UDR; #endif } @@ -309,7 +320,7 @@ static void setup_for_transaction(void) * Read dummy bytes in case there are some pending; this prevents the * receive DMA from getting that byte right when we start it. */ - dummy = spi->dr; + dummy = SPI_RXDR; #if defined(CHIP_FAMILY_STM32F0) || defined(CHIP_FAMILY_STM32L4) /* 4 Bytes makes sure the RX FIFO on the F0 is empty as well. */ dummy = spi->dr; @@ -320,6 +331,10 @@ static void setup_for_transaction(void) /* Start DMA */ dma_start_rx(&dma_rx_option, sizeof(in_msg), in_msg); +#ifdef CHIP_FAMILY_STM32H7 + spi->cr1 |= STM32_SPI_CR1_SPE; +#endif + /* Ready to receive */ state = SPI_STATE_READY_TO_RX; tx_status(EC_SPI_OLD_READY); @@ -355,7 +370,7 @@ static void check_setup_transaction_later(void) static void spi_send_response(struct host_cmd_handler_args *args) { enum ec_status result = args->result; - stm32_dma_chan_t *txdma; + dma_chan_t *txdma; /* * If we're not processing, then the AP has already terminated the @@ -391,7 +406,7 @@ static void spi_send_response(struct host_cmd_handler_args *args) */ static void spi_send_response_packet(struct host_packet *pkt) { - stm32_dma_chan_t *txdma; + dma_chan_t *txdma; /* * If we're not processing, then the AP has already terminated the @@ -418,6 +433,10 @@ static void spi_send_response_packet(struct host_packet *pkt) dma_prepare_tx(&dma_tx_option, sizeof(out_preamble) + pkt->response_size + EC_SPI_PAST_END_LENGTH, out_msg); dma_go(txdma); +#ifdef CHIP_FAMILY_STM32H7 + /* clear any previous underrun */ + STM32_SPI1_REGS->ifcr = STM32_SPI_SR_UDR; +#endif /* CHIP_FAMILY_STM32H7 */ /* * Before the state is set to SENDING, any CS de-assertion would @@ -437,7 +456,7 @@ static void spi_send_response_packet(struct host_packet *pkt) */ void spi_event(enum gpio_signal signal) { - stm32_dma_chan_t *rxdma; + dma_chan_t *rxdma; uint16_t i; /* If not enabled, ignore glitches on NSS */ @@ -633,8 +652,8 @@ static void spi_init(void) /* Fix for bug chrome-os-partner:31390 */ enabled = 0; state = SPI_STATE_DISABLED; - STM32_RCC_APB2RSTR |= (1 << 12); - STM32_RCC_APB2RSTR &= ~(1 << 12); + STM32_RCC_APB2RSTR |= STM32_RCC_PB2_SPI1; + STM32_RCC_APB2RSTR &= ~STM32_RCC_PB2_SPI1; /* 40 MHz pin speed */ STM32_GPIO_OSPEEDR(GPIO_A) |= 0xff00; @@ -649,16 +668,29 @@ static void spi_init(void) #ifdef CHIP_FAMILY_STM32L4 dma_select_channel(STM32_DMAC_SPI1_TX, 1); dma_select_channel(STM32_DMAC_SPI1_RX, 1); +#elif defined(CHIP_FAMILY_STM32H7) + dma_select_channel(STM32_DMAC_SPI1_TX, DMAMUX1_REQ_SPI1_TX); + dma_select_channel(STM32_DMAC_SPI1_RX, DMAMUX1_REQ_SPI1_RX); #endif /* * Enable rx/tx DMA and get ready to receive our first transaction and * "disable" FIFO by setting event to happen after only 1 byte */ +#ifdef CHIP_FAMILY_STM32H7 + spi->cfg2 = 0; + spi->cfg1 = STM32_SPI_CFG1_DATASIZE(8) | STM32_SPI_CFG1_FTHLV(4) | + STM32_SPI_CFG1_CRCSIZE(8) | + STM32_SPI_CFG1_TXDMAEN | STM32_SPI_CFG1_RXDMAEN | + STM32_SPI_CFG1_UDRCFG_LAST_TX | + STM32_SPI_CFG1_UDRDET_BEGIN_FRM; + spi->cr1 = 0; +#else /* !CHIP_FAMILY_STM32H7 */ spi->cr2 = STM32_SPI_CR2_RXDMAEN | STM32_SPI_CR2_TXDMAEN | STM32_SPI_CR2_FRXTH | STM32_SPI_CR2_DATASIZE(8); /* Enable the SPI peripheral */ spi->cr1 |= STM32_SPI_CR1_SPE; +#endif /* !CHIP_FAMILY_STM32H7 */ gpio_enable_interrupt(GPIO_SPI1_NSS); -- cgit v1.2.1