The MultiMediaCard (MMC)/Secure Digital (SD)/Secure Digital Input Output (SDIO) host driver implements a standard Linux driver interface to the ultra MMC/SD host controller (uSDHC). The host driver is part of the Linux kernel MMC framework.

Features

The i.MX8M Nano MMC driver supports:

  • MMC and SD cards

  • SDIO cards

  • SD3.0 cards

MMC on the ConnectCore 8M Nano platforms

On the ConnectCore 8M Nano system-on-module:

  • Internal eMMC is connected to uSDHC3 controller using eight data lines.

On the ConnectCore 8M Nano Development Kit:

  • J18 microSD card holder is connected to uSDHC2 controller using four data lines and a card detection line.

Kernel configuration

You can manage the MMC/uSDHC driver support through the following kernel configuration options:

  • MMC/SD/SDIO (CONFIG_MMC)

  • MMC block (CONFIG_MMC_BLOCK)

  • Secure Digital Host Controller Interface support (CONFIG_MMC_SDHCI)

  • SDHCI support on the platform-specific bus (CONFIG_MMC_SDHCI_PLTFM)

  • SDHCI platform support for the NXP eSDHC i.MX controller (CONFIG_MMC_SDHCI_ESDHC_IMX)

These options are enabled as built-in on the default ConnectCore 8M Nano kernel configuration file.

Kernel driver

The table below shows the uSDHC source files available in the kernel source directory: drivers/mmc/host/.

File Description

sdhci.c

standard stack code

sdhci-pltfm.c

sdhci platform layer

sdhci-esdhc-imx.c

uSDHC driver

sdhci-esdhc.h

uSDHC driver header file

Device tree bindings and customization

The i.MX8M Nano MMC/SD/SDIO interface device tree binding is documented at Documentation/devicetree/bindings/mmc/fsl-imx-esdhc.yaml.

Common MMC device tree bindings are documented at Documentation/devicetree/bindings/mmc/mmc-controller.yaml.

The MMC/SD/SDIO interfaces are defined in the i.MX8M Nano CPU, ConnectCore 8M Nano system-on-module, and ConnectCore 8M Nano Development Kit device tree files.

The common i.MX8M Nano CPU device tree defines all the uSDHC ports. The platform device tree must:

  • Enable the required uSDHC port, by setting the status property to "okay".

  • Select the bus-width depending on the number of data lines to use.

  • Select optional properties (broken-cd, no-1-8-v, non-removable…​), depending on the interface (see binding documentation).

  • Configure the IOMUX of the pads to use for the interface.

Do not modify the uSDHC1 controller because it is used to communicate with the Wi-Fi chip and defined in the ccimx8mn.dtsi include file:

ConnectCore 8M Nano device tree
/* USDHC1 (Wireless), disabled by default */
&usdhc1 {
	pinctrl-names = "default", "state_100mhz", "state_200mhz", "sleep";
	pinctrl-0 = <&pinctrl_usdhc1>;
	pinctrl-1 = <&pinctrl_usdhc1_100mhz>;
	pinctrl-2 = <&pinctrl_usdhc1_200mhz>;
	pinctrl-3 = <&pinctrl_usdhc1_sleep>;
	non-removable;
	bus-width = <4>;
	vmmc-supply = <&reg_rf_wl_en>;
	status = "disabled";
};

Example: eMMC

On the ConnectCore 8M Nano, the eMMC is connected to uSDHC3 controller using eight data lines.

Definition of the uSDHC3

i.MX8M Nano device tree
	usdhc3: mmc@30b60000 {
		compatible = "fsl,imx8mn-usdhc", "fsl,imx7d-usdhc";
		reg = <0x30b60000 0x10000>;
		interrupts = <GIC_SPI 24 IRQ_TYPE_LEVEL_HIGH>;
		clocks = <&clk IMX8MN_CLK_IPG_ROOT>,
			 <&clk IMX8MN_CLK_NAND_USDHC_BUS>,
			 <&clk IMX8MN_CLK_USDHC3_ROOT>;
		clock-names = "ipg", "ahb", "per";
		fsl,tuning-start-tap = <20>;
		fsl,tuning-step= <2>;
		bus-width = <4>;
		status = "disabled";
	};

IOMUX configuration

ConnectCore 8M Nano device tree
	/* eMMC */
	pinctrl_usdhc3: usdhc3grp {
		fsl,pins = <
			MX8MN_IOMUXC_NAND_WE_B_USDHC3_CLK		0x190
			MX8MN_IOMUXC_NAND_WP_B_USDHC3_CMD		0x1d0
			MX8MN_IOMUXC_NAND_DATA04_USDHC3_DATA0		0x1d0
			MX8MN_IOMUXC_NAND_DATA05_USDHC3_DATA1		0x1d0
			MX8MN_IOMUXC_NAND_DATA06_USDHC3_DATA2		0x1d0
			MX8MN_IOMUXC_NAND_DATA07_USDHC3_DATA3		0x1d0
			MX8MN_IOMUXC_NAND_RE_B_USDHC3_DATA4		0x1d0
			MX8MN_IOMUXC_NAND_CE2_B_USDHC3_DATA5		0x1d0
			MX8MN_IOMUXC_NAND_CE3_B_USDHC3_DATA6		0x1d0
			MX8MN_IOMUXC_NAND_CLE_USDHC3_DATA7		0x1d0
			MX8MN_IOMUXC_NAND_CE1_B_USDHC3_STROBE 		0x190
			MX8MN_IOMUXC_NAND_READY_B_USDHC3_RESET_B	0x190
		>;
	};

