/
Linux PS SPI Slave Mode

Linux PS SPI Slave Mode

This page describes how to use the PS SPI controller as a slave in Linux.

Table of Contents

Introduction

Slave support for SPI was introduced into the Linux kernel in 2017 as described here: SPI Slave Support. A patch series,[PATCH v2 2/2] spi: spi-cadence: Add support for Slave mode - Srinivas Goud, has been pushed upstream recently supporting the PS SPI driver. The patch series is still not in a Xilinx release as of 2023.1 but it can easily be applied to the Xilinx kernel tree as described below. The following guidelines were tested with the 2023.1 release of PetaLinux using a ZCU102 board with two PS SPI controllers. One controller is set up as a SPI master and the second controller is set up to be a SPI slave. The loopback feature of the MIOs is used to connect the two controllers without any special hardware. The following guidelines assume the user has Linux and PetaLinux experience and is not intended to be tutorial for either.

 

ZCU102 Hardware

The MPSoC has three SPI controllers with the first being a QSPI controller at address 0xFF0F0000. By default, the QSPI controller is used in the PetaLinux BSP as shown below.

[ 3.053808] spi-nor spi0.0: found mt25qu512a, expected m25p80 [ 3.059755] spi-nor spi0.0: mt25qu512a (131072 Kbytes)

Because QSPI is a SPI controller, it is SPI bus 0 in Linux with the other two PS SPI controllers being buses 1 and 2 in the default ZCU102 BSP of PetaLinux. The PS SPI controllers are at addresses 0xFF040000 and 0xFF050000.

PetaLinux Project

The ZCU102 BSP for PetaLinux was used as the basis of the project. Create a PetaLinux project based on the BSP.

Kernel Configuration

The kernel configuration is altered to enable more SPI features including spidev (User mode SPI device driver) and the slave mode (SPI slave protocol handlers) along with the provided SPI slave handlers. Note that slave mode has been in the kernel for some time and patches are only required for the PS SPI controller to support the slave mode.

 

Power management with the PetaLinux BSP causes the SPI controllers to be non-functional as the PS SPI controllers are not used by default. Power management is turned off in the kernel.

 

Without power management, the following warnings are seen on the console, but the system is functional. The driver does not have any normal output when it successfully probes so that the interrupts can be seen in /proc/interrupts indicating the driver is working.

[ 20.065666] uio_pdrv_genirq: Unknown symbol pm_runtime_enable (err -2) [ 20.072221] uio_pdrv_genirq: Unknown symbol __pm_runtime_resume (err -2)

With power management on and when using the PetaLinux BSP, the following errors might be seen when the driver probes, and the system is not functional.

[ 3.070864] cdns-spi ff040000.spi: error -EACCES: failed to add to PM domain domain11 [ 3.078692] cdns-spi: probe of ff040000.spi failed with error -13 [ 3.090909] cdns-spi ff050000.spi: error -EACCES: failed to add to PM domain domain12 [ 3.098735] cdns-spi: probe of ff050000.spi failed with error -13

The alternative to turning off power management is to create a Vivado system and use EMIO for the two SPI controllers as illustrated below:

 

 

Patch Series

The patch series from AMD consists of two patches but there are other patches in Mark Brown's SPI integration kernel tree at https://git.kernel.org/pub/scm/linux/kernel/git/broonie/spi.git/log/drivers/spi/spi-cadence.c. For ease of integration, a ZIP file is attached to this page which also includes patches from the community. Testing is based on the use of all of the patches.

Applying Patches

An external kernel repository could be used and then PetaLinux configured to use that kernel with the patches. For this test, the patches are integrated into the PetaLinux project kernel recipe which is quicker.

Unzip the patch zip file into the kernel recipe area of the PetaLinux project at <project>/project-spec/meta-user/recipes-kernel/linux/linux-xlnx. Alter the Linux kernel recipe linux-xlnx_%.bbappend of the PetaLinux project to apply the patch series.

FILESEXTRAPATHS:prepend := "${THISDIR}/${PN}:" SRC_URI:append = " file://bsp.cfg \ file://0001-spi-spi-cadence-Switch-to-spi_controller-structure.patch \ file://0002-spi-spi-cadence-Add-support-for-Slave-mode.patch \ file://0003-spi-spi-cadence-Avoid-read-of-RX-FIFO-before-its-rea.patch \ file://0004-spi-spi-cadence-Only-overlap-FIFO-transactions-in-sl.patch \ file://0005-spi-spi-cadence-Interleave-write-of-TX-and-read-of-R.patch \ file://0006-spi-spi-cadence-Add-missing-kernel-doc-for-clk_rate-.patch"

Device Tree Changes

The following device tree changes illustrate using the spidev driver with the first SPI Controller and making the second SPI Controller a slave. Note the compatible string for the spidev driver no longer works with “spidev” as it once did such that any compatible device from the spidev driver, such as “lwn,bk4”, can be used in the device tree.

