imx8qxp OCTAL SPI FLASH 代码分析

1.先读数据手册

FlexSPI block supports following features:
? Flexible sequence engine(LUT table)to support various vendor devices
? Serial NOR Flash or other device with similarSPI protocol as Serial NOR Flash
? Serial NAND Flash
? HyperBus device (HyperFlash/HyperRAM)
? FPGA device
? Flash access mode
? Single/Dual/Quad/Octal mode
? SDR/DDR mode
? Individual/Parallel mode
? Support sampling clock mode:
? Internal dummy read strobe loopbacked internally
? Internal dummy read strobe loopbacked from pad
? Flash provided read strobe
? Automatic Data Learning to select correct sample clock phase

2.结构方框图

image.png


2.1 可以使用 AHB BUS 和IPS BUS 两个总线输出命令通LTU Sequence 给外部flash ,使用时选择任意一个。
2.2 与外部flash 接线如下:


image.png

image.png

3.LUT Table

FlexSPI 并不直接通过寄存器来操作SPI Bus上的数据传输,而是提供了一组叫LUT Table的接口。也就是用户需要先将操作SPI Slave设备的命令根据LUT Table的规则写入到LUT Table,然后通过寄存器告诉FlexSPI某一个命令的LUT Sequence,然后FlexSPI会去处理SPI Bus上的事。

先看一下LUT Table的数据结构,它是FlexSPI内部的一段未初始化内存。目前的FlexSPI一共16个Sequence。每一个Sequence包含8个instruction,每个instruction占用两个byteInstruction的格式如最下图所示,0-7位是操作数operand,8-9位是instruction的pad(1PAD, 2PAD, 4PAD, 8PAD),10-15位是操作码opcode

image.png

4.LTU 调用关系

4.1 读取MT35XU256ABA1G12-0AAT数据手册定义如下:

image.png

4.2 代码定义如下: define SPINOR_OP_RDID 0x9f /* Read JEDEC ID */

4.3 为了理解这个控制器先看 linux 调用过程如下:

image.png

4.4 总结调用过程:
上次要读取id时先发读取id命令 SPINOR_OP_RDID通过函数指针调用到fsl-flexspi.c 中进行转换成LTU命令在发出去。

4.5 LTU初始化

