Integrate a QSPI using PetaLinux Tools Part 1

May 14, 2018

This post walks through part 1 of a complete integration of a QSPI connected to a Zynq UltraScale+ MPSoC into a Linux kernel using PetaLinux Tools 2017.4.

 

It traces the connection from a QSPI chip to the QSPI controller on the Zynq UltraScale+ MPSoC (ZU+). Then its demonstrates checking the Linux kernel software layers to ensure the right configuration has been set up.

 

I posted the solution to https://www.zachpfeffer.com/single-post/Integrate-a-QSPI-using-PetaLinux-Tools-Part-2

 

 

QSPI to ZU+ Connection

 

Detail

 

MT25QL01GBBB8E12 -0AA connected to a XCZU9EG-FFVC900

 

 

Connections (QSPI connected to ZU+)

 

D3 connected to G18 

D2 connected to H17

C4 connected to E18

D4 connected to F18

C2 connected to J17

B2 connected to C18

 

 

Figure Out Pins

 

QSPI Pins

 

Per this figure from the MT25QL01GBBB datasheet, the package code is 12 (MT25QL01GBBB8E12 -0AA): a 12 = 24-ball T-PBGA, 05/6 x 8mm (5 x 5 array)

 

Pins

 

MT25QXXXXXXX8E12-XXXX Balls Down

 

 

Connections

 

D3 - DQ0,

D2 - DQ1,

C4 - W#/DQ2,

D4 - DQ3/HOLD#,

C2 - S#,

B2 - C

 

From the QSPI data sheet:

 

DQ[3:0] (I/O) 

 

Serial I/O: The bidirectional DQ signals transfer address, data, and command information.

 

When using legacy (x1) SPI commands in extended I/O protocol (XIO-SPI), DQ0 is an input and
DQ1 is an output. DQ[3:2] are not used.

 

When using dual commands in XIO-SPI or when using DIO-SPI, DQ[1:0] are I/O. DQ[3:2] are not
used.

 

When using quad commands in XIO-SPI or when using QIO-SPI, DQ[3:0] are I/O.

 

C (Input)

 

Clock: Provides the timing of the serial interface. Command inputs are latched on the rising edge of the clock. In STR commands or protocol, address and data inputs are latched on the rising edge of the clock, while data is output on the falling edge of the clock. In DTR commands or protocol, address and data inputs are latched on both edges of the clock, and data is output on both edges of the clock.

 

S#

 

Chip select: When S# is driven HIGH, the device will enter standby mode, unless an internal PROGRAM, ERASE, or WRITE STATUS REGISTER cycle is in progress. All other input pins are ignored and the output pins are tri-stated. On parts with the pin configuration offering a dedicated RESET# pin, however, the RESET# input pin remains active even when S# is HIGH.

 

Driving S# LOW enables the device, placing it in the active mode.

 

After power-up, a falling edge on S# is required prior to the start of any command.

 

 

ZU+ Pins

 

Per this figure from the XCZU9EG-FFVC900 datasheet, we're using the FFVC900 package.

 G18, H17, E18, F18, J17, C18 are all in PS Bank 500

 

Pin Out 

 

From: https://www.xilinx.com/support/packagefiles/zuppackages/xczu9egffvc900pkg.txt 

 

Pin   Pin Name                            Memory Byte Group  Bank  I/O Type  Super Logic Region

G18   PS_MIO4                             NA                 500   PSMIO     NA                 

H17   PS_MIO1                             NA                 500   PSMIO     NA

E18   PS_MIO2                             NA                 500   PSMIO     NA                 

F18   PS_MIO3                             NA                 500   PSMIO     NA   

J17   PS_MIO5                             NA                 500   PSMIO     NA                 
C18   PS_MIO0                             NA                 500   PSMIO     NA           

 

Overlayed

 

PS_MIO4 - DQ0,

PS_MIO1 - DQ1,

PS_MIO2 - W#/DQ2,

PS_MIO3 - DQ3/HOLD#,

PS_MIO5 - S#,

PS_MIO0 - C

 

From Table 28-3 MIO Interfaces (qspi column) of the Zynq UltraScale+ Device TRM:

 

PS_MIO4 - DQ0 - si_mio[0] 

PS_MIO1 - DQ1 - io[1]

PS_MIO2 - W#/DQ2 - io[2]

PS_MIO3 - DQ3/HOLD#, - io[3]

PS_MIO5 - S# - n_ss_out

