| 1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066 |
- /*
- * Copyright (C) 2022-2024, Xiaohua Semiconductor Co., Ltd.
- *
- * SPDX-License-Identifier: Apache-2.0
- *
- * Change Logs:
- * Date Author Notes
- * 2023-02-14 CDT first version
- */
- /*******************************************************************************
- * Include files
- ******************************************************************************/
- #include <rtthread.h>
- #include <rtdevice.h>
- #if defined(RT_USING_SDIO)
- #if defined(BSP_USING_SDIO1) || defined(BSP_USING_SDIO2)
- #include "drv_sdio.h"
- #include "board_config.h"
- /*******************************************************************************
- * Local type definitions ('typedef')
- ******************************************************************************/
- /* rthw sdio */
- struct rthw_sdio
- {
- struct rt_mmcsd_host *host;
- struct hc32_sdio_config *config;
- struct hc32_sdio_des des;
- struct rt_event event;
- struct rt_mutex mutex;
- struct sdio_pkg *pkg;
- uint8_t *cache_buf;
- };
- /*******************************************************************************
- * Local pre-processor symbols/macros ('#define')
- ******************************************************************************/
- //#define DRV_DEBUG
- #define LOG_TAG "drv.sdio"
- #include <drv_log.h>
- #ifndef SDIO_BUFF_SIZE
- #define SDIO_BUFF_SIZE (4096)
- #endif
- #ifndef SDIO_ALIGN_LEN
- #define SDIO_ALIGN_LEN (4)
- #endif
- #ifndef SDIO_MAX_FREQ
- #define SDIO_MAX_FREQ (50*1000*1000)
- #endif
- #define RTHW_SDIO_LOCK(_sdio) rt_mutex_take(&(_sdio)->mutex, RT_WAITING_FOREVER)
- #define RTHW_SDIO_UNLOCK(_sdio) rt_mutex_release(&(_sdio)->mutex);
- /*******************************************************************************
- * Global variable definitions (declared in header file with 'extern')
- ******************************************************************************/
- extern rt_err_t rt_hw_board_sdio_init(CM_SDIOC_TypeDef *SDIOCx);
- /*******************************************************************************
- * Local function prototypes ('static')
- ******************************************************************************/
- #ifdef BSP_USING_SDIO1
- static void _sdio1_handler(void);
- #endif
- #ifdef BSP_USING_SDIO2
- static void _sdio2_handler(void);
- #endif
- /*******************************************************************************
- * Local variable definitions ('static')
- ******************************************************************************/
- enum
- {
- #ifdef BSP_USING_SDIO1
- SDIO1_INDEX,
- #endif
- #ifdef BSP_USING_SDIO2
- SDIO2_INDEX,
- #endif
- };
- static struct hc32_sdio_config _sdio_config[] =
- {
- #ifdef BSP_USING_SDIO1
- SDIO1_BUS_CONFIG,
- #endif /* BSP_USING_SDIO1 */
- #ifdef BSP_USING_SDIO2
- SDIO2_BUS_CONFIG,
- #endif /* BSP_USING_SDIO2 */
- };
- static const func_ptr_t _sdio_irq_handler[] =
- {
- #ifdef BSP_USING_SDIO1
- _sdio1_handler,
- #endif /* BSP_USING_SDIO1 */
- #ifdef BSP_USING_SDIO2
- _sdio2_handler,
- #endif /* BSP_USING_SDIO2 */
- };
- #ifdef BSP_USING_SDIO1
- rt_align(SDIO_ALIGN_LEN)
- static rt_uint8_t _sdio1_cache_buf[SDIO_BUFF_SIZE];
- #endif
- #ifdef BSP_USING_SDIO2
- rt_align(SDIO_ALIGN_LEN)
- static rt_uint8_t _sdio2_cache_buf[SDIO_BUFF_SIZE];
- #endif
- static rt_uint8_t *const _sdio_cache_buf[] =
- {
- #ifdef BSP_USING_SDIO1
- _sdio1_cache_buf,
- #endif /* BSP_USING_SDIO1 */
- #ifdef BSP_USING_SDIO2
- _sdio2_cache_buf,
- #endif /* BSP_USING_SDIO2 */
- };
- static struct rt_mmcsd_host *_sdio_host[sizeof(_sdio_config) / sizeof(_sdio_config[0])] = {0};
- /*******************************************************************************
- * Function implementation - global ('extern') and local ('static')
- ******************************************************************************/
- /**
- * @brief Get the response type of hc32 sdioc driver.
- * @param [in] rt_resp_type SDIO command response type defined in mmcs_core.h
- * @retval The response type of hc32 sdioc driver
- */
- static rt_uint32_t _sdio_get_cmd_resptype(rt_uint32_t rt_resptype)
- {
- rt_uint32_t sdioc_resptype;
- switch (rt_resptype)
- {
- case RESP_NONE:
- sdioc_resptype = SDIOC_RESP_TYPE_NO;
- break;
- case RESP_R1:
- sdioc_resptype = SDIOC_RESP_TYPE_R1_R5_R6_R7;
- break;
- case RESP_R2:
- sdioc_resptype = SDIOC_RESP_TYPE_R2;
- break;
- case RESP_R3:
- case RESP_R4:
- sdioc_resptype = SDIOC_RESP_TYPE_R3_R4;
- break;
- case RESP_R5:
- case RESP_R6:
- case RESP_R7:
- sdioc_resptype = SDIOC_RESP_TYPE_R1_R5_R6_R7;
- break;
- case RESP_R1B:
- sdioc_resptype = SDIOC_RESP_TYPE_R1B_R5B;
- break;
- default:
- sdioc_resptype = SDIOC_RESP_TYPE_NO;
- LOG_E("unknown response type: %d", rt_resptype);
- break;
- }
- return sdioc_resptype;
- }
- /**
- * @brief This function wait sdio completed.
- * @param [in] sdio Pointer to a @ref rthw_sdio structure
- * @retval None
- */
- static void _sdio_wait_completed(struct rthw_sdio *sdio)
- {
- rt_uint32_t status;
- rt_uint32_t response[4];
- __IO rt_uint32_t to_count;
- struct rt_mmcsd_cmd *cmd = sdio->pkg->cmd;
- struct rt_mmcsd_data *data = cmd->data;
- CM_SDIOC_TypeDef *instance = sdio->config->instance;
- if (rt_event_recv(&sdio->event, 0xFFFFFFFF, RT_EVENT_FLAG_OR | RT_EVENT_FLAG_CLEAR,
- rt_tick_from_millisecond(5000), &status) != RT_EOK)
- {
- LOG_E("[%s timeout] sta=0x%08X, cmd %d, arg:0x%08X", __func__, status, cmd->cmd_code, cmd->arg);
- cmd->err = -RT_ETIMEOUT;
- return;
- }
- if (sdio->pkg == RT_NULL)
- {
- return;
- }
- if (resp_type(cmd) == RESP_NONE)
- {
- ;
- }
- else if (resp_type(cmd) == RESP_R2)
- {
- LOG_D("R2");
- (void)SDIOC_GetResponse(instance, SDIOC_RESP_REG_BIT0_31, &response[0]);
- (void)SDIOC_GetResponse(instance, SDIOC_RESP_REG_BIT32_63, &response[1]);
- (void)SDIOC_GetResponse(instance, SDIOC_RESP_REG_BIT64_95, &response[2]);
- (void)SDIOC_GetResponse(instance, SDIOC_RESP_REG_BIT96_127, &response[3]);
- cmd->resp[0] = (response[3] << 8) + ((response[2] >> 24) & 0xFF);
- cmd->resp[1] = (response[2] << 8) + ((response[1] >> 24) & 0xFF);
- cmd->resp[2] = (response[1] << 8) + ((response[0] >> 24) & 0xFF);
- cmd->resp[3] = (response[0] << 8) + 0x00;
- }
- else
- {
- (void)SDIOC_GetResponse(instance, SDIOC_RESP_REG_BIT0_31, &response[0]);
- cmd->resp[0] = response[0];
- }
- if (status & SDIOC_INT_FLAG_EI)
- {
- if (status & (SDIOC_INT_FLAG_CTOE | SDIOC_INT_FLAG_CCE | SDIOC_INT_FLAG_CEBE | SDIOC_INT_FLAG_CIE))
- {
- SDIOC_SWReset(instance, SDIOC_SW_RST_CMD_LINE);
- cmd->err = -RT_ERROR;
- LOG_D("[%s cmd err] sta=0x%08X, %s%s%s%s cmd %d arg:0x%08X",
- __func__,
- status,
- status & SDIOC_INT_FLAG_CCE ? "Command CRC Error " : "",
- status & SDIOC_INT_FLAG_CEBE ? "Command End Bit Error" : "",
- status & SDIOC_INT_FLAG_CTOE ? "Command Timeout Error" : "",
- status == 0 ? "NULL" : "",
- cmd->cmd_code,
- cmd->arg);
- }
- if (status & (SDIOC_INT_FLAG_DTOE | SDIOC_INT_FLAG_DCE | SDIOC_INT_FLAG_DEBE))
- {
- SDIOC_SWReset(instance, SDIOC_SW_RST_DATA_LINE);
- if (data != NULL)
- {
- data->err = -RT_ERROR;
- LOG_D("[%s dat err] sta=0x%08X, %s%s%s%s cmd %d arg:0x%08X rw:%c len:%d blksize:%d",
- __func__,
- status,
- status & SDIOC_INT_FLAG_DCE ? "Data CRC Error " : "",
- status & SDIOC_INT_FLAG_DEBE ? "Data End Bit Error" : "",
- status & SDIOC_INT_FLAG_DTOE ? "Data Timeout Error" : "",
- status == 0 ? "NULL" : "",
- cmd->cmd_code,
- cmd->arg,
- data ? (data->flags & DATA_DIR_WRITE ? 'w' : 'r') : '-',
- data ? data->blks * data->blksize : 0,
- data ? data->blksize : 0);
- }
- }
- }
- else
- {
- cmd->err = RT_EOK;
- LOG_D("[%s xfer ok] sta=0x%08X, cmd %d, arg:0x%08X, resp[%08X %08X %08X %08X]",
- __func__,
- status,
- cmd->cmd_code,
- cmd->arg,
- cmd->resp[0], cmd->resp[1], cmd->resp[2], cmd->resp[3]);
- }
- }
- /**
- * @brief Transfer data by dma.
- * @param [in] sdio Pointer to a @ref rthw_sdio structure
- * @param [in] pkg Pointer to a @ref sdio_pkg structure
- * @retval None
- */
- static void _sdio_transfer_by_dma(struct rthw_sdio *sdio, struct sdio_pkg *pkg)
- {
- struct rt_mmcsd_data *data = pkg->cmd->data;
- if ((NULL == sdio) || (NULL == pkg) || (NULL == pkg->buf) || (NULL == pkg->cmd) || (NULL == pkg->cmd->data))
- {
- LOG_E("%s function arguments error: %s %s %s %s %s",
- __func__,
- (sdio == RT_NULL ? "sdio is NULL" : ""),
- (pkg == RT_NULL ? "pkg is NULL" : ""),
- (sdio ? (pkg->buf == RT_NULL ? "pkg->buf is NULL" : "") : ""),
- (sdio ? (pkg->cmd == RT_NULL ? "pkg->cmd is NULL" : "") : ""),
- (sdio ? (pkg->cmd->data == RT_NULL ? "pkg->cmd->data is NULL" : "") : "")
- );
- return;
- }
- if (data->flags & DATA_DIR_WRITE)
- {
- sdio->des.txconfig(sdio->config->dma_tx.Instance, sdio->config->dma_tx.channel, pkg);
- DMA_ChCmd(sdio->config->dma_tx.Instance, sdio->config->dma_tx.channel, ENABLE);
- }
- else if (data->flags & DATA_DIR_READ)
- {
- sdio->des.rxconfig(sdio->config->dma_rx.Instance, sdio->config->dma_rx.channel, pkg);
- DMA_ChCmd(sdio->config->dma_rx.Instance, sdio->config->dma_rx.channel, ENABLE);
- }
- }
- /**
- * @brief Send command.
- * @param [in] sdio Pointer to a @ref rthw_sdio structure
- * @param [in] pkg Pointer to a @ref sdio_pkg structure
- * @retval None
- */
- static void _sdio_send_command(struct rthw_sdio *sdio, struct sdio_pkg *pkg)
- {
- rt_int32_t ret;
- struct rt_mmcsd_cmd *cmd = pkg->cmd;
- struct rt_mmcsd_data *data = cmd->data;
- CM_SDIOC_TypeDef *instance = sdio->config->instance;
- stc_sdioc_cmd_config_t stcCmdConfig;
- stc_sdioc_data_config_t stcDataConfig;
- /* save pkg */
- sdio->pkg = pkg;
- LOG_D("CMD:%d ARG:0x%08x RES:%s%s%s%s%s%s%s%s%s rw:%c len:%d blksize:%d",
- cmd->cmd_code,
- cmd->arg,
- resp_type(cmd) == RESP_NONE ? "NONE" : "",
- resp_type(cmd) == RESP_R1 ? "R1" : "",
- resp_type(cmd) == RESP_R1B ? "R1B" : "",
- resp_type(cmd) == RESP_R2 ? "R2" : "",
- resp_type(cmd) == RESP_R3 ? "R3" : "",
- resp_type(cmd) == RESP_R4 ? "R4" : "",
- resp_type(cmd) == RESP_R5 ? "R5" : "",
- resp_type(cmd) == RESP_R6 ? "R6" : "",
- resp_type(cmd) == RESP_R7 ? "R7" : "",
- data ? (data->flags & DATA_DIR_WRITE ? 'w' : 'r') : '-',
- data ? data->blks * data->blksize : 0,
- data ? data->blksize : 0);
- /* config command */
- stcCmdConfig.u16CmdIndex = cmd->cmd_code;
- /* config command argument */
- stcCmdConfig.u32Argument = cmd->arg;
- /* config command type */
- stcCmdConfig.u16CmdType = SDIOC_CMD_TYPE_NORMAL;
- /* config response type */
- stcCmdConfig.u16ResponseType = _sdio_get_cmd_resptype(resp_type(cmd));
- if (data != RT_NULL)
- {
- /* config data */
- stcDataConfig.u16BlockSize = data->blksize;
- stcDataConfig.u16BlockCount = data->blks;
- stcDataConfig.u16TransDir = (data->flags & DATA_DIR_READ) ? SDIOC_TRANS_DIR_TO_HOST : SDIOC_TRANS_DIR_TO_CARD;
- stcDataConfig.u16AutoCmd12 = SDIOC_AUTO_SEND_CMD12_DISABLE;
- stcDataConfig.u16DataTimeout = SDIOC_DATA_TIMEOUT_CLK_2E27;
- stcDataConfig.u16TransMode = (data->blks > 1U) ? SDIOC_TRANS_MD_MULTI : SDIOC_TRANS_MD_SINGLE;
- ret = SDIOC_ConfigData(instance, &stcDataConfig);
- if (ret != 0)
- {
- LOG_E("configure data error : %d", ret);
- }
- /* transfer config */
- _sdio_transfer_by_dma(sdio, pkg);
- stcCmdConfig.u16DataLine = SDIOC_DATA_LINE_ENABLE;;
- }
- else
- {
- stcCmdConfig.u16DataLine = SDIOC_DATA_LINE_DISABLE;
- }
- /* send cmd */
- ret = SDIOC_SendCommand(instance, &stcCmdConfig);
- if (ret != 0)
- {
- LOG_E("send command error : %d", ret);
- }
- /* wait completed */
- _sdio_wait_completed(sdio);
- /* clear pkg */
- sdio->pkg = RT_NULL;
- }
- /**
- * @brief Send sdio request.
- * @param [in] host Pointer to a @ref rt_mmcsd_host structure
- * @param [in] req Pointer to a @ref rt_mmcsd_req structure
- * @retval None
- */
- static void _sdio_request(struct rt_mmcsd_host *host, struct rt_mmcsd_req *req)
- {
- rt_uint32_t mask;
- struct sdio_pkg pkg;
- struct rt_mmcsd_data *data;
- struct rthw_sdio *sdio = host->private_data;
- if ((NULL == host) || (NULL == req) || (NULL == sdio) || (NULL == sdio->config))
- {
- LOG_E("%s function arguments error: %s %s %s %s",
- __func__,
- (host == RT_NULL ? "host is NULL" : ""),
- (req == RT_NULL ? "req is NULL" : ""),
- (sdio == RT_NULL ? "sdio is NULL" : ""),
- (sdio ? (sdio->config == RT_NULL ? "sdio->config is NULL" : "") : "")
- );
- return;
- }
- RTHW_SDIO_LOCK(sdio);
- if (req->cmd != RT_NULL)
- {
- rt_memset(&pkg, 0, sizeof(pkg));
- data = req->cmd->data;
- pkg.cmd = req->cmd;
- if (SD_SEND_IF_COND == pkg.cmd->cmd_code)
- {
- mask = (CM_SDIOC1 == sdio->config->instance) ? PERIC_SDIOC_SYCTLREG_SELMMC1 : PERIC_SDIOC_SYCTLREG_SELMMC2;
- if (data == RT_NULL)
- {
- CM_PERIC->SDIOC_SYCTLREG &= ~mask;
- }
- else
- {
- CM_PERIC->SDIOC_SYCTLREG |= mask;
- }
- }
- if (data != RT_NULL)
- {
- rt_uint32_t size = data->blks * data->blksize;
- RT_ASSERT(size <= SDIO_BUFF_SIZE);
- /* buffer unaligned */
- if ((rt_uint32_t)data->buf & (SDIO_ALIGN_LEN - 1))
- {
- if (data->flags & DATA_DIR_WRITE)
- {
- rt_memcpy(sdio->cache_buf, data->buf, size);
- }
- pkg.buf = sdio->cache_buf;
- }
- else
- {
- pkg.buf = data->buf;
- }
- }
- _sdio_send_command(sdio, &pkg);
- if ((data != RT_NULL) && (data->flags & DATA_DIR_READ) && ((rt_uint32_t)data->buf & (SDIO_ALIGN_LEN - 1)))
- {
- rt_memcpy(data->buf, sdio->cache_buf, data->blksize * data->blks);
- }
- }
- if (req->stop != RT_NULL)
- {
- rt_memset(&pkg, 0, sizeof(pkg));
- pkg.cmd = req->stop;
- _sdio_send_command(sdio, &pkg);
- }
- RTHW_SDIO_UNLOCK(sdio);
- mmcsd_req_complete(sdio->host);
- }
- /**
- * @brief Config sdio.
- * @param [in] host Pointer to a @ref rt_mmcsd_host structure
- * @param [in] io_cfg Pointer to a @ref rt_mmcsd_io_cfg structure
- * @retval None
- */
- static void _sdio_iocfg(struct rt_mmcsd_host *host, struct rt_mmcsd_io_cfg *io_cfg)
- {
- rt_int32_t ret;
- rt_uint32_t clk;
- rt_uint16_t clk_div;
- rt_uint32_t clk_src;
- struct rthw_sdio *sdio = host->private_data;
- CM_SDIOC_TypeDef *instance;
- if ((NULL == host) || (NULL == io_cfg) || (NULL == sdio) || (NULL == sdio->config))
- {
- LOG_E("%s function arguments error: %s %s %s %s",
- __func__,
- (host == RT_NULL ? "host is NULL" : ""),
- (io_cfg == RT_NULL ? "io_cfg is NULL" : ""),
- (sdio == RT_NULL ? "sdio_des is NULL" : ""),
- (sdio ? (sdio->config == RT_NULL ? "sdio->config is NULL" : "") : "")
- );
- return;
- }
- instance = sdio->config->instance;
- clk_src = sdio->des.clk_get(instance);
- if (clk_src < 400 * 1000)
- {
- LOG_E("clock rate is too low! rate:%d", clk_src);
- return;
- }
- clk = io_cfg->clock;
- if (clk > host->freq_max)
- {
- clk = host->freq_max;
- }
- if (clk > clk_src)
- {
- LOG_W("setting rate is greater than clock source rate.");
- clk = clk_src;
- }
- LOG_D("clk:%d width:%s%s%s power:%s%s%s",
- clk,
- io_cfg->bus_width == MMCSD_BUS_WIDTH_8 ? "8" : "",
- io_cfg->bus_width == MMCSD_BUS_WIDTH_4 ? "4" : "",
- io_cfg->bus_width == MMCSD_BUS_WIDTH_1 ? "1" : "",
- io_cfg->power_mode == MMCSD_POWER_OFF ? "OFF" : "",
- io_cfg->power_mode == MMCSD_POWER_UP ? "UP" : "",
- io_cfg->power_mode == MMCSD_POWER_ON ? "ON" : "");
- RTHW_SDIO_LOCK(sdio);
- switch (io_cfg->bus_width)
- {
- case MMCSD_BUS_WIDTH_1:
- SDIOC_SetBusWidth(instance, SDIOC_BUS_WIDTH_1BIT);
- break;
- case MMCSD_BUS_WIDTH_4:
- SDIOC_SetBusWidth(instance, SDIOC_BUS_WIDTH_4BIT);
- break;
- case MMCSD_BUS_WIDTH_8:
- SDIOC_SetBusWidth(instance, SDIOC_BUS_WIDTH_8BIT);
- break;
- default:
- LOG_E("unknown bus width: %d", io_cfg->bus_width);
- break;
- }
- switch (io_cfg->power_mode)
- {
- case MMCSD_POWER_OFF:
- SDIOC_PowerCmd(instance, DISABLE);
- break;
- case MMCSD_POWER_UP:
- case MMCSD_POWER_ON:
- SDIOC_PowerCmd(instance, ENABLE);
- break;
- default:
- LOG_W("unknown power_mode %d", io_cfg->power_mode);
- break;
- }
- instance->CLKCON = 0;
- if (clk > 0)
- {
- ret = SDIOC_GetOptimumClockDiv(clk, &clk_div);
- if (ret != LL_OK)
- {
- LOG_E("clock division error");
- }
- else
- {
- SDIOC_SetClockDiv(instance, clk_div);
- if ((clk << 1) <= host->freq_max)
- {
- SDIOC_SetSpeedMode(instance, SDIOC_SPEED_MD_NORMAL);
- }
- else
- {
- SDIOC_SetSpeedMode(instance, SDIOC_SPEED_MD_HIGH);
- }
- instance->CLKCON = (clk_div | SDIOC_CLKCON_ICE | SDIOC_CLKCON_CE);
- }
- }
- RTHW_SDIO_UNLOCK(sdio);
- }
- /**
- * @brief Update the sdio interrupt.
- * @param [in] host Pointer to a @ref rt_mmcsd_host structure
- * @param [in] enable Enable interrupt when value is non-zero
- * @retval None
- */
- static void _sdio_enable_sdio_irq(struct rt_mmcsd_host *host, rt_int32_t enable)
- {
- struct rthw_sdio *sdio = host->private_data;
- CM_SDIOC_TypeDef *instance = sdio->config->instance;
- if (enable)
- {
- LOG_D("enable sdio interrupt");
- SDIOC_IntStatusCmd(instance, SDIOC_INT_CINTSEN, ENABLE);
- SDIOC_IntCmd(instance, SDIOC_INT_CINTSEN, ENABLE);
- }
- else
- {
- LOG_D("disable sdio interrupt");
- SDIOC_IntStatusCmd(instance, SDIOC_INT_CINTSEN, DISABLE);
- SDIOC_IntCmd(instance, SDIOC_INT_CINTSEN, DISABLE);
- }
- }
- /**
- * @brief update all of the using interrupt.
- * @param [in] host Pointer to a @ref rt_mmcsd_host structure
- * @param [in] enable Enable interrupt when value is non-zero
- * @retval None
- */
- static void _sdio_update_irq(struct rt_mmcsd_host *host, rt_int32_t enable)
- {
- struct rthw_sdio *sdio = host->private_data;
- CM_SDIOC_TypeDef *instance = sdio->config->instance;
- const rt_uint32_t int_type = (SDIOC_INT_CCSEN | SDIOC_INT_TCSEN | SDIOC_ERR_INT_ALL);
- if (enable)
- {
- LOG_D("enable all of the using interrupt");
- SDIOC_IntStatusCmd(instance, (int_type | SDIOC_INT_BRRSEN | SDIOC_INT_BWRSEN), ENABLE);
- SDIOC_IntCmd(instance, int_type, ENABLE);
- }
- else
- {
- LOG_D("disable all of the using interrupt");
- SDIOC_IntStatusCmd(instance, (int_type | SDIOC_INT_BRRSEN | SDIOC_INT_BWRSEN), DISABLE);
- SDIOC_IntCmd(instance, int_type, DISABLE);
- }
- }
- /**
- * @brief Get card status.
- * @param [in] host Pointer to a @ref rt_mmcsd_host structure
- * @retval rt_int32_t:
- * - 0: No card
- * - 1: Card inserted
- */
- static rt_int32_t _sdio_get_card_status(struct rt_mmcsd_host *host)
- {
- struct rthw_sdio *sdio = host->private_data;
- LOG_D("try to detect device");
- return (rt_int32_t)SDIOC_GetHostStatus(sdio->config->instance, SDIOC_HOST_FLAG_CIN);
- }
- static const struct rt_mmcsd_host_ops _mmcsd_host_ops =
- {
- _sdio_request,
- _sdio_iocfg,
- _sdio_get_card_status,
- _sdio_enable_sdio_irq,
- };
- /**
- * @brief Get SDIO clock source frequency.
- * @param [in] SDIOCx Pointer to SDIOC unit instance
- * @retval SDIO clock source frequency
- */
- static rt_uint32_t _sdio_clock_get(CM_SDIOC_TypeDef *SDIOCx)
- {
- rt_uint32_t clk;
- (void)SDIOCx;
- #if defined (HC32F4A0) || defined (HC32F4A8)
- clk = CLK_GetBusClockFreq(CLK_BUS_PCLK1);
- #elif defined (HC32F460)
- clk = CLK_GetBusClockFreq(CLK_BUS_EXCLK);
- #endif
- return clk;
- }
- /**
- * @brief Initialize DMA for SDIO.
- * @param [in] config Pointer to hc32_sdio_config structure
- * @retval None
- */
- static void _sdio_dma_init(struct hc32_sdio_config *config)
- {
- stc_dma_init_t stcDmaInit;
- /* Enable DMA and AOS clock */
- FCG_Fcg0PeriphClockCmd(FCG0_PERIPH_AOS, ENABLE);
- FCG_Fcg0PeriphClockCmd(config->dma_rx.clock, ENABLE);
- FCG_Fcg0PeriphClockCmd(config->dma_tx.clock, ENABLE);
- /* Initialize DMA config structure */
- (void)DMA_StructInit(&stcDmaInit);
- stcDmaInit.u32BlockSize = 512UL;
- stcDmaInit.u32DataWidth = DMA_DATAWIDTH_32BIT;
- /* Configure DMA_RX Transfer */
- stcDmaInit.u32SrcAddr = (uint32_t)(&config->instance->BUF0);
- stcDmaInit.u32DestAddr = 0UL;
- stcDmaInit.u32SrcAddrInc = DMA_SRC_ADDR_FIX;
- stcDmaInit.u32DestAddrInc = DMA_DEST_ADDR_INC;
- if (LL_OK != DMA_Init(config->dma_rx.Instance, config->dma_rx.channel, &stcDmaInit))
- {
- LOG_E("DMA_RX initialization fail");
- }
- AOS_SetTriggerEventSrc(config->dma_rx.trigger_select, config->dma_rx.trigger_event);
- /* Configure DMA_TX Transfer */
- stcDmaInit.u32SrcAddr = 0UL;
- stcDmaInit.u32DestAddr = (uint32_t)(&config->instance->BUF0);
- stcDmaInit.u32SrcAddrInc = DMA_SRC_ADDR_INC;
- stcDmaInit.u32DestAddrInc = DMA_DEST_ADDR_FIX;
- if (LL_OK != DMA_Init(config->dma_tx.Instance, config->dma_tx.channel, &stcDmaInit))
- {
- LOG_E("DMA_TX initialization fail");
- }
- AOS_SetTriggerEventSrc(config->dma_tx.trigger_select, config->dma_tx.trigger_event);
- /* Enable DMA */
- DMA_Cmd(config->dma_rx.Instance, ENABLE);
- DMA_Cmd(config->dma_tx.Instance, ENABLE);
- }
- /**
- * @brief Configure DMA for SDIO receiving.
- * @param [in] instance Pointer to DMA instance register base
- * @param [in] ch DMA channel
- * @param [in] pkg Pointer to sdio_pkg structure
- * @retval RT_EOK
- */
- static rt_err_t _sdio_dma_rxconfig(CM_DMA_TypeDef *instance, rt_uint8_t ch, struct sdio_pkg *pkg)
- {
- struct rt_mmcsd_cmd *cmd = pkg->cmd;
- struct rt_mmcsd_data *data = cmd->data;
- DMA_ClearTransCompleteStatus(instance, (DMA_INTSTAT1_BTC_0 | DMA_INTSTAT1_TC_0) << ch);
- DMA_SetDestAddr(instance, ch, (rt_uint32_t)pkg->buf);
- DMA_SetBlockSize(instance, ch, (rt_uint16_t)(data->blksize >> 2));
- DMA_SetTransCount(instance, ch, (rt_uint16_t)data->blks);
- return RT_EOK;
- }
- /**
- * @brief Configure DMA for SDIO transmitting.
- * @param [in] instance Pointer to DMA instance register base
- * @param [in] ch DMA channel
- * @param [in] pkg Pointer to sdio_pkg structure
- * @retval RT_EOK
- */
- static rt_err_t _sdio_dma_txconfig(CM_DMA_TypeDef *instance, rt_uint8_t ch, struct sdio_pkg *pkg)
- {
- struct rt_mmcsd_cmd *cmd = pkg->cmd;
- struct rt_mmcsd_data *data = cmd->data;
- DMA_ClearTransCompleteStatus(instance, (DMA_INTSTAT1_BTC_0 | DMA_INTSTAT1_TC_0) << ch);
- DMA_SetSrcAddr(instance, ch, (rt_uint32_t)pkg->buf);
- DMA_SetBlockSize(instance, ch, (rt_uint16_t)(data->blksize >> 2));
- DMA_SetTransCount(instance, ch, (rt_uint16_t)data->blks);
- return RT_EOK;
- }
- /**
- * @brief This function interrupt process function.
- * @param [in] host Pointer to rt_mmcsd_host structure
- * @retval None
- */
- static void _sdio_irq_process(struct rt_mmcsd_host *host)
- {
- int complete = 0;
- struct rthw_sdio *sdio = host->private_data;
- CM_SDIOC_TypeDef *instance = sdio->config->instance;
- rt_uint32_t norint_status = (rt_uint32_t)instance->NORINTST;
- rt_uint32_t errint_status = (rt_uint32_t)instance->ERRINTST;
- rt_uint32_t status = (errint_status << 16) | norint_status;
- LOG_D("[%s] sta=0x%08X, cmd %d, arg=0x%08X", __func__, status, sdio->pkg->cmd->cmd_code, sdio->pkg->cmd->arg);
- if (norint_status & (SDIOC_INT_FLAG_CRM | SDIOC_INT_FLAG_CIST))
- {
- SDIOC_ClearIntStatus(instance, SDIOC_INT_FLAG_CLR_ALL);
- /* ready to change */
- mmcsd_change(host);
- LOG_D("[%s] card insert or remove", __func__);
- complete = 1;
- }
- else
- {
- if (norint_status & SDIOC_INT_FLAG_EI)
- {
- SDIOC_ClearIntStatus(instance, SDIOC_INT_FLAG_CLR_ALL);
- complete = 1;
- LOG_D("[%s] error", __func__);
- }
- else
- {
- if (norint_status & SDIOC_INT_FLAG_CC)
- {
- SDIOC_ClearIntStatus(instance, SDIOC_INT_FLAG_CC);
- if (sdio->pkg != RT_NULL)
- {
- if ((!sdio->pkg->cmd->data) && (resp_type(sdio->pkg->cmd) != RESP_R1B))
- {
- complete = 1;
- }
- }
- }
- if (norint_status & SDIOC_INT_FLAG_TC)
- {
- SDIOC_ClearIntStatus(instance, SDIOC_INT_FLAG_TC);
- complete = 1;
- }
- }
- }
- if (norint_status & SDIOC_INT_FLAG_CINT)
- {
- SDIOC_ClearIntStatus(instance, SDIOC_INT_FLAG_CINT);
- sdio_irq_wakeup(host);
- }
- if (complete)
- {
- rt_event_send(&sdio->event, status);
- LOG_D("[%s] complete", __func__);
- }
- }
- #ifdef BSP_USING_SDIO1
- /**
- * @brief SDIOC1 irq handler.
- * @param None
- * @retval None
- */
- static void _sdio1_handler(void)
- {
- /* enter interrupt */
- rt_interrupt_enter();
- /* process all SDIO interrupt sources */
- _sdio_irq_process(_sdio_host[0]);
- /* leave interrupt */
- rt_interrupt_leave();
- }
- #endif
- #ifdef BSP_USING_SDIO2
- /**
- * @brief SDIOC2 irq handler.
- * @param None
- * @retval None
- */
- static void _sdio2_handler(void)
- {
- /* enter interrupt */
- rt_interrupt_enter();
- /* process all SDIO interrupt sources */
- _sdio_irq_process(_sdio_host[1]);
- /* leave interrupt */
- rt_interrupt_leave();
- }
- #endif
- /**
- * @brief verify bus clock frequency.
- * @param [in] config Pointer to hc32_sdio_config structure
- * @retval RT_EOK pass to verify
- * -RT_ERROR fail to verify
- */
- static rt_err_t _sdio_verify_bus_clock_frequency(struct hc32_sdio_config *config)
- {
- rt_err_t ret = RT_EOK;
- #if defined (HC32F4A0)
- rt_uint32_t pclk1;
- rt_uint32_t exlck;
- (void)config;
- /* ensure bus frequency condition: EXCLK >= PCLK1 */
- pclk1 = CLK_GetBusClockFreq(CLK_BUS_PCLK1);
- exlck = CLK_GetBusClockFreq(CLK_BUS_EXCLK);
- if (exlck < pclk1)
- {
- LOG_E("bus frequency error: EXCLK < PCLK1. Please meet the bus frequency condition: EXCLK >= PCLK1");
- ret = -RT_ERROR;
- }
- #endif
- return ret;
- }
- /**
- * @brief Enable SDIO clock.
- * @param [in] config Pointer to hc32_sdio_config structure
- * @retval RT_EOK pass to enable SDIO clock
- * -RT_ERROR fail to enable SDIO clock
- */
- static rt_err_t _sdio_clock_enable(struct hc32_sdio_config *config)
- {
- /* verify bus clock frequency */
- if (_sdio_verify_bus_clock_frequency(config) != RT_EOK)
- {
- LOG_E("[%s] fail to verify bus clock frequency", __func__);
- return -RT_ERROR;
- }
- FCG_Fcg1PeriphClockCmd(config->clock, ENABLE);
- return RT_EOK;
- }
- /**
- * @brief Create mmcsd host.
- * @param [in] config Pointer to a @ref hc32_sdio_config structure
- * @param [in] cache_buf Pointer to cache buffer
- * @param [in] sdio_des Pointer to a @ref hc32_sdio_des structure
- * @retval rt_mmcsd_host
- */
- static struct rt_mmcsd_host *_sdio_host_create(struct hc32_sdio_config *config,
- uint8_t *cache_buf,
- const struct hc32_sdio_des *sdio_des)
- {
- struct rt_mmcsd_host *host;
- struct rthw_sdio *sdio = RT_NULL;
- if ((config == RT_NULL) || (cache_buf == RT_NULL) || \
- (sdio_des == RT_NULL) || (sdio_des->txconfig == RT_NULL) || (sdio_des->rxconfig == RT_NULL))
- {
- LOG_E("function arguments error: %s %s %s %s %s",
- (config == RT_NULL ? "config is NULL" : ""),
- (cache_buf == RT_NULL ? "cache_buf is NULL" : ""),
- (sdio_des == RT_NULL ? "sdio_des is NULL" : ""),
- (sdio_des ? (sdio_des->txconfig ? "txconfig is NULL" : "") : ""),
- (sdio_des ? (sdio_des->rxconfig ? "rxconfig is NULL" : "") : "")
- );
- return RT_NULL;
- }
- /* malloc rthw_sdio */
- sdio = rt_malloc(sizeof(struct rthw_sdio));
- if (sdio == RT_NULL)
- {
- LOG_E("malloc rthw_sdio fail");
- return RT_NULL;
- }
- rt_memset(sdio, 0, sizeof(struct rthw_sdio));
- /* malloc mmcsd_alloc_host */
- host = mmcsd_alloc_host();
- if (host == RT_NULL)
- {
- LOG_E("mmcsd_alloc_host fail");
- rt_free(sdio);
- return RT_NULL;
- }
- rt_memcpy(&sdio->des, sdio_des, sizeof(struct hc32_sdio_des));
- rt_event_init(&sdio->event, "sdio", RT_IPC_FLAG_FIFO);
- rt_mutex_init(&sdio->mutex, "sdio", RT_IPC_FLAG_FIFO);
- /* set host default attributes */
- host->ops = &_mmcsd_host_ops;
- host->freq_min = 400 * 1000;
- host->freq_max = SDIO_MAX_FREQ;
- host->valid_ocr = VDD_32_33 | VDD_33_34;
- #ifndef SDIO_USING_1_BIT
- host->flags = MMCSD_BUSWIDTH_4 | MMCSD_MUTBLKWRITE | MMCSD_SUP_SDIO_IRQ;
- #else
- host->flags = MMCSD_MUTBLKWRITE | MMCSD_SUP_SDIO_IRQ;
- #endif
- host->max_seg_size = SDIO_BUFF_SIZE;
- host->max_dma_segs = 1;
- host->max_blk_size = 512;
- host->max_blk_count = (SDIO_BUFF_SIZE / host->max_blk_size);
- /* link up host, config, cache_buf and sdio */
- sdio->host = host;
- sdio->config = config;
- sdio->cache_buf = cache_buf;
- host->private_data = sdio;
- /* enable interrupt */
- _sdio_update_irq(host, 1);
- /* ready to change */
- mmcsd_change(host);
- return host;
- }
- int rt_hw_sdio_init(void)
- {
- struct rt_mmcsd_host *host;
- struct hc32_sdio_config *sdio_config;
- rt_size_t obj_num = sizeof(_sdio_config) / sizeof(struct hc32_sdio_config);
- const struct hc32_sdio_des sdio_des =
- {
- .clk_get = _sdio_clock_get,
- .rxconfig = _sdio_dma_rxconfig,
- .txconfig = _sdio_dma_txconfig,
- };
- for (rt_size_t i = 0; i < obj_num; i++)
- {
- sdio_config = &_sdio_config[i];
- if (_sdio_clock_enable(sdio_config) != RT_EOK)
- {
- LOG_E("clock enable fail");
- return -1;
- }
- host = _sdio_host_create(sdio_config, _sdio_cache_buf[i], &sdio_des);
- if (host == RT_NULL)
- {
- LOG_E("host create fail");
- return -1;
- }
- else
- {
- /* link host */
- _sdio_host[i] = host;
- /* init board pin */
- rt_hw_board_sdio_init(sdio_config->instance);
- /* init DMA */
- _sdio_dma_init(sdio_config);
- /* register the irq handler */
- hc32_install_irq_handler(&sdio_config->irq_config, _sdio_irq_handler[i], RT_TRUE);
- }
- }
- return RT_EOK;
- }
- INIT_DEVICE_EXPORT(rt_hw_sdio_init);
- #endif /* BSP_USING_SDIO */
- #endif /* RT_USING_SDIO */
|