From: "Steven J. Hill" <sjhill@xxxxxxxx> Add new clocksource that uses the counter present on the GIC controller. Signed-off-by: Chris Dearman <chris@xxxxxxxx> Signed-off-by: Steven J. Hill <sjhill@xxxxxxxx> --- arch/mips/Kconfig | 21 ++++++++- arch/mips/include/asm/gic.h | 3 ++ arch/mips/include/asm/time.h | 8 ++-- arch/mips/kernel/Makefile | 1 + arch/mips/kernel/csrc-gic.c | 49 +++++++++++++++++++++ arch/mips/kernel/irq-gic.c | 3 +- arch/mips/mti-malta/malta-time.c | 88 +++++++++++++++++++++++++++----------- 7 files changed, 141 insertions(+), 32 deletions(-) create mode 100644 arch/mips/kernel/csrc-gic.c diff --git a/arch/mips/Kconfig b/arch/mips/Kconfig index fae33f3..3a8d277 100644 --- a/arch/mips/Kconfig +++ b/arch/mips/Kconfig @@ -264,7 +264,6 @@ config MIPS_MALTA select BOOT_ELF32 select BOOT_RAW select CEVT_R4K - select CSRC_R4K select DMA_NONCOHERENT select GENERIC_ISA_DMA select HAVE_PCSPKR_PLATFORM @@ -863,6 +862,24 @@ source "arch/mips/netlogic/Kconfig" endmenu +menu "Clock source" + depends on MIPS_MALTA || MIPS_SEAD3 + +comment "Select one or more precise CPU clock source kernel modules below:" + +config CSRC_R4K + bool "R4K count/compare counter" + default y if !CSRC_GIC + help + Use the R4K count/compare counter for the kernel clock source. + +config CSRC_GIC + bool "GIC global counter (ROC-it or similar system controller)" + help + Use the GIC global counter for the kernel clock source. + +endmenu + config RWSEM_GENERIC_SPINLOCK bool default y @@ -2031,7 +2048,7 @@ config MIPS_APSP_KSPD config MIPS_CMP bool "MIPS CMP framework support" depends on SYS_SUPPORTS_MIPS_CMP - select SYNC_R4K + select SYNC_R4K if CSRC_R4K select SYS_SUPPORTS_SMP select SYS_SUPPORTS_SCHED_SMT if SMP select WEAK_ORDERING diff --git a/arch/mips/include/asm/gic.h b/arch/mips/include/asm/gic.h index 991b659..7583417 100644 --- a/arch/mips/include/asm/gic.h +++ b/arch/mips/include/asm/gic.h @@ -13,6 +13,8 @@ #undef GICISBYTELITTLEENDIAN +extern unsigned long _gic_base; + /* Constants */ #define GIC_POL_POS 1 #define GIC_POL_NEG 0 @@ -345,6 +347,7 @@ extern void gic_init(unsigned long gic_base_addr, unsigned long gic_addrspace_size, struct gic_intr_map *intrmap, unsigned int intrmap_size, unsigned int irqbase); +extern void gic_clocksource_init(unsigned int); extern unsigned int gic_get_int(void); extern void gic_send_ipi(unsigned int intr); extern unsigned int plat_ipi_call_int_xlate(unsigned int); diff --git a/arch/mips/include/asm/time.h b/arch/mips/include/asm/time.h index bc14447..96a6c8c 100644 --- a/arch/mips/include/asm/time.h +++ b/arch/mips/include/asm/time.h @@ -77,11 +77,11 @@ extern int init_r4k_clocksource(void); static inline int init_mips_clocksource(void) { -#ifdef CONFIG_CSRC_R4K - return init_r4k_clocksource(); -#else + extern int gic_present; + + if (!gic_present) + return init_r4k_clocksource(); return 0; -#endif } static inline void clockevent_set_clock(struct clock_event_device *cd, diff --git a/arch/mips/kernel/Makefile b/arch/mips/kernel/Makefile index 0c6877e..1b9af57 100644 --- a/arch/mips/kernel/Makefile +++ b/arch/mips/kernel/Makefile @@ -27,6 +27,7 @@ obj-$(CONFIG_CSRC_IOASIC) += csrc-ioasic.o obj-$(CONFIG_CSRC_POWERTV) += csrc-powertv.o obj-$(CONFIG_CSRC_R4K_LIB) += csrc-r4k.o obj-$(CONFIG_CSRC_SB1250) += csrc-sb1250.o +obj-$(CONFIG_CSRC_GIC) += csrc-gic.o obj-$(CONFIG_SYNC_R4K) += sync-r4k.o obj-$(CONFIG_STACKTRACE) += stacktrace.o diff --git a/arch/mips/kernel/csrc-gic.c b/arch/mips/kernel/csrc-gic.c new file mode 100644 index 0000000..82f09c4 --- /dev/null +++ b/arch/mips/kernel/csrc-gic.c @@ -0,0 +1,49 @@ +/* + * This file is subject to the terms and conditions of the GNU General Public + * License. See the file "COPYING" in the main directory of this archive + * for more details. + * + * Copyright (C) 2011 MIPS Technologies, Inc. + */ +#include <linux/clocksource.h> +#include <linux/init.h> + +#include <asm/time.h> +#include <asm/gic.h> + +static cycle_t gic_hpt_read(struct clocksource *cs) +{ + unsigned int hi, hi2, lo; + + do { + GICREAD(GIC_REG(SHARED, GIC_SH_COUNTER_63_32), hi); + GICREAD(GIC_REG(SHARED, GIC_SH_COUNTER_31_00), lo); + GICREAD(GIC_REG(SHARED, GIC_SH_COUNTER_63_32), hi2); + } while (hi2 != hi); + + return (((cycle_t) hi) << 32) + lo; +} + +static struct clocksource gic_clocksource = { + .name = "GIC", + .read = gic_hpt_read, + .flags = CLOCK_SOURCE_IS_CONTINUOUS, +}; + +void __init gic_clocksource_init(unsigned int frequency) +{ + unsigned int config, bits; + + /* Calculate the clocksource mask. */ + GICREAD(GIC_REG(SHARED, GIC_SH_CONFIG), config); + bits = 32 + ((config & GIC_SH_CONFIG_COUNTBITS_MSK) >> + (GIC_SH_CONFIG_COUNTBITS_SHF - 2)); + + /* Set clocksource mask. */ + gic_clocksource.mask = CLOCKSOURCE_MASK(bits); + + /* Calculate a somewhat reasonable rating value. */ + gic_clocksource.rating = 200 + frequency / 10000000; + + clocksource_register_hz(&gic_clocksource, frequency); +} diff --git a/arch/mips/kernel/irq-gic.c b/arch/mips/kernel/irq-gic.c index 275b163..191a255 100644 --- a/arch/mips/kernel/irq-gic.c +++ b/arch/mips/kernel/irq-gic.c @@ -20,7 +20,8 @@ #include <linux/hardirq.h> #include <asm-generic/bitops/find.h> -static unsigned long _gic_base; + +unsigned long _gic_base; static unsigned int _irqbase; static unsigned int gic_irq_flags[GIC_NUM_INTRS]; #define GIC_IRQ_FLAG_EDGE 0x0001 diff --git a/arch/mips/mti-malta/malta-time.c b/arch/mips/mti-malta/malta-time.c index 115f5bc..c9b2eaa 100644 --- a/arch/mips/mti-malta/malta-time.c +++ b/arch/mips/mti-malta/malta-time.c @@ -39,6 +39,7 @@ #include <asm/time.h> #include <asm/mc146818-time.h> #include <asm/msc01_ic.h> +#include <asm/gic.h> #include <asm/mips-boards/generic.h> #include <asm/mips-boards/prom.h> @@ -50,6 +51,10 @@ unsigned long cpu_khz; static int mips_cpu_timer_irq; static int mips_cpu_perf_irq; extern int cp0_perfcount_irq; +#ifdef CONFIG_CSRC_GIC +static int gic_frequency; +extern int gic_present; +#endif static void mips_timer_dispatch(void) { @@ -61,16 +66,23 @@ static void mips_perf_dispatch(void) do_IRQ(mips_cpu_perf_irq); } +static unsigned int freqround(unsigned int freq, unsigned int amount) +{ + freq += amount; + freq -= freq % (amount*2); + return freq; +} + /* - * Estimate CPU frequency. Sets mips_hpt_frequency as a side-effect + * Estimate CPU (and GIC) frequencies */ -static unsigned int __init estimate_cpu_frequency(void) +static void __init estimate_frequencies(void) { - unsigned int prid = read_c0_prid() & 0xffff00; - unsigned int count; - unsigned long flags; - unsigned int start; + unsigned int count, start; +#ifdef CONFIG_CSRC_GIC + unsigned int giccount = 0, gicstart = 0; +#endif local_irq_save(flags); @@ -80,25 +92,34 @@ static unsigned int __init estimate_cpu_frequency(void) /* Start r4k counter. */ start = read_c0_count(); +#ifdef CONFIG_CSRC_GIC + if (gic_present) + GICREAD(GIC_REG(SHARED, GIC_SH_COUNTER_31_00), gicstart); +#endif /* Read counter exactly on falling edge of update flag */ while (CMOS_READ(RTC_REG_A) & RTC_UIP); while (!(CMOS_READ(RTC_REG_A) & RTC_UIP)); - count = read_c0_count() - start; - + count = read_c0_count(); +#ifdef CONFIG_CSRC_GIC + if (gic_present) + GICREAD(GIC_REG(SHARED, GIC_SH_COUNTER_31_00), giccount); +#endif /* restore interrupts */ local_irq_restore(flags); - mips_hpt_frequency = count; - if ((prid != (PRID_COMP_MIPS | PRID_IMP_20KC)) && - (prid != (PRID_COMP_MIPS | PRID_IMP_25KF))) - count *= 2; - - count += 5000; /* round */ - count -= count%10000; + count -= start; +#ifdef CONFIG_CSRC_GIC + if (gic_present) + giccount -= gicstart; +#endif - return count; + mips_hpt_frequency = count; +#ifdef CONFIG_CSRC_GIC + if (gic_present) + gic_frequency = giccount; +#endif } void read_persistent_clock(struct timespec *ts) @@ -144,22 +165,39 @@ unsigned int __cpuinit get_c0_compare_int(void) void __init plat_time_init(void) { - unsigned int est_freq; - - /* Set Data mode - binary. */ - CMOS_WRITE(CMOS_READ(RTC_CONTROL) | RTC_DM_BINARY, RTC_CONTROL); - - est_freq = estimate_cpu_frequency(); + unsigned int prid = read_c0_prid() & 0xffff00; + unsigned int freq; - printk("CPU frequency %d.%02d MHz\n", est_freq/1000000, - (est_freq%1000000)*100/1000000); + estimate_frequencies(); - cpu_khz = est_freq / 1000; + freq = mips_hpt_frequency; + if ((prid != (PRID_COMP_MIPS | PRID_IMP_20KC)) && + (prid != (PRID_COMP_MIPS | PRID_IMP_25KF))) + freq *= 2; + freq = freqround(freq, 5000); + printk("CPU frequency %d.%02d MHz\n", freq/1000000, + (freq%1000000)*100/1000000); + cpu_khz = freq / 1000; + +#ifdef CONFIG_CSRC_GIC + if (gic_present) { + freq = gic_frequency; + freq = freqround(freq, 5000); + printk("GIC frequency %d.%02d MHz\n", freq/1000000, + (freq%1000000)*100/1000000); + } +#endif mips_scroll_message(); + #ifdef CONFIG_I8253 /* Only Malta has a PIT */ setup_pit_timer(); #endif +#ifdef CONFIG_CSRC_GIC + if (gic_present) + gic_clocksource_init(gic_frequency); +#endif + plat_perf_setup(); } -- 1.7.9.6