PS_MIO0 - C - sclk_out

 

From page 646 of the Zynq UltraScale+ Device TRM:

 

Also from page 646 of the Zynq UltraScale+ Device TRM:

 

The following interfaces are used by the generic Quad-SPI controller.


• The APB slave read/write interface is used to read/write the registers and also to write
the TX generic FIFO data.

 

• The AXI master write interface is used to issue DMA write requests on the AXI interface.
The data read from flash memory is written into the RXFIFO. The data from the RXFIFO
is transferred into external memory (for example, DDR) using this interface. The AXI
address bus is 44 bits wide and the data is 32 bits wide.

 

 

Base Address of QSPI

 

From Table 10-6 (p232): I/O Peripherals Register Map (LPD) Base Address of the QSPI controller is: 0xFF0F_0000

 

 

Am I Using LQSPI vs. GQSPI?

 

Using GQSPI as Linux boots up. Register is unchanged.

 

Detail

 

From page 640 from the Zynq UltraScale+ Device TRM: 

 

At Boot

 

The CSU BootROM uses the GQSPI controller for system boot. The Width Detection parameter in the boot header selects between 4- and 8-bit I/O. If the XIP FSBL is selected (FSBL length = 0 in the boot header), the BootROM switches to the LQSPI controller before handing-off the system to the FSBL code.

 

From page 643 from the Zynq UltraScale+ Device TRM: 

Controller Selection


One controller is selected at a time using the LQSPI_CFG [LQ_MODE] bit. The generic
controller is selected by setting the bit = 0 and the legacy linear controller is selected by
setting the bit = 1. The active controller must be quiescent before switching from one
controller to the other.

 

Check the Register Spec


Register Name    LQSPI_CFG
Relative Address    0x000000A0
Absolute Address    0xFF0F00A0 (QSPI)
Width    32
Type    rw
Reset Value    0x000002EB
Description    Configuration
Specifically for the Linear Quad-SPI Controller

 

 

Decode 0x000002EB 

 

0x000002EB (Reset value)

0b0000_0000_0000_0000_0000_0010_1110_1011

 

LQ_MODE: Controller Select 0: Generic Quad-SPI

TWO_MEM: I/O Configuration: 0: One memory device

SEP_BUS: I/O Configuration: 0: Single memory interface

U_PAGE: N/A

ADDR_32BIT: Flash Memory Address based on AXI address: 0: Lower 24 bits of AXI address on linear port are used as address to the flash.

MODE_EN: MODE_ON and MODE_BITS are disabled

INST_CODE: Fast read quad I/O

 

Can my Kernel See the MT25QL01GBBB8E12 -0AA?

 

In a PetaLinux Tools managed build the Linux kernel code is at build/tmp/work-shared/plnx_aarch64/kernel-source/.

 

The SPI-NOR driver is at drivers/mtd/spi-nor/spi-nor.c

 

The specific spi-nor.c used in PetaLinux Tools 2017.4 is at: https://github.com/Xilinx/linux-xlnx/blob/b450e900fdb473a53613ad014f31eedbc80b1c90/drivers/mtd/spi-nor/spi-nor.c

 

 

SPI NOR framework

 

Check Kconfig @ https://github.com/Xilinx/linux-xlnx/blob/b450e900fdb473a53613ad014f31eedbc80b1c90/drivers/mtd/spi-nor/Kconfig

 

menuconfig MTD_SPI_NOR
    tristate "SPI-NOR device support"
    depends on MTD
    help
      This is the framework for the SPI NOR which can be used by the SPI
      device drivers and the SPI-NOR device driver.

 

Check the PetaLinux kernel config:

Note: this command will wipe out the kernel source in build/tmp/work-shared/plnx_aarch64/kernel-source

 

Note 2: PetaLinux 2017.4 uses https://github.com/Xilinx/linux-xlnx/tree/b450e900fdb473a53613ad014f31eedbc80b1c90 See this link to for a method to figure this out.

 

 Type '/' to search for MTD_SPI_NOR

 

Its on:

 

Look at dmesg

 

[    1.636157] mtdoops: mtd device (mtddev=name/number) must be supplied
 

Check device tree overlay

 

https://github.com/Xilinx/linux-xlnx/blob/b450e900fdb473a53613ad014f31eedbc80b1c90/drivers/mtd/spi-nor/spi-nor.c

 

 

Hmmm.. this is looking for zynq-qspi-1.0, I'm passing in: zynqmp-qspi-1.0

 

