12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061 |
- /**************************************************************************//**
- *
- * @copyright (C) 2020 Nuvoton Technology Corp. All rights reserved.
- *
- * SPDX-License-Identifier: Apache-2.0
- *
- * Change Logs:
- * Date Author Notes
- * 2021-11-19 Wayne First version
- *
- ******************************************************************************/
- #include "rtconfig.h"
- #if defined(BSP_USING_SDH)
- #include <rtdevice.h>
- #include <drivers/mmcsd_core.h>
- #include <drivers/sdio.h>
- #include "NuMicro.h"
- #include "drv_common.h"
- #define LOG_TAG "drv.sdio"
- #undef DBG_ENABLE
- #define DBG_SECTION_NAME LOG_TAG
- #define DBG_LEVEL LOG_LVL_INFO
- #define DBG_COLOR
- #include <rtdbg.h>
- #define SDH_ALIGN_LEN 64
- #define SDH_BUFF_SIZE (512*1024)
- enum
- {
- SDH_START = -1,
- #if defined(BSP_USING_SDH0)
- SDH0_IDX,
- #endif
- #if defined(BSP_USING_SDH1)
- SDH1_IDX,
- #endif
- SDH_CNT
- };
- struct nu_sdh
- {
- struct rt_mmcsd_host *host;
- char *name;
- SDH_T *base;
- IRQn_Type irqn;
- uint32_t rstidx;
- uint32_t modid;
- uint8_t *cachebuf;
- struct rt_event event;
- };
- typedef struct nu_sdh *nu_sdh_t;
- /* Private variables ------------------------------------------------------------*/
- #if defined(BSP_USING_SDH0)
- rt_align(SDH_ALIGN_LEN)
- static uint8_t g_au8CacheBuf_SDH0[SDH_BUFF_SIZE];
- #endif
- #if defined(BSP_USING_SDH1)
- rt_align(SDH_ALIGN_LEN)
- static uint8_t g_au8CacheBuf_SDH1[SDH_BUFF_SIZE];
- #endif
- static struct nu_sdh nu_sdh_arr [] =
- {
- #if defined(BSP_USING_SDH0)
- {
- .name = "sdh0",
- .base = SDH0,
- .irqn = SDH0_IRQn,
- .rstidx = SDH0_RST,
- .modid = SDH0_MODULE,
- .cachebuf = g_au8CacheBuf_SDH0,
- },
- #endif
- #if defined(BSP_USING_SDH1)
- {
- .name = "sdh1",
- .base = SDH1,
- .irqn = SDH1_IRQn,
- .rstidx = SDH1_RST,
- .modid = SDH1_MODULE,
- .cachebuf = g_au8CacheBuf_SDH1,
- },
- #endif
- }; /* struct nu_sdh nu_sdh_arr [] */
- static uint32_t nu_sdh_get_cmd_resptype(uint32_t rt_resp_type)
- {
- uint32_t nu_resptype = 0;
- switch (rt_resp_type)
- {
- case RESP_NONE:
- nu_resptype = MMC_RSP_NONE;
- break;
- case RESP_R1:
- nu_resptype = MMC_RSP_R1;
- break;
- case RESP_R1B:
- nu_resptype = MMC_RSP_R1b;
- break;
- case RESP_R2:
- nu_resptype = MMC_RSP_R2;
- break;
- case RESP_R3:
- nu_resptype = MMC_RSP_R3;
- break;
- case RESP_R4:
- nu_resptype = MMC_RSP_R4;
- break;
- case RESP_R6:
- nu_resptype = MMC_RSP_R6;
- break;
- case RESP_R7:
- nu_resptype = MMC_RSP_R7;
- break;
- case RESP_R5:
- nu_resptype = MMC_RSP_R5;
- break;
- default:
- nu_resptype = 0xffffffff;
- }
- return nu_resptype ;
- }
- static void nu_sdh_send_commanddone(SDH_T *sdh, struct mmc_cmd *cmd)
- {
- if (cmd->resp_type & MMC_RSP_136)
- {
- /* CRC is stripped so we need to do some shifting. */
- cmd->response[0] = (sdh->RESP67 << 8) | sdh->S_RESP45.B3;
- cmd->response[1] = (sdh->RESP45 << 8) | sdh->S_RESP23.B3;
- cmd->response[2] = (sdh->RESP23 << 8) | sdh->S_RESP01.B3;
- cmd->response[3] = (sdh->RESP01 << 8);
- }
- else
- {
- cmd->response[0] = sdh->RESP01;
- cmd->response[1] = cmd->response[2] = cmd->response[3] = 0;
- }
- }
- static int nu_sdh_xfer_data(SDH_T *sdh, struct mmc_data *data)
- {
- uint32_t start_addr, timeout;
- if (data->flags & DATA_DIR_READ)
- {
- start_addr = (uint32_t)data->dest;
- }
- else
- {
- start_addr = (uint32_t)data->src;
- }
- timeout = 1000000;
- while (!sdh->S_NORMAL_INT_STAT.XFER_COMPLETE) /* SDHCI_INT_DATA_END? */
- {
- if (sdh->S_NORMAL_INT_STAT.ERR_INTERRUPT == 1)
- return -1;
- if (sdh->S_NORMAL_INT_STAT.DMA_INTERRUPT) /* SDHCI_INT_DMA_END */
- {
- sdh->S_NORMAL_INT_STAT.DMA_INTERRUPT = 1; /* Clear SDHCI_INT_DMA_END */
- start_addr &= ~(SDH_BLOCK_SIZE * 1024 - 1);
- start_addr += SDH_BLOCK_SIZE * 1024;
- sdh->SDMASA = start_addr;
- }
- if (timeout-- > 0)
- rt_hw_us_delay(10);
- else
- return -2;
- }
- return 0;
- }
- static void nu_sdh_list_errors(SDH_T *sdh)
- {
- if (sdh->S_NORMAL_INT_STAT.ERR_INTERRUPT)
- {
- LOG_D("Error List:");
- if (sdh->S_ERROR_INT_STAT.CMD_TOUT_ERR)
- LOG_D("\tCMD_TOUT_ERR.");
- if (sdh->S_ERROR_INT_STAT.CMD_CRC_ERR)
- LOG_D("\tCMD_CRC_ERR.");
- if (sdh->S_ERROR_INT_STAT.CMD_END_BIT_ERR)
- LOG_D("\tCMD_END_BIT_ERR.");
- if (sdh->S_ERROR_INT_STAT.CMD_IDX_ERR)
- LOG_D("\tCMD_IDX_ERR.");
- if (sdh->S_ERROR_INT_STAT.DATA_TOUT_ERR)
- LOG_D("\tDATA_TOUT_ERR.");
- if (sdh->S_ERROR_INT_STAT.DATA_CRC_ERR)
- LOG_D("\tDATA_CRC_ERR.");
- if (sdh->S_ERROR_INT_STAT.DATA_END_BIT_ERR)
- LOG_D("\tDATA_END_BIT_ERR.");
- if (sdh->S_ERROR_INT_STAT.CUR_LMT_ERR)
- LOG_D("\tCUR_LMT_ERR.");
- if (sdh->S_ERROR_INT_STAT.AUTO_CMD_ERR)
- LOG_D("\tAUTO_CMD_ERR.");
- if (sdh->S_ERROR_INT_STAT.ADMA_ERR)
- LOG_D("\tADMA_ERR.");
- if (sdh->S_ERROR_INT_STAT.TUNING_ERR)
- LOG_D("\tTUNING_ERR.");
- if (sdh->S_ERROR_INT_STAT.RESP_ERR)
- LOG_D("\tRESP_ERR.");
- if (sdh->S_ERROR_INT_STAT.BOOT_ACK_ERR)
- LOG_D("\tBOOT_ACK_ERR.");
- if (sdh->S_ERROR_INT_STAT.VENDOR_ERR1)
- LOG_D("\tVENDOR_ERR1.");
- if (sdh->S_ERROR_INT_STAT.VENDOR_ERR2)
- LOG_D("\tVENDOR_ERR2.");
- if (sdh->S_ERROR_INT_STAT.VENDOR_ERR3)
- LOG_D("\tVENDOR_ERR3.");
- }
- }
- /**
- * @brief This function send command.
- * @param sdio rthw_sdio
- * @param pkg sdio package
- * @retval None
- */
- static int nu_sdh_send_command(SDH_T *sdh, struct mmc_cmd *cmd, struct mmc_data *data)
- {
- int ret;
- uint32_t mask, flags, mode;
- volatile unsigned int time = 0;
- volatile unsigned int cmd_timeout, stat;
- LOG_D("[CMD:%d ARG:0x%08x] RESP_TYPE:0x%08x rw:%c addr:0x%08x len:%d blksize:%d",
- cmd->cmdidx,
- cmd->cmdarg,
- cmd->resp_type,
- data ? (data->flags & DATA_DIR_WRITE ? 'w' : 'r') : '-',
- data ? data->src : 0,
- data ? data->blocks * data->blocksize : 0,
- data ? data->blocksize : 0);
- mask = 0x3; /* SDH_CMD_INHIBIT | SDH_DATA_INHIBIT */
- if (cmd->cmdidx == MMC_CMD_STOP_TRANSMISSION)
- mask &= ~0x2; /* SDH_DATA_INHIBIT */
- ret = SD_GetBusStatus(sdh, mask);
- if (ret)
- {
- LOG_E("ERROR: Busy %d\n", ret);
- ret = __LINE__;
- goto exit_nu_sdh_send_command;
- }
- /* SDHCI_INT_ALL_MASK */
- sdh->NORMAL_INT_STAT = 0xFFFF;
- sdh->ERROR_INT_STAT = 0xFFFF;
- mask = 0x1; /* SDHCI_INT_RESPONSE */
- if (!(cmd->resp_type & MMC_RSP_PRESENT))
- flags = SDH_CMD_RESP_NONE;
- else if (cmd->resp_type & MMC_RSP_136)
- flags = SDH_CMD_RESP_LONG;
- else if (cmd->resp_type & MMC_RSP_BUSY)
- {
- flags = SDH_CMD_RESP_SHORT_BUSY;
- if (data)
- mask |= 0x2; /* SDHCI_INT_DATA_END */
- }
- else
- flags = SDH_CMD_RESP_SHORT;
- if (cmd->resp_type & MMC_RSP_CRC)
- flags |= SDH_CMD_CRC;
- if (cmd->resp_type & MMC_RSP_OPCODE)
- flags |= SDH_CMD_INDEX;
- /* Set Transfer mode regarding to data flag */
- if (data)
- {
- flags |= SDH_CMD_DATA;
- sdh->S_TOUT_CTRL.TOUT_CNT = 0xE;
- mode = 0x2; /* SDHCI_TRNS_BLK_CNT_EN */
- if (data->blocks > 1)
- mode |= 0x20; /* SDHCI_TRNS_MULTI */
- if (data->flags & DATA_DIR_READ)
- {
- mode |= 0x10; /* SDHCI_TRNS_READ */
- sdh->SDMASA = (uint32_t)data->dest;
- }
- else
- {
- sdh->SDMASA = (uint32_t)data->src;
- }
- mode |= 0x1;
- sdh->S_HOST_CTRL1.DMA_SEL = 0; //SDMA is selected
- /* 512 Kbytes SDMA Buffer Boundary */
- sdh->S_BLOCKSIZE.SDMA_BUF_BDARY = 0x7;
- /* Set Block Size */
- sdh->S_BLOCKSIZE.XFER_BLOCK_SIZE = data->blocksize;
- /* Set Block count */
- sdh->S_BLOCKCOUNT.BLOCK_CNT = data->blocks;
- /* Set transfer mode */
- sdh->XFER_MODE = mode;
- }
- else if (cmd->resp_type & MMC_RSP_BUSY)
- {
- sdh->S_TOUT_CTRL.TOUT_CNT = 0xE;
- }
- sdh->ARGUMENT = cmd->cmdarg;
- sdh->CMD = ((cmd->cmdidx & 0xff) << 8) | (flags & 0xff);
- cmd_timeout = 10000000;
- time = 0;
- do
- {
- stat = sdh->NORMAL_INT_STAT;
- if (stat & 0x8000) /* SDHCI_INT_ERROR */
- break;
- if (time > cmd_timeout)
- {
- ret = __LINE__;
- LOG_E("[%s %d] timeout stat=%04x, mask=%04x", __func__, __LINE__, stat, mask);
- goto exit_nu_sdh_send_command;
- }
- time++;
- }
- while ((stat & mask) != mask);
- if ((stat & (0x8000 | mask)) == mask)
- {
- //LOG_D("[%s %d] Done. cmdid=%d restore", __func__, __LINE__, cmd->cmdidx);
- nu_sdh_send_commanddone(sdh, cmd);
- nu_sdh_list_errors(sdh);
- /* Send data */
- if (data)
- {
- ret = nu_sdh_xfer_data(sdh, data);
- }
- stat = sdh->ERROR_INT_STAT;
- sdh->NORMAL_INT_STAT = mask;
- ret = 0;
- }
- else
- {
- //LOG_E("[%s %d] Error. cmdid=%d not restored %08x %08x", __func__, __LINE__, cmd->cmdidx, stat, mask);
- ret = __LINE__;
- nu_sdh_list_errors(sdh);
- goto exit_nu_sdh_send_command;
- }
- /* SDHCI_INT_ALL_MASK */
- sdh->NORMAL_INT_STAT = 0xFFFF;
- sdh->ERROR_INT_STAT = 0xFFFF;
- if (ret)
- {
- LOG_E("[%s %d] ret=%d cmd->cmdidx=%d, error=0x%x", __func__, __LINE__, ret, cmd->cmdidx, stat);
- ret = __LINE__;
- goto exit_nu_sdh_send_command;
- }
- return 0;
- exit_nu_sdh_send_command:
- SDH_Reset(sdh, SDH_RESET_CMD);
- SDH_Reset(sdh, SDH_RESET_DATA);
- //LOG_E("[%s %d] cmdid=%d error line=%d", __func__, __LINE__, cmd->cmdidx, ret);
- return ret;
- }
- /**
- * @brief This function send sdio request.
- * @param host rt_mmcsd_host
- * @param req request
- * @retval None
- */
- static void nu_sdh_request(struct rt_mmcsd_host *host, struct rt_mmcsd_req *req)
- {
- nu_sdh_t sdh = (nu_sdh_t)host->private_data;
- RT_ASSERT(host);
- RT_ASSERT(req);
- if (host->card)
- {
- if (host->card->card_type == CARD_TYPE_MMC)
- {
- sdh->base->S_EMMC_CTRL.CARD_IS_EMMC = 1;
- sdh->base->S_EMMC_CTRL.DISABLE_DATA_CRC_CHK = 1;
- }
- else
- {
- sdh->base->S_EMMC_CTRL.CARD_IS_EMMC = 0;
- sdh->base->S_EMMC_CTRL.DISABLE_DATA_CRC_CHK = 0;
- }
- }
- if (req->cmd != RT_NULL)
- {
- struct mmc_cmd cmd;
- LOG_D("[%s%s%s%s%s]REQ: CMD:%d ARG:0x%08x RESP_TYPE:0x%08x, 0x%08x",
- (host->card == RT_NULL) ? "Unknown" : "",
- (host->card) && (host->card->card_type == CARD_TYPE_MMC) ? "MMC" : "",
- (host->card) && (host->card->card_type == CARD_TYPE_SD) ? "SD" : "",
- (host->card) && (host->card->card_type == CARD_TYPE_SDIO) ? "SDIO" : "",
- (host->card) && (host->card->card_type == CARD_TYPE_SDIO_COMBO) ? "SDIO_COMBO" : "",
- req->cmd->cmd_code,
- req->cmd->arg,
- resp_type(req->cmd),
- nu_sdh_get_cmd_resptype(resp_type(req->cmd)));
- rt_memset(&cmd, 0, sizeof(struct mmc_cmd));
- cmd.cmdidx = req->cmd->cmd_code;
- cmd.cmdarg = req->cmd->arg;
- cmd.resp_type = nu_sdh_get_cmd_resptype(resp_type(req->cmd));
- if (req->data != RT_NULL)
- {
- struct mmc_data data;
- rt_uint32_t size;
- rt_int32_t IsNonaligned = 0;
- LOG_D("[%s]REQ: BUF:%08x FLAGS:0x%08x BLKSIZE:%d, BLKCOUNT:%d",
- sdh->name,
- req->data->buf,
- req->data->flags,
- req->data->blksize,
- req->data->blks);
- rt_memset(&data, 0, sizeof(struct mmc_data));
- data.dest = (char *)req->data->buf;
- data.flags = req->data->flags;
- data.blocksize = req->data->blksize;
- data.blocks = req->data->blks;
- size = data.blocksize * data.blocks;
- RT_ASSERT(size <= SDH_BUFF_SIZE);
- IsNonaligned = (((rt_uint32_t)data.dest & (SDH_ALIGN_LEN - 1)) > 0) ? 1 : 0;
- if (IsNonaligned)
- {
- data.dest = (char *)sdh->cachebuf;
- if (data.flags & DATA_DIR_WRITE)
- {
- LOG_D("Un-aligned, prepare into cache buf(%d)", size);
- rt_memcpy(data.dest, req->data->buf, size);
- }
- }
- rt_hw_cpu_dcache_clean_inv((void *)data.dest, size);
- req->cmd->err = nu_sdh_send_command(sdh->base, &cmd, &data);
- rt_hw_cpu_dcache_invalidate((void *)data.dest, size);
- if (!req->cmd->err && IsNonaligned)
- {
- if (data.flags & DATA_DIR_READ)
- {
- LOG_D("Un-aligned, restore from cache buf(%d)", size);
- rt_memcpy(req->data->buf, data.dest, size);
- }
- }
- LOG_HEX("data.dest", 16, (void *)data.dest, size);
- }
- else
- {
- req->cmd->err = nu_sdh_send_command(sdh->base, &cmd, NULL);
- }
- /* Report response words */
- req->cmd->resp[3] = cmd.response[3];
- req->cmd->resp[2] = cmd.response[2];
- req->cmd->resp[1] = cmd.response[1];
- req->cmd->resp[0] = cmd.response[0];
- LOG_HEX("req->cmd->resp", 16, (void *)&req->cmd->resp[0], 16);
- }
- if (req->stop != RT_NULL)
- {
- struct mmc_cmd stop;
- rt_memset(&stop, 0, sizeof(struct mmc_cmd));
- stop.cmdidx = req->stop->cmd_code;
- stop.cmdarg = req->stop->arg;
- stop.resp_type = nu_sdh_get_cmd_resptype(resp_type(req->stop));
- req->stop->err = nu_sdh_send_command(sdh->base, &stop, NULL);
- /* Report response words */
- req->stop->resp[3] = stop.response[3];
- req->stop->resp[2] = stop.response[2];
- req->stop->resp[1] = stop.response[1];
- req->stop->resp[0] = stop.response[0];
- LOG_HEX("req->stop->resp", 16, (void *)&req->stop->resp[0], 16);
- }
- mmcsd_req_complete(host);
- }
- /**
- * @brief This function config sdio.
- * @param host rt_mmcsd_host
- * @param io_cfg rt_mmcsd_io_cfg
- * @retval None
- */
- static void nu_sdh_iocfg(struct rt_mmcsd_host *host, struct rt_mmcsd_io_cfg *io_cfg)
- {
- nu_sdh_t NuSdh;
- rt_uint32_t clk = io_cfg->clock;
- SDH_T *sdh;
- RT_ASSERT(host);
- RT_ASSERT(io_cfg);
- NuSdh = (nu_sdh_t)host->private_data;
- sdh = NuSdh->base;
- LOG_D("[%s]clk:%d width:%s%s%s power:%s%s%s",
- NuSdh->name,
- 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" : "");
- /* Bus width */
- switch (io_cfg->bus_width)
- {
- case MMCSD_BUS_WIDTH_1:
- case MMCSD_BUS_WIDTH_4:
- case MMCSD_BUS_WIDTH_8:
- SDH_SetBusWidth(sdh, 1 << io_cfg->bus_width);
- break;
- default:
- break;
- }
- /* Power */
- switch (io_cfg->power_mode)
- {
- case MMCSD_POWER_UP:
- case MMCSD_POWER_ON:
- SDH_SetPower(sdh, 1);
- break;
- case MMCSD_POWER_OFF:
- SDH_SetPower(sdh, 0);
- break;
- default:
- break;
- }
- /* Clock */
- if (clk > host->freq_max)
- clk = host->freq_max;
- if (clk < host->freq_min)
- clk = host->freq_min;
- if (clk)
- {
- uint32_t u32SrcFreqInHz = 0, u32ModRealFreqInHz;
- uint32_t u32ModSrcIdx = CLK_GetModuleClockSource(NuSdh->modid);
- switch (u32ModSrcIdx)
- {
- case 0: // From SYSPLL
- u32SrcFreqInHz = CLK_GetPLLClockFreq(SYSPLL);
- break;
- default: // From APLL
- u32SrcFreqInHz = CLK_GetPLLClockFreq(APLL);
- break;
- }
- u32ModRealFreqInHz = SDH_SetClock(sdh, u32SrcFreqInHz, clk);
- u32ModRealFreqInHz = u32ModRealFreqInHz; //Avoid warning
- LOG_D("[%s] SrcClock: %d kHz, ExceptedFreq: %d kHz, RealFreq: %d kHz", NuSdh->name, u32SrcFreqInHz / 1000, clk / 1000, u32ModRealFreqInHz / 1000);
- }
- }
- /**
- * @brief This function detect sdcard.
- * @param host rt_mmcsd_host
- * @retval 0x01
- */
- static rt_int32_t nu_sdh_card_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
- */
- static void nu_sdh_isr(int vector, void *param)
- {
- nu_sdh_t sdh = (nu_sdh_t)param;
- struct rt_mmcsd_host *host = sdh->host;
- SDH_T *base = sdh->base;
- volatile unsigned int isr = base->NORMAL_INT_STAT;
- /* We just catch card detection here. */
- if (isr & 0xc0)
- {
- /* ready to change */
- mmcsd_change(host);
- base->NORMAL_INT_STAT = 0xC0;
- }
- }
- /**
- * @brief This function update sdh interrupt.
- * @param host rt_mmcsd_host
- * @param enable
- * @retval None
- */
- void nu_sdh_irq_update(struct rt_mmcsd_host *host, rt_int32_t enable)
- {
- nu_sdh_t sdh = (nu_sdh_t)host->private_data;
- SDH_T *sdh_base = sdh->base;
- if (enable)
- {
- LOG_D("Enable %s irq", sdh->name);
- /* Enable only interrupts served by the SD controller */
- /* sdh_base->NORMAL_INT_STAT_EN = 0x00FB; */
- sdh_base->S_NORMAL_INT_STAT_EN.CMD_COMPLETE_STAT_EN = 1;
- sdh_base->S_NORMAL_INT_STAT_EN.XFER_COMPLETE_STAT_EN = 1;
- sdh_base->S_NORMAL_INT_STAT_EN.DMA_INTERRUPT_STAT_EN = 1;
- sdh_base->S_NORMAL_INT_STAT_EN.BUF_WR_READY_STAT_EN = 1;
- sdh_base->S_NORMAL_INT_STAT_EN.BUF_RD_READY_STAT_EN = 1;
- sdh_base->S_NORMAL_INT_STAT_EN.CARD_INSERTION_STAT_EN = 1;
- sdh_base->S_NORMAL_INT_STAT_EN.CARD_REMOVAL_STAT_EN = 1;
- /* sdh_base->ERROR_INT_STAT_EN = 0x0271; */
- sdh_base->S_ERROR_INT_STAT_EN.CMD_TOUT_ERR_STAT_EN = 1;
- sdh_base->S_ERROR_INT_STAT_EN.DATA_TOUT_ERR_STAT_EN = 1;
- sdh_base->S_ERROR_INT_STAT_EN.DATA_CRC_ERR_STAT_EN = 1;
- sdh_base->S_ERROR_INT_STAT_EN.DATA_END_BIT_ERR_STAT_EN = 1;
- sdh_base->S_ERROR_INT_STAT_EN.ADMA_ERR_STAT_EN = 1;
- /* Mask all interrupt sources */
- /* sdh_base->NORMAL_INT_SIGNAL_EN = 0xC0; */
- sdh_base->S_NORMAL_INT_SIGNAL_EN.CARD_INSERTION_SIGNAL_EN = 1;
- sdh_base->S_NORMAL_INT_SIGNAL_EN.CARD_REMOVAL_SIGNAL_EN = 1;
- sdh_base->ERROR_INT_SIGNAL_EN = 0;
- //sdh_base->NORMAL_INT_STAT_EN = 0x7FFF;
- //sdh_base->ERROR_INT_STAT_EN = 0xFFFF;
- //sdh_base->NORMAL_INT_SIGNAL_EN=0x7FFF;
- //sdh_base->ERROR_INT_SIGNAL_EN=0xFFFF;
- }
- else
- {
- LOG_D("Disable %s irq", sdh->name);
- sdh_base->NORMAL_INT_STAT_EN = 0x0;
- sdh_base->ERROR_INT_STAT_EN = 0x0;
- sdh_base->NORMAL_INT_SIGNAL_EN = 0x0;
- sdh_base->ERROR_INT_SIGNAL_EN = 0x0;
- }
- }
- static const struct rt_mmcsd_host_ops ops =
- {
- nu_sdh_request,
- nu_sdh_iocfg,
- nu_sdh_card_detect,
- nu_sdh_irq_update,
- };
- /**
- * @brief This function create mmcsd host.
- * @param sdh nu_sdh_t
- * @retval nuvton
- */
- void nu_sdh_host_initial(nu_sdh_t sdh)
- {
- struct rt_mmcsd_host *host;
- rt_err_t ret = RT_EOK;
- host = mmcsd_alloc_host();
- RT_ASSERT(host != RT_NULL);
- ret = rt_event_init(&sdh->event, "sdh_event", RT_IPC_FLAG_FIFO);
- RT_ASSERT(ret == RT_EOK);
- /* Reset sdh at first. */
- SDH_Reset(sdh->base, SDH_RESET_ALL);
- /* set host default attributes */
- host->ops = &ops;
- host->freq_min = 200 * 1000;
- host->freq_max = 50 * 1000 * 1000;
- host->valid_ocr = VDD_30_31 | VDD_31_32 | VDD_32_33 | VDD_33_34; // | VDD_165_195;
- host->flags = MMCSD_BUSWIDTH_4 | MMCSD_MUTBLKWRITE | MMCSD_SUP_SDIO_IRQ | MMCSD_SUP_HIGHSPEED;
- host->max_seg_size = SDH_BUFF_SIZE;
- host->max_dma_segs = 1;
- host->max_blk_size = SDH_BLOCK_SIZE;
- host->max_blk_count = (SDH_BUFF_SIZE / SDH_BLOCK_SIZE);
- /* link up host and sdio */
- host->private_data = sdh;
- sdh->host = host;
- /* Set initial state: high speed */
- sdh->base->S_HOST_CTRL1.HIGH_SPEED_EN = 1;
- /* Set SDR50 mode */
- sdh->base->S_HOST_CTRL2.UHS_MODE_SEL = 2;
- /* Install ISR. */
- rt_hw_interrupt_install(sdh->irqn, nu_sdh_isr, (void *)sdh, sdh->name);
- rt_hw_interrupt_umask(sdh->irqn);
- /* Enable interrupt. */
- nu_sdh_irq_update(host, 1);
- /* ready to change */
- mmcsd_change(host);
- }
- void nu_sd_attach(void)
- {
- int i;
- /* ready to change */
- for (i = (SDH_START + 1); i < SDH_CNT; i++)
- {
- if (nu_sdh_arr[i].host)
- mmcsd_change(nu_sdh_arr[i].host);
- }
- }
- MSH_CMD_EXPORT(nu_sd_attach, attach card);
- void nu_sd_regdump(void)
- {
- int i;
- /* ready to change */
- for (i = (SDH_START + 1); i < SDH_CNT; i++)
- {
- if (nu_sdh_arr[i].host)
- SDH_DumpReg(nu_sdh_arr[i].base);
- }
- }
- MSH_CMD_EXPORT(nu_sd_regdump, dump sdh registers);
- static int rt_hw_sdh_init(void)
- {
- int i;
- for (i = (SDH_START + 1); i < SDH_CNT; i++)
- {
- CLK_EnableModuleClock(nu_sdh_arr[i].modid);
- SYS_ResetModule(nu_sdh_arr[i].rstidx);
- nu_sdh_host_initial(&nu_sdh_arr[i]);
- }
- return 0;
- }
- INIT_DEVICE_EXPORT(rt_hw_sdh_init);
- /* A simple MBR writer. */
- struct mbr
- {
- uint8_t code[440];
- union
- {
- uint32_t disk_signature;
- struct
- {
- uint32_t disk_signature_B0: 8;
- uint32_t disk_signature_B1: 8;
- uint32_t disk_signature_B2: 8;
- uint32_t disk_signature_B3: 8;
- } s_disk_signature;
- };
- uint16_t unused;
- struct mbr_partition
- {
- uint8_t status;
- uint8_t first_cylinder;
- uint8_t first_head;
- uint8_t first_sector;
- uint8_t partition_type;
- uint8_t last_cylinder;
- uint8_t last_head;
- uint8_t last_sector;
- union
- {
- uint32_t first_sector_lba;
- struct
- {
- uint32_t first_sector_lba_B0: 8;
- uint32_t first_sector_lba_B1: 8;
- uint32_t first_sector_lba_B2: 8;
- uint32_t first_sector_lba_B3: 8;
- } s_first_sector_lba;
- };
- union
- {
- uint32_t sectors ;
- struct
- {
- uint32_t sectors_B0: 8;
- uint32_t sectors_B1: 8;
- uint32_t sectors_B2: 8;
- uint32_t sectors_B3: 8;
- } s_sectors;
- };
- } partition[4];
- uint16_t mbr_signature;
- } __attribute__((packed));
- #define MBR_SIGNATURE 0xAA55
- #define MBR_STATUS_BOOTABLE 0x80
- #define le2(a, o) ((a)[o] << 0 | (a)[(o)+1] << 8)
- #define le4(a, o) (le2(a,o) | (a)[(o)+2] << 16 | (a)[(o)+3] << 24)
- static int nu_sd_mbr_read(const char *devname)
- {
- rt_device_t mmc_device = RT_NULL;
- rt_err_t ret;
- struct rt_device_blk_geometry geo = {0};
- struct mbr *psMbr = RT_NULL;
- if ((mmc_device = rt_device_find(devname)) == RT_NULL)
- {
- LOG_E("find device %s failed!\n", devname);
- goto fail_nu_sd_mbr_read;
- }
- if (rt_device_open(mmc_device, RT_DEVICE_OFLAG_RDWR) != RT_EOK)
- {
- LOG_E("open device %s failed!\n", devname);
- mmc_device = RT_NULL;
- goto fail_nu_sd_mbr_read;
- }
- if (rt_device_control(mmc_device, RT_DEVICE_CTRL_BLK_GETGEOME, &geo) != RT_EOK)
- {
- LOG_E("control device %s failed!\n", devname);
- goto fail_nu_sd_mbr_read;
- }
- LOG_I("device information:\n");
- LOG_I("sector size : %d byte\n", geo.bytes_per_sector);
- LOG_I("sector count : %d \n", geo.sector_count);
- LOG_I("block size : %d byte\n", geo.block_size);
- LOG_I("MBR size : %d byte\n", sizeof(struct mbr));
- psMbr = rt_malloc(sizeof(struct mbr));
- if (psMbr == RT_NULL)
- {
- LOG_E("no memory for mbr buffer!\n");
- goto fail_nu_sd_mbr_read;
- }
- rt_memset(psMbr, 0, sizeof(struct mbr));
- ret = rt_device_read(mmc_device, 0, psMbr, 1);
- if (ret != 1)
- {
- LOG_E("read device %s %d failed!\n", devname, ret);
- goto fail_nu_sd_mbr_read;
- }
- LOG_I("disk_signature = %08x\n", psMbr->disk_signature);
- LOG_I("unused = %02x\n", psMbr->unused);
- for (int i = 0; i < 4; i++)
- {
- LOG_I("[%d] status = %02x\n", i, psMbr->partition[i].status);
- LOG_I("[%d] first_cylinder = %d\n", i, psMbr->partition[i].first_cylinder);
- LOG_I("[%d] first_head = %d\n", i, psMbr->partition[i].first_head);
- LOG_I("[%d] first_sector = %d\n", i, psMbr->partition[i].first_sector);
- LOG_I("[%d] partition_type = %02x\n", i, psMbr->partition[i].partition_type);
- LOG_I("[%d] last_cylinder = %d\n", i, psMbr->partition[i].last_cylinder);
- LOG_I("[%d] last_head = %d\n", i, psMbr->partition[i].last_head);
- LOG_I("[%d] last_sector = %d\n", i, psMbr->partition[i].last_sector);
- LOG_I("[%d] first_sector_lba = %u\n", i, psMbr->partition[i].first_sector_lba);
- LOG_I("[%d] sectors = %u\n", i, psMbr->partition[i].sectors);
- }
- LOG_I("signature = %02x\n", psMbr->mbr_signature);
- rt_free(psMbr);
- rt_device_close(mmc_device);
- return 0;
- fail_nu_sd_mbr_read:
- if (psMbr != RT_NULL)
- rt_free(psMbr);
- if (mmc_device != RT_NULL)
- rt_device_close(mmc_device);
- return -1;
- }
- int nu_sd_mbr_dump(int argc, char *argv[])
- {
- // argc=1: string, mmcblk device name.
- if (argc != 2)
- return -1;
- return nu_sd_mbr_read(argv[1]);
- }
- MSH_CMD_EXPORT(nu_sd_mbr_dump, dump sd card device);
- static int nu_sd_mbr_write(const char *devname, int32_t u32Sectors)
- {
- rt_device_t mmc_device = RT_NULL;
- rt_err_t ret;
- struct rt_device_blk_geometry geo;
- struct mbr *psMbr = RT_NULL;
- if ((mmc_device = rt_device_find(devname)) == RT_NULL)
- {
- LOG_E("find device %s failed!\n", devname);
- goto fail_nu_sd_mbr_write;
- }
- if (rt_device_open(mmc_device, RT_DEVICE_OFLAG_RDWR) != RT_EOK)
- {
- mmc_device = RT_NULL;
- LOG_E("open device %s failed!\n", devname);
- goto fail_nu_sd_mbr_write;
- }
- rt_memset(&geo, 0, sizeof(geo));
- ret = rt_device_control(mmc_device, RT_DEVICE_CTRL_BLK_GETGEOME, &geo);
- if (ret != RT_EOK)
- {
- LOG_E("control device %s failed!\n", devname);
- goto fail_nu_sd_mbr_write;
- }
- LOG_I("device information:\n");
- LOG_I("sector size : %d byte\n", geo.bytes_per_sector);
- LOG_I("sector count : %d \n", geo.sector_count);
- LOG_I("block size : %d byte\n", geo.block_size);
- if (u32Sectors >= geo.sector_count)
- {
- LOG_E("no enough sectors for reserved. %s failed!\n", devname);
- goto fail_nu_sd_mbr_write;
- }
- psMbr = rt_malloc(sizeof(struct mbr));
- if (psMbr == RT_NULL)
- {
- LOG_E("no memory for mbr buffer!\n");
- goto fail_nu_sd_mbr_write;
- }
- rt_memset(psMbr, 0, sizeof(struct mbr));
- psMbr->disk_signature = 0xa8e7d068;
- psMbr->mbr_signature = MBR_SIGNATURE;
- psMbr->partition[0].status = 0;
- //psMbr->partition[0].first_cylinder = 0x00;
- //psMbr->partition[0].first_head = 0x21;
- //psMbr->partition[0].first_sector = 0x21;
- psMbr->partition[0].partition_type = 0x0C;
- //psMbr->partition[0].last_head = 0xFE;
- //psMbr->partition[0].last_sector = 0x3F;
- //psMbr->partition[0].last_cylinder = 0xFF;
- psMbr->partition[0].first_sector_lba = u32Sectors;
- psMbr->partition[0].sectors = geo.sector_count - u32Sectors;
- ret = rt_device_write(mmc_device, 0, psMbr, 1);
- if (ret != 1)
- {
- LOG_E("write device %s %d failed!\n", devname, ret);
- goto fail_nu_sd_mbr_write;
- }
- fail_nu_sd_mbr_write:
- if (psMbr != RT_NULL)
- rt_free(psMbr);
- if (mmc_device)
- rt_device_close(mmc_device);
- return -1;
- }
- int nu_sd_mbr_layout(int argc, char *argv[])
- {
- // argc=1: string, mmcblk device name.
- // argc=2: Reserved sectors for bootable code and remains sectors are for elm mounting.
- if (argc != 3)
- return -1;
- return nu_sd_mbr_write((const char *)argv[1], atoi(argv[2]));
- }
- MSH_CMD_EXPORT(nu_sd_mbr_layout, layout sd device);
- #endif
|