结合2012.10版本的u-boot分析SD卡驱动(笔记)

来源:互联网 发布:淘宝网男士休闲鞋 编辑:程序博客网 时间:2024/06/16 15:37

xxx_mmc_init流程:

|power up sd_card|给卡上电
        |
       \|/
|reset controller/fifo/dma|执行控制器复位/fifo复位
        |
       \|/
|清除所有状态寄存器|实际是复位硬件的状态机
        |
       \|/
|屏蔽中断寄存器| 比如设置中断掩码及使能寄存器
        |
       \|/
  |FIFO相关设置|
        |
       \|/
   |禁止时钟|

注意:这个init函数可能被重复调用,比如需要重新初始化SD控制器时,比如altera的preloader初始化一次后,u-boot中也会再次初始化一次,共两次。
-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
Q:为什么使用内部DMA之后,传输速度可以提升?
A:因为在u-boot中CPU访问SD控制器寄存器和数据内存没有开cache,性能不高,但是dma完全不受MMU管控,直接和内存打交道
   并可以配置DMA burst,获取比cpu更高的访问内存性能.
   
   一般DMA对源和目标地址有要求,比如32位地址对齐之类的。u-boot中用宏ALLOC_CACHE_ALIGN_BUFFER定义这样的buffer。
  

Q: sd 卡识别模式最大频率是多少?
A: 最大设置为400k,因为某些卡识别模式时,有工作频率限制。


命令类型:
I)广播命令
II)寻址命令

数据格式:
I)数据包格式--常规数据    先发送低地址的字节,然后发送高地址的字节;字节内部先放高位(bit7 bit6...bit1 bit0),再发低位。
II)宽幅数据---SD寄存器    先发最高位,依次发送到最低位。比如bit

class 0 :初始化,识别命令

CMD0        复位SD卡
CMD1        用来识别MMC卡的命令,用在CMD8命令之后,CMD8命令探测到卡既不是SD2.0又不是SD1.X,则用CMD1探测是否为MMC卡
ACMD41:
                    I)读取OCR寄存器(cmdarg 中电压窗口的值为0);
                   II)执行卡的初始化序列(窗口电压非零),同时在R3响应中也包含OCR寄存器,所以实际代码中直接使用这个功能
      
CMD9        读取CSD寄存器
CMD2        读取CID寄存器
CMD12     停止读多块数据是的数据传输
CMD13     读card_status寄存器

class 2:    读卡操作命令


CMD16    设置块的长度
CMD17     读单个块
CMD18     读多个块,直到主机发送CMD12为止

class 4: 写卡操作命令


CMD24     写单块
CMD25     写多块
CMD27     写CSD寄存器

class 5: 擦除命令


CMD32    设定擦除块的起始地址
CMD33    设定擦除块的结束地址
CMD38    擦除选择的块

class 6: 写保护操作


CMD28    设置写保护块地址 (标准容量卡支持,SDHC不支持)
CMD29    清除写保护块地址  (标准容量卡支持,SDHC不支持)
CMD30   写保护

ACMD51 读取SCR寄存器,即卡配置寄存器

CMD6  在SD1.10以上是必须支持的命令,该命令用于切换或扩展内存卡功能的。比如支持高速卡的功能,在group1 fucntion 1 SDR25即50MHz
              CMD6是带数据读命令,需要传输的数据有512bit,16个字节。MODE 0(Check Function), MODE 1(Set Function)
               CMD6是宽幅数据格式(512),先发送的是bit511....bit0;用8个32位的整数数组接收这样的数据时要注意了。
               u32 switch_status[16];
                                32bit                                                                                                                                       32bit
      bit487~bit480 bit495~bit488 bit503~bit496 bit511~bit504        ......                bit7~bit0  bit15~bit8 bit23~bit16 bit31~bit24   
                           switch_status[0]                                                            ......                                                switch_status[16]
      每个32位内存单元存储低地址放的高位数据(大端格式),这是由SD协议决定的;所以需要转成cpu格式的,在u-boot中调用字节调换宏。即大端转小端格式。
      而CMD2和CMD9读CID和CSD寄存器时,是从response中得到数据的,而且response是从SD控制器的响应的寄存器中得到的,实际上已经被控制器调整完顺序了。
     

