driver-platform-mmc-develop.md 17.3 KB
Newer Older
D
duangavin123 已提交
1
# MMC
D
duangavin123 已提交
2 3


D
duangavin123 已提交
4
## 概述
D
duangavin123 已提交
5

6
MMC(MultiMedia Card)即多媒体卡。在HDF框架中,MMC的接口适配模式采用独立服务模式。在这种模式下,每一个设备对象会独立发布一个设备服务来处理外部访问,设备管理器收到API的访问请求之后,通过提取该请求的参数,达到调用实际设备对象的相应内部方法的目的。独立服务模式可以直接借助HDFDeviceManager的服务管理能力,但需要为每个设备单独配置设备节点,增加内存占用。
D
duangavin123 已提交
7

D
duangavin123 已提交
8
  **图1** MMC独立服务模式结构图
9 10

  ![zh-cn_image_0000001176603968](figures/独立服务模式结构图.png "MMC独立服务模式结构图")
D
duangavin123 已提交
11

D
duangavin123 已提交
12 13

## 接口说明
D
duangavin123 已提交
14 15 16

MmcCntlrOps定义:

D
duangavin123 已提交
17
  
D
duangavin123 已提交
18 19 20 21 22 23 24 25 26 27
```
struct MmcCntlrOps {
  int32_t (*request)(struct MmcCntlr *cntlr, struct MmcCmd *cmd);
  int32_t (*setClock)(struct MmcCntlr *cntlr, uint32_t clock);
  int32_t (*setPowerMode)(struct MmcCntlr *cntlr, enum MmcPowerMode mode);
  int32_t (*setBusWidth)(struct MmcCntlr *cntlr, enum MmcBusWidth width);
  int32_t (*setBusTiming)(struct MmcCntlr *cntlr, enum MmcBusTiming timing);
  int32_t (*setSdioIrq)(struct MmcCntlr *cntlr, bool enable);
  int32_t (*hardwareReset)(struct MmcCntlr *cntlr);
  int32_t (*systemInit)(struct MmcCntlr *cntlr);
S
s00442234 已提交
28
  int32_t (*setEnhanceStrobe)(struct MmcCntlr *cntlr, bool enable);
D
duangavin123 已提交
29 30
  int32_t (*switchVoltage)(struct MmcCntlr *cntlr, enum MmcVolt volt);
  bool (*devReadOnly)(struct MmcCntlr *cntlr);
S
s00442234 已提交
31
  bool (*devPlugged)(struct MmcCntlr *cntlr);
D
duangavin123 已提交
32 33 34 35 36 37
  bool (*devBusy)(struct MmcCntlr *cntlr);
  int32_t  (*tune)(struct MmcCntlr *cntlr, uint32_t cmdCode);
  int32_t (*rescanSdioDev)(struct MmcCntlr *cntlr);
};
```

D
duangavin123 已提交
38 39 40 41
  **表1** MmcCntlrOps结构体成员的回调函数功能说明

