The purpose of this page is to describe the Linux SPI driver for Xilinx Zynq SPI PS

Introduction

This page provides information about the Zynq/ZynqMP SPI driver which can be found on Xilinx GIT and mainline as spi-cadence.c.
Zynq/ZynqMP has two SPI hard IP. This is a Cadence IP. Some minor properties in the cadence IP offer multiple options which were customized as desirable.
This driver only supports master mode.
Detailed below are its use two slaves - EEPROM and flash.

HW IP Features

  • Master mode
  • All SPI flash instructions
  • Support for 3 slaves - can be extended using a 3 to 8 decoder
  • Driver uses manual chip select and auto start options
  • Programmable clock frequency, polarity and phase
  • Interrupt support


Missing Features and known Issues/Limitations in Driver

  • None

Kernel Configuration Options

The following config options need to be enabled:
CONFIG_SPI_CADENCE
It depends on:
CONFIG_SPI_MASTER
CONFIG_ARM
Untitled.png

Device-tree

Refer to Documentation/devicetree/bindings/spi/spi-cadence.txt for complete description.
These are some specific points to be noted about the properties:
- compatible string: This can be either cdns or xlnx compatible string.
- num-cs: This is SOC specific - Since this driver is for the cadence IP in the mainline, this option is made available in the devicetree.
- is-decoded-cs: This refers to whether a decoder is used to extend the existing chip selects.
- spi-max-frequency - This should reflect the maximum frequency supported by the slave/master (or) user intends to use.
- partitions - The size and number of these are user configurable and the sum should not exceed the total flash size.

Using SPI with EEPROM

Adding an SPI EEPROM to the devicetree

The following example shows adding an SPI EEPROM to a device tree
spi: spi@e0006000 {
     compatible = "xlnx,spi-zynq-r196";
     clock-names = "ref_clk", "pclk";
     clocks = <&clkc 25>, <&clkc 34>;
     interrupt-parent = <&gic>;
     interrupts = <0 26 4>;
     num-cs = <4>;
     is-decoded-cs = <0>;
     reg = <0xe0006000 0x1000>;
     #address-cells = <1>;
     #size-cells = <0>;
     eeprom: at25@0 {
             compatible = "atmel,at25";
             at25,byte-len = <8192>;
             at25,addr-mode = <2>;
             at25,page-size = <32>;
             reg = <2>;
             spi-max-frequency = <1000000>;
     };
};

Using SPI with flash

Adding an SPI flash to the devicetree

Zynq:

spi: spi@e0007000 {
     compatible = "cdns,spi-r1p6";
     clock-names = "ref_clk", "pclk";
     clocks = <&clkc 26>, <&clkc 35>;
     interrupt-parent = <&ps7_scugic_0>;
     interrupts = <0 49 4>;
     num-cs = <4>;
     is-decoded-cs = <0>;
     reg = <0xe0007000 0x1000>;
     #address-cells = <1>;
     #size-cells = <0>;
     flash@0 {
             compatible = "sst25wf080";
             reg = <1>;
             spi-max-frequency = <1000000>;
             #address-cells = <1>;
             #size-cells = <1>;
             partition@test {
                            label = "spi-flash";
                            reg = <0x0 0x100000>;
             };
     };
};

ZynqMP:

spi0: spi@ff040000 {
    compatible = "cdns,spi-r1p6";
    interrupt-parent = <&gic>;
    interrupts = <0 19 4>;
    reg = <0x0 0xff040000 0x0 0x1000>;
    clock-names = "ref_clk", "pclk";
    #address-cells = <1>;
    #size-cells = <0>;
    power-domains = <&pd_spi0>;
    num-cs = <1>;
    pinctrl-names = "default";
    pinctrl-0 = <&pinctrl_spi0_default>;
 
    spi0_flash0: spi0_flash0@0 {
            compatible = "m25p80";
        #address-cells = <1>;
        #size-cells = <1>;
        spi-max-frequency = <50000000>;
        reg = <0>;
                spi0_flash0@00000000 {
          label = "spi0_flash0";
          reg = <0x0 0x100000>;
        };
       };
};


