[PATCH 4.2.y-ckt 293/305] ARM: OMAP2+: Fix onenand rate detection to avoid filesystem corruption

From: Kamal Mostafa
Date: Fri Jan 15 2016 - 19:12:25 EST

4.2.8-ckt2 -stable review patch. If anyone has any objections, please let me know.


From: Tony Lindgren <tony@xxxxxxxxxxx>

commit e7b11dc7b77bfce0a351230a5feeadc1d0bba997 upstream.

Commit 63aa945b1013 ("memory: omap-gpmc: Add Kconfig option for debug")
unified the GPMC debug for the SoCs with GPMC. The commit also left out
the option for HWMOD_INIT_NO_RESET as we now require proper timings for
GPMC to be able to remap GPMC devices out of address 0.

Unfortunately on Nokia N900, onenand now only partially works with the
device tree provided timings. It works enough to get detected but the
clock rate supported by the onenand chip gets misdetected. This in turn
causes the GPMC timings to be miscalculated and this leads into file
system corruption on N900.

Looks like onenand needs CS_CONFIG1 bit 27 WRITETYPE set for for sync
write. This is needed also for async timings when we write to onenand
with omap2_onenand_set_async_mode(). Without sync write bit set, the
async read for the onenand ONENAND_REG_VERSION_ID will return 0xfff.

Let's exit with an error if onenand rate is not detected. And let's
remove the extra call to omap2_onenand_set_async_mode() as we only need
to do this once at the end of omap2_onenand_setup_async().

Fixes: 63aa945b1013 ("memory: omap-gpmc: Add Kconfig option for debug")
Reported-by: Ivaylo Dimitrov <ivo.g.dimitrov.75@xxxxxxxxx>
Tested-by: Ivaylo Dimitrov <ivo.g.dimitrov.75@xxxxxxxxx>
Tested-by: Aaro Koskinen <aaro.koskinen@xxxxxx>
Signed-off-by: Tony Lindgren <tony@xxxxxxxxxxx>
Signed-off-by: Kamal Mostafa <kamal@xxxxxxxxxxxxx>
arch/arm/mach-omap2/gpmc-onenand.c | 14 +++++++++-----
1 file changed, 9 insertions(+), 5 deletions(-)

diff --git a/arch/arm/mach-omap2/gpmc-onenand.c b/arch/arm/mach-omap2/gpmc-onenand.c
index 17a6f75..7b76ce0 100644
--- a/arch/arm/mach-omap2/gpmc-onenand.c
+++ b/arch/arm/mach-omap2/gpmc-onenand.c
@@ -149,8 +149,8 @@ static int omap2_onenand_get_freq(struct omap_onenand_platform_data *cfg,
freq = 104;
- freq = 54;
- break;
+ pr_err("onenand rate not detected, bad GPMC async timings?\n");
+ freq = 0;

return freq;
@@ -271,6 +271,11 @@ static int omap2_onenand_setup_async(void __iomem *onenand_base)
struct gpmc_timings t;
int ret;

+ /*
+ * Note that we need to keep sync_write set for the call to
+ * omap2_onenand_set_async_mode() to work to detect the onenand
+ * supported clock rate for the sync timings.
+ */
if (gpmc_onenand_data->of_node) {
@@ -281,12 +286,9 @@ static int omap2_onenand_setup_async(void __iomem *onenand_base)
gpmc_onenand_data->flags |= ONENAND_SYNC_READ;
onenand_async.sync_read = false;
- onenand_async.sync_write = false;

- omap2_onenand_set_async_mode(onenand_base);

ret = gpmc_cs_program_settings(gpmc_onenand_data->cs, &onenand_async);
@@ -310,6 +312,8 @@ static int omap2_onenand_setup_sync(void __iomem *onenand_base, int *freq_ptr)
if (!freq) {
/* Very first call freq is not known */
freq = omap2_onenand_get_freq(gpmc_onenand_data, onenand_base);
+ if (!freq)
+ return -ENODEV;