From 7d0155eeaa49ce250c9b59c6544f12ea0fa261ef Mon Sep 17 00:00:00 2001 From: greedyhao Date: Wed, 20 Jan 2021 19:28:26 +0800 Subject: [PATCH] [bsp][bluetrum] add sdio support --- bsp/bluetrum/ab32vg1-ab-prougen/.config | 7 + bsp/bluetrum/ab32vg1-ab-prougen/.cproject | 307 ++++---- bsp/bluetrum/ab32vg1-ab-prougen/README.md | 12 +- .../ab32vg1-ab-prougen/applications/mnt.c | 55 +- .../ab32vg1-ab-prougen/applications/romfs.c | 2 +- bsp/bluetrum/ab32vg1-ab-prougen/board/Kconfig | 28 + .../ab32vg1-ab-prougen/makefile.targets | 7 +- bsp/bluetrum/ab32vg1-ab-prougen/rtconfig.h | 2 + bsp/bluetrum/libraries/hal_drivers/SConscript | 8 +- .../libraries/hal_drivers/config/pwm_config.h | 9 + bsp/bluetrum/libraries/hal_drivers/drv_sdio.c | 658 ++++++++++++++++++ bsp/bluetrum/libraries/hal_drivers/drv_sdio.h | 140 ++++ .../ab32vg1_hal/include/ab32vg1_hal_conf.h | 2 +- .../ab32vg1_hal/include/ab32vg1_hal_sd.h | 64 +- .../ab32vg1_hal/include/ab32vg1_ll_sdio.h | 22 +- .../ab32vg1_hal/source/ab32vg1_hal_sd.c | 309 ++++++-- 16 files changed, 1404 insertions(+), 228 deletions(-) create mode 100644 bsp/bluetrum/libraries/hal_drivers/config/pwm_config.h create mode 100644 bsp/bluetrum/libraries/hal_drivers/drv_sdio.c create mode 100644 bsp/bluetrum/libraries/hal_drivers/drv_sdio.h diff --git a/bsp/bluetrum/ab32vg1-ab-prougen/.config b/bsp/bluetrum/ab32vg1-ab-prougen/.config index 6dea3429e3..0503cd820e 100644 --- a/bsp/bluetrum/ab32vg1-ab-prougen/.config +++ b/bsp/bluetrum/ab32vg1-ab-prougen/.config @@ -381,6 +381,7 @@ CONFIG_RT_USING_LIBC=y # CONFIG_PKG_USING_UC_MODBUS is not set # CONFIG_PKG_USING_PPOOL is not set # CONFIG_PKG_USING_OPENAMP is not set +# CONFIG_PKG_USING_RT_PRINTF is not set # # peripheral libraries and drivers @@ -501,11 +502,17 @@ CONFIG_RT_USING_LIBC=y CONFIG_BSP_USING_USB_TO_USART=y CONFIG_BSP_USING_AUDIO=y CONFIG_BSP_USING_AUDIO_PLAY=y +# CONFIG_BSP_USING_SDCARD is not set # # On-chip Peripheral Drivers # CONFIG_BSP_USING_UART0=y +# CONFIG_BSP_USING_SDIO is not set + +# +# On-chip Peripheral Drivers +# # # Board extended module Drivers diff --git a/bsp/bluetrum/ab32vg1-ab-prougen/.cproject b/bsp/bluetrum/ab32vg1-ab-prougen/.cproject index e8377fab46..6e4d4ca5fe 100644 --- a/bsp/bluetrum/ab32vg1-ab-prougen/.cproject +++ b/bsp/bluetrum/ab32vg1-ab-prougen/.cproject @@ -1,155 +1,158 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/bsp/bluetrum/ab32vg1-ab-prougen/README.md b/bsp/bluetrum/ab32vg1-ab-prougen/README.md index df58a01eda..feb312a128 100644 --- a/bsp/bluetrum/ab32vg1-ab-prougen/README.md +++ b/bsp/bluetrum/ab32vg1-ab-prougen/README.md @@ -12,7 +12,7 @@ ## 开发板介绍 -ab32vg1-prougen 是 中科蓝讯(Bluetrum) 推出的一款基于 RISC-V 内核的开发板,最高主频为 120Mhz,该开发板芯片为 AB5301A。 +ab32vg1-prougen 是 中科蓝讯(Bluetrum) 推出的一款基于 RISC-V 内核的开发板,最高主频为 120Mhz,该开发板芯片为 AB32VG1。 开发板外观如下图所示: @@ -20,7 +20,7 @@ ab32vg1-prougen 是 中科蓝讯(Bluetrum) 推出的一款基于 RISC-V 内核 该开发板常用 **板载资源** 如下: -- MCU:AB5301A,主频 120MHz,可超频至 192MHz,4Mbit FLASH ,192KB RAM。 +- MCU:AB32VG1,主频 120MHz,可超频至 192MHz,8Mbit FLASH ,192KB RAM。 - 常用外设 - LED: RGB灯 - 按键: 3 个, USER(s2,s3) and RESET(s1) @@ -33,9 +33,9 @@ ab32vg1-prougen 是 中科蓝讯(Bluetrum) 推出的一款基于 RISC-V 内核 | **板载外设** | **支持情况** | **备注** | | :----------- | :----------: | :---------- | | USB 转串口 | 支持 | | -| SD卡 | 即将支持 | | +| SD卡 | 支持 | | | IRDA | 即将支持 | | -| 音频接口 | 即将支持 | | +| 音频接口 | 支持 | | | **片上外设** | **支持情况** | **备注** | | GPIO | 支持 | PA PB PE PF | | UART | 支持 | UART0/1/2 | @@ -73,11 +73,11 @@ ab32vg1-prougen 是 中科蓝讯(Bluetrum) 推出的一款基于 RISC-V 内核 #### 编译下载 -运行 `scons` 编译得到 `.dcf` 固件,通过 `downloader` 进行下载 +通过 `RT-Thread Studio` 或者 `scons` 编译得到 `.dcf` 固件,通过 `Downloader` 进行下载 #### 运行结果 -下载程序成功之后,系统会自动运行,观察开发板上 LED 的运行效果,红色 LED 常亮、绿色 LED 会周期性闪烁。 +下载程序成功之后,系统会自动运行,观察开发板上 LED 的运行效果,红色 LED 会周期性闪烁。 连接开发板对应串口到 PC , 在终端工具里打开相应的串口(115200-8-1-N),复位设备后,可以看到 RT-Thread 的输出信息: diff --git a/bsp/bluetrum/ab32vg1-ab-prougen/applications/mnt.c b/bsp/bluetrum/ab32vg1-ab-prougen/applications/mnt.c index 005a86b41a..339c44f271 100644 --- a/bsp/bluetrum/ab32vg1-ab-prougen/applications/mnt.c +++ b/bsp/bluetrum/ab32vg1-ab-prougen/applications/mnt.c @@ -1,6 +1,59 @@ #include -#ifdef RT_USING_DFS +#if 1 + +#ifdef BSP_USING_SDIO + +#include +#include +#include +#include "drv_gpio.h" + +// #define DRV_DEBUG +#define DBG_TAG "app.card" +#include + +void sd_mount(void *parameter) +{ + while (1) + { + rt_thread_mdelay(500); + if(rt_device_find("sd0") != RT_NULL) + { + if (dfs_mount("sd0", "/", "elm", 0, 0) == RT_EOK) + { + LOG_I("sd card mount to '/'"); + break; + } + else + { + LOG_W("sd card mount to '/' failed!"); + } + } + } +} + +int ab32_sdcard_mount(void) +{ + rt_thread_t tid; + + tid = rt_thread_create("sd_mount", sd_mount, RT_NULL, + 1024, RT_THREAD_PRIORITY_MAX - 2, 20); + if (tid != RT_NULL) + { + rt_thread_startup(tid); + } + else + { + LOG_E("create sd_mount thread err!"); + } + return RT_EOK; +} +INIT_APP_EXPORT(ab32_sdcard_mount); +#endif + +#else + #include #include "dfs_romfs.h" diff --git a/bsp/bluetrum/ab32vg1-ab-prougen/applications/romfs.c b/bsp/bluetrum/ab32vg1-ab-prougen/applications/romfs.c index 42670bf6b3..446f7da026 100644 --- a/bsp/bluetrum/ab32vg1-ab-prougen/applications/romfs.c +++ b/bsp/bluetrum/ab32vg1-ab-prougen/applications/romfs.c @@ -1,7 +1,7 @@ /* Generated by mkromfs. Edit with caution. */ #include -#ifdef RT_USING_DFS +#ifdef RT_USING_DFS_ROMFS #include diff --git a/bsp/bluetrum/ab32vg1-ab-prougen/board/Kconfig b/bsp/bluetrum/ab32vg1-ab-prougen/board/Kconfig index 43dc3e8229..89296912ac 100644 --- a/bsp/bluetrum/ab32vg1-ab-prougen/board/Kconfig +++ b/bsp/bluetrum/ab32vg1-ab-prougen/board/Kconfig @@ -19,6 +19,34 @@ menu "Onboard Peripheral Drivers" default y endif + config BSP_USING_SDCARD + bool "Enable SDCARD" + select BSP_USING_SDIO + default n + + if BSP_USING_SDCARD + config SDIO_MAX_FREQ + int "sdio max freq" + range 0 24000000 + default 24000000 + endif + +endmenu + +menu "On-chip Peripheral Drivers" + + menuconfig BSP_USING_UART0 + bool "Enable UART0" + select RT_USING_SERIAL + default y + + config BSP_USING_SDIO + bool "Enable SDIO" + select RT_USING_SDIO + select RT_USING_DFS + select RT_USING_DFS_ELMFAT + default n + endmenu menu "On-chip Peripheral Drivers" diff --git a/bsp/bluetrum/ab32vg1-ab-prougen/makefile.targets b/bsp/bluetrum/ab32vg1-ab-prougen/makefile.targets index 796588852b..76aedb496e 100644 --- a/bsp/bluetrum/ab32vg1-ab-prougen/makefile.targets +++ b/bsp/bluetrum/ab32vg1-ab-prougen/makefile.targets @@ -1,13 +1,10 @@ -rtthread.siz: - riscv64-unknown-elf-size --format=berkeley "rtthread.elf" +all2: all sh ../pre_build.sh riscv32-elf-xmaker -b rtthread.xm riscv32-elf-xmaker -b download.xm - + clean2: -$(RM) $(CC_DEPS)$(C++_DEPS)$(C_UPPER_DEPS)$(CXX_DEPS)$(SECONDARY_FLASH)$(SECONDARY_SIZE)$(ASM_DEPS)$(S_UPPER_DEPS)$(C_DEPS)$(CPP_DEPS) -$(RM) $(OBJS) *.elf -@echo ' ' - -*.elf: $(wildcard D:/Softwares/RT-ThreadStudio/workspace/ab32vg1/link.lds) diff --git a/bsp/bluetrum/ab32vg1-ab-prougen/rtconfig.h b/bsp/bluetrum/ab32vg1-ab-prougen/rtconfig.h index 3ce6012a61..e308ed80ca 100644 --- a/bsp/bluetrum/ab32vg1-ab-prougen/rtconfig.h +++ b/bsp/bluetrum/ab32vg1-ab-prougen/rtconfig.h @@ -176,6 +176,8 @@ #define BSP_USING_UART0 +/* On-chip Peripheral Drivers */ + /* Board extended module Drivers */ #define BOARD_BLUETRUM_EVB diff --git a/bsp/bluetrum/libraries/hal_drivers/SConscript b/bsp/bluetrum/libraries/hal_drivers/SConscript index 87c1b93152..11a76e192a 100644 --- a/bsp/bluetrum/libraries/hal_drivers/SConscript +++ b/bsp/bluetrum/libraries/hal_drivers/SConscript @@ -4,7 +4,8 @@ from building import * cwd = GetCurrentDir() src = [] -CPPPATH = [cwd] +path = [cwd] +path += [cwd + '/config'] if GetDepend('RT_USING_PIN'): src += ['drv_gpio.c'] @@ -12,7 +13,10 @@ if GetDepend('RT_USING_PIN'): if GetDepend('RT_USING_SERIAL'): src += ['drv_usart.c'] -group = DefineGroup('Drivers', src, depend = [''], CPPPATH = CPPPATH) +if GetDepend('RT_USING_SDIO'): + src += ['drv_sdio.c'] + +group = DefineGroup('Drivers', src, depend = [''], CPPPATH = path) objs = [group] diff --git a/bsp/bluetrum/libraries/hal_drivers/config/pwm_config.h b/bsp/bluetrum/libraries/hal_drivers/config/pwm_config.h new file mode 100644 index 0000000000..24d705f342 --- /dev/null +++ b/bsp/bluetrum/libraries/hal_drivers/config/pwm_config.h @@ -0,0 +1,9 @@ +/* + * Copyright (c) 2020-2021, Bluetrum Development Team + * + * SPDX-License-Identifier: Apache-2.0 + * + * Change Logs: + * Date Author Notes + * 2021/01/18 greedyhao The first version + */ diff --git a/bsp/bluetrum/libraries/hal_drivers/drv_sdio.c b/bsp/bluetrum/libraries/hal_drivers/drv_sdio.c new file mode 100644 index 0000000000..4289b82307 --- /dev/null +++ b/bsp/bluetrum/libraries/hal_drivers/drv_sdio.c @@ -0,0 +1,658 @@ +/* + * Copyright (c) 2006-2021, Bluetrum Development Team + * + * SPDX-License-Identifier: Apache-2.0 + * + * Change Logs: + * Date Author Notes + * 2021-01-20 greedyhao first version + */ + +#include "drv_sdio.h" +#include "interrupt.h" +#include + +#ifdef BSP_USING_SDIO + +// #define DRV_DEBUG +#define LOG_TAG "drv.sdio" +#include + +#define SDIO_USING_1_BIT + +static struct ab32_sdio_config sdio_config[] = +{ + {.instance = SDMMC0_BASE, + }, +}; +static struct rt_mmcsd_host *host = RT_NULL; + +#define RTHW_SDIO_LOCK(_sdio) rt_mutex_take(&(_sdio)->mutex, RT_WAITING_FOREVER) +#define RTHW_SDIO_UNLOCK(_sdio) rt_mutex_release(&(_sdio)->mutex); + +struct sdio_pkg +{ + struct rt_mmcsd_cmd *cmd; + void *buff; + rt_uint32_t flag; + rt_uint32_t xfer_blks; +}; + +struct rthw_sdio +{ + struct rt_mmcsd_host *host; + struct ab32_sdio_des sdio_des; + struct rt_event event; + struct rt_mutex mutex; + struct sdio_pkg *pkg; +}; + +ALIGN(SDIO_ALIGN_LEN) +static rt_uint8_t cache_buf[SDIO_BUFF_SIZE]; + +static uint8_t sd_baud = 119; + +uint8_t sysclk_update_baud(uint8_t baud); + +static rt_uint32_t ab32_sdio_clk_get(hal_sfr_t hw_sdio) +{ + return (get_sysclk_nhz() / (sd_baud+1)); +} + +/** + * @brief This function get order from sdio. + * @param data + * @retval sdio order + */ +static int get_order(rt_uint32_t data) +{ + int order = 0; + + switch (data) + { + case 1: + order = 0; + break; + case 2: + order = 1; + break; + case 4: + order = 2; + break; + case 8: + order = 3; + break; + case 16: + order = 4; + break; + case 32: + order = 5; + break; + case 64: + order = 6; + break; + case 128: + order = 7; + break; + case 256: + order = 8; + break; + case 512: + order = 9; + break; + case 1024: + order = 10; + break; + case 2048: + order = 11; + break; + case 4096: + order = 12; + break; + case 8192: + order = 13; + break; + case 16384: + order = 14; + break; + default : + order = 0; + break; + } + + return order; +} + +/** + * @brief This function wait sdio completed. + * @param sdio rthw_sdio + * @retval None + */ +static void rthw_sdio_wait_completed(struct rthw_sdio *sdio) +{ + rt_uint32_t status = 0; + struct rt_mmcsd_cmd *cmd = sdio->pkg->cmd; + struct rt_mmcsd_data *data = cmd->data; + hal_sfr_t hw_sdio = sdio->sdio_des.hw_sdio; + rt_err_t tx_finish = -RT_ERROR; + + if (rt_event_recv(&sdio->event, 0xFFFFFFFF & ~HW_SDIO_CON_DFLAG, RT_EVENT_FLAG_OR | RT_EVENT_FLAG_CLEAR, + rt_tick_from_millisecond(5000), &status) != RT_EOK) + { + LOG_E("wait completed timeout"); + cmd->err = -RT_ETIMEOUT; + return; + } + + if (sdio->pkg == RT_NULL) + { + return; + } + + cmd->resp[0] = hw_sdio[SDARG3]; + cmd->resp[1] = hw_sdio[SDARG2]; + cmd->resp[2] = hw_sdio[SDARG1]; + cmd->resp[3] = hw_sdio[SDARG0]; + + if (!(status & HW_SDIO_CON_NRPS)) { + cmd->err = RT_EOK; + LOG_D("sta:0x%08X [%08X %08X %08X %08X]", status, cmd->resp[0], cmd->resp[1], cmd->resp[2], cmd->resp[3]); + } else { + cmd->err = -RT_ERROR; + } +} + +/** + * @brief This function transfer data by dma. + * @param sdio rthw_sdio + * @param pkg sdio package + * @retval None + */ +static void rthw_sdio_transfer_by_dma(struct rthw_sdio *sdio, struct sdio_pkg *pkg) +{ + struct rt_mmcsd_data *data; + int size; + void *buff; + hal_sfr_t hw_sdio = sdio->sdio_des.hw_sdio; + + if ((RT_NULL == pkg) || (RT_NULL == sdio)) + { + LOG_E("rthw_sdio_transfer_by_dma invalid args"); + return; + } + + data = pkg->cmd->data; + if (RT_NULL == data) + { + LOG_E("rthw_sdio_transfer_by_dma invalid args"); + return; + } + + buff = pkg->buff; + if (RT_NULL == buff) + { + LOG_E("rthw_sdio_transfer_by_dma invalid args"); + return; + } + hw_sdio = sdio->sdio_des.hw_sdio; + size = data->blks * data->blksize; + + if (data->flags & DATA_DIR_WRITE) + { + LOG_D("DATA_DIR_WRITE %d", pkg->xfer_blks); + sdio->sdio_des.txconfig((rt_uint32_t *)((rt_uint8_t *)buff + (pkg->xfer_blks * data->blksize)), 512); + } + else if (data->flags & DATA_DIR_READ) + { + LOG_D("DATA_DIR_WRITE %d", pkg->xfer_blks); + sdio->sdio_des.rxconfig((rt_uint32_t *)((rt_uint8_t *)buff + (pkg->xfer_blks * data->blksize)), data->blksize); + } +} + +/** + * @brief This function send command. + * @param sdio rthw_sdio + * @param pkg sdio package + * @retval None + */ +static void rthw_sdio_send_command(struct rthw_sdio *sdio, struct sdio_pkg *pkg) +{ + struct rt_mmcsd_cmd *cmd = pkg->cmd; + struct rt_mmcsd_data *data = cmd->data; + hal_sfr_t hw_sdio = sdio->sdio_des.hw_sdio; + rt_uint32_t reg_cmd = 0; + rt_uint32_t data_flag = 0; + + /* save pkg */ + sdio->pkg = pkg; + + #define CK8E BIT(11) //在命令/数据包后加上8CLK + #define CBUSY BIT(10) //Busy Check + #define CLRSP BIT(9) //17Byte Long Rsp + #define CRSP BIT(8) //Need Rsp + + /* config cmd reg */ + if (cmd->cmd_code != 18) { + reg_cmd = cmd->cmd_code | 0x40 | CK8E; + } else { + reg_cmd = cmd->cmd_code | 0x40; + } + + switch (resp_type(cmd)) + { + case RESP_R1B: + reg_cmd |= CBUSY | CRSP; + break; + case RESP_R2: + reg_cmd |= CLRSP | CRSP; + break; + default: + reg_cmd |= CRSP; + break; + } + + LOG_D("CMD:%d 0x%04X ARG:0x%08x RES:%s%s%s%s%s%s%s%s%s rw:%c len:%d blksize:%d", + cmd->cmd_code, + reg_cmd, + 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 data reg */ + if (data != RT_NULL) + { + rt_uint32_t dir = 0; + rt_uint32_t size = data->blks * data->blksize; + int order; + + order = get_order(data->blksize); + dir = (data->flags & DATA_DIR_READ) ? HW_SDIO_TO_HOST : 0; + + data_flag = data->flags; + } + + /* transfer config */ + if (data_flag & DATA_DIR_READ) + { + rthw_sdio_transfer_by_dma(sdio, pkg); + } + + /* send cmd */ + hw_sdio[SDARG3] = cmd->arg; + hw_sdio[SDCMD] = reg_cmd; + + /* wait cmd completed */ + rthw_sdio_wait_completed(sdio); + + /* transfer config */ + if (data != RT_NULL) + { + do { + if ((data_flag & DATA_DIR_WRITE) || ((data_flag & DATA_DIR_READ) && (pkg->xfer_blks != 0))) { + rthw_sdio_transfer_by_dma(sdio, pkg); + } + + rt_uint32_t status = 0; + + if (rt_event_recv(&sdio->event, 0xFFFFFFFF & ~HW_SDIO_CON_DFLAG, RT_EVENT_FLAG_OR | RT_EVENT_FLAG_CLEAR, + rt_tick_from_millisecond(5000), &status) != RT_EOK) + { + LOG_E("wait completed timeout"); + LOG_E("SDCON=0x%X SDCMD=0x%X\n", hw_sdio[SDCON], hw_sdio[SDCMD]); + cmd->err = -RT_ETIMEOUT; + } + + if (data_flag & DATA_DIR_WRITE) { + if (((hw_sdio[SDCON] & HW_SDIO_CON_CRCS) >> 17) != 2) { + LOG_E("Write CRC error!"); + cmd->err = -RT_ERROR; + hw_sdio[SDCPND] = HW_SDIO_CON_DFLAG; + } + } + } while(++pkg->xfer_blks != data->blks); + } + + /* clear pkg */ + sdio->pkg = RT_NULL; +} + +/** + * @brief This function send sdio request. + * @param host rt_mmcsd_host + * @param req request + * @retval None + */ +static void rthw_sdio_request(struct rt_mmcsd_host *host, struct rt_mmcsd_req *req) +{ + struct sdio_pkg pkg; + struct rthw_sdio *sdio = host->private_data; + struct rt_mmcsd_data *data; + + RTHW_SDIO_LOCK(sdio); + + if (req->cmd != RT_NULL) + { + rt_memset(&pkg, 0, sizeof(pkg)); + data = req->cmd->data; + pkg.cmd = req->cmd; + + if (data != RT_NULL) + { + rt_uint32_t size = data->blks * data->blksize; + + RT_ASSERT(size <= SDIO_BUFF_SIZE); + + pkg.buff = data->buf; + if ((rt_uint32_t)data->buf & (SDIO_ALIGN_LEN - 1)) + { + pkg.buff = cache_buf; + if (data->flags & DATA_DIR_WRITE) + { + rt_memcpy(cache_buf, data->buf, size); + } + } + } + + rthw_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, cache_buf, data->blksize * data->blks); + } + } + + if (req->stop != RT_NULL) + { + rt_memset(&pkg, 0, sizeof(pkg)); + pkg.cmd = req->stop; + rthw_sdio_send_command(sdio, &pkg); + } + + RTHW_SDIO_UNLOCK(sdio); + + mmcsd_req_complete(sdio->host); +} + +/** + * @brief This function config sdio. + * @param host rt_mmcsd_host + * @param io_cfg rt_mmcsd_io_cfg + * @retval None + */ +static void rthw_sdio_iocfg(struct rt_mmcsd_host *host, struct rt_mmcsd_io_cfg *io_cfg) +{ + rt_uint32_t clkcr, div, clk_src; + rt_uint32_t clk = io_cfg->clock; + struct rthw_sdio *sdio = host->private_data; + hal_sfr_t hw_sdio = sdio->sdio_des.hw_sdio; + + clk_src = sdio->sdio_des.clk_get(sdio->sdio_des.hw_sdio); + if (clk_src < 240 * 1000) + { + LOG_E("The clock rate is too low! rata:%d", clk_src); + return; + } + + if (clk > host->freq_max) clk = host->freq_max; + + if (clk > clk_src) + { + // LOG_W("Setting rate(%d) is greater than clock source rate(%d).", clk, clk_src); + // 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->power_mode) + { + case MMCSD_POWER_OFF: + hw_sdio[SDCON] &= ~BIT(0); + break; + case MMCSD_POWER_UP: + sd_baud = 199; + hw_sdio[SDCON] = 0; + rt_thread_mdelay(1); + + hw_sdio[SDCON] |= BIT(0); /* SD control enable */ + hw_sdio[SDBAUD] = sysclk_update_baud(sd_baud); + hw_sdio[SDCON] |= BIT(3); /* Keep clock output */ + hw_sdio[SDCON] |= BIT(4); + hw_sdio[SDCON] |= BIT(5); /* Data interrupt enable */ + + hal_mdelay(40); + break; + case MMCSD_POWER_ON: + if (clk == SDIO_MAX_FREQ) { + hw_sdio[SDCON] &= ~BIT(3); + sd_baud = 3; + hw_sdio[SDBAUD] = sysclk_update_baud(sd_baud); + } + break; + default: + LOG_W("unknown power_mode %d", io_cfg->power_mode); + break; + } + + RTHW_SDIO_UNLOCK(sdio); +} + +/** + * @brief This function update sdio interrupt. + * @param host rt_mmcsd_host + * @param enable + * @retval None + */ +void rthw_sdio_irq_update(struct rt_mmcsd_host *host, rt_int32_t enable) +{ + struct rthw_sdio *sdio = host->private_data; + hal_sfr_t hw_sdio = sdio->sdio_des.hw_sdio; + + if (enable) + { + LOG_D("enable sdio irq"); + rt_hw_irq_enable(IRQ_SD_VECTOR); + } + else + { + LOG_D("disable sdio irq"); + rt_hw_irq_disable(IRQ_SD_VECTOR); + } +} + +/** + * @brief This function detect sdcard. + * @param host rt_mmcsd_host + * @retval 0x01 + */ +static rt_int32_t rthw_sd_detect(struct rt_mmcsd_host *host) +{ + LOG_D("try to detect device"); + return 0x01; +} + +/** + * @brief This function interrupt process function. + * @param host rt_mmcsd_host + * @retval None + */ +void rthw_sdio_irq_process(struct rt_mmcsd_host *host) +{ + int complete = 0; + struct rthw_sdio *sdio = host->private_data; + hal_sfr_t hw_sdio = sdio->sdio_des.hw_sdio; + rt_uint32_t intstatus = hw_sdio[SDCON]; + + /* clear flag */ + if (intstatus & HW_SDIO_CON_CFLAG) { + complete = 1; + hw_sdio[SDCPND] = HW_SDIO_CON_CFLAG; + } + + if (intstatus & HW_SDIO_CON_DFLAG) { + complete = 1; + hw_sdio[SDCPND] = HW_SDIO_CON_DFLAG; + } + + if (complete) + { + rt_event_send(&sdio->event, intstatus); + } +} + +static const struct rt_mmcsd_host_ops ab32_sdio_ops = +{ + rthw_sdio_request, + rthw_sdio_iocfg, + rthw_sd_detect, + rthw_sdio_irq_update, +}; + +/** + * @brief This function create mmcsd host. + * @param sdio_des ab32_sdio_des + * @retval rt_mmcsd_host + */ +struct rt_mmcsd_host *sdio_host_create(struct ab32_sdio_des *sdio_des) +{ + struct rt_mmcsd_host *host; + struct rthw_sdio *sdio = RT_NULL; + + if ((sdio_des == RT_NULL) || (sdio_des->txconfig == RT_NULL) || (sdio_des->rxconfig == RT_NULL)) + { + LOG_E("L:%d F:%s %s %s %s", + (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; + } + + sdio = rt_malloc(sizeof(struct rthw_sdio)); + if (sdio == RT_NULL) + { + LOG_E("L:%d F:%s malloc rthw_sdio fail"); + return RT_NULL; + } + rt_memset(sdio, 0, sizeof(struct rthw_sdio)); + + host = mmcsd_alloc_host(); + if (host == RT_NULL) + { + LOG_E("L:%d F:%s mmcsd alloc host fail"); + rt_free(sdio); + return RT_NULL; + } + + rt_memcpy(&sdio->sdio_des, sdio_des, sizeof(struct ab32_sdio_des)); + sdio->sdio_des.hw_sdio = (sdio_des->hw_sdio == RT_NULL ? SDMMC0_BASE : sdio_des->hw_sdio); + sdio->sdio_des.clk_get = (sdio_des->clk_get == RT_NULL ? ab32_sdio_clk_get : sdio_des->clk_get); + + rt_event_init(&sdio->event, "sdio", RT_IPC_FLAG_FIFO); + rt_mutex_init(&sdio->mutex, "sdio", RT_IPC_FLAG_FIFO); + + /* set host defautl attributes */ + host->ops = &ab32_sdio_ops; + host->freq_min = 240 * 1000; + host->freq_max = SDIO_MAX_FREQ; + host->valid_ocr = 0X00FFFF80;/* The voltage range supported is 1.65v-3.6v */ +#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 = 512; + + /* link up host and sdio */ + sdio->host = host; + host->private_data = sdio; + + rthw_sdio_irq_update(host, 1); + + /* ready to change */ + mmcsd_change(host); + + return host; +} + +static rt_err_t _dma_txconfig(rt_uint32_t *src, int Size) +{ + hal_sfr_t sdiox = sdio_config->instance; + + sdiox[SDDMAADR] = DMA_ADR(src); + sdiox[SDDMACNT] = BIT(18) | BIT(17) | BIT(16) | Size; + return RT_EOK; +} + +static rt_err_t _dma_rxconfig(rt_uint32_t *dst, int Size) +{ + hal_sfr_t sdiox = sdio_config->instance; + + sdiox[SDDMAADR] = DMA_ADR(dst); + sdiox[SDDMACNT] = (Size); + return RT_EOK; +} + +void sdio_isr(int vector, void *param) +{ + /* enter interrupt */ + rt_interrupt_enter(); + /* Process All SDIO Interrupt Sources */ + rthw_sdio_irq_process(host); + + /* leave interrupt */ + rt_interrupt_leave(); +} + +int rt_hw_sdio_init(void) +{ + struct ab32_sdio_des sdio_des = {0}; + struct sd_handle hsd = {0}; + uint8_t param = 0; + hsd.instance = SDMMC0_BASE; + + hal_rcu_periph_clk_enable(RCU_SD0); + hal_sd_mspinit(&hsd); + + rt_hw_interrupt_install(IRQ_SD_VECTOR, sdio_isr, ¶m, "sd_isr"); + + sdio_des.clk_get = ab32_sdio_clk_get; + sdio_des.hw_sdio = SDMMC0_BASE; + sdio_des.rxconfig = _dma_rxconfig; + sdio_des.txconfig = _dma_txconfig; + + host = sdio_host_create(&sdio_des); + + return 0; +} +INIT_DEVICE_EXPORT(rt_hw_sdio_init); + +void ab32_mmcsd_change(void) +{ + mmcsd_change(host); +} + +#endif // 0 diff --git a/bsp/bluetrum/libraries/hal_drivers/drv_sdio.h b/bsp/bluetrum/libraries/hal_drivers/drv_sdio.h new file mode 100644 index 0000000000..c2b5f2ba9f --- /dev/null +++ b/bsp/bluetrum/libraries/hal_drivers/drv_sdio.h @@ -0,0 +1,140 @@ +/* + * Copyright (c) 2006-2020, RT-Thread Development Team + * + * SPDX-License-Identifier: Apache-2.0 + * + * Change Logs: + * Date Author Notes + * 2020-11-30 greedyhao first version + */ + +#ifndef DEV_SDIO_H__ +#define DEV_SDIO_H__ + +#include "drv_common.h" +#include "board.h" +#include "drivers/mmcsd_core.h" +#include "drivers/sdio.h" + +#define SDIO_BUFF_SIZE 1024 +#define SDIO_ALIGN_LEN 32 + +#ifndef SDIO_MAX_FREQ +#define SDIO_MAX_FREQ (1000000) +#endif + +#ifndef SDIO_BASE_ADDRESS +#define SDIO_BASE_ADDRESS (0x40012800U) +#endif + +#ifndef SDIO_CLOCK_FREQ +#define SDIO_CLOCK_FREQ (48U * 1000 * 1000) +#endif + +#ifndef SDIO_BUFF_SIZE +#define SDIO_BUFF_SIZE (4096) +#endif + +#ifndef SDIO_ALIGN_LEN +#define SDIO_ALIGN_LEN (32) +#endif + +#ifndef SDIO_MAX_FREQ +#define SDIO_MAX_FREQ (24 * 1000 * 1000) +#endif + + +#define HW_SDIO_CON_ +#define HW_SDIO_CON_CFLAG (0x01u << 12) /*!< 0:send command or received response not finish \ + 1:send command or received response finish */ +#define HW_SDIO_CON_DFLAG (0x01u << 13) /*!< 0:send or received data not finish \ + 1:send or received data finish */ +#define HW_SDIO_CON_CCRCE (0x01u << 14) /*!< 0:command crc no error \ + 1:command crc error detected */ +#define HW_SDIO_CON_NRPS (0x01u << 15) /*!< 0:response received 1:no response received */ +#define HW_SDIO_CON_DCRCE (0x01u << 16) /*!< 0:read data crc no error \ + 1:read data crc error detected */ +#define HW_SDIO_CON_CRCS (0x07u << 17) /*!< 101:error transmission \ + 010:non-erroneous transmission \ + 111:flash error */ +#define HW_SDIO_CON_BUSY (0x01u << 20) /*!< 0:device busy 1:device not busy */ + +#define HW_SDIO_ERRORS \ + (0) + +#define HW_SDIO_POWER_OFF (0x00U) +#define HW_SDIO_POWER_UP (0x02U) +#define HW_SDIO_POWER_ON (0x03U) + +#define HW_SDIO_FLOW_ENABLE (0x01U << 14) +#define HW_SDIO_BUSWIDE_1B (0x00U << 11) +#define HW_SDIO_BUSWIDE_4B (0x01U << 11) +#define HW_SDIO_BUSWIDE_8B (0x02U << 11) +#define HW_SDIO_BYPASS_ENABLE (0x01U << 10) +#define HW_SDIO_IDLE_ENABLE (0x01U << 9) +#define HW_SDIO_CLK_ENABLE (0x01U << 8) + +#define HW_SDIO_SUSPEND_CMD (0x01U << 11) +#define HW_SDIO_CPSM_ENABLE (0x01U << 10) +#define HW_SDIO_WAIT_END (0x01U << 9) +#define HW_SDIO_WAIT_INT (0x01U << 8) +#define HW_SDIO_RESPONSE_NO (0x00U << 6) +#define HW_SDIO_RESPONSE_SHORT (0x01U << 6) +#define HW_SDIO_RESPONSE_LONG (0x03U << 6) + +#define HW_SDIO_DATA_LEN_MASK (0x01FFFFFFU) + +#define HW_SDIO_IO_ENABLE (0x01U << 11) +#define HW_SDIO_RWMOD_CK (0x01U << 10) +#define HW_SDIO_RWSTOP_ENABLE (0x01U << 9) +#define HW_SDIO_RWSTART_ENABLE (0x01U << 8) +#define HW_SDIO_DBLOCKSIZE_1 (0x00U << 4) +#define HW_SDIO_DBLOCKSIZE_2 (0x01U << 4) +#define HW_SDIO_DBLOCKSIZE_4 (0x02U << 4) +#define HW_SDIO_DBLOCKSIZE_8 (0x03U << 4) +#define HW_SDIO_DBLOCKSIZE_16 (0x04U << 4) +#define HW_SDIO_DBLOCKSIZE_32 (0x05U << 4) +#define HW_SDIO_DBLOCKSIZE_64 (0x06U << 4) +#define HW_SDIO_DBLOCKSIZE_128 (0x07U << 4) +#define HW_SDIO_DBLOCKSIZE_256 (0x08U << 4) +#define HW_SDIO_DBLOCKSIZE_512 (0x09U << 4) +#define HW_SDIO_DBLOCKSIZE_1024 (0x0AU << 4) +#define HW_SDIO_DBLOCKSIZE_2048 (0x0BU << 4) +#define HW_SDIO_DBLOCKSIZE_4096 (0x0CU << 4) +#define HW_SDIO_DBLOCKSIZE_8192 (0x0DU << 4) +#define HW_SDIO_DBLOCKSIZE_16384 (0x0EU << 4) +#define HW_SDIO_DMA_ENABLE (0x01U << 3) +#define HW_SDIO_STREAM_ENABLE (0x01U << 2) +#define HW_SDIO_TO_HOST (0x01U << 1) +#define HW_SDIO_DPSM_ENABLE (0x01U << 0) + +#define HW_SDIO_DATATIMEOUT (0xF0000000U) + +// struct ab32_sdio +// {}; + +typedef rt_err_t (*dma_txconfig)(rt_uint32_t *src, int size); +typedef rt_err_t (*dma_rxconfig)(rt_uint32_t *dst, int size); +typedef rt_uint32_t (*sdio_clk_get)(hal_sfr_t hw_sdio); + +struct ab32_sdio_des +{ + hal_sfr_t hw_sdio; + dma_txconfig txconfig; + dma_rxconfig rxconfig; + sdio_clk_get clk_get; +}; + +struct ab32_sdio_config +{ + hal_sfr_t instance; + // struct dma_config dma_rx, dma_tx; +}; + +struct ab32_sdio_class +{ + const struct ab32_sdio_config *cfg; + struct rt_mmcsd_host host; +}; + +#endif diff --git a/bsp/bluetrum/libraries/hal_libraries/ab32vg1_hal/include/ab32vg1_hal_conf.h b/bsp/bluetrum/libraries/hal_libraries/ab32vg1_hal/include/ab32vg1_hal_conf.h index 9c1f9b3fcb..a26714cc28 100644 --- a/bsp/bluetrum/libraries/hal_libraries/ab32vg1_hal/include/ab32vg1_hal_conf.h +++ b/bsp/bluetrum/libraries/hal_libraries/ab32vg1_hal/include/ab32vg1_hal_conf.h @@ -13,7 +13,7 @@ #define HAL_RCU_MODULE_ENABLED #define HAL_WDT_MODULE_ENABLED // #define HAL_DAC_MODULE_ENABLED -// #define HAL_SD_MODULE_ENABLED +#define HAL_SD_MODULE_ENABLED /* Includes */ #ifdef HAL_GPIO_MODULE_ENABLED diff --git a/bsp/bluetrum/libraries/hal_libraries/ab32vg1_hal/include/ab32vg1_hal_sd.h b/bsp/bluetrum/libraries/hal_libraries/ab32vg1_hal/include/ab32vg1_hal_sd.h index 291d1e1e36..3c1fcbd9ad 100644 --- a/bsp/bluetrum/libraries/hal_libraries/ab32vg1_hal/include/ab32vg1_hal_sd.h +++ b/bsp/bluetrum/libraries/hal_libraries/ab32vg1_hal/include/ab32vg1_hal_sd.h @@ -8,35 +8,73 @@ #define AB32VG1_HAL_SD_H__ #include "ab32vg1_hal_def.h" - -struct sd_init -{ - // uint8_t -}; +#include "ab32vg1_ll_sdio.h" +#include struct sd_card_info { - uint32_t rca; /*!< Specifies the Relative Card Address */ - uint8_t type; /*!< Specifies the card type */ + uint32_t rca; /*!< Specifies the Relative Card Address */ + uint32_t capacity; /*!< Specifies the capacity of the card */ + uint8_t abend; /*!< Specifies if the card is abnormal end */ + uint8_t flag_sdhc; /*!< Specifies if the card is SDHC card */ + uint8_t type; /*!< Specifies the card type */ + uint8_t state; /*!< Specifies the card state */ + uint8_t rw_state; /*!< Specifies the last r/w state of the card */ }; typedef struct sd_card_info* sd_card_info_t; +struct sd_cfg +{ + uint16_t go_ready_retry; + uint8_t identification_retry; + uint8_t rw_retry; + uint8_t rw_init_retry; + uint8_t stop_retry; + uint8_t rw_need_stop; +}; + struct sd_handle { hal_sfr_t instance; - struct sd_init init; + struct sdio_init init; struct sd_card_info sdcard; + struct sd_cfg cfg; }; typedef struct sd_handle* sd_handle_t; -#define SD0N (0x00u) +#define SD0N (0x00u) -#define CARD_V1 (0x01u) -#define CARD_V2 (0x02u) -#define CARD_MMC (0x03u) +// #define CARD_SDSC (0x00u) +// #define CARD_SDHC (0x01u) +// #define CARD_SECURED (0x03u) + +enum +{ + CARD_INVAL = 0x00, + CARD_V1, + CARD_V2, + CARD_MMC +}; + +enum +{ + HAL_SD_RW_STATE_IDLE = 0x00, + HAL_SD_RW_STATE_READ, + HAL_SD_RW_STATE_WRITE, +}; + +enum +{ + HAL_SD_STATE_RESET = 0x00, + HAL_SD_STATE_NEW, + HAL_SD_STATE_OK, + HAL_SD_STATE_INVAL, +}; #define SDMMC_CHECK_PATTERM (0x000001AAu) +#define SDMMC0_BASE ((hal_sfr_t)&SD0CON) + /* Initialization functions */ hal_error_t hal_sd_init(sd_handle_t hsd); void hal_sd_deinit(uint32_t sdx); @@ -44,7 +82,7 @@ void hal_sd_mspinit(sd_handle_t hsd); hal_error_t hal_sd_control(uint32_t control, uint32_t arg); void hal_sd_write(uint32_t sdx, uint32_t data); -uint32_t hal_sd_read(uint32_t sdx); +bool hal_sd_read(sd_handle_t hsd, void *buf, uint32_t lba); // void hal_uart_write_it(uint32_t uartx, uint8_t data); // uint8_t hal_uart_read_it(uint32_t uartx); diff --git a/bsp/bluetrum/libraries/hal_libraries/ab32vg1_hal/include/ab32vg1_ll_sdio.h b/bsp/bluetrum/libraries/hal_libraries/ab32vg1_hal/include/ab32vg1_ll_sdio.h index 6fff778b7d..bb2fae5256 100644 --- a/bsp/bluetrum/libraries/hal_libraries/ab32vg1_hal/include/ab32vg1_ll_sdio.h +++ b/bsp/bluetrum/libraries/hal_libraries/ab32vg1_hal/include/ab32vg1_ll_sdio.h @@ -11,8 +11,28 @@ struct sdio_init { - uint32_t tmp; + uint32_t clock_power_save; /*!< Specifies whether SDMMC Clock output is enabled or + disabled when the bus is idle. */ + uint32_t clock_div; /*!< Specifies the clock frequency of the SDMMC controller. + This parameter can be a value between Min_Data = 0 and Max_Data = 255 */ }; typedef struct sdio_init* sdio_init_t; +#define SDMMC_CLOCK_POWER_SAVE_DISABLE (0x00u) +#define SDMMC_CLOCK_POWER_SAVE_ENABLE (0x01u) + +enum +{ + SDCON = 0, /* [20]:BUSY [19:17]:CRCS [16]:DCRCE [15]:NRPS [1]:Data bus width [0]:SD enable */ + SDCPND, + SDBAUD, + SDCMD, + SDARG3, + SDARG2, + SDARG1, + SDARG0, + SDDMAADR, + SDDMACNT, +}; + #endif diff --git a/bsp/bluetrum/libraries/hal_libraries/ab32vg1_hal/source/ab32vg1_hal_sd.c b/bsp/bluetrum/libraries/hal_libraries/ab32vg1_hal/source/ab32vg1_hal_sd.c index 6beacf75a5..26d200dd89 100644 --- a/bsp/bluetrum/libraries/hal_libraries/ab32vg1_hal/source/ab32vg1_hal_sd.c +++ b/bsp/bluetrum/libraries/hal_libraries/ab32vg1_hal/source/ab32vg1_hal_sd.c @@ -1,10 +1,8 @@ #include "ab32vg1_hal.h" -#include "ab32vg1_ll_sdio.h" +#undef HAL_SD_MODULE_ENABLED #ifdef HAL_SD_MODULE_ENABLED -#include - #define HAL_LOG(...) hal_printf(__VA_ARGS__) /************************* LL ************************************/ @@ -27,20 +25,6 @@ #define RSP_BUSY_TIMEOUT 2400000 //大约2s #define RSP_TIMEOUT 6000 //大约5ms -enum -{ - SDCON = 0, /* [20]:BUSY [19:17]:CRCS [16]:DCRCE [15]:NRPS [1]:Data bus width [0]:SD enable */ - SDCPND, - SDBAUD, - SDCMD, - SDARG3, - SDARG2, - SDARG1, - SDARG0, - SDDMAADR, - SDDMACNT, -}; - uint8_t sysclk_update_baud(uint8_t baud); void sdio_setbaud(hal_sfr_t sdiox, uint8_t baud) @@ -50,14 +34,18 @@ void sdio_setbaud(hal_sfr_t sdiox, uint8_t baud) void sdio_init(hal_sfr_t sdiox, sdio_init_t init) { - /* Set clock */ - sdio_setbaud(sdiox, 199); - sdiox[SDCON] = 0; + hal_udelay(20); - sdiox[SDCON] |= BIT(0); /* SD control enable */ - sdiox[SDCON] |= BIT(3); /* Keep clock output */ - sdiox[SDCON] |= BIT(5); /* Data interrupt enable */ + sdiox[SDCON] |= BIT(0); /* SD control enable */ + sdio_setbaud(sdiox, init->clock_div); /* Set clock */ + if (init->clock_power_save == SDMMC_CLOCK_POWER_SAVE_DISABLE) { + sdiox[SDCON] |= BIT(3); /* Keep clock output */ + } else { + sdiox[SDCON] &= ~BIT(3); /* Keep clock output */ + } + sdiox[SDCON] |= BIT(5); /* Data interrupt enable */ + hal_mdelay(40); } @@ -89,16 +77,18 @@ bool sdio_check_rsp(hal_sfr_t sdiox) return !(sdiox[SDCON] & BIT(15)); } -bool sdio_send_cmd(hal_sfr_t sdiox, uint32_t cmd, uint32_t arg) +bool sdio_send_cmd(hal_sfr_t sdiox, uint32_t cmd, uint32_t arg, uint8_t *abend) { uint32_t time_out = (cmd & CBUSY) ? RSP_BUSY_TIMEOUT : RSP_TIMEOUT; - sdiox[SDCMD] = cmd; sdiox[SDARG3] = arg; + sdiox[SDCMD] = cmd; while (sdio_check_finish(sdiox) == false) { if (--time_out == 0) { HAL_LOG("cmd time out\n"); - // card.abend = 1; + if (abend != HAL_NULL) { + *abend = 1; + } return false; } } @@ -108,57 +98,258 @@ bool sdio_send_cmd(hal_sfr_t sdiox, uint32_t cmd, uint32_t arg) uint8_t sdio_get_cmd_rsp(hal_sfr_t sdiox) { - return -1; + return sdiox[SDCMD]; } -uint32_t sdio_get_rsp(hal_sfr_t sdiox, uint32_t rsp) +uint32_t sdio_get_rsp(hal_sfr_t sdiox, uint32_t rsp_reg) { - return -1; + return sdiox[rsp_reg]; } void sdio_read_kick(hal_sfr_t sdiox, void* buf) -{} +{ + sdiox[SDDMAADR] = DMA_ADR(buf); + sdiox[SDDMACNT] = 512; +} void sdio_write_kick(hal_sfr_t sdiox, void* buf) -{} +{ + sdiox[SDDMAADR] = DMA_ADR(buf); + sdiox[SDDMACNT] = BIT(18) | BIT(17) | BIT(16) | 512; +} bool sdio_isbusy(hal_sfr_t sdiox) { return false; } -void sdmmc_go_idle_state(hal_sfr_t sdiox) +bool sdmmc_cmd_go_idle_state(sd_handle_t hsd) { - // hal_sfr_t sdiox = hsd->instance; - sdio_send_cmd(sdiox, 0x00 | RSP_NO, 0); + return sdio_send_cmd(hsd->instance, 0 | RSP_NO, hsd->sdcard.rca, &(hsd->sdcard.abend)); } -void sdmmc_send_if_cond(hal_sfr_t sdiox) +bool sdmmc_cmd_send_if_cond(sd_handle_t hsd) { - // hal_sfr_t sdiox = hsd->instance; - sdio_send_cmd(sdiox, 0x08 | RSP_7, SDMMC_CHECK_PATTERM); + return sdio_send_cmd(hsd->instance, 8 | RSP_7, SDMMC_CHECK_PATTERM, &(hsd->sdcard.abend)); +} + +bool sdmmc_cmd_all_send_cid(sd_handle_t hsd) +{ + return sdio_send_cmd(hsd->instance, 2 | RSP_2, 0, &(hsd->sdcard.abend)); +} + +void sdmmc_cmd_set_rel_addr(sd_handle_t hsd) +{ + hal_sfr_t sdiox = hsd->instance; + + if (hsd->sdcard.type == CARD_MMC) { + hsd->sdcard.rca = 0x00010000; + sdio_send_cmd(sdiox, 3 | RSP_1, hsd->sdcard.rca, &(hsd->sdcard.abend)); + } else { + sdio_send_cmd(sdiox, 3 | RSP_6, 0, &(hsd->sdcard.abend)); + hsd->sdcard.rca = sdio_get_rsp(sdiox, SDARG3) & 0xffff0000; + } +} + +void sdmmc_cmd_send_csd(sd_handle_t hsd) +{ + hal_sfr_t sdiox = hsd->instance; + + sdio_send_cmd(sdiox, 9 | RSP_2, hsd->sdcard.rca, &(hsd->sdcard.abend)); + if (hsd->sdcard.type == CARD_MMC) { + // + } else { + if (hsd->sdcard.flag_sdhc == 1) { + hsd->sdcard.capacity = (sdio_get_rsp(sdiox, SDARG2) << 24) & 0x00ff0000; /* rspbuf[8] */ + hsd->sdcard.capacity |= ((sdio_get_rsp(sdiox, SDARG1) >> 16) & 0x0000ffff); /* rspbuf[9] rspbuf[10] */ + hsd->sdcard.capacity += 1; + hsd->sdcard.capacity <<= 10; + } + } + HAL_LOG("sd capacity=%d\n", hsd->sdcard.capacity); +} + +void sdmmc_cmd_select_card(sd_handle_t hsd) +{ + sdio_send_cmd(hsd->instance, 7 | RSP_1B, hsd->sdcard.rca, &(hsd->sdcard.abend)); +} + +bool sdmmc_cmd_read_multiblock(sd_handle_t hsd) +{ + return sdio_send_cmd(hsd->instance, REQ_MULTREAD, hsd->sdcard.rca, &(hsd->sdcard.abend)); +} + +bool sdmmc_cmd_app(sd_handle_t hsd) +{ + return sdio_send_cmd(hsd->instance, 55 | RSP_1, hsd->sdcard.rca, &(hsd->sdcard.abend)); +} + +bool sdmmc_acmd_op_cond(sd_handle_t hsd, uint32_t voltage) +{ + /* SEND CMD55 APP_CMD with RCA */ + if (sdmmc_cmd_app(hsd)) { + /* Send CMD41 */ + if (sdio_send_cmd(hsd->instance, 41 | RSP_3, voltage, &(hsd->sdcard.abend))) { + return true; + } + } + return false; } /************************* HAL ************************************/ - -static void sd_poweron(sd_handle_t hsd) +static bool sd_type_identification(sd_handle_t hsd) { - sdmmc_go_idle_state(hsd->instance); - sdmmc_send_if_cond(hsd->instance); - if (hsd->instance[SDCMD] == 0x08) { - hsd->sdcard.type = CARD_V2; - HAL_LOG("SD 2.0\n"); + uint8_t retry = hsd->cfg.identification_retry; + while (retry-- > 0) + { + /* CMD0: GO_IDLE_STATE */ + sdmmc_cmd_go_idle_state(hsd); + + /* CMD8: SEND_IF_COND: Command available only on V2.0 cards */ + if (sdmmc_cmd_send_if_cond(hsd)) { + if (sdio_get_cmd_rsp(hsd->instance) == 0x08) { + hsd->sdcard.type = CARD_V2; + HAL_LOG("SD 2.0\n"); + return true; + } + continue; + } + if (sdmmc_acmd_op_cond(hsd, 0x00ff8000)) { + hsd->sdcard.type = CARD_V1; + HAL_LOG("SD 1.0\n"); + return true; + } + hal_mdelay(20); } + return false; +} + +static bool sd_go_ready_try(sd_handle_t hsd) +{ + uint32_t tmp = 0; + switch (hsd->sdcard.type) + { + case CARD_V1: + sdmmc_acmd_op_cond(hsd, 0x00ff8000); + break; + + case CARD_V2: + sdmmc_acmd_op_cond(hsd, 0x40ff8000); + break; + default: + break; + } + + if (0 == (hsd->instance[SDARG3] & BIT(31))) { + return false; // no ready + } + + if ((hsd->sdcard.type == CARD_V2) && (hsd->instance[SDARG3] & BIT(30))) { + HAL_LOG("SDHC\n"); + hsd->sdcard.flag_sdhc = 1; + } + + return true; +} + +static bool sd_go_ready(sd_handle_t hsd) +{ + if (hsd->sdcard.type == CARD_INVAL) { + return false; + } + + uint8_t retry = hsd->cfg.go_ready_retry; + while (retry-- > 0) + { + if (sd_go_ready_try(hsd) == true) { + return true; + } + hal_mdelay(20); + } + + return false; +} + +static bool sd_poweron(sd_handle_t hsd) +{ + if (sd_type_identification(hsd) == false) { + HAL_LOG("card invalid\n"); + return false; + } + + if (sd_go_ready(hsd) == false) { + HAL_LOG("no ready\n"); + return false; + } + + return true; +} + +static void sd_init_card(sd_handle_t hsd) +{ + /* Send CMD2 ALL_SEND_CID */ + sdmmc_cmd_all_send_cid(hsd); + /* Send CMD3 SET_REL_ADDR */ + sdmmc_cmd_set_rel_addr(hsd); + /* Send CMD9 SEND_CSD */ + sdmmc_cmd_send_csd(hsd); + /* Select the Card */ + sdmmc_cmd_select_card(hsd); + + hsd->init.clock_div = 3; + hsd->init.clock_power_save = SDMMC_CLOCK_POWER_SAVE_ENABLE; + + sdio_init(hsd->instance, &(hsd->init)); +} + +static bool sd_read_wait(sd_handle_t hsd) +{ + bool ret = false; + hal_sfr_t sdiox = hsd->instance; + + + + return ret; +} + +static void sd_read_start(sd_handle_t hsd, void *buf, uint32_t lba) +{ + if (hsd->sdcard.rw_state == HAL_SD_RW_STATE_READ) { + + } else { + if (hsd->sdcard.rw_state == HAL_SD_RW_STATE_WRITE) { + + } + sdio_read_kick(hsd->instance, buf); + sdmmc_cmd_read_multiblock(hsd); + } + + hsd->sdcard.rw_state = HAL_SD_RW_STATE_READ; + // hsd->sdcard.rw_lba +} + +static bool sd_read_try(sd_handle_t hsd, void *buf, uint32_t lba) +{ + HAL_LOG("read: %08x\n", lba); + + if (hsd->sdcard.capacity < lba) { + lba = hsd->sdcard.capacity - 1; + } + sd_read_start(hsd, buf, lba); + return 0; } void hal_sd_initcard(sd_handle_t hsd) { - struct sdio_init init = {0}; hal_sfr_t sdiox = hsd->instance; - sdio_init(sdiox, &init); + hsd->init.clock_div = 119; /* SD clk 240KHz when system clk is 48MHz */ + hsd->init.clock_power_save = SDMMC_CLOCK_POWER_SAVE_DISABLE; + + sdio_init(sdiox, &(hsd->init)); sd_poweron(hsd); + sd_init_card(hsd); } WEAK void hal_sd_mspinit(sd_handle_t hsd) @@ -171,6 +362,11 @@ hal_error_t hal_sd_init(sd_handle_t hsd) return -HAL_ERROR; } + hsd->cfg.go_ready_retry = 200; + hsd->cfg.identification_retry = 5; + hsd->cfg.rw_init_retry = 3; + hsd->cfg.rw_retry = 3; + hal_sd_mspinit(hsd); hal_sd_initcard(hsd); @@ -181,4 +377,25 @@ void hal_sd_deinit(uint32_t sdx) { } +bool hal_sd_read(sd_handle_t hsd, void *buf, uint32_t lba) +{ + uint8_t init_retry = hsd->cfg.rw_init_retry; + + while (init_retry-- > 0) + { + uint8_t retry = hsd->cfg.rw_retry; + while (retry-- > 0) + { + if (sd_read_try(hsd, buf, lba)) { + return true; + } + } + hsd->sdcard.state = HAL_SD_STATE_INVAL; + + hal_mdelay(20); + } + + return false; +} + #endif