| 成员函数 | 入参 | 返回值 | 功能 | 
| -------- | -------- | -------- | -------- |
42 43 44 45 46 47 48 49
| doRequest | cntlr:核心层结构体指针,MMC控制器<br>cmd:结构体指针,传入命令值 | HDF_STATUS相关状态 | request相应处理 | 
| setClock | cntlr:核心层结构体指针,MMC控制器<br>clock:时钟传入值 | HDF_STATUS相关状态 | 设置时钟频率 | 
| setPowerMode | cntlr:核心层结构体指针,MMC控制器<br>mode:枚举值(见MmcPowerMode定义),功耗模式 | HDF_STATUS相关状态 | 设置功耗模式 | 
| setBusWidth | cntlr:核心层结构体指针,MMC控制器<br>width:枚举值(见MmcBusWidth定义),总线带宽 | HDF_STATUS相关状态 | 设置总线带宽 | 
| setBusTiming | cntlr:核心层结构体指针,MMC控制器<br>timing:枚举值(见MmcBusTiming定义),总线时序 | HDF_STATUS相关状态 | 设置总线时序 | 
| setSdioIrq | cntlr:核心层结构体指针,MMC控制器<br>enable:布尔值,控制中断 | HDF_STATUS相关状态 | 使能/去使能SDIO中断 | 
| hardwareReset | cntlr:核心层结构体指针,MMC控制器 | HDF_STATUS相关状态 | 复位硬件 | 
| systemInit | cntlr:核心层结构体指针,MMC控制器 | HDF_STATUS相关状态 | 系统初始化 | 
S
s00442234 已提交
50
| setEnhanceStrobe | cntlr:核心层结构体指针,MMC控制器<br>enable:布尔值,设置功能 | HDF_STATUS相关状态 | 设置增强选通 | 
51 52
| switchVoltage | cntlr:核心层结构体指针,MMC控制器<br>volt:枚举值,电压值(3.3,1.8,1.2V) | HDF_STATUS相关状态 | 设置电压值 | 
| devReadOnly | cntlr:核心层结构体指针,MMC控制器 | 布尔值 | 检验设备是否只读 | 
S
s00442234 已提交
53
| cardPlugged | cntlr:核心层结构体指针,MMC控制器 | 布尔值 | 检验设备是否拔出 | 
54 55 56
| devBusy | cntlr:核心层结构体指针,MMC控制器 | 布尔值 | 检验设备是否忙碌 | 
| tune | cntlr:核心层结构体指针,MMC控制器<br>cmdCode:uint32_t,命令代码 | HDF_STATUS相关状态 | 调谐 | 
| rescanSdioDev | cntlr:核心层结构体指针,MMC控制器 | HDF_STATUS相关状态 | 扫描并添加SDIO设备 | 
D
duangavin123 已提交
57 58 59


## 开发步骤
D
duangavin123 已提交
60

L
liyan 已提交
61
MMC模块适配的三个必选环节是实例化驱动入口,配置属性文件,以及实例化核心层接口函数。
D
duangavin123 已提交
62

L
liyan 已提交
63
1. 实例化驱动入口
D
duangavin123 已提交
64 65
   - 实例化HdfDriverEntry结构体成员。
   - 调用HDF_INIT将HdfDriverEntry实例化对象注册到HDF框架中。
D
duangavin123 已提交
66

L
liyan 已提交
67
2. 配置属性文件
D
duangavin123 已提交
68 69
   - 在device_info.hcs文件中添加deviceNode描述。
   - 【可选】添加mmc_config.hcs器件属性文件。
D
duangavin123 已提交
70

L
liyan 已提交
71
3. 实例化MMC控制器对象
D
duangavin123 已提交
72 73
   - 初始化MmcCntlr成员。
   - 实例化MmcCntlr成员MmcCntlrOps。
74
      > ![icon-note.gif](public_sys-resources/icon-note.gif) **说明:**<br>
