]> www.pilppa.org Git - linux-2.6-omap-h63xx.git/commitdiff
ARM: OMAP: Add onennand board specific support for N800
authorJarkko Lavinen <jarkko.lavinen@nokia.com>
Wed, 7 Mar 2007 11:11:16 +0000 (03:11 -0800)
committerTony Lindgren <tony@atomide.com>
Wed, 4 Apr 2007 14:32:03 +0000 (10:32 -0400)
Add onennand board specific support for N800

Signed-off-by: Jarkko Lavinen <jarkko.lavinen@nokia.com>
Signed-off-by: Tony Lindgren <tony@atomide.com>
arch/arm/mach-omap2/board-n800-flash.c
include/asm-arm/arch-omap/onenand.h

index cd302ab571125493aa6679a13dd601e0d575ab3c..4005cfb56ad1916aa54462e03cac3f5e534db470 100644 (file)
 #include <linux/kernel.h>
 #include <linux/platform_device.h>
 #include <asm/mach/flash.h>
+#include <linux/mtd/onenand_regs.h>
+
+#include <asm/io.h>
 #include <asm/arch/onenand.h>
 #include <asm/arch/board.h>
+#include <asm/arch/gpmc.h>
 
 static struct mtd_partition n800_partitions[8];
 
+static int n800_onenand_setup(void __iomem *);
+
 static struct omap_onenand_platform_data n800_onenand_data = {
        .cs = 0,
        .gpio_irq = 26,
        .parts = n800_partitions,
-       .nr_parts = 0 /* filled later */
+       .nr_parts = 0, /* filled later */
+       .onenand_setup = n800_onenand_setup
 };
 
 static struct platform_device n800_onenand_device = {
@@ -32,6 +39,94 @@ static struct platform_device n800_onenand_device = {
        },
 };
 
+static unsigned short omap2_onenand_readw(void __iomem *addr)
+{
+       return readw(addr);
+}
+
+static void omap2_onenand_writew(unsigned short value, void __iomem *addr)
+{
+       writew(value, addr);
+}
+
+static int omap2_onenand_set_sync_mode(int cs, void __iomem *onenand_base)
+{
+       const int min_gpmc_clk_period = 18;
+       struct gpmc_timings t;
+       int tick_ns, div, fclk_offset_ns, fclk_offset, gpmc_clk_ns, latency;
+       u32 reg;
+
+       tick_ns = gpmc_round_ns_to_ticks(1);
+       div = gpmc_cs_calc_divider(cs, min_gpmc_clk_period);
+       gpmc_clk_ns = div * tick_ns;
+       if (gpmc_clk_ns >= 24)
+               latency = 3;
+       else
+               latency = 4;
+
+       /* Configure OneNAND for sync read */
+       reg = omap2_onenand_readw(onenand_base + ONENAND_REG_SYS_CFG1);
+       reg &= ~((0x7 << ONENAND_SYS_CFG1_BRL_SHIFT) | (0x7 << 9));
+       reg |=  (latency << ONENAND_SYS_CFG1_BRL_SHIFT) |
+               ONENAND_SYS_CFG1_SYNC_READ |
+               ONENAND_SYS_CFG1_BL_16;
+       omap2_onenand_writew(reg, onenand_base + ONENAND_REG_SYS_CFG1);
+
+       /* FIXME: Get timings from platform data */
+       /* Set syncronous read timings */
+       memset(&t, 0, sizeof(t));
+       t.sync_clk = min_gpmc_clk_period;
+       t.cs_on = 0;
+       t.adv_on = gpmc_round_ns_to_ticks(7);
+       fclk_offset_ns = t.adv_on + gpmc_round_ns_to_ticks(7);
+       fclk_offset = fclk_offset_ns / gpmc_round_ns_to_ticks(1);
+       t.page_burst_access = gpmc_clk_ns;
+
+       /* Read */
+       t.adv_rd_off = fclk_offset_ns + gpmc_round_ns_to_ticks(7);
+       t.oe_on = t.adv_rd_off;
+       t.access = fclk_offset_ns + (latency + 1) * gpmc_clk_ns;
+       t.oe_off = t.access + gpmc_round_ns_to_ticks(1);
+       t.cs_rd_off = t.oe_off;
+       t.rd_cycle = t.cs_rd_off + gpmc_round_ns_to_ticks(17);
+
+       /* Write */
+       t.adv_wr_off = t.adv_on + gpmc_round_ns_to_ticks(12);
+       t.we_on = t.adv_wr_off + gpmc_round_ns_to_ticks(1);
+       t.we_off = t.we_on + gpmc_round_ns_to_ticks(40);
+       t.cs_wr_off = t.we_off + gpmc_round_ns_to_ticks(1);
+       t.wr_cycle = t.cs_wr_off + gpmc_round_ns_to_ticks(1);
+
+       /* Configure GPMC for synchronous read */
+       fclk_offset %= div;
+       gpmc_cs_write_reg(cs, GPMC_CS_CONFIG1,
+                         GPMC_CONFIG1_WRAPBURST_SUPP |
+                         GPMC_CONFIG1_READMULTIPLE_SUPP |
+                         GPMC_CONFIG1_READTYPE_SYNC |
+                         GPMC_CONFIG1_CLKACTIVATIONTIME(fclk_offset) |
+                         GPMC_CONFIG1_PAGE_LEN(2) |
+                         GPMC_CONFIG1_WAIT_READ_MON |
+                         GPMC_CONFIG1_WAIT_PIN_SEL(0) |
+                         GPMC_CONFIG1_DEVICESIZE_16 |
+                         GPMC_CONFIG1_DEVICETYPE_NOR |
+                         GPMC_CONFIG1_MUXADDDATA);
+
+       return gpmc_cs_set_timings(cs, &t);
+}
+
+static int n800_onenand_setup(void __iomem *onenand_base)
+{
+       struct omap_onenand_platform_data *datap = &n800_onenand_data;
+       struct device *dev = &n800_onenand_device.dev;
+
+       /* Set sync timings in GPMC */
+       if (omap2_onenand_set_sync_mode(datap->cs, onenand_base) < 0) {
+               dev_err(dev, "Unable to set synchronous mode\n");
+               return -EINVAL;
+       }
+
+       return 0;
+}
 
 void __init n800_flash_init(void)
 {
index b8a19beae1239312c95f8d69d1e3a0c4a4ac1383..3e8ab2f49c9fc37ef22a421fc9b92ed99f01c8bd 100644 (file)
@@ -16,4 +16,5 @@ struct omap_onenand_platform_data {
        int                     gpio_irq;
        struct mtd_partition    *parts;
        int                     nr_parts;
+       int                     (*onenand_setup)(void __iomem *);
 };