Check the original (non-overlay) device tree

 

system-top.dts pulls in all the dtsi components:

 Contents:

 

 So zynqmp-qspi-1.0 seems okay.

 

Configure flash through petalinux-config

 

 

Select Subsystem AUTO Hardware Settings

 

Select Flash Settings  --->

 

Configure

 

 

Use some printks

 

Launch devshell

 

petalinux-build -c kernel -x devshell

 

(this command is not documented anywhere - it also doesn't seem to work: it executed for 2 hours)

 

 

 

cat /proc/devices

 

 

Printk Based Debug

 

Go through the SPI-NOR Linux kernel doc and see if functions are getting called (via printks)

 

https://www.kernel.org/doc/Documentation/mtd/spi-nor.txt

 

                          SPI NOR framework
============================================

Part I - Why do we need this framework?
---------------------------------------

SPI bus controllers (drivers/spi/) only deal with streams of bytes; the bus

 

The Xilinx Zynq UltraScale+ MPSoC Quad-SPI (QSPI) controller driver (master mode only) is @ link

 

Which Kconfig is needed?

 

Look at the Makefile

Found:
Is the Kconfig on?

 

Output the current .config with

Grep it:
Yup.

 

 Does probe get called (and succeed)? 

 

Add a printk and a dump_stack():

 

Code added:

 

 

Rebuild the kernel with:

 

link

 

Checked kernel log. No output.

 

Did the kernel get rebuilt?

 

No:

Should be May 13th.

 

Check the reference guide. Nothing.

Check the workflow guide. Nothing.

Try petalinux-build --help. Saw:

 

 Output from command:

 

 

Output:

 

 

 its in there:

 

Hmm,.. need to do a petalinux-build again?

Hmmmm...petalinux-build is building a lot of stuff:

 

Comment: It is surprising that petalinux-build -c kernel -x compile -f didn't put an Image into images/linux/Image

 

Comment: It is surprising that a subsequent petalinux-build took another few minutes to run.

 

 

 Yes, probe gets called and succeeds. 

 


controller operates agnostic of the specific device attached. However, some
controllers (such as Freescale's QuadSPI controller) cannot easily handle
arbitrary streams of bytes, but rather are designed specifically for SPI NOR.

In particular, Freescale's QuadSPI controller must know the NOR commands to
find the right LUT sequence. Unfortunately, the SPI subsystem has no notion of
opcodes, addresses, or data payloads; a SPI controller simply knows to send or
receive bytes (Tx and Rx). Therefore, we must define a new layering scheme under
which the controller driver is aware of the opcodes, addressing, and other
details of the SPI NOR protocol.

 

Part II - How does the framework work?
--------------------------------------

This framework just adds a new layer between the MTD and the SPI bus driver.
With this new layer, the SPI NOR controller driver does not depend on the
m25p80 code anymore.

 

   Before this framework, the layer is like:

 

                   MTD
         ------------------------
                  m25p80
         ------------------------
           SPI bus driver
         ------------------------
            SPI NOR chip

 

   After this framework, the layer is like:


                   MTD
         ------------------------
              SPI NOR framework
         ------------------------
                  m25p80
         ------------------------
           SPI bus driver
         ------------------------
           SPI NOR chip

 

  With the SPI NOR controller driver (Freescale QuadSPI), it looks like:


                   MTD
         ------------------------
              SPI NOR framework
         ------------------------
                fsl-quadSPI
         ------------------------
           SPI NOR chip

 

Part III - How can drivers use the framework?
---------------------------------------------

The main API is spi_nor_scan(). Before you call the hook, a driver should
initialize the necessary fields for spi_nor{}. Please see

 

 Does spi_nor_scan() get called? 

 

Look for it:

 Output:

 

Who calls it:

Output:

 

Are any of these built in?

 

Kconfigs?

 

mtk-quadspi|fsl-quadspi|nxp-spifi|atmel-quadspi|hisi-sfc|cadence-quadspi|m25p80

 

 

 

Check the .config: 

Output:

 

 So nothing will call spi_nor_scan() 

 

 

drivers/mtd/spi-nor/spi-nor.c for detail. Please also refer to fsl-quadspi.c
when you want to write a new driver for a SPI NOR controller.
Another API is spi_nor_restore(), this is used to restore the status of SPI
flash chip such as addressing mode. Call it whenever detach the driver from
device or reboot the system.

 

 

Do I need a special driver / aren't all these JEDEC? drivers? Wait? I don't need a new SPI NOR controller, do I?

 

 

Look for n25q

Output:

 

jedec,spi-nor

 

 

It looks like we should just use the string "jedec,spi-nor" from this:

Kconfig for m25p80:

Open:

Find: 

Check if CONFIG_MTD_M25P80 is in our .config, Yes!

 

 

Find it:

 

Edit:

 

Change to:

 

Some output:

 

Check if system.dtb got updated:

 Got it! 

 

Now I see the following in the dmesg log:

 

 Partitions? 

 

I don't think I need the following, since it simply finds? the actual partitions:

Check in doc at

https://www.kernel.org/doc/Documentation/devicetree/bindings/mtd/jedec%2Cspi-nor.txt

 

I don't see anything about partitions. Try without:

 

Check that the dtb was updated:

Boot the unit.

 

Examine log:

 Without the specific partitions, it seems to have found up just the partitions on the device. 

 

Does it find the partitions or are the partitions picked up in another dts?

 

Look at docs again. Partitions are documented at link.

 

Look in our directory:

 Look for "partitions" in "dt*" files:

Found a few:

partition@0x00000000

 

 

 

How are all the dtsi's composed?

 

system-top.dts pulls in all the dtsi components:

 Contents:

 

zynqmp.dtsi

./components/plnx_workspace/device-tree/device-tree-generation/zynqmp.dtsi
./build/tmp/work-shared/plnx_aarch64/kernel-source/arch/arm64/boot/dts/xilinx/zynqmp.dtsi

 

These ^^^^ differ, e.g. iommus are commented out in ./build. Which one is used?

 

zynqmp-clk-ccf.dtsi

./components/plnx_workspace/device-tree/device-tree-generation/zynqmp.dtsi

./build/tmp/work-shared/plnx_aarch64/kernel-source/arch/arm64/boot/dts/xilinx/zynqmp.dtsi
 

These ^^^^ differ, e.g. iommus are commented out in ./build. Which one is used?

 

pl.dtsi

./components/plnx_workspace/device-tree/device-tree-generation/pl.dtsi

 

pcw.dtsi

./components/plnx_workspace/device-tree/device-tree-generation/pcw.dtsi

 

system-user.dtsi

./project-spec/meta-user/recipes-bsp/device-tree/files/system-user.dtsi
 

 

 

link

 

Look at the flattened device tree (PETALINUX is your install dir)

 

Find dtc

 

Print dtb

 

Hmmm... it looks like my dtb changes were not picked up:

 

Complete:

 

 

Try "petalinux-build" again

 

Didn't work (should be May 14th):

 

 

 

 

Hack to try it out:

Hmmm, still present.

 

How does it get in?

 

Its not in the top level of any of these:

 

 

Found here among other places:

 

 

 

File contents: 

 

This file gets included at the top of ./project-spec/meta-user/recipes-bsp/device-tree/files/system-user.dtsi:

 

 Look at device-tree.bb

 

Remove via petalinux-config

petalinux-config

 

 

Change the name to "boot_me" to test how this flows through:

 Examine it:

 Saw "boot_me"

 

 

 So I "can" and "should" use petalinux-config to specify the partitions. 

 

How do I figure out the name's and sizes of the partitions from the BOOT.bin or bootimage.bif?

 

bootimage.bif:

 

Can I look in the BOOT.bin?

 

I could match the first bytes of each image. No,

 

I can get all the partitions by passing -log trace to bootgen:

 

 

 

 

 How can I get rid of PetaLinux managed partitions? 

 

Select Manual:

 

 

 

 

 

Run: petalinux-build

 

Check with:

 Output:

 Partitions are gone! 

 

My kernel now fails to boot!

 

Its hung at:

 

Add the following:

 To: ./project-spec/meta-user/recipes-bsp/device-tree/files/system-user.dtsi

 

Force build the device-tree:

Run petalinux-build again so that the system.dtb gets updated:

Check

Boot

 

Still hung.

 

Try turning partitions back on. Maybe bootenv needs to be defined?

 

After using:

The kernel boots again. Why?

We see:

 

General flash / mtd debug:

 Leaving things here.

 

 

 

References

Please reload

Our Recent Posts

Columnize a List of Fields Using Excel 2016 on Windows 7

July 6, 2020

Turn On the Developer Tab in Excel 2016 on Windows 7

July 6, 2020

NASA's Aerospace Technology Resources

June 27, 2020

1/1
Please reload

Tags