海思ubootsd卡协议
在start_armboot()函数中调用mmc_initialize(0)初始化mmc;最终调用到int hi_mci_initialize(unsigned int dev_num)函数;内容如下:
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 使能时钟且设置时钟为50M*/hi_mci_sys_init(dev_num);base_addr = SDIO0_BASE_REG; //SDIO基地址/* check controller version. 检查控制器协议*/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)); //申请内存if (!host)return -ENOMEM;memset(host, 0, sizeof(struct himci_host));mmc = &host->mmc; //获得host中的mmc变量,下面准备填充mmc;mmc->priv = host;//私有指针放上级(父)对象;host->base = base_addr;//赋值基地址host->dma_des = hi_dma_des;host->dev_id = dev_num;//设备编号host->card_status = hi_mci_sys_card_detect(host);//探测卡状态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;//发送命令回调mmc->set_ios = hi_mci_set_ios;mmc->init = hi_mci_init;//初始化回调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);//关机回调return 0;
}
重要的两个结构体struct mmc和struct himci_host ;
struct himci_host {struct mmc mmc;unsigned long base;//基地址unsigned int card_status;//卡状态(插入/拔出)unsigned int dev_id;//设备编号idunsigned int port;int cmd_id;struct mmc_cmd *cmd;struct himci_dma_des *dma_des;
};
mmc结构体其中几个变量对应下面sd卡协议中的寄存器;
struct mmc {
#ifdef CONFIG_HIMCI_V200int is_init;
#endifstruct list_head link;char name[32];//名字void *priv;//私有指针uint voltages;//电压值uint version;//版本号uint f_min;uint f_max;int high_capacity;//最高容量uint bus_width;//总线宽度uint clock;//时钟uint card_caps;//卡容量uint host_caps;uint ocr; //操作条件寄存器; 32bituint scr[2];//sd卡配置寄存器;有关sd存储卡特殊功能的信息;64bituint csd[4];//卡特定数据;有关卡操作条件的信息; 128bituint cid[4];//卡片识别号:用于识别的卡片个人编号; 128bitushort rca;//相对卡地址;卡的本地系统地址,由卡动态建议并在初始化期间由主机批准;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位:卡容量状态位,当卡为大容量内存卡时,该位为1; 当卡为标准内存卡时,该位为0;卡容量状态位在卡上电过程完成且卡上电状态位设置为1后生效;
Bit31位:卡上电状态位,若上电状态完成,设置为1;
CID寄存器
卡标识寄存器,128bit; 包含了卡标识信息在卡识别阶段使用; 每个读写卡应该具有唯一的识别号;
对应结构体为struct mmc_cid;
struct mmc_cid {unsigned long psn; //产品序列号unsigned short oid;//一个2字符ASCII字符串,用于标识卡OEM和/或卡内容unsigned char mid;//制造商IDunsigned char prv;//产品修订版unsigned char mdt;//制造日期char pnm[7];//产品名称
};
CSD寄存器
卡特定数据寄存器提供有关访问卡内容的信息;定义了数据格式,纠错类型,最大数据访问时间,DSR寄存器寄存器的寄存器可编程部分可由CMD27更改;
TAAC
定义数据访问时间的异步部分;
NSAC
定义数据访问时间的时钟相关因素的最坏情况。NSAC的单位是100时钟周期。因此,数据访问时间的时钟相关部分的最大值是25.5k个时钟周期。
总访问时间NAC是TAAC和NSAC的总和。它应由主机根据实际时钟速率进行计算。读取访问时间应被解释为数据块或流的第一数据位的典型延迟。
TRAN_SPPED
定义了每一个数据行的最大传输速率;
CCC
SD存储卡命令集分为多个子集(命令类); CCC中的值为1bit表示支持相应的命令类;
READ_BL_LEN
最大读取数据长度计算为2的read_bl_len次方;
READ_BL_PARTIAL
SD存储卡中始终允许部分块读取;意味着可以使用最小的块,最小块为一个字节;
WRITE_BLK_MISALIGN/READ_BLK_MISALIGN
定义由一个命令写入/读的数据块是否可以分布在多个物理块上存储设备的块;内存块的大小在WRITE_BL_LEN/READ_BL_LEN中定义; =0表示跨越物理块边界无效; =1表示允许跨越物理块边界;
DSR_IMP
定义可配置驱动程序阶段是否集成在卡上。=0表未被实施 =1表示已实施;
C_SIZE
此参数用于计算用户的数据卡容量;
VDD_R_CURR_MIN, VDD_W_CURR_MIN
最小电源VDD处的读取和写入电流的最大值编码如下;
VDD_R_CURR_MAX, VDD_W_CURR_MAX
最大电源V DD处的读和写电流的最大值编码;
C_SIZE_MULT
此参数用于编码因子MULT,以计算总设备大小;
MULT = 2的(C_SIZE_MULT+2)次方;
ERASE_BLK_EN
定义要擦除的数据的单位大小的粒度,擦除操作可以擦除512字节的一个或多个单位SECTOR_SIZE;
如果ERASE_BLK_EN=0,主机可以擦除一个或多个SECTOR_SIZE单元。擦除将开始从包含起始地址的扇区的开头到包含结束地址;
如果ERASE_BLK_EN=1,主机可以擦除一个或多个512字节的单元。包含数据的所有块从起始地址到结束地址被擦除;
SECTOR_SIZE
可擦除扇区的大小;
WP_GRP_ENABLE
值为0表示不可能进行组写保护;
R2W_FACTOR
将典型块编程时间定义为读取访问时间的倍数;
WRITE_BL_LEN
最大写入数据块长度计算为2 的write_BL_LEN次方。最大块长度可能因此在512到2048字节的范围内。始终支持512字节的写入块长度。
WRITE_BL_PARTIAL
定义块写入命令中是否可以使用部分块大小。
WRITE_BL_PARTIAL=0表示在512字节单位的分辨率可用于面向块的数据写入。
WRITE_BL_PARTIAL=1表示也可以使用更小的块。最小块大小为1字节;
FILE_FORMAT_GRP
指示选定的文件格式组;
COPY
定义内容是原始(=0)还是已复制(=1);
PERM_WRITE_PROTECT
永久保护整个卡内容不被覆盖或擦除(所有写入和擦除此卡的命令被永久禁用)。默认值为0,即不永久写入受保护的。
TMP_WRITE_PROTECT
暂时保护整个卡内容不被覆盖或擦除(所有写入和擦除此卡的命令暂时禁用)。该位可以设置和重置。默认值为0,即不写保护。
FILE_FORMAT
指示卡上的文件格式;
CRC
CRC字段携带CSD内容的校验和;
uboot中对应结构体如下:
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()函数又调用了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设备链表return 0;
}
其中主要初始化block_dev结构体,结构体如下:
typedef struct block_dev_desc {int if_type; /* type of the interface 接口类型*/int dev; /* device number 设备号*/unsigned char part_type; /* partition type 分区类型*/unsigned char target; /* target SCSI ID 目标SCSI ID*/unsigned char lun; /* target LUN 目标LUN*/unsigned char type; /* device type 设备类型*/unsigned char removable; /* removable device 可移动的设备*/
#ifdef CONFIG_LBA48unsigned char lba48; /* device can use 48bit addr (ATA/ATAPI v7) 设备可以使用48bit地址*/
#endiflbaint_t lba; /* number of blocks 块数量*/unsigned long blksz; /* block size 块大小*/char vendor [40+1]; /* IDE model, SCSI Vendor */char product[20+1]; /* IDE Serial no, SCSI product IDE型号,SCSI供应商*/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,//设备号unsigned long start,//块起始地址lbaint_t blkcnt,//块数量const void *buffer);void *priv; /* driver private struct pointer */
}block_dev_desc_t;
其中block_read和block_write回调函数用于块读/写;
两个回调函数都调用了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);
}
又回调了send_cmd函数, 该函数在最初的hi_mci_initialize函数中被赋值为hi_mci_request;
mmc_send_cmd调用示例:
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结构体填充后调用mmc_send_cmd(); 读buf地址被赋值到data.dest处返回;
hi_mci_request()函数中先调用hi_mci_setup_data()准备数据,如将目的地址赋值给dma对应地址等;填充好dma结构体; 然后调用hi_mci_idma_start()开启dma; 完成数据的读/写;
在函数hi_mci_initialize()中还初始化了初始化回调mmc->init = hi_mci_init;
然后在start_armboot中调用mmc_flash_init(0); 该函数最终调用了hi_mci_init();
hi_mci_init()调用了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 时钟相位*/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:原始中断状态寄存器*/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;//使用内置DMA搬移数据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;//使能发送接收中断himci_writel(tmp_reg, host->base + MCI_IDINTEN);/* set timeout param [31-8]:卡数据传输超时时间[7-0]:回复超时时间*/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);
}
该函数实现了 (a)复位mmc主机控制器; (b)卡复位 (c)卡掉电后上电 (d)取消卡复位 (e)设置时钟相位 (f)清空mmc主机中断寄存器 (g)设置中断掩码 (h)使能dma模式且关闭mmc主机控制器中断使能;(i)使能dma中断 (j)设置超时参数 (k)设置fifo参数;
海思ubootsd卡协议相关推荐
- 海思系统开发——linux下挂载SD卡
海思系统开发--linux下挂载SD卡 (1)通过#fdisk -l命令确认板子上的linux系统是否识别SD卡 [/]# fdisk -l /mnt/mmc # fdisk -l Disk /dev ...
- RTSP协议详解与实时流视频预览-第6/11季视频课程-海思-朱有鹏-专题视频课程
RTSP协议详解与实时流视频预览-第6/11季视频课程-海思-383人已学习 课程介绍 本季详细讲解RTSP协议的技术细节,并且编程实现基于RTSP协议的实时视频流传输,在局域网内浏览 ...
- 【AI语音】华为EC6110M、Q21AQ、Q21C部分EC6110T、EC6110U_海思3798MV310_通刷_卡刷固件
[AI语音]华为EC6110M.Q21AQ.Q21C部分EC6110T.EC6110U_海思3798MV310_通刷_卡刷固件 支持EC6110-T/M的卡刷固件,杜绝TTL线,摆脱双公头USB,实打 ...
- 海思IPC平台快速拔插SD卡会出现SD卡不识别解决方法
内核需要定时检测SD卡是否插入或拔出,默认给的定时检测时间为200ms. 此定时检测时间也可通过配置内核menuconfig更改.配置路径及配置选项如下: Device Drivers ---> ...
- 56-20210402华为海思Hi3516DV300的linux系统下读取TF卡(eMMC模式)
56-20210402华为海思Hi3516DV300的linux系统下读取TF卡(eMMC模式) 2021/4/2 15:02 https://xueqiu.com/7970718062/159110 ...
- 华为海思Hikey 970+ Ubuntu16.04 Xenial +ROS kinetic
文章目录 1. 基础介绍 2. 使用指南 2.1 刷基础固件和android 2.2 刷入Ubuntu 2.3 安装ROS 1. 基础介绍 2018年3月19日的Linaro Connect大会上华为 ...
- 海思3531DV200-强编解码能力解决方案
DEC3531D_C是广州英码信息科技有限公司推出的一款以海思Hi3531DV200处理器为核心而设计的编解码一体板.Hi3531DV200内置 ARM Cortex A53 四核@1.15GHz处理 ...
- 用什么软件测试mate9的闪存_超越苹果?余承东重拳出击,华为Mate40 Pro确认采用海思自研闪存!...
当年发布华为Mate9的时候,余承东曾经说过:华为拥有独家的技术,可以把Emmc5.1优化成UFS2.1.这个理论说实话引起了很大争议,一度被认为是华为宣传历史上的黑点.4年过去了,事情突然有了反转. ...
- 开发板_Hi3516DV300核心板/开发板;Hi3516EV100+4G+AUDIO RTMP开发板;海思系列开发板/核心板定制开发...
1.海思Hi3516DV300核心板/开发板 一,芯片参数 1. 处理器内核 *双核ARM Cortex-A7@ 900MHz,32KB I-Cache,32KB D-Cache,256KB L2 C ...
最新文章
- 隔空操控iPhone!苹果新获悬停手势专利
- 全球及中国航空发动机市场动态前景及十四五项目专项调研报告2021-2027年版
- Oracle SQL性能优化技巧大总结
- java 数字 下划线_为什么要在Java SE 7的数字中使用下划线-在数字文字中使用下划线...
- linux中的加法函数,上下文管理练习(为加法函数计时)
- mysql sleep详解_MySQL中sleep函数的特殊现象示例详解
- 极简好看的个人介绍页源码
- Linux 系统中随机数在 KVM 中的应用
- Mysql实战练习之简单图书管理系统
- github客户端的使用方法教程
- html前端毕业设计项目,web前端毕业设计论文..doc
- 如何快速区分单模与多模光纤收发器?
- UVA 202 - Repeating Decimals(模拟)
- VirtuoZo:航摄影像的处理及拼接
- 常见的知识图谱(Wikidata、YAGO、ConceptNet、DBpedia)
- MYSQL SQL 不等于
- 海思方案技术研发交流群/海思方案供需交流群
- 从十亿光年到0.1飞米
- 波波碰大乱斗发布——与轨迹历代角色自由对战~
- [Selenium] Selenium定向爬取海量精美图片及搜索引擎杂谈
热门文章
- Skin++使用详解-使用方法及注意事项
- 关于https的ssl加密技术
- 谷歌收购剑桥初创公司 手机屏幕或将变扬声器
- Python编码规范(PEP 8)
- Docker基础使用
- java设计工资一般多少_java开发(java开发工程师工资一般多少)
- html input 自动伸缩,Html页面input自动获得焦点
- R语言 mice包 Error in terms.formula(tmp, simplify = TRUE) : ExtractVars里的模型公式不对
- 用c语言编写的源文件经过编译 若,用C语言编写的源文件经过编译,若没有产生编译错误,则系统将()...
- h5支付java_java实现支付宝h5手机支付