123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920 |
- /**************************************************************************//**
- * @file fmi.c
- * @brief N9H30 FMI eMMC driver source file
- *
- * @note
- * SPDX-License-Identifier: Apache-2.0
- * Copyright (C) 2018 Nuvoton Technology Corp. All rights reserved.
- *****************************************************************************/
- #include <stdio.h>
- #include <stdlib.h>
- #include <string.h>
- #include "N9H30.h"
- #include "nu_sys.h"
- #include "nu_fmi.h"
- /** @addtogroup N9H30_Device_Driver N9H30 Device Driver
- @{
- */
- /** @addtogroup N9H30_FMI_Driver FMI Driver
- @{
- */
- /** @addtogroup N9H30_FMI_EXPORTED_FUNCTIONS FMI Exported Functions
- @{
- */
- /// @cond HIDDEN_SYMBOLS
- #define FMI_BLOCK_SIZE 512
- // global variables
- // For response R3 (such as ACMD41, CRC-7 is invalid; but FMI controller will still
- // calculate CRC-7 and get an error result, software should ignore this error and clear INTSTS [CRC_IF] flag
- // _fmi_uR3_CMD is the flag for it. 1 means software should ignore CRC-7 error
- unsigned int _fmi_uR3_CMD = 0;
- unsigned int _fmi_uR7_CMD = 0;
- unsigned char volatile _fmi_eMMCDataReady = FALSE;
- unsigned char *_fmi_peMMCBuffer;
- unsigned int gFMIReferenceClock;
- #ifdef __ICCARM__
- #pragma data_alignment = 4096
- unsigned char _fmi_uceMMCBuffer[512];
- #else
- unsigned char _fmi_uceMMCBuffer[512] __attribute__((aligned(4096)));
- #endif
- int emmc_ok = 0;
- unsigned char peMMC_offset = 0;
- EMMC_INFO_T eMMC;
- void eMMC_CheckRB()
- {
- while (1)
- {
- outpw(REG_FMI_EMMCCTL, inpw(REG_FMI_EMMCCTL) | FMI_EMMCCTL_CLK8OEN_Msk);
- while (inpw(REG_FMI_EMMCCTL) & FMI_EMMCCTL_CLK8OEN_Msk);
- if (inpw(REG_FMI_EMMCINTSTS) & FMI_EMMCINTSTS_DAT0STS_Msk)
- break;
- }
- }
- int eMMC_Command(EMMC_INFO_T *pSD, unsigned char ucCmd, unsigned int uArg)
- {
- volatile int buf;
- outpw(REG_FMI_EMMCCMD, uArg);
- buf = (inpw(REG_FMI_EMMCCTL) & (~FMI_EMMCCTL_CMDCODE_Msk)) | (ucCmd << 8) | (FMI_EMMCCTL_COEN_Msk);
- outpw(REG_FMI_EMMCCTL, buf);
- while (inpw(REG_FMI_EMMCCTL) & FMI_EMMCCTL_COEN_Msk)
- {
- if (pSD->IsCardInsert == FALSE)
- return EMMC_NO_CARD;
- }
- return 0;
- }
- int eMMC_CmdAndRsp(EMMC_INFO_T *pSD, unsigned char ucCmd, unsigned int uArg, int ntickCount)
- {
- volatile int buf;
- outpw(REG_FMI_EMMCCMD, uArg);
- buf = (inpw(REG_FMI_EMMCCTL) & (~FMI_EMMCCTL_CMDCODE_Msk)) | (ucCmd << 8) | (FMI_EMMCCTL_COEN_Msk | FMI_EMMCCTL_RIEN_Msk);
- outpw(REG_FMI_EMMCCTL, buf);
- if (ntickCount > 0)
- {
- while (inpw(REG_FMI_EMMCCTL) & FMI_EMMCCTL_RIEN_Msk)
- {
- if (ntickCount-- == 0)
- {
- outpw(REG_FMI_EMMCCTL, inpw(REG_FMI_EMMCCTL) | FMI_EMMCCTL_CTLRST_Msk); // reset SD engine
- return 2;
- }
- if (pSD->IsCardInsert == FALSE)
- return EMMC_NO_CARD;
- }
- }
- else
- {
- while (inpw(REG_FMI_EMMCCTL) & FMI_EMMCCTL_RIEN_Msk)
- {
- if (pSD->IsCardInsert == FALSE)
- return EMMC_NO_CARD;
- }
- }
- if (_fmi_uR7_CMD)
- {
- if (((inpw(REG_FMI_EMMCRESP1) & 0xff) != 0x55) && ((inpw(REG_FMI_EMMCRESP0) & 0xf) != 0x01))
- {
- _fmi_uR7_CMD = 0;
- return EMMC_CMD8_ERROR;
- }
- }
- if (!_fmi_uR3_CMD)
- {
- if (inpw(REG_FMI_EMMCINTSTS) & FMI_EMMCINTSTS_CRC7_Msk) // check CRC7
- return 0;
- else
- return EMMC_CRC7_ERROR;
- }
- else // ignore CRC error for R3 case
- {
- _fmi_uR3_CMD = 0;
- outpw(REG_FMI_EMMCINTSTS, FMI_EMMCINTSTS_CRCIF_Msk);
- return 0;
- }
- }
- int eMMC_Swap32(int val)
- {
- int buf;
- buf = val;
- val <<= 24;
- val |= (buf << 8) & 0xff0000;
- val |= (buf >> 8) & 0xff00;
- val |= (buf >> 24) & 0xff;
- return val;
- }
- // Get 16 bytes CID or CSD
- int eMMC_CmdAndRsp2(EMMC_INFO_T *pSD, unsigned char ucCmd, unsigned int uArg, unsigned int *puR2ptr)
- {
- unsigned int i, buf;
- unsigned int tmpBuf[5];
- outpw(REG_FMI_EMMCCMD, uArg);
- buf = (inpw(REG_FMI_EMMCCTL) & (~FMI_EMMCCTL_CMDCODE_Msk)) | (ucCmd << 8) | (FMI_EMMCCTL_COEN_Msk | FMI_EMMCCTL_R2EN_Msk);
- outpw(REG_FMI_EMMCCTL, buf);
- while (inpw(REG_FMI_EMMCCTL) & FMI_EMMCCTL_R2EN_Msk)
- {
- if (pSD->IsCardInsert == FALSE)
- return EMMC_NO_CARD;
- }
- if (inpw(REG_FMI_EMMCINTSTS) & FMI_EMMCINTSTS_CRC7_Msk)
- {
- for (i = 0; i < 5; i++)
- tmpBuf[i] = eMMC_Swap32(*(int *)(FMI_BA + i * 4));
- for (i = 0; i < 4; i++)
- *puR2ptr++ = ((tmpBuf[i] & 0x00ffffff) << 8) | ((tmpBuf[i + 1] & 0xff000000) >> 24);
- return 0;
- }
- else
- return EMMC_CRC7_ERROR;
- }
- int eMMC_CmdAndRspDataIn(EMMC_INFO_T *pSD, unsigned char ucCmd, unsigned int uArg)
- {
- volatile int buf;
- outpw(REG_FMI_EMMCCMD, uArg);
- buf = (inpw(REG_FMI_EMMCCTL) & (~FMI_EMMCCTL_CMDCODE_Msk)) | (ucCmd << 8) | (FMI_EMMCCTL_COEN_Msk | FMI_EMMCCTL_RIEN_Msk | FMI_EMMCCTL_DIEN_Msk);
- outpw(REG_FMI_EMMCCTL, buf);
- while (inpw(REG_FMI_EMMCCTL) & FMI_EMMCCTL_RIEN_Msk)
- {
- if (pSD->IsCardInsert == FALSE)
- return EMMC_NO_CARD;
- }
- while (inpw(REG_FMI_EMMCCTL) & FMI_EMMCCTL_DIEN_Msk)
- {
- if (pSD->IsCardInsert == FALSE)
- return EMMC_NO_CARD;
- }
- if (!(inpw(REG_FMI_EMMCINTSTS) & FMI_EMMCINTSTS_CRC7_Msk)) // check CRC7
- {
- return EMMC_CRC7_ERROR;
- }
- if (!(inpw(REG_FMI_EMMCINTSTS) & FMI_EMMCINTSTS_CRC16_Msk)) // check CRC16
- {
- return EMMC_CRC16_ERROR;
- }
- return 0;
- }
- // there are 3 bits for divider N0, maximum is 8
- #define EMMC_CLK_DIV0_MAX 8
- // there are 8 bits for divider N1, maximum is 256
- #define EMMC_CLK_DIV1_MAX 256
- void eMMC_Set_clock(unsigned int clock_khz)
- {
- UINT32 rate, div0, div1, i;
- //--- calculate the rate that 2 divider have to divide
- // _fmi_uFMIReferenceClock is the input clock with unit KHz like as APLL/UPLL and
- if (clock_khz > gFMIReferenceClock)
- {
- //sysprintf("ERROR: wrong eMMC clock %dKHz since it is faster than input clock %dKHz !\n", clock_khz, gFMIReferenceClock);
- return;
- }
- rate = gFMIReferenceClock / clock_khz;
- // choose slower clock if system clock cannot divisible by wanted clock
- if (gFMIReferenceClock % clock_khz != 0)
- rate++;
- if (rate > (EMMC_CLK_DIV0_MAX * EMMC_CLK_DIV1_MAX)) // the maximum divider for EMMC_CLK is (EMMC_CLK_DIV0_MAX * EMMC_CLK_DIV1_MAX)
- {
- //sysprintf("ERROR: wrong SD clock %dKHz since it is slower than input clock %dKHz/%d !\n", clock_khz, gFMIReferenceClock, EMMC_CLK_DIV0_MAX * EMMC_CLK_DIV1_MAX);
- return;
- }
- //--- choose a suitable value for first divider
- for (div0 = EMMC_CLK_DIV0_MAX; div0 > 0; div0--) // choose the maximum value if can exact division
- {
- if (rate % div0 == 0)
- break;
- }
- if (div0 == 0) // cannot exact division
- {
- // if rate <= EMMC_CLK_DIV1_MAX, set div0 to 1 since div1 can exactly divide input clock
- div0 = (rate <= EMMC_CLK_DIV1_MAX) ? 1 : EMMC_CLK_DIV0_MAX;
- }
- //--- calculate the second divider
- div1 = rate / div0;
- div1 &= 0xFF;
- //sysprintf("Set_clock(): wanted clock=%d, rate=%d, div0=%d, div1=%d\n", clock_khz, rate, div0, div1);
- //--- setup register
- outpw(REG_CLK_DIVCTL3, (inpw(REG_CLK_DIVCTL3) & ~0x18) | (0x3 << 3));
- outpw(REG_CLK_DIVCTL3, (inpw(REG_CLK_DIVCTL3) & ~0x7) | (div0 - 1));
- outpw(REG_CLK_DIVCTL3, (inpw(REG_CLK_DIVCTL3) & ~0xff00) | ((div1 - 1) << 8));
- for (i = 0; i < 1000; i++); // waiting for clock become stable
- return;
- }
- // Initial
- int eMMC_Init(EMMC_INFO_T *pSD)
- {
- int volatile i, status;
- unsigned int resp;
- unsigned int CIDBuffer[4];
- unsigned int volatile u32CmdTimeOut;
- // set the clock to 300KHz
- eMMC_Set_clock(300);
- // power ON 74 clock
- outpw(REG_FMI_EMMCCTL, inpw(REG_FMI_EMMCCTL) | FMI_EMMCCTL_CLK74OEN_Msk);
- while (inpw(REG_FMI_EMMCCTL) & FMI_EMMCCTL_CLK74OEN_Msk);
- eMMC_Command(pSD, 0, 0); // reset all cards
- for (i = 0x1000; i > 0; i--);
- // initial SDHC
- _fmi_uR7_CMD = 1;
- u32CmdTimeOut = 5000;
- i = eMMC_CmdAndRsp(pSD, 8, 0x00000155, u32CmdTimeOut);
- if (i == 0)
- {
- // SD 2.0
- eMMC_CmdAndRsp(pSD, 55, 0x00, u32CmdTimeOut);
- _fmi_uR3_CMD = 1;
- eMMC_CmdAndRsp(pSD, 41, 0x40ff8000, u32CmdTimeOut); // 2.7v-3.6v
- resp = inpw(REG_FMI_EMMCRESP0);
- while (!(resp & 0x00800000)) // check if card is ready
- {
- eMMC_CmdAndRsp(pSD, 55, 0x00, u32CmdTimeOut);
- _fmi_uR3_CMD = 1;
- eMMC_CmdAndRsp(pSD, 41, 0x40ff8000, u32CmdTimeOut); // 3.0v-3.4v
- resp = inpw(REG_FMI_EMMCRESP0);
- }
- if (resp & 0x00400000)
- pSD->CardType = EMMC_TYPE_SD_HIGH;
- else
- pSD->CardType = EMMC_TYPE_SD_LOW;
- }
- else
- {
- // SD 1.1
- eMMC_Command(pSD, 0, 0); // reset all cards
- for (i = 0x100; i > 0; i--);
- i = eMMC_CmdAndRsp(pSD, 55, 0x00, u32CmdTimeOut);
- if (i == 2) // MMC memory
- {
- eMMC_Command(pSD, 0, 0); // reset
- for (i = 0x100; i > 0; i--);
- _fmi_uR3_CMD = 1;
- if (eMMC_CmdAndRsp(pSD, 1, 0x40ff8000, u32CmdTimeOut) != 2) // eMMC memory
- {
- resp = inpw(REG_FMI_EMMCRESP0);
- while (!(resp & 0x00800000)) // check if card is ready
- {
- _fmi_uR3_CMD = 1;
- eMMC_CmdAndRsp(pSD, 1, 0x40ff8000, u32CmdTimeOut); // high voltage
- resp = inpw(REG_FMI_EMMCRESP0);
- }
- if (resp & 0x00400000)
- pSD->CardType = EMMC_TYPE_EMMC;
- else
- pSD->CardType = EMMC_TYPE_MMC;
- }
- else
- {
- pSD->CardType = EMMC_TYPE_UNKNOWN;
- return EMMC_ERR_DEVICE;
- }
- }
- else if (i == 0) // SD Memory
- {
- _fmi_uR3_CMD = 1;
- eMMC_CmdAndRsp(pSD, 41, 0x00ff8000, u32CmdTimeOut); // 3.0v-3.4v
- resp = inpw(REG_FMI_EMMCRESP0);
- while (!(resp & 0x00800000)) // check if card is ready
- {
- eMMC_CmdAndRsp(pSD, 55, 0x00, u32CmdTimeOut);
- _fmi_uR3_CMD = 1;
- eMMC_CmdAndRsp(pSD, 41, 0x00ff8000, u32CmdTimeOut); // 3.0v-3.4v
- resp = inpw(REG_FMI_EMMCRESP0);
- }
- pSD->CardType = EMMC_TYPE_SD_LOW;
- }
- else
- {
- pSD->CardType = EMMC_TYPE_UNKNOWN;
- return EMMC_INIT_ERROR;
- }
- }
- // CMD2, CMD3
- if (pSD->CardType != EMMC_TYPE_UNKNOWN)
- {
- eMMC_CmdAndRsp2(pSD, 2, 0x00, CIDBuffer);
- if ((pSD->CardType == EMMC_TYPE_MMC) || (pSD->CardType == EMMC_TYPE_EMMC))
- {
- if ((status = eMMC_CmdAndRsp(pSD, 3, 0x10000, 0)) != 0) // set RCA
- return status;
- pSD->RCA = 0x10000;
- }
- else
- {
- if ((status = eMMC_CmdAndRsp(pSD, 3, 0x00, 0)) != 0) // get RCA
- return status;
- else
- pSD->RCA = (inpw(REG_FMI_EMMCRESP0) << 8) & 0xffff0000;
- }
- }
- #if 0
- if (pSD->CardType == EMMC_TYPE_SD_HIGH)
- sysprintf("This is high capacity SD memory card\n");
- if (pSD->CardType == EMMC_TYPE_SD_LOW)
- sysprintf("This is standard capacity SD memory card\n");
- if (pSD->CardType == EMMC_TYPE_EMMC)
- sysprintf("This is eMMC memory card\n");
- #endif
- return 0;
- }
- int eMMC_SwitchToHighSpeed(EMMC_INFO_T *pSD)
- {
- int volatile status = 0;
- unsigned short current_comsumption, busy_status0;
- outpw(REG_FMI_DMASA, (unsigned int)_fmi_peMMCBuffer); // set DMA transfer starting address
- outpw(REG_FMI_EMMCBLEN, 63); // 512 bit
- if ((status = eMMC_CmdAndRspDataIn(pSD, 6, 0x00ffff01)) != 0)
- return 1;
- current_comsumption = _fmi_peMMCBuffer[0] << 8 | _fmi_peMMCBuffer[1];
- if (!current_comsumption)
- return 1;
- busy_status0 = _fmi_peMMCBuffer[28] << 8 | _fmi_peMMCBuffer[29];
- if (!busy_status0) // function ready
- {
- outpw(REG_FMI_DMASA, (unsigned int)_fmi_peMMCBuffer); // set DMA transfer starting address
- outpw(REG_FMI_EMMCBLEN, 63); // 512 bit
- if ((status = eMMC_CmdAndRspDataIn(pSD, 6, 0x80ffff01)) != 0)
- return 1;
- // function change timing: 8 clocks
- outpw(REG_FMI_EMMCCTL, inpw(REG_FMI_EMMCCTL) | FMI_EMMCCTL_CLK8OEN_Msk);
- while (inpw(REG_FMI_EMMCCTL) & FMI_EMMCCTL_CLK8OEN_Msk);
- current_comsumption = _fmi_peMMCBuffer[0] << 8 | _fmi_peMMCBuffer[1];
- if (!current_comsumption)
- return 1;
- return 0;
- }
- else
- return 1;
- }
- int eMMC_SelectCardType(EMMC_INFO_T *pSD)
- {
- int volatile status = 0;
- //unsigned int arg;
- if ((status = eMMC_CmdAndRsp(pSD, 7, pSD->RCA, 0)) != 0)
- return status;
- eMMC_CheckRB();
- // if SD card set 4bit
- if (pSD->CardType == EMMC_TYPE_SD_HIGH)
- {
- _fmi_peMMCBuffer = (unsigned char *)((unsigned int)_fmi_uceMMCBuffer);
- outpw(REG_FMI_DMASA, (unsigned int)_fmi_peMMCBuffer); // set DMA transfer starting address
- outpw(REG_FMI_EMMCBLEN, 0x07); // 64 bit
- if ((status = eMMC_CmdAndRsp(pSD, 55, pSD->RCA, 0)) != 0)
- return status;
- if ((status = eMMC_CmdAndRspDataIn(pSD, 51, 0x00)) != 0)
- return status;
- if ((_fmi_uceMMCBuffer[0] & 0xf) == 0x2)
- {
- status = eMMC_SwitchToHighSpeed(pSD);
- if (status == 0)
- {
- /* divider */
- eMMC_Set_clock(SDHC_FREQ);
- }
- }
- if ((status = eMMC_CmdAndRsp(pSD, 55, pSD->RCA, 0)) != 0)
- return status;
- if ((status = eMMC_CmdAndRsp(pSD, 6, 0x02, 0)) != 0) // set bus width
- return status;
- outpw(REG_FMI_EMMCCTL, inpw(REG_FMI_EMMCCTL) | FMI_EMMCCTL_DBW_Msk);
- }
- else if (pSD->CardType == EMMC_TYPE_SD_LOW)
- {
- _fmi_peMMCBuffer = (unsigned char *)((unsigned int)_fmi_uceMMCBuffer);
- outpw(REG_FMI_DMASA, (unsigned int) _fmi_peMMCBuffer); // set DMA transfer starting address
- outpw(REG_FMI_EMMCBLEN, 0x07); // 64 bit
- if ((status = eMMC_CmdAndRsp(pSD, 55, pSD->RCA, 0)) != 0)
- return status;
- if ((status = eMMC_CmdAndRspDataIn(pSD, 51, 0x00)) != 0)
- return status;
- // set data bus width. ACMD6 for SD card, SDCR_DBW for host.
- if ((status = eMMC_CmdAndRsp(pSD, 55, pSD->RCA, 0)) != 0)
- return status;
- if ((status = eMMC_CmdAndRsp(pSD, 6, 0x02, 0)) != 0) // set bus width
- return status;
- outpw(REG_FMI_EMMCCTL, inpw(REG_FMI_EMMCCTL) | FMI_EMMCCTL_DBW_Msk);
- }
- else if (pSD->CardType == EMMC_TYPE_MMC)
- {
- outpw(REG_FMI_EMMCCTL, inpw(REG_FMI_EMMCCTL) & ~FMI_EMMCCTL_DBW_Msk);
- }
- else if (pSD->CardType == EMMC_TYPE_EMMC)
- {
- //--- sent CMD6 to MMC card to set bus width to 4 bits mode, skymedi only support 1-bit
- // set CMD6 argument Access field to 3, Index to 183, Value to 1 (4-bit mode)
- // arg = (3 << 24) | (183 << 16) | (1 << 8);
- // if ((status = eMMC_CmdAndRsp(pSD, 6, arg, 0)) != 0)
- // return status;
- // eMMC_CheckRB();
- // outpw(REG_FMI_EMMCCTL, inpw(REG_FMI_EMMCCTL)| FMI_EMMCCTL_DBW_Msk);
- outpw(REG_FMI_EMMCCTL, inpw(REG_FMI_EMMCCTL) & ~FMI_EMMCCTL_DBW_Msk);
- }
- if ((status = eMMC_CmdAndRsp(pSD, 16, FMI_BLOCK_SIZE, 0)) != 0) // set block length
- return status;
- outpw(REG_FMI_EMMCBLEN, FMI_BLOCK_SIZE - 1); // set the block size
- eMMC_Command(pSD, 7, 0);
- outpw(REG_FMI_EMMCCTL, inpw(REG_FMI_EMMCCTL) | FMI_EMMCCTL_CLK8OEN_Msk);
- while (inpw(REG_FMI_EMMCCTL) & FMI_EMMCCTL_CLK8OEN_Msk);
- outpw(REG_FMI_EMMCINTEN, inpw(REG_FMI_EMMCINTEN) | FMI_EMMCINTEN_BLKDIEN_Msk);
- return 0;
- }
- void eMMC_Get_info(EMMC_INFO_T *pSD)
- {
- unsigned int R_LEN, C_Size, MULT, size;
- unsigned int Buffer[4];
- unsigned char *ptr;
- eMMC_CmdAndRsp2(pSD, 9, pSD->RCA, Buffer);
- if ((pSD->CardType == EMMC_TYPE_MMC) || (pSD->CardType == EMMC_TYPE_EMMC))
- {
- // for MMC/eMMC card
- if ((Buffer[0] & 0xc0000000) == 0xc0000000)
- {
- // CSD_STRUCTURE [127:126] is 3
- // CSD version depend on EXT_CSD register in eMMC v4.4 for card size > 2GB
- eMMC_CmdAndRsp(pSD, 7, pSD->RCA, 0);
- ptr = (unsigned char *)((unsigned int)_fmi_uceMMCBuffer);
- outpw(REG_FMI_DMASA, (unsigned int)ptr); // set DMA transfer starting address
- outpw(REG_FMI_EMMCBLEN, 511); // read 512 bytes for EXT_CSD
- if (eMMC_CmdAndRspDataIn(pSD, 8, 0x00) != 0)
- return;
- eMMC_Command(pSD, 7, 0);
- outpw(REG_FMI_EMMCCTL, inpw(REG_FMI_EMMCCTL) | FMI_EMMCCTL_CLK8OEN_Msk);
- while (inpw(REG_FMI_EMMCCTL) & FMI_EMMCCTL_CLK8OEN_Msk);
- pSD->totalSectorN = (*(unsigned int *)(ptr + 212));
- pSD->diskSize = pSD->totalSectorN / 2;
- }
- else
- {
- // CSD version v1.0/1.1/1.2 in eMMC v4.4 spec for card size <= 2GB
- R_LEN = (Buffer[1] & 0x000f0000) >> 16;
- C_Size = ((Buffer[1] & 0x000003ff) << 2) | ((Buffer[2] & 0xc0000000) >> 30);
- MULT = (Buffer[2] & 0x00038000) >> 15;
- size = (C_Size + 1) * (1 << (MULT + 2)) * (1 << R_LEN);
- pSD->diskSize = size / 1024;
- pSD->totalSectorN = size / 512;
- }
- }
- else
- {
- if (Buffer[0] & 0xc0000000)
- {
- C_Size = ((Buffer[1] & 0x0000003f) << 16) | ((Buffer[2] & 0xffff0000) >> 16);
- size = (C_Size + 1) * 512; // Kbytes
- pSD->diskSize = size;
- pSD->totalSectorN = size << 1;
- }
- else
- {
- R_LEN = (Buffer[1] & 0x000f0000) >> 16;
- C_Size = ((Buffer[1] & 0x000003ff) << 2) | ((Buffer[2] & 0xc0000000) >> 30);
- MULT = (Buffer[2] & 0x00038000) >> 15;
- size = (C_Size + 1) * (1 << (MULT + 2)) * (1 << R_LEN);
- pSD->diskSize = size / 1024;
- pSD->totalSectorN = size / 512;
- }
- }
- pSD->sectorSize = 512;
- //sysprintf("The size is %d KB\n", pSD->diskSize);
- }
- /// @endcond HIDDEN_SYMBOLS
- /**
- * @brief This function use to tell FMI eMMC engine clock.
- *
- * @param[in] u32Clock Set current eMMC engine clock
- *
- * @return None
- */
- void FMI_SetReferenceClock(unsigned int u32Clock)
- {
- gFMIReferenceClock = u32Clock; // kHz
- }
- /**
- * @brief This function use to reset FMI eMMC function.
- *
- * @return None
- */
- void eMMC_Open(void)
- {
- // enable DMAC
- outpw(REG_FMI_DMACTL, FMI_DMACTL_DMARST_Msk);
- while (inpw(REG_FMI_DMACTL) & FMI_DMACTL_DMARST_Msk);
- outpw(REG_FMI_DMACTL, FMI_DMACTL_DMAEN_Msk);
- //Reset Global
- outpw(REG_FMI_CTL, FMI_CTL_CTLRST_Msk);
- while (inpw(REG_FMI_CTL) & FMI_CTL_CTLRST_Msk);
- // enable eMMC
- outpw(REG_FMI_CTL, FMI_CTL_EMMCEN_Msk);
- outpw(REG_FMI_EMMCCTL, inpw(REG_FMI_EMMCCTL) | FMI_EMMCCTL_CTLRST_Msk);
- while (inpw(REG_FMI_EMMCCTL) & FMI_EMMCCTL_CTLRST_Msk);
- memset(&eMMC, 0, sizeof(EMMC_INFO_T));
- eMMC.IsCardInsert = 1;
- }
- /**
- * @brief This function use to initial eMMC card.
- *
- * @return None
- */
- void eMMC_Probe(void)
- {
- // Disable FMI interrupt
- outpw(REG_FMI_INTEN, 0);
- outpw(REG_FMI_EMMCCTL, inpw(REG_FMI_EMMCCTL) & ~(FMI_EMMCCTL_SDNWR_Msk | FMI_EMMCCTL_BLKCNT_Msk | FMI_EMMCCTL_DBW_Msk));
- outpw(REG_FMI_EMMCCTL, inpw(REG_FMI_EMMCCTL) | (0x09 << FMI_EMMCCTL_SDNWR_Pos) | (0x01 << FMI_EMMCCTL_BLKCNT_Pos));
- if (eMMC_Init(&eMMC) < 0)
- return;
- /* divider */
- if ((eMMC.CardType == EMMC_TYPE_MMC) || (eMMC.CardType == EMMC_TYPE_EMMC))
- eMMC_Set_clock(MMC_FREQ);
- else
- eMMC_Set_clock(SD_FREQ);
- eMMC_Get_info(&eMMC);
- if (eMMC_SelectCardType(&eMMC))
- return;
- emmc_ok = 1;
- }
- /**
- * @brief This function use to read data from eMMC card.
- *
- * @param[out] pu8BufAddr The buffer to receive the data from eMMC card.
- * @param[in] u32StartSec The start read sector address.
- * @param[in] u32SecCount The the read sector number of data
- *
- * @return None
- */
- unsigned int eMMC_Read(unsigned char *pu8BufAddr, unsigned int u32StartSec, unsigned int u32SecCount)
- {
- char volatile bIsSendCmd = FALSE;
- unsigned int volatile reg;
- int volatile i, loop, status;
- unsigned int blksize = FMI_BLOCK_SIZE;
- EMMC_INFO_T *pSD;
- pSD = &eMMC;
- //--- check input parameters
- if (u32SecCount == 0)
- return EMMC_SELECT_ERROR;
- if ((status = eMMC_CmdAndRsp(pSD, 7, pSD->RCA, 0)) != 0)
- return status;
- eMMC_CheckRB();
- outpw(REG_FMI_EMMCBLEN, blksize - 1); // the actual byte count is equal to (BLEN+1)
- if ((pSD->CardType == EMMC_TYPE_SD_HIGH) || (pSD->CardType == EMMC_TYPE_EMMC))
- outpw(REG_FMI_EMMCCMD, u32StartSec);
- else
- outpw(REG_FMI_EMMCCMD, u32StartSec * blksize);
- outpw(REG_FMI_DMASA, (unsigned int)pu8BufAddr);
- loop = u32SecCount / 255;
- for (i = 0; i < loop; i++)
- {
- _fmi_eMMCDataReady = FALSE;
- reg = inpw(REG_FMI_EMMCCTL) & ~FMI_EMMCCTL_CMDCODE_Msk;
- reg = reg | 0xff0000;
- if (bIsSendCmd == FALSE)
- {
- outpw(REG_FMI_EMMCCTL, reg | (18 << 8) | (FMI_EMMCCTL_COEN_Msk | FMI_EMMCCTL_RIEN_Msk | FMI_EMMCCTL_DIEN_Msk));
- bIsSendCmd = TRUE;
- }
- else
- outpw(REG_FMI_EMMCCTL, reg | FMI_EMMCCTL_DIEN_Msk);
- while (!_fmi_eMMCDataReady)
- {
- // if ((inpw(REG_FMI_EMMCINTSTS) & FMI_EMMCINTSTS_BLKDIF_Msk) && (!(inpw(REG_FMI_EMMCCTL) & FMI_EMMCCTL_DIEN_Msk))) {
- // outpw(REG_FMI_EMMCINTSTS, FMI_EMMCINTSTS_BLKDIF_Msk);
- // break;
- // }
- if (pSD->IsCardInsert == FALSE)
- return EMMC_NO_CARD;
- }
- if (!(inpw(REG_FMI_EMMCINTSTS) & FMI_EMMCINTSTS_CRC7_Msk)) // check CRC7
- {
- return EMMC_CRC7_ERROR;
- }
- if (!(inpw(REG_FMI_EMMCINTSTS) & FMI_EMMCINTSTS_CRC16_Msk)) // check CRC16
- {
- return EMMC_CRC16_ERROR;
- }
- }
- loop = u32SecCount % 255;
- if (loop != 0)
- {
- _fmi_eMMCDataReady = FALSE;
- reg = inpw(REG_FMI_EMMCCTL) & (~FMI_EMMCCTL_CMDCODE_Msk);
- reg = reg & (~FMI_EMMCCTL_BLKCNT_Msk);
- reg |= (loop << 16);
- if (bIsSendCmd == FALSE)
- {
- outpw(REG_FMI_EMMCCTL, reg | (18 << 8) | (FMI_EMMCCTL_COEN_Msk | FMI_EMMCCTL_RIEN_Msk | FMI_EMMCCTL_DIEN_Msk));
- bIsSendCmd = TRUE;
- }
- else
- outpw(REG_FMI_EMMCCTL, reg | FMI_EMMCCTL_DIEN_Msk);
- while (!_fmi_eMMCDataReady)
- {
- // if ((inpw(REG_FMI_EMMCINTSTS) & FMI_EMMCINTSTS_BLKDIF_Msk) && (!(inpw(REG_FMI_EMMCCTL) & FMI_EMMCCTL_DIEN_Msk))) {
- // outpw(REG_FMI_EMMCINTSTS, FMI_EMMCINTSTS_BLKDIF_Msk);
- // break;
- // }
- if (pSD->IsCardInsert == FALSE)
- return EMMC_NO_CARD;
- }
- if (!(inpw(REG_FMI_EMMCINTSTS) & FMI_EMMCINTSTS_CRC7_Msk)) // check CRC7
- {
- return EMMC_CRC7_ERROR;
- }
- if (!(inpw(REG_FMI_EMMCINTSTS) & FMI_EMMCINTSTS_CRC16_Msk)) // check CRC16
- {
- return EMMC_CRC16_ERROR;
- }
- }
- if (eMMC_CmdAndRsp(pSD, 12, 0, 0)) // stop command
- {
- //sysprintf("stop command fail !!\n");
- return EMMC_CRC7_ERROR;
- }
- eMMC_CheckRB();
- eMMC_Command(pSD, 7, 0);
- outpw(REG_FMI_EMMCCTL, inpw(REG_FMI_EMMCCTL) | FMI_EMMCCTL_CLK8OEN_Msk);
- while (inpw(REG_FMI_EMMCCTL) & FMI_EMMCCTL_CLK8OEN_Msk);
- return 0;
- }
- /**
- * @brief This function use to write data to eMMC card.
- *
- * @param[in] pu8BufAddr The buffer to send the data to SD card.
- * @param[in] u32StartSec The start write sector address.
- * @param[in] u32SecCount The the write sector number of data.
- *
- * @return - \ref EMMC_SELECT_ERROR u32SecCount is zero.
- * - \ref EMMC_NO_CARD SD card be removed.
- * - \ref EMMC_CRC_ERROR CRC error happen.
- * - \ref EMMC_CRC7_ERROR CRC7 error happen.
- * - \ref Successful Write data to eMMC card success.
- */
- unsigned int eMMC_Write(unsigned char *pu8BufAddr, unsigned int u32StartSec, unsigned int u32SecCount)
- {
- char volatile bIsSendCmd = FALSE;
- unsigned int volatile reg;
- int volatile i, loop, status;
- EMMC_INFO_T *pSD;
- pSD = &eMMC;
- //--- check input parameters
- if (u32SecCount == 0)
- return EMMC_SELECT_ERROR;
- if ((status = eMMC_CmdAndRsp(pSD, 7, pSD->RCA, 0)) != 0)
- return status;
- eMMC_CheckRB();
- // According to SD Spec v2.0/ eMMC v4.4, the write CMD block size MUST be 512, and the start address MUST be 512*n.
- outpw(REG_FMI_EMMCBLEN, FMI_BLOCK_SIZE - 1); // set the block size
- if ((pSD->CardType == EMMC_TYPE_SD_HIGH) || (pSD->CardType == EMMC_TYPE_EMMC))
- outpw(REG_FMI_EMMCCMD, u32StartSec);
- else
- outpw(REG_FMI_EMMCCMD, u32StartSec * FMI_BLOCK_SIZE); // set start address for CMD
- outpw(REG_FMI_DMASA, (unsigned int)pu8BufAddr);
- loop = u32SecCount / 255; // the maximum block count is 0xFF=255
- for (i = 0; i < loop; i++)
- {
- _fmi_eMMCDataReady = FALSE;
- reg = inpw(REG_FMI_EMMCCTL) & 0xff00c080;
- reg = reg | 0xff0000;
- if (!bIsSendCmd)
- {
- outpw(REG_FMI_EMMCCTL, reg | (25 << 8) | (FMI_EMMCCTL_COEN_Msk | FMI_EMMCCTL_RIEN_Msk | FMI_EMMCCTL_DOEN_Msk));
- bIsSendCmd = TRUE;
- }
- else
- outpw(REG_FMI_EMMCCTL, reg | FMI_EMMCCTL_DOEN_Msk);
- while (!_fmi_eMMCDataReady)
- {
- // if ((inpw(REG_FMI_EMMCINTSTS) & FMI_EMMCINTSTS_BLKDIF_Msk) && (!(inpw(REG_FMI_EMMCCTL) & FMI_EMMCCTL_DOEN_Msk))) {
- // outpw(REG_FMI_EMMCINTSTS, FMI_EMMCINTSTS_BLKDIF_Msk);
- // break;
- // }
- if (pSD->IsCardInsert == FALSE)
- return EMMC_NO_CARD;
- }
- if ((inpw(REG_FMI_EMMCINTSTS) & FMI_EMMCINTSTS_CRCIF_Msk) != 0) // check CRC
- {
- outpw(REG_FMI_EMMCINTSTS, FMI_EMMCINTSTS_CRCIF_Msk);
- return EMMC_CRC_ERROR;
- }
- }
- loop = u32SecCount % 255;
- if (loop != 0)
- {
- _fmi_eMMCDataReady = FALSE;
- reg = (inpw(REG_FMI_EMMCCTL) & 0xff00c080) | (loop << 16);
- if (!bIsSendCmd)
- {
- outpw(REG_FMI_EMMCCTL, reg | (25 << 8) | (FMI_EMMCCTL_COEN_Msk | FMI_EMMCCTL_RIEN_Msk | FMI_EMMCCTL_DOEN_Msk));
- bIsSendCmd = TRUE;
- }
- else
- outpw(REG_FMI_EMMCCTL, reg | FMI_EMMCCTL_DOEN_Msk);
- while (!_fmi_eMMCDataReady)
- {
- // if ((inpw(REG_FMI_EMMCINTSTS) & FMI_EMMCINTSTS_BLKDIF_Msk) && (!(inpw(REG_FMI_EMMCCTL) & FMI_EMMCCTL_DOEN_Msk))) {
- // outpw(REG_FMI_EMMCINTSTS, FMI_EMMCINTSTS_BLKDIF_Msk);
- // break;
- // }
- if (pSD->IsCardInsert == FALSE)
- return EMMC_NO_CARD;
- }
- if ((inpw(REG_FMI_EMMCINTSTS) & FMI_EMMCINTSTS_CRCIF_Msk) != 0) // check CRC
- {
- outpw(REG_FMI_EMMCINTSTS, FMI_EMMCINTSTS_CRCIF_Msk);
- return EMMC_CRC_ERROR;
- }
- }
- outpw(REG_FMI_EMMCINTSTS, FMI_EMMCINTSTS_CRCIF_Msk);
- if (eMMC_CmdAndRsp(pSD, 12, 0, 0)) // stop command
- {
- return EMMC_CRC7_ERROR;
- }
- eMMC_CheckRB();
- eMMC_Command(pSD, 7, 0);
- outpw(REG_FMI_EMMCCTL, inpw(REG_FMI_EMMCCTL) | FMI_EMMCCTL_CLK8OEN_Msk);
- while (inpw(REG_FMI_EMMCCTL) & FMI_EMMCCTL_CLK8OEN_Msk);
- return 0;
- }
- /*@}*/ /* end of group N9H30_FMI_EXPORTED_FUNCTIONS */
- /*@}*/ /* end of group N9H30_FMI_Driver */
- /*@}*/ /* end of group N9H30_Device_Driver */
- /*** (C) COPYRIGHT 2018 Nuvoton Technology Corp. ***/
|