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