D
duangavin123 已提交
75
      > 实例化MmcCntlr成员MmcCntlrOps,其定义和成员说明见[接口说明](#接口说明)。
D
duangavin123 已提交
76

L
liyan 已提交
77 78
4. 驱动调试

D
duangavin123 已提交
79
   【可选】针对新增驱动程序,建议验证驱动基本功能,例如挂载后的信息反馈,设备启动是否成功等。
D
duangavin123 已提交
80 81


D
duangavin123 已提交
82
## 开发实例
D
duangavin123 已提交
83 84 85

下方将以himci.c为示例,展示需要厂商提供哪些内容来完整实现设备功能。

L
liyan 已提交
86 87 88
1. 驱动开发首先需要实例化驱动入口。

   驱动入口必须为HdfDriverEntry(在hdf_device_desc.h中定义)类型的全局变量,且moduleName要和device_info.hcs中保持一致。HDF框架会将所有加载的驱动的HdfDriverEntry对象首地址汇总,形成一个类似数组的段地址空间,方便上层调用。
D
duangavin123 已提交
89 90 91 92 93 94 95 96

   一般在加载驱动时HDF会先调用Bind函数,再调用Init函数加载该驱动。当Init调用异常时,HDF框架会调用Release释放驱动资源并退出。

     MMC驱动入口参考:
     
   ```
   struct HdfDriverEntry g_mmcDriverEntry = {
       .moduleVersion = 1,
97 98 99 100
       .Bind = HimciMmcBind,             // 见Bind参考
       .Init = HimciMmcInit,             // 见Init参考
       .Release = HimciMmcRelease,       // 见Release参考
       .moduleName = "hi3516_mmc_driver",// 【必要且与HCS文件中里面的moduleName匹配】
D
duangavin123 已提交
101
   };
102
   HDF_INIT(g_mmcDriverEntry);           // 调用HDF_INIT将驱动入口注册到HDF框架中
D
duangavin123 已提交
103 104
   ```

L
liyan 已提交
105 106 107 108 109 110
2. 完成驱动入口注册之后,下一步请在device_info.hcs文件中添加deviceNode信息,并在mmc_config.hcs中配置器件属性。

   deviceNode信息与驱动入口注册相关,器件属性值与核心层MmcCntlr成员的默认值或限制范围有密切关系。

   如有多个器件信息,则需要在device_info文件增加deviceNode信息,以及在mmc_config文件中增加对应的器件属性。

111
   - device_info.hcs 配置参考
D
duangavin123 已提交
112 113 114 115 116 117 118 119 120 121 122 123 124 125
   
       
     ```
     root {
       device_info {
         match_attr = "hdf_manager";
         platform :: host {
           hostName = "platform_host";
           priority = 50;
           device_mmc:: device {
             device0 :: deviceNode {
               policy = 2;
               priority = 10;
               permission = 0644;
L
liyan 已提交
126 127 128
               moduleName = "hi3516_mmc_driver";   // 【必要】用于指定驱动名称,需要与驱动Entry中的moduleName一致。
               serviceName = "HDF_PLATFORM_MMC_0"; // 【必要】驱动对外发布服务的名称,必须唯一。
               deviceMatchAttr = "hi3516_mmc_emmc";// 【必要】用于配置控制器私有数据,要与mmc_config.hcs中对应控制器保持一致。
D
duangavin123 已提交
129 130 131 132 133 134 135
             }
             device1 :: deviceNode {
               policy = 1;
               priority = 20;
               permission = 0644;
               moduleName = "hi3516_mmc_driver";
               serviceName = "HDF_PLATFORM_MMC_1";
136
               deviceMatchAttr = "hi3516_mmc_sd"; // SD类型
D
duangavin123 已提交
137 138 139 140 141 142 143
             }
             device2 :: deviceNode {
               policy = 1;
               priority = 30;
               permission = 0644;
               moduleName = "hi3516_mmc_driver";
               serviceName = "HDF_PLATFORM_MMC_2";
144
               deviceMatchAttr = "hi3516_mmc_sdio";// SDIO类型
D
duangavin123 已提交
145 146 147 148 149 150 151
             }
           }
         }
       }
     }
     ```
   
152
   - mmc_config.hcs配置参考
D
duangavin123 已提交
153 154 155 156 157 158
   
       
     ```
     root {
       platform {
         mmc_config {
L
liyan 已提交
159
           template mmc_controller { // 模板公共参数,继承该模板的节点如果使用模板中的默认值,则节点字段可以缺省。
D
duangavin123 已提交
160 161
             match_attr = "";
             voltDef = 0;            // 3.3V
162 163 164 165 166 167
             freqMin = 50000;        // 【必要】最小频率值
             freqMax = 100000000;    // 【必要】最大频率值
             freqDef = 400000;       // 【必要】默认频率值
             maxBlkNum = 2048;       // 【必要】最大的block号
             maxBlkSize = 512;       // 【必要】最大的block个数
             ocrDef = 0x300000;      // 【必要】工作电压设置相关
L
liyan 已提交
168
             caps2 = 0;              // 【必要】属性寄存器相关,见mmc_caps.h中MmcCaps2定义。
169 170 171 172
             regSize = 0x118;        // 【必要】寄存器位宽
             hostId = 0;             // 【必要】主机号
             regBasePhy = 0x10020000;// 【必要】寄存器物理基地址
             irqNum = 63;            // 【必要】中断号
L
liyan 已提交
173 174
             devType = 2;            // 【必要】模式选择:emmc、SD、SDIO、COMBO
             caps = 0x0001e045;      // 【必要】属性寄存器相关,见mmc_caps.h中MmcCaps 定义。
D
duangavin123 已提交
175 176
           }
           controller_0x10100000 :: mmc_controller {
177
             match_attr = "hi3516_mmc_emmc";// 【必要】需要和device_info.hcs中的deviceMatchAttr值一致
D
duangavin123 已提交
178 179 180 181 182 183 184 185 186 187 188 189
             hostId = 0;
             regBasePhy = 0x10100000;
             irqNum = 96;
             devType = 0;            // emmc类型
             caps = 0xd001e045;
             caps2 = 0x60;
           }
           controller_0x100f0000 :: mmc_controller {
             match_attr = "hi3516_mmc_sd";
             hostId = 1;
             regBasePhy = 0x100f0000;
             irqNum = 62;
190
             devType = 1;            // SD类型
D
duangavin123 已提交
191 192 193 194 195 196 197
             caps = 0xd001e005;
           }
           controller_0x10020000 :: mmc_controller {
             match_attr = "hi3516_mmc_sdio";
             hostId = 2;
             regBasePhy = 0x10020000;
             irqNum = 63;
198
             devType = 2;            // SDIO类型
D
duangavin123 已提交
199 200 201 202 203 204 205
             caps = 0x0001e04d;
           }
         }
       }
     }
     ```

L
liyan 已提交
206 207
3. 完成驱动入口注册之后,下一步就是以核心层MmcCntlr对象的初始化为核心,包括厂商自定义结构体(传递参数和数据),实例化MmcCntlr成员MmcCntlrOps(让用户可以通过接口来调用驱动底层函数),实现HdfDriverEntry成员函数(Bind、Init、Release)。

208
   - 自定义结构体参考
D
duangavin123 已提交
209

L
liyan 已提交
210
      从驱动的角度看,自定义结构体是参数和数据的载体,而且mmc_config.hcs文件中的数值会被HDF读入并通过DeviceResourceIface来初始化结构体成员,一些重要数值也会传递给核心层对象。
D
duangavin123 已提交
211 212 213 214

        
      ```
      struct HimciHost {
215
          struct MmcCntlr *mmc;// 【必要】核心层结构体
L
liyan 已提交
216
          struct MmcCmd *cmd;  // 【必要】核心层结构体,传递命令的,相关命令见枚举量MmcCmdCode。
217
          // 【可选】根据厂商驱动需要添加
D
duangavin123 已提交
218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233
          void *base;
          enum HimciPowerStatus powerStatus;
          uint8_t *alignedBuff;
          uint32_t buffLen;
          struct scatterlist dmaSg;
          struct scatterlist *sg;
          uint32_t dmaSgNum;
          DMA_ADDR_T dmaPaddr;
          uint32_t *dmaVaddr;
          uint32_t irqNum;
          bool isTuning;
          uint32_t id;
          struct OsalMutex mutex;
          bool waitForEvent;
          HIMCI_EVENT himciEvent;
      };
L
liyan 已提交
234
      // MmcCntlr是核心层控制器结构体,其中的成员在Bind函数中会被赋值。
D
duangavin123 已提交
235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256
      struct MmcCntlr {
          struct IDeviceIoService service;
          struct HdfDeviceObject *hdfDevObj;
          struct PlatformDevice device;
          struct OsalMutex mutex;
          struct OsalSem released;
          uint32_t devType;
          struct MmcDevice *curDev;
          struct MmcCntlrOps *ops;
          struct PlatformQueue *msgQueue;
          uint16_t index;
          uint16_t voltDef;
          uint32_t vddBit;
          uint32_t freqMin;
          uint32_t freqMax;
          uint32_t freqDef;
          union MmcOcr ocrDef;
          union MmcCaps caps;
          union MmcCaps2 caps2;
          uint32_t maxBlkNum;
          uint32_t maxBlkSize;
          uint32_t maxReqSize;
S
s00442234 已提交
257
          bool devPlugged;
D
duangavin123 已提交
258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275
          bool detecting;
          void *priv;
      };
      ```

   - MmcCntlr成员回调函数结构体MmcCntlrOps的实例化,其他成员在Bind函数中初始化。

        
      ```
      static struct MmcCntlrOps g_himciHostOps = {
          .request        = HimciDoRequest,
          .setClock       = HimciSetClock,
          .setPowerMode   = HimciSetPowerMode,
          .setBusWidth    = HimciSetBusWidth,
          .setBusTiming   = HimciSetBusTiming,
          .setSdioIrq     = HimciSetSdioIrq,
          .hardwareReset  = HimciHardwareReset,
          .systemInit     = HimciSystemInit,
S
s00442234 已提交
276
          .setEnhanceStrobe= HimciSetEnhanceStrobe,
D
duangavin123 已提交
277 278
          .switchVoltage  = HimciSwitchVoltage,
          .devReadOnly    = HimciDevReadOnly,
S
s00442234 已提交
279
          .devPlugged     = HimciCardPlugged,
D
duangavin123 已提交
280 281 282 283 284 285 286
          .devBusy        = HimciDevBusy,
          .tune           = HimciTune,
          .rescanSdioDev  = HimciRescanSdioDev,
      };
      ```
   - Bind函数参考

L
liyan 已提交
287
      入参:
D
duangavin123 已提交
288

L
liyan 已提交
289
      HdfDeviceObject是整个驱动对外暴露的接口参数,具备HCS配置文件的信息。
D
duangavin123 已提交
290 291 292

      返回值:

L
liyan 已提交
293
      HDF_STATUS相关状态(下表为部分展示,如需使用其他状态,可见//drivers/framework/include/utils/hdf_base.h中HDF_STATUS定义)。
D
duangavin123 已提交
294 295 296 297 298 299 300 301 302 303 304 305

        | 状态(值) | 问题描述 | 
      | -------- | -------- |
      | HDF_ERR_INVALID_OBJECT | 控制器对象非法 | 
      | HDF_ERR_MALLOC_FAIL | 内存分配失败 | 
      | HDF_ERR_INVALID_PARAM | 参数非法 | 
      | HDF_ERR_IO | I/O&nbsp;错误 | 
      | HDF_SUCCESS | 初始化成功 | 
      | HDF_FAILURE | 初始化失败 | 

      函数说明:

L
liyan 已提交
306
      MmcCntlr、HimciHost、HdfDeviceObject之间互相赋值,方便其他函数可以相互转化,初始化自定义结构体HimciHost对象,初始化MmcCntlr成员,调用核心层MmcCntlrAdd函数。
D
duangavin123 已提交
307 308 309 310 311 312 313 314 315 316 317

        
      ```
      static int32_t HimciMmcBind(struct HdfDeviceObject *obj)
      {
          struct MmcCntlr *cntlr = NULL;
          struct HimciHost *host = NULL;
          int32_t ret;
          cntlr = (struct MmcCntlr *)OsalMemCalloc(sizeof(struct MmcCntlr));
          host = (struct HimciHost *)OsalMemCalloc(sizeof(struct HimciHost));
          
L
liyan 已提交
318 319 320 321 322 323
          host->mmc = cntlr;                       // 【必要】使HimciHost与MmcCntlr可以相互转化的前提
          cntlr->priv = (void *)host;              // 【必要】使HimciHost与MmcCntlr可以相互转化的前提
          cntlr->ops = &g_himciHostOps;            // 【必要】MmcCntlrOps的实例化对象的挂载
          cntlr->hdfDevObj = obj;                  // 【必要】使HdfDeviceObject与MmcCntlr可以相互转化的前提
          obj->service = &cntlr->service;          // 【必要】使HdfDeviceObject与MmcCntlr可以相互转化的前提
          ret = MmcCntlrParse(cntlr, obj);         // 【必要】 初始化cntlr,失败就goto _ERR。
D
duangavin123 已提交
324
          ... 
L
liyan 已提交
325
          ret = HimciHostParse(host, obj);         // 【必要】 初始化host对象的相关属性,失败就goto _ERR。
D
duangavin123 已提交
326
          ...
L
liyan 已提交
327
          ret = HimciHostInit(host, cntlr);        // 厂商自定义的初始化,失败就goto _ERR。
D
duangavin123 已提交
328
          ...
L
liyan 已提交
329
          ret = MmcCntlrAdd(cntlr);                // 调用核心层函数,失败就goto _ERR。
D
duangavin123 已提交
330
          ...
331
          (void)MmcCntlrAddDetectMsgToQueue(cntlr);// 将卡检测消息添加到队列中。
D
duangavin123 已提交
332 333 334 335 336 337 338 339 340 341 342 343 344
          HDF_LOGD("HimciMmcBind: success.");
          return HDF_SUCCESS;
      _ERR:
          HimciDeleteHost(host);
          HDF_LOGD("HimciMmcBind: fail, err = %d.", ret);
          return ret;
      }
      ```

   - Init函数参考

      入参:

L
liyan 已提交
345
      HdfDeviceObject是整个驱动对外暴露的接口参数,具备HCS配置文件的信息。
D
duangavin123 已提交
346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364

      返回值:

      HDF_STATUS相关状态。

      函数说明:

      实现ProcMciInit。

        
      ```
      static int32_t HimciMmcInit(struct HdfDeviceObject *obj)
      {
          static bool procInit = false;
          (void)obj;
          if (procInit == false) {
              if (ProcMciInit() == HDF_SUCCESS) {
                  procInit = true;
                  HDF_LOGD("HimciMmcInit: proc init success.");
D
duangavin123 已提交
365 366
              }
          }
D
duangavin123 已提交
367 368 369 370 371 372 373 374
          HDF_LOGD("HimciMmcInit: success.");
          return HDF_SUCCESS;
      }
      ```
   - Release函数参考

      入参:

L
liyan 已提交
375
      HdfDeviceObject是整个驱动对外暴露的接口参数,具备HCS配置文件的信息。
D
duangavin123 已提交
376 377 378 379

      返回值:

      无。
D
duangavin123 已提交
380

D
duangavin123 已提交
381
      函数说明:
D
duangavin123 已提交
382

L
liyan 已提交
383 384 385 386 387
      释放内存和删除控制器等操作,该函数需要在驱动入口结构体中赋值给Release接口,当HDF框架调用Init函数初始化驱动失败时,可以调用 Release释放驱动资源。

      > ![icon-note.gif](public_sys-resources/icon-note.gif) **说明:**<br>
      > 所有强制转换获取相应对象的操作前提是在Init函数中具备对应赋值的操作。

D
duangavin123 已提交
388

D
duangavin123 已提交
389 390 391 392 393 394
        
      ```
      static void HimciMmcRelease(struct HdfDeviceObject *obj)
      {
          struct MmcCntlr *cntlr = NULL;
          ...
L
liyan 已提交
395
          cntlr = (struct MmcCntlr *)obj->service;         // 这里有HdfDeviceObject到MmcCntlr的强制转化,通过service成员,赋值见Bind函数。
D
duangavin123 已提交
396
          ...
L
liyan 已提交
397
          HimciDeleteHost((struct HimciHost *)cntlr->priv);// 厂商自定义的内存释放函数,这里有MmcCntlr到HimciHost的强制转化。
D
duangavin123 已提交
398 399
      }
      ```