9/13/2014

Linux 2.4 MMC/SD Interface 구조정리

1. DM320의 MMC/SD Driver 구현 및 관련설명정리

오래전에 Linux Kernel 2.4 기준으로 TI DM320 SD Card  와 SD-IO Spec 보고,직접 Linux Device Driver를 내 마음대로 만들어 본 경험이 있다.
물론 이 때는 Chip vendor들이 Device Driver를 제공 해주지 않으니, Chip Vendor 3rd Party에서 근무했던, 
내가 만들어 직접 개발하고 3rd Party에서 국내 각 회사에 공급했다. 

SDCard 뿐만아니라, HDMI를 비롯하여 각종 Device Drivers(Camera/LCD/Touch/Bus/등)들을 많이 만들었는데, 
우연히 예전에 정리했던 자료를 발견했으며, 그것을 오늘 간단히만 정리하려고 하며, 
현재 Linux Kernel과는 너무 많이 다르므로, 참조만 하도록하자. 

Device Driver 개발자 입장에서 생각해보면, 
USB/PCI/HPI 각 종 Bus Device Driver를 비롯하여, PATA도 만들어보고, Video MUX를 비롯하여 각종 여러 Device Driver를 개발해봤는데, 
가장 후회로 남는 것이 있다면, PCIe를 직접 개발 못해본게 좀 후회로 많이 남는다.

MMC/SD가 현재 와 많은 부분이 다를 것이며, MMC Interface 또한 많이 변경되어 왔다. 
또한 MMC Host에 따라 많이 다를 것으로 예상한다.

더불어 Linux Kernel 도 버전업 되면서 , 각 Device Driver가 Platform 화 되었으므로, 
이전과는 구조가 다르므로 주의하자.  


  • MMC&SD Card Driver 위치

 Kernel/driver/mmc 

1.1 SD/MMC Driver 기본전체구성

전체 TI의 MMC&SD Device Driver는 크게 3 부분으로 구분이 되고,Core 모듈과 MMC Block 모듈 그리고, 하드웨어에 종속적인 모듈로 구성이 된다.
만약 MMC&SD카드 Driver을 작성하고자 한다면, 전체 Driver를 작성할 필요 없이 mmc_hardware 부분 소스만 TI의 Datasheet를 보고 새로 작성을 하면된다.

  • MMC_CORE (MMC 공통사항)
Files: mmc.c mmc_queue.c mmc_sysfs.c
Description:
  mmc_block에서 등록이 된, Device들을 초기화 하고, MMC&SD Spec에 관한 Function 및 Hotplug에 관한 Function으로 구성이 되어있다.


  • MMC_BLOCK  ( block device driver)
Files: mmc_block.c
Description:
  mmc & sd card block device driver 함수들이 존재 한다. mmcblk의 block device 관련 함수들이 존재 한다.


  • mmc_hardware ( TI DM320 관련부분)
Files: dm320_mmc.c
Description:
  실제적인 MMC & SD Card Driver이며, Hardware에 종속적인 소스들로만 구성이 되어있다. 이 부분은 아래에서 자세히 다루겠다.


1.2 MMC & MMC_BLOCK 구성

MMC/SD Driver는 SD Card를 Hard disk Driver와 유사하게 인식을 하며, 그래서 기본적인 구성은 Hard disk의 Block Device Driver의 기본구조 유사하다.
이전에 FPGA관련 PATA Block Device driver도 직접 만들었 본 경험이 있어 볼 때마다 재미있다.
SD/MMC Block device driver의 구성은 다음과 같다

  • static int __init mmc_blk_init(void)
Module이 처음 올라갈 때, 실행이 되며, Block Device Driver를 등록한다.
중요함수: register_blkdev(major, "mmc");


  • static void __exit mmc_blk_exit(void)
Module이 내려 갈 때 실행이 되며, Block Device Driver를 해제한다.
중요함수: unregister_blkdev(major, "mmc");


  • static int mmc_blk_probe(struct mmc_card *card)
