|
|
@@ -0,0 +1,242 @@
|
|
|
+// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
|
|
+// File name : spi_slave.c
|
|
|
+// Description : SPI1 Slave DMA LLI Ping-Pong transport implementation
|
|
|
+// for GMSP national crypto co-processor firmware.
|
|
|
+//
|
|
|
+// Design:
|
|
|
+// - SPI1 configured as Slave: CPOL=Low, CPHA=1Edge, 8-bit, MSB first
|
|
|
+// - DMA LLI Ping-Pong: two 256-byte buffers (buf_A / buf_B) linked
|
|
|
+// in a circular chain (A->B->A->B->...). DMA auto-continues across
|
|
|
+// nodes; each block completion raises IRQ4.
|
|
|
+// - IRQ4 handler (gmsp_dma_irq_handler) records which buffer completed
|
|
|
+// and sets a volatile flag for foreground polling.
|
|
|
+// - Response path: short responses (<=8 bytes) via SPI_SlaveSendData
|
|
|
+// (CPU register write loop). Long responses via dma_spitran (blocking).
|
|
|
+// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
|
|
+
|
|
|
+#include "type.h"
|
|
|
+#include "memmap.h"
|
|
|
+#include "../src/drv/inc/spi_drv.h"
|
|
|
+#include "../src/drv/inc/spi_reg.h"
|
|
|
+#include "../src/drv/inc/dmac_drv.h"
|
|
|
+#include "../src/drv/inc/dmac_reg.h"
|
|
|
+#include "../src/common/debug.h"
|
|
|
+#include "../src/gmsp/transport/spi_slave.h"
|
|
|
+#include "../src/gmsp/transport/gmsp_isr.h"
|
|
|
+
|
|
|
+/* ------------------------------------------------------------------ */
|
|
|
+/* Ping-Pong receive buffers */
|
|
|
+/* ------------------------------------------------------------------ */
|
|
|
+static UINT8 gmsp_buf_A[GMSP_BUF_SIZE];
|
|
|
+static UINT8 gmsp_buf_B[GMSP_BUF_SIZE];
|
|
|
+
|
|
|
+/* Dummy RX buffer for response DMA transfer (full-duplex discard) */
|
|
|
+static UINT8 gmsp_dummy_rx[GMSP_BUF_SIZE];
|
|
|
+
|
|
|
+/* ------------------------------------------------------------------ */
|
|
|
+/* DMA LLI Ping-Pong descriptors (2 nodes: A -> B -> A) */
|
|
|
+/* Hardware reads first 5 fields (20 bytes) per LLI node. */
|
|
|
+/* ------------------------------------------------------------------ */
|
|
|
+static DMA_LLI gmsp_lli[2];
|
|
|
+
|
|
|
+/* ------------------------------------------------------------------ */
|
|
|
+/* ISR-shared state — ALL volatile */
|
|
|
+/* ------------------------------------------------------------------ */
|
|
|
+/* Set to 1 by IRQ4 handler when a DMA block completes */
|
|
|
+volatile UINT8 gmsp_dma_flag = 0;
|
|
|
+
|
|
|
+/* Which buffer just completed: 0 = buf_A, 1 = buf_B */
|
|
|
+volatile UINT8 gmsp_completed_buf = 0;
|
|
|
+
|
|
|
+/* Which buffer is currently being filled by DMA: 0 = A, 1 = B */
|
|
|
+/* Non-static: accessed by gmsp_dma_irq_handler in gmsp_isr.c */
|
|
|
+volatile UINT8 gmsp_currently_filling = 0;
|
|
|
+
|
|
|
+/* DMA error flag (latched, cleared by foreground) */
|
|
|
+volatile UINT8 gmsp_dma_errflag = 0;
|
|
|
+
|
|
|
+/* Track whether DMA LLI is active (to avoid double-stop) */
|
|
|
+static UINT8 gmsp_dma_active = 0;
|
|
|
+
|
|
|
+/* ------------------------------------------------------------------ */
|
|
|
+/* Internal: Set up DMA LLI Ping-Pong on DMACCH1 for SPI1 RX */
|
|
|
+/* ------------------------------------------------------------------ */
|
|
|
+static void gmsp_dma_lli_start(void)
|
|
|
+{
|
|
|
+ /* Build the two LLI nodes for Ping-Pong */
|
|
|
+ /* Node 0: receive into buf_A, next = node 1 */
|
|
|
+ gmsp_lli[0].src_addr = GMSP_SPI1_DR_ADDR;
|
|
|
+ gmsp_lli[0].dst_addr = (UINT32)gmsp_buf_A;
|
|
|
+ gmsp_lli[0].len = GMSP_BUF_SIZE;
|
|
|
+ gmsp_lli[0].control0 = DMA_IE | SNC | DI | LLP_DST_EN | LLP_SRC_EN | P2M_DMA;
|
|
|
+ gmsp_lli[0].next_lli = (UINT32)&gmsp_lli[1];
|
|
|
+
|
|
|
+ /* Node 1: receive into buf_B, next = node 0 (circular) */
|
|
|
+ gmsp_lli[1].src_addr = GMSP_SPI1_DR_ADDR;
|
|
|
+ gmsp_lli[1].dst_addr = (UINT32)gmsp_buf_B;
|
|
|
+ gmsp_lli[1].len = GMSP_BUF_SIZE;
|
|
|
+ gmsp_lli[1].control0 = DMA_IE | SNC | DI | LLP_DST_EN | LLP_SRC_EN | P2M_DMA;
|
|
|
+ gmsp_lli[1].next_lli = (UINT32)&gmsp_lli[0];
|
|
|
+
|
|
|
+ /* Reset Ping-Pong tracking state */
|
|
|
+ gmsp_currently_filling = 0; /* start filling buf_A first */
|
|
|
+ gmsp_completed_buf = 0;
|
|
|
+ gmsp_dma_flag = 0;
|
|
|
+
|
|
|
+ /* Enable DMAC globally */
|
|
|
+ m_dma_control->DMA_CONFIG = DMACEN;
|
|
|
+
|
|
|
+ /* Load first LLI node (node 0) into channel registers */
|
|
|
+ m_dma_channel[GMSP_SPI_RX_DMA_CH]->DMA_SADDR = gmsp_lli[0].src_addr;
|
|
|
+ m_dma_channel[GMSP_SPI_RX_DMA_CH]->DMA_DADDR = gmsp_lli[0].dst_addr;
|
|
|
+ m_dma_channel[GMSP_SPI_RX_DMA_CH]->DMA_CTRL = gmsp_lli[0].control0;
|
|
|
+ m_dma_channel[GMSP_SPI_RX_DMA_CH]->DMA_CTRL_HIGH = gmsp_lli[0].len;
|
|
|
+ m_dma_channel[GMSP_SPI_RX_DMA_CH]->DMA_LLP = (UINT32)&gmsp_lli[0];
|
|
|
+
|
|
|
+ /* Configure handshake: source = hardware (SPI1 RX), dest = software */
|
|
|
+ m_dma_channel[GMSP_SPI_RX_DMA_CH]->DMA_CFG = HS_SEL_DST_SOFT;
|
|
|
+ m_dma_channel[GMSP_SPI_RX_DMA_CH]->DMA_CFG_HIGH = SRC_PER_SPI_RX(0); /* spiid=0 = SPI1 */
|
|
|
+
|
|
|
+ /* Unmask transfer-complete interrupt for this channel */
|
|
|
+ m_dma_control->DMA_MASKTFR |= CHANNEL_UMASK(GMSP_SPI_RX_DMA_CH);
|
|
|
+
|
|
|
+ /* Enable the channel */
|
|
|
+ m_dma_control->DMA_CHEN |= CHANNEL_WRITE_ENABLE(GMSP_SPI_RX_DMA_CH)
|
|
|
+ | CHANNEL_ENABLE(GMSP_SPI_RX_DMA_CH);
|
|
|
+
|
|
|
+ gmsp_dma_active = 1;
|
|
|
+}
|
|
|
+
|
|
|
+/* ------------------------------------------------------------------ */
|
|
|
+/* Internal: Stop DMA LLI receive on DMACCH1 */
|
|
|
+/* ------------------------------------------------------------------ */
|
|
|
+static void gmsp_dma_lli_stop(void)
|
|
|
+{
|
|
|
+ if (!gmsp_dma_active)
|
|
|
+ return;
|
|
|
+
|
|
|
+ /* Suspend channel, wait for FIFO drain, then disable */
|
|
|
+ dma_channle_stop(GMSP_SPI_RX_DMA_CH);
|
|
|
+ gmsp_dma_active = 0;
|
|
|
+}
|
|
|
+
|
|
|
+/*******************************************************************************
|
|
|
+* Function Name : gmsp_transport_init
|
|
|
+* Description : Initialize SPI1 as slave + DMA LLI Ping-Pong receive.
|
|
|
+* CPOL=Low, CPHA=1Edge, 8-bit, MSB first.
|
|
|
+* Input : None
|
|
|
+* Output : None
|
|
|
+* Return : None
|
|
|
+******************************************************************************/
|
|
|
+void gmsp_transport_init(void)
|
|
|
+{
|
|
|
+ SPI_InitTypeDef SPI_InitStruct;
|
|
|
+
|
|
|
+ /* Configure SPI1 as slave with default parameters */
|
|
|
+ SPI_StructInit(SPI_Mode_Slave, &SPI_InitStruct);
|
|
|
+
|
|
|
+ /* Explicitly set mode 0: CPOL=Low, CPHA=1Edge */
|
|
|
+ SPI_InitStruct.SPI_CPOL = SPI_CPOL_Low;
|
|
|
+ SPI_InitStruct.SPI_CPHA = SPI_CPHA_1Edge;
|
|
|
+
|
|
|
+ /* 8-bit data, MSB first (should be defaults from StructInit) */
|
|
|
+ SPI_InitStruct.SPI_DataSize = SPI_DataSize_8b;
|
|
|
+ SPI_InitStruct.SPI_FirstBit = SPI_FirstBit_MSB;
|
|
|
+
|
|
|
+ /* Initialize SPI1 peripheral */
|
|
|
+ SPI_Init(SPI1, &SPI_InitStruct);
|
|
|
+
|
|
|
+ /* Enable SPI1 DMA request generation (RX + TX) */
|
|
|
+ SPI_EnableDMA(SPI1, TRUE);
|
|
|
+
|
|
|
+ /* Start DMA LLI Ping-Pong receive on DMACCH1 */
|
|
|
+ gmsp_dma_lli_start();
|
|
|
+}
|
|
|
+
|
|
|
+/*******************************************************************************
|
|
|
+* Function Name : gmsp_recv_ready
|
|
|
+* Description : Non-blocking check for DMA receive completion.
|
|
|
+* Input : None
|
|
|
+* Output : None
|
|
|
+* Return : 1 if new data available, 0 otherwise
|
|
|
+******************************************************************************/
|
|
|
+UINT8 gmsp_recv_ready(void)
|
|
|
+{
|
|
|
+ return gmsp_dma_flag;
|
|
|
+}
|
|
|
+
|
|
|
+/*******************************************************************************
|
|
|
+* Function Name : gmsp_get_rx_buf
|
|
|
+* Description : Return pointer to the completed receive buffer.
|
|
|
+* Input : out_len - optional pointer to receive buffer length
|
|
|
+* Output : *out_len set to GMSP_BUF_SIZE if non-NULL
|
|
|
+* Return : Pointer to buf_A or buf_B depending on gmsp_completed_buf
|
|
|
+******************************************************************************/
|
|
|
+UINT8 *gmsp_get_rx_buf(UINT16 *out_len)
|
|
|
+{
|
|
|
+ if (out_len != (UINT16 *)0)
|
|
|
+ {
|
|
|
+ *out_len = GMSP_BUF_SIZE;
|
|
|
+ }
|
|
|
+
|
|
|
+ if (gmsp_completed_buf == 0)
|
|
|
+ return gmsp_buf_A;
|
|
|
+
|
|
|
+ return gmsp_buf_B;
|
|
|
+}
|
|
|
+
|
|
|
+/*******************************************************************************
|
|
|
+* Function Name : gmsp_send_response
|
|
|
+* Description : Send response data to host via SPI1 slave.
|
|
|
+* Stops RX DMA first, then:
|
|
|
+* - len <= 8: CPU register write loop (SPI_SlaveSendData)
|
|
|
+* - len > 8: blocking DMA transfer (dma_spitran)
|
|
|
+* RX DMA is NOT automatically restarted — caller must
|
|
|
+* call gmsp_transport_rearm() after processing.
|
|
|
+* Input : resp - pointer to response data
|
|
|
+* len - number of bytes to send
|
|
|
+* Output : None
|
|
|
+* Return : None
|
|
|
+******************************************************************************/
|
|
|
+void gmsp_send_response(const UINT8 *resp, UINT16 len)
|
|
|
+{
|
|
|
+ assert_param(resp != (const UINT8 *)0 || len == 0);
|
|
|
+
|
|
|
+ if (len == 0)
|
|
|
+ return;
|
|
|
+
|
|
|
+ /* Stop DMA LLI receive to free DMACCH1 and SPI DMA */
|
|
|
+ gmsp_dma_lli_stop();
|
|
|
+ SPI_EnableDMA(SPI1, FALSE);
|
|
|
+
|
|
|
+ if (len <= SPI_FIFO_SIZE)
|
|
|
+ {
|
|
|
+ /* Short response: use CPU register write loop */
|
|
|
+ SPI_SlaveSendData(SPI1, (UINT8 *)resp, len);
|
|
|
+ }
|
|
|
+ else
|
|
|
+ {
|
|
|
+ /* Long response: blocking DMA transfer (TX via CH0, dummy RX via CH1) */
|
|
|
+ if (len > GMSP_BUF_SIZE)
|
|
|
+ len = GMSP_BUF_SIZE; /* clamp to buffer size */
|
|
|
+
|
|
|
+ SPI_EnableDMA(SPI1, TRUE);
|
|
|
+ dma_spitran(0, (UINT8 *)resp, gmsp_dummy_rx, len, FALSE);
|
|
|
+ SPI_EnableDMA(SPI1, FALSE);
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
+/*******************************************************************************
|
|
|
+* Function Name : gmsp_transport_rearm
|
|
|
+* Description : Restart DMA LLI Ping-Pong receive after processing or
|
|
|
+* after sending a response. Clears the ready flag.
|
|
|
+* Input : None
|
|
|
+* Output : None
|
|
|
+* Return : None
|
|
|
+******************************************************************************/
|
|
|
+void gmsp_transport_rearm(void)
|
|
|
+{
|
|
|
+ /* Re-enable SPI1 DMA and restart LLI receive */
|
|
|
+ SPI_EnableDMA(SPI1, TRUE);
|
|
|
+ gmsp_dma_lli_start();
|
|
|
+}
|