123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254 |
- /*
- * Copyright (c) 2021 HPMicro
- *
- * SPDX-License-Identifier: BSD-3-Clause
- *
- */
- #include "hpm_spi.h"
- #include "hpm_clock_drv.h"
- #include <stdlib.h>
- #if USE_DMA_MGR
- #include "hpm_dma_mgr.h"
- #endif
- typedef struct {
- SPI_Type *spi_ptr;
- clock_name_t spi_clock_name;
- #if USE_DMA_MGR
- uint8_t tx_dmamux_src;
- uint8_t rx_dmamux_src;
- dma_resource_t txdma_resource;
- dma_resource_t rxdma_resource;
- spi_dma_complete_cb tx_dma_complete;
- spi_dma_complete_cb rx_dma_complete;
- #endif
- } hpm_spi_cfg_t;
- static hpm_spi_cfg_t spi_dma_cfg_table[] = {
- #if defined(HPM_SPI0)
- {
- .spi_ptr = HPM_SPI0,
- .spi_clock_name = clock_spi0,
- #if USE_DMA_MGR
- .tx_dmamux_src = HPM_DMA_SRC_SPI0_TX,
- .rx_dmamux_src = HPM_DMA_SRC_SPI0_RX,
- .rx_dma_complete = NULL,
- .tx_dma_complete = NULL
- #endif
- },
- #endif
- #if defined(HPM_SPI1)
- {
- .spi_ptr = HPM_SPI1,
- .spi_clock_name = clock_spi1,
- #if USE_DMA_MGR
- .tx_dmamux_src = HPM_DMA_SRC_SPI1_TX,
- .rx_dmamux_src = HPM_DMA_SRC_SPI1_RX,
- .rx_dma_complete = NULL,
- .tx_dma_complete = NULL,
- #endif
- },
- #endif
- #if defined(HPM_SPI2)
- {
- .spi_ptr = HPM_SPI2,
- .spi_clock_name = clock_spi2,
- #if USE_DMA_MGR
- .tx_dmamux_src = HPM_DMA_SRC_SPI2_TX,
- .rx_dmamux_src = HPM_DMA_SRC_SPI2_RX,
- .rx_dma_complete = NULL,
- .tx_dma_complete = NULL,
- #endif
- },
- #endif
- #if defined(HPM_SPI3)
- {
- .spi_ptr = HPM_SPI3,
- .spi_clock_name = clock_spi3,
- #if USE_DMA_MGR
- .tx_dmamux_src = HPM_DMA_SRC_SPI3_TX,
- .rx_dmamux_src = HPM_DMA_SRC_SPI3_RX,
- .rx_dma_complete = NULL,
- .tx_dma_complete = NULL,
- #endif
- },
- #endif
- #if defined(HPM_SPI4)
- {
- .spi_ptr = HPM_SPI4,
- .spi_clock_name = clock_spi4,
- #if USE_DMA_MGR
- .tx_dmamux_src = HPM_DMA_SRC_SPI4_TX,
- .rx_dmamux_src = HPM_DMA_SRC_SPI4_RX,
- .rx_dma_complete = NULL,
- .tx_dma_complete = NULL,
- #endif
- },
- #endif
- #if defined(HPM_SPI5)
- {
- .spi_ptr = HPM_SPI5,
- .spi_clock_name = clock_spi5,
- #if USE_DMA_MGR
- .tx_dmamux_src = HPM_DMA_SRC_SPI5_TX,
- .rx_dmamux_src = HPM_DMA_SRC_SPI5_RX,
- .rx_dma_complete = NULL,
- .tx_dma_complete = NULL,
- #endif
- },
- #endif
- #if defined(HPM_SPI6)
- {
- .spi_ptr = HPM_SPI6,
- .spi_clock_name = clock_spi6,
- #if USE_DMA_MGR
- .tx_dmamux_src = HPM_DMA_SRC_SPI6_TX,
- .rx_dmamux_src = HPM_DMA_SRC_SPI6_RX,
- .rx_dma_complete = NULL,
- .tx_dma_complete = NULL,
- #endif
- },
- #endif
- #if defined(HPM_SPI7)
- {
- .spi_ptr = HPM_SPI7,
- .spi_clock_name = clock_spi7,
- #if USE_DMA_MGR
- .tx_dmamux_src = HPM_DMA_SRC_SPI7_TX,
- .rx_dmamux_src = HPM_DMA_SRC_SPI7_RX,
- .rx_dma_complete = NULL,
- .tx_dma_complete = NULL,
- #endif
- },
- #endif
- #if defined(HPM_SPI8)
- {
- .spi_ptr = HPM_SPI8,
- .spi_clock_name = clock_spi8,
- #if USE_DMA_MGR
- .tx_dmamux_src = HPM_DMA_SRC_SPI8_TX,
- .rx_dmamux_src = HPM_DMA_SRC_SPI8_RX,
- .rx_dma_complete = NULL,
- .tx_dma_complete = NULL,
- #endif
- },
- #endif
- #if defined(HPM_SPI9)
- {
- .spi_ptr = HPM_SPI9,
- .spi_clock_name = clock_spi9,
- #if USE_DMA_MGR
- .tx_dmamux_src = HPM_DMA_SRC_SPI9_TX,
- .rx_dmamux_src = HPM_DMA_SRC_SPI9_RX,
- .rx_dma_complete = NULL,
- .tx_dma_complete = NULL,
- #endif
- },
- #endif
- #if defined(HPM_SPI10)
- {
- .spi_ptr = HPM_SPI10,
- .spi_clock_name = clock_spi10,
- #if USE_DMA_MGR
- .tx_dmamux_src = HPM_DMA_SRC_SPI10_TX,
- .rx_dmamux_src = HPM_DMA_SRC_SPI10_RX,
- .rx_dma_complete = NULL,
- .tx_dma_complete = NULL,
- #endif
- },
- #endif
- };
- static hpm_stat_t hpm_spi_tx_trigger_dma(DMA_Type *dma_ptr, uint8_t ch_num, SPI_Type *spi_ptr, uint32_t src, uint8_t data_width, uint32_t size)
- {
- dma_handshake_config_t config;
- dma_default_handshake_config(dma_ptr, &config);
- config.ch_index = ch_num;
- config.dst = (uint32_t)&spi_ptr->DATA;
- config.dst_fixed = true;
- config.src = src;
- config.src_fixed = false;
- config.data_width = data_width;
- config.size_in_byte = size;
- return dma_setup_handshake(dma_ptr, &config, true);
- }
- static hpm_stat_t hpm_spi_rx_trigger_dma(DMA_Type *dma_ptr, uint8_t ch_num, SPI_Type *spi_ptr, uint32_t dst, uint8_t data_width, uint32_t size)
- {
- dma_handshake_config_t config;
- dma_default_handshake_config(dma_ptr, &config);
- config.ch_index = ch_num;
- config.dst = dst;
- config.dst_fixed = false;
- config.src = (uint32_t)&spi_ptr->DATA;
- config.src_fixed = true;
- config.data_width = data_width;
- config.size_in_byte = size;
- return dma_setup_handshake(dma_ptr, &config, true);
- }
- void hpm_spi_prepare_dma_tx_descriptors(spi_context_t *context, spi_control_config_t *config, uint32_t trans_count,
- uint32_t *spi_transctrl, dma_linked_descriptor_t *tx_dma_descriptors)
- {
- SPI_Type *ptr = context->ptr;
- uint32_t dma_transfer_size[trans_count];
- uint32_t tx_count = context->tx_count;
- uint32_t per_trans_size = context->per_trans_max;
- uint32_t dma_ch = context->dma_context.tx_dma_ch;
- uint8_t *tx_buff = context->tx_buff;
- dma_channel_config_t dma_ch_config;
- static uint8_t dummy_cmd = 0xff;
- uint32_t temp32;
- uint32_t tx_buff_index = 0;
- dma_default_channel_config(context->dma_context.dma_ptr, &dma_ch_config);
- for (uint32_t i = 0; i < trans_count; i++) {
- if (tx_count > per_trans_size) {
- temp32 = per_trans_size;
- tx_count -= per_trans_size;
- } else {
- temp32 = tx_count;
- }
- *(spi_transctrl + i) = SPI_TRANSCTRL_TRANSMODE_SET(config->common_config.trans_mode == spi_trans_write_read_together ?
- spi_trans_write_read_together : spi_trans_write_only)
- | SPI_TRANSCTRL_DUALQUAD_SET(config->common_config.data_phase_fmt)
- | SPI_TRANSCTRL_WRTRANCNT_SET(temp32 - 1)
- | SPI_TRANSCTRL_RDTRANCNT_SET(temp32 - 1);
- if (i == 0) {
- /* Set the count of data transferred by dma to be one more than that of spi */
- /* when dma transfer finished, there are data in SPI fifo, dma should not execute the dma descriptor which changes SPI CTRL register */
- temp32 = temp32 + 1;
- }
- if (i == trans_count - 1) {
- temp32 = temp32 - 1;
- }
- dma_transfer_size[i] = temp32;
- /* SPI CTRL */
- dma_ch_config.size_in_byte = 4;
- dma_ch_config.src_addr = core_local_mem_to_sys_address(context->running_core, (uint32_t)(spi_transctrl + i));
- dma_ch_config.dst_addr = core_local_mem_to_sys_address(context->running_core, (uint32_t)&ptr->TRANSCTRL);
- dma_ch_config.src_width = DMA_TRANSFER_WIDTH_WORD;
- dma_ch_config.dst_width = DMA_TRANSFER_WIDTH_WORD;
- dma_ch_config.src_burst_size = DMA_NUM_TRANSFER_PER_BURST_1T;
- dma_ch_config.src_mode = DMA_HANDSHAKE_MODE_NORMAL;
- dma_ch_config.dst_mode = DMA_HANDSHAKE_MODE_NORMAL;
- dma_ch_config.src_addr_ctrl = DMA_ADDRESS_CONTROL_FIXED;
- dma_ch_config.dst_addr_ctrl = DMA_ADDRESS_CONTROL_FIXED;
- dma_ch_config.linked_ptr = core_local_mem_to_sys_address(context->running_core, (uint32_t)(tx_dma_descriptors + i * SPI_DMA_DESC_COUNT_PER_TRANS + 1));
- dma_config_linked_descriptor(context->dma_context.dma_ptr, tx_dma_descriptors + i * SPI_DMA_DESC_COUNT_PER_TRANS, dma_ch, &dma_ch_config);
- /* SPI CMD */
- dma_ch_config.size_in_byte = 1;
- dma_ch_config.src_addr = core_local_mem_to_sys_address(context->running_core, (uint32_t)&dummy_cmd);
- dma_ch_config.dst_addr = core_local_mem_to_sys_address(context->running_core, (uint32_t)&ptr->CMD);
- dma_ch_config.src_width = DMA_TRANSFER_WIDTH_BYTE;
- dma_ch_config.dst_width = DMA_TRANSFER_WIDTH_BYTE;
- dma_ch_config.src_burst_size = DMA_NUM_TRANSFER_PER_BURST_1T;
- dma_ch_config.src_mode = DMA_HANDSHAKE_MODE_NORMAL;
- dma_ch_config.dst_mode = DMA_HANDSHAKE_MODE_NORMAL;
- dma_ch_config.src_addr_ctrl = DMA_ADDRESS_CONTROL_FIXED;
- dma_ch_config.dst_addr_ctrl = DMA_ADDRESS_CONTROL_FIXED;
- dma_ch_config.linked_ptr = core_local_mem_to_sys_address(context->running_core, (uint32_t)(tx_dma_descriptors + i * SPI_DMA_DESC_COUNT_PER_TRANS + 2));
- dma_config_linked_descriptor(context->dma_context.dma_ptr, tx_dma_descriptors + i * SPI_DMA_DESC_COUNT_PER_TRANS + 1, dma_ch, &dma_ch_config);
- /* SPI DATA */
- dma_ch_config.size_in_byte = dma_transfer_size[i] << context->dma_context.data_width;
- dma_ch_config.src_addr = core_local_mem_to_sys_address(context->running_core, (uint32_t)(tx_buff + tx_buff_index));
- dma_ch_config.dst_addr = core_local_mem_to_sys_address(context->running_core, (uint32_t)&ptr->DATA);
- dma_ch_config.src_width = context->dma_context.data_width;
- dma_ch_config.dst_width = context->dma_context.data_width;
- dma_ch_config.src_burst_size = DMA_NUM_TRANSFER_PER_BURST_1T;
- dma_ch_config.src_mode = DMA_HANDSHAKE_MODE_NORMAL;
- dma_ch_config.dst_mode = DMA_HANDSHAKE_MODE_HANDSHAKE;
- dma_ch_config.src_addr_ctrl = DMA_ADDRESS_CONTROL_INCREMENT;
- dma_ch_config.dst_addr_ctrl = DMA_ADDRESS_CONTROL_FIXED;
- if (i == trans_count - 1) {
- dma_ch_config.linked_ptr = 0;
- } else {
- dma_ch_config.linked_ptr = core_local_mem_to_sys_address(context->running_core, (uint32_t)(tx_dma_descriptors + (i + 1) * SPI_DMA_DESC_COUNT_PER_TRANS));
- }
- dma_config_linked_descriptor(context->dma_context.dma_ptr, tx_dma_descriptors + i * SPI_DMA_DESC_COUNT_PER_TRANS + 2, dma_ch, &dma_ch_config);
- tx_buff_index += temp32 * context->data_len_in_byte;
- }
- }
- void hpm_prepare_dma_rx_descriptors(spi_context_t *context, spi_control_config_t *config, uint32_t trans_count,
- uint32_t *spi_transctrl, dma_linked_descriptor_t *rx_dma_descriptors)
- {
- SPI_Type *ptr = context->ptr;
- uint32_t dma_transfer_size[trans_count];
- uint32_t rx_count = context->rx_count;
- uint32_t per_trans_size = context->per_trans_max;
- uint32_t dma_ch = context->dma_context.rx_dma_ch;
- uint8_t *rx_buff = context->rx_buff;
- dma_channel_config_t dma_ch_config;
- static uint8_t dummy_cmd = 0xff;
- uint32_t temp32;
- uint32_t rx_buff_index = 0;
- dma_default_channel_config(context->dma_context.dma_ptr, &dma_ch_config);
- for (uint32_t i = 0; i < trans_count; i++) {
- if (rx_count > per_trans_size) {
- temp32 = per_trans_size;
- rx_count -= per_trans_size;
- } else {
- temp32 = rx_count;
- }
- *(spi_transctrl + i) = SPI_TRANSCTRL_TRANSMODE_SET(spi_trans_read_only) |
- SPI_TRANSCTRL_DUALQUAD_SET(config->common_config.data_phase_fmt) |
- SPI_TRANSCTRL_WRTRANCNT_SET(temp32 - 1) |
- SPI_TRANSCTRL_RDTRANCNT_SET(temp32 - 1);
- dma_transfer_size[i] = temp32;
- /* SPI CTRL */
- dma_ch_config.size_in_byte = 4;
- dma_ch_config.src_addr = core_local_mem_to_sys_address(context->running_core, (uint32_t)(spi_transctrl + i));
- dma_ch_config.dst_addr = core_local_mem_to_sys_address(context->running_core, (uint32_t)&ptr->TRANSCTRL);
- dma_ch_config.src_width = DMA_TRANSFER_WIDTH_WORD;
- dma_ch_config.dst_width = DMA_TRANSFER_WIDTH_WORD;
- dma_ch_config.src_burst_size = DMA_NUM_TRANSFER_PER_BURST_1T;
- dma_ch_config.src_mode = DMA_HANDSHAKE_MODE_NORMAL;
- dma_ch_config.dst_mode = DMA_HANDSHAKE_MODE_NORMAL;
- dma_ch_config.src_addr_ctrl = DMA_ADDRESS_CONTROL_FIXED;
- dma_ch_config.dst_addr_ctrl = DMA_ADDRESS_CONTROL_FIXED;
- dma_ch_config.linked_ptr = core_local_mem_to_sys_address(context->running_core, (uint32_t)(rx_dma_descriptors + i * SPI_DMA_DESC_COUNT_PER_TRANS + 1));
- dma_config_linked_descriptor(context->dma_context.dma_ptr, rx_dma_descriptors + i * SPI_DMA_DESC_COUNT_PER_TRANS, dma_ch, &dma_ch_config);
- /* SPI CMD */
- dma_ch_config.size_in_byte = 1;
- dma_ch_config.src_addr = core_local_mem_to_sys_address(context->running_core, (uint32_t)&dummy_cmd);
- dma_ch_config.dst_addr = core_local_mem_to_sys_address(context->running_core, (uint32_t)&ptr->CMD);
- dma_ch_config.src_width = DMA_TRANSFER_WIDTH_BYTE;
- dma_ch_config.dst_width = DMA_TRANSFER_WIDTH_BYTE;
- dma_ch_config.src_burst_size = DMA_NUM_TRANSFER_PER_BURST_1T;
- dma_ch_config.src_mode = DMA_HANDSHAKE_MODE_NORMAL;
- dma_ch_config.dst_mode = DMA_HANDSHAKE_MODE_NORMAL;
- dma_ch_config.src_addr_ctrl = DMA_ADDRESS_CONTROL_FIXED;
- dma_ch_config.dst_addr_ctrl = DMA_ADDRESS_CONTROL_FIXED;
- dma_ch_config.linked_ptr = core_local_mem_to_sys_address(context->running_core, (uint32_t)(rx_dma_descriptors + i * SPI_DMA_DESC_COUNT_PER_TRANS + 2));
- dma_config_linked_descriptor(context->dma_context.dma_ptr, rx_dma_descriptors + i * SPI_DMA_DESC_COUNT_PER_TRANS + 1, dma_ch, &dma_ch_config);
- /* SPI DATA */
- dma_ch_config.size_in_byte = dma_transfer_size[i] << context->dma_context.data_width;
- dma_ch_config.src_addr = core_local_mem_to_sys_address(context->running_core, (uint32_t)&ptr->DATA);
- dma_ch_config.dst_addr = core_local_mem_to_sys_address(context->running_core, (uint32_t)(rx_buff + rx_buff_index));
- dma_ch_config.src_width = context->dma_context.data_width;
- dma_ch_config.dst_width = context->dma_context.data_width;
- dma_ch_config.src_burst_size = DMA_NUM_TRANSFER_PER_BURST_1T;
- dma_ch_config.src_mode = DMA_HANDSHAKE_MODE_HANDSHAKE;
- dma_ch_config.dst_mode = DMA_HANDSHAKE_MODE_NORMAL;
- dma_ch_config.src_addr_ctrl = DMA_ADDRESS_CONTROL_FIXED;
- dma_ch_config.dst_addr_ctrl = DMA_ADDRESS_CONTROL_INCREMENT;
- if (i == trans_count - 1) {
- dma_ch_config.linked_ptr = 0;
- } else {
- dma_ch_config.linked_ptr = core_local_mem_to_sys_address(context->running_core, (uint32_t)(rx_dma_descriptors + (i + 1) * SPI_DMA_DESC_COUNT_PER_TRANS));
- }
- dma_config_linked_descriptor(context->dma_context.dma_ptr, rx_dma_descriptors + i * SPI_DMA_DESC_COUNT_PER_TRANS + 2, dma_ch, &dma_ch_config);
- rx_buff_index += temp32 * context->data_len_in_byte;
- }
- }
- static uint32_t hpm_spi_get_trans_count(spi_context_t *context, spi_control_config_t *config)
- {
- uint32_t total_trans_count, per_trans_count, trans_count;
- per_trans_count = context->per_trans_max;
- if (config->common_config.trans_mode == spi_trans_write_only || config->common_config.trans_mode == spi_trans_dummy_write) {
- total_trans_count = context->tx_count;
- } else if (config->common_config.trans_mode == spi_trans_read_only || config->common_config.trans_mode == spi_trans_dummy_read) {
- total_trans_count = context->rx_count;
- } else {
- /* write read together */
- assert(context->tx_count == context->rx_count);
- total_trans_count = context->tx_count;
- }
- trans_count = (total_trans_count + per_trans_count - 1) / per_trans_count;
- return trans_count;
- }
- /**
- * spi with dma chain workflow
- *
- * 1. call spi_setup_dma_transfer to config SPI for first transmission
- * 2. execute data transmission phase in dma chain descriptor
- * 3. execute setting SPI CTRL register phase in dma chain descriptor
- * 4. execute writing SPI CMD register phase in dma chain descriptor
- * 5. Repeat steps 2-4 until finish the transmission
- */
- static hpm_stat_t spi_setup_trans_with_dma_chain(spi_context_t *context, spi_control_config_t *config)
- {
- hpm_stat_t stat = status_success;
- SPI_Type *spi_ptr = context->ptr;
- DMA_Type *dma_ptr = context->dma_context.dma_ptr;
- DMAMUX_Type *dmamux_ptr = context->dma_context.dmamux_ptr;
- dma_linked_descriptor_t *dma_linked_descriptor = context->dma_linked_descriptor;
- uint32_t *spi_transctrl = context->spi_transctrl;
- uint32_t dma_channel = 0;
- uint32_t trans_count;
- dma_channel_config_t dma_ch_config = {0};
- /* use a dummy dma transfer to start SPI trans dma chain */
- static uint32_t dummy_data1 = 0xff, dummy_data2 = 0xff;
- trans_count = hpm_spi_get_trans_count(context, config);
- /* active spi cs pin */
- context->write_cs(context->cs_pin, SPI_CS_ACTIVE);
- /* config SPI for first dma transmission */
- stat = spi_setup_dma_transfer(spi_ptr,
- config,
- &context->cmd,
- &context->addr,
- MIN(context->tx_count, context->per_trans_max),
- MIN(context->rx_count, context->per_trans_max));
- if (stat != status_success) {
- return stat;
- }
- if (config->common_config.trans_mode == spi_trans_write_only || config->common_config.trans_mode == spi_trans_dummy_write) {
- /* write only */
- hpm_spi_prepare_dma_tx_descriptors(context, config, trans_count, spi_transctrl, dma_linked_descriptor);
- dma_channel = context->dma_context.tx_dma_ch;
- dmamux_config(dmamux_ptr, context->dma_context.tx_dmamux_ch, context->dma_context.tx_req, true);
- } else if (config->common_config.trans_mode == spi_trans_read_only || config->common_config.trans_mode == spi_trans_dummy_read) {
- /* read only */
- hpm_prepare_dma_rx_descriptors(context, config, trans_count, spi_transctrl, dma_linked_descriptor);
- dma_channel = context->dma_context.rx_dma_ch;
- dmamux_config(dmamux_ptr, context->dma_context.rx_dmamux_ch, context->dma_context.rx_req, true);
- } else if (config->common_config.trans_mode == spi_trans_write_read_together) {
- /* write and read together */
- hpm_spi_prepare_dma_tx_descriptors(context, config, trans_count, spi_transctrl, dma_linked_descriptor);
- dma_channel = context->dma_context.tx_dma_ch;
- dmamux_config(dmamux_ptr, context->dma_context.tx_dmamux_ch, context->dma_context.tx_req, true);
- dmamux_config(dmamux_ptr, context->dma_context.rx_dmamux_ch, context->dma_context.rx_req, true);
- /* spi tx use chained dma descriptor, spi rx use unchained dma */
- stat = hpm_spi_rx_trigger_dma(dma_ptr,
- context->dma_context.rx_dma_ch,
- spi_ptr,
- core_local_mem_to_sys_address(context->running_core, (uint32_t)context->rx_buff),
- context->dma_context.data_width,
- context->rx_size);
- if (stat != status_success) {
- return stat;
- }
- } else {
- return status_invalid_argument;
- }
- dma_default_channel_config(context->dma_context.dma_ptr, &dma_ch_config);
- dma_ch_config.src_addr = core_local_mem_to_sys_address(context->running_core, (uint32_t)&dummy_data1);
- dma_ch_config.dst_addr = core_local_mem_to_sys_address(context->running_core, (uint32_t)&dummy_data2);
- dma_ch_config.src_burst_size = DMA_NUM_TRANSFER_PER_BURST_1T;
- dma_ch_config.src_width = DMA_TRANSFER_WIDTH_WORD;
- dma_ch_config.dst_width = DMA_TRANSFER_WIDTH_WORD;
- dma_ch_config.size_in_byte = 4;
- /* start data transmission phase in dma chain */
- dma_ch_config.linked_ptr = core_local_mem_to_sys_address(context->running_core, (uint32_t)(dma_linked_descriptor + SPI_DMA_DESC_COUNT_PER_TRANS - 1));
- stat = dma_setup_channel(dma_ptr, dma_channel, &dma_ch_config, true);
- if (stat != status_success) {
- return stat;
- }
- return stat;
- }
- static hpm_stat_t spi_setup_trans_with_dma(spi_context_t *context, spi_control_config_t *config)
- {
- hpm_stat_t stat = status_success;
- SPI_Type *spi_ptr = context->ptr;
- DMA_Type *dma_ptr = context->dma_context.dma_ptr;
- DMAMUX_Type *dmamux_ptr = context->dma_context.dmamux_ptr;
- uint32_t trans_mode = config->common_config.trans_mode;
- if (context->write_cs != NULL) {
- context->write_cs(context->cs_pin, SPI_CS_ACTIVE);
- }
- stat = spi_setup_dma_transfer(spi_ptr, config,
- &context->cmd, &context->addr,
- context->tx_count, context->rx_count);
- if (stat != status_success) {
- return stat;
- }
- if (trans_mode != spi_trans_write_only && trans_mode != spi_trans_dummy_write && trans_mode != spi_trans_no_data) {
- dmamux_config(dmamux_ptr, context->dma_context.rx_dmamux_ch, context->dma_context.rx_req, true);
- stat = hpm_spi_rx_trigger_dma(dma_ptr,
- context->dma_context.rx_dma_ch,
- spi_ptr,
- core_local_mem_to_sys_address(context->running_core, (uint32_t)context->rx_buff),
- context->dma_context.data_width,
- context->rx_size);
- if (stat != status_success) {
- return stat;
- }
- }
- if (trans_mode != spi_trans_read_only && trans_mode != spi_trans_dummy_read && trans_mode != spi_trans_no_data) {
- dmamux_config(dmamux_ptr, context->dma_context.tx_dmamux_ch, context->dma_context.tx_req, true);
- stat = hpm_spi_tx_trigger_dma(dma_ptr,
- context->dma_context.tx_dma_ch,
- spi_ptr,
- core_local_mem_to_sys_address(context->running_core, (uint32_t)context->tx_buff),
- context->dma_context.data_width,
- context->tx_size);
- if (stat != status_success) {
- return stat;
- }
- }
- return stat;
- }
- hpm_stat_t hpm_spi_setup_dma_transfer(spi_context_t *context, spi_control_config_t *config)
- {
- assert(context != NULL || config != NULL);
- /* use dma */
- assert(&context->dma_context != NULL);
- /* spi per trans data size not zero */
- assert(context->per_trans_max);
- hpm_stat_t stat = status_success;
- if (l1c_dc_is_enabled()) {
- /* cache writeback for tx buff */
- if (context->tx_buff != NULL && context->tx_size != 0) {
- uint32_t aligned_start = HPM_L1C_CACHELINE_ALIGN_DOWN((uint32_t)context->tx_buff);
- uint32_t aligned_end = HPM_L1C_CACHELINE_ALIGN_UP((uint32_t)context->tx_buff + context->tx_size);
- uint32_t aligned_size = aligned_end - aligned_start;
- l1c_dc_writeback(aligned_start, aligned_size);
- }
- /* cache invalidate for receive buff */
- if (context->rx_buff != NULL && context->rx_size != 0) {
- uint32_t aligned_start = HPM_L1C_CACHELINE_ALIGN_DOWN((uint32_t)context->rx_buff);
- uint32_t aligned_end = HPM_L1C_CACHELINE_ALIGN_UP((uint32_t)context->rx_buff + context->rx_size);
- uint32_t aligned_size = aligned_end - aligned_start;
- l1c_dc_invalidate(aligned_start, aligned_size);
- }
- }
- if ((context->rx_count > context->per_trans_max) || (context->tx_count > context->per_trans_max)) {
- /* multiple SPI transmissions with chained DMA */
- assert(config->common_config.trans_mode == spi_trans_read_only || config->common_config.trans_mode == spi_trans_dummy_read
- || config->common_config.trans_mode == spi_trans_write_only || config->common_config.trans_mode == spi_trans_dummy_write
- || config->common_config.trans_mode == spi_trans_write_read_together);
- /* master mode */
- assert((context->ptr->TRANSFMT & SPI_TRANSFMT_SLVMODE_MASK) != SPI_TRANSFMT_SLVMODE_MASK);
- /* GPIO should be used to replace SPI CS pin for SPI chained DMA transmissions */
- assert(context->write_cs != NULL);
- stat = spi_setup_trans_with_dma_chain(context, config);
- } else {
- /* one SPI transmissions with chained DMA */
- stat = spi_setup_trans_with_dma(context, config);
- }
- return stat;
- }
- /* Using GPIO as SPI CS pin */
- /* When SPI trans completed, GPIO cs pin should be released manually */
- hpm_stat_t hpm_spi_release_gpio_cs(spi_context_t *context)
- {
- hpm_stat_t stat;
- SPI_Type *ptr = context->ptr;
- assert(context->write_cs != NULL);
- stat = spi_wait_for_idle_status(ptr);
- if (stat != status_success) {
- return stat;
- }
- context->write_cs(context->cs_pin, !SPI_CS_ACTIVE);
- return status_success;
- }
- static hpm_stat_t wait_spi_slave_active(SPI_Type *ptr, bool active_status, uint32_t timeout)
- {
- uint32_t ticks_per_us = (hpm_core_clock + 1000000 - 1U) / 1000000;
- uint64_t expected_ticks = hpm_csr_get_core_cycle() + (uint64_t)ticks_per_us * 1000UL * timeout;
- do {
- if (hpm_csr_get_core_cycle() > expected_ticks) {
- return status_timeout;
- }
- } while (spi_is_active(ptr) == !active_status);
- return status_success;
- }
- static hpm_spi_cfg_t *hpm_spi_get_cfg_obj(SPI_Type *ptr)
- {
- hpm_spi_cfg_t *obj;
- uint8_t i = 0;
- for (i = 0; i < (sizeof(spi_dma_cfg_table) / sizeof(hpm_spi_cfg_t)); i++) {
- obj = &spi_dma_cfg_table[i];
- if (obj->spi_ptr == ptr) {
- return obj;
- }
- }
- return NULL;
- }
- static void hpm_spi_transfer_init(SPI_Type *ptr, spi_trans_mode_t mode, uint32_t size)
- {
- uint32_t slv_mode = SPI_TRANSFMT_SLVMODE_GET(ptr->TRANSFMT);
- uint8_t data_len_in_bytes = spi_get_data_length_in_bytes(ptr);
- if (data_len_in_bytes > 2) {
- data_len_in_bytes = 4;
- }
- if (slv_mode == spi_master_mode) {
- spi_set_transfer_mode(ptr, mode);
- } else {
- /* for slave mode, only support trans_write_read_together mode in only_data_mode */
- spi_set_transfer_mode(ptr, spi_trans_write_read_together);
- }
- if ((mode == spi_trans_write_read_together) || (slv_mode == spi_slave_mode)) {
- spi_set_write_data_count(ptr, size / data_len_in_bytes);
- spi_set_read_data_count(ptr, size / data_len_in_bytes);
- } else if (mode == spi_trans_write_only) {
- spi_set_write_data_count(ptr, size / data_len_in_bytes);
- } else {
- spi_set_read_data_count(ptr, size / data_len_in_bytes);
- }
- /* start new transmission, reset spi for slave*/
- if (slv_mode == spi_slave_mode) {
- spi_reset(ptr);
- }
- spi_transmit_fifo_reset(ptr);
- spi_receive_fifo_reset(ptr);
- while (ptr->CTRL & (SPI_CTRL_TXFIFORST_MASK | SPI_CTRL_RXFIFORST_MASK)) {
- }
- }
- static hpm_stat_t write_read_data_together(SPI_Type *ptr, uint8_t data_len_in_bytes, uint8_t *wbuff, uint32_t wsize,
- uint8_t *rbuff, uint32_t rsize, uint32_t timeout)
- {
- uint8_t txfifo_size = spi_get_tx_fifo_size(ptr);
- uint32_t rx_index = 0, tx_index = 0;
- uint8_t rxfifo_valid_size, txfifo_valid_size, j;
- uint32_t ticks_per_us = (hpm_core_clock + 1000000 - 1U) / 1000000;
- uint64_t expected_ticks = hpm_csr_get_core_cycle() + (uint64_t)ticks_per_us * 1000UL * timeout;
- while ((rx_index < rsize) || (tx_index < wsize)) {
- if (tx_index < wsize) {
- txfifo_valid_size = spi_get_tx_fifo_valid_data_size(ptr);
- if ((txfifo_size - txfifo_valid_size) > 0) {
- for (j = 0; j < (txfifo_size - txfifo_valid_size); j++) {
- if (tx_index >= wsize) {
- break;
- }
- switch (data_len_in_bytes) {
- case 1:
- ptr->DATA = *(uint8_t *)wbuff;
- break;
- case 2:
- ptr->DATA = *(uint16_t *)wbuff;
- break;
- default:
- ptr->DATA = *(uint32_t *)wbuff;
- break;
- }
- wbuff += data_len_in_bytes;
- tx_index++;
- }
- }
- }
- if (rx_index < rsize) {
- rxfifo_valid_size = spi_get_rx_fifo_valid_data_size(ptr);
- if (rxfifo_valid_size > 0) {
- for (j = 0; j < rxfifo_valid_size; j++) {
- if (rx_index >= rsize) {
- break;
- }
- switch (data_len_in_bytes) {
- case 1:
- *(uint8_t *)rbuff = (uint8_t)ptr->DATA;
- break;
- case 2:
- *(uint16_t *)rbuff = (uint16_t)ptr->DATA;
- break;
- default:
- *(uint32_t *)rbuff = ptr->DATA;
- break;
- }
- rbuff += data_len_in_bytes;
- rx_index++;
- }
- }
- }
- if (hpm_csr_get_core_cycle() > expected_ticks) {
- return status_timeout;
- }
- }
- return status_success;
- }
- static hpm_stat_t read_data_single(SPI_Type *ptr, uint8_t data_len_in_bytes, uint8_t *rbuff, uint32_t rsize, uint32_t timeout)
- {
- uint32_t rx_index = 0;
- uint8_t rxfifo_valid_size, j;
- uint32_t ticks_per_us = (hpm_core_clock + 1000000 - 1U) / 1000000;
- uint64_t expected_ticks = hpm_csr_get_core_cycle() + (uint64_t)ticks_per_us * 1000UL * timeout;
- while (rx_index < rsize) {
- rxfifo_valid_size = spi_get_rx_fifo_valid_data_size(ptr);
- if (rxfifo_valid_size > 0) {
- for (j = 0; j < rxfifo_valid_size; j++) {
- if (rx_index >= rsize) {
- break;
- }
- switch (data_len_in_bytes) {
- case 1:
- *(uint8_t *)rbuff = (uint8_t)ptr->DATA;
- break;
- case 2:
- *(uint16_t *)rbuff = (uint16_t)ptr->DATA;
- break;
- default:
- *(uint32_t *)rbuff = ptr->DATA;
- break;
- }
- rbuff += data_len_in_bytes;
- rx_index++;
- }
- }
- if (hpm_csr_get_core_cycle() > expected_ticks) {
- return status_timeout;
- }
- }
- return status_success;
- }
- static hpm_stat_t write_data_single(SPI_Type *ptr, uint8_t data_len_in_bytes, uint8_t *wbuff, uint32_t wsize, uint32_t timeout)
- {
- uint8_t txfifo_size = spi_get_tx_fifo_size(ptr);
- uint32_t tx_index = 0;
- uint8_t txfifo_valid_size, j;
- uint32_t ticks_per_us = (hpm_core_clock + 1000000 - 1U) / 1000000;
- uint64_t expected_ticks = hpm_csr_get_core_cycle() + (uint64_t)ticks_per_us * 1000UL * timeout;
- while (tx_index < wsize) {
- txfifo_valid_size = spi_get_tx_fifo_valid_data_size(ptr);
- if ((txfifo_size - txfifo_valid_size) > 0) {
- for (j = 0; j < (txfifo_size - txfifo_valid_size); j++) {
- if (tx_index >= wsize) {
- break;
- }
- switch (data_len_in_bytes) {
- case 1:
- ptr->DATA = *(uint8_t *)wbuff;
- break;
- case 2:
- ptr->DATA = *(uint16_t *)wbuff;
- break;
- default:
- ptr->DATA = *(uint32_t *)wbuff;
- break;
- }
- wbuff += data_len_in_bytes;
- tx_index++;
- }
- }
- if (hpm_csr_get_core_cycle() > expected_ticks) {
- return status_timeout;
- }
- }
- return status_success;
- }
- void hpm_spi_get_default_init_config(spi_initialize_config_t *config)
- {
- config->mode = spi_master_mode;
- config->io_mode = spi_single_io_mode;
- config->clk_polarity = spi_sclk_low_idle;
- config->clk_phase = spi_sclk_sampling_odd_clk_edges;
- config->data_len = 8;
- config->data_merge = false;
- config->direction = msb_first;
- }
- hpm_stat_t hpm_spi_initialize(SPI_Type *ptr, spi_initialize_config_t *config)
- {
- if (config->data_len == 0) {
- return status_invalid_argument;
- }
- /* frist init TRANSFMT reg*/
- ptr->TRANSFMT = SPI_TRANSFMT_DATALEN_SET(config->data_len - 1) |
- SPI_TRANSFMT_DATAMERGE_SET(config->data_merge) |
- SPI_TRANSFMT_LSB_SET(config->direction) |
- SPI_TRANSFMT_SLVMODE_SET(config->mode) |
- SPI_TRANSFMT_CPOL_SET(config->clk_polarity) |
- SPI_TRANSFMT_CPHA_SET(config->clk_phase);
- /* second init TRANSCTRL reg
- * default phase: disable command/address/token phase,
- * default Transfer mode: write and read at the same time
- */
- ptr->TRANSCTRL = SPI_TRANSCTRL_SLVDATAONLY_SET(1) | /* it's only data anyway for slave*/
- SPI_TRANSCTRL_DUALQUAD_SET(config->io_mode);
- /* third: init TIMING reg */
- ptr->TIMING = SPI_TIMING_CS2SCLK_SET(spi_cs2sclk_half_sclk_1) |
- SPI_TIMING_CSHT_SET(spi_csht_half_sclk_1) |
- SPI_TIMING_SCLK_DIV_SET(0x10);
- return status_success;
- }
- hpm_stat_t hpm_spi_set_sclk_frequency(SPI_Type *ptr, uint32_t freq)
- {
- int freq_list[clock_source_general_source_end] = {0};
- int _freq = freq;
- uint8_t i = 0;
- int min_diff_freq;
- int current_diff_freq;
- int best_freq;
- hpm_stat_t stat;
- uint32_t div;
- clock_source_t clock_source;
- clk_src_t clk_src;
- static spi_timing_config_t timing_config = {0};
- uint32_t pll_clk = 0;
- hpm_spi_cfg_t *obj = hpm_spi_get_cfg_obj(ptr);
- if (obj == NULL) {
- return status_invalid_argument;
- }
- spi_master_get_default_timing_config(&timing_config);
- timing_config.master_config.clk_src_freq_in_hz = clock_get_frequency(obj->spi_clock_name);
- timing_config.master_config.sclk_freq_in_hz = freq;
- timing_config.master_config.cs2sclk = spi_cs2sclk_half_sclk_1;
- timing_config.master_config.csht = spi_csht_half_sclk_1;
- stat = spi_master_timing_init(ptr, &timing_config);
- if (stat != status_success) {
- spi_master_set_sclk_div(ptr, 0xFF);
- for (clock_source = (clock_source_t)0; clock_source < clock_source_general_source_end; clock_source++) {
- pll_clk = get_frequency_for_source(clock_source);
- div = pll_clk / freq;
- /* The division factor ranges from 1 to 256 as any integer */
- if ((div > 0) && (div <= 0x100)) {
- freq_list[clock_source] = pll_clk / div;
- }
- }
- /* Find the best sclk frequency */
- min_diff_freq = abs(freq_list[0] - _freq);
- best_freq = freq_list[0];
- for (i = 1; i < clock_source_general_source_end; i++) {
- current_diff_freq = abs(freq_list[i] - _freq);
- if (current_diff_freq < min_diff_freq) {
- min_diff_freq = current_diff_freq;
- best_freq = freq_list[i];
- }
- }
- /* Find the best spi clock frequency */
- for (i = 0; i < clock_source_general_source_end; i++) {
- if (best_freq == freq_list[i]) {
- pll_clk = get_frequency_for_source((clock_source_t)i);
- clk_src = MAKE_CLK_SRC(CLK_SRC_GROUP_COMMON, i);
- div = pll_clk / best_freq;
- clock_set_source_divider(obj->spi_clock_name, clk_src, div);
- break;
- }
- }
- stat = status_success;
- }
- return stat;
- }
- hpm_stat_t hpm_spi_transmit_receive_blocking(SPI_Type *ptr, uint8_t *wbuff, uint8_t *rbuff, uint32_t size, uint32_t timeout)
- {
- hpm_stat_t stat = status_success;
- uint8_t data_len_in_bytes = spi_get_data_length_in_bytes(ptr);
- uint8_t txfifo_size = spi_get_tx_fifo_size(ptr);
- uint8_t remain_size = 0, j = 0;
- uint32_t temp, count;
- if (data_len_in_bytes > 2) {
- data_len_in_bytes = 4; /* must be 4 aglin */
- }
- if ((wbuff == NULL) || (rbuff == NULL) || (size == 0) ||
- ((SPI_SOC_TRANSFER_COUNT_MAX == 512) && (size > (SPI_SOC_TRANSFER_COUNT_MAX * data_len_in_bytes))) ||
- (spi_master_get_data_phase_format(ptr) != spi_single_io_mode)) {
- return status_invalid_argument;
- }
- count = (size / data_len_in_bytes);
- hpm_spi_transfer_init(ptr, spi_trans_write_read_together, size);
- /* for master mode, This CMD register must be written with a dummy value
- * to start a SPI transfer even when the command phase is not enabled
- */
- if (SPI_TRANSFMT_SLVMODE_GET(ptr->TRANSFMT) == spi_master_mode) {
- ptr->CMD = 0xFF;
- stat = write_read_data_together(ptr, data_len_in_bytes, wbuff, count, rbuff, count, timeout);
- if (stat == status_success) {
- /* waiting....in master mode, becomes 0 after the transfer is finished */
- stat = wait_spi_slave_active(ptr, false, timeout);
- }
- } else {
- /* Before receiving the host to start transmission, fill the TX FIFO */
- remain_size = txfifo_size - spi_get_tx_fifo_valid_data_size(ptr);
- for (j = 0; j < remain_size; j++) {
- temp = 0;
- for (uint8_t i = 0; i < data_len_in_bytes; i++) {
- temp += *(wbuff++) << i * 8;
- }
- ptr->DATA = temp;
- }
- count -= remain_size;
- /* waiting....in slave mode, becomes 1 after the SPI CS signal is asserted */
- stat = wait_spi_slave_active(ptr, true, timeout);
- /* no need to read RXFIFO because no effect SPI bus for slave mode */
- if (((size - remain_size) > 0) && (stat == status_success)) {
- stat = write_read_data_together(ptr, data_len_in_bytes, wbuff, count, rbuff, count + remain_size, timeout);
- }
- }
- return stat;
- }
- hpm_stat_t hpm_spi_receive_blocking(SPI_Type *ptr, uint8_t *buff, uint32_t size, uint32_t timeout)
- {
- hpm_stat_t stat = status_success;
- uint32_t count;
- uint8_t data_len_in_bytes = spi_get_data_length_in_bytes(ptr);
- if (data_len_in_bytes > 2) {
- data_len_in_bytes = 4; /* must be 4 aglin */
- }
- if ((buff == NULL) || (size == 0) ||
- ((SPI_SOC_TRANSFER_COUNT_MAX == 512) && (size > (SPI_SOC_TRANSFER_COUNT_MAX * data_len_in_bytes)))) {
- return status_invalid_argument;
- }
- count = (size / data_len_in_bytes);
- hpm_spi_transfer_init(ptr, spi_trans_read_only, size);
- /* for master mode, This CMD register must be written with a dummy value
- * to start a SPI transfer even when the command phase is not enabled
- */
- if (SPI_TRANSFMT_SLVMODE_GET(ptr->TRANSFMT) == spi_master_mode) {
- ptr->CMD = 0xFF;
- } else {
- /* waiting....in slave mode, becomes 1 after the SPI CS signal is asserted */
- stat = wait_spi_slave_active(ptr, true, timeout);
- }
- /* no need to write TXFIFO because no effect SPI bus for slave mode */
- if (stat == status_success) {
- stat = read_data_single(ptr, data_len_in_bytes, buff, count, timeout);
- }
- if (SPI_TRANSFMT_SLVMODE_GET(ptr->TRANSFMT) == spi_master_mode) {
- /* waiting....in master mode, becomes 0 after the transfer is finished */
- if (stat == status_success) {
- stat = wait_spi_slave_active(ptr, false, timeout);
- }
- }
- return stat;
- }
- hpm_stat_t hpm_spi_transmit_blocking(SPI_Type *ptr, uint8_t *buff, uint32_t size, uint32_t timeout)
- {
- hpm_stat_t stat = status_success;
- uint8_t txfifo_size = spi_get_tx_fifo_size(ptr);
- uint8_t remain_size = 0, j = 0;
- uint32_t temp, count;
- uint8_t data_len_in_bytes = spi_get_data_length_in_bytes(ptr);
- if (data_len_in_bytes > 2) {
- data_len_in_bytes = 4; /* must be 4 aglin */
- }
- if ((buff == NULL) || (size == 0) ||
- ((SPI_SOC_TRANSFER_COUNT_MAX == 512) && (size > (SPI_SOC_TRANSFER_COUNT_MAX * data_len_in_bytes)))) {
- return status_invalid_argument;
- }
- count = (size / data_len_in_bytes);
- hpm_spi_transfer_init(ptr, spi_trans_write_only, size);
- /* for master mode, This CMD register must be written with a dummy value
- * to start a SPI transfer even when the command phase is not enabled
- */
- if (SPI_TRANSFMT_SLVMODE_GET(ptr->TRANSFMT) == spi_master_mode) {
- ptr->CMD = 0xFF;
- stat = write_data_single(ptr, data_len_in_bytes, buff, count, timeout);
- if (stat == status_success) {
- /* waiting....in master mode, becomes 0 after the transfer is finished */
- stat = wait_spi_slave_active(ptr, false, timeout);
- }
- } else {
- /* Before receiving the host to start transmission, fill the TX FIFO */
- remain_size = txfifo_size - spi_get_tx_fifo_valid_data_size(ptr);
- for (j = 0; j < remain_size; j++) {
- temp = 0;
- for (uint8_t i = 0; i < data_len_in_bytes; i++) {
- temp += *(buff++) << i * 8;
- }
- ptr->DATA = temp;
- }
- count -= remain_size;
- /* waiting....in slave mode, becomes 1 after the SPI CS signal is asserted */
- stat = wait_spi_slave_active(ptr, true, timeout);
- /* no need to read RXFIFO because no effect SPI bus for slave mode */
- if ((count > 0) && (stat == status_success)) {
- stat = write_data_single(ptr, data_len_in_bytes, buff, count, timeout);
- }
- }
- return stat;
- }
- hpm_stat_t hpm_spi_transmit_receive_setup_dma(SPI_Type *ptr, uint32_t size)
- {
- hpm_stat_t stat = status_success;
- uint8_t data_len_in_bytes = spi_get_data_length_in_bytes(ptr);
- if (data_len_in_bytes > 2) {
- data_len_in_bytes = 4; /* must be 4 aglin */
- }
- if ((size == 0) ||
- ((SPI_SOC_TRANSFER_COUNT_MAX == 512) && (size > (SPI_SOC_TRANSFER_COUNT_MAX * data_len_in_bytes)))) {
- return status_invalid_argument;
- }
- hpm_spi_transfer_init(ptr, spi_trans_write_read_together, size);
- spi_enable_tx_dma(ptr);
- spi_enable_rx_dma(ptr);
- /* for master mode, This CMD register must be written with a dummy value
- * to start a SPI transfer even when the command phase is not enabled
- */
- if (SPI_TRANSFMT_SLVMODE_GET(ptr->TRANSFMT) == spi_master_mode) {
- ptr->CMD = 0xFF;
- }
- return stat;
- }
- hpm_stat_t hpm_spi_receive_setup_dma(SPI_Type *ptr, uint32_t size)
- {
- hpm_stat_t stat = status_success;
- uint8_t data_len_in_bytes = spi_get_data_length_in_bytes(ptr);
- if (data_len_in_bytes > 2) {
- data_len_in_bytes = 4; /* must be 4 aglin */
- }
- if ((size == 0) ||
- ((SPI_SOC_TRANSFER_COUNT_MAX == 512) && (size > (SPI_SOC_TRANSFER_COUNT_MAX * data_len_in_bytes)))) {
- return status_invalid_argument;
- }
- hpm_spi_transfer_init(ptr, spi_trans_read_only, size);
- spi_disable_tx_dma(ptr);
- spi_enable_rx_dma(ptr);
- /* for master mode, This CMD register must be written with a dummy value
- to start a SPI transfer even when the command phase is not enabled
- */
- if (SPI_TRANSFMT_SLVMODE_GET(ptr->TRANSFMT) == spi_master_mode) {
- ptr->CMD = 0xFF;
- }
- return stat;
- }
- hpm_stat_t hpm_spi_transmit_setup_dma(SPI_Type *ptr, uint32_t size)
- {
- hpm_stat_t stat = status_success;
- uint8_t data_len_in_bytes = spi_get_data_length_in_bytes(ptr);
- if (data_len_in_bytes > 2) {
- data_len_in_bytes = 4; /* must be 4 aglin */
- }
- if ((size == 0) ||
- ((SPI_SOC_TRANSFER_COUNT_MAX == 512) && (size > (SPI_SOC_TRANSFER_COUNT_MAX * data_len_in_bytes)))) {
- return status_invalid_argument;
- }
- hpm_spi_transfer_init(ptr, spi_trans_write_only, size);
- spi_enable_tx_dma(ptr);
- spi_disable_rx_dma(ptr);
- /* for master mode, This CMD register must be written with a dummy value
- * to start a SPI transfer even when the command phase is not enabled
- */
- if (SPI_TRANSFMT_SLVMODE_GET(ptr->TRANSFMT) == spi_master_mode) {
- ptr->CMD = 0xFF;
- }
- return stat;
- }
- #if USE_DMA_MGR
- void dma_channel_tc_callback(DMA_Type *ptr, uint32_t channel, void *user_data)
- {
- hpm_spi_cfg_t *obj = (hpm_spi_cfg_t *)user_data;
- if ((obj->rxdma_resource.channel == channel) &&
- (obj->rxdma_resource.base == ptr) &&
- (obj->rx_dma_complete != NULL)) {
- obj->rx_dma_complete(channel);
- }
- if ((obj->txdma_resource.channel == channel) &&
- (obj->txdma_resource.base == ptr) &&
- (obj->tx_dma_complete != NULL)) {
- obj->tx_dma_complete(channel);
- }
- }
- hpm_stat_t hpm_spi_dma_install_callback(SPI_Type *ptr, spi_dma_complete_cb tx_complete, spi_dma_complete_cb rx_complete)
- {
- dma_mgr_chn_conf_t chg_config;
- dma_resource_t *resource = NULL;
- hpm_spi_cfg_t *obj = hpm_spi_get_cfg_obj(ptr);
- if (obj == NULL) {
- return status_invalid_argument;
- }
- dma_mgr_get_default_chn_config(&chg_config);
- chg_config.src_width = DMA_MGR_TRANSFER_WIDTH_BYTE;
- chg_config.dst_width = DMA_MGR_TRANSFER_WIDTH_BYTE;
- /* spi rx dma config */
- resource = &obj->rxdma_resource;
- if (dma_mgr_request_resource(resource) == status_success) {
- chg_config.src_mode = DMA_MGR_HANDSHAKE_MODE_HANDSHAKE;
- chg_config.src_addr_ctrl = DMA_MGR_ADDRESS_CONTROL_FIXED;
- chg_config.src_addr = (uint32_t)&ptr->DATA;
- chg_config.dst_mode = DMA_MGR_HANDSHAKE_MODE_NORMAL;
- chg_config.dst_addr_ctrl = DMA_MGR_ADDRESS_CONTROL_INCREMENT;
- chg_config.en_dmamux = true;
- chg_config.dmamux_src = obj->rx_dmamux_src;
- dma_mgr_setup_channel(resource, &chg_config);
- dma_mgr_install_chn_tc_callback(resource, dma_channel_tc_callback, (void *)obj);
- dma_mgr_enable_chn_irq(resource, DMA_MGR_INTERRUPT_MASK_TC);
- dma_mgr_enable_dma_irq_with_priority(resource, 1);
- obj->rx_dma_complete = rx_complete;
- }
- /* spi tx dma config */
- resource = &obj->txdma_resource;
- if (dma_mgr_request_resource(resource) == status_success) {
- chg_config.src_mode = DMA_MGR_HANDSHAKE_MODE_NORMAL;
- chg_config.src_addr_ctrl = DMA_MGR_ADDRESS_CONTROL_INCREMENT;
- chg_config.dst_mode = DMA_MGR_HANDSHAKE_MODE_HANDSHAKE;
- chg_config.dst_addr_ctrl = DMA_MGR_ADDRESS_CONTROL_FIXED;
- chg_config.dst_addr = (uint32_t)&ptr->DATA;
- chg_config.en_dmamux = true;
- chg_config.dmamux_src = obj->tx_dmamux_src;
- dma_mgr_setup_channel(resource, &chg_config);
- dma_mgr_install_chn_tc_callback(resource, dma_channel_tc_callback, (void *)obj);
- dma_mgr_enable_chn_irq(resource, DMA_MGR_INTERRUPT_MASK_TC);
- dma_mgr_enable_dma_irq_with_priority(resource, 1);
- obj->tx_dma_complete = tx_complete;
- }
- return status_success;
- }
- hpm_stat_t hpm_spi_transmit_receive_nonblocking(SPI_Type *ptr, uint8_t *wbuff, uint8_t *rbuff, uint32_t size)
- {
- hpm_stat_t stat = status_success;
- uint8_t transfer_width;
- dma_resource_t *resource;
- uint32_t buf_addr;
- hpm_spi_cfg_t *obj = hpm_spi_get_cfg_obj(ptr);
- uint8_t data_len_in_bytes = spi_get_data_length_in_bytes(ptr);
- if (data_len_in_bytes > 2) {
- /* word */
- transfer_width = DMA_MGR_TRANSFER_WIDTH_WORD;
- data_len_in_bytes = 4; /* must be 4 aglin */
- } else {
- /* byte or half_word*/
- transfer_width = data_len_in_bytes - 1;
- }
- if ((obj == NULL) ||
- (spi_master_get_data_phase_format(ptr) != spi_single_io_mode) ||
- (size > (SPI_SOC_TRANSFER_COUNT_MAX * data_len_in_bytes))) {
- return status_invalid_argument;
- }
- spi_disable_rx_dma(ptr);
- spi_disable_tx_dma(ptr);
- spi_transmit_fifo_reset(ptr);
- spi_receive_fifo_reset(ptr);
- resource = &obj->rxdma_resource;
- buf_addr = core_local_mem_to_sys_address(HPM_CORE0, (uint32_t)rbuff);
- dma_mgr_set_chn_dst_width(resource, transfer_width);
- dma_mgr_set_chn_src_width(resource, transfer_width);
- dma_mgr_set_chn_dst_addr(resource, buf_addr);
- dma_mgr_set_chn_transize(resource, size / data_len_in_bytes);
- dma_mgr_enable_channel(resource);
- resource = &obj->txdma_resource;
- buf_addr = core_local_mem_to_sys_address(HPM_CORE0, (uint32_t)wbuff);
- dma_mgr_set_chn_dst_width(resource, transfer_width);
- dma_mgr_set_chn_src_width(resource, transfer_width);
- dma_mgr_set_chn_src_addr(resource, buf_addr);
- dma_mgr_set_chn_transize(resource, size / data_len_in_bytes);
- dma_mgr_enable_channel(resource);
- stat = hpm_spi_transmit_receive_setup_dma(ptr, size);
- return stat;
- }
- hpm_stat_t hpm_spi_receive_nonblocking(SPI_Type *ptr, uint8_t *buff, uint32_t size)
- {
- hpm_stat_t stat = status_success;
- uint8_t transfer_width;
- dma_resource_t *resource;
- uint32_t buf_addr;
- hpm_spi_cfg_t *obj = hpm_spi_get_cfg_obj(ptr);
- uint8_t data_len_in_bytes = spi_get_data_length_in_bytes(ptr);
- if (data_len_in_bytes > 2) {
- data_len_in_bytes = 4; /* must be 4 aglin */
- /* word */
- transfer_width = DMA_MGR_TRANSFER_WIDTH_WORD;
- } else {
- /* byte or half_word*/
- transfer_width = data_len_in_bytes - 1;
- }
- if ((obj == NULL) ||
- ((size > (SPI_SOC_TRANSFER_COUNT_MAX * data_len_in_bytes)))) {
- return status_invalid_argument;
- }
- spi_disable_rx_dma(ptr);
- spi_disable_tx_dma(ptr);
- spi_transmit_fifo_reset(ptr);
- spi_receive_fifo_reset(ptr);
- resource = &obj->rxdma_resource;
- buf_addr = core_local_mem_to_sys_address(HPM_CORE0, (uint32_t)buff);
- dma_mgr_set_chn_dst_width(resource, transfer_width);
- dma_mgr_set_chn_src_width(resource, transfer_width);
- dma_mgr_set_chn_dst_addr(resource, buf_addr);
- dma_mgr_set_chn_transize(resource, size / data_len_in_bytes);
- dma_mgr_enable_channel(resource);
- stat = hpm_spi_receive_setup_dma(ptr, size);
- return stat;
- }
- hpm_stat_t hpm_spi_transmit_nonblocking(SPI_Type *ptr, uint8_t *buff, uint32_t size)
- {
- hpm_stat_t stat = status_success;
- uint8_t transfer_width;
- dma_resource_t *resource;
- uint32_t buf_addr;
- hpm_spi_cfg_t *obj = hpm_spi_get_cfg_obj(ptr);
- uint8_t data_len_in_bytes = spi_get_data_length_in_bytes(ptr);
- if (data_len_in_bytes > 2) {
- data_len_in_bytes = 4; /* must be 4 aglin */
- /* word */
- transfer_width = DMA_MGR_TRANSFER_WIDTH_WORD;
- } else {
- /* byte or half_word*/
- transfer_width = data_len_in_bytes - 1;
- }
- if ((obj == NULL) ||
- (size > (SPI_SOC_TRANSFER_COUNT_MAX * data_len_in_bytes))) {
- return status_invalid_argument;
- }
- resource = &obj->txdma_resource;
- buf_addr = core_local_mem_to_sys_address(HPM_CORE0, (uint32_t)buff);
- spi_disable_rx_dma(ptr);
- spi_disable_tx_dma(ptr);
- spi_transmit_fifo_reset(ptr);
- spi_receive_fifo_reset(ptr);
- dma_mgr_set_chn_src_addr(resource, buf_addr);
- dma_mgr_set_chn_dst_width(resource, transfer_width);
- dma_mgr_set_chn_src_width(resource, transfer_width);
- dma_mgr_set_chn_transize(resource, size / data_len_in_bytes);
- dma_mgr_enable_channel(resource);
- stat = hpm_spi_transmit_setup_dma(ptr, size);
- return stat;
- }
- #endif
|