OMAP: OneNAND: let boards determine OneNAND frequency
authorAdrian Hunter <adrian.hunter@nokia.com>
Mon, 7 Feb 2011 08:47:00 +0000 (10:47 +0200)
committerTony Lindgren <tony@atomide.com>
Thu, 17 Feb 2011 23:44:46 +0000 (15:44 -0800)
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 <adrian.hunter@nokia.com>
Signed-off-by: Tony Lindgren <tony@atomide.com>
arch/arm/mach-omap2/gpmc-onenand.c
arch/arm/plat-omap/include/plat/onenand.h

index 46786a606e90a11ae3e7b325eb6d37050f103024..d776ded9830d922188d87873268ac522697e6228 100644 (file)
@@ -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);
index 86118dc3f19aedd557f3dc2b154b79f210c4450e..cbe897ca7f9ed395376b45f36267d33513378713 100644 (file)
 #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;