MIPS: Netlogic: Use PIC timer as a clocksource
authorJayachandran C <jchandra@broadcom.com>
Mon, 14 Jan 2013 15:11:57 +0000 (15:11 +0000)
committerJohn Crispin <blogic@openwrt.org>
Sat, 16 Feb 2013 23:15:20 +0000 (00:15 +0100)
The XLR/XLS/XLP PIC has a 8 countdown timers which run at the PIC
frequencey. One of these can be used as a clocksource to provide
timestamps that is common across cores. This can be used in place
of the count/compare clocksource which is per-CPU.

On XLR/XLS PIC registers are 32-bit, so we just use the lower 32-bits
of the PIC counter. On XLP, the whole 64-bit can be used.

Provide common macros and functions for PIC timer registers on XLR/XLS
and XLP, and use them to register a PIC clocksource.

Signed-off-by: Jayachandran C <jchandra@broadcom.com>
Patchwork: http://patchwork.linux-mips.org/patch/4786/
Signed-off-by: John Crispin <blogic@openwrt.org>
arch/mips/include/asm/netlogic/xlp-hal/pic.h
arch/mips/include/asm/netlogic/xlr/pic.h
arch/mips/netlogic/common/irq.c
arch/mips/netlogic/common/time.c
arch/mips/netlogic/xlr/platform.c
arch/mips/netlogic/xlr/setup.c

index b2e53a5383ab155338f593c241a37081d85feae1..ea6768c3e9f866d74dcb101b3c0c9b6cf0972986 100644 (file)
 #define PIC_LOCAL_SCHEDULING           1
 #define PIC_GLOBAL_SCHEDULING          0
 
+#define PIC_CLK_HZ                     133333333
+
 #define nlm_read_pic_reg(b, r) nlm_read_reg64(b, r)
 #define nlm_write_pic_reg(b, r, v) nlm_write_reg64(b, r, v)
 #define nlm_get_pic_pcibase(node) nlm_pcicfg_base(XLP_IO_PIC_OFFSET(node))
@@ -315,6 +317,12 @@ nlm_pic_read_timer(uint64_t base, int timer)
        return nlm_read_pic_reg(base, PIC_TIMER_COUNT(timer));
 }
 
+static inline uint32_t
+nlm_pic_read_timer32(uint64_t base, int timer)
+{
+       return (uint32_t)nlm_read_pic_reg(base, PIC_TIMER_COUNT(timer));
+}
+
 static inline void
 nlm_pic_write_timer(uint64_t base, int timer, uint64_t value)
 {
@@ -376,9 +384,9 @@ nlm_pic_ack(uint64_t base, int irt_num)
 }
 
 static inline void
-nlm_pic_init_irt(uint64_t base, int irt, int irq, int hwt)
+nlm_pic_init_irt(uint64_t base, int irt, int irq, int hwt, int en)
 {
-       nlm_pic_write_irt_direct(base, irt, 0, 0, 0, irq, hwt);
+       nlm_pic_write_irt_direct(base, irt, en, 0, 0, irq, hwt);
 }
 
 int nlm_irq_to_irt(int irq);
index 9a691b1f91baf7275dfd6282554cd0ec2a30c8d3..effa3377ded5ed093226d9b3d14f3484f32db7da 100644 (file)
 #ifndef _ASM_NLM_XLR_PIC_H
 #define _ASM_NLM_XLR_PIC_H
 
-#define PIC_CLKS_PER_SEC               66666666ULL
+#define PIC_CLK_HZ                     66666666
 /* PIC hardware interrupt numbers */
 #define PIC_IRT_WD_INDEX               0
 #define PIC_IRT_TIMER_0_INDEX          1
+#define PIC_IRT_TIMER_INDEX(i)         ((i) + PIC_IRT_TIMER_0_INDEX)
 #define PIC_IRT_TIMER_1_INDEX          2
 #define PIC_IRT_TIMER_2_INDEX          3
 #define PIC_IRT_TIMER_3_INDEX          4
 
 /* PIC Registers */
 #define PIC_CTRL                       0x00
+#define PIC_CTRL_STE                   8       /* timer enable start bit */
 #define PIC_IPI                                0x04
 #define PIC_INT_ACK                    0x06
 
@@ -251,12 +253,52 @@ nlm_pic_ack(uint64_t base, int irt)
 }
 
 static inline void
-nlm_pic_init_irt(uint64_t base, int irt, int irq, int hwt)
+nlm_pic_init_irt(uint64_t base, int irt, int irq, int hwt, int en)
 {
        nlm_write_reg(base, PIC_IRT_0(irt), (1u << hwt));
        /* local scheduling, invalid, level by default */
        nlm_write_reg(base, PIC_IRT_1(irt),
-               (1 << 30) | (1 << 6) | irq);
+               (en << 30) | (1 << 6) | irq);
+}
+
+static inline uint64_t
+nlm_pic_read_timer(uint64_t base, int timer)
+{
+       uint32_t up1, up2, low;
+
+       up1 = nlm_read_reg(base, PIC_TIMER_COUNT_1(timer));
+       low = nlm_read_reg(base, PIC_TIMER_COUNT_0(timer));
+       up2 = nlm_read_reg(base, PIC_TIMER_COUNT_1(timer));
+
+       if (up1 != up2) /* wrapped, get the new low */
+               low = nlm_read_reg(base, PIC_TIMER_COUNT_0(timer));
+       return ((uint64_t)up2 << 32) | low;
+
+}
+
+static inline uint32_t
+nlm_pic_read_timer32(uint64_t base, int timer)
+{
+       return nlm_read_reg(base, PIC_TIMER_COUNT_0(timer));
+}
+
+static inline void
+nlm_pic_set_timer(uint64_t base, int timer, uint64_t value, int irq, int cpu)
+{
+       uint32_t up, low;
+       uint64_t pic_ctrl = nlm_read_reg(base, PIC_CTRL);
+       int en;
+
+       en = (irq > 0);
+       up = value >> 32;
+       low = value & 0xFFFFFFFF;
+       nlm_write_reg(base, PIC_TIMER_MAXVAL_0(timer), low);
+       nlm_write_reg(base, PIC_TIMER_MAXVAL_1(timer), up);
+       nlm_pic_init_irt(base, PIC_IRT_TIMER_INDEX(timer), irq, cpu, 0);
+
+       /* enable the timer */
+       pic_ctrl |= (1 << (PIC_CTRL_STE + timer));
+       nlm_write_reg(base, PIC_CTRL, pic_ctrl);
 }
 #endif
 #endif /* _ASM_NLM_XLR_PIC_H */