-------SD2.0-----
SDR12        --- 25MHZ 12.5MB/s
SDR25        --- 50MHz   25MB/s
-------SD3.0-----
SDR50        --- 100MHz  50MB/s
SDR104       --- 208MHz  104MB/s
DDR50        --- 50MHz   50MB/s

MMC卡
标准 26MHz
高速 52MHz

SDSC(<=2GB),SDHC(2GB-32GB), SDXC(32GB-2TB)     CMD17,CMD18  对应的cmdarg是32位块地址,所以4G(块地址)x512 = 2TB max


SPI模式下的CRC校验是忽略的,但是CRC码也是要发送的,可以初始化为0x0或0xff

命令格式:48位
    0                1                                         content             CRC7             1
start bit  transmission bit        cmd + cmd_arg          7bit          stop bit

 

响应格式:48位或136位


48位:
   0              0                                          content             CRC7               1
start bit  transmission bit                                                                     stop bit

136位:
   0              0                                     CID or CSD           CRC7              1

start bit  transmisssion bit                                               7bit              stop bit           


SD响应类型:
         谁的响应                                          长度                       CRC7
R1                                                               48                          有
R1b                                                             48                          有
R2   CID,CSD                                              136                         有
R3   OCR(ACMD41的响应)                          48                         无----------特例
R6   RCA                                                      48                         有
R7   CMD8的响应                                       48                         有

 

1、CSD寄存器的版本?作用?
CMD9访问;首先读取CSD的版本号(bit127-bit126);有v1.0和V2.0两个版本;从CSD寄存器可以获取卡的读写块大小(一般512),容量大小,频率。

2、OCR寄存器作用?
ACMD41访问;可以获取SD卡的工作电压;以及容量信息(CCS--Card Capacity Status)

3、SCR寄存器的作用?
ACMD6访问;可以用来切换总线宽度,1bit或4bit;返回的数据(SCR寄存器内容)是大端格式的。

~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

SD识别过程:

调用具体sd controller的初始化函数
             |
            \|/
         CMD0复位SD CARD
             |
            \|/
         CMD8(send_if_cond查询卡电压范围)发送版本查询命令(resp = 0x01表示SD2.0;resp = 0x05表示SD1.0),ACMD41之前必须发此命令。
             |
           \ |/
         ACMD41(初始化SD卡,同时获取ocr寄存器(R7))
             |
            \|/
     CMD2(读取CID信息)  (identify mode)
             |
             |
     CMD3(SD卡则读取RCA寄存器,取RCA寄存器高16位作为RCA地址
             |
            \|/
   成功的话则进入(standby mode)
             |
            \|/
      CMD9(读CSD信息)
             |
            \|/
          CMD13(读CARD_STATUS),确认一下卡的状态
             |
            \|/
          CMD7(转卡进入transfer mode)
             |
            \|/  
      ACMD51(读取SCR寄存器,是否支持4bit)
             |
            \|/
      CMD6查询是否支持高速模式
            |
           \|/
      如果支持高速,CMD6设置高速模式
            |
           \|/
     可以发送其他读写和擦除命令了,比如读取MBR块的数据,分析SD的分区表信息
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

Sending CMD0              ---复位SD 卡
Sending CMD8       ---查询卡状态
Sending CMD55       ---应用命令
Sending CMD41             ---
Sending CMD55
Sending CMD41
Sending CMD55
Sending CMD41
Sending CMD2       --- CID 读卡的厂商信息
Sending CMD3       --- 设置RCA 给sd卡分配一个地址
Sending CMD9       --- CSD
Sending CMD13       --- 读卡状态
Sending CMD7
Sending CMD55
Sending CMD51
Sending CMD6
Sending CMD6
Sending CMD55
Sending CMD6
freq=50000000
Sending CMD16
Sending CMD17
Sending CMD16
Sending CMD18
Sending CMD12

上面命令的具体分析:


------------------识别模式------------------------------------------------------------------------------------------------------------------------------------------------------------
freq=400000
Sending CMD0,cmdarg=0x0         ---复位SD 卡;卡处于默认相对卡地址,一个默认时钟400KHz;(IDLE模式)
                                                            *********** 没有response
Sending CMD8,cmdarg=0x1aa    ---查询卡状态,SD 2.0新增命令,可以判断是否为sd 2.0;同时检查SD卡工作电压范围是否在2.7-3.6V之间(bit8 = 1),是的话,返回R7响应
response[0] =0x1aa                        *********** R7 (aa是check pattern,协议建议值)

Sending CMD55,cmdarg=0x0        ---应用命令
response[0] =0x120                        *********** R1
Sending CMD41,cmdarg=0x40300000     ---这里u-boot直接设定驱动中的电压,这里启动初始化序列,而不是读取OCR寄存器操作(cmdarg : OCR_HCS = 1(bit30), bit20,bit21 == 3.2~3.3V, 3.3V~3.4V)
response[0] =0xff8000                    ***********响应表示卡忙bit31(busy) == 0  OCR寄存器的值包含在R3中,即响应中(R3)

Sending CMD55,cmdarg=0x0
response[0] =0x120
Sending CMD41,cmdarg=0x40300000
response[0] =0xc0ff8000                ***********响应表示卡不忙bit31(busy) == 1; (大容量卡 > 2GB), (标准卡 <= 2GB)  (R3)

Sending CMD2,cmdarg=0x0         --- 读CID(读卡的厂商信息),不需要arg参数,是针对所有挂载SD总线上的SD卡的;CMD10用于读取特定RCA地址的卡CID信息;(Identify Mode)
response[3 2 1 0]=0xf500d297    0x2198033    0x43617264   0x824a544e
注意U-boot中           bit31~bit0      bit63~bit32     bit95~bit64     bit127~bit96   
                                                            *********** response[0]存放的bit127~bit96,因为SD卡协议规定响应是从高位开始传输的,
                                                                               所以接收到应该从高32开始,但是奇怪的是32位数据不是大端格式的,而是小端格式的  (R2)
                                                                                应该是SD控制器的response寄存器已经调整了每个32位数据的大小端格式的
                    
Sending CMD3,cmdarg=0x0         --- 设置RCA 给sd卡分配一个地址(16位地址);这里成功后,卡进入数据传输模式
response[0] =0x59b40520            ***********   SD卡通常可以从RCA寄存器中读到,而MMC卡一定要我们自己设定,u-boot中设定为1(R6)

------------------------进入standby mode-------------------------------------------------------------------------------------------------------------------------

Sending CMD9,cmdarg=0x59b40000     --- 读CSD
response[3 2 1 0]=0xa4000c1 0x75cd7f80 0x5b590000 0x400e0032
                                  bit31~bit0   bit63~bit32  bit95~bit64   bit127~bit96
                                                           ***********  容量((0x75cd + 1)<<(8+2))*512 = 16GB (R2)
Sending CMD13,cmdarg=0x59b40000     --- 读卡状态,响应格式请参考卡SD卡规范的4.10.1;这里主要检查卡是否处于准备接受数据(MMC_STATUS_RDY_FOR_DATA(bit8)),以及确定当前的状态不是program状态(bit9-bit12)
response[0] =0x700                        *********** R1

Sending CMD7,cmdarg=0x59b40000     --- 选中RCA = 0x59b4的SD卡,把它的状态置为传输模式(transfer mode),任何时刻只能有一个卡处在传输模式(这个命令很重要),否则卡standby mode
response[0] =0x700                        *********** R1

-------------------数据传输模式(从这里开始,必须使用RCA地址访问SD卡了)------------------------------------------------------------------------------------------------

Sending CMD55,cmdarg=0x59b40000     --- 卡寻址(点对点寻址)
response[0] =0x920
Sending CMD51,cmdarg=0x0        --- ACMD51,SCR寄存器;这里采用的是数据传输(大端格式);是从dat线上返回的数据;而respone是在cmd线上传输的
response[0] =0x920                         *********** R1

Sending CMD6,cmdarg=0xfffff1      --- CMD6 check function,总共有6个组(group 1~6, 4 bits per group),每个组16个功能;这里也是采用数据传输的方式(大端格式)
response[0] =0x900

Sending CMD6,cmdarg=0x80fffff1 --- CMD6 set function设置功能;这里设置group1, function 1(SDR25即50MHz)
response[0] =0x900                         *********** R1

Sending CMD55,cmdarg=0x59b40000     --- CMD55
response[0] =0x920                         *********** R1
Sending CMD6,cmdarg=0x2         --- ACMD6,用于切换数据线宽度的,默认是bus_width = 1; 可以使用它切到bus_width = 4;cmdarg[10]=00(1bit),10(4bit);

                                                           且数据宽度的顺序是:I)应该先用ACMD6且SD卡的数据宽度;II)然后把SD控制器这边对应的控制寄存器位改成4bit
