• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1# MMC
2
3## Overview
4
5### Function
6
7A multimedia card (MMC) is a small-sized and large-capacity flash memory card used for solid-state non-volatile storage.
8
9Nowadays, MMC refers to a standard driver interface to solid-state storage cards. Memory devices that comply with this standard can be called MMCs. An MMC consists of the MMC controller, MMC bus, and memory card, which can be an MMC, Secure Digital (SD) card, Secure Digital Input Output (SDIO) card, or TransFlash (TF) card.
10
11The MMC, SD, and SDIO buses have similar bus specifications, which have evolved from the MMC bus specifications. The MMC features multimedia storage; the SD focuses on security and data protection; the SDIO, evolving from the SD, provides the interface regardless of the specific form of the peer end (Wi-Fi, Bluetooth, or GPS device).
12
13### Basic Concepts
14
15- SD card
16
17  Introduced as an improvement over the MMC, the SD cards can protect their contents from erasure or modification, prevent unauthorized access, and protect copyrighted content using digital rights management. The size of a standard SD card is 24 mm x 32 mm x 2.1 mm, which is a little thicker than an MMC card. The SD cards are forward compatible with MMC cards, that is, all devices that support SD cards also support MMC cards.
18
19- SDIO
20
21  SDIO is an interface designed as an extension for the SD card standard. It introduces the low-speed transfer standard, which supports low-speed I/O with the minimum hardware overhead. The SDIO interface is compatible with the SD cards.
22
23### Working Principles
24
25In the Hardware Driver Foundation (HDF), the MMC uses the independent service mode (see Figure 1) for API adaptation. In this mode, each device independently publishes a service to process external access requests. When receiving an access request, the HDF DeviceManager extracts parameters from the request to call the internal APIs of the target device. In the independent service mode, the HDF DeviceManager provides service management capabilities. However, you need to configure a node for each device, which increases memory usage.
26
27In the independent service mode, the core layer does not publish a service for the upper layer. Therefore, a service must be published for each controller. To achieve this purpose:
28
29- You need to implement the **Bind()** function in **HdfDriverEntry** to bind services.
30- The **policy** field of **deviceNode** in the **device_info.hcs** file must be **1** or **2**, but not **0**.
31
32The MMC module is divided into the following layers:
33
34- Interface layer: provides APIs for opening an MMC device, checking whether the MMC controller has devices, and closing an MMC device.
35- Core layer: provides the capabilities of adding or removing an MMC controller, performing device management, and providing common controller services. The core layer interacts with the adaptation layer through hook functions.
36- Adaptation layer: instantiates the hook functions to implement specific features.
37
38**Figure 1** Independent service mode
39
40![img1](figures/independent-service-mode.png)
41
42## Development Guidelines
43
44### When to Use
45
46The MMC is used to store multimedia files. Before using your MMC device with OpenHarmony, you need to perform MMC driver adaptation.
47
48### Available APIs
49
50To enable the upper layer to successfully operate the MMC controller by calling the MMC APIs, hook functions are defined in **//drivers/hdf_core/framework/model/storage/include/mmc/mmc_corex.h** for the core layer. You need to implement these hook functions at the adaptation layer and hook them to implement the interaction between the interface layer and the core layer.
51
52**MmcCntlrOps**:
53
54```c
55struct MmcCntlrOps {
56    int32_t (*request)(struct MmcCntlr *cntlr, struct MmcCmd *cmd);
57    int32_t (*setClock)(struct MmcCntlr *cntlr, uint32_t clock);
58    int32_t (*setPowerMode)(struct MmcCntlr *cntlr, enum MmcPowerMode mode);
59    int32_t (*setBusWidth)(struct MmcCntlr *cntlr, enum MmcBusWidth width);
60    int32_t (*setBusTiming)(struct MmcCntlr *cntlr, enum MmcBusTiming timing);
61    int32_t (*setSdioIrq)(struct MmcCntlr *cntlr, bool enable);
62    int32_t (*hardwareReset)(struct MmcCntlr *cntlr);
63    int32_t (*systemInit)(struct MmcCntlr *cntlr);
64    int32_t (*setEnhanceStrobe)(struct MmcCntlr *cntlr, bool enable);
65    int32_t (*switchVoltage)(struct MmcCntlr *cntlr, enum MmcVolt volt);
66    bool (*devReadOnly)(struct MmcCntlr *cntlr);
67    bool (*devPlugged)(struct MmcCntlr *cntlr);
68    bool (*devBusy)(struct MmcCntlr *cntlr);
69    int32_t (*tune)(struct MmcCntlr *cntlr, uint32_t cmdCode);
70    int32_t (*rescanSdioDev)(struct MmcCntlr *cntlr);
71};
72```
73
74**Table 1** Hook functions in **MmcCntlrOps**
75
76| Function| Input Parameter| Return Value| Description|
77| -------- | -------- | -------- | -------- |
78| doRequest | **cntlr**: structure pointer to the MMC controller at the core layer.<br>**cmd**: structure pointer to the command to execute.| HDF_STATUS| Processes the request.|
79| setClock | **cntlr**: structure pointer to the MMC controller at the core layer.<br>**clock**: clock frequency to set.| HDF_STATUS| Sets the clock frequency.|
80| setPowerMode | **cntlr**: structure pointer to the MMC controller at the core layer.<br>**mode**: power consumption mode. For details, see **MmcPowerMode**.| HDF_STATUS| Sets the power consumption mode.|
81| setBusWidth | **cntlr**: structure pointer to the MMC controller at the core layer.<br>**width**: bus width. For details, see **MmcBusWidth**.| HDF_STATUS| Sets the bus width.|
82| setBusTiming | **cntlr**: structure pointer to the MMC controller at the core layer.<br>**timing**: bus timing. For details, see **MmcBusTiming**.| HDF_STATUS| Sets the bus timing.|
83| setSdioIrq | **cntlr**: structure pointer to the MMC controller at the core layer.<br>**enable**: whether to enable SDIO interrupts.| HDF_STATUS| Enables or disables SDIO interrupts.|
84| hardwareReset | **cntlr**: structure pointer to the MMC controller at the core layer.| HDF_STATUS| Resets hardware.|
85| systemInit | **cntlr**: structure pointer to the MMC controller at the core layer.| HDF_STATUS| Performs system initialization.|
86| setEnhanceStrobe | **cntlr**: structure pointer to the MMC controller at the core layer.<br>**enable**: whether to enable the enhanced strobe feature.| HDF_STATUS| Sets the enhanced strobe feature.|
87| switchVoltage | **cntlr**: structure pointer to the MMC controller at the core layer.<br>**volt**: voltage to set, which can be 3.3 V, 1.8 V, or 1.2 V.| HDF_STATUS| Sets the voltage.|
88| devReadOnly | **cntlr**: structure pointer to the MMC controller at the core layer.| Boolean value| Checks whether the device is read-only.|
89| cardPlugged | **cntlr**: structure pointer to the MMC controller at the core layer.| Boolean value| Checks whether the device is removed.|
90| devBusy | **cntlr**: structure pointer to the MMC controller at the core layer.| Boolean value| Checks whether the device is being used.|
91| tune | **cntlr**: structure pointer to the MMC controller at the core layer.<br>**cmdCode**: command code, which is of the uint32_t type.| HDF_STATUS| Tunes the oscillator circuit frequency.|
92| rescanSdioDev | **cntlr**: structure pointer to the MMC controller at the core layer.| HDF_STATUS| Scans and adds an SDIO device.|
93
94### How to Develop
95
96The MMC module adaptation procedure is as follows:
97
981. Instantiate the driver entry.
992. Configure attribute files.
1003. Instantiate the MMC controller object.
1014. Debug the driver.
102
103### Example
104
105The following uses the **//device_soc_hisilicon/common/platform/mmc/himci_v200/himci.c** driver of the Hi3516D V300 development board as an example to describe the driver adaptation.
106
1071. Instantiate the driver entry.
108
109   The driver entry must be a global variable of the **HdfDriverEntry** type (defined in **hdf_device_desc.h**), and the value of **moduleName** must be the same as that in **device_info.hcs**. In the HDF, the start address of each **HdfDriverEntry** object of all loaded drivers is collected to form a segment address space similar to an array for the upper layer to invoke.
110   Generally, the HDF calls the **Bind** function and then the **Init** function to load a driver. If **Init** fails to be called, the HDF calls **Release** to release driver resources and exit.
111
112   MMC driver entry example:
113
114   ```c
115   struct HdfDriverEntry g_mmcDriverEntry = {
116       .moduleVersion = 1,
117       .Bind = HimciMmcBind,                 // See the Bind function.
118       .Init = HimciMmcInit,                 // See the Init function.
119       .Release = HimciMmcRelease,           // See the Release function.
120       .moduleName = "hi3516_mmc_driver",    // (Mandatory) The value must be the same as that of moduleName in the .hcs file.
121   };
122   HDF_INIT(g_mmcDriverEntry);               // Call HDF_INIT to register the driver entry with the HDF.
123   ```
124
1252. Configure attribute files.
126
127   Add the deviceNode information to the **device_info.hcs** file. The deviceNode information is related to the driver entry registration. The following example uses three MMC controllers as an example. If there are more MMC controllers, add the deviceNode information to the **device_info.hcs** file for each controller. The device attribute values configured in **mmc_config.hcs** are closely related to the default values or value ranges of the **MmcCntlr** members at the core layer.
128
129   - **device_info.hcs** example:
130
131      Add the deviceNode information to the **//vendor/hisilicon/hispark_taurus/hdf_config/device_info/device_info.hcs** file.
132
133      ```c
134      root {
135          device_info {
136              match_attr = "hdf_manager";
137              platform :: host {
138                  hostName = "platform_host";
139                  priority = 50;
140                  device_mmc:: device {
141                      device0 :: deviceNode {                     // DeviceNode of the driver.
142                          policy = 2;                             // The value 2 means to publish services for both kernel- and user-mode processes.
143                          priority = 10;                          // Driver startup priority.
144                          permission = 0644;                      // Permission for the device node created.
145                          moduleName = "hi3516_mmc_driver";       // (Mandatory) Driver name, which must be the same as moduleName in the driver entry.
146                          serviceName = "HDF_PLATFORM_MMC_0";     // (Mandatory) Unique name of the service published by the driver.
147                          deviceMatchAttr = "hi3516_mmc_emmc";    // (Mandatory) Private data of the controller. The value must be the same as the controller information in mmc_config.hcs.
148                      }
149                      device1 :: deviceNode {
150                          policy = 1;
151                          priority = 20;
152                          permission = 0644;
153                          moduleName = "hi3516_mmc_driver";
154                          serviceName = "HDF_PLATFORM_MMC_1";
155                          deviceMatchAttr = "hi3516_mmc_sd";      // The MMC is an SD card.
156                      }
157                      device2 :: deviceNode {
158                          policy = 1;
159                          priority = 30;
160                          permission = 0644;
161                          moduleName = "hi3516_mmc_driver";
162                          serviceName = "HDF_PLATFORM_MMC_2";
163                          deviceMatchAttr = "hi3516_mmc_sdio";    // The MMC is an SDIO card.
164                      }
165                      ...
166                  }
167              }
168          }
169      }
170      ```
171
172   - **mmc_config.hcs** example
173
174      Configure the device attributes in the **//device/soc/hisilicon/hi3516dv300/sdk_liteos/hdf_config/mmc/mmc_config.hcs** file. The parameters are as follows:
175
176      ```c
177      root {
178          platform {
179              mmc_config {
180                  template mmc_controller {                     // Template configuration. If the template is used to configure device node information, the default values in the template will be used for the fields that are not declared for the node.
181                      match_attr = "";
182                      voltDef = 0;                              // MMC default voltage. The value 0 stands for 3.3 V, 1 for 1.8 V, and 2 for 1.2 V.
183                      freqMin = 50000;                          // (Mandatory) Minimum frequency.
184                      freqMax = 100000000;                      // (Mandatory) Maximum frequency.
185                      freqDef = 400000;                         // (Mandatory) Default frequency.
186                      maxBlkNum = 2048;                         // (Mandatory) Maximum block number.
187                      maxBlkSize = 512;                         // (Mandatory) Maximum block size.
188                      ocrDef = 0x300000;                        // (Mandatory) working voltage.
189                      caps2 = 0;                                // (Mandatory) Attribute register. For details, see MmcCaps2 in mmc_caps.h.
190                      regSize = 0x118;                          // (Mandatory) Register size.
191                      hostId = 0;                               // (Mandatory) Host number.
192                      regBasePhy = 0x10020000;                  // (Mandatory) Physical base address of the register.
193                      irqNum = 63;                              // (Mandatory) IRQ number.
194                      devType = 2;                              // (Mandatory) Device type, which can be eMMC, SD, SDIO, or COMBO.
195                      caps = 0x0001e045;                        // (Mandatory) Attribute register. For details, see MmcCaps in mmc_caps.h.
196                  }
197                  controller_0x10100000 :: mmc_controller {
198                      match_attr = "hi3516_mmc_emmc";           // (Mandatory) The value must be the same as deviceMatchAttr in device_info.hcs.
199                      hostId = 0;
200                      regBasePhy = 0x10100000;
201                      irqNum = 96;
202                      devType = 0;                              // The device is an eMMC card.
203                      caps = 0xd001e045;
204                      caps2 = 0x60;
205                  }
206                  controller_0x100f0000 :: mmc_controller {
207                      match_attr = "hi3516_mmc_sd";
208                      hostId = 1;
209                      regBasePhy = 0x100f0000;
210                      irqNum = 62;
211                      devType = 1;                              // The device is an SD card.
212                      caps = 0xd001e005;
213                  }
214                  controller_0x10020000 :: mmc_controller {
215                      match_attr = "hi3516_mmc_sdio";
216                      hostId = 2;
217                      regBasePhy = 0x10020000;
218                      irqNum = 63;
219                      devType = 2;                              // The device is an SDIO card.
220                      caps = 0x0001e04d;
221                  }
222              }
223          }
224      }
225      ```
226
227      After the **mmc_config.hcs** file is configured, include the file in the **hdf.hcs** file. Otherwise, the configuration file cannot take effect.
228
229      ```c
230      #include "../../../../device/soc/hisilicon/hi3516dv300/sdk_liteos/hdf_config/mmc/mmc_config.hcs" // Relative path of the file.
231      ```
232
2333. Instantiate the MMC controller object.
234
235   Initialize the **MmcCntlr** object at the core layer, including defining a custom structure (to pass parameters and data) and implementing the **HdfDriverEntry** member functions (**Bind**, **Init** and **Release**) to instantiate **MmcCntlrOps** in **MmcCntlr** (so that the underlying driver functions can be called).
236
237   - Define a custom structure.
238
239      To the driver, the custom structure holds parameters and data. The **DeviceResourceIface** method provided by the HDF reads the values in the **mmc_config.hcs** file to initialize the members in the custom structure and passes important parameters to the **MmcCntlr** object at the core layer.
240
241      ```c
242      struct HimciHost {
243          struct MmcCntlr *mmc;                             // (Mandatory) Core layer control object.
244          struct MmcCmd *cmd                                // (Mandatory) Core layer structure used to pass commands. For details about related commands, see MmcCmdCode.
245          void *base;                                       // Register base address used for address mapping.
246          enum HimciPowerStatus powerStatus;
247          uint8_t *alignedBuff;
248          uint32_t buffLen;
249          struct scatterlist dmaSg;
250          struct scatterlist *sg;
251          uint32_t dmaSgNum;
252          DMA_ADDR_T dmaPaddr;
253          uint32_t *dmaVaddr;
254          uint32_t irqNum;
255          bool isTuning;
256          uint32_t id;
257          struct OsalMutex mutex;
258          bool waitForEvent;
259          HIMCI_EVENT himciEvent;
260      };
261      // MmcCntlr is the core layer controller structure. The Bind function assigns values to the members of MmcCntlr.
262      struct MmcCntlr {
263          struct IDeviceIoService service;
264          struct HdfDeviceObject *hdfDevObj;
265          struct PlatformDevice device;
266          struct OsalMutex mutex;
267          struct OsalSem released;
268          uint32_t devType;
269          struct MmcDevice *curDev;
270          struct MmcCntlrOps *ops;
271          struct PlatformQueue *msgQueue;
272          uint16_t index;
273          uint16_t voltDef;
274          uint32_t vddBit;
275          uint32_t freqMin;
276          uint32_t freqMax;
277          uint32_t freqDef;
278          union MmcOcr ocrDef;
279          union MmcCaps caps;
280          union MmcCaps2 caps2;
281          uint32_t maxBlkNum;
282          uint32_t maxBlkSize;
283          uint32_t maxReqSize;
284          bool devPlugged;
285          bool detecting;
286          void *priv;
287      };
288      ```
289
290   - Instantiate **MmcCntlrOps** in **MmcCntlr**.
291
292      ```c
293      static struct MmcCntlrOps g_himciHostOps = {
294          .request = HimciDoRequest,
295          .setClock = HimciSetClock,
296          .setPowerMode = HimciSetPowerMode,
297          .setBusWidth = HimciSetBusWidth,
298          .setBusTiming = HimciSetBusTiming,
299          .setSdioIrq = HimciSetSdioIrq,
300          .hardwareReset = HimciHardwareReset,
301          .systemInit = HimciSystemInit,
302          .setEnhanceStrobe = HimciSetEnhanceStrobe,
303          .switchVoltage = HimciSwitchVoltage,
304          .devReadOnly = HimciDevReadOnly,
305          .devPlugged = HimciCardPlugged,
306          .devBusy = HimciDevBusy,
307          .tune = HimciTune,
308          .rescanSdioDev = HimciRescanSdioDev,
309      };
310      ```
311
312   - Implement the **Bind** function.
313
314      **Input parameter**:
315
316      **HdfDeviceObject**, a device object created by the HDF for each driver, holds device-related private data and service APIs.
317
318      **Return value**:
319
320      **HDF_STATUS**<br/>The table below describes some status. For more information, see **HDF_STATUS** in the **//drivers/hdf_core/framework/include/utils/hdf_base.h** file.
321
322      **Table 2** HDF_STATUS description
323
324      | Status| Description|
325      | -------- | -------- |
326      | HDF_ERR_INVALID_OBJECT | Invalid controller object.|
327      | HDF_ERR_MALLOC_FAIL | Failed to allocate memory.|
328      | HDF_ERR_INVALID_PARAM | Invalid parameter.|
329      | HDF_ERR_IO | I/O error.|
330      | HDF_SUCCESS | Initialization successful.|
331      | HDF_FAILURE | Initialization failed.|
332
333      **Function description**:
334
335      Initializes the **HimciHost** object and **MmcCntlr**, and calls the **MmcCntlrAdd** function at the core layer to add the MMC controllers.
336
337      ```c
338      static int32_t HimciMmcBind(struct HdfDeviceObject *obj)
339      {
340          struct MmcCntlr *cntlr = NULL;
341          struct HimciHost *host = NULL;
342          int32_t ret;
343          cntlr = (struct MmcCntlr *)OsalMemCalloc(sizeof(struct MmcCntlr));
344          host = (struct HimciHost *)OsalMemCalloc(sizeof(struct HimciHost));
345
346          host->mmc = cntlr;                              // (Mandatory) Prerequisites for conversion between HimciHost and MmcCntlr.
347          cntlr->priv = (void *)host;                     // (Mandatory) Prerequisites for conversion between HimciHost and MmcCntlr.
348          cntlr->ops = &g_himciHostOps;                   // (Mandatory) Attach the MmcCntlrOps instance to MmcCntlr.
349          cntlr->hdfDevObj = obj;                         // (Mandatory) Prerequisites for conversion between HdfDeviceObject and MmcCntlr.
350          obj->service = &cntlr->service;                 // (Mandatory) Prerequisites for conversion between HdfDeviceObject and MmcCntlr.
351          ret = MmcCntlrParse(cntlr, obj);                // (Mandatory) Initialize MmcCntlr. If the initialization fails, execute goto _ERR.
352          ...
353          ret = HimciHostParse(host, obj);                // (Mandatory) Initialize HimciHost. If the initialization fails, execute goto _ERR.
354          ...
355          ret = HimciHostInit(host, cntlr);               // Customized initizlization. If the initialization fails, goto _ERR.
356          ...
357          ret = MmcCntlrAdd(cntlr);                       // Call MmcCntlrAdd at the core layer. If the operation fails, execute goto _ERR.
358          ...
359          (void)MmcCntlrAddDetectMsgToQueue(cntlr);       // Add the card detection message to the queue.
360          HDF_LOGD("HimciMmcBind: success.");
361          return HDF_SUCCESS;
362      ERR:
363          HimciDeleteHost(host);
364          HDF_LOGD("HimciMmcBind: fail, err = %d.", ret);
365          return ret;
366      }
367      ```
368
369   - Implement the **Init** function.
370
371      **Input parameter**:
372
373      **HdfDeviceObject**, a device object created by the HDF for each driver, holds device-related private data and service APIs.
374
375      **Return value**:
376
377      HDF_STATUS
378
379      **Function description**:
380
381      Implements **ProcMciInit**.
382
383      ```c
384      static int32_t HimciMmcInit(struct HdfDeviceObject *obj)
385      {
386          static bool procInit = false;
387          (void)obj;
388          if (procInit == false) {
389              if (ProcMciInit() == HDF_SUCCESS) {
390                  procInit = true;
391                  HDF_LOGD("HimciMmcInit: proc init success.");
392              }
393          }
394          HDF_LOGD("HimciMmcInit: success.");
395          return HDF_SUCCESS;
396      }
397      ```
398
399   - Implement the **Release** function.
400
401      **Input parameter**:
402
403      **HdfDeviceObject**, a device object created by the HDF for each driver, holds device-related private data and service APIs.
404
405      **Return value**:
406
407      No value is returned.
408
409      **Function description**:
410
411      Releases the memory and deletes the controller. This function assigns values to **Release()** in the driver entry structure. If the HDF fails to call **Init()** to initialize the driver, **Release()** is called to release driver resources.
412
413      > ![icon-note.gif](public_sys-resources/icon-note.gif) **NOTE**<br>
414      > All forced conversion operations for obtaining the corresponding object can be successful only when **Init()** has the corresponding value assignment operations.
415
416      ```c
417      static void HimciMmcRelease(struct HdfDeviceObject *obj)
418      {
419          struct MmcCntlr *cntlr = NULL;
420          ...
421          cntlr = (struct MmcCntlr *)obj->service;             // Forcibly convert HdfDeviceObject to MmcCntlr by using service. For details about the value assignment, see the Bind function.
422          ...
423          HimciDeleteHost((struct HimciHost *)cntlr->priv);    // Memory release function customized. Forced conversion between MmcCntlr and HimciHost is involved.
424      }
425      ```
426
4274. Debug the driver.
428
429   (Optional) For new drivers, verify basic functions, for example, check the information returned after the driver is attached and whether data is successfully transmitted.
430