diff options
28 files changed, 474 insertions, 227 deletions
diff --git a/Documentation/devicetree/bindings/timer/ezchip,nps400-timer0.txt b/Documentation/devicetree/bindings/timer/ezchip,nps400-timer0.txt new file mode 100644 index 000000000000..e3cfce8fecc5 --- /dev/null +++ b/Documentation/devicetree/bindings/timer/ezchip,nps400-timer0.txt @@ -0,0 +1,17 @@ +NPS Network Processor + +Required properties: + +- compatible : should be "ezchip,nps400-timer0" + +Clocks required for compatible = "ezchip,nps400-timer0": +- interrupts : The interrupt of the first timer +- clocks : Must contain a single entry describing the clock input + +Example: + +timer { + compatible = "ezchip,nps400-timer0"; + interrupts = <3>; + clocks = <&sysclk>; +}; diff --git a/Documentation/devicetree/bindings/timer/ezchip,nps400-timer.txt b/Documentation/devicetree/bindings/timer/ezchip,nps400-timer1.txt index c8c03d700382..c0ab4190b8fb 100644 --- a/Documentation/devicetree/bindings/timer/ezchip,nps400-timer.txt +++ b/Documentation/devicetree/bindings/timer/ezchip,nps400-timer1.txt @@ -2,14 +2,14 @@ NPS Network Processor Required properties: -- compatible : should be "ezchip,nps400-timer" +- compatible : should be "ezchip,nps400-timer1" -Clocks required for compatible = "ezchip,nps400-timer": +Clocks required for compatible = "ezchip,nps400-timer1": - clocks : Must contain a single entry describing the clock input Example: timer { - compatible = "ezchip,nps400-timer"; + compatible = "ezchip,nps400-timer1"; clocks = <&sysclk>; }; diff --git a/MAINTAINERS b/MAINTAINERS index 9d73040b846d..d0d734683bf0 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -11827,6 +11827,7 @@ S: Supported F: arch/arc/ F: Documentation/devicetree/bindings/arc/* F: Documentation/devicetree/bindings/interrupt-controller/snps,arc* +F: drivers/clocksource/arc_timer.c F: drivers/tty/serial/arc_uart.c T: git git://git.kernel.org/pub/scm/linux/kernel/git/vgupta/arc.git diff --git a/arch/arc/Kconfig b/arch/arc/Kconfig index bd204bfa29ed..ab12723d39a0 100644 --- a/arch/arc/Kconfig +++ b/arch/arc/Kconfig @@ -8,9 +8,9 @@ config ARC def_bool y + select ARC_TIMERS select ARCH_SUPPORTS_ATOMIC_RMW if ARC_HAS_LLSC select BUILDTIME_EXTABLE_SORT - select CLKSRC_OF select CLONE_BACKWARDS select COMMON_CLK select GENERIC_ATOMIC64 if !ISA_ARCV2 || !(ARC_HAS_LL64 && ARC_HAS_LLSC) @@ -115,6 +115,7 @@ config ISA_ARCOMPACT config ISA_ARCV2 bool "ARC ISA v2" + select ARC_TIMERS_64BIT help ISA for the Next Generation ARC-HS cores @@ -410,16 +411,6 @@ config ARC_HAS_DIV_REM bool "Insn: div, divu, rem, remu" default y -config ARC_HAS_RTC - bool "Local 64-bit r/o cycle counter" - default n - depends on !SMP - -config ARC_HAS_GFRC - bool "SMP synchronized 64-bit cycle counter" - default y - depends on SMP - config ARC_NUMBER_OF_INTERRUPTS int "Number of interrupts" range 8 240 diff --git a/arch/arc/boot/dts/axs101.dts b/arch/arc/boot/dts/axs101.dts index d9b9b9dcfc4c..70aec7d6ca60 100644 --- a/arch/arc/boot/dts/axs101.dts +++ b/arch/arc/boot/dts/axs101.dts @@ -17,6 +17,6 @@ compatible = "snps,axs101", "snps,arc-sdp"; chosen { - bootargs = "earlycon=uart8250,mmio32,0xe0022000,115200n8 console=tty0 console=ttyS3,115200n8 consoleblank=0"; + bootargs = "earlycon=uart8250,mmio32,0xe0022000,115200n8 console=tty0 console=ttyS3,115200n8 consoleblank=0 video=1280x720@60"; }; }; diff --git a/arch/arc/boot/dts/axs103_idu.dts b/arch/arc/boot/dts/axs103_idu.dts index 070c29782216..5c843d9b4ac8 100644 --- a/arch/arc/boot/dts/axs103_idu.dts +++ b/arch/arc/boot/dts/axs103_idu.dts @@ -20,6 +20,6 @@ compatible = "snps,axs103", "snps,arc-sdp"; chosen { - bootargs = "earlycon=uart8250,mmio32,0xe0022000,115200n8 console=ttyS3,115200n8 debug print-fatal-signals=1"; + bootargs = "earlycon=uart8250,mmio32,0xe0022000,115200n8 console=tty0 console=ttyS3,115200n8 print-fatal-signals=1 consoleblank=0 video=1280x720@60"; }; }; diff --git a/arch/arc/boot/dts/zebu_hs.dts b/arch/arc/boot/dts/haps_hs.dts index 1c1324e84965..1c1324e84965 100644 --- a/arch/arc/boot/dts/zebu_hs.dts +++ b/arch/arc/boot/dts/haps_hs.dts diff --git a/arch/arc/boot/dts/zebu_hs_idu.dts b/arch/arc/boot/dts/haps_hs_idu.dts index 65204b4c0f13..65204b4c0f13 100644 --- a/arch/arc/boot/dts/zebu_hs_idu.dts +++ b/arch/arc/boot/dts/haps_hs_idu.dts diff --git a/arch/arc/configs/axs101_defconfig b/arch/arc/configs/axs101_defconfig index 0a0eaf09aac7..6980b966a364 100644 --- a/arch/arc/configs/axs101_defconfig +++ b/arch/arc/configs/axs101_defconfig @@ -75,9 +75,11 @@ CONFIG_I2C=y CONFIG_I2C_CHARDEV=y CONFIG_I2C_DESIGNWARE_PLATFORM=y # CONFIG_HWMON is not set +CONFIG_DRM=m +CONFIG_DRM_I2C_ADV7511=m +CONFIG_DRM_ARCPGU=m CONFIG_FB=y CONFIG_FRAMEBUFFER_CONSOLE=y -CONFIG_FRAMEBUFFER_CONSOLE_DETECT_PRIMARY=y CONFIG_LOGO=y # CONFIG_LOGO_LINUX_MONO is not set # CONFIG_LOGO_LINUX_VGA16 is not set diff --git a/arch/arc/configs/axs103_smp_defconfig b/arch/arc/configs/axs103_smp_defconfig index 110874705085..30a3d4cf53d2 100644 --- a/arch/arc/configs/axs103_smp_defconfig +++ b/arch/arc/configs/axs103_smp_defconfig @@ -77,9 +77,11 @@ CONFIG_I2C=y CONFIG_I2C_CHARDEV=y CONFIG_I2C_DESIGNWARE_PLATFORM=y # CONFIG_HWMON is not set +CONFIG_DRM=m +CONFIG_DRM_I2C_ADV7511=m +CONFIG_DRM_ARCPGU=m CONFIG_FB=y CONFIG_FRAMEBUFFER_CONSOLE=y -CONFIG_FRAMEBUFFER_CONSOLE_DETECT_PRIMARY=y CONFIG_LOGO=y # CONFIG_LOGO_LINUX_MONO is not set # CONFIG_LOGO_LINUX_VGA16 is not set diff --git a/arch/arc/configs/zebu_hs_defconfig b/arch/arc/configs/haps_hs_defconfig index 9f6166be7145..57b3e599322f 100644 --- a/arch/arc/configs/zebu_hs_defconfig +++ b/arch/arc/configs/haps_hs_defconfig @@ -23,7 +23,7 @@ CONFIG_MODULES=y # CONFIG_IOSCHED_CFQ is not set CONFIG_ARC_PLAT_SIM=y CONFIG_ISA_ARCV2=y -CONFIG_ARC_BUILTIN_DTB_NAME="zebu_hs" +CONFIG_ARC_BUILTIN_DTB_NAME="haps_hs" CONFIG_PREEMPT=y # CONFIG_COMPACTION is not set CONFIG_NET=y diff --git a/arch/arc/configs/zebu_hs_smp_defconfig b/arch/arc/configs/haps_hs_smp_defconfig index 44e9693f4257..f85985adebb2 100644 --- a/arch/arc/configs/zebu_hs_smp_defconfig +++ b/arch/arc/configs/haps_hs_smp_defconfig @@ -26,7 +26,7 @@ CONFIG_MODULES=y CONFIG_ARC_PLAT_SIM=y CONFIG_ISA_ARCV2=y CONFIG_SMP=y -CONFIG_ARC_BUILTIN_DTB_NAME="zebu_hs_idu" +CONFIG_ARC_BUILTIN_DTB_NAME="haps_hs_idu" CONFIG_PREEMPT=y # CONFIG_COMPACTION is not set CONFIG_NET=y diff --git a/arch/arc/configs/nsimosci_hs_smp_defconfig b/arch/arc/configs/nsimosci_hs_smp_defconfig index 6da71ba253a9..155add7761ed 100644 --- a/arch/arc/configs/nsimosci_hs_smp_defconfig +++ b/arch/arc/configs/nsimosci_hs_smp_defconfig @@ -21,7 +21,7 @@ CONFIG_MODULES=y CONFIG_ARC_PLAT_SIM=y CONFIG_ISA_ARCV2=y CONFIG_SMP=y -# CONFIG_ARC_HAS_GFRC is not set +# CONFIG_ARC_TIMERS_64BIT is not set CONFIG_ARC_BUILTIN_DTB_NAME="nsimosci_hs_idu" CONFIG_PREEMPT=y # CONFIG_COMPACTION is not set diff --git a/arch/arc/configs/vdk_hs38_smp_defconfig b/arch/arc/configs/vdk_hs38_smp_defconfig index 969b206d6c67..573028f19de7 100644 --- a/arch/arc/configs/vdk_hs38_smp_defconfig +++ b/arch/arc/configs/vdk_hs38_smp_defconfig @@ -15,7 +15,7 @@ CONFIG_ARC_PLAT_AXS10X=y CONFIG_AXS103=y CONFIG_ISA_ARCV2=y CONFIG_SMP=y -# CONFIG_ARC_HAS_GFRC is not set +# CONFIG_ARC_TIMERS_64BIT is not set CONFIG_ARC_UBOOT_SUPPORT=y CONFIG_ARC_BUILTIN_DTB_NAME="vdk_hs38_smp" CONFIG_PREEMPT=y diff --git a/arch/arc/include/asm/arcregs.h b/arch/arc/include/asm/arcregs.h index 1bd24ec3e350..da41a54ea2d7 100644 --- a/arch/arc/include/asm/arcregs.h +++ b/arch/arc/include/asm/arcregs.h @@ -20,7 +20,6 @@ #define ARC_REG_FP_V2_BCR 0xc8 /* ARCv2 FPU */ #define ARC_REG_SLC_BCR 0xce #define ARC_REG_DCCM_BUILD 0x74 /* DCCM size (common) */ -#define ARC_REG_TIMERS_BCR 0x75 #define ARC_REG_AP_BCR 0x76 #define ARC_REG_ICCM_BUILD 0x78 /* ICCM size (common) */ #define ARC_REG_XY_MEM_BCR 0x79 @@ -112,90 +111,7 @@ #ifndef __ASSEMBLY__ -/* - ****************************************************************** - * Inline ASM macros to read/write AUX Regs - * Essentially invocation of lr/sr insns from "C" - */ - -#if 1 - -#define read_aux_reg(reg) __builtin_arc_lr(reg) - -/* gcc builtin sr needs reg param to be long immediate */ -#define write_aux_reg(reg_immed, val) \ - __builtin_arc_sr((unsigned int)(val), reg_immed) - -#else - -#define read_aux_reg(reg) \ -({ \ - unsigned int __ret; \ - __asm__ __volatile__( \ - " lr %0, [%1]" \ - : "=r"(__ret) \ - : "i"(reg)); \ - __ret; \ -}) - -/* - * Aux Reg address is specified as long immediate by caller - * e.g. - * write_aux_reg(0x69, some_val); - * This generates tightest code. - */ -#define write_aux_reg(reg_imm, val) \ -({ \ - __asm__ __volatile__( \ - " sr %0, [%1] \n" \ - : \ - : "ir"(val), "i"(reg_imm)); \ -}) - -/* - * Aux Reg address is specified in a variable - * * e.g. - * reg_num = 0x69 - * write_aux_reg2(reg_num, some_val); - * This has to generate glue code to load the reg num from - * memory to a reg hence not recommended. - */ -#define write_aux_reg2(reg_in_var, val) \ -({ \ - unsigned int tmp; \ - \ - __asm__ __volatile__( \ - " ld %0, [%2] \n\t" \ - " sr %1, [%0] \n\t" \ - : "=&r"(tmp) \ - : "r"(val), "memory"(®_in_var)); \ -}) - -#endif - -#define READ_BCR(reg, into) \ -{ \ - unsigned int tmp; \ - tmp = read_aux_reg(reg); \ - if (sizeof(tmp) == sizeof(into)) { \ - into = *((typeof(into) *)&tmp); \ - } else { \ - extern void bogus_undefined(void); \ - bogus_undefined(); \ - } \ -} - -#define WRITE_AUX(reg, into) \ -{ \ - unsigned int tmp; \ - if (sizeof(tmp) == sizeof(into)) { \ - tmp = (*(unsigned int *)&(into)); \ - write_aux_reg(reg, tmp); \ - } else { \ - extern void bogus_undefined(void); \ - bogus_undefined(); \ - } \ -} +#include <soc/arc/aux.h> /* Helpers */ #define TO_KB(bytes) ((bytes) >> 10) @@ -291,13 +207,7 @@ struct bcr_fp_arcv2 { #endif }; -struct bcr_timer { -#ifdef CONFIG_CPU_BIG_ENDIAN - unsigned int pad2:15, rtsc:1, pad1:5, rtc:1, t1:1, t0:1, ver:8; -#else - unsigned int ver:8, t0:1, t1:1, rtc:1, pad1:5, rtsc:1, pad2:15; -#endif -}; +#include <soc/arc/timers.h> struct bcr_bpu_arcompact { #ifdef CONFIG_CPU_BIG_ENDIAN diff --git a/arch/arc/kernel/Makefile b/arch/arc/kernel/Makefile index cfcdedf52ff8..8942c5c3b4c5 100644 --- a/arch/arc/kernel/Makefile +++ b/arch/arc/kernel/Makefile @@ -8,7 +8,7 @@ # Pass UTS_MACHINE for user_regset definition CFLAGS_ptrace.o += -DUTS_MACHINE='"$(UTS_MACHINE)"' -obj-y := arcksyms.o setup.o irq.o time.o reset.o ptrace.o process.o devtree.o +obj-y := arcksyms.o setup.o irq.o reset.o ptrace.o process.o devtree.o obj-y += signal.o traps.o sys.o troubleshoot.o stacktrace.o disasm.o obj-$(CONFIG_ISA_ARCOMPACT) += entry-compact.o intc-compact.o obj-$(CONFIG_ISA_ARCV2) += entry-arcv2.o intc-arcv2.o diff --git a/arch/arc/kernel/mcip.c b/arch/arc/kernel/mcip.c index f39142acc89e..560c4afc2af4 100644 --- a/arch/arc/kernel/mcip.c +++ b/arch/arc/kernel/mcip.c @@ -11,8 +11,8 @@ #include <linux/smp.h> #include <linux/irq.h> #include <linux/spinlock.h> +#include <soc/arc/mcip.h> #include <asm/irqflags-arcv2.h> -#include <asm/mcip.h> #include <asm/setup.h> static DEFINE_RAW_SPINLOCK(mcip_lock); diff --git a/arch/arc/kernel/setup.c b/arch/arc/kernel/setup.c index 0385df77a697..3093fa898a23 100644 --- a/arch/arc/kernel/setup.c +++ b/arch/arc/kernel/setup.c @@ -10,6 +10,8 @@ #include <linux/fs.h> #include <linux/delay.h> #include <linux/root_dev.h> +#include <linux/clk-provider.h> +#include <linux/clocksource.h> #include <linux/console.h> #include <linux/module.h> #include <linux/cpu.h> @@ -234,11 +236,11 @@ static char *arc_cpu_mumbojumbo(int cpu_id, char *buf, int len) is_isa_arcompact() ? "ARCompact" : "ARCv2", IS_AVAIL1(cpu->isa.be, "[Big-Endian]")); - n += scnprintf(buf + n, len - n, "Timers\t\t: %s%s%s%s\nISA Extn\t: ", + n += scnprintf(buf + n, len - n, "Timers\t\t: %s%s%s%s%s%s\nISA Extn\t: ", IS_AVAIL1(cpu->extn.timer0, "Timer0 "), IS_AVAIL1(cpu->extn.timer1, "Timer1 "), - IS_AVAIL2(cpu->extn.rtc, "Local-64-bit-Ctr ", - CONFIG_ARC_HAS_RTC)); + IS_AVAIL2(cpu->extn.rtc, "RTC [UP 64-bit] ", CONFIG_ARC_TIMERS_64BIT), + IS_AVAIL2(cpu->extn.gfrc, "GFRC [SMP 64-bit] ", CONFIG_ARC_TIMERS_64BIT)); n += i = scnprintf(buf + n, len - n, "%s%s%s%s%s", IS_AVAIL2(cpu->isa.atomic, "atomic ", CONFIG_ARC_HAS_LLSC), @@ -449,6 +451,15 @@ void __init setup_arch(char **cmdline_p) arc_unwind_init(); } +/* + * Called from start_kernel() - boot CPU only + */ +void __init time_init(void) +{ + of_clk_init(NULL); + clocksource_probe(); +} + static int __init customize_machine(void) { if (machine_desc->init_machine) diff --git a/arch/arc/plat-axs10x/axs10x.c b/arch/arc/plat-axs10x/axs10x.c index 86548701023c..38ff349d7f2a 100644 --- a/arch/arc/plat-axs10x/axs10x.c +++ b/arch/arc/plat-axs10x/axs10x.c @@ -21,7 +21,7 @@ #include <asm/asm-offsets.h> #include <asm/io.h> #include <asm/mach_desc.h> -#include <asm/mcip.h> +#include <soc/arc/mcip.h> #define AXS_MB_CGU 0xE0010000 #define AXS_MB_CREG 0xE0011000 diff --git a/arch/arc/plat-eznps/include/plat/ctop.h b/arch/arc/plat-eznps/include/plat/ctop.h index 9d6718c1a199..ee2e32df5e90 100644 --- a/arch/arc/plat-eznps/include/plat/ctop.h +++ b/arch/arc/plat-eznps/include/plat/ctop.h @@ -46,9 +46,7 @@ #define CTOP_AUX_UDMC (CTOP_AUX_BASE + 0x300) /* EZchip core instructions */ -#define CTOP_INST_HWSCHD_OFF_R3 0x3B6F00BF #define CTOP_INST_HWSCHD_OFF_R4 0x3C6F00BF -#define CTOP_INST_HWSCHD_RESTORE_R3 0x3E6F70C3 #define CTOP_INST_HWSCHD_RESTORE_R4 0x3E6F7103 #define CTOP_INST_SCHD_RW 0x3E6F7004 #define CTOP_INST_SCHD_RD 0x3E6F7084 diff --git a/drivers/clocksource/Kconfig b/drivers/clocksource/Kconfig index e2c6e43cf8ca..4866f7aa32e6 100644 --- a/drivers/clocksource/Kconfig +++ b/drivers/clocksource/Kconfig @@ -282,6 +282,26 @@ config CLKSRC_MPS2 select CLKSRC_MMIO select CLKSRC_OF +config ARC_TIMERS + bool "Support for 32-bit TIMERn counters in ARC Cores" if COMPILE_TEST + depends on GENERIC_CLOCKEVENTS + select CLKSRC_OF + help + These are legacy 32-bit TIMER0 and TIMER1 counters found on all ARC cores + (ARC700 as well as ARC HS38). + TIMER0 serves as clockevent while TIMER1 provides clocksource + +config ARC_TIMERS_64BIT + bool "Support for 64-bit counters in ARC HS38 cores" if COMPILE_TEST + depends on GENERIC_CLOCKEVENTS + depends on ARC_TIMERS + select CLKSRC_OF + help + This enables 2 different 64-bit timers: RTC (for UP) and GFRC (for SMP) + RTC is implemented inside the core, while GFRC sits outside the core in + ARConnect IP block. Driver automatically picks one of them for clocksource + as appropriate. + config ARM_ARCH_TIMER bool select CLKSRC_OF if OF diff --git a/drivers/clocksource/Makefile b/drivers/clocksource/Makefile index cf87f407f1ad..a14111e1f087 100644 --- a/drivers/clocksource/Makefile +++ b/drivers/clocksource/Makefile @@ -51,6 +51,7 @@ obj-$(CONFIG_CLKSRC_TI_32K) += timer-ti-32k.o obj-$(CONFIG_CLKSRC_NPS) += timer-nps.o obj-$(CONFIG_OXNAS_RPS_TIMER) += timer-oxnas-rps.o +obj-$(CONFIG_ARC_TIMERS) += arc_timer.o obj-$(CONFIG_ARM_ARCH_TIMER) += arm_arch_timer.o obj-$(CONFIG_ARM_GLOBAL_TIMER) += arm_global_timer.o obj-$(CONFIG_ARMV7M_SYSTICK) += armv7m_systick.o diff --git a/arch/arc/kernel/time.c b/drivers/clocksource/arc_timer.c index c10390d1ddb6..a49748d826c0 100644 --- a/arch/arc/kernel/time.c +++ b/drivers/clocksource/arc_timer.c @@ -1,32 +1,18 @@ /* + * Copyright (C) 2016-17 Synopsys, Inc. (www.synopsys.com) * Copyright (C) 2004, 2007-2010, 2011-2012 Synopsys, Inc. (www.synopsys.com) * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 as * published by the Free Software Foundation. - * - * vineetg: Jan 1011 - * -sched_clock( ) no longer jiffies based. Uses the same clocksource - * as gtod - * - * Rajeshwarr/Vineetg: Mar 2008 - * -Implemented CONFIG_GENERIC_TIME (rather deleted arch specific code) - * for arch independent gettimeofday() - * -Implemented CONFIG_GENERIC_CLOCKEVENTS as base for hrtimers - * - * Vineetg: Mar 2008: Forked off from time.c which now is time-jiff.c */ -/* ARC700 has two 32bit independent prog Timers: TIMER0 and TIMER1 - * Each can programmed to go from @count to @limit and optionally - * interrupt when that happens. - * A write to Control Register clears the Interrupt +/* ARC700 has two 32bit independent prog Timers: TIMER0 and TIMER1, Each can be + * programmed to go from @count to @limit and optionally interrupt. + * We've designated TIMER0 for clockevents and TIMER1 for clocksource * - * We've designated TIMER0 for events (clockevents) - * while TIMER1 for free running (clocksource) - * - * Newer ARC700 cores have 64bit clk fetching RTSC insn, preferred over TIMER1 - * which however is currently broken + * ARCv2 based HS38 cores have RTC (in-core) and GFRC (inside ARConnect/MCIP) + * which are suitable for UP and SMP based clocksources respectively */ #include <linux/interrupt.h> @@ -37,23 +23,10 @@ #include <linux/cpu.h> #include <linux/of.h> #include <linux/of_irq.h> -#include <asm/irq.h> -#include <asm/arcregs.h> - -#include <asm/mcip.h> -/* Timer related Aux registers */ -#define ARC_REG_TIMER0_LIMIT 0x23 /* timer 0 limit */ -#define ARC_REG_TIMER0_CTRL 0x22 /* timer 0 control */ -#define ARC_REG_TIMER0_CNT 0x21 /* timer 0 count */ -#define ARC_REG_TIMER1_LIMIT 0x102 /* timer 1 limit */ -#define ARC_REG_TIMER1_CTRL 0x101 /* timer 1 control */ -#define ARC_REG_TIMER1_CNT 0x100 /* timer 1 count */ +#include <soc/arc/timers.h> +#include <soc/arc/mcip.h> -#define TIMER_CTRL_IE (1 << 0) /* Interrupt when Count reaches limit */ -#define TIMER_CTRL_NH (1 << 1) /* Count only when CPU NOT halted */ - -#define ARC_TIMER_MAX 0xFFFFFFFF static unsigned long arc_timer_freq; @@ -81,31 +54,24 @@ static int noinline arc_get_timer_clk(struct device_node *node) /********** Clock Source Device *********/ -#ifdef CONFIG_ARC_HAS_GFRC +#ifdef CONFIG_ARC_TIMERS_64BIT static cycle_t arc_read_gfrc(struct clocksource *cs) { unsigned long flags; - union { -#ifdef CONFIG_CPU_BIG_ENDIAN - struct { u32 h, l; }; -#else - struct { u32 l, h; }; -#endif - cycle_t full; - } stamp; + u32 l, h; local_irq_save(flags); __mcip_cmd(CMD_GFRC_READ_LO, 0); - stamp.l = read_aux_reg(ARC_REG_MCIP_READBACK); + l = read_aux_reg(ARC_REG_MCIP_READBACK); __mcip_cmd(CMD_GFRC_READ_HI, 0); - stamp.h = read_aux_reg(ARC_REG_MCIP_READBACK); + h = read_aux_reg(ARC_REG_MCIP_READBACK); local_irq_restore(flags); - return stamp.full; + return (((cycle_t)h) << 32) | l; } static struct clocksource arc_counter_gfrc = { @@ -118,11 +84,14 @@ static struct clocksource arc_counter_gfrc = { static int __init arc_cs_setup_gfrc(struct device_node *node) { - int exists = cpuinfo_arc700[0].extn.gfrc; + struct mcip_bcr mp; int ret; - if (WARN(!exists, "Global-64-bit-Ctr clocksource not detected")) + READ_BCR(ARC_REG_MCIP_BCR, mp); + if (!mp.gfrc) { + pr_warn("Global-64-bit-Ctr clocksource not detected"); return -ENXIO; + } ret = arc_get_timer_clk(node); if (ret) @@ -132,10 +101,6 @@ static int __init arc_cs_setup_gfrc(struct device_node *node) } CLOCKSOURCE_OF_DECLARE(arc_gfrc, "snps,archs-timer-gfrc", arc_cs_setup_gfrc); -#endif - -#ifdef CONFIG_ARC_HAS_RTC - #define AUX_RTC_CTRL 0x103 #define AUX_RTC_LOW 0x104 #define AUX_RTC_HIGH 0x105 @@ -143,14 +108,7 @@ CLOCKSOURCE_OF_DECLARE(arc_gfrc, "snps,archs-timer-gfrc", arc_cs_setup_gfrc); static cycle_t arc_read_rtc(struct clocksource *cs) { unsigned long status; - union { -#ifdef CONFIG_CPU_BIG_ENDIAN - struct { u32 high, low; }; -#else - struct { u32 low, high; }; -#endif - cycle_t full; - } stamp; + u32 l, h; /* * hardware has an internal state machine which tracks readout of @@ -159,12 +117,12 @@ static cycle_t arc_read_rtc(struct clocksource *cs) * - high increments after low has been read */ do { - stamp.low = read_aux_reg(AUX_RTC_LOW); - stamp.high = read_aux_reg(AUX_RTC_HIGH); + l = read_aux_reg(AUX_RTC_LOW); + h = read_aux_reg(AUX_RTC_HIGH); status = read_aux_reg(AUX_RTC_CTRL); } while (!(status & _BITUL(31))); - return stamp.full; + return (((cycle_t)h) << 32) | l; } static struct clocksource arc_counter_rtc = { @@ -177,15 +135,20 @@ static struct clocksource arc_counter_rtc = { static int __init arc_cs_setup_rtc(struct device_node *node) { - int exists = cpuinfo_arc700[smp_processor_id()].extn.rtc; + struct bcr_timer timer; int ret; - if (WARN(!exists, "Local-64-bit-Ctr clocksource not detected")) + READ_BCR(ARC_REG_TIMERS_BCR, timer); + if (!timer.rtc) { + pr_warn("Local-64-bit-Ctr clocksource not detected"); return -ENXIO; + } /* Local to CPU hence not usable in SMP */ - if (WARN(IS_ENABLED(CONFIG_SMP), "Local-64-bit-Ctr not usable in SMP")) + if (IS_ENABLED(CONFIG_SMP)) { + pr_warn("Local-64-bit-Ctr not usable in SMP"); return -EINVAL; + } ret = arc_get_timer_clk(node); if (ret) @@ -228,7 +191,7 @@ static int __init arc_cs_setup_timer1(struct device_node *node) if (ret) return ret; - write_aux_reg(ARC_REG_TIMER1_LIMIT, ARC_TIMER_MAX); + write_aux_reg(ARC_REG_TIMER1_LIMIT, ARC_TIMERN_MAX); write_aux_reg(ARC_REG_TIMER1_CNT, 0); write_aux_reg(ARC_REG_TIMER1_CTRL, TIMER_CTRL_NH); @@ -306,7 +269,7 @@ static int arc_timer_starting_cpu(unsigned int cpu) evt->cpumask = cpumask_of(smp_processor_id()); - clockevents_config_and_register(evt, arc_timer_freq, 0, ARC_TIMER_MAX); + clockevents_config_and_register(evt, arc_timer_freq, 0, ARC_TIMERN_MAX); enable_percpu_irq(arc_timer_irq, 0); return 0; } @@ -371,12 +334,3 @@ static int __init arc_of_timer_init(struct device_node *np) return ret; } CLOCKSOURCE_OF_DECLARE(arc_clkevt, "snps,arc-timer", arc_of_timer_init); - -/* - * Called from start_kernel() - boot CPU only - */ -void __init time_init(void) -{ - of_clk_init(NULL); - clocksource_probe(); -} diff --git a/drivers/clocksource/timer-nps.c b/drivers/clocksource/timer-nps.c index 70c149af8ee0..8da5e93b6810 100644 --- a/drivers/clocksource/timer-nps.c +++ b/drivers/clocksource/timer-nps.c @@ -46,7 +46,36 @@ /* This array is per cluster of CPUs (Each NPS400 cluster got 256 CPUs) */ static void *nps_msu_reg_low_addr[NPS_CLUSTER_NUM] __read_mostly; -static unsigned long nps_timer_rate; +static int __init nps_get_timer_clk(struct device_node *node, + unsigned long *timer_freq, + struct clk **clk) +{ + int ret; + + *clk = of_clk_get(node, 0); + ret = PTR_ERR_OR_ZERO(*clk); + if (ret) { + pr_err("timer missing clk"); + return ret; + } + + ret = clk_prepare_enable(*clk); + if (ret) { + pr_err("Couldn't enable parent clk\n"); + clk_put(*clk); + return ret; + } + + *timer_freq = clk_get_rate(*clk); + if (!(*timer_freq)) { + pr_err("Couldn't get clk rate\n"); + clk_disable_unprepare(*clk); + clk_put(*clk); + return -EINVAL; + } + + return 0; +} static cycle_t nps_clksrc_read(struct clocksource *clksrc) { @@ -55,26 +84,24 @@ static cycle_t nps_clksrc_read(struct clocksource *clksrc) return (cycle_t)ioread32be(nps_msu_reg_low_addr[cluster]); } -static int __init nps_setup_clocksource(struct device_node *node, - struct clk *clk) +static int __init nps_setup_clocksource(struct device_node *node) { int ret, cluster; + struct clk *clk; + unsigned long nps_timer1_freq; + for (cluster = 0; cluster < NPS_CLUSTER_NUM; cluster++) nps_msu_reg_low_addr[cluster] = nps_host_reg((cluster << NPS_CLUSTER_OFFSET), - NPS_MSU_BLKID, NPS_MSU_TICK_LOW); + NPS_MSU_BLKID, NPS_MSU_TICK_LOW); - ret = clk_prepare_enable(clk); - if (ret) { - pr_err("Couldn't enable parent clock\n"); + ret = nps_get_timer_clk(node, &nps_timer1_freq, &clk); + if (ret) return ret; - } - - nps_timer_rate = clk_get_rate(clk); - ret = clocksource_mmio_init(nps_msu_reg_low_addr, "EZnps-tick", - nps_timer_rate, 301, 32, nps_clksrc_read); + ret = clocksource_mmio_init(nps_msu_reg_low_addr, "nps-tick", + nps_timer1_freq, 300, 32, nps_clksrc_read); if (ret) { pr_err("Couldn't register clock source.\n"); clk_disable_unprepare(clk); @@ -83,18 +110,175 @@ static int __init nps_setup_clocksource(struct device_node *node, return ret; } -static int __init nps_timer_init(struct device_node *node) +CLOCKSOURCE_OF_DECLARE(ezchip_nps400_clksrc, "ezchip,nps400-timer", + nps_setup_clocksource); +CLOCKSOURCE_OF_DECLARE(ezchip_nps400_clk_src, "ezchip,nps400-timer1", + nps_setup_clocksource); + +#ifdef CONFIG_EZNPS_MTM_EXT +#include <soc/nps/mtm.h> + +/* Timer related Aux registers */ +#define NPS_REG_TIMER0_TSI 0xFFFFF850 +#define NPS_REG_TIMER0_LIMIT 0x23 +#define NPS_REG_TIMER0_CTRL 0x22 +#define NPS_REG_TIMER0_CNT 0x21 + +/* + * Interrupt Enabled (IE) - re-arm the timer + * Not Halted (NH) - is cleared when working with JTAG (for debug) + */ +#define TIMER0_CTRL_IE BIT(0) +#define TIMER0_CTRL_NH BIT(1) + +static unsigned long nps_timer0_freq; +static unsigned long nps_timer0_irq; + +static void nps_clkevent_rm_thread(void) +{ + int thread; + unsigned int cflags, enabled_threads; + + hw_schd_save(&cflags); + + enabled_threads = read_aux_reg(NPS_REG_TIMER0_TSI); + + /* remove thread from TSI1 */ + thread = read_aux_reg(CTOP_AUX_THREAD_ID); + enabled_threads &= ~(1 << thread); + write_aux_reg(NPS_REG_TIMER0_TSI, enabled_threads); + + /* Acknowledge and if needed re-arm the timer */ + if (!enabled_threads) + write_aux_reg(NPS_REG_TIMER0_CTRL, TIMER0_CTRL_NH); + else + write_aux_reg(NPS_REG_TIMER0_CTRL, + TIMER0_CTRL_IE | TIMER0_CTRL_NH); + + hw_schd_restore(cflags); +} + +static void nps_clkevent_add_thread(unsigned long delta) +{ + int thread; + unsigned int cflags, enabled_threads; + + hw_schd_save(&cflags); + + /* add thread to TSI1 */ + thread = read_aux_reg(CTOP_AUX_THREAD_ID); + enabled_threads = read_aux_reg(NPS_REG_TIMER0_TSI); + enabled_threads |= (1 << thread); + write_aux_reg(NPS_REG_TIMER0_TSI, enabled_threads); + + /* set next timer event */ + write_aux_reg(NPS_REG_TIMER0_LIMIT, delta); + write_aux_reg(NPS_REG_TIMER0_CNT, 0); + write_aux_reg(NPS_REG_TIMER0_CTRL, + TIMER0_CTRL_IE | TIMER0_CTRL_NH); + + hw_schd_restore(cflags); +} + +/* + * Whenever anyone tries to change modes, we just mask interrupts + * and wait for the next event to get set. + */ +static int nps_clkevent_set_state(struct clock_event_device *dev) +{ + nps_clkevent_rm_thread(); + disable_percpu_irq(nps_timer0_irq); + + return 0; +} + +static int nps_clkevent_set_next_event(unsigned long delta, + struct clock_event_device *dev) +{ + nps_clkevent_add_thread(delta); + enable_percpu_irq(nps_timer0_irq, IRQ_TYPE_NONE); + + return 0; +} + +static DEFINE_PER_CPU(struct clock_event_device, nps_clockevent_device) = { + .name = "NPS Timer0", + .features = CLOCK_EVT_FEAT_ONESHOT, + .rating = 300, + .set_next_event = nps_clkevent_set_next_event, + .set_state_oneshot = nps_clkevent_set_state, + .set_state_oneshot_stopped = nps_clkevent_set_state, + .set_state_shutdown = nps_clkevent_set_state, + .tick_resume = nps_clkevent_set_state, +}; + +static irqreturn_t timer_irq_handler(int irq, void *dev_id) +{ + struct clock_event_device *evt = dev_id; + + nps_clkevent_rm_thread(); + evt->event_handler(evt); + + return IRQ_HANDLED; +} + +static int nps_timer_starting_cpu(unsigned int cpu) +{ + struct clock_event_device *evt = this_cpu_ptr(&nps_clockevent_device); + + evt->cpumask = cpumask_of(smp_processor_id()); + + clockevents_config_and_register(evt, nps_timer0_freq, 0, ULONG_MAX); + enable_percpu_irq(nps_timer0_irq, IRQ_TYPE_NONE); + + return 0; +} + +static int nps_timer_dying_cpu(unsigned int cpu) +{ + disable_percpu_irq(nps_timer0_irq); + return 0; +} + +static int __init nps_setup_clockevent(struct device_node *node) { struct clk *clk; + int ret; - clk = of_clk_get(node, 0); - if (IS_ERR(clk)) { - pr_err("Can't get timer clock.\n"); - return PTR_ERR(clk); + nps_timer0_irq = irq_of_parse_and_map(node, 0); + if (nps_timer0_irq <= 0) { + pr_err("clockevent: missing irq"); + return -EINVAL; } - return nps_setup_clocksource(node, clk); + ret = nps_get_timer_clk(node, &nps_timer0_freq, &clk); + if (ret) + return ret; + + /* Needs apriori irq_set_percpu_devid() done in intc map function */ + ret = request_percpu_irq(nps_timer0_irq, timer_irq_handler, + "Timer0 (per-cpu-tick)", + &nps_clockevent_device); + if (ret) { + pr_err("Couldn't request irq\n"); + clk_disable_unprepare(clk); + return ret; + } + + ret = cpuhp_setup_state(CPUHP_AP_ARC_TIMER_STARTING, + "clockevents/nps:starting", + nps_timer_starting_cpu, + nps_timer_dying_cpu); + if (ret) { + pr_err("Failed to setup hotplug state"); + clk_disable_unprepare(clk); + free_percpu_irq(nps_timer0_irq, &nps_clockevent_device); + return ret; + } + + return 0; } -CLOCKSOURCE_OF_DECLARE(ezchip_nps400_clksrc, "ezchip,nps400-timer", - nps_timer_init); +CLOCKSOURCE_OF_DECLARE(ezchip_nps400_clk_evt, "ezchip,nps400-timer0", + nps_setup_clockevent); +#endif /* CONFIG_EZNPS_MTM_EXT */ diff --git a/include/soc/arc/aux.h b/include/soc/arc/aux.h new file mode 100644 index 000000000000..8c3fb13e0452 --- /dev/null +++ b/include/soc/arc/aux.h @@ -0,0 +1,63 @@ +/* + * Copyright (C) 2016-2017 Synopsys, Inc. (www.synopsys.com) + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + */ + +#ifndef __SOC_ARC_AUX_H__ +#define __SOC_ARC_AUX_H__ + +#ifdef CONFIG_ARC + +#define read_aux_reg(r) __builtin_arc_lr(r) + +/* gcc builtin sr needs reg param to be long immediate */ +#define write_aux_reg(r, v) __builtin_arc_sr((unsigned int)(v), r) + +#else /* !CONFIG_ARC */ + +static inline int read_aux_reg(u32 r) +{ + return 0; +} + +/* + * function helps elide unused variable warning + * see: http://lists.infradead.org/pipermail/linux-snps-arc/2016-November/001748.html + */ +static inline void write_aux_reg(u32 r, u32 v) +{ + ; +} + +#endif + +#define READ_BCR(reg, into) \ +{ \ + unsigned int tmp; \ + tmp = read_aux_reg(reg); \ + if (sizeof(tmp) == sizeof(into)) { \ + into = *((typeof(into) *)&tmp); \ + } else { \ + extern void bogus_undefined(void); \ + bogus_undefined(); \ + } \ +} + +#define WRITE_AUX(reg, into) \ +{ \ + unsigned int tmp; \ + if (sizeof(tmp) == sizeof(into)) { \ + tmp = (*(unsigned int *)&(into)); \ + write_aux_reg(reg, tmp); \ + } else { \ + extern void bogus_undefined(void); \ + bogus_undefined(); \ + } \ +} + + +#endif diff --git a/arch/arc/include/asm/mcip.h b/include/soc/arc/mcip.h index c8fbe4114bad..6902c2a8bd23 100644 --- a/arch/arc/include/asm/mcip.h +++ b/include/soc/arc/mcip.h @@ -8,12 +8,10 @@ * published by the Free Software Foundation. */ -#ifndef __ASM_MCIP_H -#define __ASM_MCIP_H +#ifndef __SOC_ARC_MCIP_H +#define __SOC_ARC_MCIP_H -#ifdef CONFIG_ISA_ARCV2 - -#include <asm/arcregs.h> +#include <soc/arc/aux.h> #define ARC_REG_MCIP_BCR 0x0d0 #define ARC_REG_MCIP_CMD 0x600 @@ -103,5 +101,3 @@ static inline void __mcip_cmd_data(unsigned int cmd, unsigned int param, } #endif - -#endif diff --git a/include/soc/arc/timers.h b/include/soc/arc/timers.h new file mode 100644 index 000000000000..a20ed2fbc432 --- /dev/null +++ b/include/soc/arc/timers.h @@ -0,0 +1,38 @@ +/* + * Copyright (C) 2016-17 Synopsys, Inc. (www.synopsys.com) + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + */ + +#ifndef __SOC_ARC_TIMERS_H +#define __SOC_ARC_TIMERS_H + +#include <soc/arc/aux.h> + +/* Timer related Aux registers */ +#define ARC_REG_TIMER0_LIMIT 0x23 /* timer 0 limit */ +#define ARC_REG_TIMER0_CTRL 0x22 /* timer 0 control */ +#define ARC_REG_TIMER0_CNT 0x21 /* timer 0 count */ +#define ARC_REG_TIMER1_LIMIT 0x102 /* timer 1 limit */ +#define ARC_REG_TIMER1_CTRL 0x101 /* timer 1 control */ +#define ARC_REG_TIMER1_CNT 0x100 /* timer 1 count */ + +/* CTRL reg bits */ +#define TIMER_CTRL_IE (1 << 0) /* Interrupt when Count reaches limit */ +#define TIMER_CTRL_NH (1 << 1) /* Count only when CPU NOT halted */ + +#define ARC_TIMERN_MAX 0xFFFFFFFF + +#define ARC_REG_TIMERS_BCR 0x75 + +struct bcr_timer { +#ifdef CONFIG_CPU_BIG_ENDIAN + unsigned int pad2:15, rtsc:1, pad1:5, rtc:1, t1:1, t0:1, ver:8; +#else + unsigned int ver:8, t0:1, t1:1, rtc:1, pad1:5, rtsc:1, pad2:15; +#endif +}; + +#endif diff --git a/include/soc/nps/mtm.h b/include/soc/nps/mtm.h new file mode 100644 index 000000000000..d2f5e7e3703e --- /dev/null +++ b/include/soc/nps/mtm.h @@ -0,0 +1,59 @@ +/* + * Copyright (c) 2016, Mellanox Technologies. All rights reserved. + * + * This software is available to you under a choice of one of two + * licenses. You may choose to be licensed under the terms of the GNU + * General Public License (GPL) Version 2, available from the file + * COPYING in the main directory of this source tree, or the + * OpenIB.org BSD license below: + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * - Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * + * - Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +#ifndef SOC_NPS_MTM_H +#define SOC_NPS_MTM_H + +#define CTOP_INST_HWSCHD_OFF_R3 0x3B6F00BF +#define CTOP_INST_HWSCHD_RESTORE_R3 0x3E6F70C3 + +static inline void hw_schd_save(unsigned int *flags) +{ + __asm__ __volatile__( + " .word %1\n" + " st r3,[%0]\n" + : + : "r"(flags), "i"(CTOP_INST_HWSCHD_OFF_R3) + : "r3", "memory"); +} + +static inline void hw_schd_restore(unsigned int flags) +{ + __asm__ __volatile__( + " mov r3, %0\n" + " .word %1\n" + : + : "r"(flags), "i"(CTOP_INST_HWSCHD_RESTORE_R3) + : "r3"); +} + +#endif /* SOC_NPS_MTM_H */ |