cancel
Showing results for 
Show  only  | Search instead for 
Did you mean: 
Highlighted
Observer
Observer
8,074 Views
Registered: ‎10-28-2013

flashcp with 32MB QSPI

Jump to solution

I am using zynq-7000 with a 32MB Winbond QSPI and am trying to update the qspi partitions using flashcp. I have setup u-boot, kernel and devicetree to use a 15MB ramdisk. Unfortunately, once booted, the mtd partitions are referencing the upper 16MB of qspi instead of the lower where everything is actually stored when programmed with jtag. Thus when I reboot I am still using the jtag flashed data instead of the data flashed with flashcp. If I use the default size (~6MB) instead of 15MB everything works fine. Also, works great with 15MB ramdisk on a zedboard.

Any help on how to have the mtd partitions reference the correct locations in qspi when using a 15MB ramdisk?

0 Kudos
1 Solution

Accepted Solutions
Highlighted
Scholar
Scholar
10,825 Views
Registered: ‎05-28-2012

I think the 3-byte HW limitation forces the driver to avoid 4-byte addressing. This bit of code is what I was looking at:

static int m25p_probe(struct spi_device *spi)
{
...
  if (info->addr_width)
    flash->addr_width = info->addr_width;
  else if (flash->mtd.size > 0x1000000) {
    np = of_get_next_parent(spi->dev.of_node);
    if (of_property_match_string(np, "compatible",
             "xlnx,zynq-qspi-1.0") >= 0) {
      int status;
      flash->addr_width = 3;
      set_4byte(flash, info->jedec_id, 0);
      status = read_ear(flash);
      if (status < 0)
        dev_warn(&spi->dev, "failed to read ear reg\n");
      else
        flash->curbank = status & EAR_SEGMENT_MASK;
    } else {
...
}

However that code will not get run if info->addr_width is non-zero. The places where I suspect Winbond support is lacking is this bit of code:

static int read_ear(struct m25p *flash)
{
...
  if (JEDEC_MFR(flash->jedec_id) == CFI_MFR_AMD)
    code = OPCODE_BRRD;
  else if (JEDEC_MFR(flash->jedec_id) == CFI_MFR_ST)
    code = OPCODE_RDEAR;
  else if (JEDEC_MFR(flash->jedec_id) == 0xEF) //<-----Missing?
    code = OPCODE_RDEAR;                       //<-----Missing?
  else
    return -EINVAL;
...
}

static int write_ear(struct m25p *flash, u32 addr)
{
...
  if (JEDEC_MFR(flash->jedec_id) == 0x01)
    flash->command[0] = OPCODE_BRWR;
  if (JEDEC_MFR(flash->jedec_id) == 0x20) {
    write_enable(flash);
    flash->command[0] = OPCODE_WREAR;
  }
  if (JEDEC_MFR(flash->jedec_id) == 0xEF) { //<-----Missing?
    write_enable(flash);                    //<-----Missing?
    flash->command[0] = OPCODE_WREAR;       //<-----Missing?
  }
  // No error if not JEDEC_MFR is not recognized!
...

}

The m25p80.c was pretty convoluted before. Xilinx just made it doubly worse with the 3-byte address work-around.

 

 

View solution in original post

0 Kudos
21 Replies
Highlighted
Scholar
Scholar
8,057 Views
Registered: ‎05-28-2012

There might be a 16MB limitation to the QSPI controller. I think it is only capable of 3 byte addressing in the controller itself. Search the forum. Many threads on this. Maybe try switching to linear or normal SPI.

 

0 Kudos
Highlighted
Observer
Observer
8,054 Views
Registered: ‎10-28-2013

I've searched the forum. From what I understand 3-byte addressing implies you can only access the lower 16MB. My problem is since I have data crossing the 16MB boundary then once booted the mtd partitions are pointing the the upper 16MB. If I leave fsbl/u-boot, kernel, and devicetree in the lower 16MB and move my ramdisk to the upper 16MB that works. I would like to not worry about data crossing the lower to upper 16MB boundary.

0 Kudos
Highlighted
Scholar
Scholar
8,051 Views
Registered: ‎05-28-2012

Not quite following you. The MTD partitions are defined in the device tree. It can define partitions over the entire memory range for the flash. Are you saying that the flashcp fails to write to partition defined in the device tree to be in the lower 16MB? But okay if the partition is defined in the upper?

0 Kudos
Highlighted
Observer
Observer
8,048 Views
Registered: ‎10-28-2013

All my mtd partition in my devicetree are defined in the lower 16MB. My ramdisk has a size, such that spans from the lower 16MB to the upper 16MB. Using that devicetree, if in u-boot I define my ramdisk size to be ~6MB, flashcp works fine. If I define it to be 15-16MB then even though my devicetree specifies the lower 16MB, flashcp always writes to the upper 16MB, leaving my old data in the lower 16MB and my new data in the upper 16MB.

0 Kudos
Highlighted
Scholar
Scholar
8,041 Views
Registered: ‎05-28-2012

This i getting beyond my past experience with the QSPI. Just to clarify:

Scenario 1:
fsbl-uboot : reg = <0x0000000 0x0100000> // mtd0
linux :      reg = <0x0100000 0x0500000> // mtd1
device-tree: reg = <0x0600000 0x0020000> // mtd2
rootfs:      reg = <0x0620000 0x0100000> // mtd3, 1MB
unused_low:  reg = <0x0720000 0x18E0000> // mtd4, crosses 16MB boundary
                  //0x2000000 End of 32MB Memory
All works?

Scenario 2:
fsbl-uboot : reg = <0x0000000 0x0100000> // mtd0
linux :      reg = <0x0100000 0x0500000> // mtd1
device-tree: reg = <0x0600000 0x0020000> // mtd2
rootfs:      reg = <0x0620000 0x1000000> // mtd3, 16MB, crosses 16MB boundary
unused_high: reg = <0x1620000 0x09E0000> // mtd4
                  //0x2000000 End of 32MB Memory

flashcp mtd3 results in upper 16MB is good but lower 16MB is bad? flashcp of other mtds are okay?

If there was 3 byte addressing limitation, I would have expected the upper 16MB of data to wrap around to overwrite the partitions in the lower 16MB. I suspect it is using a hack to write 16MB(3 byte address) blocks at a time with a separate block index and the driver is not correctly splitting up writes that cross 16MB boundaries. That would indeed be a bug. Just guessing though.

Would the work-around be to just not cross the 16MB boundary? Put the ramdisk completely in the upper 16MB, eg.

Scenario 3:
fsbl-uboot : reg = <0x0000000 0x0100000> // mtd0
linux :      reg = <0x0100000 0x0500000> // mtd1
device-tree: reg = <0x0600000 0x0020000> // mtd2
unused_low:  reg = <0x0620000 0x09E0000> // mtd3
rootfs:      reg = <0x1000000 0x1000000> // mtd4
                  //0x2000000 End of 32MB Memory

0 Kudos
Highlighted
Scholar
Scholar
8,006 Views
Registered: ‎10-26-2012

The kernel uses "paging" to address the whole flash chip. We've even used a 64MB flash device with the Zynq.

0 Kudos
Highlighted
Observer
Observer
7,992 Views
Registered: ‎10-28-2013

My devicetree is setup as follows:


fsbl-uboot:      reg = <0x0 0x450000>;
linux:               reg = <0x450000 0x500000>;
device-tree:   reg = <0x950000 0x20000>;
rootfs:              reg = <0x970000 0xF00000>;
          

 

Everything works when u-boot is setup as follows:

 

kernel_addr=0x2000000
kernel_size=0x500000
kernel_offset=0x450000

devicetree_addr=0x2A00000
devicetree_size=0x20000
devicetree_offset=0x950000

ramdisk_addr=0x3000000
ramdisk_size=0x5E0000
ramdisk_offset=0x970000

 

It doesn't work when I change to the following in u-boot:

ramdisk_size=0xF00000

 

With ramdisk_size=0xF00000 my mtd partitions for some reason point to the following. Which is located in the upper 16MB even though they are defined as stated above.

fsbl-uboot:      reg = <0x1000000 0x450000>;
linux:               reg = <0x1450000 0x500000>;
device-tree:   reg = <0x1950000 0x20000>;
rootfs:             reg = <0x1970000 0xF00000>;

0 Kudos
Highlighted
Scholar
Scholar
7,987 Views
Registered: ‎05-28-2012

Looks okay but I think your allocations are not aligned to flash segement boundaries. I believe your allocation should be an integer multiple of the segement size. For this chip I think is 0x20000. You should check your datasheet.

 

fsbl-uboot: reg = <0x000000 0x460000>;
linux:      reg = <0x460000 0x500000>;
device-tree:reg = <0x960000 0x020000>;
rootfs:     reg = <0x980000 0xF00000>;

 

I am amazed that your boot process did not complain about corrupt images. Since your device tree straddles a flash segment boundary, it is getting partially erased to 0xFF.

0 Kudos
Highlighted
Observer
Observer
7,985 Views
Registered: ‎10-28-2013

I tried that and it still didn't work.

0 Kudos
Highlighted
Scholar
Scholar
7,954 Views
Registered: ‎05-28-2012

Whick kernel are you using? Are you using the "is_dual" flag in the the device tree? That flag causes address shifts. That's all I got.

 

0 Kudos
Highlighted
Observer
Observer
7,953 Views
Registered: ‎10-28-2013

Using  Xilinx kernel 3.12 at tag xilinx-v2013.4-trd. My devicetree has is-dual = <0>

0 Kudos
Highlighted
Scholar
Scholar
7,946 Views
Registered: ‎05-28-2012

I wonder about the 3-byte address support for various flash manufacturers. The m25p80.c driver code seems to have modified to support Spansion(0x01) and ST(0x20) chips only. Winbond(0xEF) appears not to be supported. Do you see "failed to read ear reg" on boot.

Highlighted
Observer
Observer
7,942 Views
Registered: ‎10-28-2013

I do not see "failed to read ear reg" on boot. Looks to me like Winbond is supported. In m25p80.c under set_4byte() there is a case for Winbond. Am I missing something there? Also, what does the is-dual value mean in the devicetree?

0 Kudos
Highlighted
Scholar
Scholar
10,826 Views
Registered: ‎05-28-2012

I think the 3-byte HW limitation forces the driver to avoid 4-byte addressing. This bit of code is what I was looking at:

static int m25p_probe(struct spi_device *spi)
{
...
  if (info->addr_width)
    flash->addr_width = info->addr_width;
  else if (flash->mtd.size > 0x1000000) {
    np = of_get_next_parent(spi->dev.of_node);
    if (of_property_match_string(np, "compatible",
             "xlnx,zynq-qspi-1.0") >= 0) {
      int status;
      flash->addr_width = 3;
      set_4byte(flash, info->jedec_id, 0);
      status = read_ear(flash);
      if (status < 0)
        dev_warn(&spi->dev, "failed to read ear reg\n");
      else
        flash->curbank = status & EAR_SEGMENT_MASK;
    } else {
...
}

However that code will not get run if info->addr_width is non-zero. The places where I suspect Winbond support is lacking is this bit of code:

static int read_ear(struct m25p *flash)
{
...
  if (JEDEC_MFR(flash->jedec_id) == CFI_MFR_AMD)
    code = OPCODE_BRRD;
  else if (JEDEC_MFR(flash->jedec_id) == CFI_MFR_ST)
    code = OPCODE_RDEAR;
  else if (JEDEC_MFR(flash->jedec_id) == 0xEF) //<-----Missing?
    code = OPCODE_RDEAR;                       //<-----Missing?
  else
    return -EINVAL;
...
}

static int write_ear(struct m25p *flash, u32 addr)
{
...
  if (JEDEC_MFR(flash->jedec_id) == 0x01)
    flash->command[0] = OPCODE_BRWR;
  if (JEDEC_MFR(flash->jedec_id) == 0x20) {
    write_enable(flash);
    flash->command[0] = OPCODE_WREAR;
  }
  if (JEDEC_MFR(flash->jedec_id) == 0xEF) { //<-----Missing?
    write_enable(flash);                    //<-----Missing?
    flash->command[0] = OPCODE_WREAR;       //<-----Missing?
  }
  // No error if not JEDEC_MFR is not recognized!
...

}

The m25p80.c was pretty convoluted before. Xilinx just made it doubly worse with the 3-byte address work-around.

 

 

View solution in original post

0 Kudos
Highlighted
Observer
Observer
7,929 Views
Registered: ‎10-28-2013

I'm using kernel 3.12 which does not have read_ear() (3.13 gives me a kernel panic which I haven't tracked down yet). I did modify write_ear() with and without write_enable()  and had no success.

0 Kudos
Highlighted
Scholar
Scholar
7,924 Views
Registered: ‎05-28-2012

I think that read_ear() is a key bit of code. If it's not there, the field "flash->curbank" probably gets initialized to 0. I suspect the linear SPI read of the ramdisk in u-boot probably results in the actual EAR being left as 1. The linux code thnks it's writing into bank 0 but the chip itself is writing into bank 1. I'd suggest porting over the read_ear() code and flash->curbank initialization coded.

0 Kudos
Highlighted
Observer
Observer
7,920 Views
Registered: ‎10-28-2013

That worked!

 

Thanks.

0 Kudos
Highlighted
Scholar
Scholar
7,914 Views
Registered: ‎05-28-2012

That's good news. Did you still have to add extra the Winbond code? If not then 3.13/2014.1 should work without mods. Otherwise I hope Xilinx adds support for all the other manufacturers in the next release.

0 Kudos
Highlighted
Observer
Observer
7,905 Views
Registered: ‎10-28-2013

I added everything you posted (made mine 3.12 code equivalent).

0 Kudos
Highlighted
Visitor
Visitor
523 Views
Registered: ‎12-25-2018

it works,thank you very much.

0 Kudos
Highlighted
Newbie
Newbie
81 Views
Registered: ‎09-16-2020

Hello, can you tell me how the kernel USES paging to access Flash

0 Kudos