response[0] =0x920                       *********** R1
freq=50000000

Sending CMD16,cmdarg=0x200       --- 设定块长度,这里设定块长为512字节;(这里是init_part函数调用使用的命令,读取MBR数据)
response[0] =0x900

Sending CMD17,cmdarg=0x0        --- 单个块读命令,cmdarg指定从第0块(32位块地址)读;注意标准容量和大容量卡对cmdarg地址解析不同;

                                                                    大容量卡以块为单位,而标准容量卡以字节为单位
response[0] =0x900

Sending CMD16,cmdarg=0x200    --- 设置块长度
response[0] =0x900

Sending CMD18,cmdarg=0x1        --- 多块读命令,cmdarg是指定读块地址(32位),这里从第1块
response[0] =0x900

Sending CMD12,cmdarg=0x0        --- CMD12 多块读停止命令
response[0] =0xb00
================================================================================================================
SD卡信息:

SONY 16G CLASS 10:

SOCFPGA_CYCLONE5 # mmcinfo
Device: ALTERA DWMMC
Manufacturer ID: 82
OEM: 4a54
Name: NCard 
Tran Speed: 50000000
Rd Block Len: 512
SD version 2.0
High Capacity: Yes
Capacity: 14.7 GiB
Bus Width: 4-bit


Kingston 4GB class 4:

SOCFPGA_CYCLONE5 # mmcinfo
Device: ALTERA DWMMC
Manufacturer ID: 41
OEM: 3432
Name: SD4GB 
Tran Speed: 50000000
Rd Block Len: 512
SD version 2.0
High Capacity: Yes
Capacity: 3.7 GiB
Bus Width: 4-bit


=================================================================================================================

列出文件系统里的文件:
SOCFPGA_CYCLONE5 # fatls mmc 0:1 
Sending CMD16,cmdarg=0x200
response[0] =0x900
Sending CMD17,cmdarg=0x0
response[0] =0x900
Sending CMD16,cmdarg=0x200
response[0] =0x900
Sending CMD17,cmdarg=0x0
response[0] =0x900
Sending CMD16,cmdarg=0x200
response[0] =0x900
Sending CMD17,cmdarg=0x20d800
response[0] =0x900
Sending CMD16,cmdarg=0x200
response[0] =0x900
Sending CMD17,cmdarg=0x20d800
response[0] =0x900
Sending CMD16,cmdarg=0x200
response[0] =0x900
Sending CMD18,cmdarg=0x20d851
response[0] =0x900
Sending CMD12,cmdarg=0x0
response[0] =0xb00
  2694296   uimage 
     7999   socfpga.dtb 
 11075584   jffs2.img

3 file(s), 0 dir(s)
===========================================================================================

读取文件至内存:
SOCFPGA_CYCLONE5 # fatload mmc 0:1 0x4000000 socfpga.dtb
Sending CMD16,cmdarg=0x200
response[0] =0x900
Sending CMD17,cmdarg=0x0
response[0] =0x900
Sending CMD16,cmdarg=0x200
response[0] =0x900
Sending CMD17,cmdarg=0x0
response[0] =0x900
Sending CMD16,cmdarg=0x200
response[0] =0x900
Sending CMD17,cmdarg=0x20d800
response[0] =0x900
reading socfpga.dtb
Sending CMD16,cmdarg=0x200
response[0] =0x900
Sending CMD17,cmdarg=0x20d800
response[0] =0x900
Sending CMD16,cmdarg=0x200
response[0] =0x900
Sending CMD18,cmdarg=0x20d851
response[0] =0x900
Sending CMD12,cmdarg=0x0
response[0] =0xb00
Sending CMD16,cmdarg=0x200
response[0] =0x900
Sending CMD18,cmdarg=0x20d801
response[0] =0x900
Sending CMD12,cmdarg=0x0
response[0] =0xb00
Sending CMD16,cmdarg=0x200
response[0] =0x900
Sending CMD18,cmdarg=0x20ed05
response[0] =0x900
Sending CMD12,cmdarg=0x0
response[0] =0xb00
Sending CMD16,cmdarg=0x200
response[0] =0x900
Sending CMD17,cmdarg=0x20ed14
response[0] =0x900
7999 bytes read in 110 ms
 (70.3 KiB/s)

7999 bytes read

0 0