Device enabling and options

ConnectCore 8M Nano device tree
/* eMMC */
&usdhc3 {
	pinctrl-names = "default", "state_100mhz", "state_200mhz";
	pinctrl-0 = <&pinctrl_usdhc3>;
	pinctrl-1 = <&pinctrl_usdhc3_100mhz>;
	pinctrl-2 = <&pinctrl_usdhc3_200mhz>;
	bus-width = <8>;
	non-removable;
	status = "okay";
};

Example: microSD on the ConnectCore 8M Nano Development Kit

On the ConnectCore 8M Nano Development Kit, the microSD card holder is connected to uSDHC2 controller using four data lines and a card detection line. Runtime voltage select is not currently supported, and microSD card/bus voltage is set to 3.3 V by default.

Definition of the uSDHC2

i.MX8M Nano device tree
	usdhc2: mmc@30b50000 {
		compatible = "fsl,imx8mn-usdhc", "fsl,imx7d-usdhc";
		reg = <0x30b50000 0x10000>;
		interrupts = <GIC_SPI 23 IRQ_TYPE_LEVEL_HIGH>;
		clocks = <&clk IMX8MN_CLK_IPG_ROOT>,
			 <&clk IMX8MN_CLK_NAND_USDHC_BUS>,
			 <&clk IMX8MN_CLK_USDHC2_ROOT>;
		clock-names = "ipg", "ahb", "per";
		fsl,tuning-start-tap = <20>;
		fsl,tuning-step= <2>;
		bus-width = <4>;
		status = "disabled";
	};

IOMUX configuration

ConnectCore 8M Nano Development Kit device tree
	pinctrl_usdhc2_gpio: usdhc2gpiogrp {
		fsl,pins = <
			/* Card detect */
			MX8MN_IOMUXC_SD2_CD_B_GPIO2_IO12	0x1c4
		>;
	};

	pinctrl_usdhc2_vsel: usdhc2grp_vsel {
		fsl,pins = <
			MX8MN_IOMUXC_GPIO1_IO04_USDHC2_VSELECT	0x1d0
		>;
	};

	pinctrl_usdhc2: usdhc2grp {
		fsl,pins = <
			MX8MN_IOMUXC_SD2_CLK_USDHC2_CLK		0x190
			MX8MN_IOMUXC_SD2_CMD_USDHC2_CMD		0x1d0
			MX8MN_IOMUXC_SD2_DATA0_USDHC2_DATA0	0x1d0
			MX8MN_IOMUXC_SD2_DATA1_USDHC2_DATA1	0x1d0
			MX8MN_IOMUXC_SD2_DATA2_USDHC2_DATA2	0x1d0
			MX8MN_IOMUXC_SD2_DATA3_USDHC2_DATA3	0x1d0
		>;
	};

Device enabling and options

ConnectCore 8M Nano Development Kit device tree
/* Micro SD card */
&usdhc2 {
	pinctrl-names = "default", "state_100mhz", "state_200mhz";
	pinctrl-0 = <&pinctrl_usdhc2>, <&pinctrl_usdhc2_gpio>,
		    <&pinctrl_usdhc2_vsel>;
	pinctrl-1 = <&pinctrl_usdhc2_100mhz>, <&pinctrl_usdhc2_gpio>,
		    <&pinctrl_usdhc2_vsel>;
	pinctrl-2 = <&pinctrl_usdhc2_200mhz>, <&pinctrl_usdhc2_gpio>,
		    <&pinctrl_usdhc2_vsel>;
	bus-width = <4>;
	/*
	 * UHS-I mode (remove the no-1.8-v line to use this uSD in UHS-I mode).
	 * Check schematics for additional hardware changes needed.
	 */
	no-1-8-v;
	cd-gpios = <&gpio2 12 GPIO_ACTIVE_HIGH>;
	status = "okay";
};

User space usage

The MMC block driver handles the file system read/write calls and uses the low-level MMC host controller interface driver to send the commands to the uSDHC controller.

The MMC device driver exposes the device through the file system at /dev/mmcblkX where X is a number, starting at zero, that indicates the device index.

If the block device is partitioned, the partitions will appear as /dev/mmcblkXpY where Y is a number, starting at one, that indicates the partition index.

By default, formatted partitions are auto-mounted upon detection if they are block devices.

You can also mount a partition’s file system using the mount command with the partition node, the file system type, and the mount point:

# mkdir -p /run/media/mmcblk1p1 && mount -t vfat /dev/mmcblk1p1 /run/media/mmcblk1p1

MMC/SD/SDIO on the ConnectCore 8M Nano boards

Device node mapping

On the ConnectCore 8M Nano Development Kit device tree, the uSDHC interfaces are set up to be mapped by Linux as follows:

  • The eMMC (connected to uSDHC3) is mapped to /dev/mmcblk0.

  • The microSD card (connected to uSDHC2) is mapped to /dev/mmcblk1.

microSD card detection

The microSD card holder on the ConnectCore 8M Nano Development Kit has a card detection line.

Formatted partitions are auto-mounted upon card insertion.

If the device (microSD or eMMC) is not partitioned, you can use fdisk to create one partition of type .vfat and then give it format with mkfs, for example:

# echo -e 'o\nn\np\n1\n\n\nt\nb\nw\n' | fdisk /dev/mmcblk1 > /dev/null
# mkfs.vfat /dev/mmcblk1p1

If the device is partitioned but you still want to re-partition or re-format it, you must first unmount all the mounted partitions.