OneNAND version ID may not give the highest frequency
supported and some OneNAND's have setup times that are
clock dependent.  Let the board provide that information.

Signed-off-by: Adrian Hunter <[email protected]>
---
 arch/arm/mach-omap2/gpmc-onenand.c        |   80 +++++++++++++++++++++--------
 arch/arm/plat-omap/include/plat/onenand.h |    8 +++
 2 files changed, 67 insertions(+), 21 deletions(-)

diff --git a/arch/arm/mach-omap2/gpmc-onenand.c 
b/arch/arm/mach-omap2/gpmc-onenand.c
index 46786a6..d776ded 100644
--- a/arch/arm/mach-omap2/gpmc-onenand.c
+++ b/arch/arm/mach-omap2/gpmc-onenand.c
@@ -121,6 +121,47 @@ static void set_onenand_cfg(void __iomem *onenand_base, 
int latency,
        writew(reg, onenand_base + ONENAND_REG_SYS_CFG1);
 }
 
+static int omap2_onenand_get_freq(struct omap_onenand_platform_data *cfg,
+                                 void __iomem *onenand_base, bool *clk_dep)
+{
+       u16 ver = readw(onenand_base + ONENAND_REG_VERSION_ID);
+       int freq = 0;
+
+       if (cfg->get_freq) {
+               struct onenand_freq_info fi;
+
+               fi.maf_id = readw(onenand_base + ONENAND_REG_MANUFACTURER_ID);
+               fi.dev_id = readw(onenand_base + ONENAND_REG_DEVICE_ID);
+               fi.ver_id = ver;
+               freq = cfg->get_freq(&fi, clk_dep);
+               if (freq)
+                       return freq;
+       }
+
+       switch ((ver >> 4) & 0xf) {
+       case 0:
+               freq = 40;
+               break;
+       case 1:
+               freq = 54;
+               break;
+       case 2:
+               freq = 66;
+               break;
+       case 3:
+               freq = 83;
+               break;
+       case 4:
+               freq = 104;
+               break;
+       default:
+               freq = 54;
+               break;
+       }
+
+       return freq;
+}
+
 static int omap2_onenand_set_sync_mode(struct omap_onenand_platform_data *cfg,
                                        void __iomem *onenand_base,
                                        int *freq_ptr)
@@ -138,6 +179,7 @@ static int omap2_onenand_set_sync_mode(struct 
omap_onenand_platform_data *cfg,
        int err, ticks_cez;
        int cs = cfg->cs, freq = *freq_ptr;
        u32 reg;
+       bool clk_dep = false;
 
        if (cfg->flags & ONENAND_SYNC_READ) {
                sync_read = 1;
@@ -152,27 +194,7 @@ static int omap2_onenand_set_sync_mode(struct 
omap_onenand_platform_data *cfg,
                err = omap2_onenand_set_async_mode(cs, onenand_base);
                if (err)
                        return err;
-               reg = readw(onenand_base + ONENAND_REG_VERSION_ID);
-               switch ((reg >> 4) & 0xf) {
-               case 0:
-                       freq = 40;
-                       break;
-               case 1:
-                       freq = 54;
-                       break;
-               case 2:
-                       freq = 66;
-                       break;
-               case 3:
-                       freq = 83;
-                       break;
-               case 4:
-                       freq = 104;
-                       break;
-               default:
-                       freq = 54;
-                       break;
-               }
+               freq = omap2_onenand_get_freq(cfg, onenand_base, &clk_dep);
                first_time = 1;
        }
 
@@ -232,6 +254,22 @@ static int omap2_onenand_set_sync_mode(struct 
omap_onenand_platform_data *cfg,
        else
                latency = 4;
 
+       if (clk_dep) {
+               if (gpmc_clk_ns < 12) { /* >83Mhz */
+                       t_ces   = 3;
+                       t_avds  = 4;
+               } else if (gpmc_clk_ns < 15) { /* >66Mhz */
+                       t_ces   = 5;
+                       t_avds  = 4;
+               } else if (gpmc_clk_ns < 25) { /* >40Mhz */
+                       t_ces   = 6;
+                       t_avds  = 5;
+               } else {
+                       t_ces   = 7;
+                       t_avds  = 7;
+               }
+       }
+
        if (first_time)
                set_onenand_cfg(onenand_base, latency,
                                        sync_read, sync_write, hf, vhf);
diff --git a/arch/arm/plat-omap/include/plat/onenand.h 
b/arch/arm/plat-omap/include/plat/onenand.h
index 86118dc..cbe897c 100644
--- a/arch/arm/plat-omap/include/plat/onenand.h
+++ b/arch/arm/plat-omap/include/plat/onenand.h
@@ -15,12 +15,20 @@
 #define ONENAND_SYNC_READ      (1 << 0)
 #define ONENAND_SYNC_READWRITE (1 << 1)
 
+struct onenand_freq_info {
+       u16                     maf_id;
+       u16                     dev_id;
+       u16                     ver_id;
+};
+
 struct omap_onenand_platform_data {
        int                     cs;
        int                     gpio_irq;
        struct mtd_partition    *parts;
        int                     nr_parts;
        int                     (*onenand_setup)(void __iomem *, int *freq_ptr);
+       int             (*get_freq)(const struct onenand_freq_info *freq_info,
+                                   bool *clk_dep);
        int                     dma_channel;
        u8                      flags;
        u8                      regulator_can_sleep;
-- 
1.7.0.4

--
To unsubscribe from this list: send the line "unsubscribe linux-omap" in
the body of a message to [email protected]
More majordomo info at  http://vger.kernel.org/majordomo-info.html

Reply via email to