1
2
3
4
5
6
#linux
static void fsl_flexspi_init_lut(struct fsl_flexspi *flex)
{
#qnx
int init_lut(imx_fspi_t *dev)
{

5.qnx 调用过程

5.1 初始化


image.png

5.2 执行 flashctl -p /dev/fs0 -ev 调用过程


image.png

6. linux 调用:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
#fsl-imx8qxp-mek.dtsi

&flexspi0 {
    pinctrl-names = "default";
    pinctrl-0 = <&pinctrl_flexspi0>;
    status = "okay";

    flash0: mt35xu512aba@0 {
        reg = <0>;
        #address-cells = <1>;
        #size-cells = <1>;
        compatible = "micron,mt35xu512aba";
        spi-max-frequency = <29000000>;
        spi-nor,ddr-quad-read-dummy = <8>;
    };
};

        pinctrl_flexspi0: flexspi0grp {
            fsl,pins = <
                SC_P_QSPI0A_DATA0_LSIO_QSPI0A_DATA0 0x0600004c
                SC_P_QSPI0A_DATA1_LSIO_QSPI0A_DATA1 0x0600004c
                SC_P_QSPI0A_DATA2_LSIO_QSPI0A_DATA2 0x0600004c
                SC_P_QSPI0A_DATA3_LSIO_QSPI0A_DATA3 0x0600004c
                SC_P_QSPI0A_DQS_LSIO_QSPI0A_DQS     0x0600004c
                SC_P_QSPI0A_SS0_B_LSIO_QSPI0A_SS0_B 0x0600004c
                SC_P_QSPI0A_SS1_B_LSIO_QSPI0A_SS1_B 0x0600004c
                SC_P_QSPI0A_SCLK_LSIO_QSPI0A_SCLK   0x0600004c
                SC_P_QSPI0B_SCLK_LSIO_QSPI0B_SCLK   0x0600004c
                SC_P_QSPI0B_DATA0_LSIO_QSPI0B_DATA0 0x0600004c
                SC_P_QSPI0B_DATA1_LSIO_QSPI0B_DATA1 0x0600004c
                SC_P_QSPI0B_DATA2_LSIO_QSPI0B_DATA2 0x0600004c
                SC_P_QSPI0B_DATA3_LSIO_QSPI0B_DATA3 0x0600004c
                SC_P_QSPI0B_DQS_LSIO_QSPI0B_DQS     0x0600004c
                SC_P_QSPI0B_SS0_B_LSIO_QSPI0B_SS0_B 0x0600004c
                SC_P_QSPI0B_SS1_B_LSIO_QSPI0B_SS1_B 0x0600004c
            >;
        };
1
2
3
4
5
6
7
8
9
 # 匹配设备树 compatible = "micron,mt35xu512aba" 代码:
 # C:jack.niuSource_Codelinux-toradexdriversmtdspi-norspi-nor.c

static const struct flash_info spi_nor_ids[] = {
  { "mt25qu256",     INFO(0x20bb19, 0, 64 * 1024,  256, SECT_4K | SPI_NOR_DUAL_READ |
   SPI_NOR_QUAD_READ) },
  {"mt35xu512aba", INFO(0x2c5b1a, 0, 128 * 1024, 512, SECT_4K | SPI_NOR_OCTAL_READ |
  SPI_NOR_SKIP_SFDP) },
}

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
#目录树 arch/arm64/boot/dts/freescale/fsl-imx8dx.dtsi:3358:             compatible = "fsl,imx8qxp-flexspi";
#目录树代码  
 flexspi0: flexspi@05d120000 {
        #address-cells = <1>;
        #size-cells = <0>;
        compatible = "fsl,imx8qxp-flexspi";
        reg = <0x0 0x5d120000 0x0 0x10000>, <0x0 0x08000000 0x0 0x10000000>;
        reg-names = "FlexSPI", "FlexSPI-memory";
        interrupts = <GIC_SPI 92 IRQ_TYPE_LEVEL_HIGH>;
        clocks = <&clk IMX8QXP_LSIO_FSPI0_CLK>;
        assigned-clock-rates = <29000000>;
        clock-names = "fspi";
        power-domains = <&pd_lsio_flexspi0>;
        status = "disabled";
    };

#匹配代码如下
drivers/mtd/spi-nor/fsl-flexspi.c:1162: { .compatible = "fsl,imx8qxp-flexspi", .data = (void *)&imx8qxp_data, },

QNX 初始化代码

18.2.5.1 FlexSPI Initialization
FlexSPI controller initialization sequence is as following:
? Enable controller clocks (AHB clock/IP Bus clock/Serial root clock) in System level.
? Set MCR0[MDIS] to 0x1 (Make sure controller is configured in module stop mode)
? Configure module control registers: MCR0, MCR1, MCR2. (Don't change
MCR0[MDIS])
? Configure AHB bus control register (AHBCR) and AHB RX Buffer control register
(AHBRXBUFxCR0) optionally, if AHB command will be used
? Configure Flash control registers (FLSHxCR0,FLSHxCR1,FLSHxCR2) according to
external device type
? Configure DLL control register (DLLxCR) according to sample clock source
selection
? set MCR0[MDIS] to 0x0 (Exit module stop mode)
? Configure LUT as needed (For AHB command or IP command)
? Reset controller optionally (by set MCR0[SWRESET] to 0x1)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
/**
*  imx_fc_flexspi.c
 * First part of controller initialization.
 *
 * @return File descriptor.
 */
imx_fspi_t *imx_flexspi_open(void)
{
 /* Enable FLEXSPI clock */
    mcr_reg = in32(dev->vbase + IMX_FLEXSPI_MCR0);
    mcr_reg &= ~IMX_FLEXSPI_MCR0_MDIS_MASK;
    out32(dev->vbase + IMX_FLEXSPI_MCR0, mcr_reg);
    /* Configure FLEXSPI to use IP access and COMBINATION mode
     * RXCLKSRC - Flash provided Read strobe and input from DQS pad */
    mcr_reg = in32(dev->vbase + IMX_FLEXSPI_MCR0);
    mcr_reg &= ~(IMX_FLEXSPI_MCR0_ARDFEN_MASK | IMX_FLEXSPI_MCR0_ATDFEN_MASK);
    if (dev->pads == 8) {
        mcr_reg |= IMX_FLEXSPI_MCR0_COMBINATIONEN_MASK;
    }
    mcr_reg |= (dev->smpl << IMX_FLEXSPI_MCR0_RXCLKSRC_SHIFT);
    out32(dev->vbase + IMX_FLEXSPI_MCR0, mcr_reg);
    /* Reset FLEXSPI */
    mcr_reg = in32(dev->vbase + IMX_FLEXSPI_MCR0);
    mcr_reg |= IMX_FLEXSPI_MCR0_SWRESET_MASK;
    out32(dev->vbase + IMX_FLEXSPI_MCR0, mcr_reg);
    /* Wait 1ms for domains reset */
    delay(1);
    /* Enable delay line calibration (Flash provided read strobe) */
    out32(dev->vbase + IMX_FLEXSPI_DLLACR, IMX_FLEXSPI_DLLACR_DLLEN_MASK);
    /* Clear RX and TX FIFOs */
    out32(dev->vbase + IMX_FLEXSPI_IPTXFCR, IMX_FLEXSPI_IPTXFCR_CLRIPTXF_MASK);
    out32(dev->vbase + IMX_FLEXSPI_IPRXFCR, IMX_FLEXSPI_IPRXFCR_CLRIPRXF_MASK);