海思ubootsd卡协议
在start_armboot()函數(shù)中調(diào)用mmc_initialize(0)初始化mmc;最終調(diào)用到int hi_mci_initialize(unsigned int dev_num)函數(shù);內(nèi)容如下:
static int hi_mci_initialize(unsigned int dev_num) {struct mmc *mmc = NULL;static struct himci_host *host;unsigned int regval;unsigned long base_addr = 0;HIMCI_DEBUG_FUN("Function Call");/* enable SDIO clock and clock 50MHz 使能時(shí)鐘且設(shè)置時(shí)鐘為50M*/hi_mci_sys_init(dev_num);base_addr = SDIO0_BASE_REG; //SDIO基地址/* check controller version. 檢查控制器協(xié)議*/regval = himci_readl(base_addr + MCI_VERID);if ((regval != MCI_VERID_VALUE) && (regval != MCI_VERID_VALUE2)) {printf("MMC/SD/EMMC controller version incorrect.\n");return -ENODEV;}host = malloc(sizeof(struct himci_host)); //申請內(nèi)存if (!host)return -ENOMEM;memset(host, 0, sizeof(struct himci_host));mmc = &host->mmc; //獲得host中的mmc變量,下面準(zhǔn)備填充mmc;mmc->priv = host;//私有指針放上級(jí)(父)對象;host->base = base_addr;//賦值基地址host->dma_des = hi_dma_des;host->dev_id = dev_num;//設(shè)備編號(hào)host->card_status = hi_mci_sys_card_detect(host);//探測卡狀態(tài)host->port = 0; #ifdef CONFIG_EMMC_SUPPORT #ifdef CONFIG_EMMC_PORThost->port = CONFIG_EMMC_PORT; #endif #endifsprintf(mmc->name, DRIVER_NAME);mmc->send_cmd = hi_mci_request;//發(fā)送命令回調(diào)mmc->set_ios = hi_mci_set_ios;mmc->init = hi_mci_init;//初始化回調(diào)mmc->host_caps = MMC_MODE_HS | MMC_MODE_HS_52MHz| MMC_MODE_4BIT | MMC_MODE_8BIT;mmc->voltages = MMC_VDD_32_33 | MMC_VDD_33_34;//電壓值范圍mmc->f_min = MMC_CCLK_MIN;mmc->f_max = MMC_CCLK_MAX; #ifdef CONFIG_HIMCI_V200mmc->is_init = 0; #endifmmc_register(mmc);//注冊mmcadd_shutdown(himci_shutdown);//關(guān)機(jī)回調(diào)return 0; }重要的兩個(gè)結(jié)構(gòu)體struct mmc和struct himci_host ;
struct himci_host {struct mmc mmc;unsigned long base;//基地址unsigned int card_status;//卡狀態(tài)(插入/拔出)unsigned int dev_id;//設(shè)備編號(hào)idunsigned int port;int cmd_id;struct mmc_cmd *cmd;struct himci_dma_des *dma_des; };mmc結(jié)構(gòu)體其中幾個(gè)變量對應(yīng)下面sd卡協(xié)議中的寄存器;
struct mmc { #ifdef CONFIG_HIMCI_V200int is_init; #endifstruct list_head link;char name[32];//名字void *priv;//私有指針uint voltages;//電壓值uint version;//版本號(hào)uint f_min;uint f_max;int high_capacity;//最高容量uint bus_width;//總線寬度uint clock;//時(shí)鐘uint card_caps;//卡容量uint host_caps;uint ocr; //操作條件寄存器; 32bituint scr[2];//sd卡配置寄存器;有關(guān)sd存儲(chǔ)卡特殊功能的信息;64bituint csd[4];//卡特定數(shù)據(jù);有關(guān)卡操作條件的信息; 128bituint cid[4];//卡片識(shí)別號(hào):用于識(shí)別的卡片個(gè)人編號(hào); 128bitushort rca;//相對卡地址;卡的本地系統(tǒng)地址,由卡動(dòng)態(tài)建議并在初始化期間由主機(jī)批準(zhǔn);16bituint tran_speed;//傳輸速度uint read_bl_len;uint write_bl_len;u64 capacity;block_dev_desc_t block_dev;int (*send_cmd)(struct mmc *mmc,struct mmc_cmd *cmd, struct mmc_data *data);void (*set_ios)(struct mmc *mmc);int (*init)(struct mmc *mmc); };OCR寄存器:
其中0~23為電壓范圍;
bit30位:卡容量狀態(tài)位,當(dāng)卡為大容量內(nèi)存卡時(shí),該位為1; 當(dāng)卡為標(biāo)準(zhǔn)內(nèi)存卡時(shí),該位為0;卡容量狀態(tài)位在卡上電過程完成且卡上電狀態(tài)位設(shè)置為1后生效;
Bit31位:卡上電狀態(tài)位,若上電狀態(tài)完成,設(shè)置為1;
CID寄存器
卡標(biāo)識(shí)寄存器,128bit; 包含了卡標(biāo)識(shí)信息在卡識(shí)別階段使用; 每個(gè)讀寫卡應(yīng)該具有唯一的識(shí)別號(hào);
對應(yīng)結(jié)構(gòu)體為struct mmc_cid;
struct mmc_cid {unsigned long psn; //產(chǎn)品序列號(hào)unsigned short oid;//一個(gè)2字符ASCII字符串,用于標(biāo)識(shí)卡OEM和/或卡內(nèi)容unsigned char mid;//制造商IDunsigned char prv;//產(chǎn)品修訂版unsigned char mdt;//制造日期char pnm[7];//產(chǎn)品名稱 };CSD寄存器
卡特定數(shù)據(jù)寄存器提供有關(guān)訪問卡內(nèi)容的信息;定義了數(shù)據(jù)格式,糾錯(cuò)類型,最大數(shù)據(jù)訪問時(shí)間,DSR寄存器寄存器的寄存器可編程部分可由CMD27更改;
TAAC
定義數(shù)據(jù)訪問時(shí)間的異步部分;
NSAC
定義數(shù)據(jù)訪問時(shí)間的時(shí)鐘相關(guān)因素的最壞情況。NSAC的單位是100時(shí)鐘周期。因此,數(shù)據(jù)訪問時(shí)間的時(shí)鐘相關(guān)部分的最大值是25.5k個(gè)時(shí)鐘周期。
總訪問時(shí)間NAC是TAAC和NSAC的總和。它應(yīng)由主機(jī)根據(jù)實(shí)際時(shí)鐘速率進(jìn)行計(jì)算。讀取訪問時(shí)間應(yīng)被解釋為數(shù)據(jù)塊或流的第一數(shù)據(jù)位的典型延遲。
TRAN_SPPED
定義了每一個(gè)數(shù)據(jù)行的最大傳輸速率;
CCC
SD存儲(chǔ)卡命令集分為多個(gè)子集(命令類); CCC中的值為1bit表示支持相應(yīng)的命令類;
READ_BL_LEN
最大讀取數(shù)據(jù)長度計(jì)算為2的read_bl_len次方;
READ_BL_PARTIAL
SD存儲(chǔ)卡中始終允許部分塊讀取;意味著可以使用最小的塊,最小塊為一個(gè)字節(jié);
WRITE_BLK_MISALIGN/READ_BLK_MISALIGN
定義由一個(gè)命令寫入/讀的數(shù)據(jù)塊是否可以分布在多個(gè)物理塊上存儲(chǔ)設(shè)備的塊;內(nèi)存塊的大小在WRITE_BL_LEN/READ_BL_LEN中定義; =0表示跨越物理塊邊界無效; =1表示允許跨越物理塊邊界;
DSR_IMP
定義可配置驅(qū)動(dòng)程序階段是否集成在卡上。=0表未被實(shí)施 =1表示已實(shí)施;
C_SIZE
此參數(shù)用于計(jì)算用戶的數(shù)據(jù)卡容量;
VDD_R_CURR_MIN, VDD_W_CURR_MIN
最小電源VDD處的讀取和寫入電流的最大值編碼如下;
VDD_R_CURR_MAX, VDD_W_CURR_MAX
最大電源V DD處的讀和寫電流的最大值編碼;
C_SIZE_MULT
此參數(shù)用于編碼因子MULT,以計(jì)算總設(shè)備大小;
MULT = 2的(C_SIZE_MULT+2)次方;
ERASE_BLK_EN
定義要擦除的數(shù)據(jù)的單位大小的粒度,擦除操作可以擦除512字節(jié)的一個(gè)或多個(gè)單位SECTOR_SIZE;
如果ERASE_BLK_EN=0,主機(jī)可以擦除一個(gè)或多個(gè)SECTOR_SIZE單元。擦除將開始從包含起始地址的扇區(qū)的開頭到包含結(jié)束地址;
如果ERASE_BLK_EN=1,主機(jī)可以擦除一個(gè)或多個(gè)512字節(jié)的單元。包含數(shù)據(jù)的所有塊從起始地址到結(jié)束地址被擦除;
SECTOR_SIZE
可擦除扇區(qū)的大小;
WP_GRP_ENABLE
值為0表示不可能進(jìn)行組寫保護(hù);
R2W_FACTOR
將典型塊編程時(shí)間定義為讀取訪問時(shí)間的倍數(shù);
WRITE_BL_LEN
最大寫入數(shù)據(jù)塊長度計(jì)算為2 的write_BL_LEN次方。最大塊長度可能因此在512到2048字節(jié)的范圍內(nèi)。始終支持512字節(jié)的寫入塊長度。
WRITE_BL_PARTIAL
定義塊寫入命令中是否可以使用部分塊大小。
WRITE_BL_PARTIAL=0表示在512字節(jié)單位的分辨率可用于面向塊的數(shù)據(jù)寫入。
WRITE_BL_PARTIAL=1表示也可以使用更小的塊。最小塊大小為1字節(jié);
FILE_FORMAT_GRP
指示選定的文件格式組;
COPY
定義內(nèi)容是原始(=0)還是已復(fù)制(=1);
PERM_WRITE_PROTECT
永久保護(hù)整個(gè)卡內(nèi)容不被覆蓋或擦除(所有寫入和擦除此卡的命令被永久禁用)。默認(rèn)值為0,即不永久寫入受保護(hù)的。
TMP_WRITE_PROTECT
暫時(shí)保護(hù)整個(gè)卡內(nèi)容不被覆蓋或擦除(所有寫入和擦除此卡的命令暫時(shí)禁用)。該位可以設(shè)置和重置。默認(rèn)值為0,即不寫保護(hù)。
FILE_FORMAT
指示卡上的文件格式;
CRC
CRC字段攜帶CSD內(nèi)容的校驗(yàn)和;
uboot中對應(yīng)結(jié)構(gòu)體如下:
struct mmc_csd {u8 csd_structure:2,spec_vers:4,rsvd1:2;u8 taac;u8 nsac;u8 tran_speed;u16 ccc:12,read_bl_len:4;u64 read_bl_partial:1,write_blk_misalign:1,read_blk_misalign:1,dsr_imp:1,rsvd2:2,c_size:12,vdd_r_curr_min:3,vdd_r_curr_max:3,vdd_w_curr_min:3,vdd_w_curr_max:3,c_size_mult:3,sector_size:5,erase_grp_size:5,wp_grp_size:5,wp_grp_enable:1,default_ecc:2,r2w_factor:3,write_bl_len:4,write_bl_partial:1,rsvd3:5;u8 file_format_grp:1,copy:1,perm_write_protect:1,tmp_write_protect:1,file_format:2,ecc:2;u8 crc:7;u8 one:1; };hi_mci_initialize()函數(shù)又調(diào)用了mmc_register(mmc);
int mmc_register(struct mmc *mmc) { #ifdef CONFIG_HIMCI_V200struct himci_host *host = mmc->priv; #endif/* Setup the universal parts of the block interface just once */mmc->block_dev.if_type = IF_TYPE_MMC;mmc->block_dev.part_type = PART_TYPE_DOS; #ifdef CONFIG_HIMCI_V200mmc->block_dev.dev = host->dev_id; #elsemmc->block_dev.dev = cur_dev_num++; #endifmmc->block_dev.removable = 1;mmc->block_dev.block_read = mmc_mbread;mmc->block_dev.block_write = mmc_bwrite;INIT_LIST_HEAD (&mmc->link);list_add_tail (&mmc->link, &mmc_devices);//將mmc加入全局mmc設(shè)備鏈表return 0; }其中主要初始化block_dev結(jié)構(gòu)體,結(jié)構(gòu)體如下:
typedef struct block_dev_desc {int if_type; /* type of the interface 接口類型*/int dev; /* device number 設(shè)備號(hào)*/unsigned char part_type; /* partition type 分區(qū)類型*/unsigned char target; /* target SCSI ID 目標(biāo)SCSI ID*/unsigned char lun; /* target LUN 目標(biāo)LUN*/unsigned char type; /* device type 設(shè)備類型*/unsigned char removable; /* removable device 可移動(dòng)的設(shè)備*/ #ifdef CONFIG_LBA48unsigned char lba48; /* device can use 48bit addr (ATA/ATAPI v7) 設(shè)備可以使用48bit地址*/ #endiflbaint_t lba; /* number of blocks 塊數(shù)量*/unsigned long blksz; /* block size 塊大小*/char vendor [40+1]; /* IDE model, SCSI Vendor */char product[20+1]; /* IDE Serial no, SCSI product IDE型號(hào),SCSI供應(yīng)商*/char revision[8+1]; /* firmware revision 固件版本*/unsigned long (*block_read)(int dev,unsigned long start,lbaint_t blkcnt,void *buffer);unsigned long (*block_write)(int dev,//設(shè)備號(hào)unsigned long start,//塊起始地址lbaint_t blkcnt,//塊數(shù)量const void *buffer);void *priv; /* driver private struct pointer */ }block_dev_desc_t;其中block_read和block_write回調(diào)函數(shù)用于塊讀/寫;
兩個(gè)回調(diào)函數(shù)都調(diào)用了mmc_send_cmd命令;
int mmc_send_cmd(struct mmc *mmc, struct mmc_cmd *cmd, struct mmc_data *data) {return mmc->send_cmd(mmc, cmd, data); }又回調(diào)了send_cmd函數(shù), 該函數(shù)在最初的hi_mci_initialize函數(shù)中被賦值為hi_mci_request;
mmc_send_cmd調(diào)用示例:
int mmc_read_block(struct mmc *mmc, void *dst, uint blocknum) {struct mmc_cmd cmd;struct mmc_data data;cmd.cmdidx = MMC_CMD_READ_SINGLE_BLOCK;if (mmc->high_capacity)cmd.cmdarg = blocknum;elsecmd.cmdarg = blocknum * mmc->read_bl_len;cmd.resp_type = MMC_RSP_R1;cmd.flags = 0;data.dest = dst;data.blocks = 1;data.blocksize = mmc->read_bl_len;data.flags = MMC_DATA_READ;return mmc_send_cmd(mmc, &cmd, &data); }其中將cmd和data結(jié)構(gòu)體填充后調(diào)用mmc_send_cmd(); 讀buf地址被賦值到data.dest處返回;
hi_mci_request()函數(shù)中先調(diào)用hi_mci_setup_data()準(zhǔn)備數(shù)據(jù),如將目的地址賦值給dma對應(yīng)地址等;填充好dma結(jié)構(gòu)體; 然后調(diào)用hi_mci_idma_start()開啟dma; 完成數(shù)據(jù)的讀/寫;
在函數(shù)hi_mci_initialize()中還初始化了初始化回調(diào)mmc->init = hi_mci_init;
然后在start_armboot中調(diào)用mmc_flash_init(0); 該函數(shù)最終調(diào)用了hi_mci_init();
hi_mci_init()調(diào)用了hi_mci_init_card();
static void hi_mci_init_card(struct himci_host *host) {unsigned int tmp_reg;HIMCI_DEBUG_FUN("Function Call");HIMCI_ASSERT(host);hi_mci_sys_reset(host);/* card reset */himci_writel(~(1<<host->port), host->base + MCI_RESET_N);__udelay(CONFIG_MMC_RESET_LOW_TIMEOUT);/* card power off and power on */hi_mci_ctrl_power(host, POWER_OFF);__udelay(CONFIG_MMC_POWER_OFF_TIMEOUT * 1000);hi_mci_ctrl_power(host, POWER_ON);__udelay(CONFIG_MMC_POWER_ON_TIMEROUT * 1000);/* card reset cancel */himci_writel(1<<host->port, host->base + MCI_RESET_N);__udelay(CONFIG_MMC_RESET_HIGH_TIMEROUT);/* set drv/smpl phase shift 時(shí)鐘相位*/tmp_reg = himci_readl(host->base + MCI_UHS_REG_EXT);tmp_reg &= ~(DRV_PHASE_MASK | SMPL_PHASE_MASK);tmp_reg |= DRV_PHASE_SHIFT | SMPL_PHASE_SHIFT;himci_writel(tmp_reg, host->base + MCI_UHS_REG_EXT);/* clear MMC host intr MCI_RINTSTS:原始中斷狀態(tài)寄存器*/himci_writel(ALL_INT_CLR, host->base + MCI_RINTSTS);/* MASK MMC host intr MCI_INTMASK:中斷屏蔽寄存器*/tmp_reg = himci_readl(host->base + MCI_INTMASK);tmp_reg &= ~ALL_INT_MASK;himci_writel(tmp_reg, host->base + MCI_INTMASK);/* enable inner DMA mode and close intr of MMC host controler */tmp_reg = himci_readl(host->base + MCI_CTRL);tmp_reg &= ~INTR_EN; //全局中斷使能 1:=使能tmp_reg |= USE_INTERNAL_DMA;//使用內(nèi)置DMA搬移數(shù)據(jù)himci_writel(tmp_reg, host->base + MCI_CTRL);/* enable dma intr */tmp_reg = himci_readl(host->base + MCI_IDINTEN);tmp_reg &= ~MCI_IDINTEN_MASK;tmp_reg = TI | RI | NI;//使能發(fā)送接收中斷himci_writel(tmp_reg, host->base + MCI_IDINTEN);/* set timeout param [31-8]:卡數(shù)據(jù)傳輸超時(shí)時(shí)間[7-0]:回復(fù)超時(shí)時(shí)間*/himci_writel(DATA_TIMEOUT | RESPONSE_TIMEOUT, host->base + MCI_TIMEOUT);/* set FIFO param */himci_writel(BURST_SIZE | RX_WMARK | TX_WMARK, host->base + MCI_FIFOTH); }該函數(shù)實(shí)現(xiàn)了 (a)復(fù)位mmc主機(jī)控制器; (b)卡復(fù)位 (c)卡掉電后上電 (d)取消卡復(fù)位 (e)設(shè)置時(shí)鐘相位 (f)清空mmc主機(jī)中斷寄存器 (g)設(shè)置中斷掩碼 (h)使能dma模式且關(guān)閉mmc主機(jī)控制器中斷使能;(i)使能dma中斷 (j)設(shè)置超時(shí)參數(shù) (k)設(shè)置fifo參數(shù);
總結(jié)
以上是生活随笔為你收集整理的海思ubootsd卡协议的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: [solved]mac maven se
- 下一篇: 观察者模式与事件处理