MIPS: Netlogic: Use PIC timer as a clocksource

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>
This commit is contained in:
Jayachandran C 2013-01-14 15:11:57 +00:00 committed by John Crispin
parent a69ba6293d
commit 4e45e542cd
6 changed files with 110 additions and 8 deletions

View File

@ -261,6 +261,8 @@
#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);

View File

@ -35,10 +35,11 @@
#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
@ -99,6 +100,7 @@
/* 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 */

View 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;

View File

@ -35,16 +35,68 @@
#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);

View 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, \

View 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;