Merge remote-tracking branch 'lsk/v3.10/topic/aosp' into linux-linaro-lsk-android
[firefly-linux-kernel-4.4.55.git] / arch / arm / mach-msm / timer.c
index f9fd77e8f1f5a998af7b8f15e12af3afd5bcc299..284313f3e02cb1edd56cfd25a425efe40a5207a1 100644 (file)
 
 #include "common.h"
 
-#define TIMER_MATCH_VAL         0x0000
-#define TIMER_COUNT_VAL         0x0004
-#define TIMER_ENABLE            0x0008
-#define TIMER_ENABLE_CLR_ON_MATCH_EN    BIT(1)
-#define TIMER_ENABLE_EN                 BIT(0)
-#define TIMER_CLEAR             0x000C
-#define DGT_CLK_CTL_DIV_4      0x3
+#define TIMER_MATCH_VAL                        0x0000
+#define TIMER_COUNT_VAL                        0x0004
+#define TIMER_ENABLE                   0x0008
+#define TIMER_ENABLE_CLR_ON_MATCH_EN   BIT(1)
+#define TIMER_ENABLE_EN                        BIT(0)
+#define TIMER_CLEAR                    0x000C
+#define DGT_CLK_CTL                    0x10
+#define DGT_CLK_CTL_DIV_4              0x3
+#define TIMER_STS_GPT0_CLR_PEND                BIT(10)
 
 #define GPT_HZ 32768
 
 #define MSM_DGT_SHIFT 5
 
 static void __iomem *event_base;