kerenl의 module이 올라가고 처음 block device driver가 잡힐 때
mmc_blk_alloc
  *alloc_disk
  *mmc_init_queue
     *blk_init_queue() (request 함수를 등록을 한다.)
     *mmc_queue_thread (mmc_queue thread 시작)
  *md->block_bits = 9; // 2G 이상 지원 (이 부분만 수정하면, 2G 이상 지원)
  *blk_queue_hardsect_size(Sector 크기 설정)
  *set_capacity (block 수 설정)
  *md->queue.prep_fn = mmc_blk_prep_rq;
  *md->queue.issue_fn = mmc_blk_issue_rq; (MMC Request 함수)

  • static void mmc_blk_remove(struct mmc_card *card)
block device driver가 제거될때

  • static int mmc_blk_suspend(struct mmc_card *card, pm_message_t state)
block device driver가 suspend가 될 경우
  • static int mmc_blk_resume(struct mmc_card *card)
block device drver를 resume 할 때


이전에 MMC Device Driver (SD Card / SD IO)를 Linux에서 직접구현하면서 간단히 정리 한 후 만든 간단히 도표이며,
나의 경우는 아래와 같이 Polling 모드로 동작하는 구조구현을 했다.




  • DM320 MMC Block Device Driver 내부동작
상위의 함수 mmc_queue_thread 기준으로 다시 한번 Flow를 보며, MMC Interface가 CMD 방식으로 동작하기 때문에 이 관련부분이 중요.
mmc_queue_thread    (Block Device Request 함수)
  *mmc_blk_issue_rq (실제적인 Request 함수)
     blk_rq_map_sg (block driver의 make_request 함수)
        MMC_READ_MULTIPLE_BLOCK
            *mmc_wait_for_read_data()
               *read_from_card()
        MMC_WRITE_MULTIPLE_BLOCK
            *mmc_wait_for_write_data()
                *write_from_card()   

위에서 전체 Block Device Driver의 Flow을 보면 동작방식은 간단히 다음과 같다.
  1. Block Device Driver를 등록하고, blk_init_queue 함수를 이용하여 request 함수를 등록한다.
  2. Kernel Queue Thread를 생성하고 항시 mmc_request가 오기를 항상 대기한다.(무한 루프)
  3. 커널에서 mmc_request 요청이 오면, 멈춰 있던 Kernel Thread를 작동시킨다.
  4. 커널에서 요청한 Request Function을 수행을 한다( Read & Write)


1.3 DM320 MMC/SD Device Driver 

앞서 말한 것와 같이 MMC/SD Device Driver는 Hardrware 부분의 종속된 부분만 구현하면 되지만, 
이전에 Dm320는 다른부분(mmc.c 및 기타부분)도 같이 보완해서 구현했다.
그리고, 추후에 WIFI를 위해서 SDIO를 지원하기 위해서 다른부분도 넣고 수정했는데, 거의 10년 전일이라 정리를 못하겠다. 
이 부분은 문서는 Linux에서 제공하는 Platform에 맞추어 Porting하는 부분으로 구성하였다. 
추후 다시 구현하거나 수정할 기회가 있다면 그때 정리하자

  • Linux에서 구현해야 할 함수 및 설정

static struct mmc_host_ops<
   .request = mmc_request  //MMC Request 이 전체의 Block Device의 실제적인 Request
   .set_ios = mmc_set_ios //Hardware Setting Init혹은 Voltage 설정. Bus width설정. Power 설정. Busmode
   .get_ro = get_write_protect_status  //ReadOnly 지원할 경우 

static struct device_driver
   .bus     = &platform_bus_type,
   .probe   = mmc_probe,   //MMC Host 에 관련된 초기화 설정

   .remove  = mmc_remove,
   .suspend = NULL,

   .resume  = NULL,


