跳转至

MMC

MMC 特性

  • Compatible with Secure Digital Memory (SD mem-version 2.0)
  • Compatible with Secure Digital I/O (SDIO-version 3.0)
  • Compatible with embedded MultiMediaCard (eMMC-version 5.0)
  • Supports Card insertion and removal interrupt
  • Supports hardware CRC generation and error detection
  • Supports programmable baud rate
  • Supports SDIO interrupts in 1-bit and 4-bit modes
  • Supports block size of 1 to 65535 bytes
  • Supports descriptor-based internal DMA controller
  • Internal 1024-Bytes RX FIFO and 1024-Bytes TX FIFO
  • Supports 1-bit, 4-bit SD and SDIO data bus width
  • Supports 1-bit, 4-bit eMMC data bus width

模块介绍

RTOS 提供了MMC 子系统来实现对各种SD/SDIO 设备访问,MMC 子系统由上到下可以分为三层,MMC/SD card 层,MMC/SD core 层以及MMC/SD host 层,它们之间的层次关系如下所示。

MMC/SD card 层负主要是按照RTOS 块设备驱动程序的框架实现一个卡的块设备驱动。负责块设备请求的处理,以及请求队列的管理。MMC/SD core 层负责通信协议的处理,包括SD/SDIO,为上一层提供具体读写接口,同时为下一层提供host 端接口。MMC/SD host 是实现对SD/MMC 控制器相关的操作,直接操作硬件,也是主要实现部分。

image-20230731141359278

模块配置

其 menuconfig 的配置如下:

Kernel Setup --->
    Drivers Setup --->
        SoC HAL Drivers --->
            SDMMC devices --->
                [*] enable SDMMC drivers    
                -*-   enable SD
                [*]   enable SDIO
                [ ]   enable mmc
                [ ]   enable emmc
                [ ]   enable detect card
                [*]   enable dma transmission
                [*]   enable sdio irq
                [*]   enable SD Card test case.
                (64)  SD Card Align DMA Buffer Size(Kbyte).
                (0)   sdc card detect pin present value
                [*]   support SDMMC filesystem

源码结构

MMC 模块源码结构如下所示:

.
├── cmd
│   ├── cmd_sd.c
│   └── Kconfig
├── core.c
├── _core.h
├── hal
│   └── hal_ccm.c
├── hal_sdhost.c
├── hal_sdpin.c
├── Kconfig
├── Makefile
├── mmc.c
├── _mmc.h
├── osal
│   ├── Makefile
│   └── os
│       ├── FreeRTOS
│       │   ├── Makefile
│       │   ├── os_debug.c
│       │   ├── os_debug.h
│       │   ├── os_mutex.c
│       │   ├── os_queue.c
│       │   ├── os_semaphore.c
│       │   ├── os_thread.c
│       │   ├── os_timer.c
│       │   └── os_util.h
│       ├── Kconfig
│       └── Makefile
├── platform
│   └── mmc_sun20iw2p1.h
├── platform_mmc.h
├── quirks.c
├── sd.c
├── _sd_define.h
├── _sd.h
├── _sdhost.h
├── sdio.c
├── _sdio.h
├── sdio_irq.c
└── test.c

模块接口说明

SDMMC 接口

/**
 * @brief read SD card.
 * @param card:
 *        @arg card->card handler.
 * @param buf:
 *        @arg buf->for store readed data.
 * @param sblk:
 *        @arg sblk->start block num.
 * @param nblk:
 *        @arg nblk->number of blocks.
 * @retval  0 if success or other if failed.
 */
extern int32_t mmc_block_read(struct mmc_card *card, uint8_t *buf, uint64_t sblk, uint32_t nblk);

/**
 * @brief write SD card.
 * @param card:
 *        @arg card->card handler.
 * @param buf:
 *        @arg buf->data will be write.
 * @param sblk:
 *        @arg sblk->start block num.
 * @param nblk:
 *        @arg nblk->number of blocks.
 * @retval  0 if success or other if failed.
 */
extern int32_t mmc_block_write(struct mmc_card *card, const uint8_t *buf, uint64_t sblk, uint32_t nblk);

/**
 * @brief scan or rescan SD card.
 * @param card:
 *        @arg card->card handler.
 * @param sdc_id:
 *        @arg sdc_id->SDC ID which card on.
 * @retval  0 if success or other if failed.
 */
extern int32_t mmc_rescan(struct mmc_card *card, uint32_t sdc_id);

/**
 * @brief deinit SD card.
 * @param card:
 *        @arg card->card handler.
 * @retval  0 if success or other if failed.
 */
extern int32_t mmc_card_deinit(struct mmc_card *card);

/**
 * @brief malloc for card_info.
 * @param card_id:
 *        @arg card ID.
 * @retval  0 if success or other if failed.
 */
extern int32_t mmc_card_create(uint8_t card_id, SDCard_InitTypeDef *param);

/**
 * @brief free for card_info.
 * @param card_id:
 *        @arg card ID.
 * @retval  0 if success or other if failed.
 */
extern int32_t mmc_card_delete(uint8_t card_id);

/**
 * @brief get pointer of mmc_card.
 * @param card_id:
 *        @arg card ID.
 * @retval  pointer of mmc_card if success or NULL if failed.
 */
extern struct mmc_card* mmc_card_open(uint8_t card_id);

/**
 * @brief close mmc_card.
 * @param card_id:
 *        @arg card ID.
 * @retval  0 if success or other if failed.
 */
extern int32_t mmc_card_close(uint8_t card_id);
extern struct mmc_card_info* mmc_card_save(uint8_t card_id);
extern int32_t mmc_card_restore(struct mmc_card_info *s_card_info);

