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.MX93 MMC driver supports:

  • MMC and SD cards

  • SDIO cards

  • SD3.0 cards

MMC on the ConnectCore 93 platforms

On the ConnectCore 93 system-on-module:

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

On the ConnectCore 93 Development Kit:

  • J23 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 93 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.MX93 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.MX93 CPU, ConnectCore 93 system-on-module, and ConnectCore 93 Development Kit device tree files.

The common i.MX93 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 uSDHC3 controller because it is used to communicate with the Wi-Fi chip and defined in the ccimx93.dtsi include file:

ConnectCore 93 device tree
/* Wifi MAC */
&usdhc3 {
	pinctrl-names = "default", "state_100mhz", "state_200mhz";
	pinctrl-0 = <&pinctrl_usdhc3>, <&pinctrl_usdhc3_wlan>;
	pinctrl-1 = <&pinctrl_usdhc3>, <&pinctrl_usdhc3_wlan>;
	pinctrl-2 = <&pinctrl_usdhc3>, <&pinctrl_usdhc3_wlan>;

	mmc-pwrseq = <&wlan_pwrseq>;
	bus-width = <4>;
	non-removable;
	wakeup-source;
	fsl,sdio-async-interrupt-enabled;
	status = "disabled";
};

Example: eMMC

On the ConnectCore 93, the eMMC is connected to uSDHC3 controller using eight data lines.

Definition of the uSDHC3

i.MX93 device tree
usdhc1: mmc@42850000 {
	compatible = "fsl,imx93-usdhc", "fsl,imx8mm-usdhc";
	reg = <0x42850000 0x10000>;
	interrupts = <GIC_SPI 86 IRQ_TYPE_LEVEL_HIGH>;
	clocks = <&clk IMX93_CLK_BUS_WAKEUP>,
			<&clk IMX93_CLK_WAKEUP_AXI>,
			<&clk IMX93_CLK_USDHC1_GATE>;
	clock-names = "ipg", "ahb", "per";
	assigned-clocks = <&clk IMX93_CLK_USDHC1>;
	assigned-clock-parents = <&clk IMX93_CLK_SYS_PLL_PFD1>;
	assigned-clock-rates = <400000000>;
	bus-width = <8>;
	fsl,tuning-start-tap = <40>;
	fsl,tuning-step= <1>;
	status = "disabled";
};

IOMUX configuration

ConnectCore 93 device tree
	/* eMMC */
	pinctrl_usdhc1: usdhc1grp {
		fsl,pins = <
			MX93_PAD_SD1_CLK__USDHC1_CLK			0x17fe
			MX93_PAD_SD1_CMD__USDHC1_CMD			0x13fe
			MX93_PAD_SD1_DATA0__USDHC1_DATA0		0x13fe
			MX93_PAD_SD1_DATA1__USDHC1_DATA1		0x13fe
			MX93_PAD_SD1_DATA2__USDHC1_DATA2		0x13fe
			MX93_PAD_SD1_DATA3__USDHC1_DATA3		0x13fe
			MX93_PAD_SD1_DATA4__USDHC1_DATA4		0x13fe
			MX93_PAD_SD1_DATA5__USDHC1_DATA5		0x13fe
			MX93_PAD_SD1_DATA6__USDHC1_DATA6		0x13fe
			MX93_PAD_SD1_DATA7__USDHC1_DATA7		0x13fe
			MX93_PAD_SD1_STROBE__USDHC1_STROBE		0x17fe
		>;
	};

Device enabling and options

ConnectCore 93 device tree
/* eMMC */
&usdhc1 {
	pinctrl-names = "default", "state_100mhz", "state_200mhz";
	pinctrl-0 = <&pinctrl_usdhc1>;
	pinctrl-1 = <&pinctrl_usdhc1>;
	pinctrl-2 = <&pinctrl_usdhc1>;
	bus-width = <8>;
	non-removable;
	status = "okay";
};

Example: microSD on the ConnectCore 93 Development Kit

On the ConnectCore 93 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.MX93 device tree
usdhc2: mmc@42860000 {
	compatible = "fsl,imx93-usdhc", "fsl,imx8mm-usdhc";
	reg = <0x42860000 0x10000>;
	interrupts = <GIC_SPI 87 IRQ_TYPE_LEVEL_HIGH>;
	clocks = <&clk IMX93_CLK_BUS_WAKEUP>,
			<&clk IMX93_CLK_WAKEUP_AXI>,
			<&clk IMX93_CLK_USDHC2_GATE>;
	clock-names = "ipg", "ahb", "per";
	assigned-clocks = <&clk IMX93_CLK_USDHC2>;
	assigned-clock-parents = <&clk IMX93_CLK_SYS_PLL_PFD1>;
	assigned-clock-rates = <400000000>;
	bus-width = <4>;
	fsl,tuning-start-tap = <20>;
	fsl,tuning-step= <2>;
	status = "disabled";
};

IOMUX configuration

ConnectCore 93 Development Kit device tree
	/* SD card */
	pinctrl_usdhc2_gpio: usdhc2gpiogrp {
		fsl,pins = <
			MX93_PAD_SD2_CD_B__GPIO3_IO00				0x31e
		>;
	};

	pinctrl_usdhc2: usdhc2grp {
		fsl,pins = <
			MX93_PAD_SD2_CLK__USDHC2_CLK				0x17fe
			MX93_PAD_SD2_CMD__USDHC2_CMD				0x13fe
			MX93_PAD_SD2_DATA0__USDHC2_DATA0			0x13fe
			MX93_PAD_SD2_DATA1__USDHC2_DATA1			0x13fe
			MX93_PAD_SD2_DATA2__USDHC2_DATA2			0x13fe
			MX93_PAD_SD2_DATA3__USDHC2_DATA3			0x13fe
			MX93_PAD_SD2_VSELECT__USDHC2_VSELECT			0x51e
		>;
	};

Device enabling and options

ConnectCore 93 Development Kit device tree
/* SD card */
&usdhc2 {
	pinctrl-names = "default", "state_100mhz", "state_200mhz";
	pinctrl-0 = <&pinctrl_usdhc2>, <&pinctrl_usdhc2_gpio>;
	pinctrl-1 = <&pinctrl_usdhc2>, <&pinctrl_usdhc2_gpio>;
	pinctrl-2 = <&pinctrl_usdhc2>, <&pinctrl_usdhc2_gpio>;
	cd-gpios = <&gpio3 00 GPIO_ACTIVE_HIGH>;
	bus-width = <4>;
	status = "okay";
	post-power-on-delay-ms = <200>;
	no-sdio;
	no-mmc;
};

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

Device node mapping

On the ConnectCore 93 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 93 Development Kit has a card detection line.

Formatted partitions are auto-mounted upon card insertion.

If the microSD 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.