Test Procedure

Testing using sysfs

#/
#SPI - eeprom testing
#*/
#check whether eeprom device is present or not .
dmesg | grep eeprom
#read from the EEPROM
cat sys/bus/spi/devices/spi0.2/eeprom
#write to the EEPROM
echo "Hi this is testing the eeprom device through spi interface" > sys/bus/spi/devices/spi0.2/eeprom
#read from the EEPROM to verify
cat sys/bus/spi/devices/spi0.2/eeprom
#/**/

Testing using flashcp

#/*
#*SPI flash testing with flashcp
#*/
#To know MTD partion(partitions) is(are) present and size of partition(partitions)in flash
cat /proc/mtd
dev:    size   erasesize  name
mtd0: 00100000 00001000 "spi-flash"

#Creating a file to be written to the flash
dd if=/dev/urandom of=./sample.bin bs=1024 count=900
900+0 records in
900+0 records out
921600 bytes (900.0KB) copied, 0.706526 seconds, 1.2MB/s

#Write the file to the partition - this erases the partition, writes the file and verifies
flashcp -v ./smaple.bin /dev/mtd0
Erasing block: 225/225 (100%)
Writing kb: 896/900 (99%)
Verifying kb: 896/900 (99%)

Testing using jffs2

#
#/*
#*SPI flash testing with jffs2
#*/
#Erase a the whole partition with jffs2 markers
flash_eraseall -j /dev/mtd0
Erasing 4 Kibyte @ ff000 - 97% complete. Cleanmarker written at ff0000.
Erasing 4 Kibyte @ 100000 - 100% complete
#create a directory
mkdir spi_flash0
#Mount the partition to spi_flash0
mount -t jffs2 /dev/mtdblock0 /spi_flash0
#Creating a file to be written to the flash
dd if=/dev/urandom of=./sample.bin bs=1024 count=900
900+0 records in
900+0 records out
921600 bytes (900.0KB) copied, 0.706526 seconds, 1.2MB/s
#Write the file to the flash
cp ./sample.bin /spi_flash0/
#Check the presence of the file(s) in spi_flash0
ls /spi_flash0
sample.bin
#Unmount
umount spi_flash0
#Mount again - MTD 0 to spi_flash0
mount -t jffs2 /dev/mtdblock0 /spi_flash0
#Compare the files - there should be no differences
diff ./sample.bin /spi_flash0/sample.bin
#Unmount
umount spi_flash0

#The data can be verified again after a power on reset if desired.

Expected Output

jffs2 log:
 
#flash_eraseall -j /dev/mtd0
Erasing 4 Kibyte @ ff000 - 97% complete. Cleanmarker written at ff0000.
Erasing 4 Kibyte @ 100000 - 100% complete
#mkdir spi_flash0
#mount -t jffs2 /dev/mtdblock0 /spi_flash0
#dd if=/dev/urandom of=./sample.bin bs=1024 count=900
900+0 records in
900+0 records out
921600 bytes (900.0KB) copied, 0.706526 seconds, 1.2MB/s
#cp ./sample.bin /spi_flash0/
#ls /spi_flash0
sample.bin
#umount spi_flash0
#mount -t jffs2 /dev/mtdblock0 /spi_flash0
#diff ./sample.bin /spi_flash0/sample.bin
 
 

Change Log

  • 2016.3

    • Summary
      • None
    • Commits
      • None
  • 2016.4

    • Summary
      • None
    • Commits
      • None
  • 2017.1

    • Summary
      • None
    • Commits
      • None
  • 2017.2

    • Summary
      • None
    • Commits
      • None
  • 2017.3

    • Summary
      • Update PM APIs sequence of calling

  • 2017.4

    • Summary
      • None
    • Commits
      • None


Related Links