In case you have the NAND driver enabled in Linux BSP release L2.6.35_1.1.0_130130 and experience BCH timeout error on i.MX28, please try this patch.
--- a/drivers/mtd/nand/gpmi-nfc/gpmi-nfc-hal-v1.c
+++ b/drivers/mtd/nand/gpmi-nfc/gpmi-nfc-hal-v1.c
@@ -46,8 +46,15 @@ static int init(struct gpmi_nfc_data *this)
clk_enable(resources->clock);
/* Reset the GPMI block. */
-
- mxs_reset_block(resources->gpmi_regs + HW_GPMI_CTRL0, false);
+ /*
+ * Reset the BCH block. Notice that we pass in true for the just_enable
+ * flag. This is because the soft reset for the version 0 BCH block
+ * doesn't work and the version 1 BCH block is similar enough that we
+ * suspect the same (though this has not been officially tested). If you
+ * try to soft reset a version 0 BCH block, it becomes unusable until
+ * the next hard reset.
+ */
+ mxs_reset_block(resources->gpmi_regs + HW_GPMI_CTRL0, true);
/* Choose NAND mode. */
__raw_writel(BM_GPMI_CTRL1_GPMI_MODE,
@@ -108,7 +115,15 @@ static int set_geometry(struct gpmi_nfc_data *this)
clk_enable(resources->clock);
/* reset the BCH */
- mxs_reset_block(resources->bch_regs, false);
+ /*
+ * Reset the BCH block. Notice that we pass in true for the just_enable
+ * flag. This is because the soft reset for the version 0 BCH block
+ * doesn't work and the version 1 BCH block is similar enough that we
+ * suspect the same (though this has not been officially tested). If you
+ * try to soft reset a version 0 BCH block, it becomes unusable until
+ * the next hard reset.
+ */
+ mxs_reset_block(resources->bch_regs, true);
/* Configure layout 0. */
Hi Thomas,
My NAND boot up stress test at GPMI 96MHz has been running for over 24 hours or nearly 3000 boot up and not yet any error has been observed. Please let me know if you need further input from us.
Thanks,
Peter
Hi Peter,
Thanks for feedback
I would need additional confirmation from you
It looks like the default setup uses XTAL as gpmi_ref
in our design , pll.0 is used byt doing the following:
/* turn on gpmi frac: pll.0 is ref_gpmi's parent*/
REG_CLR(REGS_CLKCTRL_BASE, HW_CLKCTRL_FRAC1,
BM_CLKCTRL_FRAC1_CLKGATEGPMI |
BM_CLKCTRL_FRAC1_PIXFRAC);
REG_SET(REGS_CLKCTRL_BASE, HW_CLKCTRL_FRAC1, 18<<16); /* 480 MHz for ref_gpmi*/
/* Clear bypass bit: ref_gpmi becomes clk_gpmi's parent*/
REG_CLR(REGS_CLKCTRL_BASE, HW_CLKCTRL_CLKSEQ,
BM_CLKCTRL_CLKSEQ_BYPASS_GPMI);
Can you confirm this is the right way to configure gpmi_ref ? Thanks.
Thomas
Hi Thomas,
After writing the GPMI clock divider value, you need to poll the BUSY bit to wait for the new divider value effective in the clock domains. Below is my code to change the GPMI clock to 96 MHz.
/* source path from ref_xtal */
REG_SET(REGS_CLKCTRL_BASE, HW_CLKCTRL_CLKSEQ,
BM_CLKCTRL_CLKSEQ_BYPASS_GPMI);
/* Set GPMIFRAC = 18 */
REG_WR( REGS_CLKCTRL_BASE, HW_CLKCTRL_FRAC1,
REG_RD(REGS_CLKCTRL_BASE, HW_CLKCTRL_FRAC1) &
(~(BM_CLKCTRL_FRAC1_CLKGATEGPMI)) );
REG_WR( REGS_CLKCTRL_BASE, HW_CLKCTRL_FRAC1,
(REG_RD(REGS_CLKCTRL_BASE, HW_CLKCTRL_FRAC1) &
(~(BM_CLKCTRL_FRAC1_GPMIFRAC))) |
(18 << BP_CLKCTRL_FRAC1_GPMIFRAC) );
/* Set GPMI DIV = 5 */
REG_WR( REGS_CLKCTRL_BASE, HW_CLKCTRL_GPMI,
REG_RD(REGS_CLKCTRL_BASE, HW_CLKCTRL_GPMI) &
(~(BM_CLKCTRL_GPMI_CLKGATE)) );
while( REG_RD(REGS_CLKCTRL_BASE, HW_CLKCTRL_GPMI) & BM_CLKCTRL_GPMI_BUSY);
REG_WR( REGS_CLKCTRL_BASE, HW_CLKCTRL_GPMI,
(REG_RD(REGS_CLKCTRL_BASE, HW_CLKCTRL_GPMI) &
(~(BM_CLKCTRL_GPMI_DIV))) |
(5 << BP_CLKCTRL_GPMI_DIV) );
while( REG_RD(REGS_CLKCTRL_BASE, HW_CLKCTRL_GPMI) & BM_CLKCTRL_GPMI_BUSY);
REG_WR( REGS_CLKCTRL_BASE, HW_CLKCTRL_GPMI,
REG_RD(REGS_CLKCTRL_BASE, HW_CLKCTRL_GPMI) &
(~(BM_CLKCTRL_GPMI_DIV_FRAC_EN)) );
while( REG_RD(REGS_CLKCTRL_BASE, HW_CLKCTRL_GPMI) & BM_CLKCTRL_GPMI_BUSY);
/* source path is ref_gpmi GPMI = 480 * (18/18) / 5 = 96 MHz */
REG_CLR(REGS_CLKCTRL_BASE, HW_CLKCTRL_CLKSEQ,
BM_CLKCTRL_CLKSEQ_BYPASS_GPMI);
Thanks,
Peter
Thanks Peter ! I will try this.
My question came because I observed that I had different results given the clock source used:
- XTAL @24Mhz: issue not reproduced
- PLL.0 divided to 24 MHz: issue reproduced.
TEsting is ongoing, will let you know.
Thomas
Hi
I did the follwoign tests:
24MHz obtained by dividing pll.0: no error
40 Mhz obtained by dividing pll.0: DMA error reproduced
Peter, can you share tour u-boot code? I think we are not aligned
Note that I 'm using relaxed timings for our NAND (the default timings coded in u-boot 2009.08, manuf id 0xC, prod id 0xF1)
thanks
Hi Thomas,
My EVK has been running for 2 more days (or 5000 times) but still no BCH error or boot failure found. Here are my changes in clean L2.6.35_1.1.0_130130 u-boot for 96MHz GPMI clock. My boot environment is
bootdelay=3
baudrate=115200
ipaddr=192.168.1.103
serverip=192.168.1.101
netmask=255.255.255.0
bootfile="uImage"
loadaddr=0x42000000
nfsroot=/home/notroot/nfs/rootfs
bootargs_nfs=setenv bootargs ${bootargs} root=/dev/nfs ip=dhcp nfsroot=${serverip}:${nfsroot},v3,tcp fec_mac=${ethaddr}
bootcmd_net=run bootargs_nfs; dhcp; bootm
ethact=FEC0
bootcmd_mmc=run bootargs_mmc; mmc read 0 ${loadaddr} 0x100 0x2000; bootm
bootargs_mmc=setenv bootargs ${bootargs} root=/dev/mmcblk0p3 rw rootwait ip=none gpmi noinitrd
bootargs_nand=setenv bootargs ${bootargs} ubi.mtd=2 root=ubi0:rootfs0 rootfstype=ubifs rw rootwait ip=none gpmi noinitrd
bootcmd_nand=run bootargs_nand; nand read ${loadaddr} 0x1400000 0x300000; bootm
bootargs=console=ttyAM0,115200
bootcmd=run bootcmd_nand
stdin=serial
stdout=serial
stderr=serial
Thanks,
Peter
Hi Peter,
I'm coming back with interesting results.
It seems the following is needed:
- during u-boot NAND driver init:
reset GPMI with just_enable to FALSE
reset BCH with just enable to TRUE
- during set_geometry:
reset BCH with just enable to TRUE
GPMI can be totally soft-reset during init
BCH must never be totally soft-reset
BCH must be enabled right after GPMI during init.
I did not try to remove the additional BCH enablement in init, as my current code is working.
Could you please acknowledge this sequence ?
from <init>:
mxs_dma_init(); |
/* Reset the GPMI block. */
i = 0;
do {
error = gpmi_reset_block((void *)CONFIG_GPMI_REG_BASE, 0); | |
i++; |
} while (error != 0 && i < 10);
//try just enable
gpmi_reset_block((void *)CONFIG_BCH_REG_BASE + HW_BCH_CTRL, 1);
/* Choose NAND mode. */
REG_CLR(CONFIG_GPMI_REG_BASE, HW_GPMI_CTRL1,
BM_GPMI_CTRL1_GPMI_MODE); |
from <set_geometry>
page_size | = mtd->writesize + mtd->oobsize; |
/*
* Reset the BCH block. Notice that we pass in true for the just_enable
* flag. This is because the soft reset for the version 0 BCH block
* doesn't work and the version 1 BCH block is similar enough that we
* suspect the same (though this has not been officially tested). If you
* try to soft reset a version 0 BCH block, it becomes unusable until
* the next hard reset.
*/
gpmi_reset_block((void *)CONFIG_BCH_REG_BASE + HW_BCH_CTRL, 1);
/* Configure layout 0. */
writel(BF_BCH_FLASH0LAYOUT0_NBLOCKS(block_count) | | | |
BF_BCH_FLASH0LAYOUT0_META_SIZE(metadata_size) | | ||
BF_BCH_FLASH0LAYOUT0_ECC0(ecc_strength) | | | |
BF_BCH_FLASH0LAYOUT0_DATA0_SIZE(block_size), | ||
CONFIG_BCH_REG_BASE + HW_BCH_FLASH0LAYOUT0); |
Thanks,
Thomas
Hi Thomas,
Please see my comment about the u-boot NAND driver init sequence.
"GPMI can be totally soft-reset during init"
- agree.
"BCH must never be totally soft-reset.
- Errata 2847 is only applicable to i.MX233. i.MX28 should not have this issue. I have validated the BCH soft reset (but only on 1 board) in my previous boot up stress test. Have you ever tried the BSP sequence (GPMI soft reset with just_enable to FALSE, followed by BCH soft reset with just enabled to FALSE)? Does it also work on your side?
"BCH must be enabled right after GPMI during init"
- agree. BCH is always enabled after GPMI
Thanks,
Peter
Hi Peter,
Regarding the BCH soft-reset I'm almost sure this issue is valid for i.MX28
On my side, the only way I can get both the BCH timeout and corrupted PEBs issues gone is when I DON'T soft reset BCH
Thomas
Additional comment: Note this is very board-dependant. You should try with different boards to increase testing diversity IMO.
Thomas
I run the boot up test again using your sequence (GPMI soft reset, BCH just enabled). My EVK board also does not show any boot up issue after 3600+ times. I will get another EVK board and test both sequences again.
I don't see any harm to let the BCH just enable. If this sequence works on all your boards, please keep this.
I have tried the both sequences, {GPMI soft reset BCH just enabled} and {GPMI soft reset BCH soft reset}, on 3 i.MX28 EVKs but none of them shows any boot error.
Since no boot error is found in {GPMI soft reset BCH just enabled} sequence in both of our testings, I think this sequence can also be used in i.MX28.
Hi Peter,
Thanks for feedback. I will double check if our code is doing the GPMI source clock change correctly as you mention and come back to you
BR
Thomas
Hi Peter,
In our u-boot code, the difference is that the GPMI bypass bit is cleared before setting the GPMI divider. I would like to try your recommandation (setting it after) but I'm concerned that if it just doesn't work, my board won't be able to boot at all.
So: have you unitary-tested it ?
Hi Peter,
We are using L2.6.35 1_1_0 on iMX28. the original patch comes from a bug on imx28 as well so this should not be a surprise.
we backported the patch from gpmi-lib to the right file (where GPMI is reset) in this BSP
> may I say that setting "just_enable" to true can resolve all NAND startup issues?
No, it's the contrary in our case. If set to true, we will have DMA timeouts.
if set to false, DMA timeouts go away but we have startup issues 1 time over 100.
If we use the patch I pointed (additional BCH reset) we don't have any problmes.
Thomas