+static void __iomem *sts_base;
 
 static irqreturn_t msm_timer_interrupt(int irq, void *dev_id)
 {
@@ -67,6 +70,11 @@ static int msm_timer_set_next_event(unsigned long cycles,
 
        writel_relaxed(ctrl, event_base + TIMER_CLEAR);
        writel_relaxed(cycles, event_base + TIMER_MATCH_VAL);
+
+       if (sts_base)
+               while (readl_relaxed(sts_base) & TIMER_STS_GPT0_CLR_PEND)
+                       cpu_relax();
+
        writel_relaxed(ctrl | TIMER_ENABLE_EN, event_base + TIMER_ENABLE);
        return 0;
 }
@@ -137,9 +145,6 @@ static int __cpuinit msm_local_timer_setup(struct clock_event_device *evt)
        if (!smp_processor_id())
                return 0;
 
-       writel_relaxed(0, event_base + TIMER_ENABLE);
-       writel_relaxed(0, event_base + TIMER_CLEAR);
-       writel_relaxed(~0, event_base + TIMER_MATCH_VAL);
        evt->irq = msm_clockevent.irq;
        evt->name = "local_timer";
        evt->features = msm_clockevent.features;
@@ -177,9 +182,6 @@ static void __init msm_timer_init(u32 dgt_hz, int sched_bits, int irq,
        struct clocksource *cs = &msm_clocksource;
        int res;
 
-       writel_relaxed(0, event_base + TIMER_ENABLE);
-       writel_relaxed(0, event_base + TIMER_CLEAR);
-       writel_relaxed(~0, event_base + TIMER_MATCH_VAL);
        ce->cpumask = cpumask_of(0);
        ce->irq = irq;
 
@@ -217,13 +219,9 @@ err:
 }
 
 #ifdef CONFIG_OF
-static const struct of_device_id msm_dgt_match[] __initconst = {
-       { .compatible = "qcom,msm-dgt" },
-       { },
-};
-
-static const struct of_device_id msm_gpt_match[] __initconst = {
-       { .compatible = "qcom,msm-gpt" },
+static const struct of_device_id msm_timer_match[] __initconst = {
+       { .compatible = "qcom,kpss-timer" },
+       { .compatible = "qcom,scss-timer" },
        { },
 };
 
@@ -234,33 +232,29 @@ void __init msm_dt_timer_init(void)
        int irq;
        struct resource res;
        u32 percpu_offset;
-       void __iomem *dgt_clk_ctl;
+       void __iomem *base;
+       void __iomem *cpu0_base;
 
-       np = of_find_matching_node(NULL, msm_gpt_match);
+       np = of_find_matching_node(NULL, msm_timer_match);
        if (!np) {
-               pr_err("Can't find GPT DT node\n");
+               pr_err("Can't find msm timer DT node\n");
                return;
        }
 
-       event_base = of_iomap(np, 0);
-       if (!event_base) {
+       base = of_iomap(np, 0);
+       if (!base) {
                pr_err("Failed to map event base\n");
                return;
        }
 
-       irq = irq_of_parse_and_map(np, 0);
+       /* We use GPT0 for the clockevent */
+       irq = irq_of_parse_and_map(np, 1);
        if (irq <= 0) {
                pr_err("Can't get irq\n");
                return;
        }
-       of_node_put(np);
-
-       np = of_find_matching_node(NULL, msm_dgt_match);
-       if (!np) {
-               pr_err("Can't find DGT DT node\n");
-               return;
-       }
 
+       /* We use CPU0's DGT for the clocksource */
        if (of_property_read_u32(np, "cpu-offset", &percpu_offset))
                percpu_offset = 0;
 
@@ -269,45 +263,43 @@ void __init msm_dt_timer_init(void)
                return;
        }
 
-       source_base = ioremap(res.start + percpu_offset, resource_size(&res));
-       if (!source_base) {
+       cpu0_base = ioremap(res.start + percpu_offset, resource_size(&res));
+       if (!cpu0_base) {
                pr_err("Failed to map source base\n");
                return;
        }
 
-       if (!of_address_to_resource(np, 1, &res)) {
-               dgt_clk_ctl = ioremap(res.start + percpu_offset,
-                                     resource_size(&res));
-               if (!dgt_clk_ctl) {
-                       pr_err("Failed to map DGT control base\n");
-                       return;
-               }
-               writel_relaxed(DGT_CLK_CTL_DIV_4, dgt_clk_ctl);
-               iounmap(dgt_clk_ctl);
-       }
-
        if (of_property_read_u32(np, "clock-frequency", &freq)) {
                pr_err("Unknown frequency\n");
                return;
        }
        of_node_put(np);
 
+       event_base = base + 0x4;
+       sts_base = base + 0x88;
+       source_base = cpu0_base + 0x24;
+       freq /= 4;
+       writel_relaxed(DGT_CLK_CTL_DIV_4, source_base + DGT_CLK_CTL);
+
        msm_timer_init(freq, 32, irq, !!percpu_offset);
 }
 #endif
 
-static int __init msm_timer_map(phys_addr_t event, phys_addr_t source)
+static int __init msm_timer_map(phys_addr_t addr, u32 event, u32 source,
+                               u32 sts)
 {
-       event_base = ioremap(event, SZ_64);
-       if (!event_base) {
-               pr_err("Failed to map event base\n");
-               return 1;
-       }
-       source_base = ioremap(source, SZ_64);
-       if (!source_base) {
-               pr_err("Failed to map source base\n");
-               return 1;
+       void __iomem *base;
+
+       base = ioremap(addr, SZ_256);
+       if (!base) {
+               pr_err("Failed to map timer base\n");
+               return -ENOMEM;
        }
+       event_base = base + event;
+       source_base = base + source;
+       if (sts)
+               sts_base = base + sts;
+
        return 0;
 }
 
@@ -315,7 +307,7 @@ void __init msm7x01_timer_init(void)
 {
        struct clocksource *cs = &msm_clocksource;
 
-       if (msm_timer_map(0xc0100000, 0xc0100010))
+       if (msm_timer_map(0xc0100000, 0x0, 0x10, 0x0))
                return;
        cs->read = msm_read_timer_count_shift;
        cs->mask = CLOCKSOURCE_MASK((32 - MSM_DGT_SHIFT));
@@ -326,14 +318,14 @@ void __init msm7x01_timer_init(void)
 
 void __init msm7x30_timer_init(void)
 {
-       if (msm_timer_map(0xc0100004, 0xc0100024))
+       if (msm_timer_map(0xc0100000, 0x4, 0x24, 0x80))
                return;
        msm_timer_init(24576000 / 4, 32, 1, false);
 }
 
 void __init qsd8x50_timer_init(void)
 {
-       if (msm_timer_map(0xAC100000, 0xAC100010))
+       if (msm_timer_map(0xAC100000, 0x0, 0x10, 0x34))
                return;
        msm_timer_init(19200000 / 4, 32, 7, false);
 }