| 12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118 |
- /*
- * Copyright (C) 2022-2024, Xiaohua Semiconductor Co., Ltd.
- *
- * SPDX-License-Identifier: Apache-2.0
- *
- * Change Logs:
- * Date Author Notes
- * 2023-06-15 CDT first version
- * 2023-09-30 CDT Delete dma transmit interrupt
- * 2024-02-28 CDT support HC32F448
- * 2024-02-29 CDT Support multi line write/read
- * 2024-04-18 CDT support HC32F472
- * 2025-04-14 CDT support HC32F4A8
- */
- /*******************************************************************************
- * Include files
- ******************************************************************************/
- #include <rtthread.h>
- #include <rtdevice.h>
- #if defined(RT_USING_QSPI)
- #if defined(BSP_USING_QSPI)
- #include "drv_qspi.h"
- #include "board_config.h"
- /*******************************************************************************
- * Local type definitions ('typedef')
- ******************************************************************************/
- /*******************************************************************************
- * Local pre-processor symbols/macros ('#define')
- ******************************************************************************/
- // #define DRV_DEBUG
- #define LOG_TAG "drv.qspi"
- #include <drv_log.h>
- /* QSPI read/write function */
- #define QSPI_READ_FUNC (0U)
- #define QSPI_WRITE_FUNC (1U)
- /* QSPI direct communication line */
- #define QSPI_DIRECT_COMM_LINE_ONE (0U)
- #define QSPI_DIRECT_COMM_LINE_MULTI (1U)
- #define QSPI_BASE_BLK_SIZE (0x4000000UL)
- #define QSPI_MAX_FLASH_ADDR (0xFC000000UL)
- /* QSPI max division */
- #define QSPI_MAX_DIV_VAL (0x3FU) /* Div64 */
- /* QSPI read instruction */
- #define QSPI_3LINE_STD_RD (0x03U)
- #define QSPI_3LINE_FAST_RD (0x0BU)
- #define QSPI_3LINE_DUAL_OUTPUT_FAST_RD (0x3BU)
- #define QSPI_3LINE_DUAL_IO_FAST_RD (0xBBU)
- #define QSPI_3LINE_QUAD_OUTPUT_FAST_RD (0x6BU)
- #define QSPI_3LINE_QUAD_IO_FAST_RD (0xEBU)
- #define QSPI_4LINE_STD_RD (0x13U)
- #define QSPI_4LINE_FAST_RD (0x0CU)
- #define QSPI_4LINE_DUAL_OUTPUT_FAST_RD (0x3CU)
- #define QSPI_4LINE_DUAL_IO_FAST_RD (0xBCU)
- #define QSPI_4LINE_QUAD_OUTPUT_FAST_RD (0x6CU)
- #define QSPI_4LINE_QUAD_IO_FAST_RD (0xECU)
- /*******************************************************************************
- * Global variable definitions (declared in header file with 'extern')
- ******************************************************************************/
- extern rt_err_t rt_hw_qspi_board_init(void);
- /*******************************************************************************
- * Local function prototypes ('static')
- ******************************************************************************/
- static void qspi_err_irq_handler(void);
- /*******************************************************************************
- * Local variable definitions ('static')
- ******************************************************************************/
- #ifndef BSP_QSPI_USING_SOFT_CS
- static const uint8_t qspi_rom_cmd_list[] =
- {
- QSPI_3LINE_STD_RD, QSPI_3LINE_FAST_RD, QSPI_3LINE_DUAL_OUTPUT_FAST_RD,
- QSPI_3LINE_DUAL_IO_FAST_RD, QSPI_3LINE_QUAD_OUTPUT_FAST_RD, QSPI_3LINE_QUAD_IO_FAST_RD,
- QSPI_4LINE_STD_RD, QSPI_4LINE_FAST_RD, QSPI_4LINE_DUAL_OUTPUT_FAST_RD,
- QSPI_4LINE_DUAL_IO_FAST_RD, QSPI_4LINE_QUAD_OUTPUT_FAST_RD, QSPI_4LINE_QUAD_IO_FAST_RD,
- };
- #endif
- struct rt_spi_bus spi_bus_obj;
- struct hc32_qspi_bus qspi_bus_obj;
- /*******************************************************************************
- * Function implementation - global ('extern') and local ('static')
- ******************************************************************************/
- static int hc32_qspi_init(struct rt_qspi_device *device, struct rt_qspi_configuration *qspi_cfg)
- {
- int result = RT_EOK;
- uint32_t u32Cnt = 1;
- uint32_t u32BusFreq;
- stc_qspi_init_t stcQspiInit = QSPI_INIT_PARAMS;
- RT_ASSERT(device != RT_NULL);
- RT_ASSERT(qspi_cfg != RT_NULL);
- struct rt_spi_configuration *cfg = &qspi_cfg->parent;
- struct hc32_qspi_bus *qspi_bus = device->parent.bus->parent.user_data;
- /* Get BUS clock */
- u32BusFreq = CLK_GetBusClockFreq(CLK_BUS_HCLK);
- while (cfg->max_hz < u32BusFreq / (u32Cnt + 1U))
- {
- if (++u32Cnt == QSPI_MAX_DIV_VAL) /* Div64 */
- {
- break;
- }
- }
- stcQspiInit.u32ClockDiv = (u32Cnt << QSPI_CR_DIV_POS);
- if (!(cfg->mode & RT_SPI_CPOL))
- {
- stcQspiInit.u32SpiMode = QSPI_SPI_MD0; /* QSPI MODE0 */
- }
- else
- {
- stcQspiInit.u32SpiMode = QSPI_SPI_MD3; /* QSPI MODE3 */
- }
- /* Enable qspi clock */
- FCG_Fcg1PeriphClockCmd(qspi_bus->config->clock, ENABLE);
- /* qspi port init */
- rt_hw_qspi_board_init();
- /* Init QSPI */
- stcQspiInit.u32ReadMode = QSPI_RD_MD_STD_RD;
- stcQspiInit.u32DummyCycle = QSPI_DUMMY_CYCLE4;
- stcQspiInit.u32AddrWidth = QSPI_ADDR_WIDTH_24BIT;
- (void)QSPI_Init(&stcQspiInit);
- QSPI_SetWpPinLevel(QSPI_WP_PIN_LEVEL);
- /* Enable error interrupt */
- NVIC_EnableIRQ(qspi_bus->config->err_irq.irq_config.irq_num);
- LOG_D("qspi init success!");
- #ifdef BSP_QSPI_USING_DMA
- struct dma_config *qspi_dma;
- stc_dma_init_t stcDmaInit;
- /* Get qspi dma */
- qspi_dma = qspi_bus->config->dma_qspi;
- /* Enable Dma clock */
- FCG_Fcg0PeriphClockCmd(qspi_dma->clock, ENABLE);
- /* Config Dma */
- DMA_StructInit(&stcDmaInit);
- stcDmaInit.u32DataWidth = DMA_DATAWIDTH_8BIT;
- /* Init Dma */
- if (LL_OK != DMA_Init(qspi_dma->Instance, qspi_dma->channel, &stcDmaInit))
- {
- return -RT_ERROR;
- }
- DMA_Cmd(qspi_dma->Instance, ENABLE);
- #endif /* BSP_QSPI_USING_DMA */
- return result;
- }
- #ifndef BSP_QSPI_USING_SOFT_CS
- static int32_t hc32_qspi_search_rom_cmd(uint8_t u8Cmd)
- {
- uint32_t u32Cnt, u32ListLen;
- u32ListLen = sizeof(qspi_rom_cmd_list);
- for (u32Cnt = 0; u32Cnt < u32ListLen; u32Cnt++)
- {
- if (u8Cmd == qspi_rom_cmd_list[u32Cnt])
- {
- return LL_OK;
- }
- }
- return LL_ERR;
- }
- #endif
- static int32_t hc32_qspi_check_direct_comm_param(struct rt_qspi_message *message, uint8_t line)
- {
- if (QSPI_DIRECT_COMM_LINE_ONE == line)
- {
- if (message->instruction.qspi_lines > 1)
- {
- return LL_ERR_INVD_PARAM;
- }
- if (message->address.size != 0)
- {
- if ((message->address.qspi_lines > 1) || ((message->address.size % 8) != 0))
- {
- return LL_ERR_INVD_PARAM;
- }
- }
- if (message->qspi_data_lines > 1)
- {
- return LL_ERR_INVD_PARAM;
- }
- if (0U != message->dummy_cycles)
- {
- if ((message->dummy_cycles < 3) || (message->dummy_cycles > 18) || (message->dummy_cycles % 8) != 0)
- {
- return LL_ERR_INVD_PARAM;
- }
- }
- }
- else
- {
- if ((message->instruction.qspi_lines > 2) && (message->instruction.qspi_lines != 4))
- {
- return LL_ERR_INVD_PARAM;
- }
- if (message->address.size != 0)
- {
- if (((message->address.qspi_lines > 2) && (message->address.qspi_lines != 4)) ||
- ((message->address.size % 8) != 0))
- {
- return LL_ERR_INVD_PARAM;
- }
- }
- if ((message->qspi_data_lines > 2) && (message->qspi_data_lines != 4))
- {
- return LL_ERR_INVD_PARAM;
- }
- if ((0U != message->dummy_cycles) && ((message->dummy_cycles < 3) || (message->dummy_cycles > 18)))
- {
- return LL_ERR_INVD_PARAM;
- }
- if (0U != message->dummy_cycles)
- {
- if ((message->dummy_cycles < 3) || (message->dummy_cycles > 18))
- {
- return LL_ERR_INVD_PARAM;
- }
- }
- }
- return LL_OK;
- }
- static int32_t hc32_qspi_send_cmd(struct hc32_qspi_bus *qspi_bus, struct rt_qspi_message *message, uint8_t u8Func)
- {
- #ifndef BSP_QSPI_USING_SOFT_CS
- uint32_t u32ReadMode = QSPI_RD_MD_STD_RD;
- uint32_t u32DummyCycle = 0U;
- uint32_t u32AddrWidth;
- uint8_t u8Instr, u8CalcDummy = 0U;
- #endif
- RT_ASSERT(qspi_bus != RT_NULL);
- RT_ASSERT(message != RT_NULL);
- #ifndef BSP_QSPI_USING_SOFT_CS
- CM_QSPI_TypeDef *qspi_instance = qspi_bus->config->Instance;
- u8Instr = message->instruction.content;
- if ((QSPI_READ_FUNC == u8Func) && (LL_OK == hc32_qspi_search_rom_cmd(u8Instr)))
- {
- if ((message->instruction.qspi_lines != 1) ||
- ((message->address.qspi_lines != 1) && (message->address.qspi_lines != 2) && (message->address.qspi_lines != 4)) ||
- ((message->qspi_data_lines != 1) && (message->qspi_data_lines != 2) && (message->qspi_data_lines != 4)))
- {
- return LL_ERR_INVD_PARAM;
- }
- if (((message->address.qspi_lines == 2) && ((message->qspi_data_lines == 1) || (message->qspi_data_lines == 4))) ||
- ((message->address.qspi_lines == 4) && ((message->qspi_data_lines == 1) || (message->qspi_data_lines == 2))))
- {
- return LL_ERR_INVD_PARAM;
- }
- if ((message->instruction.qspi_lines == 1) && (message->address.qspi_lines == 1) && (message->qspi_data_lines == 1))
- {
- if (message->dummy_cycles != 0)
- {
- u32ReadMode += 1U;
- u8CalcDummy = 1U;
- }
- }
- else
- {
- u8CalcDummy = 1U;
- u32ReadMode = message->qspi_data_lines;
- if (message->address.qspi_lines == message->qspi_data_lines)
- {
- u32ReadMode += 1U;
- }
- }
- if (0U != u8CalcDummy)
- {
- if ((message->dummy_cycles < 3) || (message->dummy_cycles > 18))
- {
- return LL_ERR_INVD_PARAM;
- }
- u32DummyCycle = (message->dummy_cycles - 3) << QSPI_FCR_DMCYCN_POS;
- }
- if (message->address.size == 24)
- {
- u32AddrWidth = QSPI_ADDR_WIDTH_24BIT;
- }
- else
- {
- u32AddrWidth = QSPI_ADDR_WIDTH_32BIT_INSTR_32BIT;
- }
- /* configure register */
- MODIFY_REG32(qspi_instance->FCR, (QSPI_FCR_DMCYCN | QSPI_FCR_FOUR_BIC | QSPI_FCR_AWSL),
- (u32DummyCycle | u32AddrWidth));
- QSPI_SetReadMode(u32ReadMode);
- }
- else
- #endif
- {
- #if defined (HC32F460) || defined (HC32F4A0) || defined (HC32F472)
- #ifndef BSP_QSPI_USING_SOFT_CS
- if (LL_OK != hc32_qspi_check_direct_comm_param(message, QSPI_DIRECT_COMM_LINE_ONE))
- {
- return LL_ERR_INVD_PARAM;
- }
- /* Set standard read mode */
- QSPI_SetReadMode(QSPI_RD_MD_STD_RD);
- #else
- if (LL_OK != hc32_qspi_check_direct_comm_param(message, QSPI_DIRECT_COMM_LINE_MULTI))
- {
- return LL_ERR_INVD_PARAM;
- }
- /* Set custom read mode */
- QSPI_SetReadMode(QSPI_RD_MD_CUSTOM_FAST_RD);
- #endif
- #elif defined (HC32F448) || defined (HC32F4A8)
- if (LL_OK != hc32_qspi_check_direct_comm_param(message, QSPI_DIRECT_COMM_LINE_MULTI))
- {
- return LL_ERR_INVD_PARAM;
- }
- #endif
- }
- return LL_OK;
- }
- static void hc32_qspi_word_to_byte(uint32_t u32Word, uint8_t *pu8Byte, uint8_t u8Len)
- {
- uint8_t u8Count = 0U;
- uint32_t u32ByteNum = u8Len - 1U;
- do
- {
- pu8Byte[u8Count++] = (uint8_t)(u32Word >> (u32ByteNum * 8U)) & 0xFFU;
- }
- while ((u32ByteNum--) != 0UL);
- }
- #if defined (HC32F448) || defined (HC32F4A8)
- static rt_uint32_t hc32_qspi_get_dcom_protocol_line(rt_uint8_t protocol_line)
- {
- rt_uint32_t dcom_protocol_line;
- switch (protocol_line)
- {
- case 2:
- dcom_protocol_line = QSPI_DIRECT_COMM_PROTOCOL_2LINE;
- break;
- case 4:
- dcom_protocol_line = QSPI_DIRECT_COMM_PROTOCOL_4LINE;
- break;
- case 1:
- default:
- dcom_protocol_line = QSPI_DIRECT_COMM_PROTOCOL_1LINE;
- break;
- }
- return dcom_protocol_line;
- }
- #endif
- static void hc32_qspi_write_direct_comm_value(rt_uint8_t protocol_line, rt_uint8_t value)
- {
- #if defined (HC32F460) || defined (HC32F4A0) || defined (HC32F472)
- (void)protocol_line;
- QSPI_WriteDirectCommValue(value);
- #elif defined (HC32F448) || defined (HC32F4A8)
- QSPI_WriteDirectCommValue(hc32_qspi_get_dcom_protocol_line(protocol_line), value);
- #endif
- }
- #if defined (HC32F460) || defined (HC32F4A0) || defined (HC32F472)
- #ifdef BSP_QSPI_USING_SOFT_CS
- static void hc32_qspi_set_trans_protocol(uint32_t u32Line)
- {
- stc_qspi_custom_mode_t stcCustomMode;
- stcCustomMode.u8InstrCode = 0U;
- switch (u32Line)
- {
- case 2:
- stcCustomMode.u32InstrProtocol = QSPI_INSTR_PROTOCOL_2LINE;
- stcCustomMode.u32AddrProtocol = QSPI_ADDR_PROTOCOL_2LINE;
- stcCustomMode.u32DataProtocol = QSPI_DATA_PROTOCOL_2LINE;
- break;
- case 4:
- stcCustomMode.u32InstrProtocol = QSPI_INSTR_PROTOCOL_4LINE;
- stcCustomMode.u32AddrProtocol = QSPI_ADDR_PROTOCOL_4LINE;
- stcCustomMode.u32DataProtocol = QSPI_DATA_PROTOCOL_4LINE;
- break;
- case 1:
- default:
- stcCustomMode.u32InstrProtocol = QSPI_INSTR_PROTOCOL_1LINE;
- stcCustomMode.u32AddrProtocol = QSPI_ADDR_PROTOCOL_1LINE;
- stcCustomMode.u32DataProtocol = QSPI_DATA_PROTOCOL_1LINE;
- break;
- }
- QSPI_CustomReadConfig(&stcCustomMode);
- }
- #endif
- #endif
- static int32_t hc32_qspi_write_instr(struct hc32_qspi_bus *qspi_bus, struct rt_qspi_message *message,
- uint8_t u8Instr, uint32_t u32InstrLen, uint8_t *pu8Addr, uint32_t u32AddrLen,
- const uint8_t *pu8WriteBuf, uint32_t u32BufLen)
- {
- uint32_t u32Count;
- int32_t i32Ret = LL_OK;
- #ifdef BSP_QSPI_USING_DMA
- struct dma_config *qspi_dma;
- stc_dma_init_t stcDmaInit;
- uint32_t u32DmaTransSize;
- uint32_t u32TxIndex = 0U;
- rt_uint32_t u32TimeoutCnt;
- rt_uint32_t src_addr;
- #endif
- #if defined (HC32F460) || defined (HC32F4A0) || defined (HC32F472)
- #ifndef BSP_QSPI_USING_SOFT_CS
- /* Enter direct communication mode */
- SET_REG32_BIT(CM_QSPI->CR, QSPI_CR_DCOME);
- #endif
- #elif defined (HC32F448) || defined (HC32F4A8)
- /* Enter direct communication mode */
- SET_REG32_BIT(CM_QSPI->CR, QSPI_CR_DCOME);
- #endif
- if (0UL != u32InstrLen)
- {
- #if defined (HC32F460) || defined (HC32F4A0) || defined (HC32F472)
- #ifdef BSP_QSPI_USING_SOFT_CS
- hc32_qspi_set_trans_protocol(message->instruction.qspi_lines);
- SET_REG32_BIT(CM_QSPI->CR, QSPI_CR_DCOME);
- #endif
- #endif
- hc32_qspi_write_direct_comm_value(message->instruction.qspi_lines, u8Instr);
- #if defined (HC32F460) || defined (HC32F4A0) || defined (HC32F472)
- #ifdef BSP_QSPI_USING_SOFT_CS
- CLR_REG32_BIT(CM_QSPI->CR, QSPI_CR_DCOME);
- #endif
- #endif
- }
- if ((NULL != pu8Addr) && (0UL != u32AddrLen))
- {
- #if defined (HC32F460) || defined (HC32F4A0) || defined (HC32F472)
- #ifdef BSP_QSPI_USING_SOFT_CS
- hc32_qspi_set_trans_protocol(message->address.qspi_lines);
- SET_REG32_BIT(CM_QSPI->CR, QSPI_CR_DCOME);
- #endif
- #endif
- for (u32Count = 0UL; u32Count < u32AddrLen; u32Count++)
- {
- hc32_qspi_write_direct_comm_value(message->address.qspi_lines, pu8Addr[u32Count]);
- }
- #if defined (HC32F460) || defined (HC32F4A0) || defined (HC32F472)
- #ifdef BSP_QSPI_USING_SOFT_CS
- CLR_REG32_BIT(CM_QSPI->CR, QSPI_CR_DCOME);
- #endif
- #endif
- }
- if ((NULL != pu8WriteBuf) && (0UL != u32BufLen))
- {
- #if defined (HC32F460) || defined (HC32F4A0) || defined (HC32F472)
- #ifdef BSP_QSPI_USING_SOFT_CS
- hc32_qspi_set_trans_protocol(message->qspi_data_lines);
- SET_REG32_BIT(CM_QSPI->CR, QSPI_CR_DCOME);
- #endif
- #endif
- #ifdef BSP_QSPI_USING_DMA
- qspi_dma = qspi_bus->config->dma_qspi;
- AOS_SetTriggerEventSrc(qspi_dma->trigger_select, qspi_dma->trigger_event);
- /* Config Dma */
- DMA_StructInit(&stcDmaInit);
- #if defined (HC32F460) || defined (HC32F4A0) || defined (HC32F472)
- stcDmaInit.u32DataWidth = DMA_DATAWIDTH_8BIT;
- #elif defined (HC32F448) || defined (HC32F4A8)
- rt_uint16_t dcom_line = (rt_uint16_t)hc32_qspi_get_dcom_protocol_line(message->qspi_data_lines);
- stcDmaInit.u32DataWidth = DMA_DATAWIDTH_16BIT;
- #endif
- stcDmaInit.u32SrcAddrInc = DMA_SRC_ADDR_INC;
- stcDmaInit.u32DestAddrInc = DMA_DEST_ADDR_FIX;
- DMA_Init(qspi_dma->Instance, qspi_dma->channel, &stcDmaInit);
- while (u32BufLen != 0U)
- {
- if (u32BufLen > DMA_DTCTL_BLKSIZE)
- {
- u32DmaTransSize = DMA_DTCTL_BLKSIZE;
- u32BufLen -= DMA_DTCTL_BLKSIZE;
- }
- else
- {
- u32DmaTransSize = u32BufLen;
- u32BufLen = 0U;
- }
- #if defined (HC32F460) || defined (HC32F4A0) || defined (HC32F472)
- src_addr = (rt_uint32_t)&pu8WriteBuf[u32TxIndex];
- #elif defined (HC32F448) || defined (HC32F4A8)
- if (u32DmaTransSize > qspi_bus->config->dma_tx_buf_size)
- {
- LOG_E("qspi dma transmit size over buffer size!");
- i32Ret = LL_ERR;
- break;
- }
- for (rt_uint32_t i = 0; i < u32DmaTransSize; i++)
- {
- qspi_bus->config->dma_tx_buf[i] = (rt_uint16_t)pu8WriteBuf[u32TxIndex + i] | dcom_line;
- }
- src_addr = (rt_uint32_t)qspi_bus->config->dma_tx_buf;
- #endif
- DMA_ClearTransCompleteStatus(qspi_dma->Instance, qspi_dma->flag);
- DMA_SetSrcAddr(qspi_dma->Instance, qspi_dma->channel, src_addr);
- DMA_SetDestAddr(qspi_dma->Instance, qspi_dma->channel, (uint32_t)&qspi_bus->config->Instance->DCOM);
- DMA_SetTransCount(qspi_dma->Instance, qspi_dma->channel, 1UL);
- DMA_SetBlockSize(qspi_dma->Instance, qspi_dma->channel, (uint16_t)u32DmaTransSize);
- (void)DMA_ChCmd(qspi_dma->Instance, qspi_dma->channel, ENABLE);
- AOS_SW_Trigger(); /* 1st trigger for DMA */
- u32TimeoutCnt = 0U;
- /* Wait DMA transfer completed */
- while ((RESET == DMA_GetTransCompleteStatus(qspi_dma->Instance, qspi_dma->flag)) &&
- (u32TimeoutCnt < qspi_bus->config->timeout))
- {
- rt_thread_mdelay(1);
- u32TimeoutCnt++;
- }
- if (u32TimeoutCnt >= qspi_bus->config->timeout)
- {
- i32Ret = LL_ERR_TIMEOUT;
- break;
- }
- u32TxIndex += u32DmaTransSize;
- }
- #else
- for (u32Count = 0UL; u32Count < u32BufLen; u32Count++)
- {
- hc32_qspi_write_direct_comm_value(message->qspi_data_lines, pu8WriteBuf[u32Count]);
- }
- #endif
- #if defined (HC32F460) || defined (HC32F4A0) || defined (HC32F472)
- #ifdef BSP_QSPI_USING_SOFT_CS
- /* Exit direct communication mode */
- CLR_REG32_BIT(CM_QSPI->CR, QSPI_CR_DCOME);
- #endif
- #endif
- }
- #if defined (HC32F460) || defined (HC32F4A0) || defined (HC32F472)
- #ifndef BSP_QSPI_USING_SOFT_CS
- /* Exit direct communication mode */
- CLR_REG32_BIT(CM_QSPI->CR, QSPI_CR_DCOME);
- #endif
- #elif defined (HC32F448) || defined (HC32F4A8)
- /* Exit direct communication mode */
- CLR_REG32_BIT(CM_QSPI->CR, QSPI_CR_DCOME);
- #endif
- return i32Ret;
- }
- static int32_t hc32_qspi_read_instr(struct hc32_qspi_bus *qspi_bus, struct rt_qspi_message *message,
- uint8_t u8Instr, uint32_t u32InstrLen, uint8_t *pu8Addr, uint32_t u32AddrLen,
- uint8_t *pu8ReadBuf, uint32_t u32BufLen)
- {
- uint32_t u32Count;
- int32_t i32Ret = LL_OK;
- #ifdef BSP_QSPI_USING_DMA
- struct dma_config *qspi_dma;
- stc_dma_init_t stcDmaInit;
- uint32_t u32DmaTransSize;
- uint32_t u32RxIndex = 0U;
- rt_uint32_t u32TimeoutCnt;
- #endif
- #if defined (HC32F448) || defined (HC32F4A8)
- rt_uint32_t u32ReadMd;
- #endif
- #if defined (HC32F460) || defined (HC32F4A0) || defined (HC32F472)
- #ifndef BSP_QSPI_USING_SOFT_CS
- /* Enter direct communication mode */
- SET_REG32_BIT(CM_QSPI->CR, QSPI_CR_DCOME);
- #endif
- #elif defined (HC32F448) || defined (HC32F4A8)
- if ((message->instruction.qspi_lines == 4) || (message->address.qspi_lines == 4) ||
- (message->qspi_data_lines == 4))
- {
- u32ReadMd = READ_REG32_BIT(CM_QSPI->CR, QSPI_CR_MDSEL);
- QSPI_SetReadMode(QSPI_RD_MD_QUAD_IO_FAST_RD);
- }
- /* Enter direct communication mode */
- SET_REG32_BIT(CM_QSPI->CR, QSPI_CR_DCOME);
- #endif
- if (0UL != u32InstrLen)
- {
- #if defined (HC32F460) || defined (HC32F4A0) || defined (HC32F472)
- #ifdef BSP_QSPI_USING_SOFT_CS
- hc32_qspi_set_trans_protocol(message->instruction.qspi_lines);
- SET_REG32_BIT(CM_QSPI->CR, QSPI_CR_DCOME);
- #endif
- #endif
- hc32_qspi_write_direct_comm_value(message->instruction.qspi_lines, u8Instr);
- #if defined (HC32F460) || defined (HC32F4A0) || defined (HC32F472)
- #ifdef BSP_QSPI_USING_SOFT_CS
- CLR_REG32_BIT(CM_QSPI->CR, QSPI_CR_DCOME);
- #endif
- #endif
- }
- if ((NULL != pu8Addr) && (0UL != u32AddrLen))
- {
- #if defined (HC32F460) || defined (HC32F4A0) || defined (HC32F472)
- #ifdef BSP_QSPI_USING_SOFT_CS
- hc32_qspi_set_trans_protocol(message->address.qspi_lines);
- SET_REG32_BIT(CM_QSPI->CR, QSPI_CR_DCOME);
- #endif
- #endif
- for (u32Count = 0UL; u32Count < u32AddrLen; u32Count++)
- {
- hc32_qspi_write_direct_comm_value(message->address.qspi_lines, pu8Addr[u32Count]);
- }
- #if defined (HC32F460) || defined (HC32F4A0) || defined (HC32F472)
- #ifdef BSP_QSPI_USING_SOFT_CS
- CLR_REG32_BIT(CM_QSPI->CR, QSPI_CR_DCOME);
- #endif
- #endif
- }
- if ((NULL != pu8ReadBuf) && (0UL != u32BufLen))
- {
- #if defined (HC32F460) || defined (HC32F4A0) || defined (HC32F472)
- #ifdef BSP_QSPI_USING_SOFT_CS
- hc32_qspi_set_trans_protocol(message->qspi_data_lines);
- SET_REG32_BIT(CM_QSPI->CR, QSPI_CR_DCOME);
- #endif
- #endif
- #ifdef BSP_QSPI_USING_DMA
- qspi_dma = qspi_bus->config->dma_qspi;
- AOS_SetTriggerEventSrc(qspi_dma->trigger_select, qspi_dma->trigger_event);
- /* Config Dma */
- DMA_StructInit(&stcDmaInit);
- stcDmaInit.u32DataWidth = DMA_DATAWIDTH_8BIT;
- stcDmaInit.u32SrcAddrInc = DMA_SRC_ADDR_FIX;
- stcDmaInit.u32DestAddrInc = DMA_DEST_ADDR_INC;
- DMA_Init(qspi_dma->Instance, qspi_dma->channel, &stcDmaInit);
- while (u32BufLen != 0U)
- {
- if (u32BufLen > DMA_DTCTL_BLKSIZE)
- {
- u32DmaTransSize = DMA_DTCTL_BLKSIZE;
- u32BufLen -= DMA_DTCTL_BLKSIZE;
- }
- else
- {
- u32DmaTransSize = u32BufLen;
- u32BufLen = 0U;
- }
- DMA_ClearTransCompleteStatus(qspi_dma->Instance, qspi_dma->flag);
- DMA_SetSrcAddr(qspi_dma->Instance, qspi_dma->channel, (uint32_t)&qspi_bus->config->Instance->DCOM);
- DMA_SetDestAddr(qspi_dma->Instance, qspi_dma->channel, (uint32_t)&pu8ReadBuf[u32RxIndex]);
- DMA_SetTransCount(qspi_dma->Instance, qspi_dma->channel, 1UL);
- DMA_SetBlockSize(qspi_dma->Instance, qspi_dma->channel, (uint16_t)u32DmaTransSize);
- (void)DMA_ChCmd(qspi_dma->Instance, qspi_dma->channel, ENABLE);
- AOS_SW_Trigger(); /* 1st trigger for DMA */
- u32TimeoutCnt = 0U;
- /* Wait DMA transfer completed */
- while ((RESET == DMA_GetTransCompleteStatus(qspi_dma->Instance, qspi_dma->flag)) &&
- (u32TimeoutCnt < qspi_bus->config->timeout))
- {
- rt_thread_mdelay(1);
- u32TimeoutCnt++;
- }
- if (u32TimeoutCnt >= qspi_bus->config->timeout)
- {
- i32Ret = LL_ERR_TIMEOUT;
- break;
- }
- u32RxIndex += u32DmaTransSize;
- }
- #else
- for (u32Count = 0UL; u32Count < u32BufLen; u32Count++)
- {
- pu8ReadBuf[u32Count] = QSPI_ReadDirectCommValue();
- }
- #endif
- #if defined (HC32F460) || defined (HC32F4A0) || defined (HC32F472)
- #ifdef BSP_QSPI_USING_SOFT_CS
- /* Exit direct communication mode */
- CLR_REG32_BIT(CM_QSPI->CR, QSPI_CR_DCOME);
- #endif
- #endif
- }
- #if defined (HC32F460) || defined (HC32F4A0) || defined (HC32F472)
- #ifndef BSP_QSPI_USING_SOFT_CS
- /* Exit direct communication mode */
- CLR_REG32_BIT(CM_QSPI->CR, QSPI_CR_DCOME);
- #endif
- #elif defined (HC32F448) || defined (HC32F4A8)
- if ((message->instruction.qspi_lines == 4) || (message->address.qspi_lines == 4) ||
- (message->qspi_data_lines == 4))
- {
- QSPI_SetReadMode(u32ReadMd);
- }
- /* Exit direct communication mode */
- CLR_REG32_BIT(CM_QSPI->CR, QSPI_CR_DCOME);
- #endif
- return i32Ret;
- }
- static int32_t hc32_qspi_write(struct hc32_qspi_bus *qspi_bus, struct rt_qspi_message *message)
- {
- uint32_t u32Count = 0U;
- const rt_uint8_t *tx_buf = message->parent.send_buf;
- rt_int32_t length = message->parent.length;
- uint32_t u32Addr = message->address.content;
- uint8_t u8Instr = message->instruction.content;
- uint8_t u8AddrBuf[32];
- uint32_t u32AddrLen = 0U, u32DummyLen = 0U;
- uint32_t u32InstrLen = 0U;
- int32_t i32Ret;
- RT_ASSERT(qspi_bus != RT_NULL);
- RT_ASSERT(message != RT_NULL);
- if (message->instruction.qspi_lines != 0)
- {
- u32InstrLen = 1U;
- }
- if (message->address.size != 0)
- {
- u32AddrLen = message->address.size / 8;
- hc32_qspi_word_to_byte(u32Addr, u8AddrBuf, u32AddrLen);
- }
- if (message->dummy_cycles != 0)
- {
- u32DummyLen = message->dummy_cycles * message->address.qspi_lines / 8;
- for (u32Count = 0; u32Count < u32DummyLen; u32Count++)
- {
- u8AddrBuf[u32AddrLen] = 0xFF;
- u32AddrLen += 1;
- }
- }
- i32Ret = hc32_qspi_write_instr(qspi_bus, message, u8Instr, u32InstrLen, u8AddrBuf, u32AddrLen, tx_buf, length);
- return i32Ret;
- }
- static int32_t hc32_qspi_read(struct hc32_qspi_bus *qspi_bus, struct rt_qspi_message *message)
- {
- uint32_t u32Count = 0U;
- rt_uint8_t *rx_buf = message->parent.recv_buf;
- rt_int32_t length = message->parent.length;
- uint32_t u32Addr = message->address.content;
- uint8_t u8Instr = message->instruction.content;
- uint8_t u8AddrBuf[32];
- uint32_t u32AddrLen = 0U, u32DummyLen = 0U;
- uint32_t u32InstrLen = 0U;
- int32_t i32Ret = LL_OK;
- #ifndef BSP_QSPI_USING_SOFT_CS
- uint32_t u32ExtBlkStartNum = 0U;
- uint32_t u32GetSize, u32RxIndex = 0U;
- #ifdef BSP_QSPI_USING_DMA
- struct dma_config *qspi_dma;
- stc_dma_init_t stcDmaInit;
- uint32_t u32DmaTransSize;
- rt_uint32_t u32TimeoutCnt;
- #else
- __IO uint8_t *pu8Read;
- #endif
- #endif
- RT_ASSERT(qspi_bus != RT_NULL);
- RT_ASSERT(message != RT_NULL);
- #ifndef BSP_QSPI_USING_SOFT_CS
- if (LL_OK == hc32_qspi_search_rom_cmd(u8Instr))
- {
- u32ExtBlkStartNum = u32Addr / QSPI_BASE_BLK_SIZE;
- if ((u32Addr + length) > QSPI_MAX_FLASH_ADDR)
- {
- return LL_ERR_INVD_PARAM;
- }
- u32Addr = (u32Addr % QSPI_BASE_BLK_SIZE) + QSPI_ROM_BASE;
- #ifdef BSP_QSPI_USING_DMA
- qspi_dma = qspi_bus->config->dma_qspi;
- AOS_SetTriggerEventSrc(qspi_dma->trigger_select, qspi_dma->trigger_event);
- /* Config Dma */
- DMA_StructInit(&stcDmaInit);
- stcDmaInit.u32DataWidth = DMA_DATAWIDTH_8BIT;
- stcDmaInit.u32SrcAddrInc = DMA_SRC_ADDR_INC;
- stcDmaInit.u32DestAddrInc = DMA_DEST_ADDR_INC;
- DMA_Init(qspi_dma->Instance, qspi_dma->channel, &stcDmaInit);
- while (length != 0)
- {
- QSPI_SelectMemoryBlock((uint8_t)u32ExtBlkStartNum);
- if ((u32Addr + length) > (QSPI_ROM_END + 1U))
- {
- u32GetSize = (QSPI_ROM_END + 1U) - u32Addr;
- length -= u32GetSize;
- }
- else
- {
- u32GetSize = length;
- length = 0U;
- }
- while (u32GetSize != 0U)
- {
- if (u32GetSize > DMA_DTCTL_BLKSIZE)
- {
- u32DmaTransSize = DMA_DTCTL_BLKSIZE;
- u32GetSize -= DMA_DTCTL_BLKSIZE;
- }
- else
- {
- u32DmaTransSize = u32GetSize;
- u32GetSize = 0U;
- }
- DMA_ClearTransCompleteStatus(qspi_dma->Instance, qspi_dma->flag);
- DMA_SetSrcAddr(qspi_dma->Instance, qspi_dma->channel, u32Addr);
- DMA_SetDestAddr(qspi_dma->Instance, qspi_dma->channel, (uint32_t)&rx_buf[u32RxIndex]);
- DMA_SetTransCount(qspi_dma->Instance, qspi_dma->channel, 1UL);
- DMA_SetBlockSize(qspi_dma->Instance, qspi_dma->channel, (uint16_t)u32DmaTransSize);
- (void)DMA_ChCmd(qspi_dma->Instance, qspi_dma->channel, ENABLE);
- AOS_SW_Trigger(); /* 1st trigger for DMA */
- u32TimeoutCnt = 0U;
- /* Wait DMA transfer completed */
- while ((RESET == DMA_GetTransCompleteStatus(qspi_dma->Instance, qspi_dma->flag)) &&
- (u32TimeoutCnt < qspi_bus->config->timeout))
- {
- rt_thread_mdelay(1);
- u32TimeoutCnt++;
- }
- if (u32TimeoutCnt >= qspi_bus->config->timeout)
- {
- return LL_ERR_TIMEOUT;
- }
- u32Addr += u32DmaTransSize;
- u32RxIndex += u32DmaTransSize;
- }
- if (length != 0U)
- {
- u32ExtBlkStartNum += 1U;
- u32Addr = QSPI_ROM_BASE;
- }
- }
- #else
- while (length != 0)
- {
- QSPI_SelectMemoryBlock((uint8_t)u32ExtBlkStartNum);
- pu8Read = (__IO uint8_t *)u32Addr;
- if ((u32Addr + length) > (QSPI_ROM_END + 1U))
- {
- u32GetSize = (QSPI_ROM_END + 1U) - u32Addr;
- length -= u32GetSize;
- }
- else
- {
- u32GetSize = length;
- length = 0U;
- }
- u32Count = 0U;
- while (u32Count < u32GetSize)
- {
- rx_buf[u32RxIndex++] = *pu8Read++;
- u32Count++;
- }
- if (length != 0U)
- {
- u32ExtBlkStartNum += 1U;
- u32Addr = QSPI_ROM_BASE;
- }
- }
- #endif
- }
- else
- #endif
- {
- if (message->instruction.qspi_lines != 0)
- {
- u32InstrLen = 1U;
- }
- if (message->address.size != 0)
- {
- u32AddrLen = message->address.size / 8;
- hc32_qspi_word_to_byte(u32Addr, u8AddrBuf, u32AddrLen);
- }
- if (message->dummy_cycles != 0)
- {
- u32DummyLen = message->dummy_cycles * message->address.qspi_lines / 8;
- for (u32Count = 0; u32Count < u32DummyLen; u32Count++)
- {
- u8AddrBuf[u32AddrLen] = 0xFF;
- u32AddrLen += 1;
- }
- }
- i32Ret = hc32_qspi_read_instr(qspi_bus, message, u8Instr, u32InstrLen, u8AddrBuf, u32AddrLen, rx_buf, length);
- }
- return i32Ret;
- }
- static rt_ssize_t qspixfer(struct rt_spi_device *device, struct rt_spi_message *message)
- {
- RT_ASSERT(device != RT_NULL);
- RT_ASSERT(device->bus != RT_NULL);
- rt_size_t len = 0;
- struct rt_qspi_message *qspi_message = (struct rt_qspi_message *)message;
- struct hc32_qspi_bus *qspi_bus = device->bus->parent.user_data;
- #ifdef BSP_QSPI_USING_SOFT_CS
- struct hc32_hw_qspi_cs *cs = device->parent.user_data;
- #endif
- rt_int32_t length = message->length;
- #ifdef BSP_QSPI_USING_SOFT_CS
- if (message->cs_take)
- {
- rt_pin_write(cs->pin, 0);
- }
- #endif
- if (message->send_buf != NULL) /* send data */
- {
- if (LL_OK != hc32_qspi_send_cmd(qspi_bus, qspi_message, QSPI_WRITE_FUNC))
- {
- LOG_E("QSPI rt_qspi_message format error!");
- goto __exit;
- }
- if (LL_OK == hc32_qspi_write(qspi_bus, qspi_message))
- {
- if (qspi_message->parent.length != 0)
- {
- len = length;
- }
- else
- {
- len = 1;
- }
- }
- else
- {
- LOG_E("QSPI send data failed!");
- goto __exit;
- }
- }
- else if (message->recv_buf != NULL) /* recv data */
- {
- if (LL_OK != hc32_qspi_send_cmd(qspi_bus, qspi_message, QSPI_READ_FUNC))
- {
- LOG_E("QSPI rt_qspi_message format error!");
- goto __exit;
- }
- if (LL_OK == hc32_qspi_read(qspi_bus, qspi_message))
- {
- len = length;
- }
- else
- {
- LOG_E("QSPI recv data failed!");
- goto __exit;
- }
- }
- __exit:
- #ifdef BSP_QSPI_USING_SOFT_CS
- if (message->cs_release)
- {
- rt_pin_write(cs->pin, 1);
- }
- #endif
- return len;
- }
- static rt_err_t qspi_configure(struct rt_spi_device *device, struct rt_spi_configuration *configuration)
- {
- RT_ASSERT(device != RT_NULL);
- RT_ASSERT(configuration != RT_NULL);
- struct rt_qspi_device *qspi_device = (struct rt_qspi_device *)device;
- return hc32_qspi_init(qspi_device, &qspi_device->config);
- }
- static const struct rt_spi_ops hc32_qspi_ops =
- {
- .configure = qspi_configure,
- .xfer = qspixfer,
- };
- static int hc32_qspi_register_bus(struct hc32_qspi_bus *qspi_bus, const char *name)
- {
- RT_ASSERT(qspi_bus != RT_NULL);
- RT_ASSERT(name != RT_NULL);
- spi_bus_obj.parent.user_data = qspi_bus;
- return rt_qspi_bus_register(&spi_bus_obj, name, &hc32_qspi_ops);
- }
- static void qspi_err_irq_handler(void)
- {
- /* enter interrupt */
- rt_interrupt_enter();
- QSPI_ClearStatus(QSPI_FLAG_ROM_ACCESS_ERR);
- /* leave interrupt */
- rt_interrupt_leave();
- }
- #if defined (HC32F448) || defined (HC32F472)
- void QSPI_Handler(void)
- {
- qspi_err_irq_handler();
- }
- #endif
- /**
- * @brief This function attach device to QSPI bus.
- * @param bus_name QSPI bus name
- * @param device_name QSPI device name
- * @param pin QSPI cs pin number
- * @param data_line_width QSPI data lines width, such as 1, 2, 4
- * @param enter_qspi_mode Callback function that lets FLASH enter QSPI mode
- * @param exit_qspi_mode Callback function that lets FLASH exit QSPI mode
- * @retval 0 : success
- * -1 : failed
- */
- rt_err_t rt_hw_qspi_bus_attach_device(const char *bus_name, const char *device_name, rt_uint32_t pin, rt_uint8_t data_line_width, void (*enter_qspi_mode)(), void (*exit_qspi_mode)())
- {
- struct rt_qspi_device *qspi_device = RT_NULL;
- struct hc32_hw_qspi_cs *cs_pin = RT_NULL;
- rt_err_t result = RT_EOK;
- RT_ASSERT(bus_name != RT_NULL);
- RT_ASSERT(device_name != RT_NULL);
- RT_ASSERT(data_line_width == 1 || data_line_width == 2 || data_line_width == 4);
- qspi_device = (struct rt_qspi_device *)rt_malloc(sizeof(struct rt_qspi_device));
- if (qspi_device == RT_NULL)
- {
- LOG_E("no memory, qspi bus attach device failed!");
- result = RT_ENOMEM;
- goto __exit;
- }
- cs_pin = (struct hc32_hw_qspi_cs *)rt_malloc(sizeof(struct hc32_hw_qspi_cs));
- if (qspi_device == RT_NULL)
- {
- LOG_E("no memory, qspi bus attach device failed!");
- result = RT_ENOMEM;
- goto __exit;
- }
- qspi_device->enter_qspi_mode = enter_qspi_mode;
- qspi_device->exit_qspi_mode = exit_qspi_mode;
- qspi_device->config.qspi_dl_width = data_line_width;
- cs_pin->pin = pin;
- #ifdef BSP_QSPI_USING_SOFT_CS
- rt_pin_mode(pin, PIN_MODE_OUTPUT);
- rt_pin_write(pin, 1);
- #endif
- result = rt_spi_bus_attach_device(&qspi_device->parent, device_name, bus_name, (void *)cs_pin);
- __exit:
- if (result != RT_EOK)
- {
- if (qspi_device)
- {
- rt_free(qspi_device);
- }
- if (cs_pin)
- {
- rt_free(cs_pin);
- }
- }
- return result;
- }
- static void hc32_get_qspi_info(void)
- {
- static struct hc32_qspi_config qspi_config = QSPI_BUS_CONFIG;
- qspi_config.err_irq.irq_callback = qspi_err_irq_handler;
- #ifdef BSP_QSPI_USING_DMA
- static struct dma_config qspi_dma = QSPI_DMA_CONFIG;
- qspi_config.dma_qspi = &qspi_dma;
- #if defined (HC32F448) || defined (HC32F4A8)
- qspi_config.dma_tx_buf_size = QSPI_DMA_TX_BUFSIZE;
- qspi_config.dma_tx_buf = rt_malloc(qspi_config.dma_tx_buf_size << 1);
- #endif
- #endif
- qspi_bus_obj.config = &qspi_config;
- }
- static int rt_hw_qspi_bus_init(void)
- {
- hc32_get_qspi_info();
- /* register the handle */
- hc32_install_irq_handler(&qspi_bus_obj.config->err_irq.irq_config, qspi_bus_obj.config->err_irq.irq_callback, RT_FALSE);
- return hc32_qspi_register_bus(&qspi_bus_obj, "qspi1");
- }
- INIT_BOARD_EXPORT(rt_hw_qspi_bus_init);
- #endif /* BSP_USING_QSPI */
- #endif /* RT_USING_QSPI */
|