This thread has been locked.

If you have a related question, please click the "Ask a related question" button in the top right corner. The newly created question will be automatically linked to this question.

AM5718: Multiple QSPI flash support in U-boot

Guru 16800 points

Part Number: AM5718

Hello,

We can access the multiple QSPI flashes by following related thread on Linux.
However, it seems that the reading procedure with CS dynamic switching is not implemented on u-boot.
Do you have any plan to implement the procedure?
We want to use multiple QSPI flashes on u-boot.

Best Regards,
Nomo

  • Hi Nomo,

    I understand your question is a follow-up to: https://e2e.ti.com/support/processors/f/791/t/849482

    We have since created a preliminary PATCH that would address the concern with multiple memory devices connected that was outlined earlier but we don't have a hardware setup to validate it. Can you please help us validating the below changes. If successful, we can then make this change official in our SDK and the upstream Linux Kernel tree.

    diff --git a/drivers/spi/spi-ti-qspi.c b/drivers/spi/spi-ti-qspi.c
    index 3cb65371ae3b..66dcb6128539 100644
    --- a/drivers/spi/spi-ti-qspi.c
    +++ b/drivers/spi/spi-ti-qspi.c
    @@ -62,6 +62,7 @@ struct ti_qspi {
     	u32 dc;
     
     	bool mmap_enabled;
    +	int current_cs;
     };
     
     #define QSPI_PID			(0x0)
    @@ -487,6 +488,7 @@ static void ti_qspi_enable_memory_map(struct spi_device *spi)
     				   MEM_CS_EN(spi->chip_select));
     	}
     	qspi->mmap_enabled = true;
    +	qspi->current_cs = spi->chip_select;
     }
     
     static void ti_qspi_disable_memory_map(struct spi_device *spi)
    @@ -498,6 +500,7 @@ static void ti_qspi_disable_memory_map(struct spi_device *spi)
     		regmap_update_bits(qspi->ctrl_base, qspi->ctrl_reg,
     				   MEM_CS_MASK, 0);
     	qspi->mmap_enabled = false;
    +	qspi->current_cs = -1;
     }
     
     static void ti_qspi_setup_mmap_read(struct spi_device *spi, u8 opcode,
    @@ -543,7 +546,7 @@ static int ti_qspi_exec_mem_op(struct spi_mem *mem,
     
     	mutex_lock(&qspi->list_lock);
     
    -	if (!qspi->mmap_enabled)
    +	if (!qspi->mmap_enabled || qspi->current_cs != mem->spi->chip_select)
     		ti_qspi_enable_memory_map(mem->spi);
     	ti_qspi_setup_mmap_read(mem->spi, op->cmd.opcode, op->data.buswidth,
     				op->addr.nbytes, op->dummy.nbytes);
    @@ -799,6 +802,7 @@ static int ti_qspi_probe(struct platform_device *pdev)
     		}
     	}
     	qspi->mmap_enabled = false;
    +	qspi->current_cs = -1;
     
     	ret = devm_spi_register_master(&pdev->dev, master);
     	if (!ret)
    

    Thanks and Regards,
    Andreas

  • Hello Andreas-san,

    Thank you for your reply.
    But the patch you attached is for Linux Kernel.
    We need a patch for u-boot driver.

    Best Regards,
    Nomo

  • Nomo-sam.

    Nomo said:
    We need a patch for u-boot driver.

    Oh yes sorry you were talking about U-Boot. Our current U-Boot should fully support the dynamic switching of NOR flashes via CS and updating CTRL_CORE_CONTROL_IO_2. When I instrument the code as follows...

    $ git diff drivers/spi/ti_qspi.c
    diff --git a/drivers/spi/ti_qspi.c b/drivers/spi/ti_qspi.c
    index 77fa17ee8a..667a9be95d 100644
    --- a/drivers/spi/ti_qspi.c
    +++ b/drivers/spi/ti_qspi.c
    @@ -157,6 +157,9 @@ static int ti_qspi_xfer(struct udevice *dev, unsigned int bitlen,
            int timeout;
            unsigned int cs = slave->cs;
     
    +       /* Display value of CTRL_CORE_CONTROL_IO_2 */
    +       printf("%s: *0x4A002558=0x%0x\n", __func__, readl(0x4A002558));
    +
            bus = dev->parent;
            priv = dev_get_priv(bus);
     
    @@ -369,6 +372,9 @@ static int ti_qspi_claim_bus(struct udevice *dev)
            priv->dc <<= slave_plat->cs * 8;
            writel(priv->dc, &priv->base->dc);
     
    +       /* Display value of CTRL_CORE_CONTROL_IO_2 */
    +       printf("%s: *0x4A002558=0x%0x\n", __func__, readl(0x4A002558));
    +
            return 0;
     }

    ...and then try accessing memory devices via CS0 and CS1 sequentially in U-Boot I see that CTRL_CORE_CONTROL_IO_2.QSPI_MEMMAPPED_CS gets updated accordingly (note that the second access fails as there is nothing connected to CS1 on my board):

    => sf probe 0:0
    ti_qspi_claim_bus: *0x4A002558=0x100
    ti_qspi_claim_bus: *0x4A002558=0x100
    ti_qspi_xfer: *0x4A002558=0x100
    ti_qspi_xfer: *0x4A002558=0x100
    ti_qspi_claim_bus: *0x4A002558=0x100
    ti_qspi_xfer: *0x4A002558=0x100
    ti_qspi_xfer: *0x4A002558=0x100
    SF: Detected s25fl256s1 with page size 256 Bytes, erase size 64 KiB, total 32 MiB
    => sf probe 0:1
    Warning: SPI speed fallback to 100 kHz
    ti_qspi_claim_bus: *0x4A002558=0x200
    ti_qspi_claim_bus: *0x4A002558=0x200
    ti_qspi_xfer: *0x4A002558=0x200
    ti_qspi_xfer: *0x4A002558=0x200
    unrecognized JEDEC id bytes: 00, 00, 00
    Failed to initialize SPI flash at 0:1 (error -2)

    What commands are you using to access the second flash chip? What specific error do you get?

    Nomo said:
    But the patch you attached is for Linux Kernel.

    While this is unrelated to your U-Boot question, it would be really great if you could help us test the patch that I had posted on Linux, this way we know it works and we can proceed with integrating it.

    Thanks and Regards,
    Andreas

  • Hi Andreas-san,

    Thank you for your advice.
    As a result, it seems to be able to recognize the SPI flash connected to CS1 on u-boot; however, we cannot read/write data from/to the SPI flash connected to CS1.
    Do you know whether there is any additional setting to access the memory?
    (For example, does we need to set the register other than for QSPI?)

    The log is following:
    => sf probe 0:0
    ti_qspi_claim_bus: *0x4A002558=0x100
    ti_qspi_claim_bus: *0x4A002558=0x100
    ti_qspi_xfer: *0x4A002558=0x100
    ti_qspi_xfer: *0x4A002558=0x100
    ti_qspi_claim_bus: *0x4A002558=0x100
    ti_qspi_xfer: *0x4A002558=0x100
    ti_qspi_claim_bus: *0x4A002558=0x100
    ti_qspi_xfer: *0x4A002558=0x100
    ti_qspi_claim_bus: *0x4A002558=0x100
    ti_qspi_xfer: *0x4A002558=0x100
    SF: Detected n25q00 with page size 256 Bytes, erase size 4 KiB, total 128 MiB => sf probe 0:1
    ti_qspi_claim_bus: *0x4A002558=0x200
    ti_qspi_claim_bus: *0x4A002558=0x200
    ti_qspi_xfer: *0x4A002558=0x200
    ti_qspi_xfer: *0x4A002558=0x200
    ti_qspi_claim_bus: *0x4A002558=0x200
    ti_qspi_xfer: *0x4A002558=0x200
    ti_qspi_claim_bus: *0x4A002558=0x200
    ti_qspi_xfer: *0x4A002558=0x200
    ti_qspi_claim_bus: *0x4A002558=0x200
    ti_qspi_xfer: *0x4A002558=0x200
    SF: Detected n25q00 with page size 256 Bytes, erase size 4 KiB, total 128 MiB =>


    By the way, we had checked the patch for the Linux driver attached on the previous post and confirmed that it seems to work fine.

    Best Regards,
    Nomo

  • Nomo-san,

    Nomo said:
    Thank you for your advice.
    As a result, it seems to be able to recognize the SPI flash connected to CS1 on u-boot; however, we cannot read/write data from/to the SPI flash connected to CS1.

    Can you please share logs how you are accessing the memory at 0:1 and what specific errors are shown.

    Also do you have the ability to check the QSPI bus with a logic analyzer? For example, does CS1 get asserted as expected, do you see any commands being exchanged, etc. Since CS0 is working for you just by comparing bus activity (on all signals) between accessing the chip at CS0 and the chip at CS1 we should be able to get some good insight to determine next steps.

    Nomo said:
    Do you know whether there is any additional setting to access the memory?
    (For example, does we need to set the register other than for QSPI?)

    Well I'd like to understand what exactly is failing, and we can go from there. There's a lot of registers involved so it's a bit difficult to make a general statement as to what might be missing, if anything.

    Nomo said:
    By the way, we had checked the patch for the Linux driver attached on the previous post and confirmed that it seems to work fine.

    Thanks for checking it. We will proceed then with submitting the patch upstream and integrating it into our SDK then.

    Best Regards,
    Andreas

  • Hello Andreas-san,

    Thank you for your support.

    We've tried the commands of the followings.
    For CS0, the command is "sf probe 0:0" and for CS1, the command is "sf probe 0:1".
    And then, we execute the same "sf erase", "sf write" and "sf read" commands.

    Question 1:
    As a result, we could find read data is shifted by 1byte.
    The read data for CS1 is "83000000: 00 41 42 43 2d 2d 2d 2d 2d 2d 2d 2d 2d 2d 2d 2d", while the read data for CS0 is "83000000: 41 42 43 44 2d 2d 2d 2d 2d 2d 2d 2d 2d 2d 2d 2d"
    Do you have any idea for this result?

    Question 2:
    Also, we captured the waveform of the QSPI signals (CSx, CLK, D0, D1).
    For CS0, the QUAD OUTPUT FAST READ command (6Bh) is seems to be executed. (The left waveform)
    However, for CS1, the READ command (03h) is seems to be executed. (The right waveform)
    (The right wave read the data with 1bit data line, while the left waveform read the data with 4bit data line)
    Although we execute the same command (sf read) for each CSx, do you have any idea for this difference?

    Best Regards,
    Nomo

  • Nomo-san,

    thanks for the additional detailed findings & updates. I'm currently out of the office (Thanksgiving holiday) but will have a close look on Monday and report back. I'll also reach out to one of my colleagues in case he has some suggestion in the meantime.

    Regards, Andreas

  • Hi Nomo-san,

    Nomo said:
    Question 1:
    As a result, we could find read data is shifted by 1byte.

    This  could be an issue related to dummy cycles getting used during certain transactions (not configured correctly).

    Nomo said:
    Question 2:
    Also, we captured the waveform of the QSPI signals (CSx, CLK, D0, D1).
    For CS0, the QUAD OUTPUT FAST READ command (6Bh) is seems to be executed. (The left waveform)
    However, for CS1, the READ command (03h) is seems to be executed. (The right waveform)
    (The right wave read the data with 1bit data line, while the left waveform read the data with 4bit data line)
    Although we execute the same command (sf read) for each CSx, do you have any idea for this difference?

    As you found the controller operates only in 1-bit mode for CS1. This behavior is usually specified through the device tree spi-tx-bus-width and spi-rx-bus-width properties associated with a certain memory.

    Can you please share your full device tree additions for "&qspi"? This will allow us to further analyze both of these concerns.

    Regards, Andreas

  • Hi Andreas-san,

    Thank you for your reply.

    We can find the cause for this issue.
    QSPI_SPI_SETUP1_REG was not set when the CS1 access.
    So, we modified the following points.
    Could you tell us the correctness for the modification?

    1.We add the following code at the next line of "writel(memval, &priv->base->setup0);" in the ti_qspi_setup_mmap_read function in ti_qspi.c
      writel(memval, &priv->base->setup1);

    2.We add the following code at the next line of "writel(0, &priv->base->setup0);" in the ti_qspi_release_bus function in ti_qspi.c
      writel(0, &priv->base->setup1);

    Best Regards,
    Nomo

  • Nomo-san,

    Nomo said:
    We can find the cause for this issue.
    QSPI_SPI_SETUP1_REG was not set when the CS1 access.
    So, we modified the following points.

    Sounds like your debug efforts were successful and you got it working? That's really great!

    Nomo said:

    Could you tell us the correctness for the modification?

    1.We add the following code at the next line of "writel(memval, &priv->base->setup0);" in the ti_qspi_setup_mmap_read function in ti_qspi.c
      writel(memval, &priv->base->setup1);

    2.We add the following code at the next line of "writel(0, &priv->base->setup0);" in the ti_qspi_release_bus function in ti_qspi.c
      writel(0, &priv->base->setup1);

    I had another look at the ti_qspi.c driver code. Yes the modification you identified will fix the issue with the mode not getting configured correctly for CS1 however as you can probably guess there are some limitations to this specific approach:

    • If the SPI slave devices connected to CS0 and CS1 use different parameters (in your case they don't) the SPI configuration associated with the CS you are not accessing at the moment will also get updated. This is unnecessary but should be harmless in the context of U-Boot (single-threaded)
    • No support for CS2 and CS3

    This being said a bit cleaner approach should probably leverage the slave_plat->cs variable to selectively update only base->setup0base->setup1, etc registers. As a next step I suggest you go ahead with the implementation you found (adding a "HACK:" to the prefix of the resulting patch you would be carrying). And I'll also discuss with our driver developer so we can work on an official fix for one of our next SDK(s) and upstream U-Boot. I might have another patch for you to try out to help us validate the solution if you don't mind.

    Thanks and Regards,
    Andreas

  • Hi Andreas-san,

    As your understanding, we got it working.
    Thank you for your support and cooperation.

    Also, additional information for limitation is very helpfull for us.
    I'll refer your comment and adopt it to our design.

    If I have additional question, I'll make another thread.

    Best Regards,
    Nomo

  • Nomo-san,

    Nomo said:
    As your understanding, we got it working.
    Thank you for your support and cooperation.

    Thanks again for the confirmation.

    Also, we have since prepared a PATCH to address the issue, please see attached. It would be great if you could test this specific patch with your dual-NOR setup. If successful we can then submit this patch to upstream and incorporate into our SDKs,

    Thanks,
    Andreas

    https://e2e.ti.com/cfs-file/__key/communityserver-discussions-components-files/791/0001_2D00_spi_2D00_ti_5F00_qspi_2D00_Fix_2D00_issues_2D00_when_2D00_accessing_2D00_CS_2D00_other_2D00_than_2D00_.patch

  • Hello Andreas-san,

    Thank you for your reply and attachement of patch.

    However, it seems not to work correctly.
    We think following procedures are expected to get CS connected to memory; however, this doesn't work and slave_plat-> is 0 when for CS1.
     bus = slave->dev->parent;
     priv = dev_get_priv(bus);
     slave_plat = dev_get_parent_platdata(bus);

    Could you confirm the source code?

    Best Regards,
    Nomo

  • Nomo-san,

    many thanks for checking. Yes you are right the fix was not 100% correct. Here is how the fix should get "fixed":

    diff --git a/drivers/spi/ti_qspi.c b/drivers/spi/ti_qspi.c
    index 67acb843f1a2..f2680217a458 100644
    --- a/drivers/spi/ti_qspi.c
    +++ b/drivers/spi/ti_qspi.c
    @@ -326,7 +326,7 @@ static int ti_qspi_exec_mem_op(struct spi_slave *slave,
    
            bus = slave->dev->parent;
            priv = dev_get_priv(bus);
    -       slave_plat = dev_get_parent_platdata(bus);
    +       slave_plat = dev_get_parent_platdata(slave->dev);
    
            /* Only optimize read path. */

    I have attached a updated PATCH that has this above change integrated. If you don't mind, it would be great to try this one more time. Thanks again for your help.

    Regards, Andreas

    https://e2e.ti.com/cfs-file/__key/communityserver-discussions-components-files/791/0001_2D00_spi_2D00_ti_5F00_qspi_2D00_Fix_2D00_issues_2D00_when_2D00_accessing_2D00_CS_2D00_other_2D00_than_2D00_v2.patch

  • Hi Andreas-san,

    Thank you for an update PATCH.
    We've tried the patch and confirm we can read/write data from/to the SPI flash connected to CS1.

    Best Regards,
    Nomo

  • Nomo-san,

    Nomo said:
    Thank you for an update PATCH.
    We've tried the patch and confirm we can read/write data from/to the SPI flash connected to CS1.

    thanks again for the extra effort with helping to test our patch!

    Regards, Andreas