Kernel에서 요청하는 Page 수를 크게 하고 싶다면, 아래의 Segments 값을 변경을 하면되지만, 
변경시 한번에 전송하는 사이즈 값이 커진다. (주의: DMA 크기문제)

 mmc->max_hw_segs = 64;  //DMA Size 주의 
  mmc->max_phys_segs = 64;

  mmc->max_sectors = 128; // MAX Segments 값



  • Linux에서 각 함수 동작순서

mmc_alloc_host
  mmc_rescan
     mmc_claim_host
     mmc_check_cards
     mmc_setup
        mmc_power_up
        mmc_idle_cards
        mmc_send_op_cond    //OCR Register Read , 아래 참조 
        mmc_discover_cards  //ALL_CID & SEND_RELATIVE_ADDRESS
        mmc_read_csds       // CSD Register Read
        mmc_read_scrs       // SCR Register Read
            src_read
               init_clocks   // 변경 25MHz , SDIO일 경우는 50MHz 
        mmc_calculate_clock
        mmc_release_host


세부 구현 내용은 다른 소스를 참고하며 각 Chip Maker마다 다르므로 Datasheet를 보고 동작원리를 파악하자


1.4 Kernel 설정 및 MMC device 설정

Kernel의 Config 생성 및 설정 및 설치 (Module설정시 변경)

>make menuconfig
Device Drivers->MMC/SD Card support->   MMC support
                         [*]  MMC debugging
                           MMC block device driver  
                         [*]   Write work-around for incompatible cards
                         [*]   Multi-block writes (EXPERIMENTAL) 
                               < >  Winbond W83L51xD SD/MMC Card Interface support
                            < >  TI DAVINCI Multimedia Card Interface support
                               TI DM320 Multimedia Card In
> make modules
> make modules_install


상위와 같이 Kernel을 update 한 후 Board에서 SD Card를 삽입을 하고, SD Card의 Partition Table을 확인한 후 Device file을 확인.
Linux는 SD Card를 Hard disk처럼 인식하기 때문에, 반드시 SD Disk내에 Partition Table이 존재.


  • Partition Table 확인
> cat /proc/partitions
  254  0  249856 mmcblk0
  254  1  249805 mmcblk0p1

>ls /dev/mmcblk*   //device node 확인 
//만약 없다면, Device File 없다면,새로 생성
> # mknod /dev/mmcblk0 b 254 0
> # mknod /dev/mmcblk0p1 b 254 1

//만약 Partition Table이 존재 하지 않는다면, 다음과 같이 fdisk를 이용하여 만들어 준다.
> fdisk /dev/mmcblk0

//FileSystem이 없다면, FAT 혹은 EXT2,3를 Format 
>mkefs /dev/mmcblk0p1
or mkfs.ext2

>mount /dev/mmcblk0p1 /mnt/sd0

1.5 TI DM320 관련설정 부분



  • /mmc/dm320_mmc.c/init_clocks 함수 (clock 설정 , SDCard 와 SDIO는 25MHz/50MHz)



  • Clock Controller - INV Register 설정.





  • Clock Controller - DIV3 Register



  • MMC/SD Interface - MMCCLK Register



  • MMC/SD Interface 와 Memory Stick Controller




  • Clock Controller – MOD2




2. 다른 MMC/SD Driver 구조  (drivers/mmc )

MMC interface는 card or sdio 같은 소스를 사용하기에, 크게 수정할 일 없었으나,Host쪽 설정과 인식문제를 부분이 있어 이를 해결을 해야 할 것 같다.
(추후 시간이 있을 경우 최신것을 보도록 하자)

  • host    (이외 HOST, MCU에 의존적인 소스이며 설정소스 )
dw_mmc.c, sdhci.c sdhci-s3c.c

각 vendor에서 제공을 하며, MCU에 의존적으로 설정

  • card  ( block device driver) 
queue.c block.c mmc_block.o

sd card의 독립적인 모듈로 block device driver 구조로 각 thread queue를 사용하여 sd disk를 운영

  • core  ( sd card, mmc card, sdio  interface 및 기본 interface)
