P23 PC2 G66 SPI0_CLK
P24 PC3 G67 SPI0_CS

Nearby power and grounds:

P17 3.3V
P20 Gnd
P25 Gnd

There are two SPI devices in place, SPI0 which is located on the Pi-2 bus (pins P19, P21, P23, and P24) and SPI1 which is located on the Euler bus (pins E19, E21, E23, E24). This latter competes for its pins with UART3 and UART4 so it may be less interesting. However, SPI0 which is controlled from /dev/spidev0.0 is now operational, tested to the extent that I have connected a MAX31855 thermocouple sensor there and can read its data.

To enable this, I discovered what changes has to be made to the .dtb (device-tree blob) files, as per this Forum post by longsleep.

Briefly, it is a matter of de-compiling the relevant .dtb file found in /boot/pine64 to its corresponding .dts file, then edit the .dts file, and convert it back to .dtb, then replace that one in /boot/pine64.

There are 3 such files in /boot/pine64,


Since most of the same kernel with variations operate on the Pinebook, the SOpine, and the Pine64+, the corresponding .dtb files for these will be different, and there are also several other such sets of .bin files here, for booting. Thus the file we are interested in will be the one named sun50i-a64-pine64-plus.dtb. Convert (de-compile) this from .dtb to .dts:

dtc -I dtb -O dts sun50i-a64-pine64-plus.dtb > sun50i-a64-pine64-plus.dts

This .dts file will be a text file, which we can read and edit. It is full of hex addresses and other values that may seem baffling at first, but everything in there is related somehow to the available hardware of the A64 processor, and how it is being used. The change here will be as follows:

In the block beginning with spi@01c68000 { change the line status="disabled"; to status="okay";, and edit in a sub-block beginning with spidev@0 { so that this whole section looks like:

        spi@01c68000 {
            #address-cells = <0x1>;
            #size-cells = <0x0>;
            compatible = "allwinner,sun50i-spi";
            device_type = "spi0";
            reg = <0x0 0x1c68000 0x0 0x1000>;
            interrupts = <0x0 0x41 0x4>;
            clocks = <0x4 0x52>;
            clock-frequency = <0x5f5e100>;
            pinctrl-names = "default", "sleep";
            pinctrl-1 = <0x55>;
            spi0_cs_number = <0x1>;
            spi0_cs_bitmap = <0x1>;
            status = "okay";
            pinctrl-0 = <0xa7 0xa8>;

            spidev@0 {
                compatible = "spidev";
                reg = <0x0>;
                spi-max-frequency = <0x2faf080>;

The changes and additions are highlighted as bold here.

Presumably, the following section that is called spi@0x1c69000 is similarly related to SPI1 and /dev/spidev1.0.

After the .dts file is edited, compile it to a .dtb file and put it back into /boot/pine64, backing up and replacing the old one there:

dtc -I dts -O dtb sun50i-a64-pine64-plus.dts > sun50i-a64-pine64-plus.dtb
mv /boot/pine64/sun50i-a64-pine64-plus.dtb /boot/pine64/sun50i-a64-pine64-plus-dtb-backup
cp sun50i-a64-pine64-plus.dtb /boot/pine64

Then reboot, and /dev/spidev0.0 should now appear.

Note that there is only the chip-select line 0 here, thus there is no second select line such as the one the Raspberry Pi has on its pin 26, nor the corresponding device file. The second SPI bus will, if configured on, appear as /dev/spidev1.0, and it has its own completely separate data and clock lines.

Update 2018-12-15

Although the above changes to the device-tree files makes the /dev/spidev0.0 appear and work as expected, on the Linux 3.10.105-bsp-1.2-ayufan-136 kernels, there is now a problem with an address range conflict with the Ethernet controller. Any attempts at accessing the network causes a hang, and dmesg now shows an error:

sunxi-gmac 1c30000.eth: can't request region for resource [mem 0x01c30000-0x0x1c6ffff] 

Apparently the range of addresses demanded by the network interface is really large, and includes the addresses for the SPI controllers

Because we have turned on SPI at 0x1c68000 and this is within the range requested by the network driver, this latter will not be given the requested memory area, and thus fails to load.

The stanza for the network controller looks like the following:

      eth@01c30000 {
            pinctrl-0 = <0x9e>;
            device_type = "gmac0";
            status = "okay";
            gmac_power1 = "axp81x_dc1sw:0";
            rx-delay = <0x2>;
            tx-delay = <0x2>;
            phy-mode = "rgmii";
            clock-names = "gmac";
            clocks = <0x8f>;
            interrupt-names = "gmacirq";
            interrupts = <0x0 0x52 0x4>;
            pinctrl-names = "default";
            reg = <0x0 0x1c30000 0x0 0x40000 0x0 0x1c00000 0x0 0x30>;
            compatible = "allwinner,sunxi-gmac";

Apparently, the line

            reg = <0x0 0x1c30000 0x0 0x40000 0x0 0x1c00000 0x0 0x30>;

is where the allocation is specified, the 0x40000 looks like the requested size. Changing this to 0x38000 what happens then?

With this modification, both the spidev0.0 and the network operates correctly. Now why would the network addresses cover that large range? Looking at the manual, we see on page 74 that the EMAC (Ethernet MAC) at 0x1c30000 only occupies 64K, ahead to the GPU at 0x1c40000. Following these are a vacant block at 0x1c50000, then the HSTMR, DRAMCOM, DRAMCTL0, and DRAMPHY0, with 4K each, in the first parts of the 0x1c60000s, before we encounter our SPI0 at 0x1c68000. So it seems that the network should only have the range 0x10000 allocated, as it is not likely to have any business with the empty space, the GPU and the DRAM... Chapter 7.9 from page 668 onwards give the details of the EMAC's core registers, these extend to 0x1c300FF; presumably the rest of the space are for relevant descriptors and buffers.

I thus also tried setting the size value further down to 0x10000, so the line now reads:

            reg = <0x0 0x1c30000 0x0 0x10000 0x0 0x1c00000 0x0 0x30>;

Network worked still, and so does the spidev0.0.


The armbian system has an overlay mechanism available. There is a configuration file, /boot/armbianEnv.txt, which allows control of which IO functions are to be enabled. The general rule is that nothing is enabled unless listed here, and there is an entry in this file, overlays= that can be used to turn on certain of the periferals. Which these are is listed in the file boot/dtb-4.19.63-sunxi64/allwinner/overlay/README.sun50i-a64-overlays.

This shows an example of this file:

overlays=i2c1 uart1 uart2 uart3 uart4 spi-spidev

Here, the overlays indicate that one of the i2c busses and some uarts, and the SPI device are enabled. There is also the required parameter for spidev, indicating is that we wanted to enable spi bus 0.

A very informative listing of all the pin settings is shown in /sys/kernel/debug/pinctrl/1c20800.pinctrl/pinmux-pins. Plenty of other status info for other pin-controllers and devices can also be found here.

To Pine 64+ main page

Powered by Apache

Valid XHTML 1.0!