index d42cd1a2a1248156d35736e005f8371b695e3954..642f1e4c27176479752508b91bff900fb225a68c 100644 (file)
@@ -217,7 +217,7 @@ static void nlm_init_node_irqs(int node)
                nlm_setup_pic_irq(node, i, i, irt);
                /* set interrupts to first cpu in node */
                nlm_pic_init_irt(nodep->picbase, irt, i,
-                                       node * NLM_CPUS_PER_NODE);
+                                       node * NLM_CPUS_PER_NODE, 0);
                irqmask |= (1ull << i);
        }
        nodep->irqmask = irqmask;
index bd3e498157ff064248face4992c91e845ce20978..20f89bc0507f0df7b30a20a8e0810ba9752046db 100644 (file)
 #include <linux/init.h>
 
 #include <asm/time.h>
+#include <asm/cpu-features.h>
+
 #include <asm/netlogic/interrupt.h>
 #include <asm/netlogic/common.h>
+#include <asm/netlogic/haldefs.h>
+#include <asm/netlogic/common.h>
+
+#if defined(CONFIG_CPU_XLP)
+#include <asm/netlogic/xlp-hal/iomap.h>
+#include <asm/netlogic/xlp-hal/xlp.h>
+#include <asm/netlogic/xlp-hal/pic.h>
+#elif defined(CONFIG_CPU_XLR)
+#include <asm/netlogic/xlr/iomap.h>
+#include <asm/netlogic/xlr/pic.h>
+#include <asm/netlogic/xlr/xlr.h>
+#else
+#error "Unknown CPU"
+#endif
 
 unsigned int __cpuinit get_c0_compare_int(void)
 {
        return IRQ_TIMER;
 }
 
+static cycle_t nlm_get_pic_timer(struct clocksource *cs)
+{
+       uint64_t picbase = nlm_get_node(0)->picbase;
+
+       return ~nlm_pic_read_timer(picbase, PIC_CLOCK_TIMER);
+}
+
+static cycle_t nlm_get_pic_timer32(struct clocksource *cs)
+{
+       uint64_t picbase = nlm_get_node(0)->picbase;
+
+       return ~nlm_pic_read_timer32(picbase, PIC_CLOCK_TIMER);
+}
+
+static struct clocksource csrc_pic = {
+       .name           = "PIC",
+       .flags          = CLOCK_SOURCE_IS_CONTINUOUS,
+};
+
+static void nlm_init_pic_timer(void)
+{
+       uint64_t picbase = nlm_get_node(0)->picbase;
+
+       nlm_pic_set_timer(picbase, PIC_CLOCK_TIMER, ~0ULL, 0, 0);
+       if (current_cpu_data.cputype == CPU_XLR) {
+               csrc_pic.mask   = CLOCKSOURCE_MASK(32);
+               csrc_pic.read   = nlm_get_pic_timer32;
+       } else {
+               csrc_pic.mask   = CLOCKSOURCE_MASK(64);
+               csrc_pic.read   = nlm_get_pic_timer;
+       }
+       csrc_pic.rating = 1000;
+       clocksource_register_hz(&csrc_pic, PIC_CLK_HZ);
+}
+
 void __init plat_time_init(void)
 {
+       nlm_init_pic_timer();
        mips_hpt_frequency = nlm_get_cpu_frequency();
        pr_info("MIPS counter frequency [%ld]\n",
                        (unsigned long)mips_hpt_frequency);
index 507230eeb7685e9292eb533e7932441db11e92e0..ce838f951356334369ea682246cdd9ddefe65e9f 100644 (file)
@@ -64,7 +64,7 @@ void nlm_xlr_uart_out(struct uart_port *p, int offset, int value)
                .iotype         = UPIO_MEM32,           \
                .flags          = (UPF_SKIP_TEST |      \
                         UPF_FIXED_TYPE | UPF_BOOT_AUTOCONF),\
-               .uartclk        = PIC_CLKS_PER_SEC,     \
+               .uartclk        = PIC_CLK_HZ,           \
                .type           = PORT_16550A,          \
                .serial_in      = nlm_xlr_uart_in,      \
                .serial_out     = nlm_xlr_uart_out,     \
index c5ce6992ac4c7086aea4167a7460723a5d0cb7be..54b301c809e1137f886b62fd8296f1b89533e912 100644 (file)
@@ -70,7 +70,7 @@ static void __init nlm_early_serial_setup(void)
        s.iotype        = UPIO_MEM32;
        s.regshift      = 2;
        s.irq           = PIC_UART_0_IRQ;
-       s.uartclk       = PIC_CLKS_PER_SEC;
+       s.uartclk       = PIC_CLK_HZ;
        s.serial_in     = nlm_xlr_uart_in;
        s.serial_out    = nlm_xlr_uart_out;
        s.mapbase       = uart_base;