/include/ "system-conf.dtsi" / { }; &spi0 { status = "okay"; spidev { status = "okay"; compatible = "lwn,bk4"; spi-max-frequency = <25000000>; reg = <0>; }; }; &spi1 { status = "okay"; spi-slave; };

Optionally, the SPI slave protocol handler can be set in the device tree, and then it seems that it cannot be dynamically changed at run-time. Most of the testing illustrated on this page did not set it in the device tree. The following example illustrates setting the handler to be the “spi-slave-time” handler.

&spi1 { status = "okay"; spi-slave; slave { compatible = "spi-slave-time"; }; };

Test Application

The spidev_test.c application provided in the Linux kernel tree at linux-xlnx/tools/spi at master · Xilinx/linux-xlnx is used for testing. An application is created in PetaLinux to build the application.

petalinux-create -t apps -n spidev-test --enable

The source code file, spidev_test.c, is taken from the kernel tree, renamed to spidev-test.c, and placed into the PetaLinux application recipe at <project>/project-spec/meta-user/recipe-apps/spidev-test/files/spidev-test.c.

PetaLinux does not allow the use of the “_” character.

Testing

MIO SPI Loopback

The IOU System Controller block of MPSoC allows MIO devices to be looped back between 2 of the same controllers and in this test the SPI controllers are connected together. A write to the IOU SLCR is accomplished from user space using devmem before the tests are performed.

After Boot

You should see the following when the system is correct. SPI bus 1 is the master controller using the spidev driver.

root@xilinx-zcu102-20231:~$ ls /dev/spi* /dev/spidev1.0 root@xilinx-zcu102-20231:~$ cat /proc/interrupts | grep spi 48: 0 0 0 0 GICv2 51 Level ff040000.spi 49: 0 0 0 0 GICv2 52 Level ff050000.spi 50: 12834 0 0 0 GICv2 47 Level ff0f0000.spi

Slave Time Protocol Test

root@xilinx-zcu102-20231:~# devmem 0xff180200 32 1 root@xilinx-zcu102-20231:~# echo spi-slave-time > /sys/class/spi_slave/spi2/slave root@xilinx-zcu102-20231:~# spidev-test -D /dev/spidev1.0 -v -p dummy-8B spi mode: 0x0 bits per word: 8 max speed: 500000 Hz (500 kHz) TX | 64 75 6D 6D 79 2D 38 42 __ __ __ __ __ __ __ __ __ __ __ __ __ __ __ __ __ __ __ __ __ __ __ __ |dummy-8B| RX | 00 00 02 A0 00 08 B0 0B __ __ __ __ __ __ __ __ __ __ __ __ __ __ __ __ __ __ __ __ __ __ __ __ |........| root@xilinx-zcu102-20231:~# spidev-test -D /dev/spidev1.0 -v -p dummy-8B spi mode: 0x0 bits per word: 8 max speed: 500000 Hz (500 kHz) TX | 64 75 6D 6D 79 2D 38 42 __ __ __ __ __ __ __ __ __ __ __ __ __ __ __ __ __ __ __ __ __ __ __ __ |dummy-8B| RX | 00 00 02 A4 00 0A A3 F1 __ __ __ __ __ __ __ __ __ __ __ __ __ __ __ __ __ __ __ __ __ __ __ __ |........| root@xilinx-zcu102-20231:~# spidev-test -D /dev/spidev1.0 -v -p dummy-8B spi mode: 0x0 bits per word: 8 max speed: 500000 Hz (500 kHz) TX | 64 75 6D 6D 79 2D 38 42 __ __ __ __ __ __ __ __ __ __ __ __ __ __ __ __ __ __ __ __ __ __ __ __ |dummy-8B| RX | 00 00 02 A7 00 02 D3 80 __ __ __ __ __ __ __ __ __ __ __ __ __ __ __ __ __ __ __ __ __ __ __ __ |........| Related Links

Spidev Protocol Test

The spidev driver can also be used for the slave protocol. As with the device tree, “spidev” is not used for the name of the driver but a compatible device in the driver, such as “bk4”.

devmem 0xff180200 32 1 root@xilinx-zcu102-20231:~# echo bk4 > /sys/class/spi_slave/spi2/slave root@xilinx-zcu102-20231:~# spidev-test -D /dev/spidev2.0 -p slave-hello-to-master & [1] 679 spi mode: 0x0 bits per word: 8 max speed: 500000 Hz (500 kHz) root@xilinx-zcu102-20231:~# spidev-test -D /dev/spidev1.0 -v -p master-hello-to-slave spi mode: 0x0 bits per word: 8 max speed: 500000 Hz (500 kHz) TX | 6D 61 73 74 65 72 2D 68 65 6C 6C 6F 2D 74 6F 2D 73 6C 61 76 65 __ __ __ __ __ __ __ __ __ __ __ |master-hello-to-slave| RX | 73 6C 61 76 65 2D 68 65 6C 6C 6F 2D 74 6F 2D 6D 61 73 74 65 72 __ __ __ __ __ __ __ __ __ __ __ |slave-hello-to-master| [1]+ Done spidev-test -D /dev/spidev2.0 -p slave-hello-to-master xilinx-zcu102-20231:/# cat /proc/interrupts | grep spi 48: 1 0 0 0 GICv2 51 Level ff040000.spi 49: 1 0 0 0 GICv2 52 Level ff050000.spi 50: 12834 0 0 0 GICv2 47 Level ff0f0000.spi