sd.c sdio.c mmc.c core.c bus.c ....

각 bus 및 interface 관련소스들로 구성이 되어있다. (SDIO 및 SD 기본 interface)

  • 관련 headers 
         include/linux/mmc


2.1 MMC/SD 관련 함수

  • Core interface 주요 함수 및 구조체 
drivers/mmc/core/core.h

  struct mmc_bus_ops {   // 각 sd, mmc, sdio bus function
    int (*awake)(struct mmc_host *);
    int (*sleep)(struct mmc_host *);
    void (*remove)(struct mmc_host *);
    void (*detect)(struct mmc_host *);
    int (*suspend)(struct mmc_host *);
    int (*resume)(struct mmc_host *);
    int (*power_save)(struct mmc_host *);
    int (*power_restore)(struct mmc_host *);

};

mmc_wait_for_cmd() 함수  // SD Interface Command 함수  , 이 함수를 이용하여 host에서 command를 보낸다.


  • Host interface 주요 함수 및 구조체 

 ex) const struct mmc_host_ops

static const struct mmc_host_ops sdhci_ops = {
  .request = sdhci_request, // SD Card  Block Device의 Request 함수
  .set_ios = sdhci_set_ios,
// Hardware Setting Init혹은 Voltage 설정. Bus width설정. Power 설정. Busmode
  .get_ro = sdhci_get_ro, //ReadOnly 지원할 경우
  .hw_reset = sdhci_hw_reset,
  .enable_sdio_irq = sdhci_enable_sdio_irq,
  .start_signal_voltage_switch = sdhci_start_signal_voltage_switch,
  .execute_tuning   = sdhci_execute_tuning,
  .enable_preset_value  = sdhci_enable_preset_value,
};


static struct platform_driver sdhci_s3c_driver = {
  .probe =sdhci_s3c_probe,   // mmc_alloc_host 이 호출되며, Device 인식 및 등록이 되므로 중요.
  .remove  = __devexit_p(sdhci_s3c_remove),
  .suspend = sdhci_s3c_suspend,
  .resume  = sdhci_s3c_resume,
  .driver  = {
  .owner   = THIS_MODULE,
  .name = "s3c-sdhci",
  },

};

  • Host interface의 Probe 함수 SD Interface 인식
mmc_alloc_host       (host_ops 의 probe 에서 mmc_alloc_host 호출)
  >mmc_rescan
    >mmc_rescan_try_freq
     >mmc_power_up
      >mmc_hw_reset_for_init
      >sdio_reset
      >mmc_attach_sdio   (3 중 하나로 mmc_bus_ops  등록 )
      or mmc_attach_sd
      or mmc_attach_mmc
      or mmc_power_off


2.2 MMC/SD Register 구조

SD는 CMD로 Host와 Device와 통신을 하며, 아래와 같이 Host에 Registers 존재하며,Device에 역시 이에 관련된 Register들이 존재한다. 이부분은 Spec을 참조.

  • SD Host Controller Register Map





  • SD Device Registers (SD Card)



위 Register는 SDIO 로 갈 경우 조금씩 달라지며,  각각의 최신 Spec를 참조.



  1. OCR: Card의 Voltage Status 및 High Capacity or Standard Capacity 인지를 나타낸다. (Response)
  2. CID: Card의 관련 제조사의 정보가 있다.
  3. CSD: Card의 핵심 레지스터 군들이 모두 이곳에 있다. (자세한 내용은 Spec)  (Read &Write Block size, Transfer Speed , etc )
  4. SCR: Card의 Data bus width, SD Spec Version, Security 지원여부를 나타낸다.
  5. RCA: Card의 Relative Card Address. (Host가 설정.)
  6. SSR: Card의 Status (Card의 설정된 정보 Card Type, Speed Class, Data bus width)
  7. CSR: Card의 Status (Card의 Error Check & Card의 State)