Micro SD Card Slot Device Tree Overlay for NTC Kernel

Publish date: 2019-05-16
Tags: ntc-chip, ARM, SBC, Linux, hardware

Now that you have the Micro SD hat hardware, you need a way to tell the kernel about it so it can load the drivers and interface with it. On an ARM based machine, this is done with a data structure called the device tree. The device tree is like a giant config file that tells the kernel all about the hardware that exists in the machine. It contains things like what type of device something is, what address it’s mapped to in memory, what I/O pins it uses, and things like that.

The device tree is a hierarchical structure compiled into a binary format and passed into the kernel at boot time by the bootloader (U-Boot). It would be a bit of a hassle if we had to make our changes, recompile this file, flash it to the CHIP, and then have U-Boot pass in the new device tree. Fortunately, since we don’t need the Micro SD card reader to boot the stock NTC kernel, we can describe it in its own small file, compile that fragment, and apply it as an overlay to the device tree after the machine has booted up.

Summary

This post describes how to build the overlay if you want to do it yourself from scratch. If you don’t care about that and just want the overlay, you may enter these commands into the shell to install it yourself from the archive I have provided. These steps will download the archive, extract it, copy files to necessary locations, and then enable application of the overlay when the system starts.

cd ~
curl -LO https://byteporter.com/mmc-overlay-for-ntc-kernel/mmc2-4.4.13-ntc-mlc.tar.gz
tar xfvz mmc2-4.4.13-ntc-mlc.tar.gz
sudo mkdir /lib/firmware/overlays
sudo cp mmc2-4.4.13-ntc-mlc/mmc2-ntc.dtbo /lib/firmware/overlays/
sudo cp mmc2-4.4.13-ntc-mlc/mmc2-overlay.service /etc/systemd/system/
sudo systemctl daemon-reload
sudo systemctl enable mmc2-overlay

You may now either reboot and the mmc2 overlay should be applied on startup, or you can start the service to apply the overlay without restarting by issuing the command sudo systemctl start mmc2-overlay. After rebooting or issuing that command, you can check its status with the command systemctl status mmc2-overlay.

Describing the hardware

To describe the hardware, you could look everything up in the data sheet provided by the manufacturer. While this is a great option as a last resort, thankfully most of this work has already been done and included in the source code for the Linux kernel for a vast array of single board computers, including the CHIP. They’ve organized their source files well and provide several header files with definitions that we can make use of. We could of course just hard code the numeric values that we look up from the data sheet, but this is a poor practice because it will be hard to understand when reading it later what those values are meant to indicate.

We want to enable the SD Controller 2 peripheral on the Allwinner SoC. We’ll tell it to use the pins on Port E because that’s what we wired up. The drive current will be 30 mA and pull function should be set to pull up. Bus width is 4 bits and the power is supplied by the 3.3V regulated supply from the PMIC. Clocks come from the data sheet and are already defined for us in the included files.

A normal SD slot has a small switch inside that the controller can use to detect when a card is inserted. Our SD Adapter kludge does not have that functionality though, so we need to specify broken-cd, which will tell the driver to simply poll for an SD card. In my experience, this works just fine and seems to cost negligible computing resources.

To enable the driver, set status = "okay". That should be it! Here’s our completed overlay source:

/dts-v1/;
/plugin/;

#include <dt-bindings/pinctrl/sun4i-a10.h>
#include <dt-bindings/gpio/gpio.h>
#include <dt-bindings/input/input.h>
#include <dt-bindings/interrupt-controller/irq.h>

/ {
	compatible = "nextthing,chip", "allwinner,sun5i-r8";
	
	/* 	 Enable our SDIO pins		 */
	fragment@0 {
		target = <&pio>;		
		__overlay__ {

			chip_sdio_pins: mmc2@42 {
				allwinner,pins = "PE4", "PE5", "PE6", "PE7", "PE8", "PE9";
				allwinner,function = "mmc2";
				allwinner,drive = <SUN4I_PINCTRL_30_MA>;
				allwinner,pull = <SUN4I_PINCTRL_PULL_UP>;
			};
		};
	};


	/*	 Enable our SDIO device	 */
	fragment@1 {
		target = <&mmc2 >;

		__overlay__ {
			vmmc-supply = <&reg_vcc3v3>;
			vqmmc-supply = <&reg_vcc3v3>;

			pinctrl-names = "default";
			compatible = "allwinner,sun5i-a13-mmc";
			pinctrl-0 = <&chip_sdio_pins>;

			bus-width = <4>;
      clocks = <&ahb_gates 10>,<&mmc2_clk 0>,<&mmc2_clk 1>,<&mmc2_clk 2>;

			// SD adapter doesn't have a chip detect switch so use polling
			broken-cd;

			status = "okay";
		};
	};
	
};