Resolved Issues

A kernel driver issue was happening sometimes, about 30% of the time, as illustrated below. This issue was resolved with a patch that is the last in the patch series attached to the page above.

root@xilinx-zcu102-20231:~# echo spi-slave-time > /sys/class/spi_slave/spi2/slave [ 113.155075] Unable to handle kernel paging request at virtual address 0033383d44455a49 [ 113.162999] Mem abort info: [ 113.165781] ESR = 0x0000000096000004 [ 113.169532] EC = 0x25: DABT (current EL), IL = 32 bits [ 113.174857] SET = 0, FnV = 0 [ 113.177900] EA = 0, S1PTW = 0 [ 113.181035] FSC = 0x04: level 0 translation fault [ 113.185912] Data abort info: [ 113.188785] ISV = 0, ISS = 0x00000004 [ 113.192613] CM = 0, WnR = 0 [ 113.195573] [0033383d44455a49] address between user and kernel address ranges [ 113.202702] Internal error: Oops: 0000000096000004 [#1] SMP [ 113.208267] Modules linked in: cfg80211 uio_pdrv_genirq zocl(O) [ 113.214188] CPU: 0 PID: 630 Comm: sh Tainted: G O 6.1.0-xilinx-v2023.1 #1 [ 113.222355] Hardware name: ZynqMP ZCU102 Rev1.0 (DT) [ 113.227304] pstate: 00000005 (nzcv daif -PAN -UAO -TCO -DIT -SSBS BTYPE=--) [ 113.234256] pc : gpiod_set_value_cansleep+0x24/0xb4 [ 113.239135] lr : spi_set_cs+0x18c/0x310 [ 113.242963] sp : ffff800009e43b70 [ 113.246262] x29: ffff800009e43b70 x28: ffff0008017820c0 x27: 0000000000000000 [ 113.253389] x26: 0000000000000000 x25: 0000000000000000 x24: ffff00080486c120 [ 113.260515] x23: ffff800009e43d88 x22: 0000000000000000 x21: 0000000000000000 [ 113.267642] x20: 0000000000000000 x19: 3033383d44455a49 x18: ffffffffffffffff [ 113.274770] x17: 0000000000000000 x16: 0000000000000000 x15: ffff800009e439f0 [ 113.281896] x14: ffff00080c9f2c07 x13: ffff00080c9f2c05 x12: 0000000000004800 [ 113.289024] x11: ffff00080486ce14 x10: 000000000000002e x9 : ffff800009e43c40 [ 113.296150] x8 : 000000000000002e x7 : 0000000000000001 x6 : 000000000000002e [ 113.303278] x5 : 0000000000000000 x4 : 0000000000000000 x3 : 0000000000000000 [ 113.310404] x2 : 0000000000000000 x1 : 0000000000000000 x0 : 3033383d44455a49 [ 113.317532] Call trace: [ 113.319963] gpiod_set_value_cansleep+0x24/0xb4 [ 113.324485] spi_set_cs+0x18c/0x310 [ 113.327966] spi_setup+0x1a4/0x2cc [ 113.331360] __spi_add_device+0x74/0x130 [ 113.335275] spi_add_device+0x68/0xa4 [ 113.338930] slave_store+0xb0/0x12c [ 113.342411] dev_attr_store+0x18/0x30 [ 113.346065] sysfs_kf_write+0x44/0x54 [ 113.349720] kernfs_fop_write_iter+0x120/0x1f0 [ 113.354156] vfs_write+0x1bc/0x3a4 [ 113.357550] ksys_write+0x70/0x104 [ 113.360945] __arm64_sys_write+0x1c/0x2c [ 113.364860] invoke_syscall+0x54/0x124 [ 113.368601] el0_svc_common.constprop.0+0xcc/0xec [ 113.373297] do_el0_svc+0x2c/0xc0 [ 113.376605] el0_svc+0x2c/0x84 [ 113.379652] el0t_64_sync_handler+0xf4/0x120 [ 113.383914] el0t_64_sync+0x190/0x194 [ 113.387573] Code: aa0003f3 2a0103f4 b140041f 540001a8 (f9400000) [ 113.393656] ---[ end trace 0000000000000000 ]---

Links



Related content

© Copyright 2019 - 2022 Xilinx Inc. Privacy Policy