NET_DMA: free skbs periodically
[safe/jmp/linux-2.6] / arch / arm / plat-omap / dmtimer.c
index ee20612..4d99dfb 100644 (file)
@@ -7,6 +7,9 @@
  * OMAP2 support by Juha Yrjola
  * API improvements and OMAP2 clock framework support by Timo Teras
  *
+ * Copyright (C) 2009 Texas Instruments
+ * Added OMAP4 support - Santosh Shilimkar <santosh.shilimkar@ti.com>
+ *
  * This program is free software; you can redistribute it and/or modify it
  * under the terms of the GNU General Public License as published by the
  * Free Software Foundation; either version 2 of the License, or (at your
@@ -35,7 +38,7 @@
 #include <linux/io.h>
 #include <linux/module.h>
 #include <mach/hardware.h>
-#include <mach/dmtimer.h>
+#include <plat/dmtimer.h>
 #include <mach/irqs.h>
 
 /* register offsets */
 struct omap_dm_timer {
        unsigned long phys_base;
        int irq;
-#if defined(CONFIG_ARCH_OMAP2) || defined(CONFIG_ARCH_OMAP3)
+#ifdef CONFIG_ARCH_OMAP2PLUS
        struct clk *iclk, *fclk;
 #endif
        void __iomem *io_base;
@@ -159,17 +162,9 @@ struct omap_dm_timer {
        unsigned posted:1;
 };
 
-#ifdef CONFIG_ARCH_OMAP1
-
-#define omap_dm_clk_enable(x)
-#define omap_dm_clk_disable(x)
-#define omap2_dm_timers                        NULL
-#define omap2_dm_source_names          NULL
-#define omap2_dm_source_clocks         NULL
-#define omap3_dm_timers                        NULL
-#define omap3_dm_source_names          NULL
-#define omap3_dm_source_clocks         NULL
+static int dm_timer_count;
 
+#ifdef CONFIG_ARCH_OMAP1
 static struct omap_dm_timer omap1_dm_timers[] = {
        { .phys_base = 0xfffb1400, .irq = INT_1610_GPTIMER1 },
        { .phys_base = 0xfffb1c00, .irq = INT_1610_GPTIMER2 },
@@ -181,17 +176,14 @@ static struct omap_dm_timer omap1_dm_timers[] = {
        { .phys_base = 0xfffbd400, .irq = INT_1610_GPTIMER8 },
 };
 
-static const int dm_timer_count = ARRAY_SIZE(omap1_dm_timers);
+static const int omap1_dm_timer_count = ARRAY_SIZE(omap1_dm_timers);
 
-#elif defined(CONFIG_ARCH_OMAP2)
-
-#define omap_dm_clk_enable(x)          clk_enable(x)
-#define omap_dm_clk_disable(x)         clk_disable(x)
+#else
 #define omap1_dm_timers                        NULL
-#define omap3_dm_timers                        NULL
-#define omap3_dm_source_names          NULL
-#define omap3_dm_source_clocks         NULL
+#define omap1_dm_timer_count           0
+#endif /* CONFIG_ARCH_OMAP1 */
 
+#ifdef CONFIG_ARCH_OMAP2
 static struct omap_dm_timer omap2_dm_timers[] = {
        { .phys_base = 0x48028000, .irq = INT_24XX_GPTIMER1 },
        { .phys_base = 0x4802a000, .irq = INT_24XX_GPTIMER2 },
@@ -215,17 +207,16 @@ static const char *omap2_dm_source_names[] __initdata = {
 };
 
 static struct clk *omap2_dm_source_clocks[3];
-static const int dm_timer_count = ARRAY_SIZE(omap2_dm_timers);
+static const int omap2_dm_timer_count = ARRAY_SIZE(omap2_dm_timers);
 
-#elif defined(CONFIG_ARCH_OMAP3)
-
-#define omap_dm_clk_enable(x)          clk_enable(x)
-#define omap_dm_clk_disable(x)         clk_disable(x)
-#define omap1_dm_timers                        NULL
+#else
 #define omap2_dm_timers                        NULL
+#define omap2_dm_timer_count           0
 #define omap2_dm_source_names          NULL
 #define omap2_dm_source_clocks         NULL
+#endif /* CONFIG_ARCH_OMAP2 */
 
+#ifdef CONFIG_ARCH_OMAP3
 static struct omap_dm_timer omap3_dm_timers[] = {
        { .phys_base = 0x48318000, .irq = INT_24XX_GPTIMER1 },
        { .phys_base = 0x49032000, .irq = INT_24XX_GPTIMER2 },
@@ -248,13 +239,44 @@ static const char *omap3_dm_source_names[] __initdata = {
 };
 
 static struct clk *omap3_dm_source_clocks[2];
-static const int dm_timer_count = ARRAY_SIZE(omap3_dm_timers);
+static const int omap3_dm_timer_count = ARRAY_SIZE(omap3_dm_timers);
 
 #else
+#define omap3_dm_timers                        NULL
+#define omap3_dm_timer_count           0
+#define omap3_dm_source_names          NULL
+#define omap3_dm_source_clocks         NULL
+#endif /* CONFIG_ARCH_OMAP3 */
+
+#ifdef CONFIG_ARCH_OMAP4
+static struct omap_dm_timer omap4_dm_timers[] = {
+       { .phys_base = 0x4a318000, .irq = OMAP44XX_IRQ_GPT1 },
+       { .phys_base = 0x48032000, .irq = OMAP44XX_IRQ_GPT2 },
+       { .phys_base = 0x48034000, .irq = OMAP44XX_IRQ_GPT3 },
+       { .phys_base = 0x48036000, .irq = OMAP44XX_IRQ_GPT4 },
+       { .phys_base = 0x40138000, .irq = OMAP44XX_IRQ_GPT5 },
+       { .phys_base = 0x4013a000, .irq = OMAP44XX_IRQ_GPT6 },
+       { .phys_base = 0x4013a000, .irq = OMAP44XX_IRQ_GPT7 },
+       { .phys_base = 0x4013e000, .irq = OMAP44XX_IRQ_GPT8 },
+       { .phys_base = 0x4803e000, .irq = OMAP44XX_IRQ_GPT9 },
+       { .phys_base = 0x48086000, .irq = OMAP44XX_IRQ_GPT10 },
+       { .phys_base = 0x48088000, .irq = OMAP44XX_IRQ_GPT11 },
+       { .phys_base = 0x4a320000, .irq = OMAP44XX_IRQ_GPT12 },
+};
+static const char *omap4_dm_source_names[] __initdata = {
+       "sys_ck",
+       "omap_32k_fck",
+       NULL
+};
+static struct clk *omap4_dm_source_clocks[2];
+static const int omap4_dm_timer_count = ARRAY_SIZE(omap4_dm_timers);
 
-#error OMAP architecture not supported!
-
-#endif
+#else
+#define omap4_dm_timers                        NULL
+#define omap4_dm_timer_count           0
+#define omap4_dm_source_names          NULL
+#define omap4_dm_source_clocks         NULL
+#endif /* CONFIG_ARCH_OMAP4 */
 
 static struct omap_dm_timer *dm_timers;
 static const char **dm_source_names;
@@ -403,8 +425,12 @@ void omap_dm_timer_enable(struct omap_dm_timer *timer)
        if (timer->enabled)
                return;
 
-       omap_dm_clk_enable(timer->fclk);
-       omap_dm_clk_enable(timer->iclk);
+#ifdef CONFIG_ARCH_OMAP2PLUS
+       if (cpu_class_is_omap2()) {
+               clk_enable(timer->fclk);
+               clk_enable(timer->iclk);
+       }
+#endif
 
        timer->enabled = 1;
 }
@@ -415,8 +441,12 @@ void omap_dm_timer_disable(struct omap_dm_timer *timer)
        if (!timer->enabled)
                return;
 
-       omap_dm_clk_disable(timer->iclk);
-       omap_dm_clk_disable(timer->fclk);
+#ifdef CONFIG_ARCH_OMAP2PLUS
+       if (cpu_class_is_omap2()) {
+               clk_disable(timer->iclk);
+               clk_disable(timer->fclk);
+       }
+#endif
 
        timer->enabled = 0;
 }
@@ -459,7 +489,7 @@ __u32 omap_dm_timer_modify_idlect_mask(__u32 inputmask)
 }
 EXPORT_SYMBOL_GPL(omap_dm_timer_modify_idlect_mask);
 
-#elif defined(CONFIG_ARCH_OMAP2) || defined (CONFIG_ARCH_OMAP3)
+#else
 
 struct clk *omap_dm_timer_get_fclk(struct omap_dm_timer *timer)
 {
@@ -503,6 +533,18 @@ void omap_dm_timer_stop(struct omap_dm_timer *timer)
        if (l & OMAP_TIMER_CTRL_ST) {
                l &= ~0x1;
                omap_dm_timer_write_reg(timer, OMAP_TIMER_CTRL_REG, l);
+#ifdef CONFIG_ARCH_OMAP2PLUS
+               /* Readback to make sure write has completed */
+               omap_dm_timer_read_reg(timer, OMAP_TIMER_CTRL_REG);
+                /*
+                 * Wait for functional clock period x 3.5 to make sure that
+                 * timer is stopped
+                 */
+               udelay(3500000 / clk_get_rate(timer->fclk) + 1);
+               /* Ack possibly pending interrupt */
+               omap_dm_timer_write_reg(timer, OMAP_TIMER_STAT_REG,
+                               OMAP_TIMER_INT_OVERFLOW);
+#endif
        }
 }
 EXPORT_SYMBOL_GPL(omap_dm_timer_stop);
@@ -694,23 +736,32 @@ EXPORT_SYMBOL_GPL(omap_dm_timers_active);
 int __init omap_dm_timer_init(void)
 {
        struct omap_dm_timer *timer;
-       int i;
+       int i, map_size = SZ_8K;        /* Module 4KB + L4 4KB except on omap1 */
 
        if (!(cpu_is_omap16xx() || cpu_class_is_omap2()))
                return -ENODEV;
 
        spin_lock_init(&dm_timer_lock);
 
-       if (cpu_class_is_omap1())
+       if (cpu_class_is_omap1()) {
                dm_timers = omap1_dm_timers;
-       else if (cpu_is_omap24xx()) {
+               dm_timer_count = omap1_dm_timer_count;
+               map_size = SZ_2K;
+       } else if (cpu_is_omap24xx()) {
                dm_timers = omap2_dm_timers;
+               dm_timer_count = omap2_dm_timer_count;
                dm_source_names = omap2_dm_source_names;
                dm_source_clocks = omap2_dm_source_clocks;
        } else if (cpu_is_omap34xx()) {
                dm_timers = omap3_dm_timers;
+               dm_timer_count = omap3_dm_timer_count;
                dm_source_names = omap3_dm_source_names;
                dm_source_clocks = omap3_dm_source_clocks;
+       } else if (cpu_is_omap44xx()) {
+               dm_timers = omap4_dm_timers;
+               dm_timer_count = omap4_dm_timer_count;
+               dm_source_names = omap4_dm_source_names;
+               dm_source_clocks = omap4_dm_source_clocks;
        }
 
        if (cpu_class_is_omap2())
@@ -722,8 +773,12 @@ int __init omap_dm_timer_init(void)
 
        for (i = 0; i < dm_timer_count; i++) {
                timer = &dm_timers[i];
-               timer->io_base = IO_ADDRESS(timer->phys_base);
-#if defined(CONFIG_ARCH_OMAP2) || defined(CONFIG_ARCH_OMAP3)
+
+               /* Static mapping, never released */
+               timer->io_base = ioremap(timer->phys_base, map_size);
+               BUG_ON(!timer->io_base);
+
+#ifdef CONFIG_ARCH_OMAP2PLUS
                if (cpu_class_is_omap2()) {
                        char clk_name[16];
                        sprintf(clk_name, "gpt%d_ick", i + 1);