SDIO 接口

typedef struct mmc_card sdio_t;

/**
 *  sdio_readb - read a single byte from a SDIO function
 *  @card: SDIO to access
 *  @addr: address to read
 *  @err_ret: optional status value from transfer
 *
 *  Reads a single byte from the address space of a given SDIO
 *  function. If there is a problem reading the address, 0xff
 *  is returned and @err_ret will contain the error code.
 */
extern uint8_t
sdio_readb(struct mmc_card *card, uint32_t func_num, uint32_t addr,
           int32_t *err_ret);

/**
 *  sdio_writeb - write a single byte to a SDIO function
 *  @card: SDIO to access
 *  @b: byte to write
 *  @addr: address to write to
 *  @err_ret: optional status value from transfer
 *
 *  Writes a single byte to the address space of a given SDIO
 *  function. @err_ret will contain the status of the actual
 *  transfer.
 */
extern void
sdio_writeb(struct mmc_card *card, uint32_t func_num, const uint8_t b,
            uint32_t addr, int32_t  *err_ret);

/**
 *  sdio_readw - read a 16 bit integer from a SDIO function
 *  @func: SDIO function to access
 *  @addr: address to read
 *  @err_ret: optional status value from transfer
 *
 *  Reads a 16 bit integer from the address space of a given SDIO
 *  function. If there is a problem reading the address, 0xffff
 *  is returned and @err_ret will contain the error code.
 */
extern uint16_t sdio_readw(struct sdio_func *func, unsigned int addr, int *err_ret);
/**
 *  sdio_writew - write a 16 bit integer to a SDIO function
 *  @func: SDIO function to access
 *  @b: integer to write
 *  @addr: address to write to
 *  @err_ret: optional status value from transfer
 *
 *  Writes a 16 bit integer to the address space of a given SDIO
 *  function. @err_ret will contain the status of the actual
 *  transfer.
 */
extern void sdio_writew(struct sdio_func *func, uint16_t b, unsigned int addr, int *err_ret);
/**
 *  sdio_readl - read a 32 bit integer from a SDIO function
 *  @func: SDIO function to access
 *  @addr: address to read
 *  @err_ret: optional status value from transfer
 *
 *  Reads a 32 bit integer from the address space of a given SDIO
 *  function. If there is a problem reading the address,
 *  0xffffffff is returned and @err_ret will contain the error
 *  code.
 */
extern uint32_t sdio_readl(struct sdio_func *func, unsigned int addr, int *err_ret);
/**
 *  sdio_writel - write a 32 bit integer to a SDIO function
 *  @func: SDIO function to access
 *  @b: integer to write
 *  @addr: address to write to
 *  @err_ret: optional status value from transfer
 *
 *  Writes a 32 bit integer to the address space of a given SDIO
 *  function. @err_ret will contain the status of the actual
 *  transfer.
 */
extern void sdio_writel(struct sdio_func *func, uint32_t b, unsigned int addr, int *err_ret);

/**
 *  memcpy_fromio - read a chunk of memory from a SDIO function
 *  @dst: buffer to store the data
 *  @addr: address to begin reading from
 *  @count: number of bytes to read
 *
 *  Reads from the address space of a given SDIO function. Return
 *  value indicates if the transfer succeeded or not.
 */
extern int
sdio_memcpy_fromio(struct mmc_card *card, unsigned int func_num, void *dst,
                   unsigned int addr, int count);

/**
 *  memcpy_toio - write a chunk of memory to a SDIO function
 *  @addr: address to start writing to
 *  @src: buffer that contains the data to write
 *  @count: number of bytes to write
 *
 *  Writes to the address space of a given SDIO function. Return
 *  value indicates if the transfer succeeded or not.
 */
extern int
sdio_memcpy_toio(struct mmc_card *card, unsigned int func_num, unsigned int addr,
                 const void *src, int count);

/**
 *    sdio_claim_irq - claim the IRQ for a SDIO function
 *    @card: SDIO card
 *    @func_num: function num
 *    @handler: IRQ handler callback
 *
 *    Claim and activate the IRQ for the given SDIO function. The provided
 *    handler will be called when that IRQ is asserted.  The host is always
 *    claimed already when the handler is called so the handler must not
 *    call sdio_claim_host() nor sdio_release_host().
 */
//extern int sdio_claim_irq(struct mmc_card *card, unsigned int func_num,
//                          sdio_irq_handler_t *handler);
extern int sdio_claim_irq(struct sdio_func *func, sdio_irq_handler_t *handler);

/**
 *    sdio_release_irq - release the IRQ for a SDIO function
 *    @card: SDIO card
 *    @func_num: function num
 *
 *    Disable and release the IRQ for the given SDIO function.
 */
//extern int sdio_release_irq(struct mmc_card *card, unsigned int func_num);
extern int sdio_release_irq(struct sdio_func *func);

/**
 *  sdio_align_size - pads a transfer size to a more optimal value
 *  @func: SDIO function
 *  @sz: original transfer size
 *
 *  Pads the original data size with a number of extra bytes in
 *  order to avoid controller bugs and/or performance hits
 *  (e.g. some controllers revert to PIO for certain sizes).
 *
 *  If possible, it will also adjust the size so that it can be
 *  handled in just a single request.
 *
 *  Returns the improved size, which might be unmodified.
 */
//unsigned int sdio_align_size(struct mmc_card *card, unsigned int sz);
unsigned int sdio_align_size(struct sdio_func *func, unsigned int sz);