I saved mine as mmc2-ntc.dts and will be using that file name in these instructions. I’ll also go ahead and admit that I modified this version of the overlay source from the Tzatziffy project source on github. It’s slightly different than the one I use for kernel 4.19 as some of the binding names changed a bit.

Compiling the device tree overlay

In order to compile the device tree overlay, we’ll need to use a tool called dtc, device tree compiler. In Debian Jessie (the version on my CHIP), you can install it by running sudo apt-get install -y device-tree-compiler. We’ll also need the headers for our board from the Linux source code as well as the C preprocessor, cpp, which will include them into our overlay before we compile as the device tree language doesn’t actually have includes.

We also need the files that are included at the top, which come from the Linux kernel source code. JF Possibilities has helpfully backed up and mirrored all of the NTC source repositories (http://chip.jfpossibilities.com/gits/). The files we need come from the CHIP-linux.git repository, which as the source code for the kernel. The image I’m using on my CHIP for this demonstration is stable-gui-b149 which has the kernel version 4.4.13-ntc-mlc. To get this source, I used git to clone it from JF Possibilities and got the branch debian/4.4.13-ntc-mlc. The command to do this is git clone -b debian/4.4.13-ntc-mlc http://chip.jfpossibilities.com/gits/CHIP-linux.git. However, if you actually download the entire git repository, you’ll end up downloading 1.9GB of files and the 5 you actually need are only 60KB. So I downloaded it for you and then pulled out the necessary files and included them in the archive for you. So I would recommend just getting the archive from the end of this post instead!

To compile the device tree overlay, you first need to run the preprocessor. The command for that is cpp -nostdinc -I. -undef -x assembler-with-cpp mmc2-ntc.dts mmc2-ntc.dts.preprocessed. Next you need to run the device tree compiler on the resulting file from the last command, which can be done with dtc -I dts -O dtb -o mmc2-ntc.dtbo mmc2-ntc.dts.preprocessed. That will compile the file mmc2-ntc.dtbo, which is the compiled binary overlay and the final goal of this whole exercise. This file is also included in the archive, so you can just use that if you prefer.

Applying the device tree overlay

For this file to be useful, you’ll need to apply it to your system’s device tree. This can be done before booting and the resulting device tree passed in, or can be done to a running system using the ConfigFS kernel driver. Kernel 4.4.13-ntc-mlc does have this enabled, so it’s pretty simple to apply the overlay. All you need to do is create a directory and copy the overlay binary to a special filename. You can do that with these commands:

sudo -sH
mkdir /sys/kernel/config/device-tree/overlays/mmc2
cat mmc2-ntc.dtbo >/sys/kernel/config/device-tree/overlays/mmc2/dtbo

That’s it! The device tree overlay should now be applied and your Micro SD slot should now be working! You can verify by checking dmesg, which should have something similar to the following lines near the bottom

[ 3837.720000] sunxi-mmc 1c11000.mmc: base:0xe15d0000 irq:128
[ 3837.945000] mmc1: host does not support reading read-only switch, assuming write-enable
[ 3837.950000] mmc1: new high speed SDHC card at address aaaa
[ 3837.955000] mmcblk0: mmc1:aaaa SS32G 29.7 GiB 
[ 3837.970000]  mmcblk0: p1 p2 p3

You should also see your SD card in lsblk

chip@chip:~$ lsblk
NAME        MAJ:MIN RM  SIZE RO TYPE MOUNTPOINT
mmcblk0     179:0    0 29.7G  0 disk 
|-mmcblk0p1 179:1    0  512M  0 part 
|-mmcblk0p2 179:2    0    5G  0 part 
`-mmcblk0p3 179:3    0 24.2G  0 part 
mtdblock0    31:0    0    4M  0 disk 
mtdblock1    31:1    0    4M  0 disk 
mtdblock2    31:2    0    4M  0 disk 
mtdblock3    31:3    0    4M  0 disk 
mtdblock4    31:4    0    4G  0 disk 

You can mount it the normal way and begin using your new storage space however you like.

chip@chip:~$ sudo mount /dev/mmcblk0p3 /mnt
[sudo] password for chip: 
chip@chip:~$ ls /mnt
bin  boot  dev  etc  home  lib  lost+found  media  mnt  opt  proc  root  run  sbin  srv  sys  tmp  usr  var
chip@chip:~$

My card currently has the root file system for my Slackware installation on it, which is what is shown above.

Files

The files used in this post can be downloaded in the archive mmc2-4.4.13-ntc-mlc.tar.gz.